From 2e7be24aadb1298382cb11929cba57bd2c2ded8c Mon Sep 17 00:00:00 2001 From: Rhials <28870487+Rhials@users.noreply.github.com> Date: Mon, 20 Jan 2025 15:18:49 -0500 Subject: [PATCH 01/35] Honor-riffic: Adds toggleable honorific titles to certain job ID trims (#88309) ## About The Pull Request This implements a new, minor, but flavorful system to IDs -- Honorifics. Does going by your full name not suit you? Do you demand respect for the position on Space Station 13 that you've earned and want to be addressed by your title? Do you take yourself WAY too seriously? This is for you. Toggled by ctrl-clicking your ID, honorifics append a title to your name depending on your position. Certain titles (Captain, Officer, Doctor, etc.) will only append to the start (replacing or including the first/last name), while others (PhD., Esq.) can only be appended at the end. ![image](https://github.com/user-attachments/assets/3ae22744-5f6e-4d12-9ea8-ecd60456b5a9) Each job TRIM has a set honorific and positions it can be assigned to. A doctor can be "Doctor Peterson" or "Doctor Peterson Bungle" or "Doctor Bungle". A Lawyer can only choose to be "Peterson Bungle, Esq.". This will only occur when the speaker's voice is the same identity as the one written on the ID's registered name. This should not interfere with Unknown voice obfuscation, stolen ID shenanigans, or anything gameplay-oriented. Hopefully. This feature is also mononym friendly! ![image](https://github.com/user-attachments/assets/21555023-5dd0-49e0-acd5-2dd0a06ae621) This also makes `first_name()` and `last_name()` global procs, and adds one to check if a passed string has spaces/dashes/whitespace/whatever. All of this is compatible with ID name changes, but the voice name must align with the card name to display the honorific. If you are "Peter Stinkypants" with your honorific set to display "Doctor Stinkypants", and your ID's registered name is changed to "Peter Stinker", you show up as "Peter Stinkypants (as Peter Stinker)" with no honorific provided. If you become "Peter Stinker" and have a "Peter Stinker" ID, you will show up as "Doctor Stinker" once again. That all make sense? Great.
So about the ID name stuff...
So, when you activate an honorific on your ID, it DOES change the actual object's name. Not the registered name, but the ID's name will go from "Peter Dawson's ID card" to "Captain Dawson's ID card" when an honorific is applied. This, as far as I've tested, does not mess with anything important, but I can totally see it doing so in a way that makes ctrl-Fing through logs harder than it needs to be. This could probably be changed without too much effort so if the issue does arise I can fix it. If not I am totally fine with reverting this PR until I can make it work (if I can at all).
Admittedly this doesn't have much testing with holopads/radios, but I'm confident the message composure is handled well enough to only display the right names under the right circumstances. If this fucks up logging or naming in any way tell me ASAP because I have a sinking feeling it will in a way more catastrophic than I could ever predict. This PR has been tested thoroughly but I have my limits.
--- code/__DEFINES/id_cards.dm | 19 ++++ code/__DEFINES/say.dm | 3 + code/__HELPERS/names.dm | 19 ++++ code/datums/id_trim/_id_trim.dm | 4 + code/datums/id_trim/centcom.dm | 30 +++++ code/datums/id_trim/jobs.dm | 53 ++++++++- code/datums/id_trim/outfits.dm | 2 + code/datums/id_trim/syndicate.dm | 7 ++ code/datums/voice_of_god_command.dm | 4 +- code/game/machinery/computer/arcade/orion.dm | 2 +- code/game/objects/items/cards_ids.dm | 103 +++++++++++++++++- code/game/say.dm | 13 ++- code/modules/hallucination/fake_chat.dm | 6 +- code/modules/hallucination/fake_death.dm | 2 +- .../mob/living/carbon/human/human_helpers.dm | 2 +- code/modules/mob/mob_helpers.dm | 12 -- 16 files changed, 257 insertions(+), 24 deletions(-) diff --git a/code/__DEFINES/id_cards.dm b/code/__DEFINES/id_cards.dm index a42016dd3de3f..2d720630ce637 100644 --- a/code/__DEFINES/id_cards.dm +++ b/code/__DEFINES/id_cards.dm @@ -42,3 +42,22 @@ * Used to crop the ID card's transparency away when chaching the icon for better use in tgui chat. */ #define ID_ICON_BORDERS 1, 9, 32, 24 + +///Honorific will display next to the first name. +#define HONORIFIC_POSITION_FIRST (1<<0) +///Honorific will display next to the last name. +#define HONORIFIC_POSITION_LAST (1<<1) +///Honorific will not be displayed. +#define HONORIFIC_POSITION_NONE (1<<2) +///Honorific will be appended to the full name at the start. +#define HONORIFIC_POSITION_FIRST_FULL (1<<3) +///Honorific will be appended to the full name at the end. +#define HONORIFIC_POSITION_LAST_FULL (1<<4) + +#define HONORIFIC_POSITION_BITFIELDS(...) list( \ + "Honorific + First Name" = HONORIFIC_POSITION_FIRST, \ + "Honorific + Last Name" = HONORIFIC_POSITION_LAST, \ + "Honorific + Full Name" = HONORIFIC_POSITION_FIRST_FULL, \ + "Full Name + Honorific" = HONORIFIC_POSITION_LAST_FULL, \ + "Disable Honorific" = HONORIFIC_POSITION_NONE, \ +) diff --git a/code/__DEFINES/say.dm b/code/__DEFINES/say.dm index c3bd425af0a65..d80e0d1af2b80 100644 --- a/code/__DEFINES/say.dm +++ b/code/__DEFINES/say.dm @@ -129,3 +129,6 @@ ///Defines for priorities for the bubble_icon_override comp #define BUBBLE_ICON_PRIORITY_ACCESSORY 2 #define BUBBLE_ICON_PRIORITY_ORGAN 1 + +/// Sent from /atom/movable/proc/compose_message() to find an honorific. Compatible with NAME_PART_INDEX: (list/stored_name, mob/living/carbon/carbon_human) +#define COMSIG_ID_GET_HONORIFIC "id_get_honorific" diff --git a/code/__HELPERS/names.dm b/code/__HELPERS/names.dm index 3a82c8dc1a66c..c0615dc746b5b 100644 --- a/code/__HELPERS/names.dm +++ b/code/__HELPERS/names.dm @@ -374,3 +374,22 @@ GLOBAL_DATUM(syndicate_code_response_regex, /regex) return "a rolling pin" else return "something... but the gods didn't set this up right (Please report this bug)" + +///Find the first name of a mob from a passed string with regex +/proc/first_name(given_name) + var/static/regex/firstname = new("^\[^\\s-\]+") //First word before whitespace or "-" + firstname.Find(given_name) + return firstname.match + +/// Find the last name of a mob from a passed string with regex +/proc/last_name(given_name) + var/static/regex/lasttname = new("\[^\\s-\]+$") //First word before whitespace or "-" + lasttname.Find(given_name) + return lasttname.match + +/// Find whitespace or dashes in the passed string with regex and returns TRUE if found +/proc/is_mononym(given_name) + var/static/regex/breaks = regex(@"\s") + if(breaks.Find(given_name)) + return FALSE + return TRUE diff --git a/code/datums/id_trim/_id_trim.dm b/code/datums/id_trim/_id_trim.dm index 32bafcb41d3f7..b9356e9c35dc9 100644 --- a/code/datums/id_trim/_id_trim.dm +++ b/code/datums/id_trim/_id_trim.dm @@ -28,6 +28,10 @@ var/big_pointer = FALSE ///If set, IDs with this trim will give wearers arrows of different colors when pointing var/pointer_color + /// What honorifics, if any, will we set our wearer's name to when worn? + var/list/honorifics + /// What positions can our honorific take? To prevent names like "Peter Dr." + var/honorific_positions = NONE /datum/id_trim/proc/find_job() return null diff --git a/code/datums/id_trim/centcom.dm b/code/datums/id_trim/centcom.dm index 498a4de254e3b..7432540f07f35 100644 --- a/code/datums/id_trim/centcom.dm +++ b/code/datums/id_trim/centcom.dm @@ -23,6 +23,8 @@ department_color = COLOR_CENTCOM_BLUE subdepartment_color = COLOR_SERVICE_LIME big_pointer = FALSE + honorifics = list("Custodian") + honorific_positions = HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE /// Trim for Centcom Thunderdome Overseers. /datum/id_trim/centcom/thunderdome_overseer @@ -39,11 +41,15 @@ access = list(ACCESS_CENT_GENERAL, ACCESS_CENT_LIVING, ACCESS_WEAPONS) assignment = "CentCom Intern" big_pointer = FALSE + honorifics = list("Intern") + honorific_positions = HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE /// Trim for Centcom Head Interns. Different assignment, common station access added on. /datum/id_trim/centcom/intern/head assignment = "CentCom Head Intern" big_pointer = TRUE + honorifics = list("Head Intern") + honorific_positions = HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE /datum/id_trim/centcom/intern/head/New() . = ..() @@ -66,6 +72,8 @@ /datum/id_trim/centcom/medical_officer access = list(ACCESS_CENT_GENERAL, ACCESS_CENT_LIVING, ACCESS_CENT_MEDICAL) assignment = JOB_CENTCOM_MEDICAL_DOCTOR + honorifics = list("Doctor", "Dr.") + honorific_positions = HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE /// Trim for Centcom Research Officers. /datum/id_trim/centcom/research_officer @@ -94,6 +102,8 @@ /// Trim for Centcom Commanders. All Centcom and Station Access. /datum/id_trim/centcom/commander assignment = JOB_CENTCOM_COMMANDER + honorifics = list("Commander", "CMDR.") + honorific_positions = HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE /datum/id_trim/centcom/commander/New() . = ..() @@ -105,6 +115,9 @@ assignment = JOB_ERT_DEATHSQUAD trim_state = "trim_deathcommando" sechud_icon_state = SECHUD_DEATH_COMMANDO + honorifics = list("Commando") + honorific_positions = HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE + /datum/id_trim/centcom/deathsquad/New() . = ..() @@ -114,6 +127,8 @@ /// Trim for generic ERT interns. No universal ID card changing access. /datum/id_trim/centcom/ert assignment = "Emergency Response Team Intern" + honorifics = list("Intern") + honorific_positions = HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE /datum/id_trim/centcom/ert/New() . = ..() @@ -138,6 +153,8 @@ subdepartment_color = COLOR_SECURITY_RED sechud_icon_state = SECHUD_SECURITY_RESPONSE_OFFICER big_pointer = FALSE + honorifics = list("Officer") + honorific_positions = HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE /datum/id_trim/centcom/ert/security/New() . = ..() @@ -164,6 +181,9 @@ subdepartment_color = COLOR_MEDICAL_BLUE sechud_icon_state = SECHUD_MEDICAL_RESPONSE_OFFICER big_pointer = FALSE + honorifics = list("Doctor", "Dr.") + honorific_positions = HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE + /datum/id_trim/centcom/ert/medical/New() . = ..() @@ -177,6 +197,9 @@ subdepartment_color = COLOR_SERVICE_LIME sechud_icon_state = SECHUD_RELIGIOUS_RESPONSE_OFFICER big_pointer = FALSE + honorifics = list("Chaplain") + honorific_positions = HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE + /datum/id_trim/centcom/ert/chaplain/New() . = ..() @@ -190,6 +213,9 @@ subdepartment_color = COLOR_SERVICE_LIME sechud_icon_state = SECHUD_JANITORIAL_RESPONSE_OFFICER big_pointer = FALSE + honorifics = list("Custodian") + honorific_positions = HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE + /datum/id_trim/centcom/ert/janitor/New() . = ..() @@ -212,7 +238,11 @@ /datum/id_trim/centcom/ert/militia assignment = "Frontier Militia" big_pointer = FALSE + honorifics = list("Minuteman") + honorific_positions = HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE /datum/id_trim/centcom/ert/militia/general assignment = "Frontier Militia General" big_pointer = TRUE + honorifics = list("Minuteman General", "General") + honorific_positions = HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE diff --git a/code/datums/id_trim/jobs.dm b/code/datums/id_trim/jobs.dm index 34432a638db01..4b8b630617571 100644 --- a/code/datums/id_trim/jobs.dm +++ b/code/datums/id_trim/jobs.dm @@ -134,6 +134,8 @@ ACCESS_CE, ) job = /datum/job/atmospheric_technician + honorifics = list("Technician") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/bartender assignment = JOB_BARTENDER @@ -181,6 +183,8 @@ ACCESS_HOP, ) job = /datum/job/pun_pun + honorifics = list(", Almighty Scourge") + honorific_positions = HONORIFIC_POSITION_LAST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/bitrunner assignment = JOB_BITRUNNER @@ -250,6 +254,8 @@ ACCESS_CHANGE_IDS, ) job = /datum/job/bridge_assistant + honorifics = list("Underling", "Assistant", "Mate") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/captain assignment = JOB_CAPTAIN @@ -266,6 +272,8 @@ job = /datum/job/captain big_pointer = TRUE pointer_color = COLOR_COMMAND_BLUE + honorifics = list("Captain", "Cpt.") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /// Captain gets all station accesses hardcoded in because it's the Captain. /datum/id_trim/job/captain/New() @@ -300,6 +308,9 @@ ACCESS_QM, ) job = /datum/job/cargo_technician + honorifics = list("Courier") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE + /datum/id_trim/job/chaplain assignment = JOB_CHAPLAIN @@ -322,6 +333,8 @@ ACCESS_HOP, ) job = /datum/job/chaplain + honorifics = list("Chaplain", "Reverend") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/chemist assignment = JOB_CHEMIST @@ -390,6 +403,8 @@ job = /datum/job/chief_engineer big_pointer = TRUE pointer_color = COLOR_ENGINEERING_ORANGE + honorifics = list("Chief") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE /datum/id_trim/job/chief_medical_officer assignment = JOB_CHIEF_MEDICAL_OFFICER @@ -431,6 +446,8 @@ job = /datum/job/chief_medical_officer big_pointer = TRUE pointer_color = COLOR_MEDICAL_BLUE + honorifics = list(", PhD.", ", MD.") + honorific_positions = HONORIFIC_POSITION_LAST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/clown assignment = JOB_CLOWN @@ -473,10 +490,14 @@ ACCESS_HOP, ) job = /datum/job/cook + honorifics = list("Cook") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/cook/chef assignment = JOB_CHEF sechud_icon_state = SECHUD_CHEF + honorifics = list("Chef") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/coroner assignment = JOB_CORONER @@ -553,6 +574,8 @@ ACCESS_HOS, ) job = /datum/job/detective + honorifics = list("Detective", "Investigator") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/detective/refresh_trim_access() . = ..() @@ -697,6 +720,8 @@ job = /datum/job/head_of_security big_pointer = TRUE pointer_color = COLOR_SECURITY_RED + honorifics = list("Chief Officer", "Chief", "Officer") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/head_of_security/refresh_trim_access() . = ..() @@ -727,6 +752,8 @@ ACCESS_CHANGE_IDS, ) job = /datum/job/janitor + honorifics = list("Custodian") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/lawyer assignment = JOB_LAWYER @@ -748,6 +775,8 @@ ACCESS_HOP, ) job = /datum/job/lawyer + honorifics = list(", Esq.") + honorific_positions = HONORIFIC_POSITION_LAST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/medical_doctor assignment = JOB_MEDICAL_DOCTOR @@ -773,6 +802,8 @@ ACCESS_CMO, ) job = /datum/job/doctor + honorifics = list("Doctor", "Dr.") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/mime assignment = JOB_MIME @@ -824,6 +855,8 @@ ACCESS_CMO, ) job = /datum/job/paramedic + honorifics = list("EMT") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/prisoner assignment = JOB_PRISONER @@ -839,6 +872,8 @@ ) job = /datum/job/prisoner threat_modifier = 1 // I'm watching you + honorifics = list("Convict") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/prisoner/one trim_state = "trim_prisoner_1" @@ -891,6 +926,8 @@ ACCESS_HOP, ) job = /datum/job/psychologist + honorifics = list(", PhD.") + honorific_positions = HONORIFIC_POSITION_LAST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/quartermaster assignment = JOB_QUARTERMASTER @@ -931,6 +968,8 @@ job = /datum/job/quartermaster big_pointer = TRUE pointer_color = COLOR_CARGO_BROWN + honorifics = list("Manager") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/research_director assignment = JOB_RESEARCH_DIRECTOR @@ -981,6 +1020,8 @@ job = /datum/job/research_director big_pointer = TRUE pointer_color = COLOR_SCIENCE_PINK + honorifics = list("Director", "Dir.") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/roboticist assignment = JOB_ROBOTICIST @@ -1038,6 +1079,8 @@ ACCESS_RD, ) job = /datum/job/scientist + honorifics = list("Researcher") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /// Sec officers have departmental variants. They each have their own trims with bonus departmental accesses. /datum/id_trim/job/security_officer @@ -1066,6 +1109,8 @@ ACCESS_HOS, ) job = /datum/job/security_officer + honorifics = list("Officer") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /// List of bonus departmental accesses that departmental sec officers get by default. var/department_access = list() /// List of bonus departmental accesses that departmental security officers can in relation to how many overall security officers there are if the scaling system is set up. These can otherwise be granted via config settings. @@ -1144,6 +1189,7 @@ ACCESS_SURGERY, ACCESS_VIROLOGY, ) + honorifics = list("Orderly", "Officer") /datum/id_trim/job/security_officer/science assignment = JOB_SECURITY_OFFICER_SCIENCE @@ -1226,6 +1272,8 @@ ACCESS_CE, ) job = /datum/job/station_engineer + honorifics = list("Engineer") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/veteran_advisor assignment = JOB_VETERAN_ADVISOR @@ -1247,6 +1295,8 @@ template_access = list() job = /datum/job/veteran_advisor big_pointer = TRUE + honorifics = list("General", "Gen.") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/veteran_advisor/refresh_trim_access() . = ..() @@ -1258,7 +1308,6 @@ if(CONFIG_GET(flag/security_has_maint_access)) access |= list(ACCESS_MAINT_TUNNELS) - /datum/id_trim/job/warden assignment = JOB_WARDEN trim_state = "trim_warden" @@ -1286,6 +1335,8 @@ ACCESS_HOS, ) job = /datum/job/warden + honorifics = list("Officer", "Watchman", "Lieutenant", "Lt.") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/warden/refresh_trim_access() . = ..() diff --git a/code/datums/id_trim/outfits.dm b/code/datums/id_trim/outfits.dm index a2944a469f43e..c46938be6e094 100644 --- a/code/datums/id_trim/outfits.dm +++ b/code/datums/id_trim/outfits.dm @@ -71,6 +71,8 @@ department_color = COLOR_BLACK subdepartment_color = COLOR_GREEN threat_modifier = -1 // Cops recognise cops + honorifics = list("CISO") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE /datum/id_trim/cyber_police/New() . = ..() diff --git a/code/datums/id_trim/syndicate.dm b/code/datums/id_trim/syndicate.dm index 41c76aaf3784c..28a0429d9352f 100644 --- a/code/datums/id_trim/syndicate.dm +++ b/code/datums/id_trim/syndicate.dm @@ -17,6 +17,10 @@ big_pointer = FALSE /// Interdyne medical Staff +/datum/id_trim/syndicom/Interdyne + honorifics = list(", PhD.") + honorific_positions = HONORIFIC_POSITION_LAST_FULL | HONORIFIC_POSITION_NONE + /datum/id_trim/syndicom/Interdyne/pharmacist assignment = "Interdyne Pharmacist" trim_state = "trim_medicaldoctor" @@ -46,6 +50,9 @@ access = list(ACCESS_SYNDICATE, ACCESS_MAINT_TUNNELS) big_pointer = FALSE pointer_color = null + honorifics = list("Auditor") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE + /datum/id_trim/syndicom/irs/auditor assignment = "Internal Revenue Service Head Auditor" diff --git a/code/datums/voice_of_god_command.dm b/code/datums/voice_of_god_command.dm index 21d4f460617b6..3bbd5768e21e3 100644 --- a/code/datums/voice_of_god_command.dm +++ b/code/datums/voice_of_god_command.dm @@ -52,12 +52,12 @@ GLOBAL_LIST_INIT(voice_of_god_commands, init_voice_of_god_commands()) listeners += candidate //Let's ensure the listener's name is not matched within another word or command (and viceversa). e.g. "Saul" in "somersault" - var/their_first_name = candidate.first_name() + var/their_first_name = first_name(candidate.name) if(!GLOB.all_voice_of_god_triggers.Find(their_first_name) && findtext(message, regex("(\\L|^)[their_first_name](\\L|$)", "i"))) specific_listeners += candidate //focus on those with the specified name to_remove_string += "[to_remove_string ? "|" : null][their_first_name]" continue - var/their_last_name = candidate.last_name() + var/their_last_name = last_name(candidate.name) if(their_last_name != their_first_name && !GLOB.all_voice_of_god_triggers.Find(their_last_name) && findtext(message, regex("(\\L|^)[their_last_name](\\L|$)", "i"))) specific_listeners += candidate // Ditto to_remove_string += "[to_remove_string ? "|" : null][their_last_name]" diff --git a/code/game/machinery/computer/arcade/orion.dm b/code/game/machinery/computer/arcade/orion.dm index a6685e4782ccd..c8236b5e8839f 100644 --- a/code/game/machinery/computer/arcade/orion.dm +++ b/code/game/machinery/computer/arcade/orion.dm @@ -85,7 +85,7 @@ /obj/machinery/computer/arcade/orion_trail/proc/newgame() // Set names of settlers in crew var/mob/living/player = usr - var/player_crew_name = player.first_name() + var/player_crew_name = first_name(player.name) settlers = list() for(var/i in 1 to ORION_STARTING_CREW_COUNT - 1) //one reserved to be YOU add_crewmember(update = FALSE) diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm index afc121ab770c5..181bc6eef64c3 100644 --- a/code/game/objects/items/cards_ids.dm +++ b/code/game/objects/items/cards_ids.dm @@ -32,6 +32,8 @@ /// Cached icon that has been built for this card. Intended to be displayed in chat. Cardboards IDs and actual IDs use it. var/icon/cached_flat_icon + ///What is our honorific name/title combo to be displayed? + var/honorific_title /obj/item/card/suicide_act(mob/living/carbon/user) user.visible_message(span_suicide("[user] begins to swipe [user.p_their()] neck with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")) @@ -111,6 +113,11 @@ var/big_pointer = FALSE ///If set, the arrow will have a different color. var/pointer_color + /// Will this ID card use the first or last name as the name displayed with the honorific? + var/honorific_position = HONORIFIC_POSITION_NONE + /// What is our selected honorific? + var/chosen_honorific + /datum/armor/card_id fire = 100 @@ -142,6 +149,7 @@ register_context() RegisterSignal(src, COMSIG_ATOM_UPDATED_ICON, PROC_REF(update_in_wallet)) + RegisterSignal(src, COMSIG_ID_GET_HONORIFIC, PROC_REF(return_message_name_part)) if(prob(1)) ADD_TRAIT(src, TRAIT_TASTEFULLY_THICK_ID_CARD, ROUNDSTART_TRAIT) @@ -157,6 +165,20 @@ if(slot == ITEM_SLOT_ID) RegisterSignal(user, COMSIG_MOVABLE_POINTED, PROC_REF(on_pointed)) +/obj/item/card/id/proc/return_message_name_part(datum/source, list/stored_name, mob/living/carbon/carbon_human) + SIGNAL_HANDLER + var/voice_name = carbon_human.GetVoice() + var/end_string = "" + var/return_string = "" + if(carbon_human.name != voice_name) + end_string += " (as [registered_name])" + if(trim && honorific_position != HONORIFIC_POSITION_NONE && (carbon_human.name == voice_name)) //The voice and name are the same, so we display the title. + return_string += honorific_title + else + return_string += voice_name //Name on the ID ain't the same as the speaker, so we display their real name with no title. + return_string += end_string + stored_name[NAME_PART_INDEX] = return_string + /obj/item/card/id/proc/on_pointed(mob/living/user, atom/pointed, obj/effect/temp_visual/point/point) SIGNAL_HANDLER if((!big_pointer && !pointer_color) || HAS_TRAIT(user, TRAIT_UNKNOWN)) @@ -478,6 +500,8 @@ context[SCREENTIP_CONTEXT_ALT_RMB] = "Assign account" else if(registered_account.account_balance > 0) context[SCREENTIP_CONTEXT_ALT_LMB] = "Withdraw credits" + if(trim && length(trim.honorifics)) + context[SCREENTIP_CONTEXT_CTRL_LMB] = "Toggle honorific" return CONTEXTUAL_SCREENTIP_SET /obj/item/card/id/proc/try_project_paystand(mob/user, turf/target) @@ -786,7 +810,7 @@ for(var/mob/living/carbon/human/viewing_mob in viewers(user, 2)) if(viewing_mob.stat || viewing_mob == user) continue - viewing_mob.say("Is something wrong? [user.first_name()]... you're sweating.", forced = "psycho") + viewing_mob.say("Is something wrong? [first_name(user.name)]... you're sweating.", forced = "psycho") break /obj/item/card/id/examine_more(mob/user) @@ -845,7 +869,15 @@ /// Updates the name based on the card's vars and state. /obj/item/card/id/proc/update_label() - var/name_string = registered_name ? "[registered_name]'s ID Card" : initial(name) + var/name_string + if(registered_name) + if(trim && (honorific_position & ~HONORIFIC_POSITION_NONE)) + name_string = "[update_honorific()]'s ID Card" + else + name_string = "[registered_name]'s ID Card" + else + name_string = initial(name) + var/assignment_string if(is_intern) @@ -858,6 +890,24 @@ name = "[name_string] ([assignment_string])" +/// Re-generates the honorific title. Returns the compiled honorific_title value +/obj/item/card/id/proc/update_honorific() + var/is_mononym = is_mononym(registered_name) + switch(honorific_position) + if(HONORIFIC_POSITION_FIRST) + honorific_title = "[chosen_honorific] [first_name(registered_name)]" + if(HONORIFIC_POSITION_LAST) + honorific_title = "[chosen_honorific] [last_name(registered_name)]" + if(HONORIFIC_POSITION_FIRST_FULL) + honorific_title = "[chosen_honorific] [first_name(registered_name)]" + if(!is_mononym) + honorific_title += " [last_name(registered_name)]" + if(HONORIFIC_POSITION_LAST_FULL) + if(!is_mononym) + honorific_title += "[first_name(registered_name)] " + honorific_title += "[last_name(registered_name)][chosen_honorific]" + return honorific_title + /// Returns the trim assignment name. /obj/item/card/id/proc/get_trim_assignment() return trim?.assignment || assignment @@ -871,6 +921,55 @@ return insert_money(interacting_with, user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING return NONE +/obj/item/card/id/item_ctrl_click(mob/user) + if(!in_contents_of(user) || user.incapacitated) //Check if the ID is in the ID slot, so it can be changed from there too. + return + + if(!trim) + balloon_alert(user, "card has no trim!") + return + + if(!length(trim.honorifics)) + balloon_alert(user, "card has no honorific to use!") + return + + var/list/choices = list() + var/list/readable_names = HONORIFIC_POSITION_BITFIELDS() + for(var/i in readable_names) //Filter out the options you don't have on your ID. + if(trim.honorific_positions & readable_names[i]) //If the positions list has the same bit value as the readable list. + choices += i + + var/chosen_position = tgui_input_list(user, "What position do you want your honorific in?", "Flair!", choices) + if(user.incapacitated || !in_contents_of(user)) + return + var/honorific_position_to_use = readable_names[chosen_position] + + honorific_position = initial(honorific_position) //In case you want to force an honorific on an ID, set a default that won't always be NONE. + honorific_title = null //We reset this regardless so that we don't stack titles on accident. + + if(honorific_position_to_use & HONORIFIC_POSITION_NONE) + balloon_alert(user, "honorific disabled") + else + var/new_honorific = tgui_input_list(user, "What honorific do you want to use?", "Flair!!!", trim.honorifics) + if(!new_honorific || user.incapacitated || !in_contents_of(user)) + return + chosen_honorific = new_honorific + switch(honorific_position_to_use) + if(HONORIFIC_POSITION_FIRST) + honorific_position = HONORIFIC_POSITION_FIRST + balloon_alert(user, "honorific set: display first name") + if(HONORIFIC_POSITION_LAST) + honorific_position = HONORIFIC_POSITION_LAST + balloon_alert(user, "honorific set: display last name") + if(HONORIFIC_POSITION_FIRST_FULL) + honorific_position = HONORIFIC_POSITION_FIRST_FULL + balloon_alert(user, "honorific set: start of full name") + if(HONORIFIC_POSITION_LAST_FULL) + honorific_position = HONORIFIC_POSITION_LAST_FULL + balloon_alert(user, "honorific set: end of full name") + + update_label() + /obj/item/card/id/away name = "\proper a perfectly generic identification card" desc = "A perfectly generic identification card. Looks like it could use some flavor." diff --git a/code/game/say.dm b/code/game/say.dm index 4a37bad451b49..e597ffc7b11f8 100644 --- a/code/game/say.dm +++ b/code/game/say.dm @@ -148,7 +148,18 @@ GLOBAL_LIST_INIT(freqtospan, list( //Speaker name var/namepart var/list/stored_name = list(null) - SEND_SIGNAL(speaker, COMSIG_MOVABLE_MESSAGE_GET_NAME_PART, stored_name, visible_name) + + if(iscarbon(speaker)) //First, try to pull the modified title from a carbon's ID. This will override both visual and audible names. + var/mob/living/carbon/carbon_human = speaker + var/obj/item/id_slot = carbon_human.get_item_by_slot(ITEM_SLOT_ID) + if(id_slot) + var/obj/item/card/id/id_card = id_slot?.GetID() + if(id_card) + SEND_SIGNAL(id_card, COMSIG_ID_GET_HONORIFIC, stored_name, carbon_human) + + if(!stored_name[NAME_PART_INDEX]) //Otherwise, we just use whatever the name signal gives us. + SEND_SIGNAL(speaker, COMSIG_MOVABLE_MESSAGE_GET_NAME_PART, stored_name, visible_name) + namepart = stored_name[NAME_PART_INDEX] || "[speaker.GetVoice()]" //End name span. diff --git a/code/modules/hallucination/fake_chat.dm b/code/modules/hallucination/fake_chat.dm index 049a337c1101c..963e718eed865 100644 --- a/code/modules/hallucination/fake_chat.dm +++ b/code/modules/hallucination/fake_chat.dm @@ -50,7 +50,7 @@ chosen = pick(list("Help!", "[pick_list_replacements(HALLUCINATION_FILE, "people")] is [pick_list_replacements(HALLUCINATION_FILE, "accusations")]!", "[pick_list_replacements(HALLUCINATION_FILE, "threat")] in [pick_list_replacements(HALLUCINATION_FILE, "location")][prob(50)?"!":"!!"]", - "[pick("Where's [hallucinator.first_name()]?", "Set [hallucinator.first_name()] to arrest!")]", + "[pick("Where's [first_name(hallucinator.name)]?", "Set [first_name(hallucinator.name)] to arrest!")]", "[pick("C","Ai, c","Someone c","Rec")]all the shuttle!", "AI [pick("rogue", "is dead")]!!", "Borgs rogue!", @@ -58,7 +58,7 @@ else chosen = pick(list("[pick_list_replacements(HALLUCINATION_FILE, "suspicion")]", "[pick_list_replacements(HALLUCINATION_FILE, "conversation")]", - "[pick_list_replacements(HALLUCINATION_FILE, "greetings")][hallucinator.first_name()]!", + "[pick_list_replacements(HALLUCINATION_FILE, "greetings")][first_name(hallucinator.name)]!", "[pick_list_replacements(HALLUCINATION_FILE, "getout")]", "[pick_list_replacements(HALLUCINATION_FILE, "weird")]", "[pick_list_replacements(HALLUCINATION_FILE, "didyouhearthat")]", @@ -71,7 +71,7 @@ chosen = capitalize(chosen) - chosen = replacetext(chosen, "%TARGETNAME%", hallucinator.first_name()) + chosen = replacetext(chosen, "%TARGETNAME%", first_name(hallucinator.name)) // Log the message feedback_details += "Type: [is_radio ? "Radio" : "Talk"], Source: [speaker.real_name], Message: [chosen]" diff --git a/code/modules/hallucination/fake_death.dm b/code/modules/hallucination/fake_death.dm index 126e9dd3a2b48..9583418f23220 100644 --- a/code/modules/hallucination/fake_death.dm +++ b/code/modules/hallucination/fake_death.dm @@ -59,7 +59,7 @@ "FUCK", "git gud", "god damn it", - "hey [hallucinator.first_name()]", + "hey [first_name(hallucinator.name)]", "i[prob(50) ? " fucking" : ""] hate [pick(things_to_hate)]", "is the AI rogue?", "rip", diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index 1d72b9b1f17ec..8166612a87333 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -45,7 +45,7 @@ return signal_face // no need to null-check, because force_set will always set a signal_face var/face_name = !isnull(signal_face) ? signal_face : get_face_name("") var/id_name = !isnull(signal_id) ? signal_id : get_id_name("") - if (force_real_name) + if(force_real_name) var/fake_name if (face_name && face_name != real_name) fake_name = face_name diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 006b2684c9755..ffc201940847a 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -216,18 +216,6 @@ return M return 0 -///Find the first name of a mob from the real name with regex -/mob/proc/first_name() - var/static/regex/firstname = new("^\[^\\s-\]+") //First word before whitespace or "-" - firstname.Find(real_name) - return firstname.match - -/// Find the last name of a mob from the real name with regex -/mob/proc/last_name() - var/static/regex/lasttname = new("\[^\\s-\]+$") //First word before whitespace or "-" - lasttname.Find(real_name) - return lasttname.match - ///Returns a mob's real name between brackets. Useful when you want to display a mob's name alongside their real name /mob/proc/get_realname_string() if(real_name && real_name != name) From 2ac49eb11293b6418913e6517000edcbd2e9a395 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Mon, 20 Jan 2025 20:26:27 +0000 Subject: [PATCH 02/35] Automatic changelog for PR #88309 [ci skip] --- html/changelogs/AutoChangeLog-pr-88309.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-88309.yml diff --git a/html/changelogs/AutoChangeLog-pr-88309.yml b/html/changelogs/AutoChangeLog-pr-88309.yml new file mode 100644 index 0000000000000..8aacfcb95343c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88309.yml @@ -0,0 +1,4 @@ +author: "Rhials" +delete-after: True +changes: + - rscadd: "You can now ctrl-click IDs to set your Honorific, which will change your display name to reflect your TITLE as a WORKING MAN on SPACE STATION 13." \ No newline at end of file From 54cac28b9987be87ca000b26f49fee25975e4f52 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Tue, 21 Jan 2025 02:00:15 +0000 Subject: [PATCH 03/35] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-88309.yml | 4 ---- html/changelogs/AutoChangeLog-pr-89047.yml | 5 ----- html/changelogs/AutoChangeLog-pr-89095.yml | 4 ---- html/changelogs/AutoChangeLog-pr-89137.yml | 4 ---- html/changelogs/archive/2025-01.yml | 12 ++++++++++++ 5 files changed, 12 insertions(+), 17 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-88309.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89047.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89095.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89137.yml diff --git a/html/changelogs/AutoChangeLog-pr-88309.yml b/html/changelogs/AutoChangeLog-pr-88309.yml deleted file mode 100644 index 8aacfcb95343c..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88309.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Rhials" -delete-after: True -changes: - - rscadd: "You can now ctrl-click IDs to set your Honorific, which will change your display name to reflect your TITLE as a WORKING MAN on SPACE STATION 13." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89047.yml b/html/changelogs/AutoChangeLog-pr-89047.yml deleted file mode 100644 index 784e95a25ddc0..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89047.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "NamelessFairy" -delete-after: True -changes: - - bugfix: "Admin fired stray syndicate cargo pods will not rebel against admin whims and launch themselves when cancelled." - - admin: "Admins have new categories to fill syndicate cargo pods with." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89095.yml b/html/changelogs/AutoChangeLog-pr-89095.yml deleted file mode 100644 index 4e52e9a2c38cc..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89095.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Pickle-Coding" -delete-after: True -changes: - - bugfix: "Fixes HFR moderator leaking not leaking properly when a part is cracked." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89137.yml b/html/changelogs/AutoChangeLog-pr-89137.yml deleted file mode 100644 index bc6196b6256b8..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89137.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "AyIong" -delete-after: True -changes: - - qol: "Vending machines got new design with 2 layouts: List and Grid (List by default)" \ No newline at end of file diff --git a/html/changelogs/archive/2025-01.yml b/html/changelogs/archive/2025-01.yml index d0707a54087d2..f1115177d0d77 100644 --- a/html/changelogs/archive/2025-01.yml +++ b/html/changelogs/archive/2025-01.yml @@ -547,3 +547,15 @@ mc-oofert: - refactor: mimics (bolt of animation, malf ai Machine Override, etc) are basicmobs - bugfix: crate mimics may now be opened +2025-01-21: + AyIong: + - qol: 'Vending machines got new design with 2 layouts: List and Grid (List by default)' + NamelessFairy: + - bugfix: Admin fired stray syndicate cargo pods will not rebel against admin whims + and launch themselves when cancelled. + - admin: Admins have new categories to fill syndicate cargo pods with. + Pickle-Coding: + - bugfix: Fixes HFR moderator leaking not leaking properly when a part is cracked. + Rhials: + - rscadd: You can now ctrl-click IDs to set your Honorific, which will change your + display name to reflect your TITLE as a WORKING MAN on SPACE STATION 13. From fca15d8b03352fba686a0e68b065096a83e5496a Mon Sep 17 00:00:00 2001 From: kuricityy Date: Tue, 21 Jan 2025 00:55:41 -0500 Subject: [PATCH 04/35] Makes Icebox ruins not count towards blob total, as well as preventing them from spawning there. (#89113) ## About The Pull Request Makes icebox ruins not count towards blob total, also stops them from spawning there. ## Why It's Good For The Game I've been seeing a decent bit of blobs spawning on icebox ruins, such as Moffuchi's, the abandoned engineering outpost, Lizard gas, almost every ruin on icebox. The intent of blob isnt to cower off station, ensure likely no one can find you, then branch out onto the station. I understand that wastes blobs exist, but if they do it in the actual wastes, it doesnt count towards their total, and they actually have to branch out into the wastes before they begin. With Z level blobs already fucking over people majorly on icebox if the blob picks the right spot, I'm sure they wont need to be able to spawn in ruins to win. They also cannot spawn in ruins on any other station, so it just seems right to me. ## Changelog :cl: fix: Blob's can no longer place their core in ruins on Icebox. /:cl: --- code/game/area/areas/ruins/_ruins.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/area/areas/ruins/_ruins.dm b/code/game/area/areas/ruins/_ruins.dm index 46cf851b1ebd1..f2ecc7ac73e3e 100644 --- a/code/game/area/areas/ruins/_ruins.dm +++ b/code/game/area/areas/ruins/_ruins.dm @@ -5,7 +5,7 @@ icon = 'icons/area/areas_ruins.dmi' icon_state = "ruins" default_gravity = STANDARD_GRAVITY - area_flags = HIDDEN_AREA | BLOBS_ALLOWED | UNIQUE_AREA + area_flags = HIDDEN_AREA | UNIQUE_AREA ambience_index = AMBIENCE_RUINS flags_1 = CAN_BE_DIRTY_1 sound_environment = SOUND_ENVIRONMENT_STONEROOM From ee3693bfb09990cef02f2a91fa3d3a521edb38b7 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Tue, 21 Jan 2025 07:10:24 +0000 Subject: [PATCH 05/35] Automatic changelog for PR #89113 [ci skip] --- html/changelogs/AutoChangeLog-pr-89113.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89113.yml diff --git a/html/changelogs/AutoChangeLog-pr-89113.yml b/html/changelogs/AutoChangeLog-pr-89113.yml new file mode 100644 index 0000000000000..a11767ec7085f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89113.yml @@ -0,0 +1,4 @@ +author: "kuricityy" +delete-after: True +changes: + - bugfix: "Blob's can no longer place their core in ruins on Icebox." \ No newline at end of file From 4f2ff570907053423b0f0a196ac8f61f0934b551 Mon Sep 17 00:00:00 2001 From: necromanceranne <40847847+necromanceranne@users.noreply.github.com> Date: Wed, 22 Jan 2025 05:21:22 +1100 Subject: [PATCH 06/35] The Big Bess ripley now uses the correct sprite while piloted by an AI. (#89148) --- code/modules/vehicles/mecha/working/ripley.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/vehicles/mecha/working/ripley.dm b/code/modules/vehicles/mecha/working/ripley.dm index c9fb6b8fdbe2a..29bc3fb4d4841 100644 --- a/code/modules/vehicles/mecha/working/ripley.dm +++ b/code/modules/vehicles/mecha/working/ripley.dm @@ -259,10 +259,11 @@ GLOBAL_DATUM(cargo_ripley, /obj/vehicle/sealed/mecha/ripley/cargo) /obj/vehicle/sealed/mecha/ripley/cargo - desc = "An ailing, old, repurposed cargo hauler. Most of its equipment wires are frayed or missing and its frame is rusted." name = "\improper APLU \"Big Bess\"" + desc = "An ailing, old, repurposed cargo hauler. Most of its equipment wires are frayed or missing and its frame is rusted." icon_state = "hauler" base_icon_state = "hauler" + silicon_icon_state = "hauler-empty" max_integrity = 100 //Has half the health of a normal RIPLEY mech, so it's harder to use as a weapon. /obj/vehicle/sealed/mecha/ripley/cargo/Initialize(mapload) From 6b74818ca80ddc3a472c945d809095b50bda0edf Mon Sep 17 00:00:00 2001 From: Arceniu <129214736+Arceniu@users.noreply.github.com> Date: Tue, 21 Jan 2025 21:21:40 +0300 Subject: [PATCH 07/35] fix: floortile gloves fishing (#89145) --- code/modules/clothing/gloves/combat.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/clothing/gloves/combat.dm b/code/modules/clothing/gloves/combat.dm index 55eeeba723f11..e7e12c8ee4b14 100644 --- a/code/modules/clothing/gloves/combat.dm +++ b/code/modules/clothing/gloves/combat.dm @@ -35,6 +35,6 @@ icon_state = "ftc_gloves" inhand_icon_state = "greyscale_gloves" -/obj/item/clothing/gloves/combat/floortiletile/Initialize(mapload) +/obj/item/clothing/gloves/combat/floortile/Initialize(mapload) . = ..() AddComponent(/datum/component/adjust_fishing_difficulty, -5) //tacticool From e14fce118714e3612372e1bfbe622460dc8eff47 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Tue, 21 Jan 2025 18:21:41 +0000 Subject: [PATCH 08/35] Automatic changelog for PR #89148 [ci skip] --- html/changelogs/AutoChangeLog-pr-89148.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89148.yml diff --git a/html/changelogs/AutoChangeLog-pr-89148.yml b/html/changelogs/AutoChangeLog-pr-89148.yml new file mode 100644 index 0000000000000..ebd628d99c136 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89148.yml @@ -0,0 +1,4 @@ +author: "necromanceranne" +delete-after: True +changes: + - bugfix: "The Big Bess cargo hauler no longer magically becomes (visually) a standard Ripley exosuit." \ No newline at end of file From bc79dff6a75a5b95a5b6a29b3846adc2bad5db0f Mon Sep 17 00:00:00 2001 From: Gear <9438930+the-og-gear@users.noreply.github.com> Date: Tue, 21 Jan 2025 13:22:53 -0500 Subject: [PATCH 09/35] Make deluxe donks uncraftable unless learned (#89143) --- .../modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm index 522f6e9f695f8..130fcb57b696a 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm @@ -418,6 +418,7 @@ ) result = /obj/item/food/donkpocket/deluxe category = CAT_PASTRY + crafting_flags = parent_type::crafting_flags | CRAFT_MUST_BE_LEARNED /datum/crafting_recipe/food/donkpocket/deluxe/nocarb time = 15 From 08a197fdbdd77213199b6c51205cd68bc442c21f Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Tue, 21 Jan 2025 18:23:17 +0000 Subject: [PATCH 10/35] Automatic changelog for PR #89143 [ci skip] --- html/changelogs/AutoChangeLog-pr-89143.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89143.yml diff --git a/html/changelogs/AutoChangeLog-pr-89143.yml b/html/changelogs/AutoChangeLog-pr-89143.yml new file mode 100644 index 0000000000000..9edd1450dccd6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89143.yml @@ -0,0 +1,4 @@ +author: "the-og-gear" +delete-after: True +changes: + - bugfix: "Deluxe Donk Pockets (and their no-carb and vegan variants) are no longer craftable without collecting the recipe." \ No newline at end of file From 03203d50f419e1c67161c35a6f6587c828d9149a Mon Sep 17 00:00:00 2001 From: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Date: Tue, 21 Jan 2025 23:58:08 +0530 Subject: [PATCH 11/35] Fixes `atom_storage` breaking pockets when moving its item to hand (#89141) --- code/datums/storage/storage.dm | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/code/datums/storage/storage.dm b/code/datums/storage/storage.dm index b8bfcf80382de..fe54a84c0769e 100644 --- a/code/datums/storage/storage.dm +++ b/code/datums/storage/storage.dm @@ -856,15 +856,8 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) return COMPONENT_CANCEL_ATTACK_CHAIN if(ishuman(user)) var/mob/living/carbon/human/hum = user - if(hum.l_store == parent && !hum.get_active_held_item()) - INVOKE_ASYNC(hum, TYPE_PROC_REF(/mob, put_in_hands), parent) - hum.l_store = null + if(hum.l_store == parent || hum.r_store == parent) return - if(hum.r_store == parent && !hum.get_active_held_item()) - INVOKE_ASYNC(hum, TYPE_PROC_REF(/mob, put_in_hands), parent) - hum.r_store = null - return - if(parent.loc == user) INVOKE_ASYNC(src, PROC_REF(open_storage), user) return COMPONENT_CANCEL_ATTACK_CHAIN From a43be97d422683f9e6cbb1d1b8b2e859b7064de7 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Tue, 21 Jan 2025 18:28:44 +0000 Subject: [PATCH 12/35] Automatic changelog for PR #89141 [ci skip] --- html/changelogs/AutoChangeLog-pr-89141.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89141.yml diff --git a/html/changelogs/AutoChangeLog-pr-89141.yml b/html/changelogs/AutoChangeLog-pr-89141.yml new file mode 100644 index 0000000000000..a7315cab3523a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89141.yml @@ -0,0 +1,4 @@ +author: "SyncIt21" +delete-after: True +changes: + - bugfix: "pockets update their icons correctly when removing items that have storage (e.g. box of bandages) from them" \ No newline at end of file From 42664adb7799bb561e80774ce09aa60a6107e129 Mon Sep 17 00:00:00 2001 From: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Date: Wed, 22 Jan 2025 00:26:42 +0530 Subject: [PATCH 13/35] Fixes fishing auto reel moving fixed objects (#89144) --- code/modules/fishing/fishing_equipment.dm | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/code/modules/fishing/fishing_equipment.dm b/code/modules/fishing/fishing_equipment.dm index 37aea262426bb..4961fdbc042c8 100644 --- a/code/modules/fishing/fishing_equipment.dm +++ b/code/modules/fishing/fishing_equipment.dm @@ -104,29 +104,30 @@ SIGNAL_HANDLER UnregisterSignal(rod, COMSIG_FISHING_ROD_HOOKED_ITEM) -/obj/item/fishing_line/auto_reel/proc/on_hooked_item(obj/item/fishing_rod/source, atom/target, mob/living/user) +/obj/item/fishing_line/auto_reel/proc/on_hooked_item(obj/item/fishing_rod/source, atom/movable/target, mob/living/user) SIGNAL_HANDLER - if(!ismovable(target)) + + if(!istype(target) || target.anchored || target.move_resist >= MOVE_FORCE_STRONG) return - var/atom/movable/movable_target = target var/please_be_gentle = FALSE var/atom/destination var/datum/callback/throw_callback - if(isliving(movable_target) || !isitem(movable_target)) + if(isliving(target) || !isitem(target)) destination = get_step_towards(user, target) please_be_gentle = TRUE else destination = user - throw_callback = CALLBACK(src, PROC_REF(clear_hitby_signal), movable_target) - RegisterSignal(movable_target, COMSIG_MOVABLE_PRE_IMPACT, PROC_REF(catch_it_chucklenut)) + throw_callback = CALLBACK(src, PROC_REF(clear_hitby_signal), target) + RegisterSignal(target, COMSIG_MOVABLE_PRE_IMPACT, PROC_REF(catch_it_chucklenut)) - if(!movable_target.safe_throw_at(destination, source.cast_range, 2, callback = throw_callback, gentle = please_be_gentle)) - UnregisterSignal(movable_target, COMSIG_MOVABLE_PRE_IMPACT) + if(!target.safe_throw_at(destination, source.cast_range, 2, callback = throw_callback, gentle = please_be_gentle)) + UnregisterSignal(target, COMSIG_MOVABLE_PRE_IMPACT) else playsound(src, 'sound/items/weapons/batonextend.ogg', 50, TRUE) /obj/item/fishing_line/auto_reel/proc/catch_it_chucklenut(obj/item/source, atom/hit_atom, datum/thrownthing/throwingdatum) SIGNAL_HANDLER + var/mob/living/user = throwingdatum.initial_target.resolve() if(QDELETED(user) || hit_atom != user) return NONE From 4124f54a1518e5eaa8bb2269f0a5561bc1785474 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Tue, 21 Jan 2025 18:57:01 +0000 Subject: [PATCH 14/35] Automatic changelog for PR #89144 [ci skip] --- html/changelogs/AutoChangeLog-pr-89144.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89144.yml diff --git a/html/changelogs/AutoChangeLog-pr-89144.yml b/html/changelogs/AutoChangeLog-pr-89144.yml new file mode 100644 index 0000000000000..f0551ec98139a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89144.yml @@ -0,0 +1,4 @@ +author: "SyncIt21" +delete-after: True +changes: + - bugfix: "fishing rod auto reel won't rip of intercoms or other anchored/immovable objects" \ No newline at end of file From c3f3e9e9b9939b70b7236d517b4c5b153690abf9 Mon Sep 17 00:00:00 2001 From: Jacquerel Date: Tue, 21 Jan 2025 19:06:30 +0000 Subject: [PATCH 15/35] Fix flaky Ethereal test (#89123) --- code/datums/brain_damage/split_personality.dm | 9 +++++++-- .../surgery/organs/internal/heart/heart_ethereal.dm | 2 +- code/modules/unit_tests/ethereal_revival.dm | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/code/datums/brain_damage/split_personality.dm b/code/datums/brain_damage/split_personality.dm index cef20687a84d5..bed12417218d4 100644 --- a/code/datums/brain_damage/split_personality.dm +++ b/code/datums/brain_damage/split_personality.dm @@ -15,12 +15,17 @@ var/poll_role = "split personality" /datum/brain_trauma/severe/split_personality/on_gain() - var/mob/living/M = owner - if(M.stat == DEAD || !M.client) //No use assigning people to a corpse or braindead + var/mob/living/brain_owner = owner + if(brain_owner.stat == DEAD || !GET_CLIENT(brain_owner)) //No use assigning people to a corpse or braindead qdel(src) return ..() make_backseats() + +#ifdef UNIT_TESTS + return // There's no ghosts in the unit test +#endif + get_ghost() /datum/brain_trauma/severe/split_personality/proc/make_backseats() diff --git a/code/modules/surgery/organs/internal/heart/heart_ethereal.dm b/code/modules/surgery/organs/internal/heart/heart_ethereal.dm index 48f10a0613485..9d8ae8be5ee4f 100644 --- a/code/modules/surgery/organs/internal/heart/heart_ethereal.dm +++ b/code/modules/surgery/organs/internal/heart/heart_ethereal.dm @@ -228,13 +228,13 @@ playsound(get_turf(regenerating), 'sound/mobs/humanoids/ethereal/ethereal_revive.ogg', 100) to_chat(regenerating, span_notice("You burst out of the crystal with vigour... But at a cost.")) + regenerating.revive(HEAL_ALL & ~HEAL_REFRESH_ORGANS) if(prob(10)) //10% chance for a severe trauma regenerating.gain_trauma_type(BRAIN_TRAUMA_SEVERE, TRAUMA_RESILIENCE_ABSOLUTE) else regenerating.gain_trauma_type(BRAIN_TRAUMA_MILD, TRAUMA_RESILIENCE_ABSOLUTE) - regenerating.revive(HEAL_ALL & ~HEAL_REFRESH_ORGANS) // revive calls fully heal -> deletes the crystal. // this qdeleted check is just for sanity. if(!QDELETED(src)) diff --git a/code/modules/unit_tests/ethereal_revival.dm b/code/modules/unit_tests/ethereal_revival.dm index 1420f14d0b4fe..02b73281e85e3 100644 --- a/code/modules/unit_tests/ethereal_revival.dm +++ b/code/modules/unit_tests/ethereal_revival.dm @@ -5,6 +5,7 @@ var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human/consistent) var/obj/item/organ/heart/ethereal/respawn_heart = new() respawn_heart.Insert(victim, special = TRUE, movement_flags = DELETE_IF_REPLACED) // Pretend this guy is an ethereal + victim.mock_client = new() victim.death() TEST_ASSERT_NOTNULL(respawn_heart.crystalize_timer_id, "Ethereal heart didn't respond to host death.") From 8196190aa1b428184be3db117351be6ed440589b Mon Sep 17 00:00:00 2001 From: Penelope Haze Date: Tue, 21 Jan 2025 16:09:57 -0500 Subject: [PATCH 16/35] Removes a a at at be be of of and and have have (#89155) ## About The Pull Request I just had to one-up https://github.com/tgstation/tgstation/pull/89127. ## Why It's Good For The Game Removes a a at at be be of of and and have have ## Changelog N/A --- .../hud/rendering/plane_masters/plane_master_subtypes.dm | 2 +- code/datums/memory/general_memories.dm | 2 +- code/datums/ruins/icemoon.dm | 2 +- code/game/gamemodes/objective_items.dm | 2 +- code/game/machinery/computer/arcade/orion_event.dm | 2 +- code/game/objects/items.dm | 2 +- code/game/objects/items/chromosome.dm | 2 +- code/game/objects/items/robot/robot_upgrades.dm | 4 ++-- code/game/objects/items/stacks/tiles/tile_types.dm | 2 +- code/game/objects/structures/window.dm | 4 ++-- code/modules/admin/topic.dm | 2 +- code/modules/clothing/head/garlands.dm | 2 +- code/modules/clothing/neck/collar_bomb.dm | 2 +- code/modules/events/ion_storm.dm | 2 +- code/modules/library/skill_learning/job_skillchips/clown.dm | 2 +- code/modules/mapping/mapping_helpers.dm | 2 +- code/modules/mob/living/carbon/human/species_types/monkeys.dm | 2 +- code/modules/unit_tests/designs.dm | 2 +- 18 files changed, 20 insertions(+), 20 deletions(-) diff --git a/code/_onclick/hud/rendering/plane_masters/plane_master_subtypes.dm b/code/_onclick/hud/rendering/plane_masters/plane_master_subtypes.dm index 582253e0b926b..96a02afb5749b 100644 --- a/code/_onclick/hud/rendering/plane_masters/plane_master_subtypes.dm +++ b/code/_onclick/hud/rendering/plane_masters/plane_master_subtypes.dm @@ -380,7 +380,7 @@ /atom/movable/screen/plane_master/ghost name = "Ghost" - documentation = "Ghosts draw here, so they don't get mixed up in the visuals of the game world. Note, this is not not how we HIDE ghosts from people, that's done with invisible and see_invisible." + documentation = "Ghosts draw here, so they don't get mixed up in the visuals of the game world. Note, this is not how we HIDE ghosts from people, that's done with invisible and see_invisible." plane = GHOST_PLANE render_relay_planes = list(RENDER_PLANE_NON_GAME) diff --git a/code/datums/memory/general_memories.dm b/code/datums/memory/general_memories.dm index eca745d3283a6..8fa8420527d23 100644 --- a/code/datums/memory/general_memories.dm +++ b/code/datums/memory/general_memories.dm @@ -95,7 +95,7 @@ /datum/memory/high_five/get_starts() return list( - "[protagonist_name] and [deuteragonist_name] having a a legendary [high_five_type]", + "[protagonist_name] and [deuteragonist_name] having a legendary [high_five_type]", "[protagonist_name] giving [deuteragonist_name] a [high_five_type]", "[protagonist_name] and [deuteragonist_name] giving each other a [high_five_type]", ) diff --git a/code/datums/ruins/icemoon.dm b/code/datums/ruins/icemoon.dm index ef241d61127ba..6ab7539cecd9a 100644 --- a/code/datums/ruins/icemoon.dm +++ b/code/datums/ruins/icemoon.dm @@ -64,7 +64,7 @@ /datum/map_template/ruin/icemoon/Lodge name = "Ice-Ruin Hunters Lodge" id = "lodge" - description = "An old hunting hunting lodge. I wonder if anyone is still home?" + description = "An old hunting lodge. I wonder if anyone is still home?" suffix = "icemoon_surface_lodge.dmm" /datum/map_template/ruin/icemoon/frozen_phonebooth diff --git a/code/game/gamemodes/objective_items.dm b/code/game/gamemodes/objective_items.dm index eb74dc5df1e65..7f88dc68758ce 100644 --- a/code/game/gamemodes/objective_items.dm +++ b/code/game/gamemodes/objective_items.dm @@ -561,7 +561,7 @@ exists_on_map = TRUE difficulty = 4 steal_hint = "The station's data Blackbox, found solely within Telecommunications." - destruction_method = "Too strong to be be destroyed via normal means - needs to be dusted via the supermatter, or burnt in the chapel's crematorium." + destruction_method = "Too strong to be destroyed via normal means - needs to be dusted via the supermatter, or burnt in the chapel's crematorium." /obj/item/blackbox/add_stealing_item_objective() return add_item_to_steal(src, /obj/item/blackbox) diff --git a/code/game/machinery/computer/arcade/orion_event.dm b/code/game/machinery/computer/arcade/orion_event.dm index d39766200dc52..7c834800f1dd2 100644 --- a/code/game/machinery/computer/arcade/orion_event.dm +++ b/code/game/machinery/computer/arcade/orion_event.dm @@ -219,7 +219,7 @@ var/lostfuel = rand(4,7) var/deadname = game.remove_crewmember() game.fuel -= lostfuel - text = "[deadname] was lost deep in the wreckage, and your own vessel lost [lostfuel] Fuel maneuvering to the the abandoned ship." + text = "[deadname] was lost deep in the wreckage, and your own vessel lost [lostfuel] Fuel maneuvering to the abandoned ship." event_responses += BUTTON_WHERE_DID_YOU_GO if(36 to 65) var/oldfood = rand(5,11) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index b389438f0f9be..01bab10c962ed 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -1400,7 +1400,7 @@ return discover_after if(w_class > WEIGHT_CLASS_TINY) //small items like soap or toys that don't have mat datums - to_chat(victim, span_warning("[source_item? "Something strange was in the \the [source_item]..." : "I just bit something strange..."] ")) + to_chat(victim, span_warning("[source_item? "Something strange was in \the [source_item]..." : "I just bit something strange..."] ")) return discover_after // victim's chest (for cavity implanting the item) diff --git a/code/game/objects/items/chromosome.dm b/code/game/objects/items/chromosome.dm index dcfc7930ebfe2..43afbd43bd533 100644 --- a/code/game/objects/items/chromosome.dm +++ b/code/game/objects/items/chromosome.dm @@ -76,6 +76,6 @@ /obj/item/chromosome/energy name = "energetic chromosome" - desc = "A chromosome that reduces action based mutation cooldowns by by 50%." + desc = "A chromosome that reduces action based mutation cooldowns by 50%." icon_state = "energy" energy_coeff = 0.5 diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index bbebd91e7cb0c..f448ec0ed591e 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -688,7 +688,7 @@ /obj/item/borg/upgrade/transform name = "borg model picker (Standard)" - desc = "Allows you to to turn a cyborg into a standard cyborg." + desc = "Allows you to turn a cyborg into a standard cyborg." icon_state = "module_general" var/obj/item/robot_model/new_model = null @@ -699,7 +699,7 @@ /obj/item/borg/upgrade/transform/clown name = "borg model picker (Clown)" - desc = "Allows you to to turn a cyborg into a clown, honk." + desc = "Allows you to turn a cyborg into a clown, honk." icon_state = "module_honk" new_model = /obj/item/robot_model/clown diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm index 20ee0e69df6d7..f2c860d2d7644 100644 --- a/code/game/objects/items/stacks/tiles/tile_types.dm +++ b/code/game/objects/items/stacks/tiles/tile_types.dm @@ -1044,7 +1044,7 @@ /obj/item/stack/tile/tram/plate name = "linear induction tram tiles" - singular_name = "linear induction tram tile tile" + singular_name = "linear induction tram tile" desc = "A tile with an aluminium plate for tram propulsion." icon_state = "darkiron_plate" inhand_icon_state = "tile-neon" diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 9924713d93908..8c8a39aa59f26 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -860,7 +860,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/reinforced/tinted/frosted/spaw /obj/structure/window/reinforced/plasma/plastitanium name = "plastitanium window" - desc = "A durable looking window made of an alloy of of plasma and titanium." + desc = "A durable looking window made of an alloy of plasma and titanium." icon = 'icons/obj/smooth_structures/plastitanium_window.dmi' icon_state = "plastitanium_window-0" base_icon_state = "plastitanium_window" @@ -883,7 +883,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/reinforced/tinted/frosted/spaw /obj/structure/window/reinforced/plasma/plastitanium/indestructible name = "plastitanium window" - desc = "A durable looking window made of an alloy of of plasma and titanium." + desc = "A durable looking window made of an alloy of plasma and titanium." icon = 'icons/obj/smooth_structures/plastitanium_window.dmi' icon_state = "plastitanium_window-0" base_icon_state = "plastitanium_window" diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index e8d117fdc94ff..71374bf2464ff 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -497,7 +497,7 @@ var/new_value = input(usr, "Enter the forced threat level for dynamic mode.", "Forced threat level") as num if (new_value > 100) - return tgui_alert(usr, "The value must be be under 100.") + return tgui_alert(usr, "The value must be under 100.") GLOB.dynamic_forced_threat_level = new_value log_admin("[key_name(usr)] set 'forced_threat_level' to [GLOB.dynamic_forced_threat_level].") diff --git a/code/modules/clothing/head/garlands.dm b/code/modules/clothing/head/garlands.dm index 4de0604044e32..374bd2fdafd4b 100644 --- a/code/modules/clothing/head/garlands.dm +++ b/code/modules/clothing/head/garlands.dm @@ -47,7 +47,7 @@ /obj/item/clothing/head/costume/garland/lily name = "lily crown" - desc = "A leafy flower crown with a cluster of large white lilies at at the front." + desc = "A leafy flower crown with a cluster of large white lilies at the front." icon_state = "lily_crown" worn_icon_state = "lily_crown" diff --git a/code/modules/clothing/neck/collar_bomb.dm b/code/modules/clothing/neck/collar_bomb.dm index 7a5314f4c18c6..372c6ab7cc58a 100644 --- a/code/modules/clothing/neck/collar_bomb.dm +++ b/code/modules/clothing/neck/collar_bomb.dm @@ -109,7 +109,7 @@ return var/mob/living/carbon/human/brian = collar.loc if(brian.get_item_by_slot(ITEM_SLOT_NECK) == collar) - brian.investigate_log("has has their [collar] triggered by [user] via yellow button.", INVESTIGATE_DEATHS) + brian.investigate_log("has had their [collar] triggered by [user] via yellow button.", INVESTIGATE_DEATHS) /obj/item/collar_bomb_button/Destroy() diff --git a/code/modules/events/ion_storm.dm b/code/modules/events/ion_storm.dm index 9c9d81d01d73f..1141b94e82286 100644 --- a/code/modules/events/ion_storm.dm +++ b/code/modules/events/ion_storm.dm @@ -459,7 +459,7 @@ if(6) //X is a job message = "YOU MUST HARM [ioncrew1] AND NOT ALLOW [ioncrew1], THROUGH INACTION, TO ESCAPE HARM" if(7) //X is two jobs - message = "YOU MUST HARM [ioncrew1] AND [ioncrew2] AND AND NOT ALLOW EITHER, THROUGH INACTION, TO ESCAPE HARM" + message = "YOU MUST HARM [ioncrew1] AND [ioncrew2] AND NOT ALLOW EITHER, THROUGH INACTION, TO ESCAPE HARM" if(2) //Protect switch(rand(1,7)) //What is X? diff --git a/code/modules/library/skill_learning/job_skillchips/clown.dm b/code/modules/library/skill_learning/job_skillchips/clown.dm index 3cd88ff70963d..f8836b41dcad3 100644 --- a/code/modules/library/skill_learning/job_skillchips/clown.dm +++ b/code/modules/library/skill_learning/job_skillchips/clown.dm @@ -3,7 +3,7 @@ desc = "This biochip contain several terabytes of uncannily religious, Honkmother praising guides on how to reshape balloons into silly animals." auto_traits = list(TRAIT_BALLOON_SUTRA) skill_name = "Balloon Sutra" - skill_description = "Learn the the ancient Honkmotherian arts of balloon-sutra." + skill_description = "Learn the ancient Honkmotherian arts of balloon-sutra." skill_icon = "face-grin-tears" activate_message = span_notice("Blessed wisdom of Honkmother enwraps you, and with it, governship upon form of balloonkind.") deactivate_message = span_notice("'Remember, then, that true clownery requires freedom and willingness to bend, like ones of a floating balloon.'... Whatever that meant?") diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers.dm index c122b8abc1cd7..d04e6e0afd15b 100644 --- a/code/modules/mapping/mapping_helpers.dm +++ b/code/modules/mapping/mapping_helpers.dm @@ -102,7 +102,7 @@ /obj/effect/baseturf_helper/reinforced_plating/ceiling/replace_baseturf(turf/thing) var/turf/ceiling = get_step_multiz(thing, UP) if(isnull(ceiling)) - CRASH("baseturf helper is attempting to modify the Z level above but there is no Z level above above it.") + CRASH("baseturf helper is attempting to modify the Z level above but there is no Z level above it.") if(isspaceturf(ceiling) || istype(ceiling, /turf/open/openspace)) return return ..(ceiling) diff --git a/code/modules/mob/living/carbon/human/species_types/monkeys.dm b/code/modules/mob/living/carbon/human/species_types/monkeys.dm index c953274646245..aa58299115821 100644 --- a/code/modules/mob/living/carbon/human/species_types/monkeys.dm +++ b/code/modules/mob/living/carbon/human/species_types/monkeys.dm @@ -166,7 +166,7 @@ else monkey_brain.tripping = TRUE background_icon_state = "bg_default_on" - to_chat(monkey_brain.owner, span_notice("You will now stumble while while colliding with people who are in combat mode.")) + to_chat(monkey_brain.owner, span_notice("You will now stumble while colliding with people who are in combat mode.")) build_all_button_icons() /obj/item/organ/brain/primate/on_mob_insert(mob/living/carbon/primate) diff --git a/code/modules/unit_tests/designs.dm b/code/modules/unit_tests/designs.dm index 0495ebdc7d9ae..729f2facf81d0 100644 --- a/code/modules/unit_tests/designs.dm +++ b/code/modules/unit_tests/designs.dm @@ -15,7 +15,7 @@ TEST_FAIL("Design [current_design.type] has default or null name var but has an ID") if ((!isnull(current_design.materials) && LAZYLEN(current_design.materials)) || (!isnull(current_design.reagents_list) && LAZYLEN(current_design.reagents_list))) //Design requires materials if ((isnull(current_design.build_path) || current_design.build_path == default_design.build_path) && (isnull(current_design.make_reagent) || current_design.make_reagent == default_design.make_reagent)) //Check if design gives any output - TEST_FAIL("Design [current_design.type] requires materials but does not have have any build_path or make_reagent set") + TEST_FAIL("Design [current_design.type] requires materials but does not have either build_path or make_reagent set") else if (!isnull(current_design.build_path) || !isnull(current_design.build_path)) // //Design requires no materials but creates stuff TEST_FAIL("Design [current_design.type] requires NO materials but has build_path or make_reagent set") if (length(current_design.reagents_list) && !(current_design.build_type & LIMBGROWER)) From b72368fd03e6dc58a49dd8f70f2700e393a8de8f Mon Sep 17 00:00:00 2001 From: necromanceranne <40847847+necromanceranne@users.noreply.github.com> Date: Wed, 22 Jan 2025 10:17:23 +1100 Subject: [PATCH 17/35] #87754: Batons have their stamina damage reduced by armor, get stun armor penetration, but not a test and actually intended to be merged (#88830) ## About The Pull Request This PR is literally just https://github.com/tgstation/tgstation/pull/87754 so you should probably go read the contents of that PR to learn more. ### Sorry, No Stunsword in this PR. Stunbaton inhand tips change color as the cell it has inside increases in capacity. They also have different animations based on the cell, to make it clearer which one you are looking at. ![image](https://github.com/user-attachments/assets/95be1499-47b7-4991-a3c1-03833f329d7f) ## Why It's Good For The Game So, two things; A) The test showed that there is more work to be done, but that this was actually improving survivability to some degree against batons when properly geared, while not necessarily impacting the average tider arrest attempts. It didn't solve the issue of alleviating the need for anti-baton knockdown tools, but it did help a bit. Enough that I think this could be worked on further as a foundation for solving that problem. B) People have been asking me to, or have made it obvious that they would like to see this actually merged into the game. So uh...here is that PR if any maints care for it. I think there is still more to do for testing and possible changes to address the issues I was trying to investigate in the test. However, I actually think this change could be an important step towards accomplishing some of those changes. It isn't quite enough to start pulling out baton resistance from various sources just yet, but it is a start. ## Changelog :cl: balance: Batons now respect the armor worn by targets. Analog batons respect MELEE armor. Cell-type batons respect ENERGY armor. balance: Various batons have differing amounts of armour penetration based on what type of baton it is. balance: Heads of staff have color graded batons to denote penetration power. Bronze (Quartermaster), Silver (Chief Engineer, Chief Medical Officer, Head of Personnel, Research Director), Gold (Captain). Contractor batons are equivalent to Gold. balance: Cell-type batons gain armor penetration based on their cell's quality. The better it is, the more it penetrates. /:cl: --------- Co-authored-by: SmArtKar <44720187+SmArtKar@users.noreply.github.com> --- code/game/objects/items.dm | 2 + code/game/objects/items/melee/baton.dm | 129 ++++++++++++++++-- code/game/objects/items_reskin.dm | 7 + .../modules/hallucination/nearby_fake_item.dm | 2 +- code/modules/jobs/job_types/captain.dm | 2 +- code/modules/jobs/job_types/chief_engineer.dm | 2 +- .../jobs/job_types/chief_medical_officer.dm | 2 +- .../jobs/job_types/head_of_personnel.dm | 2 +- .../jobs/job_types/head_of_security.dm | 1 + code/modules/jobs/job_types/quartermaster.dm | 2 +- .../jobs/job_types/research_director.dm | 2 +- .../inhands/equipment/security_lefthand.dmi | Bin 2791 -> 9169 bytes .../inhands/equipment/security_righthand.dmi | Bin 3400 -> 10396 bytes icons/obj/weapons/baton.dmi | Bin 3005 -> 3836 bytes 14 files changed, 138 insertions(+), 15 deletions(-) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 01bab10c962ed..b70d105953e95 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -239,6 +239,8 @@ var/current_skin /// List of options to reskin. var/list/unique_reskin + /// If reskins change base icon state as well + var/unique_reskin_changes_base_icon_state = FALSE /// If reskins change inhands as well var/unique_reskin_changes_inhand = FALSE /// Do we apply a click cooldown when resisting this object if it is restraining them? diff --git a/code/game/objects/items/melee/baton.dm b/code/game/objects/items/melee/baton.dm index 03df05140388a..1b5f9a9fd901f 100644 --- a/code/game/objects/items/melee/baton.dm +++ b/code/game/objects/items/melee/baton.dm @@ -29,6 +29,10 @@ var/clumsy_knockdown_time = 18 SECONDS /// How much stamina damage we deal on a successful hit against a living, non-cyborg mob. var/stamina_damage = 55 + /// How much armor does our baton ignore? This operates as armour penetration, but only applies to the stun attack. + var/stun_armour_penetration = 15 + /// What armor does our stun attack check before delivering the attack? + var/armour_type_against_stun = MELEE /// Chance of causing force_say() when stunning a human mob var/force_say_chance = 33 /// Can we stun cyborgs? @@ -44,6 +48,9 @@ /// Boolean on whether people with chunky fingers can use this baton. var/chunky_finger_usable = FALSE + /// What term do we use to describe our baton being 'ready', or the phrase to use when var/active is TRUE. + var/activated_word = "ready" + /// The context to show when the baton is active and targeting a living thing var/context_living_target_active = "Stun" @@ -64,12 +71,31 @@ /obj/item/melee/baton/Initialize(mapload) . = ..() - // Adding an extra break for the sake of presentation - if(stamina_damage != 0) - offensive_notes = "It takes [span_warning("[CEILING(100 / stamina_damage, 1)] stunning hit\s")] to stun an enemy." register_item_context() +/obj/item/melee/baton/add_weapon_description() + AddElement(/datum/element/weapon_description, attached_proc = PROC_REF(add_baton_notes)) + +/obj/item/melee/baton/proc/add_baton_notes() + var/list/readout = list() + + if(affect_cyborg) + readout += "It can stun cyborgs for [round((stun_time_cyborg/10), 1)] seconds." + + readout += "\n[active ? "It is currently [span_warning("[activated_word]")], and capable of stunning." : "It is [span_warning("not [activated_word]")], and not capable of stunning."]" + + if(stamina_damage <= 0) // The advanced baton actually does have 0 stamina damage so...yeah. + readout += "Either is is [span_warning("completely unable to perform a stunning strike")], or it [span_warning("attacks via some unusual method")]." + return readout.Join("\n") + + readout += "It takes [span_warning("[HITS_TO_CRIT(stamina_damage)] strike\s")] to stun an enemy." + + readout += "\nThe effects of each strike can be mitigated by utilizing [span_warning("[armour_type_against_stun]")] armor." + + readout += "\nIt has a stun armor-piercing capability of [span_warning("[get_stun_penetration_value()]%")]." + return readout.Join("\n") + /** * Ok, think of baton attacks like a melee attack chain: * @@ -210,7 +236,9 @@ var/mob/living/carbon/human/human_target = target if(prob(force_say_chance)) human_target.force_say() - target.apply_damage(stamina_damage, STAMINA) + var/effective_armour_penetration = get_stun_penetration_value() + var/armour_block = target.run_armor_check(null, armour_type_against_stun, null, null, effective_armour_penetration) + target.apply_damage(stamina_damage, STAMINA, blocked = armour_block) if(!trait_check) target.Knockdown((isnull(stun_override) ? knockdown_time : stun_override)) additional_effects_non_cyborg(target, user) @@ -295,6 +323,10 @@ user.do_attack_animation(user) return +/// Handles the penetration value of our baton, called during baton_effect() +/obj/item/melee/baton/proc/get_stun_penetration_value() + return stun_armour_penetration + /obj/item/conversion_kit name = "conversion kit" desc = "A strange box containing wood working tools and an instruction paper to turn stun batons into something else." @@ -321,6 +353,7 @@ bare_wound_bonus = 5 clumsy_knockdown_time = 15 SECONDS active = FALSE + activated_word = "extended" var/folded_drop_sound = 'sound/items/baton/telescopic_baton_folded_drop.ogg' var/folded_pickup_sound = 'sound/items/baton/telescopic_baton_folded_pickup.ogg' var/unfolded_drop_sound = 'sound/items/baton/telescopic_baton_unfolded_drop.ogg' @@ -392,6 +425,24 @@ playsound(src, on_sound, 50, TRUE) return COMPONENT_NO_DEFAULT_MESSAGE +/obj/item/melee/baton/telescopic/bronze + name = "bronze-capped telescopic baton" + desc = "A compact yet robust personal defense weapon. Can be concealed when folded. This one is ranked BRONZE, and thus has mediocre penetrative power." + icon_state = "telebaton_bronze" + stun_armour_penetration = 20 + +/obj/item/melee/baton/telescopic/silver + name = "silver-capped telescopic baton" + desc = "A compact yet robust personal defense weapon. Can be concealed when folded. This one is ranked SILVER, and thus has decent penetrative power." + icon_state = "telebaton_silver" + stun_armour_penetration = 40 + +/obj/item/melee/baton/telescopic/gold + name = "gold-capped telescopic baton" + desc = "A compact yet robust personal defense weapon. Can be concealed when folded. This one is ranked GOLD, and thus has exceptional penetrative power." + icon_state = "telebaton_gold" + stun_armour_penetration = 60 + /obj/item/melee/baton/telescopic/contractor_baton name = "contractor baton" desc = "A compact, specialised baton assigned to Syndicate contractors. Applies light electrical shocks to targets." @@ -408,6 +459,7 @@ cooldown = 2.5 SECONDS force_say_chance = 80 //very high force say chance because it's funny stamina_damage = 85 + stun_armour_penetration = 40 clumsy_knockdown_time = 24 SECONDS affect_cyborg = TRUE on_stun_sound = 'sound/items/weapons/contractor_baton/contractorbatonhit.ogg' @@ -432,7 +484,8 @@ desc_controls = "Left click to stun, right click to harm." icon = 'icons/obj/weapons/baton.dmi' icon_state = "stunbaton" - inhand_icon_state = "baton" + base_icon_state = "stunbaton" + inhand_icon_state = "stunbaton" worn_icon_state = "baton" icon_angle = -45 force = 10 @@ -443,12 +496,16 @@ throwforce = 7 force_say_chance = 50 stamina_damage = 60 + armour_type_against_stun = ENERGY + // This value is added to our stun armour penetration when called by get_stun_penetration_value(). For giving some batons extra OOMPH. + var/additional_stun_armour_penetration = 0 knockdown_time = 5 SECONDS clumsy_knockdown_time = 15 SECONDS cooldown = 2.5 SECONDS on_stun_sound = 'sound/items/weapons/egloves.ogg' on_stun_volume = 50 active = FALSE + activated_word = "activated" context_living_rmb_active = "Harmful Stun" light_range = 1.5 light_system = OVERLAY_LIGHT @@ -469,6 +526,10 @@ var/cell_hit_cost = STANDARD_CELL_CHARGE var/can_remove_cell = TRUE var/convertible = TRUE //if it can be converted with a conversion kit + ///Whether or not our inhand changes when active. + var/active_changes_inhand = TRUE + ///Whether or not our baton visibly changes the inhand sprite based on inserted cell + var/tip_changes_color = TRUE /datum/armor/baton_security bomb = 50 @@ -534,12 +595,19 @@ /obj/item/melee/baton/security/update_icon_state() if(active) - icon_state = "[initial(icon_state)]_active" + icon_state = "[base_icon_state]_active" + if(active_changes_inhand) + if(tip_changes_color) + inhand_icon_state = "[base_icon_state]_active_[get_baton_tip_color()]" + else + inhand_icon_state = "[base_icon_state]_active" return ..() if(!cell) - icon_state = "[initial(icon_state)]_nocell" + icon_state = "[base_icon_state]_nocell" + inhand_icon_state = "[base_icon_state]" return ..() - icon_state = "[initial(icon_state)]" + icon_state = "[base_icon_state]" + inhand_icon_state = "[base_icon_state]" return ..() /obj/item/melee/baton/security/examine(mob/user) @@ -594,9 +662,36 @@ /// Toggles the stun baton's light /obj/item/melee/baton/security/proc/toggle_light() + set_light_color(get_baton_tip_color(TRUE)) set_light_on(!light_on) return +/// Change our baton's top color based on the contained cell. +/obj/item/melee/baton/security/proc/get_baton_tip_color(set_light = FALSE) + var/tip_type_to_set + var/tip_light_to_set + + if(cell) + var/chargepower = cell.maxcharge + var/zap_value = clamp(chargepower/STANDARD_CELL_CHARGE, 0, 100) + switch(zap_value) + if(-INFINITY to 10) + tip_type_to_set = "orange" + tip_light_to_set = LIGHT_COLOR_ORANGE + if(11 to 20) + tip_type_to_set = "red" + tip_light_to_set = LIGHT_COLOR_INTENSE_RED + if(21 to 30) + tip_type_to_set = "green" + tip_light_to_set = LIGHT_COLOR_GREEN + if(31 to INFINITY) + tip_type_to_set = "blue" + tip_light_to_set = LIGHT_COLOR_BLUE + else + tip_type_to_set = "orange" + + return set_light ? tip_light_to_set : tip_type_to_set + /obj/item/melee/baton/security/proc/turn_on(mob/user) active = TRUE playsound(src, SFX_SPARKS, 75, TRUE, -1) @@ -653,6 +748,13 @@ stun_override = 0 //Avoids knocking people down prematurely. return ..() +/obj/item/melee/baton/security/get_stun_penetration_value() + if(cell) + var/chargepower = cell.maxcharge + var/zap_pen = clamp(chargepower/STANDARD_CELL_CHARGE, 0, 100) + return zap_pen + additional_stun_armour_penetration + return stun_armour_penetration + additional_stun_armour_penetration + /* * After a target is hit, we apply some status effects. * After a period of time, we then check to see what stun duration we give. @@ -719,6 +821,9 @@ /obj/item/melee/baton/security/loaded //this one starts with a cell pre-installed. preload_cell_type = /obj/item/stock_parts/power_store/cell/high +/obj/item/melee/baton/security/loaded/hos + preload_cell_type = /obj/item/stock_parts/power_store/cell/super + //Makeshift stun baton. Replacement for stun gloves. /obj/item/melee/baton/security/cattleprod name = "stunprod" @@ -726,6 +831,7 @@ desc_controls = "Left click to stun, right click to harm." icon = 'icons/obj/weapons/spear.dmi' icon_state = "stunprod" + base_icon_state = "stunprod" inhand_icon_state = "prod" worn_icon_state = null icon_angle = -45 @@ -738,6 +844,8 @@ throw_stun_chance = 10 slot_flags = ITEM_SLOT_BACK convertible = FALSE + active_changes_inhand = FALSE + tip_changes_color = FALSE var/obj/item/assembly/igniter/sparkler ///Determines whether or not we can improve the cattleprod into a new type. Prevents turning the cattleprod subtypes into different subtypes, or wasting materials on making it....another version of itself. var/can_upgrade = TRUE @@ -794,6 +902,7 @@ throw_speed = 1 icon = 'icons/obj/weapons/thrown.dmi' icon_state = "boomerang" + base_icon_state = "boomerang" inhand_icon_state = "boomerang" force = 5 throwforce = 5 @@ -801,6 +910,8 @@ cell_hit_cost = STANDARD_CELL_CHARGE * 2 throw_stun_chance = 99 //Have you prayed today? convertible = FALSE + active_changes_inhand = FALSE + tip_changes_color = FALSE custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 5, /datum/material/glass = SHEET_MATERIAL_AMOUNT*2, /datum/material/silver = SHEET_MATERIAL_AMOUNT*5, /datum/material/gold = SHEET_MATERIAL_AMOUNT) /obj/item/melee/baton/security/boomerang/Initialize(mapload) @@ -823,6 +934,7 @@ desc = "A prod with a bluespace crystal on the end. The crystal doesn't look too fun to touch." w_class = WEIGHT_CLASS_NORMAL icon_state = "teleprod" + base_icon_state = "teleprod" inhand_icon_state = "teleprod" slot_flags = null can_upgrade = FALSE @@ -844,6 +956,7 @@ desc = "A prod with a telecrystal on the end. It sparks with a desire for theft and subversion." w_class = WEIGHT_CLASS_NORMAL icon_state = "telecrystalprod" + base_icon_state = "telecrystalprod" inhand_icon_state = "telecrystalprod" slot_flags = null throw_stun_chance = 50 //I think it'd be funny diff --git a/code/game/objects/items_reskin.dm b/code/game/objects/items_reskin.dm index b73df0a487b72..98a3165b5e2ab 100644 --- a/code/game/objects/items_reskin.dm +++ b/code/game/objects/items_reskin.dm @@ -64,8 +64,15 @@ return current_skin = pick icon_state = unique_reskin[pick] + + if (unique_reskin_changes_base_icon_state) + base_icon_state = icon_state + if (unique_reskin_changes_inhand) inhand_icon_state = icon_state + + update_appearance() + to_chat(user, "[src] is now skinned as '[pick].'") SEND_SIGNAL(src, COMSIG_OBJ_RESKIN, user, pick) diff --git a/code/modules/hallucination/nearby_fake_item.dm b/code/modules/hallucination/nearby_fake_item.dm index 10d08ee47c96f..1896d28d34042 100644 --- a/code/modules/hallucination/nearby_fake_item.dm +++ b/code/modules/hallucination/nearby_fake_item.dm @@ -89,7 +89,7 @@ /datum/hallucination/nearby_fake_item/baton left_hand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi' right_hand_file = 'icons/mob/inhands/equipment/security_righthand.dmi' - image_icon_state = "baton" + image_icon_state = "stunbaton" /datum/hallucination/nearby_fake_item/baton/generate_fake_image(mob/living/carbon/human/holder, file) hallucinator.playsound_local(get_turf(holder), SFX_SPARKS, 75, TRUE, -1) diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm index 35155a7c7b70d..fff1c5ed170b4 100644 --- a/code/modules/jobs/job_types/captain.dm +++ b/code/modules/jobs/job_types/captain.dm @@ -67,7 +67,7 @@ uniform = /obj/item/clothing/under/rank/captain suit = /obj/item/clothing/suit/armor/vest/capcarapace backpack_contents = list( - /obj/item/melee/baton/telescopic = 1, + /obj/item/melee/baton/telescopic/gold = 1, /obj/item/station_charter = 1, ) belt = /obj/item/modular_computer/pda/heads/captain diff --git a/code/modules/jobs/job_types/chief_engineer.dm b/code/modules/jobs/job_types/chief_engineer.dm index f85c2c54973b9..3a9a9fbc397b6 100644 --- a/code/modules/jobs/job_types/chief_engineer.dm +++ b/code/modules/jobs/job_types/chief_engineer.dm @@ -67,7 +67,7 @@ id_trim = /datum/id_trim/job/chief_engineer uniform = /obj/item/clothing/under/rank/engineering/chief_engineer backpack_contents = list( - /obj/item/melee/baton/telescopic = 1, + /obj/item/melee/baton/telescopic/silver = 1, /obj/item/construction/rcd/ce = 1, ) belt = /obj/item/storage/belt/utility/chief/full diff --git a/code/modules/jobs/job_types/chief_medical_officer.dm b/code/modules/jobs/job_types/chief_medical_officer.dm index c9f126bb750bc..13a9eb97515f1 100644 --- a/code/modules/jobs/job_types/chief_medical_officer.dm +++ b/code/modules/jobs/job_types/chief_medical_officer.dm @@ -62,7 +62,7 @@ suit = /obj/item/clothing/suit/toggle/labcoat/cmo suit_store = /obj/item/flashlight/pen/paramedic backpack_contents = list( - /obj/item/melee/baton/telescopic = 1, + /obj/item/melee/baton/telescopic/silver = 1, ) belt = /obj/item/modular_computer/pda/heads/cmo ears = /obj/item/radio/headset/heads/cmo diff --git a/code/modules/jobs/job_types/head_of_personnel.dm b/code/modules/jobs/job_types/head_of_personnel.dm index 1b8480f0d0b57..ed35cbf365f56 100644 --- a/code/modules/jobs/job_types/head_of_personnel.dm +++ b/code/modules/jobs/job_types/head_of_personnel.dm @@ -59,7 +59,7 @@ id_trim = /datum/id_trim/job/head_of_personnel uniform = /obj/item/clothing/under/rank/civilian/head_of_personnel backpack_contents = list( - /obj/item/melee/baton/telescopic = 1, + /obj/item/melee/baton/telescopic/silver = 1, ) belt = /obj/item/modular_computer/pda/heads/hop ears = /obj/item/radio/headset/heads/hop diff --git a/code/modules/jobs/job_types/head_of_security.dm b/code/modules/jobs/job_types/head_of_security.dm index b9560708114be..431e0aaaf6b44 100644 --- a/code/modules/jobs/job_types/head_of_security.dm +++ b/code/modules/jobs/job_types/head_of_security.dm @@ -57,6 +57,7 @@ suit_store = /obj/item/gun/energy/e_gun backpack_contents = list( /obj/item/evidencebag = 1, + /obj/item/melee/baton/security/loaded/hos = 1, ) belt = /obj/item/modular_computer/pda/heads/hos ears = /obj/item/radio/headset/heads/hos/alt diff --git a/code/modules/jobs/job_types/quartermaster.dm b/code/modules/jobs/job_types/quartermaster.dm index 32053daa5d8c8..251032662bf53 100644 --- a/code/modules/jobs/job_types/quartermaster.dm +++ b/code/modules/jobs/job_types/quartermaster.dm @@ -42,7 +42,7 @@ name = "Quartermaster" jobtype = /datum/job/quartermaster backpack_contents = list( - /obj/item/melee/baton/telescopic = 1, + /obj/item/melee/baton/telescopic/bronze = 1, ) id_trim = /datum/id_trim/job/quartermaster id = /obj/item/card/id/advanced/silver diff --git a/code/modules/jobs/job_types/research_director.dm b/code/modules/jobs/job_types/research_director.dm index 420138a6b9fba..cfd5044c267b0 100644 --- a/code/modules/jobs/job_types/research_director.dm +++ b/code/modules/jobs/job_types/research_director.dm @@ -62,7 +62,7 @@ uniform = /obj/item/clothing/under/rank/rnd/research_director/turtleneck suit = /obj/item/clothing/suit/toggle/labcoat/research_director backpack_contents = list( - /obj/item/melee/baton/telescopic = 1, + /obj/item/melee/baton/telescopic/silver = 1, ) belt = /obj/item/modular_computer/pda/heads/rd head = /obj/item/clothing/head/beret/science/rd diff --git a/icons/mob/inhands/equipment/security_lefthand.dmi b/icons/mob/inhands/equipment/security_lefthand.dmi index 993834e0d60847e855e3b2e76ac05a3b43703d6f..91306c0a093c1602b8ad0e17f4622bc6fb37e397 100644 GIT binary patch literal 9169 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 diff --git a/icons/mob/inhands/equipment/security_righthand.dmi b/icons/mob/inhands/equipment/security_righthand.dmi index 7d8787e3fe68e642d6bb1374d5562b8ca100671f..c6d26854eb6dacddbe6f0e33ba59dd6674c52a79 100644 GIT binary patch literal 10396 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 literal 3400 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 PYXn$X*g`R9-5>o6fa6I` diff --git a/icons/obj/weapons/baton.dmi b/icons/obj/weapons/baton.dmi index 2d5100ec4d414e571ef40938d318d3a3e5fb90b3..6b7cbd8544ac36c737b2b43be79a94bbe4909918 100644 GIT binary patch literal 3836 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 Q{hb9&jm!-z3~q(~2S5p`q5uE@ literal 3005 zcmV;u3qtgXP)004jp1^@s6jALRO0002IdQ@0+L}hbh za%pgMX>V=-0C=30jX?^7Fc3x8$teciN~u=pDx0Dd7kULrWY5=dv}aHS{jZO000WSNklZEO_R6^7r1 z1evOcVjQnY3o2@48R5Ee)fQAmT|+C?s)U*q*j}&{c~K)`tf-BZl2sz=xCrE;NTmgT zsZ#7eA&Wx`6;kB(2l7Hy1vRP(qK&mpvS2_9#4%Qd)i~%E&h*DKm zg;*>`eJIiuYT8NqLzj*32?J`)H!v{Zqdp#)3N`IiDl02(%Xhs2*?g6Vof}ya2n3{` z`vU(@6}?7$R~wMcH(z}9Yropxp~xD?TJxhU+J+02-Fp0|WE>2I*nFwt1HgsK?!Ygf zZH>p{h@N;)__fI312E#dvIDaD%oSf6{|9wXjQFlIAe+y8@rCg(|gO9?^pLYk;n$Pd|BbiJ}Hy<$HdB?`aq?_+Ruu*xw<}uoKFIy-C75~-J(kFo2 zHJ>iOh|Zgr0n^QQ@!~}c4-ZQ?C23?)zxl$f5((68-puApU3}(S zD_sND*VikdPzXpQFbH_wd`64xcs$PhB4s#&W3drU!s{_GC1%T8AznA&8 zG9b%)a>WNyS-M=ri= zUdzm-z{cJllttT61_Ult_QW3iVXsX7@V;FN0Ms8oF75V8s_1nM?f$pctXqfhF37&M zbGx>@^F%|tztM;nqCeW@wv~Pf%;k z_m?gI0RSB8>XY{AZ4JM1=#^WBeBlOM$cHP7wo!~g-F&)D@itk&R)JI1DRpI zmd}2O-~IF-0Dy+=&5G!8oX-FGpTBF!7iz$a_g2fIZTQBwMIy8FRZWJvWsKl-^IgCH z2nVBQWQ@TK^EDpzL+ykjm0I`hHOm)fK%|d>}HD7IcXTYfV z<%e(L)AN;YjZSoke3ARMI(D`Ep;vC{@`Y?d-0;SJF(T}I3oA{2smb|Gk1X?L;ST}m(c@b-f}NhyRIKb~zW)9$pSs(WVZ3a70M8g5 zgC!l1y7-I6e(HXo*UcxBT@1hI4rr@2A5hfTSD#h@=AT%w`HJHgWk6f5`3mIs?hYzj ztJeYm5;rGJ{Tnu4@%(~!!ERjhsm4o8&MxYPdSdfg!!O8yr-MNyH1~jP&9}g}aO_{d z{|M*DXK?oNHEgY3i}e*{h9+e5S;x=YfL79c=FYs~|E>pRQQ{mvYs%Sxn1go)_urLnJ`sFVBUsG}Q6n4FXs+H%B~~1RE%|!m7@##@>FNqh|946jRti6-0o|TY zmrdy=q&DAY@qc6H?j5P!Pc%QP0lkn_}ZeU|K4f*j5XkVKHOb|<{lLK zJ&O`GAD}fK0IXOFQ^g17JCL>`IgOt&g1wecmoD|aT`KdbQj4k8+!;0xV^WaiWTMCz>#3Vv;Q=Z?{dj+0dUv}3V7Ut|ZgOFo@c zzMlDH@wJ`TDc9dp1FEBsBA+gOsMx_vC=Z#J$% z#Px7$T!$qiI2WAKd?^X(cxL$`mmFsJqE!sPXahRoX5513Km6GvD6)f<~}gPM-Pn{Jd_%X!GH&CTR2NnC}k0X#;BW;b!jM zAvt;GyN_>b1iLw(j`_6woCfq#P!99u^RpVz?I+KCdcL6ny>Rl(r|0V$&?_g;e0qMy zF4$}Nbj+va>pltbQa&B?Y5BS%*h~3z%%|n+8gL-`u5ZQC#jUnsdnP;_YF4a1dFFeI zpYy{AZqKJKtbSxIBEPW}-iK?rsqdo*ri#s5TRBS*NsiYY2P*maO>He3m&0&j*xUd}=-` zKMBnTwDNm9fzQfcmUTet;#2ckg-J?2plDI^S%u5C`G97hTCn+?t)dJlviMgMS8|$= z&F6d-Y(UY)@9*#Oy%BlYXJkS)pF3pxe84v%FZ=fFi7YZ9o6kLRL_T1Df0u91o`^E{ zcm@=FmN=R2fa)9bt5%mnSpw Date: Tue, 21 Jan 2025 23:26:21 +0000 Subject: [PATCH 18/35] Automatic changelog for PR #88830 [ci skip] --- html/changelogs/AutoChangeLog-pr-88830.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-88830.yml diff --git a/html/changelogs/AutoChangeLog-pr-88830.yml b/html/changelogs/AutoChangeLog-pr-88830.yml new file mode 100644 index 0000000000000..a55f9e30c3bd1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88830.yml @@ -0,0 +1,7 @@ +author: "necromanceranne" +delete-after: True +changes: + - balance: "Batons now respect the armor worn by targets. Analog batons respect MELEE armor. Cell-type batons respect ENERGY armor." + - balance: "Various batons have differing amounts of armour penetration based on what type of baton it is." + - balance: "Heads of staff have color graded batons to denote penetration power. Bronze (Quartermaster), Silver (Chief Engineer, Chief Medical Officer, Head of Personnel, Research Director), Gold (Captain). Contractor batons are equivalent to Gold." + - balance: "Cell-type batons gain armor penetration based on their cell's quality. The better it is, the more it penetrates." \ No newline at end of file From cb2bbbeb2cc8460ac96ed58b60c14179f1119f3e Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 00:27:44 +0000 Subject: [PATCH 19/35] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-88830.yml | 7 ------- html/changelogs/AutoChangeLog-pr-89113.yml | 4 ---- html/changelogs/AutoChangeLog-pr-89141.yml | 4 ---- html/changelogs/AutoChangeLog-pr-89143.yml | 4 ---- html/changelogs/AutoChangeLog-pr-89144.yml | 4 ---- html/changelogs/AutoChangeLog-pr-89148.yml | 4 ---- html/changelogs/archive/2025-01.yml | 24 ++++++++++++++++++++++ 7 files changed, 24 insertions(+), 27 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-88830.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89113.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89141.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89143.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89144.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89148.yml diff --git a/html/changelogs/AutoChangeLog-pr-88830.yml b/html/changelogs/AutoChangeLog-pr-88830.yml deleted file mode 100644 index a55f9e30c3bd1..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88830.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: "necromanceranne" -delete-after: True -changes: - - balance: "Batons now respect the armor worn by targets. Analog batons respect MELEE armor. Cell-type batons respect ENERGY armor." - - balance: "Various batons have differing amounts of armour penetration based on what type of baton it is." - - balance: "Heads of staff have color graded batons to denote penetration power. Bronze (Quartermaster), Silver (Chief Engineer, Chief Medical Officer, Head of Personnel, Research Director), Gold (Captain). Contractor batons are equivalent to Gold." - - balance: "Cell-type batons gain armor penetration based on their cell's quality. The better it is, the more it penetrates." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89113.yml b/html/changelogs/AutoChangeLog-pr-89113.yml deleted file mode 100644 index a11767ec7085f..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89113.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "kuricityy" -delete-after: True -changes: - - bugfix: "Blob's can no longer place their core in ruins on Icebox." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89141.yml b/html/changelogs/AutoChangeLog-pr-89141.yml deleted file mode 100644 index a7315cab3523a..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89141.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SyncIt21" -delete-after: True -changes: - - bugfix: "pockets update their icons correctly when removing items that have storage (e.g. box of bandages) from them" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89143.yml b/html/changelogs/AutoChangeLog-pr-89143.yml deleted file mode 100644 index 9edd1450dccd6..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89143.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "the-og-gear" -delete-after: True -changes: - - bugfix: "Deluxe Donk Pockets (and their no-carb and vegan variants) are no longer craftable without collecting the recipe." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89144.yml b/html/changelogs/AutoChangeLog-pr-89144.yml deleted file mode 100644 index f0551ec98139a..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89144.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SyncIt21" -delete-after: True -changes: - - bugfix: "fishing rod auto reel won't rip of intercoms or other anchored/immovable objects" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89148.yml b/html/changelogs/AutoChangeLog-pr-89148.yml deleted file mode 100644 index ebd628d99c136..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89148.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "necromanceranne" -delete-after: True -changes: - - bugfix: "The Big Bess cargo hauler no longer magically becomes (visually) a standard Ripley exosuit." \ No newline at end of file diff --git a/html/changelogs/archive/2025-01.yml b/html/changelogs/archive/2025-01.yml index f1115177d0d77..0fca94159883d 100644 --- a/html/changelogs/archive/2025-01.yml +++ b/html/changelogs/archive/2025-01.yml @@ -559,3 +559,27 @@ Rhials: - rscadd: You can now ctrl-click IDs to set your Honorific, which will change your display name to reflect your TITLE as a WORKING MAN on SPACE STATION 13. +2025-01-22: + SyncIt21: + - bugfix: pockets update their icons correctly when removing items that have storage + (e.g. box of bandages) from them + - bugfix: fishing rod auto reel won't rip of intercoms or other anchored/immovable + objects + kuricityy: + - bugfix: Blob's can no longer place their core in ruins on Icebox. + necromanceranne: + - balance: Batons now respect the armor worn by targets. Analog batons respect MELEE + armor. Cell-type batons respect ENERGY armor. + - balance: Various batons have differing amounts of armour penetration based on + what type of baton it is. + - balance: Heads of staff have color graded batons to denote penetration power. + Bronze (Quartermaster), Silver (Chief Engineer, Chief Medical Officer, Head + of Personnel, Research Director), Gold (Captain). Contractor batons are equivalent + to Gold. + - balance: Cell-type batons gain armor penetration based on their cell's quality. + The better it is, the more it penetrates. + - bugfix: The Big Bess cargo hauler no longer magically becomes (visually) a standard + Ripley exosuit. + the-og-gear: + - bugfix: Deluxe Donk Pockets (and their no-carb and vegan variants) are no longer + craftable without collecting the recipe. From c5396ab66cae51b2ecc8442172a7ae477f31be7e Mon Sep 17 00:00:00 2001 From: Jacquerel Date: Wed, 22 Jan 2025 01:36:13 +0000 Subject: [PATCH 20/35] Basic Mob Zombies (#89153) ## About The Pull Request Simple to Basic ruin zombies. Zombies are about as simple as you can get so I am surprised they weren't converted already. I didn't make any particular changes, except canonising a commonly-used map varedit into a subtype and made them groan occasionally. It's a little weird that the default zombie wears a doctor's outfit but no point changing it until/unless it actually causes a problem. ## Why It's Good For The Game 2025 year of no more simple animals. ## Changelog :cl: refactor: NPC zombies found in ruins now use the basic mob framework. Please make an issue report if they exhibit any unusual behaviour. /:cl: --- _maps/RandomRuins/SpaceRuins/interdyne.dmm | 12 +-- _maps/RandomRuins/SpaceRuins/meatderelict.dmm | 2 +- .../map_files/NebulaStation/NebulaStation.dmm | 16 +--- _maps/shuttles/whiteship_box.dmm | 38 +------- _maps/shuttles/whiteship_personalshuttle.dmm | 30 +----- _maps/virtual_domains/psyker_zombies.dmm | 2 +- code/_globalvars/phobias.dm | 2 +- .../mob/living/basic/ruin_defender/zombie.dm | 93 +++++++++++++++++++ .../living/simple_animal/hostile/zombie.dm | 51 ---------- .../unit_tests/simple_animal_freeze.dm | 1 - tgstation.dme | 2 +- .../Scripts/89153_simple_to_basic_zombies.txt | 3 + 12 files changed, 116 insertions(+), 136 deletions(-) create mode 100644 code/modules/mob/living/basic/ruin_defender/zombie.dm delete mode 100644 code/modules/mob/living/simple_animal/hostile/zombie.dm create mode 100644 tools/UpdatePaths/Scripts/89153_simple_to_basic_zombies.txt diff --git a/_maps/RandomRuins/SpaceRuins/interdyne.dmm b/_maps/RandomRuins/SpaceRuins/interdyne.dmm index 46e22d19fb67b..b115c323a356e 100644 --- a/_maps/RandomRuins/SpaceRuins/interdyne.dmm +++ b/_maps/RandomRuins/SpaceRuins/interdyne.dmm @@ -104,7 +104,7 @@ /turf/open/floor/mineral/plastitanium, /area/ruin/space/has_grav/interdyne) "eJ" = ( -/mob/living/simple_animal/hostile/zombie, +/mob/living/basic/zombie, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/cable, @@ -496,7 +496,7 @@ /turf/open/floor/mineral/plastitanium, /area/ruin/space/has_grav/interdyne) "uy" = ( -/mob/living/simple_animal/hostile/zombie, +/mob/living/basic/zombie, /turf/open/floor/mineral/plastitanium, /area/ruin/space/has_grav/interdyne) "vd" = ( @@ -656,7 +656,7 @@ /turf/open/floor/mineral/plastitanium/red, /area/ruin/space/has_grav/interdyne) "By" = ( -/mob/living/simple_animal/hostile/zombie, +/mob/living/basic/zombie, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/mineral/plastitanium/red, /area/ruin/space/has_grav/interdyne) @@ -672,7 +672,7 @@ /turf/open/floor/iron/smooth, /area/ruin/space/has_grav/interdyne) "DA" = ( -/mob/living/simple_animal/hostile/zombie, +/mob/living/basic/zombie, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/mineral/plastitanium, /area/ruin/space/has_grav/interdyne) @@ -719,7 +719,7 @@ /area/ruin/space/has_grav/interdyne) "Ft" = ( /obj/effect/decal/cleanable/dirt, -/mob/living/simple_animal/hostile/zombie, +/mob/living/basic/zombie, /obj/structure/cable, /turf/open/floor/mineral/plastitanium, /area/ruin/space/has_grav/interdyne) @@ -732,7 +732,7 @@ /turf/open/floor/mineral/plastitanium/red, /area/ruin/space/has_grav/interdyne) "FC" = ( -/mob/living/simple_animal/hostile/zombie, +/mob/living/basic/zombie, /obj/structure/cable, /turf/open/floor/mineral/plastitanium, /area/ruin/space/has_grav/interdyne) diff --git a/_maps/RandomRuins/SpaceRuins/meatderelict.dmm b/_maps/RandomRuins/SpaceRuins/meatderelict.dmm index 96959954e2678..e3cdb52cad39e 100644 --- a/_maps/RandomRuins/SpaceRuins/meatderelict.dmm +++ b/_maps/RandomRuins/SpaceRuins/meatderelict.dmm @@ -1008,7 +1008,7 @@ /area/ruin/space/has_grav/powered/biooutpost) "tv" = ( /obj/effect/decal/cleanable/blood/tracks, -/mob/living/simple_animal/hostile/zombie, +/mob/living/basic/zombie, /turf/open/indestructible/white{ icon_state = "showroomfloor" }, diff --git a/_maps/map_files/NebulaStation/NebulaStation.dmm b/_maps/map_files/NebulaStation/NebulaStation.dmm index a0a228bf5fe86..a386fe33b1a97 100644 --- a/_maps/map_files/NebulaStation/NebulaStation.dmm +++ b/_maps/map_files/NebulaStation/NebulaStation.dmm @@ -81457,12 +81457,6 @@ /obj/item/reagent_containers/cup/rag, /turf/open/floor/iron/white/textured_large, /area/station/maintenance/department/medical) -"mdT" = ( -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/closed/wall, -/area/station/maintenance/fore/lesser) "mec" = ( /obj/effect/turf_decal/siding/wood{ dir = 6 @@ -118778,10 +118772,6 @@ /obj/effect/turf_decal/siding/thinplating_new/dark/corner, /turf/open/floor/iron/dark/herringbone, /area/station/service/chapel/funeral) -"rDY" = ( -/obj/structure/disposalpipe/segment, -/turf/closed/wall, -/area/station/maintenance/fore/greater) "rEc" = ( /obj/effect/turf_decal/stripes/line{ dir = 5 @@ -196595,7 +196585,7 @@ fQE cUZ xGl pjP -mdT +iEt xnA pQW hAK @@ -266242,7 +266232,7 @@ bzt jkE nLg cij -rDY +bYy loK kCi nKp @@ -294174,4 +294164,4 @@ txW txW txW txW -"} \ No newline at end of file +"} diff --git a/_maps/shuttles/whiteship_box.dmm b/_maps/shuttles/whiteship_box.dmm index 9a20e38ebcd5d..c800243246908 100644 --- a/_maps/shuttles/whiteship_box.dmm +++ b/_maps/shuttles/whiteship_box.dmm @@ -273,15 +273,7 @@ dir = 9 }, /obj/structure/cable, -/mob/living/simple_animal/hostile/zombie{ - desc = "This undead fiend looks to be badly decomposed."; - environment_smash = 0; - health = 60; - melee_damage_lower = 11; - melee_damage_upper = 11; - name = "Rotting Carcass"; - outfit = /datum/outfit/corpse_assistant - }, +/mob/living/basic/zombie/rotten/assistant, /turf/open/floor/iron/white/corner{ dir = 1 }, @@ -360,14 +352,7 @@ /obj/effect/decal/cleanable/blood/old, /obj/effect/decal/cleanable/dirt, /obj/structure/cable, -/mob/living/simple_animal/hostile/zombie{ - desc = "This undead fiend looks to be badly decomposed."; - environment_smash = 0; - health = 60; - melee_damage_lower = 11; - melee_damage_upper = 11; - name = "Rotting Carcass" - }, +/mob/living/basic/zombie/rotten, /turf/open/floor/iron, /area/shuttle/abandoned/crew) "aQ" = ( @@ -841,14 +826,7 @@ }, /obj/effect/decal/cleanable/blood/old, /obj/effect/decal/cleanable/dirt, -/mob/living/simple_animal/hostile/zombie{ - desc = "This undead fiend looks to be badly decomposed."; - environment_smash = 0; - health = 60; - melee_damage_lower = 11; - melee_damage_upper = 11; - name = "Rotting Carcass" - }, +/mob/living/basic/zombie/rotten, /turf/open/floor/iron, /area/shuttle/abandoned/medbay) "bT" = ( @@ -1449,15 +1427,7 @@ }, /obj/effect/decal/cleanable/blood/gibs/old, /obj/structure/cable, -/mob/living/simple_animal/hostile/zombie{ - desc = "This undead fiend looks to be badly decomposed."; - environment_smash = 0; - health = 60; - melee_damage_lower = 11; - melee_damage_upper = 11; - name = "Rotting Carcass"; - outfit = /datum/outfit/corpse_assistant - }, +/mob/living/basic/zombie/rotten/assistant, /turf/open/floor/iron, /area/shuttle/abandoned/medbay) "dc" = ( diff --git a/_maps/shuttles/whiteship_personalshuttle.dmm b/_maps/shuttles/whiteship_personalshuttle.dmm index 7666f6c63add1..0316e7f3aeab0 100644 --- a/_maps/shuttles/whiteship_personalshuttle.dmm +++ b/_maps/shuttles/whiteship_personalshuttle.dmm @@ -162,15 +162,7 @@ /obj/structure/cable, /obj/effect/decal/cleanable/blood/splatter, /obj/effect/decal/cleanable/dirt, -/mob/living/simple_animal/hostile/zombie{ - desc = "This undead fiend looks to be badly decomposed."; - environment_smash = 0; - health = 60; - melee_damage_lower = 11; - melee_damage_upper = 11; - name = "Rotting Carcass"; - outfit = /datum/outfit/corpse_assistant - }, +/mob/living/basic/zombie/rotten/assistant, /turf/open/floor/mineral/titanium, /area/shuttle/abandoned/engine) "gG" = ( @@ -195,15 +187,7 @@ /obj/effect/decal/cleanable/dirt, /obj/structure/cable, /obj/effect/decal/cleanable/blood/splatter, -/mob/living/simple_animal/hostile/zombie{ - desc = "This undead fiend looks to be badly decomposed."; - environment_smash = 0; - health = 60; - melee_damage_lower = 11; - melee_damage_upper = 11; - name = "Rotting Carcass"; - outfit = /datum/outfit/corpse_assistant - }, +/mob/living/basic/zombie/rotten/assistant, /turf/open/floor/plating, /area/shuttle/abandoned/engine) "nI" = ( @@ -260,15 +244,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/blood/splatter, /obj/structure/chair/comfy/shuttle, -/mob/living/simple_animal/hostile/zombie{ - desc = "This undead fiend looks to be badly decomposed."; - environment_smash = 0; - health = 60; - melee_damage_lower = 11; - melee_damage_upper = 11; - name = "Rotting Carcass"; - outfit = /datum/outfit/corpse_assistant - }, +/mob/living/basic/zombie/rotten/assistant, /turf/open/floor/mineral/plastitanium, /area/shuttle/abandoned/bridge) "pS" = ( diff --git a/_maps/virtual_domains/psyker_zombies.dmm b/_maps/virtual_domains/psyker_zombies.dmm index 4ca97f8ef6315..c532e87189f9c 100644 --- a/_maps/virtual_domains/psyker_zombies.dmm +++ b/_maps/virtual_domains/psyker_zombies.dmm @@ -114,7 +114,7 @@ /turf/open/indestructible/dark, /area/virtual_domain) "X" = ( -/mob/living/simple_animal/hostile/zombie, +/mob/living/basic/zombie, /turf/open/indestructible/dark, /area/virtual_domain) "Y" = ( diff --git a/code/_globalvars/phobias.dm b/code/_globalvars/phobias.dm index d6677a213a48a..6c93c07bbb83a 100644 --- a/code/_globalvars/phobias.dm +++ b/code/_globalvars/phobias.dm @@ -107,9 +107,9 @@ GLOBAL_LIST_INIT(phobia_mobs, list( /mob/living/basic/shade, /mob/living/basic/skeleton, /mob/living/basic/wizard, + /mob/living/basic/zombie, /mob/living/simple_animal/bot/mulebot/paranormal, /mob/living/simple_animal/hostile/dark_wizard, - /mob/living/simple_animal/hostile/zombie, )), )) diff --git a/code/modules/mob/living/basic/ruin_defender/zombie.dm b/code/modules/mob/living/basic/ruin_defender/zombie.dm new file mode 100644 index 0000000000000..b77920af8d154 --- /dev/null +++ b/code/modules/mob/living/basic/ruin_defender/zombie.dm @@ -0,0 +1,93 @@ +/// Everyone knows what a zombie is +/mob/living/basic/zombie + name = "Shambling Corpse" + desc = "When there is no more room in hell, the dead will walk in outer space." + icon = 'icons/mob/simple/simple_human.dmi' + mob_biotypes = MOB_ORGANIC|MOB_HUMANOID + sentience_type = SENTIENCE_HUMANOID + maxHealth = 100 + health = 100 + melee_damage_lower = 21 + melee_damage_upper = 21 + attack_verb_continuous = "bites" + attack_verb_simple = "bite" + attack_sound = 'sound/effects/hallucinations/growl1.ogg' + attack_vis_effect = ATTACK_EFFECT_BITE + combat_mode = TRUE + speed = 4 + status_flags = CANPUSH + death_message = "rapidly decays into a pile of bones!" + unsuitable_atmos_damage = 0 + unsuitable_cold_damage = 0 + faction = list(FACTION_HOSTILE) + basic_mob_flags = DEL_ON_DEATH + ai_controller = /datum/ai_controller/basic_controller/zombie + /// Outfit the zombie spawns with for visuals. + var/outfit = /datum/outfit/corpse_doctor + /// Chance to spread zombieism on hit + /// Only for admins because we don't actually want romerol to get into the round from space ruins generally speaking + var/infection_chance = 0 + +/mob/living/basic/zombie/Initialize(mapload) + . = ..() + apply_dynamic_human_appearance(src, outfit, /datum/species/zombie, bloody_slots = ITEM_SLOT_OCLOTHING) + AddElement(/datum/element/death_drops, string_list(list(/obj/effect/decal/remains/human))) + +/mob/living/basic/zombie/melee_attack(atom/target, list/modifiers, ignore_cooldown) + . = ..() + if (!. || !infection_chance || !ishuman(target) || !prob(infection_chance)) + return + try_to_zombie_infect(target) + +/// Weaker variant used if you want to put more of them in one place, won't attack obstacles +/mob/living/basic/zombie/rotten + name = "Rotting Carcass" + desc = "This undead fiend looks to be badly decomposed." + health = 60 + melee_damage_lower = 11 + melee_damage_upper = 11 + ai_controller = /datum/ai_controller/basic_controller/zombie/stupid + +/mob/living/basic/zombie/rotten/assistant + outfit = /datum/outfit/corpse_assistant + +/datum/outfit/corpse_doctor + name = "Corpse Doctor" + suit = /obj/item/clothing/suit/toggle/labcoat + uniform = /obj/item/clothing/under/rank/medical/doctor + shoes = /obj/item/clothing/shoes/sneakers/white + back = /obj/item/storage/backpack/medic + +/datum/outfit/corpse_assistant + name = "Corpse Assistant" + mask = /obj/item/clothing/mask/gas + uniform = /obj/item/clothing/under/color/grey + shoes = /obj/item/clothing/shoes/sneakers/black + back = /obj/item/storage/backpack + +/datum/ai_planning_subtree/random_speech/zombie + speech_chance = 1 + emote_hear = list("groans.", "moans.", "grunts.") + emote_see = list("twitches.", "shudders.") + +/datum/ai_controller/basic_controller/zombie + blackboard = list( + BB_TARGET_MINIMUM_STAT = HARD_CRIT, + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + ) + + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + planning_subtrees = list( + /datum/ai_planning_subtree/random_speech/zombie, + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/attack_obstacle_in_path, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + ) + +/datum/ai_controller/basic_controller/zombie/stupid + planning_subtrees = list( + /datum/ai_planning_subtree/random_speech/zombie, + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + ) diff --git a/code/modules/mob/living/simple_animal/hostile/zombie.dm b/code/modules/mob/living/simple_animal/hostile/zombie.dm deleted file mode 100644 index 45bcf6cd3acd7..0000000000000 --- a/code/modules/mob/living/simple_animal/hostile/zombie.dm +++ /dev/null @@ -1,51 +0,0 @@ -/mob/living/simple_animal/hostile/zombie - name = "Shambling Corpse" - desc = "When there is no more room in hell, the dead will walk in outer space." - icon = 'icons/mob/simple/simple_human.dmi' - mob_biotypes = MOB_ORGANIC|MOB_HUMANOID - sentience_type = SENTIENCE_HUMANOID - speak_chance = 0 - stat_attack = HARD_CRIT //braains - maxHealth = 100 - health = 100 - harm_intent_damage = 5 - melee_damage_lower = 21 - melee_damage_upper = 21 - attack_verb_continuous = "bites" - attack_verb_simple = "bite" - attack_sound = 'sound/effects/hallucinations/growl1.ogg' - attack_vis_effect = ATTACK_EFFECT_BITE - combat_mode = TRUE - atmos_requirements = null - minbodytemp = 0 - status_flags = CANPUSH - death_message = "collapses, flesh gone in a pile of bones!" - del_on_death = TRUE - loot = list(/obj/effect/decal/remains/human) - /// The probability that we give people real zombie infections on hit. - var/infection_chance = 0 - /// Outfit the zombie spawns with for visuals. - var/outfit = /datum/outfit/corpse_doctor - -/mob/living/simple_animal/hostile/zombie/Initialize(mapload) - . = ..() - apply_dynamic_human_appearance(src, outfit, /datum/species/zombie, bloody_slots = ITEM_SLOT_OCLOTHING) - -/mob/living/simple_animal/hostile/zombie/AttackingTarget(atom/attacked_target) - . = ..() - if(. && ishuman(target) && prob(infection_chance)) - try_to_zombie_infect(target) - -/datum/outfit/corpse_doctor - name = "Corpse Doctor" - suit = /obj/item/clothing/suit/toggle/labcoat - uniform = /obj/item/clothing/under/rank/medical/doctor - shoes = /obj/item/clothing/shoes/sneakers/white - back = /obj/item/storage/backpack/medic - -/datum/outfit/corpse_assistant - name = "Corpse Assistant" - mask = /obj/item/clothing/mask/gas - uniform = /obj/item/clothing/under/color/grey - shoes = /obj/item/clothing/shoes/sneakers/black - back = /obj/item/storage/backpack diff --git a/code/modules/unit_tests/simple_animal_freeze.dm b/code/modules/unit_tests/simple_animal_freeze.dm index e82a607a9bfb8..ac4f911b26bfa 100644 --- a/code/modules/unit_tests/simple_animal_freeze.dm +++ b/code/modules/unit_tests/simple_animal_freeze.dm @@ -64,7 +64,6 @@ /mob/living/simple_animal/hostile/retaliate/goose, /mob/living/simple_animal/hostile/retaliate/goose/vomit, /mob/living/simple_animal/hostile/vatbeast, - /mob/living/simple_animal/hostile/zombie, /mob/living/simple_animal/soulscythe, // DO NOT ADD NEW ENTRIES TO THIS LIST // READ THE COMMENT ABOVE diff --git a/tgstation.dme b/tgstation.dme index b7f67bf487db3..1d960899caeb8 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -5072,6 +5072,7 @@ #include "code\modules\mob\living\basic\ruin_defender\mad_piano.dm" #include "code\modules\mob\living\basic\ruin_defender\skeleton.dm" #include "code\modules\mob\living\basic\ruin_defender\stickman.dm" +#include "code\modules\mob\living\basic\ruin_defender\zombie.dm" #include "code\modules\mob\living\basic\ruin_defender\mimic\mimic.dm" #include "code\modules\mob\living\basic\ruin_defender\mimic\mimic_ai.dm" #include "code\modules\mob\living\basic\ruin_defender\wizard\wizard.dm" @@ -5352,7 +5353,6 @@ #include "code\modules\mob\living\simple_animal\hostile\illusion.dm" #include "code\modules\mob\living\simple_animal\hostile\ooze.dm" #include "code\modules\mob\living\simple_animal\hostile\vatbeast.dm" -#include "code\modules\mob\living\simple_animal\hostile\zombie.dm" #include "code\modules\mob\living\simple_animal\hostile\megafauna\_megafauna.dm" #include "code\modules\mob\living\simple_animal\hostile\megafauna\blood_drunk_miner.dm" #include "code\modules\mob\living\simple_animal\hostile\megafauna\bubblegum.dm" diff --git a/tools/UpdatePaths/Scripts/89153_simple_to_basic_zombies.txt b/tools/UpdatePaths/Scripts/89153_simple_to_basic_zombies.txt new file mode 100644 index 0000000000000..dbb408b60cd69 --- /dev/null +++ b/tools/UpdatePaths/Scripts/89153_simple_to_basic_zombies.txt @@ -0,0 +1,3 @@ +/mob/living/simple_animal/hostile/zombie{health=60;name="Rotting Carcass";outfit=/datum/outfit/corpse_assistant} : /mob/living/basic/zombie/rotten/assistant +/mob/living/simple_animal/hostile/zombie{health=60;name="Rotting Carcass"} : /mob/living/basic/zombie/rotten +/mob/living/simple_animal/hostile/zombie : /mob/living/basic/zombie{@OLD} From 85cbc4cbae1ff4712cc1efe9b3c8a9d1e6e7dff2 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 01:36:35 +0000 Subject: [PATCH 21/35] Automatic changelog for PR #89153 [ci skip] --- html/changelogs/AutoChangeLog-pr-89153.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89153.yml diff --git a/html/changelogs/AutoChangeLog-pr-89153.yml b/html/changelogs/AutoChangeLog-pr-89153.yml new file mode 100644 index 0000000000000..acd9df2a8fd46 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89153.yml @@ -0,0 +1,4 @@ +author: "Jacquerel" +delete-after: True +changes: + - refactor: "NPC zombies found in ruins now use the basic mob framework. Please make an issue report if they exhibit any unusual behaviour." \ No newline at end of file From 89538067db572e4f904b61a0f6b5c88445876804 Mon Sep 17 00:00:00 2001 From: Jacquerel Date: Wed, 22 Jan 2025 01:38:47 +0000 Subject: [PATCH 22/35] Remove totally unused blob curse (#89154) ## About The Pull Request We have a mob called `simple_animal/hostile/curseblob` which was used only for the `necropolis_curse` status effect. From the git history, this seems to have been added in a PR merged eight years ago where the PR author came up with a cool set of curses to apply to cursed objects and PRed it to the game as a concept to be used later. Subsequently, nobody used it. Well, to be more accurate, _two_ things apply the necropolis curse debuff right now but they only collectively use three of the four possibilities. The fourth, which spawns a mob with weird behaviour, is unused and so rather than spend my time bringing it up to standard I just removed it. Because this is dead code. To be quite honest I am not totally certain that `necropolis_curse` should be a single status effect either and it would plausibly be better off being two different status effects for the two different sources it is currently invoked (helbital overdose, and being sacrificed by a heretic). **Fun Fact!** Being sacrificed by a heretic doses you with 1 minute worth of _Helgrasp_ which spawns a frightening hand to attack you once per second, and also applies the Necropolis Curse which spawns a frightening hand to attack you once per ten seconds. This means that if you have anything in your mob which affects metabolic rate your sacrificial experience may be somewhat different, as quite a lot of the danger actually just comes from a chemical in your body. One of these effects spawns the hands slightly further away than the other, and you actually spend _2.5 minutes_ in the spooky hand room, so in that second (longer) half you'll only be tormented by very occasional spectral groping. Personally I would not do it this way I think. However rather than removing and replacing it, which would probably have some kind of aftereffect on the heretic sacrifice minigame that I would rather make larger changes to, I just touched up some of the code to avoid single-letter vars and to use a helper proc we already use in other heretic-related places. ## Why It's Good For The Game This wasn't maintained, isn't used, and was on our to-do mob conversion list. ## Changelog Not player facing --- code/__DEFINES/status_effects.dm | 6 +- code/datums/status_effects/debuffs/debuffs.dm | 58 ++++---- .../sacrifice_knowledge/sacrifice_buff.dm | 6 +- .../hostile/mining_mobs/curse_blob.dm | 132 ------------------ .../unit_tests/simple_animal_freeze.dm | 1 - tgstation.dme | 1 - 6 files changed, 29 insertions(+), 175 deletions(-) delete mode 100644 code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index e2fdf01e9aaba..46987974d8049 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -26,12 +26,10 @@ //several flags for the Necropolis curse status effect ///makes the edges of the target's screen obscured #define CURSE_BLINDING (1<<0) -///spawns creatures that attack the target only -#define CURSE_SPAWNING (1<<1) ///causes gradual damage -#define CURSE_WASTING (1<<2) +#define CURSE_WASTING (1<<1) ///hands reach out from the sides of the screen, doing damage and stunning if they hit the target -#define CURSE_GRASPING (1<<3) +#define CURSE_GRASPING (1<<2) //Incapacitated status effect flags /// If the mob is normal incapacitated. Should never need this, just avoids issues if we ever overexpand this diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm index 006a2a527dfb3..7627d16b66f45 100644 --- a/code/datums/status_effects/debuffs/debuffs.dm +++ b/code/datums/status_effects/debuffs/debuffs.dm @@ -461,26 +461,32 @@ /datum/status_effect/neck_slice/get_examine_text() return span_warning("[owner.p_Their()] neck is cut and is bleeding profusely!") +/// Applies a curse with various possible effects /mob/living/proc/apply_necropolis_curse(set_curse) - var/datum/status_effect/necropolis_curse/C = has_status_effect(/datum/status_effect/necropolis_curse) + var/datum/status_effect/necropolis_curse/curse = has_status_effect(/datum/status_effect/necropolis_curse) if(!set_curse) - set_curse = pick(CURSE_BLINDING, CURSE_SPAWNING, CURSE_WASTING, CURSE_GRASPING) - if(QDELETED(C)) + set_curse = pick(CURSE_BLINDING, CURSE_WASTING, CURSE_GRASPING) + if(QDELETED(curse)) apply_status_effect(/datum/status_effect/necropolis_curse, set_curse) else - C.apply_curse(set_curse) - C.duration += 3000 //time added by additional curses - return C + curse.apply_curse(set_curse) + curse.duration += 5 MINUTES //time added by additional curses + return curse +/// A curse that does up to three nasty things to you /datum/status_effect/necropolis_curse id = "necrocurse" duration = 10 MINUTES //you're cursed for 10 minutes have fun tick_interval = 5 SECONDS alert_type = null + /// Which nasty things are we doing? [CURSE_BLINDING / CURSE_WASTING / CURSE_GRASPING]] var/curse_flags = NONE - var/effect_last_activation = 0 - var/effect_cooldown = 100 - var/obj/effect/temp_visual/curse/wasting_effect = new + /// When should we next throw hands? + var/effect_next_activation = 0 + /// How long between throwing hands? + var/effect_cooldown = 10 SECONDS + /// Visuals for the wasting effect + var/obj/effect/temp_visual/curse/wasting_effect /datum/status_effect/necropolis_curse/on_creation(mob/living/new_owner, set_curse) . = ..() @@ -500,6 +506,8 @@ curse_flags |= set_curse if(curse_flags & CURSE_BLINDING) owner.overlay_fullscreen("curse", /atom/movable/screen/fullscreen/curse, 1) + if(curse_flags & CURSE_WASTING && !wasting_effect) + wasting_effect = new /datum/status_effect/necropolis_curse/proc/remove_curse(remove_curse) if(remove_curse & CURSE_BLINDING) @@ -509,6 +517,7 @@ /datum/status_effect/necropolis_curse/tick(seconds_between_ticks) if(owner.stat == DEAD) return + if(curse_flags & CURSE_WASTING) wasting_effect.forceMove(owner.loc) wasting_effect.setDir(owner.dir) @@ -517,31 +526,12 @@ animate(wasting_effect, alpha = 0, time = 32) playsound(owner, 'sound/effects/curse/curse5.ogg', 20, TRUE, -1) owner.adjustFireLoss(0.75) - if(effect_last_activation <= world.time) - effect_last_activation = world.time + effect_cooldown - if(curse_flags & CURSE_SPAWNING) - var/turf/spawn_turf - var/sanity = 10 - while(!spawn_turf && sanity) - spawn_turf = locate(owner.x + pick(rand(10, 15), rand(-10, -15)), owner.y + pick(rand(10, 15), rand(-10, -15)), owner.z) - sanity-- - if(spawn_turf) - var/mob/living/simple_animal/hostile/asteroid/curseblob/C = new (spawn_turf) - C.set_target = owner - C.GiveTarget() - if(curse_flags & CURSE_GRASPING) - var/grab_dir = turn(owner.dir, pick(-90, 90, 180, 180)) //grab them from a random direction other than the one faced, favoring grabbing from behind - var/turf/spawn_turf = get_ranged_target_turf(owner, grab_dir, 5) - if(spawn_turf) - grasp(spawn_turf) - -/datum/status_effect/necropolis_curse/proc/grasp(turf/spawn_turf) - set waitfor = FALSE - new/obj/effect/temp_visual/dir_setting/curse/grasp_portal(spawn_turf, owner.dir) - playsound(spawn_turf, 'sound/effects/curse/curse2.ogg', 80, TRUE, -1) - var/obj/projectile/curse_hand/C = new (spawn_turf) - C.aim_projectile(owner, spawn_turf) - C.fire() + + if(curse_flags & CURSE_GRASPING) + if(effect_next_activation > world.time) + return + effect_next_activation = world.time + effect_cooldown + fire_curse_hand(owner, range = 5, projectile_type = /obj/projectile/curse_hand) // This one stuns people /obj/effect/temp_visual/curse icon_state = "curse" diff --git a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_buff.dm b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_buff.dm index 4238b54f91543..618ee9e6f667e 100644 --- a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_buff.dm +++ b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_buff.dm @@ -109,15 +109,15 @@ bloodiest_wound.adjust_blood_flow(-0.5 * seconds_between_ticks) /// Torment the target with a frightening hand -/proc/fire_curse_hand(mob/living/carbon/victim, turf/forced_turf) +/proc/fire_curse_hand(mob/living/carbon/victim, turf/forced_turf, range = 8, projectile_type = /obj/projectile/curse_hand/hel) var/grab_dir = turn(victim.dir, pick(-90, 90, 180, 180)) // Not in front, favour behind - var/turf/spawn_turf = get_ranged_target_turf(victim, grab_dir, 8) + var/turf/spawn_turf = get_ranged_target_turf(victim, grab_dir, range) spawn_turf = forced_turf ? forced_turf : spawn_turf if (isnull(spawn_turf)) return new /obj/effect/temp_visual/dir_setting/curse/grasp_portal(spawn_turf, victim.dir) playsound(spawn_turf, 'sound/effects/curse/curse2.ogg', 80, TRUE, -1) - var/obj/projectile/curse_hand/hel/hand = new (spawn_turf) + var/obj/projectile/hand = new projectile_type(spawn_turf) hand.aim_projectile(victim, spawn_turf) if (QDELETED(hand)) // safety check if above fails - above has a stack trace if it does fail return diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm deleted file mode 100644 index 5fbd6cda5cbfb..0000000000000 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm +++ /dev/null @@ -1,132 +0,0 @@ -/mob/living/simple_animal/hostile/asteroid/curseblob - name = "curse mass" - desc = "A mass of purple... smoke?" - icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi' - icon_state = "curseblob" - icon_living = "curseblob" - icon_aggro = "curseblob" - mob_biotypes = MOB_SPIRIT - move_to_delay = 5 - vision_range = 20 - aggro_vision_range = 20 - maxHealth = 40 //easy to kill, but oh, will you be seeing a lot of them. - health = 40 - melee_damage_lower = 10 - melee_damage_upper = 10 - melee_damage_type = BURN - attack_verb_continuous = "slashes" - attack_verb_simple = "slash" - attack_sound = 'sound/effects/curse/curseattack.ogg' - attack_vis_effect = ATTACK_EFFECT_SLASH - throw_message = "passes through the smokey body of" - obj_damage = 0 - environment_smash = ENVIRONMENT_SMASH_NONE - sentience_type = SENTIENCE_BOSS - layer = LARGE_MOB_LAYER - var/mob/living/set_target - var/datum/move_loop/has_target/force_move/our_loop - -/mob/living/simple_animal/hostile/asteroid/curseblob/Initialize(mapload) - . = ..() - QDEL_IN(src, 60 SECONDS) - AddElement(/datum/element/simple_flying) - playsound(src, 'sound/effects/curse/curse1.ogg', 100, TRUE, -1) - -/mob/living/simple_animal/hostile/asteroid/curseblob/Destroy() - new /obj/effect/temp_visual/dir_setting/curse/blob(loc, dir) - set_target = null - return ..() - -/mob/living/simple_animal/hostile/asteroid/curseblob/Goto(move_target, delay, minimum_distance) //Observe - if(check_for_target()) - return - move_loop(target, delay) - -/mob/living/simple_animal/hostile/asteroid/curseblob/proc/move_loop(move_target, delay) - if(our_loop) - return - our_loop = GLOB.move_manager.force_move(src, move_target, delay, priority = MOVEMENT_ABOVE_SPACE_PRIORITY) - if(!our_loop) - return - RegisterSignal(move_target, COMSIG_MOB_STATCHANGE, PROC_REF(stat_change)) - RegisterSignal(move_target, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(target_z_change)) - RegisterSignal(src, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(our_z_change)) - RegisterSignal(our_loop, COMSIG_QDELETING, PROC_REF(handle_loop_end)) - -/mob/living/simple_animal/hostile/asteroid/curseblob/proc/stat_change(datum/source, new_stat) - SIGNAL_HANDLER - if(new_stat != CONSCIOUS) - qdel(src) - -/mob/living/simple_animal/hostile/asteroid/curseblob/proc/target_z_change(datum/source, old_z, new_z) - SIGNAL_HANDLER - qdel(src) - -/mob/living/simple_animal/hostile/asteroid/curseblob/proc/our_z_change(datum/source, old_z, new_z) - SIGNAL_HANDLER - qdel(src) - -/mob/living/simple_animal/hostile/asteroid/curseblob/proc/handle_loop_end() - SIGNAL_HANDLER - if(QDELETED(src)) - return - qdel(src) - -/mob/living/simple_animal/hostile/asteroid/curseblob/handle_target_del(datum/source) - . = ..() - qdel(src) - -/mob/living/simple_animal/hostile/asteroid/curseblob/proc/check_for_target() - if(QDELETED(src) || !set_target) - return TRUE - if(set_target.stat != CONSCIOUS) - return TRUE - if(set_target.z != z) - return TRUE - -/mob/living/simple_animal/hostile/asteroid/curseblob/GiveTarget(new_target) - if(check_for_target()) - return - new_target = set_target - . = ..() - Goto(target, move_to_delay) - -/mob/living/simple_animal/hostile/asteroid/curseblob/LoseTarget() //we can't lose our target! - if(check_for_target()) - return - -//if it's not our target, we ignore it -/mob/living/simple_animal/hostile/asteroid/curseblob/CanAllowThrough(atom/movable/mover, border_dir) - . = ..() - if(mover == set_target) - return FALSE - if(isprojectile(mover)) - var/obj/projectile/proj = mover - if(proj.firer == set_target) - return FALSE - -#define IGNORE_PROC_IF_NOT_TARGET(X) /mob/living/simple_animal/hostile/asteroid/curseblob/##X(AM) { if (AM == set_target) return ..(); } - -IGNORE_PROC_IF_NOT_TARGET(attack_hand) - -IGNORE_PROC_IF_NOT_TARGET(attack_hulk) - -IGNORE_PROC_IF_NOT_TARGET(attack_paw) - -IGNORE_PROC_IF_NOT_TARGET(attack_alien) - -IGNORE_PROC_IF_NOT_TARGET(attack_larva) - -IGNORE_PROC_IF_NOT_TARGET(attack_animal) - -/mob/living/simple_animal/hostile/asteroid/curseblob/bullet_act(obj/projectile/proj) - if(proj.firer != set_target) - return BULLET_ACT_BLOCK - return ..() - -/mob/living/simple_animal/hostile/asteroid/curseblob/attacked_by(obj/item/I, mob/living/L) - if(L != set_target) - return - return ..() - -#undef IGNORE_PROC_IF_NOT_TARGET diff --git a/code/modules/unit_tests/simple_animal_freeze.dm b/code/modules/unit_tests/simple_animal_freeze.dm index ac4f911b26bfa..70f3b82885d23 100644 --- a/code/modules/unit_tests/simple_animal_freeze.dm +++ b/code/modules/unit_tests/simple_animal_freeze.dm @@ -21,7 +21,6 @@ /mob/living/simple_animal/bot/secbot/pingsky, /mob/living/simple_animal/hostile, /mob/living/simple_animal/hostile/asteroid, - /mob/living/simple_animal/hostile/asteroid/curseblob, /mob/living/simple_animal/hostile/asteroid/elite, /mob/living/simple_animal/hostile/asteroid/elite/broodmother, /mob/living/simple_animal/hostile/asteroid/elite/broodmother_child, diff --git a/tgstation.dme b/tgstation.dme index 1d960899caeb8..07b101102de89 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -5363,7 +5363,6 @@ #include "code\modules\mob\living\simple_animal\hostile\megafauna\hierophant.dm" #include "code\modules\mob\living\simple_animal\hostile\megafauna\legion.dm" #include "code\modules\mob\living\simple_animal\hostile\megafauna\wendigo.dm" -#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\curse_blob.dm" #include "code\modules\mob\living\simple_animal\hostile\mining_mobs\mining_mobs.dm" #include "code\modules\mob\living\simple_animal\hostile\mining_mobs\polarbear.dm" #include "code\modules\mob\living\simple_animal\hostile\mining_mobs\elites\elite.dm" From 37ad103c5ec79f3f521e16b3a274428369971d93 Mon Sep 17 00:00:00 2001 From: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Date: Wed, 22 Jan 2025 02:43:26 +0100 Subject: [PATCH 23/35] Implements /Exited() for clipboards (#89156) ## About The Pull Request Moved visual updates upon pen/paper removal into /Exited(), thanks to Ephe for the idea ## Why It's Good For The Game Makes sure that we don't hang onto references if our pen/paper gets removed via less-than-normal methods, like instant recall ## Changelog :cl: fix: Clipboards should no longer retain pens that got removed via Instant Recall /:cl: --- code/modules/paperwork/clipboard.dm | 67 +++++++++++++---------------- 1 file changed, 31 insertions(+), 36 deletions(-) diff --git a/code/modules/paperwork/clipboard.dm b/code/modules/paperwork/clipboard.dm index 435cfc3e7c74a..ec81574628d21 100644 --- a/code/modules/paperwork/clipboard.dm +++ b/code/modules/paperwork/clipboard.dm @@ -26,13 +26,11 @@ /// Is the pen integrated? var/integrated_pen = FALSE /** - * Weakref of the topmost piece of paper - * + * Topmost piece of paper * This is used for the paper displayed on the clipboard's icon * and it is the one attacked, when attacking the clipboard. - * (As you can't organise contents directly in BYOND) */ - var/datum/weakref/toppaper_ref + var/obj/item/paper/top_paper /obj/item/clipboard/suicide_act(mob/living/carbon/user) user.visible_message(span_suicide("[user] begins putting [user.p_their()] head into the clip of \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")) @@ -50,9 +48,8 @@ . = ..() if(!integrated_pen && pen) . += span_notice("Alt-click to remove [pen].") - var/obj/item/paper/toppaper = toppaper_ref?.resolve() - if(toppaper) - . += span_notice("Right-click to remove [toppaper].") + if(top_paper) + . += span_notice("Right-click to remove [top_paper].") /// Take out the topmost paper /obj/item/clipboard/proc/remove_paper(obj/item/paper/paper, mob/user) @@ -61,22 +58,24 @@ paper.forceMove(user.loc) user.put_in_hands(paper) to_chat(user, span_notice("You remove [paper] from [src].")) - var/obj/item/paper/toppaper = toppaper_ref?.resolve() - if(paper == toppaper) - UnregisterSignal(toppaper, COMSIG_ATOM_UPDATED_ICON) - toppaper_ref = null - var/obj/item/paper/newtop = locate(/obj/item/paper) in src - if(newtop && (newtop != paper)) - toppaper_ref = WEAKREF(newtop) - else - toppaper_ref = null - update_icon() /obj/item/clipboard/proc/remove_pen(mob/user) pen.forceMove(user.loc) user.put_in_hands(pen) to_chat(user, span_notice("You remove [pen] from [src].")) - pen = null + +/obj/item/clipboard/Exited(atom/movable/gone, direction) + . = ..() + if (gone == pen) + pen = null + update_icon() + return + + if (gone != top_paper) + return + + UnregisterSignal(top_paper, COMSIG_ATOM_UPDATED_ICON) + top_paper = locate(/obj/item/paper) in src update_icon() /obj/item/clipboard/click_alt(mob/user) @@ -100,32 +99,29 @@ . += "clipboard_over" /obj/item/clipboard/proc/get_paper_overlay() - var/obj/item/paper/toppaper = toppaper_ref?.resolve() - if(isnull(toppaper)) + if(isnull(top_paper)) return - var/mutable_appearance/paper_overlay = mutable_appearance(icon, toppaper.icon_state, offset_spokesman = src, appearance_flags = KEEP_APART) - paper_overlay = toppaper.color_atom_overlay(paper_overlay) - paper_overlay.overlays += toppaper.overlays + var/mutable_appearance/paper_overlay = mutable_appearance(icon, top_paper.icon_state, offset_spokesman = src, appearance_flags = KEEP_APART) + paper_overlay = top_paper.color_atom_overlay(paper_overlay) + paper_overlay.overlays += top_paper.overlays return paper_overlay /obj/item/clipboard/attack_hand(mob/user, list/modifiers) if(LAZYACCESS(modifiers, RIGHT_CLICK)) - var/obj/item/paper/toppaper = toppaper_ref?.resolve() - remove_paper(toppaper, user) + remove_paper(top_paper, user) return TRUE . = ..() /obj/item/clipboard/attackby(obj/item/weapon, mob/user, params) - var/obj/item/paper/toppaper = toppaper_ref?.resolve() if(istype(weapon, /obj/item/paper)) //Add paper into the clipboard if(!user.transferItemToLoc(weapon, src)) return - if(toppaper) - UnregisterSignal(toppaper, COMSIG_ATOM_UPDATED_ICON) + if(top_paper) + UnregisterSignal(top_paper, COMSIG_ATOM_UPDATED_ICON) RegisterSignal(weapon, COMSIG_ATOM_UPDATED_ICON, PROC_REF(on_top_paper_change)) - toppaper_ref = WEAKREF(weapon) + top_paper = weapon to_chat(user, span_notice("You clip [weapon] onto [src].")) else if(istype(weapon, /obj/item/pen) && !pen) //Add a pen into the clipboard, attack (write) if there is already one @@ -133,8 +129,8 @@ return pen = weapon to_chat(usr, span_notice("You slot [weapon] into [src].")) - else if(toppaper) - toppaper.attackby(user.get_active_held_item(), user) + else if(top_paper) + top_paper.attackby(user.get_active_held_item(), user) update_appearance() /obj/item/clipboard/attack_self(mob/user) @@ -154,14 +150,13 @@ data["pen"] = "[pen]" data["integrated_pen"] = integrated_pen - var/obj/item/paper/toppaper = toppaper_ref?.resolve() - data["top_paper"] = "[toppaper]" - data["top_paper_ref"] = "[REF(toppaper)]" + data["top_paper"] = "[top_paper]" + data["top_paper_ref"] = "[REF(top_paper)]" data["paper"] = list() data["paper_ref"] = list() for(var/obj/item/paper/paper in src) - if(paper == toppaper) + if(paper == top_paper) continue data["paper"] += "[paper]" data["paper_ref"] += "[REF(paper)]" @@ -202,7 +197,7 @@ if("move_top_paper") var/obj/item/paper/paper = locate(params["ref"]) in src if(istype(paper)) - toppaper_ref = WEAKREF(paper) + top_paper = paper to_chat(usr, span_notice("You move [paper] to the top.")) update_icon() . = TRUE From b028b40f3767f5257f9aca65483fef40c36c3f23 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 01:43:46 +0000 Subject: [PATCH 24/35] Automatic changelog for PR #89156 [ci skip] --- html/changelogs/AutoChangeLog-pr-89156.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89156.yml diff --git a/html/changelogs/AutoChangeLog-pr-89156.yml b/html/changelogs/AutoChangeLog-pr-89156.yml new file mode 100644 index 0000000000000..43ad3a8538258 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89156.yml @@ -0,0 +1,4 @@ +author: "SmArtKar" +delete-after: True +changes: + - bugfix: "Clipboards should no longer retain pens that got removed via Instant Recall" \ No newline at end of file From 00297eaee6110d5cdd59454bee31444e68a4b60c Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Tue, 21 Jan 2025 19:43:51 -0600 Subject: [PATCH 25/35] Fix all decap'd heads looking brainless (#89157) ## About The Pull Request Order of operations thing (I think) - `drop_limb` - `update_limb` - It correctly updates the limb `show_debrained = FALSE` - Remove from limb - `death` - `update_body_parts` - `update_limb` - Now the head is still associated with the mob, but the organs are gone, so technically, we have no brain - It updates the limb `show_debrained = TRUE` - `update_owner(null)` - Head is only NOW disassociated with the mob after we've wrongly assumed the mob has no brain - `update_icon_dropped` (with the incorrect values) Moving to after we have been disassociated with the owner entirely seems to fix it, might have knock on effects though. Didn't seem to in (short) testing but yeah Maybe fixes #87971 ## Changelog :cl: Melbert fix: Heads with brains no longer look debrained /:cl: --- code/modules/surgery/bodyparts/dismemberment.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm index 52bc11e3cab27..bd4a5306fa0d5 100644 --- a/code/modules/surgery/bodyparts/dismemberment.dm +++ b/code/modules/surgery/bodyparts/dismemberment.dm @@ -87,7 +87,6 @@ SEND_SIGNAL(owner, COMSIG_CARBON_REMOVE_LIMB, src, special, dismembered) SEND_SIGNAL(src, COMSIG_BODYPART_REMOVED, owner, special, dismembered) - update_limb(dropping_limb = TRUE) bodypart_flags &= ~BODYPART_IMPLANTED //limb is out and about, it can't really be considered an implant owner.remove_bodypart(src, special) @@ -96,6 +95,7 @@ LAZYREMOVE(owner.all_scars, scar) var/mob/living/carbon/phantom_owner = update_owner(null) // so we can still refer to the guy who lost their limb after said limb forgets 'em + update_limb(dropping_limb = TRUE) for(var/datum/wound/wound as anything in wounds) wound.remove_wound(TRUE) From 3169ff920a605ea7bc0a0e6493fb10097ae8b4ba Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 01:44:12 +0000 Subject: [PATCH 26/35] Automatic changelog for PR #89157 [ci skip] --- html/changelogs/AutoChangeLog-pr-89157.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89157.yml diff --git a/html/changelogs/AutoChangeLog-pr-89157.yml b/html/changelogs/AutoChangeLog-pr-89157.yml new file mode 100644 index 0000000000000..b4ab02618c6ac --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89157.yml @@ -0,0 +1,4 @@ +author: "Melbert" +delete-after: True +changes: + - bugfix: "Heads with brains no longer look debrained" \ No newline at end of file From d3f7ff3e7157fd1f1f5ae2f132cc9d98b813001a Mon Sep 17 00:00:00 2001 From: Bloop <13398309+vinylspiders@users.noreply.github.com> Date: Tue, 21 Jan 2025 20:44:43 -0500 Subject: [PATCH 27/35] Fixes a fishy CI failure caused by a hard delete (#89138) ## About The Pull Request Likely caused by a race condition with a `load_trophy_fish()` occurring after the item is deleted somehow. I erred on the side of caution and just made sure we can never get any fish being added to the trophy after its deletion. ![image](https://github.com/user-attachments/assets/1968ee5a-78e8-428e-9421-2416860962bc) ## Why It's Good For The Game Too many spurious CI failures lately ## Changelog N/A --- code/modules/fishing/fish_mount.dm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/code/modules/fishing/fish_mount.dm b/code/modules/fishing/fish_mount.dm index d2334910e2a55..4649f2e9125c2 100644 --- a/code/modules/fishing/fish_mount.dm +++ b/code/modules/fishing/fish_mount.dm @@ -78,7 +78,7 @@ if(fish_path.fish_id_redirect_path) fish_path = fish_path.fish_id_redirect_path var/fluff_name = pick("John Trasen III", "a nameless intern", "Pun Pun", AQUARIUM_COMPANY, "Unknown", "Central Command") - add_fish(new fish_path(src), from_persistence = TRUE, catcher = fluff_name) + add_fish(new fish_path(loc), from_persistence = TRUE, catcher = fluff_name) mounted_fish.randomize_size_and_weight() mounted_fish.set_status(FISH_DEAD) SSpersistence.save_trophy_fish(src) @@ -108,6 +108,11 @@ return ITEM_INTERACT_SUCCESS /obj/structure/fish_mount/proc/add_fish(obj/item/fish/fish, from_persistence = FALSE, catcher) + if(QDELETED(src)) // don't ever try to add a fish to one of these that's already been deleted - and get rid of the one that was created + qdel(fish) + return + if(QDELETED(fish)) // no adding deleted fishies either + return if(mounted_fish) mounted_fish.forceMove(loc) fish.forceMove(src) From 4a1fedf64f3b97cba4b725f5ca415e0dcc3c4cd7 Mon Sep 17 00:00:00 2001 From: Bloop <13398309+vinylspiders@users.noreply.github.com> Date: Tue, 21 Jan 2025 21:03:46 -0500 Subject: [PATCH 28/35] Fixes an UpdatePaths script that was written backwards (#89128) ## About The Pull Request Tin. This script when run would actually undo any instances of the thing and revert it back to the invalid version. I found this out after running it and becoming confused when it seemingly undid their pr. ## Why It's Good For The Game Working scripts for downstreams are nice. I think. ## Changelog N/a --- tools/UpdatePaths/Scripts/88095_repaths_a357_to_c357.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/UpdatePaths/Scripts/88095_repaths_a357_to_c357.txt b/tools/UpdatePaths/Scripts/88095_repaths_a357_to_c357.txt index 28ad97efff1ab..0b6f5a9f39eb9 100644 --- a/tools/UpdatePaths/Scripts/88095_repaths_a357_to_c357.txt +++ b/tools/UpdatePaths/Scripts/88095_repaths_a357_to_c357.txt @@ -1,3 +1,3 @@ #comment Repaths instances of a357 with c357, so as to acknowledge that it is consistent with other casings. -/obj/item/ammo_casing/c357 : /obj/item/ammo_casing/a357{@OLD} +/obj/item/ammo_casing/a357 : /obj/item/ammo_casing/c357{@OLD} From 86e06b1b293f7ee2a67f783806c3c66b7a7220ab Mon Sep 17 00:00:00 2001 From: Bloop <13398309+vinylspiders@users.noreply.github.com> Date: Tue, 21 Jan 2025 21:07:12 -0500 Subject: [PATCH 29/35] Fixes an armrest related hard del (#89139) ## About The Pull Request Another spurious CI runtime that keeps coming up all the time and is annoying me. I believe it's occurring due to the chair not being initialized before a `mob_buckler` mapping helper tries to buckle mobs to it. So I moved their code to lateload to hopefully ensure that doesn't happen, as well as an additional safety measure in the armchair code itself. edit: confirmed that this does indeed fix it, as I have it merged downstream preemptively due to it being such a blocking nuisance ![image](https://github.com/user-attachments/assets/508e3f58-08ee-4e54-98a2-8a655ce85530) Caused by ## Why It's Good For The Game Less CI failures ## Changelog N/A --- code/modules/mapping/mapping_helpers.dm | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers.dm index d04e6e0afd15b..da7d288d161fe 100644 --- a/code/modules/mapping/mapping_helpers.dm +++ b/code/modules/mapping/mapping_helpers.dm @@ -1373,6 +1373,13 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_atoms_ontop) /obj/effect/mapping_helpers/mob_buckler/Initialize(mapload) . = ..() + if(!mapload) + log_mapping("[src] spawned outside of mapload!") + return INITIALIZE_HINT_QDEL + + return INITIALIZE_HINT_LATELOAD + +/obj/effect/mapping_helpers/mob_buckler/LateInitialize() var/atom/movable/buckle_to var/list/mobs = list() for(var/atom/movable/possible_buckle as anything in loc) @@ -1385,12 +1392,13 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_atoms_ontop) if(isnull(buckle_to)) log_mapping("[type] at [x] [y] [z] did not find anything to buckle to") - return INITIALIZE_HINT_QDEL + qdel(src) + return for(var/mob/living/mob as anything in mobs) buckle_to.buckle_mob(mob, force = force_buckle) - return INITIALIZE_HINT_QDEL + qdel(src) ///Basic mob flag helpers for things like deleting on death. /obj/effect/mapping_helpers/basic_mob_flags From 83e179ee21f52b5072a2210185e82ed0f53ecec4 Mon Sep 17 00:00:00 2001 From: Vekter Date: Tue, 21 Jan 2025 23:45:45 -0600 Subject: [PATCH 30/35] Drastically simplifies the roundstart report (#89150) ## About The Pull Request The roundstart report has been changed in the following ways: - There are now only four alert levels: Yellow Star (0-65 Threat), Red Star (66-79 Threat), Black Orbit (80-99 Threat), and Midnight Sun (100 Threat). - The roundstart report is now 100% accurate. - Extended rounds will still show the "No credible threat" alerts, but this should only happen if an admin sets the round to Extended. ## Why It's Good For The Game The current roundstart report system is too granular as it is now, which leads to situations where players will suicide 5-10 minutes into the round due to the threat level being too low. Making it potentially random was meaningless, because players would just act on whatever it said without actually giving the round a chance to do anything. I also feel like this brings back a fair bit of paranoia to the round, as low threat levels would often just result in people expecting nothing to happen. That can be fun when the report is lying, but it doesn't happen often enough to really make it worth keeping. We tested this a few months ago and the results seemed positive. We also had a lot of discussion about the matter and, while I'm open to changing implementation in some ways, I'm pretty set on this being a beneficial change, at least in the short term until we can make Dynamic more interesting. I kept the high threat level stuff because it's fun to know some crazy shit might happen. I might bring back the random threat level thing to differentiate between those but I don't really care tbh; the targeted behavior here is people bailing on low threat rounds, not people knowing it's a high threat round. ## Changelog :cl: Vekter balance: The roundstart report will now display a more broad, less specific message about threat levels when between 0 and 80 threat. /:cl: --- code/controllers/subsystem/dynamic/dynamic.dm | 57 +------------------ .../subsystem/dynamic/dynamic_logging.dm | 1 - 2 files changed, 3 insertions(+), 55 deletions(-) diff --git a/code/controllers/subsystem/dynamic/dynamic.dm b/code/controllers/subsystem/dynamic/dynamic.dm index b56c13308ebe1..c215feedd39d6 100644 --- a/code/controllers/subsystem/dynamic/dynamic.dm +++ b/code/controllers/subsystem/dynamic/dynamic.dm @@ -1,9 +1,3 @@ -#define FAKE_GREENSHIFT_FORM_CHANCE 15 -#define FAKE_REPORT_CHANCE 8 -#define PULSAR_REPORT_CHANCE 8 -#define REPORT_NEG_DIVERGENCE -15 -#define REPORT_POS_DIVERGENCE 15 - // Are HIGH_IMPACT_RULESETs allowed to stack? GLOBAL_VAR_INIT(dynamic_no_stacking, TRUE) // If enabled does not accept or execute any rulesets. @@ -195,10 +189,6 @@ SUBSYSTEM_DEF(dynamic) /// Used for choosing different midround injections. var/list/current_midround_rulesets - /// The amount of threat shown on the piece of paper. - /// Can differ from the actual threat amount. - var/shown_threat - VAR_PRIVATE/next_midround_injection /datum/controller/subsystem/dynamic/proc/admin_panel() @@ -336,7 +326,7 @@ SUBSYSTEM_DEF(dynamic) continue min_threat = min(ruleset.cost, min_threat) - var/greenshift = GLOB.dynamic_forced_extended || (threat_level < min_threat && shown_threat < min_threat) //if both shown and real threat are below any ruleset, its extended time + var/greenshift = GLOB.dynamic_forced_extended || (threat_level < min_threat) //if threat is below any ruleset, its extended time SSstation.generate_station_goals(greenshift ? INFINITY : CONFIG_GET(number/station_goal_budget)) var/list/datum/station_goal/goals = SSstation.get_station_goals() @@ -380,39 +370,10 @@ SUBSYSTEM_DEF(dynamic) /// Generate the advisory level depending on the shown threat level. /datum/controller/subsystem/dynamic/proc/generate_advisory_level() var/advisory_string = "" - if(prob(PULSAR_REPORT_CHANCE)) - for(var/datum/station_trait/our_trait as anything in shuffle(SSstation.station_traits)) - advisory_string += our_trait.get_pulsar_message() - if(length(advisory_string)) - return advisory_string - - advisory_string += "Advisory Level: Pulsar Star
" - advisory_string += "Your sector's advisory level is Pulsar Star. A large, unknown electromagnetic field has stormed through nearby surveillance equipment, causing major data loss. Partial data was recovered and showed no credible threats to Nanotrasen assets within the Spinward Sector; however, the Department of Intelligence advises maintaining high alert against potential threats due to the lack of complete data." - return advisory_string - //a white dwarf shift leads to a green security alert on report and special announcement, this prevents a meta check if the alert report is fake or not. - if(round(shown_threat) == 0 && round(threat_level) == 0) - advisory_string += "Advisory Level: White Dwarf
" - advisory_string += "Your sector's advisory level is White Dwarf. Our surveillance has ruled out any and all potential threats known in our database, eliminating most risks to our assets in the Spinward Sector. We advise a lower level of security, alongside distributing resources on potential profit." - return advisory_string - - switch(round(shown_threat)) - if(0 to 19) - var/show_core_territory = (GLOB.current_living_antags.len > 0) - if (prob(FAKE_GREENSHIFT_FORM_CHANCE)) - show_core_territory = !show_core_territory - - if (show_core_territory) - advisory_string += "Advisory Level: Blue Star
" - advisory_string += "Your sector's advisory level is Blue Star. At this threat advisory, the risk of attacks on Nanotrasen assets within the sector is minor but cannot be ruled out entirely. Remain vigilant." - else - advisory_string += "Advisory Level: Green Star
" - advisory_string += "Your sector's advisory level is Green Star. Surveillance information shows no credible threats to Nanotrasen assets within the Spinward Sector at this time. As always, the Department of Intelligence advises maintaining vigilance against potential threats, regardless of a lack of known threats." - if(20 to 39) + switch(round(threat_level)) + if(0 to 65) advisory_string += "Advisory Level: Yellow Star
" advisory_string += "Your sector's advisory level is Yellow Star. Surveillance shows a credible risk of enemy attack against our assets in the Spinward Sector. We advise a heightened level of security alongside maintaining vigilance against potential threats." - if(40 to 65) - advisory_string += "Advisory Level: Orange Star
" - advisory_string += "Your sector's advisory level is Orange Star. Upon reviewing your sector's intelligence, the Department has determined that the risk of enemy activity is moderate to severe. At this advisory, we recommend maintaining a higher degree of security and reviewing red alert protocols with command and the crew." if(66 to 79) advisory_string += "Advisory Level: Red Star
" advisory_string += "Your sector's advisory level is Red Star. The Department of Intelligence has decrypted Cybersun communications suggesting a high likelihood of attacks on Nanotrasen assets within the Spinward Sector. Stations in the region are advised to remain highly vigilant for signs of enemy activity and to be on high alert." @@ -497,11 +458,6 @@ SUBSYSTEM_DEF(dynamic) ) return TRUE -/datum/controller/subsystem/dynamic/proc/setup_shown_threat() - if (prob(FAKE_REPORT_CHANCE)) - shown_threat = rand(1, 100) - else - shown_threat = clamp(threat_level + rand(REPORT_NEG_DIVERGENCE, REPORT_POS_DIVERGENCE), 0, 100) /datum/controller/subsystem/dynamic/proc/set_cooldowns() var/latejoin_injection_cooldown_middle = 0.5*(latejoin_delay_max + latejoin_delay_min) @@ -523,7 +479,6 @@ SUBSYSTEM_DEF(dynamic) configure_station_trait_costs() setup_parameters() setup_hijacking() - setup_shown_threat() setup_rulesets() //We do this here instead of with the midround rulesets and such because these rules can hang refs @@ -1056,9 +1011,3 @@ SUBSYSTEM_DEF(dynamic) #undef MAXIMUM_DYN_DISTANCE - -#undef FAKE_REPORT_CHANCE -#undef FAKE_GREENSHIFT_FORM_CHANCE -#undef PULSAR_REPORT_CHANCE -#undef REPORT_NEG_DIVERGENCE -#undef REPORT_POS_DIVERGENCE diff --git a/code/controllers/subsystem/dynamic/dynamic_logging.dm b/code/controllers/subsystem/dynamic/dynamic_logging.dm index 16bd56a730316..3e4987ecf7340 100644 --- a/code/controllers/subsystem/dynamic/dynamic_logging.dm +++ b/code/controllers/subsystem/dynamic/dynamic_logging.dm @@ -74,7 +74,6 @@ serialized["threat_level"] = threat_level serialized["round_start_budget"] = initial_round_start_budget serialized["mid_round_budget"] = threat_level - initial_round_start_budget - serialized["shown_threat"] = shown_threat var/list/serialized_snapshots = list() for (var/datum/dynamic_snapshot/snapshot as anything in snapshots) From 163380a7d9ab56eae1754a3e1f253977c95b4d8e Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 05:46:04 +0000 Subject: [PATCH 31/35] Automatic changelog for PR #89150 [ci skip] --- html/changelogs/AutoChangeLog-pr-89150.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89150.yml diff --git a/html/changelogs/AutoChangeLog-pr-89150.yml b/html/changelogs/AutoChangeLog-pr-89150.yml new file mode 100644 index 0000000000000..685f90e5b0f25 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89150.yml @@ -0,0 +1,4 @@ +author: "Vekter" +delete-after: True +changes: + - balance: "The roundstart report will now display a more broad, less specific message about threat levels when between 0 and 80 threat." \ No newline at end of file From 17010c11822c21ff4af94986bfc8dd2e72dd609a Mon Sep 17 00:00:00 2001 From: The Sharkening <95130227+StrangeWeirdKitten@users.noreply.github.com> Date: Wed, 22 Jan 2025 05:11:45 -0500 Subject: [PATCH 32/35] Makes the mech repair droid unstackable + mech armor balance (#88789) ## About The Pull Request alternative to #88776 Makes the repair droid unable to be stacked and reduces armor slots to 1 on station mechs except the phazon. ## Why It's Good For The Game You can get to some pretty heavy duty values on certain mechs, especially the durand, with a very intense rate of healing. This makes those items unstackable. ![image](https://github.com/user-attachments/assets/714c48ca-f9a1-4452-bc25-9d20070f43be) ## Changelog :cl: balance: Reduces armor slots to 1 for all station built mechs except the phazon. balance: melee mech armor has been increased to 20 from 15. balance: mech bullet and laser armor has both been increased to 15 from 10. balance: You can no longer stack the repair droid on mechs. /:cl: --- code/modules/vehicles/mecha/combat/durand.dm | 2 +- code/modules/vehicles/mecha/combat/gygax.dm | 2 +- code/modules/vehicles/mecha/combat/honker.dm | 2 +- code/modules/vehicles/mecha/combat/savannah_ivanov.dm | 2 +- code/modules/vehicles/mecha/equipment/mecha_equipment.dm | 9 +++++++++ .../vehicles/mecha/equipment/tools/other_tools.dm | 7 ++++--- 6 files changed, 17 insertions(+), 7 deletions(-) diff --git a/code/modules/vehicles/mecha/combat/durand.dm b/code/modules/vehicles/mecha/combat/durand.dm index 9095197b93ea0..b9d2ccdb6533e 100644 --- a/code/modules/vehicles/mecha/combat/durand.dm +++ b/code/modules/vehicles/mecha/combat/durand.dm @@ -18,7 +18,7 @@ MECHA_R_ARM = 1, MECHA_UTILITY = 3, MECHA_POWER = 1, - MECHA_ARMOR = 3, + MECHA_ARMOR = 1, ) var/obj/durand_shield/shield diff --git a/code/modules/vehicles/mecha/combat/gygax.dm b/code/modules/vehicles/mecha/combat/gygax.dm index 0acb746c52d4a..638f53d9aaecf 100644 --- a/code/modules/vehicles/mecha/combat/gygax.dm +++ b/code/modules/vehicles/mecha/combat/gygax.dm @@ -18,7 +18,7 @@ MECHA_R_ARM = 1, MECHA_UTILITY = 3, MECHA_POWER = 1, - MECHA_ARMOR = 2, + MECHA_ARMOR = 1, ) step_energy_drain = 4 can_use_overclock = TRUE diff --git a/code/modules/vehicles/mecha/combat/honker.dm b/code/modules/vehicles/mecha/combat/honker.dm index 39c5ef1d0e8c4..2a3da129ccd4d 100644 --- a/code/modules/vehicles/mecha/combat/honker.dm +++ b/code/modules/vehicles/mecha/combat/honker.dm @@ -57,7 +57,7 @@ MECHA_R_ARM = 1, MECHA_UTILITY = 3, MECHA_POWER = 1, - MECHA_ARMOR = 3, + MECHA_ARMOR = 2, ) /obj/vehicle/sealed/mecha/honker/dark/loaded diff --git a/code/modules/vehicles/mecha/combat/savannah_ivanov.dm b/code/modules/vehicles/mecha/combat/savannah_ivanov.dm index ffc4c61e5a87f..60dad9de64ab5 100644 --- a/code/modules/vehicles/mecha/combat/savannah_ivanov.dm +++ b/code/modules/vehicles/mecha/combat/savannah_ivanov.dm @@ -35,7 +35,7 @@ MECHA_R_ARM = 1, MECHA_UTILITY = 3, MECHA_POWER = 1, - MECHA_ARMOR = 3, + MECHA_ARMOR = 1, ) //no tax on flying, since the power cost is in the leap itself. phasing_energy_drain = 0 diff --git a/code/modules/vehicles/mecha/equipment/mecha_equipment.dm b/code/modules/vehicles/mecha/equipment/mecha_equipment.dm index 2ad10ae028d17..092c8c1044889 100644 --- a/code/modules/vehicles/mecha/equipment/mecha_equipment.dm +++ b/code/modules/vehicles/mecha/equipment/mecha_equipment.dm @@ -18,6 +18,8 @@ var/can_be_triggered = FALSE ///Whether the module is currently active var/active = TRUE + ///Can we stack multiple types of the same item? + var/unstackable = FALSE ///Label used in the ui next to the Activate/Enable/Disable buttons var/active_label = "Status" ///Chassis power cell quantity used on activation @@ -157,6 +159,13 @@ to_chat(user, span_warning("\The [mech]'s left arm is full![mech.equip_by_category[MECHA_R_ARM] || !mech.max_equip_by_category[MECHA_R_ARM] ? "" : " Try right arm!"]")) return FALSE return TRUE + if(unstackable) + var/list/obj/item/mecha_parts/mecha_equipment/contents = mech.equip_by_category[equipment_slot] + for(var/obj/equipment as anything in contents) + if(src.type == equipment.type) + to_chat(user, span_warning("You can't stack more of this item ontop itself!")) + return FALSE + if(length(mech.equip_by_category[equipment_slot]) == mech.max_equip_by_category[equipment_slot]) to_chat(user, span_warning("This equipment slot is already full!")) return FALSE diff --git a/code/modules/vehicles/mecha/equipment/tools/other_tools.dm b/code/modules/vehicles/mecha/equipment/tools/other_tools.dm index 613f82fe85981..a0a1e7443acbb 100644 --- a/code/modules/vehicles/mecha/equipment/tools/other_tools.dm +++ b/code/modules/vehicles/mecha/equipment/tools/other_tools.dm @@ -173,7 +173,7 @@ armor_mod = /datum/armor/mecha_equipment_ccw_boost /datum/armor/mecha_equipment_ccw_boost - melee = 15 + melee = 20 /obj/item/mecha_parts/mecha_equipment/armor/antiproj_armor_booster name = "Projectile Shielding" @@ -184,8 +184,8 @@ armor_mod = /datum/armor/mecha_equipment_ranged_boost /datum/armor/mecha_equipment_ranged_boost - bullet = 10 - laser = 10 + bullet = 15 + laser = 15 ////////////////////////////////// REPAIR DROID ////////////////////////////////////////////////// @@ -196,6 +196,7 @@ icon_state = "repair_droid" energy_drain = 50 range = 0 + unstackable = TRUE can_be_toggled = TRUE active = FALSE equipment_slot = MECHA_UTILITY From fdb81afcaa41e7c4dece7dcaf304a02803246db5 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 10:17:28 +0000 Subject: [PATCH 33/35] Automatic changelog for PR #88789 [ci skip] --- html/changelogs/AutoChangeLog-pr-88789.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-88789.yml diff --git a/html/changelogs/AutoChangeLog-pr-88789.yml b/html/changelogs/AutoChangeLog-pr-88789.yml new file mode 100644 index 0000000000000..10f5e68880cc7 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88789.yml @@ -0,0 +1,7 @@ +author: "StrangeWeirdKitten" +delete-after: True +changes: + - balance: "Reduces armor slots to 1 for all station built mechs except the phazon." + - balance: "melee mech armor has been increased to 20 from 15." + - balance: "mech bullet and laser armor has both been increased to 15 from 10." + - balance: "You can no longer stack the repair droid on mechs." \ No newline at end of file From 29869bbcc4a077c9498a4f1d7dd753acb24e0436 Mon Sep 17 00:00:00 2001 From: Ghom <42542238+Ghommie@users.noreply.github.com> Date: Wed, 22 Jan 2025 11:28:49 +0100 Subject: [PATCH 34/35] Makes chasms not spawn things when explosions happen again. (#89132) --- code/modules/fishing/sources/source_types.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/fishing/sources/source_types.dm b/code/modules/fishing/sources/source_types.dm index af975bb4ccdb4..02df0ff9e7c0c 100644 --- a/code/modules/fishing/sources/source_types.dm +++ b/code/modules/fishing/sources/source_types.dm @@ -159,7 +159,6 @@ radial_name = "Chasm" overlay_state = "portal_chasm" radial_state = "ground_hole" - fish_source_flags = FISH_SOURCE_FLAG_EXPLOSIVE_NONE /datum/fish_source/portal/ocean fish_table = list( @@ -327,6 +326,7 @@ /datum/chasm_detritus = 30, ) fishing_difficulty = FISHING_DEFAULT_DIFFICULTY + 15 + fish_source_flags = FISH_SOURCE_FLAG_EXPLOSIVE_NONE /datum/fish_source/chasm/on_start_fishing(obj/item/fishing_rod/rod, mob/fisherman, atom/parent) . = ..() From f032bb1d4d982d4ee57c214c18238aaddb45d512 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 10:47:50 +0000 Subject: [PATCH 35/35] Automatic changelog for PR #89132 [ci skip] --- html/changelogs/AutoChangeLog-pr-89132.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89132.yml diff --git a/html/changelogs/AutoChangeLog-pr-89132.yml b/html/changelogs/AutoChangeLog-pr-89132.yml new file mode 100644 index 0000000000000..693684c833982 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89132.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Chasms are once again incompatible with explosive fishing." \ No newline at end of file