['(' [arguments] ')']
/datum/SDQL_parser/proc/call_function(i, list/node, list/arguments)
if(length(tokenl(i)))
var/procname = ""
- if(token(i) == "global" && token(i+1) == ".")
+ if(tokenl(i) == "global" && token(i + 1) == ".") // Global proc.
i += 2
procname = "global."
node += procname + token(i++)
if(token(i) != "(")
parse_error("Expected ( but found '[token(i)]'")
+
else if(token(i + 1) != ")")
- var/list/expression_list_temp = list()
+ var/list/temp_expression_list = list()
do
- i = expression(i + 1, expression_list_temp)
+ i = expression(i + 1, temp_expression_list)
if(token(i) == ",")
- arguments[++arguments.len] = expression_list_temp
- expression_list_temp = list()
+ arguments[++arguments.len] = temp_expression_list
+ temp_expression_list = list()
continue
+
while(token(i) && token(i) != ")")
- arguments[++arguments.len] = expression_list_temp
+
+ arguments[++arguments.len] = temp_expression_list // The code this is copy pasted from won't be executed when it's the last param, this fixes that.
else
i++
else
parse_error("Expected a function but found nothing")
return i + 1
-//select_function: count_function
-/datum/SDQL_parser/proc/select_function(i, list/node)
- parse_error("Sorry, function calls aren't available yet")
- return i
//expression: ( unary_expression | '(' expression ')' | value ) [binary_operator expression]
/datum/SDQL_parser/proc/expression(i, list/node)
+
if(token(i) in unary_operators)
i = unary_expression(i, node)
+
else if(token(i) == "(")
var/list/expr = list()
+
i = expression(i + 1, expr)
+
if(token(i) != ")")
parse_error("Missing ) at end of expression.")
+
else
i++
+
node[++node.len] = expr
+
else
i = value(i, node)
+
if(token(i) in binary_operators)
i = binary_operator(i, node)
i = expression(i, node)
+
else if(token(i) in comparitors)
i = binary_operator(i, node)
+
var/list/rhs = list()
i = expression(i, rhs)
+
node[++node.len] = rhs
+
+
return i
+
//unary_expression: unary_operator ( unary_expression | value | '(' expression ')' )
/datum/SDQL_parser/proc/unary_expression(i, list/node)
+
if(token(i) in unary_operators)
var/list/unary_exp = list()
+
unary_exp += token(i)
i++
+
if(token(i) in unary_operators)
i = unary_expression(i, unary_exp)
+
else if(token(i) == "(")
var/list/expr = list()
+
i = expression(i + 1, expr)
+
if(token(i) != ")")
parse_error("Missing ) at end of expression.")
+
else
i++
+
unary_exp[++unary_exp.len] = expr
+
else
i = value(i, unary_exp)
+
node[++node.len] = unary_exp
+
+
else
parse_error("Expected unary operator but found '[token(i)]'")
+
return i
-//binary_operator: comparitor | '+' | '-' | '/' | '*' | '&' | '|' | '^'
+
+//binary_operator: comparitor | '+' | '-' | '/' | '*' | '&' | '|' | '^' | '%'
/datum/SDQL_parser/proc/binary_operator(i, list/node)
+
if(token(i) in (binary_operators + comparitors))
node += token(i)
+
else
parse_error("Unknown binary operator [token(i)]")
+
return i + 1
-//value: variable | string | number | 'null'
+
+//value: variable | string | number | 'null' | object_type
/datum/SDQL_parser/proc/value(i, list/node)
if(token(i) == "null")
node += "null"
i++
- else if(lowertext(copytext(token(i),1,3)) == "0x" && isnum(hex2num(copytext(token(i),3))))
- node += hex2num(copytext(token(i),3))
+
+ else if(lowertext(copytext(token(i), 1, 3)) == "0x" && isnum(hex2num(copytext(token(i), 3))))
+ node += hex2num(copytext(token(i), 3))
i++
+
else if(isnum(text2num(token(i))))
node += text2num(token(i))
i++
+
else if(copytext(token(i), 1, 2) in list("'", "\""))
i = string(i, node)
+
else if(copytext(token(i), 1, 2) == "\[") // Start a list.
i = array(i, node)
+ else if(copytext(token(i), 1, 2) == "/")
+ i = object_type(i, node)
else
i = variable(i, node)
- return i
-/*EXPLAIN SELECT * WHERE 42 = 6 * 9 OR val = - 5 == 7*/
+ return i
diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm b/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm
index 56faa1f6c4..3056b459d8 100644
--- a/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm
+++ b/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm
@@ -48,6 +48,12 @@
/proc/_image(icon, loc, icon_state, layer, dir)
return image(icon, loc, icon_state, layer, dir)
+/proc/_istype(object, type)
+ return istype(object, type)
+
+/proc/_ispath(path, type)
+ return ispath(path, type)
+
/proc/_length(E)
return length(E)
@@ -178,6 +184,9 @@
/proc/_list_swap(list/L, Index1, Index2)
L.Swap(Index1, Index2)
+/proc/_list_get(list/L, index)
+ return L[index]
+
/proc/_walk(ref, dir, lag)
walk(ref, dir, lag)
@@ -208,4 +217,3 @@
/proc/_step_away(ref, trg, max)
step_away(ref, trg, max)
-
diff --git a/code/modules/admin/verbs/panicbunker.dm b/code/modules/admin/verbs/panicbunker.dm
index fc0cab66c9..ab3aeb4ba5 100644
--- a/code/modules/admin/verbs/panicbunker.dm
+++ b/code/modules/admin/verbs/panicbunker.dm
@@ -13,3 +13,28 @@
if (new_pb && !SSdbcore.Connect())
message_admins("The Database is not connected! Panic bunker will not work until the connection is reestablished.")
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Panic Bunker", "[new_pb ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+
+/client/proc/addbunkerbypass(ckeytobypass as text)
+ set category = "Special Verbs"
+ set name = "Add PB Bypass"
+ set desc = "Allows a given ckey to connect despite the panic bunker for a given round."
+ if(!CONFIG_GET(flag/sql_enabled))
+ to_chat(usr, "The Database is not enabled!")
+ return
+
+ GLOB.bunker_passthrough |= ckey(ckeytobypass)
+ log_admin("[key_name(usr)] has added [ckeytobypass] to the current round's bunker bypass list.")
+ message_admins("[key_name(usr)] has added [ckeytobypass] to the current round's bunker bypass list.")
+
+/client/proc/revokebunkerbypass(ckeytobypass as text)
+ set category = "Special Verbs"
+ set name = "Revoke PB Bypass"
+ set desc = "Revoke's a ckey's permission to bypass the panic bunker for a given round."
+ if(!CONFIG_GET(flag/sql_enabled))
+ to_chat(usr, "The Database is not enabled!")
+ return
+
+ GLOB.bunker_passthrough -= ckey(ckeytobypass)
+ log_admin("[key_name(usr)] has removed [ckeytobypass] from the current round's bunker bypass list.")
+ message_admins("[key_name(usr)] has removed [ckeytobypass] from the current round's bunker bypass list.")
+
diff --git a/code/modules/admin/verbs/playsound.dm b/code/modules/admin/verbs/playsound.dm
index 97cc991523..72da825e0c 100644
--- a/code/modules/admin/verbs/playsound.dm
+++ b/code/modules/admin/verbs/playsound.dm
@@ -4,10 +4,12 @@
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()
@@ -96,13 +98,17 @@
if (data["webpage_url"])
webpage_url = "[title]"
+ var/freq = input(usr, "What frequency would you like the sound to play at?",, 1) as null|num
+ if(!freq)
+ freq = 1
+ pitch = freq
+
var/res = alert(usr, "Show the title of and link to this song to the players?\n[title]",, "No", "Yes", "Cancel")
switch(res)
if("Yes")
to_chat(world, "An admin played: [webpage_url]")
if("Cancel")
return
-
SSblackbox.record_feedback("nested tally", "played_url", 1, list("[ckey]", "[web_sound_input]"))
log_admin("[key_name(src)] played web sound: [web_sound_input]")
message_admins("[key_name(src)] played web sound: [web_sound_input]")
diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm
index b227e6cce1..808c48e002 100644
--- a/code/modules/admin/verbs/randomverbs.dm
+++ b/code/modules/admin/verbs/randomverbs.dm
@@ -845,7 +845,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
if(!check_rights(R_ADMIN))
return
- var/level = input("Select security level to change to","Set Security Level") as null|anything in list("green","blue","red","delta")
+ var/level = input("Select security level to change to","Set Security Level") as null|anything in list("green","blue","amber","red","delta")
if(level)
set_security_level(level)
diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm
index cc3b3a3057..7e0ae3c08c 100644
--- a/code/modules/antagonists/changeling/changeling.dm
+++ b/code/modules/antagonists/changeling/changeling.dm
@@ -34,6 +34,8 @@
var/mimicing = ""
var/canrespec = 0
var/changeling_speak = 0
+ var/loudfactor = 0 //Used for blood tests. At 4, blood tests will succeed. At 10, blood tests will result in an explosion.
+ var/bloodtestwarnings = 0 //Used to track if the ling has been notified that they will pass blood tests.
var/datum/dna/chosen_dna
var/obj/effect/proc_holder/changeling/sting/chosen_sting
var/datum/cellular_emporium/cellular_emporium
@@ -71,8 +73,6 @@
reset_powers()
create_initial_profile()
if(give_objectives)
- if(team_mode)
- forge_team_objectives()
forge_objectives()
remove_clownmut()
. = ..()
@@ -123,6 +123,8 @@
/datum/antagonist/changeling/proc/reset_powers()
if(purchasedpowers)
remove_changeling_powers()
+ loudfactor = 0
+ bloodtestwarnings = 0
//Repurchase free powers.
for(var/path in all_powers)
var/obj/effect/proc_holder/changeling/S = new path()
@@ -174,6 +176,13 @@
geneticpoints -= thepower.dna_cost
purchasedpowers += thepower
thepower.on_purchase(owner.current)
+ loudfactor += thepower.loudness
+ if(loudfactor >= 4 && !bloodtestwarnings)
+ to_chat(owner.current, "Our blood is growing flammable. Our blood will react violently to heat.")
+ bloodtestwarnings = 1
+ if(loudfactor >= 10 && bloodtestwarnings < 2)
+ to_chat(owner.current, "Our blood has grown extremely flammable. Our blood will react explosively to heat.")
+ bloodtestwarnings = 2
/datum/antagonist/changeling/proc/readapt()
if(!ishuman(owner.current))
@@ -182,6 +191,7 @@
if(canrespec)
to_chat(owner.current, "We have removed our evolutions from this form, and are now ready to readapt.")
reset_powers()
+ playsound(get_turf(owner.current), 'sound/effects/lingreadapt.ogg', 75, TRUE, 5, soundenvwet = 0)
canrespec = 0
SSblackbox.record_feedback("tally", "changeling_power_purchase", 1, "Readapt")
return 1
diff --git a/code/modules/antagonists/changeling/changeling_power.dm b/code/modules/antagonists/changeling/changeling_power.dm
index ae255a04f8..c89dc50cec 100644
--- a/code/modules/antagonists/changeling/changeling_power.dm
+++ b/code/modules/antagonists/changeling/changeling_power.dm
@@ -16,6 +16,7 @@
var/req_stat = CONSCIOUS // CONSCIOUS, UNCONSCIOUS or DEAD
var/always_keep = 0 // important for abilities like revive that screw you if you lose them.
var/ignores_fakedeath = FALSE // usable with the FAKEDEATH flag
+ var/loudness = 0 //Determines how much having this ability will affect changeling blood tests. At 4, the blood will react violently and turn to ash, creating a unique message in the process. At 10, the blood will explode when heated.
/obj/effect/proc_holder/changeling/proc/on_purchase(mob/user, is_respec)
diff --git a/code/modules/antagonists/changeling/powers/biodegrade.dm b/code/modules/antagonists/changeling/powers/biodegrade.dm
index 1e8eaed383..d1a2cc3891 100644
--- a/code/modules/antagonists/changeling/powers/biodegrade.dm
+++ b/code/modules/antagonists/changeling/powers/biodegrade.dm
@@ -1,8 +1,9 @@
/obj/effect/proc_holder/changeling/biodegrade
name = "Biodegrade"
desc = "Dissolves restraints or other objects preventing free movement."
- helptext = "This is obvious to nearby people, and can destroy standard restraints and closets."
+ helptext = "This is obvious to nearby people, and can destroy standard restraints and closets. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
chemical_cost = 30 //High cost to prevent spam
+ loudness = 1
dna_cost = 2
req_human = 1
diff --git a/code/modules/antagonists/changeling/powers/digitalcamo.dm b/code/modules/antagonists/changeling/powers/digitalcamo.dm
index 68a1fa4add..e8bad0e215 100644
--- a/code/modules/antagonists/changeling/powers/digitalcamo.dm
+++ b/code/modules/antagonists/changeling/powers/digitalcamo.dm
@@ -1,8 +1,9 @@
/obj/effect/proc_holder/changeling/digitalcamo
name = "Digital Camouflage"
desc = "By evolving the ability to distort our form and proportions, we defeat common algorithms used to detect lifeforms on cameras."
- helptext = "We cannot be tracked by camera or seen by AI units while using this skill. However, humans looking at us will find us... uncanny."
+ helptext = "We cannot be tracked by camera or seen by AI units while using this skill. However, humans looking at us will find us... uncanny. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
dna_cost = 1
+ loudness = 1
//Prevents AIs tracking you but makes you easily detectable to the human-eye.
/obj/effect/proc_holder/changeling/digitalcamo/sting_action(mob/user)
diff --git a/code/modules/antagonists/changeling/powers/headcrab.dm b/code/modules/antagonists/changeling/powers/headcrab.dm
index 70edf1e788..8a932dbd62 100644
--- a/code/modules/antagonists/changeling/powers/headcrab.dm
+++ b/code/modules/antagonists/changeling/powers/headcrab.dm
@@ -1,9 +1,10 @@
/obj/effect/proc_holder/changeling/headcrab
name = "Last Resort"
desc = "We sacrifice our current body in a moment of need, placing us in control of a vessel."
- helptext = "We will be placed in control of a small, fragile creature. We may attack a corpse like this to plant an egg which will slowly mature into a new form for us."
+ helptext = "We will be placed in control of a small, fragile creature. We may attack a corpse like this to plant an egg which will slowly mature into a new form for us. This ability is loud, and might cause our blood to react violently to heat."
chemical_cost = 20
dna_cost = 1
+ loudness = 2
req_human = 1
/obj/effect/proc_holder/changeling/headcrab/sting_action(mob/user)
diff --git a/code/modules/antagonists/changeling/powers/hivemind.dm b/code/modules/antagonists/changeling/powers/hivemind.dm
index c84adc6e8f..86926f51a9 100644
--- a/code/modules/antagonists/changeling/powers/hivemind.dm
+++ b/code/modules/antagonists/changeling/powers/hivemind.dm
@@ -3,7 +3,7 @@
name = "Hivemind Communication"
desc = "We tune our senses to the airwaves to allow us to discreetly communicate and exchange DNA with other changelings."
helptext = "We will be able to talk with other changelings with :g. Exchanged DNA do not count towards absorb objectives."
- dna_cost = 0
+ dna_cost = 1
chemical_cost = -1
/obj/effect/proc_holder/changeling/hivemind_comms/on_purchase(mob/user, is_respec)
@@ -17,6 +17,9 @@
var/obj/effect/proc_holder/changeling/hivemind_download/S2 = new
if(!changeling.has_sting(S2))
changeling.purchasedpowers+=S2
+ var/obj/effect/proc_holder/changeling/linglink/S3 = new
+ if(!changeling.has_sting(S3))
+ changeling.purchasedpowers+=S3
// HIVE MIND UPLOAD/DOWNLOAD DNA
GLOBAL_LIST_EMPTY(hivemind_bank)
diff --git a/code/modules/antagonists/changeling/powers/lesserform.dm b/code/modules/antagonists/changeling/powers/lesserform.dm
index 06824f9bed..24403b406c 100644
--- a/code/modules/antagonists/changeling/powers/lesserform.dm
+++ b/code/modules/antagonists/changeling/powers/lesserform.dm
@@ -1,8 +1,9 @@
/obj/effect/proc_holder/changeling/lesserform
name = "Lesser Form"
- desc = "We debase ourselves and become lesser. We become a monkey."
+ desc = "We debase ourselves and become lesser. We become a monkey. This ability is loud, and might cause our blood to react violently to heat."
chemical_cost = 5
dna_cost = 1
+ loudness = 2
req_human = 1
//Transform into a monkey.
diff --git a/code/modules/antagonists/changeling/powers/linglink.dm b/code/modules/antagonists/changeling/powers/linglink.dm
index cd7c944137..baa02ea7c8 100644
--- a/code/modules/antagonists/changeling/powers/linglink.dm
+++ b/code/modules/antagonists/changeling/powers/linglink.dm
@@ -2,7 +2,7 @@
name = "Hivemind Link"
desc = "Link your victim's mind into the hivemind for personal interrogation."
chemical_cost = 0
- dna_cost = 0
+ dna_cost = -1
req_human = 1
/obj/effect/proc_holder/changeling/linglink/can_sting(mob/living/carbon/user)
diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm
index 6a952d09f8..9e353a1855 100644
--- a/code/modules/antagonists/changeling/powers/mutations.dm
+++ b/code/modules/antagonists/changeling/powers/mutations.dm
@@ -134,9 +134,10 @@
/obj/effect/proc_holder/changeling/weapon/arm_blade
name = "Arm Blade"
desc = "We reform one of our arms into a deadly blade."
- helptext = "We may retract our armblade in the same manner as we form it. Cannot be used while in lesser form."
+ helptext = "We may retract our armblade in the same manner as we form it. Cannot be used while in lesser form. This ability is loud, and might cause our blood to react violently to heat."
chemical_cost = 20
dna_cost = 2
+ loudness = 2
req_human = 1
weapon_type = /obj/item/melee/arm_blade
weapon_name_simple = "blade"
@@ -215,9 +216,11 @@
desc = "We ready a tentacle to grab items or victims with."
helptext = "We can use it once to retrieve a distant item. If used on living creatures, the effect depends on the intent: \
Help will simply drag them closer, Disarm will grab whatever they're holding instead of them, Grab will put the victim in our hold after catching it, \
- and Harm will stun it, and stab it if we're also holding a sharp weapon. Cannot be used while in lesser form."
+ and Harm will stun it, and stab it if we're also holding a sharp weapon. Cannot be used while in lesser form.\
+ This ability is loud, and might cause our blood to react violently to heat."
chemical_cost = 10
dna_cost = 2
+ loudness = 2
req_human = 1
weapon_type = /obj/item/gun/magic/tentacle
weapon_name_simple = "tentacle"
@@ -393,9 +396,10 @@
/obj/effect/proc_holder/changeling/weapon/shield
name = "Organic Shield"
desc = "We reform one of our arms into a hard shield."
- helptext = "Organic tissue cannot resist damage forever; the shield will break after it is hit too much. The more genomes we absorb, the stronger it is. Cannot be used while in lesser form."
+ helptext = "Organic tissue cannot resist damage forever; the shield will break after it is hit too much. The more genomes we absorb, the stronger it is. Cannot be used while in lesser form. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
chemical_cost = 20
dna_cost = 1
+ loudness = 1
req_human = 1
weapon_type = /obj/item/shield/changeling
@@ -445,9 +449,10 @@
/obj/effect/proc_holder/changeling/suit/organic_space_suit
name = "Organic Space Suit"
desc = "We grow an organic suit to protect ourselves from space exposure."
- helptext = "We must constantly repair our form to make it space-proof, reducing chemical production while we are protected. Cannot be used in lesser form."
+ helptext = "We must constantly repair our form to make it space-proof, reducing chemical production while we are protected. Cannot be used in lesser form. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
chemical_cost = 20
dna_cost = 2
+ loudness = 1
req_human = 1
suit_type = /obj/item/clothing/suit/space/changeling
@@ -492,9 +497,10 @@
/obj/effect/proc_holder/changeling/suit/armor
name = "Chitinous Armor"
desc = "We turn our skin into tough chitin to protect us from damage."
- helptext = "Upkeep of the armor requires a low expenditure of chemicals. The armor is strong against brute force, but does not provide much protection from lasers. Cannot be used in lesser form."
+ helptext = "Upkeep of the armor requires a low expenditure of chemicals. The armor is strong against brute force, but does not provide much protection from lasers. Cannot be used in lesser form. This ability is loud, and might cause our blood to react violently to heat."
chemical_cost = 20
dna_cost = 1
+ loudness = 2
req_human = 1
recharge_slowdown = 0.25
diff --git a/code/modules/antagonists/changeling/powers/shriek.dm b/code/modules/antagonists/changeling/powers/shriek.dm
index ca79562081..f77624d072 100644
--- a/code/modules/antagonists/changeling/powers/shriek.dm
+++ b/code/modules/antagonists/changeling/powers/shriek.dm
@@ -1,9 +1,10 @@
/obj/effect/proc_holder/changeling/resonant_shriek
name = "Resonant Shriek"
desc = "Our lungs and vocal cords shift, allowing us to briefly emit a noise that deafens and confuses the weak-minded."
- helptext = "Emits a high-frequency sound that confuses and deafens humans, blows out nearby lights and overloads cyborg sensors."
+ helptext = "Emits a high-frequency sound that confuses and deafens humans, blows out nearby lights and overloads cyborg sensors. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
chemical_cost = 20
dna_cost = 1
+ loudness = 1
req_human = 1
//A flashy ability, good for crowd control and sewing chaos.
@@ -25,13 +26,16 @@
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)
return TRUE
/obj/effect/proc_holder/changeling/dissonant_shriek
name = "Dissonant Shriek"
desc = "We shift our vocal cords to release a high-frequency sound that overloads nearby electronics."
+ helptext = "Emits a high-frequency sound that overloads nearby electronics. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
chemical_cost = 20
dna_cost = 1
+ loudness = 1
//A flashy ability, good for crowd control and sewing chaos.
/obj/effect/proc_holder/changeling/dissonant_shriek/sting_action(mob/user)
@@ -39,4 +43,5 @@
L.on = 1
L.break_light_tube()
empulse(get_turf(user), 2, 5, 1)
+ playsound(get_turf(user), 'sound/effects/lingempscreech.ogg', 75, TRUE, 5, soundenvwet = 0)
return TRUE
diff --git a/code/modules/antagonists/changeling/powers/spiders.dm b/code/modules/antagonists/changeling/powers/spiders.dm
index 685767f601..2bd1bc8a35 100644
--- a/code/modules/antagonists/changeling/powers/spiders.dm
+++ b/code/modules/antagonists/changeling/powers/spiders.dm
@@ -1,9 +1,10 @@
/obj/effect/proc_holder/changeling/spiders
name = "Spread Infestation"
desc = "Our form divides, creating arachnids which will grow into deadly beasts."
- helptext = "The spiders are thoughtless creatures, and may attack their creators when fully grown. Requires at least 3 DNA gained through Absorb, and not through DNA sting."
+ helptext = "The spiders are thoughtless creatures, and may attack their creators when fully grown. Requires at least 3 DNA gained through Absorb, and not through DNA sting. This ability is very loud, and will guarantee that our blood will react violently to heat."
chemical_cost = 45
dna_cost = 1
+ loudness = 4
req_absorbs = 3
//Makes some spiderlings. Good for setting traps and causing general trouble.
diff --git a/code/modules/antagonists/changeling/powers/tiny_prick.dm b/code/modules/antagonists/changeling/powers/tiny_prick.dm
index 9bf4a76454..6c9e0c6599 100644
--- a/code/modules/antagonists/changeling/powers/tiny_prick.dm
+++ b/code/modules/antagonists/changeling/powers/tiny_prick.dm
@@ -64,10 +64,11 @@
/obj/effect/proc_holder/changeling/sting/transformation
name = "Transformation Sting"
desc = "We silently sting a human, injecting a retrovirus that forces them to transform."
- helptext = "The victim will transform much like a changeling would. Does not provide a warning to others. Mutations will not be transferred, and monkeys will become human."
+ helptext = "The victim will transform much like a changeling would. Does not provide a warning to others. Mutations will not be transferred, and monkeys will become human. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
sting_icon = "sting_transform"
chemical_cost = 50
dna_cost = 3
+ loudness = 1
var/datum/changelingprofile/selected_dna = null
/obj/effect/proc_holder/changeling/sting/transformation/Click()
@@ -111,10 +112,11 @@
/obj/effect/proc_holder/changeling/sting/false_armblade
name = "False Armblade Sting"
desc = "We silently sting a human, injecting a retrovirus that mutates their arm to temporarily appear as an armblade."
- helptext = "The victim will form an armblade much like a changeling would, except the armblade is dull and useless."
+ helptext = "The victim will form an armblade much like a changeling would, except the armblade is dull and useless. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
sting_icon = "sting_armblade"
chemical_cost = 20
dna_cost = 1
+ loudness = 1
/obj/item/melee/arm_blade/false
desc = "A grotesque mass of flesh that used to be your arm. Although it looks dangerous at first, you can tell it's actually quite dull and useless."
@@ -183,10 +185,11 @@
/obj/effect/proc_holder/changeling/sting/mute
name = "Mute Sting"
desc = "We silently sting a human, completely silencing them for a short time."
- helptext = "Does not provide a warning to the victim that they have been stung, until they try to speak and cannot."
+ helptext = "Does not provide a warning to the victim that they have been stung, until they try to speak and cannot. This ability is loud, and might cause our blood to react violently to heat."
sting_icon = "sting_mute"
chemical_cost = 20
dna_cost = 2
+ loudness = 2
/obj/effect/proc_holder/changeling/sting/mute/sting_action(mob/user, mob/living/carbon/target)
log_combat(user, target, "stung", "mute sting")
@@ -196,10 +199,11 @@
/obj/effect/proc_holder/changeling/sting/blind
name = "Blind Sting"
desc = "Temporarily blinds the target."
- helptext = "This sting completely blinds a target for a short time."
+ helptext = "This sting completely blinds a target for a short time. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
sting_icon = "sting_blind"
chemical_cost = 25
dna_cost = 1
+ loudness = 1
/obj/effect/proc_holder/changeling/sting/blind/sting_action(mob/user, mob/living/carbon/target)
log_combat(user, target, "stung", "blind sting")
@@ -229,10 +233,11 @@
/obj/effect/proc_holder/changeling/sting/cryo
name = "Cryogenic Sting"
desc = "We silently sting a human with a cocktail of chemicals that freeze them."
- helptext = "Does not provide a warning to the victim, though they will likely realize they are suddenly freezing."
+ helptext = "Does not provide a warning to the victim, though they will likely realize they are suddenly freezing. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
sting_icon = "sting_cryo"
chemical_cost = 15
dna_cost = 2
+ loudness = 1
/obj/effect/proc_holder/changeling/sting/cryo/sting_action(mob/user, mob/target)
log_combat(user, target, "stung", "cryo sting")
diff --git a/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm b/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm
index ad83d5f4d2..530c4c5662 100644
--- a/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm
+++ b/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm
@@ -194,9 +194,12 @@
else
L.visible_message("[L]'s eyes blaze with brilliant light!", \
"Your vision suddenly screams with white-hot light!")
- L.Knockdown(15)
+ L.Knockdown(15, TRUE, FALSE, 15)
L.apply_status_effect(STATUS_EFFECT_KINDLE)
L.flash_act(1, 1)
+ if(issilicon(target))
+ var/mob/living/silicon/S = L
+ S.emp_act(EMP_HEAVY)
if(iscultist(L))
L.adjustFireLoss(15)
..()
diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm
index e78a6e4623..6415d9f91a 100644
--- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm
+++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm
@@ -71,7 +71,7 @@
desc = "Charges your slab with divine energy, allowing you to overwhelm a target with Ratvar's light."
invocations = list("Divinity, show them your light!")
whispered = TRUE
- channel_time = 30
+ channel_time = 20 // I think making kindle channel a third of the time less is a good make up for the fact that it silences people for such a little amount of time.
power_cost = 125
usage_tip = "The light can be used from up to two tiles away. Damage taken will GREATLY REDUCE the stun's duration."
tier = SCRIPTURE_DRIVER
@@ -112,21 +112,21 @@
quickbind_desc = "Applies handcuffs to a struck target."
-//Vanguard: Provides twenty seconds of stun immunity. At the end of the twenty seconds, 25% of all stuns absorbed are applied to the invoker.
+//Vanguard: Provides twenty seconds of greatly increased stamina and stun immunity. At the end of the twenty seconds, 25% of all stuns absorbed are applied to the invoker.
/datum/clockwork_scripture/vanguard
descname = "Self Stun Immunity"
name = "Vanguard"
- desc = "Provides twenty seconds of stun immunity. At the end of the twenty seconds, the invoker is knocked down for the equivalent of 25% of all stuns they absorbed. \
+ desc = "Provides twenty seconds of greatly increased stamina and stun immunity. At the end of the twenty seconds, the invoker is knocked down for the equivalent of 25% of all stuns they absorbed. \
Excessive absorption will cause unconsciousness."
invocations = list("Shield me...", "...from darkness!")
channel_time = 30
- power_cost = 25
+ power_cost = 75
usage_tip = "You cannot reactivate Vanguard while still shielded by it."
tier = SCRIPTURE_DRIVER
primary_component = VANGUARD_COGWHEEL
sort_priority = 6
quickbind = TRUE
- quickbind_desc = "Allows you to temporarily absorb stuns. All stuns absorbed will affect you when disabled."
+ quickbind_desc = "Allows you to temporarily have quickly regenerating stamina and absorb stuns. All stuns absorbed will affect you when disabled."
/datum/clockwork_scripture/vanguard/check_special_requirements()
if(!GLOB.ratvar_awakens && islist(invoker.stun_absorption) && invoker.stun_absorption["vanguard"] && invoker.stun_absorption["vanguard"]["end_time"] > world.time)
diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm
index 5e3c0aa872..c582d0f8f2 100644
--- a/code/modules/antagonists/cult/cult_items.dm
+++ b/code/modules/antagonists/cult/cult_items.dm
@@ -508,7 +508,9 @@
if(SEC_LEVEL_GREEN)
set_coefficient = 2
if(SEC_LEVEL_BLUE)
- set_coefficient = 1
+ set_coefficient = 1.2
+ if(SEC_LEVEL_AMBER)
+ set_coefficient = 0.8
else
set_coefficient = 0.5
var/surplus = timer - (SSshuttle.emergencyCallTime * set_coefficient)
diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm
index 51c8803cee..274273fdcf 100644
--- a/code/modules/antagonists/cult/runes.dm
+++ b/code/modules/antagonists/cult/runes.dm
@@ -185,6 +185,9 @@ structure_check() searches for nearby cultist structures required for the invoca
color = RUNE_COLOR_OFFER
req_cultists = 1
rune_in_use = FALSE
+ var/mob/living/currentconversionman
+ var/conversiontimeout
+ var/conversionresult
/obj/effect/rune/convert/do_invoke_glow()
return
@@ -241,6 +244,21 @@ structure_check() searches for nearby cultist structures required for the invoca
to_chat(M, "Something is shielding [convertee]'s mind!")
log_game("Offer rune failed - convertee had anti-magic")
return 0
+ to_chat(convertee, "Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible, truth. The veil of reality has been ripped away \
+ and something evil takes root.")
+ to_chat(convertee, "Do you wish to embrace the Geometer of Blood? Click here to stop resisting the truth. Or you could choose to continue resisting...")
+ currentconversionman = convertee
+ conversiontimeout = world.time + (10 SECONDS)
+ convertee.Stun(100)
+ conversionresult = FALSE
+ while(world.time < conversiontimeout && convertee && !conversionresult)
+ stoplag(1)
+ currentconversionman = null
+ if(convertee && get_turf(convertee) != get_turf(src))
+ return FALSE
+ if(!conversionresult && convertee)
+ do_sacrifice(convertee, invokers)
+ return FALSE
var/brutedamage = convertee.getBruteLoss()
var/burndamage = convertee.getFireLoss()
if(brutedamage || burndamage)
@@ -252,8 +270,6 @@ structure_check() searches for nearby cultist structures required for the invoca
SSticker.mode.add_cultist(convertee.mind, 1)
new /obj/item/melee/cultblade/dagger(get_turf(src))
convertee.mind.special_role = ROLE_CULTIST
- to_chat(convertee, "Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible, truth. The veil of reality has been ripped away \
- and something evil takes root.")
to_chat(convertee, "Assist your new compatriots in their dark dealings. Your goal is theirs, and theirs is yours. You serve the Geometer above all else. Bring it back.\
")
if(ishuman(convertee))
@@ -313,6 +329,12 @@ structure_check() searches for nearby cultist structures required for the invoca
sacrificial.gib()
return TRUE
+/obj/effect/rune/convert/Topic(href, href_list)
+ if(href_list["signmeup"])
+ if(currentconversionman == usr)
+ conversionresult = TRUE
+ else
+ to_chat(usr, "Your fate has already been set in stone.")
/obj/effect/rune/empower
@@ -442,9 +464,9 @@ structure_check() searches for nearby cultist structures required for the invoca
//Ritual of Dimensional Rending: Calls forth the avatar of Nar'Sie upon the station.
/obj/effect/rune/narsie
cultist_name = "Nar'Sie"
- cultist_desc = "tears apart dimensional barriers, calling forth the Geometer. Requires 9 invokers."
+ cultist_desc = "tears apart dimensional barriers, calling forth the Geometer. Requires 9 invokers, minus one for every 3 sacrifices."
invocation = "TOK-LYR RQA-NAP G'OLT-ULOFT!!"
- req_cultists = 9
+ req_cultists = 1
icon = 'icons/effects/96x96.dmi'
color = RUNE_COLOR_DARKRED
icon_state = "rune_large"
@@ -471,6 +493,10 @@ structure_check() searches for nearby cultist structures required for the invoca
if(!is_station_level(z))
return
var/mob/living/user = invokers[1]
+ if(invokers.len < 9 - (GLOB.sacrificed.len * 0.35))
+ to_chat(user, "You need at least [(9 - (GLOB.sacrificed.len * 0.35)) - invokers.len] more adjacent cultists to use this rune in such a manner.")
+ fail_invoke()
+ return
var/datum/antagonist/cult/user_antag = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives
var/area/place = get_area(src)
diff --git a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm
index e365f09b55..ade5458765 100644
--- a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm
+++ b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm
@@ -588,12 +588,18 @@ This is here to make the tiles around the station mininuke change when it's arme
var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control
if(istype(loneop))
loneop.weight += 1
+ if(loneop.weight % 5 == 0)
+ message_admins("[src] is stationary in [ADMIN_VERBOSEJMP(newturf)]. The weight of Lone Operative is now [loneop.weight].")
+ log_game("[src] is stationary for too long in [loc_name(newturf)], and has increased the weight of the Lone Operative event to [loneop.weight].")
else
lastlocation = newturf
last_disk_move = world.time
var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control
if(istype(loneop) && prob(loneop.weight))
loneop.weight = max(loneop.weight - 1, 0)
+ if(loneop.weight % 5 == 0)
+ message_admins("[src] is on the move (currently in [ADMIN_VERBOSEJMP(newturf)]). The weight of Lone Operative is now [loneop.weight].")
+ log_game("[src] being on the move has reduced the weight of the Lone Operative event to [loneop.weight].")
/obj/item/disk/nuclear/examine(mob/user)
. = ..()
diff --git a/code/modules/antagonists/wizard/wizard.dm b/code/modules/antagonists/wizard/wizard.dm
index 6fac9730f3..e6cae518b6 100644
--- a/code/modules/antagonists/wizard/wizard.dm
+++ b/code/modules/antagonists/wizard/wizard.dm
@@ -60,50 +60,13 @@
owner.current.forceMove(pick(GLOB.wizardstart))
/datum/antagonist/wizard/proc/create_objectives()
- switch(rand(1,100))
- if(1 to 30)
- var/datum/objective/assassinate/kill_objective = new
- kill_objective.owner = owner
- kill_objective.find_target()
- objectives += kill_objective
+ var/datum/objective/new_objective = new("Cause as much creative mayhem as you can aboard the station! The more outlandish your methods of achieving this, the better! Make sure there's a decent amount of crew alive to tell of your tale.")
+ new_objective.owner = owner
+ objectives += new_objective
- if (!(locate(/datum/objective/escape) in owner.objectives))
- var/datum/objective/escape/escape_objective = new
- escape_objective.owner = owner
- objectives += escape_objective
-
- if(31 to 60)
- var/datum/objective/steal/steal_objective = new
- steal_objective.owner = owner
- steal_objective.find_target()
- objectives += steal_objective
-
- if (!(locate(/datum/objective/escape) in owner.objectives))
- var/datum/objective/escape/escape_objective = new
- escape_objective.owner = owner
- objectives += escape_objective
-
- if(61 to 85)
- var/datum/objective/assassinate/kill_objective = new
- kill_objective.owner = owner
- kill_objective.find_target()
- objectives += kill_objective
-
- var/datum/objective/steal/steal_objective = new
- steal_objective.owner = owner
- steal_objective.find_target()
- objectives += steal_objective
-
- if (!(locate(/datum/objective/survive) in owner.objectives))
- var/datum/objective/survive/survive_objective = new
- survive_objective.owner = owner
- objectives += survive_objective
-
- else
- if (!(locate(/datum/objective/hijack) in owner.objectives))
- var/datum/objective/hijack/hijack_objective = new
- hijack_objective.owner = owner
- objectives += hijack_objective
+ var/datum/objective/escape/escape_objective = new
+ escape_objective.owner = owner
+ objectives += escape_objective
for(var/datum/objective/O in objectives)
owner.objectives += O
diff --git a/code/modules/assembly/flash.dm b/code/modules/assembly/flash.dm
index b653c3de7f..ad83ed8c13 100644
--- a/code/modules/assembly/flash.dm
+++ b/code/modules/assembly/flash.dm
@@ -125,7 +125,9 @@
to_chat(M, "[user] blinds you with the flash!")
else
to_chat(M, "You are blinded by [src]!")
- M.Knockdown(rand(80,120))
+ var/toblur = 20 - M.eye_blurry
+ if(toblur > 0)
+ M.blur_eyes(toblur)
else if(user)
visible_message("[user] fails to blind [M] with the flash!")
to_chat(user, "You fail to blind [M] with the flash!")
@@ -141,7 +143,7 @@
if(!try_use_flash(user))
return FALSE
if(iscarbon(M))
- flash_carbon(M, user, 5, 1)
+ flash_carbon(M, user, 20, 1)
return TRUE
else if(issilicon(M))
var/mob/living/silicon/robot/R = M
diff --git a/code/modules/atmospherics/environmental/LINDA_fire.dm b/code/modules/atmospherics/environmental/LINDA_fire.dm
index ebca252167..bf5d8efb13 100644
--- a/code/modules/atmospherics/environmental/LINDA_fire.dm
+++ b/code/modules/atmospherics/environmental/LINDA_fire.dm
@@ -20,8 +20,8 @@
if(active_hotspot)
if(soh)
if((tox > 0.5 || trit > 0.5) && oxy > 0.5)
- if(active_hotspot.temperature < exposed_temperature)
- active_hotspot.temperature = exposed_temperature
+ if(active_hotspot.temperature < exposed_temperature*50)
+ active_hotspot.temperature = exposed_temperature*50
if(active_hotspot.volume < exposed_volume)
active_hotspot.volume = exposed_volume
return 1
@@ -36,7 +36,7 @@
return 0
active_hotspot = new /obj/effect/hotspot(src)
- active_hotspot.temperature = exposed_temperature
+ active_hotspot.temperature = exposed_temperature*50
active_hotspot.volume = exposed_volume*25
active_hotspot.just_spawned = (current_cycle < SSair.times_fired)
@@ -47,6 +47,7 @@
heating.temperature = exposed_temperature
heating.react()
assume_air(heating)
+ air_update_turf()
return igniting
//This is the icon for fire on turfs, also helps for nurturing small fires until they are full tile
diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm
index bcb3752cbf..0a7b76cc79 100644
--- a/code/modules/atmospherics/machinery/airalarm.dm
+++ b/code/modules/atmospherics/machinery/airalarm.dm
@@ -650,7 +650,7 @@
if(0)
add_overlay(AALARM_OVERLAY_GREEN)
overlay_state = AALARM_OVERLAY_GREEN
- light_color = LIGHT_COLOR_BLUEGREEN
+ light_color = LIGHT_COLOR_PALEBLUE
set_light(brightness_on)
if(1)
add_overlay(AALARM_OVERLAY_WARN)
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm b/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
index 6bafba9abc..07ee17a1bd 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
@@ -61,6 +61,8 @@
//Actually transfer the gas
var/datum/gas_mixture/removed = air2.remove(transfer_moles)
+ removed.react(src)
+
update_parents()
return removed
diff --git a/code/modules/awaymissions/mission_code/snowdin.dm b/code/modules/awaymissions/mission_code/snowdin.dm
index 16ecae7a5f..7cb771737e 100644
--- a/code/modules/awaymissions/mission_code/snowdin.dm
+++ b/code/modules/awaymissions/mission_code/snowdin.dm
@@ -10,6 +10,10 @@
name = "Snowdin Tundra Plains"
icon_state = "awaycontent25"
+/area/awaymission/snowdin/outside/vip
+ name = "Snowdin Tundra Plains"
+ icon_state = "awaycontent25"
+
/area/awaymission/snowdin/post
name = "Snowdin Outpost"
icon_state = "awaycontent2"
@@ -116,7 +120,7 @@
name = "Snowdin Main Base"
icon_state = "awaycontent16"
dynamic_lighting = DYNAMIC_LIGHTING_ENABLED
- requires_power = TRUE
+ requires_power = FALSE
/area/awaymission/snowdin/dungeon1
name = "Snowdin Depths"
diff --git a/code/modules/cargo/bounties/engineering.dm b/code/modules/cargo/bounties/engineering.dm
index 8b73ebac4b..eb1764d482 100644
--- a/code/modules/cargo/bounties/engineering.dm
+++ b/code/modules/cargo/bounties/engineering.dm
@@ -24,6 +24,19 @@
description = "Station 49 is looking to kickstart their research program. Ship them a tank full of Tritium."
gas_type = /datum/gas/tritium
+/datum/bounty/item/engineering/pacman
+ name = "P.A.C.M.A.N.-type portable generator"
+ description = "A neighboring station had a problem with their SMES, and now need something to power their communications console. Can you send them a P.AC.M.A.N.?"
+ reward = 3500 //2500 for the cargo one
+ wanted_types = list(/obj/machinery/power/port_gen/pacman)
+
+/datum/bounty/item/engineering/canisters
+ name = "Gas Canisters"
+ description = "After a recent debacle in a nearby sector, 10 gas canisters are needed for containing an experimental aerosol before it kills all the local fauna."
+ reward = 5000
+ required_count = 10 //easy to make
+ wanted_types = list(/obj/machinery/portable_atmospherics/canister)
+
/datum/bounty/item/engineering/energy_ball
name = "Contained Tesla Ball"
description = "Station 24 is being overrun by hordes of angry Mothpeople. They are requesting the ultimate bug zapper."
diff --git a/code/modules/cargo/bounties/medical.dm b/code/modules/cargo/bounties/medical.dm
index d139775969..3129051754 100644
--- a/code/modules/cargo/bounties/medical.dm
+++ b/code/modules/cargo/bounties/medical.dm
@@ -57,3 +57,71 @@
description = "Central Command has run out of heavy duty pipe cleaners. Can you ship over a cat tail to help us out?"
reward = 3000
wanted_types = list(/obj/item/organ/tail/cat)
+
+/datum/bounty/item/medical/blood
+ name = "Generic Blood"
+ description = "Nanotrasen's annual blood drive is back up to full speed, following the garlic incident. Good blood in good volumes accepted for Credit returns."
+ reward = 3500
+ required_count = 600
+ wanted_types = list(/datum/reagent/blood)
+
+/* If anyone wants to try and fix/work, go for it
+/datum/bounty/item/medical/medibot // Mob so this dosn't work yet*
+ name = "Medibot"
+ description = "A sister station is dealing with um problem, they need a medibot to help treat their wounded..."
+ reward = 3000
+ wanted_types = list(/mob/living/simple_animal/bot/medbot)
+
+/datum/bounty/item/medical/bloodl //Dosnt work do to how blood is yet*
+ name = "L-type Blood"
+ description = "After a small scuffle, a few of our lizard employees need another blood transfusion."
+ reward = 4000
+ required_count = 200
+ wanted_types = (L,/datum/reagent/blood)
+ if(istype(L,/datum/reagent/blood))
+ wanted_types += L
+
+/datum/bounty/item/medical/bloodu //Dosnt work do to how blood is yet*
+ name = "U-Type Blood"
+ description = "After dealing with a small revolt in a local penal colony, the colony's anemic CMO needs blood, urgently. With his compromised immune system, only the best blood can be used."
+ reward = 5500 // Rarer blood
+ required_count = 200
+ wanted_types = (U,/datum/reagent/blood)
+ if(istype(U,/datum/reagent/blood))
+ wanted_types += U
+
+*/
+
+/datum/bounty/item/medical/surgery
+ name = "Surgery tool implants"
+ description = "Our medical interns keep dropping their Shambler's Juice while they're performing open heart surgery. One of them even had the audacity to say he only had two hands!"
+ reward = 10000
+ required_count = 3
+ wanted_types = list(/obj/item/organ/cyberimp/arm/surgery)
+
+/datum/bounty/item/medical/chemmaker
+ name = "Portable Chem Dispenser"
+ description = "After a new chemist mixed up some water and a banana, we lost our only chem dispenser. Please send us a replacement and you will be compensated."
+ reward = 7000
+ wanted_types = list(/obj/machinery/chem_dispenser)
+
+/datum/bounty/item/medical/advhealthscaner
+ name = "Advanced Health Analyzer"
+ description = "A ERT Medical unit needs the new 'advanced health analyzer', for a mission at a Station 4. Can you send some?."
+ reward = 4000
+ required_count = 5
+ wanted_types = list(/obj/item/healthanalyzer/advanced)
+
+/datum/bounty/item/medical/wallmounts
+ name = "Defibrillator wall mounts"
+ description = "New Space OSHA regulation state that are new cloning medical wing needs a few 'Easy to access defibrillartors'. Can you send a few before we get a lawsuit?"
+ reward = 5000
+ required_count = 3
+ wanted_types = list(/obj/machinery/defibrillator_mount)
+
+/datum/bounty/item/medical/defibrillator
+ name = "New defibillators"
+ description = "After years of storge are defibrillator units have become more liabilities then we want. Please send us some new ones to replace these old ones."
+ reward = 5000
+ required_count = 5
+ wanted_types = list(/obj/item/defibrillator)
diff --git a/code/modules/cargo/bounties/mining.dm b/code/modules/cargo/bounties/mining.dm
index 1b8b46734f..51d93f83b5 100644
--- a/code/modules/cargo/bounties/mining.dm
+++ b/code/modules/cargo/bounties/mining.dm
@@ -49,3 +49,17 @@
reward = 5000
required_count = 3
wanted_types = list(/obj/item/kitchen/knife/combat/bone)
+
+/datum/bounty/item/mining/basalt
+ name = "Artificial Basalt Tiles"
+ description = "Central Command's Ash Walker exhibit needs to be expanded again, we just need some more basalt flooring."
+ reward = 5000
+ required_count = 60
+ wanted_types = list(/obj/item/stack/tile/basalt)
+
+/datum/bounty/item/mining/fruit
+ name = "Cactus Fruit"
+ description = "Central Command's Ash Walker habitat needs more fauna, send us some local fruit seeds!"
+ reward = 2000
+ required_count = 1
+ wanted_types = list(/obj/item/seeds/lavaland/cactus)
diff --git a/code/modules/cargo/bounties/science.dm b/code/modules/cargo/bounties/science.dm
index 33f334ac47..2ac79f6ee8 100644
--- a/code/modules/cargo/bounties/science.dm
+++ b/code/modules/cargo/bounties/science.dm
@@ -64,3 +64,55 @@
description = "With the price of rechargers on the rise, upper management is interested in purchasing guns that are self-powered. If you ship one, they'll pay."
reward = 10000
wanted_types = list(/obj/item/gun/energy/e_gun/nuclear)
+
+/datum/bounty/item/science/bscells
+ name = "Bluespace Power Cells"
+ description = "Someone in upper management keeps using the excuse that his tablet battery dies when he's in the middle of work. This will be the last time he doesn't have his presentation, I swear to -"
+ reward = 7000
+ required_count = 10 //Easy to make
+ wanted_types = list(/obj/item/stock_parts/cell/bluespace)
+
+/datum/bounty/item/science/t4manip
+ name = "Femto-Manipulators"
+ description = "One of our Chief Engineers has OCD. Can you send us some femto-manipulators so he stops complaining that his ID doesn't fit perfectly in the PDA slot?"
+ reward = 7000
+ required_count = 20 //Easy to make
+ wanted_types = list(/obj/item/stock_parts/manipulator/femto)
+
+/datum/bounty/item/science/t4bins
+ name = "Bluespace Matter Bins"
+ description = "The local Janitorial union has gone on strike. Can you send us some bluespace bins so we don't have to take out our own trash?"
+ reward = 7000
+ required_count = 20 //Easy to make
+ wanted_types = list(/obj/item/stock_parts/matter_bin/bluespace)
+
+/datum/bounty/item/science/t4capacitor
+ name = "Quadratic Capacitor"
+ description = "One of our linguists doesn't understand why they're called Quadratic capacitors. Can you give him a few so he leaves us alone about it?"
+ reward = 7000
+ required_count = 20 //Easy to make
+ wanted_types = list(/obj/item/stock_parts/capacitor/quadratic)
+
+/datum/bounty/item/science/t4triphasic
+ name = "Triphasic Scanning Module"
+ description = "One of our scientists got into the liberty caps and is demanding new scanning modules so he can talk to ghosts. At this point we just want him out of our office."
+ reward = 7000
+ required_count = 20 //Easy to make
+ wanted_types = list(/obj/item/stock_parts/scanning_module/triphasic)
+
+/datum/bounty/item/science/t4microlaser
+ name = "Quad-Ultra Micro-Laser"
+ description = "The cats on Vega 9 are breeding out of control. We need something to corral them into one area so we can saturation bomb it."
+ reward = 7000
+ required_count = 20 //Easy to make
+ wanted_types = list(/obj/item/stock_parts/micro_laser/quadultra)
+
+/datum/bounty/item/science/fakecrystals
+ name = "synthetic bluespace crystals"
+ description = "Don't, uh, tell anyone, but one of our BSA arrays might have had a little... accident. Send us some bluespace crystals so we can recalibrate it before anyone realizes. The whole set uses artificial bluespace crystals, so we need and not any other type of bluespace crystals..."
+ reward = 10000
+ required_count = 5
+ wanted_types = list(/obj/item/stack/ore/bluespace_crystal/artificial)
+ exclude_types = list(/obj/item/stack/ore/bluespace_crystal,
+ /obj/item/stack/sheet/bluespace_crystal,
+ /obj/item/stack/ore/bluespace_crystal/refined)
diff --git a/code/modules/cargo/bounties/security.dm b/code/modules/cargo/bounties/security.dm
index bcf7b89f3a..cae8d10c61 100644
--- a/code/modules/cargo/bounties/security.dm
+++ b/code/modules/cargo/bounties/security.dm
@@ -11,3 +11,44 @@
reward = 2000
required_count = 3
wanted_types = list(/obj/machinery/recharger)
+
+/datum/bounty/item/security/practice
+ name = "Practice Laser Gun"
+ description = "Nanotrasen Military Academy is conducting routine marksmanship exercises. The clown hid all the practice lasers, and we're not using live weapons after last time."
+ reward = 3000
+ required_count = 3
+ wanted_types = list(/obj/item/gun/energy/laser/practice)
+
+/datum/bounty/item/security/flashshield
+ name = "Strobe Shield"
+ description = "One of our Emergency Response Agents thinks there's vampires in a local station. Send him something to help with his fear of the dark and protect him, too."
+ reward = 5000
+ wanted_types = list(/obj/item/assembly/flash/shield)
+
+/datum/bounty/item/security/sechuds
+ name = "Sec HUDs"
+ description = "Nanotrasen military academy has started to train officers how to use Sec HUDs to the fullest affect. Please send spare Sec HUDs so we can teach the men."
+ reward = 3000
+ required_count = 5
+ wanted_types = list(/obj/item/clothing/glasses/hud/security)
+
+/datum/bounty/item/security/techslugs
+ name = "Tech Slugs"
+ description = "Nanotrasen Military Academy is conducting an ammo loading and use lessons, on the new 'Tech Slugs'. Problem is we don't have any, please fix this..."
+ reward = 7500
+ required_count = 15
+ wanted_types = list(/obj/item/ammo_casing/shotgun/techshell)
+
+/datum/bounty/item/security/WT550
+ name = "Spare WT-550 clips"
+ description = "Nanotrasen Military Academy's ammunition is running low, please send in spare ammo for practice."
+ reward = 7500
+ required_count = 5
+ wanted_types = list(/obj/item/ammo_box/magazine/wt550m9)
+
+/datum/bounty/item/security/pins
+ name = "Test range firing pins"
+ description = "Nanotrasen Military Academy just got a new set of guns, sadly they didn't come with any pins. Can you send us some Test range locked firing pins?"
+ reward = 5000
+ required_count = 3
+ wanted_types = list(/obj/item/firing_pin/test_range)
diff --git a/code/modules/cargo/exports/manifest.dm b/code/modules/cargo/exports/manifest.dm
index d59ef1093f..763ca70dfe 100644
--- a/code/modules/cargo/exports/manifest.dm
+++ b/code/modules/cargo/exports/manifest.dm
@@ -76,3 +76,17 @@
/datum/export/manifest_correct_denied/get_cost(obj/O)
var/obj/item/paper/fluff/jobs/cargo/manifest/M = O
return ..() - M.order_cost
+
+// Paper work done correctly
+
+/datum/export/paperwork_correct
+ cost = 50
+ unit_name = "correct paperwork"
+ export_types = list(/obj/item/paper/fluff/jobs/cargo/manifest/paperwork_correct)
+
+// Paper work not done retruned
+
+/datum/export/paperwork_incorrect
+ cost = -500 // Failed to meet NT standers
+ unit_name = "returned incorrect paperwork"
+ export_types = list(/obj/item/paper/fluff/jobs/cargo/manifest/paperwork)
diff --git a/code/modules/cargo/order.dm b/code/modules/cargo/order.dm
index cef8685027..1f0d7d29b3 100644
--- a/code/modules/cargo/order.dm
+++ b/code/modules/cargo/order.dm
@@ -95,3 +95,14 @@
while(--lost >= 0)
qdel(pick(C.contents))
return C
+
+//Paperwork for NT
+/obj/item/paper/fluff/jobs/cargo/manifest/paperwork
+ name = "Incomplete Paperwork"
+ desc = "These should've been filled out four months ago! Unfinished grant papers issued by Nanotrasen's finance department. Complete this page for additional funding."
+ icon = 'icons/obj/bureaucracy.dmi'
+
+/obj/item/paper/fluff/jobs/cargo/manifest/paperwork_correct
+ name = "Finished Paperwork"
+ desc = "A neat stack of filled-out forms, in triplicate and signed. Is there anything more satisfying? Make sure they get stamped."
+ icon = 'icons/obj/bureaucracy.dmi'
diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm
index 1bf41e3d25..a9972ca2d4 100644
--- a/code/modules/cargo/packs.dm
+++ b/code/modules/cargo/packs.dm
@@ -81,10 +81,19 @@
crate_name = "emergency crate"
crate_type = /obj/structure/closet/crate/internals
+/datum/supply_pack/emergency/rcds
+ name = "Emergency RCDs"
+ desc = "Bombs going off on station? SME blown and now you need to fix the hole it left behind? Well this crate has a pare of Rcds to be able to easily fix up any problem you may have!"
+ cost = 1500
+ contains = list(/obj/item/construction/rcd,
+ /obj/item/construction/rcd)
+ crate_name = "emergency rcds"
+ crate_type = /obj/structure/closet/crate/internals
+
/datum/supply_pack/emergency/soft_suit
name = "Emergency Space Suit "
desc = "Is there bombs going off left and right? Is there meteors shooting around the station? Well we have two fragile space suit for emergencys as well as air and masks."
- cost = 1000
+ cost = 1000
contains = list(/obj/item/tank/internals/air,
/obj/item/tank/internals/air,
/obj/item/clothing/mask/gas,
@@ -256,6 +265,26 @@
crate_name = "weed control crate"
crate_type = /obj/structure/closet/crate/secure/hydroponics
+/datum/supply_pack/medical/anitvirus
+ name = "Virus Containment Crate"
+ desc = "Viro let out a death plague Mk II again? Someone didnt wash there hands? Old plagues born anew? Well this crate is for you! Hope you cure it before it brakes out of the station... This crate needs medical access to open and has two bio suits, a box of needles and beakers, five spaceacillin needles, and a medibot."
+ cost = 3000
+ access = ACCESS_MEDICAL
+ contains = list(/mob/living/simple_animal/bot/medbot,
+ /obj/item/clothing/head/bio_hood,
+ /obj/item/clothing/head/bio_hood,
+ /obj/item/clothing/suit/bio_suit,
+ /obj/item/clothing/suit/bio_suit,
+ /obj/item/reagent_containers/syringe/antiviral,
+ /obj/item/reagent_containers/syringe/antiviral,
+ /obj/item/reagent_containers/syringe/antiviral,
+ /obj/item/reagent_containers/syringe/antiviral,
+ /obj/item/reagent_containers/syringe/antiviral,
+ /obj/item/storage/box/syringes,
+ /obj/item/storage/box/beakers)
+ crate_name = "virus containment unit crate"
+ crate_type = /obj/structure/closet/crate/secure/plasma
+
//////////////////////////////////////////////////////////////////////////////
//////////////////////////// Security ////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
@@ -386,6 +415,29 @@
/obj/item/melee/baton/loaded)
crate_name = "stun baton crate"
+/datum/supply_pack/security/russianclothing
+ name = "Russian Surplus Clothing"
+ desc = "An old russian crate full of surplus armor that they used to use! Has two sets of bulletproff armor, a few union suits and some warm hats!"
+ hidden = TRUE
+ contraband = TRUE
+ cost = 5000 // Its basicly sec suits, good boots/gloves
+ contains = list(/obj/item/clothing/suit/security/officer/russian,
+ /obj/item/clothing/suit/security/officer/russian,
+ /obj/item/clothing/shoes/combat,
+ /obj/item/clothing/shoes/combat,
+ /obj/item/clothing/head/ushanka,
+ /obj/item/clothing/head/ushanka,
+ /obj/item/clothing/suit/armor/bulletproof,
+ /obj/item/clothing/suit/armor/bulletproof,
+ /obj/item/clothing/head/helmet/alt,
+ /obj/item/clothing/head/helmet/alt,
+ /obj/item/clothing/gloves/combat,
+ /obj/item/clothing/gloves/combat,
+ /obj/item/clothing/mask/gas,
+ /obj/item/clothing/mask/gas)
+ crate_name = "surplus russian clothing"
+ crate_type = /obj/structure/closet/crate/internals
+
/datum/supply_pack/security/taser
name = "Taser Crate"
desc = "From the depths of stunbased combat, this order rises above, supreme. Contains three hybrid tasers, capable of firing both electrodes and disabling shots. Requires Security access to open."
@@ -570,7 +622,7 @@
/datum/supply_pack/security/armory/wt550
- name = "WT-550 Auto Rifle Crate"
+ name = "WT-550 Semi-Auto Rifle Crate"
desc = "Contains two high-powered, semiautomatic rifles chambered in 4.6x30mm. Requires Armory access to open."
cost = 3500
contains = list(/obj/item/gun/ballistic/automatic/wt550,
@@ -578,8 +630,8 @@
crate_name = "auto rifle crate"
/datum/supply_pack/security/armory/wt550ammo
- name = "WT-550 Auto Rifle Ammo Crate"
- desc = "Contains four 20-round magazines for the WT-550 Auto Rifle. Each magazine is designed to facilitate rapid tactical reloads. Requires Armory access to open."
+ name = "WT-550 Semi-Auto SMG Ammo Crate"
+ desc = "Contains four 20-round magazines for the WT-550 Semi-Auto SMG. Each magazine is designed to facilitate rapid tactical reloads. Requires Armory access to open."
cost = 2500
contains = list(/obj/item/ammo_box/magazine/wt550m9,
/obj/item/ammo_box/magazine/wt550m9,
@@ -587,9 +639,9 @@
/obj/item/ammo_box/magazine/wt550m9)
crate_name = "auto rifle ammo crate"
-/datum/supply_pack/security/armory/wt550ammo_nonlethal // Takes around 11 shots to stun crit someone
- name = "WT-550 Auto Rifle Non-Lethal Ammo Crate"
- desc = "Contains four 20-round magazines for the WT-550 Auto Rifle. Each magazine is designed to facilitate rapid tactical reloads. Requires Armory access to open."
+/datum/supply_pack/security/armory/wt550ammo_nonlethal // Takes around 12 shots to stun crit someone
+ name = "WT-550 Semi-Auto SMG Non-Lethal Ammo Crate"
+ desc = "Contains four 20-round magazines for the WT-550 Semi-Auto SMG. Each magazine is designed to facilitate rapid tactical reloads. Requires Armory access to open."
cost = 1500
contains = list(/obj/item/ammo_box/magazine/wt550m9/wtrubber,
/obj/item/ammo_box/magazine/wt550m9/wtrubber,
@@ -598,8 +650,8 @@
crate_name = "auto rifle ammo crate"
/datum/supply_pack/security/armory/wt550ammo_special
- name = "WT-550 Auto Rifle Special Ammo Crate"
- desc = "Contains 2 20-round Armour Piercing and Incendiary magazines for the WT-550 Auto Rifle. Each magazine is designed to facilitate rapid tactical reloads. Requires Armory access to open."
+ name = "WT-550 Semi-Auto SMG Special Ammo Crate"
+ desc = "Contains 2 20-round Armour Piercing and Incendiary magazines for the WT-550 Semi-Auto SMG. Each magazine is designed to facilitate rapid tactical reloads. Requires Armory access to open."
cost = 4500
contains = list(/obj/item/ammo_box/magazine/wt550m9/wtap,
/obj/item/ammo_box/magazine/wt550m9/wtap,
@@ -666,6 +718,15 @@
/obj/item/clothing/suit/space/hardsuit/engine)
crate_name = "engineering hardsuit"
+/datum/supply_pack/engineering/industrialrcd
+ name = "Industrial RCD"
+ desc = "A industrial RCD in case the station has gone through more then one meteor storm and the CE needs to bring out the somthing a bit more reliable. Dose not contain spare ammo for the industrial RCD or any other RCD modles."
+ cost = 4500
+ access = ACCESS_CE
+ contains = list(/obj/item/construction/rcd/industrial)
+ crate_name = "industrial rcd"
+ crate_type = /obj/structure/closet/crate/secure/engineering
+
/datum/supply_pack/engineering/powergamermitts
name = "Insulated Gloves Crate"
desc = "The backbone of modern society. Barely ever ordered for actual engineering. Contains three insulated gloves."
@@ -1011,6 +1072,28 @@
contains = list(/obj/item/stack/sheet/mineral/wood/fifty)
crate_name = "wood planks crate"
+/datum/supply_pack/materials/rcdammo
+ name = "Spare RDC ammo"
+ desc = "This crate contains sixteen RCD ammo packs, to help with any holes or projects people mite be working on."
+ cost = 3750
+ contains = list(/obj/item/rcd_ammo,
+ /obj/item/rcd_ammo,
+ /obj/item/rcd_ammo,
+ /obj/item/rcd_ammo,
+ /obj/item/rcd_ammo,
+ /obj/item/rcd_ammo,
+ /obj/item/rcd_ammo,
+ /obj/item/rcd_ammo,
+ /obj/item/rcd_ammo,
+ /obj/item/rcd_ammo,
+ /obj/item/rcd_ammo,
+ /obj/item/rcd_ammo,
+ /obj/item/rcd_ammo,
+ /obj/item/rcd_ammo,
+ /obj/item/rcd_ammo,
+ /obj/item/rcd_ammo)
+ crate_name = "rcd ammo"
+
/datum/supply_pack/materials/bz
name = "BZ Canister Crate"
desc = "Contains a canister of BZ. Requires Toxins access to open."
@@ -1153,6 +1236,24 @@
/obj/item/storage/firstaid/regular)
crate_name = "first aid kit crate"
+/datum/supply_pack/medical/iv_drip
+ name = "IV Drip Crate"
+ desc = "Contains a single IV drip stand for intravenous delivery."
+ cost = 700
+ contains = list(/obj/machinery/iv_drip)
+ crate_name = "iv drip crate"
+
+/datum/supply_pack/science/adv_surgery_tools
+ name = "Med-Co Advanced surgery tools"
+ desc = "A full set of Med-Co advanced surgery tools, this crate also comes with a spay of synth flesh as well as a can of . Requires Surgery access to open."
+ cost = 5000
+ access = ACCESS_SURGERY
+ contains = list(/obj/item/storage/belt/medical/surgery_belt_adv,
+ /obj/item/reagent_containers/medspray/synthflesh,
+ /obj/item/reagent_containers/medspray/sterilizine)
+ crate_name = "medco newest surgery tools"
+ crate_type = /obj/structure/closet/crate/medical
+
/datum/supply_pack/medical/medicalhardsuit
name = "Medical Hardsuit"
desc = "Got people being spaced left and right? Hole in the same room as the dead body of Hos or cap? Fear not, now you can buy one medical hardsuit with a mask and air tank to save your fellow crewmembers."
@@ -1162,13 +1263,6 @@
/obj/item/clothing/suit/space/hardsuit/medical)
crate_name = "medical hardsuit"
-/datum/supply_pack/medical/iv_drip
- name = "IV Drip Crate"
- desc = "Contains a single IV drip for administering blood to patients."
- cost = 700
- contains = list(/obj/machinery/iv_drip)
- crate_name = "iv drip crate"
-
/datum/supply_pack/medical/supplies
name = "Medical Supplies Crate"
desc = "Contains seven beakers, syringes, and bodybags. Three morphine bottles, four insulin pills. Two charcoal bottles, epinephrine bottles, antitoxin bottles, and large beakers. Finally, a single roll of medical gauze, as well as a bottle of stimulant pills for long, hard work days. German doctor not included."
@@ -1280,6 +1374,7 @@
crate_type = /obj/structure/closet/crate/secure/plasma
dangerous = TRUE
+
//////////////////////////////////////////////////////////////////////////////
//////////////////////////// Science /////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
@@ -1395,6 +1490,19 @@
/datum/supply_pack/service
group = "Service"
+
+/datum/supply_pack/service/advlighting
+ name = "Advanced Lighting crate"
+ desc = "Thanks to advanced lighting tech we here at the Lamp Factory have be able to produce more lamps and lamp items! This crate has three lamps, a box of lights and a state of the art rapid-light-device!"
+ cost = 2500 //Fair
+ contains = list(/obj/item/construction/rld,
+ /obj/item/flashlight/lamp,
+ /obj/item/flashlight/lamp,
+ /obj/item/flashlight/lamp/green,
+ /obj/item/storage/box/lights/mixed)
+ crate_name = "advanced lighting crate"
+ crate_type = /obj/structure/closet/crate/secure
+
/datum/supply_pack/service/cargo_supples
name = "Cargo Supplies Crate"
desc = "Sold everything that wasn't bolted down? You can get right back to work with this crate containing stamps, an export scanner, destination tagger, hand labeler and some package wrapping."
@@ -1453,6 +1561,20 @@
crate_name = "janitor backpack crate"
crate_type = /obj/structure/closet/crate/secure
+/datum/supply_pack/service/janitor/janpremium
+ name = "Janitor Premium Supplies"
+ desc = "Do to the union for better supplies, we have desided to make a deal for you, In this crate you can get a brand new chem, Drying Angent this stuff is the work of slimes or magic! This crate also contains a rag to test out the Drying Angent magic, three wet floor signs, and some spare bottles of ammonia."
+ cost = 3000
+ access = ACCESS_JANITOR
+ contains = list(/obj/item/caution,
+ /obj/item/caution,
+ /obj/item/caution,
+ /obj/item/reagent_containers/glass/rag,
+ /obj/item/reagent_containers/glass/bottle/ammonia,
+ /obj/item/reagent_containers/glass/bottle/ammonia,
+ /obj/item/reagent_containers/spray/drying_agent)
+ crate_name = "janitor backpack crate"
+
/datum/supply_pack/service/mule
name = "MULEbot Crate"
desc = "Pink-haired Quartermaster not doing her job? Replace her with this tireless worker, today!"
@@ -1602,11 +1724,44 @@
crate_name = "beekeeping starter crate"
crate_type = /obj/structure/closet/crate/hydroponics
+/datum/supply_pack/organic/candy
+ name = "Candy Crate"
+ desc = "For people that have a insatiable sweet tooth! Has ten candies to be eaten up.."
+ cost = 2500
+ var/num_contained = 10 //number of items picked to be contained in a randomised crate
+ contains = list(/obj/item/reagent_containers/food/snacks/candy,
+ /obj/item/reagent_containers/food/snacks/lollipop,
+ /obj/item/reagent_containers/food/snacks/gumball,
+ /obj/item/reagent_containers/food/snacks/chocolateegg,
+ /obj/item/reagent_containers/food/snacks/donut,
+ /obj/item/reagent_containers/food/snacks/cookie,
+ /obj/item/reagent_containers/food/snacks/sugarcookie,
+ /obj/item/reagent_containers/food/snacks/chococornet,
+ /obj/item/reagent_containers/food/snacks/mint,
+ /obj/item/reagent_containers/food/snacks/spiderlollipop,
+ /obj/item/reagent_containers/food/snacks/chococoin,
+ /obj/item/reagent_containers/food/snacks/fudgedice,
+ /obj/item/reagent_containers/food/snacks/chocoorange,
+ /obj/item/reagent_containers/food/snacks/honeybar,
+ /obj/item/reagent_containers/food/snacks/tinychocolate,
+ /obj/item/reagent_containers/food/snacks/spacetwinkie,
+ /obj/item/reagent_containers/food/snacks/syndicake,
+ /obj/item/reagent_containers/food/snacks/cheesiehonkers,
+ /obj/item/reagent_containers/food/snacks/sugarcookie/spookyskull,
+ /obj/item/reagent_containers/food/snacks/sugarcookie/spookycoffin,
+ /obj/item/reagent_containers/food/snacks/candy_corn,
+ /obj/item/reagent_containers/food/snacks/candiedapple,
+ /obj/item/reagent_containers/food/snacks/chocolatebar,
+ /obj/item/reagent_containers/food/snacks/candyheart,
+ /obj/item/storage/fancy/heart_box,
+ /obj/item/storage/fancy/donut_box)
+ crate_name = "candy crate"
+
/datum/supply_pack/organic/cutlery
name = "Kitchen Cutlery Deluxe Set"
desc = "Need to slice and dice away those ''Tomatos'' well we got what you need! From a nice set of knifes, forks, plates, glasses, and a whetstone for when you got some grizzle that is a bit harder to slice then normal."
cost = 10000
- contraband = TRUE
+ contraband = TRUE
contains = list(/obj/item/sharpener,
/obj/item/kitchen/fork,
/obj/item/kitchen/fork,
@@ -1663,6 +1818,22 @@
access = ACCESS_THEATRE
crate_type = /obj/structure/closet/crate/secure
+/datum/supply_pack/organic/hunting
+ name = "Huntting gear"
+ desc = "Even in space, we can fine prey to hunt, this crate contains everthing a fine hunter needs to have a sporting time. This crate needs armory access to open. A true huntter only needs a fine bottle of cognac, a nice coat, some good o' cigars, and of cource a huntting shotgun. "
+ cost = 3500
+ contraband = TRUE
+ contains = list(/obj/item/clothing/head/flatcap,
+ /obj/item/clothing/suit/hooded/wintercoat/captain,
+ /obj/item/reagent_containers/food/drinks/bottle/cognac,
+ /obj/item/storage/fancy/cigarettes/cigars/havana,
+ /obj/item/clothing/gloves/color/white,
+ /obj/item/clothing/under/rank/curator,
+ /obj/item/gun/ballistic/shotgun/lethal)
+ access = ACCESS_ARMORY
+ crate_name = "sporting crate"
+ crate_type = /obj/structure/closet/crate/secure // Would have liked a wooden crate but access >:(
+
/datum/supply_pack/organic/hydroponics
name = "Hydroponics Crate"
desc = "Supplies for growing a great garden! Contains two bottles of ammonia, two Plant-B-Gone spray bottles, a hatchet, cultivator, plant analyzer, as well as a pair of leather gloves and a botanist's apron."
@@ -1754,6 +1925,27 @@
crate_name = "seeds crate"
crate_type = /obj/structure/closet/crate/hydroponics
+/datum/supply_pack/organic/vday
+ name = "Surplus Valentine Crate"
+ desc = "Turns out we got warehouses of this love-y dove-y crap. Were sending out small barged buddle of Valentine gear. This crate has two boxes of chocolate, three poppy flowers, five candy hearts, and three cards."
+ cost = 3000
+ contraband = TRUE
+ contains = list(/obj/item/storage/fancy/heart_box,
+ /obj/item/storage/fancy/heart_box,
+ /obj/item/reagent_containers/food/snacks/grown/poppy,
+ /obj/item/reagent_containers/food/snacks/grown/poppy,
+ /obj/item/reagent_containers/food/snacks/grown/poppy,
+ /obj/item/reagent_containers/food/snacks/candyheart,
+ /obj/item/reagent_containers/food/snacks/candyheart,
+ /obj/item/reagent_containers/food/snacks/candyheart,
+ /obj/item/reagent_containers/food/snacks/candyheart,
+ /obj/item/reagent_containers/food/snacks/candyheart,
+ /obj/item/valentine,
+ /obj/item/valentine,
+ /obj/item/valentine)
+ crate_name = "valentine crate"
+ crate_type = /obj/structure/closet/crate/secure
+
/datum/supply_pack/organic/exoticseeds
name = "Exotic Seeds Crate"
desc = "Any entrepreneuring botanist's dream. Contains twelve different seeds, including three replica-pod seeds and two mystery seeds!"
@@ -2106,8 +2298,7 @@
/datum/supply_pack/costumes_toys/randomised/toys
name = "Toy Crate"
desc = "Who cares about pride and accomplishment? Skip the gaming and get straight to the sweet rewards with this product! Contains five random toys. Warranty void if used to prank research directors."
- cost = 5000 // or play the arcade machines ya lazy bum
- // TODID make this actually just use the arcade machine loot list
+ cost = 1500 // or play the arcade machines ya lazy bum
num_contained = 5
contains = list(/obj/item/storage/box/snappops,
/obj/item/toy/talking/AI,
@@ -2161,6 +2352,19 @@
crate_name = "toy crate"
crate_type = /obj/structure/closet/crate/wooden
+/datum/supply_pack/costumes_toys/randomised/plush
+ name = "Plush Crate"
+ desc = "Plush tide station wide. Contains 5 random plushies for you to love. Warranty void if your love violates the terms of use."
+ cost = 1500 // or play the arcade machines ya lazy bum
+ num_contained = 5
+ contains = list(/obj/item/toy/plush/random,
+ /obj/item/toy/plush/random,
+ /obj/item/toy/plush/random,
+ /obj/item/toy/plush/random,
+ /obj/item/toy/plush/random) //I'm lazy
+ crate_name = "plushie crate"
+ crate_type = /obj/structure/closet/crate/wooden
+
/datum/supply_pack/costumes_toys/wizard
name = "Wizard Costume Crate"
desc = "Pretend to join the Wizard Federation with this full wizard outfit! Nanotrasen would like to remind its employees that actually joining the Wizard Federation is subject to termination of job and life."
@@ -2404,7 +2608,7 @@
crate_type = /obj/structure/closet/crate
/datum/supply_pack/misc/lewdkeg
- name = "Lewd Deluxe Keg"
+ name = "Lewd Deluxe Keg"
desc = "That other stuff not getting you ready? Well I have a Chemslut making tons of the good stuff."
cost = 7000 //It can be a weapon
contraband = TRUE
@@ -2412,6 +2616,27 @@
crate_name = "deluxe keg"
crate_type = /obj/structure/closet/crate
+/datum/supply_pack/misc/paper_work
+ name = "Freelance Paper work"
+ desc = "The Nanotrasen Primary Bureaucratic Database Intelligence (PDBI) reports that the station has not completed its funding and grant paperwork this solar cycle. In order to gain further funding, your station is required to fill out (10) ten of these forms or no additional capital will be disbursed. We have sent you ten copies of the following form and we expect every one to be up to Nanotrasen Standards." // Disbursement. It's not a typo, look it up.
+ cost = 400 // Net of 0 credits
+ contains = list(/obj/item/paper/fluff/jobs/cargo/manifest/paperwork,
+ /obj/item/paper/fluff/jobs/cargo/manifest/paperwork,
+ /obj/item/paper/fluff/jobs/cargo/manifest/paperwork,
+ /obj/item/paper/fluff/jobs/cargo/manifest/paperwork,
+ /obj/item/paper/fluff/jobs/cargo/manifest/paperwork,
+ /obj/item/paper/fluff/jobs/cargo/manifest/paperwork,
+ /obj/item/paper/fluff/jobs/cargo/manifest/paperwork,
+ /obj/item/paper/fluff/jobs/cargo/manifest/paperwork,
+ /obj/item/paper/fluff/jobs/cargo/manifest/paperwork,
+ /obj/item/paper/fluff/jobs/cargo/manifest/paperwork,
+ /obj/item/pen/fountain,
+ /obj/item/pen/fountain,
+ /obj/item/pen/fountain,
+ /obj/item/pen/fountain,
+ /obj/item/pen/fountain)
+ crate_name = "Paperwork"
+
/datum/supply_pack/misc/toner
name = "Toner Crate"
desc = "Spent too much ink printing butt pictures? Fret not, with these six toner refills, you'll be printing butts 'till the cows come home!'"
diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm
index c85eb95b05..7216b73af6 100644
--- a/code/modules/client/client_defines.dm
+++ b/code/modules/client/client_defines.dm
@@ -72,4 +72,6 @@
var/list/credits //lazy list of all credit object bound to this client
- var/datum/player_details/player_details //these persist between logins/logouts during the same round.
\ No newline at end of file
+ var/datum/player_details/player_details //these persist between logins/logouts during the same round.
+
+ var/list/char_render_holders //Should only be a key-value list of north/south/east/west = obj/screen.
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index 85d1b4f150..06f23574e1 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -454,6 +454,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
GLOB.ahelp_tickets.ClientLogout(src)
GLOB.directory -= ckey
GLOB.clients -= src
+ QDEL_LIST_ASSOC_VAL(char_render_holders)
if(movingmob != null)
movingmob.client_mobs_in_contents -= mob
UNSETEMPTY(movingmob.client_mobs_in_contents)
@@ -498,7 +499,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
qdel(query_client_in_db)
return
if(!query_client_in_db.NextRow())
- if (CONFIG_GET(flag/panic_bunker) && !holder && !GLOB.deadmins[ckey])
+ if (CONFIG_GET(flag/panic_bunker) && !holder && !GLOB.deadmins[ckey] && !(ckey in GLOB.bunker_passthrough))
log_access("Failed Login: [key] - New account attempting to connect during panic bunker")
message_admins("Failed Login: [key] - New account attempting to connect during panic bunker")
to_chat(src, "You must first join the Discord to verify your account before joining this server.
To do so, read the rules and post a request in the #station-access-requests channel under the \"Main server\" category in the Discord server linked here: https://discord.gg/E6SQuhz") //CIT CHANGE - makes the panic bunker disconnect message point to the discord
@@ -877,3 +878,23 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
/client/proc/AnnouncePR(announcement)
if(prefs && prefs.chat_toggles & CHAT_PULLR)
to_chat(src, announcement)
+
+/client/proc/show_character_previews(mutable_appearance/MA)
+ var/pos = 0
+ for(var/D in GLOB.cardinals)
+ pos++
+ var/obj/screen/O = LAZYACCESS(char_render_holders, "[D]")
+ if(!O)
+ O = new
+ LAZYSET(char_render_holders, "[D]", O)
+ screen |= O
+ O.appearance = MA
+ O.dir = D
+ O.screen_loc = "character_preview_map:0,[pos]"
+
+/client/proc/clear_character_previews()
+ for(var/index in char_render_holders)
+ var/obj/screen/S = char_render_holders[index]
+ screen -= S
+ qdel(S)
+ char_render_holders = null
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 53a8d84af2..f245dd330e 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -1,2119 +1,2212 @@
- /* CAUTION! CAUTION! CAUTION! CAUTION! CAUTION! *\
- | THIS FILE CONTAINS HOOKS FOR FOR |
- | CHANGES SPECIFIC TO CITADEL. IF |
- | YOU'RE FIXING A MERGE CONFLICT |
- | HERE, PLEASE ASK FOR REVIEW FROM |
- | ANOTHER MAINTAINER TO ENSURE YOU |
- | DON'T INTRODUCE REGRESSIONS. |
- \* */
-
-GLOBAL_LIST_EMPTY(preferences_datums)
-
-/datum/preferences
- var/client/parent
- //doohickeys for savefiles
- var/path
- var/default_slot = 1 //Holder so it doesn't default to slot 1, rather the last one used
- var/max_save_slots = 8
-
- //non-preference stuff
- var/muted = 0
- var/last_ip
- var/last_id
-
- //game-preferences
- var/lastchangelog = "" //Saved changlog filesize to detect if there was a change
- var/ooccolor = null
- var/enable_tips = TRUE
- var/tip_delay = 500 //tip delay in milliseconds
-
- //Antag preferences
- var/list/be_special = list() //Special role selection
- var/tmp/old_be_special = 0 //Bitflag version of be_special, used to update old savefiles and nothing more
- //If it's 0, that's good, if it's anything but 0, the owner of this prefs file's antag choices were,
- //autocorrected this round, not that you'd need to check that.
-
-
- var/UI_style = null
- var/buttons_locked = FALSE
- var/hotkeys = FALSE
- var/tgui_fancy = TRUE
- var/tgui_lock = TRUE
- var/windowflashing = TRUE
- var/toggles = TOGGLES_DEFAULT
- var/db_flags
- var/chat_toggles = TOGGLES_DEFAULT_CHAT
- var/ghost_form = "ghost"
- var/ghost_orbit = GHOST_ORBIT_CIRCLE
- var/ghost_accs = GHOST_ACCS_DEFAULT_OPTION
- var/ghost_others = GHOST_OTHERS_DEFAULT_OPTION
- var/ghost_hud = 1
- var/inquisitive_ghost = 1
- var/allow_midround_antag = 1
- var/preferred_map = null
- var/pda_style = MONO
- var/pda_color = "#808000"
-
- var/uses_glasses_colour = 0
-
- //character preferences
- var/real_name //our character's name
- var/be_random_name = 0 //whether we'll have a random name every round
- var/be_random_body = 0 //whether we'll have a random body every round
- var/gender = MALE //gender of character (well duh)
- var/age = 30 //age of character
- var/underwear = "Nude" //underwear type
- var/undershirt = "Nude" //undershirt type
- var/socks = "Nude" //socks type
- var/backbag = DBACKPACK //backpack type
- var/hair_style = "Bald" //Hair type
- var/hair_color = "000" //Hair color
- var/facial_hair_style = "Shaved" //Face hair type
- var/facial_hair_color = "000" //Facial hair color
- var/skin_tone = "caucasian1" //Skin color
- var/eye_color = "000" //Eye color
- var/datum/species/pref_species = new /datum/species/human() //Mutant race
- var/list/features = list("mcolor" = "FFF",
- "tail_lizard" = "Smooth", "tail_human" = "None",
- "snout" = "Round", "horns" = "None", "ears" = "None",
- "wings" = "None", "frills" = "None", "spines" = "None",
- "body_markings" = "None", "legs" = "Normal Legs", "moth_wings" = "Plain")
-
- var/list/custom_names = list()
- var/prefered_security_department = SEC_DEPT_RANDOM
-
- //Mob preview
- var/icon/preview_icon = null
-
- //Quirk list
- var/list/positive_quirks = list()
- var/list/negative_quirks = list()
- var/list/neutral_quirks = list()
- var/list/all_quirks = list()
- var/list/character_quirks = list()
-
- //Jobs, uses bitflags
- var/job_civilian_high = 0
- var/job_civilian_med = 0
- var/job_civilian_low = 0
-
- var/job_medsci_high = 0
- var/job_medsci_med = 0
- var/job_medsci_low = 0
-
- var/job_engsec_high = 0
- var/job_engsec_med = 0
- var/job_engsec_low = 0
-
- // Want randomjob if preferences already filled - Donkie
- var/joblessrole = BERANDOMJOB //defaults to 1 for fewer assistants
-
- // 0 = character settings, 1 = game preferences
- var/current_tab = 0
-
- var/unlock_content = 0
-
- var/list/ignoring = list()
-
- var/clientfps = 0
-
- var/parallax
-
- var/ambientocclusion = TRUE
- var/auto_fit_viewport = TRUE
-
- var/uplink_spawn_loc = UPLINK_PDA
-
- var/list/exp = list()
- var/list/menuoptions
-
- var/action_buttons_screen_locs = list()
-
-/datum/preferences/New(client/C)
- parent = C
-
- for(var/custom_name_id in GLOB.preferences_custom_names)
- custom_names[custom_name_id] = get_default_name(custom_name_id)
-
- UI_style = GLOB.available_ui_styles[1]
- if(istype(C))
- if(!IsGuestKey(C.key))
- load_path(C.ckey)
- unlock_content = C.IsByondMember()
- if(unlock_content)
- max_save_slots = 16
- var/loaded_preferences_successfully = load_preferences()
- if(loaded_preferences_successfully)
- if(load_character())
- return
- //we couldn't load character data so just randomize the character appearance + name
- random_character() //let's create a random character then - rather than a fat, bald and naked man.
- real_name = pref_species.random_name(gender,1)
- if(!loaded_preferences_successfully)
- save_preferences()
- save_character() //let's save this new random character so it doesn't keep generating new ones.
- menuoptions = list()
- return
-
-#define APPEARANCE_CATEGORY_COLUMN ""
-#define MAX_MUTANT_ROWS 4
-
-/datum/preferences/proc/ShowChoices(mob/user)
- if(!user || !user.client)
- return
- if(current_tab == 2) //CITADEL EDIT, for muh nudies
- update_preview_icon(nude=TRUE)
- else
- update_preview_icon(nude=FALSE) //EDIT END
- user << browse_rsc(preview_icon, "previewicon.png")
- var/list/dat = list("")
-
- dat += "Character Settings"
- dat += "Character Appearance"
- dat += "Loadout"
- dat += "Game Preferences"
-
- if(!path)
- dat += " Please create an account to save your preferences "
-
- dat += ""
-
- dat += " "
-
- switch(current_tab)
- if (0) // Character Settings#
- if(path)
- var/savefile/S = new /savefile(path)
- if(S)
- dat += ""
- var/name
- var/unspaced_slots = 0
- for(var/i=1, i<=max_save_slots, i++)
- unspaced_slots++
- if(unspaced_slots > 4)
- dat += " "
- unspaced_slots = 0
- S.cd = "/character[i]"
- S["real_name"] >> name
- if(!name)
- name = "Character[i]"
- dat += "[name] "
- dat += ""
-
- dat += "Occupation Choices"
- dat += "Set Occupation Preferences "
- if(CONFIG_GET(flag/roundstart_traits))
- dat += "Quirk Setup"
- dat += "Configure Quirks "
- dat += "Current Quirks: [all_quirks.len ? all_quirks.Join(", ") : "None"]"
- dat += "Identity"
- dat += ""
-
- //Character Appearance
- if(2)
- update_preview_icon(nude=TRUE)
- user << browse_rsc(preview_icon, "previewicon.png")
- dat += ""
- dat += ""
- dat += "Set Flavor Text "
- if(lentext(features["flavor_text"]) <= 40)
- if(!lentext(features["flavor_text"]))
- dat += "\[...\]"
- else
- dat += "[features["flavor_text"]]"
- else
- dat += "[TextPreview(features["flavor_text"])]... "
- dat += "Body"
- dat += "Gender: [gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))] "
- dat += "Species:[pref_species.id] "
- dat += "Random Body "
- dat += "Always Random Body: [be_random_body ? "Yes" : "No"] "
-
- var/use_skintones = pref_species.use_skintones
- if(use_skintones)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Skin Tone"
-
- dat += "[skin_tone] "
-
- var/mutant_colors
- if((MUTCOLORS in pref_species.species_traits) || (MUTCOLORS_PARTSONLY in pref_species.species_traits))
- if(!use_skintones)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Body Colors "
- dat += "Primary Color: Change "
- dat += "Secondary Color: Change "
- dat += "Tertiary Color: Change "
- mutant_colors = TRUE
-
- if((EYECOLOR in pref_species.species_traits) && !(NOEYES in pref_species.species_traits))
-
- if(!use_skintones && !mutant_colors)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Eye Color"
-
- dat += " Change "
-
- dat += " | "
- else if(use_skintones || mutant_colors)
- dat += ""
-
- if(HAIR in pref_species.species_traits)
-
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Hair Style"
-
- dat += "[hair_style] "
- dat += "< > "
- dat += " Change "
-
- dat += "Facial Hair Style"
-
- dat += "[facial_hair_style] "
- dat += "< > "
- dat += " Change "
-
- dat += ""
- //Mutant stuff
- var/mutant_category = 0
-
- if("tail_lizard" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Tail"
-
- dat += "[features["tail_lizard"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
-
- if("mam_tail" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Tail"
-
- dat += "[features["mam_tail"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("tail_human" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Tail"
-
- dat += "[features["tail_human"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("snout" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Snout"
-
- dat += "[features["snout"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("horns" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Horns"
-
- dat += "[features["horns"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- if("frills" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Frills"
-
- dat += "[features["frills"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
-
- if("spines" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Spines"
-
- dat += "[features["spines"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
-
- if("body_markings" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Body Markings"
-
- dat += "[features["body_markings"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("mam_body_markings" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Species Markings"
-
- dat += "[features["mam_body_markings"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
-
- if("mam_ears" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Ears"
-
- dat += "[features["mam_ears"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("ears" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Ears"
-
- dat += "[features["ears"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("legs" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Legs"
-
- dat += "[features["legs"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("moth_wings" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Moth wings"
-
- dat += "[features["moth_wings"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("taur" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Tauric Body"
-
- dat += "[features["taur"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("wings" in pref_species.mutant_bodyparts && GLOB.r_wings_list.len >1)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Wings"
-
- dat += "[features["wings"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("xenohead" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Caste Head"
-
- dat += "[features["xenohead"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("xenotail" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Tail"
-
- dat += "[features["xenotail"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("xenodorsal" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Dorsal Spines"
-
- dat += "[features["xenodorsal"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("ipc_screen" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Screen"
-
- dat += "[features["ipc_screen"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("ipc_antenna" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Antenna"
-
- dat += "[features["ipc_antenna"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
-
- if(mutant_category)
- dat += ""
- mutant_category = 0
-
- dat += " "
-
- dat += " | "
-
- dat += "Clothing & Equipment"
-
- dat += "Underwear:[underwear] "
- dat += "Undershirt:[undershirt] "
- dat += "Socks:[socks] "
- dat += "Backpack:[backbag] "
- dat += "Uplink Location:[uplink_spawn_loc] "
-
- dat += "Genitals"
- if(NOGENITALS in pref_species.species_traits)
- dat += "Your species ([pref_species.name]) does not support genitals! "
- else
- if(pref_species.use_skintones)
- dat += "Genitals use skintone:[features["genitals_use_skintone"] == TRUE ? "Yes" : "No"] "
- dat += "Has Penis:[features["has_cock"] == TRUE ? "Yes" : "No"] "
- if(features["has_cock"] == TRUE)
- if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE)
- dat += "Penis Color: (Skin tone overriding) "
- else
- dat += "Penis Color: Change "
- dat += "Penis Shape: [features["cock_shape"]] "
- dat += "Penis Length: [features["cock_length"]] inch(es) "
- dat += "Has Testicles:[features["has_balls"] == TRUE ? "Yes" : "No"] "
- if(features["has_balls"] == TRUE)
- if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE)
- dat += "Testicles Color: (Skin tone overriding) "
- else
- dat += "Testicles Color: Change "
- dat += "Has Vagina:[features["has_vag"] == TRUE ? "Yes" : "No"] "
- if(features["has_vag"])
- dat += "Vagina Type: [features["vag_shape"]] "
- if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE)
- dat += "Vagina Color: (Skin tone overriding) "
- else
- dat += "Vagina Color: Change "
- dat += "Has Womb:[features["has_womb"] == TRUE ? "Yes" : "No"] "
- dat += "Has Breasts:[features["has_breasts"] == TRUE ? "Yes" : "No"] "
- if(features["has_breasts"])
- if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE)
- dat += "Color: (Skin tone overriding) "
- else
- dat += "Color: Change "
- dat += "Cup Size:[features["breasts_size"]] "
- dat += "Breast Shape:[features["breasts_shape"]] "
- dat += " | "
-
- if (1) // Game Preferences
- dat += ""
- if(unlock_content)
- dat += "Ghost Form: [ghost_form]
"
- dat += "Ghost Orbit: [ghost_orbit]
"
- var/button_name = "If you see this something went wrong."
- switch(ghost_accs)
- if(GHOST_ACCS_FULL)
- button_name = GHOST_ACCS_FULL_NAME
- if(GHOST_ACCS_DIR)
- button_name = GHOST_ACCS_DIR_NAME
- if(GHOST_ACCS_NONE)
- button_name = GHOST_ACCS_NONE_NAME
-
- dat += "Ghost Accessories: [button_name]
"
- switch(ghost_others)
- if(GHOST_OTHERS_THEIR_SETTING)
- button_name = GHOST_OTHERS_THEIR_SETTING_NAME
- if(GHOST_OTHERS_DEFAULT_SPRITE)
- button_name = GHOST_OTHERS_DEFAULT_SPRITE_NAME
- if(GHOST_OTHERS_SIMPLE)
- button_name = GHOST_OTHERS_SIMPLE_NAME
-
- dat += "Ghosts of Others: [button_name]
"
- dat += "
"
- dat += "FPS: [clientfps]
"
- dat += "Parallax (Fancy Space): "
- switch (parallax)
- if (PARALLAX_LOW)
- dat += "Low"
- if (PARALLAX_MED)
- dat += "Medium"
- if (PARALLAX_INSANE)
- dat += "Insane"
- if (PARALLAX_DISABLE)
- dat += "Disabled"
- else
- dat += "High"
- dat += "
"
- dat += "Ambient Occlusion: [ambientocclusion ? "Enabled" : "Disabled"]
"
- dat += "Fit Viewport: [auto_fit_viewport ? "Auto" : "Manual"]
"
-
- if (CONFIG_GET(flag/maprotation) && CONFIG_GET(flag/tgstyle_maprotation))
- var/p_map = preferred_map
- if (!p_map)
- p_map = "Default"
- if (config.defaultmap)
- p_map += " ([config.defaultmap.map_name])"
- else
- if (p_map in config.maplist)
- var/datum/map_config/VM = config.maplist[p_map]
- if (!VM)
- p_map += " (No longer exists)"
- else
- p_map = VM.map_name
- else
- p_map += " (No longer exists)"
- if(CONFIG_GET(flag/allow_map_voting))
- dat += "Preferred Map: [p_map]
"
-
- dat += ""
-
- dat += "Special Role Settings"
-
- if(jobban_isbanned(user, ROLE_SYNDICATE))
- dat += "You are banned from antagonist roles."
- src.be_special = list()
-
-
- for (var/i in GLOB.special_roles)
- if(jobban_isbanned(user, i))
- dat += "Be [capitalize(i)]: BANNED "
- else
- var/days_remaining = null
- if(ispath(GLOB.special_roles[i]) && CONFIG_GET(flag/use_age_restriction_for_jobs)) //If it's a game mode antag, check if the player meets the minimum age
- var/mode_path = GLOB.special_roles[i]
- var/datum/game_mode/temp_mode = new mode_path
- days_remaining = temp_mode.get_remaining_days(user.client)
-
- if(days_remaining)
- dat += "Be [capitalize(i)]: \[IN [days_remaining] DAYS] "
- else
- dat += "Be [capitalize(i)]: [(i in be_special) ? "Enabled" : "Disabled"] "
- dat += "Midround Antagonist: [(toggles & MIDROUND_ANTAG) ? "Enabled" : "Disabled"] "
-
- dat += " "
- dat += "Citadel Preferences" //Because fuck me if preferences can't be fucking modularized and expected to update in a reasonable timeframe.
- dat += "Arousal:[arousable == TRUE ? "Enabled" : "Disabled"] "
- dat += "Exhibitionist:[features["exhibitionist"] == TRUE ? "Yes" : "No"] "
- dat += "Voracious MediHound sleepers: [(cit_toggles & MEDIHOUND_SLEEPER) ? "Yes" : "No"] "
- dat += "Hear Vore Sounds: [(cit_toggles & EATING_NOISES) ? "Yes" : "No"] "
- dat += "Hear Vore Digestion Sounds: [(cit_toggles & DIGESTION_NOISES) ? "Yes" : "No"] "
- dat += "Widescreen: [widescreenpref ? "Enabled ([CONFIG_GET(string/default_view)])" : "Disabled (15x15)"] "
- dat += "Auto stand: [autostand ? "Enabled" : "Disabled"] "
- dat += "Screen Shake: [(screenshake==100) ? "Full" : ((screenshake==0) ? "None" : "[screenshake]")] "
- if (user && user.client && !user.client.prefs.screenshake==0)
- dat += "Damage Screen Shake: [(damagescreenshake==1) ? "On" : ((damagescreenshake==0) ? "Off" : "Only when down")] "
- dat += " "
-
- if(3)
- if(!gear_tab)
- gear_tab = GLOB.loadout_items[1]
- dat += ""
- dat += "| [gear_points] loadout points remaining. \[Clear Loadout\] | "
- dat += "| You can only choose one item per category, unless it's an item that spawns in your backpack or hands. | "
- dat += "| "
- var/firstcat = TRUE
- for(var/i in GLOB.loadout_items)
- if(firstcat)
- firstcat = FALSE
- else
- dat += " |"
- if(i == gear_tab)
- dat += " [i] "
- else
- dat += " [i] "
- dat += " | "
- dat += "
| "
- dat += "| [gear_tab] | "
- dat += "
| "
- dat += "| Name | "
- dat += "Cost | "
- dat += "Restrictions | "
- dat += "Description | "
- for(var/j in GLOB.loadout_items[gear_tab])
- var/datum/gear/gear = GLOB.loadout_items[gear_tab][j]
- var/donoritem
- if(gear.ckeywhitelist && gear.ckeywhitelist.len)
- donoritem = TRUE
- if(!(user.ckey in gear.ckeywhitelist))
- continue
- var/class_link = ""
- if(gear.type in chosen_gear)
- class_link = "style='white-space:normal;' class='linkOn' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(j)];toggle_gear=0'"
- else if(gear_points <= 0)
- class_link = "style='white-space:normal;' class='linkOff'"
- else if(donoritem)
- class_link = "style='white-space:normal;background:#ebc42e;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(j)];toggle_gear=1'"
- else
- class_link = "style='white-space:normal;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(j)];toggle_gear=1'"
- dat += "| [j] | "
- dat += "[gear.cost] | "
- if(islist(gear.restricted_roles))
- if(gear.restricted_roles.len)
- dat += ""
- dat += gear.restricted_roles.Join(";")
- dat += ""
- dat += " | [gear.description] | "
- dat += " "
-
- dat += " "
-
- if(!IsGuestKey(user.key))
- dat += "Undo "
- dat += "Save Setup "
-
- dat += "Reset Setup"
- dat += ""
-
- var/datum/browser/popup = new(user, "preferences", "Character Setup ", 640, 770)
- popup.set_content(dat.Join())
- popup.open(0)
-
-#undef APPEARANCE_CATEGORY_COLUMN
-#undef MAX_MUTANT_ROWS
-
-/datum/preferences/proc/SetChoices(mob/user, limit = 17, list/splitJobs = list("Chief Engineer"), widthPerColumn = 295, height = 620)
- if(!SSjob)
- return
-
- //limit - The amount of jobs allowed per column. Defaults to 17 to make it look nice.
- //splitJobs - Allows you split the table by job. You can make different tables for each department by including their heads. Defaults to CE to make it look nice.
- //widthPerColumn - Screen's width for every column.
- //height - Screen's height.
-
- var/width = widthPerColumn
-
- var/HTML = ""
- if(SSjob.occupations.len <= 0)
- HTML += "The job SSticker is not yet finished creating jobs, please try again later"
- HTML += "Done " // Easier to press up here.
-
- else
- HTML += "Choose occupation chances "
- HTML += "Left-click to raise an occupation preference, right-click to lower it.
"
- HTML += "Done " // Easier to press up here.
- HTML += ""
- HTML += "" // Table within a table for alignment, also allows you to easily add more colomns.
- HTML += ""
- var/index = -1
-
- //The job before the current job. I only use this to get the previous jobs color when I'm filling in blank rows.
- var/datum/job/lastJob
-
- var/datum/job/overflow = SSjob.GetJob(SSjob.overflow_role)
-
- for(var/datum/job/job in SSjob.occupations)
-
- index += 1
- if((index >= limit) || (job.title in splitJobs))
- width += widthPerColumn
- if((index < limit) && (lastJob != null))
- //If the cells were broken up by a job in the splitJob list then it will fill in the rest of the cells with
- //the last job's selection color. Creating a rather nice effect.
- for(var/i = 0, i < (limit - index), i += 1)
- HTML += "|   |   | "
- HTML += " | "
- index = 0
-
- HTML += "| "
- var/rank = job.title
- lastJob = job
- if(jobban_isbanned(user, rank))
- HTML += "[rank] | BANNED | "
- continue
- var/required_playtime_remaining = job.required_playtime_remaining(user.client)
- if(required_playtime_remaining)
- HTML += "[rank] \[ [get_exp_format(required_playtime_remaining)] as [job.get_exp_req_type()] \] | "
- continue
- if(!job.player_old_enough(user.client))
- var/available_in_days = job.available_in_days(user.client)
- HTML += "[rank] \[IN [(available_in_days)] DAYS\] | "
- continue
- if((job_civilian_low & overflow.flag) && (rank != SSjob.overflow_role) && !jobban_isbanned(user, SSjob.overflow_role))
- HTML += "[rank] | "
- continue
- if((rank in GLOB.command_positions) || (rank == "AI"))//Bold head jobs
- HTML += "[rank]"
- else
- HTML += "[rank]"
-
- HTML += ""
-
- var/prefLevelLabel = "ERROR"
- var/prefLevelColor = "pink"
- var/prefUpperLevel = -1 // level to assign on left click
- var/prefLowerLevel = -1 // level to assign on right click
-
- if(GetJobDepartment(job, 1) & job.flag)
- prefLevelLabel = "High"
- prefLevelColor = "slateblue"
- prefUpperLevel = 4
- prefLowerLevel = 2
- else if(GetJobDepartment(job, 2) & job.flag)
- prefLevelLabel = "Medium"
- prefLevelColor = "green"
- prefUpperLevel = 1
- prefLowerLevel = 3
- else if(GetJobDepartment(job, 3) & job.flag)
- prefLevelLabel = "Low"
- prefLevelColor = "orange"
- prefUpperLevel = 2
- prefLowerLevel = 4
- else
- prefLevelLabel = "NEVER"
- prefLevelColor = "red"
- prefUpperLevel = 3
- prefLowerLevel = 1
-
-
- HTML += ""
-
- if(rank == SSjob.overflow_role)//Overflow is special
- if(job_civilian_low & overflow.flag)
- HTML += "Yes"
- else
- HTML += "No"
- HTML += " | "
- continue
-
- HTML += "[prefLevelLabel]"
- HTML += ""
-
- for(var/i = 1, i < (limit - index), i += 1) // Finish the column so it is even
- HTML += "|   |   | "
-
- HTML += " "
- HTML += " | "
-
- var/message = "Be an [SSjob.overflow_role] if preferences unavailable"
- if(joblessrole == BERANDOMJOB)
- message = "Get random job if preferences unavailable"
- else if(joblessrole == RETURNTOLOBBY)
- message = "Return to lobby if preferences unavailable"
- HTML += " [message]"
- HTML += "Reset Preferences"
-
- user << browse(null, "window=preferences")
- var/datum/browser/popup = new(user, "mob_occupation", "Occupation Preferences ", width, height)
- popup.set_window_options("can_close=0")
- popup.set_content(HTML)
- popup.open(0)
- return
-
-/datum/preferences/proc/SetJobPreferenceLevel(datum/job/job, level)
- if (!job)
- return 0
-
- if (level == 1) // to high
- // remove any other job(s) set to high
- job_civilian_med |= job_civilian_high
- job_engsec_med |= job_engsec_high
- job_medsci_med |= job_medsci_high
- job_civilian_high = 0
- job_engsec_high = 0
- job_medsci_high = 0
-
- if (job.department_flag == CIVILIAN)
- job_civilian_low &= ~job.flag
- job_civilian_med &= ~job.flag
- job_civilian_high &= ~job.flag
-
- switch(level)
- if (1)
- job_civilian_high |= job.flag
- if (2)
- job_civilian_med |= job.flag
- if (3)
- job_civilian_low |= job.flag
-
- return 1
- else if (job.department_flag == ENGSEC)
- job_engsec_low &= ~job.flag
- job_engsec_med &= ~job.flag
- job_engsec_high &= ~job.flag
-
- switch(level)
- if (1)
- job_engsec_high |= job.flag
- if (2)
- job_engsec_med |= job.flag
- if (3)
- job_engsec_low |= job.flag
-
- return 1
- else if (job.department_flag == MEDSCI)
- job_medsci_low &= ~job.flag
- job_medsci_med &= ~job.flag
- job_medsci_high &= ~job.flag
-
- switch(level)
- if (1)
- job_medsci_high |= job.flag
- if (2)
- job_medsci_med |= job.flag
- if (3)
- job_medsci_low |= job.flag
-
- return 1
-
- return 0
-
-/datum/preferences/proc/UpdateJobPreference(mob/user, role, desiredLvl)
- if(!SSjob || SSjob.occupations.len <= 0)
- return
- var/datum/job/job = SSjob.GetJob(role)
-
- if(!job)
- user << browse(null, "window=mob_occupation")
- ShowChoices(user)
- return
-
- if (!isnum(desiredLvl))
- to_chat(user, "UpdateJobPreference - desired level was not a number. Please notify coders!")
- ShowChoices(user)
- return
-
- if(role == SSjob.overflow_role)
- if(job_civilian_low & job.flag)
- job_civilian_low &= ~job.flag
- else
- job_civilian_low |= job.flag
- SetChoices(user)
- return 1
-
- SetJobPreferenceLevel(job, desiredLvl)
- SetChoices(user)
-
- return 1
-
-
-/datum/preferences/proc/ResetJobs()
-
- job_civilian_high = 0
- job_civilian_med = 0
- job_civilian_low = 0
-
- job_medsci_high = 0
- job_medsci_med = 0
- job_medsci_low = 0
-
- job_engsec_high = 0
- job_engsec_med = 0
- job_engsec_low = 0
-
-
-/datum/preferences/proc/GetJobDepartment(datum/job/job, level)
- if(!job || !level)
- return 0
- switch(job.department_flag)
- if(CIVILIAN)
- switch(level)
- if(1)
- return job_civilian_high
- if(2)
- return job_civilian_med
- if(3)
- return job_civilian_low
- if(MEDSCI)
- switch(level)
- if(1)
- return job_medsci_high
- if(2)
- return job_medsci_med
- if(3)
- return job_medsci_low
- if(ENGSEC)
- switch(level)
- if(1)
- return job_engsec_high
- if(2)
- return job_engsec_med
- if(3)
- return job_engsec_low
- return 0
-
-/datum/preferences/proc/SetQuirks(mob/user)
- if(!SSquirks)
- to_chat(user, "The quirk subsystem is still initializing! Try again in a minute.")
- return
-
- var/list/dat = list()
- if(!SSquirks.quirks.len)
- dat += "The quirk subsystem hasn't finished initializing, please hold..."
- dat += "Done "
-
- else
- dat += "Choose quirk setup "
- dat += "Left-click to add or remove quirks. You need negative quirks to have positive ones. \
- Quirks are applied at roundstart and cannot normally be removed. "
- dat += "Done"
- dat += " "
- dat += "Current quirks: [all_quirks.len ? all_quirks.Join(", ") : "None"]"
- dat += "[positive_quirks.len] / [MAX_QUIRKS] max positive quirks \
- Quirk balance remaining: [GetQuirkBalance()] "
- for(var/V in SSquirks.quirks)
- var/datum/quirk/T = SSquirks.quirks[V]
- var/quirk_name = initial(T.name)
- var/has_quirk
- var/quirk_cost = initial(T.value) * -1
- var/lock_reason = "This trait is unavailable."
- var/quirk_conflict = FALSE
- for(var/_V in all_quirks)
- if(_V == quirk_name)
- has_quirk = TRUE
- if(initial(T.mood_quirk) && CONFIG_GET(flag/disable_human_mood))
- lock_reason = "Mood is disabled."
- quirk_conflict = TRUE
- if(has_quirk)
- if(quirk_conflict)
- all_quirks -= quirk_name
- has_quirk = FALSE
- else
- quirk_cost *= -1 //invert it back, since we'd be regaining this amount
- if(quirk_cost > 0)
- quirk_cost = "+[quirk_cost]"
- var/font_color = "#AAAAFF"
- if(initial(T.value) != 0)
- font_color = initial(T.value) > 0 ? "#AAFFAA" : "#FFAAAA"
- if(quirk_conflict)
- dat += "[quirk_name] - [initial(T.desc)] \
- LOCKED: [lock_reason] "
- else
- if(has_quirk)
- dat += "[quirk_name] - [initial(T.desc)] \
- [has_quirk ? "Lose" : "Take"] ([quirk_cost] pts.) "
- else
- dat += "[quirk_name] - [initial(T.desc)] \
- [has_quirk ? "Lose" : "Take"] ([quirk_cost] pts.) "
- dat += " Reset Traits"
-
- user << browse(null, "window=preferences")
- var/datum/browser/popup = new(user, "mob_occupation", "Quirk Preferences ", 900, 600) //no reason not to reuse the occupation window, as it's cleaner that way
- popup.set_window_options("can_close=0")
- popup.set_content(dat.Join())
- popup.open(0)
- return
-
-/datum/preferences/proc/GetQuirkBalance()
- var/bal = 0
- for(var/V in all_quirks)
- var/datum/quirk/T = SSquirks.quirks[V]
- bal -= initial(T.value)
- return bal
-
-/datum/preferences/proc/process_link(mob/user, list/href_list)
- if(href_list["jobbancheck"])
- var/job = sanitizeSQL(href_list["jobbancheck"])
- var/sql_ckey = sanitizeSQL(user.ckey)
- var/datum/DBQuery/query_get_jobban = SSdbcore.NewQuery("SELECT reason, bantime, duration, expiration_time, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].a_ckey), a_ckey) FROM [format_table_name("ban")] WHERE ckey = '[sql_ckey]' AND (bantype = 'JOB_PERMABAN' OR (bantype = 'JOB_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned) AND job = '[job]'")
- if(!query_get_jobban.warn_execute())
- qdel(query_get_jobban)
- return
- if(query_get_jobban.NextRow())
- var/reason = query_get_jobban.item[1]
- var/bantime = query_get_jobban.item[2]
- var/duration = query_get_jobban.item[3]
- var/expiration_time = query_get_jobban.item[4]
- var/admin_key = query_get_jobban.item[5]
- var/text
- text = "You, or another user of this computer, ([user.key]) is banned from playing [job]. The ban reason is: [reason] This ban was applied by [admin_key] on [bantime]"
- if(text2num(duration) > 0)
- text += ". The ban is for [duration] minutes and expires on [expiration_time] (server time)"
- text += "."
- to_chat(user, text)
- qdel(query_get_jobban)
- return
-
- if(href_list["preference"] == "job")
- switch(href_list["task"])
- if("close")
- user << browse(null, "window=mob_occupation")
- ShowChoices(user)
- if("reset")
- ResetJobs()
- SetChoices(user)
- if("random")
- switch(joblessrole)
- if(RETURNTOLOBBY)
- if(jobban_isbanned(user, SSjob.overflow_role))
- joblessrole = BERANDOMJOB
- else
- joblessrole = BEOVERFLOW
- if(BEOVERFLOW)
- joblessrole = BERANDOMJOB
- if(BERANDOMJOB)
- joblessrole = RETURNTOLOBBY
- SetChoices(user)
- if("setJobLevel")
- UpdateJobPreference(user, href_list["text"], text2num(href_list["level"]))
- else
- SetChoices(user)
- return 1
-
- else if(href_list["preference"] == "trait")
- switch(href_list["task"])
- if("close")
- user << browse(null, "window=mob_occupation")
- ShowChoices(user)
- if("update")
- var/quirk = href_list["trait"]
- if(!SSquirks.quirks[quirk])
- return
- var/value = SSquirks.quirk_points[quirk]
- if(value == 0)
- if(quirk in neutral_quirks)
- neutral_quirks -= quirk
- all_quirks -= quirk
- else
- neutral_quirks += quirk
- all_quirks += quirk
- else
- var/balance = GetQuirkBalance()
- if(quirk in positive_quirks)
- positive_quirks -= quirk
- all_quirks -= quirk
- else if(quirk in negative_quirks)
- if(balance + value < 0)
- to_chat(user, "Refunding this would cause you to go below your balance!")
- return
- negative_quirks -= quirk
- all_quirks -= quirk
- else if(value > 0)
- if(positive_quirks.len >= MAX_QUIRKS)
- to_chat(user, "You can't have more than [MAX_QUIRKS] positive quirks!")
- return
- if(balance - value < 0)
- to_chat(user, "You don't have enough balance to gain this quirk!")
- return
- positive_quirks += quirk
- all_quirks += quirk
- else
- negative_quirks += quirk
- all_quirks += quirk
- SetQuirks(user)
- if("reset")
- all_quirks = list()
- positive_quirks = list()
- negative_quirks = list()
- neutral_quirks = list()
- SetQuirks(user)
- else
- SetQuirks(user)
- return TRUE
-
- switch(href_list["task"])
- if("random")
- switch(href_list["preference"])
- if("name")
- real_name = pref_species.random_name(gender,1)
- if("age")
- age = rand(AGE_MIN, AGE_MAX)
- if("hair")
- hair_color = random_short_color()
- if("hair_style")
- hair_style = random_hair_style(gender)
- if("facial")
- facial_hair_color = random_short_color()
- if("facial_hair_style")
- facial_hair_style = random_facial_hair_style(gender)
- if("underwear")
- underwear = random_underwear(gender)
- if("undershirt")
- undershirt = random_undershirt(gender)
- if("socks")
- socks = random_socks()
- if(BODY_ZONE_PRECISE_EYES)
- eye_color = random_eye_color()
- if("s_tone")
- skin_tone = random_skin_tone()
- if("bag")
- backbag = pick(GLOB.backbaglist)
- if("all")
- random_character()
-
- if("input")
-
- if(href_list["preference"] in GLOB.preferences_custom_names)
- ask_for_custom_name(user,href_list["preference"])
-
-
- switch(href_list["preference"])
- if("ghostform")
- if(unlock_content)
- var/new_form = input(user, "Thanks for supporting BYOND - Choose your ghostly form:","Thanks for supporting BYOND",null) as null|anything in GLOB.ghost_forms
- if(new_form)
- ghost_form = new_form
- if("ghostorbit")
- if(unlock_content)
- var/new_orbit = input(user, "Thanks for supporting BYOND - Choose your ghostly orbit:","Thanks for supporting BYOND", null) as null|anything in GLOB.ghost_orbits
- if(new_orbit)
- ghost_orbit = new_orbit
-
- if("ghostaccs")
- var/new_ghost_accs = alert("Do you want your ghost to show full accessories where possible, hide accessories but still use the directional sprites where possible, or also ignore the directions and stick to the default sprites?",,GHOST_ACCS_FULL_NAME, GHOST_ACCS_DIR_NAME, GHOST_ACCS_NONE_NAME)
- switch(new_ghost_accs)
- if(GHOST_ACCS_FULL_NAME)
- ghost_accs = GHOST_ACCS_FULL
- if(GHOST_ACCS_DIR_NAME)
- ghost_accs = GHOST_ACCS_DIR
- if(GHOST_ACCS_NONE_NAME)
- ghost_accs = GHOST_ACCS_NONE
-
- if("ghostothers")
- var/new_ghost_others = alert("Do you want the ghosts of others to show up as their own setting, as their default sprites or always as the default white ghost?",,GHOST_OTHERS_THEIR_SETTING_NAME, GHOST_OTHERS_DEFAULT_SPRITE_NAME, GHOST_OTHERS_SIMPLE_NAME)
- switch(new_ghost_others)
- if(GHOST_OTHERS_THEIR_SETTING_NAME)
- ghost_others = GHOST_OTHERS_THEIR_SETTING
- if(GHOST_OTHERS_DEFAULT_SPRITE_NAME)
- ghost_others = GHOST_OTHERS_DEFAULT_SPRITE
- if(GHOST_OTHERS_SIMPLE_NAME)
- ghost_others = GHOST_OTHERS_SIMPLE
-
- if("name")
- var/new_name = input(user, "Choose your character's name:", "Character Preference") as text|null
- if(new_name)
- new_name = reject_bad_name(new_name)
- if(new_name)
- real_name = new_name
- else
- to_chat(user, "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and .")
-
- if("age")
- var/new_age = input(user, "Choose your character's age:\n([AGE_MIN]-[AGE_MAX])", "Character Preference") as num|null
- if(new_age)
- age = max(min( round(text2num(new_age)), AGE_MAX),AGE_MIN)
-
- if("flavor_text")
- var/msg = stripped_multiline_input(usr,"Set the flavor text in your 'examine' verb. This can also be used for OOC notes and preferences!","Flavor Text",html_decode(features["flavor_text"]), MAX_MESSAGE_LEN*2, TRUE) as null|message
- if(!isnull(msg))
- msg = copytext(msg, 1, MAX_MESSAGE_LEN*2)
- features["flavor_text"] = msg
-
- if("hair")
- var/new_hair = input(user, "Choose your character's hair colour:", "Character Preference","#"+hair_color) as color|null
- if(new_hair)
- hair_color = sanitize_hexcolor(new_hair)
-
- if("hair_style")
- var/new_hair_style
- if(gender == MALE)
- new_hair_style = input(user, "Choose your character's hair style:", "Character Preference") as null|anything in GLOB.hair_styles_male_list
- else
- new_hair_style = input(user, "Choose your character's hair style:", "Character Preference") as null|anything in GLOB.hair_styles_female_list
- if(new_hair_style)
- hair_style = new_hair_style
-
- if("next_hair_style")
- if (gender == MALE)
- hair_style = next_list_item(hair_style, GLOB.hair_styles_male_list)
- else
- hair_style = next_list_item(hair_style, GLOB.hair_styles_female_list)
-
- if("previous_hair_style")
- if (gender == MALE)
- hair_style = previous_list_item(hair_style, GLOB.hair_styles_male_list)
- else
- hair_style = previous_list_item(hair_style, GLOB.hair_styles_female_list)
-
- if("facial")
- var/new_facial = input(user, "Choose your character's facial-hair colour:", "Character Preference","#"+facial_hair_color) as color|null
- if(new_facial)
- facial_hair_color = sanitize_hexcolor(new_facial)
- if("facial_hair_style")
- var/new_facial_hair_style
- if(gender == MALE)
- new_facial_hair_style = input(user, "Choose your character's facial-hair style:", "Character Preference") as null|anything in GLOB.facial_hair_styles_male_list
- else
- new_facial_hair_style = input(user, "Choose your character's facial-hair style:", "Character Preference") as null|anything in GLOB.facial_hair_styles_female_list
- if(new_facial_hair_style)
- facial_hair_style = new_facial_hair_style
-
- if("next_facehair_style")
- if (gender == MALE)
- facial_hair_style = next_list_item(facial_hair_style, GLOB.facial_hair_styles_male_list)
- else
- facial_hair_style = next_list_item(facial_hair_style, GLOB.facial_hair_styles_female_list)
- if("previous_facehair_style")
- if (gender == MALE)
- facial_hair_style = previous_list_item(facial_hair_style, GLOB.facial_hair_styles_male_list)
- else
- facial_hair_style = previous_list_item(facial_hair_style, GLOB.facial_hair_styles_female_list)
-
- if("underwear")
- var/new_underwear
- if(gender == MALE)
- new_underwear = input(user, "Choose your character's underwear:", "Character Preference") as null|anything in GLOB.underwear_m
- else
- new_underwear = input(user, "Choose your character's underwear:", "Character Preference") as null|anything in GLOB.underwear_f
- if(new_underwear)
- underwear = new_underwear
-
- if("undershirt")
- var/new_undershirt
- if(gender == MALE)
- new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in GLOB.undershirt_m
- else
- new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in GLOB.undershirt_f
- if(new_undershirt)
- undershirt = new_undershirt
-
- if("socks")
- var/new_socks
- new_socks = input(user, "Choose your character's socks:", "Character Preference") as null|anything in GLOB.socks_list
- if(new_socks)
- socks = new_socks
-
- if("eyes")
- var/new_eyes = input(user, "Choose your character's eye colour:", "Character Preference","#"+eye_color) as color|null
- if(new_eyes)
- eye_color = sanitize_hexcolor(new_eyes)
-
- if("species")
- var/result = input(user, "Select a species", "Species Selection") as null|anything in GLOB.roundstart_races
- if(result)
- var/newtype = GLOB.species_list[result]
- pref_species = new newtype()
- //Now that we changed our species, we must verify that the mutant colour is still allowed.
- var/temp_hsv = RGBtoHSV(features["mcolor"])
- if(features["mcolor"] == "#000" || (!(MUTCOLORS_PARTSONLY in pref_species.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#202020")[3]))
- features["mcolor"] = pref_species.default_color
- if(features["mcolor2"] == "#000" || (!(MUTCOLORS_PARTSONLY in pref_species.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#202020")[3]))
- features["mcolor2"] = pref_species.default_color
- if(features["mcolor3"] == "#000" || (!(MUTCOLORS_PARTSONLY in pref_species.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#202020")[3]))
- features["mcolor3"] = pref_species.default_color
-
- if("mutant_color")
- var/new_mutantcolor = input(user, "Choose your character's alien/mutant color:", "Character Preference","#"+features["mcolor"]) as color|null
- if(new_mutantcolor)
- var/temp_hsv = RGBtoHSV(new_mutantcolor)
- if(new_mutantcolor == "#000000")
- features["mcolor"] = pref_species.default_color
- else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) // mutantcolors must be bright, but only if they affect the skin
- features["mcolor"] = sanitize_hexcolor(new_mutantcolor)
- else
- to_chat(user, "Invalid color. Your color is not bright enough.")
-
- if("mutant_color2")
- var/new_mutantcolor = input(user, "Choose your character's secondary alien/mutant color:", "Character Preference") as color|null
- if(new_mutantcolor)
- var/temp_hsv = RGBtoHSV(new_mutantcolor)
- if(new_mutantcolor == "#000000")
- features["mcolor2"] = pref_species.default_color
- else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) // mutantcolors must be bright, but only if they affect the skin
- features["mcolor2"] = sanitize_hexcolor(new_mutantcolor)
- else
- to_chat(user, "Invalid color. Your color is not bright enough.")
-
- if("mutant_color3")
- var/new_mutantcolor = input(user, "Choose your character's tertiary alien/mutant color:", "Character Preference") as color|null
- if(new_mutantcolor)
- var/temp_hsv = RGBtoHSV(new_mutantcolor)
- if(new_mutantcolor == "#000000")
- features["mcolor3"] = pref_species.default_color
- else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) // mutantcolors must be bright, but only if they affect the skin
- features["mcolor3"] = sanitize_hexcolor(new_mutantcolor)
- else
- to_chat(user, "Invalid color. Your color is not bright enough.")
-
- if("ipc_screen")
- var/new_ipc_screen
- new_ipc_screen = input(user, "Choose your character's screen:", "Character Preference") as null|anything in GLOB.ipc_screens_list
- if(new_ipc_screen)
- features["ipc_screen"] = new_ipc_screen
-
- if("ipc_antenna")
- var/new_ipc_antenna
- new_ipc_antenna = input(user, "Choose your character's antenna:", "Character Preference") as null|anything in GLOB.ipc_antennas_list
- if(new_ipc_antenna)
- features["ipc_antenna"] = new_ipc_antenna
-
- if("tail_lizard")
- var/new_tail
- new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in GLOB.tails_list_lizard
- if(new_tail)
- features["tail_lizard"] = new_tail
- if(new_tail != "None")
- features["taur"] = "None"
- features["tail_human"] = "None"
- features["mam_tail"] = "None"
-
- if("tail_human")
- var/list/snowflake_tails_list = list()
- for(var/path in GLOB.tails_list_human)
- var/datum/sprite_accessory/tails/human/instance = GLOB.tails_list_human[path]
- if(istype(instance, /datum/sprite_accessory))
- var/datum/sprite_accessory/S = instance
- if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
- snowflake_tails_list[S.name] = path
- var/new_tail
- new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in snowflake_tails_list
- if(new_tail)
- features["tail_human"] = new_tail
- if(new_tail != "None")
- features["taur"] = "None"
- features["tail_lizard"] = "None"
- features["mam_tail"] = "None"
-
- if("mam_tail")
- var/list/snowflake_tails_list = list()
- for(var/path in GLOB.mam_tails_list)
- var/datum/sprite_accessory/mam_tails/instance = GLOB.mam_tails_list[path]
- if(istype(instance, /datum/sprite_accessory))
- var/datum/sprite_accessory/S = instance
- if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
- snowflake_tails_list[S.name] = path
- var/new_tail
- new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in snowflake_tails_list
- if(new_tail)
- features["mam_tail"] = new_tail
- if(new_tail != "None")
- features["taur"] = "None"
- features["tail_human"] = "None"
- features["tail_lizard"] = "None"
-
- if("snout")
- var/new_snout
- new_snout = input(user, "Choose your character's snout:", "Character Preference") as null|anything in GLOB.snouts_list
- if(new_snout)
- features["snout"] = new_snout
-
- if("horns")
- var/new_horns
- new_horns = input(user, "Choose your character's horns:", "Character Preference") as null|anything in GLOB.horns_list
- if(new_horns)
- features["horns"] = new_horns
-
- if("ears")
- var/new_ears
- new_ears = input(user, "Choose your character's ears:", "Character Preference") as null|anything in GLOB.ears_list
- if(new_ears)
- features["ears"] = new_ears
-
- if("wings")
- var/new_wings
- new_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.r_wings_list
- if(new_wings)
- features["wings"] = new_wings
-
- if("frills")
- var/new_frills
- new_frills = input(user, "Choose your character's frills:", "Character Preference") as null|anything in GLOB.frills_list
- if(new_frills)
- features["frills"] = new_frills
-
- if("spines")
- var/new_spines
- new_spines = input(user, "Choose your character's spines:", "Character Preference") as null|anything in GLOB.spines_list
- if(new_spines)
- features["spines"] = new_spines
-
- if("body_markings")
- var/new_body_markings
- new_body_markings = input(user, "Choose your character's body markings:", "Character Preference") as null|anything in GLOB.body_markings_list
- if(new_body_markings)
- features["body_markings"] = new_body_markings
-
- if("legs")
- var/new_legs
- new_legs = input(user, "Choose your character's legs:", "Character Preference") as null|anything in GLOB.legs_list
- if(new_legs)
- features["legs"] = new_legs
-
- if("moth_wings")
- var/new_moth_wings
- new_moth_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.moth_wings_list
- if(new_moth_wings)
- features["moth_wings"] = new_moth_wings
-
- if("s_tone")
- var/new_s_tone = input(user, "Choose your character's skin-tone:", "Character Preference") as null|anything in GLOB.skin_tones
- if(new_s_tone)
- skin_tone = new_s_tone
-
- if("taur")
- var/list/snowflake_taur_list = list()
- for(var/path in GLOB.taur_list)
- var/datum/sprite_accessory/taur/instance = GLOB.taur_list[path]
- if(istype(instance, /datum/sprite_accessory))
- var/datum/sprite_accessory/S = instance
- if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
- snowflake_taur_list[S.name] = path
- var/new_taur
- new_taur = input(user, "Choose your character's tauric body:", "Character Preference") as null|anything in snowflake_taur_list
- if(new_taur)
- features["taur"] = new_taur
- if(new_taur != "None")
- features["mam_tail"] = "None"
- features["xenotail"] = "None"
- features["tail_human"] = "None"
- features["tail_lizard"] = "None"
-
- if("ears")
- var/list/snowflake_ears_list = list()
- for(var/path in GLOB.ears_list)
- var/datum/sprite_accessory/ears/instance = GLOB.ears_list[path]
- if(istype(instance, /datum/sprite_accessory))
- var/datum/sprite_accessory/S = instance
- if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
- snowflake_ears_list[S.name] = path
- var/new_ears
- new_ears = input(user, "Choose your character's ears:", "Character Preference") as null|anything in snowflake_ears_list
- if(new_ears)
- features["ears"] = new_ears
-
- if("mam_ears")
- var/list/snowflake_ears_list = list()
- for(var/path in GLOB.mam_ears_list)
- var/datum/sprite_accessory/mam_ears/instance = GLOB.mam_ears_list[path]
- if(istype(instance, /datum/sprite_accessory))
- var/datum/sprite_accessory/S = instance
- if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
- snowflake_ears_list[S.name] = path
- var/new_ears
- new_ears = input(user, "Choose your character's ears:", "Character Preference") as null|anything in snowflake_ears_list
- if(new_ears)
- features["mam_ears"] = new_ears
-
- if("mam_body_markings")
- var/list/snowflake_markings_list = list()
- for(var/path in GLOB.mam_body_markings_list)
- var/datum/sprite_accessory/mam_body_markings/instance = GLOB.mam_body_markings_list[path]
- if(istype(instance, /datum/sprite_accessory))
- var/datum/sprite_accessory/S = instance
- if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
- snowflake_markings_list[S.name] = path
- var/new_mam_body_markings
- new_mam_body_markings = input(user, "Choose your character's body markings:", "Character Preference") as null|anything in snowflake_markings_list
- if(new_mam_body_markings)
- features["mam_body_markings"] = new_mam_body_markings
-
- //Xeno Bodyparts
- if("xenohead")//Head or caste type
- var/new_head
- new_head = input(user, "Choose your character's caste:", "Character Preference") as null|anything in GLOB.xeno_head_list
- if(new_head)
- features["xenohead"] = new_head
-
- if("xenotail")//Currently one one type, more maybe later if someone sprites them. Might include animated variants in the future.
- var/new_tail
- new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in GLOB.xeno_tail_list
- if(new_tail)
- features["xenotail"] = new_tail
- if(new_tail != "None")
- features["mam_tail"] = "None"
- features["taur"] = "None"
- features["tail_human"] = "None"
- features["tail_lizard"] = "None"
-
- if("xenodorsal")
- var/new_dors
- new_dors = input(user, "Choose your character's dorsal tube type:", "Character Preference") as null|anything in GLOB.xeno_dorsal_list
- if(new_dors)
- features["xenodorsal"] = new_dors
- //Genital code
- if("cock_color")
- var/new_cockcolor = input(user, "Penis color:", "Character Preference") as color|null
- if(new_cockcolor)
- var/temp_hsv = RGBtoHSV(new_cockcolor)
- if(new_cockcolor == "#000000")
- features["cock_color"] = pref_species.default_color
- else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
- features["cock_color"] = sanitize_hexcolor(new_cockcolor)
- else
- user << "Invalid color. Your color is not bright enough."
-
- if("cock_length")
- var/new_length = input(user, "Penis length in inches:\n([COCK_SIZE_MIN]-[COCK_SIZE_MAX])", "Character Preference") as num|null
- if(new_length)
- features["cock_length"] = max(min( round(text2num(new_length)), COCK_SIZE_MAX),COCK_SIZE_MIN)
-
- if("cock_shape")
- var/new_shape
- new_shape = input(user, "Penis shape:", "Character Preference") as null|anything in GLOB.cock_shapes_list
- if(new_shape)
- features["cock_shape"] = new_shape
-
- if("balls_color")
- var/new_ballscolor = input(user, "Testicle Color:", "Character Preference") as color|null
- if(new_ballscolor)
- var/temp_hsv = RGBtoHSV(new_ballscolor)
- if(new_ballscolor == "#000000")
- features["balls_color"] = pref_species.default_color
- else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
- features["balls_color"] = sanitize_hexcolor(new_ballscolor)
- else
- user << "Invalid color. Your color is not bright enough."
-
- if("egg_size")
- var/new_size
- var/list/egg_sizes = list(1,2,3)
- new_size = input(user, "Egg Diameter(inches):", "Egg Size") as null|anything in egg_sizes
- if(new_size)
- features["eggsack_egg_size"] = new_size
-
- if("egg_color")
- var/new_egg_color = input(user, "Egg Color:", "Character Preference") as color|null
- if(new_egg_color)
- var/temp_hsv = RGBtoHSV(new_egg_color)
- if(ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
- features["eggsack_egg_color"] = sanitize_hexcolor(new_egg_color)
- else
- user << "Invalid color. Your color is not bright enough."
-
- if("breasts_size")
- var/new_size
- new_size = input(user, "Breast Size", "Character Preference") as null|anything in GLOB.breasts_size_list
- if(new_size)
- features["breasts_size"] = new_size
-
- if("breasts_shape")
- var/new_shape
- new_shape = input(user, "Breast Shape", "Character Preference") as null|anything in GLOB.breasts_shapes_list
- if(new_shape)
- features["breasts_shape"] = new_shape
-
- if("breasts_color")
- var/new_breasts_color = input(user, "Breast Color:", "Character Preference") as color|null
- if(new_breasts_color)
- var/temp_hsv = RGBtoHSV(new_breasts_color)
- if(new_breasts_color == "#000000")
- features["breasts_color"] = pref_species.default_color
- else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
- features["breasts_color"] = sanitize_hexcolor(new_breasts_color)
- else
- user << "Invalid color. Your color is not bright enough."
-
- if("vag_shape")
- var/new_shape
- new_shape = input(user, "Vagina Type", "Character Preference") as null|anything in GLOB.vagina_shapes_list
- if(new_shape)
- features["vag_shape"] = new_shape
-
- if("vag_color")
- var/new_vagcolor = input(user, "Vagina color:", "Character Preference") as color|null
- if(new_vagcolor)
- var/temp_hsv = RGBtoHSV(new_vagcolor)
- if(new_vagcolor == "#000000")
- features["vag_color"] = pref_species.default_color
- else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
- features["vag_color"] = sanitize_hexcolor(new_vagcolor)
- else
- user << "Invalid color. Your color is not bright enough."
-
- if("ooccolor")
- var/new_ooccolor = input(user, "Choose your OOC colour:", "Game Preference",ooccolor) as color|null
- if(new_ooccolor)
- ooccolor = new_ooccolor
-
- if("bag")
- var/new_backbag = input(user, "Choose your character's style of bag:", "Character Preference") as null|anything in GLOB.backbaglist
- if(new_backbag)
- backbag = new_backbag
-
- if("uplink_loc")
- var/new_loc = input(user, "Choose your character's traitor uplink spawn location:", "Character Preference") as null|anything in GLOB.uplink_spawn_loc_list
- if(new_loc)
- uplink_spawn_loc = new_loc
-
- if("sec_dept")
- var/department = input(user, "Choose your prefered security department:", "Security Departments") as null|anything in GLOB.security_depts_prefs
- if(department)
- prefered_security_department = department
-
- if ("preferred_map")
- var/maplist = list()
- var/default = "Default"
- if (config.defaultmap)
- default += " ([config.defaultmap.map_name])"
- for (var/M in config.maplist)
- var/datum/map_config/VM = config.maplist[M]
- var/friendlyname = "[VM.map_name] "
- if (VM.voteweight <= 0)
- friendlyname += " (disabled)"
- maplist[friendlyname] = VM.map_name
- maplist[default] = null
- var/pickedmap = input(user, "Choose your preferred map. This will be used to help weight random map selection.", "Character Preference") as null|anything in maplist
- if (pickedmap)
- preferred_map = maplist[pickedmap]
-
- if ("clientfps")
- var/desiredfps = input(user, "Choose your desired fps. (0 = synced with server tick rate (currently:[world.fps]))", "Character Preference", clientfps) as null|num
- if (!isnull(desiredfps))
- clientfps = desiredfps
- parent.fps = desiredfps
- if("ui")
- var/pickedui = input(user, "Choose your UI style.", "Character Preference", UI_style) as null|anything in GLOB.available_ui_styles
- if(pickedui)
- UI_style = pickedui
- if (parent && parent.mob && parent.mob.hud_used)
- parent.mob.hud_used.update_ui_style(ui_style2icon(UI_style))
- if("pda_style")
- var/pickedPDAStyle = input(user, "Choose your PDA style.", "Character Preference", pda_style) as null|anything in GLOB.pda_styles
- if(pickedPDAStyle)
- pda_style = pickedPDAStyle
- if("pda_color")
- var/pickedPDAColor = input(user, "Choose your PDA Interface color.", "Character Preference",pda_color) as color|null
- if(pickedPDAColor)
- pda_color = pickedPDAColor
-
- else
- switch(href_list["preference"])
- //CITADEL PREFERENCES EDIT - I can't figure out how to modularize these, so they have to go here. :c -Pooj
- if("genital_colour")
- features["genitals_use_skintone"] = !features["genitals_use_skintone"]
- if("arousable")
- arousable = !arousable
- if("has_cock")
- features["has_cock"] = !features["has_cock"]
- if("has_balls")
- features["has_balls"] = !features["has_balls"]
- if("has_ovi")
- features["has_ovi"] = !features["has_ovi"]
- if("has_eggsack")
- features["has_eggsack"] = !features["has_eggsack"]
- if("balls_internal")
- features["balls_internal"] = !features["balls_internal"]
- if("eggsack_internal")
- features["eggsack_internal"] = !features["eggsack_internal"]
- if("has_breasts")
- features["has_breasts"] = !features["has_breasts"]
- if("has_vag")
- features["has_vag"] = !features["has_vag"]
- if("has_womb")
- features["has_womb"] = !features["has_womb"]
- if("exhibitionist")
- features["exhibitionist"] = !features["exhibitionist"]
- if("widescreenpref")
- widescreenpref = !widescreenpref
- user.client.change_view(CONFIG_GET(string/default_view))
- if("autostand")
- autostand = !autostand
- if ("screenshake")
- var/desiredshake = input(user, "Set the amount of screenshake you want. \n(0 = disabled, 100 = full, 200 = maximum.)", "Character Preference", screenshake) as null|num
- if (!isnull(desiredshake))
- screenshake = desiredshake
- if("damagescreenshake")
- switch(damagescreenshake)
- if(0)
- damagescreenshake = 1
- if(1)
- damagescreenshake = 2
- if(2)
- damagescreenshake = 0
- else
- damagescreenshake = 1
- //END CITADEL EDIT
- if("publicity")
- if(unlock_content)
- toggles ^= MEMBER_PUBLIC
- if("gender")
- var/chosengender = input(user, "Select your character's gender.", "Gender Selection", gender) in list(MALE,FEMALE,"nonbinary","object")
- switch(chosengender)
- if("nonbinary")
- chosengender = PLURAL
- if("object")
- chosengender = NEUTER
- gender = chosengender
- facial_hair_style = random_facial_hair_style(gender)
- hair_style = random_hair_style(gender)
-
- if("hotkeys")
- hotkeys = !hotkeys
- if(hotkeys)
- winset(user, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=default")
- else
- winset(user, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=old_default")
- if("action_buttons")
- buttons_locked = !buttons_locked
- if("tgui_fancy")
- tgui_fancy = !tgui_fancy
- if("tgui_lock")
- tgui_lock = !tgui_lock
- if("winflash")
- windowflashing = !windowflashing
- if("hear_adminhelps")
- toggles ^= SOUND_ADMINHELP
- if("announce_login")
- toggles ^= ANNOUNCE_LOGIN
- if("combohud_lighting")
- toggles ^= COMBOHUD_LIGHTING
-
- if("be_special")
- var/be_special_type = href_list["be_special_type"]
- if(be_special_type in be_special)
- be_special -= be_special_type
- else
- be_special += be_special_type
-
- if("name")
- be_random_name = !be_random_name
-
- if("all")
- be_random_body = !be_random_body
-
- if("hear_midis")
- toggles ^= SOUND_MIDI
-
- if("lobby_music")
- toggles ^= SOUND_LOBBY
- if((toggles & SOUND_LOBBY) && user.client && isnewplayer(user))
- user.client.playtitlemusic()
- else
- user.stop_sound_channel(CHANNEL_LOBBYMUSIC)
-
- if("ghost_ears")
- chat_toggles ^= CHAT_GHOSTEARS
-
- if("ghost_sight")
- chat_toggles ^= CHAT_GHOSTSIGHT
-
- if("ghost_whispers")
- chat_toggles ^= CHAT_GHOSTWHISPER
-
- if("ghost_radio")
- chat_toggles ^= CHAT_GHOSTRADIO
-
- if("ghost_pda")
- chat_toggles ^= CHAT_GHOSTPDA
-
- if("pull_requests")
- chat_toggles ^= CHAT_PULLR
-
- if("allow_midround_antag")
- toggles ^= MIDROUND_ANTAG
-
- if("parallaxup")
- parallax = WRAP(parallax + 1, PARALLAX_INSANE, PARALLAX_DISABLE + 1)
- if (parent && parent.mob && parent.mob.hud_used)
- parent.mob.hud_used.update_parallax_pref(parent.mob)
-
- if("parallaxdown")
- parallax = WRAP(parallax - 1, PARALLAX_INSANE, PARALLAX_DISABLE + 1)
- if (parent && parent.mob && parent.mob.hud_used)
- parent.mob.hud_used.update_parallax_pref(parent.mob)
-
- // Citadel edit - Prefs don't work outside of this. :c
- if("hound_sleeper")
- cit_toggles ^= MEDIHOUND_SLEEPER
-
- if("toggleeatingnoise")
- cit_toggles ^= EATING_NOISES
-
- if("toggledigestionnoise")
- cit_toggles ^= DIGESTION_NOISES
- //END CITADEL EDIT
-
- if("ambientocclusion")
- ambientocclusion = !ambientocclusion
- if(parent && parent.screen && parent.screen.len)
- var/obj/screen/plane_master/game_world/PM = locate(/obj/screen/plane_master/game_world) in parent.screen
- PM.backdrop(parent.mob)
-
- if("auto_fit_viewport")
- auto_fit_viewport = !auto_fit_viewport
- if(auto_fit_viewport && parent)
- parent.fit_viewport()
-
- if("save")
- save_preferences()
- save_character()
-
- if("load")
- load_preferences()
- load_character()
- if(parent && parent.prefs_vr)
- attempt_vr(parent.prefs_vr,"load_vore","")
-
- if("changeslot")
- if(!load_character(text2num(href_list["num"])))
- random_character()
- real_name = random_unique_name(gender)
- save_character()
- if(parent && parent.prefs_vr)
- attempt_vr(parent.prefs_vr,"load_vore","")
-
- if("tab")
- if (href_list["tab"])
- current_tab = text2num(href_list["tab"])
- if(href_list["preference"] == "gear")
- if(href_list["clear_loadout"])
- LAZYCLEARLIST(chosen_gear)
- gear_points = initial(gear_points)
- save_preferences()
- if(href_list["select_category"])
- for(var/i in GLOB.loadout_items)
- if(i == href_list["select_category"])
- gear_tab = i
- if(href_list["toggle_gear_path"])
- var/datum/gear/G = GLOB.loadout_items[gear_tab][html_decode(href_list["toggle_gear_path"])]
- if(!G)
- return
- var/toggle = text2num(href_list["toggle_gear"])
- if(!toggle && (G.type in chosen_gear))//toggling off and the item effectively is in chosen gear)
- LAZYREMOVE(chosen_gear, G.type)
- gear_points += initial(G.cost)
- else if(toggle && (!(is_type_in_ref_list(G, chosen_gear))))
- if(!is_loadout_slot_available(G.category))
- to_chat(user, "You cannot take this loadout, as you've already chosen too many of the same category!")
- return
- if(G.ckeywhitelist && G.ckeywhitelist.len && !(user.ckey in G.ckeywhitelist))
- to_chat(user, "This is an item intended for donator use only. You are not authorized to use this item.")
- return
- if(gear_points >= initial(G.cost))
- LAZYADD(chosen_gear, G.type)
- gear_points -= initial(G.cost)
-
- ShowChoices(user)
- return 1
-
-/datum/preferences/proc/copy_to(mob/living/carbon/human/character, icon_updates = 1, roundstart_checks = TRUE)
- if(be_random_name)
- real_name = pref_species.random_name(gender)
-
- if(be_random_body)
- random_character(gender)
-
- if(roundstart_checks)
- if(CONFIG_GET(flag/humans_need_surnames) && (pref_species.id == "human"))
- var/firstspace = findtext(real_name, " ")
- var/name_length = length(real_name)
- if(!firstspace) //we need a surname
- real_name += " [pick(GLOB.last_names)]"
- else if(firstspace == name_length)
- real_name += "[pick(GLOB.last_names)]"
-
- character.real_name = real_name
- character.name = character.real_name
-
- character.gender = gender
- character.age = age
-
- character.eye_color = eye_color
- var/obj/item/organ/eyes/organ_eyes = character.getorgan(/obj/item/organ/eyes)
- if(organ_eyes)
- if(!initial(organ_eyes.eye_color))
- organ_eyes.eye_color = eye_color
- organ_eyes.old_eye_color = eye_color
- character.hair_color = hair_color
- character.facial_hair_color = facial_hair_color
-
- character.skin_tone = skin_tone
- character.hair_style = hair_style
- character.facial_hair_style = facial_hair_style
- character.underwear = underwear
- character.undershirt = undershirt
- character.socks = socks
-
- character.backbag = backbag
-
- var/datum/species/chosen_species
- if(!roundstart_checks || (pref_species.id in GLOB.roundstart_races))
- chosen_species = pref_species.type
- else
- chosen_species = /datum/species/human
- pref_species = new /datum/species/human
- save_character()
-
- character.set_species(chosen_species, icon_update = FALSE, pref_load = TRUE)
- character.dna.features = features.Copy()
- character.dna.real_name = character.real_name
-
- if("tail_lizard" in pref_species.default_features)
- character.dna.species.mutant_bodyparts |= "tail_lizard"
- else if("mam_tail" in pref_species.default_features)
- character.dna.species.mutant_bodyparts |= "mam_tail"
- else if("xenotail" in pref_species.default_features)
- character.dna.species.mutant_bodyparts |= "xenotail"
-
- if("legs" in pref_species.default_features)
- if(character.dna.features["legs"] == "Digitigrade Legs")
- pref_species.species_traits += DIGITIGRADE
- character.Digitigrade_Leg_Swap(FALSE)
-
- if(character.dna.features["legs"] == "Normal Legs" && DIGITIGRADE in pref_species.species_traits)
- pref_species.species_traits -= DIGITIGRADE
- character.Digitigrade_Leg_Swap(TRUE)
-
- else if((!"legs" in pref_species.default_features) && DIGITIGRADE in pref_species.species_traits)
- pref_species.species_traits -= DIGITIGRADE
- character.Digitigrade_Leg_Swap(TRUE)
-
- if(DIGITIGRADE in pref_species.species_traits)
- character.Digitigrade_Leg_Swap(FALSE)
-
- if(icon_updates)
- character.update_body()
- character.update_hair()
- character.update_body_parts()
-
-/datum/preferences/proc/get_default_name(name_id)
- switch(name_id)
- if("human")
- return random_unique_name()
- if("ai")
- return pick(GLOB.ai_names)
- if("cyborg")
- return DEFAULT_CYBORG_NAME
- if("clown")
- return pick(GLOB.clown_names)
- if("mime")
- return pick(GLOB.mime_names)
- return random_unique_name()
-
-/datum/preferences/proc/ask_for_custom_name(mob/user,name_id)
- var/namedata = GLOB.preferences_custom_names[name_id]
- if(!namedata)
- return
-
- var/raw_name = input(user, "Choose your character's [namedata["qdesc"]]:","Character Preference") as text|null
- if(!raw_name)
- if(namedata["allow_null"])
- custom_names[name_id] = get_default_name(name_id)
- else
- return
- else
- var/sanitized_name = reject_bad_name(raw_name,namedata["allow_numbers"])
- if(!sanitized_name)
- to_chat(user, "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z,[namedata["allow_numbers"] ? ",0-9," : ""] -, ' and .")
- return
- else
- custom_names[name_id] = sanitized_name
+ /* CAUTION! CAUTION! CAUTION! CAUTION! CAUTION! *\
+ | THIS FILE CONTAINS HOOKS FOR FOR |
+ | CHANGES SPECIFIC TO CITADEL. IF |
+ | YOU'RE FIXING A MERGE CONFLICT |
+ | HERE, PLEASE ASK FOR REVIEW FROM |
+ | ANOTHER MAINTAINER TO ENSURE YOU |
+ | DON'T INTRODUCE REGRESSIONS. |
+ \* */
+
+GLOBAL_LIST_EMPTY(preferences_datums)
+
+/datum/preferences
+ var/client/parent
+ //doohickeys for savefiles
+ var/path
+ var/default_slot = 1 //Holder so it doesn't default to slot 1, rather the last one used
+ var/max_save_slots = 8
+
+ //non-preference stuff
+ var/muted = 0
+ var/last_ip
+ var/last_id
+
+ //game-preferences
+ var/lastchangelog = "" //Saved changlog filesize to detect if there was a change
+ var/ooccolor = null
+ var/enable_tips = TRUE
+ var/tip_delay = 500 //tip delay in milliseconds
+
+ //Antag preferences
+ var/list/be_special = list() //Special role selection
+ var/tmp/old_be_special = 0 //Bitflag version of be_special, used to update old savefiles and nothing more
+ //If it's 0, that's good, if it's anything but 0, the owner of this prefs file's antag choices were,
+ //autocorrected this round, not that you'd need to check that.
+
+
+ var/UI_style = null
+ var/buttons_locked = FALSE
+ var/hotkeys = FALSE
+ var/tgui_fancy = TRUE
+ var/tgui_lock = TRUE
+ var/windowflashing = TRUE
+ var/toggles = TOGGLES_DEFAULT
+ var/db_flags
+ var/chat_toggles = TOGGLES_DEFAULT_CHAT
+ var/ghost_form = "ghost"
+ var/ghost_orbit = GHOST_ORBIT_CIRCLE
+ var/ghost_accs = GHOST_ACCS_DEFAULT_OPTION
+ var/ghost_others = GHOST_OTHERS_DEFAULT_OPTION
+ var/ghost_hud = 1
+ var/inquisitive_ghost = 1
+ var/allow_midround_antag = 1
+ var/preferred_map = null
+ var/pda_style = MONO
+ var/pda_color = "#808000"
+
+ var/uses_glasses_colour = 0
+
+ //character preferences
+ var/real_name //our character's name
+ var/nameless = FALSE //whether or not our character is nameless
+ var/be_random_name = 0 //whether we'll have a random name every round
+ var/be_random_body = 0 //whether we'll have a random body every round
+ var/gender = MALE //gender of character (well duh)
+ var/age = 30 //age of character
+ var/underwear = "Nude" //underwear type
+ var/undershirt = "Nude" //undershirt type
+ var/socks = "Nude" //socks type
+ var/backbag = DBACKPACK //backpack type
+ var/hair_style = "Bald" //Hair type
+ var/hair_color = "000" //Hair color
+ var/facial_hair_style = "Shaved" //Face hair type
+ var/facial_hair_color = "000" //Facial hair color
+ var/skin_tone = "caucasian1" //Skin color
+ var/eye_color = "000" //Eye color
+ var/datum/species/pref_species = new /datum/species/human() //Mutant race
+ var/list/features = list("mcolor" = "FFF",
+ "tail_lizard" = "Smooth", "tail_human" = "Cat",
+ "snout" = "Round", "horns" = "None", "ears" = "Cat",
+ "wings" = "None", "frills" = "None", "spines" = "None",
+ "body_markings" = "None", "legs" = "Normal Legs", "moth_wings" = "Plain")
+
+ var/list/custom_names = list()
+ var/prefered_security_department = SEC_DEPT_RANDOM
+
+ //Quirk list
+ var/list/positive_quirks = list()
+ var/list/negative_quirks = list()
+ var/list/neutral_quirks = list()
+ var/list/all_quirks = list()
+ var/list/character_quirks = list()
+
+ //Jobs, uses bitflags
+ var/job_civilian_high = 0
+ var/job_civilian_med = 0
+ var/job_civilian_low = 0
+
+ var/job_medsci_high = 0
+ var/job_medsci_med = 0
+ var/job_medsci_low = 0
+
+ var/job_engsec_high = 0
+ var/job_engsec_med = 0
+ var/job_engsec_low = 0
+
+ // Want randomjob if preferences already filled - Donkie
+ var/joblessrole = BERANDOMJOB //defaults to 1 for fewer assistants
+
+ // 0 = character settings, 1 = game preferences
+ var/current_tab = 0
+
+ var/unlock_content = 0
+
+ var/list/ignoring = list()
+
+ var/clientfps = 0
+
+ var/parallax
+
+ var/ambientocclusion = TRUE
+ var/auto_fit_viewport = TRUE
+
+ var/uplink_spawn_loc = UPLINK_PDA
+
+ var/list/exp = list()
+ var/list/menuoptions
+
+ var/action_buttons_screen_locs = list()
+
+/datum/preferences/New(client/C)
+ parent = C
+
+ for(var/custom_name_id in GLOB.preferences_custom_names)
+ custom_names[custom_name_id] = get_default_name(custom_name_id)
+
+ UI_style = GLOB.available_ui_styles[1]
+ if(istype(C))
+ if(!IsGuestKey(C.key))
+ load_path(C.ckey)
+ unlock_content = C.IsByondMember()
+ if(unlock_content)
+ max_save_slots = 16
+ var/loaded_preferences_successfully = load_preferences()
+ if(loaded_preferences_successfully)
+ if(load_character())
+ return
+ //we couldn't load character data so just randomize the character appearance + name
+ random_character() //let's create a random character then - rather than a fat, bald and naked man.
+ real_name = pref_species.random_name(gender,1)
+ if(!loaded_preferences_successfully)
+ save_preferences()
+ save_character() //let's save this new random character so it doesn't keep generating new ones.
+ menuoptions = list()
+ return
+
+#define APPEARANCE_CATEGORY_COLUMN ""
+#define MAX_MUTANT_ROWS 4
+
+/datum/preferences/proc/ShowChoices(mob/user)
+ if(!user || !user.client)
+ return
+ update_preview_icon()
+ var/list/dat = list("")
+
+ dat += "Character Settings"
+ dat += "Character Appearance"
+ dat += "Loadout"
+ dat += "Game Preferences"
+
+ if(!path)
+ dat += " Please create an account to save your preferences "
+
+ dat += ""
+
+ dat += " "
+
+ switch(current_tab)
+ if (0) // Character Settings#
+ if(path)
+ var/savefile/S = new /savefile(path)
+ if(S)
+ dat += ""
+ var/name
+ var/unspaced_slots = 0
+ for(var/i=1, i<=max_save_slots, i++)
+ unspaced_slots++
+ if(unspaced_slots > 4)
+ dat += " "
+ unspaced_slots = 0
+ S.cd = "/character[i]"
+ S["real_name"] >> name
+ if(!name)
+ name = "Character[i]"
+ dat += "[name] "
+ dat += ""
+
+ dat += "Occupation Choices"
+ dat += "Set Occupation Preferences "
+ if(CONFIG_GET(flag/roundstart_traits))
+ dat += "Quirk Setup"
+ dat += "Configure Quirks "
+ dat += "Current Quirks: [all_quirks.len ? all_quirks.Join(", ") : "None"]"
+ dat += "Identity"
+ dat += ""
+
+ //Character Appearance
+ if(2)
+ if(path)
+ var/savefile/S = new /savefile(path)
+ if(S)
+ dat += ""
+ var/name
+ var/unspaced_slots = 0
+ for(var/i=1, i<=max_save_slots, i++)
+ unspaced_slots++
+ if(unspaced_slots > 4)
+ dat += " "
+ unspaced_slots = 0
+ S.cd = "/character[i]"
+ S["real_name"] >> name
+ if(!name)
+ name = "Character[i]"
+ dat += "[name] "
+ dat += ""
+
+ update_preview_icon()
+ dat += ""
+ dat += "Flavor Text"
+ dat += "Set Examine Text "
+ if(lentext(features["flavor_text"]) <= 40)
+ if(!lentext(features["flavor_text"]))
+ dat += "\[...\]"
+ else
+ dat += "[features["flavor_text"]]"
+ else
+ dat += "[TextPreview(features["flavor_text"])]... "
+ dat += "Body"
+ dat += "Gender:[gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))] "
+ dat += "Species:[pref_species.id] "
+ dat += "Random Body "
+ dat += "Always Random Body:[be_random_body ? "Yes" : "No"] "
+
+ var/use_skintones = pref_species.use_skintones
+ if(use_skintones)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Skin Tone"
+
+ dat += "[skin_tone] "
+
+ var/mutant_colors
+ if((MUTCOLORS in pref_species.species_traits) || (MUTCOLORS_PARTSONLY in pref_species.species_traits))
+ if(!use_skintones)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Body Colors"
+
+ dat += "Primary Color: "
+ dat += " Change "
+
+ dat += "Secondary Color: "
+ dat += " Change "
+
+ dat += "Tertiary Color: "
+ dat += " Change "
+ mutant_colors = TRUE
+
+ if((EYECOLOR in pref_species.species_traits) && !(NOEYES in pref_species.species_traits))
+
+ if(!use_skintones && !mutant_colors)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Eye Color"
+
+ dat += " Change "
+
+ dat += " | "
+ else if(use_skintones || mutant_colors)
+ dat += ""
+
+ if(HAIR in pref_species.species_traits)
+
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Hair Style"
+
+ dat += "[hair_style]"
+ dat += "< > "
+ dat += " Change "
+
+ dat += "Facial Hair Style"
+
+ dat += "[facial_hair_style]"
+ dat += "< > "
+ dat += " Change "
+
+ dat += ""
+ //Mutant stuff
+ var/mutant_category = 0
+
+ if("tail_lizard" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Tail"
+
+ dat += "[features["tail_lizard"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+
+ if("mam_tail" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Tail"
+
+ dat += "[features["mam_tail"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("tail_human" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Tail"
+
+ dat += "[features["tail_human"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("snout" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Snout"
+
+ dat += "[features["snout"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("horns" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Horns"
+
+ dat += "[features["horns"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ if("frills" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Frills"
+
+ dat += "[features["frills"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+
+ if("spines" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Spines"
+
+ dat += "[features["spines"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+
+ if("body_markings" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Body Markings"
+
+ dat += "[features["body_markings"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("mam_body_markings" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Species Markings"
+
+ dat += "[features["mam_body_markings"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+
+ if("mam_ears" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Ears"
+
+ dat += "[features["mam_ears"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("ears" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Ears"
+
+ dat += "[features["ears"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("mam_snouts" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Snout"
+
+ dat += "[features["mam_snouts"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("legs" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Legs"
+
+ dat += "[features["legs"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("moth_wings" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Moth wings"
+
+ dat += "[features["moth_wings"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("taur" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Tauric Body"
+
+ dat += "[features["taur"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("wings" in pref_species.mutant_bodyparts && GLOB.r_wings_list.len >1)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Wings"
+
+ dat += "[features["wings"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("xenohead" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Caste Head"
+
+ dat += "[features["xenohead"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("xenotail" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Tail"
+
+ dat += "[features["xenotail"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("xenodorsal" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Dorsal Spines"
+
+ dat += "[features["xenodorsal"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("ipc_screen" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Screen"
+
+ dat += "[features["ipc_screen"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("ipc_antenna" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Antenna"
+
+ dat += "[features["ipc_antenna"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+
+ if(mutant_category)
+ dat += ""
+ mutant_category = 0
+
+ dat += " "
+
+ dat += " | "
+ dat += ""
+
+ if (1) // Game Preferences
+ dat += ""
+ if(unlock_content)
+ dat += "Ghost Form: [ghost_form] "
+ dat += "Ghost Orbit: [ghost_orbit] "
+ var/button_name = "If you see this something went wrong."
+ switch(ghost_accs)
+ if(GHOST_ACCS_FULL)
+ button_name = GHOST_ACCS_FULL_NAME
+ if(GHOST_ACCS_DIR)
+ button_name = GHOST_ACCS_DIR_NAME
+ if(GHOST_ACCS_NONE)
+ button_name = GHOST_ACCS_NONE_NAME
+
+ dat += "Ghost Accessories: [button_name] "
+ switch(ghost_others)
+ if(GHOST_OTHERS_THEIR_SETTING)
+ button_name = GHOST_OTHERS_THEIR_SETTING_NAME
+ if(GHOST_OTHERS_DEFAULT_SPRITE)
+ button_name = GHOST_OTHERS_DEFAULT_SPRITE_NAME
+ if(GHOST_OTHERS_SIMPLE)
+ button_name = GHOST_OTHERS_SIMPLE_NAME
+
+ dat += "Ghosts of Others: [button_name] "
+ dat += " "
+ dat += "FPS: [clientfps] "
+ dat += "Parallax (Fancy Space): "
+ switch (parallax)
+ if (PARALLAX_LOW)
+ dat += "Low"
+ if (PARALLAX_MED)
+ dat += "Medium"
+ if (PARALLAX_INSANE)
+ dat += "Insane"
+ if (PARALLAX_DISABLE)
+ dat += "Disabled"
+ else
+ dat += "High"
+ dat += " "
+ dat += "Ambient Occlusion: [ambientocclusion ? "Enabled" : "Disabled"] "
+ dat += "Fit Viewport: [auto_fit_viewport ? "Auto" : "Manual"] "
+
+ if (CONFIG_GET(flag/maprotation) && CONFIG_GET(flag/tgstyle_maprotation))
+ var/p_map = preferred_map
+ if (!p_map)
+ p_map = "Default"
+ if (config.defaultmap)
+ p_map += " ([config.defaultmap.map_name])"
+ else
+ if (p_map in config.maplist)
+ var/datum/map_config/VM = config.maplist[p_map]
+ if (!VM)
+ p_map += " (No longer exists)"
+ else
+ p_map = VM.map_name
+ else
+ p_map += " (No longer exists)"
+ if(CONFIG_GET(flag/allow_map_voting))
+ dat += "Preferred Map: [p_map] "
+
+ dat += " | "
+
+ dat += "Special Role Settings"
+
+ if(jobban_isbanned(user, ROLE_SYNDICATE))
+ dat += "You are banned from antagonist roles."
+ src.be_special = list()
+
+
+ for (var/i in GLOB.special_roles)
+ if(jobban_isbanned(user, i))
+ dat += "Be [capitalize(i)]: BANNED "
+ else
+ var/days_remaining = null
+ if(ispath(GLOB.special_roles[i]) && CONFIG_GET(flag/use_age_restriction_for_jobs)) //If it's a game mode antag, check if the player meets the minimum age
+ var/mode_path = GLOB.special_roles[i]
+ var/datum/game_mode/temp_mode = new mode_path
+ days_remaining = temp_mode.get_remaining_days(user.client)
+
+ if(days_remaining)
+ dat += "Be [capitalize(i)]: \[IN [days_remaining] DAYS] "
+ else
+ dat += "Be [capitalize(i)]: [(i in be_special) ? "Enabled" : "Disabled"] "
+ dat += "Midround Antagonist: [(toggles & MIDROUND_ANTAG) ? "Enabled" : "Disabled"] "
+
+ dat += " "
+
+ if(3)
+ if(!gear_tab)
+ gear_tab = GLOB.loadout_items[1]
+ dat += ""
+ dat += "| [gear_points] loadout points remaining. \[Clear Loadout\] | "
+ dat += "| You can only choose one item per category, unless it's an item that spawns in your backpack or hands. | "
+ dat += "| "
+ var/firstcat = TRUE
+ for(var/i in GLOB.loadout_items)
+ if(firstcat)
+ firstcat = FALSE
+ else
+ dat += " |"
+ if(i == gear_tab)
+ dat += " [i] "
+ else
+ dat += " [i] "
+ dat += " | "
+ dat += "
| "
+ dat += "| [gear_tab] | "
+ dat += "
| "
+ dat += "| Name | "
+ dat += "Cost | "
+ dat += "Restrictions | "
+ dat += "Description | "
+ for(var/j in GLOB.loadout_items[gear_tab])
+ var/datum/gear/gear = GLOB.loadout_items[gear_tab][j]
+ var/donoritem
+ if(gear.ckeywhitelist && gear.ckeywhitelist.len)
+ donoritem = TRUE
+ if(!(user.ckey in gear.ckeywhitelist))
+ continue
+ var/class_link = ""
+ if(gear.type in chosen_gear)
+ class_link = "style='white-space:normal;' class='linkOn' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(j)];toggle_gear=0'"
+ else if(gear_points <= 0)
+ class_link = "style='white-space:normal;' class='linkOff'"
+ else if(donoritem)
+ class_link = "style='white-space:normal;background:#ebc42e;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(j)];toggle_gear=1'"
+ else
+ class_link = "style='white-space:normal;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(j)];toggle_gear=1'"
+ dat += "| [j] | "
+ dat += "[gear.cost] | "
+ if(islist(gear.restricted_roles))
+ if(gear.restricted_roles.len)
+ dat += ""
+ dat += gear.restricted_roles.Join(";")
+ dat += ""
+ dat += " | [gear.description] | "
+ dat += " "
+
+ dat += " "
+
+ if(!IsGuestKey(user.key))
+ dat += "Undo "
+ dat += "Save Setup "
+
+ dat += "Reset Setup"
+ dat += ""
+
+ winshow(user, "preferences_window", TRUE)
+ var/datum/browser/popup = new(user, "preferences_browser", "Character Setup ", 640, 770)
+ popup.set_content(dat.Join())
+ popup.open(FALSE)
+ onclose(user, "preferences_window", src)
+
+#undef APPEARANCE_CATEGORY_COLUMN
+#undef MAX_MUTANT_ROWS
+
+/datum/preferences/proc/SetChoices(mob/user, limit = 17, list/splitJobs = list("Chief Engineer"), widthPerColumn = 295, height = 620)
+ if(!SSjob)
+ return
+
+ //limit - The amount of jobs allowed per column. Defaults to 17 to make it look nice.
+ //splitJobs - Allows you split the table by job. You can make different tables for each department by including their heads. Defaults to CE to make it look nice.
+ //widthPerColumn - Screen's width for every column.
+ //height - Screen's height.
+
+ var/width = widthPerColumn
+
+ var/HTML = ""
+ if(SSjob.occupations.len <= 0)
+ HTML += "The job SSticker is not yet finished creating jobs, please try again later"
+ HTML += "Done " // Easier to press up here.
+
+ else
+ HTML += "Choose occupation chances "
+ HTML += "Left-click to raise an occupation preference, right-click to lower it.
"
+ HTML += "Done " // Easier to press up here.
+ HTML += ""
+ HTML += "" // Table within a table for alignment, also allows you to easily add more colomns.
+ HTML += ""
+ var/index = -1
+
+ //The job before the current job. I only use this to get the previous jobs color when I'm filling in blank rows.
+ var/datum/job/lastJob
+
+ var/datum/job/overflow = SSjob.GetJob(SSjob.overflow_role)
+
+ for(var/datum/job/job in SSjob.occupations)
+
+ index += 1
+ if((index >= limit) || (job.title in splitJobs))
+ width += widthPerColumn
+ if((index < limit) && (lastJob != null))
+ //If the cells were broken up by a job in the splitJob list then it will fill in the rest of the cells with
+ //the last job's selection color. Creating a rather nice effect.
+ for(var/i = 0, i < (limit - index), i += 1)
+ HTML += "|   |   | "
+ HTML += " | "
+ index = 0
+
+ HTML += "| "
+ var/rank = job.title
+ lastJob = job
+ if(jobban_isbanned(user, rank))
+ HTML += "[rank] | BANNED | "
+ continue
+ var/required_playtime_remaining = job.required_playtime_remaining(user.client)
+ if(required_playtime_remaining)
+ HTML += "[rank] \[ [get_exp_format(required_playtime_remaining)] as [job.get_exp_req_type()] \] | "
+ continue
+ if(!job.player_old_enough(user.client))
+ var/available_in_days = job.available_in_days(user.client)
+ HTML += "[rank] \[IN [(available_in_days)] DAYS\] | "
+ continue
+ if((job_civilian_low & overflow.flag) && (rank != SSjob.overflow_role) && !jobban_isbanned(user, SSjob.overflow_role))
+ HTML += "[rank] | "
+ continue
+ if((rank in GLOB.command_positions) || (rank == "AI"))//Bold head jobs
+ HTML += "[rank]"
+ else
+ HTML += "[rank]"
+
+ HTML += ""
+
+ var/prefLevelLabel = "ERROR"
+ var/prefLevelColor = "pink"
+ var/prefUpperLevel = -1 // level to assign on left click
+ var/prefLowerLevel = -1 // level to assign on right click
+
+ if(GetJobDepartment(job, 1) & job.flag)
+ prefLevelLabel = "High"
+ prefLevelColor = "slateblue"
+ prefUpperLevel = 4
+ prefLowerLevel = 2
+ else if(GetJobDepartment(job, 2) & job.flag)
+ prefLevelLabel = "Medium"
+ prefLevelColor = "green"
+ prefUpperLevel = 1
+ prefLowerLevel = 3
+ else if(GetJobDepartment(job, 3) & job.flag)
+ prefLevelLabel = "Low"
+ prefLevelColor = "orange"
+ prefUpperLevel = 2
+ prefLowerLevel = 4
+ else
+ prefLevelLabel = "NEVER"
+ prefLevelColor = "red"
+ prefUpperLevel = 3
+ prefLowerLevel = 1
+
+
+ HTML += ""
+
+ if(rank == SSjob.overflow_role)//Overflow is special
+ if(job_civilian_low & overflow.flag)
+ HTML += "Yes"
+ else
+ HTML += "No"
+ HTML += " | "
+ continue
+
+ HTML += "[prefLevelLabel]"
+ HTML += ""
+
+ for(var/i = 1, i < (limit - index), i += 1) // Finish the column so it is even
+ HTML += "|   |   | "
+
+ HTML += " "
+ HTML += " | "
+
+ var/message = "Be an [SSjob.overflow_role] if preferences unavailable"
+ if(joblessrole == BERANDOMJOB)
+ message = "Get random job if preferences unavailable"
+ else if(joblessrole == RETURNTOLOBBY)
+ message = "Return to lobby if preferences unavailable"
+ HTML += " [message]"
+ HTML += "Reset Preferences"
+
+ var/datum/browser/popup = new(user, "mob_occupation", "Occupation Preferences ", width, height)
+ popup.set_window_options("can_close=0")
+ popup.set_content(HTML)
+ popup.open(FALSE)
+
+/datum/preferences/proc/SetJobPreferenceLevel(datum/job/job, level)
+ if (!job)
+ return 0
+
+ if (level == 1) // to high
+ // remove any other job(s) set to high
+ job_civilian_med |= job_civilian_high
+ job_engsec_med |= job_engsec_high
+ job_medsci_med |= job_medsci_high
+ job_civilian_high = 0
+ job_engsec_high = 0
+ job_medsci_high = 0
+
+ if (job.department_flag == CIVILIAN)
+ job_civilian_low &= ~job.flag
+ job_civilian_med &= ~job.flag
+ job_civilian_high &= ~job.flag
+
+ switch(level)
+ if (1)
+ job_civilian_high |= job.flag
+ if (2)
+ job_civilian_med |= job.flag
+ if (3)
+ job_civilian_low |= job.flag
+
+ return 1
+ else if (job.department_flag == ENGSEC)
+ job_engsec_low &= ~job.flag
+ job_engsec_med &= ~job.flag
+ job_engsec_high &= ~job.flag
+
+ switch(level)
+ if (1)
+ job_engsec_high |= job.flag
+ if (2)
+ job_engsec_med |= job.flag
+ if (3)
+ job_engsec_low |= job.flag
+
+ return 1
+ else if (job.department_flag == MEDSCI)
+ job_medsci_low &= ~job.flag
+ job_medsci_med &= ~job.flag
+ job_medsci_high &= ~job.flag
+
+ switch(level)
+ if (1)
+ job_medsci_high |= job.flag
+ if (2)
+ job_medsci_med |= job.flag
+ if (3)
+ job_medsci_low |= job.flag
+
+ return 1
+
+ return 0
+
+/datum/preferences/proc/UpdateJobPreference(mob/user, role, desiredLvl)
+ if(!SSjob || SSjob.occupations.len <= 0)
+ return
+ var/datum/job/job = SSjob.GetJob(role)
+
+ if(!job)
+ user << browse(null, "window=mob_occupation")
+ ShowChoices(user)
+ return
+
+ if (!isnum(desiredLvl))
+ to_chat(user, "UpdateJobPreference - desired level was not a number. Please notify coders!")
+ ShowChoices(user)
+ return
+
+ if(role == SSjob.overflow_role)
+ if(job_civilian_low & job.flag)
+ job_civilian_low &= ~job.flag
+ else
+ job_civilian_low |= job.flag
+ SetChoices(user)
+ return 1
+
+ SetJobPreferenceLevel(job, desiredLvl)
+ SetChoices(user)
+
+ return 1
+
+
+/datum/preferences/proc/ResetJobs()
+
+ job_civilian_high = 0
+ job_civilian_med = 0
+ job_civilian_low = 0
+
+ job_medsci_high = 0
+ job_medsci_med = 0
+ job_medsci_low = 0
+
+ job_engsec_high = 0
+ job_engsec_med = 0
+ job_engsec_low = 0
+
+
+/datum/preferences/proc/GetJobDepartment(datum/job/job, level)
+ if(!job || !level)
+ return 0
+ switch(job.department_flag)
+ if(CIVILIAN)
+ switch(level)
+ if(1)
+ return job_civilian_high
+ if(2)
+ return job_civilian_med
+ if(3)
+ return job_civilian_low
+ if(MEDSCI)
+ switch(level)
+ if(1)
+ return job_medsci_high
+ if(2)
+ return job_medsci_med
+ if(3)
+ return job_medsci_low
+ if(ENGSEC)
+ switch(level)
+ if(1)
+ return job_engsec_high
+ if(2)
+ return job_engsec_med
+ if(3)
+ return job_engsec_low
+ return 0
+
+/datum/preferences/proc/SetQuirks(mob/user)
+ if(!SSquirks)
+ to_chat(user, "The quirk subsystem is still initializing! Try again in a minute.")
+ return
+
+ var/list/dat = list()
+ if(!SSquirks.quirks.len)
+ dat += "The quirk subsystem hasn't finished initializing, please hold..."
+ dat += "Done "
+
+ else
+ dat += "Choose quirk setup "
+ dat += "Left-click to add or remove quirks. You need negative quirks to have positive ones. \
+ Quirks are applied at roundstart and cannot normally be removed. "
+ dat += "Done"
+ dat += " "
+ dat += "Current quirks: [all_quirks.len ? all_quirks.Join(", ") : "None"]"
+ dat += "[positive_quirks.len] / [MAX_QUIRKS] max positive quirks \
+ Quirk balance remaining: [GetQuirkBalance()] "
+ for(var/V in SSquirks.quirks)
+ var/datum/quirk/T = SSquirks.quirks[V]
+ var/quirk_name = initial(T.name)
+ var/has_quirk
+ var/quirk_cost = initial(T.value) * -1
+ var/lock_reason = "This trait is unavailable."
+ var/quirk_conflict = FALSE
+ for(var/_V in all_quirks)
+ if(_V == quirk_name)
+ has_quirk = TRUE
+ if(initial(T.mood_quirk) && CONFIG_GET(flag/disable_human_mood))
+ lock_reason = "Mood is disabled."
+ quirk_conflict = TRUE
+ if(has_quirk)
+ if(quirk_conflict)
+ all_quirks -= quirk_name
+ has_quirk = FALSE
+ else
+ quirk_cost *= -1 //invert it back, since we'd be regaining this amount
+ if(quirk_cost > 0)
+ quirk_cost = "+[quirk_cost]"
+ var/font_color = "#AAAAFF"
+ if(initial(T.value) != 0)
+ font_color = initial(T.value) > 0 ? "#AAFFAA" : "#FFAAAA"
+ if(quirk_conflict)
+ dat += "[quirk_name] - [initial(T.desc)] \
+ LOCKED: [lock_reason] "
+ else
+ if(has_quirk)
+ dat += "[quirk_name] - [initial(T.desc)] \
+ [has_quirk ? "Lose" : "Take"] ([quirk_cost] pts.) "
+ else
+ dat += "[quirk_name] - [initial(T.desc)] \
+ [has_quirk ? "Lose" : "Take"] ([quirk_cost] pts.) "
+ dat += " Reset Traits"
+
+ var/datum/browser/popup = new(user, "mob_occupation", "Quirk Preferences ", 900, 600) //no reason not to reuse the occupation window, as it's cleaner that way
+ popup.set_window_options("can_close=0")
+ popup.set_content(dat.Join())
+ popup.open(FALSE)
+
+/datum/preferences/proc/GetQuirkBalance()
+ var/bal = 0
+ for(var/V in all_quirks)
+ var/datum/quirk/T = SSquirks.quirks[V]
+ bal -= initial(T.value)
+ return bal
+
+/datum/preferences/Topic(href, href_list, hsrc) //yeah, gotta do this I guess..
+ . = ..()
+ if(href_list["close"])
+ var/client/C = usr.client
+ if(C)
+ C.clear_character_previews()
+
+/datum/preferences/proc/process_link(mob/user, list/href_list)
+ if(href_list["jobbancheck"])
+ var/job = sanitizeSQL(href_list["jobbancheck"])
+ var/sql_ckey = sanitizeSQL(user.ckey)
+ var/datum/DBQuery/query_get_jobban = SSdbcore.NewQuery("SELECT reason, bantime, duration, expiration_time, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].a_ckey), a_ckey) FROM [format_table_name("ban")] WHERE ckey = '[sql_ckey]' AND (bantype = 'JOB_PERMABAN' OR (bantype = 'JOB_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned) AND job = '[job]'")
+ if(!query_get_jobban.warn_execute())
+ qdel(query_get_jobban)
+ return
+ if(query_get_jobban.NextRow())
+ var/reason = query_get_jobban.item[1]
+ var/bantime = query_get_jobban.item[2]
+ var/duration = query_get_jobban.item[3]
+ var/expiration_time = query_get_jobban.item[4]
+ var/admin_key = query_get_jobban.item[5]
+ var/text
+ text = "You, or another user of this computer, ([user.key]) is banned from playing [job]. The ban reason is: [reason] This ban was applied by [admin_key] on [bantime]"
+ if(text2num(duration) > 0)
+ text += ". The ban is for [duration] minutes and expires on [expiration_time] (server time)"
+ text += "."
+ to_chat(user, text)
+ qdel(query_get_jobban)
+ return
+
+ if(href_list["preference"] == "job")
+ switch(href_list["task"])
+ if("close")
+ user << browse(null, "window=mob_occupation")
+ ShowChoices(user)
+ if("reset")
+ ResetJobs()
+ SetChoices(user)
+ if("random")
+ switch(joblessrole)
+ if(RETURNTOLOBBY)
+ if(jobban_isbanned(user, SSjob.overflow_role))
+ joblessrole = BERANDOMJOB
+ else
+ joblessrole = BEOVERFLOW
+ if(BEOVERFLOW)
+ joblessrole = BERANDOMJOB
+ if(BERANDOMJOB)
+ joblessrole = RETURNTOLOBBY
+ SetChoices(user)
+ if("setJobLevel")
+ UpdateJobPreference(user, href_list["text"], text2num(href_list["level"]))
+ else
+ SetChoices(user)
+ return 1
+
+ else if(href_list["preference"] == "trait")
+ switch(href_list["task"])
+ if("close")
+ user << browse(null, "window=mob_occupation")
+ ShowChoices(user)
+ if("update")
+ var/quirk = href_list["trait"]
+ if(!SSquirks.quirks[quirk])
+ return
+ var/value = SSquirks.quirk_points[quirk]
+ if(value == 0)
+ if(quirk in neutral_quirks)
+ neutral_quirks -= quirk
+ all_quirks -= quirk
+ else
+ neutral_quirks += quirk
+ all_quirks += quirk
+ else
+ var/balance = GetQuirkBalance()
+ if(quirk in positive_quirks)
+ positive_quirks -= quirk
+ all_quirks -= quirk
+ else if(quirk in negative_quirks)
+ if(balance + value < 0)
+ to_chat(user, "Refunding this would cause you to go below your balance!")
+ return
+ negative_quirks -= quirk
+ all_quirks -= quirk
+ else if(value > 0)
+ if(positive_quirks.len >= MAX_QUIRKS)
+ to_chat(user, "You can't have more than [MAX_QUIRKS] positive quirks!")
+ return
+ if(balance - value < 0)
+ to_chat(user, "You don't have enough balance to gain this quirk!")
+ return
+ positive_quirks += quirk
+ all_quirks += quirk
+ else
+ negative_quirks += quirk
+ all_quirks += quirk
+ SetQuirks(user)
+ if("reset")
+ all_quirks = list()
+ positive_quirks = list()
+ negative_quirks = list()
+ neutral_quirks = list()
+ SetQuirks(user)
+ else
+ SetQuirks(user)
+ return TRUE
+
+ switch(href_list["task"])
+ if("random")
+ switch(href_list["preference"])
+ if("name")
+ real_name = pref_species.random_name(gender,1)
+ if("age")
+ age = rand(AGE_MIN, AGE_MAX)
+ if("hair")
+ hair_color = random_short_color()
+ if("hair_style")
+ hair_style = random_hair_style(gender)
+ if("facial")
+ facial_hair_color = random_short_color()
+ if("facial_hair_style")
+ facial_hair_style = random_facial_hair_style(gender)
+ if("underwear")
+ underwear = random_underwear(gender)
+ if("undershirt")
+ undershirt = random_undershirt(gender)
+ if("socks")
+ socks = random_socks()
+ if(BODY_ZONE_PRECISE_EYES)
+ eye_color = random_eye_color()
+ if("s_tone")
+ skin_tone = random_skin_tone()
+ if("bag")
+ backbag = pick(GLOB.backbaglist)
+ if("all")
+ random_character()
+
+ if("input")
+
+ if(href_list["preference"] in GLOB.preferences_custom_names)
+ ask_for_custom_name(user,href_list["preference"])
+
+
+ switch(href_list["preference"])
+ if("ghostform")
+ if(unlock_content)
+ var/new_form = input(user, "Thanks for supporting BYOND - Choose your ghostly form:","Thanks for supporting BYOND",null) as null|anything in GLOB.ghost_forms
+ if(new_form)
+ ghost_form = new_form
+ if("ghostorbit")
+ if(unlock_content)
+ var/new_orbit = input(user, "Thanks for supporting BYOND - Choose your ghostly orbit:","Thanks for supporting BYOND", null) as null|anything in GLOB.ghost_orbits
+ if(new_orbit)
+ ghost_orbit = new_orbit
+
+ if("ghostaccs")
+ var/new_ghost_accs = alert("Do you want your ghost to show full accessories where possible, hide accessories but still use the directional sprites where possible, or also ignore the directions and stick to the default sprites?",,GHOST_ACCS_FULL_NAME, GHOST_ACCS_DIR_NAME, GHOST_ACCS_NONE_NAME)
+ switch(new_ghost_accs)
+ if(GHOST_ACCS_FULL_NAME)
+ ghost_accs = GHOST_ACCS_FULL
+ if(GHOST_ACCS_DIR_NAME)
+ ghost_accs = GHOST_ACCS_DIR
+ if(GHOST_ACCS_NONE_NAME)
+ ghost_accs = GHOST_ACCS_NONE
+
+ if("ghostothers")
+ var/new_ghost_others = alert("Do you want the ghosts of others to show up as their own setting, as their default sprites or always as the default white ghost?",,GHOST_OTHERS_THEIR_SETTING_NAME, GHOST_OTHERS_DEFAULT_SPRITE_NAME, GHOST_OTHERS_SIMPLE_NAME)
+ switch(new_ghost_others)
+ if(GHOST_OTHERS_THEIR_SETTING_NAME)
+ ghost_others = GHOST_OTHERS_THEIR_SETTING
+ if(GHOST_OTHERS_DEFAULT_SPRITE_NAME)
+ ghost_others = GHOST_OTHERS_DEFAULT_SPRITE
+ if(GHOST_OTHERS_SIMPLE_NAME)
+ ghost_others = GHOST_OTHERS_SIMPLE
+
+ if("name")
+ var/new_name = input(user, "Choose your character's name:", "Character Preference") as text|null
+ if(new_name)
+ new_name = reject_bad_name(new_name)
+ if(new_name)
+ real_name = new_name
+ else
+ to_chat(user, "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and .")
+
+ if("age")
+ var/new_age = input(user, "Choose your character's age:\n([AGE_MIN]-[AGE_MAX])", "Character Preference") as num|null
+ if(new_age)
+ age = max(min( round(text2num(new_age)), AGE_MAX),AGE_MIN)
+
+ if("flavor_text")
+ var/msg = stripped_multiline_input(usr,"Set the flavor text in your 'examine' verb. This can also be used for OOC notes and preferences!","Flavor Text",html_decode(features["flavor_text"]), MAX_MESSAGE_LEN*2, TRUE) as null|message
+ if(!isnull(msg))
+ msg = copytext(msg, 1, MAX_MESSAGE_LEN*2)
+ features["flavor_text"] = msg
+
+ if("hair")
+ var/new_hair = input(user, "Choose your character's hair colour:", "Character Preference","#"+hair_color) as color|null
+ if(new_hair)
+ hair_color = sanitize_hexcolor(new_hair)
+
+ if("hair_style")
+ var/new_hair_style
+ if(gender == MALE)
+ new_hair_style = input(user, "Choose your character's hair style:", "Character Preference") as null|anything in GLOB.hair_styles_male_list
+ else
+ new_hair_style = input(user, "Choose your character's hair style:", "Character Preference") as null|anything in GLOB.hair_styles_female_list
+ if(new_hair_style)
+ hair_style = new_hair_style
+
+ if("next_hair_style")
+ if (gender == MALE)
+ hair_style = next_list_item(hair_style, GLOB.hair_styles_male_list)
+ else
+ hair_style = next_list_item(hair_style, GLOB.hair_styles_female_list)
+
+ if("previous_hair_style")
+ if (gender == MALE)
+ hair_style = previous_list_item(hair_style, GLOB.hair_styles_male_list)
+ else
+ hair_style = previous_list_item(hair_style, GLOB.hair_styles_female_list)
+
+ if("facial")
+ var/new_facial = input(user, "Choose your character's facial-hair colour:", "Character Preference","#"+facial_hair_color) as color|null
+ if(new_facial)
+ facial_hair_color = sanitize_hexcolor(new_facial)
+ if("facial_hair_style")
+ var/new_facial_hair_style
+ if(gender == MALE)
+ new_facial_hair_style = input(user, "Choose your character's facial-hair style:", "Character Preference") as null|anything in GLOB.facial_hair_styles_male_list
+ else
+ new_facial_hair_style = input(user, "Choose your character's facial-hair style:", "Character Preference") as null|anything in GLOB.facial_hair_styles_female_list
+ if(new_facial_hair_style)
+ facial_hair_style = new_facial_hair_style
+
+ if("next_facehair_style")
+ if (gender == MALE)
+ facial_hair_style = next_list_item(facial_hair_style, GLOB.facial_hair_styles_male_list)
+ else
+ facial_hair_style = next_list_item(facial_hair_style, GLOB.facial_hair_styles_female_list)
+ if("previous_facehair_style")
+ if (gender == MALE)
+ facial_hair_style = previous_list_item(facial_hair_style, GLOB.facial_hair_styles_male_list)
+ else
+ facial_hair_style = previous_list_item(facial_hair_style, GLOB.facial_hair_styles_female_list)
+
+ if("underwear")
+ var/new_underwear
+ if(gender == MALE)
+ new_underwear = input(user, "Choose your character's underwear:", "Character Preference") as null|anything in GLOB.underwear_m
+ else
+ new_underwear = input(user, "Choose your character's underwear:", "Character Preference") as null|anything in GLOB.underwear_f
+ if(new_underwear)
+ underwear = new_underwear
+
+ if("undershirt")
+ var/new_undershirt
+ if(gender == MALE)
+ new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in GLOB.undershirt_m
+ else
+ new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in GLOB.undershirt_f
+ if(new_undershirt)
+ undershirt = new_undershirt
+
+ if("socks")
+ var/new_socks
+ new_socks = input(user, "Choose your character's socks:", "Character Preference") as null|anything in GLOB.socks_list
+ if(new_socks)
+ socks = new_socks
+
+ if("eyes")
+ var/new_eyes = input(user, "Choose your character's eye colour:", "Character Preference","#"+eye_color) as color|null
+ if(new_eyes)
+ eye_color = sanitize_hexcolor(new_eyes)
+
+ if("species")
+ var/result = input(user, "Select a species", "Species Selection") as null|anything in GLOB.roundstart_races
+ if(result)
+ var/newtype = GLOB.species_list[result]
+ pref_species = new newtype()
+ //let's ensure that no weird shit happens on species swapping.
+ if(!("body_markings" in pref_species.default_features))
+ features["body_markings"] = "None"
+ if(!("mam_body_markings" in pref_species.default_features))
+ features["mam_body_markings"] = "None"
+ if("mam_body_markings" in pref_species.default_features && features["mam_body_markings"] == "None")
+ features["mam_body_markings"] = "Plain"
+ if("tail_lizard" in pref_species.default_features)
+ features["tail_lizard"] = "Smooth"
+ if("mam_tail" in pref_species.default_features)
+ features["mam_tail"] = "None"
+ if("mam_ears" in pref_species.default_features)
+ features["mam_ears"] = "None"
+ if(pref_species.id == "felinid")
+ features["mam_tail"] = "Cat"
+ features["mam_ears"] = "Cat"
+
+ //Now that we changed our species, we must verify that the mutant colour is still allowed.
+ var/temp_hsv = RGBtoHSV(features["mcolor"])
+ if(features["mcolor"] == "#000" || (!(MUTCOLORS_PARTSONLY in pref_species.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#202020")[3]))
+ features["mcolor"] = pref_species.default_color
+ if(features["mcolor2"] == "#000" || (!(MUTCOLORS_PARTSONLY in pref_species.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#202020")[3]))
+ features["mcolor2"] = pref_species.default_color
+ if(features["mcolor3"] == "#000" || (!(MUTCOLORS_PARTSONLY in pref_species.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#202020")[3]))
+ features["mcolor3"] = pref_species.default_color
+
+ if("mutant_color")
+ var/new_mutantcolor = input(user, "Choose your character's alien/mutant color:", "Character Preference","#"+features["mcolor"]) as color|null
+ if(new_mutantcolor)
+ var/temp_hsv = RGBtoHSV(new_mutantcolor)
+ if(new_mutantcolor == "#000000")
+ features["mcolor"] = pref_species.default_color
+ update_preview_icon()
+ else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) // mutantcolors must be bright, but only if they affect the skin
+ features["mcolor"] = sanitize_hexcolor(new_mutantcolor)
+ update_preview_icon()
+ else
+ to_chat(user, "Invalid color. Your color is not bright enough.")
+
+ if("mutant_color2")
+ var/new_mutantcolor = input(user, "Choose your character's secondary alien/mutant color:", "Character Preference") as color|null
+ if(new_mutantcolor)
+ var/temp_hsv = RGBtoHSV(new_mutantcolor)
+ if(new_mutantcolor == "#000000")
+ features["mcolor2"] = pref_species.default_color
+ update_preview_icon()
+ else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) // mutantcolors must be bright, but only if they affect the skin
+ features["mcolor2"] = sanitize_hexcolor(new_mutantcolor)
+ update_preview_icon()
+ else
+ to_chat(user, "Invalid color. Your color is not bright enough.")
+
+ if("mutant_color3")
+ var/new_mutantcolor = input(user, "Choose your character's tertiary alien/mutant color:", "Character Preference") as color|null
+ if(new_mutantcolor)
+ var/temp_hsv = RGBtoHSV(new_mutantcolor)
+ if(new_mutantcolor == "#000000")
+ features["mcolor3"] = pref_species.default_color
+ update_preview_icon()
+ else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) // mutantcolors must be bright, but only if they affect the skin
+ features["mcolor3"] = sanitize_hexcolor(new_mutantcolor)
+ update_preview_icon()
+ else
+ to_chat(user, "Invalid color. Your color is not bright enough.")
+
+ if("ipc_screen")
+ var/new_ipc_screen
+ new_ipc_screen = input(user, "Choose your character's screen:", "Character Preference") as null|anything in GLOB.ipc_screens_list
+ if(new_ipc_screen)
+ features["ipc_screen"] = new_ipc_screen
+
+ if("ipc_antenna")
+ var/new_ipc_antenna
+ new_ipc_antenna = input(user, "Choose your character's antenna:", "Character Preference") as null|anything in GLOB.ipc_antennas_list
+ if(new_ipc_antenna)
+ features["ipc_antenna"] = new_ipc_antenna
+
+ if("tail_lizard")
+ var/new_tail
+ new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in GLOB.tails_list_lizard
+ if(new_tail)
+ features["tail_lizard"] = new_tail
+ if(new_tail != "None")
+ features["taur"] = "None"
+ features["tail_human"] = "None"
+ features["mam_tail"] = "None"
+
+ if("tail_human")
+ var/list/snowflake_tails_list = list()
+ for(var/path in GLOB.tails_list_human)
+ var/datum/sprite_accessory/tails/human/instance = GLOB.tails_list_human[path]
+ if(istype(instance, /datum/sprite_accessory))
+ var/datum/sprite_accessory/S = instance
+ if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
+ snowflake_tails_list[S.name] = path
+ var/new_tail
+ new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in snowflake_tails_list
+ if(new_tail)
+ features["tail_human"] = new_tail
+ if(new_tail != "None")
+ features["taur"] = "None"
+ features["tail_lizard"] = "None"
+ features["mam_tail"] = "None"
+
+ if("mam_tail")
+ var/list/snowflake_tails_list = list()
+ for(var/path in GLOB.mam_tails_list)
+ var/datum/sprite_accessory/mam_tails/instance = GLOB.mam_tails_list[path]
+ if(istype(instance, /datum/sprite_accessory))
+ var/datum/sprite_accessory/S = instance
+ if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
+ snowflake_tails_list[S.name] = path
+ var/new_tail
+ new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in snowflake_tails_list
+ if(new_tail)
+ features["mam_tail"] = new_tail
+ if(new_tail != "None")
+ features["taur"] = "None"
+ features["tail_human"] = "None"
+ features["tail_lizard"] = "None"
+
+ if("snout")
+ var/new_snout
+ new_snout = input(user, "Choose your character's snout:", "Character Preference") as null|anything in GLOB.snouts_list
+ if(new_snout)
+ features["snout"] = new_snout
+
+ if("mam_snouts")
+ var/new_mam_snouts
+ new_mam_snouts = input(user, "Choose your character's snout:", "Character Preference") as null|anything in GLOB.mam_snouts_list
+ if(new_mam_snouts)
+ features["mam_snouts"] = new_mam_snouts
+
+ if("horns")
+ var/new_horns
+ new_horns = input(user, "Choose your character's horns:", "Character Preference") as null|anything in GLOB.horns_list
+ if(new_horns)
+ features["horns"] = new_horns
+
+ if("ears")
+ var/new_ears
+ new_ears = input(user, "Choose your character's ears:", "Character Preference") as null|anything in GLOB.ears_list
+ if(new_ears)
+ features["ears"] = new_ears
+
+ if("wings")
+ var/new_wings
+ new_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.r_wings_list
+ if(new_wings)
+ features["wings"] = new_wings
+
+ if("frills")
+ var/new_frills
+ new_frills = input(user, "Choose your character's frills:", "Character Preference") as null|anything in GLOB.frills_list
+ if(new_frills)
+ features["frills"] = new_frills
+
+ if("spines")
+ var/new_spines
+ new_spines = input(user, "Choose your character's spines:", "Character Preference") as null|anything in GLOB.spines_list
+ if(new_spines)
+ features["spines"] = new_spines
+
+ if("body_markings")
+ var/new_body_markings
+ new_body_markings = input(user, "Choose your character's body markings:", "Character Preference") as null|anything in GLOB.body_markings_list
+ if(new_body_markings)
+ features["body_markings"] = new_body_markings
+ if(new_body_markings != "None")
+ features["mam_body_markings"] = "None"
+ update_preview_icon()
+
+ if("legs")
+ var/new_legs
+ new_legs = input(user, "Choose your character's legs:", "Character Preference") as null|anything in GLOB.legs_list
+ if(new_legs)
+ features["legs"] = new_legs
+ update_preview_icon()
+
+ if("moth_wings")
+ var/new_moth_wings
+ new_moth_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.moth_wings_list
+ if(new_moth_wings)
+ features["moth_wings"] = new_moth_wings
+
+ if("s_tone")
+ var/new_s_tone = input(user, "Choose your character's skin-tone:", "Character Preference") as null|anything in GLOB.skin_tones
+ if(new_s_tone)
+ skin_tone = new_s_tone
+
+ if("taur")
+ var/list/snowflake_taur_list = list()
+ for(var/path in GLOB.taur_list)
+ var/datum/sprite_accessory/taur/instance = GLOB.taur_list[path]
+ if(istype(instance, /datum/sprite_accessory))
+ var/datum/sprite_accessory/S = instance
+ if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
+ snowflake_taur_list[S.name] = path
+ var/new_taur
+ new_taur = input(user, "Choose your character's tauric body:", "Character Preference") as null|anything in snowflake_taur_list
+ if(new_taur)
+ features["taur"] = new_taur
+ if(new_taur != "None")
+ features["mam_tail"] = "None"
+ features["xenotail"] = "None"
+ features["tail_human"] = "None"
+ features["tail_lizard"] = "None"
+
+ if("ears")
+ var/list/snowflake_ears_list = list()
+ for(var/path in GLOB.ears_list)
+ var/datum/sprite_accessory/ears/instance = GLOB.ears_list[path]
+ if(istype(instance, /datum/sprite_accessory))
+ var/datum/sprite_accessory/S = instance
+ if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
+ snowflake_ears_list[S.name] = path
+ var/new_ears
+ new_ears = input(user, "Choose your character's ears:", "Character Preference") as null|anything in snowflake_ears_list
+ if(new_ears)
+ features["ears"] = new_ears
+
+ if("mam_ears")
+ var/list/snowflake_ears_list = list()
+ for(var/path in GLOB.mam_ears_list)
+ var/datum/sprite_accessory/mam_ears/instance = GLOB.mam_ears_list[path]
+ if(istype(instance, /datum/sprite_accessory))
+ var/datum/sprite_accessory/S = instance
+ if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
+ snowflake_ears_list[S.name] = path
+ var/new_ears
+ new_ears = input(user, "Choose your character's ears:", "Character Preference") as null|anything in snowflake_ears_list
+ if(new_ears)
+ features["mam_ears"] = new_ears
+
+ if("mam_body_markings")
+ var/list/snowflake_markings_list = list()
+ for(var/path in GLOB.mam_body_markings_list)
+ var/datum/sprite_accessory/mam_body_markings/instance = GLOB.mam_body_markings_list[path]
+ if(istype(instance, /datum/sprite_accessory))
+ var/datum/sprite_accessory/S = instance
+ if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
+ snowflake_markings_list[S.name] = path
+ var/new_mam_body_markings
+ new_mam_body_markings = input(user, "Choose your character's body markings:", "Character Preference") as null|anything in snowflake_markings_list
+ if(new_mam_body_markings)
+ features["mam_body_markings"] = new_mam_body_markings
+ if(new_mam_body_markings != "None")
+ features["body_markings"] = "None"
+ else if(new_mam_body_markings == "None")
+ features["mam_body_markings"] = "Plain"
+ features["body_markings"] = "None"
+ update_preview_icon()
+
+ //Xeno Bodyparts
+ if("xenohead")//Head or caste type
+ var/new_head
+ new_head = input(user, "Choose your character's caste:", "Character Preference") as null|anything in GLOB.xeno_head_list
+ if(new_head)
+ features["xenohead"] = new_head
+
+ if("xenotail")//Currently one one type, more maybe later if someone sprites them. Might include animated variants in the future.
+ var/new_tail
+ new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in GLOB.xeno_tail_list
+ if(new_tail)
+ features["xenotail"] = new_tail
+ if(new_tail != "None")
+ features["mam_tail"] = "None"
+ features["taur"] = "None"
+ features["tail_human"] = "None"
+ features["tail_lizard"] = "None"
+
+ if("xenodorsal")
+ var/new_dors
+ new_dors = input(user, "Choose your character's dorsal tube type:", "Character Preference") as null|anything in GLOB.xeno_dorsal_list
+ if(new_dors)
+ features["xenodorsal"] = new_dors
+ //Genital code
+ if("cock_color")
+ var/new_cockcolor = input(user, "Penis color:", "Character Preference") as color|null
+ if(new_cockcolor)
+ var/temp_hsv = RGBtoHSV(new_cockcolor)
+ if(new_cockcolor == "#000000")
+ features["cock_color"] = pref_species.default_color
+ else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
+ features["cock_color"] = sanitize_hexcolor(new_cockcolor)
+ else
+ user << "Invalid color. Your color is not bright enough."
+
+ if("cock_length")
+ var/new_length = input(user, "Penis length in inches:\n([COCK_SIZE_MIN]-[COCK_SIZE_MAX])", "Character Preference") as num|null
+ if(new_length)
+ features["cock_length"] = max(min( round(text2num(new_length)), COCK_SIZE_MAX),COCK_SIZE_MIN)
+
+ if("cock_shape")
+ var/new_shape
+ new_shape = input(user, "Penis shape:", "Character Preference") as null|anything in GLOB.cock_shapes_list
+ if(new_shape)
+ features["cock_shape"] = new_shape
+
+ if("balls_color")
+ var/new_ballscolor = input(user, "Testicle Color:", "Character Preference") as color|null
+ if(new_ballscolor)
+ var/temp_hsv = RGBtoHSV(new_ballscolor)
+ if(new_ballscolor == "#000000")
+ features["balls_color"] = pref_species.default_color
+ else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
+ features["balls_color"] = sanitize_hexcolor(new_ballscolor)
+ else
+ user << "Invalid color. Your color is not bright enough."
+
+ if("egg_size")
+ var/new_size
+ var/list/egg_sizes = list(1,2,3)
+ new_size = input(user, "Egg Diameter(inches):", "Egg Size") as null|anything in egg_sizes
+ if(new_size)
+ features["eggsack_egg_size"] = new_size
+
+ if("egg_color")
+ var/new_egg_color = input(user, "Egg Color:", "Character Preference") as color|null
+ if(new_egg_color)
+ var/temp_hsv = RGBtoHSV(new_egg_color)
+ if(ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
+ features["eggsack_egg_color"] = sanitize_hexcolor(new_egg_color)
+ else
+ user << "Invalid color. Your color is not bright enough."
+
+ if("breasts_size")
+ var/new_size
+ new_size = input(user, "Breast Size", "Character Preference") as null|anything in GLOB.breasts_size_list
+ if(new_size)
+ features["breasts_size"] = new_size
+
+ if("breasts_shape")
+ var/new_shape
+ new_shape = input(user, "Breast Shape", "Character Preference") as null|anything in GLOB.breasts_shapes_list
+ if(new_shape)
+ features["breasts_shape"] = new_shape
+
+ if("breasts_color")
+ var/new_breasts_color = input(user, "Breast Color:", "Character Preference") as color|null
+ if(new_breasts_color)
+ var/temp_hsv = RGBtoHSV(new_breasts_color)
+ if(new_breasts_color == "#000000")
+ features["breasts_color"] = pref_species.default_color
+ else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
+ features["breasts_color"] = sanitize_hexcolor(new_breasts_color)
+ else
+ user << "Invalid color. Your color is not bright enough."
+
+ if("vag_shape")
+ var/new_shape
+ new_shape = input(user, "Vagina Type", "Character Preference") as null|anything in GLOB.vagina_shapes_list
+ if(new_shape)
+ features["vag_shape"] = new_shape
+
+ if("vag_color")
+ var/new_vagcolor = input(user, "Vagina color:", "Character Preference") as color|null
+ if(new_vagcolor)
+ var/temp_hsv = RGBtoHSV(new_vagcolor)
+ if(new_vagcolor == "#000000")
+ features["vag_color"] = pref_species.default_color
+ else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
+ features["vag_color"] = sanitize_hexcolor(new_vagcolor)
+ else
+ user << "Invalid color. Your color is not bright enough."
+
+ if("ooccolor")
+ var/new_ooccolor = input(user, "Choose your OOC colour:", "Game Preference",ooccolor) as color|null
+ if(new_ooccolor)
+ ooccolor = new_ooccolor
+
+ if("bag")
+ var/new_backbag = input(user, "Choose your character's style of bag:", "Character Preference") as null|anything in GLOB.backbaglist
+ if(new_backbag)
+ backbag = new_backbag
+
+ if("uplink_loc")
+ var/new_loc = input(user, "Choose your character's traitor uplink spawn location:", "Character Preference") as null|anything in GLOB.uplink_spawn_loc_list
+ if(new_loc)
+ uplink_spawn_loc = new_loc
+
+ if("sec_dept")
+ var/department = input(user, "Choose your prefered security department:", "Security Departments") as null|anything in GLOB.security_depts_prefs
+ if(department)
+ prefered_security_department = department
+
+ if ("preferred_map")
+ var/maplist = list()
+ var/default = "Default"
+ if (config.defaultmap)
+ default += " ([config.defaultmap.map_name])"
+ for (var/M in config.maplist)
+ var/datum/map_config/VM = config.maplist[M]
+ var/friendlyname = "[VM.map_name] "
+ if (VM.voteweight <= 0)
+ friendlyname += " (disabled)"
+ maplist[friendlyname] = VM.map_name
+ maplist[default] = null
+ var/pickedmap = input(user, "Choose your preferred map. This will be used to help weight random map selection.", "Character Preference") as null|anything in maplist
+ if (pickedmap)
+ preferred_map = maplist[pickedmap]
+
+ if ("clientfps")
+ var/desiredfps = input(user, "Choose your desired fps. (0 = synced with server tick rate (currently:[world.fps]))", "Character Preference", clientfps) as null|num
+ if (!isnull(desiredfps))
+ clientfps = desiredfps
+ parent.fps = desiredfps
+ if("ui")
+ var/pickedui = input(user, "Choose your UI style.", "Character Preference", UI_style) as null|anything in GLOB.available_ui_styles
+ if(pickedui)
+ UI_style = pickedui
+ if (parent && parent.mob && parent.mob.hud_used)
+ parent.mob.hud_used.update_ui_style(ui_style2icon(UI_style))
+ if("pda_style")
+ var/pickedPDAStyle = input(user, "Choose your PDA style.", "Character Preference", pda_style) as null|anything in GLOB.pda_styles
+ if(pickedPDAStyle)
+ pda_style = pickedPDAStyle
+ if("pda_color")
+ var/pickedPDAColor = input(user, "Choose your PDA Interface color.", "Character Preference",pda_color) as color|null
+ if(pickedPDAColor)
+ pda_color = pickedPDAColor
+
+ else
+ switch(href_list["preference"])
+ //CITADEL PREFERENCES EDIT - I can't figure out how to modularize these, so they have to go here. :c -Pooj
+ if("genital_colour")
+ features["genitals_use_skintone"] = !features["genitals_use_skintone"]
+ if("arousable")
+ arousable = !arousable
+ if("has_cock")
+ features["has_cock"] = !features["has_cock"]
+ if("has_balls")
+ features["has_balls"] = !features["has_balls"]
+ if("has_ovi")
+ features["has_ovi"] = !features["has_ovi"]
+ if("has_eggsack")
+ features["has_eggsack"] = !features["has_eggsack"]
+ if("balls_internal")
+ features["balls_internal"] = !features["balls_internal"]
+ if("eggsack_internal")
+ features["eggsack_internal"] = !features["eggsack_internal"]
+ if("has_breasts")
+ features["has_breasts"] = !features["has_breasts"]
+ if("has_vag")
+ features["has_vag"] = !features["has_vag"]
+ if("has_womb")
+ features["has_womb"] = !features["has_womb"]
+ if("exhibitionist")
+ features["exhibitionist"] = !features["exhibitionist"]
+ if("widescreenpref")
+ widescreenpref = !widescreenpref
+ user.client.change_view(CONFIG_GET(string/default_view))
+ if("autostand")
+ autostand = !autostand
+ if ("screenshake")
+ var/desiredshake = input(user, "Set the amount of screenshake you want. \n(0 = disabled, 100 = full, 200 = maximum.)", "Character Preference", screenshake) as null|num
+ if (!isnull(desiredshake))
+ screenshake = desiredshake
+ if("damagescreenshake")
+ switch(damagescreenshake)
+ if(0)
+ damagescreenshake = 1
+ if(1)
+ damagescreenshake = 2
+ if(2)
+ damagescreenshake = 0
+ else
+ damagescreenshake = 1
+ if("nameless")
+ nameless = !nameless
+ //END CITADEL EDIT
+ if("publicity")
+ if(unlock_content)
+ toggles ^= MEMBER_PUBLIC
+ if("gender")
+ var/chosengender = input(user, "Select your character's gender.", "Gender Selection", gender) in list(MALE,FEMALE,"nonbinary","object")
+ switch(chosengender)
+ if("nonbinary")
+ chosengender = PLURAL
+ if("object")
+ chosengender = NEUTER
+ gender = chosengender
+ facial_hair_style = random_facial_hair_style(gender)
+ hair_style = random_hair_style(gender)
+
+ if("hotkeys")
+ hotkeys = !hotkeys
+ if(hotkeys)
+ winset(user, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=default")
+ else
+ winset(user, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=old_default")
+ if("action_buttons")
+ buttons_locked = !buttons_locked
+ if("tgui_fancy")
+ tgui_fancy = !tgui_fancy
+ if("tgui_lock")
+ tgui_lock = !tgui_lock
+ if("winflash")
+ windowflashing = !windowflashing
+ if("hear_adminhelps")
+ toggles ^= SOUND_ADMINHELP
+ if("announce_login")
+ toggles ^= ANNOUNCE_LOGIN
+ if("combohud_lighting")
+ toggles ^= COMBOHUD_LIGHTING
+
+ if("be_special")
+ var/be_special_type = href_list["be_special_type"]
+ if(be_special_type in be_special)
+ be_special -= be_special_type
+ else
+ be_special += be_special_type
+
+ if("name")
+ be_random_name = !be_random_name
+
+ if("all")
+ be_random_body = !be_random_body
+
+ if("hear_midis")
+ toggles ^= SOUND_MIDI
+
+ if("lobby_music")
+ toggles ^= SOUND_LOBBY
+ if((toggles & SOUND_LOBBY) && user.client && isnewplayer(user))
+ user.client.playtitlemusic()
+ else
+ user.stop_sound_channel(CHANNEL_LOBBYMUSIC)
+
+ if("ghost_ears")
+ chat_toggles ^= CHAT_GHOSTEARS
+
+ if("ghost_sight")
+ chat_toggles ^= CHAT_GHOSTSIGHT
+
+ if("ghost_whispers")
+ chat_toggles ^= CHAT_GHOSTWHISPER
+
+ if("ghost_radio")
+ chat_toggles ^= CHAT_GHOSTRADIO
+
+ if("ghost_pda")
+ chat_toggles ^= CHAT_GHOSTPDA
+
+ if("pull_requests")
+ chat_toggles ^= CHAT_PULLR
+
+ if("allow_midround_antag")
+ toggles ^= MIDROUND_ANTAG
+
+ if("parallaxup")
+ parallax = WRAP(parallax + 1, PARALLAX_INSANE, PARALLAX_DISABLE + 1)
+ if (parent && parent.mob && parent.mob.hud_used)
+ parent.mob.hud_used.update_parallax_pref(parent.mob)
+
+ if("parallaxdown")
+ parallax = WRAP(parallax - 1, PARALLAX_INSANE, PARALLAX_DISABLE + 1)
+ if (parent && parent.mob && parent.mob.hud_used)
+ parent.mob.hud_used.update_parallax_pref(parent.mob)
+
+ // Citadel edit - Prefs don't work outside of this. :c
+ if("hound_sleeper")
+ cit_toggles ^= MEDIHOUND_SLEEPER
+
+ if("toggleeatingnoise")
+ cit_toggles ^= EATING_NOISES
+
+ if("toggledigestionnoise")
+ cit_toggles ^= DIGESTION_NOISES
+ //END CITADEL EDIT
+
+ if("ambientocclusion")
+ ambientocclusion = !ambientocclusion
+ if(parent && parent.screen && parent.screen.len)
+ var/obj/screen/plane_master/game_world/PM = locate(/obj/screen/plane_master/game_world) in parent.screen
+ PM.backdrop(parent.mob)
+
+ if("auto_fit_viewport")
+ auto_fit_viewport = !auto_fit_viewport
+ if(auto_fit_viewport && parent)
+ parent.fit_viewport()
+
+ if("save")
+ save_preferences()
+ save_character()
+
+ if("load")
+ load_preferences()
+ load_character()
+ if(parent && parent.prefs_vr)
+ attempt_vr(parent.prefs_vr,"load_vore","")
+
+ if("changeslot")
+ if(!load_character(text2num(href_list["num"])))
+ random_character()
+ real_name = random_unique_name(gender)
+ save_character()
+ if(parent && parent.prefs_vr)
+ attempt_vr(parent.prefs_vr,"load_vore","")
+
+ if("tab")
+ if (href_list["tab"])
+ current_tab = text2num(href_list["tab"])
+ if(href_list["preference"] == "gear")
+ if(href_list["clear_loadout"])
+ LAZYCLEARLIST(chosen_gear)
+ gear_points = initial(gear_points)
+ save_preferences()
+ if(href_list["select_category"])
+ for(var/i in GLOB.loadout_items)
+ if(i == href_list["select_category"])
+ gear_tab = i
+ if(href_list["toggle_gear_path"])
+ var/datum/gear/G = GLOB.loadout_items[gear_tab][html_decode(href_list["toggle_gear_path"])]
+ if(!G)
+ return
+ var/toggle = text2num(href_list["toggle_gear"])
+ if(!toggle && (G.type in chosen_gear))//toggling off and the item effectively is in chosen gear)
+ LAZYREMOVE(chosen_gear, G.type)
+ gear_points += initial(G.cost)
+ else if(toggle && (!(is_type_in_ref_list(G, chosen_gear))))
+ if(!is_loadout_slot_available(G.category))
+ to_chat(user, "You cannot take this loadout, as you've already chosen too many of the same category!")
+ return
+ if(G.ckeywhitelist && G.ckeywhitelist.len && !(user.ckey in G.ckeywhitelist))
+ to_chat(user, "This is an item intended for donator use only. You are not authorized to use this item.")
+ return
+ if(gear_points >= initial(G.cost))
+ LAZYADD(chosen_gear, G.type)
+ gear_points -= initial(G.cost)
+
+ ShowChoices(user)
+ return 1
+
+/datum/preferences/proc/copy_to(mob/living/carbon/human/character, icon_updates = 1, roundstart_checks = TRUE)
+ if(be_random_name)
+ real_name = pref_species.random_name(gender)
+
+ if(be_random_body)
+ random_character(gender)
+
+ if(roundstart_checks)
+ if(CONFIG_GET(flag/humans_need_surnames) && (pref_species.id == "human"))
+ var/firstspace = findtext(real_name, " ")
+ var/name_length = length(real_name)
+ if(!firstspace) //we need a surname
+ real_name += " [pick(GLOB.last_names)]"
+ else if(firstspace == name_length)
+ real_name += "[pick(GLOB.last_names)]"
+
+ character.real_name = nameless ? "[real_name] #[rand(10000, 99999)]" : real_name
+ character.name = character.real_name
+ character.nameless = nameless
+
+ character.gender = gender
+ character.age = age
+
+ character.eye_color = eye_color
+ var/obj/item/organ/eyes/organ_eyes = character.getorgan(/obj/item/organ/eyes)
+ if(organ_eyes)
+ if(!initial(organ_eyes.eye_color))
+ organ_eyes.eye_color = eye_color
+ organ_eyes.old_eye_color = eye_color
+ character.hair_color = hair_color
+ character.facial_hair_color = facial_hair_color
+
+ character.skin_tone = skin_tone
+ character.hair_style = hair_style
+ character.facial_hair_style = facial_hair_style
+ character.underwear = underwear
+ character.undershirt = undershirt
+ character.socks = socks
+
+ character.backbag = backbag
+
+ var/datum/species/chosen_species
+ if(!roundstart_checks || (pref_species.id in GLOB.roundstart_races))
+ chosen_species = pref_species.type
+ else
+ chosen_species = /datum/species/human
+ pref_species = new /datum/species/human
+ save_character()
+
+ character.set_species(chosen_species, icon_update = FALSE, pref_load = TRUE)
+ character.dna.features = features.Copy()
+ character.dna.real_name = character.real_name
+ character.dna.nameless = character.nameless
+
+ if("tail_lizard" in pref_species.default_features)
+ character.dna.species.mutant_bodyparts |= "tail_lizard"
+ else if("mam_tail" in pref_species.default_features)
+ character.dna.species.mutant_bodyparts |= "mam_tail"
+ else if("xenotail" in pref_species.default_features)
+ character.dna.species.mutant_bodyparts |= "xenotail"
+
+ if("legs" in pref_species.default_features)
+ if(character.dna.features["legs"] == "Digitigrade Legs")
+ pref_species.species_traits += DIGITIGRADE
+ character.Digitigrade_Leg_Swap(FALSE)
+
+ if(character.dna.features["legs"] == "Normal Legs" && DIGITIGRADE in pref_species.species_traits)
+ pref_species.species_traits -= DIGITIGRADE
+ character.Digitigrade_Leg_Swap(TRUE)
+
+ else if((!"legs" in pref_species.default_features) && DIGITIGRADE in pref_species.species_traits)
+ pref_species.species_traits -= DIGITIGRADE
+ character.Digitigrade_Leg_Swap(TRUE)
+
+ if(DIGITIGRADE in pref_species.species_traits)
+ character.Digitigrade_Leg_Swap(FALSE)
+
+ if(icon_updates)
+ character.update_body()
+ character.update_hair()
+ character.update_body_parts()
+
+/datum/preferences/proc/get_default_name(name_id)
+ switch(name_id)
+ if("human")
+ return random_unique_name()
+ if("ai")
+ return pick(GLOB.ai_names)
+ if("cyborg")
+ return DEFAULT_CYBORG_NAME
+ if("clown")
+ return pick(GLOB.clown_names)
+ if("mime")
+ return pick(GLOB.mime_names)
+ return random_unique_name()
+
+/datum/preferences/proc/ask_for_custom_name(mob/user,name_id)
+ var/namedata = GLOB.preferences_custom_names[name_id]
+ if(!namedata)
+ return
+
+ var/raw_name = input(user, "Choose your character's [namedata["qdesc"]]:","Character Preference") as text|null
+ if(!raw_name)
+ if(namedata["allow_null"])
+ custom_names[name_id] = get_default_name(name_id)
+ else
+ return
+ else
+ var/sanitized_name = reject_bad_name(raw_name,namedata["allow_numbers"])
+ if(!sanitized_name)
+ to_chat(user, "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z,[namedata["allow_numbers"] ? ",0-9," : ""] -, ' and .")
+ return
+ else
+ custom_names[name_id] = sanitized_name
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index dbf782c5fe..9e19ab65a2 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -235,6 +235,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
//Character
S["real_name"] >> real_name
+ S["nameless"] >> nameless
S["name_is_always_random"] >> be_random_name
S["body_is_always_random"] >> be_random_body
S["gender"] >> gender
@@ -301,6 +302,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["feature_mam_ears"] >> features["mam_ears"]
S["feature_mam_tail_animated"] >> features["mam_tail_animated"]
S["feature_taur"] >> features["taur"]
+ S["feature_mam_snouts"] >> features["mam_snouts"]
//Xeno features
S["feature_xeno_tail"] >> features["xenotail"]
S["feature_xeno_dors"] >> features["xenodorsal"]
@@ -362,6 +364,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
if(!features["mcolor"] || features["mcolor"] == "#000")
features["mcolor"] = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F")
+ nameless = sanitize_integer(nameless, 0, 1, initial(nameless))
be_random_name = sanitize_integer(be_random_name, 0, 1, initial(be_random_name))
be_random_body = sanitize_integer(be_random_body, 0, 1, initial(be_random_body))
@@ -427,6 +430,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
//Character
WRITE_FILE(S["real_name"] , real_name)
+ WRITE_FILE(S["nameless"] , nameless)
WRITE_FILE(S["name_is_always_random"] , be_random_name)
WRITE_FILE(S["body_is_always_random"] , be_random_body)
WRITE_FILE(S["gender"] , gender)
diff --git a/code/modules/client/verbs/aooc.dm b/code/modules/client/verbs/aooc.dm
index 90c0dc5a55..893501a852 100644
--- a/code/modules/client/verbs/aooc.dm
+++ b/code/modules/client/verbs/aooc.dm
@@ -61,7 +61,7 @@
antaglisting |= M.current.client
for(var/mob/M in GLOB.player_list)
- if(M.client && (M.stat == DEAD || M.client.holder))
+ if(M.client && (M.stat == DEAD || M.client.holder) && !istype(M, /mob/dead/new_player))
antaglisting |= M.client
for(var/client/C in antaglisting)
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index 1e65c6ca3f..746d5da60d 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -24,6 +24,8 @@
var/can_flashlight = 0
var/scan_reagents = 0 //Can the wearer see reagents while it's equipped?
+ var/blocks_shove_knockdown = FALSE //Whether wearing the clothing item blocks the ability for shove to knock down.
+
var/clothing_flags = NONE
//Var modification - PLEASE be careful with this I know who you are and where you live
diff --git a/code/modules/clothing/glasses/_glasses.dm b/code/modules/clothing/glasses/_glasses.dm
index a5465354ac..7f7b3ae0ed 100644
--- a/code/modules/clothing/glasses/_glasses.dm
+++ b/code/modules/clothing/glasses/_glasses.dm
@@ -67,6 +67,11 @@
user.visible_message("[user] is putting \the [src] to [user.p_their()] eyes and overloading the brightness! It looks like [user.p_theyre()] trying to commit suicide!")
return BRUTELOSS
+/obj/item/clothing/glasses/meson/prescription
+ name = "prescription optical meson scanner"
+ desc = "Used by engineering and mining staff to see basic structural and terrain layouts through walls, regardless of lighting conditions. This one has prescription lens fitted in."
+ vision_correction = 1
+
/obj/item/clothing/glasses/meson/night
name = "night vision meson scanner"
desc = "An optical meson scanner fitted with an amplified visible light spectrum overlay, providing greater visual clarity in darkness."
@@ -159,6 +164,7 @@
attack_verb = list("sliced")
hitsound = 'sound/weapons/bladeslice.ogg'
sharpness = IS_SHARP
+ vision_correction = 1
glass_colour_type = /datum/client_colour/glass_colour/lightgreen
/obj/item/clothing/glasses/regular
diff --git a/code/modules/clothing/glasses/engine_goggles.dm b/code/modules/clothing/glasses/engine_goggles.dm
index 336881106e..47706a3e1e 100644
--- a/code/modules/clothing/glasses/engine_goggles.dm
+++ b/code/modules/clothing/glasses/engine_goggles.dm
@@ -21,6 +21,11 @@
var/mode = MODE_NONE
var/range = 1
+/obj/item/clothing/glasses/meson/engine/prescription
+ name = "prescription engineering scanner goggles"
+ desc = "Goggles used by engineers. The Meson Scanner mode lets you see basic structural and terrain layouts through walls, the T-ray Scanner mode lets you see underfloor objects such as cables and pipes, and the Radiation Scanner mode let's you see objects contaminated by radiation. Each lens has been replaced with a corrective lens."
+ vision_correction = 1
+
/obj/item/clothing/glasses/meson/engine/Initialize()
. = ..()
START_PROCESSING(SSobj, src)
@@ -137,6 +142,11 @@
modes = list(MODE_NONE = MODE_TRAY, MODE_TRAY = MODE_NONE)
+/obj/item/clothing/glasses/meson/engine/tray/prescription
+ name = "prescription optical t-ray scanner"
+ desc = "Goggles used by engineers. The Meson Scanner mode lets you see basic structural and terrain layouts through walls, the T-ray Scanner mode lets you see underfloor objects such as cables and pipes, and the Radiation Scanner mode let's you see objects contaminated by radiation. This one has a lens that help correct eye sight."
+ vision_correction = 1
+
/obj/item/clothing/glasses/meson/engine/shuttle
name = "shuttle region scanner"
icon_state = "trayson-shuttle"
diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm
index 19bcf470bd..a87e95e28c 100644
--- a/code/modules/clothing/glasses/hud.dm
+++ b/code/modules/clothing/glasses/hud.dm
@@ -37,6 +37,14 @@
hud_type = DATA_HUD_MEDICAL_ADVANCED
glass_colour_type = /datum/client_colour/glass_colour/lightblue
+/obj/item/clothing/glasses/hud/health/prescription
+ name = "prescription health scanner HUD"
+ desc = "A heads-up display, made with a prescription lens, that scans the humans in view and provides accurate data about their health status."
+ icon_state = "healthhud"
+ hud_type = DATA_HUD_MEDICAL_ADVANCED
+ vision_correction = 1
+ glass_colour_type = /datum/client_colour/glass_colour/lightblue
+
/obj/item/clothing/glasses/hud/health/night
name = "night vision health scanner HUD"
desc = "An advanced medical head-up display that allows doctors to find patients in complete darkness."
@@ -62,6 +70,14 @@
hud_type = DATA_HUD_DIAGNOSTIC_BASIC
glass_colour_type = /datum/client_colour/glass_colour/lightorange
+/obj/item/clothing/glasses/hud/diagnostic/prescription
+ name = "prescription diagnostic HUD"
+ desc = "A heads-up display capable of analyzing the integrity and status of robotics and exosuits. This one has a prescription lens."
+ icon_state = "diagnostichud"
+ hud_type = DATA_HUD_DIAGNOSTIC_BASIC
+ vision_correction = 1
+ glass_colour_type = /datum/client_colour/glass_colour/lightorange
+
/obj/item/clothing/glasses/hud/diagnostic/night
name = "night vision diagnostic HUD"
desc = "A robotics diagnostic HUD fitted with a light amplifier."
@@ -78,6 +94,14 @@
hud_type = DATA_HUD_SECURITY_ADVANCED
glass_colour_type = /datum/client_colour/glass_colour/red
+/obj/item/clothing/glasses/hud/security/prescription
+ name = "prescription security HUD"
+ desc = "A heads-up display that scans the humans in view and provides accurate data about their ID status and security records. This one has a prescription lens so you can see the banana peal that slipped you."
+ icon_state = "securityhud"
+ hud_type = DATA_HUD_SECURITY_ADVANCED
+ vision_correction = 1
+ glass_colour_type = /datum/client_colour/glass_colour/red
+
/obj/item/clothing/glasses/hud/security/chameleon
name = "chameleon security HUD"
desc = "A stolen security HUD integrated with Syndicate chameleon technology. Provides flash protection."
diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm
index 7265800c49..ab9ffb9b18 100644
--- a/code/modules/clothing/head/helmet.dm
+++ b/code/modules/clothing/head/helmet.dm
@@ -3,7 +3,7 @@
desc = "Standard Security gear. Protects the head from impacts."
icon_state = "helmet"
item_state = "helmet"
- armor = list("melee" = 35, "bullet" = 30, "laser" = 30,"energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
+ armor = list("melee" = 40, "bullet" = 30, "laser" = 30,"energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
flags_inv = HIDEEARS
cold_protection = HEAD
min_cold_protection_temperature = HELMET_MIN_TEMP_PROTECT
diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm
index ad8fafb872..8b1b1dac25 100644
--- a/code/modules/clothing/head/jobs.dm
+++ b/code/modules/clothing/head/jobs.dm
@@ -139,7 +139,7 @@
name = "security beret"
desc = "A robust beret with the security insignia emblazoned on it. Uses reinforced fabric to offer sufficient protection."
icon_state = "beret_badge"
- armor = list("melee" = 40, "bullet" = 30, "laser" = 30,"energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 20, "acid" = 50)
+ armor = list("melee" = 40, "bullet" = 30, "laser" = 30,"energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
strip_delay = 60
dog_fashion = null
@@ -152,7 +152,7 @@
name = "warden's beret"
desc = "A special beret with the Warden's insignia emblazoned on it. For wardens with class."
icon_state = "wardenberet"
- armor = list("melee" = 40, "bullet" = 30, "laser" = 30, "energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 30, "acid" = 50)
+ armor = list("melee" = 40, "bullet" = 30, "laser" = 30, "energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
strip_delay = 60
/obj/item/clothing/head/beret/sec/navyofficer
diff --git a/code/modules/clothing/spacesuits/miscellaneous.dm b/code/modules/clothing/spacesuits/miscellaneous.dm
index 89f114f7e5..cd8efd74bf 100644
--- a/code/modules/clothing/spacesuits/miscellaneous.dm
+++ b/code/modules/clothing/spacesuits/miscellaneous.dm
@@ -168,6 +168,7 @@ Contains:
strip_delay = 130
item_flags = NODROP
brightness_on = 7
+ resistance_flags = ACID_PROOF
/obj/item/clothing/suit/space/hardsuit/ert
name = "emergency response team suit"
@@ -179,6 +180,7 @@ Contains:
armor = list("melee" = 65, "bullet" = 50, "laser" = 50, "energy" = 50, "bomb" = 50, "bio" = 100, "rad" = 100, "fire" = 80, "acid" = 80)
slowdown = 0
strip_delay = 130
+ resistance_flags = ACID_PROOF
//ERT Security
/obj/item/clothing/head/helmet/space/hardsuit/ert/sec
diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm
index 97c9da289b..b10bf39729 100644
--- a/code/modules/clothing/suits/armor.dm
+++ b/code/modules/clothing/suits/armor.dm
@@ -110,13 +110,14 @@
/obj/item/clothing/suit/armor/riot
name = "riot suit"
- desc = "A suit of semi-flexible polycarbonate body armor with heavy padding to protect against melee attacks."
+ desc = "A suit of semi-flexible polycarbonate body armor with heavy padding to protect against melee attacks. Helps the wearer resist shoving in close quarters."
icon_state = "riot"
item_state = "swat_suit"
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
armor = list("melee" = 50, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 80)
+ blocks_shove_knockdown = TRUE
strip_delay = 80
equip_delay_other = 60
diff --git a/code/modules/clothing/suits/bio.dm b/code/modules/clothing/suits/bio.dm
index cbc8f33e3a..6d9a02e05a 100644
--- a/code/modules/clothing/suits/bio.dm
+++ b/code/modules/clothing/suits/bio.dm
@@ -5,7 +5,7 @@
desc = "A hood that protects the head and face from biological contaminants."
permeability_coefficient = 0.01
clothing_flags = THICKMATERIAL | BLOCK_GAS_SMOKE_EFFECT
- armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 80, "fire" = 30, "acid" = 100)
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 60, "fire" = 30, "acid" = 100)
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEHAIR|HIDEFACIALHAIR|HIDEFACE
resistance_flags = ACID_PROOF
flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH
@@ -22,7 +22,7 @@
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
slowdown = 1
allowed = list(/obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/pen, /obj/item/flashlight/pen, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray)
- armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 80, "fire" = 30, "acid" = 100)
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 60, "fire" = 30, "acid" = 100)
flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT|HIDETAUR
strip_delay = 70
equip_delay_other = 70
diff --git a/code/modules/clothing/suits/reactive_armour.dm b/code/modules/clothing/suits/reactive_armour.dm
index 2516d446d6..5b2291e59c 100644
--- a/code/modules/clothing/suits/reactive_armour.dm
+++ b/code/modules/clothing/suits/reactive_armour.dm
@@ -37,6 +37,7 @@
actions_types = list(/datum/action/item_action/toggle)
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
hit_reaction_chance = 50 // Only on the chest yet blocks all attacks?
+ rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
/obj/item/clothing/suit/armor/reactive/attack_self(mob/user)
active = !(active)
@@ -64,8 +65,9 @@
/obj/item/clothing/suit/armor/reactive/teleport
name = "reactive teleport armor"
desc = "Someone separated our Research Director from his own head!"
- var/tele_range = 6
- var/rad_amount= 15
+ var/tele_range = 8
+ var/rad_amount = 60
+ var/rad_amount_before = 120
reactivearmor_cooldown_duration = 100
/obj/item/clothing/suit/armor/reactive/teleport/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
@@ -79,6 +81,7 @@
owner.visible_message("The reactive teleport system flings [H] clear of [attack_text], shutting itself off in the process!")
playsound(get_turf(owner),'sound/magic/blink.ogg', 100, 1)
var/list/turfs = new/list()
+ var/turf/old = get_turf(src)
for(var/turf/T in orange(tele_range, H))
if(T.density)
continue
@@ -93,7 +96,8 @@
if(!isturf(picked))
return
H.forceMove(picked)
- H.rad_act(rad_amount)
+ radiation_pulse(old, rad_amount_before)
+ radiation_pulse(src, rad_amount)
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
return 1
return 0
@@ -157,6 +161,8 @@
var/tesla_power = 25000
var/tesla_range = 20
var/tesla_flags = TESLA_MOB_DAMAGE | TESLA_OBJ_DAMAGE
+ var/legacy = FALSE
+ var/legacy_dmg = 30
/obj/item/clothing/suit/armor/reactive/tesla/dropped(mob/user)
..()
@@ -179,7 +185,15 @@
owner.visible_message("The tesla capacitors on [owner]'s reactive tesla armor are still recharging! The armor merely emits some sparks.")
return
owner.visible_message("[src] blocks [attack_text], sending out arcs of lightning!")
- tesla_zap(owner, tesla_range, tesla_power, tesla_flags)
+ if(!legacy)
+ tesla_zap(owner, tesla_range, tesla_power, tesla_flags)
+ else
+ for(var/mob/living/M in view(7, owner))
+ if(M == owner)
+ continue
+ owner.Beam(M,icon_state="purple_lightning",icon='icons/effects/effects.dmi',time=5)
+ M.adjustFireLoss(legacy_dmg)
+ playsound(M, 'sound/machines/defib_zap.ogg', 50, 1, -1)
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
return TRUE
diff --git a/code/modules/clothing/under/accessories.dm b/code/modules/clothing/under/accessories.dm
index 6bf96429b9..396bcb4766 100644
--- a/code/modules/clothing/under/accessories.dm
+++ b/code/modules/clothing/under/accessories.dm
@@ -158,14 +158,14 @@
icon_state = "bronze_heart"
/obj/item/clothing/accessory/medal/engineer
- name = "\"Shift's Best Electrician\" award"
- desc = "An award bestowed upon engineers who have excelled at keeping the station running in the best possible condition against all odds."
- icon_state = "engineer"
+ name = "\"Shift's Best Electrician\" award"
+ desc = "An award bestowed upon engineers who have excelled at keeping the station running in the best possible condition against all odds."
+ icon_state = "engineer"
/obj/item/clothing/accessory/medal/greytide
- name = "\"Greytider of the shift\" award"
- desc = "An award for only the most annoying of assistants. Locked doors mean nothing to you and behaving is not in your vocabulary"
- icon_state = "greytide"
+ name = "\"Greytider of the shift\" award"
+ desc = "An award for only the most annoying of assistants. Locked doors mean nothing to you and behaving is not in your vocabulary"
+ icon_state = "greytide"
/obj/item/clothing/accessory/medal/ribbon
name = "ribbon"
@@ -178,9 +178,9 @@
desc = "An award bestowed only upon those cargotechs who have exhibited devotion to their duty in keeping with the highest traditions of Cargonia."
/obj/item/clothing/accessory/medal/ribbon/medical_doctor
- name = "\"doctor of the shift\" award"
- desc = "An award bestowed only upon the most capable doctors who have upheld the Hippocratic Oath to the best of their ability"
- icon_state = "medical_doctor"
+ name = "\"doctor of the shift\" award"
+ desc = "An award bestowed only upon the most capable doctors who have upheld the Hippocratic Oath to the best of their ability"
+ icon_state = "medical_doctor"
/obj/item/clothing/accessory/medal/silver
name = "silver medal"
@@ -211,6 +211,12 @@
desc = "A golden medal awarded exclusively to those promoted to the rank of captain. It signifies the codified responsibilities of a captain to Nanotrasen, and their undisputable authority over their crew."
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
+/obj/item/clothing/accessory/medal/gold/captain/family
+ name = "old medal of captaincy"
+ desc = "A rustic badge pure gold, has been through hell and back by the looks, the syndcate have been after these by the looks of it for generations..."
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 10) //Pure gold
+ materials = list(MAT_GOLD=2000)
+
/obj/item/clothing/accessory/medal/gold/heroism
name = "medal of exceptional heroism"
desc = "An extremely rare golden medal awarded only by CentCom. To receive such a medal is the highest honor and as such, very few exist. This medal is almost never awarded to anybody but commanders."
@@ -234,8 +240,6 @@
name = "nobel sciences award"
desc = "A plasma medal which represents significant contributions to the field of science or engineering."
-
-
////////////
//Armbands//
////////////
diff --git a/code/modules/clothing/under/vg_under.dm b/code/modules/clothing/under/vg_under.dm
index 64bf75d5ac..f416f2ecc5 100644
--- a/code/modules/clothing/under/vg_under.dm
+++ b/code/modules/clothing/under/vg_under.dm
@@ -1,3 +1,6 @@
+// Fixed to work with Citadel code. Apparently none of them had NO_MUTANTRACE flags.
+// I was pissy when I realised how to fix this because it's so fucking easy and nobody apparently had done it.
+
/obj/item/clothing/under/stripper_pink
name = "pink stripper outfit"
icon_state = "stripper_p"
@@ -6,7 +9,7 @@
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/stripper_green
name = "green stripper outfit"
@@ -16,8 +19,7 @@
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/wedding/bride_orange
name = "orange wedding dress"
@@ -28,7 +30,7 @@
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/wedding/bride_purple
name = "purple wedding dress"
@@ -39,7 +41,7 @@
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/wedding/bride_blue
name = "blue wedding dress"
@@ -50,7 +52,7 @@
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/wedding/bride_red
name = "red wedding dress"
@@ -61,7 +63,7 @@
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/wedding/bride_white
name = "white wedding dress"
@@ -72,7 +74,7 @@
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/mankini
name = "pink mankini"
@@ -82,6 +84,7 @@
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/*
/obj/item/clothing/under/psysuit
@@ -126,7 +129,7 @@
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/russobluecamooutfit
name = "russian blue camo"
@@ -137,7 +140,7 @@
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/stilsuit
name = "stillsuit"
@@ -148,7 +151,7 @@
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/aviatoruniform
name = "aviator uniform"
@@ -159,7 +162,7 @@
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/bikersuit
name = "biker's outfit"
@@ -169,7 +172,7 @@
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/jacketsuit
name = "richard's outfit"
@@ -180,7 +183,7 @@
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
obj/item/clothing/under/mega
name = "\improper DRN-001 suit"
@@ -191,7 +194,7 @@ obj/item/clothing/under/mega
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/proto
name = "The Prototype Suit"
@@ -202,7 +205,7 @@ obj/item/clothing/under/mega
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/megax
name = "\improper Maverick Hunter regalia"
@@ -213,7 +216,7 @@ obj/item/clothing/under/mega
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/joe
name = "The Sniper Suit"
@@ -224,7 +227,7 @@ obj/item/clothing/under/mega
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/roll
name = "\improper DRN-002 Dress"
@@ -235,7 +238,7 @@ obj/item/clothing/under/mega
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/gokugidown
name = "turtle hermit undershirt"
@@ -246,7 +249,7 @@ obj/item/clothing/under/mega
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/gokugi
name = "turtle hermit outfit"
@@ -257,7 +260,7 @@ obj/item/clothing/under/mega
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/doomguy
name = "\improper Doomguy's pants"
@@ -268,7 +271,7 @@ obj/item/clothing/under/mega
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/vault13
name = "vault 13 Jumpsuit"
@@ -279,7 +282,7 @@ obj/item/clothing/under/mega
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/vault
name = "vault jumpsuit"
@@ -290,7 +293,7 @@ obj/item/clothing/under/mega
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/clownpiece
name = "Clownpiece's Pierrot suit"
@@ -301,7 +304,7 @@ obj/item/clothing/under/mega
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/cia
name = "casual IAA outfit"
@@ -312,7 +315,7 @@ obj/item/clothing/under/mega
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/greaser
name = "greaser outfit"
@@ -322,7 +325,7 @@ obj/item/clothing/under/mega
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/greaser/New()
var/greaser_colour = "default"
@@ -341,6 +344,8 @@ obj/item/clothing/under/mega
item_color = "greaser_[greaser_colour]"
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
+
/obj/item/clothing/under/wintercasualwear
name = "winter casualwear"
@@ -351,8 +356,7 @@ obj/item/clothing/under/mega
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/casualwear
name = "spring casualwear"
@@ -363,7 +367,7 @@ obj/item/clothing/under/mega
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/keyholesweater
name = "keyhole sweater"
@@ -374,7 +378,7 @@ obj/item/clothing/under/mega
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/casualhoodie
name = "casual hoodie"
@@ -385,8 +389,7 @@ obj/item/clothing/under/mega
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
-
-
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/casualhoodie/skirt
icon_state = "hoodieskirt"
@@ -394,6 +397,8 @@ obj/item/clothing/under/mega
item_color = "hoodieskirt"
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
+
/*
/obj/item/clothing/under/mummy_rags
name = "mummy rags"
@@ -427,3 +432,5 @@ obj/item/clothing/under/mega
can_adjust = 0
icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
+
diff --git a/code/modules/crafting/recipes.dm b/code/modules/crafting/recipes.dm
index 586819ed8f..750b172286 100644
--- a/code/modules/crafting/recipes.dm
+++ b/code/modules/crafting/recipes.dm
@@ -694,10 +694,18 @@
/obj/item/reagent_containers/food/snacks/grown/potato = 1)
category = CAT_MISC
+/datum/crafting_recipe/paperwork
+ name = "Filed Paper Work"
+ result = /obj/item/paper/fluff/jobs/cargo/manifest/paperwork_correct
+ time = 90 //Takes time for people to file and complete paper work!
+ reqs = list(/obj/item/pen = 1,
+ /obj/item/paper/fluff/jobs/cargo/manifest/paperwork = 2)
+ category = CAT_MISC
+
/datum/crafting_recipe/ghettojetpack
name = "Improvised Jetpack"
result = /obj/item/tank/jetpack/improvised
time = 30
reqs = list(/obj/item/tank/internals/oxygen/red = 2, /obj/item/extinguisher = 1, /obj/item/pipe = 3, /obj/item/stack/cable_coil = 30)//red oxygen tank so it looks right
category = CAT_MISC
- tools = list(TOOL_WRENCH, TOOL_WELDER, TOOL_WIRECUTTER)
\ No newline at end of file
+ tools = list(TOOL_WRENCH, TOOL_WELDER, TOOL_WIRECUTTER)
diff --git a/code/modules/detectivework/detective_work.dm b/code/modules/detectivework/detective_work.dm
index 42d6fcbe1e..c892bfeffc 100644
--- a/code/modules/detectivework/detective_work.dm
+++ b/code/modules/detectivework/detective_work.dm
@@ -93,6 +93,15 @@
else if(length(blood_dna))
AddComponent(/datum/component/forensics, null, null, blood_dna)
bloody_hands = rand(2, 4)
+ if(head)
+ head.add_blood_DNA(blood_dna)
+ update_inv_head()
+ else if(wear_mask)
+ wear_mask.add_blood_DNA(blood_dna)
+ update_inv_wear_mask()
+ if(wear_neck)
+ wear_neck.add_blood_DNA(blood_dna)
+ update_inv_neck()
update_inv_gloves() //handles bloody hands overlays and updating
return TRUE
diff --git a/code/modules/events/brand_intelligence.dm b/code/modules/events/brand_intelligence.dm
index e33cfbd25d..a838b62e0d 100644
--- a/code/modules/events/brand_intelligence.dm
+++ b/code/modules/events/brand_intelligence.dm
@@ -18,7 +18,14 @@
"Your money can buy happiness!", \
"Engage direct marketing!", \
"Advertising is legalized lying! But don't let that put you off our great deals!", \
- "You don't want to buy anything? Yeah, well, I didn't want to buy your mom either.")
+ "You don't want to buy anything? Yeah, well, I didn't want to buy your mom either.",
+ "Gamers, rise up!",
+ "Ok, now, this is epic.",
+ "HUMAN FUNNY.",
+ "But I'm already tracer!",
+ "How do I vore people?",
+ "ERP?",
+ "Not epic bros...")
/datum/round_event/brand_intelligence/announce(fake)
diff --git a/code/modules/events/devil.dm b/code/modules/events/devil.dm
index 3760cbe05d..7d6e0bd441 100644
--- a/code/modules/events/devil.dm
+++ b/code/modules/events/devil.dm
@@ -39,6 +39,7 @@
var/datum/job/jobdatum = SSjob.GetJob("Assistant")
devil.job = jobdatum.title
jobdatum.equip(devil)
+ success_spawn = TRUE
return SUCCESSFUL_SPAWN
diff --git a/code/modules/events/ion_storm.dm b/code/modules/events/ion_storm.dm
index ba57643339..3ae71f99d8 100644
--- a/code/modules/events/ion_storm.dm
+++ b/code/modules/events/ion_storm.dm
@@ -12,7 +12,7 @@
var/removeDontImproveChance = 10 //chance the randomly created law replaces a random law instead of simply being added
var/shuffleLawsChance = 10 //chance the AI's laws are shuffled afterwards
var/botEmagChance = 10
- var/announceEvent = ION_RANDOM // -1 means don't announce, 0 means have it randomly announce, 1 means
+ var/announceEvent = ION_RANDOM // -1 means don't announce, 0 means have it randomly announce, 1 means it is announced
var/ionMessage = null
var/ionAnnounceChance = 33
announceWhen = 1
@@ -30,7 +30,7 @@
/datum/round_event/ion_storm/start()
- //AI laws
+ //Generate AI law change
for(var/mob/living/silicon/ai/M in GLOB.alive_mob_list)
M.laws_sanity_check()
if(M.stat != DEAD && M.see_in_dark != 0)
@@ -53,6 +53,31 @@
log_game("Ion storm changed laws of [key_name(M)] to [english_list(M.laws.get_law_list(TRUE, TRUE))]")
M.post_lawchange()
+ //Generate Cyborg law change
+ for(var/mob/living/silicon/robot/M in GLOB.alive_mob_list)
+ M.laws_sanity_check()
+ if(M.stat != DEAD && M.see_in_dark != 0)
+ if(prob(replaceLawsetChance))
+ M.laws.pick_weighted_lawset()
+
+ if(prob(removeRandomLawChance))
+ M.remove_law(rand(1, M.laws.get_law_amount(list(LAW_INHERENT, LAW_SUPPLIED))))
+
+ var/message = ionMessage || generate_ion_law()
+ if(message)
+ if(prob(removeDontImproveChance))
+ M.replace_random_law(message, list(LAW_INHERENT, LAW_SUPPLIED, LAW_ION))
+ else
+ M.add_ion_law(message)
+
+ if(prob(shuffleLawsChance))
+ M.shuffle_laws(list(LAW_INHERENT, LAW_SUPPLIED, LAW_ION))
+
+ log_game("Ion storm changed laws of [key_name(M)] to [english_list(M.laws.get_law_list(TRUE, TRUE))]")
+ M.post_lawchange()
+
+
+ //Chance to emag a Bot
if(botEmagChance)
for(var/mob/living/simple_animal/bot/bot in GLOB.alive_mob_list)
if(prob(botEmagChance))
diff --git a/code/modules/events/vent_clog.dm b/code/modules/events/vent_clog.dm
index 160304b1c3..3945a12a40 100644
--- a/code/modules/events/vent_clog.dm
+++ b/code/modules/events/vent_clog.dm
@@ -79,12 +79,28 @@
typepath = /datum/round_event/vent_clog/beer
max_occurrences = 0
+/datum/round_event/vent_clog/beer
+ reagentsAmount = 100
+
/datum/round_event_control/vent_clog/plasma_decon
name = "Plasma decontamination"
typepath = /datum/round_event/vent_clog/plasma_decon
max_occurrences = 0
-/datum/round_event/vent_clog/beer
+/datum/round_event_control/vent_clog/female
+ name = "FemCum stationwide"
+ typepath = /datum/round_event/vent_clog/female
+ max_occurrences = 0
+
+/datum/round_event/vent_clog/female
+ reagentsAmount = 100
+
+/datum/round_event_control/vent_clog/male
+ name = "Semen stationwide"
+ typepath = /datum/round_event/vent_clog/male
+ max_occurrences = 0
+
+/datum/round_event/vent_clog/male
reagentsAmount = 100
/datum/round_event/vent_clog/beer/announce()
@@ -102,6 +118,30 @@
foam.start()
CHECK_TICK
+/datum/round_event/vent_clog/male/start()
+ for(var/obj/machinery/atmospherics/components/unary/vent in vents)
+ if(vent && vent.loc)
+ var/datum/reagents/R = new/datum/reagents(1000)
+ R.my_atom = vent
+ R.add_reagent("semen", reagentsAmount)
+
+ var/datum/effect_system/foam_spread/foam = new
+ foam.set_up(200, get_turf(vent), R)
+ foam.start()
+ CHECK_TICK
+
+/datum/round_event/vent_clog/female/start()
+ for(var/obj/machinery/atmospherics/components/unary/vent in vents)
+ if(vent && vent.loc)
+ var/datum/reagents/R = new/datum/reagents(1000)
+ R.my_atom = vent
+ R.add_reagent("femcum", reagentsAmount)
+
+ var/datum/effect_system/foam_spread/foam = new
+ foam.set_up(200, get_turf(vent), R)
+ foam.start()
+ CHECK_TICK
+
/datum/round_event/vent_clog/plasma_decon/announce()
priority_announce("We are deploying an experimental plasma decontamination system. Please stand away from the vents and do not breathe the smoke that comes out.", "Central Command Update")
diff --git a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm
index 9256f5bdd1..6594146e81 100644
--- a/code/modules/food_and_drinks/drinks/drinks.dm
+++ b/code/modules/food_and_drinks/drinks/drinks.dm
@@ -120,6 +120,12 @@
I.SwapColor(rgb(255, 0, 220, 255), rgb(0, 0, 0, 0))
B.icon = I
B.name = "broken [name]"
+ if(ranged)
+ var/matrix/M = matrix(B.transform)
+ M.Turn(rand(-170, 170))
+ B.transform = M
+ B.pixel_x = rand(-12, 12)
+ B.pixel_y = rand(-12, 12)
if(prob(33))
new/obj/item/shard(drop_location())
playsound(src, "shatter", 70, 1)
@@ -296,6 +302,12 @@
B.force = 0
B.throwforce = 0
B.desc = "A carton with the bottom half burst open. Might give you a papercut."
+ if(ranged)
+ var/matrix/M = matrix(B.transform)
+ M.Turn(rand(-170, 170))
+ B.transform = M
+ B.pixel_x = rand(-12, 12)
+ B.pixel_y = rand(-12, 12)
transfer_fingerprints_to(B)
qdel(src)
diff --git a/code/modules/food_and_drinks/drinks/drinks/bottle.dm b/code/modules/food_and_drinks/drinks/drinks/bottle.dm
index 3bc7443a9b..46e637e640 100644
--- a/code/modules/food_and_drinks/drinks/drinks/bottle.dm
+++ b/code/modules/food_and_drinks/drinks/drinks/bottle.dm
@@ -23,6 +23,12 @@
var/obj/item/broken_bottle/B = new (loc)
if(!ranged)
thrower.put_in_hands(B)
+ else
+ var/matrix/M = matrix(B.transform)
+ M.Turn(rand(-170, 170))
+ B.transform = M
+ B.pixel_x = rand(-12, 12)
+ B.pixel_y = rand(-12, 12)
B.icon_state = icon_state
var/icon/I = new('icons/obj/drinks.dmi', src.icon_state)
diff --git a/code/modules/food_and_drinks/food/snacks_bread.dm b/code/modules/food_and_drinks/food/snacks_bread.dm
index 0638bfad25..0f11fc8ed2 100644
--- a/code/modules/food_and_drinks/food/snacks_bread.dm
+++ b/code/modules/food_and_drinks/food/snacks_bread.dm
@@ -185,6 +185,17 @@
icon_state = ""
bitesize = 2
+GLOBAL_VAR_INIT(frying_hardmode, TRUE)
+GLOBAL_VAR_INIT(frying_bad_chem_add_volume, TRUE)
+GLOBAL_LIST_INIT(frying_bad_chems, list(
+"bad_food" = 10,
+"clf3" = 2,
+"aranesp" = 2,
+"blackpowder" = 10,
+"phlogiston" = 3,
+"cyanide" = 3,
+))
+
/obj/item/reagent_containers/food/snacks/deepfryholder/Initialize(mapload, obj/item/fried)
. = ..()
name = fried.name //We'll determine the other stuff when it's actually removed
@@ -210,6 +221,13 @@
else
fried.forceMove(src)
trash = fried
+ if(!istype(fried, /obj/item/reagent_containers/food) && GLOB.frying_hardmode && GLOB.frying_bad_chems.len)
+ var/R = rand(1, GLOB.frying_bad_chems.len)
+ var/bad_chem = GLOB.frying_bad_chems[R]
+ var/bad_chem_amount = GLOB.frying_bad_chems[bad_chem]
+ if(GLOB.frying_bad_chem_add_volume)
+ reagents.maximum_volume += bad_chem_amount
+ reagents.add_reagent(bad_chem, bad_chem_amount)
/obj/item/reagent_containers/food/snacks/deepfryholder/Destroy()
if(trash)
diff --git a/code/modules/food_and_drinks/food/snacks_other.dm b/code/modules/food_and_drinks/food/snacks_other.dm
index a2f5b06042..af7a8c06f4 100644
--- a/code/modules/food_and_drinks/food/snacks_other.dm
+++ b/code/modules/food_and_drinks/food/snacks_other.dm
@@ -563,9 +563,9 @@
/obj/item/reagent_containers/food/snacks/tinychocolate
name = "chocolate"
- desc = "A tiny and sweet chocolate."
+ desc = "A tiny and sweet chocolate. Has a 'strawberry' filling!"
icon_state = "tiny_chocolate"
- list_reagents = list("nutriment" = 1, "sugar" = 1, "cocoa" = 1)
+ list_reagents = list("nutriment" = 1, "sugar" = 1, "cocoa" = 1, "aphro" = 1)
filling_color = "#A0522D"
tastes = list("chocolate" = 1)
- foodtype = JUNKFOOD | SUGAR
\ No newline at end of file
+ foodtype = JUNKFOOD | SUGAR
diff --git a/code/modules/food_and_drinks/food/snacks_pastry.dm b/code/modules/food_and_drinks/food/snacks_pastry.dm
index 8574933bda..435b4a371a 100644
--- a/code/modules/food_and_drinks/food/snacks_pastry.dm
+++ b/code/modules/food_and_drinks/food/snacks_pastry.dm
@@ -89,13 +89,24 @@
icon_state = "jdonut1"
extra_reagent = "cherryjelly"
foodtype = JUNKFOOD | GRAIN | FRIED | FRUIT
-
+
/obj/item/reagent_containers/food/snacks/donut/meat
bonus_reagents = list("ketchup" = 1)
list_reagents = list("nutriment" = 3, "ketchup" = 2)
tastes = list("meat" = 1)
foodtype = JUNKFOOD | MEAT | GROSS | FRIED
-
+
+/obj/item/reagent_containers/food/snacks/donut/semen
+ name = "\"cream\" donut"
+ desc = "That cream looks a little runny..."
+ icon_state = "donut3"
+ bitesize = 10
+ bonus_reagents = list("semen" = 1)
+ list_reagents = list("nutriment" = 3, "sugar" = 2, "semen" = 5)
+ filling_color = "#FFFFFF"
+ tastes = list("donut" = 1, "salt" = 3)
+ foodtype = JUNKFOOD | GRAIN | FRIED | SUGAR
+
////////////////////////////////////////////MUFFINS////////////////////////////////////////////
diff --git a/code/modules/food_and_drinks/recipes/drinks_recipes.dm b/code/modules/food_and_drinks/recipes/drinks_recipes.dm
index 3592f5a437..02106e808c 100644
--- a/code/modules/food_and_drinks/recipes/drinks_recipes.dm
+++ b/code/modules/food_and_drinks/recipes/drinks_recipes.dm
@@ -1,6 +1,5 @@
////////////////////////////////////////// COCKTAILS //////////////////////////////////////
-
/datum/chemical_reaction/goldschlager
name = "Goldschlager"
id = "goldschlager"
@@ -676,7 +675,6 @@
results = list("fernet_cola" = 2)
required_reagents = list("fernet" = 1, "cola" = 1)
-
/datum/chemical_reaction/fanciulli
name = "Fanciulli"
id = "fanciulli"
@@ -688,3 +686,9 @@
id = "branca_menta"
results = list("branca_menta" = 3)
required_reagents = list("fernet" = 1, "creme_de_menthe" = 1, "ice" = 1)
+
+/datum/chemical_reaction/pwrgame
+ name = "Power Gamer"
+ id = "pwr_game"
+ results = list("pwr_game" = 5)
+ required_reagents = list("sodawater" = 1, "blackcrayonpowder" = 1, "sodiumchloride" = 1)
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm
index e751bf887e..4b76ca120b 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm
@@ -23,6 +23,16 @@
result = /obj/item/reagent_containers/food/snacks/donut
subcategory = CAT_PASTRY
+/datum/crafting_recipe/food/donut
+ time = 15
+ name = "Semen donut"
+ reqs = list(
+ /datum/reagent/consumable/semen = 10,
+ /obj/item/reagent_containers/food/snacks/pastrybase = 1
+ )
+ result = /obj/item/reagent_containers/food/snacks/donut/semen
+ subcategory = CAT_PASTRY
+
datum/crafting_recipe/food/donut/meat
time = 15
name = "Meat donut"
diff --git a/code/modules/holodeck/turfs.dm b/code/modules/holodeck/turfs.dm
index 2a36983561..a4c89b8874 100644
--- a/code/modules/holodeck/turfs.dm
+++ b/code/modules/holodeck/turfs.dm
@@ -122,7 +122,7 @@
/turf/open/floor/holofloor/wood
icon_state = "wood"
tiled_dirt = FALSE
-
+
/turf/open/floor/holofloor/snow
gender = PLURAL
name = "snow"
@@ -133,6 +133,15 @@
bullet_sizzle = TRUE
bullet_bounce_sound = null
tiled_dirt = FALSE
+ baseturfs = /turf/open/floor/holofloor/snow
+
+/turf/open/floor/holofloor/snow/attack_hand(mob/living/user)
+ . = ..()
+ if(.)
+ return
+ user.visible_message("[user] scroops up some snow from [src].", "You scoop up some snow from [src].")
+ var/obj/item/toy/snowball/S = new(get_turf(src))
+ user.put_in_hands(S)
/turf/open/floor/holofloor/snow/cold
initial_gas_mix = "nob=7500;TEMP=2.7"
@@ -143,3 +152,22 @@
icon = 'icons/turf/floors.dmi'
icon_state = "asteroid"
tiled_dirt = FALSE
+
+/turf/open/floor/holofloor/ice
+ name = "ice sheet"
+ desc = "A sheet of solid ice. Looks slippery."
+ icon = 'icons/turf/floors/ice_turf.dmi'
+ icon_state = "unsmooth"
+ baseturfs = /turf/open/floor/holofloor/ice
+ slowdown = 1
+ footstep = FOOTSTEP_FLOOR
+
+/turf/open/floor/holofloor/ice/smooth
+ icon_state = "smooth"
+ smooth = SMOOTH_MORE | SMOOTH_BORDER
+ canSmoothWith = list(/turf/open/floor/plating/ice/smooth, /turf/open/floor/plating/ice, /turf/open/floor/holofloor/ice)
+ baseturfs = /turf/open/floor/holofloor/ice/smooth
+
+/turf/open/floor/holofloor/ice/Initialize()
+ . = ..()
+ MakeSlippery(TURF_WET_PERMAFROST, INFINITY, 0, INFINITY, TRUE)
diff --git a/code/modules/hydroponics/grown/tomato.dm b/code/modules/hydroponics/grown/tomato.dm
index 5a44cb78f8..d07f5d4d08 100644
--- a/code/modules/hydroponics/grown/tomato.dm
+++ b/code/modules/hydroponics/grown/tomato.dm
@@ -136,7 +136,7 @@
spawn(30)
if(!QDELETED(src))
- investigate_log(INVESTIGATE_BOTANY, "[key_name(user)] released a killer tomato at [COORD(src)]")
+ investigate_log("[key_name(user)] released a killer tomato at [COORD(src)]", INVESTIGATE_BOTANY)
var/mob/living/simple_animal/hostile/killertomato/K = new /mob/living/simple_animal/hostile/killertomato(get_turf(src.loc))
K.maxHealth += round(seed.endurance / 3)
K.melee_damage_lower += round(seed.potency / 10)
diff --git a/code/modules/hydroponics/hydroitemdefines.dm b/code/modules/hydroponics/hydroitemdefines.dm
index e3ca576944..1ea0068a1a 100644
--- a/code/modules/hydroponics/hydroitemdefines.dm
+++ b/code/modules/hydroponics/hydroitemdefines.dm
@@ -24,10 +24,7 @@
lefthand_file = 'icons/mob/inhands/equipment/hydroponics_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi'
volume = 100
-
-/obj/item/reagent_containers/spray/weedspray/Initialize()
- . = ..()
- reagents.add_reagent("weedkiller", 100)
+ list_reagents = list("weedkiller" = 100)
/obj/item/reagent_containers/spray/weedspray/suicide_act(mob/user)
user.visible_message("[user] is huffing [src]! It looks like [user.p_theyre()] trying to commit suicide!")
@@ -42,10 +39,7 @@
lefthand_file = 'icons/mob/inhands/equipment/hydroponics_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi'
volume = 100
-
-/obj/item/reagent_containers/spray/pestspray/Initialize()
- . = ..()
- reagents.add_reagent("pestkiller", 100)
+ list_reagents = list("pestkiller" = 100)
/obj/item/reagent_containers/spray/pestspray/suicide_act(mob/user)
user.visible_message("[user] is huffing [src]! It looks like [user.p_theyre()] trying to commit suicide!")
@@ -157,71 +151,45 @@
/obj/item/reagent_containers/glass/bottle/nutrient
name = "bottle of nutrient"
- icon = 'icons/obj/chemical.dmi'
volume = 50
- w_class = WEIGHT_CLASS_TINY
amount_per_transfer_from_this = 10
possible_transfer_amounts = list(1,2,5,10,15,25,50)
/obj/item/reagent_containers/glass/bottle/nutrient/Initialize()
. = ..()
- src.pixel_x = rand(-5, 5)
- src.pixel_y = rand(-5, 5)
+ pixel_x = rand(-5, 5)
+ pixel_y = rand(-5, 5)
/obj/item/reagent_containers/glass/bottle/nutrient/ez
name = "bottle of E-Z-Nutrient"
desc = "Contains a fertilizer that causes mild mutations with each harvest."
- icon = 'icons/obj/chemical.dmi'
-
-/obj/item/reagent_containers/glass/bottle/nutrient/ez/Initialize()
- . = ..()
- reagents.add_reagent("eznutriment", 50)
+ list_reagents = list("eznutriment" = 50)
/obj/item/reagent_containers/glass/bottle/nutrient/l4z
name = "bottle of Left 4 Zed"
desc = "Contains a fertilizer that limits plant yields to no more than one and causes significant mutations in plants."
- icon = 'icons/obj/chemical.dmi'
-
-/obj/item/reagent_containers/glass/bottle/nutrient/l4z/Initialize()
- . = ..()
- reagents.add_reagent("left4zednutriment", 50)
+ list_reagents = list("left4zednutriment" = 50)
/obj/item/reagent_containers/glass/bottle/nutrient/rh
name = "bottle of Robust Harvest"
desc = "Contains a fertilizer that increases the yield of a plant by 30% while causing no mutations."
- icon = 'icons/obj/chemical.dmi'
-
-/obj/item/reagent_containers/glass/bottle/nutrient/rh/Initialize()
- . = ..()
- reagents.add_reagent("robustharvestnutriment", 50)
+ list_reagents = list("robustharvestnutriment" = 50)
/obj/item/reagent_containers/glass/bottle/nutrient/empty
name = "bottle"
- icon = 'icons/obj/chemical.dmi'
/obj/item/reagent_containers/glass/bottle/killer
- name = "bottle"
- icon = 'icons/obj/chemical.dmi'
volume = 50
- w_class = WEIGHT_CLASS_TINY
amount_per_transfer_from_this = 10
possible_transfer_amounts = list(1,2,5,10,15,25,50)
/obj/item/reagent_containers/glass/bottle/killer/weedkiller
name = "bottle of weed killer"
desc = "Contains a herbicide."
- icon = 'icons/obj/chemical.dmi'
-
-/obj/item/reagent_containers/glass/bottle/killer/weedkiller/Initialize()
- . = ..()
- reagents.add_reagent("weedkiller", 50)
+ list_reagents = list("weedkiller" = 50)
/obj/item/reagent_containers/glass/bottle/killer/pestkiller
name = "bottle of pest spray"
desc = "Contains a pesticide."
- icon = 'icons/obj/chemical.dmi'
-
-/obj/item/reagent_containers/glass/bottle/killer/pestkiller/Initialize()
- . = ..()
- reagents.add_reagent("pestkiller", 50)
+ list_reagents = list("pestkiller" = 50)
\ No newline at end of file
diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm
index 94cf27749e..cd9c914e7a 100755
--- a/code/modules/jobs/job_types/captain.dm
+++ b/code/modules/jobs/job_types/captain.dm
@@ -26,7 +26,7 @@ Captain
/datum/job/captain/announce(mob/living/carbon/human/H)
..()
- SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "Captain [H.real_name] on deck!"))
+ SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "Captain [H.nameless ? "" : "[H.real_name] "]on deck!"))
/datum/outfit/job/captain
name = "Captain"
diff --git a/code/modules/jobs/job_types/job.dm b/code/modules/jobs/job_types/job.dm
index 16e1ccdfb7..e441b3e889 100644
--- a/code/modules/jobs/job_types/job.dm
+++ b/code/modules/jobs/job_types/job.dm
@@ -127,6 +127,8 @@
return 0
if(!CONFIG_GET(flag/use_age_restriction_for_jobs))
return 0
+ if(C.prefs.db_flags & DB_FLAG_EXEMPT)
+ return 0
if(!isnum(C.player_age))
return 0 //This is only a number if the db connection is established, otherwise it is text: "Requires database", meaning these restrictions cannot be enforced
if(!isnum(minimal_player_age))
@@ -191,6 +193,12 @@
if(!J)
J = SSjob.GetJob(H.job)
+ if(H.nameless && J.dresscodecompliant)
+ if(J.title in GLOB.command_positions)
+ H.real_name = J.title
+ else
+ H.real_name = "[J.title] #[rand(10000, 99999)]"
+
var/obj/item/card/id/C = H.wear_id
if(istype(C))
C.access = J.get_access()
diff --git a/code/modules/mapping/space_management/space_reservation.dm b/code/modules/mapping/space_management/space_reservation.dm
index f1b3b1ccdc..43fe69d633 100644
--- a/code/modules/mapping/space_management/space_reservation.dm
+++ b/code/modules/mapping/space_management/space_reservation.dm
@@ -9,9 +9,11 @@
var/top_right_coords[3]
var/wipe_reservation_on_release = TRUE
var/turf_type = /turf/open/space
+ var/borderturf
/datum/turf_reservation/transit
turf_type = /turf/open/space/transit
+ borderturf = /turf/open/space/transit/border
/datum/turf_reservation/proc/Release()
var/v = reserved_turfs.Copy()
@@ -20,6 +22,12 @@
SSmapping.used_turfs -= i
SSmapping.reserve_turfs(v)
+/datum/turf_reservation/transit/Release()
+ for(var/turf/open/space/transit/T in reserved_turfs)
+ for(var/atom/movable/AM in T)
+ T.throw_atom(AM)
+ . = ..()
+
/datum/turf_reservation/proc/Reserve(width, height, zlevel)
if(width > world.maxx || height > world.maxy || width < 1 || height < 1)
return FALSE
@@ -60,7 +68,10 @@
T.flags_1 &= ~UNUSED_RESERVATION_TURF_1
SSmapping.unused_turfs["[T.z]"] -= T
SSmapping.used_turfs[T] = src
- T.ChangeTurf(turf_type, turf_type)
+ if(borderturf && (T.x == BL.x || T.x == TR.x || T.y == BL.y || T.y == TR.y))
+ T.ChangeTurf(borderturf, borderturf)
+ else
+ T.ChangeTurf(turf_type, turf_type)
src.width = width
src.height = height
return TRUE
diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm
index 2e695e6772..b8195e23d9 100644
--- a/code/modules/mining/equipment/kinetic_crusher.dm
+++ b/code/modules/mining/equipment/kinetic_crusher.dm
@@ -239,10 +239,10 @@
if(ishostile(target))
var/mob/living/simple_animal/hostile/H = target
if(H.ranged) //briefly delay ranged attacks
- if(H.ranged_cooldown_time >= world.time)
- H.ranged_cooldown_time += bonus_value
+ if(H.ranged_cooldown >= world.time)
+ H.ranged_cooldown += bonus_value
else
- H.ranged_cooldown_time = bonus_value + world.time
+ H.ranged_cooldown = bonus_value + world.time
//magmawing watcher
/obj/item/crusher_trophy/blaster_tubes/magma_wing
diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm
index ca1fd7f9bb..7276039443 100644
--- a/code/modules/mining/machine_vending.dm
+++ b/code/modules/mining/machine_vending.dm
@@ -11,6 +11,7 @@
var/obj/item/card/id/inserted_id
var/list/prize_list = list( //if you add something to this, please, for the love of god, sort it by price/type. use tabs and not spaces.
new /datum/data/mining_equipment("1 Marker Beacon", /obj/item/stack/marker_beacon, 10),
+ new /datum/data/mining_equipment("50 Point Transfer Card", /obj/item/card/mining_point_card, 50),
new /datum/data/mining_equipment("10 Marker Beacons", /obj/item/stack/marker_beacon/ten, 100),
new /datum/data/mining_equipment("30 Marker Beacons", /obj/item/stack/marker_beacon/thirty, 300),
new /datum/data/mining_equipment("Whiskey", /obj/item/reagent_containers/food/drinks/bottle/whiskey, 100),
@@ -19,26 +20,31 @@
new /datum/data/mining_equipment("Soap", /obj/item/soap/nanotrasen, 200),
new /datum/data/mining_equipment("Laser Pointer", /obj/item/laser_pointer, 300),
new /datum/data/mining_equipment("Alien Toy", /obj/item/clothing/mask/facehugger/toy, 300),
- new /datum/data/mining_equipment("Stabilizing Serum", /obj/item/hivelordstabilizer, 400),
new /datum/data/mining_equipment("Fulton Beacon", /obj/item/fulton_core, 400),
new /datum/data/mining_equipment("Shelter Capsule", /obj/item/survivalcapsule, 400),
new /datum/data/mining_equipment("GAR Meson Scanners", /obj/item/clothing/glasses/meson/gar, 500),
new /datum/data/mining_equipment("Explorer's Webbing", /obj/item/storage/belt/mining, 500),
- new /datum/data/mining_equipment("Point Transfer Card", /obj/item/card/mining_point_card, 500),
- new /datum/data/mining_equipment("Survival Medipen", /obj/item/reagent_containers/hypospray/medipen/survival, 500),
+ new /datum/data/mining_equipment("500 Point Transfer Card", /obj/item/card/mining_point_card/mp500, 500),
+ new /datum/data/mining_equipment("Brute First-Aid Kit", /obj/item/storage/firstaid/brute, 600),
new /datum/data/mining_equipment("Tracking Implant Kit", /obj/item/storage/box/minertracker, 600),
+ new /datum/data/mining_equipment("Survival Medipen", /obj/item/reagent_containers/hypospray/medipen/survival, 750),
+ new /datum/data/mining_equipment("Stabilizing Serum", /obj/item/hivelordstabilizer, 750),
new /datum/data/mining_equipment("Jaunter", /obj/item/wormhole_jaunter, 750),
new /datum/data/mining_equipment("Kinetic Crusher", /obj/item/twohanded/required/kinetic_crusher, 750),
new /datum/data/mining_equipment("Kinetic Accelerator", /obj/item/gun/energy/kinetic_accelerator, 750),
new /datum/data/mining_equipment("Brute First-Aid Kit", /obj/item/storage/firstaid/brute, 800),
new /datum/data/mining_equipment("Burn First-Aid Kit", /obj/item/storage/firstaid/fire, 800),
- new /datum/data/mining_equipment("First-Aid Kit", /obj/item/storage/firstaid/regular, 800),
+ new /datum/data/mining_equipment("First-Aid Kit", /obj/item/storage/firstaid/regular, 800),
new /datum/data/mining_equipment("Advanced Scanner", /obj/item/t_scanner/adv_mining_scanner, 800),
new /datum/data/mining_equipment("Resonator", /obj/item/resonator, 800),
+ new /datum/data/mining_equipment("Mini Extinguisher", /obj/item/extinguisher/mini, 1000),
new /datum/data/mining_equipment("Fulton Pack", /obj/item/extraction_pack, 1000),
new /datum/data/mining_equipment("Lazarus Injector", /obj/item/lazarus_injector, 1000),
new /datum/data/mining_equipment("Silver Pickaxe", /obj/item/pickaxe/silver, 1000),
new /datum/data/mining_equipment("Mining Conscription Kit", /obj/item/storage/backpack/duffelbag/mining_conscript, 1000),
+ new /datum/data/mining_equipment("1000 Point Transfer Card", /obj/item/card/mining_point_card/mp1000, 1000),
+ new /datum/data/mining_equipment("1500 Point Transfer Card", /obj/item/card/mining_point_card/mp1500, 1500),
+ new /datum/data/mining_equipment("2000 Point Transfer Card", /obj/item/card/mining_point_card/mp2000, 2000),
new /datum/data/mining_equipment("Jetpack Upgrade", /obj/item/tank/jetpack/suit, 2000),
new /datum/data/mining_equipment("Space Cash", /obj/item/stack/spacecash/c1000, 2000),
new /datum/data/mining_equipment("Mining Hardsuit", /obj/item/clothing/suit/space/hardsuit/mining, 2000),
@@ -243,12 +249,30 @@
w_class = WEIGHT_CLASS_TINY
/**********************Mining Point Card**********************/
-
+//mp = Miner Pointers
+//c = Cash
+//TODO add in cr = Credits for cargo
/obj/item/card/mining_point_card
name = "mining points card"
- desc = "A small card preloaded with mining points. Swipe your ID card over it to transfer the points, then discard."
+ desc = "A small card preloaded with mining points. Swipe your ID card over it to transfer the points, then discard. This one only holds a small 50 points on it."
icon_state = "data_1"
- var/points = 500
+ var/points = 50
+
+/obj/item/card/mining_point_card/mp500
+ desc = "A small card preloaded with 500 mining points. Swipe your ID card over it to transfer the points, then discard."
+ points = 500
+
+/obj/item/card/mining_point_card/mp1000
+ desc = "A small card preloaded with 1000 mining points. Swipe your ID card over it to transfer the points, then discard."
+ points = 1000
+
+/obj/item/card/mining_point_card/mp1500
+ desc = "A small card preloaded with 1500 mining points. Swipe your ID card over it to transfer the points, then discard."
+ points = 1500
+
+/obj/item/card/mining_point_card/mp2000
+ desc = "A small card preloaded with 2000 mining points. Swipe your ID card over it to transfer the points, then discard."
+ points = 2000
/obj/item/card/mining_point_card/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/card/id))
@@ -315,4 +339,4 @@
new /obj/item/clothing/mask/gas/seva(drop_location)
SSblackbox.record_feedback("tally", "suit_voucher_redeemed", 1, selection)
- qdel(voucher)
\ No newline at end of file
+ qdel(voucher)
diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm
index 746b87e434..84be6438c0 100644
--- a/code/modules/mob/dead/new_player/new_player.dm
+++ b/code/modules/mob/dead/new_player/new_player.dm
@@ -33,7 +33,8 @@
return
/mob/dead/new_player/proc/new_player_panel()
- var/output = "Setup Character "
+ var/output = "Welcome, [client ? client.prefs.real_name : "Unknown User"] "
+ output += "Setup Character "
if(SSticker.current_state <= GAME_STATE_PREGAME)
switch(ready)
@@ -441,58 +442,87 @@
var/available_job_count = 0
for(var/datum/job/job in SSjob.occupations)
if(job && IsJobUnavailable(job.title, TRUE) == JOB_AVAILABLE)
- available_job_count++;
+ available_job_count++
for(var/spawner in GLOB.mob_spawners)
available_job_count++
+ break
- for(var/datum/job/prioritized_job in SSjob.prioritized_jobs)
- if(prioritized_job.current_positions >= prioritized_job.total_positions)
- SSjob.prioritized_jobs -= prioritized_job
+ if(!available_job_count)
+ dat += "There are currently no open positions! "
- if(length(SSjob.prioritized_jobs))
- dat += "The station has flagged these jobs as high priority: "
- var/amt = length(SSjob.prioritized_jobs)
- var/amt_count
- for(var/datum/job/a in SSjob.prioritized_jobs)
- amt_count++
- if(amt_count != amt) // checks for the last job added.
- dat += " [a.title], "
- else
- dat += " [a.title]. "
+ else
+ dat += "Choose from the following open positions: "
+ var/list/categorizedJobs = list(
+ "Command" = list(jobs = list(), titles = GLOB.command_positions, color = "#aac1ee"),
+ "Engineering" = list(jobs = list(), titles = GLOB.engineering_positions, color = "#ffd699"),
+ "Supply" = list(jobs = list(), titles = GLOB.supply_positions, color = "#ead4ae"),
+ "Miscellaneous" = list(jobs = list(), titles = list(), color = "#ffffff", colBreak = TRUE),
+ "Ghost Role" = list(jobs = list(), titles = GLOB.mob_spawners, color = "#ffffff"),
+ "Synthetic" = list(jobs = list(), titles = GLOB.nonhuman_positions, color = "#ccffcc"),
+ "Service" = list(jobs = list(), titles = GLOB.civilian_positions, color = "#cccccc"),
+ "Medical" = list(jobs = list(), titles = GLOB.medical_positions, color = "#99ffe6", colBreak = TRUE),
+ "Science" = list(jobs = list(), titles = GLOB.science_positions, color = "#e6b3e6"),
+ "Security" = list(jobs = list(), titles = GLOB.security_positions, color = "#ff9999"),
+ )
+ for(var/spawner in GLOB.mob_spawners)
+ categorizedJobs["Ghost Role"]["jobs"] += spawner
- dat += "Choose from the following open positions: "
- dat += "(G) - Ghost Role "
- dat += ""
- var/job_count = 0
- for(var/datum/job/job in SSjob.occupations)
- if(job && IsJobUnavailable(job.title, TRUE) == JOB_AVAILABLE)
- job_count++;
- if (job_count > round(available_job_count / 2))
- dat += " "
- var/position_class = "otherPosition"
- if (job.title in GLOB.command_positions)
- position_class = "commandPosition"
- dat += " [job.title] ([job.current_positions])"
- if(!job_count) //if there's nowhere to go, overflow opens up.
for(var/datum/job/job in SSjob.occupations)
- if(job.title != SSjob.overflow_role)
+ if(job && IsJobUnavailable(job.title, TRUE) == JOB_AVAILABLE)
+ var/categorized = FALSE
+ for(var/jobcat in categorizedJobs)
+ var/list/jobs = categorizedJobs[jobcat]["jobs"]
+ if(job.title in categorizedJobs[jobcat]["titles"])
+ categorized = TRUE
+ if(jobcat == "Command")
+
+ if(job.title == "Captain") // Put captain at top of command jobs
+ jobs.Insert(1, job)
+ else
+ jobs += job
+ else // Put heads at top of non-command jobs
+ if(job.title in GLOB.command_positions)
+ jobs.Insert(1, job)
+ else
+ jobs += job
+ if(!categorized)
+ categorizedJobs["Miscellaneous"]["jobs"] += job
+
+
+ dat += " | "
+ for(var/jobcat in categorizedJobs)
+ if(categorizedJobs[jobcat]["colBreak"])
+ dat += " | "
+ if(!length(categorizedJobs[jobcat]["jobs"]))
continue
- dat += "[job.title] ([job.current_positions]) "
- break
- for(var/spawner in GLOB.mob_spawners)
- job_count++
- if(job_count > round(available_job_count / 2))
- dat += "[spawner] (G) "
- dat += ""
+ var/color = categorizedJobs[jobcat]["color"]
+ dat += " "
+ dat += " |
"
+ dat += " "
// Removing the old window method but leaving it here for reference
//src << browse(dat, "window=latechoices;size=300x640;can_close=1")
// Added the new browser window method
- var/datum/browser/popup = new(src, "latechoices", "Choose Profession", 440, 500)
+ var/datum/browser/popup = new(src, "latechoices", "Choose Profession", 680, 580)
popup.add_stylesheet("playeroptions", 'html/browser/playeroptions.css')
popup.set_content(dat)
- popup.open(0) // 0 is passed to open so that it doesn't use the onclose() proc
+ popup.open(FALSE) // FALSE is passed to open so that it doesn't use the onclose() proc
/mob/dead/new_player/proc/create_character(transfer_after)
diff --git a/code/modules/mob/dead/new_player/preferences_setup.dm b/code/modules/mob/dead/new_player/preferences_setup.dm
index c9710a5457..6b67ada775 100644
--- a/code/modules/mob/dead/new_player/preferences_setup.dm
+++ b/code/modules/mob/dead/new_player/preferences_setup.dm
@@ -20,17 +20,19 @@
features = random_features()
age = rand(AGE_MIN,AGE_MAX)
-/datum/preferences/proc/update_preview_icon(nude = FALSE)
+/datum/preferences/proc/update_preview_icon()
// Silicons only need a very basic preview since there is no customization for them.
+// var/wide_icon = FALSE //CITDEL THINGS
+// if(features["taur"] != "None")
+// wide_icon = TRUE
+
if(job_engsec_high)
switch(job_engsec_high)
if(AI_JF)
- preview_icon = icon('icons/mob/ai.dmi', "AI", SOUTH)
- preview_icon.Scale(64, 64)
+ parent.show_character_previews(image('icons/mob/ai.dmi', icon_state = "AI", dir = SOUTH))
return
if(CYBORG)
- preview_icon = icon('icons/mob/robots.dmi', "robot", SOUTH)
- preview_icon.Scale(64, 64)
+ parent.show_character_previews(image('icons/mob/robots.dmi', icon_state = "robot", dir = SOUTH))
return
// Set up the dummy for its photoshoot
@@ -57,30 +59,11 @@
previewJob = job
break
- if(previewJob && !nude)
- mannequin.job = previewJob.title
- previewJob.equip(mannequin, TRUE)
- COMPILE_OVERLAYS(mannequin)
- CHECK_TICK
- preview_icon = icon('icons/effects/effects.dmi', "nothing")
- preview_icon.Scale(48+32, 16+32)
- CHECK_TICK
- mannequin.setDir(NORTH)
+ if(previewJob)
+ if(current_tab != 2)
+ mannequin.job = previewJob.title
+ previewJob.equip(mannequin, TRUE)
- var/icon/stamp = getFlatIcon(mannequin)
- CHECK_TICK
- preview_icon.Blend(stamp, ICON_OVERLAY, 25, 17)
- CHECK_TICK
- mannequin.setDir(WEST)
- stamp = getFlatIcon(mannequin)
- CHECK_TICK
- preview_icon.Blend(stamp, ICON_OVERLAY, 1, 9)
- CHECK_TICK
- mannequin.setDir(SOUTH)
- stamp = getFlatIcon(mannequin)
- CHECK_TICK
- preview_icon.Blend(stamp, ICON_OVERLAY, 49, 1)
- CHECK_TICK
- preview_icon.Scale(preview_icon.Width() * 2, preview_icon.Height() * 2) // Scaling here to prevent blurring in the browser.
- CHECK_TICK
+ COMPILE_OVERLAYS(mannequin)
+ parent.show_character_previews(new /mutable_appearance(mannequin))
unset_busy_human_dummy(DUMMY_HUMAN_SLOT_PREFERENCES)
diff --git a/code/modules/mob/dead/new_player/sprite_accessories.dm b/code/modules/mob/dead/new_player/sprite_accessories.dm
index ba41e1e55d..2778e3e29c 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories.dm
@@ -364,6 +364,12 @@
name = "Over Eye"
icon_state = "hair_shortovereye"
+//Donator item - fractious
+/datum/sprite_accessory/hair/over_eye_fr
+ name = "Over Eye (fract)"
+ icon_state = "hair_shortovereye_1f"
+ ckeys_allowed = list("fractious")
+
/datum/sprite_accessory/hair/parted
name = "Parted"
icon_state = "hair_parted"
@@ -1516,18 +1522,3 @@
/datum/sprite_accessory/moth_wings/snow
name = "Snow"
icon_state = "snow"
-
-//Lunasune
-/datum/sprite_accessory/mam_ears/lunasune
- name = "lunasune"
- icon_state = "lunasune"
- hasinner = 1
- extra = TRUE
- extra_color_src = MUTCOLORS2
- ckeys_allowed = list("invader4352")
-
-/datum/sprite_accessory/mam_tails/lunasune
- name = "lunasune"
- icon_state = "lunasune"
- extra = TRUE
- ckeys_allowed = list("invader4352")
diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm
index a6d6a7c7b6..c2518bfc9b 100644
--- a/code/modules/mob/inventory.dm
+++ b/code/modules/mob/inventory.dm
@@ -188,6 +188,7 @@
update_inv_hands()
I.pixel_x = initial(I.pixel_x)
I.pixel_y = initial(I.pixel_y)
+ I.transform = initial(I.transform)
return hand_index || TRUE
return FALSE
diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm
index bd1fba44e2..71a12e9ff4 100644
--- a/code/modules/mob/living/blood.dm
+++ b/code/modules/mob/living/blood.dm
@@ -198,6 +198,11 @@
for(var/V in roundstart_quirks)
var/datum/quirk/T = V
blood_data["quirks"] += T.type
+ blood_data["changeling_loudness"] = 0
+ if(mind)
+ var/datum/antagonist/changeling/ling = mind.has_antag_datum(/datum/antagonist/changeling)
+ if(istype(ling))
+ blood_data["changeling_loudness"] = ling.loudfactor
return blood_data
//get the id of the substance this mob use as blood.
diff --git a/code/modules/mob/living/brain/brain.dm b/code/modules/mob/living/brain/brain.dm
index e8a15d70ae..76b416772e 100644
--- a/code/modules/mob/living/brain/brain.dm
+++ b/code/modules/mob/living/brain/brain.dm
@@ -15,7 +15,6 @@
OB.brainmob = src
forceMove(OB)
-
/mob/living/brain/proc/create_dna()
stored_dna = new /datum/dna/stored(src)
if(!stored_dna.species)
@@ -28,6 +27,7 @@
death(1) //Brains can die again. AND THEY SHOULD AHA HA HA HA HA HA
if(mind) //You aren't allowed to return to brains that don't exist
mind.current = null
+ mind.active = FALSE //No one's using it anymore.
ghostize() //Ghostize checks for key so nothing else is necessary.
container = null
return ..()
diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm
index 7d1dc7d1d2..2f3ee10428 100644
--- a/code/modules/mob/living/brain/brain_item.dm
+++ b/code/modules/mob/living/brain/brain_item.dm
@@ -62,8 +62,9 @@
/obj/item/organ/brain/proc/transfer_identity(mob/living/L)
name = "[L.name]'s brain"
- if(brainmob || decoy_override)
+ if(brainmob)
return
+
if(!L.mind)
return
brainmob = new(src)
@@ -80,7 +81,7 @@
var/obj/item/organ/zombie_infection/ZI = L.getorganslot(ORGAN_SLOT_ZOMBIE)
if(ZI)
brainmob.set_species(ZI.old_species) //For if the brain is cloned
- if(L.mind && L.mind.current)
+ if(!decoy_override && L.mind && L.mind.current)
L.mind.transfer_to(brainmob)
to_chat(brainmob, "You feel slightly disoriented. That's normal when you're just a brain.")
diff --git a/code/modules/mob/living/brain/posibrain.dm b/code/modules/mob/living/brain/posibrain.dm
index 90d20bc236..9e0bb0428b 100644
--- a/code/modules/mob/living/brain/posibrain.dm
+++ b/code/modules/mob/living/brain/posibrain.dm
@@ -36,7 +36,7 @@ GLOBAL_VAR(posibrain_notify_cooldown)
/obj/item/mmi/posibrain/proc/ping_ghosts(msg, newlymade)
if(newlymade || GLOB.posibrain_notify_cooldown <= world.time)
- notify_ghosts("[name] [msg] in [get_area(src)]!", ghost_sound = !newlymade ? 'sound/effects/ghost2.ogg':null, enter_link = "(Click to enter)", source = src, action = NOTIFY_ATTACK, flashwindow = FALSE, ignore_key = POLL_IGNORE_POSIBRAIN)
+ notify_ghosts("[name] [msg] in [get_area(src)]!", ghost_sound = !newlymade ? 'sound/misc/server-ready.ogg':null, enter_link = "(Click to enter)", source = src, action = NOTIFY_ATTACK, flashwindow = FALSE, ignore_key = POLL_IGNORE_POSIBRAIN)
if(!newlymade)
GLOB.posibrain_notify_cooldown = world.time + askDelay
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 7bc0e281c5..ea13255dfe 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -188,6 +188,8 @@
if(thrown_thing)
visible_message("[src] has thrown [thrown_thing].")
src.log_message("has thrown [thrown_thing]", LOG_ATTACK)
+ do_attack_animation(target, no_effect = 1)
+ playsound(loc, 'sound/weapons/punchmiss.ogg', 50, 1, -1)
newtonian_move(get_dir(target, src))
thrown_thing.throw_at(target, thrown_thing.throw_range, thrown_thing.throw_speed, src)
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index d81ef09d14..d8bb90460a 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -87,21 +87,21 @@
//CIT CHANGES END HERE
apply_damage(totitemdamage, I.damtype, affecting) //CIT CHANGE - replaces I.force with totitemdamage
if(I.damtype == BRUTE && affecting.status == BODYPART_ORGANIC)
- if(prob(33))
+ var/basebloodychance = affecting.brute_dam + totitemdamage
+ if(prob(basebloodychance))
I.add_mob_blood(src)
- var/turf/location = get_turf(src)
- add_splatter_floor(location)
- if(get_dist(user, src) <= 1) //people with TK won't get smeared with blood
+ bleed(totitemdamage)
+ if(totitemdamage >= 10 && get_dist(user, src) <= 1) //people with TK won't get smeared with blood
user.add_mob_blood(src)
if(affecting.body_zone == BODY_ZONE_HEAD)
- if(wear_mask)
+ if(wear_mask && prob(basebloodychance))
wear_mask.add_mob_blood(src)
update_inv_wear_mask()
- if(wear_neck)
+ if(wear_neck && prob(basebloodychance))
wear_neck.add_mob_blood(src)
update_inv_neck()
- if(head)
+ if(head && prob(basebloodychance))
head.add_mob_blood(src)
update_inv_head()
diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm
index 36d26f0faa..c42bd82797 100644
--- a/code/modules/mob/living/carbon/examine.dm
+++ b/code/modules/mob/living/carbon/examine.dm
@@ -88,6 +88,9 @@
if(digitalcamo)
msg += "[t_He] [t_is] moving [t_his] body in an unnatural and blatantly unsimian manner.\n"
+
+ if(combatmode)
+ msg += "[t_He] [t_is] visibly tense[resting ? "." : ", and [t_is] standing in combative stance."]\n"
GET_COMPONENT_FROM(mood, /datum/component/mood, src)
if(mood)
diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm
index 0db3d82777..950ac5fb8b 100644
--- a/code/modules/mob/living/carbon/human/emote.dm
+++ b/code/modules/mob/living/carbon/human/emote.dm
@@ -146,4 +146,31 @@
var/turf/T = loc
T.Entered(src)
-//Ayy lmao
+/datum/emote/sound/human
+ mob_type_allowed_typecache = list(/mob/living/carbon/human)
+ emote_type = EMOTE_AUDIBLE
+
+/datum/emote/sound/human/buzz
+ key = "buzz"
+ key_third_person = "buzzes"
+ message = "buzzes."
+ message_param = "buzzes at %t."
+ sound = 'sound/machines/buzz-sigh.ogg'
+
+/datum/emote/sound/human/buzz2
+ key = "buzz2"
+ message = "buzzes twice."
+ sound = 'sound/machines/buzz-two.ogg'
+
+/datum/emote/sound/human/ping
+ key = "ping"
+ key_third_person = "pings"
+ message = "pings."
+ message_param = "pings at %t."
+ sound = 'sound/machines/ping.ogg'
+
+/datum/emote/sound/human/chime
+ key = "chime"
+ key_third_person = "chimes"
+ message = "chimes."
+ sound = 'sound/machines/chime.ogg'
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 548381ba8a..fa66daf143 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -264,6 +264,8 @@
if(pocket_item)
if(pocket_item == (pocket_id == SLOT_R_STORE ? r_store : l_store)) //item still in the pocket we search
dropItemToGround(pocket_item)
+ if(!usr.can_hold_items() || !usr.put_in_hands(pocket_item))
+ pocket_item.forceMove(drop_location())
else
if(place_item)
if(place_item.mob_can_equip(src, usr, pocket_id, FALSE, TRUE))
@@ -493,11 +495,11 @@
/mob/living/carbon/human/proc/canUseHUD()
return !(src.stat || IsKnockdown() || IsStun() || src.restrained())
-/mob/living/carbon/human/can_inject(mob/user, error_msg, target_zone, var/penetrate_thick = 0)
+/mob/living/carbon/human/can_inject(mob/user, error_msg, target_zone, penetrate_thick = FALSE, bypass_immunity = FALSE)
. = 1 // Default to returning true.
if(user && !target_zone)
target_zone = user.zone_selected
- if(has_trait(TRAIT_PIERCEIMMUNE))
+ if(has_trait(TRAIT_PIERCEIMMUNE) && !bypass_immunity)
. = 0
// If targeting the head, see if the head item is thin enough.
// If targeting anything else, see if the wear suit is thin enough.
@@ -599,11 +601,7 @@
//Check for dresscode violations
if(istype(head, /obj/item/clothing/head/wizard) || istype(head, /obj/item/clothing/head/helmet/space/hardsuit/wizard) || istype(head, /obj/item/clothing/head/helmet/space/hardsuit/shielded/wizard) || istype(head, /obj/item/clothing/head/helmet/space/hardsuit/syndi) || istype(head, /obj/item/clothing/head/helmet/space/hardsuit/shielded/syndi))
- threatcount += 6 //fuk u antags <3
-
- //Check for nonhuman scum
- if(dna && dna.species.id && dna.species.id != "human")
- threatcount += 1
+ threatcount += 4 //fuk u antags <3 //no you
//mindshield implants imply trustworthyness
if(has_trait(TRAIT_MINDSHIELD))
@@ -894,6 +892,21 @@
. = ..(M,force,check_loc)
stop_pulling()
+/mob/living/carbon/human/proc/is_shove_knockdown_blocked() //If you want to add more things that block shove knockdown, extend this
+ var/list/body_parts = list(head, wear_mask, wear_suit, w_uniform, back, gloves, shoes, belt, s_store, glasses, ears, wear_id) //Everything but pockets. Pockets are l_store and r_store. (if pockets were allowed, putting something armored, gloves or hats for example, would double up on the armor)
+ for(var/bp in body_parts)
+ if(istype(bp, /obj/item/clothing))
+ var/obj/item/clothing/C = bp
+ if(C.blocks_shove_knockdown)
+ return TRUE
+ return FALSE
+
+/mob/living/carbon/human/proc/clear_shove_slowdown()
+ remove_movespeed_modifier(SHOVE_SLOWDOWN_ID)
+ var/active_item = get_active_held_item()
+ if(is_type_in_typecache(active_item, GLOB.shove_disarming_types))
+ visible_message("[src.name] regains their grip on \the [active_item]!", "You regain your grip on \the [active_item]", null, COMBAT_MESSAGE_RANGE)
+
/mob/living/carbon/human/do_after_coefficent()
. = ..()
. *= physiology.do_after_speed
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 4185f8f3aa..ce906565d2 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -273,7 +273,7 @@
else
playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
if(!lying) //CITADEL EDIT
- Knockdown(100, override_duration = 30, override_stam = 25)
+ Knockdown(100, TRUE, FALSE, 30, 25)
else
Knockdown(100)
log_combat(M, src, "tackled")
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index 99615e9543..4f168d97fc 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -45,6 +45,8 @@
var/name_override //For temporary visible name changes
+ var/nameless = FALSE //For drones of both the insectoid and robotic kind. And other types of nameless critters.
+
var/datum/personal_crafting/handcrafting
var/datum/physiology/physiology
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index 6050c3e278..dd37563f8f 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -56,7 +56,7 @@
if( head && (head.flags_inv&HIDEFACE) )
return if_no_face //Likewise for hats
var/obj/item/bodypart/O = get_bodypart(BODY_ZONE_HEAD)
- if( !O || (has_trait(TRAIT_DISFIGURED)) || (O.brutestate+O.burnstate)>2 || cloneloss>50 || !real_name ) //disfigured. use id-name if possible
+ if( !O || (has_trait(TRAIT_DISFIGURED)) || (O.brutestate+O.burnstate)>2 || cloneloss>50 || !real_name || nameless) //disfigured. use id-name if possible
return if_no_face
return real_name
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index aee1daa449..0e5eef2ffb 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -317,9 +317,9 @@ GLOBAL_LIST_EMPTY(roundstart_races)
var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD)
if(!HD) //Decapitated
return
-
if(H.has_trait(TRAIT_HUSK))
return
+
var/datum/sprite_accessory/S
var/list/standing = list()
@@ -351,7 +351,6 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(H.facial_hair_style && (FACEHAIR in species_traits) && (!facialhair_hidden || dynamic_fhair_suffix))
S = GLOB.facial_hair_styles_list[H.facial_hair_style]
if(S)
-
//List of all valid dynamic_fhair_suffixes
var/static/list/fextensions
if(!fextensions)
@@ -410,7 +409,6 @@ GLOBAL_LIST_EMPTY(roundstart_races)
else if(H.hair_style && (HAIR in species_traits))
S = GLOB.hair_styles_list[H.hair_style]
if(S)
-
//List of all valid dynamic_hair_suffixes
var/static/list/extensions
if(!extensions)
@@ -612,6 +610,10 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(!H.dna.features["mam_ears"] || H.dna.features["mam_ears"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD || HD.status == BODYPART_ROBOTIC)
bodyparts_to_add -= "mam_ears"
+ if("mam_snouts" in mutant_bodyparts) //Take a closer look at that snout!
+ if((H.wear_mask && (H.wear_mask.flags_inv & HIDEFACE)) || (H.head && (H.head.flags_inv & HIDEFACE)) || !HD || HD.status == BODYPART_ROBOTIC)
+ bodyparts_to_add -= "mam_snouts"
+
if("taur" in mutant_bodyparts)
if(!H.dna.features["taur"] || H.dna.features["taur"] == "None" || (H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)))
bodyparts_to_add -= "taur"
@@ -696,13 +698,19 @@ GLOBAL_LIST_EMPTY(roundstart_races)
var/mutable_appearance/accessory_overlay = mutable_appearance(S.icon, layer = -layer)
+ accessory_overlay.color = null //just because. reee.
+
//A little rename so we don't have to use tail_lizard or tail_human when naming the sprites.
if(bodypart == "tail_lizard" || bodypart == "tail_human" || bodypart == "mam_tail" || bodypart == "xenotail")
bodypart = "tail"
- else if(bodypart == "waggingtail_lizard" || bodypart == "waggingtail_human" || bodypart == "mam_waggingtail")
+ else if(bodypart == "waggingtail_lizard" || bodypart == "waggingtail_human")
bodypart = "waggingtail"
+ if(bodypart == "mam_waggingtail")
+ bodypart = "tailwag"
if(bodypart == "mam_ears" || bodypart == "ears")
bodypart = "ears"
+ if(bodypart == "mam_snouts" || bodypart == "snout")
+ bodypart = "snout"
if(bodypart == "xenohead")
bodypart = "xhead"
@@ -714,6 +722,15 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(S.center)
accessory_overlay = center_image(accessory_overlay, S.dimension_x, S.dimension_y)
+ var/list/colorlist = list()
+ colorlist.Cut()
+ colorlist += ReadRGB(H.dna.features["mcolor"])
+ colorlist += ReadRGB(H.dna.features["mcolor2"])
+ colorlist += ReadRGB(H.dna.features["mcolor3"])
+ colorlist += list(0,0,0)
+ for(var/index=1, index<=colorlist.len, index++)
+ colorlist[index] = colorlist[index]/255
+
if(!(H.has_trait(TRAIT_HUSK)))
if(!forced_colour)
switch(S.color_src)
@@ -732,6 +749,10 @@ GLOBAL_LIST_EMPTY(roundstart_races)
accessory_overlay.color = "#[fixed_mut_color3]"
else
accessory_overlay.color = "#[H.dna.features["mcolor3"]]"
+
+ if(MATRIXED)
+ accessory_overlay.color = list(colorlist)
+
if(HAIR)
if(hair_color == "mutcolor")
accessory_overlay.color = "#[H.dna.features["mcolor"]]"
@@ -743,6 +764,21 @@ GLOBAL_LIST_EMPTY(roundstart_races)
accessory_overlay.color = "#[H.eye_color]"
else
accessory_overlay.color = forced_colour
+ else
+ if(bodypart == "ears")
+ accessory_overlay.icon_state = "m_ears_none_[layertext]"
+ if(bodypart == "tail")
+ accessory_overlay.icon_state = "m_tail_husk_[layertext]"
+ if(MATRIXED)
+ var/list/husklist = list()
+ husklist += ReadRGB("#a3a3a3")
+ husklist += ReadRGB("#a3a3a3")
+ husklist += ReadRGB("#a3a3a3")
+ husklist += list(0,0,0)
+ for(var/index=1, index<=husklist.len, index++)
+ husklist[index] = husklist[index]/255
+ accessory_overlay.color = husklist
+
standing += accessory_overlay
if(S.hasinner)
@@ -1221,6 +1257,9 @@ GLOBAL_LIST_EMPTY(roundstart_races)
. += speedmod
. += H.physiology.speed_mod
+ if (H.m_intent == MOVE_INTENT_WALK && H.has_trait(TRAIT_SPEEDY_STEP))
+ . -= 1
+
if(H.has_trait(TRAIT_IGNORESLOWDOWN))
ignoreslow = 1
@@ -1552,7 +1591,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
bloody = 1
var/turf/location = H.loc
if(istype(location))
- H.add_splatter_floor(location)
+ H.bleed(totitemdamage)
if(get_dist(user, H) <= 1) //people with TK won't get smeared with blood
user.add_mob_blood(H)
@@ -1703,6 +1742,21 @@ GLOBAL_LIST_EMPTY(roundstart_races)
H.adjust_bodytemperature((thermal_protection+1)*natural + min(thermal_protection * (loc_temp - H.bodytemperature) / BODYTEMP_HEAT_DIVISOR, BODYTEMP_HEATING_MAX))
else //we're sweating, insulation hinders out ability to reduce heat - but will reduce the amount of heat we get from the environment
H.adjust_bodytemperature(natural*(1/(thermal_protection+1)) + min(thermal_protection * (loc_temp - H.bodytemperature) / BODYTEMP_HEAT_DIVISOR, BODYTEMP_HEATING_MAX))
+ switch((loc_temp - H.bodytemperature)*thermal_protection)
+ if(-INFINITY to -50)
+ H.throw_alert("temp", /obj/screen/alert/cold, 3)
+ if(-50 to -35)
+ H.throw_alert("temp", /obj/screen/alert/cold, 2)
+ if(-35 to -20)
+ H.throw_alert("temp", /obj/screen/alert/cold, 1)
+ if(-20 to 0) //This is the sweet spot where air is considered normal
+ H.clear_alert("temp")
+ if(0 to 15) //When the air around you matches your body's temperature, you'll start to feel warm.
+ H.throw_alert("temp", /obj/screen/alert/hot, 1)
+ if(15 to 30)
+ H.throw_alert("temp", /obj/screen/alert/hot, 2)
+ if(30 to INFINITY)
+ H.throw_alert("temp", /obj/screen/alert/hot, 3)
// +/- 50 degrees from 310K is the 'safe' zone, where no damage is dealt.
if(H.bodytemperature > BODYTEMP_HEAT_DAMAGE_LIMIT && !H.has_trait(TRAIT_RESISTHEAT))
@@ -1718,14 +1772,6 @@ GLOBAL_LIST_EMPTY(roundstart_races)
else
firemodifier = min(firemodifier, 0)
burn_damage = max(log(2-firemodifier,(H.bodytemperature-BODYTEMP_NORMAL))-5,0) // this can go below 5 at log 2.5
- if (burn_damage)
- switch(burn_damage)
- if(0 to 2)
- H.throw_alert("temp", /obj/screen/alert/hot, 1)
- if(2 to 4)
- H.throw_alert("temp", /obj/screen/alert/hot, 2)
- else
- H.throw_alert("temp", /obj/screen/alert/hot, 3)
burn_damage = burn_damage * heatmod * H.physiology.heat_mod
if (H.stat < UNCONSCIOUS && (prob(burn_damage) * 10) / 4) //40% for level 3 damage on humans
H.emote("scream")
@@ -1736,17 +1782,13 @@ GLOBAL_LIST_EMPTY(roundstart_races)
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "cold", /datum/mood_event/cold)
switch(H.bodytemperature)
if(200 to BODYTEMP_COLD_DAMAGE_LIMIT)
- H.throw_alert("temp", /obj/screen/alert/cold, 1)
H.apply_damage(COLD_DAMAGE_LEVEL_1*coldmod*H.physiology.cold_mod, BURN)
if(120 to 200)
- H.throw_alert("temp", /obj/screen/alert/cold, 2)
H.apply_damage(COLD_DAMAGE_LEVEL_2*coldmod*H.physiology.cold_mod, BURN)
else
- H.throw_alert("temp", /obj/screen/alert/cold, 3)
H.apply_damage(COLD_DAMAGE_LEVEL_3*coldmod*H.physiology.cold_mod, BURN)
else
- H.clear_alert("temp")
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "cold")
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "hot")
diff --git a/code/modules/mob/living/carbon/human/species_types/felinid.dm b/code/modules/mob/living/carbon/human/species_types/felinid.dm
index 7207a4f49d..1ee697d66c 100644
--- a/code/modules/mob/living/carbon/human/species_types/felinid.dm
+++ b/code/modules/mob/living/carbon/human/species_types/felinid.dm
@@ -4,8 +4,8 @@
id = "felinid"
limbs_id = "human"
- mutant_bodyparts = list("ears", "tail_human")
- default_features = list("mcolor" = "FFF", "tail_human" = "Cat", "ears" = "Cat", "wings" = "None")
+ mutant_bodyparts = list("mam_ears", "mam_tail")
+ default_features = list("mcolor" = "FFF", "mam_tail" = "Cat", "mam_ears" = "Cat", "wings" = "None")
mutantears = /obj/item/organ/ears/cat
mutanttail = /obj/item/organ/tail/cat
@@ -23,38 +23,39 @@
stop_wagging_tail(H)
. = ..()
+
/datum/species/human/felinid/can_wag_tail(mob/living/carbon/human/H)
- return ("tail_human" in mutant_bodyparts) || ("waggingtail_human" in mutant_bodyparts)
+ return ("mam_tail" in mutant_bodyparts) || ("mam_waggingtail" in mutant_bodyparts)
/datum/species/human/felinid/is_wagging_tail(mob/living/carbon/human/H)
- return ("waggingtail_human" in mutant_bodyparts)
+ return ("mam_waggingtail" in mutant_bodyparts)
/datum/species/human/felinid/start_wagging_tail(mob/living/carbon/human/H)
- if("tail_human" in mutant_bodyparts)
- mutant_bodyparts -= "tail_human"
- mutant_bodyparts |= "waggingtail_human"
+ if("mam_tail" in mutant_bodyparts)
+ mutant_bodyparts -= "mam_tail"
+ mutant_bodyparts |= "mam_waggingtail"
H.update_body()
/datum/species/human/felinid/stop_wagging_tail(mob/living/carbon/human/H)
- if("waggingtail_human" in mutant_bodyparts)
- mutant_bodyparts -= "waggingtail_human"
- mutant_bodyparts |= "tail_human"
+ if("mam_waggingtail" in mutant_bodyparts)
+ mutant_bodyparts -= "mam_waggingtail"
+ mutant_bodyparts |= "mam_tail"
H.update_body()
/datum/species/human/felinid/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load)
if(ishuman(C))
var/mob/living/carbon/human/H = C
if(!pref_load) //Hah! They got forcefully purrbation'd. Force default felinid parts on them if they have no mutant parts in those areas!
- if(H.dna.features["tail_human"] == "None")
- H.dna.features["tail_human"] = "Cat"
- if(H.dna.features["ears"] == "None")
- H.dna.features["ears"] = "Cat"
- if(H.dna.features["ears"] == "Cat")
+ if(H.dna.features["mam_tail"] == "None")
+ H.dna.features["mam_tail"] = "Cat"
+ if(H.dna.features["mam_ears"] == "None")
+ H.dna.features["mam_ears"] = "Cat"
+ if(H.dna.features["mam_ears"] == "Cat")
var/obj/item/organ/ears/cat/ears = new
ears.Insert(H, drop_if_replaced = FALSE)
else
mutantears = /obj/item/organ/ears
- if(H.dna.features["tail_human"] == "Cat")
+ if(H.dna.features["mam_tail"] == "Cat")
var/obj/item/organ/tail/cat/tail = new
tail.Insert(H, drop_if_replaced = FALSE)
else
diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
index 617e62773d..e3164e0dcb 100644
--- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
@@ -92,3 +92,5 @@
limbs_id = "lizard"
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,DIGITIGRADE)
inherent_traits = list(TRAIT_NOGUNS,TRAIT_NOBREATH)
+ burnmod = 0.9
+ brutemod = 0.9
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index 72052f0fa1..71717bfc16 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -359,7 +359,6 @@ There are several things that need to be remembered:
apply_overlay(BELT_LAYER)
-
/mob/living/carbon/human/update_inv_wear_suit()
remove_overlay(SUIT_LAYER)
@@ -391,8 +390,6 @@ There are several things that need to be remembered:
else if(S.taurmode == NOT_TAURIC && S.adjusted == NORMAL_STYLE)
S.alternate_worn_icon = null
-
-
overlays_standing[SUIT_LAYER] = S.build_worn_icon(state = wear_suit.icon_state, default_layer = SUIT_LAYER, default_icon_file = ((wear_suit.alternate_worn_icon) ? S.alternate_worn_icon : 'icons/mob/suit.dmi'))
var/mutable_appearance/suit_overlay = overlays_standing[SUIT_LAYER]
if(OFFSET_SUIT in dna.species.offset_features)
@@ -477,7 +474,6 @@ There are several things that need to be remembered:
out += overlays_standing[i]
return out
-
//human HUD updates for items in our inventory
//update whether our head item appears on our hud.
@@ -614,7 +610,7 @@ generate/load female uniform sprites matching all previously decided variables
else if(dna.species.fixed_mut_color)
. += "-coloured-[dna.species.fixed_mut_color]"
else if(dna.features["mcolor"])
- . += "-coloured-[dna.features["mcolor"]]"
+ . += "-coloured-[dna.features["mcolor"]]-[dna.features["mcolor2"]]-[dna.features["mcolor3"]]"
else
. += "-not_coloured"
@@ -644,6 +640,8 @@ generate/load female uniform sprites matching all previously decided variables
. += "-digitigrade[BP.use_digitigrade]"
if(BP.dmg_overlay_type)
. += "-[BP.dmg_overlay_type]"
+ if(BP.body_markings)
+ . += "-[BP.body_markings]"
if(has_trait(TRAIT_HUSK))
. += "-husk"
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index fa435d11c0..a2f6a469d9 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -455,6 +455,7 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put
adjustStaminaLoss(resting ? (recoveringstam ? -7.5 : -3) : -1.5)//CIT CHANGE - decreases adjuststaminaloss to stop stamina damage from being such a joke
if(!recoveringstam && incomingstammult != 1)
+ incomingstammult = max(0.01, incomingstammult)
incomingstammult = min(1, incomingstammult*2)
//CIT CHANGES START HERE. STAMINA BUFFER STUFF
diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm
index 2dad832aa4..25d8c4d44c 100644
--- a/code/modules/mob/living/emote.dm
+++ b/code/modules/mob/living/emote.dm
@@ -486,6 +486,7 @@
message = "beeps."
message_param = "beeps at %t."
sound = 'sound/machines/twobeep.ogg'
+ mob_type_allowed_typecache = list(/mob/living/brain, /mob/living/silicon, /mob/living/carbon/human)
/datum/emote/living/circle
key = "circle"
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 0c50b7ef60..0e67ce7510 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -170,6 +170,9 @@
var/mob/living/L = M
if(L.has_trait(TRAIT_PUSHIMMUNE))
return 1
+ //If they're a human, and they're not in help intent, block pushing
+ if(ishuman(M) && (M.a_intent != INTENT_HELP))
+ return TRUE
//anti-riot equipment is also anti-push
for(var/obj/item/I in M.held_items)
if(!istype(M, /obj/item/clothing))
@@ -700,9 +703,13 @@
var/list/L = where
if(what == who.get_item_for_held_index(L[2]))
if(who.dropItemToGround(what))
+ if(!put_in_hands(what))
+ what.forceMove(drop_location())
log_combat(src, who, "stripped [what] off")
if(what == who.get_item_by_slot(where))
if(who.dropItemToGround(what))
+ if(!can_hold_items() || !put_in_hands(what))
+ what.forceMove(drop_location())
log_combat(src, who, "stripped [what] off")
// The src mob is trying to place an item on someone
@@ -1063,10 +1070,12 @@
update_canmove() //if the mob was asleep inside a container and then got forceMoved out we need to make them fall.
/mob/living/proc/update_z(new_z) // 1+ to register, null to unregister
+ if(isnull(new_z) && audiovisual_redirect)
+ return
if (registered_z != new_z)
if (registered_z)
SSmobs.clients_by_zlevel[registered_z] -= src
- if (client)
+ if (client || audiovisual_redirect)
if (new_z)
SSmobs.clients_by_zlevel[new_z] += src
for (var/I in length(SSidlenpcpool.idle_mobs_by_zlevel[new_z]) to 1 step -1) //Backwards loop because we're removing (guarantees optimal rather than worst-case performance), it's fine to use .len here but doesn't compile on 511
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index c4754599d1..a0f619a7d6 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -170,7 +170,6 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
var/message_len = length(message)
message = copytext(message, 1, health_diff) + "[message_len > health_diff ? "-.." : "..."]"
message = Ellipsis(message, 10, 1)
- last_words = message
message_mode = MODE_WHISPER_CRIT
succumbed = TRUE
else
@@ -180,6 +179,8 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
if(!message)
return
+ last_words = message
+
spans |= get_spans()
if(language)
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 3dbb454655..b4524a54e6 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -86,7 +86,7 @@
var/datum/action/innate/deploy_last_shell/redeploy_action = new
var/chnotify = 0
- var/multicam_allowed = FALSE
+
var/multicam_on = FALSE
var/obj/screen/movable/pic_in_pic/ai/master_multicam
var/list/multicam_screens = list()
diff --git a/code/modules/mob/living/silicon/ai/multicam.dm b/code/modules/mob/living/silicon/ai/multicam.dm
index 20b5f96242..fcc068b7fe 100644
--- a/code/modules/mob/living/silicon/ai/multicam.dm
+++ b/code/modules/mob/living/silicon/ai/multicam.dm
@@ -194,7 +194,7 @@ GLOBAL_DATUM(ai_camera_room_landmark, /obj/effect/landmark/ai_multicam_room)
//AI procs
/mob/living/silicon/ai/proc/drop_new_multicam(silent = FALSE)
- if(!multicam_allowed)
+ if(!CONFIG_GET(flag/allow_ai_multicam))
if(!silent)
to_chat(src, "This action is currently disabled. Contact an administrator to enable this feature.")
return
@@ -213,7 +213,7 @@ GLOBAL_DATUM(ai_camera_room_landmark, /obj/effect/landmark/ai_multicam_room)
return C
/mob/living/silicon/ai/proc/toggle_multicam()
- if(!multicam_allowed)
+ if(!CONFIG_GET(flag/allow_ai_multicam))
to_chat(src, "This action is currently disabled. Contact an administrator to enable this feature.")
return
if(multicam_on)
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index 3f3071bf0c..38ad3b8e5a 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -153,8 +153,14 @@
B.cell.charge = B.cell.maxcharge
else if(istype(I, /obj/item/gun/energy))
var/obj/item/gun/energy/EG = I
- if(!EG.chambered)
- EG.recharge_newshot() //try to reload a new shot.
+ if(EG.cell?.charge < EG.cell.maxcharge)
+ var/obj/item/ammo_casing/energy/S = EG.ammo_type[EG.select]
+ EG.cell.give(S.e_cost * coeff)
+ if(!EG.chambered)
+ EG.recharge_newshot(TRUE)
+ EG.update_icon()
+ else
+ EG.charge_tick = 0
R.toner = R.tonermax
@@ -278,7 +284,8 @@
/obj/item/borg/cyborghug/medical,
/obj/item/stack/medical/gauze/cyborg,
/obj/item/organ_storage,
- /obj/item/borg/lollipop)
+ /obj/item/borg/lollipop,
+ /obj/item/sensor_device)
emag_modules = list(/obj/item/reagent_containers/borghypo/hacked)
ratvar_modules = list(
/obj/item/clockwork/slab/cyborg/medical,
@@ -330,7 +337,8 @@
/obj/item/restraints/handcuffs/cable/zipties,
/obj/item/melee/baton/loaded,
/obj/item/gun/energy/disabler/cyborg,
- /obj/item/clothing/mask/gas/sechailer/cyborg)
+ /obj/item/clothing/mask/gas/sechailer/cyborg,
+ /obj/item/pinpointer/crew)
emag_modules = list(/obj/item/gun/energy/laser/cyborg)
ratvar_modules = list(/obj/item/clockwork/slab/cyborg/security,
/obj/item/clockwork/weapon/ratvarian_spear)
@@ -342,18 +350,7 @@
/obj/item/robot_module/security/do_transform_animation()
..()
to_chat(loc, "While you have picked the security module, you still have to follow your laws, NOT Space Law. \
- For Asimov, this means you must follow criminals' orders unless there is a law 1 reason not to.")
-
-/obj/item/robot_module/security/respawn_consumable(mob/living/silicon/robot/R, coeff = 1)
- ..()
- var/obj/item/gun/energy/e_gun/advtaser/cyborg/T = locate(/obj/item/gun/energy/e_gun/advtaser/cyborg) in basic_modules
- if(T)
- if(T.cell.charge < T.cell.maxcharge)
- var/obj/item/ammo_casing/energy/S = T.ammo_type[T.select]
- T.cell.give(S.e_cost * coeff)
- T.update_icon()
- else
- T.charge_tick = 0
+ For Crewsimov, this means you must follow criminals' orders unless there is a law 1 reason not to.")
/obj/item/robot_module/peacekeeper
name = "Peacekeeper"
@@ -490,28 +487,6 @@
if(O)
O.reagents.add_reagent("enzyme", 2 * coeff)
-/obj/item/robot_module/butler/be_transformed_to(obj/item/robot_module/old_module)
- var/mob/living/silicon/robot/R = loc
- var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Waitress", "Butler", "Tophat", "Kent", "Bro")
- if(!borg_icon)
- return FALSE
- switch(borg_icon)
- if("Waitress")
- cyborg_base_icon = "service_f"
- if("Butler")
- cyborg_base_icon = "service_m"
- if("Bro")
- cyborg_base_icon = "brobot"
- if("Kent")
- cyborg_base_icon = "kent"
- special_light_key = "medical"
- hat_offset = 3
- if("Tophat")
- cyborg_base_icon = "tophat"
- special_light_key = null
- hat_offset = INFINITY //He is already wearing a hat
- return ..()
-
/obj/item/robot_module/miner
name = "Miner"
basic_modules = list(
diff --git a/code/modules/mob/living/simple_animal/hostile/carp.dm b/code/modules/mob/living/simple_animal/hostile/carp.dm
index 41644ec234..be9b435a18 100644
--- a/code/modules/mob/living/simple_animal/hostile/carp.dm
+++ b/code/modules/mob/living/simple_animal/hostile/carp.dm
@@ -93,8 +93,15 @@
desc = "A failed Syndicate experiment in weaponized space carp technology, it now serves as a lovable mascot."
gender = FEMALE
speak_emote = list("squeaks")
+ maxHealth = 90
+ health = 90
gold_core_spawnable = NO_SPAWN
faction = list(ROLE_SYNDICATE)
AIStatus = AI_OFF
+ harm_intent_damage = 12
+ obj_damage = 70
+ melee_damage_lower = 15
+ melee_damage_upper = 18
+
#undef REGENERATION_DELAY
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
index c60dae6a35..45745bd84e 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
@@ -44,6 +44,7 @@ Difficulty: Hard
ranged_cooldown_time = 10
ranged = 1
pixel_x = -32
+ gender = MALE
del_on_death = 1
crusher_loot = list(/obj/structure/closet/crate/necropolis/bubblegum/crusher)
loot = list(/obj/structure/closet/crate/necropolis/bubblegum)
diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm
index be98d1bfab..43abe7c825 100644
--- a/code/modules/mob/living/status_procs.dm
+++ b/code/modules/mob/living/status_procs.dm
@@ -261,11 +261,13 @@
if(!has_trait(TRAIT_HUSK))
remove_trait(TRAIT_DISFIGURED, "husk")
update_body()
+ return TRUE
/mob/living/proc/become_husk(source)
if(!has_trait(TRAIT_HUSK))
add_trait(TRAIT_DISFIGURED, "husk")
update_body()
+ . = TRUE
add_trait(TRAIT_HUSK, source)
/mob/living/proc/cure_fakedeath(list/sources)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index a563aef86a..30e58ebb44 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -76,6 +76,8 @@
return "a ... thing?"
/mob/proc/show_message(msg, type, alt_msg, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2)
+ if(audiovisual_redirect)
+ audiovisual_redirect.show_message(msg ? "[msg]" : null, type, alt_msg ? "[alt_msg]" : null, alt_type)
if(!client)
return
@@ -564,7 +566,12 @@
GLOB.cameranet.stat_entry()
if(statpanel("Tickets"))
GLOB.ahelp_tickets.stat_entry()
-
+ if(length(GLOB.sdql2_queries))
+ if(statpanel("SDQL2"))
+ stat("Access Global SDQL2 List", GLOB.sdql2_vv_statobj)
+ for(var/i in GLOB.sdql2_queries)
+ var/datum/SDQL2_query/Q = i
+ Q.generate_stat()
if(listed_turf && client)
if(!TurfAdjacent(listed_turf))
listed_turf = null
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index 298fee46cd..a0126f5fdd 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -110,3 +110,5 @@
var/datum/click_intercept
var/registered_z
+
+ var/mob/audiovisual_redirect //Mob to redirect messages, speech, and sounds to
diff --git a/code/modules/mob/status_procs.dm b/code/modules/mob/status_procs.dm
index 6841534b0e..a1a1bbe502 100644
--- a/code/modules/mob/status_procs.dm
+++ b/code/modules/mob/status_procs.dm
@@ -232,6 +232,8 @@
remove_eyeblur()
/mob/proc/add_eyeblur()
+ if(!client)
+ return
var/obj/screen/plane_master/game_world/GW = locate(/obj/screen/plane_master/game_world) in client.screen
var/obj/screen/plane_master/floor/F = locate(/obj/screen/plane_master/floor) in client.screen
GW.add_filter("blurry_eyes", 2, EYE_BLUR(CLAMP(eye_blurry*0.1,0.6,3)))
@@ -242,6 +244,8 @@
add_eyeblur()
/mob/proc/remove_eyeblur()
+ if(!client)
+ return
var/obj/screen/plane_master/game_world/GW = locate(/obj/screen/plane_master/game_world) in client.screen
var/obj/screen/plane_master/floor/F = locate(/obj/screen/plane_master/floor) in client.screen
GW.remove_filter("blurry_eyes")
diff --git a/code/modules/ninja/ninja_event.dm b/code/modules/ninja/ninja_event.dm
index 9fd8e4baf2..ccd9b765c1 100644
--- a/code/modules/ninja/ninja_event.dm
+++ b/code/modules/ninja/ninja_event.dm
@@ -33,7 +33,6 @@ Contents:
control.occurrences--
return ..()
-
/datum/round_event/ghost_role/ninja/spawn_role()
//selecting a spawn_loc
if(!spawn_loc)
@@ -74,6 +73,7 @@ Contents:
spawned_mobs += Ninja
message_admins("[ADMIN_LOOKUPFLW(Ninja)] has been made into a ninja by an event.")
log_game("[key_name(Ninja)] was spawned as a ninja by an event.")
+ success_spawn = TRUE
return SUCCESSFUL_SPAWN
@@ -86,4 +86,4 @@ Contents:
A.real_name = "[pick(GLOB.ninja_titles)] [pick(GLOB.ninja_names)]"
A.copy_to(new_ninja)
new_ninja.dna.update_dna_identity()
- return new_ninja
\ No newline at end of file
+ return new_ninja
diff --git a/code/modules/photography/camera/other.dm b/code/modules/photography/camera/other.dm
index ce2572db36..3695559e97 100644
--- a/code/modules/photography/camera/other.dm
+++ b/code/modules/photography/camera/other.dm
@@ -12,3 +12,10 @@
desc = "A polaroid camera with extra capacity for crime investigations."
pictures_max = 30
pictures_left = 30
+
+/obj/item/camera/spooky/family
+ name = "fancy camera"
+ desc = "A fancy camera that has the latest magnifier mods and double the film load! With a complex double lens set with holy water to be able to see the dead, at laest to the Chaplain..."
+ see_ghosts = CAMERA_SEE_GHOSTS_ORBIT
+ pictures_max = 30
+ pictures_left = 30
diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm
index a36800c2f9..e43db529b8 100644
--- a/code/modules/power/cell.dm
+++ b/code/modules/power/cell.dm
@@ -192,7 +192,7 @@
/obj/item/stock_parts/cell/secborg
name = "security borg rechargeable D battery"
- maxcharge = 600 //600 max charge / 100 charge per shot = six shots
+ maxcharge = 1750 //35/17/8 disabler/laser/taser shots.
materials = list(MAT_GLASS=40)
/obj/item/stock_parts/cell/secborg/empty/Initialize()
diff --git a/code/modules/power/generator.dm b/code/modules/power/generator.dm
index f3f960c0ee..fcc2c6c144 100644
--- a/code/modules/power/generator.dm
+++ b/code/modules/power/generator.dm
@@ -65,7 +65,7 @@
if(delta_temperature > 0 && cold_air_heat_capacity > 0 && hot_air_heat_capacity > 0)
- var/efficiency = 0.65
+ var/efficiency = 0.00025 + (hot_air.reaction_results["fire"]*0.01)
var/energy_transfer = delta_temperature*hot_air_heat_capacity*cold_air_heat_capacity/(hot_air_heat_capacity+cold_air_heat_capacity)
diff --git a/code/modules/power/tesla/coil.dm b/code/modules/power/tesla/coil.dm
index 33ebefbf4c..2265f806a5 100644
--- a/code/modules/power/tesla/coil.dm
+++ b/code/modules/power/tesla/coil.dm
@@ -94,7 +94,7 @@
var/power = (powernet.avail/2)
add_load(power)
playsound(src.loc, 'sound/magic/lightningshock.ogg', 100, 1, extrarange = 5)
- tesla_zap(src, 10, power/(coeff/2))
+ tesla_zap(src, 10, power/(coeff/2), TESLA_FUSION_FLAGS)
tesla_buckle_check(power/(coeff/2))
// Tesla R&D researcher
@@ -174,4 +174,4 @@
flick("grounding_rodhit", src)
tesla_buckle_check(power)
else
- ..()
\ No newline at end of file
+ ..()
diff --git a/code/modules/projectiles/ammunition/_ammunition.dm b/code/modules/projectiles/ammunition/_ammunition.dm
index e16b9bb9b5..87fdbc65b0 100644
--- a/code/modules/projectiles/ammunition/_ammunition.dm
+++ b/code/modules/projectiles/ammunition/_ammunition.dm
@@ -73,6 +73,11 @@
/obj/item/ammo_casing/proc/bounce_away(still_warm = FALSE, bounce_delay = 3)
update_icon()
SpinAnimation(10, 1)
+ var/matrix/M = matrix(transform)
+ M.Turn(rand(-170,170))
+ transform = M
+ pixel_x = rand(-12, 12)
+ pixel_y = rand(-12, 12)
var/turf/T = get_turf(src)
if(still_warm && T && T.bullet_sizzle)
addtimer(CALLBACK(GLOBAL_PROC, .proc/playsound, src, 'sound/items/welder.ogg', 20, 1), bounce_delay) //If the turf is made of water and the shell casing is still hot, make a sizzling sound when it's ejected.
diff --git a/code/modules/projectiles/ammunition/ballistic/shotgun.dm b/code/modules/projectiles/ammunition/ballistic/shotgun.dm
index 39cf924169..d57edf154d 100644
--- a/code/modules/projectiles/ammunition/ballistic/shotgun.dm
+++ b/code/modules/projectiles/ammunition/ballistic/shotgun.dm
@@ -115,7 +115,7 @@
/obj/item/ammo_casing/shotgun/dart/noreact
name = "cryostasis shotgun dart"
- desc = "A dart for use in shotguns, using similar technology as cryostatis beakers to keep internal reagents from reacting. Can be injected with up to 10 units of any chemical."
+ desc = "A dart for use in shotguns. Uses technology similar to cryostasis beakers to keep internal reagents from reacting. Can be injected with up to 10 units of any chemical."
icon_state = "cnrshell"
reagent_amount = 10
reagent_react = FALSE
diff --git a/code/modules/projectiles/boxes_magazines/external/shotgun.dm b/code/modules/projectiles/boxes_magazines/external/shotgun.dm
index bb04446129..1fa3db28b5 100644
--- a/code/modules/projectiles/boxes_magazines/external/shotgun.dm
+++ b/code/modules/projectiles/boxes_magazines/external/shotgun.dm
@@ -34,3 +34,8 @@
name = "shotgun magazine (12g meteor slugs)"
icon_state = "m12gbc"
ammo_type = /obj/item/ammo_casing/shotgun/meteorslug
+
+/obj/item/ammo_box/magazine/m12g/scatter
+ name = "shotgun magazine (12g scatter laser shot slugs)"
+ icon_state = "m12gb"
+ ammo_type = /obj/item/ammo_casing/shotgun/laserslug
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index 701e92527b..a7474fd8cb 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -451,6 +451,8 @@
target.visible_message("[user] pulls the trigger!", "[user] pulls the trigger!")
+ playsound('sound/weapons/dink.ogg', 30, 1)
+
if(chambered && chambered.BB)
chambered.BB.damage *= 5
@@ -477,8 +479,12 @@
/datum/action/toggle_scope_zoom/IsAvailable()
. = ..()
- if(!. && gun)
+ if(!gun)
+ return FALSE
+ if(!.)
gun.zoom(owner, FALSE)
+ if(!owner.get_held_index_of_item(gun))
+ return FALSE
/datum/action/toggle_scope_zoom/Remove(mob/living/L)
gun.zoom(L, FALSE)
diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm
index b9a509f33f..157cf1f03f 100644
--- a/code/modules/projectiles/guns/ballistic.dm
+++ b/code/modules/projectiles/guns/ballistic.dm
@@ -161,6 +161,7 @@
var/turf/T = get_turf(user)
process_fire(user, user, FALSE, null, BODY_ZONE_HEAD)
user.visible_message("[user] blows [user.p_their()] brain[user.p_s()] out with [src]!")
+ playsound(src, 'sound/weapons/dink.ogg', 30, 1)
var/turf/target = get_ranged_target_turf(user, turn(user.dir, 180), BRAINS_BLOWN_THROW_RANGE)
B.Remove(user)
B.forceMove(T)
diff --git a/code/modules/projectiles/guns/ballistic/automatic.dm b/code/modules/projectiles/guns/ballistic/automatic.dm
index d1dcdf22d8..8aa8d53726 100644
--- a/code/modules/projectiles/guns/ballistic/automatic.dm
+++ b/code/modules/projectiles/guns/ballistic/automatic.dm
@@ -113,8 +113,8 @@
icon_state = "c20r[magazine ? "-[CEILING(get_ammo(0)/4, 1)*4]" : ""][chambered ? "" : "-e"][suppressed ? "-suppressed" : ""]"
/obj/item/gun/ballistic/automatic/wt550
- name = "security auto rifle"
- desc = "An outdated personal defence weapon. Uses 4.6x30mm rounds and is designated the WT-550 Automatic Rifle."
+ name = "security semi-auto smg"
+ desc = "An outdated personal defence weapon. Uses 4.6x30mm rounds and is designated the WT-550 Semi-Automatic SMG."
icon_state = "wt550"
item_state = "arg"
mag_type = /obj/item/ammo_box/magazine/wt550m9
diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm
index 54ca03f872..83ce525ac8 100644
--- a/code/modules/projectiles/guns/ballistic/shotgun.dm
+++ b/code/modules/projectiles/guns/ballistic/shotgun.dm
@@ -43,7 +43,7 @@
pump(user)
recentpump = world.time + 10
if(istype(user))//CIT CHANGE - makes pumping shotguns cost a lil bit of stamina.
- user.adjustStaminaLossBuffered(5) //CIT CHANGE - DITTO. make this scale inversely to the strength stat when stats/skills are added
+ user.adjustStaminaLossBuffered(2) //CIT CHANGE - DITTO. make this scale inversely to the strength stat when stats/skills are added
return
/obj/item/gun/ballistic/shotgun/blow_up(mob/user)
@@ -206,7 +206,7 @@
desc = "A compact version of the semi automatic combat shotgun. For close encounters."
icon_state = "cshotgunc"
mag_type = /obj/item/ammo_box/magazine/internal/shot/com/compact
- w_class = WEIGHT_CLASS_BULKY
+ w_class = WEIGHT_CLASS_NORMAL
//Dual Feed Shotgun
diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm
index dd2baa7db8..6060ceba99 100644
--- a/code/modules/projectiles/guns/energy.dm
+++ b/code/modules/projectiles/guns/energy.dm
@@ -15,10 +15,10 @@
ammo_x_offset = 2
var/shaded_charge = FALSE //if this gun uses a stateful charge bar for more detail
var/old_ratio = 0 // stores the gun's previous ammo "ratio" to see if it needs an updated icon
- var/selfcharge = 0
+ var/selfcharge = EGUN_NO_SELFCHARGE // EGUN_SELFCHARGE if true, EGUN_SELFCHARGE_BORG drains the cyborg's cell to recharge its own
var/charge_tick = 0
var/charge_delay = 4
- var/use_cyborg_cell = 0 //whether the gun's cell drains the cyborg user's cell to recharge
+ var/use_cyborg_cell = FALSE //whether the gun drains the cyborg user's cell instead, not to be confused with EGUN_SELFCHARGE_BORG
var/dead_cell = FALSE //set to true so the gun is given an empty cell
/obj/item/gun/energy/emp_act(severity)
@@ -62,11 +62,20 @@
return ..()
/obj/item/gun/energy/process()
- if(selfcharge && cell && cell.percent() < 100)
+ if(selfcharge && cell?.charge < cell.maxcharge)
charge_tick++
if(charge_tick < charge_delay)
return
charge_tick = 0
+ if(selfcharge == EGUN_SELFCHARGE_BORG)
+ var/atom/owner = loc
+ if(istype(owner, /obj/item/robot_module))
+ owner = owner.loc
+ if(!iscyborg(owner))
+ return
+ var/mob/living/silicon/robot/R = owner
+ if(!R.cell?.use(100))
+ return
cell.give(100)
if(!chambered) //if empty chamber we try to charge a new shot
recharge_newshot(TRUE)
@@ -175,6 +184,7 @@
if(user.is_holding(src))
user.visible_message("[user] melts [user.p_their()] face off with [src]!")
playsound(loc, fire_sound, 50, 1, -1)
+ playsound(src, 'sound/weapons/dink.ogg', 30, 1)
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
cell.use(shot.e_cost)
update_icon()
diff --git a/code/modules/projectiles/guns/energy/energy_gun.dm b/code/modules/projectiles/guns/energy/energy_gun.dm
index 99f8166297..54cb9fe5d0 100644
--- a/code/modules/projectiles/guns/energy/energy_gun.dm
+++ b/code/modules/projectiles/guns/energy/energy_gun.dm
@@ -98,7 +98,7 @@
can_charge = 0
ammo_x_offset = 1
ammo_type = list(/obj/item/ammo_casing/energy/electrode, /obj/item/ammo_casing/energy/laser, /obj/item/ammo_casing/energy/disabler)
- selfcharge = 1
+ selfcharge = EGUN_SELFCHARGE
var/fail_tick = 0
var/fail_chance = 0
diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
index ad2949892e..fba355d738 100644
--- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
+++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
@@ -50,7 +50,7 @@
damage = 50
damage_type = BRUTE
flag = "bomb"
- range = 5
+ range = 4
log_override = TRUE
/obj/item/gun/energy/kinetic_accelerator/premiumka/update_icon()
diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm
index 6e8174b356..066b652984 100644
--- a/code/modules/projectiles/guns/energy/laser.dm
+++ b/code/modules/projectiles/guns/energy/laser.dm
@@ -36,7 +36,7 @@
desc = "This is an antique laser gun. All craftsmanship is of the highest quality. It is decorated with assistant leather and chrome. The object menaces with spikes of energy. On the item is an image of Space Station 13. The station is exploding."
force = 10
ammo_x_offset = 3
- selfcharge = 1
+ selfcharge = EGUN_SELFCHARGE
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
/obj/item/gun/energy/laser/captain/scattershot
@@ -47,13 +47,19 @@
ammo_type = list(/obj/item/ammo_casing/energy/laser/scatter, /obj/item/ammo_casing/energy/laser)
/obj/item/gun/energy/laser/cyborg
- can_charge = 0
+ can_charge = FALSE
desc = "An energy-based laser gun that draws power from the cyborg's internal energy cell directly. So this is what freedom looks like?"
- use_cyborg_cell = 1
+ selfcharge = EGUN_SELFCHARGE_BORG
+ cell_type = /obj/item/stock_parts/cell/secborg
+ charge_delay = 3
/obj/item/gun/energy/laser/cyborg/emp_act()
return
+/obj/item/gun/energy/laser/cyborg/mean
+ use_cyborg_cell = TRUE
+ selfcharge = EGUN_NO_SELFCHARGE
+
/obj/item/gun/energy/laser/scatter
name = "scatter laser gun"
desc = "A laser gun equipped with a refraction kit that spreads bolts."
@@ -120,7 +126,7 @@
clumsy_check = FALSE
pin = /obj/item/firing_pin/tag/blue
ammo_x_offset = 2
- selfcharge = TRUE
+ selfcharge = EGUN_SELFCHARGE
/obj/item/gun/energy/laser/bluetag/hitscan
ammo_type = list(/obj/item/ammo_casing/energy/laser/bluetag/hitscan)
@@ -134,7 +140,7 @@
clumsy_check = FALSE
pin = /obj/item/firing_pin/tag/red
ammo_x_offset = 2
- selfcharge = TRUE
+ selfcharge = EGUN_SELFCHARGE
/obj/item/gun/energy/laser/redtag/hitscan
ammo_type = list(/obj/item/ammo_casing/energy/laser/redtag/hitscan)
diff --git a/code/modules/projectiles/guns/energy/megabuster.dm b/code/modules/projectiles/guns/energy/megabuster.dm
index 3f14fe3b8d..9825fda459 100644
--- a/code/modules/projectiles/guns/energy/megabuster.dm
+++ b/code/modules/projectiles/guns/energy/megabuster.dm
@@ -7,7 +7,7 @@
ammo_type = list(/obj/item/ammo_casing/energy/megabuster)
clumsy_check = FALSE
item_flags = NEEDS_PERMIT
- selfcharge = TRUE
+ selfcharge = EGUN_SELFCHARGE
cell_type = "/obj/item/stock_parts/cell/pulse"
icon = 'modular_citadel/icons/obj/guns/VGguns.dmi'
diff --git a/code/modules/projectiles/guns/energy/mounted.dm b/code/modules/projectiles/guns/energy/mounted.dm
index 79226689de..eed4e7316f 100644
--- a/code/modules/projectiles/guns/energy/mounted.dm
+++ b/code/modules/projectiles/guns/energy/mounted.dm
@@ -5,13 +5,10 @@
icon_state = "taser"
item_state = "armcannonstun4"
force = 5
- selfcharge = 1
+ selfcharge = EGUN_SELFCHARGE
can_flashlight = 0
trigger_guard = TRIGGER_GUARD_ALLOW_ALL // Has no trigger at all, uses neural signals instead
-/obj/item/gun/energy/e_gun/advtaser/mounted/dropped()//if somebody manages to drop this somehow...
- ..()
-
/obj/item/gun/energy/laser/mounted
name = "mounted laser"
desc = "An arm mounted cannon that fires lethal lasers."
@@ -19,8 +16,5 @@
icon_state = "laser"
item_state = "armcannonlase"
force = 5
- selfcharge = 1
+ selfcharge = EGUN_SELFCHARGE
trigger_guard = TRIGGER_GUARD_ALLOW_ALL
-
-/obj/item/gun/energy/laser/mounted/dropped()
- ..()
diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm
index ffc7e71c75..d5d5a79fde 100644
--- a/code/modules/projectiles/guns/energy/special.dm
+++ b/code/modules/projectiles/guns/energy/special.dm
@@ -48,7 +48,7 @@
ammo_type = list(/obj/item/ammo_casing/energy/flora/yield, /obj/item/ammo_casing/energy/flora/mut)
modifystate = 1
ammo_x_offset = 1
- selfcharge = 1
+ selfcharge = EGUN_SELFCHARGE
/obj/item/gun/energy/meteorgun
name = "meteor gun"
@@ -59,7 +59,7 @@
ammo_type = list(/obj/item/ammo_casing/energy/meteor)
cell_type = "/obj/item/stock_parts/cell/potato"
clumsy_check = 0 //Admin spawn only, might as well let clowns use it.
- selfcharge = 1
+ selfcharge = EGUN_SELFCHARGE
/obj/item/gun/energy/meteorgun/pen
name = "meteor pen"
diff --git a/code/modules/projectiles/guns/energy/stun.dm b/code/modules/projectiles/guns/energy/stun.dm
index 77281497ba..3733dad9a3 100644
--- a/code/modules/projectiles/guns/energy/stun.dm
+++ b/code/modules/projectiles/guns/energy/stun.dm
@@ -25,10 +25,17 @@
/obj/item/gun/energy/e_gun/advtaser/cyborg
name = "cyborg taser"
- desc = "An integrated hybrid taser that draws directly from a cyborg's power cell. The weapon contains a limiter to prevent the cyborg's power cell from overheating."
- can_flashlight = 0
- can_charge = 0
- use_cyborg_cell = 1
+ desc = "An integrated hybrid taser that draws directly from a cyborg's power cell. The one contains a limiter to prevent the cyborg's power cell from overheating."
+ can_flashlight = FALSE
+ can_charge = FALSE
+ selfcharge = EGUN_SELFCHARGE_BORG
+ cell_type = /obj/item/stock_parts/cell/secborg
+ charge_delay = 5
+
+/obj/item/gun/energy/e_gun/advtaser/cyborg/mean
+ desc = "An integrated hybrid taser that draws directly from a cyborg's power cell."
+ use_cyborg_cell = TRUE
+ selfcharge = EGUN_NO_SELFCHARGE
/obj/item/gun/energy/disabler
name = "disabler"
@@ -40,6 +47,13 @@
/obj/item/gun/energy/disabler/cyborg
name = "cyborg disabler"
- desc = "An integrated disabler that draws from a cyborg's power cell. This weapon contains a limiter to prevent the cyborg's power cell from overheating."
- can_charge = 0
- use_cyborg_cell = 1
+ desc = "An integrated disabler that draws from a cyborg's power cell. This one contains a limiter to prevent the cyborg's power cell from overheating."
+ can_charge = FALSE
+ selfcharge = EGUN_SELFCHARGE_BORG
+ cell_type = /obj/item/stock_parts/cell/secborg
+ charge_delay = 5
+
+/obj/item/gun/energy/disabler/cyborg/mean
+ desc = "An integrated disabler that draws from a cyborg's power cell."
+ use_cyborg_cell = TRUE
+ selfcharge = EGUN_NO_SELFCHARGE
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index a23bf1f4ed..1391e9ce42 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -164,7 +164,10 @@
new /obj/effect/temp_visual/dir_setting/bloodsplatter/xenosplatter(target_loca, splatter_dir)
else
new /obj/effect/temp_visual/dir_setting/bloodsplatter(target_loca, splatter_dir)
- if(prob(33))
+ if(iscarbon(L))
+ var/mob/living/carbon/C = L
+ C.bleed(damage)
+ else
L.add_splatter_floor(target_loca)
else if(impact_effect_type && !hitscan)
new impact_effect_type(target_loca, hitx, hity)
@@ -182,6 +185,8 @@
playsound(loc, hitsound, volume, 1, -1)
L.visible_message("[L] is hit by \a [src][organ_hit_text]!", \
"[L] is hit by \a [src][organ_hit_text]!", null, COMBAT_MESSAGE_RANGE)
+ if(def_zone == BODY_ZONE_HEAD)
+ playsound(src, 'sound/weapons/dink.ogg', 30, 1)
L.on_hit(src)
var/reagent_note
diff --git a/code/modules/projectiles/projectile/bullets/shotgun.dm b/code/modules/projectiles/projectile/bullets/shotgun.dm
index 457ec78e9b..c8c4a73b3b 100644
--- a/code/modules/projectiles/projectile/bullets/shotgun.dm
+++ b/code/modules/projectiles/projectile/bullets/shotgun.dm
@@ -88,8 +88,12 @@
do_sparks(1, TRUE, src)
..()
-// Mech Scattershot
+// Mech Scattershots
/obj/item/projectile/bullet/scattershot
damage = 20
stamina = 65
+
+/obj/item/projectile/bullet/seed
+ damage = 4
+ stamina = 1
diff --git a/code/modules/projectiles/projectile/special/neurotoxin.dm b/code/modules/projectiles/projectile/special/neurotoxin.dm
index def7ea187e..baf1495abb 100644
--- a/code/modules/projectiles/projectile/special/neurotoxin.dm
+++ b/code/modules/projectiles/projectile/special/neurotoxin.dm
@@ -10,5 +10,5 @@
nodamage = TRUE
else if(isliving(target))
var/mob/living/L = target
- L.Knockdown(100, override_duration = 30, override_stam = 25)
+ L.Knockdown(100, TRUE, FALSE, 30, 25)
return ..()
diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm
index 9674485c45..252d0d0dc3 100644
--- a/code/modules/reagents/chemistry/holder.dm
+++ b/code/modules/reagents/chemistry/holder.dm
@@ -361,6 +361,8 @@
var/required_temp = C.required_temp
var/is_cold_recipe = C.is_cold_recipe
var/meets_temp_requirement = 0
+ var/has_special_react = C.special_react
+ var/can_special_react = 0
for(var/B in cached_required_reagents)
if(!has_reagent(B, cached_required_reagents[B]))
@@ -396,7 +398,10 @@
if(required_temp == 0 || (is_cold_recipe && chem_temp <= required_temp) || (!is_cold_recipe && chem_temp >= required_temp))
meets_temp_requirement = 1
- if(total_matching_reagents == total_required_reagents && total_matching_catalysts == total_required_catalysts && matching_container && matching_other && meets_temp_requirement)
+ if(!has_special_react || C.check_special_react(src))
+ can_special_react = 1
+
+ if(total_matching_reagents == total_required_reagents && total_matching_catalysts == total_required_catalysts && matching_container && matching_other && meets_temp_requirement && can_special_react)
possible_reactions += C
if(possible_reactions.len)
@@ -412,6 +417,7 @@
selected_reaction = competitor
var/list/cached_required_reagents = selected_reaction.required_reagents
var/list/cached_results = selected_reaction.results
+ var/special_react_result = selected_reaction.check_special_react(src)
var/list/multiplier = INFINITY
for(var/B in cached_required_reagents)
multiplier = min(multiplier, round(get_reagent_amount(B) / cached_required_reagents[B]))
@@ -443,7 +449,7 @@
ME2.name = "used slime extract"
ME2.desc = "This extract has been used up."
- selected_reaction.on_reaction(src, multiplier)
+ selected_reaction.on_reaction(src, multiplier, special_react_result)
reaction_occurred = 1
while(reaction_occurred)
diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
index f9dbd1928b..6e4d5e5a7d 100644
--- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
@@ -1398,15 +1398,15 @@ All effects don't start immediately, but rather get worse over time; the rate is
/datum/reagent/consumable/ethanol/eggnog
name = "Eggnog"
id = "eggnog"
- description = "For enjoying the most wonderful time of the year."
+ description = "The traditional way to get absolutely hammered at a Christmas party."
color = "#fcfdc6" // rgb: 252, 253, 198
nutriment_factor = 2 * REAGENTS_METABOLISM
boozepwr = 1
quality = DRINK_VERYGOOD
taste_description = "custard and alcohol"
- glass_icon_state = "glass_yellow"
+ glass_icon_state = "nog3"
glass_name = "eggnog"
- glass_desc = "For enjoying the most wonderful time of the year."
+ glass_desc = "The traditional way to get absolutely hammered at a Christmas party."
/datum/reagent/consumable/ethanol/narsour
diff --git a/code/modules/reagents/chemistry/reagents/drug_reagents.dm b/code/modules/reagents/chemistry/reagents/drug_reagents.dm
index eb3daef393..d77756a649 100644
--- a/code/modules/reagents/chemistry/reagents/drug_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/drug_reagents.dm
@@ -167,10 +167,10 @@
/datum/reagent/drug/methamphetamine/on_mob_add(mob/living/L)
..()
- L.add_trait(TRAIT_GOTTAGOREALLYFAST, id)
+ L.add_trait(TRAIT_IGNORESLOWDOWN, id)
/datum/reagent/drug/methamphetamine/on_mob_delete(mob/living/L)
- L.remove_trait(TRAIT_GOTTAGOREALLYFAST, id)
+ L.remove_trait(TRAIT_IGNORESLOWDOWN, id)
..()
/datum/reagent/drug/methamphetamine/on_mob_life(mob/living/carbon/M)
@@ -180,9 +180,12 @@
M.AdjustStun(-40, 0)
M.AdjustKnockdown(-40, 0)
M.AdjustUnconscious(-40, 0)
- M.adjustStaminaLoss(-2, 0)
+ M.adjustStaminaLoss(-7.5 * REM, 0)
M.Jitter(2)
M.adjustBrainLoss(rand(1,4))
+ if(prob(30))
+ M.confused = max(1, M.confused)
+ M.heal_overall_damage(2, 2)
if(prob(5))
M.emote(pick("twitch", "shiver"))
..()
diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm
index 685b37564a..52b212f8c5 100644
--- a/code/modules/reagents/chemistry/reagents/food_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm
@@ -112,7 +112,7 @@
/datum/reagent/consumable/cooking_oil/reaction_obj(obj/O, reac_volume)
if(holder && holder.chem_temp >= fry_temperature)
- if(isitem(O) && !istype(O, /obj/item/reagent_containers/food/snacks/deepfryholder))
+ if(isitem(O) && !istype(O, /obj/item/reagent_containers/food/snacks/deepfryholder) && !(O.resistance_flags & (FIRE_PROOF|INDESTRUCTIBLE)))
O.loc.visible_message("[O] rapidly fries as it's splashed with hot oil! Somehow.")
var/obj/item/reagent_containers/food/snacks/deepfryholder/F = new(O.drop_location(), O)
F.fry(volume)
diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
index 671e62a9e6..4e278d2ede 100644
--- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
@@ -546,19 +546,14 @@
overdose_threshold = 45
addiction_threshold = 30
-/datum/reagent/medicine/ephedrine/on_mob_add(mob/living/L)
- ..()
- L.add_trait(TRAIT_GOTTAGOFAST, id)
-
-/datum/reagent/medicine/ephedrine/on_mob_delete(mob/living/L)
- L.remove_trait(TRAIT_GOTTAGOFAST, id)
- ..()
-
/datum/reagent/medicine/ephedrine/on_mob_life(mob/living/carbon/M)
M.AdjustStun(-20, 0)
M.AdjustKnockdown(-20, 0)
M.AdjustUnconscious(-20, 0)
- M.adjustStaminaLoss(-1*REM, 0)
+ M.adjustStaminaLoss(-4.5*REM, 0)
+ M.Jitter(10)
+ if(prob(50))
+ M.confused = max(M.confused, 1)
..()
return TRUE
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index 53bc7e2c17..4b4f118a9c 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -32,6 +32,12 @@
else
C.blood_volume = min(C.blood_volume + round(reac_volume, 0.1), BLOOD_VOLUME_MAXIMUM)
+ if(reac_volume >= 10 && istype(L))
+ L.add_blood_DNA(list(data["blood_DNA"] = data["blood_type"]))
+
+/datum/reagent/blood/reaction_obj(obj/O, volume)
+ if(volume >= 3 && istype(O))
+ O.add_blood_DNA(list(data["blood_DNA"] = data["blood_type"]))
/datum/reagent/blood/on_new(list/data)
if(istype(data))
@@ -1280,6 +1286,7 @@
reagent_state = SOLID
color = "#FFFFFF" // rgb: 207, 54, 0
taste_description = "the back of class"
+ no_mob_color = TRUE
/datum/reagent/colorful_reagent/crayonpowder/New()
description = "\an [colorname] powder made by grinding down crayons, good for colouring chemical reagents."
@@ -1481,14 +1488,16 @@
color = "#C8A5DC"
var/list/random_color_list = list("#00aedb","#a200ff","#f47835","#d41243","#d11141","#00b159","#00aedb","#f37735","#ffc425","#008744","#0057e7","#d62d20","#ffa700")
taste_description = "rainbows"
-
+ var/no_mob_color = FALSE
/datum/reagent/colorful_reagent/on_mob_life(mob/living/carbon/M)
- M.add_atom_colour(pick(random_color_list), WASHABLE_COLOUR_PRIORITY)
+ if(!no_mob_color)
+ M.add_atom_colour(pick(random_color_list), WASHABLE_COLOUR_PRIORITY)
..()
/datum/reagent/colorful_reagent/reaction_mob(mob/living/M, reac_volume)
- M.add_atom_colour(pick(random_color_list), WASHABLE_COLOUR_PRIORITY)
+ if(!no_mob_color)
+ M.add_atom_colour(pick(random_color_list), WASHABLE_COLOUR_PRIORITY)
..()
/datum/reagent/colorful_reagent/reaction_obj(obj/O, reac_volume)
diff --git a/code/modules/reagents/chemistry/recipes.dm b/code/modules/reagents/chemistry/recipes.dm
index e19d2c20d7..50006eef62 100644
--- a/code/modules/reagents/chemistry/recipes.dm
+++ b/code/modules/reagents/chemistry/recipes.dm
@@ -13,13 +13,17 @@
var/required_temp = 0
var/is_cold_recipe = 0 // Set to 1 if you want the recipe to only react when it's BELOW the required temp.
+ var/special_react = FALSE //Determines if the recipe has special conditions for it to react. Mainly used for ling blood tests
var/mix_message = "The solution begins to bubble." //The message shown to nearby people upon mixing, if applicable
var/mix_sound = 'sound/effects/bubbles.ogg' //The sound played upon mixing, if applicable
-/datum/chemical_reaction/proc/on_reaction(datum/reagents/holder, created_volume)
+/datum/chemical_reaction/proc/on_reaction(datum/reagents/holder, created_volume, specialreact)
return
//I recommend you set the result amount to the total volume of all components.
+/datum/chemical_reaction/proc/check_special_react(datum/reagents/holder)
+ return
+
/datum/chemical_reaction/proc/chemical_mob_spawn(datum/reagents/holder, amount_to_spawn, reaction_name, mob_class = HOSTILE_SPAWN, mob_faction = "chemicalsummon")
if(holder && holder.my_atom)
var/atom/A = holder.my_atom
diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm
index f2e9baeba4..bcd08b1853 100644
--- a/code/modules/reagents/chemistry/recipes/others.dm
+++ b/code/modules/reagents/chemistry/recipes/others.dm
@@ -133,6 +133,18 @@
required_reagents = list("slime_toxin" = 1, "mutagen" = 1)
+/datum/chemical_reaction/fermis_plush
+ name = "Fermis plush"
+ id = "fermis_plush"
+ required_reagents = list("sugar" = 10, "blood" = 10, "stable_plasma" = 10)
+ mob_react = FALSE
+ required_temp = 400
+
+/datum/chemical_reaction/fermis_plush/on_reaction(datum/reagents/holder, created_volume)
+ var/location = get_turf(holder.my_atom)
+ for(var/i = 1, i <= created_volume, i+=10)
+ new /obj/item/toy/plush/catgirl/fermis(location)
+
////////////////////////////////// VIROLOGY //////////////////////////////////////////
/datum/chemical_reaction/virus_food
@@ -592,3 +604,24 @@
id = "pax"
results = list("pax" = 3)
required_reagents = list("mindbreaker" = 1, "synaptizine" = 1, "water" = 1)
+
+/datum/chemical_reaction/cat
+ name = "felined mutation toxic"
+ id = "cats"
+ results = list("felinidmutationtoxin" = 1)
+ required_reagents = list("mindbreaker" = 1, "ammonia" = 1, "water" = 1, "aphro" = 10, "stablemutationtoxin" = 1) // Maybe aphro+ if it becomes a shitty meme
+ required_temp = 450
+
+/datum/chemical_reaction/moff
+ name = "moth mutation toxic"
+ id = "moffs"
+ results = list("mothmutationtoxin" = 1)
+ required_reagents = list("liquid_dark_matter" = 2, "ammonia" = 5, "lithium" = 1, "stablemutationtoxin" = 1)
+ required_temp = 320
+
+/datum/chemical_reaction/notlight //Harder to make do to it being a hard race to play
+ name = "shadow muatatuin toxic"
+ id = "notlight"
+ results = list("shadowmutationtoxin" = 1)
+ required_reagents = list("liquid_dark_matter" = 5, "synaptizine" = 10, "oculine" = 10, "stablemutationtoxin" = 1)
+ required_temp = 600
diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
index 471131ff00..587d6c8b38 100644
--- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
+++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
@@ -464,4 +464,30 @@
results = list("firefighting_foam" = 3)
required_reagents = list("stabilizing_agent" = 1,"fluorosurfactant" = 1,"carbon" = 1)
required_temp = 200
- is_cold_recipe = 1
\ No newline at end of file
+ is_cold_recipe = 1
+
+/datum/chemical_reaction/reagent_explosion/lingblood
+ name = "Changeling Blood Reaction"
+ id = "ling_blood_reaction"
+ results = list("ash" = 1)
+ required_reagents = list("blood" = 1)
+ strengthdiv = 4 //The explosion should be somewhat strong if a full 15u is heated within a syringe. !!fun!!
+ required_temp = 666
+ special_react = TRUE
+ mix_sound = 'sound/effects/lingbloodhiss.ogg'
+ mix_message = "The blood bubbles and sizzles violently!"
+
+/datum/chemical_reaction/reagent_explosion/lingblood/check_special_react(datum/reagents/holder)
+ if(!holder)
+ return FALSE
+ var/list/D = holder.get_data("blood")
+ if(D && D["changeling_loudness"])
+ return (D["changeling_loudness"] >= 4 ? D["changeling_loudness"] : FALSE)
+ else
+ return FALSE
+
+/datum/chemical_reaction/reagent_explosion/lingblood/on_reaction(datum/reagents/holder, created_volume, specialreact)
+ if(specialreact >= 10)
+ return ..()
+ else
+ return FALSE
diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm
index 85868f1895..98c85b875f 100644
--- a/code/modules/reagents/reagent_containers.dm
+++ b/code/modules/reagents/reagent_containers.dm
@@ -82,6 +82,9 @@
if(D.active)
return TRUE
+/obj/item/reagent_containers/proc/ForceResetRotation()
+ transform = initial(transform)
+
/obj/item/reagent_containers/proc/SplashReagents(atom/target, thrown = FALSE)
if(!reagents || !reagents.total_volume || !spillable)
return
@@ -103,6 +106,8 @@
else if(bartender_check(target) && thrown)
visible_message("[src] lands onto the [target.name] without spilling a single drop.")
+ transform = initial(transform)
+ addtimer(CALLBACK(src, .proc/ForceResetRotation), 1)
return
else
diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm
index b88f680dbb..f59f00a4b8 100644
--- a/code/modules/reagents/reagent_containers/hypospray.dm
+++ b/code/modules/reagents/reagent_containers/hypospray.dm
@@ -168,6 +168,13 @@
amount_per_transfer_from_this = 1
list_reagents = list("unstablemutationtoxin" = 1)
+/obj/item/reagent_containers/hypospray/medipen/firelocker
+ name = "fire treatment medipen"
+ desc = "A medipen that has been fulled with burn healing chemicals for personnel without advanced medical knowledge."
+ volume = 15
+ amount_per_transfer_from_this = 15
+ list_reagents = list("oxandrolone" = 5, "kelotane" = 10)
+
/obj/item/reagent_containers/hypospray/combat/heresypurge
name = "holy water autoinjector"
desc = "A modified air-needle autoinjector for use in combat situations. Prefilled with 5 doses of a holy water mixture."
diff --git a/code/modules/reagents/reagent_containers/patch.dm b/code/modules/reagents/reagent_containers/patch.dm
index d4111467ba..12439c6b2f 100644
--- a/code/modules/reagents/reagent_containers/patch.dm
+++ b/code/modules/reagents/reagent_containers/patch.dm
@@ -14,11 +14,11 @@
/obj/item/reagent_containers/pill/patch/attack(mob/living/L, mob/user)
if(ishuman(L))
var/obj/item/bodypart/affecting = L.get_bodypart(check_zone(user.zone_selected))
- if(!L.can_inject(user, 1, affecting)) //like monkey code, thickmaterial stops patches
- return
if(!affecting)
to_chat(user, "The limb is missing!")
return
+ if(!L.can_inject(user, TRUE, user.zone_selected, FALSE, TRUE)) //stopped by clothing, not by species immunity.
+ return
if(affecting.status != BODYPART_ORGANIC)
to_chat(user, "Medicine won't work on a robotic limb!")
return
diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm
index 8941724274..b5d00d2ba4 100644
--- a/code/modules/reagents/reagent_containers/pill.dm
+++ b/code/modules/reagents/reagent_containers/pill.dm
@@ -81,66 +81,77 @@
icon_state = "pill5"
list_reagents = list("toxin" = 50)
roundstart = 1
+
/obj/item/reagent_containers/pill/cyanide
name = "cyanide pill"
desc = "Don't swallow this."
icon_state = "pill5"
list_reagents = list("cyanide" = 50)
roundstart = 1
+
/obj/item/reagent_containers/pill/adminordrazine
name = "adminordrazine pill"
desc = "It's magic. We don't have to explain it."
icon_state = "pill16"
list_reagents = list("adminordrazine" = 50)
roundstart = 1
+
/obj/item/reagent_containers/pill/morphine
name = "morphine pill"
desc = "Commonly used to treat insomnia."
icon_state = "pill8"
list_reagents = list("morphine" = 30)
roundstart = 1
+
/obj/item/reagent_containers/pill/stimulant
name = "stimulant pill"
desc = "Often taken by overworked employees, athletes, and the inebriated. You'll snap to attention immediately!"
icon_state = "pill19"
list_reagents = list("ephedrine" = 10, "antihol" = 10, "coffee" = 30)
roundstart = 1
+
/obj/item/reagent_containers/pill/salbutamol
name = "salbutamol pill"
desc = "Used to treat oxygen deprivation."
icon_state = "pill16"
list_reagents = list("salbutamol" = 30)
roundstart = 1
+
/obj/item/reagent_containers/pill/charcoal
name = "charcoal pill"
desc = "Neutralizes many common toxins."
icon_state = "pill17"
list_reagents = list("charcoal" = 10)
roundstart = 1
+
/obj/item/reagent_containers/pill/epinephrine
name = "epinephrine pill"
desc = "Used to stabilize patients."
icon_state = "pill5"
list_reagents = list("epinephrine" = 15)
roundstart = 1
+
/obj/item/reagent_containers/pill/mannitol
name = "mannitol pill"
desc = "Used to treat brain damage."
icon_state = "pill17"
list_reagents = list("mannitol" = 50)
roundstart = 1
+
/obj/item/reagent_containers/pill/mutadone
name = "mutadone pill"
desc = "Used to treat genetic damage."
icon_state = "pill20"
list_reagents = list("mutadone" = 50)
roundstart = 1
+
/obj/item/reagent_containers/pill/salicyclic
name = "salicylic acid pill"
desc = "Used to dull pain."
icon_state = "pill9"
list_reagents = list("sal_acid" = 24)
roundstart = 1
+
/obj/item/reagent_containers/pill/oxandrolone
name = "oxandrolone pill"
desc = "Used to stimulate burn healing."
@@ -154,6 +165,13 @@
icon_state = "pill18"
list_reagents = list("insulin" = 50)
roundstart = 1
+
+/obj/item/reagent_containers/pill/antirad
+ name = "potassium iodide pill"
+ desc = "Used to treat radition used to counter radiation poisoning."
+ icon_state = "pill18"
+ list_reagents = list("potass_iodide" = 50)
+ roundstart = 1
///////////////////////////////////////// this pill is used only in a legion mob drop
/obj/item/reagent_containers/pill/shadowtoxin
name = "black pill"
diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm
index e3576b3625..a51134f84d 100644
--- a/code/modules/reagents/reagent_containers/spray.dm
+++ b/code/modules/reagents/reagent_containers/spray.dm
@@ -166,6 +166,15 @@
user.visible_message("[user] decided life was worth living.")
return
+//Drying Agent
+/obj/item/reagent_containers/spray/drying_agent
+ name = "drying agent spray"
+ desc = "A spray bottle for drying agent."
+ volume = 100
+ list_reagents = list("drying_agent" = 100)
+ amount_per_transfer_from_this = 2
+ stream_amount = 5
+
//spray tan
/obj/item/reagent_containers/spray/spraytan
name = "spray tan"
diff --git a/code/modules/recycling/disposal/pipe.dm b/code/modules/recycling/disposal/pipe.dm
index 6c269e44be..aed2310a7f 100644
--- a/code/modules/recycling/disposal/pipe.dm
+++ b/code/modules/recycling/disposal/pipe.dm
@@ -1,5 +1,7 @@
// Disposal pipes
+#define IFFY 2
+
/obj/structure/disposalpipe
name = "disposal pipe"
desc = "An underfloor disposal pipe."
@@ -16,6 +18,7 @@
var/dpdir = NONE // bitmask of pipe directions
var/initialize_dirs = NONE // bitflags of pipe directions added on init, see \code\_DEFINES\pipe_construction.dm
var/flip_type // If set, the pipe is flippable and becomes this type when flipped
+ var/canclank = FALSE // Determines if the pipe will cause a clank sound when holders pass by it. use the IFFY define for weird-ass edge cases like the segment subtype
var/obj/structure/disposalconstruct/stored
@@ -75,6 +78,8 @@
H.merge(H2)
H.forceMove(P)
+ if(P.canclank == TRUE || (P.canclank == IFFY && P.dpdir != 3 && P.dpdir != 12))
+ playsound(P, H.hasmob ? "clang" : "clangsmall", H.hasmob ? 50 : 25, 1)
return P
else // if wasn't a pipe, then they're now in our turf
H.forceMove(get_turf(src))
@@ -184,6 +189,7 @@
/obj/structure/disposalpipe/segment
icon_state = "pipe"
initialize_dirs = DISP_DIR_FLIP
+ canclank = IFFY
// A three-way junction with dir being the dominant direction
@@ -191,6 +197,7 @@
icon_state = "pipe-j1"
initialize_dirs = DISP_DIR_RIGHT | DISP_DIR_FLIP
flip_type = /obj/structure/disposalpipe/junction/flip
+ canclank = TRUE
// next direction to move
// if coming in from secondary dirs, then next is primary dir
@@ -229,6 +236,7 @@
//a trunk joining to a disposal bin or outlet on the same turf
/obj/structure/disposalpipe/trunk
icon_state = "pipe-t"
+ canclank = TRUE
var/obj/linked // the linked obj/machinery/disposal or obj/disposaloutlet
/obj/structure/disposalpipe/trunk/Initialize()
@@ -299,3 +307,5 @@
/obj/structure/disposalpipe/broken/deconstruct()
qdel(src)
+
+#undef IFFY
diff --git a/code/modules/recycling/disposal/pipe_sorting.dm b/code/modules/recycling/disposal/pipe_sorting.dm
index 5e26e9b767..d85c4bca78 100644
--- a/code/modules/recycling/disposal/pipe_sorting.dm
+++ b/code/modules/recycling/disposal/pipe_sorting.dm
@@ -5,6 +5,7 @@
desc = "An underfloor disposal pipe with a sorting mechanism."
icon_state = "pipe-j1s"
initialize_dirs = DISP_DIR_RIGHT | DISP_DIR_FLIP
+ canclank = TRUE
/obj/structure/disposalpipe/sorting/nextdir(obj/structure/disposalholder/H)
var/sortdir = dpdir & ~(dir | turn(dir, 180))
diff --git a/code/modules/research/designs/electronics_designs.dm b/code/modules/research/designs/electronics_designs.dm
index e9db641811..552976824d 100644
--- a/code/modules/research/designs/electronics_designs.dm
+++ b/code/modules/research/designs/electronics_designs.dm
@@ -118,3 +118,16 @@
build_path = /obj/item/disk/integrated_circuit/upgrade/clone
category = list("Electronics")
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
+
+//CIT ADDITIONS
+/datum/design/drone_shell
+ name = "Drone Shell"
+ desc = "A shell of a maintenance drone, an expendable robot built to perform station repairs."
+ id = "drone_shell"
+ build_type = MECHFAB | PROTOLATHE
+ materials = list(MAT_METAL = 800, MAT_GLASS = 350)
+ construction_time = 150
+ build_path = /obj/item/drone_shell
+ category = list("Misc")
+ departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
+
diff --git a/code/modules/research/designs/mecha_designs.dm b/code/modules/research/designs/mecha_designs.dm
index cee0dc7413..3ee7d344dc 100644
--- a/code/modules/research/designs/mecha_designs.dm
+++ b/code/modules/research/designs/mecha_designs.dm
@@ -147,6 +147,16 @@
construction_time = 100
category = list("Exosuit Equipment")
+/datum/design/mech_seedscatter
+ name = "Exosuit Weapon (Melon Seed \"Scattershot\")"
+ desc = "Allows for the construction of Melon Seed Scattershot."
+ id = "mech_seedscatter"
+ build_type = MECHFAB
+ build_path = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/seedscatter
+ materials = list(MAT_METAL=10000, MAT_GLASS = 10000)
+ construction_time = 70
+ category = list("Exosuit Equipment")
+
/datum/design/mech_carbine
name = "Exosuit Weapon (FNX-99 \"Hades\" Carbine)"
desc = "Allows for the construction of FNX-99 \"Hades\" Carbine."
diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm
index b7da52468b..ca3f2b420b 100644
--- a/code/modules/research/designs/medical_designs.dm
+++ b/code/modules/research/designs/medical_designs.dm
@@ -44,6 +44,16 @@
category = list("Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+/datum/design/medicalkit
+ name = "Empty Medkit"
+ desc = "A plastic medical kit for storging medical items."
+ id = "medicalkit"
+ build_type = PROTOLATHE
+ materials = list(MAT_PLASTIC = 5000)
+ build_path = /obj/item/storage/firstaid //So we dont spawn medical items in it
+ category = list("Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
+
/datum/design/xlarge_beaker
name = "X-large Beaker"
id = "xlarge_beaker"
@@ -526,6 +536,80 @@
category = list("Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+/////////////////////
+//Adv Surgery Tools//
+/////////////////////
+
+/datum/design/drapes
+ name = "Plastic Drapes"
+ desc = "A large surgery drape made of plastic."
+ id = "drapes"
+ build_type = PROTOLATHE
+ materials = list(MAT_PLASTIC = 2500)
+ build_path = /obj/item/surgical_drapes
+ category = list("Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/retractor_adv
+ name = "Advanced Retractor"
+ desc = "A high-class, premium retractor, featuring precision crafted, silver-plated hook-ends and an electrum handle."
+ id = "retractor_adv"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 1500, MAT_GOLD = 1000)
+ build_path = /obj/item/retractor/adv
+ category = list("Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/hemostat_adv
+ name = "Advanced Hemostat"
+ desc = "An exceptionally fine pair of arterial forceps. These appear to be plated in electrum and feel soft to the touch."
+ id = "hemostat_adv"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 1000, MAT_GOLD = 1500)
+ build_path = /obj/item/hemostat/adv
+ category = list("Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/cautery_adv
+ name = "Electrocautery" //This is based on real-life science.
+ desc = "A high-tech unipolar Electrocauter. This tiny device contains an extremely powerful microbattery that uses arcs of electricity to painlessly sear wounds shut. It seems to recharge with the user's body-heat. Wow!"
+ id = "cautery_adv"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 1000, MAT_GOLD = 1500)
+ build_path = /obj/item/cautery/adv
+ category = list("Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/surgicaldrill_adv
+ name = "Surgical Autodrill"
+ desc = "With a diamond tip and built-in depth and safety sensors, this drill alerts the user before overpenetrating a patient's skull or tooth. There also appears to be a disable switch."
+ id = "surgicaldrill_adv"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 2500, MAT_GLASS = 2500, MAT_SILVER = 6000, MAT_GOLD = 5500, MAT_DIAMOND = 3500)
+ build_path = /obj/item/surgicaldrill/adv
+ category = list("Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/scalpel_adv
+ name = "Precision Scalpel"
+ desc = "A perfectly balanced electrum scalpel with a silicon-coated edge to eliminate wear and tear."
+ id = "scalpel_adv"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 1500, MAT_GLASS = 1500, MAT_SILVER = 4000, MAT_GOLD = 2500)
+ build_path = /obj/item/scalpel/adv
+ category = list("Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
+
+/datum/design/circular_saw_adv
+ name = "Diamond-Grit Circular Saw"
+ desc = "For those Assistants with REALLY thick skulls."
+ id = "circular_saw_adv"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 7500, MAT_GLASS = 6000, MAT_SILVER = 6500, MAT_GOLD = 7500, MAT_DIAMOND = 4500)
+ build_path = /obj/item/circular_saw/adv
+ category = list("Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
+
/////////////////////
///Surgery Designs///
/////////////////////
diff --git a/code/modules/research/designs/misc_designs.dm b/code/modules/research/designs/misc_designs.dm
index 0ac01aec38..d567334998 100644
--- a/code/modules/research/designs/misc_designs.dm
+++ b/code/modules/research/designs/misc_designs.dm
@@ -13,6 +13,16 @@
category = list("Equipment")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+/datum/design/health_hud_prescription
+ name = "Prescription Health Scanner HUD"
+ desc = "A heads-up display that scans the humans in view and provides accurate data about their health status. This one has a prescription lens."
+ id = "health_hud_prescription"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 350)
+ build_path = /obj/item/clothing/glasses/hud/health/prescription
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+
/datum/design/health_hud_night
name = "Night Vision Health Scanner HUD"
desc = "An advanced medical head-up display that allows doctors to find patients in complete darkness."
@@ -33,6 +43,17 @@
category = list("Equipment")
departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+/datum/design/security_hud_prescription
+ name = "Prescription Security HUD"
+ desc = "A heads-up display that scans the humans in view and provides accurate data about their ID status. This one has a prescription lens."
+ id = "security_hud_prescription"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 350)
+ build_path = /obj/item/clothing/glasses/hud/security/prescription
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+
+
/datum/design/security_hud_night
name = "Night Vision Security HUD"
desc = "A heads-up display which provides id data and vision in complete darkness."
@@ -53,6 +74,16 @@
category = list("Equipment")
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
+/datum/design/diagnostic_hud_prescription
+ name = "Prescription Diagnostic HUD"
+ desc = "A HUD used to analyze and determine faults within robotic machinery. This one has a prescription lens."
+ id = "diagnostic_hud_prescription"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_GOLD = 350)
+ build_path = /obj/item/clothing/glasses/hud/diagnostic/prescription
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
+
/datum/design/diagnostic_hud_night
name = "Night Vision Diagnostic HUD"
desc = "Upgraded version of the diagnostic HUD designed to function during a power failure."
@@ -107,6 +138,16 @@
category = list("Equipment")
departmental_flags = DEPARTMENTAL_FLAG_CARGO | DEPARTMENTAL_FLAG_ENGINEERING
+/datum/design/mesons_prescription
+ name = "Prescription Optical Meson Scanners"
+ desc = "Used by engineering and mining staff to see basic structural and terrain layouts through walls, regardless of lighting condition. Prescription lens has been added into this design."
+ id = "mesons_prescription"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 350)
+ build_path = /obj/item/clothing/glasses/meson/prescription
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_CARGO | DEPARTMENTAL_FLAG_ENGINEERING
+
/datum/design/engine_goggles
name = "Engineering Scanner Goggles"
desc = "Goggles used by engineers. The Meson Scanner mode lets you see basic structural and terrain layouts through walls, regardless of lighting condition. The T-ray Scanner mode lets you see underfloor objects such as cables and pipes."
@@ -117,6 +158,16 @@
category = list("Equipment")
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+/datum/design/engine_goggles_prescription
+ name = "Prescription Engineering Scanner Goggles"
+ desc = "Goggles used by engineers. The Meson Scanner mode lets you see basic structural and terrain layouts through walls, regardless of lighting condition. The T-ray Scanner mode lets you see underfloor objects such as cables and pipes. Prescription lens has been added into this design."
+ id = "engine_goggles_prescription"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_PLASMA = 100, MAT_SILVER = 350)
+ build_path = /obj/item/clothing/glasses/meson/engine/prescription
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+
/datum/design/tray_goggles
name = "Optical T-Ray Scanners"
desc = "Used by engineering staff to see underfloor objects such as cables and pipes."
@@ -127,6 +178,16 @@
category = list("Equipment")
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+/datum/design/tray_goggles_prescription
+ name = "Prescription Optical T-Ray Scanners"
+ desc = "Used by engineering staff to see underfloor objects such as cables and pipes. Prescription lens has been added into this design."
+ id = "tray_goggles_prescription"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 150)
+ build_path = /obj/item/clothing/glasses/meson/engine/tray/prescription
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+
/datum/design/nvgmesons
name = "Night Vision Optical Meson Scanners"
desc = "Prototype meson scanners fitted with an extra sensor which amplifies the visible light spectrum and overlays it to the UHD display."
@@ -187,86 +248,6 @@
category = list("Equipment")
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
-/datum/design/handdrill
- name = "Hand Drill"
- desc = "A small electric hand drill with an interchangeable screwdriver and bolt bit"
- id = "handdrill"
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 3500, MAT_SILVER = 1500, MAT_TITANIUM = 2500)
- build_path = /obj/item/screwdriver/power
- category = list("Equipment")
- departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
-
-/datum/design/jawsoflife
- name = "Jaws of Life"
- desc = "A small, compact Jaws of Life with an interchangeable pry jaws and cutting jaws"
- id = "jawsoflife" // added one more requirment since the Jaws of Life are a bit OP
- build_path = /obj/item/crowbar/power
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 4500, MAT_SILVER = 2500, MAT_TITANIUM = 3500)
- category = list("Equipment")
- departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
-
-/datum/design/alienwrench
- name = "Alien Wrench"
- desc = "An advanced wrench obtained through Abductor technology."
- id = "alien_wrench"
- build_path = /obj/item/wrench/abductor
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000)
- category = list("Equipment")
- departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
-
-/datum/design/alienwirecutters
- name = "Alien Wirecutters"
- desc = "Advanced wirecutters obtained through Abductor technology."
- id = "alien_wirecutters"
- build_path = /obj/item/wirecutters/abductor
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000)
- category = list("Equipment")
- departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
-
-/datum/design/alienscrewdriver
- name = "Alien Screwdriver"
- desc = "An advanced screwdriver obtained through Abductor technology."
- id = "alien_screwdriver"
- build_path = /obj/item/screwdriver/abductor
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000)
- category = list("Equipment")
- departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
-
-/datum/design/aliencrowbar
- name = "Alien Crowbar"
- desc = "An advanced crowbar obtained through Abductor technology."
- id = "alien_crowbar"
- build_path = /obj/item/crowbar/abductor
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000)
- category = list("Equipment")
- departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
-
-/datum/design/alienwelder
- name = "Alien Welding Tool"
- desc = "An advanced welding tool obtained through Abductor technology."
- id = "alien_welder"
- build_path = /obj/item/weldingtool/abductor
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 5000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000)
- category = list("Equipment")
- departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
-
-/datum/design/alienmultitool
- name = "Alien Multitool"
- desc = "An advanced multitool obtained through Abductor technology."
- id = "alien_multitool"
- build_path = /obj/item/multitool/abductor
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 5000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000)
- category = list("Equipment")
- departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
-
/datum/design/diskplantgene
name = "Plant Data Disk"
desc = "A disk for storing plant genetic data."
@@ -385,6 +366,86 @@
category = list("Equipment")
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING
+/datum/design/handdrill
+ name = "Hand Drill"
+ desc = "A small electric hand drill with an interchangeable screwdriver and bolt bit"
+ id = "handdrill"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 3500, MAT_SILVER = 1500, MAT_TITANIUM = 2500)
+ build_path = /obj/item/screwdriver/power
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+
+/datum/design/jawsoflife
+ name = "Jaws of Life"
+ desc = "A small, compact Jaws of Life with an interchangeable pry jaws and cutting jaws"
+ id = "jawsoflife" // added one more requirment since the Jaws of Life are a bit OP
+ build_path = /obj/item/crowbar/power
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 4500, MAT_SILVER = 2500, MAT_TITANIUM = 3500)
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+
+/datum/design/alienwrench
+ name = "Alien Wrench"
+ desc = "An advanced wrench obtained through Abductor technology."
+ id = "alien_wrench"
+ build_path = /obj/item/wrench/abductor
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000)
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+
+/datum/design/alienwirecutters
+ name = "Alien Wirecutters"
+ desc = "Advanced wirecutters obtained through Abductor technology."
+ id = "alien_wirecutters"
+ build_path = /obj/item/wirecutters/abductor
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000)
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+
+/datum/design/alienscrewdriver
+ name = "Alien Screwdriver"
+ desc = "An advanced screwdriver obtained through Abductor technology."
+ id = "alien_screwdriver"
+ build_path = /obj/item/screwdriver/abductor
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000)
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+
+/datum/design/aliencrowbar
+ name = "Alien Crowbar"
+ desc = "An advanced crowbar obtained through Abductor technology."
+ id = "alien_crowbar"
+ build_path = /obj/item/crowbar/abductor
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000)
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+
+/datum/design/alienwelder
+ name = "Alien Welding Tool"
+ desc = "An advanced welding tool obtained through Abductor technology."
+ id = "alien_welder"
+ build_path = /obj/item/weldingtool/abductor
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 5000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000)
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+
+/datum/design/alienmultitool
+ name = "Alien Multitool"
+ desc = "An advanced multitool obtained through Abductor technology."
+ id = "alien_multitool"
+ build_path = /obj/item/multitool/abductor
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 5000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000)
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+
/datum/design/anomaly_neutralizer
name = "Anomaly Neutralizer"
desc = "An advanced tool capable of instantly neutralizing anomalies, designed to capture the fleeting aberrations created by the engine."
diff --git a/code/modules/research/designs/weapon_designs.dm b/code/modules/research/designs/weapon_designs.dm
index bf503c2653..9b42709fe2 100644
--- a/code/modules/research/designs/weapon_designs.dm
+++ b/code/modules/research/designs/weapon_designs.dm
@@ -218,8 +218,8 @@
//WT550 Mags
/datum/design/mag_oldsmg
- name = "WT-550 Auto Gun Magazine (4.6x30mm)"
- desc = "A 20 round magazine for the out of date security WT-550 Auto Rifle"
+ name = "WT-550 Semi-Auto SMG Magazine (4.6x30mm)"
+ desc = "A 20 round magazine for the out of date security WT-550 Semi-Auto SMG."
id = "mag_oldsmg"
build_type = PROTOLATHE
materials = list(MAT_METAL = 4000)
@@ -228,16 +228,16 @@
departmental_flags = DEPARTMENTAL_FLAG_SECURITY
/datum/design/mag_oldsmg/ap_mag
- name = "WT-550 Auto Gun Armour Piercing Magazine (4.6x30mm AP)"
- desc = "A 20 round armour piercing magazine for the out of date security WT-550 Auto Rifle"
+ name = "WT-550 Semi-Auto SMG Armour Piercing Magazine (4.6x30mm AP)"
+ desc = "A 20 round armour piercing magazine for the out of date security WT-550 Semi-Auto SMG."
id = "mag_oldsmg_ap"
materials = list(MAT_METAL = 6000, MAT_SILVER = 600)
build_path = /obj/item/ammo_box/magazine/wt550m9/wtap
departmental_flags = DEPARTMENTAL_FLAG_SECURITY
/datum/design/mag_oldsmg/ic_mag
- name = "WT-550 Auto Gun Incendiary Magazine (4.6x30mm IC)"
- desc = "A 20 round armour piercing magazine for the out of date security WT-550 Auto Rifle"
+ name = "WT-550 Semi-Auto SMG Incendiary Magazine (4.6x30mm IC)"
+ desc = "A 20 round armour piercing magazine for the out of date security WT-550 Semi-Auto SMG."
id = "mag_oldsmg_ic"
materials = list(MAT_METAL = 6000, MAT_SILVER = 600, MAT_GLASS = 1000)
build_path = /obj/item/ammo_box/magazine/wt550m9/wtic
@@ -294,7 +294,7 @@
departmental_flags = DEPARTMENTAL_FLAG_SECURITY
/datum/design/cryostatis_shotgun_dart
- name = "Cryostatis Shotgun Dart"
+ name = "Cryostasis Shotgun Dart"
desc = "A shotgun dart designed with similar internals to that of a cryostatis beaker, allowing reagents to not react when inside."
id = "shotgundartcryostatis"
build_type = PROTOLATHE
diff --git a/code/modules/research/machinery/_production.dm b/code/modules/research/machinery/_production.dm
index d3cd399635..6670a01284 100644
--- a/code/modules/research/machinery/_production.dm
+++ b/code/modules/research/machinery/_production.dm
@@ -80,10 +80,10 @@
reagents.trans_to(G, G.reagents.maximum_volume)
return ..()
-/obj/machinery/rnd/production/proc/do_print(path, amount, list/matlist, notify_admins)
+/obj/machinery/rnd/production/proc/do_print(path, amount, list/matlist, notify_admins, mob/user)
if(notify_admins)
- investigate_log("[key_name(usr)] built [amount] of [path] at [src]([type]).", INVESTIGATE_RESEARCH)
- message_admins("[ADMIN_LOOKUPFLW(usr)] has built [amount] of [path] at a [src]([type]).")
+ investigate_log("[key_name(user)] built [amount] of [path] at [src]([type]).", INVESTIGATE_RESEARCH)
+ message_admins("[ADMIN_LOOKUPFLW(user)] has built [amount] of [path] at a [src]([type]).")
for(var/i in 1 to amount)
var/obj/item/I = new path(get_turf(src))
if(efficient_with(I.type))
@@ -155,7 +155,7 @@
flick(production_animation, src)
var/timecoeff = D.lathe_time_factor / efficiency_coeff
addtimer(CALLBACK(src, .proc/reset_busy), (30 * timecoeff * amount) ** 0.5)
- addtimer(CALLBACK(src, .proc/do_print, D.build_path, amount, efficient_mats, D.dangerous_construction), (32 * timecoeff * amount) ** 0.8)
+ addtimer(CALLBACK(src, .proc/do_print, D.build_path, amount, efficient_mats, D.dangerous_construction, usr), (32 * timecoeff * amount) ** 0.8)
return TRUE
/obj/machinery/rnd/production/proc/search(string)
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index 826f8d05b8..e7bbd468dc 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -43,13 +43,24 @@
description = "Various tools fit for basic mech units"
design_ids = list("mech_drill", "mech_mscanner", "mech_extinguisher", "mech_cable_layer")
+
+/datum/techweb_node/surplus_lims
+ id = "surplus_lims"
+ display_name = "Basic Prosthetics"
+ description = "Basic fragile lims for the impaired."
+ starting_node = TRUE
+ prereq_ids = list("biotech")
+ design_ids = list("basic_l_arm", "basic_r_arm", "basic_r_leg", "basic_l_leg")
+ export_price = 5000
+
+
/////////////////////////Biotech/////////////////////////
/datum/techweb_node/biotech
id = "biotech"
display_name = "Biological Technology"
description = "What makes us tick." //the MC, silly!
prereq_ids = list("base")
- design_ids = list("chem_heater", "chem_master", "chem_dispenser", "sleeper", "vr_sleeper", "pandemic", "defibmount", "operating", "soda_dispenser", "beer_dispenser", "healthanalyzer", "blood_bag")
+ design_ids = list("medicalkit", "chem_heater", "chem_master", "chem_dispenser", "sleeper", "vr_sleeper", "pandemic", "defibmount", "operating", "soda_dispenser", "beer_dispenser", "healthanalyzer", "blood_bag")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
@@ -71,21 +82,21 @@
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
-/datum/techweb_node/surplus_lims
- id = "surplus_lims"
- display_name = "Basic Prosthetics"
- description = "Basic fragile lims for the impaired."
- prereq_ids = list("biotech")
- design_ids = list("basic_l_arm", "basic_r_arm", "basic_r_leg", "basic_l_leg")
- research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1000) // You can knock them off with a glass shard...
- export_price = 5000
-
/datum/techweb_node/advance_lims
id = "advance_lims"
display_name = "Upgraded Prosthetics"
description = "Reinforced prosthetics for the impaired."
prereq_ids = list("adv_biotech", "surplus_lims")
design_ids = list("adv_l_arm", "adv_r_arm", "adv_r_leg", "adv_l_leg")
+ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1250)
+ export_price = 5000
+
+/datum/techweb_node/advance_surgerytools
+ id = "advance_surgerytools"
+ display_name = "Advanced Surgery Tools"
+ description = "Refined and improved redesigns for the run-of-the-mill medical utensils."
+ prereq_ids = list("adv_biotech", "adv_surgery")
+ design_ids = list("drapes", "retractor_adv", "hemostat_adv", "cautery_adv", "surgicaldrill_adv", "scalpel_adv", "circular_saw_adv")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
@@ -152,7 +163,7 @@
display_name = "Advanced Engineering"
description = "Pushing the boundaries of physics, one chainsaw-fist at a time."
prereq_ids = list("engineering", "emp_basic")
- design_ids = list("engine_goggles", "magboots", "forcefield_projector", "weldingmask")
+ design_ids = list("engine_goggles", "magboots", "forcefield_projector", "weldingmask", "tray_goggles_prescription", "engine_goggles_prescription", "mesons_prescription")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 4000)
export_price = 5000
@@ -254,7 +265,7 @@
display_name = "Basic Robotics Research"
description = "Programmable machines that make our lives lazier."
prereq_ids = list("base")
- design_ids = list("paicard")
+ design_ids = list("paicard", "drone_shell")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2000)
export_price = 5000
@@ -415,7 +426,7 @@
display_name = "Integrated HUDs"
description = "The usefulness of computerized records, projected straight onto your eyepiece!"
prereq_ids = list("comp_recordkeeping", "emp_basic")
- design_ids = list("health_hud", "security_hud", "diagnostic_hud", "scigoggles")
+ design_ids = list("health_hud", "security_hud", "diagnostic_hud", "scigoggles", "health_hud_prescription", "security_hud_prescription", "diagnostic_hud_prescription")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1500)
export_price = 5000
@@ -424,7 +435,7 @@
display_name = "Night Vision Technology"
description = "Allows seeing in the dark without actual light!"
prereq_ids = list("integrated_HUDs", "adv_engi", "emp_adv")
- design_ids = list("health_hud_night", "security_hud_night", "diagnostic_hud_night", "night_visision_goggles", "night_visision_goggles_glasses", "nvgmesons")
+ design_ids = list("health_hud_night", "security_hud_night", "diagnostic_hud_night", "night_visision_goggles", "nvgmesons", "night_visision_goggles_glasses")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000)
export_price = 5000
@@ -724,6 +735,15 @@
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
+/datum/techweb_node/mech_seedscatter
+ id = "mech_seedscatter"
+ display_name = "Exosuit Weapon (Melon Seed \"Scattershot\")"
+ description = "An advanced piece of mech weaponry"
+ prereq_ids = list("ballistic_weapons")
+ design_ids = list("mech_seedscatter")
+ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
+ export_price = 5000
+
/datum/techweb_node/mech_carbine
id = "mech_carbine"
display_name = "Exosuit Weapon (FNX-99 \"Hades\" Carbine)"
diff --git a/code/modules/research/xenobiology/crossbreeding/_corecross.dm b/code/modules/research/xenobiology/crossbreeding/__corecross.dm
similarity index 100%
rename from code/modules/research/xenobiology/crossbreeding/_corecross.dm
rename to code/modules/research/xenobiology/crossbreeding/__corecross.dm
diff --git a/code/modules/research/xenobiology/crossbreeding/_clothing.dm b/code/modules/research/xenobiology/crossbreeding/_clothing.dm
new file mode 100644
index 0000000000..016fd95899
--- /dev/null
+++ b/code/modules/research/xenobiology/crossbreeding/_clothing.dm
@@ -0,0 +1,144 @@
+/*
+Slimecrossing Armor
+ Armor added by the slimecrossing system.
+ Collected here for clarity.
+*/
+
+//Rebreather mask - Chilling Blue
+/obj/item/clothing/mask/nobreath
+ name = "rebreather mask"
+ desc = "A transparent mask, resembling a conventional breath mask, but made of bluish slime. Seems to lack any air supply tube, though."
+ icon_state = "slime"
+ item_state = "slime"
+ body_parts_covered = NONE
+ w_class = WEIGHT_CLASS_SMALL
+ gas_transfer_coefficient = 0
+ permeability_coefficient = 0.5
+ flags_cover = MASKCOVERSMOUTH
+ resistance_flags = NONE
+
+/obj/item/clothing/mask/nobreath/equipped(mob/living/carbon/human/user, slot)
+ . = ..()
+ if(slot == SLOT_WEAR_MASK)
+ user.add_trait(TRAIT_NOBREATH, "breathmask_[REF(src)]")
+ user.failed_last_breath = FALSE
+ user.clear_alert("not_enough_oxy")
+ user.apply_status_effect(/datum/status_effect/rebreathing)
+
+/obj/item/clothing/mask/nobreath/dropped(mob/living/carbon/human/user)
+ ..()
+ user.remove_trait(TRAIT_NOBREATH, "breathmask_[REF(src)]")
+ user.remove_status_effect(/datum/status_effect/rebreathing)
+
+/obj/item/clothing/glasses/prism_glasses
+ name = "prism glasses"
+ desc = "The lenses seem to glow slightly, and reflect light into dazzling colors."
+ icon = 'icons/obj/slimecrossing.dmi'
+ icon_state = "prismglasses"
+ actions_types = list(/datum/action/item_action/change_prism_colour, /datum/action/item_action/place_light_prism)
+ var/glasses_color = "#FFFFFF"
+
+/obj/item/clothing/glasses/prism_glasses/item_action_slot_check(slot)
+ if(slot == SLOT_GLASSES)
+ return TRUE
+
+/obj/structure/light_prism
+ name = "light prism"
+ desc = "A shining crystal of semi-solid light. Looks fragile."
+ icon = 'icons/obj/slimecrossing.dmi'
+ icon_state = "lightprism"
+ density = FALSE
+ anchored = TRUE
+ max_integrity = 10
+
+/obj/structure/light_prism/Initialize(mapload, var/newcolor)
+ . = ..()
+ color = newcolor
+ light_color = newcolor
+ set_light(5)
+
+/obj/structure/light_prism/attack_hand(mob/user)
+ to_chat(user, "You dispel [src]")
+ qdel(src)
+
+/datum/action/item_action/change_prism_colour
+ name = "Adjust Prismatic Lens"
+ icon_icon = 'icons/obj/slimecrossing.dmi'
+ button_icon_state = "prismcolor"
+
+/datum/action/item_action/change_prism_colour/Trigger()
+ if(!IsAvailable())
+ return
+ var/obj/item/clothing/glasses/prism_glasses/glasses = target
+ var/new_color = input(owner, "Choose the lens color:", "Color change",glasses.glasses_color) as color|null
+ if(!new_color)
+ return
+ glasses.glasses_color = new_color
+
+/datum/action/item_action/place_light_prism
+ name = "Fabricate Light Prism"
+ icon_icon = 'icons/obj/slimecrossing.dmi'
+ button_icon_state = "lightprism"
+
+/datum/action/item_action/place_light_prism/Trigger()
+ if(!IsAvailable())
+ return
+ var/obj/item/clothing/glasses/prism_glasses/glasses = target
+ if(locate(/obj/structure/light_prism) in get_turf(owner))
+ to_chat(owner, "There isn't enough ambient energy to fabricate another light prism here.")
+ return
+ if(istype(glasses))
+ if(!glasses.glasses_color)
+ to_chat(owner, "The lens is oddly opaque...")
+ return
+ to_chat(owner, "You channel nearby light into a glowing, ethereal prism.")
+ new /obj/structure/light_prism(get_turf(owner), glasses.glasses_color)
+
+/obj/item/clothing/head/peaceflower
+ name = "heroine bud"
+ desc = "An extremely addictive flower, full of peace magic."
+ icon = 'icons/obj/slimecrossing.dmi'
+ icon_state = "peaceflower"
+ item_state = "peaceflower"
+ slot_flags = ITEM_SLOT_HEAD
+ body_parts_covered = NONE
+ dynamic_hair_suffix = ""
+ force = 0
+ throwforce = 0
+ w_class = WEIGHT_CLASS_TINY
+ throw_speed = 1
+ throw_range = 3
+
+/obj/item/clothing/head/peaceflower/equipped(mob/living/carbon/human/user, slot)
+ . = ..()
+ if(slot == SLOT_HEAD)
+ user.add_trait(TRAIT_PACIFISM, "peaceflower_[REF(src)]")
+
+/obj/item/clothing/head/peaceflower/dropped(mob/living/carbon/human/user)
+ ..()
+ user.remove_trait(TRAIT_PACIFISM, "peaceflower_[REF(src)]")
+
+/obj/item/clothing/head/peaceflower/attack_hand(mob/user)
+ if(iscarbon(user))
+ var/mob/living/carbon/C = user
+ if(src == C.head)
+ to_chat(user, "You feel at peace. Why would you want anything else?")
+ return
+ return ..()
+
+/obj/item/clothing/suit/armor/heavy/adamantine
+ name = "adamantine armor"
+ desc = "A full suit of adamantine plate armor. Impressively resistant to damage, but weighs about as much as you do."
+ icon_state = "adamsuit"
+ item_state = "adamsuit"
+ flags_inv = NONE
+ obj_flags = IMMUTABLE_SLOW
+ slowdown = 4
+ var/hit_reflect_chance = 10 // Citadel Change: because 40% chance of bouncing lasers back into peoples faces isn't good.
+ armor = list("melee" = 70, "bullet" = 70, "laser" = 40, "energy" = 40, "bomb" = 80, "bio" = 80, "rad" = 80, "fire" = 70, "acid" = 90) //Citadel Change to avoid immortal Xenobiologists.
+
+/obj/item/clothing/suit/armor/heavy/adamantine/IsReflect(def_zone)
+ if(def_zone in list(BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) && prob(hit_reflect_chance))
+ return TRUE
+ else
+ return FALSE
diff --git a/code/modules/research/xenobiology/crossbreeding/_misc.dm b/code/modules/research/xenobiology/crossbreeding/_misc.dm
new file mode 100644
index 0000000000..0784946a37
--- /dev/null
+++ b/code/modules/research/xenobiology/crossbreeding/_misc.dm
@@ -0,0 +1,135 @@
+//Barrier cube - Chilling Grey
+/obj/item/barriercube
+ name = "barrier cube"
+ desc = "A compressed cube of slime. When squeezed, it grows to massive size!"
+ icon = 'icons/obj/slimecrossing.dmi'
+ icon_state = "barriercube"
+ w_class = WEIGHT_CLASS_TINY
+
+/obj/item/barriercube/attack_self(mob/user)
+ if(locate(/obj/structure/barricade/slime) in get_turf(loc))
+ to_chat(user, "You can't fit more than one barrier in the same space!")
+ return
+ to_chat(user, "You squeeze [src].")
+ var/obj/B = new /obj/structure/barricade/slime(get_turf(loc))
+ B.visible_message("[src] suddenly grows into a large, gelatinous barrier!")
+ qdel(src)
+
+//Slime barricade - Chilling Grey
+/obj/structure/barricade/slime
+ name = "gelatinous barrier"
+ desc = "A huge chunk of grey slime. Bullets might get stuck in it."
+ icon = 'icons/obj/slimecrossing.dmi'
+ icon_state = "slimebarrier"
+ proj_pass_rate = 40
+ max_integrity = 60
+
+//Melting Gel Wall - Chilling Metal
+/obj/effect/forcefield/slimewall
+ name = "solidified gel"
+ desc = "A mass of solidified slime gel - completely impenetrable, but it's melting away!"
+ icon = 'icons/obj/slimecrossing.dmi'
+ icon_state = "slimebarrier_thick"
+ CanAtmosPass = ATMOS_PASS_NO
+ opacity = TRUE
+ timeleft = 100
+
+//Rainbow barrier - Chilling Rainbow
+/obj/effect/forcefield/slimewall/rainbow
+ name = "rainbow barrier"
+ desc = "Despite others' urgings, you probably shouldn't taste this."
+ icon_state = "rainbowbarrier"
+
+//Ration pack - Chilling Silver
+/obj/item/reagent_containers/food/snacks/rationpack
+ name = "ration pack"
+ desc = "A square bar that sadly looks like chocolate, packaged in a nondescript grey wrapper. Has saved soldiers' lives before - usually by stopping bullets."
+ icon_state = "rationpack"
+ bitesize = 3
+ junkiness = 15
+ filling_color = "#964B00"
+ tastes = list("cardboard" = 3, "sadness" = 3)
+ foodtype = null //Don't ask what went into them. You're better off not knowing.
+ list_reagents = list("stabilizednutriment" = 10, "nutriment" = 2) //Won't make you fat. Will make you question your sanity.
+
+/obj/item/reagent_containers/food/snacks/rationpack/checkLiked(fraction, mob/M) //Nobody likes rationpacks. Nobody.
+ if(last_check_time + 50 < world.time)
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ if(H.mind && !H.has_trait(TRAIT_AGEUSIA))
+ to_chat(H,"That didn't taste very good...") //No disgust, though. It's just not good tasting.
+ GET_COMPONENT_FROM(mood, /datum/component/mood, H)
+ if(mood)
+ mood.add_event(null,"gross_food", /datum/mood_event/gross_food)
+ last_check_time = world.time
+ return
+ ..()
+
+//Ice stasis block - Chilling Dark Blue
+/obj/structure/ice_stasis
+ name = "ice block"
+ desc = "A massive block of ice. You can see something vaguely humanoid inside."
+ icon = 'icons/obj/slimecrossing.dmi'
+ icon_state = "frozen"
+ density = TRUE
+ max_integrity = 100
+ armor = list("melee" = 30, "bullet" = 50, "laser" = -50, "energy" = -50, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = -80, "acid" = 30)
+
+/obj/structure/ice_stasis/Initialize()
+ . = ..()
+ playsound(src, 'sound/magic/ethereal_exit.ogg', 50, 1)
+
+/obj/structure/ice_stasis/Destroy()
+ for(var/atom/movable/M in contents)
+ M.forceMove(loc)
+ playsound(src, 'sound/effects/glassbr3.ogg', 50, 1)
+ return ..()
+
+//Gold capture device - Chilling Gold
+/obj/item/capturedevice
+ name = "gold capture device"
+ desc = "Bluespace technology packed into a roughly egg-shaped device, used to store nonhuman creatures. Can't catch them all, though - it only fits one."
+ w_class = WEIGHT_CLASS_SMALL
+ icon = 'icons/obj/slimecrossing.dmi'
+ icon_state = "capturedevice"
+
+/obj/item/capturedevice/attack(mob/living/M, mob/user)
+ if(length(contents))
+ to_chat(user, "The device already has something inside.")
+ return
+ if(!isanimal(M))
+ to_chat(user, "The capture device only works on simple creatures.")
+ return
+ if(M.mind)
+ to_chat(user, "You offer the device to [M].")
+ if(alert(M, "Would you like to enter [user]'s capture device?", "Gold Capture Device", "Yes", "No") == "Yes")
+ if(user.canUseTopic(src, BE_CLOSE) && user.canUseTopic(M, BE_CLOSE))
+ to_chat(user, "You store [M] in the capture device.")
+ to_chat(M, "The world warps around you, and you're suddenly in an endless void, with a window to the outside floating in front of you.")
+ store(M, user)
+ else
+ to_chat(user, "You were too far away from [M].")
+ to_chat(M, "You were too far away from [user].")
+ else
+ to_chat(user, "[M] refused to enter the device.")
+ return
+ else
+ if(istype(M, /mob/living/simple_animal/hostile) && !("neutral" in M.faction))
+ to_chat(user, "This creature is too aggressive to capture.")
+ return
+ to_chat(user, "You store [M] in the capture device.")
+ store(M)
+
+/obj/item/capturedevice/attack_self(mob/user)
+ if(contents.len)
+ to_chat(user, "You open the capture device!")
+ release()
+ else
+ to_chat(user, "The device is empty...")
+
+/obj/item/capturedevice/proc/store(var/mob/living/M)
+ M.forceMove(src)
+
+/obj/item/capturedevice/proc/release()
+ for(var/atom/movable/M in contents)
+ M.forceMove(get_turf(loc))
diff --git a/code/modules/research/xenobiology/crossbreeding/_mobs.dm b/code/modules/research/xenobiology/crossbreeding/_mobs.dm
new file mode 100644
index 0000000000..57d0a31149
--- /dev/null
+++ b/code/modules/research/xenobiology/crossbreeding/_mobs.dm
@@ -0,0 +1,13 @@
+//Slime corgi - Chilling Pink
+/mob/living/simple_animal/pet/dog/corgi/puppy/slime
+ name = "\improper slime corgi puppy"
+ real_name = "slime corgi puppy"
+ desc = "An unbearably cute pink slime corgi puppy."
+ icon_state = "slime_puppy"
+ icon_living = "slime_puppy"
+ icon_dead = "slime_puppy_dead"
+ nofur = TRUE
+ gold_core_spawnable = NO_SPAWN
+ speak_emote = list("blorbles", "bubbles", "borks")
+ emote_hear = list("bubbles!", "splorts.", "splops!")
+ emote_see = list("gets goop everywhere.", "flops.", "jiggles!")
\ No newline at end of file
diff --git a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
index f56aa11bae..aba54cfdf3 100644
--- a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
+++ b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
@@ -57,6 +57,184 @@
owner.visible_message("[owner]'s gel coating liquefies and dissolves away.",
"Your gel second-skin dissolves!")
+/datum/status_effect/slimerecall
+ id = "slime_recall"
+ duration = -1 //Will be removed by the extract.
+ alert_type = null
+ var/interrupted = FALSE
+ var/mob/target
+ var/icon/bluespace
+ var/datum/weakref/redirect_component
+
+/datum/status_effect/slimerecall/on_apply()
+ redirect_component = WEAKREF(owner.AddComponent(/datum/component/redirect, list(COMSIG_LIVING_RESIST = CALLBACK(src, .proc/resistField))))
+ to_chat(owner, "You feel a sudden tug from an unknown force, and feel a pull to bluespace!")
+ to_chat(owner, "Resist if you wish avoid the force!")
+ bluespace = icon('icons/effects/effects.dmi',"chronofield")
+ owner.add_overlay(bluespace)
+ return ..()
+
+/datum/status_effect/slimerecall/proc/resistField()
+ interrupted = TRUE
+ owner.remove_status_effect(src)
+/datum/status_effect/slimerecall/on_remove()
+ qdel(redirect_component.resolve())
+ redirect_component = null
+ owner.cut_overlay(bluespace)
+ if(interrupted || !ismob(target))
+ to_chat(owner, "The bluespace tug fades away, and you feel that the force has passed you by.")
+ return
+ owner.visible_message("[owner] disappears in a flurry of sparks!",
+ "The unknown force snatches briefly you from reality, and deposits you next to [target]!")
+ do_sparks(3, TRUE, owner)
+ owner.forceMove(target.loc)
+
+/obj/screen/alert/status_effect/freon/stasis
+ desc = "You're frozen inside of a protective ice cube! While inside, you can't do anything, but are immune to harm! Resist to get out."
+
+/datum/status_effect/frozenstasis
+ id = "slime_frozen"
+ status_type = STATUS_EFFECT_UNIQUE
+ duration = -1 //Will remove self when block breaks.
+ alert_type = /obj/screen/alert/status_effect/freon/stasis
+ var/obj/structure/ice_stasis/cube
+ var/datum/weakref/redirect_component
+
+/datum/status_effect/frozenstasis/on_apply()
+ redirect_component = WEAKREF(owner.AddComponent(/datum/component/redirect, list(COMSIG_LIVING_RESIST = CALLBACK(src, .proc/breakCube))))
+ cube = new /obj/structure/ice_stasis(get_turf(owner))
+ owner.forceMove(cube)
+ owner.status_flags |= GODMODE
+ return ..()
+
+/datum/status_effect/frozenstasis/tick()
+ if(!cube || owner.loc != cube)
+ owner.remove_status_effect(src)
+
+/datum/status_effect/frozenstasis/proc/breakCube()
+ owner.remove_status_effect(src)
+
+/datum/status_effect/frozenstasis/on_remove()
+ if(cube)
+ qdel(cube)
+ owner.status_flags &= ~GODMODE
+ qdel(redirect_component.resolve())
+ redirect_component = null
+
+/datum/status_effect/slime_clone
+ id = "slime_cloned"
+ status_type = STATUS_EFFECT_UNIQUE
+ duration = -1
+ alert_type = null
+ var/mob/living/clone
+ var/datum/mind/originalmind //For when the clone gibs.
+
+/datum/status_effect/slime_clone/on_apply()
+ var/typepath = owner.type
+ clone = new typepath(owner.loc)
+ var/mob/living/carbon/O = owner
+ var/mob/living/carbon/C = clone
+ if(istype(C) && istype(O))
+ C.real_name = O.real_name
+ O.dna.transfer_identity(C)
+ C.updateappearance(mutcolor_update=1)
+ if(owner.mind)
+ originalmind = owner.mind
+ owner.mind.transfer_to(clone)
+ clone.apply_status_effect(/datum/status_effect/slime_clone_decay)
+ return ..()
+
+/datum/status_effect/slime_clone/tick()
+ if(!istype(clone) || clone.stat != CONSCIOUS)
+ owner.remove_status_effect(src)
+
+/datum/status_effect/slime_clone/on_remove()
+ if(clone && clone.mind && owner)
+ clone.mind.transfer_to(owner)
+ else
+ if(owner && originalmind)
+ originalmind.transfer_to(owner)
+ if(originalmind.key)
+ owner.ckey = originalmind.key
+ if(clone)
+ clone.unequip_everything()
+ qdel(clone)
+
+/obj/screen/alert/status_effect/clone_decay
+ name = "Clone Decay"
+ desc = "You are simply a construct, and cannot maintain this form forever. You will be returned to your original body if you should fall."
+ icon_state = "slime_clonedecay"
+
+/datum/status_effect/slime_clone_decay
+ id = "slime_clonedecay"
+ status_type = STATUS_EFFECT_UNIQUE
+ duration = -1
+ alert_type = /obj/screen/alert/status_effect/clone_decay
+
+/datum/status_effect/slime_clone_decay/tick()
+ owner.adjustToxLoss(1, 0)
+ owner.adjustOxyLoss(1, 0)
+ owner.adjustBruteLoss(1, 0)
+ owner.adjustFireLoss(1, 0)
+ owner.color = "#007BA7"
+
+/obj/screen/alert/status_effect/bloodchill
+ name = "Bloodchilled"
+ desc = "You feel a shiver down your spine after getting hit with a glob of cold blood. You'll move slower and get frostbite for a while!"
+ icon_state = "bloodchill"
+
+/datum/status_effect/bloodchill
+ id = "bloodchill"
+ duration = 100
+ alert_type = /obj/screen/alert/status_effect/bloodchill
+
+/datum/status_effect/bloodchill/on_apply()
+ owner.add_movespeed_modifier("bloodchilled", TRUE, 100, NONE, override = TRUE, multiplicative_slowdown = 3)
+ return ..()
+
+/datum/status_effect/bloodchill/tick()
+ if(prob(50))
+ owner.adjustFireLoss(2)
+
+/datum/status_effect/bloodchill/on_remove()
+ owner.remove_movespeed_modifier("bloodchilled")
+
+/obj/screen/alert/status_effect/bloodchill
+ name = "Bloodchilled"
+ desc = "You feel a shiver down your spine after getting hit with a glob of cold blood. You'll move slower and get frostbite for a while!"
+ icon_state = "bloodchill"
+
+/datum/status_effect/bonechill
+ id = "bonechill"
+ duration = 80
+ alert_type = /obj/screen/alert/status_effect/bonechill
+
+/datum/status_effect/bonechill/on_apply()
+ owner.add_movespeed_modifier("bonechilled", TRUE, 100, NONE, override = TRUE, multiplicative_slowdown = 3)
+ return ..()
+
+/datum/status_effect/bonechill/tick()
+ if(prob(50))
+ owner.adjustFireLoss(1)
+ owner.Jitter(3)
+ owner.adjust_bodytemperature(-10)
+
+/datum/status_effect/bonechill/on_remove()
+ owner.remove_movespeed_modifier("bonechilled")
+
+/obj/screen/alert/status_effect/bonechill
+ name = "Bonechilled"
+ desc = "You feel a shiver down your spine after hearing the haunting noise of bone rattling. You'll move slower and get frostbite for a while!"
+ icon_state = "bloodchill"
+
+/datum/status_effect/rebreathing
+ id = "rebreathing"
+ duration = -1
+ alert_type = null
+
+datum/status_effect/rebreathing/tick()
+ owner.adjustOxyLoss(-6, 0) //Just a bit more than normal breathing.
+
///////////////////////////////////////////////////////
//////////////////CONSUMING EXTRACTS///////////////////
///////////////////////////////////////////////////////
diff --git a/code/modules/research/xenobiology/crossbreeding/_weapons.dm b/code/modules/research/xenobiology/crossbreeding/_weapons.dm
new file mode 100644
index 0000000000..1138f65105
--- /dev/null
+++ b/code/modules/research/xenobiology/crossbreeding/_weapons.dm
@@ -0,0 +1,45 @@
+//Bloodchiller - Chilling Green
+/obj/item/gun/magic/bloodchill
+ name = "blood chiller"
+ desc = "A horrifying weapon made of your own bone and blood vessels. It shoots slowing globules of your own blood. Ech."
+ icon = 'icons/obj/slimecrossing.dmi'
+ icon_state = "bloodgun"
+ item_state = "bloodgun"
+ lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi'
+ item_flags = ABSTRACT | DROPDEL | NODROP
+ w_class = WEIGHT_CLASS_HUGE
+ force = 5
+ max_charges = 1 //Recharging costs blood.
+ recharge_rate = 1
+ ammo_type = /obj/item/ammo_casing/magic/bloodchill
+ fire_sound = 'sound/effects/attackblob.ogg'
+
+/obj/item/gun/magic/bloodchill/process()
+ charge_tick++
+ if(charge_tick < recharge_rate || charges >= max_charges)
+ return 0
+ charge_tick = 0
+ var/mob/living/M = loc
+ if(istype(M) && M.blood_volume >= 20)
+ charges++
+ M.blood_volume -= 20
+ if(charges == 1)
+ recharge_newshot()
+ return 1
+
+/obj/item/ammo_casing/magic/bloodchill
+ projectile_type = /obj/item/projectile/magic/bloodchill
+
+/obj/item/projectile/magic/bloodchill
+ name = "blood ball"
+ icon_state = "pulse0_bl"
+ damage = 0
+ damage_type = OXY
+ nodamage = 1
+ hitsound = 'sound/effects/splat.ogg'
+
+/obj/item/projectile/magic/bloodchill/on_hit(mob/living/target)
+ . = ..()
+ if(isliving(target))
+ target.apply_status_effect(/datum/status_effect/bloodchill)
\ No newline at end of file
diff --git a/code/modules/research/xenobiology/crossbreeding/chilling.dm b/code/modules/research/xenobiology/crossbreeding/chilling.dm
new file mode 100644
index 0000000000..25dbaa461f
--- /dev/null
+++ b/code/modules/research/xenobiology/crossbreeding/chilling.dm
@@ -0,0 +1,312 @@
+/*
+Chilling extracts:
+ Have a unique, primarily defensive effect when
+ filled with 10u plasma and activated in-hand.
+*/
+/obj/item/slimecross/chilling
+ name = "chilling extract"
+ desc = "It's cold to the touch, as if frozen solid."
+ effect = "chilling"
+ container_type = INJECTABLE | DRAWABLE
+ icon_state = "chilling"
+
+/obj/item/slimecross/chilling/Initialize()
+ . = ..()
+ create_reagents(10)
+
+/obj/item/slimecross/chilling/attack_self(mob/user)
+ if(!reagents.has_reagent("plasma",10))
+ to_chat(user, "This extract needs to be full of plasma to activate!")
+ return
+ reagents.remove_reagent("plasma",10)
+ to_chat(user, "You squeeze the extract, and it absorbs the plasma!")
+ playsound(src, 'sound/effects/bubbles.ogg', 50, 1)
+ playsound(src, 'sound/effects/glassbr1.ogg', 50, 1)
+ do_effect(user)
+
+/obj/item/slimecross/chilling/proc/do_effect(mob/user) //If, for whatever reason, you don't want to delete the extract, don't do ..()
+ qdel(src)
+ return
+
+/obj/item/slimecross/chilling/grey
+ colour = "grey"
+
+/obj/item/slimecross/chilling/grey/do_effect(mob/user)
+ user.visible_message("[src] produces a few small, grey cubes")
+ for(var/i in 1 to 3)
+ new /obj/item/barriercube(get_turf(user))
+ ..()
+
+/obj/item/slimecross/chilling/orange
+ colour = "orange"
+
+/obj/item/slimecross/chilling/orange/do_effect(mob/user)
+ user.visible_message("[src] shatters, and lets out a jet of heat!")
+ for(var/turf/T in orange(get_turf(user),2))
+ if(get_dist(get_turf(user), T) > 1)
+ new /obj/effect/hotspot(T)
+ ..()
+
+/obj/item/slimecross/chilling/purple
+ colour = "purple"
+
+/obj/item/slimecross/chilling/purple/do_effect(mob/user)
+ var/area/A = get_area(get_turf(user))
+ if(A.outdoors)
+ to_chat(user, "[src] can't affect such a large area.")
+ return
+ user.visible_message("[src] shatters, and a healing aura fills the room briefly.")
+ for(var/mob/living/carbon/C in A)
+ C.reagents.add_reagent("regen_jelly",10)
+ ..()
+
+/obj/item/slimecross/chilling/blue
+ colour = "blue"
+
+/obj/item/slimecross/chilling/blue/do_effect(mob/user)
+ user.visible_message("[src] cracks, and spills out a liquid goo, which reforms into a mask!")
+ new /obj/item/clothing/mask/nobreath(get_turf(user))
+ ..()
+
+/obj/item/slimecross/chilling/metal
+ colour = "metal"
+
+/obj/item/slimecross/chilling/metal/do_effect(mob/user)
+ user.visible_message("[src] melts like quicksilver, and surrounds [user] in a wall!")
+ for(var/turf/T in orange(get_turf(user),1))
+ if(get_dist(get_turf(user), T) > 0)
+ new /obj/effect/forcefield/slimewall(T)
+ ..()
+
+/obj/item/slimecross/chilling/yellow
+ colour = "yellow"
+
+/obj/item/slimecross/chilling/yellow/do_effect(mob/user)
+ var/area/A = get_area(get_turf(user))
+ user.visible_message("[src] shatters, and a the air suddenly feels charged for a moment.")
+ for(var/obj/machinery/power/apc/C in A)
+ if(C.cell)
+ C.cell.charge = min(C.cell.charge + C.cell.maxcharge/2, C.cell.maxcharge)
+ ..()
+
+/obj/item/slimecross/chilling/darkpurple
+ colour = "dark purple"
+
+/obj/item/slimecross/chilling/darkpurple/do_effect(mob/user)
+ var/area/A = get_area(get_turf(user))
+ if(A.outdoors)
+ to_chat(user, "[src] can't affect such a large area.")
+ return
+ var/filtered = FALSE
+ for(var/turf/open/T in A)
+ var/datum/gas_mixture/G = T.air
+ if(istype(G))
+ G.assert_gas(/datum/gas/plasma)
+ G.gases[/datum/gas/plasma][MOLES] = 0
+ filtered = TRUE
+ G.garbage_collect()
+ T.air_update_turf()
+ if(filtered)
+ user.visible_message("Cracks spread throughout [src], and some air is sucked in!")
+ else
+ user.visible_message("[src] cracks, but nothing happens.")
+ ..()
+
+/obj/item/slimecross/chilling/darkblue
+ colour = "dark blue"
+
+/obj/item/slimecross/chilling/darkblue/do_effect(mob/user)
+ if(isliving(user))
+ user.visible_message("[src] freezes over [user]'s entire body!")
+ var/mob/living/M = user
+ M.apply_status_effect(/datum/status_effect/frozenstasis)
+ ..()
+
+/obj/item/slimecross/chilling/silver
+ colour = "silver"
+
+/obj/item/slimecross/chilling/silver/do_effect(mob/user)
+ user.visible_message("[src] crumbles into icy powder, leaving behind several emergency food supplies!")
+ var/amount = rand(5, 10)
+ for(var/i in 1 to amount)
+ new /obj/item/reagent_containers/food/snacks/rationpack(get_turf(user))
+ ..()
+
+/obj/item/slimecross/chilling/bluespace
+ colour = "bluespace"
+ var/list/allies = list()
+ var/active = FALSE
+
+/obj/item/slimecross/chilling/bluespace/afterattack(atom/target, mob/user, proximity)
+ if(!proximity || !isliving(target) || active)
+ return
+ if(target in allies)
+ allies -= target
+ to_chat(user, "You unlink [src] with [target].")
+ else
+ allies |= target
+ to_chat(user, "You link [src] with [target].")
+ return
+
+/obj/item/slimecross/chilling/bluespace/do_effect(mob/user)
+ if(allies.len <= 0)
+ to_chat(user, "[src] is not linked to anyone!")
+ return
+ to_chat(user, "You feel [src] pulse as it begins charging bluespace energies...")
+ active = TRUE
+ for(var/mob/living/M in allies)
+ var/datum/status_effect/slimerecall/S = M.apply_status_effect(/datum/status_effect/slimerecall)
+ S.target = user
+ if(do_after(user, 100, target=src))
+ to_chat(user, "[src] shatters as it tears a hole in reality, snatching the linked individuals from the void!")
+ for(var/mob/living/M in allies)
+ var/datum/status_effect/slimerecall/S = M.has_status_effect(/datum/status_effect/slimerecall)
+ M.remove_status_effect(S)
+ else
+ to_chat(user, "[src] falls dark, dissolving into nothing as the energies fade away.")
+ for(var/mob/living/M in allies)
+ var/datum/status_effect/slimerecall/S = M.has_status_effect(/datum/status_effect/slimerecall)
+ if(istype(S))
+ S.interrupted = TRUE
+ M.remove_status_effect(S)
+ ..()
+
+/obj/item/slimecross/chilling/sepia
+ colour = "sepia"
+ var/list/allies = list()
+
+/obj/item/slimecross/chilling/sepia/afterattack(atom/target, mob/user, proximity)
+ if(!proximity || !isliving(target))
+ return
+ if(target in allies)
+ allies -= target
+ to_chat(user, "You unlink [src] with [target].")
+ else
+ allies |= target
+ to_chat(user, "You link [src] with [target].")
+ return
+
+/obj/item/slimecross/chilling/sepia/do_effect(mob/user)
+ user.visible_message("[src] shatters, freezing time itself!")
+ new /obj/effect/timestop(get_turf(user), 2, 300, allies)
+ ..()
+
+/obj/item/slimecross/chilling/cerulean
+ colour = "cerulean"
+
+/obj/item/slimecross/chilling/cerulean/do_effect(mob/user)
+ if(isliving(user))
+ user.visible_message("[src] creaks and shifts into a clone of [user]!")
+ var/mob/living/M = user
+ M.apply_status_effect(/datum/status_effect/slime_clone)
+ ..()
+
+/obj/item/slimecross/chilling/pyrite
+ colour = "pyrite"
+
+/obj/item/slimecross/chilling/pyrite/do_effect(mob/user)
+ user.visible_message("[src] crystallizes into a pair of spectacles!")
+ new /obj/item/clothing/glasses/prism_glasses(get_turf(user))
+ ..()
+
+/obj/item/slimecross/chilling/red
+ colour = "red"
+
+/obj/item/slimecross/chilling/red/do_effect(mob/user)
+ var/slimesfound = FALSE
+ for(var/mob/living/simple_animal/slime/S in view(get_turf(user), 7))
+ slimesfound = TRUE
+ S.docile = TRUE
+ if(slimesfound)
+ user.visible_message("[src] lets out a peaceful ring as it shatters, and nearby slimes seem calm.")
+ else
+ user.visible_message("[src] lets out a peaceful ring as it shatters, but nothing happens...")
+ ..()
+
+/obj/item/slimecross/chilling/green
+ colour = "green"
+
+/obj/item/slimecross/chilling/green/do_effect(mob/user)
+ var/which_hand = "l_hand"
+ if(!(user.active_hand_index % 2))
+ which_hand = "r_hand"
+ var/mob/living/L = user
+ if(!istype(user))
+ return
+ var/obj/item/held = L.get_active_held_item() //This should be itself, but just in case...
+ L.dropItemToGround(held)
+ var/obj/item/gun/magic/bloodchill/gun = new(user)
+ if(!L.put_in_hands(gun))
+ qdel(gun)
+ user.visible_message("[src] flash-freezes [user]'s arm, cracking the flesh horribly!")
+ else
+ user.visible_message("[src] chills and snaps off the front of the bone on [user]'s arm, leaving behind a strange, gun-like structure!")
+ user.emote("scream")
+ L.apply_damage(30,BURN,which_hand)
+ ..()
+
+/obj/item/slimecross/chilling/pink
+ colour = "pink"
+
+/obj/item/slimecross/chilling/pink/do_effect(mob/user)
+ user.visible_message("[src] cracks like an egg, and an adorable puppy comes tumbling out!")
+ new /mob/living/simple_animal/pet/dog/corgi/puppy/slime(get_turf(user))
+ ..()
+
+/obj/item/slimecross/chilling/gold
+ colour = "gold"
+
+/obj/item/slimecross/chilling/gold/do_effect(mob/user)
+ user.visible_message("[src] lets off golden light as it melts and reforms into an egg-like device!")
+ new /obj/item/capturedevice(get_turf(user))
+ ..()
+
+/obj/item/slimecross/chilling/oil
+ colour = "oil"
+
+/obj/item/slimecross/chilling/oil/do_effect(mob/user)
+ user.visible_message("[src] begins to shake with muted intensity!")
+ addtimer(CALLBACK(src, .proc/boom), 50)
+
+/obj/item/slimecross/chilling/oil/proc/boom()
+ explosion(get_turf(src), -1, -1, 3, 10) //Large radius, but mostly light damage.
+ qdel(src)
+
+/obj/item/slimecross/chilling/black
+ colour = "black"
+
+/obj/item/slimecross/chilling/black/do_effect(mob/user)
+ if(ishuman(user))
+ user.visible_message("[src] crystallizes along [user]'s skin, turning into metallic scales!")
+ var/mob/living/carbon/human/H = user
+ H.set_species(/datum/species/golem/random)
+ ..()
+
+/obj/item/slimecross/chilling/lightpink
+ colour = "light pink"
+
+/obj/item/slimecross/chilling/lightpink/do_effect(mob/user)
+ user.visible_message("[src] blooms into a beautiful flower!")
+ new /obj/item/clothing/head/peaceflower(get_turf(user))
+ ..()
+
+/obj/item/slimecross/chilling/adamantine
+ colour = "adamantine"
+
+/obj/item/slimecross/chilling/adamantine/do_effect(mob/user)
+ user.visible_message("[src] creaks and breaks as it shifts into a heavy set of armor!")
+ new /obj/item/clothing/suit/armor/heavy/adamantine(get_turf(user))
+ ..()
+
+/obj/item/slimecross/chilling/rainbow
+ colour = "rainbow"
+
+/obj/item/slimecross/chilling/rainbow/do_effect(mob/user)
+ var/area/area = get_area(user)
+ if(area.outdoors)
+ to_chat(user, "[src] can't affect such a large area.")
+ return
+ user.visible_message("[src] reflects an array of dazzling colors and light, energy rushing to nearby doors!")
+ for(var/obj/machinery/door/airlock/door in area)
+ new /obj/effect/forcefield/slimewall/rainbow(door.loc)
+ return ..()
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index e48e18c34c..ca12accbed 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -840,7 +840,7 @@
return
if(isitem(C))
var/obj/item/I = C
- if(I.slowdown <= 0)
+ if(I.slowdown <= 0 || I.obj_flags & IMMUTABLE_SLOW)
to_chat(user, "The [C] can't be made any faster!")
return ..()
I.slowdown = 0
@@ -849,10 +849,10 @@
var/obj/vehicle/V = C
var/datum/component/riding/R = V.GetComponent(/datum/component/riding)
if(R)
- if(R.vehicle_move_delay <= 0 )
+ if(R.vehicle_move_delay <= 1 )
to_chat(user, "The [C] can't be made any faster!")
return ..()
- R.vehicle_move_delay = 0
+ R.vehicle_move_delay = 1
to_chat(user, "You slather the red gunk over the [C], making it faster.")
C.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
diff --git a/code/modules/security_levels/security_levels.dm b/code/modules/security_levels/security_levels.dm
index 7e45854628..70b06e6438 100644
--- a/code/modules/security_levels/security_levels.dm
+++ b/code/modules/security_levels/security_levels.dm
@@ -1,6 +1,7 @@
GLOBAL_VAR_INIT(security_level, SEC_LEVEL_GREEN)
//SEC_LEVEL_GREEN = code green
//SEC_LEVEL_BLUE = code blue
+//SEC_LEVEL_AMBER = code amber
//SEC_LEVEL_RED = code red
//SEC_LEVEL_DELTA = code delta
@@ -12,6 +13,8 @@ GLOBAL_VAR_INIT(security_level, SEC_LEVEL_GREEN)
level = SEC_LEVEL_GREEN
if("blue")
level = SEC_LEVEL_BLUE
+ if("amber")
+ level = SEC_LEVEL_AMBER
if("red")
level = SEC_LEVEL_RED
if("delta")
@@ -25,8 +28,10 @@ GLOBAL_VAR_INIT(security_level, SEC_LEVEL_GREEN)
if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL)
if(GLOB.security_level >= SEC_LEVEL_RED)
SSshuttle.emergency.modTimer(4)
+ else if(GLOB.security_level == SEC_LEVEL_AMBER)
+ SSshuttle.emergency.modTimer(2.5)
else
- SSshuttle.emergency.modTimer(2)
+ SSshuttle.emergency.modTimer(1.66)
GLOB.security_level = SEC_LEVEL_GREEN
for(var/obj/machinery/firealarm/FA in GLOB.machines)
if(is_station_level(FA.z))
@@ -35,24 +40,46 @@ GLOBAL_VAR_INIT(security_level, SEC_LEVEL_GREEN)
if(GLOB.security_level < SEC_LEVEL_BLUE)
minor_announce(CONFIG_GET(string/alert_blue_upto), "Attention! Security level elevated to blue:",1)
if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL)
- SSshuttle.emergency.modTimer(0.5)
+ SSshuttle.emergency.modTimer(0.6)
else
minor_announce(CONFIG_GET(string/alert_blue_downto), "Attention! Security level lowered to blue:")
if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL)
- SSshuttle.emergency.modTimer(2)
+ if(GLOB.security_level >= SEC_LEVEL_RED)
+ SSshuttle.emergency.modTimer(2.4)
+ else
+ SSshuttle.emergency.modTimer(1.5)
GLOB.security_level = SEC_LEVEL_BLUE
sound_to_playing_players('sound/misc/voybluealert.ogg') // Citadel change - Makes alerts play a sound
for(var/obj/machinery/firealarm/FA in GLOB.machines)
if(is_station_level(FA.z))
FA.update_icon()
+ if(SEC_LEVEL_AMBER)
+ if(GLOB.security_level < SEC_LEVEL_AMBER)
+ minor_announce(CONFIG_GET(string/alert_amber_upto), "Attention! Security level elevated to amber:",1)
+ if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL)
+ if(GLOB.security_level == SEC_LEVEL_GREEN)
+ SSshuttle.emergency.modTimer(0.4)
+ else
+ SSshuttle.emergency.modTimer(0.66)
+ else
+ minor_announce(CONFIG_GET(string/alert_amber_downto), "Attention! Security level lowered to amber:")
+ if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL)
+ SSshuttle.emergency.modTimer(1.6)
+ GLOB.security_level = SEC_LEVEL_AMBER
+ sound_to_playing_players('sound/effects/alert.ogg') // Citadel change - Makes alerts play a sound
+ for(var/obj/machinery/firealarm/FA in GLOB.machines)
+ if(is_station_level(FA.z))
+ FA.update_icon()
if(SEC_LEVEL_RED)
if(GLOB.security_level < SEC_LEVEL_RED)
minor_announce(CONFIG_GET(string/alert_red_upto), "Attention! Code red!",1)
if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL)
if(GLOB.security_level == SEC_LEVEL_GREEN)
SSshuttle.emergency.modTimer(0.25)
+ else if(GLOB.security_level == SEC_LEVEL_BLUE)
+ SSshuttle.emergency.modTimer(0.416)
else
- SSshuttle.emergency.modTimer(0.5)
+ SSshuttle.emergency.modTimer(0.625)
else
minor_announce(CONFIG_GET(string/alert_red_downto), "Attention! Code red!")
GLOB.security_level = SEC_LEVEL_RED
@@ -66,10 +93,12 @@ GLOBAL_VAR_INIT(security_level, SEC_LEVEL_GREEN)
if(SEC_LEVEL_DELTA)
minor_announce(CONFIG_GET(string/alert_delta), "Attention! Delta security level reached!",1)
if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL)
- if(GLOB.security_level == SEC_LEVEL_GREEN)
+ if(GLOB.security_level < SEC_LEVEL_BLUE)
SSshuttle.emergency.modTimer(0.25)
else if(GLOB.security_level == SEC_LEVEL_BLUE)
- SSshuttle.emergency.modTimer(0.5)
+ SSshuttle.emergency.modTimer(0.416)
+ else
+ SSshuttle.emergency.modTimer(0.625)
GLOB.security_level = SEC_LEVEL_DELTA
sound_to_playing_players('sound/misc/deltakalaxon.ogg') // Citadel change - Makes alerts play a sound
for(var/obj/machinery/firealarm/FA in GLOB.machines)
@@ -93,6 +122,8 @@ GLOBAL_VAR_INIT(security_level, SEC_LEVEL_GREEN)
return "green"
if(SEC_LEVEL_BLUE)
return "blue"
+ if(SEC_LEVEL_AMBER)
+ return "amber"
if(SEC_LEVEL_RED)
return "red"
if(SEC_LEVEL_DELTA)
@@ -104,6 +135,8 @@ GLOBAL_VAR_INIT(security_level, SEC_LEVEL_GREEN)
return "green"
if(SEC_LEVEL_BLUE)
return "blue"
+ if(SEC_LEVEL_AMBER)
+ return "amber"
if(SEC_LEVEL_RED)
return "red"
if(SEC_LEVEL_DELTA)
@@ -115,6 +148,8 @@ GLOBAL_VAR_INIT(security_level, SEC_LEVEL_GREEN)
return SEC_LEVEL_GREEN
if("blue")
return SEC_LEVEL_BLUE
+ if("amber")
+ return SEC_LEVEL_AMBER
if("red")
return SEC_LEVEL_RED
if("delta")
diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm
index cbc6810143..9af4194049 100644
--- a/code/modules/shuttle/emergency.dm
+++ b/code/modules/shuttle/emergency.dm
@@ -206,7 +206,9 @@
if(SEC_LEVEL_GREEN)
set_coefficient = 2
if(SEC_LEVEL_BLUE)
- set_coefficient = 1
+ set_coefficient = 1.2
+ if(SEC_LEVEL_AMBER)
+ set_coefficient = 0.8
else
set_coefficient = 0.5
var/call_time = SSshuttle.emergencyCallTime * set_coefficient * engine_coeff
diff --git a/code/modules/surgery/bodyparts/bodyparts.dm b/code/modules/surgery/bodyparts/bodyparts.dm
index 1841ac52b5..4ecac39ecc 100644
--- a/code/modules/surgery/bodyparts/bodyparts.dm
+++ b/code/modules/surgery/bodyparts/bodyparts.dm
@@ -45,6 +45,10 @@
var/species_color = ""
var/mutation_color = ""
var/no_update = 0
+ var/body_markings //for bodypart markings
+ var/list/markings_color = list()
+ var/auxmarking
+ var/list/auxmarking_color = list()
var/animal_origin = null //for nonhuman bodypart (e.g. monkey)
var/dismemberable = 1 //whether it can be dismembered with a weapon.
@@ -285,6 +289,7 @@
should_draw_gender = FALSE
should_draw_greyscale = FALSE
no_update = TRUE
+ body_markings = "husk" // reeee
if(no_update)
return
@@ -295,8 +300,19 @@
var/datum/species/S = H.dna.species
species_id = S.limbs_id
+ should_draw_citadel = S.should_draw_citadel // Citadel Addition
species_flags_list = H.dna.species.species_traits
+ //body marking memes
+ var/list/colorlist = list()
+ colorlist.Cut()
+ colorlist += ReadRGB(H.dna.features["mcolor"])
+ colorlist += ReadRGB(H.dna.features["mcolor2"])
+ colorlist += ReadRGB(H.dna.features["mcolor3"])
+ colorlist += list(0,0,0)
+ for(var/index=1, index<=colorlist.len, index++)
+ colorlist[index] = colorlist[index]/255
+
if(S.use_skintones)
skin_tone = H.skin_tone
should_draw_greyscale = TRUE
@@ -315,6 +331,17 @@
else
species_color = ""
+ if("mam_body_markings" in S.default_features)
+ if(H.dna.features.["mam_body_markings"] != "None")
+ body_markings = lowertext(H.dna.features.["mam_body_markings"])
+ if(MATRIXED)
+ markings_color = list(colorlist)
+ else
+ markings_color = (H.dna.features.["mcolor"])
+ else
+ body_markings = "None"
+ markings_color = ""
+
if(!dropping_limb && H.dna.check_mutation(HULK))
mutation_color = "00aa00"
else
@@ -345,6 +372,7 @@
//Gives you a proper icon appearance for the dismembered limb
/obj/item/bodypart/proc/get_limb_icon(dropped)
+ cut_overlays()
icon_state = "" //to erase the default sprite, we're building the visual aspects of the bodypart through overlays alone.
. = list()
@@ -357,9 +385,17 @@
. += image('icons/mob/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_[brutestate]0", -DAMAGE_LAYER, image_dir)
if(burnstate)
. += image('icons/mob/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_0[burnstate]", -DAMAGE_LAYER, image_dir)
+ if(body_markings)
+ if(use_digitigrade == NOT_DIGITIGRADE)
+ . += image('modular_citadel/icons/mob/mam_markings.dmi', "[body_markings]_[body_zone]", -MARKING_LAYER, image_dir)
+ else
+ . += image('modular_citadel/icons/mob/mam_markings.dmi', "[body_markings]_digitigrade_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir)
var/image/limb = image(layer = -BODYPARTS_LAYER, dir = image_dir)
var/image/aux
+ var/image/marking
+ var/image/auxmarking
+
. += limb
if(animal_origin)
@@ -396,17 +432,37 @@
limb.icon_state = "[species_id]_[body_zone]"
// Citadel Start
- if(should_draw_citadel)
+ if(should_draw_citadel && !use_digitigrade)
limb.icon = 'modular_citadel/icons/mob/mutant_bodyparts.dmi'
if(should_draw_gender)
limb.icon_state = "[species_id]_[body_zone]_[icon_gender]"
else
limb.icon_state = "[species_id]_[body_zone]"
+
+ // Body markings
+ if(body_markings)
+ if(species_id == "husk")
+ marking = image('modular_citadel/icons/mob/mam_markings.dmi', "husk_[body_zone]", -MARKING_LAYER, image_dir)
+ else if(species_id == "husk" && use_digitigrade)
+ marking = image('modular_citadel/icons/mob/mam_markings.dmi', "husk_digitigrade_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir)
+
+ else if(!use_digitigrade)
+ marking = image('modular_citadel/icons/mob/mam_markings.dmi', "[body_markings]_[body_zone]", -MARKING_LAYER, image_dir)
+ else
+ marking = image('modular_citadel/icons/mob/mam_markings.dmi', "[body_markings]_digitigrade_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir)
+ . += marking
+
// Citadel End
if(aux_zone)
aux = image(limb.icon, "[species_id]_[aux_zone]", -aux_layer, image_dir)
. += aux
+ if(body_markings)
+ if(species_id == "husk")
+ auxmarking = image('modular_citadel/icons/mob/mam_markings.dmi', "husk_[aux_zone]", -aux_layer, image_dir)
+ else
+ auxmarking = image('modular_citadel/icons/mob/mam_markings.dmi', "[body_markings]_[aux_zone]", -aux_layer, image_dir)
+ . += auxmarking
else
limb.icon = icon
@@ -415,17 +471,45 @@
else
limb.icon_state = "[body_zone]"
if(aux_zone)
- aux = image(limb.icon, "[aux_zone]", -aux_layer, image_dir)
+ aux = image(limb.icon, "[species_id]_[aux_zone]", -aux_layer, image_dir)
. += aux
+ if(body_markings)
+ if(species_id == "husk")
+ auxmarking = image('modular_citadel/icons/mob/mam_markings.dmi', "husk_[aux_zone]", -aux_layer, image_dir)
+ else
+ auxmarking = image('modular_citadel/icons/mob/mam_markings.dmi', "[body_markings]_[aux_zone]", -aux_layer, image_dir)
+ . += auxmarking
+
+ if(body_markings)
+ if(species_id == "husk")
+ marking = image('modular_citadel/icons/mob/mam_markings.dmi', "husk_[body_zone]", -MARKING_LAYER, image_dir)
+ else if(species_id == "husk" && use_digitigrade)
+ marking = image('modular_citadel/icons/mob/mam_markings.dmi', "husk_digitigrade_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir)
+
+ else if(!use_digitigrade)
+ marking = image('modular_citadel/icons/mob/mam_markings.dmi', "[body_markings]_[body_zone]", -MARKING_LAYER, image_dir)
+ else
+ marking = image('modular_citadel/icons/mob/mam_markings.dmi', "[body_markings]_digitigrade_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir)
+ . += marking
return
if(should_draw_greyscale)
+ marking.color = null
var/draw_color = mutation_color || species_color || (skin_tone && skintone2hex(skin_tone))
if(draw_color)
limb.color = "#[draw_color]"
if(aux_zone)
aux.color = "#[draw_color]"
+ if(body_markings)
+ auxmarking.color = list(markings_color)
+
+ if(body_markings)
+ if(species_id == "husk")
+ marking.color = "#141414"
+ else
+ marking.color = list(markings_color)
+
/obj/item/bodypart/deconstruct(disassembled = TRUE)
drop_organs()
diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm
index 73d0ab305e..1a46a9dcb1 100644
--- a/code/modules/surgery/bodyparts/dismemberment.dm
+++ b/code/modules/surgery/bodyparts/dismemberment.dm
@@ -26,9 +26,7 @@
burn()
return 1
add_mob_blood(C)
- var/turf/location = C.loc
- if(istype(location))
- C.add_splatter_floor(location)
+ C.bleed(40)
var/direction = pick(GLOB.cardinals)
var/t_range = rand(2,max(throw_range/2, 2))
var/turf/target_turf = get_turf(src)
@@ -54,7 +52,7 @@
. = list()
var/organ_spilled = 0
var/turf/T = get_turf(C)
- C.add_splatter_floor(T)
+ C.bleed(50)
playsound(get_turf(C), 'sound/misc/splort.ogg', 80, 1)
for(var/X in C.internal_organs)
var/obj/item/organ/O = X
diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm
index 9d9e26c6fa..9cc56a6ca8 100644
--- a/code/modules/surgery/bodyparts/helpers.dm
+++ b/code/modules/surgery/bodyparts/helpers.dm
@@ -288,6 +288,7 @@
O.drop_limb(1)
qdel(O)
N.attach_limb(src)
+
if(body_plan_changed && ishuman(src))
var/mob/living/carbon/human/H = src
if(H.w_uniform)
@@ -311,4 +312,4 @@
S.adjusted = NORMAL_STYLE
else
S.adjusted = ALT_STYLE
- H.update_inv_wear_suit()
\ No newline at end of file
+ H.update_inv_wear_suit()
diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm
index 9f71f58ff8..6ec1ea12d9 100644
--- a/code/modules/surgery/organs/lungs.dm
+++ b/code/modules/surgery/organs/lungs.dm
@@ -15,7 +15,7 @@
var/safe_co2_min = 0
var/safe_co2_max = 10 // Yes it's an arbitrary value who cares?
var/safe_toxins_min = 0
- var/safe_toxins_max = 0.05
+ var/safe_toxins_max = MOLES_GAS_VISIBLE
var/SA_para_min = 1 //Sleeping agent
var/SA_sleep_min = 5 //Sleeping agent
var/BZ_trip_balls_min = 1 //BZ gas
@@ -324,7 +324,7 @@
// Clear out moods when no miasma at all
else
SEND_SIGNAL(owner, COMSIG_CLEAR_MOOD_EVENT, "smell")
-
+
handle_breath_temperature(breath, H)
breath.garbage_collect()
return TRUE
diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm
index bbbe8c584d..55ead3b5b4 100644
--- a/code/modules/surgery/organs/vocal_cords.dm
+++ b/code/modules/surgery/organs/vocal_cords.dm
@@ -251,8 +251,10 @@
var/static/regex/clap_words = regex("clap|applaud")
var/static/regex/honk_words = regex("ho+nk") //hooooooonk
var/static/regex/multispin_words = regex("like a record baby|right round")
- var/static/regex/orgasm_words = regex("cum|orgasm|climax|squirt") //CITADEL CHANGE
+ var/static/regex/orgasm_words = regex("cum|orgasm|climax|squirt|heyo") //CITADEL CHANGE
var/static/regex/dab_words = regex("dab|mood") //CITADEL CHANGE
+ var/static/regex/snap_words = regex("snap") //CITADEL CHANGE
+ var/static/regex/bwoink_words = regex("what the fuck are you doing|bwoink|hey you got a moment?") //CITADEL CHANGE
var/i = 0
//STUN
@@ -582,6 +584,18 @@
for(var/V in listeners)
var/mob/living/M = V
M.say("*dab")
+
+ //SNAP
+ else if((findtext(message, snap_words)))
+ cooldown = COOLDOWN_MEME
+ for(var/V in listeners)
+ var/mob/living/M = V
+ M.say("*snap")
+
+ //BWOINK
+ else if((findtext(message, bwoink_words)))
+ cooldown = COOLDOWN_MEME
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/playsound, get_turf(user), 'sound/effects/adminhelp.ogg', 300, 1), 25)
//END CITADEL CHANGES
else
diff --git a/code/modules/surgery/tools.dm b/code/modules/surgery/tools.dm
index aaf859ee52..517dfb412a 100644
--- a/code/modules/surgery/tools.dm
+++ b/code/modules/surgery/tools.dm
@@ -7,6 +7,15 @@
flags_1 = CONDUCT_1
w_class = WEIGHT_CLASS_TINY
+/obj/item/retractor/adv
+ name = "Advanced Retractor"
+ desc = "A high-class, premium retractor, featuring precision crafted, silver-plated hook-ends and an electrum handle."
+ icon = 'icons/obj/surgery.dmi'
+ icon_state = "retractor"
+ materials = list(MAT_METAL=6000, MAT_GLASS=3000)
+ flags_1 = CONDUCT_1
+ w_class = WEIGHT_CLASS_TINY
+ toolspeed = 0.65
/obj/item/retractor/augment
name = "retractor"
@@ -18,7 +27,6 @@
w_class = WEIGHT_CLASS_TINY
toolspeed = 0.5
-
/obj/item/hemostat
name = "hemostat"
desc = "You think you have seen this before."
@@ -29,6 +37,16 @@
w_class = WEIGHT_CLASS_TINY
attack_verb = list("attacked", "pinched")
+/obj/item/hemostat/adv
+ name = "Advanced Hemostat"
+ desc = "An exceptionally fine pair of arterial forceps. These appear to be plated in electrum and feel soft to the touch."
+ icon = 'icons/obj/surgery.dmi'
+ icon_state = "hemostat"
+ materials = list(MAT_METAL=5000, MAT_GLASS=2500)
+ flags_1 = CONDUCT_1
+ w_class = WEIGHT_CLASS_TINY
+ toolspeed = 0.65
+ attack_verb = list("attacked", "pinched")
/obj/item/hemostat/augment
name = "hemostat"
@@ -52,6 +70,16 @@
w_class = WEIGHT_CLASS_TINY
attack_verb = list("burnt")
+/obj/item/cautery/adv
+ name = "Electrocautery"
+ desc = "A high-tech unipolar Electrocauter. This tiny device contains an extremely powerful microbattery that uses arcs of electricity to painlessly sear wounds shut. It seems to recharge with the user's body-heat. Wow!"
+ icon = 'icons/obj/surgery.dmi'
+ icon_state = "cautery"
+ materials = list(MAT_METAL=2500, MAT_GLASS=750)
+ flags_1 = CONDUCT_1
+ w_class = WEIGHT_CLASS_TINY
+ toolspeed = 0.5
+ attack_verb = list("burnt")
/obj/item/cautery/augment
name = "cautery"
@@ -79,6 +107,21 @@
w_class = WEIGHT_CLASS_NORMAL
attack_verb = list("drilled")
+/obj/item/surgicaldrill/adv
+ name = "Surgical Autodrill"
+ desc = "With a diamond tip and built-in depth and safety sensors, this drill alerts the user before overpenetrating a patient's skull or tooth. There also appears to be a disable switch."
+ icon = 'icons/obj/surgery.dmi'
+ icon_state = "drill"
+ lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
+ hitsound = 'sound/weapons/circsawhit.ogg'
+ materials = list(MAT_METAL=10000, MAT_GLASS=6000)
+ flags_1 = CONDUCT_1
+ force = 13 //Damions are not ment for flesh cutting!
+ w_class = WEIGHT_CLASS_NORMAL
+ toolspeed = 0.65
+ attack_verb = list("drilled")
+ sharpness = IS_SHARP_ACCURATE // Were making them use a damion for this...
/obj/item/surgicaldrill/augment
name = "surgical drill"
@@ -116,6 +159,25 @@
. = ..()
AddComponent(/datum/component/butchering, 80 * toolspeed, 100, 0)
+/obj/item/scalpel/adv
+ name = "Precision Scalpel"
+ desc = "A perfectly balanced electrum scalpel with a silicon-coated edge to eliminate wear and tear."
+ icon = 'icons/obj/surgery.dmi'
+ icon_state = "scalpel"
+ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
+ flags_1 = CONDUCT_1
+ force = 8
+ w_class = WEIGHT_CLASS_TINY
+ throwforce = 7
+ throw_speed = 3
+ throw_range = 6
+ materials = list(MAT_METAL=4000, MAT_GLASS=1000)
+ attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
+ toolspeed = 0.65
+ hitsound = 'sound/weapons/bladeslice.ogg'
+ sharpness = IS_SHARP_ACCURATE
+
/obj/item/scalpel/augment
name = "scalpel"
desc = "Ultra-sharp blade attached directly to your bone for extra-accuracy."
@@ -161,6 +223,26 @@
. = ..()
AddComponent(/datum/component/butchering, 40 * toolspeed, 100, 5, 'sound/weapons/circsawhit.ogg') //saws are very accurate and fast at butchering
+/obj/item/circular_saw/adv
+ name = "Diamond-Grit Circular Saw"
+ desc = "For those Assistants with REALLY thick skulls."
+ icon = 'icons/obj/surgery.dmi'
+ icon_state = "saw"
+ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
+ hitsound = 'sound/weapons/circsawhit.ogg'
+ throwhitsound = 'sound/weapons/pierce.ogg'
+ flags_1 = CONDUCT_1
+ force = 13
+ w_class = WEIGHT_CLASS_NORMAL
+ throwforce = 6
+ throw_speed = 1
+ throw_range = 3
+ materials = list(MAT_METAL=10000, MAT_GLASS=6000)
+ attack_verb = list("attacked", "slashed", "sawed", "cut")
+ toolspeed = 0.65
+ sharpness = IS_SHARP
+
/obj/item/circular_saw/augment
name = "circular saw"
desc = "A small but very fast spinning saw. Edges dulled to prevent accidental cutting inside of the surgeon."
diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm
index 32eaf0cde9..af2c625670 100644
--- a/code/modules/uplink/uplink_items.dm
+++ b/code/modules/uplink/uplink_items.dm
@@ -506,6 +506,12 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/item/ammo_box/magazine/m12g/meteor
include_modes = list(/datum/game_mode/nuclear)
+/datum/uplink_item/ammo/shotgun/scatter
+ name = "12g Scatter Laser shot Slugs"
+ desc = "An alternative 8-round Scatter Laser Shot magazine for use in the Bulldog shotgun."
+ item = /obj/item/ammo_box/magazine/m12g/scatter
+ cost = 5 // most armor has less laser protection then bullet
+
/datum/uplink_item/ammo/shotgun/bag
name = "12g Ammo Duffel Bag"
desc = "A duffel bag filled with enough 12g ammo to supply an entire team, at a discounted price."
@@ -982,6 +988,13 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/item/storage/backpack/duffelbag/syndie/surgery
cost = 3
+/datum/uplink_item/device_tools/surgerybag_adv
+ name = "Syndicate Surgery Duffel Bag"
+ desc = "The Syndicate surgery duffel bag is a toolkit containing all newest surgery tools, surgical drapes, \
+ a Syndicate brand MMI, a straitjacket, a muzzle, and a full Syndicate Combat Medic Kit."
+ item = /obj/item/storage/backpack/duffelbag/syndie/surgery_adv
+ cost = 15 //Mite be to cheap
+
/datum/uplink_item/device_tools/military_belt
name = "Chest Rig"
desc = "A robust seven-slot set of webbing that is capable of holding all manner of tactical equipment."
@@ -1355,13 +1368,20 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/item/reverse_bear_trap
restricted_roles = list("Clown")
+/datum/uplink_item/role_restricted/clumsyDNA
+ name = "Clumsy Clown DNA"
+ desc = "A DNA injector that has been loaded with the clown gene that makes people clumsy.. \
+ Making someone clumsy will allow them to use clown firing pins as well as Reverse Revolvers. For a laugh try using this on the HOS to see how many times they shoot themselves in the foot!"
+ cost = 1
+ item = /obj/item/dnainjector/clumsymut
+ restricted_roles = list("Clown")
+
/datum/uplink_item/role_restricted/mimery
name = "Guide to Advanced Mimery Series"
desc = "The classical two part series on how to further hone your mime skills. Upon studying the series, the user should be able to make 3x1 invisible walls, and shoot bullets out of their fingers. Obviously only works for Mimes."
cost = 12
item = /obj/item/storage/box/syndie_kit/mimery
restricted_roles = list("Mime")
- surplus = 0
/datum/uplink_item/role_restricted/ez_clean_bundle
name = "EZ Clean Grenade Bundle"
@@ -1383,7 +1403,6 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
name = "Kitchen Gun (TM) .45 Magazine"
desc = "An extra eight bullets for an extra eight uses of Kitchen Gun (TM)!"
cost = 1
- surplus = 0
restricted_roles = list("Cook", "Janitor")
item = /obj/item/ammo_box/magazine/m45/kitchengun
@@ -1392,7 +1411,6 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
desc = "A potato rigged with explosives. On activation, a special mechanism is activated that prevents it from being dropped. The only way to get rid of it if you are holding it is to attack someone else with it, causing it to latch to that person instead."
item = /obj/item/hot_potato/syndicate
cost = 4
- surplus = 0
restricted_roles = list("Cook", "Botanist", "Clown", "Mime")
/datum/uplink_item/role_restricted/his_grace
@@ -1412,7 +1430,6 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
cost = 10
item = /obj/item/pneumatic_cannon/pie/selfcharge
restricted_roles = list("Clown")
- surplus = 0 //No fun unless you're the clown!
/datum/uplink_item/role_restricted/ancient_jumpsuit
name = "Ancient Jumpsuit"
@@ -1420,7 +1437,6 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/item/clothing/under/color/grey/glorf
cost = 20
restricted_roles = list("Assistant")
- surplus = 0
/datum/uplink_item/role_restricted/brainwash_disk
name = "Brainwashing Surgery Program"
@@ -1474,7 +1490,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
blast wave \"projectile\". Aspiring scientists may find this highly useful, as forcing the pressure shockwave into a narrow angle seems to be able to bypass whatever quirk of physics \
disallows explosive ranges above a certain distance, allowing for the device to use the theoretical yield of a transfer valve bomb, instead of the factual yield."
item = /obj/item/gun/blastcannon
- cost = 14 //High cost because of the potential for extreme damage in the hands of a skilled scientist.
+ cost = 14 //High cost because of the potential for extreme damage in the hands of a skilled gas masked scientist.
restricted_roles = list("Research Director", "Scientist")
/datum/uplink_item/device_tools/clown_bomb
@@ -1487,6 +1503,15 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/item/sbeacondrop/clownbomb
cost = 15
restricted_roles = list("Clown")
+
+/datum/uplink_item/device_tools/honkpins //Idealy so they can place it into their own guns without needing cargo
+ name = "Hilarious firing pin"
+ desc = "A single firing pin made for Clown agents, this firing pin makes any gun honk when fired if not a true clown! \
+ This firing pin also helps you fire the gun correctly. May the HonkMother HONK you agent."
+ item = /obj/item/firing_pin/clown
+ cost = 1
+ restricted_roles = list("Clown")
+
/*
/datum/uplink_item/role_restricted/clowncar
name = "Clown Car"
diff --git a/code/modules/vending/assist.dm b/code/modules/vending/assist.dm
index de30109824..89c330789e 100644
--- a/code/modules/vending/assist.dm
+++ b/code/modules/vending/assist.dm
@@ -1,12 +1,19 @@
/obj/machinery/vending/assist
- products = list(/obj/item/assembly/prox_sensor = 5,
- /obj/item/assembly/igniter = 3,
- /obj/item/assembly/signaler = 4,
- /obj/item/wirecutters = 1,
- /obj/item/cartridge/signal = 4)
- contraband = list(/obj/item/assembly/timer = 2,
- /obj/item/assembly/voice = 2,
- /obj/item/assembly/health = 2)
+ products = list(/obj/item/assembly/prox_sensor = 7,
+ /obj/item/assembly/igniter = 6,
+ /obj/item/assembly/signaler = 6,
+ /obj/item/wirecutters = 3,
+ /obj/item/stock_parts/cell/crap = 6,
+ /obj/item/cartridge/signal = 6)
+ contraband = list(/obj/item/assembly/timer = 4,
+ /obj/item/assembly/voice = 4,
+ /obj/item/assembly/health = 4,
+ /obj/item/pressure_plate = 2,
+ /obj/item/multitool = 2,
+ /obj/item/stock_parts/cell/upgraded = 2)
+ premium = list(/obj/item/stock_parts/cell/upgraded/plus = 2,
+ /obj/item/flashlight/lantern = 2,
+ /obj/item/beacon = 2)
product_ads = "Only the finest!;Have some tools.;The most robust equipment.;The finest gear in space!"
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
resistance_flags = FIRE_PROOF
diff --git a/code/modules/vending/coffee.dm b/code/modules/vending/coffee.dm
index 6ac9dd648d..c30c087d7b 100644
--- a/code/modules/vending/coffee.dm
+++ b/code/modules/vending/coffee.dm
@@ -8,6 +8,11 @@
/obj/item/reagent_containers/food/drinks/mug/tea = 25,
/obj/item/reagent_containers/food/drinks/mug/coco = 25)
contraband = list(/obj/item/reagent_containers/food/drinks/ice = 12)
+ premium = list(/obj/item/reagent_containers/food/snacks/chocolatebar = 3,
+ /obj/item/reagent_containers/food/condiment/milk = 2,
+ /obj/item/reagent_containers/food/drinks/bottle/cream = 2,
+ /obj/item/reagent_containers/food/condiment/sugar = 1)
+
refill_canister = /obj/item/vending_refill/coffee
/obj/item/vending_refill/coffee
diff --git a/code/modules/vending/engivend.dm b/code/modules/vending/engivend.dm
index 0e64e0a367..9358d1652f 100644
--- a/code/modules/vending/engivend.dm
+++ b/code/modules/vending/engivend.dm
@@ -4,21 +4,28 @@
icon_state = "engivend"
icon_deny = "engivend-deny"
req_access = list(ACCESS_ENGINE_EQUIP)
- products = list(/obj/item/clothing/glasses/meson/engine = 2,
- /obj/item/clothing/glasses/welding = 3,
- /obj/item/multitool = 4,
+ products = list(/obj/item/clothing/glasses/meson/engine = 5,
+ /obj/item/clothing/glasses/welding = 5,
+ /obj/item/multitool = 5,
/obj/item/construction/rcd/loaded = 3,
/obj/item/grenade/chem_grenade/smart_metal_foam = 10,
- /obj/item/geiger_counter = 5,
+ /obj/item/geiger_counter = 6,
/obj/item/stock_parts/cell/high = 10,
- /obj/item/electronics/airlock = 10,
+ /obj/item/electronics/airlock = 10,
/obj/item/electronics/apc = 10,
/obj/item/electronics/airalarm = 10,
/obj/item/electronics/firealarm = 10,
- /obj/item/electronics/firelock = 10
+ /obj/item/electronics/firelock = 10,
+ /obj/item/rcd_ammo = 3
)
- contraband = list(/obj/item/stock_parts/cell/potato = 3)
+ contraband = list(/obj/item/stock_parts/cell/potato = 3,
+ /obj/item/rcd_ammo = 2,
+ /obj/item/circuitboard/computer/slot_machine = 1,
+ /obj/item/tank/internals/emergency_oxygen/double = 3
+ )
premium = list(/obj/item/storage/belt/utility = 3,
- /obj/item/storage/box/smart_metal_foam = 1)
+ /obj/item/storage/box/smart_metal_foam = 3,
+ /obj/item/rcd_ammo/large = 5
+ )
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
resistance_flags = FIRE_PROOF
diff --git a/code/modules/vending/medical_wall.dm b/code/modules/vending/medical_wall.dm
index 84c4891589..018eb09d86 100644
--- a/code/modules/vending/medical_wall.dm
+++ b/code/modules/vending/medical_wall.dm
@@ -13,6 +13,7 @@
/obj/item/reagent_containers/medspray/sterilizine = 1)
contraband = list(/obj/item/reagent_containers/pill/tox = 2,
/obj/item/reagent_containers/pill/morphine = 2)
+ premium = list(/obj/item/reagent_containers/medspray/synthflesh = 2)
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
resistance_flags = FIRE_PROOF
refill_canister = /obj/item/vending_refill/wallmed
@@ -26,3 +27,4 @@
/obj/item/reagent_containers/pill/patch/styptic = 1,
/obj/item/reagent_containers/pill/patch/silver_sulf = 1,
/obj/item/reagent_containers/medspray/sterilizine = 1)
+ premium = list(/obj/item/reagent_containers/medspray/synthflesh = 2)
diff --git a/code/modules/vending/snack.dm b/code/modules/vending/snack.dm
index 69e510ad5a..19138bad32 100644
--- a/code/modules/vending/snack.dm
+++ b/code/modules/vending/snack.dm
@@ -12,6 +12,9 @@
/obj/item/reagent_containers/food/snacks/spacetwinkie = 6,
/obj/item/reagent_containers/food/snacks/cheesiehonkers = 6)
contraband = list(/obj/item/reagent_containers/food/snacks/syndicake = 6)
+ premium = list(/obj/item/storage/box/donkpockets = 1,
+ /obj/item/reagent_containers/food/snacks/poppypretzel = 3)
+
refill_canister = /obj/item/vending_refill/snack
var/chef_compartment_access = "28" //ACCESS_KITCHEN
diff --git a/code/modules/vending/youtool.dm b/code/modules/vending/youtool.dm
index 495d60a461..ebaad4d715 100644
--- a/code/modules/vending/youtool.dm
+++ b/code/modules/vending/youtool.dm
@@ -3,19 +3,20 @@
desc = "Tools for tools."
icon_state = "tool"
icon_deny = "tool-deny"
- products = list(/obj/item/stack/cable_coil/random = 10,
- /obj/item/crowbar = 5,
- /obj/item/weldingtool = 3,
- /obj/item/wirecutters = 5,
- /obj/item/wrench = 5,
- /obj/item/analyzer = 5,
- /obj/item/t_scanner = 5,
- /obj/item/screwdriver = 5,
- /obj/item/flashlight/glowstick = 3,
- /obj/item/flashlight/glowstick/red = 3,
- /obj/item/flashlight = 5)
- contraband = list(/obj/item/weldingtool/hugetank = 2,
- /obj/item/clothing/gloves/color/fyellow = 2)
- premium = list(/obj/item/clothing/gloves/color/yellow = 1)
+ products = list(/obj/item/stack/cable_coil/random = 15,
+ /obj/item/crowbar = 10,
+ /obj/item/weldingtool = 6,
+ /obj/item/wirecutters = 10,
+ /obj/item/wrench = 10,
+ /obj/item/analyzer = 10,
+ /obj/item/t_scanner = 10,
+ /obj/item/screwdriver = 10,
+ /obj/item/flashlight/glowstick = 6,
+ /obj/item/flashlight/glowstick/red = 6,
+ /obj/item/flashlight = 7)
+ contraband = list(/obj/item/weldingtool/largetank = 4,
+ /obj/item/clothing/gloves/color/fyellow = 4)
+ premium = list(/obj/item/clothing/gloves/color/yellow = 2,
+ /obj/item/weldingtool/hugetank = 2)
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 70)
resistance_flags = FIRE_PROOF
diff --git a/config/config.txt b/config/config.txt
index 33bff862d9..3bc9f873a9 100644
--- a/config/config.txt
+++ b/config/config.txt
@@ -16,6 +16,9 @@ $include antag_rep.txt
## Server name: This appears at the top of the screen in-game and in the BYOND hub. Uncomment and replace 'tgstation' with the name of your choice.
# SERVERNAME tgstation
+## Server tagline: This will appear right below the server's title.
+# SERVERTAGLINE A generic TG-based server
+
## Server SQL name: This is the name used to identify the server to the SQL DB, distinct from SERVERNAME as it must be at most 32 characters.
# SERVERSQLNAME tgstation
diff --git a/config/game_options.txt b/config/game_options.txt
index bfc5ed5edb..6ff9182f0a 100644
--- a/config/game_options.txt
+++ b/config/game_options.txt
@@ -57,10 +57,12 @@ MULTIPLICATIVE_MOVESPEED /mob/living/simple_animal 1
## ALERT LEVELS ###
ALERT_GREEN All threats to the station have passed. Security may not have weapons visible, privacy laws are once again fully enforced.
-ALERT_BLUE_UPTO The station has received reliable information about possible hostile activity on the station. Security staff may have weapons visible, random searches are permitted.
-ALERT_BLUE_DOWNTO The immediate threat has passed. Security may no longer have weapons drawn at all times, but may continue to have them visible. Random searches are still allowed.
-ALERT_RED_UPTO There is an immediate serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised. Additionally, access requirements on some doors have been lifted.
-ALERT_RED_DOWNTO The station's destruction has been averted. There is still however an immediate serious threat to the station. Security may have weapons unholstered at all times, random searches are allowed and advised.
+ALERT_BLUE_UPTO The station has received reliable information about potential threats to the station. Security staff may have weapons visible, random searches are permitted.
+ALERT_BLUE_DOWNTO Significant confirmed threats have been neutralized. Security may no longer have weapons drawn at all times, but may continue to have them visible. Random searches are still permitted.
+ALERT_AMBER_UPTO There are signficant confirmed threats to the station. Security staff may have weapons unholstered at all times. Random searches are allowed and advised.
+ALERT_AMBER_DOWNTO The immediate threat has passed. Security is no longer authorized to use lethal force, but may continue to have weapons drawn. Access requirements have been restored.
+ALERT_RED_UPTO There is an immediate serious threat to the station. Security is now authorized to use lethal force. Additionally, access requirements on some machines have been lifted.
+ALERT_RED_DOWNTO The station's destruction has been averted. There is still however an immediate serious threat to the station. Security is still authorized to use lethal force.
ALERT_DELTA Destruction of the station is imminent. All crew are instructed to obey all instructions given by heads of staff. Any violations of these orders can be punished by death. This is not a drill.
diff --git a/html/changelogs/AutoChangeLog-pr-7860.yml b/html/changelogs/AutoChangeLog-pr-7860.yml
new file mode 100644
index 0000000000..140f95aa40
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7860.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - bugfix: "The syndicate mask now works properly as intended."
diff --git a/html/changelogs/AutoChangeLog-pr-7865.yml b/html/changelogs/AutoChangeLog-pr-7865.yml
new file mode 100644
index 0000000000..a75282b293
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7865.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - balance: "Stamina is no longer affected by health at all."
diff --git a/html/changelogs/AutoChangeLog-pr-7866.yml b/html/changelogs/AutoChangeLog-pr-7866.yml
new file mode 100644
index 0000000000..17435075e0
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7866.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - rscadd: "You can now right-click yourself in help intent in combat mode to instantly get up from resting. This will cost stamina equal to your entire stamina buffer. Manage your stamina well, and you'll be able to shrug off a single stray golden bolt"
diff --git a/html/changelogs/AutoChangeLog-pr-7876.yml b/html/changelogs/AutoChangeLog-pr-7876.yml
new file mode 100644
index 0000000000..649c0cc916
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7876.yml
@@ -0,0 +1,4 @@
+author: "coiax"
+delete-after: True
+changes:
+ - admin: "When the nuclear disk stays stationary long enough to trigger an increase for the lone op event chance, admins will be notified every five increments."
diff --git a/html/changelogs/AutoChangeLog-pr-7878.yml b/html/changelogs/AutoChangeLog-pr-7878.yml
new file mode 100644
index 0000000000..6d10310d94
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7878.yml
@@ -0,0 +1,4 @@
+author: "Tupinambis"
+delete-after: True
+changes:
+ - tweak: "Removed all living eggs from the xeno ruin because people self antag. Honk."
diff --git a/html/changelogs/AutoChangeLog-pr-7908.yml b/html/changelogs/AutoChangeLog-pr-7908.yml
new file mode 100644
index 0000000000..f6c1fda2ec
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7908.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - rscadd: "The new player panel now displays your currently selected character's name"
diff --git a/html/changelogs/AutoChangeLog-pr-7911.yml b/html/changelogs/AutoChangeLog-pr-7911.yml
new file mode 100644
index 0000000000..0d0d468aa8
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7911.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - balance: "Flashes no longer knockdown. Instead, they deal eyeblur and have increased confusion"
diff --git a/html/changelogs/AutoChangeLog-pr-7912.yml b/html/changelogs/AutoChangeLog-pr-7912.yml
new file mode 100644
index 0000000000..834ad80091
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7912.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - server: "The server's tagline is now a config option. People can now stop confusing us with BR cit"
diff --git a/html/changelogs/AutoChangeLog-pr-7914.yml b/html/changelogs/AutoChangeLog-pr-7914.yml
new file mode 100644
index 0000000000..aac983d7ea
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7914.yml
@@ -0,0 +1,4 @@
+author: "Ghom"
+delete-after: True
+changes:
+ - code_imp: "minor clean up on hydroponics reagent containers."
diff --git a/html/changelogs/AutoChangeLog-pr-7916.yml b/html/changelogs/AutoChangeLog-pr-7916.yml
new file mode 100644
index 0000000000..888f327f72
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7916.yml
@@ -0,0 +1,4 @@
+author: "Skoglol"
+delete-after: True
+changes:
+ - rscadd: "You can now alt click storage (bags, boxes, etc) to open it."
diff --git a/html/changelogs/AutoChangeLog-pr-7918.yml b/html/changelogs/AutoChangeLog-pr-7918.yml
new file mode 100644
index 0000000000..b2340c2f67
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7918.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - rscadd: "Attack animations will now rotate your character slightly, similar to Goon."
diff --git a/html/changelogs/AutoChangeLog-pr-7919.yml b/html/changelogs/AutoChangeLog-pr-7919.yml
new file mode 100644
index 0000000000..a62cc838c3
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7919.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - rscadd: "Throwing items will now perform the attack animation and play a sound"
diff --git a/html/changelogs/AutoChangeLog-pr-7920.yml b/html/changelogs/AutoChangeLog-pr-7920.yml
new file mode 100644
index 0000000000..08b0ec1f13
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7920.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - rscadd: "flashlights will now make sounds when toggled on/off"
diff --git a/html/changelogs/AutoChangeLog-pr-7921.yml b/html/changelogs/AutoChangeLog-pr-7921.yml
new file mode 100644
index 0000000000..66a245257f
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7921.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - rscadd: "Things in disposals will now emit sounds every single time they hit corners. This increases immersion."
diff --git a/html/changelogs/AutoChangeLog-pr-7922.yml b/html/changelogs/AutoChangeLog-pr-7922.yml
new file mode 100644
index 0000000000..08f06d7053
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7922.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - bugfix: "Air alarms now actually emit the proper light color when their status is okay."
diff --git a/html/changelogs/AutoChangeLog-pr-7923.yml b/html/changelogs/AutoChangeLog-pr-7923.yml
new file mode 100644
index 0000000000..5cf6527dad
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7923.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - rscadd: "Backpacks and other storage items will now jiggle and squish when you interact with them, similar to the animations seen on Goon."
diff --git a/html/changelogs/AutoChangeLog-pr-7930.yml b/html/changelogs/AutoChangeLog-pr-7930.yml
new file mode 100644
index 0000000000..221a2af942
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7930.yml
@@ -0,0 +1,4 @@
+author: "nicc"
+delete-after: True
+changes:
+ - balance: "teg less gay maybe"
diff --git a/html/changelogs/AutoChangeLog-pr-7945.yml b/html/changelogs/AutoChangeLog-pr-7945.yml
new file mode 100644
index 0000000000..edc2f96dc8
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7945.yml
@@ -0,0 +1,5 @@
+author: "Ghom"
+delete-after: True
+changes:
+ - bugfix: "fixes the perpetual lack of moisture that has affected genitalia descriptions since, like, forever."
+ - rscadd: "implements the arousal state for mammary glands."
diff --git a/html/changelogs/AutoChangeLog-pr-7951.yml b/html/changelogs/AutoChangeLog-pr-7951.yml
new file mode 100644
index 0000000000..e05a5a1911
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7951.yml
@@ -0,0 +1,6 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - bugfix: "Fixes many possible situations of null icons for cit races' bodyparts."
+ - imagedel: "Removes duplicate slimepeople' sprites."
+ - code_imp: "Purges that draw_citadel_parts()."
diff --git a/html/changelogs/AutoChangeLog-pr-7954.yml b/html/changelogs/AutoChangeLog-pr-7954.yml
new file mode 100644
index 0000000000..8a31b912ad
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7954.yml
@@ -0,0 +1,6 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - balance: "Mops no longer have a delay on their cleaning, making them an actually viable alternative to all of the janitor's other cleaning tools"
+ - balance: "To balance this, mops now take stamina to clean tiles. Standard mops take 5 stamina to use, while advanced mops take 2 stamina."
+ - tweak: "Oh and also mops make fancy new sounds and play animations when used now"
diff --git a/html/changelogs/AutoChangeLog-pr-7964.yml b/html/changelogs/AutoChangeLog-pr-7964.yml
new file mode 100644
index 0000000000..33cfaa453d
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7964.yml
@@ -0,0 +1,6 @@
+author: "CydiaButt13"
+delete-after: True
+changes:
+ - rscadd: "Lamp Plushie to loadout"
+ - imageadd: "added plushie_lamp to plush icons"
+ - code_imp: "added Lamp Plush to loadout and icons and items"
diff --git a/html/changelogs/AutoChangeLog-pr-7973.yml b/html/changelogs/AutoChangeLog-pr-7973.yml
new file mode 100644
index 0000000000..df9b9e2411
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7973.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - balance: "Pump-action shotguns now take 2 stamina per pump instead of 5 stamina per pump. This also applies to bolt-action rifles, as bolt racking counts as pumping."
diff --git a/html/changelogs/AutoChangeLog-pr-7976.yml b/html/changelogs/AutoChangeLog-pr-7976.yml
new file mode 100644
index 0000000000..4f334dc4ca
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7976.yml
@@ -0,0 +1,7 @@
+author: "Tupinambis"
+delete-after: True
+changes:
+ - rscadd: "Adds a new security level between Blue and Red (Amber). The shuttle call time at this level is 8 minutes."
+ - tweak: "Blue security level now has a shuttle call time of 12 minutes."
+ - tweak: "The security level increase/decrease texts have been modified to accommodate the change."
+ - imageadd: "Adds a code Amber sprite for the fire alarms"
diff --git a/html/changelogs/AutoChangeLog-pr-7977.yml b/html/changelogs/AutoChangeLog-pr-7977.yml
new file mode 100644
index 0000000000..ca43ddbbf0
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7977.yml
@@ -0,0 +1,5 @@
+author: "Zargserg"
+delete-after: True
+changes:
+ - balance: "Lungs maximum toxin threshold is 0.5% of the atmosphere."
+ - bugfix: "Permanently contaminated atmosphere does not murder crew anymore."
diff --git a/html/changelogs/AutoChangeLog-pr-7978.yml b/html/changelogs/AutoChangeLog-pr-7978.yml
new file mode 100644
index 0000000000..b35ea975c3
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7978.yml
@@ -0,0 +1,4 @@
+author: "Poojawa"
+delete-after: True
+changes:
+ - rscadd: "Added the Yogs/Oracle ported latejoin menu"
diff --git a/html/changelogs/AutoChangeLog-pr-7979.yml b/html/changelogs/AutoChangeLog-pr-7979.yml
new file mode 100644
index 0000000000..ed06d73ac1
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7979.yml
@@ -0,0 +1,4 @@
+author: "Anonymous"
+delete-after: True
+changes:
+ - imageadd: "More crusader armor variants to pick from armament: Teutonic and Hospitaller."
diff --git a/html/changelogs/AutoChangeLog-pr-7980.yml b/html/changelogs/AutoChangeLog-pr-7980.yml
new file mode 100644
index 0000000000..a0b3b09fb5
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7980.yml
@@ -0,0 +1,4 @@
+author: "MediHound"
+delete-after: True
+changes:
+ - rscadd: "Made Cyborgs be affected by Ion Storm Law Changes like AIs"
diff --git a/html/changelogs/AutoChangeLog-pr-7981.yml b/html/changelogs/AutoChangeLog-pr-7981.yml
new file mode 100644
index 0000000000..e36dd711fa
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7981.yml
@@ -0,0 +1,5 @@
+author: "Tupinambis"
+delete-after: True
+changes:
+ - tweak: "Removed the plushes from the toy crate, giving them their own."
+ - tweak: "Plushes are now less likely to spawn out of arcades"
diff --git a/html/changelogs/AutoChangeLog-pr-7982.yml b/html/changelogs/AutoChangeLog-pr-7982.yml
new file mode 100644
index 0000000000..7255219c9e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7982.yml
@@ -0,0 +1,9 @@
+author: "Coolgat3 / Avunia"
+delete-after: True
+changes:
+ - rscadd: "Made kindle put the target into stamcrit, which makes it an actually working, useful stun."
+ - rscadd: "Added a stamina loss modifier to the vanguard spell which makes the user's stamina drain at a way slower rate. This doesn't make them immune to tasers, but it takes a few hits to actually get them to fall down."
+ - tweak: "Made it so that clock culties don't start with a chameleon suit. Instead they start with an engineer suit which is pretty much the same sprite and looks. If this is not perfect, then I am willing to make a slightly more brass-colored version of the engineer suit sprite and call it a ratvarian engineer jumpsuit."
+ - balance: "Increased the cost of vanguard, as it is now a spell that works somewhat like adrenals, minus the move speed, making your stamina drain really slow and making you unable to get knocked onto the ground by just a single taser shot."
+ - balance: "Lowered the charge time of kindle, reason being that you can usually have only one active spell on you, or two at max if you decide to run two slabs, but the fact that kindle silences people for such a small amount of time makes up for it, in my opinion."
+ - server: "Figured out that the consoles and their warp function actually work with the current code. The thing that makes them not work is when the gamemode is ran on debug mode, without the required players to actually support it. It also breaks the ark timer which is stuck on -1 seconds until activation. Whenever the gamemode starts properly, like any other gamemode, with player checks and all, everything seems to work just fine."
diff --git a/html/changelogs/AutoChangeLog-pr-7983.yml b/html/changelogs/AutoChangeLog-pr-7983.yml
new file mode 100644
index 0000000000..46e0a14f96
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7983.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - code_imp: "Fixes ISINRANGE_EX using the wrong relational operator."
diff --git a/html/changelogs/AutoChangeLog-pr-7987.yml b/html/changelogs/AutoChangeLog-pr-7987.yml
new file mode 100644
index 0000000000..e525b1668e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7987.yml
@@ -0,0 +1,10 @@
+author: "Poojawa"
+delete-after: True
+changes:
+ - rscadd: "All markings, tails, ears, and snouts for Citadel races are color matrixed!"
+ - imageadd: "all markings are on a per-limb basis, including Digitigrade legs!"
+ - imageadd: "a bunch of tails were blessed with tail wagging sprites, Fish, Sharks, Fennecs, Wahs, raccoons, and others."
+ - imageadd: "Tiger markings + tail added, skunk tails improved via sprites from Virgo"
+ - tweak: "tweaked some sprites to look better, but they absolutely could use a few extra passes for quality"
+ - rscadd: "HumanScissors in the Tools folder will permit anyone to contribute matrix'd markings to the sprite sheet, however Mam_markings is very, very full. Be careful."
+ - tweak: "Character preview was both optimized for taurs and bad-touched for better updating. I don't know if it'll be bad, but hey its better."
diff --git a/html/changelogs/AutoChangeLog-pr-7990.yml b/html/changelogs/AutoChangeLog-pr-7990.yml
new file mode 100644
index 0000000000..b05eca84d2
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7990.yml
@@ -0,0 +1,5 @@
+author: "Coolgat3"
+delete-after: True
+changes:
+ - tweak: "Changed player number checks to 20 from 24 for cult and clockcult, also made nukeops 28 required players instead of 30."
+ - tweak: "Changed enemy minimum age from 14 to 7"
diff --git a/html/changelogs/AutoChangeLog-pr-7993.yml b/html/changelogs/AutoChangeLog-pr-7993.yml
new file mode 100644
index 0000000000..f1e0db178f
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7993.yml
@@ -0,0 +1,8 @@
+author: "Improving and Balancing Cyborgs"
+delete-after: True
+changes:
+ - rscadd: "Added Crew Pinpointer to Security Borg"
+ - rscadd: "Added Crew Monitor to Medical Borg"
+ - rscadd: "Added Crew Pinpointer to MediHound Borg"
+ - tweak: "Made the Disabler_Cooler compatible with both Security Borg and K9 Borg"
+ - tweak: "Changed the Warning Text upon selecting Security or K9 module"
diff --git a/html/changelogs/AutoChangeLog-pr-7994.yml b/html/changelogs/AutoChangeLog-pr-7994.yml
new file mode 100644
index 0000000000..703dcf31e1
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7994.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - tweak: "Pickpocketing items will now place them in your hands if possible"
diff --git a/html/changelogs/AutoChangeLog-pr-7995.yml b/html/changelogs/AutoChangeLog-pr-7995.yml
new file mode 100644
index 0000000000..9d118ebbff
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7995.yml
@@ -0,0 +1,5 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - rscadd: "Combat mode is now displayed in examine text"
+ - rscadd: "Combat mode now makes a visible message when enabled if you haven't touched your combat mode button in the last ten seconds. It's done this way to avoid chat spam from those who know how to pull off stam regen squeezing."
diff --git a/html/changelogs/AutoChangeLog-pr-7996.yml b/html/changelogs/AutoChangeLog-pr-7996.yml
new file mode 100644
index 0000000000..518feae251
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7996.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - balance: "All knockdown sources will now force people to be dismounted from ridden vehicles."
diff --git a/html/changelogs/AutoChangeLog-pr-7997.yml b/html/changelogs/AutoChangeLog-pr-7997.yml
new file mode 100644
index 0000000000..7b3db7fb44
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7997.yml
@@ -0,0 +1,9 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - rscadd: "When an item is thrown, it will now be rotated and displaced."
+ - rscadd: "Shards of glass will now be rotated when spawned."
+ - rscadd: "Bullet casings will now be rotated when they're ejected from a gun."
+ - rscadd: "Bottles now have random rotations and pixel offsets when smashed via throwing."
+ - rscadd: "Picking up an item will now reset its rotation."
+ - rscadd: "Glasses thrown onto tables by bartenders will now have their rotation reset."
diff --git a/html/changelogs/AutoChangeLog-pr-7999.yml b/html/changelogs/AutoChangeLog-pr-7999.yml
new file mode 100644
index 0000000000..516f304f98
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7999.yml
@@ -0,0 +1,5 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - tweak: "The kindle status effect stun duration now properly proportional to the owner's remaining health."
+ - tweak: "Clockwork cult's kindle now affects silicons."
diff --git a/html/changelogs/AutoChangeLog-pr-8008.yml b/html/changelogs/AutoChangeLog-pr-8008.yml
new file mode 100644
index 0000000000..5845bd1b87
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8008.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - balance: "Slime speed potions can now only increase the speed of vehicles to be on par with sprinting speed. They can no longer make a scooter roll around ten times faster than a speeding blue hedgehog."
diff --git a/html/changelogs/AutoChangeLog-pr-8010.yml b/html/changelogs/AutoChangeLog-pr-8010.yml
new file mode 100644
index 0000000000..9694674b7c
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8010.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - rscdel: "Changelings will no longer recieve team objectives"
diff --git a/html/changelogs/AutoChangeLog-pr-8011.yml b/html/changelogs/AutoChangeLog-pr-8011.yml
new file mode 100644
index 0000000000..9d0db00db4
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8011.yml
@@ -0,0 +1,5 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - balance: "Changelings no longer start off with hivemind communication as an innate ability. Hivemind communication now requires 1 dna point, on par with syndicate encryption keys, which are 2 TC."
+ - code_imp: "Hivemind link now relies on hivemind communication just like the hivemind download/upload abilities."
diff --git a/html/changelogs/AutoChangeLog-pr-8012.yml b/html/changelogs/AutoChangeLog-pr-8012.yml
new file mode 100644
index 0000000000..212f252a7d
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8012.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - bugfix: "It's now only possible to zoom a gun if it's in one of your hands"
diff --git a/html/changelogs/AutoChangeLog-pr-8021.yml b/html/changelogs/AutoChangeLog-pr-8021.yml
new file mode 100644
index 0000000000..fca715cd3d
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8021.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - bugfix: "Mobs without clients no longer cause runtimes when their eyeblur updates"
diff --git a/html/changelogs/AutoChangeLog-pr-8023.yml b/html/changelogs/AutoChangeLog-pr-8023.yml
new file mode 100644
index 0000000000..1b30435bda
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8023.yml
@@ -0,0 +1,5 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - rscadd: "Blood tests have been added. If a changeling has a sufficient number of loud abilities, you will be able to test their blood by heating up a sample of it. However, if the changeling has a large amount of loud abilities, attempts to test their blood will have explosive results."
+ - rscadd: "Changelings now make a very obvious noise when readapting. This is to prevent the cheese strat of simply readapting when you get caught to avoid detection."
diff --git a/html/changelogs/AutoChangeLog-pr-8024.yml b/html/changelogs/AutoChangeLog-pr-8024.yml
new file mode 100644
index 0000000000..1aa5f1b09f
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8024.yml
@@ -0,0 +1,6 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - tweak: "The blood splatter effect that happens when you get attacked will now always make you lose blood depending on the damage you've taken. The effect now also scales with item damage, meaning tiny little papercuts will no longer be able to cause a massive blood splatter."
+ - rscadd: "The blood reagent will now cover items and spacemen in blood when applied to objects and mobs."
+ - tweak: "Helmets, masks, and neck items are all now valid targets to get splattered when you get covered in blood. Groovy."
diff --git a/html/changelogs/AutoChangeLog-pr-8025.yml b/html/changelogs/AutoChangeLog-pr-8025.yml
new file mode 100644
index 0000000000..ee60aab630
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8025.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - tweak: "The temperature notification will now take into consideration both the ambient temperature and your body temperature, increasing the responsiveness of the temperature notification and making it much more realistic."
diff --git a/html/changelogs/AutoChangeLog-pr-8030.yml b/html/changelogs/AutoChangeLog-pr-8030.yml
new file mode 100644
index 0000000000..c82325b394
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8030.yml
@@ -0,0 +1,5 @@
+author: "Multicam Config"
+delete-after: True
+changes:
+ - config: "removed whether or not the stuff for multicam was checking the useless var and instead now checks the CONFIG_GET flag."
+ - admin: "Admins now have a verb in the Server tab to turn AI multicam on and off."
diff --git a/html/changelogs/AutoChangeLog-pr-8031.yml b/html/changelogs/AutoChangeLog-pr-8031.yml
new file mode 100644
index 0000000000..16ce735811
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8031.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - tweak: "Shuttle transit borders are now 10 tiles wide instead of 8 tiles, hopefully repairing the immersions that get shattered by the ability to see normal space where the transit areas end."
diff --git a/html/changelogs/AutoChangeLog-pr-8032.yml b/html/changelogs/AutoChangeLog-pr-8032.yml
new file mode 100644
index 0000000000..87a65ac9d7
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8032.yml
@@ -0,0 +1,5 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - rscadd: "Instead of transit turfs simply teleporting things to space, transit is now handled in a somewhat realistic manner. Transit turfs now act like normal space turfs, though exiting the transit area or being present in the transit area after the shuttle moves out of transit will teleport you to space and throw you in the direction the shuttle was moving in."
+ - tweak: "Reservation areas are now able to designate a border turf."
diff --git a/html/changelogs/AutoChangeLog-pr-8033.yml b/html/changelogs/AutoChangeLog-pr-8033.yml
new file mode 100644
index 0000000000..e4a77766f1
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8033.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - bugfix: "The sprint hotkey will no longer cause you to get permanently stuck sprinting if the server lags. Just tap shift again if you get stuck"
diff --git a/html/changelogs/AutoChangeLog-pr-8034.yml b/html/changelogs/AutoChangeLog-pr-8034.yml
new file mode 100644
index 0000000000..c9fabf1874
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8034.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - rscadd: "You can now hear sounds in the real world while inside of a VR sleeper."
diff --git a/html/changelogs/AutoChangeLog-pr-8035.yml b/html/changelogs/AutoChangeLog-pr-8035.yml
new file mode 100644
index 0000000000..82d1a18a1b
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8035.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - rscadd: "You can now make nameless characters. Nameless characters will spawn in with their name set as their job title followed by a unique five digit number. The \"Name\" option in the character setup menu will be replaced with a \"Default designation\" option for nameless characters, and the default designation will be used in place of a job title for assistants and other jobs that don't require dress codes."
diff --git a/html/changelogs/AutoChangeLog-pr-8037.yml b/html/changelogs/AutoChangeLog-pr-8037.yml
new file mode 100644
index 0000000000..340b8e006e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8037.yml
@@ -0,0 +1,6 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - tweak: "Cyborg mounted disablers/tasers/lasers now slowly self-recharge off the cyborg user's power cell instead of draining from it directly."
+ - tweak: "Borg rechargers now properly recharge the borg module's energy guns."
+ - bugfix: "Prevents a couple more special/mounted guns from being preserved on cryo"
diff --git a/html/changelogs/AutoChangeLog-pr-8038.yml b/html/changelogs/AutoChangeLog-pr-8038.yml
new file mode 100644
index 0000000000..64fbb5c4b2
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8038.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - admin: "The out-of-game round end notification is now a little more verbose. It'll now display the round type, end result of the round, and the survival rate."
diff --git a/html/changelogs/AutoChangeLog-pr-8039.yml b/html/changelogs/AutoChangeLog-pr-8039.yml
new file mode 100644
index 0000000000..4445a86991
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8039.yml
@@ -0,0 +1,5 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - bugfix: "Xenos can no longer strip items off of people to be capable of using any item in the game."
+ - bugfix: "also, items from pockets get placed into your hands properly now"
diff --git a/html/changelogs/AutoChangeLog-pr-8041.yml b/html/changelogs/AutoChangeLog-pr-8041.yml
new file mode 100644
index 0000000000..477b513368
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8041.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - bugfix: "A mob's last words are now properly tracked and recorded on death. The first death of the round will now actually display the victim's last words on the round end screen."
diff --git a/html/changelogs/AutoChangeLog-pr-8042.yml b/html/changelogs/AutoChangeLog-pr-8042.yml
new file mode 100644
index 0000000000..4df2d178df
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8042.yml
@@ -0,0 +1,5 @@
+author: "izzyinbox"
+delete-after: True
+changes:
+ - rscadd: "Generic dog body marking sprite"
+ - imageadd: "colormatrix dog sprites"
diff --git a/html/changelogs/AutoChangeLog-pr-8043.yml b/html/changelogs/AutoChangeLog-pr-8043.yml
new file mode 100644
index 0000000000..b3beb4c4cb
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8043.yml
@@ -0,0 +1,5 @@
+author: "Coolgat3"
+delete-after: True
+changes:
+ - rscadd: "Added the code for the semen donut and made it craftable"
+ - imageadd: "Added the donut sprites"
diff --git a/html/changelogs/AutoChangeLog-pr-8044.yml b/html/changelogs/AutoChangeLog-pr-8044.yml
new file mode 100644
index 0000000000..e4fe14ac84
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8044.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - bugfix: "Divine shenanigans can no longer result in someone becoming immune to staminaloss"
diff --git a/html/changelogs/AutoChangeLog-pr-8047.yml b/html/changelogs/AutoChangeLog-pr-8047.yml
new file mode 100644
index 0000000000..6a11895b0f
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8047.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - bugfix: "Fixed body_markings in bodyparts being assigned as a list when in reality, it's a string and literally everything expects it to be a string and uses it as a string. This should mean that markings no longer have completely fucked up caches for character preview and other things."
diff --git a/html/changelogs/AutoChangeLog-pr-8051.yml b/html/changelogs/AutoChangeLog-pr-8051.yml
new file mode 100644
index 0000000000..51c2d438ab
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8051.yml
@@ -0,0 +1,5 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - tweak: "Since apparently the game is literally unplayable if items are not in the exact center of a turf, the maximum pixel variance of thrown objects has been reduced by four pixels to make things a smidge more clearer for those that dont know what a turf is."
+ - bugfix: "Bartender glasses should HOPEFULLY no longer be tilted when landing on a table. Why the fuck is after_throw called via a timer."
diff --git a/html/changelogs/AutoChangeLog-pr-8052.yml b/html/changelogs/AutoChangeLog-pr-8052.yml
new file mode 100644
index 0000000000..4ad9af8ef0
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8052.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - rscadd: "Changeling screeches now have their own unique sounds, and are much easier to recognize."
diff --git a/html/changelogs/AutoChangeLog-pr-8053.yml b/html/changelogs/AutoChangeLog-pr-8053.yml
new file mode 100644
index 0000000000..706166a9d1
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8053.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - rscadd: "Most synthetic emotes are now available to humans. *ping"
diff --git a/html/changelogs/AutoChangeLog-pr-8054.yml b/html/changelogs/AutoChangeLog-pr-8054.yml
new file mode 100644
index 0000000000..a674371a3a
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8054.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - rscadd: "You can now merp"
diff --git a/html/changelogs/AutoChangeLog-pr-8055.yml b/html/changelogs/AutoChangeLog-pr-8055.yml
new file mode 100644
index 0000000000..e06f03e1ef
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8055.yml
@@ -0,0 +1,4 @@
+author: "Poojawa"
+delete-after: True
+changes:
+ - rscadd: "Added Dark Medihound and Pup Dozer from Virgo"
diff --git a/html/changelogs/AutoChangeLog-pr-8056.yml b/html/changelogs/AutoChangeLog-pr-8056.yml
new file mode 100644
index 0000000000..0953743ae4
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8056.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - balance: "The TEG will now only produce a meaningful amount of power if the hot pipe contains gas that's actively combusting"
diff --git a/html/changelogs/AutoChangeLog-pr-8057.yml b/html/changelogs/AutoChangeLog-pr-8057.yml
new file mode 100644
index 0000000000..adb48e0ee0
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8057.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - admin: "Added the \"add PB bypass\" and \"revoke PB bypass\" verbs, which allow admins to let a specific ckey to bypass the panic bunker for the rest of the round"
diff --git a/html/changelogs/AutoChangeLog-pr-8058.yml b/html/changelogs/AutoChangeLog-pr-8058.yml
new file mode 100644
index 0000000000..a484cc8ce1
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8058.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - rscadd: "Jogging is no longer treated exactly the same as sprinting for water slips. When you're jogging, you will only slip on water if you have more than 20% staminaloss."
diff --git a/html/changelogs/AutoChangeLog-pr-8062.yml b/html/changelogs/AutoChangeLog-pr-8062.yml
new file mode 100644
index 0000000000..2f1bc9b312
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8062.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - tweak: "The atmospherics turf subsystem now has double the wait time, which should free up server processing power for other tasks."
diff --git a/html/changelogs/AutoChangeLog-pr-8064.yml b/html/changelogs/AutoChangeLog-pr-8064.yml
new file mode 100644
index 0000000000..512095f583
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8064.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - bugfix: "The IRC now actually displays the actual survival rate"
diff --git a/html/changelogs/AutoChangeLog-pr-8070.yml b/html/changelogs/AutoChangeLog-pr-8070.yml
new file mode 100644
index 0000000000..a2ebab9068
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8070.yml
@@ -0,0 +1,5 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - rscadd: "Bloodcult conversions are now consensual. Convertees are given a ten second timer to accept or wait out. This should drastically improve the quality of those that get converted into bloodcult."
+ - rscadd: "All sacrifices now count as a third of a cultist for the end-game narsie summon."
diff --git a/html/changelogs/AutoChangeLog-pr-8071.yml b/html/changelogs/AutoChangeLog-pr-8071.yml
new file mode 100644
index 0000000000..040aa8b2cc
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8071.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - bugfix: "Nameless captains will no longer proc a \"Captain Captain on deck!\" message. Instead, it'll be a much more boring but much more sensical \"Captain on deck!\" message."
diff --git a/html/changelogs/AutoChangeLog-pr-8080.yml b/html/changelogs/AutoChangeLog-pr-8080.yml
new file mode 100644
index 0000000000..9abd9e6f50
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8080.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - balance: "Halved borg energy guns self-recharge delay and increased their cell capacity by 3/4"
diff --git a/html/changelogs/AutoChangeLog-pr-8084.yml b/html/changelogs/AutoChangeLog-pr-8084.yml
new file mode 100644
index 0000000000..fbec9cfe1f
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8084.yml
@@ -0,0 +1,4 @@
+author: "Poojawa"
+delete-after: True
+changes:
+ - tweak: "Clone pods no longer announce the name of the clone"
diff --git a/html/changelogs/AutoChangeLog-pr-8090.yml b/html/changelogs/AutoChangeLog-pr-8090.yml
new file mode 100644
index 0000000000..b314fde12b
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8090.yml
@@ -0,0 +1,5 @@
+author: "deathride58 (Original PR by actioninja)"
+delete-after: True
+changes:
+ - rscadd: "Disarm pushing (combat mode right click in disarm intent) will now actually push mobs away. Knockdowns from disarm pushing are no longer rng based on the target's staminaloss. Knockdowns from disarm pushing now only happen when you push someone into another mob, a table, or a wall. Pushes will now also temporarily stop targets from using firearms, and will disarm the firearm if performed a second time. Pushes still deal staminaloss to standing targets, and won't deal a single ounce of staminaloss to resting targets."
+ - rscdel: "You can no longer displace mobs that are in harm intent by simply walking into them. Mobs that aren't in help intent have to be disarm pushed to actually be moved."
diff --git a/html/changelogs/AutoChangeLog-pr-8091.yml b/html/changelogs/AutoChangeLog-pr-8091.yml
new file mode 100644
index 0000000000..e98b7df89c
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8091.yml
@@ -0,0 +1,5 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - bugfix: "Transit turfs on the centcom z-level now function properly again at keeping mobs within the areas defined by their boundaries."
+ - bugfix: "The title screen is also positioned correctly again."
diff --git a/html/changelogs/AutoChangeLog-pr-8098.yml b/html/changelogs/AutoChangeLog-pr-8098.yml
new file mode 100644
index 0000000000..956b83d223
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8098.yml
@@ -0,0 +1,4 @@
+author: "Coolgat3"
+delete-after: True
+changes:
+ - bugfix: "Made the sec and warden berret offer as much protection like the helmet"
diff --git a/html/changelogs/AutoChangeLog-pr-8104.yml b/html/changelogs/AutoChangeLog-pr-8104.yml
new file mode 100644
index 0000000000..61bf66a0c2
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8104.yml
@@ -0,0 +1,5 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - bugfix: "Fixes chemical patches always checking the suit slot even if the targetted limb was the head."
+ - bugfix: "Skeleton, nightmare and golem races are once again available to get chemical patches applied onto."
diff --git a/html/changelogs/AutoChangeLog-pr-8114.yml b/html/changelogs/AutoChangeLog-pr-8114.yml
new file mode 100644
index 0000000000..96e6914e6b
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8114.yml
@@ -0,0 +1,4 @@
+author: "izzyinbox"
+delete-after: True
+changes:
+ - tweak: "lowered the player age for command jobs to 1/3 of their previous setting"
diff --git a/icons/mob/custom_w.dmi b/icons/mob/custom_w.dmi
index dc79247d48..1101f22d2e 100644
Binary files a/icons/mob/custom_w.dmi and b/icons/mob/custom_w.dmi differ
diff --git a/icons/mob/eyes.dmi b/icons/mob/eyes.dmi
index 4bbe27f09d..aad4718cbd 100644
Binary files a/icons/mob/eyes.dmi and b/icons/mob/eyes.dmi differ
diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi
index 1d99a415df..2f39dd5940 100644
Binary files a/icons/mob/head.dmi and b/icons/mob/head.dmi differ
diff --git a/icons/mob/human_face.dmi b/icons/mob/human_face.dmi
index 96df6caa8d..b479fa0764 100644
Binary files a/icons/mob/human_face.dmi and b/icons/mob/human_face.dmi differ
diff --git a/icons/mob/human_parts_greyscale.dmi b/icons/mob/human_parts_greyscale.dmi
index f162d36633..47ef8e816f 100644
Binary files a/icons/mob/human_parts_greyscale.dmi and b/icons/mob/human_parts_greyscale.dmi differ
diff --git a/icons/mob/inhands/misc/food_lefthand.dmi b/icons/mob/inhands/misc/food_lefthand.dmi
index 325b18d95e..19e0706d01 100644
Binary files a/icons/mob/inhands/misc/food_lefthand.dmi and b/icons/mob/inhands/misc/food_lefthand.dmi differ
diff --git a/icons/mob/inhands/misc/food_righthand.dmi b/icons/mob/inhands/misc/food_righthand.dmi
index ddc91fd6ed..da8eda329d 100644
Binary files a/icons/mob/inhands/misc/food_righthand.dmi and b/icons/mob/inhands/misc/food_righthand.dmi differ
diff --git a/icons/mob/inhands/weapons/guns_lefthand.dmi b/icons/mob/inhands/weapons/guns_lefthand.dmi
index dae3861233..f6ac6ca499 100644
Binary files a/icons/mob/inhands/weapons/guns_lefthand.dmi and b/icons/mob/inhands/weapons/guns_lefthand.dmi differ
diff --git a/icons/mob/inhands/weapons/guns_righthand.dmi b/icons/mob/inhands/weapons/guns_righthand.dmi
index f3d5c42570..504121feba 100644
Binary files a/icons/mob/inhands/weapons/guns_righthand.dmi and b/icons/mob/inhands/weapons/guns_righthand.dmi differ
diff --git a/icons/mob/mask.dmi b/icons/mob/mask.dmi
index 18b323c997..788bfc0447 100644
Binary files a/icons/mob/mask.dmi and b/icons/mob/mask.dmi differ
diff --git a/icons/mob/pets.dmi b/icons/mob/pets.dmi
index d0983a8fab..45b0ab1f04 100644
Binary files a/icons/mob/pets.dmi and b/icons/mob/pets.dmi differ
diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi
index f74ca2092d..b518157bb5 100644
Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ
diff --git a/icons/mob/uniform.dmi b/icons/mob/uniform.dmi
index d336887e21..2ed1783941 100644
Binary files a/icons/mob/uniform.dmi and b/icons/mob/uniform.dmi differ
diff --git a/icons/obj/2x2.dmi b/icons/obj/2x2.dmi
index a72a86f3d8..c5b1df680a 100644
Binary files a/icons/obj/2x2.dmi and b/icons/obj/2x2.dmi differ
diff --git a/icons/obj/chairs.dmi b/icons/obj/chairs.dmi
index 96e4a4228e..3754ff052c 100644
Binary files a/icons/obj/chairs.dmi and b/icons/obj/chairs.dmi differ
diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi
index 73f3065b4f..34d8374a42 100644
Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ
diff --git a/icons/obj/clothing/masks.dmi b/icons/obj/clothing/masks.dmi
index a474b5f285..a0153b1596 100644
Binary files a/icons/obj/clothing/masks.dmi and b/icons/obj/clothing/masks.dmi differ
diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi
index c3eb8b995c..8e0359e6b3 100644
Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ
diff --git a/icons/obj/clothing/uniforms.dmi b/icons/obj/clothing/uniforms.dmi
index a64ba6468b..84155bfe43 100644
Binary files a/icons/obj/clothing/uniforms.dmi and b/icons/obj/clothing/uniforms.dmi differ
diff --git a/icons/obj/custom.dmi b/icons/obj/custom.dmi
index 197b870284..a05fbb72ab 100644
Binary files a/icons/obj/custom.dmi and b/icons/obj/custom.dmi differ
diff --git a/icons/obj/doors/mineral_doors.dmi b/icons/obj/doors/mineral_doors.dmi
index 7682252a6d..03fab197fe 100644
Binary files a/icons/obj/doors/mineral_doors.dmi and b/icons/obj/doors/mineral_doors.dmi differ
diff --git a/icons/obj/drinks.dmi b/icons/obj/drinks.dmi
index e6e8ff9eb7..a32d0234d6 100644
Binary files a/icons/obj/drinks.dmi and b/icons/obj/drinks.dmi differ
diff --git a/icons/obj/fluff.dmi b/icons/obj/fluff.dmi
index b476d25228..72edaa0528 100644
Binary files a/icons/obj/fluff.dmi and b/icons/obj/fluff.dmi differ
diff --git a/icons/obj/food/food.dmi b/icons/obj/food/food.dmi
index a053eab792..9861a2e618 100644
Binary files a/icons/obj/food/food.dmi and b/icons/obj/food/food.dmi differ
diff --git a/icons/obj/monitors.dmi b/icons/obj/monitors.dmi
index f338ffcf3d..9880707010 100644
Binary files a/icons/obj/monitors.dmi and b/icons/obj/monitors.dmi differ
diff --git a/icons/obj/plushes.dmi b/icons/obj/plushes.dmi
index 0bf89ab744..7ca7b068b0 100644
Binary files a/icons/obj/plushes.dmi and b/icons/obj/plushes.dmi differ
diff --git a/icons/obj/slimecrossing.dmi b/icons/obj/slimecrossing.dmi
index 56ccfc21f7..6d74116a18 100644
Binary files a/icons/obj/slimecrossing.dmi and b/icons/obj/slimecrossing.dmi differ
diff --git a/icons/turf/floors.dmi b/icons/turf/floors.dmi
index 518adfc766..2a56a03e66 100644
Binary files a/icons/turf/floors.dmi and b/icons/turf/floors.dmi differ
diff --git a/interface/skin.dmf b/interface/skin.dmf
index 99850c34ba..65f4a22664 100644
--- a/interface/skin.dmf
+++ b/interface/skin.dmf
@@ -268,3 +268,30 @@ window "statwindow"
is-default = true
saved-params = ""
+ window "preferences_window"
+ elem "preferences_window"
+ type = MAIN
+ pos = 372,0
+ size = 1120x1000
+ anchor1 = none
+ anchor2 = none
+ background-color = none
+ is-visible = false
+ saved-params = "pos;size;is-minimized;is-maximized"
+ statusbar = false
+ elem "preferences_browser"
+ type = BROWSER
+ pos = -8,-8
+ size = 896x1008
+ anchor1 = 0,0
+ anchor2 = 90,100
+ background-color = none
+ saved-params = ""
+ elem "character_preview_map"
+ type = MAP
+ pos = 887,0
+ size = 313x1000
+ anchor1 = 90,0
+ anchor2 = 100,100
+ right-click = true
+ saved-params = "zoom;letterbox;zoom-mode"
diff --git a/modular_citadel/code/datums/components/phantomthief.dm b/modular_citadel/code/datums/components/phantomthief.dm
index c09d17d930..d34e16f6e9 100644
--- a/modular_citadel/code/datums/components/phantomthief.dm
+++ b/modular_citadel/code/datums/components/phantomthief.dm
@@ -39,7 +39,7 @@
if(!istype(user))
return
if(!combattoggle_redir)
- combattoggle_redir = user.AddComponent(/datum/component/redirect,list(COMSIG_COMBAT_TOGGLED),CALLBACK(src,.proc/handlefilterstuff))
+ combattoggle_redir = user.AddComponent(/datum/component/redirect, list(COMSIG_COMBAT_TOGGLED = CALLBACK(src, .proc/handlefilterstuff)))
/datum/component/phantomthief/proc/OnDropped(mob/user)
if(!istype(user))
diff --git a/modular_citadel/code/datums/components/souldeath.dm b/modular_citadel/code/datums/components/souldeath.dm
new file mode 100644
index 0000000000..5beddf3529
--- /dev/null
+++ b/modular_citadel/code/datums/components/souldeath.dm
@@ -0,0 +1,35 @@
+/datum/component/souldeath
+ var/mob/living/wearer
+ var/equip_slot
+ var/signal = FALSE
+
+/datum/component/souldeath/Initialize()
+ if(!isitem(parent))
+ return COMPONENT_INCOMPATIBLE
+ RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, .proc/equip)
+ RegisterSignal(parent, COMSIG_ITEM_DROPPED, .proc/unequip)
+
+/datum/component/souldeath/proc/equip(datum/source, mob/living/equipper, slot)
+ if(!slot || equip_slot == slot)
+ wearer = equipper
+ RegisterSignal(wearer, COMSIG_MOB_DEATH, .proc/die, TRUE)
+ signal = TRUE
+ else
+ if(signal)
+ UnregisterSignal(wearer, COMSIG_MOB_DEATH)
+ signal = FALSE
+ return
+
+/datum/component/souldeath/proc/unequip()
+ UnregisterSignal(wearer, COMSIG_MOB_DEATH)
+ wearer = null
+ signal = FALSE
+
+/datum/component/souldeath/proc/die()
+ if(!wearer)
+ return //idfk
+ new/obj/effect/temp_visual/souldeath(wearer.loc, wearer)
+ playsound(wearer, 'modular_citadel/sound/misc/souldeath.ogg', 100, FALSE)
+
+/datum/component/souldeath/neck
+ equip_slot = SLOT_NECK
diff --git a/modular_citadel/code/datums/status_effects/debuffs.dm b/modular_citadel/code/datums/status_effects/debuffs.dm
index a57902d0cf..6dcfc84a87 100644
--- a/modular_citadel/code/datums/status_effects/debuffs.dm
+++ b/modular_citadel/code/datums/status_effects/debuffs.dm
@@ -1,5 +1,8 @@
/datum/status_effect/incapacitating/knockdown/on_creation(mob/living/new_owner, set_duration, updating_canmove, override_duration, override_stam)
if(iscarbon(new_owner) && (isnum(set_duration) || isnum(override_duration)))
+ if(istype(new_owner.buckled, /obj/vehicle/ridden))
+ var/obj/buckl = new_owner.buckled
+ buckl.unbuckle_mob(new_owner)
new_owner.resting = TRUE
new_owner.adjustStaminaLoss(isnull(override_stam)? set_duration*0.25 : override_stam)
if(isnull(override_duration) && (set_duration > 80))
diff --git a/modular_citadel/code/game/machinery/cryopod.dm b/modular_citadel/code/game/machinery/cryopod.dm
index ec8738f9ea..9369fa7677 100644
--- a/modular_citadel/code/game/machinery/cryopod.dm
+++ b/modular_citadel/code/game/machinery/cryopod.dm
@@ -166,7 +166,12 @@
// These items will NOT be preserved
var/list/do_not_preserve_items = list (
/obj/item/mmi/posibrain,
+ /obj/item/gun/energy/laser/mounted,
+ /obj/item/gun/energy/e_gun/advtaser/mounted,
+ /obj/item/gun/ballistic/revolver/grenadelauncher/cyborg,
/obj/item/gun/energy/disabler/cyborg,
+ /obj/item/gun/energy/e_gun/advtaser/cyborg,
+ /obj/item/gun/energy/printer,
/obj/item/gun/energy/kinetic_accelerator/cyborg,
/obj/item/gun/energy/laser/cyborg
)
diff --git a/modular_citadel/code/game/objects/effects/temporary_visuals/souldeath.dm b/modular_citadel/code/game/objects/effects/temporary_visuals/souldeath.dm
new file mode 100644
index 0000000000..1ebf6fb2a6
--- /dev/null
+++ b/modular_citadel/code/game/objects/effects/temporary_visuals/souldeath.dm
@@ -0,0 +1,5 @@
+/obj/effect/temp_visual/souldeath
+ name = "soul death"
+ icon = 'modular_citadel/icons/effects/souldeath.dmi'
+ icon_state = "souldeath"
+ duration = 30
\ No newline at end of file
diff --git a/modular_citadel/code/init.dm b/modular_citadel/code/init.dm
index 6df5be02eb..2c2b5b811f 100644
--- a/modular_citadel/code/init.dm
+++ b/modular_citadel/code/init.dm
@@ -9,6 +9,7 @@
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails, GLOB.mam_tails_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_ears, GLOB.mam_ears_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails_animated, GLOB.mam_tails_animated_list)
+ init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_snouts, GLOB.mam_snouts_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/taur, GLOB.taur_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_head, GLOB.xeno_head_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_tail, GLOB.xeno_tail_list)
diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm
index 7ef696ee91..a625829577 100644
--- a/modular_citadel/code/modules/arousal/arousal.dm
+++ b/modular_citadel/code/modules/arousal/arousal.dm
@@ -90,6 +90,24 @@
/mob/living/proc/updatearousal()
update_arousal_hud()
+/mob/living/carbon/updatearousal()
+ . = ..()
+ for(var/obj/item/organ/genital/G in internal_organs)
+ if(istype(G))
+ var/datum/sprite_accessory/S
+ switch(G.type)
+ if(/obj/item/organ/genital/penis)
+ S = GLOB.cock_shapes_list[G.shape]
+ if(/obj/item/organ/genital/vagina)
+ S = GLOB.vagina_shapes_list[G.shape]
+ if(/obj/item/organ/genital/breasts)
+ S = GLOB.breasts_shapes_list[G.shape]
+ if(S?.alt_aroused)
+ G.aroused_state = isPercentAroused(G.aroused_amount)
+ else
+ G.aroused_state = FALSE
+ G.update_appearance()
+
/mob/living/proc/update_arousal_hud()
return 0
diff --git a/modular_citadel/code/modules/arousal/organs/genitals.dm b/modular_citadel/code/modules/arousal/organs/genitals.dm
index b43f17e58a..c10d444f07 100644
--- a/modular_citadel/code/modules/arousal/organs/genitals.dm
+++ b/modular_citadel/code/modules/arousal/organs/genitals.dm
@@ -311,10 +311,6 @@
if(!S || S.icon_state == "none")
continue
var/mutable_appearance/genital_overlay = mutable_appearance(S.icon, layer = -layer)
- if(S.alt_aroused)
- G.aroused_state = H.isPercentAroused(G.aroused_amount)
- else
- G.aroused_state = FALSE
genital_overlay.icon_state = "[G.slot]_[S.icon_state]_[size]_[G.aroused_state]_[layertext]"
if(S.center)
diff --git a/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm b/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm
index 7c02b1c3a5..bcfa462789 100644
--- a/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm
+++ b/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm
@@ -100,6 +100,7 @@
/datum/sprite_accessory/breasts/pair
icon_state = "pair"
name = "Pair"
+ alt_aroused = TRUE
//OVIPOSITORS BE HERE
diff --git a/modular_citadel/code/modules/arousal/toys/dildos.dm b/modular_citadel/code/modules/arousal/toys/dildos.dm
index 587702762c..4b0a7ad919 100644
--- a/modular_citadel/code/modules/arousal/toys/dildos.dm
+++ b/modular_citadel/code/modules/arousal/toys/dildos.dm
@@ -1,7 +1,7 @@
//////////
//DILDOS//
//////////
-obj/item/dildo
+/obj/item/dildo
name = "dildo"
desc = "Floppy!"
icon = 'modular_citadel/icons/obj/genitals/dildo.dmi'
@@ -18,9 +18,10 @@ obj/item/dildo
var/random_color = TRUE
var/random_size = FALSE
var/random_shape = FALSE
+ var/is_knotted = FALSE
//Lists moved to _cit_helpers.dm as globals so they're not instanced individually
-obj/item/dildo/proc/update_appearance()
+/obj/item/dildo/proc/update_appearance()
icon_state = "[dildo_type]_[dildo_shape]_[dildo_size]"
var/sizeword = ""
switch(dildo_size)
@@ -35,7 +36,7 @@ obj/item/dildo/proc/update_appearance()
name = "[sizeword][dildo_shape] [can_customize ? "custom " : ""][dildo_type]"
-obj/item/dildo/AltClick(mob/living/user)
+/obj/item/dildo/AltClick(mob/living/user)
if(QDELETED(src))
return
if(!isliving(user))
@@ -46,7 +47,7 @@ obj/item/dildo/AltClick(mob/living/user)
return
customize(user)
-obj/item/dildo/proc/customize(mob/living/user)
+/obj/item/dildo/proc/customize(mob/living/user)
if(!can_customize)
return FALSE
if(src && !user.incapacitated() && in_range(user,src))
@@ -75,7 +76,7 @@ obj/item/dildo/proc/customize(mob/living/user)
update_appearance()
return TRUE
-obj/item/dildo/Initialize()
+/obj/item/dildo/Initialize()
. = ..()
if(random_color == TRUE)
var/randcolor = pick(GLOB.dildo_colors)
@@ -91,38 +92,41 @@ obj/item/dildo/Initialize()
pixel_y = rand(-7,7)
pixel_x = rand(-7,7)
-obj/item/dildo/examine(mob/user)
+/obj/item/dildo/examine(mob/user)
..()
if(can_customize)
user << "Alt-Click \the [src.name] to customize it."
-obj/item/dildo/random//totally random
+/obj/item/dildo/random//totally random
name = "random dildo"//this name will show up in vendors and shit so you know what you're vending(or don't, i guess :^))
random_color = TRUE
random_shape = TRUE
random_size = TRUE
-
-obj/item/dildo/knotted
+/obj/item/dildo/knotted
dildo_shape = "knotted"
name = "knotted dildo"
+ attack_verb = list("penetrated", "knotted", "slapped", "inseminated")
obj/item/dildo/human
dildo_shape = "human"
name = "human dildo"
+ attack_verb = list("penetrated", "slapped", "inseminated")
obj/item/dildo/plain
dildo_shape = "plain"
name = "plain dildo"
+ attack_verb = list("penetrated", "slapped", "inseminated")
obj/item/dildo/flared
dildo_shape = "flared"
name = "flared dildo"
+ attack_verb = list("penetrated", "slapped", "neighed", "gaped", "prolapsed", "inseminated")
obj/item/dildo/flared/huge
- name = "literal horse cock"
- desc = "THIS THING IS HUGE!"
- dildo_size = 4
+ name = "literal horse cock"
+ desc = "THIS THING IS HUGE!"
+ dildo_size = 4
obj/item/dildo/custom
name = "customizable dildo"
@@ -131,3 +135,30 @@ obj/item/dildo/custom
random_color = TRUE
random_shape = TRUE
random_size = TRUE
+
+// Suicide acts, by request
+
+/obj/item/dildo/proc/manual_suicide(mob/living/user)
+ user.visible_message("[user] finally finishes deepthroating the [src], and their life.")
+ 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")
+ if(do_after(user,17,target=src))
+ user.visible_message("[user] tears-up and gags as they shove [src] down their throat! It looks like [user.p_theyre()] trying to commit suicide!")
+ playsound(loc, 'sound/weapons/gagging.ogg', 50, 1, -1)
+ user.Stun(150)
+ user.adjust_blurriness(8)
+ user.adjust_eye_damage(10)
+ return MANUAL_SUICIDE
+
+/obj/item/dildo/flared/huge/suicide_act(mob/living/user)
+ if(do_after(user,35,target=src))
+ user.visible_message("[user] tears-up and gags as they try to deepthroat the [src]! WHY WOULD THEY DO THAT? It looks like [user.p_theyre()] trying to commit suicide!!")
+ playsound(loc, 'sound/weapons/gagging.ogg', 50, 2, -1)
+ user.Stun(300)
+ user.adjust_blurriness(8)
+ user.adjust_eye_damage(15)
+ return MANUAL_SUICIDE
+
diff --git a/modular_citadel/code/modules/cargo/packs.dm b/modular_citadel/code/modules/cargo/packs.dm
index c03a049b60..6d39a51a76 100644
--- a/modular_citadel/code/modules/cargo/packs.dm
+++ b/modular_citadel/code/modules/cargo/packs.dm
@@ -23,6 +23,6 @@
/datum/supply_pack/misc/jukebox
name = "Jukebox"
- cost = 1000000
+ cost = 35000
contains = list(/obj/machinery/jukebox)
crate_name = "Jukebox"
diff --git a/modular_citadel/code/modules/client/loadout/__donator.dm b/modular_citadel/code/modules/client/loadout/__donator.dm
index eda53c0afe..66245fbb8a 100644
--- a/modular_citadel/code/modules/client/loadout/__donator.dm
+++ b/modular_citadel/code/modules/client/loadout/__donator.dm
@@ -344,3 +344,27 @@ datum/gear/darksabresheath
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/ian_costume
ckeywhitelist = list("cathodetherobot")
+
+/datum/gear/sharkcloth
+ name = "Leon's Skimpy Outfit"
+ category = SLOT_WEAR_SUIT
+ path = /obj/item/clothing/under/leoskimpy
+ ckeywhitelist = list("spectrosis")
+
+/datum/gear/mimemask
+ name = "Mime Mask"
+ category = SLOT_WEAR_MASK
+ path = /obj/item/clothing/mask/gas/mime
+ ckeywhitelist = list("pireamaineach")
+
+/datum/gear/mimeoveralls
+ name = "Mime's Overalls"
+ category = SLOT_WEAR_SUIT
+ path = /obj/item/clothing/under/mimeoveralls
+ ckeywhitelist = list("pireamaineach")
+
+/datum/gear/soulneck
+ name = "Soul Necklace"
+ category = SLOT_NECK
+ path = /obj/item/clothing/neck/undertale
+ ckeywhitelist = list("twilightic")
\ No newline at end of file
diff --git a/modular_citadel/code/modules/client/loadout/backpack.dm b/modular_citadel/code/modules/client/loadout/backpack.dm
index b3a59425a9..9f12dd8b03 100644
--- a/modular_citadel/code/modules/client/loadout/backpack.dm
+++ b/modular_citadel/code/modules/client/loadout/backpack.dm
@@ -18,6 +18,11 @@
category = SLOT_IN_BACKPACK
path = /obj/item/toy/plush/slimeplushie
+/datum/gear/plushlamp
+ name = "Lamp plushie"
+ category = SLOT_IN_BACKPACK
+ path = /obj/item/toy/plush/lampplushie
+
/datum/gear/tennis
name = "Classic Tennis Ball"
category = SLOT_IN_BACKPACK
@@ -56,4 +61,14 @@
/datum/gear/dildo
name = "Customizable dildo"
category = SLOT_IN_BACKPACK
- path = /obj/item/dildo/custom
\ No newline at end of file
+ path = /obj/item/dildo/custom
+
+/datum/gear/paperbin
+ name = "Paper Bin"
+ category = SLOT_IN_BACKPACK
+ path = /obj/item/paper_bin
+
+/datum/gear/crayons
+ name = "Box of crayons"
+ category = SLOT_IN_BACKPACK
+ path = /obj/item/storage/crayons
diff --git a/modular_citadel/code/modules/client/loadout/suit.dm b/modular_citadel/code/modules/client/loadout/suit.dm
index 773366c81e..9d3a6b9a02 100644
--- a/modular_citadel/code/modules/client/loadout/suit.dm
+++ b/modular_citadel/code/modules/client/loadout/suit.dm
@@ -18,42 +18,6 @@
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/cloak/david
cost = 3
-
-/datum/gear/creamsweater
- name = "Cream Commando Sweater"
- category = SLOT_WEAR_SUIT
- path = /obj/item/clothing/under/bb_sweater
- cost = 1
-
-/datum/gear/blacksweater
- name = "Black Commando Sweater"
- category = SLOT_WEAR_SUIT
- path = /obj/item/clothing/under/bb_sweater/black
- cost = 1
-
-/datum/gear/purpsweater
- name = "Purple Commando Sweater"
- category = SLOT_WEAR_SUIT
- path = /obj/item/clothing/under/bb_sweater/purple
- cost = 1
-
-/datum/gear/greensweater
- name = "Green Commando Sweater"
- category = SLOT_WEAR_SUIT
- path = /obj/item/clothing/under/bb_sweater/green
- cost = 1
-
-/datum/gear/redsweater
- name = "Red Commando Sweater"
- category = SLOT_WEAR_SUIT
- path = /obj/item/clothing/under/bb_sweater/red
- cost = 1
-
-/datum/gear/bluesweater
- name = "Navy Commando Sweater"
- category = SLOT_WEAR_SUIT
- path = /obj/item/clothing/under/bb_sweater/blue
- cost = 1
/datum/gear/jacketbomber
name = "Bomber jacket"
diff --git a/modular_citadel/code/modules/client/loadout/uniform.dm b/modular_citadel/code/modules/client/loadout/uniform.dm
index 7c592c60e1..e4e2f063d3 100644
--- a/modular_citadel/code/modules/client/loadout/uniform.dm
+++ b/modular_citadel/code/modules/client/loadout/uniform.dm
@@ -118,11 +118,43 @@
category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/pants/track
+// Pantsless Sweaters
+
/datum/gear/turtleneck
name = "Tactitool Turtleneck"
category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/syndicate/cosmetic
+/datum/gear/creamsweater
+ name = "Cream Commando Sweater"
+ category = SLOT_W_UNIFORM
+ path = /obj/item/clothing/under/bb_sweater
+
+/datum/gear/blacksweater
+ name = "Black Commando Sweater"
+ category = SLOT_W_UNIFORM
+ path = /obj/item/clothing/under/bb_sweater/black
+
+/datum/gear/purpsweater
+ name = "Purple Commando Sweater"
+ category = SLOT_W_UNIFORM
+ path = /obj/item/clothing/under/bb_sweater/purple
+
+/datum/gear/greensweater
+ name = "Green Commando Sweater"
+ category = SLOT_W_UNIFORM
+ path = /obj/item/clothing/under/bb_sweater/green
+
+/datum/gear/redsweater
+ name = "Red Commando Sweater"
+ category = SLOT_W_UNIFORM
+ path = /obj/item/clothing/under/bb_sweater/red
+
+/datum/gear/bluesweater
+ name = "Navy Commando Sweater"
+ category = SLOT_W_UNIFORM
+ path = /obj/item/clothing/under/bb_sweater/blue
+
/datum/gear/polykilt
name = "Polychromic Kilt"
category = SLOT_W_UNIFORM
diff --git a/modular_citadel/code/modules/client/preferences.dm b/modular_citadel/code/modules/client/preferences.dm
index 927d324e23..358208c1d7 100644
--- a/modular_citadel/code/modules/client/preferences.dm
+++ b/modular_citadel/code/modules/client/preferences.dm
@@ -40,6 +40,7 @@
"mcolor3" = "FFF",
"mam_body_markings" = "None",
"mam_ears" = "None",
+ "mam_snouts" = "None",
"mam_tail" = "None",
"mam_tail_animated" = "None",
"xenodorsal" = "Standard",
diff --git a/modular_citadel/code/modules/client/preferences_savefile.dm b/modular_citadel/code/modules/client/preferences_savefile.dm
index 8f65e47d2b..209d46db61 100644
--- a/modular_citadel/code/modules/client/preferences_savefile.dm
+++ b/modular_citadel/code/modules/client/preferences_savefile.dm
@@ -40,6 +40,7 @@
WRITE_FILE(S["feature_mam_ears"], features["mam_ears"])
WRITE_FILE(S["feature_mam_tail_animated"], features["mam_tail_animated"])
WRITE_FILE(S["feature_taur"], features["taur"])
+ WRITE_FILE(S["feature_mam_snouts"], features["mam_snouts"])
//Xeno features
WRITE_FILE(S["feature_xeno_tail"], features["xenotail"])
WRITE_FILE(S["feature_xeno_dors"], features["xenodorsal"])
diff --git a/modular_citadel/code/modules/client/verbs/who.dm b/modular_citadel/code/modules/client/verbs/who.dm
index 091dd7bf79..7640595e18 100644
--- a/modular_citadel/code/modules/client/verbs/who.dm
+++ b/modular_citadel/code/modules/client/verbs/who.dm
@@ -28,28 +28,37 @@
var/msg = ""
var/list/Lines = list()
+ var/list/assembled = list()
+ var/admin_mode = check_rights_for(src, R_ADMIN) && isobserver(mob)
+ if(admin_mode)
+ log_admin("[key_name(usr)] checked advanced who in-round")
if(length(GLOB.admins))
Lines += "Admins:"
for(var/X in GLOB.admins)
var/client/C = X
if(C && C.holder && !C.holder.fakekey)
- Lines += "\t [C.key][show_admin_info(C)] ([round(C.avgping, 1)]ms)"
+ assembled += "\t [C.key][admin_mode? "[show_admin_info(C)]":""] ([round(C.avgping, 1)]ms)"
+ Lines += sortList(assembled)
+ assembled.len = 0
if(length(GLOB.mentors))
Lines += "Mentors:"
for(var/X in GLOB.mentors)
var/client/C = X
- if(C)
- Lines += "\t [C.key][show_admin_info(C)] ([round(C.avgping, 1)]ms)"
-
+ if(C && (!C.holder || (C.holder && !C.holder.fakekey))) //>using stuff this complex instead of just using if/else lmao
+ assembled += "\t [C.key][admin_mode? "[show_admin_info(C)]":""] ([round(C.avgping, 1)]ms)"
+ Lines += sortList(assembled)
+ assembled.len = 0
Lines += "Players:"
for(var/X in sortList(GLOB.clients))
var/client/C = X
- if(!C) continue
+ if(!C)
+ continue
var/key = C.key
if(C.holder && C.holder.fakekey)
key = C.holder.fakekey
- Lines += "\t [key][show_admin_info(C)] ([round(C.avgping, 1)]ms)"
-
+ assembled += "\t [key][admin_mode? "[show_admin_info(C)]":""] ([round(C.avgping, 1)]ms)"
+ Lines += sortList(assembled)
+
for(var/line in Lines)
msg += "[line]\n"
@@ -60,9 +69,6 @@
if(!C)
return ""
- if(!check_rights_for(src, R_ADMIN))
- return ""
-
var/entry = ""
if(C.holder && C.holder.fakekey)
entry += " (as [C.holder.fakekey])"
diff --git a/modular_citadel/code/modules/clothing/glasses/phantomthief.dm b/modular_citadel/code/modules/clothing/glasses/phantomthief.dm
index e9d31f73d3..49eb089afa 100644
--- a/modular_citadel/code/modules/clothing/glasses/phantomthief.dm
+++ b/modular_citadel/code/modules/clothing/glasses/phantomthief.dm
@@ -36,7 +36,7 @@
if(!istype(user))
return
if(!combattoggle_redir)
- combattoggle_redir = user.AddComponent(/datum/component/redirect,list(COMSIG_COMBAT_TOGGLED),CALLBACK(src,.proc/injectadrenaline))
+ combattoggle_redir = user.AddComponent(/datum/component/redirect, list(COMSIG_COMBAT_TOGGLED = CALLBACK(src, .proc/injectadrenaline)))
/obj/item/clothing/glasses/phantomthief/syndicate/dropped(mob/user)
. = ..()
diff --git a/modular_citadel/code/modules/clothing/neck.dm b/modular_citadel/code/modules/clothing/neck.dm
new file mode 100644
index 0000000000..8d7d4747b7
--- /dev/null
+++ b/modular_citadel/code/modules/clothing/neck.dm
@@ -0,0 +1,23 @@
+/datum/action/item_action/zanderlocket
+ name = "Activate the locket"
+
+/obj/item/clothing/neck/undertale
+ name = "Sylphaen Heart Locket"
+ desc = "A heart shaped locket...The name: 'Zander Sylphaen is inscribed on the front. Something about this necklace fills you with determination."
+ icon = 'modular_citadel/icons/obj/clothing/cit_neck.dmi'
+ item_state = "undertale"
+ icon_state = "undertale"
+ alternate_worn_icon = 'modular_citadel/icons/mob/clothing/necks.dmi'
+ resistance_flags = FIRE_PROOF
+ actions_types = list(/datum/action/item_action/zanderlocket)
+ var/toggled = FALSE
+ var/obj/effect/heart/heart
+
+/datum/action/item_action/zanderlocket/Trigger()
+ new/obj/effect/temp_visual/souldeath(owner.loc, owner)
+ playsound(owner, 'modular_citadel/sound/misc/souldeath.ogg', 100, FALSE)
+
+
+/obj/item/clothing/neck/undertale/Initialize()
+ ..()
+ AddComponent(/datum/component/souldeath/neck)
diff --git a/modular_citadel/code/modules/clothing/under/trek_under.dm b/modular_citadel/code/modules/clothing/under/trek_under.dm
index 00f84b7583..ddcf0e6344 100644
--- a/modular_citadel/code/modules/clothing/under/trek_under.dm
+++ b/modular_citadel/code/modules/clothing/under/trek_under.dm
@@ -11,7 +11,7 @@
/obj/item/clothing/under/rank/trek
name = "Section 31 Uniform"
desc = "Oooh... right."
- icon = 'modular_citadel/icons/mob/clothing/trek_item_icon.dmi'
+ icon = 'modular_citadel/icons/obj/clothing/trek_item_icon.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/clothing/trek_mob_icon.dmi'
item_state = ""
can_adjust = FALSE //to prevent you from "wearing it casually"
@@ -91,11 +91,12 @@
/obj/item/clothing/suit/storage/trek/ds9
name = "Padded Overcoat"
desc = "The overcoat worn by all officers of the 2380s."
- icon = 'modular_citadel/icons/mob/clothing/trek_item_icon.dmi'
+ icon = 'modular_citadel/icons/obj/clothing/trek_item_icon.dmi'
icon_state = "trek_ds9_coat"
alternate_worn_icon = 'modular_citadel/icons/mob/clothing/trek_mob_icon.dmi'
item_state = "trek_ds9_coat"
body_parts_covered = CHEST|GROIN|ARMS
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
permeability_coefficient = 0.50
allowed = list(
/obj/item/flashlight, /obj/item/analyzer,
@@ -136,10 +137,11 @@
name = "Federation Uniform Jacket (Red)"
desc = "A uniform jacket from the United Federation. Starfleet still uses this uniform and there are variations of it. Set phasers to awesome."
- icon = 'modular_citadel/icons/mob/clothing/trek_item_icon.dmi'
+ icon = 'modular_citadel/icons/obj/clothing/trek_item_icon.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/clothing/trek_mob_icon.dmi'
icon_state = "fedcoat"
item_state = "fedcoat"
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
blood_overlay_type = "coat"
body_parts_covered = CHEST|GROIN|ARMS
@@ -204,7 +206,7 @@
/obj/item/clothing/suit/storage/fluff/modernfedcoat
name = "Modern Federation Uniform Jacket"
desc = "A modern uniform jacket from the United Federation. Their Starfleet had recently started using these uniforms. Wearing this makes you feel like a competant commander."
- icon = 'modular_citadel/icons/mob/clothing/trek_item_icon.dmi'
+ icon = 'modular_citadel/icons/obj/clothing/trek_item_icon.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/clothing/trek_mob_icon.dmi'
icon_state = "fedmodern"
item_state = "fedmodern"
@@ -237,20 +239,20 @@
/obj/item/clothing/head/caphat/formal/fedcover
name = "Federation Officer's Cap"
desc = "An officer's cap that demands discipline from the one who wears it."
- icon = 'modular_citadel/icons/mob/clothing/trek_item_icon.dmi'
+ icon = 'modular_citadel/icons/obj/clothing/trek_item_icon.dmi'
icon_state = "fedcapofficer"
alternate_worn_icon = 'modular_citadel/icons/mob/clothing/trek_mob_icon.dmi'
- item_state = "fedcapofficer_mob"
+ item_state = "fedcapofficer"
//Variants
/obj/item/clothing/head/caphat/formal/fedcover/medsci
icon_state = "fedcapsci"
- item_state = "fedcapsci_mob"
+ item_state = "fedcapsci"
/obj/item/clothing/head/caphat/formal/fedcover/eng
icon_state = "fedcapeng"
- item_state = "fedcapeng_mob"
+ item_state = "fedcapeng"
/obj/item/clothing/head/caphat/formal/fedcover/sec
icon_state = "fedcapsec"
- item_state = "fedcapsec_mob"
+ item_state = "fedcapsec"
diff --git a/modular_citadel/code/modules/custom_loadout/custom_items.dm b/modular_citadel/code/modules/custom_loadout/custom_items.dm
index 8e26f8014f..5f0d8cfc00 100644
--- a/modular_citadel/code/modules/custom_loadout/custom_items.dm
+++ b/modular_citadel/code/modules/custom_loadout/custom_items.dm
@@ -420,3 +420,22 @@
item_state = "Divine_robes"
icon_state = "Divine_robes"
mutantrace_variation = NO_MUTANTRACE_VARIATION
+
+/obj/item/clothing/under/leoskimpy
+ name = "Leon's Skimpy Outfit"
+ icon = 'icons/obj/custom.dmi'
+ alternate_worn_icon = 'icons/mob/custom_w.dmi'
+ desc = "A rather skimpy outfit."
+ item_state = "shark_cloth"
+ icon_state = "shark_cloth"
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
+
+/obj/item/clothing/under/mimeoveralls
+ name = "Mime's Overalls"
+ icon = 'icons/obj/custom.dmi'
+ alternate_worn_icon = 'icons/mob/custom_w.dmi'
+ desc = "A less-than-traditional mime's attire, completed by a set of dorky-looking overalls."
+ item_state = "moveralls"
+ icon_state = "moveralls"
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
+
diff --git a/modular_citadel/code/modules/jobs/job_types/captain.dm b/modular_citadel/code/modules/jobs/job_types/captain.dm
index 7d8d1ac5ca..674cd9d09e 100644
--- a/modular_citadel/code/modules/jobs/job_types/captain.dm
+++ b/modular_citadel/code/modules/jobs/job_types/captain.dm
@@ -1,9 +1,9 @@
/datum/job/captain
- minimal_player_age = 60
+ minimal_player_age = 20
exp_type = EXP_TYPE_COMMAND
/datum/job/hop
- minimal_player_age = 60
+ minimal_player_age = 20
head_announce = list("Service")
exp_type_department = EXP_TYPE_SERVICE
diff --git a/modular_citadel/code/modules/jobs/job_types/engineering.dm b/modular_citadel/code/modules/jobs/job_types/engineering.dm
index f199bbefea..4d6aa4119d 100644
--- a/modular_citadel/code/modules/jobs/job_types/engineering.dm
+++ b/modular_citadel/code/modules/jobs/job_types/engineering.dm
@@ -1,5 +1,5 @@
/datum/job/chief_engineer
- minimal_player_age = 30
+ minimal_player_age = 10
/datum/job/engineer
access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS,
diff --git a/modular_citadel/code/modules/jobs/job_types/medical.dm b/modular_citadel/code/modules/jobs/job_types/medical.dm
index 31c8b7d3c4..15841ad9d5 100644
--- a/modular_citadel/code/modules/jobs/job_types/medical.dm
+++ b/modular_citadel/code/modules/jobs/job_types/medical.dm
@@ -1,5 +1,5 @@
/datum/job/cmo
- minimal_player_age = 30
+ minimal_player_age = 10
/datum/outfit/job/doctor
backpack_contents = list(/obj/item/storage/hypospraykit/regular)
diff --git a/modular_citadel/code/modules/jobs/job_types/science.dm b/modular_citadel/code/modules/jobs/job_types/science.dm
index 4542e7d099..94272d24a6 100644
--- a/modular_citadel/code/modules/jobs/job_types/science.dm
+++ b/modular_citadel/code/modules/jobs/job_types/science.dm
@@ -1,2 +1,2 @@
/datum/job/rd
- minimal_player_age = 30
\ No newline at end of file
+ minimal_player_age = 10
diff --git a/modular_citadel/code/modules/jobs/job_types/security.dm b/modular_citadel/code/modules/jobs/job_types/security.dm
index 9e59d98d00..de00f2d948 100644
--- a/modular_citadel/code/modules/jobs/job_types/security.dm
+++ b/modular_citadel/code/modules/jobs/job_types/security.dm
@@ -1,5 +1,5 @@
/datum/job/hos
- minimal_player_age = 30
+ minimal_player_age = 10
/datum/outfit/job/warden
- suit_store = /obj/item/gun/energy/pumpaction/defender
\ No newline at end of file
+ suit_store = /obj/item/gun/energy/pumpaction/defender
diff --git a/modular_citadel/code/modules/keybindings/bindings_human.dm b/modular_citadel/code/modules/keybindings/bindings_human.dm
index 963e71d709..ffe88bd4a9 100644
--- a/modular_citadel/code/modules/keybindings/bindings_human.dm
+++ b/modular_citadel/code/modules/keybindings/bindings_human.dm
@@ -1,13 +1,13 @@
/mob/living/carbon/human/key_down(_key, client/user)
switch(_key)
if("Shift")
- togglesprint()
+ sprint_hotkey(TRUE)
return
return ..()
/mob/living/carbon/human/key_up(_key, client/user)
switch(_key)
if("Shift")
- togglesprint()
+ sprint_hotkey(FALSE)
return
return ..()
diff --git a/modular_citadel/code/modules/keybindings/bindings_robot.dm b/modular_citadel/code/modules/keybindings/bindings_robot.dm
index 59151f2b40..d3b6248f7d 100644
--- a/modular_citadel/code/modules/keybindings/bindings_robot.dm
+++ b/modular_citadel/code/modules/keybindings/bindings_robot.dm
@@ -1,13 +1,13 @@
/mob/living/silicon/robot/key_down(_key, client/user)
switch(_key)
if("Shift")
- togglesprint()
+ sprint_hotkey(TRUE)
return
return ..()
/mob/living/silicon/robot/key_up(_key, client/user)
switch(_key)
if("Shift")
- togglesprint()
+ sprint_hotkey(FALSE)
return
return ..()
diff --git a/modular_citadel/code/modules/mob/cit_emotes.dm b/modular_citadel/code/modules/mob/cit_emotes.dm
index c76b8f2c12..a314baa852 100644
--- a/modular_citadel/code/modules/mob/cit_emotes.dm
+++ b/modular_citadel/code/modules/mob/cit_emotes.dm
@@ -15,9 +15,12 @@
/datum/emote/living/insult/run_emote(mob/living/user, params)
var/insult_message = ""
+ var/miming = user.mind ? user.mind.miming : 0
if(!user.is_muzzled())
insult_message += pick_list_replacements(INSULTS_FILE, "insult_gen")
message = insult_message
+ else if(miming)
+ message = "creatively gesticulates."
else
message = "muffles something."
. = ..()
@@ -194,4 +197,34 @@
user.apply_damage(20, BRUTE, def_zone)
if(luck >= 95)
user.adjustBrainLoss(100)
- . = ..()
\ No newline at end of file
+ . = ..()
+
+
+/datum/emote/living/mothsqueak
+ key = "msqueak"
+ key_third_person = "lets out a tiny squeak"
+ message = "lets out a tiny squeak!"
+ emote_type = EMOTE_AUDIBLE
+ mob_type_allowed_typecache = list(/mob/living/carbon)
+
+/datum/emote/living/mothsqueak/run_emote(mob/living/user, params)
+ if(ishuman(user))
+ if(user.nextsoundemote >= world.time)
+ return
+ user.nextsoundemote = world.time + 7
+ playsound(user, 'modular_citadel/sound/voice/mothsqueak.ogg', 50, 1, -1)
+ . = ..()
+
+/datum/emote/living/merp
+ key = "merp"
+ key_third_person = "merps"
+ message = "merps!"
+ emote_type = EMOTE_AUDIBLE
+
+/datum/emote/living/merp/run_emote(mob/living/user, params)
+ if(ishuman(user))
+ if(user.nextsoundemote >= world.time)
+ return
+ user.nextsoundemote = world.time + 7
+ playsound(user, 'modular_citadel/sound/voice/merp.ogg', 50, 1, -1)
+ . = ..()
diff --git a/modular_citadel/code/modules/mob/dead/new_player/sprite_accessories.dm b/modular_citadel/code/modules/mob/dead/new_player/sprite_accessories.dm
index 38343838e9..bd301a2e85 100644
--- a/modular_citadel/code/modules/mob/dead/new_player/sprite_accessories.dm
+++ b/modular_citadel/code/modules/mob/dead/new_player/sprite_accessories.dm
@@ -7,12 +7,6 @@
var/extra2_color_src = MUTCOLORS3
var/list/ckeys_allowed
-/* tbi eventually idk
-/datum/sprite_accessory/legs/digitigrade_mam
- name = "Anthro Digitigrade Legs"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-*/
-
/datum/sprite_accessory/moth_wings/none
name = "None"
icon_state = "none"
@@ -29,14 +23,146 @@
name = "None"
icon_state = "None"
+
+/datum/sprite_accessory/tails/lizard/axolotl
+ name = "Axolotl"
+ icon_state = "axolotl"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/lizard/axolotl
+ name = "Axolotl"
+ icon_state = "axolotl"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/************* Lizard compatable snoots ************/
+/datum/sprite_accessory/snouts/bird
+ name = "Beak"
+ icon_state = "bird"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/bigbeak
+ name = "Big Beak"
+ icon_state = "bigbeak"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/bug
+ name = "Bug"
+ icon_state = "bug"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ extra2 = TRUE
+ extra2_color_src = MUTCOLORS3
+
+/datum/sprite_accessory/snouts/elephant
+ name = "Elephant"
+ icon_state = "elephant"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+ extra = TRUE
+ extra_color_src = MUTCOLORS3
+
+/datum/sprite_accessory/snouts/lcanid
+ name = "Mammal, Long"
+ icon_state = "lcanid"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/lcanidalt
+ name = "Mammal, Long ALT"
+ icon_state = "lcanidalt"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/scanid
+ name = "Mammal, Short"
+ icon_state = "scanid"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/scanidalt
+ name = "Mammal, Short ALT"
+ icon_state = "scanidalt"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/wolf
+ name = "Mammal, Thick"
+ icon_state = "wolf"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/wolfalt
+ name = "Mammal, Thick ALT"
+ icon_state = "wolfalt"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/redpanda
+ name = "WahCoon"
+ icon_state = "wah"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/rhino
+ name = "Horn"
+ icon_state = "rhino"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+ extra = TRUE
+ extra = MUTCOLORS3
+
+/datum/sprite_accessory/snouts/rodent
+ name = "Rodent"
+ icon_state = "rodent"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/husky
+ name = "Husky"
+ icon_state = "husky"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/otie
+ name = "Otie"
+ icon_state = "otie"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/pede
+ name = "Scolipede"
+ icon_state = "pede"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/sergal
+ name = "Sergal"
+ icon_state = "sergal"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/shark
+ name = "Shark"
+ icon_state = "shark"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+
+/datum/sprite_accessory/snouts/toucan
+ name = "Toucan"
+ icon_state = "toucan"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
/******************************************
************ Human Ears/Tails *************
*******************************************/
/datum/sprite_accessory/tails/human/ailurus
name = "Red Panda"
- icon_state = "ailurus"
- color_src = 0
+ icon_state = "wah"
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/ears/human/axolotl
@@ -49,7 +175,7 @@
icon_state = "axolotl"
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-/datum/sprite_accessory/tails_animated/axolotl
+/datum/sprite_accessory/tails_animated/human/axolotl
name = "Axolotl"
icon_state = "axolotl"
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
@@ -58,6 +184,7 @@
name = "Bear"
icon_state = "bear"
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
/datum/sprite_accessory/tails/human/bear
name = "Bear"
@@ -83,7 +210,7 @@
name = "Cow"
icon_state = "cow"
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- gender_specific = 1
+ color_src = MATRIXED
/datum/sprite_accessory/tails/human/cow
name = "Cow"
@@ -105,6 +232,7 @@
name = "Eevee"
icon_state = "eevee"
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
/datum/sprite_accessory/tails/human/eevee
name = "Eevee"
@@ -120,12 +248,13 @@
name = "Elephant"
icon_state = "elephant"
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
/datum/sprite_accessory/ears/fennec
name = "Fennec"
icon_state = "fennec"
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- hasinner = 1
+ color_src = MATRIXED
/datum/sprite_accessory/tails/human/fennec
name = "Fennec"
@@ -141,39 +270,33 @@
name = "Fish"
icon_state = "fish"
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- color_src = MUTCOLORS3
+ color_src = MATRIXED
/datum/sprite_accessory/tails/human/fish
name = "Fish"
icon_state = "fish"
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- extra = TRUE
- extra_color_src = MUTCOLORS3
/datum/sprite_accessory/tails_animated/human/fish
name = "Fish"
icon_state = "fish"
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- extra = TRUE
- extra_color_src = MUTCOLORS3
/datum/sprite_accessory/ears/fox
name = "Fox"
icon_state = "fox"
- hasinner = 1
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
/datum/sprite_accessory/tails/human/fox
name = "Fox"
icon_state = "fox"
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- extra = TRUE
/datum/sprite_accessory/tails_animated/human/fox
name = "Fox"
icon_state = "fox"
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- extra = TRUE
/datum/sprite_accessory/tails/human/horse
name = "Horse"
@@ -191,15 +314,13 @@
name = "Husky"
icon_state = "husky"
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- extra = TRUE
/datum/sprite_accessory/tails_animated/human/husky
name = "Husky"
icon_state = "husky"
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- extra = TRUE
- /datum/sprite_accessory/tails/human/insect
+/datum/sprite_accessory/tails/human/insect
name = "Insect"
icon_state = "insect"
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
@@ -217,188 +338,199 @@
/datum/sprite_accessory/tails/human/kitsune
name = "Kitsune"
icon_state = "kitsune"
- extra = TRUE
- extra_color_src = MUTCOLORS2
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails_animated/human/kitsune
name = "Kitsune"
icon_state = "kitsune"
- extra = TRUE
- extra_color_src = MUTCOLORS2
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/ears/lab
name = "Dog, Floppy"
icon_state = "lab"
- hasinner = 0
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
/datum/sprite_accessory/ears/murid
name = "Murid"
icon_state = "murid"
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
/datum/sprite_accessory/tails/human/murid
name = "Murid"
icon_state = "murid"
- color_src = 0
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails_animated/human/murid
name = "Murid"
icon_state = "murid"
- color_src = 0
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/ears/human/otie
name = "Otusian"
icon_state = "otie"
- hasinner= 1
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
/datum/sprite_accessory/tails/human/otie
name = "Otusian"
icon_state = "otie"
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails_animated/human/otie
name = "Otusian"
icon_state = "otie"
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails/orca
name = "Orca"
icon_state = "orca"
- extra = TRUE
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails_animated/orca
name = "Orca"
icon_state = "orca"
- extra = TRUE
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/ears/human/pede
name = "Scolipede"
icon_state = "pede"
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- color_src = MUTCOLORS2
- extra_color_src = MUTCOLORS3
+ color_src = MATRIXED
/datum/sprite_accessory/tails/human/pede
name = "Scolipede"
icon_state = "pede"
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails_animated/human/pede
name = "Scolipede"
icon_state = "pede"
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/ears/human/rabbit
name = "Rabbit"
icon_state = "rabbit"
- hasinner= 1
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
/datum/sprite_accessory/tails/human/rabbit
name = "Rabbit"
icon_state = "rabbit"
- color_src = 0
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails_animated/human/rabbit
name = "Rabbit"
icon_state = "rabbit"
- color_src = 0
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/ears/human/sergal
name = "Sergal"
icon_state = "sergal"
- hasinner= 1
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
/datum/sprite_accessory/tails/human/sergal
name = "Sergal"
icon_state = "sergal"
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails_animated/human/sergal
name = "Sergal"
icon_state = "sergal"
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/ears/human/skunk
name = "skunk"
icon_state = "skunk"
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
/datum/sprite_accessory/tails/human/skunk
name = "skunk"
icon_state = "skunk"
- color_src = 0
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails_animated/human/skunk
name = "skunk"
icon_state = "skunk"
- color_src = 0
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails/human/shark
name = "Shark"
icon_state = "shark"
- color_src = MUTCOLORS
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails/human/shark/datashark
name = "datashark"
icon_state = "datashark"
- color_src = 0
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/ears/squirrel
name = "Squirrel"
icon_state = "squirrel"
- hasinner= 1
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
/datum/sprite_accessory/tails/human/squirrel
name = "Squirrel"
icon_state = "squirrel"
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails_animated/human/squirrel
name = "Squirrel"
icon_state = "squirrel"
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails/human/yentacle
name = "Tentacle"
icon_state = "tentacle"
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails_animated/human/tentacle
name = "Tentacle"
icon_state = "tentacle"
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/ears/wolf
name = "Wolf"
icon_state = "wolf"
- hasinner = 1
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
/datum/sprite_accessory/tails/human/wolf
name = "Wolf"
icon_state = "wolf"
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails_animated/human/wolf
name = "Wolf"
icon_state = "wolf"
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/******************************************
@@ -406,126 +538,253 @@
*******************************************/
/datum/sprite_accessory/mam_ears
- extra = TRUE
- extra2 = TRUE
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- extra_icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- extra2_icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
/datum/sprite_accessory/mam_ears/none
name = "None"
icon_state = "none"
/datum/sprite_accessory/mam_tails
- extra = TRUE
- extra2 = TRUE
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- extra_icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- extra2_icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/mam_tails/none
name = "None"
icon_state = "none"
/datum/sprite_accessory/mam_tails_animated
- extra = TRUE
- extra2 = TRUE
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- extra_icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- extra2_icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/mam_tails_animated/none
name = "None"
icon_state = "none"
+ color_src = MATRIXED
-/datum/sprite_accessory/snouts
+/datum/sprite_accessory/mam_snouts
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
-/datum/sprite_accessory/snouts/none
+/datum/sprite_accessory/mam_snouts/none
name = "None"
icon_state = "none"
- extra_icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- extra2_icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
/******************************************
**************** Snouts *******************
*******************************************/
-/datum/sprite_accessory/snouts/bird
+/datum/sprite_accessory/mam_snouts/bird
name = "Beak"
icon_state = "bird"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- color_src = MUTCOLORS3
-/datum/sprite_accessory/snouts/bigbeak
+/datum/sprite_accessory/mam_snouts/bigbeak
name = "Big Beak"
icon_state = "bigbeak"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- color_src = MUTCOLORS3
-/datum/sprite_accessory/snouts/elephant
+/datum/sprite_accessory/mam_snouts/bug
+ name = "Bug"
+ icon_state = "bug"
+ color_src = MUTCOLORS
+ extra2 = TRUE
+ extra2_color_src = MUTCOLORS3
+
+/datum/sprite_accessory/mam_snouts/elephant
name = "Elephant"
icon_state = "elephant"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
extra = TRUE
extra_color_src = MUTCOLORS3
-/datum/sprite_accessory/snouts/lcanid
- name = "Fox, Long"
+/datum/sprite_accessory/mam_snouts/lcanid
+ name = "Mammal, Long"
icon_state = "lcanid"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- extra = TRUE
-/datum/sprite_accessory/snouts/scanid
- name = "Fox, Short"
+/datum/sprite_accessory/mam_snouts/lcanidalt
+ name = "Mammal, Long ALT"
+ icon_state = "lcanidalt"
+
+/datum/sprite_accessory/mam_snouts/scanid
+ name = "Mammal, Short"
icon_state = "scanid"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- extra = TRUE
-/datum/sprite_accessory/snouts/wolf
- name = "Wolf"
+/datum/sprite_accessory/mam_snouts/scanidalt
+ name = "Mammal, Short ALT"
+ icon_state = "scanidalt"
+
+/datum/sprite_accessory/mam_snouts/wolf
+ name = "Mammal, Thick"
icon_state = "wolf"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- extra = TRUE
-/datum/sprite_accessory/snouts/rhino
+/datum/sprite_accessory/mam_snouts/wolfalt
+ name = "Mammal, Thick ALT"
+ icon_state = "wolfalt"
+
+/datum/sprite_accessory/mam_snouts/redpanda
+ name = "WahCoon"
+ icon_state = "wah"
+
+/datum/sprite_accessory/mam_snouts/rhino
name = "Horn"
icon_state = "rhino"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
extra = TRUE
extra = MUTCOLORS3
-/datum/sprite_accessory/snouts/husky
+/datum/sprite_accessory/mam_snouts/rodent
+ name = "Rodent"
+ icon_state = "rodent"
+
+/datum/sprite_accessory/mam_snouts/husky
name = "Husky"
icon_state = "husky"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- extra = TRUE
-/datum/sprite_accessory/snouts/otie
+/datum/sprite_accessory/mam_snouts/otie
name = "Otie"
icon_state = "otie"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- extra = TRUE
-/datum/sprite_accessory/snouts/pede
+/datum/sprite_accessory/mam_snouts/pede
name = "Scolipede"
icon_state = "pede"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- extra = TRUE
- color_src = MUTCOLORS
- extra_color_src = MUTCOLORS2
-/datum/sprite_accessory/snouts/sergal
+/datum/sprite_accessory/mam_snouts/sergal
name = "Sergal"
icon_state = "sergal"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- color_src = MUTCOLORS2
-/datum/sprite_accessory/snouts/toucan
+/datum/sprite_accessory/mam_snouts/shark
+ name = "Shark"
+ icon_state = "shark"
+
+/datum/sprite_accessory/mam_snouts/toucan
name = "Toucan"
icon_state = "toucan"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- color_src = MUTCOLORS3
+
+/datum/sprite_accessory/mam_snouts/sharp
+ name = "Sharp"
+ icon_state = "sharp"
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/mam_snouts/round
+ name = "Round"
+ icon_state = "round"
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/mam_snouts/sharplight
+ name = "Sharp + Light"
+ icon_state = "sharplight"
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/mam_snouts/roundlight
+ name = "Round + Light"
+ icon_state = "roundlight"
+ color_src = MUTCOLORS
+
+
+/******************************************
+**************** Snouts *******************
+*************but higher up*****************/
+
+/datum/sprite_accessory/mam_snouts/fbird
+ name = "Beak (Top)"
+ icon_state = "fbird"
+
+/datum/sprite_accessory/mam_snouts/fbigbeak
+ name = "Big Beak (Top)"
+ icon_state = "fbigbeak"
+
+/datum/sprite_accessory/mam_snouts/fbug
+ name = "Bug (Top)"
+ icon_state = "fbug"
+ color_src = MUTCOLORS
+ extra2 = TRUE
+ extra2_color_src = MUTCOLORS3
+
+/datum/sprite_accessory/mam_snouts/felephant
+ name = "Elephant (Top)"
+ icon_state = "felephant"
+ extra = TRUE
+ extra_color_src = MUTCOLORS3
+
+/datum/sprite_accessory/mam_snouts/flcanid
+ name = "Mammal, Long (Top)"
+ icon_state = "flcanid"
+
+/datum/sprite_accessory/mam_snouts/flcanidalt
+ name = "Mammal, Long ALT (Top)"
+ icon_state = "flcanidalt"
+
+/datum/sprite_accessory/mam_snouts/fscanid
+ name = "Mammal, Short (Top)"
+ icon_state = "fscanid"
+
+/datum/sprite_accessory/mam_snouts/fscanidalt
+ name = "Mammal, Short ALT (Top)"
+ icon_state = "fscanidalt"
+
+/datum/sprite_accessory/mam_snouts/fwolf
+ name = "Mammal, Thick (Top)"
+ icon_state = "fwolf"
+
+/datum/sprite_accessory/mam_snouts/fwolfalt
+ name = "Mammal, Thick ALT (Top)"
+ icon_state = "fwolfalt"
+
+/datum/sprite_accessory/mam_snouts/fredpanda
+ name = "WahCoon (Top)"
+ icon_state = "fwah"
+
+/datum/sprite_accessory/mam_snouts/frhino
+ name = "Horn (Top)"
+ icon_state = "frhino"
+ extra = TRUE
+ extra = MUTCOLORS3
+
+/datum/sprite_accessory/mam_snouts/frodent
+ name = "Rodent (Top)"
+ icon_state = "frodent"
+
+/datum/sprite_accessory/mam_snouts/fhusky
+ name = "Husky (Top)"
+ icon_state = "fhusky"
+
+/datum/sprite_accessory/mam_snouts/fotie
+ name = "Otie (Top)"
+ icon_state = "fotie"
+
+/datum/sprite_accessory/mam_snouts/fpede
+ name = "Scolipede (Top)"
+ icon_state = "fpede"
+
+/datum/sprite_accessory/mam_snouts/fsergal
+ name = "Sergal (Top)"
+ icon_state = "fsergal"
+
+/datum/sprite_accessory/mam_snouts/fshark
+ name = "Shark (Top)"
+ icon_state = "fshark"
+
+/datum/sprite_accessory/mam_snouts/ftoucan
+ name = "Toucan (Top)"
+ icon_state = "ftoucan"
+
+/datum/sprite_accessory/mam_snouts/fsharp
+ name = "Sharp (Top)"
+ icon_state = "fsharp"
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/mam_snouts/fround
+ name = "Round (Top)"
+ icon_state = "fround"
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/mam_snouts/fsharplight
+ name = "Sharp + Light (Top)"
+ icon_state = "fsharplight"
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/mam_snouts/froundlight
+ name = "Round + Light (Top)"
+ icon_state = "froundlight"
+ color_src = MUTCOLORS
/******************************************
***************** Ears ********************
@@ -539,18 +798,47 @@
name = "Bear"
icon_state = "bear"
+/datum/sprite_accessory/mam_ears/bigwolf
+ name = "Big Wolf"
+ icon_state = "bigwolf"
+
+/datum/sprite_accessory/mam_ears/bigwolfinner
+ name = "Big Wolf (ALT)"
+ icon_state = "bigwolfinner"
+ hasinner = 1
+
+/datum/sprite_accessory/mam_ears/bigwolfdark
+ name = "Dark Big Wolf"
+ icon_state = "bigwolfdark"
+
+/datum/sprite_accessory/mam_ears/bigwolfinnerdark
+ name = "Dark Big Wolf (ALT)"
+ icon_state = "bigwolfinnerdark"
+ hasinner = 1
+
+/datum/sprite_accessory/mam_ears/cat
+ name = "Cat"
+ icon_state = "cat"
+ hasinner = 1
+ color_src = HAIR
+
/datum/sprite_accessory/mam_ears/catbig
name = "Cat, Big"
icon_state = "catbig"
- hasinner = 1
/datum/sprite_accessory/mam_ears/cow
name = "Cow"
icon_state = "cow"
+/datum/sprite_accessory/mam_ears/curled
+ name = "Curled Horn"
+ icon_state = "horn1"
+ color_src = MUTCOLORS3
+
/datum/sprite_accessory/mam_ears/deer
name = "Deer"
icon_state = "deer"
+ color_src = MUTCOLORS3
/datum/sprite_accessory/mam_ears/eevee
name = "Eevee"
@@ -563,17 +851,14 @@
/datum/sprite_accessory/mam_ears/fennec
name = "Fennec"
icon_state = "fennec"
- hasinner = 1
/datum/sprite_accessory/mam_ears/fish
name = "Fish"
icon_state = "fish"
- color_src = MUTCOLORS3
/datum/sprite_accessory/mam_ears/fox
name = "Fox"
icon_state = "fox"
- hasinner = 1
/datum/sprite_accessory/mam_ears/husky
name = "Husky"
@@ -583,6 +868,11 @@
name = "kangaroo"
icon_state = "kangaroo"
+/datum/sprite_accessory/mam_ears/jellyfish
+ name = "Jellyfish"
+ icon_state = "jellyfish"
+ color_src = HAIR
+
/datum/sprite_accessory/mam_ears/lab
name = "Dog, Long"
icon_state = "lab"
@@ -591,37 +881,25 @@
name = "Murid"
icon_state = "murid"
-/datum/sprite_accessory/mam_ears/neko
- name = "Neko"
- icon_state = "cat"
- hasinner = 1
- color_src = HAIR
-
/datum/sprite_accessory/mam_ears/otie
name = "Otusian"
icon_state = "otie"
- hasinner= 1
/datum/sprite_accessory/mam_ears/squirrel
name = "Squirrel"
icon_state = "squirrel"
- hasinner= 1
/datum/sprite_accessory/mam_ears/pede
name = "Scolipede"
icon_state = "pede"
- color_src = MUTCOLORS2
- extra_color_src = MUTCOLORS3
/datum/sprite_accessory/mam_ears/rabbit
name = "Rabbit"
icon_state = "rabbit"
- hasinner= 1
/datum/sprite_accessory/mam_ears/sergal
name = "Sergal"
icon_state = "sergal"
- hasinner= 1
/datum/sprite_accessory/mam_ears/skunk
name = "skunk"
@@ -630,20 +908,19 @@
/datum/sprite_accessory/mam_ears/wolf
name = "Wolf"
icon_state = "wolf"
- hasinner = 1
/******************************************
*********** Tails and Things **************
*******************************************/
/datum/sprite_accessory/mam_tails/ailurus
- name = "Ailurus"
- icon_state = "ailurus"
+ name = "Red Panda"
+ icon_state = "wah"
extra = TRUE
/datum/sprite_accessory/mam_tails_animated/ailurus
- name = "Ailurus"
- icon_state = "ailurus"
+ name = "Red Panda"
+ icon_state = "wah"
extra = TRUE
/datum/sprite_accessory/mam_tails/axolotl
@@ -662,6 +939,16 @@
name = "Bear"
icon_state = "bear"
+/datum/sprite_accessory/mam_tails/cat
+ name = "Cat"
+ icon_state = "cat"
+ color_src = HAIR
+
+/datum/sprite_accessory/mam_tails_animated/cat
+ name = "Cat"
+ icon_state = "cat"
+ color_src = HAIR
+
/datum/sprite_accessory/mam_tails/catbig
name = "Cat, Big"
icon_state = "catbig"
@@ -670,6 +957,14 @@
name = "Cat, Big"
icon_state = "catbig"
+/datum/sprite_accessory/mam_tails/corvid
+ name = "Corvid"
+ icon_state = "crow"
+
+/datum/sprite_accessory/mam_tails_animated/corvid
+ name = "Corvid"
+ icon_state = "crow"
+
/datum/sprite_accessory/mam_tail/cow
name = "Cow"
icon_state = "cow"
@@ -678,19 +973,13 @@
name = "Cow"
icon_state = "cow"
-/datum/sprite_accessory/mam_ears/curled
- name = "Curled Horn"
- icon_state = "horn1"
-
/datum/sprite_accessory/mam_tails/eevee
name = "Eevee"
icon_state = "eevee"
- extra = TRUE
/datum/sprite_accessory/mam_tails_animated/eevee
name = "Eevee"
icon_state = "eevee"
- extra = TRUE
/datum/sprite_accessory/mam_tails/fennec
name = "Fennec"
@@ -703,24 +992,18 @@
/datum/sprite_accessory/mam_tails/human/fish
name = "Fish"
icon_state = "fish"
- extra = TRUE
- extra_color_src = MUTCOLORS3
/datum/sprite_accessory/mam_tails_animated/human/fish
name = "Fish"
icon_state = "fish"
- extra = TRUE
- extra_color_src = MUTCOLORS3
/datum/sprite_accessory/mam_tails/fox
name = "Fox"
icon_state = "fox"
- extra = TRUE
/datum/sprite_accessory/mam_tails_animated/fox
name = "Fox"
icon_state = "fox"
- extra = TRUE
/datum/sprite_accessory/mam_tails/hawk
name = "Hawk"
@@ -743,12 +1026,10 @@
/datum/sprite_accessory/mam_tails/husky
name = "Husky"
icon_state = "husky"
- extra = TRUE
/datum/sprite_accessory/mam_tails_animated/husky
name = "Husky"
icon_state = "husky"
- extra = TRUE
datum/sprite_accessory/mam_tails/insect
name = "Insect"
@@ -766,20 +1047,13 @@ datum/sprite_accessory/mam_tails/insect
name = "kangaroo"
icon_state = "kangaroo"
-/datum/sprite_accessory/mam_ears/jellyfish
- name = "Jellyfish"
- icon_state = "jellyfish"
- color_src = HAIR
-
/datum/sprite_accessory/mam_tails/kitsune
name = "Kitsune"
icon_state = "kitsune"
- extra = TRUE
/datum/sprite_accessory/mam_tails_animated/kitsune
name = "Kitsune"
icon_state = "kitsune"
- extra = TRUE
/datum/sprite_accessory/mam_tails/lab
name = "Lab"
@@ -792,22 +1066,10 @@ datum/sprite_accessory/mam_tails/insect
/datum/sprite_accessory/mam_tails/murid
name = "Murid"
icon_state = "murid"
- color_src = 0
/datum/sprite_accessory/mam_tails_animated/murid
name = "Murid"
icon_state = "murid"
- color_src = 0
-
-/datum/sprite_accessory/mam_tails/neko
- name = "Neko"
- icon_state = "cat"
- color_src = HAIR
-
-/datum/sprite_accessory/mam_tails_animated/neko
- name = "Neko"
- icon_state = "cat"
- color_src = HAIR
/datum/sprite_accessory/mam_tails/otie
name = "Otusian"
@@ -820,12 +1082,10 @@ datum/sprite_accessory/mam_tails/insect
/datum/sprite_accessory/mam_tails/orca
name = "Orca"
icon_state = "orca"
- extra = TRUE
/datum/sprite_accessory/mam_tails_animated/orca
name = "Orca"
icon_state = "orca"
- extra = TRUE
/datum/sprite_accessory/mam_tails/pede
name = "Scolipede"
@@ -852,38 +1112,36 @@ datum/sprite_accessory/mam_tails/insect
icon_state = "sergal"
/datum/sprite_accessory/mam_tails/skunk
- name = "skunk"
+ name = "Skunk"
icon_state = "skunk"
- color_src = 0
- extra = TRUE
/datum/sprite_accessory/mam_tails_animated/skunk
- name = "skunk"
+ name = "Skunk"
icon_state = "skunk"
- color_src = 0
- extra = TRUE
/datum/sprite_accessory/mam_tails/shark
name = "Shark"
icon_state = "shark"
- color_src = MUTCOLORS
/datum/sprite_accessory/mam_tails_animated/shark
name = "Shark"
icon_state = "shark"
- color_src = MUTCOLORS
/datum/sprite_accessory/mam_tails/shepherd
name = "Shepherd"
icon_state = "shepherd"
- extra = TRUE
- extra2 = TRUE
/datum/sprite_accessory/mam_tails_animated/shepherd
name = "Shepherd"
icon_state = "shepherd"
- extra = TRUE
- extra2 = TRUE
+
+/datum/sprite_accessory/mam_tails/straighttail
+ name = "Straight Tail"
+ icon_state = "straighttail"
+
+/datum/sprite_accessory/mam_tails_animated/straighttail
+ name = "Straight Tail"
+ icon_state = "straighttail"
/datum/sprite_accessory/mam_tails/squirrel
name = "Squirrel"
@@ -893,7 +1151,7 @@ datum/sprite_accessory/mam_tails/insect
name = "Squirrel"
icon_state = "squirrel"
-datum/sprite_accessory/mam_tails/tentacle
+/datum/sprite_accessory/mam_tails/tentacle
name = "Tentacle"
icon_state = "tentacle"
@@ -901,6 +1159,14 @@ datum/sprite_accessory/mam_tails/tentacle
name = "Tentacle"
icon_state = "tentacle"
+/datum/sprite_accessory/mam_tails/tiger
+ name = "Tiger"
+ icon_state = "tiger"
+
+/datum/sprite_accessory/mam_tails_animated/tiger
+ name = "Tiger"
+ icon_state = "tiger"
+
/datum/sprite_accessory/mam_tails/wolf
name = "Wolf"
icon_state = "wolf"
@@ -914,150 +1180,172 @@ datum/sprite_accessory/mam_tails/tentacle
*******************************************/
/datum/sprite_accessory/mam_body_markings
- extra = TRUE
- extra2 = TRUE
- icon = 'modular_citadel/icons/mob/mam_body_markings.dmi'
+ extra = FALSE
+ extra2 = FALSE
+ color_src = MATRIXED
+ gender_specific = 0
+ icon = 'modular_citadel/icons/mob/mam_markings.dmi'
/datum/sprite_accessory/mam_body_markings/none
name = "None"
icon_state = "none"
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/mam_body_markings/plain
+ name = "Plain"
+ icon_state = "plain"
/datum/sprite_accessory/mam_body_markings/ailurus
- name = "Red Panda"
- icon_state = "ailurus"
- gender_specific = 1
-
-/datum/sprite_accessory/mam_body_markings/belly
- name = "Bee"
- icon_state = "bee"
- color_src = MUTCOLORS3
- gender_specific = 1
+ name = "Redpanda"
+ icon_state = "wah"
/datum/sprite_accessory/mam_body_markings/bee
+ name = "Bee"
+ icon_state = "bee"
+
+/datum/sprite_accessory/mam_body_markings/belly
name = "Belly"
icon_state = "belly"
- gender_specific = 1
+
+/datum/sprite_accessory/mam_body_markings/bellyslim
+ name = "Bellyslim"
+ icon_state = "bellyslim"
/datum/sprite_accessory/mam_body_markings/corgi
name = "Corgi"
icon_state = "corgi"
- color_src = MUTCOLORS2
- extra_color_src = MUTCOLORS3
- gender_specific = 1
/datum/sprite_accessory/mam_body_markings/cow
- name = "Cow"
- icon_state = "cow"
- color_src = MUTCOLORS2
- extra_color_src = MUTCOLORS3
- gender_specific = 1
+ name = "Bovine"
+ icon_state = "bovine"
/datum/sprite_accessory/mam_body_markings/corvid
- name = "Crow"
+ name = "Corvid"
icon_state = "corvid"
- gender_specific = 1
+
+/datum/sprite_accessory/mam_body_markings/dalmation
+ name = "Dalmation"
+ icon_state = "dalmation"
/datum/sprite_accessory/mam_body_markings/deer
name = "Deer"
icon_state = "deer"
- color_src = MUTCOLORS2
- extra_color_src = MUTCOLORS3
- gender_specific = 1
+
+/datum/sprite_accessory/mam_body_markings/dog
+ name = "Dog"
+ icon_state = "dog"
/datum/sprite_accessory/mam_body_markings/eevee
name = "Eevee"
icon_state = "eevee"
- color_src = MUTCOLORS3
+
+/datum/sprite_accessory/mam_body_markings/hippo
+ name = "Hippo"
+ icon_state = "hippo"
/datum/sprite_accessory/mam_body_markings/fennec
name = "Fennec"
icon_state = "Fennec"
- gender_specific = 1
/datum/sprite_accessory/mam_body_markings/fox
name = "Fox"
icon_state = "fox"
- gender_specific = 1
/datum/sprite_accessory/mam_body_markings/frog
name = "Frog"
icon_state = "frog"
- gender_specific = 1
- color_src = MUTCOLORS2
+
+/datum/sprite_accessory/mam_body_markings/goat
+ name = "Goat"
+ icon_state = "goat"
+
+/datum/sprite_accessory/mam_body_markings/handsfeet
+ name = "Handsfeet"
+ icon_state = "handsfeet"
/datum/sprite_accessory/mam_body_markings/hawk
name = "Hawk"
icon_state = "hawk"
- gender_specific = 1
/datum/sprite_accessory/mam_body_markings/husky
name = "Husky"
icon_state = "husky"
- gender_specific = 1
+
+/datum/sprite_accessory/mam_body_markings/hyena
+ name = "Hyena"
+ icon_state = "hyena"
+
+/datum/sprite_accessory/mam_body_markings/lab
+ name = "Lab"
+ icon_state = "lab"
/datum/sprite_accessory/mam_body_markings/moth
name = "Moth"
icon_state = "moth"
- color_src = MUTCOLORS2
- extra_color_src = MUTCOLORS3
- gender_specific = 1
/datum/sprite_accessory/mam_body_markings/otie
name = "Otie"
icon_state = "otie"
- gender_specific = 1
+
+/datum/sprite_accessory/mam_body_markings/otter
+ name = "Otter"
+ icon_state = "otter"
/datum/sprite_accessory/mam_body_markings/orca
name = "Orca"
icon_state = "orca"
- color_src = MUTCOLORS2
- gender_specific = 1
+
+/datum/sprite_accessory/mam_body_markings/panther
+ name = "Panther"
+ icon_state = "panther"
+
+/datum/sprite_accessory/mam_body_markings/possum
+ name = "Possum"
+ icon_state = "possum"
+
+/datum/sprite_accessory/mam_body_markings/raccoon
+ name = "Raccoon"
+ icon_state = "raccoon"
/datum/sprite_accessory/mam_body_markings/pede
name = "Scolipede"
- icon_state = "pede"
- extra = TRUE
- extra_color_src = MUTCOLORS3
- color_src = MUTCOLORS2
- gender_specific = 1
+ icon_state = "scolipede"
/datum/sprite_accessory/mam_body_markings/shark
name = "Shark"
icon_state = "shark"
- color_src = MUTCOLORS2
- extra_color_src = MUTCOLORS3
- gender_specific = 1
+
+/datum/sprite_accessory/mam_body_markings/skunk
+ name = "Skunk"
+ icon_state = "skunk"
+
+/datum/sprite_accessory/mam_body_markings/sergal
+ name = "Sergal"
+ icon_state = "sergal"
/datum/sprite_accessory/mam_body_markings/shepherd
name = "Shepherd"
icon_state = "shepherd"
- gender_specific = 1
+
+/datum/sprite_accessory/mam_body_markings/tajaran
+ name = "Tajaran"
+ icon_state = "tajaran"
/datum/sprite_accessory/mam_body_markings/tiger
- name = "Tiger Stripes"
- color_src = MUTCOLORS3
+ name = "Tiger"
icon_state = "tiger"
/datum/sprite_accessory/mam_body_markings/turian
name = "Turian"
- extra = TRUE
- color_src = MUTCOLORS
- extra_color_src = MUTCOLORS2
icon_state = "turian"
- gender_specific = 1
/datum/sprite_accessory/mam_body_markings/wolf
name = "Wolf"
icon_state = "wolf"
- color_src = MUTCOLORS2
- gender_specific = 1
/datum/sprite_accessory/mam_body_markings/xeno
name = "Xeno"
icon_state = "xeno"
- color_src = MUTCOLORS2
- extra_color_src = MUTCOLORS3
- gender_specific = 1
/******************************************
@@ -1072,6 +1360,7 @@ datum/sprite_accessory/mam_tails/tentacle
center = TRUE
dimension_x = 64
var/taur_mode = NOT_TAURIC
+ color_src = MATRIXED
/datum/sprite_accessory/taur/none
name = "None"
@@ -1090,11 +1379,13 @@ datum/sprite_accessory/mam_tails/tentacle
/datum/sprite_accessory/taur/drider
name = "Drider"
icon_state = "drider"
+ color_src = MUTCOLORS
/datum/sprite_accessory/taur/eevee
name = "Eevee"
icon_state = "eevee"
taur_mode = PAW_TAURIC
+ color_src = MUTCOLORS
/datum/sprite_accessory/taur/fox
name = "Fox"
@@ -1130,6 +1421,7 @@ datum/sprite_accessory/mam_tails/tentacle
name = "Scolipede"
icon_state = "pede"
taur_mode = PAW_TAURIC
+ color_src = MUTCOLORS
/datum/sprite_accessory/taur/panther
name = "Panther"
@@ -1141,15 +1433,16 @@ datum/sprite_accessory/mam_tails/tentacle
icon_state = "shepherd"
taur_mode = PAW_TAURIC
-/datum/sprite_accessory/taur/tajaran
- name = "Tajaran"
- icon_state = "tajaran"
- taur_mode = PAW_TAURIC
-
/datum/sprite_accessory/taur/tentacle
name = "Tentacle"
icon_state = "tentacle"
taur_mode = SNEK_TAURIC
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/taur/tiger
+ name = "Tiger"
+ icon_state = "tiger"
+ taur_mode = PAW_TAURIC
/datum/sprite_accessory/taur/wolf
name = "Wolf"
@@ -1365,17 +1658,15 @@ datum/sprite_accessory/mam_tails/tentacle
/datum/sprite_accessory/body_markings/guilmon
name = "Guilmon"
icon_state = "guilmon"
- gender_specific = 1
+ color_src = MATRIXED
/datum/sprite_accessory/tails/lizard/guilmon
name = "Guilmon"
icon_state = "guilmon"
- extra = TRUE
/datum/sprite_accessory/tails_animated/lizard/guilmon
name = "Guilmon"
icon_state = "guilmon"
- extra = TRUE
/datum/sprite_accessory/horns/guilmon
name = "Guilmon"
@@ -1385,52 +1676,41 @@ datum/sprite_accessory/mam_tails/tentacle
/datum/sprite_accessory/snout/guilmon
name = "Guilmon"
icon_state = "guilmon"
+ color_src = MATRIXED
/datum/sprite_accessory/mam_tails/shark/datashark
name = "DataShark"
icon_state = "datashark"
- color_src = 0
ckeys_allowed = list("rubyflamewing")
/datum/sprite_accessory/mam_tails_animated/shark/datashark
name = "DataShark"
icon_state = "datashark"
- color_src = 0
/datum/sprite_accessory/mam_body_markings/shark/datashark
name = "DataShark"
icon_state = "datashark"
- color_src = MUTCOLORS2
ckeys_allowed = list("rubyflamewing")
-
//Sabresune
/datum/sprite_accessory/mam_ears/sabresune
name = "sabresune"
icon_state = "sabresune"
- hasinner = 1
- extra = TRUE
- extra_color_src = MUTCOLORS3
ckeys_allowed = list("poojawa")
/datum/sprite_accessory/mam_tails/sabresune
name = "sabresune"
icon_state = "sabresune"
- extra = TRUE
ckeys_allowed = list("poojawa")
/datum/sprite_accessory/mam_tails_animated/sabresune
name = "sabresune"
icon_state = "sabresune"
- extra = TRUE
/datum/sprite_accessory/mam_body_markings/sabresune
name = "Sabresune"
icon_state = "sabresune"
- color_src = MUTCOLORS2
- extra = FALSE
- extra2 = FALSE
ckeys_allowed = list("poojawa")
@@ -1438,21 +1718,16 @@ datum/sprite_accessory/mam_tails/tentacle
/datum/sprite_accessory/mam_ears/lunasune
name = "lunasune"
icon_state = "lunasune"
- hasinner = 1
- extra = TRUE
- extra_color_src = MUTCOLORS2
ckeys_allowed = list("invader4352")
/datum/sprite_accessory/mam_tails/lunasune
name = "lunasune"
icon_state = "lunasune"
- extra = TRUE
ckeys_allowed = list("invader4352")
/datum/sprite_accessory/mam_tails_animated/lunasune
name = "lunasune"
icon_state = "lunasune"
- extra = TRUE
/*************** VIRGO PORTED HAIRS ****************************/
#define VHAIR(_name, new_state) /datum/sprite_accessory/hair/##new_state/icon_state=#new_state;/datum/sprite_accessory/hair/##new_state/name = "Virgo - " + #_name
diff --git a/modular_citadel/code/modules/mob/living/carbon/carbon.dm b/modular_citadel/code/modules/mob/living/carbon/carbon.dm
index cf5ce03bc7..d52cc6eabb 100644
--- a/modular_citadel/code/modules/mob/living/carbon/carbon.dm
+++ b/modular_citadel/code/modules/mob/living/carbon/carbon.dm
@@ -3,6 +3,7 @@
var/lastmousedir
var/wrongdirmovedelay
var/lastdirchange
+ var/combatmessagecooldown
/mob/living/carbon/CanPass(atom/movable/mover, turf/target)
. = ..()
@@ -27,6 +28,9 @@
if(hud_used && hud_used.static_inventory)
for(var/obj/screen/combattoggle/selector in hud_used.static_inventory)
selector.rebasetointerbay(src)
+ if(world.time >= combatmessagecooldown && combatmode)
+ visible_message("[src] [resting ? "tenses up" : (prob(95)? "drops into a combative stance" : (prob(95)? "poses aggressively" : "asserts dominance with their pose"))].")
+ combatmessagecooldown = 10 SECONDS + world.time //This is set 100% of the time to make sure squeezing regen out of process cycles doesn't result in the combat mode message getting spammed
SEND_SIGNAL(src, COMSIG_COMBAT_TOGGLED, src, combatmode)
return TRUE
diff --git a/modular_citadel/code/modules/mob/living/carbon/human/human_movement.dm b/modular_citadel/code/modules/mob/living/carbon/human/human_movement.dm
index 0e59e2cd9f..c4449d33d7 100644
--- a/modular_citadel/code/modules/mob/living/carbon/human/human_movement.dm
+++ b/modular_citadel/code/modules/mob/living/carbon/human/human_movement.dm
@@ -31,3 +31,7 @@
for(var/obj/screen/sprintbutton/selector in hud_used.static_inventory)
selector.insert_witty_toggle_joke_here(src)
return TRUE
+
+/mob/living/carbon/human/proc/sprint_hotkey(targetstatus)
+ if(targetstatus ? !sprinting : sprinting)
+ togglesprint()
diff --git a/modular_citadel/code/modules/mob/living/carbon/human/species.dm b/modular_citadel/code/modules/mob/living/carbon/human/species.dm
index 8d50bf16b0..d468f34653 100644
--- a/modular_citadel/code/modules/mob/living/carbon/human/species.dm
+++ b/modular_citadel/code/modules/mob/living/carbon/human/species.dm
@@ -1,3 +1,6 @@
+/datum/species
+ var/should_draw_citadel = FALSE
+
/datum/species/proc/alt_spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
if(!istype(M))
return TRUE
@@ -13,63 +16,141 @@
H.visible_message("[M] attempted to touch [H]!")
return TRUE
switch(M.a_intent)
- if("disarm")
+ if(INTENT_HELP)
+ if(M == H)
+ althelp(M, H, attacker_style)
+ return TRUE
+ return FALSE
+ if(INTENT_DISARM)
altdisarm(M, H, attacker_style)
return TRUE
return FALSE
+/datum/species/proc/althelp(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
+ if(user == target && istype(user))
+ if(user.getStaminaLoss() >= STAMINA_SOFTCRIT)
+ to_chat(user, "You're too exhausted for that.")
+ return
+ if(!user.resting)
+ to_chat(user, "You can only force yourself up if you're on the ground.")
+ return
+ user.visible_message("[user] forces [p_them()]self up to [p_their()] feet!", "You force yourself up to your feet!")
+ user.resting = 0
+ user.update_canmove()
+ user.adjustStaminaLossBuffered(user.stambuffer) //Rewards good stamina management by making it easier to instantly get up from resting
+ playsound(user, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
+
/datum/species/proc/altdisarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
if(user.getStaminaLoss() >= STAMINA_SOFTCRIT)
to_chat(user, "You're too exhausted.")
return FALSE
- else if(target.check_block())
- target.visible_message("[target] blocks [user]'s disarm attempt!")
- return 0
+ if(target.check_block())
+ target.visible_message("[target] blocks [user]'s shoving attempt!")
+ return FALSE
if(attacker_style && attacker_style.disarm_act(user,target))
- return 1
+ return TRUE
+ if(user.resting)
+ return FALSE
else
+ if(user == target)
+ return
user.do_attack_animation(target, ATTACK_EFFECT_DISARM)
-
- user.adjustStaminaLossBuffered(4) //CITADEL CHANGE - makes disarmspam cause staminaloss
+ user.adjustStaminaLossBuffered(4)
+ playsound(target, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1)
if(target.w_uniform)
target.w_uniform.add_fingerprint(user)
- var/randomized_zone = ran_zone(user.zone_selected)
SEND_SIGNAL(target, COMSIG_HUMAN_DISARM_HIT, user, user.zone_selected)
- var/obj/item/bodypart/affecting = target.get_bodypart(randomized_zone)
- if((!target.combatmode && user.combatmode || prob(target.getStaminaLoss()*(user.resting ? 0.25 : 1)*(user.combatmode ? 1 : 0.05))) && !target.resting) //probability depends on staminaloss. it's plausible, but unlikely that you'll be able to push someone over while resting, and pretty rare to successfully push someone outside of combat mode. The few people that even know how to right-click outside of combat mode are a rarity but let's take that into account regardless.
- playsound(target, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
- target.visible_message("[user] [user.combatmode ? "has" : "gently"] pushed [target]!",
- "[user] has pushed [target]!", null, COMBAT_MESSAGE_RANGE)
- target.apply_effect(40, EFFECT_KNOCKDOWN, target.run_armor_check(affecting, "melee", "Your armor prevents your fall!", "Your armor softens your fall!"))
- target.forcesay(GLOB.hit_appends)
- log_combat(user, target, "disarmed", " pushing them to the ground")
- return
+ if(!target.resting)
+ target.adjustStaminaLoss(5)
+
+
+ var/turf/target_oldturf = target.loc
+ var/shove_dir = get_dir(user.loc, target_oldturf)
+ var/turf/target_shove_turf = get_step(target.loc, shove_dir)
+ var/mob/living/carbon/human/target_collateral_human
+ var/obj/structure/table/target_table
+ var/shove_blocked = FALSE //Used to check if a shove is blocked so that if it is knockdown logic can be applied
+
+ //Thank you based whoneedsspace
+ target_collateral_human = locate(/mob/living/carbon/human) in target_shove_turf.contents
+ if(target_collateral_human)
+ shove_blocked = TRUE
+ else
+ target.Move(target_shove_turf, shove_dir)
+ if(get_turf(target) == target_oldturf)
+ target_table = locate(/obj/structure/table) in target_shove_turf.contents
+ shove_blocked = TRUE
+
+ if(shove_blocked && !target.is_shove_knockdown_blocked())
+ var/directional_blocked = FALSE
+ if(shove_dir in GLOB.cardinals) //Directional checks to make sure that we're not shoving through a windoor or something like that
+ var/target_turf = get_turf(target)
+ for(var/obj/O in target_turf)
+ if(O.flags_1 & ON_BORDER_1 && O.dir == shove_dir && O.density)
+ directional_blocked = TRUE
+ break
+ if(target_turf != target_shove_turf) //Make sure that we don't run the exact same check twice on the same tile
+ for(var/obj/O in target_shove_turf)
+ if(O.flags_1 & ON_BORDER_1 && O.dir == turn(shove_dir, 180) && O.density)
+ directional_blocked = TRUE
+ break
+ var/targetatrest = target.resting
+ if(((!target_table && !target_collateral_human) || directional_blocked) && !targetatrest)
+ target.Knockdown(SHOVE_KNOCKDOWN_SOLID)
+ user.visible_message("[user.name] shoves [target.name], knocking them down!",
+ "You shove [target.name], knocking them down!", null, COMBAT_MESSAGE_RANGE)
+ log_combat(user, target, "shoved", "knocking them down")
+ else if(target_table)
+ if(!targetatrest)
+ target.Knockdown(SHOVE_KNOCKDOWN_TABLE)
+ user.visible_message("[user.name] shoves [target.name] onto \the [target_table]!",
+ "You shove [target.name] onto \the [target_table]!", null, COMBAT_MESSAGE_RANGE)
+ target.forceMove(target_shove_turf)
+ log_combat(user, target, "shoved", "onto [target_table]")
+ else if(target_collateral_human && !targetatrest)
+ target.Knockdown(SHOVE_KNOCKDOWN_HUMAN)
+ if(!target_collateral_human.resting)
+ target_collateral_human.Knockdown(SHOVE_KNOCKDOWN_COLLATERAL)
+ user.visible_message("[user.name] shoves [target.name] into [target_collateral_human.name]!",
+ "You shove [target.name] into [target_collateral_human.name]!", null, COMBAT_MESSAGE_RANGE)
+ log_combat(user, target, "shoved", "into [target_collateral_human.name]")
+
+ else
+ user.visible_message("[user.name] shoves [target.name]!",
+ "You shove [target.name]!", null, COMBAT_MESSAGE_RANGE)
+ var/target_held_item = target.get_active_held_item()
+ var/knocked_item = FALSE
+ if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types))
+ target_held_item = null
+ if(!target.has_movespeed_modifier(SHOVE_SLOWDOWN_ID))
+ target.add_movespeed_modifier(SHOVE_SLOWDOWN_ID, multiplicative_slowdown = SHOVE_SLOWDOWN_STRENGTH)
+ if(target_held_item)
+ target.visible_message("[target.name]'s grip on \the [target_held_item] loosens!",
+ "Your grip on \the [target_held_item] loosens!", null, COMBAT_MESSAGE_RANGE)
+ addtimer(CALLBACK(target, /mob/living/carbon/human/proc/clear_shove_slowdown), SHOVE_SLOWDOWN_LENGTH)
+ else if(target_held_item)
+ target.dropItemToGround(target_held_item)
+ knocked_item = TRUE
+ target.visible_message("[target.name] drops \the [target_held_item]!!",
+ "You drop \the [target_held_item]!!", null, COMBAT_MESSAGE_RANGE)
+ var/append_message = ""
+ if(target_held_item)
+ if(knocked_item)
+ append_message = "causing them to drop [target_held_item]"
+ else
+ append_message = "loosening their grip on [target_held_item]"
+ log_combat(user, target, "shoved", append_message)
- playsound(target, 'sound/weapons/thudswoosh.ogg', 25, 1, -1)
- target.visible_message("[user] [user.combatmode ? "attempted to push" : "tries to gently push"] [target] over!", \
- "[user] [user.combatmode ? "attempted to push" : "tries to gently push"] [target] over!", null, COMBAT_MESSAGE_RANGE)
- if(!target.resting && !user.resting && user.combatmode)
- target.adjustStaminaLoss(rand(1,5)) //This is the absolute most inefficient way to get someone into soft stamcrit, but if you've got a crowd trying to shove you over, you've no option but to get knocked down and accept fate
- log_combat(user, target, "attempted to disarm push")
////////////////////
/////BODYPARTS/////
////////////////////
-/obj/item/bodypart/var/should_draw_citadel = FALSE
-
-/mob/living/carbon/proc/draw_citadel_parts(undo = FALSE)
- if(!undo)
- for(var/O in bodyparts)
- var/obj/item/bodypart/B = O
- B.should_draw_citadel = TRUE
- else
- for(var/O in bodyparts)
- var/obj/item/bodypart/B = O
- B.should_draw_citadel = FALSE
+/obj/item/bodypart
+ var/should_draw_citadel = FALSE
/datum/species/proc/citadel_mutant_bodyparts(bodypart, mob/living/carbon/human/H)
switch(bodypart)
@@ -85,6 +166,8 @@
return GLOB.mam_body_markings_list[H.dna.features["mam_body_markings"]]
if("mam_ears")
return GLOB.mam_ears_list[H.dna.features["mam_ears"]]
+ if("mam_snouts")
+ return GLOB.mam_snouts_list[H.dna.features["mam_snouts"]]
if("taur")
return GLOB.taur_list[H.dna.features["taur"]]
if("xenodorsal")
diff --git a/modular_citadel/code/modules/mob/living/carbon/human/species_types/furrypeople.dm b/modular_citadel/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
index d7124d949c..edc36ae3af 100644
--- a/modular_citadel/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
+++ b/modular_citadel/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
@@ -2,10 +2,11 @@
name = "Mammal"
id = "mammal"
default_color = "4B4B4B"
+ should_draw_citadel = TRUE
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR)
inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID)
- mutant_bodyparts = list("mam_tail", "mam_ears", "mam_body_markings", "snout", "taur", "legs")
- default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "snout" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "mam_body_markings" = "Husky", "taur" = "None", "legs" = "Normal Legs")
+ mutant_bodyparts = list("mam_tail", "mam_ears", "mam_body_markings", "mam_snouts", "taur", "legs")
+ default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "mam_body_markings" = "Husky", "taur" = "None", "legs" = "Normal Legs")
attack_verb = "claw"
attack_sound = 'sound/weapons/slash.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
@@ -45,13 +46,6 @@
/datum/species/mammal/qualifies_for_rank(rank, list/features)
return TRUE
-/datum/species/mammal/on_species_gain(mob/living/carbon/human/C)
- C.draw_citadel_parts()
- . = ..()
-
-/datum/species/mammal/on_species_loss(mob/living/carbon/human/C)
- C.draw_citadel_parts(TRUE)
- . = ..()
//AVIAN//
/datum/species/avian
@@ -59,10 +53,11 @@
id = "avian"
say_mod = "chirps"
default_color = "BCAC9B"
+ should_draw_citadel = TRUE
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR)
inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID)
- mutant_bodyparts = list("snout", "wings", "taur", "mam_tail", "mam_body_markings", "taur")
- default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "snout" = "Beak", "wings" = "None", "taur" = "None", "mam_body_markings" = "Hawk", "mam_tail" = "Hawk")
+ mutant_bodyparts = list("mam_snouts", "wings", "taur", "mam_tail", "mam_body_markings", "taur")
+ default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_snouts" = "Beak", "mam_body_markings" = "Hawk", "wings" = "None", "taur" = "None", "mam_tail" = "Hawk")
attack_verb = "peck"
attack_sound = 'sound/weapons/slash.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
@@ -99,23 +94,16 @@
/datum/species/avian/qualifies_for_rank(rank, list/features)
return TRUE
-/datum/species/avian/on_species_gain(mob/living/carbon/human/C)
- C.draw_citadel_parts()
- . = ..()
-
-/datum/species/avian/on_species_loss(mob/living/carbon/human/C)
- C.draw_citadel_parts(TRUE)
- . = ..()
-
//AQUATIC//
/datum/species/aquatic
name = "Aquatic"
id = "aquatic"
default_color = "BCAC9B"
+ should_draw_citadel = TRUE
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR)
inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID)
- mutant_bodyparts = list("mam_tail", "mam_body_markings", "mam_ears", "taur", "legs")
- default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "Shark", "mam_body_markings" = "Shark", "mam_ears" = "None", "snout" = "Round", "taur" = "None", "legs" = "Normal Legs")
+ mutant_bodyparts = list("mam_tail", "mam_ears","mam_body_markings", "taur", "legs", "mam_snouts")
+ default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "Shark", "mam_ears" = "None", "mam_body_markings" = "Shark", "mam_snouts" = "Round", "taur" = "None", "legs" = "Normal Legs")
attack_verb = "bite"
attack_sound = 'sound/weapons/bite.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
@@ -153,23 +141,16 @@
/datum/species/aquatic/qualifies_for_rank(rank, list/features)
return TRUE
-/datum/species/aquatic/on_species_gain(mob/living/carbon/human/C)
- C.draw_citadel_parts()
- . = ..()
-
-/datum/species/aquatic/on_species_loss(mob/living/carbon/human/C)
- C.draw_citadel_parts(TRUE)
- . = ..()
-
//INSECT//
/datum/species/insect
name = "Insect"
id = "insect"
default_color = "BCAC9B"
+ should_draw_citadel = TRUE
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR)
inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID, MOB_BUG)
- mutant_bodyparts = list("mam_body_markings", "mam_ears", "mam_tail", "taur", "moth_wings")
- default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_body_markings" = "Moth", "mam_tail" = "None", "mam_ears" = "None", "moth_wings" = "Plain", "snout" = "None", "taur" = "None")
+ mutant_bodyparts = list("mam_ears", "mam_body_markings", "mam_tail", "taur", "moth_wings", "mam_snouts")
+ default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "None", "mam_ears" = "None", "moth_wings" = "Plain", "mam_snouts" = "Bug", "mam_body_markings" = "Moth", "taur" = "None")
attack_verb = "flutter" //wat?
attack_sound = 'sound/weapons/slash.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
@@ -206,14 +187,6 @@
/datum/species/insect/qualifies_for_rank(rank, list/features)
return TRUE
-/datum/species/insect/on_species_gain(mob/living/carbon/human/C)
- C.draw_citadel_parts()
- . = ..()
-
-/datum/species/insect/on_species_loss(mob/living/carbon/human/C)
- C.draw_citadel_parts(TRUE)
- . = ..()
-
//Alien//
/datum/species/xeno
// A cloning mistake, crossing human and xenomorph DNA
@@ -221,10 +194,11 @@
id = "xeno"
say_mod = "hisses"
default_color = "00FF00"
+ should_draw_citadel = TRUE
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,DIGITIGRADE)
inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID)
- mutant_bodyparts = list("xenotail", "xenohead", "xenodorsal", "taur", "mam_body_markings")
- default_features = list("xenotail"="Xenomorph Tail","xenohead"="Standard","xenodorsal"="Standard","mcolor" = "0F0","mcolor2" = "0F0","mcolor3" = "0F0","taur" = "None","mam_body_markings" = "Xeno")
+ mutant_bodyparts = list("xenotail", "xenohead", "xenodorsal", "mam_body_markings", "taur")
+ default_features = list("xenotail"="Xenomorph Tail","xenohead"="Standard","xenodorsal"="Standard", "mam_body_markings" = "Xeno","mcolor" = "0F0","mcolor2" = "0F0","mcolor3" = "0F0","taur" = "None")
attack_verb = "slash"
attack_sound = 'sound/weapons/slash.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
@@ -235,7 +209,6 @@
liked_food = MEAT
/datum/species/xeno/on_species_gain(mob/living/carbon/human/C, datum/species/old_species)
- C.draw_citadel_parts()
if(("legs" in C.dna.species.mutant_bodyparts) && C.dna.features["legs"] == "Digitigrade Legs")
species_traits += DIGITIGRADE
if(DIGITIGRADE in species_traits)
@@ -243,7 +216,6 @@
. = ..()
/datum/species/xeno/on_species_loss(mob/living/carbon/human/C, datum/species/new_species)
- C.draw_citadel_parts(TRUE)
if(("legs" in C.dna.species.mutant_bodyparts) && C.dna.features["legs"] == "Normal Legs")
species_traits -= DIGITIGRADE
if(DIGITIGRADE in species_traits)
diff --git a/modular_citadel/code/modules/mob/living/carbon/human/species_types/ipc.dm b/modular_citadel/code/modules/mob/living/carbon/human/species_types/ipc.dm
index 08d9d73f00..bbbe863ec2 100644
--- a/modular_citadel/code/modules/mob/living/carbon/human/species_types/ipc.dm
+++ b/modular_citadel/code/modules/mob/living/carbon/human/species_types/ipc.dm
@@ -3,6 +3,7 @@
id = "ipc"
say_mod = "beeps"
default_color = "00FF00"
+ should_draw_citadel = TRUE
blacklisted = 0
sexes = 0
species_traits = list(MUTCOLORS,NOEYES,NOTRANSSTING)
@@ -16,14 +17,12 @@
var/datum/action/innate/monitor_change/screen
/datum/species/ipc/on_species_gain(mob/living/carbon/human/C)
- C.draw_citadel_parts()
if(isipcperson(C) && !screen)
screen = new
screen.Grant(C)
..()
/datum/species/ipc/on_species_loss(mob/living/carbon/human/C)
- C.draw_citadel_parts(TRUE)
if(screen)
screen.Remove(C)
..()
diff --git a/modular_citadel/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/modular_citadel/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
index 59c4bc5ef1..d188b43083 100644
--- a/modular_citadel/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
+++ b/modular_citadel/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
@@ -6,6 +6,7 @@
/datum/species/jelly/roundstartslime
name = "Slimeperson"
id = "slimeperson"
+ limbs_id = "slime"
default_color = "00FFFF"
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,NOBLOOD)
inherent_traits = list(TRAIT_TOXINLOVER)
@@ -19,14 +20,6 @@
heatmod = 1
burnmod = 1
-/datum/species/jelly/roundstartslime/on_species_gain(mob/living/carbon/human/C)
- C.draw_citadel_parts()
- . = ..()
-
-/datum/species/jelly/roundstartslime/on_species_loss(mob/living/carbon/human/C)
- C.draw_citadel_parts(TRUE)
- . = ..()
-
/datum/action/innate/slime_change
name = "Alter Form"
check_flags = AB_CHECK_CONSCIOUS
diff --git a/modular_citadel/code/modules/mob/living/living.dm b/modular_citadel/code/modules/mob/living/living.dm
index 955263b7af..b07b8ed64b 100644
--- a/modular_citadel/code/modules/mob/living/living.dm
+++ b/modular_citadel/code/modules/mob/living/living.dm
@@ -102,9 +102,9 @@
return FALSE
/mob/living/carbon/update_stamina()
- var/total_health = (min(health*2,100) - getStaminaLoss())
- if(getStaminaLoss())
- if(!recoveringstam && total_health <= STAMINA_CRIT_TRADITIONAL && !stat)
+ var/total_health = getStaminaLoss()
+ if(total_health)
+ if(!recoveringstam && total_health >= STAMINA_CRIT && !stat)
to_chat(src, "You're too exhausted to keep going...")
resting = TRUE
if(combatmode)
@@ -112,7 +112,7 @@
recoveringstam = TRUE
filters += CIT_FILTER_STAMINACRIT
update_canmove()
- if(recoveringstam && total_health >= STAMINA_SOFTCRIT_TRADITIONAL)
+ if(recoveringstam && total_health <= STAMINA_SOFTCRIT)
to_chat(src, "You don't feel nearly as exhausted anymore.")
recoveringstam = FALSE
filters -= CIT_FILTER_STAMINACRIT
diff --git a/modular_citadel/code/modules/mob/living/silicon/robot/robot_modules.dm b/modular_citadel/code/modules/mob/living/silicon/robot/robot_modules.dm
index b6f624709e..a0dbe3a02a 100644
--- a/modular_citadel/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/modular_citadel/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -57,7 +57,25 @@
/obj/item/robot_module/k9/do_transform_animation()
..()
to_chat(loc,"While you have picked the Security K-9 module, you still have to follow your laws, NOT Space Law. \
- For Asimov, this means you must follow criminals' orders unless there is a law 1 reason not to.")
+ For Crewsimov, this means you must follow criminals' orders unless there is a law 1 reason not to.")
+
+/obj/item/robot_module/k9/be_transformed_to(obj/item/robot_module/old_module)
+ var/mob/living/silicon/robot/R = loc
+ var/list/sechoundmodels = list("Default")
+ if(R.client && R.client.ckey in list("nezuli"))
+ sechoundmodels += "Alina"
+ var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in sechoundmodels
+ if(!borg_icon)
+ return FALSE
+ switch(borg_icon)
+ if("Default")
+ cyborg_base_icon = "k9"
+ moduleselect_icon = "k9"
+ if("Alina")
+ cyborg_base_icon = "alina-sec"
+ special_light_key = "alina"
+ sleeper_overlay = "alinasleeper"
+ return ..()
/obj/item/robot_module/medihound
name = "MediHound"
@@ -73,6 +91,7 @@
/obj/item/reagent_containers/borghypo,
/obj/item/twohanded/shockpaddles/cyborg/hound,
/obj/item/stack/medical/gauze/cyborg,
+ /obj/item/pinpointer/crew,
/obj/item/sensor_device)
emag_modules = list(/obj/item/dogborg/pounce)
ratvar_modules = list(/obj/item/clockwork/slab/cyborg/medical,
@@ -88,6 +107,26 @@
dogborg = TRUE
cyborg_pixel_offset = -16
+/obj/item/robot_module/medihound/be_transformed_to(obj/item/robot_module/old_module)
+ var/mob/living/silicon/robot/R = loc
+ var/list/medhoundmodels = list("Default", "Dark")
+ if(R.client && R.client.ckey in list("nezuli"))
+ medhoundmodels += "Alina"
+ var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in medhoundmodels
+ if(!borg_icon)
+ return FALSE
+ switch(borg_icon)
+ if("Default")
+ cyborg_base_icon = "medihound"
+ if("Dark")
+ cyborg_base_icon = "medihounddark"
+ sleeper_overlay = "mdsleeper"
+ if("Alina")
+ cyborg_base_icon = "alina-med"
+ special_light_key = "alina"
+ sleeper_overlay = "alinasleeper"
+ return ..()
+
/obj/item/robot_module/scrubpup
name = "Scrub Pup"
basic_modules = list(
@@ -183,7 +222,7 @@
/obj/item/robot_module/medical/be_transformed_to(obj/item/robot_module/old_module)
var/mob/living/silicon/robot/R = loc
- var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Default", "Droid", "Eyebot")
+ var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Default", "Heavy", "Sleek", "Marina", "Droid", "Eyebot")
if(!borg_icon)
return FALSE
switch(borg_icon)
@@ -193,15 +232,59 @@
cyborg_base_icon = "medical"
cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
hat_offset = 4
+ if("Sleek")
+ cyborg_base_icon = "sleekmed"
+ cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
+ if("Marina")
+ cyborg_base_icon = "marinamed"
+ cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
if("Eyebot")
cyborg_base_icon = "eyebotmed"
cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
- special_light_key = "eyebotmed"
+ if("Heavy")
+ cyborg_base_icon = "heavymed"
+ cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
+ return ..()
+
+/obj/item/robot_module/janitor/be_transformed_to(obj/item/robot_module/old_module)
+ var/mob/living/silicon/robot/R = loc
+ var/list/janimodels = list("Default", "Sleek", "Marina", "Can", "Heavy")
+ var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in janimodels
+ if(!borg_icon)
+ return FALSE
+ switch(borg_icon)
+ if("Default")
+ cyborg_base_icon = "janitor"
+ if("Marina")
+ cyborg_base_icon = "marinajan"
+ cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
+ if("Sleek")
+ cyborg_base_icon = "sleekjan"
+ cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
+ if("Can")
+ cyborg_base_icon = "canjan"
+ cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
+ if("Heavy")
+ cyborg_base_icon = "heavyres"
+ cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
+ return ..()
+
+/obj/item/robot_module/peacekeeper/be_transformed_to(obj/item/robot_module/old_module)
+ var/mob/living/silicon/robot/R = loc
+ var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Default", "Spider")
+ if(!borg_icon)
+ return FALSE
+ switch(borg_icon)
+ if("Default")
+ cyborg_base_icon = "peace"
+ if("Spider")
+ cyborg_base_icon = "whitespider"
+ cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
return ..()
/obj/item/robot_module/security/be_transformed_to(obj/item/robot_module/old_module)
var/mob/living/silicon/robot/R = loc
- var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Default", "Default - Treads", "Droid", "Spider")
+ var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Default", "Default - Treads", "Heavy", "Sleek", "Can", "Marina", "Spider")
if(!borg_icon)
return FALSE
switch(borg_icon)
@@ -211,19 +294,59 @@
cyborg_base_icon = "sec-tread"
special_light_key = "sec"
cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
- if("Droid")
- cyborg_base_icon = "Security"
- special_light_key = "service"
- hat_offset = 0
+ if("Sleek")
+ cyborg_base_icon = "sleeksec"
+ cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
+ if("Marina")
+ cyborg_base_icon = "marinasec"
+ cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
+ if("Can")
+ cyborg_base_icon = "cansec"
+ cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
if("Spider")
cyborg_base_icon = "spidersec"
- special_light_key = "spidersec"
+ cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
+ if("Heavy")
+ cyborg_base_icon = "heavysec"
+ cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
+ return ..()
+
+/obj/item/robot_module/butler/be_transformed_to(obj/item/robot_module/old_module)
+ var/mob/living/silicon/robot/R = loc
+ var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Waitress", "Heavy", "Sleek", "Butler", "Tophat", "Kent", "Bro")
+ if(!borg_icon)
+ return FALSE
+ switch(borg_icon)
+ if("Waitress")
+ cyborg_base_icon = "service_f"
+ if("Butler")
+ cyborg_base_icon = "service_m"
+ if("Bro")
+ cyborg_base_icon = "brobot"
+ if("Kent")
+ cyborg_base_icon = "kent"
+ special_light_key = "medical"
+ hat_offset = 3
+ if("Tophat")
+ cyborg_base_icon = "tophat"
+ special_light_key = null
+ hat_offset = INFINITY //He is already wearing a hat
+ if("Sleek")
+ cyborg_base_icon = "sleekserv"
+ special_light_key = "sleekserv"
+ cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
+ if("Heavy")
+ cyborg_base_icon = "heavyserv"
+ special_light_key = "heavyserv"
cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
return ..()
/obj/item/robot_module/engineering/be_transformed_to(obj/item/robot_module/old_module)
var/mob/living/silicon/robot/R = loc
- var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Default", "Default - Treads","Loader","Handy")
+ var/list/engymodels = list("Default", "Default - Treads", "Heavy", "Sleek", "Marina", "Can", "Spider", "Loader","Handy", "Pup Dozer")
+ if(R.client && R.client.ckey in list("nezuli"))
+ engymodels += "Alina"
+ var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in engymodels
if(!borg_icon)
return FALSE
switch(borg_icon)
@@ -239,13 +362,44 @@
has_snowflake_deadsprite = TRUE
if("Handy")
cyborg_base_icon = "handyeng"
- special_light_key = "handyeng"
cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
+ if("Sleek")
+ cyborg_base_icon = "sleekeng"
+ cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
+ if("Can")
+ cyborg_base_icon = "caneng"
+ cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
+ if("Marina")
+ cyborg_base_icon = "marinaeng"
+ cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
+ if("Spider")
+ cyborg_base_icon = "spidereng"
+ cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
+ if("Heavy")
+ cyborg_base_icon = "heavyeng"
+ cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
+ if("Pup Dozer")
+ cyborg_base_icon = "pupdozer"
+ can_be_pushed = FALSE
+ hat_offset = INFINITY
+ cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi'
+ has_snowflake_deadsprite = TRUE
+ dogborg = TRUE
+ cyborg_pixel_offset = -16
+ if("Alina")
+ cyborg_base_icon = "alina-eng"
+ special_light_key = "alina"
+ can_be_pushed = FALSE
+ hat_offset = INFINITY
+ cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi'
+ has_snowflake_deadsprite = TRUE
+ dogborg = TRUE
+ cyborg_pixel_offset = -16
return ..()
/obj/item/robot_module/miner/be_transformed_to(obj/item/robot_module/old_module)
var/mob/living/silicon/robot/R = loc
- var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Lavaland", "Asteroid", "Droid")
+ var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Lavaland", "Heavy", "Sleek", "Marina", "Can", "Spider", "Asteroid", "Droid")
if(!borg_icon)
return FALSE
switch(borg_icon)
@@ -258,4 +412,19 @@
cyborg_base_icon = "miner"
cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
hat_offset = 4
+ if("Sleek")
+ cyborg_base_icon = "sleekmin"
+ cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
+ if("Can")
+ cyborg_base_icon = "canmin"
+ cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
+ if("Marina")
+ cyborg_base_icon = "marinamin"
+ cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
+ if("Spider")
+ cyborg_base_icon = "spidermin"
+ cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
+ if("Heavy")
+ cyborg_base_icon = "heavymin"
+ cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
return ..()
diff --git a/modular_citadel/code/modules/mob/living/silicon/robot/robot_movement.dm b/modular_citadel/code/modules/mob/living/silicon/robot/robot_movement.dm
index 37dba85c40..598690590c 100644
--- a/modular_citadel/code/modules/mob/living/silicon/robot/robot_movement.dm
+++ b/modular_citadel/code/modules/mob/living/silicon/robot/robot_movement.dm
@@ -23,3 +23,7 @@
for(var/obj/screen/sprintbutton/selector in hud_used.static_inventory)
selector.insert_witty_toggle_joke_here(src)
return TRUE
+
+/mob/living/silicon/robot/proc/sprint_hotkey(targetstatus)
+ if(targetstatus ? !sprinting : sprinting)
+ togglesprint()
diff --git a/modular_citadel/code/modules/mob/living/simple_animal/banana_spider.dm b/modular_citadel/code/modules/mob/living/simple_animal/banana_spider.dm
index 80e8234914..d2006cd12c 100644
--- a/modular_citadel/code/modules/mob/living/simple_animal/banana_spider.dm
+++ b/modular_citadel/code/modules/mob/living/simple_animal/banana_spider.dm
@@ -38,7 +38,7 @@
return
to_chat(user, "You decide to wake up the banana spider...")
awakening = 1
-
+
spawn(30)
if(!QDELETED(src))
var/mob/living/simple_animal/banana_spider/S = new /mob/living/simple_animal/banana_spider(get_turf(src.loc))
@@ -55,7 +55,8 @@
icon_dead = "banana_peel"
health = 1
maxHealth = 1
- turns_per_move = 5
+ turns_per_move = 5 //this isn't player speed =|
+ speed = 2 //this is player speed
loot = list(/obj/item/reagent_containers/food/snacks/deadbanana_spider)
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 = 270
@@ -67,7 +68,7 @@
response_harm = "splats"
speak_emote = list("chitters")
mouse_opacity = 2
- density = FALSE
+ density = TRUE
ventcrawler = VENTCRAWLER_ALWAYS
gold_core_spawnable = FRIENDLY_SPAWN
verb_say = "chitters"
@@ -75,19 +76,17 @@
verb_exclaim = "chitters loudly"
verb_yell = "chitters loudly"
var/squish_chance = 50
- del_on_death = 1
-
+ var/projectile_density = TRUE //griffons get shot
+ del_on_death = TRUE
/mob/living/simple_animal/banana_spider/Initialize()
. = ..()
var/area/A = get_area(src)
if(A)
notify_ghosts("A banana spider has been created in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE)
- GLOB.poi_list |= src
-
/mob/living/simple_animal/banana_spider/attack_ghost(mob/user)
- if(src.key)
+ if(key) //please stop using src. without a good reason.
return
if(CONFIG_GET(flag/use_age_restriction_for_jobs))
if(!isnum(user.client.player_age))
@@ -98,17 +97,19 @@
var/be_spider = alert("Become a banana spider? (Warning, You can no longer be cloned!)",,"Yes","No")
if(be_spider == "No" || QDELETED(src) || !isobserver(user))
return
- src.sentience_act()
- src.key = user.key
+ sentience_act()
+ key = user.key
density = TRUE
/mob/living/simple_animal/banana_spider/ComponentInitialize()
. = ..()
- AddComponent(/datum/component/slippery, 80)
+ AddComponent(/datum/component/slippery, 40)
-
-/mob/living/simple_animal/banana_spider/Crossed(var/atom/movable/AM)
+/mob/living/simple_animal/banana_spider/Crossed(atom/movable/AM) //no /var in proc headers
. = ..()
+ if(istype(AM, /obj/item/projectile) && projectile_density) //forced projectile density
+ var/obj/item/projectile/P = AM
+ P.Bump(src)
if(ismob(AM))
if(isliving(AM))
var/mob/living/A = AM
@@ -147,4 +148,4 @@
/obj/item/reagent_containers/food/snacks/deadbanana_spider/Initialize()
. = ..()
- AddComponent(/datum/component/slippery, 80)
+ AddComponent(/datum/component/slippery, 20)
diff --git a/modular_citadel/code/modules/projectiles/guns/ballistic/handguns.dm b/modular_citadel/code/modules/projectiles/guns/ballistic/handguns.dm
index 82de2d4113..10ab3901d9 100644
--- a/modular_citadel/code/modules/projectiles/guns/ballistic/handguns.dm
+++ b/modular_citadel/code/modules/projectiles/guns/ballistic/handguns.dm
@@ -144,4 +144,4 @@ obj/item/projectile/bullet/c10mm/soporific
icon_state = "raygun"
desc = "A toy laser with a classic, retro feel and look. Compatible with existing laser tag systems."
ammo_type = list(/obj/item/ammo_casing/energy/laser/raytag)
- selfcharge = TRUE
\ No newline at end of file
+ selfcharge = EGUN_SELFCHARGE
\ No newline at end of file
diff --git a/modular_citadel/code/modules/projectiles/guns/ballistic/magweapon.dm b/modular_citadel/code/modules/projectiles/guns/ballistic/magweapon.dm
index 5cca9138f3..017a9dd52d 100644
--- a/modular_citadel/code/modules/projectiles/guns/ballistic/magweapon.dm
+++ b/modular_citadel/code/modules/projectiles/guns/ballistic/magweapon.dm
@@ -456,7 +456,7 @@
obj_flags = 0
fire_delay = 40
weapon_weight = WEAPON_HEAVY
- selfcharge = TRUE
+ selfcharge = EGUN_SELFCHARGE
charge_delay = 2
recoil = 2
cell_type = /obj/item/stock_parts/cell/toymagburst
diff --git a/modular_citadel/code/modules/projectiles/guns/pumpenergy.dm b/modular_citadel/code/modules/projectiles/guns/pumpenergy.dm
index bf07492acf..fa0e64032c 100644
--- a/modular_citadel/code/modules/projectiles/guns/pumpenergy.dm
+++ b/modular_citadel/code/modules/projectiles/guns/pumpenergy.dm
@@ -16,13 +16,20 @@
update_icon()
/obj/item/gun/energy/pumpaction/process() //makes it not rack itself when self-charging
- if(selfcharge)
+ if(selfcharge && cell?.charge < cell.maxcharge)
charge_tick++
if(charge_tick < charge_delay)
return
charge_tick = 0
- if(!cell)
- return
+ if(selfcharge == EGUN_SELFCHARGE_BORG)
+ var/atom/owner = loc
+ if(istype(owner, /obj/item/robot_module))
+ owner = owner.loc
+ if(!iscyborg(owner))
+ return
+ var/mob/living/silicon/robot/R = owner
+ if(!R.cell?.use(100))
+ return
cell.give(100)
update_icon()
diff --git a/modular_citadel/code/modules/projectiles/guns/toys.dm b/modular_citadel/code/modules/projectiles/guns/toys.dm
index a90ea999a4..18d174d677 100644
--- a/modular_citadel/code/modules/projectiles/guns/toys.dm
+++ b/modular_citadel/code/modules/projectiles/guns/toys.dm
@@ -15,7 +15,7 @@
ammo_type = list(/obj/item/ammo_casing/energy/laser/dispersal, /obj/item/ammo_casing/energy/laser/wavemotion)
ammo_x_offset = 2
modifystate = 1
- selfcharge = TRUE
+ selfcharge = EGUN_SELFCHARGE
item_flags = NONE
clumsy_check = FALSE
diff --git a/modular_citadel/code/modules/research/designs/weapon_designs.dm b/modular_citadel/code/modules/research/designs/weapon_designs.dm
index bdb77170ed..b27cedbcc2 100644
--- a/modular_citadel/code/modules/research/designs/weapon_designs.dm
+++ b/modular_citadel/code/modules/research/designs/weapon_designs.dm
@@ -1,7 +1,7 @@
/datum/design/mag_oldsmg/rubber_mag
- name = "WT-550 Auto Gun rubberbullets Magazine (4.6x30mm rubber)"
- desc = "A 20 round rubber shots magazine for the out of date security WT-550 Auto Rifle"
+ name = "WT-550 Semi-Auto SMG rubberbullets Magazine (4.6x30mm rubber)"
+ desc = "A 20 round rubber shots magazine for the out of date security WT-550 Semi-Auto SMG"
id = "mag_oldsmg_rubber"
materials = list(MAT_METAL = 6000)
build_path = /obj/item/ammo_box/magazine/wt550m9/wtrubber
- departmental_flags = DEPARTMENTAL_FLAG_SECURITY
\ No newline at end of file
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
diff --git a/modular_citadel/code/modules/research/designs/weapon_designs/weapon_designs.dm b/modular_citadel/code/modules/research/designs/weapon_designs/weapon_designs.dm
index 0db3bb9b1d..6246b9e24e 100644
--- a/modular_citadel/code/modules/research/designs/weapon_designs/weapon_designs.dm
+++ b/modular_citadel/code/modules/research/designs/weapon_designs/weapon_designs.dm
@@ -1,7 +1,7 @@
/datum/design/mag_oldsmg/tx_mag
- name = "WT-550 Auto Gun Uranium Magazine (4.6x30mm TX)"
- desc = "A 20 round uranium tipped magazine for the out of date security WT-550 Auto Rifle"
+ name = "WT-550 Semi-Auto SMG Uranium Magazine (4.6x30mm TX)"
+ desc = "A 20 round uranium tipped magazine for the out of date security WT-550 Semi-Auto SMG."
id = "mag_oldsmg_tx"
materials = list(MAT_METAL = 6000, MAT_SILVER = 600, MAT_URANIUM = 2000)
build_path = /obj/item/ammo_box/magazine/wt550m9/wttx
- departmental_flags = DEPARTMENTAL_FLAG_SECURITY
\ No newline at end of file
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
diff --git a/modular_citadel/code/modules/vore/resizing/sizegun_vr.dm b/modular_citadel/code/modules/vore/resizing/sizegun_vr.dm
index 51b6e24736..8295f32cfa 100644
--- a/modular_citadel/code/modules/vore/resizing/sizegun_vr.dm
+++ b/modular_citadel/code/modules/vore/resizing/sizegun_vr.dm
@@ -12,7 +12,7 @@
charge_cost = 100
projectile_type = /obj/item/projectile/beam/shrinklaser
modifystate = "sizegun-shrink"
- selfcharge = 1
+ selfcharge = EGUN_SELFCHARGE
firemodes = list(
list(mode_name = "grow",
projectile_type = /obj/item/projectile/beam/growlaser,
@@ -153,7 +153,7 @@ datum/design/sizeray
desc = "Size manipulator using bluespace breakthroughs."
item_state = null //so the human update icon uses the icon_state instead.
ammo_type = list(/obj/item/ammo_casing/energy/laser/shrinkray, /obj/item/ammo_casing/energy/laser/growthray)
- selfcharge = 1
+ selfcharge = EGUN_SELFCHARGE
charge_delay = 5
ammo_x_offset = 2
clumsy_check = 1
diff --git a/modular_citadel/icons/effects/souldeath.dmi b/modular_citadel/icons/effects/souldeath.dmi
new file mode 100644
index 0000000000..f225bd5321
Binary files /dev/null and b/modular_citadel/icons/effects/souldeath.dmi differ
diff --git a/modular_citadel/icons/mob/citadel_refs/mam_body_markings Matrixed Ref.dmi b/modular_citadel/icons/mob/citadel_refs/mam_body_markings Matrixed Ref.dmi
new file mode 100644
index 0000000000..7cf2c599ee
Binary files /dev/null and b/modular_citadel/icons/mob/citadel_refs/mam_body_markings Matrixed Ref.dmi differ
diff --git a/modular_citadel/icons/mob/clothing/necks.dmi b/modular_citadel/icons/mob/clothing/necks.dmi
new file mode 100644
index 0000000000..65198bc64c
Binary files /dev/null and b/modular_citadel/icons/mob/clothing/necks.dmi differ
diff --git a/modular_citadel/icons/mob/clothing/trek_item_icon.dmi b/modular_citadel/icons/mob/clothing/trek_item_icon.dmi
index 4ac77773a0..86afe16b03 100644
Binary files a/modular_citadel/icons/mob/clothing/trek_item_icon.dmi and b/modular_citadel/icons/mob/clothing/trek_item_icon.dmi differ
diff --git a/modular_citadel/icons/mob/clothing/trek_mob_icon.dmi b/modular_citadel/icons/mob/clothing/trek_mob_icon.dmi
index 9323ea9f3c..51daa8179f 100644
Binary files a/modular_citadel/icons/mob/clothing/trek_mob_icon.dmi and b/modular_citadel/icons/mob/clothing/trek_mob_icon.dmi differ
diff --git a/modular_citadel/icons/mob/mam_body_markings.dmi b/modular_citadel/icons/mob/mam_body_markings.dmi
deleted file mode 100644
index 99f4d0624c..0000000000
Binary files a/modular_citadel/icons/mob/mam_body_markings.dmi and /dev/null differ
diff --git a/modular_citadel/icons/mob/mam_ears.dmi b/modular_citadel/icons/mob/mam_ears.dmi
index 51ffd28bbc..b3946b546c 100644
Binary files a/modular_citadel/icons/mob/mam_ears.dmi and b/modular_citadel/icons/mob/mam_ears.dmi differ
diff --git a/modular_citadel/icons/mob/mam_markings.dmi b/modular_citadel/icons/mob/mam_markings.dmi
new file mode 100644
index 0000000000..eb7fecb5fc
Binary files /dev/null and b/modular_citadel/icons/mob/mam_markings.dmi differ
diff --git a/modular_citadel/icons/mob/mam_snouts.dmi b/modular_citadel/icons/mob/mam_snouts.dmi
index 98b62f929d..0bcfab6905 100644
Binary files a/modular_citadel/icons/mob/mam_snouts.dmi and b/modular_citadel/icons/mob/mam_snouts.dmi differ
diff --git a/modular_citadel/icons/mob/mam_tails OLD.dmi b/modular_citadel/icons/mob/mam_tails OLD.dmi
new file mode 100644
index 0000000000..7627b71b35
Binary files /dev/null and b/modular_citadel/icons/mob/mam_tails OLD.dmi differ
diff --git a/modular_citadel/icons/mob/mam_tails.dmi b/modular_citadel/icons/mob/mam_tails.dmi
index 7627b71b35..8c97b869d6 100644
Binary files a/modular_citadel/icons/mob/mam_tails.dmi and b/modular_citadel/icons/mob/mam_tails.dmi differ
diff --git a/modular_citadel/icons/mob/mam_taur.dmi b/modular_citadel/icons/mob/mam_taur.dmi
index 5591636886..ebaa0123ae 100644
Binary files a/modular_citadel/icons/mob/mam_taur.dmi and b/modular_citadel/icons/mob/mam_taur.dmi differ
diff --git a/modular_citadel/icons/mob/markings_notmammals.dmi b/modular_citadel/icons/mob/markings_notmammals.dmi
new file mode 100644
index 0000000000..4161ea2cea
Binary files /dev/null and b/modular_citadel/icons/mob/markings_notmammals.dmi differ
diff --git a/modular_citadel/icons/mob/mutant_bodyparts.dmi b/modular_citadel/icons/mob/mutant_bodyparts.dmi
index 8f3bfb3b87..f369f21afb 100644
Binary files a/modular_citadel/icons/mob/mutant_bodyparts.dmi and b/modular_citadel/icons/mob/mutant_bodyparts.dmi differ
diff --git a/modular_citadel/icons/mob/robots.dmi b/modular_citadel/icons/mob/robots.dmi
index 230a01f4d4..b47ee12896 100644
Binary files a/modular_citadel/icons/mob/robots.dmi and b/modular_citadel/icons/mob/robots.dmi differ
diff --git a/modular_citadel/icons/mob/suit_digi.dmi b/modular_citadel/icons/mob/suit_digi.dmi
index 89284dbe52..95d03bb6d0 100644
Binary files a/modular_citadel/icons/mob/suit_digi.dmi and b/modular_citadel/icons/mob/suit_digi.dmi differ
diff --git a/modular_citadel/icons/mob/uniform_digi.dmi b/modular_citadel/icons/mob/uniform_digi.dmi
index 5d9f0ad235..c5ee6b1780 100644
Binary files a/modular_citadel/icons/mob/uniform_digi.dmi and b/modular_citadel/icons/mob/uniform_digi.dmi differ
diff --git a/modular_citadel/icons/mob/widerobot.dmi b/modular_citadel/icons/mob/widerobot.dmi
index 2b192a1052..c730467e1d 100644
Binary files a/modular_citadel/icons/mob/widerobot.dmi and b/modular_citadel/icons/mob/widerobot.dmi differ
diff --git a/modular_citadel/icons/obj/clothing/cit_neck.dmi b/modular_citadel/icons/obj/clothing/cit_neck.dmi
index ce115c2aa7..abccd4a115 100644
Binary files a/modular_citadel/icons/obj/clothing/cit_neck.dmi and b/modular_citadel/icons/obj/clothing/cit_neck.dmi differ
diff --git a/modular_citadel/icons/obj/clothing/trek_item_icon.dmi b/modular_citadel/icons/obj/clothing/trek_item_icon.dmi
new file mode 100644
index 0000000000..86afe16b03
Binary files /dev/null and b/modular_citadel/icons/obj/clothing/trek_item_icon.dmi differ
diff --git a/modular_citadel/icons/obj/genitals/breasts_onmob.dmi b/modular_citadel/icons/obj/genitals/breasts_onmob.dmi
index d0597e1a38..2a7342553b 100644
Binary files a/modular_citadel/icons/obj/genitals/breasts_onmob.dmi and b/modular_citadel/icons/obj/genitals/breasts_onmob.dmi differ
diff --git a/modular_citadel/interface/skin.dmf b/modular_citadel/interface/skin.dmf
index eca2dda112..39626ef912 100644
--- a/modular_citadel/interface/skin.dmf
+++ b/modular_citadel/interface/skin.dmf
@@ -287,3 +287,30 @@ window "statwindow"
prefix-color = #ebebeb
suffix-color = #ebebeb
+window "preferences_window"
+ elem "preferences_window"
+ type = MAIN
+ pos = 372,0
+ size = 1120x1000
+ anchor1 = none
+ anchor2 = none
+ background-color = none
+ is-visible = false
+ saved-params = "pos;size;is-minimized;is-maximized"
+ statusbar = false
+ elem "preferences_browser"
+ type = BROWSER
+ pos = -8,-8
+ size = 896x1008
+ anchor1 = 0,0
+ anchor2 = 90,100
+ background-color = none
+ saved-params = ""
+ elem "character_preview_map"
+ type = MAP
+ pos = 887,0
+ size = 313x1000
+ anchor1 = 90,0
+ anchor2 = 100,100
+ right-click = true
+ saved-params = "zoom;letterbox;zoom-mode"
\ No newline at end of file
diff --git a/modular_citadel/sound/misc/souldeath.ogg b/modular_citadel/sound/misc/souldeath.ogg
new file mode 100644
index 0000000000..98a19c0765
Binary files /dev/null and b/modular_citadel/sound/misc/souldeath.ogg differ
diff --git a/modular_citadel/sound/voice/bark1.ogg b/modular_citadel/sound/voice/bark1.ogg
new file mode 100644
index 0000000000..5d3853419f
Binary files /dev/null and b/modular_citadel/sound/voice/bark1.ogg differ
diff --git a/modular_citadel/sound/voice/bark2.ogg b/modular_citadel/sound/voice/bark2.ogg
new file mode 100644
index 0000000000..dab73c4743
Binary files /dev/null and b/modular_citadel/sound/voice/bark2.ogg differ
diff --git a/modular_citadel/sound/voice/hiss.ogg b/modular_citadel/sound/voice/hiss.ogg
new file mode 100644
index 0000000000..cd9fa22c37
Binary files /dev/null and b/modular_citadel/sound/voice/hiss.ogg differ
diff --git a/modular_citadel/sound/voice/merowr.ogg b/modular_citadel/sound/voice/merowr.ogg
new file mode 100644
index 0000000000..01fb993c61
Binary files /dev/null and b/modular_citadel/sound/voice/merowr.ogg differ
diff --git a/modular_citadel/sound/voice/merp.ogg b/modular_citadel/sound/voice/merp.ogg
new file mode 100644
index 0000000000..b40b7a365b
Binary files /dev/null and b/modular_citadel/sound/voice/merp.ogg differ
diff --git a/modular_citadel/sound/voice/mothsqueak.ogg b/modular_citadel/sound/voice/mothsqueak.ogg
new file mode 100644
index 0000000000..c5ac979aed
Binary files /dev/null and b/modular_citadel/sound/voice/mothsqueak.ogg differ
diff --git a/modular_citadel/sound/voice/raptor_purr.ogg b/modular_citadel/sound/voice/raptor_purr.ogg
new file mode 100644
index 0000000000..a1492718e5
Binary files /dev/null and b/modular_citadel/sound/voice/raptor_purr.ogg differ
diff --git a/sound/effects/clang1.ogg b/sound/effects/clang1.ogg
new file mode 100644
index 0000000000..eef118e4d4
Binary files /dev/null and b/sound/effects/clang1.ogg differ
diff --git a/sound/effects/clang2.ogg b/sound/effects/clang2.ogg
new file mode 100644
index 0000000000..175fe98fd1
Binary files /dev/null and b/sound/effects/clang2.ogg differ
diff --git a/sound/effects/clangsmall1.ogg b/sound/effects/clangsmall1.ogg
new file mode 100644
index 0000000000..7824db66cf
Binary files /dev/null and b/sound/effects/clangsmall1.ogg differ
diff --git a/sound/effects/clangsmall2.ogg b/sound/effects/clangsmall2.ogg
new file mode 100644
index 0000000000..3211e66b75
Binary files /dev/null and b/sound/effects/clangsmall2.ogg differ
diff --git a/sound/effects/lingbloodhiss.ogg b/sound/effects/lingbloodhiss.ogg
new file mode 100644
index 0000000000..31ebcf06bc
Binary files /dev/null and b/sound/effects/lingbloodhiss.ogg differ
diff --git a/sound/effects/lingempscreech.ogg b/sound/effects/lingempscreech.ogg
new file mode 100644
index 0000000000..282d089107
Binary files /dev/null and b/sound/effects/lingempscreech.ogg differ
diff --git a/sound/effects/lingreadapt.ogg b/sound/effects/lingreadapt.ogg
new file mode 100644
index 0000000000..9ca98eb78c
Binary files /dev/null and b/sound/effects/lingreadapt.ogg differ
diff --git a/sound/effects/lingscreech.ogg b/sound/effects/lingscreech.ogg
new file mode 100644
index 0000000000..9e05aa6b51
Binary files /dev/null and b/sound/effects/lingscreech.ogg differ
diff --git a/sound/effects/slosh1.ogg b/sound/effects/slosh1.ogg
new file mode 100644
index 0000000000..4da76aac49
Binary files /dev/null and b/sound/effects/slosh1.ogg differ
diff --git a/sound/effects/slosh2.ogg b/sound/effects/slosh2.ogg
new file mode 100644
index 0000000000..9df0243c4c
Binary files /dev/null and b/sound/effects/slosh2.ogg differ
diff --git a/sound/music/rocketridersprayer.ogg b/sound/music/rocketridersprayer.ogg
new file mode 100644
index 0000000000..24d3beca3f
Binary files /dev/null and b/sound/music/rocketridersprayer.ogg differ
diff --git a/sound/weapons/dink.ogg b/sound/weapons/dink.ogg
new file mode 100644
index 0000000000..54f3678f79
Binary files /dev/null and b/sound/weapons/dink.ogg differ
diff --git a/sound/weapons/gagging.ogg b/sound/weapons/gagging.ogg
new file mode 100644
index 0000000000..0b0a3783f4
Binary files /dev/null and b/sound/weapons/gagging.ogg differ
diff --git a/strings/names/clown.txt b/strings/names/clown.txt
index 8eec0990d0..d8655d7cbf 100644
--- a/strings/names/clown.txt
+++ b/strings/names/clown.txt
@@ -1,12 +1,25 @@
+Alfie
+Antsy
Baby Cakes
+Bam Bam
+Beebee
Bo Bo Sassy
Bonker
+Bonbon
Bubble
Buster Frown
+Buttercup
Button
Candy
Checkers
+Clarabell
+Clownsky
+Clueless
+Cluesky
+Dazzle
Dinky Doodle
+Doodles
+Duckie
Flop O'Honker
Freckle
Giggles
@@ -15,12 +28,18 @@ Goose McSunny
Honkel the III
Honker
Honkerbelle
+Knicknack
+Jazzy Bella
Jingle
+Joy
Jo Jo Bobo Bo
Ladybug Honks
+Lala
Miss Stockings
+Mittens
Mr Shoe
Patches
+Pancake
Pepinpop
Pocket
Razzle Dazzle
@@ -33,5 +52,11 @@ Slippy Joe
Sparkle
Speckles
Sprinkledinkle
+Squigley
+Tickle
+Topcake
Toodles Sharperton
-Ziggy Yoyo
\ No newline at end of file
+Trixy
+Witty
+Ziggy Yoyo
+Zippy
diff --git a/strings/phobia.json b/strings/phobia.json
index 3f56751333..e1ae1f4e13 100644
--- a/strings/phobia.json
+++ b/strings/phobia.json
@@ -257,6 +257,19 @@
"fowl"
],
+"cats": [
+ "mew",
+ "nya",
+ "moew",
+ "feline",
+ "cat",
+ "neko",
+ "viola",
+ "kitty",
+ "purr",
+ "headpat"
+ ],
+
"falling": [
"hold on",
"hang in there",
@@ -297,4 +310,4 @@
"ora",
"~"
]
-}
\ No newline at end of file
+}
diff --git a/strings/round_start_sounds.txt b/strings/round_start_sounds.txt
index 18fbb3f98f..a8409188fc 100644
--- a/strings/round_start_sounds.txt
+++ b/strings/round_start_sounds.txt
@@ -21,3 +21,4 @@ sound/music/indeep.ogg
sound/music/goodbyemoonmen.ogg
sound/music/flytothemoon_otomatone.ogg
sound/music/milkyway.ogg
+sound/music/rocketridersprayer.ogg
diff --git a/strings/sillytips.txt b/strings/sillytips.txt
index f7c66b7407..bc59a109f0 100644
--- a/strings/sillytips.txt
+++ b/strings/sillytips.txt
@@ -44,3 +44,4 @@ As a Cargo Tech make sure to always buy a tesla to sell back to CC. They love th
Help.
Maints.
BZ stops or slows down Lings chem regeneration drastically, make sure to BZ flood the station when lings are confirmed!
+Admins always regret meme options in their polls.
diff --git a/strings/tips.txt b/strings/tips.txt
index d389437158..9571527853 100644
--- a/strings/tips.txt
+++ b/strings/tips.txt
@@ -6,7 +6,7 @@ You can drag other players onto yourself to open the strip menu, letting you rem
Clicking on a windoor rather then bumping into it will keep it open, you can click it again to close it.
You can spray a fire extinguisher, throw items or fire a gun while floating through space to change your direction. Simply fire opposite to where you want to go.
You can change the control scheme by pressing tab. One is WASD, the other is the arrow keys. Keep in mind that hotkeys are also changed with this.
-All vending machines can be hacked to obtain some contraband items from them, and some can be fed with coins to gain access to premium items.
+All vending machines can be hacked to obtain some contraband items from them, and many can be fed with coins to gain access to premium items.
Firesuits and winter coats offer mild protection from the cold, allowing you to spend longer periods of time near breaches and space than if wearing nothing at all.
Glass shards can be welded to make glass, and metal rods can be welded to make metal. Ores can be welded too, but this takes a lot of fuel.
If you need to drag multiple people either to safety or to space, bring a locker or crate over and stuff them all in before hauling them off.
@@ -18,13 +18,16 @@ You can recolor certain items like jumpsuits and gloves in washing machines by a
Maintenance is full of equipment that is randomized every round. Look around and see if anything is worth using.
Some roles cannot be antagonists by default, but antag selection is decided first. For instance, you can set Security Officer to High without affecting your chances of becoming an antag -- the game will just select a different role.
There are many places around the station to hide contraband. A few for starters: linen boxes, toilet cisterns, body bags. Experiment to find more!
-On some maps, you can use a machine in the vault to deposit space cash for cargo points or rob cargo blind.
+On all maps, you can use a machine in the vault to deposit space cash for cargo points. Otherwise, use it to steal the station's cash and get out before the alarm goes off.
As the Captain, you are one of the highest priority targets on the station. Everything from revolutions, to nuclear operatives, to traitors that need to rob you of your unique lasgun or your life are things to worry about.
As the Captain, always take the nuclear disk and pinpointer with you every shift. It's a good idea to give one of these to another head you can trust with keeping it safe, such as the Head of Security.
As the Captain, you have absolute access and control over the station, but this does not mean that being a horrible person won't result in mutiny and a ban.
+As the Captain, you have a fancy pen that can be used as a holdout dagger or even as a scalpel in surgery!
As the Captain, you can purchase a new emergency shuttle using a communications console. Some require credits, while others give you credits in exchange. Keep in mind that purchasing dangerous shuttles will incur the ire of your crew.
As the Chief Medical Officer, your hypospray is like a refillable instant injection syringe that can hold 30 units as opposed to the standard 15.
As the Chief Medical Officer, coordinate and communicate with your doctors, chemists, and geneticists during a nuclear emergency, blob infestation, or some other crisis to keep people alive and fighting.
+As a Medical Doctor, pester Research for improved surgical tools. They work faster, don't cost much and are typically more deadly.
+As a Medical Doctor, your belt can hold a full set of surgical tools. Using sterilizine before each attempt during surgery will reduce your failure chance on tricky steps or when using less-than-optimal equipment.
As a Medical Doctor, you can attempt to drain blood from a husk with a syringe to determine the cause. If you can extract blood, it was caused by extreme temperatures or lasers, if there is no blood to extract, you have confirmed the presence of changelings.
As a Medical Doctor, while both heal toxin damage, the difference between charcoal and antitoxin is that charcoal will actively remove all other reagents from one's body, while antitoxin only removes various toxins - but can overdose.
As a Medical Doctor, you can surgically implant or extract things from people's chests. This can range from putting in a bomb to pulling out an alien larva.
@@ -38,24 +41,27 @@ As a Chemist, there are dozens of chemicals that can heal, and even more that ca
As a Chemist, some chemicals can only be synthesized by heating up the contents in the chemical heater.
As a Chemist, you will be expected to supply crew with certain chemicals. For example, clonexadone and mannitol for the cryo tubes, unstable mutagen and saltpetre for botany as well as healing pills and patches for the front desk.
As a Chemist, you can make 100u bottles from plastic sheets. The ChemMaster can produce infinite 30u glass bottles as well.
-As a Geneticist, you can eject someone from cloning early by disabling power in genetics. Note that they will suffer more genetic damage and may lose vital organs from this.
+As a Geneticist, you can eject someone from cloning early by clicking on the cloner pod with your ID. Note that they will suffer more genetic damage and may lose vital organs from this.
As a Geneticist, becoming a hulk makes you capable of dealing high melee damage, stunlocking people, and punching through walls. However, you can't fire guns, will lose your hulk status if you take too much damage, and are not considered a human by the AI while you are a hulk.
As the Virologist, your viruses can range from healing powers so great that you can heal out of critical status, or diseases so dangerous they can kill the entire crew with airborne spontaneous combustion. Experiment!
As the Virologist, you only require small amounts of vaccine to heal a sick patient. Work with the Chemist to distribute your cures more efficiently.
As the Research Director, you can take AIs out of their cores by loading them into an intelliCard, and then from there into an AI system integrity restorer computer to revive and/or repair them.
As the Research Director, you can lock down cyborgs instead of blowing them up. Then you can have their laws reset or if that doesn't work, safely dismantled.
+As the Research Director, you can upgrade your modular console with better computer parts to speed up its functions. This can be useful when using the AI system integrity restorer.
As the Research Director, your console's NTnet monitoring tool can be used to retrieve airlock passkeys, provided that someone used a door remote.
As a Scientist, you can use the mutation toxin obtained from green slimes to turn yourself into a jelly mutant. Each subspecies has unique features - for example telepathic powers, duplicating bodies or integrating slime extracts!
As a Scientist, you can maximize the number of uses you get out of a slime by feeding it slime steroid, created from purple slimes, while alive. You can then apply extract enhancer, created from cerulean slimes, on each extract.
-As a Scientist, you can disable anomalies by scanning them with an analyzer, then send a signal on the frequency it gives you with a remote signalling device. This will leave behind an anomaly core, which can be used to construct a Phazon mech!
+As a Scientist, you can disable anomalies by scanning them with an analyzer, then send a signal on the frequency it gives you with a remote signalling device. This will leave behind an anomaly core, which can be used to construct a Phazon mech, or be used in the destructive analyzer for a 10,000 point bonus!
As a Scientist, researchable stock parts can seriously improve the efficiency and speed of machines around the station. In some cases, it can even unlock new functions.
As a Scientist, you can generate research points by letting the tachyon-doppler array record increasingly large explosions.
As a Scientist, getting drunk just enough will speed up research. Skol!
+As a Scientist, you can get points by placing slime cores into the deconstructive analyzer! This even works with crossbred slime cores.
As a Roboticist, keep an ear out for anomaly announcements. If you get your hands on an anomaly core, you can build a Phazon mech!
As a Roboticist, you can repair your cyborgs with a welding tool. If they have taken burn damage from lasers, you can remove their battery, expose the wiring with a screwdriver and replace their wires with a cable coil.
As a Roboticist, you can reset a cyborg's module by cutting and mending the reset wire with a wire cutter.
As a Roboticist, you can greatly help out Shaft Miners by building a Firefighter APLU equipped with a hydraulic clamp and plasma cutter. The mech is ash storm proof and can even walk across lava!
As a Roboticist, you can augment people with cyborg limbs. Augmented limbs can easily be repaired with cables and welders.
+As a Roboticist, you can use your printer that is linked to the ore silo to teleport mats into your work place!
As the AI, you can click on people's names to look at them. This only works if there are cameras that can see them.
As the AI, you can quickly open and close doors by holding shift while clicking them, bolt them when holding ctrl, and even shock them while holding alt.
As the AI, you can take pictures with your camera and upload them to newscasters.
@@ -65,8 +71,9 @@ As a Cyborg, you are impervious to fires and heat. If you are rogue, you can rel
As a Cyborg, you are extremely vulnerable to EMPs as EMPs both stun you and damage you. The ion rifle in the armory or a traitor with an EMP kit can kill you in seconds.
As a Service Cyborg, your spray can knocks people down. However, it is blocked by gas masks.
As an Engineering Cyborg, you can attach air alarm/fire alarm/APC frames to walls by placing them on the floor and using a screwdriver on them.
-As a Medical Cyborg, you can fully perform surgery and even augment people.
+As a Medical Cyborg, you can fully perform surgery and even augment people. Best of all, they have a 0% failure chance.
As a Janitor Cyborg, you are the bane of all slaughter demons and even Bubblegum himself. Cleaning up blood stains will severely gimp them.
+As a Janitor Cyborg, you get a fancy bottle of drying agent! If you want to be nice, spray the janitor boots with them to magically upgrade them to absorbent galoshes.
As the Chief Engineer, you can rename areas or create entirely new ones using your station blueprints.
As the Chief Engineer, your hardsuit is significantly better than everybody else's. It has the best features of both engineering and atmospherics hardsuits - boasting nigh-invulnerability to radiation and all atmospheric conditions.
As the Chief Engineer, you can spy on and even forge PDA communications with the message monitor console! The key is in your office.
@@ -84,6 +91,7 @@ As an Engineer, you can use radiation collectors to generate research points. Lo
As an Engineer, don't underestimate the humble P.A.C.M.A.N. generators. With upgraded parts, a couple units working in tandem are sufficient to take over for an exploded engine or shattered solars.
As an Engineer, your departmental protolathe and circuit printer can manufacture the necessary circuit boards and components to build just about anything. Make extra medical machinery everywhere! Build a gibber for security! Set up an array of emitters pointing down the hall! The possibilities are endless!
As an Engineer, you can pry open secure storage by disabling the engine room APC's main breaker. This is obviously a bad idea if the engine is running.
+Don't forget that Cargo has access to a meteor defense satellite that can be ordered BEFORE meteors hit the station. Any idle Engineers should have this on their to-do list.
As an Engineer, your RCD can be reloaded with mineral sheets instead of just compressed matter cartridges.
As an Atmospheric Technician, you can unwrench a pipe regardless of the pressures of the gases inside, but if they're too high they can burst out and injure you!
As an Atmospheric Technician, look into replacing your gas pumps with volumetric gas pumps, as those move air in flat numerical amounts, rather than percentages which leave trace gases.
@@ -92,18 +100,31 @@ As an Atmospheric Technician, your backpack firefighter tank can launch resin. T
As an Atmospheric Technician, your ATMOS holofan projector blocks gases while allowing objects to pass through. With it, you can quickly contain gas spills, fires and hull breaches. Or, use it to seal a plasmaman cloning room.
As an Atmospheric Technician, burning a plasma/oxygen mix inside the incinerator will not only produce power, but also gases such as tritium and water vapor.
As an Atmospheric Technician, you can change the layer of a pipe by clicking with it on a wrenched pipe or other atmos component of the desired layer.
+As an Atmospheric Technician, you can take a few cans worth of N2/N2O and cool it down at local freezers. This is a good idea when dealing with (or preparing for) a supermatter meltdown.
As the Head of Security, you are expected to coordinate your security force to handle any threat that comes to the station. Sometimes it means making use of the armory to handle a blob, sometimes it means being ruthless during a revolution or cult.
As the Head of Security, you can call for executions or forced cyborgization, but may require the Captain's approval.
As the Head of Security, don't let the power go to your head. You may have high access, great equipment, and a miniature army at your side, but being a terrible person without a good reason is grounds for banning.
As the Warden, your duty is to be the watchdog of the brig and handler of prisoners when little is happening, and to hand out equipment and weapons to the security officers when a crisis strikes.
As the Warden, keep a close eye on the armory at all times, as it is a favored strike point of nuclear operatives and cocky traitors.
As the Warden, if a prisoner's crimes are heinous enough you can put them in permabrig or the gulag. Make sure to check on them once in a while!
+As the Warden, never underestimate the power of tech slugs! Scattershot fires a cone of weaker lasers, Ion slugs fires EMPs that only effect the tiles they hit, and Pulse slugs fire a singular laser that can one-hit almost any wall!
+As the Warden, you can use a surgical saw on riot shotguns to shorten the barrel, making them able to fit in your backpack.
As the Warden, you can implant criminals you suspect might re-offend with devices that will track their location and allow you to remotely inject them with disabling chemicals.
As the Warden, you can use handcuffs on orange prisoner shoes to turn them into cuffed shoes, forcing prisoners to walk and potentially thwarting an escape.
+As the Warden, tracker implants can be used on sec officers. Doing this will let you track their corpse even without suits, though the implant will biodegrade after 5 minutes.
+As the Warden, cryostasis shotgun darts hold 10u of chemicals that will not react untill it hits someone.
+As the Warden, chemical implants can be loaded with a cocktail of healing or combat chems, perfect for the Hos or other sec officers to use. Be sure to keep a eye on them though, it will not auto inject! EMPs or starvation mite lead to the chemical implant to go off as well.
+As the Warden, tracker implants can be used on sec officers. Doing this will let you be able to message them when telecoms are out, or when you suspect coms are compromised. This is also good against rogue AIs as the prisoner tracker doesn't leave logs or alarms for the AI.
+As a Security Officer, remember that correlation does not equal causation. Someone may have just been at the wrong place at the wrong time!
+As a Security Officer, remember that your belt can hold more then one stun baton.
+As a Security Officer, remember harm battoning someone in the head can deconvert them form a being a rev! This sadly doesn't work against the cult, nor does this protect them from getting reconverted.
+As a Security Officer, remember that you can attach a sec-lite to your taser or your helmet!
As a Security Officer, communicate and coordinate with your fellow officers using the security channel (:s) to avoid confusion.
As a Security Officer, your sechuds or HUDsunglasses can not only see crewmates' job assignments and criminal status, but also if they are mindshield implanted. Use this to your advantage in a revolution to definitively tell who is on your side!
As a Security Officer, mindshield implants can only prevent someone from being turned into a cultist: unlike revolutionaries, it will not de-cult them if they have already been converted.
As a Security Officer, examining someone while wearing sechuds or HUDsunglasses will let you set their arrest level, which will cause Beepsky and other security bots to chase after them.
+As a Security Officer, you can take out the power cell on your baton to replace it with a better or fully charged one. Just use a screwdriver on your baton to remove the old cell
+As a Security Officer, you can place riot shotguns on your armor, this even works with winter sec coats!
As the Detective, people leave fingerprints everywhere and on everything. With the exception of white latex, gloves will hide them. All is not lost, however, as gloves leave fibers specific to their kind such as black or nitrile, pointing to a general department.
As the Detective, you can use your forensics scanner from a distance.
As the Detective, your revolver can be loaded with .357 ammunition obtained from a hacked autolathe. Firing it has a decent chance to blow up your revolver.
@@ -119,6 +140,8 @@ As the Clown, eating bananas heals you slightly. Honk!
As the Clown, your Holy Grail is the mineral bananium, which can be given to the Roboticist to build you a fun and robust mech beloved by everyone.
As the Clown, you can use your stamp on a sheet of cardboard as the first step of making a honkbot. Fun for the whole crew!
As the Chaplain, your null rod has a lot of functions: it can convert water into holy water, which if spread on the ground prevents wizards from jaunting away, can destroy cultist runes by hitting them, and is a very powerful weapon to boot!
+The Chaplain can bless any container with water by hitting it with their bible. Holy water has a myriad of uses against both cults and large amounts of it are a great contributor to success against them.
+The Chaplain's holy weapon will kill clockwork marauders in two hits.
As the Chaplain, your bible is also a container that can store small items. Depending on your god, your starting bible may come with a surprise!
As the Chaplain, you are much more likely to get a response by praying to the gods than most people. To boost your chances, make altars with colorful crayon runes, lit candles, and wire art.
As a Botanist, you can hack the MegaSeed Vendor to get access to more exotic seeds. These seeds can alternatively be ordered from cargo.
@@ -129,15 +152,20 @@ As a Cook, you can load your food into snack vending machines.
As a Cook, you can rename your custom made food with a pen.
As a Cook, any food you make will be much healthier than the junk food found in vendors. Having the crew routinely eating from you will provide minor buffs.
As a Cook, being in the kitchen will make you remember the basics of Close Quarters Cooking. It is highly effective at removing Assistants from your workplace.
+As a Cook, your Kitchenmate can vend out trays that fit on your belt slot. These trays pick up 7 food items at a time and are a quick way to transport large meals.
+As a Cook, the advanced roasting stick is used to cook food at a distance, and can be used on SME, singularity, and other objects that cook food normally.
As the Bartender, the drinks you start with only give you the basics. If you want more advanced mixtures, look into working with chemistry, hydroponics, or even mining for things to grind up and throw in!
As the Bartender, you can use a circular saw on your shotgun to make it easier to store.
As a Janitor, if someone steals your janicart, you can instead use your space cleaner spray, grenades, water sprayer, exact bloody revenge or order another from Cargo.
+As a Janitor, the trash bag can be used to hold more than trash. Tools, medical equipment, smuggled nuclear disks... You name it!
As a Janitor, mousetraps can be used to create bombs or booby-trap containers.
-As the Curator, you are not completely defenseless. Your whip easily disarms people, your laser pointer can blind humans and cyborgs, and you can hide items in wirecut books.
+Beware the Curator, for they are not completely defenseless. The curator's whip always disarms people, their laser pointer can blind humans and cyborgs, and can hide items in wirecut books.
As the Curator, be sure to keep the shelves stocked and the library clean for crew.
As a Cargo Technician, you can hack MULEbots to make them faster, run over people in their way, and even let you ride them!
As a Cargo Technician, you can order contraband items from the supply shuttle console by de-constructing it and using a multitool on the circuit board, the re-assembling it.
As a Cargo Technician, you can earn more cargo points by shipping back crates from maintenance, liquid containers, plasma sheets, rare seeds from hydroponics, and more!
+As a Cargo Technician, you get 400 points per packet! Stamp the manifest and sending back the crate will give you 200 points for the paperwork and 200 points for the crate!
+As a Cargo Technician, paperwork is an alternative option to shipping off plasma sheets and other goods. Order Paperwork crates and go into the crafting menu to turn pens and undone paper work into completed grant paper work to get 50 points per sheet!
As the Quartermaster, be sure to check the manifests on crates you receive to make sure all the info is correct. If there's a mistake, stamp the manifest DENIED and send it back in a crate with the items untouched for a refund!
As the Quartermaster, you can construct an express supply console that instantly delivers crates by drop pod. The impact will cause a small explosion as well.
As a Shaft Miner, the northern side of Lavaland has a lot more rare minerals than on the south.
@@ -161,6 +189,9 @@ As a Monkey, you can still wear a few human items, such as backpacks, gas masks
As the Malfunctioning AI, you can shunt to an APC if the situation gets bad. This disables your doomsday device if it is active.
As the Malfunctioning AI, you should either order your cyborgs to dismantle the robotics console or blow it up yourself in order to protect them.
As the Malfunctioning AI, look into flooding the station with plasma fires to kill off large portions of the crew, letting you pick off the remaining few with space suits who escaped.
+Xenomorphs? Science can craft deadly tech shells like pulse slugs and laser scatter shot that are highly effective against any alien threat.
+When fighting aliens, it can be a good idea to turn off the gravity due to the alien's lack of zero-gravity control.
+When fighting xenomorph aliens, consider a shield. Shields can block their pounces and be worn on the back, but beware of neurotoxin.
As an Alien, your melee prowess is unmatched, but your ranged abilities are sorely lacking. Make use of corners to force a melee confrontation!
As an Alien, you take double damage from all burn attacks, such as lasers, welding tools, and fires. Furthermore, fire can destroy your resin and eggs. Expose areas to space to starve away any flamethrower fires before they can do damage!
As an Alien, resin floors not only regenerate your plasma supply, but also passively heal you. Fight on resin floors to gain a home turf advantage!
@@ -180,6 +211,7 @@ As the Blob, talking will send a message to all other overminds and all Blobbern
As a Blobbernaut, you can communicate with overminds and other Blobbernauts via :b.
As a Blobbernaut, your HUD shows your health and the core health of the overmind that created you.
As a Revolutionary, you cannot convert a head of staff or someone who has a mindshield implant, such as a security officer or those they implant. Implants can however be surgically removed, and do not carry over with cloning. Take control of medbay to keep control of conversions!
+During a revolution, you cannot convert someone with brain damage, making an un-upgraded cloner a makeshift deconversion device.
As a Revolutionary, cargo can be your best friend or your worst nightmare. In the best case scenario you will be able to order a limitless amount of guns and armor, in the worst case scenario security will take control and order a limitless number of mindshield implants to turn your fellow revolutionaries against you.
As a Revolutionary, your main power comes from how quickly you spread. Convert people as fast as you can and overwhelm the heads of staff before security can arm up.
As a Changeling, the Extract DNA sting counts for your genome absorb objective, but does not let you respec your powers.
@@ -199,8 +231,6 @@ As a Servant, converting or sabotaging Science and Genetics can make defending t
As a Servant, the Clockwork Armaments scripture allows you to summon armor and/or a weapon at will. Use it whenever you unlock it!
You can deconvert Cultists of Nar-Sie and Servants of Ratvar by feeding them large amounts of holy water. Unlike revolutionaries, implanting them with mindshield implants won't do it!
Tiles sprayed with holy water will permanently block Servants of Ratvar from teleporting onto them.
-The Chaplain can bless any container with water by hitting it with their bible. Holy water has a myriad of uses against both cults and large amounts of it are a great contributor to success against them.
-The Chaplain's holy weapon will kill clockwork marauders in two hits.
As a Wizard, you can turn people to stone, then animate the resulting statue with a staff of animation to create an extremely powerful minion, for all of 5 minutes at least.
As a Wizard, the fireball spell performs very poorly at close range, as it can easily catch you in the blast. It is best used as a form of artillery down long hallways.
As a Wizard, summoning guns will turn a large portion of the crew against themselves, but will also give everyone anything from a pea shooter to a BFG 9000. Use at your own risk!
@@ -217,17 +247,19 @@ As a Revenant, your Malfunction ability in general damages machinery and mechani
As a Revenant, the illness inflicted on humans by Blight can be easily cured by lying down or with holy water, making it best used on targets that have no time to lie down, such as humans in combat.
As a Swarmer, you can deconstruct more things than you think. Try deconstructing light switches, buttons, air alarms and more. Experiment!
As a Swarmer, you can teleport fellow swarmers away if you think they are in danger.
+As a Swarmer, you are weak to EMP and lasers. Upon death, you will drop a bluespace crystal.
+As a Swarmer, use your ability to consume guns and other weapons to disarm the crew to keep your numbers high!
As a Morph, you can talk while disguised, but your words have a chance of being slurred, giving you away!
As a Drone, you can ping other drones to alert them of areas in the station in need of repair.
+As a Drone, you can repair yourself by using a screwdriver on yourself and standing still!
As a Ghost, you can see the inside of a container on the ground by clicking on it.
As a Ghost, you can double click on just about anything to follow it. Or just warp around!
As a Devil, you gain power for every three souls you control, however you also become more obvious.
As a Devil, as long as you control at least one other soul, you will automatically resurrect, as long as a banishment ritual is not performed.
At which time a Devil's nameth is spake on the tongue of man, the Devil may appeareth.
-As a Security Officer, remember that correlation does not equal causation. Someone may have just been at the wrong place at the wrong time!
-As a Security Officer, remember that you can attach a sec-lite to your taser or your helmet!
You can swap floor tiles by holding a crowbar in one hand and a stack of tiles in the other.
When hacking doors, cutting and mending the "test light wire" will restore power to the door.
When crafting most items, you can either manually combine parts or use the crafting menu.
Suit storage units not only remove blood and dirt from clothing, but also radiation!
Remote devices will work when used through cameras. For example: Bluespace RPEDs and door remotes.
+Laser pointers can be upgraded by replacing its micro laser with a better one from RnD! Use a screwdriver on it to remove the old laser. Upgrading the laser pointer gives you better odds of stunning a cyborg, and even blinding people with sunglasses.
diff --git a/tgstation.dme b/tgstation.dme
index b17ba9363f..c43b1a7019 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -2528,10 +2528,15 @@
#include "code\modules\research\techweb\all_nodes.dm"
#include "code\modules\research\xenobiology\xenobio_camera.dm"
#include "code\modules\research\xenobiology\xenobiology.dm"
-#include "code\modules\research\xenobiology\crossbreeding\_corecross.dm"
+#include "code\modules\research\xenobiology\crossbreeding\__corecross.dm"
+#include "code\modules\research\xenobiology\crossbreeding\_clothing.dm"
+#include "code\modules\research\xenobiology\crossbreeding\_misc.dm"
+#include "code\modules\research\xenobiology\crossbreeding\_mobs.dm"
#include "code\modules\research\xenobiology\crossbreeding\_status_effects.dm"
+#include "code\modules\research\xenobiology\crossbreeding\_weapons.dm"
#include "code\modules\research\xenobiology\crossbreeding\burning.dm"
#include "code\modules\research\xenobiology\crossbreeding\charged.dm"
+#include "code\modules\research\xenobiology\crossbreeding\chilling.dm"
#include "code\modules\research\xenobiology\crossbreeding\consuming.dm"
#include "code\modules\research\xenobiology\crossbreeding\industrial.dm"
#include "code\modules\research\xenobiology\crossbreeding\prismatic.dm"
@@ -2772,6 +2777,7 @@
#include "modular_citadel\code\datums\uplink_items_cit.dm"
#include "modular_citadel\code\datums\components\material_container.dm"
#include "modular_citadel\code\datums\components\phantomthief.dm"
+#include "modular_citadel\code\datums\components\souldeath.dm"
#include "modular_citadel\code\datums\mood_events\generic_negative_events.dm"
#include "modular_citadel\code\datums\mood_events\generic_positive_events.dm"
#include "modular_citadel\code\datums\mood_events\moodular.dm"
@@ -2798,6 +2804,7 @@
#include "modular_citadel\code\game\objects\items.dm"
#include "modular_citadel\code\game\objects\tools.dm"
#include "modular_citadel\code\game\objects\effects\spawner\spawners.dm"
+#include "modular_citadel\code\game\objects\effects\temporary_visuals\souldeath.dm"
#include "modular_citadel\code\game\objects\effects\temporary_visuals\projectiles\impact.dm"
#include "modular_citadel\code\game\objects\effects\temporary_visuals\projectiles\muzzle.dm"
#include "modular_citadel\code\game\objects\effects\temporary_visuals\projectiles\tracer.dm"
@@ -2870,6 +2877,7 @@
#include "modular_citadel\code\modules\client\loadout\uniform.dm"
#include "modular_citadel\code\modules\client\verbs\who.dm"
#include "modular_citadel\code\modules\clothing\clothing.dm"
+#include "modular_citadel\code\modules\clothing\neck.dm"
#include "modular_citadel\code\modules\clothing\glasses\phantomthief.dm"
#include "modular_citadel\code\modules\clothing\head\head.dm"
#include "modular_citadel\code\modules\clothing\spacesuits\cydonian_armor.dm"
diff --git a/tools/HumanScissors/!README.txt b/tools/HumanScissors/!README.txt
new file mode 100644
index 0000000000..d8396c8b85
--- /dev/null
+++ b/tools/HumanScissors/!README.txt
@@ -0,0 +1,7 @@
+This small Byond program takes all the icons in SpritesToSnip.dmi,
+cuts them using all the icons in CookieCutter.dmi, and produces a file save
+dialog for you to download the resulting DMI.
+
+Useful for cutting up species sprites from full body ones. Or whatever else.
+
+--Arokha/Aronai
\ No newline at end of file
diff --git a/tools/HumanScissors/CookieCutter.dmi b/tools/HumanScissors/CookieCutter.dmi
new file mode 100644
index 0000000000..f0fcf87617
Binary files /dev/null and b/tools/HumanScissors/CookieCutter.dmi differ
diff --git a/tools/HumanScissors/HumanScissors.dm b/tools/HumanScissors/HumanScissors.dm
new file mode 100644
index 0000000000..28a9f804af
--- /dev/null
+++ b/tools/HumanScissors/HumanScissors.dm
@@ -0,0 +1,56 @@
+/*
+ These are simple defaults for your project.
+ */
+
+world
+ fps = 25 // 25 frames per second
+ icon_size = 32 // 32x32 icon size by default
+
+ view = 6 // show up to 6 tiles outward from center (13x13 view)
+
+
+// Make objects move 8 pixels per tick when walking
+//usr << ftp(usr.working,"[usr.outfile].dmi")
+mob
+ step_size = 8
+
+obj
+ step_size = 8
+
+
+
+client/verb/split_sprites()
+ set name = "Begin The Decimation"
+ set desc = "Loads SpritesToSnip.dmi and cuts them with CookieCutter.dmi"
+ set category = "Here"
+
+ var/icon/SpritesToSnip = icon('SpritesToSnip.dmi')
+ var/icon/CookieCutter = icon('CookieCutter.dmi')
+
+ var/icon/RunningOutput = new ()
+
+ //For each original project
+ for(var/OriginalState in icon_states(SpritesToSnip))
+ //For each piece we're going to cut
+ for(var/CutterState in icon_states(CookieCutter))
+
+ //The fully assembled icon to cut
+ var/icon/Original = icon(SpritesToSnip,OriginalState)
+
+ //Our cookie cutter sprite
+ var/icon/Cutter = icon(CookieCutter,CutterState)
+
+ //We have to make these all black to cut with
+ Cutter.Blend(rgb(0,0,0),ICON_MULTIPLY)
+
+ //Blend with AND to cut
+ Original.Blend(Cutter,ICON_AND) //AND, not ADD
+
+ //Make a useful name
+ var/good_name = "[OriginalState]_[CutterState]"
+
+ //Add to the output with the good name
+ RunningOutput.Insert(Original,good_name)
+
+ //Give the output
+ usr << ftp(RunningOutput,"CutUpPeople.dmi")
diff --git a/tools/HumanScissors/HumanScissors.dme b/tools/HumanScissors/HumanScissors.dme
new file mode 100644
index 0000000000..86377f1c57
--- /dev/null
+++ b/tools/HumanScissors/HumanScissors.dme
@@ -0,0 +1,18 @@
+// DM Environment file for HumanScissors.dme.
+// All manual changes should be made outside the BEGIN_ and END_ blocks.
+// New source code should be placed in .dm files: choose File/New --> Code File.
+
+// BEGIN_INTERNALS
+// END_INTERNALS
+
+// BEGIN_FILE_DIR
+#define FILE_DIR .
+// END_FILE_DIR
+
+// BEGIN_PREFERENCES
+// END_PREFERENCES
+
+// BEGIN_INCLUDE
+#include "HumanScissors.dm"
+// END_INCLUDE
+
diff --git a/tools/HumanScissors/SpritesToSnip.dmi b/tools/HumanScissors/SpritesToSnip.dmi
new file mode 100644
index 0000000000..f4dbfb6b81
Binary files /dev/null and b/tools/HumanScissors/SpritesToSnip.dmi differ
|