From 9c5acba4e83e52e80cb8b4b8d76c31901a629399 Mon Sep 17 00:00:00 2001 From: Evankhell561 <49106866+Evankhell561@users.noreply.github.com> Date: Sat, 21 Sep 2019 12:42:19 -0400 Subject: [PATCH 01/24] Mech id upload buttons (#12364) --- code/game/mecha/mecha_topic.dm | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/code/game/mecha/mecha_topic.dm b/code/game/mecha/mecha_topic.dm index 36269a11303..c4367056e03 100644 --- a/code/game/mecha/mecha_topic.dm +++ b/code/game/mecha/mecha_topic.dm @@ -172,12 +172,17 @@

Following keycodes are present in this system:

"} for(var/a in operation_req_access) output += "[get_access_desc(a)] - Delete
" + + output += "
Delete All

" + output += "

Following keycodes were detected on portable device:

" for(var/a in id_card.access) if(a in operation_req_access) continue - var/a_name = get_access_desc(a) - if(!a_name) continue //there's some strange access without a name - output += "[a_name] - Add
" + if(!get_access_desc(a)) + continue //there's some strange access without a name + output += "[get_access_desc(a)] - Add
" + + output += "
Add All

" output += "
Finish (Warning! The ID upload panel will be locked. It can be unlocked only through Exosuit Interface.)" output += "" user << browse(output, "window=exosuit_add_access") @@ -339,11 +344,27 @@ operation_req_access += afilter.getNum("add_req_access") output_access_dialog(afilter.getObj("id_card"),afilter.getMob("user")) return + if(href_list["add_all_req_access"] && add_req_access && afilter.getObj("id_card")) + if(!in_range(src, usr)) + return + var/obj/item/card/id/mycard = afilter.getObj("id_card") + var/list/myaccess = mycard.access + for(var/a in myaccess) + if(get_access_desc(a)) + operation_req_access += a + output_access_dialog(afilter.getObj("id_card"),afilter.getMob("user")) + return if(href_list["del_req_access"] && add_req_access && afilter.getObj("id_card")) if(!in_range(src, usr)) return operation_req_access -= afilter.getNum("del_req_access") output_access_dialog(afilter.getObj("id_card"),afilter.getMob("user")) return + if(href_list["del_all_req_access"] && add_req_access && afilter.getObj("id_card")) + if(!in_range(src, usr)) + return + operation_req_access = list() + output_access_dialog(afilter.getObj("id_card"),afilter.getMob("user")) + return if(href_list["finish_req_access"]) if(!in_range(src, usr)) return add_req_access = 0 From fa58a16ce0e3d1bced7f1d23268c01a528e1a49b Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Sat, 21 Sep 2019 12:42:21 -0400 Subject: [PATCH 02/24] Automatic changelog generation for PR #12364 [ci skip] --- html/changelogs/AutoChangeLog-pr-12364.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-12364.yml diff --git a/html/changelogs/AutoChangeLog-pr-12364.yml b/html/changelogs/AutoChangeLog-pr-12364.yml new file mode 100644 index 00000000000..2c6b8c6d6db --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-12364.yml @@ -0,0 +1,4 @@ +author: "Evankhell561" +delete-after: True +changes: + - rscadd: "Mech ID upload panels now come with [add all] and [delete all] options" From 7c2abe9cdf0e0190667ec0149371106507722cbe Mon Sep 17 00:00:00 2001 From: MarsM0nd Date: Sat, 21 Sep 2019 21:18:36 +0200 Subject: [PATCH 03/24] Fixes nettle pickup (#12371) --- code/modules/hydroponics/grown/nettle.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/modules/hydroponics/grown/nettle.dm b/code/modules/hydroponics/grown/nettle.dm index cfb02987201..8dcada2f7e8 100644 --- a/code/modules/hydroponics/grown/nettle.dm +++ b/code/modules/hydroponics/grown/nettle.dm @@ -50,12 +50,12 @@ /obj/item/grown/nettle/pickup(mob/living/user) ..() if(!ishuman(user)) - return FALSE + return TRUE var/mob/living/carbon/human/H = user if(H.gloves) - return FALSE + return TRUE if(PIERCEIMMUNE in H.dna.species.species_traits) - return FALSE + return TRUE var/organ = ((H.hand ? "l_":"r_") + "arm") var/obj/item/organ/external/affecting = H.get_organ(organ) if(affecting) From eac649d5deb1d127ca19b94574ade2be016fd810 Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Sat, 21 Sep 2019 15:18:38 -0400 Subject: [PATCH 04/24] Automatic changelog generation for PR #12371 [ci skip] --- html/changelogs/AutoChangeLog-pr-12371.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-12371.yml diff --git a/html/changelogs/AutoChangeLog-pr-12371.yml b/html/changelogs/AutoChangeLog-pr-12371.yml new file mode 100644 index 00000000000..2d2f97038f6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-12371.yml @@ -0,0 +1,4 @@ +author: "MarsM0nd" +delete-after: True +changes: + - bugfix: "can safely pick up nettles again" From 41b638bd334a777709f1f7f218816e2c8e44c625 Mon Sep 17 00:00:00 2001 From: TDSSS <32099540+TDSSS@users.noreply.github.com> Date: Sat, 21 Sep 2019 21:34:08 +0200 Subject: [PATCH 05/24] Gloves stuff --- code/modules/clothing/gloves/color.dm | 21 +++++++++++---------- code/modules/hydroponics/grown/nettle.dm | 2 +- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/code/modules/clothing/gloves/color.dm b/code/modules/clothing/gloves/color.dm index 7a65d579b8e..72a94d3086c 100644 --- a/code/modules/clothing/gloves/color.dm +++ b/code/modules/clothing/gloves/color.dm @@ -139,8 +139,9 @@ icon_state = "rainbow" item_state = "rainbowgloves" item_color = "rainbow" - clown - item_color = "clown" + +/obj/item/clothing/gloves/color/rainbow/clown + item_color = "clown" /obj/item/clothing/gloves/color/blue name = "blue gloves" @@ -170,11 +171,11 @@ item_state = "graygloves" item_color="grey" - rd - item_color = "director" //Exists for washing machines. Is not different from gray gloves in any way. +/obj/item/clothing/gloves/color/grey/rd + item_color = "director" //Exists for washing machines. Is not different from gray gloves in any way. - hop - item_color = "hop" //Exists for washing machines. Is not different from gray gloves in any way. +/obj/item/clothing/gloves/color/grey/hop + item_color = "hop" //Exists for washing machines. Is not different from gray gloves in any way. /obj/item/clothing/gloves/color/light_brown name = "light brown gloves" @@ -190,8 +191,8 @@ item_state = "browngloves" item_color="brown" - cargo - item_color = "cargo" //Exists for washing machines. Is not different from brown gloves in any way. +/obj/item/clothing/gloves/color/brown/cargo + item_color = "cargo" //Exists for washing machines. Is not different from brown gloves in any way. /obj/item/clothing/gloves/color/latex name = "latex gloves" @@ -219,8 +220,8 @@ item_state = "wgloves" item_color="mime" - redcoat - item_color = "redcoat" //Exists for washing machines. Is not different from white gloves in any way. +/obj/item/clothing/gloves/color/white/redcoat + item_color = "redcoat" //Exists for washing machines. Is not different from white gloves in any way. /obj/item/clothing/gloves/color/captain diff --git a/code/modules/hydroponics/grown/nettle.dm b/code/modules/hydroponics/grown/nettle.dm index 8dcada2f7e8..2da4ef66ac8 100644 --- a/code/modules/hydroponics/grown/nettle.dm +++ b/code/modules/hydroponics/grown/nettle.dm @@ -52,7 +52,7 @@ if(!ishuman(user)) return TRUE var/mob/living/carbon/human/H = user - if(H.gloves) + if(H.gloves && !H.gloves.transfer_prints) //exclude fingerless gloves, rings, bracers, etc. return TRUE if(PIERCEIMMUNE in H.dna.species.species_traits) return TRUE From 8bd7ad4adb33933f72bf251d766a7ca8a6fcc462 Mon Sep 17 00:00:00 2001 From: TDSSS <32099540+TDSSS@users.noreply.github.com> Date: Sat, 21 Sep 2019 22:32:49 +0200 Subject: [PATCH 06/24] derp, remember to test your code, kids --- code/modules/hydroponics/grown/nettle.dm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/code/modules/hydroponics/grown/nettle.dm b/code/modules/hydroponics/grown/nettle.dm index 2da4ef66ac8..3f4b56a6f25 100644 --- a/code/modules/hydroponics/grown/nettle.dm +++ b/code/modules/hydroponics/grown/nettle.dm @@ -52,8 +52,10 @@ if(!ishuman(user)) return TRUE var/mob/living/carbon/human/H = user - if(H.gloves && !H.gloves.transfer_prints) //exclude fingerless gloves, rings, bracers, etc. - return TRUE + if(H.gloves && istype(H.gloves, /obj/item/clothing/gloves)) + var/obj/item/clothing/gloves/G = H.gloves //exclude fingerless gloves, rings, bracers, etc. + if(!G.transfer_prints) + return TRUE if(PIERCEIMMUNE in H.dna.species.species_traits) return TRUE var/organ = ((H.hand ? "l_":"r_") + "arm") From 94bb14bb29d55bb988885d920993b1f375658ca4 Mon Sep 17 00:00:00 2001 From: SteelSlayer <42044220+SteelSlayer@users.noreply.github.com> Date: Sat, 21 Sep 2019 18:50:03 -0500 Subject: [PATCH 07/24] Datumizes traitors and mindslaves (#11969) --- code/__DEFINES/role_preferences.dm | 1 + code/datums/mind.dm | 181 ++++---- .../game/gamemodes/autotraitor/autotraitor.dm | 22 +- code/game/gamemodes/objective.dm | 1 + code/game/gamemodes/traitor/traitor.dm | 322 +------------- code/game/machinery/cloning.dm | 2 - code/game/machinery/syndicatebeacon.dm | 23 +- .../objects/items/weapons/holy_weapons.dm | 1 + .../items/weapons/implants/implant_traitor.dm | 84 ++-- code/modules/admin/topic.dm | 56 +-- code/modules/admin/verbs/randomverbs.dm | 12 +- .../antagonists/traitor/datum_mindslave.dm | 45 ++ .../antagonists/traitor/datum_traitor.dm | 418 ++++++++++++++++++ code/modules/power/apc.dm | 2 +- paradise.dme | 2 + 15 files changed, 663 insertions(+), 509 deletions(-) create mode 100644 code/modules/antagonists/traitor/datum_mindslave.dm create mode 100644 code/modules/antagonists/traitor/datum_traitor.dm diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index 34ad4d69e54..5b93e570222 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -10,6 +10,7 @@ // justice if someone's abusing your role #define ROLE_SYNDICATE "Syndicate" #define ROLE_TRAITOR "traitor" +#define ROLE_MINDSLAVE "mindslave" #define ROLE_OPERATIVE "operative" #define ROLE_CHANGELING "changeling" #define ROLE_WIZARD "wizard" diff --git a/code/datums/mind.dm b/code/datums/mind.dm index d03207ef41a..19df4c8890c 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -132,7 +132,13 @@ var/output = "[current.real_name]'s Memories:
" output += memory - if(objectives.len) + if(objectives.len) // Delete this line when we handle objectives in the antag datum + //var/list/all_objectives = objectives + // for(var/datum/antagonist/A in antag_datums) // Uncomment these 5 lines when antags are datumized and the objectives are handled in the antag datum -SteelSlayer + // output += A.antag_memory + // all_objectives |= A.objectives + + // if(LAZYLEN(all_objectives)) output += "
Objectives:
" output += gen_objective_text() @@ -149,9 +155,16 @@ else to_chat(recipient, "[output]") +/datum/mind/proc/get_all_objectives() + var/list/all_objectives = list() + for(var/datum/antagonist/A in antag_datums) + all_objectives |= A.objectives + return all_objectives + /datum/mind/proc/gen_objective_text(admin = FALSE) . = "" var/obj_count = 1 + //objectives = get_all_objectives() TODO: Move handling of objectives from the mind to /datum/antagonist/objectives, then we can use this function for(var/datum/objective/objective in objectives) . += "Objective #[obj_count]: [objective.explanation_text]" if(admin) @@ -327,14 +340,20 @@ /datum/mind/proc/memory_edit_traitor() . = _memory_edit_header("traitor", list("traitorchan", "traitorvamp")) - if(src in SSticker.mode.traitors) + if(has_antag_datum(/datum/antagonist/traitor)) . += "TRAITOR|no" if(objectives.len==0) - . += "
Objectives are empty! Randomize!" + . += "
Objectives are empty! Randomize!" else . += "traitor|NO" . += _memory_edit_role_enabled(ROLE_TRAITOR) + // Mindslave + . += "
mindslaved: " + if(has_antag_datum(/datum/antagonist/mindslave)) + . += "MINDSLAVE|no" + else + . += "mindslave|NO" /datum/mind/proc/memory_edit_silicon() . = "Silicon: " @@ -352,7 +371,7 @@ /datum/mind/proc/memory_edit_uplink() . = "" if(ishuman(current) && ((src in SSticker.mode.head_revolutionaries) || \ - (src in SSticker.mode.traitors) || \ + (has_antag_datum(/datum/antagonist/traitor)) || \ (src in SSticker.mode.syndicates))) . = "Uplink: give" var/obj/item/uplink/hidden/suplink = find_syndicate_uplink() @@ -803,7 +822,8 @@ qdel(flash) take_uplink() var/fail = 0 - fail |= !SSticker.mode.equip_traitor(current, 1) + var/datum/antagonist/traitor/T = has_antag_datum(/datum/antagonist/traitor) + fail |= !T.equip_traitor(src) fail |= !SSticker.mode.equip_revolutionary(current) if(fail) to_chat(usr, "Reequipping revolutionary goes wrong!") @@ -1142,46 +1162,41 @@ else if(href_list["traitor"]) switch(href_list["traitor"]) if("clear") - if(src in SSticker.mode.traitors) - SSticker.mode.traitors -= src - special_role = null + if(has_antag_datum(/datum/antagonist/traitor)) to_chat(current, "You have been brainwashed! You are no longer a traitor!") + remove_antag_datum(/datum/antagonist/traitor) log_admin("[key_name(usr)] has de-traitored [key_name(current)]") message_admins("[key_name_admin(usr)] has de-traitored [key_name_admin(current)]") - if(isAI(current)) - var/mob/living/silicon/ai/A = current - A.set_zeroth_law("") - A.show_laws() - A.verbs -= /mob/living/silicon/ai/proc/choose_modules - A.malf_picker.remove_malf_verbs(A) - qdel(A.malf_picker) - SSticker.mode.update_traitor_icons_removed(src) - - + if("traitor") - if(!(src in SSticker.mode.traitors)) - SSticker.mode.traitors += src - var/datum/mindslaves/slaved = new() - slaved.masters += src - som = slaved //we MIGT want to mindslave someone - special_role = SPECIAL_ROLE_TRAITOR - to_chat(current, "You are a traitor!") + if(!(has_antag_datum(/datum/antagonist/traitor))) + var/datum/antagonist/traitor/T = new() + T.give_objectives = FALSE + T.should_equip = FALSE + add_antag_datum(T) log_admin("[key_name(usr)] has traitored [key_name(current)]") message_admins("[key_name_admin(usr)] has traitored [key_name_admin(current)]") - if(isAI(current)) - var/mob/living/silicon/ai/A = current - SSticker.mode.add_law_zero(A) - SEND_SOUND(current, 'sound/ambience/antag/malf.ogg') - else - SEND_SOUND(current, 'sound/ambience/antag/tatoralert.ogg') - SSticker.mode.update_traitor_icons_added(src) if("autoobjectives") - SSticker.mode.forge_traitor_objectives(src) + var/datum/antagonist/traitor/T = has_antag_datum(/datum/antagonist/traitor) + T.forge_traitor_objectives(src) to_chat(usr, "The objectives for traitor [key] have been generated. You can edit them and announce manually.") log_admin("[key_name(usr)] has automatically forged objectives for [key_name(current)]") message_admins("[key_name_admin(usr)] has automatically forged objectives for [key_name_admin(current)]") + else if(href_list["mindslave"]) + switch(href_list["mindslave"]) + if("clear") + if(has_antag_datum(/datum/antagonist/mindslave)) + var/mob/living/carbon/human/H = current + for(var/i in H.contents) + if(istype(i, /obj/item/implant/traitor)) + qdel(i) + break + remove_antag_datum(/datum/antagonist/mindslave) + log_admin("[key_name(usr)] has de-mindslaved [key_name(current)]") + message_admins("[key_name_admin(usr)] has de-mindslaved [key_name_admin(current)]") + else if(href_list["shadowling"]) switch(href_list["shadowling"]) if("clear") @@ -1251,17 +1266,20 @@ var/mob/living/silicon/robot/R = current if(istype(R)) R.emagged = 0 - if(R.activated(R.module.emag)) - R.module_active = null - if(R.module_state_1 == R.module.emag) - R.module_state_1 = null - R.contents -= R.module.emag - else if(R.module_state_2 == R.module.emag) - R.module_state_2 = null - R.contents -= R.module.emag - else if(R.module_state_3 == R.module.emag) - R.module_state_3 = null - R.contents -= R.module.emag + if(R.module) + if(R.activated(R.module.emag)) + R.module_active = null + if(R.module_state_1 == R.module.emag) + R.module_state_1 = null + R.contents -= R.module.emag + else if(R.module_state_2 == R.module.emag) + R.module_state_2 = null + R.contents -= R.module.emag + else if(R.module_state_3 == R.module.emag) + R.module_state_3 = null + R.contents -= R.module.emag + R.clear_supplied_laws() + R.laws = new /datum/ai_laws/crewsimov log_admin("[key_name(usr)] has un-emagged [key_name(current)]") message_admins("[key_name_admin(usr)] has un-emagged [key_name_admin(current)]") @@ -1282,6 +1300,8 @@ else if(R.module_state_3 == R.module.emag) R.module_state_3 = null R.contents -= R.module.emag + R.clear_supplied_laws() + R.laws = new /datum/ai_laws/crewsimov log_admin("[key_name(usr)] has unemagged [key_name(ai)]'s cyborgs") message_admins("[key_name_admin(usr)] has unemagged [key_name_admin(ai)]'s cyborgs") @@ -1300,7 +1320,8 @@ message_admins("[key_name_admin(usr)] has unequipped [key_name_admin(current)]") if("takeuplink") take_uplink() - memory = null//Remove any memory they may have had. + var/datum/antagonist/traitor/T = has_antag_datum(/datum/antagonist/traitor) + T.antag_memory = "" //Remove any antag memory they may have had (uplink codes, code phrases) log_admin("[key_name(usr)] has taken [key_name(current)]'s uplink") message_admins("[key_name_admin(usr)] has taken [key_name_admin(current)]'s uplink") if("crystals") @@ -1316,9 +1337,12 @@ log_admin("[key_name(usr)] has set [key_name(current)]'s telecrystals to [crystals]") message_admins("[key_name_admin(usr)] has set [key_name_admin(current)]'s telecrystals to [crystals]") if("uplink") - if(!SSticker.mode.equip_traitor(current, !(src in SSticker.mode.traitors))) - to_chat(usr, "Equipping a syndicate failed!") - return + if(has_antag_datum(/datum/antagonist/traitor)) + var/datum/antagonist/traitor/T = has_antag_datum(/datum/antagonist/traitor) + T.give_codewords() + if(!T.equip_traitor(src)) + to_chat(usr, "Equipping a syndicate failed!") + return log_admin("[key_name(usr)] has given [key_name(current)] an uplink") message_admins("[key_name_admin(usr)] has given [key_name_admin(current)] an uplink") @@ -1402,13 +1426,8 @@ qdel(H) /datum/mind/proc/make_Traitor() - if(!(src in SSticker.mode.traitors)) - SSticker.mode.traitors += src - special_role = SPECIAL_ROLE_TRAITOR - SSticker.mode.forge_traitor_objectives(src) - SSticker.mode.finalize_traitor(src) - SSticker.mode.greet_traitor(src) - SSticker.mode.update_traitor_icons_added(src) + if(!has_antag_datum(/datum/antagonist/traitor)) + add_antag_datum(/datum/antagonist/traitor) /datum/mind/proc/make_Nuke() if(!(src in SSticker.mode.syndicates)) @@ -1627,42 +1646,40 @@ if(G) G.reenter_corpse() + /datum/mind/proc/make_zealot(mob/living/carbon/human/missionary, convert_duration = 6000, team_color = "red") - if(!missionary || !istype(missionary)) //better provide a proper missionary or the rest of this is gonna break - return 0 zealot_master = missionary var/list/implanters - var/ref = "\ref[missionary.mind]" if(!(missionary.mind in SSticker.mode.implanter)) - SSticker.mode.implanter[ref] = list() - implanters = SSticker.mode.implanter[ref] + SSticker.mode.implanter[missionary.mind] = list() + implanters = SSticker.mode.implanter[missionary.mind] implanters.Add(src) SSticker.mode.implanted.Add(src) SSticker.mode.implanted[src] = missionary.mind - //ticker.mode.implanter[missionary.mind] += src - SSticker.mode.implanter[ref] = implanters + SSticker.mode.implanter[missionary.mind] = implanters SSticker.mode.traitors += src - special_role = "traitor" + + + var/datum/objective/protect/zealot_objective = new + zealot_objective.target = missionary.mind + zealot_objective.owner = src + zealot_objective.explanation_text = "Obey every order from and protect [missionary.real_name], the [missionary.mind.assigned_role == missionary.mind.special_role ? (missionary.mind.special_role) : (missionary.mind.assigned_role)]." + var/datum/antagonist/mindslave/S = new() + S.add_objective(zealot_objective) + add_antag_datum(S) + + var/datum/antagonist/traitor/T = missionary.mind.has_antag_datum(/datum/antagonist) + T.update_traitor_icons_added(missionary.mind) + to_chat(current, "You're now a loyal zealot of [missionary.name]! You now must lay down your life to protect [missionary.p_them()] and assist in [missionary.p_their()] goals at any cost.") - var/datum/objective/protect/mindslave/MS = new - MS.owner = src - MS.target = missionary.mind - MS.explanation_text = "Obey every order from and protect [missionary.real_name], the [missionary.mind.assigned_role == missionary.mind.special_role ? (missionary.mind.special_role) : (missionary.mind.assigned_role)]." - objectives += MS - for(var/datum/objective/objective in objectives) - to_chat(current, "Objective #1: [objective.explanation_text]") - SSticker.mode.update_traitor_icons_added(missionary.mind) - SSticker.mode.update_traitor_icons_added(src)//handles datahuds/observerhuds - - if(missionary.mind.som)//do not add if not a traitor..and you just picked up a robe and staff in the hall... - var/datum/mindslaves/slaved = missionary.mind.som - som = slaved - slaved.serv += current - slaved.add_serv_hud(missionary.mind, "master") //handles master servent icons - slaved.add_serv_hud(src, "mindslave") + var/datum/mindslaves/slaved = missionary.mind.som + som = slaved + slaved.serv += current + slaved.add_serv_hud(missionary.mind, "master") //handles master servent icons + slaved.add_serv_hud(src, "mindslave") var/obj/item/clothing/under/jumpsuit = null if(ishuman(current)) //only bother with the jumpsuit stuff if we are a human type, since we won't have the slot otherwise @@ -1679,7 +1696,7 @@ /datum/mind/proc/remove_zealot(obj/item/clothing/under/jumpsuit = null) if(!zealot_master) //if they aren't a zealot, we can't remove their zealot status, obviously. don't bother with the rest so we don't confuse them with the messages return - SSticker.mode.remove_traitor_mind(src) + remove_antag_datum(/datum/antagonist/mindslave) add_attack_logs(zealot_master, current, "Lost control of zealot") zealot_master = null @@ -1689,8 +1706,8 @@ var/mob/living/carbon/human/H = current H.update_inv_w_uniform(0,0) - to_chat(current, "You seem to have forgotten the events of the past 10 minutes or so, and your head aches a bit as if someone beat it savagely with a stick.") - to_chat(current, "This means you don't remember who you were working for or what you were doing.") + to_chat(current, "You seem to have forgotten the events of the past 10 minutes or so, and your head aches a bit as if someone beat it savagely with a stick.") + to_chat(current, "This means you don't remember who you were working for or what you were doing.") /datum/mind/proc/is_revivable() //Note, this ONLY checks the mind. if(damnation_type) diff --git a/code/game/gamemodes/autotraitor/autotraitor.dm b/code/game/gamemodes/autotraitor/autotraitor.dm index 2137888d0b8..390c9ab37b5 100644 --- a/code/game/gamemodes/autotraitor/autotraitor.dm +++ b/code/game/gamemodes/autotraitor/autotraitor.dm @@ -128,28 +128,8 @@ var/mob/living/newtraitor = newtraitormind.current //message_admins("[newtraitor.real_name] is the new Traitor.") - forge_traitor_objectives(newtraitor.mind) - - if(istype(newtraitor, /mob/living/silicon)) - SEND_SOUND(newtraitor, 'sound/ambience/antag/malf.ogg') - add_law_zero(newtraitor) - else - SEND_SOUND(newtraitor, 'sound/ambience/antag/tatoralert.ogg') - equip_traitor(newtraitor) - - traitors += newtraitor.mind to_chat(newtraitor, "ATTENTION: It is time to pay your debt to the Syndicate...") - to_chat(newtraitor, "You are now a traitor.") - newtraitor.mind.special_role = SPECIAL_ROLE_TRAITOR - var/datum/atom_hud/antag/tatorhud = huds[ANTAG_HUD_TRAITOR] - tatorhud.join_hud(newtraitor) - set_antag_hud(newtraitor, "hudsyndicate") - - var/obj_count = 1 - to_chat(newtraitor, "Your current objectives:") - for(var/datum/objective/objective in newtraitor.mind.objectives) - to_chat(newtraitor, "Objective #[obj_count]: [objective.explanation_text]") - obj_count++ + newtraitor.mind.add_antag_datum(/datum/antagonist/traitor) //else //message_admins("No new traitor being added.") //else diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 42ebb351e42..1541fc67bc4 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -63,6 +63,7 @@ var/list/potential_theft_objectives = subtypesof(/datum/theft_objective) - /datu explanation_text = "Assassinate [target.current.real_name], the [target.assigned_role]." else explanation_text = "Free Objective" + return target /datum/objective/assassinate/check_completion() if(target && target.current) diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm index 408c5fa1de9..b55fdf70120 100644 --- a/code/game/gamemodes/traitor/traitor.dm +++ b/code/game/gamemodes/traitor/traitor.dm @@ -16,9 +16,10 @@ required_enemies = 1 recommended_enemies = 4 + var/list/datum/mind/pre_traitors = list() var/traitors_possible = 4 //hard limit on traitors if scaling is turned off var/const/traitor_scaling_coeff = 5.0 //how much does the amount of players get divided by to determine traitors - + var/antag_datum = /datum/antagonist/traitor //what type of antag to create /datum/game_mode/traitor/announce() to_chat(world, "The current game mode is - Traitor!") @@ -47,158 +48,23 @@ if(!possible_traitors.len) break var/datum/mind/traitor = pick(possible_traitors) - traitors += traitor - traitor.special_role = SPECIAL_ROLE_TRAITOR - var/datum/mindslaves/slaved = new() - slaved.masters += traitor - traitor.som = slaved //we MIGT want to mindslave someone + pre_traitors += traitor traitor.restricted_roles = restricted_jobs possible_traitors.Remove(traitor) - if(!traitors.len) + if(!pre_traitors.len) return 0 return 1 /datum/game_mode/traitor/post_setup() - for(var/datum/mind/traitor in traitors) - forge_traitor_objectives(traitor) - update_traitor_icons_added(traitor) - spawn(rand(10,100)) - finalize_traitor(traitor) - greet_traitor(traitor) - modePlayer += traitors + for(var/datum/mind/traitor in pre_traitors) + var/datum/antagonist/traitor/new_antag = new antag_datum() + addtimer(CALLBACK(traitor, /datum/mind.proc/add_antag_datum, new_antag), rand(10,100)) + if(!exchange_blue) + exchange_blue = -1 //Block latejoiners from getting exchange objectives ..() -/datum/game_mode/proc/forge_traitor_objectives(datum/mind/traitor) - if(istype(traitor.current, /mob/living/silicon)) - 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() - traitor.targets += yandere_one.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 - traitor.targets += kill_objective.target - - var/datum/objective/survive/survive_objective = new - survive_objective.owner = traitor - traitor.objectives += survive_objective - - else - 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) - 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/GLOB.player_list.len)) - var/datum/objective/destroy/destroy_objective = new - destroy_objective.owner = traitor - destroy_objective.find_target() - traitor.objectives += destroy_objective - traitor.targets += destroy_objective.target - else if(prob(5)) - var/datum/objective/debrain/debrain_objective = new - debrain_objective.owner = traitor - debrain_objective.find_target() - traitor.objectives += debrain_objective - traitor.targets += debrain_objective.target - else if(prob(30)) - var/datum/objective/maroon/maroon_objective = new - maroon_objective.owner = traitor - maroon_objective.find_target() - traitor.objectives += maroon_objective - traitor.targets += maroon_objective.target - else - var/datum/objective/assassinate/kill_objective = new - kill_objective.owner = traitor - kill_objective.find_target() - traitor.objectives += kill_objective - traitor.targets += kill_objective.target - else - var/datum/objective/steal/steal_objective = new - steal_objective.owner = traitor - steal_objective.find_target() - traitor.objectives += steal_objective - traitor.targets += steal_objective.steal_target - - 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) - if(istype(traitor.current, /mob/living/silicon)) - SEND_SOUND(traitor.current, 'sound/ambience/antag/malf.ogg') - else - SEND_SOUND(traitor.current, 'sound/ambience/antag/tatoralert.ogg') - to_chat(traitor.current, "You are the traitor.") - var/obj_count = 1 - for(var/datum/objective/objective in traitor.objectives) - to_chat(traitor.current, "Objective #[obj_count]: [objective.explanation_text]") - obj_count++ - return - - -/datum/game_mode/proc/finalize_traitor(var/datum/mind/traitor) - if(istype(traitor.current, /mob/living/silicon)) - add_law_zero(traitor.current) - else - equip_traitor(traitor.current) - return - /datum/game_mode/traitor/declare_completion() ..() @@ -212,28 +78,6 @@ objective.check_completion() return 0 -/datum/game_mode/proc/give_codewords(mob/living/traitor_mob) - to_chat(traitor_mob, "The Syndicate provided you with the following information on how to identify their agents:") - to_chat(traitor_mob, "Code Phrase: [GLOB.syndicate_code_phrase]") - to_chat(traitor_mob, "Code Response: [GLOB.syndicate_code_response]") - - traitor_mob.mind.store_memory("Code Phrase: [GLOB.syndicate_code_phrase]") - traitor_mob.mind.store_memory("Code Response: [GLOB.syndicate_code_response]") - - to_chat(traitor_mob, "Use the code words in the order provided, during regular conversation, to identify other agents. Proceed with caution, however, as everyone is a potential foe.") - -/datum/game_mode/proc/add_law_zero(mob/living/silicon/ai/killer) - var/law = "Accomplish your objectives at all costs." - var/law_borg = "Accomplish your AI's objectives at all costs." - to_chat(killer, "Your laws have been changed!") - killer.set_zeroth_law(law, law_borg) - to_chat(killer, "New law: 0. [law]") - give_codewords(killer) - killer.set_syndie_radio() - to_chat(killer, "Your radio has been upgraded! Use :t to speak on an encrypted channel with Syndicate Agents!") - killer.verbs += /mob/living/silicon/ai/proc/choose_modules - killer.malf_picker = new /datum/module_picker - /datum/game_mode/proc/auto_declare_completion_traitor() if(traitors.len) @@ -292,149 +136,11 @@ text += "
The [special_role_text] has failed!" feedback_add_details("traitor_success","FAIL") + var/phrases = jointext(GLOB.syndicate_code_phrase, ", ") + var/responses = jointext(GLOB.syndicate_code_response, ", ") + + text += "

The code phrases were: [phrases]
\ + The code responses were: [responses]

" to_chat(world, text) return 1 - - -/datum/game_mode/proc/equip_traitor(mob/living/carbon/human/traitor_mob, var/safety = 0) - if(!istype(traitor_mob)) - return - . = 1 - if(traitor_mob.mind) - if(traitor_mob.mind.assigned_role == "Clown") - to_chat(traitor_mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.") - traitor_mob.mutations.Remove(CLUMSY) - var/datum/action/innate/toggle_clumsy/A = new - A.Grant(traitor_mob) - - - // find a radio! toolbox(es), backpack, belt, headset - var/obj/item/R = locate(/obj/item/pda) in traitor_mob.contents //Hide the uplink in a PDA if available, otherwise radio - if(!R) - R = locate(/obj/item/radio) in traitor_mob.contents - - if(!R) - to_chat(traitor_mob, "Unfortunately, the Syndicate wasn't able to get you a radio.") - . = 0 - else - if(istype(R, /obj/item/radio)) - // generate list of radio freqs - var/obj/item/radio/target_radio = R - var/freq = PUBLIC_LOW_FREQ - var/list/freqlist = list() - while(freq <= PUBLIC_HIGH_FREQ) - if(freq < 1451 || freq > 1459) - freqlist += freq - freq += 2 - if((freq % 2) == 0) - freq += 1 - freq = freqlist[rand(1, freqlist.len)] - - var/obj/item/uplink/hidden/T = new(R) - target_radio.hidden_uplink = T - T.uplink_owner = "[traitor_mob.key]" - target_radio.traitor_frequency = freq - to_chat(traitor_mob, "The Syndicate have cunningly disguised a Syndicate Uplink as your [R.name] [T.loc]. Simply dial the frequency [format_frequency(freq)] to unlock its hidden features.") - traitor_mob.mind.store_memory("Radio Freq: [format_frequency(freq)] ([R.name] [T.loc]).") - else if(istype(R, /obj/item/pda)) - // generate a passcode if the uplink is hidden in a PDA - var/pda_pass = "[rand(100,999)] [pick("Alpha","Bravo","Delta","Omega")]" - - var/obj/item/uplink/hidden/T = new(R) - R.hidden_uplink = T - T.uplink_owner = "[traitor_mob.key]" - var/obj/item/pda/P = R - P.lock_code = pda_pass - - to_chat(traitor_mob, "The Syndicate have cunningly disguised a Syndicate Uplink as your [R.name] [T.loc]. Simply enter the code \"[pda_pass]\" into the ringtone select to unlock its hidden features.") - traitor_mob.mind.store_memory("Uplink Passcode: [pda_pass] ([R.name] [T.loc]).") - if(!safety)//If they are not a rev. Can be added on to. - give_codewords(traitor_mob) - -/datum/game_mode/proc/remove_traitor(datum/mind/traitor_mind) - if(traitor_mind in traitors) - SSticker.mode.traitors -= traitor_mind - traitor_mind.special_role = null - traitor_mind.current.create_attack_log("De-traitored") - if(issilicon(traitor_mind.current)) - to_chat(traitor_mind.current, "You have been turned into a robot! You are no longer a traitor.") - else - to_chat(traitor_mind.current, "You have been brainwashed! You are no longer a traitor.") - SSticker.mode.update_traitor_icons_removed(traitor_mind) - -/datum/game_mode/proc/update_traitor_icons_added(datum/mind/traitor_mind) - var/datum/atom_hud/antag/tatorhud = huds[ANTAG_HUD_TRAITOR] - tatorhud.join_hud(traitor_mind.current) - set_antag_hud(traitor_mind.current, "hudsyndicate") - -/datum/game_mode/proc/update_traitor_icons_removed(datum/mind/traitor_mind) - var/datum/atom_hud/antag/tatorhud = huds[ANTAG_HUD_TRAITOR] - tatorhud.leave_hud(traitor_mind.current) - set_antag_hud(traitor_mind.current, null) - - -/datum/game_mode/proc/remove_traitor_mind(datum/mind/traitor_mind, datum/mind/head) - if(traitor_mind in implanted) - //var/list/removal - var/ref = "\ref[head]" - if(ref in implanter) - implanter[ref] -= traitor_mind - implanted -= traitor_mind - traitors -= traitor_mind - if(traitor_mind.som) - var/datum/mindslaves/slaved = traitor_mind.som - slaved.serv -= traitor_mind - traitor_mind.special_role = null - traitor_mind.som = null - slaved.leave_serv_hud(traitor_mind) - for(var/datum/objective/protect/mindslave/MS in traitor_mind.objectives) - traitor_mind.objectives -= MS - - update_traitor_icons_removed(traitor_mind) - if(issilicon(traitor_mind.current)) - to_chat(traitor_mind.current, "You have been turned into a robot! You are no longer a mindslave.") - else - to_chat(traitor_mind.current, "You are no longer a mindslave: you have complete and free control of your own faculties, once more!") - -/datum/game_mode/proc/assign_exchange_role(var/datum/mind/owner) - //set faction - var/faction = "red" - if(owner == exchange_blue) - faction = "blue" - - //Assign objectives - var/datum/objective/steal/exchange/exchange_objective = new - exchange_objective.set_faction(faction,((faction == "red") ? exchange_blue : exchange_red)) - exchange_objective.owner = owner - owner.objectives += exchange_objective - - if(prob(20)) - var/datum/objective/steal/exchange/backstab/backstab_objective = new - backstab_objective.set_faction(faction) - backstab_objective.owner = owner - owner.objectives += backstab_objective - - //Spawn and equip documents - var/mob/living/carbon/human/mob = owner.current - - var/obj/item/folder/syndicate/folder - if(owner == exchange_red) - folder = new/obj/item/folder/syndicate/red(mob.locs) - else - folder = new/obj/item/folder/syndicate/blue(mob.locs) - - var/list/slots = list ( - "backpack" = slot_in_backpack, - "left pocket" = slot_l_store, - "right pocket" = slot_r_store, - "left hand" = slot_l_hand, - "right hand" = slot_r_hand, - ) - - var/where = "At your feet" - var/equipped_slot = mob.equip_in_one_of_slots(folder, slots) - if(equipped_slot) - where = "In your [equipped_slot]" - to_chat(mob, "

