All pastes #675092 Raw Edit

Something

public text v1 · immutable
#675092 ·published 2007-08-29 20:28 UTC
rendered paste body
package main;

import java.util.*;

import org.jibble.pircbot.*;

public class CyberBot extends PircBot {
	boolean noGame = true, prep, inGame;
	String chan = "#cyberzone";
	ArrayList<Player> players = new ArrayList<Player>();
	ArrayList<String> ops = new ArrayList<String>();
	int[][] board = null; // 2-15 represent items
	int cur = 0;
	int round = 0;
	int itemUse = 0;
	int deadLoop = -1;
	int multiTrojan = 0;
	String mbHack = "";
	
	String gameStarter = "";
	int config = 0;
	int numItems = 0;
	ArrayList<Integer> pickedItems = new ArrayList<Integer>();
	boolean handPicked;
	int spawnInterval = 0;
	int roundsUntilSpawn = 0;
	int boardSize = 0;
	
//	Set<Integer> itemsForDesc = new TreeSet<Integer>();
	Timer turnTimer;
	String[] itemNames = new String[] {
			"", "", "Trojan (Godhammer)", "ICE", "Backdoor", "Query", "Scan", "Overclock", "Cloak", "Phone phreak", "Reboot",
			"Sector kill", "Invert", "Deadloop", "Defrag", "Magic Bullet", "White Knight", "tangerine.exe", "Magic Bullet ][",
			"Silver Cord", "Trojan (Masquerade)", "Trojan (Monday Morning Massacre)", "Minesweeper", "dir.", "Torchbearer",
			"Magic Bullet ]|[", "Flying Carpet"
	};
	int[] itemProbs = new int[] {
			0,0,8,5,5,6,5,3,6,3,3,	// 0  - 10
			4,4,6,3,8,4,1,6,		// 11 - 18
			3,7,7,2,5,3,			// 19 - 24
			3,2						// 25 - 
	};
	int itemProbsLen = 0;
	
	public static void main(String[] args) {
		@SuppressWarnings("unused")
		CyberBot bot = new CyberBot();
	}

