From fc09967ca8f3a187076800fafcdca868e3ca72e1 Mon Sep 17 00:00:00 2001 From: monster860 Date: Sun, 17 Apr 2016 17:14:46 -0400 Subject: [PATCH 01/37] telecomms concurrency fix --- code/game/machinery/telecomms/broadcaster.dm | 3 ++- .../game/objects/items/devices/radio/radio.dm | 9 ++++--- .../scripting/Implementations/Telecomms.dm | 27 ++++++++++++++++++- .../scripting/Implementations/_Logic.dm | 5 ---- 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/code/game/machinery/telecomms/broadcaster.dm b/code/game/machinery/telecomms/broadcaster.dm index 15b8b621b0c..5d6aa95b56f 100644 --- a/code/game/machinery/telecomms/broadcaster.dm +++ b/code/game/machinery/telecomms/broadcaster.dm @@ -621,7 +621,8 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept //#### Sending the signal to all subspace receivers ####// for(var/obj/machinery/telecomms/receiver/R in telecomms_list) - R.receive_signal(signal) + spawn(0) + R.receive_signal(signal) if(do_sleep) sleep(rand(10,25)) diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index d2fe7d2b319..ab5782afcae 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -402,11 +402,13 @@ var/global/list/default_medbay_channels = list( //#### Sending the signal to all subspace receivers ####// for(var/obj/machinery/telecomms/receiver/R in telecomms_list) - R.receive_signal(signal) + spawn(0) + R.receive_signal(signal) // Allinone can act as receivers. for(var/obj/machinery/telecomms/allinone/R in telecomms_list) - R.receive_signal(signal) + spawn(0) + R.receive_signal(signal) // Receiving code can be located in Telecommunications.dm return signal.data["done"] && position.z in signal.data["level"] @@ -455,7 +457,8 @@ var/global/list/default_medbay_channels = list( signal.frequency = connection.frequency // Quick frequency set for(var/obj/machinery/telecomms/receiver/R in telecomms_list) - R.receive_signal(signal) + spawn(0) + R.receive_signal(signal) sleep(rand(10,25)) // wait a little... diff --git a/code/modules/scripting/Implementations/Telecomms.dm b/code/modules/scripting/Implementations/Telecomms.dm index e06a5f9a18d..a4dbfb8f127 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 a97fc320e0e..43d75f8c75d 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]") From f95655419c410307b7593a9b76c9c985075dd801 Mon Sep 17 00:00:00 2001 From: KasparoVy Date: Sat, 30 Apr 2016 08:12:41 -0400 Subject: [PATCH 02/37] Refactors Hair so it's on the Head + Adds a Vox Hairstyle + Adjusts Vox Hairstyle Names for Consistency -- PASS 1 Also fixes a typo or two. TO DO: FULLY TEST AND SWEEP FOR BUGS, ERRORS AND RUNTIMES --- code/datums/datacore.dm | 19 +++--- .../datums/diseases/advance/symptoms/beard.dm | 13 ++-- .../diseases/advance/symptoms/shedding.dm | 11 ++-- code/game/dna/dna2.dm | 37 ++++++----- code/game/dna/dna2_helpers.dm | 25 +++---- code/game/dna/genes/vg_powers.dm | 25 +++---- code/game/gamemodes/blob/blobs/blob_mobs.dm | 3 +- code/game/gamemodes/heist/heist.dm | 5 +- code/game/gamemodes/nuclear/nuclear.dm | 18 ++--- code/game/objects/items/weapons/cosmetics.dm | 18 ++--- code/game/objects/items/weapons/scissors.dm | 22 +++---- code/game/response_team.dm | 17 ++--- code/modules/admin/verbs/one_click_antag.dm | 5 +- code/modules/client/preferences.dm | 31 +++++---- code/modules/clothing/head/misc_special.dm | 7 +- .../mob/living/carbon/human/appearance.dm | 62 ++++++++++-------- code/modules/mob/living/carbon/human/death.dm | 18 ++--- code/modules/mob/living/carbon/human/human.dm | 56 ++++++++++------ .../mob/living/carbon/human/human_defines.dm | 18 ----- .../mob/living/carbon/human/species/apollo.dm | 5 +- .../living/carbon/human/species/station.dm | 4 +- .../mob/living/carbon/human/update_icons.dm | 43 ++++++------ code/modules/mob/living/carbon/superheroes.dm | 5 +- .../mob/new_player/sprite_accessories.dm | 9 ++- code/modules/nano/modules/human_appearance.dm | 10 +-- code/modules/reagents/newchem/other.dm | 23 ++++--- code/modules/surgery/limb_reattach.dm | 6 +- code/modules/surgery/organs/organ_icon.dm | 29 ++++---- code/modules/surgery/organs/organ_internal.dm | 23 +++---- .../surgery/organs/subtypes/standard.dm | 18 +++++ icons/mob/human_face.dmi | Bin 71587 -> 71902 bytes 31 files changed, 322 insertions(+), 263 deletions(-) diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index a70875a7090..d07b6e3eb73 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -126,6 +126,7 @@ proc/get_id_photo(var/mob/living/carbon/human/H) var/icon/preview_icon = null + var/obj/item/organ/external/head/head_organ = H.get_organ("head") var/g = "m" if (H.gender == FEMALE) @@ -170,32 +171,32 @@ proc/get_id_photo(var/mob/living/carbon/human/H) eyes_s.Blend(rgb(H.r_eyes, H.g_eyes, H.b_eyes), ICON_ADD) face_s.Blend(eyes_s, ICON_OVERLAY) - var/datum/sprite_accessory/hair_style = hair_styles_list[H.h_style] + var/datum/sprite_accessory/hair_style = hair_styles_list[head_organ.h_style] if(hair_style) var/icon/hair_s = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s") // I'll want to make a species-specific proc for this sooner or later // But this'll do for now - if(H.get_species() == "Slime People") + if(head_organ.species.name == "Slime People") hair_s.Blend(rgb(H.r_skin, H.g_skin, H.b_skin, 160), ICON_ADD) else - hair_s.Blend(rgb(H.r_hair, H.g_hair, H.b_hair), ICON_ADD) + hair_s.Blend(rgb(head_organ.r_hair, head_organ.g_hair, head_organ.b_hair), ICON_ADD) face_s.Blend(hair_s, ICON_OVERLAY) //Head Accessory - if(H.species.bodyflags & HAS_HEAD_ACCESSORY) - var/datum/sprite_accessory/head_accessory_style = head_accessory_styles_list[H.ha_style] + if(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) var/icon/head_accessory_s = new/icon("icon" = head_accessory_style.icon, "icon_state" = "[head_accessory_style.icon_state]_s") - head_accessory_s.Blend(rgb(H.r_headacc, H.g_headacc, H.b_headacc), ICON_ADD) + head_accessory_s.Blend(rgb(head_organ.r_headacc, head_organ.g_headacc, head_organ.b_headacc), ICON_ADD) face_s.Blend(head_accessory_s, ICON_OVERLAY) - var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[H.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) var/icon/facial_s = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_s") - if(H.get_species() == "Slime People") + if(head_organ.species.name == "Slime People") facial_s.Blend(rgb(H.r_skin, H.g_skin, H.b_skin, 160), ICON_ADD) else - facial_s.Blend(rgb(H.r_facial, H.g_facial, H.b_facial), ICON_ADD) + facial_s.Blend(rgb(head_organ.r_facial, head_organ.g_facial, head_organ.b_facial), ICON_ADD) face_s.Blend(facial_s, ICON_OVERLAY) //Markings diff --git a/code/datums/diseases/advance/symptoms/beard.dm b/code/datums/diseases/advance/symptoms/beard.dm index 1dda9b46f7f..b773d25cf9a 100644 --- a/code/datums/diseases/advance/symptoms/beard.dm +++ b/code/datums/diseases/advance/symptoms/beard.dm @@ -30,20 +30,21 @@ BONUS var/mob/living/M = A.affected_mob if(istype(M, /mob/living/carbon/human)) var/mob/living/carbon/human/H = M + var/obj/item/organ/external/head/head_organ = H.get_organ("head") switch(A.stage) if(1, 2) to_chat(H, "Your chin itches.") - if(H.f_style == "Shaved") - H.f_style = "Jensen Beard" + if(head_organ.f_style == "Shaved") + head_organ.f_style = "Jensen Beard" H.update_hair() if(3, 4) to_chat(H, "You feel tough.") - if(!(H.f_style == "Dwarf Beard") && !(H.f_style == "Very Long Beard") && !(H.f_style == "Full Beard")) - H.f_style = "Full Beard" + if(!(head_organ.f_style == "Dwarf Beard") && !(head_organ.f_style == "Very Long Beard") && !(head_organ.f_style == "Full Beard")) + head_organ.f_style = "Full Beard" H.update_hair() else to_chat(H, "You feel manly!") - if(!(H.f_style == "Dwarf Beard") && !(H.f_style == "Very Long Beard")) - H.f_style = pick("Dwarf Beard", "Very Long Beard") + if(!(head_organ.f_style == "Dwarf Beard") && !(head_organ.f_style == "Very Long Beard")) + head_organ.f_style = pick("Dwarf Beard", "Very Long Beard") H.update_hair() return \ No newline at end of file diff --git a/code/datums/diseases/advance/symptoms/shedding.dm b/code/datums/diseases/advance/symptoms/shedding.dm index f7f52984c0b..dd1fc5183a6 100644 --- a/code/datums/diseases/advance/symptoms/shedding.dm +++ b/code/datums/diseases/advance/symptoms/shedding.dm @@ -31,18 +31,19 @@ BONUS to_chat(M, "[pick("Your scalp itches.", "Your skin feels flakey.")]") if(istype(M, /mob/living/carbon/human)) var/mob/living/carbon/human/H = M + var/obj/item/organ/external/head/head_organ = H.get_organ("head") switch(A.stage) if(3, 4) - if(!(H.h_style == "Bald") && !(H.h_style == "Balding Hair")) + if(!(head_organ.h_style == "Bald") && !(head_organ.h_style == "Balding Hair")) to_chat(H, "Your hair starts to fall out in clumps...") spawn(50) - H.h_style = "Balding Hair" + head_organ.h_style = "Balding Hair" H.update_hair() if(5) - if(!(H.f_style == "Shaved") || !(H.h_style == "Bald")) + if(!(head_organ.f_style == "Shaved") || !(head_organ.h_style == "Bald")) to_chat(H, "Your hair starts to fall out in clumps...") spawn(50) - H.f_style = "Shaved" - H.h_style = "Bald" + head_organ.f_style = "Shaved" + head_organ.h_style = "Bald" H.update_hair() return \ No newline at end of file diff --git a/code/game/dna/dna2.dm b/code/game/dna/dna2.dm index a15170a3956..93d7cc473dc 100644 --- a/code/game/dna/dna2.dm +++ b/code/game/dna/dna2.dm @@ -133,19 +133,20 @@ var/global/list/bad_blocks[0] ResetUI(1) // Hair // FIXME: Species-specific defaults pls - if(!character.h_style) - character.h_style = "Skinhead" - var/hair = hair_styles_list.Find(character.h_style) + var/obj/item/organ/external/head/H = character.get_organ("head") + if(!H.h_style) + H.h_style = "Skinhead" + var/hair = hair_styles_list.Find(H.h_style) // Facial Hair - if(!character.f_style) - character.f_style = "Shaved" - var/beard = facial_hair_styles_list.Find(character.f_style) + if(!H.f_style) + H.f_style = "Shaved" + var/beard = facial_hair_styles_list.Find(H.f_style) // Head Accessory - if(!character.ha_style) - character.ha_style = "None" - var/headacc = head_accessory_styles_list.Find(character.ha_style) + if(!H.ha_style) + H.ha_style = "None" + var/headacc = head_accessory_styles_list.Find(H.ha_style) /*// Body Accessory if(!character.body_accessory) @@ -157,13 +158,13 @@ var/global/list/bad_blocks[0] character.m_style = "None" var/marks = marking_styles_list.Find(character.m_style) - SetUIValueRange(DNA_UI_HAIR_R, character.r_hair, 255, 1) - SetUIValueRange(DNA_UI_HAIR_G, character.g_hair, 255, 1) - SetUIValueRange(DNA_UI_HAIR_B, character.b_hair, 255, 1) + SetUIValueRange(DNA_UI_HAIR_R, H.r_hair, 255, 1) + SetUIValueRange(DNA_UI_HAIR_G, H.g_hair, 255, 1) + SetUIValueRange(DNA_UI_HAIR_B, H.b_hair, 255, 1) - SetUIValueRange(DNA_UI_BEARD_R, character.r_facial, 255, 1) - SetUIValueRange(DNA_UI_BEARD_G, character.g_facial, 255, 1) - SetUIValueRange(DNA_UI_BEARD_B, character.b_facial, 255, 1) + SetUIValueRange(DNA_UI_BEARD_R, H.r_facial, 255, 1) + SetUIValueRange(DNA_UI_BEARD_G, H.g_facial, 255, 1) + SetUIValueRange(DNA_UI_BEARD_B, H.b_facial, 255, 1) SetUIValueRange(DNA_UI_EYES_R, character.r_eyes, 255, 1) SetUIValueRange(DNA_UI_EYES_G, character.g_eyes, 255, 1) @@ -173,9 +174,9 @@ var/global/list/bad_blocks[0] SetUIValueRange(DNA_UI_SKIN_G, character.g_skin, 255, 1) SetUIValueRange(DNA_UI_SKIN_B, character.b_skin, 255, 1) - SetUIValueRange(DNA_UI_HACC_R, character.r_headacc, 255, 1) - SetUIValueRange(DNA_UI_HACC_G, character.g_headacc, 255, 1) - SetUIValueRange(DNA_UI_HACC_B, character.b_headacc, 255, 1) + SetUIValueRange(DNA_UI_HACC_R, H.r_headacc, 255, 1) + SetUIValueRange(DNA_UI_HACC_G, H.g_headacc, 255, 1) + SetUIValueRange(DNA_UI_HACC_B, H.b_headacc, 255, 1) SetUIValueRange(DNA_UI_MARK_R, character.r_markings, 255, 1) SetUIValueRange(DNA_UI_MARK_G, character.g_markings, 255, 1) diff --git a/code/game/dna/dna2_helpers.dm b/code/game/dna/dna2_helpers.dm index 781c3a1d230..53f248d1e91 100644 --- a/code/game/dna/dna2_helpers.dm +++ b/code/game/dna/dna2_helpers.dm @@ -131,13 +131,14 @@ src.dna.UpdateUI() dna.check_integrity() var/mob/living/carbon/human/H = src - H.r_hair = dna.GetUIValueRange(DNA_UI_HAIR_R, 255) - H.g_hair = dna.GetUIValueRange(DNA_UI_HAIR_G, 255) - H.b_hair = dna.GetUIValueRange(DNA_UI_HAIR_B, 255) + var/obj/item/organ/external/head/head_organ = H.get_organ("head") + head_organ.r_hair = dna.GetUIValueRange(DNA_UI_HAIR_R, 255) + head_organ.g_hair = dna.GetUIValueRange(DNA_UI_HAIR_G, 255) + head_organ.b_hair = dna.GetUIValueRange(DNA_UI_HAIR_B, 255) - H.r_facial = dna.GetUIValueRange(DNA_UI_BEARD_R, 255) - H.g_facial = dna.GetUIValueRange(DNA_UI_BEARD_G, 255) - H.b_facial = dna.GetUIValueRange(DNA_UI_BEARD_B, 255) + head_organ.r_facial = dna.GetUIValueRange(DNA_UI_BEARD_R, 255) + head_organ.g_facial = dna.GetUIValueRange(DNA_UI_BEARD_G, 255) + head_organ.b_facial = dna.GetUIValueRange(DNA_UI_BEARD_B, 255) H.r_skin = dna.GetUIValueRange(DNA_UI_SKIN_R, 255) H.g_skin = dna.GetUIValueRange(DNA_UI_SKIN_G, 255) @@ -147,9 +148,9 @@ H.g_eyes = dna.GetUIValueRange(DNA_UI_EYES_G, 255) H.b_eyes = dna.GetUIValueRange(DNA_UI_EYES_B, 255) - H.r_headacc = dna.GetUIValueRange(DNA_UI_HACC_R, 255) - H.g_headacc = dna.GetUIValueRange(DNA_UI_HACC_G, 255) - H.b_headacc = dna.GetUIValueRange(DNA_UI_HACC_B, 255) + head_organ.r_headacc = dna.GetUIValueRange(DNA_UI_HACC_R, 255) + head_organ.g_headacc = dna.GetUIValueRange(DNA_UI_HACC_G, 255) + head_organ.b_headacc = dna.GetUIValueRange(DNA_UI_HACC_B, 255) H.r_markings = dna.GetUIValueRange(DNA_UI_MARK_R, 255) H.g_markings = dna.GetUIValueRange(DNA_UI_MARK_G, 255) @@ -168,17 +169,17 @@ //Hair var/hair = dna.GetUIValueRange(DNA_UI_HAIR_STYLE,hair_styles_list.len) if((0 < hair) && (hair <= hair_styles_list.len)) - H.h_style = hair_styles_list[hair] + head_organ.h_style = hair_styles_list[hair] //Facial Hair var/beard = dna.GetUIValueRange(DNA_UI_BEARD_STYLE,facial_hair_styles_list.len) if((0 < beard) && (beard <= facial_hair_styles_list.len)) - H.f_style = facial_hair_styles_list[beard] + head_organ.f_style = facial_hair_styles_list[beard] //Head Accessories var/headacc = dna.GetUIValueRange(DNA_UI_HACC_STYLE,head_accessory_styles_list.len) if((0 < headacc) && (headacc <= head_accessory_styles_list.len)) - H.ha_style = head_accessory_styles_list[headacc] + head_organ.ha_style = head_accessory_styles_list[headacc] //Markings var/marks = dna.GetUIValueRange(DNA_UI_MARK_STYLE,marking_styles_list.len) diff --git a/code/game/dna/genes/vg_powers.dm b/code/game/dna/genes/vg_powers.dm index 8a854c7980d..5511642e53e 100644 --- a/code/game/dna/genes/vg_powers.dm +++ b/code/game/dna/genes/vg_powers.dm @@ -37,18 +37,19 @@ to_chat(usr, "\red You can't change your appearance right now!") return var/mob/living/carbon/human/M=usr + var/obj/item/organ/external/head/head_organ = M.get_organ("head") - var/new_facial = input("Please select facial hair color.", "Character Generation",rgb(M.r_facial,M.g_facial,M.b_facial)) as null|color + var/new_facial = input("Please select facial hair color.", "Character Generation",rgb(head_organ.r_facial, head_organ.g_facial, head_organ.b_facial)) as null|color if(new_facial) - M.r_facial = hex2num(copytext(new_facial, 2, 4)) - M.g_facial = hex2num(copytext(new_facial, 4, 6)) - M.b_facial = hex2num(copytext(new_facial, 6, 8)) + head_organ.r_facial = hex2num(copytext(new_facial, 2, 4)) + head_organ.g_facial = hex2num(copytext(new_facial, 4, 6)) + head_organ.b_facial = hex2num(copytext(new_facial, 6, 8)) - var/new_hair = input("Please select hair color.", "Character Generation",rgb(M.r_hair,M.g_hair,M.b_hair)) as null|color + var/new_hair = input("Please select hair color.", "Character Generation",rgb(head_organ.r_hair, head_organ.g_hair, head_organ.b_hair)) as null|color if(new_facial) - M.r_hair = hex2num(copytext(new_hair, 2, 4)) - M.g_hair = hex2num(copytext(new_hair, 4, 6)) - M.b_hair = hex2num(copytext(new_hair, 6, 8)) + head_organ.r_hair = hex2num(copytext(new_hair, 2, 4)) + head_organ.g_hair = hex2num(copytext(new_hair, 4, 6)) + head_organ.b_hair = hex2num(copytext(new_hair, 6, 8)) var/new_eyes = input("Please select eye color.", "Character Generation",rgb(M.r_eyes,M.g_eyes,M.b_eyes)) as null|color if(new_eyes) @@ -73,11 +74,11 @@ hairs.Add(H.name) // add hair name to hairs qdel(H) // delete the hair after it's all done - var/new_style = input("Please select hair style", "Character Generation",M.h_style) as null|anything in hairs + var/new_style = input("Please select hair style", "Character Generation", head_organ.h_style) as null|anything in hairs // if new style selected (not cancel) if (new_style) - M.h_style = new_style + head_organ.h_style = new_style // facial hair var/list/all_fhairs = subtypesof(/datum/sprite_accessory/facial_hair) @@ -88,10 +89,10 @@ fhairs.Add(H.name) qdel(H) - new_style = input("Please select facial style", "Character Generation",M.f_style) as null|anything in fhairs + new_style = input("Please select facial style", "Character Generation", head_organ.f_style) as null|anything in fhairs if(new_style) - M.f_style = new_style + head_organ.f_style = new_style var/new_gender = alert(usr, "Please select gender.", "Character Generation", "Male", "Female") if (new_gender) diff --git a/code/game/gamemodes/blob/blobs/blob_mobs.dm b/code/game/gamemodes/blob/blobs/blob_mobs.dm index a35505470fa..229b35660a3 100644 --- a/code/game/gamemodes/blob/blobs/blob_mobs.dm +++ b/code/game/gamemodes/blob/blobs/blob_mobs.dm @@ -68,6 +68,7 @@ ..() /mob/living/simple_animal/hostile/blob/blobspore/proc/Zombify(var/mob/living/carbon/human/H) + var/obj/item/organ/external/head/head_organ = H.get_organ("head") is_zombie = 1 if(H.wear_suit) var/obj/item/clothing/suit/armor/A = H.wear_suit @@ -82,7 +83,7 @@ icon = H.icon speak_emote = list("groans") icon_state = "zombie2_s" - H.h_style = null + head_organ.h_style = null H.update_hair() human_overlays = H.overlays update_icons() diff --git a/code/game/gamemodes/heist/heist.dm b/code/game/gamemodes/heist/heist.dm index 057c43345f8..85244067c54 100644 --- a/code/game/gamemodes/heist/heist.dm +++ b/code/game/gamemodes/heist/heist.dm @@ -95,6 +95,7 @@ var/global/list/obj/cortical_stacks = list() //Stacks for 'leave nobody behind' newname += pick(list("ti","hi","ki","ya","ta","ha","ka","ya","chi","cha","kah")) var/mob/living/carbon/human/vox = newraider.current + var/obj/item/organ/external/head/head_organ = vox.get_organ("head") vox.real_name = capitalize(newname) vox.name = vox.real_name @@ -106,8 +107,8 @@ var/global/list/obj/cortical_stacks = list() //Stacks for 'leave nobody behind' vox.add_language("Vox-pidgin") vox.add_language("Galactic Common") vox.add_language("Tradeband") - vox.h_style = "Short Vox Quills" - vox.f_style = "Shaved" + head_organ.h_style = "Short Vox Quills" + head_organ.f_style = "Shaved" for(var/obj/item/organ/external/limb in vox.organs) limb.status &= ~(ORGAN_DESTROYED | ORGAN_ROBOT) diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index f2d05507da1..3ba413027e1 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -134,6 +134,8 @@ proc/issyndicate(mob/living/M as mob) /datum/game_mode/proc/create_syndicate(var/datum/mind/synd_mind) // So we don't have inferior species as ops - randomize a human var/mob/living/carbon/human/M = synd_mind.current + var/obj/item/organ/external/head/head_organ = M.get_organ("head") + M.set_species("Human",1) M.dna.ready_dna(M) // Quadriplegic Nuke Ops won't be participating in the paralympics @@ -150,18 +152,18 @@ proc/issyndicate(mob/living/M as mob) if(prob(5)) facial_hair_style = pick(facial_hair_styles_list) - M.r_facial = hex2num(copytext(hair_c, 2, 4)) - M.g_facial = hex2num(copytext(hair_c, 4, 6)) - M.b_facial = hex2num(copytext(hair_c, 6, 8)) - M.r_hair = hex2num(copytext(hair_c, 2, 4)) - M.g_hair = hex2num(copytext(hair_c, 4, 6)) - M.b_hair = hex2num(copytext(hair_c, 6, 8)) + head_organ.r_facial = hex2num(copytext(hair_c, 2, 4)) + head_organ.g_facial = hex2num(copytext(hair_c, 4, 6)) + head_organ.b_facial = hex2num(copytext(hair_c, 6, 8)) + head_organ.r_hair = hex2num(copytext(hair_c, 2, 4)) + head_organ.g_hair = hex2num(copytext(hair_c, 4, 6)) + head_organ.b_hair = hex2num(copytext(hair_c, 6, 8)) M.r_eyes = hex2num(copytext(eye_c, 2, 4)) M.g_eyes = hex2num(copytext(eye_c, 4, 6)) M.b_eyes = hex2num(copytext(eye_c, 6, 8)) M.s_tone = skin_tone - M.h_style = hair_style - M.f_style = facial_hair_style + head_organ.h_style = hair_style + head_organ.f_style = facial_hair_style M.body_accessory = null /datum/game_mode/proc/prepare_syndicate_leader(var/datum/mind/synd_mind, var/nuke_code) diff --git a/code/game/objects/items/weapons/cosmetics.dm b/code/game/objects/items/weapons/cosmetics.dm index 3e2448fa8fe..89a8b52b8da 100644 --- a/code/game/objects/items/weapons/cosmetics.dm +++ b/code/game/objects/items/weapons/cosmetics.dm @@ -91,16 +91,16 @@ /obj/item/weapon/razor/attack(mob/living/carbon/M as mob, mob/user as mob) if(ishuman(M)) var/mob/living/carbon/human/H = M - var/obj/item/organ/external/head/C = H.organs_by_name["head"] + var/obj/item/organ/external/head/C = H.get_organ("head") var/datum/robolimb/robohead = all_robolimbs[C.model] if(user.zone_sel.selecting == "mouth") if(!get_location_accessible(H, "mouth")) to_chat(user, "The mask is in the way.") return - if((H.species && H.species.flags & ALL_RPARTS) && robohead.is_monitor) //If the target is of a species that can have prosthetic heads, but the head doesn't support human hair 'wigs'... + if((C.species && C.species.flags & ALL_RPARTS) && robohead.is_monitor) //If the target is of a species that can have prosthetic heads, but the head doesn't support human hair 'wigs'... to_chat(user, "You find yourself disappointed at the appalling lack of facial hair.") return - if(H.f_style == "Shaved") + if(C.f_style == "Shaved") to_chat(user, "Already clean-shaven.") return if(H == user) //shaving yourself @@ -109,7 +109,7 @@ if(do_after(user, 50, target = H)) user.visible_message("[user] shaves his facial hair clean with the [src].", \ "You finish shaving with the [src]. Fast and clean!") - H.f_style = "Shaved" + C.f_style = "Shaved" H.update_fhair() playsound(src.loc, 'sound/items/Welder2.ogg', 20, 1) else @@ -121,17 +121,17 @@ if(user_loc == user.loc && H_loc == H.loc) user.visible_message("[user] shaves off [H]'s facial hair with \the [src].", \ "You shave [H]'s facial hair clean off.") - H.f_style = "Shaved" + C.f_style = "Shaved" H.update_fhair() playsound(src.loc, 'sound/items/Welder2.ogg', 20, 1) if(user.zone_sel.selecting == "head") if(!get_location_accessible(H, "head")) to_chat(user, "The headgear is in the way.") return - if((H.species && H.species.flags & ALL_RPARTS) && robohead.is_monitor) //If the target is of a species that can have prosthetic heads, but the head doesn't support human hair 'wigs'... + if((C.species && C.species.flags & ALL_RPARTS) && robohead.is_monitor) //If the target is of a species that can have prosthetic heads, but the head doesn't support human hair 'wigs'... to_chat(user, "You find yourself disappointed at the appalling lack of hair.") return - if(H.h_style == "Bald" || H.h_style == "Balding Hair" || H.h_style == "Skinhead") + if(C.h_style == "Bald" || C.h_style == "Balding Hair" || C.h_style == "Skinhead") to_chat(user, "There is not enough hair left to shave...") return if(H == user) //shaving yourself @@ -140,7 +140,7 @@ if(do_after(user, 50, target = H)) user.visible_message("[user] shaves his head with the [src].", \ "You finish shaving with the [src].") - H.h_style = "Skinhead" + C.h_style = "Skinhead" H.update_hair() playsound(src.loc, 'sound/items/Welder2.ogg', 40, 1) else @@ -152,7 +152,7 @@ if(user_loc == user.loc && H_loc == H.loc) user.visible_message("[user] shaves [H]'s head bald with \the [src]!", \ "You shave [H]'s head bald.") - H.h_style = "Skinhead" + C.h_style = "Skinhead" H.update_hair() playsound(src.loc, 'sound/items/Welder2.ogg', 40, 1) else diff --git a/code/game/objects/items/weapons/scissors.dm b/code/game/objects/items/weapons/scissors.dm index a5e0081e723..343c3788bdc 100644 --- a/code/game/objects/items/weapons/scissors.dm +++ b/code/game/objects/items/weapons/scissors.dm @@ -30,21 +30,21 @@ //this is largely copypasted from there. //handle facial hair (if necessary) var/list/species_facial_hair = list() - var/obj/item/organ/external/head/C = H.organs_by_name["head"] + var/obj/item/organ/external/head/C = H.get_organ("head") var/datum/robolimb/robohead = all_robolimbs[C.model] if(H.gender == MALE || H.get_species() == "Vulpkanin") - if(H.species) + if(C.species) for(var/i in facial_hair_styles_list) var/datum/sprite_accessory/facial_hair/tmp_facial = facial_hair_styles_list[i] - if(H.species.name in tmp_facial.species_allowed) //If the species is allowed to have the style, add the style to the list. Or, if the character has a prosthetic head, give them the human hair styles. - if(H.species.flags & ALL_RPARTS) //If the character is of a species that can have full body prosthetics and their head doesn't suport human hair 'wigs', don't add the style to the list. + if(C.species.name in tmp_facial.species_allowed) //If the species is allowed to have the style, add the style to the list. Or, if the character has a prosthetic head, give them the human hair styles. + if(C.species.flags & ALL_RPARTS) //If the character is of a species that can have full body prosthetics and their head doesn't suport human hair 'wigs', don't add the style to the list. if(robohead.is_monitor) to_chat(user, "You are unable to find anything on [H]'s face worth cutting. How disappointing.") return continue //If the head DOES support human hair wigs, make sure they don't get monitor-oriented styles. species_facial_hair += i else - if(H.species.flags & ALL_RPARTS) //If the target is of a species that can have prosthetic heads, and the head supports human hair 'wigs' AND the hair-style is human-suitable, add it to the list. + if(C.species.flags & ALL_RPARTS) //If the target is of a species that can have prosthetic heads, and the head supports human hair 'wigs' AND the hair-style is human-suitable, add it to the list. if(!robohead.is_monitor) if("Human" in tmp_facial.species_allowed) species_facial_hair += i @@ -56,18 +56,18 @@ var/f_new_style = input(user, "Select a facial hair style", "Grooming") as null|anything in species_facial_hair //handle normal hair var/list/species_hair = list() - if(H.species) + if(C.species) for(var/i in hair_styles_list) var/datum/sprite_accessory/hair/tmp_hair = hair_styles_list[i] - if(H.species.name in tmp_hair.species_allowed) //If the species is allowed to have the style, add the style to the list. Or, if the character has a prosthetic head, give them the human facial hair styles. - if(H.species.flags & ALL_RPARTS) //If the character is of a species that can have full body prosthetics and their head doesn't suport human hair 'wigs', don't add the style to the list. + if(C.species.name in tmp_hair.species_allowed) //If the species is allowed to have the style, add the style to the list. Or, if the character has a prosthetic head, give them the human facial hair styles. + if(C.species.flags & ALL_RPARTS) //If the character is of a species that can have full body prosthetics and their head doesn't suport human hair 'wigs', don't add the style to the list. if(robohead.is_monitor) to_chat(user, "You are unable to find anything on [H]'s head worth cutting. How disappointing.") return continue //If the head DOES support human hair wigs, make sure they don't get monitor-oriented styles. species_hair += i else - if(H.species.flags & ALL_RPARTS) //If the target is of a species that can have prosthetic heads, and the head supports human hair 'wigs' AND the hair-style is human-suitable, add it to the list. + if(C.species.flags & ALL_RPARTS) //If the target is of a species that can have prosthetic heads, and the head supports human hair 'wigs' AND the hair-style is human-suitable, add it to the list. if(!robohead.is_monitor) if("Human" in tmp_hair.species_allowed) species_hair += i @@ -84,9 +84,9 @@ user.visible_message("[user] stops cutting [M]'s hair.", "You stop cutting [M]'s hair.") return if(f_new_style) - H.f_style = f_new_style + C.f_style = f_new_style if(h_new_style) - H.h_style = h_new_style + C.h_style = h_new_style H.update_hair() user.visible_message("[user] finishes cutting [M]'s hair!") diff --git a/code/game/response_team.dm b/code/game/response_team.dm index 14bf44ff7b5..241e317c24b 100644 --- a/code/game/response_team.dm +++ b/code/game/response_team.dm @@ -148,6 +148,7 @@ var/send_emergency_team /client/proc/create_response_team(obj/spawn_location) var/mob/living/carbon/human/M = new(null) + var/obj/item/organ/external/head/head_organ = M.get_organ("head") response_team_members |= M var/new_gender = alert(usr, "Please select your gender.", "Character Generation", "Male", "Female") @@ -173,18 +174,18 @@ var/send_emergency_team if(prob(5)) facial_hair_style = pick(facial_hair_styles_list) - M.r_facial = hex2num(copytext(hair_c, 2, 4)) - M.g_facial = hex2num(copytext(hair_c, 4, 6)) - M.b_facial = hex2num(copytext(hair_c, 6, 8)) - M.r_hair = hex2num(copytext(hair_c, 2, 4)) - M.g_hair = hex2num(copytext(hair_c, 4, 6)) - M.b_hair = hex2num(copytext(hair_c, 6, 8)) + head_organ.r_facial = hex2num(copytext(hair_c, 2, 4)) + head_organ.g_facial = hex2num(copytext(hair_c, 4, 6)) + head_organ.b_facial = hex2num(copytext(hair_c, 6, 8)) + head_organ.r_hair = hex2num(copytext(hair_c, 2, 4)) + head_organ.g_hair = hex2num(copytext(hair_c, 4, 6)) + head_organ.b_hair = hex2num(copytext(hair_c, 6, 8)) M.r_eyes = hex2num(copytext(eye_c, 2, 4)) M.g_eyes = hex2num(copytext(eye_c, 4, 6)) M.b_eyes = hex2num(copytext(eye_c, 6, 8)) M.s_tone = skin_tone - M.h_style = hair_style - M.f_style = facial_hair_style + head_organ.h_style = hair_style + head_organ.f_style = facial_hair_style M.real_name = "[pick("Corporal", "Sergeant", "Staff Sergeant", "Sergeant First Class", "Master Sergeant", "Sergeant Major")] [pick(last_names)]" M.name = M.real_name diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm index f2d76051a37..2d41cd1d202 100644 --- a/code/modules/admin/verbs/one_click_antag.dm +++ b/code/modules/admin/verbs/one_click_antag.dm @@ -498,6 +498,7 @@ client/proc/one_click_antag() /datum/admins/proc/create_vox_raider(obj/spawn_location, leader_chosen = 0) var/mob/living/carbon/human/new_vox = new(spawn_location.loc, "Vox") + var/obj/item/organ/external/head/head_organ = new_vox.get_organ("head") var/sounds = rand(2,8) var/i = 0 @@ -516,8 +517,8 @@ client/proc/one_click_antag() new_vox.add_language("Vox-pidgin") new_vox.add_language("Galactic Common") new_vox.add_language("Tradeband") - new_vox.h_style = "Short Vox Quills" - new_vox.f_style = "Shaved" + head_organ.h_style = "Short Vox Quills" + head_organ.f_style = "Shaved" for(var/obj/item/organ/external/limb in new_vox.organs) limb.status &= ~(ORGAN_DESTROYED | ORGAN_ROBOT) diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index e53af9a5014..06e26861b6d 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -1631,7 +1631,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts if("nanoui") nanoui_fancy = !nanoui_fancy - if("ghost_att_anim") + if("ghost_att_anim") show_ghostitem_attack = !show_ghostitem_attack if("UIcolor") @@ -1753,13 +1753,19 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts character.g_eyes = g_eyes character.b_eyes = b_eyes - character.r_hair = r_hair - character.g_hair = g_hair - character.b_hair = b_hair + //Head-specific + var/obj/item/organ/external/head/H = character.get_organ("head") + H.r_hair = r_hair + H.g_hair = g_hair + H.b_hair = b_hair - character.r_facial = r_facial - character.g_facial = g_facial - character.b_facial = b_facial + H.r_facial = r_facial + H.g_facial = g_facial + H.b_facial = b_facial + + H.h_style = h_style + H.f_style = f_style + //End of head-specific. character.r_skin = r_skin character.g_skin = g_skin @@ -1767,9 +1773,6 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts character.s_tone = s_tone - character.h_style = h_style - character.f_style = f_style - // Destroy/cyborgize organs for(var/name in organ_data) @@ -1846,10 +1849,10 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts character.socks = socks if(character.species.bodyflags & HAS_HEAD_ACCESSORY) - character.r_headacc = r_headacc - character.g_headacc = g_headacc - character.b_headacc = b_headacc - character.ha_style = ha_style + H.r_headacc = r_headacc + H.g_headacc = g_headacc + H.b_headacc = b_headacc + H.ha_style = ha_style if(character.species.bodyflags & HAS_MARKINGS) character.r_markings = r_markings character.g_markings = g_markings diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm index 071c6032722..13b7a948119 100644 --- a/code/modules/clothing/head/misc_special.dm +++ b/code/modules/clothing/head/misc_special.dm @@ -176,9 +176,11 @@ /obj/item/clothing/head/kitty/update_icon(var/mob/living/carbon/human/user) if(!istype(user)) return + var/obj/item/organ/external/head/head_organ = user.get_organ("head") + mob = new/icon("icon" = 'icons/mob/head.dmi', "icon_state" = "kitty") // mob2 = new/icon("icon" = 'icons/mob/head.dmi', "icon_state" = "kitty2") - Commented out because it seemingly does nothing. - mob.Blend(rgb(user.r_hair, user.g_hair, user.b_hair), ICON_ADD) + mob.Blend(rgb(head_organ.r_hair, head_organ.g_hair, head_organ.b_hair), ICON_ADD) // mob2.Blend(rgb(user.r_hair, user.g_hair, user.b_hair), ICON_ADD) - Commented out because it seemingly does nothing. var/icon/earbit = new/icon("icon" = 'icons/mob/head.dmi', "icon_state" = "kittyinner") @@ -201,8 +203,9 @@ /obj/item/clothing/head/kitty/mouse/update_icon(var/mob/living/carbon/human/user) if(!istype(user)) return + var/obj/item/organ/external/head/head_organ = user.get_organ("head") mob = new/icon("icon" = 'icons/mob/head.dmi', "icon_state" = "mousey") - mob.Blend(rgb(user.r_hair, user.g_hair, user.b_hair), ICON_ADD) + mob.Blend(rgb(head_organ.r_hair, head_organ.g_hair, head_organ.b_hair), ICON_ADD) var/icon/earbit = new/icon("icon" = 'icons/mob/head.dmi', "icon_state" = "mouseyinner") mob.Blend(earbit, ICON_OVERLAY) diff --git a/code/modules/mob/living/carbon/human/appearance.dm b/code/modules/mob/living/carbon/human/appearance.dm index 8264db804fd..2822fa99933 100644 --- a/code/modules/mob/living/carbon/human/appearance.dm +++ b/code/modules/mob/living/carbon/human/appearance.dm @@ -18,16 +18,17 @@ return 1 /mob/living/carbon/human/proc/change_gender(var/gender, var/update_dna = 1) + var/obj/item/organ/external/head/H = organs_by_name["head"] if(src.gender == gender) return src.gender = gender - var/datum/sprite_accessory/hair/current_hair = hair_styles_list[h_style] + var/datum/sprite_accessory/hair/current_hair = hair_styles_list[H.h_style] if(current_hair.gender != NEUTER && current_hair.gender != src.gender) reset_head_hair() - var/datum/sprite_accessory/hair/current_fhair = facial_hair_styles_list[f_style] + var/datum/sprite_accessory/hair/current_fhair = facial_hair_styles_list[H.f_style] if(current_fhair.gender != NEUTER && current_fhair.gender != src.gender) reset_facial_hair() @@ -38,31 +39,33 @@ return 1 /mob/living/carbon/human/proc/change_hair(var/hair_style) + var/obj/item/organ/external/head/H = get_organ("head") if(!hair_style) return - if(h_style == hair_style) + if(H.h_style == hair_style) return if(!(hair_style in hair_styles_list)) return - h_style = hair_style + H.h_style = hair_style update_hair() return 1 /mob/living/carbon/human/proc/change_facial_hair(var/facial_hair_style) + var/obj/item/organ/external/head/H = get_organ("head") if(!facial_hair_style) return - if(f_style == facial_hair_style) + if(H.f_style == facial_hair_style) return if(!(facial_hair_style in facial_hair_styles_list)) return - f_style = facial_hair_style + H.f_style = facial_hair_style update_fhair() return 1 @@ -72,23 +75,24 @@ reset_facial_hair() /mob/living/carbon/human/proc/reset_head_hair() + var/obj/item/organ/external/head/H = get_organ("head") var/list/valid_hairstyles = generate_valid_hairstyles() - if(valid_hairstyles.len) - h_style = pick(valid_hairstyles) + H.h_style = pick(valid_hairstyles) else //this shouldn't happen - h_style = "Bald" + H.h_style = "Bald" update_hair() /mob/living/carbon/human/proc/reset_facial_hair() + var/obj/item/organ/external/head/H = get_organ("head") var/list/valid_facial_hairstyles = generate_valid_facial_hairstyles() if(valid_facial_hairstyles.len) - f_style = pick(valid_facial_hairstyles) + H.f_style = pick(valid_facial_hairstyles) else //this shouldn't happen - f_style = "Shaved" + H.f_style = "Shaved" update_fhair() /mob/living/carbon/human/proc/change_eye_color(var/red, var/green, var/blue) @@ -104,23 +108,25 @@ return 1 /mob/living/carbon/human/proc/change_hair_color(var/red, var/green, var/blue) - if(red == r_eyes && green == g_eyes && blue == b_eyes) + var/obj/item/organ/external/head/H = get_organ("head") + if(red == H.r_hair && green == H.g_hair && blue == H.b_hair) return - r_hair = red - g_hair = green - b_hair = blue + H.r_hair = red + H.g_hair = green + H.b_hair = blue update_hair() return 1 /mob/living/carbon/human/proc/change_facial_hair_color(var/red, var/green, var/blue) - if(red == r_facial && green == g_facial && blue == b_facial) + var/obj/item/organ/external/head/H = get_organ("head") + if(red == H.r_facial && green == H.g_facial && blue == H.b_facial) return - r_facial = red - g_facial = green - b_facial = blue + H.r_facial = red + H.g_facial = green + H.b_facial = blue update_fhair() return 1 @@ -172,17 +178,17 @@ var/list/valid_hairstyles = new() for(var/hairstyle in hair_styles_list) var/datum/sprite_accessory/S = hair_styles_list[hairstyle] + var/obj/item/organ/external/head/H = organs_by_name["head"] if(gender == MALE && S.gender == FEMALE) continue if(gender == FEMALE && S.gender == MALE) continue - if(species.flags & ALL_RPARTS) //If the user is a species who can have a robotic head... - var/obj/item/organ/external/head/H = organs_by_name["head"] + if(H.species.flags & ALL_RPARTS) //If the user is a species who can have a robotic head... var/datum/robolimb/robohead = all_robolimbs[H.model] if(!H) return - if(species.name in S.species_allowed) //If this is a hairstyle native to the user's species... + if(H.species.name in S.species_allowed) //If this is a hairstyle native to the user's species... if(robohead.is_monitor && (robohead.company in S.models_allowed)) //Check to see if they have a head with an ipc-style screen and that the head's company is in the screen style's allowed models list. valid_hairstyles += hairstyle //Give them their hairstyles if they do. continue @@ -195,8 +201,8 @@ if("Human" in S.species_allowed) //If the user has a robotic head and the hairstyle can fit humans, let them use it as a wig for their humanoid robot head. valid_hairstyles += hairstyle continue - else - if(!(species.name in S.species_allowed)) //If the user is not a species who can have robotic heads, use the default handling. + else //If the user is not a species who can have robotic heads, use the default handling. + if(!(H.species.name in S.species_allowed)) //If the user's head is not of a species the hair style allows, skip it. Otherwise, add it to the list. continue valid_hairstyles += hairstyle @@ -206,17 +212,17 @@ var/list/valid_facial_hairstyles = new() for(var/facialhairstyle in facial_hair_styles_list) var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle] + var/obj/item/organ/external/head/H = organs_by_name["head"] if(gender == MALE && S.gender == FEMALE) continue if(gender == FEMALE && S.gender == MALE) continue - if(species.flags & ALL_RPARTS) //If the user is a species who can have a robotic head... - var/obj/item/organ/external/head/H = organs_by_name["head"] + if(H.species.flags & ALL_RPARTS) //If the user is a species who can have a robotic head... var/datum/robolimb/robohead = all_robolimbs[H.model] if(!H) continue // No head, no hair - if(species.name in S.species_allowed) //If this is a facial hair style native to the user's species... + if(H.species.name in S.species_allowed) //If this is a facial hair style native to the user's species... if(robohead.is_monitor && (robohead.company in S.models_allowed)) //Check to see if they have a head with an ipc-style screen and that the head's company is in the screen style's allowed models list. valid_facial_hairstyles += facialhairstyle //Give them their facial hair styles if they do. continue @@ -231,7 +237,7 @@ valid_facial_hairstyles += facialhairstyle continue else //If the user is not a species who can have robotic heads, use the default handling. - if(!(species.name in S.species_allowed)) + if(!(H.species.name in S.species_allowed)) //If the user's head is not of a species the facial hair style allows, skip it. Otherwise, add it to the list. continue valid_facial_hairstyles += facialhairstyle diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index aa31c912841..fce12362d73 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -145,12 +145,13 @@ return ..(gibbed) /mob/living/carbon/human/proc/makeSkeleton() + var/obj/item/organ/external/head/H = get_organ("head") if(SKELETON in src.mutations) return - if(f_style) - f_style = "Shaved" - if(h_style) - h_style = "Bald" + if(H.f_style) + H.f_style = "Shaved" + if(H.h_style) + H.h_style = "Bald" update_fhair(0) update_hair(0) @@ -162,12 +163,13 @@ return /mob/living/carbon/human/proc/ChangeToHusk() + var/obj/item/organ/external/head/H = organs_by_name["head"] if(HUSK in mutations) return - if(f_style) - f_style = "Shaved" //we only change the icon_state of the hair datum, so it doesn't mess up their UI/UE - if(h_style) - h_style = "Bald" + if(H.f_style) + H.f_style = "Shaved" //we only change the icon_state of the hair datum, so it doesn't mess up their UI/UE + if(H.h_style) + H.h_style = "Bald" update_fhair(0) update_hair(0) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 3e5cb90f380..f78a80a3c3c 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -74,38 +74,46 @@ status_flags = GODMODE|CANPUSH /mob/living/carbon/human/skrell/New(var/new_loc) - h_style = "Skrell Male Tentacles" + var/obj/item/organ/external/head/H = get_organ("head") + H.h_style = "Skrell Male Tentacles" ..(new_loc, "Skrell") /mob/living/carbon/human/tajaran/New(var/new_loc) - ha_style = "Tajaran Ears" + var/obj/item/organ/external/head/H = get_organ("head") + H.ha_style = "Tajaran Ears" ..(new_loc, "Tajaran") /mob/living/carbon/human/vulpkanin/New(var/new_loc) - h_style = "Bald" + var/obj/item/organ/external/head/H = get_organ("head") + H.h_style = "Bald" ..(new_loc, "Vulpkanin") /mob/living/carbon/human/unathi/New(var/new_loc) - h_style = "Unathi Horns" + var/obj/item/organ/external/head/H = get_organ("head") + H.h_style = "Unathi Horns" ..(new_loc, "Unathi") /mob/living/carbon/human/vox/New(var/new_loc) - h_style = "Short Vox Quills" + var/obj/item/organ/external/head/H = get_organ("head") + H.h_style = "Short Vox Quills" ..(new_loc, "Vox") /mob/living/carbon/human/voxarmalis/New(var/new_loc) - h_style = "Bald" + var/obj/item/organ/external/head/H = get_organ("head") + H.h_style = "Bald" ..(new_loc, "Vox Armalis") /mob/living/carbon/human/skeleton/New(var/new_loc) - h_style = "Bald" + var/obj/item/organ/external/head/H = get_organ("head") + H.h_style = "Bald" ..(new_loc, "Skeleton") /mob/living/carbon/human/kidan/New(var/new_loc) ..(new_loc, "Kidan") /mob/living/carbon/human/plasma/New(var/new_loc) - h_style = "Bald" + var/obj/item/organ/external/head/H = get_organ("head") + H.h_style = "Bald" ..(new_loc, "Plasmaman") /mob/living/carbon/human/slime/New(var/new_loc) @@ -121,31 +129,38 @@ ..(new_loc, "Human") /mob/living/carbon/human/diona/New(var/new_loc) - h_style = "Bald" + var/obj/item/organ/external/head/H = get_organ("head") + H.h_style = "Bald" ..(new_loc, "Diona") /mob/living/carbon/human/machine/New(var/new_loc) - h_style = "blue IPC screen" + var/obj/item/organ/external/head/H = get_organ("head") + H.h_style = "Blue IPC Screen" ..(new_loc, "Machine") /mob/living/carbon/human/shadow/New(var/new_loc) - h_style = "Bald" + var/obj/item/organ/external/head/H = get_organ("head") + H.h_style = "Bald" ..(new_loc, "Shadow") /mob/living/carbon/human/golem/New(var/new_loc) - h_style = "Bald" + var/obj/item/organ/external/head/H = get_organ("head") + H.h_style = "Bald" ..(new_loc, "Golem") /mob/living/carbon/human/wryn/New(var/new_loc) - h_style = "Antennae" + var/obj/item/organ/external/head/H = get_organ("head") + H.h_style = "Antennae" ..(new_loc, "Wryn") /mob/living/carbon/human/nucleation/New(var/new_loc) - h_style = "Nucleation Crystals" + var/obj/item/organ/external/head/H = get_organ("head") + H.h_style = "Nucleation Crystals" ..(new_loc, "Nucleation") /mob/living/carbon/human/drask/New(var/new_loc) - h_style = "Bald" + var/obj/item/organ/external/head/H = get_organ("head") + H.h_style = "Bald" ..(new_loc, "Drask") /mob/living/carbon/human/monkey/New(var/new_loc) @@ -1601,9 +1616,8 @@ return if(species.flags & ALL_RPARTS) //If they can have a fully cybernetic body... - var/obj/item/organ/external/head/H = organs_by_name["head"] - var/datum/robolimb/robohead = all_robolimbs[H.model] - if(!H) + var/datum/robolimb/robohead = all_robolimbs[head_organ.model] + if(!head_organ) return if(!robohead.is_monitor) //If they've got a prosthetic head and it isn't a monitor, they've no screen to adjust. Instead, let them change the colour of their optics! var/optic_colour = input(src, "Select optic colour", rgb(r_markings, g_markings, b_markings)) as color|null @@ -1620,15 +1634,15 @@ var/list/hair = list() for(var/i in hair_styles_list) var/datum/sprite_accessory/hair/tmp_hair = hair_styles_list[i] - if((species.name in tmp_hair.species_allowed) && (robohead.company in tmp_hair.models_allowed)) //Populate the list of available monitor styles only with styles that the monitor-head is allowed to use. + if((head_organ.species.name in tmp_hair.species_allowed) && (robohead.company in tmp_hair.models_allowed)) //Populate the list of available monitor styles only with styles that the monitor-head is allowed to use. hair += i - var/new_style = input(src, "Select a monitor display", "Monitor Display", h_style) as null|anything in hair + var/new_style = input(src, "Select a monitor display", "Monitor Display", head_organ.h_style) as null|anything in hair if(incapacitated()) to_chat(src, "You were interrupted while changing your monitor display.") return if(new_style) - h_style = new_style + head_organ.h_style = new_style update_hair() diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index e2ebed386b3..6f106f5e125 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -9,24 +9,6 @@ var/global/default_martial_art = new/datum/martial_art var/b_markings = 0 var/m_style = "None" - //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" - //Eye colour var/r_eyes = 0 var/g_eyes = 0 diff --git a/code/modules/mob/living/carbon/human/species/apollo.dm b/code/modules/mob/living/carbon/human/species/apollo.dm index a7735a00db9..ed02ee5465a 100644 --- a/code/modules/mob/living/carbon/human/species/apollo.dm +++ b/code/modules/mob/living/carbon/human/species/apollo.dm @@ -54,6 +54,7 @@ to_chat(C, "It feels like part of you has died.") /datum/species/wryn/handle_attack_hand(var/mob/living/carbon/human/H, var/mob/living/carbon/human/M) + var/obj/item/organ/external/head/head_organ = H.get_organ("head") if(M.a_intent == I_HARM) if(H.handcuffed) if(!H.get_int_organ(/obj/item/organ/internal/wryn/hivenode)) return @@ -71,7 +72,7 @@ to_chat(M, "You hear a loud crunch as you mercilessly pull off [H]'s antennae.") to_chat(H, "You hear a loud crunch as your antennae is ripped off your head by [M].") to_chat(H, "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 +88,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." diff --git a/code/modules/mob/living/carbon/human/species/station.dm b/code/modules/mob/living/carbon/human/species/station.dm index 26c6ddb0c57..cce8b5c46ec 100644 --- a/code/modules/mob/living/carbon/human/species/station.dm +++ b/code/modules/mob/living/carbon/human/species/station.dm @@ -791,6 +791,8 @@ ) /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() \ 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 004f54a45ba..c885793f82c 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]") @@ -1266,22 +1266,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/new_player/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories.dm index e0fbfcdf91b..15452598ed5 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 diff --git a/code/modules/nano/modules/human_appearance.dm b/code/modules/nano/modules/human_appearance.dm index 606dcade9c9..4868bfdc7c5 100644 --- a/code/modules/nano/modules/human_appearance.dm +++ b/code/modules/nano/modules/human_appearance.dm @@ -2,6 +2,7 @@ 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() @@ -13,6 +14,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 +56,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 +71,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)) @@ -113,7 +115,7 @@ 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,7 +123,7 @@ 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_hair_color"] = can_change(APPEARANCE_HAIR_COLOR) data["change_facial_hair_color"] = can_change(APPEARANCE_FACIAL_HAIR_COLOR) diff --git a/code/modules/reagents/newchem/other.dm b/code/modules/reagents/newchem/other.dm index c26d8bbe983..4fe016f49ba 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.organs_by_name["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) + head_organ.f_style = random_facial_hair_style(H.gender, head_organ.species) H.update_hair() H.update_fhair() ..() @@ -256,8 +258,9 @@ datum/reagent/super_hairgrownium/on_mob_life(var/mob/living/M as mob) if(!M) M = holder.my_atom 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") + head_organ.h_style = "Very Long Hair" + head_organ.f_style = "Very Long Beard" 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/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/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..fd61410bdef 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 == "Mowhawk")) 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/icons/mob/human_face.dmi b/icons/mob/human_face.dmi index 3cd59fe3f741bfa74563dddbfb8cde1a2e8feb77..f140d02be968f598ea4466a99a043eaf7619229e 100644 GIT binary patch delta 27468 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 Fe*+S}khcH; delta 27463 zcmdSBcT`hfw=Nt+MNpc6AVm-nRFtMj6QT$L(nUd~1f)xoE+yG0C@4(?lqv{FF9Omb zQIrnS2@oLCJE0|kge2dNzxSN`$9LXw&mH%EcZ`oQke!{iSD9ROo6TKCamv~AHJrL`0FY3Y#$3wW;Bf#dhpB?NP8`wy}9=6z!z zkNV#|eeqUnhLLz@dePjkK-&S+>)IyJ`EE^#t%#Z$PaNxh_Y@a3SOppKM=P3Z)k^1r zqa^d#y&P-Ht!L#z)BKJ4@z3)^&nR`gN^;R@)8Sk7$^)2&-y5)vdtuafCR7%Oy_U^B zU$(qLZnD#qY+Ahj{`uM!5!HaThI+kp=PHXUFMDegR3+EV42$r#-c+3WT|53$4n5MS z^Kj?ih~M*@13~_9@wqgo(5gUHUBmp&7h8>x|*0iE_XcptA_%B1o4>BZd|@3^xA%^3Vn!3@G5^GbD%^t2Q?2A@?oFlpCnCpCY(X!2oI*f)gn_pkLw@~&}1NS6`by7YR! z-IXJ|%VNe;hLKWx+?h)gSa~9ExK~H3T^5^`GM2nmk-bP-THd&OBWl=DMtvUzvT9%@3;0Byw=qa zZ`A3BXkkxH)NmCNYp*_2-xNA^vGQdg?=}BYb(5A;N8OI}o3dG9?k3F0IDF;*F0JvD zaa!wGX66P?IJ~z*LWP``7QaTEQW@(Fmy}G4uf=BU?56?n3TWBR82R9yTGc|fn_Fg^C(@+6iwwDWMJrG@-}w< zB>Z#TSTTG(h#{%D&rGH(B^kVz4Gcw(r?>0rKLNSs6SDS+DJaT{vGl3GS!2wNIRg} z%!8LRjv3Z8NhE-6-s>=+%TP|C0M`Xw)(r{WUVF<0b2-v2bfa#;=i)W1nj(U?*R+tgKlofnW>%ZlIb&$gX!R*C71QSG`7NF`DE z9uR3AFBnzq2Xc~EBu_f%Q6$iMH@e}Dv2Zj6iXwe6BK;Y6?wSND7uDjKEu{IVJg1fX zLVb|_ubyMRv{;1BP(o3hJ&QqVcke)xlz7Ct{in0H&433R$gMk_7f(|%RpxbR`t?s~ z#_)`qFJ|?>yoYszC*#1Y%e~HL;@B`0iOML~pD;#sKfX=Q zv?CJ$z)NjEraiAMBVo%UHqNl5?gFKBLcnou!1J7Xazqm-?EPJ|LKoe1gn~Y(WL#F| z)!7sELPCFMyuE*8MeFm>ZcvTKXcFMtyb>BK-DvezT<~Pv?xjp@)4|s?<$5D7#o3>M&A_6!^{a*Vmv%mV8sNDC>5o+=|-xwQ#D zyB14Z_?^Bw<=v~gVTjm{F9vKk>K4zKt)__OBC0oAio^Pm;%}EjWuDIeJo6FAH$C*K zBTU*svz1qs=prl03K~>mBgH0FkenlVD(~~?bQf`OIx$gs#DG+$jlmuIXqv^vlCuQw?>skF>CRGN>g~ zoA@?@@x2uf*KQ$q<-qq+2~n@jd98EiM{J2iI+}8PXnHOfHx~YXB^D6NtaY# z@_@!`jyuWOF*NubIgb&qG~BC_#Hua%Ll_|t$W81-owp@Q2T@H9e@yx6GOyd9?{G2@ z>^DgN>w1TEUp%aVAhwLC!3MFsRk|`4au~``!^l@Tb2BGs_(iMjMx+o+lnRhRyp}Fv z7~R41)#)`L?HBE$2LG}~wa$o$u-I9aw4c-D?JDpVCe(TmnaKA)0cbXqa^*n#-a*TG zuipr9jK;(~K z5=m6mkodLixF`d9tw>c=wTx&pZfl^z?Td=Fv$W-HRL2tm;lnCOLB z%n0~}HL-N!#-V4Qu2g6}pme;|*x zIrmcde}tx$**=9&n_XNyj=HO)^}FWQPPwD46mrEa)_Kv$E}TVv@s#q^uv7{IpxsmV zDu!9PyUjx@;EIS!uGZyltfER<_^=Fpsv%ZuMnA$tr^we_T#g9b zV$O~p6W=q2bNdhJ9phS<1=uUZ8BWj}{_2yio=U{qzQ!hO7(QXv9kq$5`P6h$!j-Th z?2#(!WRRuFsdnT+eB|aKu=Pzn`-Z-Pg(F6@8&IUl#%rNq4P&m`?EiEH36V3nMQ;Ux z7~T12e;}DrkfVR^+&ulCjleYmfA87c0NH&q18@?K11vNFnRu3f;8#?{#46*``kTa>dgG%gW6<3Du?nIr zEY{r&*mFWfc3lrv?WR;B?JPU8EArRb>MHl7IQvzP?G||;!;N8LLV**Hf4DWkL}vHw#XB(*%QLSBbVD zKK36gLR5b}Z_bgUboOi85A#8R#)!jQ$Wh-NX89C_2lf23!uFKlr>}+f01mmccNv+5 zUaQ07HqiWWRN8unN=O07fLz!JF=@-)VN&8JWQjP%oe!P2G7Es+37vgPhblPp!tUOU z%Sc`1cCxb^A*;9DTPt;#O=ALSP-iH0; z6M$p4J!s?B)3pVH4{ z*OVXQIsD<>#~(R<0n-=g&2M?-$$-*~^IfvT5I$V#xq0_&SaLFxQgjdGFe z$rov&=B1A%diC}{o*@E3uFik(nt@32W8WpJ9xOsTR_4Ox++1g^;m_o&&>bm#;R~n^ zGdl3>19CWIjDVFG2(pi>ke<5}9cQr795X;C#9%D!N?*kZY3L9GX8~(Bwo$MBJe44*u3xn9Nc8y>N3t z(1`^4@%Q_W`lhvzc>PI{RcQIPX-$C17Yxu?FhDoT%LRx5SvQ&W&5`~T?w}f%m2tOn z!`pOQB$WvAA2Vqapzf6*`@cHU3W{eR*Jt+kmu5rd-Hi2o( z4b`!O(aq~7T3wsJHwvzNzc@k7x_2WV$G({FhyO6U5!mko_A7+Vj+=(1kDdnWO< zq^X_hIcK3T$DnY`r!Z&bzzsWxv?hae@>jIo2z|SzLDV)v4OP5x78pAm6Ja^IHLGmHaM%{rv|M(~} zhrPb%W1TdbCHcij4d&gIDA}6OLL94w9)~S5OYKOG&#i3RnznDf-xS()>QB2gNQ2Ag zRKQF;!XpkYzla<&;KtQ?7#(!xK&2b7m5)#ox*H0s z}TcSI_u1&KJIgb9q@J&!8~#ZRM;$$@Ny7gX|A; z6qp!%1&C9kv&HX@x3`3`j9JmD7@dQ@ zL{b8A#G^07$+#DfPLE;XayW=MTMBhX_7TYnsPfqSy4&>BnH1SJ^t2ZQ$!iwn>KYoL zzt@j}5AZ}XkHuY0_gafD?cS%cniU%zx0$g9d5MNb&demn9+U(9Z_tGBYsFZakz;Hn zoMg;5>mgp_d4~3b0>SSz6w&yU!fW;XhZ5r8`3S}s{8QVw*?iof8gr|Y$33j+#N=j>#5E@Z9yU`! zYS}D($+?Ac^6cy036aT^@VLnnR(nKxeqL32>rYd<4?l&|R~W-f`rTUmuD{SDT#B&T zG}3~lBqiP?T+C+-XzEb`LY7w#s1{wjp?1w5OJku+TbADE-@-rJlzshON9-KNF5E8= zi3R}zbbXzH@bsZ5%>;}59TU-> zRjo1?7xN%4nnrh2#uy>h4F$Bs03S_pjrQ7~7JFBa2(TK*0x05cHa)1KkL{Z=aw*@{ zMpv*6c8+hnF`%+CV8=ni{FwJr-{)@JVXKL!q1wvNKxuUbvu9KBXc#W$jH>eLdVbUy z)%v!#ytwtuxghJJ0LTQoj+(;oPT@~Ka!O0>V4P#5;d}d)r3Vjhxk(-?xZkTQ_1r@u z{SKfp2DFL$EJ^xYN2@U_L#oT_o{XXeD`7-=!_bqCyEDg`{An=9D$kJ|u@7T!-Q3p2Y{yRDcB)x)Gte?oK{TZRRU z=lG=R$?R&kU6Q46i+Km?sF6`4d4J~Wso|Uphi^EOfrMF@xBKTEa(vJ>X%d?;!PP1M z2=rzt6-NYZ;M}{Fy=tpB$ZM4bK|u|p*s4_&s7AjB4Wa8v&wfsf6eq{#Wgy070ZFS; z(8$n8p>M&ZKRz3yyVU-SSW!gZBP{4##rw0_4iEkkABvE)DyK0f1-Y$tRr4`V}g|jZt~C3AvUlWAydQTd64zG$4-JFjUtGvl1tsV9Jlhxf zg&$8xYU3i;NF^bg$k(Y+>*t;0Js)1o7Iak?1^B25xdW z)DLs2Rnw!%%aZ${hCeha(lG-*QjQAOl$GotksIo_m{rLIdb*^fNx~{1$bV ze#~b#mbO0THLR@Um1|O1+~*SPSciGm!a`>VmrpX6sM?hOOav*yInY#vt~rHCPX#6e zkr82h_0N-sq2eJYbz)I)^PjcTnxc;1fa;AhFo?*rx?YP8CUvR-W-ce)%lu?8Wgl5L zk_@Bo5_JxPG%NwkU#z(&G7TQo2-`;21;qbkZ1uxkPB zmtUKCA=-ucW;aQ%Zq`Y$LHW3YIj3CF>iwkMbLWJbCx&My4LFy#*z)fHdr#;b^}bL& zs;!gGtvfBEWV;P-*H`Y9b~Du0s7_r!+EILCi_GV>{syQfgjx2MI+y)oPE`ora)Bj% zlh)?PvqZS&1!(xnnpV=t{V8Foi6RK$+d?gckr!417&Gz>G`C+%Bi0#TpWKnUkkQNt z>6oSbQbm!O;$ND62Q*5E4e3SdaHiegPdsOXLok)mMfXh|?Na|}$#2D`VDF}Vet4B_ z=IbHR4Km74z#D#|%Ctu@awb5Q?^9&RQ8hRd}LXt%b}+$drdn6dHy%` zQ#IZTL};9Si*yLie#9`{B!s32Pru3PJ?#iaWj{J}zT7)PVF&QM`>34{>r}CbnR1Cb z6sHh@HZ@A4hdguHfBqFRL0+96$`kn~3_5Z2|7fiAH~#uxi@F}64kbyLPOYSrWeOaI zzyqGlm$>ibcD7rEW|iXHx{j}Y2pfs1y|Ix)XKyLeoN=$m>psW6Dp+>Y<p0zi-d-*wkb|fdMj|)Ko z=Rf!%6BY@I+aB$TTY3))cmv7UW=Dv6v%)a3cACo``@)t!vKww`1-}vOo_S6HoMB?4~Nj{a}u}UbV4FO8JkO@W)vn}sY>=qd8 zRrYEyrXW|BrD3hhGCTy`~rEx09T8!4oo7l<&I@ z+Sg*ydYcQ_>XEU7y(cx5I|LMvP|Z$-fGF7>(sH;(D0`zeEtb;fX*rv+O;=hJTTRtSf}c{ZNCDB zuJ8sSao3BN_>&7J#{%w-tJLQdx)rd2eSlHtoXf9rk#6 zC{_}!CzMNQ^Z<7&WwC-8{+I|xD646d6gz}F4azvi3u*!S4C;CkrN5C42WsLx9_xx} zTu4Tzy2e5;EO;*N2wo+>x`WbsfGtyXC`KOymqq0KJY5oq(A%rr1<0CPZA%b{2t-HY z)_oJX-Zz=TI}2^R4O40g09j9!?C~CpW1I86Xb#`0@t9b$@tWHkD+b6r1sVPjTk$kP zA=6a`mRai?=s9SVwa5yI(HUz!ihy-Dkh7uQae~kQ1FFxQYc8w9ljr-jHlm`JxQsmD zJChT6mRPow#ybG8kk!Yoo(d)f#>Pdn6gVqyLv~2ERG~Y5rp#94O9XDVI?#ZdyPmv`C_ppc(zTxH5KGvJS}lWzCZw8VBHBr2M+C9iVI zxE%|8^3>4Jdw58B=^Di&T)5Ivulry^ZBK#e4*#qN8tBDadLQ&KWctsX7foLLqPj{Fy3-mhx7r`tRYgn9VA|TN9OjKXWAn|FV&V2R)OzP}CTDZdPk)>m4xO8M`{oXR z+A7{2*qM#AEJ07@uLdRmxpnnfY&|Q2A(#2ky4rO~&!%3Y2;)N!co1-{O_NfPVFs~n z=8an`vi>GcArN{{`s?&8R^9kHxvx5LF!;{~OO*A~O#F^phWY-9=-*? zq!$rm64@*^jg-%v>OqVrc7TbUAcJJeFEaVoQ5gcuH58A`6o+yKDZrAk74coSFvEwi z1|62<=>How>p3;zYE#HP^b7$!<%PlPgB4;Gn9f*yVyKv>er)QJ>W0=-m|XQErD(^ zQo;(C2TWie?n9R?)ZCNkx4>DP2l4wVLsF~8cQ%IZ)pu}}rNI4fZGFK)yS6y*g#hd3 zk0NEvv#d>YH?bh!R(6FSbhEWud-v!F9A8R@a*)!eduE5zH|;d+#-&XcV<3qnzT^zL z2~OlUf1i%HS;u)0|L(6~=xI8-MJYiP?S|5`pQp#xzIwm*Q@ddk7?a^MH=*=%6 z%3gK%39O0^DCw%E!IYf!9G={NP&0hGy-H_|l#9}bS9bP)3LC@sXt-vg?{o|^m2D_r z0FhnJefMi0m{jk$Q95>YAn$XPzYqQ)1OI(m5U}p9ni@dCTP?N<9CiA-im|bKFlpMx zrrumHHKb4~llXWtTuN7x??jj>=j*(%#7+>%s^l%EM^N6Y7lF=U z=&knQHXFU*o*cRdeS{rGA^N$Jb!_^IjJgS+D(Hc~#b}mem7;fwkXr-sHFflD>}q3; z@6V{az(v*Q_%^%kx%_5J*KjJA+DLpI#s7KM+U6xMSM}%*ACBJJT(zT^>t#$fc;W$O zM0p`yjm-X4bzhE)E80H?(5IOB3$4j-RY`mXg_Tc@c~0L=i@odJ4-~F@Z`vOc@xEnU z0{I^0R{G$2&3(6LpxzWg`62U6UQ@O% ze`>YTf`=hD-KT>LCx-ag=XN5qd1IUZ*ha6`E#B#>TGQ-ImPFTGdl>%hmIWxRrTzLWsxlfbm9Y~QWB+YfD=vH{(AyClhM zS}3mpK78!UDmw37AGZODzqb=Dub24Gc0a_RUzDR_rOzY=NI9hdn8%KwX9s!Lc}>l8 zSMkkO4Ch5v$7O=(khWK{CsSlB`t;<{azt5(Y%@^1_vMQDfWVzYf_Rpw z;1y>=D7N}1n1Z>QLA7oE=p3)*a47k63Mo4ke%2~(Q>r$-2*Xn6(dt7J2|uwaM$Ejf7Vbq4^+>+tIn5OqrdWvHb)gW!1O%Jj)b=v|Npsr8OxP_OoFoG*LJthFUDf?1g{hZ|=wOgb?Jhlvz$X^1bgic(Ql%#W5?0$mumh zEx8)~c6!Lcx|;om;RNe{2B{>MWdDjW>6N+a4q@>j7-Hn9Uktb6yb z-2)?z>qCBjR~YiyeyqYCY_c+3#Ms5h@|aScJ9yoZ z9-N(P>%B`4c~c60iWPIThDn2=!rw3z{GyW%^>jZ!u!e#m<1QMGHbicRz3WEmUvOiYhTi1Q?E(TeEn_X*5R)8is=7sLz5F;AN3}8<2L??jWCV@^xY^)e_!L9&r-QlB)!PWac>oH!$UL+kB`dXC+*@k-!DZ_Oy8Yx5BDB<-<4^E2oOhp4$@nYXluX3@&$MHW9pV)I$=~L>sB)L$# zV3N_@_9S(+H#2q8kg`u(#{B3Bwu290ARKBt0O^Y85!7ol({4{qv2TWEmxp>3uxsEZ zsxJE8djHzw-8*hVj>>Xx+gDF`$M3(9*q2_f!<>);xUP8z}V&ZC{3rnu6Go#S;! z>jymY%iAuuZ{-0Dkncv{<*hkt!I)iu8zXq^>S^nHf6Bm-KVbMH=-N$R2l!=Iai>f? z4$K-AhChQJVK-(<08LU5Eb@@FIr_wZ^^r3USb9&lEzkhY0Z|Wp&4nrt-4PSwxOUym z`?=7PDM)Ua0}qyA5Qxluj_)TzlEXerRLY6vuhYdl>jT+fJv?)gwUVR zgWc}8R@r_5qb4$#(CGy6D)=NOfSy*k@<2ea@~)joS)7ArY*SCIOr8+Xvg~`&K+lNh z*WO?o1Y&(*nmdOf!dxcg*>gjD1Zjv}Bh-@#)JUUa|B2aYFAsw^ApfqSMIFX} z4aa};kN>7NzJHB2*2*{Fi{n35Qyj2FD}D9>SUK6&8R4&gdkbgc=9pD z%qpNIdVA{-2qo*y`2u~y0GGJlJK|K3^oj$hODX4dKPZ+pZodth^hGNzAnDC5E9~CH zuhIlA;hXf_xZdg|%W1AvAF*`7O*P5ccXDG9kjzCSd7~@r6T9lJQ8A(6E5_8)GQFV2 zYreCOoRyU&YJw^#xM*t2aN^X9qcY%l9C5oWiNi%^MQaINz=tc|5_(A@;BBK4(4S7M zO*WX7Hf+=v*MtYcJySGd8kO{oo2@x?zB`c* ztae#_8!`U&W9>*;aj}oNxw-wyP{9)<4(anDYL8+fDk|r@a{si7pQ{MhEP11$S2b`q z|66r6Si`bhHX(`@L|8WB!KZE?Kh!Oz*h#Y4g_n}1$jv8gI=i|ib*1Vw4AK-ifxFn$ z&6cn;AJ0(Bpa1+gFfh>VUxKW`*wnOz$%IQc$V^@4><5e!VAHBH; z-l(pr=}J@bwww9&W_zp`VLAoS;KL;GO-{~$E5qRCZ zcjs1Nw7`YxJLc{viXU-6S9%?g?IJC5>*^JyA z85#;3I4v(P&o+G=BBImCMg7Vc(iB8oXcYReBY96$bgNNxuqC|<2`Y>q@rSghx4M8R7?&M#u|<6ZFL3EdQ@Fq-7nw1 zT}x{)mVuFx56*cX+Rg-ZD+TX8izPR+K=t4re~it{7Q-x2 zrKP22P>t!$>7P%=2Q$=+_PND+tnKhC!!ZhT1!ZOatE;QG8!lLl;v1`u*9k*HGC>xnG;T+CKz%HD;)*$4t?LoTLv=@+z(+~Pan(9(xZTor~QqtE} z>S202IZ;jACq>z}Fpy$#CUEI2sM<;?lCjPCaa|N57H7~n^Hy)utCt;EDz>N_I4%1` z!wIjcp@uK`GzheU;wd~LLRk6eKNX;*k)!p!e|Y%3q-pUp)8dEI2?+`LuW!;VPDe*4 z*UHSyY{4;CKQ}t%MUsD(u<0JB0>Z{9>E*FcM=5PasegWi$)()VNUHK0#^HJyAbb(| zW`D$z;q~Fk$5J@NPuRA_^yrb+JAjAafy<{!_Ho}P0FHBu6elZ7h@X(5xx2fY!d~=G zOr+t6hP;yFE;C~2nL3#A2@4L-S+ z45_HDHf00V*v-xD>Dj19&QJ8x6lHgCTeEGB)TSpbELuCOrxlp~bWQzp#CXZ2!ci?+E8EZB{)@{Brs&F= zh&UV9%!M&@NdLRl$6(dRd@145iAoBWgu!ktc4Fkjr;4icY|T%*z%8&JA1bJD9jmbF zePNt^$6iXK=u1IChqH?dz{MFSq~h03L=sg4)~nDOVnXj+Cu(IkDWKEpkbMygQg2Zc zasAF>xi>Smwfa4DYfjLK4{Y3rgYwZaGvgKRjaFlQ1G$sqD3T?6x_=6R)H`OY`($s1 zb#hI*BxP(x48ASEYjar4^O%jEK)1IHo7>yBO}OL`jU7A|V0%7_0p7B1$7Zuf&C0CSU1^iJ;IeXOSgb}@w8B)+9>un43tcsCtH518O2MT?|Ap zjtEL~Nc^_h^3_n`xUK7f>0`~Rlb6tLC*Ym|SKfxoKm(+sly6FnN&R{nC8Tow-Rk=r zyM4C}0s`t(K(3$^xa$7al9TVQ;&&Xrf^RjC+^9k|obYORQGcaf>C zGoo#>)82V&##AeY33@s)9+jqZ-jK5*Z*JWjdOxyAXuB2uK>FJg#%oFA${f)B4#SgM ziVRmkxOrR8`j@OiZu3i8|8w=r5Yn7!0C*n_4V~*?xcg<5AY}LE+e6-YH;OSH(zr1rY@$G<)DSN z1*EzcKVG_YiS13qHFSS2hK?W8qCAC`T+ItjW&xD`&(QUenj zUl3~RZ|*&e9lK$L3amq1=U#DiF?@)xV9o~5AL9*aE_yGsN;8U7J^5%~&v++Lgna>u z>$*PtgHh=L)_2dD%P8XhDoLr+kw755z(zlnm+j&3G3wS+z|*=KRbF` zcdIdAqibZntS5ER&voqNIKp}b(AThv$wy-06zAKwB(1wOP$;Nye*UU}Lxq58lST81 z(5www{;HOx^xNxuuLPz-*-+$A7C?f2e*5XG1i5b1<{hD-7p`hmVtr|aL~%3Z`zGuS zTFh$tb30qGAczLm2*ZN5*JEWy36qq+YQd`;XZ!Uy@E`#ChjyuZuByG+vhKKaZ8FljW9>vGs^i4353$ z`g}t(_(I^_A-wnS+rX1&OjWiEvd2DvD}5x{393N(&ngM4{SDy3g9l!qgJG-HH%1d( zVzp!aQ*C9bfP-i*K4~YQ(a-#)E4Zg*%qN*Jd{WQd<0yz&Mg|jD#ZE#4>uqDgo~~T4 zKgFW(CG(=9ydV+vB2#Aqb|(DLB?36bs&Pr<#v+fXvNzg%Mb>MOm6wYduumn1+ry6F z5i;fCO=EOyg@MI5C!T&uEIRi-Z3_yMTzn6hub;0oMk~l`WI;CxEUSO6F3$=(q^mns zcd!YOR)A;`@JxG(U$p*(*4bv3FukRBpccKpX*>+}ak6ZSebz&`j5e*>yPepJ6+qhln^j@r&)bOZG$oUl8sH+cG7oVC8ae1144>N&w zJ~pm7x5DEDR+K-GWS-6N04s+!TfPYCaOH8RtyNDv`^j3$d|FRt6CCMRmUOcN?D=zW zXgTi%Jx*pdK3U&2etzGhz;SXywoDoA36s>V!v_CgPe|I@pR)yLL#8Ra5+&4QMZc}B z4Je$;v}Gt`fzW;Ze<2lzir?l8k0}S29mJ&XU)4#1sYz=8QA+@EstjdUfz+neRSs%pH%blzhL@Ay8Zaf zofka+ocoHj@P1-Z(m-y#3JfAYWmj>&(W+n|s6U!*oFj+4pIQy|if*QitjuAWDy1nDgy zA)oVL3{eWfvP8~ikrNHSEtfZL$f)}X@tqYFO+*XDo#tJit&tXRr;Zj^Rqe%{{w(w9nU zC-;U-zppgM#Dpy%1F?U)pm8H&4IB$mpPjS?mA*KOYl_`6)NS6v=2uM3Vyn`(cy)-; zrZDiiKELO<$lDF1Y#4)H!|F)WykZpr4vT-Lp0u*^)J(%}zBAFFl>DClcC4qS2I62= zIDC8WXX)YtO3xcrk1h?JF9gm0gi+@L0Vz4hO}7SsLo!b&AzekQz0`7%v9|LZXUzpQ zM9}`V{TJ8R>)m*>zPQ(ZYv1g4BhcJ+KT>Us+#5IsfuK7M-HO8B*ZF@?Js#C<|H+*2 zyEPK=t^HZSsa3^4O#Si_2JhvlgLxToot@_@ycdt{FB?XlrtQ3cc2Lv0sP-D_7QKXj zwNQQB251GMXWQ>7q__O~Y)R=abNOzud9c%k62IpNGzt221y8_IP0Z>#6$X^V5*x`oOG% z-Mp580Xd7uk6-Kh;(sA&d0|ck0#iikmS-5?l?<7(yX+`e#;8qRpC3FrUkzrvz_;fc3 z&N&rx#r#7mPRP9aGA%{h(z>K`COcN`eXJTu8!SfF5{8S3f~ygenKnr}3v{;$18D^U zJX8o-x08X7Aq^!a7{dA8{$m(qqr8pUXDk2PHnzpq-at^y<_I@~g`W-|aHw|ez1M++ z`my-?E`pBjQE-%Wv*dd=*xSV(b9eP55SCv){a6MLG*kyBW-P(;XEoB&xq#h%t?<@- zZtLN~2fr=-C+8dFv?GCns;9$++N2=Dnx$8d{PM0h(Ov75^qB)4C!_bzAlCzT1-7Sx zM16flMTO)7uQ6HQ@vWL#Rs>c5*HXVn`>5DoP|NWXuHr~S1Wb)@D4jIJn*V}IY% zgM8;`HV^-6#*ofK=Klg52v8gX9wC4~|MulIkpKQ);C_&Q`#v2#|N38G)PIYPHpnco z#$1y0Zm9O~e>qi3s6Or%zE8Z|7KgSpo9Qc6)E?gx@N_a0l%aOC?n#*6YsDT+D*XMT zb1#UFA~Pb)z%0zlYGG=Hib}>9D$^d^D_FwtFo8f-`WJ3Ex;}oa6w9E%mn`LIS*X7Acmb1a0!D@&4S`ZnQqNLUURiUFv(u??fb8g`jIOj*ir%GiZ z;Am2rQcargIH4MwFP0JTb4Te+Iz>$9b5d0H8wl@Ae4HX1GQH73ZHEbah!c?>`|54Pxi` zWfsrR^UGYpAd~A<;lCp-7#AAFz<+REt3gdvTG@Sl)Hu)cf4$)u@~QUd|8g`#*S~*j z9RC+=gFgPhHIDz8ZQPa$**D%_-LRhUJBzqatzV_Qt=IRA3){k)RJY*~nv>$^R;ryw zVoBwv4U%V-?PJVMO&3xCtx56h;$qkK7+@$C=((U`wh)NQayPL6HNb*Yw`P%SZfdnL zj?D&di9I=hQqunE_wyL9=dxofRHYR$&iizV+O7eBavWB)lRUod5frBUED`&gk)-#u9k4bp0 zc=)ffib~%|qQSvh)mJ^ve9C&&~Ys)7Gk03qqG1f)GQCqo23@y1Qx z{)QNeU2lYw2Nu<9&FW{?BF!%Rc`J#r5AtC(63hnLg;UE17m=tFO*~uQOm<1?-k4XT z7e#d~uX`$VuX&nF#gr;}&bTKP5Lim;)?fPU7e9AA7`#S&RlDXG z1^9)!{`C)Qr~U!`zMt<@=xG!1N5uW#MDzc@*8l%^ssb+=a*@32T}qT(dd+J37v;`8 zFkSdS+p?-Th$Yr%cXmz~+uN6eUg58{Cj(o(F==)J#3)wV-yclw7a)`?6=v zR3EnIgen>;QqklBGERu@N2HWlw%6z!0-7;s5qBdW2;ez@ zCi+fbR@+^IwxF^n-fsw$Ap1bP=%kGX9hd;XX?Vj-CS5d-;l^rD!cvvt%G(Hsf44Ri z>|X&AWV@}+=%29We=B;S>)(GfRrSA&?O@mcQ)vH-zyGb%Vn3U+s2hdF-RtAX$^NH$ zXV;Ue96m%uG$MC>IXT~eWa6fG6d!Hx|0(WDpqfg$G-xY!+k&`3H=AM$v;q-jQ(0U< zx>ZzM2wM^a0a+tr*u&GN6_8B^B`mTCvM-T+Cn`&nRhAGiKm>%y8nzHZmNymrXU;$8 z|IbX%%$YOiEU`Fs+Y^feiuA(}hH-B7_YK`%9MuJ$GH*qUQtDm4Jiwm|h zDn;1!bkzx*2!Hb7VJD+WD`6wUJ!P95p{X9KaRrv@a`DVumEGl&3n$A8kqwQ43psQ-4ReE%ODOhkJO$w!dyQk#{=(&=!kQ$2jPH;qhJ_kK{wH z{h_?i2>91e=bM|Bteq}gaHbW@z{~cCcWW|XKfx5mHixYDoL)s~xC{hK1u4(v10-AM z2Z6KkFzHhZMRYWTT_llc2NYqoY4fJ*yILTsx+JFrZ*oH|EENS#lvdB3ZJO|tHu-%3 zrqAt+QLyxBdWGUcqabrp4ozqy0mtFhj`izLzg>?-{nLCA8rX^2r{HvLoWHAUi<|2E=bF zwLZ_dnF#!^%QwB5Il`)jl}tqL#+=r(jF%H&5@0zwbBEI{teU?=rI~0|qCzt!Oi)Z@ zpZk;T8b7 zd$7wMK;atBXp;x~T&K+GBluHV`mIWUWwuk*vgDU(C20Ry*C;_SuVQ`nL1m+s?E`@? z-qGK$M1D_R!t(-{b%DyaT&`&N9-$kxIWXcy&Zy3Ym8ydZ1E-OV9gFe8d0>V zr65OU=eb1uu2O+u=6Pef$0o&HMr(@cuQyE&N2OItcY+@i7y7;=$6E3Vc1I7Gx^y7; zHm{r$q4(8zMJ!tNTCvHiTY-HYPaf&e1HFW+90)X3C9?~U@lF{!n5o>L(m@wg^P1tq z;Wd`UPyalW!)&bu%ZLk0v@aoT3Lu5p)Vm*~!EcNsT)ZGITse6cK?2S+06B7VMmSee zlvjS&66;8B%A}i~GAQ-PeqpmGRp${j_IVEHpYaMvp^jzlue4;y2&>ym`2F`wb(sSP zz%=_$XEIzq@iQlN*<0d{HQ4L;A?^2X2z?LOVc)L)7Y<~@{{PR@zQn_%`cpr|7nSLnB;e7 zo}vHvr5ze-COm#PD0Zf#_u#C#zV2P+ig?Q*t-GV=W$!pgC~5S%D#e#dB=_dtKb+XP zLhPI}NR`-wLbY<>8TKj0jbtpGFHCgv^wP#8=)eC5`lmO#^=>(8Y<5G&ljdr+$N1(R zV;rEqbx_A*Dbdm22P^$(wl z?sbS<17VAA1z`Bzviy)Nrx>h@OWxG4ANTW_6*aK1_);@QCdE{zY^uC@k?u}5Wj_~0@crAKyMgex7DAsPz-;u(_80JI?8WnW#Fw(I9v0wQa zWE4z^F299#|5z@d5;wcYBV}%{sw|f~sL8@Q)aT=LE~&c?o~elR=3#3@AYoFXGhIk;zt5Q&KI_wr{`i#s;ae(&5%$f0jVZF!B2UgloShko{-?vQ!yMTAkO2VNw1MR z#{&A|PD-#z4P7Pe^5umv8pb~JQ!UHv#L+{#HmkPHnpscR)v(=9Aj;obxq8wR&Lk!# zT2*)JU%!6clUEA$z~XsVj^#tUJQqHX?5LhA|2ZXG;6oVkxt`Q%?B0`EDbky17VOJwM2N2*gMk}vzec4OE>tht(W4oPpocZ9P_>E0qu3wscejqaQ5BZut`M>Y(umbV7}<_OcSF=`l%43Rk8OBlzTNfnOE z8Ss>)lc$Eb;6c;y({lNY`XEy3aX^Ir`XD_%XKQeHeHKIXbS=jzM^xl9c7LGgXLI3{ zl<-AN^k+HkuxQxFQcGXR^t9C!ZC5IuF!jDOuOgp}ASAr0Zjw8_Du}9 zZt1uI%*e{_`?+2Yj;~y-=;OF_5or<@aRbmnoCgUQSL}OtAIf9?ww|}a0SD9drM5&6 z1U}ZoP!aXf_{;5Gi{1|XS!(2=_V!bqu$(!c1~tqpQ}5?0tp+b%bF#q5Xg^qNaV@K; z`@K_p2rkldD$3;&*~6J^oz{Zilh9ttFqvqIo9FYH>1;O1)&FPB_XZ+vw_SgLY%izi zC1^!!o$$SjeWB-f41BG=m+EjupJnx_g0{5Pt%@loF>i_on4T>D7&q=#1qEgS2E`ubX+Zt@4=k;$^7;dk$^mKikUPzF z@!fXBjqTgF11&i#bYCvs-W7Y7U4j8wHH%{B;Zd{~mjZ-s&fIL;m8*6vpzQVQkG{!H zPEN=u&L}=@%CFqmQSBJUx<6gD&4pDsb)vi(WI!aCho{0kMq!RnZGili1X%LRa};RW zy4TAkJghOK*ChrR0Nt|jtKW2N?2#I*U$`#;*r0PE-Z%2G!rod36~7f_W@fsu=DaJ* z=SAB&%M5Bj>=D5df%M8fiRHOEJGi6Tz2C$!8mL@v1wP*ZWK#it%>_8BKzGY zy%^>mszSoASh(<27bYf;ahZG!mrv&^>wKxOR9+6#ZynN}84H#W3_k|QOV;(Y zn^>*<%Hr}_36eneA_qC*v7`K=*sB6DC`o-o=GtQwR6A$qTr0dQ@DMLI0u7)z1P8O{ zyF>ERRr2jB3Z9g>H3Ji%8eV1v%zCMVS>cG7&?~h&u96Pn3{d+h(?H}v#8d5p%2%Dn zmgf2FhgpoieF==Oz;Fk30BzjxVksHNr|Sl#{x}b|ZYAx7XV#}S#eah&kzyaM?>&4a z4wngQ@qzzZCo(g@wTOt@CGe_KPXIBlYTL}wdS=D?TBU-B$eWe}4+cL27I625#=r>7-Ce|G6tUg z>cTSk2y9^bi}y36lVBys&BjMlU(|M7rLDyO>sv9bFK?JV5*|dNyV_nTyc*Z`*4leV zi&kgHp6qZJK|<(q zUAmC`x&fvKtlXNO2wKCJ&~l(wtz&e$7{hL8pic^@U7MVOlE2nj6igGw; z#j$BIbfDgFtUXDxS8|cd*Qi>S8lHntgr<`b_7T{nWW#5a`C9u-2CL!jq+63o^nErT z@~kPaI|;=_cW|-w;y}j>KGZVneHshfrmx=i_xGO&>eub2zZg1v4@I5EpYyygqjfCM?Zc_Z^BY_MF2ORh*2?RTiuf=B3AMdt3Mxuoj z_=5_}ym4|g_K8NrWj?k3gT15%G`GWv0I$n=mW%gtuy0DqYf8afv3h^rdODOp1M!O@ zGZ3a?a=28a*k#l_yx{rtC!-&!wYhJ`?Vyj=ehsYY?5)V#yY*>f-+o;rVgcFW`sQ;dX2tu;d^C{F*5Dw7H#2%T zb{Nes3%Ccjss)iM_UA!VCY!2fYxeA>-fl_q!6=ix%aWdHjmn>I8Jn30pXvN?r$RMP zyRZ6%O1{f6J70w=(iUKv@1+;4OL?tBHL8bkATAz=_c*e#fBCtevuzj9_0z{TRv-Vu zALuW%`M+!e{l_;gIn}>pD3#rIIP2h;Z_{T%5W@K~#xUd}(cEd09x?1=(&u%;OWTh9 zMIb%I2|qvCx0TL0XE`Tu0E(b!;Qvdu&bah=(jEf35MaS`a<-i8O_!6btsRD+k1Hvs(ah@#COZ&vKU`232+UK!wNf z&j=Fl-UYcR*%R0BoC!iPp1bP1*eoTJ%L4rUyz1&|>2ir#S|zcRpPHDM=RNmnuavrt zFyel8QdZCR^`{1WKp=0Cyx1ax)x0(X+E0%JFeA;lZys(IgHF<5Py&3eHn{P*x0?ZA z?o+^4zpR+J?44PQB;a|cm-*B9&r{i{^KLN4e=2kOt(Zc@;NW1Hy%(4Up1k|{bR9St zv)G0al*CxU(@0X@W6W|0`yt4O<=x1F+>h915fBYsFHjBAR}y=vr%D4weF2=L8k!Px zAen^AGJCSyT-d{so;(-nnA<`;pX0;bNs_f}qF&d@z%T_INH00*qLSbz`(tGH4H&X& zxY`ltpk=KdjiJNNoU_Nd_S<=7fiJC4gdZErJ@Q6E+6MDfB#_2_RZl{5m7QmdyDXE(Bv|sFv|0RClK&mJC_>1@cOrqah0J!%>@=tWELA zbuoVl6h4J$)O1dxddYY9vUB*qR~|HpS~-v6`S`Ie67&|{Y_2zxf>CIG&mr#W+zbeZ zrymP8>ST5A+J0H2Pf!pjVFFUNqZ2leSuBYp85ymt^MiW5gq~=iFYtTB-%u)CR{6ig z*MEf9KYj!K|Bt%|V0AqQPGuCT+f?n8Fj%t{f}j#jlLI0}f}=tK8%O~;y|1;bDG4(~ zmJ6{4*ugLK1GF1pK9f8&1la^GycOGk#<6Ve`2P$)kraQR?*40|A@+R+cfY)k>0E_5 zj8vkqck4=zNCGD4M5ee&lx%JTZ>ennpso(YPmz88!njjGz~aluLtknG#)e#pxC;1` zxLls1q5xVTGRY(;KlNG&yzFbKzcj2bDH%yw{}^?S!iAT7bo3e+A(&=YMhy){7VW>`F|Y@qi`fEaqVe`B1^b zGnZkfa2HTxY@}&EQ=*!eqo^qVWVMlHg@>_&I^SGLSFWN8jMa8amA_M+DmJm3h=Koyd`KN%=xbaX%+k@Zrh z5g+b=8TtnH`sF$EDKZ`?ZP|v~{bMoA`LL6`JhIz6@Jn$ZHhA1fXt$c>j3UiKFsyjf zfo1Y_ouL{x-M|k8%_)W{PlSzSE2rY4zZx6W$<)V3=n-FZ-2!{t-x^xRft+ z=RS{xD7PX100QtdNEj>venb%n7pHy|*-^YnxRA9!LCBGm`OPx!CW+3}(wAr;O}&X=OlY$4LdF%;Owb>ode` z>KI6{NlYy80}r!|qX5FzUT|m-GX#zy9*K^G0(ha)+%=Z0_xw=x5;soG+76IQ7r|U8 zt828|M4=Fr|72a^X6fe!%A?NNb_h3%Wln?tHbjTSFCwh<5}MopO)3Fa;H>z>;RIG!rV+l05~E7>1?KiuV! zrP6vhB@DRb6&Wb;y38I2OXHiF>`av>hyClNHOszKeFIt!em{4J>c|qp17Tv9^1m<&CKaoE~{BrG=Xy} zV<2NE>U+@^xowp3enYY|ZtYr9Qqqh*Bv>1#=(C4nwO7HvyHoM2mhBxKC?wNgy)plu zNW+IL3(@P(9B>7R5dbwMs=MG#C9(~&`AP(OsLrT`(Ipcjq7=(33T@O>8+j>v$CJU5 zycrGa%dc3O;+S-*wS1{)eLOD_pO*B*j+3tIUqA8S7xxzv3x~3ZQG=mASg1kb{tZjn zqG|uzDTJAYLs2NX((jR7EMO~&4u_}b&BXYjiy8^&OXwZ%TClzoZ8`MXtS|=sb_W8} zAe$Pr?p()TrGYgnx=c!AQ&Uq_wpX%egyG@9T-SwuYb*<#|LSQ$TUkA+9PxLZsFD$2 zSr?=qSeO60Dc%zm+BXVa#7p-7`8Ex}W|1;Mkr=PpSzW{?_dMoU@!uZ#JBV#Y&EOG< z)t^xYo!B}N=F)VC%yi5|&4|u!Up5zP?e5IV-RoBfz-ak6fNook#PD!hfw@|Xyd>#T z!AML}Bpy&&izA@pgX1Pmrj3M8Scpq2Yk&$yR&#c4{cO(qH~)Lycea?EhsDoWAIU%Z zSYId~poL>|mGsNo_fIb(&~?6zP*Qw+=gJ zTI{x<0UMxfXc|%LZnx#Pq=@l0h;~%zb+vFwF>T^J{=3|^M8URQZ{~!Y?9<_3{a_>~ z94-ptO*pdNdjsfp_RCr*Y*4=++!kuVijV_+@}+89R Date: Sat, 30 Apr 2016 20:15:53 -0400 Subject: [PATCH 03/37] Fixes Runtime When Creating new Humans It runtimed because when there was /mob/living/carbon/human/vulpkanin/New(var/new_loc) >>>>>var/obj/item/organ/external/head/H = get_organ("head") >>>>>H.h_style = "Bald" >>>>>..(new_loc, "Vulpkanin") in human/human.dm, it'd error out because the mob doesn't have those organs at this point-- so I just moved the definition of what hair/head accessory styles these basic default mobs get to the species definition, where it'll accomplish the same thing as it used to while still using the head-hair system appropriately --- code/modules/mob/living/carbon/human/human.dm | 39 +++++-------------- .../mob/living/carbon/human/species/apollo.dm | 5 +++ .../living/carbon/human/species/species.dm | 6 ++- .../living/carbon/human/species/station.dm | 10 +++++ 4 files changed, 29 insertions(+), 31 deletions(-) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index f78a80a3c3c..90fed057057 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -74,46 +74,30 @@ status_flags = GODMODE|CANPUSH /mob/living/carbon/human/skrell/New(var/new_loc) - var/obj/item/organ/external/head/H = get_organ("head") - H.h_style = "Skrell Male Tentacles" ..(new_loc, "Skrell") /mob/living/carbon/human/tajaran/New(var/new_loc) - var/obj/item/organ/external/head/H = get_organ("head") - H.ha_style = "Tajaran Ears" ..(new_loc, "Tajaran") /mob/living/carbon/human/vulpkanin/New(var/new_loc) - var/obj/item/organ/external/head/H = get_organ("head") - H.h_style = "Bald" ..(new_loc, "Vulpkanin") /mob/living/carbon/human/unathi/New(var/new_loc) - var/obj/item/organ/external/head/H = get_organ("head") - H.h_style = "Unathi Horns" ..(new_loc, "Unathi") /mob/living/carbon/human/vox/New(var/new_loc) - var/obj/item/organ/external/head/H = get_organ("head") - H.h_style = "Short Vox Quills" ..(new_loc, "Vox") /mob/living/carbon/human/voxarmalis/New(var/new_loc) - var/obj/item/organ/external/head/H = get_organ("head") - H.h_style = "Bald" ..(new_loc, "Vox Armalis") /mob/living/carbon/human/skeleton/New(var/new_loc) - var/obj/item/organ/external/head/H = get_organ("head") - H.h_style = "Bald" ..(new_loc, "Skeleton") /mob/living/carbon/human/kidan/New(var/new_loc) ..(new_loc, "Kidan") /mob/living/carbon/human/plasma/New(var/new_loc) - var/obj/item/organ/external/head/H = get_organ("head") - H.h_style = "Bald" ..(new_loc, "Plasmaman") /mob/living/carbon/human/slime/New(var/new_loc) @@ -129,38 +113,24 @@ ..(new_loc, "Human") /mob/living/carbon/human/diona/New(var/new_loc) - var/obj/item/organ/external/head/H = get_organ("head") - H.h_style = "Bald" ..(new_loc, "Diona") /mob/living/carbon/human/machine/New(var/new_loc) - var/obj/item/organ/external/head/H = get_organ("head") - H.h_style = "Blue IPC Screen" ..(new_loc, "Machine") /mob/living/carbon/human/shadow/New(var/new_loc) - var/obj/item/organ/external/head/H = get_organ("head") - H.h_style = "Bald" ..(new_loc, "Shadow") /mob/living/carbon/human/golem/New(var/new_loc) - var/obj/item/organ/external/head/H = get_organ("head") - H.h_style = "Bald" ..(new_loc, "Golem") /mob/living/carbon/human/wryn/New(var/new_loc) - var/obj/item/organ/external/head/H = get_organ("head") - H.h_style = "Antennae" ..(new_loc, "Wryn") /mob/living/carbon/human/nucleation/New(var/new_loc) - var/obj/item/organ/external/head/H = get_organ("head") - H.h_style = "Nucleation Crystals" ..(new_loc, "Nucleation") /mob/living/carbon/human/drask/New(var/new_loc) - var/obj/item/organ/external/head/H = get_organ("head") - H.h_style = "Bald" ..(new_loc, "Drask") /mob/living/carbon/human/monkey/New(var/new_loc) @@ -1520,6 +1490,15 @@ species.create_organs(src) + //Handle default hair/head accessories for created mobs. + var/obj/item/organ/external/head/H = get_organ("head") + if(species.default_hair) + H.h_style = species.default_hair + if(species.default_fhair) + H.f_style = species.default_fhair + if(species.default_headacc) + H.ha_style = species.default_headacc + if(!dna) dna = new /datum/dna(null) dna.species = species.name diff --git a/code/modules/mob/living/carbon/human/species/apollo.dm b/code/modules/mob/living/carbon/human/species/apollo.dm index ed02ee5465a..5642eedbcbe 100644 --- a/code/modules/mob/living/carbon/human/species/apollo.dm +++ b/code/modules/mob/living/carbon/human/species/apollo.dm @@ -45,6 +45,8 @@ base_color = "#704300" flesh_color = "#704300" blood_color = "#FFFF99" + //Default styles for created mobs. + default_hair = "Antennae" /datum/species/wryn/handle_death(var/mob/living/carbon/human/H) @@ -98,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/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 cce8b5c46ec..6755ad5e8ef 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 From 73dbbed70e14af79894a34b10ffda8ec7d6ee319 Mon Sep 17 00:00:00 2001 From: KasparoVy Date: Sat, 30 Apr 2016 20:48:58 -0400 Subject: [PATCH 04/37] Cutting Someone's Facial Hair will now Update Facial Hair --- code/game/objects/items/weapons/scissors.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/game/objects/items/weapons/scissors.dm b/code/game/objects/items/weapons/scissors.dm index 343c3788bdc..626e1576623 100644 --- a/code/game/objects/items/weapons/scissors.dm +++ b/code/game/objects/items/weapons/scissors.dm @@ -89,6 +89,7 @@ C.h_style = h_new_style H.update_hair() + H.update_fhair() user.visible_message("[user] finishes cutting [M]'s hair!") /obj/item/weapon/scissors/safety //Totally safe, I assure you. From 7205d3a0e39478baeee7bcf49146025b52adfef6 Mon Sep 17 00:00:00 2001 From: KasparoVy Date: Sat, 30 Apr 2016 22:05:57 -0400 Subject: [PATCH 05/37] Hairgrownium and Super Hairgrownium now work on All Species, refactored so if it produces random hair styles for a non-human, it won't do so repeatedly until the reagent is depleted. Also means that species that need breath masks to live won't be killed by infinite fake moustaches. --- code/__HELPERS/mobs.dm | 2 +- code/modules/reagents/newchem/other.dm | 22 +++++++++++++++------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index f8980d61ddd..3d1648fa77a 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -52,7 +52,7 @@ proc/random_hair_style(var/gender, species = "Human") if(valid_hairstyles.len) h_style = pick(valid_hairstyles) - return h_style + return h_style proc/GetOppositeDir(var/dir) switch(dir) diff --git a/code/modules/reagents/newchem/other.dm b/code/modules/reagents/newchem/other.dm index 4fe016f49ba..0fa7c579041 100644 --- a/code/modules/reagents/newchem/other.dm +++ b/code/modules/reagents/newchem/other.dm @@ -198,7 +198,7 @@ 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 - var/obj/item/organ/external/head/head_organ = H.organs_by_name["head"] + 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) @@ -230,8 +230,8 @@ datum/reagent/hairgrownium/reaction_mob(var/mob/living/M, var/volume) if(M && ishuman(M)) var/mob/living/carbon/human/H = M var/obj/item/organ/external/head/head_organ = H.get_organ("head") - head_organ.h_style = random_hair_style(H.gender, head_organ.species) - head_organ.f_style = random_facial_hair_style(H.gender, head_organ.species) + 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() ..() @@ -254,13 +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 var/obj/item/organ/external/head/head_organ = H.get_organ("head") - head_organ.h_style = "Very Long Hair" - head_organ.f_style = "Very Long Beard" + 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)) From 8cca627918484789c0374b941ade9cea87db2f91 Mon Sep 17 00:00:00 2001 From: KasparoVy Date: Sun, 1 May 2016 18:40:50 -0400 Subject: [PATCH 06/37] Fixes Bug where Facial Hair Wouldn't Update on Death. --- code/modules/mob/living/carbon/human/species/station.dm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/modules/mob/living/carbon/human/species/station.dm b/code/modules/mob/living/carbon/human/species/station.dm index 6755ad5e8ef..8bd4386c3f8 100644 --- a/code/modules/mob/living/carbon/human/species/station.dm +++ b/code/modules/mob/living/carbon/human/species/station.dm @@ -805,4 +805,6 @@ head_organ.h_style = "Bald" head_organ.f_style = "Shaved" spawn(100) - if(H) H.update_hair() \ No newline at end of file + if(H) + H.update_hair() + H.update_fhair() \ No newline at end of file From 9015f11f41622b0252b35d93100bcfc66b5860d6 Mon Sep 17 00:00:00 2001 From: KasparoVy Date: Mon, 2 May 2016 18:13:31 -0400 Subject: [PATCH 07/37] Fixes Morph Being Borked + Additional Features for Morph and C.M.A. Before it wouldn't update skin colour or eye colour, and ended up breaking the sprite such that C.M.A wouldn't have an effect on it after. Now it works perfectly fine, C.M.A works just fine too before and after STAGE 2: Refactors Morph So you change gender first and thus can actually access male beard styles, then you choose hair style and hair colour, then beard style and beard colour, then skin tone or body colour at the very end. STAGE 3 Adds Head Accessory, Head Accessory colour, marking style and body accessory to Morph and C.M.A. --- code/__DEFINES/mob.dm | 6 +- code/game/dna/genes/vg_powers.dm | 142 +++++++++++------- code/game/objects/structures/mirror.dm | 1 + .../mob/living/carbon/human/appearance.dm | 123 ++++++++++++++- .../mob/new_player/sprite_accessories.dm | 8 +- code/modules/nano/modules/human_appearance.dm | 89 ++++++++++- nano/templates/appearance_changer.tmpl | 47 +++++- 7 files changed, 350 insertions(+), 66 deletions(-) diff --git a/code/__DEFINES/mob.dm b/code/__DEFINES/mob.dm index 2bdb3432f69..78439abcb07 100644 --- a/code/__DEFINES/mob.dm +++ b/code/__DEFINES/mob.dm @@ -76,7 +76,11 @@ #define APPEARANCE_FACIAL_HAIR_COLOR 128 #define APPEARANCE_EYE_COLOR 256 #define APPEARANCE_ALL_HAIR APPEARANCE_HAIR|APPEARANCE_HAIR_COLOR|APPEARANCE_FACIAL_HAIR|APPEARANCE_FACIAL_HAIR_COLOR -#define APPEARANCE_ALL 511 +#define APPEARANCE_HEAD_ACCESSORY 512 +#define APPEARANCE_MARKINGS 1024 +#define APPEARANCE_BODY_ACCESSORY 2048 +#define APPEARANCE_ALL_BODY APPEARANCE_ALL_HAIR|APPEARANCE_HEAD_ACCESSORY|APPEARANCE_MARKINGS|APPEARANCE_BODY_ACCESSORY +#define APPEARANCE_ALL 4095 // Intents #define I_HELP "help" diff --git a/code/game/dna/genes/vg_powers.dm b/code/game/dna/genes/vg_powers.dm index 5511642e53e..13f334c010b 100644 --- a/code/game/dna/genes/vg_powers.dm +++ b/code/game/dna/genes/vg_powers.dm @@ -39,69 +39,99 @@ var/mob/living/carbon/human/M=usr var/obj/item/organ/external/head/head_organ = M.get_organ("head") - var/new_facial = input("Please select facial hair color.", "Character Generation",rgb(head_organ.r_facial, head_organ.g_facial, head_organ.b_facial)) as null|color - if(new_facial) - head_organ.r_facial = hex2num(copytext(new_facial, 2, 4)) - head_organ.g_facial = hex2num(copytext(new_facial, 4, 6)) - head_organ.b_facial = hex2num(copytext(new_facial, 6, 8)) - - var/new_hair = input("Please select hair color.", "Character Generation",rgb(head_organ.r_hair, head_organ.g_hair, head_organ.b_hair)) as null|color - if(new_facial) - head_organ.r_hair = hex2num(copytext(new_hair, 2, 4)) - head_organ.g_hair = hex2num(copytext(new_hair, 4, 6)) - head_organ.b_hair = hex2num(copytext(new_hair, 6, 8)) - - var/new_eyes = input("Please select eye color.", "Character Generation",rgb(M.r_eyes,M.g_eyes,M.b_eyes)) as null|color - if(new_eyes) - M.r_eyes = hex2num(copytext(new_eyes, 2, 4)) - M.g_eyes = hex2num(copytext(new_eyes, 4, 6)) - M.b_eyes = hex2num(copytext(new_eyes, 6, 8)) - - var/new_tone = input("Please select skin tone level: 1-220 (1=albino, 35=caucasian, 150=black, 220='very' black)", "Character Generation", "[35-M.s_tone]") as null|text - - if (!new_tone) - new_tone = 35 - M.s_tone = max(min(round(text2num(new_tone)), 220), 1) - M.s_tone = -M.s_tone + 35 - - // hair - var/list/all_hairs = subtypesof(/datum/sprite_accessory/hair) - var/list/hairs = list() - - // loop through potential hairs - for(var/x in all_hairs) - var/datum/sprite_accessory/hair/H = new x // create new hair datum based on type x - hairs.Add(H.name) // add hair name to hairs - qdel(H) // delete the hair after it's all done - - var/new_style = input("Please select hair style", "Character Generation", head_organ.h_style) as null|anything in hairs - - // if new style selected (not cancel) - if (new_style) - head_organ.h_style = new_style - - // facial hair - var/list/all_fhairs = subtypesof(/datum/sprite_accessory/facial_hair) - var/list/fhairs = list() - - for(var/x in all_fhairs) - var/datum/sprite_accessory/facial_hair/H = new x - fhairs.Add(H.name) - qdel(H) - - new_style = input("Please select facial style", "Character Generation", head_organ.f_style) as null|anything in fhairs - - if(new_style) - head_organ.f_style = new_style - var/new_gender = alert(usr, "Please select gender.", "Character Generation", "Male", "Female") if (new_gender) if(new_gender == "Male") M.change_gender(MALE) else M.change_gender(FEMALE) + + var/new_eyes = input("Please select eye color.", "Character Generation", rgb(M.r_eyes,M.g_eyes,M.b_eyes)) as null|color + if(new_eyes) + M.r_eyes = hex2num(copytext(new_eyes, 2, 4)) + M.g_eyes = hex2num(copytext(new_eyes, 4, 6)) + M.b_eyes = hex2num(copytext(new_eyes, 6, 8)) + M.change_eye_color(M.r_eyes, M.g_eyes, M.b_eyes) + + // hair + var/list/valid_hairstyles = M.generate_valid_hairstyles() + var/new_style = input("Please select hair style", "Character Generation", head_organ.h_style) as null|anything in valid_hairstyles + + // if new style selected (not cancel) + if (new_style) + head_organ.h_style = new_style + + var/new_hair = input("Please select hair color.", "Character Generation", rgb(head_organ.r_hair, head_organ.g_hair, head_organ.b_hair)) as null|color + if(new_hair) + head_organ.r_hair = hex2num(copytext(new_hair, 2, 4)) + head_organ.g_hair = hex2num(copytext(new_hair, 4, 6)) + head_organ.b_hair = hex2num(copytext(new_hair, 6, 8)) + + // facial hair + var/list/valid_facial_hairstyles = M.generate_valid_facial_hairstyles() + new_style = input("Please select facial style", "Character Generation", head_organ.f_style) as null|anything in valid_facial_hairstyles + + if(new_style) + head_organ.f_style = new_style + + var/new_facial = input("Please select facial hair color.", "Character Generation", rgb(head_organ.r_facial, head_organ.g_facial, head_organ.b_facial)) as null|color + if(new_facial) + head_organ.r_facial = hex2num(copytext(new_facial, 2, 4)) + head_organ.g_facial = hex2num(copytext(new_facial, 4, 6)) + head_organ.b_facial = hex2num(copytext(new_facial, 6, 8)) + + //Head accessory. + if(head_organ.species.bodyflags & HAS_HEAD_ACCESSORY) + var/list/valid_head_accessories = M.generate_valid_head_accessories() + var/new_head_accessory = input("Please select head accessory style", "Character Generation", head_organ.ha_style) as null|anything in valid_head_accessories + if(new_head_accessory) + head_organ.ha_style = new_head_accessory + + var/new_head_accessory_colour = input("Please select head accessory colour.", "Character Generation", rgb(head_organ.r_headacc, head_organ.g_headacc, head_organ.b_headacc)) as null|color + if(new_head_accessory_colour) + head_organ.r_headacc = hex2num(copytext(new_head_accessory_colour, 2, 4)) + head_organ.g_headacc = hex2num(copytext(new_head_accessory_colour, 4, 6)) + head_organ.b_headacc = hex2num(copytext(new_head_accessory_colour, 6, 8)) + + //Body markings. + if(M.species.bodyflags & HAS_MARKINGS) + var/list/valid_markings = M.generate_valid_markings() + var/new_marking = input("Please select marking style", "Character Generation", M.m_style) as null|anything in valid_markings + if(new_marking) + M.m_style = new_marking + + var/new_marking_colour = input("Please select marking colour.", "Character Generation", rgb(M.r_markings, M.g_markings, M.b_markings)) as null|color + if(new_marking_colour) + M.r_markings = hex2num(copytext(new_marking_colour, 2, 4)) + M.g_markings = hex2num(copytext(new_marking_colour, 4, 6)) + M.b_markings = hex2num(copytext(new_marking_colour, 6, 8)) + + //Body accessory. + if(M.species.tail && M.species.bodyflags & HAS_TAIL) + var/list/valid_body_accessories = M.generate_valid_body_accessories() + if(valid_body_accessories.len > 1) //By default valid_body_accessories will always have at the very least a 'none' entry populating the list, even if the user's species is not present in any of the list items. + var/new_body_accessory = input("Please select body accessory style", "Character Generation", M.body_accessory) as null|anything in valid_body_accessories + if(new_body_accessory) + M.body_accessory = body_accessory_by_name[new_body_accessory] + + //Skin tone. + if(M.species.bodyflags & HAS_SKIN_TONE) + var/new_tone = input("Please select skin tone level: 1-220 (1=albino, 35=caucasian, 150=black, 220='very' black)", "Character Generation", "[M.s_tone]") as null|text + if (!new_tone) + new_tone = 35 + M.s_tone = 35 - max(min(round(text2num(new_tone)), 220), 1) + + //Skin colour. + if(M.species.bodyflags & HAS_SKIN_COLOR) + var/new_body_colour = input("Please select body colour.", "Character Generation", rgb(M.r_skin, M.g_skin, M.b_skin)) as null|color + if(new_body_colour) + M.r_skin = hex2num(copytext(new_body_colour, 2, 4)) + M.g_skin = hex2num(copytext(new_body_colour, 4, 6)) + M.b_skin = hex2num(copytext(new_body_colour, 6, 8)) + + M.force_update_limbs() M.regenerate_icons() - M.check_dna() + M.update_dna() M.visible_message("\blue \The [src] morphs and changes [M.get_visible_gender() == MALE ? "his" : M.get_visible_gender() == FEMALE ? "her" : "their"] appearance!", "\blue You change your appearance!", "\red Oh, god! What the hell was that? It sounded like flesh getting squished and bone ground into a different shape!") diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index 699f5ac85aa..d0e8d4c9c85 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -17,6 +17,7 @@ if(!AC) AC = new(src, user) AC.name = "SalonPro Nano-Mirror™" + AC.flags = APPEARANCE_ALL_BODY ui_users[user] = AC AC.ui_interact(user) diff --git a/code/modules/mob/living/carbon/human/appearance.dm b/code/modules/mob/living/carbon/human/appearance.dm index 2822fa99933..ce20923369d 100644 --- a/code/modules/mob/living/carbon/human/appearance.dm +++ b/code/modules/mob/living/carbon/human/appearance.dm @@ -70,6 +70,57 @@ update_fhair() return 1 +/mob/living/carbon/human/proc/change_head_accessory(var/head_accessory_style) + var/obj/item/organ/external/head/H = get_organ("head") + if(!head_accessory_style) + return + + if(H.ha_style == head_accessory_style) + return + + if(!(head_accessory_style in head_accessory_styles_list)) + return + + H.ha_style = head_accessory_style + + update_head_accessory() + return 1 + +/mob/living/carbon/human/proc/change_markings(var/marking_style) + if(!marking_style) + return + + if(src.m_style == marking_style) + return + + if(!(marking_style in marking_styles_list)) + return + + src.m_style = marking_style + + update_markings() + return 1 + +/mob/living/carbon/human/proc/change_body_accessory(var/body_accessory_style) + var/found + if(!body_accessory_style) + return + + if(src.body_accessory) + if(src.body_accessory.name == body_accessory_style) + return + + for(var/B in body_accessory_by_name) + if(B == body_accessory_style) + src.body_accessory = body_accessory_by_name[body_accessory_style] + found = 1 + + if(!found) + return + + update_tail_layer() + return 1 + /mob/living/carbon/human/proc/reset_hair() reset_head_hair() reset_facial_hair() @@ -131,6 +182,30 @@ update_fhair() return 1 +/mob/living/carbon/human/proc/change_head_accessory_color(var/red, var/green, var/blue) + var/obj/item/organ/external/head/H = get_organ("head") + if(red == H.r_headacc && green == H.g_headacc && blue == H.b_headacc) + return + + H.r_headacc = red + H.g_headacc = green + H.b_headacc = blue + + update_head_accessory() + return 1 + +/mob/living/carbon/human/proc/change_marking_color(var/red, var/green, var/blue) + if(red == r_markings && green == g_markings && blue == b_markings) + return + + r_markings = red + g_markings = green + b_markings = blue + + update_markings() + return 1 + + /mob/living/carbon/human/proc/change_skin_color(var/red, var/green, var/blue) if(red == r_skin && green == g_skin && blue == b_skin || !(species.bodyflags & HAS_SKIN_COLOR)) return @@ -176,9 +251,9 @@ /mob/living/carbon/human/proc/generate_valid_hairstyles() var/list/valid_hairstyles = new() + var/obj/item/organ/external/head/H = get_organ("head") for(var/hairstyle in hair_styles_list) var/datum/sprite_accessory/S = hair_styles_list[hairstyle] - var/obj/item/organ/external/head/H = organs_by_name["head"] if(gender == MALE && S.gender == FEMALE) continue @@ -210,9 +285,9 @@ /mob/living/carbon/human/proc/generate_valid_facial_hairstyles() var/list/valid_facial_hairstyles = new() + var/obj/item/organ/external/head/H = get_organ("head") for(var/facialhairstyle in facial_hair_styles_list) var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle] - var/obj/item/organ/external/head/H = organs_by_name["head"] if(gender == MALE && S.gender == FEMALE) continue @@ -242,3 +317,47 @@ valid_facial_hairstyles += facialhairstyle return valid_facial_hairstyles + +/mob/living/carbon/human/proc/generate_valid_head_accessories() + var/list/valid_head_accessories = new() + var/obj/item/organ/external/head/H = get_organ("head") + for(var/head_accessory in head_accessory_styles_list) + var/datum/sprite_accessory/S = head_accessory_styles_list[head_accessory] + + if(!(H.species.name in S.species_allowed)) //If the user's head is not of a species the head accessory style allows, skip it. Otherwise, add it to the list. + continue + valid_head_accessories += head_accessory + + return valid_head_accessories + +/mob/living/carbon/human/proc/generate_valid_markings() + var/list/valid_markings = new() + var/obj/item/organ/external/head/H = get_organ("head") + for(var/marking in marking_styles_list) + var/datum/sprite_accessory/S = marking_styles_list[marking] + + if(!(species.name in S.species_allowed)) //If the user's head is not of a species the marking style allows, skip it. Otherwise, add it to the list. + continue + if(H.species.flags & ALL_RPARTS) //If the user is a species that can have a robotic head... + var/datum/robolimb/robohead = all_robolimbs[H.model] + if(!(S.models_allowed && (robohead.company in S.models_allowed))) //Make sure they don't get markings incompatible with their head. + continue + valid_markings += marking + + return valid_markings + +/mob/living/carbon/human/proc/generate_valid_body_accessories() + var/list/valid_body_accessories = new() + for(var/B in body_accessory_by_name) + var/datum/body_accessory/A = body_accessory_by_name[B] + if(check_rights(R_ADMIN, 1, src)) + valid_body_accessories = body_accessory_by_name.Copy() + else + if(!istype(A)) + valid_body_accessories += "None" //The only null entry should be the "None" option. + continue + if(!(species.name in A.allowed_species)) //If the user is not of a species the body accessory style allows, skip it. Otherwise, add it to the list. + continue + valid_body_accessories += B + + return valid_body_accessories diff --git a/code/modules/mob/new_player/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories.dm index 15452598ed5..93797b5bb17 100644 --- a/code/modules/mob/new_player/sprite_accessories.dm +++ b/code/modules/mob/new_player/sprite_accessories.dm @@ -1898,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/nano/modules/human_appearance.dm b/code/modules/nano/modules/human_appearance.dm index 4868bfdc7c5..583b68b3dc6 100644 --- a/code/modules/nano/modules/human_appearance.dm +++ b/code/modules/nano/modules/human_appearance.dm @@ -6,6 +6,9 @@ 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 @@ -89,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 @@ -109,6 +147,14 @@ 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] @@ -125,8 +171,29 @@ data["facial_hair_styles"] = facial_hair_styles 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) @@ -147,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() @@ -160,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/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}} From b1001910b9b88723f839f13c4313021f0c2bc12d Mon Sep 17 00:00:00 2001 From: KasparoVy Date: Tue, 3 May 2016 19:59:31 -0400 Subject: [PATCH 08/37] Typo. --- code/modules/surgery/organs/organ_internal.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm index fd61410bdef..8c80b58519a 100644 --- a/code/modules/surgery/organs/organ_internal.dm +++ b/code/modules/surgery/organs/organ_internal.dm @@ -500,7 +500,7 @@ if(istype(owner, /mob/living/carbon/human)) var/mob/living/carbon/human/H = owner var/obj/item/organ/external/head/head_organ = H.get_organ("head") - if(!(head_organ.h_style == "Very Long Hair" || head_organ.h_style == "Mowhawk")) + if(!(head_organ.h_style == "Very Long Hair" || head_organ.h_style == "Mohawk")) if(prob(10)) head_organ.h_style = "Mohawk" else From a5b32d819d3c29a5bbeab1d193d744c9c971b50b Mon Sep 17 00:00:00 2001 From: KasparoVy Date: Wed, 4 May 2016 02:48:05 -0400 Subject: [PATCH 09/37] Fixes Bugs where Alopecia and Facial Hypertrichosis Wouldn't Update Sprite Correctly --- code/datums/diseases/advance/symptoms/beard.dm | 6 +++--- code/datums/diseases/advance/symptoms/shedding.dm | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/code/datums/diseases/advance/symptoms/beard.dm b/code/datums/diseases/advance/symptoms/beard.dm index b773d25cf9a..2ce411367f8 100644 --- a/code/datums/diseases/advance/symptoms/beard.dm +++ b/code/datums/diseases/advance/symptoms/beard.dm @@ -36,15 +36,15 @@ BONUS to_chat(H, "Your chin itches.") if(head_organ.f_style == "Shaved") head_organ.f_style = "Jensen Beard" - H.update_hair() + H.update_fhair() if(3, 4) to_chat(H, "You feel tough.") if(!(head_organ.f_style == "Dwarf Beard") && !(head_organ.f_style == "Very Long Beard") && !(head_organ.f_style == "Full Beard")) head_organ.f_style = "Full Beard" - H.update_hair() + H.update_fhair() else to_chat(H, "You feel manly!") if(!(head_organ.f_style == "Dwarf Beard") && !(head_organ.f_style == "Very Long Beard")) head_organ.f_style = pick("Dwarf Beard", "Very Long Beard") - H.update_hair() + H.update_fhair() return \ No newline at end of file diff --git a/code/datums/diseases/advance/symptoms/shedding.dm b/code/datums/diseases/advance/symptoms/shedding.dm index dd1fc5183a6..e79b87d1d4b 100644 --- a/code/datums/diseases/advance/symptoms/shedding.dm +++ b/code/datums/diseases/advance/symptoms/shedding.dm @@ -46,4 +46,5 @@ BONUS head_organ.f_style = "Shaved" head_organ.h_style = "Bald" H.update_hair() + H.update_fhair() return \ No newline at end of file From b8d85287a8a0b3d21a840f5b9a3520b7a9cf5936 Mon Sep 17 00:00:00 2001 From: monster860 Date: Fri, 6 May 2016 14:30:35 -0400 Subject: [PATCH 10/37] window rcd --- code/game/objects/items/weapons/RCD.dm | 78 +++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/code/game/objects/items/weapons/RCD.dm b/code/game/objects/items/weapons/RCD.dm index 7bd8f6e1207..d00e456d3e8 100644 --- a/code/game/objects/items/weapons/RCD.dm +++ b/code/game/objects/items/weapons/RCD.dm @@ -74,6 +74,12 @@ RCD src.spark_system.start() return if(3) + mode = 4 + to_chat(user, "Changed mode to 'Windows'") + if(prob(20)) + src.spark_system.start() + return + if(4) mode = 1 to_chat(user, "Changed mode to 'Floor & Walls'") if(prob(20)) @@ -88,7 +94,7 @@ RCD if(!proximity) return if(istype(A,/area/shuttle)||istype(A,/turf/space/transit)) return 0 - if(!(istype(A, /turf) || istype(A, /obj/machinery/door/airlock))) + if(!(istype(A, /turf) || istype(A, /obj/machinery/door/airlock) || istype(A, /obj/structure/grille) || istype(A, /obj/structure/window))) return 0 switch(mode) @@ -161,7 +167,77 @@ RCD qdel(A) return 1 return 0 + + if(istype(A, /obj/structure/window)) // You mean the grille of course, do you? + A = locate(/obj/structure/grille) in A.loc + + if(istype(A, /obj/structure/grille)) + if(!checkResource(2, user)) + return 0 + to_chat(user, "Deconstructing window...") + playsound(src.loc, 'sound/machines/click.ogg', 50, 1) + if(!do_after(user, 20, target = A)) + return 0 + if(locate(/obj/structure/window/full/shuttle) in A.contents) + return 0 // Let's not give shuttle-griefers an easy time. + if(!useResource(2, user)) + return 0 + activate() + var/turf/T1 = get_turf(A) + qdel(A) + A = null + for(var/obj/structure/window/W in T1.contents) + W.disassembled = 1 + W.density = 0 + qdel(W) + for(var/cdir in cardinal) + var/turf/T2 = get_step(T1, cdir) + if(locate(/obj/structure/window/full/shuttle) in T2.contents) + continue // Shuttle windows? Nah. We don't need extra windows there. + if(!(locate(/obj/structure/grille) in T2.contents)) + continue + for(var/obj/structure/window/W in T2.contents) + if(W.dir == turn(cdir, 180)) + W.disassembled = 1 + W.density = 0 + qdel(W) + var/obj/structure/window/reinforced/W = new(T2) + W.dir = turn(cdir, 180) + return 1 return 0 + if(4) + if(istype(A, /turf/simulated/floor)) + if(locate(/obj/structure/grille) in contents) + return 0 // We already have window + if(!checkResource(2, user)) + return 0 + to_chat(user, "Constructing window...") + playsound(src.loc, 'sound/machines/click.ogg', 50, 1) + if(!do_after(user, 20, target = A)) + return 0 + if(locate(/obj/structure/grille) in A.contents) + return 0 // We already have window + if(!useResource(2, user)) + return 0 + activate() + new /obj/structure/grille(A) + for(var/obj/structure/window/W in contents) + W.disassembled = 1 // Prevent that annoying glass breaking sound + W.density = 0 + qdel(W) + for(var/cdir in cardinal) + var/turf/T = get_step(A, cdir) + if(locate(/obj/structure/grille) in T.contents) + for(var/obj/structure/window/W in T.contents) + if(W.dir == turn(cdir, 180)) + W.disassembled = 1 + W.density = 0 + qdel(W) + else // Build a window! + var/obj/structure/window/reinforced/W = new(A) + W.dir = cdir + A:ChangeTurf(/turf/simulated/floor/plating) // Platings go under windows. + return 1 else to_chat(user, "ERROR: RCD in MODE: [mode] attempted use by [user]. Send this text #coderbus or an admin.") return 0 From a40460a365c442d36b70d0a4e59c085805ef44ad Mon Sep 17 00:00:00 2001 From: Fox-McCloud Date: Sat, 7 May 2016 22:28:57 -0400 Subject: [PATCH 11/37] TG Traitor Objectives Assignment --- code/controllers/configuration.dm | 4 + code/datums/mind.dm | 4 +- code/game/gamemodes/objective.dm | 314 ++++--------------------- code/game/gamemodes/traitor/traitor.dm | 159 ++++++------- config/example/game_options.txt | 4 + 5 files changed, 135 insertions(+), 350 deletions(-) diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 9cf42a511fd..f4e795f6c77 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -68,6 +68,8 @@ var/assistantlimit = 0 //enables assistant limiting var/assistantratio = 2 //how many assistants to security members + var/traitor_objectives_amount = 2 + var/max_maint_drones = 5 //This many drones can spawn, var/allow_drone_spawn = 1 //assuming the admin allow them to. var/drone_build_time = 1200 //A drone will become available every X ticks since last drone spawn. Default is 2 minutes. @@ -598,6 +600,8 @@ config.limbs_can_break = value if("shuttle_refuel_delay") config.shuttle_refuel_delay = text2num(value) + if("traitor_objectives_amount") + config.traitor_objectives_amount = text2num(value) if("reactionary_explosions") config.reactionary_explosions = 1 if("bombcap") diff --git a/code/datums/mind.dm b/code/datums/mind.dm index ea478d6b9e0..a3d9dbd8442 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -485,13 +485,13 @@ if(!def_value)//If it's a custom objective, it will be an empty string. def_value = "custom" - var/new_obj_type = input("Select objective type:", "Objective type", def_value) as null|anything in list("assassinate", "blood", "debrain", "protect", "prevent", "harm", "brig", "hijack", "escape", "survive", "steal", "download", "nuclear", "capture", "absorb", "destroy", "maroon", "identity theft", "custom") + var/new_obj_type = input("Select objective type:", "Objective type", def_value) as null|anything in list("assassinate", "blood", "debrain", "protect", "prevent", "brig", "hijack", "escape", "survive", "steal", "download", "nuclear", "capture", "absorb", "destroy", "maroon", "identity theft", "custom") if (!new_obj_type) return var/datum/objective/new_objective = null switch (new_obj_type) - if ("assassinate","protect","debrain", "harm", "brig", "maroon") + if ("assassinate","protect","debrain", "brig", "maroon") //To determine what to name the objective in explanation text. var/objective_type_capital = uppertext(copytext(new_obj_type, 1,2))//Capitalize first letter. var/objective_type_text = copytext(new_obj_type, 2)//Leave the rest of the text. diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 9544d54560c..330bbf9a742 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -8,12 +8,13 @@ var/list/potential_theft_objectives=subtypesof(/datum/theft_objective) \ - /datum/theft_objective/number/special \ - /datum/theft_objective/number/coins -datum/objective +/datum/objective var/datum/mind/owner = null //Who owns the objective. var/explanation_text = "Nothing" //What that person is supposed to do. var/datum/mind/target = null //If they are focused on a particular person. var/target_amount = 0 //If they are focused on a particular number. Steal objectives have their own counter. var/completed = 0 //currently only used for custom objectives. + var/martyr_compatible = 0 //If the objective is compatible with martyr objective, i.e. if you can still do it while dead. New(var/text) all_objectives |= src @@ -53,7 +54,9 @@ datum/objective target = pick(possible_targets) -datum/objective/assassinate +/datum/objective/assassinate + martyr_compatible = 1 + find_target() ..() if(target && target.current) @@ -81,7 +84,9 @@ datum/objective/assassinate -datum/objective/mutiny +/datum/objective/mutiny + martyr_compatible = 1 + find_target() ..() if(target && target.current) @@ -109,7 +114,7 @@ datum/objective/mutiny return 0 return 1 -datum/objective/mutiny/rp +/datum/objective/mutiny/rp find_target() ..() if(target && target.current) @@ -144,97 +149,9 @@ datum/objective/mutiny/rp return 0 return rval -datum/objective/anti_revolution/execute - find_target() - ..() - if(target && target.current) - explanation_text = "[target.current.real_name], the [target.assigned_role] has extracted confidential information above their clearance. Execute \him[target.current]." - else - explanation_text = "Free Objective" - return target +/datum/objective/maroon + martyr_compatible = 1 - - find_target_by_role(role, role_type=0) - ..(role, role_type) - if(target && target.current) - explanation_text = "[target.current.real_name], the [!role_type ? target.assigned_role : target.special_role] has extracted confidential information above their clearance. Execute \him[target.current]." - else - explanation_text = "Free Objective" - return target - - check_completion() - if(target && target.current) - if(target.current.stat == DEAD || !ishuman(target.current)) - return 1 - return 0 - return 1 - -datum/objective/anti_revolution/brig - var/already_completed = 0 - - find_target() - ..() - if(target && target.current) - explanation_text = "Brig [target.current.real_name], the [target.assigned_role] for 20 minutes to set an example." - else - explanation_text = "Free Objective" - return target - - - find_target_by_role(role, role_type=0) - ..(role, role_type) - if(target && target.current) - explanation_text = "Brig [target.current.real_name], the [!role_type ? target.assigned_role : target.special_role] for 20 minutes to set an example." - else - explanation_text = "Free Objective" - return target - - check_completion() - if(already_completed) - return 1 - - if(target && target.current) - if(target.current.stat == DEAD) - return 0 - if(target.is_brigged(10 * 60 * 10)) - already_completed = 1 - return 1 - return 0 - return 0 - -datum/objective/anti_revolution/demote - find_target() - ..() - if(target && target.current) - explanation_text = "[target.current.real_name], the [target.assigned_role] has been classified as harmful to Nanotrasen's goals. Demote \him[target.current] to assistant." - else - explanation_text = "Free Objective" - return target - - find_target_by_role(role, role_type=0) - ..(role, role_type) - if(target && target.current) - explanation_text = "[target.current.real_name], the [!role_type ? target.assigned_role : target.special_role] has been classified as harmful to Nanotrasen's goals. Demote \him[target.current] to assistant." - else - explanation_text = "Free Objective" - return target - - check_completion() - if(target && target.current && istype(target,/mob/living/carbon/human)) - var/obj/item/weapon/card/id/I = target.current:wear_id - if(istype(I, /obj/item/device/pda)) - var/obj/item/device/pda/P = I - I = P.id - - if(!istype(I)) return 1 - - if(I.assignment == "Civilian") - return 1 - else - return 0 - return 1 - -datum/objective/maroon find_target() ..() if(target && target.current) @@ -259,7 +176,7 @@ datum/objective/maroon return 0 return 1 -datum/objective/debrain//I want braaaainssss +/datum/objective/debrain //I want braaaainssss find_target() ..() if(target && target.current) @@ -292,7 +209,9 @@ datum/objective/debrain//I want braaaainssss return 0 -datum/objective/protect//The opposite of killing a dude. +/datum/objective/protect //The opposite of killing a dude. + martyr_compatible = 1 + find_target() ..() if(target && target.current) @@ -327,7 +246,8 @@ datum/objective/protect//The opposite of killing a dude. return 0 -datum/objective/hijack +/datum/objective/hijack + martyr_compatible = 0 //Technically you won't get both anyway. explanation_text = "Hijack the shuttle to ensure no loyalist Nanotrasen crew escape alive." check_completion() @@ -358,6 +278,7 @@ datum/objective/hijack /datum/objective/hijackclone explanation_text = "Hijack the emergency shuttle by ensuring only you (or your copies) escape." + martyr_compatible = 0 check_completion() if(!owner.current) @@ -386,8 +307,9 @@ datum/objective/hijack return 1 return 0 -datum/objective/block +/datum/objective/block explanation_text = "Do not allow any organic lifeforms to escape on the shuttle alive." + martyr_compatible = 1 check_completion() if(!istype(owner.current, /mob/living/silicon)) @@ -410,9 +332,7 @@ datum/objective/block return 1 - - -datum/objective/escape +/datum/objective/escape explanation_text = "Escape on the shuttle or an escape pod alive and free." var/escape_areas = list(/area/shuttle/escape, /area/shuttle/escape_pod1/centcom, @@ -447,7 +367,7 @@ datum/objective/escape return 0 -datum/objective/escape/escape_with_identity +/datum/objective/escape/escape_with_identity var/target_real_name // Has to be stored because the target's real_name can change over the course of the round find_target() @@ -477,7 +397,7 @@ datum/objective/escape/escape_with_identity return 1 return 0 -datum/objective/die +/datum/objective/die explanation_text = "Die a glorious death." check_completion() @@ -489,7 +409,7 @@ datum/objective/die -datum/objective/survive +/datum/objective/survive explanation_text = "Stay alive until the end." check_completion() @@ -499,98 +419,15 @@ datum/objective/survive return 0 return 1 -// Similar to the anti-rev objective, but for traitors -datum/objective/brig - var/already_completed = 0 - - find_target() - ..() - if(target && target.current) - explanation_text = "Have [target.current.real_name], the [target.assigned_role] brigged for 10 minutes." - else - explanation_text = "Free Objective" - return target - - - find_target_by_role(role, role_type=0) - ..(role, role_type) - if(target && target.current) - explanation_text = "Have [target.current.real_name], the [!role_type ? target.assigned_role : target.special_role] brigged for 10 minutes." - else - explanation_text = "Free Objective" - return target - - check_completion() - if(already_completed) - return 1 - - if(target && target.current) - if(target.current.stat == DEAD) - return 0 - // Make the actual required time a bit shorter than the official time - if(target.is_brigged(10 * 60 * 5)) - already_completed = 1 - return 1 - return 0 - return 0 - -// Harm a crew member, making an example of them -datum/objective/harm - var/already_completed = 0 - - find_target() - ..() - if(target && target.current) - explanation_text = "Make an example of [target.current.real_name], the [target.assigned_role]. Break one of their bones, detach one of their limbs or disfigure their face. Make sure they're alive when you do it." - else - explanation_text = "Free Objective" - return target - - - find_target_by_role(role, role_type=0) - ..(role, role_type) - if(target && target.current) - explanation_text = "Make an example of [target.current.real_name], the [!role_type ? target.assigned_role : target.special_role]. Break one of their bones, detach one of their limbs or disfigure their face. Make sure they're alive when you do it." - else - explanation_text = "Free Objective" - return target - - check_completion() - if(already_completed) - return 1 - - if(target && target.current && istype(target.current, /mob/living/carbon/human)) - if(target.current.stat == DEAD) - return 0 - - var/mob/living/carbon/human/H = target.current - for(var/obj/item/organ/external/E in H.organs) - if(E.status & ORGAN_BROKEN) - return 1 - for(var/limb_tag in H.species.has_limbs) //todo check prefs for robotic limbs and amputations. - var/list/organ_data = H.species.has_limbs[limb_tag] - var/limb_type = organ_data["path"] - var/found - for(var/obj/item/organ/external/E in H.organs) - if(limb_type == E.type) - found = 1 - break - if(!found) - return 1 - - var/obj/item/organ/external/head/head = H.get_organ("head") - if(head.disfigured) - return 1 - return 0 - - -datum/objective/nuclear +/datum/objective/nuclear explanation_text = "Destroy the station with a nuclear device." + martyr_compatible = 1 -datum/objective/steal +/datum/objective/steal var/datum/theft_objective/steal_target + martyr_compatible = 0 find_target(var/special_only=0) var/loop=50 @@ -638,7 +475,8 @@ datum/objective/steal if(!steal_target) return 1 // Free Objective return steal_target.check_completion(owner) -datum/objective/steal/exchange +/datum/objective/steal/exchange + martyr_compatible = 0 proc/set_faction(var/faction,var/otheragent) target = otheragent @@ -650,7 +488,7 @@ datum/objective/steal/exchange explanation_text = "Acquire [targetinfo.name] held by [target.current.real_name], the [target.assigned_role] and syndicate agent" steal_target = targetinfo -datum/objective/steal/exchange/backstab +/datum/objective/steal/exchange/backstab set_faction(var/faction) var/datum/theft_objective/unique/targetinfo @@ -661,7 +499,7 @@ datum/objective/steal/exchange/backstab explanation_text = "Do not give up or lose [targetinfo.name]." steal_target = targetinfo -datum/objective/download +/datum/objective/download proc/gen_amount_goal() target_amount = rand(10,20) explanation_text = "Download [target_amount] research levels." @@ -673,7 +511,7 @@ datum/objective/download -datum/objective/capture +/datum/objective/capture proc/gen_amount_goal() target_amount = rand(5,10) explanation_text = "Accumulate [target_amount] capture points." @@ -686,7 +524,7 @@ datum/objective/capture -datum/objective/absorb +/datum/objective/absorb proc/gen_amount_goal(var/lowbound = 4, var/highbound = 6) target_amount = rand (lowbound,highbound) if (ticker) @@ -714,8 +552,10 @@ datum/objective/absorb else return 0 -datum/objective/destroy +/datum/objective/destroy + martyr_compatible = 1 var/target_real_name + find_target() var/list/possible_targets = active_ais(1) var/mob/living/silicon/ai/target_ai = pick(possible_targets) @@ -734,71 +574,7 @@ datum/objective/destroy return 0 return 1 -/* Isn't suited for global objectives -/*---------CULTIST----------*/ - - eldergod - explanation_text = "Summon Nar-Sie via the use of an appropriate rune. It will only work if nine cultists stand on and around it." - - check_completion() - if(!eldergod) //global var, defined in rune4.dm - return 1 - return 0 - - survivecult - var/num_cult - var/cult_needed = 4 + round((num_players_started() / 10)) - - explanation_text = "Our knowledge must live on. Make sure at least [cult_needed] acolytes escape on the shuttle to spread their work on an another station." - - check_completion() - if(!emergency_shuttle.returned()) - return 0 - - var/cultists_escaped = 0 - - var/area/shuttle/escape/centcom/C = /area/shuttle/escape/centcom - for(var/turf/T in get_area_turfs(C.type)) - for(var/mob/living/carbon/H in T) - if(iscultist(H)) - cultists_escaped++ - - if(cultists_escaped >= cult_needed) - return 1 - - return 0 - - sacrifice //stolen from traitor target objective - - proc/find_target() //I don't know how to make it work with the rune otherwise, so I'll do it via a global var, sacrifice_target, defined in rune15.dm - var/datum/game_mode/cult/C = ticker.mode - var/list/possible_targets = C.get_unconvertables() - - if(!possible_targets.len) - for(var/mob/living/carbon/human/player in player_list) - if(player.mind && !(player.mind in cult)) - possible_targets += player.mind - - if(possible_targets.len > 0) - sacrifice_target = pick(possible_targets) - - if(sacrifice_target && sacrifice_target.current) - explanation_text = "Sacrifice [sacrifice_target.current.real_name], the [sacrifice_target.assigned_role]. You will need the sacrifice rune (hell join blood) and three acolytes to do so." - else - explanation_text = "Free Objective" - - return sacrifice_target - - check_completion() //again, calling on a global list defined in rune15.dm - if(sacrifice_target in sacrificed) - return 1 - else - return 0 - -/*-------ENDOF CULTIST------*/ -*/ - -datum/objective/blood +/datum/objective/blood proc/gen_amount_goal(low = 150, high = 400) target_amount = rand(low,high) target_amount = round(round(target_amount/5)*5) @@ -812,7 +588,7 @@ datum/objective/blood return 0 // /vg/; Vox Inviolate for humans :V -datum/objective/minimize_casualties +/datum/objective/minimize_casualties explanation_text = "Minimise casualties." check_completion() if(owner.kills.len>5) return 0 @@ -820,11 +596,11 @@ datum/objective/minimize_casualties //Vox heist objectives. -datum/objective/heist +/datum/objective/heist proc/choose_target() return -datum/objective/heist/kidnap +/datum/objective/heist/kidnap choose_target() var/list/roles = list("Chief Engineer","Research Director","Roboticist","Chemist","Station Engineer") var/list/possible_targets = list() @@ -866,7 +642,7 @@ datum/objective/heist/kidnap else return 0 -datum/objective/heist/loot +/datum/objective/heist/loot choose_target() var/loot = "an object" switch(rand(1,8)) @@ -937,7 +713,7 @@ datum/objective/heist/loot return 0 -datum/objective/heist/salvage +/datum/objective/heist/salvage choose_target() switch(rand(1,8)) if(1) @@ -1009,7 +785,7 @@ datum/objective/heist/salvage return 0 -datum/objective/heist/inviolate_crew +/datum/objective/heist/inviolate_crew explanation_text = "Do not leave any Vox behind, alive or dead." check_completion() @@ -1022,7 +798,7 @@ datum/objective/heist/inviolate_crew //Would be nice to use vox-specific kills but is currently not feasible. var/global/vox_kills = 0 //Used to check the Inviolate. -datum/objective/heist/inviolate_death +/datum/objective/heist/inviolate_death explanation_text = "Follow the Inviolate. Minimise death and loss of resources." check_completion() if(vox_kills > MAX_VOX_KILLS) return 0 diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm index c0d0edf89e3..8e06b46ac86 100644 --- a/code/game/gamemodes/traitor/traitor.dm +++ b/code/game/gamemodes/traitor/traitor.dm @@ -74,101 +74,102 @@ ..() -/datum/game_mode/proc/forge_traitor_objectives(var/datum/mind/traitor) +/datum/game_mode/proc/forge_traitor_objectives(datum/mind/traitor) if(istype(traitor.current, /mob/living/silicon)) - var/datum/objective/assassinate/kill_objective = new - kill_objective.owner = traitor - kill_objective.find_target() - traitor.objectives += kill_objective + var/objective_count = 0 + + if(prob(30)) + var/special_pick = rand(1,2) + switch(special_pick) + if(1) + var/datum/objective/block/block_objective = new + block_objective.owner = traitor + traitor.objectives += block_objective + objective_count++ + if(2) //Protect and strand a target + var/datum/objective/protect/yandere_one = new + yandere_one.owner = traitor + traitor.objectives += yandere_one + yandere_one.find_target() + objective_count++ + var/datum/objective/maroon/yandere_two = new + yandere_two.owner = traitor + yandere_two.target = yandere_one.target + traitor.objectives += yandere_two + objective_count++ + + for(var/i = objective_count, i < config.traitor_objectives_amount, i++) + var/datum/objective/assassinate/kill_objective = new + kill_objective.owner = traitor + kill_objective.find_target() + traitor.objectives += kill_objective var/datum/objective/survive/survive_objective = new survive_objective.owner = traitor traitor.objectives += survive_objective - if(prob(10)) - var/datum/objective/block/block_objective = new - block_objective.owner = traitor - traitor.objectives += block_objective - else - if(!exchange_blue && traitors.len >= 5 && name != "AutoTraitor") //Set up an exchange if there are enough traitors, turned off during autotraitor temporarily due to bugs. + var/is_hijacker = prob(10) + var/martyr_chance = prob(20) + var/objective_count = is_hijacker //Hijacking counts towards number of objectives + if(!exchange_blue && traitors.len >= 8) //Set up an exchange if there are enough traitors if(!exchange_red) exchange_red = traitor else exchange_blue = traitor assign_exchange_role(exchange_red) assign_exchange_role(exchange_blue) - else - var/list/active_ais = active_ais() - if(active_ais.len && prob(4)) // Leaving this at a flat chance for now, problems with the num_players() proc due to latejoin antags. - var/datum/objective/destroy/destroy_objective = new - destroy_objective.owner = traitor - destroy_objective.find_target() - traitor.objectives += destroy_objective - else - switch(rand(1,100)) - if(1 to 30) - var/datum/objective/assassinate/kill_objective = new - kill_objective.owner = traitor - kill_objective.find_target() - traitor.objectives += kill_objective - if(31 to 40) - var/datum/objective/debrain/debrain_objective = new - debrain_objective.owner = traitor - debrain_objective.find_target() - traitor.objectives += debrain_objective - if(41 to 50) - var/datum/objective/protect/protect_objective = new - protect_objective.owner = traitor - protect_objective.find_target_with_special_role(null,0) - if (!protect_objective.target) - protect_objective.find_target() //We could not find any traitors, protect somebody - traitor.objectives += protect_objective - if(51 to 61) - var/datum/objective/harm/harm_objective = new - harm_objective.owner = traitor - harm_objective.find_target() - traitor.objectives += harm_objective - else - var/datum/objective/steal/steal_objective = new - steal_objective.owner = traitor - steal_objective.find_target() - traitor.objectives += steal_objective - switch(rand(1,100)) - if(1 to 30) // Die glorious death - if (!(locate(/datum/objective/die) in traitor.objectives) && !(locate(/datum/objective/steal) in traitor.objectives) && !(locate(/datum/objective/steal/exchange) in traitor.objectives) && !(locate(/datum/objective/steal/exchange/backstab) in traitor.objectives)) - var/datum/objective/die/die_objective = new - die_objective.owner = traitor - traitor.objectives += die_objective + objective_count += 1 //Exchange counts towards number of objectives + var/list/active_ais = active_ais() + for(var/i = objective_count, i < config.traitor_objectives_amount, i++) + if(prob(50)) + if(active_ais.len && prob(100/player_list.len)) + var/datum/objective/destroy/destroy_objective = new + destroy_objective.owner = traitor + destroy_objective.find_target() + traitor.objectives += destroy_objective + else if(prob(30)) + var/datum/objective/maroon/maroon_objective = new + maroon_objective.owner = traitor + maroon_objective.find_target() + traitor.objectives += maroon_objective else - if(prob(85)) - if (!(locate(/datum/objective/escape) in traitor.objectives)) - var/datum/objective/escape/escape_objective = new - escape_objective.owner = traitor - traitor.objectives += escape_objective - else - if(prob(50)) - if (!(locate(/datum/objective/hijack) in traitor.objectives)) - var/datum/objective/hijack/hijack_objective = new - hijack_objective.owner = traitor - traitor.objectives += hijack_objective - else - if (!(locate(/datum/objective/minimize_casualties) in traitor.objectives)) - var/datum/objective/minimize_casualties/escape_objective = new - escape_objective.owner = traitor - traitor.objectives += escape_objective - if(31 to 85) - if (!(locate(/datum/objective/escape) in traitor.objectives)) - var/datum/objective/escape/escape_objective = new - escape_objective.owner = traitor - traitor.objectives += escape_objective + var/datum/objective/assassinate/kill_objective = new + kill_objective.owner = traitor + kill_objective.find_target() + traitor.objectives += kill_objective else - if (!(locate(/datum/objective/hijack) in traitor.objectives)) - var/datum/objective/hijack/hijack_objective = new - hijack_objective.owner = traitor - traitor.objectives += hijack_objective + var/datum/objective/steal/steal_objective = new + steal_objective.owner = traitor + steal_objective.find_target() + traitor.objectives += steal_objective - return + if(is_hijacker && objective_count <= config.traitor_objectives_amount) //Don't assign hijack if it would exceed the number of objectives set in config.traitor_objectives_amount + if (!(locate(/datum/objective/hijack) in traitor.objectives)) + var/datum/objective/hijack/hijack_objective = new + hijack_objective.owner = traitor + traitor.objectives += hijack_objective + return + + + var/martyr_compatibility = 1 //You can't succeed in stealing if you're dead. + for(var/datum/objective/O in traitor.objectives) + if(!O.martyr_compatible) + martyr_compatibility = 0 + break + + if(martyr_compatibility && martyr_chance) + var/datum/objective/die/martyr_objective = new + martyr_objective.owner = traitor + traitor.objectives += martyr_objective + return + + else + if(!(locate(/datum/objective/escape) in traitor.objectives)) + var/datum/objective/escape/escape_objective = new + escape_objective.owner = traitor + traitor.objectives += escape_objective + return /datum/game_mode/proc/greet_traitor(var/datum/mind/traitor) 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. From f73ec5a20e0d9a460f70ca4056d9daec1bb99b95 Mon Sep 17 00:00:00 2001 From: Fox-McCloud Date: Mon, 9 May 2016 02:11:53 -0400 Subject: [PATCH 12/37] Removes Players Ready From Lobby --- code/modules/mob/new_player/new_player.dm | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) 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 From c0460e4348ddce565a9ab71aa72f3c88235f5bdb Mon Sep 17 00:00:00 2001 From: Tastyfish Date: Mon, 9 May 2016 02:15:13 -0400 Subject: [PATCH 13/37] Makes borers not breathe so they can pipe --- code/game/gamemodes/miniantags/borer/borer.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/game/gamemodes/miniantags/borer/borer.dm b/code/game/gamemodes/miniantags/borer/borer.dm index 9e25a50a811..1a0d7770a1a 100644 --- a/code/game/gamemodes/miniantags/borer/borer.dm +++ b/code/game/gamemodes/miniantags/borer/borer.dm @@ -80,6 +80,7 @@ density = 0 pass_flags = PASSTABLE ventcrawler = 2 + 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) var/talk_inside_host = 0 // So that borers don't accidentally give themselves away on a botched message var/used_dominate From 4f8c42484e6cc90996410579a581a1b8df4b576e Mon Sep 17 00:00:00 2001 From: Fox-McCloud Date: Mon, 9 May 2016 16:31:51 -0400 Subject: [PATCH 14/37] Refactors Species Gun Handling --- code/__DEFINES/flags.dm | 10 +++++----- code/game/gamemodes/shadowling/shadowling.dm | 2 +- code/game/objects/items/devices/laserpointer.dm | 5 +++++ code/modules/mob/living/carbon/human/species/golem.dm | 2 +- code/modules/mob/living/carbon/human/species/monkey.dm | 2 -- code/modules/projectiles/gun.dm | 7 ++----- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index 04a20338c1f..4ce98b7f56a 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -43,11 +43,11 @@ #define HAS_LIPS 64 #define IS_PLANT 128 #define CAN_BE_FAT 256 -#define IS_RESTRICTED 512 -#define NO_INTORGANS 1024 -#define NO_POISON 2048 -#define RADIMMUNE 4096 -#define ALL_RPARTS 8192 +#define NO_INTORGANS 512 +#define NO_POISON 1024 +#define RADIMMUNE 2048 +#define ALL_RPARTS 4096 +#define NOGUNS 8192 //Species clothing flags #define HAS_UNDERWEAR 1 diff --git a/code/game/gamemodes/shadowling/shadowling.dm b/code/game/gamemodes/shadowling/shadowling.dm index 7c8100edbc5..24129a6d49f 100644 --- a/code/game/gamemodes/shadowling/shadowling.dm +++ b/code/game/gamemodes/shadowling/shadowling.dm @@ -301,7 +301,7 @@ Made by Xhuis blood_color = "#555555" flesh_color = "#222222" - flags = NO_BLOOD | NO_BREATHE | RADIMMUNE + flags = NO_BLOOD | NO_BREATHE | RADIMMUNE | NOGUNS //Can't use guns due to muzzle flash burn_mod = 1.5 //1.5x burn damage, 2x is excessive hot_env_multiplier = 1.5 diff --git a/code/game/objects/items/devices/laserpointer.dm b/code/game/objects/items/devices/laserpointer.dm index 48e477cc258..ba49f4a9e4c 100644 --- a/code/game/objects/items/devices/laserpointer.dm +++ b/code/game/objects/items/devices/laserpointer.dm @@ -77,6 +77,11 @@ if (!user.IsAdvancedToolUser()) to_chat(user, "You don't have the dexterity to do this!") return + if(ishuman(user)) + var/mob/living/carbon/human/H = user + if((HULK in H.mutations) || (H.species.flags & NOGUNS)) + user << "Your fingers can't press the button!" + return add_fingerprint(user) 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/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.") From 10780aa20086d3f866449145be0f026e2bd46eb8 Mon Sep 17 00:00:00 2001 From: Matt Date: Tue, 10 May 2016 00:02:55 +0200 Subject: [PATCH 15/37] Adds pAIzing --- code/modules/admin/admin.dm | 5 +++++ code/modules/admin/topic.dm | 22 ++++++++++++++++++++++ code/modules/mob/transform_procs.dm | 29 +++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 6e4f58c5ab2..d7e79934389 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -142,6 +142,11 @@ var/global/nologevent = 0 if(istype(M, /mob/dead/observer)) body += "
Re-incarnate | " + if(ispAI(M)) + body += "Is a pAI " + else + body += "Make pAI | " + // DNA2 - Admin Hax if(M.dna && iscarbon(M)) body += "

" diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 7fb6806b5c0..090955de57a 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1142,6 +1142,28 @@ message_admins("\blue [key_name_admin(usr)] attempting to corgize [key_name_admin(H)]", 1) H.corgize() + else if(href_list["makePAI"]) + if(!check_rights(R_SPAWN)) return + + var/mob/living/carbon/human/H = locate(href_list["makePAI"]) + if(!istype(H)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") + return + + var/painame = "Default" + var/name = "" + if(alert(usr, "Do you want to set their name or let them choose their own name?", "Name Choice", "Set Name", "Let them choose") == "Set Name") + name = sanitize(copytext(input(usr, "Enter a name for the new pAI. Default name is [painame].", "pAI Name", painame),1,MAX_NAME_LEN)) + else + name = sanitize(copytext(input(H, "An admin wants to make you into a pAI. Choose a name. Default is [painame].", "pAI Name", painame),1,MAX_NAME_LEN)) + + if(!name) + name = painame + + log_admin("[key_name(usr)] attempting to pAIze [key_name(H)]") + message_admins("\blue [key_name_admin(usr)] attempting to pAIze [key_name_admin(H)]", 1) + H.paize(name) + else if(href_list["forcespeech"]) if(!check_rights(R_SERVER|R_EVENT)) return 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 From 1d0965b1f935b18dd8887c4922b37acb2fff9ac1 Mon Sep 17 00:00:00 2001 From: KasparoVy Date: Tue, 10 May 2016 00:25:42 -0400 Subject: [PATCH 16/37] Back up to date. --- code/modules/reagents/newchem/drugs.dm | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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!") From e5fae9c078905186cc74eacf33e7420e9d5aac0a Mon Sep 17 00:00:00 2001 From: KasparoVy Date: Tue, 10 May 2016 02:23:41 -0400 Subject: [PATCH 17/37] Small Fix Fixes rare occasions where markings (IPC optics) and head accessories wouldn't reset if you switched species via C.M.A. --- .../mob/living/carbon/human/appearance.dm | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/code/modules/mob/living/carbon/human/appearance.dm b/code/modules/mob/living/carbon/human/appearance.dm index ce20923369d..52488051f50 100644 --- a/code/modules/mob/living/carbon/human/appearance.dm +++ b/code/modules/mob/living/carbon/human/appearance.dm @@ -124,6 +124,11 @@ /mob/living/carbon/human/proc/reset_hair() reset_head_hair() reset_facial_hair() + reset_head_accessory() + if(m_style && m_style != "None") //Resets the markings if they were head markings. + var/datum/sprite_accessory/marking_style = marking_styles_list[m_style] + if(marking_style && marking_style.marking_location == "head") + reset_markings() /mob/living/carbon/human/proc/reset_head_hair() var/obj/item/organ/external/head/H = get_organ("head") @@ -146,6 +151,25 @@ H.f_style = "Shaved" update_fhair() +/mob/living/carbon/human/proc/reset_markings() + var/list/valid_markings = generate_valid_markings() + if(valid_markings.len) + m_style = pick(valid_markings) + else + //this shouldn't happen + m_style = "None" + update_markings() + +/mob/living/carbon/human/proc/reset_head_accessory() + var/obj/item/organ/external/head/H = get_organ("head") + var/list/valid_head_accessories = generate_valid_head_accessories() + if(valid_head_accessories.len) + H.ha_style = pick(valid_head_accessories) + else + //this shouldn't happen + H.ha_style = "None" + update_head_accessory() + /mob/living/carbon/human/proc/change_eye_color(var/red, var/green, var/blue) if(red == r_eyes && green == g_eyes && blue == b_eyes) return From 22cb6d960ceadf5da194044d7a8fa7f17e2d7b33 Mon Sep 17 00:00:00 2001 From: Fox-McCloud Date: Tue, 10 May 2016 22:27:12 -0400 Subject: [PATCH 18/37] debrain --- code/game/gamemodes/objective.dm | 2 ++ code/game/gamemodes/traitor/traitor.dm | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 330bbf9a742..25b3727ec3a 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -177,6 +177,8 @@ var/list/potential_theft_objectives=subtypesof(/datum/theft_objective) \ return 1 /datum/objective/debrain //I want braaaainssss + martyr_compatible = 0 + find_target() ..() if(target && target.current) diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm index 8e06b46ac86..c7fcd59dfe4 100644 --- a/code/game/gamemodes/traitor/traitor.dm +++ b/code/game/gamemodes/traitor/traitor.dm @@ -128,6 +128,11 @@ destroy_objective.owner = traitor destroy_objective.find_target() traitor.objectives += destroy_objective + else if(prob(5)) + var/datum/objective/debrain/debrain_objective = new + debrain_objective.owner = traitor + debrain_objective.find_target() + traitor.objectives += debrain_objective else if(prob(30)) var/datum/objective/maroon/maroon_objective = new maroon_objective.owner = traitor From 6bd394b4b73251e204f0c8631d33a49bc6f8be82 Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Tue, 10 May 2016 22:41:51 -0400 Subject: [PATCH 19/37] Automatic changelog generation for PR #4391 --- html/changelogs/AutoChangeLog-pr-4391.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4391.yml 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" From 4150c48b80efe4f53b63c1fc907d5e0c4e40db90 Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Tue, 10 May 2016 22:46:55 -0400 Subject: [PATCH 20/37] Automatic changelog generation for PR #4407 --- html/changelogs/AutoChangeLog-pr-4407.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4407.yml 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" From b6edc4a0ac88d63cb9d6c537142359b4744df1bc Mon Sep 17 00:00:00 2001 From: Fox-McCloud Date: Tue, 10 May 2016 23:46:25 -0400 Subject: [PATCH 21/37] Can Flip Over Someone --- code/modules/mob/living/carbon/human/emote.dm | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index 1bb9ec062a9..eca554dcb0c 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -307,18 +307,28 @@ if (M == src) M = null - if (M) - if(src.lying || src.weakened) + if(M) + if(lying || weakened) message = "[src] flops and flails around on the floor." else message = "[src] flips in [M]'s general direction." - src.SpinAnimation(5,1) + SpinAnimation(5,1) else - if(src.lying || src.weakened) + if(lying || weakened) message = "[src] flops and flails around on the floor." else - message = "[src] does a flip!" - src.SpinAnimation(5,1) + var/obj/item/weapon/grab/G = get_active_hand() + if(G && G.affecting) + var/turf/oldloc = loc + var/turf/newloc = G.affecting.loc + if(isturf(oldloc) && isturf(newloc)) + SpinAnimation(5,1) + forceMove(newloc) + G.affecting.forceMove(oldloc) + message = "[src] flips over [G.affecting]!" + else + message = "[src] does a flip!" + SpinAnimation(5,1) if ("aflap", "aflaps") if (!src.restrained()) From 007c7ba8d3436ff7dce9a76bbf4057496f1d86fa Mon Sep 17 00:00:00 2001 From: Fox-McCloud Date: Wed, 11 May 2016 19:12:26 -0400 Subject: [PATCH 22/37] Dumber --- code/game/dna/genes/powers.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/game/dna/genes/powers.dm b/code/game/dna/genes/powers.dm index 2aca5878f83..eb33cef7ccf 100644 --- a/code/game/dna/genes/powers.dm +++ b/code/game/dna/genes/powers.dm @@ -144,8 +144,8 @@ /datum/dna/gene/basic/tk name="Telekenesis" - activation_messages=list("You feel smarter.") - deactivation_messages=("You feel dumber.") + activation_messages = list("You feel smarter.") + deactivation_messages = list("You feel dumber.") mutation=TK activation_prob=10 From a5da710c8b245344e82a47d63a366bed204fa4ed Mon Sep 17 00:00:00 2001 From: monster860 Date: Thu, 12 May 2016 18:20:49 -0400 Subject: [PATCH 23/37] Fixes camerachunk --- code/modules/mob/living/silicon/ai/freelook/chunk.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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) From 53e52f24d4ff54100d3ebf675c33817f54843feb Mon Sep 17 00:00:00 2001 From: monster860 Date: Thu, 12 May 2016 18:39:01 -0400 Subject: [PATCH 24/37] lein nutes --- code/game/objects/items/weapons/RCD.dm | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/code/game/objects/items/weapons/RCD.dm b/code/game/objects/items/weapons/RCD.dm index d00e456d3e8..5d85ea20e2b 100644 --- a/code/game/objects/items/weapons/RCD.dm +++ b/code/game/objects/items/weapons/RCD.dm @@ -103,7 +103,8 @@ RCD if(useResource(1, user)) to_chat(user, "Building Floor...") activate() - A:ChangeTurf(/turf/simulated/floor/plating) + var/turf/AT = A + AT.ChangeTurf(/turf/simulated/floor/plating) return 1 return 0 @@ -114,7 +115,8 @@ RCD if(do_after(user, 20, target = A)) if(!useResource(3, user)) return 0 activate() - A:ChangeTurf(/turf/simulated/wall) + var/turf/AT = A + AT.ChangeTurf(/turf/simulated/wall) return 1 return 0 @@ -142,7 +144,8 @@ RCD if(do_after(user, 40, target = A)) if(!useResource(5, user)) return 0 activate() - A:ChangeTurf(/turf/simulated/floor/plating) + var/turf/AT = A + AT.ChangeTurf(/turf/simulated/floor/plating) return 1 return 0 @@ -153,7 +156,8 @@ RCD if(do_after(user, 50, target = A)) if(!useResource(5, user)) return 0 activate() - A:ChangeTurf(/turf/space) + var/turf/AT = A + AT.ChangeTurf(/turf/space) return 1 return 0 @@ -236,7 +240,8 @@ RCD else // Build a window! var/obj/structure/window/reinforced/W = new(A) W.dir = cdir - A:ChangeTurf(/turf/simulated/floor/plating) // Platings go under windows. + var/turf/AT = A + AT.ChangeTurf(/turf/simulated/floor/plating) // Platings go under windows. return 1 else to_chat(user, "ERROR: RCD in MODE: [mode] attempted use by [user]. Send this text #coderbus or an admin.") From b77541bc9b9bfe11287deb63d3e943b9f6161ee3 Mon Sep 17 00:00:00 2001 From: Tastyfish Date: Thu, 12 May 2016 19:22:07 -0400 Subject: [PATCH 25/37] Fixes a couple runtimes and weird add_reagents/add_reagents_list that was silly --- code/_onclick/hud/action.dm | 3 ++- code/datums/diseases/advance/symptoms/sensory.dm | 2 +- code/game/objects/items/devices/radio/radio.dm | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/code/_onclick/hud/action.dm b/code/_onclick/hud/action.dm index 0a891be21f5..233add211f6 100644 --- a/code/_onclick/hud/action.dm +++ b/code/_onclick/hud/action.dm @@ -50,7 +50,8 @@ T.client.screen -= button qdel(button) button = null - T.actions.Remove(src) + if(T.actions) + T.actions.Remove(src) T.update_action_buttons() owner = null return diff --git a/code/datums/diseases/advance/symptoms/sensory.dm b/code/datums/diseases/advance/symptoms/sensory.dm index b25c4bacf47..99f670c258e 100644 --- a/code/datums/diseases/advance/symptoms/sensory.dm +++ b/code/datums/diseases/advance/symptoms/sensory.dm @@ -31,7 +31,7 @@ Bonus switch(A.stage) if(2) if(M.reagents.get_reagent_amount("oculine")<10) - M.reagents.add_reagent("oculine"=10) + M.reagents.add_reagent("oculine", 10) to_chat(M, "Your hearing feels clearer and crisp.") if(3) if(M.reagents.get_reagent_amount("antihol") < 10 && M.reagents.get_reagent_amount("oculine") < 10 ) diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 741ecfa7fa2..75b2a458d54 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -520,7 +520,7 @@ var/global/list/default_medbay_channels = list( // what the range is in which mobs will hear the radio // returns: -1 if can't receive, range otherwise - if (wires.IsIndexCut(WIRE_RECEIVE)) + if (!wires || wires.IsIndexCut(WIRE_RECEIVE)) return -1 if(!listening) return -1 From 2988b66c7b0329cec2a894857c9ac677b118a6ba Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Thu, 12 May 2016 19:35:53 -0400 Subject: [PATCH 26/37] Automatic changelog generation for PR #4375 --- html/changelogs/AutoChangeLog-pr-4375.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4375.yml 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." From e22bc8a42b07fbe61723d8d5add4037511de58ba Mon Sep 17 00:00:00 2001 From: Fox-McCloud Date: Thu, 12 May 2016 23:47:30 -0400 Subject: [PATCH 27/37] Foam Fixes+Changes --- code/game/objects/effects/effect_system.dm | 51 +++++++++++----- .../items/weapons/grenades/chem_grenade.dm | 6 +- .../mob/living/simple_animal/bot/medbot.dm | 2 +- code/modules/reagents/Chemistry-Holder.dm | 59 ++++++++++--------- code/modules/reagents/newchem/pyro.dm | 4 +- code/modules/surgery/organs/blood.dm | 4 +- 6 files changed, 76 insertions(+), 50 deletions(-) diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm index 744edcd7711..d73edde1525 100644 --- a/code/game/objects/effects/effect_system.dm +++ b/code/game/objects/effects/effect_system.dm @@ -916,6 +916,8 @@ steam.start() -- spawns the effect /obj/effect/effect/foam/New(loc, var/ismetal=0) ..(loc) icon_state = "[ismetal ? "m":""]foam" + if(!ismetal && reagents) + color = mix_color_from_reagents(reagents.reagent_list) metal = ismetal playsound(src, 'sound/effects/bubbles2.ogg', 80, 1, -3) spawn(3 + metal*3) @@ -944,10 +946,13 @@ steam.start() -- spawns the effect // on delete, transfer any reagents to the floor /obj/effect/effect/foam/Destroy() if(!metal && reagents) - for(var/atom/A in oview(0,src)) + reagents.handle_reactions() + for(var/atom/A in oview(1, src)) if(A == src) continue - reagents.reaction(A, 1, 1) + if(reagents.total_volume) + var/fraction = 5 / reagents.total_volume + reagents.reaction(A, TOUCH, fraction) return ..() /obj/effect/effect/foam/process() @@ -969,13 +974,14 @@ steam.start() -- spawns the effect if(F) continue - F = new(T, metal) + F = new /obj/effect/effect/foam(T, metal) F.amount = amount if(!metal) - F.create_reagents(10) - if (reagents) + F.create_reagents(15) + if(reagents) for(var/datum/reagent/R in reagents.reagent_list) - F.reagents.add_reagent(R.id,1) + F.reagents.add_reagent(R.id, min(R.volume, 3), R.data, reagents.chem_temp) + F.color = mix_color_from_reagents(reagents.reagent_list) // foam disolves when heated // except metal foams @@ -993,16 +999,26 @@ steam.start() -- spawns the effect if (istype(AM, /mob/living/carbon)) var/mob/living/carbon/M = AM - M.slip("foam", 5, 2) + if(M.slip("foam", 5, 2)) + if(reagents) + for(var/reagent_id in reagents.reagent_list) + var/amount = M.reagents.get_reagent_amount(reagent_id) + if(amount < 25) + M.reagents.add_reagent(reagent_id, min(round(amount / 2), 15)) + if(reagents.total_volume) + var/fraction = 5 / reagents.total_volume + reagents.reaction(M, TOUCH, fraction) /datum/effect/system/foam_spread var/amount = 5 // the size of the foam spread. var/list/carried_reagents // the IDs of reagents present when the foam was mixed var/metal = 0 // 0=foam, 1=metalfoam, 2=ironfoam + var/temperature = T0C + var/list/banned_reagents = list("smoke_powder", "fluorosurfactant", "stimulants") /datum/effect/system/foam_spread/set_up(amt=5, loca, var/datum/reagents/carry = null, var/metalfoam = 0) - amount = round(sqrt(amt / 3), 1) + amount = min(round(amt/5, 1), 7) if(istype(loca, /turf/)) location = loca else @@ -1010,35 +1026,40 @@ steam.start() -- spawns the effect carried_reagents = list() metal = metalfoam - + temperature = carry.chem_temp // bit of a hack here. Foam carries along any reagent also present in the glass it is mixed // with (defaults to water if none is present). Rather than actually transfer the reagents, // this makes a list of the reagent ids and spawns 1 unit of that reagent when the foam disolves. - if(carry && !metal) for(var/datum/reagent/R in carry.reagent_list) - carried_reagents += R.id + carried_reagents[R.id] = R.volume /datum/effect/system/foam_spread/start() spawn(0) var/obj/effect/effect/foam/F = locate() in location if(F) F.amount += amount + F.amount = min(F.amount, 27) return - F = new(src.location, metal) + F = new /obj/effect/effect/foam(location, metal) F.amount = amount if(!metal) // don't carry other chemicals if a metal foam - F.create_reagents(10) + F.create_reagents(15) if(carried_reagents) for(var/id in carried_reagents) - F.reagents.add_reagent(id,1) + if(banned_reagents.Find("[id]")) + continue + var/datum/reagent/reagent_volume = carried_reagents[id] + F.reagents.add_reagent(id, min(reagent_volume, 3), null, temperature) + F.color = mix_color_from_reagents(F.reagents.reagent_list) else - F.reagents.add_reagent("water", 1) + F.reagents.add_reagent("cleaner", 1) + F.color = mix_color_from_reagents(F.reagents.reagent_list) // wall formed by metal foams // dense and opaque, but easy to break diff --git a/code/game/objects/items/weapons/grenades/chem_grenade.dm b/code/game/objects/items/weapons/grenades/chem_grenade.dm index 149cc03a866..a951f1ade8f 100644 --- a/code/game/objects/items/weapons/grenades/chem_grenade.dm +++ b/code/game/objects/items/weapons/grenades/chem_grenade.dm @@ -458,11 +458,11 @@ New() ..() var/obj/item/weapon/reagent_containers/glass/beaker/B1 = new(src) - var/obj/item/weapon/reagent_containers/glass/beaker/large/B2 = new(src) + var/obj/item/weapon/reagent_containers/glass/beaker/B2 = new(src) B1.reagents.add_reagent("fluorosurfactant", 40) - B2.reagents.add_reagent("water", 40) - B2.reagents.add_reagent("cleaner", 60) + B2.reagents.add_reagent("cleaner", 10) + B2.reagents.add_reagent("water", 40) //when you make pre-designed foam reactions that carry the reagents, always add water last beakers += B1 beakers += B2 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/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/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/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 From a4adb28b3e07018783bfac43c0e9e5719f407556 Mon Sep 17 00:00:00 2001 From: Isaac Erwin Date: Fri, 13 May 2016 14:31:59 -0400 Subject: [PATCH 28/37] Removes a random pipe and cable from engineering There's a disposal pipe and cable in engineering under and next to the door to the hardsuit storage. Neither connect to anything or seem to serve any purpose. --- _maps/map_files/cyberiad/cyberiad.dmm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/_maps/map_files/cyberiad/cyberiad.dmm b/_maps/map_files/cyberiad/cyberiad.dmm index 47df198e5b8..3ee7365eaf2 100644 --- a/_maps/map_files/cyberiad/cyberiad.dmm +++ b/_maps/map_files/cyberiad/cyberiad.dmm @@ -7232,7 +7232,7 @@ "cJd" = (/obj/machinery/computer/station_alert,/turf/simulated/floor/plasteel,/area/engine/engineering) "cJe" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/plasteel,/area/engine/engineering) "cJf" = (/obj/effect/spawner/window/reinforced,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/engine/hardsuitstorage) -"cJg" = (/obj/effect/spawner/window/reinforced,/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plating,/area/engine/hardsuitstorage) +"cJg" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock/glass_engineering{name = "Storage"; req_access_txt = "11"; req_one_access_txt = null},/turf/simulated/floor/plasteel,/area/engine/hardsuitstorage) "cJh" = (/obj/structure/sink{icon_state = "sink"; dir = 8; pixel_x = -12; pixel_y = 2},/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -22; pixel_y = 0},/turf/simulated/floor/plasteel{tag = "icon-whitegreen (WEST)"; icon_state = "whitegreen"; dir = 8},/area/medical/virology) "cJi" = (/obj/machinery/camera{c_tag = "Engineering Chief Engineer's Office"; dir = 4; network = list("SS13")},/obj/item/device/radio/intercom{name = "station intercom (General)"; pixel_x = -28; pixel_y = 0},/obj/machinery/disposal,/obj/structure/disposalpipe/trunk,/obj/machinery/firealarm{dir = 1; pixel_y = -24},/turf/simulated/floor/plasteel{dir = 8; icon_state = "neutralfull"},/area/engine/chiefs_office) "cJj" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plasteel{dir = 8; icon_state = "neutralfull"},/area/engine/chiefs_office) @@ -7337,7 +7337,6 @@ "cLe" = (/obj/machinery/door/airlock/maintenance{req_access_txt = "12"},/turf/simulated/floor/plating,/area/maintenance/asmaint2) "cLf" = (/obj/structure/closet/crate,/obj/item/clothing/under/color/lightpurple,/obj/item/weapon/spacecash/c200,/turf/simulated/floor/plating,/area/maintenance/asmaint2) "cLg" = (/obj/effect/spawner/window,/turf/simulated/floor/plating,/area/maintenance/asmaint) -"cLh" = (/obj/machinery/door/firedoor,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/machinery/door/airlock/glass_engineering{name = "Storage"; req_access_txt = "11"; req_one_access_txt = null},/turf/simulated/floor/plasteel,/area/engine/hardsuitstorage) "cLi" = (/obj/effect/spawner/window/reinforced,/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/disposalpipe/segment,/obj/structure/cable,/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "xenobio4"; name = "Containment Blast Doors"; opacity = 0},/turf/simulated/floor/plating,/area/toxins/xenobiology) "cLj" = (/obj/machinery/door/window/southright{name = "Containment Pen"; req_access_txt = "55"},/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "xenobio4"; name = "Containment Blast Doors"; opacity = 0},/turf/simulated/floor/engine,/area/toxins/xenobiology) "cLk" = (/obj/effect/spawner/window/reinforced,/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "xenobio4"; name = "Containment Blast Doors"; opacity = 0},/obj/structure/cable,/turf/simulated/floor/plating,/area/toxins/xenobiology) @@ -8921,7 +8920,7 @@ bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbi bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikafxaabcFscFtcFtcFucFvcFwcFwcFwcFvcFwcFwcFwcFvcFwcFwcFxcFtcFtcFtcFtcFtcFycFzcFAcFBcFCcFDcFEcFFcFGcfRcwWcFHcDfcvKcvKcvKcFIcEBcECcFJcFKcFLcyrcFNcDucFPcFOcFQcFScFTcSpcFVcFWcFXcFScFYcFZcDwcGacDzcDzcDzcGbcBCcGccGccDFcGdcGecGfcGgcGhcGicGjcGkcGlcGmcGncDOcGocDQcGpcDTcDTcCKcHBcoDcEhclUcyMcyLcyNcFfclUcnkclTcFfclUcyQcyScyRcyTcyTclUcusbGycJOcoAbikckPcxOcxPcxOcGAcxRcqUcGBcJPcJJcqUdlWcGDcwAcwAcwAckPbikbikaabaabbikbikbikbikbikbwocyKcvzbwobikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikacGbikaabbikaabaabcGFaabbikaabcGFaabbikaabcGFaabbikbikbikbikbikbikbikbikcDccDccDccGGcGHcFMcDdcGJcfRcGKcExcExcExcExcGLcExcFGcECcGMcGNcGOcGPcGQcGRcGScGTcGUcGVcGWcGXcGYcGZcHacHbcFYcELcDwcHccHdcDzcDzcHecBCcHfcHgcDFcHhcCAcHicHjcHkcHlcHmcHncHocHpcHocHqaabcCKcCKcCKcCKcCKcHBcoAcEhclUcIJcyVcyYcyXcEecEccEgcEfcHwcGucHZczVcIRcIQclUcusbGycJRcoAbikckPcxOcxOcxOcFjcHEcHFcHGcJScHIcCZcCZcCZcHJcHKcHLcHMbikbikbikaabaabbikbikbikbikbwobwocvzbwobikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikacGacGafxaabaabczocHOczqbikczocHOczqbikczocHOczqaabbikbikbikbikbikbikbikaabaabcDccDdcDdcDdcDdcHPcHQcHRcfRcHScfRcfRcEBcHTcfRcECcHUcHVcGOcHWcFNcHXcHYcIacIacIbcIccIdcIedmabRFcIbcIhcIicIjcIkcIlcImcIncIocIpcIqcGfcIrcIscItcIucIvcIwcIxcIycIzcIAcIBcICcIDcDPcDQcIEcIFcIFcCKcHBcoAcEhclUclUclUclUclUcJhcANcBRcJQcMccBScMecMdcMCcBVclUcuscGqcGrcGrcGrcJTcJTcJTcJTcJTcJUcKTcKbcKUcIUczbcIVczbcIWczbcIXcHMbikbikbikbikaabaabbikbikbikbikbwocvzbwoaabaabaabaabaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikczocHOczqaabczocHOczqbikczocHOczqbikbikbikaabbikbikbikbikaabaabaabbikbikaabaabcJbcJbcJbcJbcJbcJbcJbcJccJbcJbcECcJdcJecGOcHWcFNcJfcFNcJgcLhcDtcJicJjcFWcJkcFRcDtcJmcDzcDwcJncJocJpcIncJqcJrcJscJtcJucJvcJwcJtcJxcJycJzcJAcDFcJBcJCcJDcJEaabcEVcJFcJGcJHcCKcHBcoDcKWcKVcKVcKVcKXclUcFacyLcCLcFecyScCMcyTcyTcyScCNclUcuscGvbVibGycKYcKZcoAbikbikckPcJVcJWcJXcJYcJVcJWcJZcKacJVcJWcLackPaabaabaabaabaabaabaabaabaabaabbwocvzbwobwobwobikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjcbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikczocHOczqaabczocHOczqbikczocHOczqbikbikbikaabbikbikbikbikaabaabaabbikbikaabaabcJbcJbcJbcJbcJbcJbcJbcJccJbcJbcECcJdcJecGOcHWcFNcJfcFNcFNcJgcDtcJicJjcFWcJkcFRcDtcJmcDzcDwcJncJocJpcIncJqcJrcJscJtcJucJvcJwcJtcJxcJycJzcJAcDFcJBcJCcJDcJEaabcEVcJFcJGcJHcCKcHBcoDcKWcKVcKVcKVcKXclUcFacyLcCLcFecyScCMcyTcyTcyScCNclUcuscGvbVibGycKYcKZcoAbikbikckPcJVcJWcJXcJYcJVcJWcJZcKacJVcJWcLackPaabaabaabaabaabaabaabaabaabaabbwocvzbwobwobwobikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjcbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikafxaabczocHOczqbikczocHOczqbikczocHOczqaabbikbikbikbikbikbikbikaabaabbikbikaabaabaabcJbcKjcKjcKkcGIcKmcKmcKncKocKocKpcKqcKrcGOcHWcGOcKscGOcGOcGOcDtcKtcKucKvcKwcKxcKycKzcKAcKBcKCcKCcKCcKDcKEcKFcKGcKHcKIcHhcCAcKJcKKcKLcKMcKNcDFcJBcKOcKPcKQcKRcDQcKScIFcIFcCKcHBcoDcEhbVibVibVibYDclUcFgcCOcDXcNDcyScPocPMcyTcPVcPQclUcuscGvbVibGycyHbGycoAbikbikckPcLicLjcLkcwAcLlcLmcLncwAcLocLpcLqckPaabaabbikbikbikbikbikbikbikbikbwocvzbxXbxXbwoaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikafxaabczocHOczqbikczocHOczqaabczocHOczqaabaabaabbikaabbikbikaabaabbikbikbikaabbikbikcJbcKjcKjcKkcLscLscLscLtcLucLvcECcLwcLxcLycLzcLAcLBcLCcLDcLDcLEcLFcLGcGOcGOcGOcLHcLIcLJcLKcLLcLMcLNcLOcLPcECcLQcLQcLRcHhcCAcLScLTcLUcLVcLWcDFcLXcLYcLZcMacMbcCKcCKcCKcCKcCKcHBcoDcEhcLbbGybGybYDclUcNEczVczVcOtcDZcQMcRwcyTdbkcYuclUcuscGvczhbGychCcITcoAbikbikckPcMpcxOcxOcwAcMpcxOcxOcwAcMpcxOcxOckPbikaabaabbikbikbikbikbikbikbikbwocLccyJbxXbwobwobwocJNcJNaabaabaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikagiaabczocMqczqbikczocMqczqbikczocMqczqaabafxaabaabaabaabaabaabbikbikbikbikbikbikaabcJbcMrcMscLscLscLscMtcMucMucMucMucMucMucMucMvcMwcMxcMycMzcMzcMzcMAcMBdcpdcodcvcMzcMBcMDcMEcMFcLMcMGcLOcLPcMHcMIcMJcMKcMLcMMcMNcMOcKNcMPcMQcMRcMScMTcMUcIDcMVcDQcMWcMXcMXcCKcHBcoAcEhbVicozcLdbYDclUcOBczVcQgcPYcySdcydczcyTdcBdcAclUcuscGvbVibGybVibVicoAaabaabckPcNncBZcxOcwAcNncBZcxOcwAcNncBZcxOckPbikbikaabaabbikbikbikbikbikbikbwocvzcyJcLecyJcLfbwoaabaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik From d555e9d6a34003f272c73fe9d48393e00ebdc931 Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Fri, 13 May 2016 15:10:05 -0400 Subject: [PATCH 29/37] Automatic changelog generation for PR #4415 --- html/changelogs/AutoChangeLog-pr-4415.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4415.yml 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" From e8e531eb3a49a66e52e6b5e562e9ee9a7602f02c Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Fri, 13 May 2016 15:29:00 -0400 Subject: [PATCH 30/37] Automatic changelog generation for PR #4401 --- html/changelogs/AutoChangeLog-pr-4401.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4401.yml 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" From 47e00dee34a2ee2563c4e83a84f0b9a05ee8f2fa Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Fri, 13 May 2016 15:34:17 -0400 Subject: [PATCH 31/37] Automatic changelog generation for PR #4231 --- html/changelogs/AutoChangeLog-pr-4231.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4231.yml 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" From d445506b1d5b104064774d63465929c7ae57cbb0 Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Fri, 13 May 2016 15:36:36 -0400 Subject: [PATCH 32/37] Automatic changelog generation for PR #4331 --- html/changelogs/AutoChangeLog-pr-4331.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4331.yml 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)." From 69c51878a58ef00f2285705fcfe47907517cee27 Mon Sep 17 00:00:00 2001 From: AugRob Date: Fri, 13 May 2016 17:11:17 -0500 Subject: [PATCH 33/37] Add screwdriver sound when opening airlock panels --- code/game/machinery/doors/airlock.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 26d159e959a..c131c55ee49 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -799,6 +799,7 @@ About the new airlock wires panel: else return else if(istype(C, /obj/item/weapon/screwdriver)) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 25, 1) src.p_open = !( src.p_open ) src.update_icon() else if(istype(C, /obj/item/weapon/wirecutters)) @@ -1066,4 +1067,4 @@ About the new airlock wires panel: src.unlock() src.open() src.lock() - return \ No newline at end of file + return From b1bef10909f598779cd61e1de299149cd99201d6 Mon Sep 17 00:00:00 2001 From: monster860 Date: Sun, 15 May 2016 10:17:26 -0400 Subject: [PATCH 34/37] Fix shuttle HREF exploit --- code/modules/shuttle/shuttle.dm | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index 2a794de2ff8..bf07626ffc2 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -683,7 +683,13 @@ 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)") + to_chat(usr, "Expect a ban. Soon.") + return switch(shuttle_master.moveShuttle(shuttleId, href_list["move"], 1)) if(0) to_chat(usr, "Shuttle received message and will be sent shortly.") From f58887fa1f61ce818270b377efa583002005db3c Mon Sep 17 00:00:00 2001 From: monster860 Date: Sun, 15 May 2016 10:30:19 -0400 Subject: [PATCH 35/37] removes the fun part --- code/modules/shuttle/shuttle.dm | 1 - 1 file changed, 1 deletion(-) diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index bf07626ffc2..119378d53f4 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -688,7 +688,6 @@ 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)") - to_chat(usr, "Expect a ban. Soon.") return switch(shuttle_master.moveShuttle(shuttleId, href_list["move"], 1)) if(0) From de63af38de4c6e5891cf116de0eb3e3a24624903 Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Sun, 15 May 2016 18:30:58 -0400 Subject: [PATCH 36/37] Automatic changelog generation for PR #4427 --- html/changelogs/AutoChangeLog-pr-4427.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4427.yml 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" From 683fca467b5337621dbfba4a46865e18c6f1689c Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Mon, 16 May 2016 20:15:41 -0400 Subject: [PATCH 37/37] Automatic changelog generation for PR #4423 --- html/changelogs/AutoChangeLog-pr-4423.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4423.yml 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"