Merge branch 'master' into Dispencer-UI-change

This commit is contained in:
Fermi
2021-02-06 02:40:27 +00:00
836 changed files with 9220 additions and 5737 deletions
@@ -69,7 +69,7 @@ GLOBAL_LIST_EMPTY(actionspeed_modification_cache)
return TRUE
remove_actionspeed_modifier(existing, FALSE)
if(length(actionspeed_modification))
BINARY_INSERT(type_or_datum.id, actionspeed_modification, datum/actionspeed_modifier, type_or_datum, priority, COMPARE_VALUE)
BINARY_INSERT(type_or_datum.id, actionspeed_modification, /datum/actionspeed_modifier, type_or_datum, priority, COMPARE_VALUE)
LAZYSET(actionspeed_modification, type_or_datum.id, type_or_datum)
if(update)
update_actionspeed()
+8
View File
@@ -226,6 +226,14 @@
key_cache[key] = 0
return .
/proc/restore_stickybans()
for (var/banned_ckey in GLOB.stickybanadmintexts)
world.SetConfig("ban", banned_ckey, GLOB.stickybanadmintexts[banned_ckey])
GLOB.stickybanadminexemptions = list()
GLOB.stickybanadmintexts = list()
if (GLOB.stickbanadminexemptiontimerid)
deltimer(GLOB.stickbanadminexemptiontimerid)
GLOB.stickbanadminexemptiontimerid = null
#undef STICKYBAN_MAX_MATCHES
#undef STICKYBAN_MAX_EXISTING_USER_MATCHES
+7 -9
View File
@@ -52,11 +52,9 @@
edit_emitter(user)
/obj/effect/sound_emitter/AltClick(mob/user)
. = ..()
if(check_rights_for(user.client, R_SOUNDS))
activate(user)
to_chat(user, "<span class='notice'>Sound emitter activated.</span>")
return TRUE
to_chat(user, "<span class='notice'>Sound emitter activated.</span>", confidential = TRUE)
/obj/effect/sound_emitter/proc/edit_emitter(mob/user)
var/dat = ""
@@ -84,20 +82,20 @@
if(!new_label)
return
maptext = new_label
to_chat(user, "<span class='notice'>Label set to [maptext].</span>")
to_chat(user, "<span class='notice'>Label set to [maptext].</span>", confidential = TRUE)
if(href_list["edit_sound_file"])
var/new_file = input(user, "Choose a sound file.", "Sound Emitter") as null|sound
if(!new_file)
return
sound_file = new_file
to_chat(user, "<span class='notice'>New sound file set to [sound_file].</span>")
to_chat(user, "<span class='notice'>New sound file set to [sound_file].</span>", confidential = TRUE)
if(href_list["edit_volume"])
var/new_volume = input(user, "Choose a volume.", "Sound Emitter", sound_volume) as null|num
if(isnull(new_volume))
return
new_volume = clamp(new_volume, 0, 100)
sound_volume = new_volume
to_chat(user, "<span class='notice'>Volume set to [sound_volume]%.</span>")
to_chat(user, "<span class='notice'>Volume set to [sound_volume]%.</span>", confidential = TRUE)
if(href_list["edit_mode"])
var/new_mode
var/mode_list = list("Local (normal sound)" = SOUND_EMITTER_LOCAL, "Direct (not affected by environment/location)" = SOUND_EMITTER_DIRECT)
@@ -105,7 +103,7 @@
if(!new_mode)
return
motus_operandi = mode_list[new_mode]
to_chat(user, "<span class='notice'>Mode set to [motus_operandi].</span>")
to_chat(user, "<span class='notice'>Mode set to [motus_operandi].</span>", confidential = TRUE)
if(href_list["edit_range"])
var/new_range
var/range_list = list("Radius (all mobs within a radius)" = SOUND_EMITTER_RADIUS, "Z-Level (all mobs on the same z)" = SOUND_EMITTER_ZLEVEL, "Global (all players)" = SOUND_EMITTER_GLOBAL)
@@ -113,14 +111,14 @@
if(!new_range)
return
emitter_range = range_list[new_range]
to_chat(user, "<span class='notice'>Range set to [emitter_range].</span>")
to_chat(user, "<span class='notice'>Range set to [emitter_range].</span>", confidential = TRUE)
if(href_list["edit_radius"])
var/new_radius = input(user, "Choose a radius.", "Sound Emitter", sound_volume) as null|num
if(isnull(new_radius))
return
new_radius = clamp(new_radius, 0, 127)
play_radius = new_radius
to_chat(user, "<span class='notice'>Audible radius set to [play_radius].</span>")
to_chat(user, "<span class='notice'>Audible radius set to [play_radius].</span>", confidential = TRUE)
if(href_list["play"])
activate(user)
edit_emitter(user) //Refresh the UI to see our changes
+318 -55
View File
@@ -7,7 +7,7 @@
if ("add")
var/list/ban = list()
var/ckey
ban["admin"] = usr.key
ban["admin"] = usr.ckey
ban["type"] = list("sticky")
ban["reason"] = "(InGameBan)([usr.key])" //this will be displayed in dd only
@@ -21,7 +21,8 @@
ban["ckey"] = ckey
if (get_stickyban_from_ckey(ckey))
to_chat(usr, "<span class='adminnotice'>Error: Can not add a stickyban: User already has a current sticky ban</span>")
to_chat(usr, "<span class='adminnotice'>Error: Can not add a stickyban: User already has a current sticky ban</span>", confidential = TRUE)
return
if (data["reason"])
ban["message"] = data["reason"]
@@ -31,7 +32,26 @@
return
ban["message"] = "[reason]"
if(SSdbcore.Connect()) // todo: second wave
// var/datum/db_query/query_create_stickyban = SSdbcore.NewQuery({"
// INSERT INTO [format_table_name("stickyban")] (ckey, reason, banning_admin)
// VALUES (:ckey, :message, :banning_admin)
// "}, list("ckey" = ckey, "message" = ban["message"], "banning_admin" = usr.ckey))
var/datum/DBQuery/query_create_stickyban = SSdbcore.NewQuery({"
INSERT INTO [format_table_name("stickyban")] (ckey, reason, banning_admin)
VALUES ([ckey], [ban["message"]], [usr.ckey])
"})
if (query_create_stickyban.warn_execute())
ban["fromdb"] = TRUE
qdel(query_create_stickyban)
world.SetConfig("ban",ckey,list2stickyban(ban))
ban = stickyban2list(list2stickyban(ban))
ban["matches_this_round"] = list()
ban["existing_user_matches_this_round"] = list()
ban["admin_matches_this_round"] = list()
ban["pending_matches_this_round"] = list()
SSstickyban.cache[ckey] = ban
log_admin_private("[key_name(usr)] has stickybanned [ckey].\nReason: [ban["message"]]")
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has stickybanned [ckey].\nReason: [ban["message"]]</span>")
@@ -43,14 +63,29 @@
var/ban = get_stickyban_from_ckey(ckey)
if (!ban)
to_chat(usr, "<span class='adminnotice'>Error: No sticky ban for [ckey] found!</span>")
to_chat(usr, "<span class='adminnotice'>Error: No sticky ban for [ckey] found!</span>", confidential = TRUE)
return
if (alert("Are you sure you want to remove the sticky ban on [ckey]?","Are you sure","Yes","No") == "No")
return
if (!get_stickyban_from_ckey(ckey))
to_chat(usr, "<span class='adminnotice'>Error: The ban disappeared.</span>")
to_chat(usr, "<span class='adminnotice'>Error: The ban disappeared.</span>", confidential = TRUE)
return
world.SetConfig("ban",ckey, null)
SSstickyban.cache -= ckey
if (SSdbcore.Connect())
// SSdbcore.QuerySelect(list(
// SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban")] WHERE ckey = :ckey", list("ckey" = ckey)),
// SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ckey")] WHERE stickyban = :ckey", list("ckey" = ckey)),
// SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_cid")] WHERE stickyban = :ckey", list("ckey" = ckey)),
// SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ip")] WHERE stickyban = :ckey", list("ckey" = ckey))
// ), warn = TRUE, qdel = TRUE)
SSdbcore.QuerySelect(list(
SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban")] WHERE ckey = [ckey]"),
SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ckey")] WHERE stickyban = [ckey]"),
SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_cid")] WHERE stickyban = [ckey]"),
SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ip")] WHERE stickyban = [ckey]")
), warn = TRUE, qdel = TRUE)
log_admin_private("[key_name(usr)] removed [ckey]'s stickyban")
message_admins("<span class='adminnotice'>[key_name_admin(usr)] removed [ckey]'s stickyban</span>")
@@ -64,42 +99,45 @@
var/alt = ckey(data["alt"])
var/ban = get_stickyban_from_ckey(ckey)
if (!ban)
to_chat(usr, "<span class='adminnotice'>Error: No sticky ban for [ckey] found!</span>")
to_chat(usr, "<span class='adminnotice'>Error: No sticky ban for [ckey] found!</span>", confidential = TRUE)
return
var/found = 0
//we have to do it this way because byond keeps the case in its sticky ban matches WHY!!!
for (var/key in ban["keys"])
if (ckey(key) == alt)
found = 1
break
if (!found)
to_chat(usr, "<span class='adminnotice'>Error: [alt] is not linked to [ckey]'s sticky ban!</span>")
var/key = LAZYACCESS(ban["keys"], alt)
if (!key)
to_chat(usr, "<span class='adminnotice'>Error: [alt] is not linked to [ckey]'s sticky ban!</span>", confidential = TRUE)
return
if (alert("Are you sure you want to disassociate [alt] from [ckey]'s sticky ban? \nNote: Nothing stops byond from re-linking them","Are you sure","Yes","No") == "No")
if (alert("Are you sure you want to disassociate [alt] from [ckey]'s sticky ban? \nNote: Nothing stops byond from re-linking them, Use \[E] to exempt them","Are you sure","Yes","No") == "No")
return
//we have to do this again incase something changes
ban = get_stickyban_from_ckey(ckey)
if (!ban)
to_chat(usr, "<span class='adminnotice'>Error: The ban disappeared.</span>")
to_chat(usr, "<span class='adminnotice'>Error: The ban disappeared.</span>", confidential = TRUE)
return
found = 0
for (var/key in ban["keys"])
if (ckey(key) == alt)
ban["keys"] -= key
found = 1
break
key = LAZYACCESS(ban["keys"], alt)
if (!found)
to_chat(usr, "<span class='adminnotice'>Error: [alt] link to [ckey]'s sticky ban disappeared.</span>")
if (!key)
to_chat(usr, "<span class='adminnotice'>Error: [alt] link to [ckey]'s sticky ban disappeared.</span>", confidential = TRUE)
return
LAZYREMOVE(ban["keys"], alt)
world.SetConfig("ban",ckey,list2stickyban(ban))
SSstickyban.cache[ckey] = ban
if (SSdbcore.Connect())
// var/datum/db_query/query_remove_stickyban_alt = SSdbcore.NewQuery(
// "DELETE FROM [format_table_name("stickyban_matched_ckey")] WHERE stickyban = :ckey AND matched_ckey = :alt",
// list("ckey" = ckey, "alt" = alt)
// )
var/datum/DBQuery/query_remove_stickyban_alt = SSdbcore.NewQuery(
"DELETE FROM [format_table_name("stickyban_matched_ckey")] WHERE stickyban = [ckey] AND matched_ckey = [alt]"
)
query_remove_stickyban_alt.warn_execute()
qdel(query_remove_stickyban_alt)
log_admin_private("[key_name(usr)] has disassociated [alt] from [ckey]'s sticky ban")
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has disassociated [alt] from [ckey]'s sticky ban</span>")
@@ -109,7 +147,7 @@
var/ckey = data["ckey"]
var/ban = get_stickyban_from_ckey(ckey)
if (!ban)
to_chat(usr, "<span class='adminnotice'>Error: No sticky ban for [ckey] found!</span>")
to_chat(usr, "<span class='adminnotice'>Error: No sticky ban for [ckey] found!</span>", confidential = TRUE)
return
var/oldreason = ban["message"]
var/reason = input(usr,"Reason","Reason","[ban["message"]]") as text|null
@@ -118,28 +156,203 @@
//we have to do this again incase something changed while we waited for input
ban = get_stickyban_from_ckey(ckey)
if (!ban)
to_chat(usr, "<span class='adminnotice'>Error: The ban disappeared.</span>")
to_chat(usr, "<span class='adminnotice'>Error: The ban disappeared.</span>", confidential = TRUE)
return
ban["message"] = "[reason]"
world.SetConfig("ban",ckey,list2stickyban(ban))
SSstickyban.cache[ckey] = ban
if (SSdbcore.Connect())
// var/datum/db_query/query_edit_stickyban = SSdbcore.NewQuery(
// "UPDATE [format_table_name("stickyban")] SET reason = :reason WHERE ckey = :ckey",
// list("reason" = reason, "ckey" = ckey)
// )
var/datum/DBQuery/query_edit_stickyban = SSdbcore.NewQuery(
"UPDATE [format_table_name("stickyban")] SET reason = [reason] WHERE ckey = [ckey]"
)
query_edit_stickyban.warn_execute()
qdel(query_edit_stickyban)
log_admin_private("[key_name(usr)] has edited [ckey]'s sticky ban reason from [oldreason] to [reason]")
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has edited [ckey]'s sticky ban reason from [oldreason] to [reason]</span>")
if ("exempt")
if (!data["ckey"])
return
var/ckey = data["ckey"]
if (!data["alt"])
return
var/alt = ckey(data["alt"])
var/ban = get_stickyban_from_ckey(ckey)
if (!ban)
to_chat(usr, "<span class='adminnotice'>Error: No sticky ban for [ckey] found!</span>", confidential = TRUE)
return
var/key = LAZYACCESS(ban["keys"], alt)
if (!key)
to_chat(usr, "<span class='adminnotice'>Error: [alt] is not linked to [ckey]'s sticky ban!</span>", confidential = TRUE)
return
if (alert("Are you sure you want to exempt [alt] from [ckey]'s sticky ban?","Are you sure","Yes","No") == "No")
return
//we have to do this again incase something changes
ban = get_stickyban_from_ckey(ckey)
if (!ban)
to_chat(usr, "<span class='adminnotice'>Error: The ban disappeared.</span>", confidential = TRUE)
return
key = LAZYACCESS(ban["keys"], alt)
if (!key)
to_chat(usr, "<span class='adminnotice'>Error: [alt]'s link to [ckey]'s sticky ban disappeared.</span>", confidential = TRUE)
return
LAZYREMOVE(ban["keys"], alt)
key["exempt"] = TRUE
LAZYSET(ban["whitelist"], alt, key)
world.SetConfig("ban",ckey,list2stickyban(ban))
SSstickyban.cache[ckey] = ban
if (SSdbcore.Connect())
// var/datum/db_query/query_exempt_stickyban_alt = SSdbcore.NewQuery(
// "UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 1 WHERE stickyban = :ckey AND matched_ckey = :alt",
// list("ckey" = ckey, "alt" = alt)
// )
var/datum/DBQuery/query_exempt_stickyban_alt = SSdbcore.NewQuery(
"UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 1 WHERE stickyban = [ckey] AND matched_ckey = [alt]"
)
query_exempt_stickyban_alt.warn_execute()
qdel(query_exempt_stickyban_alt)
log_admin_private("[key_name(usr)] has exempted [alt] from [ckey]'s sticky ban")
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has exempted [alt] from [ckey]'s sticky ban</span>")
if ("unexempt")
if (!data["ckey"])
return
var/ckey = data["ckey"]
if (!data["alt"])
return
var/alt = ckey(data["alt"])
var/ban = get_stickyban_from_ckey(ckey)
if (!ban)
to_chat(usr, "<span class='adminnotice'>Error: No sticky ban for [ckey] found!</span>", confidential = TRUE)
return
var/key = LAZYACCESS(ban["whitelist"], alt)
if (!key)
to_chat(usr, "<span class='adminnotice'>Error: [alt] is not exempt from [ckey]'s sticky ban!</span>", confidential = TRUE)
return
if (alert("Are you sure you want to unexempt [alt] from [ckey]'s sticky ban?","Are you sure","Yes","No") == "No")
return
//we have to do this again incase something changes
ban = get_stickyban_from_ckey(ckey)
if (!ban)
to_chat(usr, "<span class='adminnotice'>Error: The ban disappeared.</span>", confidential = TRUE)
return
key = LAZYACCESS(ban["whitelist"], alt)
if (!key)
to_chat(usr, "<span class='adminnotice'>Error: [alt]'s exemption from [ckey]'s sticky ban disappeared.</span>", confidential = TRUE)
return
LAZYREMOVE(ban["whitelist"], alt)
key["exempt"] = FALSE
LAZYSET(ban["keys"], alt, key)
world.SetConfig("ban",ckey,list2stickyban(ban))
SSstickyban.cache[ckey] = ban
if (SSdbcore.Connect())
// var/datum/db_query/query_unexempt_stickyban_alt = SSdbcore.NewQuery(
// "UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 0 WHERE stickyban = :ckey AND matched_ckey = :alt",
// list("ckey" = ckey, "alt" = alt)
// )
var/datum/DBQuery/query_unexempt_stickyban_alt = SSdbcore.NewQuery(
"UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 0 WHERE stickyban = [ckey] AND matched_ckey = [alt]"
)
query_unexempt_stickyban_alt.warn_execute()
qdel(query_unexempt_stickyban_alt)
log_admin_private("[key_name(usr)] has unexempted [alt] from [ckey]'s sticky ban")
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has unexempted [alt] from [ckey]'s sticky ban</span>")
if ("timeout")
if (!data["ckey"])
return
if (!SSdbcore.Connect())
to_chat(usr, "<span class='adminnotice'>No database connection!</span>", confidential = TRUE)
return
var/ckey = data["ckey"]
if (alert("Are you sure you want to put [ckey]'s stickyban on timeout until next round (or removed)?","Are you sure","Yes","No") == "No")
return
var/ban = get_stickyban_from_ckey(ckey)
if (!ban)
to_chat(usr, "<span class='adminnotice'>Error: No sticky ban for [ckey] found!</span>", confidential = TRUE)
return
ban["timeout"] = TRUE
world.SetConfig("ban", ckey, null)
var/cachedban = SSstickyban.cache[ckey]
if (cachedban)
cachedban["timeout"] = TRUE
log_admin_private("[key_name(usr)] has put [ckey]'s sticky ban on timeout.")
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has put [ckey]'s sticky ban on timeout.</span>")
if ("untimeout")
if (!data["ckey"])
return
if (!SSdbcore.Connect())
to_chat(usr, "<span class='adminnotice'>No database connection!</span>", confidential = TRUE)
return
var/ckey = data["ckey"]
if (alert("Are you sure you want to lift the timeout on [ckey]'s stickyban?","Are you sure","Yes","No") == "No")
return
var/ban = get_stickyban_from_ckey(ckey)
var/cachedban = SSstickyban.cache[ckey]
if (cachedban)
cachedban["timeout"] = FALSE
if (!ban)
if (!cachedban)
to_chat(usr, "<span class='adminnotice'>Error: No sticky ban for [ckey] found!</span>", confidential = TRUE)
return
ban = cachedban
ban["timeout"] = FALSE
world.SetConfig("ban",ckey,list2stickyban(ban))
log_admin_private("[key_name(usr)] has taken [ckey]'s sticky ban off of timeout.")
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has taken [ckey]'s sticky ban off of timeout.</span>")
if ("revert")
if (!data["ckey"])
return
var/ckey = data["ckey"]
if (alert("Are you sure you want to revert the sticky ban on [ckey] to its state at round start?","Are you sure","Yes","No") == "No")
if (alert("Are you sure you want to revert the sticky ban on [ckey] to its state at round start (or last edit)?","Are you sure","Yes","No") == "No")
return
var/ban = get_stickyban_from_ckey(ckey)
if (!ban)
to_chat(usr, "<span class='adminnotice'>Error: No sticky ban for [ckey] found!</span>")
to_chat(usr, "<span class='adminnotice'>Error: No sticky ban for [ckey] found!</span>", confidential = TRUE)
return
var/cached_ban = SSstickyban.cache[ckey]
if (!cached_ban)
to_chat(usr, "<span class='adminnotice'>Error: No cached sticky ban for [ckey] found!</span>")
to_chat(usr, "<span class='adminnotice'>Error: No cached sticky ban for [ckey] found!</span>", confidential = TRUE)
world.SetConfig("ban",ckey,null)
log_admin_private("[key_name(usr)] has reverted [ckey]'s sticky ban to its state at round start.")
@@ -150,14 +363,22 @@
world.SetConfig("ban",ckey,list2stickyban(cached_ban))
/datum/admins/proc/stickyban_gethtml(ckey, ban)
. = {"
/datum/admins/proc/stickyban_gethtml(ckey)
var/ban = get_stickyban_from_ckey(ckey)
if (!ban)
return
var/timeout
if (SSdbcore.Connect())
timeout = "<a href='?_src_=holder;[HrefToken()];stickyban=[(ban["timeout"] ? "untimeout" : "timeout")]&ckey=[ckey]'>\[[(ban["timeout"] ? "untimeout" : "timeout" )]\]</a>"
else
timeout = "<a href='?_src_=holder;[HrefToken()];stickyban=revert&ckey=[ckey]'>\[revert\]</a>"
. = list({"
<a href='?_src_=holder;[HrefToken()];stickyban=remove&ckey=[ckey]'>\[-\]</a>
<a href='?_src_=holder;[HrefToken()];stickyban=revert&ckey=[ckey]'>\[revert\]</a>
[timeout]
<b>[ckey]</b>
<br />"
[ban["message"]] <b><a href='?_src_=holder;[HrefToken()];stickyban=edit&ckey=[ckey]'>\[Edit\]</a></b><br />
"}
"})
if (ban["admin"])
. += "[ban["admin"]]<br />"
else
@@ -166,19 +387,24 @@
for (var/key in ban["keys"])
if (ckey(key) == ckey)
continue
. += "<li><a href='?_src_=holder;[HrefToken()];stickyban=remove_alt&ckey=[ckey]&alt=[ckey(key)]'>\[-\]</a>[key]</li>"
. += "<li><a href='?_src_=holder;[HrefToken()];stickyban=remove_alt&ckey=[ckey]&alt=[ckey(key)]'>\[-\]</a>[key]<a href='?_src_=holder;[HrefToken()];stickyban=exempt&ckey=[ckey]&alt=[ckey(key)]'>\[E\]</a></li>"
for (var/key in ban["whitelist"])
if (ckey(key) == ckey)
continue
. += "<li><a href='?_src_=holder;[HrefToken()];stickyban=remove_alt&ckey=[ckey]&alt=[ckey(key)]'>\[-\]</a>[key]<a href='?_src_=holder;[HrefToken()];stickyban=unexempt&ckey=[ckey]&alt=[ckey(key)]'>\[UE\]</a></li>"
. += "</ol>\n"
/datum/admins/proc/stickyban_show()
if(!check_rights(R_BAN))
return
var/list/bans = sortList(world.GetConfig("ban"))
var/banhtml = ""
var/list/bans = sticky_banned_ckeys()
var/list/banhtml = list()
for(var/key in bans)
var/ckey = ckey(key)
var/ban = stickyban2list(world.GetConfig("ban",key))
banhtml += "<br /><hr />\n"
banhtml += stickyban_gethtml(ckey,ban)
banhtml += stickyban_gethtml(ckey)
var/html = {"
<head>
@@ -186,22 +412,49 @@
</head>
<body>
<h2>All Sticky Bans:</h2> <a href='?_src_=holder;[HrefToken()];stickyban=add'>\[+\]</a><br>
[banhtml]
[banhtml.Join("")]
</body>
"}
usr << browse(html,"window=stickybans;size=700x400")
/proc/get_stickyban_from_ckey(var/ckey)
/proc/sticky_banned_ckeys()
if (SSdbcore.Connect() || length(SSstickyban.dbcache))
if (SSstickyban.dbcacheexpire < world.time)
SSstickyban.Populatedbcache()
if (SSstickyban.dbcacheexpire)
return SSstickyban.dbcache.Copy()
return sortList(world.GetConfig("ban"))
/proc/get_stickyban_from_ckey(ckey)
. = list()
if (!ckey)
return null
ckey = ckey(ckey)
. = null
for (var/key in world.GetConfig("ban"))
if (ckey(key) == ckey)
. = stickyban2list(world.GetConfig("ban",key))
break
if (SSdbcore.Connect() || length(SSstickyban.dbcache))
if (SSstickyban.dbcacheexpire < world.time)
SSstickyban.Populatedbcache()
if (SSstickyban.dbcacheexpire)
. = SSstickyban.dbcache[ckey]
//reset the cache incase its a newer ban (but only if we didn't update the cache recently)
if (!. && SSstickyban.dbcacheexpire != world.time+STICKYBAN_DB_CACHE_TIME)
SSstickyban.dbcacheexpire = 1
SSstickyban.Populatedbcache()
. = SSstickyban.dbcache[ckey]
if (.)
var/list/cachedban = SSstickyban.cache["[ckey]"]
if (cachedban)
.["timeout"] = cachedban["timeout"]
/proc/stickyban2list(var/ban)
.["fromdb"] = TRUE
return
. = stickyban2list(world.GetConfig("ban", ckey)) || stickyban2list(world.GetConfig("ban", ckey(ckey))) || list()
if (!length(.))
return null
/proc/stickyban2list(ban, strictdb = TRUE)
if (!ban)
return null
. = params2list(ban)
@@ -212,30 +465,40 @@
var/ckey = ckey(key)
ckeys[ckey] = ckey //to make searching faster.
.["keys"] = ckeys
if (.["whitelist"])
var/keys = splittext(.["whitelist"], ",")
var/ckeys = list()
for (var/key in keys)
var/ckey = ckey(key)
ckeys[ckey] = ckey //to make searching faster.
.["whitelist"] = ckeys
.["type"] = splittext(.["type"], ",")
.["IP"] = splittext(.["IP"], ",")
.["computer_id"] = splittext(.["computer_id"], ",")
. -= "fromdb"
/proc/list2stickyban(var/list/ban)
/proc/list2stickyban(list/ban)
if (!ban || !islist(ban))
return null
. = ban.Copy()
if (.["keys"])
.["keys"] = jointext(.["keys"], ",")
if (.["IP"])
.["IP"] = jointext(.["IP"], ",")
if (.["computer_id"])
.["computer_id"] = jointext(.["computer_id"], ",")
if (.["whitelist"])
.["whitelist"] = jointext(.["whitelist"], ",")
if (.["type"])
.["type"] = jointext(.["type"], ",")
//internal tracking only, shouldn't be stored
. -= "reverting"
. -= "matches_this_round"
. -= "existing_user_matches_this_round"
. -= "admin_matches_this_round"
. -= "matches_this_round"
. -= "reverting"
. -= "pending_matches_this_round"
//storing these can sometimes cause sticky bans to start matching everybody
// and isn't even needed for sticky ban matching, as the hub tracks these separately
. -= "IP"
. -= "computer_id"
. = list2params(.)
+1 -1
View File
@@ -782,7 +782,7 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null
if(temp.vars.Find(v))
temp.vars[v] = SDQL_expression(d, set_list[sets])
else
temp.vv_edit_var(v, SDQL_expression(d, set_list[sets]))
temp.vv_edit_var(v, SDQL_expression(d, set_list[sets]), TRUE)
break
if(temp.vars.Find(v) && (istype(temp.vars[v], /datum) || istype(temp.vars[v], /client)))
temp = temp.vars[v]
+3 -3
View File
@@ -174,7 +174,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
//is_bwoink is TRUE if this ticket was started by an admin PM
/datum/admin_help/New(msg, client/C, is_bwoink)
//clean the input msg
msg = sanitize(copytext_char(msg,1,MAX_MESSAGE_LEN))
msg = copytext_char(msg,1,MAX_MESSAGE_LEN)
if(!msg || !C || !C.mob)
qdel(src)
return
@@ -263,7 +263,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
//message from the initiator without a target, all admins will see this
//won't bug irc
/datum/admin_help/proc/MessageNoRecipient(msg)
msg = sanitize(copytext_char(msg, 1, MAX_MESSAGE_LEN))
msg = copytext_char(msg, 1, MAX_MESSAGE_LEN)
var/ref_src = "[REF(src)]"
//Message to be sent to all admins
var/admin_msg = "<span class='adminnotice'><span class='adminhelp'>Ticket [TicketHref("#[id]", ref_src)]</span><b>: [LinkedReplyName(ref_src)] [FullMonty(ref_src)]:</b> <span class='linkify'>[keywords_lookup(msg)]</span></span>"
@@ -523,7 +523,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
if(handle_spam_prevention(msg,MUTE_ADMINHELP))
return
msg = trim(msg)
msg = sanitize(trim(msg))
if(!msg)
return
+16
View File
@@ -158,3 +158,19 @@
else
to_chat(src, "Failed to move mob to a valid location.", confidential = TRUE)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Send Mob") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/// Proc to hook user-enacted teleporting behavior and keep logging of the event.
/atom/movable/proc/admin_teleport(atom/new_location, message = TRUE)
if(isnull(new_location))
log_admin("[key_name(usr)] teleported [key_name(src)] to nullspace")
moveToNullspace()
else
log_admin("[key_name(usr)] teleported [key_name(src)] to [AREACOORD(loc)]")
forceMove(new_location)
/mob/admin_teleport(atom/new_location, message = TRUE)
var/msg = "[key_name_admin(usr)] teleported [ADMIN_LOOKUPFLW(src)] to [isnull(new_location) ? "nullspace" : ADMIN_VERBOSEJMP(loc)]"
if(message)
message_admins(msg)
admin_ticket_log(src, msg)
return ..()
+7 -3
View File
@@ -113,7 +113,6 @@
to_chat(src, "<span class='danger'>Error: Use the admin IRC/Discord channel, nerd.</span>", confidential = TRUE)
return
else
//get message text, limit it's length.and clean/escape html
if(!msg)
@@ -128,11 +127,16 @@
else
if(holder)
to_chat(src, "<span class='danger'>Error: Admin-PM: Client not found.</span>", confidential = TRUE)
to_chat(src, "<span class='danger'><b>Message not sent:</b></span><br>[msg]", confidential = TRUE)
to_chat(src, "<span class='danger'><b>Message not sent:</b></span><br>[sanitize(msg)]", confidential = TRUE)
if(recipient_ticket)
recipient_ticket.AddInteraction("<b>No client found, message not sent:</b><br>[msg]")
return
else
//clean the message if it's not sent by a high-rank admin
if(!check_rights(R_SERVER|R_DEBUG,0)||external)//no sending html to the poor bots
msg = sanitize(copytext_char(msg, 1, MAX_MESSAGE_LEN))
if(!msg)
return
current_ticket.MessageNoRecipient(msg)
return
@@ -141,7 +145,7 @@
to_chat(src, "<span class='danger'>Error: Admin-PM: You are unable to use admin PM-s (muted).</span>", confidential = TRUE)
return
if (src.handle_spam_prevention(msg,MUTE_ADMINHELP))
if(src.handle_spam_prevention(msg,MUTE_ADMINHELP))
return
//clean the message if it's not sent by a high-rank admin
+4 -6
View File
@@ -4,12 +4,10 @@
if(!check_rights(R_SOUNDS))
return
var/freq = 1
var/vol = input(usr, "What volume would you like the sound to play at?",, 100) as null|num
if(!vol)
return
var/freq = input(usr, "What frequency would you like the sound to play at?",, 1) as null|num
if(!freq)
freq = 1
vol = clamp(vol, 1, 100)
var/sound/admin_sound = new()
@@ -18,14 +16,14 @@
admin_sound.channel = CHANNEL_ADMIN
admin_sound.frequency = freq
admin_sound.wait = 1
admin_sound.repeat = 0
admin_sound.repeat = FALSE
admin_sound.status = SOUND_STREAM
admin_sound.volume = vol
var/res = alert(usr, "Show the title of this song to the players?",, "Yes","No", "Cancel")
switch(res)
if("Yes")
to_chat(world, "<span class='boldannounce'>An admin played: [S]</span>")
to_chat(world, "<span class='boldannounce'>An admin played: [S]</span>", confidential = TRUE)
if("Cancel")
return
@@ -49,7 +47,7 @@
log_admin("[key_name(src)] played a local sound [S]")
message_admins("[key_name_admin(src)] played a local sound [S]")
playsound(get_turf(src.mob), S, 50, 0, 0)
playsound(get_turf(src.mob), S, 50, FALSE, FALSE)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Play Local Sound") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/play_web_sound()
@@ -104,7 +104,7 @@
if (!thing)
continue
var/datum/D = thing
if (D.vv_edit_var(variable, initial(D.vars[variable])) != FALSE)
if (D.vv_edit_var(variable, initial(D.vars[variable]), TRUE) != FALSE)
accepted++
else
rejected++
@@ -135,7 +135,7 @@
for(var/V in varsvars)
new_value = replacetext(new_value,"\[[V]]","[D.vars[V]]")
if (D.vv_edit_var(variable, new_value) != FALSE)
if (D.vv_edit_var(variable, new_value, TRUE) != FALSE)
accepted++
else
rejected++
@@ -161,7 +161,7 @@
if(many && !new_value)
new_value = new type()
if (D.vv_edit_var(variable, new_value) != FALSE)
if (D.vv_edit_var(variable, new_value, TRUE) != FALSE)
accepted++
else
rejected++
@@ -176,7 +176,7 @@
if (!thing)
continue
var/datum/D = thing
if (D.vv_edit_var(variable, new_value) != FALSE)
if (D.vv_edit_var(variable, new_value, TRUE) != FALSE)
accepted++
else
rejected++
@@ -109,7 +109,7 @@ GLOBAL_LIST_EMPTY(deletion_failures)
set name = "Find References"
set src in world
find_references(FALSE)
find_references_legacy(FALSE)
/datum/proc/find_references_legacy(skip_alert)
@@ -164,7 +164,7 @@ GLOBAL_LIST_EMPTY(deletion_failures)
qdel(src, TRUE) //force a qdel
if(!running_find_references)
find_references(TRUE)
find_references_legacy(TRUE)
/datum/verb/qdel_then_if_fail_find_references()
@@ -9,4 +9,4 @@
/obj/item/organ/heart/gland/ventcrawling/activate()
to_chat(owner, "<span class='notice'>You feel very stretchy.</span>")
owner.ventcrawler = VENTCRAWLER_ALWAYS
owner.AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
@@ -277,3 +277,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
var/datum/antagonist/blob/B = mind.has_antag_datum(/datum/antagonist/blob)
if(!B)
mind.add_antag_datum(/datum/antagonist/blob)
//the same but it's forced to be allowed by default as cameras usually don't allow emoting
/mob/camera/blob/emote(act, m_type=1, message = null, intentional = FALSE, forced = TRUE)
. = ..()
@@ -13,8 +13,9 @@
var/nightime_duration = 900 //15 Minutes
/obj/effect/sunlight/Initialize()
countdown()
hud_tick()
. = ..()
INVOKE_ASYNC(src, .proc/countdown)
INVOKE_ASYNC(src, .proc/hud_tick)
/obj/effect/sunlight/proc/countdown()
set waitfor = FALSE
@@ -90,7 +90,7 @@
/datum/antagonist/vassal/greet()
to_chat(owner, "<span class='userdanger'>You are now the mortal servant of [master.owner.current], a bloodsucking vampire!</span>")
to_chat(owner, "<span class='boldannounce'>The power of [master.owner.current.p_their()] immortal blood compells you to obey [master.owner.current.p_them()] in all things, even offering your own life to prolong theirs.<br>\
You are not required to obey any other Bloodsucker, for only [master.owner.current] is your master. The laws of Nanotransen do not apply to you now; only your vampiric master's word must be obeyed.<span>")
You are not required to obey any other Bloodsucker, for only [master.owner.current] is your master. The laws of Nanotrasen do not apply to you now; only your vampiric master's word must be obeyed.<span>")
// Effects...
owner.current.playsound_local(null, 'sound/magic/mutate.ogg', 100, FALSE, pressure_affected = FALSE)
//owner.store_memory("You became the mortal servant of [master.owner.current], a bloodsucking vampire!")
@@ -213,7 +213,7 @@
if(canrespec)
to_chat(owner.current, "<span class='notice'>We have removed our evolutions from this form, and are now ready to readapt.</span>")
reset_powers()
playsound(get_turf(owner.current), 'sound/effects/lingreadapt.ogg', 75, TRUE, 5, soundenvwet = 0)
playsound(get_turf(owner.current), 'sound/effects/lingreadapt.ogg', 75, TRUE, 5)
canrespec = 0
SSblackbox.record_feedback("tally", "changeling_power_purchase", 1, "Readapt")
return 1
@@ -29,7 +29,7 @@
for(var/obj/machinery/light/L in range(4, user))
L.on = 1
L.break_light_tube()
playsound(get_turf(user), 'sound/effects/lingscreech.ogg', 75, TRUE, 5, soundenvwet = 0)
playsound(get_turf(user), 'sound/effects/lingscreech.ogg', 75, TRUE, 5)
return TRUE
/obj/effect/proc_holder/changeling/dissonant_shriek
@@ -49,5 +49,5 @@
L.on = 1
L.break_light_tube()
empulse_using_range(get_turf(user), 8, TRUE)
playsound(get_turf(user), 'sound/effects/lingempscreech.ogg', 75, TRUE, 5, soundenvwet = 0)
playsound(get_turf(user), 'sound/effects/lingempscreech.ogg', 75, TRUE, 5)
return TRUE
@@ -22,7 +22,7 @@
for(var/mob/M in GLOB.player_list)
if(M.z == z)
if(get_dist(src, M) >= 7)
M.playsound_local(src, 'sound/magic/blink.ogg', 10, FALSE, falloff = 10)
M.playsound_local(src, 'sound/magic/blink.ogg', 10, FALSE)
else
M.playsound_local(src, 'sound/magic/blink.ogg', 50, FALSE)
@@ -165,14 +165,16 @@
/datum/clockwork_rite/treat_wounds/cast(var/mob/living/invoker, var/turf/T, var/mob/living/carbon/human/target)
if(!target)
return FALSE
if(!target.all_wounds.len)
if(!target.all_wounds || !target.all_wounds.len)
to_chat(invoker, "<span class='inathneq_small'>This one does not require mending.</span>")
return FALSE
.= ..()
if(!.)
return FALSE
target.adjustToxLoss(10 * target.all_wounds.len)
QDEL_LIST(target.all_wounds)
for(var/i in target.all_wounds)
var/datum/wound/mended = i
mended.remove_wound()
to_chat(target, "<span class='warning'>You feel your wounds heal, but are overcome with deep nausea.</span>")
new /obj/effect/temp_visual/ratvar/sigil/vitality(T)
@@ -22,7 +22,7 @@
. = ..()
desc = initial(desc)
obj/item/shield/riot/ratvarian/proc/calc_bash_mult()
/obj/item/shield/riot/ratvarian/proc/calc_bash_mult()
var/bash_mult = 0
if(!dam_absorbed)
return 1
@@ -203,10 +203,10 @@
to_chat(user, "<span class='warning'>You need to hold the slab in your active hand to recite scripture!</span>")
return FALSE
var/initial_tier = initial(scripture.tier)
if(initial_tier == SCRIPTURE_PERIPHERAL)
if(initial_tier == SCRIPTURE_PERIPHERAL && !issilicon(user)) //Silicons use peripheral scripture & cannot open the slab.
to_chat(user, "<span class='warning'>Nice try using href exploits</span>")
return
if(!GLOB.ratvar_awakens && !no_cost && !SSticker.scripture_states[initial_tier])
if(!GLOB.ratvar_awakens && !no_cost && !SSticker.scripture_states[initial_tier] &&!issilicon(user)) //silicons can't choose their spells, so lets allow them to always cast their assigned ones.
to_chat(user, "<span class='warning'>That scripture is not unlocked, and cannot be recited!</span>")
return FALSE
var/datum/clockwork_scripture/scripture_to_recite = new scripture
@@ -149,7 +149,7 @@
transform = matrix() * 2
animate(src, transform = matrix() * 0.5, time = 30, flags = ANIMATION_END_NOW)
obj/structure/destructible/clockwork/massive/celestial_gateway/Destroy()
/obj/structure/destructible/clockwork/massive/celestial_gateway/Destroy()
STOP_PROCESSING(SSprocessing, src)
if(!purpose_fulfilled)
var/area/gate_area = get_area(src)
@@ -15,3 +15,5 @@
audible_message("<i>*click*</i>")
playsound(src, 'sound/items/screwdriver2.ogg', 50, TRUE)
activate()
. = ..()
@@ -8,7 +8,7 @@
alpha = 75
/obj/structure/destructible/clockwork/trap/trigger/pressure_sensor/mech/Crossed(atom/movable/AM)
. = ..()
if(!istype(AM,/obj/mecha/))
return
@@ -21,3 +21,5 @@
if(isliving(AM) && opacity)
var/mob/living/L = AM
L.adjust_fire_stacks(-1) //It's wet!
return
. = ..()
@@ -11,7 +11,6 @@
gender = NEUTER
health = 350
maxHealth = 350
ventcrawler = VENTCRAWLER_NONE
density = TRUE
pass_flags = 0
sight = (SEE_TURFS | SEE_OBJS)
@@ -10,6 +10,8 @@
var/give_equipment = TRUE
var/list/researched_knowledge = list()
var/total_sacrifices = 0
var/list/sac_targetted = list() //Which targets did living hearts give them, but they did not sac?
var/list/actually_sacced = list() //Which targets did they actually sac?
var/ascended = FALSE
/datum/antagonist/heretic/admin_add(datum/mind/new_owner,mob/admin)
@@ -175,6 +177,17 @@
knowledge_message += "[EK.name]"
parts += knowledge_message.Join(", ")
parts += "<b>Targets assigned by living hearts, but not sacrificed:</b>"
if(!sac_targetted.len)
parts += "None."
else
parts += sac_targetted.Join(",")
parts += "<b>Sacrifices performed:</b>"
if(!actually_sacced.len)
parts += "<span class='redtext'>None!</span>"
else
parts += actually_sacced.Join(",")
return parts.Join("<br>")
////////////////
// Knowledge //
@@ -213,6 +226,23 @@
if(ascended)
. += 20
/datum/antagonist/heretic/antag_panel()
var/list/parts = list()
parts += ..()
parts += "<b>Targets currently assigned by living hearts (Can give a false negative if they stole someone elses living heart):</b>"
if(!sac_targetted.len)
parts += "None."
else
parts += sac_targetted.Join(",")
parts += "<b>Targets actually sacrificed:</b>"
if(!actually_sacced.len)
parts += "None."
else
parts += actually_sacced.Join(",")
return (parts.Join("<br>") + "<br>")
////////////////
// Objectives //
////////////////
@@ -6,6 +6,17 @@
w_class = WEIGHT_CLASS_SMALL
///Target
var/mob/living/carbon/human/target
var/datum/antagonist/heretic/sac_targetter //The heretic who used this to acquire the current target - gets cleared when target gets sacrificed.
/obj/item/living_heart/Initialize()
. = ..()
GLOB.living_heart_cache.Add(src) //Add is better than +=.
/obj/item/living_heart/Destroy()
GLOB.living_heart_cache.Remove(src)
if(sac_targetter && target)
sac_targetter.sac_targetted.Remove(target.real_name)
return ..()
/obj/item/living_heart/attack_self(mob/user)
. = ..()
@@ -1,6 +1,6 @@
/**
* #Eldritch Knwoledge
* #Eldritch Knowledge
*
* Datum that makes eldritch cultist interesting.
*
@@ -252,6 +252,10 @@
LH.target = null
var/datum/antagonist/heretic/EC = carbon_user.mind.has_antag_datum(/datum/antagonist/heretic)
EC.actually_sacced.Add(H.real_name)
if(LH.sac_targetter)
LH.sac_targetter.sac_targetted.Remove(H.real_name)
LH.sac_targetter = null
EC.total_sacrifices++
for(var/X in carbon_user.get_all_gear())
if(!istype(X,/obj/item/forbidden_book))
@@ -265,8 +269,14 @@
var/datum/objective/A = new
A.owner = user.mind
var/list/targets = list()
var/list/target_blacklist = list()
for(var/obj/item/living_heart/CLH in GLOB.living_heart_cache)
if(!CLH || !CLH.target || !CLH.target.mind)
continue
target_blacklist.Add(CLH.target.mind)
for(var/i in 0 to 3)
var/datum/mind/targeted = A.find_target()//easy way, i dont feel like copy pasting that entire block of code
var/datum/mind/targeted = A.find_target(blacklist = target_blacklist)//easy way, i dont feel like copy pasting that entire block of code
if(!targeted)
break
targets[targeted.current.real_name] = targeted.current
@@ -274,9 +284,24 @@
if(!LH.target && targets.len)
LH.target = pick(targets) //Tsk tsk, you can and will get another target if you want it or not.
if(LH.target)
target_blacklist = list()
for(var/obj/item/living_heart/CLH in (GLOB.living_heart_cache - LH)) //Recreate blacklist, excluding ourselves.
if(!CLH || !CLH.target || !CLH.target.mind)
continue
target_blacklist.Add(CLH.target.mind)
if(LH.target.mind in target_blacklist) //Someone was faster, or you tried to cheese the system.
to_chat(user, "<span class='warning'>It seems you were too slow, and your target of choice has already been selected by another living heart!</span>")
LH.target = null
qdel(A)
if(LH.target)
to_chat(user,"<span class='warning'>Your new target has been selected, go and sacrifice [LH.target.real_name]!</span>")
var/datum/antagonist/heretic/EC = carbon_user.mind.has_antag_datum(/datum/antagonist/heretic)
LH.sac_targetter = EC
EC.sac_targetted.Add(LH.target.real_name)
else
to_chat(user,"<span class='warning'>target could not be found for living heart.</span>")
+4 -1
View File
@@ -15,7 +15,6 @@
stop_automated_movement = 1
status_flags = CANPUSH
pass_flags = PASSTABLE
ventcrawler = VENTCRAWLER_ALWAYS
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
maxHealth = 150
@@ -53,6 +52,10 @@
You can attack any item or dead creature to consume it - creatures will fully restore your health. \
Finally, you can restore yourself to your original form while morphed by shift-clicking yourself.</b>"
/mob/living/simple_animal/hostile/morph/Initialize()
. = ..()
src.AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
/mob/living/simple_animal/hostile/morph/examine(mob/user)
if(morphed)
. = form.examine(user)
+49 -7
View File
@@ -72,6 +72,7 @@
var/list/drained_mobs = list() //Cannot harvest the same mob twice
var/perfectsouls = 0 //How many perfect, regen-cap increasing souls the revenant has. //TODO, add objective for getting a perfect soul(s?)
var/generated_objectives_and_spells = FALSE
var/telekinesis_cooldown
/mob/living/simple_animal/revenant/Initialize(mapload)
. = ..()
@@ -93,13 +94,16 @@
/mob/living/simple_animal/revenant/Login()
..()
to_chat(src, "<span class='deadsay'><span class='big bold'>You are a revenant.</span></span>")
to_chat(src, "<b>Your formerly mundane spirit has been infused with alien energies and empowered into a revenant.</b>")
to_chat(src, "<b>You are not dead, not alive, but somewhere in between. You are capable of limited interaction with both worlds.</b>")
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 <a href=\"https://tgstation13.org/wiki/Revenant\">the wiki page</a> to learn more.</b>")
var/revenant_greet
revenant_greet += "<span class='deadsay'><span class='big bold'>You are a revenant.</span></span>"
revenant_greet += "<b>Your formerly mundane spirit has been infused with alien energies and empowered into a revenant.</b>"
revenant_greet += "<b>You are not dead, not alive, but somewhere in between. You are capable of limited interaction with both worlds.</b>"
revenant_greet += "<b>You are invincible and invisible to everyone but other ghosts. Most abilities will reveal you, rendering you vulnerable.</b>"
revenant_greet += "<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>"
revenant_greet += "<b><i>You do not remember anything of your past lives, nor will you remember anything about this one after your death.</i></b>"
revenant_greet += "<b>Be sure to read <a href=\"https://tgstation13.org/wiki/Revenant\">the wiki page</a> to learn more.</b>"
revenant_greet += "<b>You are also able to telekinetically throw objects by clickdragging them.</b>"
to_chat(src, revenant_greet)
if(!generated_objectives_and_spells)
generated_objectives_and_spells = TRUE
mind.assigned_role = ROLE_REVENANT
@@ -317,6 +321,12 @@
to_chat(src, "<span class='revenminor'>Lost [essence_amt]E[source ? " from [source]":""].</span>")
return 1
/mob/living/simple_animal/revenant/proc/telekinesis_cooldown_end()
if(!telekinesis_cooldown)
CRASH("telekinesis_cooldown_end ran when telekinesis_cooldown on [src] was false")
else
telekinesis_cooldown = FALSE
/mob/living/simple_animal/revenant/proc/death_reset()
revealed = FALSE
unreveal_time = 0
@@ -431,6 +441,38 @@
qdel(revenant)
..()
/proc/RevenantThrow(over, mob/user, obj/item/throwable)
var/mob/living/simple_animal/revenant/spooker = user
if(!istype(throwable))
return
if(!throwable.anchored && !spooker.telekinesis_cooldown && spooker.essence > 20)
if(7 < get_dist(throwable, spooker))
return
if(3 >= get_dist(throwable, spooker))
spooker.stun(10)
spooker.reveal(25)
else
spooker.stun(20)
spooker.reveal(50)
spooker.change_essence_amount(-20, FALSE, "telekinesis")
spooker.telekinesis_cooldown = TRUE
throwable.float(TRUE, TRUE)
sleep(20)
throwable.DoRevenantThrowEffects(over)
throwable.throw_at(over, 10, 2)
ADD_TRAIT(throwable, TRAIT_SPOOKY_THROW, "revenant")
log_combat(throwable, over, "spooky telekinesised at", throwable)
var/obj/effect/temp_visual/telekinesis/T = new(get_turf(throwable))
T.color = "#8715b4"
addtimer(CALLBACK(spooker, /mob/living/simple_animal/revenant.proc/telekinesis_cooldown_end), 50)
sleep(5)
throwable.float(FALSE, TRUE)
//Use this for effects you want to happen when a revenant throws stuff, check the TRAIT_SPOOKY_THROW if you want to know if its still being thrown
/obj/item/proc/DoRevenantThrowEffects(atom/target)
return TRUE
//objectives
/datum/objective/revenant
var/targetAmount = 100
+1 -1
View File
@@ -93,7 +93,6 @@
AIStatus = AI_OFF
pass_flags = PASSTABLE
mob_size = MOB_SIZE_TINY
ventcrawler = VENTCRAWLER_ALWAYS
ranged = 1
projectiletype = /obj/item/projectile/beam/disabler
ranged_cooldown_time = 20
@@ -112,6 +111,7 @@
remove_verb(src, /mob/living/verb/pulled)
for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds)
diag_hud.add_to_hud(src)
AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
/mob/living/simple_animal/hostile/swarmer/med_hud_set_health()
var/image/holder = hud_list[DIAG_HUD]
@@ -43,7 +43,7 @@
var/list/to_generate = list(
CONTRACT_PAYOUT_LARGE,
CONTRACT_PAYOUT_MEDIUM,
CONTRACT_PAYOUT_SMALL,
CONTRACT_PAYOUT_MEDIUM,
CONTRACT_PAYOUT_SMALL,
CONTRACT_PAYOUT_SMALL,
CONTRACT_PAYOUT_SMALL
+8 -8
View File
@@ -103,29 +103,29 @@
name = "knotted dildo"
attack_verb = list("penetrated", "knotted", "slapped", "inseminated")
obj/item/dildo/human
/obj/item/dildo/human
dildo_shape = "human"
name = "human dildo"
attack_verb = list("penetrated", "slapped", "inseminated")
obj/item/dildo/plain
/obj/item/dildo/plain
dildo_shape = "plain"
name = "plain dildo"
attack_verb = list("penetrated", "slapped", "inseminated")
obj/item/dildo/flared
/obj/item/dildo/flared
dildo_shape = "flared"
name = "flared dildo"
attack_verb = list("penetrated", "slapped", "neighed", "gaped", "prolapsed", "inseminated")
obj/item/dildo/flared/huge
/obj/item/dildo/flared/huge
name = "literal horse cock"
desc = "THIS THING IS HUGE!"
dildo_size = 4
force = 10
hitsound = 'sound/weapons/klonk.ogg'
obj/item/dildo/custom
/obj/item/dildo/custom
name = "customizable dildo"
desc = "Thanks to significant advances in synthetic nanomaterials, this dildo is capable of taking on many different forms to fit the user's preferences! Pricy!"
can_customize = TRUE
@@ -136,9 +136,9 @@ obj/item/dildo/custom
// Suicide acts, by request
/obj/item/dildo/proc/manual_suicide(mob/living/user)
user.visible_message("<span class='suicide'>[user] finally finishes deepthroating the [src], and their life.</span>")
user.adjustOxyLoss(200)
user.death(0)
user.visible_message("<span class='suicide'>[user] finally finishes deepthroating the [src], and their life.</span>")
user.adjustOxyLoss(200)
user.death(0)
/obj/item/dildo/suicide_act(mob/living/user)
// is_knotted = ((src.dildo_shape == "knotted")?"They swallowed the knot":"Their face is turning blue")
+3
View File
@@ -30,6 +30,9 @@
attack(user,user)
return FIRELOSS
/obj/item/assembly/flash/DoRevenantThrowEffects(atom/target)
AOE_flash()
/obj/item/assembly/flash/update_icon(flash = FALSE)
cut_overlays()
attached_overlays = list()
+1
View File
@@ -62,6 +62,7 @@
master.update_icon()
/obj/item/assembly_holder/Crossed(atom/movable/AM as mob|obj)
. = ..()
if(a_left)
a_left.Crossed(AM)
if(a_right)
@@ -1,5 +1,5 @@
/// Process asset cache client topic calls for "asset_cache_confirm_arrival=[INT]"
/// Process asset cache client topic calls for `"asset_cache_confirm_arrival=[INT]"`
/client/proc/asset_cache_confirm_arrival(job_id)
var/asset_cache_job = round(text2num(job_id))
//because we skip the limiter, we have to make sure this is a valid arrival and not somebody tricking us into letting them append to a list without limit.
@@ -10,7 +10,7 @@
return asset_cache_job || TRUE
/// Process asset cache client topic calls for "asset_cache_preload_data=[HTML+JSON_STRING]
/// Process asset cache client topic calls for `"asset_cache_preload_data=[HTML+JSON_STRING]"`
/client/proc/asset_cache_preload_data(data)
var/json = data
var/list/preloaded_assets = json_decode(json)
+58 -5
View File
@@ -47,8 +47,9 @@
"smmon_3.gif" = 'icons/program_icons/smmon_3.gif',
"smmon_4.gif" = 'icons/program_icons/smmon_4.gif',
"smmon_5.gif" = 'icons/program_icons/smmon_5.gif',
"smmon_6.gif" = 'icons/program_icons/smmon_6.gif',
"borg_mon.gif" = 'icons/program_icons/borg_mon.gif'
"smmon_6.gif" = 'icons/program_icons/smmon_6.gif'
// "borg_mon.gif" = 'icons/program_icons/borg_mon.gif',
// "robotact.gif" = 'icons/program_icons/robotact.gif'
)
/datum/asset/simple/radar_assets
@@ -156,7 +157,6 @@
)
/datum/asset/simple/namespaced/fontawesome
legacy = TRUE
assets = list(
"fa-regular-400.eot" = 'html/font-awesome/webfonts/fa-regular-400.eot',
"fa-regular-400.woff" = 'html/font-awesome/webfonts/fa-regular-400.woff',
@@ -248,6 +248,10 @@
"rule8" = 'icons/UI_Icons/Achievements/Misc/rule8.png',
"snail" = 'icons/UI_Icons/Achievements/Misc/snail.png',
"ascension" = 'icons/UI_Icons/Achievements/Misc/ascension.png',
"ashascend" = 'icons/UI_Icons/Achievements/Misc/ashascend.png',
"fleshascend" = 'icons/UI_Icons/Achievements/Misc/fleshascend.png',
"rustascend" = 'icons/UI_Icons/Achievements/Misc/rustascend.png',
"voidascend" = 'icons/UI_Icons/Achievements/Misc/voidascend.png',
"mining" = 'icons/UI_Icons/Achievements/Skills/mining.png',
"assistant" = 'icons/UI_Icons/Achievements/Mafia/assistant.png',
"changeling" = 'icons/UI_Icons/Achievements/Mafia/changeling.png',
@@ -288,7 +292,7 @@
)
/datum/asset/spritesheet/simple/pills
name ="pills"
name = "pills"
assets = list(
"pill1" = 'icons/UI_Icons/Pills/pill1.png',
"pill2" = 'icons/UI_Icons/Pills/pill2.png',
@@ -313,7 +317,28 @@
"pill21" = 'icons/UI_Icons/Pills/pill21.png',
"pill22" = 'icons/UI_Icons/Pills/pill22.png',
)
/*
/datum/asset/spritesheet/simple/condiments
name = "condiments"
assets = list(
CONDIMASTER_STYLE_FALLBACK = 'icons/UI_Icons/Condiments/emptycondiment.png',
"enzyme" = 'icons/UI_Icons/Condiments/enzyme.png',
"flour" = 'icons/UI_Icons/Condiments/flour.png',
"mayonnaise" = 'icons/UI_Icons/Condiments/mayonnaise.png',
"milk" = 'icons/UI_Icons/Condiments/milk.png',
"blackpepper" = 'icons/UI_Icons/Condiments/peppermillsmall.png',
"rice" = 'icons/UI_Icons/Condiments/rice.png',
"sodiumchloride" = 'icons/UI_Icons/Condiments/saltshakersmall.png',
"soymilk" = 'icons/UI_Icons/Condiments/soymilk.png',
"soysauce" = 'icons/UI_Icons/Condiments/soysauce.png',
"sugar" = 'icons/UI_Icons/Condiments/sugar.png',
"ketchup" = 'icons/UI_Icons/Condiments/ketchup.png',
"capsaicin" = 'icons/UI_Icons/Condiments/hotsauce.png',
"frostoil" = 'icons/UI_Icons/Condiments/coldsauce.png',
"bbqsauce" = 'icons/UI_Icons/Condiments/bbqsauce.png',
"cornoil" = 'icons/UI_Icons/Condiments/oliveoil.png',
)
*/
//this exists purely to avoid meta by pre-loading all language icons.
/datum/asset/language/register()
for(var/path in typesof(/datum/language))
@@ -484,3 +509,31 @@
/datum/asset/spritesheet/mafia/register()
InsertAll("", 'icons/obj/mafia.dmi')
..()
/datum/asset/simple/portraits
var/tab = "use subtypes of this please"
assets = list()
/datum/asset/simple/portraits/New()
if(!SSpersistence.paintings || !SSpersistence.paintings[tab] || !length(SSpersistence.paintings[tab]))
return
for(var/p in SSpersistence.paintings[tab])
var/list/portrait = p
var/png = "data/paintings/[tab]/[portrait["md5"]].png"
if(fexists(png))
assets[portrait["title"]] = png
..() //this is where it registers all these assets we added to the list
/datum/asset/simple/portraits/library
tab = "library"
/datum/asset/simple/portraits/library_secure
tab = "library_secure"
/datum/asset/simple/portraits/library_private
tab = "library_private"
/datum/asset/simple/safe
assets = list(
"safe_dial.png" = 'html/safe_dial.png'
)
+2 -2
View File
@@ -24,7 +24,7 @@ Call .get_url_mappings() to get an associated list with the urls your assets can
See the documentation for `/datum/asset_transport` for the backend api the asset datums utilize.
The global variable `SSassets.transport` contains the currently configured transport.
The global variable `SSassets.transport` contains the currently configured transport.
@@ -32,6 +32,6 @@ The global variable `SSassets.transport` contains the currently configured trans
Because byond browse() calls use non-blocking queues, if your code uses output() (which bypasses all of these queues) to invoke javascript functions you will need to first have the javascript announce to the server it has loaded before trying to invoke js functions.
To make your code work with any CDNs configured by the server, you must make sure assets are referenced from the url returned by `get_url_mappings()` or by asset_transport's `get_asset_url()`. (TGUI also has helpers for this.) If this can not be easily done, you can bypass the cdn using legacy assets, see the simple asset datum for details.
To make your code work with any CDNs configured by the server, you must make sure assets are referenced from the url returned by `get_url_mappings()` or by asset_transport's `get_asset_url()`. (TGUI also has helpers for this.) If this can not be easily done, you can bypass the cdn using legacy assets, see the simple asset datum for details.
CSS files that use url() can be made to use the CDN without needing to rewrite all url() calls in code by using the namespaced helper datum. See the documentation for `/datum/asset/simple/namespaced` for details.
@@ -49,6 +49,7 @@
SSair.add_to_active(T)
return ..()
/// Function for Extools Atmos
/turf/proc/update_air_ref()
/////////////////GAS MIXTURE PROCS///////////////////
@@ -44,7 +44,7 @@
. = ..()
if(is_type_in_list(src, GLOB.ventcrawl_machinery) && isliving(user))
var/mob/living/L = user
if(L.ventcrawler)
if(SEND_SIGNAL(L, COMSIG_CHECK_VENTCRAWL))
. += "<span class='notice'>Alt-click to crawl through it.</span>"
/obj/machinery/atmospherics/New(loc, process = TRUE, setdir)
@@ -318,7 +318,7 @@
/obj/machinery/atmospherics/AltClick(mob/living/L)
if(is_type_in_typecache(src, GLOB.ventcrawl_machinery))
return L.handle_ventcrawl(src)
return SEND_SIGNAL(L, COMSIG_HANDLE_VENTCRAWL, src)
return ..()
@@ -261,7 +261,7 @@
new /obj/item/stack/sheet/metal (loc, 5)
qdel(src)
obj/machinery/portable_atmospherics/canister/welder_act(mob/living/user, obj/item/I)
/obj/machinery/portable_atmospherics/canister/welder_act(mob/living/user, obj/item/I)
..()
if(user.a_intent == INTENT_HARM)
return FALSE
+3 -4
View File
@@ -1,4 +1,5 @@
obj/machinery/atmospherics/pipe/simple/multiz ///This is an atmospherics pipe which can relay air up a deck (Z+1). It currently only supports being on pipe layer 1
/// This is an atmospherics pipe which can relay air up/down a deck.
/obj/machinery/atmospherics/pipe/simple/multiz
name = "multi deck pipe adapter"
desc = "An adapter which allows pipes to connect to other pipenets on different decks."
icon_state = "multiz_pipe"
@@ -24,6 +25,4 @@ obj/machinery/atmospherics/pipe/simple/multiz ///This is an atmospherics pipe wh
if(above)
nodes += above
above.nodes += src //Two way travel :)
return ..()
else
return ..()
return ..()
+90 -60
View File
@@ -7,6 +7,8 @@
#define AMMO_DROP_LIFETIME 300
#define CTF_REQUIRED_PLAYERS 4
/obj/item/ctf
name = "banner"
icon = 'icons/obj/items_and_weapons.dmi'
@@ -16,13 +18,13 @@
righthand_file = 'icons/mob/inhands/equipment/banners_righthand.dmi'
desc = "A banner with Nanotrasen's logo on it."
slowdown = 2
item_flags = SLOWS_WHILE_IN_HAND
throw_speed = 0
throw_range = 1
force = 200
armour_penetration = 1000
resistance_flags = INDESTRUCTIBLE
anchored = TRUE
item_flags = SLOWS_WHILE_IN_HAND
var/team = WHITE_TEAM
var/reset_cooldown = 0
var/anyonecanpickup = TRUE
@@ -53,12 +55,13 @@
to_chat(M, "<span class='userdanger'>\The [src] has been returned to base!</span>")
STOP_PROCESSING(SSobj, src)
/obj/item/ctf/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/item/ctf/on_attack_hand(mob/living/user)
if(!is_ctf_target(user) && !anyonecanpickup)
to_chat(user, "Non players shouldn't be moving the flag!")
to_chat(user, "<span class='warning'>Non-players shouldn't be moving the flag!</span>")
return
if(team in user.faction)
to_chat(user, "You can't move your own flag!")
to_chat(user, "<span class='warning'>You can't move your own flag!</span>")
return
if(loc == user)
if(!user.dropItemToGround(src))
@@ -68,7 +71,7 @@
if(!user.put_in_active_hand(src))
dropped(user)
return
user.anchored = TRUE
user.set_anchored(TRUE)
user.status_flags &= ~CANPUSH
for(var/mob/M in GLOB.player_list)
var/area/mob_area = get_area(M)
@@ -79,7 +82,7 @@
/obj/item/ctf/dropped(mob/user)
..()
user.anchored = FALSE
user.set_anchored(FALSE)
user.status_flags |= CANPUSH
reset_cooldown = world.time + 200 //20 seconds
START_PROCESSING(SSobj, src)
@@ -172,20 +175,20 @@
GLOB.poi_list.Remove(src)
..()
/obj/machinery/capture_the_flag/process()
/obj/machinery/capture_the_flag/process(delta_time)
for(var/i in spawned_mobs)
if(!i)
spawned_mobs -= i
continue
// Anyone in crit, automatically reap
var/mob/living/M = i
if(M.InCritical() || M.stat == DEAD)
ctf_dust_old(M)
var/mob/living/living_participant = i
if(living_participant.InCritical() || living_participant.stat == DEAD)
ctf_dust_old(living_participant)
else
// The changes that you've been hit with no shield but not
// instantly critted are low, but have some healing.
M.adjustBruteLoss(-5)
M.adjustFireLoss(-5)
living_participant.adjustBruteLoss(-2.5 * delta_time)
living_participant.adjustFireLoss(-2.5 * delta_time)
/obj/machinery/capture_the_flag/red
name = "Red CTF Controller"
@@ -212,6 +215,10 @@
toggle_all_ctf(user)
return
// if(!(GLOB.ghost_role_flags & GHOSTROLE_MINIGAME))
// to_chat(user, "<span class='warning'>CTF has been temporarily disabled by admins.</span>")
// return
people_who_want_to_play |= user.ckey
var/num = people_who_want_to_play.len
var/remaining = CTF_REQUIRED_PLAYERS - num
@@ -227,7 +234,7 @@
return
if(user.ckey in team_members)
if(user.ckey in recently_dead_ckeys)
to_chat(user, "It must be more than [DisplayTimeText(respawn_cooldown)] from your last death to respawn!")
to_chat(user, "<span class='warning'>It must be more than [DisplayTimeText(respawn_cooldown)] from your last death to respawn!</span>")
return
var/client/new_team_member = user.client
if(user.mind && user.mind.current)
@@ -239,10 +246,10 @@
if(CTF == src || CTF.ctf_enabled == FALSE)
continue
if(user.ckey in CTF.team_members)
to_chat(user, "No switching teams while the round is going!")
to_chat(user, "<span class='warning'>No switching teams while the round is going!</span>")
return
if(CTF.team_members.len < src.team_members.len)
to_chat(user, "[src.team] has more team members than [CTF.team]. Try joining [CTF.team] team to even things up.")
to_chat(user, "<span class='warning'>[src.team] has more team members than [CTF.team]! Try joining [CTF.team] team to even things up.</span>")
return
team_members |= user.ckey
var/client/new_team_member = user.client
@@ -258,7 +265,7 @@
addtimer(CALLBACK(src, .proc/clear_cooldown, body.ckey), respawn_cooldown, TIMER_UNIQUE)
body.dust()
/obj/machinery/capture_the_flag/proc/clear_cooldown(var/ckey)
/obj/machinery/capture_the_flag/proc/clear_cooldown(ckey)
recently_dead_ckeys -= ckey
/obj/machinery/capture_the_flag/proc/spawn_team_member(client/new_team_member)
@@ -270,7 +277,7 @@
M.equipOutfit(ctf_gear)
M.dna.species.punchdamagehigh = 25
M.dna.species.punchdamagelow = 25
M.AddElement(/datum/element/ghost_role_eligibility)
M.AddElement(/datum/element/ghost_role_eligibility) //??
spawned_mobs += M
/obj/machinery/capture_the_flag/Topic(href, href_list)
@@ -293,14 +300,15 @@
victory()
/obj/machinery/capture_the_flag/proc/victory()
for(var/mob/M in GLOB.mob_list)
var/area/mob_area = get_area(M)
for(var/mob/_competitor in GLOB.mob_living_list)
var/mob/living/competitor = _competitor
var/area/mob_area = get_area(competitor)
if(istype(mob_area, /area/ctf))
to_chat(M, "<span class='narsie [team_span]'>[team] team wins!</span>")
to_chat(M, "<span class='userdanger'>Teams have been cleared. Click on the machines to vote to begin another round.</span>")
for(var/obj/item/ctf/W in M)
M.dropItemToGround(W)
M.dust()
to_chat(competitor, "<span class='narsie [team_span]'>[team] team wins!</span>")
to_chat(competitor, "<span class='userdanger'>Teams have been cleared. Click on the machines to vote to begin another round.</span>")
for(var/obj/item/ctf/W in competitor)
competitor.dropItemToGround(W)
competitor.dust()
for(var/obj/machinery/control_point/control in GLOB.machines)
control.icon_state = "dominator"
control.controlling = null
@@ -328,7 +336,7 @@
dead_barricades.Cut()
notify_ghosts("[name] has been activated!", enter_link="<a href=?src=[REF(src)];join=1>(Click to join the [team] team!)</a> or click on the controller directly!", source = src, action=NOTIFY_ATTACK)
notify_ghosts("[name] has been activated!", enter_link="<a href=?src=[REF(src)];join=1>(Click to join the [team] team!)</a> or click on the controller directly!", source = src, action=NOTIFY_ATTACK, header = "CTF has been activated")
if(!arena_reset)
reset_the_arena()
@@ -355,10 +363,10 @@
ctf_enabled = FALSE
arena_reset = FALSE
var/area/A = get_area(src)
for(var/i in GLOB.mob_list)
var/mob/M = i
if((get_area(A) == A) && (M.ckey in team_members))
M.dust()
for(var/_competitor in GLOB.mob_living_list)
var/mob/living/competitor = _competitor
if((get_area(A) == A) && (competitor.ckey in team_members))
competitor.dust()
team_members.Cut()
spawned_mobs.Cut()
recently_dead_ckeys.Cut()
@@ -375,18 +383,18 @@
CTF.ctf_gear = initial(ctf_gear)
CTF.respawn_cooldown = DEFAULT_RESPAWN
/proc/ctf_floor_vanish(atom/target)
if(isturf(target.loc))
qdel(target)
/obj/item/gun/ballistic/automatic/pistol/deagle/ctf
desc = "This looks like it could really hurt in melee."
force = 75
mag_type = /obj/item/ammo_box/magazine/m50/ctf
/obj/item/gun/ballistic/automatic/pistol/deagle/ctf/dropped(mob/user)
/obj/item/gun/ballistic/automatic/pistol/deagle/ctf/dropped()
. = ..()
addtimer(CALLBACK(GLOBAL_PROC, /proc/ctf_floor_vanish, src), 1)
addtimer(CALLBACK(src, .proc/floor_vanish), 1)
/obj/item/gun/ballistic/automatic/pistol/deagle/ctf/proc/floor_vanish()
if(isturf(loc))
qdel(src)
/obj/item/ammo_box/magazine/m50/ctf
ammo_type = /obj/item/ammo_casing/a50/ctf
@@ -400,6 +408,7 @@
/obj/item/projectile/bullet/ctf/prehit(atom/target)
if(is_ctf_target(target))
damage = 60
return //PROJECTILE_PIERCE_NONE /// hey uhh don't hit anyone behind them
. = ..()
/obj/item/gun/ballistic/automatic/laser/ctf
@@ -407,16 +416,24 @@
desc = "This looks like it could really hurt in melee."
force = 50
/obj/item/gun/ballistic/automatic/laser/ctf/dropped(mob/user)
/obj/item/gun/ballistic/automatic/laser/ctf/dropped()
. = ..()
addtimer(CALLBACK(GLOBAL_PROC, /proc/ctf_floor_vanish, src), 1)
addtimer(CALLBACK(src, .proc/floor_vanish), 1)
/obj/item/gun/ballistic/automatic/laser/ctf/proc/floor_vanish()
if(isturf(loc))
qdel(src)
/obj/item/ammo_box/magazine/recharge/ctf
ammo_type = /obj/item/ammo_casing/caseless/laser/ctf
/obj/item/ammo_box/magazine/recharge/ctf/dropped(mob/user)
/obj/item/ammo_box/magazine/recharge/ctf/dropped()
. = ..()
addtimer(CALLBACK(GLOBAL_PROC, /proc/ctf_floor_vanish, src), 1)
addtimer(CALLBACK(src, .proc/floor_vanish), 1)
/obj/item/ammo_box/magazine/recharge/ctf/proc/floor_vanish()
if(isturf(loc))
qdel(src)
/obj/item/ammo_casing/caseless/laser/ctf
projectile_type = /obj/item/projectile/beam/ctf
@@ -428,15 +445,16 @@
/obj/item/projectile/beam/ctf/prehit(atom/target)
if(is_ctf_target(target))
damage = 150
return //PROJECTILE_PIERCE_NONE /// hey uhhh don't hit anyone behind them
. = ..()
/proc/is_ctf_target(atom/target)
. = FALSE
if(istype(target, /obj/structure/barricade/security/ctf))
. = TRUE
if(isliving(target))
var/mob/living/H = target
if((RED_TEAM in H.faction) || (BLUE_TEAM in H.faction))
if(ishuman(target))
var/mob/living/carbon/human/H = target
if(istype(H.wear_suit, /obj/item/clothing/suit/space/hardsuit/shielded/ctf))
. = TRUE
// RED TEAM GUNS
@@ -482,7 +500,11 @@
/obj/item/claymore/ctf/dropped(mob/user)
. = ..()
addtimer(CALLBACK(GLOBAL_PROC, /proc/ctf_floor_vanish, src), 1)
addtimer(CALLBACK(src, .proc/floor_vanish), 1)
/obj/item/claymore/ctf/proc/floor_vanish()
if(isturf(loc))
qdel(src)
/datum/outfit/ctf
name = "CTF"
@@ -491,27 +513,28 @@
suit = /obj/item/clothing/suit/space/hardsuit/shielded/ctf
toggle_helmet = FALSE // see the whites of their eyes
shoes = /obj/item/clothing/shoes/combat
gloves = /obj/item/clothing/gloves/tackler/combat
gloves = /obj/item/clothing/gloves/combat
id = /obj/item/card/id/away
belt = /obj/item/gun/ballistic/automatic/pistol/deagle/ctf
l_pocket = /obj/item/ammo_box/magazine/recharge/ctf
r_pocket = /obj/item/ammo_box/magazine/recharge/ctf
r_hand = /obj/item/gun/ballistic/automatic/laser/ctf
back = /obj/item/claymore/ctf
/datum/outfit/ctf/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
/datum/outfit/ctf/post_equip(mob/living/carbon/human/H, visualsOnly=FALSE)
if(visualsOnly)
return
var/list/no_drops = list()
var/obj/item/card/id/W = H.wear_id
no_drops += W
W.registered_name = H.real_name
W.update_label(W.registered_name, W.assignment)
W.update_label()
// The shielded hardsuit is already TRAIT_NODROP
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(ITEM_SLOT_OCLOTHING)
no_drops += H.get_item_by_slot(ITEM_SLOT_GLOVES)
no_drops += H.get_item_by_slot(ITEM_SLOT_FEET)
no_drops += H.get_item_by_slot(ITEM_SLOT_ICLOTHING)
no_drops += H.get_item_by_slot(ITEM_SLOT_EARS)
for(var/i in no_drops)
var/obj/item/I = i
ADD_TRAIT(I, TRAIT_NODROP, CAPTURE_THE_FLAG_TRAIT)
@@ -525,6 +548,7 @@
r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/red
l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/red
r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/red
id = /obj/item/card/id/syndicate_command //it's red
/datum/outfit/ctf/red/instagib
r_hand = /obj/item/gun/energy/laser/instakill/red
@@ -535,12 +559,13 @@
r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/blue
l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/blue
r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/blue
id = /obj/item/card/id/centcom //it's blue
/datum/outfit/ctf/blue/instagib
r_hand = /obj/item/gun/energy/laser/instakill/blue
shoes = /obj/item/clothing/shoes/jackboots/fast
/datum/outfit/ctf/red/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
/datum/outfit/ctf/red/post_equip(mob/living/carbon/human/H)
..()
var/obj/item/radio/R = H.ears
R.set_frequency(FREQ_CTF_RED)
@@ -548,7 +573,7 @@
R.independent = TRUE
H.dna.species.stunmod = 0
/datum/outfit/ctf/blue/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
/datum/outfit/ctf/blue/post_equip(mob/living/carbon/human/H)
..()
var/obj/item/radio/R = H.ears
R.set_frequency(FREQ_CTF_BLUE)
@@ -595,6 +620,10 @@
/obj/structure/barricade/security/ctf/make_debris()
new /obj/effect/ctf/dead_barricade(get_turf(src))
/obj/structure/table/reinforced/ctf
resistance_flags = INDESTRUCTIBLE
flags_1 = NODECONSTRUCT_1
/obj/effect/ctf
density = FALSE
anchored = TRUE
@@ -617,10 +646,11 @@
QDEL_IN(src, AMMO_DROP_LIFETIME)
/obj/effect/ctf/ammo/Crossed(atom/movable/AM)
. = ..()
reload(AM)
/obj/effect/ctf/ammo/Bump(atom/movable/AM)
reload(AM)
/obj/effect/ctf/ammo/Bump(atom/A)
reload(A)
/obj/effect/ctf/ammo/Bumped(atom/movable/AM)
reload(AM)
@@ -636,7 +666,7 @@
qdel(G)
O.equip(M)
to_chat(M, "<span class='notice'>Ammunition reloaded!</span>")
playsound(get_turf(M), 'sound/weapons/shotgunpump.ogg', 50, 1, -1)
playsound(get_turf(M), 'sound/weapons/shotgunpump.ogg', 50, TRUE, -1)
qdel(src)
break
@@ -667,18 +697,18 @@
resistance_flags = INDESTRUCTIBLE
var/obj/machinery/capture_the_flag/controlling
var/team = "none"
var/point_rate = 1
var/point_rate = 0.5
/obj/machinery/control_point/process()
/obj/machinery/control_point/process(delta_time)
if(controlling)
controlling.control_points += point_rate
controlling.control_points += point_rate * delta_time
if(controlling.control_points >= controlling.control_points_to_win)
controlling.victory()
/obj/machinery/control_point/attackby(mob/user, params)
capture(user)
/obj/machinery/control_point/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
/obj/machinery/control_point/on_attack_hand(mob/user)
capture(user)
/obj/machinery/control_point/proc/capture(mob/user)
+1 -1
View File
@@ -66,7 +66,7 @@
/obj/effect/mob_spawn/Initialize(mapload)
. = ..()
if(instant || (roundstart && (mapload || (SSticker && SSticker.current_state > GAME_STATE_SETTING_UP))))
create()
INVOKE_ASYNC(src, .proc/create)
else if(ghost_usable)
GLOB.poi_list |= src
LAZYADD(GLOB.mob_spawners[job_description ? job_description : name], src)
@@ -196,7 +196,7 @@
/obj/item/dice/d20/fate/proc/effect(var/mob/living/carbon/human/user,roll)
if(!reusable)
used = 1
visible_message("<span class='userdanger'>The die flare briefly.</span>")
visible_message("<span class='userdanger'>The die flares briefly.</span>")
switch(roll)
if(1)
//Dust
@@ -132,6 +132,7 @@
var/triggered = 0
/obj/effect/meatgrinder/Crossed(atom/movable/AM)
. = ..()
Bumped(AM)
/obj/effect/meatgrinder/Bumped(atom/movable/AM)
+3 -3
View File
@@ -35,7 +35,7 @@
name = "Simple Drink"
reward = 1500
datum/bounty/reagent/simple_drink/New()
/datum/bounty/reagent/simple_drink/New()
// Don't worry about making this comprehensive. It doesn't matter if some drinks are skipped.
var/static/list/possible_reagents = list(\
/datum/reagent/consumable/ethanol/antifreeze,\
@@ -91,7 +91,7 @@ datum/bounty/reagent/simple_drink/New()
name = "Complex Drink"
reward = 4000
datum/bounty/reagent/complex_drink/New()
/datum/bounty/reagent/complex_drink/New()
// Don't worry about making this comprehensive. It doesn't matter if some drinks are skipped.
var/static/list/possible_reagents = list(\
/datum/reagent/consumable/ethanol/atomicbomb,\
@@ -124,7 +124,7 @@ datum/bounty/reagent/complex_drink/New()
reward = 2750
required_volume = 30
datum/bounty/reagent/chemical/New()
/datum/bounty/reagent/chemical/New()
// Don't worry about making this comprehensive. It doesn't matter if some chems are skipped.
var/static/list/possible_reagents = list(\
/datum/reagent/medicine/leporazine,\
+4 -4
View File
@@ -473,7 +473,7 @@
//Soft Suits
//Blanket
datum/export/gear/space/helmet
/datum/export/gear/space/helmet
cost = 55
unit_name = "space helmet"
export_types = list(/obj/item/clothing/head/helmet/space)
@@ -485,7 +485,7 @@ datum/export/gear/space/helmet
export_types = list(/obj/item/clothing/suit/space)
include_subtypes = TRUE
datum/export/gear/space/helmet/plasma
/datum/export/gear/space/helmet/plasma
cost = 100
unit_name = "plasmaman space helmet"
export_types = list(/obj/item/clothing/suit/space/eva/plasmaman)
@@ -495,7 +495,7 @@ datum/export/gear/space/helmet/plasma
unit_name = "plasmaman space suit"
export_types = list(/obj/item/clothing/suit/space/eva/plasmaman)
datum/export/gear/space/helmet/synda
/datum/export/gear/space/helmet/synda
cost = 150 //Flash proof
unit_name = "syndicate space helmet"
export_types = list(/obj/item/clothing/head/helmet/space/syndicate)
@@ -510,7 +510,7 @@ datum/export/gear/space/helmet/synda
//Glasses
//Blanket
datum/export/gear/glasses //glasses are not worth selling
/datum/export/gear/glasses //glasses are not worth selling
cost = 3
unit_name = "glasses"
export_types = list(/obj/item/clothing/glasses)
+1 -1
View File
@@ -38,7 +38,7 @@
var/path = "sound/chatter/[phomeme]_[length].ogg"
playsound(loc, path,
vol = 40, vary = 0, extrarange = 3, falloff = FALSE)
vol = 40, vary = 0, extrarange = 3)
sleep((length + 1) * chatter_get_sleep_multiplier(phomeme))
+1
View File
@@ -31,6 +31,7 @@
var/datum/preferences/prefs = null
var/last_turn = 0
var/move_delay = 0
var/last_move = 0
var/area = null
/// Last time we Click()ed. No clicking twice in one tick!
+4 -2
View File
@@ -147,6 +147,8 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
/client/proc/handle_statpanel_click(list/href_list)
var/atom/target = locate(href_list["statpanel_item_target"])
if(!target)
return
Click(target, target.loc, null, "[href_list["statpanel_item_shiftclick"]?"shift=1;":null][href_list["statpanel_item_ctrlclick"]?"ctrl=1;":null]&alt=[href_list["statpanel_item_altclick"]?"alt=1;":null]", FALSE, "statpanel")
/client/proc/is_content_unlocked()
@@ -496,7 +498,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
GLOB.directory -= ckey
log_access("Logout: [key_name(src)]")
GLOB.ahelp_tickets.ClientLogout(src)
// SSserver_maint.UpdateHubStatus()
SSserver_maint.UpdateHubStatus()
if(credits)
QDEL_LIST(credits)
if(holder)
@@ -642,7 +644,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
query_log_connection.Execute()
qdel(query_log_connection)
// SSserver_maint.UpdateHubStatus()
SSserver_maint.UpdateHubStatus()
if(new_player)
player_age = -1
+54 -32
View File
@@ -895,19 +895,23 @@ GLOBAL_LIST_EMPTY(preferences_datums)
continue
var/class_link = ""
var/list/loadout_item = has_loadout_gear(loadout_slot, "[gear.type]")
var/extra_color_data = ""
var/extra_loadout_data = ""
if(loadout_item)
class_link = "style='white-space:normal;' class='linkOn' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(name)];toggle_gear=0'"
if(gear.loadout_flags & LOADOUT_CAN_COLOR_POLYCHROMIC)
extra_color_data += "<BR><a href='?_src_=prefs;preference=gear;loadout_color_polychromic=1;loadout_gear_name=[html_encode(gear.name)];'>Color</a>"
extra_loadout_data += "<BR><a href='?_src_=prefs;preference=gear;loadout_color_polychromic=1;loadout_gear_name=[html_encode(gear.name)];'>Color</a>"
for(var/loadout_color in loadout_item[LOADOUT_COLOR])
extra_color_data += "<span style='border: 1px solid #161616; background-color: [loadout_color];'>&nbsp;&nbsp;&nbsp;</span>"
extra_loadout_data += "<span style='border: 1px solid #161616; background-color: [loadout_color];'>&nbsp;&nbsp;&nbsp;</span>"
else
var/loadout_color_non_poly = "#FFFFFF"
if(length(loadout_item[LOADOUT_COLOR]))
loadout_color_non_poly = loadout_item[LOADOUT_COLOR][1]
extra_color_data += "<BR><a href='?_src_=prefs;preference=gear;loadout_color=1;loadout_gear_name=[html_encode(gear.name)];'>Color</a>"
extra_color_data += "<span style='border: 1px solid #161616; background-color: [loadout_color_non_poly];'>&nbsp;&nbsp;&nbsp;</span>"
extra_loadout_data += "<BR><a href='?_src_=prefs;preference=gear;loadout_color=1;loadout_gear_name=[html_encode(gear.name)];'>Color</a>"
extra_loadout_data += "<span style='border: 1px solid #161616; background-color: [loadout_color_non_poly];'>&nbsp;&nbsp;&nbsp;</span>"
if(gear.loadout_flags & LOADOUT_CAN_NAME)
extra_loadout_data += "<BR><a href='?_src_=prefs;preference=gear;loadout_rename=1;loadout_gear_name=[html_encode(gear.name)];'>Name</a> [loadout_item[LOADOUT_CUSTOM_NAME] ? loadout_item[LOADOUT_CUSTOM_NAME] : "N/A"]"
if(gear.loadout_flags & LOADOUT_CAN_DESCRIPTION)
extra_loadout_data += "<BR><a href='?_src_=prefs;preference=gear;loadout_redescribe=1;loadout_gear_name=[html_encode(gear.name)];'>Description</a>"
else if((gear_points - gear.cost) < 0)
class_link = "style='white-space:normal;' class='linkOff'"
else if(donoritem)
@@ -916,7 +920,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
class_link = "style='white-space:normal;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(name)];toggle_gear=1'"
else
class_link = "style='white-space:normal;background:#eb2e2e;' class='linkOff'"
dat += "<tr style='vertical-align:top;'><td width=15%><a [class_link]>[name]</a>[extra_color_data]</td>"
dat += "<tr style='vertical-align:top;'><td width=15%><a [class_link]>[name]</a>[extra_loadout_data]</td>"
dat += "<td width = 5% style='vertical-align:top'>[gear.cost]</td><td>"
if(islist(gear.restricted_roles))
if(gear.restricted_roles.len)
@@ -929,14 +933,15 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += gear.restricted_roles.Join(";")
dat += "</font>"
if(!istype(gear, /datum/gear/unlockable))
dat += "</td><td><font size=2><i>[gear.description]</i></font></td></tr>"
// the below line essentially means "if the loadout item is picked by the user and has a custom description, give it the custom description, otherwise give it the default description"
dat += "</td><td><font size=2><i>[loadout_item ? (loadout_item[LOADOUT_CUSTOM_DESCRIPTION] ? loadout_item[LOADOUT_CUSTOM_DESCRIPTION] : gear.description) : gear.description]</i></font></td></tr>"
else
//we add the user's progress to the description assuming they have progress
var/datum/gear/unlockable/unlockable = gear
var/progress_made = unlockable_loadout_data[unlockable.progress_key]
if(!progress_made)
progress_made = 0
dat += "</td><td><font size=2><i>[gear.description] Progress: [min(progress_made, unlockable.progress_required)]/[unlockable.progress_required]</i></font></td></tr>"
dat += "</td><td><font size=2><i>[loadout_item ? (loadout_item[LOADOUT_CUSTOM_DESCRIPTION] ? loadout_item[LOADOUT_CUSTOM_DESCRIPTION] : gear.description) : gear.description] Progress: [min(progress_made, unlockable.progress_required)]/[unlockable.progress_required]</i></font></td></tr>"
dat += "</table>"
if(4) // Content preferences
@@ -2700,7 +2705,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
loadout_data["SAVE_[loadout_slot]"] += list(new_loadout_data) //double packed because it does the union of the CONTENTS of the lists
else
loadout_data["SAVE_[loadout_slot]"] = list(new_loadout_data) //double packed because you somehow had no save slot in your loadout?
if(href_list["loadout_color"])
if(href_list["loadout_color"] || href_list["loadout_color_polychromic"] || href_list["loadout_rename"] || href_list["loadout_redescribe"])
//if the gear doesn't exist, or they don't have it, ignore the request
var/name = html_decode(href_list["loadout_gear_name"])
var/datum/gear/G = GLOB.loadout_items[gear_category][gear_subcategory][name]
if(!G)
@@ -2708,29 +2715,44 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/user_gear = has_loadout_gear(loadout_slot, "[G.type]")
if(!user_gear)
return
if(!length(user_gear[LOADOUT_COLOR]))
user_gear[LOADOUT_COLOR] = list("#FFFFFF")
var/current_color = user_gear[LOADOUT_COLOR][1]
var/new_color = input(user, "Polychromic options", "Choose Color", current_color) as color|null
user_gear[LOADOUT_COLOR][1] = sanitize_hexcolor(new_color, 6, TRUE, current_color)
if(href_list["loadout_color_polychromic"])
var/name = html_decode(href_list["loadout_gear_name"])
var/datum/gear/G = GLOB.loadout_items[gear_category][gear_subcategory][name]
if(!G)
return
var/user_gear = has_loadout_gear(loadout_slot, "[G.type]")
if(!user_gear)
return
var/list/color_options = list()
for(var/i=1, i<=length(G.loadout_initial_colors), i++)
color_options += "Color [i]"
var/color_to_change = input(user, "Polychromic options", "Recolor [name]") as null|anything in color_options
if(color_to_change)
var/color_index = text2num(copytext(color_to_change, 7))
var/current_color = user_gear[LOADOUT_COLOR][color_index]
var/new_color = input(user, "Polychromic options", "Choose [color_to_change] Color", current_color) as color|null
if(new_color)
user_gear[LOADOUT_COLOR][color_index] = sanitize_hexcolor(new_color, 6, TRUE, current_color)
//possible requests: recolor, recolor (polychromic), rename, redescribe
//always make sure the gear allows said request before proceeding
//non-poly coloring can only be done by non-poly items
if(href_list["loadout_color"] && !(G.loadout_flags & LOADOUT_CAN_COLOR_POLYCHROMIC))
if(!length(user_gear[LOADOUT_COLOR]))
user_gear[LOADOUT_COLOR] = list("#FFFFFF")
var/current_color = user_gear[LOADOUT_COLOR][1]
var/new_color = input(user, "Polychromic options", "Choose Color", current_color) as color|null
user_gear[LOADOUT_COLOR][1] = sanitize_hexcolor(new_color, 6, TRUE, current_color)
//poly coloring can only be done by poly items
if(href_list["loadout_color_polychromic"] && (G.loadout_flags & LOADOUT_CAN_COLOR_POLYCHROMIC))
var/list/color_options = list()
for(var/i=1, i<=length(G.loadout_initial_colors), i++)
color_options += "Color [i]"
var/color_to_change = input(user, "Polychromic options", "Recolor [name]") as null|anything in color_options
if(color_to_change)
var/color_index = text2num(copytext(color_to_change, 7))
var/current_color = user_gear[LOADOUT_COLOR][color_index]
var/new_color = input(user, "Polychromic options", "Choose [color_to_change] Color", current_color) as color|null
if(new_color)
user_gear[LOADOUT_COLOR][color_index] = sanitize_hexcolor(new_color, 6, TRUE, current_color)
//both renaming and redescribing strip the input to stop html injection
//renaming is only allowed if it has the flag for it
if(href_list["loadout_rename"] && (G.loadout_flags & LOADOUT_CAN_NAME))
var/new_name = stripped_input(user, "Enter new name for item. Maximum [MAX_NAME_LEN] characters.", "Loadout Item Naming", null, MAX_NAME_LEN)
if(new_name)
user_gear[LOADOUT_CUSTOM_NAME] = new_name
//redescribing is only allowed if it has the flag for it
if(href_list["loadout_redescribe"] && (G.loadout_flags & LOADOUT_CAN_DESCRIPTION)) //redescribe isnt a real word but i can't think of the right term to use
var/new_description = stripped_input(user, "Enter new description for item. Maximum 500 characters.", "Loadout Item Redescribing", null, 500)
if(new_description)
user_gear[LOADOUT_CUSTOM_DESCRIPTION] = new_description
ShowChoices(user)
return 1
@@ -36,7 +36,7 @@
/obj/item/clothing/gloves/fingerless/pugilist/equipped(mob/user, slot)
. = ..()
if(current_equipped_slot == SLOT_GLOVES)
if(slot == SLOT_GLOVES)
use_buffs(user, TRUE)
wornonce = TRUE
+20 -3
View File
@@ -17,7 +17,7 @@
/obj/item/clothing/mask/gas/examine(mob/user)
. = ..()
if(flavor_adjust)
. += "<span class='info'>Alt-click to toggle identity concealment. it's currently <b>[flags_inv & HIDEFACE ? "on" : "off"]</b>.</span>"
. += "<span class='info'>Alt-click to toggle identity concealment. It's currently <b>[flags_inv & HIDEFACE ? "on" : "off"]</b>.</span>"
/obj/item/clothing/mask/gas/AltClick(mob/user)
. = ..()
@@ -143,14 +143,17 @@
"Blanc" = image(icon = src.icon, icon_state = "mime"),
"Excité" = image(icon = src.icon, icon_state = "sexymime"),
"Triste" = image(icon = src.icon, icon_state = "sadmime"),
"Effrayé" = image(icon = src.icon, icon_state = "scaredmime")
"Effrayé" = image(icon = src.icon, icon_state = "scaredmime"),
"Timid Woman" = image(icon = src.icon, icon_state = "timidwoman"),
"Timid Man" = image(icon = src.icon, icon_state = "timidman")
)
/obj/item/clothing/mask/gas/mime/ui_action_click(mob/user)
if(!istype(user) || user.incapacitated())
return
var/static/list/options = list("Blanc" = "mime", "Triste" = "sadmime", "Effrayé" = "scaredmime", "Excité" ="sexymime")
var/static/list/options = list("Blanc" = "mime", "Triste" = "sadmime", "Effrayé" = "scaredmime", "Excité" ="sexymime",
"Timid Woman" = "timidwoman", "Timid Man" = "timidman")
var/choice = show_radial_menu(user,src, mimemask_designs, custom_check = FALSE, radius = 36, require_near = TRUE)
@@ -170,6 +173,20 @@
item_state = "sexymime"
actions_types = list()
/obj/item/clothing/mask/gas/timidcostume
name = "timid woman mask"
desc = "Most people who wear these are not really that timid."
clothing_flags = ALLOWINTERNALS
icon_state = "timidwoman"
item_state = "timidwoman"
flags_cover = MASKCOVERSEYES
resistance_flags = FLAMMABLE
/obj/item/clothing/mask/gas/timidcostume/man
name = "timid man mask"
icon_state = "timidman"
item_state = "timidman"
/obj/item/clothing/mask/gas/monkeymask
name = "monkey mask"
desc = "A mask used when acting as a monkey."
@@ -33,6 +33,16 @@
actions_types = list(/datum/action/item_action/adjust)
mutantrace_variation = STYLE_MUZZLE
/obj/item/clothing/mask/surgical/aesthetic
name = "aesthetic sterile mask"
desc = "A sterile mask designed to help prevent the spread of diseases. This one doesn't seem like it does a whole lot, somehow."
flags_inv = HIDEFACE
flags_cover = null
visor_flags_inv = null
visor_flags_cover = null
permeability_coefficient = 1
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
/obj/item/clothing/mask/surgical/attack_self(mob/user)
adjustmask(user)
+7 -1
View File
@@ -237,6 +237,12 @@
icon_state = "choker"
poly_colors = list("#222222")
/obj/item/clothing/neck/necklace/cowbell
name = "cowbell collar"
desc = "Who would wear this? Take this off, you aren't a cow, you're just an awful degenerate."
icon = 'icons/obj/clothing/neck.dmi'
icon_state = "cowbell"
/obj/item/key/collar
name = "Collar Key"
desc = "A key for a tiny lock on a collar or bag."
@@ -289,7 +295,7 @@
//VERY SUPER BADASS NECKERCHIEFS//
//////////////////////////////////
obj/item/clothing/neck/neckerchief
/obj/item/clothing/neck/neckerchief
icon = 'icons/obj/clothing/masks.dmi' //In order to reuse the bandana sprite
w_class = WEIGHT_CLASS_TINY
var/sourceBandanaType
@@ -413,6 +413,22 @@
var/wallcharges = 4
var/newlocobject = null
/obj/item/clothing/shoes/timidcostume
name = "timid woman boots"
desc = "Ready to rock your hips back and forth? These boots have a polychromic finish."
icon_state = "timidwoman"
item_state = "timidwoman"
/obj/item/clothing/shoes/timidcostume/ComponentInitialize()
. = ..()
AddElement(/datum/element/polychromic, list("#0094FF"), 1)
/obj/item/clothing/shoes/timidcostume/man
name = "timid man shoes"
desc = "Ready to go kart racing? These shoes have a polychromic finish."
icon_state = "timidman"
item_state = "timidman"
/obj/item/clothing/shoes/wallwalkers/equipped(mob/user,slot)
. = ..()
if(slot == SLOT_SHOES)
+6 -1
View File
@@ -55,7 +55,7 @@
/obj/item/clothing/suit/toggle/labcoat/virologist
name = "virologist labcoat"
desc = "A suit that protects against minor chemical spills. Offers slightly more protection against biohazards than the standard model. Has a green stripe on the shoulder."
desc = "A suit that protects against minor chemical spills. Has a green stripe on the shoulder."
icon_state = "labcoat_vir"
/obj/item/clothing/suit/toggle/labcoat/science
@@ -63,6 +63,11 @@
desc = "A suit that protects against minor chemical spills. Has a purple stripe on the shoulder."
icon_state = "labcoat_tox"
/obj/item/clothing/suit/toggle/labcoat/roboticist
name = "roboticist labcoat"
desc = "More like an eccentric coat than a labcoat. Helps pass off bloodstains as part of the aesthetic. Comes with red shoulder pads."
icon_state = "labcoat_robo"
// Departmental Jackets
/obj/item/clothing/suit/toggle/labcoat/depjacket
mutantrace_variation = STYLE_DIGITIGRADE|STYLE_NO_ANTHRO_ICON
@@ -1088,6 +1088,36 @@
icon_state = "winterhood_poly"
item_state = "winterhood_poly"
/obj/item/clothing/suit/hooded/wintercoat/timidcostume
name = "timid woman hoodie"
desc = "A snug, tight yet warm outfit with belts wrapped around it. Looks to be made of polychromic materials."
icon_state = "timidwoman"
item_state = "timidwoman"
hoodtype = /obj/item/clothing/head/hooded/winterhood/timidcostume
/obj/item/clothing/suit/hooded/wintercoat/timidcostume/ComponentInitialize()
. = ..()
AddElement(/datum/element/polychromic, list("#EB0C07", "#5E2400", "#CEA100"), 3)
/obj/item/clothing/head/hooded/winterhood/timidcostume
name = "timid woman hood"
desc = "A hood attached to the hoodie."
icon_state = "timidwoman"
item_state = "timidwoman"
/obj/item/clothing/suit/hooded/wintercoat/timidcostume/man
name = "timid man hoodie"
desc = "A snug, tight yet warm outfit a belt wrapped around it. Looks to be made of polychromic materials."
icon_state = "timidman"
item_state = "timidman"
hoodtype = /obj/item/clothing/head/hooded/winterhood/timidcostume/man
/obj/item/clothing/head/hooded/winterhood/timidcostume/man
name = "timid man hood"
icon_state = "timidman"
item_state = "timidman"
/obj/item/clothing/suit/striped_sweater
name = "striped sweater"
desc = "Reminds you of someone, but you just can't put your finger on it..."
+10
View File
@@ -58,6 +58,12 @@
RemoveHood()
/obj/item/clothing/suit/hooded/proc/ToggleHood()
if(!hood)
to_chat(loc, "<span class='warning'>[src] seems to be missing its hood..</span>")
return
if(atom_colours)
hood.atom_colours = atom_colours.Copy()
hood.update_atom_colour()
if(!suittoggled)
if(ishuman(src.loc))
var/mob/living/carbon/human/H = src.loc
@@ -191,7 +197,11 @@
if(!helmettype)
return
if(!helmet)
to_chat(H, "<span class='warning'>[src] seems to be missing its helmet..</span>")
return
if(atom_colours)
helmet.atom_colours = atom_colours.Copy()
helmet.update_atom_colour()
if(!suittoggled)
if(ishuman(src.loc))
if(H.wear_suit != src)
+163 -1
View File
@@ -79,13 +79,175 @@
if(initial(above_suit))
. += "<span class='notice'>\The [src] can be worn above or below your suit. Alt-click to toggle.</span>"
//////////////
//Waistcoats//
//////////////
/obj/item/clothing/accessory/waistcoat
name = "waistcoat"
name = "black waistcoat"
desc = "For some classy, murderous fun."
icon_state = "waistcoat"
item_state = "waistcoat"
minimize_when_attached = FALSE
/obj/item/clothing/accessory/waistcoat/red
name = "red waistcoat"
icon_state = "waistcoat_red"
item_state = "waistcoat_red"
/obj/item/clothing/accessory/waistcoat/grey
name = "grey waistcoat"
icon_state = "waistcoat_grey"
item_state = "waistcoat_grey"
/obj/item/clothing/accessory/waistcoat/brown
name = "red waistcoat"
icon_state = "waistcoat_brown"
item_state = "waistcoat_brown"
/obj/item/clothing/accessory/waistcoat/sweatervest
name = "black sweatervest"
icon_state = "sweatervest"
item_state = "sweatervest"
/obj/item/clothing/accessory/waistcoat/sweatervest/blue
name = "blue sweatervest"
icon_state = "sweatervest_blue"
item_state = "sweatervest_blue"
/obj/item/clothing/accessory/waistcoat/sweatervest/red
name = "red sweatervest"
icon_state = "sweatervest_red"
item_state = "sweatervest_red"
////////////
//Sweaters//
////////////
/obj/item/clothing/accessory/sweater
name = "grey sweater"
desc = "Nicely comfy and warm!"
icon_state = "sweater"
item_state = "sweater"
minimize_when_attached = FALSE
/obj/item/clothing/accessory/sweater/pink
name = "pink sweater"
icon_state = "sweater_pink"
item_state = "sweater_pink"
/obj/item/clothing/accessory/sweater/heart
name = "heart sweater"
icon_state = "sweater_heart"
item_state = "sweater_heart"
/obj/item/clothing/accessory/sweater/blue
name = "blue sweater"
icon_state = "sweater_blue"
item_state = "sweater_blue"
/obj/item/clothing/accessory/sweater/nt
name = "nanotrasen sweater"
icon_state = "sweater_nt"
item_state = "sweater_nt"
/obj/item/clothing/accessory/sweater/mint
name = "mint sweater"
icon_state = "sweater_mint"
item_state = "sweater_mint"
/obj/item/clothing/accessory/sweater/shoulderless
name = "shoulderless sweater"
icon_state = "sweater_shoulderless"
item_state = "sweater_shoulderless"
/obj/item/clothing/accessory/sweater/uglyxmas
name = "ugly xmas sweater"
icon_state = "sweater_uglyxmas"
item_state = "sweater_uglyxmas"
/obj/item/clothing/accessory/sweater/flower
name = "flower sweater"
icon_state = "sweater_flower"
item_state = "sweater_flower"
////////////////
//Suit Jackets//
////////////////
/obj/item/clothing/accessory/suitjacket
name = "tan suit jacket"
desc = "For those times when you have to attend a fancy business meeting without wearing your pants."
icon_state = "jacket_tan"
item_state = "jacket_tan"
minimize_when_attached = FALSE
/obj/item/clothing/accessory/suitjacket/charcoal
name = "charcoal suit jacket"
icon_state = "jacket_charcoal"
item_state = "jacket_charcoal"
/obj/item/clothing/accessory/suitjacket/navy
name = "navy suit jacket"
icon_state = "jacket_navy"
item_state = "jacket_navy"
/obj/item/clothing/accessory/suitjacket/burgundy
name = "burgundy suit jacket"
icon_state = "jacket_burgundy"
item_state = "jacket_burgundy"
/obj/item/clothing/accessory/suitjacket/checkered
name = "checkered suit jacket"
icon_state = "jacket_checkered"
item_state = "jacket_checkered"
///////////////////////
//Tactical Turtlnecks//
///////////////////////
/obj/item/clothing/accessory/turtleneck
name = "black turtleneck"
desc = "Extra cool. Extra fool."
icon_state = "turtleneck"
item_state = "turtleneck"
minimize_when_attached = FALSE
/obj/item/clothing/accessory/turtleneck/red
name = "red turtleneck"
icon_state = "turtleneck_red"
item_state = "turtleneck_red"
/obj/item/clothing/accessory/turtleneck/comfy
name = "comfy turtleneck"
icon_state = "turtleneck_comfy"
item_state = "turtleneck_comfy"
/obj/item/clothing/accessory/turtleneck/tactifool
name = "black sweaterneck"
desc = "Extra fool. Extra cool."
icon_state = "tactifool"
item_state = "tactifool"
/obj/item/clothing/accessory/turtleneck/tactifool/green
name = "green sweaterneck"
icon_state = "tactifool_green"
item_state = "tactifool_green"
/obj/item/clothing/accessory/turtleneck/tactifool/blue
name = "blue sweaterneck"
icon_state = "tactifool_blue"
item_state = "tactifool_blue"
/obj/item/clothing/accessory/turtleneck/tactifool/syndicate
name = "tactifool sweaterneck"
icon_state = "tactifool_syndicate"
item_state = "tactifool_syndicate"
/////////////////
//Miscellaneous//
/////////////////
/obj/item/clothing/accessory/maidapron
name = "maid apron"
desc = "The best part of a maid costume."
+1 -1
View File
@@ -92,7 +92,7 @@
log_admin_private("[key_name(usr)] cancelled event [name].")
SSblackbox.record_feedback("tally", "event_admin_cancelled", 1, typepath)
/datum/round_event_control/proc/runEvent()
/datum/round_event_control/proc/runEvent(random = FALSE)
var/datum/round_event/E = new typepath()
E.current_players = get_active_player_count(alive_check = 1, afk_check = 1, human_check = 1)
E.control = src
+20 -19
View File
@@ -144,22 +144,23 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
if(L && (L.density || prob(10)))
L.ex_act(EXPLODE_HEAVY)
obj/effect/immovablerod/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
if(ishuman(user))
var/mob/living/carbon/human/U = user
if(U.job in list("Research Director"))
playsound(src, 'sound/effects/meteorimpact.ogg', 100, 1)
for(var/mob/M in urange(8, src))
if(!M.stat)
shake_camera(M, 2, 3)
if(wizard)
U.visible_message("<span class='boldwarning'>[src] transforms into [wizard] as [U] suplexes them!</span>", "<span class='warning'>As you grab [src], it suddenly turns into [wizard] as you suplex them!</span>")
to_chat(wizard, "<span class='boldwarning'>You're suddenly jolted out of rod-form as [U] somehow manages to grab you, slamming you into the ground!</span>")
wizard.Stun(60)
wizard.apply_damage(25, BRUTE)
qdel(src)
else
U.visible_message("<span class='boldwarning'>[U] suplexes [src] into the ground!</span>", "<span class='warning'>You suplex [src] into the ground!</span>")
new /obj/structure/festivus/anchored(drop_location())
new /obj/effect/anomaly/flux(drop_location())
qdel(src)
/obj/effect/immovablerod/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!ishuman(user))
return
var/mob/living/carbon/human/U = user
if(U.job in list("Research Director"))
playsound(src, 'sound/effects/meteorimpact.ogg', 100, TRUE)
for(var/mob/M in urange(8, src))
if(!M.stat)
shake_camera(M, 2, 3)
if(wizard)
U.visible_message("<span class='boldwarning'>[src] transforms into [wizard] as [U] suplexes them!</span>", "<span class='warning'>As you grab [src], it suddenly turns into [wizard] as you suplex them!</span>")
to_chat(wizard, "<span class='boldwarning'>You're suddenly jolted out of rod-form as [U] somehow manages to grab you, slamming you into the ground!</span>")
wizard.Stun(60)
wizard.apply_damage(25, BRUTE)
qdel(src)
else
U.visible_message("<span class='boldwarning'>[U] suplexes [src] into the ground!</span>", "<span class='warning'>You suplex [src] into the ground!</span>")
new /obj/structure/festivus/anchored(drop_location())
new /obj/effect/anomaly/flux(drop_location())
qdel(src)
+1
View File
@@ -340,6 +340,7 @@
playsound(src.loc, 'sound/items/welder.ogg', 100, TRUE)
/obj/structure/spacevine/Crossed(atom/movable/AM)
. = ..()
if(!isliving(AM))
return
for(var/datum/spacevine_mutation/SM in mutations)
+9 -9
View File
@@ -25,14 +25,14 @@
var/datum/effect_system/smoke_spread/smoke = new
smoke.set_up(1, spawn_location)
smoke.start()
trader.visible_message("<b>[src]</b> suddenly appears in a puff of smoke!")
trader.visible_message("<b>[trader]</b> suddenly appears in a puff of smoke!")
/datum/round_event/travelling_trader/announce(fake)
priority_announce("A mysterious figure has been detected on sensors at [get_area(spawn_location)]", "Mysterious Figure")
/datum/round_event/travelling_trader/end()
if(trader)
trader.visible_message("The <b>[src]</b> has given up on waiting!")
if(trader) // the /datum/round_event/travelling_trader has given up on waiting!
trader.visible_message("The <b>[trader]</b> has given up on waiting!")
qdel(trader)
//the actual trader mob
@@ -99,7 +99,7 @@
new reward(get_turf(src))
/mob/living/carbon/human/dummy/travelling_trader/Initialize()
..()
. = ..() // return a hint you fuck
add_atom_colour("#570d6b", FIXED_COLOUR_PRIORITY) //make them purple (otherworldly!)
set_light(1, -0.7, "#AAD84B")
ADD_TRAIT(src,TRAIT_PIERCEIMMUNE, "trader_pierce_immune") //don't let people take their blood
@@ -188,18 +188,18 @@
/mob/living/simple_animal/hostile/netherworld/blankbody = 1,
/mob/living/simple_animal/hostile/retaliate/goose = 1)
mob/living/carbon/human/dummy/travelling_trader/animal_hunter/Initialize()
/mob/living/carbon/human/dummy/travelling_trader/animal_hunter/Initialize()
. = ..()
acceptance_speech = pick(list("This lifeform shall make for a great stew, thank you.", "This lifeform shall be of a true use to our cause, thank you.", "The lifeform is adequate. Goodbye.", "This lifeform shall make a great addition to my collection."))
..()
/mob/living/carbon/human/dummy/travelling_trader/animal_hunter/check_item(var/obj/item/supplied_item) //item is likely to be in contents of whats supplied
/mob/living/carbon/human/dummy/travelling_trader/animal_hunter/check_item(obj/item/supplied_item) //item is likely to be in contents of whats supplied
for(var/atom/something in supplied_item.contents)
if(istype(something, requested_item))
qdel(something) //typically things holding mobs release the mob when the container is deleted, so delete the mob first here
return TRUE
return FALSE
/mob/living/carbon/human/dummy/travelling_trader/animal_hunter/give_reward(var/mob/giver) //the reward is actually given in a jar, because releasing it onto the station might be a bad idea
/mob/living/carbon/human/dummy/travelling_trader/animal_hunter/give_reward(mob/giver) //the reward is actually given in a jar, because releasing it onto the station might be a bad idea
var/obj/item/pet_carrier/bluespace/jar = new(get_turf(src))
var/chosen_animal = pickweight(possible_rewards)
var/mob/living/new_animal = new chosen_animal(jar)
@@ -223,6 +223,7 @@ mob/living/carbon/human/dummy/travelling_trader/animal_hunter/Initialize()
/obj/structure/reagent_dispensers/keg/quintuple_sec = 3)
/mob/living/carbon/human/dummy/travelling_trader/bartender/Initialize() //pick a subtype of ethanol that isn't found in the default set of the booze dispensers reagents
. = ..() // RETURN A HINT.
requested_item = pick(subtypesof(/datum/reagent/consumable/ethanol) - list(/datum/reagent/consumable/ethanol/beer,
/datum/reagent/consumable/ethanol/kahlua,
/datum/reagent/consumable/ethanol/whiskey,
@@ -242,7 +243,6 @@ mob/living/carbon/human/dummy/travelling_trader/animal_hunter/Initialize()
/datum/reagent/consumable/ethanol/triple_sec,
/datum/reagent/consumable/ethanol/sake,
/datum/reagent/consumable/ethanol/applejack))
..()
/mob/living/carbon/human/dummy/travelling_trader/bartender/check_item(var/obj/item/supplied_item) //you need to check its reagents
if(istype(supplied_item, /obj/item/reagent_containers))
+8 -6
View File
@@ -16,7 +16,7 @@
if(!F.check_variables() && !override_checks)
QDEL_NULL(F)
if(start_field && (F || override_checks))
F.Initialize()
F.begin_field()
return F
/datum/proximity_monitor/advanced
@@ -78,11 +78,11 @@
/datum/proximity_monitor/advanced/proc/process_edge_turf(turf/T)
/datum/proximity_monitor/advanced/New()
/datum/proximity_monitor/advanced/New(atom/_host, range, _ignore_if_not_on_turf = TRUE)
if(requires_processing)
START_PROCESSING(SSfields, src)
/datum/proximity_monitor/advanced/proc/Initialize()
/datum/proximity_monitor/advanced/proc/begin_field()
setup_field()
post_setup_field()
@@ -154,7 +154,7 @@
var/atom/_host = host
var/atom/new_host_loc = _host.loc
if(last_host_loc != new_host_loc)
recalculate_field()
INVOKE_ASYNC(src, .proc/recalculate_field)
/datum/proximity_monitor/advanced/proc/post_setup_field()
@@ -302,7 +302,7 @@
/obj/item/multitool/field_debug/attack_self(mob/user)
operating = !operating
to_chat(user, "You turn [src] [operating? "on":"off"].")
to_chat(user, "<span class='notice'>You turn [src] [operating? "on":"off"].</span>")
UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
listeningTo = null
if(!istype(current) && operating)
@@ -312,13 +312,15 @@
else if(!operating)
QDEL_NULL(current)
/obj/item/multitool/field_debug/dropped(mob/user)
/obj/item/multitool/field_debug/dropped()
. = ..()
if(listeningTo)
UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
listeningTo = null
/obj/item/multitool/field_debug/proc/on_mob_move()
SIGNAL_HANDLER
check_turf(get_turf(src))
/obj/item/multitool/field_debug/process()
+13 -8
View File
@@ -33,7 +33,7 @@
if(G.summoner && locate(/obj/effect/proc_holder/spell/aoe_turf/timestop) in G.summoner.mind.spell_list) //It would only make sense that a person's stand would also be immune.
immune[G] = TRUE
if(start)
timestop()
INVOKE_ASYNC(src, .proc/timestop)
/obj/effect/timestop/Destroy()
qdel(chronofield)
@@ -42,7 +42,7 @@
/obj/effect/timestop/proc/timestop()
target = get_turf(src)
playsound(src, 'sound/magic/timeparadox2.ogg', 75, 1, -1)
playsound(src, 'sound/magic/timeparadox2.ogg', 75, TRUE, -1)
chronofield = make_field(/datum/proximity_monitor/advanced/timestop, list("current_range" = freezerange, "host" = src, "immune" = immune, "check_anti_magic" = check_anti_magic, "check_holy" = check_holy))
QDEL_IN(src, duration)
@@ -112,6 +112,8 @@
unfreeze_turf(T)
/datum/proximity_monitor/advanced/timestop/proc/unfreeze_atom(atom/movable/A)
SIGNAL_HANDLER
if(A.throwing)
unfreeze_throwing(A)
if(isliving(A))
@@ -128,12 +130,14 @@
frozen_things -= A
global_frozen_atoms -= A
/datum/proximity_monitor/advanced/timestop/proc/freeze_mecha(obj/mecha/M)
M.completely_disabled = TRUE
/datum/proximity_monitor/advanced/timestop/proc/unfreeze_mecha(obj/mecha/M)
M.completely_disabled = FALSE
/datum/proximity_monitor/advanced/timestop/proc/freeze_throwing(atom/movable/AM)
var/datum/thrownthing/T = AM.throwing
T.paused = TRUE
@@ -160,7 +164,7 @@
/datum/proximity_monitor/advanced/timestop/process()
for(var/i in frozen_mobs)
var/mob/living/m = i
m.Stun(20, 1, 1)
m.Stun(20, ignore_canstun = TRUE)
/datum/proximity_monitor/advanced/timestop/setup_field_turf(turf/T)
for(var/i in T.contents)
@@ -168,6 +172,7 @@
freeze_turf(T)
return ..()
/datum/proximity_monitor/advanced/timestop/proc/freeze_projectile(obj/item/projectile/P)
P.paused = TRUE
@@ -176,18 +181,18 @@
/datum/proximity_monitor/advanced/timestop/proc/freeze_mob(mob/living/L)
frozen_mobs += L
L.Stun(20, 1, 1)
L.Stun(20, ignore_canstun = TRUE)
ADD_TRAIT(L, TRAIT_MUTE, TIMESTOP_TRAIT)
walk(L, 0) //stops them mid pathing even if they're stunimmune
if(isanimal(L))
var/mob/living/simple_animal/S = L
S.toggle_ai(AI_OFF)
if(ishostile(L))
var/mob/living/simple_animal/hostile/H = L
H.LoseTarget()
if(ishostile(L))
var/mob/living/simple_animal/hostile/H = L
H.LoseTarget()
/datum/proximity_monitor/advanced/timestop/proc/unfreeze_mob(mob/living/L)
L.AdjustStun(-20, 1, 1)
L.AdjustStun(-20, ignore_canstun = TRUE)
REMOVE_TRAIT(L, TRAIT_MUTE, TIMESTOP_TRAIT)
frozen_mobs -= L
if(isanimal(L))
+4 -2
View File
@@ -24,11 +24,12 @@
desc = "Get off my turf!"
/obj/effect/abstract/proximity_checker/advanced/field_turf/CanPass(atom/movable/AM, turf/target)
. = ..()
if(parent)
return parent.field_turf_canpass(AM, src, target)
return TRUE
/obj/effect/abstract/proximity_checker/advanced/field_turf/Crossed(atom/movable/AM)
. = ..()
if(parent)
return parent.field_turf_crossed(AM, src)
return TRUE
@@ -48,11 +49,12 @@
desc = "Edgy description here."
/obj/effect/abstract/proximity_checker/advanced/field_edge/CanPass(atom/movable/AM, turf/target)
. = ..()
if(parent)
return parent.field_edge_canpass(AM, src, target)
return TRUE
/obj/effect/abstract/proximity_checker/advanced/field_edge/Crossed(atom/movable/AM)
. = ..()
if(parent)
return parent.field_edge_crossed(AM, src)
return TRUE
+3 -1
View File
@@ -139,10 +139,11 @@ GLOBAL_LIST_INIT(hallucination_list, list(
Show()
/obj/effect/hallucination/simple/Moved(atom/OldLoc, Dir)
. = ..()
Show()
/obj/effect/hallucination/simple/Destroy()
if(target && target.client)
if(target?.client)
target.client.images.Remove(current_image)
active = FALSE
return ..()
@@ -1093,6 +1094,7 @@ GLOBAL_LIST_INIT(hallucination_list, list(
target.client.images += image
/obj/effect/hallucination/danger/lava/Crossed(atom/movable/AM)
. = ..()
if(AM == target)
target.adjustStaminaLoss(20)
new /datum/hallucination/fire(target)
@@ -17,10 +17,7 @@
var/isGlass = TRUE //Whether the 'bottle' is made of glass or not so that milk cartons dont shatter when someone gets hit by it
/obj/item/reagent_containers/food/drinks/on_reagent_change(changetype)
if (gulp_size < 5)
gulp_size = 5
else
gulp_size = max(round(reagents.total_volume / 5), 5)
gulp_size = max(round(reagents.total_volume / 5), 5)
/obj/item/reagent_containers/food/drinks/attack(mob/living/M, mob/user, def_zone)
if(!reagents || !reagents.total_volume)
@@ -596,7 +593,7 @@
name = "Buzz Fuzz"
desc = "The sister drink of Shambler's Juice! Uses real honey, making it a sweet tooth's dream drink. The slogan reads ''A Hive of Flavour'', there's also a label about how it is adddicting."
icon_state = "honeysoda_can"
list_reagents = list(/datum/reagent/consumable/buzz_fuzz = 25, /datum/reagent/consumable/honey = 5)
list_reagents = list(/datum/reagent/consumable/buzz_fuzz = 30)
foodtype = SUGAR | JUNKFOOD
/obj/item/reagent_containers/food/drinks/soda_cans/grey_bull
@@ -52,10 +52,7 @@
/obj/item/reagent_containers/food/drinks/drinkingglass/shotglass/on_reagent_change(changetype)
cut_overlays()
if (gulp_size < 15)
gulp_size = 15
else
gulp_size = max(round(reagents.total_volume / 15), 15)
gulp_size = max(round(reagents.total_volume / 15), 15)
if (reagents.reagent_list.len > 0)
var/datum/reagent/largest_reagent = reagents.get_master_reagent()
@@ -308,7 +308,7 @@
tastes = list("cake" = 5, "sweetness" = 1, "clouds" = 1)
foodtype = GRAIN | DAIRY | SUGAR
obj/item/reagent_containers/food/snacks/store/cake/pound_cake
/obj/item/reagent_containers/food/snacks/store/cake/pound_cake
name = "pound cake"
desc = "A condensed cake made for filling people up quickly."
icon_state = "pound_cake"
@@ -151,10 +151,13 @@
to_chat(user, "<span class='warning'>You need more space cleaner!</span>")
return TRUE
if(istype(O, /obj/item/soap))
var/obj/item/soap/P = O
if(istype(O, /obj/item/soap) || istype(O, /obj/item/reagent_containers/rag))
var/cleanspeed = 50
if(istype(O, /obj/item/soap))
var/obj/item/soap/used_soap = O
cleanspeed = used_soap.cleanspeed
user.visible_message("[user] starts to clean \the [src].", "<span class='notice'>You start to clean \the [src]...</span>")
if(do_after(user, P.cleanspeed, target = src))
if(do_after(user, cleanspeed, target = src))
user.visible_message("[user] has cleaned \the [src].", "<span class='notice'>You clean \the [src].</span>")
dirty = 0
update_icon()
@@ -21,7 +21,7 @@
)
result = /obj/item/reagent_containers/food/snacks/donut/chaos
datum/crafting_recipe/food/donut/meat
/datum/crafting_recipe/food/donut/meat
time = 15
name = "Meat donut"
reqs = list(
+16 -19
View File
@@ -50,16 +50,18 @@
var/cached_z
/// I'm busy, don't move.
var/busy = FALSE
var/static/blacklisted_items = typecacheof(list(
/obj/effect,
/obj/belly,
/obj/mafia_game_board,
/obj/docking_port,
/obj/shapeshift_holder,
/obj/screen))
/obj/effect,
/obj/belly,
/obj/mafia_game_board,
/obj/docking_port,
/obj/shapeshift_holder,
/obj/screen
))
/mob/living/simple_animal/jacq/Initialize()
..()
. = ..() //fuck you jacq, return a hint you shit
cached_z = z
poof()
@@ -158,23 +160,18 @@
return FALSE
/mob/living/simple_animal/jacq/proc/gender_check(mob/living/carbon/C)
var/gender = "lamb"
if(C)
if(C.gender == MALE)
gender = "laddie"
if(C.gender == FEMALE)
gender = "lassie"
return gender
. = "lamb"
switch(C)
if(MALE)
. = "laddie"
if(FEMALE)
. = "lassie"
//Ye wee bugger, gerrout of it. Ye've nae tae enjoy reading the code fer mae secrets like.
/mob/living/simple_animal/jacq/proc/chit_chat(mob/living/carbon/C)
//Very important
var/gender = gender_check(C)
if(C)
if(C.gender == MALE)
gender = "laddie"
if(C.gender == FEMALE)
gender = "lassie"
// it physicaly cannot fail*. Why is there a fucking dupe
if(!progression["[C.real_name]"] || !(progression["[C.real_name]"] & JACQ_HELLO))
visible_message("<b>[src]</b> smiles ominously at [C], <span class='spooky'>\"Well halo there [gender]! Ah'm Jacqueline, tae great Pumpqueen, great tae meet ye.\"</span>")
+8 -10
View File
@@ -34,16 +34,14 @@
/obj/item/grown/cotton/attack_self(mob/user)
user.show_message("<span class='notice'>You pull some [cotton_name] out of the [name]!</span>", MSG_VISUAL)
var/seed_modifier = 0
if(seed)
seed_modifier = round(seed.potency / 25)
var/obj/item/stack/cotton = new cotton_type(user.loc, 1 + seed_modifier)
var/old_cotton_amount = cotton.amount
for(var/obj/item/stack/ST in user.loc)
if(ST != cotton && istype(ST, cotton_type) && ST.amount < ST.max_amount)
ST.attackby(cotton, user)
if(cotton.amount > old_cotton_amount)
to_chat(user, "<span class='notice'>You add the newly-formed [cotton_name] to the stack. It now contains [cotton.amount] [cotton_name].</span>")
var/cottonAmt = 1 + round(seed.potency / 25) // cotton inhand we're holding
for(var/obj/item/grown/cotton/ctn in user.loc) // cotton on the floor
if(ctn.type != type)
continue
cottonAmt += 1 + round(ctn.seed.potency / 25)
qdel(ctn)
new cotton_type(user.drop_location(), cottonAmt)
// above code stolen from grass
qdel(src)
//reinforced mutated variant
+33 -2
View File
@@ -92,6 +92,11 @@
return BULLET_ACT_HIT
else if(istype(Proj , /obj/item/projectile/energy/florayield))
return myseed.bullet_act(Proj)
else if(istype(Proj , /obj/item/projectile/energy/florarevolution))
if(myseed)
if(myseed.mutatelist.len > 0)
myseed.instability = (myseed.instability/2)
mutatespecie()
else
return ..()
@@ -384,7 +389,6 @@
/obj/machinery/hydroponics/proc/hardmutate()
mutate(4, 10, 2, 4, 50, 4, 10, 3)
/obj/machinery/hydroponics/proc/mutatespecie() // Mutagent produced a new plant!
if(!myseed || dead)
return
@@ -600,7 +604,34 @@
desc = initial(desc)
weedlevel = 0 //Has a side effect of cleaning up those nasty weeds
update_icon()
else if(istype(O, /obj/item/gun/energy/floragun))
var/obj/item/gun/energy/floragun/flowergun = O
if(flowergun.cell.charge < flowergun.cell.maxcharge)
to_chat(user, "<span class='notice'>[flowergun] must be fully charged to lock in a mutation!</span>")
return
if(!myseed)
to_chat(user, "<span class='warning'>[src] is empty!</span>")
return
if(myseed.endurance <= 20)
to_chat(user, "<span class='warning'>[myseed.plantname] isn't hardy enough to sequence its mutation!</span>")
return
if(!myseed.mutatelist)
to_chat(user, "<span class='warning'>[myseed.plantname] has nothing else to mutate into!</span>")
return
else
var/list/fresh_mut_list = list()
for(var/muties in myseed.mutatelist)
var/obj/item/seeds/another_mut = new muties
fresh_mut_list[another_mut.plantname] = muties
var/locked_mutation = (input(user, "Select a mutation to lock.", "Plant Mutation Locks") as null|anything in sortList(fresh_mut_list))
if(!user.canUseTopic(src, BE_CLOSE) || !locked_mutation)
return
myseed.mutatelist = list(fresh_mut_list[locked_mutation])
myseed.endurance = (myseed.endurance/2)
flowergun.cell.use(flowergun.cell.charge)
flowergun.update_icon()
to_chat(user, "<span class='notice'>[myseed.plantname]'s mutation was set to [locked_mutation], depleting [flowergun]'s cell!</span>")
return
else
return ..()
+2 -2
View File
@@ -24,7 +24,7 @@
var/yield = 3 // Amount of growns created per harvest. If is -1, the plant/shroom/weed is never meant to be harvested.
var/potency = 10 // The 'power' of a plant. Generally effects the amount of reagent in a plant, also used in other ways.
var/growthstages = 6 // Amount of growth sprites the plant has.
var/instability = 5 //Chance that a plant will mutate in each stage of it's life.
var/instability = 5 //Chance that a plant will mutate in each stage of it's life.
var/rarity = 0 // How rare the plant is. Used for giving points to cargo when shipping off to CentCom.
var/list/mutatelist = list() // The type of plants that this plant can mutate into.
var/list/genes = list() // Plant genes are stored here, see plant_genes.dm for more info.
@@ -105,7 +105,7 @@
S.reagents_add = reagents_add.Copy() // Faster than grabbing the list from genes.
return S
obj/item/seeds/proc/is_gene_forbidden(typepath)
/obj/item/seeds/proc/is_gene_forbidden(typepath)
return (typepath in forbiddengenes)
@@ -82,5 +82,5 @@
var/sound/music_played = sound(soundfile)
for(var/i in hearing_mobs)
var/mob/M = i
M.playsound_local(source, null, volume * using_instrument.volume_multiplier, falloff = 5, S = music_played)
M.playsound_local(source, null, volume * using_instrument.volume_multiplier, S = music_played)
// Could do environment and echo later but not for now
@@ -578,6 +578,7 @@
return FALSE
/obj/item/electronic_assembly/Moved(oldLoc, dir)
. = ..()
for(var/I in assembly_components)
var/obj/item/integrated_circuit/IC = I
IC.ext_moved(oldLoc, dir)
@@ -378,7 +378,7 @@ a creative player the means to solve many problems. Circuits are held inside an
// Checks if the target object is reachable. Useful for various manipulators and manipulator-like objects.
/obj/item/integrated_circuit/proc/check_target(atom/target, exclude_contents = FALSE, exclude_components = FALSE, exclude_self = FALSE)
/obj/item/integrated_circuit/proc/check_target(atom/target, exclude_contents = FALSE, exclude_components = FALSE, exclude_self = FALSE, exclude_outside = FALSE)
if(!target)
return FALSE
@@ -394,7 +394,7 @@ a creative player the means to solve many problems. Circuits are held inside an
if(target == assembly.battery)
return FALSE
if(target.Adjacent(acting_object) && isturf(target.loc))
if(!exclude_outside && target.Adjacent(acting_object) && isturf(target.loc))
return TRUE
if(!exclude_contents && (target in acting_object.GetAllContents()))
@@ -292,7 +292,7 @@
activate_pin(2)
// Required for making the connector port script work
obj/item/integrated_circuit/atmospherics/connector/portableConnectorReturnAir()
/obj/item/integrated_circuit/atmospherics/connector/portableConnectorReturnAir()
return air_contents
@@ -186,6 +186,8 @@
AM.forceMove(src)
/obj/item/integrated_circuit/manipulation/grabber/proc/drop(obj/item/AM, turf/T = drop_location())
if(!check_target(AM, FALSE, TRUE, TRUE, TRUE))
return
var/atom/A = get_object()
A.investigate_log("dropped ([AM]) from [src].", INVESTIGATE_CIRCUIT)
AM.forceMove(T)
@@ -137,6 +137,10 @@
//Shooting Code:
A.preparePixelProjectile(target, src)
A.fire()
if(ismob(loc.loc))
installed_gun.shoot_live_shot(loc.loc)
else
installed_gun.shoot_live_shot() //Shitcode, but we don't have much of a choice
log_attack("[assembly] [REF(assembly)] has fired [installed_gun].")
return A
+1 -1
View File
@@ -187,7 +187,7 @@
/datum/job/proc/announce_head(var/mob/living/carbon/human/H, var/channels) //tells the given channel that the given mob is the new department head. See communications.dm for valid channels.
if(H && GLOB.announcement_systems.len)
//timer because these should come after the captain announcement
SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/addtimer, CALLBACK(pick(GLOB.announcement_systems), /obj/machinery/announcement_system/proc/announce, "NEWHEAD", H.real_name, H.job, channels), 1))
SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/_addtimer, CALLBACK(pick(GLOB.announcement_systems), /obj/machinery/announcement_system/proc/announce, "NEWHEAD", H.real_name, H.job, channels), 1))
//If the configuration option is set to require players to be logged as old enough to play certain jobs, then this proc checks that they are, otherwise it just returns 1
/datum/job/proc/player_old_enough(client/C)
+1 -1
View File
@@ -32,7 +32,7 @@
l_pocket = /obj/item/pda/roboticist
ears = /obj/item/radio/headset/headset_sci
uniform = /obj/item/clothing/under/rank/rnd/roboticist
suit = /obj/item/clothing/suit/toggle/labcoat
suit = /obj/item/clothing/suit/toggle/labcoat/roboticist
backpack = /obj/item/storage/backpack/science
satchel = /obj/item/storage/backpack/satchel/tox
@@ -60,3 +60,14 @@
/datum/keybinding/carbon/select_harm_intent/down(client/user)
user.mob?.a_intent_change(INTENT_HARM)
return TRUE
/datum/keybinding/carbon/give
hotkey_keys = list("CtrlG")
name = "Give_Item"
full_name = "Give item"
description = "Give the item you're currently holding"
/datum/keybinding/carbon/give/down(client/user)
var/mob/living/carbon/C = user.mob
C.give()
return TRUE
+5 -5
View File
@@ -135,7 +135,7 @@
var/curr_z = text2num(dmmRegex.group[5])
if(curr_z < z_lower || curr_z > z_upper)
continue
var/curr_x = text2num(dmmRegex.group[3])
var/curr_y = text2num(dmmRegex.group[4])
@@ -171,7 +171,7 @@
if(width > right_width)
for(var/i in 1 to lines)
gridLines[i] = copytext(gridLines[i], 1, key_len * right_width)
// during the actual load we're starting at the top and working our way down
gridSet.ycrd += lines - 1
@@ -300,14 +300,14 @@
//we do this after we load everything in. if we don't; we'll have weird atmos bugs regarding atmos adjacent turfs
T.AfterChange(CHANGETURF_IGNORE_AIR)
if(did_expand)
world.refresh_atmos_grid()
#ifdef TESTING
if(turfsSkipped)
testing("Skipped loading [turfsSkipped] default turfs")
#endif
if(did_expand)
world.refresh_atmos_grid()
return TRUE
/datum/parsed_map/proc/build_cache(no_changeturf, bad_paths=null)
@@ -522,7 +522,7 @@
max_charges = 1
item_flags = NEEDS_PERMIT | NOBLUDGEON
w_class = WEIGHT_CLASS_BULKY
force = 18
force = 15
/obj/item/ammo_casing/magic/hook
name = "hook"
@@ -536,11 +536,11 @@
icon_state = "hook"
icon = 'icons/obj/lavaland/artefacts.dmi'
pass_flags = PASSTABLE
damage = 25
armour_penetration = 100
damage = 15
armour_penetration = 10
knockdown = 5
damage_type = BRUTE
hitsound = 'sound/effects/splat.ogg'
knockdown = 30
var/chain
/obj/item/projectile/hook/fire(setAngle)
@@ -250,6 +250,8 @@
if(points)
if(I)
I.mining_points += points
if(usr.client)
usr.client.increment_progress("miner", points)
points = 0
else
to_chat(usr, "<span class='warning'>No ID detected.</span>")
-19
View File
@@ -20,25 +20,6 @@
data["totalPoints"] = points
return data
/obj/machinery/mineral/ore_redemption/ui_act(action, params)
if(..())
return
switch(action)
if("Claim")
var/mob/M = usr
var/obj/item/card/id/I = M.get_idcard(TRUE)
if(points)
if(I)
I.mining_points += points
if(usr.client)
usr.client.increment_progress("miner", points)
points = 0
else
to_chat(usr, "<span class='warning'>No ID detected.</span>")
else
to_chat(usr, "<span class='warning'>No points to claim.</span>")
return TRUE
/obj/machinery/point_bank/power_change()
..()
update_icon()
+5 -3
View File
@@ -8,6 +8,7 @@ INITIALIZE_IMMEDIATE(/mob/dead)
throwforce = 0
/mob/dead/Initialize()
SHOULD_CALL_PARENT(FALSE)
if(flags_1 & INITIALIZED_1)
stack_trace("Warning: [src]([type]) initialized multiple times!")
flags_1 |= INITIALIZED_1
@@ -68,14 +69,15 @@ INITIALIZE_IMMEDIATE(/mob/dead)
set desc= "Jump to the other server"
if(mob_transforming)
return
var/list/csa = CONFIG_GET(keyed_list/cross_server)
var/list/our_id = CONFIG_GET(string/cross_comms_name)
var/list/csa = CONFIG_GET(keyed_list/cross_server) - our_id
var/pick
switch(csa.len)
if(0)
remove_verb(src, /mob/dead/proc/server_hop)
to_chat(src, "<span class='notice'>Server Hop has been disabled.</span>")
if(1)
pick = csa[0]
pick = csa[1]
else
pick = input(src, "Pick a server to jump to", "Server Hop") as null|anything in csa
@@ -100,7 +102,7 @@ INITIALIZE_IMMEDIATE(/mob/dead)
winset(src, null, "command=.options") //other wise the user never knows if byond is downloading resources
C << link("[addr]?server_hop=[key]")
C << link("[addr]")
/mob/dead/proc/update_z(new_z) // 1+ to register, null to unregister
if (registered_z != new_z)
@@ -341,4 +341,4 @@
/datum/sprite_accessory/insect_fluff/witchwing
name = "Witch Wing"
icon_state = "witchwing"
icon_state = "witchwing"
@@ -1,4 +1,4 @@
datum/sprite_accessory/caps
/datum/sprite_accessory/caps
icon = 'icons/mob/mutant_bodyparts.dmi'
color_src = HAIR
relevant_layers = list(BODY_ADJ_LAYER)
@@ -13,6 +13,10 @@
name = "Bald"
icon_state = "bald"
/datum/sprite_accessory/hair/adhara
name = "Adhara"
icon_state = "hair_adhara"
/datum/sprite_accessory/hair/afro
name = "Afro"
icon_state = "hair_afro"
@@ -29,6 +33,14 @@
name = "Ahoge"
icon_state = "hair_antenna"
/datum/sprite_accessory/hair/amazon
name = "Amazon"
icon_state = "hair_amazon"
/datum/sprite_accessory/hair/anita
name = "Anita"
icon_state = "hair_anita"
/datum/sprite_accessory/hair/balding
name = "Balding Hair"
icon_state = "hair_e"
@@ -61,6 +73,18 @@
name = "Beehive 2"
icon_state = "hair_beehive2"
/datum/sprite_accessory/hair/belenko
name = "Beleneko"
icon_state = "hair_belenko"
/datum/sprite_accessory/hair/belenkotied
name = "Belenko (Tied)"
icon_state = "hair_belenkotied"
/datum/sprite_accessory/hair/belle
name = "Belle"
icon_state = "hair_belle"
/datum/sprite_accessory/hair/bob
name = "Bob Hair"
icon_state = "hair_bob"
@@ -309,6 +333,10 @@
name = "Flow Hair"
icon_state = "hair_f"
/datum/sprite_accessory/hair/fluffy
name = "Fluffy"
icon_state = "hair_fluffy"
/datum/sprite_accessory/hair/fringetail
name = "Fringe Tail"
icon_state = "hair_fringetail"
@@ -365,6 +393,10 @@
name = "Hitop"
icon_state = "hair_hitop"
/datum/sprite_accessory/hair/inkling
name = "Inkling"
icon_state = "hair_inkling"
/datum/sprite_accessory/hair/jade
name = "Jade"
icon_state = "hair_jade"
@@ -373,6 +405,10 @@
name = "Jensen"
icon_state = "hair_jensen"
/datum/sprite_accessory/hair/jessica
name = "Jessica"
icon_state = "hair_jessica"
/datum/sprite_accessory/hair/joestar
name = "Joestar"
icon_state = "hair_joestar"
@@ -389,6 +425,10 @@
name = "Kusanagi"
icon_state = "hair_kusanagi"
/datum/sprite_accessory/hair/kleeia
name = "Kleeia"
icon_state = "hair_kleeia"
/datum/sprite_accessory/hair/long
name = "Long Hair 1"
icon_state = "hair_long"
@@ -445,6 +485,10 @@
name = "Mohawk"
icon_state = "hair_d"
/datum/sprite_accessory/hair/newyou
name = "New You"
icon_state = "hair_newyou"
/datum/sprite_accessory/hair/reversemohawk
name = "Mohawk (Reverse)"
icon_state = "hair_reversemohawk"
@@ -575,6 +619,10 @@
name = "Ponytail (Side) 4"
icon_state = "hair_sidetail4"
/datum/sprite_accessory/hair/sharptail
name = "Ponytail (Sharp)"
icon_state = "hair_sharptail"
/datum/sprite_accessory/hair/spikytail
name = "Ponytail (Spiky)"
icon_state = "hair_spikyponytail"
@@ -679,6 +727,26 @@
name = "Skinhead"
icon_state = "hair_skinhead"
/datum/sprite_accessory/hair/simple
name = "Simple"
icon_state = "hair_simple"
/datum/sprite_accessory/hair/skrellvshort
name = "Skrell Replicant (Very Short)"
icon_state = "hair_skrellvshort"
/datum/sprite_accessory/hair/skrellshort
name = "Skrell Replicant (Short)"
icon_state = "hair_skrellshort"
/datum/sprite_accessory/hair/skrell
name = "Skrell Replicant (Average)"
icon_state = "hair_skrell"
/datum/sprite_accessory/hair/skrelllong
name = "Skrell Replicant (Long)"
icon_state = "hair_skrelllong"
/datum/sprite_accessory/hair/sleaze
name = "Sleaze"
icon_state = "hair_sleaze"
@@ -699,6 +767,10 @@
name = "Spiky 3"
icon_state = "hair_spiky2"
/datum/sprite_accessory/hair/supernova
name = "Supernova"
icon_state = "hair_supernova"
/datum/sprite_accessory/hair/swept
name = "Swept Back Hair"
icon_state = "hair_swept"
@@ -743,6 +815,10 @@
name = "Trimmed (Flat)"
icon_state = "hair_trimflat"
/datum/sprite_accessory/hair/twincurls
name = "Twincurls"
icon_state = "hair_twincurls"
/datum/sprite_accessory/hair/twintails
name = "Twintails"
icon_state = "hair_twintail"
@@ -787,6 +863,10 @@
name = "Very Short Over Eye (Alt)"
icon_state = "hair_veryshortovereyealternate"
/datum/sprite_accessory/hair/vivi
name = "Vivi"
icon_state = "hair_vivi"
/datum/sprite_accessory/hair/volaju
name = "Volaju"
icon_state = "hair_volaju"
@@ -11,6 +11,11 @@
// please make sure they're sorted alphabetically and categorized
/datum/sprite_accessory/underwear/socks/garter
name = "Garter"
icon_state = "garter"
has_color = TRUE
/datum/sprite_accessory/underwear/socks/socks_knee
name = "Knee-high"
icon_state = "socks_knee"
@@ -83,6 +88,10 @@
name = "Pantyhose"
icon_state = "pantyhose"
/datum/sprite_accessory/underwear/socks/pantyhose_ripped
name = "Pantyhose - Ripped"
icon_state = "pantyhose_ripped"
/datum/sprite_accessory/underwear/socks/socks_short
name = "Short"
icon_state = "socks_short"
@@ -757,7 +757,7 @@
icon_state = "husky"
matrixed_sections = MATRIX_RED_GREEN
datum/sprite_accessory/tails/mam_tails/insect
/datum/sprite_accessory/tails/mam_tails/insect
name = "Insect"
icon_state = "insect"
matrixed_sections = MATRIX_RED
@@ -343,6 +343,20 @@
icon_state = "fishnet_body"
gender = FEMALE
/datum/sprite_accessory/underwear/top/shibari
name = "Shibari Ropes"
icon_state = "shibari"
gender = FEMALE
has_color = TRUE
covers_chest = FALSE
/datum/sprite_accessory/underwear/top/shibari_sleeved
name = "Shibari Ropes - sleeves"
icon_state = "shibari_sleeves"
gender = FEMALE
has_color = TRUE
covers_chest = FALSE
/datum/sprite_accessory/underwear/top/swimsuit
name = "Swimsuit Top"
icon_state = "bra_swimming"
+4 -2
View File
@@ -556,7 +556,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
var/list/dest = list() //List of possible destinations (mobs)
var/target = null //Chosen target.
dest += getpois(mobs_only=1) //Fill list, prompt user with list
dest += getpois(mobs_only = TRUE) //Fill list, prompt user with list
target = input("Please, select a player!", "Jump to Mob", null, null) as null|anything in dest
if (!target)//Make sure we actually have a target
@@ -893,7 +893,9 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if (!eye_name)
return
var/mob/mob_eye = creatures[eye_name]
do_observe(creatures[eye_name])
/mob/dead/observer/proc/do_observe(mob/mob_eye)
//Istype so we filter out points of interest that are not mobs
if(client && mob_eye && istype(mob_eye))
client.eye = mob_eye

Some files were not shown because too many files have changed in this diff Show More