	public CyberBot() {
		ops.add("thecalcgenius");
		ops.add("blue_tetris");
		for(int pr : itemProbs)
			itemProbsLen += pr;
		setMessageDelay(500);
		setVerbose(true);
		setName("CyberBot");
		setLogin("Cyberzone");
		setVersion("CyberBot by Calcy, v0.95; Game idea by blue_tetris");
		try {
			connect("irc.waypasteleven.com");
			identify("pa55w0rd");
			setMode(getNick(), "+B");
			joinChannel(chan);
			Thread.sleep(1000);
			setTopic(chan, "Cyberzone | Type !start to begin. If the preparation for the game seems to be frozen, type !end. | About the game: http://metanet.2.forumer.com/index.php?showtopic=16812");
		}
		catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	private void msg(String m) {
		sendMessage(chan, m);
	}

	public void onMessage(String channel, String sender, String login, String hostname, String message) {
		if(sender.equals("thecalcgenius")) {
			if(message.equals("!verboseoff")) {
				setVerbose(false);
			}
			else if(message.equals("!verboseon")) {
				setVerbose(true);
			}
			else if(message.equals("!testprobs") && noGame) {
				int[] times = new int[itemProbs.length];
				Random rnd = new Random();
				for(int i = 0; i < 1000; i++) {
					int rndNum = rnd.nextInt(itemProbsLen);
					int n, sum;
					for(n = 2, sum = 0; n < itemProbs.length; n++) {
						sum += itemProbs[n];
						if(rndNum < sum) break;
					}
					times[n]++;
				}
				msg("After 1000 iterations: ");
				for(int i = 0; i < times.length; i++) {
					msg(itemNames[i] + ": " + times[i]);
				}
			}
		}
		if(noGame && message.equals("!start")) {
			noGame = false;
			prep =  true;
			players = new ArrayList<Player>();
//			itemsForDesc = new TreeSet<Integer>();
			board = null;
			cur = 0;
			round = 0;
			itemUse = 0;
			deadLoop = -1;
			gameStarter = sender;
			turnTimer = new Timer("Prep timer");
			turnTimer.schedule(new TimerTask() {
				public void run() {
					endGame();
				}
			}, 300000);
			setMode(chan, "+N");
			msg(Colors.BLUE + "Grid active.  Type \'jack\' to log into the mainframe. " + bold(sender) + ", once all hackers have " +
					"jacked into the mainframe, type \'!load\' to boot the interface.");
		}
		else if((prep || config > 0) && (sender.equals(gameStarter) || ops.contains(sender)) && message.equals("!end")) {
			endGame();
		}
		else if(prep && message.equals("jack")) {
			for(Player p : players) {
				if(p.name.equals(sender)) {
					sendNotice(sender, "You are already playing!");
					return;
				}
			}
			if(players.size() == 12) {
				msg(Colors.RED + "Sorry, 12 players maximum.");
				return;
			}
			players.add(new Player(sender));
			voice(chan, sender);
			msg(Colors.BLUE + bold(sender) + " jacks into the mainframe.");
		}
		else if(prep && message.equals("unjack")) {
			int ind = findIndex(sender);
			if(ind != -1) {
				players.remove(ind);
				deVoice(chan, sender);
				msg(Colors.RED + bold(sender) + " unjacks himself from the mainframe.");
			}
		}
		else if(prep && (sender.equals(gameStarter) || ops.contains(sender)) && message.equals("!config")) {
			if(players.size() < 2) {
				msg(Colors.RED + "2 or more hackers required to configure and load interface.");
				return;
			}
			turnTimer.cancel();
			config = 1;
			prep = false;
			
			// DELETE
			msg(Colors.DARK_GREEN + bold(gameStarter) + " edits \"config.ini\".");
			msg(Colors.DARK_GREEN + bold(gameStarter) + ", enter the length of the board you wish to play on. The length can be " +
					"any number from " + (players.size()+1) + " to 20, inclusive. Type \"default\" to select the default value.");
			//config = 0;
		}
		else if((sender.equals(gameStarter) || ops.contains(sender)) && config > 0 && config != 100) {
			configure(message);
			return;
		}
		else if((prep || config == 100) && (sender.equals(gameStarter) || ops.contains(sender)) && message.equals("!load")) {
			//msg("config finished, loading interface...");
			if(players.size() < 2) {
				msg(Colors.RED + "2 or more hackers required to load interface.");
				return;
			}
			prep = false;
			inGame = true;
			turnTimer.cancel();
			//numItems = 0;
			//pickedItems = new ArrayList<Integer>();
			//handpicked
			//spawnInterval = 0;
			//boardSize = 0;
			if(config == 0) {
				boardSize = 4+players.size()+(players.size()/3);
				numItems = boardSize - players.size();
				spawnInterval = 2 + players.size();
	//			msg("if statement on line 182 reached, shouldn\'t happen");
			}
			roundsUntilSpawn = spawnInterval;
			config = 0;
			setTopic(chan, "Cyberzone | Game in progress. | About the game: http://metanet.2.forumer.com/index.php?showtopic=16812");
			board = new int[boardSize][boardSize];
			ArrayList<Integer> rows = new ArrayList<Integer>(), cols = new ArrayList<Integer>();
			ArrayList<String> names = new ArrayList<String>();
			for(int i = 0; i < board.length; i++) {
				rows.add(i);
				cols.add(i);
			}
			Random rnd = new Random();
			for(Player p : players) {
				int r = rows.remove(rnd.nextInt(rows.size()));
				int c = cols.remove(rnd.nextInt(cols.size()));
				board[r][c] = 1;
				p.r = r;
				p.c = c;
			}
			
			boolean calcPlay = false;
			for(Player p : players)
				if(p.name.equals("thecalcgenius"))
					calcPlay = true;

			for(int i = 0; i < numItems; i++) {
				int r = rows.remove(rnd.nextInt(rows.size()));
				int c = cols.remove(rnd.nextInt(cols.size()));
				int rndNum = rnd.nextInt(itemProbsLen);
				int n, sum;
				for(n = 2, sum = 0; n < itemProbs.length; n++) {
					sum += itemProbs[n];
					if(rndNum < sum) break;
				}
				board[r][c] = n;
				names.add(itemNames[n]);
				//if(!calcPlay) sendMessage("thecalcgenius", itemNames[n] + " is at " + ((char)(r+65)) + "" + (c+1));
			}

			for(int i = 0; i < 7; i++) Collections.shuffle(players);
			msg(Colors.BLUE + "Interface online.  Hacker avatars have been uploaded to the mainframe.");
			String temp = "";
			for(Player p : players) {
				temp += " " + p.name;
			}
			msg(Colors.BLUE + "Grid size is " + board.length + "x" + board.length + ".");
			msg(Colors.BLUE + "The hacker order will be:" + temp);
			Collections.sort(names);
			if(!names.isEmpty()) msg(Colors.DARK_GREEN + "Programs loaded: " + names.toString()); 
			//msg(Colors.BLUE + "PM \"!desc\" to me for detailed descriptions of the programs in the mainframe.");
			giveInfo();
		}
		else if(inGame && ops.contains(sender) && message.startsWith("!eject ") && itemUse == 0) {
			String name = message.split(" ")[1];
			int ind;
			if((ind = findIndex(name)) != -1) {
				if(ind == cur) {
					players.remove(ind);
					deVoice(chan, name);
					msg(Colors.RED + bold(name) + " has been forcibly ejected from the mainframe. His space will not be holed.");
					if(players.size() == 1) {
						win(players.get(0).name);
						return;
					}
					giveInfo();
				}
				else {
					players.remove(ind);
					deVoice(chan, name);
					msg(Colors.RED + bold(name) + " has been forcibly ejected from the mainframe. His space will not be holed.");
					if(players.size() == 1) {
						win(players.get(0).name);
						return;
					}
					if(ind < cur) cur--;
				}
			}
			else {
				msg(Colors.RED + bold(name) + " is not a part of this game.");
			}
		}
		else if(inGame && sender.equals(players.get(cur).name) && itemUse != 4 && itemUse != 20 && itemUse != 21) {
			if(itemUse == 2) {
				if(!validSpace(message,1)) {
					msg(Colors.DARK_GREEN + "FAT32 error. Node inaccessible. Input a different move.");
					return;
				}
				int rr = message.charAt(0) - 65, cc = Integer.parseInt(message.substring(1))-1;
				if(board[rr][cc] == 1) {
					board[rr][cc] = -1;
					itemUse = 0;
					testHack(rr, cc, sender);
					return;
				}
				board[rr][cc] = -1;
			}
			else if(itemUse == 5) {
				if(sender.equalsIgnoreCase("message")) {
					msg(Colors.DARK_GREEN + "Probable recursion has forced a program abort. Query a non-host avatar.");
					return;
				}
				Player p;
				if((p = nameExists(message)) == null) {
					msg(Colors.DARK_GREEN + "Avatar not found. Query an avatar within the database.");
					return;
				}
				sendMessage(sender, p.name + " is located at " + p.loc() + ".");
			}
			else if(itemUse == 6) {
				if(!validSpace(message,0)) {
					msg(Colors.DARK_GREEN + "FAT32 error. Node inaccessible. Input a different move.");
					return;
				}
				int rr = message.charAt(0) - 65, cc = Integer.parseInt(message.substring(1))-1;
				sendMessage(sender, "At " + message + ": " + giveInfo2(rr, cc, 1));
			}
			else if(itemUse == 9) {
				if(!validSpace(message,0)) {
					msg(Colors.DARK_GREEN + "FAT32 error. Node inaccessible. Input a different move.");
					return;
				}
				int rr = message.charAt(0) - 65, cc = Integer.parseInt(message.substring(1))-1;
				if(board[rr][cc] == 0)
					board[rr][cc] = -1;
				multiTrojan--;
				if(multiTrojan > 0) {
					msg(Colors.DARK_GREEN + multiTrojan + " left.");
					return;
				}
			}
			else if(itemUse == 10) {
				if(!validRC(message)) {
					msg(Colors.DARK_GREEN + "Target sector does not meet core criterion.  Select a different row or column.");
					return;
				}
				if(Character.isUpperCase(message.charAt(0))) {
					int rr = message.charAt(0)-65;
					for(int c = 0; c < board.length; c++) {
						if(board[rr][c] == -1)
							board[rr][c] = 0;
					}
				}
				else {
					int cc = Integer.parseInt(message) - 1;
					for(int r = 0; r < board.length; r++) {
						if(board[r][cc] == -1)
							board[r][cc] = 0;
					}
				}
			}
			else if(itemUse == 11) {
				if(!validRC(message)) {
					msg(Colors.DARK_GREEN + "Target sector does not meet core criterion.  Select a different row or column.");
					return;
				}
				if(Character.isUpperCase(message.charAt(0))) {
					int rr = message.charAt(0)-65;
					for(int c = 0; c < board.length; c++) {
						if(board[rr][c] != 1)
							board[rr][c] = -1;
					}
				}
				else {
					int cc = Integer.parseInt(message) - 1;
					for(int r = 0; r < board.length; r++) {
						if(board[r][cc] != 1)
							board[r][cc] = -1;
					}
				}
			}
			else if(itemUse == 12) {
				if(!validRC(message)) {
					msg(Colors.DARK_GREEN + "Target sector does not meet core criterion.  Select a different row or column.");
					return;
				}
				if(Character.isUpperCase(message.charAt(0))) {
					int rr = message.charAt(0)-65;
					for(int c = 0; c < board.length; c++) {
						if(board[rr][c] == -1)
							board[rr][c] = 0;
						else if(board[rr][c] == 0)
							board[rr][c] = -1;
					}
				}
				else {
					int cc = Integer.parseInt(message) - 1;
					for(int r = 0; r < board.length; r++) {
						if(board[r][cc] == -1)
							board[r][cc] = 0;
						else if(board[r][cc] == 0)
							board[r][cc] = -1;
					}
				}
			}
			else if(itemUse == 15) {
				if(!(message.equalsIgnoreCase("r") || message.equalsIgnoreCase("c") || message.equalsIgnoreCase("row") || 
						message.equalsIgnoreCase("column"))) {
					msg(Colors.DARK_GREEN + "Invalid input string. State row " + bold("(R)") + " or column " +
							bold("(C)") + ".");
					return;
				}
				Player p = players.get(cur);
				if(message.equalsIgnoreCase("r") || message.equalsIgnoreCase("row")) {
					int rr = p.r;
					for(int c = 0; c < board.length; c++) {
						if(c == p.c) continue;
						if(board[rr][c] == 1) {
							board[rr][c] = -1;
							int ind = findIndex(rr, c);
							Player np = players.get(ind);
							msg(Colors.RED + bold(p.name) + " uploads magic bullet program to " + bold(np.name) + "\'s avatar. " + 
									bold(np.name) + " is forced to hard reboot, and drops from the mainframe!");
							deVoice(chan, np.name);
							players.remove(ind);
							if(players.size() == 1) {
								win(players.get(0).name);
								return;
							}
							if(ind < cur) cur--;
						}
					}
				}
				else {
					int cc = p.c;
					for(int r = 0; r < board.length; r++) {
						if(r == p.r) continue;
						if(board[r][cc] == 1) {
							board[r][cc] = -1;
							int ind = findIndex(r, cc);
							Player np = players.get(ind);
							msg(Colors.RED + bold(p.name) + " uploads magic bullet program to " + bold(np.name) + "\'s avatar. " + 
									bold(np.name) + " is forced to hard reboot, and drops from the mainframe!");
							deVoice(chan, np.name);
							players.remove(ind);
							if(players.size() == 1) {
								win(players.get(0).name);
								return;
							}
							if(ind < cur) cur--;
						}
					}
				}
				if(cur < 0) cur += players.size();
			}
			else if(itemUse == 18) {
				if(mbHack.equals("")) {
					if(sender.equalsIgnoreCase(message)) {
						msg(Colors.DARK_GREEN + "Probable recursion has forced a program abort. Query a non-host avatar.");
						return;
					}
					if(nameExists(message) == null) {
						msg(Colors.DARK_GREEN + "Avatar not found. Query an avatar within the database.");
						return;
					}
					mbHack = message;
					msg(Colors.DARK_GREEN + "Now, enter a specific name of a row (A-" + ((char)(board.length+64)) + ") or a column " +
							"(1-" + (board.length) + "). If the hacker\'s avatar is located within that row or column, he will " +
							"be ejected from the mainframe.");
					return;
				}
				else {
					if(!validRC(message)) {
						msg(Colors.DARK_GREEN + "Target sector does not meet core criterion.  Select a different row or column.");
						return;
					}
					int ind = findIndex(mbHack);
					Player np = players.get(ind);
					mbHack = "";
					if(Character.isUpperCase(message.charAt(0))) {
						int rr = message.charAt(0)-65;
						if(np.r == rr) {
							Player p = players.get(cur);
							msg(Colors.RED + bold(p.name) + " uploads \"Jade Lightning\" to " + bold(np.name) + "\'s avatar. " + 
									bold(np.name) + " is forced to hard reboot, and drops from the mainframe!");
							deVoice(chan, np.name);
							players.remove(ind);
							if(players.size() == 1) {
								win(players.get(0).name);
								return;
							}
							if(ind < cur) cur--;
						}
					}
					else {
						int cc = Integer.parseInt(message) - 1;
						//msg(bold("cc = " + cc));
						if(np.c == cc) {
							Player p = players.get(cur);
							msg(Colors.RED + bold(p.name) + " uploads \"Jade Lightning\" to " + bold(np.name) + "\'s avatar. " + 
									bold(np.name) + " is forced to hard reboot, and drops from the mainframe!");
							deVoice(chan, np.name);
							players.remove(ind);
							if(players.size() == 1) {
								win(players.get(0).name);
								return;
							}
							if(ind < cur) cur--;
						}
					}
					
				}
			}
			else if(itemUse == 22) {
				if(!validSpace(message,0)) {
					msg(Colors.DARK_GREEN + "FAT32 error. Node inaccessible. Input a different move.");
					return;
				}
				int rr = message.charAt(0) - 65, cc = Integer.parseInt(message.substring(1))-1;
				if(board[rr][cc] == -1)
					board[rr][cc] = 0;
				multiTrojan--;
				if(multiTrojan > 0) {
					msg(Colors.DARK_GREEN + multiTrojan + " left.");
					return;
				}
			}
			else if(itemUse == 23) {
				if(!validRC(message)) {
					msg(Colors.DARK_GREEN + "Target sector does not meet core criterion.  Select a different row or column.");
					return;
				}
				if(Character.isUpperCase(message.charAt(0))) {
					int rr = message.charAt(0)-65;
					String s = "Holes in row " + message.charAt(0) + ":";
					for(int c = 0; c < board.length; c++)
						if(board[rr][c] == -1)
							s += " " + ((char)(rr+65)) + (c+1) + ",";
					if(s.endsWith(":"))
						sendMessage(sender, "No holes in row " + message.charAt(0) + ".");
					else
						sendMessage(sender, s.substring(0, s.length() - 1) + ".");
				}
				else {
					int cc = Integer.parseInt(message) - 1;
					String s = "Holes in column " + (cc+1) + ":";
					for(int r = 0; r < board.length; r++)
						if(board[r][cc] == -1)
							s += " " + ((char)(r+65)) + (cc+1) + ",";
					if(s.endsWith(":"))
						sendMessage(sender, "No holes in column " + (cc+1) + ".");
					else
						sendMessage(sender, s.substring(0, s.length() - 1) + ".");
				}
			}
			else if(itemUse == 24) {
				if(!(message.equalsIgnoreCase("r") || message.equalsIgnoreCase("c") || message.equalsIgnoreCase("row") || 
						message.equalsIgnoreCase("column"))) {
					msg(Colors.DARK_GREEN + "Invalid input string. State row " + bold("(R)") + " or column " +
							bold("(C)") + ".");
					return;
				}
				msg(Colors.DARK_GREEN + "Uploading info...");
				if(message.equalsIgnoreCase("r") || message.equalsIgnoreCase("row")) {
					for(int r = 0; r < board.length; r++)
						sendMessage(sender, giveInfoR(r, 0, 1));
				}
				else {
					for(int c = 0; c < board.length; c++)
						sendMessage(sender, giveInfoC(0, c, 1));
				}
			}
			else if(itemUse == 25) {
				if(!validSpace(message,0)) {
					msg(Colors.DARK_GREEN + "FAT32 error. Node inaccessible. Input a different move.");
					return;
				}
				//msg("25. input accepted. cur = " + cur);
				boolean found = false;
				int rr = message.charAt(0) - 65, cc = Integer.parseInt(message.substring(1))-1;
				Player p = players.get(cur);
				for(int c = 0; c < board.length; c++) {
					if(board[rr][c] == 1) {
						int ind = findIndex(rr, c);
						if(cur == ind) continue;
						//msg("victim found in 1. cur = " + cur);
						found = true;
						board[rr][c] = 0;
						Player np = players.get(ind);
						msg(Colors.RED + bold(p.name) + " rides the bomb onto " + bold(np.name) + "\'s avatar. " + bold(np.name) + 
								" stops worrying and hard reboots.");
						msg(Colors.RED + bold(np.name) + " drops from the mainframe!");
						deVoice(chan, np.name);
						players.remove(ind);
						if(players.size() == 1) {
							win(players.get(0).name);
							return;
						}
						if(ind < cur) cur--;
						//msg("victim dead, player removed. cur = " + cur);
					}
				}
				for(int r = 0; r < board.length; r++) {
					if(board[r][cc] == 1) {
						int ind = findIndex(r,cc);
						if(cur == ind) continue;
						//msg("victim found in 2. cur = " + cur);
						found = true;
						board[r][cc] = 0;
						Player np = players.get(ind);
						msg(Colors.RED + bold(p.name) + " rides the bomb onto " + bold(np.name) + "\'s avatar. " + bold(np.name) + 
								" stops worrying and hard reboots.");
						msg(Colors.RED + bold(np.name) + " drops from the mainframe!");
						deVoice(chan, np.name);
						players.remove(ind);
						if(players.size() == 1) {
							win(players.get(0).name);
							return;
						}
						if(ind < cur) cur--;
						//msg("victim dead, player removed. cur = " + cur);
					}
				}
				//msg("all victims dead. now moving player. cur = " + cur);
				if(found) {
					board[p.r][p.c] = 0;
					p.r = rr;
					p.c = cc;
					itemUse = 0;
					if(board[rr][cc] == 1) {
						testHack(rr, cc, sender);
						return;
					}
					if(board[rr][cc] > 1) {
						informItem(p, rr, cc, sender);
						return;
					}
					board[p.r][p.c] = 1;
					cur++;
					cur = cur % players.size();
					giveInfo();
					return;
				}
				else {
					board[p.r][p.c] = 0;
					msg(Colors.RED + bold(sender) + " is reported to SysOps, and drops from the mainframe.");
					deVoice(chan, sender);
					players.remove(cur);
					if(players.size() == 1) {
						win(players.get(0).name);
						return;
					}
					cur--;
				}
				//msg("25 done. cur = " + cur);
			}
			if(itemUse != 0) {
				itemUse = 0;
				cur++;
				cur = cur % players.size();
				giveInfo();
			}
		}
	}

	private void endGame() {
		prep = false;
		config = 0;
		noGame = true;
		msg(Colors.RED + "Grid deactivated.");
		for(Player p : players) {
			deVoice(chan, p.name);
		}
		setMode(chan, "-N");
	}

	private void configure(String message) {
		if(config == 1) {
			try {
				int n = Integer.parseInt(message);
				if(n <= players.size() || n > 20) {
					msg(Colors.DARK_GREEN + "Invalid board size.");
					return;
				}
				boardSize = n;
				msg(Colors.DARK_GREEN + "Now, enter the number of programs to initially place on the board. You can have between " +
						"0 and " + (boardSize-players.size()) + " programs, inclusive. Type \"default\" for the default setting.");
				config = 2;
			} catch(Exception ex) {
				if(message.equalsIgnoreCase("default")) {
					boardSize = 4 + players.size() + (players.size()/3);
					msg(Colors.DARK_GREEN + "Now, enter the number of programs to initially place on the board. You can have between " +
							"0 and " + (boardSize-players.size()) + " programs, inclusive. Type \"default\" for the default setting.");
					config = 2;
				}
				else
					msg(Colors.DARK_GREEN + "Invalid entry.");
				return;
			}
		}
		else if(config == 2) {
			try {
				int n = Integer.parseInt(message);
				if(n < 0 || (n > boardSize-players.size())) {
					msg(Colors.DARK_GREEN + "Invalid amount.");
					return;
				}
				numItems = n;
				if(numItems > 0) {
					msg(Colors.DARK_GREEN + "Do you want to pick what programs show up on the board yourself? Answer \"yes\" or " +
							"\"no\". If you choose not to pick, random programs will be loaded.");
					config = 3;
				}
				else {
					msg(Colors.DARK_GREEN + "Enter the number of rounds to wait before loading a new program into the mainframe. " +
							"Minimum is 2. Type \"none\" to eliminate spawning of items. Type \"default\" for the default setting.");
					config = 5;
				}
			} catch(Exception ex) {
				if(message.equalsIgnoreCase("default")) {
					numItems = boardSize - players.size();
					msg(Colors.DARK_GREEN + "Do you want to pick what programs show up on the board yourself? Answer \"yes\" or " +
					"\"no\". If you choose not to pick, random programs will be loaded.");
					config = 3;
				}
				else
					msg(Colors.DARK_GREEN + "Invalid entry.");
				return;
			}
			//		msg(Colors.DARK_GREEN + "Congratulations! The mainframe has been succesfully configured. Type \"!load\" to activate " +
			//			"the grid.");
			//		config = 100;
		}
		else if(config == 3) {
			if(message.equalsIgnoreCase("y") || message.equalsIgnoreCase("yes")) {
				msg(Colors.DARK_GREEN + "It\'s not implemented yet. Type no.");
			}
			else if(message.equalsIgnoreCase("n") || message.equalsIgnoreCase("no")) {
				msg(Colors.DARK_GREEN + "Enter the number of rounds to wait before loading a new program into the mainframe. " +
					"Minimum is 2. Type \"none\" to eliminate spawning of items. Type \"default\" for the default setting.");
				config = 5;
			}
		}
		else if(config == 4) {
			
		}
		else if(config == 5) {
			try {
				int n = Integer.parseInt(message);
				if(n < 2) {
					msg(Colors.DARK_GREEN + "Invalid amount.");
					return;
				}
				spawnInterval = n;
				msg(Colors.DARK_GREEN + "Enter any permanent items you wish to have at the start of the game. Choices are \"ICE\", " +
						"\"Cloak\", \"WK\" (White Knight), \"SC\" (Silver Cord), \"FC\" (Flying Carpet), or any combination of " +
						"these (enter each one separately). Once you are finished entering the combination of items, or if you " +
						"do not want any initial items, type \"done\".");
				config = 6;
			} catch(Exception ex) {
				if(message.equalsIgnoreCase("default")) {
					spawnInterval = 2 + players.size();
					msg(Colors.DARK_GREEN + "Enter any permanent items you wish to have at the start of the game. Choices are \"ICE\", " +
							"\"Cloak\", \"WK\" (White Knight), \"SC\" (Silver Cord), \"FC\" (Flying Carpet), or any combination of " +
							"these (enter each one separately). Once you are finished entering the combination of items, or if you " +
							"do not want any initial items, type \"done\".");
					config = 6;
				}
				else if(message.equalsIgnoreCase("none")) {
					spawnInterval = -1;
					msg(Colors.DARK_GREEN + "Enter any permanent items you wish to have at the start of the game. Choices are \"ICE\", " +
							"\"Cloak\", \"WK\" (White Knight), \"SC\" (Silver Cord), \"FC\" (Flying Carpet), or any combination of " +
							"these (enter each one separately). Once you are finished entering the combination of items, or if you " +
							"do not want any initial items, type \"done\".");
					config = 6;
				}
				else
					msg(Colors.DARK_GREEN + "Invalid entry.");
				return;
			}
		}
		else if(config == 6) {
			if(message.equalsIgnoreCase("ice")) {
				for(Player p : players)
					p.ice = true;
				msg(Colors.DARK_GREEN + "ICE has been loaded.");
			}
			else if(message.equalsIgnoreCase("cloak")) {
				for(Player p : players)
					p.cloak = true;
				msg(Colors.DARK_GREEN + "The Cloak program has been loaded.");
			}
			else if(message.equalsIgnoreCase("wk")) {
				for(Player p : players)
					p.knight = true;
				msg(Colors.DARK_GREEN + "The White Knight (tm) program has been loaded.");
			}
			else if(message.equalsIgnoreCase("sc")) {
				for(Player p : players)
					p.cord = true;
				msg(Colors.DARK_GREEN + "The Silver Cord has been loaded.");
			}
			else if(message.equalsIgnoreCase("fc")) {
				for(Player p : players)
					p.carpet = true;
				msg(Colors.DARK_GREEN + "The Flying Carpet has been loaded.");
			}
			else if(message.equalsIgnoreCase("done")) {
				msg(Colors.DARK_GREEN + "Congratulations! The mainframe has been succesfully configured. Type \"!load\" to activate " +
					"the grid.");
				config = 100;
			//	msg("boardSize = " + boardSize);
			//	msg("numItems = " + numItems);
			//	msg("spawnInt = " + spawnInterval);
			}
		}
	}

	private void win(String name) {
		turnTimer.cancel();
		msg(Colors.BLUE + bold(name) + " now has uncontested domain over the mainframe!");
		msg(Colors.BLUE + "Good game.");
		setMode(chan, "-N");
		setTopic(chan, "Cyberzone | Type !start to begin. If the preparation for the game seems to be frozen, type !end. | About the game: http://metanet.2.forumer.com/index.php?showtopic=16812");
		deVoice(chan, name);
		noGame = true;
		inGame = false;
		config = 0;
		return;
	}
	
	private String bold(String n) {
		return Colors.BOLD + n + Colors.BOLD;
	}

	private boolean validRC(String message) {
		try {
			int c = Integer.parseInt(message) - 1;
			return c >= 0 && c < board.length;
		} catch(Exception ex) {
			if(message.length() != 1 || !Character.isUpperCase(message.charAt(0)))
				return false;
			char r = message.charAt(0);
			return r >= 'A' && r < board.length + 65;
		}
	}
	
	private int findIndex(int r, int c) {
		for(int i = 0; i < players.size(); i++) {
			Player pl = players.get(i);
			if(pl.r == r && pl.c == c)
				return i;
		}
		return -1;
	}

	private int findIndex(String message) {
		for(int i = 0; i < players.size(); i++) {
			if(players.get(i).name.equalsIgnoreCase(message))
				return i;
		}
		return -1;
	}

	private Player nameExists(String message) {
		for(Player p : players) {
			if(p.name.equalsIgnoreCase(message))
				return p;
		}
		return null;
	}

	private boolean validSpace(String msg, int eq) { // EQ = 1 IF CHECKING IS REQUIRED
		if(msg.length() < 2 || !Character.isUpperCase(msg.charAt(0))) {
			return false;
		}
		int rr, cc;
		try {
			cc = Integer.parseInt(msg.substring(1))-1;
		}catch(Exception ex) {
			return false;
		}
		rr = msg.charAt(0) - 65;
		Player p = players.get(cur);
		if(rr < 0 || rr >= board.length || cc < 0 || cc >= board.length) {
			return false;
		}
		if(eq == 1 && p.r == rr && p.c == cc)
			return false;
		return true;
	}

	public void onPrivateMessage(String sender, String login, String hostname, String message)  {
		turnTimer.cancel();
		if(inGame && sender.equals(players.get(cur).name)) {
			if(itemUse == 4 || itemUse == 20 || itemUse == 21) {
				if(itemUse == 4) {
					if(!validSpace(message,0)) {
						sendMessage(sender, Colors.DARK_GREEN + bold(sender) + " Invalid location. Please choose " +
						"another space.");
						return;
					}
					Player p = players.get(cur);
					int rr = message.charAt(0) - 65, cc = Integer.parseInt(message.substring(1))-1;
					p.r = rr;
					p.c = cc;
					itemUse = 0;
					if(board[rr][cc] == 1) {
						testHack(rr, cc, sender);
						return;
					}
					if(board[rr][cc] > 1) {
						informItem(p, rr, cc, sender);
						return;
					}
					board[p.r][p.c] = 1;
				}
				else if(itemUse == 20) {
					if(!validSpace(message,1)) {
						sendMessage(sender, "Invalid location. Please choose another space.");
						return;
					}
					Player p = players.get(cur);
					int rr = message.charAt(0) - 65, cc = Integer.parseInt(message.substring(1))-1;
					if(p.r != rr && p.c != cc) {
						sendMessage(sender, "The location must be in your row or column!");
						return;
					}
					if(board[rr][cc] == 1) {
						board[rr][cc] = -1;
						itemUse = 0;
						testHack(rr, cc, sender);
						return;
					}
					board[rr][cc] = -1;
				}
				else if(itemUse == 21) {
					if(!validSpace(message,1)) {
						sendMessage(sender, "Invalid location. Please choose another space.");
						return;
					}
					int rr = message.charAt(0) - 65, cc = Integer.parseInt(message.substring(1))-1;
					if(board[rr][cc] == 1) {
						board[rr][cc] = -1;
						itemUse = 0;
						testHack(rr, cc, sender);
						return;
					}
					board[rr][cc] = -1;
				}
				itemUse = 0;
				cur++;
				cur = cur % players.size();
				giveInfo();
			}
			else if(itemUse == 0){
				if(!validSpace(message,1)) {
					sendMessage(sender, "Invalid location. Please enter another space.");
					return;
				}

				Player p = players.get(cur);
				int rr = message.charAt(0) - 65, cc = Integer.parseInt(message.substring(1))-1;
				if(p.r != rr && p.c != cc && !p.knight) {
					sendMessage(sender, "The location must be in your row or column!");
					return;
				}
				board[p.r][p.c] = -1;
				if(board[rr][cc] == -1) {
					p.r = rr;
					p.c = cc;
					if(p.cord) {
						msg(Colors.DARK_GREEN + bold(sender) + " slips through a hole in the mainframe, but is lifted out by The " +
								"Silver Cord. The Silver Cord is broken.");
						board[rr][cc] = 1;
						p.cord = false;
						cur++;
					}
					else if(p.carpet) {
						msg(Colors.DARK_GREEN + bold(sender) + " invokes the power of the Flying Carpet to soar over a hole at " +
								p.loc() + ".");
						board[rr][cc] = 1;
						cur++;
					}
					else {
						msg(Colors.RED + bold(sender) + " slips through the hole " + p.loc() + ", and loses all user access. " +
								bold(sender) + " drops from the mainframe!");
						deVoice(chan, sender);
						players.remove(cur);
						if(players.size() == 1) {
							win(players.get(0).name);
							return;
						}
					}
					cur = cur % players.size();
					giveInfo();
					return;
				}
				p.r = rr;
				p.c = cc;
				if(board[rr][cc] == 1) {
					testHack(rr, cc, sender);
					return;
				}
				if(board[rr][cc] > 1) {
					informItem(p, rr, cc, sender);
					return;
				}
				board[p.r][p.c] = 1;
				cur++;
				cur = cur % players.size();
				giveInfo();
			}
		}
	}
	
	/*private void testHack2(int rr, int cc, int ind) {
		Player p = players.get(ind);
		for(int i = 0; i < players.size(); i++) {
			if(i == cur) continue;
			Player np = players.get(i);
			if(np.r == rr && np.c == cc) {
				if(np.ice) {
					msg(Colors.RED + bold(p.name) + " hacks " + bold(np.name) + "\'s avatar. " + bold(np.name) + " executes ICE, " +
							"preventing the hack. " + bold(p.name) + " is revealed to SysOps and is forcibly ejected from the " +
							"mainframe!"); 
					deVoice(chan, p.name);
					players.remove(cur);
					if(players.size() == 1) {
						win(players.get(0).name);
						return;
					}
					cur = cur % players.size();
					giveInfo();
					return;
				}
				else {
					msg(Colors.RED + bold(p.name) + " hacks " + bold(np.name) + "\'s avatar. " + bold(np.name) + " drops from the " +
							"mainframe!");
					deVoice(chan, np.name);
					players.remove(i);
					if(players.size() == 1) {
						win(players.get(0).name);
						return;
					}
					if(i > cur) cur++;
					cur = cur % players.size();
					giveInfo();
					return;
				}
			}
		}
		msg("Something failed when " + p.name + " tried to take over the spot at " + rr + " " + cc);
	}
	*/

	private void testHack(int rr, int cc, String sender) {
		for(int i = 0; i < players.size(); i++) {
			if(i == cur) continue;
			Player np = players.get(i);
			if(np.r == rr && np.c == cc) {
				if(np.ice) {
					msg(Colors.RED + bold(sender) + " hacks " + bold(np.name) + "\'s avatar at " + np.loc() + ". " + bold(np.name) + 
							" executes ICE, preventing the hack. " + bold(sender) + " is revealed to SysOps and is forcibly ejected " +
							"from the mainframe!");
					deVoice(chan, sender);
					players.remove(cur);
					if(players.size() == 1) {
						win(players.get(0).name);
						return;
					}
					cur = cur % players.size();
					giveInfo();
					return;
				}
				else {
					msg(Colors.RED + bold(sender) + " hacks " + bold(np.name) + "\'s avatar at " + np.loc() + ". " + bold(np.name) + 
							" drops from the mainframe!");
					deVoice(chan, np.name);
					players.remove(i);
					if(players.size() == 1) {
						win(players.get(0).name);
						return;
					}
					if(i > cur) cur++;
					cur = cur % players.size();
					giveInfo();
					return;
				}
			}
		}
		//msg("Something failed when " + sender + " tried to take over the spot at " + rr + " " + cc);
	}

	private void informItem(Player p, int rr, int cc, String sender) {
		if(board[rr][cc] == 2) {
			itemUse = 2;
			msg(Colors.DARK_GREEN + bold(sender) + " downloads and executes the Trojan virus, GodHammer Edition.");
			msg(Colors.DARK_GREEN + bold(sender) + ", input the name of a space publically.  The space you name will be holed.  If " +
					"an avatar or item is in that space, it slips from the mainframe.");
			board[p.r][p.c] = 1;
			return;
		}
		else if(board[rr][cc] == 3) {
			msg(Colors.DARK_GREEN + bold(sender) + " downloads and installs Intrustion Counter-Electronics. " + bold(sender) + 
					" cannot be hacked. Avatars hacking " + bold(sender) + " will instead be revealed to system operators and " +
							"ejected from the mainframe.");
			p.ice = true;
		}
		else if(board[rr][cc] == 4) {
			itemUse = 4;
			msg(Colors.DARK_GREEN + bold(sender) + " locates a backdoor in the mainframe.");
			msg(Colors.DARK_GREEN + bold(sender) + ", using PM, input the name of a space.  Your avatar will be relocated to the " +
					"space you input. If this space is holed, the hole will be removed and your avatar will land safely. If this " +
					"space contains an avatar, you hack them. If this space contains a program, you instantly run that program. The " +
					"space where you originated from will be holed.");
			board[p.r][p.c] = -1;
			return;
		}
		else if(board[rr][cc] == 5) {
			itemUse = 5;
			msg(Colors.DARK_GREEN + bold(sender) + " downloads and executes a query relay.");
			msg(Colors.DARK_GREEN + bold(sender) + ", input the name of a hacker publically. The query will privately reveal the " +
					"exact location of that hacker's avatar. " + Colors.BOLD + "Hacker names are case-sensitive.");
			board[p.r][p.c] = 1;
			return;
		}
		else if(board[rr][cc] == 6) {
			itemUse = 6;
			msg(Colors.DARK_GREEN + bold(sender) + " downloads and executes a scan relay.");
			msg(Colors.DARK_GREEN + bold(sender) + ", input the name of a space publically. The scan will retrieve information for " +
					"you as if you were in that space. The information will arrive privately.");
			board[p.r][p.c] = 1;
			return;
		}
		else if(board[rr][cc] == 7) {
			msg(Colors.DARK_GREEN + bold(sender) + " overclocks the deck, and immediately takes another turn.");
			board[p.r][p.c] = 1;
			giveInfo3();
			return;
		}
		else if(board[rr][cc] == 8) {
			msg(Colors.DARK_GREEN + bold(sender) + " downloads and installs a cloaking program, and is now invisible to normal " +
					"detection.");
			p.cloak = true;
		}
		else if(board[rr][cc] == 9) {
			itemUse = 9;
			multiTrojan = board.length;
			msg(Colors.DARK_GREEN + bold(sender) + " finds an insecure port to phone phreak the mainframe.");
			msg(Colors.DARK_GREEN + bold(sender) + ", enter " + board.length + " spaces, one by one. Each space you type will be " +
					"holed unless there is an avatar or an item in that space.");
			board[p.r][p.c] = 1;
			return;
		}
		else if(board[rr][cc] == 10) {
			itemUse = 10;
			msg(Colors.DARK_GREEN + bold(sender) + " finds a gap in code, allowing for a safe reboot.");
			msg(Colors.DARK_GREEN + bold(sender) + ", publically input the name of a row (A-" + 
					((char)(board.length+64)) + ") or a column (1-" + (board.length) + "). The holes in that sector will become " +
					"free grid spaces again.");
			board[p.r][p.c] = 1;
			return;
		}
		else if(board[rr][cc] == 11) {
			itemUse = 11;
			msg(Colors.DARK_GREEN + bold(sender) + " finds a gap in code, allowing for a potent sector kill.");
			msg(Colors.DARK_GREEN + bold(sender) + ", publically input the name of a row (A-" + 
					((char)(board.length+64)) + ") or a column (1-" + (board.length) + "). The free spaces in this sector become " +
					"holes. Any program on a space in this sector is dropped from the mainframe. Avatar spaces are not " +
					"affected.");
			board[p.r][p.c] = 1;
			return;
		}
		else if(board[rr][cc] == 12) {
			itemUse = 12;
			msg(Colors.DARK_GREEN + bold(sender) + " finds a gap in code, allowing for a strategic inversion.");
			msg(Colors.DARK_GREEN + bold(sender) + ", publically input the name of a row (A-" + 
					((char)(board.length+64)) + ") or a column (1-" + (board.length) + "). The free spaces in this sector become " +
							"holes, while holed spaces become free spaces. Spaces containing items or avatars are not affected.");
			board[p.r][p.c] = 1;
			return;
		}
		else if(board[rr][cc] == 13) {
			deadLoop = cur;
			msg(Colors.DARK_GREEN + bold(sender) + " discovers a dormant deadloop within the mainframe and executes it. As a result, " +
					"other hackers will not receive information about their surroundings for one full round.");
		}
		else if(board[rr][cc] == 14) {
			ArrayList<int[]> holes = new ArrayList<int[]>();
			for(int r = 0; r < board.length; r++)
				for(int c = 0; c < board.length; c++)
					if(board[r][c] == -1)
						holes.add(new int[] {r,c});
			int n = (int)(Math.round(holes.size()/2.0));
			for(int i = 0; i < 7; i++) Collections.shuffle(holes);
			for(int i = 0; i < n; i++)  {
				int[] loc = holes.remove(0);
				board[loc[0]][loc[1]] = 0;
			}
			msg(Colors.DARK_GREEN + bold(sender) + " downloads and executes a defrag program.  A random set of half of the holed " +
					"grid spaces are reconfigured, becoming free spaces again.");
		}
		else if(board[rr][cc] == 15) {
			itemUse = 15;
			msg(Colors.DARK_GREEN + bold(sender) + " downloads and executes the magic bullet program.");
			msg(Colors.DARK_GREEN + bold(sender) + ", publically declare \"column\" or \"row\".  Any avatars in the same column or " +
					"row (whichever was declared) as you are forced to hard reboot, removing them from the mainframe.  Remember " +
					"that your column is a number and your row is a letter.");
			board[p.r][p.c] = 1;
			return;
		}
		else if(board[rr][cc] == 16) {
			p.knight = true;
			msg(Colors.DARK_GREEN + bold(sender) + " downloads and installs White Knight (tm). You can now move to any location " +
					"during your turn, instead of a location within the same row or column.");
		}
		else if(board[rr][cc] == 17) {
			for(int r = 0; r < board.length; r++) 
				for(int c = 0; c < board.length; c++)
					if(board[r][c] == 0)
						board[r][c] = -1;
			msg(Colors.DARK_GREEN + bold(sender) + " downloads and executes a silhouette copy of the lengendary virus " +
					"\"tangerine.exe\". Every space on the mainframe has been holed, except spaces containing avatars or items. " +
					"A single cryptic message arrives in the program's readme text file: \"Never forget her. Never forget her. The " +
					"Tangerine.");
		}
		else if(board[rr][cc] == 18) {
			itemUse = 18;
			msg(Colors.DARK_GREEN + bold(sender) + " downloads and executes the magic bullet ][ program.");
			msg(Colors.DARK_GREEN + bold(sender) + ", first name a hacker. " + bold("Names are case-sensitive."));
			board[p.r][p.c] = 1;
			return;
		}
		else if(board[rr][cc] == 19) {
			p.cord = true;
			msg(Colors.DARK_GREEN + bold(sender) + " downloads and installs The Silver Cord. " + bold(sender) + " is now immune " +
					"to slipping through a hole. After slipping through a hole once, The Silver Cord will break.");
		}
		else if(board[rr][cc] == 20) {
			itemUse = 20;
			msg(Colors.DARK_GREEN + bold(sender) + " downloads and executes the Trojan virus, Masquerade Edition. ");
			msg(Colors.DARK_GREEN + bold(sender) + ", PM me the name of a space that is in your same row or column. This space " +
				"will be holed. If an avatar or program is on that space, they will be dropped from the mainframe.");
			board[p.r][p.c] = 1;
			return;
		}
		else if(board[rr][cc] == 21) {
			itemUse = 21;
			msg(Colors.DARK_GREEN + bold(sender) + " downloads and executes the Trojan virus, triple-M edition. ");
			msg(Colors.DARK_GREEN + bold(sender) + ", PM me the name of a space. This space will be holed. If an avatar or program " +
					"is on that space, they will be dropped from the mainframe.");
			board[p.r][p.c] = 1;
			return;
		}
		else if(board[rr][cc] == 22) {
			itemUse = 22;
			multiTrojan = board.length;
			msg(Colors.DARK_GREEN + bold(sender) + " finds a minesweeper.");
			msg(Colors.DARK_GREEN + bold(sender) + ", enter " + board.length + " spaces, one by one. If that space is a hole, " +
					"it will be turned into a free space.");
			board[p.r][p.c] = 1;
			return;
		}
		else if(board[rr][cc] == 23) {
			itemUse = 23;
			msg(Colors.DARK_GREEN + bold(sender) + " gains access to the parent directory, allowing for the execution of a " +
					"\"dir.\" command.");
			msg(Colors.DARK_GREEN + bold(sender) + ", publically input the name of a row (A-" + 
					((char)(board.length+64)) + ") or a column (1-" + (board.length) + "). You will privately receive exact locations" +
					" of any holes in that row or column.");
			board[p.r][p.c] = 1;
			return;
		}
		else if (board[rr][cc] == 24) {
			itemUse = 24;
			msg(Colors.DARK_GREEN + bold(sender) + " downloads and executes Torchbearer (tm) by JourneymanWorks, who provide the " +
					"latest in deckrunning technology at affordable prices!");
			msg(Colors.DARK_GREEN + bold(sender) + ", publically declare \"column\" or \"row\". The Torchbearer will retrieve " +
					"information about every column or every row (whichever was selected) as if you were viewing those sectors. " +
					"This information will arrive privately.");
			board[p.r][p.c] = 1;
			return;
		}
		else if(board[rr][cc] == 25) {
			itemUse = 25;
			msg(Colors.DARK_GREEN + bold(sender) + " downloads and executes \"Strangelove\", the third magic bullet virus.");
			msg(Colors.DARK_GREEN + bold(sender) + ", enter the name of a space. If any avatar is on the same column or row, they " +
					"will be ejected from the mainframe, and you will backdoor onto that space. However, if there are no avatars " +
					"on that column or row, you will be reported to SysOps and will be ejected from the mainframe.");
			board[p.r][p.c] = 1;
			return;
		}
		else if(board[rr][cc] == 26) {
			p.carpet = true;
			msg(Colors.DARK_GREEN + bold(sender) + " downloads and installs The Flying Carpet. " + bold(sender) + " is now immune " +
					"to slipping through a hole for the rest of the game. However, if he is rescued from a hole, the mainframe " +
					"will publically say what square he is in.");
		}
		board[p.r][p.c] = 1;
		cur++;
		cur = cur % players.size();
		giveInfo();
	}
	
	private String giveInfoR(int rr, int cc, int sc) {
		String pl = "", i = "";
		int h = 0;
		for(int c = 0; c < board.length; c++) {
			if(sc == 0 && c == cc) continue;
			if(board[rr][c] == -1) h++;
			else if(board[rr][c] == 1) {
				Player pp = findPlayer(rr,c);
				if(!pp.cloak) pl += pp.name + ", ";
			}
			else if(board[rr][c] > 1) i += itemNames[board[rr][c]] + ", ";
		}
		StringBuffer s = new StringBuffer();
		if(pl.length() > 0)
			s.append(pl.substring(0, pl.length() - 2));
		if(i.length() > 0) {
			if(pl.length() > 0) s.append(", ");
			s.append(i.substring(0, i.length() - 2));
		}
		if(h > 0) {
			if(pl.length() > 0 || i.length() > 0) s.append(" and ");
			s.append("" + h + (h == 1? " hole": " holes"));
		}
		if(!pl.equals("") || h > 0 || !i.equals("")) s.append(" in row " + ((char)(rr+65)) + ". ");
		return s.toString();
	}
	
	private String giveInfoC(int rr, int cc, int sc) {
		String pl = "", i = "";
		int h = 0;
		for(int r = 0; r < board.length; r++) {
			if(sc == 0 && r == rr) continue;
			if(board[r][cc] == -1) h++;
			else if(board[r][cc] == 1) {
				Player pp = findPlayer(r, cc);
				if(!pp.cloak) pl += pp.name + ", ";
			}
			else if(board[r][cc] > 1) i += itemNames[board[r][cc]] + ", ";
		}
		StringBuffer s = new StringBuffer();
		if(pl.length() > 0)
			s.append(pl.substring(0, pl.length() - 2));
		if(i.length() > 0) {
			if(pl.length() > 0) s.append(", ");
			s.append(i.substring(0, i.length() - 2));
		}
		if(h > 0) {
			if(pl.length() > 0 || i.length() > 0) s.append(" and ");
			s.append("" + h + (h == 1? " hole": " holes"));
		}
		if(!pl.equals("") || h > 0 || !i.equals("")) s.append(" in column " + (cc+1) + ". ");
		return s.toString();
	}
	
	private String giveInfo2(int rr, int cc, int sc) {
		return giveInfoR(rr, cc, sc) + giveInfoC(rr, cc, sc);
	}
	
	private void notify30() {
		turnTimer.cancel();
		msg(Colors.BLUE + bold(players.get(cur).name) + ", you have 30 seconds to make your move. You will be ejected from the " +
				"mainframe if you do not make one.");
		turnTimer = new Timer("Final timer");
		turnTimer.schedule(new TimerTask() {
			public void run() {
				noMoveTaken();
			}
		}, 30000);
	}
	
	private void noMoveTaken() {
		turnTimer.cancel();
		Player p = players.get(cur);
		msg(Colors.RED + "The mainframe was unable to receive a PING acknowledgement from " + bold(p.name) + ". As a result, " + 
				bold(p.name) + " has been gracefully unjacked from the mainframe. His space will not be holed.");
		board[p.r][p.c] = 0;
		deVoice(chan, p.name);
		players.remove(cur);
		if(players.size() == 1) {
			win(players.get(0).name);
			return;
		}
		cur = cur % players.size();
		giveInfo();
	}
	
	private void giveInfo() {
		if(cur == 0) {
			msg(Colors.BLUE + Colors.BOLD + "Round " + (++round) + ".");
			if(roundsUntilSpawn == 0 && spawnInterval != -1) {
				if(spawnInterval > 3) spawnInterval--;
				roundsUntilSpawn = spawnInterval;
				int r, c;
				Random rnd = new Random();
				int rndNum = rnd.nextInt(itemProbsLen);
				int n, sum;
				for(n = 2, sum = 0; n < itemProbs.length; n++) {
					sum += itemProbs[n];
					if(rndNum < sum || n == itemProbs.length - 1) break;
				}
				r = rnd.nextInt(board.length);
				c = rnd.nextInt(board.length);
				while(board[r][c] == 1) {
					r = rnd.nextInt(board.length);
					c = rnd.nextInt(board.length);
				}
				board[r][c] = n;
				msg(Colors.DARK_GREEN + "Program loaded: " + itemNames[n] + ".");
			}
			else roundsUntilSpawn--;
		}
		msg(Colors.BLUE + bold(players.get(cur).name) + "\'s turn.");
		giveInfo3();
	}
	
	private void giveInfo3() {
		turnTimer = new Timer("Initial timer");
		turnTimer.schedule(new TimerTask() {
			public void run() {
				notify30();
			}
		}, 60000);
		Player p = players.get(cur);
		String s = "You are at " + p.loc() + ". ";
		if(deadLoop == cur) deadLoop = -1;
		if(deadLoop == -1) s += giveInfo2(p.r, p.c, 0);
		else s += "You are adrift in a maelstrom of useless code. ";
		s += "Where to?";
		sendMessage(p.name, s);
	}

	private Player findPlayer(int r, int c) {
		for(Player p : players) {
			if(p.r == r && p.c == c)
				return p;
		}
		return null;
	}

	public class Player {
		int r;
		int c;
		String name;
		boolean cloak;
		boolean ice;
		boolean knight;
		boolean cord;
		boolean carpet;
		//ArrayList<String> cookie = new ArrayList<String>();

		public Player(String n) {
			name = n;
		}

		public String loc() {
			return "" + ((char)(r+65)) + (c+1);
		}
		
		public String toString() {
			return name;
		}
	}
}