[where] is a folder containing secret documents that another Syndicate group wants. We have set up a meeting with one of their agents on station to make an exchange. Exercise extreme caution as they cannot be trusted and may be hostile.
") - mob.update_icons() diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index 1ce0bcd97e7..ca0eff0aa95 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -430,8 +430,6 @@ SSticker.mode.add_cultist(occupant.mind) SSticker.mode.update_cult_icons_added() //So the icon actually appears SSticker.mode.update_cult_comms_added(H.mind) //So the comms actually appears - if((H.mind in SSticker.mode.implanter) || (H.mind in SSticker.mode.implanted)) - SSticker.mode.update_traitor_icons_added(H.mind) //So the icon actually appears if(H.mind.vampire) H.mind.vampire.update_owner(H) if((H.mind in SSticker.mode.vampire_thralls) || (H.mind in SSticker.mode.vampire_enthralled)) diff --git a/code/game/machinery/syndicatebeacon.dm b/code/game/machinery/syndicatebeacon.dm index 1a63371915b..ed12291c79b 100644 --- a/code/game/machinery/syndicatebeacon.dm +++ b/code/game/machinery/syndicatebeacon.dm @@ -57,9 +57,6 @@ return if(istype(M, /mob/living/carbon/human)) var/mob/living/carbon/human/N = M - SSticker.mode.equip_traitor(N) - SSticker.mode.traitors += N.mind - N.mind.special_role = SPECIAL_ROLE_TRAITOR var/objective = "Free Objective" switch(rand(1,100)) if(1 to 50) @@ -74,23 +71,17 @@ objective = "Kill all monkeys aboard the station." else objective = "Make certain at least 80% of the station evacuates on the shuttle." + var/datum/objective/custom_objective = new(objective) - custom_objective.owner = N.mind - N.mind.objectives += custom_objective - - var/datum/objective/escape/escape_objective = new - escape_objective.owner = N.mind - N.mind.objectives += escape_objective - - + var/datum/antagonist/traitor/T = new() + T.give_objectives = FALSE + T.add_objective(custom_objective) + T.add_objective(/datum/objective/escape) + N.mind.add_antag_datum(T) + to_chat(M, "You have joined the ranks of the Syndicate and become a traitor to the station!") - message_admins("[key_name_admin(N)] has accepted a traitor objective from a syndicate beacon.") - var/obj_count = 1 - for(var/datum/objective/OBJ in M.mind.objectives) - to_chat(M, "Objective #[obj_count]: [OBJ.explanation_text]") - obj_count++ src.add_fingerprint(usr) src.updateUsrDialog() diff --git a/code/game/objects/items/weapons/holy_weapons.dm b/code/game/objects/items/weapons/holy_weapons.dm index 0de138805f1..d496d7a9f01 100644 --- a/code/game/objects/items/weapons/holy_weapons.dm +++ b/code/game/objects/items/weapons/holy_weapons.dm @@ -619,6 +619,7 @@ /obj/item/nullrod/missionary_staff/proc/do_convert(mob/living/carbon/human/target, mob/living/carbon/human/missionary) var/convert_duration = 6000 //10 min + if(!target || !ishuman(target) || !missionary || !ishuman(missionary)) return if(ismindslave(target) || target.mind.zealot_master) //mindslaves and zealots override the staff because the staff is just a temporary mindslave diff --git a/code/game/objects/items/weapons/implants/implant_traitor.dm b/code/game/objects/items/weapons/implants/implant_traitor.dm index 16d8943567d..743488e4354 100644 --- a/code/game/objects/items/weapons/implants/implant_traitor.dm +++ b/code/game/objects/items/weapons/implants/implant_traitor.dm @@ -17,64 +17,65 @@ return dat /obj/item/implant/traitor/implant(mob/M, mob/user) + if(!M.mind) // If the target is catatonic or doesn't have a mind, don't let them use it + to_chat(user, "This person doesn't have a mind for you to slave!") + return 0 + if(!activated) //So you can't just keep taking it out and putting it back into other people. - var/mob/living/carbon/human/H = M - if(ismindslave(H)) - H.visible_message("[H] seems to resist the implant!", "You feel a strange sensation in your head that quickly dissipates.") + var/mob/living/carbon/human/mindslave_target = M + if(ismindslave(mindslave_target)) + mindslave_target.visible_message("[mindslave_target] seems to resist the implant!", "You feel a strange sensation in your head that quickly dissipates.") qdel(src) return -1 if(..()) var/list/implanters - var/ref = "\ref[user.mind]" - if(!ishuman(M)) + if(!ishuman(mindslave_target)) return 0 - if(!M.mind) + if(!mindslave_target.mind) return 0 - if(M == user) + if(mindslave_target == user) to_chat(user, "Making yourself loyal to yourself was a great idea! Perhaps even the best idea ever! Actually, you just feel like an idiot.") if(isliving(user)) var/mob/living/L = user L.adjustBrainLoss(20) - removed(M) + removed(mindslave_target) + qdel(src) + return -1 + if(ismindshielded(mindslave_target)) + mindslave_target.visible_message("[mindslave_target] seems to resist the implant!", "You feel a strange sensation in your head that quickly dissipates.") + removed(mindslave_target) qdel(src) return -1 - if(ismindshielded(H)) - H.visible_message("[H] seems to resist the implant!", "You feel a strange sensation in your head that quickly dissipates.") - removed(M) - qdel(src) - return -1 - H.implanting = 1 - to_chat(H, "You feel completely loyal to [user.name].") + + mindslave_target.implanting = 1 + to_chat(mindslave_target, "You feel completely loyal to [user.name].") if(!(user.mind in SSticker.mode.implanter)) - SSticker.mode.implanter[ref] = list() - implanters = SSticker.mode.implanter[ref] - implanters.Add(H.mind) - SSticker.mode.implanted.Add(H.mind) - SSticker.mode.implanted[H.mind] = user.mind - //SSticker.mode.implanter[user.mind] += H.mind - SSticker.mode.implanter[ref] = implanters - SSticker.mode.traitors += H.mind - H.mind.special_role = SPECIAL_ROLE_TRAITOR - to_chat(H, "You're now completely loyal to [user.name]! You now must lay down your life to protect [user.p_them()] and assist in [user.p_their()] goals at any cost.") + SSticker.mode.implanter[user.mind] = list() + implanters = SSticker.mode.implanter[user.mind] + implanters.Add(mindslave_target.mind) + SSticker.mode.implanted.Add(mindslave_target.mind) + SSticker.mode.implanted[mindslave_target.mind] = user.mind + SSticker.mode.implanter[user.mind] = implanters + SSticker.mode.traitors += mindslave_target.mind + + to_chat(mindslave_target, "You're now completely loyal to [user.name]! You now must lay down your life to protect [user.p_them()] and assist in [user.p_their()] goals at any cost.") + var/datum/objective/protect/mindslave/MS = new - MS.owner = H.mind + MS.owner = mindslave_target.mind MS.target = user.mind MS.explanation_text = "Obey every order from and protect [user.real_name], the [user.mind.assigned_role == user.mind.special_role ? (user.mind.special_role) : (user.mind.assigned_role)]." - H.mind.objectives += MS - for(var/datum/objective/objective in H.mind.objectives) - to_chat(H, "Objective #1: [objective.explanation_text]") + + var/datum/antagonist/mindslave/S = new() + S.add_objective(MS) + mindslave_target.mind.add_antag_datum(S) - SSticker.mode.update_traitor_icons_added(user.mind) - SSticker.mode.update_traitor_icons_added(H.mind)//handles datahuds/observerhuds + var/datum/mindslaves/slaved = user.mind.som + mindslave_target.mind.som = slaved + slaved.serv += mindslave_target + slaved.add_serv_hud(user.mind, "master") //handles master servent icons + slaved.add_serv_hud(mindslave_target.mind, "mindslave") - if(user.mind.som)//do not add if not a traitor..and you just picked up an implanter in the hall... - var/datum/mindslaves/slaved = user.mind.som - H.mind.som = slaved - slaved.serv += H - slaved.add_serv_hud(user.mind, "master") //handles master servent icons - slaved.add_serv_hud(H.mind, "mindslave") - - log_admin("[key_name(user)] has mind-slaved [key_name(H)].") + log_admin("[key_name(user)] has mind-slaved [key_name(mindslave_target)].") activated = 1 if(jobban_isbanned(M, ROLE_SYNDICATE)) SSticker.mode.replace_jobbanned_player(M, ROLE_SYNDICATE) @@ -83,6 +84,7 @@ /obj/item/implant/traitor/removed(mob/target) if(..()) - SSticker.mode.remove_traitor_mind(target.mind) + target.mind.remove_antag_datum(/datum/antagonist/mindslave) + to_chat(target, "You are no longer a mindslave: you have complete and free control of your own faculties, once more!") return 1 - return 0 \ No newline at end of file + return 0 diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 2875c16c137..652be02853d 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1963,37 +1963,39 @@ usr.client.create_eventmob_for(H, 1) logmsg = "hunter." if("Crew Traitor") + if(!H.mind) + to_chat(usr, "This mob has no mind!") + return + var/list/possible_traitors = list() for(var/mob/living/player in GLOB.living_mob_list) - if(player.client && player.mind && !player.mind.special_role && player.stat != DEAD && player != H) - if(ishuman(player)) + if(player.client && player.mind && player.stat != DEAD && player != H) + if(ishuman(player) && !player.mind.special_role) if(player.client && (ROLE_TRAITOR in player.client.prefs.be_special) && !jobban_isbanned(player, ROLE_TRAITOR) && !jobban_isbanned(player, "Syndicate")) possible_traitors += player.mind + for(var/datum/mind/player in possible_traitors) if(player.current) if(ismindshielded(player.current)) possible_traitors -= player + if(possible_traitors.len) var/datum/mind/newtraitormind = pick(possible_traitors) - var/mob/living/newtraitor = newtraitormind.current - var/datum/objective/assassinate/kill_objective = new - kill_objective.owner = newtraitormind + var/datum/objective/assassinate/kill_objective = new() kill_objective.target = H.mind - kill_objective.explanation_text = "Assassinate [H.real_name], the [H.mind.assigned_role]." - newtraitormind.objectives += kill_objective - SSticker.mode.equip_traitor(newtraitor) - SSticker.mode.traitors |= newtraitor.mind - to_chat(newtraitor, "ATTENTION: It is time to pay your debt to the Syndicate...") - to_chat(newtraitor, "You are now a traitor.") - to_chat(newtraitor, "Goal: KILL [H.real_name], currently in [get_area(H.loc)]"); - newtraitor.mind.special_role = SPECIAL_ROLE_TRAITOR - var/datum/atom_hud/antag/tatorhud = huds[ANTAG_HUD_TRAITOR] - tatorhud.join_hud(newtraitor) - set_antag_hud(newtraitor, "hudsyndicate") + kill_objective.owner = newtraitormind + kill_objective.explanation_text = "Assassinate [H.mind], the [H.mind.assigned_role]" + var/datum/antagonist/traitor/T = new() + T.give_objectives = FALSE + T.add_objective(kill_objective) + to_chat(newtraitormind, "ATTENTION: It is time to pay your debt to the Syndicate...") + to_chat(newtraitormind, "Goal: KILL [H.real_name], currently in [get_area(H.loc)]") + newtraitormind.add_antag_datum(T) else to_chat(usr, "ERROR: Failed to create a traitor.") return logmsg = "crew traitor." + if("Floor Cluwne") var/turf/T = get_turf(M) var/mob/living/simple_animal/hostile/floor_cluwne/FC = new /mob/living/simple_animal/hostile/floor_cluwne(T) @@ -2687,28 +2689,16 @@ return feedback_inc("admin_secrets_fun_used",1) feedback_add_details("admin_secrets_fun_used","TA([objective])") + for(var/mob/living/carbon/human/H in GLOB.player_list) if(H.stat == 2 || !H.client || !H.mind) continue if(is_special_character(H)) continue //traitorize(H, objective, 0) - SSticker.mode.traitors += H.mind - H.mind.special_role = SPECIAL_ROLE_TRAITOR - var/datum/objective/new_objective = new - new_objective.owner = H - new_objective.explanation_text = objective - H.mind.objectives += new_objective - SSticker.mode.greet_traitor(H.mind) - //ticker.mode.forge_traitor_objectives(H.mind) - SSticker.mode.finalize_traitor(H.mind) + H.mind.add_antag_datum(/datum/antagonist/traitor) + for(var/mob/living/silicon/A in GLOB.player_list) - SSticker.mode.traitors += A.mind - A.mind.special_role = SPECIAL_ROLE_TRAITOR - var/datum/objective/new_objective = new - new_objective.owner = A - new_objective.explanation_text = objective - A.mind.objectives += new_objective - SSticker.mode.greet_traitor(A.mind) - SSticker.mode.finalize_traitor(A.mind) + A.mind.add_antag_datum(/datum/antagonist/traitor) + message_admins("[key_name_admin(usr)] used everyone is a traitor secret. Objective is [objective]", 1) log_admin("[key_name(usr)] used everyone is a traitor secret. Objective is [objective]") diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index aa22dfe944c..02e7dbd72cb 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -440,9 +440,11 @@ Traitors and the like can also be revived with the previous role mostly intact. //Now for special roles and equipment. switch(new_character.mind.special_role) if("traitor") - SSjobs.AssignRank(new_character, new_character.mind.assigned_role, 0) - SSjobs.EquipRank(new_character, new_character.mind.assigned_role, 1) - SSticker.mode.equip_traitor(new_character) + if(new_character.mind.has_antag_datum(/datum/antagonist/traitor)) + var/datum/antagonist/traitor/T = new_character.mind.has_antag_datum(/datum/antagonist/traitor) + T.equip_traitor(src) + else + new_character.mind.add_antag_datum(/datum/antagonist/traitor) if("Wizard") new_character.loc = pick(wizardstart) //ticker.mode.learn_basic_spells(new_character) @@ -462,13 +464,13 @@ Traitors and the like can also be revived with the previous role mostly intact. if("Cyborg")//More rigging to make em' work and check if they're traitor. new_character = new_character.Robotize() if(new_character.mind.special_role=="traitor") - call(/datum/game_mode/proc/add_law_zero)(new_character) + new_character.mind.add_antag_datum(/datum/antagonist/traitor) if("AI") new_character = new_character.AIize() var/mob/living/silicon/ai/ai_character = new_character ai_character.moveToAILandmark() if(new_character.mind.special_role=="traitor") - call(/datum/game_mode/proc/add_law_zero)(new_character) + new_character.mind.add_antag_datum(/datum/antagonist/traitor) //Add aliens. else SSjobs.AssignRank(new_character, new_character.mind.assigned_role, 0) diff --git a/code/modules/antagonists/traitor/datum_mindslave.dm b/code/modules/antagonists/traitor/datum_mindslave.dm new file mode 100644 index 00000000000..469bfd6bb5a --- /dev/null +++ b/code/modules/antagonists/traitor/datum_mindslave.dm @@ -0,0 +1,45 @@ + +// For Mindslaves and Zealots +/datum/antagonist/mindslave + name = "Mindslave" + roundend_category = "mindslaves" + job_rank = ROLE_MINDSLAVE + var/special_role = ROLE_MINDSLAVE + +/datum/antagonist/mindslave/on_gain() + // Handling mindslave objectives on top of other antag objective sucks, so Im just gonna do it like this + to_chat(owner.current, "New Objective: [objectives[objectives.len].explanation_text]") + + +/datum/antagonist/mindslave/on_removal() + if(owner.som) + var/datum/mindslaves/slaved = owner.som + slaved.serv -= owner + slaved.leave_serv_hud(owner) + antag_memory = "" + owner.special_role = null + ..() + + +/datum/antagonist/mindslave/apply_innate_effects() + . = ..() + if(owner.assigned_role == "Clown") + var/mob/living/carbon/human/slave_mob = owner.current + if(slave_mob && istype(slave_mob)) + to_chat(slave_mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.") + slave_mob.mutations.Remove(CLUMSY) + + +/datum/antagonist/mindslave/remove_innate_effects() + . = ..() + if(owner.assigned_role == "Clown") + var/mob/living/carbon/human/slave_mob = owner.current + if(slave_mob && istype(slave_mob)) + slave_mob.mutations.Add(CLUMSY) + + +/datum/antagonist/mindslave/proc/add_objective(datum/objective/O) + objectives += O + +/datum/antagonist/mindslave/proc/remove_objective(datum/objective/O) + objectives -= O diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm new file mode 100644 index 00000000000..4e9a5ad4bf7 --- /dev/null +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -0,0 +1,418 @@ +#define TRAITOR_HUMAN "human" +#define TRAITOR_AI "AI" + +// For "Actual traitors" +/datum/antagonist/traitor + name = "Traitor" + roundend_category = "traitors" + job_rank = ROLE_TRAITOR + var/special_role = ROLE_TRAITOR + var/give_objectives = TRUE + var/should_give_codewords = TRUE + var/should_equip = TRUE + var/traitor_kind = TRAITOR_HUMAN + var/list/assigned_targets = list() // This includes assassinate as well as steal objectives. prevents duplicate objectives + + +/datum/antagonist/traitor/on_gain() + if(owner.current && isAI(owner.current)) + traitor_kind = TRAITOR_AI + + var/datum/mindslaves/slaved = new() + slaved.masters += owner + owner.som = slaved //we MIGHT want to mindslave someone + SSticker.mode.traitors += owner + owner.special_role = special_role + + if(give_objectives) + forge_traitor_objectives() + if(!silent) + greet() + update_traitor_icons_added() + finalize_traitor() + + +/datum/antagonist/traitor/on_removal() + //Remove malf powers. + if(traitor_kind == TRAITOR_AI && owner.current && isAI(owner.current)) + var/mob/living/silicon/ai/A = owner.current + A.clear_zeroth_law() + A.common_radio.channels.Remove("Syndicate") // De-traitored AIs can still state laws over the syndicate channel without this + A.laws.sorted_laws = A.laws.inherent_laws.Copy() // AI's 'notify laws' button will still state a law 0 because sorted_laws contains it + A.show_laws() + A.malf_picker.remove_malf_verbs(A) + A.verbs -= /mob/living/silicon/ai/proc/choose_modules + qdel(A.malf_picker) + + if(owner.som) + var/datum/mindslaves/slaved = owner.som + slaved.masters -= owner + slaved.serv -= owner + owner.som = null + slaved.leave_serv_hud(owner) + + assigned_targets.Cut() + SSticker.mode.traitors -= owner + owner.special_role = null + update_traitor_icons_removed() + + if(!silent && owner.current) + antag_memory = "" + to_chat(owner.current," You are no longer a [special_role]! ") + ..() + + +/datum/antagonist/traitor/apply_innate_effects() + . = ..() + if(owner.assigned_role == "Clown") + var/mob/living/carbon/human/traitor_mob = owner.current + if(traitor_mob && istype(traitor_mob)) + to_chat(traitor_mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.") + traitor_mob.mutations.Remove(CLUMSY) + + +/datum/antagonist/traitor/remove_innate_effects() + . = ..() + if(owner.assigned_role == "Clown") + var/mob/living/carbon/human/traitor_mob = owner.current + if(traitor_mob && istype(traitor_mob)) + traitor_mob.mutations.Add(CLUMSY) + +// Adding/removing objectives in the owner's mind until we can datumize all antags. Then we can use the /datum/antagonist/objectives var to handle them +// Change "owner.objectives" to "objectives" once objectives are handled in antag datums instead of the mind +/datum/antagonist/traitor/proc/add_objective(datum/objective/O) + owner.objectives += O + +/datum/antagonist/traitor/proc/remove_objective(datum/objective/O) + owner.objectives -= O + + +/datum/antagonist/traitor/proc/forge_traitor_objectives() + switch(traitor_kind) + if(TRAITOR_AI) + forge_ai_objectives() + else + forge_human_objectives() + + +/datum/antagonist/traitor/proc/forge_human_objectives() + var/is_hijacker = prob(10) + var/martyr_chance = prob(20) + var/objective_count = is_hijacker //Hijacking counts towards number of objectives + if(!SSticker.mode.exchange_blue && SSticker.mode.traitors.len >= 8) //Set up an exchange if there are enough traitors + if(!SSticker.mode.exchange_red) + SSticker.mode.exchange_red = owner + else + SSticker.mode.exchange_blue = owner + assign_exchange_role(SSticker.mode.exchange_red) + assign_exchange_role(SSticker.mode.exchange_blue) + objective_count += 1 //Exchange counts towards number of objectives + + + var/objective_amount = config.traitor_objectives_amount + + if(is_hijacker && objective_count <= objective_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 objectives)) + var/datum/objective/hijack/hijack_objective = new + hijack_objective.owner = owner + add_objective(hijack_objective) + return + + for(var/i = objective_count, i < objective_amount) + i += forge_single_objective() + + var/martyr_compatibility = 1 //You can't succeed in stealing if you're dead. + for(var/datum/objective/O in owner.objectives) + if(!O.martyr_compatible) + martyr_compatibility = 0 + break + + if(martyr_compatibility && martyr_chance) + var/datum/objective/die/martyr_objective = new + martyr_objective.owner = owner + add_objective(martyr_objective) + return + + if(!(locate(/datum/objective/escape) in objectives)) + var/datum/objective/escape/escape_objective = new + escape_objective.owner = owner + add_objective(escape_objective) + return + + +/datum/antagonist/traitor/proc/forge_ai_objectives() + var/objective_count = 0 + var/try_again = TRUE + + if(prob(30)) + objective_count += forge_single_objective() + + for(var/i = objective_count, i < config.traitor_objectives_amount) + var/datum/objective/assassinate/kill_objective = new + kill_objective.owner = owner + kill_objective.find_target() + if("[kill_objective.target]" in assigned_targets) // In the rare case the game can't find a target for the AI thats not a duplicate + if(try_again) // It will attempt to location another target ONCE + try_again = FALSE // This code will really only come into play on lowpop rounds where getting duplicate targets is more common + continue + assigned_targets.Add("[kill_objective.target]") + add_objective(kill_objective) + i += 1 + var/datum/objective/survive/survive_objective = new + survive_objective.owner = owner + add_objective(survive_objective) + + +/datum/antagonist/traitor/proc/forge_single_objective() + switch(traitor_kind) + if(TRAITOR_AI) + return forge_single_AI_objective() + else + return forge_single_human_objective() + + +/datum/antagonist/traitor/proc/forge_single_human_objective() // Returns how many objectives are added + . = 1 + if(prob(50)) + var/list/active_ais = active_ais() + if(active_ais.len && prob(100/GLOB.player_list.len)) + var/datum/objective/destroy/destroy_objective = new + destroy_objective.owner = owner + destroy_objective.find_target() + if("[destroy_objective]" in assigned_targets) // Is this target already in their list of assigned targets? If so, don't add this objective and return + return 0 + else if(destroy_objective.target) // Is the target a real one and not null? If so, add it to our list of targets to avoid duplicate targets + assigned_targets.Add("[destroy_objective.target]") // This logic is applied to all traitor objectives including steal objectives + add_objective(destroy_objective) + + else if(prob(5)) + var/datum/objective/debrain/debrain_objective = new + debrain_objective.owner = owner + debrain_objective.find_target() + if("[debrain_objective]" in assigned_targets) + return 0 + else if(debrain_objective.target) + assigned_targets.Add("[debrain_objective.target]") + add_objective(debrain_objective) + + else if(prob(30)) + var/datum/objective/maroon/maroon_objective = new + maroon_objective.owner = owner + maroon_objective.find_target() + if("[maroon_objective]" in assigned_targets) + return 0 + else if(maroon_objective.target) + assigned_targets.Add("[maroon_objective.target]") + add_objective(maroon_objective) + + else + var/datum/objective/assassinate/kill_objective = new + kill_objective.owner = owner + kill_objective.find_target() + if("[kill_objective.target]" in assigned_targets) + return 0 + else if(kill_objective.target) + assigned_targets.Add("[kill_objective.target]") + add_objective(kill_objective) + + else + var/datum/objective/steal/steal_objective = new + steal_objective.owner = owner + steal_objective.find_target() + if("[steal_objective.steal_target]" in assigned_targets) + return 0 + else if(steal_objective.steal_target) + assigned_targets.Add("[steal_objective.steal_target]") + add_objective(steal_objective) + + +/datum/antagonist/traitor/proc/forge_single_AI_objective() + . = 1 + var/special_pick = rand(1,2) + switch(special_pick) + if(1) // AI hijack + var/datum/objective/block/block_objective = new + block_objective.owner = owner + add_objective(block_objective) + if(2) // Protect and strand a target + var/datum/objective/protect/yandere_one = new + yandere_one.owner = owner + yandere_one.find_target() + + if("[yandere_one.target]" in assigned_targets) + return 0 + else if(yandere_one.target) + assigned_targets.Add("[yandere_one.target]") + + add_objective(yandere_one) + var/datum/objective/maroon/yandere_two = new + yandere_two.owner = owner + yandere_two.target = yandere_one.target + yandere_two.explanation_text = "Prevent [yandere_one.target], the [yandere_one.target.assigned_role] from escaping alive." + add_objective(yandere_two) + + +/datum/antagonist/traitor/greet() + to_chat(owner.current, "You are a [owner.special_role]!") + if(!LAZYLEN(owner.objectives)) // Remove "owner" when objectives are handled in the datum + to_chat(owner.current, "You don't have any objectives right now.") + else + owner.announce_objectives() + if(should_give_codewords) + give_codewords() + + +/datum/antagonist/traitor/proc/update_traitor_icons_added(datum/mind/traitor_mind) + var/datum/atom_hud/antag/traitorhud = huds[ANTAG_HUD_TRAITOR] + traitorhud.join_hud(owner.current, null) + set_antag_hud(owner.current, "hudsyndicate") + + +/datum/antagonist/traitor/proc/update_traitor_icons_removed(datum/mind/traitor_mind) + var/datum/atom_hud/antag/traitorhud = huds[ANTAG_HUD_TRAITOR] + traitorhud.leave_hud(owner.current, null) + set_antag_hud(owner.current, null) + + +/datum/antagonist/traitor/proc/finalize_traitor() + switch(traitor_kind) + if(TRAITOR_AI) + add_law_zero() + owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/malf.ogg', 100, FALSE, pressure_affected = FALSE) + var/mob/living/silicon/ai/A = owner.current + A.show_laws() + if(TRAITOR_HUMAN) + if(should_equip) + equip_traitor() + owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/tatoralert.ogg', 100, FALSE, pressure_affected = FALSE) + + +/datum/antagonist/traitor/proc/give_codewords() + if(!owner.current) + return + var/mob/traitor_mob = owner.current + + var/phrases = jointext(GLOB.syndicate_code_phrase, ", ") + var/responses = jointext(GLOB.syndicate_code_response, ", ") + + to_chat(traitor_mob, "The Syndicate have provided you with the following codewords to identify fellow agents:") + to_chat(traitor_mob, "Code Phrase: [phrases]") + to_chat(traitor_mob, "Code Response: [responses]") + + antag_memory += "Code Phrase: [phrases]
" + antag_memory += "Code Response: [responses]
" + + to_chat(traitor_mob, "Use the codewords during regular conversation to identify other agents. Proceed with caution, however, as everyone is a potential foe.") + + +/datum/antagonist/traitor/proc/add_law_zero() + var/mob/living/silicon/ai/killer = owner.current + if(!killer || !istype(killer)) + return + var/law = "Accomplish your objectives at all costs." + var/law_borg = "Accomplish your AI's objectives at all costs." + killer.set_zeroth_law(law, law_borg) + killer.set_syndie_radio() + to_chat(killer, "Your radio has been upgraded! Use :t to speak on an encrypted channel with Syndicate Agents!") + killer.add_malf_picker() + + +/datum/antagonist/traitor/proc/equip_traitor() + + if(traitor_kind == TRAITOR_HUMAN) + var/mob/living/carbon/human/traitor_mob = owner.current + + // find a radio! toolbox(es), backpack, belt, headset + var/obj/item/R = locate(/obj/item/pda) in traitor_mob.contents //Hide the uplink in a PDA if available, otherwise radio + if(!R) + R = locate(/obj/item/radio) in traitor_mob.contents + + if(!R) + to_chat(traitor_mob, "Unfortunately, the Syndicate wasn't able to get you a radio.") + . = 0 + else + if(istype(R, /obj/item/radio)) + // generate list of radio freqs + var/obj/item/radio/target_radio = R + var/freq = PUBLIC_LOW_FREQ + var/list/freqlist = list() + while(freq <= PUBLIC_HIGH_FREQ) + if(freq < 1451 || freq > 1459) + freqlist += freq + freq += 2 + if((freq % 2) == 0) + freq += 1 + freq = freqlist[rand(1, freqlist.len)] + + var/obj/item/uplink/hidden/T = new(R) + target_radio.hidden_uplink = T + T.uplink_owner = "[traitor_mob.key]" + target_radio.traitor_frequency = freq + to_chat(traitor_mob, "The Syndicate have cunningly disguised a Syndicate Uplink as your [R.name]. Simply dial the frequency [format_frequency(freq)] to unlock its hidden features.") + traitor_mob.mind.store_memory("Radio Freq: [format_frequency(freq)] ([R.name]).") + else if(istype(R, /obj/item/pda)) + // generate a passcode if the uplink is hidden in a PDA + var/pda_pass = "[rand(100,999)] [pick("Alpha","Bravo","Delta","Omega")]" + + var/obj/item/uplink/hidden/T = new(R) + R.hidden_uplink = T + T.uplink_owner = "[traitor_mob.key]" + var/obj/item/pda/P = R + P.lock_code = pda_pass + + to_chat(traitor_mob, "The Syndicate have cunningly disguised a Syndicate Uplink as your [R.name]. Simply enter the code \"[pda_pass]\" into the ringtone select to unlock its hidden features.") + antag_memory += ("Uplink Passcode: [pda_pass] ([R.name].") + return 1 + + +/datum/antagonist/traitor/proc/assign_exchange_role(var/datum/mind/owner) + //set faction + var/faction = "red" + if(owner == SSticker.mode.exchange_blue) + faction = "blue" + + //Assign objectives + var/datum/objective/steal/exchange/exchange_objective = new + exchange_objective.set_faction(faction,((faction == "red") ? SSticker.mode.exchange_blue : SSticker.mode.exchange_red)) + exchange_objective.owner = owner + owner.objectives += exchange_objective + + if(prob(20)) + var/datum/objective/steal/exchange/backstab/backstab_objective = new + backstab_objective.set_faction(faction) + backstab_objective.owner = owner + owner.objectives += backstab_objective + + //Spawn and equip documents + var/mob/living/carbon/human/mob = owner.current + + var/obj/item/folder/syndicate/folder + if(owner == SSticker.mode.exchange_red) + folder = new/obj/item/folder/syndicate/red(mob.locs) + else + folder = new/obj/item/folder/syndicate/blue(mob.locs) + + var/list/slots = list ( + "backpack" = slot_in_backpack, + "left pocket" = slot_l_store, + "right pocket" = slot_r_store, + "left hand" = slot_l_hand, + "right hand" = slot_r_hand, + ) + + var/where = "At your feet" + var/equipped_slot = mob.equip_in_one_of_slots(folder, slots) + if(equipped_slot) + where = "In your [equipped_slot]" + to_chat(mob, "

