Merge branch 'master' into upstream-merge-37529
This commit is contained in:
@@ -1,31 +1,46 @@
|
||||
/datum/netdata //this requires some thought later on but for now it's fine.
|
||||
var/network_id
|
||||
|
||||
var/autopasskey = TRUE
|
||||
|
||||
var/list/recipient_ids = list()
|
||||
var/sender_id
|
||||
var/broadcast = FALSE //Whether this is a broadcast packet.
|
||||
|
||||
var/plaintext_data
|
||||
var/plaintext_data_secondary
|
||||
var/encrypted_passkey
|
||||
var/list/data = list()
|
||||
|
||||
var/list/passkey
|
||||
|
||||
// Process data before sending it
|
||||
/datum/netdata/proc/pre_send(datum/component/ntnet_interface/interface)
|
||||
// Decrypt the passkey.
|
||||
if(encrypted_passkey && !passkey)
|
||||
var/result = XorEncrypt(hextostr(encrypted_passkey, TRUE), SScircuit.cipherkey)
|
||||
if(length(result) > 1)
|
||||
passkey = json_decode(XorEncrypt(hextostr(encrypted_passkey, TRUE), SScircuit.cipherkey))
|
||||
if(autopasskey)
|
||||
if(data["encrypted_passkey"] && !passkey)
|
||||
var/result = XorEncrypt(hextostr(data["encrypted_passkey"], TRUE), SScircuit.cipherkey)
|
||||
if(length(result) > 1)
|
||||
passkey = json_decode(XorEncrypt(hextostr(data["encrypted_passkey"], TRUE), SScircuit.cipherkey))
|
||||
|
||||
// Encrypt the passkey.
|
||||
if(!encrypted_passkey && passkey)
|
||||
encrypted_passkey = strtohex(XorEncrypt(json_encode(passkey), SScircuit.cipherkey))
|
||||
// Encrypt the passkey.
|
||||
if(!data["encrypted_passkey"] && passkey)
|
||||
data["encrypted_passkey"] = strtohex(XorEncrypt(json_encode(passkey), SScircuit.cipherkey))
|
||||
|
||||
// If there is no sender ID, set the default one.
|
||||
if(!sender_id && interface)
|
||||
sender_id = interface.hardware_id
|
||||
|
||||
/datum/netdata/proc/standard_format_data(primary, secondary, passkey)
|
||||
data["data"] = primary
|
||||
data["data_secondary"] = secondary
|
||||
data["encrypted_passkey"] = passkey
|
||||
|
||||
/datum/netdata/proc/json_to_data(json)
|
||||
data = json_decode(json)
|
||||
|
||||
/datum/netdata/proc/json_append_to_data(json)
|
||||
data |= json_decode(json)
|
||||
|
||||
/datum/netdata/proc/data_to_json()
|
||||
return json_encode(data)
|
||||
|
||||
/datum/netdata/proc/json_list_generation_admin() //for admin logs and such.
|
||||
. = list()
|
||||
@@ -40,9 +55,7 @@
|
||||
. = list()
|
||||
.["recipient_ids"] = recipient_ids
|
||||
.["sender_id"] = sender_id
|
||||
.["data"] = plaintext_data
|
||||
.["data_secondary"] = plaintext_data_secondary
|
||||
.["passkey"] = encrypted_passkey
|
||||
.["data_list"] = data
|
||||
|
||||
/datum/netdata/proc/generate_netlog()
|
||||
return "[json_encode(json_list_generation_netlog())]"
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
/datum/ntnet
|
||||
var/network_id = "Network"
|
||||
var/connected_interfaces_by_id = list() //id = datum/component/ntnet_interface
|
||||
var/list/connected_interfaces_by_id = list() //id = datum/component/ntnet_interface
|
||||
var/list/services_by_path = list() //type = datum/ntnet_service
|
||||
var/list/services_by_id = list() //id = datum/ntnet_service
|
||||
|
||||
var/list/autoinit_service_paths = list() //typepaths
|
||||
|
||||
|
||||
var/list/relays = list()
|
||||
var/list/logs = list()
|
||||
@@ -32,7 +37,18 @@
|
||||
stack_trace("Network [type] with ID [network_id] failed to register and has been deleted.")
|
||||
qdel(src)
|
||||
|
||||
/datum/ntnet/Destroy()
|
||||
for(var/i in connected_interfaces_by_id)
|
||||
var/datum/component/ntnet_interface/I = i
|
||||
I.unregister_connection(src)
|
||||
for(var/i in services_by_id)
|
||||
var/datum/ntnet_service/S = i
|
||||
S.disconnect(src, TRUE)
|
||||
return ..()
|
||||
|
||||
/datum/ntnet/proc/interface_connect(datum/component/ntnet_interface/I)
|
||||
if(connected_interfaces_by_id[I.hardware_id])
|
||||
return FALSE
|
||||
connected_interfaces_by_id[I.hardware_id] = I
|
||||
return TRUE
|
||||
|
||||
@@ -43,15 +59,68 @@
|
||||
/datum/ntnet/proc/find_interface_id(id)
|
||||
return connected_interfaces_by_id[id]
|
||||
|
||||
/datum/ntnet/proc/find_service_id(id)
|
||||
return services_by_id[id]
|
||||
|
||||
/datum/ntnet/proc/find_service_path(path)
|
||||
return services_by_path[path]
|
||||
|
||||
/datum/ntnet/proc/register_service(datum/ntnet_service/S)
|
||||
if(!istype(S))
|
||||
return FALSE
|
||||
if(services_by_path[S.type] || services_by_id[S.id])
|
||||
return FALSE
|
||||
services_by_path[S.type] = S
|
||||
services_by_id[S.id] = S
|
||||
return TRUE
|
||||
|
||||
/datum/ntnet/proc/unregister_service(datum/ntnet_service/S)
|
||||
if(!istype(S))
|
||||
return FALSE
|
||||
services_by_path -= S.type
|
||||
services_by_id -= S.id
|
||||
return TRUE
|
||||
|
||||
/datum/ntnet/proc/create_service(type)
|
||||
var/datum/ntnet_service/S = new type
|
||||
if(!istype(S))
|
||||
return FALSE
|
||||
. = S.connect(src)
|
||||
if(!.)
|
||||
qdel(S)
|
||||
|
||||
/datum/ntnet/proc/destroy_service(type)
|
||||
var/datum/ntnet_service/S = find_service_path(type)
|
||||
if(!istype(S))
|
||||
return FALSE
|
||||
. = S.disconnect(src)
|
||||
if(.)
|
||||
qdel(src)
|
||||
|
||||
/datum/ntnet/proc/process_data_transmit(datum/component/ntnet_interface/sender, datum/netdata/data)
|
||||
data.network_id = src
|
||||
log_data_transfer(data)
|
||||
if(!check_relay_operation())
|
||||
return FALSE
|
||||
for(var/i in data.recipient_ids)
|
||||
var/datum/component/ntnet_interface/reciever = find_interface_id(i)
|
||||
data.network_id = src
|
||||
log_data_transfer(data)
|
||||
var/list/datum/component/ntnet_interface/recieving = list()
|
||||
if((length(data.recipient_ids == 1) && data.recipient_ids[1] == NETWORK_BROADCAST_ID) || data.recipient_ids == NETWORK_BROADCAST_ID)
|
||||
data.broadcast = TRUE
|
||||
for(var/i in connected_interfaces_by_id)
|
||||
recieving |= connected_interfaces_by_id[i]
|
||||
else
|
||||
for(var/i in data.recipient_ids)
|
||||
var/datum/component/ntnet_interface/reciever = find_interface_id(i)
|
||||
recieving |= reciever
|
||||
|
||||
for(var/i in recieving)
|
||||
var/datum/component/ntnet_interface/reciever = i
|
||||
if(reciever)
|
||||
reciever.__network_recieve(data)
|
||||
|
||||
for(var/i in services_by_id)
|
||||
var/datum/ntnet_service/serv = services_by_id[i]
|
||||
serv.ntnet_intercept(data, src, sender)
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/ntnet/proc/check_relay_operation(zlevel) //can be expanded later but right now it's true/false.
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/datum/ntnet_service
|
||||
var/name = "Unidentified Network Service"
|
||||
var/id
|
||||
var/list/networks_by_id = list() //Yes we support multinetwork services!
|
||||
|
||||
/datum/ntnet_service/New()
|
||||
var/datum/component/ntnet_interface/N = AddComponent(/datum/component/ntnet_interface, id, name, FALSE)
|
||||
id = N.hardware_id
|
||||
|
||||
/datum/ntnet_service/Destroy()
|
||||
for(var/i in networks_by_id)
|
||||
var/datum/ntnet/N = i
|
||||
disconnect(N, TRUE)
|
||||
networks_by_id = null
|
||||
return ..()
|
||||
|
||||
/datum/ntnet_service/proc/connect(datum/ntnet/net)
|
||||
if(!istype(net))
|
||||
return FALSE
|
||||
GET_COMPONENT(interface, /datum/component/ntnet_interface)
|
||||
if(!interface.register_connection(net))
|
||||
return FALSE
|
||||
if(!net.register_service(src))
|
||||
interface.unregister_connection(net)
|
||||
return FALSE
|
||||
networks_by_id[net.network_id] = net
|
||||
return TRUE
|
||||
|
||||
/datum/ntnet_service/proc/disconnect(datum/ntnet/net, force = FALSE)
|
||||
if(!istype(net) || (!net.unregister_service(src) && !force))
|
||||
return FALSE
|
||||
GET_COMPONENT(interface, /datum/component/ntnet_interface)
|
||||
interface.unregister_connection(net)
|
||||
networks_by_id -= net.network_id
|
||||
return TRUE
|
||||
|
||||
/datum/ntnet_service/proc/ntnet_intercept(datum/netdata/data, datum/ntnet/net, datum/component/ntnet_interface/sender)
|
||||
return
|
||||
@@ -39,7 +39,7 @@
|
||||
return list("reason"="guest", "desc"="\nReason: Guests not allowed. Please sign in with a byond account.")
|
||||
if (CONFIG_GET(flag/panic_bunker) && SSdbcore.Connect())
|
||||
log_access("Failed Login: [key] - Guests not allowed during panic bunker")
|
||||
return list("reason"="guest", "desc"="\nReason: You must first join the Discord to verify your account before joining this server. Please ping an admin once you've joined and read the rules. https://discord.gg/E6SQuhz")
|
||||
return list("reason"="guest", "desc"="\nReason: You must first sign into your BYOND account or join the Discord to verify your account before joining this server. Please ping an admin once you've joined and read the rules. https://discord.gg/E6SQuhz")
|
||||
|
||||
//Population Cap Checking
|
||||
var/extreme_popcap = CONFIG_GET(number/extreme_popcap)
|
||||
|
||||
@@ -434,7 +434,7 @@
|
||||
return
|
||||
|
||||
var/list/options = list("Regular Restart", "Hard Restart (No Delay/Feeback Reason)", "Hardest Restart (No actions, just reboot)")
|
||||
if(SERVER_TOOLS_PRESENT)
|
||||
if(world.TgsAvailable())
|
||||
options += "Server Restart (Kill and restart DD)";
|
||||
|
||||
var/rebootconfirm
|
||||
@@ -459,7 +459,7 @@
|
||||
world.Reboot(fast_track = TRUE)
|
||||
if("Server Restart (Kill and restart DD)")
|
||||
to_chat(world, "Server restart - [init_by]")
|
||||
SERVER_TOOLS_REBOOT_BYOND
|
||||
world.TgsEndProcess()
|
||||
|
||||
/datum/admins/proc/end_round()
|
||||
set category = "Server"
|
||||
|
||||
@@ -242,7 +242,6 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
var/skip
|
||||
if(rank_names[admin_rank] == null)
|
||||
message_admins("[admin_ckey] loaded with invalid admin rank [admin_rank].")
|
||||
log_sql("[admin_ckey] loaded with invalid admin rank [admin_rank].")
|
||||
skip = 1
|
||||
if(GLOB.admin_datums[admin_ckey] || GLOB.deadmins[admin_ckey])
|
||||
skip = 1
|
||||
|
||||
@@ -93,6 +93,7 @@ GLOBAL_LIST_INIT(admin_verbs_fun, list(
|
||||
/client/proc/forceEvent,
|
||||
/client/proc/admin_change_sec_level,
|
||||
/client/proc/toggle_nuke,
|
||||
/client/proc/run_weather,
|
||||
/client/proc/mass_zombie_infection,
|
||||
/client/proc/mass_zombie_cure,
|
||||
/client/proc/polymorph_all,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#define IRC_STATUS_THROTTLE 5
|
||||
|
||||
/datum/server_tools_command/ircstatus
|
||||
/datum/tgs_chat_command/ircstatus
|
||||
name = "status"
|
||||
help_text = "Gets the admincount, playercount, gamemode, and true game mode of the server"
|
||||
admin_only = TRUE
|
||||
var/static/last_irc_status = 0
|
||||
var/last_irc_status = 0
|
||||
|
||||
/datum/server_tools_command/ircstatus/Run(sender, params)
|
||||
/datum/tgs_chat_command/ircstatus/Run(datum/tgs_chat_user/sender, params)
|
||||
var/rtod = REALTIMEOFDAY
|
||||
if(rtod - last_irc_status < IRC_STATUS_THROTTLE)
|
||||
return
|
||||
@@ -17,12 +17,12 @@
|
||||
status += "Players: [GLOB.clients.len] (Active: [get_active_player_count(0,1,0)]). Mode: [SSticker.mode ? SSticker.mode.name : "Not started"]."
|
||||
return status
|
||||
|
||||
/datum/server_tools_command/irccheck
|
||||
/datum/tgs_chat_command/irccheck
|
||||
name = "check"
|
||||
help_text = "Gets the playercount, gamemode, and address of the server"
|
||||
var/static/last_irc_check = 0
|
||||
var/last_irc_check = 0
|
||||
|
||||
/datum/server_tools_command/irccheck/Run(sender, params)
|
||||
/datum/tgs_chat_command/irccheck/Run(datum/tgs_chat_user/sender, params)
|
||||
var/rtod = REALTIMEOFDAY
|
||||
if(rtod - last_irc_check < IRC_STATUS_THROTTLE)
|
||||
return
|
||||
@@ -30,14 +30,15 @@
|
||||
var/server = CONFIG_GET(string/server)
|
||||
return "[GLOB.round_id ? "Round #[GLOB.round_id]: " : ""][GLOB.clients.len] players on [SSmapping.config.map_name]; Round [SSticker.HasRoundStarted() ? (SSticker.IsRoundInProgress() ? "Active" : "Finishing") : "Starting"] -- [server ? server : "[world.internet_address]:[world.port]"]" //CIT CHANGE - obfuscates the current gamemode from players
|
||||
|
||||
/datum/server_tools_command/ahelp
|
||||
/datum/tgs_chat_command/ahelp
|
||||
name = "ahelp"
|
||||
help_text = "<ckey|ticket #> <message|ticket <close|resolve|icissue|reject|reopen <ticket #>|list>>"
|
||||
required_parameters = 2
|
||||
admin_only = TRUE
|
||||
|
||||
/datum/server_tools_command/ahelp/Run(sender, params)
|
||||
/datum/tgs_chat_command/ahelp/Run(datum/tgs_chat_user/sender, params)
|
||||
var/list/all_params = splittext(params, " ")
|
||||
if(all_params.len < 2)
|
||||
return "Insufficient parameters"
|
||||
var/target = all_params[1]
|
||||
all_params.Cut(1, 2)
|
||||
var/id = text2num(target)
|
||||
@@ -47,52 +48,54 @@
|
||||
target = AH.initiator_ckey
|
||||
else
|
||||
return "Ticket #[id] not found!"
|
||||
var/res = IrcPm(target, all_params.Join(" "), sender)
|
||||
var/res = IrcPm(target, all_params.Join(" "), sender.friendly_name)
|
||||
if(res != "Message Successful")
|
||||
return res
|
||||
|
||||
/datum/server_tools_command/namecheck
|
||||
/datum/tgs_chat_command/namecheck
|
||||
name = "namecheck"
|
||||
help_text = "Returns info on the specified target"
|
||||
required_parameters = 1
|
||||
admin_only = TRUE
|
||||
|
||||
/datum/server_tools_command/namecheck/Run(sender, params)
|
||||
log_admin("Chat Name Check: [sender] on [params]")
|
||||
message_admins("Name checking [params] from [sender]")
|
||||
/datum/tgs_chat_command/namecheck/Run(datum/tgs_chat_user/sender, params)
|
||||
params = trim(params)
|
||||
if(!params)
|
||||
return "Insufficient parameters"
|
||||
log_admin("Chat Name Check: [sender.friendly_name] on [params]")
|
||||
message_admins("Name checking [params] from [sender.friendly_name]")
|
||||
return keywords_lookup(params, 1)
|
||||
|
||||
/datum/server_tools_command/adminwho
|
||||
/datum/tgs_chat_command/adminwho
|
||||
name = "adminwho"
|
||||
help_text = "Lists administrators currently on the server"
|
||||
admin_only = TRUE
|
||||
|
||||
/datum/server_tools_command/adminwho/Run(sender, params)
|
||||
/datum/tgs_chat_command/adminwho/Run(datum/tgs_chat_user/sender, params)
|
||||
return ircadminwho()
|
||||
|
||||
GLOBAL_LIST(round_end_notifiees)
|
||||
|
||||
/datum/server_tools_command/notify
|
||||
/datum/tgs_chat_command/notify
|
||||
name = "notify"
|
||||
help_text = "Pings the invoker when the round ends"
|
||||
admin_only = TRUE
|
||||
|
||||
/datum/server_tools_command/notify/Run(sender, params)
|
||||
/datum/tgs_chat_command/notify/Run(datum/tgs_chat_user/sender, params)
|
||||
if(!SSticker.IsRoundInProgress() && SSticker.HasRoundStarted())
|
||||
return "[sender], the round has already ended!"
|
||||
return "[sender.mention], the round has already ended!"
|
||||
LAZYINITLIST(GLOB.round_end_notifiees)
|
||||
GLOB.round_end_notifiees[sender] = TRUE
|
||||
return "I will notify [sender] when the round ends."
|
||||
return "I will notify [sender.mention] when the round ends."
|
||||
|
||||
/datum/server_tools_command/sdql
|
||||
/datum/tgs_chat_command/sdql
|
||||
name = "sdql"
|
||||
help_text = "Runs an SDQL query"
|
||||
admin_only = TRUE
|
||||
|
||||
/datum/server_tools_command/sdql/Run(sender, params)
|
||||
/datum/tgs_chat_command/sdql/Run(datum/tgs_chat_user/sender, params)
|
||||
if(GLOB.AdminProcCaller)
|
||||
return "Unable to run query, another admin proc call is in progress. Try again later."
|
||||
GLOB.AdminProcCaller = "CHAT_[sender]" //_ won't show up in ckeys so it'll never match with a real admin
|
||||
GLOB.AdminProcCaller = "CHAT_[sender.friendly_name]" //_ won't show up in ckeys so it'll never match with a real admin
|
||||
var/list/results = world.SDQL2_query(params, GLOB.AdminProcCaller, GLOB.AdminProcCaller)
|
||||
GLOB.AdminProcCaller = null
|
||||
if(!results)
|
||||
@@ -100,13 +103,13 @@ GLOBAL_LIST(round_end_notifiees)
|
||||
var/list/text_res = results.Copy(1, 3)
|
||||
var/list/refs = results.len > 3 ? results.Copy(4) : null
|
||||
. = "[text_res.Join("\n")][refs ? "\nRefs: [refs.Join(" ")]" : ""]"
|
||||
|
||||
/datum/server_tools_command/reload_admins
|
||||
|
||||
/datum/tgs_chat_command/reload_admins
|
||||
name = "reload_admins"
|
||||
help_text = "Forces the server to reload admins."
|
||||
admin_only = TRUE
|
||||
|
||||
/datum/server_tools_command/reload_admins/Run(sender, params)
|
||||
/datum/tgs_chat_command/reload_admins/Run(datum/tgs_chat_user/sender, params)
|
||||
load_admins()
|
||||
log_admin("[sender] reloaded admins via chat command.")
|
||||
log_admin("[sender.friendly_name] reloaded admins via chat command.")
|
||||
return "Admins reloaded."
|
||||
|
||||
@@ -22,6 +22,17 @@
|
||||
H.facial_hair_color = H.hair_color
|
||||
H.eye_color = random_eye_color()
|
||||
H.dna.blood_type = random_blood_type()
|
||||
|
||||
// Mutant randomizing, doesn't affect the mob appearance unless it's the specific mutant.
|
||||
H.dna.features["mcolor"] = random_short_color()
|
||||
H.dna.features["tail_lizard"] = pick(GLOB.tails_list_lizard)
|
||||
H.dna.features["snout"] = pick(GLOB.snouts_list)
|
||||
H.dna.features["horns"] = pick(GLOB.horns_list)
|
||||
H.dna.features["frills"] = pick(GLOB.frills_list)
|
||||
H.dna.features["spines"] = pick(GLOB.spines_list)
|
||||
H.dna.features["body_markings"] = pick(GLOB.body_markings_list)
|
||||
H.dna.features["moth_wings"] = pick(GLOB.moth_wings_list)
|
||||
|
||||
H.update_body()
|
||||
H.update_hair()
|
||||
H.update_body_parts()
|
||||
@@ -16,7 +16,7 @@
|
||||
/datum/admins/proc/quick_create_object(mob/user)
|
||||
var/static/list/create_object_forms = list(
|
||||
/obj, /obj/structure, /obj/machinery, /obj/effect,
|
||||
/obj/item, /obj/item/clothing, /obj/item/stack, /obj/item/device,
|
||||
/obj/item, /obj/item/clothing, /obj/item/stack, /obj/item,
|
||||
/obj/item/reagent_containers, /obj/item/gun)
|
||||
|
||||
var/path = input("Select the path of the object you wish to create.", "Path", /obj) in create_object_forms
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
if(!option)
|
||||
return
|
||||
option = sanitizeSQL(option)
|
||||
var/default_percentage_calc
|
||||
var/default_percentage_calc = 0
|
||||
if(polltype != POLLTYPE_IRV)
|
||||
switch(alert("Should this option be included by default when poll result percentages are generated?",,"Yes","No","Cancel"))
|
||||
if("Yes")
|
||||
|
||||
@@ -6,56 +6,106 @@
|
||||
return
|
||||
usr.client.holder.edit_admin_permissions()
|
||||
|
||||
/datum/admins/proc/edit_admin_permissions()
|
||||
/datum/admins/proc/edit_admin_permissions(action, target, operation, page)
|
||||
if(!check_rights(R_PERMISSIONS))
|
||||
return
|
||||
|
||||
var/list/output = list({"<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Permissions Panel</title>
|
||||
<script type='text/javascript' src='search.js'></script>
|
||||
<link rel='stylesheet' type='text/css' href='panels.css'>
|
||||
</head>
|
||||
<body onload='selectTextField();updateSearch();'>
|
||||
<div id='main'><table id='searchable' cellspacing='0'>
|
||||
<tr class='title'>
|
||||
<th style='width:150px;text-align:right;'>CKEY <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=add'>\[+\]</a></th>
|
||||
<th style='width:125px;'>RANK</th>
|
||||
<th style='width:40%;'>PERMISSIONS</th>
|
||||
<th style='width:20%;'>DENIED</th>
|
||||
<th style='width:40%;'>ALLOWED TO EDIT</th>
|
||||
</tr>
|
||||
"})
|
||||
|
||||
for(var/adm_ckey in GLOB.admin_datums+GLOB.deadmins)
|
||||
var/datum/admins/D = GLOB.admin_datums[adm_ckey]
|
||||
if(!D)
|
||||
D = GLOB.deadmins[adm_ckey]
|
||||
if (!D)
|
||||
continue
|
||||
|
||||
var/deadminlink = ""
|
||||
if (D.deadmined)
|
||||
deadminlink = " <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=activate;ckey=[adm_ckey]'>\[RA\]</a>"
|
||||
else
|
||||
deadminlink = " <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=deactivate;ckey=[adm_ckey]'>\[DA\]</a>"
|
||||
|
||||
output += "<tr>"
|
||||
output += "<td style='text-align:center;'>[adm_ckey]<br>[deadminlink]<a class='small' href='?src=[REF(src)];[HrefToken()];editrights=remove;ckey=[adm_ckey]'>\[-\]</a><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=sync;ckey=[adm_ckey]'>\[SYNC TGDB\]</a></td>"
|
||||
output += "<td><a href='?src=[REF(src)];[HrefToken()];editrights=rank;ckey=[adm_ckey]'>[D.rank.name]</a></td>"
|
||||
output += "<td><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=permissions;ckey=[adm_ckey]'>[rights2text(D.rank.include_rights," ")]</a></td>"
|
||||
output += "<td><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=permissions;ckey=[adm_ckey]'>[rights2text(D.rank.exclude_rights," ", "-")]</a></td>"
|
||||
output += "<td><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=permissions;ckey=[adm_ckey]'>[rights2text(D.rank.can_edit_rights," ", "*")]</a></td>"
|
||||
output += "</tr>"
|
||||
|
||||
output += {"
|
||||
</table></div>
|
||||
<div id='top'><b>Search:</b> <input type='text' id='filter' value='' style='width:70%;' onkeyup='updateSearch();'></div>
|
||||
</body>
|
||||
</html>"}
|
||||
|
||||
usr << browse(jointext(output, ""),"window=editrights;size=1000x650")
|
||||
var/list/output = list("<link rel='stylesheet' type='text/css' href='panels.css'><a href='?_src_=holder;[HrefToken()];editrightsbrowser=1'>\[Permissions\]</a>")
|
||||
if(action)
|
||||
output += " | <a href='?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightspage=0'>\[Log\]</a> | <a href='?_src_=holder;[HrefToken()];editrightsbrowsermanage=1'>\[Management\]</a><hr style='background:#000000; border:0; height:3px'>"
|
||||
else
|
||||
output += "<br><a href='?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightspage=0'>\[Log\]</a><br><a href='?_src_=holder;[HrefToken()];editrightsbrowsermanage=1'>\[Management\]</a>"
|
||||
if(action == 1)
|
||||
var/list/searchlist = list(" WHERE ")
|
||||
if(target)
|
||||
searchlist += "ckey = '[sanitizeSQL(target)]'"
|
||||
if(operation)
|
||||
if(target)
|
||||
searchlist += " AND "
|
||||
searchlist += "operation = '[sanitizeSQL(operation)]'"
|
||||
var/search
|
||||
if(searchlist.len > 1)
|
||||
search = searchlist.Join("")
|
||||
var/logcount = 0
|
||||
var/logssperpage = 20
|
||||
var/pagecount = 0
|
||||
page = text2num(page)
|
||||
var/datum/DBQuery/query_count_admin_logs = SSdbcore.NewQuery("SELECT COUNT(id) FROM [format_table_name("admin_log")][search]")
|
||||
if(!query_count_admin_logs.warn_execute())
|
||||
return
|
||||
if(query_count_admin_logs.NextRow())
|
||||
logcount = text2num(query_count_admin_logs.item[1])
|
||||
if(logcount > logssperpage)
|
||||
output += "<br><b>Page: </b>"
|
||||
while(logcount > 0)
|
||||
output += "|<a href='?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightstarget=[target];editrightsoperation=[operation];editrightspage=[pagecount]'>[pagecount == page ? "<b>\[[pagecount]\]</b>" : "\[[pagecount]\]"]</a>"
|
||||
logcount -= logssperpage
|
||||
pagecount++
|
||||
output += "|"
|
||||
var/limit = " LIMIT [logssperpage * page], [logssperpage]"
|
||||
var/datum/DBQuery/query_search_admin_logs = SSdbcore.NewQuery("SELECT datetime, round_id, adminckey, operation, target, log FROM [format_table_name("admin_log")][search] ORDER BY datetime DESC[limit]")
|
||||
if(!query_search_admin_logs.warn_execute())
|
||||
return
|
||||
while(query_search_admin_logs.NextRow())
|
||||
var/datetime = query_search_admin_logs.item[1]
|
||||
var/round_id = query_search_admin_logs.item[2]
|
||||
var/admin_ckey = query_search_admin_logs.item[3]
|
||||
operation = query_search_admin_logs.item[4]
|
||||
target = query_search_admin_logs.item[5]
|
||||
var/log = query_search_admin_logs.item[6]
|
||||
output += "<p style='margin:0px'><b>[datetime] | Round ID [round_id] | Admin [admin_ckey] | Operation [operation] on [target]</b><br>[log]</p><hr style='background:#000000; border:0; height:3px'>"
|
||||
if(action == 2)
|
||||
output += "<h3>Admin ckeys with invalid ranks</h3>"
|
||||
var/datum/DBQuery/query_check_admin_errors = SSdbcore.NewQuery("SELECT ckey, [format_table_name("admin")].rank FROM [format_table_name("admin")] LEFT JOIN [format_table_name("admin_ranks")] ON [format_table_name("admin_ranks")].rank = [format_table_name("admin")].rank WHERE [format_table_name("admin_ranks")].rank IS NULL")
|
||||
if(!query_check_admin_errors.warn_execute())
|
||||
return
|
||||
while(query_check_admin_errors.NextRow())
|
||||
var/admin_ckey = query_check_admin_errors.item[1]
|
||||
var/admin_rank = query_check_admin_errors.item[2]
|
||||
output += "[admin_ckey] has non-existant rank [admin_rank] | <a href='?_src_=holder;[HrefToken()];editrightsbrowsermanage=1;editrightschange=[admin_ckey]'>\[Change Rank\]</a> | <a href='?_src_=holder;[HrefToken()];editrightsbrowsermanage=1;editrightsremove=[admin_ckey]'>\[Remove\]</a>"
|
||||
output += "<hr style='background:#000000; border:0; height:1px'>"
|
||||
output += "<h3>Unused ranks</h3>"
|
||||
var/datum/DBQuery/query_check_unused_rank = SSdbcore.NewQuery("SELECT [format_table_name("admin_ranks")].rank FROM [format_table_name("admin_ranks")] LEFT JOIN [format_table_name("admin")] ON [format_table_name("admin")].rank = [format_table_name("admin_ranks")].rank WHERE [format_table_name("admin")].rank IS NULL")
|
||||
if(!query_check_unused_rank.warn_execute())
|
||||
return
|
||||
while(query_check_unused_rank.NextRow())
|
||||
var/admin_rank = query_check_unused_rank.item[1]
|
||||
output += "Rank [admin_rank] is not held by any admin | <a href='?_src_=holder;[HrefToken()];editrightsbrowsermanage=1;editrightsremoverank=[admin_rank]'>\[Remove\]</a>"
|
||||
output += "<hr style='background:#000000; border:0; height:1px'>"
|
||||
else if(!action)
|
||||
output += {"<head>
|
||||
<title>Permissions Panel</title>
|
||||
<script type='text/javascript' src='search.js'></script>
|
||||
</head>
|
||||
<body onload='selectTextField();updateSearch();'>
|
||||
<div id='main'><table id='searchable' cellspacing='0'>
|
||||
<tr class='title'>
|
||||
<th style='width:150px;'>CKEY <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=add'>\[+\]</a></th>
|
||||
<th style='width:125px;'>RANK</th>
|
||||
<th style='width:40%;'>PERMISSIONS</th>
|
||||
<th style='width:20%;'>DENIED</th>
|
||||
<th style='width:40%;'>ALLOWED TO EDIT</th>
|
||||
</tr>
|
||||
"}
|
||||
for(var/adm_ckey in GLOB.admin_datums+GLOB.deadmins)
|
||||
var/datum/admins/D = GLOB.admin_datums[adm_ckey]
|
||||
if(!D)
|
||||
D = GLOB.deadmins[adm_ckey]
|
||||
if (!D)
|
||||
continue
|
||||
var/deadminlink = ""
|
||||
if (D.deadmined)
|
||||
deadminlink = " <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=activate;ckey=[adm_ckey]'>\[RA\]</a>"
|
||||
else
|
||||
deadminlink = " <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=deactivate;ckey=[adm_ckey]'>\[DA\]</a>"
|
||||
output += "<tr>"
|
||||
output += "<td style='text-align:center;'>[adm_ckey]<br>[deadminlink]<a class='small' href='?src=[REF(src)];[HrefToken()];editrights=remove;ckey=[adm_ckey]'>\[-\]</a><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=sync;ckey=[adm_ckey]'>\[SYNC TGDB\]</a></td>"
|
||||
output += "<td><a href='?src=[REF(src)];[HrefToken()];editrights=rank;ckey=[adm_ckey]'>[D.rank.name]</a></td>"
|
||||
output += "<td><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=permissions;ckey=[adm_ckey]'>[rights2text(D.rank.include_rights," ")]</a></td>"
|
||||
output += "<td><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=permissions;ckey=[adm_ckey]'>[rights2text(D.rank.exclude_rights," ", "-")]</a></td>"
|
||||
output += "<td><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=permissions;ckey=[adm_ckey]'>[rights2text(D.rank.can_edit_rights," ", "*")]</a></td>"
|
||||
output += "</tr>"
|
||||
output += "</table></div><div id='top'><b>Search:</b> <input type='text' id='filter' value='' style='width:70%;' onkeyup='updateSearch();'></div></body>"
|
||||
usr << browse("<!DOCTYPE html><html>[jointext(output, "")]</html>","window=editrights;size=1000x650")
|
||||
|
||||
/datum/admins/proc/edit_rights_topic(list/href_list)
|
||||
if(!check_rights(R_PERMISSIONS))
|
||||
@@ -142,10 +192,17 @@
|
||||
return FALSE
|
||||
if(use_db)
|
||||
. = sanitizeSQL(.)
|
||||
//if an admin exists without a datum they won't be caught by the above
|
||||
var/datum/DBQuery/query_admin_in_db = SSdbcore.NewQuery("SELECT 1 FROM [format_table_name("admin_ranks")] WHERE ckey = '[.]'")
|
||||
if(!query_admin_in_db.warn_execute())
|
||||
return FALSE
|
||||
if(query_admin_in_db.NextRow())
|
||||
to_chat(usr, "<span class='danger'>[.] already listed in admin database. Check the Management tab if they don't appear in the list of admins.</span>")
|
||||
return FALSE
|
||||
var/datum/DBQuery/query_add_admin = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin")] (ckey, rank) VALUES ('[.]', 'NEW ADMIN')")
|
||||
if(!query_add_admin.warn_execute())
|
||||
return FALSE
|
||||
var/datum/DBQuery/query_add_admin_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, adminckey, adminip, operation, log) VALUES ('[SQLtime()]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'add admin', 'New admin added: [.]')")
|
||||
var/datum/DBQuery/query_add_admin_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'add admin', '[.]', 'New admin added: [.]')")
|
||||
if(!query_add_admin_log.warn_execute())
|
||||
return FALSE
|
||||
|
||||
@@ -153,12 +210,13 @@
|
||||
if(alert("Are you sure you want to remove [admin_ckey]?","Confirm Removal","Do it","Cancel") == "Do it")
|
||||
GLOB.admin_datums -= admin_ckey
|
||||
GLOB.deadmins -= admin_ckey
|
||||
D.disassociate()
|
||||
if(D)
|
||||
D.disassociate()
|
||||
if(use_db)
|
||||
var/datum/DBQuery/query_add_rank = SSdbcore.NewQuery("DELETE FROM [format_table_name("admin")] WHERE ckey = '[admin_ckey]'")
|
||||
if(!query_add_rank.warn_execute())
|
||||
return
|
||||
var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, adminckey, adminip, operation, log) VALUES ('[SQLtime()]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'remove admin', 'Admin removed: [admin_ckey]')")
|
||||
var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'remove admin', '[admin_ckey]', 'Admin removed: [admin_ckey]')")
|
||||
if(!query_add_rank_log.warn_execute())
|
||||
return
|
||||
message_admins("[key_name_admin(usr)] removed [admin_ckey] from the admins list [use_db ? "permanently" : "temporarily"]")
|
||||
@@ -216,13 +274,13 @@
|
||||
var/datum/DBQuery/query_add_rank = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_ranks")] (rank, flags, exclude_flags, can_edit_flags) VALUES ('[new_rank]', '0', '0', '0')")
|
||||
if(!query_add_rank.warn_execute())
|
||||
return
|
||||
var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, adminckey, adminip, operation, log) VALUES ('[SQLtime()]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'add rank', 'New rank added: [admin_ckey]')")
|
||||
var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'add rank', '[new_rank]', 'New rank added: [new_rank]')")
|
||||
if(!query_add_rank_log.warn_execute())
|
||||
return
|
||||
var/datum/DBQuery/query_change_rank = SSdbcore.NewQuery("UPDATE [format_table_name("admin")] SET rank = '[new_rank]' WHERE ckey = '[admin_ckey]'")
|
||||
if(!query_change_rank.warn_execute())
|
||||
return
|
||||
var/datum/DBQuery/query_change_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, adminckey, adminip, operation, log) VALUES ('[SQLtime()]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'change admin rank', 'Rank of [admin_ckey] changed from [old_rank] to [new_rank]')")
|
||||
var/datum/DBQuery/query_change_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'change admin rank', '[admin_ckey]', 'Rank of [admin_ckey] changed from [old_rank] to [new_rank]')")
|
||||
if(!query_change_rank_log.warn_execute())
|
||||
return
|
||||
if(D) //they were previously an admin
|
||||
@@ -259,7 +317,7 @@
|
||||
var/datum/DBQuery/query_change_rank_flags = SSdbcore.NewQuery("UPDATE [format_table_name("admin_ranks")] SET flags = '[new_flags]', exclude_flags = '[new_exclude_flags]', can_edit_flags = '[new_can_edit_flags]' WHERE rank = '[D.rank.name]'")
|
||||
if(!query_change_rank_flags.warn_execute())
|
||||
return
|
||||
var/datum/DBQuery/query_change_rank_flags_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, adminckey, adminip, operation, log) VALUES ('[SQLtime()]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'change rank flags', 'Permissions of [admin_ckey] changed from[rights2text(old_flags," ")][rights2text(old_exclude_flags," ", "-")][rights2text(old_can_edit_flags," ", "*")] to[rights2text(new_flags," ")][rights2text(new_exclude_flags," ", "-")][rights2text(new_can_edit_flags," ", "*")]')")
|
||||
var/datum/DBQuery/query_change_rank_flags_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'change rank flags', '[D.rank.name]', 'Permissions of [D.rank.name] changed from[rights2text(old_flags," ")][rights2text(old_exclude_flags," ", "-")][rights2text(old_can_edit_flags," ", "*")] to[rights2text(new_flags," ")][rights2text(new_exclude_flags," ", "-")][rights2text(new_can_edit_flags," ", "*")]')")
|
||||
if(!query_change_rank_flags_log.warn_execute())
|
||||
return
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
@@ -294,6 +352,36 @@
|
||||
message_admins("[key_name_admin(usr)] edited the permissions of [use_db ? " rank [D.rank.name] permanently" : "[admin_ckey] temporarily"]")
|
||||
log_admin("[key_name(usr)] edited the permissions of [use_db ? " rank [D.rank.name] permanently" : "[admin_ckey] temporarily"]")
|
||||
|
||||
/datum/admins/proc/remove_rank(admin_rank)
|
||||
if(!admin_rank)
|
||||
return
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
if(R.name == admin_rank && (!(R.rights & usr.client.holder.rank.can_edit_rights) == R.rights))
|
||||
to_chat(usr, "<span class='admin prefix'>You don't have edit rights to all the rights this rank has, rank deletion not permitted.</span>")
|
||||
return
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) && CONFIG_GET(flag/protect_legacy_ranks) && (admin_rank in GLOB.protected_ranks))
|
||||
to_chat(usr, "<span class='admin prefix'>Deletion of protected ranks is not permitted, it must be removed from admin_ranks.txt.</span>")
|
||||
return
|
||||
if(CONFIG_GET(flag/load_legacy_ranks_only))
|
||||
to_chat(usr, "<span class='admin prefix'>Rank deletion not permitted while database rank loading is disabled.</span>")
|
||||
return
|
||||
admin_rank = sanitizeSQL(admin_rank)
|
||||
var/datum/DBQuery/query_admins_with_rank = SSdbcore.NewQuery("SELECT 1 FROM [format_table_name("admin")] WHERE rank = '[admin_rank]'")
|
||||
if(!query_admins_with_rank.warn_execute())
|
||||
return
|
||||
if(query_admins_with_rank.NextRow())
|
||||
to_chat(usr, "<span class='danger'>Error: Rank deletion attempted while rank still used; Tell a coder, this shouldn't happen.</span>")
|
||||
return
|
||||
if(alert("Are you sure you want to remove [admin_rank]?","Confirm Removal","Do it","Cancel") == "Do it")
|
||||
var/datum/DBQuery/query_add_rank = SSdbcore.NewQuery("DELETE FROM [format_table_name("admin_ranks")] WHERE rank = '[admin_rank]'")
|
||||
if(!query_add_rank.warn_execute())
|
||||
return
|
||||
var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'remove rank', '[admin_rank]', 'Rank removed: [admin_rank]')")
|
||||
if(!query_add_rank_log.warn_execute())
|
||||
return
|
||||
message_admins("[key_name_admin(usr)] removed rank [admin_rank] permanently")
|
||||
log_admin("[key_name(usr)] removed rank [admin_rank] permanently")
|
||||
|
||||
/datum/admins/proc/sync_lastadminrank(admin_ckey, datum/admins/D)
|
||||
var/sqlrank = sanitizeSQL(D.rank.name)
|
||||
admin_ckey = sanitizeSQL(admin_ckey)
|
||||
|
||||
@@ -430,7 +430,7 @@
|
||||
var/obj/item/clothing/under/schoolgirl/I = new seifuku
|
||||
var/olduniform = H.w_uniform
|
||||
H.temporarilyRemoveItemFromInventory(H.w_uniform, TRUE, FALSE)
|
||||
H.equip_to_slot_or_del(I, slot_w_uniform)
|
||||
H.equip_to_slot_or_del(I, SLOT_W_UNIFORM)
|
||||
qdel(olduniform)
|
||||
if(droptype == "Yes")
|
||||
I.flags_1 |= NODROP_1
|
||||
|
||||
@@ -273,6 +273,21 @@
|
||||
return
|
||||
create_message("note", banckey, null, banreason, null, null, 0, 0)
|
||||
|
||||
else if(href_list["editrightsbrowser"])
|
||||
edit_admin_permissions(0)
|
||||
|
||||
else if(href_list["editrightsbrowserlog"])
|
||||
edit_admin_permissions(1, href_list["editrightstarget"], href_list["editrightsoperation"], href_list["editrightspage"])
|
||||
|
||||
if(href_list["editrightsbrowsermanage"])
|
||||
if(href_list["editrightschange"])
|
||||
change_admin_rank(href_list["editrightschange"], TRUE)
|
||||
else if(href_list["editrightsremove"])
|
||||
remove_admin(href_list["editrightsremove"], TRUE)
|
||||
else if(href_list["editrightsremoverank"])
|
||||
remove_rank(href_list["editrightsremoverank"])
|
||||
edit_admin_permissions(2)
|
||||
|
||||
else if(href_list["editrights"])
|
||||
edit_rights_topic(href_list)
|
||||
|
||||
@@ -1493,8 +1508,8 @@
|
||||
|
||||
if(ishuman(L))
|
||||
var/mob/living/carbon/human/observer = L
|
||||
observer.equip_to_slot_or_del(new /obj/item/clothing/under/suit_jacket(observer), slot_w_uniform)
|
||||
observer.equip_to_slot_or_del(new /obj/item/clothing/shoes/sneakers/black(observer), slot_shoes)
|
||||
observer.equip_to_slot_or_del(new /obj/item/clothing/under/suit_jacket(observer), SLOT_W_UNIFORM)
|
||||
observer.equip_to_slot_or_del(new /obj/item/clothing/shoes/sneakers/black(observer), SLOT_SHOES)
|
||||
L.Unconscious(100)
|
||||
sleep(5)
|
||||
L.forceMove(pick(GLOB.tdomeobserve))
|
||||
@@ -1804,7 +1819,7 @@
|
||||
if(!istype(H))
|
||||
to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
|
||||
return
|
||||
if(!istype(H.ears, /obj/item/device/radio/headset))
|
||||
if(!istype(H.ears, /obj/item/radio/headset))
|
||||
to_chat(usr, "The person you are trying to contact is not wearing a headset.")
|
||||
return
|
||||
|
||||
@@ -1823,7 +1838,7 @@
|
||||
if(!istype(H))
|
||||
to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human.")
|
||||
return
|
||||
if(!istype(H.ears, /obj/item/device/radio/headset))
|
||||
if(!istype(H.ears, /obj/item/radio/headset))
|
||||
to_chat(usr, "The person you are trying to contact is not wearing a headset.")
|
||||
return
|
||||
|
||||
@@ -2448,6 +2463,19 @@
|
||||
usr.client.cmd_admin_mod_antag_rep(C, href_list["modantagrep"])
|
||||
show_player_panel(M)
|
||||
|
||||
else if(href_list["slowquery"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/answer = href_list["slowquery"]
|
||||
if(answer == "yes")
|
||||
log_query_debug("[usr.key] | Reported a server hang")
|
||||
if(alert(usr, "Had you just press any admin buttons?", "Query server hang report", "Yes", "No") == "Yes")
|
||||
var/response = input(usr,"What were you just doing?","Query server hang report") as null|text
|
||||
if(response)
|
||||
log_query_debug("[usr.key] | [response]")
|
||||
else if(answer == "no")
|
||||
log_query_debug("[usr.key] | Reported no server hang")
|
||||
|
||||
/datum/admins/proc/HandleCMode()
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
@@ -594,7 +594,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
/proc/send2irc(msg,msg2)
|
||||
msg = replacetext(replacetext(msg, "\proper", ""), "\improper", "")
|
||||
msg2 = replacetext(replacetext(msg2, "\proper", ""), "\improper", "")
|
||||
SERVER_TOOLS_RELAY_BROADCAST("[msg] | [msg2]")
|
||||
world.TgsTargetedChatBroadcast("[msg] | [msg2]", TRUE)
|
||||
|
||||
/proc/send2otherserver(source,msg,type = "Ahelp")
|
||||
var/comms_key = CONFIG_GET(string/comms_key)
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Jump To Key") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/Getmob(mob/M in GLOB.mob_list)
|
||||
/client/proc/Getmob(mob/M in GLOB.mob_list - GLOB.dummy_mob_list)
|
||||
set category = "Admin"
|
||||
set name = "Get Mob"
|
||||
set desc = "Mob to teleport"
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
if(isnewplayer(M))
|
||||
continue
|
||||
if (M.stat == DEAD || (M.client && M.client.holder && (M.client.prefs.chat_toggles & CHAT_DEAD))) //admins can toggle deadchat on and off. This is a proc in admin.dm and is only give to Administrators and above
|
||||
M.show_message(rendered, 2)
|
||||
to_chat(M, rendered)
|
||||
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Dsay") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
@@ -110,10 +110,14 @@ GLOBAL_PROTECT(LastAdminCalledProc)
|
||||
GLOBAL_LIST_EMPTY(AdminProcCallSpamPrevention)
|
||||
GLOBAL_PROTECT(AdminProcCallSpamPrevention)
|
||||
|
||||
/proc/WrapAdminProcCall(target, procname, list/arguments)
|
||||
/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
|
||||
if(target && procname == "Del")
|
||||
to_chat(usr, "Calling Del() is not allowed")
|
||||
return
|
||||
|
||||
if(!target.CanProcCall(procname))
|
||||
to_chat(usr, "Proccall on [target.type]/proc/[procname] is disallowed!")
|
||||
return
|
||||
var/current_caller = GLOB.AdminProcCaller
|
||||
var/ckey = usr ? usr.client.ckey : GLOB.AdminProcCaller
|
||||
if(!ckey)
|
||||
@@ -137,7 +141,7 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
|
||||
GLOB.AdminProcCaller = null
|
||||
|
||||
//adv proc call this, ya nerds
|
||||
/world/proc/WrapAdminProcCall(target, procname, list/arguments)
|
||||
/world/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
|
||||
if(target == GLOBAL_PROC)
|
||||
return call(procname)(arglist(arguments))
|
||||
else if(target != world)
|
||||
@@ -308,7 +312,7 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
|
||||
var/confirm = input("[choice.key] isn't ghosting right now. Are you sure you want to yank him out of them out of their body and place them in this pAI?", "Spawn pAI Confirmation", "No") in list("Yes", "No")
|
||||
if(confirm != "Yes")
|
||||
return 0
|
||||
var/obj/item/device/paicard/card = new(T)
|
||||
var/obj/item/paicard/card = new(T)
|
||||
var/mob/living/silicon/pai/pai = new(card)
|
||||
pai.name = input(choice, "Enter your pAI name:", "pAI Name", "Personal AI") as text
|
||||
pai.real_name = pai.name
|
||||
@@ -357,7 +361,7 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
|
||||
var/typename = "[type]"
|
||||
var/static/list/TYPES_SHORTCUTS = list(
|
||||
/obj/effect/decal/cleanable = "CLEANABLE",
|
||||
/obj/item/device/radio/headset = "HEADSET",
|
||||
/obj/item/radio/headset = "HEADSET",
|
||||
/obj/item/clothing/head/helmet/space = "SPESSHELMET",
|
||||
/obj/item/book/manual = "MANUAL",
|
||||
/obj/item/reagent_containers/food/drinks = "DRINK", //longest paths comes first
|
||||
@@ -466,8 +470,8 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
|
||||
id.update_label()
|
||||
|
||||
if(worn)
|
||||
if(istype(worn, /obj/item/device/pda))
|
||||
var/obj/item/device/pda/PDA = worn
|
||||
if(istype(worn, /obj/item/pda))
|
||||
var/obj/item/pda/PDA = worn
|
||||
PDA.id = id
|
||||
id.forceMove(PDA)
|
||||
else if(istype(worn, /obj/item/storage/wallet))
|
||||
@@ -476,7 +480,7 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
|
||||
id.forceMove(W)
|
||||
W.update_icon()
|
||||
else
|
||||
H.equip_to_slot(id,slot_wear_id)
|
||||
H.equip_to_slot(id,SLOT_WEAR_ID)
|
||||
|
||||
else
|
||||
alert("Invalid mob")
|
||||
@@ -626,7 +630,7 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
|
||||
areas_with_LS.Add(A.type)
|
||||
CHECK_TICK
|
||||
|
||||
for(var/obj/item/device/radio/intercom/I in GLOB.machines)
|
||||
for(var/obj/item/radio/intercom/I in GLOB.machines)
|
||||
var/area/A = get_area(I)
|
||||
if(!A)
|
||||
dat += "Skipped over [I] in invalid location, [I.loc].<br>"
|
||||
|
||||
@@ -136,7 +136,7 @@ GLOBAL_LIST_INIT(admin_verbs_debug_mapping, list(
|
||||
qdel(M)
|
||||
|
||||
if(intercom_range_display_status)
|
||||
for(var/obj/item/device/radio/intercom/I in world)
|
||||
for(var/obj/item/radio/intercom/I in world)
|
||||
for(var/turf/T in orange(7,I))
|
||||
var/obj/effect/debugging/marker/F = new/obj/effect/debugging/marker(T)
|
||||
if (!(F in view(7,I.loc)))
|
||||
|
||||
@@ -1043,6 +1043,30 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
for(var/obj/machinery/shuttle_manipulator/M in GLOB.machines)
|
||||
M.ui_interact(usr)
|
||||
|
||||
/client/proc/run_weather()
|
||||
set category = "Fun"
|
||||
set name = "Run Weather"
|
||||
set desc = "Triggers a weather on the z-level you choose."
|
||||
|
||||
if(!holder)
|
||||
return
|
||||
|
||||
var/weather_type = input("Choose a weather", "Weather") as null|anything in subtypesof(/datum/weather)
|
||||
if(!weather_type)
|
||||
return
|
||||
|
||||
var/z_level = input("Z-Level to target? Leave blank to target current Z-Level.", "Z-Level") as num|null
|
||||
if(!isnum(z_level))
|
||||
if(!src.mob)
|
||||
return
|
||||
z_level = src.mob.z
|
||||
|
||||
SSweather.run_weather(weather_type, z_level)
|
||||
|
||||
message_admins("[key_name_admin(usr)] started weather of type [weather_type] on the z-level [z_level].")
|
||||
log_admin("[key_name(usr)] started weather of type [weather_type] on the z-level [z_level].")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Run Weather")
|
||||
|
||||
/client/proc/mass_zombie_infection()
|
||||
set category = "Fun"
|
||||
set name = "Mass Zombie Infection"
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
armor = list("melee" = 15, "bullet" = 15, "laser" = 15, "energy" = 15, "bomb" = 15, "bio" = 15, "rad" = 15, "fire" = 70, "acid" = 70)
|
||||
actions_types = list(/datum/action/item_action/hands_free/activate)
|
||||
allowed = list(
|
||||
/obj/item/device/abductor,
|
||||
/obj/item/abductor,
|
||||
/obj/item/abductor_baton,
|
||||
/obj/item/melee/baton,
|
||||
/obj/item/gun/energy,
|
||||
@@ -53,7 +53,7 @@
|
||||
A.UpdateButtonIcon()
|
||||
|
||||
/obj/item/clothing/suit/armor/abductor/vest/item_action_slot_check(slot, mob/user)
|
||||
if(slot == slot_wear_suit) //we only give the mob the ability to activate the vest if he's actually wearing it.
|
||||
if(slot == SLOT_WEAR_SUIT) //we only give the mob the ability to activate the vest if he's actually wearing it.
|
||||
return 1
|
||||
|
||||
/obj/item/clothing/suit/armor/abductor/vest/proc/SetDisguise(datum/icon_snapshot/entry)
|
||||
@@ -129,16 +129,16 @@
|
||||
. = ..()
|
||||
|
||||
|
||||
/obj/item/device/abductor
|
||||
/obj/item/abductor
|
||||
icon = 'icons/obj/abductor.dmi'
|
||||
|
||||
/obj/item/device/abductor/proc/AbductorCheck(user)
|
||||
/obj/item/abductor/proc/AbductorCheck(user)
|
||||
if(isabductor(user))
|
||||
return TRUE
|
||||
to_chat(user, "<span class='warning'>You can't figure how this works!</span>")
|
||||
return FALSE
|
||||
|
||||
/obj/item/device/abductor/proc/ScientistCheck(user)
|
||||
/obj/item/abductor/proc/ScientistCheck(user)
|
||||
if(!AbductorCheck(user))
|
||||
return FALSE
|
||||
|
||||
@@ -149,7 +149,7 @@
|
||||
to_chat(user, "<span class='warning'>You're not trained to use this!</span>")
|
||||
return FALSE
|
||||
|
||||
/obj/item/device/abductor/gizmo
|
||||
/obj/item/abductor/gizmo
|
||||
name = "science tool"
|
||||
desc = "A dual-mode tool for retrieving specimens and scanning appearances. Scanning can be done through cameras."
|
||||
icon_state = "gizmo_scan"
|
||||
@@ -160,7 +160,7 @@
|
||||
var/mob/living/marked = null
|
||||
var/obj/machinery/abductor/console/console
|
||||
|
||||
/obj/item/device/abductor/gizmo/attack_self(mob/user)
|
||||
/obj/item/abductor/gizmo/attack_self(mob/user)
|
||||
if(!ScientistCheck(user))
|
||||
return
|
||||
if(!console)
|
||||
@@ -175,7 +175,7 @@
|
||||
icon_state = "gizmo_scan"
|
||||
to_chat(user, "<span class='notice'>You switch the device to [mode==GIZMO_SCAN? "SCAN": "MARK"] MODE</span>")
|
||||
|
||||
/obj/item/device/abductor/gizmo/attack(mob/living/M, mob/user)
|
||||
/obj/item/abductor/gizmo/attack(mob/living/M, mob/user)
|
||||
if(!ScientistCheck(user))
|
||||
return
|
||||
if(!console)
|
||||
@@ -189,7 +189,7 @@
|
||||
mark(M, user)
|
||||
|
||||
|
||||
/obj/item/device/abductor/gizmo/afterattack(atom/target, mob/living/user, flag, params)
|
||||
/obj/item/abductor/gizmo/afterattack(atom/target, mob/living/user, flag, params)
|
||||
if(flag)
|
||||
return
|
||||
if(!ScientistCheck(user))
|
||||
@@ -204,12 +204,12 @@
|
||||
if(GIZMO_MARK)
|
||||
mark(target, user)
|
||||
|
||||
/obj/item/device/abductor/gizmo/proc/scan(atom/target, mob/living/user)
|
||||
/obj/item/abductor/gizmo/proc/scan(atom/target, mob/living/user)
|
||||
if(ishuman(target))
|
||||
console.AddSnapshot(target)
|
||||
to_chat(user, "<span class='notice'>You scan [target] and add them to the database.</span>")
|
||||
|
||||
/obj/item/device/abductor/gizmo/proc/mark(atom/target, mob/living/user)
|
||||
/obj/item/abductor/gizmo/proc/mark(atom/target, mob/living/user)
|
||||
if(marked == target)
|
||||
to_chat(user, "<span class='warning'>This specimen is already marked!</span>")
|
||||
return
|
||||
@@ -222,7 +222,7 @@
|
||||
else
|
||||
prepare(target,user)
|
||||
|
||||
/obj/item/device/abductor/gizmo/proc/prepare(atom/target, mob/living/user)
|
||||
/obj/item/abductor/gizmo/proc/prepare(atom/target, mob/living/user)
|
||||
if(get_dist(target,user)>1)
|
||||
to_chat(user, "<span class='warning'>You need to be next to the specimen to prepare it for transport!</span>")
|
||||
return
|
||||
@@ -231,13 +231,13 @@
|
||||
marked = target
|
||||
to_chat(user, "<span class='notice'>You finish preparing [target] for transport.</span>")
|
||||
|
||||
/obj/item/device/abductor/gizmo/Destroy()
|
||||
/obj/item/abductor/gizmo/Destroy()
|
||||
if(console)
|
||||
console.gizmo = null
|
||||
. = ..()
|
||||
|
||||
|
||||
/obj/item/device/abductor/silencer
|
||||
/obj/item/abductor/silencer
|
||||
name = "abductor silencer"
|
||||
desc = "A compact device used to shut down communications equipment."
|
||||
icon_state = "silencer"
|
||||
@@ -245,19 +245,19 @@
|
||||
lefthand_file = 'icons/mob/inhands/antag/abductor_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/antag/abductor_righthand.dmi'
|
||||
|
||||
/obj/item/device/abductor/silencer/attack(mob/living/M, mob/user)
|
||||
/obj/item/abductor/silencer/attack(mob/living/M, mob/user)
|
||||
if(!AbductorCheck(user))
|
||||
return
|
||||
radio_off(M, user)
|
||||
|
||||
/obj/item/device/abductor/silencer/afterattack(atom/target, mob/living/user, flag, params)
|
||||
/obj/item/abductor/silencer/afterattack(atom/target, mob/living/user, flag, params)
|
||||
if(flag)
|
||||
return
|
||||
if(!AbductorCheck(user))
|
||||
return
|
||||
radio_off(target, user)
|
||||
|
||||
/obj/item/device/abductor/silencer/proc/radio_off(atom/target, mob/living/user)
|
||||
/obj/item/abductor/silencer/proc/radio_off(atom/target, mob/living/user)
|
||||
if( !(user in (viewers(7,target))) )
|
||||
return
|
||||
|
||||
@@ -270,17 +270,17 @@
|
||||
to_chat(user, "<span class='notice'>You silence [M]'s radio devices.</span>")
|
||||
radio_off_mob(M)
|
||||
|
||||
/obj/item/device/abductor/silencer/proc/radio_off_mob(mob/living/carbon/human/M)
|
||||
/obj/item/abductor/silencer/proc/radio_off_mob(mob/living/carbon/human/M)
|
||||
var/list/all_items = M.GetAllContents()
|
||||
|
||||
for(var/obj/I in all_items)
|
||||
if(istype(I, /obj/item/device/radio/))
|
||||
var/obj/item/device/radio/r = I
|
||||
if(istype(I, /obj/item/radio/))
|
||||
var/obj/item/radio/r = I
|
||||
r.listening = 0
|
||||
if(!istype(I, /obj/item/device/radio/headset))
|
||||
if(!istype(I, /obj/item/radio/headset))
|
||||
r.broadcasting = 0 //goddamned headset hacks
|
||||
|
||||
/obj/item/device/abductor/mind_device
|
||||
/obj/item/abductor/mind_device
|
||||
name = "mental interface device"
|
||||
desc = "A dual-mode tool for directly communicating with sentient brains. It can be used to send a direct message to a target, \
|
||||
or to send a command to a test subject with a charged gland."
|
||||
@@ -290,7 +290,7 @@
|
||||
righthand_file = 'icons/mob/inhands/antag/abductor_righthand.dmi'
|
||||
var/mode = MIND_DEVICE_MESSAGE
|
||||
|
||||
/obj/item/device/abductor/mind_device/attack_self(mob/user)
|
||||
/obj/item/abductor/mind_device/attack_self(mob/user)
|
||||
if(!ScientistCheck(user))
|
||||
return
|
||||
|
||||
@@ -302,7 +302,7 @@
|
||||
icon_state = "mind_device_message"
|
||||
to_chat(user, "<span class='notice'>You switch the device to [mode==MIND_DEVICE_MESSAGE? "TRANSMISSION": "COMMAND"] MODE</span>")
|
||||
|
||||
/obj/item/device/abductor/mind_device/afterattack(atom/target, mob/living/user, flag, params)
|
||||
/obj/item/abductor/mind_device/afterattack(atom/target, mob/living/user, flag, params)
|
||||
if(!ScientistCheck(user))
|
||||
return
|
||||
|
||||
@@ -312,7 +312,7 @@
|
||||
if(MIND_DEVICE_MESSAGE)
|
||||
mind_message(target, user)
|
||||
|
||||
/obj/item/device/abductor/mind_device/proc/mind_control(atom/target, mob/living/user)
|
||||
/obj/item/abductor/mind_device/proc/mind_control(atom/target, mob/living/user)
|
||||
if(iscarbon(target))
|
||||
var/mob/living/carbon/C = target
|
||||
var/obj/item/organ/heart/gland/G = C.getorganslot("heart")
|
||||
@@ -338,14 +338,14 @@
|
||||
if(QDELETED(G))
|
||||
return
|
||||
|
||||
if(istype(C.get_item_by_slot(slot_head), /obj/item/clothing/head/foilhat))
|
||||
if(istype(C.get_item_by_slot(SLOT_HEAD), /obj/item/clothing/head/foilhat))
|
||||
to_chat(user, "<span class='warning'>Your target seems to have some sort of protective headgear on, blocking the message from being sent!</span>")
|
||||
return
|
||||
|
||||
G.mind_control(command, user)
|
||||
to_chat(user, "<span class='notice'>You send the command to your target.</span>")
|
||||
|
||||
/obj/item/device/abductor/mind_device/proc/mind_message(atom/target, mob/living/user)
|
||||
/obj/item/abductor/mind_device/proc/mind_message(atom/target, mob/living/user)
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(L.stat == DEAD)
|
||||
@@ -362,7 +362,7 @@
|
||||
log_talk(user,"[key_name(user)] sent an abductor mind message to [L]/[L.ckey]: '[message]'", LOGSAY)
|
||||
|
||||
|
||||
/obj/item/device/firing_pin/abductor
|
||||
/obj/item/firing_pin/abductor
|
||||
name = "alien firing pin"
|
||||
icon_state = "firing_pin_ayy"
|
||||
desc = "This firing pin is slimy and warm; you can swear you feel it \
|
||||
@@ -370,14 +370,14 @@
|
||||
fail_message = "<span class='abductor'>\
|
||||
Firing error, please contact Command.</span>"
|
||||
|
||||
/obj/item/device/firing_pin/abductor/pin_auth(mob/living/user)
|
||||
/obj/item/firing_pin/abductor/pin_auth(mob/living/user)
|
||||
. = isabductor(user)
|
||||
|
||||
/obj/item/gun/energy/alien
|
||||
name = "alien pistol"
|
||||
desc = "A complicated gun that fires bursts of high-intensity radiation."
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/declone)
|
||||
pin = /obj/item/device/firing_pin/abductor
|
||||
pin = /obj/item/firing_pin/abductor
|
||||
icon_state = "alienpistol"
|
||||
item_state = "alienpistol"
|
||||
trigger_guard = TRIGGER_GUARD_ALLOW_ALL
|
||||
@@ -425,7 +425,7 @@ Congratulations! You are now trained for invasive xenobiology research!"}
|
||||
item_state = "wonderprod"
|
||||
lefthand_file = 'icons/mob/inhands/antag/abductor_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/antag/abductor_righthand.dmi'
|
||||
slot_flags = SLOT_BELT
|
||||
slot_flags = ITEM_SLOT_BELT
|
||||
force = 7
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
actions_types = list(/datum/action/item_action/toggle_mode)
|
||||
@@ -515,7 +515,7 @@ Congratulations! You are now trained for invasive xenobiology research!"}
|
||||
|
||||
/obj/item/abductor_baton/proc/SleepAttack(mob/living/L,mob/living/user)
|
||||
if(L.incapacitated(TRUE, TRUE))
|
||||
if(istype(L.get_item_by_slot(slot_head), /obj/item/clothing/head/foilhat))
|
||||
if(istype(L.get_item_by_slot(SLOT_HEAD), /obj/item/clothing/head/foilhat))
|
||||
to_chat(user, "<span class='warning'>The specimen's protective headgear is interfering with the sleep inducement!</span>")
|
||||
L.visible_message("<span class='danger'>[user] tried to induced sleep in [L] with [src], but their headgear protected them!</span>", \
|
||||
"<span class='userdanger'>You feel a strange wave of heavy drowsiness wash over you, but your headgear deflects most of it!</span>")
|
||||
@@ -527,7 +527,7 @@ Congratulations! You are now trained for invasive xenobiology research!"}
|
||||
L.Sleeping(1200)
|
||||
add_logs(user, L, "put to sleep")
|
||||
else
|
||||
if(istype(L.get_item_by_slot(slot_head), /obj/item/clothing/head/foilhat))
|
||||
if(istype(L.get_item_by_slot(SLOT_HEAD), /obj/item/clothing/head/foilhat))
|
||||
to_chat(user, "<span class='warning'>The specimen's protective headgear is completely blocking our sleep inducement methods!</span>")
|
||||
L.visible_message("<span class='danger'>[user] tried to induce sleep in [L] with [src], but their headgear completely protected them!</span>", \
|
||||
"<span class='userdanger'>Any sense of drowsiness is quickly diminished as your headgear deflects the effects!</span>")
|
||||
@@ -613,20 +613,20 @@ Congratulations! You are now trained for invasive xenobiology research!"}
|
||||
if(BATON_PROBE)
|
||||
to_chat(user, "<span class='warning'>The baton is in probing mode.</span>")
|
||||
|
||||
/obj/item/device/radio/headset/abductor
|
||||
/obj/item/radio/headset/abductor
|
||||
name = "alien headset"
|
||||
desc = "An advanced alien headset designed to monitor communications of human space stations. Why does it have a microphone? No one knows."
|
||||
icon = 'icons/obj/abductor.dmi'
|
||||
icon_state = "abductor_headset"
|
||||
item_state = "abductor_headset"
|
||||
keyslot2 = new /obj/item/device/encryptionkey/heads/captain
|
||||
keyslot2 = new /obj/item/encryptionkey/heads/captain
|
||||
flags_2 = BANG_PROTECT_2
|
||||
|
||||
/obj/item/device/radio/headset/abductor/Initialize(mapload)
|
||||
/obj/item/radio/headset/abductor/Initialize(mapload)
|
||||
. = ..()
|
||||
make_syndie()
|
||||
|
||||
/obj/item/device/radio/headset/abductor/attackby(obj/item/W, mob/user, params)
|
||||
/obj/item/radio/headset/abductor/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/screwdriver))
|
||||
return // Stops humans from disassembling abductor headsets.
|
||||
return ..()
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
uniform = /obj/item/clothing/under/color/grey //they're greys gettit
|
||||
shoes = /obj/item/clothing/shoes/combat
|
||||
back = /obj/item/storage/backpack
|
||||
ears = /obj/item/device/radio/headset/abductor
|
||||
ears = /obj/item/radio/headset/abductor
|
||||
|
||||
/datum/outfit/abductor/proc/link_to_console(mob/living/carbon/human/H, team_number)
|
||||
var/datum/antagonist/abductor/A = H.mind.has_antag_datum(/datum/antagonist/abductor)
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
var/obj/item/storage/backpack/B = locate() in H
|
||||
if(B)
|
||||
for(var/obj/item/device/abductor/gizmo/G in B.contents)
|
||||
for(var/obj/item/abductor/gizmo/G in B.contents)
|
||||
console.AddGizmo(G)
|
||||
|
||||
/datum/outfit/abductor/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
@@ -39,14 +39,14 @@
|
||||
|
||||
backpack_contents = list(
|
||||
/obj/item/gun/energy/alien = 1,
|
||||
/obj/item/device/abductor/silencer = 1
|
||||
/obj/item/abductor/silencer = 1
|
||||
)
|
||||
|
||||
/datum/outfit/abductor/scientist
|
||||
name = "Abductor Scientist"
|
||||
|
||||
backpack_contents = list(
|
||||
/obj/item/device/abductor/gizmo = 1
|
||||
/obj/item/abductor/gizmo = 1
|
||||
)
|
||||
|
||||
/datum/outfit/abductor/scientist/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
owner.grant_language(/datum/language/slime)
|
||||
|
||||
/obj/item/organ/heart/gland/slime/activate()
|
||||
to_chat(owner, "<span class='warning'>You feel nauseous!</span>")
|
||||
to_chat(owner, "<span class='warning'>You feel nauseated!</span>")
|
||||
owner.vomit(20)
|
||||
|
||||
var/mob/living/simple_animal/slime/Slime = new(get_turf(owner), "grey")
|
||||
@@ -153,7 +153,7 @@
|
||||
H.confused += 15
|
||||
H.adjustBrainLoss(10, 160)
|
||||
if(3)
|
||||
H.hallucination += 80
|
||||
H.hallucination += 60
|
||||
|
||||
/obj/item/organ/heart/gland/pop
|
||||
cooldown_low = 900
|
||||
@@ -272,10 +272,10 @@
|
||||
|
||||
/obj/item/organ/heart/gland/electric/Insert(mob/living/carbon/M, special = 0)
|
||||
..()
|
||||
owner.add_trait(TRAIT_SHOCKIMMUNE, "abductor_gland")
|
||||
owner.add_trait(TRAIT_SHOCKIMMUNE, ORGAN_TRAIT)
|
||||
|
||||
/obj/item/organ/heart/gland/electric/Remove(mob/living/carbon/M, special = 0)
|
||||
owner.remove_trait(TRAIT_SHOCKIMMUNE, "abductor_gland")
|
||||
owner.remove_trait(TRAIT_SHOCKIMMUNE, ORGAN_TRAIT)
|
||||
..()
|
||||
|
||||
/obj/item/organ/heart/gland/electric/activate()
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
icon_state = "console"
|
||||
density = TRUE
|
||||
anchored = TRUE
|
||||
var/obj/item/device/abductor/gizmo/gizmo
|
||||
var/obj/item/abductor/gizmo/gizmo
|
||||
var/obj/item/clothing/suit/armor/abductor/vest/vest
|
||||
var/obj/machinery/abductor/experiment/experiment
|
||||
var/obj/machinery/abductor/pad/pad
|
||||
@@ -106,13 +106,13 @@
|
||||
if("helmet")
|
||||
Dispense(/obj/item/clothing/head/helmet/abductor)
|
||||
if("silencer")
|
||||
Dispense(/obj/item/device/abductor/silencer)
|
||||
Dispense(/obj/item/abductor/silencer)
|
||||
if("tool")
|
||||
Dispense(/obj/item/device/abductor/gizmo)
|
||||
Dispense(/obj/item/abductor/gizmo)
|
||||
if("vest")
|
||||
Dispense(/obj/item/clothing/suit/armor/abductor/vest)
|
||||
if("mind_device")
|
||||
Dispense(/obj/item/device/abductor/mind_device,cost=2)
|
||||
Dispense(/obj/item/abductor/mind_device,cost=2)
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/abductor/console/proc/TeleporterRetrieve()
|
||||
@@ -167,7 +167,7 @@
|
||||
c.console = src
|
||||
|
||||
/obj/machinery/abductor/console/proc/AddSnapshot(mob/living/carbon/human/target)
|
||||
if(istype(target.get_item_by_slot(slot_head), /obj/item/clothing/head/foilhat))
|
||||
if(istype(target.get_item_by_slot(SLOT_HEAD), /obj/item/clothing/head/foilhat))
|
||||
say("Subject wearing specialized protective headgear, unable to get a proper scan!")
|
||||
return
|
||||
var/datum/icon_snapshot/entry = new
|
||||
@@ -181,7 +181,7 @@
|
||||
return
|
||||
disguises[entry.name] = entry
|
||||
|
||||
/obj/machinery/abductor/console/proc/AddGizmo(obj/item/device/abductor/gizmo/G)
|
||||
/obj/machinery/abductor/console/proc/AddGizmo(obj/item/abductor/gizmo/G)
|
||||
if(G == gizmo && G.console == src)
|
||||
return FALSE
|
||||
|
||||
@@ -205,7 +205,7 @@
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/abductor/console/attackby(obj/O, mob/user, params)
|
||||
if(istype(O, /obj/item/device/abductor/gizmo) && AddGizmo(O))
|
||||
if(istype(O, /obj/item/abductor/gizmo) && AddGizmo(O))
|
||||
to_chat(user, "<span class='notice'>You link the tool to the console.</span>")
|
||||
else if(istype(O, /obj/item/clothing/suit/armor/abductor/vest) && AddVest(O))
|
||||
to_chat(user, "<span class='notice'>You link the vest to the console.</span>")
|
||||
|
||||
@@ -227,7 +227,7 @@
|
||||
return 15
|
||||
|
||||
/obj/structure/blob/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/device/analyzer))
|
||||
if(istype(I, /obj/item/analyzer))
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
to_chat(user, "<b>The analyzer beeps once, then reports:</b><br>")
|
||||
SEND_SOUND(user, sound('sound/machines/ping.ogg'))
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
var/can_readapt = changeling.canrespec
|
||||
var/genetic_points_remaining = changeling.geneticpoints
|
||||
var/absorbed_dna_count = changeling.absorbedcount
|
||||
var/true_absorbs = changeling.trueabsorbs
|
||||
|
||||
data["can_readapt"] = can_readapt
|
||||
data["genetic_points_remaining"] = genetic_points_remaining
|
||||
@@ -45,8 +46,9 @@
|
||||
AL["helptext"] = initial(ability.helptext)
|
||||
AL["owned"] = changeling.has_sting(ability)
|
||||
var/req_dna = initial(ability.req_dna)
|
||||
var/req_absorbs = initial(ability.req_absorbs)
|
||||
AL["dna_cost"] = dna_cost
|
||||
AL["can_purchase"] = ((req_dna <= absorbed_dna_count) && (dna_cost <= genetic_points_remaining))
|
||||
AL["can_purchase"] = ((req_absorbs <= true_absorbs) && (req_dna <= absorbed_dna_count) && (dna_cost <= genetic_points_remaining))
|
||||
|
||||
abilities += list(AL)
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
var/datum/changelingprofile/first_prof = null
|
||||
var/dna_max = 6 //How many extra DNA strands the changeling can store for transformation.
|
||||
var/absorbedcount = 0
|
||||
var/trueabsorbs = 0//dna gained using absorb, not dna sting
|
||||
var/chem_charges = 20
|
||||
var/chem_storage = 75
|
||||
var/chem_recharge_rate = 1
|
||||
@@ -352,7 +353,10 @@
|
||||
if(GLOB.changeling_team_objective_type)
|
||||
var/datum/objective/changeling_team_objective/team_objective = new GLOB.changeling_team_objective_type
|
||||
team_objective.owner = owner
|
||||
objectives += team_objective
|
||||
if(team_objective.prepare())//Setting up succeeded
|
||||
objectives += team_objective
|
||||
else
|
||||
qdel(team_objective)
|
||||
return
|
||||
|
||||
/datum/antagonist/changeling/proc/forge_objectives()
|
||||
|
||||
@@ -1,78 +1,81 @@
|
||||
/*
|
||||
* Don't use the apostrophe in name or desc. Causes script errors.
|
||||
* TODO: combine atleast some of the functionality with /proc_holder/spell
|
||||
*/
|
||||
|
||||
/obj/effect/proc_holder/changeling
|
||||
panel = "Changeling"
|
||||
name = "Prototype Sting"
|
||||
desc = "" // Fluff
|
||||
var/helptext = "" // Details
|
||||
var/chemical_cost = 0 // negative chemical cost is for passive abilities (chemical glands)
|
||||
var/dna_cost = -1 //cost of the sting in dna points. 0 = auto-purchase, -1 = cannot be purchased
|
||||
var/req_dna = 0 //amount of dna needed to use this ability. Changelings always have atleast 1
|
||||
var/req_human = 0 //if you need to be human to use this ability
|
||||
var/req_stat = CONSCIOUS // CONSCIOUS, UNCONSCIOUS or DEAD
|
||||
var/always_keep = 0 // important for abilities like revive that screw you if you lose them.
|
||||
var/ignores_fakedeath = FALSE // usable with the FAKEDEATH flag
|
||||
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/on_purchase(mob/user, is_respec)
|
||||
if(!is_respec)
|
||||
SSblackbox.record_feedback("tally", "changeling_power_purchase", 1, name)
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/on_refund(mob/user)
|
||||
return
|
||||
|
||||
/obj/effect/proc_holder/changeling/Click()
|
||||
var/mob/user = usr
|
||||
if(!user || !user.mind || !user.mind.has_antag_datum(/datum/antagonist/changeling))
|
||||
return
|
||||
try_to_sting(user)
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/try_to_sting(mob/user, mob/target)
|
||||
if(!can_sting(user, target))
|
||||
return
|
||||
var/datum/antagonist/changeling/c = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(sting_action(user, target))
|
||||
SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("[name]"))
|
||||
sting_feedback(user, target)
|
||||
c.chem_charges -= chemical_cost
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/sting_action(mob/user, mob/target)
|
||||
return 0
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/sting_feedback(mob/user, mob/target)
|
||||
return 0
|
||||
|
||||
//Fairly important to remember to return 1 on success >.<
|
||||
/obj/effect/proc_holder/changeling/proc/can_sting(mob/living/user, mob/target)
|
||||
if(!ishuman(user) && !ismonkey(user)) //typecast everything from mob to carbon from this point onwards
|
||||
return 0
|
||||
if(req_human && !ishuman(user))
|
||||
to_chat(user, "<span class='warning'>We cannot do that in this form!</span>")
|
||||
return 0
|
||||
var/datum/antagonist/changeling/c = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(c.chem_charges < chemical_cost)
|
||||
to_chat(user, "<span class='warning'>We require at least [chemical_cost] unit\s of chemicals to do that!</span>")
|
||||
return 0
|
||||
if(c.absorbedcount < req_dna)
|
||||
to_chat(user, "<span class='warning'>We require at least [req_dna] sample\s of compatible DNA.</span>")
|
||||
return 0
|
||||
if(req_stat < user.stat)
|
||||
to_chat(user, "<span class='warning'>We are incapacitated.</span>")
|
||||
return 0
|
||||
if((user.has_trait(TRAIT_FAKEDEATH)) && (!ignores_fakedeath))
|
||||
to_chat(user, "<span class='warning'>We are incapacitated.</span>")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
//used in /mob/Stat()
|
||||
/obj/effect/proc_holder/changeling/proc/can_be_used_by(mob/user)
|
||||
if(!user || QDELETED(user))
|
||||
return 0
|
||||
if(!ishuman(user) && !ismonkey(user))
|
||||
return 0
|
||||
if(req_human && !ishuman(user))
|
||||
return 0
|
||||
return 1
|
||||
/*
|
||||
* Don't use the apostrophe in name or desc. Causes script errors.
|
||||
* TODO: combine atleast some of the functionality with /proc_holder/spell
|
||||
*/
|
||||
|
||||
/obj/effect/proc_holder/changeling
|
||||
panel = "Changeling"
|
||||
name = "Prototype Sting"
|
||||
desc = "" // Fluff
|
||||
var/helptext = "" // Details
|
||||
var/chemical_cost = 0 // negative chemical cost is for passive abilities (chemical glands)
|
||||
var/dna_cost = -1 //cost of the sting in dna points. 0 = auto-purchase, -1 = cannot be purchased
|
||||
var/req_dna = 0 //amount of dna needed to use this ability. Changelings always have atleast 1
|
||||
var/req_human = 0 //if you need to be human to use this ability
|
||||
var/req_absorbs = 0 //similar to req_dna, but only gained from absorbing, not DNA sting
|
||||
var/req_stat = CONSCIOUS // CONSCIOUS, UNCONSCIOUS or DEAD
|
||||
var/always_keep = 0 // important for abilities like revive that screw you if you lose them.
|
||||
var/ignores_fakedeath = FALSE // usable with the FAKEDEATH flag
|
||||
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/on_purchase(mob/user, is_respec)
|
||||
if(!is_respec)
|
||||
SSblackbox.record_feedback("tally", "changeling_power_purchase", 1, name)
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/on_refund(mob/user)
|
||||
return
|
||||
|
||||
/obj/effect/proc_holder/changeling/Click()
|
||||
var/mob/user = usr
|
||||
if(!user || !user.mind || !user.mind.has_antag_datum(/datum/antagonist/changeling))
|
||||
return
|
||||
try_to_sting(user)
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/try_to_sting(mob/user, mob/target)
|
||||
if(!can_sting(user, target))
|
||||
return
|
||||
var/datum/antagonist/changeling/c = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(sting_action(user, target))
|
||||
SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("[name]"))
|
||||
sting_feedback(user, target)
|
||||
c.chem_charges -= chemical_cost
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/sting_action(mob/user, mob/target)
|
||||
return 0
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/sting_feedback(mob/user, mob/target)
|
||||
return 0
|
||||
|
||||
//Fairly important to remember to return 1 on success >.<
|
||||
/obj/effect/proc_holder/changeling/proc/can_sting(mob/living/user, mob/target)
|
||||
if(!ishuman(user) && !ismonkey(user)) //typecast everything from mob to carbon from this point onwards
|
||||
return 0
|
||||
if(req_human && !ishuman(user))
|
||||
to_chat(user, "<span class='warning'>We cannot do that in this form!</span>")
|
||||
return 0
|
||||
var/datum/antagonist/changeling/c = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(c.chem_charges < chemical_cost)
|
||||
to_chat(user, "<span class='warning'>We require at least [chemical_cost] unit\s of chemicals to do that!</span>")
|
||||
return 0
|
||||
if(c.absorbedcount < req_dna)
|
||||
to_chat(user, "<span class='warning'>We require at least [req_dna] sample\s of compatible DNA.</span>")
|
||||
return 0
|
||||
if(c.trueabsorbs < req_absorbs)
|
||||
to_chat(user, "<span class='warning'>We require at least [req_absorbs] sample\s of DNA gained through our Absorb ability.</span>")
|
||||
if(req_stat < user.stat)
|
||||
to_chat(user, "<span class='warning'>We are incapacitated.</span>")
|
||||
return 0
|
||||
if((user.has_trait(TRAIT_FAKEDEATH)) && (!ignores_fakedeath))
|
||||
to_chat(user, "<span class='warning'>We are incapacitated.</span>")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
//used in /mob/Stat()
|
||||
/obj/effect/proc_holder/changeling/proc/can_be_used_by(mob/user)
|
||||
if(QDELETED(user))
|
||||
return FALSE
|
||||
if(!ishuman(user) && !ismonkey(user))
|
||||
return FALSE
|
||||
if(req_human && !ishuman(user))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -1,120 +1,121 @@
|
||||
/obj/effect/proc_holder/changeling/absorbDNA
|
||||
name = "Absorb DNA"
|
||||
desc = "Absorb the DNA of our victim."
|
||||
chemical_cost = 0
|
||||
dna_cost = 0
|
||||
req_human = 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/absorbDNA/can_sting(mob/living/carbon/user)
|
||||
if(!..())
|
||||
return
|
||||
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(changeling.isabsorbing)
|
||||
to_chat(user, "<span class='warning'>We are already absorbing!</span>")
|
||||
return
|
||||
|
||||
if(!user.pulling || !iscarbon(user.pulling))
|
||||
to_chat(user, "<span class='warning'>We must be grabbing a creature to absorb them!</span>")
|
||||
return
|
||||
if(user.grab_state <= GRAB_NECK)
|
||||
to_chat(user, "<span class='warning'>We must have a tighter grip to absorb this creature!</span>")
|
||||
return
|
||||
|
||||
var/mob/living/carbon/target = user.pulling
|
||||
return changeling.can_absorb_dna(target)
|
||||
|
||||
|
||||
|
||||
/obj/effect/proc_holder/changeling/absorbDNA/sting_action(mob/user)
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
var/mob/living/carbon/human/target = user.pulling
|
||||
changeling.isabsorbing = 1
|
||||
for(var/i in 1 to 3)
|
||||
switch(i)
|
||||
if(1)
|
||||
to_chat(user, "<span class='notice'>This creature is compatible. We must hold still...</span>")
|
||||
if(2)
|
||||
user.visible_message("<span class='warning'>[user] extends a proboscis!</span>", "<span class='notice'>We extend a proboscis.</span>")
|
||||
if(3)
|
||||
user.visible_message("<span class='danger'>[user] stabs [target] with the proboscis!</span>", "<span class='notice'>We stab [target] with the proboscis.</span>")
|
||||
to_chat(target, "<span class='userdanger'>You feel a sharp stabbing pain!</span>")
|
||||
target.take_overall_damage(40)
|
||||
|
||||
SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("Absorb DNA", "[i]"))
|
||||
if(!do_mob(user, target, 150))
|
||||
to_chat(user, "<span class='warning'>Our absorption of [target] has been interrupted!</span>")
|
||||
changeling.isabsorbing = 0
|
||||
return
|
||||
|
||||
SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("Absorb DNA", "4"))
|
||||
user.visible_message("<span class='danger'>[user] sucks the fluids from [target]!</span>", "<span class='notice'>We have absorbed [target].</span>")
|
||||
to_chat(target, "<span class='userdanger'>You are absorbed by the changeling!</span>")
|
||||
|
||||
if(!changeling.has_dna(target.dna))
|
||||
changeling.add_new_profile(target)
|
||||
|
||||
if(user.nutrition < NUTRITION_LEVEL_WELL_FED)
|
||||
user.nutrition = min((user.nutrition + target.nutrition), NUTRITION_LEVEL_WELL_FED)
|
||||
|
||||
if(target.mind)//if the victim has got a mind
|
||||
// Absorb a lizard, speak Draconic.
|
||||
user.copy_known_languages_from(target)
|
||||
|
||||
target.mind.show_memory(user, 0) //I can read your mind, kekeke. Output all their notes.
|
||||
|
||||
//Some of target's recent speech, so the changeling can attempt to imitate them better.
|
||||
//Recent as opposed to all because rounds tend to have a LOT of text.
|
||||
var/list/recent_speech = list()
|
||||
|
||||
var/list/say_log = target.logging[INDIVIDUAL_SAY_LOG]
|
||||
|
||||
if(LAZYLEN(say_log) > LING_ABSORB_RECENT_SPEECH)
|
||||
recent_speech = say_log.Copy(say_log.len-LING_ABSORB_RECENT_SPEECH+1,0) //0 so len-LING_ARS+1 to end of list
|
||||
else
|
||||
for(var/spoken_memory in say_log)
|
||||
if(recent_speech.len >= LING_ABSORB_RECENT_SPEECH)
|
||||
break
|
||||
recent_speech[spoken_memory] = say_log[spoken_memory]
|
||||
|
||||
if(recent_speech.len)
|
||||
changeling.antag_memory += "<B>Some of [target]'s speech patterns, we should study these to better impersonate them!</B><br>"
|
||||
to_chat(user, "<span class='boldnotice'>Some of [target]'s speech patterns, we should study these to better impersonate them!</span>")
|
||||
for(var/spoken_memory in recent_speech)
|
||||
changeling.antag_memory += "\"[recent_speech[spoken_memory]]\"<br>"
|
||||
to_chat(user, "<span class='notice'>\"[recent_speech[spoken_memory]]\"</span>")
|
||||
changeling.antag_memory += "<B>We have no more knowledge of [target]'s speech patterns.</B><br>"
|
||||
to_chat(user, "<span class='boldnotice'>We have no more knowledge of [target]'s speech patterns.</span>")
|
||||
|
||||
|
||||
var/datum/antagonist/changeling/target_ling = target.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(target_ling)//If the target was a changeling, suck out their extra juice and objective points!
|
||||
to_chat(user, "<span class='boldnotice'>[target] was one of us. We have absorbed their power.</span>")
|
||||
target_ling.remove_changeling_powers()
|
||||
changeling.geneticpoints += round(target_ling.geneticpoints/2)
|
||||
target_ling.geneticpoints = 0
|
||||
target_ling.canrespec = 0
|
||||
changeling.chem_storage += round(target_ling.chem_storage/2)
|
||||
changeling.chem_charges += min(target_ling.chem_charges, changeling.chem_storage)
|
||||
target_ling.chem_charges = 0
|
||||
target_ling.chem_storage = 0
|
||||
changeling.absorbedcount += (target_ling.absorbedcount)
|
||||
target_ling.stored_profiles.len = 1
|
||||
target_ling.absorbedcount = 0
|
||||
|
||||
|
||||
changeling.chem_charges=min(changeling.chem_charges+10, changeling.chem_storage)
|
||||
|
||||
changeling.isabsorbing = 0
|
||||
changeling.canrespec = 1
|
||||
|
||||
target.death(0)
|
||||
target.Drain()
|
||||
return TRUE
|
||||
|
||||
|
||||
|
||||
//Absorbs the target DNA.
|
||||
//datum/changeling/proc/absorb_dna(mob/living/carbon/T, mob/user)
|
||||
|
||||
//datum/changeling/proc/store_dna(datum/dna/new_dna, mob/user)
|
||||
/obj/effect/proc_holder/changeling/absorbDNA
|
||||
name = "Absorb DNA"
|
||||
desc = "Absorb the DNA of our victim."
|
||||
chemical_cost = 0
|
||||
dna_cost = 0
|
||||
req_human = 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/absorbDNA/can_sting(mob/living/carbon/user)
|
||||
if(!..())
|
||||
return
|
||||
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(changeling.isabsorbing)
|
||||
to_chat(user, "<span class='warning'>We are already absorbing!</span>")
|
||||
return
|
||||
|
||||
if(!user.pulling || !iscarbon(user.pulling))
|
||||
to_chat(user, "<span class='warning'>We must be grabbing a creature to absorb them!</span>")
|
||||
return
|
||||
if(user.grab_state <= GRAB_NECK)
|
||||
to_chat(user, "<span class='warning'>We must have a tighter grip to absorb this creature!</span>")
|
||||
return
|
||||
|
||||
var/mob/living/carbon/target = user.pulling
|
||||
return changeling.can_absorb_dna(target)
|
||||
|
||||
|
||||
|
||||
/obj/effect/proc_holder/changeling/absorbDNA/sting_action(mob/user)
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
var/mob/living/carbon/human/target = user.pulling
|
||||
changeling.isabsorbing = 1
|
||||
for(var/i in 1 to 3)
|
||||
switch(i)
|
||||
if(1)
|
||||
to_chat(user, "<span class='notice'>This creature is compatible. We must hold still...</span>")
|
||||
if(2)
|
||||
user.visible_message("<span class='warning'>[user] extends a proboscis!</span>", "<span class='notice'>We extend a proboscis.</span>")
|
||||
if(3)
|
||||
user.visible_message("<span class='danger'>[user] stabs [target] with the proboscis!</span>", "<span class='notice'>We stab [target] with the proboscis.</span>")
|
||||
to_chat(target, "<span class='userdanger'>You feel a sharp stabbing pain!</span>")
|
||||
target.take_overall_damage(40)
|
||||
|
||||
SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("Absorb DNA", "[i]"))
|
||||
if(!do_mob(user, target, 150))
|
||||
to_chat(user, "<span class='warning'>Our absorption of [target] has been interrupted!</span>")
|
||||
changeling.isabsorbing = 0
|
||||
return
|
||||
|
||||
SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("Absorb DNA", "4"))
|
||||
user.visible_message("<span class='danger'>[user] sucks the fluids from [target]!</span>", "<span class='notice'>We have absorbed [target].</span>")
|
||||
to_chat(target, "<span class='userdanger'>You are absorbed by the changeling!</span>")
|
||||
|
||||
if(!changeling.has_dna(target.dna))
|
||||
changeling.add_new_profile(target)
|
||||
changeling.trueabsorbs++
|
||||
|
||||
if(user.nutrition < NUTRITION_LEVEL_WELL_FED)
|
||||
user.nutrition = min((user.nutrition + target.nutrition), NUTRITION_LEVEL_WELL_FED)
|
||||
|
||||
if(target.mind)//if the victim has got a mind
|
||||
// Absorb a lizard, speak Draconic.
|
||||
user.copy_known_languages_from(target)
|
||||
|
||||
target.mind.show_memory(user, 0) //I can read your mind, kekeke. Output all their notes.
|
||||
|
||||
//Some of target's recent speech, so the changeling can attempt to imitate them better.
|
||||
//Recent as opposed to all because rounds tend to have a LOT of text.
|
||||
var/list/recent_speech = list()
|
||||
|
||||
var/list/say_log = target.logging[INDIVIDUAL_SAY_LOG]
|
||||
|
||||
if(LAZYLEN(say_log) > LING_ABSORB_RECENT_SPEECH)
|
||||
recent_speech = say_log.Copy(say_log.len-LING_ABSORB_RECENT_SPEECH+1,0) //0 so len-LING_ARS+1 to end of list
|
||||
else
|
||||
for(var/spoken_memory in say_log)
|
||||
if(recent_speech.len >= LING_ABSORB_RECENT_SPEECH)
|
||||
break
|
||||
recent_speech[spoken_memory] = say_log[spoken_memory]
|
||||
|
||||
if(recent_speech.len)
|
||||
changeling.antag_memory += "<B>Some of [target]'s speech patterns, we should study these to better impersonate them!</B><br>"
|
||||
to_chat(user, "<span class='boldnotice'>Some of [target]'s speech patterns, we should study these to better impersonate them!</span>")
|
||||
for(var/spoken_memory in recent_speech)
|
||||
changeling.antag_memory += "\"[recent_speech[spoken_memory]]\"<br>"
|
||||
to_chat(user, "<span class='notice'>\"[recent_speech[spoken_memory]]\"</span>")
|
||||
changeling.antag_memory += "<B>We have no more knowledge of [target]'s speech patterns.</B><br>"
|
||||
to_chat(user, "<span class='boldnotice'>We have no more knowledge of [target]'s speech patterns.</span>")
|
||||
|
||||
|
||||
var/datum/antagonist/changeling/target_ling = target.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(target_ling)//If the target was a changeling, suck out their extra juice and objective points!
|
||||
to_chat(user, "<span class='boldnotice'>[target] was one of us. We have absorbed their power.</span>")
|
||||
target_ling.remove_changeling_powers()
|
||||
changeling.geneticpoints += round(target_ling.geneticpoints/2)
|
||||
target_ling.geneticpoints = 0
|
||||
target_ling.canrespec = 0
|
||||
changeling.chem_storage += round(target_ling.chem_storage/2)
|
||||
changeling.chem_charges += min(target_ling.chem_charges, changeling.chem_storage)
|
||||
target_ling.chem_charges = 0
|
||||
target_ling.chem_storage = 0
|
||||
changeling.absorbedcount += (target_ling.absorbedcount)
|
||||
target_ling.stored_profiles.len = 1
|
||||
target_ling.absorbedcount = 0
|
||||
|
||||
|
||||
changeling.chem_charges=min(changeling.chem_charges+10, changeling.chem_storage)
|
||||
|
||||
changeling.isabsorbing = 0
|
||||
changeling.canrespec = 1
|
||||
|
||||
target.death(0)
|
||||
target.Drain()
|
||||
return TRUE
|
||||
|
||||
|
||||
|
||||
//Absorbs the target DNA.
|
||||
//datum/changeling/proc/absorb_dna(mob/living/carbon/T, mob/user)
|
||||
|
||||
//datum/changeling/proc/store_dna(datum/dna/new_dna, mob/user)
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
return 0
|
||||
|
||||
if(user.handcuffed)
|
||||
var/obj/O = user.get_item_by_slot(slot_handcuffed)
|
||||
var/obj/O = user.get_item_by_slot(SLOT_HANDCUFFED)
|
||||
if(!istype(O))
|
||||
return 0
|
||||
user.visible_message("<span class='warning'>[user] vomits a glob of acid on [user.p_their()] [O]!</span>", \
|
||||
@@ -23,7 +23,7 @@
|
||||
used = TRUE
|
||||
|
||||
if(user.wear_suit && user.wear_suit.breakouttime && !used)
|
||||
var/obj/item/clothing/suit/S = user.get_item_by_slot(slot_wear_suit)
|
||||
var/obj/item/clothing/suit/S = user.get_item_by_slot(SLOT_WEAR_SUIT)
|
||||
if(!istype(S))
|
||||
return 0
|
||||
user.visible_message("<span class='warning'>[user] vomits a glob of acid across the front of [user.p_their()] [S]!</span>", \
|
||||
|
||||
@@ -119,8 +119,8 @@
|
||||
user.dropItemToGround(user.head)
|
||||
user.dropItemToGround(user.wear_suit)
|
||||
|
||||
user.equip_to_slot_if_possible(new suit_type(user), slot_wear_suit, 1, 1, 1)
|
||||
user.equip_to_slot_if_possible(new helmet_type(user), slot_head, 1, 1, 1)
|
||||
user.equip_to_slot_if_possible(new suit_type(user), SLOT_WEAR_SUIT, 1, 1, 1)
|
||||
user.equip_to_slot_if_possible(new helmet_type(user), SLOT_HEAD, 1, 1, 1)
|
||||
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
changeling.chem_recharge_slowdown += recharge_slowdown
|
||||
@@ -445,8 +445,9 @@
|
||||
name = "flesh mass"
|
||||
icon_state = "lingspacesuit"
|
||||
desc = "A huge, bulky mass of pressure and temperature-resistant organic tissue, evolved to facilitate space travel."
|
||||
flags_1 = STOPSPRESSUREDMAGE_1 | NODROP_1 | DROPDEL_1 //Not THICKMATERIAL_1 because it's organic tissue, so if somebody tries to inject something into it, it still ends up in your blood. (also balance but muh fluff)
|
||||
allowed = list(/obj/item/device/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/oxygen)
|
||||
flags_1 = NODROP_1 | DROPDEL_1
|
||||
clothing_flags = STOPSPRESSUREDAMAGE //Not THICKMATERIAL because it's organic tissue, so if somebody tries to inject something into it, it still ends up in your blood. (also balance but muh fluff)
|
||||
allowed = list(/obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/oxygen)
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 90, "acid" = 90) //No armor at all.
|
||||
|
||||
/obj/item/clothing/suit/space/changeling/Initialize()
|
||||
@@ -464,7 +465,8 @@
|
||||
name = "flesh mass"
|
||||
icon_state = "lingspacehelmet"
|
||||
desc = "A covering of pressure and temperature-resistant organic tissue with a glass-like chitin front."
|
||||
flags_1 = STOPSPRESSUREDMAGE_1 | NODROP_1 | DROPDEL_1 //Again, no THICKMATERIAL_1.
|
||||
flags_1 = NODROP_1 | DROPDEL_1
|
||||
clothing_flags = STOPSPRESSUREDAMAGE
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 90, "acid" = 90)
|
||||
flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH
|
||||
|
||||
|
||||
@@ -29,8 +29,12 @@
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/revive/can_be_used_by(mob/living/user)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
if(user.has_trait(CHANGELING_DRAIN) || ((user.stat != DEAD) && !(user.has_trait(TRAIT_FAKEDEATH))))
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
changeling.purchasedpowers -= src
|
||||
return 0
|
||||
. = ..()
|
||||
return FALSE
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/obj/effect/proc_holder/changeling/spiders
|
||||
name = "Spread Infestation"
|
||||
desc = "Our form divides, creating arachnids which will grow into deadly beasts."
|
||||
helptext = "The spiders are thoughtless creatures, and may attack their creators when fully grown. Requires at least 5 DNA absorptions."
|
||||
chemical_cost = 45
|
||||
dna_cost = 1
|
||||
req_dna = 5
|
||||
|
||||
//Makes some spiderlings. Good for setting traps and causing general trouble.
|
||||
/obj/effect/proc_holder/changeling/spiders/sting_action(mob/user)
|
||||
spawn_atom_to_turf(/obj/structure/spider/spiderling/hunter, user, 2, FALSE)
|
||||
return TRUE
|
||||
/obj/effect/proc_holder/changeling/spiders
|
||||
name = "Spread Infestation"
|
||||
desc = "Our form divides, creating arachnids which will grow into deadly beasts."
|
||||
helptext = "The spiders are thoughtless creatures, and may attack their creators when fully grown. Requires at least 3 DNA gained through Absorb, and not through DNA sting."
|
||||
chemical_cost = 45
|
||||
dna_cost = 1
|
||||
req_absorbs = 3
|
||||
|
||||
//Makes some spiderlings. Good for setting traps and causing general trouble.
|
||||
/obj/effect/proc_holder/changeling/spiders/sting_action(mob/user)
|
||||
spawn_atom_to_turf(/obj/structure/spider/spiderling/hunter, user, 2, FALSE)
|
||||
return TRUE
|
||||
|
||||
@@ -214,19 +214,19 @@
|
||||
/obj/effect/proc_holder/changeling/sting/LSD
|
||||
name = "Hallucination Sting"
|
||||
desc = "Causes terror in the target."
|
||||
helptext = "We evolve the ability to sting a target with a powerful hallucinogenic chemical. The target does not notice they have been stung, and the effect occurs after 30 to 60 seconds."
|
||||
helptext = "We evolve the ability to sting a target with a powerful hallucinogenic chemical. The target does not notice they have been stung, and the effect begins after a few seconds."
|
||||
sting_icon = "sting_lsd"
|
||||
chemical_cost = 10
|
||||
dna_cost = 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/LSD/sting_action(mob/user, mob/living/carbon/target)
|
||||
add_logs(user, target, "stung", "LSD sting")
|
||||
addtimer(CALLBACK(src, .proc/hallucination_time, target), rand(300,600))
|
||||
addtimer(CALLBACK(src, .proc/hallucination_time, target), rand(100,200))
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/LSD/proc/hallucination_time(mob/living/carbon/target)
|
||||
if(target)
|
||||
target.hallucination = max(400, target.hallucination)
|
||||
target.hallucination = max(90, target.hallucination)
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/cryo
|
||||
name = "Cryogenic Sting"
|
||||
|
||||
@@ -72,6 +72,6 @@
|
||||
var/mob/living/L = AM
|
||||
L.overlay_fullscreen("flash", /obj/screen/fullscreen/flash/static)
|
||||
L.clear_fullscreen("flash", 5)
|
||||
var/obj/item/device/transfer_valve/TTV = locate() in L.GetAllContents()
|
||||
var/obj/item/transfer_valve/TTV = locate() in L.GetAllContents()
|
||||
if(TTV)
|
||||
to_chat(L, "<span class='userdanger'>The air resonates with the Ark's presence; your explosives will be significantly dampened here!</span>")
|
||||
|
||||
@@ -21,23 +21,23 @@
|
||||
/obj/item/clothing/head/helmet/clockwork/ratvar_act()
|
||||
if(GLOB.ratvar_awakens)
|
||||
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 100, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 100)
|
||||
flags_1 |= STOPSPRESSUREDMAGE_1
|
||||
clothing_flags |= STOPSPRESSUREDAMAGE
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else if(GLOB.ratvar_approaches)
|
||||
armor = list("melee" = 70, "bullet" = 80, "laser" = -15, "energy" = 25, "bomb" = 70, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
|
||||
flags_1 |= STOPSPRESSUREDMAGE_1
|
||||
clothing_flags |= STOPSPRESSUREDAMAGE
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else
|
||||
armor = list("melee" = 60, "bullet" = 70, "laser" = -25, "energy" = 0, "bomb" = 60, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
|
||||
flags_1 &= ~STOPSPRESSUREDMAGE_1
|
||||
clothing_flags &= ~STOPSPRESSUREDAMAGE
|
||||
max_heat_protection_temperature = initial(max_heat_protection_temperature)
|
||||
min_cold_protection_temperature = initial(min_cold_protection_temperature)
|
||||
|
||||
/obj/item/clothing/head/helmet/clockwork/equipped(mob/living/user, slot)
|
||||
..()
|
||||
if(slot == slot_head && !is_servant_of_ratvar(user))
|
||||
if(slot == SLOT_HEAD && !is_servant_of_ratvar(user))
|
||||
if(!iscultist(user))
|
||||
to_chat(user, "<span class='heavy_brass'>\"Now now, this is for my servants, not you.\"</span>")
|
||||
user.visible_message("<span class='warning'>As [user] puts [src] on, it flickers off their head!</span>", "<span class='warning'>The helmet flickers off your head, leaving only nausea!</span>")
|
||||
@@ -68,7 +68,7 @@
|
||||
heat_protection = CHEST|GROIN|LEGS
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
armor = list("melee" = 60, "bullet" = 70, "laser" = -25, "energy" = 0, "bomb" = 60, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
|
||||
allowed = list(/obj/item/clockwork, /obj/item/clothing/glasses/wraith_spectacles, /obj/item/clothing/glasses/judicial_visor, /obj/item/device/mmi/posibrain/soul_vessel)
|
||||
allowed = list(/obj/item/clockwork, /obj/item/clothing/glasses/wraith_spectacles, /obj/item/clothing/glasses/judicial_visor, /obj/item/mmi/posibrain/soul_vessel)
|
||||
|
||||
/obj/item/clothing/suit/armor/clockwork/Initialize()
|
||||
. = ..()
|
||||
@@ -82,17 +82,17 @@
|
||||
/obj/item/clothing/suit/armor/clockwork/ratvar_act()
|
||||
if(GLOB.ratvar_awakens)
|
||||
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 100, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 100)
|
||||
flags_1 |= STOPSPRESSUREDMAGE_1
|
||||
clothing_flags |= STOPSPRESSUREDAMAGE
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else if(GLOB.ratvar_approaches)
|
||||
armor = list("melee" = 70, "bullet" = 80, "laser" = -15, "energy" = 25, "bomb" = 70, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
|
||||
flags_1 |= STOPSPRESSUREDMAGE_1
|
||||
clothing_flags |= STOPSPRESSUREDAMAGE
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else
|
||||
armor = list("melee" = 60, "bullet" = 70, "laser" = -25, "energy" = 0, "bomb" = 60, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
|
||||
flags_1 &= ~STOPSPRESSUREDMAGE_1
|
||||
clothing_flags &= ~STOPSPRESSUREDAMAGE
|
||||
max_heat_protection_temperature = initial(max_heat_protection_temperature)
|
||||
min_cold_protection_temperature = initial(min_cold_protection_temperature)
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
|
||||
/obj/item/clothing/suit/armor/clockwork/equipped(mob/living/user, slot)
|
||||
..()
|
||||
if(slot == slot_wear_suit && !is_servant_of_ratvar(user))
|
||||
if(slot == SLOT_WEAR_SUIT && !is_servant_of_ratvar(user))
|
||||
if(!iscultist(user))
|
||||
to_chat(user, "<span class='heavy_brass'>\"Now now, this is for my servants, not you.\"</span>")
|
||||
user.visible_message("<span class='warning'>As [user] puts [src] on, it flickers off their body!</span>", "<span class='warning'>The curiass flickers off your body, leaving only nausea!</span>")
|
||||
@@ -148,12 +148,12 @@
|
||||
/obj/item/clothing/gloves/clockwork/ratvar_act()
|
||||
if(GLOB.ratvar_awakens)
|
||||
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 100, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 100)
|
||||
flags_1 |= STOPSPRESSUREDMAGE_1
|
||||
clothing_flags |= STOPSPRESSUREDAMAGE
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else
|
||||
armor = list("melee" = 80, "bullet" = 70, "laser" = -25, "energy" = 0, "bomb" = 60, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
|
||||
flags_1 &= ~STOPSPRESSUREDMAGE_1
|
||||
clothing_flags &= ~STOPSPRESSUREDAMAGE
|
||||
max_heat_protection_temperature = initial(max_heat_protection_temperature)
|
||||
min_cold_protection_temperature = initial(min_cold_protection_temperature)
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
|
||||
/obj/item/clothing/gloves/clockwork/equipped(mob/living/user, slot)
|
||||
..()
|
||||
if(slot == slot_gloves && !is_servant_of_ratvar(user))
|
||||
if(slot == SLOT_GLOVES && !is_servant_of_ratvar(user))
|
||||
if(!iscultist(user))
|
||||
to_chat(user, "<span class='heavy_brass'>\"Now now, this is for my servants, not you.\"</span>")
|
||||
user.visible_message("<span class='warning'>As [user] puts [src] on, it flickers off their arms!</span>", "<span class='warning'>The gauntlets flicker off your arms, leaving only nausea!</span>")
|
||||
@@ -203,9 +203,9 @@
|
||||
|
||||
/obj/item/clothing/shoes/clockwork/ratvar_act()
|
||||
if(GLOB.ratvar_awakens)
|
||||
flags_1 |= NOSLIP_1
|
||||
clothing_flags |= NOSLIP
|
||||
else
|
||||
flags_1 &= ~NOSLIP_1
|
||||
clothing_flags &= ~NOSLIP
|
||||
|
||||
/obj/item/clothing/shoes/clockwork/mob_can_equip(mob/M, mob/equipper, slot, disable_warning = 0)
|
||||
if(equipper && !is_servant_of_ratvar(equipper))
|
||||
@@ -214,7 +214,7 @@
|
||||
|
||||
/obj/item/clothing/shoes/clockwork/equipped(mob/living/user, slot)
|
||||
..()
|
||||
if(slot == slot_shoes && !is_servant_of_ratvar(user))
|
||||
if(slot == SLOT_SHOES && !is_servant_of_ratvar(user))
|
||||
if(!iscultist(user))
|
||||
to_chat(user, "<span class='heavy_brass'>\"Now now, this is for my servants, not you.\"</span>")
|
||||
user.visible_message("<span class='warning'>As [user] puts [src] on, it flickers off their feet!</span>", "<span class='warning'>The treads flicker off your feet, leaving only nausea!</span>")
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
righthand_file = 'icons/mob/inhands/antag/clockwork_righthand.dmi'
|
||||
var/inhand_overlay //If applicable, this overlay will be applied to the slab's inhand
|
||||
|
||||
slot_flags = SLOT_BELT
|
||||
slot_flags = ITEM_SLOT_BELT
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
var/busy //If the slab is currently being used by something
|
||||
|
||||
@@ -115,4 +115,4 @@
|
||||
S.no_cost = TRUE
|
||||
if(seasonal_hat && seasonal_hat != "none")
|
||||
var/obj/item/hat = new seasonal_hat(construct)
|
||||
construct.equip_to_slot_or_del(hat, slot_head)
|
||||
construct.equip_to_slot_or_del(hat, SLOT_HEAD)
|
||||
|
||||
@@ -28,13 +28,13 @@
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/glasses/judicial_visor/item_action_slot_check(slot, mob/user)
|
||||
if(slot != slot_glasses)
|
||||
if(slot != SLOT_GLASSES)
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/glasses/judicial_visor/equipped(mob/living/user, slot)
|
||||
..()
|
||||
if(slot != slot_glasses)
|
||||
if(slot != SLOT_GLASSES)
|
||||
update_status(FALSE)
|
||||
if(blaster.ranged_ability_user)
|
||||
blaster.remove_ranged_ability()
|
||||
@@ -55,13 +55,13 @@
|
||||
addtimer(CALLBACK(src, .proc/check_on_mob, user), 1) //dropped is called before the item is out of the slot, so we need to check slightly later
|
||||
|
||||
/obj/item/clothing/glasses/judicial_visor/proc/check_on_mob(mob/user)
|
||||
if(user && src != user.get_item_by_slot(slot_glasses)) //if we happen to check and we AREN'T in the slot, we need to remove our shit from whoever we got dropped from
|
||||
if(user && src != user.get_item_by_slot(SLOT_GLASSES)) //if we happen to check and we AREN'T in the slot, we need to remove our shit from whoever we got dropped from
|
||||
update_status(FALSE)
|
||||
if(blaster.ranged_ability_user)
|
||||
blaster.remove_ranged_ability()
|
||||
|
||||
/obj/item/clothing/glasses/judicial_visor/attack_self(mob/user)
|
||||
if(is_servant_of_ratvar(user) && src == user.get_item_by_slot(slot_glasses))
|
||||
if(is_servant_of_ratvar(user) && src == user.get_item_by_slot(SLOT_GLASSES))
|
||||
blaster.toggle(user)
|
||||
|
||||
/obj/item/clothing/glasses/judicial_visor/proc/update_status(change_to)
|
||||
@@ -89,7 +89,7 @@
|
||||
if(!src)
|
||||
return 0
|
||||
recharging = FALSE
|
||||
if(user && src == user.get_item_by_slot(slot_glasses))
|
||||
if(user && src == user.get_item_by_slot(SLOT_GLASSES))
|
||||
to_chat(user, "<span class='brass'>Your [name] hums. It is ready.</span>")
|
||||
else
|
||||
active = FALSE
|
||||
@@ -115,7 +115,7 @@
|
||||
/obj/effect/proc_holder/judicial_visor/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(..())
|
||||
return
|
||||
if(ranged_ability_user.incapacitated() || !visor || visor != ranged_ability_user.get_item_by_slot(slot_glasses))
|
||||
if(ranged_ability_user.incapacitated() || !visor || visor != ranged_ability_user.get_item_by_slot(SLOT_GLASSES))
|
||||
remove_ranged_ability()
|
||||
return
|
||||
|
||||
@@ -151,6 +151,7 @@
|
||||
desc = "You get the feeling that you shouldn't be standing here."
|
||||
clockwork_desc = "A sigil that will soon erupt and smite any unenlightened nearby."
|
||||
icon = 'icons/effects/96x96.dmi'
|
||||
icon_state = ""
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
layer = BELOW_MOB_LAYER
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//Soul vessel: An ancient positronic brain that serves only Ratvar.
|
||||
/obj/item/device/mmi/posibrain/soul_vessel
|
||||
/obj/item/mmi/posibrain/soul_vessel
|
||||
name = "soul vessel"
|
||||
desc = "A heavy brass cube, three inches to a side, with a single protruding cogwheel."
|
||||
var/clockwork_desc = "A soul vessel, an ancient relic that can attract the souls of the damned or simply rip a mind from an unconscious or dead human.\n\
|
||||
@@ -25,35 +25,35 @@
|
||||
force_replace_ai_name = TRUE
|
||||
overrides_aicore_laws = TRUE
|
||||
|
||||
/obj/item/device/mmi/posibrain/soul_vessel/Initialize()
|
||||
/obj/item/mmi/posibrain/soul_vessel/Initialize()
|
||||
. = ..()
|
||||
radio.on = FALSE
|
||||
laws = new /datum/ai_laws/ratvar()
|
||||
braintype = picked_name
|
||||
GLOB.all_clockwork_objects += src
|
||||
|
||||
/obj/item/device/mmi/posibrain/soul_vessel/Destroy()
|
||||
/obj/item/mmi/posibrain/soul_vessel/Destroy()
|
||||
GLOB.all_clockwork_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/item/device/mmi/posibrain/soul_vessel/examine(mob/user)
|
||||
/obj/item/mmi/posibrain/soul_vessel/examine(mob/user)
|
||||
if((is_servant_of_ratvar(user) || isobserver(user)) && clockwork_desc)
|
||||
desc = clockwork_desc
|
||||
..()
|
||||
desc = initial(desc)
|
||||
|
||||
/obj/item/device/mmi/posibrain/soul_vessel/transfer_personality(mob/candidate)
|
||||
/obj/item/mmi/posibrain/soul_vessel/transfer_personality(mob/candidate)
|
||||
. = ..()
|
||||
if(.)
|
||||
add_servant_of_ratvar(brainmob, TRUE)
|
||||
|
||||
/obj/item/device/mmi/posibrain/soul_vessel/attack_self(mob/living/user)
|
||||
/obj/item/mmi/posibrain/soul_vessel/attack_self(mob/living/user)
|
||||
if(!is_servant_of_ratvar(user))
|
||||
to_chat(user, "<span class='warning'>You fiddle around with [src], to no avail.</span>")
|
||||
return FALSE
|
||||
..()
|
||||
|
||||
/obj/item/device/mmi/posibrain/soul_vessel/attack(mob/living/target, mob/living/carbon/human/user)
|
||||
/obj/item/mmi/posibrain/soul_vessel/attack(mob/living/target, mob/living/carbon/human/user)
|
||||
if(!is_servant_of_ratvar(user) || !ishuman(target))
|
||||
..()
|
||||
return
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
|
||||
/obj/item/clothing/glasses/wraith_spectacles/equipped(mob/living/user, slot)
|
||||
..()
|
||||
if(slot != slot_glasses || up)
|
||||
if(slot != SLOT_GLASSES || up)
|
||||
return
|
||||
if(user.has_trait(TRAIT_BLIND))
|
||||
to_chat(user, "<span class='heavy_brass'>\"You're blind, idiot. Stop embarrassing yourself.\"</span>" )
|
||||
|
||||
@@ -160,18 +160,18 @@
|
||||
|
||||
/datum/action/innate/clockwork_armaments/Activate()
|
||||
var/do_message = 0
|
||||
var/obj/item/I = owner.get_item_by_slot(slot_wear_suit)
|
||||
var/obj/item/I = owner.get_item_by_slot(SLOT_WEAR_SUIT)
|
||||
if(remove_item_if_better(I, owner))
|
||||
do_message += owner.equip_to_slot_or_del(new/obj/item/clothing/suit/armor/clockwork(null), slot_wear_suit)
|
||||
I = owner.get_item_by_slot(slot_head)
|
||||
do_message += owner.equip_to_slot_or_del(new/obj/item/clothing/suit/armor/clockwork(null), SLOT_WEAR_SUIT)
|
||||
I = owner.get_item_by_slot(SLOT_HEAD)
|
||||
if(remove_item_if_better(I, owner))
|
||||
do_message += owner.equip_to_slot_or_del(new/obj/item/clothing/head/helmet/clockwork(null), slot_head)
|
||||
I = owner.get_item_by_slot(slot_gloves)
|
||||
do_message += owner.equip_to_slot_or_del(new/obj/item/clothing/head/helmet/clockwork(null), SLOT_HEAD)
|
||||
I = owner.get_item_by_slot(SLOT_GLOVES)
|
||||
if(remove_item_if_better(I, owner))
|
||||
do_message += owner.equip_to_slot_or_del(new/obj/item/clothing/gloves/clockwork(null), slot_gloves)
|
||||
I = owner.get_item_by_slot(slot_shoes)
|
||||
do_message += owner.equip_to_slot_or_del(new/obj/item/clothing/gloves/clockwork(null), SLOT_GLOVES)
|
||||
I = owner.get_item_by_slot(SLOT_SHOES)
|
||||
if(remove_item_if_better(I, owner))
|
||||
do_message += owner.equip_to_slot_or_del(new/obj/item/clothing/shoes/clockwork(null), slot_shoes)
|
||||
do_message += owner.equip_to_slot_or_del(new/obj/item/clothing/shoes/clockwork(null), SLOT_SHOES)
|
||||
if(do_message)
|
||||
owner.visible_message("<span class='warning'>Strange armor appears on [owner]!</span>", "<span class='heavy_brass'>A bright shimmer runs down your body, equipping you with Ratvarian armor.</span>")
|
||||
playsound(owner, 'sound/magic/clockwork/fellowship_armory.ogg', 15 * do_message, TRUE) //get sound loudness based on how much we equipped
|
||||
|
||||
@@ -159,7 +159,7 @@
|
||||
SSticker.mode.servants_of_ratvar -= owner
|
||||
SSticker.mode.update_servant_icons_removed(owner)
|
||||
if(!silent)
|
||||
owner.current.visible_message("<span class='deconversion_message'>[owner] seems to have remembered their true allegiance!</span>", null, null, null, owner.current)
|
||||
owner.current.visible_message("<span class='deconversion_message'>[owner.current] seems to have remembered [owner.current.p_their()] true allegiance!</span>", null, null, null, owner.current)
|
||||
to_chat(owner, "<span class='userdanger'>A cold, cold darkness flows through your mind, extinguishing the Justiciar's light and all of your memories as his servant.</span>")
|
||||
owner.current.log_message("<font color=#BE8700>Has renounced the cult of Ratvar!</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
owner.special_role = null
|
||||
|
||||
@@ -260,7 +260,7 @@
|
||||
if(!ishuman(target) || iscultist(target))
|
||||
return
|
||||
var/mob/living/carbon/human/H = target
|
||||
H.hallucination = max(H.hallucination, 240)
|
||||
H.hallucination = max(H.hallucination, 120)
|
||||
SEND_SOUND(ranged_ability_user, sound('sound/effects/ghost.ogg',0,1,50))
|
||||
var/image/C = image('icons/effects/cult_effects.dmi',H,"bloodsparkles", ABOVE_MOB_LAYER)
|
||||
add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/cult, "cult_apoc", C, FALSE)
|
||||
@@ -605,11 +605,11 @@
|
||||
uses--
|
||||
var/mob/living/carbon/C = target
|
||||
C.visible_message("<span class='warning'>Otherworldly armor suddenly appears on [C]!</span>")
|
||||
C.equip_to_slot_or_del(new /obj/item/clothing/under/color/black,slot_w_uniform)
|
||||
C.equip_to_slot_or_del(new /obj/item/clothing/head/culthood/alt(user), slot_head)
|
||||
C.equip_to_slot_or_del(new /obj/item/clothing/suit/cultrobes/alt(user), slot_wear_suit)
|
||||
C.equip_to_slot_or_del(new /obj/item/clothing/shoes/cult/alt(user), slot_shoes)
|
||||
C.equip_to_slot_or_del(new /obj/item/storage/backpack/cultpack(user), slot_back)
|
||||
C.equip_to_slot_or_del(new /obj/item/clothing/under/color/black,SLOT_W_UNIFORM)
|
||||
C.equip_to_slot_or_del(new /obj/item/clothing/head/culthood/alt(user), SLOT_HEAD)
|
||||
C.equip_to_slot_or_del(new /obj/item/clothing/suit/cultrobes/alt(user), SLOT_WEAR_SUIT)
|
||||
C.equip_to_slot_or_del(new /obj/item/clothing/shoes/cult/alt(user), SLOT_SHOES)
|
||||
C.equip_to_slot_or_del(new /obj/item/storage/backpack/cultpack(user), SLOT_BACK)
|
||||
if(C == user)
|
||||
qdel(src) //Clears the hands
|
||||
C.put_in_hands(new /obj/item/melee/cultblade(user))
|
||||
|
||||
@@ -81,9 +81,9 @@
|
||||
|
||||
/datum/antagonist/cult/proc/cult_give_item(obj/item/item_path, mob/living/carbon/human/mob)
|
||||
var/list/slots = list(
|
||||
"backpack" = slot_in_backpack,
|
||||
"left pocket" = slot_l_store,
|
||||
"right pocket" = slot_r_store
|
||||
"backpack" = SLOT_IN_BACKPACK,
|
||||
"left pocket" = SLOT_L_STORE,
|
||||
"right pocket" = SLOT_R_STORE
|
||||
)
|
||||
|
||||
var/T = new item_path(mob)
|
||||
@@ -128,7 +128,7 @@
|
||||
SSticker.mode.cult -= owner
|
||||
SSticker.mode.update_cult_icons_removed(owner)
|
||||
if(!silent)
|
||||
owner.current.visible_message("<span class='deconversion_message'>[owner.current] looks like [owner.current.p_they()] just reverted to their old faith!</span>", null, null, null, owner.current)
|
||||
owner.current.visible_message("<span class='deconversion_message'>[owner.current] looks like [owner.current.p_theyve()] just reverted to [owner.current.p_their()] old faith!</span>", null, null, null, owner.current)
|
||||
to_chat(owner.current, "<span class='userdanger'>An unfamiliar white light flashes through your mind, cleansing the taint of the Geometer and all your memories as her servant.</span>")
|
||||
owner.current.log_message("<font color=#960000>Has renounced the cult of Nar'Sie!</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
if(cult_team.blood_target && cult_team.blood_target_image && owner.current.client)
|
||||
|
||||
@@ -178,8 +178,8 @@
|
||||
playsound(mobloc, 'sound/magic/exit_blood.ogg', 100, 1)
|
||||
if(B.current != owner)
|
||||
var/turf/final = pick(destinations)
|
||||
if(istype(B.current.loc, /obj/item/device/soulstone))
|
||||
var/obj/item/device/soulstone/S = B.current.loc
|
||||
if(istype(B.current.loc, /obj/item/soulstone))
|
||||
var/obj/item/soulstone/S = B.current.loc
|
||||
S.release_shades(owner)
|
||||
B.current.setDir(SOUTH)
|
||||
new /obj/effect/temp_visual/cult/blood(final)
|
||||
|
||||
@@ -33,10 +33,8 @@
|
||||
desc = "A sword humming with unholy energy. It glows with a dim red light."
|
||||
icon_state = "cultblade"
|
||||
item_state = "cultblade"
|
||||
lefthand_file = 'icons/mob/inhands/64x64_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/64x64_righthand.dmi'
|
||||
inhand_x_dimension = 64
|
||||
inhand_y_dimension = 64
|
||||
lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
|
||||
flags_1 = CONDUCT_1
|
||||
sharpness = IS_SHARP
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
@@ -73,8 +71,6 @@
|
||||
if(!iscultist(user))
|
||||
if(!is_servant_of_ratvar(user))
|
||||
to_chat(user, "<span class='cultlarge'>\"I wouldn't advise that.\"</span>")
|
||||
to_chat(user, "<span class='warning'>An overwhelming sense of nausea overpowers you!</span>")
|
||||
user.Dizzy(120)
|
||||
else
|
||||
to_chat(user, "<span class='cultlarge'>\"One of Ratvar's toys is trying to play with things [user.p_they()] shouldn't. Cute.\"</span>")
|
||||
to_chat(user, "<span class='userdanger'>A horrible force yanks at your arm!</span>")
|
||||
@@ -138,10 +134,7 @@
|
||||
if(!iscultist(user))
|
||||
if(!is_servant_of_ratvar(user))
|
||||
to_chat(user, "<span class='cultlarge'>\"I wouldn't advise that.\"</span>")
|
||||
to_chat(user, "<span class='warning'>An overwhelming sense of nausea overpowers you!</span>")
|
||||
user.Dizzy(80)
|
||||
user.dropItemToGround(src, TRUE)
|
||||
user.Knockdown(30)
|
||||
force = 5
|
||||
return
|
||||
else
|
||||
to_chat(user, "<span class='cultlarge'>\"One of Ratvar's toys is trying to play with things [user.p_they()] shouldn't. Cute.\"</span>")
|
||||
@@ -151,6 +144,7 @@
|
||||
user.dropItemToGround(src, TRUE)
|
||||
user.Knockdown(50)
|
||||
return
|
||||
force = initial(force)
|
||||
jaunt.Grant(user, src)
|
||||
linked_action.Grant(user, src)
|
||||
user.update_icons()
|
||||
@@ -189,12 +183,12 @@
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
if(H.stat != CONSCIOUS)
|
||||
var/obj/item/device/soulstone/SS = new /obj/item/device/soulstone(src)
|
||||
var/obj/item/soulstone/SS = new /obj/item/soulstone(src)
|
||||
SS.attack(H, user)
|
||||
if(!LAZYLEN(SS.contents))
|
||||
qdel(SS)
|
||||
if(istype(target, /obj/structure/constructshell) && contents.len)
|
||||
var/obj/item/device/soulstone/SS = contents[1]
|
||||
var/obj/item/soulstone/SS = contents[1]
|
||||
if(istype(SS))
|
||||
SS.transfer_soul("CONSTRUCT",target,user)
|
||||
qdel(SS)
|
||||
@@ -484,14 +478,14 @@
|
||||
color = "#333333"
|
||||
list_reagents = list("unholywater" = 50)
|
||||
|
||||
/obj/item/device/shuttle_curse
|
||||
/obj/item/shuttle_curse
|
||||
name = "cursed orb"
|
||||
desc = "You peer within this smokey orb and glimpse terrible fates befalling the escape shuttle."
|
||||
icon = 'icons/obj/cult.dmi'
|
||||
icon_state ="shuttlecurse"
|
||||
var/global/curselimit = 0
|
||||
|
||||
/obj/item/device/shuttle_curse/attack_self(mob/living/user)
|
||||
/obj/item/shuttle_curse/attack_self(mob/living/user)
|
||||
if(!iscultist(user))
|
||||
user.dropItemToGround(src, TRUE)
|
||||
user.Knockdown(100)
|
||||
@@ -538,28 +532,28 @@
|
||||
priority_announce("[message]", "System Failure", 'sound/misc/notice1.ogg')
|
||||
curselimit++
|
||||
|
||||
/obj/item/device/cult_shift
|
||||
/obj/item/cult_shift
|
||||
name = "veil shifter"
|
||||
desc = "This relic instantly teleports you, and anything you're pulling, forward by a moderate distance."
|
||||
icon = 'icons/obj/cult.dmi'
|
||||
icon_state ="shifter"
|
||||
var/uses = 4
|
||||
|
||||
/obj/item/device/cult_shift/examine(mob/user)
|
||||
/obj/item/cult_shift/examine(mob/user)
|
||||
..()
|
||||
if(uses)
|
||||
to_chat(user, "<span class='cult'>It has [uses] use\s remaining.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='cult'>It seems drained.</span>")
|
||||
|
||||
/obj/item/device/cult_shift/proc/handle_teleport_grab(turf/T, mob/user)
|
||||
/obj/item/cult_shift/proc/handle_teleport_grab(turf/T, mob/user)
|
||||
var/mob/living/carbon/C = user
|
||||
if(C.pulling)
|
||||
var/atom/movable/pulled = C.pulling
|
||||
pulled.forceMove(T)
|
||||
. = pulled
|
||||
|
||||
/obj/item/device/cult_shift/attack_self(mob/user)
|
||||
/obj/item/cult_shift/attack_self(mob/user)
|
||||
if(!uses || !iscarbon(user))
|
||||
to_chat(user, "<span class='warning'>\The [src] is dull and unmoving in your hands.</span>")
|
||||
return
|
||||
@@ -592,7 +586,7 @@
|
||||
else
|
||||
to_chat(C, "<span class='danger'>The veil cannot be torn here!</span>")
|
||||
|
||||
/obj/item/device/flashlight/flare/culttorch
|
||||
/obj/item/flashlight/flare/culttorch
|
||||
name = "void torch"
|
||||
desc = "Used by veteran cultists to instantly transport items to their needful bretheren."
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
@@ -605,7 +599,7 @@
|
||||
on = TRUE
|
||||
var/charges = 5
|
||||
|
||||
/obj/item/device/flashlight/flare/culttorch/afterattack(atom/movable/A, mob/user, proximity)
|
||||
/obj/item/flashlight/flare/culttorch/afterattack(atom/movable/A, mob/user, proximity)
|
||||
if(!proximity)
|
||||
return
|
||||
if(!iscultist(user))
|
||||
|
||||
@@ -258,10 +258,10 @@
|
||||
if("Zealot's Blindfold")
|
||||
pickedtype += /obj/item/clothing/glasses/hud/health/night/cultblind
|
||||
if("Shuttle Curse")
|
||||
pickedtype += /obj/item/device/shuttle_curse
|
||||
pickedtype += /obj/item/shuttle_curse
|
||||
if("Veil Walker Set")
|
||||
pickedtype += /obj/item/device/cult_shift
|
||||
pickedtype += /obj/item/device/flashlight/flare/culttorch
|
||||
pickedtype += /obj/item/cult_shift
|
||||
pickedtype += /obj/item/flashlight/flare/culttorch
|
||||
if(src && !QDELETED(src) && anchored && pickedtype.len && Adjacent(user) && !user.incapacitated() && iscultist(user) && cooldowntime <= world.time)
|
||||
cooldowntime = world.time + 2400
|
||||
for(var/N in pickedtype)
|
||||
|
||||
@@ -144,7 +144,8 @@ This file contains the cult dagger and rune list code
|
||||
if(locate(/obj/effect/rune) in T)
|
||||
to_chat(user, "<span class='cult'>There is already a rune here.</span>")
|
||||
return FALSE
|
||||
if(!is_station_level(T.z) && !is_mining_level(T.z))
|
||||
var/area/A = get_area(T)
|
||||
if((!is_station_level(T.z) && !is_mining_level(T.z)) || (A && !A.blob_allowed))
|
||||
to_chat(user, "<span class='warning'>The veil is not weak enough here.</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -299,7 +299,7 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
else
|
||||
to_chat(M, "<span class='cultlarge'>\"I accept this meager sacrifice.\"</span>")
|
||||
|
||||
var/obj/item/device/soulstone/stone = new /obj/item/device/soulstone(get_turf(src))
|
||||
var/obj/item/soulstone/stone = new /obj/item/soulstone(get_turf(src))
|
||||
if(sacrificial.mind && !sacrificial.suiciding)
|
||||
stone.invisibility = INVISIBILITY_MAXIMUM //so it's not picked up during transfer_soul()
|
||||
stone.transfer_soul("FORCE", sacrificial, usr)
|
||||
@@ -708,6 +708,11 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
fail_invoke()
|
||||
log_game("Summon Cultist rune failed - target died")
|
||||
return
|
||||
if(cultist_to_summon.pulledby || cultist_to_summon.buckled)
|
||||
to_chat(user, "<span class='cult italic'>[cultist_to_summon] is being held in place!</span>")
|
||||
fail_invoke()
|
||||
log_game("Summon Cultist rune failed - target restrained")
|
||||
return
|
||||
if(!iscultist(cultist_to_summon))
|
||||
to_chat(user, "<span class='cult italic'>[cultist_to_summon] is not a follower of the Geometer!</span>")
|
||||
fail_invoke()
|
||||
@@ -1056,7 +1061,7 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
/proc/hudFix(mob/living/carbon/human/target)
|
||||
if(!target || !target.client)
|
||||
return
|
||||
var/obj/O = target.get_item_by_slot(slot_glasses)
|
||||
var/obj/O = target.get_item_by_slot(SLOT_GLASSES)
|
||||
if(istype(O, /obj/item/clothing/glasses/hud/security))
|
||||
var/datum/atom_hud/AH = GLOB.huds[DATA_HUD_SECURITY_ADVANCED]
|
||||
AH.add_hud_to(target)
|
||||
|
||||
@@ -456,10 +456,10 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
|
||||
return -1
|
||||
currentMob.change_mob_type( /mob/living/carbon/human, targetturf, null, 1)
|
||||
var/mob/living/carbon/human/H = owner.current
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/under/lawyer/black(H), slot_w_uniform)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/laceup(H), slot_shoes)
|
||||
H.equip_to_slot_or_del(new /obj/item/storage/briefcase(H), slot_hands)
|
||||
H.equip_to_slot_or_del(new /obj/item/pen(H), slot_l_store)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/under/lawyer/black(H), SLOT_W_UNIFORM)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/laceup(H), SLOT_SHOES)
|
||||
H.equip_to_slot_or_del(new /obj/item/storage/briefcase(H), SLOT_HANDS)
|
||||
H.equip_to_slot_or_del(new /obj/item/pen(H), SLOT_L_STORE)
|
||||
if(SOULVALUE >= BLOOD_THRESHOLD)
|
||||
H.set_species(/datum/species/lizard, 1)
|
||||
H.underwear = "Nude"
|
||||
|
||||
@@ -46,11 +46,11 @@
|
||||
qdel(I)
|
||||
for(var/obj/item/I in H.held_items)
|
||||
qdel(I)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/under/kilt/highlander(H), slot_w_uniform)
|
||||
H.equip_to_slot_or_del(new /obj/item/device/radio/headset/heads/captain(H), slot_ears)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/head/beret/highlander(H), slot_head)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/combat(H), slot_shoes)
|
||||
H.equip_to_slot_or_del(new /obj/item/pinpointer/nuke(H), slot_l_store)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/under/kilt/highlander(H), SLOT_W_UNIFORM)
|
||||
H.equip_to_slot_or_del(new /obj/item/radio/headset/heads/captain(H), SLOT_EARS)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/head/beret/highlander(H), SLOT_HEAD)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/combat(H), SLOT_SHOES)
|
||||
H.equip_to_slot_or_del(new /obj/item/pinpointer/nuke(H), SLOT_L_STORE)
|
||||
for(var/obj/item/pinpointer/nuke/P in H)
|
||||
P.attack_self(H)
|
||||
var/obj/item/card/id/W = new(H)
|
||||
@@ -61,7 +61,7 @@
|
||||
W.registered_name = H.real_name
|
||||
W.flags_1 |= NODROP_1
|
||||
W.update_label(H.real_name)
|
||||
H.equip_to_slot_or_del(W, slot_wear_id)
|
||||
H.equip_to_slot_or_del(W, SLOT_WEAR_ID)
|
||||
|
||||
sword = new(H)
|
||||
if(!GLOB.highlander)
|
||||
|
||||
@@ -27,12 +27,14 @@
|
||||
see_in_dark = 8
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
vision_range = 1 // Only attack when target is close
|
||||
wander = 0
|
||||
wander = FALSE
|
||||
attacktext = "glomps"
|
||||
attack_sound = 'sound/effects/blobattack.ogg'
|
||||
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 2)
|
||||
|
||||
var/morphed = FALSE
|
||||
var/melee_damage_disguised = 0
|
||||
var/eat_while_disguised = FALSE
|
||||
var/atom/movable/form = null
|
||||
var/morph_time = 0
|
||||
var/static/list/blacklist_typecache = typecacheof(list(
|
||||
@@ -75,11 +77,14 @@
|
||||
return !is_type_in_typecache(A, blacklist_typecache) && (isobj(A) || ismob(A))
|
||||
|
||||
/mob/living/simple_animal/hostile/morph/proc/eat(atom/movable/A)
|
||||
if(morphed && !eat_while_disguised)
|
||||
to_chat(src, "<span class='warning'>You can not eat anything while you are disguised!</span>")
|
||||
return FALSE
|
||||
if(A && A.loc != src)
|
||||
visible_message("<span class='warning'>[src] swallows [A] whole!</span>")
|
||||
A.forceMove(src)
|
||||
return 1
|
||||
return 0
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/morph/ShiftClickOn(atom/movable/A)
|
||||
if(morph_time <= world.time && !stat)
|
||||
@@ -109,8 +114,8 @@
|
||||
pixel_x = initial(pixel_x)
|
||||
|
||||
//Morphed is weaker
|
||||
melee_damage_lower = 5
|
||||
melee_damage_upper = 5
|
||||
melee_damage_lower = melee_damage_disguised
|
||||
melee_damage_upper = melee_damage_disguised
|
||||
speed = 0
|
||||
|
||||
morph_time = world.time + MORPH_COOLDOWN
|
||||
@@ -181,10 +186,13 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/morph/can_track(mob/living/user)
|
||||
if(morphed)
|
||||
return 0
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/morph/AttackingTarget()
|
||||
if(morphed && !melee_damage_disguised)
|
||||
to_chat(src, "<span class='warning'>You can not attack while disguised!</span>")
|
||||
return
|
||||
if(isliving(target)) //Eat Corpses to regen health
|
||||
var/mob/living/L = target
|
||||
if(L.stat == DEAD)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
GLOBAL_LIST_EMPTY(jam_on_wardec)
|
||||
|
||||
/obj/item/device/nuclear_challenge
|
||||
/obj/item/nuclear_challenge
|
||||
name = "Declaration of War (Challenge Mode)"
|
||||
icon_state = "gangtool-red"
|
||||
item_state = "radio"
|
||||
@@ -15,9 +15,9 @@ GLOBAL_LIST_EMPTY(jam_on_wardec)
|
||||
Such a brazen move will attract the attention of powerful benefactors within the Syndicate, who will supply your team with a massive amount of bonus telecrystals. \
|
||||
Must be used within five minutes, or your benefactors will lose interest."
|
||||
var/declaring_war = FALSE
|
||||
var/uplink_type = /obj/item/device/radio/uplink/nuclear
|
||||
var/uplink_type = /obj/item/radio/uplink/nuclear
|
||||
|
||||
/obj/item/device/nuclear_challenge/attack_self(mob/living/user)
|
||||
/obj/item/nuclear_challenge/attack_self(mob/living/user)
|
||||
if(!check_allowed(user))
|
||||
return
|
||||
|
||||
@@ -66,7 +66,7 @@ GLOBAL_LIST_EMPTY(jam_on_wardec)
|
||||
|
||||
qdel(src)
|
||||
|
||||
/obj/item/device/nuclear_challenge/proc/check_allowed(mob/living/user)
|
||||
/obj/item/nuclear_challenge/proc/check_allowed(mob/living/user)
|
||||
if(declaring_war)
|
||||
to_chat(user, "You are already in the process of declaring war! Make your mind up.")
|
||||
return FALSE
|
||||
@@ -86,8 +86,8 @@ GLOBAL_LIST_EMPTY(jam_on_wardec)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/device/nuclear_challenge/clownops
|
||||
uplink_type = /obj/item/device/radio/uplink/clownop
|
||||
/obj/item/nuclear_challenge/clownops
|
||||
uplink_type = /obj/item/radio/uplink/clownop
|
||||
|
||||
#undef CHALLENGE_TELECRYSTALS
|
||||
#undef CHALLENGE_TIME_LIMIT
|
||||
|
||||
@@ -501,16 +501,37 @@ This is here to make the tiles around the station mininuke change when it's arme
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 30, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
var/fake = FALSE
|
||||
var/turf/lastlocation
|
||||
var/last_disk_move
|
||||
|
||||
/obj/item/disk/nuclear/Initialize()
|
||||
. = ..()
|
||||
if(!fake)
|
||||
GLOB.poi_list |= src
|
||||
last_disk_move = world.time
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/disk/nuclear/ComponentInitialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/stationloving, !fake)
|
||||
|
||||
/obj/item/disk/nuclear/process()
|
||||
if(fake)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
CRASH("A fake nuke disk tried to call process(). Who the fuck and how the fuck")
|
||||
var/turf/newturf = get_turf(src)
|
||||
if(newturf && lastlocation == newturf)
|
||||
if(last_disk_move < world.time - 5000 && prob((world.time - 5000 - last_disk_move)*0.00001))
|
||||
var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control
|
||||
if(istype(loneop))
|
||||
loneop.weight += 1
|
||||
else
|
||||
lastlocation = newturf
|
||||
last_disk_move = world.time
|
||||
var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control
|
||||
if(istype(loneop) && prob(loneop.weight))
|
||||
loneop.weight = max(loneop.weight - 1, 0)
|
||||
|
||||
/obj/item/disk/nuclear/examine(mob/user)
|
||||
. = ..()
|
||||
if(!fake)
|
||||
|
||||
@@ -218,7 +218,7 @@
|
||||
else //Already set by admins/something else?
|
||||
nuke_team.memorized_code = nuke.r_code
|
||||
else
|
||||
stack_trace("Station self destruct ot found during lone op team creation.")
|
||||
stack_trace("Station self destruct not found during lone op team creation.")
|
||||
nuke_team.memorized_code = null
|
||||
|
||||
/datum/antagonist/nukeop/reinforcement
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
to_chat(src, "<b>You are invincible and invisible to everyone but other ghosts. Most abilities will reveal you, rendering you vulnerable.</b>")
|
||||
to_chat(src, "<b>To function, you are to drain the life essence from humans. This essence is a resource, as well as your health, and will power all of your abilities.</b>")
|
||||
to_chat(src, "<b><i>You do not remember anything of your past lives, nor will you remember anything about this one after your death.</i></b>")
|
||||
to_chat(src, "<b>Be sure to read the wiki page at https://tgstation13.org/wiki/Revenant to learn more.</b>")
|
||||
to_chat(src, "<b>Be sure to read <a href=\"https://tgstation13.org/wiki/Revenant\">the wiki page</a> to learn more.</b>")
|
||||
if(!generated_objectives_and_spells)
|
||||
generated_objectives_and_spells = TRUE
|
||||
mind.assigned_role = ROLE_REVENANT
|
||||
|
||||
@@ -290,7 +290,7 @@
|
||||
unlock_amount = 200
|
||||
action_icon_state = "malfunction"
|
||||
|
||||
//A note to future coders: do not replace this with an EMP because it will wreck malf AIs and gang dominators and everyone will hate you.
|
||||
//A note to future coders: do not replace this with an EMP because it will wreck malf AIs and everyone will hate you.
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
|
||||
if(attempt_cast(user))
|
||||
for(var/turf/T in targets)
|
||||
@@ -312,7 +312,7 @@
|
||||
new /obj/effect/temp_visual/revenant(human.loc)
|
||||
human.emp_act(EMP_HEAVY)
|
||||
for(var/obj/thing in T)
|
||||
if(istype(thing, /obj/machinery/dominator) || istype(thing, /obj/machinery/power/apc) || istype(thing, /obj/machinery/power/smes)) //Doesn't work on dominators, SMES and APCs, to prevent kekkery
|
||||
if(istype(thing, /obj/machinery/power/apc) || istype(thing, /obj/machinery/power/smes)) //Doesn't work on SMES and APCs, to prevent kekkery
|
||||
continue
|
||||
if(prob(20))
|
||||
if(prob(50))
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
|
||||
/datum/antagonist/rev/head/proc/admin_take_flash(mob/admin)
|
||||
var/list/L = owner.current.get_contents()
|
||||
var/obj/item/device/assembly/flash/flash = locate() in L
|
||||
var/obj/item/assembly/flash/flash = locate() in L
|
||||
if (!flash)
|
||||
to_chat(admin, "<span class='danger'>Deleting flash failed!</span>")
|
||||
return
|
||||
@@ -133,7 +133,7 @@
|
||||
|
||||
/datum/antagonist/rev/head/proc/admin_repair_flash(mob/admin)
|
||||
var/list/L = owner.current.get_contents()
|
||||
var/obj/item/device/assembly/flash/flash = locate() in L
|
||||
var/obj/item/assembly/flash/flash = locate() in L
|
||||
if (!flash)
|
||||
to_chat(admin, "<span class='danger'>Repairing flash failed!</span>")
|
||||
else
|
||||
@@ -201,12 +201,13 @@
|
||||
|
||||
/datum/antagonist/rev/farewell()
|
||||
if(ishuman(owner.current))
|
||||
owner.current.visible_message("<span class='deconversion_message'>[owner.current] looks like they just remembered their real allegiance!</span>", null, null, null, owner.current)
|
||||
owner.current.visible_message("<span class='deconversion_message'>[owner.current] looks like [owner.current.p_theyve()] just remembered [owner.current.p_their()] real allegiance!</span>", null, null, null, owner.current)
|
||||
to_chat(owner, "<span class='userdanger'>You are no longer a brainwashed revolutionary! Your memory is hazy from the time you were a rebel...the only thing you remember is the name of the one who brainwashed you...</span>")
|
||||
else if(issilicon(owner.current))
|
||||
owner.current.visible_message("<span class='deconversion_message'>The frame beeps contentedly, purging the hostile memory engram from the MMI before initalizing it.</span>", null, null, null, owner.current)
|
||||
to_chat(owner, "<span class='userdanger'>The frame's firmware detects and deletes your neural reprogramming! You remember nothing but the name of the one who flashed you.</span>")
|
||||
|
||||
//blunt trauma deconversions call this through species.dm spec_attacked_by()
|
||||
/datum/antagonist/rev/proc/remove_revolutionary(borged, deconverter)
|
||||
log_attack("[owner.current] (Key: [key_name(owner.current)]) has been deconverted from the revolution by [deconverter] (Key: [key_name(deconverter)])!")
|
||||
if(borged)
|
||||
@@ -232,11 +233,11 @@
|
||||
H.dna.remove_mutation(CLOWNMUT)
|
||||
|
||||
if(give_flash)
|
||||
var/obj/item/device/assembly/flash/T = new(H)
|
||||
var/obj/item/assembly/flash/T = new(H)
|
||||
var/list/slots = list (
|
||||
"backpack" = slot_in_backpack,
|
||||
"left pocket" = slot_l_store,
|
||||
"right pocket" = slot_r_store
|
||||
"backpack" = SLOT_IN_BACKPACK,
|
||||
"left pocket" = SLOT_L_STORE,
|
||||
"right pocket" = SLOT_R_STORE
|
||||
)
|
||||
var/where = H.equip_in_one_of_slots(T, slots)
|
||||
if (!where)
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
name = "pile of viscera"
|
||||
desc = "A repulsive pile of guts and gore."
|
||||
gender = NEUTER
|
||||
random_icon_states = list("innards")
|
||||
icon_state = "innards"
|
||||
|
||||
/mob/living/simple_animal/slaughter/phasein()
|
||||
. = ..()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
////Deactivated swarmer shell////
|
||||
/obj/item/device/deactivated_swarmer
|
||||
/obj/item/deactivated_swarmer
|
||||
name = "deactivated swarmer"
|
||||
desc = "A shell of swarmer that was completely powered down. It can no longer activate itself."
|
||||
icon = 'icons/mob/swarmer.dmi'
|
||||
@@ -45,7 +45,7 @@
|
||||
user.visible_message("<span class='warning'>[usr.name] deactivates [src].</span>",
|
||||
"<span class='notice'>After some fiddling, you find a way to disable [src]'s power source.</span>",
|
||||
"<span class='italics'>You hear clicking.</span>")
|
||||
new /obj/item/device/deactivated_swarmer(get_turf(src))
|
||||
new /obj/item/deactivated_swarmer(get_turf(src))
|
||||
qdel(src)
|
||||
else
|
||||
..()
|
||||
@@ -302,10 +302,6 @@
|
||||
to_chat(S, "<span class='warning'>This device's destruction would result in the extermination of everything in the area. Aborting.</span>")
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/dominator/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
to_chat(S, "<span class='warning'>This device is attempting to corrupt our entire network; attempting to interact with it is too risky. Aborting.</span>")
|
||||
return FALSE
|
||||
|
||||
/obj/effect/rune/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
to_chat(S, "<span class='warning'>Searching... sensor malfunction! Target lost. Aborting.</span>")
|
||||
return FALSE
|
||||
@@ -399,7 +395,7 @@
|
||||
to_chat(S, "<span class='warning'>Disrupting the power grid would bring no benefit to us. Aborting.</span>")
|
||||
return FALSE
|
||||
|
||||
/obj/item/device/deactivated_swarmer/IntegrateAmount()
|
||||
/obj/item/deactivated_swarmer/IntegrateAmount()
|
||||
return 50
|
||||
|
||||
/obj/machinery/hydroponics/soil/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
@@ -497,10 +493,10 @@
|
||||
D.pixel_z = target.pixel_z
|
||||
if(do_mob(src, target, 100))
|
||||
to_chat(src, "<span class='info'>Dismantling complete.</span>")
|
||||
var/obj/item/stack/sheet/metal/M = new /obj/item/stack/sheet/metal(target.loc)
|
||||
M.amount = 5
|
||||
var/atom/Tsec = target.drop_location()
|
||||
new /obj/item/stack/sheet/metal(Tsec, 5)
|
||||
for(var/obj/item/I in target.component_parts)
|
||||
I.forceMove(M.drop_location())
|
||||
I.forceMove(Tsec)
|
||||
var/obj/effect/temp_visual/swarmer/disintegration/N = new /obj/effect/temp_visual/swarmer/disintegration(get_turf(target))
|
||||
N.pixel_x = target.pixel_x
|
||||
N.pixel_y = target.pixel_y
|
||||
@@ -509,7 +505,7 @@
|
||||
if(istype(target, /obj/machinery/computer))
|
||||
var/obj/machinery/computer/C = target
|
||||
if(C.circuit)
|
||||
C.circuit.forceMove(M.drop_location())
|
||||
C.circuit.forceMove(Tsec)
|
||||
qdel(target)
|
||||
|
||||
|
||||
|
||||
@@ -296,9 +296,9 @@
|
||||
folder = new/obj/item/folder/syndicate/blue(mob.loc)
|
||||
|
||||
var/list/slots = list (
|
||||
"backpack" = slot_in_backpack,
|
||||
"left pocket" = slot_l_store,
|
||||
"right pocket" = slot_r_store
|
||||
"backpack" = SLOT_IN_BACKPACK,
|
||||
"left pocket" = SLOT_L_STORE,
|
||||
"right pocket" = SLOT_R_STORE
|
||||
)
|
||||
|
||||
var/where = "At your feet"
|
||||
|
||||
@@ -138,7 +138,7 @@
|
||||
|
||||
/////////////////////////////////////////Necromantic Stone///////////////////
|
||||
|
||||
/obj/item/device/necromantic_stone
|
||||
/obj/item/necromantic_stone
|
||||
name = "necromantic stone"
|
||||
desc = "A shard capable of resurrecting humans as skeleton thralls."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
@@ -150,10 +150,10 @@
|
||||
var/list/spooky_scaries = list()
|
||||
var/unlimited = 0
|
||||
|
||||
/obj/item/device/necromantic_stone/unlimited
|
||||
/obj/item/necromantic_stone/unlimited
|
||||
unlimited = 1
|
||||
|
||||
/obj/item/device/necromantic_stone/attack(mob/living/carbon/human/M, mob/living/carbon/human/user)
|
||||
/obj/item/necromantic_stone/attack(mob/living/carbon/human/M, mob/living/carbon/human/user)
|
||||
if(!istype(M))
|
||||
return ..()
|
||||
|
||||
@@ -183,7 +183,7 @@
|
||||
|
||||
desc = "A shard capable of resurrecting humans as skeleton thralls[unlimited ? "." : ", [spooky_scaries.len]/3 active thralls."]"
|
||||
|
||||
/obj/item/device/necromantic_stone/proc/check_spooky()
|
||||
/obj/item/necromantic_stone/proc/check_spooky()
|
||||
if(unlimited) //no point, the list isn't used.
|
||||
return
|
||||
|
||||
@@ -199,17 +199,17 @@
|
||||
listclearnulls(spooky_scaries)
|
||||
|
||||
//Funny gimmick, skeletons always seem to wear roman/ancient armour
|
||||
/obj/item/device/necromantic_stone/proc/equip_roman_skeleton(mob/living/carbon/human/H)
|
||||
/obj/item/necromantic_stone/proc/equip_roman_skeleton(mob/living/carbon/human/H)
|
||||
for(var/obj/item/I in H)
|
||||
H.dropItemToGround(I)
|
||||
|
||||
var/hat = pick(/obj/item/clothing/head/helmet/roman, /obj/item/clothing/head/helmet/roman/legionaire)
|
||||
H.equip_to_slot_or_del(new hat(H), slot_head)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/under/roman(H), slot_w_uniform)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/roman(H), slot_shoes)
|
||||
H.equip_to_slot_or_del(new hat(H), SLOT_HEAD)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/under/roman(H), SLOT_W_UNIFORM)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/roman(H), SLOT_SHOES)
|
||||
H.put_in_hands(new /obj/item/shield/riot/roman(H), TRUE)
|
||||
H.put_in_hands(new /obj/item/claymore(H), TRUE)
|
||||
H.equip_to_slot_or_del(new /obj/item/twohanded/spear(H), slot_back)
|
||||
H.equip_to_slot_or_del(new /obj/item/twohanded/spear(H), SLOT_BACK)
|
||||
|
||||
|
||||
/obj/item/voodoo
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/obj/item/device/soulstone
|
||||
/obj/item/soulstone
|
||||
name = "soulstone shard"
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "soulstone"
|
||||
@@ -8,13 +8,13 @@
|
||||
layer = HIGH_OBJ_LAYER
|
||||
desc = "A fragment of the legendary treasure known simply as the 'Soul Stone'. The shard still flickers with a fraction of the full artefact's power."
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
slot_flags = SLOT_BELT
|
||||
slot_flags = ITEM_SLOT_BELT
|
||||
var/usability = 0
|
||||
|
||||
var/old_shard = FALSE
|
||||
var/spent = FALSE
|
||||
|
||||
/obj/item/device/soulstone/proc/was_used()
|
||||
/obj/item/soulstone/proc/was_used()
|
||||
if(old_shard)
|
||||
spent = TRUE
|
||||
name = "dull [name]"
|
||||
@@ -22,20 +22,19 @@
|
||||
the 'Soul Stone'. The shard lies still, dull and lifeless; \
|
||||
whatever spark it once held long extinguished."
|
||||
|
||||
/obj/item/device/soulstone/anybody
|
||||
/obj/item/soulstone/anybody
|
||||
usability = 1
|
||||
|
||||
/obj/item/device/soulstone/anybody/chaplain
|
||||
/obj/item/soulstone/anybody/chaplain
|
||||
name = "mysterious old shard"
|
||||
old_shard = TRUE
|
||||
|
||||
/obj/item/device/soulstone/pickup(mob/living/user)
|
||||
/obj/item/soulstone/pickup(mob/living/user)
|
||||
..()
|
||||
if(!iscultist(user) && !iswizard(user) && !usability)
|
||||
to_chat(user, "<span class='danger'>An overwhelming feeling of dread comes over you as you pick up the soulstone. It would be wise to be rid of this quickly.</span>")
|
||||
user.Dizzy(120)
|
||||
|
||||
/obj/item/device/soulstone/examine(mob/user)
|
||||
/obj/item/soulstone/examine(mob/user)
|
||||
..()
|
||||
if(usability || iscultist(user) || iswizard(user) || isobserver(user))
|
||||
if (old_shard)
|
||||
@@ -46,14 +45,14 @@
|
||||
if(spent)
|
||||
to_chat(user, "<span class='cult'>This shard is spent; it is now just a creepy rock.</span>")
|
||||
|
||||
/obj/item/device/soulstone/Destroy() //Stops the shade from being qdel'd immediately and their ghost being sent back to the arrival shuttle.
|
||||
/obj/item/soulstone/Destroy() //Stops the shade from being qdel'd immediately and their ghost being sent back to the arrival shuttle.
|
||||
for(var/mob/living/simple_animal/shade/A in src)
|
||||
A.death()
|
||||
return ..()
|
||||
|
||||
//////////////////////////////Capturing////////////////////////////////////////////////////////
|
||||
|
||||
/obj/item/device/soulstone/attack(mob/living/carbon/human/M, mob/living/user)
|
||||
/obj/item/soulstone/attack(mob/living/carbon/human/M, mob/living/user)
|
||||
if(!iscultist(user) && !iswizard(user) && !usability)
|
||||
user.Unconscious(100)
|
||||
to_chat(user, "<span class='userdanger'>Your body is wracked with debilitating pain!</span>")
|
||||
@@ -71,7 +70,7 @@
|
||||
|
||||
///////////////////Options for using captured souls///////////////////////////////////////
|
||||
|
||||
/obj/item/device/soulstone/attack_self(mob/living/user)
|
||||
/obj/item/soulstone/attack_self(mob/living/user)
|
||||
if(!in_range(src, user))
|
||||
return
|
||||
if(!iscultist(user) && !iswizard(user) && !usability)
|
||||
@@ -80,7 +79,7 @@
|
||||
return
|
||||
release_shades(user)
|
||||
|
||||
/obj/item/device/soulstone/proc/release_shades(mob/user)
|
||||
/obj/item/soulstone/proc/release_shades(mob/user)
|
||||
for(var/mob/living/simple_animal/shade/A in src)
|
||||
A.status_flags &= ~GODMODE
|
||||
A.canmove = 1
|
||||
@@ -111,8 +110,8 @@
|
||||
to_chat(user, "<span class='cult'>A <b>Juggernaut</b>, which is very hard to kill and can produce temporary walls, but is slow.</span>")
|
||||
|
||||
/obj/structure/constructshell/attackby(obj/item/O, mob/user, params)
|
||||
if(istype(O, /obj/item/device/soulstone))
|
||||
var/obj/item/device/soulstone/SS = O
|
||||
if(istype(O, /obj/item/soulstone))
|
||||
var/obj/item/soulstone/SS = O
|
||||
if(!iscultist(user) && !iswizard(user) && !SS.usability)
|
||||
to_chat(user, "<span class='danger'>An overwhelming feeling of dread comes over you as you attempt to place the soulstone into the shell. It would be wise to be rid of this quickly.</span>")
|
||||
user.Dizzy(120)
|
||||
@@ -125,7 +124,7 @@
|
||||
////////////////////////////Proc for moving soul in and out off stone//////////////////////////////////////
|
||||
|
||||
|
||||
/obj/item/device/soulstone/proc/transfer_soul(choice as text, target, mob/user)
|
||||
/obj/item/soulstone/proc/transfer_soul(choice as text, target, mob/user)
|
||||
switch(choice)
|
||||
if("FORCE")
|
||||
if(!iscarbon(target)) //TODO: Add sacrifice stoning for non-organics, just because you have no body doesnt mean you dont have a soul
|
||||
@@ -223,7 +222,7 @@
|
||||
if(newstruct.mind && ((stoner && iscultist(stoner)) || cultoverride) && SSticker && SSticker.mode)
|
||||
SSticker.mode.add_cultist(newstruct.mind, 0)
|
||||
if(iscultist(stoner) || cultoverride)
|
||||
to_chat(newstruct, "<b>You are still bound to serve the cult[stoner ? " and [stoner]":""], follow their orders and help them complete their goals at all costs.</b>")
|
||||
to_chat(newstruct, "<b>You are still bound to serve the cult[stoner ? " and [stoner]":""], follow [stoner ? stoner.p_their() : "their"] orders and help [stoner ? stoner.p_them() : "them"] complete [stoner ? stoner.p_their() : "their"] goals at all costs.</b>")
|
||||
else if(stoner)
|
||||
to_chat(newstruct, "<b>You are still bound to serve your creator, [stoner], follow their orders and help them complete their goals at all costs.</b>")
|
||||
newstruct.clear_alert("bloodsense")
|
||||
@@ -233,7 +232,7 @@
|
||||
newstruct.cancel_camera()
|
||||
|
||||
|
||||
/obj/item/device/soulstone/proc/init_shade(mob/living/carbon/human/T, mob/U, vic = 0)
|
||||
/obj/item/soulstone/proc/init_shade(mob/living/carbon/human/T, mob/U, vic = 0)
|
||||
new /obj/effect/decal/remains/human(T.loc) //Spawns a skeleton
|
||||
T.stop_sound_channel(CHANNEL_HEARTBEAT)
|
||||
T.invisibility = INVISIBILITY_ABSTRACT
|
||||
@@ -260,7 +259,7 @@
|
||||
to_chat(U, "<span class='info'><b>Capture successful!</b>:</span> [T.real_name]'s soul has been ripped from their body and stored within the soul stone.")
|
||||
|
||||
|
||||
/obj/item/device/soulstone/proc/getCultGhost(mob/living/carbon/human/T, mob/U)
|
||||
/obj/item/soulstone/proc/getCultGhost(mob/living/carbon/human/T, mob/U)
|
||||
var/mob/dead/observer/chosen_ghost
|
||||
|
||||
for(var/mob/dead/observer/ghost in GLOB.player_list) //We put them back in their body
|
||||
|
||||
@@ -337,7 +337,7 @@
|
||||
/datum/spellbook_entry/item/necrostone
|
||||
name = "A Necromantic Stone"
|
||||
desc = "A Necromantic stone is able to resurrect three dead individuals as skeletal thralls for you to command."
|
||||
item_path = /obj/item/device/necromantic_stone
|
||||
item_path = /obj/item/necromantic_stone
|
||||
category = "Assistance"
|
||||
|
||||
/datum/spellbook_entry/item/wands
|
||||
|
||||
@@ -238,17 +238,17 @@
|
||||
if(!istype(master_mob) || !istype(H))
|
||||
return
|
||||
if(master_mob.ears)
|
||||
H.equip_to_slot_or_del(new master_mob.ears.type, slot_ears)
|
||||
H.equip_to_slot_or_del(new master_mob.ears.type, SLOT_EARS)
|
||||
if(master_mob.w_uniform)
|
||||
H.equip_to_slot_or_del(new master_mob.w_uniform.type, slot_w_uniform)
|
||||
H.equip_to_slot_or_del(new master_mob.w_uniform.type, SLOT_W_UNIFORM)
|
||||
if(master_mob.shoes)
|
||||
H.equip_to_slot_or_del(new master_mob.shoes.type, slot_shoes)
|
||||
H.equip_to_slot_or_del(new master_mob.shoes.type, SLOT_SHOES)
|
||||
if(master_mob.wear_suit)
|
||||
H.equip_to_slot_or_del(new master_mob.wear_suit.type, slot_wear_suit)
|
||||
H.equip_to_slot_or_del(new master_mob.wear_suit.type, SLOT_WEAR_SUIT)
|
||||
if(master_mob.head)
|
||||
H.equip_to_slot_or_del(new master_mob.head.type, slot_head)
|
||||
H.equip_to_slot_or_del(new master_mob.head.type, SLOT_HEAD)
|
||||
if(master_mob.back)
|
||||
H.equip_to_slot_or_del(new master_mob.back.type, slot_back)
|
||||
H.equip_to_slot_or_del(new master_mob.back.type, SLOT_BACK)
|
||||
|
||||
//Operation: Fuck off and scare people
|
||||
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/area_teleport/teleport(null))
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
#define WIRE_PULSE_SPECIAL (1<<2)
|
||||
#define WIRE_RADIO_RECEIVE (1<<3)
|
||||
#define WIRE_RADIO_PULSE (1<<4)
|
||||
#define ASSEMBLY_BEEP_VOLUME 5
|
||||
|
||||
/obj/item/device/assembly
|
||||
/obj/item/assembly
|
||||
name = "assembly"
|
||||
desc = "A small electronic device that should never exist."
|
||||
icon = 'icons/obj/assemblies/new_assemblies.dmi'
|
||||
@@ -16,30 +17,36 @@
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
|
||||
var/is_position_sensitive = FALSE //set to true if the device has different icons for each position.
|
||||
//This will prevent things such as visible lasers from facing the incorrect direction when transformed by assembly_holder's update_icon()
|
||||
var/secured = TRUE
|
||||
var/list/attached_overlays = null
|
||||
var/obj/item/device/assembly_holder/holder = null
|
||||
var/obj/item/assembly_holder/holder = null
|
||||
var/wire_type = WIRE_RECEIVE | WIRE_PULSE
|
||||
var/attachable = FALSE // can this be attached to wires
|
||||
var/datum/wires/connected = null
|
||||
|
||||
var/next_activate = 0 //When we're next allowed to activate - for spam control
|
||||
|
||||
/obj/item/device/assembly/get_part_rating()
|
||||
/obj/item/assembly/get_part_rating()
|
||||
return 1
|
||||
|
||||
/obj/item/device/assembly/proc/on_attach()
|
||||
/obj/item/assembly/proc/on_attach()
|
||||
|
||||
/obj/item/device/assembly/proc/on_detach()
|
||||
/obj/item/assembly/proc/on_detach() //call this when detaching it from a device. handles any special functions that need to be updated ex post facto
|
||||
if(!holder)
|
||||
return FALSE
|
||||
forceMove(holder.drop_location())
|
||||
holder = null
|
||||
return TRUE
|
||||
|
||||
/obj/item/device/assembly/proc/holder_movement() //Called when the holder is moved
|
||||
return
|
||||
/obj/item/assembly/proc/holder_movement() //Called when the holder is moved
|
||||
if(!holder)
|
||||
return FALSE
|
||||
setDir(holder.dir)
|
||||
return TRUE
|
||||
|
||||
/obj/item/device/assembly/proc/describe() // Called by grenades to describe the state of the trigger (time left, etc)
|
||||
return "The trigger assembly looks broken!"
|
||||
|
||||
|
||||
/obj/item/device/assembly/proc/is_secured(mob/user)
|
||||
/obj/item/assembly/proc/is_secured(mob/user)
|
||||
if(!secured)
|
||||
to_chat(user, "<span class='warning'>The [name] is unsecured!</span>")
|
||||
return FALSE
|
||||
@@ -47,7 +54,7 @@
|
||||
|
||||
|
||||
//Called when another assembly acts on this one, var/radio will determine where it came from for wire calcs
|
||||
/obj/item/device/assembly/proc/pulsed(radio = 0)
|
||||
/obj/item/assembly/proc/pulsed(radio = FALSE)
|
||||
if(wire_type & WIRE_RECEIVE)
|
||||
INVOKE_ASYNC(src, .proc/activate)
|
||||
if(radio && (wire_type & WIRE_RADIO_RECEIVE))
|
||||
@@ -56,7 +63,7 @@
|
||||
|
||||
|
||||
//Called when this device attempts to act on another device, var/radio determines if it was sent via radio or direct
|
||||
/obj/item/device/assembly/proc/pulse(radio = 0)
|
||||
/obj/item/assembly/proc/pulse(radio = FALSE)
|
||||
if(connected && wire_type)
|
||||
connected.pulse_assembly(src)
|
||||
return TRUE
|
||||
@@ -68,52 +75,50 @@
|
||||
|
||||
|
||||
// What the device does when turned on
|
||||
/obj/item/device/assembly/proc/activate()
|
||||
/obj/item/assembly/proc/activate()
|
||||
if(QDELETED(src) || !secured || (next_activate > world.time))
|
||||
return FALSE
|
||||
next_activate = world.time + 30
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/item/device/assembly/proc/toggle_secure()
|
||||
/obj/item/assembly/proc/toggle_secure()
|
||||
secured = !secured
|
||||
update_icon()
|
||||
return secured
|
||||
|
||||
|
||||
/obj/item/device/assembly/attackby(obj/item/W, mob/user, params)
|
||||
/obj/item/assembly/attackby(obj/item/W, mob/user, params)
|
||||
if(isassembly(W))
|
||||
var/obj/item/device/assembly/A = W
|
||||
var/obj/item/assembly/A = W
|
||||
if((!A.secured) && (!secured))
|
||||
holder = new/obj/item/device/assembly_holder(get_turf(src))
|
||||
holder = new/obj/item/assembly_holder(get_turf(src))
|
||||
holder.assemble(src,A,user)
|
||||
to_chat(user, "<span class='notice'>You attach and secure \the [A] to \the [src]!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Both devices must be in attachable mode to be attached together.</span>")
|
||||
return
|
||||
if(istype(W, /obj/item/screwdriver))
|
||||
if(toggle_secure())
|
||||
to_chat(user, "<span class='notice'>\The [src] is ready!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>\The [src] can now be attached!</span>")
|
||||
return
|
||||
..()
|
||||
|
||||
|
||||
/obj/item/device/assembly/examine(mob/user)
|
||||
..()
|
||||
if(secured)
|
||||
to_chat(user, "\The [src] is secured and ready to be used.")
|
||||
/obj/item/assembly/screwdriver_act(mob/living/user, obj/item/I)
|
||||
if(toggle_secure())
|
||||
to_chat(user, "<span class='notice'>\The [src] is ready!</span>")
|
||||
else
|
||||
to_chat(user, "\The [src] can be attached to other things.")
|
||||
to_chat(user, "<span class='notice'>\The [src] can now be attached!</span>")
|
||||
add_fingerprint(user)
|
||||
return TRUE
|
||||
|
||||
/obj/item/assembly/examine(mob/user)
|
||||
..()
|
||||
to_chat(user, "<span class='notice'>\The [src] [secured? "is secured and ready to be used!" : "can be attached to other things."]</span>")
|
||||
|
||||
|
||||
/obj/item/device/assembly/attack_self(mob/user)
|
||||
/obj/item/assembly/attack_self(mob/user)
|
||||
if(!user)
|
||||
return FALSE
|
||||
user.set_machine(src)
|
||||
interact(user)
|
||||
return TRUE
|
||||
|
||||
/obj/item/device/assembly/interact(mob/user)
|
||||
/obj/item/assembly/interact(mob/user)
|
||||
return ui_interact(user)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/obj/item/device/onetankbomb
|
||||
/obj/item/onetankbomb
|
||||
name = "bomb"
|
||||
icon = 'icons/obj/tank.dmi'
|
||||
item_state = "assembly"
|
||||
@@ -10,14 +10,17 @@
|
||||
throw_range = 4
|
||||
flags_1 = CONDUCT_1
|
||||
var/status = FALSE //0 - not readied //1 - bomb finished with welder
|
||||
var/obj/item/device/assembly_holder/bombassembly = null //The first part of the bomb is an assembly holder, holding an igniter+some device
|
||||
var/obj/item/assembly_holder/bombassembly = null //The first part of the bomb is an assembly holder, holding an igniter+some device
|
||||
var/obj/item/tank/bombtank = null //the second part of the bomb is a plasma tank
|
||||
|
||||
/obj/item/onetankbomb/IsSpecialAssembly()
|
||||
return TRUE
|
||||
|
||||
/obj/item/device/onetankbomb/examine(mob/user)
|
||||
/obj/item/onetankbomb/examine(mob/user)
|
||||
bombtank.examine(user)
|
||||
|
||||
/obj/item/device/onetankbomb/update_icon()
|
||||
/obj/item/onetankbomb/update_icon()
|
||||
cut_overlays()
|
||||
if(bombtank)
|
||||
icon = bombtank.icon
|
||||
icon_state = bombtank.icon_state
|
||||
@@ -26,62 +29,94 @@
|
||||
copy_overlays(bombassembly)
|
||||
add_overlay("bomb_assembly")
|
||||
|
||||
/obj/item/device/onetankbomb/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/device/analyzer))
|
||||
/obj/item/onetankbomb/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/analyzer))
|
||||
bombtank.attackby(W, user)
|
||||
return
|
||||
if(istype(W, /obj/item/wrench) && !status) //This is basically bomb assembly code inverted. apparently it works.
|
||||
|
||||
to_chat(user, "<span class='notice'>You disassemble [src].</span>")
|
||||
|
||||
bombassembly.forceMove(drop_location())
|
||||
bombassembly.master = null
|
||||
bombassembly = null
|
||||
|
||||
bombtank.forceMove(drop_location())
|
||||
bombtank.master = null
|
||||
bombtank = null
|
||||
|
||||
qdel(src)
|
||||
return
|
||||
var/obj/item/weldingtool/WT = W
|
||||
if((istype(WT) && WT.welding))
|
||||
if(!status)
|
||||
status = TRUE
|
||||
GLOB.bombers += "[key_name(user)] welded a single tank bomb. Temp: [bombtank.air_contents.temperature-T0C]"
|
||||
message_admins("[key_name_admin(user)] welded a single tank bomb. Temp: [bombtank.air_contents.temperature-T0C]")
|
||||
to_chat(user, "<span class='notice'>A pressure hole has been bored to [bombtank] valve. \The [bombtank] can now be ignited.</span>")
|
||||
add_fingerprint(user)
|
||||
..()
|
||||
|
||||
/obj/item/device/onetankbomb/attack_self(mob/user) //pressing the bomb accesses its assembly
|
||||
/obj/item/onetankbomb/wrench_act(mob/living/user, obj/item/I)
|
||||
to_chat(user, "<span class='notice'>You disassemble [src]!</span>")
|
||||
if(bombassembly)
|
||||
bombassembly.forceMove(drop_location())
|
||||
bombassembly.master = null
|
||||
bombassembly = null
|
||||
if(bombtank)
|
||||
bombtank.forceMove(drop_location())
|
||||
bombtank.master = null
|
||||
bombtank = null
|
||||
qdel(src)
|
||||
return TRUE
|
||||
|
||||
/obj/item/onetankbomb/welder_act(mob/living/user, obj/item/I)
|
||||
. = FALSE
|
||||
if(status)
|
||||
to_chat(user, "<span class='notice'>[bombtank] already has a pressure hole!</span>")
|
||||
return
|
||||
if(!I.tool_start_check(user, amount=0))
|
||||
return
|
||||
if(I.use_tool(src, user, 0, volume=40))
|
||||
status = TRUE
|
||||
GLOB.bombers += "[key_name(user)] welded a single tank bomb. Temp: [bombtank.air_contents.temperature-T0C]"
|
||||
message_admins("[key_name_admin(user)] welded a single tank bomb. Temp: [bombtank.air_contents.temperature-T0C]")
|
||||
to_chat(user, "<span class='notice'>A pressure hole has been bored to [bombtank] valve. \The [bombtank] can now be ignited.</span>")
|
||||
add_fingerprint(user)
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/item/onetankbomb/attack_self(mob/user) //pressing the bomb accesses its assembly
|
||||
bombassembly.attack_self(user, TRUE)
|
||||
add_fingerprint(user)
|
||||
return
|
||||
|
||||
/obj/item/device/onetankbomb/receive_signal() //This is mainly called by the sensor through sense() to the holder, and from the holder to here.
|
||||
visible_message("[icon2html(src, viewers(src))] *beep* *beep*", "*beep* *beep*")
|
||||
/obj/item/onetankbomb/receive_signal() //This is mainly called by the sensor through sense() to the holder, and from the holder to here.
|
||||
audible_message("[icon2html(src, hearers(src))] *beep* *beep* *beep*")
|
||||
playsound(src, 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE)
|
||||
sleep(10)
|
||||
if(!src)
|
||||
if(QDELETED(src))
|
||||
return
|
||||
if(status)
|
||||
bombtank.ignite() //if its not a dud, boom (or not boom if you made shitty mix) the ignite proc is below, in this file
|
||||
else
|
||||
bombtank.release()
|
||||
|
||||
/obj/item/device/onetankbomb/Crossed(atom/movable/AM as mob|obj) //for mousetraps
|
||||
//Assembly / attached device memes
|
||||
|
||||
/obj/item/onetankbomb/Crossed(atom/movable/AM as mob|obj) //for mousetraps
|
||||
. = ..()
|
||||
if(bombassembly)
|
||||
bombassembly.Crossed(AM)
|
||||
|
||||
/obj/item/device/onetankbomb/on_found(mob/finder) //for mousetraps
|
||||
/obj/item/onetankbomb/on_found(mob/finder) //for mousetraps
|
||||
if(bombassembly)
|
||||
bombassembly.on_found(finder)
|
||||
|
||||
/obj/item/onetankbomb/attack_hand() //also for mousetraps
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(bombassembly)
|
||||
bombassembly.attack_hand()
|
||||
|
||||
/obj/item/onetankbomb/Move()
|
||||
. = ..()
|
||||
if(bombassembly)
|
||||
bombassembly.setDir(dir)
|
||||
bombassembly.Move()
|
||||
|
||||
/obj/item/onetankbomb/dropped()
|
||||
. = ..()
|
||||
if(bombassembly)
|
||||
bombassembly.dropped()
|
||||
|
||||
|
||||
|
||||
|
||||
// ---------- Procs below are for tanks that are used exclusively in 1-tank bombs ----------
|
||||
|
||||
//Bomb assembly proc. This turns assembly+tank into a bomb
|
||||
/obj/item/tank/proc/bomb_assemble(obj/item/device/assembly_holder/assembly, mob/living/user)
|
||||
/obj/item/tank/proc/bomb_assemble(obj/item/assembly_holder/assembly, mob/living/user)
|
||||
//Check if either part of the assembly has an igniter, but if both parts are igniters, then fuck it
|
||||
if(isigniter(assembly.a_left) == isigniter(assembly.a_right))
|
||||
return
|
||||
@@ -94,7 +129,7 @@
|
||||
to_chat(user, "<span class='warning'>[assembly] is stuck to your hand!</span>")
|
||||
return
|
||||
|
||||
var/obj/item/device/onetankbomb/bomb = new
|
||||
var/obj/item/onetankbomb/bomb = new
|
||||
user.transferItemToLoc(src, bomb)
|
||||
user.transferItemToLoc(assembly, bomb)
|
||||
|
||||
|
||||
@@ -1,30 +1,29 @@
|
||||
/obj/item/device/assembly/control
|
||||
/obj/item/assembly/control
|
||||
name = "blast door controller"
|
||||
desc = "A small electronic device able to control a blast door remotely."
|
||||
icon_state = "control"
|
||||
attachable = 1
|
||||
attachable = TRUE
|
||||
var/id = null
|
||||
var/can_change_id = 0
|
||||
var/cooldown = 0//Door cooldowns
|
||||
var/cooldown = FALSE //Door cooldowns
|
||||
|
||||
/obj/item/device/assembly/control/examine(mob/user)
|
||||
/obj/item/assembly/control/examine(mob/user)
|
||||
..()
|
||||
if(id)
|
||||
to_chat(user, "<span class='notice'>Its channel ID is '[id]'.</span>")
|
||||
|
||||
/obj/item/device/assembly/control/activate()
|
||||
cooldown = 1
|
||||
/obj/item/assembly/control/activate()
|
||||
cooldown = TRUE
|
||||
var/openclose
|
||||
for(var/obj/machinery/door/poddoor/M in GLOB.machines)
|
||||
if(M.id == src.id)
|
||||
if(openclose == null)
|
||||
openclose = M.density
|
||||
INVOKE_ASYNC(M, openclose ? /obj/machinery/door/poddoor.proc/open : /obj/machinery/door/poddoor.proc/close)
|
||||
sleep(10)
|
||||
cooldown = 0
|
||||
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 10)
|
||||
|
||||
|
||||
/obj/item/device/assembly/control/airlock
|
||||
/obj/item/assembly/control/airlock
|
||||
name = "airlock controller"
|
||||
desc = "A small electronic device able to control an airlock remotely."
|
||||
id = "badmin" // Set it to null for MEGAFUN.
|
||||
@@ -37,8 +36,8 @@
|
||||
16= door safties (SAFE)
|
||||
*/
|
||||
|
||||
/obj/item/device/assembly/control/airlock/activate()
|
||||
cooldown = 1
|
||||
/obj/item/assembly/control/airlock/activate()
|
||||
cooldown = TRUE
|
||||
var/doors_need_closing = FALSE
|
||||
var/list/obj/machinery/door/airlock/open_or_close = list()
|
||||
for(var/obj/machinery/door/airlock/D in GLOB.airlocks)
|
||||
@@ -66,16 +65,15 @@
|
||||
for(var/D in open_or_close)
|
||||
INVOKE_ASYNC(D, doors_need_closing ? /obj/machinery/door/airlock.proc/close : /obj/machinery/door/airlock.proc/open)
|
||||
|
||||
sleep(10)
|
||||
cooldown = 0
|
||||
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 10)
|
||||
|
||||
|
||||
/obj/item/device/assembly/control/massdriver
|
||||
/obj/item/assembly/control/massdriver
|
||||
name = "mass driver controller"
|
||||
desc = "A small electronic device able to control a mass driver."
|
||||
|
||||
/obj/item/device/assembly/control/massdriver/activate()
|
||||
cooldown = 1
|
||||
/obj/item/assembly/control/massdriver/activate()
|
||||
cooldown = TRUE
|
||||
for(var/obj/machinery/door/poddoor/M in GLOB.machines)
|
||||
if (M.id == src.id)
|
||||
INVOKE_ASYNC(M, /obj/machinery/door/poddoor.proc/open)
|
||||
@@ -92,16 +90,15 @@
|
||||
if (M.id == src.id)
|
||||
INVOKE_ASYNC(M, /obj/machinery/door/poddoor.proc/close)
|
||||
|
||||
sleep(10)
|
||||
cooldown = 0
|
||||
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 10)
|
||||
|
||||
|
||||
/obj/item/device/assembly/control/igniter
|
||||
/obj/item/assembly/control/igniter
|
||||
name = "ignition controller"
|
||||
desc = "A remote controller for a mounted igniter."
|
||||
|
||||
/obj/item/device/assembly/control/igniter/activate()
|
||||
cooldown = 1
|
||||
/obj/item/assembly/control/igniter/activate()
|
||||
cooldown = TRUE
|
||||
for(var/obj/machinery/sparker/M in GLOB.machines)
|
||||
if (M.id == src.id)
|
||||
INVOKE_ASYNC(M, /obj/machinery/sparker.proc/ignite)
|
||||
@@ -112,33 +109,29 @@
|
||||
M.on = !M.on
|
||||
M.icon_state = "igniter[M.on]"
|
||||
|
||||
sleep(30)
|
||||
cooldown = 0
|
||||
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 30)
|
||||
|
||||
|
||||
/obj/item/device/assembly/control/flasher
|
||||
/obj/item/assembly/control/flasher
|
||||
name = "flasher controller"
|
||||
desc = "A remote controller for a mounted flasher."
|
||||
|
||||
/obj/item/device/assembly/control/flasher/activate()
|
||||
cooldown = 1
|
||||
/obj/item/assembly/control/flasher/activate()
|
||||
cooldown = TRUE
|
||||
for(var/obj/machinery/flasher/M in GLOB.machines)
|
||||
if(M.id == src.id)
|
||||
INVOKE_ASYNC(M, /obj/machinery/flasher.proc/flash)
|
||||
|
||||
sleep(50)
|
||||
cooldown = 0
|
||||
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 50)
|
||||
|
||||
|
||||
/obj/item/device/assembly/control/crematorium
|
||||
/obj/item/assembly/control/crematorium
|
||||
name = "crematorium controller"
|
||||
desc = "An evil-looking remote controller for a crematorium."
|
||||
|
||||
/obj/item/device/assembly/control/crematorium/activate()
|
||||
cooldown = 1
|
||||
/obj/item/assembly/control/crematorium/activate()
|
||||
cooldown = TRUE
|
||||
for (var/obj/structure/bodycontainer/crematorium/C in GLOB.crematoriums)
|
||||
if (C.id == id)
|
||||
C.cremate(usr)
|
||||
|
||||
sleep(50)
|
||||
cooldown = 0
|
||||
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 50)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/obj/item/device/assembly/flash
|
||||
/obj/item/assembly/flash
|
||||
name = "flash"
|
||||
desc = "A powerful and versatile flashbulb device, with applications ranging from disorienting attackers to acting as visual receptors in robot production."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "flash"
|
||||
item_state = "flashtool"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
|
||||
@@ -15,7 +16,7 @@
|
||||
var/cooldown = 0
|
||||
var/last_trigger = 0 //Last time it was successfully triggered.
|
||||
|
||||
/obj/item/device/assembly/flash/suicide_act(mob/living/user)
|
||||
/obj/item/assembly/flash/suicide_act(mob/living/user)
|
||||
if (crit_fail)
|
||||
user.visible_message("<span class='suicide'>[user] raises \the [src] up to [user.p_their()] eyes and activates it ... but its burnt out!</span>")
|
||||
return SHAME
|
||||
@@ -26,7 +27,7 @@
|
||||
attack(user,user)
|
||||
return FIRELOSS
|
||||
|
||||
/obj/item/device/assembly/flash/update_icon(flash = FALSE)
|
||||
/obj/item/assembly/flash/update_icon(flash = FALSE)
|
||||
cut_overlays()
|
||||
attached_overlays = list()
|
||||
if(crit_fail)
|
||||
@@ -39,13 +40,13 @@
|
||||
if(holder)
|
||||
holder.update_icon()
|
||||
|
||||
/obj/item/device/assembly/flash/proc/clown_check(mob/living/carbon/human/user)
|
||||
/obj/item/assembly/flash/proc/clown_check(mob/living/carbon/human/user)
|
||||
if(user.has_trait(TRAIT_CLUMSY) && prob(50))
|
||||
flash_carbon(user, user, 15, 0)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/device/assembly/flash/proc/burn_out() //Made so you can override it if you want to have an invincible flash from R&D or something.
|
||||
/obj/item/assembly/flash/proc/burn_out() //Made so you can override it if you want to have an invincible flash from R&D or something.
|
||||
if(!crit_fail)
|
||||
crit_fail = TRUE
|
||||
update_icon()
|
||||
@@ -56,7 +57,7 @@
|
||||
var/turf/T = get_turf(src)
|
||||
T.visible_message("<span class='danger'>[src] burns out!</span>")
|
||||
|
||||
/obj/item/device/assembly/flash/proc/flash_recharge(interval = 10)
|
||||
/obj/item/assembly/flash/proc/flash_recharge(interval = 10)
|
||||
var/deciseconds_passed = world.time - last_used
|
||||
for(var/seconds = deciseconds_passed / 10, seconds >= interval, seconds -= interval) //get 1 charge every interval
|
||||
times_used--
|
||||
@@ -68,7 +69,7 @@
|
||||
return TRUE
|
||||
|
||||
//BYPASS CHECKS ALSO PREVENTS BURNOUT!
|
||||
/obj/item/device/assembly/flash/proc/AOE_flash(bypass_checks = FALSE, range = 3, power = 5, targeted = FALSE, mob/user)
|
||||
/obj/item/assembly/flash/proc/AOE_flash(bypass_checks = FALSE, range = 3, power = 5, targeted = FALSE, mob/user)
|
||||
if(!bypass_checks && !try_use_flash())
|
||||
return FALSE
|
||||
var/list/mob/targets = get_flash_targets(get_turf(src), range, FALSE)
|
||||
@@ -78,7 +79,7 @@
|
||||
flash_carbon(C, user, power, targeted, TRUE)
|
||||
return TRUE
|
||||
|
||||
/obj/item/device/assembly/flash/proc/get_flash_targets(atom/target_loc, range = 3, override_vision_checks = FALSE)
|
||||
/obj/item/assembly/flash/proc/get_flash_targets(atom/target_loc, range = 3, override_vision_checks = FALSE)
|
||||
if(!target_loc)
|
||||
target_loc = loc
|
||||
if(override_vision_checks)
|
||||
@@ -88,11 +89,11 @@
|
||||
else
|
||||
return typecache_filter_list(target_loc.GetAllContents(), typecacheof(list(/mob/living)))
|
||||
|
||||
/obj/item/device/assembly/flash/proc/try_use_flash(mob/user = null)
|
||||
/obj/item/assembly/flash/proc/try_use_flash(mob/user = null)
|
||||
if(crit_fail || (world.time < last_trigger + cooldown))
|
||||
return FALSE
|
||||
last_trigger = world.time
|
||||
playsound(src, 'sound/weapons/flash.ogg', 100, 1)
|
||||
playsound(src, 'sound/weapons/flash.ogg', 100, TRUE)
|
||||
times_used++
|
||||
flash_recharge()
|
||||
update_icon(TRUE)
|
||||
@@ -100,7 +101,7 @@
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/device/assembly/flash/proc/flash_carbon(mob/living/carbon/M, mob/user, power = 15, targeted = TRUE, generic_message = FALSE)
|
||||
/obj/item/assembly/flash/proc/flash_carbon(mob/living/carbon/M, mob/user, power = 15, targeted = TRUE, generic_message = FALSE)
|
||||
if(!istype(M))
|
||||
return
|
||||
add_logs(user, M, "[targeted? "flashed(targeted)" : "flashed(AOE)"]", src)
|
||||
@@ -127,7 +128,7 @@
|
||||
if(M.flash_act())
|
||||
M.confused += power
|
||||
|
||||
/obj/item/device/assembly/flash/attack(mob/living/M, mob/user)
|
||||
/obj/item/assembly/flash/attack(mob/living/M, mob/user)
|
||||
if(!try_use_flash(user))
|
||||
return FALSE
|
||||
if(iscarbon(M))
|
||||
@@ -145,26 +146,26 @@
|
||||
|
||||
user.visible_message("<span class='disarm'>[user] fails to blind [M] with the flash!</span>", "<span class='warning'>You fail to blind [M] with the flash!</span>")
|
||||
|
||||
/obj/item/device/assembly/flash/attack_self(mob/living/carbon/user, flag = 0, emp = 0)
|
||||
/obj/item/assembly/flash/attack_self(mob/living/carbon/user, flag = 0, emp = 0)
|
||||
if(holder)
|
||||
return FALSE
|
||||
if(!AOE_flash(FALSE, 3, 5, FALSE, user))
|
||||
return FALSE
|
||||
to_chat(user, "<span class='danger'>[src] emits a blinding light!</span>")
|
||||
|
||||
/obj/item/device/assembly/flash/emp_act(severity)
|
||||
/obj/item/assembly/flash/emp_act(severity)
|
||||
if(!try_use_flash())
|
||||
return FALSE
|
||||
AOE_flash()
|
||||
burn_out()
|
||||
. = ..()
|
||||
|
||||
/obj/item/device/assembly/flash/activate()//AOE flash on signal recieved
|
||||
/obj/item/assembly/flash/activate()//AOE flash on signal recieved
|
||||
if(!..())
|
||||
return
|
||||
AOE_flash()
|
||||
|
||||
/obj/item/device/assembly/flash/proc/terrible_conversion_proc(mob/living/carbon/human/H, mob/user)
|
||||
/obj/item/assembly/flash/proc/terrible_conversion_proc(mob/living/carbon/human/H, mob/user)
|
||||
if(istype(H) && ishuman(user) && H.stat != DEAD)
|
||||
if(user.mind)
|
||||
var/datum/antagonist/rev/head/converter = user.mind.has_antag_datum(/datum/antagonist/rev/head)
|
||||
@@ -182,58 +183,60 @@
|
||||
to_chat(user, "<span class='warning'>This mind seems resistant to the flash!</span>")
|
||||
|
||||
|
||||
/obj/item/device/assembly/flash/cyborg
|
||||
/obj/item/assembly/flash/cyborg
|
||||
|
||||
/obj/item/device/assembly/flash/cyborg/attack(mob/living/M, mob/user)
|
||||
/obj/item/assembly/flash/cyborg/attack(mob/living/M, mob/user)
|
||||
..()
|
||||
new /obj/effect/temp_visual/borgflash(get_turf(src))
|
||||
|
||||
/obj/item/device/assembly/flash/cyborg/attack_self(mob/user)
|
||||
/obj/item/assembly/flash/cyborg/attack_self(mob/user)
|
||||
..()
|
||||
new /obj/effect/temp_visual/borgflash(get_turf(src))
|
||||
|
||||
/obj/item/device/assembly/flash/cyborg/attackby(obj/item/W, mob/user, params)
|
||||
/obj/item/assembly/flash/cyborg/attackby(obj/item/W, mob/user, params)
|
||||
return
|
||||
/obj/item/assembly/flash/cyborg/screwdriver_act(mob/living/user, obj/item/I)
|
||||
return
|
||||
|
||||
/obj/item/device/assembly/flash/memorizer
|
||||
/obj/item/assembly/flash/memorizer
|
||||
name = "memorizer"
|
||||
desc = "If you see this, you're not likely to remember it any time soon."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "memorizer"
|
||||
item_state = "nullrod"
|
||||
|
||||
/obj/item/device/assembly/flash/handheld //this is now the regular pocket flashes
|
||||
/obj/item/assembly/flash/handheld //this is now the regular pocket flashes
|
||||
|
||||
/obj/item/device/assembly/flash/armimplant
|
||||
/obj/item/assembly/flash/armimplant
|
||||
name = "photon projector"
|
||||
desc = "A high-powered photon projector implant normally used for lighting purposes, but also doubles as a flashbulb weapon. Self-repair protocals fix the flashbulb if it ever burns out."
|
||||
var/flashcd = 20
|
||||
var/overheat = 0
|
||||
var/obj/item/organ/cyberimp/arm/flash/I = null
|
||||
|
||||
/obj/item/device/assembly/flash/armimplant/burn_out()
|
||||
/obj/item/assembly/flash/armimplant/burn_out()
|
||||
if(I && I.owner)
|
||||
to_chat(I.owner, "<span class='warning'>Your photon projector implant overheats and deactivates!</span>")
|
||||
I.Retract()
|
||||
overheat = TRUE
|
||||
addtimer(CALLBACK(src, .proc/cooldown), flashcd * 2)
|
||||
|
||||
/obj/item/device/assembly/flash/armimplant/try_use_flash(mob/user = null)
|
||||
/obj/item/assembly/flash/armimplant/try_use_flash(mob/user = null)
|
||||
if(overheat)
|
||||
if(I && I.owner)
|
||||
to_chat(I.owner, "<span class='warning'>Your photon projector is running too hot to be used again so quickly!</span>")
|
||||
return FALSE
|
||||
overheat = TRUE
|
||||
addtimer(CALLBACK(src, .proc/cooldown), flashcd)
|
||||
playsound(src, 'sound/weapons/flash.ogg', 100, 1)
|
||||
playsound(src, 'sound/weapons/flash.ogg', 100, TRUE)
|
||||
update_icon(1)
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/item/device/assembly/flash/armimplant/proc/cooldown()
|
||||
/obj/item/assembly/flash/armimplant/proc/cooldown()
|
||||
overheat = FALSE
|
||||
|
||||
/obj/item/device/assembly/flash/shield
|
||||
/obj/item/assembly/flash/shield
|
||||
name = "strobe shield"
|
||||
desc = "A shield with a built in, high intensity light capable of blinding and disorienting suspects. Takes regular handheld flashes as bulbs."
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
@@ -241,7 +244,7 @@
|
||||
item_state = "flashshield"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi'
|
||||
slot_flags = SLOT_BACK
|
||||
slot_flags = ITEM_SLOT_BACK
|
||||
force = 10
|
||||
throwforce = 5
|
||||
throw_speed = 2
|
||||
@@ -252,15 +255,15 @@
|
||||
block_chance = 50
|
||||
armor = list("melee" = 50, "bullet" = 50, "laser" = 50, "energy" = 0, "bomb" = 30, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 70)
|
||||
|
||||
/obj/item/device/assembly/flash/shield/flash_recharge(interval=10)
|
||||
/obj/item/assembly/flash/shield/flash_recharge(interval=10)
|
||||
if(times_used >= 4)
|
||||
burn_out()
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/device/assembly/flash/shield/attackby(obj/item/W, mob/user)
|
||||
if(istype(W, /obj/item/device/assembly/flash/handheld))
|
||||
var/obj/item/device/assembly/flash/handheld/flash = W
|
||||
/obj/item/assembly/flash/shield/attackby(obj/item/W, mob/user)
|
||||
if(istype(W, /obj/item/assembly/flash/handheld))
|
||||
var/obj/item/assembly/flash/handheld/flash = W
|
||||
if(flash.crit_fail)
|
||||
to_chat(user, "No sense replacing it with a broken bulb.")
|
||||
return
|
||||
@@ -271,14 +274,14 @@
|
||||
return
|
||||
crit_fail = FALSE
|
||||
times_used = 0
|
||||
playsound(src, 'sound/items/deconstruct.ogg', 50, 1)
|
||||
playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE)
|
||||
update_icon()
|
||||
flash.crit_fail = TRUE
|
||||
flash.update_icon()
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/device/assembly/flash/shield/update_icon(flash = FALSE)
|
||||
/obj/item/assembly/flash/shield/update_icon(flash = FALSE)
|
||||
icon_state = "flashshield"
|
||||
item_state = "flashshield"
|
||||
|
||||
@@ -293,6 +296,6 @@
|
||||
if(holder)
|
||||
holder.update_icon()
|
||||
|
||||
/obj/item/device/assembly/flash/shield/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
|
||||
/obj/item/assembly/flash/shield/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
|
||||
activate()
|
||||
return ..()
|
||||
|
||||
@@ -1,48 +1,45 @@
|
||||
/obj/item/device/assembly/health
|
||||
/obj/item/assembly/health
|
||||
name = "health sensor"
|
||||
desc = "Used for scanning and monitoring health."
|
||||
icon_state = "health"
|
||||
materials = list(MAT_METAL=800, MAT_GLASS=200)
|
||||
attachable = 1
|
||||
secured = 0
|
||||
attachable = TRUE
|
||||
secured = FALSE
|
||||
|
||||
var/scanning = 0
|
||||
var/scanning = FALSE
|
||||
var/health_scan
|
||||
var/alarm_health = 0
|
||||
|
||||
/obj/item/device/assembly/health/examine(mob/user)
|
||||
/obj/item/assembly/health/examine(mob/user)
|
||||
..()
|
||||
to_chat(user, "<span class='notice'>Use a multitool to swap between \"detect death\" mode and \"detect critical state\" mode.</span>")
|
||||
|
||||
/obj/item/device/assembly/health/activate()
|
||||
/obj/item/assembly/health/activate()
|
||||
if(!..())
|
||||
return 0//Cooldown check
|
||||
return FALSE//Cooldown check
|
||||
toggle_scan()
|
||||
return 0
|
||||
return TRUE
|
||||
|
||||
/obj/item/device/assembly/health/toggle_secure()
|
||||
/obj/item/assembly/health/toggle_secure()
|
||||
secured = !secured
|
||||
if(secured && scanning)
|
||||
START_PROCESSING(SSobj, src)
|
||||
else
|
||||
scanning = 0
|
||||
scanning = FALSE
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
update_icon()
|
||||
return secured
|
||||
|
||||
/obj/item/device/assembly/health/attackby(obj/item/W as obj, mob/user as mob)
|
||||
if(istype(W, /obj/item/device/multitool))
|
||||
if(alarm_health == 0)
|
||||
alarm_health = -90
|
||||
user.show_message("You toggle [src] to \"detect death\" mode.")
|
||||
else
|
||||
alarm_health = 0
|
||||
user.show_message("You toggle [src] to \"detect critical state\" mode.")
|
||||
return
|
||||
/obj/item/assembly/health/multitool_act(mob/living/user, obj/item/I)
|
||||
if(alarm_health == 0)
|
||||
alarm_health = -90
|
||||
to_chat(user, "<span class='notice'>You toggle [src] to \"detect death\" mode.</span>")
|
||||
else
|
||||
return ..()
|
||||
alarm_health = 0
|
||||
to_chat(user, "<span class='notice'>You toggle [src] to \"detect critical state\" mode.</span>")
|
||||
return TRUE
|
||||
|
||||
/obj/item/device/assembly/health/process()
|
||||
/obj/item/assembly/health/process()
|
||||
if(!scanning || !secured)
|
||||
return
|
||||
|
||||
@@ -58,12 +55,13 @@
|
||||
health_scan = M.health
|
||||
if(health_scan <= alarm_health)
|
||||
pulse()
|
||||
audible_message("[icon2html(src, hearers(src))] *beep* *beep*", "*beep* *beep*")
|
||||
audible_message("[icon2html(src, hearers(src))] *beep* *beep* *beep*")
|
||||
playsound(src, 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE)
|
||||
toggle_scan()
|
||||
return
|
||||
return
|
||||
|
||||
/obj/item/device/assembly/health/proc/toggle_scan()
|
||||
/obj/item/assembly/health/proc/toggle_scan()
|
||||
if(!secured)
|
||||
return 0
|
||||
scanning = !scanning
|
||||
@@ -73,18 +71,19 @@
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return
|
||||
|
||||
/obj/item/device/assembly/health/ui_interact(mob/user as mob)//TODO: Change this to the wires thingy
|
||||
/obj/item/assembly/health/ui_interact(mob/user as mob)//TODO: Change this to the wires thingy
|
||||
. = ..()
|
||||
if(!secured)
|
||||
user.show_message("<span class='warning'>The [name] is unsecured!</span>")
|
||||
return 0
|
||||
var/dat = "<TT><B>Health Sensor</B> <A href='?src=[REF(src)];scanning=1'>[scanning?"On":"Off"]</A>"
|
||||
return FALSE
|
||||
var/dat = "<TT><B>Health Sensor</B></TT>"
|
||||
dat += "<BR><A href='?src=[REF(src)];scanning=1'>[scanning?"On":"Off"]</A>"
|
||||
if(scanning && health_scan)
|
||||
dat += "<BR>Health: [health_scan]"
|
||||
user << browse(dat, "window=hscan")
|
||||
onclose(user, "hscan")
|
||||
|
||||
/obj/item/device/assembly/health/Topic(href, href_list)
|
||||
/obj/item/assembly/health/Topic(href, href_list)
|
||||
..()
|
||||
if(!ismob(usr))
|
||||
return
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
// See _DEFINES/is_helpers.dm for type helpers
|
||||
|
||||
/*
|
||||
Name: IsSpecialAssembly
|
||||
Desc: If true is an object that can be attached to an assembly holder but is a special thing like a plasma can or door
|
||||
*/
|
||||
|
||||
/obj/proc/IsSpecialAssembly()
|
||||
return 0
|
||||
|
||||
/*
|
||||
Name: IsAssemblyHolder
|
||||
Desc: If true is an object that can hold an assemblyholder object
|
||||
*/
|
||||
/obj/proc/IsAssemblyHolder()
|
||||
return 0
|
||||
// See _DEFINES/is_helpers.dm for type helpers
|
||||
|
||||
/*
|
||||
Name: IsSpecialAssembly
|
||||
Desc: If true is an object that can be attached to an assembly holder but is a special thing like a plasma can or door
|
||||
*/
|
||||
|
||||
/obj/proc/IsSpecialAssembly()
|
||||
return FALSE
|
||||
|
||||
/*
|
||||
Name: IsAssemblyHolder
|
||||
Desc: If true is an object that can hold an assemblyholder object
|
||||
*/
|
||||
/obj/proc/IsAssemblyHolder()
|
||||
return FALSE
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/obj/item/device/assembly_holder
|
||||
/obj/item/assembly_holder
|
||||
name = "Assembly"
|
||||
icon = 'icons/obj/assemblies/new_assemblies.dmi'
|
||||
icon_state = "holder"
|
||||
@@ -11,21 +11,21 @@
|
||||
throw_speed = 2
|
||||
throw_range = 7
|
||||
|
||||
var/obj/item/device/assembly/a_left = null
|
||||
var/obj/item/device/assembly/a_right = null
|
||||
var/obj/item/assembly/a_left = null
|
||||
var/obj/item/assembly/a_right = null
|
||||
|
||||
/obj/item/device/assembly_holder/IsAssemblyHolder()
|
||||
return 1
|
||||
/obj/item/assembly_holder/IsAssemblyHolder()
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/item/device/assembly_holder/proc/assemble(obj/item/device/assembly/A, obj/item/device/assembly/A2, mob/user)
|
||||
/obj/item/assembly_holder/proc/assemble(obj/item/assembly/A, obj/item/assembly/A2, mob/user)
|
||||
attach(A,user)
|
||||
attach(A2,user)
|
||||
name = "[A.name]-[A2.name] assembly"
|
||||
update_icon()
|
||||
SSblackbox.record_feedback("tally", "assembly_made", 1, "[initial(A.name)]-[initial(A2.name)]")
|
||||
|
||||
/obj/item/device/assembly_holder/proc/attach(obj/item/device/assembly/A, mob/user)
|
||||
/obj/item/assembly_holder/proc/attach(obj/item/assembly/A, mob/user)
|
||||
if(!A.remove_item_from_storage(src))
|
||||
if(user)
|
||||
user.transferItemToLoc(A, src)
|
||||
@@ -37,8 +37,9 @@
|
||||
a_left = A
|
||||
else
|
||||
a_right = A
|
||||
A.holder_movement()
|
||||
|
||||
/obj/item/device/assembly_holder/update_icon()
|
||||
/obj/item/assembly_holder/update_icon()
|
||||
cut_overlays()
|
||||
if(a_left)
|
||||
add_overlay("[a_left.icon_state]_left")
|
||||
@@ -46,57 +47,67 @@
|
||||
add_overlay("[O]_l")
|
||||
|
||||
if(a_right)
|
||||
var/mutable_appearance/right = mutable_appearance(icon, "[a_right.icon_state]_left")
|
||||
right.transform = matrix(-1, 0, 0, 0, 1, 0)
|
||||
for(var/O in a_right.attached_overlays)
|
||||
right.add_overlay("[O]_l")
|
||||
add_overlay(right)
|
||||
if(a_right.is_position_sensitive)
|
||||
add_overlay("[a_right.icon_state]_right")
|
||||
for(var/O in a_right.attached_overlays)
|
||||
add_overlay("[O]_r")
|
||||
else
|
||||
var/mutable_appearance/right = mutable_appearance(icon, "[a_right.icon_state]_left")
|
||||
right.transform = matrix(-1, 0, 0, 0, 1, 0)
|
||||
for(var/O in a_right.attached_overlays)
|
||||
right.add_overlay("[O]_l")
|
||||
add_overlay(right)
|
||||
|
||||
if(master)
|
||||
master.update_icon()
|
||||
|
||||
/obj/item/device/assembly_holder/Crossed(atom/movable/AM as mob|obj)
|
||||
/obj/item/assembly_holder/Crossed(atom/movable/AM as mob|obj)
|
||||
if(a_left)
|
||||
a_left.Crossed(AM)
|
||||
if(a_right)
|
||||
a_right.Crossed(AM)
|
||||
|
||||
/obj/item/device/assembly_holder/on_found(mob/finder)
|
||||
/obj/item/assembly_holder/on_found(mob/finder)
|
||||
if(a_left)
|
||||
a_left.on_found(finder)
|
||||
if(a_right)
|
||||
a_right.on_found(finder)
|
||||
|
||||
/obj/item/device/assembly_holder/Move()
|
||||
/obj/item/assembly_holder/Move()
|
||||
. = ..()
|
||||
if(a_left && a_right)
|
||||
if(a_left)
|
||||
a_left.holder_movement()
|
||||
if(a_right)
|
||||
a_right.holder_movement()
|
||||
|
||||
/obj/item/device/assembly_holder/attack_hand()//Perhapse this should be a holder_pickup proc instead, can add if needbe I guess
|
||||
/obj/item/assembly_holder/dropped(mob/user)
|
||||
. = ..()
|
||||
if(a_left)
|
||||
a_left.dropped()
|
||||
if(a_right)
|
||||
a_right.dropped()
|
||||
|
||||
/obj/item/assembly_holder/attack_hand()//Perhapse this should be a holder_pickup proc instead, can add if needbe I guess
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(a_left && a_right)
|
||||
a_left.holder_movement()
|
||||
a_right.holder_movement()
|
||||
if(a_left)
|
||||
a_left.attack_hand()
|
||||
if(a_right)
|
||||
a_right.attack_hand()
|
||||
|
||||
/obj/item/device/assembly_holder/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/screwdriver))
|
||||
var/turf/T = get_turf(src)
|
||||
if(!T)
|
||||
return 0
|
||||
if(a_left)
|
||||
a_left.holder = null
|
||||
a_left.forceMove(T)
|
||||
if(a_right)
|
||||
a_right.holder = null
|
||||
a_right.forceMove(T)
|
||||
qdel(src)
|
||||
else
|
||||
..()
|
||||
/obj/item/assembly_holder/screwdriver_act(mob/user, obj/item/tool)
|
||||
to_chat(user, "<span class='notice'>You disassemble [src]!</span>")
|
||||
if(a_left)
|
||||
a_left.on_detach()
|
||||
a_left = null
|
||||
if(a_right)
|
||||
a_right.on_detach()
|
||||
a_right = null
|
||||
qdel(src)
|
||||
return TRUE
|
||||
|
||||
/obj/item/device/assembly_holder/attack_self(mob/user)
|
||||
/obj/item/assembly_holder/attack_self(mob/user)
|
||||
src.add_fingerprint(user)
|
||||
if(!a_left || !a_right)
|
||||
to_chat(user, "<span class='danger'>Assembly part missing!</span>")
|
||||
@@ -113,14 +124,14 @@
|
||||
a_right.attack_self(user)
|
||||
|
||||
|
||||
/obj/item/device/assembly_holder/proc/process_activation(obj/D, normal = 1, special = 1)
|
||||
/obj/item/assembly_holder/proc/process_activation(obj/D, normal = 1, special = 1)
|
||||
if(!D)
|
||||
return 0
|
||||
return FALSE
|
||||
if((normal) && (a_right) && (a_left))
|
||||
if(a_right != D)
|
||||
a_right.pulsed(0)
|
||||
a_right.pulsed(FALSE)
|
||||
if(a_left != D)
|
||||
a_left.pulsed(0)
|
||||
a_left.pulsed(FALSE)
|
||||
if(master)
|
||||
master.receive_signal()
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/obj/item/device/assembly/igniter
|
||||
/obj/item/assembly/igniter
|
||||
name = "igniter"
|
||||
desc = "A small electronic device able to ignite combustible substances."
|
||||
icon_state = "igniter"
|
||||
@@ -6,35 +6,35 @@
|
||||
var/datum/effect_system/spark_spread/sparks = new /datum/effect_system/spark_spread
|
||||
heat = 1000
|
||||
|
||||
/obj/item/device/assembly/igniter/suicide_act(mob/living/carbon/user)
|
||||
/obj/item/assembly/igniter/suicide_act(mob/living/carbon/user)
|
||||
user.visible_message("<span class='suicide'>[user] is trying to ignite [user.p_them()]self with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
user.IgniteMob()
|
||||
return FIRELOSS
|
||||
|
||||
/obj/item/device/assembly/igniter/New()
|
||||
/obj/item/assembly/igniter/New()
|
||||
..()
|
||||
sparks.set_up(2, 0, src)
|
||||
sparks.attach(src)
|
||||
|
||||
/obj/item/device/assembly/igniter/Destroy()
|
||||
/obj/item/assembly/igniter/Destroy()
|
||||
qdel(sparks)
|
||||
sparks = null
|
||||
. = ..()
|
||||
|
||||
/obj/item/device/assembly/igniter/activate()
|
||||
/obj/item/assembly/igniter/activate()
|
||||
if(!..())
|
||||
return 0//Cooldown check
|
||||
return FALSE//Cooldown check
|
||||
var/turf/location = get_turf(loc)
|
||||
if(location)
|
||||
location.hotspot_expose(1000,1000)
|
||||
sparks.start()
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/obj/item/device/assembly/igniter/attack_self(mob/user)
|
||||
/obj/item/assembly/igniter/attack_self(mob/user)
|
||||
activate()
|
||||
add_fingerprint(user)
|
||||
|
||||
/obj/item/device/assembly/igniter/ignition_effect(atom/A, mob/user)
|
||||
/obj/item/assembly/igniter/ignition_effect(atom/A, mob/user)
|
||||
. = "<span class='notice'>[user] fiddles with [src], and manages to \
|
||||
light [A].</span>"
|
||||
activate()
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
/obj/item/device/assembly/infra
|
||||
/obj/item/assembly/infra
|
||||
name = "infrared emitter"
|
||||
desc = "Emits a visible or invisible beam and is triggered when the beam is interrupted.\n<span class='notice'>Alt-click to rotate it clockwise.</span>"
|
||||
desc = "Emits a visible or invisible beam and is triggered when the beam is interrupted."
|
||||
icon_state = "infrared"
|
||||
materials = list(MAT_METAL=1000, MAT_GLASS=500)
|
||||
is_position_sensitive = TRUE
|
||||
|
||||
var/on = FALSE
|
||||
var/visible = FALSE
|
||||
@@ -10,58 +11,91 @@
|
||||
var/list/obj/effect/beam/i_beam/beams
|
||||
var/olddir = 0
|
||||
var/datum/component/redirect/listener
|
||||
var/hearing_range = 3
|
||||
|
||||
/obj/item/device/assembly/infra/Initialize()
|
||||
/obj/item/assembly/infra/Initialize()
|
||||
. = ..()
|
||||
beams = list()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/device/assembly/infra/Destroy()
|
||||
/obj/item/assembly/infra/ComponentInitialize()
|
||||
. = ..()
|
||||
AddComponent(
|
||||
/datum/component/simple_rotation,
|
||||
ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_FLIP | ROTATION_VERBS,
|
||||
null,
|
||||
null,
|
||||
CALLBACK(src,.proc/after_rotation)
|
||||
)
|
||||
|
||||
/obj/item/assembly/infra/proc/after_rotation()
|
||||
refreshBeam()
|
||||
|
||||
/obj/item/assembly/infra/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
QDEL_LIST(beams)
|
||||
return ..()
|
||||
. = ..()
|
||||
|
||||
/obj/item/device/assembly/infra/describe()
|
||||
return "The infrared trigger is [on?"on":"off"]."
|
||||
/obj/item/assembly/infra/examine(mob/user)
|
||||
..()
|
||||
to_chat(user, "<span class='notice'>The infrared trigger is [on?"on":"off"].</span>")
|
||||
|
||||
/obj/item/device/assembly/infra/activate()
|
||||
/obj/item/assembly/infra/activate()
|
||||
if(!..())
|
||||
return 0//Cooldown check
|
||||
return FALSE//Cooldown check
|
||||
on = !on
|
||||
refreshBeam()
|
||||
update_icon()
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/obj/item/device/assembly/infra/toggle_secure()
|
||||
/obj/item/assembly/infra/toggle_secure()
|
||||
secured = !secured
|
||||
if(secured)
|
||||
START_PROCESSING(SSobj, src)
|
||||
refreshBeam()
|
||||
else
|
||||
QDEL_LIST(beams)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
update_icon()
|
||||
return secured
|
||||
|
||||
/obj/item/device/assembly/infra/update_icon()
|
||||
/obj/item/assembly/infra/update_icon()
|
||||
cut_overlays()
|
||||
attached_overlays = list()
|
||||
if(on)
|
||||
add_overlay("infrared_on")
|
||||
attached_overlays += "infrared_on"
|
||||
if(visible && secured)
|
||||
add_overlay("infrared_visible")
|
||||
attached_overlays += "infrared_visible"
|
||||
|
||||
if(holder)
|
||||
holder.update_icon()
|
||||
return
|
||||
|
||||
/obj/item/device/assembly/infra/dropped()
|
||||
refreshBeam()
|
||||
/obj/item/assembly/infra/dropped()
|
||||
. = ..()
|
||||
if(holder)
|
||||
holder_movement() //sync the dir of the device as well if it's contained in a TTV or an assembly holder
|
||||
else
|
||||
refreshBeam()
|
||||
|
||||
/obj/item/device/assembly/infra/process()
|
||||
/obj/item/assembly/infra/process()
|
||||
if(!on || !secured)
|
||||
refreshBeam()
|
||||
return
|
||||
|
||||
/obj/item/device/assembly/infra/proc/refreshBeam()
|
||||
/obj/item/assembly/infra/proc/refreshBeam()
|
||||
QDEL_LIST(beams)
|
||||
if(throwing || !on || !secured || !(isturf(loc) || holder && isturf(holder.loc)))
|
||||
if(throwing || !on || !secured)
|
||||
return
|
||||
if(holder)
|
||||
if(holder.master) //incase the sensor is part of an assembly that's contained in another item, such as a single tank bomb
|
||||
if(!holder.master.IsSpecialAssembly() || !isturf(holder.master.loc))
|
||||
return
|
||||
else if(!isturf(holder.loc)) //else just check where the holder is
|
||||
return
|
||||
else if(!isturf(loc)) //or just where the fuck we are in general
|
||||
return
|
||||
var/turf/T = get_turf(src)
|
||||
var/_dir = dir
|
||||
@@ -69,6 +103,11 @@
|
||||
if(_T)
|
||||
for(var/i in 1 to maxlength)
|
||||
var/obj/effect/beam/i_beam/I = new(T)
|
||||
if(istype(holder, /obj/item/assembly_holder))
|
||||
var/obj/item/assembly_holder/assembly_holder = holder
|
||||
I.icon_state = "[initial(I.icon_state)]_[(assembly_holder.a_left == src) ? "l":"r"]" //Sync the offset of the beam with the position of the sensor.
|
||||
else if(istype(holder, /obj/item/transfer_valve))
|
||||
I.icon_state = "[initial(I.icon_state)]_ttv"
|
||||
I.density = TRUE
|
||||
if(!I.Move(_T))
|
||||
qdel(I)
|
||||
@@ -83,62 +122,68 @@
|
||||
_T = get_step(_T, _dir)
|
||||
CHECK_TICK
|
||||
|
||||
/obj/item/device/assembly/infra/attack_hand()
|
||||
/obj/item/assembly/infra/on_detach()
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
refreshBeam()
|
||||
|
||||
/obj/item/assembly/infra/attack_hand()
|
||||
. = ..()
|
||||
refreshBeam()
|
||||
|
||||
/obj/item/device/assembly/infra/Moved()
|
||||
/obj/item/assembly/infra/Moved()
|
||||
var/t = dir
|
||||
. = ..()
|
||||
setDir(t)
|
||||
|
||||
/obj/item/device/assembly/infra/throw_at()
|
||||
/obj/item/assembly/infra/throw_at()
|
||||
. = ..()
|
||||
olddir = dir
|
||||
|
||||
/obj/item/device/assembly/infra/throw_impact()
|
||||
/obj/item/assembly/infra/throw_impact()
|
||||
. = ..()
|
||||
if(!olddir)
|
||||
return
|
||||
setDir(olddir)
|
||||
olddir = null
|
||||
|
||||
/obj/item/device/assembly/infra/holder_movement()
|
||||
if(!holder)
|
||||
return 0
|
||||
refreshBeam()
|
||||
return 1
|
||||
|
||||
/obj/item/device/assembly/infra/proc/trigger_beam(atom/movable/AM, turf/location)
|
||||
/obj/item/assembly/infra/proc/trigger_beam(atom/movable/AM, turf/location)
|
||||
refreshBeam()
|
||||
switchListener(location)
|
||||
if(!secured || !on || next_activate > world.time)
|
||||
return FALSE
|
||||
pulse(0)
|
||||
audible_message("[icon2html(src, hearers(src))] *beep* *beep*", null, 3)
|
||||
pulse(FALSE)
|
||||
audible_message("[icon2html(src, hearers(src))] *beep* *beep* *beep*", null, hearing_range)
|
||||
for(var/CHM in get_hearers_in_view(hearing_range, src))
|
||||
if(ismob(CHM))
|
||||
var/mob/LM = CHM
|
||||
LM.playsound_local(get_turf(src), 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE)
|
||||
next_activate = world.time + 30
|
||||
|
||||
/obj/item/device/assembly/infra/proc/switchListener(turf/newloc)
|
||||
/obj/item/assembly/infra/proc/switchListener(turf/newloc)
|
||||
QDEL_NULL(listener)
|
||||
listener = newloc.AddComponent(/datum/component/redirect, COMSIG_ATOM_EXITED, CALLBACK(src, .proc/check_exit))
|
||||
|
||||
/obj/item/device/assembly/infra/proc/check_exit(atom/movable/offender)
|
||||
/obj/item/assembly/infra/proc/check_exit(atom/movable/offender)
|
||||
if(offender && ((offender.flags_1 & ABSTRACT_1) || offender == src))
|
||||
return
|
||||
return refreshBeam()
|
||||
|
||||
/obj/item/device/assembly/infra/ui_interact(mob/user)//TODO: change this this to the wire control panel
|
||||
/obj/item/assembly/infra/ui_interact(mob/user)//TODO: change this this to the wire control panel
|
||||
. = ..()
|
||||
if(is_secured(user))
|
||||
user.set_machine(src)
|
||||
var/dat = "<TT><B>Infrared Laser</B>\n<B>Status</B>: [on ? "<A href='?src=[REF(src)];state=0'>On</A>" : "<A href='?src=[REF(src)];state=1'>Off</A>"]<BR>\n<B>Visibility</B>: [visible ? "<A href='?src=[REF(src)];visible=0'>Visible</A>" : "<A href='?src=[REF(src)];visible=1'>Invisible</A>"]<BR>\n</TT>"
|
||||
var/dat = "<TT><B>Infrared Laser</B></TT>"
|
||||
dat += "<BR><B>Status</B>: [on ? "<A href='?src=[REF(src)];state=0'>On</A>" : "<A href='?src=[REF(src)];state=1'>Off</A>"]"
|
||||
dat += "<BR><B>Visibility</B>: [visible ? "<A href='?src=[REF(src)];visible=0'>Visible</A>" : "<A href='?src=[REF(src)];visible=1'>Invisible</A>"]"
|
||||
dat += "<BR><BR><A href='?src=[REF(src)];refresh=1'>Refresh</A>"
|
||||
dat += "<BR><BR><A href='?src=[REF(src)];close=1'>Close</A>"
|
||||
user << browse(dat, "window=infra")
|
||||
onclose(user, "infra")
|
||||
return
|
||||
|
||||
/obj/item/device/assembly/infra/Topic(href, href_list)
|
||||
/obj/item/assembly/infra/Topic(href, href_list)
|
||||
..()
|
||||
if(usr.incapacitated() || !in_range(loc, usr))
|
||||
usr << browse(null, "window=infra")
|
||||
@@ -150,6 +195,7 @@
|
||||
refreshBeam()
|
||||
if(href_list["visible"])
|
||||
visible = !(visible)
|
||||
update_icon()
|
||||
refreshBeam()
|
||||
if(href_list["close"])
|
||||
usr << browse(null, "window=infra")
|
||||
@@ -157,24 +203,7 @@
|
||||
if(usr)
|
||||
attack_self(usr)
|
||||
|
||||
/obj/item/device/assembly/infra/verb/rotate()//This could likely be better
|
||||
set name = "Rotate Infrared Laser"
|
||||
set category = "Object"
|
||||
set src in usr
|
||||
|
||||
if(!usr.canUseTopic(src, BE_CLOSE, NO_DEXTERY))
|
||||
return
|
||||
|
||||
setDir(turn(dir, -90))
|
||||
|
||||
/obj/item/device/assembly/infra/AltClick(mob/user)
|
||||
..()
|
||||
if(!user.canUseTopic(src, BE_CLOSE, NO_DEXTERY))
|
||||
return
|
||||
else
|
||||
rotate()
|
||||
|
||||
/obj/item/device/assembly/infra/setDir()
|
||||
/obj/item/assembly/infra/setDir()
|
||||
. = ..()
|
||||
refreshBeam()
|
||||
|
||||
@@ -184,7 +213,7 @@
|
||||
name = "infrared beam"
|
||||
icon = 'icons/obj/projectiles.dmi'
|
||||
icon_state = "ibeam"
|
||||
var/obj/item/device/assembly/infra/master
|
||||
var/obj/item/assembly/infra/master
|
||||
anchored = TRUE
|
||||
density = FALSE
|
||||
flags_1 = ABSTRACT_1
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
/obj/item/device/assembly/mousetrap
|
||||
/obj/item/assembly/mousetrap
|
||||
name = "mousetrap"
|
||||
desc = "A handy little spring-loaded trap for catching pesty rodents."
|
||||
icon_state = "mousetrap"
|
||||
item_state = "mousetrap"
|
||||
materials = list(MAT_METAL=100)
|
||||
attachable = 1
|
||||
var/armed = 0
|
||||
attachable = TRUE
|
||||
var/armed = FALSE
|
||||
|
||||
|
||||
/obj/item/device/assembly/mousetrap/examine(mob/user)
|
||||
/obj/item/assembly/mousetrap/examine(mob/user)
|
||||
..()
|
||||
if(armed)
|
||||
to_chat(user, "The mousetrap is armed!")
|
||||
else
|
||||
to_chat(user, "The mousetrap is not armed.")
|
||||
to_chat(user, "<span class='notice'>The pressure plate is [armed?"primed":"safe"].</span>")
|
||||
|
||||
/obj/item/device/assembly/mousetrap/activate()
|
||||
/obj/item/assembly/mousetrap/activate()
|
||||
if(..())
|
||||
armed = !armed
|
||||
if(!armed)
|
||||
@@ -22,15 +20,11 @@
|
||||
var/mob/living/carbon/human/user = usr
|
||||
if((user.has_trait(TRAIT_DUMB) || user.has_trait(TRAIT_CLUMSY)) && prob(50))
|
||||
to_chat(user, "<span class='warning'>Your hand slips, setting off the trigger!</span>")
|
||||
pulse(0)
|
||||
pulse(FALSE)
|
||||
update_icon()
|
||||
if(usr)
|
||||
playsound(usr.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -3)
|
||||
playsound(src, 'sound/weapons/handcuffs.ogg', 30, TRUE, -3)
|
||||
|
||||
/obj/item/device/assembly/mousetrap/describe()
|
||||
return "The pressure switch is [armed?"primed":"safe"]."
|
||||
|
||||
/obj/item/device/assembly/mousetrap/update_icon()
|
||||
/obj/item/assembly/mousetrap/update_icon()
|
||||
if(armed)
|
||||
icon_state = "mousetraparmed"
|
||||
else
|
||||
@@ -38,18 +32,18 @@
|
||||
if(holder)
|
||||
holder.update_icon()
|
||||
|
||||
/obj/item/device/assembly/mousetrap/proc/triggered(mob/target, type = "feet")
|
||||
/obj/item/assembly/mousetrap/proc/triggered(mob/target, type = "feet")
|
||||
if(!armed)
|
||||
return
|
||||
var/obj/item/bodypart/affecting = null
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
if(H.has_trait(TRAIT_PIERCEIMMUNE))
|
||||
playsound(src.loc, 'sound/effects/snap.ogg', 50, 1)
|
||||
armed = 0
|
||||
playsound(src, 'sound/effects/snap.ogg', 50, TRUE)
|
||||
armed = FALSE
|
||||
update_icon()
|
||||
pulse(0)
|
||||
return 0
|
||||
pulse(FALSE)
|
||||
return FALSE
|
||||
switch(type)
|
||||
if("feet")
|
||||
if(!H.shoes)
|
||||
@@ -66,13 +60,13 @@
|
||||
var/mob/living/simple_animal/mouse/M = target
|
||||
visible_message("<span class='boldannounce'>SPLAT!</span>")
|
||||
M.splat()
|
||||
playsound(src.loc, 'sound/effects/snap.ogg', 50, 1)
|
||||
armed = 0
|
||||
playsound(src, 'sound/effects/snap.ogg', 50, TRUE)
|
||||
armed = FALSE
|
||||
update_icon()
|
||||
pulse(0)
|
||||
pulse(FALSE)
|
||||
|
||||
|
||||
/obj/item/device/assembly/mousetrap/attack_self(mob/living/carbon/human/user)
|
||||
/obj/item/assembly/mousetrap/attack_self(mob/living/carbon/human/user)
|
||||
if(!armed)
|
||||
to_chat(user, "<span class='notice'>You arm [src].</span>")
|
||||
else
|
||||
@@ -87,11 +81,11 @@
|
||||
to_chat(user, "<span class='notice'>You disarm [src].</span>")
|
||||
armed = !armed
|
||||
update_icon()
|
||||
playsound(user.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -3)
|
||||
playsound(src, 'sound/weapons/handcuffs.ogg', 30, TRUE, -3)
|
||||
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/item/device/assembly/mousetrap/attack_hand(mob/living/carbon/human/user)
|
||||
/obj/item/assembly/mousetrap/attack_hand(mob/living/carbon/human/user)
|
||||
if(armed)
|
||||
if((user.has_trait(TRAIT_DUMB) || user.has_trait(TRAIT_CLUMSY)) && prob(50))
|
||||
var/which_hand = BODY_ZONE_PRECISE_L_HAND
|
||||
@@ -104,7 +98,7 @@
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/item/device/assembly/mousetrap/Crossed(atom/movable/AM as mob|obj)
|
||||
/obj/item/assembly/mousetrap/Crossed(atom/movable/AM as mob|obj)
|
||||
if(armed)
|
||||
if(ismob(AM))
|
||||
var/mob/MM = AM
|
||||
@@ -122,22 +116,27 @@
|
||||
..()
|
||||
|
||||
|
||||
/obj/item/device/assembly/mousetrap/on_found(mob/finder)
|
||||
/obj/item/assembly/mousetrap/on_found(mob/finder)
|
||||
if(armed)
|
||||
finder.visible_message("<span class='warning'>[finder] accidentally sets off [src], breaking their fingers.</span>", \
|
||||
if(finder)
|
||||
finder.visible_message("<span class='warning'>[finder] accidentally sets off [src], breaking their fingers.</span>", \
|
||||
"<span class='warning'>You accidentally trigger [src]!</span>")
|
||||
triggered(finder, (finder.active_hand_index % 2 == 0) ? BODY_ZONE_PRECISE_R_HAND : BODY_ZONE_PRECISE_L_HAND)
|
||||
return 1 //end the search!
|
||||
return 0
|
||||
triggered(finder, (finder.active_hand_index % 2 == 0) ? BODY_ZONE_PRECISE_R_HAND : BODY_ZONE_PRECISE_L_HAND)
|
||||
return TRUE //end the search!
|
||||
else
|
||||
visible_message("<span class='warning'>[src] snaps shut!</span>")
|
||||
triggered(loc)
|
||||
return FALSE
|
||||
return FALSE
|
||||
|
||||
|
||||
/obj/item/device/assembly/mousetrap/hitby(A as mob|obj)
|
||||
/obj/item/assembly/mousetrap/hitby(A as mob|obj)
|
||||
if(!armed)
|
||||
return ..()
|
||||
visible_message("<span class='warning'>[src] is triggered by [A].</span>")
|
||||
triggered(null)
|
||||
|
||||
|
||||
/obj/item/device/assembly/mousetrap/armed
|
||||
/obj/item/assembly/mousetrap/armed
|
||||
icon_state = "mousetraparmed"
|
||||
armed = 1
|
||||
armed = TRUE
|
||||
|
||||
@@ -1,86 +1,96 @@
|
||||
/obj/item/device/assembly/prox_sensor
|
||||
/obj/item/assembly/prox_sensor
|
||||
name = "proximity sensor"
|
||||
desc = "Used for scanning and alerting when someone enters a certain proximity."
|
||||
icon_state = "prox"
|
||||
materials = list(MAT_METAL=800, MAT_GLASS=200)
|
||||
attachable = 1
|
||||
attachable = TRUE
|
||||
|
||||
var/scanning = 0
|
||||
var/timing = 0
|
||||
var/scanning = FALSE
|
||||
var/timing = FALSE
|
||||
var/time = 10
|
||||
var/sensitivity = 1
|
||||
var/hearing_range = 3
|
||||
|
||||
/obj/item/device/assembly/prox_sensor/proc/toggle_scan()
|
||||
|
||||
|
||||
/obj/item/device/assembly/prox_sensor/proc/sense()
|
||||
|
||||
|
||||
/obj/item/device/assembly/prox_sensor/Initialize()
|
||||
/obj/item/assembly/prox_sensor/Initialize()
|
||||
. = ..()
|
||||
proximity_monitor = new(src, 0)
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/device/assembly/prox_sensor/describe()
|
||||
if(timing)
|
||||
return "<span class='notice'>The proximity sensor is arming.</span>"
|
||||
return "The proximity sensor is [scanning?"armed":"disarmed"]."
|
||||
/obj/item/assembly/prox_sensor/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
. = ..()
|
||||
|
||||
/obj/item/device/assembly/prox_sensor/activate()
|
||||
/obj/item/assembly/prox_sensor/examine(mob/user)
|
||||
..()
|
||||
to_chat(user, "<span class='notice'>The proximity sensor is [timing ? "arming" : (scanning ? "armed" : "disarmed")].</span>")
|
||||
|
||||
/obj/item/assembly/prox_sensor/activate()
|
||||
if(!..())
|
||||
return 0//Cooldown check
|
||||
timing = !timing
|
||||
return FALSE//Cooldown check
|
||||
if(!scanning)
|
||||
timing = !timing
|
||||
else
|
||||
scanning = FALSE
|
||||
update_icon()
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/obj/item/device/assembly/prox_sensor/toggle_secure()
|
||||
/obj/item/assembly/prox_sensor/toggle_secure()
|
||||
secured = !secured
|
||||
if(!secured)
|
||||
if(scanning)
|
||||
toggle_scan()
|
||||
proximity_monitor.host = src
|
||||
timing = 0
|
||||
timing = FALSE
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
else
|
||||
START_PROCESSING(SSobj, src)
|
||||
proximity_monitor.host = loc
|
||||
update_icon()
|
||||
return secured
|
||||
|
||||
|
||||
/obj/item/device/assembly/prox_sensor/HasProximity(atom/movable/AM as mob|obj)
|
||||
/obj/item/assembly/prox_sensor/HasProximity(atom/movable/AM as mob|obj)
|
||||
if (istype(AM, /obj/effect/beam))
|
||||
return
|
||||
sense()
|
||||
|
||||
|
||||
/obj/item/device/assembly/prox_sensor/sense()
|
||||
/obj/item/assembly/prox_sensor/proc/sense()
|
||||
if(!scanning || !secured || next_activate > world.time)
|
||||
return 0
|
||||
pulse(0)
|
||||
audible_message("[icon2html(src, hearers(src))] *beep* *beep*", null, 3)
|
||||
return FALSE
|
||||
pulse(FALSE)
|
||||
audible_message("[icon2html(src, hearers(src))] *beep* *beep* *beep*", null, hearing_range)
|
||||
for(var/CHM in get_hearers_in_view(hearing_range, src))
|
||||
if(ismob(CHM))
|
||||
var/mob/LM = CHM
|
||||
LM.playsound_local(get_turf(src), 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE)
|
||||
next_activate = world.time + 30
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/item/device/assembly/prox_sensor/process()
|
||||
if(timing)
|
||||
time--
|
||||
if(time <= 0)
|
||||
timing = 0
|
||||
toggle_scan(1)
|
||||
time = initial(time)
|
||||
/obj/item/assembly/prox_sensor/process()
|
||||
if(!timing)
|
||||
return
|
||||
time--
|
||||
if(time <= 0)
|
||||
timing = FALSE
|
||||
toggle_scan(TRUE)
|
||||
time = initial(time)
|
||||
|
||||
/obj/item/device/assembly/prox_sensor/toggle_scan(scan)
|
||||
/obj/item/assembly/prox_sensor/proc/toggle_scan(scan)
|
||||
if(!secured)
|
||||
return 0
|
||||
return FALSE
|
||||
scanning = scan
|
||||
proximity_monitor.SetRange(scanning ? sensitivity : 0)
|
||||
update_icon()
|
||||
|
||||
/obj/item/device/assembly/prox_sensor/proc/sensitivity_change(value)
|
||||
/obj/item/assembly/prox_sensor/proc/sensitivity_change(value)
|
||||
var/sense = min(max(sensitivity + value, 0), 5)
|
||||
sensitivity = sense
|
||||
if(scanning && proximity_monitor.SetRange(sense))
|
||||
sense()
|
||||
|
||||
/obj/item/device/assembly/prox_sensor/update_icon()
|
||||
/obj/item/assembly/prox_sensor/update_icon()
|
||||
cut_overlays()
|
||||
attached_overlays = list()
|
||||
if(timing)
|
||||
@@ -93,13 +103,16 @@
|
||||
holder.update_icon()
|
||||
return
|
||||
|
||||
/obj/item/device/assembly/prox_sensor/ui_interact(mob/user)//TODO: Change this to the wires thingy
|
||||
/obj/item/assembly/prox_sensor/ui_interact(mob/user)//TODO: Change this to the wires thingy
|
||||
. = ..()
|
||||
if(is_secured(user))
|
||||
var/second = time % 60
|
||||
var/minute = (time - second) / 60
|
||||
var/dat = "<TT><B>Proximity Sensor</B>\n[(timing ? "<A href='?src=[REF(src)];time=0'>Arming</A>" : "<A href='?src=[REF(src)];time=1'>Not Arming</A>")] [minute]:[second]\n<A href='?src=[REF(src)];tp=-30'>-</A> <A href='?src=[REF(src)];tp=-1'>-</A> <A href='?src=[REF(src)];tp=1'>+</A> <A href='?src=[REF(src)];tp=30'>+</A>\n</TT>"
|
||||
dat += "<BR><A href='?src=[REF(src)];scanning=[scanning?"0'>Armed":"1'>Unarmed"]</A> (Movement sensor active when armed!)"
|
||||
var/dat = "<TT><B>Proximity Sensor</B></TT>"
|
||||
if(!scanning)
|
||||
dat += "<BR>[(timing ? "<A href='?src=[REF(src)];time=0'>Arming</A>" : "<A href='?src=[REF(src)];time=1'>Not Arming</A>")] [minute]:[second]"
|
||||
dat += "<BR><A href='?src=[REF(src)];tp=-30'>-</A> <A href='?src=[REF(src)];tp=-1'>-</A> <A href='?src=[REF(src)];tp=1'>+</A> <A href='?src=[REF(src)];tp=30'>+</A>"
|
||||
dat += "<BR><A href='?src=[REF(src)];scanning=[scanning?"0'>Armed":"1'>Unarmed (Movement sensor active when armed!)"]</A>"
|
||||
dat += "<BR>Detection range: <A href='?src=[REF(src)];sense=down'>-</A> [sensitivity] <A href='?src=[REF(src)];sense=up'>+</A>"
|
||||
dat += "<BR><BR><A href='?src=[REF(src)];refresh=1'>Refresh</A>"
|
||||
dat += "<BR><BR><A href='?src=[REF(src)];close=1'>Close</A>"
|
||||
@@ -108,7 +121,7 @@
|
||||
return
|
||||
|
||||
|
||||
/obj/item/device/assembly/prox_sensor/Topic(href, href_list)
|
||||
/obj/item/assembly/prox_sensor/Topic(href, href_list)
|
||||
..()
|
||||
if(usr.incapacitated() || !in_range(loc, usr))
|
||||
usr << browse(null, "window=prox")
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
icon = 'icons/obj/assemblies.dmi'
|
||||
icon_state = "shock_kit"
|
||||
var/obj/item/clothing/head/helmet/part1 = null
|
||||
var/obj/item/device/electropack/part2 = null
|
||||
var/obj/item/electropack/part2 = null
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
flags_1 = CONDUCT_1
|
||||
|
||||
@@ -13,18 +13,18 @@
|
||||
qdel(part2)
|
||||
return ..()
|
||||
|
||||
/obj/item/assembly/shock_kit/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/wrench))
|
||||
/obj/item/assembly/shock_kit/wrench_act(mob/living/user, obj/item/I)
|
||||
to_chat(user, "<span class='notice'>You disassemble [src].</span>")
|
||||
if(part1)
|
||||
part1.forceMove(drop_location())
|
||||
part2.forceMove(drop_location())
|
||||
part1.master = null
|
||||
part2.master = null
|
||||
part1 = null
|
||||
if(part2)
|
||||
part2.forceMove(drop_location())
|
||||
part2.master = null
|
||||
part2 = null
|
||||
qdel(src)
|
||||
return
|
||||
add_fingerprint(user)
|
||||
return
|
||||
qdel(src)
|
||||
return TRUE
|
||||
|
||||
/obj/item/assembly/shock_kit/attack_self(mob/user)
|
||||
part1.attack_self(user)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/obj/item/device/assembly/signaler
|
||||
/obj/item/assembly/signaler
|
||||
name = "remote signaling device"
|
||||
desc = "Used to remotely activate devices. Allows for syncing when using a secure signaler on another."
|
||||
icon_state = "signaller"
|
||||
@@ -7,48 +7,48 @@
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
materials = list(MAT_METAL=400, MAT_GLASS=120)
|
||||
wires = WIRE_RECEIVE | WIRE_PULSE | WIRE_RADIO_PULSE | WIRE_RADIO_RECEIVE
|
||||
attachable = 1
|
||||
attachable = TRUE
|
||||
|
||||
var/code = DEFAULT_SIGNALER_CODE
|
||||
var/frequency = FREQ_SIGNALER
|
||||
var/delay = 0
|
||||
var/datum/radio_frequency/radio_connection
|
||||
var/suicider = null
|
||||
var/hearing_range = 1
|
||||
|
||||
/obj/item/device/assembly/signaler/suicide_act(mob/living/carbon/user)
|
||||
/obj/item/assembly/signaler/suicide_act(mob/living/carbon/user)
|
||||
user.visible_message("<span class='suicide'>[user] eats \the [src]! If it is signaled, [user.p_they()] will die!</span>")
|
||||
playsound(src, 'sound/items/eatfood.ogg', 50, 1)
|
||||
playsound(src, 'sound/items/eatfood.ogg', 50, TRUE)
|
||||
user.transferItemToLoc(src, user, TRUE)
|
||||
suicider = user
|
||||
return MANUAL_SUICIDE
|
||||
|
||||
/obj/item/device/assembly/signaler/proc/manual_suicide(mob/living/carbon/user)
|
||||
/obj/item/assembly/signaler/proc/manual_suicide(mob/living/carbon/user)
|
||||
user.visible_message("<span class='suicide'>[user]'s \the [src] recieves a signal, killing them instantly!</span>")
|
||||
user.adjustOxyLoss(200)//it sends an electrical pulse to their heart, killing them. or something.
|
||||
user.death(0)
|
||||
|
||||
/obj/item/device/assembly/signaler/New()
|
||||
..()
|
||||
spawn(40)
|
||||
set_frequency(frequency)
|
||||
/obj/item/assembly/signaler/Initialize()
|
||||
. = ..()
|
||||
set_frequency(frequency)
|
||||
|
||||
|
||||
/obj/item/device/assembly/signaler/Destroy()
|
||||
/obj/item/assembly/signaler/Destroy()
|
||||
SSradio.remove_object(src,frequency)
|
||||
return ..()
|
||||
. = ..()
|
||||
|
||||
/obj/item/device/assembly/signaler/activate()
|
||||
/obj/item/assembly/signaler/activate()
|
||||
if(!..())//cooldown processing
|
||||
return FALSE
|
||||
signal()
|
||||
return TRUE
|
||||
|
||||
/obj/item/device/assembly/signaler/update_icon()
|
||||
/obj/item/assembly/signaler/update_icon()
|
||||
if(holder)
|
||||
holder.update_icon()
|
||||
return
|
||||
|
||||
/obj/item/device/assembly/signaler/ui_interact(mob/user, flag1)
|
||||
/obj/item/assembly/signaler/ui_interact(mob/user, flag1)
|
||||
. = ..()
|
||||
if(is_secured(user))
|
||||
var/t1 = "-------"
|
||||
@@ -77,10 +77,10 @@ Code:
|
||||
return
|
||||
|
||||
|
||||
/obj/item/device/assembly/signaler/Topic(href, href_list)
|
||||
/obj/item/assembly/signaler/Topic(href, href_list)
|
||||
..()
|
||||
|
||||
if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr))
|
||||
if(!usr.canUseTopic(src, BE_CLOSE))
|
||||
usr << browse(null, "window=radio")
|
||||
onclose(usr, "radio")
|
||||
return
|
||||
@@ -106,16 +106,16 @@ Code:
|
||||
|
||||
return
|
||||
|
||||
/obj/item/device/assembly/signaler/attackby(obj/item/W, mob/user, params)
|
||||
/obj/item/assembly/signaler/attackby(obj/item/W, mob/user, params)
|
||||
if(issignaler(W))
|
||||
var/obj/item/device/assembly/signaler/signaler2 = W
|
||||
var/obj/item/assembly/signaler/signaler2 = W
|
||||
if(secured && signaler2.secured)
|
||||
code = signaler2.code
|
||||
frequency = signaler2.frequency
|
||||
set_frequency(signaler2.frequency)
|
||||
to_chat(user, "You transfer the frequency and code of \the [signaler2.name] to \the [name]")
|
||||
..()
|
||||
|
||||
/obj/item/device/assembly/signaler/proc/signal()
|
||||
/obj/item/assembly/signaler/proc/signal()
|
||||
if(!radio_connection)
|
||||
return
|
||||
|
||||
@@ -130,21 +130,26 @@ Code:
|
||||
|
||||
return
|
||||
|
||||
/obj/item/device/assembly/signaler/receive_signal(datum/signal/signal)
|
||||
/obj/item/assembly/signaler/receive_signal(datum/signal/signal)
|
||||
. = FALSE
|
||||
if(!signal)
|
||||
return 0
|
||||
return
|
||||
if(signal.data["code"] != code)
|
||||
return 0
|
||||
return
|
||||
if(!(src.wires & WIRE_RADIO_RECEIVE))
|
||||
return 0
|
||||
return
|
||||
if(suicider)
|
||||
manual_suicide(suicider)
|
||||
pulse(1)
|
||||
audible_message("[icon2html(src, hearers(src))] *beep* *beep*", null, 1)
|
||||
return
|
||||
pulse(TRUE)
|
||||
audible_message("[icon2html(src, hearers(src))] *beep* *beep* *beep*", null, hearing_range)
|
||||
for(var/CHM in get_hearers_in_view(hearing_range, src))
|
||||
if(ismob(CHM))
|
||||
var/mob/LM = CHM
|
||||
LM.playsound_local(get_turf(src), 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE)
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/item/device/assembly/signaler/proc/set_frequency(new_frequency)
|
||||
/obj/item/assembly/signaler/proc/set_frequency(new_frequency)
|
||||
SSradio.remove_object(src, frequency)
|
||||
frequency = new_frequency
|
||||
radio_connection = SSradio.add_object(src, frequency, RADIO_SIGNALER)
|
||||
@@ -153,46 +158,51 @@ Code:
|
||||
// Embedded signaller used in grenade construction.
|
||||
// It's necessary because the signaler doens't have an off state.
|
||||
// Generated during grenade construction. -Sayu
|
||||
/obj/item/device/assembly/signaler/reciever
|
||||
/obj/item/assembly/signaler/reciever
|
||||
var/on = FALSE
|
||||
|
||||
/obj/item/device/assembly/signaler/reciever/proc/toggle_safety()
|
||||
/obj/item/assembly/signaler/reciever/proc/toggle_safety()
|
||||
on = !on
|
||||
|
||||
/obj/item/device/assembly/signaler/reciever/activate()
|
||||
/obj/item/assembly/signaler/reciever/activate()
|
||||
toggle_safety()
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/obj/item/device/assembly/signaler/reciever/describe()
|
||||
return "The radio receiver is [on?"on":"off"]."
|
||||
/obj/item/assembly/signaler/reciever/examine(mob/user)
|
||||
..()
|
||||
to_chat(user, "<span class='notice'>The radio receiver is [on?"on":"off"].</span>")
|
||||
|
||||
/obj/item/device/assembly/signaler/reciever/receive_signal(datum/signal/signal)
|
||||
/obj/item/assembly/signaler/reciever/receive_signal(datum/signal/signal)
|
||||
if(!on)
|
||||
return
|
||||
return ..(signal)
|
||||
|
||||
|
||||
// Embedded signaller used in anomalies.
|
||||
/obj/item/device/assembly/signaler/anomaly
|
||||
/obj/item/assembly/signaler/anomaly
|
||||
name = "anomaly core"
|
||||
desc = "The neutralized core of an anomaly. It'd probably be valuable for research."
|
||||
icon_state = "anomaly core"
|
||||
item_state = "electronic"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
var/anomaly_type = /obj/effect/anomaly
|
||||
|
||||
/obj/item/device/assembly/signaler/anomaly/receive_signal(datum/signal/signal)
|
||||
/obj/item/assembly/signaler/anomaly/receive_signal(datum/signal/signal)
|
||||
if(!signal)
|
||||
return 0
|
||||
return FALSE
|
||||
if(signal.data["code"] != code)
|
||||
return 0
|
||||
return FALSE
|
||||
for(var/obj/effect/anomaly/A in get_turf(src))
|
||||
A.anomalyNeutralize()
|
||||
return TRUE
|
||||
|
||||
/obj/item/device/assembly/signaler/anomaly/attack_self()
|
||||
/obj/item/assembly/signaler/anomaly/attack_self()
|
||||
return
|
||||
|
||||
/obj/item/device/assembly/signaler/cyborg
|
||||
/obj/item/assembly/signaler/cyborg
|
||||
|
||||
/obj/item/device/assembly/signaler/cyborg/attackby(obj/item/W, mob/user, params)
|
||||
/obj/item/assembly/signaler/cyborg/attackby(obj/item/W, mob/user, params)
|
||||
return
|
||||
/obj/item/assembly/signaler/cyborg/screwdriver_act(mob/living/user, obj/item/I)
|
||||
return
|
||||
|
||||
@@ -1,75 +1,83 @@
|
||||
/obj/item/device/assembly/timer
|
||||
/obj/item/assembly/timer
|
||||
name = "timer"
|
||||
desc = "Used to time things. Works well with contraptions which has to count down. Tick tock."
|
||||
icon_state = "timer"
|
||||
materials = list(MAT_METAL=500, MAT_GLASS=50)
|
||||
attachable = 1
|
||||
attachable = TRUE
|
||||
|
||||
var/timing = 0
|
||||
var/timing = FALSE
|
||||
var/time = 5
|
||||
var/saved_time = 5
|
||||
var/loop = 0
|
||||
var/loop = FALSE
|
||||
var/hearing_range = 3
|
||||
|
||||
/obj/item/device/assembly/timer/suicide_act(mob/living/user)
|
||||
/obj/item/assembly/timer/suicide_act(mob/living/user)
|
||||
user.visible_message("<span class='suicide'>[user] looks at the timer and decides [user.p_their()] fate! It looks like [user.p_theyre()] going to commit suicide!</span>")
|
||||
activate()//doesnt rely on timer_end to prevent weird metas where one person can control the timer and therefore someone's life. (maybe that should be how it works...)
|
||||
addtimer(CALLBACK(src, .proc/manual_suicide, user), time*10)//kill yourself once the time runs out
|
||||
return MANUAL_SUICIDE
|
||||
|
||||
/obj/item/device/assembly/timer/proc/manual_suicide(mob/living/user)
|
||||
/obj/item/assembly/timer/proc/manual_suicide(mob/living/user)
|
||||
user.visible_message("<span class='suicide'>[user]'s time is up!</span>")
|
||||
user.adjustOxyLoss(200)
|
||||
user.death(0)
|
||||
|
||||
/obj/item/device/assembly/timer/New()
|
||||
..()
|
||||
/obj/item/assembly/timer/Initialize()
|
||||
. = ..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/device/assembly/timer/describe()
|
||||
if(timing)
|
||||
return "The timer is counting down from [time]!"
|
||||
return "The timer is set for [time] seconds."
|
||||
/obj/item/assembly/timer/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
. = ..()
|
||||
|
||||
/obj/item/assembly/timer/examine(mob/user)
|
||||
..()
|
||||
to_chat(user, "<span class='notice'>The timer is [timing ? "counting down from [time]":"set for [time] seconds"].</span>")
|
||||
|
||||
/obj/item/device/assembly/timer/activate()
|
||||
/obj/item/assembly/timer/activate()
|
||||
if(!..())
|
||||
return 0//Cooldown check
|
||||
return FALSE//Cooldown check
|
||||
timing = !timing
|
||||
update_icon()
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/item/device/assembly/timer/toggle_secure()
|
||||
/obj/item/assembly/timer/toggle_secure()
|
||||
secured = !secured
|
||||
if(secured)
|
||||
START_PROCESSING(SSobj, src)
|
||||
else
|
||||
timing = 0
|
||||
timing = FALSE
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
update_icon()
|
||||
return secured
|
||||
|
||||
|
||||
/obj/item/device/assembly/timer/proc/timer_end()
|
||||
/obj/item/assembly/timer/proc/timer_end()
|
||||
if(!secured || next_activate > world.time)
|
||||
return FALSE
|
||||
pulse(0)
|
||||
audible_message("[icon2html(src, hearers(src))] *beep* *beep*", null, 3)
|
||||
pulse(FALSE)
|
||||
audible_message("[icon2html(src, hearers(src))] *beep* *beep* *beep*", null, hearing_range)
|
||||
for(var/CHM in get_hearers_in_view(hearing_range, src))
|
||||
if(ismob(CHM))
|
||||
var/mob/LM = CHM
|
||||
LM.playsound_local(get_turf(src), 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE)
|
||||
if(loop)
|
||||
timing = 1
|
||||
timing = TRUE
|
||||
update_icon()
|
||||
|
||||
|
||||
/obj/item/device/assembly/timer/process()
|
||||
if(timing)
|
||||
time--
|
||||
if(time <= 0)
|
||||
timing = 0
|
||||
timer_end()
|
||||
time = saved_time
|
||||
/obj/item/assembly/timer/process()
|
||||
if(!timing)
|
||||
return
|
||||
time--
|
||||
if(time <= 0)
|
||||
timing = FALSE
|
||||
timer_end()
|
||||
time = saved_time
|
||||
|
||||
|
||||
/obj/item/device/assembly/timer/update_icon()
|
||||
/obj/item/assembly/timer/update_icon()
|
||||
cut_overlays()
|
||||
attached_overlays = list()
|
||||
if(timing)
|
||||
@@ -79,12 +87,14 @@
|
||||
holder.update_icon()
|
||||
|
||||
|
||||
/obj/item/device/assembly/timer/ui_interact(mob/user)//TODO: Have this use the wires
|
||||
/obj/item/assembly/timer/ui_interact(mob/user)//TODO: Have this use the wires
|
||||
. = ..()
|
||||
if(is_secured(user))
|
||||
var/second = time % 60
|
||||
var/minute = (time - second) / 60
|
||||
var/dat = "<TT><B>Timing Unit</B>\n[(timing ? "<A href='?src=[REF(src)];time=0'>Timing</A>" : "<A href='?src=[REF(src)];time=1'>Not Timing</A>")] [minute]:[second]\n<A href='?src=[REF(src)];tp=-30'>-</A> <A href='?src=[REF(src)];tp=-1'>-</A> <A href='?src=[REF(src)];tp=1'>+</A> <A href='?src=[REF(src)];tp=30'>+</A>\n</TT>"
|
||||
var/dat = "<TT><B>Timing Unit</B></TT>"
|
||||
dat += "<BR>[(timing ? "<A href='?src=[REF(src)];time=0'>Timing</A>" : "<A href='?src=[REF(src)];time=1'>Not Timing</A>")] [minute]:[second]"
|
||||
dat += "<BR><A href='?src=[REF(src)];tp=-30'>-</A> <A href='?src=[REF(src)];tp=-1'>-</A> <A href='?src=[REF(src)];tp=1'>+</A> <A href='?src=[REF(src)];tp=30'>+</A>"
|
||||
dat += "<BR><BR><A href='?src=[REF(src)];repeat=[(loop ? "0'>Stop repeating" : "1'>Set to repeat")]</A>"
|
||||
dat += "<BR><BR><A href='?src=[REF(src)];refresh=1'>Refresh</A>"
|
||||
dat += "<BR><BR><A href='?src=[REF(src)];close=1'>Close</A>"
|
||||
@@ -93,16 +103,16 @@
|
||||
popup.open()
|
||||
|
||||
|
||||
/obj/item/device/assembly/timer/Topic(href, href_list)
|
||||
/obj/item/assembly/timer/Topic(href, href_list)
|
||||
..()
|
||||
if(usr.incapacitated() || !in_range(loc, usr))
|
||||
if(!usr.canUseTopic(src, BE_CLOSE))
|
||||
usr << browse(null, "window=timer")
|
||||
onclose(usr, "timer")
|
||||
return
|
||||
|
||||
if(href_list["time"])
|
||||
timing = text2num(href_list["time"])
|
||||
if(timing && istype(holder, /obj/item/device/transfer_valve))
|
||||
if(timing && istype(holder, /obj/item/transfer_valve))
|
||||
var/timer_message = "[ADMIN_LOOKUPFLW(usr)] activated [src] attachment on [holder]."
|
||||
message_admins(timer_message)
|
||||
GLOB.bombers += timer_message
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
/obj/item/device/assembly/voice
|
||||
#define INCLUSIVE_MODE 1
|
||||
#define EXCLUSIVE_MODE 2
|
||||
#define RECOGNIZER_MODE 3
|
||||
#define VOICE_SENSOR_MODE 4
|
||||
|
||||
/obj/item/assembly/voice
|
||||
name = "voice analyzer"
|
||||
desc = "A small electronic device able to record a voice sample, and send a signal when that sample is repeated."
|
||||
icon_state = "voice"
|
||||
materials = list(MAT_METAL=500, MAT_GLASS=50)
|
||||
flags_1 = HEAR_1
|
||||
attachable = 1
|
||||
attachable = TRUE
|
||||
verb_say = "beeps"
|
||||
verb_ask = "beeps"
|
||||
verb_exclaim = "beeps"
|
||||
var/listening = 0
|
||||
var/listening = FALSE
|
||||
var/recorded = "" //the activation message
|
||||
var/mode = 1
|
||||
var/static/list/modes = list("inclusive",
|
||||
@@ -16,11 +21,11 @@
|
||||
"recognizer",
|
||||
"voice sensor")
|
||||
|
||||
/obj/item/device/assembly/voice/examine(mob/user)
|
||||
/obj/item/assembly/voice/examine(mob/user)
|
||||
..()
|
||||
to_chat(user, "<span class='notice'>Use a multitool to swap between \"inclusive\", \"exclusive\", \"recognizer\", and \"voice sensor\" mode.</span>")
|
||||
|
||||
/obj/item/device/assembly/voice/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
/obj/item/assembly/voice/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
if(speaker == src)
|
||||
return
|
||||
|
||||
@@ -30,62 +35,66 @@
|
||||
if(check_activation(speaker, raw_message))
|
||||
addtimer(CALLBACK(src, .proc/pulse, 0), 10)
|
||||
|
||||
/obj/item/device/assembly/voice/proc/record_speech(atom/movable/speaker, raw_message, datum/language/message_language)
|
||||
/obj/item/assembly/voice/proc/record_speech(atom/movable/speaker, raw_message, datum/language/message_language)
|
||||
switch(mode)
|
||||
if(1)
|
||||
if(INCLUSIVE_MODE)
|
||||
recorded = raw_message
|
||||
listening = 0
|
||||
listening = FALSE
|
||||
say("Activation message is '[recorded]'.", message_language)
|
||||
if(2)
|
||||
if(EXCLUSIVE_MODE)
|
||||
recorded = raw_message
|
||||
listening = 0
|
||||
listening = FALSE
|
||||
say("Activation message is '[recorded]'.", message_language)
|
||||
if(3)
|
||||
if(RECOGNIZER_MODE)
|
||||
recorded = speaker.GetVoice()
|
||||
listening = 0
|
||||
listening = FALSE
|
||||
say("Your voice pattern is saved.", message_language)
|
||||
if(4)
|
||||
if(VOICE_SENSOR_MODE)
|
||||
if(length(raw_message))
|
||||
addtimer(CALLBACK(src, .proc/pulse, 0), 10)
|
||||
|
||||
/obj/item/device/assembly/voice/proc/check_activation(atom/movable/speaker, raw_message)
|
||||
. = 0
|
||||
/obj/item/assembly/voice/proc/check_activation(atom/movable/speaker, raw_message)
|
||||
. = FALSE
|
||||
switch(mode)
|
||||
if(1)
|
||||
if(INCLUSIVE_MODE)
|
||||
if(findtext(raw_message, recorded))
|
||||
. = 1
|
||||
if(2)
|
||||
. = TRUE
|
||||
if(EXCLUSIVE_MODE)
|
||||
if(raw_message == recorded)
|
||||
. = 1
|
||||
if(3)
|
||||
. = TRUE
|
||||
if(RECOGNIZER_MODE)
|
||||
if(speaker.GetVoice() == recorded)
|
||||
. = 1
|
||||
if(4)
|
||||
. = TRUE
|
||||
if(VOICE_SENSOR_MODE)
|
||||
if(length(raw_message))
|
||||
. = 1
|
||||
. = TRUE
|
||||
|
||||
/obj/item/device/assembly/voice/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/device/multitool))
|
||||
mode %= modes.len
|
||||
mode++
|
||||
to_chat(user, "You set [src] into a [modes[mode]] mode.")
|
||||
listening = 0
|
||||
recorded = ""
|
||||
else
|
||||
return ..()
|
||||
/obj/item/assembly/voice/multitool_act(mob/living/user, obj/item/I)
|
||||
mode %= modes.len
|
||||
mode++
|
||||
to_chat(user, "<span class='notice'>You set [src] into [modes[mode]] mode.</span>")
|
||||
listening = FALSE
|
||||
recorded = ""
|
||||
return TRUE
|
||||
|
||||
/obj/item/device/assembly/voice/activate()
|
||||
if(secured)
|
||||
if(!holder)
|
||||
listening = !listening
|
||||
say("[listening ? "Now" : "No longer"] recording input.")
|
||||
/obj/item/assembly/voice/activate()
|
||||
if(!secured || holder)
|
||||
return FALSE
|
||||
listening = !listening
|
||||
say("[listening ? "Now" : "No longer"] recording input.")
|
||||
return TRUE
|
||||
|
||||
/obj/item/device/assembly/voice/attack_self(mob/user)
|
||||
/obj/item/assembly/voice/attack_self(mob/user)
|
||||
if(!user)
|
||||
return 0
|
||||
return FALSE
|
||||
activate()
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/obj/item/device/assembly/voice/toggle_secure()
|
||||
/obj/item/assembly/voice/toggle_secure()
|
||||
. = ..()
|
||||
listening = 0
|
||||
listening = FALSE
|
||||
|
||||
#undef INCLUSIVE_MODE
|
||||
#undef EXCLUSIVE_MODE
|
||||
#undef RECOGNIZER_MODE
|
||||
#undef VOICE_SENSOR_MODE
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
|
||||
for(var/A in location)
|
||||
var/atom/AT = A
|
||||
if(AT && AT != src) // It's possible that the item is deleted in temperature_expose
|
||||
if(!QDELETED(AT) && AT != src) // It's possible that the item is deleted in temperature_expose
|
||||
AT.fire_act(temperature, volume)
|
||||
return
|
||||
|
||||
|
||||
@@ -4,11 +4,11 @@ What are the archived variables for?
|
||||
This prevents race conditions that arise based on the order of tile processing.
|
||||
*/
|
||||
#define MINIMUM_HEAT_CAPACITY 0.0003
|
||||
#define MINIMUM_MOLE_COUNT 0.01
|
||||
#define QUANTIZE(variable) (round(variable,0.0000001))/*I feel the need to document what happens here. Basically this is used to catch most rounding errors, however it's previous value made it so that
|
||||
once gases got hot enough, most procedures wouldnt occur due to the fact that the mole counts would get rounded away. Thus, we lowered it a few orders of magnititude */
|
||||
GLOBAL_LIST_INIT(meta_gas_info, meta_gas_list()) //see ATMOSPHERICS/gas_types.dm
|
||||
GLOBAL_LIST_INIT(gaslist_cache, init_gaslist_cache())
|
||||
GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(/datum/gas/oxygen, /datum/gas/nitrogen, /datum/gas/carbon_dioxide))) // These gasses cannot react amongst themselves
|
||||
|
||||
/proc/init_gaslist_cache()
|
||||
. = list()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
GLOBAL_LIST_INIT(hardcoded_gases, list(/datum/gas/oxygen, /datum/gas/nitrogen, /datum/gas/carbon_dioxide, /datum/gas/plasma)) //the main four gases, which were at one time hardcoded
|
||||
GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(/datum/gas/oxygen, /datum/gas/nitrogen, /datum/gas/carbon_dioxide, /datum/gas/pluoxium, /datum/gas/stimulum, /datum/gas/nitryl))) //unable to react amongst themselves
|
||||
|
||||
/proc/meta_gas_list()
|
||||
. = subtypesof(/datum/gas)
|
||||
@@ -11,7 +12,7 @@ GLOBAL_LIST_INIT(hardcoded_gases, list(/datum/gas/oxygen, /datum/gas/nitrogen, /
|
||||
gas_info[META_GAS_MOLES_VISIBLE] = initial(gas.moles_visible)
|
||||
if(initial(gas.moles_visible) != null)
|
||||
gas_info[META_GAS_OVERLAY] = new /obj/effect/overlay/gas(initial(gas.gas_overlay))
|
||||
gas_info[META_GAS_FUSION_POWER] = initial(gas.dangerous)
|
||||
gas_info[META_GAS_FUSION_POWER] = initial(gas.fusion_power)
|
||||
gas_info[META_GAS_DANGER] = initial(gas.dangerous)
|
||||
gas_info[META_GAS_ID] = initial(gas.id)
|
||||
.[gas_path] = gas_info
|
||||
@@ -124,6 +125,7 @@ GLOBAL_LIST_INIT(hardcoded_gases, list(/datum/gas/oxygen, /datum/gas/nitrogen, /
|
||||
specific_heat = 80
|
||||
name = "Pluoxium"
|
||||
fusion_power = 10
|
||||
|
||||
/obj/effect/overlay/gas
|
||||
icon = 'icons/effects/tile_effects.dmi'
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
//Plasma fire properties
|
||||
#define OXYGEN_BURN_RATE_BASE 1.4
|
||||
#define PLASMA_BURN_RATE_DELTA 9
|
||||
#define PLASMA_UPPER_TEMPERATURE (1370+T0C)
|
||||
#define PLASMA_MINIMUM_OXYGEN_NEEDED 2
|
||||
#define PLASMA_MINIMUM_OXYGEN_PLASMA_RATIO 30
|
||||
#define PLASMA_OXYGEN_FULLBURN 10
|
||||
#define FIRE_CARBON_ENERGY_RELEASED 100000 //Amount of heat released per mole of burnt carbon into the tile
|
||||
#define FIRE_HYDROGEN_ENERGY_RELEASED 280000 // Amount of heat released per mole of burnt hydrogen and/or tritium(hydrogen isotope)
|
||||
#define FIRE_PLASMA_ENERGY_RELEASED 3000000 //Amount of heat released per mole of burnt plasma into the tile
|
||||
@@ -30,7 +28,6 @@
|
||||
#define FUSION_PURITY_THRESHOLD 0.95
|
||||
#define FUSION_HEAT_DROPOFF (20000+T0C)
|
||||
#define NOBLIUM_FORMATION_ENERGY 2e9 //1 Mole of Noblium takes the planck energy to condense.
|
||||
/datum/controller/subsystem/air/var/list/gas_reactions //this is our singleton of all reactions
|
||||
|
||||
/proc/init_gas_reactions()
|
||||
var/list/reaction_types = list()
|
||||
@@ -49,7 +46,7 @@
|
||||
|
||||
/datum/gas_reaction
|
||||
//regarding the requirements lists: the minimum or maximum requirements must be non-zero.
|
||||
//when in doubt, use MINIMUM_HEAT_CAPACITY.
|
||||
//when in doubt, use MINIMUM_MOLE_COUNT.
|
||||
var/list/min_requirements
|
||||
var/list/max_requirements
|
||||
var/exclude = FALSE //do it this way to allow for addition/removal of reactions midmatch in the future
|
||||
@@ -61,6 +58,7 @@
|
||||
init_reqs()
|
||||
|
||||
/datum/gas_reaction/proc/init_reqs()
|
||||
|
||||
/datum/gas_reaction/proc/react(datum/gas_mixture/air, atom/location)
|
||||
return NO_REACTION
|
||||
|
||||
@@ -94,16 +92,20 @@
|
||||
air.gases[/datum/gas/water_vapor][MOLES] -= MOLES_GAS_VISIBLE
|
||||
. = REACTING
|
||||
|
||||
//fire: combustion of plasma and volatile fuel (treated as hydrocarbons). creates hotspots. exothermic
|
||||
/datum/gas_reaction/fire
|
||||
priority = -1 //fire should ALWAYS be last
|
||||
name = "Hydrocarbon Combustion"
|
||||
id = "fire"
|
||||
//tritium combustion: combustion of oxygen and tritium (treated as hydrocarbons). creates hotspots. exothermic
|
||||
/datum/gas_reaction/tritfire
|
||||
priority = -1 //fire should ALWAYS be last, but tritium fires happen before plasma fires
|
||||
name = "Tritium Combustion"
|
||||
id = "tritfire"
|
||||
|
||||
/datum/gas_reaction/fire/init_reqs()
|
||||
min_requirements = list("TEMP" = FIRE_MINIMUM_TEMPERATURE_TO_EXIST) //doesn't include plasma reqs b/c of other, rarer, burning gases.
|
||||
/datum/gas_reaction/tritfire/init_reqs()
|
||||
min_requirements = list(
|
||||
"TEMP" = FIRE_MINIMUM_TEMPERATURE_TO_EXIST,
|
||||
/datum/gas/tritium = MINIMUM_MOLE_COUNT,
|
||||
/datum/gas/oxygen = MINIMUM_MOLE_COUNT
|
||||
)
|
||||
|
||||
/datum/gas_reaction/fire/react(datum/gas_mixture/air, datum/holder)
|
||||
/datum/gas_reaction/tritfire/react(datum/gas_mixture/air, datum/holder)
|
||||
var/energy_released = 0
|
||||
var/old_heat_capacity = air.heat_capacity()
|
||||
var/list/cached_gases = air.gases //this speeds things up because accessing datum vars is slow
|
||||
@@ -112,65 +114,99 @@
|
||||
cached_results[id] = 0
|
||||
var/turf/open/location = isturf(holder) ? holder : null
|
||||
|
||||
//General volatile gas burn
|
||||
if(cached_gases[/datum/gas/tritium] && cached_gases[/datum/gas/tritium][MOLES])
|
||||
var/burned_fuel
|
||||
if(!cached_gases[/datum/gas/oxygen])
|
||||
burned_fuel = 0
|
||||
else if(cached_gases[/datum/gas/oxygen][MOLES] < cached_gases[/datum/gas/tritium][MOLES])
|
||||
burned_fuel = cached_gases[/datum/gas/oxygen][MOLES]/TRITIUM_BURN_OXY_FACTOR
|
||||
cached_gases[/datum/gas/tritium][MOLES] -= burned_fuel
|
||||
else
|
||||
burned_fuel = cached_gases[/datum/gas/tritium][MOLES]*TRITIUM_BURN_TRIT_FACTOR
|
||||
cached_gases[/datum/gas/tritium][MOLES] -= cached_gases[/datum/gas/tritium][MOLES]/TRITIUM_BURN_TRIT_FACTOR
|
||||
cached_gases[/datum/gas/oxygen][MOLES] -= cached_gases[/datum/gas/tritium][MOLES]
|
||||
var/burned_fuel = 0
|
||||
if(cached_gases[/datum/gas/oxygen][MOLES] < cached_gases[/datum/gas/tritium][MOLES])
|
||||
burned_fuel = cached_gases[/datum/gas/oxygen][MOLES]/TRITIUM_BURN_OXY_FACTOR
|
||||
cached_gases[/datum/gas/tritium][MOLES] -= burned_fuel
|
||||
else
|
||||
burned_fuel = cached_gases[/datum/gas/tritium][MOLES]*TRITIUM_BURN_TRIT_FACTOR
|
||||
cached_gases[/datum/gas/tritium][MOLES] -= cached_gases[/datum/gas/tritium][MOLES]/TRITIUM_BURN_TRIT_FACTOR
|
||||
cached_gases[/datum/gas/oxygen][MOLES] -= cached_gases[/datum/gas/tritium][MOLES]
|
||||
|
||||
if(burned_fuel)
|
||||
energy_released += FIRE_HYDROGEN_ENERGY_RELEASED * burned_fuel
|
||||
if(location && prob(10) && burned_fuel > TRITIUM_MINIMUM_RADIATION_ENERGY) //woah there let's not crash the server
|
||||
radiation_pulse(location, energy_released/TRITIUM_BURN_RADIOACTIVITY_FACTOR)
|
||||
if(burned_fuel)
|
||||
energy_released += FIRE_HYDROGEN_ENERGY_RELEASED * burned_fuel
|
||||
if(location && prob(10) && burned_fuel > TRITIUM_MINIMUM_RADIATION_ENERGY) //woah there let's not crash the server
|
||||
radiation_pulse(location, energy_released/TRITIUM_BURN_RADIOACTIVITY_FACTOR)
|
||||
|
||||
ASSERT_GAS(/datum/gas/water_vapor, air) //oxygen+more-or-less hydrogen=H2O
|
||||
cached_gases[/datum/gas/water_vapor][MOLES] += burned_fuel/TRITIUM_BURN_OXY_FACTOR
|
||||
ASSERT_GAS(/datum/gas/water_vapor, air) //oxygen+more-or-less hydrogen=H2O
|
||||
cached_gases[/datum/gas/water_vapor][MOLES] += burned_fuel/TRITIUM_BURN_OXY_FACTOR
|
||||
|
||||
cached_results[id] += burned_fuel
|
||||
cached_results[id] += burned_fuel
|
||||
|
||||
if(energy_released > 0)
|
||||
var/new_heat_capacity = air.heat_capacity()
|
||||
if(new_heat_capacity > MINIMUM_HEAT_CAPACITY)
|
||||
air.temperature = (temperature*old_heat_capacity + energy_released)/new_heat_capacity
|
||||
|
||||
//let the floor know a fire is happening
|
||||
if(istype(location))
|
||||
temperature = air.temperature
|
||||
if(temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
|
||||
location.hotspot_expose(temperature, CELL_VOLUME)
|
||||
for(var/I in location)
|
||||
var/atom/movable/item = I
|
||||
item.temperature_expose(air, temperature, CELL_VOLUME)
|
||||
location.temperature_expose(air, temperature, CELL_VOLUME)
|
||||
|
||||
return cached_results[id] ? REACTING : NO_REACTION
|
||||
|
||||
//plasma combustion: combustion of oxygen and plasma (treated as hydrocarbons). creates hotspots. exothermic
|
||||
/datum/gas_reaction/plasmafire
|
||||
priority = -2 //fire should ALWAYS be last, but plasma fires happen after tritium fires
|
||||
name = "Plasma Combustion"
|
||||
id = "plasmafire"
|
||||
|
||||
/datum/gas_reaction/plasmafire/init_reqs()
|
||||
min_requirements = list(
|
||||
"TEMP" = FIRE_MINIMUM_TEMPERATURE_TO_EXIST,
|
||||
/datum/gas/plasma = MINIMUM_MOLE_COUNT,
|
||||
/datum/gas/oxygen = MINIMUM_MOLE_COUNT
|
||||
)
|
||||
|
||||
/datum/gas_reaction/plasmafire/react(datum/gas_mixture/air, datum/holder)
|
||||
var/energy_released = 0
|
||||
var/old_heat_capacity = air.heat_capacity()
|
||||
var/list/cached_gases = air.gases //this speeds things up because accessing datum vars is slow
|
||||
var/temperature = air.temperature
|
||||
var/list/cached_results = air.reaction_results
|
||||
cached_results[id] = 0
|
||||
var/turf/open/location = isturf(holder) ? holder : null
|
||||
|
||||
//Handle plasma burning
|
||||
if(cached_gases[/datum/gas/plasma] && cached_gases[/datum/gas/plasma][MOLES] > MINIMUM_HEAT_CAPACITY)
|
||||
var/plasma_burn_rate = 0
|
||||
var/oxygen_burn_rate = 0
|
||||
//more plasma released at higher temperatures
|
||||
var/temperature_scale
|
||||
var/super_saturation
|
||||
if(temperature > PLASMA_UPPER_TEMPERATURE)
|
||||
temperature_scale = 1
|
||||
var/plasma_burn_rate = 0
|
||||
var/oxygen_burn_rate = 0
|
||||
//more plasma released at higher temperatures
|
||||
var/temperature_scale = 0
|
||||
//to make tritium
|
||||
var/super_saturation = FALSE
|
||||
|
||||
if(temperature > PLASMA_UPPER_TEMPERATURE)
|
||||
temperature_scale = 1
|
||||
else
|
||||
temperature_scale = (temperature-PLASMA_MINIMUM_BURN_TEMPERATURE)/(PLASMA_UPPER_TEMPERATURE-PLASMA_MINIMUM_BURN_TEMPERATURE)
|
||||
if(temperature_scale > 0)
|
||||
oxygen_burn_rate = OXYGEN_BURN_RATE_BASE - temperature_scale
|
||||
if(cached_gases[/datum/gas/oxygen][MOLES] / cached_gases[/datum/gas/plasma][MOLES] > SUPER_SATURATION_THRESHOLD) //supersaturation. Form Tritium.
|
||||
super_saturation = TRUE
|
||||
if(cached_gases[/datum/gas/oxygen][MOLES] > cached_gases[/datum/gas/plasma][MOLES]*PLASMA_OXYGEN_FULLBURN)
|
||||
plasma_burn_rate = (cached_gases[/datum/gas/plasma][MOLES]*temperature_scale)/PLASMA_BURN_RATE_DELTA
|
||||
else
|
||||
temperature_scale = (temperature-PLASMA_MINIMUM_BURN_TEMPERATURE)/(PLASMA_UPPER_TEMPERATURE-PLASMA_MINIMUM_BURN_TEMPERATURE)
|
||||
if(temperature_scale > 0)
|
||||
var/o2 = cached_gases[/datum/gas/oxygen] ? cached_gases[/datum/gas/oxygen][MOLES] : 0
|
||||
oxygen_burn_rate = OXYGEN_BURN_RATE_BASE - temperature_scale
|
||||
if(o2 / cached_gases[/datum/gas/plasma][MOLES] > SUPER_SATURATION_THRESHOLD) //supersaturation. Form Tritium.
|
||||
super_saturation = TRUE
|
||||
if(o2 > cached_gases[/datum/gas/plasma][MOLES]*PLASMA_OXYGEN_FULLBURN)
|
||||
plasma_burn_rate = (cached_gases[/datum/gas/plasma][MOLES]*temperature_scale)/PLASMA_BURN_RATE_DELTA
|
||||
plasma_burn_rate = (temperature_scale*(cached_gases[/datum/gas/oxygen][MOLES]/PLASMA_OXYGEN_FULLBURN))/PLASMA_BURN_RATE_DELTA
|
||||
|
||||
if(plasma_burn_rate > MINIMUM_HEAT_CAPACITY)
|
||||
plasma_burn_rate = min(plasma_burn_rate,cached_gases[/datum/gas/plasma][MOLES],cached_gases[/datum/gas/oxygen][MOLES]/oxygen_burn_rate) //Ensures matter is conserved properly
|
||||
cached_gases[/datum/gas/plasma][MOLES] = QUANTIZE(cached_gases[/datum/gas/plasma][MOLES] - plasma_burn_rate)
|
||||
cached_gases[/datum/gas/oxygen][MOLES] = QUANTIZE(cached_gases[/datum/gas/oxygen][MOLES] - (plasma_burn_rate * oxygen_burn_rate))
|
||||
if (super_saturation)
|
||||
ASSERT_GAS(/datum/gas/tritium,air)
|
||||
cached_gases[/datum/gas/tritium][MOLES] += plasma_burn_rate
|
||||
else
|
||||
plasma_burn_rate = (temperature_scale*(o2/PLASMA_OXYGEN_FULLBURN))/PLASMA_BURN_RATE_DELTA
|
||||
ASSERT_GAS(/datum/gas/carbon_dioxide,air)
|
||||
cached_gases[/datum/gas/carbon_dioxide][MOLES] += plasma_burn_rate
|
||||
|
||||
if(plasma_burn_rate > MINIMUM_HEAT_CAPACITY)
|
||||
ASSERT_GAS(/datum/gas/carbon_dioxide, air) //don't need to assert o2, since if it isn't present we'll never reach this point anyway
|
||||
plasma_burn_rate = min(plasma_burn_rate,cached_gases[/datum/gas/plasma][MOLES],cached_gases[/datum/gas/oxygen][MOLES]/oxygen_burn_rate) //Ensures matter is conserved properly
|
||||
cached_gases[/datum/gas/plasma][MOLES] = QUANTIZE(cached_gases[/datum/gas/plasma][MOLES] - plasma_burn_rate)
|
||||
cached_gases[/datum/gas/oxygen][MOLES] = QUANTIZE(cached_gases[/datum/gas/oxygen][MOLES] - (plasma_burn_rate * oxygen_burn_rate))
|
||||
if (super_saturation)
|
||||
ASSERT_GAS(/datum/gas/tritium,air)
|
||||
cached_gases[/datum/gas/tritium][MOLES] += plasma_burn_rate
|
||||
else
|
||||
ASSERT_GAS(/datum/gas/carbon_dioxide,air)
|
||||
cached_gases[/datum/gas/carbon_dioxide][MOLES] += plasma_burn_rate
|
||||
energy_released += FIRE_PLASMA_ENERGY_RELEASED * (plasma_burn_rate)
|
||||
|
||||
energy_released += FIRE_PLASMA_ENERGY_RELEASED * (plasma_burn_rate)
|
||||
|
||||
cached_results[id] += (plasma_burn_rate)*(1+oxygen_burn_rate)
|
||||
cached_results[id] += (plasma_burn_rate)*(1+oxygen_burn_rate)
|
||||
|
||||
if(energy_released > 0)
|
||||
var/new_heat_capacity = air.heat_capacity()
|
||||
@@ -191,12 +227,11 @@
|
||||
|
||||
//fusion: a terrible idea that was fun but broken. Now reworked to be less broken and more interesting. Again.
|
||||
/datum/gas_reaction/fusion
|
||||
exclude = FALSE
|
||||
exclude = TRUE
|
||||
priority = 2
|
||||
name = "Plasmic Fusion"
|
||||
id = "fusion"
|
||||
|
||||
|
||||
/datum/gas_reaction/fusion/init_reqs()
|
||||
min_requirements = list(
|
||||
"ENER" = PLASMA_BINDING_ENERGY * 1000,
|
||||
@@ -361,7 +396,7 @@
|
||||
air.temperature = max(((air.temperature*old_heat_capacity + stim_energy_change)/new_heat_capacity),TCMB)
|
||||
return REACTING
|
||||
|
||||
/datum/gas_reaction/nobliumformation //Hyper-Nobelium formation is extrememly endothermic, but requires high temperatures to start. Due to its high mass, hyper-nobelium uses large amounts of nitrogen and tritium. BZ can be used as a catalyst to make it less endothermic.
|
||||
/datum/gas_reaction/nobliumformation //Hyper-Noblium formation is extrememly endothermic, but requires high temperatures to start. Due to its high mass, hyper-nobelium uses large amounts of nitrogen and tritium. BZ can be used as a catalyst to make it less endothermic.
|
||||
priority = 6
|
||||
name = "Hyper-Noblium condensation"
|
||||
id = "nobformation"
|
||||
@@ -380,8 +415,8 @@
|
||||
var/energy_taken = nob_formed*(NOBLIUM_FORMATION_ENERGY/(max(cached_gases[/datum/gas/bz][MOLES],1)))
|
||||
if ((cached_gases[/datum/gas/tritium][MOLES] - 10*nob_formed < 0) || (cached_gases[/datum/gas/nitrogen][MOLES] - 20*nob_formed < 0))
|
||||
return NO_REACTION
|
||||
cached_gases[/datum/gas/tritium][MOLES] = max(cached_gases[/datum/gas/tritium][MOLES]- 10*nob_formed,0)
|
||||
cached_gases[/datum/gas/nitrogen][MOLES] = max(cached_gases[/datum/gas/nitrogen][MOLES]- 20*nob_formed,0)
|
||||
cached_gases[/datum/gas/tritium][MOLES] -= 10*nob_formed
|
||||
cached_gases[/datum/gas/nitrogen][MOLES] -= 20*nob_formed
|
||||
cached_gases[/datum/gas/hypernoblium][MOLES]+= nob_formed
|
||||
|
||||
|
||||
@@ -392,10 +427,8 @@
|
||||
|
||||
#undef OXYGEN_BURN_RATE_BASE
|
||||
#undef PLASMA_BURN_RATE_DELTA
|
||||
#undef PLASMA_UPPER_TEMPERATURE
|
||||
#undef PLASMA_MINIMUM_OXYGEN_NEEDED
|
||||
#undef PLASMA_MINIMUM_OXYGEN_PLASMA_RATIO
|
||||
#undef PLASMA_OXYGEN_FULLBURN
|
||||
#undef FIRE_CARBON_ENERGY_RELEASED
|
||||
#undef FIRE_PLASMA_ENERGY_RELEASED
|
||||
#undef WATER_VAPOR_FREEZE
|
||||
|
||||
@@ -153,6 +153,9 @@
|
||||
req_access = null
|
||||
req_one_access = null
|
||||
|
||||
/obj/machinery/airalarm/syndicate //general syndicate access
|
||||
req_access = list(ACCESS_SYNDICATE)
|
||||
|
||||
//all air alarms in area are connected via magic
|
||||
/area
|
||||
var/list/air_vent_names = list()
|
||||
@@ -667,7 +670,7 @@
|
||||
to_chat(user, "<span class='notice'>The wires have been [panel_open ? "exposed" : "unexposed"].</span>")
|
||||
update_icon()
|
||||
return
|
||||
else if(istype(W, /obj/item/card/id) || istype(W, /obj/item/device/pda))// trying to unlock the interface with an ID card
|
||||
else if(istype(W, /obj/item/card/id) || istype(W, /obj/item/pda))// trying to unlock the interface with an ID card
|
||||
togglelock(user)
|
||||
else if(panel_open && is_wire_tool(W))
|
||||
wires.interact(user)
|
||||
@@ -715,8 +718,8 @@
|
||||
qdel(W)
|
||||
return
|
||||
|
||||
if(istype(W, /obj/item/device/electroadaptive_pseudocircuit))
|
||||
var/obj/item/device/electroadaptive_pseudocircuit/P = W
|
||||
if(istype(W, /obj/item/electroadaptive_pseudocircuit))
|
||||
var/obj/item/electroadaptive_pseudocircuit/P = W
|
||||
if(!P.adapt_circuit(user, 25))
|
||||
return
|
||||
user.visible_message("<span class='notice'>[user] fabricates a circuit and places it into [src].</span>", \
|
||||
|
||||
@@ -34,8 +34,10 @@ Iconnery
|
||||
var/turf/T = loc
|
||||
if(level == 2 || !T.intact)
|
||||
showpipe = TRUE
|
||||
plane = GAME_PLANE
|
||||
else
|
||||
showpipe = FALSE
|
||||
plane = FLOOR_PLANE
|
||||
|
||||
if(!showpipe)
|
||||
return //no need to update the pipes if they aren't showing
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
var/obj/item/reagent_containers/glass/beaker = null
|
||||
var/reagent_transfer = 0
|
||||
|
||||
var/obj/item/device/radio/radio
|
||||
var/radio_key = /obj/item/device/encryptionkey/headset_med
|
||||
var/obj/item/radio/radio
|
||||
var/radio_key = /obj/item/encryptionkey/headset_med
|
||||
var/radio_channel = "Medical"
|
||||
|
||||
var/running_anim = FALSE
|
||||
@@ -298,7 +298,7 @@
|
||||
var/reagentlist = pretty_string_from_reagent_list(I.reagents.reagent_list)
|
||||
log_game("[key_name(user)] added an [I] to cyro containing [reagentlist]")
|
||||
return
|
||||
if(!on && !occupant && !state_open && (default_deconstruction_screwdriver(user, "pod-off", "pod-off", I) || exchange_parts(user, I)) \
|
||||
if(!on && !occupant && !state_open && (default_deconstruction_screwdriver(user, "pod-off", "pod-off", I)) \
|
||||
|| default_change_direction_wrench(user, I) \
|
||||
|| default_pry_open(I) \
|
||||
|| default_deconstruction_crowbar(I))
|
||||
|
||||
@@ -80,8 +80,6 @@
|
||||
return
|
||||
if(default_deconstruction_crowbar(I))
|
||||
return
|
||||
if(exchange_parts(user, I))
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/thermomachine/default_change_direction_wrench(mob/user, obj/item/I)
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
..(intact)
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/device/analyzer))
|
||||
if(istype(W, /obj/item/analyzer))
|
||||
atmosanalyzer_scan(airs[1], user)
|
||||
else
|
||||
return ..()
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
return parent.air.remove(amount)
|
||||
|
||||
/obj/machinery/atmospherics/pipe/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/device/analyzer))
|
||||
if(istype(W, /obj/item/analyzer))
|
||||
atmosanalyzer_scan(parent.air, user)
|
||||
if(istype(W, /obj/item/pipe_meter))
|
||||
var/obj/item/pipe_meter/meter = W
|
||||
|
||||
@@ -138,7 +138,7 @@
|
||||
"<span class='notice'>You fasten [src] to the port.</span>", \
|
||||
"<span class='italics'>You hear a ratchet.</span>")
|
||||
update_icon()
|
||||
else if(istype(W, /obj/item/device/analyzer) && Adjacent(user))
|
||||
else if(istype(W, /obj/item/analyzer) && Adjacent(user))
|
||||
atmosanalyzer_scan(air_contents, user)
|
||||
else
|
||||
return ..()
|
||||
|
||||
@@ -474,7 +474,7 @@
|
||||
|
||||
/datum/outfit/ctf
|
||||
name = "CTF"
|
||||
ears = /obj/item/device/radio/headset
|
||||
ears = /obj/item/radio/headset
|
||||
uniform = /obj/item/clothing/under/syndicate
|
||||
suit = /obj/item/clothing/suit/space/hardsuit/shielded/ctf
|
||||
toggle_helmet = FALSE // see the whites of their eyes
|
||||
@@ -496,10 +496,10 @@
|
||||
W.update_label(W.registered_name, W.assignment)
|
||||
|
||||
// The shielded hardsuit is already NODROP_1
|
||||
no_drops += H.get_item_by_slot(slot_gloves)
|
||||
no_drops += H.get_item_by_slot(slot_shoes)
|
||||
no_drops += H.get_item_by_slot(slot_w_uniform)
|
||||
no_drops += H.get_item_by_slot(slot_ears)
|
||||
no_drops += H.get_item_by_slot(SLOT_GLOVES)
|
||||
no_drops += H.get_item_by_slot(SLOT_SHOES)
|
||||
no_drops += H.get_item_by_slot(SLOT_W_UNIFORM)
|
||||
no_drops += H.get_item_by_slot(SLOT_EARS)
|
||||
for(var/i in no_drops)
|
||||
var/obj/item/I = i
|
||||
I.flags_1 |= NODROP_1
|
||||
@@ -530,7 +530,7 @@
|
||||
|
||||
/datum/outfit/ctf/red/post_equip(mob/living/carbon/human/H)
|
||||
..()
|
||||
var/obj/item/device/radio/R = H.ears
|
||||
var/obj/item/radio/R = H.ears
|
||||
R.set_frequency(FREQ_CTF_RED)
|
||||
R.freqlock = TRUE
|
||||
R.independent = TRUE
|
||||
@@ -538,7 +538,7 @@
|
||||
|
||||
/datum/outfit/ctf/blue/post_equip(mob/living/carbon/human/H)
|
||||
..()
|
||||
var/obj/item/device/radio/R = H.ears
|
||||
var/obj/item/radio/R = H.ears
|
||||
R.set_frequency(FREQ_CTF_BLUE)
|
||||
R.freqlock = TRUE
|
||||
R.independent = TRUE
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
var/list/spawners = GLOB.mob_spawners[name]
|
||||
LAZYREMOVE(spawners, src)
|
||||
if(!LAZYLEN(spawners))
|
||||
LAZYREMOVE(GLOB.mob_spawners,name)
|
||||
GLOB.mob_spawners -= name
|
||||
return ..()
|
||||
|
||||
/obj/effect/mob_spawn/proc/special(mob/M)
|
||||
@@ -182,7 +182,7 @@
|
||||
H.equipOutfit(outfit)
|
||||
if(disable_pda)
|
||||
// We don't want corpse PDAs to show up in the messenger list.
|
||||
var/obj/item/device/pda/PDA = locate(/obj/item/device/pda) in H
|
||||
var/obj/item/pda/PDA = locate(/obj/item/pda) in H
|
||||
if(PDA)
|
||||
PDA.toff = TRUE
|
||||
if(disable_sensors)
|
||||
@@ -312,7 +312,7 @@
|
||||
/obj/effect/mob_spawn/human/doctor/alive/equip(mob/living/carbon/human/H)
|
||||
..()
|
||||
// Remove radio and PDA so they wouldn't annoy station crew.
|
||||
var/list/del_types = list(/obj/item/device/pda, /obj/item/device/radio/headset)
|
||||
var/list/del_types = list(/obj/item/pda, /obj/item/radio/headset)
|
||||
for(var/del_type in del_types)
|
||||
var/obj/item/I = locate(del_type) in H
|
||||
qdel(I)
|
||||
@@ -410,7 +410,7 @@
|
||||
|
||||
/datum/outfit/nanotrasenbridgeofficercorpse
|
||||
name = "Bridge Officer Corpse"
|
||||
ears = /obj/item/device/radio/headset/heads/hop
|
||||
ears = /obj/item/radio/headset/heads/hop
|
||||
uniform = /obj/item/clothing/under/rank/centcom_officer
|
||||
suit = /obj/item/clothing/suit/armor/bulletproof
|
||||
shoes = /obj/item/clothing/shoes/sneakers/black
|
||||
@@ -428,7 +428,7 @@
|
||||
name = "Nanotrasen Private Security Commander"
|
||||
uniform = /obj/item/clothing/under/rank/centcom_commander
|
||||
suit = /obj/item/clothing/suit/armor/bulletproof
|
||||
ears = /obj/item/device/radio/headset/heads/captain
|
||||
ears = /obj/item/radio/headset/heads/captain
|
||||
glasses = /obj/item/clothing/glasses/eyepatch
|
||||
mask = /obj/item/clothing/mask/cigarette/cigar/cohiba
|
||||
head = /obj/item/clothing/head/centhat
|
||||
|
||||
@@ -159,8 +159,8 @@ GLOBAL_DATUM(the_gateway, /obj/machinery/gateway/centerstation)
|
||||
use_power(5000)
|
||||
return
|
||||
|
||||
/obj/machinery/gateway/centeraway/attackby(obj/item/device/W, mob/user, params)
|
||||
if(istype(W, /obj/item/device/multitool))
|
||||
/obj/machinery/gateway/centeraway/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/multitool))
|
||||
if(calibrated)
|
||||
to_chat(user, "\black The gate is already calibrated, there is no work for you to do here.")
|
||||
return
|
||||
|
||||
@@ -529,7 +529,7 @@
|
||||
/obj/item/gun/ballistic/automatic/c20r/unrestricted = 16,
|
||||
/obj/item/gun/magic/wand/resurrection/inert = 15,
|
||||
/obj/item/gun/magic/wand/resurrection = 10,
|
||||
/obj/item/device/radio/uplink/old = 2,
|
||||
/obj/item/radio/uplink/old = 2,
|
||||
/obj/item/book/granter/spell/charge = 12,
|
||||
/obj/item/grenade/clusterbuster/spawner_manhacks = 15,
|
||||
/obj/item/book/granter/spell/fireball = 10,
|
||||
@@ -601,7 +601,7 @@
|
||||
name = "Syndicate Snow Operative"
|
||||
uniform = /obj/item/clothing/under/syndicate/coldres
|
||||
shoes = /obj/item/clothing/shoes/combat/coldres
|
||||
ears = /obj/item/device/radio/headset/syndicate/alt
|
||||
ears = /obj/item/radio/headset/syndicate/alt
|
||||
r_pocket = /obj/item/gun/ballistic/automatic/pistol
|
||||
id = /obj/item/card/id/syndicate
|
||||
implants = list(/obj/item/implant/exile)
|
||||
|
||||
@@ -128,7 +128,7 @@ GLOBAL_VAR_INIT(sc_safecode5, "[rand(0,9)]")
|
||||
l_code = "[GLOB.sc_safecode1][GLOB.sc_safecode2][GLOB.sc_safecode3][GLOB.sc_safecode4][GLOB.sc_safecode5]"
|
||||
l_set = 1
|
||||
new /obj/item/gun/energy/mindflayer(src)
|
||||
new /obj/item/device/soulstone(src)
|
||||
new /obj/item/soulstone(src)
|
||||
new /obj/item/clothing/suit/space/hardsuit/cult(src)
|
||||
//new /obj/item/teleportation_scroll(src)
|
||||
new /obj/item/stack/ore/diamond(src)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/obj/item/device/export_scanner
|
||||
/obj/item/export_scanner
|
||||
name = "export scanner"
|
||||
desc = "A device used to check objects against Nanotrasen exports database."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
@@ -11,12 +11,12 @@
|
||||
siemens_coefficient = 1
|
||||
var/obj/machinery/computer/cargo/cargo_console = null
|
||||
|
||||
/obj/item/device/export_scanner/examine(user)
|
||||
/obj/item/export_scanner/examine(user)
|
||||
..()
|
||||
if(!cargo_console)
|
||||
to_chat(user, "<span class='notice'>[src] is not currently linked to a cargo console.</span>")
|
||||
|
||||
/obj/item/device/export_scanner/afterattack(obj/O, mob/user, proximity)
|
||||
/obj/item/export_scanner/afterattack(obj/O, mob/user, proximity)
|
||||
if(!istype(O) || !proximity)
|
||||
return
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
export_types = list(/obj/machinery/iv_drip)
|
||||
|
||||
/datum/export/large/barrier
|
||||
cost = 325
|
||||
cost = 100
|
||||
unit_name = "security barrier"
|
||||
export_types = list(/obj/item/grenade/barrier, /obj/structure/barricade/security)
|
||||
|
||||
|
||||
@@ -18,4 +18,4 @@
|
||||
/datum/export/swarmer
|
||||
cost = 2000
|
||||
unit_name = "deactivated alien deconstruction drone"
|
||||
export_types = list(/obj/item/device/deactivated_swarmer)
|
||||
export_types = list(/obj/item/deactivated_swarmer)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user