| @@ -0,0 +1,95 @@ | ||
| # vorestation | ||
|
|
||
| [Forums](http://forum.vore-station.net/) - [Wiki](http://wiki.vore-station.net/) | ||
|
|
||
| VOREStation is a fork of the Polaris code branch, itself a fork of the Baystation12 code branch, for the game Spacestation13. | ||
|
|
||
| --- | ||
|
|
||
| ### LICENSE | ||
| VOREStation is licensed under the GNU Affero General Public License version 3, which can be found in full in LICENSE-AGPL3.txt. | ||
|
|
||
| Commits with a git authorship date prior to `1420675200 +0000` (2015/01/08 00:00) are licensed under the GNU General Public License version 3, which can be found in full in LICENSE-GPL3.txt. | ||
|
|
||
| All commits whose authorship dates are not prior to `1420675200 +0000` are assumed to be licensed under AGPL v3, if you wish to license under GPL v3 please make this clear in the commit message and any added files. | ||
|
|
||
| If you wish to develop and host this codebase in a closed source manner you may use all commits prior to `1420675200 +0000`, which are licensed under GPL v3. The major change here is that if you host a server using any code licensed under AGPLv3 you are required to provide full source code for your servers users as well including addons and modifications you have made. | ||
|
|
||
| See [here](https://www.gnu.org/licenses/why-affero-gpl.html) for more information. | ||
|
|
||
| ### GETTING THE CODE | ||
| The simplest way to obtain the code is using the github .zip feature. | ||
|
|
||
| Click [here](https://github.com/VOREStation/VOREStation/archive/master.zip) to get the latest code as a .zip file, then unzip it to wherever you want. | ||
|
|
||
| The more complicated and easier to update method is using git. You'll need to download git or some client from [here](http://git-scm.com/). When that's installed, right click in any folder and click on "Git Bash". When that opens, type in: | ||
|
|
||
| git clone https://github.com/VOREStation/VOREStation.git | ||
|
|
||
| (hint: hold down ctrl and press insert to paste into git bash) | ||
|
|
||
| This will take a while to download, but it provides an easier method for updating. | ||
|
|
||
| Once the repository is in place, run this command: | ||
| ```bash | ||
| cd VOREStation | ||
| git update-index --assume-unchanged vorestation.int | ||
| ``` | ||
| Now git will ignore changes to the file vorestation.int. | ||
|
|
||
| ### INSTALLATION | ||
|
|
||
| First-time installation should be fairly straightforward. First, you'll need BYOND installed. You can get it from [here](http://www.byond.com/). | ||
|
|
||
| This is a sourcecode-only release, so the next step is to compile the server files. Open vorestation.dme by double-clicking it, open the Build menu, and click compile. This'll take a little while, and if everything's done right you'll get a message like this: | ||
|
|
||
| saving vorestation.dmb (DEBUG mode) | ||
|
|
||
| vorestation.dmb - 0 errors, 0 warnings | ||
|
|
||
| If you see any errors or warnings, something has gone wrong - possibly a corrupt download or the files extracted wrong, or a code issue on the main repo. Ask on IRC. | ||
|
|
||
| Once that's done, open up the config folder. You'll want to edit config.txt to set the probabilities for different gamemodes in Secret and to set your server location so that all your players don't get disconnected at the end of each round. It's recommended you don't turn on the gamemodes with probability 0, as they have various issues and aren't currently being tested, so they may have unknown and bizarre bugs. | ||
|
|
||
| You'll also want to edit admins.txt to remove the default admins and add your own. "Game Master" is the highest level of access, and the other recommended admin levels for now are "Game Admin" and "Moderator". The format is: | ||
|
|
||
| byondkey - Rank | ||
|
|
||
| where the BYOND key must be in lowercase and the admin rank must be properly capitalised. There are a bunch more admin ranks, but these two should be enough for most servers, assuming you have trustworthy admins. | ||
|
|
||
| Finally, to start the server, run Dream Daemon and enter the path to your compiled vorestation.dmb file. Make sure to set the port to the one you specified in the config.txt, and set the Security box to 'Trusted'. Then press GO and the server should start up and be ready to join. | ||
|
|
||
| --- | ||
|
|
||
| ### UPDATING | ||
|
|
||
| To update an existing installation, first back up your /config and /data folders | ||
| as these store your server configuration, player preferences and banlist. | ||
|
|
||
| If you used the zip method, you'll need to download the zip file again and unzip it somewhere else, and then copy the /config and /data folders over. | ||
|
|
||
| If you used the git method, you simply need to type this in to git bash: | ||
|
|
||
| git pull | ||
|
|
||
| When this completes, copy over your /data and /config folders again, just in case. | ||
|
|
||
| When you have done this, you'll need to recompile the code, but then it should work fine. | ||
|
|
||
| --- | ||
|
|
||
| ### Configuration | ||
|
|
||
| For a basic setup, simply copy every file from config/example to config. | ||
|
|
||
| --- | ||
|
|
||
| ### SQL Setup | ||
|
|
||
| The SQL backend for the library and stats tracking requires a MySQL server. Your server details go in /config/dbconfig.txt, and the SQL schema is in /SQL/tgstation_schema.sql. More detailed setup instructions arecoming soon, for now ask in our IRC channel. | ||
|
|
||
| --- | ||
|
|
||
| ### IRC Bot Setup | ||
|
|
||
| Included in the repo is an IRC bot capable of relaying adminhelps to a specified IRC channel/server (thanks to Skibiliano). Instructions for bot setup are included in the /bot/ folder along with the bot/relay script itself. |
| @@ -0,0 +1,125 @@ | ||
| CREATE SCHEMA IF NOT EXISTS `mydb` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci ; | ||
| CREATE SCHEMA IF NOT EXISTS `feedback` DEFAULT CHARACTER SET latin1 ; | ||
| USE `mydb` ; | ||
| USE `feedback` ; | ||
|
|
||
| CREATE TABLE `erro_admin` ( | ||
| `id` int(11) NOT NULL AUTO_INCREMENT, | ||
| `ckey` varchar(32) NOT NULL, | ||
| `rank` varchar(32) NOT NULL DEFAULT 'Administrator', | ||
| `level` int(2) NOT NULL DEFAULT '0', | ||
| `flags` int(16) NOT NULL DEFAULT '0', | ||
| PRIMARY KEY (`id`) | ||
| ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; | ||
|
|
||
| CREATE TABLE `erro_admin_log` ( | ||
| `id` int(11) NOT NULL AUTO_INCREMENT, | ||
| `datetime` datetime NOT NULL, | ||
| `adminckey` varchar(32) NOT NULL, | ||
| `adminip` varchar(18) NOT NULL, | ||
| `log` text NOT NULL, | ||
| PRIMARY KEY (`id`) | ||
| ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; | ||
|
|
||
| CREATE TABLE `erro_ban` ( | ||
| `id` int(11) NOT NULL AUTO_INCREMENT, | ||
| `bantime` datetime NOT NULL, | ||
| `serverip` varchar(32) NOT NULL, | ||
| `bantype` varchar(32) NOT NULL, | ||
| `reason` text NOT NULL, | ||
| `job` varchar(32) DEFAULT NULL, | ||
| `duration` int(11) NOT NULL, | ||
| `rounds` int(11) DEFAULT NULL, | ||
| `expiration_time` datetime NOT NULL, | ||
| `ckey` varchar(32) NOT NULL, | ||
| `computerid` varchar(32) NOT NULL, | ||
| `ip` varchar(32) NOT NULL, | ||
| `a_ckey` varchar(32) NOT NULL, | ||
| `a_computerid` varchar(32) NOT NULL, | ||
| `a_ip` varchar(32) NOT NULL, | ||
| `who` text NOT NULL, | ||
| `adminwho` text NOT NULL, | ||
| `edits` text, | ||
| `unbanned` tinyint(1) DEFAULT NULL, | ||
| `unbanned_datetime` datetime DEFAULT NULL, | ||
| `unbanned_ckey` varchar(32) DEFAULT NULL, | ||
| `unbanned_computerid` varchar(32) DEFAULT NULL, | ||
| `unbanned_ip` varchar(32) DEFAULT NULL, | ||
| PRIMARY KEY (`id`) | ||
| ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; | ||
|
|
||
| CREATE TABLE `erro_feedback` ( | ||
| `id` int(11) NOT NULL AUTO_INCREMENT, | ||
| `time` datetime NOT NULL, | ||
| `round_id` int(8) NOT NULL, | ||
| `var_name` varchar(32) NOT NULL, | ||
| `var_value` int(16) DEFAULT NULL, | ||
| `details` text, | ||
| PRIMARY KEY (`id`) | ||
| ) ENGINE=MyISAM DEFAULT CHARSET=latin1 ; | ||
|
|
||
| CREATE TABLE `erro_player` ( | ||
| `id` int(11) NOT NULL AUTO_INCREMENT, | ||
| `ckey` varchar(32) NOT NULL, | ||
| `firstseen` datetime NOT NULL, | ||
| `lastseen` datetime NOT NULL, | ||
| `ip` varchar(18) NOT NULL, | ||
| `computerid` varchar(32) NOT NULL, | ||
| `lastadminrank` varchar(32) NOT NULL DEFAULT 'Player', | ||
| PRIMARY KEY (`id`), | ||
| UNIQUE KEY `ckey` (`ckey`) | ||
| ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; | ||
|
|
||
| CREATE TABLE `erro_poll_option` ( | ||
| `id` int(11) NOT NULL AUTO_INCREMENT, | ||
| `pollid` int(11) NOT NULL, | ||
| `text` varchar(255) NOT NULL, | ||
| `percentagecalc` tinyint(1) NOT NULL DEFAULT '1', | ||
| `minval` int(3) DEFAULT NULL, | ||
| `maxval` int(3) DEFAULT NULL, | ||
| `descmin` varchar(32) DEFAULT NULL, | ||
| `descmid` varchar(32) DEFAULT NULL, | ||
| `descmax` varchar(32) DEFAULT NULL, | ||
| PRIMARY KEY (`id`) | ||
| ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; | ||
|
|
||
| CREATE TABLE `erro_poll_question` ( | ||
| `id` int(11) NOT NULL AUTO_INCREMENT, | ||
| `polltype` varchar(16) NOT NULL DEFAULT 'OPTION', | ||
| `starttime` datetime NOT NULL, | ||
| `endtime` datetime NOT NULL, | ||
| `question` varchar(255) NOT NULL, | ||
| `adminonly` tinyint(1) DEFAULT '0', | ||
| PRIMARY KEY (`id`) | ||
| ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; | ||
|
|
||
| CREATE TABLE `erro_poll_textreply` ( | ||
| `id` int(11) NOT NULL AUTO_INCREMENT, | ||
| `datetime` datetime NOT NULL, | ||
| `pollid` int(11) NOT NULL, | ||
| `ckey` varchar(32) NOT NULL, | ||
| `ip` varchar(18) NOT NULL, | ||
| `replytext` text NOT NULL, | ||
| `adminrank` varchar(32) NOT NULL DEFAULT 'Player', | ||
| PRIMARY KEY (`id`) | ||
| ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; | ||
|
|
||
| CREATE TABLE `erro_poll_vote` ( | ||
| `id` int(11) NOT NULL AUTO_INCREMENT, | ||
| `datetime` datetime NOT NULL, | ||
| `pollid` int(11) NOT NULL, | ||
| `optionid` int(11) NOT NULL, | ||
| `ckey` varchar(255) NOT NULL, | ||
| `ip` varchar(16) NOT NULL, | ||
| `adminrank` varchar(32) NOT NULL, | ||
| `rating` int(2) DEFAULT NULL, | ||
| PRIMARY KEY (`id`) | ||
| ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; | ||
|
|
||
| CREATE TABLE `erro_privacy` ( | ||
| `id` int(11) NOT NULL AUTO_INCREMENT, | ||
| `datetime` datetime NOT NULL, | ||
| `ckey` varchar(32) NOT NULL, | ||
| `option` varchar(128) NOT NULL, | ||
| PRIMARY KEY (`id`) | ||
| ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; |
| @@ -0,0 +1,100 @@ | ||
| SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0; | ||
| SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0; | ||
| SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL'; | ||
|
|
||
| CREATE SCHEMA IF NOT EXISTS `mydb` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci ; | ||
| CREATE SCHEMA IF NOT EXISTS `tgstation` DEFAULT CHARACTER SET latin1 ; | ||
| USE `mydb` ; | ||
| USE `tgstation` ; | ||
|
|
||
| -- ----------------------------------------------------- | ||
| -- Table `tgstation`.`death` | ||
| -- ----------------------------------------------------- | ||
| CREATE TABLE IF NOT EXISTS `tgstation`.`death` ( | ||
| `id` INT(11) NOT NULL AUTO_INCREMENT , | ||
| `pod` TEXT NOT NULL COMMENT 'Place of death' , | ||
| `coord` TEXT NOT NULL COMMENT 'X, Y, Z POD' , | ||
| `tod` DATETIME NOT NULL COMMENT 'Time of death' , | ||
| `job` TEXT NOT NULL , | ||
| `special` TEXT NOT NULL , | ||
| `name` TEXT NOT NULL , | ||
| `byondkey` TEXT NOT NULL , | ||
| `laname` TEXT NOT NULL COMMENT 'Last attacker name' , | ||
| `lakey` TEXT NOT NULL COMMENT 'Last attacker key' , | ||
| `gender` TEXT NOT NULL , | ||
| `bruteloss` INT(11) NOT NULL , | ||
| `brainloss` INT(11) NOT NULL , | ||
| `fireloss` INT(11) NOT NULL , | ||
| `oxyloss` INT(11) NOT NULL , | ||
| PRIMARY KEY (`id`) ) | ||
| ENGINE = MyISAM | ||
| AUTO_INCREMENT = 3409 | ||
| DEFAULT CHARACTER SET = latin1; | ||
|
|
||
|
|
||
| -- ----------------------------------------------------- | ||
| -- Table `tgstation`.`karma` | ||
| -- ----------------------------------------------------- | ||
| CREATE TABLE IF NOT EXISTS `tgstation`.`karma` ( | ||
| `id` INT(11) NOT NULL AUTO_INCREMENT , | ||
| `spendername` TEXT NOT NULL , | ||
| `spenderkey` TEXT NOT NULL , | ||
| `receivername` TEXT NOT NULL , | ||
| `receiverkey` TEXT NOT NULL , | ||
| `receiverrole` TEXT NOT NULL , | ||
| `receiverspecial` TEXT NOT NULL , | ||
| `isnegative` TINYINT(1) NOT NULL , | ||
| `spenderip` TEXT NOT NULL , | ||
| `time` DATETIME NOT NULL , | ||
| PRIMARY KEY (`id`) ) | ||
| ENGINE = MyISAM | ||
| AUTO_INCREMENT = 943 | ||
| DEFAULT CHARACTER SET = latin1; | ||
|
|
||
|
|
||
| -- ----------------------------------------------------- | ||
| -- Table `tgstation`.`karmatotals` | ||
| -- ----------------------------------------------------- | ||
| CREATE TABLE IF NOT EXISTS `tgstation`.`karmatotals` ( | ||
| `id` INT(11) NOT NULL AUTO_INCREMENT , | ||
| `byondkey` TEXT NOT NULL , | ||
| `karma` INT(11) NOT NULL , | ||
| PRIMARY KEY (`id`) ) | ||
| ENGINE = MyISAM | ||
| AUTO_INCREMENT = 244 | ||
| DEFAULT CHARACTER SET = latin1; | ||
|
|
||
|
|
||
| -- ----------------------------------------------------- | ||
| -- Table `tgstation`.`library` | ||
| -- ----------------------------------------------------- | ||
| CREATE TABLE IF NOT EXISTS `tgstation`.`library` ( | ||
| `id` INT(11) NOT NULL AUTO_INCREMENT , | ||
| `author` TEXT NOT NULL , | ||
| `title` TEXT NOT NULL , | ||
| `content` TEXT NOT NULL , | ||
| `category` TEXT NOT NULL , | ||
| PRIMARY KEY (`id`) ) | ||
| ENGINE = MyISAM | ||
| AUTO_INCREMENT = 184 | ||
| DEFAULT CHARACTER SET = latin1; | ||
|
|
||
|
|
||
| -- ----------------------------------------------------- | ||
| -- Table `tgstation`.`population` | ||
| -- ----------------------------------------------------- | ||
| CREATE TABLE IF NOT EXISTS `tgstation`.`population` ( | ||
| `id` INT(11) NOT NULL AUTO_INCREMENT , | ||
| `playercount` INT(11) NULL DEFAULT NULL , | ||
| `admincount` INT(11) NULL DEFAULT NULL , | ||
| `time` DATETIME NOT NULL , | ||
| PRIMARY KEY (`id`) ) | ||
| ENGINE = MyISAM | ||
| AUTO_INCREMENT = 2544 | ||
| DEFAULT CHARACTER SET = latin1; | ||
|
|
||
|
|
||
|
|
||
| SET SQL_MODE=@OLD_SQL_MODE; | ||
| SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS; | ||
| SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS; |
| @@ -0,0 +1,13 @@ | ||
| Name = "CC_NanoTrasen" #The name he uses to connect | ||
| no_absolute_paths = True | ||
| debug_on = False | ||
| SName = ["cc","nt","trasen","nano","nanotrasen"] #Other names he will respond to, in lowercase | ||
| DISABLE_ALL_NON_MANDATORY_SOCKET_CONNECTIONS = False | ||
| directory = "bot/directory/here/" # Directory the bot is located in, make sure to keep the "/" at the end | ||
| version = "TG CC-BY-SA 6" | ||
| Network = 'YOUR.SERVER.HERE' #e.g. "irc.rizon.net" | ||
| channel = "#YOUR CHANNEL HERE" #what channel you want the bot in | ||
| channels = ["#YOUR CHANNEL HERE"] #same as above | ||
| greeting = "Welcome!" #what he says when a person he hasn't seen before joins | ||
| prefix = "!" #prefix for bot commands | ||
| Port = 7000 |
| @@ -0,0 +1,32 @@ | ||
| from random import choice as fsample #Yay for added speed! | ||
| global responses | ||
| responses = ['Yes','Too bad','Will you turn me off if I tell you?','Absolutely', | ||
| "Not at all", "Nope", "It does", "No", "All the time", | ||
| "I don't really know", "Could be","Possibly","You're still here?",# Chaoticag | ||
| "No idea", "Of course", "Would you turn me off if I tell you?", | ||
| "Sweet!","Nah","Certainly","Yeah","Yup","I am quite confident that the answer is Yes", | ||
| "Perhaps", "Yeeeeaah... No.", "Indubitably" ] # Richard | ||
| def eightball(data,debug,sender,prefix): | ||
| global responses | ||
| arg = data.lower().replace(prefix+"eightball ","") | ||
| arg = arg.replace(prefix+"8ball ","") | ||
| if debug: | ||
| print sender+":"+prefix+"eightball", arg | ||
| if "answer" in arg and "everything" in arg and "to" in arg: | ||
| if debug: | ||
| print "Responded with",42 | ||
| return "42" | ||
| elif arg == "derp": | ||
| if debug: | ||
| print "Responded with herp" | ||
| return("herp") | ||
| elif arg == "herp": | ||
| if debug: | ||
| print "Responded with derp" | ||
| return("derp") | ||
| else: | ||
| #choice = sample(responses,1)[0] | ||
| choice = fsample(responses) | ||
| if debug: | ||
| print "Responded with", choice | ||
| return(choice) |
| @@ -0,0 +1,5 @@ | ||
| #Throws a coin, simple. | ||
| from random import random | ||
| def heaortai(debug,sender): return("Heads" if random() > 0.5 else "Tails") | ||
| # Takes 1/6th the time of doing it with random.randint(0,1) | ||
| # This file used to be a lot bigger, now it's kind of useless. |
| @@ -0,0 +1,21 @@ | ||
| from save_load import save | ||
| from os import listdir | ||
| import CORE_DATA | ||
| directory = CORE_DATA.directory | ||
| def mkquote(prefix,influx,sender,debug): | ||
| arg = influx[10+len(prefix):] | ||
| if debug: | ||
| print sender+":"+prefix+"makequote "+str(len(arg))+" Characters" | ||
| if len(arg) == 0: | ||
| return("Type something to a quote") | ||
| else: | ||
| files = listdir(directory+"userquotes") | ||
| numb = 0 | ||
| while True: | ||
| numb += 1 | ||
| if sender.lower()+str(numb) in files: | ||
| pass | ||
| else: | ||
| save(directory+"userquotes/"+sender.lower()+str(numb),[arg,sender.lower()]) | ||
| return("Saved as:"+sender.lower()+str(numb)) | ||
| break |
| @@ -0,0 +1,70 @@ | ||
| ### EXPERIMENTAL PROTOTYPE ### | ||
| # e = 2.7182818284590452353602874713526624977572 | ||
| # pi = math.pi | ||
| from __future__ import division #PYTHON Y U NO TELL ME THIS BEFORE | ||
| import math | ||
| import random | ||
| import re | ||
| e = "2.7182818284590452353602874713526624977572" | ||
| pi = str(math.pi) | ||
| global pre | ||
| pre = len("maths ") | ||
| def maths(influx,prefix="!",sender="NaN",debug=True,method="n"): | ||
| global pre | ||
| influx = influx.lower() | ||
| influx = influx[len(prefix)+pre:] | ||
| influx = influx.replace("pie",pi+"*"+e) | ||
| influx = influx.replace("e*",e+"*") | ||
| influx = influx.replace("*e","*"+e) | ||
| influx = influx.replace("pi",pi) | ||
| if debug: | ||
| print sender+":"+prefix+"maths" | ||
| if influx.count("**") == 0 and influx.count('"') == 0 and influx.count("'") == 0 and influx.count(";") == 0 and influx.count(":") == 0: | ||
| influx_low = influx.lower() | ||
| influx_hi = influx.upper() | ||
| if "0b" in influx_low: | ||
| influx_low = re.sub("0b[0-1]*","",influx_low) | ||
| influx_hi = re.sub("0B[0-1]*","",influx_hi) | ||
| if "0x" in influx_low: | ||
| influx_low = re.sub("0x[a-f0-9]*","",influx_low) | ||
| influx_hi = re.sub("0X[A-F0-9]*","",influx_hi) | ||
| if "rand" in influx_low: | ||
| influx_low = re.sub("rand","",influx_low) | ||
| influx_hi = re.sub("RAND","",influx_hi) | ||
| if influx_low == influx_hi: | ||
| influx = re.sub("rand","random.random()",influx) | ||
| try: | ||
| result = eval(influx.lower()) | ||
| except ZeroDivisionError: | ||
| return "Divide by zero detected." | ||
| except SyntaxError: | ||
| return "Syntax Error detected." | ||
| except TypeError: | ||
| return "Type Error detected." | ||
| except: | ||
| return "Unknown Error detected." | ||
| else: | ||
| if method == "n": #Normal | ||
| return result | ||
| elif method == "i": #Forced Int | ||
| return int(result) | ||
| elif method == "h": #Hex | ||
| try: | ||
| if "L" in hex(result)[2:]: | ||
| return hex(result)[2:-1] | ||
| else: | ||
| return hex(result)[2:].upper() | ||
| except TypeError: | ||
| return "That value (%s) cannot be interpreted properly using !hmaths" %(str(result)) | ||
| elif method == "b": #Binary | ||
| try: | ||
| return bin(result)[2:].upper() | ||
| except TypeError: | ||
| return "That value (%s) cannot be interpreted properly using !bmaths" %(str(result)) | ||
| else: | ||
| return result | ||
| else: | ||
| return "What are you trying to make me do again?" | ||
| else: | ||
| return "Those are likely to make me hang" | ||
|
|
| @@ -0,0 +1,23 @@ | ||
| global parta,partb | ||
| parta = {"A":"N","B":"O","C":"P","D":"Q","E":"R","F":"S","G":"T","H":"U","I":"V","J":"W","K":"X","L":"Y","M":"Z"} | ||
| partb = {'O':'B','N':'A','Q':'D','P':'C','S':'F','R':'E','U':'H','T':'G','W':'J','V':'I','Y':'L','X':'K','Z':'M'} | ||
| def rot13(text): | ||
| global parta,partb | ||
| newtext = "" | ||
| for letter in text: | ||
| try: | ||
| if letter.isupper(): | ||
| newtext += parta[letter] | ||
| else: | ||
| newtext += parta[letter.upper()].lower() | ||
| except: | ||
| try: | ||
| if letter.isupper(): | ||
| newtext += partb[letter] | ||
| pass | ||
| else: | ||
| newtext += partb[letter.upper()].lower() | ||
| pass | ||
| except: | ||
| newtext += letter | ||
| return newtext |
| @@ -0,0 +1,96 @@ | ||
| import random | ||
| def rtd(data,debug,sender): | ||
| backo = data | ||
| try: | ||
| arg1,arg2 = backo.split("d") | ||
| except ValueError, err: | ||
| return("Too many or too small amount of arguments") | ||
| else: | ||
| if debug: | ||
| print sender+":!rtd "+arg1+"d"+arg2 #faster than using %s's | ||
| die,die2 = [],[] | ||
| current_mark = "" | ||
| outcome = 0 | ||
| realnumberfound = False | ||
| checks = [] | ||
| count = 0 | ||
| arg1 = arg1.replace(" ","") | ||
| arg2 = arg2.replace(" ","") | ||
| try: | ||
| i_arg1 = int(arg1) | ||
| a_arg1 = abs(i_arg1) | ||
| if "+" in arg2 or "-" in arg2: | ||
| plus_spot = arg2.find("+") | ||
| minus_spot = arg2.find("-") | ||
| if plus_spot == -1 and minus_spot == -1: | ||
| nicer_form = "" | ||
| elif plus_spot != -1 and minus_spot == -1: | ||
| nicer_form = arg2[plus_spot:] | ||
| elif plus_spot == -1 and minus_spot != -1: | ||
| nicer_form = arg2[minus_spot:] | ||
| else: | ||
| if plus_spot < minus_spot: | ||
| nicer_form = arg2[plus_spot:] | ||
| else: | ||
| nicer_form = arg2[minus_spot:] | ||
| for letter in arg2: | ||
| if letter == "+" or letter == "-": | ||
| current_mark = letter | ||
| checks = [] | ||
| count += 1 | ||
| continue | ||
| checks.append(letter) | ||
| try: | ||
| next_up = arg2[count+1] | ||
| except: | ||
| if realnumberfound == False: | ||
| i_arg2 = int("".join(checks)) | ||
| checks = [] | ||
| realnumberfound = True | ||
| elif current_mark == "+": | ||
| outcome += int("".join(checks)) | ||
| else: | ||
| outcome -= int("".join(checks)) | ||
| else: | ||
| if next_up == "+" or next_up == "-": | ||
| if realnumberfound == False: | ||
| i_arg2 = int("".join(checks)) | ||
| checks = [] | ||
| realnumberfound = True | ||
| else: | ||
| if current_mark == "+": | ||
| outcome += int("".join(checks)) | ||
| else: | ||
| outcome -= int("".join(checks)) | ||
| checks = [] | ||
| count += 1 | ||
| else: | ||
| i_arg2 = int(arg2) | ||
| if a_arg1 == 0 or abs(i_arg2) == 0: | ||
| raise RuntimeError | ||
| except ValueError: | ||
| return("You lied! That's not a number!") | ||
| except RuntimeError: | ||
| return("Too many zeroes!") | ||
| else: | ||
| if a_arg1 > 100: | ||
| return("Too many rolls, I can only do one hundred at max.") | ||
| else: | ||
| for i in xrange(0,a_arg1): | ||
| if i_arg2 < 0: | ||
| dice = random.randint(i_arg2,0) | ||
| else: | ||
| dice = random.randint(1,i_arg2) | ||
| die.append(dice) | ||
| die2.append(str(dice)) | ||
| if i_arg2 < 0: | ||
| flist = "".join(die2) | ||
| else: | ||
| flist = "+".join(die2) | ||
| if len(flist) > 350: | ||
| return(str(reduce(lambda x,y: x+y, die)+outcome)) | ||
| else: | ||
| if current_mark == "": | ||
| return(flist+" = "+str(reduce(lambda x,y: x+y, die)+outcome)) | ||
| else: | ||
| return(flist+" ("+nicer_form+") = "+str(reduce(lambda x,y: x+y, die)+outcome)) |
| @@ -0,0 +1,30 @@ | ||
| from random import choice as fsample | ||
| sarcastic_responses = ["Yeah right","What do I look like to you?","Are you kidding me?",#UsF | ||
| "As much as you","You don't believe that yourself","When pigs fly",#UsF | ||
| "Like your grandma","You would like to know, wouldn't you?", #UsF | ||
| "Like your mom", #Spectre | ||
| "Totally","Not at all", #Spectre | ||
| "AHAHAHahahaha, No.", #Strumpetplaya | ||
| "Not as much as USER","As much as USER", | ||
| "Really, you expect me to tell you that?", | ||
| "Right, and you've been building NOUNs for those USERs in the LOCATION, haven't you?" ] #Richard | ||
| locations = ["woods","baystation","ditch"] | ||
| nouns = ["bomb","toilet","robot","cyborg", | ||
| "garbage can","gun","cake", | ||
| "missile"] | ||
| def sarcasticball(data,debug,sender,users,prefix): | ||
| arg = data.lower().replace(prefix+"sarcasticball ","") | ||
| arg = arg.replace(prefix+"sball ","") | ||
| if debug: | ||
| print sender+":"+prefix+"sarcasticball", arg | ||
| choice = fsample(sarcastic_responses) | ||
| if "USER" in choice: | ||
| choice = choice.replace("USER",fsample(users),1) | ||
| choice = choice.replace("USER",fsample(users),1) | ||
| if "NOUN" in choice: | ||
| choice = choice.replace("NOUN",fsample(nouns),1) | ||
| if "LOCATION" in choice: | ||
| choice = choice.replace("LOCATION",fsample(locations),1) | ||
| if debug: | ||
| print "Responded with", choice | ||
| return(choice) |
| @@ -0,0 +1,35 @@ | ||
| import random | ||
| def srtd(data,debug,sender): | ||
| try: | ||
| arg1,arg2 = data.split("d") | ||
| except ValueError, err: | ||
| if str(err) == "need more than 1 value to unpack": | ||
| return("Too small amount of arguments") | ||
| else: | ||
| return("Too many arguments") | ||
| else: | ||
| if debug: | ||
| print sender+":!rtd "+arg1+"d"+arg2 | ||
| die = [] | ||
| arg1 = arg1.replace(" ","") | ||
| arg2 = arg2.replace(" ","") | ||
| try: | ||
| i_arg1 = int(arg1) | ||
| i_arg2 = int(arg2) | ||
| if abs(i_arg1) == 0 or abs(i_arg2) == 0: | ||
| raise RuntimeError | ||
| except ValueError: | ||
| return("You lied! That's not a number!") | ||
| except RuntimeError: | ||
| return("Too many zeroes!") | ||
| else: | ||
| if abs(i_arg1) > 500: | ||
| return("Too many rolls, I can only do five hundred at max.") | ||
| else: | ||
| for i in xrange(0,abs(i_arg1)): | ||
| if i_arg2 < 0: | ||
| dice = random.randint(i_arg2,0) | ||
| else: | ||
| dice = random.randint(1,i_arg2) | ||
| die.append(dice) | ||
| return(str(reduce(lambda x,y: x+y, die))) |
| @@ -0,0 +1,60 @@ | ||
| #As new commands are added, update this. | ||
| # Last updated: 8.3.2011 | ||
|
|
||
| # Updated 12.3.2011: | ||
| # - Added the missing help data for Version | ||
| # - Imported CORE_DATA to get the name. | ||
| # - Tidied some commands up a bit. | ||
| # - Replaced all "Bot"s with the Skibot's current name. | ||
|
|
||
| from CORE_DATA import Name | ||
| everything = {"8ball":"[8ball <arg>] Responds to the argument", | ||
| "allcaps":"[allcaps <arg>] Takes an uppercase string and returns a capitalized version", | ||
| "bmaths":"[bmaths <arg>] Takes a math equation (Like 5+5) and returns a binary result", | ||
| "coin":"[coin] Flips a coin", | ||
| "dance":"[dance] Makes %s do a little dance" %(Name), | ||
| "delquote":"(OP ONLY) [delquote <arg>] Removes a quote with the filename equal to the argument", | ||
| "disable":"(OP ONLY) [disable] Disables all output from %s" %(Name), | ||
| "disable dance":"(HALFOP / OP ONLY) [disable dance] or [dd] Toggles dancing", | ||
| "disable fml":"(HALFOP / OP ONLY) [disable fml] Disables FML", | ||
| "eightball":"[eightball <arg>] Responds to the argument", | ||
| "enable":"(OP ONLY) [enable] After being disabled, enable will turn output back on", | ||
| "enable fml":"{HALFOP / OP ONLY} [enable fml] After fml has been disabled, enable fml will make it available again", | ||
| "fml":"[fml] Returns a random Fuck My Life bit", | ||
| "give":"[give <arg>] Gives the Pneumatic Disposal Unit the argument", | ||
| "help":"[help [<command>]] Returns the list of commands or a detailed description of a command if specified", | ||
| "hmaths":"[hmaths <arg>] Takes a math equation (Like 5+5) and returns a hex result", | ||
| "makequote":"[makequote <arg>] Creates a quote with arg being the quote itself", | ||
| "maths":"[maths <arg>] Takes a math equation (Like 5+5) and returns a default result", | ||
| "note":"[note <arg1> [<arg2>]] Opens a note if only arg1 is specified, Creates a note with the name of arg1 and contents of arg2 if arg2 is specified, if you prefix the note name with [CP], it creates a public note only to that channel. Which can be accessed by !note _<note name>", | ||
| "notes":"[notes] Displays all your saved notes on %s" %(Name), | ||
| "otherball":"[otherball] If Floorbot is on the same channel, %s will ask him a random question when this command is passed" %(Name), | ||
| "purgemessages":"[purgemessages] Used to delete all your Tell messages (%s,Tell <User> <Message>)" %(Name), | ||
| "quote":"[quote [<author>]] Picks a random quote, if the author is specified, a random quote by that author", | ||
| "redmine":"[redmine] If you have a note called redmine, with a valid whoopshop redmine address, this displays all the bugs labeled as 'New' on that page. It also displays the todo note if it's found.", | ||
| "replace":"[replace] Fixes the Pneumatic Smasher if it's been broken", | ||
| "rot13":"[rot13 <arg>] Encrypts the arg by using the rot13 method", | ||
| "rtd":"[rtd [<arg1>d<arg2>]] Rolls a six-sided dice if no arguments are specified, otherwise arg1 is the amount of rolls and arg2 is the amount of sides the dice have", | ||
| "sarcasticball":"[sarcasticball <arg>] Responds to the argument sarcastically", | ||
| "sball":"[sball <arg>] Responds to the argument sarcastically", | ||
| "srtd":"[srtd <arg1>d<arg2>] Rolls <arg1> amount of <arg2> sided die without showing the dice values separately", | ||
| "stop":"(RESTRICTED TO OP AND CREATOR) [stop] Stops %s, plain and simple" %(Name), | ||
| "suggest":"[suggest <arg>] Saves a suggestion given to %s, to be later viewed by the creator" %(Name), | ||
| "take":"[take <arg>] Takes an item specified in the argument from the Pneumatic Smasher", | ||
| "tban":"(OP ONLY) [tban <user> <seconds>] When %s is an operator, You can ban an user for specified amount of seconds" %(Name), | ||
| "thm":"(RESTRICTED TO OP AND CREATOR) [thm] Normally in 8ball and sarcasticball, Users are not shown, instead replaced by things like demons or plasma researchers, toggling this changes that behaviour.", | ||
| "tm":"(OP AND CREATOR ONLY) [tm] Toggles marakov", | ||
| "togglequotemakers":"(OP ONLY) [togglequotemakers or tqm] Normally with the quote command, makers are not shown, this toggles that behaviour.", | ||
| "tqm":"(OP ONLY) [tqm or togglequotemakers] Normally with the quote command, makers are not shown, this toggles that behaviour.", | ||
| "toggleofflinemessages":"(OP ONLY) [toggleofflinemessages or tom] Allows an operator to toggle leaving Tell messages (%s, Tell <User> <Message)" %(Name), | ||
| "tom":"(OP ONLY) [tom or toggleofflinemessages] Allows an operator to toggle leaving Tell messages (%s, Tell <User> <Message)" %(Name), | ||
| "toggleyoutubereveal":"(OP ONLY) [toggleyoutubereveal] or [tyr] Toggles the automatic showing of youtube video titles based on URL's.", | ||
| "tyr":"(OP ONLY) [tyr] or [toggleyoutubereveal] Toggles the automatic showing of youtube video titles based on URL's.", | ||
| "translate":"(OP ONLY) [translate <user>] Whenever the user says something in allcaps, it's capitalized.", | ||
| "uptime":"[uptime] Displays how long %s has been alive on the channel."%(Name), | ||
| "use":"[use] Uses the Pneumatic Smasher.", | ||
| "youtube":"[youtube <url>] Shows the title of a video by checking the URL provided.", | ||
| "version":"[version] Shows the current version of %s." %(Name), | ||
| "weather":"[weather <location>] Displays the current weather of the provided location.", | ||
| "life":"I cannot help you with that, sorry."} | ||
|
|
| @@ -0,0 +1,55 @@ | ||
| from htmltagremove import htr | ||
| def formatter(data): | ||
| newdata = [] | ||
| data = htr(data) | ||
| bad = ["Your nick : Categories : ","\r","Advanced search - last", | ||
| "FMyLife","Get the guts to spill the beans","FML: Your random funny stories", | ||
| "Woman","Man","Choose","Health","Intimacy","Miscellaneous","Man or woman? ", | ||
| "Money","Kids","Work","Love","Email notification?", | ||
| "Moderate the FMLs","Submit your FML story", | ||
| "- If your story isn't published on the website, don't feel offended, and thank you nevertheless!", | ||
| "Pick a country","See all","Your account","Team's blog", | ||
| "Meet the FMLHello readers! Did you meet someone new this...The whole blog", | ||
| "Amazon","Borders","IndieBound","Personalized book","Terms of use", | ||
| "FML t-shirts -","Love - Money - Kids - Work - Health - Intimacy - Miscellaneous - Members", | ||
| "Follow the FML Follow the FML blog Follow the FML comments ", | ||
| "_qoptions={", | ||
| "};","})();","Categories","Sign up - Password? ", " Net Avenir : gestion publicitaire", | ||
| "FMyLife, the book","Available NOW on:","Barnes & Noble"] | ||
|
|
||
| for checkable in data: | ||
| if checkable in bad: | ||
| pass | ||
| elif "_gaq.push" in checkable: | ||
| pass | ||
| elif "ga.src" in checkable: | ||
| pass | ||
| elif "var _gaq" in checkable: | ||
| pass | ||
| elif "var s =" in checkable: | ||
| pass | ||
| elif "var ga" in checkable: | ||
| pass | ||
| elif "function()" in checkable: | ||
| pass | ||
| elif "siteanalytics" in checkable: | ||
| pass | ||
| elif "qacct:" in checkable: | ||
| pass | ||
| elif "\r" in checkable: | ||
| pass | ||
| elif "ic_" in checkable: | ||
| pass | ||
| elif "Please note that spam and nonsensical stories" in checkable: | ||
| pass | ||
| elif "Refresh this page" in checkable: | ||
| pass | ||
| elif "You...The whole blo" in checkable: | ||
| pass | ||
| elif "Net Avenir : gestion publicitair" in checkable: | ||
| pass | ||
| else: | ||
| if "Net Avenir : gestion publicitaireClose the advertisement" in checkable: | ||
| checkable = checkable.replace("Net Avenir : gestion publicitaireClose the advertisement","") | ||
| newdata.append(checkable) | ||
| return newdata |
| @@ -0,0 +1,203 @@ | ||
| import pickle | ||
| import random | ||
| import os | ||
| import sys | ||
| import time | ||
| import CORE_DATA | ||
| def merge(d1, d2, merger=lambda x,y:x+y): | ||
| #http://stackoverflow.com/questions/38987/how-can-i-merge-two-python-dictionaries-as-a-single-expression | ||
| result = dict(d1) | ||
| for k,v in d2.iteritems(): | ||
| if k in result: | ||
| result[k] = merger(result[k], v) | ||
| else: | ||
| result[k] = v | ||
| return result | ||
| full_data = {} | ||
| imported_data = {} | ||
| try: | ||
| tiedostot = os.listdir("Marakov") | ||
| except: | ||
| os.mkdir("Marakov") | ||
| tiedostot = os.listdir("Marakov") | ||
| else: | ||
| pass | ||
|
|
||
| listaus = [] | ||
| for i in tiedostot: | ||
| if "marakov." not in i.lower(): | ||
| pass | ||
| else: | ||
| listaus.append(i) | ||
| for i in listaus: | ||
| tiedosto = open("Marakov/"+i,"r") | ||
| old_size = len(full_data.keys()) | ||
| if i != "Marakov.Cache": | ||
| imported_data = merge(imported_data,pickle.load(tiedosto)) | ||
| print "Added contents of "+i+" (Import)" | ||
| print "Entries: "+str(len(imported_data)) | ||
| else: | ||
| full_data = merge(full_data,pickle.load(tiedosto)) | ||
| new_size = len(full_data.keys()) | ||
| print "Added contents of "+i | ||
| print "Entries: "+str(new_size-old_size) | ||
| time.sleep(0.1) | ||
|
|
||
| def give_data(data): | ||
| state = False | ||
| for a,b in zip(data.split(" "),data.split(" ")[1:]): | ||
| a = a.lower().replace(",","").replace(".","").replace("?","").replace("!","").replace("(","").replace(")","").replace("[","").replace("]","").replace('"',"").replace("'","") | ||
| b = b.lower().replace(",","").replace(".","").replace("?","").replace("!","").replace("(","").replace(")","").replace("[","").replace("]","").replace('"',"").replace("'","") | ||
| if a not in [CORE_DATA.prefix+"marakov"]+CORE_DATA.SName: | ||
| state = True | ||
| if a[:7] == "http://" or a[:7] == "http:\\\\" or a[:4] == "www.": | ||
| pass | ||
| else: | ||
| try: | ||
| if b not in full_data[a]: | ||
| full_data[a].append(b) | ||
| except: | ||
| try: | ||
| if b not in imported_data[a]: | ||
| pass | ||
| except: | ||
| full_data[a] = [] | ||
| full_data[a].append(b) | ||
| if state == True: | ||
| tiedosto = open("Marakov/Marakov.Cache","w") | ||
| pickle.dump(full_data,tiedosto) | ||
| tiedosto.close() | ||
| def form_sentence(argument=None): | ||
| length = 0 | ||
| attempts = 0 | ||
| while attempts < 20: | ||
| sentence = [] | ||
| if argument != None: | ||
| a = argument | ||
| else: | ||
| try: | ||
| a = random.choice(full_data.keys()) | ||
| except IndexError: | ||
| try: | ||
| b = random.choice(imported_data.keys()) | ||
| except IndexError: | ||
| attempts = 999 | ||
| return "No sentences formable at all" | ||
| sentence.append(a) | ||
| length = 0 | ||
| attempts += 1 | ||
| while length < 12 or sentence[-1].lower() in ["but","who","gets","im","most","is","it","if","then","after","over","every","of","on","or","as","the","wheather","whether","a","to","and","for"] and length < 24: | ||
| try: | ||
| b = random.choice(full_data[a]) | ||
| except: | ||
| try: | ||
| b = random.choice(imported_data[a]) | ||
| except IndexError: | ||
| break | ||
| except KeyError: | ||
| break | ||
| else: | ||
| sentence.append(b) | ||
| length += 1 | ||
| a = b | ||
| else: | ||
| sentence.append(b) | ||
| length += 1 | ||
| a = b | ||
| if len(sentence) > 5: | ||
| argument = None | ||
| return sentence | ||
| else: | ||
| pass | ||
| argument = None | ||
| return sentence | ||
| def remdata(arg): | ||
| try: | ||
| del(full_data[arg]) | ||
| except: | ||
| print "There is no such data" | ||
| else: | ||
| tiedosto = open("Marakov/Marakov.Cache","w") | ||
| pickle.dump(full_data,tiedosto) | ||
| tiedosto.close() | ||
| def remobject(arg1,arg2): | ||
| try: | ||
| del(full_data[arg1][full_data[arg1].index(arg2)]) | ||
| except ValueError: | ||
| print "No such object" | ||
| except KeyError: | ||
| print "No such data" | ||
| else: | ||
| tiedosto = open("Marakov/Marakov.Cache","w") | ||
| pickle.dump(full_data,tiedosto) | ||
| tiedosto.close() | ||
| def convert(filename_from,filename_to): | ||
| try: | ||
| tiedosto = open(filename_from,"r") | ||
| data = pickle.load(tiedosto) | ||
| tiedosto.close() | ||
| except: | ||
| try: | ||
| tiedosto.close() | ||
| except: | ||
| pass | ||
| print "Error!" | ||
| else: | ||
| for lista in data.keys(): | ||
| try: | ||
| a = lista[-1] | ||
| except IndexError: | ||
| pass | ||
| else: | ||
| if lista[-1] in """",.?!'()[]{}""" and not lista.islower(): | ||
| if lista[:-1].lower() in data.keys(): | ||
| data[lista[:-1].lower()] += data[lista] | ||
| print "Added "+str(len(data[lista]))+" Objects from "+lista+" To "+lista[:-1].lower() | ||
| del(data[lista]) | ||
| else: | ||
| data[lista[:-1].lower()] = data[lista] | ||
| print lista+" Is now "+lista[:-1].lower() | ||
| del(data[lista]) | ||
| elif lista[-1] in """",.?!'()[]{}""" and lista.islower(): | ||
| if lista[:-1] in data.keys(): | ||
| data[lista[:-1]] += data[lista] | ||
| print "Added "+str(len(data[lista]))+" Objects from "+lista+" To "+lista[:-1] | ||
| del(data[lista]) | ||
| else: | ||
| data[lista[:-1]] = data[lista] | ||
| print lista+" Is now "+lista[:-1] | ||
| del(data[lista]) | ||
| elif not lista.islower(): | ||
| if lista.lower() in data.keys(): | ||
| data[lista.lower()] += data[lista] | ||
| print "Added "+str(len(data[lista]))+" Objects from "+lista+" To "+lista.lower() | ||
| del(data[lista]) | ||
| else: | ||
| data[lista.lower()] = data[lista] | ||
| print lista+" Is now "+lista.lower() | ||
| del(data[lista]) | ||
|
|
||
|
|
||
| for a in data.keys(): | ||
| for b in data[a]: | ||
| if b.lower()[:7] == "http://" or b.lower()[:7] == "http:\\\\" or b.lower()[:4] == "www.": | ||
| data[a].pop(b) | ||
| else: | ||
| try: | ||
| if b[-1] in """",.?!'()[]{}""" and not b.islower() and not b.isdigit(): | ||
| data[a].pop(data[a].index(b)) | ||
| data[a].append(b[:-1].lower()) | ||
| print a+" | "+b +" -> "+b[:-1].lower() | ||
| elif b[-1] in """",.?!'()[]{}""" and b.islower(): | ||
| data[a].pop(data[a].index(b)) | ||
| data[a].append(b[:-1].lower()) | ||
| print a+" | "+b +" -> "+b[:-1] | ||
| elif not b.islower() and not b.isdigit(): | ||
| data[a].pop(data[a].index(b)) | ||
| data[a].append(b.lower()) | ||
| print a+" | "+b +" -> "+b.lower() | ||
| except IndexError: #If it has no letters.. well.. yeah. | ||
| data[a].pop(data[a].index(b)) | ||
| print "Removed a NULL object" | ||
| tiedosto = open(filename_to,"w") | ||
| pickle.dump(data,tiedosto) |
| @@ -0,0 +1,19 @@ | ||
| def Namecheck(name,against,sender): | ||
| __doc__ = "False = No match, True = Match" | ||
| for i in against: | ||
| if i.lower() in name.lower() and sender.lower() not in name.lower(): | ||
| return True | ||
| else: | ||
| pass | ||
| def Namecheck_dict(name,against): | ||
| __doc__ = "False = No match, True = Match" | ||
| fuse = False | ||
| for a,i in against.items(): | ||
| if i.lower() in name.lower(): | ||
| fuse = True | ||
| break | ||
| else: | ||
| pass | ||
| return fuse,a | ||
|
|
||
|
|
| @@ -0,0 +1,28 @@ | ||
| def shortname(name): | ||
| lowname = name.lower() | ||
| numb = 0 | ||
| count = 0 | ||
| spot = 0 | ||
| for letter in name: | ||
| if letter.isupper(): | ||
| spot = numb | ||
| count += 1 | ||
| numb += 1 | ||
| if "_" in name: | ||
| if name.count("_") > 1: | ||
| name = " ".join(name.split("_")[0:name.count("_")]) | ||
| if name.lower()[-3:] == "the": | ||
| return name[:-4] | ||
| else: | ||
| return name | ||
| else: | ||
| return name.split("_")[0] | ||
| if count > 1: | ||
| if len(name[0:spot]) > 2: | ||
| return name[0:spot] | ||
| if len(name) < 5: | ||
| return name #Too short to be shortened | ||
| elif "ca" in lowname or "ct" in lowname or "tp" in lowname or "lp" in lowname: | ||
| return name[0:max(map(lambda x: lowname.find(x),["ca","ct","tp","lp"]))+1] | ||
| else: | ||
| return name[0:len(name)/2+len(name)%2] |
| @@ -0,0 +1,204 @@ | ||
| #Sources: | ||
| # http://wwp.greenwichmeantime.com/time-zone/usa/eastern-time/convert/ | ||
| # http://www.timeanddate.com/library/abbreviations/timezones/na/ | ||
| # Times are GMT +- x | ||
| # For eq. | ||
| # EST = -5 | ||
| # GMT = 0 | ||
| # UTC = 0 | ||
| #Times are in hours, | ||
| #2.5 = 2 and half hours | ||
| global times | ||
| times = {"ADT":-3,"HAA":-3, #Synonyms on the same line | ||
| "AKDT":-8,"HAY":-8, | ||
| "AKST":-9,"HNY":-9, | ||
| "AST":-4,"HNA":-4, | ||
| "CDT":-5,"HAC":-5, | ||
| "CST":-6,"HNC":-6, | ||
| "EDT":-4,"HAE":-4, | ||
| "EGST":0, | ||
| "EGT":-1, | ||
| "EST":-5,"HNE":-5,"ET":-5, | ||
| "HADT":-9, | ||
| "HAST":-10, | ||
| "MDT":-6,"HAR":-6, | ||
| "MST":-7,"HNR":-7, | ||
| "NDT":-2.5,"HAT":-2.5, | ||
| "NST":-3.5,"HNT":-3.5, | ||
| "PDT":-7,"HAP":-7, | ||
| "PMDT":-2, | ||
| "PMST":-3, | ||
| "PST":-8,"HNP":-8,"PT":-8, | ||
| "WGST":-2, | ||
| "WGT":-3, | ||
| "GMT":0, | ||
| "UTC":0} | ||
| def converter(zones,time): | ||
| #Zones should be a list containing | ||
| # ( From zone | ||
| # To zone ) | ||
| global times | ||
| #from_z = for example UTC+00:00, WGT or GMT-05:30 | ||
| #to_z = same style as above. | ||
| from_z,to_z = zones | ||
| from_z = from_z.upper() | ||
| to_z = to_z.upper() | ||
| if from_z.find("+") != -1: | ||
| from_zone_offset = from_z[from_z.find("+"):] | ||
| if ":" in from_zone_offset: | ||
| try: | ||
| from_zone_offset1,from_zone_offset2 = from_zone_offset.split(":") | ||
| except ValueError: | ||
| return "Too many or too small amount of values" | ||
| try: | ||
| from_zone_offset = int(from_zone_offset1) + int(from_zone_offset2)/60.0 | ||
| except: | ||
| return "Error, the 'From Zone' variable has an incorrect offset number" | ||
| else: | ||
| try: | ||
| from_zone_offset = float(from_zone_offset) | ||
| except: | ||
| return "Error, the 'From Zone' variable has an incorrect offset number" | ||
| try: | ||
| from_zone_realtime = from_zone_offset + times[from_z[:from_z.find("+")]] | ||
| except KeyError: | ||
| return "Incorrect From zone" | ||
|
|
||
| elif "-" in from_z: | ||
| from_zone_offset = from_z[from_z.find("-"):] | ||
| if ":" in from_zone_offset: | ||
| from_zone_offset1,from_zone_offset2 = from_zone_offset.split(":") | ||
| try: | ||
| from_zone_offset = -int(from_zone_offset1) + int(from_zone_offset2)/60.0 | ||
| except: | ||
| return "Error, the 'From Zone' variable has an incorrect offset number" | ||
| else: | ||
| try: | ||
| from_zone_offset = -float(from_zone_offset) | ||
| except: | ||
| return "Error, the 'From Zone' variable has an incorrect offset number" | ||
| from_zone_realtime = times[from_z[:from_z.find("-")]] - from_zone_offset | ||
| pass | ||
| else: | ||
| from_zone_offset = 0 | ||
| try: | ||
| from_zone_realtime = from_zone_offset + times[from_z] | ||
| except KeyError: | ||
| return "Incorrect From zone" | ||
| if to_z.find("+") != -1: | ||
| to_zone_offset = to_z[to_z.find("+"):] | ||
| if ":" in to_zone_offset: | ||
| try: | ||
| to_zone_offset1,to_zone_offset2 = to_zone_offset.split(":") | ||
| except ValueError: | ||
| return "Too many or too small amount of values" | ||
| try: | ||
| to_zone_offset = int(to_zone_offset1) + int(to_zone_offset2)/60.0 | ||
| except: | ||
| return "Error, the 'To Zone' variable has an incorrect offset number" | ||
| else: | ||
| try: | ||
| to_zone_offset = float(to_zone_offset) | ||
| except: | ||
| return "Error, the 'To Zone' variable has an incorrect offset number" | ||
| try: | ||
| to_zone_realtime = to_zone_offset + times[to_z[:to_z.find("+")]] | ||
| except KeyError: | ||
| return "The zone you want the time to be changed to is not found" | ||
|
|
||
| elif "-" in to_z: | ||
| to_zone_offset = to_z[to_z.find("-"):] | ||
| if ":" in to_zone_offset: | ||
| to_zone_offset1,to_zone_offset2 = to_zone_offset.split(":") | ||
| try: | ||
| to_zone_offset = -int(to_zone_offset1) + int(to_zone_offset2)/60.0 | ||
| except: | ||
| return "Error, the 'To Zone' variable has an incorrect offset number" | ||
| else: | ||
| try: | ||
| to_zone_offset = -float(to_zone_offset) | ||
| except: | ||
| return "Error, the 'To Zone' variable has an incorrect offset number" | ||
| to_zone_realtime = times[to_z[:to_z.find("-")]] -to_zone_offset | ||
|
|
||
| pass | ||
| else: | ||
| to_zone_offset = 0 | ||
| try: | ||
| to_zone_realtime = to_zone_offset + times[to_z] | ||
| except KeyError: | ||
| return "Incorrect To zone" | ||
| try: | ||
| time_hour,time_minute = time.split(":") | ||
| time_hour,time_minute = int(time_hour),int(time_minute) | ||
| string = ":" | ||
| except: | ||
| try: | ||
| time_hour,time_minute = time.split(".") | ||
| time_hour,time_minute = int(time_hour),int(time_minute) | ||
| string = "." | ||
| except ValueError: | ||
| return "The time was input in an odd way" | ||
| if to_zone_realtime % 1.0 == 0.0 and from_zone_realtime % 1.0 == 0.0: | ||
| time_hour = time_hour + (to_zone_realtime - from_zone_realtime) | ||
| return str(int(time_hour))+string+str(int(time_minute)) | ||
| else: | ||
| if to_zone_realtime % 1.0 != 0.0 and from_zone_realtime % 1.0 != 0.0: | ||
| time_minute = time_minute + (((to_zone_realtime % 1.0) * 60) - ((from_zone_realtime % 1.0) * 60)) | ||
| elif to_zone_realtime % 1.0 != 0.0 and from_zone_realtime % 1.0 == 0.0: | ||
| time_minute = time_minute + (((to_zone_realtime % 1.0) * 60) - 0) | ||
| elif to_zone_realtime % 1.0 == 0.0 and from_zone_realtime % 1.0 != 0.0: | ||
| time_minute = time_minute + (0 - ((from_zone_realtime % 1.0) * 60)) | ||
| else: | ||
| print "Wut?" | ||
| time_hour = time_hour + (int(to_zone_realtime//1) - int(from_zone_realtime//1)) | ||
| return str(int(time_hour))+string+str(int(time_minute)) | ||
|
|
||
|
|
||
| def formatter(time): | ||
| if "." in time: | ||
| string = "." | ||
| elif ":" in time: | ||
| string = ":" | ||
| else: | ||
| return time | ||
| hours,minutes = time.split(string) | ||
| days = 0 | ||
| if int(minutes) < 0: | ||
| buphours = int(hours) | ||
| hours,minutes = divmod(int(minutes),60) | ||
| hours += buphours | ||
| if int(minutes) > 60: | ||
| hours,minutes = divmod(int(minutes),60) | ||
| hours += int(hours) | ||
| if int(hours) < 0: | ||
| days = 0 | ||
| days,hours = divmod(int(hours),24) | ||
| if int(hours) > 24: | ||
| days = 0 | ||
| days,hours = divmod(int(hours),24) | ||
| if int(hours) == 24 and int(minutes) > 0: | ||
| days += 1 | ||
| hours = int(hours) - 24 | ||
| hours = str(hours) | ||
| minutes = str(minutes) | ||
| if len(minutes) == 1: | ||
| minutes = "0"+minutes | ||
| if len(hours) == 1: | ||
| hours = "0"+hours | ||
| if days > 0: | ||
| if days == 1: | ||
| return hours+string+minutes+" (Tomorrow)" | ||
| else: | ||
| return hours+string+minutes+" (After "+str(days)+" days)" | ||
| elif days < 0: | ||
| if days == -1: | ||
| return hours+string+minutes+" (Yesterday)" | ||
| else: | ||
| return hours+string+minutes+" ("+str(abs(days))+" days ago)" | ||
| return hours+string+minutes | ||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
| @@ -0,0 +1,61 @@ | ||
| # -*- coding: cp1252 -*- | ||
| import urllib,xml.sax.handler | ||
| # S10 COMPATIABLE | ||
| def message(data): | ||
| if data["type"] == "PRIVMSG": | ||
| try: | ||
| splitdata = data["content"].lower().split(" ") | ||
| if splitdata[0] == ":weather" and len(splitdata) > 1: | ||
| data = Weather(" ".join(splitdata[1:])) | ||
|
|
||
| data["conn"].privmsg(data["target"],"Weather for "+data[1]+": "+data[0]) | ||
| return True | ||
| except KeyError: | ||
| print "WUT" | ||
| else: | ||
| return -1 | ||
| def Weather(question): | ||
| question = question.replace("ä","a") | ||
| url = "http://api.wunderground.com/auto/wui/geo/WXCurrentObXML/index.xml?query="+question | ||
| opener = urllib.FancyURLopener({}) | ||
| f = opener.open(url) | ||
| data = f.read() | ||
| f.close() | ||
| bufferi = [] | ||
| seen = False | ||
| for i in data.split("\n"): | ||
| if "<temperature_string>" in i: | ||
| stuff = cutter(i,"<temperature_string>") | ||
| if len(stuff) > 7: | ||
| bufferi.append("Temperature: "+stuff) | ||
| elif "<observation_time>" in i: | ||
| stuff = cutter(i,"<observation_time>") | ||
| if len(stuff) > 19: | ||
| bufferi.append(stuff) | ||
| elif "<weather>" in i: | ||
| stuff = cutter(i,"<weather>") | ||
| if len(stuff) > 0: | ||
| bufferi.append("Weather: "+stuff) | ||
| elif "<relative_humidity>" in i: | ||
| stuff = cutter(i,"<relative_humidity>") | ||
| if len(stuff) > 0: | ||
| bufferi.append("Humidity: "+stuff) | ||
| elif "<wind_string>" in i: | ||
| stuff = cutter(i,"<wind_string>") | ||
| if len(stuff) > 0: | ||
| bufferi.append("Wind blows "+stuff) | ||
| elif "<pressure_string>" in i: | ||
| stuff = cutter(i,"<pressure_string>") | ||
| if len(stuff) > 9: | ||
| bufferi.append("Air pressure is "+stuff) | ||
| elif "<full>" in i and seen == False: | ||
| seen = True | ||
| where = cutter(i,"<full>") | ||
| if len(where) == 4: | ||
| where = "Location doesn't exist" | ||
| return [", ".join(bufferi),where] | ||
| def cutter(fullstring,cut): | ||
| fullstring = fullstring.replace(cut,"") | ||
| fullstring = fullstring.replace("</"+cut[1:],"") | ||
| fullstring = fullstring.replace("\t","") | ||
| return fullstring |
| @@ -0,0 +1,75 @@ | ||
| from urllib2 import urlopen | ||
| from CORE_DATA import directory,no_absolute_paths | ||
| def YTCV2(youtube_url,cache=1,debug=0): | ||
| import time | ||
| __doc__ = "Cache 0 = No cache access, Cache 1 = Cache access (Default)" | ||
| if cache == 1: | ||
| import md5 | ||
| import pickle | ||
| crypt = md5.md5(youtube_url) | ||
| try: | ||
| cryp = crypt.hexdigest() | ||
| if no_absolute_paths: | ||
| tiedosto = open("YTCache/"+cryp,"r") | ||
| else: | ||
| tiedosto = open(directory+"\NanoTrasen\YTCache\\"+cryp,"r") | ||
| aha = pickle.load(tiedosto) | ||
| tiedosto.close() | ||
| return aha[0] | ||
| except: | ||
| if no_absolute_paths: | ||
| tiedosto = open("YTCache/"+crypt.hexdigest(),"w") | ||
| else: | ||
| tiedosto = open(directory+"\NanoTrasen\YTCache\\"+crypt.hexdigest(),"w") | ||
| else: | ||
| pass | ||
| youtube_url = youtube_url.replace("http//","http://") | ||
| if youtube_url.lower()[0:7] != "http://" and youtube_url[0:4] == "www.": | ||
| youtube_url = "http://" + youtube_url | ||
| if youtube_url.count("/") + youtube_url.count("\\") < 3: | ||
| return "Reflex: Video cannot exist" | ||
| else: | ||
| if youtube_url[0:7].lower() != "http://": | ||
| return "Reflex: Incorrect link start" | ||
| try: | ||
| website = urlopen(youtube_url) | ||
| except: | ||
| return "Reflex: Incorrect link!" | ||
| for i in website: | ||
| if i.count('<meta name="title" content') == 1: | ||
| epoch = time.time() | ||
| if type(i[30:-3]) != str: | ||
| if cache == 1: | ||
| aha = ["No title for video",epoch] | ||
| pickle.dump(aha,tiedosto) | ||
| tiedosto.close() | ||
| tiedosto.close() | ||
| return "Video deleted" | ||
| else: | ||
| result = i[30:-3] | ||
| if "&quot;" in result: | ||
| result = result.replace("&quot;",'"') | ||
| else: | ||
| pass | ||
| if "&amp;" in result: | ||
| result = result.replace("&amp;","&") | ||
| else: | ||
| pass | ||
| if "&#39;" in result: | ||
| result = result.replace("&#39;","'") | ||
| else: | ||
| pass | ||
| if cache == 1: | ||
| aha = [result,epoch] | ||
| pickle.dump(aha,tiedosto) | ||
| tiedosto.close() | ||
| tiedosto.close() | ||
| return result | ||
|
|
||
| if cache == 1: | ||
| epoch = time.time() | ||
| aha = ["No title for video, could be removed / does not exist at all",epoch] | ||
| pickle.dump(aha,tiedosto) | ||
| tiedosto.close() | ||
| tiedosto.close() | ||
| return "No title for video, could be removed / does not exist at all" |
| @@ -0,0 +1,132 @@ | ||
| from urllib2 import urlopen | ||
| import os | ||
| import pickle | ||
| from CORE_DATA import directory,no_absolute_paths | ||
| global did_tell, no_absolute_paths | ||
| no_absolute_paths = True | ||
| did_tell = False | ||
| def YTCV4(youtube_url,cache=1,debug=0): | ||
| global did_tell, no_absolute_paths | ||
| Do_not_open = True | ||
| __doc__ = "Cache does not affect anything, it's legacy for skibot." | ||
| try: | ||
| cut_down = youtube_url.split("watch?v=")[1].split("&")[0] | ||
| if len(cut_down) > 11: #Longer than normal, presume troll. | ||
| youtube_url.replace(cut_down,cut_down[:11]) | ||
| elif len(cut_down) < 11: #Shorter than normal | ||
| pass | ||
| except IndexError: | ||
| return "Reflex: Where's the watch?v=?" | ||
| first_two = cut_down[0:2] | ||
| try: | ||
| if no_absolute_paths: | ||
| tiedosto = open("YTCache/"+first_two+".tcc","r") | ||
| else: | ||
| tiedosto = open(directory+"YTCache/"+first_two+".tcc","r") | ||
| except: | ||
| prev_dict = {} | ||
| else: | ||
| try: | ||
| prev_dict = pickle.load(tiedosto) | ||
| except EOFError: # Cache is corrupt | ||
| os.remove(directory+tiedosto.name) | ||
| print "REMOVED CORRUPT CACHE: "+tiedosto.name | ||
| prev_dict = {} | ||
| tiedosto.close() # I think this should belong here. | ||
| if cut_down in prev_dict.keys(): | ||
| return prev_dict[cut_down] | ||
| else: | ||
| pass | ||
| try: | ||
| if no_absolute_paths: | ||
| tiedosto = open("YTCache/"+first_two+".tcc","w") | ||
| else: | ||
| tiedosto = open(directory+"YTCache/"+first_two+".tcc","w") | ||
| except IOError,error: | ||
| if len(prev_dict.keys()) > 0: | ||
| try: | ||
| tiedosto = open(directory+"YTCache/"+first_two+".tcc","w") #This is a Just In Case | ||
| except IOError: | ||
| if did_tell == False: | ||
| did_tell = True | ||
| return "COULD NOT ACCESS FILE "+first_two+".tcc! The next time you run this link, it checks it through the web" | ||
| Do_not_open = False | ||
| else: | ||
| did_tell = False | ||
| pickle.dump(prev_dict,tiedosto) | ||
| tiedosto.close() | ||
| else: | ||
| pass | ||
| return "Very odd error occurred: " + str(error) | ||
| youtube_url = youtube_url.replace("http//","http://") | ||
| if youtube_url.lower()[0:7] != "http://" and youtube_url[0:4] == "www.": | ||
| youtube_url = "http://" + youtube_url | ||
| if youtube_url.count("/") + youtube_url.count("\\") < 3: | ||
| if len(prev_dict.keys()) > 0: | ||
| if Do_not_open == True: | ||
| tiedosto = open(directory+"YTCache/"+first_two+".tcc","w") #This is a Just In Case | ||
| pickle.dump(prev_dict,tiedosto) | ||
| tiedosto.close() | ||
| else: | ||
| pass | ||
| return "Reflex: Video cannot exist" | ||
| else: | ||
| if "http://" in youtube_url[0:12].lower() and youtube_url[0:7].lower() != "http://": | ||
| youtube_url = youtube_url[youtube_url.find("http://"):] | ||
| elif youtube_url[0:7].lower() != "http://": | ||
| if len(prev_dict.keys()) > 0: | ||
| if Do_not_open == True: | ||
| tiedosto = open(directory+"YTCache/"+first_two+".tcc","w") #This is a Just In Case | ||
| pickle.dump(prev_dict,tiedosto) | ||
| tiedosto.close() | ||
| return "Reflex: Incorrect link start" | ||
| if "?feature=player_embedded&" in youtube_url: | ||
| youtube_url = youtube_url.replace("?feature=player_embedded&","?") | ||
| try: | ||
| website = urlopen(youtube_url) | ||
| except: | ||
| if len(prev_dict.keys()) > 0: | ||
| if Do_not_open == True: | ||
| tiedosto = open(directory+"YTCache/"+first_two+".tcc","w") #This is a Just In Case | ||
| pickle.dump(prev_dict,tiedosto) | ||
| tiedosto.close() | ||
| else: | ||
| pass | ||
| return "Reflex: Incorrect link!" | ||
| for i in website.readlines(): | ||
| if i.count('<meta name="title" content') == 1: | ||
| if type(i[30:-3]) != str: | ||
| if Do_not_open == True: | ||
| tiedosto = open(directory+"YTCache/"+first_two+".tcc","w") #This is a Just In Case | ||
| prev_dict[cut_down] = "No title for video" | ||
| pickle.dump(prev_dict,tiedosto) | ||
| tiedosto.close() | ||
| return "Video deleted" | ||
| else: | ||
| #result = i[30:-3] | ||
| contentvar = i.find('content="') | ||
| result = i[contentvar+5:i.find('">',contentvar)] | ||
| if "&quot;" in result: | ||
| result = result.replace("&quot;",'"') | ||
| else: | ||
| pass | ||
| if "&amp;" in result: | ||
| result = result.replace("&amp;","&") | ||
| else: | ||
| pass | ||
| if "&#39;" in result: | ||
| result = result.replace("&#39;","'") | ||
| else: | ||
| pass | ||
| if Do_not_open == True: | ||
| tiedosto = open(directory+"YTCache/"+first_two+".tcc","w") #This is a Just In Case | ||
| prev_dict[cut_down] = result | ||
| pickle.dump(prev_dict,tiedosto) | ||
| tiedosto.close() | ||
| return result | ||
| if Do_not_open == True: | ||
| tiedosto = open(directory+"YTCache/"+first_two+".tcc","w") #This is a Just In Case | ||
| prev_dict[cut_down] = "No title for video, Removed / Needs Age verification / Does not exist" | ||
| pickle.dump(prev_dict,tiedosto) | ||
| tiedosto.close() | ||
| return "No title for video, Removed / Needs age verification / Does not exist" |
| @@ -0,0 +1,74 @@ | ||
| /// Adminhelp relay IRC bot setup guide | ||
| /// CC_Nanotrasen bot created by Skibiliano and distributed under the CC-BY-SA 3.0 license | ||
| /// All derivative works of this bot must properly credit Skibiliano as the original author | ||
| /// Big thanks to Skibiliano his bot and allowing distribution, and to BS12 for sharing their code for making use of it ingame | ||
|
|
||
| QUESTION: What does this bot do? | ||
| ANSWER: It, in conjunction with BYOND, relays adminhelps to a designated channel, along with various extra functions that can be accessed by saying !help in the same channel/in a query with the bot. | ||
|
|
||
| Some basic info before you set this up: | ||
| CC_Nanotrasen is coded in python 2.6 and requires a serverside installation of python 2.6 (obtainable at http://www.python.org/getit/releases/2.6/) | ||
| - Python MUST BE installed to the same directory as the .dmb you are using to host your server/server config folder | ||
| - CC_Nanotrasen supports, but does not require, Psyco (obtainable at http://psyco.sourceforge.net/download.html) which increases the speed 20-30% and slightly increases RAM usage | ||
|
|
||
| Now that that's out of the way, I'll teach you how to set this up. | ||
|
|
||
| BOT CONFIG: | ||
| Move everything in this folder (this file noninclusive) to the same folder as the hosting server (where your .dmb, config folder, and python are installed) | ||
| Open CORE_DATA.py with a text editor of your choice (recommended to be notepad++ or notepad) | ||
| You should see 14 lines of code which look like | ||
| Name = "CC_NanoTrasen" #The name he uses to connect | ||
| no_absolute_paths = True #Do not change this. | ||
| debug_on = False | ||
| SName = ["cc","nt","trasen","nano","nanotrasen"] #Other names he will respond to, must be lowercase | ||
| DISABLE_ALL_NON_MANDATORY_SOCKET_CONNECTIONS = False | ||
| directory = "BOT DIRECTORY GOES HERE/" #make sure to keep the "/" at the end | ||
| version = "TG CC-BY-SA 6" | ||
| Network = 'irc.server.goes.here' #e.g. "irc.rizon.net" | ||
| channel = "#CHANNEL GOES HERE" #what channel you want the bot in | ||
| channels = ["#CHANNEL GOES HERE","#ALSO ANOTHER CHANNEL GOES HERE IF YOU WANT"] #same as above | ||
| greeting = "Welcome!" #what he says when a person he hasn't seen before joins | ||
| prefix = "!" #prefix for bot commands | ||
| Port = 7000 | ||
| There are some basic comments besides every important config option in here, but I'll summarize them in detail | ||
| NAME - The name the bot assumes when it connects to IRC, so in this example it would join the IRC under the nickname "CC_Nanotrasen" | ||
| SNAME - A list of secondary names, with commas, that the bot will respond to for commands (for example, this setup will allow the bot to respond to "nt, tell quarxink he's a terrible writer") | ||
| DIRECTORY - The directory of the bot files, dmb, python, and config folder IN FORWARD SLASHES, WITH FORWARD SLASH AT THE END(for example, I host my test server from "c:\tgstation\tgstation13\tgstation.dmb" so for me the line would say directory = "c:/tgstation/tgstation13/") | ||
| NETWORK - The IRC server it will connect to, such as "irc.rizon.net" | ||
| CHANNEL/CHANNELS - what channel the bot will join (channels allows for multiple channel connections, in the same formatting as SName separates nicknames) | ||
| GREETING - CC_Nanotrasen will store the names of people it has seen before, but when a nickname joins that it hasn't seen before it will greet that person with whatever message is put in this | ||
| PREFIX = What character/string will be placed before commands for the bot (so if you changed this to "$", you would pull up the bot's help menu by saying $help instead of !help) | ||
| PORT - What port to connect to for the IRC server (if you are unsure of what port to use, most IRC clients will show you what port you are connecting to) | ||
|
|
||
| Once you have that ready, you're on to step two. | ||
| Open up the config folder in your install dir, and open config.txt | ||
| Scroll to the bottom, right below #FORBID_SINGULO_POSSESSION should be | ||
| ##Remove the # mark if you are going to use the SVN irc bot to relay adminhelps | ||
| #USEIRCBOT | ||
| Just remove the "#" in front of USEIRCBOT (you don't even have to recompile your DMB! | ||
|
|
||
| Got that all ready to go? Good, it's time for step three. | ||
| Open Dream Daemon (that thing you use when you host) | ||
| On the bottom of the window you should see port, security, and visibility. | ||
| Change security to "Trusted" | ||
|
|
||
| Congratulations, you've set up this bot! | ||
| A few things to note as far as features: | ||
| Use !help to list most commands for the bot. | ||
| You can leave notes for other users! Just say "[bot name], tell [other user's name] [message]" | ||
| So let's say you wonder if I'm going to jump in to your IRC ever and you want to tell me this readme was horrible, you would say "Nano, tell Quarxink Your readme was horrible" | ||
|
|
||
| TROUBLESHOOTING: | ||
| Attempting to run the bot gives me an error about encoding.utf-8. | ||
| You've probably installed python to a separate folder than the bot/server, move python's files over and it should run fine | ||
|
|
||
| It's telling me connection refused when someone adminhelps. | ||
| You've moved the bot to a separate folder from the nudge script, most likely. | ||
|
|
||
| BYOND asks me on any restart if I want to allow nudge.py to run. | ||
| Set security to trusted in Dream Daemon | ||
|
|
||
|
|
||
|
|
||
|
|
||
| If you have any requests, suggestions, or issues not covered by this guide, I can be contacted as Quarxink at #coderbus on irc.rizon.net (If I don't respond, leave me a query with your problem and how to reach you [preferably an email address, steam, other irc channel, or aim/msn]) |
| @@ -0,0 +1,15 @@ | ||
| from FMLformatter import formatter | ||
| from urllib2 import urlopen | ||
| try: | ||
| from hashlib import md5 | ||
| except: | ||
| from md5 import md5 | ||
| from save_load import save,load | ||
| import CORE_DATA | ||
| directory = CORE_DATA.directory | ||
| FML = urlopen("http://www.fmylife.com/random") | ||
| formatted = formatter(FML.read().split("\n")) | ||
| for Quote in formatted: | ||
| exact = Quote[:Quote.find("#")] | ||
| # print exact | ||
| save(directory+"fmlquotes/"+md5(exact).hexdigest()+".txt",exact) |
| @@ -0,0 +1,28 @@ | ||
| def htr(data): | ||
| ignore = False | ||
| if type(data) == list: | ||
| b = [] | ||
| for olio in data: | ||
| tempolio = "" | ||
| for letter in olio: | ||
| if letter == "<": | ||
| ignore = True | ||
| else: | ||
| pass | ||
| if ignore != True: | ||
| tempolio += letter | ||
| else: | ||
| pass | ||
| if letter == ">": | ||
| ignore = False | ||
| else: | ||
| pass | ||
| tempolio = tempolio.replace("\t","") | ||
| if len(tempolio) == 0: | ||
| pass | ||
| elif len(tempolio.replace(" ","")) == 0: | ||
| pass | ||
| else: | ||
| b.append(tempolio) | ||
| #Finetuning | ||
| return b |
| @@ -0,0 +1,94 @@ | ||
| import socket | ||
| import time | ||
| class IRC: | ||
| queue = [] | ||
| partial = '' | ||
| def __init__ ( self, network, port, name, hostName, serverName, realName ): | ||
| self.network = network | ||
| self.port = port | ||
| self.hostName = hostName | ||
| self.serverName = serverName | ||
| self.realName = realName | ||
| self.socket = socket.socket ( socket.AF_INET, socket.SOCK_STREAM ) | ||
| self.socket.connect ( ( self.network, self.port ) ) | ||
| self.address = self.socket.getpeername() | ||
| self.nick ( name ) | ||
| self.send ( 'USER ' + self.name + ' ' + self.serverName + ' ' + self.hostName + ' :' + self.realName ) | ||
| def quit ( self ): | ||
| self.send ( 'QUIT' ) | ||
| self.socket.close() | ||
| def send ( self, text ): | ||
| count = 0 | ||
| try: | ||
| count += 1 | ||
| self.socket.send ( text + '\r\n' ) | ||
| except: | ||
| if count > 10: | ||
| time.sleep(1) | ||
| self.socket.send(text+'\r\n') | ||
| else: | ||
| count = 0 | ||
| def nick ( self, name ): | ||
| self.name = name | ||
| self.send ( 'NICK ' + self.name ) | ||
| def addressquery(self): | ||
| print self.address | ||
| aha = socket.gethostbyaddr(str(self.address[0])) | ||
| return aha | ||
| def recv ( self, size = 2048 ): | ||
| commands = self.socket.recv ( size ).split ( '\r\n' ) | ||
| if len ( self.partial ): | ||
| commands [ 0 ] = self.partial + commands [ 0 ] | ||
| self.partial = '' | ||
| if len ( commands [ -1 ] ): | ||
| self.partial = commands [ -1 ] | ||
| self.queue.extend ( commands [ :-1 ] ) | ||
| else: | ||
| self.queue.extend ( commands ) | ||
| def retrieve ( self ): | ||
| if len ( self.queue ): | ||
| command = self.queue [ 0 ] | ||
| self.queue.pop ( 0 ) | ||
| return command | ||
| else: | ||
| return False | ||
| def dismantle ( self, command ): | ||
| if command: | ||
| source = command.split ( ':' ) [ 1 ].split ( ' ' ) [ 0 ] | ||
| parameters = command.split ( ':' ) [ 1 ].split ( ' ' ) [ 1: ] | ||
| if len(parameters) > 0: | ||
| if not len ( parameters [ -1 ] ): | ||
| parameters.pop() | ||
| if command.count ( ':' ) > 1: | ||
| parameters.append(command[command.find(":",command.find(":")+1)+1:]) | ||
| return source, parameters | ||
| def privmsg ( self, destination, message ): | ||
| self.send ( 'PRIVMSG ' + destination + ' :' + message ) | ||
| def handshake(self,hexstring): | ||
| self.send("PONG :"+hexstring) | ||
| def notice ( self, destination, message ): | ||
| self.send ( 'NOTICE ' + destination + ' :' + message ) | ||
| def join ( self, channel ): | ||
| self.send ( 'JOIN ' + channel ) | ||
| def part ( self, channel ): | ||
| self.send ( 'PART ' + channel ) | ||
| def topic ( self, channel, topic = '' ): | ||
| self.send ( 'TOPIC ' + channel + ' ' + topic ) | ||
| def names ( self, channel ): | ||
| self.send ( 'NAMES ' + channel ) | ||
| def invite ( self, nick, channel ): | ||
| self.send ( 'INVITE ' + nick + ' ' + channel ) | ||
| def mode ( self, channel, mode, nick = '' ): | ||
| self.send ( 'MODE ' + channel + ' ' + mode + ' ' + nick ) | ||
| def banon(self,channel,name): | ||
| self.mode(channel,"+b",name) | ||
| def banoff(self,channel,name): | ||
| self.mode(channel,"-b",name) | ||
| def kick ( self, channel, nick, reason = '' ): | ||
| self.send ( 'KICK ' + channel + ' ' + nick + ' ' + reason ) | ||
| def who ( self, pattern ): | ||
| self.send ( 'WHO ' + pattern ) | ||
| def whois ( self, nick ): | ||
| self.send ( 'WHOIS ' + nick ) | ||
| def whowas ( self, nick ): | ||
| self.send ( 'WHOWAS ' + nick ) |
| @@ -0,0 +1,43 @@ | ||
| import os | ||
| directory = "" | ||
| raw = os.listdir(directory) | ||
| extract = [] | ||
| for i in raw: | ||
| if i[-3:] == ".py": | ||
| extract.append(i) | ||
| toc = 0 | ||
| toc3 = 0 | ||
| toc2 = 0 | ||
| print len(extract),"Files" | ||
| lista = [] | ||
| for ob in extract: | ||
| count3 = 0 | ||
| if directory == "": | ||
| tiedosto = open(ob,"r") | ||
| tiedosto2 = open(ob,"r") | ||
| count3 += os.path.getsize(ob) | ||
| toc3 += count3 | ||
| else: | ||
| tiedosto = open(directory+"/"+ob,"r") | ||
| tiedosto2 = open(directory+"/"+ob,"r") | ||
| count3 += os.path.getsize(directory+"/"+ob) | ||
| toc3 += count3 | ||
| count = 0 | ||
| count2 = 0 | ||
| line = tiedosto.readline() | ||
| while line != "": | ||
| count += 1 | ||
| toc += 1 | ||
| line = tiedosto.readline() | ||
| count2 += len(tiedosto2.read()) | ||
| toc2 += count2 | ||
| lista.append([count,count2,ob,count3]) | ||
| tiedosto.close() | ||
| tiedosto2.close() | ||
| print toc,"Lines in total" | ||
| print toc2,"Letters in total" | ||
| print toc3,"Bytes in total" | ||
|
|
||
| for linecount, lettercount, filename, bytecount in lista: | ||
| print str(linecount)+" Lines (%s%%) || "%(str(round((float(linecount)/toc)*100,1))),str(lettercount)+" Letters (%s%%) in file " %(str(round((float(lettercount)/toc2)*100,1)))+filename | ||
| print str(bytecount) + " Bytes (%s%%) "%(str(round((float(bytecount)/toc3)*100,1))) |
| @@ -0,0 +1,39 @@ | ||
| import sys,pickle,socket, CORE_DATA | ||
| #def pack(): | ||
| # path = "/home/ski/Nanotrasen/message.txt" | ||
| # ip = sys.argv[1] | ||
| # dictionary = {"ip":ip,"data":1} | ||
| # try: | ||
| # targetfile = open(path,"r") | ||
| # except IOError: | ||
| # targetfile = open(path,"w") | ||
| # pickle.dump(dictionary,targetfile) | ||
| # targetfile.close() | ||
| # nudge() | ||
| # else: | ||
| # targetfile.close() #Professionals, have standards. | ||
| # pass | ||
| def pack(): | ||
| ip = sys.argv[1] | ||
| try: | ||
| data = sys.argv[2:] #The rest of the arguments is data | ||
| except: | ||
| data = "NO DATA SPECIFIED" | ||
| dictionary = {"ip":ip,"data":data} | ||
| pickled = pickle.dumps(dictionary) | ||
| nudge(pickled) | ||
| def nudge(data): | ||
| if CORE_DATA.DISABLE_ALL_NON_MANDATORY_SOCKET_CONNECTIONS: | ||
| pass | ||
| else: | ||
| HOST = "localhost" | ||
| PORT = 45678 | ||
| size = 1024 | ||
| s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||
| s.connect((HOST,PORT)) | ||
| s.send(data) | ||
| s.close() | ||
|
|
||
| if __name__ == "__main__" and len(sys.argv) > 1: # If not imported and more than one argument | ||
| pack() | ||
|
|
| @@ -0,0 +1,24 @@ | ||
| import pickle | ||
| def save(filename,data,dnrw=0): | ||
| if dnrw == 1: | ||
| try: | ||
| tiedosto = open(filename,"r") | ||
| except: | ||
| tiedosto = open(filename,"w") | ||
| else: | ||
| return False | ||
| else: | ||
| tiedosto = open(filename,"w") | ||
|
|
||
| if "http//" in data: | ||
| data = data.replace("http//","http://") | ||
| pickle.dump(data,tiedosto) | ||
| tiedosto.close() | ||
| def load(filename): | ||
| try: | ||
| tiedosto = open(filename,"r") | ||
| except IOError: | ||
| return "ERROR ERROR ERROR ERR" | ||
| a = pickle.load(tiedosto) | ||
| tiedosto.close() | ||
| return a |
| @@ -0,0 +1,20 @@ | ||
| def sbna2(only_one,one_of_these,data): | ||
| if type(only_one) != list: | ||
| only_one = list(only_one) | ||
| if type(data) != list: | ||
| data = data.split(" ") | ||
| count = 0 | ||
| for datoid in only_one: | ||
| if datoid in data and count >= 1: | ||
| return False | ||
| elif datoid in data: | ||
| count += 1 | ||
| pass | ||
| else: | ||
| pass | ||
| if count == 0: | ||
| return False | ||
| for datoid in one_of_these: | ||
| if datoid in data: | ||
| return True | ||
| return False |
| @@ -0,0 +1,40 @@ | ||
| from urllib2 import urlopen | ||
| from json import loads | ||
| from pickle import dump,load | ||
| from CORE_DATA import no_absolute_paths | ||
| def xkcd(link): | ||
| try: | ||
| filename = link[link.find("xkcd.com")+9:].replace("/","").replace("\\","") | ||
| if no_absolute_paths: | ||
| tiedosto = open("xkcdcache/"+filename,"r") | ||
| else: | ||
| tiedosto = open(directory+"xkcdcache/"+filename,"r") | ||
| except: | ||
| try: | ||
| if no_absolute_paths: | ||
| tiedosto = open("xkcdcache/"+filename,"w") | ||
| else: | ||
| tiedosto = open(directory+"xkcdcache/"+filename,"w") | ||
| except IOError: | ||
| return "NOTHING" | ||
| else: | ||
| try: | ||
| return load(tiedosto) | ||
| except EOFError: | ||
| tiedosto = open("xkcdcache/"+filename,"w") | ||
| pass #Corrupt cache, moving on. | ||
| if link[-1] == "/" or link[-1] == "\\": #Ending is fine. | ||
| link += "info.0.json" | ||
| else: | ||
| link += "/info.0.json" | ||
| try: | ||
| data = urlopen(link).read() | ||
| except: | ||
| return "NOTHING" | ||
| try: | ||
| newdata = loads(data)["title"] | ||
| dump(newdata,tiedosto) | ||
| return newdata | ||
| except: | ||
| return "NOTHING" | ||
|
|
| @@ -0,0 +1,295 @@ | ||
| //-------------------------------------------- | ||
| // Pipe colors | ||
| // | ||
| // Add them here and to the pipe_colors list | ||
| // to automatically add them to all relevant | ||
| // atmospherics devices. | ||
| //-------------------------------------------- | ||
|
|
||
| #define PIPE_COLOR_GREY "#ffffff" //yes white is grey | ||
| #define PIPE_COLOR_RED "#ff0000" | ||
| #define PIPE_COLOR_BLUE "#0000ff" | ||
| #define PIPE_COLOR_CYAN "#00ffff" | ||
| #define PIPE_COLOR_GREEN "#00ff00" | ||
| #define PIPE_COLOR_YELLOW "#ffcc00" | ||
| #define PIPE_COLOR_BLACK "#444444" | ||
| #define PIPE_COLOR_PURPLE "#5c1ec0" | ||
|
|
||
| #define CONNECT_TYPE_REGULAR 1 | ||
| #define CONNECT_TYPE_SUPPLY 2 | ||
| #define CONNECT_TYPE_SCRUBBER 4 | ||
| #define CONNECT_TYPE_HE 8 | ||
|
|
||
| var/global/list/pipe_colors = list("grey" = PIPE_COLOR_GREY, "red" = PIPE_COLOR_RED, "blue" = PIPE_COLOR_BLUE, "cyan" = PIPE_COLOR_CYAN, "green" = PIPE_COLOR_GREEN, "yellow" = PIPE_COLOR_YELLOW, "black" = PIPE_COLOR_BLACK, "purple" = PIPE_COLOR_PURPLE) | ||
|
|
||
| /proc/pipe_color_lookup(var/color) | ||
| for(var/C in pipe_colors) | ||
| if(color == pipe_colors[C]) | ||
| return "[C]" | ||
|
|
||
| /proc/pipe_color_check(var/color) | ||
| if(!color) | ||
| return 1 | ||
| for(var/C in pipe_colors) | ||
| if(color == pipe_colors[C]) | ||
| return 1 | ||
| return 0 | ||
|
|
||
| //-------------------------------------------- | ||
| // Icon cache generation | ||
| //-------------------------------------------- | ||
|
|
||
| /datum/pipe_icon_manager | ||
| var/list/pipe_icons[] | ||
| var/list/manifold_icons[] | ||
| var/list/device_icons[] | ||
| var/list/underlays[] | ||
| //var/list/underlays_down[] | ||
| //var/list/underlays_exposed[] | ||
| //var/list/underlays_intact[] | ||
| //var/list/pipe_underlays_exposed[] | ||
| //var/list/pipe_underlays_intact[] | ||
| var/list/omni_icons[] | ||
|
|
||
| /datum/pipe_icon_manager/New() | ||
| check_icons() | ||
|
|
||
| /datum/pipe_icon_manager/proc/get_atmos_icon(var/device, var/dir, var/color, var/state) | ||
| check_icons() | ||
|
|
||
| device = "[device]" | ||
| state = "[state]" | ||
| color = "[color]" | ||
| dir = "[dir]" | ||
|
|
||
| switch(device) | ||
| if("pipe") | ||
| return pipe_icons[state + color] | ||
| if("manifold") | ||
| return manifold_icons[state + color] | ||
| if("device") | ||
| return device_icons[state] | ||
| if("omni") | ||
| return omni_icons[state] | ||
| if("underlay") | ||
| return underlays[state + dir + color] | ||
| // if("underlay_intact") | ||
| // return underlays_intact[state + dir + color] | ||
| // if("underlay_exposed") | ||
| // return underlays_exposed[state + dir + color] | ||
| // if("underlay_down") | ||
| // return underlays_down[state + dir + color] | ||
| // if("pipe_underlay_exposed") | ||
| // return pipe_underlays_exposed[state + dir + color] | ||
| // if("pipe_underlay_intact") | ||
| // return pipe_underlays_intact[state + dir + color] | ||
|
|
||
| /datum/pipe_icon_manager/proc/check_icons() | ||
| if(!pipe_icons) | ||
| gen_pipe_icons() | ||
| if(!manifold_icons) | ||
| gen_manifold_icons() | ||
| if(!device_icons) | ||
| gen_device_icons() | ||
| if(!omni_icons) | ||
| gen_omni_icons() | ||
| //if(!underlays_intact || !underlays_down || !underlays_exposed || !pipe_underlays_exposed || !pipe_underlays_intact) | ||
| if(!underlays) | ||
| gen_underlay_icons() | ||
|
|
||
| /datum/pipe_icon_manager/proc/gen_pipe_icons() | ||
| if(!pipe_icons) | ||
| pipe_icons = new() | ||
|
|
||
| var/icon/pipe = new('icons/atmos/pipes.dmi') | ||
|
|
||
| for(var/state in pipe.IconStates()) | ||
| if(!state || findtext(state, "map")) | ||
| continue | ||
|
|
||
| var/cache_name = state | ||
| var/image/I = image('icons/atmos/pipes.dmi', icon_state = state) | ||
| pipe_icons[cache_name] = I | ||
|
|
||
| for(var/pipe_color in pipe_colors) | ||
| I = image('icons/atmos/pipes.dmi', icon_state = state) | ||
| I.color = pipe_colors[pipe_color] | ||
| pipe_icons[state + "[pipe_colors[pipe_color]]"] = I | ||
|
|
||
| pipe = new ('icons/atmos/heat.dmi') | ||
| for(var/state in pipe.IconStates()) | ||
| if(!state || findtext(state, "map")) | ||
| continue | ||
| pipe_icons["hepipe" + state] = image('icons/atmos/heat.dmi', icon_state = state) | ||
|
|
||
| pipe = new ('icons/atmos/junction.dmi') | ||
| for(var/state in pipe.IconStates()) | ||
| if(!state || findtext(state, "map")) | ||
| continue | ||
| pipe_icons["hejunction" + state] = image('icons/atmos/junction.dmi', icon_state = state) | ||
|
|
||
|
|
||
| /datum/pipe_icon_manager/proc/gen_manifold_icons() | ||
| if(!manifold_icons) | ||
| manifold_icons = new() | ||
|
|
||
| var/icon/pipe = new('icons/atmos/manifold.dmi') | ||
|
|
||
| for(var/state in pipe.IconStates()) | ||
| if(findtext(state, "clamps")) | ||
| var/image/I = image('icons/atmos/manifold.dmi', icon_state = state) | ||
| manifold_icons[state] = I | ||
| continue | ||
|
|
||
| if(findtext(state, "core") || findtext(state, "4way")) | ||
| var/image/I = image('icons/atmos/manifold.dmi', icon_state = state) | ||
| manifold_icons[state] = I | ||
| for(var/pipe_color in pipe_colors) | ||
| I = image('icons/atmos/manifold.dmi', icon_state = state) | ||
| I.color = pipe_colors[pipe_color] | ||
| manifold_icons[state + pipe_colors[pipe_color]] = I | ||
|
|
||
| /datum/pipe_icon_manager/proc/gen_device_icons() | ||
| if(!device_icons) | ||
| device_icons = new() | ||
|
|
||
| var/icon/device | ||
|
|
||
| device = new('icons/atmos/vent_pump.dmi') | ||
| for(var/state in device.IconStates()) | ||
| if(!state || findtext(state, "map")) | ||
| continue | ||
| device_icons["vent" + state] = image('icons/atmos/vent_pump.dmi', icon_state = state) | ||
|
|
||
| device = new('icons/atmos/vent_scrubber.dmi') | ||
| for(var/state in device.IconStates()) | ||
| if(!state || findtext(state, "map")) | ||
| continue | ||
| device_icons["scrubber" + state] = image('icons/atmos/vent_scrubber.dmi', icon_state = state) | ||
|
|
||
| /datum/pipe_icon_manager/proc/gen_omni_icons() | ||
| if(!omni_icons) | ||
| omni_icons = new() | ||
|
|
||
| var/icon/omni = new('icons/atmos/omni_devices.dmi') | ||
|
|
||
| for(var/state in omni.IconStates()) | ||
| if(!state || findtext(state, "map")) | ||
| continue | ||
| omni_icons[state] = image('icons/atmos/omni_devices.dmi', icon_state = state) | ||
|
|
||
|
|
||
| /datum/pipe_icon_manager/proc/gen_underlay_icons() | ||
|
|
||
| if(!underlays) | ||
| underlays = new() | ||
|
|
||
| var/icon/pipe = new('icons/atmos/pipe_underlays.dmi') | ||
|
|
||
| for(var/state in pipe.IconStates()) | ||
| if(state == "") | ||
| continue | ||
|
|
||
| var/cache_name = state | ||
|
|
||
| for(var/D in cardinal) | ||
| var/image/I = image('icons/atmos/pipe_underlays.dmi', icon_state = state, dir = D) | ||
| underlays[cache_name + "[D]"] = I | ||
| for(var/pipe_color in pipe_colors) | ||
| I = image('icons/atmos/pipe_underlays.dmi', icon_state = state, dir = D) | ||
| I.color = pipe_colors[pipe_color] | ||
| underlays[state + "[D]" + "[pipe_colors[pipe_color]]"] = I | ||
|
|
||
| /* | ||
| Leaving the old icon manager code commented out for now, as we may want to rewrite the new code to cleanly | ||
| separate the newpipe icon caching (speshul supply and scrubber lines) from the rest of the pipe code. | ||
| */ | ||
|
|
||
| /* | ||
| /datum/pipe_icon_manager/proc/gen_underlay_icons() | ||
| if(!underlays_intact) | ||
| underlays_intact = new() | ||
| if(!underlays_exposed) | ||
| underlays_exposed = new() | ||
| if(!underlays_down) | ||
| underlays_down = new() | ||
| if(!pipe_underlays_exposed) | ||
| pipe_underlays_exposed = new() | ||
| if(!pipe_underlays_intact) | ||
| pipe_underlays_intact = new() | ||
| var/icon/pipe = new('icons/atmos/pipe_underlays.dmi') | ||
| for(var/state in pipe.IconStates()) | ||
| if(state == "") | ||
| continue | ||
| for(var/D in cardinal) | ||
| var/image/I = image('icons/atmos/pipe_underlays.dmi', icon_state = state, dir = D) | ||
| switch(state) | ||
| if("intact") | ||
| underlays_intact["[D]"] = I | ||
| if("exposed") | ||
| underlays_exposed["[D]"] = I | ||
| if("down") | ||
| underlays_down["[D]"] = I | ||
| if("pipe_exposed") | ||
| pipe_underlays_exposed["[D]"] = I | ||
| if("pipe_intact") | ||
| pipe_underlays_intact["[D]"] = I | ||
| if("intact-supply") | ||
| underlays_intact["[D]"] = I | ||
| if("exposed-supply") | ||
| underlays_exposed["[D]"] = I | ||
| if("down-supply") | ||
| underlays_down["[D]"] = I | ||
| if("pipe_exposed-supply") | ||
| pipe_underlays_exposed["[D]"] = I | ||
| if("pipe_intact-supply") | ||
| pipe_underlays_intact["[D]"] = I | ||
| if("intact-scrubbers") | ||
| underlays_intact["[D]"] = I | ||
| if("exposed-scrubbers") | ||
| underlays_exposed["[D]"] = I | ||
| if("down-scrubbers") | ||
| underlays_down["[D]"] = I | ||
| if("pipe_exposed-scrubbers") | ||
| pipe_underlays_exposed["[D]"] = I | ||
| if("pipe_intact-scrubbers") | ||
| pipe_underlays_intact["[D]"] = I | ||
| for(var/pipe_color in pipe_colors) | ||
| I = image('icons/atmos/pipe_underlays.dmi', icon_state = state, dir = D) | ||
| I.color = pipe_colors[pipe_color] | ||
| switch(state) | ||
| if("intact") | ||
| underlays_intact["[D]" + pipe_colors[pipe_color]] = I | ||
| if("exposed") | ||
| underlays_exposed["[D]" + pipe_colors[pipe_color]] = I | ||
| if("down") | ||
| underlays_down["[D]" + pipe_colors[pipe_color]] = I | ||
| if("pipe_exposed") | ||
| pipe_underlays_exposed["[D]" + pipe_colors[pipe_color]] = I | ||
| if("pipe_intact") | ||
| pipe_underlays_intact["[D]" + pipe_colors[pipe_color]] = I | ||
| if("intact-supply") | ||
| underlays_intact["[D]" + pipe_colors[pipe_color]] = I | ||
| if("exposed-supply") | ||
| underlays_exposed["[D]" + pipe_colors[pipe_color]] = I | ||
| if("down-supply") | ||
| underlays_down["[D]" + pipe_colors[pipe_color]] = I | ||
| if("pipe_exposed-supply") | ||
| pipe_underlays_exposed["[D]" + pipe_colors[pipe_color]] = I | ||
| if("pipe_intact-supply") | ||
| pipe_underlays_intact["[D]" + pipe_colors[pipe_color]] = I | ||
| if("intact-scrubbers") | ||
| underlays_intact["[D]" + pipe_colors[pipe_color]] = I | ||
| if("exposed-scrubbers") | ||
| underlays_exposed["[D]" + pipe_colors[pipe_color]] = I | ||
| if("down-scrubbers") | ||
| underlays_down["[D]" + pipe_colors[pipe_color]] = I | ||
| if("pipe_exposed-scrubbers") | ||
| pipe_underlays_exposed["[D]" + pipe_colors[pipe_color]] = I | ||
| if("pipe_intact-scrubbers") | ||
| pipe_underlays_intact["[D]" + pipe_colors[pipe_color]] = I | ||
| */ |
| @@ -0,0 +1,125 @@ | ||
| /* | ||
| Quick overview: | ||
| Pipes combine to form pipelines | ||
| Pipelines and other atmospheric objects combine to form pipe_networks | ||
| Note: A single pipe_network represents a completely open space | ||
| Pipes -> Pipelines | ||
| Pipelines + Other Objects -> Pipe network | ||
| */ | ||
| /obj/machinery/atmospherics | ||
|
|
||
| auto_init = 0 | ||
|
|
||
| anchored = 1 | ||
| idle_power_usage = 0 | ||
| active_power_usage = 0 | ||
| power_channel = ENVIRON | ||
| var/nodealert = 0 | ||
| var/power_rating //the maximum amount of power the machine can use to do work, affects how powerful the machine is, in Watts | ||
|
|
||
| layer = 2.4 //under wires with their 2.44 | ||
|
|
||
| var/connect_types = CONNECT_TYPE_REGULAR | ||
| var/icon_connect_type = "" //"-supply" or "-scrubbers" | ||
|
|
||
| var/initialize_directions = 0 | ||
| var/pipe_color | ||
|
|
||
| var/global/datum/pipe_icon_manager/icon_manager | ||
|
|
||
| /obj/machinery/atmospherics/New() | ||
| if(!icon_manager) | ||
| icon_manager = new() | ||
|
|
||
| if(!pipe_color) | ||
| pipe_color = color | ||
| color = null | ||
|
|
||
| if(!pipe_color_check(pipe_color)) | ||
| pipe_color = null | ||
| ..() | ||
|
|
||
| /obj/machinery/atmospherics/attackby(atom/A, mob/user as mob) | ||
| if(istype(A, /obj/item/device/pipe_painter)) | ||
| return | ||
| ..() | ||
|
|
||
| /obj/machinery/atmospherics/proc/add_underlay(var/turf/T, var/obj/machinery/atmospherics/node, var/direction, var/icon_connect_type) | ||
| if(node) | ||
| if(!T.is_plating() && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe)) | ||
| //underlays += icon_manager.get_atmos_icon("underlay_down", direction, color_cache_name(node)) | ||
| underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "down" + icon_connect_type) | ||
| else | ||
| //underlays += icon_manager.get_atmos_icon("underlay_intact", direction, color_cache_name(node)) | ||
| underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "intact" + icon_connect_type) | ||
| else | ||
| //underlays += icon_manager.get_atmos_icon("underlay_exposed", direction, pipe_color) | ||
| underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "exposed" + icon_connect_type) | ||
|
|
||
| /obj/machinery/atmospherics/proc/update_underlays() | ||
| if(check_icon_cache()) | ||
| return 1 | ||
| else | ||
| return 0 | ||
|
|
||
| obj/machinery/atmospherics/proc/check_connect_types(obj/machinery/atmospherics/atmos1, obj/machinery/atmospherics/atmos2) | ||
| return (atmos1.connect_types & atmos2.connect_types) | ||
|
|
||
| /obj/machinery/atmospherics/proc/check_connect_types_construction(obj/machinery/atmospherics/atmos1, obj/item/pipe/pipe2) | ||
| return (atmos1.connect_types & pipe2.connect_types) | ||
|
|
||
| /obj/machinery/atmospherics/proc/check_icon_cache(var/safety = 0) | ||
| if(!istype(icon_manager)) | ||
| if(!safety) //to prevent infinite loops | ||
| icon_manager = new() | ||
| check_icon_cache(1) | ||
| return 0 | ||
|
|
||
| return 1 | ||
|
|
||
| /obj/machinery/atmospherics/proc/color_cache_name(var/obj/machinery/atmospherics/node) | ||
| //Don't use this for standard pipes | ||
| if(!istype(node)) | ||
| return null | ||
|
|
||
| return node.pipe_color | ||
|
|
||
| /obj/machinery/atmospherics/process() | ||
| last_flow_rate = 0 | ||
| last_power_draw = 0 | ||
|
|
||
| build_network() | ||
|
|
||
| /obj/machinery/atmospherics/proc/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) | ||
| // Check to see if should be added to network. Add self if so and adjust variables appropriately. | ||
| // Note don't forget to have neighbors look as well! | ||
|
|
||
| return null | ||
|
|
||
| /obj/machinery/atmospherics/proc/build_network() | ||
| // Called to build a network from this node | ||
|
|
||
| return null | ||
|
|
||
| /obj/machinery/atmospherics/proc/return_network(obj/machinery/atmospherics/reference) | ||
| // Returns pipe_network associated with connection to reference | ||
| // Notes: should create network if necessary | ||
| // Should never return null | ||
|
|
||
| return null | ||
|
|
||
| /obj/machinery/atmospherics/proc/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network) | ||
| // Used when two pipe_networks are combining | ||
|
|
||
| /obj/machinery/atmospherics/proc/return_network_air(datum/network/reference) | ||
| // Return a list of gas_mixture(s) in the object | ||
| // associated with reference pipe_network for use in rebuilding the networks gases list | ||
| // Is permitted to return null | ||
|
|
||
| /obj/machinery/atmospherics/proc/disconnect(obj/machinery/atmospherics/reference) | ||
|
|
||
| /obj/machinery/atmospherics/update_icon() | ||
| return null |
| @@ -0,0 +1,136 @@ | ||
| obj/machinery/atmospherics/binary | ||
| dir = SOUTH | ||
| initialize_directions = SOUTH|NORTH | ||
| use_power = 1 | ||
|
|
||
| var/datum/gas_mixture/air1 | ||
| var/datum/gas_mixture/air2 | ||
|
|
||
| var/obj/machinery/atmospherics/node1 | ||
| var/obj/machinery/atmospherics/node2 | ||
|
|
||
| var/datum/pipe_network/network1 | ||
| var/datum/pipe_network/network2 | ||
|
|
||
| New() | ||
| ..() | ||
| switch(dir) | ||
| if(NORTH) | ||
| initialize_directions = NORTH|SOUTH | ||
| if(SOUTH) | ||
| initialize_directions = NORTH|SOUTH | ||
| if(EAST) | ||
| initialize_directions = EAST|WEST | ||
| if(WEST) | ||
| initialize_directions = EAST|WEST | ||
| air1 = new | ||
| air2 = new | ||
|
|
||
| air1.volume = 200 | ||
| air2.volume = 200 | ||
|
|
||
| // Housekeeping and pipe network stuff below | ||
| network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) | ||
| if(reference == node1) | ||
| network1 = new_network | ||
|
|
||
| else if(reference == node2) | ||
| network2 = new_network | ||
|
|
||
| if(new_network.normal_members.Find(src)) | ||
| return 0 | ||
|
|
||
| new_network.normal_members += src | ||
|
|
||
| return null | ||
|
|
||
| Destroy() | ||
| loc = null | ||
|
|
||
| if(node1) | ||
| node1.disconnect(src) | ||
| qdel(network1) | ||
| if(node2) | ||
| node2.disconnect(src) | ||
| qdel(network2) | ||
|
|
||
| node1 = null | ||
| node2 = null | ||
|
|
||
| ..() | ||
|
|
||
| initialize() | ||
| if(node1 && node2) return | ||
|
|
||
| var/node2_connect = dir | ||
| var/node1_connect = turn(dir, 180) | ||
|
|
||
| for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect)) | ||
| if(target.initialize_directions & get_dir(target,src)) | ||
| if (check_connect_types(target,src)) | ||
| node1 = target | ||
| break | ||
|
|
||
| for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect)) | ||
| if(target.initialize_directions & get_dir(target,src)) | ||
| if (check_connect_types(target,src)) | ||
| node2 = target | ||
| break | ||
|
|
||
| update_icon() | ||
| update_underlays() | ||
|
|
||
| build_network() | ||
| if(!network1 && node1) | ||
| network1 = new /datum/pipe_network() | ||
| network1.normal_members += src | ||
| network1.build_network(node1, src) | ||
|
|
||
| if(!network2 && node2) | ||
| network2 = new /datum/pipe_network() | ||
| network2.normal_members += src | ||
| network2.build_network(node2, src) | ||
|
|
||
|
|
||
| return_network(obj/machinery/atmospherics/reference) | ||
| build_network() | ||
|
|
||
| if(reference==node1) | ||
| return network1 | ||
|
|
||
| if(reference==node2) | ||
| return network2 | ||
|
|
||
| return null | ||
|
|
||
| reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network) | ||
| if(network1 == old_network) | ||
| network1 = new_network | ||
| if(network2 == old_network) | ||
| network2 = new_network | ||
|
|
||
| return 1 | ||
|
|
||
| return_network_air(datum/pipe_network/reference) | ||
| var/list/results = list() | ||
|
|
||
| if(network1 == reference) | ||
| results += air1 | ||
| if(network2 == reference) | ||
| results += air2 | ||
|
|
||
| return results | ||
|
|
||
| disconnect(obj/machinery/atmospherics/reference) | ||
| if(reference==node1) | ||
| qdel(network1) | ||
| node1 = null | ||
|
|
||
| else if(reference==node2) | ||
| qdel(network2) | ||
| node2 = null | ||
|
|
||
| update_icon() | ||
| update_underlays() | ||
|
|
||
| return null |
| @@ -0,0 +1,147 @@ | ||
| //node1, air1, network1 correspond to input | ||
| //node2, air2, network2 correspond to output | ||
|
|
||
| #define ADIABATIC_EXPONENT 0.667 //Actually adiabatic exponent - 1. | ||
|
|
||
| /obj/machinery/atmospherics/binary/circulator | ||
| name = "circulator" | ||
| desc = "A gas circulator turbine and heat exchanger." | ||
| icon = 'icons/obj/pipes.dmi' | ||
| icon_state = "circ-off" | ||
| anchored = 0 | ||
|
|
||
| var/kinetic_efficiency = 0.04 //combined kinetic and kinetic-to-electric efficiency | ||
| var/volume_ratio = 0.2 | ||
|
|
||
| var/recent_moles_transferred = 0 | ||
| var/last_heat_capacity = 0 | ||
| var/last_temperature = 0 | ||
| var/last_pressure_delta = 0 | ||
| var/last_worldtime_transfer = 0 | ||
| var/last_stored_energy_transferred = 0 | ||
| var/volume_capacity_used = 0 | ||
| var/stored_energy = 0 | ||
|
|
||
| density = 1 | ||
|
|
||
| /obj/machinery/atmospherics/binary/circulator/New() | ||
| ..() | ||
| desc = initial(desc) + " Its outlet port is to the [dir2text(dir)]." | ||
| air1.volume = 400 | ||
|
|
||
| /obj/machinery/atmospherics/binary/circulator/proc/return_transfer_air() | ||
| var/datum/gas_mixture/removed | ||
| if(anchored && !(stat&BROKEN) && network1) | ||
| var/input_starting_pressure = air1.return_pressure() | ||
| var/output_starting_pressure = air2.return_pressure() | ||
| last_pressure_delta = max(input_starting_pressure - output_starting_pressure - 5, 0) | ||
|
|
||
| //only circulate air if there is a pressure difference (plus 5kPa kinetic, 10kPa static friction) | ||
| if(air1.temperature > 0 && last_pressure_delta > 5) | ||
|
|
||
| //Calculate necessary moles to transfer using PV = nRT | ||
| recent_moles_transferred = (last_pressure_delta*network1.volume/(air1.temperature * R_IDEAL_GAS_EQUATION))/3 //uses the volume of the whole network, not just itself | ||
| volume_capacity_used = min( (last_pressure_delta*network1.volume/3)/(input_starting_pressure*air1.volume) , 1) //how much of the gas in the input air volume is consumed | ||
|
|
||
| //Calculate energy generated from kinetic turbine | ||
| stored_energy += 1/ADIABATIC_EXPONENT * min(last_pressure_delta * network1.volume , input_starting_pressure*air1.volume) * (1 - volume_ratio**ADIABATIC_EXPONENT) * kinetic_efficiency | ||
|
|
||
| //Actually transfer the gas | ||
| removed = air1.remove(recent_moles_transferred) | ||
| if(removed) | ||
| last_heat_capacity = removed.heat_capacity() | ||
| last_temperature = removed.temperature | ||
|
|
||
| //Update the gas networks. | ||
| network1.update = 1 | ||
|
|
||
| last_worldtime_transfer = world.time | ||
| else | ||
| recent_moles_transferred = 0 | ||
|
|
||
| update_icon() | ||
| return removed | ||
|
|
||
| /obj/machinery/atmospherics/binary/circulator/proc/return_stored_energy() | ||
| last_stored_energy_transferred = stored_energy | ||
| stored_energy = 0 | ||
| return last_stored_energy_transferred | ||
|
|
||
| /obj/machinery/atmospherics/binary/circulator/process() | ||
| ..() | ||
|
|
||
| if(last_worldtime_transfer < world.time - 50) | ||
| recent_moles_transferred = 0 | ||
| update_icon() | ||
|
|
||
| /obj/machinery/atmospherics/binary/circulator/update_icon() | ||
| if(stat & (BROKEN|NOPOWER) || !anchored) | ||
| icon_state = "circ-p" | ||
| else if(last_pressure_delta > 0 && recent_moles_transferred > 0) | ||
| if(last_pressure_delta > 5*ONE_ATMOSPHERE) | ||
| icon_state = "circ-run" | ||
| else | ||
| icon_state = "circ-slow" | ||
| else | ||
| icon_state = "circ-off" | ||
|
|
||
| return 1 | ||
|
|
||
| /obj/machinery/atmospherics/binary/circulator/attackby(obj/item/weapon/W as obj, mob/user as mob) | ||
| if(istype(W, /obj/item/weapon/wrench)) | ||
| playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1) | ||
| anchored = !anchored | ||
| user.visible_message("[user.name] [anchored ? "secures" : "unsecures"] the bolts holding [src.name] to the floor.", \ | ||
| "You [anchored ? "secure" : "unsecure"] the bolts holding [src] to the floor.", \ | ||
| "You hear a ratchet") | ||
|
|
||
| if(anchored) | ||
| if(dir & (NORTH|SOUTH)) | ||
| initialize_directions = NORTH|SOUTH | ||
| else if(dir & (EAST|WEST)) | ||
| initialize_directions = EAST|WEST | ||
|
|
||
| initialize() | ||
| build_network() | ||
| if (node1) | ||
| node1.initialize() | ||
| node1.build_network() | ||
| if (node2) | ||
| node2.initialize() | ||
| node2.build_network() | ||
| else | ||
| if(node1) | ||
| node1.disconnect(src) | ||
| qdel(network1) | ||
| if(node2) | ||
| node2.disconnect(src) | ||
| qdel(network2) | ||
|
|
||
| node1 = null | ||
| node2 = null | ||
|
|
||
| else | ||
| ..() | ||
|
|
||
| /obj/machinery/atmospherics/binary/circulator/verb/rotate_clockwise() | ||
| set category = "Object" | ||
| set name = "Rotate Circulator (Clockwise)" | ||
| set src in view(1) | ||
|
|
||
| if (usr.stat || usr.restrained() || anchored) | ||
| return | ||
|
|
||
| src.set_dir(turn(src.dir, 90)) | ||
| desc = initial(desc) + " Its outlet port is to the [dir2text(dir)]." | ||
|
|
||
|
|
||
| /obj/machinery/atmospherics/binary/circulator/verb/rotate_anticlockwise() | ||
| set category = "Object" | ||
| set name = "Rotate Circulator (Counterclockwise)" | ||
| set src in view(1) | ||
|
|
||
| if (usr.stat || usr.restrained() || anchored) | ||
| return | ||
|
|
||
| src.set_dir(turn(src.dir, -90)) | ||
| desc = initial(desc) + " Its outlet port is to the [dir2text(dir)]." |