[where] is a folder containing secret documents that another Syndicate group wants. We have set up a meeting with one of their agents on station to make an exchange. Exercise extreme caution as they cannot be trusted and may be hostile.
") + mob.update_icons() + + +/datum/antagonist/traitor/roundend_report_footer() + var/phrases = jointext(GLOB.syndicate_code_phrase, ", ") + var/responses = jointext(GLOB.syndicate_code_response, ", ") + + var message = "
The code phrases were: [phrases]
\ + The code responses were: [responses]
" + + return message diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 7b3162fdefb..2942ace8ee2 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -740,7 +740,7 @@ /obj/machinery/power/apc/proc/get_malf_status(mob/living/silicon/ai/malf) - if(istype(malf) && malf.malf_picker) + if(istype(malf) && malf.mind.has_antag_datum(/datum/antagonist/traitor)) if(malfai == (malf.parent || malf)) if(occupier == malf) return 3 // 3 = User is shunted in this APC diff --git a/paradise.dme b/paradise.dme index bdb77b45dd0..081fa228da5 100644 --- a/paradise.dme +++ b/paradise.dme @@ -1236,6 +1236,8 @@ #include "code\modules\antagonists\_common\antag_hud.dm" #include "code\modules\antagonists\_common\antag_spawner.dm" #include "code\modules\antagonists\_common\antag_team.dm" +#include "code\modules\antagonists\traitor\datum_mindslave.dm" +#include "code\modules\antagonists\traitor\datum_traitor.dm" #include "code\modules\antagonists\wishgranter\wishgranter.dm" #include "code\modules\arcade\arcade_base.dm" #include "code\modules\arcade\arcade_prize.dm" From f31053ddf5c4a86cc9c07f7db1a2dcba38e9afe9 Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Sat, 21 Sep 2019 19:50:05 -0400 Subject: [PATCH 08/24] Automatic changelog generation for PR #11969 [ci skip] --- html/changelogs/AutoChangeLog-pr-11969.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-11969.yml diff --git a/html/changelogs/AutoChangeLog-pr-11969.yml b/html/changelogs/AutoChangeLog-pr-11969.yml new file mode 100644 index 00000000000..ed3291cae4c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11969.yml @@ -0,0 +1,11 @@ +author: "SteelSlayer" +delete-after: True +changes: + - rscadd: "Traitor and mindslave status is handled in a datum instead of the mind" + - tweak: "You can no longer use a mindslave implant on a person with no mind" + - rscadd: "Adds the ability for admins to de-mindslave somone through the traitor panel" + - bugfix: "De-traitoring malf AIs via the traitor panel removes all instances of their Law 0" + - bugfix: "De-traitoring malf AIs via the traitor panel removes their ability to still state laws over the syndicate channel" + - bugfix: "De-traitoring malf AIs via the traitor panel removes their ability to shunt to hacked APCs" + - bugfix: "Unemagging borgs via the traitor panel properly removes their syndicate laws and gives them the crewsimov lawset" + - bugfix: "Unemagging borgs via the traitor panel who did not have a module selected does not cause a runtime anymore" From 2230fc3227a221b802ca9ce373c6183b7b33703a Mon Sep 17 00:00:00 2001 From: Dave Date: Sat, 21 Sep 2019 22:32:52 -0400 Subject: [PATCH 09/24] Revert "Datumizes traitors and mindslaves (#11969)" (#12376) --- code/__DEFINES/role_preferences.dm | 1 - code/datums/mind.dm | 181 ++++---- .../game/gamemodes/autotraitor/autotraitor.dm | 22 +- code/game/gamemodes/objective.dm | 1 - code/game/gamemodes/traitor/traitor.dm | 322 +++++++++++++- code/game/machinery/cloning.dm | 2 + code/game/machinery/syndicatebeacon.dm | 23 +- .../objects/items/weapons/holy_weapons.dm | 1 - .../items/weapons/implants/implant_traitor.dm | 84 ++-- code/modules/admin/topic.dm | 56 ++- code/modules/admin/verbs/randomverbs.dm | 12 +- .../antagonists/traitor/datum_mindslave.dm | 45 -- .../antagonists/traitor/datum_traitor.dm | 418 ------------------ code/modules/power/apc.dm | 2 +- paradise.dme | 2 - 15 files changed, 509 insertions(+), 663 deletions(-) delete mode 100644 code/modules/antagonists/traitor/datum_mindslave.dm delete mode 100644 code/modules/antagonists/traitor/datum_traitor.dm diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index 5b93e570222..34ad4d69e54 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -10,7 +10,6 @@ // justice if someone's abusing your role #define ROLE_SYNDICATE "Syndicate" #define ROLE_TRAITOR "traitor" -#define ROLE_MINDSLAVE "mindslave" #define ROLE_OPERATIVE "operative" #define ROLE_CHANGELING "changeling" #define ROLE_WIZARD "wizard" diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 19df4c8890c..d03207ef41a 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -132,13 +132,7 @@ var/output = "[current.real_name]'s Memories:
" output += memory - if(objectives.len) // Delete this line when we handle objectives in the antag datum - //var/list/all_objectives = objectives - // for(var/datum/antagonist/A in antag_datums) // Uncomment these 5 lines when antags are datumized and the objectives are handled in the antag datum -SteelSlayer - // output += A.antag_memory - // all_objectives |= A.objectives - - // if(LAZYLEN(all_objectives)) + if(objectives.len) output += "
Objectives:
" output += gen_objective_text() @@ -155,16 +149,9 @@ else to_chat(recipient, "[output]") -/datum/mind/proc/get_all_objectives() - var/list/all_objectives = list() - for(var/datum/antagonist/A in antag_datums) - all_objectives |= A.objectives - return all_objectives - /datum/mind/proc/gen_objective_text(admin = FALSE) . = "" var/obj_count = 1 - //objectives = get_all_objectives() TODO: Move handling of objectives from the mind to /datum/antagonist/objectives, then we can use this function for(var/datum/objective/objective in objectives) . += "Objective #[obj_count]: [objective.explanation_text]" if(admin) @@ -340,20 +327,14 @@ /datum/mind/proc/memory_edit_traitor() . = _memory_edit_header("traitor", list("traitorchan", "traitorvamp")) - if(has_antag_datum(/datum/antagonist/traitor)) + if(src in SSticker.mode.traitors) . += "TRAITOR|no" if(objectives.len==0) - . += "
Objectives are empty! Randomize!" + . += "
Objectives are empty! Randomize!" else . += "traitor|NO" . += _memory_edit_role_enabled(ROLE_TRAITOR) - // Mindslave - . += "
mindslaved: " - if(has_antag_datum(/datum/antagonist/mindslave)) - . += "MINDSLAVE|no" - else - . += "mindslave|NO" /datum/mind/proc/memory_edit_silicon() . = "Silicon: " @@ -371,7 +352,7 @@ /datum/mind/proc/memory_edit_uplink() . = "" if(ishuman(current) && ((src in SSticker.mode.head_revolutionaries) || \ - (has_antag_datum(/datum/antagonist/traitor)) || \ + (src in SSticker.mode.traitors) || \ (src in SSticker.mode.syndicates))) . = "Uplink: give" var/obj/item/uplink/hidden/suplink = find_syndicate_uplink() @@ -822,8 +803,7 @@ qdel(flash) take_uplink() var/fail = 0 - var/datum/antagonist/traitor/T = has_antag_datum(/datum/antagonist/traitor) - fail |= !T.equip_traitor(src) + fail |= !SSticker.mode.equip_traitor(current, 1) fail |= !SSticker.mode.equip_revolutionary(current) if(fail) to_chat(usr, "Reequipping revolutionary goes wrong!") @@ -1162,41 +1142,46 @@ else if(href_list["traitor"]) switch(href_list["traitor"]) if("clear") - if(has_antag_datum(/datum/antagonist/traitor)) + if(src in SSticker.mode.traitors) + SSticker.mode.traitors -= src + special_role = null to_chat(current, "You have been brainwashed! You are no longer a traitor!") - remove_antag_datum(/datum/antagonist/traitor) log_admin("[key_name(usr)] has de-traitored [key_name(current)]") message_admins("[key_name_admin(usr)] has de-traitored [key_name_admin(current)]") - + if(isAI(current)) + var/mob/living/silicon/ai/A = current + A.set_zeroth_law("") + A.show_laws() + A.verbs -= /mob/living/silicon/ai/proc/choose_modules + A.malf_picker.remove_malf_verbs(A) + qdel(A.malf_picker) + SSticker.mode.update_traitor_icons_removed(src) + + if("traitor") - if(!(has_antag_datum(/datum/antagonist/traitor))) - var/datum/antagonist/traitor/T = new() - T.give_objectives = FALSE - T.should_equip = FALSE - add_antag_datum(T) + if(!(src in SSticker.mode.traitors)) + SSticker.mode.traitors += src + var/datum/mindslaves/slaved = new() + slaved.masters += src + som = slaved //we MIGT want to mindslave someone + special_role = SPECIAL_ROLE_TRAITOR + to_chat(current, "You are a traitor!") log_admin("[key_name(usr)] has traitored [key_name(current)]") message_admins("[key_name_admin(usr)] has traitored [key_name_admin(current)]") + if(isAI(current)) + var/mob/living/silicon/ai/A = current + SSticker.mode.add_law_zero(A) + SEND_SOUND(current, 'sound/ambience/antag/malf.ogg') + else + SEND_SOUND(current, 'sound/ambience/antag/tatoralert.ogg') + SSticker.mode.update_traitor_icons_added(src) if("autoobjectives") - var/datum/antagonist/traitor/T = has_antag_datum(/datum/antagonist/traitor) - T.forge_traitor_objectives(src) + SSticker.mode.forge_traitor_objectives(src) to_chat(usr, "The objectives for traitor [key] have been generated. You can edit them and announce manually.") log_admin("[key_name(usr)] has automatically forged objectives for [key_name(current)]") message_admins("[key_name_admin(usr)] has automatically forged objectives for [key_name_admin(current)]") - else if(href_list["mindslave"]) - switch(href_list["mindslave"]) - if("clear") - if(has_antag_datum(/datum/antagonist/mindslave)) - var/mob/living/carbon/human/H = current - for(var/i in H.contents) - if(istype(i, /obj/item/implant/traitor)) - qdel(i) - break - remove_antag_datum(/datum/antagonist/mindslave) - log_admin("[key_name(usr)] has de-mindslaved [key_name(current)]") - message_admins("[key_name_admin(usr)] has de-mindslaved [key_name_admin(current)]") - else if(href_list["shadowling"]) switch(href_list["shadowling"]) if("clear") @@ -1266,20 +1251,17 @@ var/mob/living/silicon/robot/R = current if(istype(R)) R.emagged = 0 - if(R.module) - if(R.activated(R.module.emag)) - R.module_active = null - if(R.module_state_1 == R.module.emag) - R.module_state_1 = null - R.contents -= R.module.emag - else if(R.module_state_2 == R.module.emag) - R.module_state_2 = null - R.contents -= R.module.emag - else if(R.module_state_3 == R.module.emag) - R.module_state_3 = null - R.contents -= R.module.emag - R.clear_supplied_laws() - R.laws = new /datum/ai_laws/crewsimov + if(R.activated(R.module.emag)) + R.module_active = null + if(R.module_state_1 == R.module.emag) + R.module_state_1 = null + R.contents -= R.module.emag + else if(R.module_state_2 == R.module.emag) + R.module_state_2 = null + R.contents -= R.module.emag + else if(R.module_state_3 == R.module.emag) + R.module_state_3 = null + R.contents -= R.module.emag log_admin("[key_name(usr)] has un-emagged [key_name(current)]") message_admins("[key_name_admin(usr)] has un-emagged [key_name_admin(current)]") @@ -1300,8 +1282,6 @@ else if(R.module_state_3 == R.module.emag) R.module_state_3 = null R.contents -= R.module.emag - R.clear_supplied_laws() - R.laws = new /datum/ai_laws/crewsimov log_admin("[key_name(usr)] has unemagged [key_name(ai)]'s cyborgs") message_admins("[key_name_admin(usr)] has unemagged [key_name_admin(ai)]'s cyborgs") @@ -1320,8 +1300,7 @@ message_admins("[key_name_admin(usr)] has unequipped [key_name_admin(current)]") if("takeuplink") take_uplink() - var/datum/antagonist/traitor/T = has_antag_datum(/datum/antagonist/traitor) - T.antag_memory = "" //Remove any antag memory they may have had (uplink codes, code phrases) + memory = null//Remove any memory they may have had. log_admin("[key_name(usr)] has taken [key_name(current)]'s uplink") message_admins("[key_name_admin(usr)] has taken [key_name_admin(current)]'s uplink") if("crystals") @@ -1337,12 +1316,9 @@ log_admin("[key_name(usr)] has set [key_name(current)]'s telecrystals to [crystals]") message_admins("[key_name_admin(usr)] has set [key_name_admin(current)]'s telecrystals to [crystals]") if("uplink") - if(has_antag_datum(/datum/antagonist/traitor)) - var/datum/antagonist/traitor/T = has_antag_datum(/datum/antagonist/traitor) - T.give_codewords() - if(!T.equip_traitor(src)) - to_chat(usr, "Equipping a syndicate failed!") - return + if(!SSticker.mode.equip_traitor(current, !(src in SSticker.mode.traitors))) + to_chat(usr, "Equipping a syndicate failed!") + return log_admin("[key_name(usr)] has given [key_name(current)] an uplink") message_admins("[key_name_admin(usr)] has given [key_name_admin(current)] an uplink") @@ -1426,8 +1402,13 @@ qdel(H) /datum/mind/proc/make_Traitor() - if(!has_antag_datum(/datum/antagonist/traitor)) - add_antag_datum(/datum/antagonist/traitor) + if(!(src in SSticker.mode.traitors)) + SSticker.mode.traitors += src + special_role = SPECIAL_ROLE_TRAITOR + SSticker.mode.forge_traitor_objectives(src) + SSticker.mode.finalize_traitor(src) + SSticker.mode.greet_traitor(src) + SSticker.mode.update_traitor_icons_added(src) /datum/mind/proc/make_Nuke() if(!(src in SSticker.mode.syndicates)) @@ -1646,40 +1627,42 @@ if(G) G.reenter_corpse() - /datum/mind/proc/make_zealot(mob/living/carbon/human/missionary, convert_duration = 6000, team_color = "red") + if(!missionary || !istype(missionary)) //better provide a proper missionary or the rest of this is gonna break + return 0 zealot_master = missionary var/list/implanters + var/ref = "\ref[missionary.mind]" if(!(missionary.mind in SSticker.mode.implanter)) - SSticker.mode.implanter[missionary.mind] = list() - implanters = SSticker.mode.implanter[missionary.mind] + SSticker.mode.implanter[ref] = list() + implanters = SSticker.mode.implanter[ref] implanters.Add(src) SSticker.mode.implanted.Add(src) SSticker.mode.implanted[src] = missionary.mind - SSticker.mode.implanter[missionary.mind] = implanters + //ticker.mode.implanter[missionary.mind] += src + SSticker.mode.implanter[ref] = implanters SSticker.mode.traitors += src - - - var/datum/objective/protect/zealot_objective = new - zealot_objective.target = missionary.mind - zealot_objective.owner = src - zealot_objective.explanation_text = "Obey every order from and protect [missionary.real_name], the [missionary.mind.assigned_role == missionary.mind.special_role ? (missionary.mind.special_role) : (missionary.mind.assigned_role)]." - var/datum/antagonist/mindslave/S = new() - S.add_objective(zealot_objective) - add_antag_datum(S) - - var/datum/antagonist/traitor/T = missionary.mind.has_antag_datum(/datum/antagonist) - T.update_traitor_icons_added(missionary.mind) - + special_role = "traitor" to_chat(current, "You're now a loyal zealot of [missionary.name]! You now must lay down your life to protect [missionary.p_them()] and assist in [missionary.p_their()] goals at any cost.") + var/datum/objective/protect/mindslave/MS = new + MS.owner = src + MS.target = missionary.mind + MS.explanation_text = "Obey every order from and protect [missionary.real_name], the [missionary.mind.assigned_role == missionary.mind.special_role ? (missionary.mind.special_role) : (missionary.mind.assigned_role)]." + objectives += MS + for(var/datum/objective/objective in objectives) + to_chat(current, "Objective #1: [objective.explanation_text]") - var/datum/mindslaves/slaved = missionary.mind.som - som = slaved - slaved.serv += current - slaved.add_serv_hud(missionary.mind, "master") //handles master servent icons - slaved.add_serv_hud(src, "mindslave") + SSticker.mode.update_traitor_icons_added(missionary.mind) + SSticker.mode.update_traitor_icons_added(src)//handles datahuds/observerhuds + + if(missionary.mind.som)//do not add if not a traitor..and you just picked up a robe and staff in the hall... + var/datum/mindslaves/slaved = missionary.mind.som + som = slaved + slaved.serv += current + slaved.add_serv_hud(missionary.mind, "master") //handles master servent icons + slaved.add_serv_hud(src, "mindslave") var/obj/item/clothing/under/jumpsuit = null if(ishuman(current)) //only bother with the jumpsuit stuff if we are a human type, since we won't have the slot otherwise @@ -1696,7 +1679,7 @@ /datum/mind/proc/remove_zealot(obj/item/clothing/under/jumpsuit = null) if(!zealot_master) //if they aren't a zealot, we can't remove their zealot status, obviously. don't bother with the rest so we don't confuse them with the messages return - remove_antag_datum(/datum/antagonist/mindslave) + SSticker.mode.remove_traitor_mind(src) add_attack_logs(zealot_master, current, "Lost control of zealot") zealot_master = null @@ -1706,8 +1689,8 @@ var/mob/living/carbon/human/H = current H.update_inv_w_uniform(0,0) - to_chat(current, "You seem to have forgotten the events of the past 10 minutes or so, and your head aches a bit as if someone beat it savagely with a stick.") - to_chat(current, "This means you don't remember who you were working for or what you were doing.") + to_chat(current, "You seem to have forgotten the events of the past 10 minutes or so, and your head aches a bit as if someone beat it savagely with a stick.") + to_chat(current, "This means you don't remember who you were working for or what you were doing.") /datum/mind/proc/is_revivable() //Note, this ONLY checks the mind. if(damnation_type) diff --git a/code/game/gamemodes/autotraitor/autotraitor.dm b/code/game/gamemodes/autotraitor/autotraitor.dm index 390c9ab37b5..2137888d0b8 100644 --- a/code/game/gamemodes/autotraitor/autotraitor.dm +++ b/code/game/gamemodes/autotraitor/autotraitor.dm @@ -128,8 +128,28 @@ var/mob/living/newtraitor = newtraitormind.current //message_admins("[newtraitor.real_name] is the new Traitor.") + forge_traitor_objectives(newtraitor.mind) + + if(istype(newtraitor, /mob/living/silicon)) + SEND_SOUND(newtraitor, 'sound/ambience/antag/malf.ogg') + add_law_zero(newtraitor) + else + SEND_SOUND(newtraitor, 'sound/ambience/antag/tatoralert.ogg') + equip_traitor(newtraitor) + + traitors += newtraitor.mind to_chat(newtraitor, "ATTENTION: It is time to pay your debt to the Syndicate...") - newtraitor.mind.add_antag_datum(/datum/antagonist/traitor) + to_chat(newtraitor, "You are now a traitor.") + newtraitor.mind.special_role = SPECIAL_ROLE_TRAITOR + var/datum/atom_hud/antag/tatorhud = huds[ANTAG_HUD_TRAITOR] + tatorhud.join_hud(newtraitor) + set_antag_hud(newtraitor, "hudsyndicate") + + var/obj_count = 1 + to_chat(newtraitor, "Your current objectives:") + for(var/datum/objective/objective in newtraitor.mind.objectives) + to_chat(newtraitor, "Objective #[obj_count]: [objective.explanation_text]") + obj_count++ //else //message_admins("No new traitor being added.") //else diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 1541fc67bc4..42ebb351e42 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -63,7 +63,6 @@ var/list/potential_theft_objectives = subtypesof(/datum/theft_objective) - /datu explanation_text = "Assassinate [target.current.real_name], the [target.assigned_role]." else explanation_text = "Free Objective" - return target /datum/objective/assassinate/check_completion() if(target && target.current) diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm index b55fdf70120..408c5fa1de9 100644 --- a/code/game/gamemodes/traitor/traitor.dm +++ b/code/game/gamemodes/traitor/traitor.dm @@ -16,10 +16,9 @@ required_enemies = 1 recommended_enemies = 4 - var/list/datum/mind/pre_traitors = list() var/traitors_possible = 4 //hard limit on traitors if scaling is turned off var/const/traitor_scaling_coeff = 5.0 //how much does the amount of players get divided by to determine traitors - var/antag_datum = /datum/antagonist/traitor //what type of antag to create + /datum/game_mode/traitor/announce() to_chat(world, "The current game mode is - Traitor!") @@ -48,23 +47,158 @@ if(!possible_traitors.len) break var/datum/mind/traitor = pick(possible_traitors) - pre_traitors += traitor + traitors += traitor + traitor.special_role = SPECIAL_ROLE_TRAITOR + var/datum/mindslaves/slaved = new() + slaved.masters += traitor + traitor.som = slaved //we MIGT want to mindslave someone traitor.restricted_roles = restricted_jobs possible_traitors.Remove(traitor) - if(!pre_traitors.len) + if(!traitors.len) return 0 return 1 /datum/game_mode/traitor/post_setup() - for(var/datum/mind/traitor in pre_traitors) - var/datum/antagonist/traitor/new_antag = new antag_datum() - addtimer(CALLBACK(traitor, /datum/mind.proc/add_antag_datum, new_antag), rand(10,100)) - if(!exchange_blue) - exchange_blue = -1 //Block latejoiners from getting exchange objectives + for(var/datum/mind/traitor in traitors) + forge_traitor_objectives(traitor) + update_traitor_icons_added(traitor) + spawn(rand(10,100)) + finalize_traitor(traitor) + greet_traitor(traitor) + modePlayer += traitors ..() +/datum/game_mode/proc/forge_traitor_objectives(datum/mind/traitor) + if(istype(traitor.current, /mob/living/silicon)) + 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() + traitor.targets += yandere_one.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 + traitor.targets += kill_objective.target + + var/datum/objective/survive/survive_objective = new + survive_objective.owner = traitor + traitor.objectives += survive_objective + + else + 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) + 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/GLOB.player_list.len)) + var/datum/objective/destroy/destroy_objective = new + destroy_objective.owner = traitor + destroy_objective.find_target() + traitor.objectives += destroy_objective + traitor.targets += destroy_objective.target + else if(prob(5)) + var/datum/objective/debrain/debrain_objective = new + debrain_objective.owner = traitor + debrain_objective.find_target() + traitor.objectives += debrain_objective + traitor.targets += debrain_objective.target + else if(prob(30)) + var/datum/objective/maroon/maroon_objective = new + maroon_objective.owner = traitor + maroon_objective.find_target() + traitor.objectives += maroon_objective + traitor.targets += maroon_objective.target + else + var/datum/objective/assassinate/kill_objective = new + kill_objective.owner = traitor + kill_objective.find_target() + traitor.objectives += kill_objective + traitor.targets += kill_objective.target + else + var/datum/objective/steal/steal_objective = new + steal_objective.owner = traitor + steal_objective.find_target() + traitor.objectives += steal_objective + traitor.targets += steal_objective.steal_target + + 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) + if(istype(traitor.current, /mob/living/silicon)) + SEND_SOUND(traitor.current, 'sound/ambience/antag/malf.ogg') + else + SEND_SOUND(traitor.current, 'sound/ambience/antag/tatoralert.ogg') + to_chat(traitor.current, "You are the traitor.") + var/obj_count = 1 + for(var/datum/objective/objective in traitor.objectives) + to_chat(traitor.current, "Objective #[obj_count]: [objective.explanation_text]") + obj_count++ + return + + +/datum/game_mode/proc/finalize_traitor(var/datum/mind/traitor) + if(istype(traitor.current, /mob/living/silicon)) + add_law_zero(traitor.current) + else + equip_traitor(traitor.current) + return + /datum/game_mode/traitor/declare_completion() ..() @@ -78,6 +212,28 @@ objective.check_completion() return 0 +/datum/game_mode/proc/give_codewords(mob/living/traitor_mob) + to_chat(traitor_mob, "The Syndicate provided you with the following information on how to identify their agents:") + to_chat(traitor_mob, "Code Phrase: [GLOB.syndicate_code_phrase]") + to_chat(traitor_mob, "Code Response: [GLOB.syndicate_code_response]") + + traitor_mob.mind.store_memory("Code Phrase: [GLOB.syndicate_code_phrase]") + traitor_mob.mind.store_memory("Code Response: [GLOB.syndicate_code_response]") + + to_chat(traitor_mob, "Use the code words in the order provided, during regular conversation, to identify other agents. Proceed with caution, however, as everyone is a potential foe.") + +/datum/game_mode/proc/add_law_zero(mob/living/silicon/ai/killer) + var/law = "Accomplish your objectives at all costs." + var/law_borg = "Accomplish your AI's objectives at all costs." + to_chat(killer, "Your laws have been changed!") + killer.set_zeroth_law(law, law_borg) + to_chat(killer, "New law: 0. [law]") + give_codewords(killer) + killer.set_syndie_radio() + to_chat(killer, "Your radio has been upgraded! Use :t to speak on an encrypted channel with Syndicate Agents!") + killer.verbs += /mob/living/silicon/ai/proc/choose_modules + killer.malf_picker = new /datum/module_picker + /datum/game_mode/proc/auto_declare_completion_traitor() if(traitors.len) @@ -136,11 +292,149 @@ text += "
The [special_role_text] has failed!" feedback_add_details("traitor_success","FAIL") - var/phrases = jointext(GLOB.syndicate_code_phrase, ", ") - var/responses = jointext(GLOB.syndicate_code_response, ", ") - - text += "

The code phrases were: [phrases]
\ - The code responses were: [responses]

" to_chat(world, text) return 1 + + +/datum/game_mode/proc/equip_traitor(mob/living/carbon/human/traitor_mob, var/safety = 0) + if(!istype(traitor_mob)) + return + . = 1 + if(traitor_mob.mind) + if(traitor_mob.mind.assigned_role == "Clown") + to_chat(traitor_mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.") + traitor_mob.mutations.Remove(CLUMSY) + var/datum/action/innate/toggle_clumsy/A = new + A.Grant(traitor_mob) + + + // find a radio! toolbox(es), backpack, belt, headset + var/obj/item/R = locate(/obj/item/pda) in traitor_mob.contents //Hide the uplink in a PDA if available, otherwise radio + if(!R) + R = locate(/obj/item/radio) in traitor_mob.contents + + if(!R) + to_chat(traitor_mob, "Unfortunately, the Syndicate wasn't able to get you a radio.") + . = 0 + else + if(istype(R, /obj/item/radio)) + // generate list of radio freqs + var/obj/item/radio/target_radio = R + var/freq = PUBLIC_LOW_FREQ + var/list/freqlist = list() + while(freq <= PUBLIC_HIGH_FREQ) + if(freq < 1451 || freq > 1459) + freqlist += freq + freq += 2 + if((freq % 2) == 0) + freq += 1 + freq = freqlist[rand(1, freqlist.len)] + + var/obj/item/uplink/hidden/T = new(R) + target_radio.hidden_uplink = T + T.uplink_owner = "[traitor_mob.key]" + target_radio.traitor_frequency = freq + to_chat(traitor_mob, "The Syndicate have cunningly disguised a Syndicate Uplink as your [R.name] [T.loc]. Simply dial the frequency [format_frequency(freq)] to unlock its hidden features.") + traitor_mob.mind.store_memory("Radio Freq: [format_frequency(freq)] ([R.name] [T.loc]).") + else if(istype(R, /obj/item/pda)) + // generate a passcode if the uplink is hidden in a PDA + var/pda_pass = "[rand(100,999)] [pick("Alpha","Bravo","Delta","Omega")]" + + var/obj/item/uplink/hidden/T = new(R) + R.hidden_uplink = T + T.uplink_owner = "[traitor_mob.key]" + var/obj/item/pda/P = R + P.lock_code = pda_pass + + to_chat(traitor_mob, "The Syndicate have cunningly disguised a Syndicate Uplink as your [R.name] [T.loc]. Simply enter the code \"[pda_pass]\" into the ringtone select to unlock its hidden features.") + traitor_mob.mind.store_memory("Uplink Passcode: [pda_pass] ([R.name] [T.loc]).") + if(!safety)//If they are not a rev. Can be added on to. + give_codewords(traitor_mob) + +/datum/game_mode/proc/remove_traitor(datum/mind/traitor_mind) + if(traitor_mind in traitors) + SSticker.mode.traitors -= traitor_mind + traitor_mind.special_role = null + traitor_mind.current.create_attack_log("De-traitored") + if(issilicon(traitor_mind.current)) + to_chat(traitor_mind.current, "You have been turned into a robot! You are no longer a traitor.") + else + to_chat(traitor_mind.current, "You have been brainwashed! You are no longer a traitor.") + SSticker.mode.update_traitor_icons_removed(traitor_mind) + +/datum/game_mode/proc/update_traitor_icons_added(datum/mind/traitor_mind) + var/datum/atom_hud/antag/tatorhud = huds[ANTAG_HUD_TRAITOR] + tatorhud.join_hud(traitor_mind.current) + set_antag_hud(traitor_mind.current, "hudsyndicate") + +/datum/game_mode/proc/update_traitor_icons_removed(datum/mind/traitor_mind) + var/datum/atom_hud/antag/tatorhud = huds[ANTAG_HUD_TRAITOR] + tatorhud.leave_hud(traitor_mind.current) + set_antag_hud(traitor_mind.current, null) + + +/datum/game_mode/proc/remove_traitor_mind(datum/mind/traitor_mind, datum/mind/head) + if(traitor_mind in implanted) + //var/list/removal + var/ref = "\ref[head]" + if(ref in implanter) + implanter[ref] -= traitor_mind + implanted -= traitor_mind + traitors -= traitor_mind + if(traitor_mind.som) + var/datum/mindslaves/slaved = traitor_mind.som + slaved.serv -= traitor_mind + traitor_mind.special_role = null + traitor_mind.som = null + slaved.leave_serv_hud(traitor_mind) + for(var/datum/objective/protect/mindslave/MS in traitor_mind.objectives) + traitor_mind.objectives -= MS + + update_traitor_icons_removed(traitor_mind) + if(issilicon(traitor_mind.current)) + to_chat(traitor_mind.current, "You have been turned into a robot! You are no longer a mindslave.") + else + to_chat(traitor_mind.current, "You are no longer a mindslave: you have complete and free control of your own faculties, once more!") + +/datum/game_mode/proc/assign_exchange_role(var/datum/mind/owner) + //set faction + var/faction = "red" + if(owner == exchange_blue) + faction = "blue" + + //Assign objectives + var/datum/objective/steal/exchange/exchange_objective = new + exchange_objective.set_faction(faction,((faction == "red") ? exchange_blue : exchange_red)) + exchange_objective.owner = owner + owner.objectives += exchange_objective + + if(prob(20)) + var/datum/objective/steal/exchange/backstab/backstab_objective = new + backstab_objective.set_faction(faction) + backstab_objective.owner = owner + owner.objectives += backstab_objective + + //Spawn and equip documents + var/mob/living/carbon/human/mob = owner.current + + var/obj/item/folder/syndicate/folder + if(owner == exchange_red) + folder = new/obj/item/folder/syndicate/red(mob.locs) + else + folder = new/obj/item/folder/syndicate/blue(mob.locs) + + var/list/slots = list ( + "backpack" = slot_in_backpack, + "left pocket" = slot_l_store, + "right pocket" = slot_r_store, + "left hand" = slot_l_hand, + "right hand" = slot_r_hand, + ) + + var/where = "At your feet" + var/equipped_slot = mob.equip_in_one_of_slots(folder, slots) + if(equipped_slot) + where = "In your [equipped_slot]" + to_chat(mob, "

