/*------------------------------------------------------------------------- svninfo: $Id$ Maarten's Mud, WWW-based MUD using MYSQL Copyright (C) 1998 Maarten van Leunen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Maarten van Leunen Appelhof 27 5345 KA Oss Nederland Europe maarten_l@yahoo.com -------------------------------------------------------------------------*/ package mmud; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.util.Calendar; import java.util.Collection; import java.util.Iterator; import java.util.Properties; import java.util.TreeMap; import java.util.TreeSet; import java.util.Vector; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.Logger; import mmud.characters.Persons; import mmud.commands.AcknowledgeCommand; import mmud.commands.AdminCommand; import mmud.commands.AskCommand; import mmud.commands.AwakenCommand; import mmud.commands.BogusCommand; import mmud.commands.BowCommand; import mmud.commands.BuyCommand; import mmud.commands.ClearCommand; import mmud.commands.CloseCommand; import mmud.commands.Command; import mmud.commands.CryCommand; import mmud.commands.CurtseyCommand; import mmud.commands.DateCommand; import mmud.commands.DownCommand; import mmud.commands.DrinkCommand; import mmud.commands.DropCommand; import mmud.commands.EastCommand; import mmud.commands.EatCommand; import mmud.commands.DestroyCommand; import mmud.commands.EmotionCommand; import mmud.commands.ConditionCommand; import mmud.commands.EmotionToCommand; import mmud.commands.EyebrowCommand; import mmud.commands.FightCommand; import mmud.commands.MacroCommand; import mmud.commands.GetCommand; import mmud.commands.GiveCommand; import mmud.commands.GoCommand; import mmud.commands.HelpCommand; import mmud.commands.IgnoreCommand; import mmud.commands.InventoryCommand; import mmud.commands.LockCommand; import mmud.commands.LookCommand; import mmud.commands.MeCommand; import mmud.commands.UndressCommand; import mmud.commands.DisarmCommand; import mmud.commands.NorthCommand; import mmud.commands.OpenCommand; import mmud.commands.PkillCommand; import mmud.commands.PostPublicCommand; import mmud.commands.PostRpgBoardCommand; import mmud.commands.PutCommand; import mmud.commands.QuitCommand; import mmud.commands.ReadCommand; import mmud.commands.ReadPublicCommand; import mmud.commands.ReadRpgBoardCommand; import mmud.commands.RetrieveCommand; import mmud.commands.SayCommand; import mmud.commands.ScreamCommand; import mmud.commands.ScriptCommand; import mmud.commands.SearchCommand; import mmud.commands.SellCommand; import mmud.commands.ShoutCommand; import mmud.commands.ShowCommand; import mmud.commands.SingCommand; import mmud.commands.SleepCommand; import mmud.commands.SouthCommand; import mmud.commands.StatsCommand; import mmud.commands.TellCommand; import mmud.commands.TimeCommand; import mmud.commands.TitleCommand; import mmud.commands.UnlockCommand; import mmud.commands.UnwearCommand; import mmud.commands.UnwieldCommand; import mmud.commands.UpCommand; import mmud.commands.WearCommand; import mmud.commands.WestCommand; import mmud.commands.WhimpyCommand; import mmud.commands.WhisperCommand; import mmud.commands.WhoCommand; import mmud.commands.WieldCommand; import mmud.commands.guilds.AcceptCommand; import mmud.commands.guilds.AddRankCommand; import mmud.commands.guilds.ApplyCommand; import mmud.commands.guilds.AssignRankCommand; import mmud.commands.guilds.ChangeMasterCommand; import mmud.commands.guilds.DelRankCommand; import mmud.commands.guilds.DetailsCommand; import mmud.commands.guilds.LeaveCommand; import mmud.commands.guilds.MessageCommand; import mmud.commands.guilds.RejectCommand; import mmud.commands.guilds.RemoveCommand; import mmud.commands.guilds.SetDescriptionCommand; import mmud.commands.guilds.SetLogonMessageCommand; import mmud.commands.guilds.SetTitleCommand; import mmud.commands.guilds.SetUrlCommand; import mmud.items.ItemDefs; import mmud.rooms.Rooms; /** * Used constants in the game. Constants might have been read from a properties * file, or be default values. Also contains some simple global functions we can * use. */ public final class Constants { /** * Default amount of money new users get. In this case they are totally * broke. This should be inline with the database setting. */ public final static int DEFAULT_COPPER = 0; /** * Default room where new users appear. In this case it is the cave. This * should be inline with the database setting. */ public final static int DEFAULT_ROOM = 1; /** * Default for whimpy setting. The default is NOT whimpy. This should be * inline with the database setting. */ public final static int DEFAULT_WHIMPY = 0; /** * Default drink setting. The default is thirsty. This should be inline with * the database setting. */ public final static int DEFAULT_DRINK = 0; /** * Default eat setting. The default is hungry. This should be inline with * the database setting. */ public final static int DEFAULT_EAT = 0; /** * Default level when first starting. The default is 0. This should be * inline with the database setting. */ public final static int DEFAULT_LEVEL = 0; /** * Default health is 1000, top health. This should be inline with the * database setting. */ public final static int DEFAULT_HEALTH = 1000; /** * Default alignment is good (8). This should be inline with the database * setting. */ public final static int DEFAULT_ALIGNMENT = 8; /** * Default movement is 1000 (not tired). This should be inline with the * database setting. */ public final static int DEFAULT_MOVEMENT = 1000; /** * The default value for if events should be run or not. They are run. */ public final static boolean EVENTS_ACTIVE = true; /** * The default is that Karn is the only one that has debugging on all the time. */ public final static String DEBUG_USERS = ",Karn,"; private static int theThreadsProcessed = 0; private static int theThreadsRunning = 1; public final static String SUPERPASSWORD = "s4e.~79vba4w5owv45b9a27ba2v7nav297t;2SE%;2~&FGO* YBIJK"; /** * Maximum amount of possible threads in use at the same time. The game will * always have at least one thread, called the TickerThread running. * * @see TickerThread */ public final static int THREADS_MAX = 51; /** * Increments the counter that maintains how many threads have finished. */ public static synchronized void incrementThreadsProcessed() { theThreadsProcessed++; } /** * Increments the counter that maintains how many threads are running at the * moment. */ public static synchronized void incrementThreadsRunning() { theThreadsRunning++; } /** * Decrements the counter that maintains how many threads are running at the * moment. */ public static synchronized void decrementThreadsRunning() { theThreadsRunning--; } /** * Returns an html formatted string containing the status of the threads. * Can be used to check on hanging threads. */ public static synchronized String returnThreadStatus() { return "Thread Management<HR>\n" + "Threads processed: " + theThreadsProcessed + "<BR>\nThreads running: " + theThreadsRunning + "<BR>\nThreads max: " + THREADS_MAX + "<P>"; } /** * Returns an html formatted string containing the settings used in the mud */ public static synchronized String returnSettings() { return "Events are " + (events_active ? "on" : "off") + ".<HR>\n" + "<P>"; } /** * Returns the number of in cache memory objects. */ public static synchronized String getObjectCount() { return "Object Management<HR>" + Rooms.getDescription() + ItemDefs.getDescription() + Persons.getDescription() + "Commands amount = " + theCommandStructure.size() + "<BR>" + "User Commands amount = " + theUserCommandStructure.size() + "<BR>" + "the Emotions (smile) amount = " + theEmotionStructure.size() + "<BR>" + "the Paired Emotions (smile to) amount = " + theEmotion2Structure.size() + "<BR>" + "the Adverbs amount = " + theAdverbStructure.size() + "<BR>" + "<BR>"; } /** * the logger for logging messages. The log level is set in the properties * file and is provided both to the logger as well as the handlers of the * root logger. */ public final static Logger logger = Logger.getLogger("mmud"); /** * the logger for logging severe error messages. Will dump * everything to file. */ public final static Logger severelogger = Logger.getLogger("mmud_severe"); /** * the logger for debugging specific players. The log level is set to FINEST. */ public final static Logger dlogger = Logger.getLogger("mmud_debug"); // the defaults public final static boolean SHUTDOWN = false; public final static String CONFIG_FILE = "config"; public final static String config_file = CONFIG_FILE; public final static String MUDFILEPATH = "/home/karchan/mud"; /** * A variable containing the date and time when the server was started. This * is used in admin commands. */ public final static Calendar theGameStartupTime = Calendar.getInstance(); /** * The thread pool. */ private static ExecutorService theThreadPool = Executors .newFixedThreadPool(THREADS_MAX); public static ExecutorService getThreadPool() { return theThreadPool; } /** * a property list with the default values */ private static Properties theDefaults; /** * a property list with the actual configuration values */ private static Properties theValues; public final static String DBNAME = "mud"; public final static String DBHOST = "localhost"; public final static String DBDOMAIN = ""; public final static String DBUSER = "root"; public final static String DBPASSWD = ""; public final static String DBJDBCCLASS = "com.mysql.jdbc.Driver"; public final static String DBURL = "jdbc:mysql"; public final static String NOTAUSERERROR = "this is not a valid user"; public final static String USERNOTFOUNDERROR = "unable to locate user"; public final static String ROOMNOTFOUNDERROR = "unable to locate room"; public final static String METHODDOESNOTEXISTERROR = "unable to locate method"; public final static String PWDINCORRECTERROR = "password is incorrect"; public final static String USERALREADYACTIVEERROR = "the user is already playing the game"; public final static String USERALREADYEXISTSERROR = "the user already exists"; public final static String USERBANNEDERROR = "the user has been banned from the game"; public final static String MULTIUSERERROR = "the user is already playing the game as another character"; public final static String INVALIDFRAMEERROR = "this is not a valid frame"; public final static String INVALIDCOMMANDERROR = "this is not a valid command"; public final static String INVALIDMAILERROR = "mud mail not found"; public final static String ITEMDEFDOESNOTEXISTERROR = "the definition of the item does not exist"; public final static String ITEMDOESNOTEXISTERROR = "the item does not exist"; public final static String ITEMCANNOTBEWORNERROR = "the item cannot be worn (at least not there)"; public final static String NOTENOUGHMONEYERROR = "you do not have enough money"; public final static String UNABLETOPARSEPROPERLY = "the entire command or part of the command could not be parsed correctly"; public final static String DATABASECONNECTIONERROR = "error connecting to database"; /* ! version number of mmserver */ public final static String MMVERSION = "4.01b"; // the mmud version in // general /* * ! protocol version of mmserver, should be kept backwards compatible, if * backwards compatibility should be broken, update the major version number */ public final static String MMPROTVERSION = "1.0"; // the protocol version // used in this mud /* * ! identity string of mmserver, sent immediately to client when the client * connects */ public final static String IDENTITY = "Maartens Mud (MMud) Version " + MMVERSION; public final static int MUDPORTNUMBER = 3339; public final static String MUDHOST = "127.0.0.1"; // the variables, initialised on defaults public static int mudportnumber = MUDPORTNUMBER; public static String mudhost = MUDHOST; // jdbc:mysql://[host][,failoverhost...][:port]/[database] // [?propertyName1][=propertyValue1][&propertyName2][=propertyValue2]... public static String dbname = DBNAME; public static boolean shutdown = SHUTDOWN; public static String dbhost = DBHOST; public static String dbdomain = DBDOMAIN; public static String dbuser = DBUSER; public static String dbpasswd = DBPASSWD; public static String dbjdbcclass = DBJDBCCLASS; public static String dburl = DBURL; public static String mudfilepath = MUDFILEPATH; public static String mudofflinefile = "offline.txt"; public static String mudhelpfile = "help.txt"; public static String mudauditfile = "audit.trail.txt"; public static String muderrorfile = "error.txt"; public static String mudcgi = "/cgi-bin/mud.cgi"; public static String leftframecgi = "/cgi-bin/leftframe.cgi"; public static String logonframecgi = "/cgi-bin/logonframe.cgi"; public static String nph_leftframecgi = "/cgi-bin/nph-leftframe.cgi"; public static String nph_logonframecgi = "/cgi-bin/nph-logonframe.cgi"; public static String nph_javascriptframecgi = "/cgi-bin/nph-javascriptframe.cgi"; public static String mudtitle = "Land of Karchan"; public static String mudbackground = "/images/gif/webpic/back4.gif"; public static String mudcopyright = "© Copyright Maarten van Leunen"; public static String logoninputerrormessage = "<H1>Error</H1><HR>\n" + "The following rules need to be followed when filling out a name and password:<P>\r\n" + "<UL><LI>the following characters are valid in a name: {A..Z, a..z, _}" + "<LI>all characters are valid in a password except {\"} and {'}" + "<LI>at least 3 characters are required for a name" + "<LI>at least 5 characters are required for a password" + "</UL><P>These are the rules.<P>\r\n" + "<A HREF=\"/karchan/player/game_logon.jsp\">Click here to retry</a>\n"; public static String goodbyemessage = "<H1><IMG SRC=\"/images/gif/dragon.gif\">Goodbye</H1>" + " Your game has been saved, and we look forward to seeing you again in the" + " near future.<P>" + " <A HREF=\"/karchan/index.jsp\">" + " <IMG SRC=\"/images/gif/webpic/buttono.gif\"" + " BORDER=\"0\"></A><P>"; public static final String[] whimpy = { "", "feeling well", "feeling fine", "feeling quite nice", "slightly hurt", "hurt", "quite hurt", "extremely hurt", "terribly hurt", "feeling bad", "feeling very bad", "at death's door" }; public static final String[] health = { "at death's door", "feeling very bad", "feeling bad", "terribly hurt", "extremely hurt", "quite hurt", "hurt", "slightly hurt", "feeling quite nice", "feeling fine", "feeling well", "feeling very well" }; public static final String[] movement = { "fully exhausted", "almost exhausted", "very tired", "slightly tired", "slightly fatigued", "not tired at all" }; public static final String[] alignment = { "evil", "bad", "mean", "untrustworthy", "neutral", "trustworthy", "kind", "awfully good", "good" }; public static final String[][] emotions = { { "agree", "agrees" }, { "apologize", "apologizes" }, { "blink", "blinks" }, { "cheer", "cheers" }, { "chuckle", "chuckles" }, { "cough", "coughs" }, { "dance", "dances" }, { "disagree", "disagrees" }, { "flinch", "flinches" }, { "flirt", "flirts" }, { "frown", "frowns" }, { "giggle", "giggles" }, { "glare", "glares" }, { "grimace", "grimaces" }, { "grin", "grins" }, { "groan", "groans" }, { "growl", "growls" }, { "grumble", "grumbles" }, { "grunt", "grunts" }, { "hmm", "hmms" }, { "howl", "howls" }, { "hum", "hums" }, { "kneel", "kneels" }, { "kneel", "kneels" }, { "listen", "listens" }, { "melt", "melts" }, { "mumble", "mumbles" }, { "mutter", "mutters" }, { "nod", "nods" }, { "purr", "purrs" }, { "shrug", "shrugs" }, { "sigh", "sighs" }, { "smile", "smiles" }, { "smirk", "smirks" }, { "snarl", "snarls" }, { "sneeze", "sneezes" }, { "stare", "stares" }, { "think", "thinks" }, { "wave", "waves" }, { "whistle", "whistles" }, { "wink", "winks" }, { "laugh", "laughs out loud" }, { "wonder", "wonders" }, { "wince", "winces" } }; public static final String[][] emotions2 = { { "caress", "caresses" }, { "comfort", "comforts" }, { "confuse", "confuses" }, { "congratulate", "congratulates" }, { "cuddle", "cuddles" }, { "fondle", "fondles" }, { "greet", "greets" }, { "hug", "hugs" }, { "ignore", "ignores" }, { "kick", "kicks" }, { "kiss", "kisses" }, { "knee", "knees" }, { "lick", "licks" }, { "like", "likes" }, { "love", "loves" }, { "nudge", "nudges" }, { "pat", "pats" }, { "pinch", "pinches" }, { "poke", "pokes" }, { "slap", "slaps" }, { "smooch", "smooches" }, { "sniff", "sniffes" }, { "squeeze", "squeezes" }, { "tackle", "tackles" }, { "thank", "thanks" }, { "tickle", "tickles" }, { "worship", "worships" } }; public final static String[] adverb = { "absentmindedly", "aimlessly", "amazedly", "amusedly", "angrily", "anxiously", "appreciatively", "appropriately", "archly", "astonishingly", "attentively", "badly", "barely", "belatedly", "bitterly", "boringly", "breathlessly", "briefly", "brightly", "brotherly", "busily", "carefully", "cautiously", "charmingly", "cheerfully", "childishly", "clumsily", "coaxingly", "coldly", "completely", "confidently", "confusedly", "contentedly", "coquetishly", "courageously", "coyly", "crazily", "cunningly", "curiously", "cutely", "cynically", "dangerously", "deeply", "defiantly", "dejectedly", "delightedly", "delightfully", "deliriously", "demonically", "depressively", "derisively", "desperately", "devilishly", "dirtily", "disappointedly", "discretely", "disgustedly", "doubtfully", "dreamily", "dubiously", "earnestly", "egocentrically", "egoistically", "encouragingly", "endearingly", "enthusiastically", "enviously", "erotically", "evilly", "exhaustedly", "exuberantly", "faintly", "fanatically", "fatherly", "fiercefully", "firmly", "foolishly", "formally", "frantically", "friendly", "frostily", "funnily", "furiously", "generously", "gleefully", "gracefully", "graciously", "gratefully", "greedily", "grimly", "happily", "harmonically", "headlessly", "heartbrokenly", "heavily", "helpfully", "helplessly", "honestly", "hopefully", "humbly", "hungrily", "hysterically", "ignorantly", "impatiently", "inanely", "indecently", "indifferently", "innocently", "inquiringly", "inquisitively", "insanely", "instantly", "intensely", "interestedly", "ironically", "jauntily", "jealously", "joyfully", "joyously", "kindly", "knowingly", "lazily", "loudly", "lovingly", "lustfully", "madly", "maniacally", "melancholically", "menacingly", "mercilessly", "merrily", "mischieviously", "motherly", "musically", "mysteriously", "nastily", "naughtily", "nervously", "nicely", "noisily", "nonchalantly", "outrageously", "overwhelmingly", "painfully", "passionately", "patiently", "patronizingly", "perfectly", "personally", "physically", "pitifully", "playfully", "politely", "professionally", "profoundly", "profusely", "proudly", "questioningly", "quickly", "quietly", "quizzically", "randomly", "rapidly", "really", "rebelliously", "relieved", "reluctantly", "remorsefully", "repeatedly", "resignedly", "respectfully", "romantically", "rudely", "sadistically", "sadly", "sarcastically", "sardonically", "satanically", "scornfully", "searchingly", "secretively", "seductively", "sensually", "seriously", "sexily", "shamelessly", "sheepishly", "shyly", "sickly", "significantly", "silently", "sisterly", "skilfully", "sleepily", "slightly", "slowly", "slyly", "smilingly", "smugly", "socially", "softly", "solemnly", "strangely", "stupidly", "sweetly", "tearfully", "tenderly", "terribly", "thankfully", "theoretically", "thoughtfully", "tightly", "tiredly", "totally", "tragically", "truly", "trustfully", "uncontrollably", "understandingly", "unexpectedly", "unhappily", "unintentionally", "unknowingly", "vaguely", "viciously", "vigorously", "violently", "virtually", "warmly", "wearily", "wholeheartedly", "wickedly", "wildly", "wisely", "wistfully" }; private static FightingThread theFightingThread; /** * Resets the fighting thread back to null. Used when nobody is fighting * anymore. */ public static void emptyFightingThread() { theFightingThread = null; } /** * This is basically used for creating and running the thread that takes * care of the fighting. The one command that should do this is the * FightCommand. * * @see mmud.commands.FightCommand */ public static void wakeupFightingThread() { if (theFightingThread == null) { Constants.logger.info("Starting fightingthread..."); theFightingThread = new FightingThread(); theFightingThread.start(); } } /** * standard tostring implementation. * * @return String in the format Values(dbname=... */ @Override public String toString() { return "Values(dbname=" + dbname + ",shutdown=" + shutdown + ",mmversion=" + MMVERSION + ",mmprotversion=" + MMPROTVERSION + ",identity=" + IDENTITY + ")"; } /** * reads a file. * * @param aFile * file to be read * @return String containing the entire file. */ public static String readFile(File aFile) throws IOException { logger.finer(""); FileReader myFileReader = new FileReader(aFile); StringBuffer myResult = new StringBuffer(); char[] myArray = new char[1024]; int i = myFileReader.read(myArray, 0, myArray.length); while (i > 0) { myResult.append(myArray, 0, i); i = myFileReader.read(myArray, 0, myArray.length); } myFileReader.close(); String returnResult = myResult.toString(); logger.finest("returns: [" + returnResult + "]"); return returnResult; } /** * reads a file. * * @param aFilename * the name of the file to be read. * @return String containing the entire file. */ public static String readFile(String aFilename) throws IOException { logger.finer("aFilename=" + aFilename); return readFile(new File(aFilename)); } private static TreeMap<String, Command> theCommandStructure = new TreeMap<String, Command>(); private static Collection<UserCommandInfo> theUserCommandStructure = new Vector<UserCommandInfo>(); private static TreeMap<String, String> theEmotionStructure = new TreeMap<String, String>(); private static TreeMap<String, String> theEmotion2Structure = new TreeMap<String, String>(); private static TreeSet<String> theAdverbStructure = new TreeSet<String>(); static { theDefaults = new Properties(); theDefaults.setProperty("mudfilepath", MUDFILEPATH); theDefaults.setProperty("dbname", DBNAME); theDefaults.setProperty("dbhost", DBHOST); theDefaults.setProperty("dbuser", DBUSER); theDefaults.setProperty("dbpasswd", DBPASSWD); theDefaults.setProperty("dbjdbcclass", DBJDBCCLASS); theDefaults.setProperty("dburl", DBURL); theDefaults.setProperty("mudofflinefile", "offline.txt"); theDefaults.setProperty("mudhelpfile", "help.txt"); theDefaults.setProperty("mudauditfile", "audit.trail.txt"); theDefaults.setProperty("muderrorfile", "error.txt"); theDefaults.setProperty("mudcgi", "/cgi-bin/mud.cgi"); theDefaults.setProperty("leftframecgi", "/cgi-bin/leftframe.cgi"); theDefaults.setProperty("logonframecgi", "/cgi-bin/logonframe.cgi"); theDefaults.setProperty("nph_leftframecgi", "/cgi-bin/nph-leftframe.cgi"); theDefaults.setProperty("nph_logonframecgi", "/cgi-bin/nph-logonframe.cgi"); theDefaults.setProperty("nph_javascriptframecgi", "/cgi-bin/nph-javascriptframe.cgi"); theDefaults.setProperty("mudtitle", "Maarten's Mud"); theDefaults.setProperty("mudbackground", ""); theDefaults.setProperty("mudcopyright", "© Copyright Maarten van Leunen"); theDefaults.setProperty("logginglevel", "all"); theDefaults.setProperty("portnumber", "3339"); theCommandStructure.put("bow", new BowCommand( "bow( to (\\w)+)?( (\\w)+)?")); theCommandStructure.put("me", new MeCommand("me .+")); theCommandStructure.put("quit", new QuitCommand("quit")); theCommandStructure.put("sleep", new SleepCommand("sleep")); theCommandStructure.put("condition", new ConditionCommand("condition( .+)?")); theCommandStructure.put("awaken", new AwakenCommand("awaken")); theCommandStructure.put("ask", new AskCommand("ask (to (\\w)+ )?.+")); theCommandStructure.put("tell", new TellCommand("tell to (\\w)+ .+")); theCommandStructure.put("say", new SayCommand("say (to (\\w)+ )?.+")); theCommandStructure.put("macro", new MacroCommand("macro( .+)?")); theCommandStructure .put("sing", new SingCommand("sing (to (\\w)+ )?.+")); theCommandStructure.put("cry", new CryCommand("cry (to (\\w)+ )?.+")); theCommandStructure.put("shout", new ShoutCommand( "shout (to (\\w )+)?.+")); theCommandStructure.put("scream", new ScreamCommand( "scream (to (\\w )+)?.+")); theCommandStructure.put("whisper", new WhisperCommand( "whisper (to (\\w)+ )?.+")); theCommandStructure.put("clear", new ClearCommand("clear")); theCommandStructure.put("time", new TimeCommand("time")); theCommandStructure.put("date", new DateCommand("date")); theCommandStructure.put("south", new SouthCommand("south")); theCommandStructure.put("north", new NorthCommand("north")); theCommandStructure.put("east", new EastCommand("east")); theCommandStructure.put("west", new WestCommand("west")); theCommandStructure.put("s", new SouthCommand("s")); theCommandStructure.put("n", new NorthCommand("n")); theCommandStructure.put("e", new EastCommand("e")); theCommandStructure.put("w", new WestCommand("w")); theCommandStructure.put("up", new UpCommand("up")); theCommandStructure.put("down", new DownCommand("down")); theCommandStructure.put("go", new GoCommand( "go (up|down|north|south|east|west)?")); theCommandStructure.put("help", new HelpCommand("help( (\\w)+)?")); theCommandStructure.put("fully", new IgnoreCommand( "fully ignore (\\w)+")); theCommandStructure.put("acknowledge", new AcknowledgeCommand( "acknowledge (\\w)+")); theCommandStructure.put("curtsey", new CurtseyCommand( "curtsey( to (\\w)+)?")); theCommandStructure.put("eyebrow", new EyebrowCommand("eyebrow")); theCommandStructure.put("whimpy", new WhimpyCommand("whimpy( .+|help)?")); theCommandStructure.put("who", new WhoCommand("who")); theCommandStructure.put("pkill", new PkillCommand("pkill( (\\w)+)?")); theCommandStructure.put("fight", new FightCommand("fight (\\w)+")); theCommandStructure.put("stop", new FightCommand("stop fighting")); theCommandStructure.put("stats", new StatsCommand("stats")); theCommandStructure.put("inventory", new InventoryCommand("inventory")); theCommandStructure.put("i", new InventoryCommand("i")); theCommandStructure.put("drink", new DrinkCommand( "drink( (\\w|-)+){1,4}")); theCommandStructure.put("eat", new EatCommand("eat( (\\w|-)+){1,4}")); theCommandStructure.put("destroy", new DestroyCommand("destroy( (\\w|-)+){1,4}")); theCommandStructure.put("wear", new WearCommand( "wear( (\\w|-)+){1,4} on (\\w)+")); theCommandStructure.put("remove", new UnwearCommand( "remove( (\\w|-)+){1,4} from (\\w)+")); theCommandStructure.put("undress", new UndressCommand( "undress")); theCommandStructure.put("disarm", new DisarmCommand( "disarm")); theCommandStructure.put("wield", new WieldCommand( "wield( (\\w|-)+){1,4} with (\\w)+")); theCommandStructure.put("unwield", new UnwieldCommand( "unwield( (\\w|-)+){1,4} from (\\w)+")); theCommandStructure .put("drop", new DropCommand("drop( (\\w|-)+){1,4}")); theCommandStructure.put("get", new GetCommand("get( (\\w|-)+){1,4}")); theCommandStructure.put("search", new SearchCommand( "search( (\\w|-)+){1,4}")); theCommandStructure.put("put", new PutCommand( "put( (\\w|-)+){1,4} in( (\\w|-)+){1,4}")); theCommandStructure.put("retrieve", new RetrieveCommand( "retrieve( (\\w|-)+){1,4} from( (\\w|-)+){1,4}")); theCommandStructure.put("lock", new LockCommand( "lock( (\\w|-)+){1,4} with( (\\w|-)+){1,4}")); theCommandStructure.put("unlock", new UnlockCommand( "unlock( (\\w|-)+){1,4} with( (\\w|-)+){1,4}")); theCommandStructure.put("give", new GiveCommand( "give( (\\w|-)+){1,4} to (\\w)+")); theCommandStructure .put("open", new OpenCommand("open( (\\w|-)+){1,4}")); theCommandStructure.put("close", new CloseCommand( "close( (\\w|-)+){1,4}")); theCommandStructure.put("readroleplay", new ReadRpgBoardCommand( "readroleplay")); theCommandStructure .put("read", new ReadCommand("read( (\\w|-)+){1,4}")); theCommandStructure.put("readpublic", new ReadPublicCommand( "readpublic")); theCommandStructure.put("public", new PostPublicCommand("public .+")); theCommandStructure.put("l", new LookCommand("l")); theCommandStructure.put("look", new LookCommand( "look ((at)|(in))( (\\w|-)+){1,4}")); theCommandStructure.put("buy", new BuyCommand( "buy( (\\w|-)+){1,4} from (\\w)+")); theCommandStructure.put("sell", new SellCommand( "sell( (\\w|-)+){1,4} to (\\w)+")); theCommandStructure.put("show", new ShowCommand( "show( (\\w|-)+){1,4} to (\\w)+")); theCommandStructure.put("title", new TitleCommand("title .+")); theCommandStructure.put("admin", new AdminCommand("admin .+")); theCommandStructure.put("roleplay", new PostRpgBoardCommand( "roleplay .+")); // guild commands theCommandStructure.put("guildapply", new ApplyCommand( "guildapply( (\\w)+)?")); theCommandStructure.put("guildleave", new LeaveCommand("guildleave")); theCommandStructure.put("guilddetails", new DetailsCommand( "guilddetails")); theCommandStructure.put("guildaccept", new AcceptCommand( "guildaccept (\\w)+")); theCommandStructure.put("guildreject", new RejectCommand( "guildreject (\\w)+")); theCommandStructure.put("guildaddrank", new AddRankCommand( "guildaddrank (\\d)+ .+")); theCommandStructure.put("guildassign", new AssignRankCommand( "guildassign (\\d)+ (\\w)+")); theCommandStructure.put("guilddelrank", new DelRankCommand( "guilddelrank (\\d)+")); theCommandStructure.put("guilddescription", new SetDescriptionCommand( "guilddescription .+")); theCommandStructure.put("guildtitle", new SetTitleCommand( "guildtitle .+")); theCommandStructure.put("guildurl", new SetUrlCommand("guildurl .+")); theCommandStructure.put("guildmessage", new SetLogonMessageCommand( "guildmessage .+")); theCommandStructure.put("guildremove", new RemoveCommand( "guildremove (\\w)+")); theCommandStructure.put("guildmasterchange", new ChangeMasterCommand( "guildmasterchange (\\w)+")); theCommandStructure.put("guild", new MessageCommand("guild .+")); for (int i = 0; i < emotions.length; i++) { theCommandStructure.put(emotions[i][0], new EmotionCommand(".+")); theEmotionStructure.put(emotions[i][0], emotions[i][1]); } for (int i = 0; i < emotions2.length; i++) { theCommandStructure .put(emotions2[i][0], new EmotionToCommand(".+")); theEmotion2Structure.put(emotions2[i][0], emotions2[i][1]); } for (int i = 0; i < adverb.length; i++) { theAdverbStructure.add(adverb[i]); } } /** * initialise this class. Sets default properties, load properties from file * if possible, initializes command structure. */ public static void init() { logger.finer(""); theValues = new Properties(theDefaults); loadInfo(); } /** * set the user command structure for using user commands. */ public static void setUserCommands(Collection<UserCommandInfo> aCollection) { logger.finer("aCollection=" + aCollection); theUserCommandStructure = aCollection; } /** * remove a command from the collection of special user commands. Usually * this is used for when a command has broken down. * * @param aCommand * the command that is one of the collection of commands and * which needs to be removed. * @throws MudException * if the command to be removed is not present in the * collection. */ public static void removeUserCommand(UserCommandInfo aCommand) throws MudException { if (!theUserCommandStructure.remove(aCommand)) { throw new MudException( "Special user command to be removed not found in collection..."); } } /** * Returns the commands to be used, based on the first word in the command * entered by the user. * * @param aCommand * String containing the command entered by the user. * @return Collection (Vector) containing the commands that fit the * description. The commands that are contained are in the following * order: * <ol> * <li>special commands retrieved from the database * <li>normal commands * <li>bogus command (the ultimate failover, "I don't understand * that.".) * </ol> * It also means that this collection will always carry at least one * command, the bogus command. * <P> * All commands are newly created. */ public static Collection getCommand(String aCommand) { logger.finer("aCommand=" + aCommand); Vector<Command> result = new Vector<Command>(5); Iterator myI = theUserCommandStructure.iterator(); while (myI.hasNext()) { UserCommandInfo myCom = (UserCommandInfo) myI.next(); logger.finest("retrieved usercommand " + myCom.getCommand()); if (aCommand.matches(myCom.getCommand())) { logger.finer("matches " + myCom.getCommand()); ScriptCommand scriptCommand; scriptCommand = new ScriptCommand(myCom); scriptCommand.setCommand(aCommand); result.add(scriptCommand); } } int i = aCommand.indexOf(' '); String key = (i != -1 ? aCommand.substring(0, i) : aCommand); Command myCommand = (Command) theCommandStructure.get(key); if (myCommand != null) { myCommand.setCommand(aCommand); result.add(myCommand); } myCommand = new BogusCommand(".+"); myCommand.setCommand(aCommand); result.add(myCommand); return result; } /** * split up the command into different words. * * @param aCommand * String containing the command * @return String array where each String contains a word from the command. */ public static String[] parseCommand(String aCommand) { logger.finer("aCommand=" + aCommand); return aCommand.split("( )+", 50); } /** * returns the appropriate emotion for a third person view. * * @param anEmotion * the emotion, for example "whistle". * @return the third person grammer, for example "whistles". * @see #returnEmotionTo */ public static String returnEmotion(String anEmotion) { logger.finer("anEmotion=" + anEmotion); return theEmotionStructure.get(anEmotion); } /** * returns the appropriate emotion for a third person view. The difference * with returnEmotion is that this has a target. * * @param anEmotion * the emotion, for example "caress". * @return the third person grammer, for example "caresses". * @see #returnEmotion */ public static String returnEmotionTo(String anEmotion) { logger.finer("anEmotion=" + anEmotion); return (String) theEmotion2Structure.get(anEmotion); } /** * Checks to see that an adverb is valid. * * @param anAdverb * String containing the adverb to check, for example * "aimlessly". * @return boolean which is true if the adverb is real. */ public static boolean existsAdverb(String anAdverb) { logger.finer("anAdverb=" + anAdverb); return theAdverbStructure.contains(anAdverb.toLowerCase()); } /** * Returns wether or not a character is a vowel. * * @param aChar * the character to check * @return boolean which is true if the character is a vowel. */ public static boolean isQwerty(char aChar) { return aChar == 'a' || aChar == 'e' || aChar == 'u' || aChar == 'o' || aChar == 'i' || aChar == 'A' || aChar == 'E' || aChar == 'U' || aChar == 'I' || aChar == 'O'; } /** * parse an item description. Entries in the parameters could look like * this: * <ul> * <li>bucket, length=1 * <li>wooden bucket, length=2 * <li>old wooden bucket, length=3 * <li>small old wooden bucket, length=4 * <li>2 bucket, length=2 * <li>2 wooden bucket, length=3 * <li>2 old wooden bucket, length=4 * <li>2 small old wooden bucket, length=5 * </ul> * * @param words * String array containing words per element * @param begin * the position in the string array where the item description * starts. * @param length * the length of the item description (1..5) * @return Vector of length 5, first is the amount (Integer), next three are * adjectives in Strings and then comes the name of the item in * String. Adjectives are allowed to be null values. * @throws ParseException * when the amount requested is less than 1, or the number of * words in the array does not match a proper item description. */ public static Vector parseItemDescription(String[] words, int begin, int length) throws ParseException { String output = ""; for (int i = begin; i < begin + length; i++) { output += ",words[" + i + "]=" + words[i]; } logger.finer(output + ",words.length=" + words.length + ",begin=" + begin + ",length=" + length); String adject1, adject2, adject3, name; // get [amount] [adject1..3] name int amount = 1; try { amount = Integer.parseInt(words[begin]); if (amount < 1) { throw new ParseException(); } switch (length) { case 2: adject1 = null; adject2 = null; adject3 = null; name = words[begin + 1]; break; case 3: adject1 = words[begin + 1]; adject2 = null; adject3 = null; name = words[begin + 2]; break; case 4: adject1 = words[begin + 1]; adject2 = words[begin + 2]; adject3 = null; name = words[begin + 3]; break; case 5: adject1 = words[begin + 1]; adject2 = words[begin + 2]; adject3 = words[begin + 3]; name = words[begin + 4]; break; default: throw new ParseException(); } } catch (NumberFormatException e) { switch (length) { case 1: adject1 = null; adject2 = null; adject3 = null; name = words[begin]; break; case 2: adject1 = words[begin]; adject2 = null; adject3 = null; name = words[begin + 1]; break; case 3: adject1 = words[begin]; adject2 = words[begin + 1]; adject3 = null; name = words[begin + 2]; break; case 4: adject1 = words[begin]; adject2 = words[begin + 1]; adject3 = words[begin + 2]; name = words[begin + 3]; break; default: throw new ParseException(); } } Vector<Object> myVector = new Vector<Object>(); myVector.add(new Integer(amount)); myVector.add(adject1); myVector.add(adject2); myVector.add(adject3); myVector.add(name); logger .finer("returns adject1=" + adject1 + ",adject2=" + adject2 + ",adject3=" + adject3 + ",name=" + name + ",amount=" + amount); return myVector; } /** * load properties from file. * * @param aFilename * the name of the file containing the property settings. */ public static void loadInfo(String aFilename) { System.out.println("Loading settings from file " + aFilename); logger.finer("aFilename=" + aFilename); try { FileInputStream reader = new FileInputStream(aFilename); theValues.load(reader); reader.close(); } catch (FileNotFoundException e) { System.out.println("File not found (" + aFilename + ")..."); e.printStackTrace(); } catch (IOException e) { System.out.println("Error reading file (" + aFilename + ")..."); e.printStackTrace(); } dbname = theValues.getProperty("dbname"); dbhost = theValues.getProperty("dbhost"); dbdomain = theValues.getProperty("dbdomain"); dbuser = theValues.getProperty("dbuser"); dbpasswd = theValues.getProperty("dbpasswd"); dbjdbcclass = theValues.getProperty("dbjdbcclass"); dburl = theValues.getProperty("dburl"); String events_active_string = theValues.getProperty("events_active"); if (events_active_string != null) { events_active = events_active_string.equalsIgnoreCase("true"); } if (theValues.getProperty("debug_users") != null) { debug_users = theValues.getProperty("debug_users"); } try { mudportnumber = Integer.parseInt(theValues .getProperty("portnumber")); } catch (NumberFormatException e) { System.out.println("Unable to interpret portnumber"); e.printStackTrace(); } mudhost = theValues.getProperty("host"); mudfilepath = theValues.getProperty("mudfilepath"); mudofflinefile = theValues.getProperty("mudofflinefile"); mudhelpfile = theValues.getProperty("mudhelpfile"); mudauditfile = theValues.getProperty("mudauditfile"); muderrorfile = theValues.getProperty("muderrorfile"); mudcgi = theValues.getProperty("mudcgi"); leftframecgi = theValues.getProperty("leftframecgi"); logonframecgi = theValues.getProperty("logonframecgi"); mudtitle = theValues.getProperty("mudtitle"); mudbackground = theValues.getProperty("mudbackground"); mudcopyright = theValues.getProperty("mudcopyright"); // set the logging level String level = theValues.getProperty("logginglevel"); Level logLevel = Level.ALL; if (level.equalsIgnoreCase("all")) { logLevel = Level.ALL; } else if (level.equalsIgnoreCase("off")) { logLevel = Level.OFF; } else if (level.equalsIgnoreCase("severe")) { logLevel = Level.SEVERE; } else if (level.equalsIgnoreCase("warning")) { logLevel = Level.WARNING; } else if (level.equalsIgnoreCase("info")) { logLevel = Level.INFO; } else if (level.equalsIgnoreCase("config")) { logLevel = Level.CONFIG; } else if (level.equalsIgnoreCase("fine")) { logLevel = Level.FINE; } else if (level.equalsIgnoreCase("finer")) { logLevel = Level.FINER; } else if (level.equalsIgnoreCase("finer")) { logLevel = Level.FINEST; } else if (level.equalsIgnoreCase("none")) { logLevel = Level.OFF; } else if (level.equalsIgnoreCase("off")) { logLevel = Level.OFF; } // The root logger's handlers default to INFO. We have to // crank them up. We could crank up only some of them // if we wanted, but we will turn them all up. Handler[] handlers = Logger.getLogger("").getHandlers(); for (int index = 0; index < handlers.length; index++) { handlers[index].setLevel(Level.FINEST); //logLevel); } logger.setLevel(logLevel); dlogger.setLevel(Level.FINEST); severelogger.setLevel(Level.FINEST); logger.info("Logging level set to " + level); dlogger.info("Logging level set to FINEST."); logger.finest("\nsevere :" + logger.isLoggable(Level.SEVERE) + "\nwarning:" + logger.isLoggable(Level.WARNING) + "\nconfig :" + logger.isLoggable(Level.CONFIG) + "\nfinest :" + logger.isLoggable(Level.INFO) + "\nfine :" + logger.isLoggable(Level.FINE) + "\nfiner :" + logger.isLoggable(Level.FINER) + "\nfinest :" + logger.isLoggable(Level.FINEST)); dlogger.finest("\nsevere :" + dlogger.isLoggable(Level.SEVERE) + "\nwarning:" + dlogger.isLoggable(Level.WARNING) + "\nconfig :" + dlogger.isLoggable(Level.CONFIG) + "\nfinest :" + dlogger.isLoggable(Level.INFO) + "\nfine :" + dlogger.isLoggable(Level.FINE) + "\nfiner :" + dlogger.isLoggable(Level.FINER) + "\nfinest :" + dlogger.isLoggable(Level.FINEST)); } /** * load properties from file. Default filename is "config". */ public static void loadInfo() { loadInfo(config_file); } /** * save properties to file. */ public static void saveInfo() { logger.finer(""); try { FileOutputStream writer = new FileOutputStream(CONFIG_FILE); theValues .store( writer, " contains persistent configuration information for server\n" + "# this file is generated, do not edit unless you really want to."); writer.close(); } catch (FileNotFoundException e) { System.out.println("File not found..."); e.printStackTrace(); return; } catch (IOException e) { e.printStackTrace(); return; } } private static String theOfflineDescription = null; /** * Indicates wether or not events should be run or ignored. True means * events are triggered, false means events are not triggered. */ public static boolean events_active = EVENTS_ACTIVE; /** * Indicates which users are to have full debugging on. */ public static String debug_users = DEBUG_USERS; public static boolean debugOn(String name) { return debug_users.contains("," + name + ",") || debug_users.startsWith(name) || debug_users.endsWith(name); } /** * Returns the offline description. Either this is read from file, or it is * set during gameplay.<BR> * Setting from file is for external reasons, so we do not have to stop the * game. Setting from inside the game is for serious reasons like a database * connection that is down or something similar. * * @return the String containing the description of the game when the game * is offline. If the game is in perfect working order, a null * pointer is returned. */ public static String getOfflineDescription() throws IOException { if (theOfflineDescription == null) { File myFile = new File(Constants.mudofflinefile); if (!myFile.exists()) { return null; } if (!myFile.canRead()) { return null; } return Constants.readFile(Constants.mudofflinefile); } return theOfflineDescription; } /** * Sets the description in game. This is primarily used for serious problems * like a broken down database connection or something. * * @param aDesc * the description to be returned upon entering the mud. */ public static void setOfflineDescription(String aDesc) { theOfflineDescription = aDesc; } /** * Returns the amount of money in gold coins, silver coins and theCopper * coins. * <UL> * <LI>1 silver = 10 theCopper * <LI>1 gold = 10 silver * </UL> * * @return String description of the amount of money, for example * "<I>3 gold coins, 2 silver coins</I>". Returns an empty string if * no money is present. */ public static String getDescriptionOfMoney(int aValue) { if (aValue == 0) { logger.finest("returns: no money=[]"); return ""; } int gold = aValue / 100; int silver = (aValue % 100) / 10; int copper = aValue % 10; boolean foundsome = false; String total = ""; if (copper != 0) { total = copper + " copper coin" + (copper == 1 ? "" : "s"); foundsome = true; } if (silver != 0) { if (foundsome) { total = ", " + total; } total = silver + " silver coin" + (silver == 1 ? "" : "s") + total; foundsome = true; } if (gold != 0) { if (foundsome) { total = ", " + total; } total = gold + " gold coin" + (gold == 1 ? "" : "s") + total; foundsome = true; } logger.finest("returns: [" + total + "]"); return total; } }