mirror of
https://github.com/CHOMPstation/CHOMPstation.git
synced 2026-08-20 02:26:44 +01:00
Merge branch 'dev' of https://github.com/Baystation12/Baystation12 into miasma
This commit is contained in:
@@ -139,7 +139,9 @@ var/list/admin_verbs_debug = list(
|
||||
/client/proc/restart_controller,
|
||||
/client/proc/enable_debug_verbs,
|
||||
/client/proc/callproc,
|
||||
/client/proc/toggledebuglogs
|
||||
/client/proc/toggledebuglogs,
|
||||
/client/proc/SDQL_query,
|
||||
/client/proc/SDQL2_query
|
||||
)
|
||||
var/list/admin_verbs_possess = list(
|
||||
/proc/possess,
|
||||
|
||||
@@ -0,0 +1,497 @@
|
||||
|
||||
//Structured Datum Query Language. Basically SQL meets BYOND objects.
|
||||
|
||||
//Note: For use in BS12, need text_starts_with proc, and to modify the action on select to use BS12's object edit command(s).
|
||||
|
||||
/client/proc/SDQL_query(query_text as message)
|
||||
set category = "Admin"
|
||||
if(!check_rights(R_DEBUG)) //Shouldn't happen... but just to be safe.
|
||||
message_admins("\red ERROR: Non-admin [usr.key] attempted to execute a SDQL query!")
|
||||
log_admin("Non-admin [usr.key] attempted to execute a SDQL query!")
|
||||
|
||||
var/list/query_list = SDQL_tokenize(query_text)
|
||||
|
||||
if(query_list.len < 2)
|
||||
if(query_list.len > 0)
|
||||
usr << "\red SDQL: Too few discrete tokens in query \"[query_text]\". Please check your syntax and try again."
|
||||
return
|
||||
|
||||
if(!(lowertext(query_list[1]) in list("select", "delete", "update")))
|
||||
usr << "\red SDQL: Unknown query type: \"[query_list[1]]\" in query \"[query_text]\". Please check your syntax and try again."
|
||||
return
|
||||
|
||||
var/list/types = list()
|
||||
|
||||
var/i
|
||||
for(i = 2; i <= query_list.len; i += 2)
|
||||
types += query_list[i]
|
||||
|
||||
if(i + 1 >= query_list.len || query_list[i + 1] != ",")
|
||||
break
|
||||
|
||||
i++
|
||||
|
||||
var/list/from = list()
|
||||
|
||||
if(i <= query_list.len)
|
||||
if(lowertext(query_list[i]) in list("from", "in"))
|
||||
for(i++; i <= query_list.len; i += 2)
|
||||
from += query_list[i]
|
||||
|
||||
if(i + 1 >= query_list.len || query_list[i + 1] != ",")
|
||||
break
|
||||
|
||||
i++
|
||||
|
||||
if(from.len < 1)
|
||||
from += "world"
|
||||
|
||||
var/list/set_vars = list()
|
||||
|
||||
if(lowertext(query_list[1]) == "update")
|
||||
if(i <= query_list.len && lowertext(query_list[i]) == "set")
|
||||
for(i++; i <= query_list.len; i++)
|
||||
if(i + 2 <= query_list.len && query_list[i + 1] == "=")
|
||||
set_vars += query_list[i]
|
||||
set_vars[query_list[i]] = query_list[i + 2]
|
||||
|
||||
else
|
||||
usr << "\red SDQL: Invalid set parameter in query \"[query_text]\". Please check your syntax and try again."
|
||||
return
|
||||
|
||||
i += 3
|
||||
|
||||
if(i >= query_list.len || query_list[i] != ",")
|
||||
break
|
||||
|
||||
if(set_vars.len < 1)
|
||||
usr << "\red SDQL: Invalid or missing set in query \"[query_text]\". Please check your syntax and try again."
|
||||
return
|
||||
|
||||
var/list/where = list()
|
||||
|
||||
if(i <= query_list.len && lowertext(query_list[i]) == "where")
|
||||
where = query_list.Copy(i + 1)
|
||||
|
||||
var/list/from_objs = list()
|
||||
if("world" in from)
|
||||
from_objs += world
|
||||
else
|
||||
for(var/f in from)
|
||||
if(copytext(f, 1, 2) == "'" || copytext(f, 1, 2) == "\"")
|
||||
from_objs += locate(copytext(f, 2, length(f)))
|
||||
else if(copytext(f, 1, 2) != "/")
|
||||
from_objs += locate(f)
|
||||
else
|
||||
var/f2 = text2path(f)
|
||||
if(text_starts_with(f, "/mob"))
|
||||
for(var/mob/m in world)
|
||||
if(istype(m, f2))
|
||||
from_objs += m
|
||||
|
||||
else if(text_starts_with(f, "/turf/space"))
|
||||
for(var/turf/space/m in world)
|
||||
if(istype(m, f2))
|
||||
from_objs += m
|
||||
|
||||
else if(text_starts_with(f, "/turf/simulated"))
|
||||
for(var/turf/simulated/m in world)
|
||||
if(istype(m, f2))
|
||||
from_objs += m
|
||||
|
||||
else if(text_starts_with(f, "/turf/unsimulated"))
|
||||
for(var/turf/unsimulated/m in world)
|
||||
if(istype(m, f2))
|
||||
from_objs += m
|
||||
|
||||
else if(text_starts_with(f, "/turf"))
|
||||
for(var/turf/m in world)
|
||||
if(istype(m, f2))
|
||||
from_objs += m
|
||||
|
||||
else if(text_starts_with(f, "/area"))
|
||||
for(var/area/m in world)
|
||||
if(istype(m, f2))
|
||||
from_objs += m
|
||||
|
||||
else if(text_starts_with(f, "/obj/item"))
|
||||
for(var/obj/item/m in world)
|
||||
if(istype(m, f2))
|
||||
from_objs += m
|
||||
|
||||
else if(text_starts_with(f, "/obj/machinery"))
|
||||
for(var/obj/machinery/m in world)
|
||||
if(istype(m, f2))
|
||||
from_objs += m
|
||||
|
||||
else if(text_starts_with(f, "/obj"))
|
||||
for(var/obj/m in world)
|
||||
if(istype(m, f2))
|
||||
from_objs += m
|
||||
|
||||
else if(text_starts_with(f, "/atom"))
|
||||
for(var/atom/m in world)
|
||||
if(istype(m, f2))
|
||||
from_objs += m
|
||||
/*
|
||||
else
|
||||
for(var/datum/m in world)
|
||||
if(istype(m, f2))
|
||||
from_objs += m
|
||||
*/
|
||||
|
||||
var/list/objs = list()
|
||||
|
||||
for(var/from_obj in from_objs)
|
||||
if("*" in types)
|
||||
objs += from_obj:contents
|
||||
else
|
||||
for(var/f in types)
|
||||
if(copytext(f, 1, 2) == "'" || copytext(f, 1, 2) == "\"")
|
||||
objs += locate(copytext(f, 2, length(f))) in from_obj
|
||||
else if(copytext(f, 1, 2) != "/")
|
||||
objs += locate(f) in from_obj
|
||||
else
|
||||
var/f2 = text2path(f)
|
||||
if(text_starts_with(f, "/mob"))
|
||||
for(var/mob/m in from_obj)
|
||||
if(istype(m, f2))
|
||||
objs += m
|
||||
|
||||
else if(text_starts_with(f, "/turf/space"))
|
||||
for(var/turf/space/m in from_obj)
|
||||
if(istype(m, f2))
|
||||
objs += m
|
||||
|
||||
else if(text_starts_with(f, "/turf/simulated"))
|
||||
for(var/turf/simulated/m in from_obj)
|
||||
if(istype(m, f2))
|
||||
objs += m
|
||||
|
||||
else if(text_starts_with(f, "/turf/unsimulated"))
|
||||
for(var/turf/unsimulated/m in from_obj)
|
||||
if(istype(m, f2))
|
||||
objs += m
|
||||
|
||||
else if(text_starts_with(f, "/turf"))
|
||||
for(var/turf/m in from_obj)
|
||||
if(istype(m, f2))
|
||||
objs += m
|
||||
|
||||
else if(text_starts_with(f, "/area"))
|
||||
for(var/area/m in from_obj)
|
||||
if(istype(m, f2))
|
||||
objs += m
|
||||
|
||||
else if(text_starts_with(f, "/obj/item"))
|
||||
for(var/obj/item/m in from_obj)
|
||||
if(istype(m, f2))
|
||||
objs += m
|
||||
|
||||
else if(text_starts_with(f, "/obj/machinery"))
|
||||
for(var/obj/machinery/m in from_obj)
|
||||
if(istype(m, f2))
|
||||
objs += m
|
||||
|
||||
else if(text_starts_with(f, "/obj"))
|
||||
for(var/obj/m in from_obj)
|
||||
if(istype(m, f2))
|
||||
objs += m
|
||||
|
||||
else if(text_starts_with(f, "/atom"))
|
||||
for(var/atom/m in from_obj)
|
||||
if(istype(m, f2))
|
||||
objs += m
|
||||
|
||||
else
|
||||
for(var/datum/m in from_obj)
|
||||
if(istype(m, f2))
|
||||
objs += m
|
||||
|
||||
|
||||
for(var/datum/t in objs)
|
||||
var/currently_false = 0
|
||||
for(i = 1, i - 1 < where.len, i++)
|
||||
var/v = where[i++]
|
||||
var/compare_op = where[i++]
|
||||
if(!(compare_op in list("==", "=", "<>", "<", ">", "<=", ">=", "!=")))
|
||||
usr << "\red SDQL: Unknown comparison operator [compare_op] in where clause following [v] in query \"[query_text]\". Please check your syntax and try again."
|
||||
return
|
||||
|
||||
var/j
|
||||
for(j = i, j <= where.len, j++)
|
||||
if(lowertext(where[j]) in list("and", "or", ";"))
|
||||
break
|
||||
|
||||
if(!currently_false)
|
||||
var/value = SDQL_text2value(t, v)
|
||||
var/result = SDQL_evaluate(t, where.Copy(i, j))
|
||||
|
||||
switch(compare_op)
|
||||
if("=", "==")
|
||||
currently_false = !(value == result)
|
||||
|
||||
if("!=", "<>")
|
||||
currently_false = !(value != result)
|
||||
|
||||
if("<")
|
||||
currently_false = !(value < result)
|
||||
|
||||
if(">")
|
||||
currently_false = !(value > result)
|
||||
|
||||
if("<=")
|
||||
currently_false = !(value <= result)
|
||||
|
||||
if(">=")
|
||||
currently_false = !(value >= result)
|
||||
|
||||
|
||||
if(j > where.len || lowertext(where[j]) == ";")
|
||||
break
|
||||
else if(lowertext(where[j]) == "or")
|
||||
if(currently_false)
|
||||
currently_false = 0
|
||||
else
|
||||
break
|
||||
|
||||
i = j
|
||||
|
||||
if(currently_false)
|
||||
objs -= t
|
||||
|
||||
|
||||
|
||||
usr << "\blue SQDL Query: [query_text]"
|
||||
message_admins("[usr] executed SDQL query: \"[query_text]\".")
|
||||
/*
|
||||
for(var/t in types)
|
||||
usr << "Type: [t]"
|
||||
|
||||
for(var/t in from)
|
||||
usr << "From: [t]"
|
||||
|
||||
for(var/t in set_vars)
|
||||
usr << "Set: [t] = [set_vars[t]]"
|
||||
|
||||
if(where.len)
|
||||
var/where_str = ""
|
||||
for(var/t in where)
|
||||
where_str += "[t] "
|
||||
|
||||
usr << "Where: [where_str]"
|
||||
|
||||
usr << "From objects:"
|
||||
for(var/datum/t in from_objs)
|
||||
usr << t
|
||||
|
||||
usr << "Objects:"
|
||||
for(var/datum/t in objs)
|
||||
usr << t
|
||||
*/
|
||||
switch(lowertext(query_list[1]))
|
||||
if("delete")
|
||||
for(var/datum/t in objs)
|
||||
del t
|
||||
|
||||
if("update")
|
||||
for(var/datum/t in objs)
|
||||
objs[t] = list()
|
||||
for(var/v in set_vars)
|
||||
if(v in t.vars)
|
||||
objs[t][v] = SDQL_text2value(t, set_vars[v])
|
||||
|
||||
for(var/datum/t in objs)
|
||||
for(var/v in objs[t])
|
||||
t.vars[v] = objs[t][v]
|
||||
|
||||
if("select")
|
||||
var/text = ""
|
||||
for(var/datum/t in objs)
|
||||
if(istype(t, /atom))
|
||||
var/atom/a = t
|
||||
|
||||
if(a.x)
|
||||
text += "<a href='?src=\ref[t];SDQL_select=\ref[t]'>\ref[t]</a>: [t] at ([a.x], [a.y], [a.z])<br>"
|
||||
|
||||
else if(a.loc && a.loc.x)
|
||||
text += "<a href='?src=\ref[t];SDQL_select=\ref[t]'>\ref[t]</a>: [t] in [a.loc] at ([a.loc.x], [a.loc.y], [a.loc.z])<br>"
|
||||
|
||||
else
|
||||
text += "<a href='?src=\ref[t];SDQL_select=\ref[t]'>\ref[t]</a>: [t]<br>"
|
||||
|
||||
else
|
||||
text += "<a href='?src=\ref[t];SDQL_select=\ref[t]'>\ref[t]</a>: [t]<br>"
|
||||
|
||||
//text += "[t]<br>"
|
||||
usr << browse(text, "window=sdql_result")
|
||||
|
||||
|
||||
/client/Topic(href,href_list[],hsrc)
|
||||
if(href_list["SDQL_select"])
|
||||
debug_variables(locate(href_list["SDQL_select"]))
|
||||
|
||||
..()
|
||||
|
||||
|
||||
/proc/SDQL_evaluate(datum/object, list/equation)
|
||||
if(equation.len == 0)
|
||||
return null
|
||||
|
||||
else if(equation.len == 1)
|
||||
return SDQL_text2value(object, equation[1])
|
||||
|
||||
else if(equation[1] == "!")
|
||||
return !SDQL_evaluate(object, equation.Copy(2))
|
||||
|
||||
else if(equation[1] == "-")
|
||||
return -SDQL_evaluate(object, equation.Copy(2))
|
||||
|
||||
|
||||
else
|
||||
usr << "\red SDQL: Sorry, equations not yet supported :("
|
||||
return null
|
||||
|
||||
|
||||
/proc/SDQL_text2value(datum/object, text)
|
||||
if(text2num(text) != null)
|
||||
return text2num(text)
|
||||
else if(text == "null")
|
||||
return null
|
||||
else if(copytext(text, 1, 2) == "'" || copytext(text, 1, 2) == "\"" )
|
||||
return copytext(text, 2, length(text))
|
||||
else if(copytext(text, 1, 2) == "/")
|
||||
return text2path(text)
|
||||
else
|
||||
if(findtext(text, "."))
|
||||
var/split = findtext(text, ".")
|
||||
var/v = copytext(text, 1, split)
|
||||
|
||||
if((v in object.vars) && istype(object.vars[v], /datum))
|
||||
return SDQL_text2value(object.vars[v], copytext(text, split + 1))
|
||||
else
|
||||
return null
|
||||
|
||||
else
|
||||
if(text in object.vars)
|
||||
return object.vars[text]
|
||||
else
|
||||
return null
|
||||
|
||||
|
||||
/proc/text_starts_with(text, start)
|
||||
if(copytext(text, 1, length(start) + 1) == start)
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/proc/SDQL_tokenize(query_text)
|
||||
|
||||
var/list/whitespace = list(" ", "\n", "\t")
|
||||
var/list/single = list("(", ")", ",", "+", "-")
|
||||
var/list/multi = list(
|
||||
"=" = list("", "="),
|
||||
"<" = list("", "=", ">"),
|
||||
">" = list("", "="),
|
||||
"!" = list("", "="))
|
||||
|
||||
var/word = ""
|
||||
var/list/query_list = list()
|
||||
var/len = length(query_text)
|
||||
|
||||
for(var/i = 1, i <= len, i++)
|
||||
var/char = copytext(query_text, i, i + 1)
|
||||
|
||||
if(char in whitespace)
|
||||
if(word != "")
|
||||
query_list += word
|
||||
word = ""
|
||||
|
||||
else if(char in single)
|
||||
if(word != "")
|
||||
query_list += word
|
||||
word = ""
|
||||
|
||||
query_list += char
|
||||
|
||||
else if(char in multi)
|
||||
if(word != "")
|
||||
query_list += word
|
||||
word = ""
|
||||
|
||||
var/char2 = copytext(query_text, i + 1, i + 2)
|
||||
|
||||
if(char2 in multi[char])
|
||||
query_list += "[char][char2]"
|
||||
i++
|
||||
|
||||
else
|
||||
query_list += char
|
||||
|
||||
else if(char == "'")
|
||||
if(word != "")
|
||||
usr << "\red SDQL: You have an error in your SDQL syntax, unexpected ' in query: \"<font color=gray>[query_text]</font>\" following \"<font color=gray>[word]</font>\". Please check your syntax, and try again."
|
||||
return null
|
||||
|
||||
word = "'"
|
||||
|
||||
for(i++, i <= len, i++)
|
||||
char = copytext(query_text, i, i + 1)
|
||||
|
||||
if(char == "'")
|
||||
if(copytext(query_text, i + 1, i + 2) == "'")
|
||||
word += "'"
|
||||
i++
|
||||
|
||||
else
|
||||
break
|
||||
|
||||
else
|
||||
word += char
|
||||
|
||||
if(i > len)
|
||||
usr << "\red SDQL: You have an error in your SDQL syntax, unmatched ' in query: \"<font color=gray>[query_text]</font>\". Please check your syntax, and try again."
|
||||
return null
|
||||
|
||||
query_list += "[word]'"
|
||||
word = ""
|
||||
|
||||
else if(char == "\"")
|
||||
if(word != "")
|
||||
usr << "\red SDQL: You have an error in your SDQL syntax, unexpected \" in query: \"<font color=gray>[query_text]</font>\" following \"<font color=gray>[word]</font>\". Please check your syntax, and try again."
|
||||
return null
|
||||
|
||||
word = "\""
|
||||
|
||||
for(i++, i <= len, i++)
|
||||
char = copytext(query_text, i, i + 1)
|
||||
|
||||
if(char == "\"")
|
||||
if(copytext(query_text, i + 1, i + 2) == "'")
|
||||
word += "\""
|
||||
i++
|
||||
|
||||
else
|
||||
break
|
||||
|
||||
else
|
||||
word += char
|
||||
|
||||
if(i > len)
|
||||
usr << "\red SDQL: You have an error in your SDQL syntax, unmatched \" in query: \"<font color=gray>[query_text]</font>\". Please check your syntax, and try again."
|
||||
return null
|
||||
|
||||
query_list += "[word]\""
|
||||
word = ""
|
||||
|
||||
else
|
||||
word += char
|
||||
|
||||
if(word != "")
|
||||
query_list += word
|
||||
|
||||
return query_list
|
||||
@@ -0,0 +1,426 @@
|
||||
|
||||
|
||||
/client/proc/SDQL2_query(query_text as message)
|
||||
set category = "Admin"
|
||||
if(!check_rights(R_DEBUG)) //Shouldn't happen... but just to be safe.
|
||||
message_admins("\red ERROR: Non-admin [usr.key] attempted to execute a SDQL query!")
|
||||
log_admin("Non-admin [usr.key] attempted to execute a SDQL query!")
|
||||
|
||||
if(!query_text || length(query_text) < 1)
|
||||
return
|
||||
|
||||
//world << query_text
|
||||
|
||||
var/list/query_list = SDQL2_tokenize(query_text)
|
||||
|
||||
if(!query_list || query_list.len < 1)
|
||||
return
|
||||
|
||||
var/list/query_tree = SDQL_parse(query_list)
|
||||
|
||||
if(query_tree.len < 1)
|
||||
return
|
||||
|
||||
var/list/from_objs = list()
|
||||
var/list/select_types = list()
|
||||
|
||||
switch(query_tree[1])
|
||||
if("explain")
|
||||
SDQL_testout(query_tree["explain"])
|
||||
return
|
||||
|
||||
if("call")
|
||||
if("on" in query_tree)
|
||||
select_types = query_tree["on"]
|
||||
else
|
||||
return
|
||||
|
||||
if("select", "delete", "update")
|
||||
select_types = query_tree[query_tree[1]]
|
||||
|
||||
from_objs = SDQL_from_objs(query_tree["from"])
|
||||
|
||||
var/list/objs = list()
|
||||
|
||||
for(var/type in select_types)
|
||||
var/char = copytext(type, 1, 2)
|
||||
|
||||
if(char == "/" || char == "*")
|
||||
for(var/from in from_objs)
|
||||
objs += SDQL_get_all(type, from)
|
||||
|
||||
else if(char == "'" || char == "\"")
|
||||
objs += locate(copytext(type, 2, length(type)))
|
||||
|
||||
if("where" in query_tree)
|
||||
var/objs_temp = objs
|
||||
objs = list()
|
||||
for(var/datum/d in objs_temp)
|
||||
if(SDQL_expression(d, query_tree["where"]))
|
||||
objs += d
|
||||
|
||||
//usr << "Query: [query_text]"
|
||||
message_admins("[usr] executed SDQL query: \"[query_text]\".")
|
||||
|
||||
switch(query_tree[1])
|
||||
if("delete")
|
||||
for(var/datum/d in objs)
|
||||
del d
|
||||
|
||||
if("select")
|
||||
var/text = ""
|
||||
for(var/datum/t in objs)
|
||||
if(istype(t, /atom))
|
||||
var/atom/a = t
|
||||
|
||||
if(a.x)
|
||||
text += "<a href='?src=\ref[t];SDQL_select=\ref[t]'>\ref[t]</a>: [t] at ([a.x], [a.y], [a.z])<br>"
|
||||
|
||||
else if(a.loc && a.loc.x)
|
||||
text += "<a href='?src=\ref[t];SDQL_select=\ref[t]'>\ref[t]</a>: [t] in [a.loc] at ([a.loc.x], [a.loc.y], [a.loc.z])<br>"
|
||||
|
||||
else
|
||||
text += "<a href='?src=\ref[t];SDQL_select=\ref[t]'>\ref[t]</a>: [t]<br>"
|
||||
|
||||
else
|
||||
text += "<a href='?src=\ref[t];SDQL_select=\ref[t]'>\ref[t]</a>: [t]<br>"
|
||||
|
||||
usr << browse(text, "window=SDQL-result")
|
||||
|
||||
if("update")
|
||||
if("set" in query_tree)
|
||||
var/list/set_list = query_tree["set"]
|
||||
for(var/datum/d in objs)
|
||||
var/list/vals = list()
|
||||
for(var/v in set_list)
|
||||
if(v in d.vars)
|
||||
vals += v
|
||||
vals[v] = SDQL_expression(d, set_list[v])
|
||||
|
||||
if(istype(d, /turf))
|
||||
for(var/v in vals)
|
||||
if(v == "x" || v == "y" || v == "z")
|
||||
continue
|
||||
|
||||
d.vars[v] = vals[v]
|
||||
|
||||
else
|
||||
for(var/v in vals)
|
||||
d.vars[v] = vals[v]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/proc/SDQL_parse(list/query_list)
|
||||
var/datum/SDQL_parser/parser = new(query_list)
|
||||
var/list/query_tree = parser.parse()
|
||||
|
||||
del(parser)
|
||||
|
||||
return query_tree
|
||||
|
||||
|
||||
|
||||
/proc/SDQL_testout(list/query_tree, indent = 0)
|
||||
var/spaces = ""
|
||||
for(var/s = 0, s < indent, s++)
|
||||
spaces += " "
|
||||
|
||||
for(var/item in query_tree)
|
||||
if(istype(item, /list))
|
||||
world << "[spaces]("
|
||||
SDQL_testout(item, indent + 1)
|
||||
world << "[spaces])"
|
||||
|
||||
else
|
||||
world << "[spaces][item]"
|
||||
|
||||
if(!isnum(item) && query_tree[item])
|
||||
|
||||
if(istype(query_tree[item], /list))
|
||||
world << "[spaces] ("
|
||||
SDQL_testout(query_tree[item], indent + 2)
|
||||
world << "[spaces] )"
|
||||
|
||||
else
|
||||
world << "[spaces] [query_tree[item]]"
|
||||
|
||||
|
||||
|
||||
/proc/SDQL_from_objs(list/tree)
|
||||
if("world" in tree)
|
||||
return list(world)
|
||||
|
||||
var/list/out = list()
|
||||
|
||||
for(var/type in tree)
|
||||
var/char = copytext(type, 1, 2)
|
||||
|
||||
if(char == "/")
|
||||
out += SDQL_get_all(type, world)
|
||||
|
||||
else if(char == "'" || char == "\"")
|
||||
out += locate(copytext(type, 2, length(type)))
|
||||
|
||||
return out
|
||||
|
||||
|
||||
/proc/SDQL_get_all(type, location)
|
||||
var/list/out = list()
|
||||
|
||||
if(type == "*")
|
||||
for(var/datum/d in location)
|
||||
out += d
|
||||
|
||||
return out
|
||||
|
||||
type = text2path(type)
|
||||
|
||||
if(ispath(type, /mob))
|
||||
for(var/mob/d in location)
|
||||
if(istype(d, type))
|
||||
out += d
|
||||
|
||||
else if(ispath(type, /turf))
|
||||
for(var/turf/d in location)
|
||||
if(istype(d, type))
|
||||
out += d
|
||||
|
||||
else if(ispath(type, /obj))
|
||||
for(var/obj/d in location)
|
||||
if(istype(d, type))
|
||||
out += d
|
||||
|
||||
else if(ispath(type, /area))
|
||||
for(var/area/d in location)
|
||||
if(istype(d, type))
|
||||
out += d
|
||||
|
||||
else if(ispath(type, /atom))
|
||||
for(var/atom/d in location)
|
||||
if(istype(d, type))
|
||||
out += d
|
||||
|
||||
else
|
||||
for(var/datum/d in location)
|
||||
if(istype(d, type))
|
||||
out += d
|
||||
|
||||
return out
|
||||
|
||||
|
||||
/proc/SDQL_expression(datum/object, list/expression, start = 1)
|
||||
var/result = 0
|
||||
var/val
|
||||
|
||||
for(var/i = start, i <= expression.len, i++)
|
||||
var/op = ""
|
||||
|
||||
if(i > start)
|
||||
op = expression[i]
|
||||
i++
|
||||
|
||||
var/list/ret = SDQL_value(object, expression, i)
|
||||
val = ret["val"]
|
||||
i = ret["i"]
|
||||
|
||||
if(op != "")
|
||||
switch(op)
|
||||
if("+")
|
||||
result += val
|
||||
if("-")
|
||||
result -= val
|
||||
if("*")
|
||||
result *= val
|
||||
if("/")
|
||||
result /= val
|
||||
if("&")
|
||||
result &= val
|
||||
if("|")
|
||||
result |= val
|
||||
if("^")
|
||||
result ^= val
|
||||
if("=", "==")
|
||||
result = (result == val)
|
||||
if("!=", "<>")
|
||||
result = (result != val)
|
||||
if("<")
|
||||
result = (result < val)
|
||||
if("<=")
|
||||
result = (result <= val)
|
||||
if(">")
|
||||
result = (result > val)
|
||||
if(">=")
|
||||
result = (result >= val)
|
||||
if("and", "&&")
|
||||
result = (result && val)
|
||||
if("or", "||")
|
||||
result = (result || val)
|
||||
else
|
||||
usr << "\red SDQL2: Unknown op [op]"
|
||||
result = null
|
||||
else
|
||||
result = val
|
||||
|
||||
return result
|
||||
|
||||
/proc/SDQL_value(datum/object, list/expression, start = 1)
|
||||
var/i = start
|
||||
var/val = null
|
||||
|
||||
if(i > expression.len)
|
||||
return list("val" = null, "i" = i)
|
||||
|
||||
if(istype(expression[i], /list))
|
||||
val = SDQL_expression(object, expression[i])
|
||||
|
||||
else if(expression[i] == "!")
|
||||
var/list/ret = SDQL_value(object, expression, i + 1)
|
||||
val = !ret["val"]
|
||||
i = ret["i"]
|
||||
|
||||
else if(expression[i] == "~")
|
||||
var/list/ret = SDQL_value(object, expression, i + 1)
|
||||
val = ~ret["val"]
|
||||
i = ret["i"]
|
||||
|
||||
else if(expression[i] == "-")
|
||||
var/list/ret = SDQL_value(object, expression, i + 1)
|
||||
val = -ret["val"]
|
||||
i = ret["i"]
|
||||
|
||||
else if(expression[i] == "null")
|
||||
val = null
|
||||
|
||||
else if(isnum(expression[i]))
|
||||
val = expression[i]
|
||||
|
||||
else if(copytext(expression[i], 1, 2) in list("'", "\""))
|
||||
val = copytext(expression[i], 2, length(expression[i]))
|
||||
|
||||
else
|
||||
val = SDQL_var(object, expression, i)
|
||||
i = expression.len
|
||||
|
||||
return list("val" = val, "i" = i)
|
||||
|
||||
/proc/SDQL_var(datum/object, list/expression, start = 1)
|
||||
|
||||
if(expression[start] in object.vars)
|
||||
|
||||
if(start < expression.len && expression[start + 1] == ".")
|
||||
return SDQL_var(object.vars[expression[start]], expression[start + 2])
|
||||
|
||||
else
|
||||
return object.vars[expression[start]]
|
||||
|
||||
else
|
||||
return null
|
||||
|
||||
/proc/SDQL2_tokenize(query_text)
|
||||
|
||||
var/list/whitespace = list(" ", "\n", "\t")
|
||||
var/list/single = list("(", ")", ",", "+", "-", ".")
|
||||
var/list/multi = list(
|
||||
"=" = list("", "="),
|
||||
"<" = list("", "=", ">"),
|
||||
">" = list("", "="),
|
||||
"!" = list("", "="))
|
||||
|
||||
var/word = ""
|
||||
var/list/query_list = list()
|
||||
var/len = length(query_text)
|
||||
|
||||
for(var/i = 1, i <= len, i++)
|
||||
var/char = copytext(query_text, i, i + 1)
|
||||
|
||||
if(char in whitespace)
|
||||
if(word != "")
|
||||
query_list += word
|
||||
word = ""
|
||||
|
||||
else if(char in single)
|
||||
if(word != "")
|
||||
query_list += word
|
||||
word = ""
|
||||
|
||||
query_list += char
|
||||
|
||||
else if(char in multi)
|
||||
if(word != "")
|
||||
query_list += word
|
||||
word = ""
|
||||
|
||||
var/char2 = copytext(query_text, i + 1, i + 2)
|
||||
|
||||
if(char2 in multi[char])
|
||||
query_list += "[char][char2]"
|
||||
i++
|
||||
|
||||
else
|
||||
query_list += char
|
||||
|
||||
else if(char == "'")
|
||||
if(word != "")
|
||||
usr << "\red SDQL2: You have an error in your SDQL syntax, unexpected ' in query: \"<font color=gray>[query_text]</font>\" following \"<font color=gray>[word]</font>\". Please check your syntax, and try again."
|
||||
return null
|
||||
|
||||
word = "'"
|
||||
|
||||
for(i++, i <= len, i++)
|
||||
char = copytext(query_text, i, i + 1)
|
||||
|
||||
if(char == "'")
|
||||
if(copytext(query_text, i + 1, i + 2) == "'")
|
||||
word += "'"
|
||||
i++
|
||||
|
||||
else
|
||||
break
|
||||
|
||||
else
|
||||
word += char
|
||||
|
||||
if(i > len)
|
||||
usr << "\red SDQL2: You have an error in your SDQL syntax, unmatched ' in query: \"<font color=gray>[query_text]</font>\". Please check your syntax, and try again."
|
||||
return null
|
||||
|
||||
query_list += "[word]'"
|
||||
word = ""
|
||||
|
||||
else if(char == "\"")
|
||||
if(word != "")
|
||||
usr << "\red SDQL2: You have an error in your SDQL syntax, unexpected \" in query: \"<font color=gray>[query_text]</font>\" following \"<font color=gray>[word]</font>\". Please check your syntax, and try again."
|
||||
return null
|
||||
|
||||
word = "\""
|
||||
|
||||
for(i++, i <= len, i++)
|
||||
char = copytext(query_text, i, i + 1)
|
||||
|
||||
if(char == "\"")
|
||||
if(copytext(query_text, i + 1, i + 2) == "'")
|
||||
word += "\""
|
||||
i++
|
||||
|
||||
else
|
||||
break
|
||||
|
||||
else
|
||||
word += char
|
||||
|
||||
if(i > len)
|
||||
usr << "\red SDQL2: You have an error in your SDQL syntax, unmatched \" in query: \"<font color=gray>[query_text]</font>\". Please check your syntax, and try again."
|
||||
return null
|
||||
|
||||
query_list += "[word]\""
|
||||
word = ""
|
||||
|
||||
else
|
||||
word += char
|
||||
|
||||
if(word != "")
|
||||
query_list += word
|
||||
|
||||
return query_list
|
||||
@@ -0,0 +1,531 @@
|
||||
//I'm pretty sure that this is a recursive [s]descent[/s] ascent parser.
|
||||
|
||||
|
||||
|
||||
//Spec
|
||||
|
||||
//////////
|
||||
//
|
||||
// query : select_query | delete_query | update_query | call_query | explain
|
||||
// explain : 'EXPLAIN' query
|
||||
//
|
||||
// select_query : 'SELECT' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression]
|
||||
// delete_query : 'DELETE' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression]
|
||||
// update_query : 'UPDATE' select_list [('FROM' | 'IN') from_list] 'SET' assignments ['WHERE' bool_expression]
|
||||
// call_query : 'CALL' call_function ['ON' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression]]
|
||||
//
|
||||
// select_list : select_item [',' select_list]
|
||||
// select_item : '*' | select_function | object_type
|
||||
// select_function : count_function
|
||||
// count_function : 'COUNT' '(' '*' ')' | 'COUNT' '(' object_types ')'
|
||||
//
|
||||
// from_list : from_item [',' from_list]
|
||||
// from_item : 'world' | object_type
|
||||
//
|
||||
// call_function : <function name> ['(' [arguments] ')']
|
||||
// arguments : expression [',' arguments]
|
||||
//
|
||||
// object_type : <type path> | string
|
||||
//
|
||||
// assignments : assignment, [',' assignments]
|
||||
// assignment : <variable name> '=' expression
|
||||
// variable : <variable name> | <variable name> '.' variable
|
||||
//
|
||||
// bool_expression : expression comparitor expression [bool_operator bool_expression]
|
||||
// expression : ( unary_expression | '(' expression ')' | value ) [binary_operator expression]
|
||||
// unary_expression : unary_operator ( unary_expression | value | '(' expression ')' )
|
||||
// comparitor : '=' | '==' | '!=' | '<>' | '<' | '<=' | '>' | '>='
|
||||
// value : variable | string | number | 'null'
|
||||
// unary_operator : '!' | '-' | '~'
|
||||
// binary_operator : comparitor | '+' | '-' | '/' | '*' | '&' | '|' | '^'
|
||||
// bool_operator : 'AND' | '&&' | 'OR' | '||'
|
||||
//
|
||||
// string : ''' <some text> ''' | '"' <some text > '"'
|
||||
// number : <some digits>
|
||||
//
|
||||
//////////
|
||||
|
||||
/datum/SDQL_parser
|
||||
var/query_type
|
||||
var/error = 0
|
||||
|
||||
var/list/query
|
||||
var/list/tree
|
||||
|
||||
var/list/select_functions = list("count")
|
||||
var/list/boolean_operators = list("and", "or", "&&", "||")
|
||||
var/list/unary_operators = list("!", "-", "~")
|
||||
var/list/binary_operators = list("+", "-", "/", "*", "&", "|", "^")
|
||||
var/list/comparitors = list("=", "==", "!=", "<>", "<", "<=", ">", ">=")
|
||||
|
||||
|
||||
|
||||
/datum/SDQL_parser/New(query_list)
|
||||
query = query_list
|
||||
|
||||
|
||||
|
||||
/datum/SDQL_parser/proc/parse_error(error_message)
|
||||
error = 1
|
||||
usr << "\red SQDL2 Parsing Error: [error_message]"
|
||||
return query.len + 1
|
||||
|
||||
/datum/SDQL_parser/proc/parse()
|
||||
tree = list()
|
||||
query(1, tree)
|
||||
|
||||
if(error)
|
||||
return list()
|
||||
else
|
||||
return tree
|
||||
|
||||
/datum/SDQL_parser/proc/token(i)
|
||||
if(i <= query.len)
|
||||
return query[i]
|
||||
|
||||
else
|
||||
return null
|
||||
|
||||
/datum/SDQL_parser/proc/tokens(i, num)
|
||||
if(i + num <= query.len)
|
||||
return query.Copy(i, i + num)
|
||||
|
||||
else
|
||||
return null
|
||||
|
||||
/datum/SDQL_parser/proc/tokenl(i)
|
||||
return lowertext(token(i))
|
||||
|
||||
|
||||
|
||||
/datum/SDQL_parser/proc
|
||||
|
||||
//query: select_query | delete_query | update_query
|
||||
query(i, list/node)
|
||||
query_type = tokenl(i)
|
||||
|
||||
switch(query_type)
|
||||
if("select")
|
||||
select_query(i, node)
|
||||
|
||||
if("delete")
|
||||
delete_query(i, node)
|
||||
|
||||
if("update")
|
||||
update_query(i, node)
|
||||
|
||||
if("call")
|
||||
call_query(i, node)
|
||||
|
||||
if("explain")
|
||||
node += "explain"
|
||||
node["explain"] = list()
|
||||
query(i + 1, node["explain"])
|
||||
|
||||
|
||||
// select_query: 'SELECT' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression]
|
||||
select_query(i, list/node)
|
||||
var/list/select = list()
|
||||
i = select_list(i + 1, select)
|
||||
|
||||
node += "select"
|
||||
node["select"] = select
|
||||
|
||||
var/list/from = list()
|
||||
if(tokenl(i) in list("from", "in"))
|
||||
i = from_list(i + 1, from)
|
||||
else
|
||||
from += "world"
|
||||
|
||||
node += "from"
|
||||
node["from"] = from
|
||||
|
||||
if(tokenl(i) == "where")
|
||||
var/list/where = list()
|
||||
i = bool_expression(i + 1, where)
|
||||
|
||||
node += "where"
|
||||
node["where"] = where
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//delete_query: 'DELETE' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression]
|
||||
delete_query(i, list/node)
|
||||
var/list/select = list()
|
||||
i = select_list(i + 1, select)
|
||||
|
||||
node += "delete"
|
||||
node["delete"] = select
|
||||
|
||||
var/list/from = list()
|
||||
if(tokenl(i) in list("from", "in"))
|
||||
i = from_list(i + 1, from)
|
||||
else
|
||||
from += "world"
|
||||
|
||||
node += "from"
|
||||
node["from"] = from
|
||||
|
||||
if(tokenl(i) == "where")
|
||||
var/list/where = list()
|
||||
i = bool_expression(i + 1, where)
|
||||
|
||||
node += "where"
|
||||
node["where"] = where
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//update_query: 'UPDATE' select_list [('FROM' | 'IN') from_list] 'SET' assignments ['WHERE' bool_expression]
|
||||
update_query(i, list/node)
|
||||
var/list/select = list()
|
||||
i = select_list(i + 1, select)
|
||||
|
||||
node += "update"
|
||||
node["update"] = select
|
||||
|
||||
var/list/from = list()
|
||||
if(tokenl(i) in list("from", "in"))
|
||||
i = from_list(i + 1, from)
|
||||
else
|
||||
from += "world"
|
||||
|
||||
node += "from"
|
||||
node["from"] = from
|
||||
|
||||
if(tokenl(i) != "set")
|
||||
i = parse_error("UPDATE has misplaced SET")
|
||||
|
||||
var/list/set_assignments = list()
|
||||
i = assignments(i + 1, set_assignments)
|
||||
|
||||
node += "set"
|
||||
node["set"] = set_assignments
|
||||
|
||||
if(tokenl(i) == "where")
|
||||
var/list/where = list()
|
||||
i = bool_expression(i + 1, where)
|
||||
|
||||
node += "where"
|
||||
node["where"] = where
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//call_query: 'CALL' call_function ['ON' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression]]
|
||||
call_query(i, list/node)
|
||||
var/list/func = list()
|
||||
i = call_function(i + 1, func)
|
||||
|
||||
node += "call"
|
||||
node["call"] = func
|
||||
|
||||
if(tokenl(i) != "on")
|
||||
return i
|
||||
|
||||
var/list/select = list()
|
||||
i = select_list(i + 1, select)
|
||||
|
||||
node += "on"
|
||||
node["on"] = select
|
||||
|
||||
var/list/from = list()
|
||||
if(tokenl(i) in list("from", "in"))
|
||||
i = from_list(i + 1, from)
|
||||
else
|
||||
from += "world"
|
||||
|
||||
node += "from"
|
||||
node["from"] = from
|
||||
|
||||
if(tokenl(i) == "where")
|
||||
var/list/where = list()
|
||||
i = bool_expression(i + 1, where)
|
||||
|
||||
node += "where"
|
||||
node["where"] = where
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//select_list: select_item [',' select_list]
|
||||
select_list(i, list/node)
|
||||
i = select_item(i, node)
|
||||
|
||||
if(token(i) == ",")
|
||||
i = select_list(i + 1, node)
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//from_list: from_item [',' from_list]
|
||||
from_list(i, list/node)
|
||||
i = from_item(i, node)
|
||||
|
||||
if(token(i) == ",")
|
||||
i = from_list(i + 1, node)
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//assignments: assignment, [',' assignments]
|
||||
assignments(i, list/node)
|
||||
i = assignment(i, node)
|
||||
|
||||
if(token(i) == ",")
|
||||
i = assignments(i + 1, node)
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//select_item: '*' | select_function | object_type
|
||||
select_item(i, list/node)
|
||||
|
||||
if(token(i) == "*")
|
||||
node += "*"
|
||||
i++
|
||||
|
||||
else if(tokenl(i) in select_functions)
|
||||
i = select_function(i, node)
|
||||
|
||||
else
|
||||
i = object_type(i, node)
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//from_item: 'world' | object_type
|
||||
from_item(i, list/node)
|
||||
|
||||
if(token(i) == "world")
|
||||
node += "world"
|
||||
i++
|
||||
|
||||
else
|
||||
i = object_type(i, node)
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//bool_expression: expression [bool_operator bool_expression]
|
||||
bool_expression(i, list/node)
|
||||
|
||||
var/list/bool = list()
|
||||
i = expression(i, bool)
|
||||
|
||||
node[++node.len] = bool
|
||||
|
||||
if(tokenl(i) in boolean_operators)
|
||||
i = bool_operator(i, node)
|
||||
i = bool_expression(i, node)
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//assignment: <variable name> '=' expression
|
||||
assignment(i, list/node)
|
||||
|
||||
node += token(i)
|
||||
|
||||
if(token(i + 1) == "=")
|
||||
var/varname = token(i)
|
||||
node[varname] = list()
|
||||
|
||||
i = expression(i + 2, node[varname])
|
||||
|
||||
else
|
||||
parse_error("Assignment expected, but no = found")
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//variable: <variable name> | <variable name> '.' variable
|
||||
variable(i, list/node)
|
||||
var/list/L = list(token(i))
|
||||
node[++node.len] = L
|
||||
|
||||
if(token(i + 1) == ".")
|
||||
L += "."
|
||||
i = variable(i + 2, L)
|
||||
|
||||
else
|
||||
i++
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//object_type: <type path> | string
|
||||
object_type(i, list/node)
|
||||
|
||||
if(copytext(token(i), 1, 2) == "/")
|
||||
node += token(i)
|
||||
|
||||
else
|
||||
i = string(i, node)
|
||||
|
||||
return i + 1
|
||||
|
||||
|
||||
//comparitor: '=' | '==' | '!=' | '<>' | '<' | '<=' | '>' | '>='
|
||||
comparitor(i, list/node)
|
||||
|
||||
if(token(i) in list("=", "==", "!=", "<>", "<", "<=", ">", ">="))
|
||||
node += token(i)
|
||||
|
||||
else
|
||||
parse_error("Unknown comparitor [token(i)]")
|
||||
|
||||
return i + 1
|
||||
|
||||
|
||||
//bool_operator: 'AND' | '&&' | 'OR' | '||'
|
||||
bool_operator(i, list/node)
|
||||
|
||||
if(tokenl(i) in list("and", "or", "&&", "||"))
|
||||
node += token(i)
|
||||
|
||||
else
|
||||
parse_error("Unknown comparitor [token(i)]")
|
||||
|
||||
return i + 1
|
||||
|
||||
|
||||
//string: ''' <some text> ''' | '"' <some text > '"'
|
||||
string(i, list/node)
|
||||
|
||||
if(copytext(token(i), 1, 2) in list("'", "\""))
|
||||
node += token(i)
|
||||
|
||||
else
|
||||
parse_error("Expected string but found '[token(i)]'")
|
||||
|
||||
return i + 1
|
||||
|
||||
|
||||
//call_function: <function name> ['(' [arguments] ')']
|
||||
call_function(i, list/node)
|
||||
|
||||
parse_error("Sorry, function calls aren't available yet")
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//select_function: count_function
|
||||
select_function(i, list/node)
|
||||
|
||||
parse_error("Sorry, function calls aren't available yet")
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//expression: ( unary_expression | '(' expression ')' | value ) [binary_operator expression]
|
||||
expression(i, list/node)
|
||||
|
||||
if(token(i) in unary_operators)
|
||||
i = unary_expression(i, node)
|
||||
|
||||
else if(token(i) == "(")
|
||||
var/list/expr = list()
|
||||
|
||||
i = expression(i + 1, expr)
|
||||
|
||||
if(token(i) != ")")
|
||||
parse_error("Missing ) at end of expression.")
|
||||
|
||||
else
|
||||
i++
|
||||
|
||||
node[++node.len] = expr
|
||||
|
||||
else
|
||||
i = value(i, node)
|
||||
|
||||
if(token(i) in binary_operators)
|
||||
i = binary_operator(i, node)
|
||||
i = expression(i, node)
|
||||
|
||||
else if(token(i) in comparitors)
|
||||
i = binary_operator(i, node)
|
||||
|
||||
var/list/rhs = list()
|
||||
i = expression(i, rhs)
|
||||
|
||||
node[++node.len] = rhs
|
||||
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//unary_expression: unary_operator ( unary_expression | value | '(' expression ')' )
|
||||
unary_expression(i, list/node)
|
||||
|
||||
if(token(i) in unary_operators)
|
||||
var/list/unary_exp = list()
|
||||
|
||||
unary_exp += token(i)
|
||||
i++
|
||||
|
||||
if(token(i) in unary_operators)
|
||||
i = unary_expression(i, unary_exp)
|
||||
|
||||
else if(token(i) == "(")
|
||||
var/list/expr = list()
|
||||
|
||||
i = expression(i + 1, expr)
|
||||
|
||||
if(token(i) != ")")
|
||||
parse_error("Missing ) at end of expression.")
|
||||
|
||||
else
|
||||
i++
|
||||
|
||||
unary_exp[++unary_exp.len] = expr
|
||||
|
||||
else
|
||||
i = value(i, unary_exp)
|
||||
|
||||
node[++node.len] = unary_exp
|
||||
|
||||
|
||||
else
|
||||
parse_error("Expected unary operator but found '[token(i)]'")
|
||||
|
||||
return i
|
||||
|
||||
|
||||
//binary_operator: comparitor | '+' | '-' | '/' | '*' | '&' | '|' | '^'
|
||||
binary_operator(i, list/node)
|
||||
|
||||
if(token(i) in (binary_operators + comparitors))
|
||||
node += token(i)
|
||||
|
||||
else
|
||||
parse_error("Unknown binary operator [token(i)]")
|
||||
|
||||
return i + 1
|
||||
|
||||
|
||||
//value: variable | string | number | 'null'
|
||||
value(i, list/node)
|
||||
|
||||
if(token(i) == "null")
|
||||
node += "null"
|
||||
i++
|
||||
|
||||
else if(isnum(text2num(token(i))))
|
||||
node += text2num(token(i))
|
||||
i++
|
||||
|
||||
else if(copytext(token(i), 1, 2) in list("'", "\""))
|
||||
i = string(i, node)
|
||||
|
||||
else
|
||||
i = variable(i, node)
|
||||
|
||||
return i
|
||||
|
||||
|
||||
|
||||
|
||||
/*EXPLAIN SELECT * WHERE 42 = 6 * 9 OR val = - 5 == 7*/
|
||||
@@ -251,6 +251,7 @@
|
||||
'nano/css/icons.css',
|
||||
'nano/templates/chem_dispenser.tmpl',
|
||||
'nano/templates/cryo.tmpl',
|
||||
'nano/templates/geoscanner.tmpl',
|
||||
'nano/templates/dna_modifier.tmpl',
|
||||
'nano/images/uiBackground.png',
|
||||
'nano/images/uiIcons16.png',
|
||||
@@ -298,9 +299,5 @@
|
||||
'icons/spideros_icons/sos_11.png',
|
||||
'icons/spideros_icons/sos_12.png',
|
||||
'icons/spideros_icons/sos_13.png',
|
||||
'icons/spideros_icons/sos_14.png',
|
||||
'icons/xenoarch_icons/chart1.jpg',
|
||||
'icons/xenoarch_icons/chart2.jpg',
|
||||
'icons/xenoarch_icons/chart3.jpg',
|
||||
'icons/xenoarch_icons/chart4.jpg'
|
||||
'icons/spideros_icons/sos_14.png'
|
||||
)
|
||||
|
||||
@@ -257,15 +257,6 @@
|
||||
item_state = "neocoat"
|
||||
flags = FPRINT | TABLEPASS
|
||||
|
||||
//actual suits
|
||||
|
||||
/obj/item/clothing/suit/creamsuit
|
||||
name = "cream suit"
|
||||
desc = "A cream coloured, genteel suit."
|
||||
icon_state = "creamsuit"
|
||||
item_state = "creamsuit"
|
||||
flags = FPRINT | TABLEPASS
|
||||
|
||||
//stripper
|
||||
|
||||
/obj/item/clothing/under/stripper/stripper_pink
|
||||
|
||||
@@ -478,6 +478,7 @@
|
||||
siemens_coefficient = 0.30
|
||||
permeability_coefficient = 0.01
|
||||
item_color="white"
|
||||
species_restricted = list("exclude","Unathi")
|
||||
|
||||
/obj/item/clothing/gloves/fluff/walter_brooks_1 //botanistpower: Walter Brooks
|
||||
name = "mittens"
|
||||
@@ -860,6 +861,7 @@
|
||||
desc = "Made of a special fiber that gives special protection against biohazards. Has a cross on the chest denoting that the wearer is trained medical personnel and short sleeves."
|
||||
icon = 'icons/obj/custom_items.dmi'
|
||||
icon_state = "medical_short"
|
||||
item_state = "medical_short"
|
||||
item_color = "medical_short"
|
||||
|
||||
/obj/item/clothing/suit/storage/labcoat/fluff/red
|
||||
|
||||
@@ -99,8 +99,9 @@
|
||||
new /obj/item/weapon/book/manual/engineering_particle_accelerator(src)
|
||||
new /obj/item/weapon/book/manual/engineering_hacking(src)
|
||||
new /obj/item/weapon/book/manual/engineering_guide(src)
|
||||
new /obj/item/weapon/book/manual/atmospipes(src)
|
||||
new /obj/item/weapon/book/manual/engineering_singularity_safety(src)
|
||||
new /obj/item/weapon/book/manual/robotics_cyborgs(src)
|
||||
new /obj/item/weapon/book/manual/evaguide(src)
|
||||
update_icon()
|
||||
|
||||
/obj/structure/bookcase/manuals/research_and_development
|
||||
|
||||
@@ -298,9 +298,25 @@
|
||||
new /obj/item/stack/sheet/mineral/clown(output.loc)
|
||||
else
|
||||
on = 0
|
||||
if (selected_glass == 1 && selected_gold == 0 && selected_silver == 0 && selected_diamond == 0 && selected_plasma == 1 && selected_uranium == 0 && selected_iron == 0 && selected_clown == 0)
|
||||
if (ore_glass > 0 && ore_plasma > 0)
|
||||
ore_glass--;
|
||||
ore_plasma--;
|
||||
new /obj/item/stack/sheet/glass/plasmaglass(output.loc)
|
||||
else
|
||||
on = 0
|
||||
if (selected_glass == 1 && selected_gold == 0 && selected_silver == 0 && selected_diamond == 0 && selected_plasma == 1 && selected_uranium == 0 && selected_iron == 1 && selected_clown == 0)
|
||||
if (ore_glass > 0 && ore_plasma > 0 && ore_iron > 0)
|
||||
ore_glass--;
|
||||
ore_iron--;
|
||||
ore_plasma--;
|
||||
new /obj/item/stack/sheet/glass/plasmarglass(output.loc)
|
||||
else
|
||||
on = 0
|
||||
continue
|
||||
//THESE TWO ARE CODED FOR URIST TO USE WHEN HE GETS AROUND TO IT.
|
||||
//They were coded on 18 Feb 2012. If you're reading this in 2015, then firstly congratulations on the world not ending on 21 Dec 2012 and secondly, Urist is apparently VERY lazy. ~Errorage
|
||||
//Iamgoofball here, this comment I'm typing right now was made in 11/1/2013. If you're reading this in 2020, then please let me know if the world has gone into a nuclear apocalypse. Also Urist has been tried and hung for how lazy he was. That and he was jaywalking.
|
||||
/*if (selected_glass == 0 && selected_gold == 0 && selected_silver == 0 && selected_diamond == 1 && selected_plasma == 0 && selected_uranium == 1 && selected_iron == 0 && selected_clown == 0)
|
||||
if (ore_uranium >= 2 && ore_diamond >= 1)
|
||||
ore_uranium -= 2
|
||||
@@ -380,34 +396,42 @@
|
||||
if (O)
|
||||
if (istype(O,/obj/item/weapon/ore/iron))
|
||||
ore_iron++;
|
||||
O.loc = null
|
||||
del(O)
|
||||
continue
|
||||
if (istype(O,/obj/item/weapon/ore/glass))
|
||||
ore_glass++;
|
||||
O.loc = null
|
||||
del(O)
|
||||
continue
|
||||
if (istype(O,/obj/item/weapon/ore/diamond))
|
||||
ore_diamond++;
|
||||
O.loc = null
|
||||
del(O)
|
||||
continue
|
||||
if (istype(O,/obj/item/weapon/ore/plasma))
|
||||
ore_plasma++
|
||||
O.loc = null
|
||||
del(O)
|
||||
continue
|
||||
if (istype(O,/obj/item/weapon/ore/gold))
|
||||
ore_gold++
|
||||
O.loc = null
|
||||
del(O)
|
||||
continue
|
||||
if (istype(O,/obj/item/weapon/ore/silver))
|
||||
ore_silver++
|
||||
O.loc = null
|
||||
del(O)
|
||||
continue
|
||||
if (istype(O,/obj/item/weapon/ore/uranium))
|
||||
ore_uranium++
|
||||
O.loc = null
|
||||
del(O)
|
||||
continue
|
||||
if (istype(O,/obj/item/weapon/ore/clown))
|
||||
ore_clown++
|
||||
O.loc = null
|
||||
del(O)
|
||||
continue
|
||||
O.loc = src.output.loc
|
||||
|
||||
@@ -42,6 +42,10 @@
|
||||
dat += text("Reinforced Glass: [machine.ore_rglass] <A href='?src=\ref[src];release=rglass'>Release</A><br>")
|
||||
if(machine.ore_plasma)
|
||||
dat += text("Plasma: [machine.ore_plasma] <A href='?src=\ref[src];release=plasma'>Release</A><br>")
|
||||
if(machine.ore_plasmaglass)
|
||||
dat += text("Plasma Glass: [machine.ore_plasmaglass] <A href='?src=\ref[src];release=plasmaglass'>Release</A><br>")
|
||||
if(machine.ore_plasmarglass)
|
||||
dat += text("Reinforced Plasma Glass: [machine.ore_plasmarglass] <A href='?src=\ref[src];release=plasmarglass'>Release</A><br>")
|
||||
if(machine.ore_gold)
|
||||
dat += text("Gold: [machine.ore_gold] <A href='?src=\ref[src];release=gold'>Release</A><br>")
|
||||
if(machine.ore_silver)
|
||||
@@ -83,6 +87,18 @@
|
||||
G.amount = machine.ore_plasma
|
||||
G.loc = machine.output.loc
|
||||
machine.ore_plasma = 0
|
||||
if ("plasmaglass")
|
||||
if (machine.ore_plasmaglass > 0)
|
||||
var/obj/item/stack/sheet/glass/plasmaglass/G = new /obj/item/stack/sheet/glass/plasmaglass
|
||||
G.amount = machine.ore_plasmaglass
|
||||
G.loc = machine.output.loc
|
||||
machine.ore_plasmaglass = 0
|
||||
if ("plasmarglass")
|
||||
if (machine.ore_plasmarglass > 0)
|
||||
var/obj/item/stack/sheet/glass/plasmarglass/G = new /obj/item/stack/sheet/glass/plasmarglass
|
||||
G.amount = machine.ore_plasmarglass
|
||||
G.loc = machine.output.loc
|
||||
machine.ore_plasmarglass = 0
|
||||
if ("uranium")
|
||||
if (machine.ore_uranium > 0)
|
||||
var/obj/item/stack/sheet/mineral/uranium/G = new /obj/item/stack/sheet/mineral/uranium
|
||||
@@ -195,6 +211,8 @@
|
||||
var/ore_silver = 0;
|
||||
var/ore_diamond = 0;
|
||||
var/ore_plasma = 0;
|
||||
var/ore_plasmaglass = 0;
|
||||
var/ore_plasmarglass = 0;
|
||||
var/ore_iron = 0;
|
||||
var/ore_uranium = 0;
|
||||
var/ore_clown = 0;
|
||||
@@ -263,6 +281,14 @@
|
||||
ore_rglass+= O:amount
|
||||
del(O)
|
||||
continue
|
||||
if (istype(O,/obj/item/stack/sheet/glass/plasmaglass))
|
||||
ore_plasmaglass+= O:amount
|
||||
del(O)
|
||||
continue
|
||||
if (istype(O,/obj/item/stack/sheet/glass/plasmarglass))
|
||||
ore_plasmarglass+= O:amount
|
||||
del(O)
|
||||
continue
|
||||
if (istype(O,/obj/item/stack/sheet/plasteel))
|
||||
ore_plasteel+= O:amount
|
||||
del(O)
|
||||
@@ -349,6 +375,18 @@
|
||||
G.loc = output.loc
|
||||
ore_rglass -= stack_amt
|
||||
return
|
||||
if (ore_plasmaglass >= stack_amt)
|
||||
var/obj/item/stack/sheet/glass/plasmaglass/G = new /obj/item/stack/sheet/glass/plasmaglass
|
||||
G.amount = stack_amt
|
||||
G.loc = output.loc
|
||||
ore_plasmaglass -= stack_amt
|
||||
return
|
||||
if (ore_plasmarglass >= stack_amt)
|
||||
var/obj/item/stack/sheet/glass/plasmarglass/G = new /obj/item/stack/sheet/glass/plasmarglass
|
||||
G.amount = stack_amt
|
||||
G.loc = output.loc
|
||||
ore_plasmarglass -= stack_amt
|
||||
return
|
||||
if (ore_plasteel >= stack_amt)
|
||||
var/obj/item/stack/sheet/plasteel/G = new /obj/item/stack/sheet/plasteel
|
||||
G.amount = stack_amt
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#define XENOARCH_SPREAD_CHANCE 15
|
||||
#define ARTIFACT_SPAWN_CHANCE 20
|
||||
|
||||
/datum/controller/game_controller/var/list/artifact_spawning_turfs = list()
|
||||
|
||||
/turf/simulated/mineral //wall piece
|
||||
name = "Rock"
|
||||
icon = 'icons/turf/walls.dmi'
|
||||
@@ -127,7 +129,7 @@
|
||||
//dont create artifact machinery in animal or plant digsites, or if we already have one
|
||||
if(!artifact_find && digsite != 1 && digsite != 2 && prob(ARTIFACT_SPAWN_CHANCE))
|
||||
artifact_find = new()
|
||||
artifact_spawning_turfs.Add(src)
|
||||
master_controller.artifact_spawning_turfs.Add(src)
|
||||
|
||||
if(!src.geological_data)
|
||||
src.geological_data = new/datum/geosample(src)
|
||||
@@ -369,29 +371,25 @@ commented out in r5061, I left it because of the shroom thingies
|
||||
//just pull the surrounding rock out
|
||||
excavate_find(0, F)
|
||||
|
||||
if( src.excavation_level + P.excavation_amount >= 100 || (!finds.len && !excavation_minerals.len) )
|
||||
//if players have been excavating this turf, have a chance to leave some rocky debris behind
|
||||
var/boulder_prob = 0
|
||||
if( src.excavation_level + P.excavation_amount >= 100 )
|
||||
//if players have been excavating this turf, leave some rocky debris behind
|
||||
var/obj/structure/boulder/B
|
||||
|
||||
if(src.excavation_level > 15)
|
||||
boulder_prob = 10
|
||||
if(artifact_find)
|
||||
boulder_prob += 25
|
||||
if(src.excavation_level >= 100)
|
||||
boulder_prob += 40
|
||||
else if(src.excavation_level > 95)
|
||||
boulder_prob += 25
|
||||
else if(src.excavation_level > 90)
|
||||
boulder_prob += 10
|
||||
if(prob(boulder_prob))
|
||||
if( src.excavation_level > 0 || prob(15) )
|
||||
//boulder with an artifact inside
|
||||
B = new(src)
|
||||
if(artifact_find)
|
||||
B.artifact_find = artifact_find
|
||||
else
|
||||
artifact_debris(1)
|
||||
else if(prob(15))
|
||||
//empty boulder
|
||||
B = new(src)
|
||||
if(artifact_find)
|
||||
B.artifact_find = artifact_find
|
||||
else if(artifact_find && src.excavation_level + P.excavation_amount >= 100)
|
||||
artifact_debris(1)
|
||||
|
||||
gets_drilled(B ? 0 : 1)
|
||||
if(B)
|
||||
gets_drilled(0)
|
||||
else
|
||||
gets_drilled(1)
|
||||
return
|
||||
else
|
||||
src.excavation_level += P.excavation_amount
|
||||
@@ -475,7 +473,7 @@ commented out in r5061, I left it because of the shroom thingies
|
||||
if(prob(50))
|
||||
pain = 1
|
||||
for(var/mob/living/M in range(src, 200))
|
||||
M << "<font color='red'><b>[pick("A high pitched [pick("keening","wailing","whistle")]","A rumbling noise like [pick("thunder","heavy machinery")]")] somehow penetrates your mind before fadaing away!</b></font>"
|
||||
M << "<font color='red'><b>[pick("A high pitched [pick("keening","wailing","whistle")]","A rumbling noise like [pick("thunder","heavy machinery")]")] somehow penetrates your mind before fading away!</b></font>"
|
||||
if(pain)
|
||||
flick("pain",M.pain)
|
||||
if(prob(50))
|
||||
|
||||
@@ -180,7 +180,7 @@ This function restores the subjects blood to max.
|
||||
/mob/living/carbon/human/proc/restore_blood()
|
||||
var/blood_volume = vessel.get_reagent_amount("blood")
|
||||
vessel.add_reagent("blood",560.0-blood_volume)
|
||||
|
||||
|
||||
|
||||
/*
|
||||
This function restores all organs.
|
||||
@@ -252,8 +252,9 @@ This function restores all organs.
|
||||
W.loc = src
|
||||
|
||||
else if(istype(used_weapon,/obj/item/projectile)) //We don't want to use the actual projectile item, so we spawn some shrapnel.
|
||||
if(prob(75) && damagetype == BRUTE)
|
||||
var/obj/item/projectile/P = used_weapon
|
||||
|
||||
var/obj/item/projectile/P = used_weapon
|
||||
if(prob(75) && P.embed)
|
||||
var/obj/item/weapon/shard/shrapnel/S = new()
|
||||
S.name = "[P.name] shrapnel"
|
||||
S.desc = "[S.desc] It looks like it was fired from [P.shot_from]."
|
||||
|
||||
@@ -1433,7 +1433,7 @@
|
||||
else if(health < config.health_threshold_softcrit)
|
||||
shock_stage = max(shock_stage, 61)
|
||||
else
|
||||
shock_stage = min(shock_stage, 100)
|
||||
shock_stage = min(shock_stage, 160)
|
||||
shock_stage = max(shock_stage-1, 0)
|
||||
return
|
||||
|
||||
@@ -1450,15 +1450,26 @@
|
||||
|
||||
if (shock_stage >= 60)
|
||||
if(shock_stage == 60) emote("me",1,"'s body becomes limp.")
|
||||
if (prob(2))
|
||||
src << "<font color='red'><b>"+pick("The pain is excrutiating!", "Please, just end the pain!", "Your whole body is going numb!")
|
||||
Weaken(20)
|
||||
|
||||
if(shock_stage >= 80)
|
||||
if (prob(5))
|
||||
Stun(20)
|
||||
lying = 1
|
||||
src << "<font color='red'><b>"+pick("The pain is excrutiating!", "Please, just end the pain!", "Your whole body is going numb!")
|
||||
Weaken(20)
|
||||
|
||||
if(shock_stage == 80)
|
||||
src << "<font color='red'><b>"+pick("You see a light at the end of the tunnel!", "You feel like you could die any moment now.", "You're about to lose consciousness.")
|
||||
if(shock_stage >= 120)
|
||||
if (prob(2))
|
||||
src << "<font color='red'><b>"+pick("You black out!", "You feel like you could die any moment now.", "You're about to lose consciousness.")
|
||||
Paralyse(5)
|
||||
|
||||
if(shock_stage > 80)
|
||||
Paralyse(rand(15,28))
|
||||
if(shock_stage == 150)
|
||||
emote("me",1,"can no longer stand, collapsing!")
|
||||
Weaken(20)
|
||||
|
||||
if(shock_stage >= 150)
|
||||
Weaken(20)
|
||||
|
||||
proc/handle_pulse()
|
||||
if(life_tick % 5) return pulse //update pulse every 5 life ticks (~1 tick/sec, depending on server load)
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
/mob/living/carbon/proc/updateshock()
|
||||
src.traumatic_shock = \
|
||||
1 * src.getOxyLoss() + \
|
||||
0.5 * src.getToxLoss() + \
|
||||
2.5 * src.getFireLoss() + \
|
||||
1.5 * src.getBruteLoss() + \
|
||||
2 * src.getCloneLoss() + \
|
||||
1 * src.halloss
|
||||
0.7 * src.getToxLoss() + \
|
||||
1.5 * src.getFireLoss() + \
|
||||
1.2 * src.getBruteLoss() + \
|
||||
1.7 * src.getCloneLoss() + \
|
||||
2 * src.halloss
|
||||
|
||||
if(reagents.has_reagent("alkysine"))
|
||||
src.traumatic_shock -= 10
|
||||
@@ -35,7 +35,7 @@
|
||||
else if(organ.status & ORGAN_BROKEN || organ.open)
|
||||
src.traumatic_shock += 30
|
||||
if(organ.status & ORGAN_SPLINTED)
|
||||
src.traumatic_shock -= 20
|
||||
src.traumatic_shock -= 25
|
||||
|
||||
if(src.traumatic_shock < 0)
|
||||
src.traumatic_shock = 0
|
||||
|
||||
@@ -171,9 +171,14 @@
|
||||
|
||||
O.loc = loc
|
||||
O.job = "Cyborg"
|
||||
|
||||
O.mmi = new /obj/item/device/mmi(O)
|
||||
O.mmi.transfer_identity(src)//Does not transfer key/client.
|
||||
if(O.mind.assigned_role == "Cyborg")
|
||||
if(O.mind.role_alt_title == "Android")
|
||||
O.mmi = new /obj/item/device/mmi/posibrain(O)
|
||||
if(O.mind.role_alt_title == "Robot")
|
||||
O.mmi = new /obj/item/device/mmi/posibrain(O) //Ravensdale wants a circuit based brain for another robot class, this is a placeholder.
|
||||
else
|
||||
O.mmi = new /obj/item/device/mmi(O)
|
||||
O.mmi.transfer_identity(src)//Does not transfer key/client.
|
||||
|
||||
O.Namepick()
|
||||
|
||||
|
||||
@@ -890,17 +890,17 @@ obj/item/weapon/organ/head/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
switch(brain_op_stage)
|
||||
if(0)
|
||||
for(var/mob/O in (oviewers(brainmob) - user))
|
||||
O.show_message("\red [brainmob] is beginning to have \his head cut open with [src] by [user].", 1)
|
||||
brainmob << "\red [user] begins to cut open your head with [src]!"
|
||||
user << "\red You cut [brainmob]'s head open with [src]!"
|
||||
O.show_message("\red [brainmob] is beginning to have \his head cut open with [W] by [user].", 1)
|
||||
brainmob << "\red [user] begins to cut open your head with [W]!"
|
||||
user << "\red You cut [brainmob]'s head open with [W]!"
|
||||
|
||||
brain_op_stage = 1
|
||||
|
||||
if(2)
|
||||
for(var/mob/O in (oviewers(brainmob) - user))
|
||||
O.show_message("\red [brainmob] is having \his connections to the brain delicately severed with [src] by [user].", 1)
|
||||
brainmob << "\red [user] begins to cut open your head with [src]!"
|
||||
user << "\red You cut [brainmob]'s head open with [src]!"
|
||||
O.show_message("\red [brainmob] is having \his connections to the brain delicately severed with [W] by [user].", 1)
|
||||
brainmob << "\red [user] begins to cut open your head with [W]!"
|
||||
user << "\red You cut [brainmob]'s head open with [W]!"
|
||||
|
||||
brain_op_stage = 3.0
|
||||
else
|
||||
@@ -909,20 +909,20 @@ obj/item/weapon/organ/head/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
switch(brain_op_stage)
|
||||
if(1)
|
||||
for(var/mob/O in (oviewers(brainmob) - user))
|
||||
O.show_message("\red [brainmob] has \his skull sawed open with [src] by [user].", 1)
|
||||
brainmob << "\red [user] begins to saw open your head with [src]!"
|
||||
user << "\red You saw [brainmob]'s head open with [src]!"
|
||||
O.show_message("\red [brainmob] has \his skull sawed open with [W] by [user].", 1)
|
||||
brainmob << "\red [user] begins to saw open your head with [W]!"
|
||||
user << "\red You saw [brainmob]'s head open with [W]!"
|
||||
|
||||
brain_op_stage = 2
|
||||
if(3)
|
||||
for(var/mob/O in (oviewers(brainmob) - user))
|
||||
O.show_message("\red [brainmob] has \his spine's connection to the brain severed with [src] by [user].", 1)
|
||||
brainmob << "\red [user] severs your brain's connection to the spine with [src]!"
|
||||
user << "\red You sever [brainmob]'s brain's connection to the spine with [src]!"
|
||||
O.show_message("\red [brainmob] has \his spine's connection to the brain severed with [W] by [user].", 1)
|
||||
brainmob << "\red [user] severs your brain's connection to the spine with [W]!"
|
||||
user << "\red You sever [brainmob]'s brain's connection to the spine with [W]!"
|
||||
|
||||
user.attack_log += "\[[time_stamp()]\]<font color='red'> Debrained [brainmob.name] ([brainmob.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])</font>"
|
||||
brainmob.attack_log += "\[[time_stamp()]\]<font color='orange'> Debrained by [user.name] ([user.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])</font>"
|
||||
msg_admin_attack("[brainmob] ([brainmob.ckey]) debrained [user] ([user.ckey]) (INTENT: [uppertext(user.a_intent)]) (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[user.x];Y=[user.y];Z=[user.z]'>JMP</a>)")
|
||||
user.attack_log += "\[[time_stamp()]\]<font color='red'> Debrained [brainmob.name] ([brainmob.ckey]) with [W.name] (INTENT: [uppertext(user.a_intent)])</font>"
|
||||
brainmob.attack_log += "\[[time_stamp()]\]<font color='orange'> Debrained by [user.name] ([user.ckey]) with [W.name] (INTENT: [uppertext(user.a_intent)])</font>"
|
||||
msg_admin_attack("[user] ([user.ckey]) debrained [brainmob] ([brainmob.ckey]) (INTENT: [uppertext(user.a_intent)]) (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[user.x];Y=[user.y];Z=[user.z]'>JMP</a>)")
|
||||
|
||||
var/obj/item/brain/B = new(loc)
|
||||
B.transfer_identity(brainmob)
|
||||
|
||||
@@ -136,6 +136,14 @@
|
||||
in_chamber.current = curloc
|
||||
in_chamber.yo = targloc.y - curloc.y
|
||||
in_chamber.xo = targloc.x - curloc.x
|
||||
if(istype(user, /mob/living/carbon))
|
||||
var/mob/living/carbon/mob = user
|
||||
if(mob.shock_stage > 120)
|
||||
in_chamber.yo += rand(-2,2)
|
||||
in_chamber.xo += rand(-2,2)
|
||||
else if(mob.shock_stage > 70)
|
||||
in_chamber.yo += rand(-1,1)
|
||||
in_chamber.xo += rand(-1,1)
|
||||
|
||||
if(params)
|
||||
var/list/mouse_control = params2list(params)
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
var/drowsy = 0
|
||||
var/agony = 0
|
||||
|
||||
var/embed = 0 // whether or not the projectile can embed itself in the mob
|
||||
|
||||
proc/on_hit(var/atom/target, var/blocked = 0)
|
||||
if(blocked >= 2) return 0//Full block
|
||||
|
||||
@@ -5,16 +5,18 @@
|
||||
damage_type = BRUTE
|
||||
nodamage = 0
|
||||
flag = "bullet"
|
||||
embed = 1
|
||||
|
||||
on_hit(var/atom/target, var/blocked = 0)
|
||||
if (..(target, blocked))
|
||||
var/mob/living/L = target
|
||||
shake_camera(L, 3, 2)
|
||||
|
||||
/obj/item/projectile/bullet/weakbullet
|
||||
/obj/item/projectile/bullet/weakbullet // "rubber" bullets
|
||||
damage = 10
|
||||
stun = 5
|
||||
weaken = 5
|
||||
embed = 0
|
||||
|
||||
|
||||
/obj/item/projectile/bullet/midbullet
|
||||
@@ -48,6 +50,7 @@
|
||||
stun = 10
|
||||
weaken = 10
|
||||
stutter = 10
|
||||
embed = 0
|
||||
|
||||
/obj/item/projectile/bullet/a762
|
||||
damage = 25
|
||||
@@ -4,6 +4,7 @@
|
||||
icon_state = "ice_1"
|
||||
damage = 20
|
||||
flag = "energy"
|
||||
embed = 1
|
||||
|
||||
/obj/item/projectile/forcebolt/strong
|
||||
name = "force bolt"
|
||||
|
||||
@@ -15,9 +15,12 @@
|
||||
var/amount = 30
|
||||
var/beaker = null
|
||||
var/recharged = 0
|
||||
var/hackedcheck = 0
|
||||
var/list/dispensable_reagents = list("hydrogen","lithium","carbon","nitrogen","oxygen","fluorine",
|
||||
"sodium","aluminum","silicon","phosphorus","sulfur","chlorine","potassium","iron",
|
||||
"copper","mercury","radium","water","ethanol","sugar","sacid","tungsten")
|
||||
var/list/broken_requirements = list()
|
||||
var/broken_on_spawn = 0
|
||||
|
||||
/obj/machinery/chem_dispenser/proc/recharge()
|
||||
if(stat & (BROKEN|NOPOWER)) return
|
||||
@@ -49,6 +52,28 @@
|
||||
recharge()
|
||||
dispensable_reagents = sortList(dispensable_reagents)
|
||||
|
||||
if(broken_on_spawn)
|
||||
var/amount = pick(1,2,2,3,4)
|
||||
var/list/options = list()
|
||||
options[/obj/item/weapon/stock_parts/capacitor/adv] = "Add an advanced capacitor to fix it."
|
||||
options[/obj/item/weapon/stock_parts/console_screen] = "Replace the console screen to fix it."
|
||||
options[/obj/item/weapon/stock_parts/manipulator/pico] = "Upgrade to a pico manipulator to fix it."
|
||||
options[/obj/item/weapon/stock_parts/matter_bin/adv] = "Give it an advanced matter bin to fix it."
|
||||
options[/obj/item/stack/sheet/mineral/diamond] = "Line up a cut diamond with the nozzle to fix it."
|
||||
options[/obj/item/stack/sheet/mineral/uranium] = "Position a uranium sheet inside to fix it."
|
||||
options[/obj/item/stack/sheet/mineral/plasma] = "Enter a block of plasma to fix it."
|
||||
options[/obj/item/stack/sheet/mineral/silver] = "Cover the internals with a silver lining to fix it."
|
||||
options[/obj/item/stack/sheet/mineral/gold] = "Wire a golden filament to fix it."
|
||||
options[/obj/item/stack/sheet/plasteel] = "Surround the outside with a plasteel cover to fix it."
|
||||
options[/obj/item/stack/sheet/rglass] = "Insert a pane of reinforced glass to fix it."
|
||||
|
||||
while(amount > 0)
|
||||
amount -= 1
|
||||
|
||||
var/index = pick(options)
|
||||
broken_requirements[index] = options[index]
|
||||
options -= index
|
||||
|
||||
/obj/machinery/chem_dispenser/ex_act(severity)
|
||||
switch(severity)
|
||||
if(1.0)
|
||||
@@ -74,14 +99,17 @@
|
||||
*
|
||||
* @param user /mob The mob who is interacting with this ui
|
||||
* @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main")
|
||||
* @param ui /datum/nanoui This parameter is passed by the nanoui process() proc when updating an open ui
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
/obj/machinery/chem_dispenser/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
|
||||
/obj/machinery/chem_dispenser/ui_interact(mob/user, ui_key = "main")
|
||||
if(stat & (BROKEN|NOPOWER)) return
|
||||
if(user.stat || user.restrained()) return
|
||||
|
||||
if(broken_requirements.len)
|
||||
user << "<span class='warning'>[src] is broken. [broken_requirements[broken_requirements[1]]]</span>"
|
||||
return
|
||||
|
||||
// this is the data which will be sent to the ui
|
||||
var/data[0]
|
||||
data["amount"] = amount
|
||||
@@ -111,13 +139,10 @@
|
||||
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
|
||||
|
||||
if (!ui) // no ui has been passed, so we'll search for one
|
||||
{
|
||||
ui = nanomanager.get_open_ui(user, src, ui_key)
|
||||
}
|
||||
var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, ui_key)
|
||||
if (!ui)
|
||||
// the ui does not exist, so we'll create a new one
|
||||
ui = new(user, src, ui_key, "chem_dispenser.tmpl", "Chem Dispenser 5000", 374, 640)
|
||||
ui = new(user, src, ui_key, "chem_dispenser.tmpl", "Chem Dispenser 5000", 370, 605)
|
||||
// When the UI is first opened this is the data it will use
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
@@ -159,18 +184,26 @@
|
||||
if(isrobot(user))
|
||||
return
|
||||
|
||||
if(!istype(B, /obj/item/weapon/reagent_containers/glass))
|
||||
if(broken_requirements.len && B.type == broken_requirements[1])
|
||||
broken_requirements -= broken_requirements[1]
|
||||
user << "<span class='notice'>You fix [src].</span>"
|
||||
if(istype(B,/obj/item/stack))
|
||||
var/obj/item/stack/S = B
|
||||
S.use(1)
|
||||
else
|
||||
user.drop_item()
|
||||
del(B)
|
||||
return
|
||||
|
||||
if(src.beaker)
|
||||
user << "A beaker is already loaded into the machine."
|
||||
user << "Something is already loaded into the machine."
|
||||
return
|
||||
if(istype(B, /obj/item/weapon/reagent_containers/glass||/obj/item/weapon/reagent_containers/food))
|
||||
src.beaker = B
|
||||
user.drop_item()
|
||||
B.loc = src
|
||||
user << "You set [B] on the machine."
|
||||
nanomanager.update_uis(src) // update all UIs attached to src
|
||||
return
|
||||
|
||||
src.beaker = B
|
||||
user.drop_item()
|
||||
B.loc = src
|
||||
user << "You add the beaker to the machine!"
|
||||
nanomanager.update_uis(src) // update all UIs attached to src
|
||||
|
||||
/obj/machinery/chem_dispenser/attack_ai(mob/user as mob)
|
||||
return src.attack_hand(user)
|
||||
@@ -184,6 +217,50 @@
|
||||
|
||||
ui_interact(user)
|
||||
|
||||
/obj/machinery/chem_dispenser/soda
|
||||
icon_state = "soda_dispenser"
|
||||
name = "soda fountain"
|
||||
desc = "A drink fabricating machine, capable of producing many sugary drinks with just one touch."
|
||||
energy = 100
|
||||
max_energy = 100
|
||||
dispensable_reagents = list("water","ice","coffee","tea","icetea","space_cola","spacemountainwind","dr_gibb","space_up","tonic","sodawater","lemon_lime","sugar","orangejuice","limejuice")
|
||||
|
||||
/obj/machinery/chem_dispenser/soda/attackby(var/obj/item/weapon/B as obj, var/mob/user as mob)
|
||||
..()
|
||||
if(istype(B, /obj/item/device/multitool))
|
||||
if(hackedcheck == 0)
|
||||
user << "You change the mode from 'McNano' to 'Pizza King'."
|
||||
dispensable_reagents += list("thirteenloko","grapesoda")
|
||||
hackedcheck = 1
|
||||
return
|
||||
|
||||
else
|
||||
user << "You change the mode from 'Pizza King' to 'McNano'."
|
||||
dispensable_reagents -= list("thirteenloko")
|
||||
hackedcheck = 0
|
||||
return
|
||||
/obj/machinery/chem_dispenser/beer
|
||||
icon_state = "booze_dispenser"
|
||||
name = "booze dispenser"
|
||||
energy = 100
|
||||
max_energy = 100
|
||||
desc = "A technological marvel, supposedly able to mix just the mixture you'd like to drink the moment you ask for one."
|
||||
dispensable_reagents = list("water","ice","coffee","tea","cream","lemon_lime","sugar","orangejuice","limejuice","cola","sodawater","tonic","beer","kahlua","whiskey","wine","vodka","gin","rum","tequila","vermouth","cognac","ale","mead")
|
||||
|
||||
/obj/machinery/chem_dispenser/beer/attackby(var/obj/item/weapon/B as obj, var/mob/user as mob)
|
||||
..()
|
||||
if(istype(B, /obj/item/device/multitool))
|
||||
if(hackedcheck == 0)
|
||||
user << "You disable the 'nanotrasen-are-cheap-bastards' lock, enabling hidden and very expensive boozes."
|
||||
dispensable_reagents += list("goldschlager","patron","watermelonjuice","berryjuice")
|
||||
hackedcheck = 1
|
||||
return
|
||||
|
||||
else
|
||||
user << "You re-enable the 'nanotrasen-are-cheap-bastards' lock, disabling hidden and very expensive boozes."
|
||||
dispensable_reagents -= list("goldschlager","patron","watermelonjuice","berryjuice")
|
||||
hackedcheck = 0
|
||||
return
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -347,15 +424,15 @@
|
||||
reagents.clear_reagents()
|
||||
icon_state = "mixer0"
|
||||
else if (href_list["createpill"] || href_list["createpill_multiple"])
|
||||
var/name = reject_bad_text(input(usr,"Name:","Name your pill!",reagents.get_master_reagent_name()))
|
||||
var/count = 1
|
||||
if (href_list["createpill_multiple"]) count = isgoodnumber(input("Select the number of pills to make.", 10, pillamount) as num)
|
||||
if (count > 20) count = 20 //Pevent people from creating huge stacks of pills easily. Maybe move the number to defines?
|
||||
var/amount_per_pill = reagents.total_volume/count
|
||||
if (amount_per_pill > 50) amount_per_pill = 50
|
||||
var/name = reject_bad_text(input(usr,"Name:","Name your pill!","[reagents.get_master_reagent_name()] ([amount_per_pill] units)"))
|
||||
while (count--)
|
||||
var/obj/item/weapon/reagent_containers/pill/P = new/obj/item/weapon/reagent_containers/pill(src.loc)
|
||||
if(!name) name = "[reagents.get_master_reagent_name()] ([amount_per_pill] units)"
|
||||
if(!name) name = reagents.get_master_reagent_name()
|
||||
P.name = "[name] pill"
|
||||
P.pixel_x = rand(-7, 7) //random position
|
||||
P.pixel_y = rand(-7, 7)
|
||||
@@ -367,9 +444,9 @@
|
||||
src.updateUsrDialog()
|
||||
else if (href_list["createbottle"])
|
||||
if(!condi)
|
||||
var/name = reject_bad_text(input(usr,"Name:","Name your bottle!","[reagents.get_master_reagent_name()] ([reagents.total_volume] units)"))
|
||||
var/name = reject_bad_text(input(usr,"Name:","Name your bottle!",reagents.get_master_reagent_name()))
|
||||
var/obj/item/weapon/reagent_containers/glass/bottle/P = new/obj/item/weapon/reagent_containers/glass/bottle(src.loc)
|
||||
if(!name) name = "[reagents.get_master_reagent_name()] ([reagents.total_volume] units)"
|
||||
if(!name) name = reagents.get_master_reagent_name()
|
||||
P.name = "[name] bottle"
|
||||
P.pixel_x = rand(-7, 7) //random position
|
||||
P.pixel_y = rand(-7, 7)
|
||||
|
||||
@@ -2347,6 +2347,13 @@ datum
|
||||
id = "grapejuice"
|
||||
description = "It's grrrrrape!"
|
||||
color = "#863333" // rgb: 134, 51, 51
|
||||
|
||||
drink/grapesoda
|
||||
name = "Grape Soda"
|
||||
id = "grapesoda"
|
||||
description = "Grapes made into a fine drank."
|
||||
color = "#421C52" // rgb: 98, 57, 53
|
||||
adj_drowsy = -3
|
||||
|
||||
drink/poisonberryjuice
|
||||
name = "Poison Berry Juice"
|
||||
|
||||
@@ -1790,6 +1790,14 @@ datum
|
||||
result = "barefoot"
|
||||
required_reagents = list("berryjuice" = 1, "cream" = 1, "vermouth" = 1)
|
||||
result_amount = 3
|
||||
|
||||
grapesoda //Allows Grape Soda to be made
|
||||
name = "Grape Soda"
|
||||
id = "grapesoda"
|
||||
result = "grapesoda"
|
||||
required_reagents = list("grapejuice" = 2, "cola" = 1)
|
||||
result_amount = 3
|
||||
|
||||
|
||||
|
||||
////DRINKS THAT REQUIRED IMPROVED SPRITES BELOW:: -Agouri/////
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
|
||||
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/drinks/drinkingglass
|
||||
name = "glass"
|
||||
desc = "Your standard drinking glass."
|
||||
@@ -434,6 +434,10 @@
|
||||
icon_state = "grapejuice"
|
||||
name = "Glass of grape juice"
|
||||
desc = "It's grrrrrape!"
|
||||
if("grapesoda")
|
||||
icon_state = "grapesoda"
|
||||
name = "Can of Grape Soda"
|
||||
desc = "Looks like a delicious drank!"
|
||||
if("icetea")
|
||||
icon_state = "icedteaglass"
|
||||
name = "Iced Tea"
|
||||
@@ -499,4 +503,4 @@
|
||||
New()
|
||||
..()
|
||||
reagents.add_reagent("cola", 50)
|
||||
on_reagent_change()
|
||||
on_reagent_change()
|
||||
|
||||
@@ -1,318 +1,337 @@
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// (Mixing)Glass.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/obj/item/weapon/reagent_containers/glass
|
||||
name = " "
|
||||
var/base_name = " "
|
||||
desc = " "
|
||||
icon = 'icons/obj/chemical.dmi'
|
||||
icon_state = "null"
|
||||
item_state = "null"
|
||||
amount_per_transfer_from_this = 10
|
||||
possible_transfer_amounts = list(5,10,15,25,30,50)
|
||||
volume = 50
|
||||
flags = FPRINT | TABLEPASS | OPENCONTAINER
|
||||
|
||||
var/label_text = ""
|
||||
|
||||
var/list/can_be_placed_into = list(
|
||||
/obj/machinery/chem_master/,
|
||||
/obj/machinery/chem_dispenser/,
|
||||
/obj/machinery/reagentgrinder,
|
||||
/obj/structure/table,
|
||||
/obj/structure/closet,
|
||||
/obj/structure/sink,
|
||||
/obj/item/weapon/storage,
|
||||
/obj/machinery/atmospherics/unary/cryo_cell,
|
||||
/obj/machinery/dna_scannernew,
|
||||
/obj/item/weapon/grenade/chem_grenade,
|
||||
/obj/machinery/bot/medbot,
|
||||
/obj/machinery/computer/pandemic,
|
||||
/obj/item/weapon/storage/secure/safe,
|
||||
/obj/machinery/iv_drip,
|
||||
/obj/machinery/disease2/incubator,
|
||||
/obj/machinery/disposal,
|
||||
/obj/machinery/apiary,
|
||||
/mob/living/simple_animal/cow,
|
||||
/mob/living/simple_animal/hostile/retaliate/goat,
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// (Mixing)Glass.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/obj/item/weapon/reagent_containers/glass
|
||||
name = " "
|
||||
var/base_name = " "
|
||||
desc = " "
|
||||
icon = 'icons/obj/chemical.dmi'
|
||||
icon_state = "null"
|
||||
item_state = "null"
|
||||
amount_per_transfer_from_this = 10
|
||||
possible_transfer_amounts = list(5,10,15,25,30,50)
|
||||
volume = 50
|
||||
flags = FPRINT | TABLEPASS | OPENCONTAINER
|
||||
|
||||
var/label_text = ""
|
||||
|
||||
var/list/can_be_placed_into = list(
|
||||
/obj/machinery/chem_master/,
|
||||
/obj/machinery/chem_dispenser/,
|
||||
/obj/machinery/reagentgrinder,
|
||||
/obj/structure/table,
|
||||
/obj/structure/closet,
|
||||
/obj/structure/sink,
|
||||
/obj/item/weapon/storage,
|
||||
/obj/machinery/atmospherics/unary/cryo_cell,
|
||||
/obj/machinery/dna_scannernew,
|
||||
/obj/item/weapon/grenade/chem_grenade,
|
||||
/obj/machinery/bot/medbot,
|
||||
/obj/machinery/computer/pandemic,
|
||||
/obj/item/weapon/storage/secure/safe,
|
||||
/obj/machinery/iv_drip,
|
||||
/obj/machinery/disease2/incubator,
|
||||
/obj/machinery/disposal,
|
||||
/obj/machinery/apiary,
|
||||
/mob/living/simple_animal/cow,
|
||||
/mob/living/simple_animal/hostile/retaliate/goat,
|
||||
/obj/machinery/computer/centrifuge,
|
||||
/obj/machinery/sleeper )
|
||||
|
||||
New()
|
||||
..()
|
||||
base_name = name
|
||||
|
||||
examine()
|
||||
set src in view()
|
||||
..()
|
||||
if (!(usr in view(2)) && usr!=src.loc) return
|
||||
usr << "\blue It contains:"
|
||||
if(reagents && reagents.reagent_list.len)
|
||||
usr << "\blue [src.reagents.total_volume] units of liquid."
|
||||
else
|
||||
usr << "\blue Nothing."
|
||||
if (!is_open_container())
|
||||
usr << "\blue Airtight lid seals it completely."
|
||||
|
||||
attack_self()
|
||||
..()
|
||||
if (is_open_container())
|
||||
usr << "<span class = 'notice'>You put the lid on \the [src]."
|
||||
flags ^= OPENCONTAINER
|
||||
else
|
||||
usr << "<span class = 'notice'>You take the lid off \the [src]."
|
||||
flags |= OPENCONTAINER
|
||||
update_icon()
|
||||
|
||||
afterattack(obj/target, mob/user, proximity)
|
||||
if(!proximity) return
|
||||
if (!is_open_container())
|
||||
return
|
||||
|
||||
for(var/type in src.can_be_placed_into)
|
||||
if(istype(target, type))
|
||||
return
|
||||
|
||||
if(ismob(target) && target.reagents && reagents.total_volume)
|
||||
user << "\blue You splash the solution onto [target]."
|
||||
|
||||
var/mob/living/M = target
|
||||
var/list/injected = list()
|
||||
for(var/datum/reagent/R in src.reagents.reagent_list)
|
||||
injected += R.name
|
||||
var/contained = english_list(injected)
|
||||
M.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has been splashed with [src.name] by [user.name] ([user.ckey]). Reagents: [contained]</font>")
|
||||
user.attack_log += text("\[[time_stamp()]\] <font color='red'>Used the [src.name] to splash [M.name] ([M.key]). Reagents: [contained]</font>")
|
||||
msg_admin_attack("[user.name] ([user.ckey]) splashed [M.name] ([M.key]) with [src.name]. Reagents: [contained] (INTENT: [uppertext(user.a_intent)]) (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[user.x];Y=[user.y];Z=[user.z]'>JMP</a>)")
|
||||
|
||||
for(var/mob/O in viewers(world.view, user))
|
||||
O.show_message(text("\red [] has been splashed with something by []!", target, user), 1)
|
||||
src.reagents.reaction(target, TOUCH)
|
||||
spawn(5) src.reagents.clear_reagents()
|
||||
return
|
||||
else if(istype(target, /obj/structure/reagent_dispensers)) //A dispenser. Transfer FROM it TO us.
|
||||
|
||||
if(!target.reagents.total_volume && target.reagents)
|
||||
user << "\red [target] is empty."
|
||||
return
|
||||
|
||||
if(reagents.total_volume >= reagents.maximum_volume)
|
||||
user << "\red [src] is full."
|
||||
return
|
||||
|
||||
var/trans = target.reagents.trans_to(src, target:amount_per_transfer_from_this)
|
||||
user << "\blue You fill [src] with [trans] units of the contents of [target]."
|
||||
|
||||
else if(target.is_open_container() && target.reagents) //Something like a glass. Player probably wants to transfer TO it.
|
||||
if(!reagents.total_volume)
|
||||
user << "\red [src] is empty."
|
||||
return
|
||||
|
||||
if(target.reagents.total_volume >= target.reagents.maximum_volume)
|
||||
user << "\red [target] is full."
|
||||
return
|
||||
|
||||
var/trans = src.reagents.trans_to(target, amount_per_transfer_from_this)
|
||||
user << "\blue You transfer [trans] units of the solution to [target]."
|
||||
|
||||
//Safety for dumping stuff into a ninja suit. It handles everything through attackby() and this is unnecessary.
|
||||
else if(istype(target, /obj/item/clothing/suit/space/space_ninja))
|
||||
return
|
||||
|
||||
else if(istype(target, /obj/machinery/bunsen_burner))
|
||||
return
|
||||
|
||||
else if(istype(target, /obj/machinery/anomaly))
|
||||
return
|
||||
|
||||
else if(reagents.total_volume)
|
||||
user << "\blue You splash the solution onto [target]."
|
||||
src.reagents.reaction(target, TOUCH)
|
||||
spawn(5) src.reagents.clear_reagents()
|
||||
return
|
||||
|
||||
attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
if(istype(W, /obj/item/weapon/pen) || istype(W, /obj/item/device/flashlight/pen))
|
||||
var/tmp_label = sanitize(input(user, "Enter a label for [src.name]","Label",src.label_text))
|
||||
if(length(tmp_label) > 10)
|
||||
user << "\red The label can be at most 10 characters long."
|
||||
else
|
||||
user << "\blue You set the label to \"[tmp_label]\"."
|
||||
src.label_text = tmp_label
|
||||
src.update_name_label()
|
||||
|
||||
proc/update_name_label()
|
||||
if(src.label_text == "")
|
||||
src.name = src.base_name
|
||||
else
|
||||
src.name = "[src.base_name] ([src.label_text])"
|
||||
|
||||
/obj/item/weapon/reagent_containers/glass/beaker
|
||||
name = "beaker"
|
||||
desc = "A beaker. Can hold up to 50 units."
|
||||
icon = 'icons/obj/chemical.dmi'
|
||||
icon_state = "beaker"
|
||||
item_state = "beaker"
|
||||
m_amt = 0
|
||||
g_amt = 500
|
||||
|
||||
on_reagent_change()
|
||||
update_icon()
|
||||
|
||||
pickup(mob/user)
|
||||
..()
|
||||
update_icon()
|
||||
|
||||
dropped(mob/user)
|
||||
..()
|
||||
update_icon()
|
||||
|
||||
attack_hand()
|
||||
..()
|
||||
update_icon()
|
||||
|
||||
update_icon()
|
||||
overlays.Cut()
|
||||
|
||||
if(reagents.total_volume)
|
||||
var/image/filling = image('icons/obj/reagentfillings.dmi', src, "[icon_state]10")
|
||||
|
||||
var/percent = round((reagents.total_volume / volume) * 100)
|
||||
switch(percent)
|
||||
if(0 to 9) filling.icon_state = "[icon_state]-10"
|
||||
if(10 to 24) filling.icon_state = "[icon_state]10"
|
||||
if(25 to 49) filling.icon_state = "[icon_state]25"
|
||||
if(50 to 74) filling.icon_state = "[icon_state]50"
|
||||
if(75 to 79) filling.icon_state = "[icon_state]75"
|
||||
if(80 to 90) filling.icon_state = "[icon_state]80"
|
||||
if(91 to INFINITY) filling.icon_state = "[icon_state]100"
|
||||
|
||||
filling.icon += mix_color_from_reagents(reagents.reagent_list)
|
||||
overlays += filling
|
||||
|
||||
if (!is_open_container())
|
||||
var/image/lid = image(icon, src, "lid_[initial(icon_state)]")
|
||||
overlays += lid
|
||||
|
||||
/obj/item/weapon/reagent_containers/glass/beaker/large
|
||||
name = "large beaker"
|
||||
desc = "A large beaker. Can hold up to 100 units."
|
||||
icon_state = "beakerlarge"
|
||||
g_amt = 5000
|
||||
volume = 100
|
||||
amount_per_transfer_from_this = 10
|
||||
possible_transfer_amounts = list(5,10,15,25,30,50,100)
|
||||
flags = FPRINT | TABLEPASS | OPENCONTAINER
|
||||
|
||||
/obj/item/weapon/reagent_containers/glass/beaker/vial
|
||||
name = "vial"
|
||||
desc = "A small glass vial. Can hold up to 25 units."
|
||||
icon_state = "vial"
|
||||
g_amt = 250
|
||||
volume = 25
|
||||
amount_per_transfer_from_this = 10
|
||||
possible_transfer_amounts = list(5,10,15,25)
|
||||
flags = FPRINT | TABLEPASS | OPENCONTAINER
|
||||
|
||||
/obj/item/weapon/reagent_containers/glass/beaker/cryoxadone
|
||||
New()
|
||||
..()
|
||||
reagents.add_reagent("cryoxadone", 30)
|
||||
update_icon()
|
||||
|
||||
/obj/item/weapon/reagent_containers/glass/beaker/sulphuric
|
||||
New()
|
||||
..()
|
||||
reagents.add_reagent("sacid", 50)
|
||||
update_icon()
|
||||
|
||||
/obj/item/weapon/reagent_containers/glass/beaker/slime
|
||||
New()
|
||||
..()
|
||||
reagents.add_reagent("slimejelly", 50)
|
||||
update_icon()
|
||||
|
||||
/obj/item/weapon/reagent_containers/glass/bucket
|
||||
desc = "It's a bucket."
|
||||
name = "bucket"
|
||||
icon = 'icons/obj/janitor.dmi'
|
||||
icon_state = "bucket"
|
||||
item_state = "bucket"
|
||||
m_amt = 200
|
||||
g_amt = 0
|
||||
w_class = 3.0
|
||||
amount_per_transfer_from_this = 20
|
||||
possible_transfer_amounts = list(10,20,30,50,70)
|
||||
volume = 70
|
||||
flags = FPRINT | OPENCONTAINER
|
||||
|
||||
attackby(var/obj/D, mob/user as mob)
|
||||
if(isprox(D))
|
||||
user << "You add [D] to [src]."
|
||||
del(D)
|
||||
user.put_in_hands(new /obj/item/weapon/bucket_sensor)
|
||||
user.drop_from_inventory(src)
|
||||
del(src)
|
||||
|
||||
// vials are defined twice, what?
|
||||
/*
|
||||
/obj/item/weapon/reagent_containers/glass/beaker/vial
|
||||
name = "vial"
|
||||
desc = "Small glass vial. Looks fragile."
|
||||
icon_state = "vial"
|
||||
g_amt = 500
|
||||
volume = 15
|
||||
amount_per_transfer_from_this = 5
|
||||
possible_transfer_amounts = list(1,5,15)
|
||||
flags = FPRINT | TABLEPASS | OPENCONTAINER */
|
||||
|
||||
/*
|
||||
/obj/item/weapon/reagent_containers/glass/blender_jug
|
||||
name = "Blender Jug"
|
||||
desc = "A blender jug, part of a blender."
|
||||
icon = 'icons/obj/kitchen.dmi'
|
||||
icon_state = "blender_jug_e"
|
||||
volume = 100
|
||||
|
||||
on_reagent_change()
|
||||
switch(src.reagents.total_volume)
|
||||
if(0)
|
||||
icon_state = "blender_jug_e"
|
||||
if(1 to 75)
|
||||
icon_state = "blender_jug_h"
|
||||
if(76 to 100)
|
||||
icon_state = "blender_jug_f"
|
||||
|
||||
/obj/item/weapon/reagent_containers/glass/canister //not used apparantly
|
||||
desc = "It's a canister. Mainly used for transporting fuel."
|
||||
name = "canister"
|
||||
icon = 'icons/obj/tank.dmi'
|
||||
icon_state = "canister"
|
||||
item_state = "canister"
|
||||
m_amt = 300
|
||||
g_amt = 0
|
||||
w_class = 4.0
|
||||
|
||||
amount_per_transfer_from_this = 20
|
||||
possible_transfer_amounts = list(10,20,30,60)
|
||||
volume = 120
|
||||
flags = FPRINT
|
||||
|
||||
/obj/item/weapon/reagent_containers/glass/dispenser
|
||||
name = "reagent glass"
|
||||
desc = "A reagent glass."
|
||||
icon = 'icons/obj/chemical.dmi'
|
||||
icon_state = "beaker0"
|
||||
amount_per_transfer_from_this = 10
|
||||
flags = FPRINT | TABLEPASS | OPENCONTAINER
|
||||
|
||||
/obj/item/weapon/reagent_containers/glass/dispenser/surfactant
|
||||
name = "reagent glass (surfactant)"
|
||||
icon_state = "liquid"
|
||||
|
||||
New()
|
||||
..()
|
||||
reagents.add_reagent("fluorosurfactant", 20)
|
||||
|
||||
*/
|
||||
|
||||
New()
|
||||
..()
|
||||
base_name = name
|
||||
|
||||
examine()
|
||||
set src in view()
|
||||
..()
|
||||
if (!(usr in view(2)) && usr!=src.loc) return
|
||||
usr << "\blue It contains:"
|
||||
if(reagents && reagents.reagent_list.len)
|
||||
usr << "\blue [src.reagents.total_volume] units of liquid."
|
||||
else
|
||||
usr << "\blue Nothing."
|
||||
if (!is_open_container())
|
||||
usr << "\blue Airtight lid seals it completely."
|
||||
|
||||
attack_self()
|
||||
..()
|
||||
if (is_open_container())
|
||||
usr << "<span class = 'notice'>You put the lid on \the [src]."
|
||||
flags ^= OPENCONTAINER
|
||||
else
|
||||
usr << "<span class = 'notice'>You take the lid off \the [src]."
|
||||
flags |= OPENCONTAINER
|
||||
update_icon()
|
||||
|
||||
afterattack(obj/target, mob/user , flag)
|
||||
if (!is_open_container())
|
||||
return
|
||||
|
||||
for(var/type in src.can_be_placed_into)
|
||||
if(istype(target, type))
|
||||
return
|
||||
|
||||
if(ismob(target) && target.reagents && reagents.total_volume)
|
||||
user << "\blue You splash the solution onto [target]."
|
||||
|
||||
var/mob/living/M = target
|
||||
var/list/injected = list()
|
||||
for(var/datum/reagent/R in src.reagents.reagent_list)
|
||||
injected += R.name
|
||||
var/contained = english_list(injected)
|
||||
M.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has been splashed with [src.name] by [user.name] ([user.ckey]). Reagents: [contained]</font>")
|
||||
user.attack_log += text("\[[time_stamp()]\] <font color='red'>Used the [src.name] to splash [M.name] ([M.key]). Reagents: [contained]</font>")
|
||||
msg_admin_attack("[user.name] ([user.ckey]) splashed [M.name] ([M.key]) with [src.name]. Reagents: [contained] (INTENT: [uppertext(user.a_intent)]) (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[user.x];Y=[user.y];Z=[user.z]'>JMP</a>)")
|
||||
|
||||
for(var/mob/O in viewers(world.view, user))
|
||||
O.show_message(text("\red [] has been splashed with something by []!", target, user), 1)
|
||||
src.reagents.reaction(target, TOUCH)
|
||||
spawn(5) src.reagents.clear_reagents()
|
||||
return
|
||||
else if(istype(target, /obj/structure/reagent_dispensers)) //A dispenser. Transfer FROM it TO us.
|
||||
|
||||
if(!target.reagents.total_volume && target.reagents)
|
||||
user << "\red [target] is empty."
|
||||
return
|
||||
|
||||
if(reagents.total_volume >= reagents.maximum_volume)
|
||||
user << "\red [src] is full."
|
||||
return
|
||||
|
||||
var/trans = target.reagents.trans_to(src, target:amount_per_transfer_from_this)
|
||||
user << "\blue You fill [src] with [trans] units of the contents of [target]."
|
||||
|
||||
else if(target.is_open_container() && target.reagents) //Something like a glass. Player probably wants to transfer TO it.
|
||||
if(!reagents.total_volume)
|
||||
user << "\red [src] is empty."
|
||||
return
|
||||
|
||||
if(target.reagents.total_volume >= target.reagents.maximum_volume)
|
||||
user << "\red [target] is full."
|
||||
return
|
||||
|
||||
var/trans = src.reagents.trans_to(target, amount_per_transfer_from_this)
|
||||
user << "\blue You transfer [trans] units of the solution to [target]."
|
||||
|
||||
//Safety for dumping stuff into a ninja suit. It handles everything through attackby() and this is unnecessary.
|
||||
else if(istype(target, /obj/item/clothing/suit/space/space_ninja))
|
||||
return
|
||||
|
||||
else if(istype(target, /obj/machinery/bunsen_burner))
|
||||
return
|
||||
|
||||
else if(istype(target, /obj/machinery/radiocarbon_spectrometer))
|
||||
return
|
||||
|
||||
else if(reagents.total_volume)
|
||||
user << "\blue You splash the solution onto [target]."
|
||||
src.reagents.reaction(target, TOUCH)
|
||||
spawn(5) src.reagents.clear_reagents()
|
||||
return
|
||||
|
||||
attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
if(istype(W, /obj/item/weapon/pen) || istype(W, /obj/item/device/flashlight/pen))
|
||||
var/tmp_label = sanitize(input(user, "Enter a label for [src.name]","Label",src.label_text))
|
||||
if(length(tmp_label) > 10)
|
||||
user << "\red The label can be at most 10 characters long."
|
||||
else
|
||||
user << "\blue You set the label to \"[tmp_label]\"."
|
||||
src.label_text = tmp_label
|
||||
src.update_name_label()
|
||||
|
||||
proc/update_name_label()
|
||||
if(src.label_text == "")
|
||||
src.name = src.base_name
|
||||
else
|
||||
src.name = "[src.base_name] ([src.label_text])"
|
||||
|
||||
/obj/item/weapon/reagent_containers/glass/beaker
|
||||
name = "beaker"
|
||||
desc = "A beaker. Can hold up to 50 units."
|
||||
icon = 'icons/obj/chemical.dmi'
|
||||
icon_state = "beaker"
|
||||
item_state = "beaker"
|
||||
m_amt = 0
|
||||
g_amt = 500
|
||||
|
||||
on_reagent_change()
|
||||
update_icon()
|
||||
|
||||
pickup(mob/user)
|
||||
..()
|
||||
update_icon()
|
||||
|
||||
dropped(mob/user)
|
||||
..()
|
||||
update_icon()
|
||||
|
||||
attack_hand()
|
||||
..()
|
||||
update_icon()
|
||||
|
||||
update_icon()
|
||||
overlays.Cut()
|
||||
|
||||
if(reagents.total_volume)
|
||||
var/image/filling = image('icons/obj/reagentfillings.dmi', src, "[icon_state]10")
|
||||
|
||||
var/percent = round((reagents.total_volume / volume) * 100)
|
||||
switch(percent)
|
||||
if(0 to 9) filling.icon_state = "[icon_state]-10"
|
||||
if(10 to 24) filling.icon_state = "[icon_state]10"
|
||||
if(25 to 49) filling.icon_state = "[icon_state]25"
|
||||
if(50 to 74) filling.icon_state = "[icon_state]50"
|
||||
if(75 to 79) filling.icon_state = "[icon_state]75"
|
||||
if(80 to 90) filling.icon_state = "[icon_state]80"
|
||||
if(91 to INFINITY) filling.icon_state = "[icon_state]100"
|
||||
|
||||
filling.icon += mix_color_from_reagents(reagents.reagent_list)
|
||||
overlays += filling
|
||||
|
||||
if (!is_open_container())
|
||||
var/image/lid = image(icon, src, "lid_[initial(icon_state)]")
|
||||
overlays += lid
|
||||
|
||||
/obj/item/weapon/reagent_containers/glass/beaker/large
|
||||
name = "large beaker"
|
||||
desc = "A large beaker. Can hold up to 100 units."
|
||||
icon_state = "beakerlarge"
|
||||
g_amt = 5000
|
||||
volume = 100
|
||||
amount_per_transfer_from_this = 10
|
||||
possible_transfer_amounts = list(5,10,15,25,30,50,100)
|
||||
flags = FPRINT | TABLEPASS | OPENCONTAINER
|
||||
|
||||
/obj/item/weapon/reagent_containers/glass/beaker/noreact
|
||||
name = "cryostasis beaker"
|
||||
desc = "A cryostasis beaker that allows for chemical storage without reactions. Can hold up to 50 units."
|
||||
icon_state = "beakernoreact"
|
||||
g_amt = 500
|
||||
volume = 50
|
||||
amount_per_transfer_from_this = 10
|
||||
flags = FPRINT | TABLEPASS | OPENCONTAINER | NOREACT
|
||||
|
||||
/obj/item/weapon/reagent_containers/glass/beaker/bluespace
|
||||
name = "bluespace beaker"
|
||||
desc = "A bluespace beaker, powered by experimental bluespace technology and Element Cuban combined with the Compound Pete. Can hold up to 300 units."
|
||||
icon_state = "beakerbluespace"
|
||||
g_amt = 5000
|
||||
volume = 300
|
||||
amount_per_transfer_from_this = 10
|
||||
possible_transfer_amounts = list(5,10,15,25,30,50,100,300)
|
||||
flags = FPRINT | TABLEPASS | OPENCONTAINER
|
||||
|
||||
|
||||
/obj/item/weapon/reagent_containers/glass/beaker/vial
|
||||
name = "vial"
|
||||
desc = "A small glass vial. Can hold up to 25 units."
|
||||
icon_state = "vial"
|
||||
g_amt = 250
|
||||
volume = 25
|
||||
amount_per_transfer_from_this = 10
|
||||
possible_transfer_amounts = list(5,10,15,25)
|
||||
flags = FPRINT | TABLEPASS | OPENCONTAINER
|
||||
|
||||
/obj/item/weapon/reagent_containers/glass/beaker/cryoxadone
|
||||
New()
|
||||
..()
|
||||
reagents.add_reagent("cryoxadone", 30)
|
||||
update_icon()
|
||||
|
||||
/obj/item/weapon/reagent_containers/glass/beaker/sulphuric
|
||||
New()
|
||||
..()
|
||||
reagents.add_reagent("sacid", 50)
|
||||
update_icon()
|
||||
|
||||
/obj/item/weapon/reagent_containers/glass/beaker/slime
|
||||
New()
|
||||
..()
|
||||
reagents.add_reagent("slimejelly", 50)
|
||||
update_icon()
|
||||
|
||||
/obj/item/weapon/reagent_containers/glass/bucket
|
||||
desc = "It's a bucket."
|
||||
name = "bucket"
|
||||
icon = 'icons/obj/janitor.dmi'
|
||||
icon_state = "bucket"
|
||||
item_state = "bucket"
|
||||
m_amt = 200
|
||||
g_amt = 0
|
||||
w_class = 3.0
|
||||
amount_per_transfer_from_this = 20
|
||||
possible_transfer_amounts = list(10,20,30,50,70)
|
||||
volume = 70
|
||||
flags = FPRINT | OPENCONTAINER
|
||||
|
||||
attackby(var/obj/D, mob/user as mob)
|
||||
if(isprox(D))
|
||||
user << "You add [D] to [src]."
|
||||
del(D)
|
||||
user.put_in_hands(new /obj/item/weapon/bucket_sensor)
|
||||
user.drop_from_inventory(src)
|
||||
del(src)
|
||||
|
||||
// vials are defined twice, what?
|
||||
/*
|
||||
/obj/item/weapon/reagent_containers/glass/beaker/vial
|
||||
name = "vial"
|
||||
desc = "Small glass vial. Looks fragile."
|
||||
icon_state = "vial"
|
||||
g_amt = 500
|
||||
volume = 15
|
||||
amount_per_transfer_from_this = 5
|
||||
possible_transfer_amounts = list(1,5,15)
|
||||
flags = FPRINT | TABLEPASS | OPENCONTAINER */
|
||||
|
||||
/*
|
||||
/obj/item/weapon/reagent_containers/glass/blender_jug
|
||||
name = "Blender Jug"
|
||||
desc = "A blender jug, part of a blender."
|
||||
icon = 'icons/obj/kitchen.dmi'
|
||||
icon_state = "blender_jug_e"
|
||||
volume = 100
|
||||
|
||||
on_reagent_change()
|
||||
switch(src.reagents.total_volume)
|
||||
if(0)
|
||||
icon_state = "blender_jug_e"
|
||||
if(1 to 75)
|
||||
icon_state = "blender_jug_h"
|
||||
if(76 to 100)
|
||||
icon_state = "blender_jug_f"
|
||||
|
||||
/obj/item/weapon/reagent_containers/glass/canister //not used apparantly
|
||||
desc = "It's a canister. Mainly used for transporting fuel."
|
||||
name = "canister"
|
||||
icon = 'icons/obj/tank.dmi'
|
||||
icon_state = "canister"
|
||||
item_state = "canister"
|
||||
m_amt = 300
|
||||
g_amt = 0
|
||||
w_class = 4.0
|
||||
|
||||
amount_per_transfer_from_this = 20
|
||||
possible_transfer_amounts = list(10,20,30,60)
|
||||
volume = 120
|
||||
flags = FPRINT
|
||||
|
||||
/obj/item/weapon/reagent_containers/glass/dispenser
|
||||
name = "reagent glass"
|
||||
desc = "A reagent glass."
|
||||
icon = 'icons/obj/chemical.dmi'
|
||||
icon_state = "beaker0"
|
||||
amount_per_transfer_from_this = 10
|
||||
flags = FPRINT | TABLEPASS | OPENCONTAINER
|
||||
|
||||
/obj/item/weapon/reagent_containers/glass/dispenser/surfactant
|
||||
name = "reagent glass (surfactant)"
|
||||
icon_state = "liquid"
|
||||
|
||||
New()
|
||||
..()
|
||||
reagents.add_reagent("fluorosurfactant", 20)
|
||||
|
||||
*/
|
||||
|
||||
@@ -211,6 +211,10 @@
|
||||
|
||||
// attack with hand, switch position
|
||||
/obj/machinery/conveyor_switch/attack_hand(mob/user)
|
||||
if(!allowed(user))
|
||||
user << "<span class='warning'>Access denied.</span>"
|
||||
return
|
||||
|
||||
if(position == 0)
|
||||
if(last_pos < 0)
|
||||
position = 1
|
||||
|
||||
@@ -157,7 +157,7 @@
|
||||
/obj/item/device/destTagger
|
||||
name = "destination tagger"
|
||||
desc = "Used to set the destination of properly wrapped packages."
|
||||
icon_state = "forensic0-old"
|
||||
icon_state = "dest_tagger"
|
||||
var/currTag = 0
|
||||
//The whole system for the sorttype var is determined based on the order of this list,
|
||||
//disposals must always be 1, since anything that's untagged will automatically go to disposals, or sorttype = 1 --Superxpdude
|
||||
|
||||
@@ -1340,6 +1340,28 @@ datum/design/nanopaste
|
||||
build_type = PROTOLATHE
|
||||
materials = list("$metal" = 7000, "$glass" = 7000)
|
||||
build_path = "/obj/item/stack/nanopaste"
|
||||
|
||||
datum/design/bluespacebeaker
|
||||
name = "bluespace beaker"
|
||||
desc = "A bluespace beaker, powered by experimental bluespace technology and Element Cuban combined with the Compound Pete. Can hold up to 300 units."
|
||||
id = "bluespacebeaker"
|
||||
req_tech = list("bluespace" = 2, "materials" = 6)
|
||||
build_type = PROTOLATHE
|
||||
materials = list("$metal" = 3000, "$plasma" = 3000, "$diamond" = 500)
|
||||
reliability_base = 76
|
||||
build_path = "/obj/item/weapon/reagent_containers/glass/beaker/bluespace"
|
||||
category = "Misc"
|
||||
|
||||
datum/design/noreactbeaker
|
||||
name = "cryostasis beaker"
|
||||
desc = "A cryostasis beaker that allows for chemical storage without reactions. Can hold up to 50 units."
|
||||
id = "splitbeaker"
|
||||
req_tech = list("materials" = 2)
|
||||
build_type = PROTOLATHE
|
||||
materials = list("$metal" = 3000)
|
||||
reliability_base = 76
|
||||
build_path = "/obj/item/weapon/reagent_containers/glass/beaker/noreact"
|
||||
category = "Misc"
|
||||
/////////////////////////////////////////
|
||||
/////////////////Weapons/////////////////
|
||||
/////////////////////////////////////////
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
icon_state = "boulder1"
|
||||
density = 1
|
||||
opacity = 1
|
||||
anchored = 1
|
||||
var/excavation_level = 0
|
||||
var/datum/geosample/geological_data
|
||||
var/datum/artifact_find/artifact_find
|
||||
@@ -75,17 +76,14 @@
|
||||
user << "\blue You finish [P.drill_verb] [src]."
|
||||
excavation_level += P.excavation_amount
|
||||
|
||||
var/reveal_prob = 1
|
||||
if(excavation_level >= 95)
|
||||
reveal_prob = 50 + (excavation_level - 90) * (excavation_level - 90)
|
||||
else if(excavation_level >= 90)
|
||||
reveal_prob = 5
|
||||
if(excavation_level >= 100)
|
||||
if(excavation_level > 100)
|
||||
//failure
|
||||
user.visible_message("<font color='red'><b>[src] suddenly crumbles away.</b></font>",\
|
||||
"\red [src] has disintegrated under your onslaught, any secrets it was holding long gone.")
|
||||
"\red [src] has disintegrated under your onslaught, any secrets it was holding are long gone.")
|
||||
del(src)
|
||||
else if(prob(reveal_prob))
|
||||
return
|
||||
|
||||
if(prob(excavation_level))
|
||||
//success
|
||||
if(artifact_find)
|
||||
var/spawn_type = artifact_find.artifact_find_type
|
||||
|
||||
@@ -1,242 +0,0 @@
|
||||
//Part of ISaidNo's public release around July 2011(ish), multiple changes
|
||||
//many thanks
|
||||
|
||||
#define PLASMA_SPAWN 1
|
||||
#define N2_SPAWN 2
|
||||
#define CO2_SPAWN 3
|
||||
#define RADIATE 4
|
||||
#define VIRUS 5
|
||||
#define HEAT 6
|
||||
#define COLD 7
|
||||
|
||||
/obj/machinery/artifact
|
||||
name = "alien artifact"
|
||||
desc = "A large alien device."
|
||||
icon = 'icons/obj/xenoarchaeology.dmi'
|
||||
icon_state = "ano00"
|
||||
var/icon_num = 0
|
||||
anchored = 0
|
||||
density = 1
|
||||
var/origin = null // Used in the randomisation/research of the artifact.
|
||||
var/activated = 0 // Whether or not the artifact has been unlocked.
|
||||
var/charged = 1 // Whether the artifact is ready to have it's effect.
|
||||
var/chargetime = 0 // How much time until the artifact is charged.
|
||||
var/recharge = 5 // How long does it take this artifact to recharge?
|
||||
var/display_id = "" // Artifact ID to display once successfully scanned
|
||||
var/datum/artifact_effect/my_effect = null
|
||||
var/being_used = 0
|
||||
|
||||
/obj/machinery/artifact/New()
|
||||
..()
|
||||
// Origin and appearance randomisation
|
||||
|
||||
my_effect = new()
|
||||
|
||||
|
||||
icon_num = rand(0,5)
|
||||
icon_state = "ano[icon_num]0"
|
||||
|
||||
// Power randomisation
|
||||
my_effect.trigger = pick("force","energy","chemical","heat","touch","presence")
|
||||
if (my_effect.trigger == "chemical")
|
||||
my_effect.triggerX = pick("hydrogen","corrosive","volatile","toxic")
|
||||
|
||||
my_effect.effecttype = pick("healing","injure","stun","roboheal","robohurt","cellcharge","celldrain","planthelper","forcefield","teleport","dnaswitch","emp","sleepy")
|
||||
|
||||
// Select range based on the power
|
||||
var/canworldpulse = 1
|
||||
switch(my_effect.effecttype)
|
||||
if("healing")
|
||||
my_effect.effectmode = pick("aura","pulse","contact")
|
||||
if("injure")
|
||||
my_effect.effectmode = pick("aura","pulse","contact")
|
||||
if("stun")
|
||||
my_effect.effectmode = pick("aura","pulse","contact")
|
||||
if("roboheal")
|
||||
my_effect.effectmode = pick("aura","pulse","contact")
|
||||
if("robohurt")
|
||||
my_effect.effectmode = pick("aura","pulse","contact")
|
||||
if("sleepy")
|
||||
my_effect.effectmode = pick("aura","pulse","contact")
|
||||
if("cellcharge")
|
||||
my_effect.effectmode = pick("aura","pulse")
|
||||
if("celldrain")
|
||||
my_effect.effectmode = pick("aura","pulse")
|
||||
if("planthelper")
|
||||
my_effect.effectmode = pick("aura","pulse")
|
||||
canworldpulse = 0
|
||||
if("forcefield")
|
||||
my_effect.effectmode = "contact"
|
||||
canworldpulse = 0
|
||||
if("teleport")
|
||||
my_effect.effectmode = pick("pulse","contact")
|
||||
if("genderswitch")
|
||||
my_effect.effectmode = pick("pulse","contact")
|
||||
if("emp")
|
||||
my_effect.effectmode = pick("pulse","contact")
|
||||
|
||||
// Recharge timer & range setup
|
||||
if (my_effect.effectmode == "aura")
|
||||
my_effect.aurarange = rand(1,4)
|
||||
if (my_effect.effectmode == "contact")
|
||||
src.recharge = rand(5,15)
|
||||
if (my_effect.effectmode == "pulse")
|
||||
my_effect.aurarange = rand(2,14)
|
||||
src.recharge = rand(5,20)
|
||||
if (canworldpulse == 1 && prob(1))
|
||||
my_effect.effectmode = "worldpulse"
|
||||
src.recharge = rand(40,120)
|
||||
|
||||
/*
|
||||
display_id += pick("kappa","sigma","antaeres","beta","lorard","omicron","iota","upsilon","omega","gamma","delta")
|
||||
display_id += "-"
|
||||
display_id += num2text(rand(100,999))
|
||||
*/
|
||||
|
||||
/obj/machinery/artifact/Del()
|
||||
..()
|
||||
my_effect.HaltEffect()
|
||||
|
||||
/obj/machinery/artifact/attack_hand(var/mob/user as mob)
|
||||
if (istype(user, /mob/living/silicon/ai) || istype(user, /mob/dead/)) return
|
||||
if (istype(user, /mob/living/silicon/robot))
|
||||
if (get_dist(user, src) > 1)
|
||||
user << "\red You can't reach [src] from here."
|
||||
return
|
||||
if(ishuman(user) && istype(user:gloves,/obj/item/clothing/gloves))
|
||||
return ..()
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<b>[]</b> touches [].", user, src), 1)
|
||||
src.add_fingerprint(user)
|
||||
src.Artifact_Contact(user)
|
||||
|
||||
/obj/machinery/artifact/attackby(obj/item/weapon/W as obj, mob/living/user as mob)
|
||||
/*if (istype(W, /obj/item/weapon/cargotele))
|
||||
W:cargoteleport(src, user)
|
||||
return*/
|
||||
if (my_effect.trigger == "chemical" && istype(W, /obj/item/weapon/reagent_containers/))
|
||||
switch(my_effect.triggerX)
|
||||
if("hydrogen")
|
||||
if (W.reagents.has_reagent("hydrogen", 1) || W.reagents.has_reagent("water", 1))
|
||||
src.Artifact_Activate()
|
||||
return
|
||||
if("corrosive")
|
||||
if (W.reagents.has_reagent("acid", 1) || W.reagents.has_reagent("pacid", 1) || W.reagents.has_reagent("diethylamine", 1))
|
||||
src.Artifact_Activate()
|
||||
return
|
||||
if("volatile")
|
||||
if (W.reagents.has_reagent("plasma", 1) || W.reagents.has_reagent("thermite", 1))
|
||||
src.Artifact_Activate()
|
||||
return
|
||||
if("toxic")
|
||||
if (W.reagents.has_reagent("toxin", 1) || W.reagents.has_reagent("cyanide", 1) || W.reagents.has_reagent("amanitin", 1) || W.reagents.has_reagent("neurotoxin", 1))
|
||||
src.Artifact_Activate()
|
||||
return
|
||||
..()
|
||||
if (my_effect.trigger == "force" && W.force >= 10 && !src.activated) src.Artifact_Activate()
|
||||
if (my_effect.trigger == "energy")
|
||||
if (istype(W,/obj/item/weapon/melee/baton) && W:status) src.Artifact_Activate()
|
||||
if (istype(W,/obj/item/weapon/melee/energy)) src.Artifact_Activate()
|
||||
if (istype(W,/obj/item/weapon/melee/cultblade)) src.Artifact_Activate()
|
||||
if (istype(W,/obj/item/weapon/gun/energy/)) src.Artifact_Activate()
|
||||
if (istype(W,/obj/item/device/multitool)) src.Artifact_Activate()
|
||||
if (istype(W,/obj/item/weapon/card/emag)) src.Artifact_Activate()
|
||||
if (my_effect.trigger == "heat")
|
||||
if (istype(W,/obj/item/weapon/match) && W:lit) src.Artifact_Activate()
|
||||
if (istype(W, /obj/item/weapon/weldingtool) && W:welding) src.Artifact_Activate()
|
||||
if (istype(W, /obj/item/weapon/lighter) && W:lit) src.Artifact_Activate()
|
||||
|
||||
//Bump(atom/A)
|
||||
|
||||
/obj/machinery/artifact/Bumped(M as mob|obj)
|
||||
if (istype(M,/obj/item/weapon/) && my_effect.trigger == "force" && M:throwforce >= 10) src.Artifact_Activate()
|
||||
|
||||
/obj/machinery/artifact/bullet_act(var/obj/item/projectile/P)
|
||||
if (my_effect.trigger == "force")
|
||||
if(istype(P,/obj/item/projectile/bullet)) src.Artifact_Activate()
|
||||
else if(istype(P,/obj/item/projectile/hivebotbullet)) src.Artifact_Activate()
|
||||
if (my_effect.trigger == "energy")
|
||||
if(istype(P,/obj/item/projectile/beam)) src.Artifact_Activate()
|
||||
else if(istype(P,/obj/item/projectile/ion)) src.Artifact_Activate()
|
||||
else if(istype(P,/obj/item/projectile/energy)) src.Artifact_Activate()
|
||||
if (my_effect.trigger == "heat")
|
||||
if(istype(P,/obj/item/projectile/temp)) src.Artifact_Activate()
|
||||
|
||||
/obj/machinery/artifact/ex_act(severity)
|
||||
switch(severity)
|
||||
if(1.0) del src
|
||||
if(2.0)
|
||||
if (prob(50)) del src
|
||||
if (my_effect.trigger == "force") src.Artifact_Activate()
|
||||
if (my_effect.trigger == "heat") src.Artifact_Activate()
|
||||
if(3.0)
|
||||
if (my_effect.trigger == "force") src.Artifact_Activate()
|
||||
if (my_effect.trigger == "heat") src.Artifact_Activate()
|
||||
return
|
||||
|
||||
/obj/machinery/artifact/temperature_expose(null, temp, volume)
|
||||
if (my_effect.trigger == "heat") src.Artifact_Activate()
|
||||
|
||||
/obj/machinery/artifact/process()
|
||||
if (!src.activated)
|
||||
return
|
||||
if (chargetime > 0)
|
||||
chargetime -= 1
|
||||
else
|
||||
src.charged = 1
|
||||
|
||||
my_effect.UpdateEffect(src.loc)
|
||||
|
||||
//activate
|
||||
if( (my_effect.effectmode == "pulse" || my_effect.effecttype == "worldpulse") && activated)
|
||||
if(src.charged && my_effect.DoEffect(src))
|
||||
src.charged = 0
|
||||
src.chargetime = src.recharge
|
||||
|
||||
/obj/machinery/artifact/proc/Artifact_Activate()
|
||||
src.activated = !src.activated
|
||||
var/display_msg = ""
|
||||
if(activated)
|
||||
if(prob(30))
|
||||
switch(rand(4))
|
||||
if(0)
|
||||
display_msg = "momentarily glows brightly!"
|
||||
if(1)
|
||||
display_msg = "distorts slightly for a moment!"
|
||||
if(2)
|
||||
display_msg = "makes a slightly clicking noise!"
|
||||
if(3)
|
||||
display_msg = "flickers slightly!"
|
||||
if(4)
|
||||
display_msg = "vibrates!"
|
||||
else
|
||||
my_effect.HaltEffect()
|
||||
if(prob(30))
|
||||
switch(rand(2))
|
||||
if(0)
|
||||
display_msg = "grows dull!"
|
||||
if(1)
|
||||
display_msg = "fades in intensity!"
|
||||
if(2)
|
||||
display_msg = "suddenly becomes very quiet!"
|
||||
|
||||
icon_state = "ano[icon_num][activated]"
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<b>[]</b> [display_msg]", src), 1)
|
||||
|
||||
/obj/machinery/artifact/proc/Artifact_Contact(var/mob/user as mob)
|
||||
// Trigger Code
|
||||
if (istype (user,/mob/living/carbon/) && my_effect.trigger == "touch" && !src.activated) src.Artifact_Activate()
|
||||
else if (my_effect.trigger != "touch" && !src.activated) user << "Nothing happens."
|
||||
|
||||
if (my_effect.effectmode == "contact" && src.activated && src.charged)
|
||||
my_effect.DoEffect(user)
|
||||
src.charged = 0
|
||||
src.chargetime = src.recharge
|
||||
|
||||
// this was used in QM for a time but it fell into disuse and wasn't removed, the purpose being to check if an artifact
|
||||
// was benevolent or malicious, to determine whether QMs would be paid or punished for shipping it
|
||||
|
||||
/obj/machinery/artifact/Move()
|
||||
..()
|
||||
my_effect.update_move(src, src.loc)
|
||||
@@ -1,542 +0,0 @@
|
||||
//
|
||||
|
||||
/datum/artifact_effect
|
||||
var/artifact_id = "" // Display ID of the spawning artifact
|
||||
var/trigger = "touch" // What activates it?
|
||||
var/triggerX = "none" // Used for more varied triggers
|
||||
var/effecttype = "healing" // What does it do?
|
||||
var/effectmode = "aura" // How does it carry out the effect?
|
||||
var/aurarange = 4 // How far the artifact will extend an aura effect.
|
||||
var/list/created_field
|
||||
var/archived_loc
|
||||
|
||||
/datum/artifact_effect/New()
|
||||
//
|
||||
created_field = new()
|
||||
|
||||
/datum/artifact_effect/proc/GetOriginString(var/origin)
|
||||
|
||||
/datum/artifact_effect/proc/GetEffectString(var/effect)
|
||||
|
||||
/datum/artifact_effect/proc/GetTriggerString(var/trigger)
|
||||
|
||||
/datum/artifact_effect/proc/GetRangeString(var/range)
|
||||
switch(effectmode)
|
||||
if("aura") return "Constant Short-Range Energy Field"
|
||||
if("pulse")
|
||||
if(aurarange > 7) return "Long Range Energy Pulses"
|
||||
else return "Medium Range Energy Pulses"
|
||||
if("worldpulse") return "Extreme Range Energy Pulses"
|
||||
if("contact") return "Requires contact with subject"
|
||||
else return "Unknown Range"
|
||||
|
||||
/datum/artifact_effect/proc/HaltEffect()
|
||||
for(var/obj/effect/energy_field/F in created_field)
|
||||
created_field.Remove(F)
|
||||
del F
|
||||
|
||||
/datum/artifact_effect/proc/UpdateEffect(var/atom/originator)
|
||||
/*for(var/obj/effect/energy_field/F in created_field)
|
||||
created_field.Remove(F)
|
||||
del F*/
|
||||
if(originator.loc != archived_loc)
|
||||
archived_loc = originator.loc
|
||||
update_move(originator)
|
||||
|
||||
for(var/obj/effect/energy_field/E in created_field)
|
||||
if(E.strength < 5)
|
||||
E.Strengthen(0.2)
|
||||
|
||||
/datum/artifact_effect/proc/DoEffect(var/atom/originator)
|
||||
archived_loc = originator.loc
|
||||
if (src.effectmode == "contact")
|
||||
var/mob/living/user = originator
|
||||
if(!user)
|
||||
return
|
||||
switch(src.effecttype)
|
||||
if("healing")
|
||||
//caeltodo
|
||||
if (istype(user, /mob/living/carbon/human/))
|
||||
user << "\blue You feel a soothing energy invigorate you."
|
||||
|
||||
var/mob/living/carbon/human/H = user
|
||||
for(var/datum/organ/external/affecting in H.organs)
|
||||
if(!affecting) continue
|
||||
if(!istype(affecting, /datum/organ/external)) continue
|
||||
affecting.heal_damage(25, 25) //fixes getting hit after ingestion, killing you when game updates organ health
|
||||
//user:heal_organ_damage(25, 25)
|
||||
//
|
||||
user.adjustOxyLoss(-25)
|
||||
user.adjustToxLoss(-25)
|
||||
user.adjustBruteLoss(-25)
|
||||
user.adjustFireLoss(-25)
|
||||
user.adjustBrainLoss(-25)
|
||||
user.radiation -= min(user.radiation, 25)
|
||||
user.nutrition += 50
|
||||
H.bodytemperature = initial(H.bodytemperature)
|
||||
//
|
||||
H.vessel.add_reagent("blood",50)
|
||||
spawn(1)
|
||||
H.fixblood()
|
||||
H.regenerate_icons()
|
||||
return 1
|
||||
//
|
||||
if (istype(user, /mob/living/carbon/monkey/))
|
||||
user << "\blue You feel a soothing energy invigorate you."
|
||||
user.adjustOxyLoss(-25)
|
||||
user.adjustToxLoss(-25)
|
||||
user.adjustBruteLoss(-25)
|
||||
user.adjustFireLoss(-25)
|
||||
user.adjustBrainLoss(-25)
|
||||
return 1
|
||||
else user << "Nothing happens."
|
||||
if("injure")
|
||||
if (istype(user, /mob/living/carbon/))
|
||||
user << "\red A painful discharge of energy strikes you!"
|
||||
user.adjustOxyLoss(rand(5,25))
|
||||
user.adjustToxLoss(rand(5,25))
|
||||
user.adjustBruteLoss(rand(5,25))
|
||||
user.adjustFireLoss(rand(5,25))
|
||||
user.adjustBrainLoss(rand(5,25))
|
||||
user.radiation += 25
|
||||
user.nutrition -= min(50, user.nutrition)
|
||||
user.make_dizzy(6)
|
||||
user.weakened += 6
|
||||
return 1
|
||||
else user << "Nothing happens."
|
||||
if("stun")
|
||||
if (istype(user, /mob/living/carbon/))
|
||||
user << "\red A powerful force overwhelms your consciousness."
|
||||
user.weakened += 45
|
||||
user.stuttering += 45
|
||||
if(prob(50))
|
||||
user.stunned += rand(1,10)
|
||||
return 1
|
||||
else user << "Nothing happens."
|
||||
if("roboheal")
|
||||
if (istype(user, /mob/living/silicon/robot))
|
||||
user << "\blue Your systems report damaged components mending by themselves!"
|
||||
user.adjustBruteLoss(rand(-10,-30))
|
||||
user.adjustFireLoss(rand(-10,-30))
|
||||
return 1
|
||||
else user << "Nothing happens."
|
||||
if("robohurt")
|
||||
if (istype(user, /mob/living/silicon/robot))
|
||||
user << "\red Your systems report severe damage has been inflicted!"
|
||||
user.adjustBruteLoss(rand(10,50))
|
||||
user.adjustFireLoss(rand(10,50))
|
||||
return 1
|
||||
else user << "Nothing happens."
|
||||
if("forcefield")
|
||||
while(created_field.len < 16)
|
||||
var/obj/effect/energy_field/E = new (locate(user.x,user.y,user.z))
|
||||
created_field.Add(E)
|
||||
E.strength = 1
|
||||
E.density = 1
|
||||
E.anchored = 1
|
||||
E.invisibility = 0
|
||||
return 1
|
||||
if("teleport")
|
||||
var/list/randomturfs = new/list()
|
||||
for(var/turf/T in orange(user, 50))
|
||||
if(!istype(T, /turf/simulated/floor) || T.density)
|
||||
continue
|
||||
randomturfs.Add(T)
|
||||
if(randomturfs.len > 0)
|
||||
user << "\red You are suddenly zapped away elsewhere!"
|
||||
if (user.buckled)
|
||||
user.buckled.unbuckle()
|
||||
user.loc = pick(randomturfs)
|
||||
var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread()
|
||||
sparks.set_up(3, 0, get_turf(originator)) //no idea what the 0 is
|
||||
sparks.start()
|
||||
return 1
|
||||
if("sleepy")
|
||||
user << pick("\blue You feel like taking a nap.","\blue You feel a yawn coming on.","\blue You feel a little tired.")
|
||||
user.drowsyness = min(user.drowsyness + rand(5,25), 50)
|
||||
user.eye_blurry = min(user.eye_blurry + rand(1,3), 50)
|
||||
return 1
|
||||
else if (src.effectmode == "aura")
|
||||
switch(src.effecttype)
|
||||
//caeltodo
|
||||
if("healing")
|
||||
for (var/mob/living/carbon/M in range(src.aurarange,originator))
|
||||
if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly))
|
||||
continue
|
||||
if(prob(10)) M << "\blue You feel a soothing energy radiating from something nearby."
|
||||
M.adjustBruteLoss(-1)
|
||||
M.adjustFireLoss(-1)
|
||||
M.adjustToxLoss(-1)
|
||||
M.adjustOxyLoss(-1)
|
||||
M.adjustBrainLoss(-1)
|
||||
M.updatehealth()
|
||||
return 1
|
||||
if("injure")
|
||||
for (var/mob/living/carbon/M in range(src.aurarange,originator))
|
||||
if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly))
|
||||
continue
|
||||
if(prob(10)) M << "\red You feel a painful force radiating from something nearby."
|
||||
M.adjustBruteLoss(1)
|
||||
M.adjustFireLoss(1)
|
||||
M.adjustToxLoss(1)
|
||||
M.adjustOxyLoss(1)
|
||||
M.adjustBrainLoss(1)
|
||||
M.updatehealth()
|
||||
return 1
|
||||
if("stun")
|
||||
for (var/mob/living/carbon/M in range(src.aurarange,originator))
|
||||
if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly))
|
||||
continue
|
||||
if(prob(10)) M << "\red Energy radiating from the [originator] is making you feel numb."
|
||||
if(prob(20))
|
||||
M << "\red Your body goes numb for a moment."
|
||||
M.stunned += 2
|
||||
M.weakened += 2
|
||||
M.stuttering += 2
|
||||
return 1
|
||||
if("roboheal")
|
||||
for (var/mob/living/silicon/robot/M in range(src.aurarange,originator))
|
||||
if(prob(10)) M << "\blue SYSTEM ALERT: Beneficial energy field detected!"
|
||||
M.adjustBruteLoss(-1)
|
||||
M.adjustFireLoss(-1)
|
||||
M.updatehealth()
|
||||
return 1
|
||||
if("robohurt")
|
||||
for (var/mob/living/silicon/robot/M in range(src.aurarange,originator))
|
||||
if(prob(10)) M << "\red SYSTEM ALERT: Harmful energy field detected!"
|
||||
M.adjustBruteLoss(1)
|
||||
M.adjustFireLoss(1)
|
||||
M.updatehealth()
|
||||
return 1
|
||||
if("cellcharge")
|
||||
for (var/obj/machinery/power/apc/C in range(src.aurarange,originator))
|
||||
for (var/obj/item/weapon/cell/B in C.contents)
|
||||
B.charge += 10
|
||||
for (var/obj/machinery/power/smes/S in range (src.aurarange,originator)) S.charge += 20
|
||||
for (var/mob/living/silicon/robot/M in range(src.aurarange,originator))
|
||||
for (var/obj/item/weapon/cell/D in M.contents)
|
||||
D.charge += 10
|
||||
if(prob(10)) M << "\blue SYSTEM ALERT: Energy boosting field detected!"
|
||||
return 1
|
||||
if("celldrain")
|
||||
for (var/obj/machinery/power/apc/C in range(src.aurarange,originator))
|
||||
for (var/obj/item/weapon/cell/B in C.contents)
|
||||
B.charge = max(B.charge-10,0)
|
||||
for (var/obj/machinery/power/smes/S in range (src.aurarange,originator))
|
||||
S.charge = max(S.charge-20,0)
|
||||
for (var/mob/living/silicon/robot/M in range(src.aurarange,originator))
|
||||
for (var/obj/item/weapon/cell/D in M.contents)
|
||||
D.charge = max(D.charge-10,0)
|
||||
if(prob(10)) M << "\red SYSTEM ALERT: Energy draining field detected!"
|
||||
return 1
|
||||
if("planthelper")
|
||||
for (var/obj/machinery/hydroponics/H in range(src.aurarange,originator))
|
||||
//makes weeds and shrooms and stuff more potent too
|
||||
if(H.planted)
|
||||
H.waterlevel += 2
|
||||
H.nutrilevel += 2
|
||||
if(H.toxic > 0)
|
||||
H.toxic -= 1
|
||||
H.health += 1
|
||||
if(H.pestlevel > 0)
|
||||
H.pestlevel -= 1
|
||||
if(H.weedlevel > 0)
|
||||
H.weedlevel -= 1
|
||||
H.lastcycle += 5
|
||||
return 1
|
||||
if("sleepy")
|
||||
for (var/mob/living/carbon/M in range(src.aurarange,originator))
|
||||
if(prob(10))
|
||||
M << pick("\blue You feel like taking a nap.","\blue You feel a yawn coming on.","\blue You feel a little tired.")
|
||||
M.drowsyness = min(M.drowsyness + 1, 25)
|
||||
M.eye_blurry = min(M.eye_blurry + 1, 25)
|
||||
return 1
|
||||
else if (src.effectmode == "pulse")
|
||||
for(var/mob/O in viewers(originator, null))
|
||||
O.show_message(text("<b>[]</b> emits a pulse of energy!", originator), 1)
|
||||
switch(src.effecttype)
|
||||
//caeltodo
|
||||
if("healing")
|
||||
for (var/mob/living/carbon/M in range(src.aurarange,originator))
|
||||
if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly))
|
||||
continue
|
||||
M << "\blue A wave of energy invigorates you."
|
||||
M.adjustBruteLoss(-5)
|
||||
M.adjustFireLoss(-5)
|
||||
M.adjustToxLoss(-5)
|
||||
M.adjustOxyLoss(-5)
|
||||
M.adjustBrainLoss(-5)
|
||||
M.updatehealth()
|
||||
return 1
|
||||
if("injure")
|
||||
for (var/mob/living/carbon/M in range(src.aurarange,originator))
|
||||
if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly))
|
||||
continue
|
||||
M << "\red A wave of energy causes you great pain!"
|
||||
M.adjustBruteLoss(5)
|
||||
M.adjustFireLoss(5)
|
||||
M.adjustToxLoss(5)
|
||||
M.adjustOxyLoss(5)
|
||||
M.adjustBrainLoss(5)
|
||||
M.make_dizzy(6)
|
||||
M.weakened += 3
|
||||
M.updatehealth()
|
||||
return 1
|
||||
if("stun")
|
||||
for (var/mob/living/carbon/M in range(src.aurarange,originator))
|
||||
if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly))
|
||||
continue
|
||||
M << "\red A wave of energy overwhelms your senses!"
|
||||
M.paralysis += 3
|
||||
M.weakened += 4
|
||||
M.stuttering += 4
|
||||
return 1
|
||||
if("roboheal")
|
||||
for (var/mob/living/silicon/robot/M in range(src.aurarange,originator))
|
||||
M << "\blue SYSTEM ALERT: Structural damage has been repaired by energy pulse!"
|
||||
M.adjustBruteLoss(-10)
|
||||
M.adjustFireLoss(-10)
|
||||
M.updatehealth()
|
||||
return 1
|
||||
if("robohurt")
|
||||
for (var/mob/living/silicon/robot/M in range(src.aurarange,originator))
|
||||
M << "\red SYSTEM ALERT: Structural damage inflicted by energy pulse!"
|
||||
M.adjustBruteLoss(10)
|
||||
M.adjustFireLoss(10)
|
||||
M.updatehealth()
|
||||
return 1
|
||||
if("cellcharge")
|
||||
for (var/obj/machinery/power/apc/C in range(src.aurarange,originator))
|
||||
for (var/obj/item/weapon/cell/B in C.contents)
|
||||
B.charge += 250
|
||||
for (var/obj/machinery/power/smes/S in range (src.aurarange,originator)) S.charge += 400
|
||||
for (var/mob/living/silicon/robot/M in range(src.aurarange,originator))
|
||||
for (var/obj/item/weapon/cell/D in M.contents)
|
||||
D.charge += 250
|
||||
M << "\blue SYSTEM ALERT: Large energy boost detected!"
|
||||
return 1
|
||||
if("celldrain")
|
||||
for (var/obj/machinery/power/apc/C in range(src.aurarange,originator))
|
||||
for (var/obj/item/weapon/cell/B in C.contents)
|
||||
B.charge = max(B.charge-500,0)
|
||||
for (var/obj/machinery/power/smes/S in range (src.aurarange,originator))
|
||||
S.charge = max(S.charge-400,0)
|
||||
for (var/mob/living/silicon/robot/M in range(src.aurarange,originator))
|
||||
for (var/obj/item/weapon/cell/D in M.contents)
|
||||
D.charge = max(D.charge-500,0)
|
||||
M << "\red SYSTEM ALERT: Severe energy drain detected!"
|
||||
return 1
|
||||
if("planthelper")
|
||||
//makes weeds and shrooms and stuff more potent too
|
||||
for (var/obj/machinery/hydroponics/H in range(src.aurarange,originator))
|
||||
if(H.planted)
|
||||
H.dead = 0
|
||||
H.waterlevel = 200
|
||||
H.nutrilevel = 200
|
||||
H.toxic = 0
|
||||
H.health = 100
|
||||
H.pestlevel = 0
|
||||
H.weedlevel = 0
|
||||
H.lastcycle = H.cycledelay
|
||||
return 1
|
||||
if("teleport")
|
||||
for (var/mob/living/M in range(src.aurarange,originator))
|
||||
if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly))
|
||||
continue
|
||||
var/list/randomturfs = new/list()
|
||||
for(var/turf/T in orange(M, 30))
|
||||
if(!istype(T, /turf/simulated/floor) || T.density)
|
||||
continue
|
||||
randomturfs.Add(T)
|
||||
if(randomturfs.len > 0)
|
||||
M << "\red You are displaced by a strange force!"
|
||||
if(M.buckled)
|
||||
M.buckled.unbuckle()
|
||||
M.loc = pick(randomturfs)
|
||||
var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread()
|
||||
sparks.set_up(3, 0, get_turf(originator)) //no idea what the 0 is
|
||||
sparks.start()
|
||||
return 1
|
||||
if("dnaswitch")
|
||||
for(var/mob/living/H in range(src.aurarange,originator))
|
||||
if(ishuman(H) && istype(H:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(H:head,/obj/item/clothing/head/bio_hood/anomaly))
|
||||
continue
|
||||
|
||||
if(prob(30))
|
||||
H << pick("\green You feel a little different.","\green You feel strange.","\green You feel different.")
|
||||
//todo
|
||||
if (H.gender == FEMALE)
|
||||
H.gender = MALE
|
||||
else
|
||||
H.gender = FEMALE
|
||||
/*H.dna.ready_dna(H)
|
||||
H.update_body()
|
||||
H.update_face()*/
|
||||
return 1
|
||||
if("emp")
|
||||
empulse(get_turf(originator), aurarange/2, aurarange)
|
||||
return 1
|
||||
if("sleepy")
|
||||
for (var/mob/living/carbon/M in range(src.aurarange,originator))
|
||||
if(prob(30))
|
||||
M << pick("\blue You feel like taking a nap.","\blue You feel a yawn coming on.","\blue You feel a little tired.")
|
||||
if(prob(50))
|
||||
M.drowsyness = min(M.drowsyness + rand(1,5), 25)
|
||||
if(prob(50))
|
||||
M.eye_blurry = min(M.eye_blurry + rand(1,5), 25)
|
||||
return 1
|
||||
else if (src.effectmode == "worldpulse")
|
||||
for(var/mob/O in viewers(originator, null))
|
||||
O.show_message(text("<b>[]</b> emits a powerful burst of energy!", originator), 1)
|
||||
switch(src.effecttype)
|
||||
if("healing")
|
||||
for (var/mob/living/carbon/M in range(200, originator))
|
||||
if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly))
|
||||
continue
|
||||
M << "\blue Waves of soothing energy wash over you."
|
||||
M.adjustBruteLoss(-3)
|
||||
M.adjustFireLoss(-3)
|
||||
M.adjustToxLoss(-3)
|
||||
M.adjustOxyLoss(-3)
|
||||
M.adjustBrainLoss(-3)
|
||||
M.updatehealth()
|
||||
return 1
|
||||
if("injure")
|
||||
for (var/mob/living/carbon/human/M in range(200, originator))
|
||||
M << "\red A wave of painful energy strikes you!"
|
||||
M.adjustBruteLoss(3)
|
||||
M.adjustFireLoss(3)
|
||||
M.adjustToxLoss(3)
|
||||
M.adjustOxyLoss(3)
|
||||
M.adjustBrainLoss(3)
|
||||
M.updatehealth()
|
||||
return 1
|
||||
if("stun")
|
||||
for (var/mob/living/carbon/M in range(200, originator))
|
||||
if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly))
|
||||
continue
|
||||
M << "\red A powerful force causes you to black out momentarily."
|
||||
M.paralysis += 5
|
||||
M.weakened += 8
|
||||
M.stuttering += 8
|
||||
return 1
|
||||
if("roboheal")
|
||||
for (var/mob/living/silicon/robot/M in range(200, originator))
|
||||
M << "\blue SYSTEM ALERT: Structural damage has been repaired by energy pulse!"
|
||||
M.adjustBruteLoss(-5)
|
||||
M.adjustFireLoss(-5)
|
||||
M.updatehealth()
|
||||
return 1
|
||||
if("robohurt")
|
||||
for (var/mob/living/silicon/robot/M in range(200, originator))
|
||||
M << "\red SYSTEM ALERT: Structural damage inflicted by energy pulse!"
|
||||
M.adjustBruteLoss(5)
|
||||
M.adjustFireLoss(5)
|
||||
M.updatehealth()
|
||||
return 1
|
||||
if("cellcharge")
|
||||
for (var/obj/machinery/power/apc/C in range(200, originator))
|
||||
for (var/obj/item/weapon/cell/B in C.contents)
|
||||
B.charge += 100
|
||||
for (var/obj/machinery/power/smes/S in range (src.aurarange,src)) S.charge += 250
|
||||
for (var/mob/living/silicon/robot/M in world)
|
||||
for (var/obj/item/weapon/cell/D in M.contents)
|
||||
D.charge += 100
|
||||
M << "\blue SYSTEM ALERT: Energy boost detected!"
|
||||
return 1
|
||||
if("celldrain")
|
||||
for (var/obj/machinery/power/apc/C in range(200, originator))
|
||||
for (var/obj/item/weapon/cell/B in C.contents)
|
||||
B.charge = max(B.charge-250,0)
|
||||
for (var/obj/machinery/power/smes/S in range (src.aurarange,src))
|
||||
S.charge = max(S.charge-250,0)
|
||||
for (var/mob/living/silicon/robot/M in world)
|
||||
for (var/obj/item/weapon/cell/D in M.contents)
|
||||
D.charge = max(D.charge-250,0)
|
||||
M << "\red SYSTEM ALERT: Energy drain detected!"
|
||||
return 1
|
||||
if("teleport")
|
||||
for (var/mob/living/M in range(200, originator))
|
||||
if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly))
|
||||
continue
|
||||
var/list/randomturfs = new/list()
|
||||
for(var/turf/T in orange(M, 15))
|
||||
if(!istype(T, /turf/simulated/floor) || T.density)
|
||||
continue
|
||||
randomturfs.Add(T)
|
||||
if(randomturfs.len > 0)
|
||||
M << "\red You are displaced by a strange force!"
|
||||
if(M.buckled)
|
||||
M.buckled.unbuckle()
|
||||
M.loc = pick(randomturfs)
|
||||
var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread()
|
||||
sparks.set_up(3, 0, get_turf(originator)) //no idea what the 0 is
|
||||
sparks.start()
|
||||
return 1
|
||||
if("dnaswitch")
|
||||
for(var/mob/living/H in range(200, originator))
|
||||
if(ishuman(H) && istype(H:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(H:head,/obj/item/clothing/head/bio_hood/anomaly))
|
||||
continue
|
||||
|
||||
if(prob(30))
|
||||
H << pick("\green You feel a little different.","\green You feel strange.","\green You feel different.")
|
||||
//todo
|
||||
if (H.gender == FEMALE)
|
||||
H.gender = MALE
|
||||
else
|
||||
H.gender = FEMALE
|
||||
/*H.dna.ready_dna(H)
|
||||
H.update_body()
|
||||
H.update_face()*/
|
||||
return 1
|
||||
if("sleepy")
|
||||
for(var/mob/living/H in range(200, originator))
|
||||
H.drowsyness = min(H.drowsyness + rand(5,15), 50)
|
||||
H.eye_blurry = min(H.eye_blurry + rand(5,15), 50)
|
||||
return 1
|
||||
|
||||
//initially for the force field artifact
|
||||
/datum/artifact_effect/proc/update_move(var/atom/originator)
|
||||
switch(effecttype)
|
||||
if("forcefield")
|
||||
while(created_field.len < 16)
|
||||
//for now, just instantly respawn the fields when they get destroyed
|
||||
var/obj/effect/energy_field/E = new (locate(originator.x,originator.y,originator))
|
||||
created_field.Add(E)
|
||||
E.strength = 1
|
||||
E.density = 1
|
||||
E.anchored = 1
|
||||
E.invisibility = 0
|
||||
|
||||
var/obj/effect/energy_field/E = created_field[1]
|
||||
E.loc = locate(originator.x + 2,originator.y + 2,originator.z)
|
||||
E = created_field[2]
|
||||
E.loc = locate(originator.x + 2,originator.y + 1,originator.z)
|
||||
E = created_field[3]
|
||||
E.loc = locate(originator.x + 2,originator.y,originator.z)
|
||||
E = created_field[4]
|
||||
E.loc = locate(originator.x + 2,originator.y - 1,originator.z)
|
||||
E = created_field[5]
|
||||
E.loc = locate(originator.x + 2,originator.y - 2,originator.z)
|
||||
E = created_field[6]
|
||||
E.loc = locate(originator.x + 1,originator.y + 2,originator.z)
|
||||
E = created_field[7]
|
||||
E.loc = locate(originator.x + 1,originator.y - 2,originator.z)
|
||||
E = created_field[8]
|
||||
E.loc = locate(originator.x,originator.y + 2,originator.z)
|
||||
E = created_field[9]
|
||||
E.loc = locate(originator.x,originator.y - 2,originator.z)
|
||||
E = created_field[10]
|
||||
E.loc = locate(originator.x - 1,originator.y + 2,originator.z)
|
||||
E = created_field[11]
|
||||
E.loc = locate(originator.x - 1,originator.y - 2,originator.z)
|
||||
E = created_field[12]
|
||||
E.loc = locate(originator.x - 2,originator.y + 2,originator.z)
|
||||
E = created_field[13]
|
||||
E.loc = locate(originator.x - 2,originator.y + 1,originator.z)
|
||||
E = created_field[14]
|
||||
E.loc = locate(originator.x - 2,originator.y,originator.z)
|
||||
E = created_field[15]
|
||||
E.loc = locate(originator.x - 2,originator.y - 1,originator.z)
|
||||
E = created_field[16]
|
||||
E.loc = locate(originator.x - 2,originator.y - 2,originator.z)
|
||||
@@ -324,26 +324,27 @@
|
||||
if(26)
|
||||
//energy gun
|
||||
var/spawn_type = pick(\
|
||||
/obj/item/weapon/gun/energy/laser/practice;100,\
|
||||
/obj/item/weapon/gun/energy/laser;75,\
|
||||
/obj/item/weapon/gun/energy/xray;50,\
|
||||
/obj/item/weapon/gun/energy/laser/captain;25,\
|
||||
)
|
||||
var/obj/item/weapon/gun/energy/new_gun = new spawn_type(src.loc)
|
||||
new_item = new_gun
|
||||
new_item.icon_state = "egun[rand(1,6)]"
|
||||
/obj/item/weapon/gun/energy/laser/practice,\
|
||||
/obj/item/weapon/gun/energy/laser,\
|
||||
/obj/item/weapon/gun/energy/xray,\
|
||||
/obj/item/weapon/gun/energy/laser/captain)
|
||||
if(spawn_type)
|
||||
var/obj/item/weapon/gun/energy/new_gun = new spawn_type(src.loc)
|
||||
new_item = new_gun
|
||||
new_item.icon_state = "egun[rand(1,6)]"
|
||||
new_gun.desc = "This is an antique energy weapon, you're not sure if it will fire or not."
|
||||
|
||||
//5% chance to explode when first fired
|
||||
//10% chance to have an unchargeable cell
|
||||
//15% chance to gain a random amount of starting energy, otherwise start with an empty cell
|
||||
if(prob(5))
|
||||
new_gun.power_supply.rigged = 1
|
||||
if(prob(10))
|
||||
new_gun.power_supply.maxcharge = 0
|
||||
if(prob(15))
|
||||
new_gun.power_supply.charge = rand(0, new_gun.power_supply.maxcharge)
|
||||
else
|
||||
new_gun.power_supply.charge = 0
|
||||
//5% chance to explode when first fired
|
||||
//10% chance to have an unchargeable cell
|
||||
//15% chance to gain a random amount of starting energy, otherwise start with an empty cell
|
||||
if(prob(5))
|
||||
new_gun.power_supply.rigged = 1
|
||||
if(prob(10))
|
||||
new_gun.power_supply.maxcharge = 0
|
||||
if(prob(15))
|
||||
new_gun.power_supply.charge = rand(0, new_gun.power_supply.maxcharge)
|
||||
else
|
||||
new_gun.power_supply.charge = 0
|
||||
|
||||
item_type = "gun"
|
||||
if(27)
|
||||
|
||||
@@ -206,6 +206,28 @@
|
||||
)
|
||||
return find_type
|
||||
|
||||
var/list/responsive_carriers = list( \
|
||||
"carbon", \
|
||||
"potassium", \
|
||||
"hydrogen", \
|
||||
"nitrogen", \
|
||||
"mercury", \
|
||||
"iron", \
|
||||
"chlorine", \
|
||||
"phosphorus", \
|
||||
"plasma")
|
||||
|
||||
var/list/finds_as_strings = list( \
|
||||
"Trace organic cells", \
|
||||
"Long exposure particles", \
|
||||
"Trace water particles", \
|
||||
"Crystalline structures", \
|
||||
"Metallic derivative", \
|
||||
"Metallic composite", \
|
||||
"Metamorphic/igneous rock composite", \
|
||||
"Metamorphic/sedimentary rock composite", \
|
||||
"Anomalous material" )
|
||||
|
||||
#undef ARCHAEO_BOWL
|
||||
#undef ARCHAEO_URN
|
||||
#undef ARCHAEO_CUTLERY
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
|
||||
/obj/item/weapon/shard/plasma
|
||||
name = "plasma shard"
|
||||
desc = "A shard of plasma glass. Considerably tougher then normal glass shards. Apparently not tough enough to be a window."
|
||||
force = 8.0
|
||||
throwforce = 15.0
|
||||
icon_state = "plasmalarge"
|
||||
|
||||
/obj/item/weapon/shard/plasma/New()
|
||||
|
||||
src.icon_state = pick("plasmalarge", "plasmamedium", "plasmasmall")
|
||||
@@ -24,14 +26,14 @@
|
||||
if ( istype(W, /obj/item/weapon/weldingtool))
|
||||
var/obj/item/weapon/weldingtool/WT = W
|
||||
if(WT.remove_fuel(0, user))
|
||||
var/obj/item/stack/sheet/mineral/plasma/NG = new (user.loc)
|
||||
for (var/obj/item/stack/sheet/mineral/plasma/G in user.loc)
|
||||
var/obj/item/stack/sheet/glass/plasmaglass/NG = new (user.loc)
|
||||
for (var/obj/item/stack/sheet/glass/plasmaglass/G in user.loc)
|
||||
if(G==NG)
|
||||
continue
|
||||
if(G.amount>=G.max_amount)
|
||||
continue
|
||||
G.attackby(NG, user)
|
||||
usr << "You add the newly-formed plasma to the stack. It now contains [NG.amount] sheets."
|
||||
usr << "You add the newly-formed plasma glass to the stack. It now contains [NG.amount] sheets."
|
||||
//SN src = null
|
||||
del(src)
|
||||
return
|
||||
|
||||
@@ -29,30 +29,6 @@
|
||||
pixel_x = rand(0,16)-8
|
||||
pixel_y = rand(0,8)-8
|
||||
|
||||
var/list/responsive_carriers = list( \
|
||||
"carbon", \
|
||||
"potassium", \
|
||||
"hydrogen", \
|
||||
"nitrogen", \
|
||||
"mercury", \
|
||||
"iron", \
|
||||
"chlorine", \
|
||||
"phosphorus", \
|
||||
"plasma")
|
||||
|
||||
var/list/finds_as_strings = list( \
|
||||
"Trace organic cells", \
|
||||
"Long exposure particles", \
|
||||
"Trace water particles", \
|
||||
"Crystalline structures", \
|
||||
"Metallic derivative", \
|
||||
"Metallic composite", \
|
||||
"Metamorphic/igneous rock composite", \
|
||||
"Metamorphic/sedimentary rock composite", \
|
||||
"Anomalous material" )
|
||||
|
||||
var/list/artifact_spawning_turfs = list()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Geosample datum
|
||||
|
||||
@@ -64,7 +40,6 @@ var/list/artifact_spawning_turfs = list()
|
||||
var/artifact_id = "" //id of a nearby artifact, if there is one
|
||||
var/artifact_distance = -1 //proportional to distance
|
||||
var/source_mineral = "chlorine" //machines will pop up a warning telling players that the sample may be confused
|
||||
var/total_spread = 0
|
||||
//
|
||||
//var/source_mineral
|
||||
//all potential finds are initialised to null, so nullcheck before you access them
|
||||
@@ -76,11 +51,11 @@ var/list/artifact_spawning_turfs = list()
|
||||
|
||||
//this should only need to be called once
|
||||
/datum/geosample/proc/UpdateTurf(var/turf/simulated/mineral/container)
|
||||
set background = 1
|
||||
if(!container || !istype(container))
|
||||
return
|
||||
|
||||
age = rand(1,999)
|
||||
total_spread = 0
|
||||
|
||||
switch(container.mineralName)
|
||||
if("Uranium")
|
||||
@@ -132,8 +107,15 @@ var/list/artifact_spawning_turfs = list()
|
||||
var/responsive_reagent = get_responsive_reagent(F.find_type)
|
||||
find_presence[responsive_reagent] = F.dissonance_spread
|
||||
|
||||
for(var/entry in find_presence)
|
||||
total_spread += find_presence[entry]
|
||||
//loop over again to reset values to percentages
|
||||
var/total_presence = 0
|
||||
for(var/carrier in find_presence)
|
||||
total_presence += find_presence[carrier]
|
||||
for(var/carrier in find_presence)
|
||||
find_presence[carrier] = find_presence[carrier] / total_presence
|
||||
|
||||
/*for(var/entry in find_presence)
|
||||
total_spread += find_presence[entry]*/
|
||||
|
||||
//have this separate from UpdateTurf() so that we dont have a billion turfs being updated (redundantly) every time an artifact spawns
|
||||
/datum/geosample/proc/UpdateNearbyArtifactInfo(var/turf/simulated/mineral/container)
|
||||
@@ -144,14 +126,14 @@ var/list/artifact_spawning_turfs = list()
|
||||
artifact_distance = rand()
|
||||
artifact_id = container.artifact_find.artifact_id
|
||||
else
|
||||
for(var/turf/simulated/mineral/holder in artifact_spawning_turfs)
|
||||
if(holder.artifact_find)
|
||||
var/dist = get_dist(container, holder)
|
||||
if(dist < holder.artifact_find.artifact_detect_range && dist < src.artifact_distance)
|
||||
src.artifact_distance = dist
|
||||
src.artifact_id = holder.artifact_find.artifact_id
|
||||
for(var/turf/simulated/mineral/T in master_controller.artifact_spawning_turfs)
|
||||
if(T.artifact_find)
|
||||
var/cur_dist = get_dist(container, T) * 2
|
||||
if( (artifact_distance < 0 || cur_dist < artifact_distance) && cur_dist <= T.artifact_find.artifact_detect_range )
|
||||
artifact_distance = cur_dist + rand() * 2 - 1
|
||||
artifact_id = T.artifact_find.artifact_id
|
||||
else
|
||||
artifact_spawning_turfs.Remove(holder)
|
||||
master_controller.artifact_spawning_turfs.Remove(T)
|
||||
|
||||
/*
|
||||
#undef FIND_PLANT
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
|
||||
// This machine shows the age for extremely old finds
|
||||
|
||||
obj/machinery/anomaly/accelerator
|
||||
name = "Accelerator spectrometer"
|
||||
|
||||
obj/machinery/anomaly/accelerator/ScanResults()
|
||||
var/results = "The scan was inconclusive. Check sample integrity and carrier consistency."
|
||||
|
||||
var/datum/geosample/scanned_sample
|
||||
var/carrier_name
|
||||
var/num_reagents = 0
|
||||
|
||||
for(var/datum/reagent/A in held_container.reagents.reagent_list)
|
||||
var/datum/reagent/R = A
|
||||
if(istype(R, /datum/reagent/analysis_sample))
|
||||
scanned_sample = R.data
|
||||
else
|
||||
carrier_name = R.id
|
||||
num_reagents++
|
||||
|
||||
if(num_reagents == 2 && scanned_sample && carrier_name)
|
||||
var/specifity = GetResultSpecifity(scanned_sample, carrier_name)
|
||||
results = "Kinetic acceleration of carrier ([carrier_name]) indicates age ([100 * specifity]% accuracy): <br><br>"
|
||||
|
||||
if(scanned_sample.age_billion)
|
||||
var/displayed_age_millions = scanned_sample.age_million + max(scanned_sample.age_million * ((1 - specifity) * (2 * rand() - 1)), 0)
|
||||
var/displayed_age_billions = scanned_sample.age_billion + max(scanned_sample.age_billion * ((1 - specifity) * (2 * rand() - 1)), 0)
|
||||
results += "[displayed_age_billions + displayed_age_millions / 1000] billion years.<br>"
|
||||
else if(scanned_sample.age_million)
|
||||
var/displayed_age_thousands = scanned_sample.age_thousand + max(scanned_sample.age_thousand * ((1 - specifity) * (4 * rand() - 2)), 0)
|
||||
var/displayed_age_millions = scanned_sample.age_million + max(scanned_sample.age_million * ((1 - specifity) * (2 * rand() - 1)), 0)
|
||||
results += "[displayed_age_millions + displayed_age_thousands / 1000] million years.<br>"
|
||||
else if(scanned_sample.age_thousand)
|
||||
var/displayed_age = scanned_sample.age + max(scanned_sample.age * ((1 - specifity) * (8 * rand() - 4)), 0)
|
||||
var/displayed_age_thousands = scanned_sample.age_thousand + max(scanned_sample.age * ((1 - specifity) * (4 * rand() - 2)), 0)
|
||||
results += "[displayed_age_thousands + displayed_age / 1000] thousand years.<br>"
|
||||
else
|
||||
var/displayed_age = scanned_sample.age + max(scanned_sample.age * ((1 - specifity) * (8 * rand() - 4)), 0)
|
||||
results += "[displayed_age] years.<br>"
|
||||
|
||||
results += "<br>Warning, results only valid for ages on the scale of billions of years."
|
||||
|
||||
return results
|
||||
@@ -1,203 +0,0 @@
|
||||
//Handles how much the temperature changes on power use. (Joules/Kelvin)
|
||||
//Equates to as much heat energy per kelvin as a quarter tile of air.
|
||||
#define XENOARCH_HEAT_CAPACITY 5000
|
||||
|
||||
//Handles heat transfer to the air. (In watts)
|
||||
//Can heat a single tile 2 degrees per tick.
|
||||
#define XENOARCH_MAX_ENERGY_TRANSFER 4000
|
||||
|
||||
//How many joules of electrical energy produce how many joules of heat energy?
|
||||
#define XENOARCH_HEAT_COEFFICIENT 3
|
||||
|
||||
|
||||
/obj/machinery/anomaly
|
||||
name = "Analysis machine"
|
||||
desc = "A specialised, complex analysis machine."
|
||||
anchored = 1
|
||||
density = 1
|
||||
icon = 'icons/obj/virology.dmi'
|
||||
icon_state = "analyser"
|
||||
|
||||
idle_power_usage = 20 //watts
|
||||
active_power_usage = 300 //Because I need to make up numbers~
|
||||
|
||||
var/obj/item/weapon/reagent_containers/glass/held_container
|
||||
var/obj/item/weapon/tank/fuel_container
|
||||
var/target_scan_ticks = 30
|
||||
var/report_num = 0
|
||||
var/scan_process = 0
|
||||
var/temperature = 273 //measured in kelvin, if this exceeds 1200, the machine is damaged and requires repairs
|
||||
//if this exceeds 600 and safety is enabled it will shutdown
|
||||
//temp greater than 600 also requires a safety prompt to initiate scanning
|
||||
var/max_temp = 450
|
||||
|
||||
/obj/machinery/anomaly/New()
|
||||
..()
|
||||
|
||||
//for analysis debugging
|
||||
/*var/obj/item/weapon/reagent_containers/glass/solution_tray/S = new(src.loc)
|
||||
var/turf/simulated/mineral/diamond/D
|
||||
for(var/turf/simulated/mineral/diamond/M in world)
|
||||
D = M
|
||||
break
|
||||
S.reagents.add_reagent("analysis_sample", 1, D.geological_data)
|
||||
S.reagents.add_reagent("chlorine", 1, null)*/
|
||||
|
||||
/obj/machinery/anomaly/process()
|
||||
//not sure if everything needs to heat up, or just the GLPC
|
||||
var/datum/gas_mixture/env = loc.return_air()
|
||||
var/environmental_temp = env.temperature
|
||||
if(scan_process)
|
||||
if(scan_process++ > target_scan_ticks)
|
||||
FinishScan()
|
||||
else if(temperature > 400)
|
||||
src.visible_message("\blue \icon[src] shuts down from the heat!", 2)
|
||||
scan_process = 0
|
||||
else if(temperature > 350 && prob(10))
|
||||
src.visible_message("\blue \icon[src] bleets plaintively.", 2)
|
||||
if(temperature > 400)
|
||||
scan_process = 0
|
||||
|
||||
//show we're busy
|
||||
if(prob(5))
|
||||
src.visible_message("\blue \icon[src] [pick("whirrs","chuffs","clicks")][pick(" quietly"," softly"," sadly"," excitedly"," energetically"," angrily"," plaintively")].", 2)
|
||||
|
||||
use_power = 2
|
||||
|
||||
else
|
||||
use_power = 1
|
||||
|
||||
auto_use_power()
|
||||
|
||||
//Add 3000 joules when active. This is about 0.6 degrees per tick.
|
||||
//May need adjustment
|
||||
if(use_power == 1)
|
||||
var/heat_added = active_power_usage *XENOARCH_HEAT_COEFFICIENT
|
||||
|
||||
if(temperature < max_temp)
|
||||
temperature += heat_added/XENOARCH_HEAT_CAPACITY
|
||||
|
||||
var/temperature_difference = abs(environmental_temp-temperature)
|
||||
var/datum/gas_mixture/removed = loc.remove_air(env.total_moles*0.25)
|
||||
var/heat_capacity = removed.heat_capacity()
|
||||
|
||||
heat_added = max(temperature_difference*heat_capacity, XENOARCH_MAX_ENERGY_TRANSFER)
|
||||
|
||||
if(temperature > environmental_temp)
|
||||
//cool down to match the air
|
||||
temperature = max(TCMB, temperature - heat_added/XENOARCH_HEAT_CAPACITY)
|
||||
removed.temperature = max(TCMB, removed.temperature + heat_added/heat_capacity)
|
||||
|
||||
if(temperature_difference > 10 && prob(5))
|
||||
src.visible_message("\blue \icon[src] hisses softly.", 2)
|
||||
|
||||
else
|
||||
//heat up to match the air
|
||||
temperature = max(TCMB, temperature + heat_added/XENOARCH_HEAT_CAPACITY)
|
||||
removed.temperature = max(TCMB, removed.temperature - heat_added/heat_capacity)
|
||||
|
||||
if(temperature_difference > 10 && prob(5))
|
||||
src.visible_message("\blue \icon[src] plinks quietly.", 2)
|
||||
|
||||
env.merge(removed)
|
||||
|
||||
|
||||
//this proc should be overriden by each individual machine
|
||||
/obj/machinery/anomaly/attack_hand(var/mob/user as mob)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
user.machine = src
|
||||
var/dat = "<B>[src.name]</B><BR>"
|
||||
dat += "Module heat level: [temperature] kelvin<br>"
|
||||
dat += "Safeties set at 350k, shielding failure at 400k. Failure to maintain safe heat levels may result in equipment damage.<br>"
|
||||
dat += "<hr>"
|
||||
if(scan_process)
|
||||
dat += "Scan in progress<br><br><br>"
|
||||
else
|
||||
dat += "[held_container ? "<A href='?src=\ref[src];eject_beaker=1'>Eject beaker</a>" : "No beaker inserted."]<br>"
|
||||
//dat += "[fuel_container ? "<A href='?src=\ref[src];eject_fuel=1'>Eject fuel tank</a>" : "No fuel tank inserted."]<br>"
|
||||
dat += "[held_container ? "<A href='?src=\ref[src];begin=1'>Begin scanning</a>" : ""]"
|
||||
dat += "<hr>"
|
||||
dat += "<A href='?src=\ref[src];refresh=1'>Refresh</a><BR>"
|
||||
dat += "<A href='?src=\ref[src];close=1'>Close</a><BR>"
|
||||
user << browse(dat, "window=anomaly;size=450x500")
|
||||
onclose(user, "anomaly")
|
||||
|
||||
obj/machinery/anomaly/attackby(obj/item/weapon/W as obj, mob/living/user as mob)
|
||||
if(istype(W, /obj/item/weapon/reagent_containers/glass))
|
||||
//var/obj/item/weapon/reagent_containers/glass/G = W
|
||||
if(held_container)
|
||||
user << "\red You must remove the [held_container] first."
|
||||
else
|
||||
user << "\blue You put the [W] into the [src]."
|
||||
user.drop_item(W)
|
||||
held_container = W
|
||||
held_container.loc = src
|
||||
updateDialog()
|
||||
|
||||
/*else if(istype(W, /obj/item/weapon/tank))
|
||||
//var/obj/item/weapon/reagent_containers/glass/G = W
|
||||
if(fuel_container)
|
||||
user << "\red You must remove the [fuel_container] first."
|
||||
else
|
||||
user << "\blue You put the [fuel_container] into the [src]."
|
||||
user.drop_item(W)
|
||||
fuel_container.loc = src
|
||||
fuel_container = W
|
||||
updateDialog()*/
|
||||
else
|
||||
return ..()
|
||||
|
||||
obj/machinery/anomaly/proc/ScanResults()
|
||||
//instantiate in children to produce unique scan behaviour
|
||||
return "\red Error initialising scanning components."
|
||||
|
||||
obj/machinery/anomaly/proc/FinishScan()
|
||||
scan_process = 0
|
||||
updateDialog()
|
||||
|
||||
//determine the results and print a report
|
||||
if(held_container)
|
||||
src.visible_message("\blue \icon[src] makes an insistent chime.", 2)
|
||||
var/obj/item/weapon/paper/P = new(src.loc)
|
||||
P.name = "[src] report #[++report_num]"
|
||||
P.info = "<b>[src] analysis report #[report_num]</b><br><br>" + ScanResults()
|
||||
P.stamped = list(/obj/item/weapon/stamp)
|
||||
P.overlays = list("paper_stamped")
|
||||
else
|
||||
src.visible_message("\blue \icon[src] makes a low buzzing noise.", 2)
|
||||
|
||||
obj/machinery/anomaly/Topic(href, href_list)
|
||||
..()
|
||||
usr.set_machine(src)
|
||||
if(href_list["close"])
|
||||
usr << browse(null, "window=anomaly")
|
||||
usr.machine = null
|
||||
if(href_list["eject_beaker"])
|
||||
held_container.loc = src.loc
|
||||
held_container = null
|
||||
if(href_list["eject_fuel"])
|
||||
fuel_container.loc = src.loc
|
||||
fuel_container = null
|
||||
if(href_list["begin"])
|
||||
if(temperature >= 350)
|
||||
var/proceed = input("Unsafe internal temperature detected, enter YES below to continue.","Warning")
|
||||
if(proceed == "YES" && get_dist(src, usr) <= 1)
|
||||
scan_process = 1
|
||||
else
|
||||
scan_process = 1
|
||||
|
||||
updateUsrDialog()
|
||||
|
||||
//whether the carrier sample matches the possible finds
|
||||
//results greater than a threshold of 0.6 means a positive result
|
||||
obj/machinery/anomaly/proc/GetResultSpecifity(var/datum/geosample/scanned_sample, var/carrier_name)
|
||||
var/specifity = 0
|
||||
if(scanned_sample && carrier_name)
|
||||
|
||||
if(scanned_sample.find_presence.Find(carrier_name))
|
||||
specifity = 0.75 * (scanned_sample.find_presence[carrier_name] / scanned_sample.total_spread) + 0.25
|
||||
else
|
||||
specifity = rand(0, 0.5)
|
||||
|
||||
return specifity
|
||||
@@ -1,34 +0,0 @@
|
||||
|
||||
// This machine tells the distance to a nearby artifact, if there is one
|
||||
|
||||
obj/machinery/anomaly/fourier_transform
|
||||
name = "Fourier Transform spectroscope"
|
||||
|
||||
obj/machinery/anomaly/fourier_transform/ScanResults()
|
||||
var/results = "The scan was inconclusive. Check sample integrity and carrier consistency."
|
||||
|
||||
var/datum/geosample/scanned_sample
|
||||
var/carrier
|
||||
var/num_reagents = 0
|
||||
|
||||
for(var/datum/reagent/A in held_container.reagents.reagent_list)
|
||||
var/datum/reagent/R = A
|
||||
if(istype(R, /datum/reagent/analysis_sample))
|
||||
scanned_sample = R.data
|
||||
else
|
||||
carrier = R.id
|
||||
num_reagents++
|
||||
|
||||
if(num_reagents == 2 && scanned_sample && carrier)
|
||||
//all necessary components are present
|
||||
var/specifity = GetResultSpecifity(scanned_sample, carrier)
|
||||
var/distance = scanned_sample.artifact_distance
|
||||
if(distance > 0)
|
||||
distance += (2 * rand() - 1) * distance * 0.05
|
||||
results = "Fourier transform analysis on anomalous energy absorption through carrier ([carrier]) indicates source located inside emission radius ([95 * specifity]% accuracy): [distance]."
|
||||
else
|
||||
results = "Energy dispersion detected throughout sample consistent with background readings.<br>"
|
||||
if(carrier == scanned_sample.source_mineral)
|
||||
results += "Warning, analysis may be contaminated by high quantities of molecular carrier present throughout sample."
|
||||
|
||||
return results
|
||||
@@ -1,39 +0,0 @@
|
||||
|
||||
// This machine shows the materials that are present
|
||||
|
||||
obj/machinery/anomaly/gas_chromatography
|
||||
name = "Gas Chromatography spectrometer"
|
||||
|
||||
obj/machinery/anomaly/gas_chromatography/ScanResults()
|
||||
var/results = "The scan was inconclusive. Check sample integrity and carrier consistency."
|
||||
|
||||
var/datum/geosample/scanned_sample
|
||||
var/carrier
|
||||
var/num_reagents = 0
|
||||
|
||||
for(var/datum/reagent/A in held_container.reagents.reagent_list)
|
||||
var/datum/reagent/R = A
|
||||
if(istype(R, /datum/reagent/analysis_sample))
|
||||
scanned_sample = R.data
|
||||
else
|
||||
carrier = R.id
|
||||
num_reagents++
|
||||
|
||||
if(num_reagents == 2 && scanned_sample)
|
||||
var/specifity = GetResultSpecifity(scanned_sample, carrier)
|
||||
results = "Chromatography partitioning analysis over carrier ([carrier]) indicates the following elements present ([100 * specifity]% accuracy):<br><br>"
|
||||
|
||||
var/num_found = 0
|
||||
for(var/index=1,index <= scanned_sample.find_presence.len, index++)
|
||||
var/find = scanned_sample.find_presence[index]
|
||||
if(find && prob(100 * specifity))
|
||||
results += " - " + finds_as_strings[index] + "<br>"
|
||||
num_found++
|
||||
|
||||
if(!num_found)
|
||||
results = "Chromatography partitioning results over carrier ([carrier]) to determine elemental makeup were inconclusive.<br>"
|
||||
|
||||
if(!carrier)
|
||||
results += "<br>No carrier detected, scan accuracy affected.<br>"
|
||||
|
||||
return results
|
||||
@@ -1,55 +0,0 @@
|
||||
|
||||
obj/machinery/anomaly/hyperspectral
|
||||
name = "Hyperspectral Imager"
|
||||
icon = 'icons/obj/xenoarchaeology.dmi'
|
||||
icon_state = "scanner"
|
||||
|
||||
obj/machinery/anomaly/hyperspectral/process()
|
||||
..()
|
||||
if(scan_process)
|
||||
icon_state = "scanner_active"
|
||||
else if(prob(10))
|
||||
icon_state = "scanner"
|
||||
flick(src, "scanner_active")
|
||||
|
||||
obj/machinery/anomaly/hyperspectral/ScanResults()
|
||||
var/results = "The scan was inconclusive. Check sample integrity and carrier consistency."
|
||||
|
||||
var/datum/geosample/scanned_sample
|
||||
var/carrier
|
||||
var/num_reagents = 0
|
||||
|
||||
for(var/datum/reagent/A in held_container.reagents.reagent_list)
|
||||
var/datum/reagent/R = A
|
||||
if(istype(R, /datum/reagent/analysis_sample))
|
||||
scanned_sample = R.data
|
||||
else
|
||||
carrier = R.id
|
||||
num_reagents++
|
||||
|
||||
if(num_reagents == 2 && scanned_sample && carrier)
|
||||
//all necessary components are present
|
||||
var/specifity = GetResultSpecifity(scanned_sample, carrier)
|
||||
results = "Spectral signature over carrier ([carrier]):<br>"
|
||||
if(specifity <= 0.25)
|
||||
//results += "<img src=\"http://i.imgur.com/TAQHn.jpg\"></img><br>"
|
||||
results += "<img src=chart1.jpg>"
|
||||
else if(specifity <= 0.5)
|
||||
//results += "<img src=\"http://i.imgur.com/EwOZ7.jpg\"></img><br>"
|
||||
results += "<img src=chart2.jpg>"
|
||||
else if(specifity <= 0.75)
|
||||
//results += "<img src=\"http://i.imgur.com/1qCae.jpg\"></img><br>"
|
||||
results += "<img src=chart3.jpg>"
|
||||
else
|
||||
//results += "<img src=\"http://i.imgur.com/9T9nc.jpg\"></img><br>"
|
||||
results += "<img src=chart4.jpg>"
|
||||
|
||||
results += "<br>"
|
||||
if(scanned_sample.artifact_id)
|
||||
results += "Detected energy signatures [100 * (1 - specifity)]% consistent with standard background readings.<br>"
|
||||
if(prob( (specifity + 0.5 * (1 - specifity)) * 100))
|
||||
results += "Anomalous exotic energy signature isolated: <font color='red'><b>[scanned_sample.artifact_id].</b></font>"
|
||||
else
|
||||
results += "Detected energy signatures [95 + 5 * (2 * rand() - 1) * (1 - specifity)]% consistent with standard background readings."
|
||||
|
||||
return results
|
||||
@@ -1,47 +0,0 @@
|
||||
|
||||
// This machine shows the amount of a certain material that is present
|
||||
|
||||
obj/machinery/anomaly/ion_mobility
|
||||
name = "Ion Mobility Spectrometer"
|
||||
desc = "A specialised, complex analysis machine."
|
||||
icon = 'icons/obj/virology.dmi'
|
||||
icon_state = "analyser"
|
||||
|
||||
obj/machinery/anomaly/ion_mobility/ScanResults()
|
||||
var/results = "The scan was inconclusive. Check sample integrity and carrier consistency."
|
||||
|
||||
var/datum/geosample/scanned_sample
|
||||
var/carrier
|
||||
var/num_reagents = 0
|
||||
|
||||
for(var/datum/reagent/A in held_container.reagents.reagent_list)
|
||||
var/datum/reagent/R = A
|
||||
if(istype(R, /datum/reagent/analysis_sample))
|
||||
scanned_sample = R.data
|
||||
else
|
||||
carrier = R.id
|
||||
num_reagents++
|
||||
|
||||
if(num_reagents == 2 && scanned_sample && carrier)
|
||||
//all necessary components are present
|
||||
results = "Kinetic analysis on sample's ionic residue in carrier ([carrier]) indicates the dissonance spread:<br><br>"
|
||||
var/found = 0
|
||||
if(scanned_sample.find_presence.Find(carrier))
|
||||
var/dis_ratio = scanned_sample.find_presence[carrier]
|
||||
var/desc_index = responsive_carriers.Find(carrier)
|
||||
results += " - [finds_as_strings[desc_index]]: [dis_ratio]<br>"
|
||||
found++
|
||||
/*
|
||||
for(var/index=1,index <= scanned_sample.find_presence.len, index++)
|
||||
var/find = scanned_sample.find_presence[index]
|
||||
//world << "index: [index], find: [find], response: [responsive_carriers[index]], carrier: [carrier]"
|
||||
if(find && responsive_carriers[index] == carrier)
|
||||
results += " - [finds_as_strings[index]] [find * 100]%<br>"
|
||||
found++
|
||||
*/
|
||||
if(!found)
|
||||
results = "Kinetic analysis on sample's ionic residue in carrier ([carrier]) to determine composition were inconclusive.<br>"
|
||||
if(carrier == scanned_sample.source_mineral)
|
||||
results += "Warning, analysis may be contaminated by high quantities of molecular carrier present throughout sample."
|
||||
|
||||
return results
|
||||
@@ -1,51 +0,0 @@
|
||||
|
||||
// This machine shows the age for newer finds
|
||||
|
||||
obj/machinery/anomaly/isotope_ratio
|
||||
name = "Isotope ratio spectrometer"
|
||||
desc = "A specialised, complex analysis machine."
|
||||
icon = 'icons/obj/virology.dmi'
|
||||
icon_state = "analyser"
|
||||
|
||||
obj/machinery/anomaly/isotope_ratio/ScanResults()
|
||||
var/results = "The scan was inconclusive. Check sample integrity and carrier consistency."
|
||||
|
||||
var/datum/geosample/scanned_sample
|
||||
var/carrier_name
|
||||
var/num_reagents = 0
|
||||
|
||||
for(var/datum/reagent/A in held_container.reagents.reagent_list)
|
||||
var/datum/reagent/R = A
|
||||
if(istype(R, /datum/reagent/analysis_sample))
|
||||
scanned_sample = R.data
|
||||
else
|
||||
carrier_name = R.id
|
||||
num_reagents++
|
||||
|
||||
if(num_reagents == 2 && scanned_sample && carrier_name)
|
||||
var/accuracy = GetResultSpecifity(scanned_sample, carrier_name)
|
||||
accuracy += 0.5 * (1 - accuracy) / scanned_sample.total_spread
|
||||
if(!accuracy)
|
||||
accuracy = rand(0.01, 0.5)
|
||||
results = "Isotope decay analysis in carrier ([carrier_name]) indicates age ([100 * accuracy]% accuracy): <br><br>"
|
||||
|
||||
if(scanned_sample.age_billion)
|
||||
//scramble the results
|
||||
var/displayed_age_thousands = rand(0, 999)
|
||||
var/displayed_age_millions = rand(0, 999)
|
||||
results += "[displayed_age_millions + displayed_age_thousands / 1000] million years.<br>"
|
||||
else if(scanned_sample.age_million)
|
||||
var/displayed_age_thousands = scanned_sample.age_thousand + max(scanned_sample.age_thousand * ((1 - accuracy) * (2 * rand() - 1)), 0)
|
||||
var/displayed_age_millions = scanned_sample.age_million + max(scanned_sample.age_million * ((1 - accuracy) * (4 * rand() - 2)), 0)
|
||||
results += "[displayed_age_millions + displayed_age_thousands / 1000] million years.<br>"
|
||||
else if(scanned_sample.age_thousand)
|
||||
var/displayed_age = scanned_sample.age + scanned_sample.age * ((1 - accuracy) * (2 * rand() - 1))
|
||||
var/displayed_age_thousands = scanned_sample.age_thousand + max(scanned_sample.age_thousand * ((1 - accuracy) * (2 * rand() - 1)), 0)
|
||||
results += "[displayed_age_thousands + displayed_age / 1000] thousand years.<br>"
|
||||
else
|
||||
var/displayed_age = scanned_sample.age + max(scanned_sample.age * ((1 - accuracy) * (2 * rand() - 1)), 0)
|
||||
results += "[displayed_age] years.<br>"
|
||||
|
||||
results += "<br>Warning, results only valid up to ages of one billion years."
|
||||
|
||||
return results
|
||||
@@ -1,318 +0,0 @@
|
||||
|
||||
//cael - some changes here. the analysis pad is entirely new
|
||||
|
||||
/obj/machinery/artifact_analyser
|
||||
name = "Artifact Analyser"
|
||||
desc = "Studies the structure of artifacts to discover their uses."
|
||||
icon = 'icons/obj/virology.dmi'
|
||||
icon_state = "analyser"
|
||||
anchored = 1
|
||||
density = 1
|
||||
var/working = 0
|
||||
var/accuO = 0
|
||||
var/accuT = 0
|
||||
var/accuE1 = 0
|
||||
var/accuE2 = 0
|
||||
var/aorigin = "None"
|
||||
var/atrigger = "None"
|
||||
var/aeffect1 = "None"
|
||||
var/aeffect2 = "None"
|
||||
var/list/origin_bonuses
|
||||
var/list/trigger_bonuses
|
||||
var/list/function_bonuses
|
||||
var/list/range_bonuses
|
||||
var/cur_id = ""
|
||||
var/scan_num = 0
|
||||
var/obj/machinery/artifact/cur_artifact = null
|
||||
var/obj/machinery/analyser_pad/owned_pad = null
|
||||
var/list/allorigins = list("Ancient Robots","Martian","Wizard Federation","Extradimensional","Precursor")
|
||||
var/list/alltriggers = list("Contact with Living Organism","Heavy Impact","Contact with Energy Source","Contact with Hydrogen","Contact with Corrosive Substance","Contact with Volatile Substance","Contact with Toxins","Exposure to Heat")
|
||||
var/list/alleffects = list("Healing Device","Anti-biological Weapon","Non-lethal Stunning Trap","Mechanoid Repair Module","Mechanoid Deconstruction Device","Power Generator","Power Drain","Stellar Mineral Attractor","Agriculture Regulator","Shield Generator","Space-Time Displacer")
|
||||
var/list/allranges = list("Constant Short-Range Energy Field","Medium Range Energy Pulses","Long Range Energy Pulses","Extreme Range Energy Pulses","Requires contact with subject")
|
||||
|
||||
/obj/machinery/artifact_analyser/New()
|
||||
..()
|
||||
origin_bonuses = new/list()
|
||||
origin_bonuses["ancient"] = 0
|
||||
origin_bonuses["martian"] = 0
|
||||
origin_bonuses["wizard"] = 0
|
||||
origin_bonuses["eldritch"] = 0
|
||||
origin_bonuses["precursor"] = 0
|
||||
trigger_bonuses = new/list()
|
||||
trigger_bonuses["ancient"] = 0
|
||||
trigger_bonuses["martian"] = 0
|
||||
trigger_bonuses["wizard"] = 0
|
||||
trigger_bonuses["eldritch"] = 0
|
||||
trigger_bonuses["precursor"] = 0
|
||||
function_bonuses = new/list()
|
||||
function_bonuses["ancient"] = 0
|
||||
function_bonuses["martian"] = 0
|
||||
function_bonuses["wizard"] = 0
|
||||
function_bonuses["eldritch"] = 0
|
||||
function_bonuses["precursor"] = 0
|
||||
range_bonuses = new/list()
|
||||
range_bonuses["ancient"] = 0
|
||||
range_bonuses["martian"] = 0
|
||||
range_bonuses["wizard"] = 0
|
||||
range_bonuses["eldritch"] = 0
|
||||
range_bonuses["precursor"] = 0
|
||||
//
|
||||
spawn(10)
|
||||
owned_pad = locate() in orange(1, src)
|
||||
|
||||
/obj/machinery/artifact_analyser/attack_hand(var/mob/user as mob)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
user.machine = src
|
||||
var/dat = "<B>Artifact Analyser</B><BR>"
|
||||
dat += "<HR><BR>"
|
||||
if(!owned_pad)
|
||||
dat += "<B><font color=red>Unable to locate analysis pad.</font><BR></b>"
|
||||
dat += "<HR><BR>"
|
||||
else if (!src.working)
|
||||
dat += "<B>Artifact ID:</B> [cur_id]<BR>"
|
||||
dat += "<B>Artifact Origin:</B> [aorigin] ([accuO]%)<BR>"
|
||||
dat += "<B>Activation Trigger:</B> [atrigger] ([accuT]%)<BR>"
|
||||
dat += "<B>Artifact Function:</B> [aeffect1] ([accuE1]%)<BR>"
|
||||
dat += "<B>Artifact Range:</B> [aeffect2] ([accuE2]%)<BR><BR>"
|
||||
dat += "<HR><BR>"
|
||||
dat += "Artifact ID is determined from unique energy emission signatures.<br>"
|
||||
dat += "<A href='?src=\ref[src];analyse=1'>Analyse Artifact (Scan number #[scan_num+1])</a><BR>"
|
||||
dat += "<A href='?src=\ref[src];upload=1'>Upload/update artifact scan</a><BR>"
|
||||
dat += "<A href='?src=\ref[src];print=1'>Print Page</a><BR>"
|
||||
else
|
||||
dat += "<B>Please wait. Analysis in progress.</B><BR>"
|
||||
dat += "<HR><BR>"
|
||||
//
|
||||
dat += "<A href='?src=\ref[src];close=1'>Close<BR>"
|
||||
user << browse(dat, "window=artanalyser;size=450x500")
|
||||
onclose(user, "artanalyser")
|
||||
|
||||
/obj/machinery/artifact_analyser/process()
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
use_power(350)
|
||||
//
|
||||
if(!owned_pad)
|
||||
for(var/obj/machinery/analyser_pad/pad in range(1))
|
||||
owned_pad = pad
|
||||
break
|
||||
|
||||
/obj/machinery/artifact_analyser/proc/AA_FailedAnalysis(var/failtype)
|
||||
switch(failtype)
|
||||
if(1)
|
||||
src.aorigin = "Failed to Identify"
|
||||
if (prob(20)) src.aorigin = pick(src.allorigins)
|
||||
if(2)
|
||||
src.atrigger = "Failed to Identify"
|
||||
if (prob(20)) src.atrigger = pick(src.alltriggers)
|
||||
if(3)
|
||||
src.aeffect1 = "Failed to Identify"
|
||||
if (prob(20)) src.aeffect1 = pick(src.alleffects)
|
||||
if(4)
|
||||
src.aeffect2 = "Failed to Identify"
|
||||
if (prob(20)) src.aeffect2 = pick(src.allranges)
|
||||
|
||||
/obj/machinery/artifact_analyser/proc/AA_Analyse()
|
||||
if(!cur_artifact)
|
||||
return
|
||||
src.accuO = 5 + rand(0,10) + origin_bonuses[cur_artifact.origin] + cur_artifact.activated * 50
|
||||
src.accuT = 5 + rand(0,10) + trigger_bonuses[cur_artifact.origin] + cur_artifact.activated * 50
|
||||
src.accuE1 = 5 + rand(0,10) + function_bonuses[cur_artifact.origin] + cur_artifact.activated * 50
|
||||
src.accuE2 = 5 + rand(0,10) + range_bonuses[cur_artifact.origin] + cur_artifact.activated * 50
|
||||
|
||||
//keep any correctly determined properties the same
|
||||
var/origin_correct = 0
|
||||
var/trigger_correct = 0
|
||||
var/function_correct = 0
|
||||
var/range_correct = 0
|
||||
if(cur_id == cur_artifact.display_id)
|
||||
if(src.aorigin == cur_artifact.origin)
|
||||
origin_correct = 1
|
||||
|
||||
if(src.atrigger == cur_artifact.my_effect.trigger)
|
||||
trigger_correct = 1
|
||||
else if(src.atrigger == cur_artifact.my_effect.triggerX)
|
||||
trigger_correct = 1
|
||||
|
||||
if(src.aeffect1 == cur_artifact.my_effect.effecttype)
|
||||
function_correct = 1
|
||||
|
||||
if(src.aeffect2 == cur_artifact.my_effect.effectmode)
|
||||
range_correct = 1
|
||||
|
||||
if (src.accuO > 100) src.accuO = 100
|
||||
if (src.accuT > 100) src.accuT = 100
|
||||
if (src.accuE1 > 100) src.accuE1 = 100
|
||||
if (src.accuE2 > 100) src.accuE2 = 100
|
||||
// Roll to generate report
|
||||
if (prob(accuO) || origin_correct)
|
||||
switch(cur_artifact.origin)
|
||||
if("ancient") src.aorigin = "Ancient Robots"
|
||||
if("martian") src.aorigin = "Martian"
|
||||
if("wizard") src.aorigin = "Wizard Federation"
|
||||
if("eldritch") src.aorigin = "Extradimensional"
|
||||
if("precursor") src.aorigin = "Precursor"
|
||||
else src.aorigin = "Unknown Origin"
|
||||
origin_bonuses[cur_artifact.origin] += 10
|
||||
else
|
||||
AA_FailedAnalysis(1)
|
||||
origin_bonuses[cur_artifact.origin] += 5
|
||||
if (prob(accuT) || trigger_correct)
|
||||
switch(cur_artifact.my_effect.trigger)
|
||||
if("touch") src.atrigger = "Contact with Living Organism"
|
||||
if("force") src.atrigger = "Heavy Impact"
|
||||
if("energy") src.atrigger = "Contact with Energy Source"
|
||||
if("chemical")
|
||||
switch(cur_artifact.my_effect.triggerX)
|
||||
if("hydrogen") src.atrigger = "Contact with Hydrogen"
|
||||
if("corrosive") src.atrigger = "Contact with Corrosive Substance"
|
||||
if("volatile") src.atrigger = "Contact with Volatile Substance"
|
||||
if("toxin") src.atrigger = "Contact with Toxins"
|
||||
if("heat") src.atrigger = "Exposure to Heat"
|
||||
else src.atrigger = "Unknown Trigger"
|
||||
trigger_bonuses[cur_artifact.origin] += 5
|
||||
else
|
||||
AA_FailedAnalysis(2)
|
||||
trigger_bonuses[cur_artifact.origin] += 1
|
||||
if (prob(accuE1) || function_correct)
|
||||
switch(cur_artifact.my_effect.effecttype)
|
||||
if("healing") src.aeffect1 = "Healing Device"
|
||||
if("injure") src.aeffect1 = "Anti-biological Weapon"
|
||||
// if("stun") src.aeffect1 = "Non-lethal Stunning Trap"
|
||||
if("roboheal") src.aeffect1 = "Mechanoid Repair Module"
|
||||
if("robohurt") src.aeffect1 = "Mechanoid Deconstruction Device"
|
||||
if("cellcharge") src.aeffect1 = "Power Generator"
|
||||
if("celldrain") src.aeffect1 = "Power Drain"
|
||||
if("planthelper") src.aeffect1 = "Agriculture Regulator"
|
||||
if("forcefield") src.aeffect1 = "Shield Generator"
|
||||
if("teleport") src.aeffect1 = "Space-Time Displacer"
|
||||
else src.aeffect1 = "Unknown Effect"
|
||||
function_bonuses[cur_artifact.origin] += 5
|
||||
else
|
||||
AA_FailedAnalysis(3)
|
||||
function_bonuses[cur_artifact.origin] += 1
|
||||
if (prob(accuE2) || range_correct)
|
||||
switch(cur_artifact.my_effect.effectmode)
|
||||
if("aura") src.aeffect2 = "Constant Short-Range Energy Field"
|
||||
if("pulse")
|
||||
if(cur_artifact.my_effect.aurarange > 7) src.aeffect2 = "Long Range Energy Pulses"
|
||||
else src.aeffect2 = "Medium Range Energy Pulses"
|
||||
if("worldpulse") src.aeffect2 = "Extreme Range Energy Pulses"
|
||||
if("contact") src.aeffect2 = "Requires contact with subject"
|
||||
else src.aeffect2 = "Unknown Range"
|
||||
range_bonuses[cur_artifact.origin] += 5
|
||||
else
|
||||
AA_FailedAnalysis(4)
|
||||
range_bonuses[cur_artifact.origin] += 1
|
||||
|
||||
cur_artifact.name = "alien artifact ([cur_artifact.display_id])"
|
||||
cur_artifact.desc = "A large alien device. It has a small tag near the bottom that reads \"[cur_artifact.display_id]\"."
|
||||
cur_id = cur_artifact.display_id
|
||||
cur_artifact.my_effect.artifact_id = cur_artifact.display_id
|
||||
|
||||
/obj/machinery/artifact_analyser/Topic(href, href_list)
|
||||
|
||||
if(href_list["analyse"])
|
||||
if(owned_pad)
|
||||
var/turf/pad_turf = get_turf(owned_pad)
|
||||
var/findarti = 0
|
||||
for(var/obj/machinery/artifact/A in pad_turf.contents)
|
||||
findarti++
|
||||
cur_artifact = A
|
||||
if (findarti == 1)
|
||||
if(cur_artifact && cur_artifact.being_used)
|
||||
var/message = "<b>[src]</b> states, \"Cannot analyse. Excess energy drain is disrupting signal.\""
|
||||
src.visible_message(message, message)
|
||||
else
|
||||
cur_artifact.anchored = 1
|
||||
cur_artifact.being_used = 1
|
||||
src.working = 1
|
||||
src.icon_state = "analyser_processing"
|
||||
var/time = rand(30,50) + max(0, 300 - scan_num * 10)
|
||||
/*for(var/i = artifact_research.starting_tier, i <= artifact_research.max_tiers, i++)
|
||||
for(var/datum/artiresearch/R in artifact_research.researched_items[i])
|
||||
if (R.bonustype == "analyser") time -= R.bonusTime*/
|
||||
time *= 10
|
||||
var/message = "<b>[src]</b> states, \"Commencing analysis.\""
|
||||
src.visible_message(message, message)
|
||||
use_power(500)
|
||||
spawn(time)
|
||||
src.working = 0
|
||||
icon_state = "analyser"
|
||||
cur_artifact.anchored = 0
|
||||
cur_artifact.being_used = 0
|
||||
if(cur_artifact.loc == pad_turf)
|
||||
AA_Analyse()
|
||||
scan_num++
|
||||
message = "<b>[src]</b> states, \"Analysis complete.\""
|
||||
src.visible_message(message, message)
|
||||
use_power(500)
|
||||
else if (findarti > 1)
|
||||
var/message = "<b>[src]</b> states, \"Cannot analyse. Error isolating energy signature.\""
|
||||
src.visible_message(message, message)
|
||||
else
|
||||
var/message = "<b>[src]</b> states, \"Cannot analyse. No noteworthy energy signature isolated.\""
|
||||
src.visible_message(message, message)
|
||||
|
||||
if(href_list["upload"] && cur_id != "")
|
||||
//add new datum to every DB in the world
|
||||
for(var/obj/machinery/computer/artifact_database/DB in world)
|
||||
var/update = 0
|
||||
for(var/datum/catalogued_artifact/CA in DB.catalogued_artifacts)
|
||||
if(CA.display_id == cur_id)
|
||||
//already there, so update it
|
||||
update = 1
|
||||
CA.origin = aorigin + " ([accuO]%)"
|
||||
CA.trigger = atrigger + " ([accuT]%)"
|
||||
CA.effecttype = aeffect1 + " ([accuE1]%)"
|
||||
CA.effectmode = aeffect2 + " ([accuE2]%)"
|
||||
if(!update)
|
||||
//not there, so add it
|
||||
var/datum/catalogued_artifact/CA = new()
|
||||
CA.display_id = cur_id
|
||||
CA.origin = aorigin + " ([accuO]%)"
|
||||
CA.trigger = atrigger + " ([accuT]%)"
|
||||
CA.effecttype = aeffect1 + " ([accuE1]%)"
|
||||
CA.effectmode = aeffect2 + " ([accuE2]%)"
|
||||
DB.catalogued_artifacts.Add(CA)
|
||||
use_power(100)
|
||||
|
||||
if(href_list["print"])
|
||||
var/r = "Artifact Analysis Report (Scan #[scan_num])<hr>"
|
||||
r += "<B>Artifact ID:</B> [cur_id] (determined from unique energy emission signatures)<BR>"
|
||||
r += "<B>Artifact Origin:</B> [aorigin] ([accuO]%)<BR>"
|
||||
r += "<B>Activation Trigger:</B> [atrigger] ([accuT]%)<BR>"
|
||||
r += "<B>Artifact Function:</B> [aeffect1] ([accuE1]%)<BR>"
|
||||
r += "<B>Artifact Range:</B> [aeffect2] ([accuE2]%)<BR><BR>"
|
||||
var/obj/item/weapon/paper/P = new /obj/item/weapon/paper(src.loc)
|
||||
P.name = "Artifact Analysis Report #[scan_num]"
|
||||
P.info = r
|
||||
for(var/mob/O in hearers(src, null))
|
||||
O.show_message("\icon[src] \blue The [src.name] prints a sheet of paper", 3)
|
||||
use_power(10)
|
||||
|
||||
if(href_list["close"])
|
||||
usr << browse(null, "window=artanalyser")
|
||||
usr.machine = null
|
||||
|
||||
src.updateDialog()
|
||||
|
||||
//stick artifacts onto this then switch the analyser on
|
||||
/obj/machinery/analyser_pad
|
||||
name = "artifact analysis pad"
|
||||
desc = "Studies the structure of artifacts to discover their uses."
|
||||
icon = 'icons/obj/stationobjs.dmi'
|
||||
icon_state = "tele0"
|
||||
anchored = 1
|
||||
density = 0
|
||||
|
||||
/obj/machinery/analyser_pad/New()
|
||||
..()
|
||||
/*spawn(10)
|
||||
for(var/obj/machinery/artifact_analyser/analyser in orange(1))
|
||||
world << "pad found analyser"
|
||||
if(!analyser.owned_pad)
|
||||
analyser.owned_pad = src
|
||||
world << "pad set analyser to self"
|
||||
break*/
|
||||
@@ -1,58 +0,0 @@
|
||||
|
||||
/datum/catalogued_artifact
|
||||
var/trigger = "touch" // What activates it?
|
||||
var/effecttype = "healing" // What does it do?
|
||||
var/effectmode = "aura" // How does it carry out the effect?
|
||||
var/display_id = "" // Artifact ID to display once successfully scanned
|
||||
var/origin = ""
|
||||
|
||||
/obj/machinery/computer/artifact_database
|
||||
name = "Artifact Database"
|
||||
icon_state = "rdcomp"
|
||||
var/list/catalogued_artifacts
|
||||
|
||||
/obj/machinery/computer/artifact_database/New()
|
||||
..()
|
||||
catalogued_artifacts = new/list
|
||||
|
||||
/obj/machinery/computer/artifact_database/Topic(href, href_list)
|
||||
..()
|
||||
if( href_list["close"] )
|
||||
usr << browse(null, "window=artifact_db")
|
||||
usr.machine = null
|
||||
updateDialog()
|
||||
|
||||
/obj/machinery/computer/artifact_database/process()
|
||||
..()
|
||||
updateDialog()
|
||||
|
||||
/obj/machinery/computer/artifact_database/interact(mob/user)
|
||||
if ( (get_dist(src, user) > 1 ) || (stat & (BROKEN|NOPOWER)) )
|
||||
if (!istype(user, /mob/living/silicon))
|
||||
user.machine = null
|
||||
user << browse(null, "window=artifact_db")
|
||||
return
|
||||
var/t = "<B>Artifact Database</B><BR>"
|
||||
t += "<hr>"
|
||||
for(var/datum/catalogued_artifact/CA in catalogued_artifacts)
|
||||
t += "<B>Artifact ID:</B> [CA.display_id] (determined from unique energy emission signatures)<BR>"
|
||||
t += "<B>Artifact Origin:</B> [CA.origin]<BR>"
|
||||
t += "<B>Activation Trigger:</B> [CA.trigger]<BR>"
|
||||
t += "<B>Artifact Function:</B> [CA.effecttype]<BR>"
|
||||
t += "<B>Artifact Range:</B> [CA.effectmode]<BR><BR>"
|
||||
t += "<hr>"
|
||||
t += "<A href='?src=\ref[src];refresh=1'>Refresh</A> <A href='?src=\ref[src];close=1'>Close</A><BR>"
|
||||
user << browse(t, "window=artifact_db;size=500x800")
|
||||
user.machine = src
|
||||
|
||||
/*
|
||||
/datum/artifact_effect
|
||||
var/origin = null // Used in the randomisation/research of the artifact.
|
||||
var/trigger = "touch" // What activates it?
|
||||
var/triggerX = "none" // Used for more varied triggers
|
||||
var/effecttype = "healing" // What does it do?
|
||||
var/effectmode = "aura" // How does it carry out the effect?
|
||||
var/aurarange = 4 // How far the artifact will extend an aura effect.
|
||||
var/display_id = "" // Artifact ID to display once successfully scanned
|
||||
var/list/created_field
|
||||
*/
|
||||
@@ -0,0 +1,59 @@
|
||||
|
||||
datum/reagent/coolant
|
||||
name = "Coolant"
|
||||
id = "coolant"
|
||||
description = "Industrial cooling substance."
|
||||
reagent_state = LIQUID
|
||||
color = "#C8A5DC" // rgb: 200, 165, 220
|
||||
|
||||
datum/chemical_reaction/coolant
|
||||
name = "Coolant"
|
||||
id = "coolant"
|
||||
result = "coolant"
|
||||
required_reagents = list("tungsten" = 1, "oxygen" = 1, "water" = 1)
|
||||
result_amount = 3
|
||||
|
||||
|
||||
|
||||
/obj/structure/reagent_dispensers/coolanttank
|
||||
name = "coolant tank"
|
||||
desc = "A tank of industrial coolant"
|
||||
icon = 'icons/obj/objects.dmi'
|
||||
icon_state = "coolanttank"
|
||||
amount_per_transfer_from_this = 10
|
||||
New()
|
||||
..()
|
||||
reagents.add_reagent("coolant",1000)
|
||||
|
||||
/obj/structure/reagent_dispensers/coolanttank/bullet_act(var/obj/item/projectile/Proj)
|
||||
if(istype(Proj ,/obj/item/projectile/beam)||istype(Proj,/obj/item/projectile/bullet))
|
||||
if(!istype(Proj ,/obj/item/projectile/beam/lastertag) && !istype(Proj ,/obj/item/projectile/beam/practice) )
|
||||
explode()
|
||||
|
||||
/obj/structure/reagent_dispensers/coolanttank/blob_act()
|
||||
explode()
|
||||
|
||||
/obj/structure/reagent_dispensers/coolanttank/ex_act()
|
||||
explode()
|
||||
|
||||
/obj/structure/reagent_dispensers/coolanttank/proc/explode()
|
||||
var/datum/effect/effect/system/harmless_smoke_spread/S = new /datum/effect/effect/system/harmless_smoke_spread
|
||||
//S.attach(src)
|
||||
S.set_up(5, 0, src.loc)
|
||||
|
||||
playsound(src.loc, 'sound/effects/smoke.ogg', 50, 1, -3)
|
||||
spawn(0)
|
||||
S.start()
|
||||
|
||||
var/datum/gas_mixture/env = src.loc.return_air()
|
||||
if(env)
|
||||
if (reagents.total_volume > 750)
|
||||
env.temperature = 0
|
||||
else if (reagents.total_volume > 500)
|
||||
env.temperature -= 100
|
||||
else
|
||||
env.temperature -= 50
|
||||
|
||||
sleep(10)
|
||||
if(src)
|
||||
del(src)
|
||||
@@ -0,0 +1,363 @@
|
||||
|
||||
/obj/machinery/radiocarbon_spectrometer
|
||||
name = "Radiocarbon spectrometer"
|
||||
desc = "A specialised, complex scanner for gleaning information on all manner of small things."
|
||||
anchored = 1
|
||||
density = 1
|
||||
icon = 'icons/obj/virology.dmi'
|
||||
icon_state = "analyser"
|
||||
|
||||
use_power = 1 //1 = idle, 2 = active
|
||||
idle_power_usage = 20
|
||||
active_power_usage = 300
|
||||
|
||||
//var/obj/item/weapon/reagent_containers/glass/coolant_container
|
||||
var/scanning = 0
|
||||
var/report_num = 0
|
||||
//
|
||||
var/obj/item/scanned_item
|
||||
var/last_scan_data = "No scans on record."
|
||||
//
|
||||
var/last_process_worldtime = 0
|
||||
//
|
||||
var/scanner_progress = 0
|
||||
var/scanner_rate = 1.25 //80 seconds per scan
|
||||
var/scanner_rpm = 0
|
||||
var/scanner_rpm_dir = 1
|
||||
var/scanner_temperature = 0
|
||||
var/scanner_seal_integrity = 100
|
||||
//
|
||||
var/coolant_usage_rate = 0 //measured in u/microsec
|
||||
var/fresh_coolant = 0
|
||||
var/coolant_purity = 0
|
||||
var/datum/reagents/coolant_reagents
|
||||
var/used_coolant = 0
|
||||
var/list/coolant_reagents_purity = list()
|
||||
//
|
||||
var/maser_wavelength = 0
|
||||
var/optimal_wavelength = 0
|
||||
var/optimal_wavelength_target = 0
|
||||
var/tleft_retarget_optimal_wavelength = 0
|
||||
var/maser_efficiency = 0
|
||||
//
|
||||
var/radiation = 0 //0-100 mSv
|
||||
var/t_left_radspike = 0
|
||||
var/rad_shield = 0
|
||||
|
||||
/obj/machinery/radiocarbon_spectrometer/New()
|
||||
..()
|
||||
create_reagents(500)
|
||||
coolant_reagents_purity["water"] = 0.5
|
||||
coolant_reagents_purity["icecoffee"] = 0.6
|
||||
coolant_reagents_purity["icetea"] = 0.6
|
||||
coolant_reagents_purity["milkshake"] = 0.6
|
||||
coolant_reagents_purity["leporazine"] = 0.7
|
||||
coolant_reagents_purity["kelotane"] = 0.7
|
||||
coolant_reagents_purity["sterilizine"] = 0.7
|
||||
coolant_reagents_purity["dermaline"] = 0.7
|
||||
coolant_reagents_purity["hyperzine"] = 0.8
|
||||
coolant_reagents_purity["cryoxadone"] = 0.9
|
||||
coolant_reagents_purity["coolant"] = 1
|
||||
coolant_reagents_purity["adminordrazine"] = 2
|
||||
|
||||
/obj/machinery/radiocarbon_spectrometer/attack_hand(var/mob/user as mob)
|
||||
ui_interact(user)
|
||||
|
||||
/obj/machinery/radiocarbon_spectrometer/attackby(var/obj/I as obj, var/mob/user as mob)
|
||||
if(scanning)
|
||||
user << "<span class='warning'>You can't do that while [src] is scanning!</span>"
|
||||
else
|
||||
if(istype(I, /obj/item/stack/nanopaste))
|
||||
var/choice = alert("What do you want to do with the nanopaste?","Radiometric Scanner","Scan nanopaste","Fix seal integrity")
|
||||
if(choice == "Fix seal integrity")
|
||||
var/obj/item/stack/nanopaste/N = I
|
||||
var/amount_used = min(N.amount, 10 - scanner_seal_integrity / 10)
|
||||
N.use(amount_used)
|
||||
scanner_seal_integrity = round(scanner_seal_integrity + amount_used * 10)
|
||||
return
|
||||
if(istype(I, /obj/item/weapon/reagent_containers/glass))
|
||||
var/choice = alert("What do you want to do with the container?","Radiometric Scanner","Add coolant","Empty coolant","Scan container")
|
||||
if(choice == "Add coolant")
|
||||
var/obj/item/weapon/reagent_containers/glass/G = I
|
||||
var/amount_transferred = min(src.reagents.maximum_volume - src.reagents.total_volume, G.reagents.total_volume)
|
||||
G.reagents.trans_to(src, amount_transferred)
|
||||
user << "<span class='info'>You empty [amount_transferred]u of coolant into [src].</span>"
|
||||
update_coolant()
|
||||
return
|
||||
else if(choice == "Empty coolant")
|
||||
var/obj/item/weapon/reagent_containers/glass/G = I
|
||||
var/amount_transferred = min(G.reagents.maximum_volume - G.reagents.total_volume, src.reagents.total_volume)
|
||||
src.reagents.trans_to(G, amount_transferred)
|
||||
user << "<span class='info'>You remove [amount_transferred]u of coolant from [src].</span>"
|
||||
update_coolant()
|
||||
return
|
||||
user.drop_item()
|
||||
I.loc = src
|
||||
scanned_item = I
|
||||
|
||||
/obj/machinery/radiocarbon_spectrometer/proc/update_coolant()
|
||||
var/total_purity = 0
|
||||
fresh_coolant = 0
|
||||
coolant_purity = 0
|
||||
var/num_reagent_types = 0
|
||||
for (var/datum/reagent/current_reagent in src.reagents.reagent_list)
|
||||
if (!current_reagent)
|
||||
continue
|
||||
var/cur_purity = coolant_reagents_purity[current_reagent.id]
|
||||
if(!cur_purity)
|
||||
cur_purity = 0.1
|
||||
else if(cur_purity > 1)
|
||||
cur_purity = 1
|
||||
total_purity += cur_purity * current_reagent.volume
|
||||
fresh_coolant += current_reagent.volume
|
||||
num_reagent_types += 1
|
||||
if(total_purity && fresh_coolant)
|
||||
coolant_purity = total_purity / fresh_coolant
|
||||
|
||||
/obj/machinery/radiocarbon_spectrometer/ui_interact(mob/user, ui_key = "radio_spectro")
|
||||
|
||||
if(user.stat)
|
||||
return
|
||||
|
||||
// this is the data which will be sent to the ui
|
||||
var/data[0]
|
||||
data["scanned_item"] = (scanned_item ? scanned_item.name : "")
|
||||
data["scanned_item_desc"] = (scanned_item ? (scanned_item.desc ? scanned_item.desc : "No information on record.") : "")
|
||||
data["last_scan_data"] = last_scan_data
|
||||
//
|
||||
data["scan_progress"] = round(scanner_progress)
|
||||
data["scanning"] = scanning
|
||||
//
|
||||
data["scanner_seal_integrity"] = round(scanner_seal_integrity)
|
||||
data["scanner_rpm"] = round(scanner_rpm)
|
||||
data["scanner_temperature"] = round(scanner_temperature)
|
||||
//
|
||||
data["coolant_usage_rate"] = "[coolant_usage_rate]"
|
||||
data["unused_coolant_abs"] = round(fresh_coolant)
|
||||
data["unused_coolant_per"] = round(fresh_coolant / reagents.maximum_volume * 100)
|
||||
data["coolant_purity"] = "[coolant_purity * 100]"
|
||||
//
|
||||
data["optimal_wavelength"] = round(optimal_wavelength)
|
||||
data["maser_wavelength"] = round(maser_wavelength)
|
||||
data["maser_efficiency"] = round(maser_efficiency * 100)
|
||||
//
|
||||
data["radiation"] = round(radiation)
|
||||
data["t_left_radspike"] = round(t_left_radspike)
|
||||
data["rad_shield_on"] = rad_shield
|
||||
|
||||
var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, ui_key)
|
||||
if (!ui)
|
||||
// the ui does not exist, so we'll create a new one
|
||||
ui = new(user, src, ui_key, "geoscanner.tmpl", "High Res Radiocarbon Spectrometer", 900, 825)
|
||||
// When the UI is first opened this is the data it will use
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
// Auto update every Master Controller tick
|
||||
ui.set_auto_update(1)
|
||||
else
|
||||
// The UI is already open so push the new data to it
|
||||
ui.push_data(data)
|
||||
return
|
||||
|
||||
/obj/machinery/radiocarbon_spectrometer/process()
|
||||
if(scanning)
|
||||
if(!scanned_item || scanned_item.loc != src)
|
||||
scanned_item = null
|
||||
stop_scanning()
|
||||
else if(scanner_progress >= 100)
|
||||
complete_scan()
|
||||
else
|
||||
//calculate time difference
|
||||
var/deltaT = (world.time - last_process_worldtime) * 0.1
|
||||
|
||||
//modify the RPM over time
|
||||
//i want 1u to last for 10 sec at 500 RPM, scaling linearly
|
||||
scanner_rpm += scanner_rpm_dir * 50 * deltaT
|
||||
if(scanner_rpm > 1000)
|
||||
scanner_rpm = 1000
|
||||
scanner_rpm_dir = -1 * pick(0.5, 2.5, 5.5)
|
||||
else if(scanner_rpm < 1)
|
||||
scanner_rpm = 1
|
||||
scanner_rpm_dir = 1 * pick(0.5, 2.5, 5.5)
|
||||
|
||||
//heat up according to RPM
|
||||
//each unit of coolant
|
||||
scanner_temperature += scanner_rpm * deltaT * 0.05
|
||||
|
||||
//radiation
|
||||
t_left_radspike -= deltaT
|
||||
if(t_left_radspike > 0)
|
||||
//ordinary radiation
|
||||
radiation = rand() * 15
|
||||
else
|
||||
//radspike
|
||||
if(t_left_radspike > -5)
|
||||
radiation = rand() * 15 + 85
|
||||
if(!rad_shield)
|
||||
//irradiate nearby mobs
|
||||
for(var/mob/living/M in view(7,src))
|
||||
M.apply_effect(radiation / 25, IRRADIATE, 0)
|
||||
else
|
||||
t_left_radspike = pick(10,15,25)
|
||||
|
||||
//use some coolant to cool down
|
||||
if(coolant_usage_rate > 0)
|
||||
var/coolant_used = min(fresh_coolant, coolant_usage_rate * deltaT)
|
||||
if(coolant_used > 0)
|
||||
fresh_coolant -= coolant_used
|
||||
used_coolant += coolant_used
|
||||
scanner_temperature = max(scanner_temperature - coolant_used * coolant_purity * 20, 0)
|
||||
|
||||
//modify the optimal wavelength
|
||||
tleft_retarget_optimal_wavelength -= deltaT
|
||||
if(tleft_retarget_optimal_wavelength <= 0)
|
||||
tleft_retarget_optimal_wavelength = pick(4,8,15)
|
||||
optimal_wavelength_target = rand() * 9900 + 100
|
||||
//
|
||||
if(optimal_wavelength < optimal_wavelength_target)
|
||||
optimal_wavelength = min(optimal_wavelength + 700 * deltaT, optimal_wavelength_target)
|
||||
else if(optimal_wavelength > optimal_wavelength_target)
|
||||
optimal_wavelength = max(optimal_wavelength - 700 * deltaT, optimal_wavelength_target)
|
||||
//
|
||||
maser_efficiency = 1 - max(min(10000, abs(optimal_wavelength - maser_wavelength) * 3), 1) / 10000
|
||||
|
||||
//make some scan progress
|
||||
if(!rad_shield)
|
||||
scanner_progress = min(100, scanner_progress + scanner_rate * maser_efficiency * deltaT)
|
||||
|
||||
//degrade the seal over time according to temperature
|
||||
//i want temperature of 50K to degrade at 1%/sec
|
||||
scanner_seal_integrity -= (max(scanner_temperature, 1) / 1000) * deltaT
|
||||
|
||||
//emergency stop if seal integrity reaches 0
|
||||
if(scanner_seal_integrity <= 0 || (scanner_temperature >= 1273 && !rad_shield))
|
||||
stop_scanning()
|
||||
src.visible_message("\blue \icon[src] buzzes unhappily. It has failed mid-scan!", 2)
|
||||
|
||||
if(prob(5))
|
||||
src.visible_message("\blue \icon[src] [pick("whirrs","chuffs","clicks")][pick(" excitedly"," energetically"," busily")].", 2)
|
||||
else
|
||||
//gradually cool down over time
|
||||
if(scanner_temperature > 0)
|
||||
scanner_temperature = max(scanner_temperature - 5 - 10 * rand(), 0)
|
||||
if(prob(0.75))
|
||||
src.visible_message("\blue \icon[src] [pick("plinks","hisses")][pick(" quietly"," softly"," sadly"," plaintively")].", 2)
|
||||
last_process_worldtime = world.time
|
||||
|
||||
/obj/machinery/radiocarbon_spectrometer/proc/stop_scanning()
|
||||
scanning = 0
|
||||
scanner_rpm_dir = 1
|
||||
scanner_rpm = 0
|
||||
optimal_wavelength = 0
|
||||
maser_efficiency = 0
|
||||
maser_wavelength = 0
|
||||
coolant_usage_rate = 0
|
||||
radiation = 0
|
||||
t_left_radspike = 0
|
||||
if(used_coolant)
|
||||
src.reagents.remove_any(used_coolant)
|
||||
used_coolant = 0
|
||||
|
||||
/obj/machinery/radiocarbon_spectrometer/proc/complete_scan()
|
||||
src.visible_message("\blue \icon[src] makes an insistent chime.", 2)
|
||||
|
||||
if(scanned_item)
|
||||
//create report
|
||||
var/obj/item/weapon/paper/P = new(src)
|
||||
P.name = "[src] report #[++report_num]: [scanned_item.name]"
|
||||
P.stamped = list(/obj/item/weapon/stamp)
|
||||
P.overlays = list("paper_stamped")
|
||||
|
||||
//work out data
|
||||
var/data = " - Mundane object: [scanned_item.desc ? scanned_item.desc : "No information on record."]<br>"
|
||||
var/datum/geosample/G
|
||||
switch(scanned_item.type)
|
||||
if(/obj/item/weapon/ore)
|
||||
var/obj/item/weapon/ore/O = scanned_item
|
||||
if(O.geological_data)
|
||||
G = O.geological_data
|
||||
|
||||
if(/obj/item/weapon/rocksliver)
|
||||
var/obj/item/weapon/rocksliver/O = scanned_item
|
||||
if(O.geological_data)
|
||||
G = O.geological_data
|
||||
|
||||
if(/obj/item/weapon/archaeological_find)
|
||||
data = " - Mundane object (archaic xenos origins)<br>"
|
||||
|
||||
var/obj/item/weapon/archaeological_find/A = scanned_item
|
||||
if(A.speaking_to_players)
|
||||
data = " - Exhibits properties consistent with sonic reproduction.<br>"
|
||||
if(A.listening_to_players)
|
||||
data = " - Exhibits properties similar to audio capture technology.<br>"
|
||||
|
||||
var/anom_found = 0
|
||||
if(G)
|
||||
data = " - Spectometric analysis on mineral sample has determined type [finds_as_strings[responsive_carriers.Find(G.source_mineral)]]<br>"
|
||||
if(G.age_billion > 0)
|
||||
data += " - Radiometric dating shows age of [G.age_billion].[G.age_million] billion years<br>"
|
||||
else if(G.age_million > 0)
|
||||
data += " - Radiometric dating shows age of [G.age_million].[G.age_thousand] million years<br>"
|
||||
else
|
||||
data += " - Radiometric dating shows age of [G.age_thousand * 1000 + G.age] years<br>"
|
||||
data += " - Chromatographic analysis shows the following materials present:<br>"
|
||||
for(var/carrier in G.find_presence)
|
||||
if(G.find_presence[carrier])
|
||||
var/index = responsive_carriers.Find(carrier)
|
||||
if(index > 0 && index <= finds_as_strings.len)
|
||||
data += " > [100 * G.find_presence[carrier]]% [finds_as_strings[index]]<br>"
|
||||
|
||||
if(G.artifact_id && G.artifact_distance >= 0)
|
||||
anom_found = 1
|
||||
data += " - Hyperspectral imaging reveals exotic energy wavelength detected with ID: [G.artifact_id]<br>"
|
||||
data += " - Fourier transform analysis on anomalous energy absorption indicates energy source located inside emission radius of [G.artifact_distance]m<br>"
|
||||
|
||||
if(!anom_found)
|
||||
data += " - No anomalous data<br>"
|
||||
|
||||
P.info = "<b>[src] analysis report #[report_num]</b><br>"
|
||||
P.info += "<b>Scanned item:</b> [scanned_item.name]<br><br>" + data
|
||||
last_scan_data = P.info
|
||||
P.loc = src.loc
|
||||
|
||||
scanned_item.loc = src.loc
|
||||
scanned_item = null
|
||||
|
||||
/obj/machinery/radiocarbon_spectrometer/Topic(href, href_list)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return 0 // don't update UIs attached to this object
|
||||
|
||||
if(href_list["scanItem"])
|
||||
if(scanning)
|
||||
stop_scanning()
|
||||
else
|
||||
if(scanned_item)
|
||||
if(scanner_seal_integrity > 0)
|
||||
scanner_progress = 0
|
||||
scanning = 1
|
||||
t_left_radspike = pick(5,10,15)
|
||||
usr << "<span class='notice'>Scan initiated.</span>"
|
||||
else
|
||||
usr << "<span class='warning'>Could not initiate scan, seal requires replacing.</span>"
|
||||
else
|
||||
usr << "<span class='warning'>Insert an item to scan.</span>"
|
||||
|
||||
if(href_list["maserWavelength"])
|
||||
maser_wavelength = max(min(maser_wavelength + 1000 * text2num(href_list["maserWavelength"]), 10000), 1)
|
||||
|
||||
if(href_list["coolantRate"])
|
||||
coolant_usage_rate = max(min(coolant_usage_rate + text2num(href_list["coolantRate"]), 10000), 0)
|
||||
|
||||
if(href_list["toggle_rad_shield"])
|
||||
if(rad_shield)
|
||||
rad_shield = 0
|
||||
else
|
||||
rad_shield = 1
|
||||
|
||||
if(href_list["ejectItem"])
|
||||
if(scanned_item)
|
||||
scanned_item.loc = src.loc
|
||||
scanned_item = null
|
||||
|
||||
add_fingerprint(usr)
|
||||
return 1 // update UIs attached to this object
|
||||
@@ -49,6 +49,8 @@
|
||||
<li><b>Core sampler</b> - use this to take core samples from rock faces, which you can then run to the lab for analysis.</li>
|
||||
<li><b>Depth scanner</b> - uses x-ray diffraction to locate anomalous densities in rock, indicating archaeological deposits or mineral veins.
|
||||
Comes with a handy reference log containing co-ordinates and time of each scan.</li>
|
||||
<li><b>Alden-Saraspova counter</b> - uses a patented application of Fourier Transform analysis to determine the difference between background and
|
||||
exotic radiation. Use it to determine how far you are from anomalous energy sources.</li>
|
||||
<li><b>Radio beacon locater</b> - leave a beacon at an item of interest, then track it down later with this handy gadget. Watch for interference from other
|
||||
devices though.</li>
|
||||
<li><b>Flashlight or portable light source</b> - Self explanatory, I hope.</li>
|
||||
@@ -129,51 +131,50 @@
|
||||
<h1><a name="Contents">Contents</a></h1>
|
||||
<ol>
|
||||
<li><a href="#Terms">A note on terms</a></li>
|
||||
<li><a href="#Isotope">Isotope ratio spectrometer</a></li>
|
||||
<li><a href="#Accelerator">Accelerator spectrometer</a></li>
|
||||
<li><a href="#Gas">Gas chromatography spectrometer</a></li>
|
||||
<li><a href="#Ion">Ion mobility spectrometer</a></li>
|
||||
<li><a href="#Analysis">Analysis progression</a></li>
|
||||
<li><a href="#Heat">Heat management</a></li>
|
||||
<li><a href="#Radiation">Ambient radiation</a></li>
|
||||
</ol>
|
||||
|
||||
<br>
|
||||
<h1><a name="Terms">A note on terms</a></h1>
|
||||
<list>
|
||||
<li><b>Dissonance ratio</b> - This is a pseudoarbitrary value indicating the overal presence of a particular element in a greater composite.
|
||||
It takes into account volume, density, molecular excitation and isotope spread.</li>
|
||||
<li><b>Mass spectrometry</b> - MS is the procedure used used to measure and quantify the components of matter. The most prized tool in the field of
|
||||
'Materials analysis'</li>
|
||||
<li><b>Radiometric dating</b> - MS applied using the right carrier reagents can be used to accurately determine the age of a sample.</li>
|
||||
<li><b>Sample specifity</b> - A pseudoarbitrary value used to indicate how well a sample resonates with the employed carrier reagent. Great specifity
|
||||
(material resonance) indicates that there is much of the carrier reagent present in the sample.</li>
|
||||
<li><b>Dissonance ratio</b> - This is a pseudoarbitrary value indicating the overal presence of a particular element in a greater composite.
|
||||
It takes into account volume, density, molecular excitation and isotope spread.</li>
|
||||
<li><b>Vacuum seal integrity</b> - A reference to how close an airtight seal is to failure.</li>
|
||||
</list><br>
|
||||
<a href="#Contents">Contents</a>
|
||||
|
||||
<h1><a name="Isotope">Isotope ratio spectrometer</a></h1>
|
||||
Isotope ratio mass spectrometers work by coating a small surface with a semiliquid <i>stationary phase</i> consisting of the sample to be
|
||||
analysed, and recording it's interactions with a gaseous <i>mobile phase</i> comprised of an inert or nonreactive gas such as helium or nitrogen.<br>
|
||||
<h1><a name="Analysis">Analysis progression</a></h1>
|
||||
Modern mass spectrometry requires constant attention from the diligant researcher in order to be successul. There are many different elements to juggle,
|
||||
and later chapters will delve into them. For the spectrometry assistant, the first thing you need to know is that the scanner wavelength is automatically
|
||||
calculated for you. Just tweak the settings and try to match it with the actual wavelength as closely as possible.<br>
|
||||
<br>
|
||||
IRMS are employed as radiometric daters, extremely accurate but only so up to ages of one billion years.<br>
|
||||
<a href="#Contents">Contents</a>
|
||||
|
||||
<h1><a name="Accelerator">Accelerator spectrometer</a></h1>
|
||||
The accelerator mass spectrometer works by accelerating ions to extraordinarily high kinetic energies before mass analysis. The special strength of AMS is
|
||||
isolate rare or low-strength isotopes, making it able to determine much greater ages with reasonable accuracy.<br>
|
||||
<h1><a name="Seal">Seal integrity</a></h1>
|
||||
In order to maintain sterile and environmentally static procedures, a special chamber is setup inside the spectrometer. It's protected by a proprietary vacuum seal
|
||||
produced by top tier industrial science. It will only last for a certain number of scans before failing outright, but it can be resealed through use of nanite paste.
|
||||
Unfortunately, it's susceptible to malforming under heat stress so exposing it to higher temperatures will cause it's operation life to drop significantly.<br>
|
||||
<br>
|
||||
AMS are employed as extreme age radiometric daters, able to determine the age of the sample on a scale of billions of years.
|
||||
They are commonly located in geology and archaeology laboratories.<br>
|
||||
<a href="#Contents">Contents</a>
|
||||
|
||||
<h1><a name="Gas">Gas chromatography spectrometer</a></h1>
|
||||
Gas-liquid chromatography mass spectrometers work by coating a small surface with a semiliquid <i>stationary phase</i> consisting of the sample to be
|
||||
analysed, and recording it's interactions with a gaseous <i>mobile phase</i> comprised of an inert or nonreactive gas such as helium or nitrogen.<br>
|
||||
<h1><a name="Heat">Heat management</a></h1>
|
||||
The scanner relies on a gyro-rotational system that varies in speed and intensity. Over the course of an ordinary scan, the RPMs can change dramatically. Higher RPMs
|
||||
means greater heat generation, but is necessary for the ongoing continuation of the scan. To offset heat production, spectrometers have an inbuilt cooling system.
|
||||
Researchers can modify the flow rate of coolant to aid in dropping temperature as necessary, but are advised that frequent coolant replacements may be necessary
|
||||
depending on coolant purity. Water and substances such as cryoxadone are viable substitutes, but nowhere near as effective as pure coolant itself.<br>
|
||||
<br>
|
||||
GLCS are employed in forensic and geological analysis to determine what elements are present in a sample.<br>
|
||||
<a href="#Contents">Contents</a>
|
||||
|
||||
<h1><a name="Ion">Ion mobility spectrometer</a></h1>
|
||||
Ion mobility mass spectrometers work by examining the mobility of ionized molecules in an inert carrier gas<br>
|
||||
<h1><a name="Radiation">Ambient radiation</a></h1>
|
||||
Researchers are warned that while operational, mass spectrometers emit period bursts of radiation and are thus advised to wear protective gear. In the event of
|
||||
radiation spikes, there is also a special shield that can be lowered to block emissions. Lowering this, however, will have the effect of blocking the scanner
|
||||
so use it sparingly.<br>
|
||||
<br>
|
||||
IMS returns a dissonance ratio over the scanned sample and carrier reagent, indicating the average total presence of the sample.<br>
|
||||
<a href="#Contents">Contents</a>
|
||||
|
||||
</body>
|
||||
@@ -197,67 +198,17 @@
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1><a name="Contents">Contents</a></h1>
|
||||
<ol>
|
||||
<li><a href="#Terms">Some useful phrases for you</a></li>
|
||||
<li><a href="#Sample">Sample preparation and analysis</a></li>
|
||||
<li><a href="#Fourier">Fourier transform spectroscope</a></li>
|
||||
<li><a href="#Hyperspectral">Hyperspectral Imager</a></li>
|
||||
</ol>
|
||||
|
||||
<br>
|
||||
<h1><a name="Terms">Some useful phrases for you</a></h1>
|
||||
<list>
|
||||
<li><b>Spectroscopy</b> - Spectroscopy is the study of the behaviour of light, commonly used in the 26th century for analysis of anomalous
|
||||
behaviour of energy or light.</li>
|
||||
<li><b>Sample specifity</b> - A pseudoarbitrary value used to indicate how well a sample resonates with the employed carrier reagent. Great specifity
|
||||
(material resonance) indicates that there is much of the carrier reagent present in the sample.</li>
|
||||
<li><b>Anomalies</b> - Inexplicable or uncategorised occurrences in the cosmos. A fascinating and dangerous study is made to determine the function of
|
||||
these rare finds, and the term is often applied to describe technology left behind by vastly superior ancient alien forerunners.</li>
|
||||
</list><br>
|
||||
<a href="#Contents">Contents</a>
|
||||
|
||||
<h1><a name="Sample">Sample preparation and analysis</a></h1>
|
||||
When you are readying your spectrometry lab for analysis, you'll need to make sure the sample is in a form the machines can glean data from.
|
||||
<list>
|
||||
<li><b>Obtain material sample</b> - This should be an ordinary chunk of matter the size of your finger, a good example is a 6mm rock core.</li>
|
||||
<li><b>Run density separation treatment</b> - Perform the DST procedure on your sample, following generic specifications.</li>
|
||||
<li><b>Ensure sample purity</b> - DST can sometimes leave behind chemical waste or chunks of matter, make sure there aren't any before proceeding.</li>
|
||||
<li><b>Prepare analysis tray</b> - A sample tray holds a miniscule amount of liquid (2u), but that's all that our spectrometers require for a good reading.</li>
|
||||
<li><b>Choose carrier reagent</b> - Standard spectrometers require 1u of the material sample, and 1u of a 'carrier' reagent to provide control comparison
|
||||
and to enable refraction inferencing.</li>
|
||||
<li><b>Insert sample tray into machine</b> - And press the 'Go' button. Now go make a cup of coffee.</li>
|
||||
<li><b>Monitor machine heat levels</b> - The upper end mass spectrometers have quite complex internals, and have a tendency to critically overheat.
|
||||
Make sure the heat limit isn't exceeded, or there may be potentially disastrous consequences.</li>
|
||||
<li><b>Examine analysis report</b> - it won't always make sense or provide the information you hoped for, but if you've been careful during DST and ensured
|
||||
sample integrity, then there's always something to be learnt. Just don't lose the paperwork!</li>
|
||||
</list><br>
|
||||
<a href="#Contents">Contents</a>
|
||||
|
||||
<h1><a name="Fourier">Fourier transform spectroscope</a></h1>
|
||||
The FTS measures temporal coherence of radiating energy, then applies time-and-space domain measurements on the collected emission data. The collective
|
||||
procedure is known as the <i>Fourier Transform Procedure,</i> with the mathematical algorithms dating back to the 19th century on Earth.<br>
|
||||
<br>
|
||||
As well as providing background energy readings, an FTS calculates the approximate distance and direction towards any anomalous energy signatures from
|
||||
the location the scanned sample was taken from.<br>
|
||||
<a href="#Contents">Contents</a>
|
||||
|
||||
<h1><a name="Hyperspectral">Hyperspectral Imager</a></h1>
|
||||
The imager scans and collates spectral energy signatures from across the electromagnetic spectrum. The collected data is then presented to the viewer in
|
||||
graph form, with any anomalous (uncatalogued or unidentified) energy signatures highlighted.<br>
|
||||
<br>
|
||||
As well as visualising background energy readings, a hyperspectral imager will isolate and identify any anomalous energy signatures in the sample.<br>
|
||||
<a href="#Contents">Contents</a>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
It's perhaps one of the most exciting times to be alive, with the recent breakthroughs in understanding and categorisation of things we may one day no longer call
|
||||
'anomalies,' but rather 'infrequent or rare occurrences of certain celestial weather or phenomena.' Perhaps a little more long winded, but no less eloquent all the
|
||||
same! Why, look at the strides we're making in piercing the walls of bluespace or our steadily improving ability to clarify and stabilise subspace emissions; it's
|
||||
certainly an exciting time to be alive. For the moment the Hydrolian hasn't seen two spatial anomalies alike but the day will come and it is soon, I can feel it.
|
||||
"}
|
||||
|
||||
/obj/item/weapon/book/manual/materials_chemistry_analysis
|
||||
name = "Chemical preparation for materials analysis"
|
||||
name = "Materials analysis and the chemical implications"
|
||||
icon_state = "chemistry"
|
||||
author = "Jasper Pascal, Senior Lecturer in Materials Analysis at the University of Jol'Nar"
|
||||
title = "Chemical preparation for materials analysis"
|
||||
title = "Materials analysis and the chemical implications"
|
||||
dat = {"<html>
|
||||
<head>
|
||||
<style>
|
||||
@@ -270,70 +221,13 @@
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1><a name="Contents">Contents</a></h1>
|
||||
<ol>
|
||||
<li><a href="#Terms">Relevant words and their meanings</a></li>
|
||||
<li><a href="#Sample">Sample preparation for spectrometry/spectroscopy</a></li>
|
||||
<li><a href="#DST">Density Separation Treatment</a></li>
|
||||
<li><a href="#Carrier">Choosing a carrier reagent</a></li>
|
||||
</ol>
|
||||
In today's high tech research fields, leaps and bounds are being made every day. Whether it's great strides forward in our understanding of the physical universe
|
||||
or the operation of some fancy new piece of equipment, it seems like all the cool fields are producing new toys to play with leaving doddery old fields such as
|
||||
materials analysis and chemistry relegated to the previous few centuries, when we were still learning the makeup and structure of the elements.<br>
|
||||
<br>
|
||||
<h1><a name="Terms">Relevant words and their meanings</a></h1>
|
||||
<list>
|
||||
<li><b>Dissonance ratio</b> - This is a pseudoarbitrary value indicating the overal presence of a particular element in a greater composite.
|
||||
It takes into account volume, density, molecular excitation and isotope spread.</li>
|
||||
<li><b>Density separation treatment</b> - The DST procedure purifies a sample, removing any unwanted matter to ensure the finest scan resolution possible.</li>
|
||||
<li><b>Mass spectrometry</b> - MS is the procedure used used to measure and quantify the components of matter. The most prized tool in the field of
|
||||
'Materials analysis'</li>
|
||||
<li><b>Spectroscopy</b> - Spectroscopy is the study of the behaviour of light, commonly used in the 26th century for analysis of anomalous
|
||||
behaviour of energy or light.</li>
|
||||
<li><b>Sample specifity</b> - A pseudoarbitrary value used to indicate how well a sample resonates with the employed carrier reagent. Great specifity
|
||||
(material resonance) indicates that there is much of the carrier reagent present in the sample.</li>
|
||||
</list><br>
|
||||
<a href="#Contents">Contents</a>
|
||||
|
||||
<h1><a name="Sample">Sample preparation for spectrometry/spectroscopy</a></h1>
|
||||
When you are readying your spectrometry lab for analysis, you'll need to make sure the sample is in a form the machines can glean data from.
|
||||
<list>
|
||||
<li><b>Obtain material sample</b> - This should be an ordinary chunk of matter the size of your finger, a good example is a 6mm rock core.</li>
|
||||
<li><b>Run density separation treatment</b> - Perform the DST procedure on your sample, following generic specifications.</li>
|
||||
<li><b>Ensure sample purity</b> - DST can sometimes leave behind chemical waste or chunks of matter, make sure there aren't any before proceeding.</li>
|
||||
<li><b>Prepare analysis tray</b> - A sample tray holds a miniscule amount of liquid (2u), but that's all that our spectrometers require for a good reading.</li>
|
||||
<li><b>Choose carrier reagent</b> - Standard spectrometers require 1u of the material sample, and 1u of a 'carrier' reagent to provide control comparison
|
||||
and to enable refraction inferencing.</li>
|
||||
</list><br>
|
||||
<a href="#Contents">Contents</a>
|
||||
|
||||
<h1><a name="DST">Density Separation Treatment</a></h1>
|
||||
<list>
|
||||
<li><b>Obtain material sample</b> - This should be an ordinary chunk of matter the size of your finger, a good example is a 6mm rock core.</li>
|
||||
<li><b>Grind material to powder</b> - In order to treat the material, we have to have the sample in it's basest form.</li>
|
||||
<li><b>Prepare separator solution</b> - A chemical solution called LiNa2WO4, or <i>Lithium Sodium Tungstate</i> must be prepared to separate
|
||||
the the denser clumps of matter out of the refined sample. This is done by mixing 1 part lithium, 2 parts sodium, 1 part tungsten, 4 parts oxygen.</li>
|
||||
<li><b>Mix separator with sample</b> - The resulting mixture is very close to the final product, but make sure to extract any leftover reagents and
|
||||
the chemical waste byproduct.</li>
|
||||
<li><b>Bring sample to boil</b> - Using a standard bunsen burner, bring the mixture containing at least 5u of DST to a boil to vaporise the remaining unwanted matter. Remember
|
||||
to again clear out any waste byproducts.</li>
|
||||
</list><br>
|
||||
<a href="#Contents">Contents</a>
|
||||
|
||||
<h1><a name="Carrier">Choosing a carrier reagent</a></h1>
|
||||
Below is a list of the most commonly used scan carrier reagents, and the particular molecules they resonate most strongly with:
|
||||
<list>
|
||||
<li><b>Carbon</b> - Trace organic cells, typically used for carbon dating of organic remains.</li>
|
||||
<li><b>Potassium</b> - Long exposure particles floating in the depths of space, such as meteorites.</li>
|
||||
<li><b>Hydrogen</b> - Trace water particles.</li>
|
||||
<li><b>Nitrogen</b> - Crystalline structures.</li>
|
||||
<li><b>Mercury</b> - Metallic derivatives such as ferritic elements and pure metallic substances.</li>
|
||||
<li><b>Iron</b> - Metallic composites such as alloys and atomic structures that are metallic in nature.</li>
|
||||
<li><b>Chlorine</b> - Metamorphic/igneous rock composite.</li>
|
||||
<li><b>Phosphorus</b> - Metamorphic/sedimentary rock composite.</li>
|
||||
<li><b>Plasma</b> - Anomalous materials such as bluespace phased composites that are not fully understood by modern science.</li>
|
||||
</list><br>
|
||||
<a href="#Contents">Contents</a>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Well, when you're out there building the next gryo-whatsitron or isotope mobility thingummy, remember how the field of archaeology experienced a massive new rebirth
|
||||
following the excavations at Paranol IV and consider how all of the scientific greats will come crawling back to basic paradigms of natural philosophy when they discover
|
||||
a new element that defies classification. I defy you to classify it without reviving this once great field!
|
||||
"}
|
||||
|
||||
/obj/item/weapon/book/manual/anomaly_testing
|
||||
@@ -391,10 +285,11 @@
|
||||
matter composites that are spatially fixed relative to the source.<br>
|
||||
<br>
|
||||
By taking samples of such 'fixed' matter, we can apply complex analytics such as the modified Fourier Transform Procedure to reverse engineer the path of the
|
||||
energy, and determine the approximate distance and direction that the energy source is, relative to the sample's point in space.<br>
|
||||
energy, and determine the approximate distance and direction that the energy source is, relative to the sample's point in space. Modern portable devices can do
|
||||
all this purely by taking readings of local radiation.<br>
|
||||
<br>
|
||||
A canny researcher can thusly analyse material samples from pre-chosen points strategically scattered around an area, and if there are any anomalous energy
|
||||
emissions in range of those points, combined they can direct the researcher to the source.<br>
|
||||
A canny researcher can thusly analyse radiationat pre-chosen points strategically scattered around an area, and if there are any anomalous energy
|
||||
emissions in range of those points, combined the researcher can triangulate the source.<br>
|
||||
<a href="#Contents">Contents</a>
|
||||
|
||||
<h1><a name="Synthetic">Harvesting and utilising anomalous energy signatures</a></h1>
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
|
||||
//---- Noticeboard
|
||||
|
||||
/obj/structure/noticeboard/anomaly/New()
|
||||
/obj/structure/noticeboard/anomaly
|
||||
notices = 5
|
||||
icon_state = "nboard05"
|
||||
|
||||
/obj/structure/noticeboard/anomaly/New()
|
||||
//add some memos
|
||||
var/obj/item/weapon/paper/P = new()
|
||||
P.name = "Memo RE: proper analysis procedure"
|
||||
P.info = "Rose,<br>activate <i>then</i> analyse the artifacts, the machine will have a much easier time determining their function/s. Remember to employ basic quasi-elemental forces such as heat, energy, force and various chemical mixes - who knows why those ancient aliens made such obscure activation indices.<br><br>And don't forget your suit this time, I can't afford to have any researchers out of commision for as long as that again!.<br>Ward"
|
||||
P.info = "<br>We keep test dummies in pens here for a reason, so standard procedure should be to activate newfound alien artifacts and place the two in close proximity. Promising items I might even approve monkey testing on."
|
||||
P.stamped = list(/obj/item/weapon/stamp/rd)
|
||||
P.overlays = list("paper_stamped_rd")
|
||||
src.contents += P
|
||||
@@ -29,7 +30,7 @@
|
||||
|
||||
P = new()
|
||||
P.name = "READ ME! Before you people destroy any more samples"
|
||||
P.info = "how many times do i have to tell you people, these xeno-arch samples are del-i-cate, and should be handled so! careful application of a focussed, ceoncentrated heat or some corrosive liquids should clear away the extraneous carbon matter, while application of an energy beam will most decidedly destroy it entirely! W, <b>the one who signs your paychecks</b>"
|
||||
P.info = "how many times do i have to tell you people, these xeno-arch samples are del-i-cate, and should be handled so! careful application of a focussed, concentrated heat or some corrosive liquids should clear away the extraneous carbon matter, while application of an energy beam will most decidedly destroy it entirely - like someone did to the chemical dispenser! W, <b>the one who signs your paychecks</b>"
|
||||
P.stamped = list(/obj/item/weapon/stamp/rd)
|
||||
P.overlays = list("paper_stamped_rd")
|
||||
src.contents += P
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
|
||||
/obj/item/device/ano_scanner
|
||||
name = "Alden-Saraspova counter"
|
||||
desc = "Aids in triangulation of exotic particles."
|
||||
icon = 'icons/obj/xenoarchaeology.dmi'
|
||||
icon_state = "flashgun"
|
||||
item_state = "lampgreen"
|
||||
w_class = 1.0
|
||||
flags = FPRINT | TABLEPASS
|
||||
slot_flags = SLOT_BELT
|
||||
var/nearest_artifact_id = "unknown"
|
||||
var/nearest_artifact_distance = -1
|
||||
var/last_scan_time = 0
|
||||
var/scan_delay = 25
|
||||
|
||||
/obj/item/device/ano_scanner/New()
|
||||
..()
|
||||
spawn(0)
|
||||
scan()
|
||||
|
||||
/obj/item/device/ano_scanner/attack_self(var/mob/user as mob)
|
||||
return src.interact(user)
|
||||
|
||||
/obj/item/device/ano_scanner/interact(var/mob/user as mob)
|
||||
var/message = "Background radiation levels detected."
|
||||
if(nearest_artifact_distance >= 0)
|
||||
message = "Exotic energy detected on wavelength '[nearest_artifact_id]' in a radius of [nearest_artifact_distance]m"
|
||||
user << "<span class='info'>[message]</span>"
|
||||
if(world.time - last_scan_time >= scan_delay)
|
||||
spawn(0)
|
||||
scan()
|
||||
|
||||
/obj/item/device/ano_scanner/proc/scan()
|
||||
set background = 1
|
||||
|
||||
last_scan_time = world.time
|
||||
nearest_artifact_distance = -1
|
||||
var/turf/cur_turf = get_turf(src)
|
||||
for(var/turf/simulated/mineral/T in master_controller.artifact_spawning_turfs)
|
||||
if(T.artifact_find)
|
||||
if(T.z == cur_turf.z)
|
||||
var/cur_dist = get_dist(cur_turf, T) * 2
|
||||
if( (nearest_artifact_distance < 0 || cur_dist < nearest_artifact_distance) && cur_dist <= T.artifact_find.artifact_detect_range )
|
||||
nearest_artifact_distance = cur_dist + rand() * 2 - 1
|
||||
nearest_artifact_id = T.artifact_find.artifact_id
|
||||
else
|
||||
master_controller.artifact_spawning_turfs.Remove(T)
|
||||
cur_turf.visible_message("<span class='info'>[src] clicks.</span>")
|
||||
@@ -37,17 +37,19 @@
|
||||
D.record_index = positive_locations.len + 1
|
||||
D.material = M.mineralName
|
||||
|
||||
//find whichever is closer: find or mineral
|
||||
//find the first artifact and store it
|
||||
if(M.finds.len)
|
||||
var/datum/find/F = M.finds[1]
|
||||
D.depth = F.excavation_required * 2
|
||||
D.depth = F.excavation_required * 2 //0-100% and 0-200cm
|
||||
D.clearance = F.clearance_range * 2
|
||||
D.material = get_responsive_reagent(F.find_type)
|
||||
|
||||
//check if there are minerals interfering with the scan
|
||||
if(M.excavation_minerals.len)
|
||||
if(M.excavation_minerals[1] < D.depth)
|
||||
if(!D.depth || M.excavation_minerals[1] < D.depth)
|
||||
D.depth = M.excavation_minerals[1]
|
||||
D.clearance = rand(2,6)
|
||||
D.dissonance_spread = rand(1,1000) / 100
|
||||
D.clearance = rand() * 4 + 1
|
||||
D.material = M.mineralName
|
||||
|
||||
positive_locations.Add(D)
|
||||
|
||||
@@ -71,7 +73,7 @@
|
||||
positive_locations.Add(D)
|
||||
|
||||
for(var/mob/L in range(src, 1))
|
||||
L << "\blue \icon[src] [src] pings [pick("madly","wildly","excitedly","crazily")]."
|
||||
L << "\blue \icon[src] [src] pings [pick("madly","wildly","excitedly","crazily")]!."
|
||||
|
||||
/obj/item/device/depth_scanner/attack_self(var/mob/user as mob)
|
||||
return src.interact(user)
|
||||
@@ -85,7 +87,11 @@
|
||||
dat += "Anomaly depth: [current.depth] cm<br>"
|
||||
dat += "Clearance above anomaly depth: [current.clearance] cm<br>"
|
||||
dat += "Dissonance spread: [current.dissonance_spread]<br>"
|
||||
dat += "Anomaly material: [current.material]<br>"
|
||||
var/index = responsive_carriers.Find(current.material)
|
||||
if(index > 0 && index <= finds_as_strings.len)
|
||||
dat += "Anomaly material: [finds_as_strings[index]]<br>"
|
||||
else
|
||||
dat += "Anomaly material: Unknown<br>"
|
||||
dat += "<A href='?src=\ref[src];clear=[current.record_index]'>clear entry</a><br>"
|
||||
else
|
||||
dat += "Select an entry from the list<br>"
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
//This is an uguu head restoration surgery TOTALLY not yoinked from chinsky's limb reattacher
|
||||
|
||||
|
||||
/datum/surgery_step/head/
|
||||
can_infect = 0
|
||||
can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
if (!hasorgans(target))
|
||||
return 0
|
||||
var/datum/organ/external/affected = target.get_organ(target_zone)
|
||||
if (!affected)
|
||||
return 0
|
||||
if (!(affected.status & ORGAN_DESTROYED))
|
||||
return 0
|
||||
if (affected.parent)
|
||||
if (affected.parent.status & ORGAN_DESTROYED)
|
||||
return 0
|
||||
return target_zone == "head"
|
||||
|
||||
|
||||
/datum/surgery_step/head/peel
|
||||
allowed_tools = list(
|
||||
/obj/item/weapon/retractor = 100, \
|
||||
/obj/item/weapon/crowbar = 75, \
|
||||
/obj/item/weapon/kitchen/utensil/fork = 50, \
|
||||
)
|
||||
|
||||
min_duration = 80
|
||||
max_duration = 100
|
||||
|
||||
|
||||
begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
user.visible_message("[user] starts peeling back tattered flesh where [target]'s head used to be with \the [tool].", \
|
||||
"You start peeling back tattered flesh where [target]'s head used to be with \the [tool].")
|
||||
..()
|
||||
|
||||
end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
var/datum/organ/external/affected = target.get_organ(target_zone)
|
||||
user.visible_message("\blue [user] peels back tattered flesh where [target]'s head used to be with \the [tool].", \
|
||||
"\blue You peel back tattered flesh where [target]'s head used to be with \the [tool].")
|
||||
affected.status |= ORGAN_CUT_AWAY
|
||||
|
||||
fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
var/datum/organ/external/affected = target.get_organ(target_zone)
|
||||
if (affected.parent)
|
||||
affected = affected.parent
|
||||
user.visible_message("\red [user]'s hand slips, ripping [target]'s [affected.display_name] open!", \
|
||||
"\red Your hand slips, ripping [target]'s [affected.display_name] open!")
|
||||
affected.createwound(CUT, 10)
|
||||
|
||||
|
||||
/datum/surgery_step/head/shape
|
||||
allowed_tools = list(
|
||||
/obj/item/weapon/FixOVein = 100, \
|
||||
/obj/item/weapon/cable_coil = 75, \
|
||||
/obj/item/device/assembly/mousetrap = 10) //ok chinsky
|
||||
|
||||
min_duration = 80
|
||||
max_duration = 100
|
||||
|
||||
can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
var/datum/organ/external/affected = target.get_organ(target_zone)
|
||||
return ..() && affected.status & ORGAN_CUT_AWAY
|
||||
|
||||
begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
var/datum/organ/external/affected = target.get_organ(target_zone)
|
||||
user.visible_message("[user] is beginning to reshape [target]'s esophagal and vocal region with \the [tool].", \
|
||||
"You start to reshape [target]'s [affected.display_name] esophagal and vocal region with \the [tool].")
|
||||
..()
|
||||
|
||||
end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
var/datum/organ/external/affected = target.get_organ(target_zone)
|
||||
user.visible_message("\blue [user] has finished repositioning flesh and tissue to something anatomically recognizable where [target]'s head used to be with \the [tool].", \
|
||||
"\blue You have finished repositioning flesh and tissue to something anatomically recognizable where [target]'s head used to be with \the [tool].")
|
||||
affected.open = 3
|
||||
|
||||
fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
var/datum/organ/external/affected = target.get_organ(target_zone)
|
||||
if (affected.parent)
|
||||
affected = affected.parent
|
||||
user.visible_message("\red [user]'s hand slips, further rending flesh on [target]'s neck!", \
|
||||
"\red Your hand slips, further rending flesh on [target]'s neck!")
|
||||
target.apply_damage(10, BRUTE, affected)
|
||||
|
||||
/datum/surgery_step/head/suture
|
||||
allowed_tools = list(
|
||||
/obj/item/weapon/hemostat = 100, \
|
||||
/obj/item/weapon/cable_coil = 60, \
|
||||
/obj/item/weapon/FixOVein = 80)
|
||||
|
||||
min_duration = 80
|
||||
max_duration = 100
|
||||
|
||||
can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
var/datum/organ/external/affected = target.get_organ(target_zone)
|
||||
return ..() && affected.open == 3
|
||||
|
||||
begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
user.visible_message("[user] is stapling and suturing flesh into place in [target]'s esophagal and vocal region with \the [tool].", \
|
||||
"You start to staple and suture flesh into place in [target]'s esophagal and vocal region with \the [tool].")
|
||||
..()
|
||||
|
||||
end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
var/datum/organ/external/affected = target.get_organ(target_zone)
|
||||
user.visible_message("\blue [user] has finished stapling [target]'s neck into place with \the [tool].", \
|
||||
"\blue You have finished stapling [target]'s neck into place with \the [tool].")
|
||||
affected.open = 4
|
||||
|
||||
fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
var/datum/organ/external/affected = target.get_organ(target_zone)
|
||||
if (affected.parent)
|
||||
affected = affected.parent
|
||||
user.visible_message("\red [user]'s hand slips, ripping apart flesh on [target]'s neck!", \
|
||||
"\red Your hand slips, ripping apart flesh on [target]'s neck!")
|
||||
target.apply_damage(10, BRUTE, affected)
|
||||
|
||||
/datum/surgery_step/head/prepare
|
||||
allowed_tools = list(
|
||||
/obj/item/weapon/cautery = 100, \
|
||||
/obj/item/clothing/mask/cigarette = 75, \
|
||||
/obj/item/weapon/lighter = 50, \
|
||||
/obj/item/weapon/weldingtool = 25
|
||||
)
|
||||
|
||||
min_duration = 60
|
||||
max_duration = 70
|
||||
|
||||
can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
var/datum/organ/external/affected = target.get_organ(target_zone)
|
||||
return ..() && affected.open == 4
|
||||
|
||||
begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
user.visible_message("[user] starts adjusting area around [target]'s neck with \the [tool].", \
|
||||
"You start adjusting area around [target]'s neck with \the [tool].")
|
||||
..()
|
||||
|
||||
end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
var/datum/organ/external/affected = target.get_organ(target_zone)
|
||||
user.visible_message("\blue [user] has finished adjusting the area around [target]'s neck with \the [tool].", \
|
||||
"\blue You have finished adjusting the area around [target]'s neck with \the [tool].")
|
||||
affected.status |= ORGAN_ATTACHABLE
|
||||
affected.amputated = 1
|
||||
affected.setAmputatedTree()
|
||||
affected.open = 0
|
||||
|
||||
fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
var/datum/organ/external/affected = target.get_organ(target_zone)
|
||||
if (affected.parent)
|
||||
affected = affected.parent
|
||||
user.visible_message("\red [user]'s hand slips, searing [target]'s neck!", \
|
||||
"\red Your hand slips, searing [target]'s [affected.display_name]!")
|
||||
target.apply_damage(10, BURN, affected)
|
||||
|
||||
|
||||
/datum/surgery_step/head/attach
|
||||
allowed_tools = list(/obj/item/weapon/organ/head = 100)
|
||||
can_infect = 0
|
||||
|
||||
min_duration = 80
|
||||
max_duration = 100
|
||||
|
||||
can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
var/datum/organ/external/head = target.get_organ(target_zone)
|
||||
return ..() && head.status & ORGAN_ATTACHABLE
|
||||
|
||||
begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
user.visible_message("[user] starts attaching [tool] to [target]'s reshaped neck.", \
|
||||
"You start attaching [tool] to [target]'s reshaped neck.")
|
||||
|
||||
end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
var/datum/organ/external/affected = target.get_organ(target_zone)
|
||||
user.visible_message("\blue [user] has attached [target]'s head to the body.", \
|
||||
"\blue You have attached [target]'s head to the body.")
|
||||
affected.status = 0
|
||||
affected.amputated = 0
|
||||
affected.destspawn = 0
|
||||
target.update_body()
|
||||
target.updatehealth()
|
||||
target.UpdateDamageIcon()
|
||||
var/obj/item/weapon/organ/head/B = tool
|
||||
B.brainmob.mind.transfer_to(target)
|
||||
del(B)
|
||||
|
||||
|
||||
fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
||||
var/datum/organ/external/affected = target.get_organ(target_zone)
|
||||
user.visible_message("\red [user]'s hand slips, damaging connectors on [target]'s neck!", \
|
||||
"\red Your hand slips, damaging connectors on [target]'s neck!")
|
||||
target.apply_damage(10, BRUTE, affected)
|
||||
Reference in New Issue
Block a user