It's so quiet...")
- H.h_style = "Bald"
+ head_organ.h_style = "Bald"
H.update_hair()
M.attack_log += text("\[[time_stamp()]\] removed antennae [H.name] ([H.ckey])")
@@ -87,7 +90,7 @@
blurb = "A sub-race of unforunates who have been exposed to too much supermatter radiation. As a result, \
supermatter crystal clusters have begun to grow across their bodies. Research to find a cure for this ailment \
has been slow, and so this is a common fate for veteran engineers. The supermatter crystals produce oxygen, \
- negating the need for the individual to breath. Their massive change in biology, however, renders most medicines \
+ negating the need for the individual to breathe. Their massive change in biology, however, renders most medicines \
obselete. Ionizing radiation seems to cause resonance in some of their crystals, which seems to encourage regeneration \
and produces a calming effect on the individual. Nucleations are highly stigmatized, and are treated much in the same \
way as lepers were back on Earth."
@@ -97,6 +100,9 @@
flags = IS_WHITELISTED | NO_BREATHE | NO_BLOOD | NO_PAIN | HAS_LIPS | NO_SCAN
dietflags = DIET_OMNI //still human at their core, so they maintain their eating habits and diet
+ //Default styles for created mobs.
+ default_hair = "Nucleation Crystals"
+
reagent_tag = PROCESS_ORG
has_organ = list(
"heart" = /obj/item/organ/internal/heart,
diff --git a/code/modules/mob/living/carbon/human/species/golem.dm b/code/modules/mob/living/carbon/human/species/golem.dm
index f3e8793fed1..922810e758d 100644
--- a/code/modules/mob/living/carbon/human/species/golem.dm
+++ b/code/modules/mob/living/carbon/human/species/golem.dm
@@ -6,7 +6,7 @@
deform = 'icons/mob/human_races/r_golem.dmi'
default_language = "Galactic Common"
- flags = NO_BREATHE | NO_BLOOD | RADIMMUNE
+ flags = NO_BREATHE | NO_BLOOD | RADIMMUNE | NOGUNS
virus_immune = 1
dietflags = DIET_OMNI //golems can eat anything because they are magic or something
reagent_tag = PROCESS_ORG
diff --git a/code/modules/mob/living/carbon/human/species/monkey.dm b/code/modules/mob/living/carbon/human/species/monkey.dm
index 72972f98baf..dffc73d4e1d 100644
--- a/code/modules/mob/living/carbon/human/species/monkey.dm
+++ b/code/modules/mob/living/carbon/human/species/monkey.dm
@@ -34,8 +34,6 @@
brute_mod = 1.5
burn_mod = 1.5
- flags = IS_RESTRICTED
-
/datum/species/monkey/handle_npc(var/mob/living/carbon/human/H)
if(H.stat != CONSCIOUS)
return
diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm
index 03091a7e50f..7430dde4331 100644
--- a/code/modules/mob/living/carbon/human/species/species.dm
+++ b/code/modules/mob/living/carbon/human/species/species.dm
@@ -118,6 +118,11 @@
var/male_scream_sound = 'sound/goonstation/voice/male_scream.ogg'
var/female_scream_sound = 'sound/goonstation/voice/female_scream.ogg'
+ //Default hair/headacc style vars.
+ var/default_hair = "Bald" //Default hair style for newly created humans unless otherwise set.
+ var/default_fhair = "Shaved" //Default facial hair style for newly created humans unless otherwise set.
+ var/default_headacc = "None" //Default head accessory style for newly created humans unless otherwise set.
+
// Determines the organs that the species spawns with and
var/list/has_organ = list( // which required-organ checks are conducted.
"heart" = /obj/item/organ/internal/heart,
@@ -158,7 +163,6 @@
/datum/species/proc/create_organs(var/mob/living/carbon/human/H) //Handles creation of mob organs.
-
for(var/obj/item/organ/internal/iorgan in H.internal_organs)
if(iorgan in H.internal_organs)
qdel(iorgan)
diff --git a/code/modules/mob/living/carbon/human/species/station.dm b/code/modules/mob/living/carbon/human/species/station.dm
index bccd2a1ffdf..19e48ba5fc0 100644
--- a/code/modules/mob/living/carbon/human/species/station.dm
+++ b/code/modules/mob/living/carbon/human/species/station.dm
@@ -55,6 +55,8 @@
flesh_color = "#34AF10"
reagent_tag = PROCESS_ORG
base_color = "#066000"
+ //Default styles for created mobs.
+ default_hair = "Unathi Horns"
allowed_consumed_mobs = list(/mob/living/simple_animal/mouse, /mob/living/simple_animal/lizard, /mob/living/simple_animal/chick, /mob/living/simple_animal/chicken,
/mob/living/simple_animal/crab, /mob/living/simple_animal/butterfly, /mob/living/simple_animal/parrot, /mob/living/simple_animal/tribble)
@@ -109,6 +111,8 @@
reagent_tag = PROCESS_ORG
flesh_color = "#AFA59E"
base_color = "#333333"
+ //Default styles for created mobs.
+ default_headacc = "Tajaran Ears"
allowed_consumed_mobs = list(/mob/living/simple_animal/mouse, /mob/living/simple_animal/chick, /mob/living/simple_animal/butterfly, /mob/living/simple_animal/parrot,
/mob/living/simple_animal/tribble)
@@ -189,6 +193,8 @@
dietflags = DIET_HERB
flesh_color = "#8CD7A3"
blood_color = "#1D2CBF"
+ //Default styles for created mobs.
+ default_hair = "Skrell Male Tentacles"
reagent_tag = PROCESS_ORG
suicide_messages = list(
@@ -251,6 +257,8 @@
blood_color = "#2299FC"
flesh_color = "#808D11"
+ //Default styles for created mobs.
+ default_hair = "Short Vox Quills"
reagent_tag = PROCESS_ORG
scream_verb = "shrieks"
@@ -751,6 +759,8 @@
dietflags = 0 //IPCs can't eat, so no diet
blood_color = "#1F181F"
flesh_color = "#AAAAAA"
+ //Default styles for created mobs.
+ default_hair = "Blue IPC Screen"
virus_immune = 1
can_revive_by_healing = 1
reagent_tag = PROCESS_SYN
@@ -791,6 +801,10 @@
)
/datum/species/machine/handle_death(var/mob/living/carbon/human/H)
- H.h_style = ""
+ var/obj/item/organ/external/head/head_organ = H.get_organ("head")
+ head_organ.h_style = "Bald"
+ head_organ.f_style = "Shaved"
spawn(100)
- if(H) H.update_hair()
+ if(H)
+ H.update_hair()
+ H.update_fhair()
\ 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 85fff9e6ead..1b5f6c25735 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -393,13 +393,13 @@ var/global/list/damage_icon_parts = list()
//base icons
var/icon/head_accessory_standing = new /icon('icons/mob/body_accessory.dmi',"accessory_none_s")
- if(ha_style && (src.species.bodyflags & HAS_HEAD_ACCESSORY))
- var/datum/sprite_accessory/head_accessory_style = head_accessory_styles_list[ha_style]
+ if(head_organ.ha_style && (head_organ.species.bodyflags & HAS_HEAD_ACCESSORY))
+ var/datum/sprite_accessory/head_accessory_style = head_accessory_styles_list[head_organ.ha_style]
if(head_accessory_style && head_accessory_style.species_allowed)
- if(src.species.name in head_accessory_style.species_allowed)
+ if(head_organ.species.name in head_accessory_style.species_allowed)
var/icon/head_accessory_s = new/icon("icon" = head_accessory_style.icon, "icon_state" = "[head_accessory_style.icon_state]_s")
if(head_accessory_style.do_colouration)
- head_accessory_s.Blend(rgb(r_headacc, g_headacc, b_headacc), ICON_ADD)
+ head_accessory_s.Blend(rgb(head_organ.r_headacc, head_organ.g_headacc, head_organ.b_headacc), ICON_ADD)
head_accessory_standing = head_accessory_s //head_accessory_standing.Blend(head_accessory_s, ICON_OVERLAY)
//Having it this way preserves animations. Useful for animated antennae.
else
@@ -429,17 +429,17 @@ var/global/list/damage_icon_parts = list()
var/icon/hair_standing = new /icon('icons/mob/human_face.dmi',"bald_s")
//var/icon/debrained_s = new /icon("icon"='icons/mob/human_face.dmi', "icon_state" = "debrained_s")
- if(h_style && !(head && (head.flags & BLOCKHEADHAIR) && !(isSynthetic())))
- var/datum/sprite_accessory/hair_style = hair_styles_list[h_style]
+ if(head_organ.h_style && !(head && (head.flags & BLOCKHEADHAIR) && !(isSynthetic())))
+ var/datum/sprite_accessory/hair_style = hair_styles_list[head_organ.h_style]
//if(!src.get_int_organ(/obj/item/organ/internal/brain) && src.get_species() != "Machine" )//make it obvious we have NO BRAIN
// hair_standing.Blend(debrained_s, ICON_OVERLAY)
if(hair_style && hair_style.species_allowed)
- if((src.species.name in hair_style.species_allowed) || (src.species.flags & ALL_RPARTS))
+ if((head_organ.species.name in hair_style.species_allowed) || (head_organ.species.flags & ALL_RPARTS)) //If the head's species is in the list of allowed species for the hairstyle, or the head's species is one flagged to have bodies comprised wholly of cybernetics...
var/icon/hair_s = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s")
- if(src.get_species() == "Slime People") // I am el worstos
+ if(head_organ.species.name == "Slime People") // I am el worstos
hair_s.Blend(rgb(r_skin, g_skin, b_skin, 160), ICON_AND)
else if(hair_style.do_colouration)
- hair_s.Blend(rgb(r_hair, g_hair, b_hair), ICON_ADD)
+ hair_s.Blend(rgb(head_organ.r_hair, head_organ.g_hair, head_organ.b_hair), ICON_ADD)
hair_standing = hair_s //hair_standing.Blend(hair_s, ICON_OVERLAY)
//Having it this way preserves animations. Useful for IPC screens.
@@ -470,15 +470,15 @@ var/global/list/damage_icon_parts = list()
//base icons
var/icon/face_standing = new /icon('icons/mob/human_face.dmi',"bald_s")
- if(f_style)
- var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[f_style]
+ if(head_organ.f_style)
+ var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[head_organ.f_style]
if(facial_hair_style && facial_hair_style.species_allowed)
- if((src.species.name in facial_hair_style.species_allowed) || (src.species.flags & ALL_RPARTS))
+ if((head_organ.species.name in facial_hair_style.species_allowed) || (head_organ.species.flags & ALL_RPARTS)) //If the head's species is in the list of allowed species for the hairstyle, or the head's species is one flagged to have bodies comprised wholly of cybernetics...
var/icon/facial_s = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_s")
- if(src.get_species() == "Slime People") // I am el worstos
+ if(head_organ.species.name == "Slime People") // I am el worstos
facial_s.Blend(rgb(r_skin, g_skin, b_skin, 160), ICON_AND)
else if(facial_hair_style.do_colouration)
- facial_s.Blend(rgb(r_facial, g_facial, b_facial), ICON_ADD)
+ facial_s.Blend(rgb(head_organ.r_facial, head_organ.g_facial, head_organ.b_facial), ICON_ADD)
face_standing.Blend(facial_s, ICON_OVERLAY)
else
//warning("Invalid f_style for [species.name]: [f_style]")
@@ -1265,22 +1265,23 @@ var/global/list/damage_icon_parts = list()
//gender no longer matters for the mouth, although there should probably be seperate base head icons.
// var/g = "m"
// if (gender == FEMALE) g = "f"
-
+ var/obj/item/organ/external/head/H = get_organ("head")
//base icons
var/icon/face_lying = new /icon('icons/mob/human_face.dmi',"bald_l")
- if(f_style)
- var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[f_style]
+
+ if(H.f_style)
+ var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[H.f_style]
if(facial_hair_style)
var/icon/facial_l = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_l")
- facial_l.Blend(rgb(r_facial, g_facial, b_facial), ICON_ADD)
+ facial_l.Blend(rgb(H.r_facial, H.g_facial, H.b_facial), ICON_ADD)
face_lying.Blend(facial_l, ICON_OVERLAY)
- if(h_style)
- var/datum/sprite_accessory/hair_style = hair_styles_list[h_style]
+ if(H.h_style)
+ var/datum/sprite_accessory/hair_style = hair_styles_list[H.h_style]
if(hair_style)
var/icon/hair_l = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_l")
- hair_l.Blend(rgb(r_hair, g_hair, b_hair), ICON_ADD)
+ hair_l.Blend(rgb(H.r_hair, H.g_hair, H.b_hair), ICON_ADD)
face_lying.Blend(hair_l, ICON_OVERLAY)
//Eyes
diff --git a/code/modules/mob/living/carbon/superheroes.dm b/code/modules/mob/living/carbon/superheroes.dm
index 08f5089a200..1ad57bd787d 100644
--- a/code/modules/mob/living/carbon/superheroes.dm
+++ b/code/modules/mob/living/carbon/superheroes.dm
@@ -148,6 +148,7 @@
/obj/effect/proc_holder/spell/targeted/recruit/cast(list/targets)
for(var/mob/living/carbon/human/target in targets)
+ var/obj/item/organ/external/head/head_organ = target.get_organ("head")
if(ticker.mode.greyshirts.len >= 3)
to_chat(usr, "You have already recruited the maximum number of henchmen.")
if(!in_range(usr, target))
@@ -210,8 +211,8 @@
to_chat(target, "You may not harm other Greyshirt or [usr]. However, you do not need to obey other Greyshirts.")
ticker.mode.greyshirts += target.mind
target.set_species("Human")
- target.h_style = "Bald"
- target.f_style = "Shaved"
+ head_organ.h_style = "Bald"
+ head_organ.f_style = "Shaved"
target.s_tone = 35
target.r_eyes = 1
target.b_eyes = 1
diff --git a/code/modules/mob/living/silicon/ai/freelook/chunk.dm b/code/modules/mob/living/silicon/ai/freelook/chunk.dm
index e4b7f983b9d..71d80df9e02 100644
--- a/code/modules/mob/living/silicon/ai/freelook/chunk.dm
+++ b/code/modules/mob/living/silicon/ai/freelook/chunk.dm
@@ -142,7 +142,7 @@
if(c.can_use())
cameras += c
- for(var/turf/t in block(locate(x, y, z), locate(min(x + CHUNK_SIZE - 1, world.maxx), min(y + CHUNK_SIZE - 1, world.maxy), z)))
+ for(var/turf/t in block(locate(max(x, 1), max(y, 1), max(z, 1)), locate(min(x + CHUNK_SIZE - 1, world.maxx), min(y + CHUNK_SIZE - 1, world.maxy), z)))
turfs[t] = t
for(var/camera in cameras)
diff --git a/code/modules/mob/living/simple_animal/bot/medbot.dm b/code/modules/mob/living/simple_animal/bot/medbot.dm
index 3534bbf55b2..80bcbc679f0 100644
--- a/code/modules/mob/living/simple_animal/bot/medbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/medbot.dm
@@ -492,7 +492,7 @@
if(reagent_id == "internal_beaker")
if(use_beaker && reagent_glass && reagent_glass.reagents.total_volume)
var/fraction = min(injection_amount/reagent_glass.reagents.total_volume, 1)
- reagent_glass.reagents.reaction(patient, 2, fraction)
+ reagent_glass.reagents.reaction(patient, INGEST, fraction)
reagent_glass.reagents.trans_to(patient, injection_amount) //Inject from beaker instead.
else
patient.reagents.add_reagent(reagent_id,injection_amount)
diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm
index ffb6f6c13b8..c427f6e7a50 100644
--- a/code/modules/mob/new_player/new_player.dm
+++ b/code/modules/mob/new_player/new_player.dm
@@ -88,13 +88,17 @@
stat("Time To Start:", "DELAYED")
if(ticker.current_state == GAME_STATE_PREGAME)
- stat("Players: [totalPlayers]", "Players Ready: [totalPlayersReady]")
+ stat("Players:", "[totalPlayers]")
+ if(client.holder)
+ stat("Players Ready:", "[totalPlayersReady]")
totalPlayers = 0
totalPlayersReady = 0
for(var/mob/new_player/player in player_list)
- stat("[player.key]", (player.ready)?("(Playing)"):(null))
+ if(client.holder)
+ stat("[player.key]", (player.ready)?("(Playing)"):(null))
totalPlayers++
- if(player.ready)totalPlayersReady++
+ if(player.ready)
+ totalPlayersReady++
/mob/new_player/Topic(href, href_list[])
if(!client) return 0
diff --git a/code/modules/mob/new_player/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories.dm
index e0fbfcdf91b..93797b5bb17 100644
--- a/code/modules/mob/new_player/sprite_accessories.dm
+++ b/code/modules/mob/new_player/sprite_accessories.dm
@@ -886,12 +886,12 @@
species_allowed = list("Vox")
vox_quills_fluff
- name = "Fluffy Quills"
+ name = "Fluffy Vox Quills"
icon_state = "vox_afro"
species_allowed = list("Vox")
vox_quills_mohawk
- name = "Quill Mohawk"
+ name = "Vox Quill Mohawk"
icon_state = "vox_mohawk"
species_allowed = list("Vox")
@@ -910,6 +910,11 @@
icon_state = "vox_nights"
species_allowed = list("Vox")
+ vox_razor
+ name = "Vox Razorback"
+ icon_state = "vox_razor"
+ species_allowed = list("Vox")
+
// Apollo-specific
//Wryn antennae
@@ -1893,22 +1898,22 @@
icon_state = "markings_tiger"
/datum/sprite_accessory/body_markings/tigerhead
- name = "Tiger Body + Head"
+ name = "Tiger Body and Head"
species_allowed = list("Unathi", "Tajaran", "Vulpkanin")
icon_state = "markings_tigerhead"
/datum/sprite_accessory/body_markings/tigerheadface_taj
- name = "Tajaran Tiger Body + Head + Face"
+ name = "Tajaran Tiger Body, Head and Face"
species_allowed = list("Tajaran")
icon_state = "markings_tigerheadface_taj"
/datum/sprite_accessory/body_markings/tigerheadface_vulp
- name = "Vulpkanin Tiger Body + Head + Face"
+ name = "Vulpkanin Tiger Body, Head and Face"
species_allowed = list("Vulpkanin")
icon_state = "markings_tigerheadface_vulp"
/datum/sprite_accessory/body_markings/tigerheadface_una
- name = "Unathi Tiger Body + Head + Face"
+ name = "Unathi Tiger Body, Head and Face"
species_allowed = list("Unathi")
icon_state = "markings_tigerheadface_una"
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index ac3dd8af716..ea70bbe88ac 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -319,6 +319,35 @@
qdel(src)
+
+/mob/living/carbon/human/proc/paize(var/name)
+ if(notransform)
+ return
+ for(var/obj/item/W in src)
+ unEquip(W)
+ regenerate_icons()
+ notransform = 1
+ canmove = 0
+ icon = null
+ invisibility = 101
+ for(var/t in organs) //this really should not be necessary
+ qdel(t)
+
+ var/obj/item/device/paicard/card = new(loc)
+ var/mob/living/silicon/pai/pai = new(card)
+ pai.key = key
+ card.setPersonality(pai)
+
+ pai.name = name
+ pai.real_name = name
+ card.name = name
+
+ to_chat(pai, "You have become a pAI! Your name is [pai.name].")
+ pai.update_pipe_vision()
+ spawn(0)//To prevent the proc from returning null.
+ qdel(src)
+ return
+
/mob/proc/safe_respawn(var/MP)
if(!MP)
return 0
diff --git a/code/modules/nano/modules/human_appearance.dm b/code/modules/nano/modules/human_appearance.dm
index 606dcade9c9..583b68b3dc6 100644
--- a/code/modules/nano/modules/human_appearance.dm
+++ b/code/modules/nano/modules/human_appearance.dm
@@ -2,9 +2,13 @@
name = "Appearance Editor"
var/flags = APPEARANCE_ALL_HAIR
var/mob/living/carbon/human/owner = null
+ var/obj/item/organ/external/head/head_organ = null
var/list/valid_species = list()
var/list/valid_hairstyles = list()
var/list/valid_facial_hairstyles = list()
+ var/list/valid_head_accessories = list()
+ var/list/valid_marking_styles = list()
+ var/list/valid_body_accessories = list()
var/check_whitelist
var/list/whitelist
@@ -13,6 +17,7 @@
/datum/nano_module/appearance_changer/New(var/location, var/mob/living/carbon/human/H, var/check_species_whitelist = 1, var/list/species_whitelist = list(), var/list/species_blacklist = list())
..()
owner = H
+ head_organ = owner.get_organ("head")
src.check_whitelist = check_species_whitelist
src.whitelist = species_whitelist
src.blacklist = species_blacklist
@@ -54,7 +59,7 @@
return 1
if(href_list["hair_color"])
if(can_change(APPEARANCE_HAIR_COLOR))
- var/new_hair = input("Please select hair color.", "Hair Color", rgb(owner.r_hair, owner.g_hair, owner.b_hair)) as color|null
+ var/new_hair = input("Please select hair color.", "Hair Color", rgb(head_organ.r_hair, head_organ.g_hair, head_organ.b_hair)) as color|null
if(new_hair && can_still_topic(state))
var/r_hair = hex2num(copytext(new_hair, 2, 4))
var/g_hair = hex2num(copytext(new_hair, 4, 6))
@@ -69,7 +74,7 @@
return 1
if(href_list["facial_hair_color"])
if(can_change(APPEARANCE_FACIAL_HAIR_COLOR))
- var/new_facial = input("Please select facial hair color.", "Facial Hair Color", rgb(owner.r_facial, owner.g_facial, owner.b_facial)) as color|null
+ var/new_facial = input("Please select facial hair color.", "Facial Hair Color", rgb(head_organ.r_facial, head_organ.g_facial, head_organ.b_facial)) as color|null
if(new_facial && can_still_topic(state))
var/r_facial = hex2num(copytext(new_facial, 2, 4))
var/g_facial = hex2num(copytext(new_facial, 4, 6))
@@ -87,6 +92,41 @@
if(owner.change_eye_color(r_eyes, g_eyes, b_eyes))
update_dna()
return 1
+ if(href_list["head_accessory"])
+ if(can_change_head_accessory() && (href_list["head_accessory"] in valid_head_accessories))
+ if(owner.change_head_accessory(href_list["head_accessory"]))
+ update_dna()
+ return 1
+ if(href_list["head_accessory_color"])
+ if(can_change_head_accessory())
+ var/new_head_accessory = input("Please select head accessory color.", "Head Accessory Color", rgb(head_organ.r_headacc, head_organ.g_headacc, head_organ.b_headacc)) as color|null
+ if(new_head_accessory && can_still_topic(state))
+ var/r_headacc = hex2num(copytext(new_head_accessory, 2, 4))
+ var/g_headacc = hex2num(copytext(new_head_accessory, 4, 6))
+ var/b_headacc = hex2num(copytext(new_head_accessory, 6, 8))
+ if(owner.change_head_accessory_color(r_headacc, g_headacc, b_headacc))
+ update_dna()
+ return 1
+ if(href_list["marking"])
+ if(can_change_markings() && (href_list["marking"] in valid_marking_styles))
+ if(owner.change_markings(href_list["marking"]))
+ update_dna()
+ return 1
+ if(href_list["marking_color"])
+ if(can_change_markings())
+ var/new_markings = input("Please select marking color.", "Marking Color", rgb(owner.r_markings, owner.g_markings, owner.b_markings)) as color|null
+ if(new_markings && can_still_topic(state))
+ var/r_markings = hex2num(copytext(new_markings, 2, 4))
+ var/g_markings = hex2num(copytext(new_markings, 4, 6))
+ var/b_markings = hex2num(copytext(new_markings, 6, 8))
+ if(owner.change_marking_color(r_markings, g_markings, b_markings))
+ update_dna()
+ return 1
+ if(href_list["body_accessory"])
+ if(can_change_body_accessory() && (href_list["body_accessory"] in valid_body_accessories))
+ if(owner.change_body_accessory(href_list["body_accessory"]))
+ update_dna()
+ return 1
return 0
@@ -107,13 +147,21 @@
data["change_skin_tone"] = can_change_skin_tone()
data["change_skin_color"] = can_change_skin_color()
data["change_eye_color"] = can_change(APPEARANCE_EYE_COLOR)
+ data["change_head_accessory"] = can_change_head_accessory()
+ if(data["change_head_accessory"])
+ var/head_accessory_styles[0]
+ for(var/head_accessory_style in valid_head_accessories)
+ head_accessory_styles[++head_accessory_styles.len] = list("headaccessorystyle" = head_accessory_style)
+ data["head_accessory_styles"] = head_accessory_styles
+ data["head_accessory_style"] = head_organ.ha_style
+
data["change_hair"] = can_change(APPEARANCE_HAIR)
if(data["change_hair"])
var/hair_styles[0]
for(var/hair_style in valid_hairstyles)
hair_styles[++hair_styles.len] = list("hairstyle" = hair_style)
data["hair_styles"] = hair_styles
- data["hair_style"] = owner.h_style
+ data["hair_style"] = head_organ.h_style
data["change_facial_hair"] = can_change(APPEARANCE_FACIAL_HAIR)
if(data["change_facial_hair"])
@@ -121,10 +169,31 @@
for(var/facial_hair_style in valid_facial_hairstyles)
facial_hair_styles[++facial_hair_styles.len] = list("facialhairstyle" = facial_hair_style)
data["facial_hair_styles"] = facial_hair_styles
- data["facial_hair_style"] = owner.f_style
+ data["facial_hair_style"] = head_organ.f_style
+ data["change_markings"] = can_change_markings()
+ if(data["change_markings"])
+ var/marking_styles[0]
+ for(var/marking_style in valid_marking_styles)
+ marking_styles[++marking_styles.len] = list("markingstyle" = marking_style)
+ data["marking_styles"] = marking_styles
+ data["marking_style"] = owner.m_style
+
+ data["change_body_accessory"] = can_change_body_accessory()
+ if(data["change_body_accessory"])
+ var/body_accessory_styles[0]
+ for(var/body_accessory_style in valid_body_accessories)
+ body_accessory_styles[++body_accessory_styles.len] = list("bodyaccessorystyle" = body_accessory_style)
+ data["body_accessory_styles"] = body_accessory_styles
+ var/datum/body_accessory/BA
+ if(owner.body_accessory)
+ BA = owner.body_accessory.name
+ data["body_accessory_style"] = BA
+
+ data["change_head_accessory_color"] = can_change_head_accessory()
data["change_hair_color"] = can_change(APPEARANCE_HAIR_COLOR)
data["change_facial_hair_color"] = can_change(APPEARANCE_FACIAL_HAIR_COLOR)
+ data["change_marking_color"] = can_change_markings()
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "appearance_changer.tmpl", "[src]", 800, 450, state = state)
@@ -145,10 +214,22 @@
/datum/nano_module/appearance_changer/proc/can_change_skin_color()
return owner && (flags & APPEARANCE_SKIN) && (owner.species.bodyflags & HAS_SKIN_COLOR)
+/datum/nano_module/appearance_changer/proc/can_change_head_accessory()
+ return owner && (flags & APPEARANCE_HEAD_ACCESSORY) && (head_organ.species.bodyflags & HAS_HEAD_ACCESSORY)
+
+/datum/nano_module/appearance_changer/proc/can_change_markings()
+ return owner && (flags & APPEARANCE_MARKINGS) && (owner.species.bodyflags & HAS_MARKINGS)
+
+/datum/nano_module/appearance_changer/proc/can_change_body_accessory()
+ return owner && (flags & APPEARANCE_BODY_ACCESSORY) && (owner.species.bodyflags & HAS_TAIL)
+
/datum/nano_module/appearance_changer/proc/cut_and_generate_data()
// Making the assumption that the available species remain constant
+ valid_hairstyles.Cut()
valid_facial_hairstyles.Cut()
- valid_facial_hairstyles.Cut()
+ valid_head_accessories.Cut()
+ valid_marking_styles.Cut()
+ valid_body_accessories.Cut()
generate_data()
/datum/nano_module/appearance_changer/proc/generate_data()
@@ -158,4 +239,10 @@
valid_species = owner.generate_valid_species(check_whitelist, whitelist, blacklist)
if(!valid_hairstyles.len || !valid_facial_hairstyles.len)
valid_hairstyles = owner.generate_valid_hairstyles()
- valid_facial_hairstyles = owner.generate_valid_facial_hairstyles()
\ No newline at end of file
+ valid_facial_hairstyles = owner.generate_valid_facial_hairstyles()
+ if(!valid_head_accessories.len)
+ valid_head_accessories = owner.generate_valid_head_accessories()
+ if(!valid_marking_styles.len)
+ valid_marking_styles = owner.generate_valid_markings()
+ if(!valid_body_accessories.len)
+ valid_body_accessories = owner.generate_valid_body_accessories()
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index a4858a4a8c8..cb4f21d2497 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -134,11 +134,8 @@
return
if(ishuman(user))
var/mob/living/carbon/human/H = user
- if(H.get_species() == "Golem")
- to_chat(user, "Your metal fingers don't fit in the trigger guard!")
- return
- if(H.get_species() == "Shadowling")
- to_chat(user, "The muzzle flash would cause damage to your form!")
+ if(H.species.flags & NOGUNS)
+ to_chat(user, "Your fingers don't fit in the trigger guard!")
return
if(H.martial_art && H.martial_art.name == "The Sleeping Carp") //great dishonor to famiry
to_chat(user, "Use of ranged weaponry would bring dishonor to the clan.")
diff --git a/code/modules/reagents/Chemistry-Holder.dm b/code/modules/reagents/Chemistry-Holder.dm
index 1b2e9a0b3d4..9be9ea9c124 100644
--- a/code/modules/reagents/Chemistry-Holder.dm
+++ b/code/modules/reagents/Chemistry-Holder.dm
@@ -387,45 +387,48 @@ var/const/INGEST = 2
can_process = 1
return can_process
-/datum/reagents/proc/reaction(var/atom/A, var/method=TOUCH, var/volume_modifier=0)
-
+/datum/reagents/proc/reaction(atom/A, method=TOUCH, volume_modifier = 1)
switch(method)
if(TOUCH)
for(var/datum/reagent/R in reagent_list)
if(ismob(A))
- spawn(0)
- if(!R) return
- var/check = reaction_check(A, R)
- if(!check)
- continue
- else
- R.reaction_mob(A, TOUCH, R.volume+volume_modifier)
+ if(!R)
+ return
+ var/check = reaction_check(A, R)
+ if(!check)
+ continue
+ else
+ R.reaction_mob(A, TOUCH, R.volume*volume_modifier)
if(isturf(A))
- spawn(0)
- if(!R) return
- else R.reaction_turf(A, R.volume+volume_modifier)
+ if(!R)
+ return
+ else
+ R.reaction_turf(A, R.volume*volume_modifier)
if(isobj(A))
- spawn(0)
- if(!R) return
- else R.reaction_obj(A, R.volume+volume_modifier)
+ if(!R)
+ return
+ else
+ R.reaction_obj(A, R.volume*volume_modifier)
if(INGEST)
for(var/datum/reagent/R in reagent_list)
if(ismob(A) && R)
- spawn(0)
- if(!R) return
- var/check = reaction_check(A, R)
- if(!check)
- continue
- else
- R.reaction_mob(A, INGEST, R.volume+volume_modifier)
+ if(!R)
+ return
+ var/check = reaction_check(A, R)
+ if(!check)
+ continue
+ else
+ R.reaction_mob(A, INGEST, R.volume*volume_modifier)
if(isturf(A) && R)
- spawn(0)
- if(!R) return
- else R.reaction_turf(A, R.volume+volume_modifier)
+ if(!R)
+ return
+ else
+ R.reaction_turf(A, R.volume*volume_modifier)
if(isobj(A) && R)
- spawn(0)
- if(!R) return
- else R.reaction_obj(A, R.volume+volume_modifier)
+ if(!R)
+ return
+ else
+ R.reaction_obj(A, R.volume*volume_modifier)
return
/datum/reagents/proc/add_reagent_list(list/list_reagents, list/data=null) // Like add_reagent but you can enter a list. Format it like this: list("toxin" = 10, "beer" = 15)
diff --git a/code/modules/reagents/newchem/drugs.dm b/code/modules/reagents/newchem/drugs.dm
index 127a37593d1..62daeee99a3 100644
--- a/code/modules/reagents/newchem/drugs.dm
+++ b/code/modules/reagents/newchem/drugs.dm
@@ -337,9 +337,10 @@
var/check = rand(0,100)
if(ishuman(M))
var/mob/living/carbon/human/H = M
- if(check < 8 && H.h_style != "Very Long Beard")
- H.h_style = "Very Long Hair"
- H.f_style = "Very Long Beard"
+ var/obj/item/organ/external/head/head_organ = H.get_organ("head")
+ if(check < 8 && head_organ.h_style != "Very Long Beard")
+ head_organ.h_style = "Very Long Hair"
+ head_organ.f_style = "Very Long Beard"
H.update_hair()
H.update_fhair()
H.visible_message("[H] has a wild look in their eyes!")
diff --git a/code/modules/reagents/newchem/other.dm b/code/modules/reagents/newchem/other.dm
index 7ef7dff6ff5..1e31ba5b506 100644
--- a/code/modules/reagents/newchem/other.dm
+++ b/code/modules/reagents/newchem/other.dm
@@ -198,12 +198,13 @@ datum/reagent/hair_dye
datum/reagent/hair_dye/reaction_mob(var/mob/living/M, var/volume)
if(M && ishuman(M))
var/mob/living/carbon/human/H = M
- H.r_facial = rand(0,255)
- H.g_facial = rand(0,255)
- H.b_facial = rand(0,255)
- H.r_hair = rand(0,255)
- H.g_hair = rand(0,255)
- H.b_hair = rand(0,255)
+ var/obj/item/organ/external/head/head_organ = H.get_organ("head")
+ head_organ.r_facial = rand(0,255)
+ head_organ.g_facial = rand(0,255)
+ head_organ.b_facial = rand(0,255)
+ head_organ.r_hair = rand(0,255)
+ head_organ.g_hair = rand(0,255)
+ head_organ.b_hair = rand(0,255)
H.update_hair()
H.update_fhair()
..()
@@ -228,8 +229,9 @@ datum/reagent/hairgrownium
datum/reagent/hairgrownium/reaction_mob(var/mob/living/M, var/volume)
if(M && ishuman(M))
var/mob/living/carbon/human/H = M
- H.h_style = random_hair_style(H.gender, H.species)
- H.f_style = random_facial_hair_style(H.gender, H.species)
+ var/obj/item/organ/external/head/head_organ = H.get_organ("head")
+ head_organ.h_style = random_hair_style(H.gender, head_organ.species.name)
+ head_organ.f_style = random_facial_hair_style(H.gender, head_organ.species.name)
H.update_hair()
H.update_fhair()
..()
@@ -252,12 +254,21 @@ datum/reagent/super_hairgrownium
result_amount = 3
mix_message = "The liquid becomes amazingly furry and smells peculiar."
-datum/reagent/super_hairgrownium/on_mob_life(var/mob/living/M as mob)
- if(!M) M = holder.my_atom
+datum/reagent/super_hairgrownium/reaction_mob(var/mob/living/M, var/volume)
if(M && ishuman(M))
var/mob/living/carbon/human/H = M
- H.h_style = "Very Long Hair"
- H.f_style = "Very Long Beard"
+ var/obj/item/organ/external/head/head_organ = H.get_organ("head")
+ var/datum/sprite_accessory/tmp_hair_style = hair_styles_list["Very Long Hair"]
+ var/datum/sprite_accessory/tmp_facial_hair_style = facial_hair_styles_list["Very Long Beard"]
+
+ if(head_organ.species.name in tmp_hair_style.species_allowed) //If 'Very Long Hair' is a style the person's species can have, give it to them.
+ head_organ.h_style = "Very Long Hair"
+ else //Otherwise, give them a random hair style.
+ head_organ.h_style = random_hair_style(H.gender, head_organ.species.name)
+ if(head_organ.species.name in tmp_facial_hair_style.species_allowed) //If 'Very Long Beard' is a style the person's species can have, give it to them.
+ head_organ.f_style = "Very Long Beard"
+ else //Otherwise, give them a random facial hair style.
+ head_organ.f_style = random_facial_hair_style(H.gender, head_organ.species.name)
H.update_hair()
H.update_fhair()
if(!H.wear_mask || H.wear_mask && !istype(H.wear_mask, /obj/item/clothing/mask/fakemoustache))
diff --git a/code/modules/reagents/newchem/pyro.dm b/code/modules/reagents/newchem/pyro.dm
index b4070440ab3..655b8e996eb 100644
--- a/code/modules/reagents/newchem/pyro.dm
+++ b/code/modules/reagents/newchem/pyro.dm
@@ -293,7 +293,7 @@ datum/reagent/blackpowder/reaction_turf(var/turf/T, var/volume) //oh shit
required_reagents = list("potassium" = 1, "sugar" = 1, "phosphorus" = 1)
result_amount = 1
mix_message = "The mixture quickly turns into a pall of smoke!"
- var/forbidden_reagents = list("sugar", "phosphorus", "potassium") //Do not transfer this stuff through smoke.
+ var/forbidden_reagents = list("sugar", "phosphorus", "potassium", "stimulants") //Do not transfer this stuff through smoke.
/datum/chemical_reaction/smoke/on_reaction(var/datum/reagents/holder, var/created_volume)
for(var/f_reagent in forbidden_reagents)
@@ -325,7 +325,7 @@ datum/reagent/blackpowder/reaction_turf(var/turf/T, var/volume) //oh shit
min_temp = 374
secondary = 1
result_amount = 1
- forbidden_reagents = list()
+ forbidden_reagents = list("stimulants")
mix_sound = null
/datum/reagent/sonic_powder
diff --git a/code/modules/scripting/Implementations/Telecomms.dm b/code/modules/scripting/Implementations/Telecomms.dm
index b85d63fac2b..273ccb67d0e 100644
--- a/code/modules/scripting/Implementations/Telecomms.dm
+++ b/code/modules/scripting/Implementations/Telecomms.dm
@@ -60,6 +60,9 @@
return
interpreter.container = src
+
+ interpreter.CreateGlobalScope() // Reset the variables.
+ interpreter.curScope = interpreter.globalScope
interpreter.SetVar("PI", 3.141592653) // value of pi
interpreter.SetVar("E", 2.718281828) // value of e
@@ -127,7 +130,7 @@
@param time: time to sleep in deciseconds (1/10th second)
*/
- interpreter.SetProc("sleep", /proc/delay)
+ interpreter.SetProc("sleep", "delay", signal, list("time"))
/*
-> Replaces a string with another string
@@ -255,6 +258,28 @@
signal.data["reject"] = 1
/* -- Actual language proc code -- */
+/datum/signal/proc/delay(var/time)
+ var/obj/machinery/telecomms/server/S = data["server"]
+ var/datum/n_Interpreter/TCS_Interpreter/interpreter = S.Compiler.interpreter
+ // Backup the scope
+ var/datum/scope/globalScope = interpreter.globalScope
+ var/datum/scope/curScope = interpreter.curScope
+ var/list/scopes = interpreter.scopes.stack.Copy()
+ var/list/functions = interpreter.functions.stack.Copy()
+ var/datum/node/statement/FunctionDefinition/curFunction = interpreter.curFunction
+ var/status = interpreter.status
+ var/returnVal = interpreter.returnVal
+ // Sleep
+ sleep(time)
+ // Restore the scope
+ interpreter.returnVal = returnVal
+ interpreter.status = status
+ interpreter.curFunction = curFunction
+ interpreter.functions.stack = functions
+ interpreter.scopes.stack = scopes
+ interpreter.curScope = curScope
+ interpreter.globalScope = globalScope
+
/datum/signal/proc/mem(var/address, var/value)
if(istext(address))
var/obj/machinery/telecomms/server/S = data["server"]
diff --git a/code/modules/scripting/Implementations/_Logic.dm b/code/modules/scripting/Implementations/_Logic.dm
index 6befaa6f0eb..c31d55f3077 100644
--- a/code/modules/scripting/Implementations/_Logic.dm
+++ b/code/modules/scripting/Implementations/_Logic.dm
@@ -99,11 +99,6 @@
// --- Miscellaneous functions ---
-// Clone of sleep()
-/proc/delay(var/time)
- //writepanic("[__FILE__].[__LINE__] (no type)([usr ? usr.ckey : ""]) \\/proc/delay() called tick#: [world.time]")
- sleep(time)
-
// Clone of rand()
/proc/rand_chance(var/low = 0, var/high)
//writepanic("[__FILE__].[__LINE__] (no type)([usr ? usr.ckey : ""]) \\/proc/rand_chance() called tick#: [world.time]")
diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm
index 2a794de2ff8..119378d53f4 100644
--- a/code/modules/shuttle/shuttle.dm
+++ b/code/modules/shuttle/shuttle.dm
@@ -683,7 +683,12 @@
to_chat(usr, "Access denied.")
return
+ var/list/options = params2list(possible_destinations)
if(href_list["move"])
+ if(!options.Find(href_list["move"])) //I see you're trying Href exploits, I see you're failing, I SEE ADMIN WARNING.
+ // Seriously, though, NEVER trust a Topic with something like this. Ever.
+ message_admins("move HREF ([src] attempted to move to: [href_list["move"]]) exploit attempted by [key_name_admin(usr)] on [src] (JMP)")
+ return
switch(shuttle_master.moveShuttle(shuttleId, href_list["move"], 1))
if(0)
to_chat(usr, "Shuttle received message and will be sent shortly.")
diff --git a/code/modules/surgery/limb_reattach.dm b/code/modules/surgery/limb_reattach.dm
index 3386f4b9366..90f2d9afed0 100644
--- a/code/modules/surgery/limb_reattach.dm
+++ b/code/modules/surgery/limb_reattach.dm
@@ -97,10 +97,12 @@
E.forceMove(target)
if(target.get_species() == "Machine")//as this is the only step needed for ipc put togethers
if(target_zone == "head")
- var/obj/item/organ/external/head/H = target.organs_by_name["head"]
+ var/obj/item/organ/external/head/H = target.get_organ("head")
var/datum/robolimb/robohead = all_robolimbs[H.model]
if(robohead.is_monitor) //Ensures that if an IPC gets a head that's got a human hair wig attached to their body, the hair won't wipe.
- target.h_style = ""
+ H.h_style = ""
+ H.f_style = ""
+ target.m_style = ""
E.status &= ~ORGAN_DESTROYED
if(E.children)
for(var/obj/item/organ/external/C in E.children)
diff --git a/code/modules/surgery/organs/blood.dm b/code/modules/surgery/organs/blood.dm
index f2dd4c3c778..c1a1c7562a9 100644
--- a/code/modules/surgery/organs/blood.dm
+++ b/code/modules/surgery/organs/blood.dm
@@ -190,7 +190,9 @@ var/const/BLOOD_VOLUME_SURVIVE = 122
if(src.species.exotic_blood)
vessel.remove_reagent(species.exotic_blood,amm)
- vessel.reaction(T, TOUCH, amm)
+ if(vessel.total_volume)
+ var/fraction = amm / vessel.total_volume
+ vessel.reaction(T, TOUCH, fraction)
return
else
diff --git a/code/modules/surgery/organs/organ_icon.dm b/code/modules/surgery/organs/organ_icon.dm
index db6ffd81a2a..0488d768adf 100644
--- a/code/modules/surgery/organs/organ_icon.dm
+++ b/code/modules/surgery/organs/organ_icon.dm
@@ -54,6 +54,7 @@ var/global/list/limb_icon_cache = list()
overlays.Cut()
if(!owner)
return
+ var/obj/item/organ/external/head/H = owner.get_organ("head")
if(species.has_organ["eyes"])
var/obj/item/organ/internal/eyes/eyes = owner.get_int_organ(/obj/item/organ/internal/eyes)//owner.internal_organs_by_name["eyes"]
@@ -79,32 +80,32 @@ var/global/list/limb_icon_cache = list()
markings_s.Blend(rgb(owner.r_markings, owner.g_markings, owner.b_markings), ICON_ADD)
overlays |= markings_s
- if(owner.ha_style)
- var/datum/sprite_accessory/head_accessory_style = head_accessory_styles_list[owner.ha_style]
- if(head_accessory_style && head_accessory_style.species_allowed && (species.name in head_accessory_style.species_allowed))
+ if(H.ha_style)
+ var/datum/sprite_accessory/head_accessory_style = head_accessory_styles_list[H.ha_style]
+ if(head_accessory_style && head_accessory_style.species_allowed && (H.species.name in head_accessory_style.species_allowed))
var/icon/head_accessory_s = new/icon("icon" = head_accessory_style.icon, "icon_state" = "[head_accessory_style.icon_state]_s")
if(head_accessory_style.do_colouration)
- head_accessory_s.Blend(rgb(owner.r_headacc, owner.g_headacc, owner.b_headacc), ICON_ADD)
+ head_accessory_s.Blend(rgb(H.r_headacc, H.g_headacc, H.b_headacc), ICON_ADD)
overlays |= head_accessory_s
- if(owner.f_style)
- var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[owner.f_style]
- if(facial_hair_style && ((facial_hair_style.species_allowed && (species.name in facial_hair_style.species_allowed)) || (src.species.flags & ALL_RPARTS)))
+ if(H.f_style)
+ var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[H.f_style]
+ if(facial_hair_style && ((facial_hair_style.species_allowed && (H.species.name in facial_hair_style.species_allowed)) || (src.species.flags & ALL_RPARTS)))
var/icon/facial_s = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_s")
- if(species.name == "Slime People") // I am el worstos
+ if(H.species.name == "Slime People") // I am el worstos
facial_s.Blend(rgb(owner.r_skin, owner.g_skin, owner.b_skin, 160), ICON_AND)
else if(facial_hair_style.do_colouration)
- facial_s.Blend(rgb(owner.r_facial, owner.g_facial, owner.b_facial), ICON_ADD)
+ facial_s.Blend(rgb(H.r_facial, H.g_facial, H.b_facial), ICON_ADD)
overlays |= facial_s
- if(owner.h_style && !(owner.head && (owner.head.flags & BLOCKHEADHAIR)))
- var/datum/sprite_accessory/hair_style = hair_styles_list[owner.h_style]
- if(hair_style && ((species.name in hair_style.species_allowed) || (src.species.flags & ALL_RPARTS)))
+ if(H.h_style && !(owner.head && (owner.head.flags & BLOCKHEADHAIR)))
+ var/datum/sprite_accessory/hair_style = hair_styles_list[H.h_style]
+ if(hair_style && ((H.species.name in hair_style.species_allowed) || (src.species.flags & ALL_RPARTS)))
var/icon/hair_s = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s")
- if(species.name == "Slime People") // I am el worstos
+ if(H.species.name == "Slime People") // I am el worstos
hair_s.Blend(rgb(owner.r_skin, owner.g_skin, owner.b_skin, 160), ICON_AND)
else if(hair_style.do_colouration)
- hair_s.Blend(rgb(owner.r_hair, owner.g_hair, owner.b_hair), ICON_ADD)
+ hair_s.Blend(rgb(H.r_hair, H.g_hair, H.b_hair), ICON_ADD)
overlays |= hair_s
return mob_icon
diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm
index 248da9d1154..8c80b58519a 100644
--- a/code/modules/surgery/organs/organ_internal.dm
+++ b/code/modules/surgery/organs/organ_internal.dm
@@ -499,18 +499,19 @@
if(istype(owner, /mob/living/carbon/human))
var/mob/living/carbon/human/H = owner
- if(!(H.h_style == "Very Long Hair" || H.h_style == "Mowhawk"))
+ var/obj/item/organ/external/head/head_organ = H.get_organ("head")
+ if(!(head_organ.h_style == "Very Long Hair" || head_organ.h_style == "Mohawk"))
if(prob(10))
- H.h_style = "Mohawk"
+ head_organ.h_style = "Mohawk"
else
- H.h_style = "Very Long Hair"
- H.r_hair = 216
- H.g_hair = 192
- H.b_hair = 120
+ head_organ.h_style = "Very Long Hair"
+ head_organ.r_hair = 216
+ head_organ.g_hair = 192
+ head_organ.b_hair = 120
H.update_hair()
- if(!(H.f_style == "Very Long Beard"))
- H.f_style = "Very Long Beard"
- H.r_facial = 216
- H.g_facial = 192
- H.b_facial = 120
+ if(!(head_organ.f_style == "Very Long Beard"))
+ head_organ.f_style = "Very Long Beard"
+ head_organ.r_facial = 216
+ head_organ.g_facial = 192
+ head_organ.b_facial = 120
H.update_fhair()
\ No newline at end of file
diff --git a/code/modules/surgery/organs/subtypes/standard.dm b/code/modules/surgery/organs/subtypes/standard.dm
index c9cbbb17906..d481ba1b7ae 100644
--- a/code/modules/surgery/organs/subtypes/standard.dm
+++ b/code/modules/surgery/organs/subtypes/standard.dm
@@ -141,6 +141,24 @@
encased = "skull"
var/can_intake_reagents = 1
+ //Hair colour and style
+ var/r_hair = 0
+ var/g_hair = 0
+ var/b_hair = 0
+ var/h_style = "Bald"
+
+ //Head accessory colour and style
+ var/r_headacc = 0
+ var/g_headacc = 0
+ var/b_headacc = 0
+ var/ha_style = "None"
+
+ //Facial hair colour and style
+ var/r_facial = 0
+ var/g_facial = 0
+ var/b_facial = 0
+ var/f_style = "Shaved"
+
/obj/item/organ/external/head/remove()
if(owner)
if(!istype(dna))
diff --git a/config/example/game_options.txt b/config/example/game_options.txt
index 69847e0a6b6..5d82bfb425d 100644
--- a/config/example/game_options.txt
+++ b/config/example/game_options.txt
@@ -54,6 +54,10 @@ ANIMAL_DELAY 0
## Uncomment for explosions that react to doors and walls
REACTIONARY_EXPLOSIONS
+# The number of objectives traitors get.
+# Not including escaping/hijacking.
+TRAITOR_OBJECTIVES_AMOUNT 2
+
### Configure the bomb cap
## This caps all explosions to the specified range. Used for both balance reasons and to prevent overloading the server and lagging the game out.
## This is given as the 3rd number(light damage) in the standard (1,2,3) explosion notation. The other numbers are derived by dividing by 2 and 4.
diff --git a/html/changelogs/AutoChangeLog-pr-4231.yml b/html/changelogs/AutoChangeLog-pr-4231.yml
new file mode 100644
index 00000000000..047c22c3b30
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4231.yml
@@ -0,0 +1,4 @@
+author: monster860
+delete-after: True
+changes:
+ - bugfix: "Fixes sleep() in telecomms"
diff --git a/html/changelogs/AutoChangeLog-pr-4331.yml b/html/changelogs/AutoChangeLog-pr-4331.yml
new file mode 100644
index 00000000000..f6ca1298944
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4331.yml
@@ -0,0 +1,14 @@
+author: KasparoVy
+delete-after: True
+changes:
+ - tweak: "Refactors hair so it's on the head (organ)."
+ - tweak: "Adjusts some Vox hair style names so they're consistent with all others."
+ - tweak: "Refactors Morph and the order by which options are presented."
+ - tweak: "Players with heads of a different species than the body will now only be able to access the head accessories, hair/facial hair styles of the head's species."
+ - bugfix: "Fixes some typos."
+ - bugfix: "Fixes a bug where hairgrownium made you bald and super hairgrownium only changed the hair/facial hair styles of Humans."
+ - bugfix: "Fixes a bug where Morph wouldn't correctly set eye colour or skin tone."
+ - bugfix: "Fixes a typo that didn't really have any negative effect on the beard organ to begin with."
+ - bugfix: "Fixes bugs where Alopecia and Facial Hypertrichosis disease symptoms wouldn't update player sprite correctly."
+ - rscadd: "Adds a new Vox hairstyle."
+ - rscadd: "You can now change your head accessory (and its colour), body markings (and their colour), and body accessory if you're a species that has such things via the Morph genetic power and C.M.A. (the bathroom SalonPro Nano-Mirrors and admin verbs)."
diff --git a/html/changelogs/AutoChangeLog-pr-4375.yml b/html/changelogs/AutoChangeLog-pr-4375.yml
new file mode 100644
index 00000000000..5556d1b71b2
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4375.yml
@@ -0,0 +1,4 @@
+author: monster860
+delete-after: True
+changes:
+ - rscadd: "Windows can now be constructed and deconstructed using RCD's."
diff --git a/html/changelogs/AutoChangeLog-pr-4391.yml b/html/changelogs/AutoChangeLog-pr-4391.yml
new file mode 100644
index 00000000000..8567b77dbee
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4391.yml
@@ -0,0 +1,6 @@
+author: Fox MCCloud
+delete-after: True
+changes:
+ - tweak: "Removes \"harm\" traitor objective"
+ - tweak: "Increases non-escape/hijack/die objectives from 1 to 2"
+ - tweak: "Tweaks available objectives to traitors a bit"
diff --git a/html/changelogs/AutoChangeLog-pr-4401.yml b/html/changelogs/AutoChangeLog-pr-4401.yml
new file mode 100644
index 00000000000..8f9a142b383
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4401.yml
@@ -0,0 +1,4 @@
+author: Fox McCloud
+delete-after: True
+changes:
+ - tweak: "Players can no longer see how many players have readied up or who has readied up"
diff --git a/html/changelogs/AutoChangeLog-pr-4407.yml b/html/changelogs/AutoChangeLog-pr-4407.yml
new file mode 100644
index 00000000000..936843c7952
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4407.yml
@@ -0,0 +1,4 @@
+author: Fox McCloud
+delete-after: True
+changes:
+ - tweak: "Hulks, Shadowlings, and Golems can no longer use laserpointers"
diff --git a/html/changelogs/AutoChangeLog-pr-4415.yml b/html/changelogs/AutoChangeLog-pr-4415.yml
new file mode 100644
index 00000000000..25ae9a07845
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4415.yml
@@ -0,0 +1,4 @@
+author: Fox McCloud
+delete-after: True
+changes:
+ - rscadd: "Adds in the ability to flip over someone with *flip"
diff --git a/html/changelogs/AutoChangeLog-pr-4423.yml b/html/changelogs/AutoChangeLog-pr-4423.yml
new file mode 100644
index 00000000000..c59bf34afcb
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4423.yml
@@ -0,0 +1,4 @@
+author: Fox McCloud
+delete-after: True
+changes:
+ - tweak: "Fixes and improves foam to better interact with reagents"
diff --git a/html/changelogs/AutoChangeLog-pr-4427.yml b/html/changelogs/AutoChangeLog-pr-4427.yml
new file mode 100644
index 00000000000..fdec7855212
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4427.yml
@@ -0,0 +1,4 @@
+author: AugRob
+delete-after: True
+changes:
+ - rscadd: "Add screwdriver sound when opening/closing panels on airlocks"
diff --git a/icons/mob/human_face.dmi b/icons/mob/human_face.dmi
index f036d7e3111..a53d468804d 100644
Binary files a/icons/mob/human_face.dmi and b/icons/mob/human_face.dmi differ
diff --git a/nano/templates/appearance_changer.tmpl b/nano/templates/appearance_changer.tmpl
index 19e7fd4759b..886076f21d2 100644
--- a/nano/templates/appearance_changer.tmpl
+++ b/nano/templates/appearance_changer.tmpl
@@ -23,7 +23,7 @@
{{/if}}
-{{if data.change_eye_color || data.change_skin_tone || data.change_skin_color || data.change_hair_color || data.change_facial_hair_color}}
+{{if data.change_eye_color || data.change_skin_tone || data.change_skin_color || data.change_head_accessory_color || data.change_hair_color || data.change_facial_hair_color || data.change_marking_color}}
Colors:
@@ -38,12 +38,31 @@
{{if data.change_skin_color}}
{{:helper.link('Change skin color', null, { 'skin_color' : 1})}}
{{/if}}
+ {{if data.change_head_accessory_color}}
+ {{:helper.link('Change head accessory color', null, { 'head_accessory_color' : 1})}}
+ {{/if}}
{{if data.change_hair_color}}
{{:helper.link('Change hair color', null, { 'hair_color' : 1})}}
{{/if}}
{{if data.change_facial_hair_color}}
{{:helper.link('Change facial hair color', null, { 'facial_hair_color' : 1})}}
{{/if}}
+ {{if data.change_marking_color}}
+ {{:helper.link('Change marking color', null, { 'marking_color' : 1})}}
+ {{/if}}
+
+
+{{/if}}
+
+{{if data.change_head_accessory}}
+
+
+ Head accessory styles:
+
+
+ {{for data.head_accessory_styles}}
+ {{:helper.link(value.headaccessorystyle, null, { 'head_accessory' : value.headaccessorystyle}, null, data.head_accessory_style == value.headaccessorystyle ? 'selected' : null)}}
+ {{/for}}
{{/if}}
@@ -73,3 +92,29 @@
{{/if}}
+
+{{if data.change_markings}}
+
+
+ Marking styles:
+
+
+ {{for data.marking_styles}}
+ {{:helper.link(value.markingstyle, null, { 'marking' : value.markingstyle}, null, data.marking_style == value.markingstyle ? 'selected' : null)}}
+ {{/for}}
+
+
+{{/if}}
+
+{{if data.change_body_accessory}}
+
+
+ Body accessory styles:
+
+
+ {{for data.body_accessory_styles}}
+ {{:helper.link(value.bodyaccessorystyle, null, { 'body_accessory' : value.bodyaccessorystyle}, null, data.body_accessory_style == value.bodyaccessorystyle ? 'selected' : null)}}
+ {{/for}}
+
+
+{{/if}}