private void setup() {
		Thread thread = null;
		
		// snag this machine's real IP address
		try {
			// Get the address and hostname, so you can report it
			InetAddress addr = InetAddress.getLocalHost(); // Get IP Address
			this.computer = addr.getHostName(); // get computer name
			System.out.println("");
			System.out.println(this.computer); // print computer name
			System.out.println("");
		}
		catch (final UnknownHostException e) {
			System.out.println("--- Stack Trace ---");
			e.printStackTrace();
		}

		// Tell Us where the program is running from
		System.out.println("Current Working Directory: " + new File("").getAbsolutePath());
		System.out.println("MAIN_DIR: " + MAIN_DIR);

		System.out.println("");

		System.out.println("Important!: The two above should be the same if the top is where you have the program AND it's data");

		System.out.println("");

		// search for needed directories and files (using predefined names and
		// locations)
		ArrayList<File> directories = new ArrayList<File>();
		ArrayList<File> files = new ArrayList<File>();

		// directories
		directories.add(new File(MAIN_DIR));
		directories.add(new File(DATA_DIR));

		directories.add(new File(BACKUP_DIR));
		directories.add(new File(BOARD_DIR));
		directories.add(new File(CONFIG_DIR));
		directories.add(new File(HELP_DIR));
		directories.add(new File(MAP_DIR));
		directories.add(new File(MOTD_DIR));
		directories.add(new File(SPELL_DIR));
		directories.add(new File(THEME_DIR));
		directories.add(new File(LOG_DIR));
		directories.add(new File(SESSION_DIR));
		directories.add(new File(WORLD_DIR));

		// check that the directories exist, if not create them
		for (final File dir : directories) {
			if (!dir.exists()) {
				boolean success = dir.mkdir();

				if (success) {
					System.out.println("Directory: " + dir.getAbsolutePath() + " created");
				}
			}
			else {
				System.out.println("Directory: " + dir.getAbsolutePath() + " exists.");
			}
		}

		/*
		 * files.add(new File(ALIASES_FILE)); files.add(new File(BANLIST_FILE));
		 * files.add(new File(CHANNELS_FILE)); files.add(new File(CONFIG_FILE));
		 * files.add(new File(FORBIDDEN_FILE));
		 * 
		 * // check that the files exist, if not create them for (final File
		 * file : directories) { boolean success = false;
		 * 
		 * try { success = file.createNewFile(); } catch (IOException e1) { //
		 * TODO Auto-generated catch block e1.printStackTrace(); }
		 * 
		 * if (success) { System.out.println("File: " + file.getAbsolutePath() +
		 * " created"); } else { System.out.println("file: " +
		 * file.getAbsolutePath() + " exists."); } }
		 */

		System.out.println("");

		// TODO this is a kludge to set the ruleset based on the module
		if (module != null) {
			if (module.getName().equals("Fallout Equestria")) {
				rules = mud.rulesets.foe.FOESpecial.getInstance();
				rs_special = true;
			}
			else rules = D20.getInstance();
		}
		else rules = D20.getInstance();

		Player.ruleset = rules; // set static Ruleset reference in Player

		// if this is the first run (as indicated by setup parameter)
		if (firstRun) {
			System.out.print("Running initial setup...");
			create_data();
			System.out.println("Done");
		}

		// Logging
		if ( logging ) {
			Logger logger = new Logger();
			
			logger.addConfigOption("debug", debug);
			logger.addConfigOption("log_chat", log_chat);
			logger.addConfigOption("log_debug", log_debug);
			
			// instantiate log objects (using no max length, no buffer -- for now)
			this.log = new Log("log", false);
			
			logger.register( this.log );                // character actions, etc
			logger.register( new Log("error", false) ); // any software errors that occur
			
			if( log_debug ) logger.register( new Log("debug", false) ); // any and all debugging
			if( log_chat )  logger.register( new Log("chat", false) );  // all chat messages
			
			attach( logger );
			
			// open log files for writing
			this.logger.start();
			
			debug("Logs Initialized.");
		}
		else {
			// tell us it's disabled
			debug("Logging Disabled.");
		}

		debug(""); // formatting

		if (module != null) {
			debug("Module: " + module.getName() + " v" + module.getVersion());
		}

		debug(""); // formatting

		// TODO should it always load a theme or only when specified?

		// Theme Loading
		this.loadTheme(THEME_FILE);
		
		// TODO resolve this somehow, perhaps those aren't appropriate pieces of a theme
		// NOTE: going to set these in loadTheme for now (8-8-2015)
		/*day = 0;
		month = 0;
		year = 0;*/

		//this.month_name = MONTH_NAMES[month - 1];
		//this.year_name = years.get(year);

		debug(""); // formatting

		debug("Using database " + this.DB_FILE);

		debug(""); // formatting

		// initialize player array
		this.players = new ArrayList<Player>(max_players);

		// Load Databases/Persistent Data into memory
		//
		// Note: Does it make any sense to replace loading all this into memory
		// using a buffered reader and loading objects as it goes? It would be
		// really
		// wise to implement configurable auto db-saving here
		//

		// error message hashmap loading
		final String[] errors = Utils.loadStrings(ERRORS_FILE);
		for (final String e : errors) {
			final String[] working = e.split(":");

			if (working.length >= 2) {
				debug("Error(number): " + working[0]);
				debug("Error(message): " + working[1]);
				
				this.Errors.put(Integer.parseInt(working[0]), working[1]);
			}
		}
		
		debug("");
		
		// load spells
		if (magic) {
			loadSpells(Utils.loadStrings(SPELLS_FILE));
			debug("Spells Loaded!");
		}
		else debug("Magic Disabled!");
		
		debug("");
		
		debug("Loading Zones...");
		
		debug("");

		// Load Zones (only doing this here, because Rooms may be in a zone, and
		// so
		// by loading Zones first then rooms can be placed in them by the
		// ObjectLoader
		loadZones(WORLD_DIR + world + "\\zones.txt");

		debug("");

		debug("Loading Races...");
		
		debug("");

		// TODO get rid of this kludge and deal with JSON stuff
		boolean test = false;

		if (!test && !firstRun) {
			loadRaces();
		}
		else {
			for (int i = 0; i < 8; i++) races.add(Races.getRace(i));
		}
		
		debug("");

		debug("Loading Database...");

		final ObjectLoader loader = new ObjectLoader(this, objectDB);

		// Load everything from databases by flag
		loader.loadObjects(loadListDatabase(DB_FILE), logger);

		debug("Database Loaded!");
		debug("");
		
		// TODO what do these functions output?
		
		// Post-Room Loading (i.e. place within the game world)
		loadExits();          // load exits
		placeThingsInRooms(); // load thing
		loadItems();          // load items
		// stackItems(); // put items inside of the objects they belong

		// objectDB.stackItems(); // put items inside of the objects they belong

		debug("");

		debug("Filling shops with merchandise!");
		
		fillShops(); // put stuff in merchant's shops (deprecated?)
		
		debug("");
		
		debug("Adding Listeners to Rooms");
		
		// make sure npcs are added to listeners
		for (final NPC npc : objectDB.getNPCs()) {
			if (npc != null) {
				debug("NPC(" + npc.getName() + "): " + npc.getLocation());
				
				final Room room = getRoom(npc.getLocation());
				
				if( room != null ) room.addListener(npc);
				else               debug("Missing ROOM (#" + npc.getLocation() + ")");
			}
			else debug("NULL NPC?");
		}

		// TODO remove later
		CNode opt1 = new CNode(1, "What's up?", "Nothing. Much");
		CNode opt2 = new CNode(2, "I'd like to buy something", "Sure.", null, true);
		CNode opt3 = new CNode(3, "Bye.", "See ya.", null, true);

		opt1.addOptions(opt1, opt2, opt3);

		// add conversations?
		for (final NPC npc : objectDB.getNPCs()) {
			if (npc != null) {
				// TODO rip this out later, it doesn't really belong here

				// generate and add conversations
				CNode opt0 = new CNode(0, "", npc.greeting, Utils.mkList(opt1, opt2, opt3));

				npc.setConversation(opt0);
			}
		}
		
		// instantiate banned ip list
		banlist = loadListDatabase(BANLIST_FILE);

		// instantiate forbidden names list
		forbiddenNames = loadListDatabase(FORBIDDEN_FILE);

		// load configuration data (file -- default.config)
		// loadConfiguration(CONFIG_DIR + "config.txt", configs); ?
		/*
		 * for (final String s : loadListDatabase(CONFIG_DIR + "config.txt")) {
		 * final String[] configInfo = s.split(":"); String name =
		 * Utils.trim(configInfo[0]); String value = Utils.trim(configInfo[1]);
		 * value = value.substring(0, value.indexOf('#')); config.put(name,
		 * value); }
		 */

		// print out config map
		// debug(config.entrySet());

		debug("");
		
		// for help/topic file loading
		final StringBuilder sb = new StringBuilder();
		Counter c = new Counter(0, 0, 3);
		
		// help file loading
		debug("Loading Help Files... ");
		System.out.println("");
		
		System.out.println("Help Files");
		System.out.println("----------------------------------------");
		
		for (final String helpFileName : generateHelpFileIndex()) {
			if( c.isMax() ) {
				System.out.println( sb.toString().trim() );
				sb.delete(0,  sb.length());
				c.reset();
			}
			else {
				sb.append(Utils.padRight(helpFileName, ' ', 25)).append(" ");
				c.increment();
			}
			
			final String[] helpfile = Utils.loadStrings(this.HELP_DIR + helpFileName);
			
			final String key = helpfile[0];
			
			helpTable.put(key, helpfile);

			// HelpFile hf = new HelpFile(helpfile[0], helpfile);

			// TODO consider a config option for this
			// check to see if the mapping made it into the table
			/*if( helpTable.containsKey(key) && helpTable.get(key) != null ) {
				debug(Utils.padRight(helpFileName, ' ', 20) + " -- HelpFile Loaded!");
			}
			else {
				
			}*/
		}

		// cleanup
		System.out.println( sb.toString().trim() );
		sb.delete(0,  sb.length());
		c.reset();
		
		System.out.println("");
		debug("Help Files Loaded!");

		debug("");

		// topic file loading
		debug("Loading Topic Files... ");
		System.out.println("");
		
		System.out.println("Topic Files");
		System.out.println("----------------------------------------");
		
		for (final String topicFileName : generateTopicFileIndex()) {
			if( c.isMax() ) {
				System.out.println( sb.toString().trim() );
				sb.delete(0,  sb.length());
				c.reset();
			}
			else {
				sb.append(Utils.padRight(topicFileName, ' ', 25)).append(" ");
				c.increment();
			}

			final String[] topicfile = Utils.loadStrings(this.TOPIC_DIR + topicFileName);

			topicTable.put(topicfile[0], topicfile);

			// TODO consider a config option for this
			// check to see if the mapping made it into the table
			/*
			 * if( topicTable.containsKey( topicfile[0] ) ) {
			 * debug("Topic Loaded!"); } else debug("Error!");
			 */
		}
		
		// cleanup
		System.out.println( sb.toString().trim() );
		sb.delete(0,  sb.length());
		c.reset();
		
		System.out.println("");
		debug("Topic Files Loaded!");

		debug("");

		debug("Colors (ANSI): " + ANSI.getColors().keySet()); // DEBUG
		debug("Colors (XTERM): " + XTERM256.getColors().keySet()); // DEBUG

		// set up display colors (ANSI, XTERM256)
		setDisplayColor("exit", "green", "green");
		setDisplayColor("player", "magenta", "orange");
		setDisplayColor("npc", "cyan", "cyan");
		setDisplayColor("thing", "yellow", "yellow");
		setDisplayColor("room", "green", "other");
		setDisplayColor("item", "yellow", "yellow");
		setDisplayColor("creature", "cyan", "cyan");
		setDisplayColor("quest", "cyan", "cyan");

		debug("Object Colors: " + displayColors.entrySet()); // DEBUG
		
		debug("");
		
		/*
		 * Command Mapping
		 * 
		 * Ideally this would be done for all commands and the cmd parser would
		 * simply check aliases, get the actual name, and call
		 * commandMap.get(name).execute(arg, client)
		 * 
		 * I really need to be careful with access permissions, or I need to
		 * facilitate some means to get just a basic interface
		 * 
		 * NOTE: these need to be kept up to date with the implementation in the
		 * functions cmd_x, the plan is to eventually remove those and the cmd
		 * interpreter to a major extent so that I am mostly just doing this:
		 * 
		 * commandMap.get(cmd).execute(arg, client)
		 * 
		 * for each command. The point being that I can reduce the amount of
		 * work I need to add a new command to virtually nil if I use existing
		 * features. In fact that bit just above doesn't need any changing.
		 * Although I might need to explicity handle aliases better.
		 */
		addCommand("@access",   new AccessCommand());   //
		addCommand("attack",    new AttackCommand());   //
		addCommand("cast",      new CastCommand());     //
		addCommand("greet",     new GreetCommand());    //
		addCommand("mail",      new MailCommand());     //
		addCommand("say",       new SayCommand());      //
		addCommand("staff",     new StaffCommand());    //
		addCommand("@teleport", new TeleportCommand()); //
		
		// TODO not sure the best way to store/access aliases for Command objects
		addAlias("attack", "kill");
		
		debug("Mapped Commands: " + commandMap.keySet()); // Print out all the command mappings (DEBUG)

		/* Set up Command Aliases */
		loadAliases(this.ALIASES_FILE);
		
		for (final String alias : aliases.keySet()) {
			String command = aliases.get(alias);
			
			if( c.isMax() ) {
				System.out.println( sb.toString().trim() );
				sb.delete(0,  sb.length());
				c.reset();
			}
			else {
				sb.append(Utils.padRight(alias + " -> " + command, ' ', 26)).append(" ");
				c.increment();
			}
		}

		// cleanup
		System.out.println( sb.toString().trim() );
		sb.delete(0,  sb.length());
		c.reset();

		debug("Aliases: " + aliases.keySet());

		// TODO rewrite board loading as state based system and change format of files

		/* bulletin board(s) */
		loadBoards();
		
		/* auctions ? */
		auctions = new ArrayList<Auction>();

		debug("");

		// Time Loop
		// cpu: -for now, appears marginal-
		final Date startDate = new Date(month, day, year);
		final Time startTime = new Time(game_hour, game_minute, 0);

		game_time = new TimeLoop(this, DAYS, startDate, startTime);
		
		thread = new Thread(game_time, "time");
		thread.start();
		
		this.threads.put(thread.getName(), thread);
		
		debug("Time (Thread) Started!");

		// Weather Loop
		// cpu: ~20%
		// System.out.println("Weather (Thread) Started!");

		if (queued_commands) {
			cmdQueue = new ConcurrentLinkedQueue<CMD>();
			cmdExec = new CommandExec(this, cmdQueue);
			
			thread = new Thread(cmdExec, "command_exec");
			thread.start();
			
			this.threads.put(thread.getName(), thread);
			
			debug("Command Execution (Thread) Started!");
		}

		// System.out.println("");
		debug("");

		if (testing_enabled) {
			weather_test(); // set up basic weather system of sorts (should generally be okay on a new database all though it may not be desired)
			world_test(); // set up some testing (probably not valid on your database)
		}

		debug("");

		loadChannels(CHANNELS_FILE); // load chat channels
		
		debug("Loaded chat channels.");
		
		debug("");

		if ( use_accounts ) {
			debug("Loading Accounts...");

			loadAccounts(ACCOUNT_DIR); // load Player Accounts

			debug("Done");

			debug("");
			
			if (acctMgr.numAccounts() == 0) {
				debug("No accounts.");
			}
		}

		// Initialize Program Interpreter
		this.pgm = new ProgramInterpreter(this, true);

		// Coins.debug();
		
		// scripted commands
		addCommand("@dbref",
				new ScriptedCommand("get object dbref", pgm, new Script("{dbref:{&arg}}")));
		addCommand("@list", new ScriptedCommand("", pgm, new Script("{list:{&arg},{&this}}")));

		debug("");

		// TODO resolve the problems that make this not work
		if ( module != null ) {
			debug("Module: " + module.getName());

			final Ruleset modRS = module.getRuleset();

			// just going to be extra careful here...
			if (modRS != null) {
				debug("Ruleset: " + modRS.getName());

				if( module.hasClasses() ) {
					// TODO debug?
					System.out.println(Arrays.asList(modRS.getClasses()));

					for (final PClass pcl : modRS.getClasses()) {
						numPlayersOnlinePerClass.put(pcl, 0);
					}
				}
			}

			debug("");
		}

		/* Server Initialization (network level) */

		// TODO convert printlns to debug calls

		// almost everything that needs to be loaded should be done before here
		debug("Creating server on port " + port);
		
		// TODO it'd be good to caught server launch failures in here, maybe?
		this.s = new Server(this, port);
		
		thread = new Thread(this.s, "server");
		thread.start();
		
		this.threads.put(thread.getName(), thread);
		
		debug("Server (Thread) Started!");
		
		debug("");

		debug("Server> Setup Done.");

		debug("Next Database Reference: " + objectDB.peekNextId());

		debug(Utils.checkMem());

		debug("");
		
		// Initialize Console Monitor?
		if( console_enabled ) {
			cmon = new ConsoleMonitor(this);
		}
	}