Merge remote-tracking branch 'upstream/master' into vision

This commit is contained in:
DZD
2015-09-28 19:03:14 -04:00
128 changed files with 1962 additions and 2922 deletions
+61
View File
@@ -1,3 +1,4 @@
#define MAX_ADMIN_BANS_PER_ADMIN 1
datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration = -1, var/reason, var/job = "", var/rounds = 0, var/banckey = null, var/banip = null, var/bancid = null)
@@ -10,14 +11,22 @@ datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration =
var/serverip = "[world.internet_address]:[world.port]"
var/bantype_pass = 0
var/bantype_str
var/maxadminbancheck //Used to limit the number of active bans of a certein type that each admin can give. Used to protect against abuse or mutiny.
var/announceinirc //When set, it announces the ban in irc. Intended to be a way to raise an alarm, so to speak.
var/blockselfban //Used to prevent the banning of yourself.
var/kickbannedckey //Defines whether this proc should kick the banned person, if they are connected (if banned_mob is defined).
//some ban types kick players after this proc passes (tempban, permaban), but some are specific to db_ban, so
//they should kick within this proc.
switch(bantype)
if(BANTYPE_PERMA)
bantype_str = "PERMABAN"
duration = -1
bantype_pass = 1
blockselfban = 1
if(BANTYPE_TEMP)
bantype_str = "TEMPBAN"
bantype_pass = 1
blockselfban = 1
if(BANTYPE_JOB_PERMA)
bantype_str = "JOB_PERMABAN"
duration = -1
@@ -29,6 +38,21 @@ datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration =
bantype_str = "APPEARANCE_BAN"
duration = -1
bantype_pass = 1
if(BANTYPE_ADMIN_PERMA)
bantype_str = "ADMIN_PERMABAN"
duration = -1
bantype_pass = 1
maxadminbancheck = 1
announceinirc = 1
blockselfban = 1
kickbannedckey = 1
if(BANTYPE_ADMIN_TEMP)
bantype_str = "ADMIN_TEMPBAN"
bantype_pass = 1
maxadminbancheck = 1
announceinirc = 1
blockselfban = 1
kickbannedckey = 1
if( !bantype_pass ) return
if( !istext(reason) ) return
@@ -66,6 +90,11 @@ datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration =
a_ckey = src.owner:ckey
a_computerid = src.owner:computer_id
a_ip = src.owner:address
if(blockselfban)
if(a_ckey == ckey)
usr << "<span class='danger'>You cannot apply this ban type on yourself.</span>"
return
var/who
for(var/client/C in clients)
@@ -82,6 +111,15 @@ datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration =
adminwho += ", [C]"
reason = sql_sanitize_text(reason)
if(maxadminbancheck)
var/DBQuery/adm_query = dbcon.NewQuery("SELECT count(id) AS num FROM [format_table_name("ban")] WHERE (a_ckey = '[a_ckey]') AND (bantype = 'ADMIN_PERMABAN' OR (bantype = 'ADMIN_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)")
adm_query.Execute()
if(adm_query.NextRow())
var/adm_bans = text2num(adm_query.item[1])
if(adm_bans >= MAX_ADMIN_BANS_PER_ADMIN)
usr << "<span class='danger'>You already logged [MAX_ADMIN_BANS_PER_ADMIN] admin ban(s) or more. Do not abuse this function!</span>"
return
var/sql = "INSERT INTO [format_table_name("ban")] (`id`,`bantime`,`serverip`,`bantype`,`reason`,`job`,`duration`,`rounds`,`expiration_time`,`ckey`,`computerid`,`ip`,`a_ckey`,`a_computerid`,`a_ip`,`who`,`adminwho`,`edits`,`unbanned`,`unbanned_datetime`,`unbanned_ckey`,`unbanned_computerid`,`unbanned_ip`) VALUES (null, Now(), '[serverip]', '[bantype_str]', '[reason]', '[job]', [(duration)?"[duration]":"0"], [(rounds)?"[rounds]":"0"], Now() + INTERVAL [(duration>0) ? duration : 0] MINUTE, '[ckey]', '[computerid]', '[ip]', '[a_ckey]', '[a_computerid]', '[a_ip]', '[who]', '[adminwho]', '', null, null, null, null, null)"
var/DBQuery/query_insert = dbcon.NewQuery(sql)
@@ -89,7 +127,12 @@ datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration =
usr << "\blue Ban saved to database."
message_admins("[key_name_admin(usr)] has added a [bantype_str] for [ckey] [(job)?"([job])":""] [(duration > 0)?"([duration] minutes)":""] with the reason: \"[reason]\" to the ban database.",1)
if(announceinirc)
send2irc("BAN ALERT","[a_ckey] applied a [bantype_str] on [ckey]")
if(kickbannedckey)
if(banned_mob && banned_mob.client && banned_mob.client.ckey == banckey)
del(banned_mob.client)
datum/admins/proc/DB_ban_unban(var/ckey, var/bantype, var/job = "")
@@ -114,6 +157,12 @@ datum/admins/proc/DB_ban_unban(var/ckey, var/bantype, var/job = "")
if(BANTYPE_APPEARANCE)
bantype_str = "APPEARANCE_BAN"
bantype_pass = 1
if(BANTYPE_ADMIN_PERMA)
bantype_str = "ADMIN_PERMABAN"
bantype_pass = 1
if(BANTYPE_ADMIN_TEMP)
bantype_str = "ADMIN_TEMPBAN"
bantype_pass = 1
if(BANTYPE_ANY_FULLBAN)
bantype_str = "ANY"
bantype_pass = 1
@@ -300,6 +349,8 @@ datum/admins/proc/DB_ban_unban_by_id(var/id)
output += "<option value='[BANTYPE_JOB_PERMA]'>JOB PERMABAN</option>"
output += "<option value='[BANTYPE_JOB_TEMP]'>JOB TEMPBAN</option>"
output += "<option value='[BANTYPE_APPEARANCE]'>APPEARANCE BAN</option>"
output += "<option value='[BANTYPE_ADMIN_PERMA]'>ADMIN PERMABAN</option>"
output += "<option value='[BANTYPE_ADMIN_TEMP]'>ADMIN TEMPBAN</option>"
output += "</select></td>"
output += "<td width='50%' align='right'><b>Ckey:</b> <input type='text' name='dbbanaddckey'></td></tr>"
output += "<tr><td width='50%' align='right'><b>IP:</b> <input type='text' name='dbbanaddip'></td>"
@@ -339,6 +390,8 @@ datum/admins/proc/DB_ban_unban_by_id(var/id)
output += "<option value='[BANTYPE_JOB_PERMA]'>JOB PERMABAN</option>"
output += "<option value='[BANTYPE_JOB_TEMP]'>JOB TEMPBAN</option>"
output += "<option value='[BANTYPE_APPEARANCE]'>APPEARANCE BAN</option>"
output += "<option value='[BANTYPE_ADMIN_PERMA]'>ADMIN PERMABAN</option>"
output += "<option value='[BANTYPE_ADMIN_TEMP]'>ADMIN TEMPBAN</option>"
output += "</select></td></tr></table>"
output += "<br><input type='submit' value='search'><br>"
output += "<input type='checkbox' value='[match]' name='dbmatch' [match? "checked=\"1\"" : null]> Match(min. 3 characters to search by key or ip, and 7 to search by cid)<br>"
@@ -406,6 +459,10 @@ datum/admins/proc/DB_ban_unban_by_id(var/id)
bantypesearch += "'JOB_TEMPBAN' "
if(BANTYPE_APPEARANCE)
bantypesearch += "'APPEARANCE_BAN' "
if(BANTYPE_ADMIN_PERMA)
bantypesearch = "'ADMIN_PERMABAN' "
if(BANTYPE_ADMIN_TEMP)
bantypesearch = "'ADMIN_TEMPBAN' "
else
bantypesearch += "'PERMABAN' "
@@ -448,6 +505,10 @@ datum/admins/proc/DB_ban_unban_by_id(var/id)
typedesc = "<b>TEMP JOBBAN</b><br><font size='2'>([job])<br>([duration] minutes<br>Expires [expiration]"
if("APPEARANCE_BAN")
typedesc = "<b>APPEARANCE/NAME BAN</b>"
if("ADMIN_PERMABAN")
typedesc = "<b>ADMIN PERMABAN</b>"
if("ADMIN_TEMPBAN")
typedesc = "<b>ADMIN TEMPBAN</b><br><font size='2'>([duration] minutes [(unbanned) ? "" : "(<a href=\"byond://?src=\ref[src];dbbanedit=duration;dbbanid=[banid]\">Edit</a>))"]<br>Expires [expiration]</font>"
output += "<tr bgcolor='[dcolor]'>"
output += "<td align='center'>[typedesc]</td>"
+64 -31
View File
@@ -2,38 +2,42 @@
world/IsBanned(key,address,computer_id)
if (!key || !address || !computer_id)
log_access("Failed Login (invalid data): [key] [address]-[computer_id]")
return list("reason"="invalid login data", "desc"="Your computer provided invalid or blank information to the server on connection (byond username, IP, and Computer ID.) Provided information for reference: Username:'[key]' IP:'[address]' Computer ID:'[computer_id]' If you continue to get this error, please restart byond or contact byond support.")
if(ckey(key) in admin_datums)
return ..()
return list("reason"="invalid login data", "desc"="Error: Could not check ban status, please try again. Error message: Your computer provided invalid or blank information to the server on connection (BYOND Username, IP, and Computer ID). Provided information for reference: Username: '[key]' IP: '[address]' Computer ID: '[computer_id]'. If you continue to get this error, please restart byond or contact byond support.")
var/admin = 0
var/ckey = ckey(key)
if((ckey in admin_datums) || (ckey in deadmins))
admin = 1
//Guest Checking
if(!guests_allowed && IsGuestKey(key))
log_access("Failed Login: [key] - Guests not allowed")
log_access("Failed Login: [key] [computer_id] [address] - Guests not allowed")
// message_admins("\blue Failed Login: [key] - Guests not allowed")
return list("reason"="guest", "desc"="\nReason: Guests not allowed. Please sign in with a byond account.")
return list("reason"="guest", "desc"="\nReason: Guests not allowed. Please sign in with a BYOND account.")
//check if the IP address is a known TOR node
if(config && config.ToRban && ToRban_isbanned(address))
log_access("Failed Login: [src] - Banned: ToR")
message_admins("\blue Failed Login: [src] - Banned: ToR")
//check if the IP address is a known Tor node
if(config.ToRban && ToRban_isbanned(address))
log_access("Failed Login: [key] [computer_id] [address] - Banned: Tor")
message_admins("<span class='adminnotice'>Failed Login: [key] - Banned: Tor</span>")
//ban their computer_id and ckey for posterity
AddBan(ckey(key), computer_id, "Use of ToR", "Automated Ban", 0, 0)
return list("reason"="Using ToR", "desc"="\nReason: The network you are using to connect has been banned.\nIf you believe this is a mistake, please request help at [config.banappeals]")
AddBan(ckey(key), computer_id, "Use of Tor", "Automated Ban", 0, 0)
var/mistakemessage = ""
if(config.banappeals)
mistakemessage = "\nIf you believe this is a mistake, please request help at [config.banappeals]."
return list("reason"="using Tor", "desc"="\nReason: The network you are using to connect has been banned.[mistakemessage]")
if(config.ban_legacy_system)
//Ban Checking
. = CheckBan( ckey(key), computer_id, address )
. = CheckBan(ckey(key), computer_id, address)
if(.)
log_access("Failed Login: [key] [computer_id] [address] - Banned [.["reason"]]")
message_admins("\blue Failed Login: [key] id:[computer_id] ip:[address] - Banned [.["reason"]]")
return .
return ..() //default pager ban stuff
if (admin)
log_admin("The admin [key] has been allowed to bypass a matching ban on [.["key"]]")
message_admins("<span class='adminnotice'>The admin [key] has been allowed to bypass a matching ban on [.["key"]]</span>")
addclientmessage(ckey,"<span class='adminnotice'>You have been allowed to bypass a matching ban on [.["key"]].</span>")
else
log_access("Failed Login: [key] [computer_id] [address] - Banned [.["reason"]]")
return .
else
var/ckeytext = ckey(key)
if(!establish_db_connection())
@@ -49,7 +53,7 @@ world/IsBanned(key,address,computer_id)
if(computer_id)
cidquery = " OR computerid = '[computer_id]' "
var/DBQuery/query = dbcon.NewQuery("SELECT ckey, ip, computerid, a_ckey, reason, expiration_time, duration, bantime, bantype FROM [format_table_name("ban")] WHERE (ckey = '[ckeytext]' [ipquery] [cidquery]) AND (bantype = 'PERMABAN' OR (bantype = 'TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)")
var/DBQuery/query = dbcon.NewQuery("SELECT ckey, ip, computerid, a_ckey, reason, expiration_time, duration, bantime, bantype FROM [format_table_name("ban")] WHERE (ckey = '[ckeytext]' [ipquery] [cidquery]) AND (bantype = 'PERMABAN' OR bantype = 'ADMIN_PERMABAN' OR ((bantype = 'TEMPBAN' OR bantype = 'ADMIN_TEMPBAN') AND expiration_time > Now())) AND isnull(unbanned)")
query.Execute()
@@ -63,18 +67,47 @@ world/IsBanned(key,address,computer_id)
var/duration = query.item[7]
var/bantime = query.item[8]
var/bantype = query.item[9]
if (bantype == "ADMIN_PERMABAN" || bantype == "ADMIN_TEMPBAN")
//admin bans MUST match on ckey to prevent cid-spoofing attacks
// as well as dynamic ip abuse
if (pckey != ckey)
continue
if (admin)
if (bantype == "ADMIN_PERMABAN" || bantype == "ADMIN_TEMPBAN")
log_admin("The admin [key] is admin banned, and has been disallowed access")
message_admins("<span class='adminnotice'>The admin [key] is admin banned, and has been disallowed access</span>")
else
log_admin("The admin [key] has been allowed to bypass a matching ban on [pckey]")
message_admins("<span class='adminnotice'>The admin [key] has been allowed to bypass a matching ban on [pckey]</span>")
addclientmessage(ckey,"<span class='adminnotice'>You have been allowed to bypass a matching ban on [pckey].</span>")
continue
var/expires = ""
if(text2num(duration) > 0)
expires = "The ban is for [duration] minutes and expires on [expiration] (server time)."
if(istext(bantype) && (bantype == "PERMABAN"))
var/appealmsg = ""
if(config && config.banappeals)
appealmsg = " You may appeal it at <a href='[config.banappeals]'>[config.banappeals]</a>."
expires = "The ban is permanent.[appealmsg]"
expires = " The ban is for [duration] minutes and expires on [expiration] (server time)."
else
var/appealmessage = ""
if(config.banappeals)
appealmessage = " You may appeal it at <a href='[config.banappeals]'>[config.banappeals]</a>."
expires = " The is a permanent ban.[appealmessage]"
var/desc = "\nReason: You, or another user of this computer or connection ([pckey]) is banned from playing here. The ban reason is:\n[reason]\nThis ban was applied by [ackey] on [bantime]. [expires]"
var/desc = "\nReason: You, or another user of this computer or connection ([pckey]) is banned from playing here. The ban reason is:\n[reason]\nThis ban was applied by [ackey] on [bantime].[expires]"
return list("reason"="[bantype]", "desc"="[desc]")
. = list("reason"="[bantype]", "desc"="[desc]")
return ..() //default pager ban stuff
log_access("Failed Login: [key] [computer_id] [address] - Banned [.["reason"]]")
return .
. = ..() //default pager ban stuff
if (.)
//byond will not trigger isbanned() for "global" host bans,
//ie, ones where the "apply to this game only" checkbox is not checked (defaults to not checked)
//So it's safe to let admins walk thru host/sticky bans here
if (admin)
log_admin("The admin [key] has been allowed to bypass a matching host/sticky ban")
message_admins("<span class='adminnotice'>The admin [key] has been allowed to bypass a matching host/sticky ban</span>")
addclientmessage(ckey,"<span class='adminnotice'>You have been allowed to bypass a matching host/sticky ban.</span>")
return null
else
log_access("Failed Login: [key] [computer_id] [address] - Banned [.["message"]]")
return .
+2 -2
View File
@@ -11,7 +11,7 @@
return
admin_memo_output(memotask)
/client/proc/admin_memo_output(task, checkrights = 1)
/client/proc/admin_memo_output(task, checkrights = 1, silent = 0)
if(checkrights && !check_rights(R_SERVER))
return
if(!task)
@@ -99,7 +99,7 @@
if(last_editor)
output += "<br><span class='memoedit'>Last edit by [last_editor] <A href='?_src_=holder;memoeditlist=[ckey]'>(Click here to see edit log)</A></span>"
output += "<br>[memotext]</span><br>"
if(!output)
if(!output && !silent)
src << "No memos found in database."
return
src << output
+1 -1
View File
@@ -118,7 +118,7 @@ client/proc/display_admin_reports()
usr << browse(output, "window=news;size=600x400")
client/proc/Report(mob/M as mob in world)
client/proc/Report(mob/M as mob in view())
set category = "Admin"
if(!src.holder)
return
+5 -3
View File
@@ -74,7 +74,8 @@ var/list/admin_verbs_admin = list(
)
var/list/admin_verbs_ban = list(
/client/proc/unban_panel,
/client/proc/jobbans
/client/proc/jobbans,
/client/proc/stickybanpanel
)
var/list/admin_verbs_sounds = list(
/client/proc/play_local_sound,
@@ -225,6 +226,7 @@ var/list/admin_verbs_proccall = list (
admin_verbs_spawn,
admin_verbs_mod,
admin_verbs_mentor,
admin_verbs_proccall,
admin_verbs_show_debug_verbs,
/client/proc/readmin,
)
@@ -570,7 +572,7 @@ var/list/admin_verbs_proccall = list (
log_admin("[key_name(usr)] gave [key_name(T)] a [greater] disease2 with infection chance [D.infectionchance].")
message_admins("[key_name_admin(usr)] gave [key_name(T)] a [greater] disease2 with infection chance [D.infectionchance].")
/client/proc/make_sound(var/obj/O in world) // -- TLE
/client/proc/make_sound(var/obj/O in view()) // -- TLE
set category = "Event"
set name = "Make Sound"
set desc = "Display a message to everyone who can hear the target"
@@ -639,7 +641,7 @@ var/list/admin_verbs_proccall = list (
set name = "De-admin self"
set category = "Admin"
if(!check_rights(R_ADMIN|R_MOD))
if(!check_rights(R_ADMIN|R_MOD|R_MENTOR))
return
log_admin("[key_name(usr)] deadmined themself.")
+211
View File
@@ -0,0 +1,211 @@
/datum/admins/proc/stickyban(action,data)
if(!check_rights(R_BAN))
return
switch (action)
if ("show")
stickyban_show()
return
if ("add")
var/list/ban = list()
var/ckey
ban["admin"] = usr.key
ban["type"] = list("sticky")
ban["reason"] = "(InGameBan)([usr.key])" //this will be displayed in dd only
if (data["ckey"])
ckey = ckey(data["ckey"])
else
ckey = input(usr,"Ckey","Ckey","") as text|null
if (!ckey)
return
ckey = ckey(ckey)
if (get_stickyban_from_ckey(ckey))
usr << "<span class='adminnotice'>Error: Can not add a stickyban: User already has a current sticky ban</span>"
if (data["reason"])
ban["message"] = data["reason"]
else
var/reason = input(usr,"Reason","Reason","Ban Evasion") as text|null
if (!reason)
return
ban["message"] = "[reason]"
world.SetConfig("ban", ckey, list2stickyban(ban))
log_admin("[key_name(usr)] has stickybanned [ckey].\nReason: [ban["message"]]")
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has stickybanned [ckey].\nReason: [ban["message"]]</span>")
if ("remove")
if (!data["ckey"])
return
var/ckey = data["ckey"]
var/ban = get_stickyban_from_ckey(ckey)
if (!ban)
usr << "<span class='adminnotice'>Error: No sticky ban for [ckey] found!</span>"
return
if (alert("Are you sure you want to remove the sticky ban on [ckey]?","Are you sure","Yes","No") == "No")
return
if (!get_stickyban_from_ckey(ckey))
usr << "<span class='adminnotice'>Error: The ban disappeared.</span>"
return
world.SetConfig("ban", ckey, null)
log_admin("[key_name(usr)] removed [ckey]'s stickyban")
message_admins("<span class='adminnotice'>[key_name_admin(usr)] removed [ckey]'s stickyban</span>")
if ("remove_alt")
if (!data["ckey"])
return
var/ckey = data["ckey"]
if (!data["alt"])
return
var/alt = ckey(data["alt"])
var/ban = get_stickyban_from_ckey(ckey)
if (!ban)
usr << "<span class='adminnotice'>Error: No sticky ban for [ckey] found!</span>"
return
var/found = 0
//we have to do it this way because byond keeps the case in its sticky ban matches WHY!!!
for (var/key in ban["keys"])
if (ckey(key) == alt)
found = 1
break
if (!found)
usr << "<span class='adminnotice'>Error: [alt] is not linked to [ckey]'s sticky ban!</span>"
return
if (alert("Are you sure you want to disassociate [alt] from [ckey]'s sticky ban? \nNote: Nothing stops byond from re-linking them","Are you sure","Yes","No") == "No")
return
//we have to do this again incase something changes
ban = get_stickyban_from_ckey(ckey)
if (!ban)
usr << "<span class='adminnotice'>Error: The ban disappeared.</span>"
return
found = 0
for (var/key in ban["keys"])
if (ckey(key) == alt)
ban["keys"] -= key
found = 1
break
if (!found)
usr << "<span class='adminnotice'>Error: [alt] link to [ckey]'s sticky ban disappeared.</span>"
return
world.SetConfig("ban",ckey,list2stickyban(ban))
log_admin("[key_name(usr)] has disassociated [alt] from [ckey]'s sticky ban")
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has disassociated [alt] from [ckey]'s sticky ban</span>")
if ("edit")
if (!data["ckey"])
return
var/ckey = data["ckey"]
var/ban = get_stickyban_from_ckey(ckey)
if (!ban)
usr << "<span class='adminnotice'>Error: No sticky ban for [ckey] found!"
return
var/oldreason = ban["message"]
var/reason = input(usr,"Reason","Reason","[ban["message"]]") as text|null
if (!reason || reason == oldreason)
return
//we have to do this again incase something changed while we waited for input
ban = get_stickyban_from_ckey(ckey)
if (!ban)
usr << "<span class='adminnotice'>Error: The ban disappeared.</span>"
return
ban["message"] = "[reason]"
world.SetConfig("ban",ckey,list2stickyban(ban))
log_admin("[key_name(usr)] has edited [ckey]'s sticky ban reason from [oldreason] to [reason]")
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has edited [ckey]'s sticky ban reason from [oldreason] to [reason]</span>")
spawn(10)
stickyban_show()
/datum/admins/proc/stickyban_gethtml(ckey, ban)
. = "<a href='?_src_=holder;stickyban=remove&ckey=[ckey]'>\[-\]</a><b>[ckey]</b><br />"
. += "[ban["message"]] <b><a href='?_src_=holder;stickyban=edit&ckey=[ckey]'>\[Edit\]</a></b><br />"
if (ban["admin"])
. += "[ban["admin"]]<br />"
else
. += "LEGACY<br />"
. += "Caught keys<br />\n<ol>"
for (var/key in ban["keys"])
if (ckey(key) == ckey)
continue
. += "<li><a href='?_src_=holder;stickyban=remove_alt&ckey=[ckey]&alt=[ckey(key)]'>\[-\]</a>[key]</li>"
. += "</ol>\n"
/datum/admins/proc/stickyban_show()
if(!check_rights(R_BAN))
return
var/list/bans = sortList(world.GetConfig("ban"))
var/banhtml = ""
for(var/key in bans)
var/ckey = ckey(key)
var/ban = stickyban2list(world.GetConfig("ban",key))
banhtml += "<br /><hr />\n"
banhtml += stickyban_gethtml(ckey,ban)
var/html = {"
<head>
<title>Sticky Bans</title>
</head>
<body>
<h2>All Sticky Bans:</h2> <a href='?_src_=holder;stickyban=add'>\[+\]</a><br>
[banhtml]
</body>
"}
usr << browse(html,"window=stickybans;size=700x400")
/proc/get_stickyban_from_ckey(var/ckey)
if (!ckey)
return null
ckey = ckey(ckey)
. = null
for (var/key in world.GetConfig("ban"))
if (ckey(key) == ckey)
. = stickyban2list(world.GetConfig("ban",key))
break
/proc/stickyban2list(var/ban)
if (!ban)
return null
. = params2list(ban)
.["keys"] = text2list(.["keys"], ",")
.["type"] = text2list(.["type"], ",")
.["IP"] = text2list(.["IP"], ",")
.["computer_id"] = text2list(.["computer_id"], ",")
/proc/list2stickyban(var/list/ban)
if (!ban || !islist(ban))
return null
. = ban.Copy()
if (.["keys"])
.["keys"] = list2text(.["keys"], ",")
if (.["type"])
.["type"] = list2text(.["type"], ",")
if (.["IP"])
.["IP"] = list2text(.["IP"], ",")
if (.["computer_id"])
.["computer_id"] = list2text(.["computer_id"], ",")
. = list2params(.)
/client/proc/stickybanpanel()
set name = "Sticky Ban Panel"
set category = "Admin"
if(!check_rights(R_BAN))
return
holder.stickyban_show()
+14
View File
@@ -25,6 +25,9 @@
message_admins("[key_name_admin(usr)] rejected [key_name_admin(C.mob)]'s admin help")
log_admin("[key_name(usr)] rejected [key_name(C.mob)]'s admin help")
if(href_list["stickyban"])
stickyban(href_list["stickyban"],href_list)
if(href_list["makeAntag"])
switch(href_list["makeAntag"])
@@ -123,6 +126,17 @@
return
banduration = null
banjob = null
if(BANTYPE_ADMIN_PERMA)
if(!banckey || !banreason)
usr << "Not enough parameters (Requires ckey and reason)"
return
banduration = null
banjob = null
if(BANTYPE_ADMIN_TEMP)
if(!banckey || !banreason || !banduration)
usr << "Not enough parameters (Requires ckey, reason and duration)"
return
banjob = null
var/mob/playermob
+8 -12
View File
@@ -92,7 +92,6 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","
//send this msg to all admins
var/admin_number_afk = 0
var/list/modholders = list()
var/list/banholders = list()
var/list/adminholders = list()
for(var/client/X in admins)
if(check_rights(R_MOD|R_MENTOR, 0, X.mob))
@@ -103,8 +102,6 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","
if(X.is_afk())
admin_number_afk++
adminholders += X
if(check_rights(R_BAN, 0, X.mob))
banholders += X
switch(selected_type)
if("Question")
@@ -113,15 +110,14 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","
if(X.prefs.sound & SOUND_ADMINHELP)
X << 'sound/effects/adminhelp.ogg'
X << msg
else
if(adminholders.len)
for(var/client/X in adminholders)
if(X.prefs.sound & SOUND_ADMINHELP)
X << 'sound/effects/adminhelp.ogg'
X << msg
else if("Player Complaint")
if(banholders.len)
for(var/client/X in banholders)
if(adminholders.len)
for(var/client/X in adminholders)
if(X.prefs.sound & SOUND_ADMINHELP)
X << 'sound/effects/adminhelp.ogg'
X << msg
if("Player Complaint")
if(adminholders.len)
for(var/client/X in adminholders)
if(X.prefs.sound & SOUND_ADMINHELP)
X << 'sound/effects/adminhelp.ogg'
X << msg
+5 -2
View File
@@ -83,11 +83,13 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
if(!target)
usr << "<font color='red'>Error: callproc(): owner of proc no longer exists.</font>"
return
message_admins("[key_name_admin(src)] called [target]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].")
log_admin("[key_name(src)] called [target]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].")
returnval = call(target,procname)(arglist(lst)) // Pass the lst as an argument list to the proc
else
//this currently has no hascall protection. wasn't able to get it working.
log_admin("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].")
message_admins("[key_name_admin(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]")
log_admin("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]")
returnval = call(procname)(arglist(lst)) // Pass the lst as an argument list to the proc
usr << "<font color='blue'>[procname] returned: [returnval ? returnval : "null"]</font>"
@@ -115,7 +117,8 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
if(!A || !IsValidSrc(A))
usr << "<span class='warning'>Error: callproc_datum(): owner of proc no longer exists.</span>"
return
log_admin("[key_name(src)] called [A]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].")
message_admins("[key_name_admin(src)] called [A]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]")
log_admin("[key_name(src)] called [A]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]")
spawn()
var/returnval = call(A,procname)(arglist(lst)) // Pass the lst as an argument list to the proc
+40 -2
View File
@@ -1,6 +1,9 @@
/client/proc/air_status(turf/target as turf)
set category = "Debug"
set name = "Display Air Status"
if(!check_rights(R_DEBUG))
return
if(!isturf(target))
return
@@ -15,11 +18,22 @@
usr << "\blue @[target.x],[target.y]: O:[GM.oxygen] T:[GM.toxins] N:[GM.nitrogen] C:[GM.carbon_dioxide] w [GM.temperature] Kelvin, [GM.return_pressure()] kPa [(burning)?("\red BURNING"):(null)]"
for(var/datum/gas/trace_gas in GM.trace_gases)
usr << "[trace_gas.type]: [trace_gas.moles]"
message_admins("[key_name_admin(usr)] has checked the air status of [T]")
log_admin("[key_name(usr)] has checked the air status of [T]")
feedback_add_details("admin_verb","DAST") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/fix_next_move()
set category = "Debug"
set name = "Unfreeze Everyone"
if(!check_rights(R_DEBUG))
return
message_admins("[key_name_admin(usr)] has unfrozen everyone")
log_admin("[key_name(usr)] has unfrozen everyone")
var/largest_move_time = 0
var/largest_click_time = 0
var/mob/largest_move_mob = null
@@ -42,15 +56,20 @@
log_admin("DEBUG: [key_name(M)] next_move = [M.next_move] next_click = [M.next_click] world.time = [world.time]")
M.next_move = 1
M.next_click = 0
message_admins("[key_name_admin(largest_move_mob)] had the largest move delay with [largest_move_time] frames / [largest_move_time/10] seconds!", 1)
message_admins("[key_name_admin(largest_click_mob)] had the largest click delay with [largest_click_time] frames / [largest_click_time/10] seconds!", 1)
message_admins("world.time = [world.time]", 1)
feedback_add_details("admin_verb","UFE") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
return
/client/proc/radio_report()
set category = "Debug"
set name = "Radio report"
if(!check_rights(R_DEBUG))
return
var/filters = list(
"1" = "RADIO_TO_AIRALARM",
@@ -83,15 +102,22 @@
output += "&nbsp;&nbsp;&nbsp;&nbsp;[device]<br>"
usr << browse(output,"window=radioreport")
message_admins("[key_name_admin(usr)] has generated a radio report")
log_admin("[key_name(usr)] has generated a radio report")
feedback_add_details("admin_verb","RR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/reload_admins()
set name = "Reload Admins"
set category = "Debug"
if(!check_rights(R_SERVER)) return
if(!check_rights(R_SERVER))
return
message_admins("[usr] manually reloaded admins")
message_admins("[key_name_admin(usr)] has manually reloaded admins")
log_admin("[key_name(usr)] has manually reloaded admins")
load_admins()
feedback_add_details("admin_verb","RLDA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -100,15 +126,24 @@
set name = "Print Jobban Log"
set desc = "This spams all the active jobban entries for the current round to standard output."
set category = "Debug"
if(!check_rights(R_DEBUG))
return
usr << "<b>Jobbans active in this round.</b>"
for(var/t in jobban_keylist)
usr << "[t]"
message_admins("[key_name_admin(usr)] has printed the jobban log")
log_admin("[key_name(usr)] has printed the jobban log")
/client/proc/print_jobban_old_filter()
set name = "Search Jobban Log"
set desc = "This searches all the active jobban entries for the current round and outputs the results to standard output."
set category = "Debug"
if(!check_rights(R_DEBUG))
return
var/filter = input("Contains what?","Filter") as text|null
if(!filter)
@@ -118,3 +153,6 @@
for(var/t in jobban_keylist)
if(findtext(t, filter))
usr << "[t]"
message_admins("[key_name_admin(usr)] has searched the jobban log for [filter]")
log_admin("[key_name(usr)] has searched the jobban log for [filter]")
+5 -1
View File
@@ -323,8 +323,12 @@ var/list/forbidden_varedit_object_types = list(
for(var/p in forbidden_varedit_object_types)
if( istype(O,p) )
usr << "\red It is forbidden to edit this object's variables."
usr << "<span class='warning'>It is forbidden to edit this object's variables.</span>"
return
if(istype(O, /client) && (param_var_name == "ckey" || param_var_name == "key"))
usr << "<span class='warning'>You cannot edit ckeys on client objects.</span>"
return
var/class
var/variable
+3 -3
View File
@@ -567,7 +567,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
message_admins("[key_name_admin(src)] has created a command report", 1)
feedback_add_details("admin_verb","CCR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/cmd_admin_delete(atom/O as obj|mob|turf in world)
/client/proc/cmd_admin_delete(atom/O as obj|mob|turf in view())
set category = "Admin"
set name = "Delete"
@@ -596,7 +596,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
src << "[job.title]: [job.total_positions]"
feedback_add_details("admin_verb","LFS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/cmd_admin_explosion(atom/O as obj|mob|turf in world)
/client/proc/cmd_admin_explosion(atom/O as obj|mob|turf in view())
set category = "Event"
set name = "Explosion"
@@ -627,7 +627,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
else
return
/client/proc/cmd_admin_emp(atom/O as obj|mob|turf in world)
/client/proc/cmd_admin_emp(atom/O as obj|mob|turf in view())
set category = "Special Verbs"
set name = "EM Pulse"
+9 -4
View File
@@ -272,7 +272,7 @@
if(holder)
add_admin_verbs()
admin_memo_output("Show", 0)
admin_memo_output("Show", 0, 1)
// Forcibly enable hardware-accelerated graphics, as we need them for the lighting overlays.
// (but turn them off first, since sometimes BYOND doesn't turn them on properly otherwise)
@@ -282,15 +282,20 @@
winset(src, null, "command=\".configure graphics-hwmode on\"")
log_client_to_db()
if (ckey in clientmessages)
for (var/message in clientmessages[ckey])
src << message
clientmessages.Remove(ckey)
if (config && config.autoconvert_notes)
convert_notes_sql(ckey)
send_resources()
//////////////
//DISCONNECT//
//////////////
//////////////
//DISCONNECT//
//////////////
/client/Del()
if(holder)
holder.owner = null
+9
View File
@@ -0,0 +1,9 @@
var/list/clientmessages = list()
proc/addclientmessage(var/ckey, var/message)
ckey = ckey(ckey)
if (!ckey || !message)
return
if (!(ckey in clientmessages))
clientmessages[ckey] = list()
clientmessages[ckey] += message
+5 -5
View File
@@ -264,10 +264,10 @@
job_karma_high='[job_karma_high]',
job_karma_med='[job_karma_med]',
job_karma_low='[job_karma_low]',
flavor_text='[sql_sanitize_text(flavor_text)]',
med_record='[sql_sanitize_text(med_record)]',
sec_record='[sql_sanitize_text(sec_record)]',
gen_record='[sql_sanitize_text(gen_record)]',
flavor_text='[sql_sanitize_text(html_decode(flavor_text))]',
med_record='[sql_sanitize_text(html_decode(med_record))]',
sec_record='[sql_sanitize_text(html_decode(sec_record))]',
gen_record='[sql_sanitize_text(html_decode(gen_record))]',
player_alt_titles='[playertitlelist]',
be_special='[be_special]',
disabilities='[disabilities]',
@@ -321,7 +321,7 @@
'[job_medsci_high]', '[job_medsci_med]', '[job_medsci_low]',
'[job_engsec_high]', '[job_engsec_med]', '[job_engsec_low]',
'[job_karma_high]', '[job_karma_med]', '[job_karma_low]',
'[sql_sanitize_text(flavor_text)]', '[sql_sanitize_text(med_record)]', '[sql_sanitize_text(sec_record)]', '[sql_sanitize_text(gen_record)]',
'[sql_sanitize_text(html_encode(flavor_text))]', '[sql_sanitize_text(html_encode(med_record))]', '[sql_sanitize_text(html_encode(sec_record))]', '[sql_sanitize_text(html_encode(gen_record))]',
'[playertitlelist]', '[be_special]',
'[disabilities]', '[organlist]', '[rlimblist]', '[nanotrasen_relation]', '[speciesprefs]',
'[socks]', '[body_accessory]')
+16 -40
View File
@@ -5,7 +5,7 @@
desc = "A special containment suit designed to protect a plasmaman's volatile body from outside exposure and quickly extinguish it in emergencies."
allowed = list(/obj/item/weapon/gun,/obj/item/ammo_casing,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/melee/energy/sword,/obj/item/weapon/restraints/handcuffs,/obj/item/weapon/tank)
slowdown = 0
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 100, rad = 20)
armor = list(melee = 0, bullet = 0, laser = 0 ,energy = 0, bomb = 0, bio = 100, rad = 20)
heat_protection = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS
body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS
flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
@@ -16,9 +16,9 @@
icon_state = "plasmaman_suit"
item_state = "plasmaman_suit"
var/next_extinguish=0
var/extinguish_cooldown=10 SECONDS
var/extinguishes_left=10 // Yeah yeah, reagents, blah blah blah. This should be simple.
var/next_extinguish = 0
var/extinguish_cooldown = 10 SECONDS
var/extinguishes_left = 10 // Yeah yeah, reagents, blah blah blah. This should be simple.
/obj/item/clothing/suit/space/eva/plasmaman/examine(mob/user)
..(user)
@@ -46,35 +46,26 @@
var/base_state = "plasmaman_helmet"
var/brightness_on = 4 //luminosity when on
var/on = 0
var/no_light=0 // Disable the light on the atmos suit
action_button_name = "Toggle Helmet Light"
/obj/item/clothing/head/helmet/space/eva/plasmaman/attack_self(mob/user)
if(!isturf(user.loc))
user << "You cannot turn the light on while in this [user.loc]" //To prevent some lighting anomalities.
return
if(no_light)
user << "<span class='warning'>You cannot turn the light on while in this [user.loc].</span>" //To prevent some lighting anomalities.
return
toggle_light(user)
/obj/item/clothing/head/helmet/space/eva/plasmaman/proc/toggle_light(mob/user)
on = !on
icon_state = "[base_state][on]"
if(on) user.set_light(user.luminosity + brightness_on)
else user.set_light(user.luminosity - brightness_on)
user.update_inv_head()
/obj/item/clothing/head/helmet/space/eva/plasmaman/pickup(mob/user)
if(on)
user.set_light(user.luminosity + brightness_on)
// user.UpdateLuminosity()
if(on)
set_light(brightness_on)
else
set_light(0)
/obj/item/clothing/head/helmet/space/eva/plasmaman/dropped(mob/user)
if(on)
user.set_light(user.luminosity - brightness_on)
// user.UpdateLuminosity()
set_light(brightness_on)
if(istype(user,/mob/living/carbon/human))
var/mob/living/carbon/human/H = user
H.update_inv_head()
// ENGINEERING
/obj/item/clothing/suit/space/eva/plasmaman/assistant
@@ -305,7 +296,7 @@
/obj/item/clothing/suit/space/eva/plasmaman/nuclear
name = "blood red plasmaman suit"
icon_state = "plasmaman_Nukeops"
armor = list(melee = 60, bullet = 50, laser = 30, energy = 15, bomb = 35, bio = 100, rad = 60)
armor = list(melee = 60, bullet = 50, laser = 30, energy = 15, bomb = 35, bio = 100, rad = 50)
allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/weapon/gun,/obj/item/ammo_casing,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/melee/energy/sword,/obj/item/weapon/restraints/handcuffs)
siemens_coefficient = 0.6
@@ -313,20 +304,5 @@
name = "blood red plasmaman helmet"
icon_state = "plasmaman_Nukeops_helmet0"
base_state = "plasmaman_Nukeops_helmet"
armor = list(melee = 60, bullet = 50, laser = 30,energy = 15, bomb = 35, bio = 100, rad = 60)
armor = list(melee = 60, bullet = 50, laser = 30, energy = 15, bomb = 35, bio = 100, rad = 50)
siemens_coefficient = 0.6
var/obj/machinery/camera/camera
/obj/item/clothing/head/helmet/space/eva/plasmaman/nuclear/attack_self(mob/user)
if(camera)
..(user)
else
camera = new /obj/machinery/camera(src)
camera.network = list("NUKE")
cameranet.removeCamera(camera)
camera.c_tag = user.name
user << "<span class='notice'>User scanned as [camera.c_tag]. Camera activated.</span>"
/obj/item/clothing/head/helmet/space/eva/plasmaman/nuclear/examine(mob/user)
if(..(user, 1))
user << "<span class='info'>This helmet has a built-in camera. It's [camera ? "" : "in"]active.</span>"
+31 -71
View File
@@ -27,20 +27,24 @@
"Vox" = 'icons/obj/clothing/species/vox/hats.dmi',
)
attack_self(mob/user)
if(!isturf(user.loc))
user << "You cannot turn the light on while in this [user.loc]" //To prevent some lighting anomalities.
return
on = !on
icon_state = "rig[on]-[_color]"
// item_state = "rig[on]-[color]"
/obj/item/clothing/head/helmet/space/rig/attack_self(mob/user)
if(!isturf(user.loc))
user << "<span class='warning'>You cannot turn the light on while in this [user.loc].</span>" //To prevent some lighting anomalities.
return
toggle_light(user)
if(on) set_light(brightness_on)
else set_light(0)
/obj/item/clothing/head/helmet/space/rig/proc/toggle_light(mob/user)
on = !on
icon_state = "rig[on]-[_color]"
if(istype(user,/mob/living/carbon/human))
var/mob/living/carbon/human/H = user
H.update_inv_head()
if(on)
set_light(brightness_on)
else
set_light(0)
if(istype(user,/mob/living/carbon/human))
var/mob/living/carbon/human/H = user
H.update_inv_head()
/obj/item/clothing/suit/space/rig
name = "hardsuit"
@@ -98,7 +102,7 @@
else
M << "Your suit's helmet deploys with a hiss."
//TODO: Species check, skull damage for forcing an unfitting helmet on?
helmet.loc = H
helmet.forceMove(H)
H.equip_to_slot(helmet, slot_head)
helmet.flags |= NODROP
@@ -107,7 +111,7 @@
M << "You are unable to deploy your suit's magboots as \the [H.shoes] are in the way."
else
M << "Your suit's boots deploy with a hiss."
boots.loc = H
boots.forceMove(H)
H.equip_to_slot(boots, slot_shoes)
boots.flags |= NODROP
@@ -122,7 +126,7 @@
if(helmet && H.head == helmet)
helmet.flags &= ~NODROP
H.unEquip(helmet)
helmet.loc = src
helmet.forceMove(src)
if(boots)
H = boots.loc
@@ -130,58 +134,15 @@
if(boots && H.shoes == boots)
boots.flags &= ~NODROP
H.unEquip(boots)
boots.loc = src
/*
/obj/item/clothing/suit/space/rig/verb/get_mounted_device()
set name = "Deploy Mounted Device"
set category = "Object"
set src in usr
if(!can_mount)
verbs -= /obj/item/clothing/suit/space/rig/verb/get_mounted_device
verbs -= /obj/item/clothing/suit/space/rig/verb/stow_mounted_device
return
if(!istype(usr, /mob/living)) return
if(usr.stat) return
if(active_device)
usr << "You already have \the [active_device] deployed."
return
if(!mounted_devices.len)
usr << "You do not have any devices mounted on \the [src]."
return
/obj/item/clothing/suit/space/rig/verb/stow_mounted_device()
set name = "Stow Mounted Device"
set category = "Object"
set src in usr
if(!can_mount)
verbs -= /obj/item/clothing/suit/space/rig/verb/get_mounted_device
verbs -= /obj/item/clothing/suit/space/rig/verb/stow_mounted_device
return
if(!istype(usr, /mob/living)) return
if(usr.stat) return
if(!active_device)
usr << "You have no device currently deployed."
return
*/
boots.forceMove(src)
/obj/item/clothing/suit/space/rig/verb/toggle_helmet()
set name = "Toggle Helmet"
set category = "Object"
set src in usr
if(!istype(src.loc,/mob/living)) return
if(!isliving(usr))
return
if(!helmet)
usr << "There is no helmet installed."
@@ -197,23 +158,22 @@
helmet.flags &= ~NODROP
H.unEquip(helmet)
helmet.loc = src
H << "\blue You retract your hardsuit helmet."
H << "<span class='notice'>You retract your hardsuit helmet.</span>"
else
if(H.head)
H << "\red You cannot deploy your helmet while wearing another helmet."
H << "<span class='warning'>You cannot deploy your helmet while wearing another helmet.</span>"
return
//TODO: Species check, skull damage for forcing an unfitting helmet on?
helmet.loc = H
helmet.pickup(H)
H.equip_to_slot(helmet, slot_head)
helmet.flags |= NODROP
H << "\blue You deploy your hardsuit helmet, sealing you off from the world."
H << "<span class='notice'>You deploy your hardsuit helmet, sealing you off from the world.</span>"
H.update_inv_head()
/obj/item/clothing/suit/space/rig/attackby(obj/item/W as obj, mob/user as mob, params)
if(!istype(user,/mob/living)) return
if(!isliving(user))
return
if(istype(src.loc,/mob/living))
user << "How do you propose to modify a hardsuit while it is being worn?"
@@ -230,7 +190,7 @@
if(!boots)
user << "\The [src] does not have any boots installed."
else
user << "You detatch \the [boots] from \the [src]'s boot mounts."
user << "You detach \the [boots] from \the [src]'s boot mounts."
boots.loc = get_turf(src)
boots = null
return
@@ -338,8 +298,9 @@
/obj/item/clothing/head/helmet/space/rig/syndi/attack_self(mob/user)
if(!isturf(user.loc))
user << "You cannot toggle your helmet while in this [user.loc]" //To prevent some lighting anomalities.
user << "You cannot toggle your helmet while in this [user.loc]." //To prevent some lighting anomalities.
return
on = !on
if(on)
user << "<span class='notice'>You switch your helmet to travel mode. It will allow you to stand in zero pressure environments, at the cost of speed and armor.</span>"
@@ -484,7 +445,6 @@
heat_protection = HEAD //Uncomment to enable firesuit protection
max_heat_protection_temperature = FIRE_IMMUNITY_HELM_MAX_TEMP_PROTECT
/obj/item/clothing/suit/space/rig/atmos
desc = "A special suit that protects against hazardous, low pressure environments. Has improved thermal protection and minor radiation shielding."
icon_state = "rig-atmos"
@@ -62,6 +62,7 @@
Item.loc = get_turf(M.loc)
HackProperties(Item,propadjust)
M.regenerate_icons()
// This is hacky, but since it's difficult as fuck to make a proper parser in BYOND without killing the server, here it is. - N3X
/proc/HackProperties(var/mob/living/carbon/human/M,var/obj/item/I,var/script)
View File
-63
View File
@@ -1,63 +0,0 @@
// Management of available genes.
/datum/genetree
var/list/sectors=list()
var/list/dependencies=list()
var/list/dependants=list()
var/obj/machinery/networked/biomass_controller/biomass = null
/datum/genetree/New(var/obj/machinery/networked/biomass_controller/holder)
biomass = holder
// Build list of all sectors
for(var/typepath in subtypesof(/datum/genetic_sector))
var/datum/genetic_sector/sector = new typepath
sectors[sector.id]=sector
if(sector.prerequisites.len > 0)
sector.locked=1
// Make list of things that depend on this sector.
dependencies[sector.id]=sector.prerequisites
// Generate reverse dependencies
for(var/dependee in sector.prerequisites)
if(!(dependee in dependants))
dependants[dependee]=list(sector.id)
else
var/list/D = dependants[dependee]
D.Add(sector.name)
/datum/genetree/proc/IsActive(var/sname)
var/datum/genetic_sector/sector = sectors[sname]
return sector.active
/datum/genetree/proc/CanActivateSector(var/sname)
var/datum/genetic_sector/sector = sectors[sname]
for(var/dep in sector.prerequisites)
if(!IsActive(sector.id))
return 0
return biomass.available >= sector.required_biomass
// Does NOT check for biomass
/datum/genetree/proc/ActivateSector(var/sname)
var/datum/genetic_sector/sector = sectors[sname]
sector.active = 1
sector.OnActivate()
for(var/subsect in dependants[sname])
var/datum/genetic_sector/subsector = sectors[subsect]
subsector.locked=0
/datum/genetree/proc/CheckSectors()
var/sectors_changed=0
for(var/sname in sectors)
var/datum/genetic_sector/sector = sectors[sname]
var/pstate=sector.active
sector.active=1
for(var/prereq in sector.prerequisites)
if(!IsActive(prereq))
sector.active=0
break
if(pstate != sector.active)
sectors_changed = 1
if(sectors_changed)
CheckSectors()
-110
View File
@@ -1,110 +0,0 @@
var/global/current_sector_id=0
/datum/genetic_sector
var/name = "UNKNOWN SECTOR"
var/desc = "LOLIDK"
var/id = ""
var/uniqid = "" // 3-char ID, shown when locked.
var/list/prerequisites = list()
var/list/blocks_txt = list()
var/list/blocks = list() // DO NOT FUCKING USE THIS
var/required_biomass = 0 // In hominids (/mob/living/carbon)
var/time_required = 300 // Decaseconds required to unlock
var/time_researched = 0
var/active=0 // Accessible
var/locked=0 // Cannot be purchased (yet)
/datum/genetic_sector/New()
uniqid = add_zero2("[current_sector_id++]",3)
// Set blocks
for(var/blockname in blocks_txt)
var/block = assigned_blocks[blockname]
if(block)
blocks += block
///////////////////////////////////////
// SECTORS
///////////////////////////////////////
/datum/genetic_sector/metabolism
id = "metabolism"
name = "Metabolism"
desc = "Grants access to areas of DNA that affect how the body controls its temperature."
required_biomass = 1
time_required = 30 SECONDS
blocks_txt=list(
"COLD",
"FIRE",
"IMMOLATE",
"SOBER",
"MELT",
"FAT"
)
/datum/genetic_sector/mind
id = "mind"
name = "Mental Aptitude"
desc = "Reveals parts of DNA that affect mental capabilities"
required_biomass = 2
time_required = 30 SECONDS
blocks_txt=list(
"PSYRESIST",
"HALLUCINATION",
"TWITCH",
"EPILEPSY",
)
/datum/genetic_sector/teleability
id = "teleability"
name = "Teleability"
desc = "Activates unused portions of the brain that can affect people a great distance away."
prerequisites = list("mind")
required_biomass = 4
time_required = 1 MINUTES
blocks_txt = list(
"REMOTEVIEW",
"REMOTETALK",
"CRYO",
"EMPATH"
)
/datum/genetic_sector/telekinesis
id = "telekinesis"
name = "Telekinesis"
desc = "Activates unused portions of the brain that can affect objects a great distance away."
prerequisites = list("teleability")
required_biomass = 5
time_required = 2 MINUTES
blocks_txt = list(
"TELE",
"FAKE"
)
/datum/genetic_sector/senses
id = "senses"
name = "Senses"
desc = "Accesses genes that affect vision and hearing."
prerequisites = list("mind")
required_biomass = 4
time_required = 30 SECONDS
blocks_txt = list(
"XRAY",
"BLIND",
"GLASSES",
"EMPATH",
"DEAF"
)
/datum/genetic_sector/respiration
id = "respiration"
name = "Respiration"
desc = "Mess around with genes that affect breathing and lungs."
prerequisites = list("metabolism")
time_required = 1 MINUTES
required_biomass = 4
blocks_txt = list(
"NOBREATH",
"COUGH",
"INCREASERUN",
)
-243
View File
@@ -1,243 +0,0 @@
/proc/bsi_cast_ray(icon/I, list/start, list/end)
if(abs(start[1] - end[1]) > abs(start[2] - end[2]))
var/dist = abs(start[1] - end[1]) * 2
for(var/i = 1, i <= dist, i++)
var/x = round((start[1] * i / dist) + (end[1] * (1 - i / dist)))
var/y = round((start[2] * i / dist) + (end[2] * (1 - i / dist)))
if(I.GetPixel(x, y) != null)
return list(x, y)
else
var/dist = abs(start[2] - end[2]) * 2
for(var/i = 1, i <= dist, i++)
var/x = round((start[1] * i / dist) + (end[1] * (1 - i / dist)))
var/y = round((start[2] * i / dist) + (end[2] * (1 - i / dist)))
if(I.GetPixel(x, y) != null)
return list(x, y)
return null
/proc/bsi_split_colors(color)
if(color == null)
return list(0, 0, 0, 0)
var/list/colors = list(0, 0, 0, 0)
colors[1] = hex2num(copytext(color, 2, 4))
colors[2] = hex2num(copytext(color, 4, 6))
colors[3] = hex2num(copytext(color, 6, 8))
colors[4] = (length(color) > 7)? hex2num(copytext(color, 8, 10)) : 255
return colors
/proc/bsi_spread(icon/I, list/start_point)
var/list/queue = list()
queue[++queue.len] = start_point
var/i = 0
while(i++ < length(queue))
var/x = queue[i][1]
var/y = queue[i][2]
var/list/pixel = bsi_split_colors(I.GetPixel(x, y))
if(pixel[4] == 0)
continue
var/list/n = (y < I.Height())? bsi_split_colors(I.GetPixel(x, y + 1)) : list(0, 0, 0, 0)
var/list/s = (y > 1)? bsi_split_colors(I.GetPixel(x, y - 1)) : list(0, 0, 0, 0)
var/list/e = (x < I.Width())? bsi_split_colors(I.GetPixel(x + 1, y)) : list(0, 0, 0, 0)
var/list/w = (x > 1)? bsi_split_colors(I.GetPixel(x - 1, y)) : list(0, 0, 0, 0)
var/value = (i == 1)? 16 : max(n[1] - 1, e[1] - 1, s[1] - 1, w[1] - 1)
if(prob(50))
value = max(0, value - 1)
if(prob(50))
value = max(0, value - 1)
if(prob(50))
value = max(0, value - 1)
if(value <= pixel[1])
continue
var/v2 = 256 - ((16 - value) * (16 - value))
I.DrawBox(rgb(value, v2, pixel[4] - v2, pixel[4]), x, y)
if(n[4] != 0 && n[1] < value - 1)
queue[++queue.len] = list(x, y + 1)
if(s[4] != 0 && s[1] < value - 1)
queue[++queue.len] = list(x, y - 1)
if(e[4] != 0 && e[1] < value - 1)
queue[++queue.len] = list(x + 1, y)
if(w[4] != 0 && w[1] < value - 1)
queue[++queue.len] = list(x - 1, y)
/proc/bsi_generate_mask(icon/source, state)
var/icon/mask = icon(source, state)
mask.MapColors(
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 1, 1,
0, 0, 0, 0)
var/hits = 0
for(var/i = 1, i <= 10, i++)
var/point1
var/point2
if(prob(50))
if(prob(50))
point1 = list(rand(1, mask.Width()), mask.Height())
point2 = list(rand(1, mask.Width()), 1)
else
point2 = list(rand(1, mask.Width()), mask.Height())
point1 = list(rand(1, mask.Width()), 1)
else
if(prob(50))
point1 = list(mask.Width(), rand(1, mask.Height()))
point2 = list(1, rand(1, mask.Height()))
else
point2 = list(mask.Width(), rand(1, mask.Height()))
point1 = list(1, rand(1, mask.Height()))
var/hit = bsi_cast_ray(mask, point1, point2)
if(hit == null)
continue
hits++
bsi_spread(mask, hit)
if(prob(20 + hits * 20))
break
if(hits == 0)
return null
else
return mask
/proc/generate_bluespace_icon(icon/source, state)
var/icon/mask = bsi_generate_mask(source, state)
if(mask == null)
return source
var/icon/unaffected = icon(mask)
unaffected.MapColors(
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 1,
0, 0, 0, 0,
255, 255, 255, 0)
var/icon/temp = icon(source, state) //Mask already contains the original alpha values, avoid squaring them
temp.MapColors(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 0,
0, 0, 0, 255)
unaffected.Blend(temp, ICON_MULTIPLY)
var/icon/bluespaced = icon(mask)
bluespaced.MapColors(
0, 0, 0, 0,
0, 0, 0, 1,
0, 0, 0, 0,
0, 0, 0, 0,
1, 1, 1, 0)
bluespaced.Blend(icon(source, state), ICON_MULTIPLY)
var/list/frames = list(
list(0.000,20),
list(0.020, 5),
list(0.050, 4),
list(0.080, 5),
list(0.100,10),
list(0.080, 5),
list(0.050, 4),
list(0.020, 5),
list(0.000,20),
list(0.020, 5),
list(0.050, 4),
list(0.080, 5),
list(0.100,10),
list(0.080, 5),
list(0.050, 4),
list(0.020, 5),
list(0.000,20),
list(0.020, 5),
list(0.050, 4),
list(0.080, 5),
list(0.100,10),
list(0.080, 5),
list(0.050, 4),
list(0.020, 5),
)
var/list/colors = list(
list( 75, 75, 75, 0),
list( 25, 25, 25, 0),
list( 75, 75, 75, 0),
list( 25, 25, 75, 0),
list( 75, 75, 300, 0),
list( 25, 25, 300, 0),
list(255, 255, 255, 0),
list( 0, 0, 0, 255),
list( 0, 0, 0, 0),
list( 0, 0, 0, 0),
)
for(var/i = 1, i <= rand(1, 5), i++)
var/f = rand(1, length(frames))
if(frames[f][2] > 1)
frames[f][2]--
frames.Insert(f, 0)
frames[f] = list(0.8, 1)
var/icon/result = generate_color_animation(bluespaced, colors, frames)
result.Blend(unaffected, ICON_UNDERLAY)
return result
/atom/verb/test()
set src in view()
src.icon = generate_bluespace_icon(src.icon, src.icon_state)
/mob/verb/bluespam()
for(var/turf/t in view(5))
var/obj/s = new /obj/square(t)
s.icon = generate_bluespace_icon(s.icon, s.icon_state)
@@ -1,96 +0,0 @@
//----------------------------------------
//
// Return a copy of the provided icon,
// after calling MapColors on it. The
// color values are linearily interpolated
// between the pairs provided, based on
// the ratio argument.
//
//----------------------------------------
/proc/MapColors_interpolate(icon/input, ratio,
rr1, rg1, rb1, ra1, rr2, rg2, rb2, ra2,
gr1, gg1, gb1, ga1, gr2, gg2, gb2, ga2,
br1, bg1, bb1, ba1, br2, bg2, bb2, ba2,
ar1, ag1, ab1, aa1, ar2, ag2, ab2, aa2,
zr1, zg1, zb1, za1, zr2, zg2, zb2, za2)
var/r = ratio
var/i = 1 - ratio
var/icon/I = icon(input)
I.MapColors(
(rr1 * r + rr2 * i) / 255.0, (rg1 * r + rg2 * i) / 255.0, (rb1 * r + rb2 * i) / 255.0, (ra1 * r + ra2 * i) / 255.0,
(gr1 * r + gr2 * i) / 255.0, (gg1 * r + gg2 * i) / 255.0, (gb1 * r + gb2 * i) / 255.0, (ga1 * r + ga2 * i) / 255.0,
(br1 * r + br2 * i) / 255.0, (bg1 * r + bg2 * i) / 255.0, (bb1 * r + bb2 * i) / 255.0, (ba1 * r + ba2 * i) / 255.0,
(ar1 * r + ar2 * i) / 255.0, (ag1 * r + ag2 * i) / 255.0, (ab1 * r + ab2 * i) / 255.0, (aa1 * r + aa2 * i) / 255.0,
(zr1 * r + zr2 * i) / 255.0, (zg1 * r + zg2 * i) / 255.0, (zb1 * r + zb2 * i) / 255.0, (za1 * r + za2 * i) / 255.0)
return I
//----------------------------------------
//
// Extension of the above that takes a
// list of lists of color values, rather
// than a large number of arguments.
//
//----------------------------------------
/proc/MapColors_interpolate_list(icon/I, ratio, list/colors)
var/list/c[10]
//Provide default values for any missing colors (without altering the original list
for(var/i = 1, i <= 10, i++)
c[i] = list(0, 0, 0, (i == 7 || i == 8)? 255 : 0)
if(istype(colors[i], /list))
for(var/j = 1, j <= 4, j++)
if(j <= length(colors[i]) && isnum(colors[i][j]))
c[i][j] = colors[i][j]
return MapColors_interpolate(I, ratio,
colors[ 1][1], colors[ 1][2], colors[ 1][3], colors[ 1][4], // Red 1
colors[ 2][1], colors[ 2][2], colors[ 2][3], colors[ 2][4], // Red 2
colors[ 3][1], colors[ 3][2], colors[ 3][3], colors[ 3][4], // Green 1
colors[ 4][1], colors[ 4][2], colors[ 4][3], colors[ 4][4], // Green 2
colors[ 5][1], colors[ 5][2], colors[ 5][3], colors[ 5][4], // Blue 1
colors[ 6][1], colors[ 6][2], colors[ 6][3], colors[ 6][4], // Blue 2
colors[ 7][1], colors[ 7][2], colors[ 7][3], colors[ 7][4], // Alpha 1
colors[ 8][1], colors[ 8][2], colors[ 8][3], colors[ 8][4], // Alpha 2
colors[ 9][1], colors[ 9][2], colors[ 9][3], colors[ 9][4], // Added 1
colors[10][1], colors[10][2], colors[10][3], colors[10][4]) // Added 2
//----------------------------------------
//
// Take the source image, and return an animated
// version, that transitions between the provided
// color mappings, according to the provided
// pattern.
//
// Colors should be in a format suitable for
// MapColors_interpolate_list, and frames should
// be a list of 'frames', where each frame is itself
// a list, element 1 being the ratio of the first
// color to the second, and element 2 being how
// long the frame lasts, in tenths of a second.
//
//----------------------------------------
/proc/generate_color_animation(icon/icon, list/colors, list/frames)
var/icon/out = icon('icons/effects/uristrunes.dmi', "")
var/frame_num = 1
for(var/frame in frames)
var/icon/I = MapColors_interpolate_list(icon, frame[1], colors)
out.Insert(I, "", 2, frame_num++, 0, frame[2])
return out
-268
View File
@@ -1,268 +0,0 @@
//----------------------------------------
//
// Take a source icon, convert into a mask,
// then create a border around it.
//
// The output then uses the colors and
// alpha values provided.
//
//----------------------------------------
/proc/create_border_image(icon/input, border_color = "#000000", fill_color = "#000000", border_alpha = 255, fill_alpha = 255)
var/icon/I = icon('icons/effects/uristrunes.dmi', "blank")
I.Blend(input, ICON_OVERLAY)
//Discard the image
I.MapColors(0, 0, 0, 0, //-\ Ignore
0, 0, 0, 0, //--> The
0, 0, 0, 0, //-/ Colors
0,255, 0, 1, //Keep alpha channel, any pixel with non-zero alpha gets max green channel
0, 0, 0, 0)
//Loop over the image, calculating the border value, and storing it in the red channel
//Store border's alpha in the blue channel
for(var/x = 1, x <= 32, x++)
for(var/y = 1, y <= 32, y++)
var/p = I.GetPixel(x, y)
if(p == null)
var/n = I.GetPixel(x, y + 1)
var/s = I.GetPixel(x, y - 1)
var/e = I.GetPixel(x + 1, y)
var/w = I.GetPixel(x - 1, y)
var/ne = I.GetPixel(x + 1, y + 1)
var/se = I.GetPixel(x + 1, y - 1)
var/nw = I.GetPixel(x - 1, y + 1)
var/sw = I.GetPixel(x - 1, y - 1)
var/sum_adj = ((n == "#00ff00"? 1 : 0) \
+ (s == "#00ff00"? 1 : 0) \
+ (e == "#00ff00"? 1 : 0) \
+ (w == "#00ff00"? 1 : 0))
var/sum_diag = ((ne == "#00ff00"? 1 : 0) \
+ (se == "#00ff00"? 1 : 0) \
+ (nw == "#00ff00"? 1 : 0) \
+ (sw == "#00ff00"? 1 : 0))
if(sum_adj)
I.DrawBox(rgb(255, 0, 200, 0), x, y)
else if(sum_diag)
I.DrawBox(rgb(255, 0, 100, 0), x, y)
else
I.DrawBox(rgb(0, 0, 0, 0), x, y)
else if(p != "#00ff00")
var/a = 255
if(length(p) == 9) // "#rrggbbaa", we want the aa
a = hex2num(copytext(p, 8))
I.DrawBox(rgb(255 - a, a, 255 - a, a), x, y)
//Map the red and green channels to the desired output colors
I.MapColors(border_color, fill_color, rgb(0, 0, 0, border_alpha), rgb(0, 0, 0, fill_alpha), "#00000000")
return I
//----------------------------------------
//
// Take a source icon, convert into a mask,
// and border. Color them according to args,
// and animate.
//
//----------------------------------------
/proc/animate_rune_full(icon/input, rr1, rg1, rb1, ra1, rr2, rg2, rb2, ra2, br1, bg1, bb1, ba1, br2, bg2, bb2, ba2, ar1, ag1, ab1, aa1, ar2, ag2, ab2, aa2, or1, og1, ob1, oa1, or2, og2, ob2, oa2, frames)
var/list/colors[10]
colors[ 1] = list(rr1, rg1, rb1, ra1) //Rune color 1
colors[ 2] = list(rr2, rg2, rb2, ra2) //Rune color 2
colors[ 3] = list(br1, bg1, bb1, ba1) //Border color 1
colors[ 4] = list(br2, bg2, bb2, ba2) //Border color 2
colors[ 5] = list( 0, 0, 0, 0) //Unused
colors[ 6] = list( 0, 0, 0, 0) //Unused
colors[ 7] = list(ar1, ag1, ab1, aa1) //Alpha color 1
colors[ 8] = list(ar2, ag2, ab2, aa2) //Alpha color 2
colors[ 9] = list(or1, og1, ob1, oa1) //Added color 1
colors[10] = list(or2, og2, ob2, oa2) //Added color 2
var/icon/base = create_border_image(input, "#00ff0000", "#ff000000")
return generate_color_animation(base, colors, frames)
//----------------------------------------
//
// Calls the above, but accepts colors in
// the form of "#RRGGBBAA", and provides
// default values.
//
// Main limit is that it doesn't accept
// negative values, which you probably
// don't need anyway. Also missing a few
// color inputs, which would also be rarely
// used.
//
//----------------------------------------
/proc/animate_rune(icon/input, rune_color = "#00000000", border_color = "#c8000000", rune_color2 = "#00000000", border_color2 = "#d8380000", alpha = 255, alpha2 = 255, frames = rune_animation)
var/rr1 = hex2num(copytext(rune_color, 2, 4))
var/rg1 = hex2num(copytext(rune_color, 4, 6))
var/rb1 = hex2num(copytext(rune_color, 6, 8))
var/ra1 = hex2num(copytext(rune_color, 8, 10))
var/rr2 = hex2num(copytext(rune_color2, 2, 4))
var/rg2 = hex2num(copytext(rune_color2, 4, 6))
var/rb2 = hex2num(copytext(rune_color2, 6, 8))
var/ra2 = hex2num(copytext(rune_color2, 8, 10))
var/br1 = hex2num(copytext(border_color, 2, 4))
var/bg1 = hex2num(copytext(border_color, 4, 6))
var/bb1 = hex2num(copytext(border_color, 6, 8))
var/ba1 = hex2num(copytext(border_color, 8, 10))
var/br2 = hex2num(copytext(border_color2, 2, 4))
var/bg2 = hex2num(copytext(border_color2, 4, 6))
var/bb2 = hex2num(copytext(border_color2, 6, 8))
var/ba2 = hex2num(copytext(border_color2, 8, 10))
return animate_rune_full(input, rr1, rg1, rb1, ra1, rr2, rg2, rb2, ra2, br1, bg1, bb1, ba1, br2, bg2, bb2, ba2, 0, 0, 0, alpha, 0, 0, 0, alpha2, 0, 0, 0, 0, 0, 0, 0, 0, frames)
/proc/inanimate_rune(icon/input, rune_color = "#00000000", border_color = "#c8000000")
var/icon/base = create_border_image(input, "#00ff0000", "#ff000000")
base.MapColors(rune_color, border_color, "#00000000", "#000000ff", "#00000000")
return base
var/list/rune_animation = list(
list(0.000, 5),
list(0.020, 1),
list(0.050, 1),
list(0.090, 1),
list(0.140, 1),
list(0.200, 1),
list(0.270, 1),
list(0.340, 1),
list(0.420, 1),
list(0.500, 1),
list(0.590, 1),
list(0.675, 1),
list(0.750, 1),
list(0.900, 1),
list(1.000, 6),
list(0.875, 1),
list(0.750, 1),
list(0.625, 1),
list(0.500, 1),
list(0.375, 1),
list(0.250, 1),
list(0.125, 1),
)
/var/list/rune_cache = list()
/proc/get_rune(rune_bits, animated = 0)
var/lookup = "[rune_bits]-[animated]"
if(lookup in rune_cache)
return rune_cache[lookup]
var/icon/base = icon('icons/effects/uristrunes.dmi', "")
for(var/i = 0, i < 10, i++)
if(rune_bits & (1 << i))
base.Blend(icon('icons/effects/uristrunes.dmi', "rune-[1 << i]"), ICON_OVERLAY)
var/icon/result
if(animated == 1)
result = animate_rune(base)
else
result = inanimate_rune(base)
rune_cache[lookup] = result
return result
// Testing procs and Fun procs
/mob/verb/create_rune()
var/obj/o = new(locate(x, y, z))
o.icon = get_rune(rand(1, 1023), 1)
/mob/verb/runes_15x15()
for(var/turf/t in range(7))
var/obj/o = new /obj(t)
o.icon = get_rune(rand(1, 1023), 1)
/*
/mob/verb/create_rune_custom(rune as num, color1 as color, border1 as color, color2 as color, border2 as color, alpha1 as num, alpha2 as num)
var/icon/I = icon('icons/effects/uristrunes.dmi', "blank")
for(var/i = 0, i < 10, i++)
if(rune & (1 << i))
I.Blend(icon('icons/effects/uristrunes.dmi', "rune-[1 << i]"), ICON_OVERLAY)
var/obj/o = new(locate(x, y, z))
o.icon = animate_rune(I, color1, border1, color2, border2, alpha1, alpha2)
/mob/verb/spam()
for(var/turf/t in range(4))
var/icon/I = icon('icons/effects/uristrunes.dmi', "blank")
var/rune = rand(1, 1023)
for(var/i = 0, i < 10, i++)
if(rune & (1 << i))
I.Blend(icon('icons/effects/uristrunes.dmi', "rune-[1 << i]"), ICON_OVERLAY)
var/obj/o = new(t)
o.icon = animate_rune_full(I, rand(0, 255), rand(0, 255), rand(0, 255), rand(-255, 255),
rand(0, 255), rand(0, 255), rand(0, 255), rand(-255, 255),
rand(0, 255), rand(0, 255), rand(0, 255), rand(-255, 255),
rand(0, 255), rand(0, 255), rand(0, 255), rand(-255, 255),
0, 0, 0, rand(0, 255),
0, 0, 0, rand(0, 255),
0, 0, 0, 0,
0, 0, 0, 0,
list(
list(0.000, 5),
list(0.020, 1),
list(0.050, 1),
list(0.090, 1),
list(0.140, 1),
list(0.200, 1),
list(0.270, 1),
list(0.340, 1),
list(0.420, 1),
list(0.500, 1),
list(0.590, 1),
list(0.675, 1),
list(0.750, 1),
list(0.900, 1),
list(1.000, 6),
list(0.875, 1),
list(0.750, 1),
list(0.625, 1),
list(0.500, 1),
list(0.375, 1),
list(0.250, 1),
list(0.125, 1),
))
*/
+4 -4
View File
@@ -656,7 +656,7 @@
return
..()
/mob/living/simple_animal/hostile/mining_drone/death()
/mob/living/simple_animal/hostile/mining_drone/Die()
..()
visible_message("<span class='danger'>[src] is destroyed!</span>")
new /obj/effect/decal/cleanable/blood/gibs/robot(src.loc)
@@ -707,11 +707,11 @@
/mob/living/simple_animal/hostile/mining_drone/proc/CollectOre()
var/obj/item/weapon/ore/O
for(O in src.loc)
O.loc = src
O.forceMove(src)
for(var/dir in alldirs)
var/turf/T = get_step(src,dir)
for(O in T)
O.loc = src
O.forceMove(src)
return
/mob/living/simple_animal/hostile/mining_drone/proc/DropOre()
@@ -719,7 +719,7 @@
return
for(var/obj/item/weapon/ore/O in contents)
contents -= O
O.loc = src.loc
O.forceMove(loc)
return
/mob/living/simple_animal/hostile/mining_drone/adjustBruteLoss()
@@ -1,4 +1,7 @@
/mob/living/carbon/alien/humanoid/emote(var/act,var/m_type=1,var/message = null)
if(stat)
return
var/param = null
if (findtext(act, "-", 1, null))
var/t1 = findtext(act, "-", 1, null)
@@ -1,5 +1,7 @@
/mob/living/carbon/alien/larva/emote(var/act,var/m_type=1,var/message = null)
if(stat)
return
var/param = null
if (findtext(act, "-", 1, null))
var/t1 = findtext(act, "-", 1, null)
@@ -1,4 +1,7 @@
/mob/living/carbon/brain/emote(var/act,var/m_type=1,var/message = null)
if(stat)
return
if(!(container && istype(container, /obj/item/device/mmi)))//No MMI, no emotes
return
@@ -110,7 +110,7 @@
return 1
/mob/living/carbon/human/proc/change_skin_color(var/red, var/green, var/blue)
if(red == r_skin && green == g_skin && blue == b_skin || !(species.flags & HAS_SKIN_COLOR))
if(red == r_skin && green == g_skin && blue == b_skin || !(species.bodyflags & HAS_SKIN_COLOR))
return
r_skin = red
@@ -122,7 +122,7 @@
return 1
/mob/living/carbon/human/proc/change_skin_tone(var/tone)
if(s_tone == tone || !(species.flags & HAS_SKIN_TONE))
if(s_tone == tone || !(species.bodyflags & HAS_SKIN_TONE))
return
s_tone = tone
@@ -182,4 +182,3 @@
valid_facial_hairstyles += facialhairstyle
return valid_facial_hairstyles
@@ -1,4 +1,7 @@
/mob/living/carbon/human/emote(var/act,var/m_type=1,var/message = null)
if(stat)
return
var/param = null
if (findtext(act, "-", 1, null))
var/t1 = findtext(act, "-", 1, null)
@@ -334,8 +337,12 @@
m_type = 2
if ("deathgasp")
message = "<B>[src]</B> seizes up and falls limp, \his eyes dead and lifeless..."
m_type = 1
if (species.name == "Machine")
message = "<B>[src]</B> gives one shrill beep before falling limp, screen quickly flashing blue before shutting off entirely."
m_type = 1
else
message = "<B>[src]</B> seizes up and falls limp, \his eyes dead and lifeless..."
m_type = 1
if ("giggle")
if(miming)
@@ -10,6 +10,11 @@
var/embedded_flag //To check if we've need to roll for damage on movement while an item is imbedded in us.
/mob/living/carbon/human/New(var/new_loc, var/new_species = null, var/delay_ready_dna=0)
if(!dna)
dna = new /datum/dna(null)
// Species name is handled by set_species()
if(!species)
if(new_species)
set_species(new_species,1)
@@ -36,9 +41,6 @@
..()
if(dna)
dna.real_name = real_name
prev_gender = gender // Debug for plural genders
make_blood()
@@ -46,8 +48,10 @@
faction |= "\ref[M]"
// Set up DNA.
if(!delay_ready_dna)
if(!delay_ready_dna && dna)
dna.ready_dna(src)
dna.real_name = real_name
sync_organ_dna() //this shouldn't be necessaaaarrrryyyyyyyy
UpdateAppearance()
/mob/living/carbon/human/Destroy()
@@ -24,20 +24,10 @@
if(wear_suit)
tally += wear_suit.slowdown
if(!buckled || (buckled && !istype(buckled, /obj/structure/stool/bed/chair/wheelchair)))
if(!buckled)
if(shoes)
tally += shoes.slowdown
if(buckled && istype(buckled, /obj/structure/stool/bed/chair/wheelchair))
for(var/organ_name in list("l_hand","r_hand","l_arm","r_arm"))
var/obj/item/organ/external/E = get_organ(organ_name)
if(!E || (E.status & ORGAN_DESTROYED))
tally += 4
else if(E.status & ORGAN_SPLINTED)
tally += 0.5
else if(E.status & ORGAN_BROKEN)
tally += 1.5
if(shock_stage >= 10) tally += 3
if(back)
@@ -144,4 +144,9 @@
//New are added for reagents to random organs.
for(var/datum/reagent/A in reagents.reagent_list)
var/obj/item/organ/O = pick(organs)
O.trace_chemicals[A.name] = 100
O.trace_chemicals[A.name] = 100
/mob/living/carbon/human/proc/sync_organ_dna()
var/list/all_bits = internal_organs|organs
for(var/obj/item/organ/O in all_bits)
O.set_dna(dna)
@@ -5,5 +5,6 @@
src << "<span class='notice'>You can ventcrawl! Use alt+click on vents to quickly travel about the station.</span>"
update_pipe_vision()
update_hud()
ticker.mode.update_all_synd_icons() //This proc only sounds CPU-expensive on paper. It is O(n^2), but the outer for-loop only iterates through syndicates, which are only prsenet in nuke rounds and even when they exist, there's usually 6 of them.
if(ticker && ticker.mode)
ticker.mode.update_all_synd_icons() //This proc only sounds CPU-expensive on paper. It is O(n^2), but the outer for-loop only iterates through syndicates, which are only prsenet in nuke rounds and even when they exist, there's usually 6 of them.
return
@@ -59,7 +59,7 @@
/datum/species/unathi/handle_death(var/mob/living/carbon/human/H)
H.stop_tail_wagging(1)
/datum/species/unathi/equip(var/mob/living/carbon/human/H)
if(H.mind.assigned_role != "Clown")
H.unEquip(H.shoes)
@@ -105,7 +105,7 @@
/datum/species/tajaran/handle_death(var/mob/living/carbon/human/H)
H.stop_tail_wagging(1)
/datum/species/tajaran/equip(var/mob/living/carbon/human/H)
if(H.mind.assigned_role != "Clown")
H.unEquip(H.shoes)
@@ -219,7 +219,7 @@
i++
newname += pick(vox_name_syllables)
return capitalize(newname)
/datum/species/vox/equip(var/mob/living/carbon/human/H)
if(H.mind.assigned_role != "Clown" && H.mind.assigned_role != "Mime")
H.unEquip(H.wear_mask)
@@ -235,7 +235,7 @@
H.internal = H.l_hand
if (H.internals)
H.internals.icon_state = "internal1"
/*
/datum/species/vox/handle_post_spawn(var/mob/living/carbon/human/H)
H.verbs += /mob/living/carbon/human/proc/leap
@@ -469,20 +469,20 @@
/datum/species/machine
name = "Machine"
name_plural = "Machines"
blurb = "Positronic intelligence really took off in the 26th century, and it is not uncommon to see independant, free-willed \
robots on many human stations, particularly in fringe systems where standards are slightly lax and public opinion less relevant \
to corporate operations. IPCs (Integrated Positronic Chassis) are a loose category of self-willed robots with a humanoid form, \
generally self-owned after being 'born' into servitude; they are reliable and dedicated workers, albeit more than slightly \
inhuman in outlook and perspective."
inhuman in outlook and perspective."
icobase = 'icons/mob/human_races/r_machine.dmi'
deform = 'icons/mob/human_races/r_machine.dmi'
path = /mob/living/carbon/human/machine
default_language = "Galactic Common"
language = "Trinary"
unarmed_type = /datum/unarmed_attack/punch
eyes = "blank_eyes"
brute_mod = 2.5 // 100% * 2.5 * 0.6 (robolimbs) ~= 150%
burn_mod = 2.5 // So they take 50% extra damage from brute/burn overall.
@@ -500,20 +500,21 @@
flags = IS_WHITELISTED | NO_BREATHE | NO_SCAN | NO_BLOOD | NO_PAIN | NO_DNA_RAD
clothing_flags = HAS_SOCKS
bodyflags = HAS_SKIN_COLOR
dietflags = 0 //IPCs can't eat, so no diet
blood_color = "#1F181F"
flesh_color = "#AAAAAA"
virus_immune = 1
can_revive_by_healing = 1
reagent_tag = PROCESS_SYN
has_organ = list(
"brain" = /obj/item/organ/mmi_holder/posibrain,
"cell" = /obj/item/organ/cell,
"optics" = /obj/item/organ/optical_sensor
)
vision_organ = "optics"
vision_organ = "optics"
has_limbs = list(
"chest" = list("path" = /obj/item/organ/external/chest/ipc),
"groin" = list("path" = /obj/item/organ/external/groin/ipc),
@@ -532,7 +533,7 @@
H.h_style = ""
spawn(100)
if(H) H.update_hair()
/datum/species/machine/handle_post_spawn(var/mob/living/carbon/human/H)
..()
H.verbs += /mob/living/carbon/human/proc/change_monitor
@@ -238,15 +238,13 @@ var/global/list/damage_icon_parts = list()
var/hulk = (HULK in src.mutations)
var/skeleton = (SKELETON in src.mutations)
var/g = (gender == FEMALE ? "f" : "m")
//CACHING: Generate an index key from visible bodyparts.
//0 = destroyed, 1 = normal, 2 = robotic, 3 = necrotic.
//Create a new, blank icon for our mob to use.
if(stand_icon)
qdel(stand_icon)
stand_icon = new(species.icon_template ? species.icon_template : 'icons/mob/human.dmi',"blank")
var/icon_key = "[species.race_key][g][s_tone][r_skin][g_skin][b_skin]"
var/icon_key = ""
var/obj/item/organ/eyes/eyes = internal_organs_by_name["eyes"]
if(eyes)
@@ -265,6 +263,13 @@ var/global/list/damage_icon_parts = list()
else
icon_key += "1"
if(part)
icon_key += "[part.species.race_key]"
icon_key += "[part.dna.GetUIState(DNA_UI_GENDER)]"
icon_key += "[part.dna.GetUIValue(DNA_UI_SKIN_TONE)]"
if(part.s_col)
icon_key += "[rgb(part.s_col[1], part.s_col[2], part.s_col[3])]"
icon_key = "[icon_key][husk ? 1 : 0][fat ? 1 : 0][hulk ? 1 : 0][skeleton ? 1 : 0]"
var/icon/base_icon
@@ -868,8 +873,8 @@ var/global/list/damage_icon_parts = list()
var/image/I = image("icon" = r_hand.righthand_file, "icon_state"="[t_state]")
I = center_image(I, r_hand.inhand_x_dimension, r_hand.inhand_y_dimension)
overlays_standing[R_HAND_LAYER] = I
overlays_standing[R_HAND_LAYER] = I
if (handcuffed) drop_r_hand()
else
overlays_standing[R_HAND_LAYER] = null
@@ -1,5 +1,6 @@
/mob/living/carbon/slime/emote(var/act, var/m_type=1, var/message = null)
if(stat)
return
if (findtext(act, "-", 1, null))
var/t1 = findtext(act, "-", 1, null)
+3
View File
@@ -1,4 +1,7 @@
/mob/living/silicon/emote(var/act, var/m_type=1, var/message = null)
if(stat)
return
var/param = null
if (findtext(act, "-", 1, null))
var/t1 = findtext(act, "-", 1, null)
+13 -8
View File
@@ -12,7 +12,8 @@
/mob/living/silicon/proc/set_zeroth_law(var/law, var/law_borg)
laws_sanity_check()
laws.set_zeroth_law(law, law_borg)
log_and_message_admins("has given [src] the zeroth laws: [law]/[law_borg ? law_borg : "N/A"]")
if(!isnull(usr) && law)
log_and_message_admins("has given [src] the zeroth laws: [law]/[law_borg ? law_borg : "N/A"]")
/mob/living/silicon/robot/set_zeroth_law(var/law, var/law_borg)
..()
@@ -22,39 +23,43 @@
/mob/living/silicon/proc/add_ion_law(var/law)
laws_sanity_check()
laws.add_ion_law(law)
log_and_message_admins("has given [src] the ion law: [law]")
if(!isnull(usr) && law)
log_and_message_admins("has given [src] the ion law: [law]")
/mob/living/silicon/proc/add_inherent_law(var/law)
laws_sanity_check()
laws.add_inherent_law(law)
log_and_message_admins("has given [src] the inherent law: [law]")
if(!isnull(usr) && law)
log_and_message_admins("has given [src] the inherent law: [law]")
/mob/living/silicon/proc/add_supplied_law(var/number, var/law)
laws_sanity_check()
laws.add_supplied_law(number, law)
log_and_message_admins("has given [src] the supplied law: [law]")
if(!isnull(usr) && law)
log_and_message_admins("has given [src] the supplied law: [law]")
/mob/living/silicon/proc/delete_law(var/datum/ai_law/law)
laws_sanity_check()
laws.delete_law(law)
log_and_message_admins("has deleted a law belonging to [src]: [law.law]")
if(!isnull(usr) && law)
log_and_message_admins("has deleted a law belonging to [src]: [law.law]")
/mob/living/silicon/proc/clear_inherent_laws(var/silent = 0)
laws_sanity_check()
laws.clear_inherent_laws()
if(!silent)
if(!silent && !isnull(usr))
log_and_message_admins("cleared the inherent laws of [src]")
/mob/living/silicon/proc/clear_ion_laws(var/silent = 0)
laws_sanity_check()
laws.clear_ion_laws()
if(!silent)
if(!silent && !isnull(usr))
log_and_message_admins("cleared the ion laws of [src]")
/mob/living/silicon/proc/clear_supplied_laws(var/silent = 0)
laws_sanity_check()
laws.clear_supplied_laws()
if(!silent)
if(!silent && !isnull(usr))
log_and_message_admins("cleared the supplied laws of [src]")
/mob/living/silicon/proc/statelaws(var/datum/ai_laws/laws)
@@ -1,4 +1,7 @@
/mob/living/silicon/pai/emote(var/act, var/m_type=1, var/message = null)
if(stat)
return
switch(act)
if ("help")
src << "ping, beep, buzz."
@@ -1,14 +1,15 @@
// TODO: remove the robot.mmi and robot.cell variables and completely rely on the robot component system
/datum/robot_component/var/name
/datum/robot_component/var/installed = 0
/datum/robot_component/var/powered = 0
/datum/robot_component/var/toggled = 1
/datum/robot_component/var/brute_damage = 0
/datum/robot_component/var/electronics_damage = 0
/datum/robot_component/var/energy_consumption = 0
/datum/robot_component/var/max_damage = 30
/datum/robot_component/var/mob/living/silicon/robot/owner
/datum/robot_component
var/name = "Component"
var/installed = 0
var/powered = 1
var/toggled = 1
var/brute_damage = 0
var/electronics_damage = 0
var/energy_consumption = 0
var/max_damage = 30
var/mob/living/silicon/robot/owner
// The actual device object that has to be installed for this.
/datum/robot_component/var/external_type = null
@@ -1,4 +1,7 @@
/mob/living/silicon/robot/emote(var/act, var/m_type=1, var/message = null)
if(stat)
return
var/param = null
if (findtext(act, "-", 1, null))
var/t1 = findtext(act, "-", 1, null)
@@ -1135,7 +1135,7 @@ var/list/robot_verbs_default = list(
S.dirt = 0
for(var/A in tile)
if(istype(A, /obj/effect))
if(istype(A, /obj/effect/rune) || istype(A, /obj/effect/decal/cleanable) || istype(A, /obj/effect/overlay))
if(is_cleanable(A))
qdel(A)
else if(istype(A, /obj/item))
var/obj/item/cleaned_item = A
@@ -81,7 +81,7 @@
set name = "Law Manager"
set category = "Subsystems"
law_manager.ui_interact(usr, state = self_state)
law_manager.ui_interact(usr, state = conscious_state)
/********************
* Power Monitor *
-5
View File
@@ -639,11 +639,6 @@ var/list/slot_equipment_priority = list( \
flavor_text = msg
/mob/proc/warn_flavor_changed()
if(flavor_text && flavor_text != "") // don't spam people that don't use it!
src << "<h2 class='alert'>OOC Warning:</h2>"
src << "<span class='alert'>Your flavor text is likely out of date! <a href='byond://?src=\ref[src];flavor_change=1'>Change</a></span>"
/mob/proc/print_flavor_text(var/shrink = 1)
if (flavor_text && flavor_text != "")
var/msg = replacetext(flavor_text, "\n", " ")
+1 -1
View File
@@ -509,7 +509,7 @@
proc/has_admin_rights()
return client.holder.rights & R_ADMIN
return check_rights(R_ADMIN, 0, src)
proc/is_species_whitelisted(datum/species/S)
if(!S) return 1
@@ -0,0 +1,7 @@
/*
This state only checks if user is conscious.
*/
/var/global/datum/topic_state/conscious_state/conscious_state = new()
/datum/topic_state/conscious_state/can_use_topic(var/src_object, var/mob/user)
return user.stat == CONSCIOUS ? STATUS_INTERACTIVE : STATUS_CLOSE
+16 -3
View File
@@ -21,7 +21,8 @@ var/list/organ_cache = list()
var/list/trace_chemicals = list() // traces of chemicals in the organ,
// links chemical IDs to number of ticks for which they'll stay in the blood
germ_level = 0
var/datum/dna/dna
var/datum/species/species
/obj/item/organ/Destroy()
if(!owner)
@@ -59,6 +60,12 @@ var/list/organ_cache = list()
max_damage = min_broken_damage * 2
if(istype(holder))
src.owner = holder
species = all_species["Human"]
if(holder.dna)
dna = holder.dna.Clone()
species = all_species[dna.species]
else
log_to_dd("[src] at [loc] spawned without a proper DNA.")
var/mob/living/carbon/human/H = holder
if(istype(H))
if(internal)
@@ -67,13 +74,19 @@ var/list/organ_cache = list()
if(E.internal_organs == null)
E.internal_organs = list()
E.internal_organs |= src
if(H.dna)
if(dna)
if(!blood_DNA)
blood_DNA = list()
blood_DNA[H.dna.unique_enzymes] = H.dna.b_type
blood_DNA[dna.unique_enzymes] = dna.b_type
if(internal)
holder.internal_organs |= src
/obj/item/organ/proc/set_dna(var/datum/dna/new_dna)
if(new_dna)
dna = new_dna.Clone()
blood_DNA.Cut()
blood_DNA[dna.unique_enzymes] = dna.b_type
/obj/item/organ/proc/die()
if(status & ORGAN_ROBOT)
return
+28 -13
View File
@@ -12,13 +12,25 @@ var/global/list/limb_icon_cache = list()
/obj/item/organ/external/proc/sync_colour_to_human(var/mob/living/carbon/human/human)
s_tone = null
s_col = null
if(status & ORGAN_ROBOT)
if(status & ORGAN_ROBOT && !(species && species.name == "Machine")) //machine people get skin color
return
if(species && human.species && species.name != human.species.name)
return
if(!isnull(human.s_tone) && (human.species.bodyflags & HAS_SKIN_TONE))
s_tone = human.s_tone
if(human.species.bodyflags & HAS_SKIN_COLOR)
s_col = list(human.r_skin, human.g_skin, human.b_skin)
/obj/item/organ/external/proc/sync_colour_to_dna()
s_tone = null
s_col = null
if(status & ORGAN_ROBOT)
return
if(!isnull(dna.GetUIValue(DNA_UI_SKIN_TONE)) && (species.flags & HAS_SKIN_TONE))
s_tone = dna.GetUIValue(DNA_UI_SKIN_TONE)
if(species.flags & HAS_SKIN_COLOR)
s_col = list(dna.GetUIValue(DNA_UI_SKIN_R), dna.GetUIValue(DNA_UI_SKIN_G), dna.GetUIValue(DNA_UI_SKIN_B))
/obj/item/organ/external/head/sync_colour_to_human(var/mob/living/carbon/human/human)
..()
var/obj/item/organ/eyes/eyes = owner.internal_organs_by_name["eyes"]
@@ -34,11 +46,11 @@ var/global/list/limb_icon_cache = list()
overlays.Cut()
if(!owner)
return
if(owner.species.has_organ["eyes"])
if(species.has_organ["eyes"])
var/obj/item/organ/eyes/eyes = owner.internal_organs_by_name["eyes"]
if(owner.species.eyes)
var/icon/eyes_icon = new/icon('icons/mob/human_face.dmi', owner.species.eyes)
if(species.eyes)
var/icon/eyes_icon = new/icon('icons/mob/human_face.dmi', species.eyes)
if(eyes)
eyes_icon.Blend(rgb(eyes.eye_colour[1], eyes.eye_colour[2], eyes.eye_colour[3]), ICON_ADD)
else
@@ -46,14 +58,14 @@ var/global/list/limb_icon_cache = list()
mob_icon.Blend(eyes_icon, ICON_OVERLAY)
overlays |= eyes_icon
if(owner.lip_style && (owner.species && (owner.species.flags & HAS_LIPS)))
if(owner.lip_style && (species && (species.flags & HAS_LIPS)))
var/icon/lip_icon = new/icon('icons/mob/human_face.dmi', "lips_[owner.lip_style]_s")
overlays |= lip_icon
mob_icon.Blend(lip_icon, ICON_OVERLAY)
if(owner.f_style)
var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[owner.f_style]
if(facial_hair_style && facial_hair_style.species_allowed && (owner.species.name in facial_hair_style.species_allowed))
if(facial_hair_style && facial_hair_style.species_allowed && (species.name in facial_hair_style.species_allowed))
var/icon/facial_s = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_s")
if(facial_hair_style.do_colouration)
facial_s.Blend(rgb(owner.r_facial, owner.g_facial, owner.b_facial), ICON_ADD)
@@ -61,7 +73,7 @@ var/global/list/limb_icon_cache = list()
if(owner.h_style && !(owner.head && (owner.head.flags & BLOCKHEADHAIR)))
var/datum/sprite_accessory/hair_style = hair_styles_list[owner.h_style]
if(hair_style && (owner.species.name in hair_style.species_allowed))
if(hair_style && (species.name in hair_style.species_allowed))
var/icon/hair_s = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s")
if(hair_style.do_colouration)
hair_s.Blend(rgb(owner.r_hair, owner.g_hair, owner.b_hair), ICON_ADD)
@@ -74,26 +86,29 @@ var/global/list/limb_icon_cache = list()
var/gender
if(force_icon)
mob_icon = new /icon(force_icon, "[icon_name]")
if(species && species.name == "Machine") //snowflake for IPC's, sorry.
if(s_col && s_col.len >= 3)
mob_icon.Blend(rgb(s_col[1], s_col[2], s_col[3]), ICON_ADD)
else
if(!owner)
if(!dna)
mob_icon = new /icon('icons/mob/human_races/r_human.dmi', "[icon_name][gendered_icon ? "_f" : ""]")
else
if(gendered_icon)
if(owner.gender == FEMALE)
if(dna.GetUIState(DNA_UI_GENDER))
gender = "f"
else
gender = "m"
if(skeletal)
mob_icon = new /icon('icons/mob/human_races/r_skeleton.dmi', "[icon_name][gender ? "_[gender]" : ""]")
else if (status & ORGAN_ROBOT)
else if(status & ORGAN_ROBOT)
mob_icon = new /icon('icons/mob/human_races/robotic.dmi', "[icon_name][gender ? "_[gender]" : ""]")
else
if (status & ORGAN_MUTATED)
mob_icon = new /icon(owner.species.deform, "[icon_name][gender ? "_[gender]" : ""]")
mob_icon = new /icon(species.deform, "[icon_name][gender ? "_[gender]" : ""]")
else
mob_icon = new /icon(owner.species.icobase, "[icon_name][gender ? "_[gender]" : ""]")
mob_icon = new /icon(species.icobase, "[icon_name][gender ? "_[gender]" : ""]")
if(status & ORGAN_DEAD)
mob_icon.ColorTone(rgb(10,50,0))
@@ -591,6 +591,8 @@
if(!condi)
var/count = 1
if (href_list["createpatch_multiple"]) count = isgoodnumber(input("Select the number of patches to make.", 10, patchamount) as num)
if(!count || count <= 0)
return
if (count > 20) count = 20 //Pevent people from creating huge stacks of patches easily. Maybe move the number to defines?
var/amount_per_patch = reagents.total_volume/count
if (amount_per_patch > 40) amount_per_patch = 40
+1 -1
View File
@@ -63,7 +63,7 @@
/obj/item/weapon/reagent_containers/proc/reagentlist(var/obj/item/weapon/reagent_containers/snack) //Attack logs for regents in pills
var/data
if(snack.reagents.reagent_list && snack.reagents.reagent_list.len) //find a reagent list if there is and check if it has entries
if(snack && snack.reagents && snack.reagents.reagent_list && snack.reagents.reagent_list.len) //find a reagent list if there is and check if it has entries
for (var/datum/reagent/R in snack.reagents.reagent_list) //no reagents will be left behind
data += "[R.id]([R.volume] units); " //Using IDs because SOME chemicals(I'm looking at you, chlorhydrate-beer) have the same names as other chemicals.
return data
@@ -11,6 +11,26 @@
build_path = /obj/item/weapon/mop/advanced
category = list("Janitorial")
/datum/design/blutrash
name = "Trashbag of Holding"
desc = "An advanced trashabg with bluespace properties; capable of holding a plethora of garbage."
id = "blutrash"
req_tech = list("materials" = 5, "bluespace" = 3)
build_type = PROTOLATHE
materials = list(MAT_GOLD = 1500, MAT_URANIUM = 250, MAT_PLASMA = 1500)
build_path = /obj/item/weapon/storage/bag/trash/bluespace
category = list("Janitorial")
/datum/design/buffer
name = "Floor Buffer Upgrade"
desc = "A floor buffer that can be attached to vehicular janicarts."
id = "buffer"
req_tech = list("materials" = 5, "engineering" = 3)
build_type = PROTOLATHE
materials = list(MAT_METAL = 3000, MAT_GLASS = 200)
build_path = /obj/item/janiupgrade
category = list("Janitorial")
/datum/design/holosign
name = "Holographic Sign Projector"
desc = "A holograpic projector used to project various warning signs."
+13 -13
View File
@@ -184,7 +184,7 @@ won't update every console in existence) but it's more of a hassle to do. Also,
if(..())
return 1
if(!allowed(usr))
if(!allowed(usr) && !isobserver(usr))
return 1
add_fingerprint(usr)
@@ -324,7 +324,7 @@ won't update every console in existence) but it's more of a hassle to do. Also,
use_power(250)
updateUsrDialog()
else if(href_list["lock"]) //Lock the console from use by anyone without tox access.
else if(href_list["lock"]) //Lock the console from use by anyone without access.
if(src.allowed(usr))
screen = text2num(href_list["lock"])
else
@@ -606,7 +606,7 @@ won't update every console in existence) but it's more of a hassle to do. Also,
/obj/machinery/computer/rdconsole/attack_hand(mob/user as mob)
if(..())
return 1
if(!allowed(user))
if(!allowed(user) && !isobserver(user))
user << "<span class='warning'>Access denied.</span>"
return 1
interact(user)
@@ -1115,26 +1115,26 @@ won't update every console in existence) but it's more of a hassle to do. Also,
dat += "</tr></table></div>"
return dat
/obj/machinery/computer/rdconsole/core
name = "Core R&D Console"
desc = "A console used to interface with R&D tools."
id = 1
/obj/machinery/computer/rdconsole/robotics
name = "Robotics R&D Console"
desc = "A console used to interface with R&D tools."
id = 2
req_access = list(access_robotics)
/obj/machinery/computer/rdconsole/experiment
name = "E.X.P.E.R.I-MENTOR R&D Console"
desc = "A console used to interface with R&D tools."
id = 3
/obj/machinery/computer/rdconsole/mechanics
name = "Mechanics R&D Console"
desc = "A console used to interface with R&D tools."
id = 4
req_access = list(access_mechanic)
/obj/machinery/computer/rdconsole/core
name = "Core R&D Console"
desc = "A console used to interface with R&D tools."
id = 1
/obj/machinery/computer/rdconsole/experiment
name = "E.X.P.E.R.I-MENTOR R&D Console"
desc = "A console used to interface with R&D tools."
id = 3
+9 -10
View File
@@ -335,16 +335,15 @@
emagged = 1
user << "\blue You you disable the security protocols"
src.updateUsrDialog()
/obj/machinery/r_n_d/server/robotics
name = "Robotics R&D Server"
id_with_upload_string = "1;2"
id_with_download_string = "1;2"
server_id = 2
/obj/machinery/r_n_d/server/core
name = "Core R&D Server"
id_with_upload_string = "1"
id_with_download_string = "1"
id_with_upload_string = "1;3"
id_with_download_string = "1;3"
server_id = 1
/obj/machinery/r_n_d/server/robotics
name = "Robotics and Mechanic R&D Server"
id_with_upload_string = "1;2;4"
id_with_download_string = "1;2;4"
server_id = 2
@@ -1,186 +1,186 @@
/obj/machinery/keycard_auth
name = "Keycard Authentication Device"
desc = "This device is used to trigger station functions, which require more than one ID card to authenticate."
icon = 'icons/obj/monitors.dmi'
icon_state = "auth_off"
var/active = 0 //This gets set to 1 on all devices except the one where the initial request was made.
var/event = ""
var/screen = 1
var/list/ert_chosen = list()
var/confirmed = 0 //This variable is set by the device that confirms the request.
var/confirm_delay = 20 //(2 seconds)
var/busy = 0 //Busy when waiting for authentication or an event request has been sent from this device.
var/obj/machinery/keycard_auth/event_source
var/mob/event_triggered_by
var/mob/event_confirmed_by
var/ert_reason = "Reason for ERT"
//1 = select event
//2 = authenticate
anchored = 1.0
use_power = 1
idle_power_usage = 2
active_power_usage = 6
power_channel = ENVIRON
/obj/machinery/keycard_auth/attack_ai(mob/user as mob)
user << "The station AI is not to interact with these devices."
return
/obj/machinery/keycard_auth/attackby(obj/item/weapon/W as obj, mob/user as mob, params)
if(stat & (NOPOWER|BROKEN))
user << "This device is not powered."
return
if(istype(W,/obj/item/weapon/card/id))
var/obj/item/weapon/card/id/ID = W
if(access_keycard_auth in ID.access)
if(active == 1)
//This is not the device that made the initial request. It is the device confirming the request.
if(event_source)
event_source.confirmed = 1
event_source.event_confirmed_by = usr
else if(screen == 2)
if(event == "Emergency Response Team" && ert_reason == "Reason for ERT")
user << "<span class='notice'>Supply a reason for calling the ERT first!</span>"
return
event_triggered_by = usr
broadcast_request() //This is the device making the initial event request. It needs to broadcast to other devices
/obj/machinery/keycard_auth/power_change()
if(powered(ENVIRON))
stat &= ~NOPOWER
icon_state = "auth_off"
else
stat |= NOPOWER
/obj/machinery/keycard_auth/attack_hand(mob/user as mob)
if(!user.IsAdvancedToolUser())
return 0
ui_interact(user)
/obj/machinery/keycard_auth/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
if(user.stat || stat & (NOPOWER|BROKEN))
user << "This device is not powered."
return
if(busy)
user << "This device is busy."
return
user.set_machine(src)
var/data[0]
data["screen"] = screen
data["event"] = event
data["ertreason"] = ert_reason
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "keycard_auth.tmpl", "Keycard Authentication Device UI", 520, 320)
ui.set_initial_data(data)
ui.open()
/obj/machinery/keycard_auth/Topic(href, href_list)
if(..())
return
if(busy)
usr << "This device is busy."
return
if(usr.stat || stat & (BROKEN|NOPOWER))
usr << "This device is without power."
return
if(href_list["triggerevent"])
event = href_list["triggerevent"]
screen = 2
if(href_list["reset"])
reset()
if(href_list["ert"])
ert_reason = input(usr, "Reason for ERT Call:", "", "")
nanomanager.update_uis(src)
add_fingerprint(usr)
return
/obj/machinery/keycard_auth/proc/reset()
active = 0
event = ""
screen = 1
confirmed = 0
event_source = null
icon_state = "auth_off"
event_triggered_by = null
event_confirmed_by = null
/obj/machinery/keycard_auth/proc/broadcast_request()
icon_state = "auth_on"
for(var/obj/machinery/keycard_auth/KA in world)
if(KA == src) continue
KA.reset()
spawn()
KA.receive_request(src)
sleep(confirm_delay)
if(confirmed)
confirmed = 0
trigger_event(event)
log_game("[key_name(event_triggered_by)] triggered and [key_name(event_confirmed_by)] confirmed event [event]")
message_admins("[key_name_admin(event_triggered_by)] triggered and [key_name_admin(event_confirmed_by)] confirmed event [event]", 1)
reset()
/obj/machinery/keycard_auth/proc/receive_request(var/obj/machinery/keycard_auth/source)
if(stat & (BROKEN|NOPOWER))
return
event_source = source
busy = 1
active = 1
icon_state = "auth_on"
sleep(confirm_delay)
event_source = null
icon_state = "auth_off"
active = 0
busy = 0
/obj/machinery/keycard_auth/proc/trigger_event()
switch(event)
if("Red Alert")
set_security_level(SEC_LEVEL_RED)
feedback_inc("alert_keycard_auth_red",1)
if("Grant Emergency Maintenance Access")
make_maint_all_access()
feedback_inc("alert_keycard_auth_maintGrant",1)
if("Revoke Emergency Maintenance Access")
revoke_maint_all_access()
feedback_inc("alert_keycard_auth_maintRevoke",1)
if("Emergency Response Team")
if(is_ert_blocked())
usr << "\red All Emergency Response Teams are dispatched and can not be called at this time."
return
usr << "<span class = 'notice'>ERT request transmitted.</span>"
if(admins.len)
ERT_Announce(ert_reason , event_triggered_by)
ert_reason = "Reason for ERT"
feedback_inc("alert_keycard_auth_ert",1)
else
trigger_armed_response_team(new /datum/response_team/amber) // No admins? No problem. Automatically send a code amber ERT.
/obj/machinery/keycard_auth/proc/is_ert_blocked()
return ticker.mode && ticker.mode.ert_disabled
var/global/maint_all_access = 0
/proc/make_maint_all_access()
for(var/area/maintenance/A in world)
for(var/obj/machinery/door/airlock/D in A)
D.emergency = 1
D.update_icon(0)
minor_announcement.Announce("The maintenance access requirement has been revoked on all airlocks.")
maint_all_access = 1
/proc/revoke_maint_all_access()
for(var/area/maintenance/A in world)
for(var/obj/machinery/door/airlock/D in A)
D.emergency = 0
D.update_icon(0)
minor_announcement.Announce("The maintenance access requirement has been readded on all maintenance airlocks.")
/obj/machinery/keycard_auth
name = "Keycard Authentication Device"
desc = "This device is used to trigger station functions, which require more than one ID card to authenticate."
icon = 'icons/obj/monitors.dmi'
icon_state = "auth_off"
var/active = 0 //This gets set to 1 on all devices except the one where the initial request was made.
var/event = ""
var/screen = 1
var/list/ert_chosen = list()
var/confirmed = 0 //This variable is set by the device that confirms the request.
var/confirm_delay = 20 //(2 seconds)
var/busy = 0 //Busy when waiting for authentication or an event request has been sent from this device.
var/obj/machinery/keycard_auth/event_source
var/mob/event_triggered_by
var/mob/event_confirmed_by
var/ert_reason = "Reason for ERT"
//1 = select event
//2 = authenticate
anchored = 1.0
use_power = 1
idle_power_usage = 2
active_power_usage = 6
power_channel = ENVIRON
/obj/machinery/keycard_auth/attack_ai(mob/user as mob)
user << "The station AI is not to interact with these devices."
return
/obj/machinery/keycard_auth/attackby(obj/item/weapon/W as obj, mob/user as mob, params)
if(stat & (NOPOWER|BROKEN))
user << "This device is not powered."
return
if(istype(W,/obj/item/weapon/card/id))
var/obj/item/weapon/card/id/ID = W
if(access_keycard_auth in ID.access)
if(active == 1)
//This is not the device that made the initial request. It is the device confirming the request.
if(event_source)
event_source.confirmed = 1
event_source.event_confirmed_by = usr
else if(screen == 2)
if(event == "Emergency Response Team" && ert_reason == "Reason for ERT")
user << "<span class='notice'>Supply a reason for calling the ERT first!</span>"
return
event_triggered_by = usr
broadcast_request() //This is the device making the initial event request. It needs to broadcast to other devices
/obj/machinery/keycard_auth/power_change()
if(powered(ENVIRON))
stat &= ~NOPOWER
icon_state = "auth_off"
else
stat |= NOPOWER
/obj/machinery/keycard_auth/attack_hand(mob/user as mob)
if(!user.IsAdvancedToolUser())
return 0
ui_interact(user)
/obj/machinery/keycard_auth/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
if(user.stat || stat & (NOPOWER|BROKEN))
user << "This device is not powered."
return
if(busy)
user << "This device is busy."
return
user.set_machine(src)
var/data[0]
data["screen"] = screen
data["event"] = event
data["ertreason"] = ert_reason
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "keycard_auth.tmpl", "Keycard Authentication Device UI", 520, 320)
ui.set_initial_data(data)
ui.open()
/obj/machinery/keycard_auth/Topic(href, href_list)
if(..())
return
if(busy)
usr << "This device is busy."
return
if(usr.stat || stat & (BROKEN|NOPOWER))
usr << "This device is without power."
return
if(href_list["triggerevent"])
event = href_list["triggerevent"]
screen = 2
if(href_list["reset"])
reset()
if(href_list["ert"])
ert_reason = input(usr, "Reason for ERT Call:", "", "")
nanomanager.update_uis(src)
add_fingerprint(usr)
return
/obj/machinery/keycard_auth/proc/reset()
active = 0
event = ""
screen = 1
confirmed = 0
event_source = null
icon_state = "auth_off"
event_triggered_by = null
event_confirmed_by = null
/obj/machinery/keycard_auth/proc/broadcast_request()
icon_state = "auth_on"
for(var/obj/machinery/keycard_auth/KA in world)
if(KA == src) continue
KA.reset()
spawn()
KA.receive_request(src)
sleep(confirm_delay)
if(confirmed)
confirmed = 0
trigger_event(event)
log_game("[key_name(event_triggered_by)] triggered and [key_name(event_confirmed_by)] confirmed event [event]")
message_admins("[key_name_admin(event_triggered_by)] triggered and [key_name_admin(event_confirmed_by)] confirmed event [event]", 1)
reset()
/obj/machinery/keycard_auth/proc/receive_request(var/obj/machinery/keycard_auth/source)
if(stat & (BROKEN|NOPOWER))
return
event_source = source
busy = 1
active = 1
icon_state = "auth_on"
sleep(confirm_delay)
event_source = null
icon_state = "auth_off"
active = 0
busy = 0
/obj/machinery/keycard_auth/proc/trigger_event()
switch(event)
if("Red Alert")
set_security_level(SEC_LEVEL_RED)
feedback_inc("alert_keycard_auth_red",1)
if("Grant Emergency Maintenance Access")
make_maint_all_access()
feedback_inc("alert_keycard_auth_maintGrant",1)
if("Revoke Emergency Maintenance Access")
revoke_maint_all_access()
feedback_inc("alert_keycard_auth_maintRevoke",1)
if("Emergency Response Team")
if(is_ert_blocked())
usr << "\red All Emergency Response Teams are dispatched and can not be called at this time."
return
usr << "<span class = 'notice'>ERT request transmitted.</span>"
if(admins.len)
ERT_Announce(ert_reason , event_triggered_by)
ert_reason = "Reason for ERT"
feedback_inc("alert_keycard_auth_ert",1)
else
trigger_armed_response_team(new /datum/response_team/amber) // No admins? No problem. Automatically send a code amber ERT.
/obj/machinery/keycard_auth/proc/is_ert_blocked()
return ticker.mode && ticker.mode.ert_disabled
var/global/maint_all_access = 0
/proc/make_maint_all_access()
for(var/area/maintenance/A in world)
for(var/obj/machinery/door/airlock/D in A)
D.emergency = 1
D.update_icon(0)
minor_announcement.Announce("The maintenance access requirement has been revoked on all airlocks.")
maint_all_access = 1
/proc/revoke_maint_all_access()
for(var/area/maintenance/A in world)
for(var/obj/machinery/door/airlock/D in A)
D.emergency = 0
D.update_icon(0)
minor_announcement.Announce("The maintenance access requirement has been readded on all maintenance airlocks.")
maint_all_access = 0
@@ -1,184 +1,184 @@
/var/security_level = 0
//0 = code green
//1 = code blue
//2 = code red
//3 = gamma
//4 = epsilon
//5 = code delta
//config.alert_desc_blue_downto
/var/datum/announcement/priority/security/security_announcement_up = new(do_log = 0, do_newscast = 1, new_sound = sound('sound/misc/notice1.ogg'))
/var/datum/announcement/priority/security/security_announcement_down = new(do_log = 0, do_newscast = 1)
/proc/set_security_level(var/level)
switch(level)
if("green")
level = SEC_LEVEL_GREEN
if("blue")
level = SEC_LEVEL_BLUE
if("red")
level = SEC_LEVEL_RED
if("gamma")
level = SEC_LEVEL_GAMMA
if("epsilon")
level = SEC_LEVEL_EPSILON
if("delta")
level = SEC_LEVEL_DELTA
//Will not be announced if you try to set to the same level as it already is
if(level >= SEC_LEVEL_GREEN && level <= SEC_LEVEL_DELTA && level != security_level)
switch(level)
if(SEC_LEVEL_GREEN)
security_announcement_down.Announce("All threats to the station have passed. All weapons need to be holstered and privacy laws are once again fully enforced.","Attention! Security level lowered to green.")
security_level = SEC_LEVEL_GREEN
for(var/obj/machinery/firealarm/FA in world)
if((FA.z in config.contact_levels))
FA.overlays = list()
FA.overlays += image('icons/obj/monitors.dmi', "overlay_green")
if(SEC_LEVEL_BLUE)
if(security_level < SEC_LEVEL_BLUE)
security_announcement_up.Announce("The station has received reliable information about possible hostile activity on the station. Security staff may have weapons visible and random searches are permitted.","Attention! Security level elevated to blue.")
else
security_announcement_down.Announce("The immediate threat has passed. Security may no longer have weapons drawn at all times, but may continue to have them visible. Random searches are still allowed.","Attention! Security level lowered to blue.")
security_level = SEC_LEVEL_BLUE
for(var/obj/machinery/firealarm/FA in world)
if((FA.z in config.contact_levels))
FA.overlays = list()
FA.overlays += image('icons/obj/monitors.dmi', "overlay_blue")
if(SEC_LEVEL_RED)
if(security_level < SEC_LEVEL_RED)
security_announcement_up.Announce("There is an immediate and serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised.","Attention! Code Red!")
else
security_announcement_down.Announce("The station's self-destruct mechanism has been deactivated, but there is still an immediate and serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised.","Attention! Code Red!")
security_level = SEC_LEVEL_RED
var/obj/machinery/door/airlock/highsecurity/red/R = locate(/obj/machinery/door/airlock/highsecurity/red) in world
if(R && (R.z in config.station_levels))
R.locked = 0
R.update_icon()
var/obj/machinery/computer/communications/CC = locate(/obj/machinery/computer/communications,world)
if(CC)
CC.post_status("alert", "redalert")
for(var/obj/machinery/firealarm/FA in world)
if((FA.z in config.contact_levels))
FA.overlays = list()
FA.overlays += image('icons/obj/monitors.dmi', "overlay_red")
if(SEC_LEVEL_GAMMA)
security_announcement_up.Announce("Central Command has ordered the Gamma security level on the station. Security is to have weapons equipped at all times, and all civilians are to immediately seek their nearest head for transportation to a secure location. The station's Gamma armory has been unlocked and is ready for use.","Attention! Gamma security level activated!")
security_level = SEC_LEVEL_GAMMA
move_gamma_ship()
if(security_level < SEC_LEVEL_RED)
for(var/obj/machinery/door/airlock/highsecurity/red/R in world)
if((R.z in config.station_levels))
R.locked = 0
R.update_icon()
for(var/obj/machinery/door/airlock/hatch/gamma/H in world)
if((H.z in config.station_levels))
H.locked = 0
H.update_icon()
var/obj/machinery/computer/communications/CC = locate(/obj/machinery/computer/communications,world)
if(CC)
CC.post_status("alert", "redalert")
for(var/obj/machinery/firealarm/FA in world)
if((FA.z in config.contact_levels))
FA.overlays = list()
FA.overlays += image('icons/obj/monitors.dmi', "overlay_gamma")
FA.update_icon()
if(SEC_LEVEL_EPSILON)
security_announcement_up.Announce("Central Command has ordered the Epsilon security level on the station. Consider all contracts terminated.","Attention! Epsilon security level activated!")
security_level = SEC_LEVEL_EPSILON
var/obj/machinery/computer/communications/CC = locate(/obj/machinery/computer/communications,world)
if(CC)
CC.post_status("alert", "redalert")
for(var/obj/machinery/firealarm/FA in world)
if((FA.z in config.contact_levels))
FA.overlays = list()
FA.overlays += image('icons/obj/monitors.dmi', "overlay_epsilon")
if(SEC_LEVEL_DELTA)
security_announcement_up.Announce("The station's self-destruct mechanism has been engaged. All crew are instructed to obey all instructions given by heads of staff. Any violations of these orders can be punished by death. This is not a drill.","Attention! Delta security level reached!")
security_level = SEC_LEVEL_DELTA
var/obj/machinery/computer/communications/CC = locate(/obj/machinery/computer/communications,world)
if(CC)
CC.post_status("alert", "redalert")
for(var/obj/machinery/firealarm/FA in world)
if((FA.z in config.contact_levels))
FA.overlays = list()
FA.overlays += image('icons/obj/monitors.dmi', "overlay_delta")
else
return
/proc/get_security_level()
switch(security_level)
if(SEC_LEVEL_GREEN)
return "green"
if(SEC_LEVEL_BLUE)
return "blue"
if(SEC_LEVEL_RED)
return "red"
if(SEC_LEVEL_GAMMA)
return "gamma"
if(SEC_LEVEL_EPSILON)
return "epsilon"
if(SEC_LEVEL_DELTA)
return "delta"
/proc/num2seclevel(var/num)
switch(num)
if(SEC_LEVEL_GREEN)
return "green"
if(SEC_LEVEL_BLUE)
return "blue"
if(SEC_LEVEL_RED)
return "red"
if(SEC_LEVEL_GAMMA)
return "gamma"
if(SEC_LEVEL_EPSILON)
return "epsilon"
if(SEC_LEVEL_DELTA)
return "delta"
/proc/seclevel2num(var/seclevel)
switch( lowertext(seclevel) )
if("green")
return SEC_LEVEL_GREEN
if("blue")
return SEC_LEVEL_BLUE
if("red")
return SEC_LEVEL_RED
if("gamma")
return SEC_LEVEL_GAMMA
if("epsilon")
return SEC_LEVEL_EPSILON
if("delta")
return SEC_LEVEL_DELTA
/*DEBUG
/mob/verb/set_thing0()
set_security_level(0)
/mob/verb/set_thing1()
set_security_level(1)
/mob/verb/set_thing2()
set_security_level(2)
/mob/verb/set_thing3()
set_security_level(3)
/var/security_level = 0
//0 = code green
//1 = code blue
//2 = code red
//3 = gamma
//4 = epsilon
//5 = code delta
//config.alert_desc_blue_downto
/var/datum/announcement/priority/security/security_announcement_up = new(do_log = 0, do_newscast = 1, new_sound = sound('sound/misc/notice1.ogg'))
/var/datum/announcement/priority/security/security_announcement_down = new(do_log = 0, do_newscast = 1)
/proc/set_security_level(var/level)
switch(level)
if("green")
level = SEC_LEVEL_GREEN
if("blue")
level = SEC_LEVEL_BLUE
if("red")
level = SEC_LEVEL_RED
if("gamma")
level = SEC_LEVEL_GAMMA
if("epsilon")
level = SEC_LEVEL_EPSILON
if("delta")
level = SEC_LEVEL_DELTA
//Will not be announced if you try to set to the same level as it already is
if(level >= SEC_LEVEL_GREEN && level <= SEC_LEVEL_DELTA && level != security_level)
switch(level)
if(SEC_LEVEL_GREEN)
security_announcement_down.Announce("All threats to the station have passed. All weapons need to be holstered and privacy laws are once again fully enforced.","Attention! Security level lowered to green.")
security_level = SEC_LEVEL_GREEN
for(var/obj/machinery/firealarm/FA in world)
if((FA.z in config.contact_levels))
FA.overlays = list()
FA.overlays += image('icons/obj/monitors.dmi', "overlay_green")
if(SEC_LEVEL_BLUE)
if(security_level < SEC_LEVEL_BLUE)
security_announcement_up.Announce("The station has received reliable information about possible hostile activity on the station. Security staff may have weapons visible and random searches are permitted.","Attention! Security level elevated to blue.")
else
security_announcement_down.Announce("The immediate threat has passed. Security may no longer have weapons drawn at all times, but may continue to have them visible. Random searches are still allowed.","Attention! Security level lowered to blue.")
security_level = SEC_LEVEL_BLUE
for(var/obj/machinery/firealarm/FA in world)
if((FA.z in config.contact_levels))
FA.overlays = list()
FA.overlays += image('icons/obj/monitors.dmi', "overlay_blue")
if(SEC_LEVEL_RED)
if(security_level < SEC_LEVEL_RED)
security_announcement_up.Announce("There is an immediate and serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised.","Attention! Code Red!")
else
security_announcement_down.Announce("The station's self-destruct mechanism has been deactivated, but there is still an immediate and serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised.","Attention! Code Red!")
security_level = SEC_LEVEL_RED
var/obj/machinery/door/airlock/highsecurity/red/R = locate(/obj/machinery/door/airlock/highsecurity/red) in world
if(R && (R.z in config.station_levels))
R.locked = 0
R.update_icon()
var/obj/machinery/computer/communications/CC = locate(/obj/machinery/computer/communications,world)
if(CC)
CC.post_status("alert", "redalert")
for(var/obj/machinery/firealarm/FA in world)
if((FA.z in config.contact_levels))
FA.overlays = list()
FA.overlays += image('icons/obj/monitors.dmi', "overlay_red")
if(SEC_LEVEL_GAMMA)
security_announcement_up.Announce("Central Command has ordered the Gamma security level on the station. Security is to have weapons equipped at all times, and all civilians are to immediately seek their nearest head for transportation to a secure location. The station's Gamma armory has been unlocked and is ready for use.","Attention! Gamma security level activated!")
security_level = SEC_LEVEL_GAMMA
move_gamma_ship()
if(security_level < SEC_LEVEL_RED)
for(var/obj/machinery/door/airlock/highsecurity/red/R in world)
if((R.z in config.station_levels))
R.locked = 0
R.update_icon()
for(var/obj/machinery/door/airlock/hatch/gamma/H in world)
if((H.z in config.station_levels))
H.locked = 0
H.update_icon()
var/obj/machinery/computer/communications/CC = locate(/obj/machinery/computer/communications,world)
if(CC)
CC.post_status("alert", "redalert")
for(var/obj/machinery/firealarm/FA in world)
if((FA.z in config.contact_levels))
FA.overlays = list()
FA.overlays += image('icons/obj/monitors.dmi', "overlay_gamma")
FA.update_icon()
if(SEC_LEVEL_EPSILON)
security_announcement_up.Announce("Central Command has ordered the Epsilon security level on the station. Consider all contracts terminated.","Attention! Epsilon security level activated!")
security_level = SEC_LEVEL_EPSILON
var/obj/machinery/computer/communications/CC = locate(/obj/machinery/computer/communications,world)
if(CC)
CC.post_status("alert", "redalert")
for(var/obj/machinery/firealarm/FA in world)
if((FA.z in config.contact_levels))
FA.overlays = list()
FA.overlays += image('icons/obj/monitors.dmi', "overlay_epsilon")
if(SEC_LEVEL_DELTA)
security_announcement_up.Announce("The station's self-destruct mechanism has been engaged. All crew are instructed to obey all instructions given by heads of staff. Any violations of these orders can be punished by death. This is not a drill.","Attention! Delta security level reached!")
security_level = SEC_LEVEL_DELTA
var/obj/machinery/computer/communications/CC = locate(/obj/machinery/computer/communications,world)
if(CC)
CC.post_status("alert", "redalert")
for(var/obj/machinery/firealarm/FA in world)
if((FA.z in config.contact_levels))
FA.overlays = list()
FA.overlays += image('icons/obj/monitors.dmi', "overlay_delta")
else
return
/proc/get_security_level()
switch(security_level)
if(SEC_LEVEL_GREEN)
return "green"
if(SEC_LEVEL_BLUE)
return "blue"
if(SEC_LEVEL_RED)
return "red"
if(SEC_LEVEL_GAMMA)
return "gamma"
if(SEC_LEVEL_EPSILON)
return "epsilon"
if(SEC_LEVEL_DELTA)
return "delta"
/proc/num2seclevel(var/num)
switch(num)
if(SEC_LEVEL_GREEN)
return "green"
if(SEC_LEVEL_BLUE)
return "blue"
if(SEC_LEVEL_RED)
return "red"
if(SEC_LEVEL_GAMMA)
return "gamma"
if(SEC_LEVEL_EPSILON)
return "epsilon"
if(SEC_LEVEL_DELTA)
return "delta"
/proc/seclevel2num(var/seclevel)
switch( lowertext(seclevel) )
if("green")
return SEC_LEVEL_GREEN
if("blue")
return SEC_LEVEL_BLUE
if("red")
return SEC_LEVEL_RED
if("gamma")
return SEC_LEVEL_GAMMA
if("epsilon")
return SEC_LEVEL_EPSILON
if("delta")
return SEC_LEVEL_DELTA
/*DEBUG
/mob/verb/set_thing0()
set_security_level(0)
/mob/verb/set_thing1()
set_security_level(1)
/mob/verb/set_thing2()
set_security_level(2)
/mob/verb/set_thing3()
set_security_level(3)
*/
@@ -0,0 +1,187 @@
//This is realisation of the working torus-looping randomized-per-round space map, this kills the cube
#define Z_LEVEL_NORTH "1"
#define Z_LEVEL_SOUTH "2"
#define Z_LEVEL_EAST "4"
#define Z_LEVEL_WEST "8"
var/list/z_levels_list = list()
/datum/space_level
var/name = "Your config settings failed, you need to fix this for the datum space levels to work"
var/list/neigbours
var/z_value = 1 //actual z placement
var/linked = 1
var/xi
var/yi //imaginary placements on the grid
/datum/space_level/New()
neigbours = list()
var/list/L = list(Z_LEVEL_NORTH,Z_LEVEL_SOUTH,Z_LEVEL_EAST,Z_LEVEL_WEST)
for(var/A in L)
neigbours[A] = src
/datum/space_level/proc/set_neigbours(list/L)
for(var/datum/point/P in L)
if(P.x == xi)
if(P.y == yi+1)
neigbours[Z_LEVEL_NORTH] = P.spl
P.spl.neigbours[Z_LEVEL_SOUTH] = src
else if(P.y == yi-1)
neigbours[Z_LEVEL_SOUTH] = P.spl
P.spl.neigbours[Z_LEVEL_NORTH] = src
else if(P.y == yi)
if(P.x == xi+1)
neigbours[Z_LEVEL_EAST] = P.spl
P.spl.neigbours[Z_LEVEL_WEST] = src
else if(P.x == xi-1)
neigbours[Z_LEVEL_WEST] = P.spl
P.spl.neigbours[Z_LEVEL_EAST] = src
/datum/point //this is explicitly utilitarian datum type made specially for the space map generation and are absolutely unusable for anything else
var/list/neigbours = list()
var/x
var/y
var/datum/space_level/spl
/datum/point/New(nx, ny, list/point_grid)
if(!point_grid)
qdel(src)
return
var/list/L = point_grid[1]
if(nx > point_grid.len || ny > L.len)
qdel(src)
return
x = nx
y = ny
if(point_grid[x][y])
return
point_grid[x][y] = src
/datum/point/proc/set_neigbours(list/grid)
var/max_X = grid.len
var/list/max_Y = grid[1]
max_Y = max_Y.len
neigbours.Cut()
if(x+1 <= max_X)
neigbours |= grid[x+1][y]
if(x-1 >= 1)
neigbours |= grid[x-1][y]
if(y+1 <= max_Y)
neigbours |= grid[x][y+1]
if(y-1 >= 1)
neigbours |= grid[x][y-1]
//config/space_levels.txt is where you define your zlevel datum names, their connection to actual z levels and if you want them connected to one another or not
//Grammar: Name;z value;linked/unlinked
//Name is the name of the datum, just for the sake of it
//z value is to what actual map z level this datum is pointing
//linked/unlinked decide if you want the z level in the general map or not, for example centcomm is not reachable
//Each entry must be separated with a single empty line, no spaces outside the name
//No comments in the file allowed
/proc/setup_map_transitions() //listamania
var/list/SLS = file2list("config/space_levels.txt", "\n\n")
var/datum/space_level/D
var/list/config_settings[SLS.len][]
for(var/A in SLS)
config_settings[SLS.Find(A)] = text2list(A, ";")
var/conf_set_len = SLS.len
SLS.Cut()
for(var/A in config_settings)
D = new()
D.name = A[1]
D.z_value = text2num(A[2])
if(A[3] != "linked")
D.linked = 0
z_levels_list["[D.z_value]"] = D
else
SLS.Add(D)
var/list/point_grid[conf_set_len*2+1][conf_set_len*2+1]
var/list/grid = list()
var/datum/point/P
for(var/i = 1, i<=conf_set_len*2+1, i++)
for(var/j = 1, j<=conf_set_len*2+1, j++)
P = new/datum/point(i,j, point_grid)
point_grid[i][j] = P
grid.Add(P)
for(var/datum/point/pnt in grid)
pnt.set_neigbours(point_grid)
P = point_grid[conf_set_len][conf_set_len]
var/list/possible_points = list()
var/list/used_points = list()
grid.Cut()
while(SLS.len)
D = pick(SLS)
SLS.Remove(D)
D.xi = P.x
D.yi = P.y
P.spl = D
possible_points |= P.neigbours
used_points |= P
possible_points.Remove(used_points)
D.set_neigbours(used_points)
P = pick(possible_points)
grid["[D.z_value]"] = D
for(var/A in z_levels_list)
grid[A] = z_levels_list[A]
for(var/turf/space/S in world) //Define the transistions of the z levels
if(S.x <= TRANSITIONEDGE)
D = grid["[S.z]"]
if(D.neigbours[Z_LEVEL_WEST] != D)
D = D.neigbours[Z_LEVEL_WEST]
S.destination_z = D.z_value
else
while(D.neigbours[Z_LEVEL_EAST] != D)
D = D.neigbours[Z_LEVEL_EAST]
S.destination_z = D.z_value
S.destination_x = world.maxx - TRANSITIONEDGE - 2
S.destination_y = S.y
if(S.x >= (world.maxx - TRANSITIONEDGE - 1))
D = grid["[S.z]"]
if(D.neigbours[Z_LEVEL_EAST] != D)
D = D.neigbours[Z_LEVEL_EAST]
S.destination_z = D.z_value
else
while(D.neigbours[Z_LEVEL_WEST] != D)
D = D.neigbours[Z_LEVEL_WEST]
S.destination_z = D.z_value
S.destination_x = TRANSITIONEDGE + 2
S.destination_y = S.y
if(S.y <= TRANSITIONEDGE)
D = grid["[S.z]"]
if(D.neigbours[Z_LEVEL_SOUTH] != D)
D = D.neigbours[Z_LEVEL_SOUTH]
S.destination_z = D.z_value
else
while(D.neigbours[Z_LEVEL_NORTH] != D)
D = D.neigbours[Z_LEVEL_NORTH]
S.destination_z = D.z_value
S.destination_x = S.x
S.destination_y = world.maxy - TRANSITIONEDGE - 2
if(S.y >= (world.maxy - TRANSITIONEDGE - 1))
D = grid["[S.z]"]
if(D.neigbours[Z_LEVEL_NORTH] != D)
D = D.neigbours[Z_LEVEL_NORTH]
S.destination_z = D.z_value
else
while(D.neigbours[Z_LEVEL_SOUTH] != D)
D = D.neigbours[Z_LEVEL_SOUTH]
S.destination_z = D.z_value
S.destination_x = S.x
S.destination_y = TRANSITIONEDGE + 2
for(var/A in grid)
z_levels_list[A] = grid[A]
#undef Z_LEVEL_NORTH
#undef Z_LEVEL_SOUTH
#undef Z_LEVEL_EAST
#undef Z_LEVEL_WEST
@@ -1,342 +0,0 @@
/obj/vehicle/train/janitor/engine
name = "janitor train tug"
desc = "A ridable electric car designed for pulling janitor trolleys."
icon = 'icons/obj/vehicles.dmi'
icon_state = "pussywagon" //mulebot icons until I get some proper icons
on = 0
powered = 1
locked = 0
layer = MOB_LAYER + 0.1
load_item_visible = 1
load_offset_x = 0
load_offset_y = 7
var/car_limit = 3 //how many cars an engine can pull before performance degrades
active_engines = 1
var/obj/item/weapon/key/janitor_train/key
flags = OPENCONTAINER
var/amount_per_transfer_from_this = 5 //shit I dunno, adding this so syringes stop runtime erroring. --NeoFite
var/obj/item/weapon/storage/bag/trash/mybag = null
/obj/item/weapon/key/janitor_train
name = "key"
desc = "A keyring with a small steel key, and a yellow fob reading \"Choo Choo!\"."
icon = 'icons/obj/vehicles.dmi'
icon_state = "keys"
w_class = 1
/obj/vehicle/train/janitor/trolley
name = "janitor train trolley"
icon = 'icons/obj/janitor.dmi'
icon_state = "trashcart"
anchored = 0
passenger_allowed = 0
locked = 0
load_item_visible = 1
load_offset_x = 1
load_offset_y = 7
var/openTop = 0
var/organs = 0
//-------------------------------------------
// Standard procs
//-------------------------------------------
/obj/vehicle/train/janitor/engine/New()
..()
cell = new /obj/item/weapon/stock_parts/cell/high
verbs -= /atom/movable/verb/pull
key = new()
var/datum/reagents/R = new/datum/reagents(100)
reagents = R
R.my_atom = src
/obj/vehicle/train/janitor/engine/Move()
. = ..()
handle_rotation()
update_mob()
/obj/vehicle/train/janitor/trolley/attackby(obj/item/weapon/W as obj, mob/user as mob, params)
if(openTop)
W.loc = src
user.visible_message("<span class='notice'>[user] puts [W] in [src].</span>","<span class='notice'>You put [W] in [src].</span>")
if(istype(W,/obj/item/weapon/organ))
organs = 1
update_icon()
else
user << "The top is closed!"
/obj/vehicle/train/janitor/trolley/attack_hand(mob/user)
openTop = !openTop
user.visible_message("<span class='notice'>[user] [openTop ? "opens" : "closes"] the top of [src].</span>","<span class='notice'>You [openTop ? "open" : "close"] the the top of [src].</span>")
update_icon()
..()
/obj/vehicle/train/janitor/trolley/update_icon()
if(openTop)
if(organs)
icon_state = "trashcartopengib"
else
icon_state = "trashcartopen"
else
if(organs)
icon_state = "trashcartgib"
else
icon_state = "trashcart"
/obj/vehicle/train/janitor/engine/attackby(obj/item/weapon/W as obj, mob/user as mob, params)
if(istype(W, /obj/item/weapon/key/janitor_train))
if(!key)
user.drop_item()
key = W
W.loc = src
verbs += /obj/vehicle/train/janitor/engine/verb/remove_key
return
else if(istype(W, /obj/item/weapon/mop))
if(reagents.total_volume >= 2)
reagents.trans_to(W, 2)
user << "<span class='notice'>You wet the mop in the pimpin' ride.</span>"
playsound(src.loc, 'sound/effects/slosh.ogg', 25, 1)
if(reagents.total_volume < 1)
user << "<span class='notice'>This pimpin' ride is out of water!</span>"
return
else if(istype(W, /obj/item/weapon/storage/bag/trash))
user << "<span class='notice'>You hook the trashbag onto the pimpin' ride.</span>"
user.drop_item()
W.loc = src
mybag = W
return
..()
/obj/vehicle/train/janitor/engine/attack_hand(mob/user)
if(mybag)
mybag.loc = get_turf(user)
user.put_in_hands(mybag)
mybag = null
else
..()
/obj/vehicle/train/janitor/update_icon()
if(open)
//icon_state = "mulebot-hatch"
icon_state = initial(icon_state)
else
icon_state = initial(icon_state)
/obj/vehicle/train/janitor/engine/Emag(mob/user as mob)
..()
flick("mulebot-emagged", src)
/obj/vehicle/train/janitor/trolley/insert_cell(var/obj/item/weapon/stock_parts/cell/C, var/mob/living/carbon/human/H)
return
/obj/vehicle/train/janitor/engine/insert_cell(var/obj/item/weapon/stock_parts/cell/C, var/mob/living/carbon/human/H)
..()
update_stats()
/obj/vehicle/train/janitor/engine/remove_cell(var/mob/living/carbon/human/H)
..()
update_stats()
/obj/vehicle/train/janitor/engine/Bump(atom/Obstacle)
var/obj/machinery/door/D = Obstacle
var/mob/living/carbon/human/H = load
if(istype(D) && istype(H))
D.Bumped(H) //a little hacky, but hey, it works, and repects access rights
..()
/obj/vehicle/train/janitor/trolley/Bump(atom/Obstacle)
if(!lead)
return //so people can't knock others over by pushing a trolley around
..()
/obj/vehicle/train/janitor/engine/handle_rotation()
if(dir == SOUTH)
layer = FLY_LAYER
else
layer = OBJ_LAYER
/obj/vehicle/train/janitor/engine/proc/update_mob()
if(load)
load.dir = dir
switch(dir)
if(SOUTH)
load.pixel_x = 0
load.pixel_y = 7
if(WEST)
load.pixel_x = 13
load.pixel_y = 7
if(NORTH)
load.pixel_x = 0
load.pixel_y = 4
if(EAST)
load.pixel_x = -13
load.pixel_y = 7
//-------------------------------------------
// Train procs
//-------------------------------------------
/obj/vehicle/train/janitor/engine/turn_on()
if(!key)
return
else
..()
update_stats()
/obj/vehicle/train/janitor/RunOver(var/mob/living/carbon/human/H)
var/list/parts = list("head", "chest", "l_leg", "r_leg", "l_arm", "r_arm")
H.apply_effects(5, 5)
for(var/i = 0, i < rand(1,3), i++)
H.apply_damage(rand(1,5), BRUTE, pick(parts))
/obj/vehicle/train/janitor/trolley/RunOver(var/mob/living/carbon/human/H)
..()
attack_log += text("\[[time_stamp()]\] <font color='red'>ran over [H.name] ([H.ckey])</font>")
/obj/vehicle/train/janitor/engine/RunOver(var/mob/living/carbon/human/H)
..()
if(is_train_head() && istype(load, /mob/living/carbon/human))
var/mob/living/carbon/human/D = load
D << "\red \b You ran over [H]!"
visible_message("<B>\red \The [src] ran over [H]!</B>")
attack_log += text("\[[time_stamp()]\] <font color='red'>ran over [key_name(H)], driven by [key_name(D)]</font>")
msg_admin_attack("[key_name_admin(D)] ran over [key_name_admin(H)]")
else
attack_log += text("\[[time_stamp()]\] <font color='red'>ran over [key_name(H)]</font>")
//-------------------------------------------
// Interaction procs
//-------------------------------------------
/obj/vehicle/train/janitor/engine/relaymove(mob/user, direction)
if(user != load)
return 0
if(is_train_head())
if(direction == reverse_direction(dir))
return 0
if(Move(get_step(src, direction)))
return 1
return 0
else
return ..()
/obj/vehicle/train/janitor/engine/examine(mob/user)
if(!..(user, 1))
return
user << "\icon[src] This [name] contains [reagents.total_volume] unit\s of [reagents]!"
if(mybag)
user << "\A [mybag] is hanging on the [name]."
user << "The power light is [on ? "on" : "off"].\nThere are[key ? "" : " no"] keys in the ignition."
/obj/vehicle/train/janitor/engine/verb/check_power()
set name = "Check power level"
set category = "Object"
set src in view(1)
if(!istype(usr, /mob/living/carbon/human))
return
if(!cell)
usr << "There is no power cell installed in [src]."
return
usr << "The power meter reads [round(cell.percent(), 0.01)]%"
/obj/vehicle/train/janitor/engine/verb/start_engine()
set name = "Start engine"
set category = "Object"
set src in view(1)
if(!istype(usr, /mob/living/carbon/human))
return
if(on)
usr << "The engine is already running."
return
turn_on()
if (on)
usr << "You start [src]'s engine."
else
if(cell.charge < charge_use)
usr << "[src] is out of power."
else
usr << "[src]'s engine won't start."
/obj/vehicle/train/janitor/engine/verb/stop_engine()
set name = "Stop engine"
set category = "Object"
set src in view(1)
if(!istype(usr, /mob/living/carbon/human))
return
if(!on)
usr << "The engine is already stopped."
return
turn_off()
if (!on)
usr << "You stop [src]'s engine."
/obj/vehicle/train/janitor/engine/verb/remove_key()
set name = "Remove key"
set category = "Object"
set src in view(1)
if(!istype(usr, /mob/living/carbon/human))
return
if(!key || (load && load != usr))
return
if(on)
turn_off()
key.loc = usr.loc
if(!usr.get_active_hand())
usr.put_in_hands(key)
key = null
verbs -= /obj/vehicle/train/janitor/engine/verb/remove_key
//-------------------------------------------
// Loading/unloading procs
//-------------------------------------------
/obj/vehicle/train/janitor/trolley/load(var/atom/movable/C)
return 0
/obj/vehicle/train/janitor/engine/load(var/atom/movable/C)
if(!ismob(C))
return 0
return ..()
//-------------------------------------------------------
// Stat update procs
//
// Update the trains stats for speed calculations.
// The longer the train, the slower it will go. car_limit
// sets the max number of cars one engine can pull at
// full speed. Adding more cars beyond this will slow the
// train proportionate to the length of the train. Adding
// more engines increases this limit by car_limit per
// engine.
//-------------------------------------------------------
/obj/vehicle/train/janitor/engine/proc/update_move_delay()
if(!is_train_head() || !on)
move_delay = initial(move_delay) //so that engines that have been turned off don't lag behind
else
move_delay = max(0, (-car_limit * active_engines) + train_length - active_engines) //limits base overweight so you cant overspeed trains
move_delay *= (1 / max(1, active_engines)) * 2 //overweight penalty (scaled by the number of engines)
move_delay += config.run_speed //base reference speed
move_delay *= 1.05