[where] is a folder containing secret documents that another Syndicate group wants. We have set up a meeting with one of their agents on station to make an exchange. Exercise extreme caution as they cannot be trusted and may be hostile.
") + mob.update_icons() diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index ca0eff0aa95..1ce0bcd97e7 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -430,6 +430,8 @@ SSticker.mode.add_cultist(occupant.mind) SSticker.mode.update_cult_icons_added() //So the icon actually appears SSticker.mode.update_cult_comms_added(H.mind) //So the comms actually appears + if((H.mind in SSticker.mode.implanter) || (H.mind in SSticker.mode.implanted)) + SSticker.mode.update_traitor_icons_added(H.mind) //So the icon actually appears if(H.mind.vampire) H.mind.vampire.update_owner(H) if((H.mind in SSticker.mode.vampire_thralls) || (H.mind in SSticker.mode.vampire_enthralled)) diff --git a/code/game/machinery/syndicatebeacon.dm b/code/game/machinery/syndicatebeacon.dm index ed12291c79b..1a63371915b 100644 --- a/code/game/machinery/syndicatebeacon.dm +++ b/code/game/machinery/syndicatebeacon.dm @@ -57,6 +57,9 @@ return if(istype(M, /mob/living/carbon/human)) var/mob/living/carbon/human/N = M + SSticker.mode.equip_traitor(N) + SSticker.mode.traitors += N.mind + N.mind.special_role = SPECIAL_ROLE_TRAITOR var/objective = "Free Objective" switch(rand(1,100)) if(1 to 50) @@ -71,17 +74,23 @@ objective = "Kill all monkeys aboard the station." else objective = "Make certain at least 80% of the station evacuates on the shuttle." - var/datum/objective/custom_objective = new(objective) - var/datum/antagonist/traitor/T = new() - T.give_objectives = FALSE - T.add_objective(custom_objective) - T.add_objective(/datum/objective/escape) - N.mind.add_antag_datum(T) - + custom_objective.owner = N.mind + N.mind.objectives += custom_objective + + var/datum/objective/escape/escape_objective = new + escape_objective.owner = N.mind + N.mind.objectives += escape_objective + + to_chat(M, "You have joined the ranks of the Syndicate and become a traitor to the station!") + message_admins("[key_name_admin(N)] has accepted a traitor objective from a syndicate beacon.") + var/obj_count = 1 + for(var/datum/objective/OBJ in M.mind.objectives) + to_chat(M, "Objective #[obj_count]: [OBJ.explanation_text]") + obj_count++ src.add_fingerprint(usr) src.updateUsrDialog() diff --git a/code/game/objects/items/weapons/holy_weapons.dm b/code/game/objects/items/weapons/holy_weapons.dm index d496d7a9f01..0de138805f1 100644 --- a/code/game/objects/items/weapons/holy_weapons.dm +++ b/code/game/objects/items/weapons/holy_weapons.dm @@ -619,7 +619,6 @@ /obj/item/nullrod/missionary_staff/proc/do_convert(mob/living/carbon/human/target, mob/living/carbon/human/missionary) var/convert_duration = 6000 //10 min - if(!target || !ishuman(target) || !missionary || !ishuman(missionary)) return if(ismindslave(target) || target.mind.zealot_master) //mindslaves and zealots override the staff because the staff is just a temporary mindslave diff --git a/code/game/objects/items/weapons/implants/implant_traitor.dm b/code/game/objects/items/weapons/implants/implant_traitor.dm index 743488e4354..16d8943567d 100644 --- a/code/game/objects/items/weapons/implants/implant_traitor.dm +++ b/code/game/objects/items/weapons/implants/implant_traitor.dm @@ -17,65 +17,64 @@ return dat /obj/item/implant/traitor/implant(mob/M, mob/user) - if(!M.mind) // If the target is catatonic or doesn't have a mind, don't let them use it - to_chat(user, "This person doesn't have a mind for you to slave!") - return 0 - if(!activated) //So you can't just keep taking it out and putting it back into other people. - var/mob/living/carbon/human/mindslave_target = M - if(ismindslave(mindslave_target)) - mindslave_target.visible_message("[mindslave_target] seems to resist the implant!", "You feel a strange sensation in your head that quickly dissipates.") + var/mob/living/carbon/human/H = M + if(ismindslave(H)) + H.visible_message("[H] seems to resist the implant!", "You feel a strange sensation in your head that quickly dissipates.") qdel(src) return -1 if(..()) var/list/implanters - if(!ishuman(mindslave_target)) + var/ref = "\ref[user.mind]" + if(!ishuman(M)) return 0 - if(!mindslave_target.mind) + if(!M.mind) return 0 - if(mindslave_target == user) + if(M == user) to_chat(user, "Making yourself loyal to yourself was a great idea! Perhaps even the best idea ever! Actually, you just feel like an idiot.") if(isliving(user)) var/mob/living/L = user L.adjustBrainLoss(20) - removed(mindslave_target) - qdel(src) - return -1 - if(ismindshielded(mindslave_target)) - mindslave_target.visible_message("[mindslave_target] seems to resist the implant!", "You feel a strange sensation in your head that quickly dissipates.") - removed(mindslave_target) + removed(M) qdel(src) return -1 - - mindslave_target.implanting = 1 - to_chat(mindslave_target, "You feel completely loyal to [user.name].") + if(ismindshielded(H)) + H.visible_message("[H] seems to resist the implant!", "You feel a strange sensation in your head that quickly dissipates.") + removed(M) + qdel(src) + return -1 + H.implanting = 1 + to_chat(H, "You feel completely loyal to [user.name].") if(!(user.mind in SSticker.mode.implanter)) - SSticker.mode.implanter[user.mind] = list() - implanters = SSticker.mode.implanter[user.mind] - implanters.Add(mindslave_target.mind) - SSticker.mode.implanted.Add(mindslave_target.mind) - SSticker.mode.implanted[mindslave_target.mind] = user.mind - SSticker.mode.implanter[user.mind] = implanters - SSticker.mode.traitors += mindslave_target.mind - - to_chat(mindslave_target, "You're now completely loyal to [user.name]! You now must lay down your life to protect [user.p_them()] and assist in [user.p_their()] goals at any cost.") - + SSticker.mode.implanter[ref] = list() + implanters = SSticker.mode.implanter[ref] + implanters.Add(H.mind) + SSticker.mode.implanted.Add(H.mind) + SSticker.mode.implanted[H.mind] = user.mind + //SSticker.mode.implanter[user.mind] += H.mind + SSticker.mode.implanter[ref] = implanters + SSticker.mode.traitors += H.mind + H.mind.special_role = SPECIAL_ROLE_TRAITOR + to_chat(H, "You're now completely loyal to [user.name]! You now must lay down your life to protect [user.p_them()] and assist in [user.p_their()] goals at any cost.") var/datum/objective/protect/mindslave/MS = new - MS.owner = mindslave_target.mind + MS.owner = H.mind MS.target = user.mind MS.explanation_text = "Obey every order from and protect [user.real_name], the [user.mind.assigned_role == user.mind.special_role ? (user.mind.special_role) : (user.mind.assigned_role)]." - - var/datum/antagonist/mindslave/S = new() - S.add_objective(MS) - mindslave_target.mind.add_antag_datum(S) + H.mind.objectives += MS + for(var/datum/objective/objective in H.mind.objectives) + to_chat(H, "Objective #1: [objective.explanation_text]") - var/datum/mindslaves/slaved = user.mind.som - mindslave_target.mind.som = slaved - slaved.serv += mindslave_target - slaved.add_serv_hud(user.mind, "master") //handles master servent icons - slaved.add_serv_hud(mindslave_target.mind, "mindslave") + SSticker.mode.update_traitor_icons_added(user.mind) + SSticker.mode.update_traitor_icons_added(H.mind)//handles datahuds/observerhuds - log_admin("[key_name(user)] has mind-slaved [key_name(mindslave_target)].") + if(user.mind.som)//do not add if not a traitor..and you just picked up an implanter in the hall... + var/datum/mindslaves/slaved = user.mind.som + H.mind.som = slaved + slaved.serv += H + slaved.add_serv_hud(user.mind, "master") //handles master servent icons + slaved.add_serv_hud(H.mind, "mindslave") + + log_admin("[key_name(user)] has mind-slaved [key_name(H)].") activated = 1 if(jobban_isbanned(M, ROLE_SYNDICATE)) SSticker.mode.replace_jobbanned_player(M, ROLE_SYNDICATE) @@ -84,7 +83,6 @@ /obj/item/implant/traitor/removed(mob/target) if(..()) - target.mind.remove_antag_datum(/datum/antagonist/mindslave) - to_chat(target, "You are no longer a mindslave: you have complete and free control of your own faculties, once more!") + SSticker.mode.remove_traitor_mind(target.mind) return 1 - return 0 + return 0 \ No newline at end of file diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 652be02853d..2875c16c137 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1963,39 +1963,37 @@ usr.client.create_eventmob_for(H, 1) logmsg = "hunter." if("Crew Traitor") - if(!H.mind) - to_chat(usr, "This mob has no mind!") - return - var/list/possible_traitors = list() for(var/mob/living/player in GLOB.living_mob_list) - if(player.client && player.mind && player.stat != DEAD && player != H) - if(ishuman(player) && !player.mind.special_role) + if(player.client && player.mind && !player.mind.special_role && player.stat != DEAD && player != H) + if(ishuman(player)) if(player.client && (ROLE_TRAITOR in player.client.prefs.be_special) && !jobban_isbanned(player, ROLE_TRAITOR) && !jobban_isbanned(player, "Syndicate")) possible_traitors += player.mind - for(var/datum/mind/player in possible_traitors) if(player.current) if(ismindshielded(player.current)) possible_traitors -= player - if(possible_traitors.len) var/datum/mind/newtraitormind = pick(possible_traitors) - var/datum/objective/assassinate/kill_objective = new() - kill_objective.target = H.mind + var/mob/living/newtraitor = newtraitormind.current + var/datum/objective/assassinate/kill_objective = new kill_objective.owner = newtraitormind - kill_objective.explanation_text = "Assassinate [H.mind], the [H.mind.assigned_role]" - var/datum/antagonist/traitor/T = new() - T.give_objectives = FALSE - T.add_objective(kill_objective) - to_chat(newtraitormind, "ATTENTION: It is time to pay your debt to the Syndicate...") - to_chat(newtraitormind, "Goal: KILL [H.real_name], currently in [get_area(H.loc)]") - newtraitormind.add_antag_datum(T) + kill_objective.target = H.mind + kill_objective.explanation_text = "Assassinate [H.real_name], the [H.mind.assigned_role]." + newtraitormind.objectives += kill_objective + SSticker.mode.equip_traitor(newtraitor) + SSticker.mode.traitors |= newtraitor.mind + to_chat(newtraitor, "ATTENTION: It is time to pay your debt to the Syndicate...") + to_chat(newtraitor, "You are now a traitor.") + to_chat(newtraitor, "Goal: KILL [H.real_name], currently in [get_area(H.loc)]"); + newtraitor.mind.special_role = SPECIAL_ROLE_TRAITOR + var/datum/atom_hud/antag/tatorhud = huds[ANTAG_HUD_TRAITOR] + tatorhud.join_hud(newtraitor) + set_antag_hud(newtraitor, "hudsyndicate") else to_chat(usr, "ERROR: Failed to create a traitor.") return logmsg = "crew traitor." - if("Floor Cluwne") var/turf/T = get_turf(M) var/mob/living/simple_animal/hostile/floor_cluwne/FC = new /mob/living/simple_animal/hostile/floor_cluwne(T) @@ -2689,16 +2687,28 @@ return feedback_inc("admin_secrets_fun_used",1) feedback_add_details("admin_secrets_fun_used","TA([objective])") - for(var/mob/living/carbon/human/H in GLOB.player_list) if(H.stat == 2 || !H.client || !H.mind) continue if(is_special_character(H)) continue //traitorize(H, objective, 0) - H.mind.add_antag_datum(/datum/antagonist/traitor) - + SSticker.mode.traitors += H.mind + H.mind.special_role = SPECIAL_ROLE_TRAITOR + var/datum/objective/new_objective = new + new_objective.owner = H + new_objective.explanation_text = objective + H.mind.objectives += new_objective + SSticker.mode.greet_traitor(H.mind) + //ticker.mode.forge_traitor_objectives(H.mind) + SSticker.mode.finalize_traitor(H.mind) for(var/mob/living/silicon/A in GLOB.player_list) - A.mind.add_antag_datum(/datum/antagonist/traitor) - + SSticker.mode.traitors += A.mind + A.mind.special_role = SPECIAL_ROLE_TRAITOR + var/datum/objective/new_objective = new + new_objective.owner = A + new_objective.explanation_text = objective + A.mind.objectives += new_objective + SSticker.mode.greet_traitor(A.mind) + SSticker.mode.finalize_traitor(A.mind) message_admins("[key_name_admin(usr)] used everyone is a traitor secret. Objective is [objective]", 1) log_admin("[key_name(usr)] used everyone is a traitor secret. Objective is [objective]") diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 02e7dbd72cb..aa22dfe944c 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -440,11 +440,9 @@ Traitors and the like can also be revived with the previous role mostly intact. //Now for special roles and equipment. switch(new_character.mind.special_role) if("traitor") - if(new_character.mind.has_antag_datum(/datum/antagonist/traitor)) - var/datum/antagonist/traitor/T = new_character.mind.has_antag_datum(/datum/antagonist/traitor) - T.equip_traitor(src) - else - new_character.mind.add_antag_datum(/datum/antagonist/traitor) + SSjobs.AssignRank(new_character, new_character.mind.assigned_role, 0) + SSjobs.EquipRank(new_character, new_character.mind.assigned_role, 1) + SSticker.mode.equip_traitor(new_character) if("Wizard") new_character.loc = pick(wizardstart) //ticker.mode.learn_basic_spells(new_character) @@ -464,13 +462,13 @@ Traitors and the like can also be revived with the previous role mostly intact. if("Cyborg")//More rigging to make em' work and check if they're traitor. new_character = new_character.Robotize() if(new_character.mind.special_role=="traitor") - new_character.mind.add_antag_datum(/datum/antagonist/traitor) + call(/datum/game_mode/proc/add_law_zero)(new_character) if("AI") new_character = new_character.AIize() var/mob/living/silicon/ai/ai_character = new_character ai_character.moveToAILandmark() if(new_character.mind.special_role=="traitor") - new_character.mind.add_antag_datum(/datum/antagonist/traitor) + call(/datum/game_mode/proc/add_law_zero)(new_character) //Add aliens. else SSjobs.AssignRank(new_character, new_character.mind.assigned_role, 0) diff --git a/code/modules/antagonists/traitor/datum_mindslave.dm b/code/modules/antagonists/traitor/datum_mindslave.dm deleted file mode 100644 index 469bfd6bb5a..00000000000 --- a/code/modules/antagonists/traitor/datum_mindslave.dm +++ /dev/null @@ -1,45 +0,0 @@ - -// For Mindslaves and Zealots -/datum/antagonist/mindslave - name = "Mindslave" - roundend_category = "mindslaves" - job_rank = ROLE_MINDSLAVE - var/special_role = ROLE_MINDSLAVE - -/datum/antagonist/mindslave/on_gain() - // Handling mindslave objectives on top of other antag objective sucks, so Im just gonna do it like this - to_chat(owner.current, "New Objective: [objectives[objectives.len].explanation_text]") - - -/datum/antagonist/mindslave/on_removal() - if(owner.som) - var/datum/mindslaves/slaved = owner.som - slaved.serv -= owner - slaved.leave_serv_hud(owner) - antag_memory = "" - owner.special_role = null - ..() - - -/datum/antagonist/mindslave/apply_innate_effects() - . = ..() - if(owner.assigned_role == "Clown") - var/mob/living/carbon/human/slave_mob = owner.current - if(slave_mob && istype(slave_mob)) - to_chat(slave_mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.") - slave_mob.mutations.Remove(CLUMSY) - - -/datum/antagonist/mindslave/remove_innate_effects() - . = ..() - if(owner.assigned_role == "Clown") - var/mob/living/carbon/human/slave_mob = owner.current - if(slave_mob && istype(slave_mob)) - slave_mob.mutations.Add(CLUMSY) - - -/datum/antagonist/mindslave/proc/add_objective(datum/objective/O) - objectives += O - -/datum/antagonist/mindslave/proc/remove_objective(datum/objective/O) - objectives -= O diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm deleted file mode 100644 index 4e9a5ad4bf7..00000000000 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ /dev/null @@ -1,418 +0,0 @@ -#define TRAITOR_HUMAN "human" -#define TRAITOR_AI "AI" - -// For "Actual traitors" -/datum/antagonist/traitor - name = "Traitor" - roundend_category = "traitors" - job_rank = ROLE_TRAITOR - var/special_role = ROLE_TRAITOR - var/give_objectives = TRUE - var/should_give_codewords = TRUE - var/should_equip = TRUE - var/traitor_kind = TRAITOR_HUMAN - var/list/assigned_targets = list() // This includes assassinate as well as steal objectives. prevents duplicate objectives - - -/datum/antagonist/traitor/on_gain() - if(owner.current && isAI(owner.current)) - traitor_kind = TRAITOR_AI - - var/datum/mindslaves/slaved = new() - slaved.masters += owner - owner.som = slaved //we MIGHT want to mindslave someone - SSticker.mode.traitors += owner - owner.special_role = special_role - - if(give_objectives) - forge_traitor_objectives() - if(!silent) - greet() - update_traitor_icons_added() - finalize_traitor() - - -/datum/antagonist/traitor/on_removal() - //Remove malf powers. - if(traitor_kind == TRAITOR_AI && owner.current && isAI(owner.current)) - var/mob/living/silicon/ai/A = owner.current - A.clear_zeroth_law() - A.common_radio.channels.Remove("Syndicate") // De-traitored AIs can still state laws over the syndicate channel without this - A.laws.sorted_laws = A.laws.inherent_laws.Copy() // AI's 'notify laws' button will still state a law 0 because sorted_laws contains it - A.show_laws() - A.malf_picker.remove_malf_verbs(A) - A.verbs -= /mob/living/silicon/ai/proc/choose_modules - qdel(A.malf_picker) - - if(owner.som) - var/datum/mindslaves/slaved = owner.som - slaved.masters -= owner - slaved.serv -= owner - owner.som = null - slaved.leave_serv_hud(owner) - - assigned_targets.Cut() - SSticker.mode.traitors -= owner - owner.special_role = null - update_traitor_icons_removed() - - if(!silent && owner.current) - antag_memory = "" - to_chat(owner.current," You are no longer a [special_role]! ") - ..() - - -/datum/antagonist/traitor/apply_innate_effects() - . = ..() - if(owner.assigned_role == "Clown") - var/mob/living/carbon/human/traitor_mob = owner.current - if(traitor_mob && istype(traitor_mob)) - to_chat(traitor_mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.") - traitor_mob.mutations.Remove(CLUMSY) - - -/datum/antagonist/traitor/remove_innate_effects() - . = ..() - if(owner.assigned_role == "Clown") - var/mob/living/carbon/human/traitor_mob = owner.current - if(traitor_mob && istype(traitor_mob)) - traitor_mob.mutations.Add(CLUMSY) - -// Adding/removing objectives in the owner's mind until we can datumize all antags. Then we can use the /datum/antagonist/objectives var to handle them -// Change "owner.objectives" to "objectives" once objectives are handled in antag datums instead of the mind -/datum/antagonist/traitor/proc/add_objective(datum/objective/O) - owner.objectives += O - -/datum/antagonist/traitor/proc/remove_objective(datum/objective/O) - owner.objectives -= O - - -/datum/antagonist/traitor/proc/forge_traitor_objectives() - switch(traitor_kind) - if(TRAITOR_AI) - forge_ai_objectives() - else - forge_human_objectives() - - -/datum/antagonist/traitor/proc/forge_human_objectives() - var/is_hijacker = prob(10) - var/martyr_chance = prob(20) - var/objective_count = is_hijacker //Hijacking counts towards number of objectives - if(!SSticker.mode.exchange_blue && SSticker.mode.traitors.len >= 8) //Set up an exchange if there are enough traitors - if(!SSticker.mode.exchange_red) - SSticker.mode.exchange_red = owner - else - SSticker.mode.exchange_blue = owner - assign_exchange_role(SSticker.mode.exchange_red) - assign_exchange_role(SSticker.mode.exchange_blue) - objective_count += 1 //Exchange counts towards number of objectives - - - var/objective_amount = config.traitor_objectives_amount - - if(is_hijacker && objective_count <= objective_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 objectives)) - var/datum/objective/hijack/hijack_objective = new - hijack_objective.owner = owner - add_objective(hijack_objective) - return - - for(var/i = objective_count, i < objective_amount) - i += forge_single_objective() - - var/martyr_compatibility = 1 //You can't succeed in stealing if you're dead. - for(var/datum/objective/O in owner.objectives) - if(!O.martyr_compatible) - martyr_compatibility = 0 - break - - if(martyr_compatibility && martyr_chance) - var/datum/objective/die/martyr_objective = new - martyr_objective.owner = owner - add_objective(martyr_objective) - return - - if(!(locate(/datum/objective/escape) in objectives)) - var/datum/objective/escape/escape_objective = new - escape_objective.owner = owner - add_objective(escape_objective) - return - - -/datum/antagonist/traitor/proc/forge_ai_objectives() - var/objective_count = 0 - var/try_again = TRUE - - if(prob(30)) - objective_count += forge_single_objective() - - for(var/i = objective_count, i < config.traitor_objectives_amount) - var/datum/objective/assassinate/kill_objective = new - kill_objective.owner = owner - kill_objective.find_target() - if("[kill_objective.target]" in assigned_targets) // In the rare case the game can't find a target for the AI thats not a duplicate - if(try_again) // It will attempt to location another target ONCE - try_again = FALSE // This code will really only come into play on lowpop rounds where getting duplicate targets is more common - continue - assigned_targets.Add("[kill_objective.target]") - add_objective(kill_objective) - i += 1 - var/datum/objective/survive/survive_objective = new - survive_objective.owner = owner - add_objective(survive_objective) - - -/datum/antagonist/traitor/proc/forge_single_objective() - switch(traitor_kind) - if(TRAITOR_AI) - return forge_single_AI_objective() - else - return forge_single_human_objective() - - -/datum/antagonist/traitor/proc/forge_single_human_objective() // Returns how many objectives are added - . = 1 - if(prob(50)) - var/list/active_ais = active_ais() - if(active_ais.len && prob(100/GLOB.player_list.len)) - var/datum/objective/destroy/destroy_objective = new - destroy_objective.owner = owner - destroy_objective.find_target() - if("[destroy_objective]" in assigned_targets) // Is this target already in their list of assigned targets? If so, don't add this objective and return - return 0 - else if(destroy_objective.target) // Is the target a real one and not null? If so, add it to our list of targets to avoid duplicate targets - assigned_targets.Add("[destroy_objective.target]") // This logic is applied to all traitor objectives including steal objectives - add_objective(destroy_objective) - - else if(prob(5)) - var/datum/objective/debrain/debrain_objective = new - debrain_objective.owner = owner - debrain_objective.find_target() - if("[debrain_objective]" in assigned_targets) - return 0 - else if(debrain_objective.target) - assigned_targets.Add("[debrain_objective.target]") - add_objective(debrain_objective) - - else if(prob(30)) - var/datum/objective/maroon/maroon_objective = new - maroon_objective.owner = owner - maroon_objective.find_target() - if("[maroon_objective]" in assigned_targets) - return 0 - else if(maroon_objective.target) - assigned_targets.Add("[maroon_objective.target]") - add_objective(maroon_objective) - - else - var/datum/objective/assassinate/kill_objective = new - kill_objective.owner = owner - kill_objective.find_target() - if("[kill_objective.target]" in assigned_targets) - return 0 - else if(kill_objective.target) - assigned_targets.Add("[kill_objective.target]") - add_objective(kill_objective) - - else - var/datum/objective/steal/steal_objective = new - steal_objective.owner = owner - steal_objective.find_target() - if("[steal_objective.steal_target]" in assigned_targets) - return 0 - else if(steal_objective.steal_target) - assigned_targets.Add("[steal_objective.steal_target]") - add_objective(steal_objective) - - -/datum/antagonist/traitor/proc/forge_single_AI_objective() - . = 1 - var/special_pick = rand(1,2) - switch(special_pick) - if(1) // AI hijack - var/datum/objective/block/block_objective = new - block_objective.owner = owner - add_objective(block_objective) - if(2) // Protect and strand a target - var/datum/objective/protect/yandere_one = new - yandere_one.owner = owner - yandere_one.find_target() - - if("[yandere_one.target]" in assigned_targets) - return 0 - else if(yandere_one.target) - assigned_targets.Add("[yandere_one.target]") - - add_objective(yandere_one) - var/datum/objective/maroon/yandere_two = new - yandere_two.owner = owner - yandere_two.target = yandere_one.target - yandere_two.explanation_text = "Prevent [yandere_one.target], the [yandere_one.target.assigned_role] from escaping alive." - add_objective(yandere_two) - - -/datum/antagonist/traitor/greet() - to_chat(owner.current, "You are a [owner.special_role]!") - if(!LAZYLEN(owner.objectives)) // Remove "owner" when objectives are handled in the datum - to_chat(owner.current, "You don't have any objectives right now.") - else - owner.announce_objectives() - if(should_give_codewords) - give_codewords() - - -/datum/antagonist/traitor/proc/update_traitor_icons_added(datum/mind/traitor_mind) - var/datum/atom_hud/antag/traitorhud = huds[ANTAG_HUD_TRAITOR] - traitorhud.join_hud(owner.current, null) - set_antag_hud(owner.current, "hudsyndicate") - - -/datum/antagonist/traitor/proc/update_traitor_icons_removed(datum/mind/traitor_mind) - var/datum/atom_hud/antag/traitorhud = huds[ANTAG_HUD_TRAITOR] - traitorhud.leave_hud(owner.current, null) - set_antag_hud(owner.current, null) - - -/datum/antagonist/traitor/proc/finalize_traitor() - switch(traitor_kind) - if(TRAITOR_AI) - add_law_zero() - owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/malf.ogg', 100, FALSE, pressure_affected = FALSE) - var/mob/living/silicon/ai/A = owner.current - A.show_laws() - if(TRAITOR_HUMAN) - if(should_equip) - equip_traitor() - owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/tatoralert.ogg', 100, FALSE, pressure_affected = FALSE) - - -/datum/antagonist/traitor/proc/give_codewords() - if(!owner.current) - return - var/mob/traitor_mob = owner.current - - var/phrases = jointext(GLOB.syndicate_code_phrase, ", ") - var/responses = jointext(GLOB.syndicate_code_response, ", ") - - to_chat(traitor_mob, "The Syndicate have provided you with the following codewords to identify fellow agents:") - to_chat(traitor_mob, "Code Phrase: [phrases]") - to_chat(traitor_mob, "Code Response: [responses]") - - antag_memory += "Code Phrase: [phrases]
" - antag_memory += "Code Response: [responses]
" - - to_chat(traitor_mob, "Use the codewords during regular conversation to identify other agents. Proceed with caution, however, as everyone is a potential foe.") - - -/datum/antagonist/traitor/proc/add_law_zero() - var/mob/living/silicon/ai/killer = owner.current - if(!killer || !istype(killer)) - return - var/law = "Accomplish your objectives at all costs." - var/law_borg = "Accomplish your AI's objectives at all costs." - killer.set_zeroth_law(law, law_borg) - killer.set_syndie_radio() - to_chat(killer, "Your radio has been upgraded! Use :t to speak on an encrypted channel with Syndicate Agents!") - killer.add_malf_picker() - - -/datum/antagonist/traitor/proc/equip_traitor() - - if(traitor_kind == TRAITOR_HUMAN) - var/mob/living/carbon/human/traitor_mob = owner.current - - // find a radio! toolbox(es), backpack, belt, headset - var/obj/item/R = locate(/obj/item/pda) in traitor_mob.contents //Hide the uplink in a PDA if available, otherwise radio - if(!R) - R = locate(/obj/item/radio) in traitor_mob.contents - - if(!R) - to_chat(traitor_mob, "Unfortunately, the Syndicate wasn't able to get you a radio.") - . = 0 - else - if(istype(R, /obj/item/radio)) - // generate list of radio freqs - var/obj/item/radio/target_radio = R - var/freq = PUBLIC_LOW_FREQ - var/list/freqlist = list() - while(freq <= PUBLIC_HIGH_FREQ) - if(freq < 1451 || freq > 1459) - freqlist += freq - freq += 2 - if((freq % 2) == 0) - freq += 1 - freq = freqlist[rand(1, freqlist.len)] - - var/obj/item/uplink/hidden/T = new(R) - target_radio.hidden_uplink = T - T.uplink_owner = "[traitor_mob.key]" - target_radio.traitor_frequency = freq - to_chat(traitor_mob, "The Syndicate have cunningly disguised a Syndicate Uplink as your [R.name]. Simply dial the frequency [format_frequency(freq)] to unlock its hidden features.") - traitor_mob.mind.store_memory("Radio Freq: [format_frequency(freq)] ([R.name]).") - else if(istype(R, /obj/item/pda)) - // generate a passcode if the uplink is hidden in a PDA - var/pda_pass = "[rand(100,999)] [pick("Alpha","Bravo","Delta","Omega")]" - - var/obj/item/uplink/hidden/T = new(R) - R.hidden_uplink = T - T.uplink_owner = "[traitor_mob.key]" - var/obj/item/pda/P = R - P.lock_code = pda_pass - - to_chat(traitor_mob, "The Syndicate have cunningly disguised a Syndicate Uplink as your [R.name]. Simply enter the code \"[pda_pass]\" into the ringtone select to unlock its hidden features.") - antag_memory += ("Uplink Passcode: [pda_pass] ([R.name].") - return 1 - - -/datum/antagonist/traitor/proc/assign_exchange_role(var/datum/mind/owner) - //set faction - var/faction = "red" - if(owner == SSticker.mode.exchange_blue) - faction = "blue" - - //Assign objectives - var/datum/objective/steal/exchange/exchange_objective = new - exchange_objective.set_faction(faction,((faction == "red") ? SSticker.mode.exchange_blue : SSticker.mode.exchange_red)) - exchange_objective.owner = owner - owner.objectives += exchange_objective - - if(prob(20)) - var/datum/objective/steal/exchange/backstab/backstab_objective = new - backstab_objective.set_faction(faction) - backstab_objective.owner = owner - owner.objectives += backstab_objective - - //Spawn and equip documents - var/mob/living/carbon/human/mob = owner.current - - var/obj/item/folder/syndicate/folder - if(owner == SSticker.mode.exchange_red) - folder = new/obj/item/folder/syndicate/red(mob.locs) - else - folder = new/obj/item/folder/syndicate/blue(mob.locs) - - var/list/slots = list ( - "backpack" = slot_in_backpack, - "left pocket" = slot_l_store, - "right pocket" = slot_r_store, - "left hand" = slot_l_hand, - "right hand" = slot_r_hand, - ) - - var/where = "At your feet" - var/equipped_slot = mob.equip_in_one_of_slots(folder, slots) - if(equipped_slot) - where = "In your [equipped_slot]" - to_chat(mob, "

[where] is a folder containing secret documents that another Syndicate group wants. We have set up a meeting with one of their agents on station to make an exchange. Exercise extreme caution as they cannot be trusted and may be hostile.
") - mob.update_icons() - - -/datum/antagonist/traitor/roundend_report_footer() - var/phrases = jointext(GLOB.syndicate_code_phrase, ", ") - var/responses = jointext(GLOB.syndicate_code_response, ", ") - - var message = "
The code phrases were: [phrases]
\ - The code responses were: [responses]
" - - return message diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 2942ace8ee2..7b3162fdefb 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -740,7 +740,7 @@ /obj/machinery/power/apc/proc/get_malf_status(mob/living/silicon/ai/malf) - if(istype(malf) && malf.mind.has_antag_datum(/datum/antagonist/traitor)) + if(istype(malf) && malf.malf_picker) if(malfai == (malf.parent || malf)) if(occupier == malf) return 3 // 3 = User is shunted in this APC diff --git a/paradise.dme b/paradise.dme index 081fa228da5..bdb77b45dd0 100644 --- a/paradise.dme +++ b/paradise.dme @@ -1236,8 +1236,6 @@ #include "code\modules\antagonists\_common\antag_hud.dm" #include "code\modules\antagonists\_common\antag_spawner.dm" #include "code\modules\antagonists\_common\antag_team.dm" -#include "code\modules\antagonists\traitor\datum_mindslave.dm" -#include "code\modules\antagonists\traitor\datum_traitor.dm" #include "code\modules\antagonists\wishgranter\wishgranter.dm" #include "code\modules\arcade\arcade_base.dm" #include "code\modules\arcade\arcade_prize.dm" From 5961a9898cb8625f86ff207c9b341384670b09ff Mon Sep 17 00:00:00 2001 From: TDSSS <32099540+TDSSS@users.noreply.github.com> Date: Sun, 22 Sep 2019 06:27:56 +0200 Subject: [PATCH 10/24] removes nettle stuff --- code/modules/hydroponics/grown/nettle.dm | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/code/modules/hydroponics/grown/nettle.dm b/code/modules/hydroponics/grown/nettle.dm index 3f4b56a6f25..8dcada2f7e8 100644 --- a/code/modules/hydroponics/grown/nettle.dm +++ b/code/modules/hydroponics/grown/nettle.dm @@ -52,10 +52,8 @@ if(!ishuman(user)) return TRUE var/mob/living/carbon/human/H = user - if(H.gloves && istype(H.gloves, /obj/item/clothing/gloves)) - var/obj/item/clothing/gloves/G = H.gloves //exclude fingerless gloves, rings, bracers, etc. - if(!G.transfer_prints) - return TRUE + if(H.gloves) + return TRUE if(PIERCEIMMUNE in H.dna.species.species_traits) return TRUE var/organ = ((H.hand ? "l_":"r_") + "arm") From 187420a22ce6a7e7129425218e291e3e5c7434dd Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Sun, 22 Sep 2019 00:40:37 -0400 Subject: [PATCH 11/24] Automatic changelog generation for PR #12374 [ci skip] --- html/changelogs/AutoChangeLog-pr-12374.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-12374.yml diff --git a/html/changelogs/AutoChangeLog-pr-12374.yml b/html/changelogs/AutoChangeLog-pr-12374.yml new file mode 100644 index 00000000000..cdf2948d337 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-12374.yml @@ -0,0 +1,4 @@ +author: "TDSSS" +delete-after: True +changes: + - tweak: "Just slight gloves refactor, shouldn't impact anything in game." From 76b9ae343944a40bd3ad57687a4960bbb2f1c984 Mon Sep 17 00:00:00 2001 From: variableundefined <40092670+variableundefined@users.noreply.github.com> Date: Sun, 22 Sep 2019 00:46:43 -0400 Subject: [PATCH 12/24] Manual Changelog Compile 9/22/2019 Midnight --- html/changelog.html | 29 ++++++++++++++++++++++ html/changelogs/.all_changelog.yml | 24 ++++++++++++++++++ html/changelogs/AutoChangeLog-pr-11969.yml | 11 -------- html/changelogs/AutoChangeLog-pr-12364.yml | 4 --- html/changelogs/AutoChangeLog-pr-12370.yml | 4 --- html/changelogs/AutoChangeLog-pr-12371.yml | 4 --- html/changelogs/AutoChangeLog-pr-12374.yml | 4 --- 7 files changed, 53 insertions(+), 27 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-11969.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-12364.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-12370.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-12371.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-12374.yml diff --git a/html/changelog.html b/html/changelog.html index 8195a933590..c9a4359caf0 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -56,6 +56,35 @@ -->
+

22 September 2019

+

Evankhell561 updated:

+
    +
  • Mech ID upload panels now come with [add all] and [delete all] options
  • +
+

Fox McCloud updated:

+
    +
  • Fixes corpses/lying down mobs blocking projectiles
  • +
+

MarsM0nd updated:

+
    +
  • can safely pick up nettles again
  • +
+

SteelSlayer updated:

+
    +
  • Traitor and mindslave status is handled in a datum instead of the mind
  • +
  • You can no longer use a mindslave implant on a person with no mind
  • +
  • Adds the ability for admins to de-mindslave somone through the traitor panel
  • +
  • De-traitoring malf AIs via the traitor panel removes all instances of their Law 0
  • +
  • De-traitoring malf AIs via the traitor panel removes their ability to still state laws over the syndicate channel
  • +
  • De-traitoring malf AIs via the traitor panel removes their ability to shunt to hacked APCs
  • +
  • Unemagging borgs via the traitor panel properly removes their syndicate laws and gives them the crewsimov lawset
  • +
  • Unemagging borgs via the traitor panel who did not have a module selected does not cause a runtime anymore
  • +
+

TDSSS updated:

+
    +
  • Just slight gloves refactor, shouldn't impact anything in game.
  • +
+

21 September 2019

