mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-28 22:47:59 +01:00
Merge remote-tracking branch 'upstream/master' into vision
This commit is contained in:
@@ -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>"
|
||||
|
||||
@@ -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 .
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.")
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 += " [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]")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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]')
|
||||
|
||||
@@ -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>"
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
@@ -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",
|
||||
)
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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),
|
||||
))
|
||||
*/
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 *
|
||||
|
||||
@@ -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", " ")
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
+185
-185
@@ -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
|
||||
+183
-183
@@ -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
|
||||
Reference in New Issue
Block a user