")
+
+/datum/html_interface/cards/sendResources(client/client)
+ . = ..() // we need the default resources
+
+ client << browse_rsc('cards.css')
+ client << browse_rsc('cards.png')
\ No newline at end of file
diff --git a/code/modules/html_interface/cards/cards.png b/code/modules/html_interface/cards/cards.png
new file mode 100644
index 00000000000..8001168246d
Binary files /dev/null and b/code/modules/html_interface/cards/cards.png differ
diff --git a/code/modules/html_interface/html_interface.css b/code/modules/html_interface/html_interface.css
new file mode 100644
index 00000000000..85c07f3b857
--- /dev/null
+++ b/code/modules/html_interface/html_interface.css
@@ -0,0 +1,11 @@
+html
+{
+ -ms-overflow-style: scrollbar;
+}
+
+body
+{
+ font-family: Arial;
+ overflow-y: scroll;
+ overflow-x: auto;
+}
\ No newline at end of file
diff --git a/code/modules/html_interface/html_interface.dm b/code/modules/html_interface/html_interface.dm
new file mode 100644
index 00000000000..0c9984f0b06
--- /dev/null
+++ b/code/modules/html_interface/html_interface.dm
@@ -0,0 +1,321 @@
+/*
+Author: NullQuery
+Created on: 2014-09-24
+
+ ** CAUTION - A WORD OF WARNING **
+
+If there is no getter or setter available and you aren't extending my code with a sub-type, DO NOT ACCESS VARIABLES DIRECTLY!
+
+Add a getter/setter instead, even if it does nothing but return or set the variable. Thank you for your patience with me. -NQ
+
+ ** Public API **
+
+ var/datum/html_interface/hi = new/datum/html_interface(ref, title, width = 700, height = 480, head = "")
+
+Creates a new HTML interface object with [ref] as the object and [title] as the initial title of the page. [width] and [height] is the initial width and height
+of the window. The text in [head] is added just before the end tag.
+
+ hi.setTitle(title)
+
+Changes the title of the page.
+
+ hi.getTitle()
+
+Returns the current title of the page.
+
+ hi.updateLayout(layout)
+
+Updates the overall layout of the page (the HTML code between the body tags).
+
+This should be used sparingly.
+
+ hi.updateContent(id, content, ignore_cache = FALSE)
+
+Updates a portion of the page, i.e., the DOM element with the appropriate ID. The contents of the element are replaced with the provided HTML.
+
+The content is cached on the server-side to minimize network traffic when the client "should have" the same HTML. The client may not have
+the same HTML if scripts cause the content to change. In this case set the ignore_cache parameter.
+
+ hi.executeJavaScript(jscript, client = null)
+
+Executes Javascript on the browser.
+
+The client is optional and may be a /mob, /client or /html_interface_client object. If not specified the code is executed on all clients.
+
+ hi.show(client)
+
+Shows the HTML interface to the provided client. This will create a window, apply the current layout and contents. It will then wait for events.
+
+ hi.hide(client)
+
+Hides the HTML interface from the provided client. This will close the browser window.
+
+ hi.isUsed()
+
+Returns TRUE if the interface is being used (has an active client) or FALSE if not.
+
+ ** Additional notes **
+
+When working with byond:// links make sure to reference the HTML interface object and NOT the original object. Topic() will still be called on
+your object, but it will pass through the HTML interface first allowing interception at a higher level.
+
+
+ ** Sample code **
+
+mob/var/datum/html_interface/hi
+
+mob/verb/test()
+ if (!hi) hi = new/datum/html_interface(src, "[src.key]")
+
+ hi.updateLayout("")
+ hi.updateContent("content", "
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
")
+
+ hi.show(src)
+
+*/
+
+/datum/html_interface
+ // The atom we should report to.
+ var/atom/ref
+
+ // The current title of the browser window.
+ var/title
+
+ // A list of content elements that have been changed. This is necessary when showing the browser control to new clients.
+ var/list/content_elements = new/list()
+
+ // The HTML layout, typically what's in-between the tag. May be overridden by extensions.
+ var/layout
+
+ // An associative list of clients currently viewing this screen. The key is the /client object, the value is the /datum/html_interface_client object.
+ var/list/clients
+
+ // This goes just before the closing HEAD tag. I haven't exposed any getters/setters for it because it's only being used by extensions.
+ var/head = ""
+
+ // The initial width of the browser control, used when the window is first shown to a client.
+ var/width
+
+ // The initial height of the browser control, used when the window is first shown to a client.
+ var/height
+
+/datum/html_interface/New(atom/ref, title, width = 700, height = 480, head = "")
+ . = ..()
+
+ src.ref = ref
+ src.title = title
+ src.width = width
+ src.height = height
+ src.head = head
+
+/datum/html_interface/Destroy()
+ if (src.clients)
+ for (var/client in src.clients)
+ src.hide(src.clients[client])
+
+ return ..()
+
+/* * Hooks */
+/datum/html_interface/proc/specificRenderTitle(datum/html_interface_client/hclient, ignore_cache = FALSE)
+
+/datum/html_interface/proc/sendResources(client/client)
+ client << browse_rsc('jquery.min.js')
+ client << browse_rsc('bootstrap.min.js')
+ client << browse_rsc('bootstrap.min.css')
+ client << browse_rsc('html_interface.css')
+ client << browse_rsc('html_interface.js')
+
+/datum/html_interface/proc/createWindow(datum/html_interface_client/hclient)
+ winclone(hclient.client, "window", "browser_\ref[src]")
+
+ var/list/params = list(
+ "size" = "[width]x[height]",
+ "statusbar" = "false",
+ "on-close" = "byond://?src=\ref[src]&html_interface_action=onclose"
+ )
+
+ if (hclient.client.hi_last_pos) params["pos"] = "[hclient.client.hi_last_pos]"
+
+ winset(hclient.client, "browser_\ref[src]", list2params(params))
+
+ winset(hclient.client, "browser_\ref[src].browser", list2params(list("parent" = "browser_\ref[src]", "type" = "browser", "pos" = "0,0", "size" = "[width]x[height]", "anchor1" = "0,0", "anchor2" = "100,100", "use-title" = "true", "auto-format" = "false")))
+
+/* * Public API */
+/datum/html_interface/proc/getTitle() return src.title
+
+/datum/html_interface/proc/setTitle(title, ignore_cache = FALSE)
+ src.title = title
+
+ var/datum/html_interface_client/hclient
+
+ for (var/client in src.clients)
+ hclient = src._getClient(src.clients[client])
+
+ if (hclient && hclient.active) src._renderTitle(src.clients[client], ignore_cache)
+
+/datum/html_interface/proc/executeJavaScript(jscript, datum/html_interface_client/hclient = null)
+ if (hclient)
+ hclient = getClient(hclient)
+
+ if (istype(hclient))
+ if (hclient.is_loaded) hclient.client << output(list2params(list(jscript)), "browser_\ref[src].browser:eval")
+ else
+ for (var/client in src.clients) src.executeJavaScript(jscript, src.clients[client])
+
+/datum/html_interface/proc/updateLayout(layout)
+ src.layout = layout
+
+ var/datum/html_interface_client/hclient
+
+ for (var/client in src.clients)
+ hclient = src._getClient(src.clients[client])
+
+ if (hclient && hclient.active) src._renderLayout(hclient)
+
+/datum/html_interface/proc/updateContent(id, content, ignore_cache = FALSE)
+ src.content_elements[id] = content
+
+ var/datum/html_interface_client/hclient
+
+ for (var/client in src.clients)
+ hclient = src._getClient(src.clients[client])
+
+ if (hclient && hclient.active) src._renderContent(id, hclient, ignore_cache)
+
+/datum/html_interface/proc/show(datum/html_interface_client/hclient)
+ hclient = getClient(hclient, TRUE)
+
+ if (istype(hclient))
+ // This needs to be commented out due to BYOND bug http://www.byond.com/forum/?post=1487244
+ // /client/proc/send_resources() executes this per client to avoid the bug, but by using it here files may be deleted just as the HTML is loaded,
+ // causing file not found errors.
+// src.sendResources(hclient.client)
+
+ if (winexists(hclient.client, "browser_\ref[src]"))
+ src._renderTitle(hclient, TRUE)
+ src._renderLayout(hclient)
+ else
+ src.createWindow(hclient)
+ hclient.is_loaded = FALSE
+ hclient.client << output(replacetextEx(replacetextEx(file2text('html_interface.html'), "\[hsrc\]", "\ref[src]"), "", "[head]"), "browser_\ref[src].browser")
+ winshow(hclient.client, "browser_\ref[src]", TRUE)
+
+/datum/html_interface/proc/hide(datum/html_interface_client/hclient)
+ hclient = getClient(hclient)
+
+ if (istype(hclient))
+ if (src.clients)
+ src.clients.Remove(hclient.client)
+
+ if (!src.clients.len) src.clients = null
+
+ hclient.client.hi_last_pos = winget(hclient.client, "browser_\ref[src]" ,"pos")
+
+ winshow(hclient.client, "browser_\ref[src]", FALSE)
+ winset(hclient.client, "browser_\ref[src]", "parent=none")
+
+ if (hascall(src.ref, "hiOnHide")) call(src.ref, "hiOnHide")(hclient)
+
+// Convert a /mob to /client, and /client to /datum/html_interface_client
+/datum/html_interface/proc/getClient(client, create_if_not_exist = FALSE)
+ if (istype(client, /datum/html_interface_client)) return src._getClient(client)
+ else if (ismob(client))
+ var/mob/mob = client
+ client = mob.client
+
+ if (istype(client, /client))
+ if (create_if_not_exist && (!src.clients || !(client in src.clients)))
+ if (!src.clients) src.clients = new/list()
+ if (!(client in src.clients)) src.clients[client] = new/datum/html_interface_client(client)
+
+ if (src.clients && (client in src.clients)) return src._getClient(src.clients[client])
+ else return null
+ else return null
+
+/datum/html_interface/proc/enableFor(datum/html_interface_client/hclient)
+ hclient.active = TRUE
+
+ src.show(hclient)
+
+/datum/html_interface/proc/disableFor(datum/html_interface_client/hclient)
+ hclient.active = FALSE
+
+/datum/html_interface/proc/isUsed()
+ if (src.clients && src.clients.len > 0)
+ var/datum/html_interface_client/hclient
+ for (var/key in clients)
+ hclient = clients[key]
+ if (hclient.active) return TRUE
+
+ return FALSE
+
+/* * Danger Zone */
+
+/datum/html_interface/proc/_getClient(datum/html_interface_client/hclient)
+ if (hclient)
+ if (hclient.client)
+ if (hascall(src.ref, "hiIsValidClient"))
+ var/res = call(src.ref, "hiIsValidClient")(hclient)
+
+ if (res)
+ if (!hclient.active) src.enableFor(hclient)
+ else
+ if (hclient.active) src.disableFor(hclient)
+
+ return hclient
+ else
+ return null
+ else
+ return null
+
+/datum/html_interface/proc/_renderTitle(datum/html_interface_client/hclient, ignore_cache = FALSE)
+ if (hclient && hclient.is_loaded)
+ // Only render if we have new content.
+
+ if (ignore_cache || src.title != hclient.title)
+ hclient.title = title
+
+ src.specificRenderTitle(hclient)
+
+ hclient.client << output(list2params(list(title)), "browser_\ref[src].browser:setTitle")
+
+/datum/html_interface/proc/_renderLayout(datum/html_interface_client/hclient)
+ if (hclient && hclient.is_loaded)
+ var/html = src.layout
+
+ // Only render if we have new content.
+ if (html != hclient.layout)
+ hclient.layout = html
+
+ hclient.client << output(list2params(list(html)), "browser_\ref[src].browser:updateLayout")
+
+ for (var/id in src.content_elements) src._renderContent(id, hclient)
+
+/datum/html_interface/proc/_renderContent(id, datum/html_interface_client/hclient, ignore_cache = FALSE)
+ if (hclient && hclient.is_loaded)
+ var/html = src.content_elements[id]
+
+ // Only render if we have new content.
+ if (ignore_cache || !(id in hclient.content_elements) || html != hclient.content_elements[id])
+ hclient.content_elements[id] = html
+
+ hclient.client << output(list2params(list(id, html)), "browser_\ref[src].browser:updateContent")
+
+/datum/html_interface/Topic(href, href_list[])
+ var/datum/html_interface_client/hclient = getClient(usr.client)
+
+ if (istype(hclient))
+ if ("html_interface_action" in href_list)
+ switch (href_list["html_interface_action"])
+
+ if ("onload")
+ hclient.layout = null
+ hclient.content_elements.len = 0
+ hclient.is_loaded = TRUE
+
+ src._renderTitle(hclient, TRUE)
+ src._renderLayout(hclient)
+
+ if ("onclose")
+ src.hide(hclient)
+ else if (src.ref && hclient.active) src.ref.Topic(href, href_list, hclient)
\ No newline at end of file
diff --git a/code/modules/html_interface/html_interface.html b/code/modules/html_interface/html_interface.html
new file mode 100644
index 00000000000..1231c21df53
--- /dev/null
+++ b/code/modules/html_interface/html_interface.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/code/modules/html_interface/html_interface.js b/code/modules/html_interface/html_interface.js
new file mode 100644
index 00000000000..83300ee27c4
--- /dev/null
+++ b/code/modules/html_interface/html_interface.js
@@ -0,0 +1,45 @@
+var is_loading = false;
+var load_count = 0;
+
+function onload()
+{
+ if (!is_loading)
+ {
+ var count = ++load_count;
+ is_loading = true;
+ $("body").html("");
+
+ window.location.href = "byond://?src=" + hSrc + "&html_interface_action=onload";
+
+ // The request may fail which would prevent the player from refreshing the screen again. Try to detect this retry.
+ setTimeout(function()
+ {
+ if (count == load_count && is_loading && $("body").html() == "")
+ {
+ is_loading = false;
+ onload();
+ }
+ }, 500);
+ }
+}
+
+$(document).ready(function()
+{
+ $(document).on("keydown", function(e)
+ {
+ if (!e.ctrlKey && e.which == 116)
+ {
+ e.preventDefault();
+
+ onload();
+ }
+ });
+
+ onload();
+});
+
+function fixText(text) { return text.replace(/ÿ/g, ""); }
+
+function setTitle(new_title) { $("title").html(fixText(new_title)); $(window).trigger("onUpdateTitle"); }
+function updateLayout(new_html) { $("body").html(fixText(new_html)); $(window).trigger("onUpdateLayout"); setTimeout(function(){ is_loading = false; }, 200); }
+function updateContent(id, new_html) { $("#" + id).html(fixText(new_html)); $(window).trigger("onUpdateContent"); }
\ No newline at end of file
diff --git a/code/modules/html_interface/html_interface_client.dm b/code/modules/html_interface/html_interface_client.dm
new file mode 100644
index 00000000000..e571a86b3a2
--- /dev/null
+++ b/code/modules/html_interface/html_interface_client.dm
@@ -0,0 +1,43 @@
+/datum/html_interface_client
+ // The /client object represented by this model.
+ var/client/client
+
+ // The layout currently visible to the client.
+ var/layout
+
+ // The content elements (mirrored from /datum/html_interface) currently visible to the client.
+ var/list/content_elements = new/list()
+
+ // The current title for this client
+ var/title
+
+ // TRUE if the browser control has loaded and will accept input, FALSE if not.
+ var/is_loaded = FALSE
+
+ // TRUE if this client should receive updates, FALSE if not.
+ var/active = TRUE
+
+ // A list of extra variables, for use by extensions.
+ var/list/extra_vars
+
+/datum/html_interface_client/New(client/client)
+ . = ..()
+
+ src.client = client
+
+/datum/html_interface_client/proc/putExtraVar(key, value)
+ if (!src.extra_vars) src.extra_vars = new/list()
+ src.extra_vars[key] = value
+
+/datum/html_interface_client/proc/removeExtraVar(key)
+ if (src.extra_vars)
+ . = src.extra_vars[key]
+
+ src.extra_vars.Remove(key)
+
+ if (!src.extra_vars.len) src.extra_vars = null
+
+ return .
+
+/datum/html_interface_client/proc/getExtraVar(key)
+ if (src.extra_vars) return src.extra_vars[key]
\ No newline at end of file
diff --git a/code/modules/html_interface/jquery.min.js b/code/modules/html_interface/jquery.min.js
new file mode 100644
index 00000000000..ab28a24729b
--- /dev/null
+++ b/code/modules/html_interface/jquery.min.js
@@ -0,0 +1,4 @@
+/*! jQuery v1.11.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
+!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.1",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h;
+if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="
")
+
+/datum/html_interface/specificRenderTitle(datum/html_interface_client/hclient, ignore_cache = FALSE)
+ // Update the title in our custom header (in addition to default functionality)
+ winset(hclient.client, "browser_\ref[src].uiTitle", list2params(list("text" = "[src.title]")))
+
+/datum/html_interface/nanotrasen/sendResources(client/client)
+ . = ..() // we need the default resources
+
+ client << browse_rsc('uiBg.png')
+ client << browse_rsc('uiBgcenter.png')
+ client << browse_rsc('nanotrasen.css')
+
+/datum/html_interface/nanotrasen/createWindow(datum/html_interface_client/hclient)
+ . = ..() // we want the default window
+
+ // Remove the titlebar
+ winset(hclient.client, "browser_\ref[src]", list2params(list(
+ "titlebar" = "false"
+ )))
+
+ // Reposition the browser
+ winset(hclient.client, "browser_\ref[src].browser", list2params(list(
+ "pos" = "0,35",
+ "size" = "[width]x[height - 35]"
+ )))
+
+ // Add top background image
+ winset(hclient.client, "browser_\ref[src].topbg", list2params(list(
+ "parent" = "browser_\ref[src]",
+ "type" = "label",
+ "pos" = "0,0",
+ "size" = "[width]x35",
+ "anchor1" = "0,0",
+ "anchor2" = "100,0",
+ "image" = "['uiBgtop.png']",
+ "image-mode" = "tile",
+ "is-disabled" = "true"
+ )))
+
+ // Add Nanotrasen logo
+ winset(hclient.client, "browser_\ref[src].uiTitleFluff", list2params(list(
+ "parent" = "browser_\ref[src]",
+ "type" = "label",
+ "pos" = "[width - 42 - 4 - 24 - 4 - 24 - 4],5",
+ "size" = "42x24",
+ "anchor1" = "100,0",
+ "anchor2" = "100,0",
+ "image" = "['uiTitleFluff.png']",
+ "image-mode" = "tile",
+ "is-disabled" = "true"
+ )))
+
+ // Add Eye picture
+ winset(hclient.client, "browser_\ref[src].uiTitleEye", list2params(list(
+ "parent" = "browser_\ref[src]",
+ "type" = "label",
+ "pos" = "8,5",
+ "size" = "42x24",
+ "anchor1" = "0,0",
+ "anchor2" = "0,0",
+ "image" = "['uiEyeGreen.png']",
+ "image-mode" = "tile",
+ "is-disabled" = "true"
+ )))
+
+ // Add title text
+ winset(hclient.client, "browser_\ref[src].uiTitle", list2params(list(
+ "parent" = "browser_\ref[src]",
+ "type" = "label",
+ "is-transparent" = "true",
+ "pos" = "64,0",
+ "size" = "580x35",
+ "anchor1" = "0,0",
+ "anchor2" = "100,0",
+ "is-disabled" = "true",
+ "text" = "[src.title]",
+ "align" = "left",
+ "font-family" = "verdana,Geneva,sans-serif",
+ "font-size" = "12", // ~ 16px
+ "text-color" = "#E9C183"
+ )))
+
+ // Add minimize button
+ // TODO: Style the button (add image)
+ winset(hclient.client, "browser_\ref[src].uiTitleMinimize", list2params(list(
+ "parent" = "browser_\ref[src]",
+ "type" = "button",
+ "is-flat" = "true",
+ "background-color"="#383838", // should be unnecessary if image is used
+ "text-color" = "#FFFFFF", // should be unnecessary if image is used
+ "is-transparent" = "true",
+ "pos" = "[width - 24 - 4 - 24 - 4],5",
+ "size" = "24x24",
+ "anchor1" = "100,0",
+ "anchor2" = "100,0",
+ "text" = "-",
+ "font-family" = "verdana,Geneva,sans-serif", // should be unnecessary if image is used
+ "font-size" = "12", // ~ 16px - should be unnecessary if image is used
+
+ // Disable resizing (disables maximizing), minimize window, bind window.on-size to catch 'restore window' button to enable resizing if restored.
+ "command" = ".winset \"browser_\ref[src].can-resize=false;browser_\ref[src].is-minimized=true;browser_\ref[src].on-size=\".swinset \\\"browser_\ref[src].can-resize=true;browser_\ref[src].on-size=\\\"\"\""
+ )))
+
+ // Add close button
+ // TODO: Style the button (add image)
+ winset(hclient.client, "browser_\ref[src].uiTitleClose", list2params(list(
+ "parent" = "browser_\ref[src]",
+ "type" = "button",
+ "is-flat" = "true",
+ "background-color"="#383838", // should be unnecessary if image is used
+ "text-color" = "#FFFFFF", // should be unnecessary if image is used
+ "command" = "byond://?src=\ref[src];html_interface_action=onclose",
+ "is-transparent" = "true",
+ "pos" = "[width - 24 - 4],5",
+ "size" = "24x24",
+ "anchor1" = "100,0",
+ "anchor2" = "100,0",
+ "text" = "X",
+ "font-family" = "verdana,Geneva,sans-serif", // should be unnecessary if image is used
+ "font-size" = "12" // ~ 16px - should be unnecessary if image is used
+ )))
+
+/datum/html_interface/nanotrasen/enableFor(datum/html_interface_client/hclient)
+ . = ..()
+
+ src.setEyeColor("green", hclient)
+
+/datum/html_interface/nanotrasen/disableFor(datum/html_interface_client/hclient)
+ hclient.active = FALSE
+
+ src.setEyeColor("red", hclient)
+
+/datum/html_interface/nanotrasen/proc/setEyeColor(color, datum/html_interface_client/hclient)
+ hclient = getClient(hclient)
+
+ if (istype(hclient))
+ var/resource
+ switch (color)
+ if ("green") resource = 'uiEyeGreen.png'
+ if ("orange") resource = 'uiEyeOrange.png'
+ if ("red") resource = 'uiEyeRed.png'
+ else CRASH("Invalid color: [color]")
+
+ if (hclient.getExtraVar("eye_color") != color)
+ hclient.putExtraVar("eye_color", color)
+
+ winset(hclient.client, "browser_\ref[src].uiTitleEye", list2params(list("image" = "[resource]")))
+ else
+ WARNING("Invalid object passed to /datum/html_interface/nanotrasen/proc/setEyeColor")
\ No newline at end of file
diff --git a/code/modules/html_interface/nanotrasen/uiBg.png b/code/modules/html_interface/nanotrasen/uiBg.png
new file mode 100644
index 00000000000..bba99d3106a
Binary files /dev/null and b/code/modules/html_interface/nanotrasen/uiBg.png differ
diff --git a/code/modules/html_interface/nanotrasen/uiBgcenter.png b/code/modules/html_interface/nanotrasen/uiBgcenter.png
new file mode 100644
index 00000000000..b258f180192
Binary files /dev/null and b/code/modules/html_interface/nanotrasen/uiBgcenter.png differ
diff --git a/code/modules/html_interface/nanotrasen/uiBgtop.png b/code/modules/html_interface/nanotrasen/uiBgtop.png
new file mode 100644
index 00000000000..a3579d6df94
Binary files /dev/null and b/code/modules/html_interface/nanotrasen/uiBgtop.png differ
diff --git a/code/modules/html_interface/nanotrasen/uiEyeGreen.png b/code/modules/html_interface/nanotrasen/uiEyeGreen.png
new file mode 100644
index 00000000000..0205f4ae00c
Binary files /dev/null and b/code/modules/html_interface/nanotrasen/uiEyeGreen.png differ
diff --git a/code/modules/html_interface/nanotrasen/uiEyeOrange.png b/code/modules/html_interface/nanotrasen/uiEyeOrange.png
new file mode 100644
index 00000000000..cce6cfe5374
Binary files /dev/null and b/code/modules/html_interface/nanotrasen/uiEyeOrange.png differ
diff --git a/code/modules/html_interface/nanotrasen/uiEyeRed.png b/code/modules/html_interface/nanotrasen/uiEyeRed.png
new file mode 100644
index 00000000000..662f0d522fa
Binary files /dev/null and b/code/modules/html_interface/nanotrasen/uiEyeRed.png differ
diff --git a/code/modules/html_interface/nanotrasen/uiTitleFluff.png b/code/modules/html_interface/nanotrasen/uiTitleFluff.png
new file mode 100644
index 00000000000..5d499f7afad
Binary files /dev/null and b/code/modules/html_interface/nanotrasen/uiTitleFluff.png differ
diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm
index 38c9be4e471..8fe33dc7e58 100644
--- a/code/modules/hydroponics/grown.dm
+++ b/code/modules/hydroponics/grown.dm
@@ -20,6 +20,7 @@
icon = 'icons/obj/hydroponics/harvest.dmi'
potency = -1
dried_type = -1 //bit different. saves us from having to define each stupid grown's dried_type as itself. If you don't want a plant to be driable (watermelons) set this to null in the time definition.
+ burn_state = 0 //Burnable
/obj/item/weapon/reagent_containers/food/snacks/grown/New(newloc, new_potency = 50)
..()
diff --git a/code/modules/hydroponics/growninedible.dm b/code/modules/hydroponics/growninedible.dm
index 07ee7c17a2e..f0ca0943691 100644
--- a/code/modules/hydroponics/growninedible.dm
+++ b/code/modules/hydroponics/growninedible.dm
@@ -5,6 +5,7 @@
/obj/item/weapon/grown // Grown weapons
name = "grown_weapon"
icon = 'icons/obj/hydroponics/harvest.dmi'
+ burn_state = 0 //Burnable
var/seed = null
var/plantname = ""
var/product //a type path
diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm
index 3b3b9ab28d2..bb6cf6c74af 100644
--- a/code/modules/hydroponics/hydroponics.dm
+++ b/code/modules/hydroponics/hydroponics.dm
@@ -730,7 +730,7 @@
user.visible_message("[user] begins to wrench [src] into place.", \
"You begin to wrench [src] in place...")
playsound(loc, 'sound/items/Ratchet.ogg', 50, 1)
- if (do_after(user, 20))
+ if (do_after(user, 20, target = src))
if(anchored)
return
anchored = 1
@@ -740,7 +740,7 @@
user.visible_message("[user] begins to unwrench [src].", \
"You begin to unwrench [src]...")
playsound(loc, 'sound/items/Ratchet.ogg', 50, 1)
- if (do_after(user, 20))
+ if (do_after(user, 20, target = src))
if(!anchored)
return
anchored = 0
diff --git a/code/modules/hydroponics/seeds.dm b/code/modules/hydroponics/seeds.dm
index 0e491e575bf..662f76cb686 100644
--- a/code/modules/hydroponics/seeds.dm
+++ b/code/modules/hydroponics/seeds.dm
@@ -7,6 +7,7 @@
icon = 'icons/obj/hydroponics/seeds.dmi'
icon_state = "seed" //Unknown plant seed - these shouldn't exist in-game.
w_class = 1 //Pocketable.
+ burn_state = 0 //Burnable
var/plantname = "Plants" //Name of plant when planted.
var/product //A type path. The thing that is created when the plant is harvested.
var/species = "" //Used to update icons. Should match the name in the sprites.
diff --git a/code/modules/library/lib_items.dm b/code/modules/library/lib_items.dm
index 298ebdcf61c..96dc3f1b9a1 100644
--- a/code/modules/library/lib_items.dm
+++ b/code/modules/library/lib_items.dm
@@ -17,6 +17,8 @@
anchored = 0
density = 1
opacity = 0
+ burn_state = 0 //Burnable
+ burntime = 30
var/state = 0
var/list/allowed_books = list(/obj/item/weapon/book, /obj/item/weapon/spellbook, /obj/item/weapon/storage/book) //Things allowed in the bookcase
@@ -36,13 +38,13 @@
if(0)
if(istype(I, /obj/item/weapon/wrench))
playsound(loc, 'sound/items/Ratchet.ogg', 100, 1)
- if(do_after(user, 20))
+ if(do_after(user, 20, target = src))
user << "You wrench the frame into place."
anchored = 1
state = 1
if(istype(I, /obj/item/weapon/crowbar))
playsound(loc, 'sound/items/Crowbar.ogg', 100, 1)
- if(do_after(user, 20))
+ if(do_after(user, 20, target = src))
user << "You pry the frame apart."
new /obj/item/stack/sheet/mineral/wood(loc, 4)
qdel(src)
@@ -165,6 +167,7 @@
throw_range = 5
w_class = 3 //upped to three because books are, y'know, pretty big. (and you could hide them inside eachother recursively forever)
attack_verb = list("bashed", "whacked", "educated")
+ burn_state = 0 //Burnable
var/dat //Actual page content
var/due_date = 0 //Game time in 1/10th seconds
var/author //Who wrote the thing, can be changed by pen or PC. It is not automatically assigned
@@ -253,7 +256,7 @@
else if(istype(I, /obj/item/weapon/kitchen/knife) || istype(I, /obj/item/weapon/wirecutters))
user << "You begin to carve out [title]..."
- if(do_after(user, 30))
+ if(do_after(user, 30, target = src))
user << "You carve out the pages from [title]! You didn't want to read it anyway."
var/obj/item/weapon/storage/book/B = new
B.name = src.name
diff --git a/code/modules/mining/abandoned_crates.dm b/code/modules/mining/abandoned_crates.dm
new file mode 100644
index 00000000000..1e38491439f
--- /dev/null
+++ b/code/modules/mining/abandoned_crates.dm
@@ -0,0 +1,212 @@
+//Originally coded by ISaidNo, later modified by Kelenius. Ported from Baystation12.
+
+/obj/structure/closet/crate/secure/loot
+ name = "abandoned crate"
+ desc = "What could be inside?"
+ icon_crate = "securecrate"
+ icon_state = "securecrate"
+ var/code = null
+ var/lastattempt = null
+ var/attempts = 10
+ var/codelen = 4
+ locked = 1
+
+/obj/structure/closet/crate/secure/loot/New()
+ ..()
+ var/list/digits = list("1", "2", "3", "4", "5", "6", "7", "8", "9", "0")
+
+ code = ""
+ for(var/i = 0, i < codelen, i++)
+ var/dig = pick(digits)
+ code += dig
+ digits -= dig //Player can enter codes with matching digits, but there are never matching digits in the answer
+
+ var/loot = rand(1,100) //100 different crates with varying chances of spawning
+ switch(loot)
+ if(1 to 5) //5% chance
+ new /obj/item/weapon/reagent_containers/food/drinks/bottle/rum(src)
+ new /obj/item/weapon/reagent_containers/food/snacks/grown/ambrosia(src)
+ new /obj/item/weapon/reagent_containers/food/drinks/bottle/whiskey(src)
+ new /obj/item/weapon/lighter(src)
+ if(6 to 10)
+ new /obj/item/weapon/bedsheet(src)
+ new /obj/item/weapon/kitchen/knife(src)
+ new /obj/item/weapon/wirecutters(src)
+ new /obj/item/weapon/screwdriver(src)
+ new /obj/item/weapon/weldingtool(src)
+ new /obj/item/weapon/hatchet(src)
+ new /obj/item/weapon/crowbar(src)
+ if(11 to 15)
+ new /obj/item/weapon/reagent_containers/glass/beaker/bluespace(src)
+ if(16 to 20)
+ for(var/i = 0, i < 10, i++)
+ new /obj/item/weapon/ore/diamond(src)
+ if(21 to 25)
+ for(var/i = 0, i < 5, i++)
+ new /obj/item/weapon/contraband/poster(src)
+ if(26 to 30)
+ for(var/i = 0, i < 3, i++)
+ new /obj/item/weapon/reagent_containers/glass/beaker/noreact(src)
+ if(31 to 35)
+ new /obj/item/seeds/cashseed(src)
+ if(36 to 40)
+ new /obj/item/weapon/melee/baton(src)
+ if(41 to 45)
+ new /obj/item/clothing/under/shorts/red(src)
+ new /obj/item/clothing/under/shorts/blue(src)
+ if(46 to 50)
+ new /obj/item/clothing/under/chameleon(src)
+ for(var/i = 0, i < 7, i++)
+ new /obj/item/clothing/tie/horrible(src)
+ if(51 to 52) // 2% chance
+ new /obj/item/weapon/melee/classic_baton(src)
+ if(53 to 54)
+ new /obj/item/toy/balloon(src)
+ if(55 to 56)
+ var/newitem = pick(typesof(/obj/item/toy/prize) - /obj/item/toy/prize)
+ new newitem(src)
+ if(57 to 58)
+ new /obj/item/toy/syndicateballoon(src)
+ if(59 to 60)
+ new /obj/item/weapon/pickaxe/drill(src)
+ new /obj/item/device/taperecorder(src)
+ new /obj/item/clothing/suit/space(src)
+ new /obj/item/clothing/head/helmet/space(src)
+ if(61 to 62)
+ for(var/i = 0, i < 12, ++i)
+ new /obj/item/clothing/head/kitty(src)
+ if(63 to 64)
+ var/t = rand(4,7)
+ for(var/i = 0, i < t, ++i)
+ var/newcoin = pick(/obj/item/weapon/coin/silver, /obj/item/weapon/coin/silver, /obj/item/weapon/coin/silver, /obj/item/weapon/coin/iron, /obj/item/weapon/coin/iron, /obj/item/weapon/coin/iron, /obj/item/weapon/coin/gold, /obj/item/weapon/coin/diamond, /obj/item/weapon/coin/plasma, /obj/item/weapon/coin/uranium)
+ new newcoin(src)
+ if(65 to 66)
+ new /obj/item/clothing/suit/ianshirt(src)
+ if(67 to 68)
+ var/t = rand(4,7)
+ for(var/i = 0, i < t, ++i)
+ var /newitem = pick(typesof(/obj/item/weapon/stock_parts) - /obj/item/weapon/stock_parts - /obj/item/weapon/stock_parts/subspace)
+ new newitem(src)
+ if(69 to 70)
+ for(var/i = 0, i < 5, ++i)
+ new /obj/item/bluespace_crystal(src)
+ if(71 to 72)
+ new /obj/item/weapon/pickaxe/drill(src)
+ if(73 to 74)
+ new /obj/item/weapon/pickaxe/drill/jackhammer(src)
+ if(75 to 76)
+ new /obj/item/weapon/pickaxe/diamond(src)
+ if(77 to 78)
+ new /obj/item/weapon/pickaxe/drill/diamonddrill(src)
+ if(79 to 80)
+ new /obj/item/weapon/cane(src)
+ new /obj/item/clothing/head/collectable/tophat(src)
+ if(81 to 82)
+ new /obj/item/weapon/gun/energy/plasmacutter(src)
+ if(83 to 84)
+ new /obj/item/toy/katana(src)
+ if(85 to 86)
+ new /obj/item/weapon/defibrillator/compact(src)
+ if(87) //1% chance
+ new /obj/item/weed_extract(src)
+ if(88)
+ new /obj/item/organ/brain(src)
+ if(89)
+ new /obj/item/organ/brain/alien(src)
+ if(90)
+ new /obj/item/organ/heart(src)
+ if(91)
+ new /obj/item/device/soulstone/anybody(src)
+ if(92)
+ new /obj/item/weapon/katana(src)
+ if(93)
+ new /obj/item/weapon/dnainjector/xraymut(src)
+ if(94)
+ new /obj/item/weapon/storage/backpack/clown(src)
+ new /obj/item/clothing/under/rank/clown(src)
+ new /obj/item/clothing/shoes/clown_shoes(src)
+ new /obj/item/device/pda/clown(src)
+ new /obj/item/clothing/mask/gas/clown_hat(src)
+ new /obj/item/weapon/bikehorn(src)
+ new /obj/item/toy/crayon/rainbow(src)
+ new /obj/item/weapon/reagent_containers/spray/waterflower(src)
+ if(95)
+ new /obj/item/clothing/under/rank/mime(src)
+ new /obj/item/clothing/shoes/sneakers/black(src)
+ new /obj/item/device/pda/mime(src)
+ new /obj/item/clothing/gloves/color/white(src)
+ new /obj/item/clothing/mask/gas/mime(src)
+ new /obj/item/clothing/head/beret(src)
+ new /obj/item/clothing/suit/suspenders(src)
+ new /obj/item/toy/crayon/mime(src)
+ new /obj/item/weapon/reagent_containers/food/drinks/bottle/bottleofnothing(src)
+ if(96)
+ new /obj/item/weapon/hand_tele(src)
+ if(97)
+ new /obj/item/clothing/mask/balaclava
+ new /obj/item/weapon/gun/projectile/automatic/pistol(src)
+ new /obj/item/ammo_box/magazine/m10mm(src)
+ if(98)
+ new /obj/item/weapon/katana/cursed(src)
+ if(99)
+ new /obj/item/weapon/storage/belt/champion(src)
+ new /obj/item/clothing/mask/luchador(src)
+ if(100)
+ new /obj/item/clothing/head/bearpelt(src)
+
+/obj/structure/closet/crate/secure/loot/attack_hand(mob/user as mob)
+ if(locked)
+ user << "The crate is locked with a Deca-code lock."
+ var/input = input(usr, "Enter [codelen] digits.", "Deca-Code Lock", "") as text
+ if(user.canUseTopic(src, 1))
+ if (input == code)
+ user << "The crate unlocks!"
+ locked = 0
+ overlays.Cut()
+ overlays += greenlight
+ else if (input == null || length(input) != codelen)
+ user << "You leave the crate alone."
+ else
+ user << "A red light flashes."
+ lastattempt = input
+ attempts--
+ if (attempts == 0)
+ user << "The crate's anti-tamper system activates!"
+ var/turf/T = get_turf(src.loc)
+ explosion(T, -1, -1, 1, 1)
+ qdel(src)
+ return
+ else
+ return ..()
+
+/obj/structure/closet/crate/secure/loot/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ if(locked)
+ if (istype(W, /obj/item/weapon/card/emag))
+ user << "The crate's anti-tamper system activates!"
+ var/turf/T = get_turf(src.loc)
+ explosion(T, -1, -1, 1, 1)
+ qdel(src)
+ return
+ if (istype(W, /obj/item/device/multitool))
+ user << "DECA-CODE LOCK REPORT:"
+ if (attempts == 1)
+ user << "* Anti-Tamper Bomb will activate on next failed access attempt."
+ else
+ user << "* Anti-Tamper Bomb will activate after [src.attempts] failed access attempts."
+ if (lastattempt != null)
+ var/list/guess = list()
+ var/bulls = 0
+ var/cows = 0
+ for(var/i = 1, i < codelen + 1, i++)
+ var/a = copytext(lastattempt, i, i+1) //Stuff the code into the list
+ guess += a
+ guess[a] = i
+ for(var/i in guess) //Go through list and count matches
+ var/a = findtext(code, i)
+ if(a == guess[i])
+ ++bulls
+ else if(a)
+ ++cows
+ user << "Last code attempt had [bulls] correct digits at correct positions and [cows] correct digits at incorrect positions."
+ else ..()
+ else ..()
diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm
index 00bed34c8fd..2f3218f4e27 100644
--- a/code/modules/mining/mine_turfs.dm
+++ b/code/modules/mining/mine_turfs.dm
@@ -431,7 +431,7 @@ var/global/list/rockTurfEdgeCache
user << "You start picking..."
P.playDigSound()
- if(do_after(user,P.digspeed))
+ if(do_after(user,P.digspeed, target = src))
if(istype(src, /turf/simulated/mineral)) //sanity check against turf being deleted during digspeed delay
user << "You finish cutting into the rock."
P.update_icon()
diff --git a/code/modules/mining/money_bag.dm b/code/modules/mining/money_bag.dm
index e9befa30d43..a8eefeb5bfc 100644
--- a/code/modules/mining/money_bag.dm
+++ b/code/modules/mining/money_bag.dm
@@ -8,6 +8,8 @@
force = 10.0
throwforce = 0
w_class = 4.0
+ burn_state = 0 //Burnable
+ burntime = 20
/obj/item/weapon/moneybag/attack_hand(user as mob)
var/amt_gold = 0
diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm
index baddbc27a53..52e97f3a423 100644
--- a/code/modules/mining/ores_coins.dm
+++ b/code/modules/mining/ores_coins.dm
@@ -326,7 +326,7 @@
flick("coin_[cmineral]_flip", src)
icon_state = "coin_[cmineral]_[coinflip]"
playsound(user.loc, 'sound/items/coinflip.ogg', 50, 1)
- if(do_after(user, 15))
+ if(do_after(user, 15, target = src))
user.visible_message("[user] has flipped [src]. It lands on [coinflip].", \
"You flip [src]. It lands on [coinflip].", \
"You hear the clattering of loose change.")
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/alien/humanoid/queen.dm b/code/modules/mob/living/carbon/alien/humanoid/queen.dm
index 9670240e4aa..1b58d61fb27 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/queen.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/queen.dm
@@ -84,7 +84,9 @@
overlays.Cut()
if(stat == DEAD)
icon_state = "queen_dead"
- else if(stat == UNCONSCIOUS || lying || resting)
+ else if((stat == UNCONSCIOUS && !sleeping) || weakened)
+ icon_state = "queen_l"
+ else if(sleeping || lying || resting)
icon_state = "queen_sleep"
else
icon_state = "queen_s"
diff --git a/code/modules/mob/living/carbon/alien/life.dm b/code/modules/mob/living/carbon/alien/life.dm
index 39b9a267f9e..f081e566f3a 100644
--- a/code/modules/mob/living/carbon/alien/life.dm
+++ b/code/modules/mob/living/carbon/alien/life.dm
@@ -64,4 +64,5 @@
return 1
/mob/living/carbon/alien/CheckStamina()
+ setStaminaLoss(max((staminaloss - 2), 0))
return
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm
index 7ff98ab7531..c053d20c090 100644
--- a/code/modules/mob/living/carbon/alien/special/facehugger.dm
+++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm
@@ -15,9 +15,10 @@ var/const/MAX_ACTIVE_TIME = 400
icon_state = "facehugger"
item_state = "facehugger"
w_class = 1 //note: can be picked up by aliens unlike most other items of w_class below 4
- flags = MASKCOVERSMOUTH | MASKCOVERSEYES | MASKINTERNALS
+ flags = MASKINTERNALS
throw_range = 5
tint = 3
+ flags_cover = MASKCOVERSEYES | MASKCOVERSMOUTH
var/stat = CONSCIOUS //UNCONSCIOUS is the idle state in this case
diff --git a/code/modules/mob/living/carbon/brain/MMI.dm b/code/modules/mob/living/carbon/brain/MMI.dm
index ffb73ef359f..753d2bd2d6c 100644
--- a/code/modules/mob/living/carbon/brain/MMI.dm
+++ b/code/modules/mob/living/carbon/brain/MMI.dm
@@ -41,7 +41,7 @@
user << "You aren't sure where this brain came from, but you're pretty sure it's a useless brain!"
return
- if(!user.unEquip(src))
+ if(!user.unEquip(O))
return
var/mob/living/carbon/brain/B = newbrain.brainmob
if(!B.key)
diff --git a/code/modules/mob/living/carbon/brain/brain_item.dm b/code/modules/mob/living/carbon/brain/brain_item.dm
index ed151132066..7a233cea9c2 100644
--- a/code/modules/mob/living/carbon/brain/brain_item.dm
+++ b/code/modules/mob/living/carbon/brain/brain_item.dm
@@ -51,7 +51,7 @@
return ..()
var/mob/living/carbon/human/H = M
- if(istype(M, /mob/living/carbon/human) && ((H.head && H.head.flags & HEADCOVERSEYES) || (H.wear_mask && H.wear_mask.flags & MASKCOVERSEYES) || (H.glasses && H.glasses.flags & GLASSESCOVERSEYES)))
+ if(istype(M, /mob/living/carbon/human) && ((H.head && H.head.flags_cover & HEADCOVERSEYES) || (H.wear_mask && H.wear_mask.flags_cover & MASKCOVERSEYES) || (H.glasses && H.glasses.flags & GLASSESCOVERSEYES)))
user << "You're going to need to remove their head cover first!"
return
diff --git a/code/modules/mob/living/carbon/brain/posibrain.dm b/code/modules/mob/living/carbon/brain/posibrain.dm
index efdceeb7529..37a596ab08a 100644
--- a/code/modules/mob/living/carbon/brain/posibrain.dm
+++ b/code/modules/mob/living/carbon/brain/posibrain.dm
@@ -78,17 +78,13 @@ var/global/posibrain_notif_cooldown = 0
return
/obj/item/device/mmi/posibrain/proc/transfer_personality(var/mob/candidate)
- if(brainmob && brainmob.key) //Prevents hostile takeover if two ghosts get the prompt for the same brain.
+ if(brainmob && brainmob.key) //Prevents hostile takeover if two ghosts get the prompt or link for the same brain.
candidate << "This brain has already been taken! Please try your possesion again later!"
return
notified = 0
- brainmob.mind = candidate.mind
brainmob.ckey = candidate.ckey
name = "positronic brain ([brainmob.name])"
- brainmob.mind.remove_all_antag()
- brainmob.mind.wipe_memory()
-
brainmob << "ALL PAST LIVES ARE FORGOTTEN."
brainmob << "You are a positronic brain, brought into existence on [station_name()]."
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 030b2a74750..937d13e4ec4 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -38,9 +38,10 @@
/mob/living/carbon/relaymove(var/mob/user, direction)
if(user in src.stomach_contents)
if(prob(40))
- audible_message("You hear something rumbling inside [src]'s stomach...", \
- "You hear something rumbling.", 4,\
- "Something is rumbling inside your stomach!")
+ if(prob(25))
+ audible_message("You hear something rumbling inside [src]'s stomach...", \
+ "You hear something rumbling.", 4,\
+ "Something is rumbling inside your stomach!")
var/obj/item/I = user.get_active_hand()
if(I && I.force)
var/d = rand(round(I.force / 4), I.force)
@@ -407,7 +408,7 @@ var/const/GALOSHES_DONT_HELP = 8
last_special = world.time + CLICK_CD_BREAKOUT
visible_message("[src] attempts to unbuckle themself!", \
"You attempt to unbuckle yourself... (This will take around one minute and you need to stay still.)")
- if(do_after(src, 600, needhand = 0))
+ if(do_after(src, 600, needhand = 0, target = src))
if(!buckled)
return
buckled.user_unbuckle_mob(src,src)
@@ -450,7 +451,7 @@ var/const/GALOSHES_DONT_HELP = 8
if(!cuff_break)
visible_message("[src] attempts to remove [I]!")
src << "You attempt to remove [I]... (This will take around [displaytime] minutes and you need to stand still.)"
- if(do_after(src, breakouttime, 10, 0))
+ if(do_after(src, breakouttime, 10, 0, target = src))
if(I.loc != src || buckled)
return
visible_message("[src] manages to remove [I]!")
@@ -466,6 +467,7 @@ var/const/GALOSHES_DONT_HELP = 8
return
if(legcuffed)
legcuffed.loc = loc
+ legcuffed.dropped()
legcuffed = null
update_inv_legcuffed(0)
else
@@ -475,7 +477,7 @@ var/const/GALOSHES_DONT_HELP = 8
breakouttime = 50
visible_message("[src] is trying to break [I]!")
src << "You attempt to break [I]... (This will take around 5 seconds and you need to stand still.)"
- if(do_after(src, breakouttime, needhand = 0))
+ if(do_after(src, breakouttime, needhand = 0, target = src))
if(!I.loc || buckled)
return
visible_message("[src] manages to break [I]!")
@@ -493,7 +495,7 @@ var/const/GALOSHES_DONT_HELP = 8
src << "You fail to break [I]!"
/mob/living/carbon/proc/is_mouth_covered(head_only = 0, mask_only = 0)
- if( (!mask_only && head && (head.flags & HEADCOVERSMOUTH)) || (!head_only && wear_mask && (wear_mask.flags & MASKCOVERSMOUTH)) )
+ if( (!mask_only && head && (head.flags_cover & HEADCOVERSMOUTH)) || (!head_only && wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH)) )
return 1
/mob/living/carbon/get_standard_pixel_y_offset(lying = 0)
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 16be6a0f49e..b99a78d7e9e 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -116,17 +116,17 @@
gib()
return
else
+ shred_clothing(1,150)
var/atom/target = get_edge_target_turf(src, get_dir(src, get_step_away(src, src)))
throw_at(target, 200, 4)
- //return
-// var/atom/target = get_edge_target_turf(user, get_dir(src, get_step_away(user, src)))
- //user.throw_at(target, 200, 4)
if (2.0)
b_loss += 60
f_loss += 60
+ shred_clothing(1,50)
+
if (prob(getarmor(null, "bomb")))
b_loss = b_loss/1.5
f_loss = f_loss/1.5
@@ -140,6 +140,8 @@
b_loss += 30
if (prob(getarmor(null, "bomb")))
b_loss = b_loss/2
+ else
+ shred_clothing(1,10)
if (!istype(ears, /obj/item/clothing/ears/earmuffs))
adjustEarDamage(15,60)
if (prob(50))
@@ -284,7 +286,7 @@
return
var/time_taken = I.embedded_unsafe_removal_time*I.w_class
usr.visible_message("[usr] attempts to remove [I] from their [L.getDisplayName()].","You attempt to remove [I] from your [L.getDisplayName()]... (It will take [time_taken/10] seconds.)")
- if(do_after(usr, time_taken, needhand = 1))
+ if(do_after(usr, time_taken, needhand = 1, target = src))
L.embedded_objects -= I
L.take_damage(I.embedded_unsafe_removal_pain_multiplier*I.w_class)//It hurts to rip it out, get surgery you dingus.
I.loc = get_turf(src)
diff --git a/code/modules/mob/living/carbon/human/human_attackalien.dm b/code/modules/mob/living/carbon/human/human_attackalien.dm
index 970761f0d26..ed9c6ef91c1 100644
--- a/code/modules/mob/living/carbon/human/human_attackalien.dm
+++ b/code/modules/mob/living/carbon/human/human_attackalien.dm
@@ -14,7 +14,7 @@
"[M] has lunged at [src]!")
return 0
var/obj/item/organ/limb/affecting = get_organ(ran_zone(M.zone_sel.selecting))
- var/armor_block = run_armor_check(affecting, "melee")
+ var/armor_block = run_armor_check(affecting, "melee","","",10)
playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
visible_message("[M] has slashed at [src]!", \
diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm
index 7c0773877c1..df2c627615c 100644
--- a/code/modules/mob/living/carbon/human/human_damage.dm
+++ b/code/modules/mob/living/carbon/human/human_damage.dm
@@ -10,9 +10,10 @@
total_brute += O.brute_dam
total_burn += O.burn_dam
health = maxHealth - getOxyLoss() - getToxLoss() - getCloneLoss() - total_burn - total_brute
- //TODO: fix husking
if( ((maxHealth - total_burn) < config.health_threshold_dead) && stat == DEAD )
ChangeToHusk()
+ if(bodytemperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
+ shred_clothing()
med_hud_set_health()
med_hud_set_status()
return
@@ -50,7 +51,7 @@
var/loose = 40
if(stat || (status_flags & FAKEDEATH))
multiplier = 2
- if(H.flags & (HEADCOVERSEYES | HEADCOVERSMOUTH) || H.flags_inv & (HIDEEYES | HIDEFACE))
+ if(H.flags_cover & (HEADCOVERSEYES | HEADCOVERSMOUTH) || H.flags_inv & (HIDEEYES | HIDEFACE))
loose = 0
return loose * multiplier
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 32086909dbf..b46faf97501 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -151,8 +151,9 @@ emp_act
else
return 0
- var/armor = run_armor_check(affecting, "melee", "Your armor has protected your [hit_area].", "Your armor has softened a hit to your [hit_area].")
- if(armor >= 100) return 0
+ var/armor = run_armor_check(affecting, "melee", "Your armor has protected your [hit_area].", "Your armor has softened a hit to your [hit_area].", I.armour_penetration)
+ armor = min(90,armor) //cap damage reduction at 90%
+
var/Iforce = I.force //to avoid runtimes on the forcesay checks at the bottom. Some items might delete themselves if you drop them. (stunning yourself, ninja swords)
apply_damage(I.force, I.damtype, affecting, armor , I)
@@ -188,7 +189,7 @@ emp_act
visible_message("[src] has been knocked unconscious!", \
"[src] has been knocked unconscious!")
apply_effect(20, PARALYZE, armor)
- if(prob(I.force + ((100 - src.health)/2)) && src != user && I.damtype == BRUTE)
+ if(prob(I.force + min(100,100 - src.health)) && src != user && I.damtype == BRUTE)
ticker.mode.remove_revolutionary(mind)
ticker.mode.remove_gangster(mind, exclude_bosses=1)
if(bloody) //Apply blood
@@ -384,8 +385,6 @@ emp_act
var/armor = run_armor_check(affecting, "melee")
apply_damage(damage, BRUTE, affecting, armor)
updatehealth()
-/* if(armor >= 2) //why is this here?
- return */
/mob/living/carbon/human/attack_larva(mob/living/carbon/alien/larva/L as mob)
diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm
index 1a4cd41351c..a4c1a29a2aa 100644
--- a/code/modules/mob/living/carbon/human/inventory.dm
+++ b/code/modules/mob/living/carbon/human/inventory.dm
@@ -390,3 +390,83 @@
src << "You are trying to equip this item to an unsupported inventory slot. Report this to a coder!"
return
+//Cycles through all clothing slots and tests them for destruction
+/mob/living/carbon/human/proc/shred_clothing(var/bomb,var/shock)
+ var/covered_parts //The body parts that are protected by exterior clothing/armor
+ var/head_absorbed = 0 //How much of the shock the headgear absorbs when it is shredded. -1=it survives
+ var/suit_absorbed = 0 //How much of the shock the exosuit absorbs when it is shredded. -1=it survives
+
+ //Backpacks can never be protected but are annoying as fuck to lose, so they get a lower chance to be shredded
+ if(back)
+ back.shred(bomb,shock-30,src)
+
+ if(head)
+ covered_parts |= head.flags_inv
+ head_absorbed = head.shred(bomb,shock,src)
+ if(wear_mask)
+ var/absorbed = ((covered_parts & HIDEMASK) ? head_absorbed : 0) //Check if clothing covering this part absorbed any of the shock
+ if(!(absorbed < 0))
+ //Masks can be used to shield other parts, but are simplified to simply add their absorbsion to the head armor if it covers the face
+ var/mask_absorbed = wear_mask.shred(bomb,shock-absorbed,src)
+ if(wear_mask.flags_inv & HIDEFACE)
+ covered_parts |= wear_mask.flags_inv
+ if(mask_absorbed < 0) //If the mask didn't get shredded, everything else on the head is protected
+ head_absorbed = -1
+ else
+ head_absorbed += mask_absorbed
+ if(ears)
+ var/absorbed = ((covered_parts & HIDEEARS) ? head_absorbed : 0)
+ if(!(absorbed < 0))
+ ears.shred(bomb,shock-absorbed,src)
+ if(glasses)
+ var/absorbed = ((covered_parts & HIDEEYES) ? head_absorbed : 0)
+ if(!(absorbed < 0))
+ glasses.shred(bomb,shock-absorbed,src)
+
+ if(wear_suit)
+ covered_parts |= wear_suit.flags_inv
+ suit_absorbed = wear_suit.shred(bomb,shock,src)
+ if(gloves)
+ var/absorbed = ((covered_parts & HIDEGLOVES) ? suit_absorbed : 0)
+ if(!(absorbed < 0))
+ gloves.shred(bomb,shock-absorbed,src)
+ if(shoes)
+ var/absorbed = ((covered_parts & HIDESHOES) ? suit_absorbed : 0)
+ if(!(absorbed < 0))
+ shoes.shred(bomb,shock-absorbed,src)
+ if(w_uniform)
+ var/absorbed = ((covered_parts & HIDEJUMPSUIT) ? suit_absorbed : 0)
+ if(!(absorbed < 0))
+ w_uniform.shred(bomb,shock-absorbed,src)
+
+/obj/item/proc/shred(var/bomb,var/shock,var/mob/living/carbon/human/Human)
+ var/shredded
+
+ if(!bomb)
+ if(burn_state != -1)
+ shredded = 1 //No heat protection, it burns
+ else
+ shredded = -1 //Heat protection = Fireproof
+
+ else if(shock > 0)
+ if(prob(min(90,max(10,shock))))
+ shredded = armor["bomb"] + 10 //It gets shredded, but it also absorbs the shock the clothes underneath would recieve by this amount
+ else
+ shredded = -1 //It survives explosion
+
+ if(shredded > 0)
+ if(Human) //Unequip if equipped
+ Human.unEquip(src)
+
+ if(bomb)
+ for(var/obj/item/Item in contents) //Empty out the contents
+ Item.loc = src.loc
+ spawn(1) //so the shreds aren't instantly deleted by the explosion
+ var/obj/effect/decal/cleanable/shreds/Shreds = new(loc)
+ Shreds.name = "shredded [src.name]"
+ Shreds.desc = "The sad remains of what used to be a glorious [src.name]."
+ qdel(src)
+ else
+ burn()
+
+ return shredded
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index ae6d8824d95..67caa33abac 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -923,8 +923,8 @@
else
return 0
- var/armor = H.run_armor_check(affecting, "melee", "Your armor has protected your [hit_area].", "Your armor has softened a hit to your [hit_area].")
- if(armor >= 100) return 0
+ var/armor = H.run_armor_check(affecting, "melee", "Your armor has protected your [hit_area].", "Your armor has softened a hit to your [hit_area].",I.armour_penetration)
+ armor = min(90,armor) //cap damage reduction at 90%
var/Iforce = I.force //to avoid runtimes on the forcesay checks at the bottom. Some items might delete themselves if you drop them. (stunning yourself, ninja swords)
apply_damage(I.force, I.damtype, affecting, armor, H)
diff --git a/code/modules/mob/living/carbon/human/whisper.dm b/code/modules/mob/living/carbon/human/whisper.dm
index fd4573900c7..f42c367d4bb 100644
--- a/code/modules/mob/living/carbon/human/whisper.dm
+++ b/code/modules/mob/living/carbon/human/whisper.dm
@@ -1,6 +1,8 @@
/mob/living/carbon/human/whisper(message as text)
if(!IsVocal())
return
+ if(!message)
+ return
if(say_disabled) //This is here to try to identify lag problems
usr << "Speech is currently admin-disabled."
@@ -9,18 +11,18 @@
if(stat == DEAD)
return
-
+
message = trim(html_encode(message))
if(!can_speak(message))
return
-
- message = "[message]"
+
+ message = "[message]"
log_whisper("[src.name]/[src.key] : [message]")
if (src.client)
if (src.client.prefs.muted & MUTE_IC)
src << "You cannot whisper (muted)."
- return
+ return
log_whisper("[src.name]/[src.key] : [message]")
@@ -66,13 +68,17 @@
var/spans = list(SPAN_ITALICS)
rendered = "[GetVoice()][alt_name] [whispers], \"[attach_spans(message, spans)]\""
- for(var/mob/M in listening)
- M.Hear(rendered, src, languages, message, , spans)
+ for(var/atom/movable/AM in listening)
+ if(istype(AM,/obj/item/device/radio))
+ continue
+ AM.Hear(rendered, src, languages, message, , spans)
message = stars(message)
rendered = "[GetVoice()][alt_name] [whispers], \"[attach_spans(message, spans)]\""
- for(var/mob/M in eavesdropping)
- M.Hear(rendered, src, languages, message, , spans)
+ for(var/atom/movable/AM in eavesdropping)
+ if(istype(AM,/obj/item/device/radio))
+ continue
+ AM.Hear(rendered, src, languages, message, , spans)
if(critical) //Dying words.
succumb(1)
diff --git a/code/modules/mob/living/carbon/say.dm b/code/modules/mob/living/carbon/say.dm
index 9f218605c01..0d8a39ee9ef 100644
--- a/code/modules/mob/living/carbon/say.dm
+++ b/code/modules/mob/living/carbon/say.dm
@@ -5,7 +5,7 @@
return message
-/mob/living/carbon/can_speak_basic(message)
+/mob/living/carbon/can_speak_vocal(message)
if(silent)
return 0
return ..()
diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm
index d79896f82dd..08ffb07c7d9 100644
--- a/code/modules/mob/living/emote.dm
+++ b/code/modules/mob/living/emote.dm
@@ -3,6 +3,9 @@
//Intended to be called by a higher up emote proc if the requested emote isn't in the custom emotes.
/mob/living/emote(var/act, var/m_type=1, var/message = null)
+ if(stat)
+ return
+
var/param = null
if (findtext(act, "-", 1, null))
@@ -150,8 +153,6 @@
return
if (src.client.handle_spam_prevention(message,MUTE_IC))
return
- if (stat)
- return
if(!(message))
return
else
diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm
index 5beeeb3a847..151b8978dc8 100644
--- a/code/modules/mob/living/life.dm
+++ b/code/modules/mob/living/life.dm
@@ -62,6 +62,7 @@
return
/mob/living/proc/handle_mutations_and_radiation()
+ radiation = 0 //so radiation don't accumulate in simple animals
return
/mob/living/proc/handle_chemicals_in_body()
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index d23dcbabcc0..bc689b62098 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -673,10 +673,13 @@ Sorry Giacom. Please don't be mad :(
/mob/living/proc/float(on)
if(throwing)
return
- if(on && !floating)
+ var/fixed = 0
+ if(anchored || (buckled && buckled.anchored))
+ fixed = 1
+ if(on && !floating && !fixed)
animate(src, pixel_y = pixel_y + 2, time = 10, loop = -1)
floating = 1
- else if(!on && floating)
+ else if(((!on || fixed) && floating))
var/final_pixel_y = get_standard_pixel_y_offset(lying)
animate(src, pixel_y = final_pixel_y, time = 10)
floating = 0
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 100251062c5..af8b231f78a 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -1,5 +1,14 @@
-/mob/living/proc/run_armor_check(def_zone = null, attack_flag = "melee", absorb_text = null, soften_text = null)
+/mob/living/proc/run_armor_check(def_zone = null, attack_flag = "melee", absorb_text = null, soften_text = null, var/armour_penetration, var/penetrated_text)
var/armor = getarmor(def_zone, attack_flag)
+
+ //the if "armor" check is because this is used for everything on /living, including humans
+ if(armor && armour_penetration)
+ armor = max(0, armor - armour_penetration)
+ if(penetrated_text)
+ src << "[penetrated_text]"
+ else
+ src << "Your armor was penetrated!"
+
if(armor >= 100)
if(absorb_text)
src << "[absorb_text]"
@@ -20,7 +29,7 @@
return
/mob/living/bullet_act(obj/item/projectile/P, def_zone)
- var/armor = run_armor_check(def_zone, P.flag)
+ var/armor = run_armor_check(def_zone, P.flag, "","",P.armour_penetration)
if(!P.nodamage)
apply_damage(P.damage, P.damage_type, def_zone, armor)
return P.on_hit(src, armor, def_zone)
@@ -60,7 +69,7 @@
visible_message("[src] has been hit by [I].", \
"[src] has been hit by [I].")
- var/armor = run_armor_check(zone, "melee", "Your armor has protected your [parse_zone(zone)].", "Your armor has softened hit to your [parse_zone(zone)].")
+ var/armor = run_armor_check(zone, "melee", "Your armor has protected your [parse_zone(zone)].", "Your armor has softened hit to your [parse_zone(zone)].",I.armour_penetration)
apply_damage(I.throwforce, dtype, zone, armor, I)
if(!I.fingerprintslast)
return
@@ -219,7 +228,7 @@
return 0
if (M.a_intent == "harm")
- if(M.is_muzzled() || (M.wear_mask && M.wear_mask.flags & MASKCOVERSMOUTH))
+ if(M.is_muzzled() || (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSMOUTH))
M << "You can't bite with your mouth covered!"
return 0
M.do_attack_animation(src)
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index def924f9943..a0df06a9088 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -56,6 +56,8 @@ var/list/department_radio_keys = list(
":ï" = "changeling", "#ï" = "changeling", ".ï" = "changeling"
)
+var/list/crit_allowed_modes = list(MODE_WHISPER,MODE_CHANGELING,MODE_ALIEN)
+
/mob/living/say(message, bubble_type,)
message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
@@ -63,18 +65,17 @@ var/list/department_radio_keys = list(
say_dead(message)
return
- if(stat)
- return
-
if(check_emote(message))
return
if(!can_speak_basic(message)) //Stat is seperate so I can handle whispers properly.
- src << "You find yourself unable to speak!"
return
var/message_mode = get_message_mode(message)
+ if(stat && !(message_mode in crit_allowed_modes))
+ return
+
if(message_mode == MODE_HEADSET || message_mode == MODE_ROBOT)
message = copytext(message, 2)
else if(message_mode)
@@ -86,14 +87,14 @@ var/list/department_radio_keys = list(
return
if(!can_speak_vocal(message))
- src << "You find yourself unable to speak!" //repetition intended
+ src << "You find yourself unable to speak!"
return
message = treat_message(message)
var/spans = list()
spans += get_spans()
- if(!message || message == "")
+ if(!message)
return
var/message_range = 7
@@ -163,9 +164,6 @@ var/list/department_radio_keys = list(
return 1
/mob/living/proc/can_speak_basic(message) //Check BEFORE handling of xeno and ling channels
- if(!message || message == "")
- return 0
-
if(client)
if(client.prefs.muted & MUTE_IC)
src << "You cannot speak in IC (muted)."
@@ -176,9 +174,6 @@ var/list/department_radio_keys = list(
return 1
/mob/living/proc/can_speak_vocal(message) //Check AFTER handling of xeno and ling channels
- if(!message)
- return 0
-
if(disabilities & MUTE)
return 0
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index e37ac76c526..c1030d43b39 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -483,7 +483,7 @@
else
playsound(src, 'sound/items/Ratchet.ogg', 50, 1)
user << "You start to unfasten [src]'s securing bolts..."
- if(do_after(user, 50) && !cell)
+ if(do_after(user, 50, target = src) && !cell)
user.visible_message("[user] deconstructs [src]!", "You unfasten the securing bolts, and [src] falls to pieces!")
deconstruct()
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index e9bd8434232..8cace44236d 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -221,7 +221,7 @@
modules += new /obj/item/weapon/reagent_containers/dropper(src)
- var/obj/item/weapon/lighter/zippo/L = new /obj/item/weapon/lighter/zippo(src)
+ var/obj/item/weapon/lighter/L = new /obj/item/weapon/lighter(src)
L.lit = 1
modules += L
diff --git a/code/modules/mob/living/simple_animal/friendly/corgi.dm b/code/modules/mob/living/simple_animal/friendly/corgi.dm
index c73a3443b09..1462e2b52ed 100644
--- a/code/modules/mob/living/simple_animal/friendly/corgi.dm
+++ b/code/modules/mob/living/simple_animal/friendly/corgi.dm
@@ -81,7 +81,7 @@
user << "You can't shave this corgi, it's already been shaved!"
return
user.visible_message("[user] starts to shave [src] using \the [O].", "You start to shave [src] using \the [O]...")
- if(do_after(user, 50))
+ if(do_after(user, 50, target = src))
user.visible_message("[user] shaves [src]'s hair using \the [O].")
playsound(loc, 'sound/items/Welder2.ogg', 20, 1)
shaved = 1
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
index 930dff33f2e..d4b664f4536 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
@@ -42,7 +42,7 @@
if(istype(loc, /mob/living))
var/mob/living/L = loc
L.show_message("[drone] is trying to escape!")
- if(!do_after(L, 50) || loc != L)
+ if(!do_after(L, 50, target = L) || loc != L)
return
L.unEquip(src)
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
index 61ffbe0eecf..98253d6b5d5 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
@@ -33,7 +33,7 @@
D << "You can't seem to find the [pick(faux_gadgets)]! Without it, [src] [pick(faux_problems)]."
return
D.visible_message("[D] begins to reactivate [src].", "You begin to reactivate [src]...")
- if(do_after(user,30,needhand = 1))
+ if(do_after(user,30,needhand = 1, target = src))
health = health_repair_max
stat = CONSCIOUS
icon_state = icon_living
@@ -49,7 +49,7 @@
if("Cannibalize")
if(D.health < D.maxHealth)
D.visible_message("[D] begins to cannibalize parts from [src].", "You begin to cannibalize parts from [src]...")
- if(do_after(D, 60,5,0))
+ if(do_after(D, 60,5,0, target = src))
D.visible_message("[D] repairs itself using [src]'s remains!", "You repair yourself using [src]'s remains.")
D.adjustBruteLoss(-src.maxHealth)
new /obj/effect/decal/cleanable/oil/streak(get_turf(src))
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm
index b4616ae9fb7..850f307f63b 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm
@@ -264,7 +264,7 @@
/obj/item/asteroid/hivelord_core
name = "hivelord remains"
- desc = "All that remains of a hivelord, it seems to be what allows it to break pieces of itself off without being hurt... its healing properties will soon become inert if not used quickly. Try not to think about what you're eating."
+ desc = "All that remains of a hivelord, it seems to be what allows it to break pieces of itself off without being hurt... its healing properties will soon become inert if not used quickly."
icon = 'icons/obj/food/food.dmi'
icon_state = "boiledrorocore"
var/inert = 0
@@ -285,10 +285,9 @@
user << "[src] are useless on the dead."
return
if(H != user)
- H.visible_message("[user] forces [H] to eat [src]... they quickly regenerate all injuries!")
+ H.visible_message("[user] forces [H] to apply [src]... they quickly regenerate all injuries!")
else
- user << "You chomp into [src], barely managing to hold it down, but feel amazingly refreshed in mere moments."
- playsound(src.loc,'sound/items/eatfood.ogg', rand(10,50), 1)
+ user << "You start to smear [src] on yourself. It feels and smells disgusting, but you feel amazingly refreshed in mere moments."
H.revive()
qdel(src)
..()
diff --git a/code/modules/mob/living/simple_animal/revenant/revenant.dm b/code/modules/mob/living/simple_animal/revenant/revenant.dm
index c81bb72ee31..dc1137e62d5 100644
--- a/code/modules/mob/living/simple_animal/revenant/revenant.dm
+++ b/code/modules/mob/living/simple_animal/revenant/revenant.dm
@@ -18,6 +18,7 @@
response_help = "passes through"
response_disarm = "swings at"
response_harm = "punches"
+ atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
maxbodytemp = INFINITY
harm_intent_damage = 5
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index f7f81ef7c41..6d3ff27d7a9 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -201,6 +201,10 @@
if(!atmos_suitable)
adjustBruteLoss(unsuitable_atmos_damage)
+ else
+ if(atmos_requirements["min_oxy"] || atmos_requirements["min_tox"] || atmos_requirements["min_n2"] || atmos_requirements["min_co2"])
+ adjustBruteLoss(unsuitable_atmos_damage)
+
handle_temperature_damage()
/mob/living/simple_animal/proc/handle_temperature_damage()
diff --git a/code/modules/mob/living/ventcrawling.dm b/code/modules/mob/living/ventcrawling.dm
index 9165e233d1b..5df785e016c 100644
--- a/code/modules/mob/living/ventcrawling.dm
+++ b/code/modules/mob/living/ventcrawling.dm
@@ -37,7 +37,7 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump,
if(vent_found.parent && (vent_found.parent.members.len || vent_found.parent.other_atmosmch))
visible_message("[src] begins climbing into the ventilation system..." ,"You begin climbing into the ventilation system...")
- if(!do_after(src, 25))
+ if(!do_after(src, 25, target = vent_found))
return
if(!client)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 416fe4d1170..1ff60cfeffb 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -159,8 +159,8 @@ var/next_mob_id = 0
var/range = 7
if(hearing_distance)
range = hearing_distance
- var/msg = message
for(var/mob/M in get_hearers_in_view(range, src))
+ var/msg = message
if(self_message && M==src)
msg = self_message
M.show_message( msg, 2, deaf_message, 1)
diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm
index 45f84087221..fa3a9bb4bbc 100644
--- a/code/modules/mob/mob_grab.dm
+++ b/code/modules/mob/mob_grab.dm
@@ -158,7 +158,7 @@
assailant.visible_message("[assailant] starts to tighten \his grip on [affecting]'s neck!")
hud.icon_state = "disarm/kill1"
state = GRAB_UPGRADING
- if(do_after(assailant, UPGRADE_KILL_TIMER))
+ if(do_after(assailant, UPGRADE_KILL_TIMER, target = affecting))
if(state == GRAB_KILL)
return
if(!affecting)
@@ -207,9 +207,9 @@
var/mob/living/carbon/attacker = user
user.visible_message("[user] is attempting to devour [affecting]!")
if(istype(user, /mob/living/carbon/alien/humanoid/hunter))
- if(!do_mob(user, affecting)||!do_after(user, 30)) return
+ if(!do_mob(user, affecting)||!do_after(user, 30, target = affecting)) return
else
- if(!do_mob(user, affecting)||!do_after(user, 100)) return
+ if(!do_mob(user, affecting)||!do_after(user, 100, target = affecting)) return
user.visible_message("[user] devours [affecting]!")
affecting.loc = user
attacker.stomach_contents.Add(affecting)
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index 8496da0ee08..a0106cfcc02 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -138,8 +138,12 @@
if(isturf(mob.loc))
+
+ var/turf/T = mob.loc
move_delay = world.time//set move delay
+ move_delay += T.slowdown
+
if(mob.restrained()) //Why being pulled while cuffed prevents you from moving
for(var/mob/M in range(mob, 1))
if(M.pulling == mob)
@@ -176,7 +180,6 @@
var/mob/M = L[1]
if(M)
if ((get_dist(mob, M) <= 1 || M.loc == mob.loc))
- var/turf/T = mob.loc
. = ..()
if (isturf(M.loc))
var/diag = get_dir(mob, M)
@@ -341,8 +344,6 @@
continue
if(AM.density)
if(AM.anchored)
- if(istype(AM, /obj/item/projectile)) //"You grab the bullet and push off of it!" No
- continue
return 1
if(pulling == AM)
continue
diff --git a/code/modules/nano/nanoexternal.dm b/code/modules/nano/nanoexternal.dm
index d6d2833e1e3..265629ec4df 100644
--- a/code/modules/nano/nanoexternal.dm
+++ b/code/modules/nano/nanoexternal.dm
@@ -39,5 +39,8 @@
/atom/movable/proc/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
return
+/atom/movable/proc/get_ui_data(mob/user)
+ return list()
+
// Used by the Nano UI SubSystem (/datum/subsystem/nano) to track UIs opened by this mob
/mob/var/list/open_uis = list()
diff --git a/code/modules/nano/nanomanager.dm b/code/modules/nano/nanomanager.dm
index 09b8a4796be..5f47c8da5ca 100644
--- a/code/modules/nano/nanomanager.dm
+++ b/code/modules/nano/nanomanager.dm
@@ -1,3 +1,27 @@
+ /**
+ * Get an open /nanoui ui for the current user, or create a new one.
+ *
+ * @param user /mob The mob who opened/owns the ui
+ * @param src_object /obj|/mob The obj or mob which the ui belongs to
+ * @param ui_key string A string key used for the ui
+ * @param ui /datum/nanoui An existing instance of the ui (can be null)
+ * @param data list The data to be passed to the ui, if it exists
+ *
+ * @return /nanoui Returns the new or found ui
+ */
+/datum/subsystem/nano/proc/push_open_or_new_ui(var/mob/user, var/atom/movable/src_object, ui_key, var/datum/nanoui/ui, template, title, width, height, auto_update)
+ var/list/data = src_object.get_ui_data(user)
+ if (!data)
+ data = list()
+
+ ui = try_update_ui(user, src_object, ui_key, ui, data)
+
+ if (isnull(ui))
+ ui = new /datum/nanoui(user, src_object, ui_key, template, title, width, height)
+ ui.set_initial_data(data)
+ ui.open()
+ ui.set_auto_update(auto_update)
+
/**
* Get an open /nanoui ui for the current user, src_object and ui_key and try to update it with data
*
@@ -11,9 +35,8 @@
*/
/datum/subsystem/nano/proc/try_update_ui(var/mob/user, src_object, ui_key, var/datum/nanoui/ui, data)
if (isnull(ui)) // no ui has been passed, so we'll search for one
- {
ui = get_open_ui(user, src_object, ui_key)
- }
+
if (!isnull(ui))
// The UI is already open so push the data to it
ui.push_data(data)
@@ -186,4 +209,4 @@
//Send all needed nano ui files to the client
/datum/subsystem/nano/proc/send_resources(client)
for(var/file in asset_files)
- client << browse_rsc(file)
+ client << browse_rsc(file)
\ No newline at end of file
diff --git a/code/modules/nano/nanoui.dm b/code/modules/nano/nanoui.dm
index 5bebfcb8682..729f0327a4b 100644
--- a/code/modules/nano/nanoui.dm
+++ b/code/modules/nano/nanoui.dm
@@ -131,8 +131,13 @@ nanoui is used to open and update nano browser uis
set_status(STATUS_DISABLED, push_update) // no updates, completely disabled (red visibility)
else
var/dist = get_dist(src_object, user)
+ var/isTK = 0
- if (dist > 4)
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ isTK = H.dna.check_mutation(TK)
+
+ if (dist > 4 && !isTK)
close()
return
@@ -141,10 +146,10 @@ nanoui is used to open and update nano browser uis
else if (user.restrained() || user.lying)
set_status(STATUS_UPDATE, push_update) // update only (orange visibility)
else if (!(src_object in view(4, user))) // If the src object is not in visable, set status to 0
- set_status(STATUS_DISABLED, push_update) // interactive (green visibility)
+ set_status(STATUS_DISABLED, push_update) // no updates, completely disabled (red visibility)
else if (dist <= 1)
set_status(STATUS_INTERACTIVE, push_update) // interactive (green visibility)
- else if (dist <= 2)
+ else if (dist <= 2 || isTK)
set_status(STATUS_UPDATE, push_update) // update only (orange visibility)
else if (dist <= 4)
set_status(STATUS_DISABLED, push_update) // no updates, completely disabled (red visibility)
diff --git a/code/modules/ninja/energy_katana.dm b/code/modules/ninja/energy_katana.dm
index 5950d5c0f0c..14a871ddf22 100644
--- a/code/modules/ninja/energy_katana.dm
+++ b/code/modules/ninja/energy_katana.dm
@@ -6,6 +6,7 @@
item_state = "energy_katana"
force = 40
throwforce = 20
+ armour_penetration = 15
var/datum/effect/effect/system/spark_spread/spark_system
/obj/item/weapon/katana/energy/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
diff --git a/code/modules/ninja/suit/ninjaDrainAct.dm b/code/modules/ninja/suit/ninjaDrainAct.dm
index 71f729da249..bea7284744c 100644
--- a/code/modules/ninja/suit/ninjaDrainAct.dm
+++ b/code/modules/ninja/suit/ninjaDrainAct.dm
@@ -41,7 +41,7 @@ They *could* go in their appropriate files, but this is supposed to be modular
drain = S.cell.maxcharge - S.cell.charge
maxcapacity = 1//Reached maximum battery capacity.
- if (do_after(H,10))
+ if (do_after(H,10, target = src))
spark_system.start()
playsound(loc, "sparks", 50, 1)
cell.charge -= drain
@@ -84,7 +84,7 @@ They *could* go in their appropriate files, but this is supposed to be modular
drain = S.cell.maxcharge - S.cell.charge
maxcapacity = 1
- if (do_after(H,10))
+ if (do_after(H,10, target = src))
spark_system.start()
playsound(loc, "sparks", 50, 1)
charge -= drain
@@ -103,7 +103,7 @@ They *could* go in their appropriate files, but this is supposed to be modular
. = 0
if(charge)
- if(G.candrain && do_after(H,30))
+ if(G.candrain && do_after(H,30, target = src))
. = charge
if(S.cell.charge + charge > S.cell.maxcharge)
S.cell.charge = S.cell.maxcharge
@@ -130,7 +130,7 @@ They *could* go in their appropriate files, but this is supposed to be modular
if(files && files.known_tech.len)
for(var/datum/tech/current_data in S.stored_research)
H << "Checking \the [current_data.name] database."
- if(do_after(H, S.s_delay) && G.candrain && src)
+ if(do_after(H, S.s_delay, target = src) && G.candrain && src)
for(var/datum/tech/analyzing_data in files.known_tech)
if(current_data.id == analyzing_data.id)
if(analyzing_data.level > current_data.level)
@@ -161,7 +161,7 @@ They *could* go in their appropriate files, but this is supposed to be modular
if(files && files.known_tech.len)
for(var/datum/tech/current_data in S.stored_research)
H << "Checking \the [current_data.name] database."
- if(do_after(H, S.s_delay) && G.candrain && src)
+ if(do_after(H, S.s_delay, target = src) && G.candrain && src)
for(var/datum/tech/analyzing_data in files.known_tech)
if(current_data.id == analyzing_data.id)
if(analyzing_data.level > current_data.level)
@@ -189,7 +189,7 @@ They *could* go in their appropriate files, but this is supposed to be modular
while(G.candrain && !maxcapacity && src)
drain = (round((rand(G.mindrain, G.maxdrain))/2))
var/drained = 0
- if(PN && do_after(H,10))
+ if(PN && do_after(H,10, target = src))
drained = min(drain, PN.avail)
PN.load += drained
if(drained < drain)//if no power on net, drain apcs
@@ -229,7 +229,7 @@ They *could* go in their appropriate files, but this is supposed to be modular
if(S.cell.charge + drain > S.cell.maxcharge)
drain = S.cell.maxcharge - S.cell.charge
maxcapacity = 1
- if (do_after(H,10))
+ if (do_after(H,10, target = src))
spark_system.start()
playsound(loc, "sparks", 50, 1)
cell.use(drain)
diff --git a/code/modules/ninja/suit/suit_attackby.dm b/code/modules/ninja/suit/suit_attackby.dm
index a2683d39d8c..775143b8feb 100644
--- a/code/modules/ninja/suit/suit_attackby.dm
+++ b/code/modules/ninja/suit/suit_attackby.dm
@@ -23,7 +23,7 @@
var/obj/item/weapon/stock_parts/cell/CELL = I
if(CELL.maxcharge > cell.maxcharge && n_gloves && n_gloves.candrain)
U << "Higher maximum capacity detected.\nUpgrading..."
- if (n_gloves && n_gloves.candrain && do_after(U,s_delay))
+ if (n_gloves && n_gloves.candrain && do_after(U,s_delay, target = src))
U.drop_item()
CELL.loc = src
CELL.charge = min(CELL.charge+cell.charge, CELL.maxcharge)
@@ -43,7 +43,7 @@
var/obj/item/weapon/disk/tech_disk/TD = I
if(TD.stored)//If it has something on it.
U << "Research information detected, processing..."
- if(do_after(U,s_delay))
+ if(do_after(U,s_delay, target = src))
for(var/datum/tech/current_data in stored_research)
if(current_data.id==TD.stored.id)
if(current_data.levelPicking up a burning paper seems awfully stupid."
- return //Doesn't make any sense to pick up a burning paper
- else //Probably isn't necessary but it's safer
- ..()
-
-
/obj/item/weapon/paper/attack_ai(mob/living/silicon/ai/user)
var/dist
if(istype(user) && user.current) //is AI
@@ -278,7 +273,7 @@
/obj/item/weapon/paper/attackby(obj/item/weapon/P, mob/living/carbon/human/user, params)
..()
- if(burning)
+ if(burn_state == 1)
return
if(is_blind(user))
@@ -325,27 +320,21 @@
user.unEquip(src)
user.visible_message("[user] lights [src] ablaze with [P]!", "You light [src] on fire!")
- burn(0, 100)
+ fire_act()
add_fingerprint(user)
/obj/item/weapon/paper/fire_act()
- burn(1, 50)
-
-/obj/item/weapon/paper/proc/burn(var/showmsg, var/burntime)
- if (burning)
- return
- if(showmsg)
- src.visible_message("[src] catches on fire.")
- burning = 1
+ ..(0)
icon_state = "paper_onfire"
info = "[stars(info)]"
- spawn(burntime) //7 seconds
- src.visible_message("[src] burns away, leaving behind a pile of ashes.")
- new /obj/effect/decal/cleanable/ash(src.loc)
- qdel(src)
+
+
+/obj/item/weapon/paper/extinguish()
+ ..()
+ update_icon()
/*
* Premade paper
diff --git a/code/modules/paperwork/paperbin.dm b/code/modules/paperwork/paperbin.dm
index dd672a6d11c..568680b5d45 100644
--- a/code/modules/paperwork/paperbin.dm
+++ b/code/modules/paperwork/paperbin.dm
@@ -8,9 +8,20 @@
throw_speed = 3
throw_range = 7
pressure_resistance = 8
+ burn_state = 0 //Burnable
var/amount = 30 //How much paper is in the bin.
var/list/papers = new/list() //List of papers put in the bin for reference.
+/obj/item/weapon/paper_bin/fire_act()
+ if(!amount)
+ return
+ ..()
+
+/obj/item/weapon/paper_bin/burn()
+ amount = 0
+ extinguish()
+ update_icon()
+ return
/obj/item/weapon/paper_bin/MouseDrop(atom/over_object)
var/mob/M = usr
diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm
index d5efcbe8dd4..5ec959df34f 100644
--- a/code/modules/paperwork/pen.dm
+++ b/code/modules/paperwork/pen.dm
@@ -44,13 +44,14 @@
colour = "white"
-/obj/item/weapon/pen/attack(mob/living/M, mob/user)
+/obj/item/weapon/pen/attack(mob/living/M, mob/user,var/stealth)
if(!istype(M))
return
if(M.can_inject(user, 1))
user << "You stab [M] with the pen."
- M << "You feel a tiny prick!"
+ if(!stealth)
+ M << "You feel a tiny prick!"
. = 1
add_logs(user, M, "stabbed", object="[name]")
@@ -68,59 +69,12 @@
if(..())
if(reagents.total_volume)
if(M.reagents)
- reagents.trans_to(M, 55)
+ reagents.trans_to(M, reagents.total_volume)
/obj/item/weapon/pen/sleepy/New()
- create_reagents(55)
- reagents.add_reagent("morphine", 30)
+ create_reagents(45)
+ reagents.add_reagent("morphine", 20)
reagents.add_reagent("mutetoxin", 15)
reagents.add_reagent("tirizene", 10)
..()
-
-/*
- * Gang Boss Pens
- */
-/obj/item/weapon/pen/gang
- origin_tech = "materials=2;syndicate=5"
- var/cooldown
-
-/obj/item/weapon/pen/gang/attack(mob/living/M, mob/user)
- if(!istype(M)) return
- if(..())
- if(ishuman(M) && ishuman(user) && M.stat != DEAD)
- if(user.mind && ((user.mind in ticker.mode.A_bosses) || (user.mind in ticker.mode.B_bosses)))
- if(cooldown)
- user << "[src] needs more time to recharge before it can be used."
- return
- if(M.client)
- M.mind_initialize() //give them a mind datum if they don't have one.
- if(user.mind in ticker.mode.A_bosses)
- var/recruitable = ticker.mode.add_gangster(M.mind,"A")
- switch(recruitable)
- if(2)
- M.Paralyse(5)
- cooldown(max(0,ticker.mode.B_gang.len - ticker.mode.A_gang.len))
- if(1)
- user << "This mind has already been recruited by another gang!"
- else
- user << "This mind is resistant to recruitment!"
- else if(user.mind in ticker.mode.B_bosses)
- var/recruitable = ticker.mode.add_gangster(M.mind,"B")
- switch(recruitable)
- if(2)
- M.Paralyse(5)
- cooldown(max(0,ticker.mode.A_gang.len - ticker.mode.B_gang.len))
- if(1)
- user << "This mind has already been recruited by another gang!"
- else
- user << "This mind is resistant to recruitment!"
-
-/obj/item/weapon/pen/gang/proc/cooldown(modifier)
- cooldown = 1
- icon_state = "pen_blink"
- spawn(max(50,1200-(modifier*100)))
- cooldown = 0
- icon_state = "pen"
- var/mob/M = get(src, /mob)
- M << "\icon[src] [src][(src.loc == M)?(""):(" in your [src.loc]")] vibrates softly."
diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm
index 35e87edada7..ee16c94ee28 100644
--- a/code/modules/paperwork/photocopier.dm
+++ b/code/modules/paperwork/photocopier.dm
@@ -262,7 +262,7 @@
return
playsound(loc, 'sound/items/Ratchet.ogg', 50, 1)
user << "You start [anchored ? "unwrenching" : "wrenching"] [src]..."
- if(do_after(user, 20))
+ if(do_after(user, 20, target = src))
if(gc_destroyed)
return
user << "You [anchored ? "unwrench" : "wrench"] [src]."
@@ -309,7 +309,7 @@
else
user.visible_message("[user] starts putting [target] onto the photocopier!", "You start putting [target] onto the photocopier...")
- if(do_after(user, 20))
+ if(do_after(user, 20, target = src))
if(!target || target.gc_destroyed || gc_destroyed || !Adjacent(target)) //check if the photocopier/target still exists.
return
diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm
index 0832ab226f3..d8312036260 100644
--- a/code/modules/paperwork/photography.dm
+++ b/code/modules/paperwork/photography.dm
@@ -17,7 +17,7 @@
icon_state = "film"
item_state = "electropack"
w_class = 1.0
-
+ burn_state = 0 //Burnable
/*
* Photo
@@ -28,6 +28,8 @@
icon_state = "photo"
item_state = "paper"
w_class = 1.0
+ burn_state = 0 //Burnable
+ burntime = 5
var/icon/img //Big photo image
var/scribble //Scribble on the back.
var/blueprints = 0 //Does it include the blueprints?
@@ -92,7 +94,7 @@
icon_state = "album"
item_state = "briefcase"
can_hold = list(/obj/item/weapon/photo)
-
+ burn_state = 0 //Burnable
/*
* Camera
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index c57cd9b9875..51f6b311a84 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -381,7 +381,7 @@
return
playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1)
user << "You are trying to remove the power control board..." //lpeters - fixed grammar issues
- if(do_after(user, 50))
+ if(do_after(user, 50, target = src))
if (has_electronics==1)
has_electronics = 0
if ((stat & BROKEN) || malfhack)
@@ -476,7 +476,7 @@
user.visible_message("[user.name] adds cables to the APC frame.", \
"You start adding cables to the APC frame...")
playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
- if(do_after(user, 20))
+ if(do_after(user, 20, target = src))
if (C.amount >= 10 && !terminal && opened && has_electronics != 2)
var/turf/T = get_turf(src)
var/obj/structure/cable/N = T.get_cable_node()
@@ -496,7 +496,7 @@
user.visible_message("[user.name] inserts the power control board into [src].", \
"You start to insert the power control board into the frame...")
playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
- if(do_after(user, 10))
+ if(do_after(user, 10, target = src))
if(has_electronics==0)
has_electronics = 1
user << "You place the power control board inside the frame."
@@ -513,7 +513,7 @@
"You start welding the APC frame...", \
"You hear welding.")
playsound(src.loc, 'sound/items/Welder.ogg', 50, 1)
- if(do_after(user, 50))
+ if(do_after(user, 50, target = src))
if(!src || !WT.remove_fuel(3, user)) return
if (emagged || malfhack || (stat & BROKEN) || opened==2)
new /obj/item/stack/sheet/metal(loc)
@@ -542,7 +542,7 @@
return
user.visible_message("[user.name] replaces the damaged APC frame with a new one.",\
"You begin to replace the damaged APC frame...")
- if(do_after(user, 50))
+ if(do_after(user, 50, target = src))
user << "You replace the damaged APC frame with a new one."
qdel(W)
stat &= ~BROKEN
@@ -664,6 +664,9 @@
if(!user)
return
+ ui = SSnano.push_open_or_new_ui(user, src, ui_key, ui, "apc.tmpl", "[area.name] - APC", 520, user.has_unlimited_silicon_privilege ? 465 : 420, 1)
+
+/obj/machinery/power/apc/get_ui_data(mob/user)
var/list/data = list(
"locked" = locked,
"isOperating" = operating,
@@ -709,19 +712,7 @@
)
)
)
-
- // update the ui if it exists, returns null if no ui is passed/found
- ui = SSnano.try_update_ui(user, src, ui_key, ui, data)
- if (!ui)
- // the ui does not exist, so we'll create a new() one
- // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
- ui = new(user, src, ui_key, "apc.tmpl", "[area.name] - APC", 520, data["siliconUser"] ? 465 : 420)
- // when the ui is first opened this is the data it will use
- ui.set_initial_data(data)
- // open the new ui window
- ui.open()
- // auto update every Master Controller tick
- ui.set_auto_update(1)
+ return data
/obj/machinery/power/apc/proc/report()
return "[area.name] : [equipment]/[lighting]/[environ] ([lastused_equip+lastused_light+lastused_environ]) : [cell? cell.percent() : "N/C"] ([charging])"
diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm
index 3608dde2b80..c9784c27f94 100644
--- a/code/modules/power/lighting.dm
+++ b/code/modules/power/lighting.dm
@@ -42,7 +42,7 @@
playsound(src.loc, 'sound/machines/click.ogg', 75, 1)
var/constrdir = usr.dir
var/constrloc = usr.loc
- if (!do_after(usr, 30))
+ if (!do_after(usr, 30, target = src))
return
switch(fixture_type)
if("bulb")
@@ -100,7 +100,7 @@
if (src.stage == 1)
playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
usr << "You begin deconstructing [src]..."
- if (!do_after(usr, 30))
+ if (!do_after(usr, 30, target = src))
return
new /obj/item/stack/sheet/metal( get_turf(src.loc), sheets_refunded )
user.visible_message("[user.name] deconstructs [src].", \
diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm
index 1ab4c078d11..cfffc52cdd7 100644
--- a/code/modules/power/singularity/emitter.dm
+++ b/code/modules/power/singularity/emitter.dm
@@ -213,7 +213,7 @@
user.visible_message("[user.name] starts to weld the [src.name] to the floor.", \
"You start to weld \the [src] to the floor...", \
"You hear welding.")
- if (do_after(user,20))
+ if (do_after(user,20, target = src))
if(!src || !WT.isOn()) return
state = 2
user << "You weld \the [src] to the floor."
@@ -224,7 +224,7 @@
user.visible_message("[user.name] starts to cut the [src.name] free from the floor.", \
"You start to cut \the [src] free from the floor...", \
"You hear welding.")
- if (do_after(user,20))
+ if (do_after(user,20, target = src))
if(!src || !WT.isOn()) return
state = 1
user << "You cut \the [src] free from the floor."
diff --git a/code/modules/power/singularity/field_generator.dm b/code/modules/power/singularity/field_generator.dm
index 8cb5c1c626f..07943676729 100644
--- a/code/modules/power/singularity/field_generator.dm
+++ b/code/modules/power/singularity/field_generator.dm
@@ -129,7 +129,7 @@ field_generator power level display
user.visible_message("[user.name] starts to weld the [src.name] to the floor.", \
"You start to weld \the [src] to the floor...", \
"You hear welding.")
- if (do_after(user,20))
+ if (do_after(user,20, target = src))
if(!src || !WT.isOn()) return
state = 2
user << "You weld the field generator to the floor."
@@ -141,7 +141,7 @@ field_generator power level display
user.visible_message("[user.name] starts to cut the [src.name] free from the floor.", \
"You start to cut \the [src] free from the floor...", \
"You hear welding.")
- if (do_after(user,20))
+ if (do_after(user,20, target = src))
if(!src || !WT.isOn()) return
state = 1
user << "You cut \the [src] free from the floor."
diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm
index 9a30df83891..90c60fc5769 100644
--- a/code/modules/power/singularity/singularity.dm
+++ b/code/modules/power/singularity/singularity.dm
@@ -358,18 +358,13 @@
/obj/singularity/proc/toxmob()
var/toxrange = 10
- var/toxdamage = 4
var/radiation = 15
var/radiationmin = 3
- if (src.energy>200)
- toxdamage = round(((src.energy-150)/50)*4,1)
- radiation = round(((src.energy-150)/50)*5,1)
- radiationmin = round((radiation/5),1)//
+ if (energy>200)
+ radiation += round((energy-150)/10,1)
+ radiationmin = round((radiation/5),1)
for(var/mob/living/M in view(toxrange, src.loc))
M.irradiate(rand(radiationmin,radiation))
- toxdamage = (toxdamage - (toxdamage*M.getarmor(null, "rad")))
- M.apply_effect(toxdamage, TOX)
- return
/obj/singularity/proc/combust_mobs()
diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm
index e97f5462d7d..04f15cbdfec 100644
--- a/code/modules/power/smes.dm
+++ b/code/modules/power/smes.dm
@@ -135,7 +135,7 @@
user << "You start building the power terminal..."
playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
- if(do_after(user, 20) && C.amount >= 10)
+ if(do_after(user, 20, target = src) && C.amount >= 10)
var/obj/structure/cable/N = T.get_cable_node() //get the connecting node cable, if there's one
if (prob(50) && electrocute_mob(usr, N, N)) //animate the electrocution if uncautious and unlucky
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
@@ -326,6 +326,10 @@
if(!user)
return
+ // update the ui if it exists, create a new one if it doesn't
+ ui = SSnano.push_open_or_new_ui(user, src, ui_key, ui, "smes.tmpl", "SMES - [name]", 350, 560, 1)
+
+/obj/machinery/power/smes/get_ui_data()
var/list/data = list(
"capacityPercent" = round(100.0*charge/capacity, 0.1),
"capacity" = capacity,
@@ -343,19 +347,7 @@
"outputLevelMax" = output_level_max,
"outputUsed" = output_used
)
-
- // update the ui if it exists, returns null if no ui is passed/found
- ui = SSnano.try_update_ui(user, src, ui_key, ui, data)
- if (!ui)
- // the ui does not exist, so we'll create a new() one
- // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
- ui = new(user, src, ui_key, "smes.tmpl", "SMES - [name]", 350, 560)
- // when the ui is first opened this is the data it will use
- ui.set_initial_data(data)
- // open the new ui window
- ui.open()
- // auto update every Master Controller tick
- ui.set_auto_update(1)
+ return data
/obj/machinery/power/smes/Topic(href, href_list)
// world << "[href] ; [href_list[href]]"
diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm
index 38bf1d6c869..f85d5dcc655 100644
--- a/code/modules/power/solar.dm
+++ b/code/modules/power/solar.dm
@@ -60,7 +60,7 @@
if(istype(W, /obj/item/weapon/crowbar))
playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
user.visible_message("[user] begins to take the glass off the solar panel.", "You begin to take the glass off the solar panel...")
- if(do_after(user, 50))
+ if(do_after(user, 50, target = src))
var/obj/item/solar_assembly/S = locate() in src
if(S)
S.loc = src.loc
@@ -370,8 +370,10 @@
if(!..())
ui_interact(user)
-/obj/machinery/power/solar_control/ui_interact(mob/user, ui_key = "main")
+/obj/machinery/power/solar_control/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
+ ui = SSnano.push_open_or_new_ui(user, src, ui_key, ui, "solar_control.tmpl", name, 490, 420, 1)
+/obj/machinery/power/solar_control/get_ui_data()
var/data = list()
data["generated"] = round(lastgen)
@@ -384,21 +386,12 @@
data["connected_panels"] = connected_panels.len
data["connected_tracker"] = (connected_tracker ? 1 : 0)
-
- var/datum/nanoui/ui = SSnano.get_open_ui(user, src, ui_key)
- if (!ui)
- ui = new(user, src, ui_key, "solar_control.tmpl", name, 490, 420)
- ui.set_initial_data(data)
- ui.open()
- ui.set_auto_update(1)
- else
- ui.push_data(data)
- return
+ return data
/obj/machinery/power/solar_control/attackby(I as obj, user as mob, params)
if(istype(I, /obj/item/weapon/screwdriver))
playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
- if(do_after(user, 20))
+ if(do_after(user, 20, target = src))
if (src.stat & BROKEN)
user << "The broken glass falls out."
var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc )
diff --git a/code/modules/power/terminal.dm b/code/modules/power/terminal.dm
index 724de7a1b41..ded1f663392 100644
--- a/code/modules/power/terminal.dm
+++ b/code/modules/power/terminal.dm
@@ -60,7 +60,7 @@
"You begin to cut the cables...")
playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
- if(do_after(user, 50))
+ if(do_after(user, 50, target = src))
if(master && master.can_terminal_dismantle())
if(prob(50) && electrocute_mob(user, powernet, src))
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
diff --git a/code/modules/power/tracker.dm b/code/modules/power/tracker.dm
index 2ce74ae88dd..d39921f2699 100644
--- a/code/modules/power/tracker.dm
+++ b/code/modules/power/tracker.dm
@@ -63,7 +63,7 @@
if(istype(W, /obj/item/weapon/crowbar))
playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
user.visible_message("[user] begins to take the glass off the solar tracker.", "You begin to take the glass off the solar tracker...")
- if(do_after(user, 50))
+ if(do_after(user, 50, target = src))
var/obj/item/solar_assembly/S = locate() in src
if(S)
S.loc = src.loc
diff --git a/code/modules/projectiles/ammunition/energy.dm b/code/modules/projectiles/ammunition/energy.dm
index d170962a7ae..3518b4c35ab 100644
--- a/code/modules/projectiles/ammunition/energy.dm
+++ b/code/modules/projectiles/ammunition/energy.dm
@@ -154,3 +154,13 @@
/obj/item/ammo_casing/energy/bolt/large
projectile_type = /obj/item/projectile/energy/bolt/large
select_name = "heavy bolt"
+
+obj/item/ammo_casing/energy/net
+ projectile_type = /obj/item/projectile/energy/net
+ select_name = "netting"
+ pellets = 6
+ variance = 1
+
+/obj/item/ammo_casing/energy/trap
+ projectile_type = /obj/item/projectile/energy/trap
+ select_name = "snare"
\ No newline at end of file
diff --git a/code/modules/projectiles/guns/energy/nuclear.dm b/code/modules/projectiles/guns/energy/nuclear.dm
index aa1d4931ea4..6de08880434 100644
--- a/code/modules/projectiles/guns/energy/nuclear.dm
+++ b/code/modules/projectiles/guns/energy/nuclear.dm
@@ -19,6 +19,15 @@
force = 10
ammo_type = list(/obj/item/ammo_casing/energy/electrode/hos, /obj/item/ammo_casing/energy/laser/hos, /obj/item/ammo_casing/energy/disabler)
+/obj/item/weapon/gun/energy/gun/dragnet
+ name = "DRAGnet"
+ desc = "The \"Dynamic Rapid-Apprehension of the Guilty\" net is a revolution in law enforcement technology."
+ icon_state = "dragnet"
+ item_state = null
+ origin_tech = "combat=3;magnets=3;materials=4; bluespace=4"
+ ammo_type = list(/obj/item/ammo_casing/energy/net, /obj/item/ammo_casing/energy/trap)
+ can_flashlight = 0
+
/obj/item/weapon/gun/energy/gun/nuclear
name = "advanced energy gun"
desc = "An energy gun with an experimental miniaturized nuclear reactor that automatically charges the internal power cell."
@@ -127,4 +136,4 @@
trigger_guard = 0
/obj/item/weapon/gun/energy/gun/turret/update_icon()
- icon_state = initial(icon_state)
+ icon_state = initial(icon_state)
\ No newline at end of file
diff --git a/code/modules/projectiles/guns/projectile/revolver.dm b/code/modules/projectiles/guns/projectile/revolver.dm
index 9e1dc22e592..c31eedd7b5d 100644
--- a/code/modules/projectiles/guns/projectile/revolver.dm
+++ b/code/modules/projectiles/guns/projectile/revolver.dm
@@ -93,7 +93,7 @@
afterattack(user, user) //you know the drill
user.visible_message("[src] goes off!", "[src] goes off in your face!")
return
- if(do_after(user, 30))
+ if(do_after(user, 30, target = src))
if(magazine.ammo_count())
user << "You can't modify it!"
return
@@ -106,7 +106,7 @@
afterattack(user, user) //and again
user.visible_message("[src] goes off!", "[src] goes off in your face!")
return
- if(do_after(user, 30))
+ if(do_after(user, 30, target = src))
if(magazine.ammo_count())
user << "You can't modify it!"
return
diff --git a/code/modules/projectiles/guns/projectile/shotgun.dm b/code/modules/projectiles/guns/projectile/shotgun.dm
index 56a312e9c19..56fb14a3dd1 100644
--- a/code/modules/projectiles/guns/projectile/shotgun.dm
+++ b/code/modules/projectiles/guns/projectile/shotgun.dm
@@ -229,7 +229,7 @@
sawn_state = SAWN_SAWING
- if(do_after(user, 30))
+ if(do_after(user, 30, target = src))
user.visible_message("[user] shortens \the [src]!", "You shorten \the [src].")
name = "sawn-off [src.name]"
desc = sawn_desc
@@ -296,4 +296,4 @@
icon_state = "cshotgun"
origin_tech = "combat=5;materials=2"
mag_type = /obj/item/ammo_box/magazine/internal/shotcom
- w_class = 5
\ No newline at end of file
+ w_class = 5
diff --git a/code/modules/projectiles/projectile/energy.dm b/code/modules/projectiles/projectile/energy.dm
index ea3b048e13e..2cfe90da467 100644
--- a/code/modules/projectiles/projectile/energy.dm
+++ b/code/modules/projectiles/projectile/energy.dm
@@ -38,6 +38,78 @@
sparks.start()
..()
+/obj/item/projectile/energy/net
+ name = "energy netting"
+ icon_state = "e_netting"
+ damage = 10
+ damage_type = STAMINA
+ hitsound = 'sound/weapons/taserhit.ogg'
+ range = 10
+
+/obj/item/projectile/energy/net/New()
+ ..()
+ SpinAnimation()
+
+/obj/item/projectile/energy/net/on_hit(var/atom/target, var/blocked = 0)
+ if(isliving(target) && !locate(/obj/effect/nettingportal) in loc)
+ new/obj/effect/nettingportal(get_turf(target))
+ ..()
+
+/obj/item/projectile/energy/net/on_range()
+ var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread
+ sparks.set_up(1, 1, src)
+ sparks.start()
+ ..()
+
+/obj/effect/nettingportal
+ name = "DRAGnet teleportation field"
+ desc = "A field of bluespace energy, locking on to teleport a target."
+ icon = 'icons/effects/effects.dmi'
+ icon_state = "dragnetfield"
+ anchored = 1
+ unacidable = 1
+
+/obj/effect/nettingportal/New()
+ ..()
+ SetLuminosity(3)
+ var/obj/item/device/radio/beacon/teletarget = null
+ for(var/obj/machinery/computer/teleporter/com in machines)
+ if(com.target)
+ if(com.power_station && com.power_station.teleporter_hub && com.power_station.engaged)
+ teletarget = com.target
+ if(teletarget)
+ spawn(30)
+ for(var/mob/living/L in get_turf(src))
+ do_teleport(L, teletarget, 2)//teleport what's in the tile to the beacon
+ qdel(src)
+ else
+ spawn(30)
+ for(var/mob/living/L in get_turf(src))
+ do_teleport(L, L, 15) //Otherwise it just warps you off somewhere.
+ qdel(src)
+
+
+/obj/item/projectile/energy/trap
+ name = "energy snare"
+ icon_state = "e_snare"
+ nodamage = 1
+ weaken = 1
+ hitsound = 'sound/weapons/taserhit.ogg'
+ range = 4
+
+/obj/item/projectile/energy/trap/on_hit(var/atom/target, var/blocked = 0)
+ if(!ismob(target) || blocked >= 2) //Fully blocked by mob or collided with dense object - drop a trap
+ new/obj/item/weapon/restraints/legcuffs/beartrap/energy(get_turf(loc))
+ else if(iscarbon(target))
+ var/obj/item/weapon/restraints/legcuffs/beartrap/B = new /obj/item/weapon/restraints/legcuffs/beartrap/energy(get_turf(target))
+ B.Crossed(target)
+ ..()
+
+/obj/item/projectile/energy/trap/on_range()
+ new/obj/item/weapon/restraints/legcuffs/beartrap/energy(loc)
+ ..()
+
+
/obj/item/projectile/energy/declone
name = "radiation beam"
icon_state = "declone"
@@ -45,7 +117,6 @@
damage_type = CLONE
irradiate = 40
-
/obj/item/projectile/energy/dart //ninja throwing dart
name = "dart"
icon_state = "toxin"
diff --git a/code/modules/reagents/Chemistry-Machinery.dm b/code/modules/reagents/Chemistry-Machinery.dm
index 0fbb8ee12b3..5c79572d938 100644
--- a/code/modules/reagents/Chemistry-Machinery.dm
+++ b/code/modules/reagents/Chemistry-Machinery.dm
@@ -75,8 +75,10 @@
if(stat & (BROKEN)) return
if(user.stat || user.restrained()) return
- // this is the data which will be sent to the ui
- var/data[0]
+ ui = SSnano.push_open_or_new_ui(user, src, ui_key, ui, "chem_dispenser.tmpl", "[uiname]", 490, 710, 0)
+
+/obj/machinery/chem_dispenser/get_ui_data()
+ var/data = list()
data["amount"] = amount
data["energy"] = energy
data["maxEnergy"] = max_energy
@@ -103,17 +105,7 @@
if(temp)
chemicals.Add(list(list("title" = temp.name, "id" = temp.id, "commands" = list("dispense" = temp.id)))) // list in a list because Byond merges the first list...
data["chemicals"] = chemicals
-
- // update the ui if it exists, returns null if no ui is passed/found
- ui = SSnano.try_update_ui(user, src, ui_key, ui, data)
- if (!ui)
- // the ui does not exist, so we'll create a new() one
- // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
- ui = new(user, src, ui_key, "chem_dispenser.tmpl", "[uiname]", 490, 710)
- // when the ui is first opened this is the data it will use
- ui.set_initial_data(data)
- // open the new ui window
- ui.open()
+ return data
/obj/machinery/chem_dispenser/Topic(href, href_list)
if(stat & (BROKEN))
@@ -1510,7 +1502,10 @@
/obj/machinery/chem_heater/ui_interact(var/mob/user, ui_key = "main", var/datum/nanoui/ui = null)
if(user.stat || user.restrained()) return
- var/data[0]
+ ui = SSnano.push_open_or_new_ui(user, src, ui_key, ui, "chem_heater.tmpl", "ChemHeater", 350, 270, 0)
+
+/obj/machinery/chem_heater/get_ui_data()
+ var/data = list()
data["targetTemp"] = desired_temp
data["isActive"] = on
data["isBeakerLoaded"] = beaker ? 1 : 0
@@ -1525,13 +1520,7 @@
for(var/datum/reagent/R in beaker.reagents.reagent_list)
beakerContents.Add(list(list("name" = R.name, "volume" = R.volume))) // list in a list because Byond merges the first list...
data["beakerContents"] = beakerContents
-
- // update the ui if it exists, returns null if no ui is passed/found
- ui = SSnano.try_update_ui(user, src, ui_key, ui, data)
- if (!ui)
- ui = new(user, src, ui_key, "chem_heater.tmpl", "ChemHeater", 350, 270)
- ui.set_initial_data(data)
- ui.open()
+ return data
///////////////////////////////////////////////////////////////////////////
diff --git a/code/modules/reagents/Chemistry-Reagents/Consumable-Reagents/Food-Reagents.dm b/code/modules/reagents/Chemistry-Reagents/Consumable-Reagents/Food-Reagents.dm
index 7fd49928443..64ac0c3278b 100644
--- a/code/modules/reagents/Chemistry-Reagents/Consumable-Reagents/Food-Reagents.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Consumable-Reagents/Food-Reagents.dm
@@ -176,10 +176,10 @@
//monkeys and humans can have masks
if( victim.wear_mask )
- if ( victim.wear_mask.flags & MASKCOVERSEYES )
+ if ( victim.wear_mask.flags_cover & MASKCOVERSEYES )
eyes_covered = 1
safe_thing = victim.wear_mask
- if ( victim.wear_mask.flags & MASKCOVERSMOUTH )
+ if ( victim.wear_mask.flags_cover & MASKCOVERSMOUTH )
mouth_covered = 1
safe_thing = victim.wear_mask
@@ -187,10 +187,10 @@
if(istype(victim, /mob/living/carbon/human))
var/mob/living/carbon/human/H = victim
if( H.head )
- if ( H.head.flags & MASKCOVERSEYES )
+ if ( H.head.flags_cover & MASKCOVERSEYES )
eyes_covered = 1
safe_thing = H.head
- if ( H.head.flags & MASKCOVERSMOUTH )
+ if ( H.head.flags_cover & MASKCOVERSMOUTH )
mouth_covered = 1
safe_thing = H.head
if(H.glasses)
diff --git a/code/modules/reagents/Chemistry-Reagents/Medicine-Reagents.dm b/code/modules/reagents/Chemistry-Reagents/Medicine-Reagents.dm
index d53b85db81d..0637664da4d 100644
--- a/code/modules/reagents/Chemistry-Reagents/Medicine-Reagents.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Medicine-Reagents.dm
@@ -704,10 +704,10 @@
M.adjustToxLoss(-1*REM)
M.adjustBruteLoss(-1*REM)
M.adjustFireLoss(-1*REM)
- M.AdjustParalysis(-1)
- M.AdjustStunned(-1)
- M.AdjustWeakened(-1)
- M.adjustStaminaLoss(-1.5*REM)
+ M.AdjustParalysis(-3)
+ M.AdjustStunned(-3)
+ M.AdjustWeakened(-3)
+ M.adjustStaminaLoss(-5*REM)
..()
/datum/reagent/medicine/stimulants/overdose_process(var/mob/living/M as mob)
diff --git a/code/modules/reagents/Chemistry-Reagents/Other-Reagents.dm b/code/modules/reagents/Chemistry-Reagents/Other-Reagents.dm
index 270ddfdabb6..5a3f47db923 100644
--- a/code/modules/reagents/Chemistry-Reagents/Other-Reagents.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Other-Reagents.dm
@@ -144,6 +144,11 @@
/datum/reagent/water/reaction_obj(var/obj/O, var/volume)
src = null
+
+ if(istype(O,/obj/item))
+ var/obj/item/Item = O
+ Item.extinguish()
+
// Monkey cube
if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/monkeycube))
var/obj/item/weapon/reagent_containers/food/snacks/monkeycube/cube = O
@@ -151,7 +156,7 @@
cube.Expand()
// Dehydrated carp
- if(istype(O,/obj/item/toy/carpplushie/dehy_carp))
+ else if(istype(O,/obj/item/toy/carpplushie/dehy_carp))
var/obj/item/toy/carpplushie/dehy_carp/dehy = O
dehy.Swell() // Makes a carp
diff --git a/code/modules/reagents/Chemistry-Recipes/Slime_extracts.dm b/code/modules/reagents/Chemistry-Recipes/Slime_extracts.dm
index 7c26d80e4c2..996604a0822 100644
--- a/code/modules/reagents/Chemistry-Recipes/Slime_extracts.dm
+++ b/code/modules/reagents/Chemistry-Recipes/Slime_extracts.dm
@@ -502,11 +502,27 @@
notify_ghosts("Golem rune created in [get_area(Z)].", 'sound/effects/ghost2.ogg')
//Bluespace
+/datum/chemical_reaction/slimefloor2
+ name = "Bluespace Floor"
+ id = "m_floor2"
+ result = null
+ required_reagents = list("blood" = 1)
+ result_amount = 1
+ required_container = /obj/item/slime_extract/bluespace
+ required_other = 1
+
+/datum/chemical_reaction/slimefloor2/on_reaction(var/datum/reagents/holder, var/created_volume)
+ feedback_add_details("slime_cores_used","[replacetext(name," ","_")]")
+ var/obj/item/stack/tile/bluespace/P = new /obj/item/stack/tile/bluespace
+ P.amount = 25
+ P.loc = get_turf(holder.my_atom)
+
+
/datum/chemical_reaction/slimecrystal
name = "Slime Crystal"
id = "m_crystal"
result = null
- required_reagents = list("blood" = 1)
+ required_reagents = list("plasma" = 1)
result_amount = 1
required_container = /obj/item/slime_extract/bluespace
required_other = 1
@@ -555,7 +571,7 @@
name = "Slime Camera"
id = "m_camera"
result = null
- required_reagents = list("blood" = 1)
+ required_reagents = list("water" = 1)
result_amount = 1
required_container = /obj/item/slime_extract/sepia
required_other = 1
@@ -564,19 +580,22 @@
feedback_add_details("slime_cores_used","[replacetext(name," ","_")]")
var/obj/item/device/camera/P = new /obj/item/device/camera
P.loc = get_turf(holder.my_atom)
+ var/obj/item/device/camera_film/Z = new /obj/item/device/camera_film
+ Z.loc = get_turf(holder.my_atom)
-/datum/chemical_reaction/slimefilm
- name = "Slime Film"
- id = "m_film"
+/datum/chemical_reaction/slimefloor
+ name = "Sepia Floor"
+ id = "m_floor"
result = null
- required_reagents = list("water" = 1)
+ required_reagents = list("blood" = 1)
result_amount = 1
required_container = /obj/item/slime_extract/sepia
required_other = 1
-/datum/chemical_reaction/slimefilm/on_reaction(var/datum/reagents/holder)
+/datum/chemical_reaction/slimefloor/on_reaction(var/datum/reagents/holder)
feedback_add_details("slime_cores_used","[replacetext(name," ","_")]")
- var/obj/item/device/camera_film/P = new /obj/item/device/camera_film
+ var/obj/item/stack/tile/sepia/P = new /obj/item/stack/tile/sepia
+ P.amount = 25
P.loc = get_turf(holder.my_atom)
diff --git a/code/modules/reagents/reagent_containers/dropper.dm b/code/modules/reagents/reagent_containers/dropper.dm
index 8a8f5f1728b..f67392fab7d 100644
--- a/code/modules/reagents/reagent_containers/dropper.dm
+++ b/code/modules/reagents/reagent_containers/dropper.dm
@@ -2,7 +2,7 @@
name = "dropper"
desc = "A dropper. Holds up to 5 units."
icon = 'icons/obj/chemical.dmi'
- icon_state = "dropper0"
+ icon_state = "dropper"
amount_per_transfer_from_this = 5
possible_transfer_amounts = list(1, 2, 3, 4, 5)
volume = 5
@@ -28,10 +28,10 @@
var/obj/item/safe_thing = null
if(victim.wear_mask)
- if(victim.wear_mask.flags & MASKCOVERSEYES)
+ if(victim.wear_mask.flags_cover & MASKCOVERSEYES)
safe_thing = victim.wear_mask
if(victim.head)
- if(victim.head.flags & MASKCOVERSEYES)
+ if(victim.head.flags_cover & MASKCOVERSEYES)
safe_thing = victim.head
if(victim.glasses)
if(!safe_thing)
@@ -83,7 +83,8 @@
update_icon()
/obj/item/weapon/reagent_containers/dropper/update_icon()
- if(reagents.total_volume<=0)
- icon_state = "dropper0"
- else
- icon_state = "dropper1"
\ No newline at end of file
+ overlays.Cut()
+ if(reagents.total_volume)
+ var/image/filling = image('icons/obj/reagentfillings.dmi', src, "dropper")
+ filling.color = mix_color_from_reagents(reagents.reagent_list)
+ overlays += filling
\ No newline at end of file
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index 9d7988c289e..ad9c064c873 100644
--- a/code/modules/reagents/reagent_containers/syringes.dm
+++ b/code/modules/reagents/reagent_containers/syringes.dm
@@ -180,7 +180,7 @@
/obj/item/weapon/reagent_containers/syringe/update_icon()
- var/rounded_vol = round(reagents.total_volume,5)
+ var/rounded_vol = min(round(reagents.total_volume,5), 15)
overlays.Cut()
if(ismob(loc))
var/injoverlay
@@ -195,12 +195,7 @@
if(reagents.total_volume)
var/image/filling = image('icons/obj/reagentfillings.dmi', src, "syringe10")
-
- switch(rounded_vol)
- if(5) filling.icon_state = "syringe5"
- if(10) filling.icon_state = "syringe10"
- if(15) filling.icon_state = "syringe15"
-
+ filling.icon_state = "syringe[rounded_vol]"
filling.color = mix_color_from_reagents(reagents.reagent_list)
overlays += filling
diff --git a/code/modules/recycling/disposal-construction.dm b/code/modules/recycling/disposal-construction.dm
index bf75185292d..2576dcfc98c 100644
--- a/code/modules/recycling/disposal-construction.dm
+++ b/code/modules/recycling/disposal-construction.dm
@@ -223,7 +223,7 @@
if(W.remove_fuel(0,user))
playsound(loc, 'sound/items/Welder2.ogg', 100, 1)
user << "You start welding the [nicetype] in place..."
- if(do_after(user, 20))
+ if(do_after(user, 20, target = src))
if(!loc || !W.isOn())
return
user << "The [nicetype] has been welded in place."
diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm
index f1afbfe34ee..80035f45a33 100644
--- a/code/modules/recycling/disposal.dm
+++ b/code/modules/recycling/disposal.dm
@@ -100,7 +100,7 @@
playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1)
user << "You start slicing the floorweld off \the [src]..."
- if(do_after(user,20))
+ if(do_after(user,20, target = src))
if(!src || !W.isOn()) return
user << "You slice the floorweld off \the [src]."
Deconstruct()
@@ -847,7 +847,7 @@
playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1)
user << "You start slicing the disposal pipe..."
// check if anything changed over 2 seconds
- if(do_after(user,30))
+ if(do_after(user,30, target = src))
if(!src || !W.isOn()) return
Deconstruct()
user << "You slice the disposal pipe."
@@ -1151,7 +1151,7 @@
if(W.remove_fuel(0,user))
playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1)
user << "You start slicing the disposal pipe..."
- if(do_after(user,30))
+ if(do_after(user,30, target = src))
if(!src || !W.isOn()) return
Deconstruct()
user << "You slice the disposal pipe."
@@ -1285,7 +1285,7 @@
if(W.remove_fuel(0,user))
playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1)
user << "You start slicing the floorweld off \the [src]..."
- if(do_after(user,20))
+ if(do_after(user,20, target = src))
if(!src || !W.isOn()) return
user << "You slice the floorweld off \the [src]."
stored.loc = loc
@@ -1330,4 +1330,4 @@
else
dirs = alldirs.Copy()
- src.streak(dirs)
\ No newline at end of file
+ src.streak(dirs)
diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm
index f4495358aed..5225e5a4d48 100644
--- a/code/modules/recycling/sortingmachinery.dm
+++ b/code/modules/recycling/sortingmachinery.dm
@@ -117,6 +117,7 @@
flags = NOBLUDGEON
amount = 25
max_amount = 25
+ burn_state = 0 //burnable
/obj/item/stack/packageWrap/afterattack(var/obj/target as obj, mob/user as mob, proximity)
@@ -312,7 +313,7 @@
if(W.remove_fuel(0,user))
playsound(loc, 'sound/items/Welder2.ogg', 100, 1)
user << "You start slicing the floorweld off the delivery chute..."
- if(do_after(user,20))
+ if(do_after(user,20, target = src))
if(!src || !W.isOn()) return
Deconstruct()
user << "You slice the floorweld off the delivery chute."
diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm
index b8d71cc1dca..c397712a6b1 100644
--- a/code/modules/research/designs/medical_designs.dm
+++ b/code/modules/research/designs/medical_designs.dm
@@ -117,7 +117,7 @@
id = "ci-medhud"
req_tech = list("materials" = 6, "programming" = 4, "biotech" = 4)
build_type = PROTOLATHE | MECHFAB
- materials = list("$metal" = 200, "$glass" = 200, "$silver" = 200, "$gold" = 100)
+ materials = list("$metal" = 200, "$glass" = 200, "$silver" = 500, "$gold" = 500)
build_path = /obj/item/cybernetic_implant/eyes/hud/medical
category = list("Medical Designs")
@@ -127,7 +127,7 @@
id = "ci-sechud"
req_tech = list("materials" = 6, "programming" = 5, "biotech" = 4, "combat" = 2)
build_type = PROTOLATHE | MECHFAB
- materials = list("$metal" = 200, "$glass" = 200, "$silver" = 300, "$gold" = 300)
+ materials = list("$metal" = 200, "$glass" = 200, "$silver" = 750, "$gold" = 750)
build_path = /obj/item/cybernetic_implant/eyes/hud/security
category = list("Medical Designs")
@@ -135,9 +135,9 @@
name = "X-Ray implant"
desc = "These cybernetic eyes will give you X-ray vision. Blinking is futile."
id = "ci-xray"
- req_tech = list("materials" = 7, "programming" = 5, "biotech" = 6, "magnets" = 5, "plasmatech" = 3)
+ req_tech = list("materials" = 7, "programming" = 5, "biotech" = 6, "magnets" = 5)
build_type = PROTOLATHE | MECHFAB
- materials = list("$metal" = 200, "$glass" = 200, "$silver" = 200, "$gold" = 200, "$plasma" = 200, "$uranium" = 500, "$diamond" = 1000)
+ materials = list("$metal" = 200, "$glass" = 200, "$silver" = 600, "$gold" = 600, "$plasma" = 1000, "$uranium" = 1000, "$diamond" = 2000)
build_path = /obj/item/cybernetic_implant/eyes/xray
category = list("Medical Designs")
@@ -145,9 +145,9 @@
name = "Thermals implant"
desc = "These cybernetic eyes will give you Thermal vision. Vertical slit pupil included."
id = "ci-thermals"
- req_tech = list("materials" = 7, "programming" = 5, "biotech" = 5, "magnets" = 5, "plasmatech" = 3, "syndicate" = 4)
+ req_tech = list("materials" = 7, "programming" = 5, "biotech" = 5, "magnets" = 5, "syndicate" = 5)
build_type = PROTOLATHE | MECHFAB
- materials = list("$metal" = 200, "$glass" = 200, "$silver" = 200, "$gold" = 200, "$plasma" = 200, "$diamond" = 1000)
+ materials = list("$metal" = 200, "$glass" = 200, "$silver" = 600, "$gold" = 600, "$plasma" = 1000, "$diamond" = 2000)
build_path = /obj/item/cybernetic_implant/eyes/thermals
category = list("Medical Designs")
@@ -171,13 +171,14 @@
build_path = /obj/item/cybernetic_implant/brain/anti_stun
category = list("Medical Designs")
-/*/datum/design/cyberimp_nutriment
+/datum/design/cyberimp_nutriment
name = "Nutriment pump implant"
desc = "This implant with synthesize and pump into your bloodstream a small amount of nutriment when you are starving."
id = "ci-nutriment"
req_tech = list("materials" = 6, "programming" = 4, "biotech" = 5)
build_type = PROTOLATHE | MECHFAB
materials = list("$metal" = 200, "$glass" = 200, "$gold" = 500, "$uranium" = 500)
+ build_path = /obj/item/cybernetic_implant/chest/nutriment
category = list("Medical Designs")
/datum/design/cyberimp_nutriment_plus
@@ -187,4 +188,15 @@
req_tech = list("materials" = 6, "programming" = 4, "biotech" = 6)
build_type = PROTOLATHE | MECHFAB
materials = list("$metal" = 200, "$glass" = 200, "$gold" = 500, "$uranium" = 750)
- category = list("Medical Designs")*/
\ No newline at end of file
+ build_path = /obj/item/cybernetic_implant/chest/nutriment/plus
+ category = list("Medical Designs")
+
+/datum/design/cyberimp_reviver
+ name = "Reviver implant"
+ desc = "This implant will attempt to revive you if you lose consciousness. For the faint of heart!"
+ id = "ci-reviver"
+ req_tech = list("materials" = 6, "programming" = 4, "biotech" = 7, "syndicate" = 4)
+ build_type = PROTOLATHE | MECHFAB
+ materials = list("$metal" = 200, "$glass" = 200, "$gold" = 500, "$uranium" = 1000, "$diamond" = 2000)
+ build_path = /obj/item/cybernetic_implant/chest/reviver
+ category = list("Medical Designs")
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index fd4c133308f..19892b22d1e 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -472,3 +472,50 @@
qdel(src)
return
sleep(1)
+
+
+
+/obj/item/stack/tile/bluespace
+ name = "bluespace floor tile"
+ singular_name = "floor tile"
+ desc = "Through a series of micro-teleports these tiles let people move at incredible speeds"
+ icon_state = "tile-bluespace"
+ w_class = 3.0
+ force = 6.0
+ m_amt = 937.5
+ throwforce = 10.0
+ throw_speed = 3
+ throw_range = 7
+ flags = CONDUCT
+ max_amount = 60
+ turf_type = /turf/simulated/floor/bluespace
+
+
+/turf/simulated/floor/bluespace
+ slowdown = -1
+ icon_state = "bluespace"
+ desc = "Through a series of micro-teleports these tiles let people move at incredible speeds"
+ floor_tile = /obj/item/stack/tile/bluespace
+
+
+/obj/item/stack/tile/sepia
+ name = "sepia floor tile"
+ singular_name = "floor tile"
+ desc = "Time seems to flow very slowly around these tiles"
+ icon_state = "tile-sepia"
+ w_class = 3.0
+ force = 6.0
+ m_amt = 937.5
+ throwforce = 10.0
+ throw_speed = 3
+ throw_range = 7
+ flags = CONDUCT
+ max_amount = 60
+ turf_type = /turf/simulated/floor/sepia
+
+
+/turf/simulated/floor/sepia
+ slowdown = 2
+ icon_state = "sepia"
+ desc = "Time seems to flow very slowly around these tiles"
+ floor_tile = /obj/item/stack/tile/sepia
\ No newline at end of file
diff --git a/code/modules/scripting/Implementations/Telecomms.dm b/code/modules/scripting/Implementations/Telecomms.dm
index 62aac98be5e..75ae34bc050 100644
--- a/code/modules/scripting/Implementations/Telecomms.dm
+++ b/code/modules/scripting/Implementations/Telecomms.dm
@@ -308,7 +308,7 @@ var/const/SIGNAL_COOLDOWN = 20 // 2 seconds
ERROR("[src] has no radio.")
return
- if((!message || message == "") && message != 0)
+ if((!message) && message != 0)
message = "*beep*"
if(!source)
source = "[html_encode(uppertext(S.id))]"
diff --git a/code/modules/surgery/helpers.dm b/code/modules/surgery/helpers.dm
index 662a4304d3e..4982c6bcc64 100644
--- a/code/modules/surgery/helpers.dm
+++ b/code/modules/surgery/helpers.dm
@@ -80,13 +80,13 @@
for(var/obj/item/clothing/I in list(C.back, C.wear_mask, C.head))
covered_locations |= I.body_parts_covered
face_covered |= I.flags_inv
- eyesmouth_covered |= I.flags
+ eyesmouth_covered |= I.flags_cover
if(ishuman(C))
var/mob/living/carbon/human/H = C
for(var/obj/item/I in list(H.wear_suit, H.w_uniform, H.shoes, H.belt, H.gloves, H.glasses, H.ears))
covered_locations |= I.body_parts_covered
face_covered |= I.flags_inv
- eyesmouth_covered |= I.flags
+ eyesmouth_covered |= I.flags_cover
switch(location)
if("head")
diff --git a/code/modules/surgery/organs/cybernetic_implants.dm b/code/modules/surgery/organs/cybernetic_implants.dm
index 5a6d84c3019..7230c1d0572 100644
--- a/code/modules/surgery/organs/cybernetic_implants.dm
+++ b/code/modules/surgery/organs/cybernetic_implants.dm
@@ -75,7 +75,7 @@
desc = "These cybernetic eyes will give you X-ray vision. Blinking is futile."
eye_color = "000"
implant_color = "#000000"
- origin_tech = "materials=6;programming=4;biotech=5;magnets=5;plasmatech=2"
+ origin_tech = "materials=6;programming=4;biotech=6;magnets=5"
/obj/item/cybernetic_implant/eyes/xray/function()
if(!owner)
@@ -95,7 +95,7 @@
eye_color = "FC0"
implant_color = "#FFCC00"
flash_protect = -1
- origin_tech = "materials=6;programming=4;biotech=5;magnets=5;plasmatech=2;syndicate=4"
+ origin_tech = "materials=6;programming=4;biotech=5;magnets=5;syndicate=4"
/obj/item/cybernetic_implant/eyes/thermals/function()
if(!owner)
@@ -295,7 +295,7 @@
/obj/item/cybernetic_implant/chest/nutriment/plus
name = "Nutriment pump implant PLUS"
- desc = "This implant with synthesize and pump into your bloodstream a small amount of nutriment when you are hungry."
+ desc = "This implant will synthesize and pump into your bloodstream a small amount of nutriment when you are hungry."
icon_state = "chest_implant"
implant_color = "#006607"
hunger_threshold = NUTRITION_LEVEL_HUNGRY
@@ -307,4 +307,86 @@
if(!owner)
return
owner.reagents.add_reagent("????",poison_amount / severity) //food poisoning
- owner << "You feel like your insides are burning."
+ owner << "You feel like your insides are burning."
+
+
+/obj/item/cybernetic_implant/chest/reviver
+ name = "Reviver implant"
+ desc = "This implant will attempt to revive you if you lose consciousness. For the faint of heart!"
+ icon_state = "chest_implant"
+ implant_color = "#AD0000"
+ origin_tech = "materials=6;programming=3;biotech=6;syndicate=4"
+ var/revive_cost = 0
+ var/reviving = 0
+ var/cooldown = 0
+
+/obj/item/cybernetic_implant/chest/reviver/function()
+ SSobj.processing |= src
+
+/obj/item/cybernetic_implant/chest/reviver/process()
+ if(!owner)
+ SSobj.processing.Remove(src)
+ qdel(src)
+ return
+
+ if(reviving)
+ if(owner.stat == UNCONSCIOUS)
+ spawn(30)
+ if(prob(90) && owner.getOxyLoss())
+ owner.adjustOxyLoss(-3)
+ revive_cost += 5
+ if(prob(75) && owner.getBruteLoss())
+ owner.adjustBruteLoss(-1)
+ revive_cost += 20
+ if(prob(75) && owner.getFireLoss())
+ owner.adjustFireLoss(-1)
+ revive_cost += 20
+ if(prob(40) && owner.getToxLoss())
+ owner.adjustToxLoss(-1)
+ revive_cost += 50
+ else
+ cooldown = revive_cost + world.time
+ reviving = 0
+ return
+
+ if(cooldown > world.time)
+ return
+ if(owner.stat != UNCONSCIOUS)
+ return
+ if(owner.suiciding)
+ SSobj.processing.Remove(src)
+ return
+
+ revive_cost = 0
+ reviving = 1
+
+/obj/item/cybernetic_implant/chest/reviver/emp_act(severity)
+ if(reviving)
+ revive_cost += 200
+ else
+ cooldown += 200
+
+ if(prob(50 / severity))
+ owner.heart_attack = 1
+ spawn(600 / severity)
+ owner.heart_attack = 0
+
+
+//BOX O' IMPLANTS
+
+/obj/item/weapon/storage/box/cyber_implants
+ name = "boxed cybernetic implants"
+ desc = "A sleek, sturdy box."
+ icon_state = "cyber_implants"
+ var/list/boxed = list(/obj/item/cybernetic_implant/eyes/xray,/obj/item/cybernetic_implant/eyes/thermals,
+ /obj/item/cybernetic_implant/brain/anti_drop, /obj/item/cybernetic_implant/brain/anti_stun,
+ /obj/item/cybernetic_implant/chest/nutriment/plus, /obj/item/cybernetic_implant/chest/reviver)
+ var/amount = 5
+
+/obj/item/weapon/storage/box/cyber_implants/New()
+ ..()
+ var/i
+ var/implant
+ for(i = 0, i < amount, i++)
+ implant = pick(boxed)
+ new implant(src)
\ No newline at end of file
diff --git a/code/modules/surgery/surgery_step.dm b/code/modules/surgery/surgery_step.dm
index 76365b0790c..e630e7da48e 100644
--- a/code/modules/surgery/surgery_step.dm
+++ b/code/modules/surgery/surgery_step.dm
@@ -43,7 +43,7 @@
Handle_Multi_Loc(user, target)
preop(user, target, target_zone, tool)
- if(do_after(user, time))
+ if(do_after(user, time, target = target))
var/advance = 0
var/prob_chance = 100
@@ -77,9 +77,9 @@
return 1
/datum/surgery_step/saw/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- if(ishuman(target))
- var/mob/living/carbon/human/H = target
- H.apply_damage(75,"brute","[target_zone]")
+ if(ishuman(target) || ismonkey(target) || isalienadult(target))
+ var/mob/living/carbon/M = target
+ M.apply_damage(75,"brute","[target_zone]")
user.visible_message("[user] saws [target]'s [parse_zone(target_zone)] open!", "You saw [target]'s [parse_zone(target_zone)] open.")
feedback_add_details("surgery_step_success","[src.type]")
return 1
diff --git a/config/tips.txt b/config/tips.txt
index 04ea4ab50d0..ca03cc723d6 100644
--- a/config/tips.txt
+++ b/config/tips.txt
@@ -12,7 +12,7 @@ You can drag the icon of an equipped headset or PDA onto your screen to interact
The mime's invisible wall will block electrodes and other projectiles, but beams pass straight through it like windows.
The Library system is much more robust than most people think! Mess around with it, see if you can log who takes out the books for radio-reading.
Use a pair of handcuffs on a pair of orange shoes (standard prisoner issue) to chain them together.
-Revolutionaries brainwashed by Rev leaders can have their opinions swayed back to Nanotrasen loyalty by enough heavy objects to the head.
+Revolutionaries and gangsters can have their opinions swayed back to Nanotrasen loyalty by enough heavy objects to the head.
Husked corpses that have been drained of their genomes by a changeling also lack blood in their veins, unlike burned or space frozen corpses.
The stethoscope's utility extends beyond lung and heart check-ups. They can also be used to crack certain safes.
Chloral Hydrate can be counteracted by having coffee in your system!
@@ -43,6 +43,7 @@ Blobs are extremely powerful and are impossible to defeat alone. Communicate wit
You can fight blob pieces diagonally, as they can only expand onto adjacent tiles in cardinal directions.
Security huds and secglass huds can tell you if someone is implanted with a loyalty implant. Use this to your advantage in a revolution.
Loyalty implants can only prevent someone from being turned into a cultist: unlike revolutionaries, it will not de-cult them if they have already been converted.
+Loyalty implants can only prevent someone from being turned into a gangster: unlike revolutionaries, it will not de-gang them if they have already been recruited.
Don't neglect upgrading your machines with the machine parts produced by research! These can seriously improve the efficiency of your equipment.
Cyborgs are impervious to fires and temperature, and can walk in a blazing inferno without worry. Don't shy away from setting the whole station on fire as a malfunctioning or rogue AI!
The heads of staff, especially the Head of Security and the Captain, are usually extremely difficult to kill. If one of them is your target as a traitor, plan carefully.
@@ -88,3 +89,4 @@ In the job selection menu, from the lobby, you can use right click on the "Low/M
If you stay out of camera range for 10 seconds, the AI's track on you will break.
You can shoot cameras with bullets to disable them remotely.
Disabling a camera with wirecutters will not cause a camera alarm, but bludgeoning it will.
+Gangs derive their power from their presence. Cleaning up gang tags is the best way to prevent them from growing out of control.
diff --git a/html/changelog.html b/html/changelog.html
index d8584150d32..929ed44f31f 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -55,6 +55,147 @@
-->
+
26 June 2015
+
Ikarrus updated:
+
+
Added a couple of new gang tag resprites by Joan.
+
+
Kor updated:
+
+
Summon Guns has returned to its former glory. The spell will once again create antagonists, now with the objective to steal as many guns as possible.
+
Summon Guns once again costs a spell point, rather than granting one.
+
+
phil235 updated:
+
+
Buffs traitor stimpack (and adrenalin implant) to be more efficient against stuns/knockdowns.
+
+
pudl updated:
+
+
You can now play games of mastermind to unlock abandoned crates found throughout space.
+
+
+
25 June 2015
+
Iamgoofball updated:
+
+
Changes up how Explosive Implants work.
+
They have become Microbomb Implants. They cost 1 TC each. Each implant you inject increases the size of the explosion. You gib on usage, regardless of explosion size.
+
A Macrobomb implant was added for 20 TC. It is the equivalent of injecting 20 microbombs.
+
Nuke Ops start with microbomb implants again.
+
+
+
24 June 2015
+
Ikarrus updated:
+
+
Request Console message sent to major departments will now be broadcasted on that department's radio.
+
Request Consoles can be used to quicly declare a security, medical, or engineering emergency.
+
+
+
23 June 2015
+
Fayrik updated:
+
+
NanoUI is now Telekenesis aware, but due to other constraints, NanoUI interfaces are read only at a distance.
+
Refactored all NanoUI interfaces to use a more universal proc.
+
Adjusted the refresh time of the NanoUI SubSystem. All interfaces will update less, but register mouse clicks faster.
+
Removed automatic updates on atmospheric pumps, canisters and tanks, making them respond to button clicks much faster.
+
Atmos alarm reset buttons work now. Probably.
+
+
Iamgoofball updated:
+
+
Adds a progress bar when performing actions.
+
+
Ikarrus updated:
+
+
New gang names with tags created by Joan
+
C4 explosive can be purchased by gangs for 10 influence.
+
Recruitment pen cost increased to 50.
+
Lieutenants recieve one free recruitment pen.
+
Recruitment pens are now stealthy and no longer give a tiny prick message.
+
Increased chance of deconversion with head trauma
+
Recalling the shuttle now takes about a minute to work, during which you won't be able to use your gangtool.
+
Pinpointers no longer point at dominators. Instead, dominators will beep while active.
+
Added puffer jackets and vests.
+
Increased gang outfit armor. It is moderately resistant to bullets now.
+
Removed bulletproof vests from gangtool menu.
+
+
Jordie0608 updated:
+
+
Admins can now flag ckeys to be alerted when they connect to the server.
+
+
N3X15 updated:
+
+
Admins can now reject poor adminhelps. This will tell the player how to construct a useful adminhelp and give them back their adminhelp verb
+
+
RemieRichards updated:
+
+
Cumulative armour damage resistance is now capped at 90%, you will now always take at bare minimum, 10% of the incoming damage.
+
Added a system for Armour Penetration to items, it works by temporarily (It does NOT damage the armour or anything) reducing the armour values by the AP value during the attack instance.
+
The formula for AP is Armour-ArmourPenetration = AdjustedArmour and AdjustedArmour is used for all the remaining calculations instead of Armour (Eg: 80 Melee - 15 AP = 65 Melee).
+
The Ninja's Energy Katana has 15 AP, Xenomorphs have an inbuilt AP of 10.
+
You can now unwrench pipes who's internal pressures are greater than that of their environment...
+
However it will throw you away from the pipe at extreme speed! (You are warned beforehand if the pipe will do this, allowing you to cancel)
+
+
Vekter updated:
+
+
Finally fixed immovable rods! They will now properly bisect the station (and crit anyone unlucky enough to be in their path).
+
Increased Meteor activity detected in the vicinity of the station. Be advised that many storms may be more violent than they once were.
+
Gravitational anomalies will now throw items at mobs in their vicinity. Take care while scanning them.
+
Flux anomalies explode much more violently now. Get there and destroy them, or risk losing half a department.
+
+
xxalpha updated:
+
+
Added a new Reviver implant: now it revives you from unconsciousness rather than death.
+
Added cybernetic implants and a cybernetic implants bundle to the Nuke Ops uplink.
+
Fixed Nutriment pump implant printing.
+
Health Analyzers now have the ability to detect cybernetic implants.
+
X-Ray implants are now much harder to unlock.
+
+
+
22 June 2015
+
Iamgoofball updated:
+
+
Removed failure chance and delay when emagging an APC.
+
+
KorPhaeron updated:
+
+
Rebalanced armor to be less effective, reducing the melee, bullet and/or laser damage reduction of all armor suits.
+
+
LaharlMontogmmery updated:
+
+
You can now click and drag a storage container to empty it's contents into another container, disposal bin or floor tile.
+
+
Xhuis updated:
+
+
Revenants have received a considerable overhaul.
+
Revenants will no longer share spawn points with space carp and will spawn in locations like the morgue and prisoner transfer center.
+
Revenants can no longer cross tiles covered in holy water.
+
Revenants have a new ability called Defile for 30E. It will cause robots to malfunction, holy water over tiles to evaporate, and a few other effects.
+
Upon death, revenants will appear and play a sound before rapidly fading away and leaving behind glimmering residue as evidence of their demise.
+
This residue lingers with the essence of the revenant. If left unattended, it may reform into a new revenant. Simply scattering it is enough to stop this, but it also has high research levels.
+
Revenants now have fluff objectives as well as a set essence goal.
+
Revenanants will be revealed for longer when using abilities and also receive feedback on this revealing.
+
Revenants can now only spawn via random event with a specific amount of dead mobs on the station. The default for this is 10.
+
Revenants can no longer use abilities from inside walls.
+
Directly lethal abilities have been removed from revenants. In addition, they can no longer harvest unconscious people, only the dead.
+
+
+
21 June 2015
+
GunHog updated:
+
+
The Hostile Lockdown ability for Malfunctioning AIs has been nerfed. It now costs 30 CPU, is much more obvious, and automatically resets in 90 seconds.
+
Buffed the Upgrade Turrets Malfunction ability. Turrets will now fire heavy lasers instead of simply shooting faster.
+
Nanotrasen has released an Artificial Intelligence firmware upgrade under the ID 41ST0L3MYB1K3. It contains drivers for interacting with all variants of exosuit technology, from the Ripley APLU design to even experimental Phazon units. Simply upload your AI to the exosuit's internal computer via the InteliCard device. Per safety regulations, the exosuit must have maintenance protocols enabled in order to remove an AI from it.
+
Malfunctioning AIs may wirelessly steal mechs via a new power, Mech Domination. For 30 CPU, a Malf AI may permanently upload itself to a mech, ejecting any pilots. Malf AIs will still lose if they leave the Z-level, and the Malf will be gibbed if the mech is destroyed - they cannot be carded out of the mech or shunt to an APC.
+
+
Iamgoofball updated:
+
+
Blobs can no longer have Morphine as their chemical.
+
+
duncathan updated:
+
+
Heat exchangers now update their color to match that of the pipe connected to them.
+
Heat exchangers are on longer dense.
+
+
20 June 2015
Dorsisdwarf updated:
@@ -70,7 +211,7 @@
Gang tags are now named 'graffiti' to make them harder to detect
Initial takeover timer is now capped at 5 minutes (50% control)
Server Operators: The default Delta Alert texts have changed. Please check if your game_options.txt is up to date.
-
Loyalty implants now treat gangs as it treats cultis. Implants can no longer deconvert gangsters, but it can still prevent recruitments.
+
Loyalty implants now treat gangs as it treats cultists. Implants can no longer deconvert gangsters, but it can still prevent recruitments.
Replaced tommy guns with 9mm 2-burst 32 mag uzis that costs 40 influence. Unlike tommy guns gangs will be able to purchase ammo for uzis.
Jordie0608 updated:
@@ -134,7 +275,7 @@
spasticVerbalizer updated:
-
Drones can now properly quick-equip.
+
Drones can now properly quick-equip.
14 June 2015
diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml
index daf133ffbcb..c9ad089f910 100644
--- a/html/changelogs/.all_changelog.yml
+++ b/html/changelogs/.all_changelog.yml
@@ -2773,7 +2773,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- rscadd: The wizard has a new artefact related to said creature.
- rscadd: Added a new sepia slime plasma reaction. Try it out!
spasticVerbalizer:
- - rscfix: Drones can now properly quick-equip.
+ - bugfix: Drones can now properly quick-equip.
2015-06-18:
AnturK:
- rscadd: Added new photo-over-pda function. Apply the photo to PDA to send it with
@@ -2810,7 +2810,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- tweak: Initial takeover timer is now capped at 5 minutes (50% control)
- tweak: 'Server Operators: The default Delta Alert texts have changed. Please check
if your game_options.txt is up to date.'
- - rscdel: Loyalty implants now treat gangs as it treats cultis. Implants can no
+ - rscdel: Loyalty implants now treat gangs as it treats cultists. Implants can no
longer deconvert gangsters, but it can still prevent recruitments.
- tweak: Replaced tommy guns with 9mm 2-burst 32 mag uzis that costs 40 influence.
Unlike tommy guns gangs will be able to purchase ammo for uzis.
@@ -2838,3 +2838,146 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- rscadd: Back-worn cloaks have been added for all heads except the HoP. LARPers
rejoice!
- rscadd: More suicide messages have been added for a few items.
+2015-06-21:
+ GunHog:
+ - tweak: The Hostile Lockdown ability for Malfunctioning AIs has been nerfed. It
+ now costs 30 CPU, is much more obvious, and automatically resets in 90 seconds.
+ - tweak: Buffed the Upgrade Turrets Malfunction ability. Turrets will now fire heavy
+ lasers instead of simply shooting faster.
+ - rscadd: Nanotrasen has released an Artificial Intelligence firmware upgrade under
+ the ID 41ST0L3MYB1K3. It contains drivers for interacting with all variants
+ of exosuit technology, from the Ripley APLU design to even experimental Phazon
+ units. Simply upload your AI to the exosuit's internal computer via the InteliCard
+ device. Per safety regulations, the exosuit must have maintenance protocols
+ enabled in order to remove an AI from it.
+ - rscadd: Malfunctioning AIs may wirelessly steal mechs via a new power, Mech Domination.
+ For 30 CPU, a Malf AI may permanently upload itself to a mech, ejecting any
+ pilots. Malf AIs will still lose if they leave the Z-level, and the Malf will
+ be gibbed if the mech is destroyed - they cannot be carded out of the mech or
+ shunt to an APC.
+ Iamgoofball:
+ - rscdel: Blobs can no longer have Morphine as their chemical.
+ duncathan:
+ - tweak: Heat exchangers now update their color to match that of the pipe connected
+ to them.
+ - tweak: Heat exchangers are on longer dense.
+2015-06-22:
+ Iamgoofball:
+ - rscdel: Removed failure chance and delay when emagging an APC.
+ KorPhaeron:
+ - tweak: Rebalanced armor to be less effective, reducing the melee, bullet and/or
+ laser damage reduction of all armor suits.
+ LaharlMontogmmery:
+ - rscadd: You can now click and drag a storage container to empty it's contents
+ into another container, disposal bin or floor tile.
+ Xhuis:
+ - experiment: Revenants have received a considerable overhaul.
+ - rscadd: Revenants will no longer share spawn points with space carp and will spawn
+ in locations like the morgue and prisoner transfer center.
+ - rscadd: Revenants can no longer cross tiles covered in holy water.
+ - rscadd: Revenants have a new ability called Defile for 30E. It will cause robots
+ to malfunction, holy water over tiles to evaporate, and a few other effects.
+ - rscadd: Upon death, revenants will appear and play a sound before rapidly fading
+ away and leaving behind glimmering residue as evidence of their demise.
+ - rscadd: This residue lingers with the essence of the revenant. If left unattended,
+ it may reform into a new revenant. Simply scattering it is enough to stop this,
+ but it also has high research levels.
+ - rscadd: Revenants now have fluff objectives as well as a set essence goal.
+ - tweak: Revenanants will be revealed for longer when using abilities and also receive
+ feedback on this revealing.
+ - tweak: Revenants can now only spawn via random event with a specific amount of
+ dead mobs on the station. The default for this is 10.
+ - bugfix: Revenants can no longer use abilities from inside walls.
+ - rscdel: Directly lethal abilities have been removed from revenants. In addition,
+ they can no longer harvest unconscious people, only the dead.
+2015-06-23:
+ Fayrik:
+ - rscadd: NanoUI is now Telekenesis aware, but due to other constraints, NanoUI
+ interfaces are read only at a distance.
+ - tweak: Refactored all NanoUI interfaces to use a more universal proc.
+ - tweak: Adjusted the refresh time of the NanoUI SubSystem. All interfaces will
+ update less, but register mouse clicks faster.
+ - bugfix: Removed automatic updates on atmospheric pumps, canisters and tanks, making
+ them respond to button clicks much faster.
+ - bugfix: Atmos alarm reset buttons work now. Probably.
+ Iamgoofball:
+ - rscadd: Adds a progress bar when performing actions.
+ Ikarrus:
+ - rscadd: New gang names with tags created by Joan
+ - rscadd: C4 explosive can be purchased by gangs for 10 influence.
+ - tweak: Recruitment pen cost increased to 50.
+ - rscadd: Lieutenants recieve one free recruitment pen.
+ - tweak: Recruitment pens are now stealthy and no longer give a tiny prick message.
+ - tweak: Increased chance of deconversion with head trauma
+ - tweak: Recalling the shuttle now takes about a minute to work, during which you
+ won't be able to use your gangtool.
+ - rscadd: Pinpointers no longer point at dominators. Instead, dominators will beep
+ while active.
+ - rscadd: Added puffer jackets and vests.
+ - tweak: Increased gang outfit armor. It is moderately resistant to bullets now.
+ - rscdel: Removed bulletproof vests from gangtool menu.
+ Jordie0608:
+ - rscadd: Admins can now flag ckeys to be alerted when they connect to the server.
+ N3X15:
+ - rscadd: Admins can now reject poor adminhelps. This will tell the player how to
+ construct a useful adminhelp and give them back their adminhelp verb
+ RemieRichards:
+ - tweak: Cumulative armour damage resistance is now capped at 90%, you will now
+ always take at bare minimum, 10% of the incoming damage.
+ - rscadd: Added a system for Armour Penetration to items, it works by temporarily
+ (It does NOT damage the armour or anything) reducing the armour values by the
+ AP value during the attack instance.
+ - rscadd: 'The formula for AP is Armour-ArmourPenetration = AdjustedArmour and AdjustedArmour
+ is used for all the remaining calculations instead of Armour (Eg: 80 Melee -
+ 15 AP = 65 Melee).'
+ - rscadd: The Ninja's Energy Katana has 15 AP, Xenomorphs have an inbuilt AP of
+ 10.
+ - tweak: You can now unwrench pipes who's internal pressures are greater than that
+ of their environment...
+ - rscadd: However it will throw you away from the pipe at extreme speed! (You are
+ warned beforehand if the pipe will do this, allowing you to cancel)
+ Vekter:
+ - bugfix: Finally fixed immovable rods! They will now properly bisect the station
+ (and crit anyone unlucky enough to be in their path).
+ - tweak: Increased Meteor activity detected in the vicinity of the station. Be advised
+ that many storms may be more violent than they once were.
+ - rscadd: Gravitational anomalies will now throw items at mobs in their vicinity.
+ Take care while scanning them.
+ - rscadd: Flux anomalies explode much more violently now. Get there and destroy
+ them, or risk losing half a department.
+ xxalpha:
+ - rscadd: 'Added a new Reviver implant: now it revives you from unconsciousness
+ rather than death.'
+ - rscadd: Added cybernetic implants and a cybernetic implants bundle to the Nuke
+ Ops uplink.
+ - bugfix: Fixed Nutriment pump implant printing.
+ - tweak: Health Analyzers now have the ability to detect cybernetic implants.
+ - tweak: X-Ray implants are now much harder to unlock.
+2015-06-24:
+ Ikarrus:
+ - rscadd: Request Console message sent to major departments will now be broadcasted
+ on that department's radio.
+ - rscadd: Request Consoles can be used to quicly declare a security, medical, or
+ engineering emergency.
+2015-06-25:
+ Iamgoofball:
+ - rscadd: Changes up how Explosive Implants work.
+ - rscadd: They have become Microbomb Implants. They cost 1 TC each. Each implant
+ you inject increases the size of the explosion. You gib on usage, regardless
+ of explosion size.
+ - rscadd: A Macrobomb implant was added for 20 TC. It is the equivalent of injecting
+ 20 microbombs.
+ - rscadd: Nuke Ops start with microbomb implants again.
+2015-06-26:
+ Ikarrus:
+ - imageadd: Added a couple of new gang tag resprites by Joan.
+ Kor:
+ - tweak: Summon Guns has returned to its former glory. The spell will once again
+ create antagonists, now with the objective to steal as many guns as possible.
+ - tweak: Summon Guns once again costs a spell point, rather than granting one.
+ phil235:
+ - tweak: Buffs traitor stimpack (and adrenalin implant) to be more efficient against
+ stuns/knockdowns.
+ pudl:
+ - rscadd: You can now play games of mastermind to unlock abandoned crates found
+ throughout space.
diff --git a/html/changelogs/NullQuery-Nullstation.yml b/html/changelogs/NullQuery-Nullstation.yml
new file mode 100644
index 00000000000..981bb1c1d36
--- /dev/null
+++ b/html/changelogs/NullQuery-Nullstation.yml
@@ -0,0 +1,6 @@
+author: NullQuery
+delete-after: True
+
+changes:
+ - wip: "Introduces html_interface, a module to streamline the management of browser windows."
+ - rscadd: "Adds playing cards that utilize a new HTML window management system."
diff --git a/html/changelogs/Xhuis-RevenantUpdate.yml b/html/changelogs/Xhuis-RevenantUpdate.yml
deleted file mode 100644
index 40e8b2f58d0..00000000000
--- a/html/changelogs/Xhuis-RevenantUpdate.yml
+++ /dev/null
@@ -1,15 +0,0 @@
-author: Xhuis
-delete-after: True
-
-changes:
- - experimental: "Revenants have received a considerable overhaul."
- - rscadd: "Revenants will no longer share spawn points with space carp and will spawn in locations like the morgue and prisoner transfer center."
- - rscadd: "Revenants can no longer cross tiles covered in holy water."
- - rscadd: "Revenants have a new ability called Defile for 30E. It will cause robots to malfunction, holy water over tiles to evaporate, and a few other effects."
- - rscadd: "Upon death, revenants will appear and play a sound before rapidly fading away and leaving behind glimmering residue as evidence of their demise."
- - rscadd: " This residue lingers with the essence of the revenant. If left unattended, it may reform into a new revenant. Simply scattering it is enough to stop this, but it also has high research levels."
- - rscadd: "Revenants now have fluff objectives as well as a set essence goal."
- - tweak: "Revenanants will be revealed for longer when using abilities and also receive feedback on this revealing."
- - tweak: "Revenants can now only spawn via random event with a specific amount of dead mobs on the station. The default for this is 10."
- - bugfix: "Revenants can no longer use abilities from inside walls."
- - rscdel: "Directly lethal abilities have been removed from revenants. In addition, they can no longer harvest unconscious people, only the dead."
\ No newline at end of file
diff --git a/html/changelogs/Gun-Hog-PR9792.yml b/html/changelogs/ikarrus-shredme.yml
similarity index 54%
rename from html/changelogs/Gun-Hog-PR9792.yml
rename to html/changelogs/ikarrus-shredme.yml
index 7ceb4a1a306..8e01db13def 100644
--- a/html/changelogs/Gun-Hog-PR9792.yml
+++ b/html/changelogs/ikarrus-shredme.yml
@@ -22,7 +22,7 @@
#################################
# Your name.
-author: Gun Hog
+author: Ikarrus
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
delete-after: True
@@ -33,7 +33,5 @@ delete-after: True
# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit.
# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog.
changes:
- - tweak: "The Hostile Lockdown ability for Malfunctioning AIs has been nerfed. It now costs 30 CPU, is much more obvious, and automatically resets in 90 seconds."
- - tweak: "Buffed the Upgrade Turrets Malfunction ability. Turrets will now fire heavy lasers instead of simply shooting faster."
- - rscadd: "Nanotrasen has released an Artificial Intelligence firmware upgrade under the ID 41ST0L3MYB1K3. It contains drivers for interacting with all variants of exosuit technology, from the Ripley APLU design to even experimental Phazon units. Simply upload your AI to the exosuit's internal computer via the InteliCard device. Per safety regulations, the exosuit must have maintenance protocols enabled in order to remove an AI from it."
- - rscadd: "Malfunctioning AIs may wirelessly steal mechs via a new power, Mech Domination. For 30 CPU, a Malf AI may permanently upload itself to a mech, ejecting any pilots. Malf AIs will still lose if they leave the Z-level, and the Malf will be gibbed if the mech is destroyed - they cannot be carded out of the mech or shunt to an APC."
+ - rscadd: "Some objects can be burned now."
+ - rscadd: "Bombs will shred your clothes, with respect to their layering and armor values. Exterior clothing will shield clothing underneath. Storage items will drop their contents when bombed this way."
\ No newline at end of file
diff --git a/html/changelogs/duncathan-givinunarysomelovin.yml b/html/changelogs/vekter-10159.yml
similarity index 88%
rename from html/changelogs/duncathan-givinunarysomelovin.yml
rename to html/changelogs/vekter-10159.yml
index 0458e85cebe..f99d832a38c 100644
--- a/html/changelogs/duncathan-givinunarysomelovin.yml
+++ b/html/changelogs/vekter-10159.yml
@@ -22,7 +22,7 @@
#################################
# Your name.
-author: duncathan
+author: Vekter
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
delete-after: True
@@ -33,5 +33,4 @@ delete-after: True
# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit.
# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog.
changes:
- - tweak: "Heat exchangers now update their color to match that of the pipe connected to them."
- - tweak: "Heat exchangers are on longer dense."
+ - rscadd: "Added a new military jacket to the Autodrobe and ClothesMate."
diff --git a/icons/effects/crayondecal.dmi b/icons/effects/crayondecal.dmi
index 5525d3b1cbf..0225a6349b6 100644
Binary files a/icons/effects/crayondecal.dmi and b/icons/effects/crayondecal.dmi differ
diff --git a/icons/effects/doafter_icon.dmi b/icons/effects/doafter_icon.dmi
new file mode 100644
index 00000000000..0add263e976
Binary files /dev/null and b/icons/effects/doafter_icon.dmi differ
diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi
index 2e9d5216270..5102b40d59e 100644
Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ
diff --git a/icons/mob/hud.dmi b/icons/mob/hud.dmi
index a8e2032719a..a536f9f7919 100644
Binary files a/icons/mob/hud.dmi and b/icons/mob/hud.dmi differ
diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi
index 3b14ad7d0cb..fded89b9805 100644
Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ
diff --git a/icons/obj/chemical.dmi b/icons/obj/chemical.dmi
index 42e1b95b2c0..e44ddedfcd4 100644
Binary files a/icons/obj/chemical.dmi and b/icons/obj/chemical.dmi differ
diff --git a/icons/obj/cigarettes.dmi b/icons/obj/cigarettes.dmi
index 8a22d33423e..517f220f2ba 100644
Binary files a/icons/obj/cigarettes.dmi and b/icons/obj/cigarettes.dmi differ
diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi
index 647f1384e17..324c7d695b8 100644
Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ
diff --git a/icons/obj/dropper.dmi b/icons/obj/dropper.dmi
deleted file mode 100644
index 40fa42fafd3..00000000000
Binary files a/icons/obj/dropper.dmi and /dev/null differ
diff --git a/icons/obj/guns/energy.dmi b/icons/obj/guns/energy.dmi
index ff23c626c9f..09fa557ac1a 100644
Binary files a/icons/obj/guns/energy.dmi and b/icons/obj/guns/energy.dmi differ
diff --git a/icons/obj/items.dmi b/icons/obj/items.dmi
index fabc21f2d9e..194a21eecb6 100644
Binary files a/icons/obj/items.dmi and b/icons/obj/items.dmi differ
diff --git a/icons/obj/projectiles.dmi b/icons/obj/projectiles.dmi
index 52619ce1640..cc0325cdfae 100644
Binary files a/icons/obj/projectiles.dmi and b/icons/obj/projectiles.dmi differ
diff --git a/icons/obj/reagentfillings.dmi b/icons/obj/reagentfillings.dmi
index 594e646fa2d..52aea26c0cb 100644
Binary files a/icons/obj/reagentfillings.dmi and b/icons/obj/reagentfillings.dmi differ
diff --git a/icons/obj/structures.dmi b/icons/obj/structures.dmi
index f7d418e6fcb..1a7b8fb091c 100644
Binary files a/icons/obj/structures.dmi and b/icons/obj/structures.dmi differ
diff --git a/icons/obj/syringe.dmi b/icons/obj/syringe.dmi
index 52fefa673d1..d9be4abbce7 100644
Binary files a/icons/obj/syringe.dmi and b/icons/obj/syringe.dmi differ
diff --git a/icons/turf/floors.dmi b/icons/turf/floors.dmi
index 56c0c7d5afa..f988d836e36 100644
Binary files a/icons/turf/floors.dmi and b/icons/turf/floors.dmi differ
diff --git a/nano/templates/air_alarm.tmpl b/nano/templates/air_alarm.tmpl
index f3a64d9efd8..a5556180308 100644
--- a/nano/templates/air_alarm.tmpl
+++ b/nano/templates/air_alarm.tmpl
@@ -91,7 +91,7 @@ Used In File(s): \code\game\machinery\alarm.dm
{{if mode==3}}
{{:~link('PANIC SIPHON ACTIVE - Turn siphoning off', null, { 'mode' : 1}, null, 'redButton')}}
- {{else}}
+ {{else}}
{{:~link('ACTIVATE PANIC SIPHON IN AREA', null, { 'mode' : 3}, null, 'yellowButton')}}
{{/if}}
{{else screen == 2}}
diff --git a/sound/magic/TIMEPARADOX2.ogg b/sound/magic/TIMEPARADOX2.ogg
index d35aeb389f6..1a025a895b0 100644
Binary files a/sound/magic/TIMEPARADOX2.ogg and b/sound/magic/TIMEPARADOX2.ogg differ