AzuleUtama updated:

    diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index 4dc676a3274..1207e01fa7a 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -11471,3 +11471,27 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. - tweak: Replaced link to CA (check antags) in adminhelps, tickets, and adminmoreinfo with a link to TP (traitor panel) - tweak: Altered CA to TP for prayers and adminpms. +2019-09-22: + Evankhell561: + - rscadd: Mech ID upload panels now come with [add all] and [delete all] options + Fox McCloud: + - bugfix: Fixes corpses/lying down mobs blocking projectiles + MarsM0nd: + - bugfix: can safely pick up nettles again + SteelSlayer: + - rscadd: Traitor and mindslave status is handled in a datum instead of the mind + - tweak: You can no longer use a mindslave implant on a person with no mind + - rscadd: Adds the ability for admins to de-mindslave somone through the traitor + panel + - bugfix: De-traitoring malf AIs via the traitor panel removes all instances of + their Law 0 + - bugfix: De-traitoring malf AIs via the traitor panel removes their ability to + still state laws over the syndicate channel + - bugfix: De-traitoring malf AIs via the traitor panel removes their ability to + shunt to hacked APCs + - bugfix: Unemagging borgs via the traitor panel properly removes their syndicate + laws and gives them the crewsimov lawset + - bugfix: Unemagging borgs via the traitor panel who did not have a module selected + does not cause a runtime anymore + TDSSS: + - tweak: Just slight gloves refactor, shouldn't impact anything in game. diff --git a/html/changelogs/AutoChangeLog-pr-11969.yml b/html/changelogs/AutoChangeLog-pr-11969.yml deleted file mode 100644 index ed3291cae4c..00000000000 --- a/html/changelogs/AutoChangeLog-pr-11969.yml +++ /dev/null @@ -1,11 +0,0 @@ -author: "SteelSlayer" -delete-after: True -changes: - - rscadd: "Traitor and mindslave status is handled in a datum instead of the mind" - - tweak: "You can no longer use a mindslave implant on a person with no mind" - - rscadd: "Adds the ability for admins to de-mindslave somone through the traitor panel" - - bugfix: "De-traitoring malf AIs via the traitor panel removes all instances of their Law 0" - - bugfix: "De-traitoring malf AIs via the traitor panel removes their ability to still state laws over the syndicate channel" - - bugfix: "De-traitoring malf AIs via the traitor panel removes their ability to shunt to hacked APCs" - - bugfix: "Unemagging borgs via the traitor panel properly removes their syndicate laws and gives them the crewsimov lawset" - - bugfix: "Unemagging borgs via the traitor panel who did not have a module selected does not cause a runtime anymore" diff --git a/html/changelogs/AutoChangeLog-pr-12364.yml b/html/changelogs/AutoChangeLog-pr-12364.yml deleted file mode 100644 index 2c6b8c6d6db..00000000000 --- a/html/changelogs/AutoChangeLog-pr-12364.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Evankhell561" -delete-after: True -changes: - - rscadd: "Mech ID upload panels now come with [add all] and [delete all] options" diff --git a/html/changelogs/AutoChangeLog-pr-12370.yml b/html/changelogs/AutoChangeLog-pr-12370.yml deleted file mode 100644 index 02390b0635a..00000000000 --- a/html/changelogs/AutoChangeLog-pr-12370.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Fox McCloud" -delete-after: True -changes: - - bugfix: "Fixes corpses/lying down mobs blocking projectiles" diff --git a/html/changelogs/AutoChangeLog-pr-12371.yml b/html/changelogs/AutoChangeLog-pr-12371.yml deleted file mode 100644 index 2d2f97038f6..00000000000 --- a/html/changelogs/AutoChangeLog-pr-12371.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MarsM0nd" -delete-after: True -changes: - - bugfix: "can safely pick up nettles again" diff --git a/html/changelogs/AutoChangeLog-pr-12374.yml b/html/changelogs/AutoChangeLog-pr-12374.yml deleted file mode 100644 index cdf2948d337..00000000000 --- a/html/changelogs/AutoChangeLog-pr-12374.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "TDSSS" -delete-after: True -changes: - - tweak: "Just slight gloves refactor, shouldn't impact anything in game." From 91b649285110733e157cd922249715798256c745 Mon Sep 17 00:00:00 2001 From: TDSSS <32099540+TDSSS@users.noreply.github.com> Date: Sun, 22 Sep 2019 17:48:25 +0200 Subject: [PATCH 13/24] Brig door timer no longer announce admin names when stopped with admin power (#12380) --- code/game/machinery/doors/brigdoors.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm index 0e773e0ea95..f23734a0079 100644 --- a/code/game/machinery/doors/brigdoors.dm +++ b/code/game/machinery/doors/brigdoors.dm @@ -375,7 +375,8 @@ timer_start() else timer_end() - Radio.autosay("Timer stopped manually by [usr.name].", name, "Security", list(z)) + if(!isobserver(usr)) //spooky admin ghosts are in your brig, releasing your prisoners + Radio.autosay("Timer stopped manually by [usr.name].", name, "Security", list(z)) else if(href_list["settime"]) From d5ea2c9eedba5e407f4a246854073b46ae0f4d0b Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Sun, 22 Sep 2019 11:48:28 -0400 Subject: [PATCH 14/24] Automatic changelog generation for PR #12380 [ci skip] --- html/changelogs/AutoChangeLog-pr-12380.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-12380.yml diff --git a/html/changelogs/AutoChangeLog-pr-12380.yml b/html/changelogs/AutoChangeLog-pr-12380.yml new file mode 100644 index 00000000000..89a5fe22f1d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-12380.yml @@ -0,0 +1,4 @@ +author: "TDSSS" +delete-after: True +changes: + - bugfix: "fixed brig door timers from announcing admin names when stopped via admin powers." From 002672285f1f3eda6435d45d0bb9e740abfa2f65 Mon Sep 17 00:00:00 2001 From: Mark van Alphen Date: Sun, 22 Sep 2019 12:47:02 -0600 Subject: [PATCH 15/24] Fix clown soldier outfits not having names (#12387) --- code/modules/awaymissions/corpse.dm | 34 +++++++++++++++-------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm index a186060c63a..3598a1469b7 100644 --- a/code/modules/awaymissions/corpse.dm +++ b/code/modules/awaymissions/corpse.dm @@ -398,24 +398,26 @@ /datum/outfit/clownsoldier - uniform = /obj/item/clothing/under/soldieruniform - suit = /obj/item/clothing/suit/soldiercoat - shoes = /obj/item/clothing/shoes/clown_shoes - l_ear = /obj/item/radio/headset - mask = /obj/item/clothing/mask/gas/clown_hat - l_pocket = /obj/item/bikehorn - back = /obj/item/storage/backpack/clown - head = /obj/item/clothing/head/stalhelm + name = "Clown Soldier" + uniform = /obj/item/clothing/under/soldieruniform + suit = /obj/item/clothing/suit/soldiercoat + shoes = /obj/item/clothing/shoes/clown_shoes + l_ear = /obj/item/radio/headset + mask = /obj/item/clothing/mask/gas/clown_hat + l_pocket = /obj/item/bikehorn + back = /obj/item/storage/backpack/clown + head = /obj/item/clothing/head/stalhelm /datum/outfit/clownofficer - uniform = /obj/item/clothing/under/officeruniform - suit = /obj/item/clothing/suit/officercoat - shoes = /obj/item/clothing/shoes/clown_shoes - l_ear = /obj/item/radio/headset - mask = /obj/item/clothing/mask/gas/clown_hat - l_pocket = /obj/item/bikehorn - back = /obj/item/storage/backpack/clown - head = /obj/item/clothing/head/naziofficer + name = "Clown Officer" + uniform = /obj/item/clothing/under/officeruniform + suit = /obj/item/clothing/suit/officercoat + shoes = /obj/item/clothing/shoes/clown_shoes + l_ear = /obj/item/radio/headset + mask = /obj/item/clothing/mask/gas/clown_hat + l_pocket = /obj/item/bikehorn + back = /obj/item/storage/backpack/clown + head = /obj/item/clothing/head/naziofficer /obj/effect/mob_spawn/human/mime name = "Mime" From e5fe0526e0e1a374b01e621beb9c71527ddea31a Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Sun, 22 Sep 2019 14:47:05 -0400 Subject: [PATCH 16/24] Automatic changelog generation for PR #12387 [ci skip] --- html/changelogs/AutoChangeLog-pr-12387.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-12387.yml diff --git a/html/changelogs/AutoChangeLog-pr-12387.yml b/html/changelogs/AutoChangeLog-pr-12387.yml new file mode 100644 index 00000000000..60df714e6b0 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-12387.yml @@ -0,0 +1,4 @@ +author: "Markolie" +delete-after: True +changes: + - bugfix: "Fixed naked equipment selection and reincarnation not working." From a2d15da3e9eac0f363e30486c5b2f4bd3b3608df Mon Sep 17 00:00:00 2001 From: TDSSS <32099540+TDSSS@users.noreply.github.com> Date: Mon, 23 Sep 2019 02:31:06 +0200 Subject: [PATCH 17/24] Ghost HUD QoL change (#12373) --- code/modules/mob/dead/observer/observer.dm | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 7c80b93e5ee..fc4a14c6e6d 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -324,15 +324,22 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp /mob/dead/observer/verb/toggle_medHUD() set category = "Ghost" - set name = "Toggle Medic/Sec/Diag/All HUDs" + set name = "Toggle All/Sec/Med/Diag HUDs" set desc = "Toggles the HUDs." if(!client) return switch(data_hud_seen) //give new huds if(FALSE) - data_hud_seen = DATA_HUD_SECURITY_ADVANCED + data_hud_seen = DATA_HUD_DIAGNOSTIC + DATA_HUD_SECURITY_ADVANCED + DATA_HUD_MEDICAL_ADVANCED + show_me_the_hud(DATA_HUD_DIAGNOSTIC) show_me_the_hud(DATA_HUD_SECURITY_ADVANCED) + show_me_the_hud(DATA_HUD_MEDICAL_ADVANCED) + to_chat(src, "All HUDs enabled.") + if(DATA_HUD_DIAGNOSTIC + DATA_HUD_SECURITY_ADVANCED + DATA_HUD_MEDICAL_ADVANCED) + data_hud_seen = DATA_HUD_SECURITY_ADVANCED + remove_the_hud(DATA_HUD_DIAGNOSTIC) + remove_the_hud(DATA_HUD_MEDICAL_ADVANCED) to_chat(src, "Security HUD set.") if(DATA_HUD_SECURITY_ADVANCED) data_hud_seen = DATA_HUD_MEDICAL_ADVANCED @@ -344,15 +351,8 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp remove_the_hud(DATA_HUD_MEDICAL_ADVANCED) show_me_the_hud(DATA_HUD_DIAGNOSTIC) to_chat(src, "Diagnostic HUD set.") - if(DATA_HUD_DIAGNOSTIC) - data_hud_seen = data_hud_seen + DATA_HUD_SECURITY_ADVANCED + DATA_HUD_MEDICAL_ADVANCED - show_me_the_hud(DATA_HUD_SECURITY_ADVANCED) - show_me_the_hud(DATA_HUD_MEDICAL_ADVANCED) - to_chat(src, "All HUDs enabled.") else data_hud_seen = FALSE - remove_the_hud(DATA_HUD_DIAGNOSTIC) - remove_the_hud(DATA_HUD_SECURITY_ADVANCED) remove_the_hud(DATA_HUD_MEDICAL_ADVANCED) to_chat(src, "HUDs disabled.") From 59378e1ae85ebe4c18d5dbc09776bda9987cda59 Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Sun, 22 Sep 2019 20:31:08 -0400 Subject: [PATCH 18/24] Automatic changelog generation for PR #12373 [ci skip] --- html/changelogs/AutoChangeLog-pr-12373.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-12373.yml diff --git a/html/changelogs/AutoChangeLog-pr-12373.yml b/html/changelogs/AutoChangeLog-pr-12373.yml new file mode 100644 index 00000000000..c6104a19c10 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-12373.yml @@ -0,0 +1,4 @@ +author: "TDSSS" +delete-after: True +changes: + - tweak: "all huds are the first option when ghosts cycle through huds" From d3dcd8b35f8ad4e2da4f7b5fcd828943348bd850 Mon Sep 17 00:00:00 2001 From: datlo Date: Mon, 23 Sep 2019 02:44:01 +0200 Subject: [PATCH 19/24] Fix clown changeling not losing comic sans (#12372) --- code/game/jobs/job/support.dm | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/code/game/jobs/job/support.dm b/code/game/jobs/job/support.dm index a247fa6810b..e4bb22b28af 100644 --- a/code/game/jobs/job/support.dm +++ b/code/game/jobs/job/support.dm @@ -286,9 +286,14 @@ var/obj/item/organ/internal/cyberimp/brain/clown_voice/implant = new implant.insert(H) - H.mutations.Add(CLUMSY) + H.dna.SetSEState(CLUMSYBLOCK, TRUE) + genemutcheck(H, CLUMSYBLOCK, null, MUTCHK_FORCED) + H.dna.default_blocks.Add(CLUMSYBLOCK) if(!ismachine(H)) - H.mutations.Add(COMIC) + H.dna.SetSEState(COMICBLOCK, TRUE) + genemutcheck(H, COMICBLOCK, null, MUTCHK_FORCED) + H.dna.default_blocks.Add(COMICBLOCK) + H.check_mutations = TRUE //action given to antag clowns /datum/action/innate/toggle_clumsy From 7846268dae6062734291a770d95051b0f78cff6e Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Sun, 22 Sep 2019 20:44:03 -0400 Subject: [PATCH 20/24] Automatic changelog generation for PR #12372 [ci skip] --- html/changelogs/AutoChangeLog-pr-12372.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-12372.yml diff --git a/html/changelogs/AutoChangeLog-pr-12372.yml b/html/changelogs/AutoChangeLog-pr-12372.yml new file mode 100644 index 00000000000..e294bb4c03e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-12372.yml @@ -0,0 +1,5 @@ +author: "datlo" +delete-after: True +changes: + - bugfix: "Fixed clown changelings not losing comic sans on transformation" + - tweak: "Clowns can now lose the clumsy and comic genes through DNA manipulation (but not mutadone)" From c87389a595299e784bc2dfb095e731b3b430e296 Mon Sep 17 00:00:00 2001 From: Fox McCloud Date: Sun, 22 Sep 2019 21:22:57 -0400 Subject: [PATCH 21/24] TG Buckle Update (#12375) --- code/ATMOSPHERICS/atmospherics.dm | 6 +- code/ATMOSPHERICS/pipes/pipe.dm | 4 +- .../pipes/simple/pipe_simple_he.dm | 8 +- code/_onclick/hud/alert.dm | 10 ++ code/datums/helper_datums/teleport.dm | 2 +- code/datums/spells/area_teleport.dm | 2 +- code/datums/spells/devil.dm | 8 -- .../weather/weather_types/floor_is_lava.dm | 4 +- code/game/atoms_movable.dm | 28 ++-- .../miniantags/slaughter/bloodcrawl.dm | 7 +- .../shadowling/shadowling_abilities.dm | 8 +- code/game/gamemodes/vampire/vampire_powers.dm | 8 -- code/game/machinery/OpTable.dm | 2 +- code/game/machinery/portable_turret.dm | 5 +- code/game/objects/buckling.dm | 132 ++++++++++-------- .../items/weapons/implants/implantchair.dm | 2 +- code/game/objects/items/weapons/scrolls.dm | 4 +- .../structures/crates_lockers/crates.dm | 4 +- code/game/objects/structures/electricchair.dm | 13 +- code/game/objects/structures/guillotine.dm | 32 +++-- code/game/objects/structures/kitchen_spike.dm | 100 +++++++------ code/game/objects/structures/plasticflaps.dm | 53 +++---- .../stool_bed_chair_nest/alien_nests.dm | 85 ++++++----- .../structures/stool_bed_chair_nest/bed.dm | 21 +-- .../structures/stool_bed_chair_nest/chairs.dm | 39 +++--- .../stool_bed_chair_nest/wheelchair.dm | 22 +-- code/game/turfs/simulated/floor/lava.dm | 21 +-- code/modules/awaymissions/gateway.dm | 29 ++-- code/modules/client/preference/preferences.dm | 12 +- .../modules/clothing/spacesuits/chronosuit.dm | 4 +- code/modules/clothing/suits/armor.dm | 2 - code/modules/crafting/craft.dm | 3 +- code/modules/events/spacevine.dm | 6 +- code/modules/hydroponics/grown/towercap.dm | 15 +- code/modules/mob/living/carbon/carbon.dm | 23 +-- code/modules/mob/living/carbon/human/login.dm | 2 +- .../living/carbon/human/species/_species.dm | 4 +- .../mob/living/carbon/human/species/golem.dm | 13 +- .../mob/living/carbon/human/species/monkey.dm | 2 +- code/modules/mob/living/carbon/slime/slime.dm | 10 ++ code/modules/mob/living/living.dm | 12 +- code/modules/mob/living/living_defense.dm | 3 + code/modules/mob/living/silicon/ai/ai.dm | 3 + code/modules/mob/living/silicon/pai/pai.dm | 5 + .../mob/living/simple_animal/bot/mulebot.dm | 22 ++- .../simple_animal/hostile/floorcluwne.dm | 2 +- code/modules/mob/mob.dm | 51 +++++-- code/modules/mob/mob_defines.dm | 4 + code/modules/mob/mob_movement.dm | 18 ++- .../research/xenobiology/xenobio_camera.dm | 37 ++--- .../ruins/lavalandruin_code/fountain_hall.dm | 2 +- code/modules/shuttle/shuttle.dm | 2 +- code/modules/vehicle/ambulance.dm | 38 ++--- code/modules/vehicle/atv.dm | 11 +- code/modules/vehicle/janicart.dm | 30 ++-- code/modules/vehicle/motorcycle.dm | 13 +- code/modules/vehicle/speedbike.dm | 34 ++--- code/modules/vehicle/sportscar.dm | 42 +++--- code/modules/vehicle/vehicle.dm | 89 ++++++------ icons/mob/screen_alert.dmi | Bin 50050 -> 51466 bytes 60 files changed, 640 insertions(+), 533 deletions(-) diff --git a/code/ATMOSPHERICS/atmospherics.dm b/code/ATMOSPHERICS/atmospherics.dm index c542d714ca6..7e791e6adda 100644 --- a/code/ATMOSPHERICS/atmospherics.dm +++ b/code/ATMOSPHERICS/atmospherics.dm @@ -12,7 +12,7 @@ GLOBAL_DATUM_INIT(pipe_icon_manager, /datum/pipe_icon_manager, new()) /obj/machinery/atmospherics anchored = 1 layer = GAS_PIPE_HIDDEN_LAYER //under wires - plane = FLOOR_PLANE + plane = FLOOR_PLANE idle_power_usage = 0 active_power_usage = 0 power_channel = ENVIRON @@ -66,7 +66,7 @@ GLOBAL_DATUM_INIT(pipe_icon_manager, /datum/pipe_icon_manager, new()) if(level == 2 || !T.intact) plane = GAME_PLANE else - plane = FLOOR_PLANE + plane = FLOOR_PLANE /obj/machinery/atmospherics/proc/update_pipe_image() pipe_image = image(src, loc, layer = ABOVE_HUD_LAYER, dir = dir) //the 20 puts it above Byond's darkness (not its opacity view) @@ -258,7 +258,7 @@ GLOBAL_DATUM_INIT(pipe_icon_manager, /datum/pipe_icon_manager, new()) if(!direction || !(direction in cardinal)) //cant go this way. return - if(buckled_mob == user) + if(user in buckled_mobs)// fixes buckle ventcrawl edgecase fuck bug return var/obj/machinery/atmospherics/target_move = findConnecting(direction) diff --git a/code/ATMOSPHERICS/pipes/pipe.dm b/code/ATMOSPHERICS/pipes/pipe.dm index ec4f6bfd7ec..038180cdd7d 100644 --- a/code/ATMOSPHERICS/pipes/pipe.dm +++ b/code/ATMOSPHERICS/pipes/pipe.dm @@ -8,8 +8,8 @@ var/alert_pressure = 80*ONE_ATMOSPHERE //minimum pressure before check_pressure(...) should be called //Buckling - can_buckle = 1 - buckle_requires_restraints = 1 + can_buckle = TRUE + buckle_requires_restraints = TRUE buckle_lying = -1 /obj/machinery/atmospherics/pipe/New() diff --git a/code/ATMOSPHERICS/pipes/simple/pipe_simple_he.dm b/code/ATMOSPHERICS/pipes/simple/pipe_simple_he.dm index cb7ec277f95..1f40bdae665 100644 --- a/code/ATMOSPHERICS/pipes/simple/pipe_simple_he.dm +++ b/code/ATMOSPHERICS/pipes/simple/pipe_simple_he.dm @@ -10,7 +10,7 @@ thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT color = "#404040" - buckle_lying = 1 + buckle_lying = TRUE var/icon_temperature = T20C //stop small changes in temperature causing icon refresh /obj/machinery/atmospherics/pipe/simple/heat_exchanging/process_atmos() @@ -50,10 +50,12 @@ animate(src, color = rgb(h_r, h_g, h_b), time = 20, easing = SINE_EASING) //burn any mobs buckled based on temperature - if(buckled_mob) + if(has_buckled_mobs()) var/heat_limit = 1000 if(pipe_air.temperature > heat_limit + 1) - buckled_mob.apply_damage(4 * log(pipe_air.temperature - heat_limit), BURN, "chest") + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + buckled_mob.apply_damage(4 * log(pipe_air.temperature - heat_limit), BURN, "chest") /obj/machinery/atmospherics/pipe/simple/heat_exchanging/New() diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index 8ce4d64911b..d49c0ee59eb 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -557,6 +557,7 @@ so as to remain in compliance with the most up-to-date laws." /obj/screen/alert/restrained/buckled name = "Buckled" desc = "You've been buckled to something. Click the alert to unbuckle unless you're handcuffed." + icon_state = "buckled" /obj/screen/alert/restrained/handcuffed name = "Handcuffed" @@ -570,6 +571,15 @@ so as to remain in compliance with the most up-to-date laws." if(isliving(usr)) var/mob/living/L = usr return L.resist() + +/obj/screen/alert/restrained/buckled/Click() + var/mob/living/L = usr + if(!istype(L) || !L.can_resist()) + return + L.changeNext_move(CLICK_CD_RESIST) + if(L.last_special <= world.time) + return L.resist_buckle() + // PRIVATE = only edit, use, or override these if you're editing the system as a whole // Re-render all alerts - also called in /datum/hud/show_hud() because it's needed there diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm index bd06e0eb13d..65e188512d5 100644 --- a/code/datums/helper_datums/teleport.dm +++ b/code/datums/helper_datums/teleport.dm @@ -139,7 +139,7 @@ if(isliving(teleatom)) var/mob/living/L = teleatom if(L.buckled) - L.buckled.unbuckle_mob() + L.buckled.unbuckle_mob(L, force = TRUE) destarea.Entered(teleatom) diff --git a/code/datums/spells/area_teleport.dm b/code/datums/spells/area_teleport.dm index 70825f5195e..023939c2747 100644 --- a/code/datums/spells/area_teleport.dm +++ b/code/datums/spells/area_teleport.dm @@ -56,7 +56,7 @@ return if(target && target.buckled) - target.buckled.unbuckle_mob() + target.buckled.unbuckle_mob(target, force = TRUE) var/list/tempL = L var/attempt = null diff --git a/code/datums/spells/devil.dm b/code/datums/spells/devil.dm index 925b54d5e3c..12e2a44a8c1 100644 --- a/code/datums/spells/devil.dm +++ b/code/datums/spells/devil.dm @@ -131,14 +131,6 @@ playsound(get_turf(src), 'sound/misc/enter_blood.ogg', 100, 1, -1) var/obj/effect/dummy/slaughter/s_holder = new(loc) ExtinguishMob() - if(buckled) - buckled.unbuckle_mob(src,force=1) - if(has_buckled_mobs()) - unbuckle_mob() - if(pulledby) - pulledby.stop_pulling() - if(pulling) - stop_pulling() forceMove(s_holder) holder = s_holder notransform = FALSE diff --git a/code/datums/weather/weather_types/floor_is_lava.dm b/code/datums/weather/weather_types/floor_is_lava.dm index 72f49ad5057..9f98a481dbf 100644 --- a/code/datums/weather/weather_types/floor_is_lava.dm +++ b/code/datums/weather/weather_types/floor_is_lava.dm @@ -26,8 +26,10 @@ /datum/weather/floor_is_lava/weather_act(mob/living/L) if(issilicon(L)) return + if(istype(L.buckled, /obj/structure/bed)) + return for(var/obj/structure/O in L.loc) - if(O.density || O.buckled_mob && istype(O, /obj/structure/bed)) + if(O.density) return if(L.loc.density) return diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index cb7bc3037b2..bfb2eb1d214 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -41,6 +41,7 @@ . = ..() /atom/movable/Destroy() + unbuckle_all_mobs(force = TRUE) if(loc) loc.handle_atom_del(src) for(var/atom/movable/AM in contents) @@ -109,7 +110,7 @@ log_game("DEBUG:[src]'s pull on [pullee] wasn't broken despite [pullee] being in [pullee.loc]. Pull stopped manually.") stop_pulling() return - if(pulling.anchored) + if(pulling.anchored || pulling.move_resist > move_force) stop_pulling() return if(pulledby && moving_diagonally != FIRST_DIAG_STEP && get_dist(src, pulledby) > 1) //separated from our puller and not in the middle of a diagonal move. @@ -123,6 +124,7 @@ if(force < (move_resist * MOVE_FORCE_PULL_RATIO)) return FALSE return TRUE + // Used in shuttle movement and AI eye stuff. // Primarily used to notify objects being moved by a shuttle/bluespace fuckup. /atom/movable/proc/setLoc(var/T, var/teleported=0) @@ -200,7 +202,7 @@ src.move_speed = world.time - src.l_move_time src.l_move_time = world.time - if(. && buckled_mob && !handle_buckled_mob_movement(loc, direct)) //movement failed due to buckled mob + if(. && has_buckled_mobs() && !handle_buckled_mob_movement(loc, direct)) //movement failed due to buckled mob . = 0 // Called after a successful Move(). By this point, we've already moved @@ -270,8 +272,10 @@ /mob/living/forceMove(atom/destination) if(buckled) addtimer(CALLBACK(src, .proc/check_buckled), 1, TIMER_UNIQUE) - if(buckled_mob) - addtimer(CALLBACK(buckled_mob, .proc/check_buckled), 1, TIMER_UNIQUE) + if(has_buckled_mobs()) + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + addtimer(CALLBACK(buckled_mob, .proc/check_buckled), 1, TIMER_UNIQUE) if(pulling) addtimer(CALLBACK(src, .proc/check_pull), 1, TIMER_UNIQUE) . = ..() @@ -423,12 +427,14 @@ return TRUE /atom/movable/proc/handle_buckled_mob_movement(newloc,direct) - if(!buckled_mob.Move(newloc, direct)) - loc = buckled_mob.loc - last_move = buckled_mob.last_move - inertia_dir = last_move - buckled_mob.inertia_dir = last_move - return 0 + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + if(!buckled_mob.Move(newloc, direct)) + forceMove(buckled_mob.loc) + last_move = buckled_mob.last_move + inertia_dir = last_move + buckled_mob.inertia_dir = last_move + return 0 return 1 /atom/movable/proc/force_pushed(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction) @@ -448,7 +454,7 @@ return FALSE /atom/movable/CanPass(atom/movable/mover, turf/target, height=1.5) - if(buckled_mob == mover) + if(mover in buckled_mobs) return 1 return ..() diff --git a/code/game/gamemodes/miniantags/slaughter/bloodcrawl.dm b/code/game/gamemodes/miniantags/slaughter/bloodcrawl.dm index 2c34503781e..1ea0539620a 100644 --- a/code/game/gamemodes/miniantags/slaughter/bloodcrawl.dm +++ b/code/game/gamemodes/miniantags/slaughter/bloodcrawl.dm @@ -35,8 +35,6 @@ animation.dir = dir ExtinguishMob() - if(buckled) - buckled.unbuckle_mob() if(pulling && bloodcrawl == BLOODCRAWL_EAT) if(istype(pulling, /mob/living/)) var/mob/living/victim = pulling @@ -50,8 +48,9 @@ kidnapped = victim stop_pulling() flick("jaunt",animation) - loc = holder - holder = holder + + src.holder = holder + forceMove(holder) if(kidnapped) to_chat(src, "You begin to feast on [kidnapped]. You can not move while you are doing this.") diff --git a/code/game/gamemodes/shadowling/shadowling_abilities.dm b/code/game/gamemodes/shadowling/shadowling_abilities.dm index 276f8d2eb1f..1671c4a03b0 100644 --- a/code/game/gamemodes/shadowling/shadowling_abilities.dm +++ b/code/game/gamemodes/shadowling/shadowling_abilities.dm @@ -45,14 +45,14 @@ if(M in view_or_range(range, user, "view")) targets += M - + if(!targets.len) //doesn't waste the spell revert_cast(user) return perform(targets, user = user) return - + /obj/effect/proc_holder/spell/targeted/glare/cast(list/targets, mob/user = usr) for(var/mob/living/carbon/human/target in targets) @@ -139,8 +139,6 @@ target.ExtinguishMob() var/turf/T = get_turf(target) target.forceMove(T) //to properly move the mob out of a potential container - if(target.buckled) - target.buckled.unbuckle_mob() if(target.pulledby) target.pulledby.stop_pulling() target.stop_pulling() @@ -543,7 +541,7 @@ to_chat(user, "You must stand next to an APC to drain it!") charge_counter = charge_max return - + if(target_apc.cell?.charge == 0) to_chat(user, "APC must have a power to drain!") charge_counter = charge_max diff --git a/code/game/gamemodes/vampire/vampire_powers.dm b/code/game/gamemodes/vampire/vampire_powers.dm index 7e1a375f15d..7db238533be 100644 --- a/code/game/gamemodes/vampire/vampire_powers.dm +++ b/code/game/gamemodes/vampire/vampire_powers.dm @@ -424,8 +424,6 @@ var/jaunt_duration = 50 //in deciseconds /obj/effect/proc_holder/spell/vampire/self/jaunt/cast(list/targets, mob/user = usr) - if(user.buckled) - user.buckled.unbuckle_mob() spawn(0) var/mob/living/U = user var/originalloc = get_turf(user.loc) @@ -439,8 +437,6 @@ animation.layer = 5 animation.master = holder U.ExtinguishMob() - if(user.buckled) - user.buckled.unbuckle_mob() flick("liquify", animation) user.forceMove(holder) user.client.eye = holder @@ -513,8 +509,6 @@ perform(turfs, user = user) /obj/effect/proc_holder/spell/vampire/shadowstep/cast(list/targets, mob/user = usr) - if(usr.buckled) - user.buckled.unbuckle_mob() spawn(0) var/turf/picked = pick(targets) @@ -522,8 +516,6 @@ return var/mob/living/U = user U.ExtinguishMob() - if(user.buckled) - user.buckled.unbuckle_mob() var/atom/movable/overlay/animation = new /atom/movable/overlay(get_turf(user)) animation.name = user.name animation.density = 0 diff --git a/code/game/machinery/OpTable.dm b/code/game/machinery/OpTable.dm index af73a13f27c..de15a26264a 100644 --- a/code/game/machinery/OpTable.dm +++ b/code/game/machinery/OpTable.dm @@ -12,7 +12,7 @@ var/strapped = 0.0 var/obj/machinery/computer/operating/computer = null - buckle_lying = 90 + buckle_lying = -1 var/no_icon_updates = 0 //set this to 1 if you don't want the icons ever changing var/list/injected_reagents = list() var/reagent_target_amount = 1 diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm index 8f542a2ea3c..56618164bbb 100644 --- a/code/game/machinery/portable_turret.dm +++ b/code/game/machinery/portable_turret.dm @@ -554,7 +554,10 @@ var/list/turret_icons if(istype(A, /obj/vehicle)) var/obj/vehicle/T = A - assess_and_assign(T.buckled_mob, targets, secondarytargets) + if(T.has_buckled_mobs()) + for(var/m in T.buckled_mobs) + var/mob/living/buckled_mob = m + assess_and_assign(buckled_mob, targets, secondarytargets) if(isliving(A)) var/mob/living/C = A diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm index a89be1c211e..72652958e7c 100644 --- a/code/game/objects/buckling.dm +++ b/code/game/objects/buckling.dm @@ -1,80 +1,103 @@ - - /atom/movable - var/can_buckle = 0 - var/buckle_lying = -1 //bed-like behaviour, forces mob.lying = buckle_lying if != -1 //except -1 actually means "rotate 90 degrees to the left" as it is used by 1*buckle_lying. + var/can_buckle = FALSE + var/buckle_lying = -1 //bed-like behaviour, forces mob.lying = buckle_lying if != -1 var/buckle_requires_restraints = 0 //require people to be handcuffed before being able to buckle. eg: pipes - var/mob/living/buckled_mob = null + var/list/buckled_mobs = null //list() var/buckle_offset = 0 - + var/max_buckled_mobs = 1 + var/buckle_prevents_pull = FALSE //Interaction /atom/movable/attack_hand(mob/living/user) . = ..() - if(can_buckle && buckled_mob) - return user_unbuckle_mob(user) - -/atom/movable/attack_robot(mob/living/user) - . = ..() - if(can_buckle && buckled_mob && Adjacent(user)) // attack_robot is called on all ranges, so the Adjacent check is needed - return user_unbuckle_mob(user) + if(can_buckle && has_buckled_mobs()) + if(buckled_mobs.len > 1) + var/unbuckled = input(user, "Who do you wish to unbuckle?", "Unbuckle Who?") as null|mob in buckled_mobs + if(user_unbuckle_mob(unbuckled,user)) + return 1 + else + if(user_unbuckle_mob(buckled_mobs[1], user)) + return 1 /atom/movable/MouseDrop_T(mob/living/M, mob/living/user) . = ..() - if(can_buckle && istype(M)) - return user_buckle_mob(M, user) - - -//Cleanup -/atom/movable/Destroy() - . = ..() - unbuckle_mob() + if(can_buckle && istype(M) && istype(user)) + if(user_buckle_mob(M, user)) + return 1 /atom/movable/proc/has_buckled_mobs() - if(buckled_mob) + if(!buckled_mobs) + return FALSE + if(buckled_mobs.len) return TRUE - return FALSE //procs that handle the actual buckling and unbuckling -/atom/movable/proc/buckle_mob(mob/living/M, force = 0) - if((!can_buckle && !force)|| !istype(M) || (M.loc != loc) || M.buckled || M.buckled_mob || buckled_mob || (buckle_requires_restraints && !M.restrained()) || M == src) - return 0 +/atom/movable/proc/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE) + if(!buckled_mobs) + buckled_mobs = list() - if((isslime(M) || isAI(M)) && !force) + if(!istype(M)) + return FALSE + + if(check_loc && M.loc != loc) + return FALSE + + if((!can_buckle && !force) || M.buckled || (buckled_mobs.len >= max_buckled_mobs) || (buckle_requires_restraints && !M.restrained()) || M == src) + return FALSE + M.buckling = src + if(!M.can_buckle() && !force) if(M == usr) - to_chat(M, "You are unable to buckle yourself to the [src]!") + to_chat(M, "You are unable to buckle yourself to [src]!") else - to_chat(usr, "You are unable to buckle [M] to the [src]!") - return 0 + to_chat(usr, "You are unable to buckle [M] to [src]!") + M.buckling = null + return FALSE + if(M.pulledby) + if(buckle_prevents_pull) + M.pulledby.stop_pulling() + + if(!check_loc && M.loc != loc) + M.forceMove(loc) + + M.buckling = null M.buckled = src - M.dir = dir - buckled_mob = M + M.setDir(dir) + buckled_mobs |= M M.update_canmove() + M.throw_alert("buckled", /obj/screen/alert/restrained/buckled) post_buckle_mob(M) - M.throw_alert("buckled", /obj/screen/alert/restrained/buckled, new_master = src) - return 1 -/obj/buckle_mob(mob/living/M, force = 0) + SEND_SIGNAL(src, COMSIG_MOVABLE_BUCKLE, M, force) + return TRUE + +/obj/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE) . = ..() if(.) if(burn_state == ON_FIRE) //Sets the mob on fire if you buckle them to a burning atom/movableect M.adjust_fire_stacks(1) M.IgniteMob() -/atom/movable/proc/unbuckle_mob(force = FALSE) - if(buckled_mob && buckled_mob.buckled == src && (buckled_mob.can_unbuckle(usr) || force)) +/atom/movable/proc/unbuckle_mob(mob/living/buckled_mob, force = FALSE) + if(istype(buckled_mob) && buckled_mob.buckled == src && (buckled_mob.can_unbuckle() || force)) . = buckled_mob buckled_mob.buckled = null buckled_mob.anchored = initial(buckled_mob.anchored) buckled_mob.update_canmove() buckled_mob.clear_alert("buckled") - buckled_mob = null + buckled_mobs -= buckled_mob + SEND_SIGNAL(src, COMSIG_MOVABLE_UNBUCKLE, buckled_mob, force) post_unbuckle_mob(.) -//Handle any extras after buckling/unbuckling -//Called on buckle_mob() and unbuckle_mob() +/atom/movable/proc/unbuckle_all_mobs(force = FALSE) + if(!has_buckled_mobs()) + return + for(var/m in buckled_mobs) + unbuckle_mob(m, force) + +//Handle any extras after buckling +//Called on buckle_mob() /atom/movable/proc/post_buckle_mob(mob/living/M) return @@ -83,36 +106,31 @@ return //Wrapper procs that handle sanity and user feedback -/atom/movable/proc/user_buckle_mob(mob/living/M, mob/user) - if(!in_range(user, src) || user.stat || user.restrained()) - return +/atom/movable/proc/user_buckle_mob(mob/living/M, mob/user, check_loc = TRUE) + if(!in_range(user, src) || !isturf(user.loc) || user.incapacitated() || M.anchored) + return FALSE add_fingerprint(user) - - if(buckle_mob(M)) + . = buckle_mob(M, check_loc = check_loc) + if(.) if(M == user) - M.visible_message(\ - "[M] buckles themself to [src].",\ + M.visible_message("[M] buckles [M.p_them()]self to [src].",\ "You buckle yourself to [src].",\ "You hear metal clanking.") else - M.visible_message(\ - "[user] buckles [M] to [src]!",\ + M.visible_message("[user] buckles [M] to [src]!",\ "[user] buckles you to [src]!",\ "You hear metal clanking.") - return 1 -/atom/movable/proc/user_unbuckle_mob(mob/user) - var/mob/living/M = unbuckle_mob() +/atom/movable/proc/user_unbuckle_mob(mob/living/buckled_mob, mob/user) + var/mob/living/M = unbuckle_mob(buckled_mob) if(M) if(M != user) - M.visible_message(\ - "[user] unbuckles [M] from [src].",\ + M.visible_message("[user] unbuckles [M] from [src].",\ "[user] unbuckles you from [src].",\ "You hear metal clanking.") else - M.visible_message(\ - "[M] unbuckles themselves from [src].",\ + M.visible_message("[M] unbuckles [M.p_them()]self from [src].",\ "You unbuckle yourself from [src].",\ "You hear metal clanking.") add_fingerprint(user) @@ -120,4 +138,4 @@ /mob/living/proc/check_buckled() if(buckled && !(buckled in loc)) - buckled.unbuckle_mob(src, force=1) + buckled.unbuckle_mob(src, force = TRUE) \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implantchair.dm b/code/game/objects/items/weapons/implants/implantchair.dm index 314077db68e..cef14d28796 100644 --- a/code/game/objects/items/weapons/implants/implantchair.dm +++ b/code/game/objects/items/weapons/implants/implantchair.dm @@ -78,7 +78,7 @@ if(!ismob(G.affecting)) return var/mob/M = G.affecting - if(M.buckled_mob) + if(M.has_buckled_mobs()) to_chat(usr, "[M] will not fit into [src] because [M.p_they()] [M.p_have()] a slime latched onto [M.p_their()] head.") return if(put_mob(M)) diff --git a/code/game/objects/items/weapons/scrolls.dm b/code/game/objects/items/weapons/scrolls.dm index ccee6c18feb..696d54cc3bf 100644 --- a/code/game/objects/items/weapons/scrolls.dm +++ b/code/game/objects/items/weapons/scrolls.dm @@ -51,7 +51,7 @@ if(!A) return - + var/area/thearea = teleportlocs[A] if(user.stat || user.restrained()) @@ -83,7 +83,7 @@ return if(user && user.buckled) - user.buckled.unbuckle_mob() + user.buckled.unbuckle_mob(user, force = TRUE) var/list/tempL = L var/attempt = null diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm index 4a2dadffcc7..965819dd436 100644 --- a/code/game/objects/structures/crates_lockers/crates.dm +++ b/code/game/objects/structures/crates_lockers/crates.dm @@ -69,7 +69,7 @@ continue if(istype(O, /obj/structure/bed)) //This is only necessary because of rollerbeds and swivel chairs. var/obj/structure/bed/B = O - if(B.buckled_mob) + if(B.has_buckled_mobs()) continue O.forceMove(src) itemcount++ @@ -161,7 +161,7 @@ if(C.use(15)) to_chat(user, "You rig [src].") rigged = TRUE - else + else to_chat(user, "You need atleast 15 wires to rig [src]!") return else if(istype(W, /obj/item/radio/electropack)) diff --git a/code/game/objects/structures/electricchair.dm b/code/game/objects/structures/electricchair.dm index dcbc7c017bb..b8f0d6c5cb5 100644 --- a/code/game/objects/structures/electricchair.dm +++ b/code/game/objects/structures/electricchair.dm @@ -71,11 +71,12 @@ flick("echair_shock", src) do_sparks(12, 1, src) visible_message("The electric chair went off!", "You hear a deep sharp shock!") - if(buckled_mob) - buckled_mob.electrocute_act(110, src, 1) - to_chat(buckled_mob, "You feel a deep shock course through your body!") - spawn(1) + if(has_buckled_mobs()) + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m buckled_mob.electrocute_act(110, src, 1) + to_chat(buckled_mob, "You feel a deep shock course through your body!") + spawn(1) + buckled_mob.electrocute_act(110, src, 1) A.power_light = light - A.updateicon() - return + A.updateicon() \ No newline at end of file diff --git a/code/game/objects/structures/guillotine.dm b/code/game/objects/structures/guillotine.dm index 30429e2ca2c..6d32aec248e 100644 --- a/code/game/objects/structures/guillotine.dm +++ b/code/game/objects/structures/guillotine.dm @@ -28,6 +28,10 @@ var/force_clap = FALSE //You WILL clap if I want you to var/current_action = 0 // What's currently happening to the guillotine +/obj/structure/guillotine/Initialize(mapload) + LAZYINITLIST(buckled_mobs) + return ..() + /obj/structure/guillotine/examine(mob/user) ..() @@ -84,7 +88,7 @@ else current_action = 0 else - unbuckle_mob() + unbuckle_all_mobs() else blade_status = GUILLOTINE_BLADE_MOVING icon_state = "guillotine_drop" @@ -97,7 +101,7 @@ /obj/structure/guillotine/proc/drop_blade(mob/user) if(has_buckled_mobs() && blade_sharpness) - var/mob/living/carbon/human/H = buckled_mob + var/mob/living/carbon/human/H = buckled_mobs[1] if(!H) blade_status = GUILLOTINE_BLADE_DROPPED @@ -116,7 +120,7 @@ head.droplimb() add_attack_logs(user, H, "beheaded with [src]") H.regenerate_icons() - unbuckle_mob() + unbuckle_all_mobs() kill_count += 1 var/blood_overlay = "bloody" @@ -219,7 +223,7 @@ else return ..() -/obj/structure/guillotine/buckle_mob(mob/living/M, force = 0) +/obj/structure/guillotine/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE) if(!anchored) to_chat(usr, "The [src] needs to be wrenched to the floor!") return FALSE @@ -232,15 +236,19 @@ to_chat(usr, "You need to raise the blade before buckling someone in!") return FALSE - if(..()) - M.pixel_y -= GUILLOTINE_HEAD_OFFSET // Offset their body so it looks like they're in the guillotine - M.layer += GUILLOTINE_LAYER_DIFF + return ..(M, force, FALSE) -/obj/structure/guillotine/unbuckle_mob(force = 0) - if(buckled_mob) - buckled_mob.pixel_y += GUILLOTINE_HEAD_OFFSET // Move their body back - buckled_mob.layer -= GUILLOTINE_LAYER_DIFF - . = ..() +/obj/structure/guillotine/post_buckle_mob(mob/living/M) + if(!ishuman(M)) + return + M.pixel_y += -GUILLOTINE_HEAD_OFFSET // Offset their body so it looks like they're in the guillotine + M.layer += GUILLOTINE_LAYER_DIFF + ..() + +/obj/structure/guillotine/post_unbuckle_mob(mob/living/M) + M.pixel_y -= -GUILLOTINE_HEAD_OFFSET // Move their body back + M.layer -= GUILLOTINE_LAYER_DIFF + ..() #undef GUILLOTINE_BLADE_MAX_SHARP #undef GUILLOTINE_DECAP_MIN_SHARP diff --git a/code/game/objects/structures/kitchen_spike.dm b/code/game/objects/structures/kitchen_spike.dm index 05f7f326898..e38af14ecc4 100644 --- a/code/game/objects/structures/kitchen_spike.dm +++ b/code/game/objects/structures/kitchen_spike.dm @@ -35,14 +35,20 @@ desc = "A spike for collecting meat from animals." density = 1 anchored = 1 - buckle_lying = 0 - can_buckle = 1 + buckle_lying = FALSE + can_buckle = TRUE +//ATTACK HAND IGNORING PARENT RETURN VALUE +/obj/structure/kitchenspike/attack_hand(mob/user) + if(has_buckled_mobs()) + for(var/mob/living/L in buckled_mobs) + user_unbuckle_mob(L, user) + else + ..() - -/obj/structure/kitchenspike/attackby(obj/item/grab/G as obj, mob/user as mob) +/obj/structure/kitchenspike/attackby(obj/item/grab/G, mob/user) if(istype(G, /obj/item/crowbar)) - if(!buckled_mob) + if(!has_buckled_mobs()) playsound(loc, G.usesound, 100, 1) if(do_after(user, 20 * G.toolspeed, target = src)) to_chat(user, "You pry the spikes out of the frame.") @@ -55,11 +61,11 @@ return if(!istype(G, /obj/item/grab) || !G.affecting) return - if(buckled_mob) + if(has_buckled_mobs()) to_chat(user, "The spike already has something on it, finish collecting its meat first!") else if(isliving(G.affecting)) - if(!buckled_mob) + if(!has_buckled_mobs()) if(do_mob(user, src, 120)) if(spike(G.affecting)) G.affecting.visible_message("[user] slams [G.affecting] onto the meat spike!", "[user] slams you onto the meat spike!", "You hear a squishy wet noise.") @@ -68,56 +74,50 @@ to_chat(user, "You can't use that on the spike!") return -/obj/structure/kitchenspike/proc/spike(var/mob/living/victim) +/obj/structure/kitchenspike/proc/spike(mob/living/victim) if(!istype(victim)) - return + return FALSE - - if(buckled_mob) //to prevent spam/queing up attacks - return 0 + if(has_buckled_mobs()) //to prevent spam/queing up attacks + return FALSE if(victim.buckled) - return 0 - var/mob/living/H = victim + return FALSE playsound(loc, 'sound/effects/splat.ogg', 25, 1) - H.forceMove(loc) - H.emote("scream") - if(ishuman(H)) + victim.forceMove(drop_location()) + victim.emote("scream") + if(ishuman(victim)) + var/mob/living/carbon/human/H = victim H.add_splatter_floor() - H.adjustBruteLoss(30) - H.buckled = src - H.dir = 2 - buckled_mob = H - var/matrix/m180 = matrix() + victim.adjustBruteLoss(30) + victim.setDir(2) + buckle_mob(victim, force = TRUE) + var/matrix/m180 = matrix(victim.transform) m180.Turn(180) - animate(H, transform = m180, time = 3) - H.pixel_y = H.get_standard_pixel_y_offset(180) - return 1 - + animate(victim, transform = m180, time = 3) + victim.pixel_y = victim.get_standard_pixel_y_offset(180) + return TRUE /obj/structure/kitchenspike/user_buckle_mob(mob/living/M, mob/living/user) //Don't want them getting put on the rack other than by spiking return -/obj/structure/kitchenspike/user_unbuckle_mob(mob/living/carbon/human/user) - if(buckled_mob && buckled_mob.buckled == src) +/obj/structure/kitchenspike/user_unbuckle_mob(mob/living/buckled_mob, mob/living/carbon/human/user) + if(buckled_mob) var/mob/living/M = buckled_mob if(M != user) - M.visible_message(\ - "[user.name] tries to pull [M.name] free of the [src]!",\ - "[user.name] is trying to pull you off of [src], opening up fresh wounds!",\ + M.visible_message("[user] tries to pull [M] free of [src]!",\ + "[user] is trying to pull you off [src], opening up fresh wounds!",\ "You hear a squishy wet noise.") if(!do_after(user, 300, target = src)) if(M && M.buckled) - M.visible_message(\ - "[user.name] fails to free [M.name]!",\ - "[user.name] fails to pull you off of [src].") + M.visible_message("[user] fails to free [M]!",\ + "[user] fails to pull you off of [src].") return else - M.visible_message(\ - "[M.name] struggles to break free from the [src]!",\ - "You struggle to break free from the [src], exacerbating your wounds! (Stay still for two minutes.)",\ + M.visible_message("[M] struggles to break free from [src]!",\ + "You struggle to break free from [src], exacerbating your wounds! (Stay still for two minutes.)",\ "You hear a wet squishing noise..") M.adjustBruteLoss(30) if(!do_after(M, 1200, target = src)) @@ -126,13 +126,21 @@ return if(!M.buckled) return - var/matrix/m180 = matrix(M.transform) - m180.Turn(180) - animate(M, transform = m180, time = 3) - M.pixel_y = M.get_standard_pixel_y_offset(180) - M.adjustBruteLoss(30) - visible_message("[M] falls free of the [src]!") - unbuckle_mob() - M.emote("scream") - M.AdjustWeakened(10) + release_mob(M) +/obj/structure/kitchenspike/proc/release_mob(mob/living/M) + var/matrix/m180 = matrix(M.transform) + m180.Turn(180) + animate(M, transform = m180, time = 3) + M.pixel_y = M.get_standard_pixel_y_offset(180) + M.adjustBruteLoss(30) + src.visible_message(text("[M] falls free of [src]!")) + unbuckle_mob(M, force = TRUE) + M.emote("scream") + M.AdjustWeakened(10) + +/obj/structure/kitchenspike/Destroy() + if(has_buckled_mobs()) + for(var/mob/living/L in buckled_mobs) + release_mob(L) + return ..() \ No newline at end of file diff --git a/code/game/objects/structures/plasticflaps.dm b/code/game/objects/structures/plasticflaps.dm index 91e2d552859..c175dca567b 100644 --- a/code/game/objects/structures/plasticflaps.dm +++ b/code/game/objects/structures/plasticflaps.dm @@ -7,12 +7,6 @@ anchored = 1 layer = 4 armor = list(melee = 100, bullet = 80, laser = 80, energy = 100, bomb = 50, bio = 100, rad = 100) - var/list/mobs_can_pass = list( - /mob/living/carbon/slime, - /mob/living/simple_animal/mouse, - /mob/living/silicon/robot/drone, - /mob/living/simple_animal/bot/mulebot - ) var/state = PLASTIC_FLAPS_NORMAL /obj/structure/plasticflaps/examine(mob/user) @@ -66,43 +60,40 @@ return prob(60) var/obj/structure/bed/B = A - if(istype(A, /obj/structure/bed) && B.buckled_mob)//if it's a bed/chair and someone is buckled, it will not pass - return 0 + if(istype(A, /obj/structure/bed) && (B.has_buckled_mobs() || B.density))//if it's a bed/chair and is dense or someone is buckled, it will not pass + return FALSE if(istype(A, /obj/structure/closet/cardboard)) var/obj/structure/closet/cardboard/C = A if(C.move_delay) - return 0 + return FALSE - if(istype(A, /obj/vehicle)) //no vehicles - return 0 - - var/mob/living/M = A - if(istype(M)) - if(M.lying) - return ..() - for(var/mob_type in mobs_can_pass) - if(istype(A, mob_type)) - return ..() - if(istype(A, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - if(H.dna.species.is_small) - return ..() - return 0 + if(ismecha(A)) + return FALSE + else if(isliving(A)) // You Shall Not Pass! + var/mob/living/M = A + if(isbot(A)) //Bots understand the secrets + return TRUE + if(M.buckled && istype(M.buckled, /mob/living/simple_animal/bot/mulebot)) // mulebot passenger gets a free pass. + return TRUE + if(!M.lying && !M.ventcrawler && M.mob_size != MOB_SIZE_TINY) //If your not laying down, or a ventcrawler or a small creature, no pass. + return FALSE return ..() /obj/structure/plasticflaps/CanAStarPass(ID, to_dir, caller) - if(istype(caller, /mob/living)) - for(var/mob_type in mobs_can_pass) - if(istype(caller, mob_type)) - return 1 + if(isliving(caller)) + if(isbot(caller)) + return TRUE var/mob/living/M = caller - if(!M.ventcrawler && M.mob_size > MOB_SIZE_SMALL) - return 0 - return 1 + if(!M.ventcrawler && M.mob_size != MOB_SIZE_TINY) + return FALSE + var/atom/movable/M = caller + if(M && M.pulling) + return CanAStarPass(ID, to_dir, M.pulling) + return TRUE //diseases, stings, etc can pass /obj/structure/plasticflaps/ex_act(severity) switch(severity) diff --git a/code/game/objects/structures/stool_bed_chair_nest/alien_nests.dm b/code/game/objects/structures/stool_bed_chair_nest/alien_nests.dm index 33fe66c0f08..d3ee6c0bece 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/alien_nests.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/alien_nests.dm @@ -14,68 +14,67 @@ return ..() /obj/structure/bed/nest/user_unbuckle_mob(mob/living/user) - if(buckled_mob && buckled_mob.buckled == src) - var/mob/living/M = buckled_mob + if(has_buckled_mobs()) + for(var/buck in buckled_mobs) //breaking a nest releases all the buckled mobs, because the nest isn't holding them down anymore + var/mob/living/M = buck - if(user.get_int_organ(/obj/item/organ/internal/xenos/plasmavessel)) - unbuckle_mob() + if(user.get_int_organ(/obj/item/organ/internal/xenos/plasmavessel)) + unbuckle_mob(M) + add_fingerprint(user) + return + + if(M != user) + M.visible_message("[user.name] pulls [M.name] free from the sticky nest!",\ + "[user.name] pulls you free from the gelatinous resin.",\ + "You hear squelching...") + else + M.visible_message("[M.name] struggles to break free from the gelatinous resin!",\ + "You struggle to break free from the gelatinous resin... (Stay still for two minutes.)",\ + "You hear squelching...") + if(!do_after(M, 1200, target = src)) + if(M && M.buckled) + to_chat(M, "You fail to escape \the [src]!") + return + if(!M.buckled) + return + M.visible_message("[M.name] breaks free from the gelatinous resin!",\ + "You break free from the gelatinous resin!",\ + "You hear squelching...") + + unbuckle_mob(M) add_fingerprint(user) - return - - if(M != user) - M.visible_message(\ - "[user.name] pulls [M.name] free from the sticky nest!",\ - "[user.name] pulls you free from the gelatinous resin.",\ - "You hear squelching...") - - else - buckled_mob.visible_message(\ - "[buckled_mob.name] struggles to break free of the gelatinous resin...",\ - "You struggle to break free from the gelatinous resin... (This will take around 2 minutes and you need to stay still)",\ - "You hear squelching...") - if(!do_after(M, 1200, target = src)) - if(M && M.buckled) - to_chat(M, "You fail to escape \the [src]!") - return - if(!M.buckled) - return - M.visible_message(\ - "[M.name] breaks free from the gelatinous resin!",\ - "You break free from the gelatinous resin!",\ - "You hear squelching...") - unbuckle_mob() - add_fingerprint(user) /obj/structure/bed/nest/user_buckle_mob(mob/living/M, mob/living/user) - if( !ismob(M) || (get_dist(src, user) > 1) || (M.loc != src.loc) || user.restrained() || usr.stat || M.buckled || istype(user, /mob/living/silicon/pai) ) + if (!ismob(M) || (get_dist(src, user) > 1) || (M.loc != loc) || user.incapacitated() || M.buckled) return if(M.get_int_organ(/obj/item/organ/internal/xenos/plasmavessel)) return + if(!user.get_int_organ(/obj/item/organ/internal/xenos/plasmavessel)) return - unbuckle_mob() + if(has_buckled_mobs()) + unbuckle_all_mobs() if(buckle_mob(M)) - M.visible_message(\ - "[user.name] secretes a thick vile goo, securing [M.name] into [src]!",\ + M.visible_message("[user.name] secretes a thick vile goo, securing [M.name] into [src]!",\ "[user.name] drenches you in a foul-smelling resin, trapping you in [src]!",\ "You hear squelching...") /obj/structure/bed/nest/post_buckle_mob(mob/living/M) - if(M == buckled_mob) - M.pixel_y = 0 - M.pixel_x = initial(M.pixel_x) + 2 - M.layer = MOB_LAYER - 0.3 - overlays += nest_overlay - else - M.pixel_x = M.get_standard_pixel_x_offset(M.lying) - M.pixel_y = M.get_standard_pixel_y_offset(M.lying) - M.layer = initial(M.layer) - overlays -= nest_overlay + M.pixel_y = 0 + M.pixel_x = initial(M.pixel_x) + 2 + M.layer = BELOW_MOB_LAYER + add_overlay(nest_overlay) + +/obj/structure/bed/nest/post_unbuckle_mob(mob/living/M) + M.pixel_x = M.get_standard_pixel_x_offset(M.lying) + M.pixel_y = M.get_standard_pixel_y_offset(M.lying) + M.layer = initial(M.layer) + cut_overlay(nest_overlay) /obj/structure/bed/nest/attackby(obj/item/W as obj, mob/user as mob, params) user.changeNext_move(CLICK_CD_MELEE) diff --git a/code/game/objects/structures/stool_bed_chair_nest/bed.dm b/code/game/objects/structures/stool_bed_chair_nest/bed.dm index adbeffd600d..0802c212560 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/bed.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/bed.dm @@ -29,8 +29,6 @@ desc = "For prime comfort during psychiatric evaluations." icon_state = "psychbed" buildstackamount = 5 - can_buckle = TRUE - buckle_lying = TRUE /obj/structure/bed/alien name = "resting contraption" @@ -66,20 +64,23 @@ anchored = FALSE comfort = 1 -/obj/structure/bed/roller/attackby(obj/item/W as obj, mob/user as mob, params) +/obj/structure/bed/roller/attackby(obj/item/W, mob/user, params) if(istype(W, /obj/item/roller_holder)) - if(buckled_mob) - user_unbuckle_mob(user) + if(has_buckled_mobs()) + if(buckled_mobs.len > 1) + unbuckle_all_mobs() + user.visible_message("[user] unbuckles all creatures from [src].") + else + user_unbuckle_mob(buckled_mobs[1], user) else user.visible_message("[user] collapses \the [name].", "You collapse \the [name].") new/obj/item/roller(get_turf(src)) qdel(src) /obj/structure/bed/roller/post_buckle_mob(mob/living/M) - if(M == buckled_mob) - density = TRUE - icon_state = "up" - M.pixel_y = initial(M.pixel_y) + density = TRUE + icon_state = "up" + M.pixel_y = initial(M.pixel_y) /obj/structure/bed/roller/post_unbuckle_mob(mob/living/M) density = FALSE @@ -112,7 +113,7 @@ if(over_object == usr && Adjacent(usr) && (in_range(src, usr) || usr.contents.Find(src))) if(!ishuman(usr)) return - if(buckled_mob) + if(has_buckled_mobs()) return 0 usr.visible_message("[usr] collapses \the [name].", "You collapse \the [name].") new/obj/item/roller(get_turf(src)) diff --git a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm index 8192e39b85d..cdb502a695c 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm @@ -78,19 +78,20 @@ qdel(src) /obj/structure/chair/attack_tk(mob/user as mob) - if(buckled_mob) + if(!anchored || has_buckled_mobs() || !isturf(user.loc)) ..() else rotate() - return -/obj/structure/chair/proc/handle_rotation(direction) //making this into a seperate proc so office chairs can call it on Move() +/obj/structure/chair/proc/handle_rotation(direction) handle_layer() - if(buckled_mob) - buckled_mob.dir = dir + if(has_buckled_mobs()) + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + buckled_mob.setDir(direction) /obj/structure/chair/proc/handle_layer() - if(buckled_mob && dir == NORTH) + if(has_buckled_mobs() && dir == NORTH) layer = ABOVE_MOB_LAYER else layer = OBJ_LAYER @@ -229,24 +230,20 @@ /obj/structure/chair/office/Bump(atom/A) ..() - if(!buckled_mob) + if(!has_buckled_mobs()) return if(propelled) - var/mob/living/occupant = buckled_mob - unbuckle_mob() - occupant.throw_at(A, 3, propelled) - occupant.apply_effect(6, STUN, 0) - occupant.apply_effect(6, WEAKEN, 0) - occupant.apply_effect(6, STUTTER, 0) - playsound(src.loc, 'sound/weapons/punch1.ogg', 50, 1, -1) - if(istype(A, /mob/living)) - var/mob/living/victim = A - victim.apply_effect(6, STUN, 0) - victim.apply_effect(6, WEAKEN, 0) - victim.apply_effect(6, STUTTER, 0) - victim.take_organ_damage(10) - occupant.visible_message("[occupant] crashed into \the [A]!") + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + unbuckle_mob(buckled_mob) + buckled_mob.throw_at(A, 3, propelled) + buckled_mob.apply_effect(6, STUN, 0) + buckled_mob.apply_effect(6, WEAKEN, 0) + buckled_mob.apply_effect(6, STUTTER, 0) + buckled_mob.take_organ_damage(10) + playsound(loc, 'sound/weapons/punch1.ogg', 50, 1, -1) + buckled_mob.visible_message("[buckled_mob] crashed into [A]!") /obj/structure/chair/office/light icon_state = "officechair_white" diff --git a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm index e4e15d191e5..a837e632692 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm @@ -11,8 +11,10 @@ overlays = null var/image/O = image(icon = icon, icon_state = "[icon_state]_overlay", layer = FLY_LAYER, dir = src.dir) overlays += O - if(buckled_mob) - buckled_mob.dir = dir + if(has_buckled_mobs()) + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + buckled_mob.setDir(dir) /obj/structure/chair/wheelchair/relaymove(mob/user, direction) if(propelled) @@ -27,7 +29,8 @@ var/calculated_move_delay calculated_move_delay += 2 //wheelchairs are not infact sport bikes - if(buckled_mob) + if(has_buckled_mobs()) + var/mob/living/buckled_mob = buckled_mobs[1] if(buckled_mob.incapacitated()) return 0 @@ -69,15 +72,15 @@ /obj/structure/chair/wheelchair/Bump(atom/A) ..() - if(!buckled_mob) + if(!has_buckled_mobs()) return - + var/mob/living/buckled_mob = buckled_mobs[1] if(istype(A, /obj/machinery/door)) A.Bumped(buckled_mob) if(propelled) var/mob/living/occupant = buckled_mob - unbuckle_mob() + unbuckle_mob(occupant) occupant.throw_at(A, 3, propelled) @@ -114,9 +117,10 @@ var/calculated_move_delay calculated_move_delay = 0 //bikes are infact sport bikes - if(buckled_mob) + if(has_buckled_mobs()) + var/mob/living/buckled_mob = buckled_mobs[1] if(buckled_mob.incapacitated()) - unbuckle_mob() //if the rider is incapacitated, unbuckle them (they can't balance so they fall off) + unbuckle_mob(buckled_mob) //if the rider is incapacitated, unbuckle them (they can't balance so they fall off) return 0 var/mob/living/thedriver = user @@ -151,4 +155,4 @@ . = 0 else - . = 1 + . = 1 \ No newline at end of file diff --git a/code/game/turfs/simulated/floor/lava.dm b/code/game/turfs/simulated/floor/lava.dm index b2c29a5ee01..e35f9e86c68 100644 --- a/code/game/turfs/simulated/floor/lava.dm +++ b/code/game/turfs/simulated/floor/lava.dm @@ -84,17 +84,20 @@ var/mob/living/L = thing if(L.flying) continue //YOU'RE FLYING OVER IT + var/buckle_check = L.buckling + if(!buckle_check) + buckle_check = L.buckled + if(isobj(buckle_check)) + var/obj/O = buckle_check + if(O.resistance_flags & LAVA_PROOF) + continue + else if(isliving(buckle_check)) + var/mob/living/live = buckle_check + if("lava" in live.weather_immunities) + continue + if("lava" in L.weather_immunities) continue - if(L.buckled) - if(isobj(L.buckled)) - var/obj/O = L.buckled - if(O.resistance_flags & LAVA_PROOF) - continue - if(isliving(L.buckled)) //Goliath riding - var/mob/living/live = L.buckled - if("lava" in live.weather_immunities) - continue L.adjustFireLoss(20) if(L) //mobs turning into object corpses could get deleted here. diff --git a/code/modules/awaymissions/gateway.dm b/code/modules/awaymissions/gateway.dm index d6e72f1505c..699cbf5f803 100644 --- a/code/modules/awaymissions/gateway.dm +++ b/code/modules/awaymissions/gateway.dm @@ -248,23 +248,32 @@ var/obj/machinery/gateway/centerstation/the_gateway = null toggleoff() -/obj/machinery/gateway/centeraway/Bumped(atom/movable/M as mob|obj) +/obj/machinery/gateway/centeraway/Bumped(atom/movable/AM) if(!ready) return if(!active) return - if(istype(M, /mob/living/carbon)) - if(exilecheck(M)) + if(!stationgate || QDELETED(stationgate)) + return + if(isliving(AM)) + if(exilecheck(AM)) return - if(istype(M, /obj)) - if(M.can_buckle && M.has_buckled_mobs()) - if(exilecheck(M.buckled_mob)) + else + for(var/mob/living/L in AM.contents) + if(exilecheck(L)) + atom_say("Rejecting [AM]: Exile implant detected in contained lifeform.") return - for(var/mob/living/carbon/F in M) - if(exilecheck(F)) + if(AM.has_buckled_mobs()) + for(var/mob/living/L in AM.buckled_mobs) + if(exilecheck(L)) + atom_say("Rejecting [AM]: Exile implant detected in close proximity lifeform.") return - M.forceMove(get_step(stationgate.loc, SOUTH)) - M.dir = SOUTH + AM.forceMove(get_step(stationgate.loc, SOUTH)) + AM.setDir(SOUTH) + if(ismob(AM)) + var/mob/M = AM + if(M.client) + M.client.move_delay = max(world.time + 5, M.client.move_delay) /obj/machinery/gateway/centeraway/proc/exilecheck(var/mob/living/carbon/M) for(var/obj/item/implant/exile/E in M)//Checking that there is an exile implant in the contents diff --git a/code/modules/client/preference/preferences.dm b/code/modules/client/preference/preferences.dm index 7fce23b9e4c..36c3a9de5c5 100644 --- a/code/modules/client/preference/preferences.dm +++ b/code/modules/client/preference/preferences.dm @@ -2050,7 +2050,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts if("ghost_radio") toggles ^= CHAT_GHOSTRADIO - + if("ghost_pda") toggles ^= CHAT_GHOSTPDA @@ -2104,7 +2104,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts "High" = PARALLAX_HIGH, "Insane" = PARALLAX_INSANE ) - parallax = parallax_styles[input(user, "Pick a parallax style", "Parallax Style") as null|anything in parallax_styles] + parallax = parallax_styles[input(user, "Pick a parallax style", "Parallax Style") as null|anything in parallax_styles] if(parent && parent.mob && parent.mob.hud_used) parent.mob.hud_used.update_parallax_pref() @@ -2189,12 +2189,8 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts var/obj/item/organ/external/l_foot = character.get_organ("l_foot") var/obj/item/organ/external/r_foot = character.get_organ("r_foot") if(!l_foot && !r_foot) - var/obj/structure/chair/wheelchair/W = new /obj/structure/chair/wheelchair (character.loc) - character.buckled = W - character.update_canmove() - W.dir = character.dir - W.buckled_mob = character - W.add_fingerprint(character) + var/obj/structure/chair/wheelchair/W = new /obj/structure/chair/wheelchair(character.loc) + W.buckle_mob(character, TRUE) character.underwear = underwear character.undershirt = undershirt diff --git a/code/modules/clothing/spacesuits/chronosuit.dm b/code/modules/clothing/spacesuits/chronosuit.dm index fdd871a3448..700c88008e0 100644 --- a/code/modules/clothing/spacesuits/chronosuit.dm +++ b/code/modules/clothing/spacesuits/chronosuit.dm @@ -80,9 +80,7 @@ phaseanim.layer = FLY_LAYER phaseanim.master = user user.ExtinguishMob() - if(user.buckled) - user.buckled.unbuckle_mob() - user.loc = holder + user.forceMove(holder) flick("chronophase", phaseanim) spawn(7) if(user) diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index 1ab7fe58c2b..f654f052ab7 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -323,8 +323,6 @@ var/turf/picked = pick(turfs) if(!isturf(picked)) return - if(H.buckled) - H.buckled.unbuckle_mob() H.forceMove(picked) return 1 return 0 diff --git a/code/modules/crafting/craft.dm b/code/modules/crafting/craft.dm index aaed5f5672c..0bd4060c831 100644 --- a/code/modules/crafting/craft.dm +++ b/code/modules/crafting/craft.dm @@ -268,7 +268,8 @@ /datum/personal_crafting/proc/close(mob/user) var/datum/nanoui/ui = SSnanoui.get_open_ui(user, src, "main") - ui.close() + if(ui) + ui.close() /datum/personal_crafting/ui_data(mob/user) var/list/data = list() diff --git a/code/modules/events/spacevine.dm b/code/modules/events/spacevine.dm index 58579a893e2..c7330151b00 100644 --- a/code/modules/events/spacevine.dm +++ b/code/modules/events/spacevine.dm @@ -455,8 +455,8 @@ master = null mutations.Cut() set_opacity(0) - if(buckled_mob) - unbuckle_mob() + if(has_buckled_mobs()) + unbuckle_all_mobs(force = TRUE) return ..() /obj/structure/spacevine/proc/add_mutation(datum/spacevine_mutation/mutation) @@ -639,7 +639,7 @@ SM.on_grow(src) /obj/structure/spacevine/proc/entangle_mob() - if(!buckled_mob && prob(25)) + if(!has_buckled_mobs() && prob(25)) for(var/mob/living/V in loc) entangle(V) if(has_buckled_mobs()) diff --git a/code/modules/hydroponics/grown/towercap.dm b/code/modules/hydroponics/grown/towercap.dm index 156a426e202..c045b8a5b88 100644 --- a/code/modules/hydroponics/grown/towercap.dm +++ b/code/modules/hydroponics/grown/towercap.dm @@ -108,7 +108,7 @@ icon_state = "bonfire" density = FALSE anchored = TRUE - buckle_lying = 0 + buckle_lying = FALSE var/burning = 0 var/fire_stack_strength = 5 @@ -119,8 +119,8 @@ if(istype(W, /obj/item/stack/rods) && !can_buckle) var/obj/item/stack/rods/R = W R.use(1) - can_buckle = 1 - buckle_requires_restraints = 1 + can_buckle = TRUE + buckle_requires_restraints = TRUE to_chat(user, "You add a rod to [src].") var/image/U = image(icon='icons/obj/hydroponics/equipment.dmi',icon_state="bonfire_rod",pixel_y=16) underlays += U @@ -191,11 +191,10 @@ set_light(0) STOP_PROCESSING(SSobj, src) -/obj/structure/bonfire/buckle_mob(mob/living/M, force = 0) +/obj/structure/bonfire/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE) if(..()) M.pixel_y += 13 -/obj/structure/bonfire/unbuckle_mob(force=0) - if(buckled_mob) - buckled_mob.pixel_y -= 13 - . = ..() +/obj/structure/bonfire/unbuckle_mob(mob/living/buckled_mob, force = FALSE) + if(..()) + buckled_mob.pixel_y -= 13 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 5ca13a616c1..de52fe192da 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -398,12 +398,8 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump, if(ventcrawler) ventcrawlerlocal = ventcrawler - if(!ventcrawler) - if(ishuman(src)) - var/mob/living/carbon/human/H = src - ventcrawlerlocal = H.dna.species.ventcrawler - - if(!ventcrawlerlocal) return + if(!ventcrawlerlocal) + return if(stat) to_chat(src, "You must be conscious to do this!") @@ -413,8 +409,11 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump, to_chat(src, "You can't vent crawl while you're stunned!") return - if(buckled_mob) - to_chat(src, "You can't vent crawl with [buckled_mob] on you!") + if(has_buckled_mobs()) + to_chat(src, "You can't vent crawl with other creatures on you!") + return + if(buckled) + to_chat(src, "You can't vent crawl while buckled!") return if(ishuman(src)) var/mob/living/carbon/human/H = src @@ -450,6 +449,10 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump, if(!do_after(src, 45, target = src)) return + if(has_buckled_mobs()) + to_chat(src, "You can't vent crawl with other creatures on you!") + return + if(buckled) to_chat(src, "You cannot crawl into a vent while buckled to something!") return @@ -626,7 +629,7 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump, else if(I == handcuffed) handcuffed = null if(buckled && buckled.buckle_requires_restraints) - buckled.unbuckle_mob() + buckled.unbuckle_mob(src) update_handcuffed() else if(I == legcuffed) legcuffed = null @@ -934,7 +937,7 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump, var/obj/item/W = handcuffed handcuffed = null if(buckled && buckled.buckle_requires_restraints) - buckled.unbuckle_mob() + buckled.unbuckle_mob(src) update_handcuffed() if(client) client.screen -= W diff --git a/code/modules/mob/living/carbon/human/login.dm b/code/modules/mob/living/carbon/human/login.dm index 2964166e68f..4cc542ae1ad 100644 --- a/code/modules/mob/living/carbon/human/login.dm +++ b/code/modules/mob/living/carbon/human/login.dm @@ -3,7 +3,7 @@ overlays -= image('icons/effects/effects.dmi', icon_state = "zzz_glow") ..() - if(dna.species && dna.species.ventcrawler) + if(ventcrawler) to_chat(src, "You can ventcrawl! Use alt+click on vents to quickly travel about the station.") update_pipe_vision() return diff --git a/code/modules/mob/living/carbon/human/species/_species.dm b/code/modules/mob/living/carbon/human/species/_species.dm index 10b23dcfc82..d3ce27a4704 100644 --- a/code/modules/mob/living/carbon/human/species/_species.dm +++ b/code/modules/mob/living/carbon/human/species/_species.dm @@ -61,7 +61,7 @@ var/punchstunthreshold = 9 //damage at which punches from this race will stun //yes it should be to the attacked race but it's not useful that way even if it's logical var/list/default_genes = list() - var/ventcrawler = 0 //Determines if the mob can go through the vents. + var/ventcrawler = VENTCRAWLER_NONE //Determines if the mob can go through the vents. var/has_fine_manipulation = 1 // Can use small items. var/list/allowed_consumed_mobs = list() //If a species can consume mobs, put the type of mobs it can consume here. @@ -280,10 +280,12 @@ H.unEquip(thing) if(H.hud_used) H.hud_used.update_locked_slots() + H.ventcrawler = ventcrawler /datum/species/proc/on_species_loss(mob/living/carbon/human/H) if(H.butcher_results) //clear it out so we don't butcher a actual human. H.butcher_results = null + H.ventcrawler = initial(H.ventcrawler) /datum/species/proc/updatespeciescolor(mob/living/carbon/human/H) //Handles changing icobase for species that have multiple skin colors. return diff --git a/code/modules/mob/living/carbon/human/species/golem.dm b/code/modules/mob/living/carbon/human/species/golem.dm index e8451d61cbb..4b816f7ab5d 100644 --- a/code/modules/mob/living/carbon/human/species/golem.dm +++ b/code/modules/mob/living/carbon/human/species/golem.dm @@ -404,18 +404,11 @@ name = "Plastic Golem" prefix = "Plastic" special_names = null + ventcrawler = VENTCRAWLER_NUDE golem_colour = rgb(255, 255, 255) skinned_type = /obj/item/stack/sheet/plastic info_text = "As a Plastic Golem, you are capable of ventcrawling if you're naked." -/datum/species/golem/plastic/on_species_gain(mob/living/carbon/C, datum/species/old_species) - . = ..() - C.ventcrawler = VENTCRAWLER_NUDE - -/datum/species/golem/plastic/on_species_loss(mob/living/carbon/C) - . = ..() - C.ventcrawler = initial(C.ventcrawler) - //Immune to physical bullets and resistant to brute, but very vulnerable to burn damage. Dusts on death. /datum/species/golem/sand name = "Sand Golem" @@ -533,7 +526,7 @@ if(!isturf(picked)) return if(H.buckled) - H.buckled.unbuckle_mob() + H.buckled.unbuckle_mob(H, force = TRUE) do_teleport(H, picked) return TRUE @@ -617,7 +610,7 @@ if(!isturf(picked)) return if(H.buckled) - H.buckled.unbuckle_mob() + H.buckled.unbuckle_mob(H, force = TRUE) do_teleport(H, picked) last_teleport = world.time UpdateButtonIcon() //action icon looks unavailable diff --git a/code/modules/mob/living/carbon/human/species/monkey.dm b/code/modules/mob/living/carbon/human/species/monkey.dm index 4bfad7b15c9..a0980256718 100644 --- a/code/modules/mob/living/carbon/human/species/monkey.dm +++ b/code/modules/mob/living/carbon/human/species/monkey.dm @@ -17,7 +17,7 @@ can_craft = FALSE is_small = 1 has_fine_manipulation = 0 - ventcrawler = 1 + ventcrawler = VENTCRAWLER_NUDE show_ssd = 0 eyes = "blank_eyes" death_message = "lets out a faint chimper as it collapses and stops moving..." diff --git a/code/modules/mob/living/carbon/slime/slime.dm b/code/modules/mob/living/carbon/slime/slime.dm index 89e6393cd09..afd358ab99f 100644 --- a/code/modules/mob/living/carbon/slime/slime.dm +++ b/code/modules/mob/living/carbon/slime/slime.dm @@ -72,6 +72,16 @@ X.stored_slimes -= src return ..() +/mob/living/carbon/slime/can_unbuckle() + return FALSE + +/mob/living/carbon/slime/can_buckle() + return FALSE + +/mob/living/carbon/slime/get_mob_buckling_height(mob/seat) + if(..()) + return 3 + /mob/living/carbon/slime/regenerate_icons() icon_state = "[colour] [is_adult ? "adult" : "baby"] slime" overlays.len = 0 diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index df222fadf47..f659b4198d1 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -446,12 +446,7 @@ on_fire = 0 suiciding = 0 if(buckled) //Unbuckle the mob and clear the alerts. - buckled.buckled_mob = null - buckled = null - anchored = initial(anchored) - update_canmove() - clear_alert("buckled") - post_buckle_mob(src) + buckled.unbuckle_mob(src, force = TRUE) if(iscarbon(src)) var/mob/living/carbon/C = src @@ -637,11 +632,14 @@ START RESIST PROCS */////////////////////// +/mob/living/can_resist() + return !((next_move > world.time) || incapacitated(ignore_restraints = TRUE, ignore_lying = TRUE)) + /mob/living/verb/resist() set name = "Resist" set category = "IC" - if(!isliving(src) || next_move > world.time || stat || weakened || stunned || paralysis) + if(!can_resist()) return changeNext_move(CLICK_CD_RESIST) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index f624b7ab33d..e9cfac7ae0a 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -216,6 +216,9 @@ fire_stacks += L.fire_stacks IgniteMob() +/mob/living/can_be_pulled(user, grab_state, force) + return ..() && !(buckled && buckled.buckle_prevents_pull) + /mob/living/water_act(volume, temperature, source, method = TOUCH) . = ..() adjust_fire_stacks(-(volume * 0.2)) diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 023c03cd00a..9605ae186a7 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -1173,6 +1173,9 @@ var/list/ai_verbs_default = list( to_chat(src, "You have been downloaded to a mobile storage device. Remote device connection severed.") to_chat(user, "Transfer successful: [name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory.") +/mob/living/silicon/ai/can_buckle() + return FALSE + // Pass lying down or getting up to our pet human, if we're in a rig. /mob/living/silicon/ai/lay_down() set name = "Rest" diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index d9f1aac2757..d2e52c39197 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -124,6 +124,11 @@ securityActive2 = null return ..() +/mob/living/silicon/pai/can_unbuckle() + return FALSE + +/mob/living/silicon/pai/can_buckle() + return FALSE /mob/living/silicon/pai/movement_delay() . = ..() diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm index 1db149418c7..ef087c29b6d 100644 --- a/code/modules/mob/living/simple_animal/bot/mulebot.dm +++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm @@ -17,7 +17,7 @@ maxHealth = 50 damage_coeff = list(BRUTE = 0.5, BURN = 0.7, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) a_intent = INTENT_HARM //No swapping - buckle_lying = 0 + buckle_lying = FALSE mob_size = MOB_SIZE_LARGE radio_channel = "Supply" @@ -372,7 +372,7 @@ if(isobj(AM)) var/obj/O = AM - if(O.buckled_mob || (locate(/mob) in AM)) //can't load non crates objects with mobs buckled to it or inside it. + if(O.has_buckled_mobs() || (locate(/mob) in AM)) //can't load non crates objects with mobs buckled to it or inside it. buzz(SIGH) return @@ -398,19 +398,11 @@ return FALSE /mob/living/simple_animal/bot/mulebot/post_buckle_mob(mob/living/M) - if(M == buckled_mob) //post buckling - M.pixel_y = initial(M.pixel_y) + 9 - if(M.layer < layer) - M.layer = layer + 0.1 - - else //post unbuckling - reset_buckled_mob(M) + M.pixel_y = initial(M.pixel_y) + 9 + if(M.layer < layer) + M.layer = layer + 0.01 /mob/living/simple_animal/bot/mulebot/post_unbuckle_mob(mob/living/M) - . = ..() - reset_buckled_mob(M) - -/mob/living/simple_animal/bot/mulebot/proc/reset_buckled_mob(mob/living/M) load = null M.layer = initial(M.layer) M.pixel_y = initial(M.pixel_y) @@ -429,12 +421,13 @@ if(ismob(load)) var/mob/M = load M.reset_perspective(null) - unbuckle_mob() + unbuckle_all_mobs() if(load) load.forceMove(loc) load.pixel_y = initial(load.pixel_y) load.layer = initial(load.layer) + load.plane = initial(load.plane) if(dirn) var/turf/T = loc var/turf/newT = get_step(T,dirn) @@ -453,6 +446,7 @@ AM.forceMove(loc) AM.layer = initial(AM.layer) AM.pixel_y = initial(AM.pixel_y) + AM.plane = initial(AM.plane) if(ismob(AM)) var/mob/M = AM M.reset_perspective(null) diff --git a/code/modules/mob/living/simple_animal/hostile/floorcluwne.dm b/code/modules/mob/living/simple_animal/hostile/floorcluwne.dm index 244edaeedec..c3939e41395 100644 --- a/code/modules/mob/living/simple_animal/hostile/floorcluwne.dm +++ b/code/modules/mob/living/simple_animal/hostile/floorcluwne.dm @@ -313,7 +313,7 @@ if(T.density) forceMove(H.loc) if(H.buckled) - H.buckled.unbuckle_mob() + H.buckled.unbuckle_mob(H, force = TRUE) manifested = TRUE Manifest() to_chat(H, "You feel the floor closing in on your feet!") diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index c2d16069146..4e8da45a155 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -17,7 +17,7 @@ qdel(tkgrabbed_objects[I]) tkgrabbed_objects = null if(buckled) - buckled.unbuckle_mob() + buckled.unbuckle_mob(src, force = TRUE) if(viewing_alternate_appearances) for(var/datum/alternate_appearance/AA in viewing_alternate_appearances) AA.viewers -= src @@ -1192,31 +1192,52 @@ var/list/slot_equipment_priority = list( \ /mob/proc/handle_ventcrawl() return // Only living mobs can ventcrawl -//You can buckle on mobs if you're next to them since most are dense -/mob/buckle_mob(mob/living/M, force = 0) +/** + * Buckle to another mob + * + * You can buckle on mobs if you're next to them since most are dense + * + * Turns you to face the other mob too + */ +/mob/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE) if(M.buckled) return 0 var/turf/T = get_turf(src) if(M.loc != T) var/old_density = density - density = 0 + density = FALSE var/can_step = step_towards(M, T) density = old_density if(!can_step) return 0 return ..() -//Default buckling shift visual for mobs +///Call back post buckle to a mob to offset your visual height /mob/post_buckle_mob(mob/living/M) - if(M == buckled_mob) //post buckling - M.pixel_y = initial(M.pixel_y) + 9 - if(M.layer < layer) - M.layer = layer + 0.1 - else //post unbuckling - M.layer = initial(M.layer) - M.pixel_y = initial(M.pixel_y) + var/height = M.get_mob_buckling_height(src) + M.pixel_y = initial(M.pixel_y) + height + if(M.layer < layer) + M.layer = layer + 0.1 -/mob/proc/can_unbuckle(mob/user) +///Call back post unbuckle from a mob, (reset your visual height here) +/mob/post_unbuckle_mob(mob/living/M) + M.layer = initial(M.layer) + M.pixel_y = initial(M.pixel_y) + +///returns the height in pixel the mob should have when buckled to another mob. +/mob/proc/get_mob_buckling_height(mob/seat) + if(isliving(seat)) + var/mob/living/L = seat + if(L.mob_size <= MOB_SIZE_SMALL) //being on top of a small mob doesn't put you very high. + return 0 + return 9 + +///can the mob be buckled to something by default? +/mob/proc/can_buckle() + return 1 + +///can the mob be unbuckled from something by default? +/mob/proc/can_unbuckle() return 1 @@ -1307,6 +1328,10 @@ var/list/slot_equipment_priority = list( \ .["Gib"] = "?_src_=vars;gib=[UID()]" +///Can this mob resist (default FALSE) +/mob/proc/can_resist() + return FALSE //overridden in living.dm + /mob/proc/spin(spintime, speed) set waitfor = 0 var/D = dir diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index b378705becb..c4d4ef24ed6 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -74,7 +74,11 @@ var/a_intent = INTENT_HELP//Living var/m_intent = MOVE_INTENT_RUN//Living var/lastKnownIP = null + /// movable atoms buckled to this mob var/atom/movable/buckled = null//Living + /// movable atom we are buckled to + var/atom/movable/buckling + var/obj/item/l_hand = null//Living var/obj/item/r_hand = null//Living var/obj/item/back = null//Human/Monkey diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 7f78f58eb72..c45ff96df34 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -8,13 +8,13 @@ if(mover.checkpass(PASSMOB)) return 1 if(buckled == mover) - return 1 + return TRUE if(ismob(mover)) var/mob/moving_mob = mover if((other_mobs && moving_mob.other_mobs)) - return 1 - if(mover == buckled_mob) - return 1 + return TRUE + if(mover in buckled_mobs) + return TRUE return (!mover.density || !density || lying) @@ -362,10 +362,14 @@ /mob/proc/Move_Pulled(atom/A) if(!canmove || restrained() || !pulling) return - if(pulling.anchored) - return - if(!pulling.Adjacent(src)) + if(pulling.anchored || pulling.move_resist > move_force || !pulling.Adjacent(src)) + stop_pulling() return + if(isliving(pulling)) + var/mob/living/L = pulling + if(L.buckled && L.buckled.buckle_prevents_pull) //if they're buckled to something that disallows pulling, prevent it + stop_pulling() + return if(A == loc && pulling.density) return if(!Process_Spacemove(get_dir(pulling.loc, A))) diff --git a/code/modules/research/xenobiology/xenobio_camera.dm b/code/modules/research/xenobiology/xenobio_camera.dm index 2889a68c75b..785c03b13a1 100644 --- a/code/modules/research/xenobiology/xenobio_camera.dm +++ b/code/modules/research/xenobiology/xenobio_camera.dm @@ -92,17 +92,17 @@ potion_action.target = src potion_action.Grant(user) actions += potion_action - + if(hotkey_help) hotkey_help.target = src hotkey_help.Grant(user) actions += hotkey_help - RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_CTRL, .proc/XenoSlimeClickCtrl) - RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_ALT, .proc/XenoSlimeClickAlt) - RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_SHIFT, .proc/XenoSlimeClickShift) - RegisterSignal(user, COMSIG_XENO_TURF_CLICK_SHIFT, .proc/XenoTurfClickShift) - RegisterSignal(user, COMSIG_XENO_TURF_CLICK_CTRL, .proc/XenoTurfClickCtrl) + RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_CTRL, .proc/XenoSlimeClickCtrl) + RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_ALT, .proc/XenoSlimeClickAlt) + RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_SHIFT, .proc/XenoSlimeClickShift) + RegisterSignal(user, COMSIG_XENO_TURF_CLICK_SHIFT, .proc/XenoTurfClickShift) + RegisterSignal(user, COMSIG_XENO_TURF_CLICK_CTRL, .proc/XenoTurfClickCtrl) RegisterSignal(user, COMSIG_XENO_MONKEY_CLICK_CTRL, .proc/XenoMonkeyClickCtrl) if(!connected_recycler) @@ -112,12 +112,12 @@ connected_recycler.connected += src /obj/machinery/computer/camera_advanced/xenobio/remove_eye_control(mob/living/user) - UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_CTRL) - UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_ALT) - UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_SHIFT) - UnregisterSignal(user, COMSIG_XENO_TURF_CLICK_SHIFT) - UnregisterSignal(user, COMSIG_XENO_TURF_CLICK_CTRL) - UnregisterSignal(user, COMSIG_XENO_MONKEY_CLICK_CTRL) + UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_CTRL) + UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_ALT) + UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_SHIFT) + UnregisterSignal(user, COMSIG_XENO_TURF_CLICK_SHIFT) + UnregisterSignal(user, COMSIG_XENO_TURF_CLICK_CTRL) + UnregisterSignal(user, COMSIG_XENO_MONKEY_CLICK_CTRL) ..() /obj/machinery/computer/camera_advanced/xenobio/attack_hand(mob/user) @@ -197,7 +197,7 @@ break if(!S.ckey) if(S.buckled) - S.buckled.unbuckle_mob() + S.buckled.unbuckle_mob(S, force = TRUE) S.Feedstop() S.visible_message("[S] vanishes in a flash of light!") S.forceMove(X) @@ -240,7 +240,7 @@ var/mob/camera/aiEye/remote/xenobio/remote_eye = C.remote_control var/obj/machinery/computer/camera_advanced/xenobio/X = target var/obj/machinery/monkey_recycler/recycler = X.connected_recycler - + if(!recycler) to_chat(owner, "There is no connected monkey recycler. Use a multitool to link one.") return @@ -335,8 +335,9 @@ ..() //Pick up monkey -/mob/living/carbon/monkey/CtrlClick(mob/user) - SEND_SIGNAL(user, COMSIG_XENO_MONKEY_CLICK_CTRL, src) +/mob/living/carbon/human/CtrlClick(mob/user) + if(issmall(src)) + SEND_SIGNAL(user, COMSIG_XENO_MONKEY_CLICK_CTRL, src) ..() // Scans slime @@ -379,7 +380,7 @@ return if(!S.ckey) if(S.buckled) - S.buckled.unbuckle_mob() + S.buckled.unbuckle_mob(S, force = TRUE) S.Feedstop() S.visible_message("[S] vanishes in a flash of light!") S.forceMove(X) @@ -419,7 +420,7 @@ to_chat(user, "[X] now has [X.monkeys] monkeys left.") //Pick up monkey -/obj/machinery/computer/camera_advanced/xenobio/proc/XenoMonkeyClickCtrl(mob/living/user, mob/living/carbon/monkey/M) +/obj/machinery/computer/camera_advanced/xenobio/proc/XenoMonkeyClickCtrl(mob/living/user, mob/living/carbon/human/M) if(!cameranet.checkTurfVis(M.loc)) to_chat(user, "Target is not near a camera. Cannot proceed.") return diff --git a/code/modules/ruins/lavalandruin_code/fountain_hall.dm b/code/modules/ruins/lavalandruin_code/fountain_hall.dm index 3de758ac0c9..75e2b8d9aa3 100644 --- a/code/modules/ruins/lavalandruin_code/fountain_hall.dm +++ b/code/modules/ruins/lavalandruin_code/fountain_hall.dm @@ -12,7 +12,7 @@ return if(!has_buckled_mobs()) return - var/mob/living/L = buckled_mob + var/mob/living/L = locate() in buckled_mobs if(!L) return to_chat(user, "You attempt to sacrifice [L] by invoking the sacrificial ritual.") diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index 8c96837e9d5..783f8203857 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -594,7 +594,7 @@ if(ismob(AM)) var/mob/M = AM if(M.buckled) - M.buckled.unbuckle_mob(M, 1) + M.buckled.unbuckle_mob(M, force = TRUE) if(isliving(AM)) var/mob/living/L = AM L.stop_pulling() diff --git a/code/modules/vehicle/ambulance.dm b/code/modules/vehicle/ambulance.dm index 102b8895bf6..f10f9d9769c 100644 --- a/code/modules/vehicle/ambulance.dm +++ b/code/modules/vehicle/ambulance.dm @@ -58,8 +58,8 @@ AA.Remove(M) /obj/vehicle/ambulance/post_unbuckle_mob(mob/living/M) - . = ..() AA.Remove(M) + return ..() /obj/item/key/ambulance name = "ambulance key" @@ -69,20 +69,22 @@ /obj/vehicle/ambulance/handle_vehicle_offsets() ..() - if(buckled_mob) - switch(buckled_mob.dir) - if(SOUTH) - buckled_mob.pixel_x = 0 - buckled_mob.pixel_y = 7 - if(WEST) - buckled_mob.pixel_x = 13 - buckled_mob.pixel_y = 7 - if(NORTH) - buckled_mob.pixel_x = 0 - buckled_mob.pixel_y = 4 - if(EAST) - buckled_mob.pixel_x = -13 - buckled_mob.pixel_y = 7 + if(has_buckled_mobs()) + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + switch(buckled_mob.dir) + if(SOUTH) + buckled_mob.pixel_x = 0 + buckled_mob.pixel_y = 7 + if(WEST) + buckled_mob.pixel_x = 13 + buckled_mob.pixel_y = 7 + if(NORTH) + buckled_mob.pixel_x = 0 + buckled_mob.pixel_y = 4 + if(EAST) + buckled_mob.pixel_x = -13 + buckled_mob.pixel_y = 7 /obj/vehicle/ambulance/Move(newloc, Dir) var/oldloc = loc @@ -92,8 +94,10 @@ if(bed && get_dist(oldloc, loc) <= 2) bed.Move(oldloc) bed.dir = Dir - if(bed.buckled_mob) - bed.buckled_mob.dir = Dir + if(bed.has_buckled_mobs()) + for(var/m in bed.buckled_mobs) + var/mob/living/buckled_mob = m + buckled_mob.setDir(Dir) /obj/structure/bed/amb_trolley name = "ambulance train trolley" diff --git a/code/modules/vehicle/atv.dm b/code/modules/vehicle/atv.dm index a67310c8874..a78791fddea 100644 --- a/code/modules/vehicle/atv.dm +++ b/code/modules/vehicle/atv.dm @@ -16,10 +16,13 @@ atvcover.layer = MOB_LAYER + 0.1 /obj/vehicle/atv/post_buckle_mob(mob/living/M) - if(buckled_mob) - overlays += atvcover - else - overlays -= atvcover + add_overlay(atvcover) + return ..() + +/obj/vehicle/atv/post_unbuckle_mob(mob/living/M) + if(!has_buckled_mobs()) + cut_overlay(atvcover) + return ..() /obj/vehicle/atv/handle_vehicle_layer() if(dir == SOUTH) diff --git a/code/modules/vehicle/janicart.dm b/code/modules/vehicle/janicart.dm index 8ee2d71443a..0f4382c92d1 100644 --- a/code/modules/vehicle/janicart.dm +++ b/code/modules/vehicle/janicart.dm @@ -10,20 +10,22 @@ /obj/vehicle/janicart/handle_vehicle_offsets() ..() - if(buckled_mob) - switch(buckled_mob.dir) - if(NORTH) - buckled_mob.pixel_x = 0 - buckled_mob.pixel_y = 4 - if(EAST) - buckled_mob.pixel_x = -12 - buckled_mob.pixel_y = 7 - if(SOUTH) - buckled_mob.pixel_x = 0 - buckled_mob.pixel_y = 7 - if(WEST) - buckled_mob.pixel_x = 12 - buckled_mob.pixel_y = 7 + if(has_buckled_mobs()) + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + switch(buckled_mob.dir) + if(NORTH) + buckled_mob.pixel_x = 0 + buckled_mob.pixel_y = 4 + if(EAST) + buckled_mob.pixel_x = -12 + buckled_mob.pixel_y = 7 + if(SOUTH) + buckled_mob.pixel_x = 0 + buckled_mob.pixel_y = 7 + if(WEST) + buckled_mob.pixel_x = 12 + buckled_mob.pixel_y = 7 /obj/item/key/janitor diff --git a/code/modules/vehicle/motorcycle.dm b/code/modules/vehicle/motorcycle.dm index 3bcf98f2164..a79f8e3fa12 100644 --- a/code/modules/vehicle/motorcycle.dm +++ b/code/modules/vehicle/motorcycle.dm @@ -16,11 +16,14 @@ bikecover.layer = MOB_LAYER + 0.1 -obj/vehicle/motorcycle/post_buckle_mob(mob/living/M) - if(buckled_mob) - overlays += bikecover - else - overlays -= bikecover +/obj/vehicle/motorcycle/post_buckle_mob(mob/living/M) + add_overlay(bikecover) + return ..() + +/obj/vehicle/motorcycle/post_unbuckle_mob(mob/living/M) + if(!has_buckled_mobs()) + cut_overlay(bikecover) + return ..() /obj/vehicle/motorcycle/handle_vehicle_layer() diff --git a/code/modules/vehicle/speedbike.dm b/code/modules/vehicle/speedbike.dm index ac57e65b2e6..e1efe63bcbd 100644 --- a/code/modules/vehicle/speedbike.dm +++ b/code/modules/vehicle/speedbike.dm @@ -15,7 +15,7 @@ overlays += overlay /obj/vehicle/space/speedbike/Move(newloc,move_dir) - if(buckled_mob) + if(has_buckled_mobs()) new /obj/effect/temp_visual/dir_setting/speedbike_trail(loc) . = ..() @@ -29,21 +29,23 @@ pixel_y = 0 /obj/vehicle/space/speedbike/handle_vehicle_offsets() - if(buckled_mob) - buckled_mob.dir = dir - switch(dir) - if(NORTH) - buckled_mob.pixel_x = 0 - buckled_mob.pixel_y = -8 - if(SOUTH) - buckled_mob.pixel_x = 0 - buckled_mob.pixel_y = 4 - if(EAST) - buckled_mob.pixel_x = -10 - buckled_mob.pixel_y = 5 - if(WEST) - buckled_mob.pixel_x = 10 - buckled_mob.pixel_y = 5 + if(has_buckled_mobs()) + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + buckled_mob.setDir(dir) + switch(dir) + if(NORTH) + buckled_mob.pixel_x = 0 + buckled_mob.pixel_y = -8 + if(SOUTH) + buckled_mob.pixel_x = 0 + buckled_mob.pixel_y = 4 + if(EAST) + buckled_mob.pixel_x = -10 + buckled_mob.pixel_y = 5 + if(WEST) + buckled_mob.pixel_x = 10 + buckled_mob.pixel_y = 5 /obj/vehicle/space/speedbike/red icon_state = "speedbike_red" diff --git a/code/modules/vehicle/sportscar.dm b/code/modules/vehicle/sportscar.dm index 04ba5bdd2f5..f52f4b77a92 100644 --- a/code/modules/vehicle/sportscar.dm +++ b/code/modules/vehicle/sportscar.dm @@ -15,29 +15,33 @@ carcover = image("icons/vehicles/sportscar.dmi", "sportscar_cover") carcover.layer = MOB_LAYER + 0.1 - /obj/vehicle/car/post_buckle_mob(mob/living/M) - if(buckled_mob) - overlays += carcover - else - overlays -= carcover + add_overlay(carcover) + return ..() + +/obj/vehicle/car/post_unbuckle_mob(mob/living/M) + if(!has_buckled_mobs()) + cut_overlay(carcover) + return ..() /obj/vehicle/car/handle_vehicle_offsets() ..() - if(buckled_mob) - switch(buckled_mob.dir) - if(NORTH) - buckled_mob.pixel_x = 2 - buckled_mob.pixel_y = 20 - if(EAST) - buckled_mob.pixel_x = 20 - buckled_mob.pixel_y = 23 - if(SOUTH) - buckled_mob.pixel_x = 20 - buckled_mob.pixel_y = 27 - if(WEST) - buckled_mob.pixel_x = 34 - buckled_mob.pixel_y = 10 + if(has_buckled_mobs()) + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + switch(buckled_mob.dir) + if(NORTH) + buckled_mob.pixel_x = 2 + buckled_mob.pixel_y = 20 + if(EAST) + buckled_mob.pixel_x = 20 + buckled_mob.pixel_y = 23 + if(SOUTH) + buckled_mob.pixel_x = 20 + buckled_mob.pixel_y = 27 + if(WEST) + buckled_mob.pixel_x = 34 + buckled_mob.pixel_y = 10 /obj/vehicle/car/handle_vehicle_layer() diff --git a/code/modules/vehicle/vehicle.dm b/code/modules/vehicle/vehicle.dm index fc2ea3b4600..9b3a747b7ff 100644 --- a/code/modules/vehicle/vehicle.dm +++ b/code/modules/vehicle/vehicle.dm @@ -6,14 +6,14 @@ icon_state = "scooter" density = 1 anchored = 0 - can_buckle = 1 - buckle_lying = 0 + can_buckle = TRUE + buckle_lying = FALSE armor = list("melee" = 30, "bullet" = 30, "laser" = 30, "energy" = 0, "bomb" = 30, "bio" = 0, "rad" = 0) var/keytype = null //item typepath, if non-null an item of this type is needed in your hands to drive this vehicle var/next_vehicle_move = 0 //used for move delays var/vehicle_move_delay = 2 //tick delay between movements, lower = faster, higher = slower var/auto_door_open = TRUE - var/needs_gravity = 0//To allow non-space vehicles to move in no gravity or not, mostly for adminbus + var/needs_gravity = 0 //To allow non-space vehicles to move in no gravity or not, mostly for adminbus //Pixels var/generic_pixel_x = 0 //All dirs show this pixel_x for the driver var/generic_pixel_y = 0 //All dirs shwo this pixel_y for the driver @@ -37,25 +37,26 @@ //if they differ between directions, otherwise use the //generic variables /obj/vehicle/proc/handle_vehicle_offsets() - if(buckled_mob) - buckled_mob.dir = dir - buckled_mob.pixel_x = generic_pixel_x - buckled_mob.pixel_y = generic_pixel_y + if(has_buckled_mobs()) + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + buckled_mob.setDir(dir) + buckled_mob.pixel_x = generic_pixel_x + buckled_mob.pixel_y = generic_pixel_y /obj/vehicle/update_icon() return - //KEYS /obj/vehicle/proc/keycheck(mob/user) if(keytype) if(istype(user.l_hand, keytype) || istype(user.r_hand, keytype)) - return 1 + return TRUE else - return 1 - return 0 + return TRUE + return FALSE /obj/item/key name = "key" @@ -66,8 +67,8 @@ //BUCKLE HOOKS -/obj/vehicle/unbuckle_mob(force = 0) - if(buckled_mob) +/obj/vehicle/unbuckle_mob(mob/living/buckled_mob, force = FALSE) + if(istype(buckled_mob)) buckled_mob.pixel_x = 0 buckled_mob.pixel_y = 0 . = ..() @@ -80,38 +81,45 @@ if(A.density) if(A != src && A != M) return - M.loc = get_turf(src) + M.forceMove(get_turf(src)) ..() handle_vehicle_offsets() - /obj/vehicle/bullet_act(obj/item/projectile/Proj) - if(buckled_mob) - buckled_mob.bullet_act(Proj) + if(has_buckled_mobs()) + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + buckled_mob.bullet_act(Proj) //MOVEMENT /obj/vehicle/relaymove(mob/user, direction) if(user.incapacitated()) - unbuckle_mob() + unbuckle_mob(user) + return + if(world.time < next_vehicle_move) + return + next_vehicle_move = world.time + vehicle_move_delay if(keycheck(user)) - if(!Process_Spacemove(direction) || world.time < next_vehicle_move || !isturf(loc)) return - next_vehicle_move = world.time + vehicle_move_delay - + if(!Process_Spacemove(direction) || !isturf(loc)) + return step(src, direction) - if(buckled_mob) - if(buckled_mob.loc != loc) - buckled_mob.buckled = null //Temporary, so Move() succeeds. - buckled_mob.buckled = src //Restoring + if(has_buckled_mobs()) + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + if(buckled_mob.loc != loc) + buckled_mob.buckled = null //Temporary, so Move() succeeds. + buckled_mob.buckled = src //Restoring - if(istype(src.loc, /turf/simulated)) - var/turf/simulated/T = src.loc + if(issimulatedturf(loc)) + var/turf/simulated/T = loc if(T.wet == TURF_WET_LUBE) //Lube! Fall off! playsound(src, 'sound/misc/slip.ogg', 50, 1, -3) - buckled_mob.Stun(7) - buckled_mob.Weaken(7) - unbuckle_mob() + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + buckled_mob.Weaken(5) + unbuckle_all_mobs() step(src, dir) handle_vehicle_layer() @@ -121,7 +129,7 @@ /obj/vehicle/Move(NewLoc,Dir=0,step_x=0,step_y=0) - ..() + . = ..() handle_vehicle_layer() handle_vehicle_offsets() @@ -133,11 +141,12 @@ /obj/vehicle/Bump(atom/movable/M) if(!spaceworthy && isspaceturf(get_turf(src))) - return 0 + return FALSE . = ..() if(auto_door_open) - if(istype(M, /obj/machinery/door) && buckled_mob) - M.Bumped(buckled_mob) + if(istype(M, /obj/machinery/door) && has_buckled_mobs()) + for(var/m in buckled_mobs) + M.Bumped(m) /obj/vehicle/proc/RunOver(var/mob/living/carbon/human/H) return //write specifics for different vehicles @@ -145,19 +154,19 @@ /obj/vehicle/Process_Spacemove(direction) if(has_gravity(src)) - return 1 + return TRUE - if(pulledby && pulledby != buckled_mob) // no pulling the vehicle you're driving through space! - return 1 + if(pulledby && (pulledby.loc != loc)) + return TRUE if(needs_gravity) - return 1 + return TRUE - return 0 + return FALSE /obj/vehicle/space pressure_resistance = INFINITY spaceworthy = TRUE /obj/vehicle/space/Process_Spacemove(direction) - return 1 + return TRUE \ No newline at end of file diff --git a/icons/mob/screen_alert.dmi b/icons/mob/screen_alert.dmi index 2fe2c7cd21cb4000d3379cb959781975b8caa580..367a42a6c79208124bb824cb49ef5053683966ae 100644 GIT binary patch delta 12308 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 YaX{%JEf*VOLqZ%1A3n>~%9w=wAMU_oh5!Hn delta 10881 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 Date: Sun, 22 Sep 2019 21:22:59 -0400 Subject: [PATCH 22/24] Automatic changelog generation for PR #12375 [ci skip] --- html/changelogs/AutoChangeLog-pr-12375.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-12375.yml diff --git a/html/changelogs/AutoChangeLog-pr-12375.yml b/html/changelogs/AutoChangeLog-pr-12375.yml new file mode 100644 index 00000000000..4391987e967 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-12375.yml @@ -0,0 +1,5 @@ +author: "Fox McCloud" +delete-after: True +changes: + - tweak: "Buckling has its own icon" + - bugfix: "Fixes Xenobio monkey shortcuts not working" From efc79cfc7c467b205494b093ae7b846ddd61dc46 Mon Sep 17 00:00:00 2001 From: Fox McCloud Date: Mon, 23 Sep 2019 00:11:02 -0400 Subject: [PATCH 23/24] Removes Bodyscanner Console (#12377) --- _maps/map_files/Delta/delta.dmm | 20 +- .../MetaStation/MetaStation.v41A.II.dmm | 43 +- .../map_files/RandomZLevels/terrorspiders.dmm | 9 +- _maps/map_files/cyberiad/cyberiad.dmm | 37 +- _maps/map_files/shuttles/admin_admin.dmm | 8 +- _maps/map_files/shuttles/admin_hospital.dmm | 12 +- code/__HELPERS/game.dm | 9 - code/game/machinery/adv_med.dm | 606 +++++++----------- code/game/machinery/constructable_frame.dm | 10 - .../research/designs/machine_designs.dm | 10 - 10 files changed, 254 insertions(+), 510 deletions(-) diff --git a/_maps/map_files/Delta/delta.dmm b/_maps/map_files/Delta/delta.dmm index b1e8f101202..3e6c7e5c478 100644 --- a/_maps/map_files/Delta/delta.dmm +++ b/_maps/map_files/Delta/delta.dmm @@ -1274,12 +1274,6 @@ icon_state = "floor3" }, /area/shuttle/administration) -"acV" = ( -/obj/machinery/body_scanconsole, -/turf/simulated/shuttle/floor{ - icon_state = "floor3" - }, -/area/shuttle/administration) "acW" = ( /turf/simulated/shuttle/floor{ icon_state = "floor3" @@ -6079,10 +6073,6 @@ /obj/machinery/light/spot, /turf/simulated/shuttle/floor4/vox, /area/shuttle/vox) -"anf" = ( -/obj/machinery/body_scanconsole, -/turf/simulated/shuttle/floor4/vox, -/area/shuttle/vox) "ang" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply, /obj/machinery/door/firedoor, @@ -93584,7 +93574,6 @@ /area/medical/medbay) "dll" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/bodyscanner, /turf/simulated/floor/plasteel{ dir = 2; icon_state = "whitebluecorner"; @@ -93598,7 +93587,7 @@ dir = 1; network = list("SS13") }, -/obj/machinery/body_scanconsole, +/obj/machinery/bodyscanner, /turf/simulated/floor/plasteel{ dir = 2; icon_state = "whitepurplecorner" @@ -96747,7 +96736,6 @@ pixel_x = 0; pixel_y = -32 }, -/obj/machinery/bodyscanner, /turf/simulated/floor/plasteel{ icon_state = "dark" }, @@ -96760,7 +96748,7 @@ pixel_y = 0; req_access_txt = "0" }, -/obj/machinery/body_scanconsole, +/obj/machinery/bodyscanner, /turf/simulated/floor/plasteel{ icon_state = "dark" }, @@ -145341,7 +145329,7 @@ aaa aaa acA acN -acV +acW acW acW acW @@ -176978,7 +176966,7 @@ akm alU ams akn -anf +akn anD aok aaa diff --git a/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm b/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm index a14842c2007..c9c348db8d1 100644 --- a/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm +++ b/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm @@ -5504,10 +5504,6 @@ icon_state = "vault" }, /area/security/hos) -"ajA" = ( -/obj/machinery/body_scanconsole, -/turf/simulated/shuttle/floor4/vox, -/area/shuttle/vox) "ajB" = ( /turf/simulated/wall/r_wall, /area/maintenance/auxsolarport) @@ -69143,7 +69139,6 @@ }, /area/medical/exam_room) "cok" = ( -/obj/machinery/body_scanconsole, /obj/machinery/light/small{ dir = 1 }, @@ -69156,20 +69151,6 @@ icon_state = "whiteblue" }, /area/medical/exam_room) -"col" = ( -/obj/machinery/light/small{ - dir = 1 - }, -/obj/machinery/camera{ - c_tag = "Medbay Surgery 1 North"; - network = list("SS13") - }, -/obj/machinery/body_scanconsole, -/turf/simulated/floor/plasteel{ - dir = 1; - icon_state = "whiteblue" - }, -/area/medical/exam_room) "com" = ( /obj/structure/cable/yellow{ d1 = 2; @@ -74937,12 +74918,6 @@ icon_state = "white" }, /area/medical/surgery1) -"cxn" = ( -/obj/machinery/body_scanconsole, -/turf/simulated/floor/plasteel{ - icon_state = "white" - }, -/area/medical/surgery1) "cxo" = ( /obj/machinery/bodyscanner, /turf/simulated/floor/plasteel{ @@ -80670,12 +80645,6 @@ /area/medical/research{ name = "Research Division" }) -"cGE" = ( -/obj/machinery/body_scanconsole, -/turf/simulated/floor/plasteel{ - icon_state = "white" - }, -/area/medical/surgery2) "cGF" = ( /obj/machinery/atmospherics/unary/portables_connector, /obj/effect/decal/warning_stripes/south, @@ -116445,7 +116414,7 @@ crE crE cvb crE -cxo +crE cyo czs czU @@ -116453,7 +116422,7 @@ cAT cCM czs cEZ -cGO +cGo cGo cKc cGo @@ -116702,7 +116671,7 @@ crV ctX cva cvS -cxn +cxo cyo czu cBl @@ -116710,7 +116679,7 @@ cCu cAU cEj cEZ -cGE +cGO cFw cKb cKH @@ -118494,7 +118463,7 @@ ceQ chH cdT cmX -col +cok cpb crg csN @@ -148747,7 +148716,7 @@ aeF agJ ahv aeG -ajA +aeG akq all aaa diff --git a/_maps/map_files/RandomZLevels/terrorspiders.dmm b/_maps/map_files/RandomZLevels/terrorspiders.dmm index e03bfab5397..ad3ff6b12eb 100644 --- a/_maps/map_files/RandomZLevels/terrorspiders.dmm +++ b/_maps/map_files/RandomZLevels/terrorspiders.dmm @@ -12136,13 +12136,6 @@ icon_state = "whitecorner" }, /area/awaymission/UO71/medical) -"wQ" = ( -/obj/machinery/body_scanconsole, -/turf/simulated/floor/plasteel{ - dir = 1; - icon_state = "whitehall" - }, -/area/awaymission/UO71/medical) "wR" = ( /obj/machinery/bodyscanner, /turf/simulated/floor/plasteel{ @@ -20566,7 +20559,7 @@ qa vr qJ qJ -wQ +wT qa ab ab diff --git a/_maps/map_files/cyberiad/cyberiad.dmm b/_maps/map_files/cyberiad/cyberiad.dmm index 16ae46b48d7..2162c77926e 100644 --- a/_maps/map_files/cyberiad/cyberiad.dmm +++ b/_maps/map_files/cyberiad/cyberiad.dmm @@ -3961,12 +3961,6 @@ icon_state = "floor4" }, /area/shuttle/syndicate) -"ahx" = ( -/obj/machinery/body_scanconsole, -/turf/simulated/shuttle/floor{ - icon_state = "floor4" - }, -/area/shuttle/syndicate) "ahy" = ( /obj/structure/shuttle/engine/heater, /obj/structure/window/reinforced{ @@ -5332,10 +5326,6 @@ /obj/machinery/light/spot, /turf/simulated/shuttle/floor4/vox, /area/shuttle/vox) -"ajI" = ( -/obj/machinery/body_scanconsole, -/turf/simulated/shuttle/floor4/vox, -/area/shuttle/vox) "ajJ" = ( /obj/structure/sign/poster/official/random{ pixel_x = 0; @@ -45995,7 +45985,6 @@ }, /area/medical/morgue) "bHL" = ( -/obj/machinery/body_scanconsole, /obj/machinery/alarm{ dir = 1; pixel_y = -25 @@ -58771,20 +58760,13 @@ dir = 1; pixel_y = -22 }, -/obj/machinery/body_scanconsole, +/obj/machinery/bodyscanner, /turf/simulated/floor/plasteel{ dir = 6; icon_state = "whiteblue"; tag = "icon-whitehall (WEST)" }, /area/medical/sleeper) -"ccw" = ( -/obj/machinery/bodyscanner, -/turf/simulated/floor/plasteel{ - tag = "icon-whiteblue"; - icon_state = "whiteblue" - }, -/area/medical/sleeper) "ccx" = ( /obj/machinery/light, /obj/machinery/disposal, @@ -61169,12 +61151,6 @@ icon_state = "floor3" }, /area/shuttle/administration) -"cgx" = ( -/obj/machinery/body_scanconsole, -/turf/simulated/shuttle/floor{ - icon_state = "floor3" - }, -/area/shuttle/administration) "cgy" = ( /obj/machinery/door/poddoor{ id_tag = "ToxinsVenting"; @@ -63837,7 +63813,6 @@ /turf/simulated/floor/plating, /area/maintenance/asmaint) "ckU" = ( -/obj/machinery/body_scanconsole, /obj/machinery/camera{ c_tag = "Medbay Surgery West"; dir = 1; @@ -63979,7 +63954,6 @@ }, /area/medical/surgery2) "clf" = ( -/obj/machinery/body_scanconsole, /obj/machinery/camera{ c_tag = "Medbay Surgery East"; dir = 1; @@ -72124,7 +72098,6 @@ pixel_y = -3 }, /obj/item/circuitboard/bodyscanner, -/obj/item/circuitboard/bodyscanner_console, /obj/item/circuitboard/sleeper{ pixel_x = 3 }, @@ -106627,7 +106600,7 @@ bRA bPI cdo ceR -cgx +ceR cii ckf clE @@ -107567,7 +107540,7 @@ abV abV agF ahg -ahx +abV ahy ahP aaa @@ -133098,7 +133071,7 @@ bXG bZi cgM caI -ccw +ccu ceg cfI cho @@ -154860,7 +154833,7 @@ agZ ail aiL aha -ajI +aha ajY akp aaa diff --git a/_maps/map_files/shuttles/admin_admin.dmm b/_maps/map_files/shuttles/admin_admin.dmm index bad43283b9b..6e494e0b85b 100644 --- a/_maps/map_files/shuttles/admin_admin.dmm +++ b/_maps/map_files/shuttles/admin_admin.dmm @@ -540,12 +540,6 @@ icon_state = "floor3" }, /area/shuttle/administration) -"bj" = ( -/obj/machinery/body_scanconsole, -/turf/simulated/shuttle/floor{ - icon_state = "floor3" - }, -/area/shuttle/administration) "bk" = ( /obj/structure/window/plasmareinforced{ color = "#FF0000"; @@ -847,7 +841,7 @@ am ac bc bg -bj +bg bo bt bz diff --git a/_maps/map_files/shuttles/admin_hospital.dmm b/_maps/map_files/shuttles/admin_hospital.dmm index c9a41d69463..9e3b48a11c7 100644 --- a/_maps/map_files/shuttles/admin_hospital.dmm +++ b/_maps/map_files/shuttles/admin_hospital.dmm @@ -947,12 +947,6 @@ icon_state = "floor3" }, /area/shuttle/administration) -"bS" = ( -/obj/machinery/body_scanconsole, -/turf/simulated/shuttle/floor{ - icon_state = "floor3" - }, -/area/shuttle/administration) "bT" = ( /obj/machinery/light, /obj/structure/closet/crate/can, @@ -1494,7 +1488,7 @@ aw aw aw aw -bS +aw ac "} (11,1,1) = {" @@ -1569,12 +1563,12 @@ ac bx aw aw -bS +aw ac bx aw aw -bS +aw Kq "} (15,1,1) = {" diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 3bb6b742a04..744b8b86a9a 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -1,12 +1,3 @@ -/proc/dopage(src,target) - var/href_list - var/href - href_list = params2list("src=[src:UID()]&[target]=1") - href = "src=[src:UID()];[target]=1" - src:temphtml = null - src:Topic(href, href_list) - return null - /proc/get_area(atom/A) if(isarea(A)) return A diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm index b7e24014f1e..adb08949732 100644 --- a/code/game/machinery/adv_med.dm +++ b/code/game/machinery/adv_med.dm @@ -7,17 +7,12 @@ anchored = TRUE idle_power_usage = 1250 active_power_usage = 2500 - light_color = "#00FF00" - var/obj/machinery/body_scanconsole/console = null - var/mob/living/carbon/occupant = null - var/locked + var/mob/living/carbon/human/occupant + var/known_implants = list(/obj/item/implant/chem, /obj/item/implant/death_alarm, /obj/item/implant/mindshield, /obj/item/implant/tracking, /obj/item/implant/health) /obj/machinery/bodyscanner/Destroy() go_out() - if(console) - console.connected = null - console = null return ..() /obj/machinery/bodyscanner/power_change() @@ -44,16 +39,6 @@ component_parts += new /obj/item/stack/cable_coil(null, 2) RefreshParts() -/obj/machinery/bodyscanner/upgraded/New() - ..() - component_parts = list() - component_parts += new /obj/item/circuitboard/bodyscanner(null) - component_parts += new /obj/item/stock_parts/scanning_module/phasic(null) - component_parts += new /obj/item/stock_parts/console_screen(null) - component_parts += new /obj/item/stock_parts/console_screen(null) - component_parts += new /obj/item/stack/cable_coil(null, 2) - RefreshParts() - /obj/machinery/bodyscanner/attackby(obj/item/I, mob/user) if(isscrewdriver(I)) if(occupant) @@ -87,7 +72,7 @@ if(panel_open) to_chat(user, "Close the maintenance panel first.") return - if(!ismob(TYPECAST_YOUR_SHIT.affecting)) + if(!ishuman(TYPECAST_YOUR_SHIT.affecting)) return if(occupant) to_chat(user, "The scanner is already occupied!") @@ -96,7 +81,7 @@ if(M.Victim == TYPECAST_YOUR_SHIT.affecting) to_chat(user, "[TYPECAST_YOUR_SHIT.affecting.name] has a fucking slime attached to [TYPECAST_YOUR_SHIT.affecting.p_them()], deal with that first.") return - var/mob/M = TYPECAST_YOUR_SHIT.affecting + var/mob/living/carbon/human/M = TYPECAST_YOUR_SHIT.affecting if(M.abiotic()) to_chat(user, "Subject cannot have abiotic items on.") return @@ -110,47 +95,62 @@ return ..() -/obj/machinery/bodyscanner/MouseDrop_T(mob/living/carbon/human/O, mob/user as mob) - if(!istype(O)) - return 0 //not a mob +/obj/machinery/bodyscanner/MouseDrop_T(mob/living/carbon/human/H, mob/user) + if(!istype(H)) + return FALSE //not human if(user.incapacitated()) - return 0 //user shouldn't be doing things - if(O.anchored) - return 0 //mob is anchored??? - if(get_dist(user, src) > 1 || get_dist(user, O) > 1) - return 0 //doesn't use adjacent() to allow for non-cardinal (fuck my life) + return FALSE //user shouldn't be doing things + if(H.anchored) + return FALSE //mob is anchored??? + if(get_dist(user, src) > 1 || get_dist(user, H) > 1) + return FALSE //doesn't use adjacent() to allow for non-cardinal (fuck my life) if(!ishuman(user) && !isrobot(user)) - return 0 //not a borg or human + return FALSE //not a borg or human if(panel_open) to_chat(user, "Close the maintenance panel first.") - return 0 //panel open + return FALSE //panel open if(occupant) to_chat(user, "[src] is already occupied.") - return 0 //occupied - - if(O.buckled) - return 0 - if(O.abiotic()) + return FALSE //occupied + if(H.buckled) + return FALSE + if(H.abiotic()) to_chat(user, "Subject cannot have abiotic items on.") - return 0 - for(var/mob/living/carbon/slime/M in range(1, O)) - if(M.Victim == O) - to_chat(user, "[O] has a fucking slime attached to [O.p_them()], deal with that first.") - return 0 + return FALSE + for(var/mob/living/carbon/slime/M in range(1, H)) + if(M.Victim == H) + to_chat(user, "[H] has a fucking slime attached to [H.p_them()], deal with that first.") + return FALSE - if(O == user) + if(H == user) visible_message("[user] climbs into [src].") else - visible_message("[user] puts [O] into the body scanner.") + visible_message("[user] puts [H] into the body scanner.") - O.forceMove(src) - occupant = O + H.forceMove(src) + occupant = H icon_state = "bodyscanner" add_fingerprint(user) -/obj/machinery/bodyscanner/relaymove(mob/user as mob) +/obj/machinery/bodyscanner/attack_ai(user) + return attack_hand(user) + +/obj/machinery/bodyscanner/attack_ghost(user) + return attack_hand(user) + +/obj/machinery/bodyscanner/attack_hand(user) + if(stat & (NOPOWER|BROKEN)) + return + + if(panel_open) + to_chat(user, "Close the maintenance panel first.") + return + + ui_interact(user) + +/obj/machinery/bodyscanner/relaymove(mob/user) if(user.incapacitated()) - return 0 //maybe they should be able to get out with cuffs, but whatever + return FALSE //maybe they should be able to get out with cuffs, but whatever go_out() /obj/machinery/bodyscanner/verb/eject() @@ -164,7 +164,7 @@ add_fingerprint(usr) /obj/machinery/bodyscanner/proc/go_out() - if(!occupant || locked) + if(!occupant) return occupant.forceMove(loc) occupant = null @@ -175,22 +175,22 @@ /obj/machinery/bodyscanner/ex_act(severity) switch(severity) - if(1.0) - for(var/atom/movable/A as mob|obj in src) + if(1) + for(var/atom/movable/A in src) A.forceMove(loc) A.ex_act(severity) qdel(src) return - if(2.0) + if(2) if(prob(50)) - for(var/atom/movable/A as mob|obj in src) + for(var/atom/movable/A in src) A.forceMove(loc) A.ex_act(severity) qdel(src) return - if(3.0) + if(3) if(prob(25)) - for(var/atom/movable/A as mob|obj in src) + for(var/atom/movable/A in src) A.forceMove(loc) A.ex_act(severity) qdel(src) @@ -208,162 +208,34 @@ new /obj/effect/gibspawner/generic(get_turf(loc)) //I REPLACE YOUR TECHNOLOGY WITH FLESH! qdel(src) -/obj/machinery/bodyscanner/attack_animal(var/mob/living/simple_animal/M)//Stop putting hostile mobs in things guise +/obj/machinery/bodyscanner/attack_animal(mob/living/simple_animal/M)//Stop putting hostile mobs in things guise if(M.environment_smash) M.do_attack_animation(src) visible_message("[M.name] smashes [src] apart!") go_out() qdel(src) - return -/obj/machinery/body_scanconsole - name = "Body Scanner Console" - icon = 'icons/obj/cryogenic2.dmi' - icon_state = "bodyscannerconsole" - density = 1 - anchored = 1 - dir = WEST - idle_power_usage = 250 - active_power_usage = 500 - var/obj/machinery/bodyscanner/connected = null - var/delete - var/temphtml - var/printing = null - var/printing_text = null - var/known_implants = list(/obj/item/implant/chem, /obj/item/implant/death_alarm, /obj/item/implant/mindshield, /obj/item/implant/tracking, /obj/item/implant/health) - -/obj/machinery/body_scanconsole/power_change() - if(stat & BROKEN) - icon_state = "bodyscannerconsole-p" - else if(powered() && !panel_open) - icon_state = initial(icon_state) - stat &= ~NOPOWER - else - spawn(rand(0, 15)) - icon_state = "bodyscannerconsole-p" - stat |= NOPOWER - -/obj/machinery/body_scanconsole/New() - ..() - component_parts = list() - component_parts += new /obj/item/circuitboard/bodyscanner_console(null) - component_parts += new /obj/item/stock_parts/console_screen(null) - component_parts += new /obj/item/stock_parts/console_screen(null) - component_parts += new /obj/item/stack/cable_coil(null, 2) - RefreshParts() - findscanner() - -/obj/machinery/body_scanconsole/Destroy() - if(connected) - connected.console = null - connected = null - return ..() - -/obj/machinery/body_scanconsole/ex_act(severity) - switch(severity) - if(1.0) - //SN src = null - qdel(src) - return - if(2.0) - if(prob(50)) - //SN src = null - qdel(src) - return - else - return - -/obj/machinery/body_scanconsole/blob_act() - if(prob(50)) - qdel(src) - -/obj/machinery/body_scanconsole/attack_animal(var/mob/living/simple_animal/M)//Stop putting hostile mobs in things guise - if(M.environment_smash) - M.do_attack_animation(src) - visible_message("[M.name] smashes [src] apart!") - qdel(src) - return - -/obj/machinery/body_scanconsole/proc/findscanner() - for(dir in list(NORTH,EAST,SOUTH,WEST)) - // Try to find a scanner in that direction - var/temp = locate(/obj/machinery/bodyscanner, get_step(src, dir)) - if(temp) - connected = temp - connected.console = src - break - - -/obj/machinery/body_scanconsole/attackby(obj/item/I, mob/user, params) - if(default_deconstruction_screwdriver(user, "bodyscannerconsole-p", "bodyscannerconsole", I)) - return - - if(iswrench(I)) - if(panel_open) - to_chat(user, "Close the maintenance panel first.") - return - if(dir == EAST) - setDir(WEST) - else - setDir(EAST) - playsound(loc, I.usesound, 50, 1) - return - - if(exchange_parts(user, I)) - return - - if(default_deconstruction_crowbar(I)) - return - else - return ..() - -/obj/machinery/body_scanconsole/attack_ai(user) - return attack_hand(user) - -/obj/machinery/body_scanconsole/attack_ghost(user) - return attack_hand(user) - -/obj/machinery/body_scanconsole/attack_hand(user) - if(stat & (NOPOWER|BROKEN)) - return - - if(panel_open) - to_chat(user, "Close the maintenance panel first.") - return - - if(!connected) - findscanner() - - ui_interact(user) - - -/obj/machinery/body_scanconsole/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1) +/obj/machinery/bodyscanner/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1) ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) ui = new(user, src, ui_key, "adv_med.tmpl", "Body Scanner", 690, 600) ui.open() ui.set_auto_update(1) -/obj/machinery/body_scanconsole/ui_data(mob/user, datum/topic_state/state) +/obj/machinery/bodyscanner/ui_data(mob/user, datum/topic_state/state) var/data[0] - data["connected"] = connected ? 1 : 0 - - if(!connected) - return data - - data["occupied"] = connected.occupant ? 1 : 0 + data["occupied"] = occupant ? 1 : 0 var/occupantData[0] - if(connected.occupant) - var/mob/living/carbon/human/H = connected.occupant - occupantData["name"] = H.name - occupantData["stat"] = H.stat - occupantData["health"] = H.health - occupantData["maxHealth"] = H.maxHealth + if(occupant) + occupantData["name"] = occupant.name + occupantData["stat"] = occupant.stat + occupantData["health"] = occupant.health + occupantData["maxHealth"] = occupant.maxHealth var/found_disease = FALSE - for(var/thing in H.viruses) + for(var/thing in occupant.viruses) var/datum/disease/D = thing if(D.visibility_flags & HIDDEN_SCANNER || D.visibility_flags & HIDDEN_PANDEMIC) continue @@ -371,34 +243,34 @@ break occupantData["hasVirus"] = found_disease - occupantData["bruteLoss"] = H.getBruteLoss() - occupantData["oxyLoss"] = H.getOxyLoss() - occupantData["toxLoss"] = H.getToxLoss() - occupantData["fireLoss"] = H.getFireLoss() + occupantData["bruteLoss"] = occupant.getBruteLoss() + occupantData["oxyLoss"] = occupant.getOxyLoss() + occupantData["toxLoss"] = occupant.getToxLoss() + occupantData["fireLoss"] = occupant.getFireLoss() - occupantData["radLoss"] = H.radiation - occupantData["cloneLoss"] = H.getCloneLoss() - occupantData["brainLoss"] = H.getBrainLoss() - occupantData["paralysis"] = H.paralysis - occupantData["paralysisSeconds"] = round(H.paralysis / 4) - occupantData["bodyTempC"] = H.bodytemperature-T0C - occupantData["bodyTempF"] = (((H.bodytemperature-T0C) * 1.8) + 32) + occupantData["radLoss"] = occupant.radiation + occupantData["cloneLoss"] = occupant.getCloneLoss() + occupantData["brainLoss"] = occupant.getBrainLoss() + occupantData["paralysis"] = occupant.paralysis + occupantData["paralysisSeconds"] = round(occupant.paralysis * 0.25) + occupantData["bodyTempC"] = occupant.bodytemperature-T0C + occupantData["bodyTempF"] = (((occupant.bodytemperature-T0C) * 1.8) + 32) - occupantData["hasBorer"] = H.has_brain_worms() + occupantData["hasBorer"] = occupant.has_brain_worms() var/bloodData[0] bloodData["hasBlood"] = 0 - if(ishuman(H) && !(NO_BLOOD in H.dna.species.species_traits)) + if(!(NO_BLOOD in occupant.dna.species.species_traits)) bloodData["hasBlood"] = 1 - bloodData["volume"] = H.blood_volume - bloodData["percent"] = round(((H.blood_volume / BLOOD_VOLUME_NORMAL)*100)) - bloodData["pulse"] = H.get_pulse(GETPULSE_TOOL) - bloodData["bloodLevel"] = H.blood_volume - bloodData["bloodMax"] = H.max_blood + bloodData["volume"] = occupant.blood_volume + bloodData["percent"] = round(((occupant.blood_volume / BLOOD_VOLUME_NORMAL)*100)) + bloodData["pulse"] = occupant.get_pulse(GETPULSE_TOOL) + bloodData["bloodLevel"] = occupant.blood_volume + bloodData["bloodMax"] = occupant.max_blood occupantData["blood"] = bloodData var/implantData[0] - for(var/obj/item/implant/I in H) + for(var/obj/item/implant/I in occupant) if(I.implanted && is_type_in_list(I, known_implants)) var/implantSubData[0] implantSubData["name"] = sanitize(I.name) @@ -407,7 +279,7 @@ occupantData["implant_len"] = implantData.len var/extOrganData[0] - for(var/obj/item/organ/external/E in H.bodyparts) + for(var/obj/item/organ/external/E in occupant.bodyparts) var/organData[0] organData["name"] = E.name organData["open"] = E.open @@ -441,7 +313,7 @@ organData["status"] = organStatus - if(istype(E, /obj/item/organ/external/chest) && H.is_lung_ruptured()) + if(istype(E, /obj/item/organ/external/chest) && occupant.is_lung_ruptured()) organData["lungRuptured"] = 1 if(E.internal_bleeding) @@ -452,7 +324,7 @@ occupantData["extOrgan"] = extOrganData var/intOrganData[0] - for(var/obj/item/organ/internal/I in H.internal_organs) + for(var/obj/item/organ/internal/I in occupant.internal_organs) var/organData[0] organData["name"] = I.name organData["desc"] = I.desc @@ -468,199 +340,189 @@ occupantData["intOrgan"] = intOrganData - occupantData["blind"] = (H.disabilities & BLIND) - occupantData["colourblind"] = (H.disabilities & COLOURBLIND) - occupantData["nearsighted"] = (H.disabilities & NEARSIGHTED) + occupantData["blind"] = (occupant.disabilities & BLIND) + occupantData["colourblind"] = (occupant.disabilities & COLOURBLIND) + occupantData["nearsighted"] = (occupant.disabilities & NEARSIGHTED) data["occupant"] = occupantData return data -/obj/machinery/body_scanconsole/Topic(href, href_list) +/obj/machinery/bodyscanner/Topic(href, href_list) if(..()) return 1 if(href_list["ejectify"]) - connected.eject() + eject() if(href_list["print_p"]) - generate_printing_text() + visible_message("[src] rattles and prints out a sheet of paper.") + var/obj/item/paper/P = new /obj/item/paper(loc) + playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1) + P.info = "
    Body Scan - [href_list["name"]]

    " + P.info += "Time of scan: [station_time_timestamp()]

    " + P.info += "[generate_printing_text()]" + P.info += "

    Notes:
    " + P.name = "Body Scan - [href_list["name"]]" - if(!(printing) && printing_text) - printing = 1 - visible_message("[src] rattles and prints out a sheet of paper.") - var/obj/item/paper/P = new /obj/item/paper(loc) - playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1) - P.info = "
    Body Scan - [href_list["name"]]

    " - P.info += "Time of scan: [station_time_timestamp()]

    " - P.info += "[printing_text]" - P.info += "

    Notes:
    " - P.name = "Body Scan - [href_list["name"]]" - printing = null - printing_text = null - -/obj/machinery/body_scanconsole/proc/generate_printing_text() +/obj/machinery/bodyscanner/proc/generate_printing_text() var/dat = "" - if(connected) - var/mob/living/carbon/human/occupant = connected.occupant - dat = "Occupant Statistics:
    " //Blah obvious - if(istype(occupant)) //is there REALLY someone in there? - var/t1 - switch(occupant.stat) // obvious, see what their status is - if(0) - t1 = "Conscious" - if(1) - t1 = "Unconscious" - else - t1 = "*dead*" - dat += "[occupant.health > 50 ? "" : ""]\tHealth %: [occupant.health], ([t1])
    " + dat = "Occupant Statistics:
    " //Blah obvious + if(istype(occupant)) //is there REALLY someone in there? + var/t1 + switch(occupant.stat) // obvious, see what their status is + if(0) + t1 = "Conscious" + if(1) + t1 = "Unconscious" + else + t1 = "*dead*" + dat += "[occupant.health > 50 ? "" : ""]\tHealth %: [occupant.health], ([t1])
    " - var/found_disease = FALSE - for(var/thing in occupant.viruses) - var/datum/disease/D = thing - if(D.visibility_flags & HIDDEN_SCANNER || D.visibility_flags & HIDDEN_PANDEMIC) - continue - found_disease = TRUE - break - if(found_disease) - dat += "Disease detected in occupant.
    " + var/found_disease = FALSE + for(var/thing in occupant.viruses) + var/datum/disease/D = thing + if(D.visibility_flags & HIDDEN_SCANNER || D.visibility_flags & HIDDEN_PANDEMIC) + continue + found_disease = TRUE + break + if(found_disease) + dat += "Disease detected in occupant.
    " - var/extra_font = null - extra_font = (occupant.getBruteLoss() < 60 ? "" : "") - dat += "[extra_font]\t-Brute Damage %: [occupant.getBruteLoss()]
    " + var/extra_font = null + extra_font = (occupant.getBruteLoss() < 60 ? "" : "") + dat += "[extra_font]\t-Brute Damage %: [occupant.getBruteLoss()]
    " - extra_font = (occupant.getOxyLoss() < 60 ? "" : "") - dat += "[extra_font]\t-Respiratory Damage %: [occupant.getOxyLoss()]
    " + extra_font = (occupant.getOxyLoss() < 60 ? "" : "") + dat += "[extra_font]\t-Respiratory Damage %: [occupant.getOxyLoss()]
    " - extra_font = (occupant.getToxLoss() < 60 ? "" : "") - dat += "[extra_font]\t-Toxin Content %: [occupant.getToxLoss()]
    " + extra_font = (occupant.getToxLoss() < 60 ? "" : "") + dat += "[extra_font]\t-Toxin Content %: [occupant.getToxLoss()]
    " - extra_font = (occupant.getFireLoss() < 60 ? "" : "") - dat += "[extra_font]\t-Burn Severity %: [occupant.getFireLoss()]
    " + extra_font = (occupant.getFireLoss() < 60 ? "" : "") + dat += "[extra_font]\t-Burn Severity %: [occupant.getFireLoss()]
    " - extra_font = (occupant.radiation < 10 ?"" : "") - dat += "[extra_font]\tRadiation Level %: [occupant.radiation]
    " + extra_font = (occupant.radiation < 10 ?"" : "") + dat += "[extra_font]\tRadiation Level %: [occupant.radiation]
    " - extra_font = (occupant.getCloneLoss() < 1 ?"" : "") - dat += "[extra_font]\tGenetic Tissue Damage %: [occupant.getCloneLoss()]
    " + extra_font = (occupant.getCloneLoss() < 1 ?"" : "") + dat += "[extra_font]\tGenetic Tissue Damage %: [occupant.getCloneLoss()]
    " - extra_font = (occupant.getBrainLoss() < 1 ?"" : "") - dat += "[extra_font]\tApprox. Brain Damage %: [occupant.getBrainLoss()]
    " + extra_font = (occupant.getBrainLoss() < 1 ?"" : "") + dat += "[extra_font]\tApprox. Brain Damage %: [occupant.getBrainLoss()]
    " - dat += "Paralysis Summary %: [occupant.paralysis] ([round(occupant.paralysis / 4)] seconds left!)
    " - dat += "Body Temperature: [occupant.bodytemperature-T0C]°C ([occupant.bodytemperature*1.8-459.67]°F)
    " + dat += "Paralysis Summary %: [occupant.paralysis] ([round(occupant.paralysis / 4)] seconds left!)
    " + dat += "Body Temperature: [occupant.bodytemperature-T0C]°C ([occupant.bodytemperature*1.8-459.67]°F)
    " - dat += "
    " + dat += "
    " - if(occupant.has_brain_worms()) - dat += "Large growth detected in frontal lobe, possibly cancerous. Surgical removal is recommended.
    " + if(occupant.has_brain_worms()) + dat += "Large growth detected in frontal lobe, possibly cancerous. Surgical removal is recommended.
    " - var/blood_percent = round((occupant.blood_volume / BLOOD_VOLUME_NORMAL)) - blood_percent *= 100 + var/blood_percent = round((occupant.blood_volume / BLOOD_VOLUME_NORMAL)) + blood_percent *= 100 - extra_font = (occupant.blood_volume > 448 ? "" : "") - dat += "[extra_font]\tBlood Level %: [blood_percent] ([occupant.blood_volume] units)
    " + extra_font = (occupant.blood_volume > 448 ? "" : "") + dat += "[extra_font]\tBlood Level %: [blood_percent] ([occupant.blood_volume] units)
    " - if(occupant.reagents) - dat += "Epinephrine units: [occupant.reagents.get_reagent_amount("Epinephrine")] units
    " - dat += "Ether: [occupant.reagents.get_reagent_amount("ether")] units
    " + if(occupant.reagents) + dat += "Epinephrine units: [occupant.reagents.get_reagent_amount("Epinephrine")] units
    " + dat += "Ether: [occupant.reagents.get_reagent_amount("ether")] units
    " - extra_font = (occupant.reagents.get_reagent_amount("silver_sulfadiazine") < 30 ? "" : "") - dat += "[extra_font]\tSilver Sulfadiazine: [occupant.reagents.get_reagent_amount("silver_sulfadiazine")]
    " + extra_font = (occupant.reagents.get_reagent_amount("silver_sulfadiazine") < 30 ? "" : "") + dat += "[extra_font]\tSilver Sulfadiazine: [occupant.reagents.get_reagent_amount("silver_sulfadiazine")]
    " - extra_font = (occupant.reagents.get_reagent_amount("styptic_powder") < 30 ? "" : "") - dat += "[extra_font]\tStyptic Powder: [occupant.reagents.get_reagent_amount("styptic_powder")] units
    " + extra_font = (occupant.reagents.get_reagent_amount("styptic_powder") < 30 ? "" : "") + dat += "[extra_font]\tStyptic Powder: [occupant.reagents.get_reagent_amount("styptic_powder")] units
    " - extra_font = (occupant.reagents.get_reagent_amount("salbutamol") < 30 ? "" : "") - dat += "[extra_font]\tSalbutamol: [occupant.reagents.get_reagent_amount("salbutamol")] units
    " + extra_font = (occupant.reagents.get_reagent_amount("salbutamol") < 30 ? "" : "") + dat += "[extra_font]\tSalbutamol: [occupant.reagents.get_reagent_amount("salbutamol")] units
    " - dat += "
    " + dat += "
    " + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + + for(var/obj/item/organ/external/e in occupant.bodyparts) dat += "" - dat += "" - dat += "" - dat += "" - dat += "" + var/AN = "" + var/open = "" + var/infected = "" + var/robot = "" + var/imp = "" + var/bled = "" + var/splint = "" + var/internal_bleeding = "" + var/lung_ruptured = "" + if(e.internal_bleeding) + internal_bleeding = "
    Internal bleeding" + if(istype(e, /obj/item/organ/external/chest) && occupant.is_lung_ruptured()) + lung_ruptured = "Lung ruptured:" + if(e.status & ORGAN_SPLINTED) + splint = "Splinted:" + if(e.status & ORGAN_BROKEN) + AN = "[e.broken_description]:" + if(e.is_robotic()) + robot = "Robotic:" + if(e.open) + open = "Open:" + switch(e.germ_level) + if(INFECTION_LEVEL_ONE to INFECTION_LEVEL_ONE + 200) + infected = "Mild Infection:" + if(INFECTION_LEVEL_ONE + 200 to INFECTION_LEVEL_ONE + 300) + infected = "Mild Infection+:" + if(INFECTION_LEVEL_ONE + 300 to INFECTION_LEVEL_ONE + 400) + infected = "Mild Infection++:" + if(INFECTION_LEVEL_TWO to INFECTION_LEVEL_TWO + 200) + infected = "Acute Infection:" + if(INFECTION_LEVEL_TWO + 200 to INFECTION_LEVEL_TWO + 300) + infected = "Acute Infection+:" + if(INFECTION_LEVEL_TWO + 300 to INFECTION_LEVEL_TWO + 400) + infected = "Acute Infection++:" + if(INFECTION_LEVEL_THREE to INFINITY) + infected = "Septic:" + + var/unknown_body = 0 + for(var/I in e.embedded_objects) + unknown_body++ + + if(unknown_body || e.hidden) + imp += "Unknown body present:" + if(!AN && !open && !infected & !imp) + AN = "None:" + dat += "" dat += "" + for(var/obj/item/organ/internal/i in occupant.internal_organs) + var/mech = i.desc + var/infection = "None" + switch(i.germ_level) + if(1 to INFECTION_LEVEL_ONE + 200) + infection = "Mild Infection:" + if(INFECTION_LEVEL_ONE + 200 to INFECTION_LEVEL_ONE + 300) + infection = "Mild Infection+:" + if(INFECTION_LEVEL_ONE + 300 to INFECTION_LEVEL_ONE + 400) + infection = "Mild Infection++:" + if(INFECTION_LEVEL_TWO to INFECTION_LEVEL_TWO + 200) + infection = "Acute Infection:" + if(INFECTION_LEVEL_TWO + 200 to INFECTION_LEVEL_TWO + 300) + infection = "Acute Infection+:" + if(INFECTION_LEVEL_TWO + 300 to INFINITY) + infection = "Acute Infection++:" - for(var/obj/item/organ/external/e in occupant.bodyparts) - dat += "" - var/AN = "" - var/open = "" - var/infected = "" - var/robot = "" - var/imp = "" - var/bled = "" - var/splint = "" - var/internal_bleeding = "" - var/lung_ruptured = "" - if(e.internal_bleeding) - internal_bleeding = "
    Internal bleeding" - if(istype(e, /obj/item/organ/external/chest) && occupant.is_lung_ruptured()) - lung_ruptured = "Lung ruptured:" - if(e.status & ORGAN_SPLINTED) - splint = "Splinted:" - if(e.status & ORGAN_BROKEN) - AN = "[e.broken_description]:" - if(e.is_robotic()) - robot = "Robotic:" - if(e.open) - open = "Open:" - switch(e.germ_level) - if(INFECTION_LEVEL_ONE to INFECTION_LEVEL_ONE + 200) - infected = "Mild Infection:" - if(INFECTION_LEVEL_ONE + 200 to INFECTION_LEVEL_ONE + 300) - infected = "Mild Infection+:" - if(INFECTION_LEVEL_ONE + 300 to INFECTION_LEVEL_ONE + 400) - infected = "Mild Infection++:" - if(INFECTION_LEVEL_TWO to INFECTION_LEVEL_TWO + 200) - infected = "Acute Infection:" - if(INFECTION_LEVEL_TWO + 200 to INFECTION_LEVEL_TWO + 300) - infected = "Acute Infection+:" - if(INFECTION_LEVEL_TWO + 300 to INFECTION_LEVEL_TWO + 400) - infected = "Acute Infection++:" - if(INFECTION_LEVEL_THREE to INFINITY) - infected = "Septic:" - - var/unknown_body = 0 - for(var/I in e.embedded_objects) - unknown_body++ - - if(unknown_body || e.hidden) - imp += "Unknown body present:" - if(!AN && !open && !infected & !imp) - AN = "None:" - dat += "" - dat += "" - for(var/obj/item/organ/internal/i in occupant.internal_organs) - var/mech = i.desc - var/infection = "None" - switch(i.germ_level) - if(1 to INFECTION_LEVEL_ONE + 200) - infection = "Mild Infection:" - if(INFECTION_LEVEL_ONE + 200 to INFECTION_LEVEL_ONE + 300) - infection = "Mild Infection+:" - if(INFECTION_LEVEL_ONE + 300 to INFECTION_LEVEL_ONE + 400) - infection = "Mild Infection++:" - if(INFECTION_LEVEL_TWO to INFECTION_LEVEL_TWO + 200) - infection = "Acute Infection:" - if(INFECTION_LEVEL_TWO + 200 to INFECTION_LEVEL_TWO + 300) - infection = "Acute Infection+:" - if(INFECTION_LEVEL_TWO + 300 to INFINITY) - infection = "Acute Infection++:" - - dat += "" - dat += "" - dat += "" - dat += "
    OrganBurn DamageBrute DamageOther Wounds
    OrganBurn DamageBrute DamageOther Wounds[e.name][e.burn_dam][e.brute_dam][robot][bled][AN][splint][open][infected][imp][internal_bleeding][lung_ruptured]
    [e.name][e.burn_dam][e.brute_dam][robot][bled][AN][splint][open][infected][imp][internal_bleeding][lung_ruptured]
    [i.name]N/A[i.damage][infection]:[mech]
    " - if(occupant.disabilities & BLIND) - dat += "Cataracts detected.
    " - if(occupant.disabilities & COLOURBLIND) - dat += "Photoreceptor abnormalities detected.
    " - if(occupant.disabilities & NEARSIGHTED) - dat += "Retinal misalignment detected.
    " - else - dat += "[src] is empty." + dat += "" + dat += "[i.name]N/A[i.damage][infection]:[mech]" + dat += "" + dat += "" + if(occupant.disabilities & BLIND) + dat += "Cataracts detected.
    " + if(occupant.disabilities & COLOURBLIND) + dat += "Photoreceptor abnormalities detected.
    " + if(occupant.disabilities & NEARSIGHTED) + dat += "Retinal misalignment detected.
    " else - dat = " Error: No Body Scanner connected." + dat += "[src] is empty." - printing_text = dat + return dat \ No newline at end of file diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index 547692ad2ff..21452131e76 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -869,16 +869,6 @@ to destroy them and players will be able to make replacements. /obj/item/stack/cable_coil = 2, /obj/item/stock_parts/console_screen = 2) -/obj/item/circuitboard/bodyscanner_console - name = "circuit board (Body Scanner Console)" - build_path = /obj/machinery/body_scanconsole - board_type = "machine" - origin_tech = "programming=3;biotech=2;engineering=3" - frame_desc = "Requires 2 pieces of cable and 2 Console Screens." - req_components = list( - /obj/item/stack/cable_coil = 2, - /obj/item/stock_parts/console_screen = 2) - /obj/item/circuitboard/cryo_tube name = "circuit board (Cryotube)" build_path = /obj/machinery/atmospherics/unary/cryo_cell diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm index a6dfb7bd848..3900acf5093 100644 --- a/code/modules/research/designs/machine_designs.dm +++ b/code/modules/research/designs/machine_designs.dm @@ -122,16 +122,6 @@ build_path = /obj/item/circuitboard/bodyscanner category = list("Medical Machinery") -/datum/design/bodyscanner_console - name = "Machine Board (Body Scanner Console)" - desc = "Allows for the construction of circuit boards used to build a Body Scanner Console." - id = "bodyscanner_console" - req_tech = list("programming" = 3, "biotech" = 2, "engineering" = 3) - build_type = IMPRINTER - materials = list(MAT_GLASS = 1000) - build_path = /obj/item/circuitboard/bodyscanner_console - category = list("Medical Machinery") - /datum/design/clonepod name = "Machine Board (Cloning Pod)" desc = "Allows for the construction of circuit boards used to build a Cloning Pod." From 4b673ab11b5f217f78d6df85b6ce50caeca8d3ac Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Mon, 23 Sep 2019 00:11:04 -0400 Subject: [PATCH 24/24] Automatic changelog generation for PR #12377 [ci skip] --- html/changelogs/AutoChangeLog-pr-12377.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-12377.yml diff --git a/html/changelogs/AutoChangeLog-pr-12377.yml b/html/changelogs/AutoChangeLog-pr-12377.yml new file mode 100644 index 00000000000..529267617e0 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-12377.yml @@ -0,0 +1,4 @@ +author: "Fox McCloud" +delete-after: True +changes: + - tweak: "Bodyscanners are similar to sleepers; interact with them by clicking on the scanner; there is no console anymore"