From 85c030b3e282d57a5d819613be91ca09fb9a2b0b Mon Sep 17 00:00:00 2001 From: _0Steven <42909981+00-Steven@users.noreply.github.com> Date: Thu, 4 Apr 2024 04:35:37 +0200 Subject: [PATCH 001/938] Fix all nighter runtimes (#82405) ## About The Pull Request So, recently, someone asked me why their All Nighter eyebags weren't working, and though after a short conversation we worked out it was working as intended and they had just taken a few naps to train fitness, I still checked the round logs once they were public. https://scrubby.melonmesa.com/round/226476/runtimes ![image](https://github.com/tgstation/tgstation/assets/42909981/162d76ae-2d43-428b-bc7e-37371ba27a1c) Coincidentally! Someone else _did_ have an All Nighter runtime! Well. Time to fix it. I look into the code, and lo and behold, it seems we're really just not caring about whether the head actually exists. https://github.com/tgstation/tgstation/blob/d38f9385b863e49f83455a227764d302629e2867/code/datums/quirks/negative_quirks/all_nighter.dm#L50-L56 But that reminds me. We have more ways to lose your head, like H.A.R.S.... So... I boot the game, and... Oh no. _Oh no._ That's a _lot_ of runtimes huh. (See "Why It's Good For The Game") Soooo we just add a check for whether our head-in-question actually exists to both adding and removing our bags, and be done with it. ```dm ///adds the bag overlay /datum/quirk/all_nighter/proc/add_bags() var/mob/living/carbon/human/sleepy_head = quirk_holder var/obj/item/bodypart/head/face = sleepy_head?.get_bodypart(BODY_ZONE_HEAD) if(isnull(face)) return bodypart_overlay = new() //creates our overlay face.add_bodypart_overlay(bodypart_overlay) sleepy_head.update_body_parts() //make sure to update icon ///removes the bag overlay /datum/quirk/all_nighter/proc/remove_bags() var/mob/living/carbon/human/sleepy_head = quirk_holder var/obj/item/bodypart/head/face = sleepy_head?.get_bodypart(BODY_ZONE_HEAD) if(face) //our overlay is stored as a datum var, so referencing it is easy face.remove_bodypart_overlay(bodypart_overlay) sleepy_head.update_body_parts() QDEL_NULL(bodypart_overlay) ``` Right? Well, no. Yes, this stops the runtimes, but while testing this I also noticed that the bags don't come back. We lose our head, we regenerate a new one, and we don't have bags. Even though we removed our head, we never actually removed _our bags_. So our `bodypart_overlay` is never set to null, and it's never actually attempting to apply them to our new head. To resolve this, we then just add a new proc called on `COMSIG_CARBON_REMOVE_LIMB`, which handles removing the eyebags before we remove our head if needed. ```dm ///if we have bags and lost a head, remove them /datum/quirk/all_nighter/proc/on_removed_limb(datum/source, obj/item/bodypart/removed_limb, special, dismembered) if(bodypart_overlay && istype(removed_limb, /obj/item/bodypart/head)) remove_bags() ``` Oh, we also remove the unused `client/client_source` argument from both the `add_bags(...)` and `remove_bags(...)` procs. ## Why It's Good For The Game ![image](https://github.com/tgstation/tgstation/assets/42909981/31fd97b5-dce3-46ec-9388-abf568fe4f0b) ## Changelog :cl: fix: All Nighter: fixed a runtime from not having a head, whether from hars/deletion/somesuch. fix: All Nighter: losing and regaining your head while you had eyebags no longer removes your eyebags until you've slept. /:cl: --- .../quirks/negative_quirks/all_nighter.dm | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/code/datums/quirks/negative_quirks/all_nighter.dm b/code/datums/quirks/negative_quirks/all_nighter.dm index 0062537fde8ff..7f9f051ecf75a 100644 --- a/code/datums/quirks/negative_quirks/all_nighter.dm +++ b/code/datums/quirks/negative_quirks/all_nighter.dm @@ -30,30 +30,40 @@ ///adds the corresponding moodlet and visual effects /datum/quirk/all_nighter/add(client/client_source) + RegisterSignal(quirk_holder, COMSIG_CARBON_REMOVE_LIMB, PROC_REF(on_removed_limb)) quirk_holder.add_mood_event("all_nighter", /datum/mood_event/all_nighter) add_bags() ///removes the corresponding moodlet and visual effects /datum/quirk/all_nighter/remove(client/client_source) + UnregisterSignal(quirk_holder, COMSIG_CARBON_REMOVE_LIMB) quirk_holder.clear_mood_event("all_nighter", /datum/mood_event/all_nighter) - remove_bags() + if(bodypart_overlay) + remove_bags() + +///if we have bags and lost a head, remove them +/datum/quirk/all_nighter/proc/on_removed_limb(datum/source, obj/item/bodypart/removed_limb, special, dismembered) + if(bodypart_overlay && istype(removed_limb, /obj/item/bodypart/head)) + remove_bags() ///adds the bag overlay -/datum/quirk/all_nighter/proc/add_bags(client/client_source) +/datum/quirk/all_nighter/proc/add_bags() var/mob/living/carbon/human/sleepy_head = quirk_holder - var/obj/item/bodypart/head/face = sleepy_head.get_bodypart(BODY_ZONE_HEAD) + var/obj/item/bodypart/head/face = sleepy_head?.get_bodypart(BODY_ZONE_HEAD) + if(isnull(face)) + return bodypart_overlay = new() //creates our overlay face.add_bodypart_overlay(bodypart_overlay) sleepy_head.update_body_parts() //make sure to update icon ///removes the bag overlay -/datum/quirk/all_nighter/proc/remove_bags(client/client_source) +/datum/quirk/all_nighter/proc/remove_bags() var/mob/living/carbon/human/sleepy_head = quirk_holder - var/obj/item/bodypart/head/face = sleepy_head.get_bodypart(BODY_ZONE_HEAD) - //our overlay is stored as a datum var, so referencing it is easy - face.remove_bodypart_overlay(bodypart_overlay) + var/obj/item/bodypart/head/face = sleepy_head?.get_bodypart(BODY_ZONE_HEAD) + if(face) + face.remove_bodypart_overlay(bodypart_overlay) + sleepy_head.update_body_parts() QDEL_NULL(bodypart_overlay) - sleepy_head.update_body_parts() /** *Here we actively handle our moodlet & eye bags, adding/removing them as necessary From a02dc8221c5bf4b5e25e9549a99a299df30b4fa2 Mon Sep 17 00:00:00 2001 From: DATAxPUNGED <44149906+DATA-xPUNGED@users.noreply.github.com> Date: Wed, 3 Apr 2024 23:36:28 -0300 Subject: [PATCH 002/938] [NO GBP] Fixes Alcoholic quirk selection and addiction in general not being forever. (#82403) ## About The Pull Request Fixes #82346 Also fixes a bug where Junkie, Smoker, and Alcoholic would not give you more addiction once yours ran out. ## Changelog :cl: fix: Fixes Alcoholic quirk selection fix: Fixes Junkie, Smoker, and Alcoholic not giving you more addiction when you come clean. /:cl: --- code/_globalvars/lists/quirks.dm | 12 ++++++------ code/datums/quirks/negative_quirks/addict.dm | 8 ++++---- .../client/preferences/{junkie.dm => addict.dm} | 0 .../reagents/reagent_containers/cups/glassbottle.dm | 2 +- tgstation.dme | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) rename code/modules/client/preferences/{junkie.dm => addict.dm} (100%) diff --git a/code/_globalvars/lists/quirks.dm b/code/_globalvars/lists/quirks.dm index 085eaaa510788..d40a3b1366b41 100644 --- a/code/_globalvars/lists/quirks.dm +++ b/code/_globalvars/lists/quirks.dm @@ -12,10 +12,10 @@ GLOBAL_LIST_INIT(nearsighted_glasses, list( ///Options for the prosthetic limb quirk to choose from GLOBAL_LIST_INIT(limb_choice, list( - "Left arm" = /obj/item/bodypart/arm/left/robot/surplus, - "Right arm" = /obj/item/bodypart/arm/right/robot/surplus, - "Left leg" = /obj/item/bodypart/leg/left/robot/surplus, - "Right leg" = /obj/item/bodypart/leg/right/robot/surplus, + "Left Arm" = /obj/item/bodypart/arm/left/robot/surplus, + "Right Arm" = /obj/item/bodypart/arm/right/robot/surplus, + "Left Leg" = /obj/item/bodypart/leg/left/robot/surplus, + "Right Leg" = /obj/item/bodypart/leg/right/robot/surplus, )) ///Transhumanist quirk @@ -54,7 +54,7 @@ GLOBAL_LIST_INIT(possible_smoker_addictions, setup_junkie_addictions(list( ))) ///Options for the Alcoholic quirk to choose from -GLOBAL_LIST_INIT(possible_alcoholic_addictions, setup_junkie_addictions(list( +GLOBAL_LIST_INIT(possible_alcoholic_addictions, list( "Beekhof Blauw Curaçao" = list("bottlepath" = /obj/item/reagent_containers/cup/glass/bottle/curacao, "reagent" = /datum/reagent/consumable/ethanol/curacao), "Buckin' Bronco's Applejack" = list("bottlepath" = /obj/item/reagent_containers/cup/glass/bottle/applejack, "reagent" = /datum/reagent/consumable/ethanol/applejack), "Voltaic Yellow Wine" = list("bottlepath" = /obj/item/reagent_containers/cup/glass/bottle/wine_voltaic, "reagent" = /datum/reagent/consumable/ethanol/wine_voltaic), @@ -79,7 +79,7 @@ GLOBAL_LIST_INIT(possible_alcoholic_addictions, setup_junkie_addictions(list( "Breezy Shoals Coconut Rum" = list("bottlepath" = /obj/item/reagent_containers/cup/glass/bottle/coconut_rum, "reagent" = /datum/reagent/consumable/ethanol/coconut_rum), "Moonlabor Yūyake" = list("bottlepath" = /obj/item/reagent_containers/cup/glass/bottle/yuyake, "reagent" = /datum/reagent/consumable/ethanol/yuyake), "Shu-Kouba Straight Shochu" = list("bottlepath" = /obj/item/reagent_containers/cup/glass/bottle/shochu, "reagent" = /datum/reagent/consumable/ethanol/shochu) -))) +)) ///Options for Prosthetic Organ GLOBAL_LIST_INIT(organ_choice, list( diff --git a/code/datums/quirks/negative_quirks/addict.dm b/code/datums/quirks/negative_quirks/addict.dm index 46c1edd5cb652..f97dae32c260f 100644 --- a/code/datums/quirks/negative_quirks/addict.dm +++ b/code/datums/quirks/negative_quirks/addict.dm @@ -194,13 +194,16 @@ customization_options = list(/datum/preference/choiced/alcoholic) /datum/quirk/item_quirk/addict/alcoholic/New() - drug_container_type = GLOB.possible_alcoholic_addictions[pick(GLOB.possible_alcoholic_addictions["bottlepath"])] + var/random_alcohol = pick(GLOB.possible_alcoholic_addictions) + drug_container_type = GLOB.possible_alcoholic_addictions[random_alcohol]["bottlepath"] + favorite_alcohol = GLOB.possible_alcoholic_addictions[random_alcohol]["reagent"] return ..() /datum/quirk/item_quirk/addict/alcoholic/add_unique(client/client_source) var/addiction = client_source?.prefs.read_preference(/datum/preference/choiced/alcoholic) if(addiction && (addiction != "Random")) drug_container_type = GLOB.possible_alcoholic_addictions[addiction]["bottlepath"] + favorite_alcohol = GLOB.possible_alcoholic_addictions[addiction]["reagent"] return ..() /datum/quirk/item_quirk/addict/alcoholic/post_add() @@ -210,10 +213,7 @@ if(isnull(brandy_container)) stack_trace("Alcoholic quirk added while the GLOB.alcohol_containers is (somehow) not initialized!") brandy_container = new drug_container_type - favorite_alcohol = brandy_container["reagent"] qdel(brandy_container) - else - favorite_alcohol = brandy_container["reagent"] quirk_holder.add_mob_memory(/datum/memory/key/quirk_alcoholic, protagonist = quirk_holder, preferred_brandy = initial(favorite_alcohol.name)) // alcoholic livers have 25% less health and healing diff --git a/code/modules/client/preferences/junkie.dm b/code/modules/client/preferences/addict.dm similarity index 100% rename from code/modules/client/preferences/junkie.dm rename to code/modules/client/preferences/addict.dm diff --git a/code/modules/reagents/reagent_containers/cups/glassbottle.dm b/code/modules/reagents/reagent_containers/cups/glassbottle.dm index a69810ca95447..4f7abbe6f20bd 100644 --- a/code/modules/reagents/reagent_containers/cups/glassbottle.dm +++ b/code/modules/reagents/reagent_containers/cups/glassbottle.dm @@ -406,7 +406,7 @@ return "[year] [origin] [type]" /obj/item/reagent_containers/cup/glass/bottle/absinthe - name = "extra-strong absinthe" + name = "Extra-strong absinthe" desc = "A strong alcoholic drink brewed and distributed by" icon_state = "absinthebottle" list_reagents = list(/datum/reagent/consumable/ethanol/absinthe = 100) diff --git a/tgstation.dme b/tgstation.dme index f7ec13785814b..3a67046d8ac95 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -3608,6 +3608,7 @@ #include "code\modules\client\preferences_menu.dm" #include "code\modules\client\preferences_savefile.dm" #include "code\modules\client\preferences\_preference.dm" +#include "code\modules\client\preferences\addict.dm" #include "code\modules\client\preferences\admin.dm" #include "code\modules\client\preferences\age.dm" #include "code\modules\client\preferences\ai_core_display.dm" @@ -3631,7 +3632,6 @@ #include "code\modules\client\preferences\hotkeys.dm" #include "code\modules\client\preferences\item_outlines.dm" #include "code\modules\client\preferences\jobless_role.dm" -#include "code\modules\client\preferences\junkie.dm" #include "code\modules\client\preferences\language.dm" #include "code\modules\client\preferences\mod_select.dm" #include "code\modules\client\preferences\multiz_parallax.dm" From 692278982d978bca3c356812ce8ab4e59d783f8d Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 4 Apr 2024 15:36:48 +1300 Subject: [PATCH 003/938] Automatic changelog for PR #82405 [ci skip] --- html/changelogs/AutoChangeLog-pr-82405.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82405.yml diff --git a/html/changelogs/AutoChangeLog-pr-82405.yml b/html/changelogs/AutoChangeLog-pr-82405.yml new file mode 100644 index 0000000000000..eda714363bd57 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82405.yml @@ -0,0 +1,5 @@ +author: "00-Steven" +delete-after: True +changes: + - bugfix: "All Nighter: fixed a runtime from not having a head, whether from hars/deletion/somesuch." + - bugfix: "All Nighter: losing and regaining your head while you had eyebags no longer removes your eyebags until you've slept." \ No newline at end of file From 62dcda9847d9c42035df351da634823c815bcdf2 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 4 Apr 2024 15:37:14 +1300 Subject: [PATCH 004/938] Automatic changelog for PR #82403 [ci skip] --- html/changelogs/AutoChangeLog-pr-82403.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82403.yml diff --git a/html/changelogs/AutoChangeLog-pr-82403.yml b/html/changelogs/AutoChangeLog-pr-82403.yml new file mode 100644 index 0000000000000..b1ec4526c63dc --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82403.yml @@ -0,0 +1,5 @@ +author: "DATA-xPUNGED" +delete-after: True +changes: + - bugfix: "Fixes Alcoholic quirk selection" + - bugfix: "Fixes Junkie, Smoker, and Alcoholic not giving you more addiction when you come clean." \ No newline at end of file From 874e1b3667ca7738a3ce883ba7d0d54d6f7d4740 Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Wed, 3 Apr 2024 21:38:23 -0500 Subject: [PATCH 005/938] Adds a visual effect to breathing in cold environments (#82336) ## About The Pull Request Humans (who breathe) (with lungs) now has a particle associated when breathing in cold air. The colder the air, the more likely the particle to occur per breath. https://github.com/tgstation/tgstation/assets/51863163/f375dd1b-87f6-4124-9329-4714fe988c16 Other changes: - Adjusts the probability of getting "your lungs feel cold/hot" when breathing cold/hot air depending on how cold/hot the air is. - Very cold air now has a chance of causing humans to shiver when they breathe it in. ## Why It's Good For The Game Some nice VFX to breathe some style into the game. ## Changelog :cl: Melbert qol: Breathing cold air now has a particle effect associated, careful not to let your glasses fog up. qol: Breathing cold air will now occasionally make your spaceman shiver. Brrr. /:cl: --- code/game/objects/effects/particles/smoke.dm | 13 ++++ .../surgery/organs/internal/lungs/_lungs.dm | 70 ++++++++++++++++-- icons/effects/particles/smoke.dmi | Bin 480 -> 1274 bytes 3 files changed, 75 insertions(+), 8 deletions(-) diff --git a/code/game/objects/effects/particles/smoke.dm b/code/game/objects/effects/particles/smoke.dm index 4f31ffc086998..b41b4eb1d96c9 100644 --- a/code/game/objects/effects/particles/smoke.dm +++ b/code/game/objects/effects/particles/smoke.dm @@ -46,3 +46,16 @@ fadein = 0.7 SECONDS position = generator(GEN_VECTOR, list(-3, 5, 0), list(3, 6.5, 0), NORMAL_RAND) velocity = generator(GEN_VECTOR, list(-0.1, 0.4, 0), list(0.1, 0.5, 0), NORMAL_RAND) + +/particles/fog + icon = 'icons/effects/particles/smoke.dmi' + icon_state = list("chill_1" = 2, "chill_2" = 2, "chill_3" = 1) + +/particles/fog/breath + count = 1 + spawning = 1 + lifespan = 1 SECONDS + fade = 0.5 SECONDS + grow = 0.05 + spin = 2 + color = "#fcffff77" diff --git a/code/modules/surgery/organs/internal/lungs/_lungs.dm b/code/modules/surgery/organs/internal/lungs/_lungs.dm index 1db1963e8d665..8bba59d79874f 100644 --- a/code/modules/surgery/organs/internal/lungs/_lungs.dm +++ b/code/modules/surgery/organs/internal/lungs/_lungs.dm @@ -754,31 +754,85 @@ if(!HAS_TRAIT(breather, TRAIT_RESISTCOLD)) // COLD DAMAGE var/cold_modifier = breather.dna.species.coldmod + var/breath_effect_prob = 0 if(breath_temperature < cold_level_3_threshold) - breather.apply_damage(cold_level_3_damage*cold_modifier, cold_damage_type, spread_damage = TRUE) + breather.apply_damage(cold_level_3_damage * cold_modifier, cold_damage_type, spread_damage = TRUE) + breath_effect_prob = 100 if(breath_temperature > cold_level_3_threshold && breath_temperature < cold_level_2_threshold) - breather.apply_damage(cold_level_2_damage*cold_modifier, cold_damage_type, spread_damage = TRUE) + breather.apply_damage(cold_level_2_damage * cold_modifier, cold_damage_type, spread_damage = TRUE) + breath_effect_prob = 50 if(breath_temperature > cold_level_2_threshold && breath_temperature < cold_level_1_threshold) - breather.apply_damage(cold_level_1_damage*cold_modifier, cold_damage_type, spread_damage = TRUE) + breather.apply_damage(cold_level_1_damage * cold_modifier, cold_damage_type, spread_damage = TRUE) + breath_effect_prob = 25 if(breath_temperature < cold_level_1_threshold) - if(prob(20)) + if(prob(sqrt(breath_effect_prob) * 4)) to_chat(breather, span_warning("You feel [cold_message] in your [name]!")) + if(prob(50)) + breather.emote("shiver") + if(prob(breath_effect_prob)) + // Breathing into your mask, no particle. We can add fogged up glasses later + if(breather.is_mouth_covered()) + return + // Even though breathing via internals TECHNICALLY exhales into the environment, we'll still block it + if(breather.internal || breather.external) + return + emit_breath_particle(breather, /particles/fog/breath) if(!HAS_TRAIT(breather, TRAIT_RESISTHEAT)) // HEAT DAMAGE var/heat_modifier = breather.dna.species.heatmod + var/heat_message_prob = 0 if(breath_temperature > heat_level_1_threshold && breath_temperature < heat_level_2_threshold) - breather.apply_damage(heat_level_1_damage*heat_modifier, heat_damage_type, spread_damage = TRUE) + breather.apply_damage(heat_level_1_damage * heat_modifier, heat_damage_type, spread_damage = TRUE) + heat_message_prob = 100 if(breath_temperature > heat_level_2_threshold && breath_temperature < heat_level_3_threshold) - breather.apply_damage(heat_level_2_damage*heat_modifier, heat_damage_type, spread_damage = TRUE) + breather.apply_damage(heat_level_2_damage * heat_modifier, heat_damage_type, spread_damage = TRUE) + heat_message_prob = 50 if(breath_temperature > heat_level_3_threshold) - breather.apply_damage(heat_level_3_damage*heat_modifier, heat_damage_type, spread_damage = TRUE) + breather.apply_damage(heat_level_3_damage * heat_modifier, heat_damage_type, spread_damage = TRUE) + heat_message_prob = 25 if(breath_temperature > heat_level_1_threshold) - if(prob(20)) + if(prob(sqrt(heat_message_prob) * 4)) to_chat(breather, span_warning("You feel [hot_message] in your [name]!")) // The air you breathe out should match your body temperature breath.temperature = breather.bodytemperature +/// Creates a particle effect off the mouth of the passed mob. +/obj/item/organ/internal/lungs/proc/emit_breath_particle(mob/living/carbon/human/breather, particle_type) + ASSERT(ispath(particle_type, /particles)) + + var/obj/effect/abstract/particle_holder/holder = new(breather, particle_type) + var/particles/breath_particle = holder.particles + var/breath_dir = breather.dir + + var/list/particle_grav = list(0, 0.1, 0) + var/list/particle_pos = list(0, breather.get_mob_height() + 2, 0) + if(breath_dir & NORTH) + particle_grav[2] = 0.2 + breath_particle.rotation = pick(-45, 45) + // Layer it behind the mob since we're facing away from the camera + holder.pixel_w -= 4 + holder.pixel_y += 4 + if(breath_dir & WEST) + particle_grav[1] = -0.2 + particle_pos[1] = -5 + breath_particle.rotation = -45 + if(breath_dir & EAST) + particle_grav[1] = 0.2 + particle_pos[1] = 5 + breath_particle.rotation = 45 + if(breath_dir & SOUTH) + particle_grav[2] = 0.2 + breath_particle.rotation = pick(-45, 45) + // Shouldn't be necessary but just for parity + holder.pixel_w += 4 + holder.pixel_y -= 4 + + breath_particle.gravity = particle_grav + breath_particle.position = particle_pos + + QDEL_IN(holder, breath_particle.lifespan) + /obj/item/organ/internal/lungs/on_life(seconds_per_tick, times_fired) . = ..() if(failed && !(organ_flags & ORGAN_FAILING)) diff --git a/icons/effects/particles/smoke.dmi b/icons/effects/particles/smoke.dmi index 4a3239499b965b8b35f854eb90d216983f5e78f2..99123beeb59a98ff228d7857a35e2cc07c803d11 100644 GIT binary patch literal 1274 zcmeAS@N?(olHy`uVBq!ia0vp^4M3d0!3HF+R#kZdsYO*G5hX6E#mPmP1tppJc?=8{ zb9&DjavgFIXnk1qUBvlPw`b1wi7Ypjb~f>(m56O-Gir{zpJeT5bhrA$;qb$iJC1Pv zGW=zpJL#G@i-m08z1mA_co=tGvtITkLDyYms)B=RW$mS{EBDO4tR}GF-onme|UzAjU`OBhgr(aQ0*Tp zpIYzRzUIOUSNl5~J!BOV-yDyXa+2DomL~k_!k)8BH+-2><@ceo?s9JX?|t9*>@R-z zbkg^dr1W(5rs>feg#`*HGCc8MC{kgt6l##+bm(JIaA%sJ%y^`FF&Ig4-K{ffV45kU0|%j>_%F+BM9X0NwV zPt#@wv)?%aZ;CnElK z1q@~%UjMdg!wl2OfmUfUmsEsu2A^X08!NV0k1Du6X4a0Czz;k+;Z7#?Tz zryY-Mh}m~x^RgqYKX*Q0-S8;7yM*~g>$!*ZH{=h#6ie9qlKXRU#lJTz!|QkX*JSsa zZ8|&YztnBz1)J&`&juNv`o|J~Uv$rR_kt+KvhUv}>Nc!p0XqEj%Q=}Q(cvl_uHQd! z*zd1D{BgcfTuEB<_T~B0W*rdwP_**@-N|o-mls#sGDk2n?3eo*c=FgL8N1qlLOT04 z?%Bju^5{)}!S-u%GW%bgv6_GU=X!?OrSt9TIiqS8+~?lEd%Jx{_R;dU6U!I=didAn z`v;9%_ZUuVuV!dCzW;p%=ZiaXcECWh{BixMfO4JBv90z^-`Ex0^_!qc21kexCH(lR zw8UoHCN&);s>oWrl5KV}4mhv1**w>PJ-E1Jx0ei!w8fwbzr*zKj6yZf4h zvm=&9z0RFB%OYNjnL%y)t!A;86MQFicXu~;ue<)*&p1J5qx13ePr0+NP34XGC;IV{ zPvH`qIpGbvx0(S}YuNv4{Jhji>$Uj0R~+6l-%`X3p;BwYEEfSz@ib z+>7(aB#v&c&PywwvcU32*JcCz=Tn=*t1Gs-+q!*BPIm23OfcK$&v#3{L1r(95^|=) d7F2&&-A|wC|9+xj5wI|0@O1TaS?83{1OOfFDZ*Bkpc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5fFwryM;w;ZhDainGjE%TB zGg33tGfE(w;*!LYR3KBSI5$5#HQrE(i!&v&s2C_>$i` ziMhns3sy&jy;XV9i(+p8ye)S3FWG`2A^e}a%iZ}C zf?>Xk)GJ0&qt?v^4P(HN4g<0=1s1lhno89aprv!9P-8$jGN6scf Date: Thu, 4 Apr 2024 15:46:15 +1300 Subject: [PATCH 006/938] Automatic changelog for PR #82336 [ci skip] --- html/changelogs/AutoChangeLog-pr-82336.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82336.yml diff --git a/html/changelogs/AutoChangeLog-pr-82336.yml b/html/changelogs/AutoChangeLog-pr-82336.yml new file mode 100644 index 0000000000000..4857c219793e6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82336.yml @@ -0,0 +1,5 @@ +author: "Melbert" +delete-after: True +changes: + - qol: "Breathing cold air now has a particle effect associated, careful not to let your glasses fog up." + - qol: "Breathing cold air will now occasionally make your spaceman shiver. Brrr." \ No newline at end of file From 099763d823f1e2a28b932dfc85d0ec4ba553b491 Mon Sep 17 00:00:00 2001 From: nikothedude <59709059+nikothedude@users.noreply.github.com> Date: Thu, 4 Apr 2024 06:53:59 -0400 Subject: [PATCH 007/938] Fixes root beer rounding down to 0 delay for laser carbines/disabler SMGs (#82414) ## About The Pull Request Title. Closes https://github.com/tgstation/tgstation/issues/80921. Uses SSprojectiles wait, via lemon's suggestion (https://discord.com/channels/326822144233439242/326831214667235328/1195468576514130010) ## Why It's Good For The Game bug bad ## Changelog :cl: fix: Root beer no longer causes laser carbines and disabler smgs to fire infinitely fast. /:cl: --- code/datums/components/fullauto.dm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/datums/components/fullauto.dm b/code/datums/components/fullauto.dm index 8663de5adc691..d8484dc3a110b 100644 --- a/code/datums/components/fullauto.dm +++ b/code/datums/components/fullauto.dm @@ -9,11 +9,11 @@ var/autofire_stat = AUTOFIRE_STAT_IDLE var/mouse_parameters /// Time between individual shots. - var/autofire_shot_delay = 0.3 SECONDS + var/autofire_shot_delay = 0.3 SECONDS /// This seems hacky but there can be two MouseDown() without a MouseUp() in between if the user holds click and uses alt+tab, printscreen or similar. - var/mouse_status = AUTOFIRE_MOUSEUP + var/mouse_status = AUTOFIRE_MOUSEUP /// Should dual wielding be allowed? - var/allow_akimbo + var/allow_akimbo ///windup autofire vars ///Whether the delay between shots increases over time, simulating a spooling weapon @@ -259,7 +259,7 @@ current_windup_reduction = (current_windup_reduction + round(autofire_shot_delay * windup_autofire_reduction_multiplier)) timerid = addtimer(CALLBACK(src, PROC_REF(windup_reset), FALSE), windup_spindown, TIMER_UNIQUE|TIMER_OVERRIDE|TIMER_STOPPABLE) if(HAS_TRAIT(shooter, TRAIT_DOUBLE_TAP)) - next_delay = round(next_delay * 0.5) + next_delay = round(next_delay * 0.5, SSprojectiles.wait) COOLDOWN_START(src, next_shot_cd, next_delay) if(SEND_SIGNAL(parent, COMSIG_AUTOFIRE_SHOT, target, shooter, allow_akimbo, mouse_parameters) & COMPONENT_AUTOFIRE_SHOT_SUCCESS) return TRUE From 372286a53eaa7a297c241517f7e87b16ad74236d Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 4 Apr 2024 23:54:19 +1300 Subject: [PATCH 008/938] Automatic changelog for PR #82414 [ci skip] --- html/changelogs/AutoChangeLog-pr-82414.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82414.yml diff --git a/html/changelogs/AutoChangeLog-pr-82414.yml b/html/changelogs/AutoChangeLog-pr-82414.yml new file mode 100644 index 0000000000000..2b8d485b48532 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82414.yml @@ -0,0 +1,4 @@ +author: "nikothedude" +delete-after: True +changes: + - bugfix: "Root beer no longer causes laser carbines and disabler smgs to fire infinitely fast." \ No newline at end of file From 5bea693bda4870a6071efce1ffc54a2a6f768db0 Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Thu, 4 Apr 2024 05:55:40 -0500 Subject: [PATCH 009/938] `heal_and_revive` restarts hearts (#82418) ## About The Pull Request The intent of this proc is to make sure the guy can survive after being revived and having your heart stopped kinda works against that ## Changelog :cl: Melbert fix: Heretic sac restarts your heart /:cl: --- code/modules/mob/living/carbon/carbon.dm | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 657fec3705380..955db6d9fb8c9 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -888,7 +888,11 @@ if(!HAS_TRAIT(src, TRAIT_LIVERLESS_METABOLISM) && !isnull(dna?.species.mutantliver) && !get_organ_slot(ORGAN_SLOT_LIVER)) return FALSE - return ..() + . = ..() + if(.) // if revived successfully + set_heartattack(FALSE) + + return . /mob/living/carbon/fully_heal(heal_flags = HEAL_ALL) From a7a20d395b4b844836d759766fbdf46c6d8230d4 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 4 Apr 2024 23:56:02 +1300 Subject: [PATCH 010/938] Automatic changelog for PR #82418 [ci skip] --- html/changelogs/AutoChangeLog-pr-82418.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82418.yml diff --git a/html/changelogs/AutoChangeLog-pr-82418.yml b/html/changelogs/AutoChangeLog-pr-82418.yml new file mode 100644 index 0000000000000..fcfdc0bef4256 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82418.yml @@ -0,0 +1,4 @@ +author: "Melbert" +delete-after: True +changes: + - bugfix: "Heretic sac restarts your heart" \ No newline at end of file From 6ae15437c9152884a4ff414f4a128a896b38ee12 Mon Sep 17 00:00:00 2001 From: Waterpig <49160555+Majkl-J@users.noreply.github.com> Date: Thu, 4 Apr 2024 12:56:19 +0200 Subject: [PATCH 011/938] Fixes quirk being examined when observing (#82424) ## About The Pull Request Examining a human as ghost now shows their quirks again. This was unintentionally removed with https://github.com/tgstation/tgstation/pull/80692 ## Why It's Good For The Game This was unintentionally removed. Bugfix good me thinks? ![image](https://github.com/tgstation/tgstation/assets/49160555/57a8d817-c9f4-4bf5-bc10-498be58ed23d) ## Changelog :cl: fix: Observers can now see people's quirks again /:cl: --- code/modules/mob/living/carbon/human/examine.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 1a1827e198fe6..dafc0327ee49d 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -403,8 +403,8 @@ . += jointext(list("\[Add citation\]", "\[Add crime\]", "\[Add note\]"), "") - else if(isobserver(user)) - . += span_info("Quirks: [get_quirk_string(FALSE, CAT_QUIRK_ALL)]") + if(isobserver(user)) + . += span_info("\nQuirks: [get_quirk_string(FALSE, CAT_QUIRK_ALL)]") . += "" SEND_SIGNAL(src, COMSIG_ATOM_EXAMINE, user, .) From 8247bc140bfe5691dfbb9c2372512c1fab30d546 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 5 Apr 2024 00:02:25 +1300 Subject: [PATCH 012/938] Automatic changelog for PR #82424 [ci skip] --- html/changelogs/AutoChangeLog-pr-82424.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82424.yml diff --git a/html/changelogs/AutoChangeLog-pr-82424.yml b/html/changelogs/AutoChangeLog-pr-82424.yml new file mode 100644 index 0000000000000..501d881ed7431 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82424.yml @@ -0,0 +1,4 @@ +author: "Majkl-J" +delete-after: True +changes: + - bugfix: "Observers can now see people's quirks again" \ No newline at end of file From 732d29a86e0f04c80294cd14f59bd75a408edf34 Mon Sep 17 00:00:00 2001 From: KingkumaArt <69398298+KingkumaArt@users.noreply.github.com> Date: Thu, 4 Apr 2024 07:11:50 -0400 Subject: [PATCH 013/938] Moves that one wall in NorthStar Maints (#82382) You know the one, right? ![image](https://github.com/tgstation/tgstation/assets/69398298/43f98dcb-2a00-43bb-9b9c-6541a77a8454) Seriously though I asked "where's that random wall in northstar maints" and not only did people know what I meant, within 5 min people told me where it was. image ## Why It's Good For The Game Hallways work best when they're traversable. ## Changelog :cl: fix: Moves that one wall on NorthStar to not block the maints passage /:cl: --- _maps/map_files/NorthStar/north_star.dmm | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/_maps/map_files/NorthStar/north_star.dmm b/_maps/map_files/NorthStar/north_star.dmm index cc20da6c1d741..5e86f74088df2 100644 --- a/_maps/map_files/NorthStar/north_star.dmm +++ b/_maps/map_files/NorthStar/north_star.dmm @@ -7946,10 +7946,9 @@ /turf/open/floor/iron/dark/smooth_large, /area/station/hallway/secondary/entry) "bWZ" = ( -/obj/structure/sign/poster/contraband/hacking_guide/directional/north, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/extinguisher_cabinet/directional/west, /obj/machinery/duct, +/obj/machinery/camera/autoname/directional/north, /turf/open/floor/iron/dark/textured, /area/station/commons/fitness) "bXd" = ( @@ -44185,8 +44184,9 @@ /area/station/command/meeting_room) "ltH" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/camera/autoname/directional/north, /obj/machinery/duct, +/obj/structure/sign/poster/contraband/hacking_guide/directional/north, +/obj/structure/extinguisher_cabinet/directional/west, /turf/open/floor/iron/dark/textured, /area/station/commons/fitness) "ltI" = ( @@ -63803,6 +63803,8 @@ dir = 4 }, /obj/effect/turf_decal/trimline/red/filled/corner, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/duct, /turf/open/floor/iron/dark/textured, /area/station/commons/fitness) "qtH" = ( @@ -257493,7 +257495,7 @@ sSB sSB sSB sSB -qrd +sSB qrd qrd sNE @@ -257751,7 +257753,7 @@ qrd qrd qrd qrd -bWZ +qrd vTf gvO boP @@ -259036,7 +259038,7 @@ qrd oeQ xgb nWe -mkl +bWZ hwr oWt wJH From 02690ae9675f23b99acd0632f1fb933f2618fcb2 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 5 Apr 2024 00:12:30 +1300 Subject: [PATCH 014/938] Automatic changelog for PR #82382 [ci skip] --- html/changelogs/AutoChangeLog-pr-82382.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82382.yml diff --git a/html/changelogs/AutoChangeLog-pr-82382.yml b/html/changelogs/AutoChangeLog-pr-82382.yml new file mode 100644 index 0000000000000..2be839df70952 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82382.yml @@ -0,0 +1,4 @@ +author: "KingkumaArt" +delete-after: True +changes: + - bugfix: "Moves that one wall on NorthStar to not block the maints passage" \ No newline at end of file From 29ecfb7e5681a8df29c909d49256582b79002e4f Mon Sep 17 00:00:00 2001 From: Bilbo367 <163439532+Bilbo367@users.noreply.github.com> Date: Thu, 4 Apr 2024 08:22:48 -0600 Subject: [PATCH 015/938] fixes material scanning, so we can scan again (#82428) I broke material scanning, This fixes it. --- .../experisci/experiment/types/scanning.dm | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/code/modules/experisci/experiment/types/scanning.dm b/code/modules/experisci/experiment/types/scanning.dm index 197158c56f375..08ddf066f9b79 100644 --- a/code/modules/experisci/experiment/types/scanning.dm +++ b/code/modules/experisci/experiment/types/scanning.dm @@ -106,17 +106,20 @@ * * target - The atom to attempt to scan */ /datum/experiment/scanning/proc/experiment_requirements(datum/component/experiment_handler/experiment_handler, atom/target) + var/destructive = (traits & EXPERIMENT_TRAIT_DESTRUCTIVE) for (var/req_atom in required_atoms) - if (istype(target, req_atom)) - // Try to select a required atom that this scanned atom would contribute towards - var/destructive = traits & EXPERIMENT_TRAIT_DESTRUCTIVE - var/list/seen = scanned[req_atom] - var/selected = destructive && (req_atom in scanned) && seen < required_atoms[req_atom] - if (!selected) - selected = !destructive && seen.len < required_atoms[req_atom] && !(WEAKREF(target) in seen) - // Run any additonal checks if necessary - if (selected && final_contributing_index_checks(experiment_handler, target, selected)) - return req_atom + if (!istype(target, req_atom)) + continue + // Try to select a required atom that this scanned atom would contribute towards + var/selected + var/list/seen = scanned[req_atom] + if (destructive && (req_atom in scanned) && scanned[req_atom] < required_atoms[req_atom]) + selected = req_atom + else if (!destructive && seen.len < required_atoms[req_atom] && !(WEAKREF(target) in seen)) + selected = req_atom + // Run any additonal checks if necessary + if (selected && final_contributing_index_checks(experiment_handler, target, selected)) + return selected /** * Performs any additional checks against the atom being considered for selection as a contributing index From 03e466b15c87cbe83003d999149a6d32487bacbf Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 5 Apr 2024 03:23:37 +1300 Subject: [PATCH 016/938] Automatic changelog for PR #82428 [ci skip] --- html/changelogs/AutoChangeLog-pr-82428.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82428.yml diff --git a/html/changelogs/AutoChangeLog-pr-82428.yml b/html/changelogs/AutoChangeLog-pr-82428.yml new file mode 100644 index 0000000000000..ddb5a0eacab39 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82428.yml @@ -0,0 +1,4 @@ +author: "Bilbo367" +delete-after: True +changes: + - bugfix: "material experiments not scanning" \ No newline at end of file From 6ab7f0c9710d1f08909327dad79cc1c9e9c754d7 Mon Sep 17 00:00:00 2001 From: Zergspower Date: Thu, 4 Apr 2024 15:34:32 -0500 Subject: [PATCH 017/938] Fixes access to borg panels (#82427) ## About The Pull Request https://github.com/tgstation/tgstation/pull/81681 removed the access requirement to unlock a borg, which of course meant anyone with any ID could fiddle with them. ## Why It's Good For The Game back to sanity ## Changelog :cl:Zergspower fix: borg panel access now requires robotics access again /:cl: --- code/modules/mob/living/silicon/robot/robot_defines.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/mob/living/silicon/robot/robot_defines.dm b/code/modules/mob/living/silicon/robot/robot_defines.dm index 04aadc7e5bc9d..0701584476cd2 100644 --- a/code/modules/mob/living/silicon/robot/robot_defines.dm +++ b/code/modules/mob/living/silicon/robot/robot_defines.dm @@ -106,6 +106,7 @@ ///Random serial number generated for each cyborg upon its initialization var/ident = 0 var/locked = TRUE + req_one_access = list(ACCESS_ROBOTICS) ///Whether the robot has no charge left. var/low_power_mode = FALSE From aea4a7e7ce97771b4dc51bc54573debb0663a7e7 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 5 Apr 2024 09:34:52 +1300 Subject: [PATCH 018/938] Automatic changelog for PR #82427 [ci skip] --- html/changelogs/AutoChangeLog-pr-82427.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82427.yml diff --git a/html/changelogs/AutoChangeLog-pr-82427.yml b/html/changelogs/AutoChangeLog-pr-82427.yml new file mode 100644 index 0000000000000..b5d11936c2620 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82427.yml @@ -0,0 +1,4 @@ +author: "Zergspower" +delete-after: True +changes: + - bugfix: "borg panel access now requires robotics access again" \ No newline at end of file From ec991f8c1dbb4dd1330715d0defb68d499108148 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Fri, 5 Apr 2024 00:20:15 +0000 Subject: [PATCH 019/938] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-82336.yml | 5 ---- html/changelogs/AutoChangeLog-pr-82382.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82402.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82403.yml | 5 ---- html/changelogs/AutoChangeLog-pr-82405.yml | 5 ---- html/changelogs/AutoChangeLog-pr-82414.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82418.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82424.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82427.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82428.yml | 4 ---- html/changelogs/archive/2024-04.yml | 28 ++++++++++++++++++++++ 11 files changed, 28 insertions(+), 43 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-82336.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82382.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82402.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82403.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82405.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82414.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82418.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82424.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82427.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82428.yml diff --git a/html/changelogs/AutoChangeLog-pr-82336.yml b/html/changelogs/AutoChangeLog-pr-82336.yml deleted file mode 100644 index 4857c219793e6..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82336.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Melbert" -delete-after: True -changes: - - qol: "Breathing cold air now has a particle effect associated, careful not to let your glasses fog up." - - qol: "Breathing cold air will now occasionally make your spaceman shiver. Brrr." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82382.yml b/html/changelogs/AutoChangeLog-pr-82382.yml deleted file mode 100644 index 2be839df70952..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82382.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "KingkumaArt" -delete-after: True -changes: - - bugfix: "Moves that one wall on NorthStar to not block the maints passage" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82402.yml b/html/changelogs/AutoChangeLog-pr-82402.yml deleted file mode 100644 index 1c0eedc6f5af1..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82402.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Momo8289" -delete-after: True -changes: - - bugfix: "Holographic energy swords have undergone some more rigorous safety inspections, and should no longer be a danger to clumsy crew members." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82403.yml b/html/changelogs/AutoChangeLog-pr-82403.yml deleted file mode 100644 index b1ec4526c63dc..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82403.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "DATA-xPUNGED" -delete-after: True -changes: - - bugfix: "Fixes Alcoholic quirk selection" - - bugfix: "Fixes Junkie, Smoker, and Alcoholic not giving you more addiction when you come clean." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82405.yml b/html/changelogs/AutoChangeLog-pr-82405.yml deleted file mode 100644 index eda714363bd57..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82405.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "00-Steven" -delete-after: True -changes: - - bugfix: "All Nighter: fixed a runtime from not having a head, whether from hars/deletion/somesuch." - - bugfix: "All Nighter: losing and regaining your head while you had eyebags no longer removes your eyebags until you've slept." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82414.yml b/html/changelogs/AutoChangeLog-pr-82414.yml deleted file mode 100644 index 2b8d485b48532..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82414.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "nikothedude" -delete-after: True -changes: - - bugfix: "Root beer no longer causes laser carbines and disabler smgs to fire infinitely fast." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82418.yml b/html/changelogs/AutoChangeLog-pr-82418.yml deleted file mode 100644 index fcfdc0bef4256..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82418.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Melbert" -delete-after: True -changes: - - bugfix: "Heretic sac restarts your heart" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82424.yml b/html/changelogs/AutoChangeLog-pr-82424.yml deleted file mode 100644 index 501d881ed7431..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82424.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Majkl-J" -delete-after: True -changes: - - bugfix: "Observers can now see people's quirks again" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82427.yml b/html/changelogs/AutoChangeLog-pr-82427.yml deleted file mode 100644 index b5d11936c2620..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82427.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Zergspower" -delete-after: True -changes: - - bugfix: "borg panel access now requires robotics access again" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82428.yml b/html/changelogs/AutoChangeLog-pr-82428.yml deleted file mode 100644 index ddb5a0eacab39..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82428.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Bilbo367" -delete-after: True -changes: - - bugfix: "material experiments not scanning" \ No newline at end of file diff --git a/html/changelogs/archive/2024-04.yml b/html/changelogs/archive/2024-04.yml index 2475630906b24..76fc8f4c26dc2 100644 --- a/html/changelogs/archive/2024-04.yml +++ b/html/changelogs/archive/2024-04.yml @@ -152,3 +152,31 @@ - qol: Makes the clown anomalous crystal actually useful for once rather than an open griefing tool. It now revives the dead...as clowns! - admin: Adds logging for the anomalous crystal activation, including fingerprints. +2024-04-05: + 00-Steven: + - bugfix: 'All Nighter: fixed a runtime from not having a head, whether from hars/deletion/somesuch.' + - bugfix: 'All Nighter: losing and regaining your head while you had eyebags no + longer removes your eyebags until you''ve slept.' + Bilbo367: + - bugfix: material experiments not scanning + DATA-xPUNGED: + - bugfix: Fixes Alcoholic quirk selection + - bugfix: Fixes Junkie, Smoker, and Alcoholic not giving you more addiction when + you come clean. + KingkumaArt: + - bugfix: Moves that one wall on NorthStar to not block the maints passage + Majkl-J: + - bugfix: Observers can now see people's quirks again + Melbert: + - qol: Breathing cold air now has a particle effect associated, careful not to let + your glasses fog up. + - qol: Breathing cold air will now occasionally make your spaceman shiver. Brrr. + - bugfix: Heretic sac restarts your heart + Momo8289: + - bugfix: Holographic energy swords have undergone some more rigorous safety inspections, + and should no longer be a danger to clumsy crew members. + Zergspower: + - bugfix: borg panel access now requires robotics access again + nikothedude: + - bugfix: Root beer no longer causes laser carbines and disabler smgs to fire infinitely + fast. From 6dc40ca522d4d4d6a4f226fc9b6654052ded84ed Mon Sep 17 00:00:00 2001 From: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Date: Fri, 5 Apr 2024 06:25:51 +0530 Subject: [PATCH 020/938] Standardizes object deconstruction throughout the codebase. (#82280) ## About The Pull Request When it comes to deconstructing an object we have `proc/deconstruct()` & `NO_DECONSTRUCT` Lets talk about the flag first. **Problems with `NO_DECONSTRUCTION`** I know what the comment says on what it should do https://github.com/tgstation/tgstation/blob/b5593bc6930cb60803214869a7b94c84e7baa02c/code/__DEFINES/obj_flags.dm#L18 But everywhere people have decided to give their own meaning/definition to this flag. Here are some examples on how this flag is used **1. Make the object just disappear(not drop anything) when deconstructed** This is by far the largest use case everywhere. If an object is deconstructed(either via tools or smashed apart) then if it has this flag it should not drop any of its contents but just disappear. You have seen this code pattern used everywhere https://github.com/tgstation/tgstation/blob/b5593bc6930cb60803214869a7b94c84e7baa02c/code/game/machinery/constructable_frame.dm#L26-L31 This behaviour is then leveraged by 2 important components. When an object is frozen, if it is deconstructed it should just disappear without leaving any traces behind https://github.com/tgstation/tgstation/blob/b5593bc6930cb60803214869a7b94c84e7baa02c/code/datums/elements/frozen.dm#L66-L67 By hologram objects. Obviously if you destroy an hologram nothing real should drop out https://github.com/tgstation/tgstation/blob/b5593bc6930cb60803214869a7b94c84e7baa02c/code/modules/holodeck/computer.dm#L301-L304 And there are other use cases as well but we won't go into them as they aren't as significant as these. **2. To stop an object from being wrenched ??** Yeah this one is weird. Like why? I understand in some instances (chair, table, rack etc) a wrench can be used to deconstruct a object so using the flag there to stop it from happening makes sense but why can't we even anchor an object just because of this flag? https://github.com/tgstation/tgstation/blob/b5593bc6930cb60803214869a7b94c84e7baa02c/code/game/objects/objs.dm#L368-L369 This is one of those instances where somebody just decided this behaviour for their own convenience just like the above example with no explanation as to why **3. To stop using tools to deconstruct the object** This was the original intent of the flag but it is enforced in few places far & between. One example is when deconstructing the a machine via crowbar. https://github.com/tgstation/tgstation/blob/b5593bc6930cb60803214869a7b94c84e7baa02c/code/game/machinery/_machinery.dm#L811 But machines are a special dual use case for this flag. Because if you look at its deconstruct proc the flag also prevents the machine from spawning a frame. https://github.com/tgstation/tgstation/blob/b5593bc6930cb60803214869a7b94c84e7baa02c/code/game/machinery/_machinery.dm#L820-L822 How can 1 flag serve 2 purposes within the same type? **4. Simply forget to check for this flag altogether** Yup if you find this flag not doing its job for some objects don't be surprised. People & sometimes even maintainers just forget that it even exists https://github.com/tgstation/tgstation/blob/b5593bc6930cb60803214869a7b94c84e7baa02c/code/game/objects/items/piggy_bank.dm#L66-L67 **Solution** These are the main examples i found. As you can see the same flag can perform 2 different functions within the same type and do something else in a different object & in some instances don't even work cause people just forget, etc. In order to bring consistency to this flag we need to move it to the atom level where it means the same thing everywhere. Where in the atom you may ask? .Well, I'll just post what MrMelbert said in https://github.com/tgstation/tgstation/pull/81656#discussion_r1503086862 > ...Ideally the .deconstruct call would handle NO_DECONSTRUCTION handling as it wants, Yup that's the ideal case now. This flag is checked directly in `deconstruct()`. Now like i said we want to give a universal definition to this flag and as you have seen from my examples it is used in 3 cases 1) Make an object disappear(doesn't dropping anything) when deconstructed 2) Stop it from being wrenched 3) Stop it from being deconstructed via tools We can't enforce points 2 & 3 inside `deconstruct()` which leaves us with only case 1) i.e. make the object disappear. And that's what i have done. Therefore after more than a decade or since this flag got introduced `NO_DECONSTRUCT` now has a new definition as of 2024 _"Make an object disappear(don't dropping anything) when deconstructed either via tools or forcefully smashed apart"_ Now i very well understand this will open up bugs in places where cases 2 & 3 are required but its worth it. In fact they could even be qol changes for all we know so who knows it might even benefit us but for now we need to give a universal definition to this flag to bring some consistency & that's what this PR does. **Problem with deconstruct()** This proc actually sends out a signal which is currently used by the material container but could be used by other objects later on. https://github.com/tgstation/tgstation/blob/3e84c3e6dad33c831ac259f52f2f023680e4899b/code/game/objects/obj_defense.dm#L160 So objects that override this proc should call its parent. Sadly that isn't the case in many instances like such https://github.com/tgstation/tgstation/blob/3e84c3e6dad33c831ac259f52f2f023680e4899b/code/game/machinery/deployable.dm#L20-L23 Instead of `return ..()` which would delete the object & send the signal it deletes the object directly thus the signal never gets sent. **Solution** Make this proc non overridable. For objects to add their own custom deconstruction behaviour a new proc has been introduced `atom_deconstruct()` Subtypes should now override this proc to handle object deconstruction. If objects have certain important stuff inside them (like mobs in machines for example) they want to drop by handling `NO_DECONSTRUCT` flag in a more carefully customized way they can do this by overriding `handle_deconstruct()` which by default delegates to `atom_deconstruct()` if the `NO_DECONSTRUCT` flag is absent. This proc will allow you to handle the flag in a more customized way if you ever need to. ## Why It's Good For The Game 1) I'm goanna post the full comment from MrMelbert https://github.com/tgstation/tgstation/pull/81656#discussion_r1503086862 > ...Ideally the .deconstruct call would handle NO_DECONSTRUCTION handling as it wants, but there's a shocking lack of consistency around NO_DECONSTRUCTION, where some objects treat it as "allow deconstruction, but make it drop no parts" and others simply "disallow deconstruction at all" This PR now makes `NO_DECONSTRUCTION` handled by `deconstruct()` & gives this flag the consistency it deserves. Not to mention as shown in case 4 there are objects that simply forgot to check for this flag. Now it applies for those missing instances as well. 2) No more copying pasting the most overused code pattern in this code base history `if(obj_flags & NO_DECONSTRUCTION)`. Just makes code cleaner everywhere 3) All objects now send the `COMSIG_OBJ_DECONSTRUCT` signal on object deconstruction which is now available for use should you need it ## Changelog :cl: refactor: refactors how objects are deconstructed in relation to the `NO_DECONSTRUCTION` flag. Certain objects & machinery may display different tool interactions & behaviours when destroyed/deconstructed. Report these changes if you feel like they are bugs /:cl: --------- Co-authored-by: san7890 --- code/__DEFINES/obj_flags.dm | 2 +- code/datums/elements/screentips/README.md | 23 +++-- code/game/machinery/_machinery.dm | 20 ++--- code/game/machinery/barsigns.dm | 2 +- code/game/machinery/camera/camera.dm | 33 ++++--- code/game/machinery/computer/_computer.dm | 2 +- .../computer/atmos_computers/_air_sensor.dm | 8 +- .../game/machinery/computer/buildandrepair.dm | 22 +++-- code/game/machinery/constructable_frame.dm | 13 +-- code/game/machinery/dance_machine.dm | 2 - code/game/machinery/deployable.dm | 9 +- code/game/machinery/doors/windowdoor.dm | 4 - code/game/machinery/harvester.dm | 2 +- code/game/machinery/hologram.dm | 8 +- code/game/machinery/limbgrower.dm | 1 - code/game/machinery/machine_frame.dm | 9 +- code/game/machinery/sleepers.dm | 2 +- code/game/machinery/suit_storage_unit.dm | 6 +- .../machinery/telecomms/machines/allinone.dm | 6 ++ code/game/objects/items/cardboard_cutouts.dm | 6 +- code/game/objects/items/grenades/_grenade.dm | 4 +- code/game/objects/items/piggy_bank.dm | 2 +- code/game/objects/items/rcd/RCD.dm | 5 ++ code/game/objects/items/surgery_tray.dm | 10 +-- code/game/objects/items/tanks/tanks.dm | 2 +- code/game/objects/obj_defense.dm | 41 ++++++++- code/game/objects/objs.dm | 2 - code/game/objects/structures/ai_core.dm | 3 +- code/game/objects/structures/aliens.dm | 11 +-- .../structures/beds_chairs/alien_nest.dm | 10 ++- .../objects/structures/beds_chairs/bed.dm | 16 ++-- .../objects/structures/beds_chairs/chair.dm | 25 +++--- code/game/objects/structures/bedsheet_bin.dm | 2 - .../structures/crates_lockers/closets.dm | 28 +++--- .../crates_lockers/closets/secure/freezer.dm | 6 +- .../structures/destructible_structures.dm | 21 ++--- code/game/objects/structures/displaycase.dm | 16 ++-- code/game/objects/structures/door_assembly.dm | 33 ++++--- .../objects/structures/door_assembly_types.dm | 31 +++---- code/game/objects/structures/dresser.dm | 6 +- code/game/objects/structures/extinguisher.dm | 20 ++--- code/game/objects/structures/false_walls.dm | 28 +++--- code/game/objects/structures/fans.dm | 14 +-- code/game/objects/structures/fireaxe.dm | 22 ++--- code/game/objects/structures/flora.dm | 10 +-- code/game/objects/structures/girders.dm | 14 ++- code/game/objects/structures/grille.dm | 21 ++--- code/game/objects/structures/headpike.dm | 3 +- .../structures/icemoon/cave_entrance.dm | 3 +- code/game/objects/structures/kitchen_spike.dm | 3 +- code/game/objects/structures/lattice.dm | 9 +- .../structures/lavaland/necropolis_tendril.dm | 3 +- code/game/objects/structures/maintenance.dm | 8 +- code/game/objects/structures/mineral_doors.dm | 4 +- code/game/objects/structures/mirror.dm | 14 ++- code/game/objects/structures/morgue.dm | 9 +- code/game/objects/structures/noticeboard.dm | 12 ++- .../objects/structures/petrified_statue.dm | 3 +- code/game/objects/structures/pinatas.dm | 5 +- code/game/objects/structures/plasticflaps.dm | 6 +- code/game/objects/structures/railings.dm | 7 +- code/game/objects/structures/secure_safe.dm | 3 +- code/game/objects/structures/shower.dm | 3 - code/game/objects/structures/stairs.dm | 3 +- code/game/objects/structures/table_frames.dm | 3 +- code/game/objects/structures/tables_racks.dm | 88 +++++++------------ .../game/objects/structures/tank_dispenser.dm | 12 ++- code/game/objects/structures/tank_holder.dm | 3 +- .../transit_tubes/transit_tube_pod.dm | 20 ++--- code/game/objects/structures/votingbox.dm | 3 +- code/game/objects/structures/watercloset.dm | 55 +++++------- code/game/objects/structures/window.dm | 29 ++---- .../heretic/structures/mawed_crucible.dm | 3 +- code/modules/art/statues.dm | 33 +++---- .../atmospherics/machinery/components/tank.dm | 3 +- code/modules/economy/holopay.dm | 3 +- .../food_and_drinks/machinery/griddle.dm | 2 - code/modules/holodeck/items.dm | 2 +- code/modules/hydroponics/beekeeping/beebox.dm | 3 +- code/modules/hydroponics/hydroponics.dm | 6 ++ code/modules/library/bookcase.dm | 3 +- .../lavalandruin_code/elephantgraveyard.dm | 2 +- .../ruins/objects_and_mobs/ash_walker_den.dm | 3 +- code/modules/mining/abandoned_crates.dm | 2 +- .../mining/equipment/marker_beacons.dm | 10 +-- code/modules/mining/equipment/survival_pod.dm | 2 - code/modules/mining/satchel_ore_box.dm | 4 +- .../gutlunchers/gutluncher_foodtrough.dm | 5 +- code/modules/mob/living/brain/MMI.dm | 3 +- .../computers/item/computer.dm | 20 ++--- code/modules/paperwork/filingcabinet.dm | 10 +-- code/modules/paperwork/paper_cutter.dm | 3 +- code/modules/paperwork/paperbin.dm | 2 +- code/modules/photography/photos/frame.dm | 21 ++--- code/modules/power/cable.dm | 8 +- .../modules/power/lighting/light_construct.dm | 6 +- code/modules/power/pipecleaners.dm | 16 ++-- .../chemistry/machinery/chem_dispenser.dm | 8 +- code/modules/reagents/reagent_dispenser.dm | 9 +- code/modules/recycling/disposal/pipe.dm | 40 ++++----- code/modules/recycling/sortingmachinery.dm | 3 +- code/modules/surgery/bodyparts/_bodyparts.dm | 3 +- .../modules/transport/tram/tram_structures.dm | 14 ++- code/modules/vending/_vending.dm | 2 +- code/modules/wiremod/shell/dispenser.dm | 3 +- code/modules/wiremod/shell/moneybot.dm | 3 +- 106 files changed, 490 insertions(+), 664 deletions(-) diff --git a/code/__DEFINES/obj_flags.dm b/code/__DEFINES/obj_flags.dm index 8ace303b843e1..469811c96dc59 100644 --- a/code/__DEFINES/obj_flags.dm +++ b/code/__DEFINES/obj_flags.dm @@ -15,7 +15,7 @@ #define IGNORE_DENSITY (1<<11) //! Can we ignore density when building on this object? (for example, directional windows and grilles) #define INFINITE_RESKIN (1<<12) // We can reskin this item infinitely #define CONDUCTS_ELECTRICITY (1<<13) //! Can this object conduct electricity? -#define NO_DECONSTRUCTION (1<<14) //! Prevent deconstruction of this object. +#define NO_DECONSTRUCTION (1<<14) //! Atoms don't spawn anything when deconstructed. They just vanish // If you add new ones, be sure to add them to /obj/Initialize as well for complete mapping support diff --git a/code/datums/elements/screentips/README.md b/code/datums/elements/screentips/README.md index 92a66ca9dd47c..30d0e7a90ccb4 100644 --- a/code/datums/elements/screentips/README.md +++ b/code/datums/elements/screentips/README.md @@ -35,18 +35,17 @@ Example: ```dm /obj/structure/table/Initialize(mapload) - if (!(obj_flags & NO_DECONSTRUCTION)) - var/static/list/tool_behaviors = list( - TOOL_SCREWDRIVER = list( - SCREENTIP_CONTEXT_RMB = "Disassemble", - ), - - TOOL_WRENCH = list( - SCREENTIP_CONTEXT_RMB = "Deconstruct", - ), - ) - - AddElement(/datum/element/contextual_screentip_tools, tool_behaviors) + var/static/list/tool_behaviors = list( + TOOL_SCREWDRIVER = list( + SCREENTIP_CONTEXT_RMB = "Disassemble", + ), + + TOOL_WRENCH = list( + SCREENTIP_CONTEXT_RMB = "Deconstruct", + ), + ) + + AddElement(/datum/element/contextual_screentip_tools, tool_behaviors) ``` This will display "RMB: Deconstruct" when the user hovers over a table with a wrench. diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index 6d7f8a4960600..edf2cd21534cb 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -798,7 +798,7 @@ SEND_SIGNAL(src, COMSIG_MACHINERY_REFRESH_PARTS) /obj/machinery/proc/default_pry_open(obj/item/crowbar, close_after_pry = FALSE, open_density = FALSE, closed_density = TRUE) - . = !(state_open || panel_open || is_operational || (obj_flags & NO_DECONSTRUCTION)) && crowbar.tool_behaviour == TOOL_CROWBAR + . = !(state_open || panel_open || is_operational) && crowbar.tool_behaviour == TOOL_CROWBAR if(!.) return crowbar.play_tool_sound(src, 50) @@ -808,23 +808,23 @@ close_machine(density_to_set = closed_density) /obj/machinery/proc/default_deconstruction_crowbar(obj/item/crowbar, ignore_panel = 0, custom_deconstruct = FALSE) - . = (panel_open || ignore_panel) && !(obj_flags & NO_DECONSTRUCTION) && crowbar.tool_behaviour == TOOL_CROWBAR + . = (panel_open || ignore_panel) && crowbar.tool_behaviour == TOOL_CROWBAR if(!. || custom_deconstruct) return crowbar.play_tool_sound(src, 50) deconstruct(TRUE) -/obj/machinery/deconstruct(disassembled = TRUE) +/obj/machinery/handle_deconstruct(disassembled = TRUE) SHOULD_NOT_OVERRIDE(TRUE) if(obj_flags & NO_DECONSTRUCTION) - dump_contents() //drop everything inside us - return ..() //Just delete us, no need to call anything else. + dump_inventory_contents() //drop stuff we consider important + return //Just delete us, no need to call anything else. on_deconstruction(disassembled) if(!LAZYLEN(component_parts)) dump_contents() //drop everything inside us - return ..() //we don't have any parts. + return //we don't have any parts. spawn_frame(disassembled) for(var/part in component_parts) @@ -848,8 +848,6 @@ //to handle their contents before we dump them dump_contents() - return ..() - /** * Spawns a frame where this machine is. If the machine was not disassmbled, the * frame is spawned damaged. If the frame couldn't exist on this turf, it's smashed @@ -881,7 +879,7 @@ /obj/machinery/atom_break(damage_flag) . = ..() - if(!(machine_stat & BROKEN) && !(obj_flags & NO_DECONSTRUCTION)) + if(!(machine_stat & BROKEN)) set_machine_stat(machine_stat | BROKEN) SEND_SIGNAL(src, COMSIG_MACHINERY_BROKEN, damage_flag) update_appearance() @@ -928,7 +926,7 @@ qdel(atom_part) /obj/machinery/proc/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver) - if((obj_flags & NO_DECONSTRUCTION) || screwdriver.tool_behaviour != TOOL_SCREWDRIVER) + if(screwdriver.tool_behaviour != TOOL_SCREWDRIVER) return FALSE screwdriver.play_tool_sound(src, 50) @@ -955,7 +953,7 @@ if(!istype(replacer_tool)) return FALSE - if((obj_flags & NO_DECONSTRUCTION) && !replacer_tool.works_from_distance) + if(!replacer_tool.works_from_distance) return FALSE var/shouldplaysound = FALSE diff --git a/code/game/machinery/barsigns.dm b/code/game/machinery/barsigns.dm index faa29c2673ef6..006620ec5f4d5 100644 --- a/code/game/machinery/barsigns.dm +++ b/code/game/machinery/barsigns.dm @@ -88,7 +88,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/barsign, 32) /obj/machinery/barsign/atom_break(damage_flag) . = ..() - if((machine_stat & BROKEN) && !(obj_flags & NO_DECONSTRUCTION)) + if(machine_stat & BROKEN) set_sign(new /datum/barsign/hiddensigns/signoff) /obj/machinery/barsign/on_deconstruction(disassembled) diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index 33dde81af5837..28dcf2de5e8c9 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -302,23 +302,22 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) toggle_cam(null, 0) /obj/machinery/camera/on_deconstruction(disassembled) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(disassembled) - var/obj/item/wallframe/camera/dropped_cam = new(drop_location()) - dropped_cam.update_integrity(dropped_cam.max_integrity * 0.5) - if(camera_construction_state >= CAMERA_STATE_WIRED) - new /obj/item/stack/cable_coil(drop_location(), 2) - if(xray_module) - drop_upgrade(xray_module) - if(emp_module) - drop_upgrade(emp_module) - if(proximity_monitor) - drop_upgrade(proximity_monitor) - else - if(camera_construction_state >= CAMERA_STATE_WIRED) - new /obj/item/stack/cable_coil(drop_location(), 2) - new /obj/item/stack/sheet/iron(loc) - return ..() + if(!disassembled) + if(camera_construction_state >= CAMERA_STATE_WIRED) + new /obj/item/stack/cable_coil(drop_location(), 2) + new /obj/item/stack/sheet/iron(loc) + return + + var/obj/item/wallframe/camera/dropped_cam = new(drop_location()) + dropped_cam.update_integrity(dropped_cam.max_integrity * 0.5) + if(camera_construction_state >= CAMERA_STATE_WIRED) + new /obj/item/stack/cable_coil(drop_location(), 2) + if(xray_module) + drop_upgrade(xray_module) + if(emp_module) + drop_upgrade(emp_module) + if(proximity_monitor) + drop_upgrade(proximity_monitor) /obj/machinery/camera/update_icon_state() //TO-DO: Make panel open states, xray camera, and indicator lights overlays instead. var/xray_module diff --git a/code/game/machinery/computer/_computer.dm b/code/game/machinery/computer/_computer.dm index 36480be6e90db..c2ef2258e3338 100644 --- a/code/game/machinery/computer/_computer.dm +++ b/code/game/machinery/computer/_computer.dm @@ -63,7 +63,7 @@ /obj/machinery/computer/screwdriver_act(mob/living/user, obj/item/I) if(..()) return TRUE - if(circuit && !(obj_flags & NO_DECONSTRUCTION)) + if(circuit) balloon_alert(user, "disconnecting monitor...") if(I.use_tool(src, user, time_to_unscrew, volume=50)) deconstruct(TRUE) diff --git a/code/game/machinery/computer/atmos_computers/_air_sensor.dm b/code/game/machinery/computer/atmos_computers/_air_sensor.dm index d9d461149bca0..1c365dd087649 100644 --- a/code/game/machinery/computer/atmos_computers/_air_sensor.dm +++ b/code/game/machinery/computer/atmos_computers/_air_sensor.dm @@ -221,8 +221,6 @@ deconstruct(TRUE) return ITEM_INTERACT_SUCCESS -/obj/item/air_sensor/deconstruct(disassembled) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/analyzer(loc) - new /obj/item/stack/sheet/iron(loc, 1) - return ..() +/obj/item/air_sensor/atom_deconstruct(disassembled) + new /obj/item/analyzer(loc) + new /obj/item/stack/sheet/iron(loc, 1) diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm index 1fc8322bb7899..fc4b5fcb516f9 100644 --- a/code/game/machinery/computer/buildandrepair.dm +++ b/code/game/machinery/computer/buildandrepair.dm @@ -11,18 +11,16 @@ AddComponent(/datum/component/simple_rotation) register_context() -/obj/structure/frame/computer/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/atom/drop_loc = drop_location() - if(state == FRAME_COMPUTER_STATE_GLASSED) - if(disassembled) - new /obj/item/stack/sheet/glass(drop_loc, 2) - else - new /obj/item/shard(drop_loc) - new /obj/item/shard(drop_loc) - if(state >= FRAME_COMPUTER_STATE_WIRED) - new /obj/item/stack/cable_coil(drop_loc, 5) - +/obj/structure/frame/computer/atom_deconstruct(disassembled = TRUE) + var/atom/drop_loc = drop_location() + if(state == FRAME_COMPUTER_STATE_GLASSED) + if(disassembled) + new /obj/item/stack/sheet/glass(drop_loc, 2) + else + new /obj/item/shard(drop_loc) + new /obj/item/shard(drop_loc) + if(state >= FRAME_COMPUTER_STATE_WIRED) + new /obj/item/stack/cable_coil(drop_loc, 5) return ..() /obj/structure/frame/computer/add_context(atom/source, list/context, obj/item/held_item, mob/user) diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index e6830fd1848b6..f47948753ab34 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -22,13 +22,10 @@ if(circuit) . += "It has \a [circuit] installed." -/obj/structure/frame/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/atom/movable/drop_loc = drop_location() - new /obj/item/stack/sheet/iron(drop_loc, 5) - circuit?.forceMove(drop_loc) - - return ..() +/obj/structure/frame/atom_deconstruct(disassembled = TRUE) + var/atom/movable/drop_loc = drop_location() + new /obj/item/stack/sheet/iron(drop_loc, 5) + circuit?.forceMove(drop_loc) /// Called when circuit has been set to a new board /obj/structure/frame/proc/circuit_added(obj/item/circuitboard/added) @@ -61,8 +58,6 @@ /obj/structure/frame/proc/try_dissassemble(mob/living/user, obj/item/tool, disassemble_time = 8 SECONDS) if(state != FRAME_STATE_EMPTY) return NONE - if(obj_flags & NO_DECONSTRUCTION) - return NONE if(anchored && state == FRAME_STATE_EMPTY) //when using a screwdriver on an incomplete frame(missing components) no point checking for this balloon_alert(user, "must be unanchored first!") return ITEM_INTERACT_BLOCKING diff --git a/code/game/machinery/dance_machine.dm b/code/game/machinery/dance_machine.dm index 9d19d0d9be98b..53799d6dfc188 100644 --- a/code/game/machinery/dance_machine.dm +++ b/code/game/machinery/dance_machine.dm @@ -32,8 +32,6 @@ /obj/machinery/jukebox/wrench_act(mob/living/user, obj/item/tool) if(!isnull(music_player.active_song_sound)) return NONE - if(obj_flags & NO_DECONSTRUCTION) - return NONE if(default_unfasten_wrench(user, tool) == SUCCESSFUL_UNFASTEN) return ITEM_INTERACT_SUCCESS diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm index 0d3c04ccd6f8b..a9a4336e5bb50 100644 --- a/code/game/machinery/deployable.dm +++ b/code/game/machinery/deployable.dm @@ -17,12 +17,13 @@ var/proj_pass_rate = 50 //How many projectiles will pass the cover. Lower means stronger cover var/bar_material = METAL -/obj/structure/barricade/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - make_debris() - qdel(src) +/obj/structure/barricade/atom_deconstruct(disassembled = TRUE) + make_debris() +/// Spawn debris & stuff upon deconstruction /obj/structure/barricade/proc/make_debris() + PROTECTED_PROC(TRUE) + return /obj/structure/barricade/attackby(obj/item/I, mob/living/user, params) diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index 1dc343a0c0b2d..0849a5ad8c5c8 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -347,8 +347,6 @@ /obj/machinery/door/window/screwdriver_act(mob/living/user, obj/item/tool) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return if(density || operating) to_chat(user, span_warning("You need to open the door to access the maintenance panel!")) return @@ -360,8 +358,6 @@ /obj/machinery/door/window/crowbar_act(mob/living/user, obj/item/tool) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return if(!panel_open || density || operating) return add_fingerprint(user) diff --git a/code/game/machinery/harvester.dm b/code/game/machinery/harvester.dm index 33d08def9d292..09599b0cbff6b 100644 --- a/code/game/machinery/harvester.dm +++ b/code/game/machinery/harvester.dm @@ -171,7 +171,7 @@ return TRUE /obj/machinery/harvester/default_pry_open(obj/item/tool) //wew - . = !(state_open || panel_open || (obj_flags & NO_DECONSTRUCTION)) && tool.tool_behaviour == TOOL_CROWBAR //We removed is_operational here + . = !(state_open || panel_open) && tool.tool_behaviour == TOOL_CROWBAR //We removed is_operational here if(.) tool.play_tool_sound(src, 50) visible_message(span_notice("[usr] pries open \the [src]."), span_notice("You pry open [src].")) diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index 05c0fe242461f..88c2959416c3f 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -111,6 +111,9 @@ Possible to do for anyone motivated enough: ) AddElement(/datum/element/contextual_screentip_mob_typechecks, hovering_mob_typechecks) + if(on_network) + holopads += src + /obj/machinery/holopad/secure name = "secure holopad" desc = "It's a floor-mounted device for projecting holographic images. This one will refuse to auto-connect incoming calls." @@ -175,11 +178,6 @@ Possible to do for anyone motivated enough: if(!replay_mode && (disk?.record)) replay_start() -/obj/machinery/holopad/Initialize(mapload) - . = ..() - if(on_network) - holopads += src - /obj/machinery/holopad/Destroy() if(outgoing_call) outgoing_call.ConnectionFailure(src) diff --git a/code/game/machinery/limbgrower.dm b/code/game/machinery/limbgrower.dm index 1fe2f542ba215..b63d13648eb76 100644 --- a/code/game/machinery/limbgrower.dm +++ b/code/game/machinery/limbgrower.dm @@ -283,7 +283,6 @@ /obj/machinery/limbgrower/fullupgrade //Inherently cheaper organ production. This is to NEVER be inherently emagged, no valids. desc = "It grows new limbs using Synthflesh. This alien model seems more efficient." - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION circuit = /obj/item/circuitboard/machine/limbgrower/fullupgrade /obj/machinery/limbgrower/fullupgrade/Initialize(mapload) diff --git a/code/game/machinery/machine_frame.dm b/code/game/machinery/machine_frame.dm index 84c58d3282376..4edb3215e2bd4 100644 --- a/code/game/machinery/machine_frame.dm +++ b/code/game/machinery/machine_frame.dm @@ -17,11 +17,10 @@ QDEL_LIST(components) return ..() -/obj/structure/frame/machine/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(state >= FRAME_STATE_WIRED) - new /obj/item/stack/cable_coil(drop_location(), 5) - dump_contents() +/obj/structure/frame/machine/atom_deconstruct(disassembled = TRUE) + if(state >= FRAME_STATE_WIRED) + new /obj/item/stack/cable_coil(drop_location(), 5) + dump_contents() return ..() /obj/structure/frame/machine/add_context(atom/source, list/context, obj/item/held_item, mob/user) diff --git a/code/game/machinery/sleepers.dm b/code/game/machinery/sleepers.dm index 68b4026b7444a..f768381548a5b 100644 --- a/code/game/machinery/sleepers.dm +++ b/code/game/machinery/sleepers.dm @@ -147,7 +147,7 @@ return FALSE /obj/machinery/sleeper/default_pry_open(obj/item/I) //wew - . = !(state_open || panel_open || (obj_flags & NO_DECONSTRUCTION)) && I.tool_behaviour == TOOL_CROWBAR + . = !(state_open || panel_open) && I.tool_behaviour == TOOL_CROWBAR if(.) I.play_tool_sound(src, 50) visible_message(span_notice("[usr] pries open [src]."), span_notice("You pry open [src].")) diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index 1b7b041a7a96a..255cf3ce7f181 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -794,21 +794,21 @@ causes the SSU to break due to state_open being set to TRUE at the end, and the panel becoming inaccessible. */ /obj/machinery/suit_storage_unit/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver) - if(!(obj_flags & NO_DECONSTRUCTION) && screwdriver.tool_behaviour == TOOL_SCREWDRIVER && (uv || locked)) + if(screwdriver.tool_behaviour == TOOL_SCREWDRIVER && (uv || locked)) to_chat(user, span_warning("You cant open the panel while its [locked ? "locked" : "decontaminating"]")) return TRUE return ..() /obj/machinery/suit_storage_unit/default_pry_open(obj/item/crowbar)//needs to check if the storage is locked. - . = !(state_open || panel_open || is_operational || locked || (obj_flags & NO_DECONSTRUCTION)) && crowbar.tool_behaviour == TOOL_CROWBAR + . = !(state_open || panel_open || is_operational || locked) && crowbar.tool_behaviour == TOOL_CROWBAR if(.) crowbar.play_tool_sound(src, 50) visible_message(span_notice("[usr] pries open \the [src]."), span_notice("You pry open \the [src].")) open_machine() /obj/machinery/suit_storage_unit/default_deconstruction_crowbar(obj/item/crowbar, ignore_panel, custom_deconstruct) - . = (!locked && panel_open && !(obj_flags & NO_DECONSTRUCTION) && crowbar.tool_behaviour == TOOL_CROWBAR) + . = (!locked && panel_open && crowbar.tool_behaviour == TOOL_CROWBAR) if(.) return ..() diff --git a/code/game/machinery/telecomms/machines/allinone.dm b/code/game/machinery/telecomms/machines/allinone.dm index f8a6b66c049ce..f159339193e5a 100644 --- a/code/game/machinery/telecomms/machines/allinone.dm +++ b/code/game/machinery/telecomms/machines/allinone.dm @@ -22,6 +22,12 @@ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION +/obj/machinery/telecomms/allinone/indestructible/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver) + return NONE + +/obj/machinery/telecomms/allinone/indestructible/default_deconstruction_crowbar(obj/item/crowbar, ignore_panel, custom_deconstruct) + return NONE + /obj/machinery/telecomms/allinone/receive_signal(datum/signal/subspace/signal) if(!istype(signal) || signal.transmission_method != TRANSMISSION_SUBSPACE) // receives on subspace only return diff --git a/code/game/objects/items/cardboard_cutouts.dm b/code/game/objects/items/cardboard_cutouts.dm index e50963a855e2b..71f3a244a3081 100644 --- a/code/game/objects/items/cardboard_cutouts.dm +++ b/code/game/objects/items/cardboard_cutouts.dm @@ -92,10 +92,8 @@ if((damage_flag == BULLET || damage_flag == MELEE) && (damage_type == BRUTE) && prob(damage_sustained)) push_over() -/obj/item/cardboard_cutout/deconstruct(disassembled) - if(!(flags_1 & HOLOGRAM_1) || !(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/cardboard(loc, 1) - return ..() +/obj/item/cardboard_cutout/atom_deconstruct(disassembled) + new /obj/item/stack/sheet/cardboard(loc, 1) /proc/get_cardboard_cutout_instance(datum/cardboard_cutout/cardboard_cutout) ASSERT(ispath(cardboard_cutout), "[cardboard_cutout] is not a path of /datum/cardboard_cutout") diff --git a/code/game/objects/items/grenades/_grenade.dm b/code/game/objects/items/grenades/_grenade.dm index e7e592eabacec..4c737ed53f3cb 100644 --- a/code/game/objects/items/grenades/_grenade.dm +++ b/code/game/objects/items/grenades/_grenade.dm @@ -63,11 +63,9 @@ sleep(det_time)//so you dont die instantly return dud_flags ? SHAME : BRUTELOSS -/obj/item/grenade/deconstruct(disassembled = TRUE) +/obj/item/grenade/atom_deconstruct(disassembled = TRUE) if(!disassembled) detonate() - if(!QDELETED(src)) - qdel(src) /obj/item/grenade/apply_fantasy_bonuses(bonus) . = ..() diff --git a/code/game/objects/items/piggy_bank.dm b/code/game/objects/items/piggy_bank.dm index 8d50e8a39e8fe..b6294dbc4dd8c 100644 --- a/code/game/objects/items/piggy_bank.dm +++ b/code/game/objects/items/piggy_bank.dm @@ -63,7 +63,7 @@ persistence_cb = null return ..() -/obj/item/piggy_bank/deconstruct(disassembled = TRUE) +/obj/item/piggy_bank/atom_deconstruct(disassembled = TRUE) for(var/obj/item/thing as anything in contents) thing.forceMove(loc) //Smashing the piggy after the round is over doesn't count. diff --git a/code/game/objects/items/rcd/RCD.dm b/code/game/objects/items/rcd/RCD.dm index d050da4fa5e10..b4e5ffb35ee18 100644 --- a/code/game/objects/items/rcd/RCD.dm +++ b/code/game/objects/items/rcd/RCD.dm @@ -203,6 +203,11 @@ * * [mob][user]- the user building this structure */ /obj/item/construction/rcd/proc/rcd_create(atom/target, mob/user) + //straight up cant touch this + if(mode == RCD_DECONSTRUCT && (target.resistance_flags & INDESTRUCTIBLE)) + balloon_alert(user, "too durable!") + return + //does this atom allow for rcd actions? var/list/rcd_results = target.rcd_vals(user, src) if(!rcd_results) diff --git a/code/game/objects/items/surgery_tray.dm b/code/game/objects/items/surgery_tray.dm index e31b8f24cb8a2..028366481d45a 100644 --- a/code/game/objects/items/surgery_tray.dm +++ b/code/game/objects/items/surgery_tray.dm @@ -150,12 +150,10 @@ for(var/atom/movable/tool as anything in contents) tool.forceMove(drop_point) -/obj/item/surgery_tray/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - dump_contents() - new /obj/item/stack/rods(drop_location(), 2) - new /obj/item/stack/sheet/mineral/silver(drop_location()) - return ..() +/obj/item/surgery_tray/atom_deconstruct(disassembled = TRUE) + dump_contents() + new /obj/item/stack/rods(drop_location(), 2) + new /obj/item/stack/sheet/mineral/silver(drop_location()) /obj/item/surgery_tray/deployed is_portable = FALSE diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm index e198f7d75d74d..8772e2f41c98b 100644 --- a/code/game/objects/items/tanks/tanks.dm +++ b/code/game/objects/items/tanks/tanks.dm @@ -174,7 +174,7 @@ if(tank_assembly) . += span_warning("There is some kind of device [EXAMINE_HINT("rigged")] to the tank!") -/obj/item/tank/deconstruct(disassembled = TRUE) +/obj/item/tank/atom_deconstruct(disassembled = TRUE) var/atom/location = loc if(location) location.assume_air(air_contents) diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index 9b118ea7c2f72..4731ad4395f17 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -155,9 +155,48 @@ var/mob/living/buckled_mob = m buckled_mob.electrocute_act((clamp(round(strength * 1.25e-3), 10, 90) + rand(-5, 5)), src, flags = SHOCK_TESLA) -///the obj is deconstructed into pieces, whether through careful disassembly or when destroyed. +/** + * Custom behaviour per atom subtype on how they should deconstruct themselves + * Arguments + * + * * disassembled - TRUE means we cleanly took this atom apart using tools. FALSE means this was destroyed in a violent way + */ +/obj/proc/atom_deconstruct(disassembled = TRUE) + PROTECTED_PROC(TRUE) + + return + +/** + * The interminate proc between deconstruct() & atom_deconstruct(). By default this delegates deconstruction to + * atom_deconstruct if NO_DECONSTRUCTION is absent but subtypes can override this to handle NO_DECONSTRUCTION in their + * own unique way. Override this if for example you want to dump out important content like mobs from the + * atom before deconstruction regardless if NO_DECONSTRUCTION is present or not + * Arguments + * + * * disassembled - TRUE means we cleanly took this atom apart using tools. FALSE means this was destroyed in a violent way + */ +/obj/proc/handle_deconstruct(disassembled = TRUE) + SHOULD_CALL_PARENT(FALSE) + + if(!(obj_flags & NO_DECONSTRUCTION)) + atom_deconstruct(disassembled) + +/** + * The obj is deconstructed into pieces, whether through careful disassembly or when destroyed. + * Arguments + * + * * disassembled - TRUE means we cleanly took this atom apart using tools. FALSE means this was destroyed in a violent way + */ /obj/proc/deconstruct(disassembled = TRUE) + SHOULD_NOT_OVERRIDE(TRUE) + + //allow objects to deconstruct themselves + handle_deconstruct(disassembled) + + //inform objects we were deconstructed SEND_SIGNAL(src, COMSIG_OBJ_DECONSTRUCT, disassembled) + + //delete our self qdel(src) ///what happens when the obj's integrity reaches zero. diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index c2183728d4f19..1872f62d90793 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -367,8 +367,6 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) /// If we can unwrench this object; returns SUCCESSFUL_UNFASTEN and FAILED_UNFASTEN, which are both TRUE, or CANT_UNFASTEN, which isn't. /obj/proc/can_be_unfasten_wrench(mob/user, silent) - if(obj_flags & NO_DECONSTRUCTION) - return CANT_UNFASTEN if(!(isfloorturf(loc) || isindestructiblefloor(loc)) && !anchored) to_chat(user, span_warning("[src] needs to be on the floor to be secured!")) return FAILED_UNFASTEN diff --git a/code/game/objects/structures/ai_core.dm b/code/game/objects/structures/ai_core.dm index 7615a37a88b36..70c9c95459127 100644 --- a/code/game/objects/structures/ai_core.dm +++ b/code/game/objects/structures/ai_core.dm @@ -380,7 +380,7 @@ icon_state = "ai-empty" return ..() -/obj/structure/ai_core/deconstruct(disassembled = TRUE) +/obj/structure/ai_core/atom_deconstruct(disassembled = TRUE) if(state >= GLASS_CORE) new /obj/item/stack/sheet/rglass(loc, 2) if(state >= CABLED_CORE) @@ -389,7 +389,6 @@ circuit.forceMove(loc) circuit = null new /obj/item/stack/sheet/plasteel(loc, 4) - qdel(src) /// Quick proc to call to see if the brainmob inside of us has suicided. Returns TRUE if we have, FALSE in any other scenario. /obj/structure/ai_core/proc/suicide_check() diff --git a/code/game/objects/structures/aliens.dm b/code/game/objects/structures/aliens.dm index 886d0b9bcba63..c5a69bfa3290c 100644 --- a/code/game/objects/structures/aliens.dm +++ b/code/game/objects/structures/aliens.dm @@ -41,10 +41,8 @@ icon = 'icons/obj/fluff/general.dmi' icon_state = "gelmound" -/obj/structure/alien/gelpod/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/effect/mob_spawn/corpse/human/damaged(get_turf(src)) - qdel(src) +/obj/structure/alien/gelpod/atom_deconstruct(disassembled = TRUE) + new /obj/effect/mob_spawn/corpse/human/damaged(get_turf(src)) /* * Resin @@ -446,9 +444,8 @@ /obj/structure/alien/egg/atom_break(damage_flag) . = ..() - if(!(obj_flags & NO_DECONSTRUCTION)) - if(status != BURST) - Burst(kill=TRUE) + if(status != BURST) + Burst(kill=TRUE) /obj/structure/alien/egg/HasProximity(atom/movable/AM) if(status == GROWN) diff --git a/code/game/objects/structures/beds_chairs/alien_nest.dm b/code/game/objects/structures/beds_chairs/alien_nest.dm index 0a157dc98a1f3..1654cecff4556 100644 --- a/code/game/objects/structures/beds_chairs/alien_nest.dm +++ b/code/game/objects/structures/beds_chairs/alien_nest.dm @@ -12,10 +12,18 @@ smoothing_groups = SMOOTH_GROUP_ALIEN_NEST canSmoothWith = SMOOTH_GROUP_ALIEN_NEST build_stack_type = null - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION elevation = 0 var/static/mutable_appearance/nest_overlay = mutable_appearance('icons/mob/nonhuman-player/alien.dmi', "nestoverlay", LYING_MOB_LAYER) +/obj/structure/bed/nest/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) + if(held_item?.tool_behaviour == TOOL_WRENCH) + return NONE + + return ..() + +/obj/structure/bed/nest/wrench_act_secondary(mob/living/user, obj/item/weapon) + return ITEM_INTERACT_BLOCKING + /obj/structure/bed/nest/user_unbuckle_mob(mob/living/buckled_mob, mob/living/user) if(has_buckled_mobs()) for(var/buck in buckled_mobs) //breaking a nest releases all the buckled mobs, because the nest isn't holding them down anymore diff --git a/code/game/objects/structures/beds_chairs/bed.dm b/code/game/objects/structures/beds_chairs/bed.dm index e2038cb623b5f..5c5fac60eaaa4 100644 --- a/code/game/objects/structures/beds_chairs/bed.dm +++ b/code/game/objects/structures/beds_chairs/bed.dm @@ -34,12 +34,11 @@ /obj/structure/bed/examine(mob/user) . = ..() - if(!(obj_flags & NO_DECONSTRUCTION)) - . += span_notice("It's held together by a couple of bolts.") + . += span_notice("It's held together by a couple of bolts.") /obj/structure/bed/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) if(held_item) - if(held_item.tool_behaviour != TOOL_WRENCH || obj_flags & NO_DECONSTRUCTION) + if(held_item.tool_behaviour != TOOL_WRENCH) return context[SCREENTIP_CONTEXT_RMB] = "Dismantle" @@ -49,19 +48,14 @@ context[SCREENTIP_CONTEXT_LMB] = "Unbuckle" return CONTEXTUAL_SCREENTIP_SET -/obj/structure/bed/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(build_stack_type) - new build_stack_type(loc, build_stack_amount) - ..() +/obj/structure/bed/atom_deconstruct(disassembled = TRUE) + if(build_stack_type) + new build_stack_type(loc, build_stack_amount) /obj/structure/bed/attack_paw(mob/user, list/modifiers) return attack_hand(user, modifiers) /obj/structure/bed/wrench_act_secondary(mob/living/user, obj/item/weapon) - if(obj_flags & NO_DECONSTRUCTION) - return TRUE - ..() weapon.play_tool_sound(src) deconstruct(disassembled = TRUE) diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm index 0c4555bf390a4..74546e2ccd79c 100644 --- a/code/game/objects/structures/beds_chairs/chair.dm +++ b/code/game/objects/structures/beds_chairs/chair.dm @@ -36,16 +36,12 @@ SSjob.latejoin_trackers -= src //These may be here due to the arrivals shuttle return ..() -/obj/structure/chair/deconstruct(disassembled) - // If we have materials, and don't have the NOCONSTRUCT flag - if(!(obj_flags & NO_DECONSTRUCTION)) - if(buildstacktype) - new buildstacktype(loc,buildstackamount) - else - for(var/i in custom_materials) - var/datum/material/M = i - new M.sheet_type(loc, FLOOR(custom_materials[M] / SHEET_MATERIAL_AMOUNT, 1)) - ..() +/obj/structure/chair/atom_deconstruct(disassembled) + if(buildstacktype) + new buildstacktype(loc,buildstackamount) + else + for(var/datum/material/mat as anything in custom_materials) + new mat.sheet_type(loc, FLOOR(custom_materials[mat] / SHEET_MATERIAL_AMOUNT, 1)) /obj/structure/chair/attack_paw(mob/user, list/modifiers) return attack_hand(user, modifiers) @@ -56,8 +52,6 @@ qdel(src) /obj/structure/chair/attackby(obj/item/W, mob/user, params) - if(obj_flags & NO_DECONSTRUCTION) - return . = ..() if(istype(W, /obj/item/assembly/shock_kit) && !HAS_TRAIT(src, TRAIT_ELECTRIFIED_BUCKLE)) electrify_self(W, user) return @@ -85,8 +79,6 @@ /obj/structure/chair/wrench_act_secondary(mob/living/user, obj/item/weapon) - if(obj_flags & NO_DECONSTRUCTION) - return TRUE ..() weapon.play_tool_sound(src) deconstruct(disassembled = TRUE) @@ -274,7 +266,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool, 0) /obj/structure/chair/MouseDrop(over_object, src_location, over_location) . = ..() if(over_object == usr && Adjacent(usr)) - if(!item_chair || has_buckled_mobs() || src.obj_flags & NO_DECONSTRUCTION) + if(!item_chair || has_buckled_mobs()) return if(!usr.can_perform_action(src, NEED_DEXTERITY|NEED_HANDS)) return @@ -490,6 +482,9 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool/bar, 0) obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION alpha = 0 +/obj/structure/chair/mime/wrench_act_secondary(mob/living/user, obj/item/weapon) + return ITEM_INTERACT_BLOCKING + /obj/structure/chair/mime/post_buckle_mob(mob/living/M) M.pixel_y += 5 diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm index 50fcae8dec138..108ca3fe9b8b0 100644 --- a/code/game/objects/structures/bedsheet_bin.dm +++ b/code/game/objects/structures/bedsheet_bin.dm @@ -609,8 +609,6 @@ LINEN BINS ..() /obj/structure/bedsheetbin/screwdriver_act(mob/living/user, obj/item/tool) - if(obj_flags & NO_DECONSTRUCTION) - return FALSE if(amount) to_chat(user, span_warning("The [src] must be empty first!")) return ITEM_INTERACT_SUCCESS diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index dc273bdc938e8..3eb29fc1526a3 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -581,25 +581,23 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets) else return open(user) -/obj/structure/closet/deconstruct(disassembled = TRUE) - if (!(obj_flags & NO_DECONSTRUCTION)) - if(ispath(material_drop) && material_drop_amount) - new material_drop(loc, material_drop_amount) - if (secure) - var/obj/item/electronics/airlock/electronics = new(drop_location()) - if(length(req_one_access)) - electronics.one_access = TRUE - electronics.accesses = req_one_access - else - electronics.accesses = req_access - if(card_reader_installed) - new /obj/item/stock_parts/card_reader(drop_location()) +/obj/structure/closet/atom_deconstruct(disassembled = TRUE) + if(ispath(material_drop) && material_drop_amount) + new material_drop(loc, material_drop_amount) + if (secure) + var/obj/item/electronics/airlock/electronics = new(drop_location()) + if(length(req_one_access)) + electronics.one_access = TRUE + electronics.accesses = req_one_access + else + electronics.accesses = req_access + if(card_reader_installed) + new /obj/item/stock_parts/card_reader(drop_location()) dump_contents() - qdel(src) /obj/structure/closet/atom_break(damage_flag) . = ..() - if(!broken && !(obj_flags & NO_DECONSTRUCTION)) + if(!broken) bust_open() /obj/structure/closet/CheckParts(list/parts_list) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm b/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm index 1ac7e65884e40..1e19671a45546 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm @@ -36,10 +36,8 @@ flags_1 &= ~PREVENT_CONTENTS_EXPLOSION_1 return FALSE -/obj/structure/closet/secure_closet/freezer/deconstruct(disassembled) - if (!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/assembly/igniter/condenser(drop_location()) - . = ..() +/obj/structure/closet/secure_closet/freezer/atom_deconstruct(disassembled) + new /obj/item/assembly/igniter/condenser(drop_location()) /obj/structure/closet/secure_closet/freezer/empty name = "freezer" diff --git a/code/game/objects/structures/destructible_structures.dm b/code/game/objects/structures/destructible_structures.dm index f33c99b681a64..beffa5d4fd741 100644 --- a/code/game/objects/structures/destructible_structures.dm +++ b/code/game/objects/structures/destructible_structures.dm @@ -4,16 +4,13 @@ var/break_sound = 'sound/magic/clockwork/invoke_general.ogg' //The sound played when a structure breaks var/list/debris = null //Parts left behind when a structure breaks, takes the form of list(path = amount_to_spawn) -/obj/structure/destructible/deconstruct(disassembled = TRUE) +/obj/structure/destructible/atom_deconstruct(disassembled = TRUE) if(!disassembled) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(islist(debris)) - for(var/I in debris) - for(var/i in 1 to debris[I]) - new I (get_turf(src)) - if(break_message) - visible_message(break_message) - if(break_sound) - playsound(src, break_sound, 50, TRUE) - qdel(src) - return 1 + if(islist(debris)) + for(var/I in debris) + for(var/i in 1 to debris[I]) + new I (get_turf(src)) + if(break_message) + visible_message(break_message) + if(break_sound) + playsound(src, break_sound, 50, TRUE) diff --git a/code/game/objects/structures/displaycase.dm b/code/game/objects/structures/displaycase.dm index d7deb5b42cf79..b9b4698d78032 100644 --- a/code/game/objects/structures/displaycase.dm +++ b/code/game/objects/structures/displaycase.dm @@ -81,17 +81,15 @@ if(BURN) playsound(src, 'sound/items/welder.ogg', 100, TRUE) -/obj/structure/displaycase/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - dump() - if(!disassembled) - new /obj/item/shard(drop_location()) - trigger_alarm() - qdel(src) +/obj/structure/displaycase/atom_deconstruct(disassembled = TRUE) + dump() + if(!disassembled) + new /obj/item/shard(drop_location()) + trigger_alarm() /obj/structure/displaycase/atom_break(damage_flag) . = ..() - if(!broken && !(obj_flags & NO_DECONSTRUCTION)) + if(!broken) set_density(FALSE) broken = TRUE new /obj/item/shard(drop_location()) @@ -673,7 +671,7 @@ /obj/structure/displaycase/forsale/atom_break(damage_flag) . = ..() - if(!broken && !(obj_flags & NO_DECONSTRUCTION)) + if(!broken) broken = TRUE playsound(src, SFX_SHATTER, 70, TRUE) update_appearance() diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm index f110cd8b43eab..b6cac0aa5bec6 100644 --- a/code/game/objects/structures/door_assembly.dm +++ b/code/game/objects/structures/door_assembly.dm @@ -363,25 +363,22 @@ target.update_name() qdel(source) -/obj/structure/door_assembly/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/turf/T = get_turf(src) - if(!disassembled) - material_amt = rand(2,4) - new material_type(T, material_amt) - if(glass) - if(disassembled) - if(heat_proof_finished) - new /obj/item/stack/sheet/rglass(T) - else - new /obj/item/stack/sheet/glass(T) +/obj/structure/door_assembly/atom_deconstruct(disassembled = TRUE) + var/turf/target_turf = get_turf(src) + if(!disassembled) + material_amt = rand(2,4) + new material_type(target_turf, material_amt) + if(glass) + if(disassembled) + if(heat_proof_finished) + new /obj/item/stack/sheet/rglass(target_turf) else - new /obj/item/shard(T) - if(mineral) - var/obj/item/stack/sheet/mineral/mineral_path = text2path("/obj/item/stack/sheet/mineral/[mineral]") - new mineral_path(T, 2) - qdel(src) - + new /obj/item/stack/sheet/glass(target_turf) + else + new /obj/item/shard(target_turf) + if(mineral) + var/obj/item/stack/sheet/mineral/mineral_path = text2path("/obj/item/stack/sheet/mineral/[mineral]") + new mineral_path(target_turf, 2) /obj/structure/door_assembly/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) if(the_rcd.mode == RCD_DECONSTRUCT) diff --git a/code/game/objects/structures/door_assembly_types.dm b/code/game/objects/structures/door_assembly_types.dm index 589cad42bcabc..dd06f7e42a9a4 100644 --- a/code/game/objects/structures/door_assembly_types.dm +++ b/code/game/objects/structures/door_assembly_types.dm @@ -271,24 +271,21 @@ name = "large public airlock assembly" base_name = "large public airlock" -/obj/structure/door_assembly/door_assembly_material/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/turf/T = get_turf(src) - for(var/material in custom_materials) - var/datum/material/material_datum = material - var/material_count = FLOOR(custom_materials[material_datum] / SHEET_MATERIAL_AMOUNT, 1) - if(!disassembled) - material_count = rand(FLOOR(material_count/2, 1), material_count) - new material_datum.sheet_type(T, material_count) - if(glass) - if(disassembled) - if(heat_proof_finished) - new /obj/item/stack/sheet/rglass(T) - else - new /obj/item/stack/sheet/glass(T) +/obj/structure/door_assembly/door_assembly_material/atom_deconstruct(disassembled = TRUE) + var/turf/target_turf = get_turf(src) + for(var/datum/material/material_datum as anything in custom_materials) + var/material_count = FLOOR(custom_materials[material_datum] / SHEET_MATERIAL_AMOUNT, 1) + if(!disassembled) + material_count = rand(FLOOR(material_count/2, 1), material_count) + new material_datum.sheet_type(target_turf, material_count) + if(glass) + if(disassembled) + if(heat_proof_finished) + new /obj/item/stack/sheet/rglass(target_turf) else - new /obj/item/shard(T) - qdel(src) + new /obj/item/stack/sheet/glass(target_turf) + else + new /obj/item/shard(target_turf) /obj/structure/door_assembly/door_assembly_material/finish_door() var/obj/machinery/door/airlock/door = ..() diff --git a/code/game/objects/structures/dresser.dm b/code/game/objects/structures/dresser.dm index 0d9b3664cb29a..4296ac3368443 100644 --- a/code/game/objects/structures/dresser.dm +++ b/code/game/objects/structures/dresser.dm @@ -16,10 +16,8 @@ else return ..() -/obj/structure/dresser/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/mineral/wood(drop_location(), 10) - qdel(src) +/obj/structure/dresser/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/mineral/wood(drop_location(), 10) /obj/structure/dresser/attack_hand(mob/user, list/modifiers) . = ..() diff --git a/code/game/objects/structures/extinguisher.dm b/code/game/objects/structures/extinguisher.dm index fb925cdb7dae8..e78b71f14e963 100644 --- a/code/game/objects/structures/extinguisher.dm +++ b/code/game/objects/structures/extinguisher.dm @@ -160,7 +160,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/extinguisher_cabinet, 29) /obj/structure/extinguisher_cabinet/atom_break(damage_flag) . = ..() - if(!broken && !(obj_flags & NO_DECONSTRUCTION)) + if(!broken) broken = 1 opened = 1 if(stored_extinguisher) @@ -169,16 +169,14 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/extinguisher_cabinet, 29) update_appearance(UPDATE_ICON) -/obj/structure/extinguisher_cabinet/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(disassembled) - new /obj/item/wallframe/extinguisher_cabinet(loc) - else - new /obj/item/stack/sheet/iron (loc, 2) - if(stored_extinguisher) - stored_extinguisher.forceMove(loc) - stored_extinguisher = null - qdel(src) +/obj/structure/extinguisher_cabinet/atom_deconstruct(disassembled = TRUE) + if(disassembled) + new /obj/item/wallframe/extinguisher_cabinet(loc) + else + new /obj/item/stack/sheet/iron (loc, 2) + if(stored_extinguisher) + stored_extinguisher.forceMove(loc) + stored_extinguisher = null /obj/item/wallframe/extinguisher_cabinet name = "extinguisher cabinet frame" diff --git a/code/game/objects/structures/false_walls.dm b/code/game/objects/structures/false_walls.dm index eaf830b7db78e..bfae47065354c 100644 --- a/code/game/objects/structures/false_walls.dm +++ b/code/game/objects/structures/false_walls.dm @@ -133,14 +133,12 @@ playsound(src, 'sound/items/welder.ogg', 100, TRUE) deconstruct(disassembled) -/obj/structure/falsewall/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(disassembled) - new girder_type(loc) - if(mineral_amount) - for(var/i in 1 to mineral_amount) - new mineral(loc) - qdel(src) +/obj/structure/falsewall/atom_deconstruct(disassembled = TRUE) + if(disassembled) + new girder_type(loc) + if(mineral_amount) + for(var/i in 1 to mineral_amount) + new mineral(loc) /obj/structure/falsewall/get_dumping_location() return null @@ -387,14 +385,12 @@ canSmoothWith = SMOOTH_GROUP_MATERIAL_WALLS material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS -/obj/structure/falsewall/material/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(disassembled) - new girder_type(loc) - for(var/material in custom_materials) - var/datum/material/material_datum = material - new material_datum.sheet_type(loc, FLOOR(custom_materials[material_datum] / SHEET_MATERIAL_AMOUNT, 1)) - qdel(src) +/obj/structure/falsewall/material/atom_deconstruct(disassembled = TRUE) + if(disassembled) + new girder_type(loc) + for(var/material in custom_materials) + var/datum/material/material_datum = material + new material_datum.sheet_type(loc, FLOOR(custom_materials[material_datum] / SHEET_MATERIAL_AMOUNT, 1)) /obj/structure/falsewall/material/mat_update_desc(mat) desc = "A huge chunk of [mat] used to separate rooms." diff --git a/code/game/objects/structures/fans.dm b/code/game/objects/structures/fans.dm index 924da72ee3098..4f0a5fc450bfe 100644 --- a/code/game/objects/structures/fans.dm +++ b/code/game/objects/structures/fans.dm @@ -10,21 +10,15 @@ var/buildstackamount = 5 can_atmos_pass = ATMOS_PASS_NO -/obj/structure/fans/deconstruct() - if(!(obj_flags & NO_DECONSTRUCTION)) - if(buildstacktype) - new buildstacktype(loc,buildstackamount) - qdel(src) +/obj/structure/fans/atom_deconstruct(disassembled = TRUE) + if(buildstacktype) + new buildstacktype(loc,buildstackamount) /obj/structure/fans/wrench_act(mob/living/user, obj/item/I) - ..() - if(obj_flags & NO_DECONSTRUCTION) - return TRUE - user.visible_message(span_warning("[user] disassembles [src]."), span_notice("You start to disassemble [src]..."), span_hear("You hear clanking and banging noises.")) if(I.use_tool(src, user, 20, volume=50)) - deconstruct() + deconstruct(TRUE) return TRUE /obj/structure/fans/tiny diff --git a/code/game/objects/structures/fireaxe.dm b/code/game/objects/structures/fireaxe.dm index ab7d410f0966e..ab69b7bc7a41e 100644 --- a/code/game/objects/structures/fireaxe.dm +++ b/code/game/objects/structures/fireaxe.dm @@ -108,19 +108,17 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/fireaxecabinet, 32) /obj/structure/fireaxecabinet/atom_break(damage_flag) . = ..() - if(!broken && !(obj_flags & NO_DECONSTRUCTION)) + if(!broken) update_appearance() broken = TRUE playsound(src, 'sound/effects/glassbr3.ogg', 100, TRUE) new /obj/item/shard(loc) new /obj/item/shard(loc) -/obj/structure/fireaxecabinet/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(held_item && loc) - held_item.forceMove(loc) - new /obj/item/wallframe/fireaxecabinet(loc) - qdel(src) +/obj/structure/fireaxecabinet/atom_deconstruct(disassembled = TRUE) + if(held_item && loc) + held_item.forceMove(loc) + new /obj/item/wallframe/fireaxecabinet(loc) /obj/structure/fireaxecabinet/blob_act(obj/structure/blob/B) if(held_item) @@ -230,12 +228,10 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/fireaxecabinet/empty, 32) MAPPING_DIRECTIONAL_HELPERS(/obj/structure/fireaxecabinet/mechremoval, 32) -/obj/structure/fireaxecabinet/mechremoval/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(held_item && loc) - held_item.forceMove(loc) - new /obj/item/wallframe/fireaxecabinet/mechremoval(loc) - qdel(src) +/obj/structure/fireaxecabinet/mechremoval/atom_deconstruct(disassembled = TRUE) + if(held_item && loc) + held_item.forceMove(loc) + new /obj/item/wallframe/fireaxecabinet/mechremoval(loc) /obj/structure/fireaxecabinet/mechremoval/empty populate_contents = FALSE diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm index e7060a145e99a..8749691c91d4d 100644 --- a/code/game/objects/structures/flora.dm +++ b/code/game/objects/structures/flora.dm @@ -263,13 +263,11 @@ var/matrix/M = matrix(transform) transform = M.Turn(-previous_rotation) -/obj/structure/flora/deconstruct() - if(!(obj_flags & NO_DECONSTRUCTION)) - if(harvested) - return ..() +/obj/structure/flora/atom_deconstruct(disassembled = TRUE) + if(harvested) + return ..() - harvest(product_amount_multiplier = 0.6) - . = ..() + harvest(product_amount_multiplier = 0.6) /********* * Trees * diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index 3bb24147f5c49..513525ffca399 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -384,11 +384,9 @@ return TRUE return FALSE -/obj/structure/girder/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/remains = pick(/obj/item/stack/rods, /obj/item/stack/sheet/iron) - new remains(loc) - qdel(src) +/obj/structure/girder/atom_deconstruct(disassembled = TRUE) + var/remains = pick(/obj/item/stack/rods, /obj/item/stack/sheet/iron) + new remains(loc) /obj/structure/girder/narsie_act() new /obj/structure/girder/cult(loc) @@ -461,10 +459,8 @@ /obj/structure/girder/cult/narsie_act() return -/obj/structure/girder/cult/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/runed_metal(drop_location(), 1) - qdel(src) +/obj/structure/girder/cult/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/runed_metal(drop_location(), 1) /obj/structure/girder/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) switch(the_rcd.mode) diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index da02394251810..a25dfaada505f 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -52,8 +52,6 @@ /obj/structure/grille/examine(mob/user) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return if(anchored) . += span_notice("It's secured in place with screws. The rods look like they could be cut through.") @@ -200,10 +198,8 @@ add_fingerprint(user) if(shock(user, 100)) return - if(obj_flags & NO_DECONSTRUCTION) - return FALSE tool.play_tool_sound(src, 100) - deconstruct() + deconstruct(TRUE) return ITEM_INTERACT_SUCCESS /obj/structure/grille/screwdriver_act(mob/living/user, obj/item/tool) @@ -212,8 +208,6 @@ add_fingerprint(user) if(shock(user, 90)) return FALSE - if(obj_flags & NO_DECONSTRUCTION) - return FALSE if(!tool.use_tool(src, user, 0, volume=100)) return FALSE set_anchored(!anchored) @@ -296,18 +290,13 @@ playsound(src, 'sound/items/welder.ogg', 80, TRUE) -/obj/structure/grille/deconstruct(disassembled = TRUE) - if(!loc) //if already qdel'd somehow, we do nothing - return - if(!(obj_flags & NO_DECONSTRUCTION)) - var/obj/R = new rods_type(drop_location(), rods_amount) - transfer_fingerprints_to(R) - qdel(src) - ..() +/obj/structure/grille/atom_deconstruct(disassembled = TRUE) + var/obj/rods = new rods_type(drop_location(), rods_amount) + transfer_fingerprints_to(rods) /obj/structure/grille/atom_break() . = ..() - if(!broken && !(obj_flags & NO_DECONSTRUCTION)) + if(!broken) icon_state = "brokengrille" set_density(FALSE) atom_integrity = 20 diff --git a/code/game/objects/structures/headpike.dm b/code/game/objects/structures/headpike.dm index b48cafc85d99f..0c29d92d53b98 100644 --- a/code/game/objects/structures/headpike.dm +++ b/code/game/objects/structures/headpike.dm @@ -64,7 +64,7 @@ if(!QDELETED(src)) deconstruct(TRUE) -/obj/structure/headpike/deconstruct(disassembled) +/obj/structure/headpike/atom_deconstruct(disassembled) var/obj/item/bodypart/head/our_head = victim var/obj/item/spear/our_spear = spear victim = null @@ -73,7 +73,6 @@ if(!disassembled) return ..() our_spear?.forceMove(drop_location()) - return ..() /obj/structure/headpike/attack_hand(mob/user, list/modifiers) . = ..() diff --git a/code/game/objects/structures/icemoon/cave_entrance.dm b/code/game/objects/structures/icemoon/cave_entrance.dm index 20f14844c12b5..4401b87d23eca 100644 --- a/code/game/objects/structures/icemoon/cave_entrance.dm +++ b/code/game/objects/structures/icemoon/cave_entrance.dm @@ -40,10 +40,9 @@ GLOBAL_LIST_INIT(ore_probability, list( var/turf/closed/mineral/clearable = potential clearable.ScrapeAway(flags = CHANGETURF_IGNORE_AIR) -/obj/structure/spawner/ice_moon/deconstruct(disassembled) +/obj/structure/spawner/ice_moon/atom_deconstruct(disassembled) destroy_effect() drop_loot() - return ..() /** * Effects and messages created when the spawner is destroyed diff --git a/code/game/objects/structures/kitchen_spike.dm b/code/game/objects/structures/kitchen_spike.dm index 7a7307b0431f5..bfb26d481a28c 100644 --- a/code/game/objects/structures/kitchen_spike.dm +++ b/code/game/objects/structures/kitchen_spike.dm @@ -159,13 +159,12 @@ buckled_mob.pixel_y = buckled_mob.base_pixel_y + PIXEL_Y_OFFSET_LYING REMOVE_TRAIT(buckled_mob, TRAIT_MOVE_UPSIDE_DOWN, REF(src)) -/obj/structure/kitchenspike/deconstruct(disassembled = TRUE) +/obj/structure/kitchenspike/atom_deconstruct(disassembled = TRUE) if(disassembled) var/obj/structure/meatspike_frame = new /obj/structure/kitchenspike_frame(src.loc) transfer_fingerprints_to(meatspike_frame) else new /obj/item/stack/sheet/iron(src.loc, 4) new /obj/item/stack/rods(loc, MEATSPIKE_IRONROD_REQUIREMENT) - qdel(src) #undef MEATSPIKE_IRONROD_REQUIREMENT diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm index 72f28ed82517a..6d65705586a6a 100644 --- a/code/game/objects/structures/lattice.dm +++ b/code/game/objects/structures/lattice.dm @@ -57,10 +57,8 @@ var/turf/T = get_turf(src) return T.attackby(C, user) //hand this off to the turf instead (for building plating, catwalks, etc) -/obj/structure/lattice/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new build_material(get_turf(src), number_of_mats) - qdel(src) +/obj/structure/lattice/atom_deconstruct(disassembled = TRUE) + new build_material(get_turf(src), number_of_mats) /obj/structure/lattice/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) if(the_rcd.mode == RCD_TURF) @@ -113,11 +111,10 @@ C.deconstruct() ..() -/obj/structure/lattice/catwalk/deconstruct() +/obj/structure/lattice/catwalk/atom_deconstruct(disassembled = TRUE) var/turf/T = loc for(var/obj/structure/cable/C in T) C.deconstruct() - ..() /obj/structure/lattice/catwalk/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) if(the_rcd.mode == RCD_DECONSTRUCT) diff --git a/code/game/objects/structures/lavaland/necropolis_tendril.dm b/code/game/objects/structures/lavaland/necropolis_tendril.dm index 6d6b2e6af37af..357fdaa967705 100644 --- a/code/game/objects/structures/lavaland/necropolis_tendril.dm +++ b/code/game/objects/structures/lavaland/necropolis_tendril.dm @@ -42,9 +42,8 @@ GLOBAL_LIST_INIT(tendrils, list()) AddComponent(/datum/component/gps, "Eerie Signal") GLOB.tendrils += src -/obj/structure/spawner/lavaland/deconstruct(disassembled) +/obj/structure/spawner/lavaland/atom_deconstruct(disassembled) new /obj/effect/collapse(loc) - return ..() /obj/structure/spawner/lavaland/examine(mob/user) var/list/examine_messages = ..() diff --git a/code/game/objects/structures/maintenance.dm b/code/game/objects/structures/maintenance.dm index f9ed6d93c1e9f..ecd6f54d2557a 100644 --- a/code/game/objects/structures/maintenance.dm +++ b/code/game/objects/structures/maintenance.dm @@ -303,11 +303,9 @@ at the cost of risking a vicious bite.**/ deconstruct() return TRUE -/obj/structure/steam_vent/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/iron(loc, 1) - new /obj/item/stock_parts/water_recycler(loc, 1) - qdel(src) +/obj/structure/steam_vent/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/iron(loc, 1) + new /obj/item/stock_parts/water_recycler(loc, 1) /** * Creates "steam" smoke, and determines when the vent needs to block line of sight via reset_opacity. diff --git a/code/game/objects/structures/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm index 03e37346c5714..d794f24dd0894 100644 --- a/code/game/objects/structures/mineral_doors.dm +++ b/code/game/objects/structures/mineral_doors.dm @@ -204,14 +204,12 @@ /////////////////////// END TOOL OVERRIDES /////////////////////// -/obj/structure/mineral_door/deconstruct(disassembled = TRUE) +/obj/structure/mineral_door/atom_deconstruct(disassembled = TRUE) var/turf/T = get_turf(src) if(disassembled) new sheetType(T, sheetAmount) else new sheetType(T, max(sheetAmount - 2, 1)) - qdel(src) - /obj/structure/mineral_door/iron name = "iron door" diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index f796bae34cf4d..f15cabd707ec8 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -260,7 +260,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) /obj/structure/mirror/atom_break(damage_flag, mapload) . = ..() - if(broken || (obj_flags & NO_DECONSTRUCTION)) + if(broken) return icon_state = "mirror_broke" if(!mapload) @@ -269,13 +269,11 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28) desc = "Oh no, seven years of bad luck!" broken = TRUE -/obj/structure/mirror/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(!disassembled) - new /obj/item/shard(loc) - else - new /obj/item/wallframe/mirror(loc) - qdel(src) +/obj/structure/mirror/atom_deconstruct(disassembled = TRUE) + if(!disassembled) + new /obj/item/shard(loc) + else + new /obj/item/wallframe/mirror(loc) /obj/structure/mirror/welder_act(mob/living/user, obj/item/I) ..() diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm index 05af991303f92..698bc37c89310 100644 --- a/code/game/objects/structures/morgue.dm +++ b/code/game/objects/structures/morgue.dm @@ -104,10 +104,8 @@ GLOBAL_LIST_EMPTY(bodycontainers) //Let them act as spawnpoints for revenants an return return attack_hand(user) -/obj/structure/bodycontainer/deconstruct(disassembled = TRUE) - if (!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/iron(loc, 5) - qdel(src) +/obj/structure/bodycontainer/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/iron(loc, 5) /obj/structure/bodycontainer/container_resist_act(mob/living/user) if(!locked) @@ -473,9 +471,8 @@ GLOBAL_LIST_EMPTY(crematoriums) connected = null return ..() -/obj/structure/tray/deconstruct(disassembled = TRUE) +/obj/structure/tray/atom_deconstruct(disassembled = TRUE) new /obj/item/stack/sheet/iron (loc, 2) - qdel(src) /obj/structure/tray/attack_paw(mob/user, list/modifiers) return attack_hand(user, modifiers) diff --git a/code/game/objects/structures/noticeboard.dm b/code/game/objects/structures/noticeboard.dm index c737f21e6d9e6..841da89972599 100644 --- a/code/game/objects/structures/noticeboard.dm +++ b/code/game/objects/structures/noticeboard.dm @@ -110,15 +110,13 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/noticeboard, 32) notices-- update_appearance(UPDATE_ICON) -/obj/structure/noticeboard/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(!disassembled) - new /obj/item/stack/sheet/mineral/wood(loc) - else - new /obj/item/wallframe/noticeboard(loc) +/obj/structure/noticeboard/atom_deconstruct(disassembled = TRUE) + if(!disassembled) + new /obj/item/stack/sheet/mineral/wood(loc) + else + new /obj/item/wallframe/noticeboard(loc) for(var/obj/item/content in contents) remove_item(content) - qdel(src) /obj/item/wallframe/noticeboard name = "notice board" diff --git a/code/game/objects/structures/petrified_statue.dm b/code/game/objects/structures/petrified_statue.dm index a752faba40c33..5383436d4dbff 100644 --- a/code/game/objects/structures/petrified_statue.dm +++ b/code/game/objects/structures/petrified_statue.dm @@ -73,7 +73,7 @@ petrified_mob.forceMove(loc) return ..() -/obj/structure/statue/petrified/deconstruct(disassembled = TRUE) +/obj/structure/statue/petrified/atom_deconstruct(disassembled = TRUE) var/destruction_message = "[src] shatters!" if(!disassembled) if(petrified_mob) @@ -89,7 +89,6 @@ destruction_message = "[src] shatters, a solid brain tumbling out!" petrified_mob.dust() visible_message(span_danger(destruction_message)) - qdel(src) /obj/structure/statue/petrified/animate_atom_living(mob/living/owner) if(isnull(petrified_mob)) diff --git a/code/game/objects/structures/pinatas.dm b/code/game/objects/structures/pinatas.dm index 116de95c1676a..63502f12ad5e2 100644 --- a/code/game/objects/structures/pinatas.dm +++ b/code/game/objects/structures/pinatas.dm @@ -41,9 +41,8 @@ if(BURN) playsound(src, 'sound/items/welder.ogg', 100, TRUE) -/obj/structure/pinata/deconstruct(disassembled) +/obj/structure/pinata/atom_deconstruct(disassembled) new debris(get_turf(src)) - return ..() ///An item that when used inhand spawns an immovable pinata /obj/item/pinata @@ -72,7 +71,7 @@ base_icon_state = "pinata_syndie_placed" destruction_loot = 2 debris = /obj/effect/decal/cleanable/wrapping/pinata/syndie - candy_options = list( + candy_options = list( /obj/item/food/bubblegum, /obj/item/food/candy, /obj/item/food/chocolatebar, diff --git a/code/game/objects/structures/plasticflaps.dm b/code/game/objects/structures/plasticflaps.dm index 6dd3eb800a316..a2a1e1c04bc20 100644 --- a/code/game/objects/structures/plasticflaps.dm +++ b/code/game/objects/structures/plasticflaps.dm @@ -124,10 +124,8 @@ return FALSE //If you're not laying down, or a small creature, or a ventcrawler, then no pass. -/obj/structure/plasticflaps/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/plastic/five(loc) - qdel(src) +/obj/structure/plasticflaps/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/plastic/five(loc) /obj/structure/plasticflaps/Initialize(mapload) . = ..() diff --git a/code/game/objects/structures/railings.dm b/code/game/objects/structures/railings.dm index 3604bd06c63c8..95cf4fc58e52e 100644 --- a/code/game/objects/structures/railings.dm +++ b/code/game/objects/structures/railings.dm @@ -98,19 +98,14 @@ deconstruct() return TRUE -/obj/structure/railing/deconstruct(disassembled) - if((obj_flags & NO_DECONSTRUCTION)) - return ..() +/obj/structure/railing/atom_deconstruct(disassembled) var/rods_to_make = istype(src,/obj/structure/railing/corner) ? 1 : 2 var/obj/rod = new item_deconstruct(drop_location(), rods_to_make) transfer_fingerprints_to(rod) - return ..() ///Implements behaviour that makes it possible to unanchor the railing. /obj/structure/railing/wrench_act(mob/living/user, obj/item/I) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return to_chat(user, span_notice("You begin to [anchored ? "unfasten the railing from":"fasten the railing to"] the floor...")) if(I.use_tool(src, user, volume = 75, extra_checks = CALLBACK(src, PROC_REF(check_anchored), anchored))) set_anchored(!anchored) diff --git a/code/game/objects/structures/secure_safe.dm b/code/game/objects/structures/secure_safe.dm index bc73eea6ec056..76c3ab4575f6c 100644 --- a/code/game/objects/structures/secure_safe.dm +++ b/code/game/objects/structures/secure_safe.dm @@ -45,12 +45,11 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/secure_safe, 32) if(mapload) PopulateContents() -/obj/structure/secure_safe/deconstruct(disassembled) +/obj/structure/secure_safe/atom_deconstruct(disassembled) if(!density) //if we're a wall item, we'll drop a wall frame. var/obj/item/wallframe/secure_safe/new_safe = new(get_turf(src)) for(var/obj/item in contents) item.forceMove(new_safe) - return ..() /obj/structure/secure_safe/proc/PopulateContents() new /obj/item/paper(src) diff --git a/code/game/objects/structures/shower.dm b/code/game/objects/structures/shower.dm index c71bd3c7e0cdd..48fa379b41613 100644 --- a/code/game/objects/structures/shower.dm +++ b/code/game/objects/structures/shower.dm @@ -184,9 +184,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/shower, (-16)) /obj/machinery/shower/wrench_act(mob/living/user, obj/item/I) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return - I.play_tool_sound(src) deconstruct() return TRUE diff --git a/code/game/objects/structures/stairs.dm b/code/game/objects/structures/stairs.dm index 169f76a4b5708..a26354211dc27 100644 --- a/code/game/objects/structures/stairs.dm +++ b/code/game/objects/structures/stairs.dm @@ -209,9 +209,8 @@ deconstruct(TRUE) return TRUE -/obj/structure/stairs_frame/deconstruct(disassembled = TRUE) +/obj/structure/stairs_frame/atom_deconstruct(disassembled = TRUE) new frame_stack(get_turf(src), frame_stack_amount) - qdel(src) /obj/structure/stairs_frame/attackby(obj/item/attacked_by, mob/user, params) if(!isstack(attacked_by)) diff --git a/code/game/objects/structures/table_frames.dm b/code/game/objects/structures/table_frames.dm index ba654d10b912c..331667c506e40 100644 --- a/code/game/objects/structures/table_frames.dm +++ b/code/game/objects/structures/table_frames.dm @@ -75,9 +75,8 @@ T.set_custom_materials(custom_materials) qdel(src) -/obj/structure/table_frame/deconstruct(disassembled = TRUE) +/obj/structure/table_frame/atom_deconstruct(disassembled = TRUE) new framestack(get_turf(src), framestackamount) - qdel(src) /obj/structure/table_frame/narsie_act() new /obj/structure/table_frame/wood(src.loc) diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 997d23c413962..eff8aa8ba36b3 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -73,7 +73,7 @@ context[SCREENTIP_CONTEXT_RMB] = "Deal card faceup" . = CONTEXTUAL_SCREENTIP_SET - if(!(obj_flags & NO_DECONSTRUCTION) && deconstruction_ready) + if(deconstruction_ready) if(held_item.tool_behaviour == TOOL_SCREWDRIVER) context[SCREENTIP_CONTEXT_RMB] = "Disassemble" . = CONTEXTUAL_SCREENTIP_SET @@ -207,7 +207,7 @@ pushed_mob.add_mood_event("table", /datum/mood_event/table_limbsmash, banged_limb) /obj/structure/table/screwdriver_act_secondary(mob/living/user, obj/item/tool) - if(obj_flags & NO_DECONSTRUCTION || !deconstruction_ready) + if(!deconstruction_ready) return FALSE to_chat(user, span_notice("You start disassembling [src]...")) if(tool.use_tool(src, user, 2 SECONDS, volume=50)) @@ -215,12 +215,12 @@ return ITEM_INTERACT_SUCCESS /obj/structure/table/wrench_act_secondary(mob/living/user, obj/item/tool) - if(obj_flags & NO_DECONSTRUCTION || !deconstruction_ready) + if(!deconstruction_ready) return FALSE to_chat(user, span_notice("You start deconstructing [src]...")) if(tool.use_tool(src, user, 4 SECONDS, volume=50)) playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE) - deconstruct(TRUE, 1) + deconstruct(TRUE) return ITEM_INTERACT_SUCCESS /obj/structure/table/attackby(obj/item/I, mob/living/user, params) @@ -297,20 +297,14 @@ /obj/structure/table/proc/AfterPutItemOnTable(obj/item/thing, mob/living/user) return -/obj/structure/table/deconstruct(disassembled = TRUE, wrench_disassembly = 0) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/turf/T = get_turf(src) - if(buildstack) - new buildstack(T, buildstackamount) - else - for(var/i in custom_materials) - var/datum/material/M = i - new M.sheet_type(T, FLOOR(custom_materials[M] / SHEET_MATERIAL_AMOUNT, 1)) - if(!wrench_disassembly) - new frame(T) - else - new framestack(T, framestackamount) - qdel(src) +/obj/structure/table/atom_deconstruct(disassembled = TRUE) + var/turf/target_turf = get_turf(src) + if(buildstack) + new buildstack(target_turf, buildstackamount) + else + for(var/datum/material/mat in custom_materials) + new mat.sheet_type(target_turf, FLOOR(custom_materials[mat] / SHEET_MATERIAL_AMOUNT, 1)) + new framestack(target_turf, framestackamount) /obj/structure/table/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) if(the_rcd.mode == RCD_DECONSTRUCT) @@ -437,8 +431,7 @@ /obj/structure/table/glass/proc/on_entered(datum/source, atom/movable/AM) SIGNAL_HANDLER - if(obj_flags & NO_DECONSTRUCTION) - return + if(!isliving(AM)) return // Don't break if they're just flying past @@ -469,19 +462,16 @@ victim.Paralyze(100) qdel(src) -/obj/structure/table/glass/deconstruct(disassembled = TRUE, wrench_disassembly = 0) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(disassembled) - ..() - return - else - var/turf/T = get_turf(src) - playsound(T, SFX_SHATTER, 50, TRUE) - - new frame(loc) - new glass_shard_type(loc) +/obj/structure/table/glass/atom_deconstruct(disassembled = TRUE) + if(disassembled) + ..() + return + else + var/turf/T = get_turf(src) + playsound(T, SFX_SHATTER, 50, TRUE) - qdel(src) + new frame(loc) + new glass_shard_type(loc) /obj/structure/table/glass/narsie_act() color = NARSIE_WINDOW_COLOUR @@ -841,10 +831,9 @@ if(isnull(held_item)) return NONE - if(!(obj_flags & NO_DECONSTRUCTION)) - if(held_item.tool_behaviour == TOOL_WRENCH) - context[SCREENTIP_CONTEXT_RMB] = "Deconstruct" - return CONTEXTUAL_SCREENTIP_SET + if(held_item.tool_behaviour == TOOL_WRENCH) + context[SCREENTIP_CONTEXT_RMB] = "Deconstruct" + return CONTEXTUAL_SCREENTIP_SET return NONE @@ -860,8 +849,6 @@ return TRUE /obj/structure/rack/wrench_act_secondary(mob/living/user, obj/item/tool) - if(obj_flags & NO_DECONSTRUCTION) - return NONE tool.play_tool_sound(src) deconstruct(TRUE) return ITEM_INTERACT_SUCCESS @@ -901,12 +888,10 @@ * Rack destruction */ -/obj/structure/rack/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - set_density(FALSE) - var/obj/item/rack_parts/newparts = new(loc) - transfer_fingerprints_to(newparts) - qdel(src) +/obj/structure/rack/atom_deconstruct(disassembled = TRUE) + set_density(FALSE) + var/obj/item/rack_parts/newparts = new(loc) + transfer_fingerprints_to(newparts) /* @@ -935,24 +920,19 @@ context[SCREENTIP_CONTEXT_LMB] = "Construct Rack" return CONTEXTUAL_SCREENTIP_SET - if(!(obj_flags & NO_DECONSTRUCTION)) - if(held_item.tool_behaviour == TOOL_WRENCH) - context[SCREENTIP_CONTEXT_LMB] = "Deconstruct" - return CONTEXTUAL_SCREENTIP_SET + if(held_item.tool_behaviour == TOOL_WRENCH) + context[SCREENTIP_CONTEXT_LMB] = "Deconstruct" + return CONTEXTUAL_SCREENTIP_SET return NONE /obj/item/rack_parts/wrench_act(mob/living/user, obj/item/tool) - if(obj_flags & NO_DECONSTRUCTION) - return NONE tool.play_tool_sound(src) deconstruct(TRUE) return ITEM_INTERACT_SUCCESS -/obj/item/rack_parts/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/iron(drop_location()) - return ..() +/obj/item/rack_parts/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/iron(drop_location()) /obj/item/rack_parts/attack_self(mob/user) if(building) diff --git a/code/game/objects/structures/tank_dispenser.dm b/code/game/objects/structures/tank_dispenser.dm index ec00eb110a7af..2c0b3bdc95bbd 100644 --- a/code/game/objects/structures/tank_dispenser.dm +++ b/code/game/objects/structures/tank_dispenser.dm @@ -103,13 +103,11 @@ return TRUE -/obj/structure/tank_dispenser/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - for(var/X in src) - var/obj/item/I = X - I.forceMove(loc) - new /obj/item/stack/sheet/iron (loc, 2) - qdel(src) +/obj/structure/tank_dispenser/atom_deconstruct(disassembled = TRUE) + for(var/X in src) + var/obj/item/I = X + I.forceMove(loc) + new /obj/item/stack/sheet/iron (loc, 2) /obj/structure/tank_dispenser/proc/dispense(tank_type, mob/receiver) var/existing_tank = locate(tank_type) in src diff --git a/code/game/objects/structures/tank_holder.dm b/code/game/objects/structures/tank_holder.dm index 5b7c9d2ed5534..34284b1f1dd0d 100644 --- a/code/game/objects/structures/tank_holder.dm +++ b/code/game/objects/structures/tank_holder.dm @@ -63,12 +63,11 @@ deconstruct(TRUE) return TRUE -/obj/structure/tank_holder/deconstruct(disassembled = TRUE) +/obj/structure/tank_holder/atom_deconstruct(disassembled = TRUE) var/atom/Tsec = drop_location() new /obj/item/stack/rods(Tsec, 2) if(tank) tank.forceMove(Tsec) - qdel(src) /obj/structure/tank_holder/attack_paw(mob/user, list/modifiers) return attack_hand(user, modifiers) diff --git a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm index 67d3d4c9510fa..b1168302f683f 100644 --- a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm +++ b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm @@ -35,22 +35,16 @@ user.visible_message(span_notice("[user] empties \the [src]."), span_notice("You empty \the [src].")) empty_pod() else - deconstruct(TRUE, user) + deconstruct(TRUE) else return ..() -/obj/structure/transit_tube_pod/deconstruct(disassembled = TRUE, mob/user) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/atom/location = get_turf(src) - if(user) - location = user.loc - add_fingerprint(user) - user.visible_message(span_notice("[user] removes [src]."), span_notice("You remove [src].")) - var/obj/structure/c_transit_tube_pod/R = new/obj/structure/c_transit_tube_pod(location) - transfer_fingerprints_to(R) - R.setDir(dir) - empty_pod(location) - qdel(src) +/obj/structure/transit_tube_pod/atom_deconstruct(disassembled = TRUE) + var/atom/location = get_turf(src) + var/obj/structure/c_transit_tube_pod/tube_pod = new/obj/structure/c_transit_tube_pod(location) + transfer_fingerprints_to(tube_pod) + tube_pod.setDir(dir) + empty_pod(location) /obj/structure/transit_tube_pod/ex_act(severity, target) . = ..() diff --git a/code/game/objects/structures/votingbox.dm b/code/game/objects/structures/votingbox.dm index 00eeeb55ae298..42ccd62509304 100644 --- a/code/game/objects/structures/votingbox.dm +++ b/code/game/objects/structures/votingbox.dm @@ -149,9 +149,8 @@ for(var/atom/movable/AM in contents) AM.forceMove(droppoint) -/obj/structure/votebox/deconstruct(disassembled) +/obj/structure/votebox/atom_deconstruct(disassembled) dump_contents() - . = ..() /obj/structure/votebox/proc/raffle(mob/user) var/list/options = list() diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index eac58d119a8b9..ecdd4bdacdd55 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -83,17 +83,15 @@ icon_state = "toilet[open][cistern]" return ..() -/obj/structure/toilet/deconstruct() - if(!(obj_flags & NO_DECONSTRUCTION)) - for(var/obj/toilet_item in contents) - toilet_item.forceMove(drop_location()) - if(buildstacktype) - new buildstacktype(loc,buildstackamount) - else - for(var/i in custom_materials) - var/datum/material/M = i - new M.sheet_type(loc, FLOOR(custom_materials[M] / SHEET_MATERIAL_AMOUNT, 1)) - ..() +/obj/structure/toilet/atom_deconstruct(dissambled = TRUE) + for(var/obj/toilet_item in contents) + toilet_item.forceMove(drop_location()) + if(buildstacktype) + new buildstacktype(loc,buildstackamount) + else + for(var/i in custom_materials) + var/datum/material/M = i + new M.sheet_type(loc, FLOOR(custom_materials[M] / SHEET_MATERIAL_AMOUNT, 1)) /obj/structure/toilet/attackby(obj/item/I, mob/living/user, params) add_fingerprint(user) @@ -105,7 +103,7 @@ cistern = !cistern update_appearance() return COMPONENT_CANCEL_ATTACK_CHAIN - else if(I.tool_behaviour == TOOL_WRENCH && !(obj_flags & NO_DECONSTRUCTION)) + else if(I.tool_behaviour == TOOL_WRENCH) I.play_tool_sound(src) deconstruct() return TRUE @@ -227,10 +225,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/urinal, 32) exposed = !exposed return TRUE -/obj/structure/urinal/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/wallframe/urinal(loc) - qdel(src) +/obj/structure/urinal/atom_deconstruct(disassembled = TRUE) + new /obj/item/wallframe/urinal(loc) /obj/item/wallframe/urinal name = "urinal frame" @@ -419,7 +415,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink, (-14)) playsound(loc, 'sound/effects/slosh.ogg', 25, TRUE) return - if(O.tool_behaviour == TOOL_WRENCH && !(obj_flags & NO_DECONSTRUCTION)) + if(O.tool_behaviour == TOOL_WRENCH) O.play_tool_sound(src) deconstruct() return @@ -495,12 +491,10 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink, (-14)) else return ..() -/obj/structure/sink/deconstruct() - if(!(obj_flags & NO_DECONSTRUCTION)) - drop_materials() - if(has_water_reclaimer) - new /obj/item/stock_parts/water_recycler(drop_location()) - ..() +/obj/structure/sink/atom_deconstruct(dissambled = TRUE) + drop_materials() + if(has_water_reclaimer) + new /obj/item/stock_parts/water_recycler(drop_location()) /obj/structure/sink/process(seconds_per_tick) // Water reclamation complete? @@ -571,10 +565,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink/kitchen, (-16)) deconstruct() return TRUE -/obj/structure/sinkframe/deconstruct() - if(!(obj_flags & NO_DECONSTRUCTION)) - drop_materials() - return ..() +/obj/structure/sinkframe/atom_deconstruct(dissambled = TRUE) + drop_materials() /obj/structure/sinkframe/proc/drop_materials() for(var/datum/material/material as anything in custom_materials) @@ -725,9 +717,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink/kitchen, (-16)) . = ..() icon_state = "puddle" -/obj/structure/water_source/puddle/deconstruct(disassembled = TRUE) - qdel(src) - //End legacy sink @@ -804,11 +793,10 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink/kitchen, (-16)) playsound(loc, 'sound/effects/curtain.ogg', 50, TRUE) toggle() -/obj/structure/curtain/deconstruct(disassembled = TRUE) +/obj/structure/curtain/atom_deconstruct(disassembled = TRUE) new /obj/item/stack/sheet/cloth (loc, 2) new /obj/item/stack/sheet/plastic (loc, 2) new /obj/item/stack/rods (loc, 1) - qdel(src) /obj/structure/curtain/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) switch(damage_type) @@ -840,10 +828,9 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink/kitchen, (-16)) alpha = 255 opaque_closed = TRUE -/obj/structure/curtain/cloth/deconstruct(disassembled = TRUE) +/obj/structure/curtain/cloth/atom_deconstruct(disassembled = TRUE) new /obj/item/stack/sheet/cloth (loc, 4) new /obj/item/stack/rods (loc, 1) - qdel(src) /obj/structure/curtain/cloth/fancy icon_type = "cur_fancy" diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 730735b8b3a22..4fd6c061068c5 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -78,8 +78,6 @@ /obj/structure/window/examine(mob/user) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return switch(state) if(WINDOW_SCREWED_TO_FRAME) @@ -210,8 +208,6 @@ return ITEM_INTERACT_SUCCESS /obj/structure/window/screwdriver_act(mob/living/user, obj/item/tool) - if(obj_flags & NO_DECONSTRUCTION) - return switch(state) if(WINDOW_SCREWED_TO_FRAME) @@ -240,7 +236,7 @@ /obj/structure/window/wrench_act(mob/living/user, obj/item/tool) if(anchored) return FALSE - if((obj_flags & NO_DECONSTRUCTION) || (reinf && state >= RWINDOW_FRAME_BOLTED)) + if(reinf && state >= RWINDOW_FRAME_BOLTED) return FALSE to_chat(user, span_notice("You begin to disassemble [src]...")) @@ -255,7 +251,7 @@ return ITEM_INTERACT_SUCCESS /obj/structure/window/crowbar_act(mob/living/user, obj/item/tool) - if(!anchored || (obj_flags & NO_DECONSTRUCTION)) + if(!anchored) return FALSE switch(state) @@ -330,18 +326,13 @@ playsound(src, 'sound/items/welder.ogg', 100, TRUE) -/obj/structure/window/deconstruct(disassembled = TRUE) - if(QDELETED(src)) - return +/obj/structure/window/atom_deconstruct(disassembled = TRUE) if(!disassembled) playsound(src, break_sound, 70, TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - for(var/obj/item/shard/debris in spawn_debris(drop_location())) - transfer_fingerprints_to(debris) // transfer fingerprints to shards only - qdel(src) + for(var/obj/item/shard/debris in spawn_debris(drop_location())) + transfer_fingerprints_to(debris) // transfer fingerprints to shards only update_nearby_icons() - ///Spawns shard and debris decal based on the glass_material_datum, spawns rods if window is reinforned and number of shards/rods is determined by the window being fulltile or not. /obj/structure/window/proc/spawn_debris(location) var/datum/material/glass_material_ref = GET_MATERIAL_REF(glass_material_datum) @@ -480,9 +471,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/unanchored/spawner, 0) return FALSE /obj/structure/window/reinforced/attackby_secondary(obj/item/tool, mob/user, params) - if(obj_flags & NO_DECONSTRUCTION) - return ..() - switch(state) if(RWINDOW_SECURE) if(tool.tool_behaviour == TOOL_WELDER) @@ -546,7 +534,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/unanchored/spawner, 0) /obj/structure/window/reinforced/crowbar_act(mob/living/user, obj/item/tool) if(!anchored) return FALSE - if((obj_flags & NO_DECONSTRUCTION) || (state != WINDOW_OUT_OF_FRAME)) + if(state != WINDOW_OUT_OF_FRAME) return FALSE to_chat(user, span_notice("You begin to lever the window back into the frame...")) if(tool.use_tool(src, user, 10 SECONDS, volume = 75, extra_checks = CALLBACK(src, PROC_REF(check_state_and_anchored), state, anchored))) @@ -561,8 +549,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/unanchored/spawner, 0) /obj/structure/window/reinforced/examine(mob/user) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return + switch(state) if(RWINDOW_SECURE) . += span_notice("It's been screwed in with one way screws, you'd need to heat them to have any chance of backing them out.") @@ -803,9 +790,9 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/reinforced/tinted/frosted/spaw /obj/structure/window/reinforced/shuttle/indestructible name = "hardened shuttle window" - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION flags_1 = PREVENT_CLICK_UNDER_1 resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION /obj/structure/window/reinforced/shuttle/indestructible/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) return FALSE diff --git a/code/modules/antagonists/heretic/structures/mawed_crucible.dm b/code/modules/antagonists/heretic/structures/mawed_crucible.dm index 7c1208b1e44bf..8e5410f0f6751 100644 --- a/code/modules/antagonists/heretic/structures/mawed_crucible.dm +++ b/code/modules/antagonists/heretic/structures/mawed_crucible.dm @@ -21,8 +21,7 @@ . = ..() break_message = span_warning("[src] falls apart with a thud!") -/obj/structure/destructible/eldritch_crucible/deconstruct(disassembled = TRUE) - +/obj/structure/destructible/eldritch_crucible/atom_deconstruct(disassembled = TRUE) // Create a spillage if we were destroyed with leftover mass if(current_mass) break_message = span_warning("[src] falls apart with a thud, spilling shining extract everywhere!") diff --git a/code/modules/art/statues.dm b/code/modules/art/statues.dm index caebda5076605..428bb5d8e06ca 100644 --- a/code/modules/art/statues.dm +++ b/code/modules/art/statues.dm @@ -30,35 +30,30 @@ /obj/structure/statue/wrench_act(mob/living/user, obj/item/tool) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return FALSE default_unfasten_wrench(user, tool) return ITEM_INTERACT_SUCCESS /obj/structure/statue/attackby(obj/item/W, mob/living/user, params) add_fingerprint(user) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(W.tool_behaviour == TOOL_WELDER) - if(!W.tool_start_check(user, amount=1)) - return FALSE - user.balloon_alert(user, "slicing apart...") - if(W.use_tool(src, user, 40, volume=50)) - deconstruct(TRUE) - return + if(W.tool_behaviour == TOOL_WELDER) + if(!W.tool_start_check(user, amount=1)) + return FALSE + user.balloon_alert(user, "slicing apart...") + if(W.use_tool(src, user, 40, volume=50)) + deconstruct(TRUE) + return return ..() /obj/structure/statue/AltClick(mob/user) return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation -/obj/structure/statue/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/amount_mod = disassembled ? 0 : -2 - for(var/mat in custom_materials) - var/datum/material/custom_material = GET_MATERIAL_REF(mat) - var/amount = max(0,round(custom_materials[mat]/SHEET_MATERIAL_AMOUNT) + amount_mod) - if(amount > 0) - new custom_material.sheet_type(drop_location(), amount) - qdel(src) +/obj/structure/statue/atom_deconstruct(disassembled = TRUE) + var/amount_mod = disassembled ? 0 : -2 + for(var/mat in custom_materials) + var/datum/material/custom_material = GET_MATERIAL_REF(mat) + var/amount = max(0,round(custom_materials[mat]/SHEET_MATERIAL_AMOUNT) + amount_mod) + if(amount > 0) + new custom_material.sheet_type(drop_location(), amount) //////////////////////////////////////STATUES///////////////////////////////////////////////////////////// ////////////////////////uranium/////////////////////////////////// diff --git a/code/modules/atmospherics/machinery/components/tank.dm b/code/modules/atmospherics/machinery/components/tank.dm index cf18488f0522c..8df616c179cca 100644 --- a/code/modules/atmospherics/machinery/components/tank.dm +++ b/code/modules/atmospherics/machinery/components/tank.dm @@ -459,11 +459,10 @@ var/welder_hint = EXAMINE_HINT("welder") . += span_notice("The plating has been firmly attached and would need a [crowbar_hint] to detach, but still needs to be sealed by a [welder_hint].") -/obj/structure/tank_frame/deconstruct(disassembled) +/obj/structure/tank_frame/atom_deconstruct(disassembled) if(disassembled) for(var/datum/material/mat as anything in custom_materials) new mat.sheet_type(drop_location(), custom_materials[mat] / SHEET_MATERIAL_AMOUNT) - return ..() /obj/structure/tank_frame/update_icon(updates) . = ..() diff --git a/code/modules/economy/holopay.dm b/code/modules/economy/holopay.dm index 3f11d0962050c..15247d19d572f 100644 --- a/code/modules/economy/holopay.dm +++ b/code/modules/economy/holopay.dm @@ -65,9 +65,8 @@ if(BURN) playsound(loc, 'sound/weapons/egloves.ogg', 80, TRUE) -/obj/structure/holopay/deconstruct() +/obj/structure/holopay/atom_deconstruct(dissambled = TRUE) dissipate() - return ..() /obj/structure/holopay/Destroy() linked_card?.my_store = null diff --git a/code/modules/food_and_drinks/machinery/griddle.dm b/code/modules/food_and_drinks/machinery/griddle.dm index f997b049feb2c..b54a470897f5b 100644 --- a/code/modules/food_and_drinks/machinery/griddle.dm +++ b/code/modules/food_and_drinks/machinery/griddle.dm @@ -37,8 +37,6 @@ /obj/machinery/griddle/crowbar_act(mob/living/user, obj/item/I) . = ..() - if(obj_flags & NO_DECONSTRUCTION) - return if(default_deconstruction_crowbar(I, ignore_panel = TRUE)) return variant = rand(1,3) diff --git a/code/modules/holodeck/items.dm b/code/modules/holodeck/items.dm index eb0261739adbf..3d80ef6d968c0 100644 --- a/code/modules/holodeck/items.dm +++ b/code/modules/holodeck/items.dm @@ -140,7 +140,7 @@ for (var/list/zlevel_turfs as anything in currentarea.get_zlevel_turf_lists()) for(var/turf/area_turf as anything in zlevel_turfs) for(var/obj/structure/window/barrier in area_turf) - if((barrier.obj_flags & NO_DECONSTRUCTION) || (barrier.flags_1 & HOLOGRAM_1))// Just in case: only holo-windows + if(barrier.flags_1 & HOLOGRAM_1)// Just in case: only holo-windows qdel(barrier) for(var/mob/contestant in area_turf) diff --git a/code/modules/hydroponics/beekeeping/beebox.dm b/code/modules/hydroponics/beekeeping/beebox.dm index 6636fedd25cab..521afd6b53903 100644 --- a/code/modules/hydroponics/beekeeping/beebox.dm +++ b/code/modules/hydroponics/beekeeping/beebox.dm @@ -249,7 +249,7 @@ visible_message(span_notice("[user] removes the queen from the apiary.")) queen_bee = null -/obj/structure/beebox/deconstruct(disassembled = TRUE) +/obj/structure/beebox/atom_deconstruct(disassembled = TRUE) new /obj/item/stack/sheet/mineral/wood (loc, 20) for(var/mob/living/basic/bee/worker as anything in bees) if(worker.loc == src) @@ -260,7 +260,6 @@ if(frame.loc == src) frame.forceMove(get_turf(src)) honey_frames -= frame - qdel(src) /obj/structure/beebox/unwrenched anchored = FALSE diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index 0752d418a4eff..cc432d4bbad85 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -1164,6 +1164,12 @@ self_sustaining_overlay_icon_state = null maxnutri = 15 +/obj/machinery/hydroponics/soil/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver) + return NONE + +/obj/machinery/hydroponics/soil/default_deconstruction_crowbar(obj/item/crowbar, ignore_panel, custom_deconstruct) + return NONE + /obj/machinery/hydroponics/soil/update_icon(updates=ALL) . = ..() if(self_sustaining) diff --git a/code/modules/library/bookcase.dm b/code/modules/library/bookcase.dm index be2beca42bad7..822e4ae583c97 100644 --- a/code/modules/library/bookcase.dm +++ b/code/modules/library/bookcase.dm @@ -172,14 +172,13 @@ choice.forceMove(drop_location()) update_appearance() -/obj/structure/bookcase/deconstruct(disassembled = TRUE) +/obj/structure/bookcase/atom_deconstruct(disassembled = TRUE) var/atom/Tsec = drop_location() new /obj/item/stack/sheet/mineral/wood(Tsec, 4) for(var/obj/item/I in contents) if(!isbook(I)) //Wake me up inside continue I.forceMove(Tsec) - return ..() /obj/structure/bookcase/update_icon_state() if(state == BOOKCASE_UNANCHORED || state == BOOKCASE_ANCHORED) diff --git a/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm b/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm index 97a543fa7e727..3c29a6a39450c 100644 --- a/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm +++ b/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm @@ -107,7 +107,7 @@ /obj/structure/sink/oil_well/attackby(obj/item/O, mob/living/user, params) flick("puddle-oil-splash",src) - if(O.tool_behaviour == TOOL_SHOVEL && !(obj_flags & NO_DECONSTRUCTION)) //attempt to deconstruct the puddle with a shovel + if(O.tool_behaviour == TOOL_SHOVEL) //attempt to deconstruct the puddle with a shovel to_chat(user, "You fill in the oil well with soil.") O.play_tool_sound(src) deconstruct() diff --git a/code/modules/mapfluff/ruins/objects_and_mobs/ash_walker_den.dm b/code/modules/mapfluff/ruins/objects_and_mobs/ash_walker_den.dm index a1391f92ed35e..21c96f0aeaa10 100644 --- a/code/modules/mapfluff/ruins/objects_and_mobs/ash_walker_den.dm +++ b/code/modules/mapfluff/ruins/objects_and_mobs/ash_walker_den.dm @@ -35,11 +35,10 @@ STOP_PROCESSING(SSprocessing, src) return ..() -/obj/structure/lavaland/ash_walker/deconstruct(disassembled) +/obj/structure/lavaland/ash_walker/atom_deconstruct(disassembled) var/core_to_drop = pick(subtypesof(/obj/item/assembly/signaler/anomaly)) new core_to_drop (get_step(loc, pick(GLOB.alldirs))) new /obj/effect/collapse(loc) - return ..() /obj/structure/lavaland/ash_walker/process() consume() diff --git a/code/modules/mining/abandoned_crates.dm b/code/modules/mining/abandoned_crates.dm index ce42eaa43c28d..5022dac212c56 100644 --- a/code/modules/mining/abandoned_crates.dm +++ b/code/modules/mining/abandoned_crates.dm @@ -121,7 +121,7 @@ return return ..() -/obj/structure/closet/crate/secure/loot/deconstruct(disassembled = TRUE) +/obj/structure/closet/crate/secure/loot/atom_deconstruct(disassembled = TRUE) if(locked) boom() return diff --git a/code/modules/mining/equipment/marker_beacons.dm b/code/modules/mining/equipment/marker_beacons.dm index 67eb767f7673e..38dda48d345e7 100644 --- a/code/modules/mining/equipment/marker_beacons.dm +++ b/code/modules/mining/equipment/marker_beacons.dm @@ -99,12 +99,10 @@ GLOBAL_LIST_INIT(marker_beacon_colors, sort_list(list( picked_color = set_color update_appearance() -/obj/structure/marker_beacon/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/obj/item/stack/marker_beacon/M = new(loc) - M.picked_color = picked_color - M.update_appearance() - qdel(src) +/obj/structure/marker_beacon/atom_deconstruct(disassembled = TRUE) + var/obj/item/stack/marker_beacon/beacon = new(loc) + beacon.picked_color = picked_color + beacon.update_appearance() /obj/structure/marker_beacon/examine(mob/user) . = ..() diff --git a/code/modules/mining/equipment/survival_pod.dm b/code/modules/mining/equipment/survival_pod.dm index f4463434066c7..d40589dd3f8ab 100644 --- a/code/modules/mining/equipment/survival_pod.dm +++ b/code/modules/mining/equipment/survival_pod.dm @@ -214,8 +214,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/door/window/survival_pod/left, 0) /obj/item/gps/computer/wrench_act(mob/living/user, obj/item/I) ..() - if(obj_flags & NO_DECONSTRUCTION) - return TRUE user.visible_message(span_warning("[user] disassembles [src]."), span_notice("You start to disassemble [src]..."), span_hear("You hear clanking and banging noises.")) diff --git a/code/modules/mining/satchel_ore_box.dm b/code/modules/mining/satchel_ore_box.dm index 3b2a5ce054c1d..b94796b161433 100644 --- a/code/modules/mining/satchel_ore_box.dm +++ b/code/modules/mining/satchel_ore_box.dm @@ -19,13 +19,11 @@ for(var/obj/item/weapon in src) weapon.forceMove(drop) -/obj/structure/ore_box/deconstruct(disassembled = TRUE) +/obj/structure/ore_box/atom_deconstruct(disassembled = TRUE) new /obj/item/stack/sheet/mineral/wood(loc, 4) dump_box_contents() - return ..() - /obj/structure/ore_box/add_context(atom/source, list/context, obj/item/held_item, mob/user) . = NONE if(isnull(held_item)) diff --git a/code/modules/mob/living/basic/lavaland/gutlunchers/gutluncher_foodtrough.dm b/code/modules/mob/living/basic/lavaland/gutlunchers/gutluncher_foodtrough.dm index 1ac43c13eb443..734d431912f47 100644 --- a/code/modules/mob/living/basic/lavaland/gutlunchers/gutluncher_foodtrough.dm +++ b/code/modules/mob/living/basic/lavaland/gutlunchers/gutluncher_foodtrough.dm @@ -22,11 +22,8 @@ list_of_materials -= mover.type return ..() -/obj/structure/ore_container/gutlunch_trough/deconstruct(disassembled = TRUE) - if(obj_flags & NO_DECONSTRUCTION) - return +/obj/structure/ore_container/gutlunch_trough/atom_deconstruct(disassembled = TRUE) new /obj/item/stack/sheet/mineral/wood(drop_location(), 5) - qdel(src) /obj/structure/ore_container/gutlunch_trough/update_overlays() . = ..() diff --git a/code/modules/mob/living/brain/MMI.dm b/code/modules/mob/living/brain/MMI.dm index 74e5931163b49..56693b20b367b 100644 --- a/code/modules/mob/living/brain/MMI.dm +++ b/code/modules/mob/living/brain/MMI.dm @@ -289,10 +289,9 @@ brainmob.emp_damage = min(brainmob.emp_damage + rand(0,10), 30) brainmob.emote("alarm") -/obj/item/mmi/deconstruct(disassembled = TRUE) +/obj/item/mmi/atom_deconstruct(disassembled = TRUE) if(brain) eject_brain() - qdel(src) /obj/item/mmi/examine(mob/user) . = ..() diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm index da3e378ef30a5..f47210901df0b 100644 --- a/code/modules/modular_computers/computers/item/computer.dm +++ b/code/modules/modular_computers/computers/item/computer.dm @@ -901,20 +901,18 @@ update_appearance() return ITEM_INTERACT_SUCCESS -/obj/item/modular_computer/deconstruct(disassembled = TRUE) +/obj/item/modular_computer/atom_deconstruct(disassembled = TRUE) remove_pai() eject_aicard() - if(!(obj_flags & NO_DECONSTRUCTION)) - if (disassembled) - internal_cell?.forceMove(drop_location()) - computer_id_slot?.forceMove(drop_location()) - inserted_disk?.forceMove(drop_location()) - new /obj/item/stack/sheet/iron(drop_location(), steel_sheet_cost) - else - physical.visible_message(span_notice("\The [src] breaks apart!")) - new /obj/item/stack/sheet/iron(drop_location(), round(steel_sheet_cost * 0.5)) + if (disassembled) + internal_cell?.forceMove(drop_location()) + computer_id_slot?.forceMove(drop_location()) + inserted_disk?.forceMove(drop_location()) + new /obj/item/stack/sheet/iron(drop_location(), steel_sheet_cost) + else + physical.visible_message(span_notice("\The [src] breaks apart!")) + new /obj/item/stack/sheet/iron(drop_location(), round(steel_sheet_cost * 0.5)) relay_qdel() - return ..() // Ejects the inserted intellicard, if one exists. Used when the computer is deconstructed. /obj/item/modular_computer/proc/eject_aicard() diff --git a/code/modules/paperwork/filingcabinet.dm b/code/modules/paperwork/filingcabinet.dm index 140bdffcf8767..8a62f6a87b989 100644 --- a/code/modules/paperwork/filingcabinet.dm +++ b/code/modules/paperwork/filingcabinet.dm @@ -37,12 +37,10 @@ if(I.w_class < WEIGHT_CLASS_NORMAL) //there probably shouldn't be anything placed ontop of filing cabinets in a map that isn't meant to go in them I.forceMove(src) -/obj/structure/filingcabinet/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/iron(loc, 2) - for(var/obj/item/I in src) - I.forceMove(loc) - qdel(src) +/obj/structure/filingcabinet/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/iron(loc, 2) + for(var/obj/item/obj in src) + obj.forceMove(loc) /obj/structure/filingcabinet/attackby(obj/item/P, mob/living/user, params) var/list/modifiers = params2list(params) diff --git a/code/modules/paperwork/paper_cutter.dm b/code/modules/paperwork/paper_cutter.dm index 9878249a6d12d..ae93a1daad870 100644 --- a/code/modules/paperwork/paper_cutter.dm +++ b/code/modules/paperwork/paper_cutter.dm @@ -61,8 +61,7 @@ return CONTEXTUAL_SCREENTIP_SET -/obj/item/papercutter/deconstruct(disassembled) - ..() +/obj/item/papercutter/atom_deconstruct(disassembled) if(!disassembled) return diff --git a/code/modules/paperwork/paperbin.dm b/code/modules/paperwork/paperbin.dm index 86db803322f05..3d7177dcb3e01 100644 --- a/code/modules/paperwork/paperbin.dm +++ b/code/modules/paperwork/paperbin.dm @@ -240,7 +240,7 @@ if(total_paper == 0) deconstruct(FALSE) -/obj/item/paper_bin/bundlenatural/deconstruct(disassembled) +/obj/item/paper_bin/bundlenatural/atom_deconstruct(disassembled) dump_contents(drop_location()) return ..() diff --git a/code/modules/photography/photos/frame.dm b/code/modules/photography/photos/frame.dm index 4fbe3e034d88c..9efde283e0767 100644 --- a/code/modules/photography/photos/frame.dm +++ b/code/modules/photography/photos/frame.dm @@ -173,18 +173,15 @@ if(framed) . += framed -/obj/structure/sign/picture_frame/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/obj/item/wallframe/picture/F = new /obj/item/wallframe/picture(loc) - if(framed) - F.displayed = framed - set_and_save_framed(null) - if(contents.len) - var/obj/item/I = pick(contents) - I.forceMove(F) - F.update_appearance() - qdel(src) - +/obj/structure/sign/picture_frame/atom_deconstruct(disassembled = TRUE) + var/obj/item/wallframe/picture/showcase = new /obj/item/wallframe/picture(loc) + if(framed) + showcase.displayed = framed + set_and_save_framed(null) + if(contents.len) + var/obj/item/I = pick(contents) + I.forceMove(showcase) + showcase.update_appearance() /obj/structure/sign/picture_frame/showroom name = "distinguished crew display" diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index 4480dc981efc3..ffda41a42b0b4 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -141,11 +141,9 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri return ..() // then go ahead and delete the cable -/obj/structure/cable/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/obj/item/stack/cable_coil/cable = new(drop_location(), 1) - cable.set_cable_color(cable_color) - qdel(src) +/obj/structure/cable/atom_deconstruct(disassembled = TRUE) + var/obj/item/stack/cable_coil/cable = new(drop_location(), 1) + cable.set_cable_color(cable_color) /////////////////////////////////// // General procedures diff --git a/code/modules/power/lighting/light_construct.dm b/code/modules/power/lighting/light_construct.dm index 905ae72c2e38b..8b79c33d69bcb 100644 --- a/code/modules/power/lighting/light_construct.dm +++ b/code/modules/power/lighting/light_construct.dm @@ -162,10 +162,8 @@ if(attacking_blob && attacking_blob.loc == loc) qdel(src) -/obj/structure/light_construct/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - new /obj/item/stack/sheet/iron(loc, sheets_refunded) - qdel(src) +/obj/structure/light_construct/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/iron(loc, sheets_refunded) /obj/structure/light_construct/small name = "small light fixture frame" diff --git a/code/modules/power/pipecleaners.dm b/code/modules/power/pipecleaners.dm index 2f18bab660a1c..2a41c70bdfe10 100644 --- a/code/modules/power/pipecleaners.dm +++ b/code/modules/power/pipecleaners.dm @@ -106,15 +106,13 @@ By design, d1 is the smallest direction and d2 is the highest QDEL_NULL(stored) return ..() // then go ahead and delete the pipe_cleaner -/obj/structure/pipe_cleaner/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/turf/T = get_turf(loc) - if(T) - stored.forceMove(T) - stored = null - else - qdel(stored) - qdel(src) +/obj/structure/pipe_cleaner/atom_deconstruct(disassembled = TRUE) + var/turf/location = get_turf(loc) + if(location) + stored.forceMove(location) + stored = null + else + qdel(stored) /////////////////////////////////// // General procedures diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm index bacef74180b02..d406e9f489f08 100644 --- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm +++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm @@ -570,8 +570,7 @@ /obj/machinery/chem_dispenser/drinks/fullupgrade //fully ugpraded stock parts, emagged desc = "Contains a large reservoir of soft drinks. This model has had its safeties shorted out." - obj_flags = CAN_BE_HIT | EMAGGED | NO_DECONSTRUCTION - circuit = /obj/item/circuitboard/machine/chem_dispenser/drinks/fullupgrade + obj_flags = CAN_BE_HIT | EMAGGED /obj/machinery/chem_dispenser/drinks/fullupgrade/Initialize(mapload) . = ..() @@ -630,7 +629,7 @@ /obj/machinery/chem_dispenser/drinks/beer/fullupgrade //fully ugpraded stock parts, emagged desc = "Contains a large reservoir of the good stuff. This model has had its safeties shorted out." - obj_flags = CAN_BE_HIT | EMAGGED | NO_DECONSTRUCTION + obj_flags = CAN_BE_HIT | EMAGGED circuit = /obj/item/circuitboard/machine/chem_dispenser/drinks/beer/fullupgrade /obj/machinery/chem_dispenser/drinks/beer/fullupgrade/Initialize(mapload) @@ -654,7 +653,6 @@ /obj/machinery/chem_dispenser/mutagensaltpeter name = "botanical chemical dispenser" desc = "Creates and dispenses chemicals useful for botany." - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION circuit = /obj/item/circuitboard/machine/chem_dispenser/mutagensaltpeter /// The default list of dispensable reagents available in the mutagensaltpeter chem dispenser @@ -680,7 +678,7 @@ /obj/machinery/chem_dispenser/fullupgrade //fully ugpraded stock parts, emagged desc = "Creates and dispenses chemicals. This model has had its safeties shorted out." - obj_flags = CAN_BE_HIT | EMAGGED | NO_DECONSTRUCTION + obj_flags = CAN_BE_HIT | EMAGGED circuit = /obj/item/circuitboard/machine/chem_dispenser/fullupgrade /obj/machinery/chem_dispenser/fullupgrade/Initialize(mapload) diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm index 5dd5e8b93dd22..b3238f7349392 100644 --- a/code/modules/reagents/reagent_dispenser.dm +++ b/code/modules/reagents/reagent_dispenser.dm @@ -196,12 +196,9 @@ explosion(src, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 6, flame_range = 8) qdel(src) -/obj/structure/reagent_dispensers/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(!disassembled) - boom() - else - qdel(src) +/obj/structure/reagent_dispensers/atom_deconstruct(disassembled = TRUE) + if(!disassembled) + boom() /obj/structure/reagent_dispensers/proc/tank_leak() if(leaking && reagents && reagents.total_volume >= amount_to_leak) diff --git a/code/modules/recycling/disposal/pipe.dm b/code/modules/recycling/disposal/pipe.dm index 69519874cd2ca..9a1ad786e7220 100644 --- a/code/modules/recycling/disposal/pipe.dm +++ b/code/modules/recycling/disposal/pipe.dm @@ -170,27 +170,24 @@ return TRUE // called when pipe is cut with welder -/obj/structure/disposalpipe/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(disassembled) - if(spawn_pipe) - var/obj/structure/disposalconstruct/construct = stored - if(!construct) // Don't have something? Make one now - construct = new /obj/structure/disposalconstruct(src, null, SOUTH, FALSE, src) - stored = null - construct.forceMove(loc) - transfer_fingerprints_to(construct) - construct.setDir(dir) - spawn_pipe = FALSE - else - var/turf/T = get_turf(src) - for(var/D in GLOB.cardinals) - if(D & dpdir) - var/obj/structure/disposalpipe/broken/P = new(T) - P.setDir(D) +/obj/structure/disposalpipe/atom_deconstruct(disassembled = TRUE) + if(disassembled) + if(spawn_pipe) + var/obj/structure/disposalconstruct/construct = stored + if(!construct) // Don't have something? Make one now + construct = new /obj/structure/disposalconstruct(src, null, SOUTH, FALSE, src) + stored = null + construct.forceMove(loc) + transfer_fingerprints_to(construct) + construct.setDir(dir) + spawn_pipe = FALSE + else + var/turf/location = get_turf(src) + for(var/dir in GLOB.cardinals) + if(dir & dpdir) + var/obj/structure/disposalpipe/broken/pipe = new(location) + pipe.setDir(dir) spew_forth() - qdel(src) - /obj/structure/disposalpipe/singularity_pull(S, current_size) ..() @@ -323,9 +320,6 @@ spawn_pipe = FALSE anchored = FALSE -/obj/structure/disposalpipe/broken/deconstruct() - qdel(src) - /obj/structure/disposalpipe/rotator icon_state = "pipe-r1" initialize_dirs = DISP_DIR_LEFT | DISP_DIR_RIGHT | DISP_DIR_FLIP diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm index a178bcd6ad5ff..278030fbc44fb 100644 --- a/code/modules/recycling/sortingmachinery.dm +++ b/code/modules/recycling/sortingmachinery.dm @@ -51,10 +51,9 @@ if(EXPLODE_LIGHT) SSexplosions.low_mov_atom += contents -/obj/item/delivery/deconstruct() +/obj/item/delivery/atom_deconstruct(dissambled = TRUE) unwrap_contents() post_unwrap_contents() - return ..() /obj/item/delivery/examine(mob/user) . = ..() diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 58e91646c0fee..7cfbcf05e5e00 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -1085,10 +1085,11 @@ bodypart_overlays -= overlay overlay.removed_from_limb(src) -/obj/item/bodypart/deconstruct(disassembled = TRUE) +/obj/item/bodypart/atom_deconstruct(disassembled = TRUE) SHOULD_CALL_PARENT(TRUE) drop_organs() + return ..() /// INTERNAL PROC, DO NOT USE diff --git a/code/modules/transport/tram/tram_structures.dm b/code/modules/transport/tram/tram_structures.dm index 74532d87be76d..f868fe21c4816 100644 --- a/code/modules/transport/tram/tram_structures.dm +++ b/code/modules/transport/tram/tram_structures.dm @@ -212,14 +212,12 @@ return ..() -/obj/structure/tram/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(disassembled) - new girder_type(loc) - if(mineral_amount) - for(var/i in 1 to mineral_amount) - new mineral(loc) - qdel(src) +/obj/structure/tram/atom_deconstruct(disassembled = TRUE) + if(disassembled) + new girder_type(loc) + if(mineral_amount) + for(var/i in 1 to mineral_amount) + new mineral(loc) /obj/structure/tram/attackby(obj/item/item, mob/user, params) . = ..() diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm index cf966727abb74..4a37ba6cc9a64 100644 --- a/code/modules/vending/_vending.dm +++ b/code/modules/vending/_vending.dm @@ -1142,7 +1142,7 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock) /obj/machinery/vending/exchange_parts(mob/user, obj/item/storage/part_replacer/replacer) if(!istype(replacer)) return FALSE - if((obj_flags & NO_DECONSTRUCTION) && !replacer.works_from_distance) + if(!replacer.works_from_distance) return FALSE if(!component_parts || !refill_canister) return FALSE diff --git a/code/modules/wiremod/shell/dispenser.dm b/code/modules/wiremod/shell/dispenser.dm index 4ea2d03c9d706..4a00f7fed88d0 100644 --- a/code/modules/wiremod/shell/dispenser.dm +++ b/code/modules/wiremod/shell/dispenser.dm @@ -18,10 +18,9 @@ var/list/obj/item/stored_items = list() var/locked = FALSE -/obj/structure/dispenser_bot/deconstruct(disassembled) +/obj/structure/dispenser_bot/atom_deconstruct(disassembled = TRUE) for(var/obj/item/stored_item as anything in stored_items) remove_item(stored_item) - return ..() /obj/structure/dispenser_bot/Destroy() QDEL_LIST(stored_items) diff --git a/code/modules/wiremod/shell/moneybot.dm b/code/modules/wiremod/shell/moneybot.dm index cacb457149dc7..f3c2dfe93dab4 100644 --- a/code/modules/wiremod/shell/moneybot.dm +++ b/code/modules/wiremod/shell/moneybot.dm @@ -15,9 +15,8 @@ var/stored_money = 0 var/locked = FALSE -/obj/structure/money_bot/deconstruct(disassembled) +/obj/structure/money_bot/atom_deconstruct(disassembled = TRUE) new /obj/item/holochip(drop_location(), stored_money) - return ..() /obj/structure/money_bot/proc/add_money(to_add) stored_money += to_add From 1443ef79d3d3ee8d3af8f6e0bdcc77711e47c7ea Mon Sep 17 00:00:00 2001 From: Jeremiah <42397676+jlsnow301@users.noreply.github.com> Date: Thu, 4 Apr 2024 17:56:08 -0700 Subject: [PATCH 021/938] Replaces a number of deciseconds into SECONDS (#82436) ## About The Pull Request Using these search regexes: Number ending in 0: `do_after\((\w+), (\d+)0,` Replace: `do_after($1, $2 SECONDS,` Single digit number: `do_after\((\w+), [1-9],` replace: `do_after($1, 0.$2 SECONDS,` Double: `do_after\((\w+), (\d)([1-9]),` Replace: `do_after($1, $2.$3 SECONDS,` ## Why It's Good For The Game Code readability --- code/__HELPERS/mobs.dm | 17 +++++++++++++- .../machinery/computer/operating_computer.dm | 2 +- code/game/machinery/defibrillator_mount.dm | 2 +- code/game/machinery/deployable.dm | 2 +- code/game/machinery/launch_pad.dm | 4 ++-- code/game/machinery/medipen_refiller.dm | 2 +- code/game/machinery/prisonlabor.dm | 2 +- code/game/machinery/quantum_pad.dm | 2 +- code/game/machinery/shieldgen.dm | 2 +- code/game/machinery/suit_storage_unit.dm | 2 +- code/game/objects/items/cosmetics.dm | 2 +- .../game/objects/items/devices/polycircuit.dm | 2 +- .../objects/items/devices/quantum_keycard.dm | 2 +- code/game/objects/items/grenades/plastic.dm | 2 +- code/game/objects/items/inducer.dm | 2 +- code/game/objects/items/melee/misc.dm | 2 +- code/game/objects/items/pet_carrier.dm | 2 +- code/game/objects/items/rcd/RPLD.dm | 2 +- .../game/objects/items/robot/items/generic.dm | 6 ++--- code/game/objects/items/shields.dm | 2 +- .../objects/items/stacks/sheets/leather.dm | 2 +- code/game/objects/items/storage/medkit.dm | 2 +- code/game/objects/structures/ai_core.dm | 4 ++-- code/game/objects/structures/bonfire.dm | 2 +- code/game/objects/structures/displaycase.dm | 4 ++-- code/game/objects/structures/door_assembly.dm | 6 ++--- code/game/objects/structures/girders.dm | 14 ++++++------ code/game/objects/structures/guillotine.dm | 2 +- .../objects/structures/plaques/_plaques.dm | 2 +- code/game/objects/structures/table_frames.dm | 2 +- code/game/objects/structures/tables_racks.dm | 2 +- .../structures/transit_tubes/station.dm | 4 ++-- code/game/objects/structures/watercloset.dm | 4 ++-- .../objects/structures/windoor_assembly.dm | 4 ++-- code/game/objects/structures/window.dm | 2 +- code/game/turfs/closed/minerals.dm | 2 +- code/game/turfs/open/floor/plating.dm | 2 +- .../abductor/abductor_structures.dm | 4 ++-- .../abductor/equipment/gear/abductor_items.dm | 2 +- code/modules/antagonists/cult/blood_magic.dm | 6 ++--- code/modules/antagonists/cult/cult_comms.dm | 2 +- .../fugitive/hunters/hunter_gear.dm | 2 +- .../nukeop/equipment/borgchameleon.dm | 2 +- .../machinery/air_alarm/air_alarm_interact.dm | 2 +- .../components/unary_devices/vent_pump.dm | 2 +- .../components/unary_devices/vent_scrubber.dm | 2 +- code/modules/clothing/shoes/cowboy.dm | 2 +- code/modules/clothing/spacesuits/plasmamen.dm | 2 +- code/modules/mining/aux_base.dm | 2 +- .../modules/mining/lavaland/megafauna_loot.dm | 6 ++--- code/modules/mining/lavaland/tendril_loot.dm | 10 ++++----- .../mob/living/basic/drone/interaction.dm | 4 ++-- .../mob/living/silicon/robot/robot_defense.dm | 4 ++-- .../living/simple_animal/bot/construction.dm | 4 ++-- .../mob/living/simple_animal/bot/floorbot.dm | 6 ++--- .../hostile/megafauna/hierophant.dm | 2 +- .../mob/living/simple_animal/hostile/ooze.dm | 2 +- code/modules/paperwork/photocopier.dm | 2 +- code/modules/paperwork/ticketmachine.dm | 2 +- .../plumbing/plumbers/_plumb_machinery.dm | 2 +- code/modules/plumbing/plumbers/iv_drip.dm | 2 +- code/modules/power/apc/apc_malf.dm | 2 +- code/modules/power/apc/apc_tool_act.dm | 8 +++---- code/modules/power/cable.dm | 2 +- code/modules/power/smes.dm | 2 +- code/modules/projectiles/gun.dm | 2 +- code/modules/projectiles/guns/ballistic.dm | 4 ++-- .../reagents/reagent_containers/cups/_cup.dm | 2 +- code/modules/recycling/sortingmachinery.dm | 2 +- .../xenobiology/crossbreeding/_potions.dm | 4 ++-- .../xenobiology/crossbreeding/chilling.dm | 2 +- .../xenobiology/crossbreeding/consuming.dm | 2 +- .../research/xenobiology/xenobiology.dm | 22 +++++++++---------- code/modules/surgery/bodyparts/_bodyparts.dm | 2 +- code/modules/vehicles/mecha/working/ripley.dm | 2 +- code/modules/vehicles/secway.dm | 2 +- code/modules/vending/_vending.dm | 2 +- 77 files changed, 137 insertions(+), 122 deletions(-) diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index d42f1b1967577..ff218afe1e1ac 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -201,7 +201,22 @@ GLOBAL_LIST_EMPTY(species_list) * * Checks that `user` does not move, change hands, get stunned, etc. for the * given `delay`. Returns `TRUE` on success or `FALSE` on failure. - * Interaction_key is the assoc key under which the do_after is capped, with max_interact_count being the cap. Interaction key will default to target if not set. + * + * @param {mob} user - The mob performing the action. + * + * @param {number} delay - The time in deciseconds. Use the SECONDS define for readability. `1 SECONDS` is 10 deciseconds. + * + * @param {atom} target - The target of the action. This is where the progressbar will display. + * + * @param {flag} timed_action_flags - Flags to control the behavior of the timed action. + * + * @param {boolean} progress - Whether to display a progress bar / cogbar. + * + * @param {datum/callback} extra_checks - Additional checks to perform before the action is executed. + * + * @param {string} interaction_key - The assoc key under which the do_after is capped, with max_interact_count being the cap. Interaction key will default to target if not set. + * + * @param {number} max_interact_count - The maximum amount of interactions allowed. */ /proc/do_after(mob/user, delay, atom/target, timed_action_flags = NONE, progress = TRUE, datum/callback/extra_checks, interaction_key, max_interact_count = 1) if(!user) diff --git a/code/game/machinery/computer/operating_computer.dm b/code/game/machinery/computer/operating_computer.dm index 3b639a9ce573f..da6821814a5e6 100644 --- a/code/game/machinery/computer/operating_computer.dm +++ b/code/game/machinery/computer/operating_computer.dm @@ -55,7 +55,7 @@ span_notice("You begin to load a surgery protocol from \the [O]..."), \ span_hear("You hear the chatter of a floppy drive.")) var/obj/item/disk/surgery/D = O - if(do_after(user, 10, target = src)) + if(do_after(user, 1 SECONDS, target = src)) advanced_surgeries |= D.surgeries return TRUE return ..() diff --git a/code/game/machinery/defibrillator_mount.dm b/code/game/machinery/defibrillator_mount.dm index 4e6e45bb20482..c067fcfef0b97 100644 --- a/code/game/machinery/defibrillator_mount.dm +++ b/code/game/machinery/defibrillator_mount.dm @@ -133,7 +133,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/defibrillator_mount, 28) user.visible_message(span_notice("[user] presses [multitool] into [src]'s ID slot..."), \ span_notice("You begin overriding the clamps on [src]...")) playsound(src, 'sound/machines/click.ogg', 50, TRUE) - if(!do_after(user, 100, target = src) || !clamps_locked) + if(!do_after(user, 10 SECONDS, target = src) || !clamps_locked) return user.visible_message(span_notice("[user] pulses [multitool], and [src]'s clamps slide up."), \ span_notice("You override the locking clamps on [src]!")) diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm index a9a4336e5bb50..61f12100de21e 100644 --- a/code/game/machinery/deployable.dm +++ b/code/game/machinery/deployable.dm @@ -78,7 +78,7 @@ else to_chat(user, span_notice("You start adding [I] to [src]...")) playsound(src, 'sound/items/hammering_wood.ogg', 50, vary = TRUE) - if(do_after(user, 50, target=src)) + if(do_after(user, 5 SECONDS, target=src)) W.use(5) var/turf/T = get_turf(src) T.place_on_top(/turf/closed/wall/mineral/wood/nonmetal) diff --git a/code/game/machinery/launch_pad.dm b/code/game/machinery/launch_pad.dm index 0c95d3aa5c1d1..57047c25cac10 100644 --- a/code/game/machinery/launch_pad.dm +++ b/code/game/machinery/launch_pad.dm @@ -304,7 +304,7 @@ if(!briefcase || !usr.can_perform_action(src, NEED_DEXTERITY|NEED_HANDS)) return usr.visible_message(span_notice("[usr] starts closing [src]..."), span_notice("You start closing [src]...")) - if(do_after(usr, 30, target = usr)) + if(do_after(usr, 3 SECONDS, target = usr)) usr.put_in_hands(briefcase) moveToNullspace() //hides it from suitcase contents closed = TRUE @@ -343,7 +343,7 @@ return add_fingerprint(user) user.visible_message(span_notice("[user] starts setting down [src]..."), span_notice("You start setting up [pad]...")) - if(do_after(user, 30, target = user)) + if(do_after(user, 3 SECONDS, target = user)) pad.forceMove(get_turf(src)) pad.update_indicator() pad.closed = FALSE diff --git a/code/game/machinery/medipen_refiller.dm b/code/game/machinery/medipen_refiller.dm index 241b43d93da78..0a085af396345 100644 --- a/code/game/machinery/medipen_refiller.dm +++ b/code/game/machinery/medipen_refiller.dm @@ -87,7 +87,7 @@ /obj/machinery/medipen_refiller/plunger_act(obj/item/plunger/P, mob/living/user, reinforced) to_chat(user, span_notice("You start furiously plunging [name].")) - if(do_after(user, 30, target = src)) + if(do_after(user, 3 SECONDS, target = src)) to_chat(user, span_notice("You finish plunging the [name].")) reagents.expose(get_turf(src), TOUCH) reagents.clear_reagents() diff --git a/code/game/machinery/prisonlabor.dm b/code/game/machinery/prisonlabor.dm index 116edc2430e18..aaf1e6a342eaa 100644 --- a/code/game/machinery/prisonlabor.dm +++ b/code/game/machinery/prisonlabor.dm @@ -53,7 +53,7 @@ update_appearance() to_chat(user, span_notice("You start pressing a new license plate!")) - if(!do_after(user, 40, target = src)) + if(!do_after(user, 4 SECONDS, target = src)) pressing = FALSE update_appearance() return FALSE diff --git a/code/game/machinery/quantum_pad.dm b/code/game/machinery/quantum_pad.dm index 99aaaff46c1c5..1c014927e62d4 100644 --- a/code/game/machinery/quantum_pad.dm +++ b/code/game/machinery/quantum_pad.dm @@ -89,7 +89,7 @@ interact(user, K.qpad) else to_chat(user, span_notice("You insert [K] into [src]'s card slot, initiating the link procedure.")) - if(do_after(user, 40, target = src)) + if(do_after(user, 4 SECONDS, target = src)) to_chat(user, span_notice("You complete the link between [K] and [src].")) K.set_pad(src) diff --git a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm index 82fe82edb1a27..0e2be91490c5a 100644 --- a/code/game/machinery/shieldgen.dm +++ b/code/game/machinery/shieldgen.dm @@ -243,7 +243,7 @@ to_chat(user, span_warning("You need one length of cable to repair [src]!")) return to_chat(user, span_notice("You begin to replace the wires...")) - if(do_after(user, 30, target = src)) + if(do_after(user, 3 SECONDS, target = src)) if(coil.get_amount() < 1) return coil.use(1) diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index 255cf3ce7f181..eed7ba47877d1 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -468,7 +468,7 @@ else target.visible_message(span_warning("[user] starts shoving [target] into [src]!"), span_userdanger("[user] starts shoving you into [src]!")) - if(do_after(user, 30, target)) + if(do_after(user, 3 SECONDS, target)) if(occupant || helmet || suit || storage) return if(target == user) diff --git a/code/game/objects/items/cosmetics.dm b/code/game/objects/items/cosmetics.dm index 49780e3f5edcd..12d71db1d5a1e 100644 --- a/code/game/objects/items/cosmetics.dm +++ b/code/game/objects/items/cosmetics.dm @@ -176,7 +176,7 @@ user.visible_message(span_warning("[user] begins to wipe [target]'s lipstick off with \the [src]."), \ span_notice("You begin to wipe off [target]'s lipstick...")) - if(!do_after(user, 10, target = target)) + if(!do_after(user, 1 SECONDS, target = target)) return user.visible_message(span_notice("[user] wipes [target]'s lipstick off with \the [src]."), \ span_notice("You wipe off [target]'s lipstick.")) diff --git a/code/game/objects/items/devices/polycircuit.dm b/code/game/objects/items/devices/polycircuit.dm index 5b7fd42d6f6bd..e3faa67823883 100644 --- a/code/game/objects/items/devices/polycircuit.dm +++ b/code/game/objects/items/devices/polycircuit.dm @@ -40,7 +40,7 @@ if("APC") circuit_type = /obj/item/electronics/apc to_chat(user, span_notice("You spot your circuit, and carefully attempt to remove it from [src], hold still!")) - if(do_after(user, 30, target = user)) + if(do_after(user, 3 SECONDS, target = user)) if(!src || QDELETED(src))//Sanity Check. return var/returned_circuit = new circuit_type(src) diff --git a/code/game/objects/items/devices/quantum_keycard.dm b/code/game/objects/items/devices/quantum_keycard.dm index 6c718cc9a431e..abffdcca4d59a 100644 --- a/code/game/objects/items/devices/quantum_keycard.dm +++ b/code/game/objects/items/devices/quantum_keycard.dm @@ -44,7 +44,7 @@ if(!istype(user) || !user.can_perform_action(src, NEED_DEXTERITY)) return to_chat(user, span_notice("You start pressing [src]'s unlink button...")) - if(do_after(user, 40, target = src)) + if(do_after(user, 4 SECONDS, target = src)) to_chat(user, span_notice("The keycard beeps twice and disconnects the quantum link.")) set_pad() diff --git a/code/game/objects/items/grenades/plastic.dm b/code/game/objects/items/grenades/plastic.dm index ea758c8993e1d..8e8aeb2617f1d 100644 --- a/code/game/objects/items/grenades/plastic.dm +++ b/code/game/objects/items/grenades/plastic.dm @@ -111,7 +111,7 @@ to_chat(user, span_notice("You start planting [src]. The timer is set to [det_time]...")) - if(do_after(user, 30, target = bomb_target)) + if(do_after(user, 3 SECONDS, target = bomb_target)) if(!user.temporarilyRemoveItemFromInventory(src)) return . target = bomb_target diff --git a/code/game/objects/items/inducer.dm b/code/game/objects/items/inducer.dm index 9cbb3f054f571..c3637644aab54 100644 --- a/code/game/objects/items/inducer.dm +++ b/code/game/objects/items/inducer.dm @@ -127,7 +127,7 @@ user.visible_message(span_notice("[user] starts recharging [target] with [src]."), span_notice("You start recharging [target] with [src].")) while(target_cell.charge < target_cell.maxcharge) - if(do_after(user, 10, target = user) && our_cell.charge) + if(do_after(user, 1 SECONDS, target = user) && our_cell.charge) done_any = TRUE induce(target_cell, coefficient) do_sparks(1, FALSE, target) diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm index 0f400536b8fd8..3310aa11faada 100644 --- a/code/game/objects/items/melee/misc.dm +++ b/code/game/objects/items/melee/misc.dm @@ -446,7 +446,7 @@ finish_roasting(user, target) /obj/item/melee/roastingstick/proc/finish_roasting(user, atom/target) - if(do_after(user, 100, target = user)) + if(do_after(user, 10 SECONDS, target = user)) to_chat(user, span_notice("You finish roasting [held_sausage].")) playsound(src, 'sound/items/welder2.ogg', 50, TRUE) held_sausage.add_atom_colour(rgb(103, 63, 24), FIXED_COLOUR_PRIORITY) diff --git a/code/game/objects/items/pet_carrier.dm b/code/game/objects/items/pet_carrier.dm index 567b32304e47f..61c1a892c4705 100644 --- a/code/game/objects/items/pet_carrier.dm +++ b/code/game/objects/items/pet_carrier.dm @@ -131,7 +131,7 @@ else loc.visible_message(span_warning("[src] starts rattling as something pushes against the door!"), null, null, null, user) to_chat(user, span_notice("You start pushing out of [src]... (This will take about 20 seconds.)")) - if(!do_after(user, 200, target = user) || open || !locked || !(user in occupants)) + if(!do_after(user, 20 SECONDS, target = user) || open || !locked || !(user in occupants)) return loc.visible_message(span_warning("[user] shoves out of [src]!"), null, null, null, user) to_chat(user, span_notice("You shove open [src]'s door against the lock's resistance and fall out!")) diff --git a/code/game/objects/items/rcd/RPLD.dm b/code/game/objects/items/rcd/RPLD.dm index 7f03fad1a9c32..de7e80cf190cf 100644 --- a/code/game/objects/items/rcd/RPLD.dm +++ b/code/game/objects/items/rcd/RPLD.dm @@ -268,7 +268,7 @@ if(machine_target.anchored) balloon_alert(user, "unanchor first!") return - if(do_after(user, 20, target = target)) + if(do_after(user, 2 SECONDS, target = target)) machine_target.deconstruct() //Let's not substract matter playsound(get_turf(src), 'sound/machines/click.ogg', 50, TRUE) //this is just such a great sound effect return diff --git a/code/game/objects/items/robot/items/generic.dm b/code/game/objects/items/robot/items/generic.dm index f1f7f379ffbf8..b9f28b4003e65 100644 --- a/code/game/objects/items/robot/items/generic.dm +++ b/code/game/objects/items/robot/items/generic.dm @@ -247,7 +247,7 @@ return to_chat(user, span_notice("You connect to [target_machine]'s power line...")) - while(do_after(user, 15, target = target_machine, progress = 0)) + while(do_after(user, 1.5 SECONDS, target = target_machine, progress = FALSE)) if(!user || !user.cell || mode != "draw") return @@ -278,7 +278,7 @@ to_chat(user, span_notice("You connect to [target]'s power port...")) - while(do_after(user, 15, target = target, progress = 0)) + while(do_after(user, 1.5 SECONDS, target = target, progress = FALSE)) if(!user || !user.cell || mode != "draw") return @@ -316,7 +316,7 @@ to_chat(user, span_notice("You connect to [target]'s power port...")) - while(do_after(user, 15, target = target, progress = 0)) + while(do_after(user, 1.5 SECONDS, target = target, progress = FALSE)) if(!user || !user.cell || mode != "charge") return diff --git a/code/game/objects/items/shields.dm b/code/game/objects/items/shields.dm index 3e3af7bc36f5e..66dd5a34b6ac5 100644 --- a/code/game/objects/items/shields.dm +++ b/code/game/objects/items/shields.dm @@ -231,7 +231,7 @@ return else to_chat(user, span_notice("You begin to replace the bulb...")) - if(do_after(user, 20, target = user)) + if(do_after(user, 2 SECONDS, target = user)) if(QDELETED(flash) || flash.burnt_out) return playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) diff --git a/code/game/objects/items/stacks/sheets/leather.dm b/code/game/objects/items/stacks/sheets/leather.dm index e9426a913ec70..851e544ff8a83 100644 --- a/code/game/objects/items/stacks/sheets/leather.dm +++ b/code/game/objects/items/stacks/sheets/leather.dm @@ -322,7 +322,7 @@ GLOBAL_LIST_INIT(sinew_recipes, list ( \ if(W.get_sharpness()) playsound(loc, 'sound/weapons/slice.ogg', 50, TRUE, -1) user.visible_message(span_notice("[user] starts cutting hair off \the [src]."), span_notice("You start cutting the hair off \the [src]..."), span_hear("You hear the sound of a knife rubbing against flesh.")) - if(do_after(user, 50, target = src)) + if(do_after(user, 5 SECONDS, target = src)) to_chat(user, span_notice("You cut the hair from [src.name].")) new /obj/item/stack/sheet/hairlesshide(user.drop_location(), amount) use(amount) diff --git a/code/game/objects/items/storage/medkit.dm b/code/game/objects/items/storage/medkit.dm index 0ecd943b60457..5b09b5e0605bd 100644 --- a/code/game/objects/items/storage/medkit.dm +++ b/code/game/objects/items/storage/medkit.dm @@ -742,7 +742,7 @@ return if(istype(I, /obj/item/plunger)) balloon_alert(user, "plunging...") - if(do_after(user, 10, target = src)) + if(do_after(user, 1 SECONDS, target = src)) balloon_alert(user, "plunged") reagents.clear_reagents() return diff --git a/code/game/objects/structures/ai_core.dm b/code/game/objects/structures/ai_core.dm index 70c9c95459127..6207a4031c105 100644 --- a/code/game/objects/structures/ai_core.dm +++ b/code/game/objects/structures/ai_core.dm @@ -214,7 +214,7 @@ if(C.get_amount() >= 5) playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE) balloon_alert(user, "adding cables to frame...") - if(do_after(user, 20, target = src) && state == SCREWED_CORE && C.use(5)) + if(do_after(user, 2 SECONDS, target = src) && state == SCREWED_CORE && C.use(5)) balloon_alert(user, "added cables to frame.") state = CABLED_CORE update_appearance() @@ -241,7 +241,7 @@ if(G.get_amount() >= 2) playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE) balloon_alert(user, "adding glass panel...") - if(do_after(user, 20, target = src) && state == CABLED_CORE && G.use(2)) + if(do_after(user, 2 SECONDS, target = src) && state == CABLED_CORE && G.use(2)) balloon_alert(user, "added glass panel") state = GLASS_CORE update_appearance() diff --git a/code/game/objects/structures/bonfire.dm b/code/game/objects/structures/bonfire.dm index 987b9bcc37b56..02f611eb4e37d 100644 --- a/code/game/objects/structures/bonfire.dm +++ b/code/game/objects/structures/bonfire.dm @@ -85,7 +85,7 @@ if(burning) to_chat(user, span_warning("You need to extinguish [src] before removing the logs!")) return - if(!has_buckled_mobs() && do_after(user, 50, target = src)) + if(!has_buckled_mobs() && do_after(user, 5 SECONDS, target = src)) for(var/obj/item/grown/log/bonfire_log in contents) bonfire_log.forceMove(drop_location()) bonfire_log.pixel_x += rand(1,4) diff --git a/code/game/objects/structures/displaycase.dm b/code/game/objects/structures/displaycase.dm index b9b4698d78032..5449d0bcf0601 100644 --- a/code/game/objects/structures/displaycase.dm +++ b/code/game/objects/structures/displaycase.dm @@ -166,7 +166,7 @@ to_chat(user, span_warning("You need two glass sheets to fix the case!")) return to_chat(user, span_notice("You start fixing [src]...")) - if(do_after(user, 20, target = src)) + if(do_after(user, 2 SECONDS, target = src)) glass_sheet.use(2) broken = FALSE atom_integrity = max_integrity @@ -628,7 +628,7 @@ . = ..() if(atom_integrity <= (integrity_failure * max_integrity)) to_chat(user, span_notice("You start recalibrating [src]'s hover field...")) - if(do_after(user, 20, target = src)) + if(do_after(user, 2 SECONDS, target = src)) broken = FALSE atom_integrity = max_integrity update_appearance() diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm index b6cac0aa5bec6..f75a8b9ce726c 100644 --- a/code/game/objects/structures/door_assembly.dm +++ b/code/game/objects/structures/door_assembly.dm @@ -184,7 +184,7 @@ W.play_tool_sound(src, 100) user.visible_message(span_notice("[user] installs the electronics into the airlock assembly."), \ span_notice("You start to install electronics into the airlock assembly...")) - if(do_after(user, 40, target = src)) + if(do_after(user, 4 SECONDS, target = src)) if( state != AIRLOCK_ASSEMBLY_NEEDS_ELECTRONICS ) return if(!user.transferItemToLoc(W, src)) @@ -224,7 +224,7 @@ playsound(src, 'sound/items/crowbar.ogg', 100, TRUE) user.visible_message(span_notice("[user] adds [G.name] to the airlock assembly."), \ span_notice("You start to install [G.name] into the airlock assembly...")) - if(do_after(user, 40, target = src)) + if(do_after(user, 4 SECONDS, target = src)) if(G.get_amount() < 1 || glass) return if(G.type == /obj/item/stack/sheet/rglass) @@ -247,7 +247,7 @@ playsound(src, 'sound/items/crowbar.ogg', 100, TRUE) user.visible_message(span_notice("[user] adds [G.name] to the airlock assembly."), \ span_notice("You start to install [G.name] into the airlock assembly...")) - if(do_after(user, 40, target = src)) + if(do_after(user, 4 SECONDS, target = src)) if(G.get_amount() < 2 || mineral) return to_chat(user, span_notice("You install [M] plating into the airlock assembly.")) diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index 513525ffca399..0f20f87e0b547 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -81,7 +81,7 @@ balloon_alert(user, "need [amount] rods!") return balloon_alert(user, "concealing entrance...") - if(do_after(user, 20, target = src)) + if(do_after(user, 2 SECONDS, target = src)) if(rod.get_amount() < amount) return rod.use(amount) @@ -94,7 +94,7 @@ balloon_alert(user, "need [amount] rods!") return balloon_alert(user, "adding plating...") - if(do_after(user, 40, target = src)) + if(do_after(user, 4 SECONDS, target = src)) if(rod.get_amount() < amount) return rod.use(amount) @@ -176,7 +176,7 @@ balloon_alert(user, "need [amount] sheets!") return balloon_alert(user, "concealing entrance...") - if(do_after(user, 20, target = src)) + if(do_after(user, 2 SECONDS, target = src)) if(sheets.get_amount() < amount) return sheets.use(amount) @@ -243,7 +243,7 @@ balloon_alert(user, "need [amount] sheets!") return balloon_alert(user, "concealing entrance...") - if(do_after(user, 20, target = src)) + if(do_after(user, 2 SECONDS, target = src)) if(sheets.get_amount() < amount) return sheets.use(amount) @@ -265,7 +265,7 @@ balloon_alert(user, "need [amount] sheets!") return balloon_alert(user, "adding plating...") - if (do_after(user, 40, target = src)) + if (do_after(user, 4 SECONDS, target = src)) if(sheets.get_amount() < amount) return sheets.use(amount) @@ -445,7 +445,7 @@ balloon_alert(user, "need [amount] sheet!") return balloon_alert(user, "adding plating...") - if(do_after(user, 50, target = src)) + if(do_after(user, 5 SECONDS, target = src)) if(R.get_amount() < amount) return R.use(amount) @@ -515,7 +515,7 @@ balloon_alert(user, "need [amount] sheets!") return balloon_alert(user, "adding plating...") - if(do_after(user, 50, target = src)) + if(do_after(user, 5 SECONDS, target = src)) if(B.get_amount() < amount) return B.use(amount) diff --git a/code/game/objects/structures/guillotine.dm b/code/game/objects/structures/guillotine.dm index bc56b3838ca11..a51e82498e2bc 100644 --- a/code/game/objects/structures/guillotine.dm +++ b/code/game/objects/structures/guillotine.dm @@ -192,7 +192,7 @@ if (blade_status == GUILLOTINE_BLADE_RAISED) if (blade_sharpness < GUILLOTINE_BLADE_MAX_SHARP) blade_status = GUILLOTINE_BLADE_SHARPENING - if(do_after(user, 7, target = src)) + if(do_after(user, 0.7 SECONDS, target = src)) blade_status = GUILLOTINE_BLADE_RAISED user.visible_message(span_notice("[user] sharpens the large blade of the guillotine."), span_notice("You sharpen the large blade of the guillotine.")) diff --git a/code/game/objects/structures/plaques/_plaques.dm b/code/game/objects/structures/plaques/_plaques.dm index 8b8047ba4641a..4a1684434dcca 100644 --- a/code/game/objects/structures/plaques/_plaques.dm +++ b/code/game/objects/structures/plaques/_plaques.dm @@ -169,7 +169,7 @@ return user.visible_message(span_notice("[user] begins engraving [src]."), \ span_notice("You begin engraving [src].")) - if(!do_after(user, 40, target = src)) //This spits out a visible message that somebody is engraving a plaque, then has a delay. + if(!do_after(user, 4 SECONDS, target = src)) //This spits out a visible message that somebody is engraving a plaque, then has a delay. return name = "\improper [namechoice]" //We want improper here so examine doesn't get weird if somebody capitalizes the plaque title. desc = "The plaque reads: '[descriptionchoice]'" diff --git a/code/game/objects/structures/table_frames.dm b/code/game/objects/structures/table_frames.dm index 331667c506e40..cb45eb18e75eb 100644 --- a/code/game/objects/structures/table_frames.dm +++ b/code/game/objects/structures/table_frames.dm @@ -109,7 +109,7 @@ to_chat(user, span_warning("You need one [material.name] sheet to do this!")) return to_chat(user, span_notice("You start adding [material] to [src]...")) - if(do_after(user, 20, target = src) && material.use(1)) + if(do_after(user, 2 SECONDS, target = src) && material.use(1)) make_new_table(toConstruct, null, carpet_type) else return ..() diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index eff8aa8ba36b3..755927e319142 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -939,7 +939,7 @@ return building = TRUE to_chat(user, span_notice("You start constructing a rack...")) - if(do_after(user, 50, target = user, progress=TRUE)) + if(do_after(user, 5 SECONDS, target = user, progress=TRUE)) if(!user.temporarilyRemoveItemFromInventory(src)) return var/obj/structure/rack/R = new /obj/structure/rack(get_turf(src)) diff --git a/code/game/objects/structures/transit_tubes/station.dm b/code/game/objects/structures/transit_tubes/station.dm index b04d9803569d1..0765273ebf463 100644 --- a/code/game/objects/structures/transit_tubes/station.dm +++ b/code/game/objects/structures/transit_tubes/station.dm @@ -73,7 +73,7 @@ return for(var/obj/structure/transit_tube_pod/pod in loc) pod.visible_message(span_warning("[user] starts putting [GM] into the [pod]!")) - if(do_after(user, 15, target = src)) + if(do_after(user, 1.5 SECONDS, target = src)) if(open_status == STATION_TUBE_OPEN && GM && user.grab_state >= GRAB_AGGRESSIVE && user.pulling == GM && !GM.buckled && !GM.has_buckled_mobs()) GM.Paralyze(100) src.Bumped(GM) @@ -87,7 +87,7 @@ else if(open_status == STATION_TUBE_OPEN) if(pod.contents.len && user.loc != pod) user.visible_message(span_notice("[user] starts emptying [pod]'s contents onto the floor."), span_notice("You start emptying [pod]'s contents onto the floor...")) - if(do_after(user, 10, target = src)) //So it doesn't default to close_animation() on fail + if(do_after(user, 1 SECONDS, target = src)) //So it doesn't default to close_animation() on fail if(pod && pod.loc == loc) for(var/atom/movable/AM in pod) AM.forceMove(get_turf(user)) diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index ecdd4bdacdd55..da084945b98d0 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -353,7 +353,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink, (-14)) span_notice("You start washing your [washing_face ? "face" : "hands"]...")) busy = TRUE - if(!do_after(user, 40, target = src)) + if(!do_after(user, 4 SECONDS, target = src)) busy = FALSE return @@ -479,7 +479,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink, (-14)) if(!user.combat_mode) to_chat(user, span_notice("You start washing [O]...")) busy = TRUE - if(!do_after(user, 40, target = src)) + if(!do_after(user, 4 SECONDS, target = src)) busy = FALSE return 1 busy = FALSE diff --git a/code/game/objects/structures/windoor_assembly.dm b/code/game/objects/structures/windoor_assembly.dm index 46eb13ee2b7c1..0a56c6add6984 100644 --- a/code/game/objects/structures/windoor_assembly.dm +++ b/code/game/objects/structures/windoor_assembly.dm @@ -178,7 +178,7 @@ else if(istype(W, /obj/item/stack/cable_coil) && anchored) user.visible_message(span_notice("[user] wires the windoor assembly."), span_notice("You start to wire the windoor assembly...")) - if(do_after(user, 40, target = src)) + if(do_after(user, 4 SECONDS, target = src)) if(!src || !anchored || src.state != "01") return var/obj/item/stack/cable_coil/CC = W @@ -220,7 +220,7 @@ user.visible_message(span_notice("[user] installs the electronics into the airlock assembly."), span_notice("You start to install electronics into the airlock assembly...")) - if(do_after(user, 40, target = src)) + if(do_after(user, 4 SECONDS, target = src)) if(!src || electronics) W.forceMove(drop_location()) return diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 4fd6c061068c5..94ec90e3c0360 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -902,7 +902,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/reinforced/tinted/frosted/spaw return ..() if(istype(W, /obj/item/paper) && atom_integrity < max_integrity) user.visible_message(span_notice("[user] starts to patch the holes in \the [src].")) - if(do_after(user, 20, target = src)) + if(do_after(user, 2 SECONDS, target = src)) atom_integrity = min(atom_integrity+4,max_integrity) qdel(W) user.visible_message(span_notice("[user] patches some of the holes in \the [src].")) diff --git a/code/game/turfs/closed/minerals.dm b/code/game/turfs/closed/minerals.dm index 74f14c56cbb32..04e44f6e968c7 100644 --- a/code/game/turfs/closed/minerals.dm +++ b/code/game/turfs/closed/minerals.dm @@ -243,7 +243,7 @@ /turf/closed/mineral/attack_hulk(mob/living/carbon/human/H) ..() - if(do_after(H, 50, target = src)) + if(do_after(H, 5 SECONDS, target = src)) playsound(src, 'sound/effects/meteorimpact.ogg', 100, TRUE) H.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ), forced = "hulk") gets_drilled(H) diff --git a/code/game/turfs/open/floor/plating.dm b/code/game/turfs/open/floor/plating.dm index 1de28b201d84c..974042ce7c8e1 100644 --- a/code/game/turfs/open/floor/plating.dm +++ b/code/game/turfs/open/floor/plating.dm @@ -62,7 +62,7 @@ return else to_chat(user, span_notice("You begin reinforcing the floor...")) - if(do_after(user, 30, target = src)) + if(do_after(user, 3 SECONDS, target = src)) if (R.get_amount() >= 2 && !istype(src, /turf/open/floor/engine)) place_on_top(/turf/open/floor/engine, flags = CHANGETURF_INHERIT_AIR) playsound(src, 'sound/items/deconstruct.ogg', 80, TRUE) diff --git a/code/modules/antagonists/abductor/abductor_structures.dm b/code/modules/antagonists/abductor/abductor_structures.dm index 7da1d72d06b5a..da0ad5de9ea5b 100644 --- a/code/modules/antagonists/abductor/abductor_structures.dm +++ b/code/modules/antagonists/abductor/abductor_structures.dm @@ -31,7 +31,7 @@ to_chat(user, span_warning("You need one alien alloy sheet to do this!")) return to_chat(user, span_notice("You start adding [stacked_sheets] to [src]...")) - if(do_after(user, 50, target = src)) + if(do_after(user, 5 SECONDS, target = src)) stacked_sheets.use(1) new /obj/structure/table/abductor(src.loc) qdel(src) @@ -42,7 +42,7 @@ to_chat(user, span_warning("You need one sheet of silver to do this!")) return to_chat(user, span_notice("You start adding [stacked_sheets] to [src]...")) - if(do_after(user, 50, target = src)) + if(do_after(user, 5 SECONDS, target = src)) stacked_sheets.use(1) new /obj/structure/table/optable/abductor(src.loc) qdel(src) diff --git a/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm b/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm index 14d8d73788655..1ec8940394fdf 100644 --- a/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm +++ b/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm @@ -93,7 +93,7 @@ to_chat(user, span_warning("You need to be next to the specimen to prepare it for transport!")) return to_chat(user, span_notice("You begin preparing [target] for transport...")) - if(do_after(user, 100, target = target)) + if(do_after(user, 10 SECONDS, target = target)) marked_target_weakref = WEAKREF(target) to_chat(user, span_notice("You finish preparing [target] for transport.")) diff --git a/code/modules/antagonists/cult/blood_magic.dm b/code/modules/antagonists/cult/blood_magic.dm index e70e3fc31b3a1..33a12af2c7844 100644 --- a/code/modules/antagonists/cult/blood_magic.dm +++ b/code/modules/antagonists/cult/blood_magic.dm @@ -501,7 +501,7 @@ playsound(loc, 'sound/weapons/cablecuff.ogg', 30, TRUE, -2) C.visible_message(span_danger("[user] begins restraining [C] with dark magic!"), \ span_userdanger("[user] begins shaping dark magic shackles around your wrists!")) - if(do_after(user, 30, C)) + if(do_after(user, 3 SECONDS, C)) if(!C.handcuffed) C.set_handcuffed(new /obj/item/restraints/handcuffs/energy/cult/used(C)) C.update_handcuffed() @@ -580,7 +580,7 @@ playsound(T, 'sound/machines/airlock_alien_prying.ogg', 80, TRUE) var/prev_color = candidate.color candidate.color = "black" - if(do_after(user, 90, target = candidate)) + if(do_after(user, 9 SECONDS, target = candidate)) candidate.undeploy() candidate.emp_act(EMP_HEAVY) var/construct_class = show_radial_menu(user, src, GLOB.construct_radial_images, custom_check = CALLBACK(src, PROC_REF(check_menu), user), require_near = TRUE, tooltips = TRUE) @@ -609,7 +609,7 @@ channeling = TRUE playsound(T, 'sound/machines/airlockforced.ogg', 50, TRUE) do_sparks(5, TRUE, target) - if(do_after(user, 50, target = user)) + if(do_after(user, 5 SECONDS, target = user)) if(QDELETED(target)) channeling = FALSE return diff --git a/code/modules/antagonists/cult/cult_comms.dm b/code/modules/antagonists/cult/cult_comms.dm index ff64cc86a2bb1..96aa06e7075af 100644 --- a/code/modules/antagonists/cult/cult_comms.dm +++ b/code/modules/antagonists/cult/cult_comms.dm @@ -229,7 +229,7 @@ if(!LAZYLEN(destinations)) to_chat(owner, span_warning("You need more space to summon your cult!")) return - if(do_after(owner, 30, target = owner)) + if(do_after(owner, 3 SECONDS, target = owner)) for(var/datum/mind/B in antag.cult_team.members) if(B.current && B.current.stat != DEAD) var/turf/mobloc = get_turf(B.current) diff --git a/code/modules/antagonists/fugitive/hunters/hunter_gear.dm b/code/modules/antagonists/fugitive/hunters/hunter_gear.dm index 54f2ef351a78e..31f312ae5407b 100644 --- a/code/modules/antagonists/fugitive/hunters/hunter_gear.dm +++ b/code/modules/antagonists/fugitive/hunters/hunter_gear.dm @@ -23,7 +23,7 @@ if(!fug_antag) to_chat(fugitive_hunter, span_warning("This is not a wanted fugitive!")) return - if(do_after(fugitive_hunter, 50, target = fugitive)) + if(do_after(fugitive_hunter, 5 SECONDS, target = fugitive)) add_prisoner(fugitive, fug_antag) /obj/machinery/fugitive_capture/proc/add_prisoner(mob/living/carbon/human/fugitive, datum/antagonist/fugitive/antag) diff --git a/code/modules/antagonists/nukeop/equipment/borgchameleon.dm b/code/modules/antagonists/nukeop/equipment/borgchameleon.dm index e5a5d2cfb3567..68e62a1044cfe 100644 --- a/code/modules/antagonists/nukeop/equipment/borgchameleon.dm +++ b/code/modules/antagonists/nukeop/equipment/borgchameleon.dm @@ -66,7 +66,7 @@ to_chat(user, span_notice("You activate \the [src].")) playsound(src, 'sound/effects/seedling_chargeup.ogg', 100, TRUE, -6) apply_wibbly_filters(user) - if (do_after(user, 50, target=user) && user.cell.use(ACTIVATION_COST)) + if (do_after(user, 5 SECONDS, target=user) && user.cell.use(ACTIVATION_COST)) playsound(src, 'sound/effects/bamf.ogg', 100, TRUE, -6) to_chat(user, span_notice("You are now disguised as the Nanotrasen engineering borg \"[friendlyName]\".")) activate(user) diff --git a/code/modules/atmospherics/machinery/air_alarm/air_alarm_interact.dm b/code/modules/atmospherics/machinery/air_alarm/air_alarm_interact.dm index 7b21309e4e56e..bb45d1f8c1fec 100644 --- a/code/modules/atmospherics/machinery/air_alarm/air_alarm_interact.dm +++ b/code/modules/atmospherics/machinery/air_alarm/air_alarm_interact.dm @@ -116,7 +116,7 @@ return user.visible_message(span_notice("[user.name] wires the air alarm."), \ span_notice("You start wiring the air alarm...")) - if (do_after(user, 20, target = src)) + if (do_after(user, 2 SECONDS, target = src)) if (cable.get_amount() >= 5 && buildstage == AIR_ALARM_BUILD_NO_WIRES) cable.use(5) to_chat(user, span_notice("You wire the air alarm.")) diff --git a/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm b/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm index bece67572b6f5..2220f6405416f 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm @@ -352,7 +352,7 @@ update_icon_nopipes() /obj/machinery/atmospherics/components/unary/vent_pump/attack_alien(mob/user, list/modifiers) - if(!welded || !(do_after(user, 20, target = src))) + if(!welded || !(do_after(user, 2 SECONDS, target = src))) return user.visible_message(span_warning("[user] furiously claws at [src]!"), span_notice("You manage to clear away the stuff blocking the vent."), span_hear("You hear loud scraping noises.")) welded = FALSE diff --git a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm index 102728fb59149..c318d78a335bb 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm @@ -328,7 +328,7 @@ . += "It seems welded shut." /obj/machinery/atmospherics/components/unary/vent_scrubber/attack_alien(mob/user, list/modifiers) - if(!welded || !(do_after(user, 20, target = src))) + if(!welded || !(do_after(user, 2 SECONDS, target = src))) return user.visible_message(span_warning("[user] furiously claws at [src]!"), span_notice("You manage to clear away the stuff blocking the scrubber."), span_hear("You hear loud scraping noises.")) welded = FALSE diff --git a/code/modules/clothing/shoes/cowboy.dm b/code/modules/clothing/shoes/cowboy.dm index a033a561439ff..b7382584e5705 100644 --- a/code/modules/clothing/shoes/cowboy.dm +++ b/code/modules/clothing/shoes/cowboy.dm @@ -64,7 +64,7 @@ to_chat(user, span_notice("[target] slithers into [src].")) /obj/item/clothing/shoes/cowboy/container_resist_act(mob/living/user) - if(!do_after(user, 10, target = user)) + if(!do_after(user, 1 SECONDS, target = user)) return user.forceMove(drop_location()) diff --git a/code/modules/clothing/spacesuits/plasmamen.dm b/code/modules/clothing/spacesuits/plasmamen.dm index 5bdec24b96739..ce21351c88522 100644 --- a/code/modules/clothing/spacesuits/plasmamen.dm +++ b/code/modules/clothing/spacesuits/plasmamen.dm @@ -124,7 +124,7 @@ if(smile == FALSE) var/obj/item/toy/crayon/CR = hitting_item to_chat(user, span_notice("You start drawing a smiley face on the helmet's visor..")) - if(do_after(user, 25, target = src)) + if(do_after(user, 2.5 SECONDS, target = src)) smile = TRUE smile_color = CR.paint_color to_chat(user, "You draw a smiley on the helmet visor.") diff --git a/code/modules/mining/aux_base.dm b/code/modules/mining/aux_base.dm index 5dd9832a8b01c..88f8634fabf95 100644 --- a/code/modules/mining/aux_base.dm +++ b/code/modules/mining/aux_base.dm @@ -273,7 +273,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/auxiliary_base, 32) to_chat(user, span_notice("You begin setting the landing zone parameters...")) setting = TRUE - if(!do_after(user, 50, target = user)) //You get a few seconds to cancel if you do not want to drop there. + if(!do_after(user, 5 SECONDS, target = user)) //You get a few seconds to cancel if you do not want to drop there. setting = FALSE return setting = FALSE diff --git a/code/modules/mining/lavaland/megafauna_loot.dm b/code/modules/mining/lavaland/megafauna_loot.dm index 25240b0330fb3..a5c087191872a 100644 --- a/code/modules/mining/lavaland/megafauna_loot.dm +++ b/code/modules/mining/lavaland/megafauna_loot.dm @@ -120,7 +120,7 @@ if(isturf(user.loc)) user.visible_message(span_hierophant_warning("[user] starts fiddling with [src]'s pommel..."), \ span_notice("You start detaching the hierophant beacon...")) - if(do_after(user, 50, target = user) && !beacon) + if(do_after(user, 5 SECONDS, target = user) && !beacon) var/turf/user_turf = get_turf(user) playsound(user_turf,'sound/magic/blind.ogg', 200, TRUE, -4) new /obj/effect/temp_visual/hierophant/telegraph/teleport(user_turf, user) @@ -149,7 +149,7 @@ beacon.icon_state = "hierophant_tele_on" var/obj/effect/temp_visual/hierophant/telegraph/edge/user_telegraph = new /obj/effect/temp_visual/hierophant/telegraph/edge(user.loc) var/obj/effect/temp_visual/hierophant/telegraph/edge/beacon_telegraph = new /obj/effect/temp_visual/hierophant/telegraph/edge(beacon.loc) - if(do_after(user, 40, target = user) && user && beacon) + if(do_after(user, 4 SECONDS, target = user) && user && beacon) var/turf/destination = get_turf(beacon) var/turf/source = get_turf(user) if(destination.is_blocked_turf(TRUE)) @@ -162,7 +162,7 @@ new /obj/effect/temp_visual/hierophant/telegraph(source, user) playsound(destination,'sound/magic/wand_teleport.ogg', 200, TRUE) playsound(source,'sound/machines/airlockopen.ogg', 200, TRUE) - if(!do_after(user, 3, target = user) || !user || !beacon || QDELETED(beacon)) //no walking away shitlord + if(!do_after(user, 0.3 SECONDS, target = user) || !user || !beacon || QDELETED(beacon)) //no walking away shitlord teleporting = FALSE if(user) user.update_mob_action_buttons() diff --git a/code/modules/mining/lavaland/tendril_loot.dm b/code/modules/mining/lavaland/tendril_loot.dm index 764c1ddb98f39..c8d0f5580d724 100644 --- a/code/modules/mining/lavaland/tendril_loot.dm +++ b/code/modules/mining/lavaland/tendril_loot.dm @@ -105,22 +105,22 @@ return var/failText = span_warning("The snake seems unsatisfied with your incomplete oath and returns to its previous place on the rod, returning to its dormant, wooden state. You must stand still while completing your oath!") to_chat(itemUser, span_notice("The wooden snake that was carved into the rod seems to suddenly come alive and begins to slither down your arm! The compulsion to help others grows abnormally strong...")) - if(do_after(itemUser, 40, target = itemUser)) + if(do_after(itemUser, 4 SECONDS, target = itemUser)) itemUser.say("I swear to fulfill, to the best of my ability and judgment, this covenant:", forced = "hippocratic oath") else to_chat(itemUser, failText) return - if(do_after(itemUser, 20, target = itemUser)) + if(do_after(itemUser, 2 SECONDS, target = itemUser)) itemUser.say("I will apply, for the benefit of the sick, all measures that are required, avoiding those twin traps of overtreatment and therapeutic nihilism.", forced = "hippocratic oath") else to_chat(itemUser, failText) return - if(do_after(itemUser, 30, target = itemUser)) + if(do_after(itemUser, 3 SECONDS, target = itemUser)) itemUser.say("I will remember that I remain a member of society, with special obligations to all my fellow human beings, those sound of mind and body as well as the infirm.", forced = "hippocratic oath") else to_chat(itemUser, failText) return - if(do_after(itemUser, 30, target = itemUser)) + if(do_after(itemUser, 3 SECONDS, target = itemUser)) itemUser.say("If I do not violate this oath, may I enjoy life and art, respected while I live and remembered with affection thereafter. May I always act so as to preserve the finest traditions of my calling and may I long experience the joy of healing those who seek my help.", forced = "hippocratic oath") else to_chat(itemUser, failText) @@ -163,7 +163,7 @@ /obj/item/clothing/neck/necklace/memento_mori/proc/memento(mob/living/carbon/human/user) to_chat(user, span_warning("You feel your life being drained by the pendant...")) - if(do_after(user, 40, target = user)) + if(do_after(user, 4 SECONDS, target = user)) to_chat(user, span_notice("Your lifeforce is now linked to the pendant! You feel like removing it would kill you, and yet you instinctively know that until then, you won't die.")) user.add_traits(list(TRAIT_NODEATH, TRAIT_NOHARDCRIT, TRAIT_NOCRITDAMAGE), CLOTHING_TRAIT) RegisterSignal(user, COMSIG_LIVING_HEALTH_UPDATE, PROC_REF(check_health)) diff --git a/code/modules/mob/living/basic/drone/interaction.dm b/code/modules/mob/living/basic/drone/interaction.dm index c528dafcbd6de..0b0247c1c45f3 100644 --- a/code/modules/mob/living/basic/drone/interaction.dm +++ b/code/modules/mob/living/basic/drone/interaction.dm @@ -14,7 +14,7 @@ to_chat(drone, span_warning("You're already in perfect condition!")) return drone.visible_message(span_notice("[drone] begins to cannibalize parts from [src]."), span_notice("You begin to cannibalize parts from [src]...")) - if(do_after(drone, 60, 0, target = src)) + if(do_after(drone, 6 SECONDS, 0, target = src)) drone.visible_message(span_notice("[drone] repairs itself using [src]'s remains!"), span_notice("You repair yourself using [src]'s remains.")) drone.adjustBruteLoss(-src.maxHealth) new /obj/effect/decal/cleanable/oil/streak(get_turf(src)) @@ -67,7 +67,7 @@ to_chat(user, span_warning("You can't seem to find the [pick(faux_gadgets)]! Without it, [src] [pick(faux_problems)].")) return user.visible_message(span_notice("[user] begins to reactivate [src]."), span_notice("You begin to reactivate [src]...")) - if(do_after(user, 30, 1, target = src)) + if(do_after(user, 3 SECONDS, 1, target = src)) revive(HEAL_ALL) user.visible_message(span_notice("[user] reactivates [src]!"), span_notice("You reactivate [src].")) alert_drones(DRONE_NET_CONNECT) diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm index 722b92835c8e0..f6b94c9f15c6b 100644 --- a/code/modules/mob/living/silicon/robot/robot_defense.dm +++ b/code/modules/mob/living/silicon/robot/robot_defense.dm @@ -11,7 +11,7 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real if (getFireLoss() > 0 || getToxLoss() > 0) if(src == user) to_chat(user, span_notice("You start fixing yourself...")) - if(!do_after(user, 50, target = src)) + if(!do_after(user, 5 SECONDS, target = src)) return if (coil.use(1)) adjustFireLoss(-30) @@ -52,7 +52,7 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real return to_chat(user, span_notice("You begin to place [W] on [src]'s head...")) to_chat(src, span_notice("[user] is placing [W] on your head...")) - if(do_after(user, 30, target = src)) + if(do_after(user, 3 SECONDS, target = src)) if (user.temporarilyRemoveItemFromInventory(W, TRUE)) place_on_head(W) return diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm index 698b62a1c2e9f..1bef64de8a66b 100644 --- a/code/modules/mob/living/simple_animal/bot/construction.dm +++ b/code/modules/mob/living/simple_animal/bot/construction.dm @@ -163,7 +163,7 @@ to_chat(user, span_warning("You need one length of cable to wire the ED-209!")) return to_chat(user, span_notice("You start to wire [src]...")) - if(do_after(user, 40, target = src)) + if(do_after(user, 4 SECONDS, target = src)) if(coil.get_amount() >= 1 && build_step == ASSEMBLY_SEVENTH_STEP) coil.use(1) to_chat(user, span_notice("You wire [src].")) @@ -546,7 +546,7 @@ to_chat(user, span_warning("You need one fluid duct to finish [src]")) return to_chat(user, span_notice("You start to pipe up [src]...")) - if(do_after(user, 40, target = src) && D.use(1)) + if(do_after(user, 4 SECONDS, target = src) && D.use(1)) to_chat(user, span_notice("You pipe up [src].")) var/mob/living/basic/bot/hygienebot/new_bot = new(drop_location()) new_bot.name = created_name diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm index 94713a69a12e8..faa7d3a9edb95 100644 --- a/code/modules/mob/living/simple_animal/bot/floorbot.dm +++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm @@ -326,7 +326,7 @@ toggle_magnet() visible_message(span_notice("[targetdirection ? "[src] begins installing a bridge plating." : "[src] begins to repair the hole."] ")) mode = BOT_REPAIRING - if(do_after(src, 50, target = target_turf) && mode == BOT_REPAIRING) + if(do_after(src, 5 SECONDS, target = target_turf) && mode == BOT_REPAIRING) if(autotile) //Build the floor and include a tile. if(replacetiles && tilestack) target_turf.place_on_top(/turf/open/floor/plating, flags = CHANGETURF_INHERIT_AIR) //make sure a hull is actually below the floor tile @@ -348,14 +348,14 @@ toggle_magnet() mode = BOT_REPAIRING visible_message(span_notice("[src] begins [(F.broken || F.burnt) ? "repairing the floor" : "placing a floor tile"].")) - if(do_after(src, 50, target = F) && mode == BOT_REPAIRING) + if(do_after(src, 5 SECONDS, target = F) && mode == BOT_REPAIRING) success = TRUE else if(replacetiles && tilestack && F.type != tilestack.turf_type) toggle_magnet() mode = BOT_REPAIRING visible_message(span_notice("[src] begins replacing the floor tiles.")) - if(do_after(src, 50, target = target_turf) && mode == BOT_REPAIRING && tilestack) + if(do_after(src, 5 SECONDS, target = target_turf) && mode == BOT_REPAIRING && tilestack) success = TRUE if(success) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm index d7fceecf0532f..a223004f85c4e 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm @@ -753,7 +753,7 @@ Difficulty: Hard var/obj/item/hierophant_club/club = attacking_item if(club.beacon == src) to_chat(user, span_notice("You start removing your hierophant beacon...")) - if(do_after(user, 50, target = src)) + if(do_after(user, 5 SECONDS, target = src)) playsound(src,'sound/magic/blind.ogg', 100, TRUE, -4) new /obj/effect/temp_visual/hierophant/telegraph/teleport(get_turf(src), user) to_chat(user, span_hierophant_warning("You collect [src], reattaching it to the club!")) diff --git a/code/modules/mob/living/simple_animal/hostile/ooze.dm b/code/modules/mob/living/simple_animal/hostile/ooze.dm index ddfe4c18ee83e..e20ecc2337a4d 100644 --- a/code/modules/mob/living/simple_animal/hostile/ooze.dm +++ b/code/modules/mob/living/simple_animal/hostile/ooze.dm @@ -223,7 +223,7 @@ to_chat(src, span_warning("You are already consuming another creature!")) return FALSE owner.visible_message(span_warning("[ooze] starts attempting to devour [target]!"), span_notice("You start attempting to devour [target].")) - if(!do_after(ooze, 15, target = ooze.pulling)) + if(!do_after(ooze, 1.5 SECONDS, target = ooze.pulling)) return FALSE var/mob/living/eat_target = ooze.pulling diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm index e55225b1ca00a..207b8351a58ea 100644 --- a/code/modules/paperwork/photocopier.dm +++ b/code/modules/paperwork/photocopier.dm @@ -595,7 +595,7 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) else user.visible_message(span_warning("[user] starts putting [target] onto the photocopier!"), span_notice("You start putting [target] onto the photocopier...")) - if(do_after(user, 20, target = src)) + if(do_after(user, 2 SECONDS, target = src)) if(!target || QDELETED(target) || QDELETED(src) || !Adjacent(target)) //check if the photocopier/target still exists. return diff --git a/code/modules/paperwork/ticketmachine.dm b/code/modules/paperwork/ticketmachine.dm index 56b7343995a2c..f9ade59edc1a5 100644 --- a/code/modules/paperwork/ticketmachine.dm +++ b/code/modules/paperwork/ticketmachine.dm @@ -187,7 +187,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/ticket_machine, 32) to_chat(user, span_notice("[src] refuses [I]! There [max_number - ticket_number == 1 ? "is" : "are"] still [max_number - ticket_number] ticket\s left!")) return to_chat(user, span_notice("You start to refill [src]'s ticket holder (doing this will reset its ticket count!).")) - if(do_after(user, 30, target = src)) + if(do_after(user, 3 SECONDS, target = src)) to_chat(user, span_notice("You insert [I] into [src] as it whirs nondescriptly.")) qdel(I) ticket_number = 0 diff --git a/code/modules/plumbing/plumbers/_plumb_machinery.dm b/code/modules/plumbing/plumbers/_plumb_machinery.dm index dcfa5faac5cbb..418df177465d2 100644 --- a/code/modules/plumbing/plumbers/_plumb_machinery.dm +++ b/code/modules/plumbing/plumbers/_plumb_machinery.dm @@ -36,7 +36,7 @@ /obj/machinery/plumbing/plunger_act(obj/item/plunger/P, mob/living/user, reinforced) to_chat(user, span_notice("You start furiously plunging [name].")) - if(do_after(user, 30, target = src)) + if(do_after(user, 3 SECONDS, target = src)) to_chat(user, span_notice("You finish plunging the [name].")) reagents.expose(get_turf(src), TOUCH) //splash on the floor reagents.clear_reagents() diff --git a/code/modules/plumbing/plumbers/iv_drip.dm b/code/modules/plumbing/plumbers/iv_drip.dm index bbdb80f57b16d..7275212ee7677 100644 --- a/code/modules/plumbing/plumbers/iv_drip.dm +++ b/code/modules/plumbing/plumbers/iv_drip.dm @@ -24,7 +24,7 @@ /obj/machinery/iv_drip/plumbing/plunger_act(obj/item/plunger/P, mob/living/user, reinforced) to_chat(user, span_notice("You start furiously plunging [name].")) - if(do_after(user, 30, target = src)) + if(do_after(user, 3 SECONDS, target = src)) to_chat(user, span_notice("You finish plunging the [name].")) reagents.expose(get_turf(src), TOUCH) //splash on the floor reagents.clear_reagents() diff --git a/code/modules/power/apc/apc_malf.dm b/code/modules/power/apc/apc_malf.dm index 62134de146e82..dee0d95de4daa 100644 --- a/code/modules/power/apc/apc_malf.dm +++ b/code/modules/power/apc/apc_malf.dm @@ -116,7 +116,7 @@ return FALSE to_chat(user, span_notice("AI accepted request. Transferring stored intelligence to [card]...")) to_chat(occupier, span_notice("Transfer starting. You will be moved to [card] shortly.")) - if(!do_after(user, 50, target = src)) + if(!do_after(user, 5 SECONDS, target = src)) to_chat(occupier, span_warning("[user] was interrupted! Transfer canceled.")) transfer_in_progress = FALSE return FALSE diff --git a/code/modules/power/apc/apc_tool_act.dm b/code/modules/power/apc/apc_tool_act.dm index 8ae76fe01549b..00718c4ada9d6 100644 --- a/code/modules/power/apc/apc_tool_act.dm +++ b/code/modules/power/apc/apc_tool_act.dm @@ -106,7 +106,7 @@ balloon_alert(user, "adding cables to the frame...") playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE) - if(!do_after(user, 20, target = src)) + if(!do_after(user, 2 SECONDS, target = src)) return ITEM_INTERACT_BLOCKING if(installing_cable.get_amount() < 10 || !installing_cable) return ITEM_INTERACT_BLOCKING @@ -140,7 +140,7 @@ balloon_alert(user, "inserting the board...") playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE) - if(!do_after(user, 10, target = src) || has_electronics) + if(!do_after(user, 1 SECONDS, target = src) || has_electronics) return ITEM_INTERACT_BLOCKING has_electronics = APC_ELECTRONICS_INSTALLED @@ -195,7 +195,7 @@ if((machine_stat & BROKEN) && opened == APC_COVER_REMOVED && has_electronics && terminal) // Cover is the only thing broken, we do not need to remove elctronicks to replace cover user.visible_message(span_notice("[user.name] replaces missing APC's cover.")) balloon_alert(user, "replacing APC's cover...") - if(!do_after(user, 20, target = src)) // replacing cover is quicker than replacing whole frame + if(!do_after(user, 2 SECONDS, target = src)) // replacing cover is quicker than replacing whole frame return ITEM_INTERACT_BLOCKING balloon_alert(user, "cover replaced") qdel(wallframe) @@ -209,7 +209,7 @@ return ITEM_INTERACT_BLOCKING user.visible_message(span_notice("[user.name] replaces the damaged APC frame with a new one.")) balloon_alert(user, "replacing damaged frame...") - if(!do_after(user, 50, target = src)) + if(!do_after(user, 5 SECONDS, target = src)) return ITEM_INTERACT_BLOCKING balloon_alert(user, "replaced frame") qdel(wallframe) diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index ffda41a42b0b4..7810f2efed826 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -573,7 +573,7 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri if(affecting && IS_ROBOTIC_LIMB(affecting)) if(user == H) user.visible_message(span_notice("[user] starts to fix some of the wires in [H]'s [affecting.name]."), span_notice("You start fixing some of the wires in [H == user ? "your" : "[H]'s"] [affecting.name].")) - if(!do_after(user, 50, H)) + if(!do_after(user, 5 SECONDS, H)) return if(item_heal_robotic(H, user, 0, 15)) use(1) diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm index a9a512bceafd7..8a1a948553986 100644 --- a/code/modules/power/smes.dm +++ b/code/modules/power/smes.dm @@ -145,7 +145,7 @@ to_chat(user, span_notice("You start building the power terminal...")) playsound(src.loc, 'sound/items/deconstruct.ogg', 50, TRUE) - if(do_after(user, 20, target = src)) + if(do_after(user, 2 SECONDS, target = src)) if(cable.get_amount() < 10 || !cable) return var/obj/structure/cable/connected_cable = turf.get_cable_node(terminal_cable_layer) //get the connecting node cable, if there's one diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 322ee737c9b09..2a18aae0c0f3e 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -592,7 +592,7 @@ semicd = TRUE - if(!bypass_timer && (!do_after(user, 120, target) || user.zone_selected != BODY_ZONE_PRECISE_MOUTH)) + if(!bypass_timer && (!do_after(user, 12 SECONDS, target) || user.zone_selected != BODY_ZONE_PRECISE_MOUTH)) if(user) if(user == target) user.visible_message(span_notice("[user] decided not to shoot.")) diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm index 8c069ae8c4be0..9a4eb8dc5db98 100644 --- a/code/modules/projectiles/guns/ballistic.dm +++ b/code/modules/projectiles/guns/ballistic.dm @@ -651,7 +651,7 @@ GLOBAL_LIST_INIT(gun_saw_types, typecacheof(list( user.visible_message(span_danger("[src] goes off!"), span_danger("[src] goes off in your face!")) return - if(do_after(user, 30, target = src)) + if(do_after(user, 3 SECONDS, target = src)) if(sawn_off) return user.visible_message(span_notice("[user] shortens [src]!"), span_notice("You shorten [src].")) @@ -681,7 +681,7 @@ GLOBAL_LIST_INIT(gun_saw_types, typecacheof(list( user.changeNext_move(CLICK_CD_MELEE) balloon_alert(user, "cleaning...") - if(do_after(user, 100, target = src)) + if(do_after(user, 10 SECONDS, target = src)) misfire_probability = initial(misfire_probability) balloon_alert(user, "fouling cleaned out") return TRUE diff --git a/code/modules/reagents/reagent_containers/cups/_cup.dm b/code/modules/reagents/reagent_containers/cups/_cup.dm index 6134731cafd9d..cb3ab1a122bde 100644 --- a/code/modules/reagents/reagent_containers/cups/_cup.dm +++ b/code/modules/reagents/reagent_containers/cups/_cup.dm @@ -473,7 +473,7 @@ var/picked_option = show_radial_menu(user, src, choose_options, radius = 38, require_near = TRUE) if(grinded && in_range(src, user) && user.is_holding(I) && picked_option) to_chat(user, span_notice("You start grinding...")) - if(do_after(user, 25, target = src)) + if(do_after(user, 2.5 SECONDS, target = src)) user.adjustStaminaLoss(40) switch(picked_option) if("Juice") diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm index 278030fbc44fb..47352fc6240af 100644 --- a/code/modules/recycling/sortingmachinery.dm +++ b/code/modules/recycling/sortingmachinery.dm @@ -79,7 +79,7 @@ movable_loc.relay_container_resist_act(user, object) return to_chat(user, span_notice("You lean on the back of [object] and start pushing to rip the wrapping around it.")) - if(do_after(user, 50, target = object)) + if(do_after(user, 5 SECONDS, target = object)) if(!user || user.stat != CONSCIOUS || user.loc != object || object.loc != src) return to_chat(user, span_notice("You successfully removed [object]'s wrapping!")) diff --git a/code/modules/research/xenobiology/crossbreeding/_potions.dm b/code/modules/research/xenobiology/crossbreeding/_potions.dm index 7b37ce3ae6b55..ecf76357e2010 100644 --- a/code/modules/research/xenobiology/crossbreeding/_potions.dm +++ b/code/modules/research/xenobiology/crossbreeding/_potions.dm @@ -54,7 +54,7 @@ Slimecrossing Potions peace_target.visible_message(span_danger("[user] starts to drink [src]!"), span_danger("You start to drink [src]!")) - if(!do_after(user, 100, target = peace_target)) + if(!do_after(user, 10 SECONDS, target = peace_target)) return if(peace_target != user) to_chat(user, span_notice("You feed [peace_target] [src]!")) @@ -91,7 +91,7 @@ Slimecrossing Potions love_target.visible_message(span_danger("[user] starts to feed [love_target] a love potion!"), span_userdanger("[user] starts to feed you a love potion!")) - if(!do_after(user, 50, target = love_target)) + if(!do_after(user, 5 SECONDS, target = love_target)) return to_chat(user, span_notice("You feed [love_target] the love potion!")) to_chat(love_target, span_notice("You develop feelings for [user], and anyone [user.p_they()] like[user.p_s()].")) diff --git a/code/modules/research/xenobiology/crossbreeding/chilling.dm b/code/modules/research/xenobiology/crossbreeding/chilling.dm index 2a23e34cb171b..0d7396be1e573 100644 --- a/code/modules/research/xenobiology/crossbreeding/chilling.dm +++ b/code/modules/research/xenobiology/crossbreeding/chilling.dm @@ -174,7 +174,7 @@ Chilling extracts: for(var/mob/living/M in allies) var/datum/status_effect/slimerecall/S = M.apply_status_effect(/datum/status_effect/slimerecall) S.target = user - if(do_after(user, 100, target=src)) + if(do_after(user, 10 SECONDS, target=src)) to_chat(user, span_notice("[src] shatters as it tears a hole in reality, snatching the linked individuals from the void!")) for(var/mob/living/M in allies) var/datum/status_effect/slimerecall/S = M.has_status_effect(/datum/status_effect/slimerecall) diff --git a/code/modules/research/xenobiology/crossbreeding/consuming.dm b/code/modules/research/xenobiology/crossbreeding/consuming.dm index bffc15256943d..5a23d30671f54 100644 --- a/code/modules/research/xenobiology/crossbreeding/consuming.dm +++ b/code/modules/research/xenobiology/crossbreeding/consuming.dm @@ -66,7 +66,7 @@ Consuming extracts: fed = TRUE else M.visible_message(span_danger("[user] tries to force [M] to eat [src]!"), span_userdanger("[user] tries to force you to eat [src]!")) - if(do_after(user, 20, target = M)) + if(do_after(user, 2 SECONDS, target = M)) fed = TRUE M.visible_message(span_danger("[user] forces [M] to eat [src]!"), span_warning("[user] forces you to eat [src].")) if(fed) diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm index 866b2902b3389..e14c1e56e39a4 100644 --- a/code/modules/research/xenobiology/xenobiology.dm +++ b/code/modules/research/xenobiology/xenobiology.dm @@ -108,7 +108,7 @@ return 120 if(SLIME_ACTIVATE_MAJOR) to_chat(user, span_notice("Your [name] starts pulsing...")) - if(do_after(user, 40, target = user)) + if(do_after(user, 4 SECONDS, target = user)) var/mob/living/basic/slime/new_slime = new(get_turf(user), /datum/slime_type/grey) playsound(user, 'sound/effects/splat.ogg', 50, TRUE) to_chat(user, span_notice("You spit out [new_slime].")) @@ -128,7 +128,7 @@ switch(activation_type) if(SLIME_ACTIVATE_MINOR) user.visible_message(span_warning("[user] starts shaking!"),span_notice("Your [name] starts pulsing gently...")) - if(do_after(user, 40, target = user)) + if(do_after(user, 4 SECONDS, target = user)) var/mob/living/spawned_mob = create_random_mob(user.drop_location(), FRIENDLY_SPAWN) spawned_mob.faction |= FACTION_NEUTRAL playsound(user, 'sound/effects/splat.ogg', 50, TRUE) @@ -137,7 +137,7 @@ if(SLIME_ACTIVATE_MAJOR) user.visible_message(span_warning("[user] starts shaking violently!"),span_warning("Your [name] starts pulsing violently...")) - if(do_after(user, 50, target = user)) + if(do_after(user, 5 SECONDS, target = user)) var/mob/living/spawned_mob = create_random_mob(user.drop_location(), HOSTILE_SPAWN) if(!user.combat_mode) spawned_mob.faction |= FACTION_NEUTRAL @@ -279,7 +279,7 @@ if(SLIME_ACTIVATE_MAJOR) user.visible_message(span_warning("[user]'s skin starts flashing intermittently..."), span_warning("Your skin starts flashing intermittently...")) - if(do_after(user, 25, target = user)) + if(do_after(user, 2.5 SECONDS, target = user)) empulse(user, 1, 2) user.visible_message(span_warning("[user]'s skin flashes!"), span_warning("Your skin flashes as you emit an electromagnetic pulse!")) return 600 @@ -384,7 +384,7 @@ switch(activation_type) if(SLIME_ACTIVATE_MINOR) to_chat(user, span_warning("You feel yourself reverting to human form...")) - if(do_after(user, 120, target = user)) + if(do_after(user, 12 SECONDS, target = user)) to_chat(user, span_warning("You feel human again!")) user.set_species(/datum/species/human) return @@ -392,7 +392,7 @@ if(SLIME_ACTIVATE_MAJOR) to_chat(user, span_warning("You feel yourself radically changing your slime type...")) - if(do_after(user, 120, target = user)) + if(do_after(user, 12 SECONDS, target = user)) to_chat(user, span_warning("You feel different!")) user.set_species(pick(/datum/species/jelly/slime, /datum/species/jelly/stargazer)) return @@ -437,7 +437,7 @@ if(SLIME_ACTIVATE_MAJOR) to_chat(user, span_warning("You feel your own light turning dark...")) - if(do_after(user, 120, target = user)) + if(do_after(user, 12 SECONDS, target = user)) to_chat(user, span_warning("You feel a longing for darkness.")) user.set_species(pick(/datum/species/shadow)) return @@ -459,7 +459,7 @@ if(SLIME_ACTIVATE_MAJOR) user.visible_message(span_warning("[user]'s skin starts pulsing and glowing ominously..."), span_userdanger("You feel unstable...")) - if(do_after(user, 60, target = user)) + if(do_after(user, 6 SECONDS, target = user)) to_chat(user, span_userdanger("You explode!")) explosion(user, devastation_range = 1, heavy_impact_range = 3, light_impact_range = 6, explosion_cause = src) user.investigate_log("has been gibbed by an oil slime extract explosion.", INVESTIGATE_DEATHS) @@ -487,7 +487,7 @@ if(SLIME_ACTIVATE_MAJOR) to_chat(user, span_warning("You feel your body rapidly hardening...")) - if(do_after(user, 120, target = user)) + if(do_after(user, 12 SECONDS, target = user)) to_chat(user, span_warning("You feel solid.")) user.set_species(/datum/species/golem) return @@ -511,7 +511,7 @@ switch(activation_type) if(SLIME_ACTIVATE_MINOR) to_chat(user, span_warning("You feel your body vibrating...")) - if(do_after(user, 25, target = user)) + if(do_after(user, 2.5 SECONDS, target = user)) to_chat(user, span_warning("You teleport!")) do_teleport(user, get_turf(user), 6, asoundin = 'sound/weapons/emitter2.ogg', channel = TELEPORT_CHANNEL_BLUESPACE) return 300 @@ -598,7 +598,7 @@ if(SLIME_ACTIVATE_MAJOR) to_chat(user, span_warning("You feel time slow down...")) - if(do_after(user, 30, target = user)) + if(do_after(user, 3 SECONDS, target = user)) new /obj/effect/timestop(get_turf(user), 2, 50, list(user)) return 900 diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 7cfbcf05e5e00..445dba9af1310 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -393,7 +393,7 @@ playsound(loc, 'sound/weapons/slice.ogg', 50, TRUE, -1) user.visible_message(span_warning("[user] begins to cut open [src]."),\ span_notice("You begin to cut open [src]...")) - if(do_after(user, 54, target = src)) + if(do_after(user, 5.4 SECONDS, target = src)) drop_organs(user, TRUE) else return ..() diff --git a/code/modules/vehicles/mecha/working/ripley.dm b/code/modules/vehicles/mecha/working/ripley.dm index 711da429cca2f..a4872289e962c 100644 --- a/code/modules/vehicles/mecha/working/ripley.dm +++ b/code/modules/vehicles/mecha/working/ripley.dm @@ -318,7 +318,7 @@ GLOBAL_DATUM(cargo_ripley, /obj/vehicle/sealed/mecha/ripley/cargo) /obj/item/mecha_parts/mecha_equipment/ejector/relay_container_resist_act(mob/living/user, obj/container) to_chat(user, span_notice("You lean on the back of [container] and start pushing so it falls out of [src].")) - if(do_after(user, 300, target = container)) + if(do_after(user, 30 SECONDS, target = container)) if(!user || user.stat != CONSCIOUS || user.loc != src || container.loc != src ) return to_chat(user, span_notice("You successfully pushed [container] out of [src]!")) diff --git a/code/modules/vehicles/secway.dm b/code/modules/vehicles/secway.dm index fb23739333888..c8cab1a7dc1cd 100644 --- a/code/modules/vehicles/secway.dm +++ b/code/modules/vehicles/secway.dm @@ -77,7 +77,7 @@ if(!eddie_murphy) return ..() user.visible_message(span_warning("[user] begins cleaning [eddie_murphy] out of [src]."), span_warning("You begin cleaning [eddie_murphy] out of [src]...")) - if(!do_after(user, 60, target = src)) + if(!do_after(user, 6 SECONDS, target = src)) return ..() user.visible_message(span_warning("[user] cleans [eddie_murphy] out of [src]."), span_warning("You manage to get [eddie_murphy] out of [src].")) eddie_murphy.forceMove(drop_location()) diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm index 4a37ba6cc9a64..00f961b498c07 100644 --- a/code/modules/vending/_vending.dm +++ b/code/modules/vending/_vending.dm @@ -1180,7 +1180,7 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock) if(tilted && !user.buckled && !isAdminGhostAI(user)) to_chat(user, span_notice("You begin righting [src].")) - if(do_after(user, 50, target=src)) + if(do_after(user, 5 SECONDS, target=src)) untilt(user) return From 4b6926c5e9fa60f9fa932e05ee0ecb46fe1fbe49 Mon Sep 17 00:00:00 2001 From: Archie700 Date: Fri, 5 Apr 2024 08:56:56 +0800 Subject: [PATCH 022/938] Updates cyborg cells created from borgifier to the SI standard (#82437) ## About The Pull Request Unchanged value in transformer.dm resulted in borg charge draining to zero immediately after forced conversion in the borgifer. Changing the value of robot cell charge to 5 MJs to fix this. ## Why It's Good For The Game Fixes #82426 ## Changelog :cl: fix: changed value of cell charge from 5000 to 5 megajoules /:cl: --- code/game/machinery/transformer.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/machinery/transformer.dm b/code/game/machinery/transformer.dm index 9c87ca0cfc746..ecb7ef941aad8 100644 --- a/code/game/machinery/transformer.dm +++ b/code/game/machinery/transformer.dm @@ -20,7 +20,7 @@ /// How long until the next mob can be processed var/cooldown_timer /// The created cyborg's cell chage - var/robot_cell_charge = 5000 + var/robot_cell_charge = STANDARD_CELL_CHARGE * 5 /// The visual countdown effect var/obj/effect/countdown/transformer/countdown /// Who the master AI is that created this factory From 7f8ea34a0e6721a85918213165e8c241c4f9a409 Mon Sep 17 00:00:00 2001 From: _0Steven <42909981+00-Steven@users.noreply.github.com> Date: Fri, 5 Apr 2024 02:57:04 +0200 Subject: [PATCH 023/938] Makes attempting to refresh the logs not just throw a runtime error (#82432) ## About The Pull Request Really all this seems to be is a mismatch between the tgui and dm side of the menu. https://github.com/tgstation/tgstation/blob/3c71b14df0957749f31fb2e678130daf4cfb3250/tgui/packages/tgui/interfaces/LogViewer.tsx#L71 https://github.com/tgstation/tgstation/blob/3c71b14df0957749f31fb2e678130daf4cfb3250/code/modules/logging/log_holder.dm#L110-L113 Making these line up by renaming `re-render` to `refresh` seems to make it work just fine, and not just throw an error. ## Why It's Good For The Game Life tends to be better when refreshing to see new runtimes doesn't just add its own lovely little runtimes. ![image](https://github.com/tgstation/tgstation/assets/42909981/79bee3db-5c28-409b-9ff5-3a315fb4ed1c) ![image](https://github.com/tgstation/tgstation/assets/42909981/82a25038-ba7a-430a-bb79-f59d5f4b262b) And then not show them til you re-open the window cause it doesn't refresh. ## Changelog :cl: admin: Refresh button on the View Round Logs menu actually works, instead of just adding a runtime to the logs (and not updating them). /:cl: --- code/modules/logging/log_holder.dm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/code/modules/logging/log_holder.dm b/code/modules/logging/log_holder.dm index 1102df45f4f2a..20ff2c866b308 100644 --- a/code/modules/logging/log_holder.dm +++ b/code/modules/logging/log_holder.dm @@ -107,11 +107,10 @@ GENERAL_PROTECT_DATUM(/datum/log_holder) return switch(action) - if("re-render") + if("refresh") cache_ui_data() SStgui.update_uis(src) return TRUE - else stack_trace("unknown ui_act action [action] for [type]") From ef69920a3a6603e8f6f53de682d98ee97ef8a671 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 5 Apr 2024 13:59:37 +1300 Subject: [PATCH 024/938] Automatic changelog for PR #82280 [ci skip] --- html/changelogs/AutoChangeLog-pr-82280.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82280.yml diff --git a/html/changelogs/AutoChangeLog-pr-82280.yml b/html/changelogs/AutoChangeLog-pr-82280.yml new file mode 100644 index 0000000000000..ebcc638cfca03 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82280.yml @@ -0,0 +1,4 @@ +author: "SyncIt21" +delete-after: True +changes: + - refactor: "refactors how objects are deconstructed in relation to the `NO_DECONSTRUCTION` flag. Certain objects & machinery may display different tool interactions & behaviours when destroyed/deconstructed. Report these changes if you feel like they are bugs" \ No newline at end of file From cc692ae9f4447292ab277da45b3496c7b88eaaf7 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 5 Apr 2024 14:00:05 +1300 Subject: [PATCH 025/938] Automatic changelog for PR #82437 [ci skip] --- html/changelogs/AutoChangeLog-pr-82437.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82437.yml diff --git a/html/changelogs/AutoChangeLog-pr-82437.yml b/html/changelogs/AutoChangeLog-pr-82437.yml new file mode 100644 index 0000000000000..8978467f002f7 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82437.yml @@ -0,0 +1,4 @@ +author: "Archie700" +delete-after: True +changes: + - bugfix: "changed value of cell charge from 5000 to 5 megajoules" \ No newline at end of file From ec64d626c3db5851ce04ce113ee18ee393badfd4 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 5 Apr 2024 14:00:19 +1300 Subject: [PATCH 026/938] Automatic changelog for PR #82432 [ci skip] --- html/changelogs/AutoChangeLog-pr-82432.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82432.yml diff --git a/html/changelogs/AutoChangeLog-pr-82432.yml b/html/changelogs/AutoChangeLog-pr-82432.yml new file mode 100644 index 0000000000000..11e0e41f785f0 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82432.yml @@ -0,0 +1,4 @@ +author: "00-Steven" +delete-after: True +changes: + - admin: "Refresh button on the View Round Logs menu actually works, instead of just adding a runtime to the logs (and not updating them)." \ No newline at end of file From cd2bceafecafd4569dec2874b1021b9b359617ae Mon Sep 17 00:00:00 2001 From: Blacklist897 <149209377+Blacklist897@users.noreply.github.com> Date: Fri, 5 Apr 2024 14:02:59 +1300 Subject: [PATCH 027/938] cell chargers now bypass APCs (#82309) ## About The Pull Request This makes cell chargers and suit storage units draw from the grid before the local apc ## Why It's Good For The Game Upgraded Cell chargers have a charging power of 1MW leading to them instantly draining the apc of any room they are in, this Pr makes them draw from the grid preventing immediate blackout. This is a stopgap until someone smarter than me changes power values so a pocket-sized battery won't require the same power to charge then over 600 average suburban homes. ## Changelog :cl: balance: suit and cell chargers should draw from grid preventing instant apc blackouts in most cases. /:cl: --- code/game/machinery/cell_charger.dm | 2 +- code/game/machinery/suit_storage_unit.dm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/game/machinery/cell_charger.dm b/code/game/machinery/cell_charger.dm index aaa24526da5e5..cff1c0bdac9e5 100644 --- a/code/game/machinery/cell_charger.dm +++ b/code/game/machinery/cell_charger.dm @@ -141,6 +141,6 @@ return use_energy(main_draw * 0.01) //use a small bit for the charger itself, but power usage scales up with the part tier - charge_cell(main_draw, charging) + charge_cell(main_draw, charging, grid_only = TRUE) update_appearance() diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index eed7ba47877d1..9ccecc436bf7f 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -567,7 +567,7 @@ var/charge_per_item = (final_charge_rate * seconds_per_tick) / cell_count for(var/obj/item/stock_parts/cell/cell as anything in cells_to_charge) - charge_cell(charge_per_item, cell) + charge_cell(charge_per_item, cell, grid_only = TRUE) /obj/machinery/suit_storage_unit/proc/shock(mob/user, prb) if(!prob(prb)) From 25d7675581ea0bddd8c49e612c174d459226d70c Mon Sep 17 00:00:00 2001 From: Zergspower Date: Thu, 4 Apr 2024 20:03:36 -0500 Subject: [PATCH 028/938] Inducer fixes for Syndie and Borg (#82430) Borg and Syndies ## About The Pull Request The borg and syndie inducers were basically inoperable, so this just fixes that ![image](https://github.com/tgstation/tgstation/assets/22140677/b0bc411a-ad38-456f-944b-5272e121a01f) ![image](https://github.com/tgstation/tgstation/assets/22140677/ebaab84f-36e7-4871-958b-eb47af335a3a) Also i just noticed TG borgs have no Messenger or ability to see the manifest??? ## Why It's Good For The Game ## Changelog :cl:Zergspower fix: fixes Borg and Syndicate inducers not working /:cl: --- code/game/objects/items/inducer.dm | 2 +- code/game/objects/items/robot/robot_upgrades.dm | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/code/game/objects/items/inducer.dm b/code/game/objects/items/inducer.dm index c3637644aab54..086b965e1ac41 100644 --- a/code/game/objects/items/inducer.dm +++ b/code/game/objects/items/inducer.dm @@ -203,5 +203,5 @@ icon_state = "inducer-syndi" inhand_icon_state = "inducer-syndi" desc = "A tool for inductively charging internal power cells. This one has a suspicious colour scheme, and seems to be rigged to transfer charge at a much faster rate." - powertransfer = 2000 + powertransfer = 2 * STANDARD_CELL_CHARGE cell_type = /obj/item/stock_parts/cell/super diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 9a1f92f58ec53..bccf596ebba01 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -633,7 +633,6 @@ /obj/item/inducer/cyborg name = "Internal inducer" - powertransfer = 1500 icon = 'icons/obj/tools.dmi' icon_state = "inducer-engi" cell_type = null From d257ef17b07cce390a0c4737755d307c8830e2e4 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 5 Apr 2024 14:26:24 +1300 Subject: [PATCH 029/938] Automatic changelog for PR #82309 [ci skip] --- html/changelogs/AutoChangeLog-pr-82309.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82309.yml diff --git a/html/changelogs/AutoChangeLog-pr-82309.yml b/html/changelogs/AutoChangeLog-pr-82309.yml new file mode 100644 index 0000000000000..dde2c2f5c8b95 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82309.yml @@ -0,0 +1,4 @@ +author: "Blacklist897" +delete-after: True +changes: + - balance: "suit and cell chargers should draw from grid preventing instant apc blackouts in most cases." \ No newline at end of file From d0c1ecd6efda15a65eec101a6cdf70e141333449 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 5 Apr 2024 14:26:45 +1300 Subject: [PATCH 030/938] Automatic changelog for PR #82430 [ci skip] --- html/changelogs/AutoChangeLog-pr-82430.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82430.yml diff --git a/html/changelogs/AutoChangeLog-pr-82430.yml b/html/changelogs/AutoChangeLog-pr-82430.yml new file mode 100644 index 0000000000000..99ef15b39ba32 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82430.yml @@ -0,0 +1,4 @@ +author: "Zergspower" +delete-after: True +changes: + - bugfix: "fixes Borg and Syndicate inducers not working" \ No newline at end of file From c4487459766d3f883d190e336fa68062d91f1829 Mon Sep 17 00:00:00 2001 From: Jeremiah <42397676+jlsnow301@users.noreply.github.com> Date: Thu, 4 Apr 2024 19:02:14 -0700 Subject: [PATCH 031/938] Creates a "busy" animation for players (#82416) ## About The Pull Request Little indicator above a player when they're currently doing something.
vids Perspective: You are the moth ![dreamseeker_b2LA4PpPAr](https://github.com/tgstation/tgstation/assets/42397676/3a38dd3c-23f2-430f-acf4-444ad5c478d3) Hides under runechat ![dreamseeker_ZgkCWTGqDz](https://github.com/tgstation/tgstation/assets/42397676/ec1d9665-4ff0-47f7-85b6-65998c31b9be)
Todo: - [x] Feedback? - [x] Sneaky params so it doesn't spoil your stealth run - [x] Possible refactor - [x] Probably missed some "sneaky" actions - [x] coggers ## Why It's Good For The Game
sound on: https://github.com/tgstation/tgstation/assets/42397676/ad71c567-0202-4158-ba50-c2946375f988
## Changelog :cl: jlsnow301, infraredbaron add: Added a new UI element over players that are interacting, building, etc. /:cl: --------- Co-authored-by: Zephyr <12817816+ZephyrTFA@users.noreply.github.com> Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Co-authored-by: san7890 --- code/__HELPERS/mobs.dm | 11 ++- code/datums/cogbar.dm | 87 ++++++++++++++++++ code/game/machinery/fat_sucker.dm | 2 +- code/game/objects/items/syndie_spraycan.dm | 2 +- .../structures/syndicate_uplink_beacon.dm | 4 +- .../antagonists/changeling/powers/absorb.dm | 2 +- .../antagonists/heretic/heretic_antag.dm | 2 +- .../modules/antagonists/heretic/influences.dm | 2 +- .../antagonists/heretic/magic/manse_link.dm | 2 +- .../antagonists/heretic/magic/mirror_walk.dm | 4 +- .../antagonists/ninja/ninjaDrainAct.dm | 30 +++--- .../nukeop/equipment/borgchameleon.dm | 2 +- .../equipment/nuclear_bomb/_nuclear_bomb.dm | 2 +- code/modules/antagonists/spy/spy_uplink.dm | 2 +- .../antagonists/traitor/objectives/infect.dm | 2 +- .../traitor/objectives/locate_weakpoint.dm | 2 +- .../traitor/objectives/sabotage_machinery.dm | 2 +- .../antagonists/traitor/objectives/steal.dm | 2 +- .../components/unary_devices/cryo.dm | 2 +- .../clothing/chameleon/chameleon_scanner.dm | 2 +- .../carbon/human/species_types/vampire.dm | 2 +- icons/effects/progressbar.dmi | Bin 1013 -> 1246 bytes tgstation.dme | 1 + 23 files changed, 133 insertions(+), 36 deletions(-) create mode 100644 code/datums/cogbar.dm diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index ff218afe1e1ac..126a565bd359f 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -217,8 +217,10 @@ GLOBAL_LIST_EMPTY(species_list) * @param {string} interaction_key - The assoc key under which the do_after is capped, with max_interact_count being the cap. Interaction key will default to target if not set. * * @param {number} max_interact_count - The maximum amount of interactions allowed. + * + * @param {boolean} hidden - By default, any action 1 second or longer shows a cog over the user while it is in progress. If hidden is set to TRUE, the cog will not be shown. */ -/proc/do_after(mob/user, delay, atom/target, timed_action_flags = NONE, progress = TRUE, datum/callback/extra_checks, interaction_key, max_interact_count = 1) +/proc/do_after(mob/user, delay, atom/target, timed_action_flags = NONE, progress = TRUE, datum/callback/extra_checks, interaction_key, max_interact_count = 1, hidden = FALSE) if(!user) return FALSE if(!isnum(delay)) @@ -245,10 +247,15 @@ GLOBAL_LIST_EMPTY(species_list) delay *= user.cached_multiplicative_actions_slowdown var/datum/progressbar/progbar + var/datum/cogbar/cog + if(progress) if(user.client) progbar = new(user, delay, target || user) + if(!hidden && delay >= 1 SECONDS) + cog = new(user) + SEND_SIGNAL(user, COMSIG_DO_AFTER_BEGAN) var/endtime = world.time + delay @@ -280,6 +287,8 @@ GLOBAL_LIST_EMPTY(species_list) if(!QDELETED(progbar)) progbar.end_progress() + + cog?.remove() if(interaction_key) var/reduced_interaction_count = (LAZYACCESS(user.do_afters, interaction_key) || 0) - 1 diff --git a/code/datums/cogbar.dm b/code/datums/cogbar.dm new file mode 100644 index 0000000000000..c52092e5bd1bb --- /dev/null +++ b/code/datums/cogbar.dm @@ -0,0 +1,87 @@ +#define COGBAR_ANIMATION_TIME 5 DECISECONDS + +/** + * ### Cogbar + * Represents that the user is busy doing something. + */ +/datum/cogbar + /// Who's doing the thing + var/mob/user + /// The user client + var/client/user_client + /// The visible element to other players + var/obj/effect/overlay/vis/cog + /// The blank image that overlaps the cog - hides it from the source user + var/image/blank + /// The offset of the icon + var/offset_y + + +/datum/cogbar/New(mob/user) + src.user = user + src.user_client = user.client + + var/list/icon_offsets = user.get_oversized_icon_offsets() + offset_y = icon_offsets["y"] + + add_cog_to_user() + + RegisterSignal(user, COMSIG_QDELETING, PROC_REF(on_user_delete)) + + +/datum/cogbar/Destroy() + if(user) + SSvis_overlays.remove_vis_overlay(user, user.managed_vis_overlays) + user_client?.images -= blank + + user = null + user_client = null + cog = null + QDEL_NULL(blank) + + return ..() + + +/// Adds the cog to the user, visible by other players +/datum/cogbar/proc/add_cog_to_user() + cog = SSvis_overlays.add_vis_overlay(user, + icon = 'icons/effects/progressbar.dmi', + iconstate = "cog", + plane = HIGH_GAME_PLANE, + add_appearance_flags = APPEARANCE_UI_IGNORE_ALPHA, + unique = TRUE, + alpha = 0, + ) + cog.pixel_y = world.icon_size + offset_y + animate(cog, alpha = 255, time = COGBAR_ANIMATION_TIME) + + if(isnull(user_client)) + return + + blank = image('icons/blanks/32x32.dmi', cog, "nothing") + SET_PLANE_EXPLICIT(blank, HIGH_GAME_PLANE, user) + blank.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA + blank.override = TRUE + + user_client.images += blank + + +/// Removes the cog from the user +/datum/cogbar/proc/remove() + if(isnull(cog)) + qdel(src) + return + + animate(cog, alpha = 0, time = COGBAR_ANIMATION_TIME) + + QDEL_IN(src, COGBAR_ANIMATION_TIME) + + +/// When the user is deleted, remove the cog +/datum/cogbar/proc/on_user_delete(datum/source) + SIGNAL_HANDLER + + qdel(src) + + +#undef COGBAR_ANIMATION_TIME diff --git a/code/game/machinery/fat_sucker.dm b/code/game/machinery/fat_sucker.dm index 279e83ecbe999..4567959b8443f 100644 --- a/code/game/machinery/fat_sucker.dm +++ b/code/game/machinery/fat_sucker.dm @@ -80,7 +80,7 @@ user.visible_message(span_notice("You see [user] kicking against the door of [src]!"), \ span_notice("You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)"), \ span_hear("You hear a metallic creaking from [src].")) - if(do_after(user, breakout_time, target = src)) + if(do_after(user, breakout_time, target = src, hidden = TRUE)) if(!user || user.stat != CONSCIOUS || user.loc != src || state_open) return free_exit = TRUE diff --git a/code/game/objects/items/syndie_spraycan.dm b/code/game/objects/items/syndie_spraycan.dm index 02a576a2cb97d..774219fa12229 100644 --- a/code/game/objects/items/syndie_spraycan.dm +++ b/code/game/objects/items/syndie_spraycan.dm @@ -86,7 +86,7 @@ if(HAS_TRAIT(user, TRAIT_TAGGER)) wait_time *= 0.5 - if(!do_after(user, wait_time, target)) + if(!do_after(user, wait_time, target, hidden = TRUE)) user.balloon_alert(user, "interrupted!") drawing_rune = FALSE return FALSE diff --git a/code/game/objects/structures/syndicate_uplink_beacon.dm b/code/game/objects/structures/syndicate_uplink_beacon.dm index f4d4ea6fe6421..2106fade55a5c 100644 --- a/code/game/objects/structures/syndicate_uplink_beacon.dm +++ b/code/game/objects/structures/syndicate_uplink_beacon.dm @@ -43,7 +43,7 @@ return var/datum/looping_sound/typing/typing_sounds = new(src, start_immediately = TRUE) balloon_alert(user, "synchronizing...") - if(!do_after(user = user, delay = 3 SECONDS, target = src, interaction_key = REF(src))) + if(!do_after(user = user, delay = 3 SECONDS, target = src, interaction_key = REF(src), hidden = TRUE)) typing_sounds.stop() return typing_sounds.stop() @@ -52,7 +52,7 @@ /obj/structure/syndicate_uplink_beacon/screwdriver_act_secondary(mob/living/user, obj/item/tool) tool.play_tool_sound(src) balloon_alert(user, "deconstructing...") - if (!do_after(user, 5 SECONDS, target = src)) + if (!do_after(user, 5 SECONDS, target = src, hidden = TRUE)) return FALSE var/turf/beacon_tile = get_turf(src) new /obj/item/stack/sheet/iron/five(beacon_tile) diff --git a/code/modules/antagonists/changeling/powers/absorb.dm b/code/modules/antagonists/changeling/powers/absorb.dm index 5bd0f390cb8bb..7e13612153b49 100644 --- a/code/modules/antagonists/changeling/powers/absorb.dm +++ b/code/modules/antagonists/changeling/powers/absorb.dm @@ -145,7 +145,7 @@ target.take_overall_damage(40) SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("Absorb DNA", "[absorbing_iteration]")) - if(!do_after(owner, 15 SECONDS, target)) + if(!do_after(owner, 15 SECONDS, target, hidden = TRUE)) owner.balloon_alert(owner, "interrupted!") is_absorbing = FALSE return FALSE diff --git a/code/modules/antagonists/heretic/heretic_antag.dm b/code/modules/antagonists/heretic/heretic_antag.dm index 01ca69fa734c6..b95b608d535f4 100644 --- a/code/modules/antagonists/heretic/heretic_antag.dm +++ b/code/modules/antagonists/heretic/heretic_antag.dm @@ -350,7 +350,7 @@ else drawing_effect = new(target_turf, rune_colour) - if(!do_after(user, drawing_time, target_turf, extra_checks = additional_checks)) + if(!do_after(user, drawing_time, target_turf, extra_checks = additional_checks, hidden = TRUE)) target_turf.balloon_alert(user, "interrupted!") new /obj/effect/temp_visual/drawing_heretic_rune/fail(target_turf, rune_colour) qdel(drawing_effect) diff --git a/code/modules/antagonists/heretic/influences.dm b/code/modules/antagonists/heretic/influences.dm index 5123f7ec4bf62..662af81249a5c 100644 --- a/code/modules/antagonists/heretic/influences.dm +++ b/code/modules/antagonists/heretic/influences.dm @@ -282,7 +282,7 @@ being_drained = TRUE balloon_alert(user, "draining influence...") - if(!do_after(user, 10 SECONDS, src)) + if(!do_after(user, 10 SECONDS, src, hidden = TRUE)) being_drained = FALSE balloon_alert(user, "interrupted!") return diff --git a/code/modules/antagonists/heretic/magic/manse_link.dm b/code/modules/antagonists/heretic/magic/manse_link.dm index 565e7e683ebdf..06fd4dd9863f4 100644 --- a/code/modules/antagonists/heretic/magic/manse_link.dm +++ b/code/modules/antagonists/heretic/magic/manse_link.dm @@ -55,7 +55,7 @@ to_chat(owner, span_notice("You begin linking [linkee]'s mind to yours...")) to_chat(linkee, span_warning("You feel your mind being pulled somewhere... connected... intertwined with the very fabric of reality...")) - if(!do_after(owner, link_time, linkee)) + if(!do_after(owner, link_time, linkee, hidden = TRUE)) to_chat(owner, span_warning("You fail to link to [linkee]'s mind.")) to_chat(linkee, span_warning("The foreign presence leaves your mind.")) return FALSE diff --git a/code/modules/antagonists/heretic/magic/mirror_walk.dm b/code/modules/antagonists/heretic/magic/mirror_walk.dm index 0bc9b05902025..b9029e1ab072d 100644 --- a/code/modules/antagonists/heretic/magic/mirror_walk.dm +++ b/code/modules/antagonists/heretic/magic/mirror_walk.dm @@ -64,7 +64,7 @@ jaunter.Beam(nearby_reflection, icon_state = "light_beam", time = phase_out_time) nearby_reflection.visible_message(span_warning("[nearby_reflection] begins to shimmer and shake slightly!")) - if(!do_after(jaunter, phase_out_time, nearby_reflection, IGNORE_USER_LOC_CHANGE|IGNORE_INCAPACITATED)) + if(!do_after(jaunter, phase_out_time, nearby_reflection, IGNORE_USER_LOC_CHANGE|IGNORE_INCAPACITATED, hidden = TRUE)) return playsound(jaunter, 'sound/magic/ethereal_enter.ogg', 50, TRUE, -1) @@ -96,7 +96,7 @@ nearby_reflection.Beam(phase_turf, icon_state = "light_beam", time = phase_in_time) nearby_reflection.visible_message(span_warning("[nearby_reflection] begins to shimmer and shake slightly!")) - if(!do_after(unjaunter, phase_in_time, nearby_reflection)) + if(!do_after(unjaunter, phase_in_time, nearby_reflection, hidden = TRUE)) return FALSE // We can move around while phasing in, but we'll always end up where we started it. diff --git a/code/modules/antagonists/ninja/ninjaDrainAct.dm b/code/modules/antagonists/ninja/ninjaDrainAct.dm index 7f11d934cc6ff..af77a18417857 100644 --- a/code/modules/antagonists/ninja/ninjaDrainAct.dm +++ b/code/modules/antagonists/ninja/ninjaDrainAct.dm @@ -32,7 +32,7 @@ if(hacking_module.mod.get_charge() + drain > hacking_module.mod.get_max_charge()) drain = hacking_module.mod.get_max_charge() - hacking_module.mod.get_charge() maxcapacity = TRUE//Reached maximum battery capacity. - if (do_after(ninja, 1 SECONDS, target = src)) + if (do_after(ninja, 1 SECONDS, target = src, hidden = TRUE)) spark_system.start() playsound(loc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) cell.use(drain) @@ -68,7 +68,7 @@ if(hacking_module.mod.get_charge() + drain > hacking_module.mod.get_max_charge()) drain = hacking_module.mod.get_max_charge() - hacking_module.mod.get_charge() maxcapacity = TRUE - if (do_after(ninja, 1 SECONDS, target = src)) + if (do_after(ninja, 1 SECONDS, target = src, hidden = TRUE)) spark_system.start() playsound(loc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) charge -= drain @@ -88,7 +88,7 @@ /obj/item/stock_parts/cell/proc/ninjadrain_charge(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module) var/drain_total = 0 - if(charge && !do_after(ninja, 3 SECONDS, target = src)) + if(charge && !do_after(ninja, 3 SECONDS, target = src, hidden = TRUE)) drain_total = charge if(hacking_module.mod.get_charge() + charge > hacking_module.mod.get_max_charge()) drain_total = hacking_module.mod.get_max_charge() - hacking_module.mod.get_charge() @@ -112,7 +112,7 @@ return COMPONENT_CANCEL_ATTACK_CHAIN /obj/machinery/rnd/server/master/ninjadrain_charge(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module) - if(!do_after(ninja, 30 SECONDS, target = src)) + if(!do_after(ninja, 30 SECONDS, target = src, hidden = TRUE)) return overload_source_code_hdd() to_chat(ninja, span_notice("Sabotage complete. Storage device overloaded.")) @@ -131,7 +131,7 @@ return COMPONENT_CANCEL_ATTACK_CHAIN /obj/machinery/rnd/server/proc/ninjadrain_charge(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module) - if(!do_after(ninja, 30 SECONDS, target = src)) + if(!do_after(ninja, 30 SECONDS, target = src, hidden = TRUE)) return stored_research.modify_points_all(0) to_chat(ninja, span_notice("Sabotage complete. Research notes corrupted.")) @@ -154,7 +154,7 @@ return COMPONENT_CANCEL_ATTACK_CHAIN /obj/machinery/computer/records/security/proc/ninjadrain_charge(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module) - if(!do_after(ninja, 20 SECONDS, src, extra_checks = CALLBACK(src, PROC_REF(can_hack), ninja))) + if(!do_after(ninja, 20 SECONDS, src, extra_checks = CALLBACK(src, PROC_REF(can_hack), ninja), hidden = TRUE)) return for(var/datum/record/crew/target in GLOB.manifest.general) target.wanted_status = WANTED_ARREST @@ -230,7 +230,7 @@ while(!maxcapacity && src) drain = (round((rand(hacking_module.mindrain, hacking_module.maxdrain))/2)) var/drained = 0 - if(wire_powernet && do_after(ninja, 1 SECONDS, target = src)) + if(wire_powernet && do_after(ninja, 1 SECONDS, target = src, hidden = TRUE)) drained = min(drain, delayed_surplus()) add_delayedload(drained) if(drained < drain)//if no power on net, drain apcs @@ -270,7 +270,7 @@ if(hacking_module.mod.get_charge() + drain > hacking_module.mod.get_max_charge()) drain = hacking_module.mod.get_max_charge() - hacking_module.mod.get_charge() maxcapacity = TRUE - if (do_after(ninja, 1 SECONDS, target = src)) + if (do_after(ninja, 1 SECONDS, target = src, hidden = TRUE)) spark_system.start() playsound(loc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) cell.use(drain) @@ -290,7 +290,7 @@ return COMPONENT_CANCEL_ATTACK_CHAIN /mob/living/silicon/robot/proc/ninjadrain_charge(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module) - if(!do_after(ninja, 6 SECONDS, target = src)) + if(!do_after(ninja, 6 SECONDS, target = src, hidden = TRUE)) return spark_system.start() playsound(loc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) @@ -342,7 +342,7 @@ //BOTS// /mob/living/simple_animal/bot/ninjadrain_act(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module) to_chat(src, span_boldwarning("Your circutry suddenly begins heating up!")) - if(!do_after(ninja, 1.5 SECONDS, target = src)) + if(!do_after(ninja, 1.5 SECONDS, target = src, hidden = TRUE)) return COMPONENT_CANCEL_ATTACK_CHAIN if(!hacking_module.mod.subtract_charge(DEFAULT_CHARGE_DRAIN * 7)) @@ -368,7 +368,7 @@ balloon_alert(ninja, "no energy!") return COMPONENT_CANCEL_ATTACK_CHAIN - if(!do_after(ninja, 1.5 SECONDS, target = src)) + if(!do_after(ninja, 1.5 SECONDS, target = src, hidden = TRUE)) return COMPONENT_CANCEL_ATTACK_CHAIN hacking_module.mod.add_charge(cell.charge) @@ -385,7 +385,7 @@ balloon_alert(ninja, "already hacked!") return COMPONENT_CANCEL_ATTACK_CHAIN - if(!do_after(ninja, 2 SECONDS, target = src)) + if(!do_after(ninja, 2 SECONDS, target = src, hidden = TRUE)) return COMPONENT_CANCEL_ATTACK_CHAIN if(!hacking_module.mod.subtract_charge(DEFAULT_CHARGE_DRAIN * 5)) @@ -403,7 +403,7 @@ return COMPONENT_CANCEL_ATTACK_CHAIN AI_notify_hack() - if(!do_after(ninja, 30 SECONDS, target = src)) + if(!do_after(ninja, 30 SECONDS, target = src, hidden = TRUE)) return COMPONENT_CANCEL_ATTACK_CHAIN do_sparks(3, cardinal_only = FALSE, source = src) @@ -417,7 +417,7 @@ balloon_alert(ninja, "already hacked!") return COMPONENT_CANCEL_ATTACK_CHAIN - if(!do_after(ninja, 2 SECONDS, target = src)) + if(!do_after(ninja, 2 SECONDS, target = src, hidden = TRUE)) return COMPONENT_CANCEL_ATTACK_CHAIN do_sparks(3, cardinal_only = FALSE, source = src) @@ -438,7 +438,7 @@ AI_notify_hack() - if(!do_after(ninja, 20 SECONDS, target = src)) //Shorter due to how incredibly easy it is for someone to (even accidentally) interrupt. + if(!do_after(ninja, 20 SECONDS, target = src, hidden = TRUE)) //Shorter due to how incredibly easy it is for someone to (even accidentally) interrupt. return COMPONENT_CANCEL_ATTACK_CHAIN force_event(/datum/round_event_control/tram_malfunction, "ninja interference") diff --git a/code/modules/antagonists/nukeop/equipment/borgchameleon.dm b/code/modules/antagonists/nukeop/equipment/borgchameleon.dm index 68e62a1044cfe..a2a072f02e28f 100644 --- a/code/modules/antagonists/nukeop/equipment/borgchameleon.dm +++ b/code/modules/antagonists/nukeop/equipment/borgchameleon.dm @@ -66,7 +66,7 @@ to_chat(user, span_notice("You activate \the [src].")) playsound(src, 'sound/effects/seedling_chargeup.ogg', 100, TRUE, -6) apply_wibbly_filters(user) - if (do_after(user, 5 SECONDS, target=user) && user.cell.use(ACTIVATION_COST)) + if (do_after(user, 5 SECONDS, target = user, hidden = TRUE) && user.cell.use(ACTIVATION_COST)) playsound(src, 'sound/effects/bamf.ogg', 100, TRUE, -6) to_chat(user, span_notice("You are now disguised as the Nanotrasen engineering borg \"[friendlyName]\".")) activate(user) diff --git a/code/modules/antagonists/nukeop/equipment/nuclear_bomb/_nuclear_bomb.dm b/code/modules/antagonists/nukeop/equipment/nuclear_bomb/_nuclear_bomb.dm index 6082567129c34..8d2e746f0a220 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclear_bomb/_nuclear_bomb.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclear_bomb/_nuclear_bomb.dm @@ -124,7 +124,7 @@ GLOBAL_VAR(station_nuke_source) if(istype(weapon, /obj/item/nuke_core_container)) var/obj/item/nuke_core_container/core_box = weapon to_chat(user, span_notice("You start loading the plutonium core into [core_box]...")) - if(do_after(user, 5 SECONDS, target=src)) + if(do_after(user, 5 SECONDS, target = src, hidden = TRUE)) if(core_box.load(core, user)) to_chat(user, span_notice("You load the plutonium core into [core_box].")) deconstruction_state = NUKESTATE_CORE_REMOVED diff --git a/code/modules/antagonists/spy/spy_uplink.dm b/code/modules/antagonists/spy/spy_uplink.dm index 2a9d9b9b14e9b..88e091310ca0b 100644 --- a/code/modules/antagonists/spy/spy_uplink.dm +++ b/code/modules/antagonists/spy/spy_uplink.dm @@ -136,7 +136,7 @@ span_notice("You start scanning [stealing], preparing it for extraction."), ) - if(!do_after(spy, bounty.theft_time, stealing, interaction_key = REF(src))) + if(!do_after(spy, bounty.theft_time, stealing, interaction_key = REF(src), hidden = TRUE)) return FALSE if(bounty.claimed) to_chat(spy, span_warning("Your uplinks blinks red: The bounty for [stealing] has been claimed by another spy!")) diff --git a/code/modules/antagonists/traitor/objectives/infect.dm b/code/modules/antagonists/traitor/objectives/infect.dm index 5f761a273fce5..459e8f54a0d70 100644 --- a/code/modules/antagonists/traitor/objectives/infect.dm +++ b/code/modules/antagonists/traitor/objectives/infect.dm @@ -166,7 +166,7 @@ to_chat(affected_mob, span_warning("You feel someone try to inject you with something.")) balloon_alert(user, "injecting...") log_combat(user, affected_mob, "attempted to inject", src) - if(!do_after(user, 1.5 SECONDS)) + if(!do_after(user, 1.5 SECONDS, hidden = TRUE)) balloon_alert(user, "interrupted!") return var/datum/disease/chronic_illness/hms = new /datum/disease/chronic_illness() diff --git a/code/modules/antagonists/traitor/objectives/locate_weakpoint.dm b/code/modules/antagonists/traitor/objectives/locate_weakpoint.dm index b3e211d28671f..1976fd38fc8ae 100644 --- a/code/modules/antagonists/traitor/objectives/locate_weakpoint.dm +++ b/code/modules/antagonists/traitor/objectives/locate_weakpoint.dm @@ -192,7 +192,7 @@ for(var/mob/living/silicon/ai/ai_player in GLOB.player_list) to_chat(ai_player, alertstr) - if(!do_after(user, 30 SECONDS, src, IGNORE_USER_LOC_CHANGE | IGNORE_TARGET_LOC_CHANGE | IGNORE_HELD_ITEM | IGNORE_INCAPACITATED | IGNORE_SLOWDOWNS, extra_checks = CALLBACK(src, PROC_REF(scan_checks), user, user_area, objective))) + if(!do_after(user, 30 SECONDS, src, IGNORE_USER_LOC_CHANGE | IGNORE_TARGET_LOC_CHANGE | IGNORE_HELD_ITEM | IGNORE_INCAPACITATED | IGNORE_SLOWDOWNS, extra_checks = CALLBACK(src, PROC_REF(scan_checks), user, user_area, objective), hidden = TRUE)) playsound(user, 'sound/machines/buzz-sigh.ogg', 30, TRUE) return diff --git a/code/modules/antagonists/traitor/objectives/sabotage_machinery.dm b/code/modules/antagonists/traitor/objectives/sabotage_machinery.dm index 48a295989816e..9723d2b653e02 100644 --- a/code/modules/antagonists/traitor/objectives/sabotage_machinery.dm +++ b/code/modules/antagonists/traitor/objectives/sabotage_machinery.dm @@ -165,7 +165,7 @@ GLOBAL_DATUM_INIT(objective_machine_handler, /datum/objective_target_machine_han if (. || !istype(target, target_machine_path)) return balloon_alert(user, "planting device...") - if(!do_after(user, delay = deploy_time, target = src, interaction_key = DOAFTER_SOURCE_PLANTING_DEVICE)) + if(!do_after(user, delay = deploy_time, target = src, interaction_key = DOAFTER_SOURCE_PLANTING_DEVICE, hidden = TRUE)) return TRUE target.AddComponent(\ /datum/component/interaction_booby_trap,\ diff --git a/code/modules/antagonists/traitor/objectives/steal.dm b/code/modules/antagonists/traitor/objectives/steal.dm index 61d4796d66fb1..22d8ed7d39c7b 100644 --- a/code/modules/antagonists/traitor/objectives/steal.dm +++ b/code/modules/antagonists/traitor/objectives/steal.dm @@ -285,7 +285,7 @@ GLOBAL_DATUM_INIT(steal_item_handler, /datum/objective_item_handler, new()) if(result & COMPONENT_FORCE_FAIL_PLACEMENT || !istype(target, target_object_type)) balloon_alert(user, "you can't attach this onto here!") return - if(!do_after(user, deploy_time, src)) + if(!do_after(user, deploy_time, src, hidden = TRUE)) return if(planted_on) return diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm index beded509497c2..4d35875f1d742 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm @@ -429,7 +429,7 @@ user.visible_message(span_notice("You see [user] kicking against the glass of [src]!"), \ span_notice("You struggle inside [src], kicking the release with your foot... (this will take about [DisplayTimeText(CRYO_BREAKOUT_TIME)].)"), \ span_hear("You hear a thump from [src].")) - if(do_after(user, CRYO_BREAKOUT_TIME, target = src)) + if(do_after(user, CRYO_BREAKOUT_TIME, target = src, hidden = TRUE)) if(!user || user.stat != CONSCIOUS || user.loc != src ) return user.visible_message(span_warning("[user] successfully broke out of [src]!"), \ diff --git a/code/modules/clothing/chameleon/chameleon_scanner.dm b/code/modules/clothing/chameleon/chameleon_scanner.dm index 343ceb5c001cb..5023997cefebf 100644 --- a/code/modules/clothing/chameleon/chameleon_scanner.dm +++ b/code/modules/clothing/chameleon/chameleon_scanner.dm @@ -89,7 +89,7 @@ balloon_alert(scanner, "too far away!") return // Very short scan timer, keep you on your toes - if(!do_after(scanner, 0.5 SECONDS, scanned)) + if(!do_after(scanner, 0.5 SECONDS, scanned, hidden = TRUE)) return var/list/all_scanned_items = list() diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm index fbd56846ecbaf..111b35cb7f7bf 100644 --- a/code/modules/mob/living/carbon/human/species_types/vampire.dm +++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm @@ -186,7 +186,7 @@ victim.show_message(span_warning("[H] tries to bite you, but recoils in disgust!")) to_chat(H, span_warning("[victim] reeks of garlic! you can't bring yourself to drain such tainted blood.")) return - if(!do_after(H, 3 SECONDS, target = victim)) + if(!do_after(H, 3 SECONDS, target = victim, hidden = TRUE)) return var/blood_volume_difference = BLOOD_VOLUME_MAXIMUM - H.blood_volume //How much capacity we have left to absorb blood var/drained_blood = min(victim.blood_volume, VAMP_DRAIN_AMOUNT, blood_volume_difference) diff --git a/icons/effects/progressbar.dmi b/icons/effects/progressbar.dmi index f055a07ba1492a36912ed6b9fdbf1b8e278e4864..3eed14db704a76ab77d9ea02c39e290c85e428c1 100644 GIT binary patch delta 1184 zcmY+=eNd7I90zb7xa6FvyQY)0!@SMZUVPuQ(xD0SH8pYBsl`)G!$xL`@Ay1enYA@d zV@*?}^fGNJz0fg_22@HXQ_)^M8Pbc2q`V|4;v+EI&fD$x*YCc6eD3@E&11)HFMJ7X zuk-YU?>~~&vpU?}HoxoJYn?uyc|zQZLZJY9N+KB*F*TaKvSZ3p_tA-21&8x<^5{9o zb5W?0=4&th{PCf`lg+C_gHt3wkQZB)@%wtG6IZ#(Z-S3uj#l#qUdb~GJ;^u-y0hJ@ zIa5gTjW_iuG`0B!qd&R3*eEHJ>6dHw5n+)KFYpK2*)~$j+B?vxl=Y?;+Fb`blZ)dtXN zgf-x1Z?bJeoHP~PUe747Mpw*h7(bUbnMZn4a%-DZvIz(9YFP={V&8{CVTiHB$kdW% zjY3n?#c?Cq`q98^^jYF>(>V*pJ6MzCM$UFIG8BVzKfoGR}QSa^q-+gf2GEk zdg1tsYLoUi#B&;!0PLW-9%SdiQ>`Y6C2{l$0s)Yn&{6;GH^s0YEjd^@s#??8usD zLhKK!ZDCb2Q>)B>y}I-;B;M0OdA{&`kXEe24yy!jOez-%!#L(ZFzUS8U}F$sMt~0{ zVTon3DnOYu?l`*i33VAiX=Yw4SOuAy4#mJTnOv)NU4$xMF3i(-+}vz|+qa(Xgv1x|9H_H~edf4|Ts};OE>FLK zN2BREX$Fn+y3mT7SKc}S1ii>PaHimCnm#XgX{78B|y{pR-{O_ly0TTLPTQPt1djBr`&JFoEus z+mBh}Nyu`5LLA`QlMh9;_~xrk+`H%}+`Q|}<}cEQEO^!21rETWsQ`*zr9C8E~(rtN>tUH$}?(|{#a^0n8eU_sOT%JnH&uzbA%e*=GC2joh=_WB$wXqsQS zJ_idHPr&I04E~Nj{TndASGaEu0000005Ff<%}oD%?Cx%a^8q*8)nk6Opsn4#eSHcR zw9YSIe^>v0t6x9nR}0$u{oB{)U_tBr^7Wp8-tS=Ve1xxX-y8q{0001B9=)5H{`uJ5 z-8Y;M*c?^b)l`4ZYwheN*x-78D&}|2-<0wcY;abOZ;vYddM@X+etsKla6La4^E>Bn zOL-19SUdrz8!-4g>U_Yna{vGU004k_^loPQ=VNzw1N{GhO;Eo^?Q1IJchBF%c?vdY znZG*;+u^(W_iZ81K>`0rzyEcEaDI;S+Wh@Vd_G|ICt!c@chvcSXXgL_00000^XT2o z^v}oc?!MuCKnm*D2iwz~{tMdV~KLLZkqs|9BI|l#&0001(NAG5)e?E41H^A=; zT(+-=O8c5tw!0r2+?=1*&OfyMzQASw{#NPV^U8kzV}qOX^V<1uZND$@+n<2J-%;lS zo}B{#00000%wzWE<@w#);G*_5HMOt*0?SXj0oN)0dv5CA{|A254Ve82nEe|t^Iw5? XZsBHuRElq(00000NkvXXu0mjf90JxT diff --git a/tgstation.dme b/tgstation.dme index 3a67046d8ac95..105655cbaa38e 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -764,6 +764,7 @@ #include "code\datums\candidate_poll.dm" #include "code\datums\chat_payload.dm" #include "code\datums\chatmessage.dm" +#include "code\datums\cogbar.dm" #include "code\datums\dash_weapon.dm" #include "code\datums\datum.dm" #include "code\datums\datumvars.dm" From e61955b24975c1de6b77820c887e088f12be0e50 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 5 Apr 2024 15:02:31 +1300 Subject: [PATCH 032/938] Automatic changelog for PR #82416 [ci skip] --- html/changelogs/AutoChangeLog-pr-82416.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82416.yml diff --git a/html/changelogs/AutoChangeLog-pr-82416.yml b/html/changelogs/AutoChangeLog-pr-82416.yml new file mode 100644 index 0000000000000..7176ad6d03c7f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82416.yml @@ -0,0 +1,4 @@ +author: "jlsnow301, infraredbaron" +delete-after: True +changes: + - rscadd: "Added a new UI element over players that are interacting, building, etc." \ No newline at end of file From 980ef98e0428b78bdc7661cce6ae87202558aa29 Mon Sep 17 00:00:00 2001 From: Rhials <28870487+Rhials@users.noreply.github.com> Date: Thu, 4 Apr 2024 23:19:56 -0400 Subject: [PATCH 033/938] New operative reinforcement option: Intelligence Overwatch Agent (#82307) ## About The Pull Request Introducing a new Nuclear Operative reinforcement option: The Overwatch Intelligence Agent. Equipped with multi-hudglasses, they have an advanced camera console, station alerts, and bodycams of every operative! If something can be known, they will know about it. They can also remotely pilot your ship. Finally, everyone can ride in the Steel Rain without getting stuck on the station! This role spawns in the formerly unused outpost just north of the nukie base. With a few shelves of supplies and some tools in the back room, they can set up their workplace however they like. This also gives them something to work on while they wait for the operatives to gear up. ![image](https://github.com/tgstation/tgstation/assets/28870487/4a39ec5f-0578-4825-8c6b-cc4db47bf726) As you can see, it's rather cramped and the lights are quite dim in the backroom. Set it up however you like, this is how I did mine: ![image](https://github.com/tgstation/tgstation/assets/28870487/f80b65fa-dcd1-425e-a6ce-c0ed94a8a3a5) Total price? 12 TC per agent. It might get a bit cramped, but you could buy a second to make sure the first guy doesn't get lonely! This turned into a 30-commit ugly because the bodycams were originally meant to be accomplished via a refactoring of the spyglass kit. Big mistake that made me shelve the project -- until Melbert's simple bodycam component conveniently did exactly what I needed in a much simpler way. ## Why It's Good For The Game Having a "guy in the chair" for your kickass murder operator squad enables more brainy strategizing, and is thematically sound. Also, nukies have the opportunity to bring in another player to participate in the fun! ## Changelog :cl: Rhials add: Nuclear Operatives now purchase an Intelligence Agent, who can watch cameras and bodycams, move the shuttle, and provide radio support. Only 12 Telecrystals! /:cl: --- _maps/templates/lazy_templates/nukie_base.dmm | 229 +++++++++++++++--- code/__DEFINES/cameranets.dm | 1 + .../dcs/signals/signals_operatives.dm | 2 + code/__DEFINES/role_preferences.dm | 1 + code/_globalvars/lists/mapping.dm | 1 + code/game/objects/effects/landmarks.dm | 10 + .../antagonists/_common/antag_spawner.dm | 33 ++- .../antagonists/nukeop/datums/operative.dm | 1 - .../nukeop/datums/operative_support.dm | 54 +++++ .../nukeop/datums/operative_team.dm | 4 + .../nukeop/equipment/overwatch_tools.dm | 46 ++++ code/modules/antagonists/nukeop/outfits.dm | 21 ++ .../carbon/human/species_types/plasmamen.dm | 1 + code/modules/power/cable.dm | 3 + code/modules/shuttle/syndicate.dm | 1 + code/modules/uplink/uplink_items/nukeops.dm | 8 + tgstation.dme | 3 + 17 files changed, 379 insertions(+), 40 deletions(-) create mode 100644 code/__DEFINES/dcs/signals/signals_operatives.dm create mode 100644 code/modules/antagonists/nukeop/datums/operative_support.dm create mode 100644 code/modules/antagonists/nukeop/equipment/overwatch_tools.dm diff --git a/_maps/templates/lazy_templates/nukie_base.dmm b/_maps/templates/lazy_templates/nukie_base.dmm index 63c0fc2b1683b..059d27000d0e5 100644 --- a/_maps/templates/lazy_templates/nukie_base.dmm +++ b/_maps/templates/lazy_templates/nukie_base.dmm @@ -152,6 +152,10 @@ }, /turf/open/floor/plating, /area/centcom/syndicate_mothership/control) +"bZ" = ( +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "cl" = ( /turf/open/lava/plasma/ice_moon, /area/centcom/syndicate_mothership/control) @@ -349,6 +353,15 @@ }, /turf/open/floor/iron/dark/textured_large, /area/centcom/syndicate_mothership/control) +"dZ" = ( +/obj/machinery/light/small/directional/north, +/obj/effect/decal/cleanable/cobweb/cobweb2, +/obj/structure/closet/crate/bin, +/obj/effect/decal/cleanable/fuel_pool, +/obj/item/binoculars, +/obj/item/stack/sheet/animalhide/carp/five, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "ec" = ( /obj/structure/sign/poster/contraband/cc64k_ad, /turf/closed/indestructible/syndicate, @@ -485,9 +498,27 @@ /turf/open/floor/iron/freezer, /area/centcom/syndicate_mothership/control) "fw" = ( -/obj/item/kirbyplants/random, +/obj/structure/frame/computer, +/obj/effect/decal/cleanable/cobweb, +/obj/structure/sign/poster/contraband/syndiemoth/directional/north, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership) +"fx" = ( +/obj/machinery/light/small/dim/directional/west, +/obj/structure/rack, +/obj/effect/turf_decal/box/white, +/obj/item/stack/cable_coil/thirty{ + pixel_x = 4; + pixel_y = -2 + }, +/obj/item/circuitboard/computer/stationalert{ + pixel_y = 1; + pixel_x = 3 + }, +/obj/item/stack/cable_coil/thirty, +/obj/item/circuitboard/computer/advanced_camera, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "fy" = ( /obj/structure/lattice/catwalk, /obj/effect/turf_decal/stripes/line{ @@ -536,6 +567,8 @@ /obj/structure/frame/computer{ dir = 1 }, +/obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/computer/security/telescreen/entertainment/directional/south, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership) "gf" = ( @@ -740,6 +773,20 @@ /obj/item/melee/powerfist, /turf/open/floor/mineral/plastitanium/red, /area/centcom/syndicate_mothership/expansion_bombthreat) +"id" = ( +/obj/structure/extinguisher_cabinet/directional/south, +/obj/item/storage/fancy/donut_box, +/obj/structure/rack, +/obj/item/food/syndicake{ + pixel_x = -1; + pixel_y = -1 + }, +/obj/item/food/syndicake{ + pixel_x = 1; + pixel_y = 1 + }, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "ig" = ( /obj/effect/turf_decal/siding/wideplating{ dir = 1 @@ -1033,6 +1080,10 @@ /obj/structure/sign/poster/contraband/power/directional/north, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership/expansion_chemicalwarfare) +"lx" = ( +/obj/machinery/light/small/dim/directional/east, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "lA" = ( /obj/machinery/door/window/survival_pod/left/directional/west{ name = "Toilet Door" @@ -1281,6 +1332,22 @@ dir = 8 }, /area/centcom/syndicate_mothership/control) +"oN" = ( +/obj/structure/rack, +/obj/item/poster/random_contraband{ + pixel_x = 3; + pixel_y = 4 + }, +/obj/item/poster/random_contraband{ + pixel_x = 3; + pixel_y = 8 + }, +/obj/item/poster/random_contraband{ + pixel_x = 1 + }, +/obj/effect/decal/cleanable/cobweb, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "oR" = ( /obj/structure/table/wood, /obj/item/storage/box/donkpockets, @@ -1367,6 +1434,7 @@ /obj/structure/chair/greyscale{ dir = 4 }, +/obj/effect/landmark/start/nukeop_overwatch, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership) "pU" = ( @@ -1641,6 +1709,7 @@ /area/centcom/syndicate_mothership/control) "sv" = ( /obj/machinery/light/small/directional/north, +/obj/effect/decal/cleanable/dirt/dust, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership) "sE" = ( @@ -1731,6 +1800,17 @@ /obj/machinery/portable_atmospherics/scrubber, /turf/open/floor/mineral/plastitanium/red, /area/centcom/syndicate_mothership/expansion_bombthreat) +"tB" = ( +/obj/effect/turf_decal/siding/wideplating{ + dir = 1 + }, +/obj/effect/turf_decal/siding/wideplating, +/obj/machinery/door/airlock/hatch{ + name = "Workout Room" + }, +/obj/effect/mapping_helpers/airlock/access/all/syndicate/general, +/turf/open/floor/mineral/plastitanium, +/area/centcom/syndicate_mothership) "tJ" = ( /obj/effect/light_emitter{ set_cap = 1; @@ -2046,6 +2126,10 @@ dir = 8 }, /area/centcom/syndicate_mothership/control) +"yA" = ( +/obj/effect/decal/cleanable/insectguts, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "yB" = ( /obj/machinery/light/small/directional/north, /turf/open/misc/asteroid/snow/icemoon, @@ -2100,12 +2184,12 @@ /area/centcom/syndicate_mothership/control) "zy" = ( /obj/structure/table/reinforced/plasmarglass, -/obj/item/pen{ - pixel_x = 6; - pixel_y = 5 +/obj/item/flashlight/lamp/green{ + pixel_y = 9; + pixel_x = 5 }, -/obj/item/folder/red{ - pixel_x = -5 +/obj/item/circuitboard/computer/overwatch{ + pixel_x = -2 }, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership) @@ -3037,6 +3121,10 @@ }, /turf/open/floor/mineral/plastitanium/red, /area/centcom/syndicate_mothership/expansion_bioterrorism) +"Jx" = ( +/obj/effect/decal/cleanable/plastic, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "JJ" = ( /obj/effect/turf_decal/siding/thinplating_new/dark{ dir = 5 @@ -3318,6 +3406,19 @@ /obj/structure/noticeboard/directional/east, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership/expansion_bioterrorism) +"MA" = ( +/obj/item/stack/sheet/iron/fifty{ + pixel_x = -3; + pixel_y = 3 + }, +/obj/structure/rack, +/obj/item/stack/sheet/glass/fifty{ + pixel_y = 3; + pixel_x = 5 + }, +/obj/item/storage/toolbox/mechanical, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "MD" = ( /obj/machinery/door/airlock/maintenance/external{ name = "Bunk Room 1" @@ -3483,6 +3584,14 @@ pixel_x = -2; pixel_y = 6 }, +/obj/item/paper/fluff/overwatch{ + pixel_y = 8; + pixel_x = -2 + }, +/obj/item/toy/figure/syndie{ + pixel_x = 5 + }, +/obj/structure/sign/clock/directional/north, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership) "Ov" = ( @@ -3706,6 +3815,14 @@ /obj/effect/turf_decal/tile/bar/opposingcorners, /turf/open/floor/iron, /area/centcom/syndicate_mothership/control) +"QD" = ( +/obj/item/flashlight{ + pixel_y = 6 + }, +/obj/structure/rack, +/obj/item/flashlight, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "QJ" = ( /obj/effect/turf_decal/stripes/line{ dir = 4 @@ -3728,10 +3845,39 @@ }, /turf/open/misc/asteroid/snow/icemoon, /area/centcom/syndicate_mothership/control) +"QS" = ( +/obj/item/soap/syndie, +/obj/structure/rack, +/obj/item/storage/fancy/cigarettes/cigpack_syndicate{ + pixel_x = 5; + pixel_y = 2 + }, +/obj/effect/spawner/random/entertainment/lighter, +/obj/machinery/light/small/directional/north, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "Rd" = ( /obj/structure/cable, /turf/open/floor/catwalk_floor/iron, /area/centcom/syndicate_mothership/control) +"Rn" = ( +/obj/item/circuitboard/computer/syndicate_shuttle{ + pixel_x = 2; + pixel_y = 3 + }, +/obj/structure/rack, +/obj/item/stack/cable_coil/thirty{ + pixel_x = -2; + pixel_y = -1 + }, +/obj/effect/turf_decal/box/white, +/obj/item/circuitboard/computer/syndicate_shuttle_docker, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) +"Rr" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "Rs" = ( /obj/effect/turf_decal/siding/thinplating_new/dark{ dir = 1 @@ -3830,6 +3976,11 @@ }, /turf/open/floor/mineral/plastitanium/red, /area/centcom/syndicate_mothership/expansion_bombthreat) +"St" = ( +/obj/effect/decal/cleanable/fuel_pool, +/obj/machinery/light_switch/directional/east, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "Su" = ( /obj/structure/chair/stool/bar/directional/west, /obj/effect/turf_decal/siding/thinplating/dark{ @@ -4276,6 +4427,11 @@ /obj/machinery/light/cold/directional/east, /turf/open/floor/catwalk_floor/iron_dark, /area/centcom/syndicate_mothership/control) +"XO" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/fuel_pool, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "XQ" = ( /obj/effect/turf_decal/siding/wideplating/dark, /obj/effect/turf_decal/siding/wideplating/dark{ @@ -4375,6 +4531,14 @@ }, /turf/open/misc/asteroid/snow/icemoon, /area/centcom/syndicate_mothership/control) +"YT" = ( +/obj/structure/rack, +/obj/effect/turf_decal/box/white, +/obj/item/storage/medkit/emergency, +/obj/item/tank/internals/emergency_oxygen/double, +/obj/item/clothing/mask/gas/syndicate, +/turf/open/floor/mineral/plastitanium/red, +/area/centcom/syndicate_mothership) "YX" = ( /obj/structure/railing{ dir = 6 @@ -4491,6 +4655,7 @@ /turf/open/floor/plating/snowed/icemoon, /area/centcom/syndicate_mothership/control) "ZX" = ( +/obj/effect/decal/cleanable/dirt/dust, /turf/open/floor/mineral/plastitanium, /area/centcom/syndicate_mothership) "ZZ" = ( @@ -5254,9 +5419,9 @@ sU sU sU sU -sU -sU -sU +Ye +Ye +Ye Ye Ye Ye @@ -5356,13 +5521,13 @@ sU sU sU sU -sU -sU Ye Ye Kq Kq Kq +Kq +Kq Ye KU KU @@ -5458,12 +5623,12 @@ sU sU sU sU -sU -Ye Ye Kq Kq -Xk +YT +fx +Rn Kq Kq KU @@ -5561,12 +5726,12 @@ sU sU sU Ye -Ye Kq -Kq -Xk -Xk +oN +Jx Xk +Rr +MA Kq Kq uT @@ -5664,12 +5829,12 @@ sU sU Ye Kq -Kq -Xk -Xk -Xk +QS Xk Xk +bZ +Rr +id Kq Kq uT @@ -5766,12 +5931,12 @@ sU sU Ye Kq -Xk -Xk -Xk -Xk -Xk -Xk +QD +Rr +lx +bZ +St +XO Xk Kq Kq @@ -5871,12 +6036,12 @@ Kq Kq Kq Kq -lg +tB Kq +dZ Xk -Xk -Xk -Kq +yA +tO uT ds HW diff --git a/code/__DEFINES/cameranets.dm b/code/__DEFINES/cameranets.dm index 1dea0cd18aec4..15b4493738e2f 100644 --- a/code/__DEFINES/cameranets.dm +++ b/code/__DEFINES/cameranets.dm @@ -26,3 +26,4 @@ #define CAMERANET_NETWORK_BAR "bar" #define CAMERANET_NETWORK_INTERROGATION "interrogation" #define CAMERANET_NETWORK_ABDUCTOR "abductor" +#define OPERATIVE_CAMERA_NET "operative" diff --git a/code/__DEFINES/dcs/signals/signals_operatives.dm b/code/__DEFINES/dcs/signals/signals_operatives.dm new file mode 100644 index 0000000000000..12a3bed466850 --- /dev/null +++ b/code/__DEFINES/dcs/signals/signals_operatives.dm @@ -0,0 +1,2 @@ +/// For when a new teammate is added to a nukie team +#define COMSIG_NUKE_TEAM_ADDITION "nuke_team_addition" diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index 71fa29b6ea31a..ee7e5dfee0d12 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -78,6 +78,7 @@ #define ROLE_WIZARD_APPRENTICE "apprentice" #define ROLE_SYNDICATE_MONKEY "Syndicate Monkey Agent" #define ROLE_CONTRACTOR_SUPPORT "Contractor Support Unit" +#define ROLE_OPERATIVE_OVERWATCH "Operative Overwatch Agent" #define ROLE_SYNDICATE_SABOBORG "Syndicate Sabotage Cyborg" #define ROLE_SYNDICATE_MEDBORG "Syndicate Medical Cyborg" #define ROLE_SYNDICATE_ASSAULTBORG "Syndicate Assault Cyborg" diff --git a/code/_globalvars/lists/mapping.dm b/code/_globalvars/lists/mapping.dm index 8719f45f18fc0..45f59fb447514 100644 --- a/code/_globalvars/lists/mapping.dm +++ b/code/_globalvars/lists/mapping.dm @@ -111,6 +111,7 @@ GLOBAL_LIST_EMPTY(gorilla_start) GLOBAL_LIST_EMPTY(wizardstart) GLOBAL_LIST_EMPTY(nukeop_start) GLOBAL_LIST_EMPTY(nukeop_leader_start) +GLOBAL_LIST_EMPTY(nukeop_overwatch_start) GLOBAL_LIST_EMPTY(newplayer_start) GLOBAL_LIST_EMPTY(prisonwarp) //admin prisoners go to these GLOBAL_LIST_EMPTY(holdingfacility) //captured people go here (ninja energy net) diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm index 5c4964cca058a..a8bbfc529ecd3 100644 --- a/code/game/objects/effects/landmarks.dm +++ b/code/game/objects/effects/landmarks.dm @@ -287,6 +287,16 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark) GLOB.nukeop_leader_start += loc return INITIALIZE_HINT_QDEL +/obj/effect/landmark/start/nukeop_overwatch + name = "nukeop overwatch" + icon = 'icons/effects/landmarks_static.dmi' + icon_state = "snukeop_leader_spawn" + +/obj/effect/landmark/start/nukeop_overwatch/Initialize(mapload) + ..() + GLOB.nukeop_overwatch_start += loc + return INITIALIZE_HINT_QDEL + // Must be immediate because players will // join before SSatom initializes everything. INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player) diff --git a/code/modules/antagonists/_common/antag_spawner.dm b/code/modules/antagonists/_common/antag_spawner.dm index 2719c576a5eca..8be6abe98eae6 100644 --- a/code/modules/antagonists/_common/antag_spawner.dm +++ b/code/modules/antagonists/_common/antag_spawner.dm @@ -103,11 +103,13 @@ /// The applied outfit var/datum/outfit/syndicate/outfit = /datum/outfit/syndicate/reinforcement /// The antag datum applied - var/datum/antagonist/nukeop/reinforcement/antag_datum = /datum/antagonist/nukeop/reinforcement + var/antag_datum = /datum/antagonist/nukeop/reinforcement /// Style used by the droppod var/pod_style = STYLE_SYNDICATE /// Do we use a random subtype of the outfit? var/use_subtypes = TRUE + /// Where do we land our pod? + var/turf/spawn_location /obj/item/antag_spawner/nuke_ops/proc/check_usability(mob/user) if(used) @@ -143,7 +145,6 @@ /obj/item/antag_spawner/nuke_ops/spawn_antag(client/our_client, turf/T, kind, datum/mind/user) var/mob/living/carbon/human/nukie = new() - var/obj/structure/closet/supplypod/pod = setup_pod() our_client.prefs.safe_transfer_prefs_to(nukie, is_antag = TRUE) nukie.ckey = our_client.key var/datum/mind/op_mind = nukie.mind @@ -152,15 +153,33 @@ else nukie.forceMove(locate(1,1,1)) - antag_datum = new() - - antag_datum.nukeop_outfit = use_subtypes ? pick(subtypesof(outfit)) : outfit + var/new_datum = new antag_datum() var/datum/antagonist/nukeop/creator_op = user.has_antag_datum(/datum/antagonist/nukeop, TRUE) - op_mind.add_antag_datum(antag_datum, creator_op ? creator_op.get_team() : null) + op_mind.add_antag_datum(new_datum, creator_op ? creator_op.get_team() : null) op_mind.special_role = special_role_name + + if(outfit) + var/datum/antagonist/nukeop/nukie_datum = op_mind.has_antag_datum(antag_datum) + nukie_datum.nukeop_outfit = use_subtypes ? pick(subtypesof(outfit)) : outfit + + var/obj/structure/closet/supplypod/pod = setup_pod() nukie.forceMove(pod) - new /obj/effect/pod_landingzone(get_turf(src), pod) + new /obj/effect/pod_landingzone(spawn_location ? spawn_location : get_turf(src), pod) + +/obj/item/antag_spawner/nuke_ops/overwatch + name = "overwatch support beacon" + desc = "Assigns an Overwatch Intelligence Agent to your operation. Stationed at their own remote outpost, they can view station cameras, alarms, and even move the Infiltrator shuttle! \ + Also, all members of your operation will recieve body cameras that they can view your progress from." + special_role_name = ROLE_OPERATIVE_OVERWATCH + outfit = /datum/outfit/syndicate/support + use_subtypes = FALSE + antag_datum = /datum/antagonist/nukeop/support + +/obj/item/antag_spawner/nuke_ops/overwatch/Initialize(mapload) + . = ..() + if(length(GLOB.nukeop_overwatch_start)) //Otherwise, it will default to the datum's spawn point anyways + spawn_location = pick(GLOB.nukeop_overwatch_start) //////CLOWN OP /obj/item/antag_spawner/nuke_ops/clown diff --git a/code/modules/antagonists/nukeop/datums/operative.dm b/code/modules/antagonists/nukeop/datums/operative.dm index 516108c572513..3b4c9fa4da7ce 100644 --- a/code/modules/antagonists/nukeop/datums/operative.dm +++ b/code/modules/antagonists/nukeop/datums/operative.dm @@ -46,7 +46,6 @@ var/datum/component/uplink/uplink = owner.find_syndicate_uplink() if (uplink) uplink.uplink_handler.add_telecrystals(extra_tc) - var/datum/component/uplink/uplink = owner.find_syndicate_uplink() if(uplink) var/datum/team/nuclear/nuke_team = get_team() diff --git a/code/modules/antagonists/nukeop/datums/operative_support.dm b/code/modules/antagonists/nukeop/datums/operative_support.dm new file mode 100644 index 0000000000000..c9ea12b63c5d2 --- /dev/null +++ b/code/modules/antagonists/nukeop/datums/operative_support.dm @@ -0,0 +1,54 @@ +/datum/antagonist/nukeop/support + name = ROLE_OPERATIVE_OVERWATCH + show_to_ghosts = TRUE + send_to_spawnpoint = TRUE + nukeop_outfit = /datum/outfit/syndicate/support + +/datum/antagonist/nukeop/support/greet() + owner.current.playsound_local(get_turf(owner.current), 'sound/machines/printer.ogg', 100, 0, use_reverb = FALSE) + to_chat(owner, span_big("You are a [name]! You've been temporarily assigned to provide camera overwatch and manage communications for a nuclear operative team!")) + to_chat(owner, span_red("Use your tools to set up your equipment however you like, but do NOT attempt to leave your outpost.")) + owner.announce_objectives() + +/datum/antagonist/nukeop/support/on_gain() + ..() + for(var/datum/mind/teammate_mind in nuke_team.members) + var/mob/living/our_teammate = teammate_mind.current + our_teammate.AddComponent( \ + /datum/component/simple_bodycam, \ + camera_name = "operative bodycam", \ + c_tag = "[our_teammate.real_name]", \ + network = OPERATIVE_CAMERA_NET, \ + emp_proof = FALSE, \ + ) + our_teammate.playsound_local(get_turf(owner.current), 'sound/weapons/egloves.ogg', 100, 0) + to_chat(our_teammate, span_notice("A Syndicate Overwatch Intelligence Agent has been assigned to your team. Smile, you're on camera!")) + + RegisterSignal(nuke_team, COMSIG_NUKE_TEAM_ADDITION, PROC_REF(late_bodycam)) + + owner.current.grant_language(/datum/language/codespeak) + +/datum/antagonist/nukeop/support/get_spawnpoint() + return pick(GLOB.nukeop_overwatch_start) + +/datum/antagonist/nukeop/support/forge_objectives() + var/datum/objective/overwatch/objective = new + objective.owner = owner + objectives += objective + +/datum/antagonist/nukeop/support/proc/late_bodycam(datum/source, mob/living/new_teammate) + SIGNAL_HANDLER + new_teammate.AddComponent( \ + /datum/component/simple_bodycam, \ + camera_name = "operative bodycam", \ + c_tag = "[new_teammate.real_name]", \ + network = OPERATIVE_CAMERA_NET, \ + emp_proof = FALSE, \ + ) + to_chat(new_teammate, span_notice("You have been equipped with a bodycam, viewable by your Overwatch Intelligence Agent. Make sure to show them a good performance!")) + +/datum/objective/overwatch + explanation_text = "Provide intelligence support and overwatch to your operative team!" + +/datum/objective/overwatch/check_completion() + return GLOB.station_was_nuked diff --git a/code/modules/antagonists/nukeop/datums/operative_team.dm b/code/modules/antagonists/nukeop/datums/operative_team.dm index 9bec3b0fcf0e1..3345f3cf4d25f 100644 --- a/code/modules/antagonists/nukeop/datums/operative_team.dm +++ b/code/modules/antagonists/nukeop/datums/operative_team.dm @@ -313,5 +313,9 @@ return TRUE return FALSE +/datum/team/nuclear/add_member(datum/mind/new_member) + ..() + SEND_SIGNAL(src, COMSIG_NUKE_TEAM_ADDITION, new_member.current) + #undef SPAWN_AT_BASE #undef SPAWN_AT_INFILTRATOR diff --git a/code/modules/antagonists/nukeop/equipment/overwatch_tools.dm b/code/modules/antagonists/nukeop/equipment/overwatch_tools.dm new file mode 100644 index 0000000000000..852c0d7d32fbd --- /dev/null +++ b/code/modules/antagonists/nukeop/equipment/overwatch_tools.dm @@ -0,0 +1,46 @@ +///One of the special items that spawns in the overwatch agent's room. +/obj/item/paper/fluff/overwatch + name = "OVERWATCH NOTES #1" + color = COLOR_RED + desc = "A note from Syndicate leadership regarding your new job. You should read this!" + default_raw_text = @{" +Congratulations! You have been picked to be the Sole Survivor of an anti-Nanotrasen suicide mission! +We're kidding of course, these types of missions tend to have abnormally high survival rates. I guess that says a lot about who your team will be going up against. +
+You've been assigned to provide intelligence support to the ground-pounders carrying out the operation. +Each operative has been equipped with a bodycam that can be accessed via your Overwatch Camera Console. +Additionally, you have been given the boards to access station alerts, cameras, and remotely control the infiltrator shuttle. +
+Feel free to set up your workplace however you like. We've provided the tools and boards in your backroom. +
+Happy hunting! + "} + +/obj/machinery/computer/security/overwatch + name = "overwatch camera console" + desc = "Allows you to view members of your operative team via their bodycam feeds. We call them 'bodycams', but they're actually a swarm of tiny, near-imperceptible camera drones that follow each target. \ + It is believed that adversaries either don't notice the drones, or avoid attacking them in hopes that they'll capture footage of their combat prowess against our operatives." + icon_screen = "commsyndie" + icon_keyboard = "syndie_key" + network = list(OPERATIVE_CAMERA_NET) + circuit = /obj/item/circuitboard/computer/overwatch + +/obj/item/circuitboard/computer/overwatch + name = "Overwatch Body Cameras" + build_path = /obj/machinery/computer/security/overwatch + greyscale_colors = CIRCUIT_COLOR_SECURITY + +/obj/item/circuitboard/computer/syndicate_shuttle_docker + name = "Shuttle Controller" + build_path = /obj/machinery/computer/camera_advanced/shuttle_docker/syndicate + greyscale_colors = CIRCUIT_COLOR_SECURITY + +/obj/item/clothing/glasses/overwatch + name = "intelligence glasses" + desc = "A set of incredibly advanced sunglasses, providing you with an array of different sensor scans and visual readouts for pretty much anything you look at. \ + It's kind of overwhelming, actually. Wearing this for a few hours will probably give you a migrane." + icon_state = "sunhudmed" + flags_cover = GLASSESCOVERSEYES + flash_protect = FLASH_PROTECTION_WELDER + clothing_traits = list(TRAIT_REAGENT_SCANNER) + var/list/hudlist = list(DATA_HUD_MEDICAL_ADVANCED, DATA_HUD_DIAGNOSTIC_ADVANCED, DATA_HUD_SECURITY_ADVANCED) diff --git a/code/modules/antagonists/nukeop/outfits.dm b/code/modules/antagonists/nukeop/outfits.dm index 80360f5636098..eb251bcc363a2 100644 --- a/code/modules/antagonists/nukeop/outfits.dm +++ b/code/modules/antagonists/nukeop/outfits.dm @@ -114,6 +114,17 @@ r_hand = /obj/item/tank/internals/plasmaman/belt/full tc = 0 +/datum/outfit/syndicate/support/plasmaman + name = "Nuclear Operative Overwatch Agent (Plasmaman)" + back = /obj/item/storage/backpack/satchel + head = /obj/item/clothing/head/helmet/space/plasmaman/syndie + uniform = /obj/item/clothing/under/plasmaman/syndicate + glasses = /obj/item/clothing/glasses/overwatch + suit = /obj/item/clothing/suit/jacket/letterman_syndie + r_hand = /obj/item/tank/internals/plasmaman/belt/full + command_radio = TRUE + tc = 0 + /datum/outfit/syndicate/reinforcement/gorlex name = "Syndicate Operative - Gorlex Reinforcement" suit = /obj/item/clothing/suit/armor/vest/alt @@ -191,3 +202,13 @@ var/obj/item/shield/energy/shield = locate() in H.held_items shield.icon_state = "[shield.base_icon_state]1" H.update_held_items() + +/datum/outfit/syndicate/support + name = "Nuclear Operative Overwatch Agent" + back = /obj/item/storage/backpack/satchel + uniform = /obj/item/clothing/under/syndicate/tacticool + glasses = /obj/item/clothing/glasses/overwatch + suit = /obj/item/clothing/suit/jacket/letterman_syndie + shoes = /obj/item/clothing/shoes/sandal + command_radio = TRUE + tc = 0 diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm index c130b7d3ac729..2d053813e5b83 100644 --- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm +++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm @@ -61,6 +61,7 @@ /datum/outfit/syndicate/reinforcement/interdyne = /datum/outfit/syndicate/reinforcement/plasmaman, /datum/outfit/syndicate/reinforcement/mi13 = /datum/outfit/syndicate/reinforcement/plasmaman, /datum/outfit/syndicate/reinforcement/waffle = /datum/outfit/syndicate/reinforcement/plasmaman, + /datum/outfit/syndicate/support = /datum/outfit/syndicate/support/plasmaman, ) /// If the bones themselves are burning clothes won't help you much diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index 7810f2efed826..2e95b12914650 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -629,6 +629,9 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri /obj/item/stack/cable_coil/five amount = 5 +/obj/item/stack/cable_coil/thirty + amount = 30 + /obj/item/stack/cable_coil/cut amount = null icon_state = "coil2" diff --git a/code/modules/shuttle/syndicate.dm b/code/modules/shuttle/syndicate.dm index f08446b650da3..402a87bf6d43d 100644 --- a/code/modules/shuttle/syndicate.dm +++ b/code/modules/shuttle/syndicate.dm @@ -64,5 +64,6 @@ y_offset = -1 whitelist_turfs = list(/turf/open/space, /turf/open/floor/plating, /turf/open/lava, /turf/closed/mineral, /turf/open/openspace, /turf/open/misc) see_hidden = TRUE + circuit = /obj/item/circuitboard/computer/syndicate_shuttle_docker #undef SYNDICATE_CHALLENGE_TIMER diff --git a/code/modules/uplink/uplink_items/nukeops.dm b/code/modules/uplink/uplink_items/nukeops.dm index f18cc9a565eb1..c8486f4b5d008 100644 --- a/code/modules/uplink/uplink_items/nukeops.dm +++ b/code/modules/uplink/uplink_items/nukeops.dm @@ -475,6 +475,14 @@ Its chameleon projector lets it disguise itself as a Nanotrasen cyborg, on top it has thermal vision and a pinpointer." item = /obj/item/antag_spawner/nuke_ops/borg_tele/saboteur +/datum/uplink_item/reinforcements/overwatch_agent + name = "Overwatch Intelligence Agent" + desc = "An Overwatch Intelligence Agent is assigned to your operation. They can view your progress and help coordinate using your \ + operative team's body-cams. They can also pilot the shuttle remotely and view the station's camera net. \ + If you're a meathead who's just here to kill people and don't care about strategising or intel, you'll still have someone to bear witness to your murder-spree!" + item = /obj/item/antag_spawner/nuke_ops/overwatch + cost = 12 + // ~~ Disposable Sentry Gun ~~ // Technically not a spawn but it is a kind of reinforcement...I guess. diff --git a/tgstation.dme b/tgstation.dme index 105655cbaa38e..9b3f3bcff0cac 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -337,6 +337,7 @@ #include "code\__DEFINES\dcs\signals\signals_music.dm" #include "code\__DEFINES\dcs\signals\signals_object.dm" #include "code\__DEFINES\dcs\signals\signals_operating_computer.dm" +#include "code\__DEFINES\dcs\signals\signals_operatives.dm" #include "code\__DEFINES\dcs\signals\signals_painting.dm" #include "code\__DEFINES\dcs\signals\signals_proxmonitor.dm" #include "code\__DEFINES\dcs\signals\signals_radiation.dm" @@ -3146,10 +3147,12 @@ #include "code\modules\antagonists\nukeop\datums\operative_leader.dm" #include "code\modules\antagonists\nukeop\datums\operative_lone.dm" #include "code\modules\antagonists\nukeop\datums\operative_reinforcement.dm" +#include "code\modules\antagonists\nukeop\datums\operative_support.dm" #include "code\modules\antagonists\nukeop\datums\operative_team.dm" #include "code\modules\antagonists\nukeop\equipment\borgchameleon.dm" #include "code\modules\antagonists\nukeop\equipment\nuclear_authentication_disk.dm" #include "code\modules\antagonists\nukeop\equipment\nuclear_challenge.dm" +#include "code\modules\antagonists\nukeop\equipment\overwatch_tools.dm" #include "code\modules\antagonists\nukeop\equipment\pinpointer.dm" #include "code\modules\antagonists\nukeop\equipment\nuclear_bomb\_nuclear_bomb.dm" #include "code\modules\antagonists\nukeop\equipment\nuclear_bomb\beer_nuke.dm" From 6e36ed984070d53e16bed4fa43eb0cbe6460deed Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 5 Apr 2024 16:20:15 +1300 Subject: [PATCH 034/938] Automatic changelog for PR #82307 [ci skip] --- html/changelogs/AutoChangeLog-pr-82307.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82307.yml diff --git a/html/changelogs/AutoChangeLog-pr-82307.yml b/html/changelogs/AutoChangeLog-pr-82307.yml new file mode 100644 index 0000000000000..1b5ee32a1d43f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82307.yml @@ -0,0 +1,4 @@ +author: "Rhials" +delete-after: True +changes: + - rscadd: "Nuclear Operatives now purchase an Intelligence Agent, who can watch cameras and bodycams, move the shuttle, and provide radio support. Only 12 Telecrystals!" \ No newline at end of file From 17deef69d98e2350f18ad639fd982f7d78f59f1a Mon Sep 17 00:00:00 2001 From: John Willard <53777086+JohnFulpWillard@users.noreply.github.com> Date: Fri, 5 Apr 2024 23:45:09 +0000 Subject: [PATCH 035/938] re-adds list of components for admins to remove (#82461) ## About The Pull Request The list of components on a mob when admins try to remove one didn't actually show them, now it does. ![image](https://github.com/tgstation/tgstation/assets/53777086/a6102c3a-df30-4e9c-b7fd-29a4d8ddaa89) ## Why It's Good For The Game Messing with components/elements on mobs are such a pain, in this case was broken entirely. ![admin-toolings](https://github.com/tgstation/tgstation/assets/53777086/3d190c66-34e4-4424-824b-37f95e88b003) ## Changelog :cl: admin: Removing components button now lists components to remove /:cl: --- code/modules/admin/view_variables/topic_basic.dm | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/code/modules/admin/view_variables/topic_basic.dm b/code/modules/admin/view_variables/topic_basic.dm index 96500de507001..8a27d34257810 100644 --- a/code/modules/admin/view_variables/topic_basic.dm +++ b/code/modules/admin/view_variables/topic_basic.dm @@ -98,9 +98,7 @@ if(!check_rights(NONE)) return var/mass_remove = href_list[VV_HK_MASS_REMOVECOMPONENT] - var/list/components = list() - for(var/datum/component/component in target.GetComponents(/datum/component)) - components += component.type + var/list/components = target._datum_components.Copy() var/list/names = list() names += "---Components---" if(length(components)) From a0895029a523278d3e4c8c76e55e490811128382 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sat, 6 Apr 2024 12:45:27 +1300 Subject: [PATCH 036/938] Automatic changelog for PR #82461 [ci skip] --- html/changelogs/AutoChangeLog-pr-82461.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82461.yml diff --git a/html/changelogs/AutoChangeLog-pr-82461.yml b/html/changelogs/AutoChangeLog-pr-82461.yml new file mode 100644 index 0000000000000..a06fb824d2011 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82461.yml @@ -0,0 +1,4 @@ +author: "JohnFulpWillard" +delete-after: True +changes: + - admin: "Removing components button now lists components to remove" \ No newline at end of file From 3ece14ec6ea955049118f9f92d9f20ef69f914b4 Mon Sep 17 00:00:00 2001 From: EnterTheJake <102721711+EnterTheJake@users.noreply.github.com> Date: Sat, 6 Apr 2024 02:05:28 +0200 Subject: [PATCH 037/938] Reboots the CNS Rebooter Implant. (#82441) ## About The Pull Request The CNS Rebooter Implant will now pull you out of stuns and stamcrit, while granting you a few seconds of stun immunity, comes with a 60 seconds cooldown ## Why It's Good For The Game The CNS Rebooter Implant is a strong candidate for the absolute worst implant in the game, it caps your stuns at 4 seconds (which is plenty of time to get murdered) and does nothing to prevent stamina damage, for something accessible in one of the latest research nodes and in the nukie uplink it should perform better than it does now. Besides, the game is in dire need for more tools to keep the stun meta at bay, and this is a good place to start. This PR makes it so the rebooter will bail you out stamcrit every 60 seconds, along with giving you a few seconds of immunity to run away or get a couple of hits in. ## Changelog :cl: balance: CNS Rebooter Implant will now pull you out of stamcrit and grant you a few seconds of stun immunity /:cl: --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> --- .../signals/signals_mob/signals_mob_carbon.dm | 2 + .../modules/mob/living/carbon/status_procs.dm | 1 + .../internal/cyberimp/augments_internal.dm | 47 +++++++++++++++---- 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm index c6cde1d8b4627..637ea90c8e4eb 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm @@ -57,6 +57,8 @@ /// Called from bodypart being removed /obj/item/bodypart/proc/drop_limb(mob/living/carbon/old_owner, special, dismembered) #define COMSIG_BODYPART_REMOVED "bodypart_removed" +/// from /mob/living/carbon/enter_stamcrit() +#define COMSIG_CARBON_ENTER_STAMCRIT "carbon_enter_stamcrit" ///from base of mob/living/carbon/soundbang_act(): (list(intensity)) #define COMSIG_CARBON_SOUNDBANG "carbon_soundbang" ///from /item/organ/proc/Insert() (/obj/item/organ/) diff --git a/code/modules/mob/living/carbon/status_procs.dm b/code/modules/mob/living/carbon/status_procs.dm index dc0b659fbec44..ba19418e2e220 100644 --- a/code/modules/mob/living/carbon/status_procs.dm +++ b/code/modules/mob/living/carbon/status_procs.dm @@ -10,6 +10,7 @@ return if(check_stun_immunity(CANKNOCKDOWN)) return + SEND_SIGNAL(src, COMSIG_CARBON_ENTER_STAMCRIT) to_chat(src, span_notice("You're too exhausted to keep going...")) add_traits(list(TRAIT_INCAPACITATED, TRAIT_IMMOBILIZED, TRAIT_FLOORED), STAMINA) diff --git a/code/modules/surgery/organs/internal/cyberimp/augments_internal.dm b/code/modules/surgery/organs/internal/cyberimp/augments_internal.dm index 0e004ab3c5cb5..89c6f9c96a411 100644 --- a/code/modules/surgery/organs/internal/cyberimp/augments_internal.dm +++ b/code/modules/surgery/organs/internal/cyberimp/augments_internal.dm @@ -106,32 +106,62 @@ var/static/list/signalCache = list( COMSIG_LIVING_STATUS_STUN, - COMSIG_LIVING_STATUS_KNOCKDOWN, COMSIG_LIVING_STATUS_IMMOBILIZE, COMSIG_LIVING_STATUS_PARALYZE, ) - var/stun_cap_amount = 40 + ///timer before the implant activates + var/stun_cap_amount = 1 SECONDS + ///amount of time you are resistant to stuns and knockdowns + var/stun_resistance_time = 6 SECONDS + COOLDOWN_DECLARE(implant_cooldown) /obj/item/organ/internal/cyberimp/brain/anti_stun/on_mob_remove(mob/living/carbon/implant_owner) . = ..() UnregisterSignal(implant_owner, signalCache) + UnregisterSignal(implant_owner, COMSIG_CARBON_ENTER_STAMCRIT) /obj/item/organ/internal/cyberimp/brain/anti_stun/on_mob_insert(mob/living/carbon/receiver) . = ..() RegisterSignals(receiver, signalCache, PROC_REF(on_signal)) + RegisterSignal(receiver, COMSIG_CARBON_ENTER_STAMCRIT, PROC_REF(on_stamcrit)) /obj/item/organ/internal/cyberimp/brain/anti_stun/proc/on_signal(datum/source, amount) SIGNAL_HANDLER if(!(organ_flags & ORGAN_FAILING) && amount > 0) addtimer(CALLBACK(src, PROC_REF(clear_stuns)), stun_cap_amount, TIMER_UNIQUE|TIMER_OVERRIDE) +/obj/item/organ/internal/cyberimp/brain/anti_stun/proc/on_stamcrit(datum/source) + SIGNAL_HANDLER + if(!(organ_flags & ORGAN_FAILING)) + addtimer(CALLBACK(src, PROC_REF(clear_stuns)), stun_cap_amount, TIMER_UNIQUE|TIMER_OVERRIDE) + /obj/item/organ/internal/cyberimp/brain/anti_stun/proc/clear_stuns() - if(owner || !(organ_flags & ORGAN_FAILING)) - owner.SetStun(0) - owner.SetKnockdown(0) - owner.SetImmobilized(0) - owner.SetParalyzed(0) + if(isnull(owner) || (organ_flags & ORGAN_FAILING) || !COOLDOWN_FINISHED(src, implant_cooldown)) + return + + owner.SetStun(0) + owner.SetKnockdown(0) + owner.SetImmobilized(0) + owner.SetParalyzed(0) + owner.setStaminaLoss(0) + addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob/living, setStaminaLoss), 0), stun_resistance_time) + + var/datum/effect_system/spark_spread/sparks = new /datum/effect_system/spark_spread + sparks.set_up(5, 1, src) + sparks.start() + + owner.add_traits(list(TRAIT_IGNOREDAMAGESLOWDOWN, TRAIT_BATON_RESISTANCE, TRAIT_STUNIMMUNE), REF(src)) + addtimer(TRAIT_CALLBACK_REMOVE(owner, TRAIT_IGNOREDAMAGESLOWDOWN, REF(src)), stun_resistance_time) + addtimer(TRAIT_CALLBACK_REMOVE(owner, TRAIT_BATON_RESISTANCE, REF(src)), stun_resistance_time) + addtimer(TRAIT_CALLBACK_REMOVE(owner, TRAIT_STUNIMMUNE, REF(src)), stun_resistance_time) + + COOLDOWN_START(src, implant_cooldown, 60 SECONDS) + addtimer(CALLBACK(src, PROC_REF(implant_ready)),60 SECONDS) + +/obj/item/organ/internal/cyberimp/brain/anti_stun/proc/implant_ready() + if(owner) + to_chat(owner, span_purple("Your rebooter implant is ready.")) /obj/item/organ/internal/cyberimp/brain/anti_stun/emp_act(severity) . = ..() @@ -141,7 +171,8 @@ addtimer(CALLBACK(src, PROC_REF(reboot)), 90 / severity) /obj/item/organ/internal/cyberimp/brain/anti_stun/proc/reboot() - organ_flags &= ~ORGAN_FAILING + organ_flags &= ~ORGAN_FAILING + implant_ready() //[[[[MOUTH]]]] /obj/item/organ/internal/cyberimp/mouth From 893dedf4579b07617004500d9879228365b3c935 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sat, 6 Apr 2024 13:05:46 +1300 Subject: [PATCH 038/938] Automatic changelog for PR #82441 [ci skip] --- html/changelogs/AutoChangeLog-pr-82441.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82441.yml diff --git a/html/changelogs/AutoChangeLog-pr-82441.yml b/html/changelogs/AutoChangeLog-pr-82441.yml new file mode 100644 index 0000000000000..caff69cb2e651 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82441.yml @@ -0,0 +1,4 @@ +author: "EnterTheJake" +delete-after: True +changes: + - balance: "CNS Rebooter Implant will now pull you out of stamcrit and grant you a few seconds of stun immunity" \ No newline at end of file From 3892aea8711f67c46fe6b4429c77cc9d04fab20a Mon Sep 17 00:00:00 2001 From: Artemchik542 <32270644+Artemchik542@users.noreply.github.com> Date: Sat, 6 Apr 2024 07:06:21 +0700 Subject: [PATCH 039/938] Fix "Aheal" for ears deafness (#82448) ## About The Pull Request Make the admin button "Aheal" and Magic Wand of Healing (resurrection) actually full heal carbon's Ears. File _ears.dm contains timer variable "deaf" that should be updated to 0 after complete healing. But I think this must be properly code-refactored because looks like it's just duplicates(?) standart variable "damage" for organ type. ## Why It's Good For The Game Aheal - means FULLY HEAL. ## Changelog :cl: fix: aheal now properly heals ears deafness /:cl: --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> --- code/modules/surgery/organs/_organ.dm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/code/modules/surgery/organs/_organ.dm b/code/modules/surgery/organs/_organ.dm index d7f08a7be35b6..366f0f0087ff2 100644 --- a/code/modules/surgery/organs/_organ.dm +++ b/code/modules/surgery/organs/_organ.dm @@ -239,6 +239,11 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) for(var/obj/item/organ/organ as anything in organs) organ.set_organ_damage(0) set_heartattack(FALSE) + + // Ears have aditional vаr "deaf", need to update it too + var/obj/item/organ/internal/ears/ears = get_organ_slot(ORGAN_SLOT_EARS) + ears?.adjustEarDamage(0, -INFINITY) // full heal ears deafness + return // Default organ fixing handling @@ -273,7 +278,7 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) if(!ears) ears = new() ears.Insert(src) - ears.set_organ_damage(0) + ears.adjustEarDamage(-INFINITY, -INFINITY) // actually do: set_organ_damage(0) and deaf = 0 /obj/item/organ/proc/handle_failing_organs(seconds_per_tick) return From c6a78d6d093e0b43c1d886a3f66300b1925d4a8e Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sat, 6 Apr 2024 13:06:46 +1300 Subject: [PATCH 040/938] Automatic changelog for PR #82448 [ci skip] --- html/changelogs/AutoChangeLog-pr-82448.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82448.yml diff --git a/html/changelogs/AutoChangeLog-pr-82448.yml b/html/changelogs/AutoChangeLog-pr-82448.yml new file mode 100644 index 0000000000000..4d679e87f79b1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82448.yml @@ -0,0 +1,4 @@ +author: "Artemchik542" +delete-after: True +changes: + - bugfix: "aheal now properly heals ears deafness" \ No newline at end of file From 3af85ebb6040bf83ae691b053652baebd72694f5 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Sat, 6 Apr 2024 00:19:13 +0000 Subject: [PATCH 041/938] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-82280.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82307.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82309.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82416.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82430.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82432.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82437.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82441.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82448.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82461.yml | 4 ---- html/changelogs/archive/2024-04.yml | 28 ++++++++++++++++++++++ 11 files changed, 28 insertions(+), 40 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-82280.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82307.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82309.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82416.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82430.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82432.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82437.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82441.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82448.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82461.yml diff --git a/html/changelogs/AutoChangeLog-pr-82280.yml b/html/changelogs/AutoChangeLog-pr-82280.yml deleted file mode 100644 index ebcc638cfca03..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82280.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SyncIt21" -delete-after: True -changes: - - refactor: "refactors how objects are deconstructed in relation to the `NO_DECONSTRUCTION` flag. Certain objects & machinery may display different tool interactions & behaviours when destroyed/deconstructed. Report these changes if you feel like they are bugs" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82307.yml b/html/changelogs/AutoChangeLog-pr-82307.yml deleted file mode 100644 index 1b5ee32a1d43f..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82307.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Rhials" -delete-after: True -changes: - - rscadd: "Nuclear Operatives now purchase an Intelligence Agent, who can watch cameras and bodycams, move the shuttle, and provide radio support. Only 12 Telecrystals!" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82309.yml b/html/changelogs/AutoChangeLog-pr-82309.yml deleted file mode 100644 index dde2c2f5c8b95..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82309.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Blacklist897" -delete-after: True -changes: - - balance: "suit and cell chargers should draw from grid preventing instant apc blackouts in most cases." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82416.yml b/html/changelogs/AutoChangeLog-pr-82416.yml deleted file mode 100644 index 7176ad6d03c7f..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82416.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "jlsnow301, infraredbaron" -delete-after: True -changes: - - rscadd: "Added a new UI element over players that are interacting, building, etc." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82430.yml b/html/changelogs/AutoChangeLog-pr-82430.yml deleted file mode 100644 index 99ef15b39ba32..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82430.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Zergspower" -delete-after: True -changes: - - bugfix: "fixes Borg and Syndicate inducers not working" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82432.yml b/html/changelogs/AutoChangeLog-pr-82432.yml deleted file mode 100644 index 11e0e41f785f0..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82432.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "00-Steven" -delete-after: True -changes: - - admin: "Refresh button on the View Round Logs menu actually works, instead of just adding a runtime to the logs (and not updating them)." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82437.yml b/html/changelogs/AutoChangeLog-pr-82437.yml deleted file mode 100644 index 8978467f002f7..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82437.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Archie700" -delete-after: True -changes: - - bugfix: "changed value of cell charge from 5000 to 5 megajoules" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82441.yml b/html/changelogs/AutoChangeLog-pr-82441.yml deleted file mode 100644 index caff69cb2e651..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82441.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "EnterTheJake" -delete-after: True -changes: - - balance: "CNS Rebooter Implant will now pull you out of stamcrit and grant you a few seconds of stun immunity" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82448.yml b/html/changelogs/AutoChangeLog-pr-82448.yml deleted file mode 100644 index 4d679e87f79b1..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82448.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Artemchik542" -delete-after: True -changes: - - bugfix: "aheal now properly heals ears deafness" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82461.yml b/html/changelogs/AutoChangeLog-pr-82461.yml deleted file mode 100644 index a06fb824d2011..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82461.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "JohnFulpWillard" -delete-after: True -changes: - - admin: "Removing components button now lists components to remove" \ No newline at end of file diff --git a/html/changelogs/archive/2024-04.yml b/html/changelogs/archive/2024-04.yml index 76fc8f4c26dc2..dddc2eb8aa4a3 100644 --- a/html/changelogs/archive/2024-04.yml +++ b/html/changelogs/archive/2024-04.yml @@ -180,3 +180,31 @@ nikothedude: - bugfix: Root beer no longer causes laser carbines and disabler smgs to fire infinitely fast. +2024-04-06: + 00-Steven: + - admin: Refresh button on the View Round Logs menu actually works, instead of just + adding a runtime to the logs (and not updating them). + Archie700: + - bugfix: changed value of cell charge from 5000 to 5 megajoules + Artemchik542: + - bugfix: aheal now properly heals ears deafness + Blacklist897: + - balance: suit and cell chargers should draw from grid preventing instant apc blackouts + in most cases. + EnterTheJake: + - balance: CNS Rebooter Implant will now pull you out of stamcrit and grant you + a few seconds of stun immunity + JohnFulpWillard: + - admin: Removing components button now lists components to remove + Rhials: + - rscadd: Nuclear Operatives now purchase an Intelligence Agent, who can watch cameras + and bodycams, move the shuttle, and provide radio support. Only 12 Telecrystals! + SyncIt21: + - refactor: refactors how objects are deconstructed in relation to the `NO_DECONSTRUCTION` + flag. Certain objects & machinery may display different tool interactions & + behaviours when destroyed/deconstructed. Report these changes if you feel like + they are bugs + Zergspower: + - bugfix: fixes Borg and Syndicate inducers not working + jlsnow301, infraredbaron: + - rscadd: Added a new UI element over players that are interacting, building, etc. From 0235ebc38e46abba2e0e747ff9ed3ab8465b3309 Mon Sep 17 00:00:00 2001 From: John Willard <53777086+JohnFulpWillard@users.noreply.github.com> Date: Sat, 6 Apr 2024 05:02:34 +0000 Subject: [PATCH 042/938] Medipens can't have reagents removed from them anymore. (#82451) ## About The Pull Request This will be needed for https://github.com/tgstation/tgstation/pull/82449 because this removes the machine's ability to make infinite chems. Basically in https://github.com/tgstation/tgstation/pull/29139 they removed medipen's ability to have reagents injected into them, but never removed the ability to take reagents out. You could take a syringe, remove all chemicals from a medipen, put the main ingredient in a medipen refiller, then refill. You could do this right now on live servers with an epipen for infinite formaldehyde. This doesn't affect the hypospray. ## Why It's Good For The Game Removes a way of infinitely making reagents with a medipen refiller and also removes a dumb mechanic. You could take all chemicals out of an EHMS autoinjector, which removes the visual and feedback tell to the target that they've been injected, and even with 0 chemicals they get the disease anyways. You could buy medipens as a miner, take the chemicals out, and put them in a syringe or pill that you can inject yourself instantly with. You can take otherwise hard-to-get chemicals like fungal TB's 2-use cure injector, and make 40 cure pills instead. ## Changelog :cl: fix: You can no longer take chemicals out of medipens with a syringe. /:cl: --- code/modules/reagents/reagent_containers/hypospray.dm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index 4cbb4839416c3..c4cd57b15680e 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -122,7 +122,7 @@ has_variable_transfer_amount = FALSE volume = 15 ignore_flags = 1 //so you can medipen through spacesuits - reagent_flags = DRAWABLE + reagent_flags = NONE flags_1 = null list_reagents = list(/datum/reagent/medicine/epinephrine = 10, /datum/reagent/toxin/formaldehyde = 3, /datum/reagent/medicine/coagulant = 2) custom_price = PAYCHECK_CREW @@ -312,7 +312,6 @@ base_icon_state = "gorillapen" volume = 5 ignore_flags = 0 - reagent_flags = NONE list_reagents = list(/datum/reagent/magillitis = 5) /obj/item/reagent_containers/hypospray/medipen/pumpup From d2d40230c24cc9fd1730a7911c3971ad675525c2 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sat, 6 Apr 2024 18:02:53 +1300 Subject: [PATCH 043/938] Automatic changelog for PR #82451 [ci skip] --- html/changelogs/AutoChangeLog-pr-82451.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82451.yml diff --git a/html/changelogs/AutoChangeLog-pr-82451.yml b/html/changelogs/AutoChangeLog-pr-82451.yml new file mode 100644 index 0000000000000..92829037ef6ab --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82451.yml @@ -0,0 +1,4 @@ +author: "JohnFulpWillard" +delete-after: True +changes: + - bugfix: "You can no longer take chemicals out of medipens with a syringe." \ No newline at end of file From 437dff3511da2493affd69ac44d685f8262458e9 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Sat, 6 Apr 2024 08:38:47 +0300 Subject: [PATCH 044/938] Search string in catalogs in char prefs (#82423) --- .../interfaces/PreferencesMenu/MainPage.tsx | 78 ++++++++++++------- 1 file changed, 49 insertions(+), 29 deletions(-) diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/MainPage.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/MainPage.tsx index 2e3c40305acc9..dbb31c73cbb8b 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/MainPage.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/MainPage.tsx @@ -2,12 +2,16 @@ import { filterMap, sortBy } from 'common/collections'; import { classes } from 'common/react'; import { useState } from 'react'; +import { filter } from '../../../common/collections'; +import { flow } from '../../../common/fp'; +import { createSearch } from '../../../common/string'; import { sendAct, useBackend } from '../../backend'; import { Autofocus, Box, Button, Flex, + Input, LabeledList, Popper, Stack, @@ -90,6 +94,7 @@ const ChoicedSelection = (props: { const { act } = useBackend(); const { catalog, supplementalFeature, supplementalValue } = props; + const [getSearchText, searchTextSet] = useState(''); if (!catalog.icons) { return Provided catalog had no icons!; @@ -145,39 +150,49 @@ const ChoicedSelection = (props: { + searchTextSet(value)} + /> - {Object.entries(catalog.icons).map(([name, image], index) => { - return ( - - - - ); - })} + + + ); + }, + )} @@ -186,6 +201,11 @@ const ChoicedSelection = (props: { ); }; +const searchInCatalog = (searchText = '', catalog: Record) => { + const maybeSearch = createSearch(searchText, ([name, _icon]) => name); + return flow([searchText && filter(maybeSearch)])(Object.entries(catalog)); +}; + const GenderButton = (props: { handleSetGender: (gender: Gender) => void; gender: Gender; From c34d56a45b0461f5e0fad3cc75e81580c3357119 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sat, 6 Apr 2024 18:39:07 +1300 Subject: [PATCH 045/938] Automatic changelog for PR #82423 [ci skip] --- html/changelogs/AutoChangeLog-pr-82423.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82423.yml diff --git a/html/changelogs/AutoChangeLog-pr-82423.yml b/html/changelogs/AutoChangeLog-pr-82423.yml new file mode 100644 index 0000000000000..193c73820f683 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82423.yml @@ -0,0 +1,4 @@ +author: "Vishenka0704" +delete-after: True +changes: + - qol: "Added search bar to character prefs catalogs" \ No newline at end of file From c33d9ccaf42964dc17950510fab93f4b2b5feb7f Mon Sep 17 00:00:00 2001 From: jimmyl <70376633+mc-oofert@users.noreply.github.com> Date: Sat, 6 Apr 2024 22:55:34 +0200 Subject: [PATCH 046/938] actually just removes stamina damage and knockdown from punches (#82400) ## About The Pull Request removes punch knockdowns and stamina damage from them ## Why It's Good For The Game knockdown punches were also around the time disarm could just hardstun you to RNG this is dumb so we remove that also watermelon supposedly wanted to remove stamina damage from punches so idk about that anyway so this is a problem because you could be randomly floored by sheer luck through thick plates of metal and is overall not a very fun thing to play against especially with northstar gloves resolves unfun RNG by removing knockdowns and does something watermelon wanted by removing stam damage from it ## Changelog :cl: balance: punches no longer knock down or deal stamina damage /:cl: --- code/modules/mob/living/carbon/human/_species.dm | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index 46e0b0e967cbe..d6fe9bc8c31ad 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -1143,25 +1143,12 @@ GLOBAL_LIST_EMPTY(features_by_species) target.force_say() log_combat(user, target, grappled ? "grapple punched" : "kicked") target.apply_damage(damage, attack_type, affecting, armor_block - limb_accuracy, attack_direction = attack_direction) - target.apply_damage(damage*1.5, STAMINA, affecting, armor_block - limb_accuracy) else // Normal attacks do not gain the benefit of armor penetration. target.apply_damage(damage, attack_type, affecting, armor_block, attack_direction = attack_direction) - target.apply_damage(damage*1.5, STAMINA, affecting, armor_block) if(damage >= 9) target.force_say() log_combat(user, target, "punched") - //If we rolled a punch high enough to hit our stun threshold, or our target is staggered and they have at least 40 damage+stamina loss, we knock them down - //This does not work against opponents who are knockdown immune, such as from wearing riot armor. - if(!HAS_TRAIT(src, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED)) - if((target.stat != DEAD) && prob(limb_accuracy) || (target.stat != DEAD) && staggered && (target.getStaminaLoss() + user.getBruteLoss()) >= 40) - target.visible_message(span_danger("[user] knocks [target] down!"), \ - span_userdanger("You're knocked down by [user]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, user) - to_chat(user, span_danger("You knock [target] down!")) - var/knockdown_duration = 4 SECONDS + (target.getStaminaLoss() + (target.getBruteLoss()*0.5))*0.8 //50 total damage = 4 second base stun + 4 second stun modifier = 8 second knockdown duration - target.apply_effect(knockdown_duration, EFFECT_KNOCKDOWN, armor_block) - log_combat(user, target, "got a stun punch with their previous punch") - /datum/species/proc/disarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style) if(user.body_position != STANDING_UP) return FALSE From d4339bf4539bb50688b72cdd99391f99f7bd9ac9 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sun, 7 Apr 2024 08:55:53 +1200 Subject: [PATCH 047/938] Automatic changelog for PR #82400 [ci skip] --- html/changelogs/AutoChangeLog-pr-82400.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82400.yml diff --git a/html/changelogs/AutoChangeLog-pr-82400.yml b/html/changelogs/AutoChangeLog-pr-82400.yml new file mode 100644 index 0000000000000..1f74d8b9559d1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82400.yml @@ -0,0 +1,4 @@ +author: "mc-oofert" +delete-after: True +changes: + - balance: "punches no longer knock down or deal stamina damage" \ No newline at end of file From 080f1656875140ca195467d8d32e15f772da6247 Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Sat, 6 Apr 2024 16:14:00 -0500 Subject: [PATCH 048/938] Fix slime `check_item_passthrough` effect (#82484) ## About The Pull Request This proc expects a user but is not passed one. ## Changelog :cl: Melbert fix: Items will properly pass through slime on occasion /:cl: --- code/modules/mob/living/basic/slime/defense.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/living/basic/slime/defense.dm b/code/modules/mob/living/basic/slime/defense.dm index 17bd22b905ae3..b747c24201971 100644 --- a/code/modules/mob/living/basic/slime/defense.dm +++ b/code/modules/mob/living/basic/slime/defense.dm @@ -31,7 +31,7 @@ return //Checks if the item passes through the slime first. Safe items can be used simply - if(check_item_passthrough(attacking_item)) + if(check_item_passthrough(attacking_item, user)) return try_discipline_slime(attacking_item) From 018a267b92295fef5709fd244d3921f9178e2ee6 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sun, 7 Apr 2024 09:14:20 +1200 Subject: [PATCH 049/938] Automatic changelog for PR #82484 [ci skip] --- html/changelogs/AutoChangeLog-pr-82484.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82484.yml diff --git a/html/changelogs/AutoChangeLog-pr-82484.yml b/html/changelogs/AutoChangeLog-pr-82484.yml new file mode 100644 index 0000000000000..c31f8ec103978 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82484.yml @@ -0,0 +1,4 @@ +author: "Melbert" +delete-after: True +changes: + - bugfix: "Items will properly pass through slime on occasion" \ No newline at end of file From a15a1b88ed7d80523f73d928cf658bf50bbdf744 Mon Sep 17 00:00:00 2001 From: John Willard <53777086+JohnFulpWillard@users.noreply.github.com> Date: Sat, 6 Apr 2024 21:17:53 +0000 Subject: [PATCH 050/938] Basic mobs now use z-level turnoff instead of simple (#82469) ## About The Pull Request On one compile of MetaStation, I saw that there's 45 basic mobs on the station, 256 on lavaland (the number growing from tendrils), and 59 in all other z levels combined. While we do expect Lavaland to be visited every round, at least it won't be running during the times when no one is there, but even more importantly, space exploration is something not done every round, so we don't have any reason to waste our resources on AIs that will never be interacted with. Simple animals had an easy solution to this: If no one is on the Z level, their AI turns off If someone is on the Z level, they are idle unless needed. The last simple animals that exists right now are bots, megafauna, geese, gondolas, and some minor ones like mimic, zombie, dark wizard, soulscythe, etc. Point is, we're very much nearly done going through all simple animals, so this code is being wasted just to ensure things like cleanbots won't work if no one is on the z level, something I doubt happens often, so I took their code and made it work for basic mobs instead. I could've done both but I thought it would look very bad, and maybe this is a good incentivize to get more basic mob conversions. There's one major change here and it's that we're missing the "Idle" mode, some basic mobs like the Lavaland village seems to be made with intent that they'll be running even if players aren't around, so this sets up a future PR that makes idle AI easier to add, and I want to make sure those cases are taken into account. ## Why It's Good For The Game We don't need to always be processing these basic mobs, and sets us in the future to hopefully also implement idle AIs. ## Changelog :cl: balance: Basic mob AIs with no mobs on the Z level now stop. /:cl: --------- Co-authored-by: san7890 --- code/__DEFINES/ai/ai.dm | 8 ++- code/__DEFINES/mobs.dm | 1 - code/__DEFINES/subsystems.dm | 1 - code/_globalvars/lists/mobs.dm | 2 +- code/controllers/subsystem/ai_controllers.dm | 39 +++++++--- code/controllers/subsystem/idlenpcpool.dm | 47 ------------ code/datums/ai/_ai_controller.dm | 72 ++++++++++++++----- code/game/world.dm | 2 +- code/modules/clothing/shoes/cowboy.dm | 2 +- code/modules/mob/dead/dead.dm | 24 ++++--- code/modules/mob/dead/observer/login.dm | 4 -- code/modules/mob/dead/observer/logout.dm | 1 - .../mob/living/basic/ruin_defender/flesh.dm | 45 +++++++----- code/modules/mob/living/living.dm | 54 +++++++------- .../living/simple_animal/hostile/hostile.dm | 23 ------ .../mob/living/simple_animal/simple_animal.dm | 23 +----- code/modules/mob/mob_defines.dm | 2 +- code/modules/unit_tests/limbsanity.dm | 10 +-- code/modules/unit_tests/mouse_bite_cable.dm | 2 + code/modules/unit_tests/suit_storage_icons.dm | 13 ++-- tgstation.dme | 1 - 21 files changed, 177 insertions(+), 199 deletions(-) delete mode 100644 code/controllers/subsystem/idlenpcpool.dm diff --git a/code/__DEFINES/ai/ai.dm b/code/__DEFINES/ai/ai.dm index 65cc421490866..e894b32b1f646 100644 --- a/code/__DEFINES/ai/ai.dm +++ b/code/__DEFINES/ai/ai.dm @@ -2,8 +2,12 @@ #define GET_TARGETING_STRATEGY(targeting_type) SSai_behaviors.targeting_strategies[targeting_type] #define HAS_AI_CONTROLLER_TYPE(thing, type) istype(thing?.ai_controller, type) -#define AI_STATUS_ON 1 -#define AI_STATUS_OFF 2 +//AI controller flags +//If you add a new status, be sure to add it to the ai_controllers subsystem's ai_controllers_by_status list. +///The AI is currently active. +#define AI_STATUS_ON "ai_on" +///The AI is currently offline for any reason. +#define AI_STATUS_OFF "ai_off" ///For JPS pathing, the maximum length of a path we'll try to generate. Should be modularized depending on what we're doing later on #define AI_MAX_PATH_LENGTH 30 // 30 is possibly overkill since by default we lose interest after 14 tiles of distance, but this gives wiggle room for weaving around obstacles diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 9bfe6df5a5af9..066a37b6d4818 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -341,7 +341,6 @@ #define AI_ON 1 #define AI_IDLE 2 #define AI_OFF 3 -#define AI_Z_OFF 4 //The range at which a mob should wake up if you spawn into the z level near it #define MAX_SIMPLEMOB_WAKEUP_RANGE 5 diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 6d04fca876b48..c3778351882bc 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -193,7 +193,6 @@ // If the subsystem isn't listed here it's either DEFAULT or PROCESS (if it's a processing subsystem child) #define FIRE_PRIORITY_PING 10 -#define FIRE_PRIORITY_IDLE_NPC 10 #define FIRE_PRIORITY_SERVER_MAINT 10 #define FIRE_PRIORITY_RESEARCH 10 #define FIRE_PRIORITY_VIS 10 diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm index 2de6a1c691fc8..4e33aa43708a2 100644 --- a/code/_globalvars/lists/mobs.dm +++ b/code/_globalvars/lists/mobs.dm @@ -59,7 +59,7 @@ GLOBAL_LIST_EMPTY(human_list) //all instances of /mob/living/carbon/human and su GLOBAL_LIST_EMPTY(ai_list) GLOBAL_LIST_EMPTY(pai_list) GLOBAL_LIST_EMPTY(available_ai_shells) -GLOBAL_LIST_INIT(simple_animals, list(list(),list(),list(),list())) // One for each AI_* status define +GLOBAL_LIST_INIT(simple_animals, list(list(),list(),list())) // One for each AI_* status define GLOBAL_LIST_EMPTY(spidermobs) //all sentient spider mobs GLOBAL_LIST_EMPTY(bots_list) GLOBAL_LIST_EMPTY(aiEyes) diff --git a/code/controllers/subsystem/ai_controllers.dm b/code/controllers/subsystem/ai_controllers.dm index 3d8d26531497c..44e1948e3864b 100644 --- a/code/controllers/subsystem/ai_controllers.dm +++ b/code/controllers/subsystem/ai_controllers.dm @@ -3,27 +3,32 @@ SUBSYSTEM_DEF(ai_controllers) name = "AI Controller Ticker" flags = SS_POST_FIRE_TIMING|SS_BACKGROUND priority = FIRE_PRIORITY_NPC - runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME init_order = INIT_ORDER_AI_CONTROLLERS wait = 0.5 SECONDS //Plan every half second if required, not great not terrible. + runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME ///List of all ai_subtree singletons, key is the typepath while assigned value is a newly created instance of the typepath. See setup_subtrees() - var/list/ai_subtrees = list() - ///List of all ai controllers currently running - var/list/active_ai_controllers = list() + var/list/datum/ai_planning_subtree/ai_subtrees = list() + ///Assoc List of all AI statuses and all AI controllers with that status. + var/list/ai_controllers_by_status = list( + AI_STATUS_ON = list(), + AI_STATUS_OFF = list(), + ) + ///Assoc List of all AI controllers and the Z level they are on, which we check when someone enters/leaves a Z level to turn them on/off. + var/list/ai_controllers_by_zlevel = list() /datum/controller/subsystem/ai_controllers/Initialize() setup_subtrees() return SS_INIT_SUCCESS -/datum/controller/subsystem/ai_controllers/proc/setup_subtrees() - ai_subtrees = list() - for(var/subtree_type in subtypesof(/datum/ai_planning_subtree)) - var/datum/ai_planning_subtree/subtree = new subtree_type - ai_subtrees[subtree_type] = subtree +/datum/controller/subsystem/ai_controllers/stat_entry(msg) + var/list/active_list = ai_controllers_by_status[AI_STATUS_ON] + var/list/inactive_list = ai_controllers_by_status[AI_STATUS_OFF] + msg = "Active AIs:[length(active_list)]|Inactive:[length(inactive_list)]" + return ..() /datum/controller/subsystem/ai_controllers/fire(resumed) - for(var/datum/ai_controller/ai_controller as anything in active_ai_controllers) + for(var/datum/ai_controller/ai_controller as anything in ai_controllers_by_status[AI_STATUS_ON]) if(!COOLDOWN_FINISHED(ai_controller, failed_planning_cooldown)) continue @@ -32,3 +37,17 @@ SUBSYSTEM_DEF(ai_controllers) ai_controller.SelectBehaviors(wait * 0.1) if(!LAZYLEN(ai_controller.current_behaviors)) //Still no plan COOLDOWN_START(ai_controller, failed_planning_cooldown, AI_FAILED_PLANNING_COOLDOWN) + +///Creates all instances of ai_subtrees and assigns them to the ai_subtrees list. +/datum/controller/subsystem/ai_controllers/proc/setup_subtrees() + for(var/subtree_type in subtypesof(/datum/ai_planning_subtree)) + var/datum/ai_planning_subtree/subtree = new subtree_type + ai_subtrees[subtree_type] = subtree + +///Called when the max Z level was changed, updating our coverage. +/datum/controller/subsystem/ai_controllers/proc/on_max_z_changed() + if (!islist(ai_controllers_by_zlevel)) + ai_controllers_by_zlevel = new /list(world.maxz,0) + while (SSai_controllers.ai_controllers_by_zlevel.len < world.maxz) + SSai_controllers.ai_controllers_by_zlevel.len++ + SSai_controllers.ai_controllers_by_zlevel[ai_controllers_by_zlevel.len] = list() diff --git a/code/controllers/subsystem/idlenpcpool.dm b/code/controllers/subsystem/idlenpcpool.dm deleted file mode 100644 index ee98e8c4e67c2..0000000000000 --- a/code/controllers/subsystem/idlenpcpool.dm +++ /dev/null @@ -1,47 +0,0 @@ -SUBSYSTEM_DEF(idlenpcpool) - name = "Idling NPC Pool" - flags = SS_POST_FIRE_TIMING|SS_BACKGROUND|SS_NO_INIT - priority = FIRE_PRIORITY_IDLE_NPC - wait = 60 - runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME - - var/list/currentrun = list() - var/static/list/idle_mobs_by_zlevel[][] - -/datum/controller/subsystem/idlenpcpool/stat_entry(msg) - var/list/idlelist = GLOB.simple_animals[AI_IDLE] - var/list/zlist = GLOB.simple_animals[AI_Z_OFF] - msg = "IdleNPCS:[length(idlelist)]|Z:[length(zlist)]" - return ..() - -/datum/controller/subsystem/idlenpcpool/proc/MaxZChanged() - if (!islist(idle_mobs_by_zlevel)) - idle_mobs_by_zlevel = new /list(world.maxz,0) - while (SSidlenpcpool.idle_mobs_by_zlevel.len < world.maxz) - SSidlenpcpool.idle_mobs_by_zlevel.len++ - SSidlenpcpool.idle_mobs_by_zlevel[idle_mobs_by_zlevel.len] = list() - -/datum/controller/subsystem/idlenpcpool/fire(resumed = FALSE) - - if (!resumed) - var/list/idlelist = GLOB.simple_animals[AI_IDLE] - src.currentrun = idlelist.Copy() - - //cache for sanic speed (lists are references anyways) - var/list/currentrun = src.currentrun - - while(currentrun.len) - var/mob/living/simple_animal/SA = currentrun[currentrun.len] - --currentrun.len - if (QDELETED(SA)) - GLOB.simple_animals[AI_IDLE] -= SA - stack_trace("Found a null in simple_animals deactive list [SA.type]!") - continue - - if(!SA.ckey) - if(SA.stat != DEAD) - SA.handle_automated_movement() - if(SA.stat != DEAD) - SA.consider_wakeup() - if (MC_TICK_CHECK) - return diff --git a/code/datums/ai/_ai_controller.dm b/code/datums/ai/_ai_controller.dm index 91f624972adce..664e89eab09f4 100644 --- a/code/datums/ai/_ai_controller.dm +++ b/code/datums/ai/_ai_controller.dm @@ -68,7 +68,6 @@ multiple modular subtrees with behaviors PossessPawn(new_pawn) /datum/ai_controller/Destroy(force) - set_ai_status(AI_STATUS_OFF) UnpossessPawn(FALSE) set_movement_target(type, null) if(ai_movement.moving_controllers[src]) @@ -116,9 +115,14 @@ multiple modular subtrees with behaviors pawn = new_pawn pawn.ai_controller = src + var/turf/pawn_turf = get_turf(pawn) + if(pawn_turf) + SSai_controllers.ai_controllers_by_zlevel[pawn_turf.z] += src + SEND_SIGNAL(src, COMSIG_AI_CONTROLLER_POSSESSED_PAWN) reset_ai_status() + RegisterSignal(pawn, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(on_changed_z_level)) RegisterSignal(pawn, COMSIG_MOB_STATCHANGE, PROC_REF(on_stat_changed)) RegisterSignal(pawn, COMSIG_MOB_LOGIN, PROC_REF(on_sentience_gained)) RegisterSignal(pawn, COMSIG_QDELETING, PROC_REF(on_pawn_qdeleted)) @@ -127,25 +131,53 @@ multiple modular subtrees with behaviors /datum/ai_controller/proc/reset_ai_status() set_ai_status(get_expected_ai_status()) -/// Returns what the AI status should be based on current conditions. +/** + * Gets the AI status we expect the AI controller to be on at this current moment. + * Returns AI_STATUS_OFF if it's inhabited by a Client and shouldn't be, if it's dead and cannot act while dead, or is on a z level without clients. + * Returns AI_STATUS_ON otherwise. + */ /datum/ai_controller/proc/get_expected_ai_status() - var/final_status = AI_STATUS_ON - if (!ismob(pawn)) - return final_status + return AI_STATUS_ON var/mob/living/mob_pawn = pawn - if(!continue_processing_when_client && mob_pawn.client) - final_status = AI_STATUS_OFF - - if(ai_traits & CAN_ACT_WHILE_DEAD) - return final_status + return AI_STATUS_OFF if(mob_pawn.stat == DEAD) - final_status = AI_STATUS_OFF + if(ai_traits & CAN_ACT_WHILE_DEAD) + return AI_STATUS_ON + return AI_STATUS_OFF + + var/turf/pawn_turf = get_turf(mob_pawn) +#ifdef TESTING + if(!pawn_turf) + CRASH("AI controller [src] controlling pawn ([pawn]) is not on a turf.") +#endif + if(!length(SSmobs.clients_by_zlevel[pawn_turf.z])) + return AI_STATUS_OFF + return AI_STATUS_ON + +/datum/ai_controller/proc/get_current_turf() + var/mob/living/mob_pawn = pawn + var/turf/pawn_turf = get_turf(mob_pawn) + to_chat(world, "[pawn_turf]") - return final_status +///Called when the AI controller pawn changes z levels, we check if there's any clients on the new one and wake up the AI if there is. +/datum/ai_controller/proc/on_changed_z_level(atom/source, turf/old_turf, turf/new_turf, same_z_layer, notify_contents) + SIGNAL_HANDLER + var/mob/mob_pawn = pawn + if((mob_pawn?.client && !continue_processing_when_client)) + return + if(old_turf) + SSai_controllers.ai_controllers_by_zlevel[old_turf.z] -= src + if(new_turf) + SSai_controllers.ai_controllers_by_zlevel[new_turf.z] += src + var/new_level_clients = SSmobs.clients_by_zlevel[new_turf.z].len + if(new_level_clients) + set_ai_status(AI_STATUS_ON) + else + set_ai_status(AI_STATUS_OFF) ///Abstract proc for initializing the pawn to the new controller /datum/ai_controller/proc/TryPossessPawn(atom/new_pawn) @@ -156,9 +188,15 @@ multiple modular subtrees with behaviors if(isnull(pawn)) return // instantiated without an applicable pawn, fine - UnregisterSignal(pawn, list(COMSIG_MOB_LOGIN, COMSIG_MOB_LOGOUT, COMSIG_MOB_STATCHANGE, COMSIG_QDELETING)) + set_ai_status(AI_STATUS_OFF) + UnregisterSignal(pawn, list(COMSIG_MOVABLE_Z_CHANGED, COMSIG_MOB_LOGIN, COMSIG_MOB_LOGOUT, COMSIG_MOB_STATCHANGE, COMSIG_QDELETING)) if(ai_movement.moving_controllers[src]) ai_movement.stop_moving_towards(src) + var/turf/pawn_turf = get_turf(pawn) + if(pawn_turf) + SSai_controllers.ai_controllers_by_zlevel[pawn_turf.z] -= src + if(ai_status) + SSai_controllers.ai_controllers_by_status[ai_status] -= src pawn.ai_controller = null pawn = null if(destroy) @@ -269,15 +307,17 @@ multiple modular subtrees with behaviors /datum/ai_controller/proc/set_ai_status(new_ai_status) if(ai_status == new_ai_status) return FALSE //no change - + + //remove old status, if we've got one + if(ai_status) + SSai_controllers.ai_controllers_by_status[ai_status] -= src ai_status = new_ai_status + SSai_controllers.ai_controllers_by_status[new_ai_status] += src switch(ai_status) if(AI_STATUS_ON) - SSai_controllers.active_ai_controllers += src START_PROCESSING(SSai_behaviors, src) if(AI_STATUS_OFF) STOP_PROCESSING(SSai_behaviors, src) - SSai_controllers.active_ai_controllers -= src CancelActions() /datum/ai_controller/proc/PauseAi(time) diff --git a/code/game/world.dm b/code/game/world.dm index cda503bd3b5b7..9e57dbba343c5 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -448,7 +448,7 @@ GLOBAL_VAR(restart_counter) /world/proc/incrementMaxZ() maxz++ SSmobs.MaxZChanged() - SSidlenpcpool.MaxZChanged() + SSai_controllers.on_max_z_changed() /world/proc/change_fps(new_value = 20) if(new_value <= 0) diff --git a/code/modules/clothing/shoes/cowboy.dm b/code/modules/clothing/shoes/cowboy.dm index b7382584e5705..73c5a9d0d958c 100644 --- a/code/modules/clothing/shoes/cowboy.dm +++ b/code/modules/clothing/shoes/cowboy.dm @@ -4,8 +4,8 @@ icon_state = "cowboy_brown" armor_type = /datum/armor/shoes_cowboy custom_price = PAYCHECK_CREW - var/max_occupants = 4 can_be_tied = FALSE + var/max_occupants = 4 /// Do these boots have spur sounds? var/has_spurs = FALSE /// The jingle jangle jingle of our spurs diff --git a/code/modules/mob/dead/dead.dm b/code/modules/mob/dead/dead.dm index 615eb55898c92..30d273db7daae 100644 --- a/code/modules/mob/dead/dead.dm +++ b/code/modules/mob/dead/dead.dm @@ -90,16 +90,20 @@ INITIALIZE_IMMEDIATE(/mob/dead) #undef SERVER_HOPPER_TRAIT -/mob/dead/proc/update_z(new_z) // 1+ to register, null to unregister - if (registered_z != new_z) - if (registered_z) - SSmobs.dead_players_by_zlevel[registered_z] -= src - if (client) - if (new_z) - SSmobs.dead_players_by_zlevel[new_z] += src - registered_z = new_z - else - registered_z = null +/** + * updates the Z level for dead players + * If they don't have a new z, we'll keep the old one, preventing bugs from ghosting and re-entering, among others + */ +/mob/dead/proc/update_z(new_z) + if(registered_z == new_z) + return + if(registered_z) + SSmobs.dead_players_by_zlevel[registered_z] -= src + if(isnull(client)) + registered_z = null + return + registered_z = new_z + SSmobs.dead_players_by_zlevel[new_z] += src /mob/dead/Login() . = ..() diff --git a/code/modules/mob/dead/observer/login.dm b/code/modules/mob/dead/observer/login.dm index 4135f8d22faff..c239817a30e14 100644 --- a/code/modules/mob/dead/observer/login.dm +++ b/code/modules/mob/dead/observer/login.dm @@ -14,10 +14,6 @@ preferred_form = client.prefs.read_preference(/datum/preference/choiced/ghost_form) ghost_orbit = client.prefs.read_preference(/datum/preference/choiced/ghost_orbit) - var/turf/T = get_turf(src) - if (isturf(T)) - update_z(T.z) - update_icon(ALL, preferred_form) updateghostimages() client.set_right_click_menu_mode(FALSE) diff --git a/code/modules/mob/dead/observer/logout.dm b/code/modules/mob/dead/observer/logout.dm index 4ba701c0ae091..53db92d91e32c 100644 --- a/code/modules/mob/dead/observer/logout.dm +++ b/code/modules/mob/dead/observer/logout.dm @@ -1,5 +1,4 @@ /mob/dead/observer/Logout() - update_z(null) if (client) client.images -= (GLOB.ghost_images_default+GLOB.ghost_images_simple) diff --git a/code/modules/mob/living/basic/ruin_defender/flesh.dm b/code/modules/mob/living/basic/ruin_defender/flesh.dm index e33cdcad1a1ea..17d625cb591f6 100644 --- a/code/modules/mob/living/basic/ruin_defender/flesh.dm +++ b/code/modules/mob/living/basic/ruin_defender/flesh.dm @@ -40,7 +40,11 @@ /mob/living/basic/living_limb_flesh/Destroy(force) . = ..() - QDEL_NULL(current_bodypart) + if(current_bodypart) + var/obj/item/bodypart/bodypart = current_bodypart + unregister_from_limb(current_bodypart.owner) + if(!QDELETED(bodypart)) + qdel(bodypart) /mob/living/basic/living_limb_flesh/Life(seconds_per_tick = SSMOBS_DT, times_fired) . = ..() @@ -119,16 +123,10 @@ part_type = /obj/item/bodypart/leg/right/flesh target.visible_message(span_danger("[src] [target_part ? "tears off and attaches itself" : "attaches itself"] to where [target][target.p_s()] limb used to be!")) - current_bodypart = new part_type(TRUE) //dont_spawn_flesh, we cant use named arguments here - current_bodypart.replace_limb(target, TRUE) - forceMove(current_bodypart) - register_to_limb(current_bodypart) - -/mob/living/basic/living_limb_flesh/proc/register_to_limb(obj/item/bodypart/part) - ai_controller.set_ai_status(AI_STATUS_OFF) - RegisterSignal(part, COMSIG_BODYPART_REMOVED, PROC_REF(on_limb_lost)) - RegisterSignal(part.owner, COMSIG_LIVING_DEATH, PROC_REF(owner_died)) - RegisterSignal(part.owner, COMSIG_LIVING_ELECTROCUTE_ACT, PROC_REF(owner_shocked)) //detach if we are shocked, not beneficial for the host but hey its a sideeffect + var/obj/item/bodypart/new_bodypart = new part_type(TRUE) //dont_spawn_flesh, we cant use named arguments here + new_bodypart.replace_limb(target, TRUE) + forceMove(new_bodypart) + register_to_limb(new_bodypart) /mob/living/basic/living_limb_flesh/proc/owner_shocked(datum/source, shock_damage, shock_source, siemens_coeff, flags) SIGNAL_HANDLER @@ -154,15 +152,28 @@ /mob/living/basic/living_limb_flesh/proc/on_limb_lost(atom/movable/source, mob/living/carbon/old_owner, special, dismembered) SIGNAL_HANDLER - UnregisterSignal(source, COMSIG_BODYPART_REMOVED) - UnregisterSignal(old_owner, COMSIG_LIVING_ELECTROCUTE_ACT) - UnregisterSignal(old_owner, COMSIG_LIVING_DEATH) + unregister_from_limb(old_owner) addtimer(CALLBACK(src, PROC_REF(wake_up), source), 2 SECONDS) +/mob/living/basic/living_limb_flesh/proc/register_to_limb(obj/item/bodypart/part) + current_bodypart = part + ai_controller.set_ai_status(AI_STATUS_OFF) + RegisterSignal(current_bodypart, COMSIG_BODYPART_REMOVED, PROC_REF(on_limb_lost)) + if(current_bodypart.owner) + RegisterSignal(current_bodypart.owner, COMSIG_LIVING_DEATH, PROC_REF(owner_died)) + RegisterSignal(current_bodypart.owner, COMSIG_LIVING_ELECTROCUTE_ACT, PROC_REF(owner_shocked)) //detach if we are shocked, not beneficial for the host but hey its a sideeffect + +/mob/living/basic/living_limb_flesh/proc/unregister_from_limb(mob/living/carbon/removing_owner) + UnregisterSignal(current_bodypart, COMSIG_BODYPART_REMOVED) + if(removing_owner) + UnregisterSignal(removing_owner, COMSIG_LIVING_ELECTROCUTE_ACT) + UnregisterSignal(removing_owner, COMSIG_LIVING_DEATH) + current_bodypart = null + /mob/living/basic/living_limb_flesh/proc/wake_up(atom/limb) + visible_message(span_warning("[src] begins flailing around!")) + Shake(6, 6, 0.5 SECONDS) ai_controller.set_ai_status(AI_STATUS_ON) forceMove(limb.drop_location()) - current_bodypart = null qdel(limb) - visible_message(span_warning("[src] begins flailing around!")) - Shake(6, 6, 0.5 SECONDS) + diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 0af9c50416525..70849c936cbcb 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1748,32 +1748,34 @@ GLOBAL_LIST_EMPTY(fire_appearances) /mob/living/proc/update_z(new_z) // 1+ to register, null to unregister - if (registered_z != new_z) - if (registered_z) - SSmobs.clients_by_zlevel[registered_z] -= src - if (client) - if (new_z) - //Figure out how many clients were here before - var/oldlen = SSmobs.clients_by_zlevel[new_z].len - SSmobs.clients_by_zlevel[new_z] += src - for (var/I in length(SSidlenpcpool.idle_mobs_by_zlevel[new_z]) to 1 step -1) //Backwards loop because we're removing (guarantees optimal rather than worst-case performance), it's fine to use .len here but doesn't compile on 511 - var/mob/living/simple_animal/SA = SSidlenpcpool.idle_mobs_by_zlevel[new_z][I] - if (SA) - if(oldlen == 0) - //Start AI idle if nobody else was on this z level before (mobs will switch off when this is the case) - SA.toggle_ai(AI_IDLE) - - //If they are also within a close distance ask the AI if it wants to wake up - if(get_dist(get_turf(src), get_turf(SA)) < MAX_SIMPLEMOB_WAKEUP_RANGE) - SA.consider_wakeup() // Ask the mob if it wants to turn on it's AI - //They should clean up in destroy, but often don't so we get them here - else - SSidlenpcpool.idle_mobs_by_zlevel[new_z] -= SA - - - registered_z = new_z - else - registered_z = null + if(registered_z == new_z) + return + if(registered_z) + SSmobs.clients_by_zlevel[registered_z] -= src + if(isnull(client)) + registered_z = null + return + + //Check the amount of clients exists on the Z level we're leaving from, + //this excludes us as we haven't added ourselves to the new z level yet. + var/old_level_new_clients = (registered_z ? SSmobs.clients_by_zlevel[registered_z].len : null) + //No one is left after we're gone, shut off inactive ones + if(registered_z && old_level_new_clients == 0) + for(var/datum/ai_controller/controller as anything in SSai_controllers.ai_controllers_by_zlevel[registered_z]) + controller.set_ai_status(AI_STATUS_OFF) + + //Check the amount of clients exists on the Z level we're moving towards, excluding ourselves. + var/new_level_old_clients = SSmobs.clients_by_zlevel[new_z].len + + registered_z = new_z + //We'll add ourselves to the list now so get_expected_ai_status() will know we're on the z level. + SSmobs.clients_by_zlevel[registered_z] += src + + if(new_level_old_clients == 0) //No one was here before, wake up all the AIs. + for (var/datum/ai_controller/controller as anything in SSai_controllers.ai_controllers_by_zlevel[new_z]) + //We don't set them directly on, for instances like AIs acting while dead and other cases that may exist in the future. + //This isn't a problem for AIs with a client since the client will prevent this from being called anyway. + controller.set_ai_status(controller.get_expected_ai_status()) /mob/living/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents) ..() diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index 1cde4d4a74058..1c9a67fafbe67 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -615,29 +615,6 @@ value = initial(search_objects) search_objects = value -/mob/living/simple_animal/hostile/consider_wakeup() - ..() - var/list/tlist - var/turf/T = get_turf(src) - - if (!T) - return - - if (!length(SSmobs.clients_by_zlevel[T.z])) // It's fine to use .len here but doesn't compile on 511 - toggle_ai(AI_Z_OFF) - return - - var/cheap_search = isturf(T) && !is_station_level(T.z) - if (cheap_search) - tlist = ListTargetsLazy(T.z) - else - tlist = ListTargets() - - if(AIStatus == AI_IDLE && FindTarget(tlist)) - if(cheap_search) //Try again with full effort - FindTarget() - toggle_ai(AI_ON) - /mob/living/simple_animal/hostile/proc/ListTargetsLazy(_Z)//Step 1, find out what we can see var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/vehicle/sealed/mecha)) . = list() diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 1c1ea138d23cf..47d3ddcf20f60 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -131,7 +131,7 @@ ///Played when someone punches the creature. var/attacked_sound = SFX_PUNCH - ///The Status of our AI, can be set to AI_ON (On, usual processing), AI_IDLE (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever), AI_Z_OFF (Temporarily off due to nonpresence of players). + ///The Status of our AI, can be set to AI_ON (On, usual processing), AI_IDLE (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever). var/AIStatus = AI_ON ///once we have become sentient, we can never go back. var/can_have_ai = TRUE @@ -221,10 +221,6 @@ GLOB.simple_animals[AIStatus] -= src SSnpcpool.currentrun -= src - var/turf/T = get_turf(src) - if (T && AIStatus == AI_Z_OFF) - SSidlenpcpool.idle_mobs_by_zlevel[T.z] -= src - return ..() /mob/living/simple_animal/examine(mob/user) @@ -514,29 +510,12 @@ return if (AIStatus != togglestatus) if (togglestatus > 0 && togglestatus < 5) - if (togglestatus == AI_Z_OFF || AIStatus == AI_Z_OFF) - var/turf/T = get_turf(src) - if (T) - if (AIStatus == AI_Z_OFF) - SSidlenpcpool.idle_mobs_by_zlevel[T.z] -= src - else - SSidlenpcpool.idle_mobs_by_zlevel[T.z] += src GLOB.simple_animals[AIStatus] -= src GLOB.simple_animals[togglestatus] += src AIStatus = togglestatus else stack_trace("Something attempted to set simple animals AI to an invalid state: [togglestatus]") -/mob/living/simple_animal/proc/consider_wakeup() - if (pulledby || shouldwakeup) - toggle_ai(AI_ON) - -/mob/living/simple_animal/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents) - ..() - if (old_turf && AIStatus == AI_Z_OFF) - SSidlenpcpool.idle_mobs_by_zlevel[old_turf.z] -= src - toggle_ai(initial(AIStatus)) - ///This proc is used for adding the swabbale element to mobs so that they are able to be biopsied and making sure holograpic and butter-based creatures don't yield viable cells samples. /mob/living/simple_animal/proc/add_cell_sample() return diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 7da01f047efe2..44d0db903550b 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -164,7 +164,7 @@ ///Allows a datum to intercept all click calls this mob is the source of var/datum/click_intercept - ///THe z level this mob is currently registered in + ///The z level this mob is currently registered in var/registered_z = null var/memory_throttle_time = 0 diff --git a/code/modules/unit_tests/limbsanity.dm b/code/modules/unit_tests/limbsanity.dm index 9988c7471e297..a92d481f556a5 100644 --- a/code/modules/unit_tests/limbsanity.dm +++ b/code/modules/unit_tests/limbsanity.dm @@ -2,13 +2,13 @@ /datum/unit_test/limbsanity/Run() for(var/path in subtypesof(/obj/item/bodypart) - list(/obj/item/bodypart/arm, /obj/item/bodypart/leg)) /// removes the abstract items. - var/obj/item/bodypart/part = new path(null) - if(part.is_dimorphic) - if(!icon_exists(UNLINT(part.should_draw_greyscale ? part.icon_greyscale : part.icon_static), "[part.limb_id]_[part.body_zone]_m")) + var/obj/item/bodypart/part = path + if(part::is_dimorphic) + if(!icon_exists(UNLINT(part::should_draw_greyscale ? part::icon_greyscale : part::icon_static), "[part::limb_id]_[part::body_zone]_m")) TEST_FAIL("[path] does not have a valid icon for male variants") - if(!icon_exists(UNLINT(part.should_draw_greyscale ? part.icon_greyscale : part.icon_static), "[part.limb_id]_[part.body_zone]_f")) + if(!icon_exists(UNLINT(part::should_draw_greyscale ? part::icon_greyscale : part::icon_static), "[part::limb_id]_[part::body_zone]_f")) TEST_FAIL("[path] does not have a valid icon for female variants") - else if(!icon_exists(UNLINT(part.should_draw_greyscale ? part.icon_greyscale : part.icon_static), "[part.limb_id]_[part.body_zone]")) + else if(!icon_exists(UNLINT(part::should_draw_greyscale ? part::icon_greyscale : part::icon_static), "[part::limb_id]_[part::body_zone]")) TEST_FAIL("[path] does not have a valid icon") /// Tests the height adjustment system which dynamically changes how much the chest, head, and arms of a carbon are adjusted upwards or downwards based on the length of their legs and chest. diff --git a/code/modules/unit_tests/mouse_bite_cable.dm b/code/modules/unit_tests/mouse_bite_cable.dm index 6d3150d279d6a..c2277fe4fd708 100644 --- a/code/modules/unit_tests/mouse_bite_cable.dm +++ b/code/modules/unit_tests/mouse_bite_cable.dm @@ -19,6 +19,8 @@ // Ai controlling processes expect a seconds_per_tick, supply a real-fake dt var/fake_dt = SSai_controllers.wait * 0.1 + // Set AI - AIs by default are off in z-levels with no client, we have to force it on. + biter.ai_controller.set_ai_status(AI_STATUS_ON) // Select behavior - this will queue finding the cable biter.ai_controller.SelectBehaviors(fake_dt) // Process behavior - this will execute the "locate the cable" behavior diff --git a/code/modules/unit_tests/suit_storage_icons.dm b/code/modules/unit_tests/suit_storage_icons.dm index 8c77b0524112b..12305e7abfc0b 100644 --- a/code/modules/unit_tests/suit_storage_icons.dm +++ b/code/modules/unit_tests/suit_storage_icons.dm @@ -10,18 +10,13 @@ continue wearable_item_paths |= item_path - for(var/clothing_path in (subtypesof(/obj/item/clothing) - typesof(/obj/item/clothing/head/mob_holder) - typesof(/obj/item/clothing/suit/space/santa))) //mob_holder is a psuedo abstract item. santa suit is a VERY SNOWFLAKE admin spawn suit that can hold /every/ possible item. - var/obj/item/clothing/spawned_item = new clothing_path - for(var/path in spawned_item.allowed) //find all usable suit storage stuff. + for(var/obj/item/clothing/clothing_path in (subtypesof(/obj/item/clothing) - typesof(/obj/item/clothing/head/mob_holder) - typesof(/obj/item/clothing/suit/space/santa))) //mob_holder is a psuedo abstract item. santa suit is a VERY SNOWFLAKE admin spawn suit that can hold /every/ possible item. + for(var/path in clothing_path::allowed) //find all usable suit storage stuff. wearable_item_paths |= path - qdel(spawned_item) - for(var/mod_path in subtypesof(/obj/item/mod/control)) - var/obj/item/mod/control/control_mod = new - for(var/path in control_mod.chestplate.allowed) + for(var/obj/item/mod/control/mod_path in subtypesof(/obj/item/mod/control)) + for(var/path in mod_path::chestplate::allowed) wearable_item_paths |= path - qdel(control_mod) - var/list/already_warned_icons = list() var/count = 1 //to be removed once the test goes live / into CI failure mode. diff --git a/tgstation.dme b/tgstation.dme index 9b3f3bcff0cac..1b1eb4995121f 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -640,7 +640,6 @@ #include "code\controllers\subsystem\garbage.dm" #include "code\controllers\subsystem\icon_smooth.dm" #include "code\controllers\subsystem\id_access.dm" -#include "code\controllers\subsystem\idlenpcpool.dm" #include "code\controllers\subsystem\init_profiler.dm" #include "code\controllers\subsystem\input.dm" #include "code\controllers\subsystem\ipintel.dm" From 1486acbd662c11122243467f125aa42ae854a67f Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sun, 7 Apr 2024 09:18:11 +1200 Subject: [PATCH 051/938] Automatic changelog for PR #82469 [ci skip] --- html/changelogs/AutoChangeLog-pr-82469.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82469.yml diff --git a/html/changelogs/AutoChangeLog-pr-82469.yml b/html/changelogs/AutoChangeLog-pr-82469.yml new file mode 100644 index 0000000000000..bc549fca827a5 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82469.yml @@ -0,0 +1,4 @@ +author: "JohnFulpWillard" +delete-after: True +changes: + - balance: "Basic mob AIs with no mobs on the Z level now stop." \ No newline at end of file From 9723b4b317a51859c46a8647d90d3028c97c5291 Mon Sep 17 00:00:00 2001 From: Jeremiah <42397676+jlsnow301@users.noreply.github.com> Date: Sat, 6 Apr 2024 14:18:49 -0700 Subject: [PATCH 052/938] Replaces even more deciseconds with SECONDS (#82438) ## About The Pull Request Using these search regexes: Ending in 0: `addtimer\((.*),\s?(\d{1,3})0\b\)` replacement: `addtimer($1, $2 SECONDS)` Two digit ending in odd: `addtimer\((.*), (\d)([1-9])\)$` replacement: `addtimer($1, $2.$3 SECONDS)` Single digit ending odd: `addtimer\((.*), ([1-9])\)$` replacement: `addtimer($1, 0.$2 SECONDS)` ## Why It's Good For The Game Code readability --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> --- code/controllers/subsystem/explosions.dm | 2 +- code/datums/brain_damage/creepy_trauma.dm | 2 +- code/datums/brain_damage/imaginary_friend.dm | 2 +- code/datums/brain_damage/mild.dm | 4 ++-- code/datums/brain_damage/phobia.dm | 2 +- code/datums/brain_damage/severe.dm | 4 ++-- code/datums/brain_damage/special.dm | 4 ++-- code/datums/brain_damage/split_personality.dm | 2 +- code/datums/components/boomerang.dm | 2 +- code/datums/components/fullauto.dm | 2 +- code/datums/components/plumbing/_plumbing.dm | 2 +- .../datums/diseases/advance/symptoms/cough.dm | 6 +++--- code/datums/diseases/advance/symptoms/heal.dm | 4 ++-- code/datums/dna.dm | 6 +++--- code/datums/martial/wrestling.dm | 2 +- code/datums/mutations/body.dm | 2 +- .../quirks/negative_quirks/social_anxiety.dm | 2 +- code/datums/status_effects/debuffs/debuffs.dm | 2 +- code/datums/wires/airalarm.dm | 4 ++-- code/datums/wires/autolathe.dm | 6 +++--- code/game/atom/atom_act.dm | 2 +- code/game/machinery/camera/camera.dm | 2 +- .../machinery/computer/arcade/orion_event.dm | 2 +- .../computer/prisoner/gulag_teleporter.dm | 2 +- .../machinery/porta_turret/portable_turret.dm | 8 ++++---- code/game/machinery/roulette_machine.dm | 4 ++-- code/game/machinery/sheetifier.dm | 2 +- code/game/machinery/suit_storage_unit.dm | 4 ++-- code/game/machinery/syndicatebomb.dm | 2 +- .../effect_system/effects_explosion.dm | 2 +- .../temporary_visuals/miscellaneous.dm | 2 +- code/game/objects/items/crab17.dm | 6 +++--- .../items/devices/radio/electropack.dm | 2 +- .../game/objects/items/devices/radio/radio.dm | 4 ++-- code/game/objects/items/devices/swapper.dm | 2 +- code/game/objects/items/extinguisher.dm | 2 +- code/game/objects/items/hand_items.dm | 6 +++--- code/game/objects/items/handcuffs.dm | 2 +- code/game/objects/items/rcd/RCD.dm | 2 +- code/game/objects/items/theft_tools.dm | 4 ++-- code/game/objects/items/toys.dm | 2 +- code/game/objects/items/virgin_mary.dm | 4 ++-- code/game/objects/items/wizard_weapons.dm | 2 +- code/game/objects/structures/aliens.dm | 2 +- .../structures/crates_lockers/crates/bins.dm | 2 +- code/game/objects/structures/false_walls.dm | 2 +- code/game/objects/structures/hivebot.dm | 2 +- code/game/objects/structures/holosign.dm | 4 ++-- .../structures/lavaland/necropolis_tendril.dm | 2 +- code/game/objects/structures/tables_racks.dm | 2 +- .../structures/transit_tubes/station.dm | 2 +- code/game/objects/structures/watercloset.dm | 2 +- code/modules/admin/verbs/adminhelp.dm | 2 +- code/modules/admin/verbs/highlander_datum.dm | 2 +- .../abductor/equipment/gear/abductor_items.dm | 2 +- .../abductor/equipment/glands/electric.dm | 2 +- .../abductor/equipment/glands/heal.dm | 6 +++--- .../abductor/equipment/glands/plasma.dm | 4 ++-- .../abductor/equipment/glands/quantum.dm | 2 +- .../antagonists/abductor/machinery/pad.dm | 4 ++-- code/modules/antagonists/blob/overmind.dm | 2 +- .../changeling/powers/biodegrade.dm | 8 ++++---- .../changeling/powers/tiny_prick.dm | 2 +- code/modules/antagonists/cult/cult_comms.dm | 2 +- code/modules/antagonists/cult/cult_items.dm | 2 +- code/modules/antagonists/cult/runes.dm | 2 +- .../antagonists/heretic/magic/cosmic_runes.dm | 2 +- .../heretic/magic/flesh_surgery.dm | 2 +- .../heretic/status_effects/buffs.dm | 2 +- .../antagonists/malf_ai/malf_ai_modules.dm | 2 +- .../nukeop/datums/operative_leader.dm | 2 +- .../wizard/grand_ritual/grand_rune.dm | 2 +- code/modules/assembly/doorcontrol.dm | 14 ++++++------- code/modules/assembly/flash.dm | 2 +- code/modules/awaymissions/away_props.dm | 2 +- code/modules/cargo/gondolapod.dm | 2 +- code/modules/client/client_colour.dm | 2 +- code/modules/clothing/clothing.dm | 2 +- code/modules/holodeck/computer.dm | 2 +- code/modules/holodeck/turfs.dm | 2 +- code/modules/interview/interview.dm | 4 ++-- .../ruins/lavalandruin_code/biodome_winter.dm | 2 +- code/modules/mining/aux_base.dm | 2 +- .../mining/equipment/wormhole_jaunter.dm | 2 +- code/modules/mining/ores_coins.dm | 2 +- code/modules/mob/dead/observer/observer.dm | 2 +- .../revenant/revenant_abilities.dm | 2 +- .../living/carbon/alien/special/facehugger.dm | 2 +- code/modules/mob/living/carbon/death.dm | 2 +- code/modules/mob/living/living_defense.dm | 4 ++-- code/modules/mob/living/silicon/ai/life.dm | 2 +- .../mob/living/silicon/robot/robot_defense.dm | 2 +- .../living/simple_animal/bot/SuperBeepsky.dm | 2 +- .../mob/living/simple_animal/bot/bot.dm | 6 +++--- .../mob/living/simple_animal/bot/secbot.dm | 2 +- .../hostile/megafauna/bubblegum.dm | 2 +- .../hostile/megafauna/hierophant.dm | 8 ++++---- .../hostile/mining_mobs/elites/elite.dm | 8 ++++---- .../mining_mobs/elites/goliath_broodmother.dm | 2 +- .../hostile/mining_mobs/elites/herald.dm | 20 +++++++++---------- .../hostile/mining_mobs/elites/legionnaire.dm | 4 ++-- .../hostile/mining_mobs/elites/pandora.dm | 6 +++--- .../simple_animal/hostile/retaliate/goose.dm | 6 +++--- code/modules/mob/mob.dm | 2 +- code/modules/paperwork/filingcabinet.dm | 2 +- code/modules/paperwork/ticketmachine.dm | 2 +- .../plumbing/plumbers/plumbing_buffer.dm | 2 +- code/modules/power/apc/apc_main.dm | 2 +- code/modules/power/apc/apc_tool_act.dm | 2 +- code/modules/power/power.dm | 2 +- .../power/singularity/containment_field.dm | 2 +- .../power/singularity/field_generator.dm | 10 +++++----- code/modules/power/tesla/energy_ball.dm | 2 +- .../guns/special/grenade_launcher.dm | 2 +- .../projectile/energy/net_snare.dm | 2 +- .../projectiles/projectile/energy/stun.dm | 2 +- .../chemistry/reagents/drug_reagents.dm | 2 +- .../chemistry/reagents/food_reagents.dm | 2 +- .../chemistry/reagents/other_reagents.dm | 2 +- code/modules/reagents/chemistry/recipes.dm | 4 ++-- .../chemistry/recipes/pyrotechnics.dm | 2 +- .../chemistry/recipes/slime_extracts.dm | 18 ++++++++--------- .../reagents/reagent_containers/pill.dm | 2 +- code/modules/research/experimentor.dm | 8 ++++---- .../xenobiology/crossbreeding/burning.dm | 2 +- .../xenobiology/crossbreeding/charged.dm | 4 ++-- .../xenobiology/crossbreeding/chilling.dm | 2 +- .../research/xenobiology/xenobiology.dm | 2 +- .../security_levels/keycard_authentication.dm | 4 ++-- code/modules/shuttle/special.dm | 2 +- code/modules/station_goals/bsa.dm | 2 +- .../internal/cyberimp/augments_chest.dm | 2 +- code/modules/surgery/tools.dm | 2 +- code/modules/tooltip/tooltip.dm | 2 +- code/modules/transport/transport_module.dm | 4 ++-- .../modules/vehicles/mecha/mech_fabricator.dm | 2 +- code/modules/vehicles/scooter.dm | 2 +- code/modules/vehicles/vehicle_actions.dm | 2 +- code/modules/vehicles/vehicle_key.dm | 4 ++-- 139 files changed, 220 insertions(+), 220 deletions(-) diff --git a/code/controllers/subsystem/explosions.dm b/code/controllers/subsystem/explosions.dm index f44482e8541ca..266da5f1a455c 100644 --- a/code/controllers/subsystem/explosions.dm +++ b/code/controllers/subsystem/explosions.dm @@ -154,7 +154,7 @@ SUBSYSTEM_DEF(explosions) else continue - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(wipe_color_and_text), wipe_colours), 100) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(wipe_color_and_text), wipe_colours), 10 SECONDS) /proc/wipe_color_and_text(list/atom/wiping) for(var/i in wiping) diff --git a/code/datums/brain_damage/creepy_trauma.dm b/code/datums/brain_damage/creepy_trauma.dm index 601b56c03bb51..742f1fe57e9db 100644 --- a/code/datums/brain_damage/creepy_trauma.dm +++ b/code/datums/brain_damage/creepy_trauma.dm @@ -77,7 +77,7 @@ return if(prob(25)) // 25% chances to be nervous and stutter. if(prob(50)) // 12.5% chance (previous check taken into account) of doing something suspicious. - addtimer(CALLBACK(src, PROC_REF(on_failed_social_interaction)), rand(1, 3) SECONDS) + addtimer(CALLBACK(src, PROC_REF(on_failed_social_interaction)), rand(1 SECONDS, 3 SECONDS)) else if(!owner.has_status_effect(/datum/status_effect/speech/stutter)) to_chat(owner, span_warning("Being near [obsession] makes you nervous and you begin to stutter...")) owner.set_stutter_if_lower(6 SECONDS) diff --git a/code/datums/brain_damage/imaginary_friend.dm b/code/datums/brain_damage/imaginary_friend.dm index 29cf637a86e95..18ca8172968d1 100644 --- a/code/datums/brain_damage/imaginary_friend.dm +++ b/code/datums/brain_damage/imaginary_friend.dm @@ -23,7 +23,7 @@ qdel(src) return if(!friend.client && friend_initialized) - addtimer(CALLBACK(src, PROC_REF(reroll_friend)), 600) + addtimer(CALLBACK(src, PROC_REF(reroll_friend)), 1 MINUTES) /datum/brain_trauma/special/imaginary_friend/on_death() ..() diff --git a/code/datums/brain_damage/mild.dm b/code/datums/brain_damage/mild.dm index b8f70f8a79f5c..21ecf1b520b8e 100644 --- a/code/datums/brain_damage/mild.dm +++ b/code/datums/brain_damage/mild.dm @@ -179,8 +179,8 @@ to_chat(owner, span_warning("[pick("You have a coughing fit!", "You can't stop coughing!")]")) owner.Immobilize(20) owner.emote("cough") - addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob/, emote), "cough"), 6) - addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob/, emote), "cough"), 12) + addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob/, emote), "cough"), 0.6 SECONDS) + addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob/, emote), "cough"), 1.2 SECONDS) owner.emote("cough") ..() diff --git a/code/datums/brain_damage/phobia.dm b/code/datums/brain_damage/phobia.dm index 725c92ab7e8d1..cf97c2e6e855c 100644 --- a/code/datums/brain_damage/phobia.dm +++ b/code/datums/brain_damage/phobia.dm @@ -93,7 +93,7 @@ return if(trigger_regex.Find(hearing_args[HEARING_RAW_MESSAGE]) != 0) - addtimer(CALLBACK(src, PROC_REF(freak_out), null, trigger_regex.group[2]), 10) //to react AFTER the chat message + addtimer(CALLBACK(src, PROC_REF(freak_out), null, trigger_regex.group[2]), 1 SECONDS) //to react AFTER the chat message hearing_args[HEARING_RAW_MESSAGE] = trigger_regex.Replace(hearing_args[HEARING_RAW_MESSAGE], "[span_phobia("$2")]$3") /datum/brain_trauma/mild/phobia/handle_speech(datum/source, list/speech_args) diff --git a/code/datums/brain_damage/severe.dm b/code/datums/brain_damage/severe.dm index 8754c87adc27c..f22b0ab44b331 100644 --- a/code/datums/brain_damage/severe.dm +++ b/code/datums/brain_damage/severe.dm @@ -202,7 +202,7 @@ to_chat(owner, span_warning("You feel really sick at the thought of being alone!")) else to_chat(owner, span_warning("You feel sick...")) - addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob/living/carbon, vomit), high_stress), 50) //blood vomit if high stress + addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob/living/carbon, vomit), high_stress), 5 SECONDS) //blood vomit if high stress if(2) if(high_stress) to_chat(owner, span_warning("You feel weak and scared! If only you weren't alone...")) @@ -309,7 +309,7 @@ var/regex/reg = new("(\\b[REGEX_QUOTE(trigger_phrase)]\\b)","ig") if(findtext(hearing_args[HEARING_RAW_MESSAGE], reg)) - addtimer(CALLBACK(src, PROC_REF(hypnotrigger)), 10) //to react AFTER the chat message + addtimer(CALLBACK(src, PROC_REF(hypnotrigger)), 1 SECONDS) //to react AFTER the chat message hearing_args[HEARING_RAW_MESSAGE] = reg.Replace(hearing_args[HEARING_RAW_MESSAGE], span_hypnophrase("*********")) /datum/brain_trauma/severe/hypnotic_trigger/proc/hypnotrigger() diff --git a/code/datums/brain_damage/special.dm b/code/datums/brain_damage/special.dm index 233713f45becf..bfbf2d84d73d8 100644 --- a/code/datums/brain_damage/special.dm +++ b/code/datums/brain_damage/special.dm @@ -220,7 +220,7 @@ to_chat(owner, span_warning("Your connection to [linked_target] suddenly feels extremely strong... you can feel it pulling you!")) owner.playsound_local(owner, 'sound/magic/lightning_chargeup.ogg', 75, FALSE) returning = TRUE - addtimer(CALLBACK(src, PROC_REF(snapback)), 100) + addtimer(CALLBACK(src, PROC_REF(snapback)), 10 SECONDS) /datum/brain_trauma/special/quantum_alignment/proc/snapback() returning = FALSE @@ -295,7 +295,7 @@ /datum/brain_trauma/special/death_whispers/proc/whispering() ADD_TRAIT(owner, TRAIT_SIXTHSENSE, TRAUMA_TRAIT) active = TRUE - addtimer(CALLBACK(src, PROC_REF(cease_whispering)), rand(50, 300)) + addtimer(CALLBACK(src, PROC_REF(cease_whispering)), rand(5 SECONDS, 30 SECONDS)) /datum/brain_trauma/special/death_whispers/proc/cease_whispering() REMOVE_TRAIT(owner, TRAIT_SIXTHSENSE, TRAUMA_TRAIT) diff --git a/code/datums/brain_damage/split_personality.dm b/code/datums/brain_damage/split_personality.dm index 3e2c91efb5da3..3e8bd52e5f94e 100644 --- a/code/datums/brain_damage/split_personality.dm +++ b/code/datums/brain_damage/split_personality.dm @@ -231,7 +231,7 @@ var/message = hearing_args[HEARING_RAW_MESSAGE] if(findtext(message, codeword)) hearing_args[HEARING_RAW_MESSAGE] = replacetext(message, codeword, span_warning("[codeword]")) - addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/brain_trauma/severe/split_personality, switch_personalities)), 10) + addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/brain_trauma/severe/split_personality, switch_personalities)), 1 SECONDS) /datum/brain_trauma/severe/split_personality/brainwashing/handle_speech(datum/source, list/speech_args) if(findtext(speech_args[SPEECH_MESSAGE], codeword)) diff --git a/code/datums/components/boomerang.dm b/code/datums/components/boomerang.dm index 8b35f171c28ae..13169e4d0cdd0 100644 --- a/code/datums/components/boomerang.dm +++ b/code/datums/components/boomerang.dm @@ -79,7 +79,7 @@ /datum/component/boomerang/proc/aerodynamic_swing(datum/thrownthing/throwingdatum, obj/item/true_parent) var/mob/thrown_by = true_parent.thrownby?.resolve() if(thrown_by) - addtimer(CALLBACK(true_parent, TYPE_PROC_REF(/atom/movable, throw_at), thrown_by, boomerang_throw_range, throwingdatum.speed, null, TRUE), 1) + addtimer(CALLBACK(true_parent, TYPE_PROC_REF(/atom/movable, throw_at), thrown_by, boomerang_throw_range, throwingdatum.speed, null, TRUE), 0.1 SECONDS) COOLDOWN_START(src, last_boomerang_throw, BOOMERANG_REBOUND_INTERVAL) var/mob/thrower = throwingdatum?.get_thrower() true_parent.visible_message(span_danger("[true_parent] is flying back at [thrower]!"), \ diff --git a/code/datums/components/fullauto.dm b/code/datums/components/fullauto.dm index d8484dc3a110b..33b713e8a57d4 100644 --- a/code/datums/components/fullauto.dm +++ b/code/datums/components/fullauto.dm @@ -310,7 +310,7 @@ if(istype(akimbo_gun) && weapon_weight < WEAPON_MEDIUM && allow_akimbo) if(akimbo_gun.weapon_weight < WEAPON_MEDIUM && akimbo_gun.can_trigger_gun(shooter)) bonus_spread = dual_wield_spread - addtimer(CALLBACK(akimbo_gun, TYPE_PROC_REF(/obj/item/gun, process_fire), target, shooter, TRUE, params, null, bonus_spread), 1) + addtimer(CALLBACK(akimbo_gun, TYPE_PROC_REF(/obj/item/gun, process_fire), target, shooter, TRUE, params, null, bonus_spread), 0.1 SECONDS) process_fire(target, shooter, TRUE, params, null, bonus_spread) #undef AUTOFIRE_MOUSEUP diff --git a/code/datums/components/plumbing/_plumbing.dm b/code/datums/components/plumbing/_plumbing.dm index 245f8f969a980..3e5528b1095a3 100644 --- a/code/datums/components/plumbing/_plumbing.dm +++ b/code/datums/components/plumbing/_plumbing.dm @@ -375,7 +375,7 @@ return // Defer to later frame because pixel_* is actually updated after all callbacks - addtimer(CALLBACK(parent_obj, TYPE_PROC_REF(/atom/, update_appearance)), 1) + addtimer(CALLBACK(parent_obj, TYPE_PROC_REF(/atom/, update_appearance)), 0.1 SECONDS) ///has one pipe input that only takes, example is manual output pipe /datum/component/plumbing/simple_demand diff --git a/code/datums/diseases/advance/symptoms/cough.dm b/code/datums/diseases/advance/symptoms/cough.dm index 4c2715668ba48..7368e99acc814 100644 --- a/code/datums/diseases/advance/symptoms/cough.dm +++ b/code/datums/diseases/advance/symptoms/cough.dm @@ -76,6 +76,6 @@ if(power >= 2 && prob(30)) to_chat(affected_mob, span_userdanger("[pick("You have a coughing fit!", "You can't stop coughing!")]")) affected_mob.Immobilize(20) - addtimer(CALLBACK(affected_mob, TYPE_PROC_REF(/mob/, emote), "cough"), 6) - addtimer(CALLBACK(affected_mob, TYPE_PROC_REF(/mob/, emote), "cough"), 12) - addtimer(CALLBACK(affected_mob, TYPE_PROC_REF(/mob/, emote), "cough"), 18) + addtimer(CALLBACK(affected_mob, TYPE_PROC_REF(/mob/, emote), "cough"), 0.6 SECONDS) + addtimer(CALLBACK(affected_mob, TYPE_PROC_REF(/mob/, emote), "cough"), 1.2 SECONDS) + addtimer(CALLBACK(affected_mob, TYPE_PROC_REF(/mob/, emote), "cough"), 1.8 SECONDS) diff --git a/code/datums/diseases/advance/symptoms/heal.dm b/code/datums/diseases/advance/symptoms/heal.dm index 8cdeceb586166..ae77ade0fb7d2 100644 --- a/code/datums/diseases/advance/symptoms/heal.dm +++ b/code/datums/diseases/advance/symptoms/heal.dm @@ -381,14 +381,14 @@ if(M.getBruteLoss() + M.getFireLoss() >= 70 && !active_coma) to_chat(M, span_warning("You feel yourself slip into a regenerative coma...")) active_coma = TRUE - addtimer(CALLBACK(src, PROC_REF(coma), M), 60) + addtimer(CALLBACK(src, PROC_REF(coma), M), 6 SECONDS) /datum/symptom/heal/coma/proc/coma(mob/living/M) if(QDELETED(M) || M.stat == DEAD) return M.fakedeath("regenerative_coma", !deathgasp) - addtimer(CALLBACK(src, PROC_REF(uncoma), M), 300) + addtimer(CALLBACK(src, PROC_REF(uncoma), M), 30 SECONDS) /datum/symptom/heal/coma/proc/uncoma(mob/living/M) if(QDELETED(M) || !active_coma) diff --git a/code/datums/dna.dm b/code/datums/dna.dm index 9126e40373684..4cc8a37d10325 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -922,10 +922,10 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) spawn_gibs() set_species(/datum/species/skeleton) if(prob(90)) - addtimer(CALLBACK(src, PROC_REF(death)), 30) + addtimer(CALLBACK(src, PROC_REF(death)), 3 SECONDS) if(5) to_chat(src, span_phobia("LOOK UP!")) - addtimer(CALLBACK(src, PROC_REF(something_horrible_mindmelt)), 30) + addtimer(CALLBACK(src, PROC_REF(something_horrible_mindmelt)), 3 SECONDS) if(6) slow_psykerize() @@ -937,4 +937,4 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) eyes.Remove(src) qdel(eyes) visible_message(span_notice("[src] looks up and their eyes melt away!"), span_userdanger("I understand now.")) - addtimer(CALLBACK(src, PROC_REF(adjustOrganLoss), ORGAN_SLOT_BRAIN, 200), 20) + addtimer(CALLBACK(src, PROC_REF(adjustOrganLoss), ORGAN_SLOT_BRAIN, 200), 2 SECONDS) diff --git a/code/datums/martial/wrestling.dm b/code/datums/martial/wrestling.dm index 23591852ec90b..6969c3eeb9ef4 100644 --- a/code/datums/martial/wrestling.dm +++ b/code/datums/martial/wrestling.dm @@ -358,7 +358,7 @@ If you make a derivative work from this code, you must include this notification attacker.setDir(turn(attacker.dir, 90)) attacker.forceMove(defender.loc) - addtimer(CALLBACK(src, PROC_REF(CheckStrikeTurf), attacker, T), 4) + addtimer(CALLBACK(src, PROC_REF(CheckStrikeTurf), attacker, T), 0.4 SECONDS) defender.visible_message(span_danger("[attacker] headbutts [defender]!"), \ span_userdanger("You're headbutted by [attacker]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker) diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm index 37f23218043af..de77727a3e490 100644 --- a/code/datums/mutations/body.dm +++ b/code/datums/mutations/body.dm @@ -20,7 +20,7 @@ owner.Unconscious(200 * GET_MUTATION_POWER(src)) owner.set_jitter(2000 SECONDS * GET_MUTATION_POWER(src)) //yes this number looks crazy but the jitter animations are amplified based on the duration. owner.add_mood_event("epilepsy", /datum/mood_event/epilepsy) - addtimer(CALLBACK(src, PROC_REF(jitter_less)), 90) + addtimer(CALLBACK(src, PROC_REF(jitter_less)), 9 SECONDS) /datum/mutation/human/epilepsy/proc/jitter_less() if(QDELETED(owner)) diff --git a/code/datums/quirks/negative_quirks/social_anxiety.dm b/code/datums/quirks/negative_quirks/social_anxiety.dm index 046ac4715f57c..2f28a646b320c 100644 --- a/code/datums/quirks/negative_quirks/social_anxiety.dm +++ b/code/datums/quirks/negative_quirks/social_anxiety.dm @@ -84,7 +84,7 @@ if(prob(85) || (istype(mind_check) && mind_check.mind)) return - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), quirk_holder, span_smallnotice("You make eye contact with [A].")), 3) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), quirk_holder, span_smallnotice("You make eye contact with [A].")), 0.3 SECONDS) /datum/quirk/social_anxiety/proc/eye_contact(datum/source, mob/living/other_mob, triggering_examiner) SIGNAL_HANDLER diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm index 0b5e09267504d..b2a37356e53c0 100644 --- a/code/datums/status_effects/debuffs/debuffs.dm +++ b/code/datums/status_effects/debuffs/debuffs.dm @@ -601,7 +601,7 @@ // The brain trauma itself does its own set of logging, but this is the only place the source of the hypnosis phrase can be found. hearing_speaker.log_message("hypnotised [key_name(C)] with the phrase '[hearing_args[HEARING_RAW_MESSAGE]]'", LOG_ATTACK, color="red") C.log_message("has been hypnotised by the phrase '[hearing_args[HEARING_RAW_MESSAGE]]' spoken by [key_name(hearing_speaker)]", LOG_VICTIM, color="orange", log_globally = FALSE) - addtimer(CALLBACK(C, TYPE_PROC_REF(/mob/living/carbon, gain_trauma), /datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY, hearing_args[HEARING_RAW_MESSAGE]), 10) + addtimer(CALLBACK(C, TYPE_PROC_REF(/mob/living/carbon, gain_trauma), /datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY, hearing_args[HEARING_RAW_MESSAGE]), 1 SECONDS) addtimer(CALLBACK(C, TYPE_PROC_REF(/mob/living, Stun), 60, TRUE, TRUE), 15) //Take some time to think about it qdel(src) diff --git a/code/datums/wires/airalarm.dm b/code/datums/wires/airalarm.dm index 2dc3244e9cac6..00291609871c3 100644 --- a/code/datums/wires/airalarm.dm +++ b/code/datums/wires/airalarm.dm @@ -34,13 +34,13 @@ if(!A.shorted) A.shorted = TRUE A.update_appearance() - addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/airalarm, reset), wire), 1200) + addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/airalarm, reset), wire), 2 MINUTES) if(WIRE_IDSCAN) // Toggle lock. A.locked = !A.locked if(WIRE_AI) // Disable AI control for a while. if(!A.aidisabled) A.aidisabled = TRUE - addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/airalarm, reset), wire), 100) + addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/airalarm, reset), wire), 10 SECONDS) if(WIRE_PANIC) // Toggle panic siphon. if(!A.shorted) if(istype(A.selected_mode, /datum/air_alarm_mode/filtering)) diff --git a/code/datums/wires/autolathe.dm b/code/datums/wires/autolathe.dm index ca55dad954f6d..75c3a3687602f 100644 --- a/code/datums/wires/autolathe.dm +++ b/code/datums/wires/autolathe.dm @@ -29,13 +29,13 @@ switch(wire) if(WIRE_HACK) A.adjust_hacked(!A.hacked) - addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/autolathe, reset), wire), 60) + addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/autolathe, reset), wire), 6 SECONDS) if(WIRE_SHOCK) A.shocked = !A.shocked - addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/autolathe, reset), wire), 60) + addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/autolathe, reset), wire), 6 SECONDS) if(WIRE_DISABLE) A.disabled = !A.disabled - addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/autolathe, reset), wire), 60) + addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/autolathe, reset), wire), 6 SECONDS) /datum/wires/autolathe/on_cut(wire, mend, source) var/obj/machinery/autolathe/A = holder diff --git a/code/game/atom/atom_act.dm b/code/game/atom/atom_act.dm index ae7cd5a3eb287..7d05a6aaa6822 100644 --- a/code/game/atom/atom_act.dm +++ b/code/game/atom/atom_act.dm @@ -119,7 +119,7 @@ /atom/proc/hitby(atom/movable/hitting_atom, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum) SEND_SIGNAL(src, COMSIG_ATOM_HITBY, hitting_atom, skipcatch, hitpush, blocked, throwingdatum) if(density && !has_gravity(hitting_atom)) //thrown stuff bounces off dense stuff in no grav, unless the thrown stuff ends up inside what it hit(embedding, bola, etc...). - addtimer(CALLBACK(src, PROC_REF(hitby_react), hitting_atom), 2) + addtimer(CALLBACK(src, PROC_REF(hitby_react), hitting_atom), 0.2 SECONDS) /** * We have have actually hit the passed in atom diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index 28dcf2de5e8c9..ed896cc7576cb 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -355,7 +355,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) change_msg = "reactivates" triggerCameraAlarm() if(!QDELETED(src)) //We'll be doing it anyway in destroy - addtimer(CALLBACK(src, PROC_REF(cancelCameraAlarm)), 100) + addtimer(CALLBACK(src, PROC_REF(cancelCameraAlarm)), 10 SECONDS) if(displaymessage) if(user) visible_message(span_danger("[user] [change_msg] [src]!")) diff --git a/code/game/machinery/computer/arcade/orion_event.dm b/code/game/machinery/computer/arcade/orion_event.dm index f1050e9a8e276..7ab2f3b98b3b0 100644 --- a/code/game/machinery/computer/arcade/orion_event.dm +++ b/code/game/machinery/computer/arcade/orion_event.dm @@ -438,7 +438,7 @@ game.say("A miniature black hole suddenly appears in front of [game], devouring [gamer] alive!") gamer.Stun(200, ignore_canstun = TRUE) //you can't run :^) var/black_hole = new /obj/singularity/orion(gamer.loc) - addtimer(CALLBACK(game, TYPE_PROC_REF(/atom/movable, say), "[black_hole] winks out, just as suddenly as it appeared."), 50) + addtimer(CALLBACK(game, TYPE_PROC_REF(/atom/movable, say), "[black_hole] winks out, just as suddenly as it appeared."), 5 SECONDS) QDEL_IN(black_hole, 5 SECONDS) #define BUTTON_DOCK "Dock" diff --git a/code/game/machinery/computer/prisoner/gulag_teleporter.dm b/code/game/machinery/computer/prisoner/gulag_teleporter.dm index 45124eefeee9f..f3dacdb8e205f 100644 --- a/code/game/machinery/computer/prisoner/gulag_teleporter.dm +++ b/code/game/machinery/computer/prisoner/gulag_teleporter.dm @@ -114,7 +114,7 @@ if("teleport") if(!teleporter || !beacon) return - addtimer(CALLBACK(src, PROC_REF(teleport), usr), 5) + addtimer(CALLBACK(src, PROC_REF(teleport), usr), 0.5 SECONDS) return TRUE /obj/machinery/computer/prisoner/gulag_teleporter_computer/proc/scan_machinery() diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm index f318d93ecbd92..d4cf080da699a 100644 --- a/code/game/machinery/porta_turret/portable_turret.dm +++ b/code/game/machinery/porta_turret/portable_turret.dm @@ -409,7 +409,7 @@ DEFINE_BITFIELD(turret_flags, list( spark_system.start() if(on && !(turret_flags & TURRET_FLAG_SHOOT_ALL_REACT) && !(obj_flags & EMAGGED)) turret_flags |= TURRET_FLAG_SHOOT_ALL_REACT - addtimer(CALLBACK(src, PROC_REF(reset_attacked)), 60) + addtimer(CALLBACK(src, PROC_REF(reset_attacked)), 6 SECONDS) /obj/machinery/porta_turret/proc/reset_attacked() turret_flags &= ~TURRET_FLAG_SHOOT_ALL_REACT @@ -827,9 +827,9 @@ DEFINE_BITFIELD(turret_flags, list( if(target) setDir(get_dir(base, target))//even if you can't shoot, follow the target shootAt(target) - addtimer(CALLBACK(src, PROC_REF(shootAt), target), 5) - addtimer(CALLBACK(src, PROC_REF(shootAt), target), 10) - addtimer(CALLBACK(src, PROC_REF(shootAt), target), 15) + addtimer(CALLBACK(src, PROC_REF(shootAt), target), 0.5 SECONDS) + addtimer(CALLBACK(src, PROC_REF(shootAt), target), 1 SECONDS) + addtimer(CALLBACK(src, PROC_REF(shootAt), target), 1.5 SECONDS) return TRUE /obj/machinery/porta_turret/ai diff --git a/code/game/machinery/roulette_machine.dm b/code/game/machinery/roulette_machine.dm index f2e6ddd819532..ba4a5136a8978 100644 --- a/code/game/machinery/roulette_machine.dm +++ b/code/game/machinery/roulette_machine.dm @@ -224,7 +224,7 @@ playsound(src, 'sound/machines/roulettewheel.ogg', 50) addtimer(CALLBACK(src, PROC_REF(finish_play), player_id, bet_type, bet_amount, payout, rolled_number), 34) //4 deciseconds more so the animation can play - addtimer(CALLBACK(src, PROC_REF(finish_play_animation)), 30) + addtimer(CALLBACK(src, PROC_REF(finish_play_animation)), 3 SECONDS) use_energy(active_power_usage) @@ -448,7 +448,7 @@ return loc.visible_message(span_warning("\The [src] begins to beep loudly!")) used = TRUE - addtimer(CALLBACK(src, PROC_REF(launch_payload)), 40) + addtimer(CALLBACK(src, PROC_REF(launch_payload)), 4 SECONDS) /obj/item/roulette_wheel_beacon/proc/launch_payload() var/obj/structure/closet/supplypod/centcompod/toLaunch = new() diff --git a/code/game/machinery/sheetifier.dm b/code/game/machinery/sheetifier.dm index d9619092af6f3..bff759a6c7274 100644 --- a/code/game/machinery/sheetifier.dm +++ b/code/game/machinery/sheetifier.dm @@ -50,7 +50,7 @@ var/mutable_appearance/processing_overlay = mutable_appearance(icon, "processing") processing_overlay.color = last_inserted_material.color flick_overlay_static(processing_overlay, src, 64) - addtimer(CALLBACK(src, PROC_REF(finish_processing)), 64) + addtimer(CALLBACK(src, PROC_REF(finish_processing)), 6.4 SECONDS) /obj/machinery/sheetifier/proc/finish_processing() busy_processing = FALSE diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index 9ccecc436bf7f..d95668975f5b7 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -501,7 +501,7 @@ if(iscarbon(mob_occupant) && mob_occupant.stat < UNCONSCIOUS) //Awake, organic and screaming mob_occupant.emote("scream") - addtimer(CALLBACK(src, PROC_REF(cook)), 50) + addtimer(CALLBACK(src, PROC_REF(cook)), 5 SECONDS) else uv_cycles = initial(uv_cycles) uv = FALSE @@ -608,7 +608,7 @@ if(locked) visible_message(span_notice("You see [user] kicking against the doors of [src]!"), \ span_notice("You start kicking against the doors...")) - addtimer(CALLBACK(src, PROC_REF(resist_open), user), 300) + addtimer(CALLBACK(src, PROC_REF(resist_open), user), 30 SECONDS) else open_machine() dump_inventory_contents() diff --git a/code/game/machinery/syndicatebomb.dm b/code/game/machinery/syndicatebomb.dm index ebe24b449748b..693668e9e8900 100644 --- a/code/game/machinery/syndicatebomb.dm +++ b/code/game/machinery/syndicatebomb.dm @@ -484,7 +484,7 @@ chem_splash(get_turf(src), reagents, spread_range, list(reactants), temp_boost) // Detonate it again in one second, until it's out of juice. - addtimer(CALLBACK(src, PROC_REF(detonate)), 10) + addtimer(CALLBACK(src, PROC_REF(detonate)), 1 SECONDS) // If it's not a time release bomb, do normal explosion diff --git a/code/game/objects/effects/effect_system/effects_explosion.dm b/code/game/objects/effects/effect_system/effects_explosion.dm index 231feb2ec3dfc..32be64c9353f4 100644 --- a/code/game/objects/effects/effect_system/effects_explosion.dm +++ b/code/game/objects/effects/effect_system/effects_explosion.dm @@ -63,4 +63,4 @@ /datum/effect_system/explosion/smoke/start() ..() - addtimer(CALLBACK(src, PROC_REF(create_smoke)), 5) + addtimer(CALLBACK(src, PROC_REF(create_smoke)), 0.5 SECONDS) diff --git a/code/game/objects/effects/temporary_visuals/miscellaneous.dm b/code/game/objects/effects/temporary_visuals/miscellaneous.dm index 06b4a8e4b0721..4c8ce41debfee 100644 --- a/code/game/objects/effects/temporary_visuals/miscellaneous.dm +++ b/code/game/objects/effects/temporary_visuals/miscellaneous.dm @@ -555,7 +555,7 @@ mouse_opacity = MOUSE_OPACITY_TRANSPARENT obj_flags &= ~CAN_BE_HIT icon_state = "rcd_end" - addtimer(CALLBACK(src, PROC_REF(end)), 15) + addtimer(CALLBACK(src, PROC_REF(end)), 1.5 SECONDS) /obj/effect/constructing_effect/proc/end() qdel(src) diff --git a/code/game/objects/items/crab17.dm b/code/game/objects/items/crab17.dm index 1e43197c47ef2..25582bc918971 100644 --- a/code/game/objects/items/crab17.dm +++ b/code/game/objects/items/crab17.dm @@ -106,7 +106,7 @@ add_overlay("flaps") add_overlay("hatch") add_overlay("legs_retracted") - addtimer(CALLBACK(src, PROC_REF(startUp)), 50) + addtimer(CALLBACK(src, PROC_REF(startUp)), 5 SECONDS) QDEL_IN(src, 8 MINUTES) //Self-destruct after 8 min ADD_TRAIT(SSeconomy, TRAIT_MARKET_CRASHING, REF(src)) @@ -202,7 +202,7 @@ if (account) // get_bank_account() may return FALSE account.transfer_money(B, amount, "?VIVA¿: !LA CRABBE¡") B.bank_card_talk("You have lost [percentage_lost * 100]% of your funds! A spacecoin credit deposit machine is located at: [get_area(src)].") - addtimer(CALLBACK(src, PROC_REF(dump)), 150) //Drain every 15 seconds + addtimer(CALLBACK(src, PROC_REF(dump)), 15 SECONDS) //Drain every 15 seconds /obj/structure/checkoutmachine/process() var/anydir = pick(GLOB.cardinals) @@ -238,7 +238,7 @@ /obj/effect/dumpeet_target/Initialize(mapload, user) . = ..() bogdanoff = user - addtimer(CALLBACK(src, PROC_REF(startLaunch)), 100) + addtimer(CALLBACK(src, PROC_REF(startLaunch)), 10 SECONDS) sound_to_playing_players('sound/items/dump_it.ogg', 20) deadchat_broadcast("Protocol CRAB-17 has been activated. A space-coin market has been launched at the station!", turf_target = get_turf(src), message_type=DEADCHAT_ANNOUNCEMENT) diff --git a/code/game/objects/items/devices/radio/electropack.dm b/code/game/objects/items/devices/radio/electropack.dm index 426e673437ef5..af19c6cd4f5da 100644 --- a/code/game/objects/items/devices/radio/electropack.dm +++ b/code/game/objects/items/devices/radio/electropack.dm @@ -64,7 +64,7 @@ if(shock_cooldown) return shock_cooldown = TRUE - addtimer(VARSET_CALLBACK(src, shock_cooldown, FALSE), 100) + addtimer(VARSET_CALLBACK(src, shock_cooldown, FALSE), 10 SECONDS) var/mob/living/L = loc step(L, pick(GLOB.cardinals)) diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index bf662fcc1b90a..ffb4f486cb89d 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -363,7 +363,7 @@ // Non-subspace radios will check in a couple of seconds, and if the signal // was never received, send a mundane broadcast (no headsets). - addtimer(CALLBACK(src, PROC_REF(backup_transmission), signal), 20) + addtimer(CALLBACK(src, PROC_REF(backup_transmission), signal), 2 SECONDS) /obj/item/radio/proc/backup_transmission(datum/signal/subspace/vocal/signal) var/turf/T = get_turf(src) @@ -543,7 +543,7 @@ for (var/ch_name in channels) channels[ch_name] = 0 set_on(FALSE) - addtimer(CALLBACK(src, PROC_REF(end_emp_effect), curremp), 200) + addtimer(CALLBACK(src, PROC_REF(end_emp_effect), curremp), 20 SECONDS) /obj/item/radio/suicide_act(mob/living/user) user.visible_message(span_suicide("[user] starts bouncing [src] off [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!")) diff --git a/code/game/objects/items/devices/swapper.dm b/code/game/objects/items/devices/swapper.dm index 1022e72cc443d..ea7d06f9596f0 100644 --- a/code/game/objects/items/devices/swapper.dm +++ b/code/game/objects/items/devices/swapper.dm @@ -55,7 +55,7 @@ var/mob/holder = linked_swapper.loc to_chat(holder, span_notice("[linked_swapper] starts buzzing.")) next_use = world.time + cooldown //only the one used goes on cooldown - addtimer(CALLBACK(src, PROC_REF(swap), user), 25) + addtimer(CALLBACK(src, PROC_REF(swap), user), 2.5 SECONDS) /obj/item/swapper/examine(mob/user) . = ..() diff --git a/code/game/objects/items/extinguisher.dm b/code/game/objects/items/extinguisher.dm index b0189a0c4ecef..c949380d743fe 100644 --- a/code/game/objects/items/extinguisher.dm +++ b/code/game/objects/items/extinguisher.dm @@ -215,7 +215,7 @@ if(user.buckled && isobj(user.buckled) && !user.buckled.anchored) var/obj/B = user.buckled var/movementdirection = REVERSE_DIR(direction) - addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/item/extinguisher, move_chair), B, movementdirection), 1) + addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/item/extinguisher, move_chair), B, movementdirection), 0.1 SECONDS) else user.newtonian_move(REVERSE_DIR(direction)) diff --git a/code/game/objects/items/hand_items.dm b/code/game/objects/items/hand_items.dm index 2255afe10541c..57c240e427327 100644 --- a/code/game/objects/items/hand_items.dm +++ b/code/game/objects/items/hand_items.dm @@ -41,7 +41,7 @@ if(!istype(sucker) || !in_range(owner, sucker)) return - addtimer(CALLBACK(src, PROC_REF(waitASecond), owner, sucker), 4) + addtimer(CALLBACK(src, PROC_REF(waitASecond), owner, sucker), 0.4 SECONDS) /// Stage 2: Fear sets in /obj/item/hand_item/circlegame/proc/waitASecond(mob/living/owner, mob/living/sucker) @@ -50,10 +50,10 @@ if(owner == sucker) // big mood to_chat(owner, span_danger("Wait a second... you just looked at your own [src.name]!")) - addtimer(CALLBACK(src, PROC_REF(selfGottem), owner), 10) + addtimer(CALLBACK(src, PROC_REF(selfGottem), owner), 1 SECONDS) else to_chat(sucker, span_danger("Wait a second... was that a-")) - addtimer(CALLBACK(src, PROC_REF(GOTTEM), owner, sucker), 6) + addtimer(CALLBACK(src, PROC_REF(GOTTEM), owner, sucker), 0.6 SECONDS) /// Stage 3A: We face our own failures /obj/item/hand_item/circlegame/proc/selfGottem(mob/living/owner) diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm index e00a2aa61f3b4..8db6b3556a07c 100644 --- a/code/game/objects/items/handcuffs.dm +++ b/code/game/objects/items/handcuffs.dm @@ -485,7 +485,7 @@ /obj/item/restraints/legcuffs/beartrap/energy/Initialize(mapload) . = ..() - addtimer(CALLBACK(src, PROC_REF(dissipate)), 100) + addtimer(CALLBACK(src, PROC_REF(dissipate)), 10 SECONDS) /** * Handles energy snares disappearing diff --git a/code/game/objects/items/rcd/RCD.dm b/code/game/objects/items/rcd/RCD.dm index b4e5ffb35ee18..91b51053b0ea0 100644 --- a/code/game/objects/items/rcd/RCD.dm +++ b/code/game/objects/items/rcd/RCD.dm @@ -418,7 +418,7 @@ buzz loudly!","[src] begins \ vibrating violently!") // 5 seconds to get rid of it - addtimer(CALLBACK(src, PROC_REF(detonate_pulse_explode)), 50) + addtimer(CALLBACK(src, PROC_REF(detonate_pulse_explode)), 5 SECONDS) /obj/item/construction/rcd/proc/detonate_pulse_explode() explosion(src, light_impact_range = 3, flame_range = 1, flash_range = 1) diff --git a/code/game/objects/items/theft_tools.dm b/code/game/objects/items/theft_tools.dm index e695dedbca3de..5f0404c342350 100644 --- a/code/game/objects/items/theft_tools.dm +++ b/code/game/objects/items/theft_tools.dm @@ -61,7 +61,7 @@ core = ncore icon_state = "core_container_loaded" to_chat(user, span_warning("Container is sealing...")) - addtimer(CALLBACK(src, PROC_REF(seal)), 50) + addtimer(CALLBACK(src, PROC_REF(seal)), 5 SECONDS) return TRUE /obj/item/nuke_core_container/proc/seal() @@ -236,7 +236,7 @@ T.icon_state = "supermatter_tongs" icon_state = "core_container_loaded" to_chat(user, span_warning("Container is sealing...")) - addtimer(CALLBACK(src, PROC_REF(seal)), 50) + addtimer(CALLBACK(src, PROC_REF(seal)), 5 SECONDS) return TRUE /obj/item/nuke_core_container/supermatter/seal() diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 1d2b0bba7b134..67192b829a74d 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -555,7 +555,7 @@ update_appearance() playsound(src, 'sound/effects/pope_entry.ogg', 100) Rumble() - addtimer(CALLBACK(src, PROC_REF(stopRumble)), 600) + addtimer(CALLBACK(src, PROC_REF(stopRumble)), 60 SECONDS) else to_chat(user, span_warning("[src] is already active!")) diff --git a/code/game/objects/items/virgin_mary.dm b/code/game/objects/items/virgin_mary.dm index 7c3c305858c1c..b0446abadbdfd 100644 --- a/code/game/objects/items/virgin_mary.dm +++ b/code/game/objects/items/virgin_mary.dm @@ -47,8 +47,8 @@ /obj/item/virgin_mary/suicide_act(mob/living/user) user.visible_message(span_suicide("[user] starts saying their Hail Mary's at a terrifying pace! It looks like [user.p_theyre()] trying to enter the afterlife!")) user.say("Hail Mary, full of grace, the Lord is with thee. Blessed are thou amongst women, and blessed is the fruit of thy womb, Jesus. Holy Mary, mother of God, pray for us sinners, now and at the hour of our death. Amen. ", forced = /obj/item/virgin_mary) - addtimer(CALLBACK(src, PROC_REF(manual_suicide), user), 75) - addtimer(CALLBACK(user, TYPE_PROC_REF(/atom/movable, say), "O my Mother, preserve me this day from mortal sin..."), 50) + addtimer(CALLBACK(src, PROC_REF(manual_suicide), user), 7.5 SECONDS) + addtimer(CALLBACK(user, TYPE_PROC_REF(/atom/movable, say), "O my Mother, preserve me this day from mortal sin..."), 5 SECONDS) return MANUAL_SUICIDE /obj/item/virgin_mary/proc/manual_suicide(mob/living/user) diff --git a/code/game/objects/items/wizard_weapons.dm b/code/game/objects/items/wizard_weapons.dm index 533ae118dc2a0..8c2677d3ee35b 100644 --- a/code/game/objects/items/wizard_weapons.dm +++ b/code/game/objects/items/wizard_weapons.dm @@ -73,7 +73,7 @@ playsound(user, 'sound/weapons/marauder.ogg', 50, TRUE) var/turf/target = get_turf(A) vortex(target,user) - addtimer(CALLBACK(src, PROC_REF(recharge)), 100) + addtimer(CALLBACK(src, PROC_REF(recharge)), 10 SECONDS) return . /obj/item/mjollnir diff --git a/code/game/objects/structures/aliens.dm b/code/game/objects/structures/aliens.dm index c5a69bfa3290c..6d8e8ca701e3a 100644 --- a/code/game/objects/structures/aliens.dm +++ b/code/game/objects/structures/aliens.dm @@ -414,7 +414,7 @@ status = BURSTING proximity_monitor.set_range(0) flick("egg_opening", src) - addtimer(CALLBACK(src, PROC_REF(finish_bursting), kill), 15) + addtimer(CALLBACK(src, PROC_REF(finish_bursting), kill), 1.5 SECONDS) /obj/structure/alien/egg/proc/finish_bursting(kill = TRUE) status = BURST diff --git a/code/game/objects/structures/crates_lockers/crates/bins.dm b/code/game/objects/structures/crates_lockers/crates/bins.dm index 6b865b845861f..a686d53f392c6 100644 --- a/code/game/objects/structures/crates_lockers/crates/bins.dm +++ b/code/game/objects/structures/crates_lockers/crates/bins.dm @@ -47,7 +47,7 @@ /obj/structure/closet/crate/bin/proc/do_animate() playsound(loc, open_sound, 15, TRUE, -3) flick(base_icon_state + "_animate", src) - addtimer(CALLBACK(src, PROC_REF(do_close)), 11) + addtimer(CALLBACK(src, PROC_REF(do_close)), 1.1 SECONDS) /obj/structure/closet/crate/bin/proc/do_close() playsound(loc, close_sound, 15, TRUE, -3) diff --git a/code/game/objects/structures/false_walls.dm b/code/game/objects/structures/false_walls.dm index bfae47065354c..e9f9eb5d11e8a 100644 --- a/code/game/objects/structures/false_walls.dm +++ b/code/game/objects/structures/false_walls.dm @@ -49,7 +49,7 @@ opening = FALSE return update_appearance() - addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/structure/falsewall, toggle_open)), 5) + addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/structure/falsewall, toggle_open)), 0.5 SECONDS) /obj/structure/falsewall/proc/toggle_open() if(!QDELETED(src)) diff --git a/code/game/objects/structures/hivebot.dm b/code/game/objects/structures/hivebot.dm index ba371f8d65836..838113cab8c38 100644 --- a/code/game/objects/structures/hivebot.dm +++ b/code/game/objects/structures/hivebot.dm @@ -15,7 +15,7 @@ smoke.start() visible_message(span_boldannounce("[src] warps in!")) playsound(src.loc, 'sound/effects/empulse.ogg', 25, TRUE) - addtimer(CALLBACK(src, PROC_REF(warpbots)), rand(10, 600)) + addtimer(CALLBACK(src, PROC_REF(warpbots)), rand(1 SECONDS, 1 MINUTES)) /obj/structure/hivebot_beacon/proc/warpbots() icon_state = "def_radar" diff --git a/code/game/objects/structures/holosign.dm b/code/game/objects/structures/holosign.dm index a1a3adf325145..1d7fc470afff8 100644 --- a/code/game/objects/structures/holosign.dm +++ b/code/game/objects/structures/holosign.dm @@ -215,7 +215,7 @@ var/mob/living/M = user M.electrocute_act(15,"Energy Barrier") shockcd = TRUE - addtimer(CALLBACK(src, PROC_REF(cooldown)), 5) + addtimer(CALLBACK(src, PROC_REF(cooldown)), 0.5 SECONDS) /obj/structure/holosign/barrier/cyborg/hacked/Bumped(atom/movable/AM) if(shockcd) @@ -227,4 +227,4 @@ var/mob/living/M = AM M.electrocute_act(15,"Energy Barrier") shockcd = TRUE - addtimer(CALLBACK(src, PROC_REF(cooldown)), 5) + addtimer(CALLBACK(src, PROC_REF(cooldown)), 0.5 SECONDS) diff --git a/code/game/objects/structures/lavaland/necropolis_tendril.dm b/code/game/objects/structures/lavaland/necropolis_tendril.dm index 357fdaa967705..58308b9b9cf2b 100644 --- a/code/game/objects/structures/lavaland/necropolis_tendril.dm +++ b/code/game/objects/structures/lavaland/necropolis_tendril.dm @@ -91,7 +91,7 @@ GLOBAL_LIST_INIT(tendrils, list()) visible_message(span_boldannounce("The tendril writhes in fury as the earth around it begins to crack and break apart! Get back!")) balloon_alert_to_viewers("interact to grab loot before collapse!", vision_distance = 7) playsound(loc,'sound/effects/tendril_destroyed.ogg', 200, FALSE, 50, TRUE, TRUE) - addtimer(CALLBACK(src, PROC_REF(collapse)), 50) + addtimer(CALLBACK(src, PROC_REF(collapse)), 5 SECONDS) /obj/effect/collapse/examine(mob/user) var/list/examine_messages = ..() diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 755927e319142..922c7df3ad995 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -436,7 +436,7 @@ return // Don't break if they're just flying past if(AM.throwing) - addtimer(CALLBACK(src, PROC_REF(throw_check), AM), 5) + addtimer(CALLBACK(src, PROC_REF(throw_check), AM), 0.5 SECONDS) else check_break(AM) diff --git a/code/game/objects/structures/transit_tubes/station.dm b/code/game/objects/structures/transit_tubes/station.dm index 0765273ebf463..3eeb81cb8aca5 100644 --- a/code/game/objects/structures/transit_tubes/station.dm +++ b/code/game/objects/structures/transit_tubes/station.dm @@ -153,7 +153,7 @@ /obj/structure/transit_tube/station/pod_stopped(obj/structure/transit_tube_pod/pod, from_dir) pod_moving = TRUE - addtimer(CALLBACK(src, PROC_REF(start_stopped), pod), 5) + addtimer(CALLBACK(src, PROC_REF(start_stopped), pod), 0.5 SECONDS) /obj/structure/transit_tube/station/proc/start_stopped(obj/structure/transit_tube_pod/pod) if(QDELETED(pod)) diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index da084945b98d0..559e2dd78089b 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -252,7 +252,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/urinal, 32) /obj/item/food/urinalcake/attack_self(mob/living/user) user.visible_message(span_notice("[user] squishes [src]!"), span_notice("You squish [src]."), "You hear a squish.") icon_state = "urinalcake_squish" - addtimer(VARSET_CALLBACK(src, icon_state, "urinalcake"), 8) + addtimer(VARSET_CALLBACK(src, icon_state, "urinalcake"), 0.8 SECONDS) /obj/item/bikehorn/rubberducky/plasticducky name = "plastic ducky" diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index 6c6dc4335c7ac..8d09e28ec7cb7 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -500,7 +500,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) state = AHELP_RESOLVED GLOB.ahelp_tickets.ListInsert(src) - addtimer(CALLBACK(initiator, TYPE_PROC_REF(/client, giveadminhelpverb)), 50) + addtimer(CALLBACK(initiator, TYPE_PROC_REF(/client, giveadminhelpverb)), 5 SECONDS) AddInteraction("Resolved by [key_name].", player_message = "Ticket resolved!") to_chat(initiator, span_adminhelp("Your ticket has been resolved by an admin. The Adminhelp verb will be returned to you shortly."), confidential = TRUE) diff --git a/code/modules/admin/verbs/highlander_datum.dm b/code/modules/admin/verbs/highlander_datum.dm index ad8f75bca82b1..de7e4918fc00b 100644 --- a/code/modules/admin/verbs/highlander_datum.dm +++ b/code/modules/admin/verbs/highlander_datum.dm @@ -36,7 +36,7 @@ GLOBAL_DATUM(highlander_controller, /datum/highlander_controller) robot.gib() continue robot.make_scottish() - addtimer(CALLBACK(SSshuttle.emergency, TYPE_PROC_REF(/obj/docking_port/mobile/emergency, request), null, 1), 50) + addtimer(CALLBACK(SSshuttle.emergency, TYPE_PROC_REF(/obj/docking_port/mobile/emergency, request), null, 1), 5 SECONDS) /datum/highlander_controller/Destroy(force) . = ..() diff --git a/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm b/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm index 1ec8940394fdf..07e8dad2aa659 100644 --- a/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm +++ b/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm @@ -523,7 +523,7 @@ Congratulations! You are now trained for invasive xenobiology research!"} user.visible_message(span_notice("[user] places down [src] and activates it."), span_notice("You place down [src] and activate it.")) user.dropItemToGround(src) playsound(src, 'sound/machines/terminal_alert.ogg', 50) - addtimer(CALLBACK(src, PROC_REF(try_spawn_machine)), 30) + addtimer(CALLBACK(src, PROC_REF(try_spawn_machine)), 3 SECONDS) /obj/item/abductor_machine_beacon/proc/try_spawn_machine() var/viable = FALSE diff --git a/code/modules/antagonists/abductor/equipment/glands/electric.dm b/code/modules/antagonists/abductor/equipment/glands/electric.dm index a5ec2cfde2153..72b2c1e14ad1c 100644 --- a/code/modules/antagonists/abductor/equipment/glands/electric.dm +++ b/code/modules/antagonists/abductor/equipment/glands/electric.dm @@ -19,7 +19,7 @@ owner.visible_message(span_danger("[owner]'s skin starts emitting electric arcs!"),\ span_warning("You feel electric energy building up inside you!")) playsound(get_turf(owner), SFX_SPARKS, 100, TRUE, -1, SHORT_RANGE_SOUND_EXTRARANGE) - addtimer(CALLBACK(src, PROC_REF(zap)), rand(30, 100)) + addtimer(CALLBACK(src, PROC_REF(zap)), rand(3 SECONDS, 10 SECONDS)) /obj/item/organ/internal/heart/gland/electric/proc/zap() tesla_zap(source = owner, zap_range = 4, power = 8e3, cutoff = 1e3, zap_flags = ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE | ZAP_MOB_STUN) diff --git a/code/modules/antagonists/abductor/equipment/glands/heal.dm b/code/modules/antagonists/abductor/equipment/glands/heal.dm index 683cb33fc9adb..7f4462377654c 100644 --- a/code/modules/antagonists/abductor/equipment/glands/heal.dm +++ b/code/modules/antagonists/abductor/equipment/glands/heal.dm @@ -159,7 +159,7 @@ else to_chat(owner, span_warning("You feel a weird rumble behind your eye sockets...")) - addtimer(CALLBACK(src, PROC_REF(finish_replace_eyes)), rand(100, 200)) + addtimer(CALLBACK(src, PROC_REF(finish_replace_eyes)), rand(10 SECONDS, 20 SECONDS)) /obj/item/organ/internal/heart/gland/heal/proc/finish_replace_eyes() var/eye_type = /obj/item/organ/internal/eyes @@ -177,7 +177,7 @@ else to_chat(owner, span_warning("You feel a weird tingle in your [parse_zone(body_zone)]... even if you don't have one.")) - addtimer(CALLBACK(src, PROC_REF(finish_replace_limb), body_zone), rand(150, 300)) + addtimer(CALLBACK(src, PROC_REF(finish_replace_limb), body_zone), rand(15 SECONDS, 30 SECONDS)) /obj/item/organ/internal/heart/gland/heal/proc/finish_replace_limb(body_zone) owner.visible_message(span_warning("With a loud snap, [owner]'s [parse_zone(body_zone)] rapidly grows back from [owner.p_their()] body!"), @@ -207,7 +207,7 @@ if(owner.reagents.has_reagent(R.type)) keep_going = TRUE if(keep_going) - addtimer(CALLBACK(src, PROC_REF(keep_replacing_blood)), 30) + addtimer(CALLBACK(src, PROC_REF(keep_replacing_blood)), 3 SECONDS) /obj/item/organ/internal/heart/gland/heal/proc/replace_chest(obj/item/bodypart/chest/chest) if(!IS_ORGANIC_LIMB(chest)) diff --git a/code/modules/antagonists/abductor/equipment/glands/plasma.dm b/code/modules/antagonists/abductor/equipment/glands/plasma.dm index 0d709579cc8c5..76cd806bb42b8 100644 --- a/code/modules/antagonists/abductor/equipment/glands/plasma.dm +++ b/code/modules/antagonists/abductor/equipment/glands/plasma.dm @@ -9,8 +9,8 @@ /obj/item/organ/internal/heart/gland/plasma/activate() to_chat(owner, span_warning("You feel bloated.")) - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), owner, span_userdanger("A massive stomachache overcomes you.")), 150) - addtimer(CALLBACK(src, PROC_REF(vomit_plasma)), 200) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), owner, span_userdanger("A massive stomachache overcomes you.")), 15 SECONDS) + addtimer(CALLBACK(src, PROC_REF(vomit_plasma)), 20 SECONDS) /obj/item/organ/internal/heart/gland/plasma/proc/vomit_plasma() if(!owner) diff --git a/code/modules/antagonists/abductor/equipment/glands/quantum.dm b/code/modules/antagonists/abductor/equipment/glands/quantum.dm index d32304a5987e8..a2a4a9149e741 100644 --- a/code/modules/antagonists/abductor/equipment/glands/quantum.dm +++ b/code/modules/antagonists/abductor/equipment/glands/quantum.dm @@ -15,7 +15,7 @@ if(!iscarbon(M)) continue entangled_mob = M - addtimer(CALLBACK(src, PROC_REF(quantum_swap)), rand(600, 2400)) + addtimer(CALLBACK(src, PROC_REF(quantum_swap)), rand(1 MINUTES, 4 MINUTES)) return /obj/item/organ/internal/heart/gland/quantum/proc/quantum_swap() diff --git a/code/modules/antagonists/abductor/machinery/pad.dm b/code/modules/antagonists/abductor/machinery/pad.dm index 6f2dc48a67213..1610d9a6cff33 100644 --- a/code/modules/antagonists/abductor/machinery/pad.dm +++ b/code/modules/antagonists/abductor/machinery/pad.dm @@ -38,7 +38,7 @@ /obj/machinery/abductor/pad/proc/MobToLoc(place,mob/living/target) new /obj/effect/temp_visual/teleport_abductor(place) - addtimer(CALLBACK(src, PROC_REF(doMobToLoc), place, target), 80) + addtimer(CALLBACK(src, PROC_REF(doMobToLoc), place, target), 8 SECONDS) /obj/machinery/abductor/pad/proc/doPadToLoc(place) flick("alien-pad", src) @@ -48,7 +48,7 @@ /obj/machinery/abductor/pad/proc/PadToLoc(place) new /obj/effect/temp_visual/teleport_abductor(place) - addtimer(CALLBACK(src, PROC_REF(doPadToLoc), place), 80) + addtimer(CALLBACK(src, PROC_REF(doPadToLoc), place), 8 SECONDS) /obj/effect/temp_visual/teleport_abductor name = "Huh" diff --git a/code/modules/antagonists/blob/overmind.dm b/code/modules/antagonists/blob/overmind.dm index 401daa97ac5b2..929a3b5c4ffd4 100644 --- a/code/modules/antagonists/blob/overmind.dm +++ b/code/modules/antagonists/blob/overmind.dm @@ -153,7 +153,7 @@ GLOBAL_LIST_EMPTY(blob_nodes) SSsecurity_level.set_level(SEC_LEVEL_DELTA) max_blob_points = INFINITY blob_points = INFINITY - addtimer(CALLBACK(src, PROC_REF(victory)), 450) + addtimer(CALLBACK(src, PROC_REF(victory)), 45 SECONDS) else if(!free_strain_rerolls && (last_reroll_time + BLOB_POWER_REROLL_FREE_TIME 0) illusions-- - addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/item/shield/mirror, readd)), 450) + addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/item/shield/mirror, readd)), 45 SECONDS) if(prob(60)) var/mob/living/simple_animal/hostile/illusion/M = new(owner.loc) M.faction = list(FACTION_CULT) diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm index 6fe9cf472989b..d42ace3f4cd93 100644 --- a/code/modules/antagonists/cult/runes.dm +++ b/code/modules/antagonists/cult/runes.dm @@ -187,7 +187,7 @@ structure_check() searches for nearby cultist structures required for the invoca var/oldcolor = color color = rgb(255, 0, 0) animate(src, color = oldcolor, time = 5) - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 5) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 0.5 SECONDS) //Malformed Rune: This forms if a rune is not drawn correctly. Invoking it does nothing but hurt the user. /obj/effect/rune/malformed diff --git a/code/modules/antagonists/heretic/magic/cosmic_runes.dm b/code/modules/antagonists/heretic/magic/cosmic_runes.dm index 4af3b94b44f34..207b60ae9393a 100644 --- a/code/modules/antagonists/heretic/magic/cosmic_runes.dm +++ b/code/modules/antagonists/heretic/magic/cosmic_runes.dm @@ -113,7 +113,7 @@ var/oldcolor = rgb(255, 255, 255) color = rgb(150, 50, 200) animate(src, color = oldcolor, time = 5) - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 5) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 0.5 SECONDS) /// For linking a new rune /obj/effect/cosmic_rune/proc/link_rune(datum/weakref/new_rune) diff --git a/code/modules/antagonists/heretic/magic/flesh_surgery.dm b/code/modules/antagonists/heretic/magic/flesh_surgery.dm index 12b3fcfbcaf33..898b1a63fa66c 100644 --- a/code/modules/antagonists/heretic/magic/flesh_surgery.dm +++ b/code/modules/antagonists/heretic/magic/flesh_surgery.dm @@ -211,7 +211,7 @@ carbon_victim.emote("scream") // We need to wait for the spell to actually finish casting to put the organ in their hands, hence, 1 ms timer. - addtimer(CALLBACK(caster, TYPE_PROC_REF(/mob, put_in_hands), picked_organ), 1) + addtimer(CALLBACK(caster, TYPE_PROC_REF(/mob, put_in_hands), picked_organ), 0.1 SECONDS) return TRUE /// Extra checks ran while we're extracting an organ to make sure we can continue to do. diff --git a/code/modules/antagonists/heretic/status_effects/buffs.dm b/code/modules/antagonists/heretic/status_effects/buffs.dm index 607f485ff6421..1ec0df389fcc9 100644 --- a/code/modules/antagonists/heretic/status_effects/buffs.dm +++ b/code/modules/antagonists/heretic/status_effects/buffs.dm @@ -192,7 +192,7 @@ qdel(to_remove) - addtimer(TRAIT_CALLBACK_REMOVE(source, TRAIT_BEING_BLADE_SHIELDED, type), 1) + addtimer(TRAIT_CALLBACK_REMOVE(source, TRAIT_BEING_BLADE_SHIELDED, type), 0.1 SECONDS) return SUCCESSFUL_BLOCK diff --git a/code/modules/antagonists/malf_ai/malf_ai_modules.dm b/code/modules/antagonists/malf_ai/malf_ai_modules.dm index ab88a6f02fc3d..75c3c98e3f614 100644 --- a/code/modules/antagonists/malf_ai/malf_ai_modules.dm +++ b/code/modules/antagonists/malf_ai/malf_ai_modules.dm @@ -686,7 +686,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) I.loc = T client.images += I I.icon_state = "[success ? "green" : "red"]Overlay" //greenOverlay and redOverlay for success and failure respectively - addtimer(CALLBACK(src, PROC_REF(remove_transformer_image), client, I, T), 30) + addtimer(CALLBACK(src, PROC_REF(remove_transformer_image), client, I, T), 3 SECONDS) if(!success) to_chat(src, span_warning("[alert_msg]")) return success diff --git a/code/modules/antagonists/nukeop/datums/operative_leader.dm b/code/modules/antagonists/nukeop/datums/operative_leader.dm index 76ca635158b16..0c583bfe794b0 100644 --- a/code/modules/antagonists/nukeop/datums/operative_leader.dm +++ b/code/modules/antagonists/nukeop/datums/operative_leader.dm @@ -35,7 +35,7 @@ var/obj/item/war_declaration = new challengeitem(leader.drop_location()) leader.put_in_hands(war_declaration) nuke_team.war_button_ref = WEAKREF(war_declaration) - addtimer(CALLBACK(src, PROC_REF(nuketeam_name_assign)), 1) + addtimer(CALLBACK(src, PROC_REF(nuketeam_name_assign)), 0.1 SECONDS) /datum/antagonist/nukeop/leader/proc/nuketeam_name_assign() if(!nuke_team) diff --git a/code/modules/antagonists/wizard/grand_ritual/grand_rune.dm b/code/modules/antagonists/wizard/grand_ritual/grand_rune.dm index f75da5f855742..79364a80a198a 100644 --- a/code/modules/antagonists/wizard/grand_ritual/grand_rune.dm +++ b/code/modules/antagonists/wizard/grand_ritual/grand_rune.dm @@ -187,7 +187,7 @@ tear_reality() SEND_SIGNAL(src, COMSIG_GRAND_RUNE_COMPLETE, cheese_sacrificed) flick("[icon_state]_activate", src) - addtimer(CALLBACK(src, PROC_REF(remove_rune)), 6) + addtimer(CALLBACK(src, PROC_REF(remove_rune)), 0.6 SECONDS) SSblackbox.record_feedback("amount", "grand_runes_invoked", 1) /obj/effect/grand_rune/proc/remove_rune() diff --git a/code/modules/assembly/doorcontrol.dm b/code/modules/assembly/doorcontrol.dm index f5f33afa83c34..31584976cedf3 100644 --- a/code/modules/assembly/doorcontrol.dm +++ b/code/modules/assembly/doorcontrol.dm @@ -32,7 +32,7 @@ if(openclose == null || !sync_doors) openclose = M.density INVOKE_ASYNC(M, openclose ? TYPE_PROC_REF(/obj/machinery/door/poddoor, open) : TYPE_PROC_REF(/obj/machinery/door/poddoor, close)) - addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 10) + addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 1 SECONDS) /obj/item/assembly/control/curtain name = "curtain controller" @@ -53,7 +53,7 @@ if(openclose == null || !sync_doors) openclose = M.density INVOKE_ASYNC(M, openclose ? TYPE_PROC_REF(/obj/structure/curtain/cloth/fancy/mechanical, open) : TYPE_PROC_REF(/obj/structure/curtain/cloth/fancy/mechanical, close)) - addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 5) + addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 0.5 SECONDS) /obj/item/assembly/control/airlock @@ -101,7 +101,7 @@ for(var/D in open_or_close) INVOKE_ASYNC(D, doors_need_closing ? TYPE_PROC_REF(/obj/machinery/door/airlock, close) : TYPE_PROC_REF(/obj/machinery/door/airlock, open)) - addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 10) + addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 1 SECONDS) /obj/item/assembly/control/massdriver @@ -130,7 +130,7 @@ if (M.id == src.id) INVOKE_ASYNC(M, TYPE_PROC_REF(/obj/machinery/door/poddoor, close)) - addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 10) + addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 1 SECONDS) /obj/item/assembly/control/igniter @@ -149,7 +149,7 @@ if(M.id == src.id) INVOKE_ASYNC(M, TYPE_PROC_REF(/obj/machinery/igniter, toggle)) - addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 30) + addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 3 SECONDS) /obj/item/assembly/control/flasher name = "flasher controller" @@ -163,7 +163,7 @@ if(M.id == src.id) INVOKE_ASYNC(M, TYPE_PROC_REF(/obj/machinery/flasher, flash)) - addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 50) + addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 5 SECONDS) /obj/item/assembly/control/crematorium @@ -178,4 +178,4 @@ if (C.id == id) C.cremate(usr) - addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 50) + addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 5 SECONDS) diff --git a/code/modules/assembly/flash.dm b/code/modules/assembly/flash.dm index 659bcec50cf97..b81eb26e7fae9 100644 --- a/code/modules/assembly/flash.dm +++ b/code/modules/assembly/flash.dm @@ -43,7 +43,7 @@ flashing = flash . = ..() if(flash) - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/, update_icon)), 5) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/, update_icon)), 0.5 SECONDS) holder?.update_icon(updates) /obj/item/assembly/flash/update_overlays() diff --git a/code/modules/awaymissions/away_props.dm b/code/modules/awaymissions/away_props.dm index 1ed0a1ec0ffdb..22d9f532efcbd 100644 --- a/code/modules/awaymissions/away_props.dm +++ b/code/modules/awaymissions/away_props.dm @@ -96,7 +96,7 @@ obj_flags |= BLOCK_Z_OUT_DOWN | BLOCK_Z_IN_UP SET_PLANE_IMPLICIT(src, ABOVE_LIGHTING_PLANE) //What matters it's one above openspace, so our animation is not dependant on what's there. Up to revision with 513 animate(src,alpha = talpha,time = 10) - addtimer(CALLBACK(src, PROC_REF(reset_plane)),10) + addtimer(CALLBACK(src, PROC_REF(reset_plane)), 1 SECONDS) if(hidden) update_openspace() var/turf/T = get_turf(src) diff --git a/code/modules/cargo/gondolapod.dm b/code/modules/cargo/gondolapod.dm index 36ceff8ad5114..2491084ab7039 100644 --- a/code/modules/cargo/gondolapod.dm +++ b/code/modules/cargo/gondolapod.dm @@ -67,7 +67,7 @@ opened = TRUE layer = initial(layer) update_appearance() - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/, setClosed)), 50) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/, setClosed)), 5 SECONDS) /mob/living/simple_animal/pet/gondola/gondolapod/setClosed() opened = FALSE diff --git a/code/modules/client/client_colour.dm b/code/modules/client/client_colour.dm index 6fa3bb36f3fb8..1209b5c35823c 100644 --- a/code/modules/client/client_colour.dm +++ b/code/modules/client/client_colour.dm @@ -228,7 +228,7 @@ /datum/client_colour/bloodlust/New(mob/owner) ..() if(owner) - addtimer(CALLBACK(src, PROC_REF(update_colour), list(1,0,0,0.8,0.2,0, 0.8,0,0.2,0.1,0,0), 10, SINE_EASING|EASE_OUT), 1) + addtimer(CALLBACK(src, PROC_REF(update_colour), list(1,0,0,0.8,0.2,0, 0.8,0,0.2,0.1,0,0), 10, SINE_EASING|EASE_OUT), 0.1 SECONDS) /datum/client_colour/rave priority = PRIORITY_LOW diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 7722cf791a6db..587e9c6628714 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -516,7 +516,7 @@ BLIND // can't see anything return ..() if(damage_flag == BOMB) //so the shred survives potential turf change from the explosion. - addtimer(CALLBACK(src, PROC_REF(_spawn_shreds)), 1) + addtimer(CALLBACK(src, PROC_REF(_spawn_shreds)), 0.1 SECONDS) deconstruct(FALSE) if(damage_flag == CONSUME) //This allows for moths to fully consume clothing, rather than damaging it like other sources like brute var/turf/current_position = get_turf(src) diff --git a/code/modules/holodeck/computer.dm b/code/modules/holodeck/computer.dm index f75a1329246b3..7b4b23a313b82 100644 --- a/code/modules/holodeck/computer.dm +++ b/code/modules/holodeck/computer.dm @@ -380,7 +380,7 @@ GLOBAL_LIST_INIT(typecache_holodeck_linked_floorcheck_ok, typecacheof(list(/turf if(toggleOn) if(last_program && (last_program != offline_program)) - addtimer(CALLBACK(src, PROC_REF(load_program), last_program, TRUE), 25) + addtimer(CALLBACK(src, PROC_REF(load_program), last_program, TRUE), 2.5 SECONDS) active = TRUE else last_program = program diff --git a/code/modules/holodeck/turfs.dm b/code/modules/holodeck/turfs.dm index 15a82c5aa5577..3e54c13410604 100644 --- a/code/modules/holodeck/turfs.dm +++ b/code/modules/holodeck/turfs.dm @@ -158,7 +158,7 @@ /turf/open/floor/holofloor/carpet/Initialize(mapload) . = ..() - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/, update_appearance)), 1) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/, update_appearance)), 0.1 SECONDS) /turf/open/floor/holofloor/carpet/update_icon(updates=ALL) . = ..() diff --git a/code/modules/interview/interview.dm b/code/modules/interview/interview.dm index 923d11fc76f4a..a1703b9c06974 100644 --- a/code/modules/interview/interview.dm +++ b/code/modules/interview/interview.dm @@ -58,7 +58,7 @@ SEND_SOUND(owner, sound('sound/effects/adminhelp.ogg')) to_chat(owner, "-- Interview Update --" \ + "\n[span_adminsay("Your interview was approved, you will now be reconnected in 5 seconds.")]", confidential = TRUE) - addtimer(CALLBACK(src, PROC_REF(reconnect_owner)), 50) + addtimer(CALLBACK(src, PROC_REF(reconnect_owner)), 5 SECONDS) /** * Denies the interview and adds the owner to the cooldown for new interviews. @@ -73,7 +73,7 @@ GLOB.interviews.cooldown_ckeys |= owner_ckey log_admin_private("[key_name(denied_by)] has denied interview #[id] for [owner_ckey][!owner ? "(DC)": ""].") message_admins(span_adminnotice("[key_name(denied_by)] has denied [link_self()] for [owner_ckey][!owner ? "(DC)": ""].")) - addtimer(CALLBACK(GLOB.interviews, TYPE_PROC_REF(/datum/interview_manager, release_from_cooldown), owner_ckey), 180) + addtimer(CALLBACK(GLOB.interviews, TYPE_PROC_REF(/datum/interview_manager, release_from_cooldown), owner_ckey), 18 SECONDS) if (owner) SEND_SOUND(owner, sound('sound/effects/adminhelp.ogg')) to_chat(owner, "-- Interview Update --" \ diff --git a/code/modules/mapfluff/ruins/lavalandruin_code/biodome_winter.dm b/code/modules/mapfluff/ruins/lavalandruin_code/biodome_winter.dm index 770d787f8ad54..150b4c5e44b73 100644 --- a/code/modules/mapfluff/ruins/lavalandruin_code/biodome_winter.dm +++ b/code/modules/mapfluff/ruins/lavalandruin_code/biodome_winter.dm @@ -32,7 +32,7 @@ if(ismovable(hit_atom) && !caught && (!thrown_by || thrown_by && COOLDOWN_FINISHED(src, freeze_cooldown))) freeze_hit_atom(hit_atom) if(thrown_by && !caught) - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/movable, throw_at), thrown_by, throw_range+2, throw_speed, null, TRUE), 1) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/movable, throw_at), thrown_by, throw_range+2, throw_speed, null, TRUE), 0.1 SECONDS) /obj/item/freeze_cube/proc/freeze_hit_atom(atom/movable/hit_atom) playsound(src, 'sound/effects/glassbr3.ogg', 50, TRUE) diff --git a/code/modules/mining/aux_base.dm b/code/modules/mining/aux_base.dm index 88f8634fabf95..a1503b7f63420 100644 --- a/code/modules/mining/aux_base.dm +++ b/code/modules/mining/aux_base.dm @@ -355,7 +355,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/auxiliary_base, 32) return anti_spam_cd = 1 - addtimer(CALLBACK(src, PROC_REF(clear_cooldown)), 50) + addtimer(CALLBACK(src, PROC_REF(clear_cooldown)), 5 SECONDS) var/turf/landing_spot = get_turf(src) diff --git a/code/modules/mining/equipment/wormhole_jaunter.dm b/code/modules/mining/equipment/wormhole_jaunter.dm index b4165a13cd0af..a19d0a7242083 100644 --- a/code/modules/mining/equipment/wormhole_jaunter.dm +++ b/code/modules/mining/equipment/wormhole_jaunter.dm @@ -114,4 +114,4 @@ L.Paralyze(60) if(ishuman(L)) shake_camera(L, 20, 1) - addtimer(CALLBACK(L, TYPE_PROC_REF(/mob/living/carbon, vomit)), 20) + addtimer(CALLBACK(L, TYPE_PROC_REF(/mob/living/carbon, vomit)), 2 SECONDS) diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm index 4fe26281b10a7..e94b8d981ffeb 100644 --- a/code/modules/mining/ores_coins.dm +++ b/code/modules/mining/ores_coins.dm @@ -453,7 +453,7 @@ GLOBAL_LIST_INIT(sand_recipes, list(\ if (!attack_self(user)) user.visible_message(span_suicide("[user] couldn't flip \the [src]!")) return SHAME - addtimer(CALLBACK(src, PROC_REF(manual_suicide), user), 10)//10 = time takes for flip animation + addtimer(CALLBACK(src, PROC_REF(manual_suicide), user), 1 SECONDS)//10 = time takes for flip animation return MANUAL_SUICIDE_NONLETHAL /obj/item/coin/proc/manual_suicide(mob/living/user) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 0f7d5b16cce55..095d73bf3c3c1 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -161,7 +161,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) var/old_color = color color = COLOR_CULT_RED animate(src, color = old_color, time = 10, flags = ANIMATION_PARALLEL) - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 10) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 1 SECONDS) /mob/dead/observer/Destroy() if(data_huds_on) diff --git a/code/modules/mob/living/basic/space_fauna/revenant/revenant_abilities.dm b/code/modules/mob/living/basic/space_fauna/revenant/revenant_abilities.dm index b7bbcad2df0c0..9f565dab11253 100644 --- a/code/modules/mob/living/basic/space_fauna/revenant/revenant_abilities.dm +++ b/code/modules/mob/living/basic/space_fauna/revenant/revenant_abilities.dm @@ -123,7 +123,7 @@ light_sparks.set_up(4, 0, light) light_sparks.start() new /obj/effect/temp_visual/revenant(get_turf(light)) - addtimer(CALLBACK(src, PROC_REF(overload_shock), light, caster), 20) + addtimer(CALLBACK(src, PROC_REF(overload_shock), light, caster), 2 SECONDS) /datum/action/cooldown/spell/aoe/revenant/overload/proc/overload_shock(obj/machinery/light/to_shock, mob/living/basic/revenant/caster) flick("[to_shock.base_state]2", to_shock) diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm index cffdd1f648fbb..d068610b28f7a 100644 --- a/code/modules/mob/living/carbon/alien/special/facehugger.dm +++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm @@ -108,7 +108,7 @@ return if(stat == CONSCIOUS) icon_state = "[base_icon_state]_thrown" - addtimer(CALLBACK(src, PROC_REF(clear_throw_icon_state)), 15) + addtimer(CALLBACK(src, PROC_REF(clear_throw_icon_state)), 1.5 SECONDS) /obj/item/clothing/mask/facehugger/proc/clear_throw_icon_state() if(icon_state == "[base_icon_state]_thrown") diff --git a/code/modules/mob/living/carbon/death.dm b/code/modules/mob/living/carbon/death.dm index eafb6f8ba22e1..41a958518c597 100644 --- a/code/modules/mob/living/carbon/death.dm +++ b/code/modules/mob/living/carbon/death.dm @@ -19,7 +19,7 @@ BT.on_death() /mob/living/carbon/proc/inflate_gib() // Plays an animation that makes mobs appear to inflate before finally gibbing - addtimer(CALLBACK(src, PROC_REF(gib), DROP_BRAIN|DROP_ORGANS|DROP_ITEMS), 25) + addtimer(CALLBACK(src, PROC_REF(gib), DROP_BRAIN|DROP_ORGANS|DROP_ITEMS), 2.5 SECONDS) var/matrix/M = matrix() M.Scale(1.8, 1.2) animate(src, time = 40, transform = M, easing = SINE_EASING) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index ec366f0f26ce8..31f7d1cb8df0f 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -545,8 +545,8 @@ if((GLOB.cult_narsie.souls == GLOB.cult_narsie.soul_goal) && (GLOB.cult_narsie.resolved == FALSE)) GLOB.cult_narsie.resolved = TRUE sound_to_playing_players('sound/machines/alarm.ogg') - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cult_ending_helper), CULT_VICTORY_MASS_CONVERSION), 120) - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(ending_helper)), 270) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cult_ending_helper), CULT_VICTORY_MASS_CONVERSION), 12 SECONDS) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(ending_helper)), 27 SECONDS) if(client) make_new_construct(/mob/living/basic/construct/harvester, src, cultoverride = TRUE) else diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm index 331291db4ea2f..76f5c2eec9331 100644 --- a/code/modules/mob/living/silicon/ai/life.dm +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -164,4 +164,4 @@ adjust_temp_blindness(2 SECONDS) update_sight() to_chat(src, span_alert("You've lost power!")) - addtimer(CALLBACK(src, PROC_REF(start_RestorePowerRoutine)), 20) + addtimer(CALLBACK(src, PROC_REF(start_RestorePowerRoutine)), 2 SECONDS) diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm index f6b94c9f15c6b..70e7d8b34ab25 100644 --- a/code/modules/mob/living/silicon/robot/robot_defense.dm +++ b/code/modules/mob/living/silicon/robot/robot_defense.dm @@ -227,7 +227,7 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real return spark_system.start() step_away(src, user, 15) - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step_away), src, get_turf(user), 15), 3) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step_away), src, get_turf(user), 15), 0.3 SECONDS) /mob/living/silicon/robot/get_shove_flags(mob/living/shover, obj/item/weapon) . = ..() diff --git a/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm index 8bf51bbffd4e0..a0c9a964fb395 100644 --- a/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm +++ b/code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm @@ -61,7 +61,7 @@ weapon.attack(C, src) playsound(src, 'sound/weapons/blade1.ogg', 50, TRUE, -1) if(C.stat == DEAD) - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/, update_appearance)), 2) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/, update_appearance)), 0.2 SECONDS) back_to_idle() diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index c8f512d78f8a1..2ebac99efdaf1 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -760,7 +760,7 @@ Pass a positive integer as an argument to override a bot's default speed. /mob/living/simple_animal/bot/proc/bot_patrol() patrol_step() - addtimer(CALLBACK(src, PROC_REF(do_patrol)), 5) + addtimer(CALLBACK(src, PROC_REF(do_patrol)), 0.5 SECONDS) /mob/living/simple_animal/bot/proc/do_patrol() if(mode == BOT_PATROL) @@ -814,7 +814,7 @@ Pass a positive integer as an argument to override a bot's default speed. var/moved = bot_move(patrol_target)//step_towards(src, next) // attempt to move if(!moved) //Couldn't proceed the next step of the path BOT_STEP_MAX_RETRIES times - addtimer(CALLBACK(src, PROC_REF(patrol_step_not_moved)), 2) + addtimer(CALLBACK(src, PROC_REF(patrol_step_not_moved)), 0.2 SECONDS) else // no path, so calculate new one mode = BOT_START_PATROL @@ -945,7 +945,7 @@ Pass a positive integer as an argument to override a bot's default speed. var/moved = bot_move(summon_target, 3) // Move attempt if(!moved) - addtimer(CALLBACK(src, PROC_REF(summon_step_not_moved)), 2) + addtimer(CALLBACK(src, PROC_REF(summon_step_not_moved)), 0.2 SECONDS) else // no path, so calculate new one calc_summon_path() diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index 9c52ca8e23858..2080567de0549 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -180,7 +180,7 @@ /mob/living/simple_animal/bot/secbot/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE)//shocks only make him angry if(base_speed < initial(base_speed) + 3) base_speed += 3 - addtimer(VARSET_CALLBACK(src, base_speed, base_speed - 3), 60) + addtimer(VARSET_CALLBACK(src, base_speed, base_speed - 3), 6 SECONDS) playsound(src, 'sound/machines/defib_zap.ogg', 50) visible_message(span_warning("[src] shakes and speeds up!")) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm index 91cf152acb07f..00cc37fe618cb 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm @@ -225,7 +225,7 @@ Difficulty: Hard var/turf/targetturf = get_step(src, dir) L.forceMove(targetturf) playsound(targetturf, 'sound/magic/exit_blood.ogg', 100, TRUE, -1) - addtimer(CALLBACK(src, PROC_REF(devour), L), 2) + addtimer(CALLBACK(src, PROC_REF(devour), L), 0.2 SECONDS) SLEEP_CHECK_DEATH(1, src) /mob/living/simple_animal/hostile/megafauna/bubblegum/devour(mob/living/yummy_food) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm index a223004f85c4e..b4cafdb6d538d 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm @@ -231,7 +231,7 @@ Difficulty: Hard blinking = TRUE SLEEP_CHECK_DEATH(4 + target_slowness, src) animate(src, color = oldcolor, time = 8) - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 8) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 0.8 SECONDS) SLEEP_CHECK_DEATH(8, src) blinking = FALSE else @@ -252,7 +252,7 @@ Difficulty: Hard INVOKE_ASYNC(src, PROC_REF(blasts), target, GLOB.diagonals) SLEEP_CHECK_DEATH(6 + target_slowness, src) animate(src, color = oldcolor, time = 8) - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 8) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 0.8 SECONDS) SLEEP_CHECK_DEATH(8, src) blinking = FALSE @@ -280,7 +280,7 @@ Difficulty: Hard SLEEP_CHECK_DEATH(8 + target_slowness, src) update_cooldowns(list(COOLDOWN_UPDATE_SET_CHASER = chaser_cooldown_time)) animate(src, color = oldcolor, time = 8) - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 8) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 0.8 SECONDS) SLEEP_CHECK_DEATH(8, src) blinking = FALSE @@ -582,7 +582,7 @@ Difficulty: Hard friendly_fire_check = is_friendly_fire if(new_speed) speed = new_speed - addtimer(CALLBACK(src, PROC_REF(seek_target)), 1) + addtimer(CALLBACK(src, PROC_REF(seek_target)), 0.1 SECONDS) /obj/effect/temp_visual/hierophant/chaser/proc/get_target_dir() . = get_cardinal_dir(src, targetturf) diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm index ba34883489fc8..71801a44c95ef 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm @@ -169,7 +169,7 @@ While using this makes the system rely on OnFire, it still gives options for tim if(boosted) mychild.playsound_local(get_turf(mychild), 'sound/effects/magic.ogg', 40, 0) to_chat(mychild, "Someone has activated your tumor. You will be returned to fight shortly, get ready!") - addtimer(CALLBACK(src, PROC_REF(return_elite)), 30) + addtimer(CALLBACK(src, PROC_REF(return_elite)), 3 SECONDS) INVOKE_ASYNC(src, PROC_REF(arena_checks)) if(TUMOR_INACTIVE) if(HAS_TRAIT(user, TRAIT_ELITE_CHALLENGER)) @@ -181,7 +181,7 @@ While using this makes the system rely on OnFire, it still gives options for tim visible_message(span_boldwarning("[src] begins to convulse. Your instincts tell you to step back.")) make_activator(user) if(!boosted) - addtimer(CALLBACK(src, PROC_REF(spawn_elite)), 30) + addtimer(CALLBACK(src, PROC_REF(spawn_elite)), 3 SECONDS) return visible_message(span_boldwarning("Something within [src] stirs...")) var/mob/chosen_one = SSpolling.poll_ghosts_for_target(check_jobban = ROLE_SENTIENCE, role = ROLE_SENTIENCE, poll_time = 5 SECONDS, checked_target = src, ignore_category = POLL_IGNORE_LAVALAND_ELITE, alert_pic = src, role_name_text = "lavaland elite") @@ -194,7 +194,7 @@ While using this makes the system rely on OnFire, it still gives options for tim While the opponent might have an upper hand with powerful mining equipment and tools, you have great power normally limited by AI mobs.\n\ If you want to win, you'll have to use your powers in creative ways to ensure the kill. It's suggested you try using them all as soon as possible.\n\ Should you win, you'll receive extra information regarding what to do after. Good luck!") - addtimer(CALLBACK(src, PROC_REF(spawn_elite), elitemind), 100) + addtimer(CALLBACK(src, PROC_REF(spawn_elite), elitemind), 10 SECONDS) else visible_message(span_boldwarning("The stirring stops, and nothing emerges. Perhaps try again later.")) activity = TUMOR_INACTIVE @@ -291,7 +291,7 @@ While using this makes the system rely on OnFire, it still gives options for tim INVOKE_ASYNC(src, PROC_REF(arena_trap)) //Gets another arena trap queued up for when this one runs out. INVOKE_ASYNC(src, PROC_REF(border_check)) //Checks to see if our fighters got out of the arena somehow. if(!QDELETED(src)) - addtimer(CALLBACK(src, PROC_REF(arena_checks)), 50) + addtimer(CALLBACK(src, PROC_REF(arena_checks)), 5 SECONDS) /obj/structure/elite_tumor/proc/fighters_check() if(QDELETED(mychild) || mychild.stat == DEAD) diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm index 2b1d638ac495c..f7d86c350deef 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm @@ -146,7 +146,7 @@ color = COLOR_RED set_varspeed(0) move_to_delay = 3 - addtimer(CALLBACK(src, PROC_REF(reset_rage)), 65) + addtimer(CALLBACK(src, PROC_REF(reset_rage)), 6.5 SECONDS) /mob/living/simple_animal/hostile/asteroid/elite/broodmother/proc/reset_rage() color = COLOR_WHITE diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm index 77557879ccb93..9f162e0cfdc77 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm @@ -56,7 +56,7 @@ /mob/living/simple_animal/hostile/asteroid/elite/herald/death() . = ..() if(!is_mirror) - addtimer(CALLBACK(src, PROC_REF(become_ghost)), 8) + addtimer(CALLBACK(src, PROC_REF(become_ghost)), 0.8 SECONDS) if(my_mirror != null) qdel(my_mirror) @@ -150,13 +150,13 @@ var/target_turf = get_turf(target) var/angle_to_target = get_angle(src, target_turf) shoot_projectile(target_turf, angle_to_target, FALSE, TRUE) - addtimer(CALLBACK(src, PROC_REF(shoot_projectile), target_turf, angle_to_target, FALSE, TRUE), 2) - addtimer(CALLBACK(src, PROC_REF(shoot_projectile), target_turf, angle_to_target, FALSE, TRUE), 4) + addtimer(CALLBACK(src, PROC_REF(shoot_projectile), target_turf, angle_to_target, FALSE, TRUE), 0.2 SECONDS) + addtimer(CALLBACK(src, PROC_REF(shoot_projectile), target_turf, angle_to_target, FALSE, TRUE), 0.4 SECONDS) if(health < maxHealth * 0.5 && !is_mirror) playsound(get_turf(src), 'sound/magic/clockwork/invoke_general.ogg', 20, TRUE) - addtimer(CALLBACK(src, PROC_REF(shoot_projectile), target_turf, angle_to_target, FALSE, TRUE), 10) - addtimer(CALLBACK(src, PROC_REF(shoot_projectile), target_turf, angle_to_target, FALSE, TRUE), 12) - addtimer(CALLBACK(src, PROC_REF(shoot_projectile), target_turf, angle_to_target, FALSE, TRUE), 14) + addtimer(CALLBACK(src, PROC_REF(shoot_projectile), target_turf, angle_to_target, FALSE, TRUE), 1 SECONDS) + addtimer(CALLBACK(src, PROC_REF(shoot_projectile), target_turf, angle_to_target, FALSE, TRUE), 1.2 SECONDS) + addtimer(CALLBACK(src, PROC_REF(shoot_projectile), target_turf, angle_to_target, FALSE, TRUE), 1.4 SECONDS) /mob/living/simple_animal/hostile/asteroid/elite/herald/proc/herald_circleshot(offset) var/static/list/directional_shot_angles = list(0, 45, 90, 135, 180, 225, 270, 315) @@ -173,11 +173,11 @@ if(!is_mirror) icon_state = "herald_enraged" playsound(get_turf(src), 'sound/magic/clockwork/invoke_general.ogg', 20, TRUE) - addtimer(CALLBACK(src, PROC_REF(herald_circleshot), 0), 5) + addtimer(CALLBACK(src, PROC_REF(herald_circleshot), 0), 0.5 SECONDS) if(health < maxHealth * 0.5 && !is_mirror) playsound(get_turf(src), 'sound/magic/clockwork/invoke_general.ogg', 20, TRUE) - addtimer(CALLBACK(src, PROC_REF(herald_circleshot), 22.5), 15) - addtimer(CALLBACK(src, PROC_REF(unenrage)), 20) + addtimer(CALLBACK(src, PROC_REF(herald_circleshot), 22.5), 1.5 SECONDS) + addtimer(CALLBACK(src, PROC_REF(unenrage)), 2 SECONDS) /mob/living/simple_animal/hostile/asteroid/elite/herald/proc/herald_teleshot(target) ranged_cooldown = world.time + 30 @@ -283,7 +283,7 @@ owner.visible_message(span_danger("[owner]'s [src] emits a loud noise as [owner] is struck!")) var/static/list/directional_shot_angles = list(0, 45, 90, 135, 180, 225, 270, 315) playsound(get_turf(owner), 'sound/magic/clockwork/invoke_general.ogg', 20, TRUE) - addtimer(CALLBACK(src, PROC_REF(reactionshot), owner), 10) + addtimer(CALLBACK(src, PROC_REF(reactionshot), owner), 1 SECONDS) #undef HERALD_TRISHOT #undef HERALD_DIRECTIONALSHOT diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm index 926f4e96baaef..1ec573dbd6c56 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm @@ -123,7 +123,7 @@ T = get_step(T, dir_to_target) playsound(src,'sound/magic/demon_attack1.ogg', 200, 1) visible_message(span_boldwarning("[src] prepares to charge!")) - addtimer(CALLBACK(src, PROC_REF(legionnaire_charge_2), dir_to_target, 0), 4) + addtimer(CALLBACK(src, PROC_REF(legionnaire_charge_2), dir_to_target, 0), 0.4 SECONDS) /mob/living/simple_animal/hostile/asteroid/elite/legionnaire/proc/legionnaire_charge_2(move_dir, times_ran) if(times_ran >= 6) @@ -183,7 +183,7 @@ /mob/living/simple_animal/hostile/asteroid/elite/legionnaire/proc/onHeadDeath() myhead = null - addtimer(CALLBACK(src, PROC_REF(regain_head)), 50) + addtimer(CALLBACK(src, PROC_REF(regain_head)), 5 SECONDS) /mob/living/simple_animal/hostile/asteroid/elite/legionnaire/proc/regain_head() has_head = TRUE diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm index 2d6cdb39da061..a9babf2eccafa 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm @@ -136,7 +136,7 @@ new /obj/effect/temp_visual/hierophant/telegraph(turf_target, src) new /obj/effect/temp_visual/hierophant/telegraph(source, src) playsound(source,'sound/machines/airlockopen.ogg', 200, 1) - addtimer(CALLBACK(src, PROC_REF(pandora_teleport_2), turf_target, source), 2) + addtimer(CALLBACK(src, PROC_REF(pandora_teleport_2), turf_target, source), 0.2 SECONDS) /mob/living/simple_animal/hostile/asteroid/elite/pandora/proc/pandora_teleport_2(turf/T, turf/source) new /obj/effect/temp_visual/hierophant/telegraph/teleport(T, src) @@ -148,7 +148,7 @@ animate(src, alpha = 0, time = 2, easing = EASE_OUT) //fade out visible_message(span_hierophant_warning("[src] fades out!")) ADD_TRAIT(src, TRAIT_UNDENSE, VANISHING_TRAIT) - addtimer(CALLBACK(src, PROC_REF(pandora_teleport_3), T), 2) + addtimer(CALLBACK(src, PROC_REF(pandora_teleport_3), T), 0.2 SECONDS) /mob/living/simple_animal/hostile/asteroid/elite/pandora/proc/pandora_teleport_3(turf/T) forceMove(T) @@ -161,7 +161,7 @@ var/turf/T = get_turf(target) new /obj/effect/temp_visual/hierophant/blast/damaging/pandora(T, src) var/max_size = 3 - addtimer(CALLBACK(src, PROC_REF(aoe_squares_2), T, 0, max_size), 2) + addtimer(CALLBACK(src, PROC_REF(aoe_squares_2), T, 0, max_size), 0.2 SECONDS) /mob/living/simple_animal/hostile/asteroid/elite/pandora/proc/aoe_squares_2(turf/T, ring, max_size) if(ring > max_size) diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/goose.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/goose.dm index e4b07470c5882..30afc69c8b3e9 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/goose.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/goose.dm @@ -144,7 +144,7 @@ /mob/living/simple_animal/hostile/retaliate/goose/proc/choke(obj/item/food/plastic) if(stat == DEAD || choking) return - addtimer(CALLBACK(src, PROC_REF(suffocate)), 300) + addtimer(CALLBACK(src, PROC_REF(suffocate)), 30 SECONDS) /mob/living/simple_animal/hostile/retaliate/goose/vomit/choke(obj/item/food/plastic) if(stat == DEAD || choking) @@ -152,9 +152,9 @@ if(prob(25)) visible_message(span_warning("[src] is gagging on \the [plastic]!")) manual_emote("gags!") - addtimer(CALLBACK(src, PROC_REF(vomit)), 300) + addtimer(CALLBACK(src, PROC_REF(vomit)), 30 SECONDS) else - addtimer(CALLBACK(src, PROC_REF(suffocate)), 300) + addtimer(CALLBACK(src, PROC_REF(suffocate)), 30 SECONDS) /mob/living/simple_animal/hostile/retaliate/goose/Life(seconds_per_tick = SSMOBS_DT, times_fired) . = ..() diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index fa332d7837ad7..92ad416c27573 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -689,7 +689,7 @@ if(!imagined_eye_contact && is_face_visible() && SEND_SIGNAL(examined_mob, COMSIG_MOB_EYECONTACT, src, FALSE) != COMSIG_BLOCK_EYECONTACT) var/msg = span_smallnotice("[src] makes eye contact with you.") - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), examined_mob, msg), 3) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), examined_mob, msg), 0.3 SECONDS) /** * Called by using Activate Held Object with an empty hand/limb diff --git a/code/modules/paperwork/filingcabinet.dm b/code/modules/paperwork/filingcabinet.dm index 8a62f6a87b989..70e930ca31e3e 100644 --- a/code/modules/paperwork/filingcabinet.dm +++ b/code/modules/paperwork/filingcabinet.dm @@ -95,7 +95,7 @@ if(istype(content) && in_range(src, usr)) usr.put_in_hands(content) icon_state = "[initial(icon_state)]-open" - addtimer(VARSET_CALLBACK(src, icon_state, initial(icon_state)), 5) + addtimer(VARSET_CALLBACK(src, icon_state, initial(icon_state)), 0.5 SECONDS) return TRUE /obj/structure/filingcabinet/attack_tk(mob/user) diff --git a/code/modules/paperwork/ticketmachine.dm b/code/modules/paperwork/ticketmachine.dm index f9ade59edc1a5..5c849f4a530cd 100644 --- a/code/modules/paperwork/ticketmachine.dm +++ b/code/modules/paperwork/ticketmachine.dm @@ -156,7 +156,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/ticket_machine, 32) machine.increment() if(isnull(machine.current_ticket)) to_chat(activator, span_notice("The button light indicates that there are no more tickets to be processed.")) - addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 10) + addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 1 SECONDS) /obj/machinery/ticket_machine/update_icon() . = ..() diff --git a/code/modules/plumbing/plumbers/plumbing_buffer.dm b/code/modules/plumbing/plumbers/plumbing_buffer.dm index 7b3ef306d0419..06aad506ff035 100644 --- a/code/modules/plumbing/plumbers/plumbing_buffer.dm +++ b/code/modules/plumbing/plumbers/plumbing_buffer.dm @@ -68,7 +68,7 @@ neighbour.attempt_connect() //technically this would runtime if you made about 200~ buffers add_overlay(icon_state + "_alert") - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/, cut_overlay), icon_state + "_alert"), 20) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/, cut_overlay), icon_state + "_alert"), 2 SECONDS) /obj/machinery/plumbing/buffer/attack_hand_secondary(mob/user, modifiers) . = ..() diff --git a/code/modules/power/apc/apc_main.dm b/code/modules/power/apc/apc_main.dm index a90d1cd388a5a..62398aa4fc05d 100644 --- a/code/modules/power/apc/apc_main.dm +++ b/code/modules/power/apc/apc_main.dm @@ -208,7 +208,7 @@ //Make the apc visually interactive register_context() - addtimer(CALLBACK(src, PROC_REF(update)), 5) + addtimer(CALLBACK(src, PROC_REF(update)), 0.5 SECONDS) RegisterSignal(SSdcs, COMSIG_GLOB_GREY_TIDE, PROC_REF(grey_tide)) RegisterSignal(src, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur)) update_appearance() diff --git a/code/modules/power/apc/apc_tool_act.dm b/code/modules/power/apc/apc_tool_act.dm index 00718c4ada9d6..00d3fc7a53879 100644 --- a/code/modules/power/apc/apc_tool_act.dm +++ b/code/modules/power/apc/apc_tool_act.dm @@ -459,7 +459,7 @@ environ = APC_CHANNEL_OFF update_appearance() update() - addtimer(CALLBACK(src, PROC_REF(reset), APC_RESET_EMP), 600) + addtimer(CALLBACK(src, PROC_REF(reset), APC_RESET_EMP), 60 SECONDS) /obj/machinery/power/apc/proc/togglelock(mob/living/user) if(obj_flags & EMAGGED) diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm index f5b4a8ca66b6a..ce91202722544 100644 --- a/code/modules/power/power.dm +++ b/code/modules/power/power.dm @@ -30,7 +30,7 @@ /obj/machinery/power/Destroy() disconnect_from_network() - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(update_cable_icons_on_turf), get_turf(src)), 3) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(update_cable_icons_on_turf), get_turf(src)), 0.3 SECONDS) return ..() /////////////////////////////// diff --git a/code/modules/power/singularity/containment_field.dm b/code/modules/power/singularity/containment_field.dm index d9fc0671e31d7..0fd3c15a39a6b 100644 --- a/code/modules/power/singularity/containment_field.dm +++ b/code/modules/power/singularity/containment_field.dm @@ -164,4 +164,4 @@ to_chat(considered_atom, span_userdanger("The field repels you with tremendous force!")) playsound(src, 'sound/effects/gravhit.ogg', 50, TRUE) considered_atom.throw_at(target, 200, 4) - addtimer(CALLBACK(src, PROC_REF(clear_shock)), 5) + addtimer(CALLBACK(src, PROC_REF(clear_shock)), 0.5 SECONDS) diff --git a/code/modules/power/singularity/field_generator.dm b/code/modules/power/singularity/field_generator.dm index c83db17c586d8..c18e7f15a65f1 100644 --- a/code/modules/power/singularity/field_generator.dm +++ b/code/modules/power/singularity/field_generator.dm @@ -283,11 +283,11 @@ no power level overlay is currently in the overlays list. set_explosion_block(INFINITY) can_atmos_pass = ATMOS_PASS_NO air_update_turf(TRUE, TRUE) - addtimer(CALLBACK(src, PROC_REF(setup_field), 1), 1) - addtimer(CALLBACK(src, PROC_REF(setup_field), 2), 2) - addtimer(CALLBACK(src, PROC_REF(setup_field), 4), 3) - addtimer(CALLBACK(src, PROC_REF(setup_field), 8), 4) - addtimer(VARSET_CALLBACK(src, active, FG_ONLINE), 5) + addtimer(CALLBACK(src, PROC_REF(setup_field), 1), 0.1 SECONDS) + addtimer(CALLBACK(src, PROC_REF(setup_field), 2), 0.2 SECONDS) + addtimer(CALLBACK(src, PROC_REF(setup_field), 4), 0.3 SECONDS) + addtimer(CALLBACK(src, PROC_REF(setup_field), 8), 0.4 SECONDS) + addtimer(VARSET_CALLBACK(src, active, FG_ONLINE), 0.5 SECONDS) /obj/machinery/field/generator/proc/setup_field(NSEW) var/turf/current_turf = loc diff --git a/code/modules/power/tesla/energy_ball.dm b/code/modules/power/tesla/energy_ball.dm index 376cebb7dcd9e..0e7957b65fb2f 100644 --- a/code/modules/power/tesla/energy_ball.dm +++ b/code/modules/power/tesla/energy_ball.dm @@ -127,7 +127,7 @@ energy_to_raise = energy_to_raise * 1.25 playsound(src.loc, 'sound/magic/lightning_chargeup.ogg', 100, TRUE, extrarange = 30) - addtimer(CALLBACK(src, PROC_REF(new_mini_ball)), 100) + addtimer(CALLBACK(src, PROC_REF(new_mini_ball)), 10 SECONDS) else if(energy < energy_to_lower && orbiting_balls.len) energy_to_raise = energy_to_raise / 1.25 energy_to_lower = (energy_to_raise / 1.25) - 20 diff --git a/code/modules/projectiles/guns/special/grenade_launcher.dm b/code/modules/projectiles/guns/special/grenade_launcher.dm index e5ce8c51316a9..830952dd769e6 100644 --- a/code/modules/projectiles/guns/special/grenade_launcher.dm +++ b/code/modules/projectiles/guns/special/grenade_launcher.dm @@ -53,4 +53,4 @@ F.active = 1 F.icon_state = initial(F.icon_state) + "_active" playsound(user.loc, 'sound/weapons/armbomb.ogg', 75, TRUE, -3) - addtimer(CALLBACK(F, TYPE_PROC_REF(/obj/item/grenade, detonate)), 15) + addtimer(CALLBACK(F, TYPE_PROC_REF(/obj/item/grenade, detonate)), 1.5 SECONDS) diff --git a/code/modules/projectiles/projectile/energy/net_snare.dm b/code/modules/projectiles/projectile/energy/net_snare.dm index 7eb0945b18b48..1bb7988e4bae4 100644 --- a/code/modules/projectiles/projectile/energy/net_snare.dm +++ b/code/modules/projectiles/projectile/energy/net_snare.dm @@ -40,7 +40,7 @@ else com.target_ref = null - addtimer(CALLBACK(src, PROC_REF(pop), teletarget), 30) + addtimer(CALLBACK(src, PROC_REF(pop), teletarget), 3 SECONDS) /obj/effect/nettingportal/proc/pop(teletarget) if(teletarget) diff --git a/code/modules/projectiles/projectile/energy/stun.dm b/code/modules/projectiles/projectile/energy/stun.dm index 5172a9984dae0..66ea4d2c86593 100644 --- a/code/modules/projectiles/projectile/energy/stun.dm +++ b/code/modules/projectiles/projectile/energy/stun.dm @@ -22,7 +22,7 @@ if(C.dna && C.dna.check_mutation(/datum/mutation/human/hulk)) C.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ), forced = "hulk") else if(!C.check_stun_immunity(CANKNOCKDOWN)) - addtimer(CALLBACK(C, TYPE_PROC_REF(/mob/living/carbon, do_jitter_animation), 20), 5) + addtimer(CALLBACK(C, TYPE_PROC_REF(/mob/living/carbon, do_jitter_animation), 20), 0.5 SECONDS) /obj/projectile/energy/electrode/on_range() //to ensure the bolt sparks when it reaches the end of its range if it didn't hit a target yet do_sparks(1, TRUE, src) diff --git a/code/modules/reagents/chemistry/reagents/drug_reagents.dm b/code/modules/reagents/chemistry/reagents/drug_reagents.dm index 7cb3943b28623..cb05757bdc548 100644 --- a/code/modules/reagents/chemistry/reagents/drug_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drug_reagents.dm @@ -685,7 +685,7 @@ . = ..() playsound(invisible_man, 'sound/chemistry/saturnx_fade.ogg', 40) to_chat(invisible_man, span_nicegreen("You feel pins and needles all over your skin as your body suddenly becomes transparent!")) - addtimer(CALLBACK(src, PROC_REF(turn_man_invisible), invisible_man), 10) //just a quick delay to synch up the sound. + addtimer(CALLBACK(src, PROC_REF(turn_man_invisible), invisible_man), 1 SECONDS) //just a quick delay to synch up the sound. if(!invisible_man.hud_used) return diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm index f1bf67348fb16..40553bf0aa5cd 100644 --- a/code/modules/reagents/chemistry/reagents/food_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm @@ -185,7 +185,7 @@ exposed_mob.emote("scream") playsound(exposed_mob, 'sound/machines/fryer/deep_fryer_emerge.ogg', 25, TRUE) ADD_TRAIT(exposed_mob, TRAIT_OIL_FRIED, "cooking_oil_react") - addtimer(CALLBACK(exposed_mob, TYPE_PROC_REF(/mob/living, unfry_mob)), 3) + addtimer(CALLBACK(exposed_mob, TYPE_PROC_REF(/mob/living, unfry_mob)), 0.3 SECONDS) if(FryLoss) exposed_mob.adjustFireLoss(FryLoss) diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index ce8cbc3275870..75a7cfa579278 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -1228,7 +1228,7 @@ to_chat(affected_mob, span_warning("You feel unstable...")) affected_mob.set_jitter_if_lower(2 SECONDS) current_cycle = 1 - addtimer(CALLBACK(affected_mob, TYPE_PROC_REF(/mob/living, bluespace_shuffle)), 30) + addtimer(CALLBACK(affected_mob, TYPE_PROC_REF(/mob/living, bluespace_shuffle)), 3 SECONDS) /mob/living/proc/bluespace_shuffle() do_teleport(src, get_turf(src), 5, asoundin = 'sound/effects/phasein.ogg', channel = TELEPORT_CHANNEL_BLUESPACE) diff --git a/code/modules/reagents/chemistry/recipes.dm b/code/modules/reagents/chemistry/recipes.dm index c7732e0908a0d..f7fc1b04ac8de 100644 --- a/code/modules/reagents/chemistry/recipes.dm +++ b/code/modules/reagents/chemistry/recipes.dm @@ -261,10 +261,10 @@ else if(setting_type) if(step_away(X, T) && moving_power > 1) //Can happen twice at most. So this is fine. - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step_away), X, T), 2) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step_away), X, T), 0.2 SECONDS) else if(step_towards(X, T) && moving_power > 1) - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step_towards), X, T), 2) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step_towards), X, T), 0.2 SECONDS) //////////////////Generic explosions/failures//////////////////// // It is HIGHLY, HIGHLY recomended that you consume all/a good volume of the reagents/products in an explosion - because it will just keep going forever until the reaction stops diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm index edb11633e91bc..d190a44aea063 100644 --- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm +++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm @@ -157,7 +157,7 @@ mix_message = "Sparks start flying around the gunpowder!" /datum/chemical_reaction/reagent_explosion/gunpowder_explosion/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) - addtimer(CALLBACK(src, PROC_REF(default_explode), holder, created_volume, modifier, strengthdiv), rand(5,10) SECONDS) + addtimer(CALLBACK(src, PROC_REF(default_explode), holder, created_volume, modifier, strengthdiv), rand(5 SECONDS, 10 SECONDS)) /datum/chemical_reaction/thermite results = list(/datum/reagent/thermite = 3) diff --git a/code/modules/reagents/chemistry/recipes/slime_extracts.dm b/code/modules/reagents/chemistry/recipes/slime_extracts.dm index ecd46a44db01e..ce13c9c70de7f 100644 --- a/code/modules/reagents/chemistry/recipes/slime_extracts.dm +++ b/code/modules/reagents/chemistry/recipes/slime_extracts.dm @@ -103,21 +103,21 @@ /datum/chemical_reaction/slime/slimemobspawn/proc/summon_mobs(datum/reagents/holder, turf/T) T.visible_message(span_danger("The slime extract begins to vibrate violently!")) - addtimer(CALLBACK(src, PROC_REF(chemical_mob_spawn), holder, 5, "Gold Slime", HOSTILE_SPAWN), 50) + addtimer(CALLBACK(src, PROC_REF(chemical_mob_spawn), holder, 5, "Gold Slime", HOSTILE_SPAWN), 5 SECONDS) /datum/chemical_reaction/slime/slimemobspawn/lesser required_reagents = list(/datum/reagent/blood = 1) /datum/chemical_reaction/slime/slimemobspawn/lesser/summon_mobs(datum/reagents/holder, turf/T) T.visible_message(span_danger("The slime extract begins to vibrate violently!")) - addtimer(CALLBACK(src, PROC_REF(chemical_mob_spawn), holder, 3, "Lesser Gold Slime", HOSTILE_SPAWN, FACTION_NEUTRAL), 50) + addtimer(CALLBACK(src, PROC_REF(chemical_mob_spawn), holder, 3, "Lesser Gold Slime", HOSTILE_SPAWN, FACTION_NEUTRAL), 5 SECONDS) /datum/chemical_reaction/slime/slimemobspawn/friendly required_reagents = list(/datum/reagent/water = 1) /datum/chemical_reaction/slime/slimemobspawn/friendly/summon_mobs(datum/reagents/holder, turf/T) T.visible_message(span_danger("The slime extract begins to vibrate adorably!")) - addtimer(CALLBACK(src, PROC_REF(chemical_mob_spawn), holder, 1, "Friendly Gold Slime", FRIENDLY_SPAWN, FACTION_NEUTRAL), 50) + addtimer(CALLBACK(src, PROC_REF(chemical_mob_spawn), holder, 1, "Friendly Gold Slime", FRIENDLY_SPAWN, FACTION_NEUTRAL), 5 SECONDS) /datum/chemical_reaction/slime/slimemobspawn/spider required_reagents = list(/datum/reagent/spider_extract = 1) @@ -125,7 +125,7 @@ /datum/chemical_reaction/slime/slimemobspawn/spider/summon_mobs(datum/reagents/holder, turf/T) T.visible_message(span_danger("The slime extract begins to vibrate crikey-ingly!")) - addtimer(CALLBACK(src, PROC_REF(chemical_mob_spawn), holder, 3, "Traitor Spider Slime", /mob/living/basic/spider/giant/midwife, FACTION_NEUTRAL, FALSE), 50) + addtimer(CALLBACK(src, PROC_REF(chemical_mob_spawn), holder, 3, "Traitor Spider Slime", /mob/living/basic/spider/giant/midwife, FACTION_NEUTRAL, FALSE), 5 SECONDS) //Silver @@ -194,7 +194,7 @@ /datum/chemical_reaction/slime/slimefreeze/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) var/turf/T = get_turf(holder.my_atom) T.visible_message(span_danger("The slime extract starts to feel extremely cold!")) - addtimer(CALLBACK(src, PROC_REF(freeze), holder), 50) + addtimer(CALLBACK(src, PROC_REF(freeze), holder), 5 SECONDS) var/obj/item/slime_extract/M = holder.my_atom deltimer(M.qdel_timer) ..() @@ -229,7 +229,7 @@ /datum/chemical_reaction/slime/slimefire/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) var/turf/T = get_turf(holder.my_atom) T.visible_message(span_danger("The slime extract begins to vibrate adorably!")) - addtimer(CALLBACK(src, PROC_REF(slime_burn), holder), 50) + addtimer(CALLBACK(src, PROC_REF(slime_burn), holder), 5 SECONDS) var/obj/item/slime_extract/M = holder.my_atom deltimer(M.qdel_timer) ..() @@ -372,7 +372,7 @@ message_admins("Slime Explosion reaction started at [ADMIN_VERBOSEJMP(T)]. Last Fingerprint: [touch_msg]") log_game("Slime Explosion reaction started at [AREACOORD(T)]. Last Fingerprint: [lastkey ? lastkey : "N/A"].") T.visible_message(span_danger("The slime extract begins to vibrate violently !")) - addtimer(CALLBACK(src, PROC_REF(boom), holder), 50) + addtimer(CALLBACK(src, PROC_REF(boom), holder), 5 SECONDS) var/obj/item/slime_extract/M = holder.my_atom deltimer(M.qdel_timer) ..() @@ -525,7 +525,7 @@ S.visible_message(span_danger("Infused with plasma, the core begins to expand uncontrollably!")) S.icon_state = "[S.base_state]_active" S.active = TRUE - addtimer(CALLBACK(S, TYPE_PROC_REF(/obj/item/grenade, detonate)), rand(15,60)) + addtimer(CALLBACK(S, TYPE_PROC_REF(/obj/item/grenade, detonate)), rand(1.5 SECONDS, 6 SECONDS)) else var/mob/living/basic/slime/random/random_slime = new (get_turf(holder.my_atom)) random_slime.visible_message(span_danger("Infused with plasma, the core begins to quiver and grow, and a new baby slime emerges from it!")) @@ -541,7 +541,7 @@ S.visible_message(span_danger("Infused with slime jelly, the core begins to expand uncontrollably!")) S.icon_state = "[S.base_state]_active" S.active = TRUE - addtimer(CALLBACK(S, TYPE_PROC_REF(/obj/item/grenade, detonate)), rand(15,60)) + addtimer(CALLBACK(S, TYPE_PROC_REF(/obj/item/grenade, detonate)), rand(1.5 SECONDS, 6 SECONDS)) var/lastkey = holder.my_atom.fingerprintslast var/touch_msg = "N/A" if(lastkey) diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm index fd2ab0eb4931a..ee512224184c1 100644 --- a/code/modules/reagents/reagent_containers/pill.dm +++ b/code/modules/reagents/reagent_containers/pill.dm @@ -49,7 +49,7 @@ ///Runs the consumption code, can be overriden for special effects /obj/item/reagent_containers/pill/proc/on_consumption(mob/consumer, mob/giver) if(icon_state == "pill4" && prob(5)) //you take the red pill - you stay in Wonderland, and I show you how deep the rabbit hole goes - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), consumer, span_notice("[pick(strings(REDPILL_FILE, "redpill_questions"))]")), 50) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), consumer, span_notice("[pick(strings(REDPILL_FILE, "redpill_questions"))]")), 5 SECONDS) if(apply_type == INGEST) SEND_SIGNAL(consumer, COMSIG_LIVING_PILL_CONSUMED, src, giver) SEND_SIGNAL(src, COMSIG_PILL_CONSUMED, eater = consumer, feeder = giver) diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm index 11d87bdd66780..89c69b7334e40 100644 --- a/code/modules/research/experimentor.dm +++ b/code/modules/research/experimentor.dm @@ -509,10 +509,10 @@ investigate_log("Experimentor has drained power from its APC", INVESTIGATE_EXPERIMENTOR) if(globalMalf == 99) visible_message(span_warning("[src] begins to glow and vibrate. It's going to blow!")) - addtimer(CALLBACK(src, PROC_REF(boom)), 50) + addtimer(CALLBACK(src, PROC_REF(boom)), 5 SECONDS) if(globalMalf == 100) visible_message(span_warning("[src] begins to glow and vibrate. It's going to blow!")) - addtimer(CALLBACK(src, PROC_REF(honk)), 50) + addtimer(CALLBACK(src, PROC_REF(honk)), 5 SECONDS) addtimer(CALLBACK(src, PROC_REF(reset_exp)), resetTime) @@ -663,7 +663,7 @@ /obj/item/relic/proc/explode(mob/user) to_chat(user, span_danger("[src] begins to heat up!")) - addtimer(CALLBACK(src, PROC_REF(do_explode), user), rand(35, 100)) + addtimer(CALLBACK(src, PROC_REF(do_explode), user), rand(3.5 SECONDS, 10 SECONDS)) /obj/item/relic/proc/do_explode(mob/user) if(loc == user) @@ -674,7 +674,7 @@ /obj/item/relic/proc/teleport(mob/user) to_chat(user, span_notice("[src] begins to vibrate!")) - addtimer(CALLBACK(src, PROC_REF(do_the_teleport), user), rand(10, 30)) + addtimer(CALLBACK(src, PROC_REF(do_the_teleport), user), rand(1 SECONDS, 3 SECONDS)) /obj/item/relic/proc/do_the_teleport(mob/user) var/turf/userturf = get_turf(user) diff --git a/code/modules/research/xenobiology/crossbreeding/burning.dm b/code/modules/research/xenobiology/crossbreeding/burning.dm index c21645ede96e1..72ee9d98516eb 100644 --- a/code/modules/research/xenobiology/crossbreeding/burning.dm +++ b/code/modules/research/xenobiology/crossbreeding/burning.dm @@ -258,7 +258,7 @@ Burning extracts: /obj/item/slimecross/burning/oil/do_effect(mob/user) user.visible_message(span_warning("[user] activates [src]. It's going to explode!"), span_danger("You activate [src]. It crackles in anticipation")) - addtimer(CALLBACK(src, PROC_REF(boom)), 50) + addtimer(CALLBACK(src, PROC_REF(boom)), 5 SECONDS) /// Inflicts a blastwave upon every mob within a small radius. /obj/item/slimecross/burning/oil/proc/boom() diff --git a/code/modules/research/xenobiology/crossbreeding/charged.dm b/code/modules/research/xenobiology/crossbreeding/charged.dm index 0440c7e9205ac..76c4d3eaa1437 100644 --- a/code/modules/research/xenobiology/crossbreeding/charged.dm +++ b/code/modules/research/xenobiology/crossbreeding/charged.dm @@ -199,7 +199,7 @@ Charged extracts: /obj/item/slimecross/charged/gold/do_effect(mob/user) user.visible_message(span_warning("[src] starts shuddering violently!")) - addtimer(CALLBACK(src, PROC_REF(startTimer)), 50) + addtimer(CALLBACK(src, PROC_REF(startTimer)), 5 SECONDS) /obj/item/slimecross/charged/gold/proc/startTimer() START_PROCESSING(SSobj, src) @@ -224,7 +224,7 @@ Charged extracts: /obj/item/slimecross/charged/oil/do_effect(mob/user) user.visible_message(span_danger("[src] begins to shake with rapidly increasing force!")) - addtimer(CALLBACK(src, PROC_REF(boom)), 50) + addtimer(CALLBACK(src, PROC_REF(boom)), 5 SECONDS) /obj/item/slimecross/charged/oil/proc/boom() explosion(src, devastation_range = 2, heavy_impact_range = 3, light_impact_range = 4, explosion_cause = src) //Much smaller effect than normal oils, but devastatingly strong where it does hit. diff --git a/code/modules/research/xenobiology/crossbreeding/chilling.dm b/code/modules/research/xenobiology/crossbreeding/chilling.dm index 0d7396be1e573..d8cf3456ed221 100644 --- a/code/modules/research/xenobiology/crossbreeding/chilling.dm +++ b/code/modules/research/xenobiology/crossbreeding/chilling.dm @@ -292,7 +292,7 @@ Chilling extracts: /obj/item/slimecross/chilling/oil/do_effect(mob/user) user.visible_message(span_danger("[src] begins to shake with muted intensity!")) - addtimer(CALLBACK(src, PROC_REF(boom)), 50) + addtimer(CALLBACK(src, PROC_REF(boom)), 5 SECONDS) /obj/item/slimecross/chilling/oil/proc/boom() explosion(src, devastation_range = -1, heavy_impact_range = -1, light_impact_range = 10, explosion_cause = src) //Large radius, but mostly light damage, and no flash. diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm index e14c1e56e39a4..1551d6eb952ba 100644 --- a/code/modules/research/xenobiology/xenobiology.dm +++ b/code/modules/research/xenobiology/xenobiology.dm @@ -274,7 +274,7 @@ to_chat(user, span_warning("Your glow is already enhanced!")) return species.update_glow(user, 5) - addtimer(CALLBACK(species, TYPE_PROC_REF(/datum/species/jelly/luminescent, update_glow), user, LUMINESCENT_DEFAULT_GLOW), 600) + addtimer(CALLBACK(species, TYPE_PROC_REF(/datum/species/jelly/luminescent, update_glow), user, LUMINESCENT_DEFAULT_GLOW), 1 MINUTES) to_chat(user, span_notice("You start glowing brighter.")) if(SLIME_ACTIVATE_MAJOR) diff --git a/code/modules/security_levels/keycard_authentication.dm b/code/modules/security_levels/keycard_authentication.dm index e4b2eaa6c2829..dc046d6fa6fb5 100644 --- a/code/modules/security_levels/keycard_authentication.dm +++ b/code/modules/security_levels/keycard_authentication.dm @@ -125,7 +125,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/keycard_auth, 26) event = event_type waiting = TRUE GLOB.keycard_events.fireEvent("triggerEvent", src) - addtimer(CALLBACK(src, PROC_REF(eventSent)), 20) + addtimer(CALLBACK(src, PROC_REF(eventSent)), 2 SECONDS) /obj/machinery/keycard_auth/proc/eventSent() triggerer = null @@ -135,7 +135,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/keycard_auth, 26) /obj/machinery/keycard_auth/proc/triggerEvent(source) event_source = source update_appearance() - addtimer(CALLBACK(src, PROC_REF(eventTriggered)), 20) + addtimer(CALLBACK(src, PROC_REF(eventTriggered)), 2 SECONDS) /obj/machinery/keycard_auth/proc/eventTriggered() event_source = null diff --git a/code/modules/shuttle/special.dm b/code/modules/shuttle/special.dm index 0617b9696a708..989ab4edc94a9 100644 --- a/code/modules/shuttle/special.dm +++ b/code/modules/shuttle/special.dm @@ -112,7 +112,7 @@ L.visible_message(span_revennotice("A strange purple glow wraps itself around [L] as [L.p_they()] suddenly fall[L.p_s()] unconscious."), span_revendanger("[desc]")) // Don't let them sit suround unconscious forever - addtimer(CALLBACK(src, PROC_REF(sleeper_dreams), L), 100) + addtimer(CALLBACK(src, PROC_REF(sleeper_dreams), L), 10 SECONDS) // Existing sleepers for(var/i in found) diff --git a/code/modules/station_goals/bsa.dm b/code/modules/station_goals/bsa.dm index db5a5e09761b9..c83f710d1df1d 100644 --- a/code/modules/station_goals/bsa.dm +++ b/code/modules/station_goals/bsa.dm @@ -258,7 +258,7 @@ GLOBAL_VAR_INIT(bsa_unlock, FALSE) /obj/machinery/bsa/full/proc/reload() ready = FALSE use_energy(power_used_per_shot) - addtimer(CALLBACK(src,"ready_cannon"),600) + addtimer(CALLBACK(src,"ready_cannon"), 1 MINUTES) /obj/machinery/bsa/full/proc/ready_cannon() ready = TRUE diff --git a/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm b/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm index df194bbed0f42..24aadfeca14f6 100644 --- a/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm +++ b/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm @@ -23,7 +23,7 @@ synthesizing = TRUE to_chat(owner, span_notice("You feel less hungry...")) owner.adjust_nutrition(25 * seconds_per_tick) - addtimer(CALLBACK(src, PROC_REF(synth_cool)), 50) + addtimer(CALLBACK(src, PROC_REF(synth_cool)), 5 SECONDS) /obj/item/organ/internal/cyberimp/chest/nutriment/proc/synth_cool() synthesizing = FALSE diff --git a/code/modules/surgery/tools.dm b/code/modules/surgery/tools.dm index d24b1a5927157..85c1beab0a357 100644 --- a/code/modules/surgery/tools.dm +++ b/code/modules/surgery/tools.dm @@ -170,7 +170,7 @@ /obj/item/surgicaldrill/suicide_act(mob/living/user) user.visible_message(span_suicide("[user] rams [src] into [user.p_their()] chest! It looks like [user.p_theyre()] trying to commit suicide!")) - addtimer(CALLBACK(user, TYPE_PROC_REF(/mob/living/carbon, gib), null, null, TRUE, TRUE), 25) + addtimer(CALLBACK(user, TYPE_PROC_REF(/mob/living/carbon, gib), null, null, TRUE, TRUE), 2.5 SECONDS) user.SpinAnimation(3, 10) playsound(user, 'sound/machines/juicer.ogg', 20, TRUE) return MANUAL_SUICIDE diff --git a/code/modules/tooltip/tooltip.dm b/code/modules/tooltip/tooltip.dm index 22027a3cf8e13..4b9514aa38c11 100644 --- a/code/modules/tooltip/tooltip.dm +++ b/code/modules/tooltip/tooltip.dm @@ -85,7 +85,7 @@ Notes: queueHide = showing ? TRUE : FALSE if (queueHide) - addtimer(CALLBACK(src, PROC_REF(do_hide)), 1) + addtimer(CALLBACK(src, PROC_REF(do_hide)), 0.1 SECONDS) else do_hide() diff --git a/code/modules/transport/transport_module.dm b/code/modules/transport/transport_module.dm index baa6d9d0fc82d..d027cf7ba6dd0 100644 --- a/code/modules/transport/transport_module.dm +++ b/code/modules/transport/transport_module.dm @@ -908,7 +908,7 @@ new overlay(our_turf) turfs += our_turf - addtimer(CALLBACK(src, PROC_REF(clear_turfs), turfs, iterations), 1) + addtimer(CALLBACK(src, PROC_REF(clear_turfs), turfs, iterations), 0.1 SECONDS) /obj/structure/transport/linear/tram/proc/clear_turfs(list/turfs_to_clear, iterations) for(var/turf/our_old_turf as anything in turfs_to_clear) @@ -928,7 +928,7 @@ turfs += our_turf if(iterations) - addtimer(CALLBACK(src, PROC_REF(clear_turfs), turfs, iterations), 1) + addtimer(CALLBACK(src, PROC_REF(clear_turfs), turfs, iterations), 0.1 SECONDS) /obj/structure/transport/linear/tram/proc/estop_throw(throw_direction) for(var/mob/living/passenger in transport_contents) diff --git a/code/modules/vehicles/mecha/mech_fabricator.dm b/code/modules/vehicles/mecha/mech_fabricator.dm index c4acded799446..54acd183affea 100644 --- a/code/modules/vehicles/mecha/mech_fabricator.dm +++ b/code/modules/vehicles/mecha/mech_fabricator.dm @@ -474,7 +474,7 @@ /obj/machinery/mecha_part_fabricator/proc/AfterMaterialInsert(item_inserted, id_inserted, amount_inserted) var/datum/material/M = id_inserted add_overlay("fab-load-[M.name]") - addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, cut_overlay), "fab-load-[M.name]"), 10) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, cut_overlay), "fab-load-[M.name]"), 1 SECONDS) /obj/machinery/mecha_part_fabricator/screwdriver_act(mob/living/user, obj/item/I) if(..()) diff --git a/code/modules/vehicles/scooter.dm b/code/modules/vehicles/scooter.dm index 9e320c2f8deb6..a4f3652448342 100644 --- a/code/modules/vehicles/scooter.dm +++ b/code/modules/vehicles/scooter.dm @@ -159,7 +159,7 @@ victim.Paralyze(1.5 SECONDS) skater.adjustStaminaLoss(instability) victim.visible_message(span_danger("[victim] straight up gets grinded into the ground by [skater]'s [src]! Radical!")) - addtimer(CALLBACK(src, PROC_REF(grind)), 1) + addtimer(CALLBACK(src, PROC_REF(grind)), 0.1 SECONDS) /obj/vehicle/ridden/scooter/skateboard/MouseDrop(atom/over_object) . = ..() diff --git a/code/modules/vehicles/vehicle_actions.dm b/code/modules/vehicles/vehicle_actions.dm index ed9884a9ea3cb..c378009996618 100644 --- a/code/modules/vehicles/vehicle_actions.dm +++ b/code/modules/vehicles/vehicle_actions.dm @@ -353,7 +353,7 @@ rider.client.give_award(/datum/award/achievement/misc/tram_surfer, rider) vehicle.grinding = TRUE vehicle.icon_state = "[initial(vehicle.icon_state)]-grind" - addtimer(CALLBACK(vehicle, TYPE_PROC_REF(/obj/vehicle/ridden/scooter/skateboard/, grind)), 2) + addtimer(CALLBACK(vehicle, TYPE_PROC_REF(/obj/vehicle/ridden/scooter/skateboard/, grind)), 0.2 SECONDS) else vehicle.obj_flags &= ~BLOCK_Z_OUT_DOWN rider.spin(spintime = 4, speed = 1) diff --git a/code/modules/vehicles/vehicle_key.dm b/code/modules/vehicles/vehicle_key.dm index f6e5f7c4e2882..08cb75df2d440 100644 --- a/code/modules/vehicles/vehicle_key.dm +++ b/code/modules/vehicles/vehicle_key.dm @@ -20,7 +20,7 @@ return SHAME user.visible_message(span_suicide("[user] is putting \the [src] in [user.p_their()] ear and starts [user.p_their()] motor! It looks like [user.p_theyre()] trying to commit suicide!")) user.say("Vroom vroom!!", forced="secway key suicide") //Not doing a shamestate here, because even if they fail to speak they're spinning. - addtimer(CALLBACK(user, TYPE_PROC_REF(/mob/living/, gib)), 20) + addtimer(CALLBACK(user, TYPE_PROC_REF(/mob/living/, gib)), 2 SECONDS) return MANUAL_SUICIDE /obj/item/key/janitor @@ -46,7 +46,7 @@ if(SKILL_LEVEL_APPRENTICE to SKILL_LEVEL_JOURNEYMAN) //At least they tried user.visible_message(span_suicide("[user] is putting \the [src] in [user.p_their()] mouth and has inefficiently become one with the janicart! It looks like [user.p_theyre()] trying to commit suicide!")) user.AddElement(/datum/element/cleaning) - addtimer(CALLBACK(src, PROC_REF(manual_suicide), user), 51) + addtimer(CALLBACK(src, PROC_REF(manual_suicide), user), 5.1 SECONDS) return MANUAL_SUICIDE if(SKILL_LEVEL_EXPERT to SKILL_LEVEL_MASTER) //They are worthy enough, but can it go even further beyond? user.visible_message(span_suicide("[user] is putting \the [src] in [user.p_their()] mouth and has skillfully become one with the janicart! It looks like [user.p_theyre()] trying to commit suicide!")) From b602a8138c31d6ae7a5d7b8f8930e064457e8458 Mon Sep 17 00:00:00 2001 From: necromanceranne <40847847+necromanceranne@users.noreply.github.com> Date: Sun, 7 Apr 2024 07:19:05 +1000 Subject: [PATCH 053/938] Watcher wreaths; Normal and Icewing varieties (#82457) ## About The Pull Request Adds Watcher Wreaths. An item that makes it look like you have a slightly floating thorn crown that you can make from some of their material parts (and the icewing crusher trophy for the icewing variant). The wreath has emissives. They don't do anything mechanically, they're just for show. ![wreath](https://github.com/tgstation/tgstation/assets/40847847/84b7cf89-2087-4c5c-85c1-d911c2e7ea13) ![image](https://github.com/tgstation/tgstation/assets/40847847/77bcda12-e29f-45f0-ad4a-8f25de12c0ef) ![image](https://github.com/tgstation/tgstation/assets/40847847/da3321bb-b24d-4e60-8648-455483e955d6) ## Why It's Good For The Game I really like the whole thing with turning lavaland monsters into trophies and cosmetics. Going down and coming back up looking like someone who just crawled through a horror movie and took some souvenirs is great. Stuff like the trophy accessories, bone and drake armor and many of the various lavaland items have this quality, and it always amuses me when a tech sees a dressed up miner and just goes 'holy shit, where did you get that'? Drip is the ultimate reward for playing miner. Nobody can tell me otherwise. this is the endgame every miner craves. And I crave a goddamn crown made from the broken remains of my enemies. ## Changelog :cl: add: Watcher wreaths. Made from the mangled remains of a watcher, now a handsome accessory for you to wear a few inches behind your head. Comes in Normal and Icewing variants. add: Some bounties for the two variants of watcher wreaths. /:cl: --- code/datums/components/crafting/tailoring.dm | 23 +++++++++++++++++++ code/modules/cargo/bounties/mining.dm | 14 +++++++++++ code/modules/clothing/neck/_neck.dm | 20 ++++++++++++++++ icons/mob/clothing/neck.dmi | Bin 114115 -> 115349 bytes icons/obj/clothing/neck.dmi | Bin 4253 -> 4550 bytes 5 files changed, 57 insertions(+) diff --git a/code/datums/components/crafting/tailoring.dm b/code/datums/components/crafting/tailoring.dm index 56a6bfb2c3f18..14a7ebfc21b01 100644 --- a/code/datums/components/crafting/tailoring.dm +++ b/code/datums/components/crafting/tailoring.dm @@ -199,6 +199,29 @@ ) category = CAT_CLOTHING +/datum/crafting_recipe/wreath + name = "Watcher Wreath" + result = /obj/item/clothing/neck/wreath + time = 2 SECONDS + reqs = list( + /obj/item/stack/sheet/bone = 2, + /obj/item/stack/sheet/sinew = 2, + /obj/item/stack/ore/diamond = 2, + ) + category = CAT_CLOTHING + +/datum/crafting_recipe/icewreath + name = "Icewing Wreath" + result = /obj/item/clothing/neck/wreath/icewing + time = 2 SECONDS + reqs = list( + /obj/item/stack/sheet/bone = 1, + /obj/item/stack/sheet/sinew = 1, + /obj/item/stack/ore/diamond = 2, + /obj/item/crusher_trophy/watcher_wing/ice_wing = 1, + ) + category = CAT_CLOTHING + /datum/crafting_recipe/bracers name = "Bone Bracers" result = /obj/item/clothing/gloves/bracer diff --git a/code/modules/cargo/bounties/mining.dm b/code/modules/cargo/bounties/mining.dm index a552e62aeb1f7..c49fc982a3ab9 100644 --- a/code/modules/cargo/bounties/mining.dm +++ b/code/modules/cargo/bounties/mining.dm @@ -43,6 +43,20 @@ required_count = 3 wanted_types = list(/obj/item/clothing/accessory/talisman = TRUE) +/datum/bounty/item/mining/watcher_wreath + name = "Watcher Wreaths" + description = "Station 14's Research Director thinks they're onto a break-through on the cultural icons of some pagan beliefs. Ship them a few watcher wreaths for analysis." + reward = CARGO_CRATE_VALUE * 15 + required_count = 3 + wanted_types = list(/obj/item/clothing/neck/wreath = FALSE) + +/datum/bounty/item/mining/icewing_wreath + name = "Icewing Wreath" + description = "We're getting some....weird messages from Station 14's Research Director. And most of what they said was incoherent. But they apparently want an icewing wreath. Could you send them one?" + reward = CARGO_CRATE_VALUE * 30 + required_count = 1 + wanted_types = list(/obj/item/clothing/neck/wreath/icewing = FALSE) + /datum/bounty/item/mining/bone_dagger name = "Bone Daggers" description = "Central Command's canteen is undergoing budget cuts. Ship over some bone daggers so our chef can keep working." diff --git a/code/modules/clothing/neck/_neck.dm b/code/modules/clothing/neck/_neck.dm index b9d684cbbbf7b..d2e019d0c4488 100644 --- a/code/modules/clothing/neck/_neck.dm +++ b/code/modules/clothing/neck/_neck.dm @@ -487,3 +487,23 @@ /obj/item/clothing/neck/beads/Initialize(mapload) . = ..() color = color = pick("#ff0077","#d400ff","#2600ff","#00ccff","#00ff2a","#e5ff00","#ffae00","#ff0000", "#ffffff") + +/obj/item/clothing/neck/wreath + name = "\improper Watcher Wreath" + desc = "An elaborate crown made from the twisted flesh and sinew of a watcher. \ + Wearing it makes you feel like you have eyes in the back of your head." + icon_state = "watcher_wreath" + worn_y_offset = 10 + alternate_worn_layer = ABOVE_BODY_FRONT_HEAD_LAYER + resistance_flags = FIRE_PROOF + +/obj/item/clothing/neck/wreath/worn_overlays(mutable_appearance/standing, isinhands, icon_file) + . = ..() + if(!isinhands) + . += emissive_appearance(icon_file, "wreath_emissive", src, alpha = src.alpha) + +/obj/item/clothing/neck/wreath/icewing + name = "\improper Icewing Wreath" + desc = "An elaborate crown made from the twisted flesh and sinew of an icewing watcher. \ + Wearing it sends shivers down your spine just from being near it." + icon_state = "icewing_wreath" diff --git a/icons/mob/clothing/neck.dmi b/icons/mob/clothing/neck.dmi index 7895a3ac7facf9ff2078195f1f2992939cdbbae3..a193fbd74a8e36a39e3a0198c6532486373890a4 100644 GIT binary patch delta 7217 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 XXEHkObp57v#USm61`nz=Uq<{N%xb>9 delta 5922 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 MZ~CC}zC+ai16V2ZfB*mh diff --git a/icons/obj/clothing/neck.dmi b/icons/obj/clothing/neck.dmi index 986d9bd9158a933986c1008572aff99ef2fff924..e937d125ec2a4a114817d35856d915fe43370da2 100644 GIT binary patch delta 4197 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 delta 3878 zcmV+>583d>Bb_0TBmudxC20W|?yn!MUkY0lj7}*bd?}_8J;8Y(Bzq{OlfD5MfB(z? z*LfV~gCJ&bkN=YZ0cIsj93bYo7yscFs%$MDI*?^n97ZBp&;S4c0d!JMQvg8b*k%9# z0XBM6Sad{Xb7OL8aCB*JZU6vyoRyT%Zi6rk#?SB+sJ${&S|;t%%hYP>VSNRZKQ35H zlPd9A_3h_@v@&TZ*};(=e&1(^e;k&@>;COol-Bkoa! zG-%_#8VD5OHGTpTgbq;(jP^*XZ&QZn2ezO-j8HR*7v2T_tP+M z&BOOBP!FEbH~1T99u4biT~1=s!)ZR?cn9fjzb;{_zzejTM)7efTItSmj$Ib}<8Jul zd;vu`Q57E1GVK5W4Nyr$e?e4uob8>BUlT_f$0q>^U|_druh-+St=fQ5R9+=Q3#I29 zV%qwGZBc7$YwLMlUk(D8qSklitoHgB-}5}PyP4g23rS>2Z+{KTvXjaFzBA7=Gdt<$ zBV&oSs#2*`+!pFlDwR&B>p^H~X`GoFltTBZ*4hbLwzb7ckmB)^e@bO!f|M`gC$zM; zwZ}-1%5dj00ESkEWCUnwYwyqlbapntqfsf(U=)DcPm>_R^dHdD)~1i4?W|^iEXn$| zR7MF9w7y5sr6qs>+SakHU6sh&>8K&dc9ZN5EkXcvml6Y|5B zBIpeL+MqnX?rz88f4>#{cY)22f8Tz_vz^icv_Ruy0<@@lz(kPk&bp41wL7#Zm1)hi zwuTcm71$44s{z1u2ZT>Y3w!NPuPMsw=mH1$=$8f1%iz#RnM!woD$P&VB!Culk0SrC ziT-!&uoG~DSyPO-CgXuG#SqB>x_%_#j>e+vLTKw%`O0AoEpp+9%NwQ+wAW_n7aO%E6xnicp@zxk$We|F^nCjWj9cuAlFK;JwQ;ACfy z;vF`*TEGCHt5vzYkpLwBl@tH~Wd{%eb^rnJld26`vo#4Ua&cF{+nQ-c0M~JY{p~FpLuLs8 znk;rGvfQ`^F~O5M$g>`S?mHfbs=1DKb9vY9e_gxbwX0T#=K2uf-hK5!jsV)PsBrff zrV##1bAM8;1eW>;fUb=}Zuo}H!KSC(P3#B-0p6c}*GOQi?`E@NmTq{UbhFR|xHsF4 zpQET9+_!cBbN#G9pz!BJ-W#@g5Pea4LS2|!)s1{?R@WF}dJc6Wjwje|Y!zPrchAIePx zm7_+kE=Q?tk-(pel>pH8F1Eimfy@T&<+TgHzs-iyTsDbK&%c7u4*;eRsis`-&;EZP zpt}G-k;MeSwfPGT9wEX7J~${gcd94COw5$M*&x!4$MZe0H9 z<}QsMj7cD>2H4M~t!*o>TKRzkQ37t8tOJBLjQaib4Pr@j zcaTf%(N+#RG>AG>1;CJkKx}q>81?t{<%WlI3jg5DJ4KJOe@i*pAHm;tg#5tJ&_D

DVNFSdVVBAb|$?lL*Cf%2$nBY>B|`Je|NeD+E2+PgObkb~)$5QYzre=;17#KMLE zR098y2>>%VlEBdvM(vaQGfZGW7#_n6Xgt73KyXM*2TA$yfhd3~W1~UkuORw!h4%{b zG$1*Q__LLxM)>&YkEUwn^W)<~kttyNUbzD#s=#ky?7dNW8fXLnAq?8>!}t@qEc=&J zz*ph$=vbj&ng*f{C4aVZe_w_fAn)0ac7Sr(5KRFRj6;Rt!q{j*_3`9z0;Tq6EBB;L zUl=!G`b7fSzf7Q-1ai6er}}b*(NTFC^Bqo1e*oIA_J`$@C`~z+E`IU@0|#LE$0G)11)=mG33)jKa(z=XQ&X0Qu!#?*%>b5in#+_)?00~&`Q?aLWI%4}$ds)E z8UTRL0?G(N`$KtUfAf>$y=hOD?oB_GMBOi{UBPD1%96dmW-9E!~aS586sX%roctcYU8;L7PLf9f|1fLjla5&*w-aFhVJ_24K0 zXzMos0FUH5^rB8616WS?4ZWxl2>{Ec@$MB51W?3s(S3#CbQSe0_RpU`KhG|}QH@Xyz^9+$OAqkbXZX?s zeEvDU^Z=^*BESO2P!U|bcmW9D-LxG4Y>JpglkkziqA zfBwvmKh7_luML0^022UM$N(b)OfbMg0E_^b08mZ+NFSW}>E9arsLPl6PZ$7?n866Z z1OVm%;1M$r4KTp~^8oOO8H@l-0AR&x>PK|pryuqHtpJ$8EJ$J*05gyUNhkwg2D2cE zWdK$Eh!*DOHwaJ}M!zJ0uY_R~m(!JDfADKE@QpAG;&Qk$jDAZ1-wDI$i7M(xbYcE% z9RQW18lZAi15}P`09E}cz=FZQQd?*#QJek%i@9URu0+<-S3=9_qVz#l1D=#f%azfk}pLvTfWs24m0SHy>Ufg!kZx{CUV5+zEMC{dzB&85YqQYmf^ z^=NUqw6xf?1dE_jsnnzZE2~RO%h3MN0Wkoi)9Q0yw{EG=D_UADFD)-Em6n&6W9R|= z$HP_UzHa^e^O}Et`_3H&0h$N6!%VQA;s1s;z3^l`e_X!y5dHt> z+2hCexc}$j@^X0*0-v8_5^Q=75CAm)`g%H(Q2;!D2>zcvd;06IkiqxwK8OI6S63F% zHq8RdE32D73L!wo&w-2z;K`F0&z|DxtvhQHK&ia)auND~3o>By0WkX4<#S)pAH8_- z^f!L~-?fJiUpxvGmsiW>e3vg5c@N-W6D&uxp00Qn&wc&=$oCHfQU3_Ay7H0)BWOGe ziS>2$xv$@U6V88+6qZ)YE9LSE^h3G4+LUWi=m6*iAXwe}DWD-Lq5bm83Nkb$01}YO oP3oT^0;(w!AW@=3iE7sW00}D^$gQ12L;wH)07*qoM6N<$g6z7CC;$Ke From da3294d89641f3c26e16442a0e798c8b8a89ea6f Mon Sep 17 00:00:00 2001 From: Skeleton-In-Disguise <49223093+Skeleton-In-Disguise@users.noreply.github.com> Date: Sat, 6 Apr 2024 14:19:39 -0700 Subject: [PATCH 054/938] adds preferences to transhumanist (#82435) ## About The Pull Request You may remember this, that's because I accidentally deleted it before while trying to change things. Anyways! Adds drop-down selections and new options to transhumanist. also fixes a minor typo Previously, you could choose your replaced limb by taking prosthetic limb, setting what you want changed, and then switching to transhumanist, since they used the same preference previously. ## Why It's Good For The Game Transhumanist felt strange because it was hypothetically a voluntary operation, but the augmentation clinic just spun the wheel on what you got replaced. From a role-playing perspective, being unable to choose is uninteresting and confusing. Also it always says your limb being was being replaced with a robotic arm and that annoyed me. Now that you are able to select your replacement part, I've added two new options, the robotic voice box, good for a more prominent change then a limb that will be hidden for most of a round, and flashlight eyes, for when you are truly committed to being rushed directly to robotics seeing the bright future ahead of humanity! ## Changelog :cl: add: Transhumanist now allows you to select your augmentation add: Transhumanist can now provide a robotic voice box, or flashlight eyes spellcheck: Transhumanist's roundstart text has been re-written to not be wrong /:cl: --------- Co-authored-by: san7890 --- code/_globalvars/lists/quirks.dm | 6 +- .../quirks/neutral_quirks/transhumanist.dm | 63 ++++++++++++++----- .../client/preferences/trans_prosthetic.dm | 17 +++++ tgstation.dme | 1 + .../trans_prosthetic.tsx | 6 ++ 5 files changed, 77 insertions(+), 16 deletions(-) create mode 100644 code/modules/client/preferences/trans_prosthetic.dm create mode 100644 tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/trans_prosthetic.tsx diff --git a/code/_globalvars/lists/quirks.dm b/code/_globalvars/lists/quirks.dm index d40a3b1366b41..4ce15f2e09e12 100644 --- a/code/_globalvars/lists/quirks.dm +++ b/code/_globalvars/lists/quirks.dm @@ -18,13 +18,17 @@ GLOBAL_LIST_INIT(limb_choice, list( "Right Leg" = /obj/item/bodypart/leg/right/robot/surplus, )) + ///Transhumanist quirk -GLOBAL_LIST_INIT(limb_choice_transhuman, list( +GLOBAL_LIST_INIT(part_choice_transhuman, list( "Left Arm" = /obj/item/bodypart/arm/left/robot, "Right Arm" = /obj/item/bodypart/arm/right/robot, "Left Leg" = /obj/item/bodypart/leg/left/robot, "Right Leg" = /obj/item/bodypart/leg/right/robot, + "Robotic Voice Box" = /obj/item/organ/internal/tongue/robot, + "Flashlights for Eyes" = /obj/item/organ/internal/eyes/robotic/flashlight, )) + ///Hemiplegic Quirk GLOBAL_LIST_INIT(side_choice_hemiplegic, list( "Left Side" = /datum/brain_trauma/severe/paralysis/hemiplegic/left, diff --git a/code/datums/quirks/neutral_quirks/transhumanist.dm b/code/datums/quirks/neutral_quirks/transhumanist.dm index 88923d463f697..046c2bb30f089 100644 --- a/code/datums/quirks/neutral_quirks/transhumanist.dm +++ b/code/datums/quirks/neutral_quirks/transhumanist.dm @@ -15,7 +15,7 @@ /datum/quirk/transhumanist name = "Transhumanist" - desc = "You see silicon life as the perfect lifeform and despise organic flesh. You are happier around silicons, but get frustrated when around organics. You seek to replace your fleshy limbs with their silicon counterparts. You start with a robotic limb." + desc = "You see silicon life as the perfect lifeform and despise organic flesh. You are happier around silicons, but get frustrated when around organics. You seek to replace your failing flesh with perfect silicon. You start with a robotic augmentation." icon = FA_ICON_ROBOT quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_PROCESSES|QUIRK_MOODLET_BASED value = 0 @@ -29,7 +29,8 @@ /obj/item/toy/figure/borg, ) var/slot_string - var/obj/item/bodypart/old_limb + var/obj/item/old_part + /datum/quirk/transhumanist/add(client/client_source) RegisterSignal(quirk_holder, COMSIG_CARBON_POST_ATTACH_LIMB, PROC_REF(calculate_bodypart_score)) @@ -100,27 +101,59 @@ if(-INFINITY to 0) quirk_holder.add_mood_event(MOOD_CATEGORY_TRANSHUMANIST_BODYPART, /datum/mood_event/very_organic) +/datum/quirk_constant_data/transhumanist + associated_typepath = /datum/quirk/transhumanist + customization_options = list(/datum/preference/choiced/trans_prosthetic) /datum/quirk/transhumanist/add_unique(client/client_source) - var/limb_type = GLOB.limb_choice_transhuman[client_source?.prefs?.read_preference(/datum/preference/choiced/prosthetic)] - if(isnull(limb_type)) //Client gone or they chose a random prosthetic - limb_type = GLOB.limb_choice_transhuman[pick(GLOB.limb_choice_transhuman)] + var/part_type = GLOB.part_choice_transhuman[client_source?.prefs?.read_preference(/datum/preference/choiced/trans_prosthetic)] + if(isnull(part_type)) //Client gone or they chose a random part + part_type = GLOB.part_choice_transhuman[pick(GLOB.part_choice_transhuman)] var/mob/living/carbon/human/human_holder = quirk_holder - var/obj/item/bodypart/new_part = new limb_type() - - slot_string = "[new_part.plaintext_zone]" - old_limb = human_holder.return_and_replace_bodypart(new_part, special = TRUE) + var/obj/item/new_part = new part_type() + if(isbodypart(new_part)) + var/obj/item/bodypart/new_bodypart = new_part + slot_string = new_bodypart.plaintext_zone + old_part = human_holder.return_and_replace_bodypart(new_bodypart, special = TRUE) + else if(isorgan(new_part)) + var/obj/item/organ/new_organ = new_part + old_part = human_holder.get_organ_slot(new_organ.slot) + if(new_organ.Insert(human_holder, special = TRUE)) + old_part.moveToNullspace() + STOP_PROCESSING(SSobj, old_part) + slot_string = new_organ.name /datum/quirk/transhumanist/post_add() - if(slot_string) - to_chat(quirk_holder, span_boldannounce("Your [slot_string] has been replaced with a robot arm. You need to use a welding tool and cables to repair it, instead of sutures and regenerative meshes.")) + if(!slot_string) + return + if(isbodypart(old_part)) + to_chat(quirk_holder, span_boldannounce("Your [slot_string] has been replaced with a robotic limb. You need to use a welding tool and cables to repair it, instead of sutures and regenerative meshes.")) + else if (old_part.name == "eyes") + to_chat(quirk_holder, span_boldannounce("You replaced your eyes with flashlights, not cameras. You can't see a thing!")) + else if (isorgan(old_part)) + to_chat(quirk_holder, span_boldannounce("Your [slot_string] brings you one step closer to silicon perfection, but you feel you're not quite there yet.")) /datum/quirk/transhumanist/remove() - if(old_limb) - var/mob/living/carbon/human/human_holder = quirk_holder - human_holder.del_and_replace_bodypart(old_limb, special = TRUE) - old_limb = null + if(isnull(old_part)) + quirk_holder.clear_mood_event(MOOD_CATEGORY_TRANSHUMANIST_BODYPART) + quirk_holder.clear_mood_event(MOOD_CATEGORY_TRANSHUMANIST_PEOPLE) + return + + var/mob/living/carbon/human/human_holder = quirk_holder + if(isbodypart(old_part)) + var/obj/item/bodypart/old_bodypart = old_part + human_holder.del_and_replace_bodypart(old_bodypart, special = TRUE) + old_bodypart = null + else if(isorgan(old_part)) + var/obj/item/organ/old_organ = old_part + old_part = human_holder.get_organ_slot(ORGAN_SLOT_TONGUE) + old_organ.Insert(quirk_holder, special = TRUE) + old_part.moveToNullspace() + STOP_PROCESSING(SSobj, old_part) + old_organ = null + old_part = null + quirk_holder.clear_mood_event(MOOD_CATEGORY_TRANSHUMANIST_BODYPART) quirk_holder.clear_mood_event(MOOD_CATEGORY_TRANSHUMANIST_PEOPLE) diff --git a/code/modules/client/preferences/trans_prosthetic.dm b/code/modules/client/preferences/trans_prosthetic.dm new file mode 100644 index 0000000000000..fd28cb1ecf8c8 --- /dev/null +++ b/code/modules/client/preferences/trans_prosthetic.dm @@ -0,0 +1,17 @@ +/datum/preference/choiced/trans_prosthetic + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + savefile_key = "trans_prosthetic" + savefile_identifier = PREFERENCE_CHARACTER + +/datum/preference/choiced/trans_prosthetic/init_possible_values() + return list("Random") + GLOB.part_choice_transhuman + +/datum/preference/choiced/trans_prosthetic/is_accessible(datum/preferences/preferences) + . = ..() + if (!.) + return FALSE + + return "Transhumanist" in preferences.all_quirks + +/datum/preference/choiced/trans_prosthetic/apply_to_human(mob/living/carbon/human/target, value) + return diff --git a/tgstation.dme b/tgstation.dme index 1b1eb4995121f..9dcfacb087c0b 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -3665,6 +3665,7 @@ #include "code\modules\client\preferences\statpanel.dm" #include "code\modules\client\preferences\tgui.dm" #include "code\modules\client\preferences\tooltips.dm" +#include "code\modules\client\preferences\trans_prosthetic.dm" #include "code\modules\client\preferences\ui_style.dm" #include "code\modules\client\preferences\underwear_color.dm" #include "code\modules\client\preferences\uplink_location.dm" diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/trans_prosthetic.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/trans_prosthetic.tsx new file mode 100644 index 0000000000000..368a2a16a1b37 --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/trans_prosthetic.tsx @@ -0,0 +1,6 @@ +import { FeatureChoiced, FeatureDropdownInput } from '../base'; + +export const trans_prosthetic: FeatureChoiced = { + name: 'Augment', + component: FeatureDropdownInput, +}; From 34890b9d0a83e1572ffcd965fde2a28f49d9793d Mon Sep 17 00:00:00 2001 From: Jeremiah <42397676+jlsnow301@users.noreply.github.com> Date: Sat, 6 Apr 2024 14:20:22 -0700 Subject: [PATCH 055/938] Pre-516 tgui prep (#82473) ## About The Pull Request This should be completely fine to run on our current servers. Moves the (massive) javascript out of tgui.html into its own file so I can lint/format/minify it Removes some of the checks for earlier versions of IE. No need to check for these now, especially not later Removes some pre-ie11 checks we're not using now Creates a fn to check if the user is running blink engine (chromium/edge) ## Why It's Good For The Game 516 prep --- tgui/.gitignore | 1 + tgui/global.d.ts | 25 - tgui/packages/tgui-panel/chat/renderer.jsx | 33 +- tgui/packages/tgui-panel/panelFocus.js | 2 +- tgui/packages/tgui-polyfill/byondutils.js | 488 +++++++++++++++++ tgui/packages/tgui-polyfill/package.json | 3 +- tgui/packages/tgui-say/index.tsx | 21 +- tgui/packages/tgui-say/package.json | 2 + tgui/packages/tgui/backend.ts | 4 +- tgui/packages/tgui/components/Flex.tsx | 8 +- .../packages/tgui/stories/ByondUi.stories.jsx | 2 +- tgui/public/tgui.html | 503 +----------------- tgui/public/utils.min.js | 1 + tgui/yarn.lock | 13 +- 14 files changed, 536 insertions(+), 570 deletions(-) create mode 100644 tgui/packages/tgui-polyfill/byondutils.js create mode 100644 tgui/public/utils.min.js diff --git a/tgui/.gitignore b/tgui/.gitignore index 4d0dd666d88e2..799a6dc89006c 100644 --- a/tgui/.gitignore +++ b/tgui/.gitignore @@ -17,6 +17,7 @@ package-lock.json /public/**/* !/public/*.html !/public/tgui-polyfill.min.js +!/public/utils.min.js /coverage ## Previously ignored locations that are kept to avoid confusing git diff --git a/tgui/global.d.ts b/tgui/global.d.ts index 542788717ab64..8ad057b77f7fe 100644 --- a/tgui/global.d.ts +++ b/tgui/global.d.ts @@ -46,31 +46,6 @@ type ByondType = { */ IS_BYOND: boolean; - /** - * Version of Trident engine of Internet Explorer. Null if N/A. - */ - TRIDENT: number | null; - - /** - * True if browser is IE8 or lower. - */ - IS_LTE_IE8: boolean; - - /** - * True if browser is IE9 or lower. - */ - IS_LTE_IE9: boolean; - - /** - * True if browser is IE10 or lower. - */ - IS_LTE_IE10: boolean; - - /** - * True if browser is IE11 or lower. - */ - IS_LTE_IE11: boolean; - /** * If `true`, unhandled errors and common mistakes result in a blue screen * of death, which stops this window from handling incoming messages and diff --git a/tgui/packages/tgui-panel/chat/renderer.jsx b/tgui/packages/tgui-panel/chat/renderer.jsx index 0d26061f60b0a..bbe3c80a5f285 100644 --- a/tgui/packages/tgui-panel/chat/renderer.jsx +++ b/tgui/packages/tgui-panel/chat/renderer.jsx @@ -6,7 +6,7 @@ import { EventEmitter } from 'common/events'; import { classes } from 'common/react'; -import { render } from 'react-dom'; +import { createRoot } from 'react-dom/client'; import { Tooltip } from 'tgui/components'; import { createLogger } from 'tgui/logging'; @@ -37,6 +37,8 @@ export const TGUI_CHAT_COMPONENTS = { Tooltip, }; +let reactRoot = null; + // List of injectable attibute names mapped to their proper prop // We need this because attibutes don't support lowercase names export const TGUI_CHAT_ATTRIBUTES_TO_PROPS = { @@ -168,7 +170,7 @@ class ChatRenderer { // Find scrollable parent this.scrollNode = findNearestScrollableParent(this.rootNode); this.scrollNode.addEventListener('scroll', this.handleScroll); - setImmediate(() => { + setTimeout(() => { this.scrollToBottom(); }); // Flush the queue @@ -413,14 +415,19 @@ class ChatRenderer { childNode.removeChild(childNode.firstChild); } const Element = TGUI_CHAT_COMPONENTS[targetName]; + + if (!reactRoot) { + const root = document.getElementById('react-root'); + reactRoot = createRoot(root); + } + /* eslint-disable react/no-danger */ - render( + reactRoot.render( , childNode, ); - /* eslint-enable react/no-danger */ } // Highlight text @@ -455,15 +462,9 @@ class ChatRenderer { message.node = node; // Query all possible selectors to find out the message type if (!message.type) { - // IE8: Does not support querySelector on elements that - // are not yet in the document. - - const typeDef = - !Byond.IS_LTE_IE8 && - MESSAGE_TYPES.find( - (typeDef) => - typeDef.selector && node.querySelector(typeDef.selector), - ); + const typeDef = MESSAGE_TYPES.find( + (typeDef) => typeDef.selector && node.querySelector(typeDef.selector), + ); message.type = typeDef?.type || MESSAGE_TYPE_UNKNOWN; } updateMessageBadge(message); @@ -486,7 +487,7 @@ class ChatRenderer { this.rootNode.appendChild(fragment); } if (this.scrollTracking) { - setImmediate(() => this.scrollToBottom()); + setTimeout(() => this.scrollToBottom()); } } // Notify listeners that we have processed the batch @@ -586,10 +587,6 @@ class ChatRenderer { } saveToDisk() { - // Allow only on IE11 - if (Byond.IS_LTE_IE10) { - return; - } // Compile currently loaded stylesheets as CSS text let cssText = ''; const styleSheets = document.styleSheets; diff --git a/tgui/packages/tgui-panel/panelFocus.js b/tgui/packages/tgui-panel/panelFocus.js index b7cea2293149e..8cff4a361b3eb 100644 --- a/tgui/packages/tgui-panel/panelFocus.js +++ b/tgui/packages/tgui-panel/panelFocus.js @@ -15,7 +15,7 @@ import { focusMap } from 'tgui/focus'; // text you can select with the mouse. const MIN_SELECTION_DISTANCE = 10; -const deferredFocusMap = () => setImmediate(() => focusMap()); +const deferredFocusMap = () => setTimeout(() => focusMap()); export const setupPanelFocusHacks = () => { let focusStolen = false; diff --git a/tgui/packages/tgui-polyfill/byondutils.js b/tgui/packages/tgui-polyfill/byondutils.js new file mode 100644 index 0000000000000..f04e5137296d3 --- /dev/null +++ b/tgui/packages/tgui-polyfill/byondutils.js @@ -0,0 +1,488 @@ +(function () { + // Utility functions + let hasOwn = Object.prototype.hasOwnProperty; + // todo: remove + let assign = function (target) { + for (let i = 1; i < arguments.length; i++) { + let source = arguments[i]; + for (let key in source) { + if (hasOwn.call(source, key)) { + target[key] = source[key]; + } + } + } + return target; + }; + let parseMetaTag = function (name) { + let content = document.getElementById(name).getAttribute('content'); + if (content === '[' + name + ']') { + return null; + } + return content; + }; + + // BYOND API object + // ------------------------------------------------------ + + let Byond = (window.Byond = {}); + + // Expose inlined metadata + Byond.windowId = parseMetaTag('tgui:windowId'); + + // Backwards compatibility + window.__windowId__ = Byond.windowId; + + // Trident engine version + // todo: remove + Byond.TRIDENT = (function () { + let groups = navigator.userAgent.match(/Trident\/(\d+).+?;/i); + let majorVersion = groups && groups[1]; + return majorVersion ? parseInt(majorVersion, 10) : null; + })(); + + // Blink engine version + Byond.BLINK = (function () { + let groups = navigator.userAgent.match(/Chrome\/(\d+)\./); + let majorVersion = groups && groups[1]; + return majorVersion ? parseInt(majorVersion, 10) : null; + })(); + + // Basic checks to detect whether this page runs in BYOND + // todo: remoe trident + let isByond = + (Byond.TRIDENT !== null || Byond.BLINK !== null || window.cef_to_byond) && + location.hostname === '127.0.0.1' && + location.search !== '?external'; + // As of BYOND 515 the path doesn't seem to include tmp dir anymore if you're trying to open tgui in external browser and looking why it doesn't work + // && location.pathname.indexOf('/tmp') === 0 + + // Version constants + Byond.IS_BYOND = isByond; + + // Strict mode flag + Byond.strictMode = Boolean(Number(parseMetaTag('tgui:strictMode'))); + + // Callbacks for asynchronous calls + Byond.__callbacks__ = []; + + // Reviver for BYOND JSON + let byondJsonReviver = function (key, value) { + if (typeof value === 'object' && value !== null && value.__number__) { + return parseFloat(value.__number__); + } + return value; + }; + + // Makes a BYOND call. + // See: https://secure.byond.com/docs/ref/skinparams.html + Byond.call = function (path, params) { + // Not running in BYOND, abort. + if (!isByond) { + return; + } + // Build the URL + let url = (path || '') + '?'; + let i = 0; + if (params) { + for (let key in params) { + if (hasOwn.call(params, key)) { + if (i++ > 0) { + url += '&'; + } + let value = params[key]; + if (value === null || value === undefined) { + value = ''; + } + url += encodeURIComponent(key) + '=' + encodeURIComponent(value); + } + } + } + + // If we're a Chromium client, just use the fancy method + if (window.cef_to_byond) { + cef_to_byond('byond://' + url); + return; + } + + // Perform a standard call via location.href + // todo: remove + if (url.length < 2048) { + location.href = 'byond://' + url; + return; + } + // Send an HTTP request to DreamSeeker's HTTP server. + // Allows sending much bigger payloads. + let xhr = new XMLHttpRequest(); + xhr.open('GET', url); + xhr.send(); + }; + + Byond.callAsync = function (path, params) { + if (!window.Promise) { + throw new Error('Async calls require API level of ES2015 or later.'); + } + let index = Byond.__callbacks__.length; + let promise = new window.Promise((resolve) => { + Byond.__callbacks__.push(resolve); + }); + Byond.call( + path, + assign({}, params, { + callback: 'Byond.__callbacks__[' + index + ']', + }), + ); + return promise; + }; + + Byond.topic = function (params) { + return Byond.call('', params); + }; + + Byond.command = function (command) { + return Byond.call('winset', { + command: command, + }); + }; + + Byond.winget = function (id, propName) { + if (id === null) { + id = ''; + } + let isArray = propName instanceof Array; + let isSpecific = propName && propName !== '*' && !isArray; + let promise = Byond.callAsync('winget', { + id: id, + property: (isArray && propName.join(',')) || propName || '*', + }); + if (isSpecific) { + promise = promise.then((props) => { + return props[propName]; + }); + } + return promise; + }; + + Byond.winset = function (id, propName, propValue) { + if (id === null) { + id = ''; + } else if (typeof id === 'object') { + return Byond.call('winset', id); + } + let props = {}; + if (typeof propName === 'string') { + props[propName] = propValue; + } else { + assign(props, propName); + } + props.id = id; + return Byond.call('winset', props); + }; + + Byond.parseJson = function (json) { + try { + return JSON.parse(json, byondJsonReviver); + } catch (err) { + throw new Error('JSON parsing error: ' + (err && err.message)); + } + }; + + Byond.sendMessage = function (type, payload) { + let message = + typeof type === 'string' ? { type: type, payload: payload } : type; + // JSON-encode the payload + if (message.payload !== null && message.payload !== undefined) { + message.payload = JSON.stringify(message.payload); + } + // Append an identifying header + assign(message, { + tgui: 1, + window_id: Byond.windowId, + }); + Byond.topic(message); + }; + + // This function exists purely for debugging, do not use it in code! + Byond.injectMessage = function (type, payload) { + window.update(JSON.stringify({ type: type, payload: payload })); + }; + + Byond.subscribe = function (listener) { + window.update.flushQueue(listener); + window.update.listeners.push(listener); + }; + + Byond.subscribeTo = function (type, listener) { + let _listener = function (_type, payload) { + if (_type === type) { + listener(payload); + } + }; + window.update.flushQueue(_listener); + window.update.listeners.push(_listener); + }; + + // Asset loaders + // ------------------------------------------------------ + + let RETRY_ATTEMPTS = 5; + let RETRY_WAIT_INITIAL = 500; + let RETRY_WAIT_INCREMENT = 500; + + let loadedAssetByUrl = {}; + + let isStyleSheetLoaded = function (node, url) { + let styleSheet = node.sheet; + if (styleSheet) { + return styleSheet.rules.length > 0; + } + return false; + }; + + let injectNode = function (node) { + if (!document.body) { + // todo: replace with DOMContentLoaded + setTimeout(() => { + injectNode(node); + }); + // document.addEventListener('DOMContentLoaded', () => { + // injectNode(node); + // }); + return; + } + let refs = document.body.childNodes; + let ref = refs[refs.length - 1]; + ref.parentNode.insertBefore(node, ref.nextSibling); + }; + + let loadAsset = function (options) { + let url = options.url; + let type = options.type; + let sync = options.sync; + let attempt = options.attempt || 0; + if (loadedAssetByUrl[url]) { + return; + } + loadedAssetByUrl[url] = options; + // Generic retry function + let retry = function () { + if (attempt >= RETRY_ATTEMPTS) { + let errorMessage = + 'Error: Failed to load the asset ' + + "'" + + url + + "' after several attempts."; + if (type === 'css') { + errorMessage += + +'\nStylesheet was either not found, ' + + "or you're trying to load an empty stylesheet " + + 'that has no CSS rules in it.'; + } + throw new Error(errorMessage); + } + setTimeout( + () => { + loadedAssetByUrl[url] = null; + options.attempt += 1; + loadAsset(options); + }, + RETRY_WAIT_INITIAL + attempt * RETRY_WAIT_INCREMENT, + ); + }; + // JS specific code + if (type === 'js') { + let node = document.createElement('script'); + node.type = 'text/javascript'; + node.crossOrigin = 'anonymous'; + node.src = url; + if (sync) { + node.defer = true; + } else { + node.async = true; + } + node.onerror = function () { + node.onerror = null; + node.parentNode.removeChild(node); + node = null; + retry(); + }; + injectNode(node); + return; + } + // CSS specific code + if (type === 'css') { + let node = document.createElement('link'); + node.type = 'text/css'; + node.rel = 'stylesheet'; + node.href = url; + // Temporarily set media to something inapplicable + // to ensure it'll fetch without blocking render + if (!sync) { + node.media = 'only x'; + } + node.onload = function () { + node.onload = null; + if (isStyleSheetLoaded(node, url)) { + // Render the stylesheet + node.media = 'all'; + return; + } + // Try again + node.parentNode.removeChild(node); + node = null; + retry(); + }; + injectNode(node); + return; + } + }; + + Byond.loadJs = function (url, sync) { + loadAsset({ url: url, sync: sync, type: 'js' }); + }; + + Byond.loadCss = function (url, sync) { + loadAsset({ url: url, sync: sync, type: 'css' }); + }; +})(); + +// Error handling +// ------------------------------------------------------ + +window.onerror = function (msg, url, line, col, error) { + window.onerror.errorCount = (window.onerror.errorCount || 0) + 1; + // Proper stacktrace + let stack = error && error.stack; + // Ghetto stacktrace + if (!stack) { + stack = msg + '\n at ' + url + ':' + line; + if (col) { + stack += ':' + col; + } + } + // Augment the stack + stack = window.__augmentStack__(stack, error); + // Print error to the page + if (Byond.strictMode) { + let errorRoot = document.getElementById('FatalError'); + let errorStack = document.getElementById('FatalError__stack'); + if (errorRoot) { + errorRoot.className = 'FatalError FatalError--visible'; + if (window.onerror.__stack__) { + window.onerror.__stack__ += '\n\n' + stack; + } else { + window.onerror.__stack__ = stack; + } + let textProp = 'textContent'; + errorStack[textProp] = window.onerror.__stack__; + } + // Set window geometry + let setFatalErrorGeometry = function () { + Byond.winset(Byond.windowId, { + titlebar: true, + 'is-visible': true, + 'can-resize': true, + }); + }; + setFatalErrorGeometry(); + setInterval(setFatalErrorGeometry, 1000); + } + // Send logs to the game server + if (Byond.strictMode) { + Byond.sendMessage({ + type: 'log', + fatal: 1, + message: stack, + }); + } else if (window.onerror.errorCount <= 1) { + stack += '\nWindow is in non-strict mode, future errors are suppressed.'; + Byond.sendMessage({ + type: 'log', + message: stack, + }); + } + // Short-circuit further updates + if (Byond.strictMode) { + window.update = function () {}; + window.update.queue = []; + } + // Prevent default action + return true; +}; + +// Catch unhandled promise rejections +window.onunhandledrejection = function (e) { + let msg = 'UnhandledRejection'; + if (e.reason) { + msg += ': ' + (e.reason.message || e.reason.description || e.reason); + if (e.reason.stack) { + e.reason.stack = 'UnhandledRejection: ' + e.reason.stack; + } + } + window.onerror(msg, null, null, null, e.reason); +}; + +// Helper for augmenting stack traces on fatal errors +window.__augmentStack__ = function (stack, error) { + return stack + '\nUser Agent: ' + navigator.userAgent; +}; + +// Incoming message handling +// ------------------------------------------------------ + +// Message handler +window.update = function (rawMessage) { + // Push onto the queue (active during initialization) + if (window.update.queueActive) { + window.update.queue.push(rawMessage); + return; + } + // Parse the message + let message = Byond.parseJson(rawMessage); + // Notify listeners + let listeners = window.update.listeners; + for (let i = 0; i < listeners.length; i++) { + listeners[i](message.type, message.payload); + } +}; + +// Properties and variables of this specific handler +window.update.listeners = []; +window.update.queue = []; +window.update.queueActive = true; +window.update.flushQueue = function (listener) { + // Disable and clear the queue permanently on short delay + if (window.update.queueActive) { + window.update.queueActive = false; + if (window.setTimeout) { + window.setTimeout(() => { + window.update.queue = []; + }, 0); + } + } + // Process queued messages on provided listener + let queue = window.update.queue; + for (let i = 0; i < queue.length; i++) { + let message = Byond.parseJson(queue[i]); + listener(message.type, message.payload); + } +}; + +window.replaceHtml = function (inline_html) { + let children = document.body.childNodes; + + for (let i = 0; i < children.length; i++) { + if (children[i].nodeValue === ' tgui:inline-html-start ') { + while (children[i].nodeValue !== ' tgui:inline-html-end ') { + children[i].remove(); + } + children[i].remove(); + } + } + + document.body.insertAdjacentHTML( + 'afterbegin', + '' + + inline_html + + '', + ); +}; diff --git a/tgui/packages/tgui-polyfill/package.json b/tgui/packages/tgui-polyfill/package.json index 30f4b6d970027..324a434564c0a 100644 --- a/tgui/packages/tgui-polyfill/package.json +++ b/tgui/packages/tgui-polyfill/package.json @@ -3,7 +3,8 @@ "name": "tgui-polyfill", "version": "5.0.1", "scripts": { - "tgui-polyfill:build": "terser 1-misc.js -f ascii_only,comments=false -o ../../public/tgui-polyfill.min.js" + "tgui-polyfill:build": "terser 1-misc.js -f ascii_only,comments=false -o ../../public/tgui-polyfill.min.js", + "tgui-polyfill:utils": "terser utils.js -f ascii_only,comments=false -o ../../public/utils.min.js" }, "dependencies": { "core-js": "^3.36.1", diff --git a/tgui/packages/tgui-say/index.tsx b/tgui/packages/tgui-say/index.tsx index d902ae85cdf84..9757cca4ff4c1 100644 --- a/tgui/packages/tgui-say/index.tsx +++ b/tgui/packages/tgui-say/index.tsx @@ -1,21 +1,18 @@ import './styles/main.scss'; -import { createRenderer } from 'tgui/renderer'; +import { createRoot, Root } from 'react-dom/client'; import { TguiSay } from './TguiSay'; -const renderApp = createRenderer(() => { - return ; -}); +let reactRoot: Root | null = null; -const setupApp = () => { - // Delay setup - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', setupApp); - return; +document.onreadystatechange = function () { + if (document.readyState !== 'complete') return; + + if (!reactRoot) { + const root = document.getElementById('react-root'); + reactRoot = createRoot(root!); } - renderApp(); + reactRoot.render(); }; - -setupApp(); diff --git a/tgui/packages/tgui-say/package.json b/tgui/packages/tgui-say/package.json index da9ff074d4b0a..55410500e586c 100644 --- a/tgui/packages/tgui-say/package.json +++ b/tgui/packages/tgui-say/package.json @@ -4,8 +4,10 @@ "version": "1.0.0", "dependencies": { "@types/react": "^18.2.74", + "@types/react-dom": "^18.2.24", "common": "workspace:*", "react": "^18.2.0", + "react-dom": "^18.2.0", "tgui": "workspace:*", "tgui-polyfill": "workspace:*" } diff --git a/tgui/packages/tgui/backend.ts b/tgui/packages/tgui/backend.ts index bf75306108a4d..c85d515321020 100644 --- a/tgui/packages/tgui/backend.ts +++ b/tgui/packages/tgui/backend.ts @@ -177,7 +177,7 @@ export const backendMiddleware = (store) => { Byond.winset(Byond.windowId, { 'is-visible': false, }); - setImmediate(() => focusMap()); + setTimeout(() => focusMap()); } if (type === 'backend/update') { @@ -207,7 +207,7 @@ export const backendMiddleware = (store) => { setupDrag(); // We schedule this for the next tick here because resizing and unhiding // during the same tick will flash with a white background. - setImmediate(() => { + setTimeout(() => { perf.mark('resume/start'); // Doublecheck if we are not re-suspended. const { suspended } = selectBackend(store.getState()); diff --git a/tgui/packages/tgui/components/Flex.tsx b/tgui/packages/tgui/components/Flex.tsx index 50dba27795871..41ea6bd8275af 100644 --- a/tgui/packages/tgui/components/Flex.tsx +++ b/tgui/packages/tgui/components/Flex.tsx @@ -23,8 +23,6 @@ export const computeFlexClassName = (props: FlexProps) => { return classes([ 'Flex', props.inline && 'Flex--inline', - Byond.IS_LTE_IE10 && 'Flex--iefix', - Byond.IS_LTE_IE10 && props.direction === 'column' && 'Flex--iefix--column', computeBoxClassName(props), ]); }; @@ -65,11 +63,7 @@ export type FlexItemProps = BoxProps & }>; export const computeFlexItemClassName = (props: FlexItemProps) => { - return classes([ - 'Flex__item', - Byond.IS_LTE_IE10 && 'Flex__item--iefix', - computeBoxClassName(props), - ]); + return classes(['Flex__item', computeBoxClassName(props)]); }; export const computeFlexItemProps = (props: FlexItemProps) => { diff --git a/tgui/packages/tgui/stories/ByondUi.stories.jsx b/tgui/packages/tgui/stories/ByondUi.stories.jsx index 0a97be11da764..2203fef23ca2e 100644 --- a/tgui/packages/tgui/stories/ByondUi.stories.jsx +++ b/tgui/packages/tgui/stories/ByondUi.stories.jsx @@ -34,7 +34,7 @@ const Story = (props) => { + + + ))} + ); }; @@ -473,17 +525,17 @@ const SnowflakeSyringe = (props) => { } = props.module.snowflake; return ( <> - + {`${syringe} of ${max_syringe}`} - + {`${reagents} of ${total_reagents} units`} - + ) } > - {!hasBeaker && ( + {!beaker ? ( No beaker loaded. - )} - {!!hasBeaker && beakerCurrentVolume === 0 && ( + ) : beaker.currentVolume === 0 ? ( Beaker is empty. + ) : ( + + {beaker.contents.map((chemical) => ( + + ))} +
)} - - {beakerContents.map((chemical) => ( - - ))} -

- - {` / ${bufferMaxVolume} units`} + + {` / ${buffer.maxVolume} units`} } > - {bufferContents.length === 0 && ( + {buffer_contents.length === 0 ? ( Buffer is empty. + ) : ( + + {buffer_contents.map((chemical) => ( + + ))} +
)} - - {bufferContents.map((chemical) => ( - - ))} -
{!isPrinting && (
+ + setShowPreferredContainer((currentValue) => !currentValue) + } + > + Suggest + { setItemCount(value); }} @@ -200,51 +208,36 @@ const ChemMasterContent = (props) => { Math.round( Math.min( selectedContainerVolume, - bufferCurrentVolume / itemCount, + buffer.currentVolume / itemCount, ) * 100, ) / 100 } u. each`} - ) : ( -
@@ -256,9 +249,10 @@ const ChemMasterContent = (props) => { } > { ); }; -const ReagentEntry = (props) => { +type ReagentProps = { + chemical: AnalyzableReagent; + transferTo: string; + analyze: (chemical: AnalyzableReagent) => void; +}; + +const ReagentEntry = (props: ReagentProps) => { const { data, act } = useBackend(); - const { chemical, transferTo } = props; + const { chemical, transferTo, analyze } = props; const { isPrinting } = data; return ( @@ -295,7 +295,6 @@ const ReagentEntry = (props) => { } > @@ -438,7 +454,6 @@ const AnalysisResults = (props) => { {pH} - {state} {color} diff --git a/tgui/packages/tgui/interfaces/common/BeakerDisplay.tsx b/tgui/packages/tgui/interfaces/common/BeakerDisplay.tsx index 6c2d364932538..3483c3ceede80 100644 --- a/tgui/packages/tgui/interfaces/common/BeakerDisplay.tsx +++ b/tgui/packages/tgui/interfaces/common/BeakerDisplay.tsx @@ -8,7 +8,7 @@ import { Section, } from '../../components'; -type BeakerReagent = { +export type BeakerReagent = { name: string; volume: number; }; From ce23a59c3681b228e7b9b254cb57dd4aa55fd885 Mon Sep 17 00:00:00 2001 From: Watermelon914 <37270891+Watermelon914@users.noreply.github.com> Date: Wed, 10 Apr 2024 19:10:30 +0000 Subject: [PATCH 140/938] Cleans up the SS13_base lua file and adds a new lua file for easily handling multiple signals on different objects. (#82458) ## About The Pull Request Cleaned up the SS13.register_signal and SS13.unregister_signal, removing the weird list shifting. Also adds a new lua file that can be included for the use of registering different signals on various datums and being able to clear them all in 1 function. Removed the make_easy_clear_function option when registering a signal via lua because I don't think it's used by anyone and it lacks any sort of versatility. Users can just create their own function for clearing signals from a datum. Also updates the documentation for HARDDELETES.md as COMSIG_PARENT_QDELETING was renamed to COMSIG_QDELETING ## Why It's Good For The Game New handler file makes registering signals in batches a lot easier if you want to clear them in one go without clearing unrelated callbacks on the same datum. The list shifting in SS13.register_signal had pretty significant performance problems, so removing that will make registering and unregistering signals faster. ## Changelog :cl: admin: LUA - Adds a new library called handler_group. Include it in your files by doing require('handler_group') /:cl: --------- Co-authored-by: Watermelon914 <3052169-Watermelon914@users.noreply.gitlab.com> --- .github/guides/HARDDELETES.md | 6 +- code/modules/admin/verbs/lua/lua_state.dm | 9 +- lua/SS13_base.lua | 122 ++++++++++------------ lua/docs/handler_group.md | 66 ++++++++++++ lua/handler_group.lua | 49 +++++++++ lua/state.lua | 9 ++ lua/timer.lua | 10 +- 7 files changed, 188 insertions(+), 83 deletions(-) create mode 100644 lua/docs/handler_group.md create mode 100644 lua/handler_group.lua create mode 100644 lua/state.lua diff --git a/.github/guides/HARDDELETES.md b/.github/guides/HARDDELETES.md index defc09360af68..cdbdb2a126d68 100644 --- a/.github/guides/HARDDELETES.md +++ b/.github/guides/HARDDELETES.md @@ -243,7 +243,7 @@ So then, we want to temporarily remember to clear a reference when it's deleted This is where I might lose you, but we're gonna use signals -`qdel()`, the proc that sets off this whole deletion business, sends a signal called `COMSIG_PARENT_QDELETING` +`qdel()`, the proc that sets off this whole deletion business, sends a signal called `COMSIG_QDELETING` We can listen for that signal, and if we hear it clear whatever reference we may have @@ -255,10 +255,10 @@ Here's an example /somemob/proc/set_target(new_target) if(target) - UnregisterSignal(target, COMSIG_PARENT_QDELETING) //We need to make sure any old signals are cleared + UnregisterSignal(target, COMSIG_QDELETING) //We need to make sure any old signals are cleared target = new_target if(target) - RegisterSignal(target, COMSIG_PARENT_QDELETING, PROC_REF(clear_target)) //Call clear_target if target is ever qdel()'d + RegisterSignal(target, COMSIG_QDELETING, PROC_REF(clear_target)) //Call clear_target if target is ever qdel()'d /somemob/proc/clear_target(datum/source) SIGNAL_HANDLER diff --git a/code/modules/admin/verbs/lua/lua_state.dm b/code/modules/admin/verbs/lua/lua_state.dm index ee7d6953e12ac..27994d966a7cb 100644 --- a/code/modules/admin/verbs/lua/lua_state.dm +++ b/code/modules/admin/verbs/lua/lua_state.dm @@ -109,14 +109,7 @@ GLOBAL_PROTECT(lua_usr) if(islist(function)) var/list/new_function_path = list() for(var/path_element in function) - if(isweakref(path_element)) - var/datum/weakref/weak_ref = path_element - var/resolved = weak_ref.hard_resolve() - if(!resolved) - return list("status" = "errored", "param" = "Weakref in function path ([weak_ref] [text_ref(weak_ref)]) resolved to null.", "name" = jointext(function, ".")) - new_function_path += resolved - else - new_function_path += path_element + new_function_path += path_element function = new_function_path var/msg = "[key_name(usr)] called the lua function \"[function]\" with arguments: [english_list(call_args)]" log_lua(msg) diff --git a/lua/SS13_base.lua b/lua/SS13_base.lua index ddacb345fd5c4..4bdd49d5d9052 100644 --- a/lua/SS13_base.lua +++ b/lua/SS13_base.lua @@ -1,3 +1,6 @@ +local timer = require("timer") +local state = require("state") + local SS13 = {} __SS13_signal_handlers = __SS13_signal_handlers or {} @@ -6,12 +9,7 @@ SS13.SSlua = dm.global_vars.vars.SSlua SS13.global_proc = "some_magic_bullshit" -for _, state in SS13.SSlua.vars.states do - if state.vars.internal_id == dm.state_id then - SS13.state = state - break - end -end +SS13.state = state.state function SS13.get_runner_ckey() return SS13.state:get_var("ckey_last_runner") @@ -25,12 +23,16 @@ function SS13.istype(thing, type) return dm.global_proc("_istype", thing, dm.global_proc("_text2path", type)) == 1 end +function SS13.start_tracking(datum) + local references = SS13.state.vars.references + references:add(datum) + SS13.state:call_proc("clear_on_delete", datum) +end + function SS13.new(type, ...) - local datum = SS13.new_untracked(type, table.unpack({...})) + local datum = SS13.new_untracked(type, ...) if datum then - local references = SS13.state.vars.references - references:add(datum) - SS13.state:call_proc("clear_on_delete", datum) + SS13.start_tracking(datum) return datum end end @@ -75,58 +77,40 @@ function SS13.await(thing_to_call, proc_to_call, ...) return return_value, runtime_message end -function SS13.register_signal(datum, signal, func, make_easy_clear_function) +function SS13.register_signal(datum, signal, func) if not SS13.istype(datum, "/datum") then return end - if not __SS13_signal_handlers[datum] then - __SS13_signal_handlers[datum] = {} + local datumWeakRef = dm.global_proc("WEAKREF", datum) + if not __SS13_signal_handlers[datumWeakRef] then + __SS13_signal_handlers[datumWeakRef] = {} end if signal == "_cleanup" then return end - if not __SS13_signal_handlers[datum][signal] then - __SS13_signal_handlers[datum][signal] = {} + if not __SS13_signal_handlers[datumWeakRef][signal] then + __SS13_signal_handlers[datumWeakRef][signal] = {} end local callback = SS13.new("/datum/callback", SS13.state, "call_function_return_first") + local callbackWeakRef = dm.global_proc("WEAKREF", callback) callback:call_proc("RegisterSignal", datum, signal, "Invoke") - local path = { "__SS13_signal_handlers", dm.global_proc("WEAKREF", datum), signal, dm.global_proc("WEAKREF", callback), "func" } + local path = { "__SS13_signal_handlers", datumWeakRef, signal, callbackWeakRef, "func" } callback.vars.arguments = { path } - if not __SS13_signal_handlers[datum]["_cleanup"] then - local cleanup_path = { "__SS13_signal_handlers", dm.global_proc("WEAKREF", datum), "_cleanup", "func" } - local cleanup_callback = SS13.new("/datum/callback", SS13.state, "call_function_return_first", cleanup_path) - cleanup_callback:call_proc("RegisterSignal", datum, "parent_qdeleting", "Invoke") - __SS13_signal_handlers[datum]["_cleanup"] = { - func = function(datum) - SS13.signal_handler_cleanup(datum) - SS13.stop_tracking(cleanup_callback) - end, - callback = cleanup_callback, - } - end - if signal == "parent_qdeleting" then --We want to make sure that the cleanup function is the very last signal handler called. - local comp_lookup = datum.vars._listen_lookup - if comp_lookup then - local lookup_for_signal = comp_lookup.entries.parent_qdeleting - if lookup_for_signal and not SS13.istype(lookup_for_signal, "/datum") then - local cleanup_callback_index = - dm.global_proc("_list_find", lookup_for_signal, __SS13_signal_handlers[datum]["_cleanup"].callback) - if cleanup_callback_index ~= 0 and cleanup_callback_index ~= #comp_lookup then - dm.global_proc("_list_swap", lookup_for_signal, cleanup_callback_index, #lookup_for_signal) - end - end - end - end - __SS13_signal_handlers[datum][signal][callback] = { func = func, callback = callback } - if make_easy_clear_function then - local clear_function_name = "clear_signal_" .. tostring(datum) .. "_" .. signal .. "_" .. tostring(callback) - SS13[clear_function_name] = function() - if callback then - SS13.unregister_signal(datum, signal, callback) - end - SS13[clear_function_name] = nil + if not __SS13_signal_handlers[datumWeakRef]._cleanup then + local cleanupCallback = SS13.new("/datum/callback", SS13.state, "call_function_return_first") + local cleanupPath = { "__SS13_signal_handlers", datumWeakRef, "_cleanup"} + cleanupCallback.vars.arguments = { cleanupPath } + cleanupCallback:call_proc("RegisterSignal", datum, "parent_qdeleting", "Invoke") + __SS13_signal_handlers[datumWeakRef]._cleanup = function(datum) + SS13.start_tracking(datumWeakRef) + timer.set_timeout(0, function() + SS13.signal_handler_cleanup(datumWeakRef) + SS13.stop_tracking(cleanupCallback) + SS13.stop_tracking(datumWeakRef) + end) end end + __SS13_signal_handlers[datumWeakRef][signal][callbackWeakRef] = { func = func, callback = callback } return callback end @@ -143,51 +127,53 @@ function SS13.unregister_signal(datum, signal, callback) return end local handler_callback = handler_info.callback - handler_callback:call_proc("UnregisterSignal", datum, signal) + local callbackWeakRef = dm.global_proc("WEAKREF", handler_callback) + if not SS13.istype(datum, "/datum/weakref") then + handler_callback:call_proc("UnregisterSignal", datum, signal) + end SS13.stop_tracking(handler_callback) end - local function clear_easy_clear_function(callback_to_clear) - local clear_function_name = "clear_signal_" .. tostring(datum) .. "_" .. signal .. "_" .. tostring(callback_to_clear) - SS13[clear_function_name] = nil + local datumWeakRef = datum + if not SS13.istype(datum, "/datum/weakref") then + datumWeakRef = dm.global_proc("WEAKREF", datum) end - - if not __SS13_signal_handlers[datum] then + if not __SS13_signal_handlers[datumWeakRef] then return end + if signal == "_cleanup" then return end - if not __SS13_signal_handlers[datum][signal] then + + if not __SS13_signal_handlers[datumWeakRef][signal] then return end if not callback then - for handler_key, handler_info in __SS13_signal_handlers[datum][signal] do - clear_easy_clear_function(handler_key) + for handler_key, handler_info in __SS13_signal_handlers[datumWeakRef][signal] do clear_handler(handler_info) end - __SS13_signal_handlers[datum][signal] = nil + __SS13_signal_handlers[datumWeakRef][signal] = nil else if not SS13.istype(callback, "/datum/callback") then return end - clear_easy_clear_function(callback) - clear_handler(__SS13_signal_handlers[datum][signal][callback]) - __SS13_signal_handlers[datum][signal][callback] = nil + local callbackWeakRef = dm.global_proc("WEAKREF", callback) + clear_handler(__SS13_signal_handlers[datumWeakRef][signal][callbackWeakRef]) + __SS13_signal_handlers[datumWeakRef][signal][callbackWeakRef] = nil end end -function SS13.signal_handler_cleanup(datum) - if not __SS13_signal_handlers[datum] then +function SS13.signal_handler_cleanup(datumWeakRef) + if not __SS13_signal_handlers[datumWeakRef] then return end - for signal, _ in __SS13_signal_handlers[datum] do - SS13.unregister_signal(datum, signal) + for signal, _ in __SS13_signal_handlers[datumWeakRef] do + SS13.unregister_signal(datumWeakRef, signal) end - - __SS13_signal_handlers[datum] = nil + __SS13_signal_handlers[datumWeakRef] = nil end return SS13 diff --git a/lua/docs/handler_group.md b/lua/docs/handler_group.md new file mode 100644 index 0000000000000..7856ff58b4859 --- /dev/null +++ b/lua/docs/handler_group.md @@ -0,0 +1,66 @@ +# Handler Group + +This module is for registering signals on a datum or several datums and being able to clear them all at once without having to unregister them manually. This is particularly useful if you register signals on a datum and need to clear them later without accidentally unregistering unrelated signals + +## Functions + +### HandlerGroup.new() +Creates a new handler group instance + +### HandlerGroup:register_signal(datum, signal, func) +Registers a signal on a datum, exactly the same as `SS13.register_signal` + +### HandlerGroup:clear() +Clears all registered signals that have been registered by this handler group. + +### HandlerGroup:clear_on(datum, signal, func) +Clears all registered signals that have been registered by this handler group when a signal is called on the specified datum. Additionally, a function can be ran before it is cleared + +### HandlerGroup.register_once(datum, signal func) +Identical to just creating a new HandlerGroup instance and calling `clear_on(datum, signal, func)`. + +The idea is to register a signal and clear it after it has been called once. + +## Examples + +The following examples showcase why using handler groups can make life easier in specific situations. + +### Explode when mob enters location +This function creates a 1 tile-wide explosion at the specified location if a specific mob walks over it. The explosion won't happen if the mob dies. This function should be callable on the same mob for different locations. The function should be self-contained, it should not affect other registered signals that the mob may have registered. + +#### Without Handler Groups +```lua +local function explodeAtLocation(mobVar, position) + local deathCallback + local moveCallback + local function unlinkFromMob() + SS13.unregister_signal(mobVar, "living_death", deathCallback) + SS13.unregister_signal(mobVar, "movable_moved", moveCallback) + end + deathCallback = SS13.register_signal(mobVar, "living_death", function(_, gibbed) + unlinkFromMob() + end) + moveCallback = SS13.register_signal(mobVar, "movable_moved", function(_, oldLoc) + if mobVar:get_var("loc") == position then + -- Creates a 1 tile-wide explosion at the specified position + dm.global_proc("explosion", position, 1, 0, 0) + unlinkFromMob() + end + end) +end +``` + +#### With Handler Groups +```lua +local function explodeAtLocation(mobVar, position) + local handler = handler_group.new() + handler:clear_on(mobVar, "living_death") + handler:register_signal(mobVar, "movable_moved", function(_, oldLoc) + if mobVar:get_var("loc") == position then + -- Creates a 1 tile-wide explosion at the specified position + dm.global_proc("explosion", position, 1, 0, 0) + handler:clear() + end + end) +end +``` diff --git a/lua/handler_group.lua b/lua/handler_group.lua new file mode 100644 index 0000000000000..fff63ad18e427 --- /dev/null +++ b/lua/handler_group.lua @@ -0,0 +1,49 @@ +local SS13 = require('SS13') +local HandlerGroup = {} +HandlerGroup.__index = HandlerGroup + +function HandlerGroup.new() + return setmetatable({ + registered = {} + }, HandlerGroup) +end + +-- Registers a signal on a datum for this handler group instance. +function HandlerGroup:register_signal(datum, signal, func) + local callback = SS13.register_signal(datum, signal, func) + if not callback then + return + end + table.insert(self.registered, { datum = datum, signal = signal, callback = callback }) +end + +-- Clears all the signals that have been registered on this HandlerGroup +function HandlerGroup:clear() + for _, data in self.registered do + if not data.callback or not data.datum then + continue + end + SS13.unregister_signal(data.datum, data.signal, data.callback) + end + table.clear(self.registered) +end + +-- Clears all the signals that have been registered on this HandlerGroup when a specific signal is sent on a datum. +function HandlerGroup:clear_on(datum, signal, func) + SS13.register_signal(datum, signal, function(...) + if func then + func(...) + end + self:clear() + end) +end + +-- Registers a signal on a datum and clears it after it is called once. +function HandlerGroup.register_once(datum, signal, func) + local callback = HandlerGroup.new() + callback:clear_on(datum, signal, func) + return callback +end + + +return HandlerGroup diff --git a/lua/state.lua b/lua/state.lua new file mode 100644 index 0000000000000..080ee9f7eb32c --- /dev/null +++ b/lua/state.lua @@ -0,0 +1,9 @@ +local SSlua = dm.global_vars:get_var("SSlua") + +for _, state in SSlua:get_var("states") do + if state:get_var("internal_id") == dm.state_id then + return { state = state } + end +end + +return { state = nil } diff --git a/lua/timer.lua b/lua/timer.lua index 605e5b98a2e5c..8619bbb54a29e 100644 --- a/lua/timer.lua +++ b/lua/timer.lua @@ -1,6 +1,8 @@ -local SS13 = require("SS13_base") +local state = require("state") + local Timer = {} +local SSlua = dm.global_vars:get_var("SSlua") __Timer_timers = __Timer_timers or {} __Timer_callbacks = __Timer_callbacks or {} @@ -35,7 +37,7 @@ function __stop_internal_timer(func) end __Timer_timer_processing = __Timer_timer_processing or false -SS13.state:set_var("timer_enabled", 1) +state.state:set_var("timer_enabled", 1) __Timer_timer_process = function(seconds_per_tick) if __Timer_timer_processing then return 0 @@ -50,7 +52,7 @@ __Timer_timer_process = function(seconds_per_tick) sleep() end if time >= timeData.executeTime then - SS13.state:get_var("functions_to_execute"):add(func) + state.state:get_var("functions_to_execute"):add(func) timeData.executing = true end end @@ -61,7 +63,7 @@ end function Timer.wait(time) local next_yield_index = __next_yield_index __add_internal_timer(function() - SS13.SSlua:call_proc("queue_resume", SS13.state, next_yield_index) + SSlua:call_proc("queue_resume", state.state, next_yield_index) end, time * 10, false) coroutine.yield() end From a127f1a20bd67ec699b673b0221a308a388349a2 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 11 Apr 2024 07:12:20 +1200 Subject: [PATCH 141/938] Automatic changelog for PR #82507 [ci skip] --- html/changelogs/AutoChangeLog-pr-82507.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82507.yml diff --git a/html/changelogs/AutoChangeLog-pr-82507.yml b/html/changelogs/AutoChangeLog-pr-82507.yml new file mode 100644 index 0000000000000..36059fcae8438 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82507.yml @@ -0,0 +1,4 @@ +author: "SyncIt21" +delete-after: True +changes: + - bugfix: "Autolathe correctly computes the print amount of custom material items like toolboxes and doesn't grey out its print button" \ No newline at end of file From 52e27d88d1969f278e188fc49670ec71da982120 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 11 Apr 2024 07:12:37 +1200 Subject: [PATCH 142/938] Automatic changelog for PR #82002 [ci skip] --- html/changelogs/AutoChangeLog-pr-82002.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82002.yml diff --git a/html/changelogs/AutoChangeLog-pr-82002.yml b/html/changelogs/AutoChangeLog-pr-82002.yml new file mode 100644 index 0000000000000..8ce69499f2a81 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82002.yml @@ -0,0 +1,13 @@ +author: "SyncIt21" +delete-after: True +changes: + - qol: "Adds screen tips & examines for screwdriver, wrench, crowbar & beaker insertion, removal & replacing actions" + - qol: "Analyzing reagents no longer blocks other players from doing other operations. Multiple players can analyze different reagents on the same machine" + - qol: "You cannot do any tool acts on the machine while printing to prevent any side effects." + - qol: "The preferred container for the master reagent in the beaker is now showed in both condiment & chem master. The feature can be enabled/disabled via a check box" + - code_imp: "removed defines for reagent transfer, vars for reagent analyzis to save memory. Autodoc for other vars & procs" + - bugfix: "You can hit the chem master with tools like screwdriver, crowbar, wrench & beaker in combat mode" + - bugfix: "You cannot insert hologram items into the chem master" + - bugfix: "Deconstructing a condiment master will give you the circuit board already pre-programmed with that option" + - bugfix: "You now print the exact amount of containers requested even with upgraded parts without creating empty containers. Max printable containers is 13 with tier 4 parts able to print 50 containers." + - refactor: "Optimized client side UI code & chem master as a whole." \ No newline at end of file From a8ea2910c9bc0c27d2a7fa151365c1f75337cadb Mon Sep 17 00:00:00 2001 From: Hoolny <84478872+SethLafuente@users.noreply.github.com> Date: Wed, 10 Apr 2024 12:18:34 -0700 Subject: [PATCH 143/938] Makes radiaton and bomb good helmets have the FOV effect...... its not my fault (#82366) ## About The Pull Request Fixes Radiation hood having normal vision Closes #80917 ![image](https://github.com/tgstation/tgstation/assets/84478872/81e43edb-7b66-4403-b06d-fa4d256ebc48) ## Why It's Good For The Game It isnt but it must be done in order to remove github issues ## Changelog :cl: fix: Fixes Radiation Hood not having FOV blockage /:cl: --- code/modules/clothing/suits/utility.dm | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/code/modules/clothing/suits/utility.dm b/code/modules/clothing/suits/utility.dm index c867349f6564a..c04b68ab553a8 100644 --- a/code/modules/clothing/suits/utility.dm +++ b/code/modules/clothing/suits/utility.dm @@ -99,6 +99,11 @@ flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH | PEPPERPROOF resistance_flags = NONE +/obj/item/clothing/head/utility/bomb_hood/Initialize(mapload) + . = ..() + if(flags_inv & HIDEFACE) + AddComponent(/datum/component/clothing_fov_visor, FOV_90_DEGREES) + /datum/armor/utility_bomb_hood melee = 20 laser = 20 @@ -169,6 +174,11 @@ flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH | PEPPERPROOF resistance_flags = NONE +/obj/item/clothing/head/utility/radiation/Initialize(mapload) + . = ..() + if(flags_inv & HIDEFACE) + AddComponent(/datum/component/clothing_fov_visor, FOV_90_DEGREES) + /datum/armor/utility_radiation bio = 60 fire = 30 From c403a6ecccc5dadca785d3ab30406686b21bfd8e Mon Sep 17 00:00:00 2001 From: san7890 Date: Wed, 10 Apr 2024 13:19:43 -0600 Subject: [PATCH 144/938] Wraps `lowertext()` to ensure proper stringification. (#82442) ## About The Pull Request Fixes #82440 This PR just creates a new macro, `LOWER_TEXT()` (yes the irony is not lost on me) to wrap around all calls of `lowertext()` and ensure that whatever we input into that proc will be stringified using the `"[]"` (or `tostring()` for the nerds) operator. very simple. I also added a linter to enforce this (and prevent all forms of regression) because I think that machines should do the menial work and we shouldn't expect maintainers to remember this, let me know if you disagree. if there is a time when it should be opted out for some reason, the linter does respect it if you wrap your input with the `UNLINT()` function. --- code/__DEFINES/text.dm | 4 ++++ code/__HELPERS/atmospherics.dm | 4 ++-- code/__HELPERS/chat_filter.dm | 2 +- code/__HELPERS/hearted.dm | 2 +- code/__HELPERS/icons.dm | 2 +- code/__HELPERS/names.dm | 14 +++++++------- code/__HELPERS/reagents.dm | 4 ++-- code/__HELPERS/sanitize_values.dm | 2 +- code/__HELPERS/text.dm | 4 ++-- code/__HELPERS/type2type.dm | 2 +- code/controllers/configuration/config_entry.dm | 8 ++++---- .../controllers/configuration/configuration.dm | 14 +++++++------- .../configuration/entries/resources.dm | 2 +- code/controllers/subsystem/ticker.dm | 4 ++-- code/controllers/subsystem/title.dm | 2 +- code/datums/brain_damage/hypnosis.dm | 2 +- code/datums/brain_damage/mild.dm | 2 +- code/datums/components/cult_ritual_item.dm | 6 +++--- code/datums/components/deadchat_control.dm | 4 ++-- code/datums/components/food/edible.dm | 2 +- .../components/material/material_container.dm | 2 +- code/datums/components/surgery_initiator.dm | 2 +- code/datums/components/uplink.dm | 8 ++++---- code/datums/greyscale/json_reader.dm | 2 +- code/datums/memory/_memory.dm | 2 +- code/datums/quirks/negative_quirks/insanity.dm | 4 ++-- code/datums/station_traits/negative_traits.dm | 2 +- .../status_effects/debuffs/speech_debuffs.dm | 2 +- code/datums/storage/storage.dm | 2 +- code/datums/voice_of_god_command.dm | 4 ++-- code/datums/wounds/bones.dm | 2 +- code/datums/wounds/pierce.dm | 2 +- code/game/atom/atom_color.dm | 8 ++++---- code/game/machinery/camera/camera.dm | 2 +- .../machinery/camera/camera_construction.dm | 2 +- code/game/machinery/computer/camera.dm | 2 +- .../game/machinery/computer/camera_advanced.dm | 2 +- .../dna_infuser/organ_sets/rat_organs.dm | 2 +- .../machinery/porta_turret/portable_turret.dm | 2 +- code/game/objects/items.dm | 2 +- code/game/objects/items/crayons.dm | 2 +- .../items/devices/radio/encryptionkey.dm | 2 +- .../objects/items/devices/radio/headset.dm | 4 ++-- .../items/devices/scanners/gas_analyzer.dm | 4 ++-- .../items/granters/magic/_spell_granter.dm | 2 +- code/game/objects/items/mail.dm | 2 +- code/modules/admin/greyscale_modify_menu.dm | 4 ++-- code/modules/admin/sql_ban_system.dm | 2 +- code/modules/admin/verbs/SDQL2/SDQL_2.dm | 2 +- .../modules/admin/verbs/SDQL2/SDQL_2_parser.dm | 4 ++-- .../admin/verbs/SDQL2/SDQL_2_wrappers.dm | 4 ++-- code/modules/admin/verbs/admingame.dm | 2 +- code/modules/admin/verbs/adminhelp.dm | 4 ++-- code/modules/admin/verbs/adminpm.dm | 2 +- .../admin/verbs/player_ticket_history.dm | 2 +- .../antagonists/disease/disease_datum.dm | 2 +- code/modules/antagonists/malf_ai/malf_ai.dm | 2 +- .../antagonists/traitor/datum_traitor.dm | 2 +- .../traitor/objectives/sabotage_machinery.dm | 2 +- code/modules/art/paintings.dm | 4 ++-- code/modules/awaymissions/zlevel.dm | 4 ++-- code/modules/cargo/bounties/assistant.dm | 2 +- code/modules/client/client_procs.dm | 2 +- code/modules/client/preferences/glasses.dm | 2 +- .../client/preferences/middleware/antags.dm | 2 +- code/modules/emoji/emoji_parse.dm | 6 +++--- code/modules/hydroponics/seeds.dm | 4 ++-- code/modules/instruments/songs/play_legacy.dm | 2 +- .../instruments/songs/play_synthesized.dm | 2 +- .../jobs/job_types/chaplain/chaplain.dm | 2 +- code/modules/jobs/jobs.dm | 2 +- code/modules/language/language.dm | 2 +- .../modules/mining/equipment/marker_beacons.dm | 4 ++-- code/modules/mob/dead/observer/observer_say.dm | 2 +- code/modules/mob/emote.dm | 2 +- code/modules/mob/living/emote.dm | 6 +++--- .../mob/living/silicon/ai/_preferences.dm | 2 +- code/modules/mob/living/silicon/ai/ai_say.dm | 4 ++-- code/modules/mob/mob.dm | 2 +- code/modules/mob/mob_say.dm | 8 ++++---- .../computers/machinery/console_presets.dm | 4 ++-- .../file_system/programs/atmosscan.dm | 2 +- .../file_system/programs/secureye.dm | 2 +- code/modules/power/power.dm | 4 ++-- code/modules/power/terminal.dm | 4 ++-- .../reagents/drinks/alcohol_reagents.dm | 2 +- .../chemistry/reagents/food_reagents.dm | 18 +++++++++--------- .../chemistry/reagents/other_reagents.dm | 8 ++++---- .../reagents/reagent_containers/cups/_cup.dm | 2 +- code/modules/surgery/bodyparts/_bodyparts.dm | 8 ++++---- .../surgery/organs/internal/eyes/_eyes.dm | 2 +- .../surgery/organs/internal/tongue/_tongue.dm | 2 +- code/modules/tooltip/tooltip.dm | 2 +- .../components/action/equpiment_action.dm | 2 +- .../wiremod/components/string/textcase.dm | 2 +- code/modules/wiremod/core/component.dm | 2 +- code/modules/wiremod/shell/module.dm | 2 +- tools/ci/check_grep.sh | 10 ++++++++++ 98 files changed, 175 insertions(+), 161 deletions(-) diff --git a/code/__DEFINES/text.dm b/code/__DEFINES/text.dm index c303eebbcdc56..8b0fda53cd79e 100644 --- a/code/__DEFINES/text.dm +++ b/code/__DEFINES/text.dm @@ -64,6 +64,10 @@ */ #define PREVENT_CHARACTER_TRIM_LOSS(integer) (integer + 1) +/// BYOND's string procs don't support being used on datum references (as in it doesn't look for a name for stringification) +/// We just use this macro to ensure that we will only pass strings to this BYOND-level function without developers needing to really worry about it. +#define LOWER_TEXT(thing) lowertext(UNLINT("[thing]")) + /// Folder directory for strings #define STRING_DIRECTORY "strings" diff --git a/code/__HELPERS/atmospherics.dm b/code/__HELPERS/atmospherics.dm index 3ac3bfaed569d..2a59cf60b403f 100644 --- a/code/__HELPERS/atmospherics.dm +++ b/code/__HELPERS/atmospherics.dm @@ -105,7 +105,7 @@ GLOBAL_LIST_EMPTY(gas_handbook) factor_info["factor_name"] = factor factor_info["factor_type"] = "misc" if(factor == "Temperature" || factor == "Pressure") - factor_info["tooltip"] = "Reaction is influenced by the [lowertext(factor)] of the place where the reaction is occuring." + factor_info["tooltip"] = "Reaction is influenced by the [LOWER_TEXT(factor)] of the place where the reaction is occuring." else if(factor == "Energy") factor_info["tooltip"] = "Energy released by the reaction, may or may not result in linear temperature change depending on a slew of other factors." else if(factor == "Radiation") @@ -138,7 +138,7 @@ GLOBAL_LIST_EMPTY(gas_handbook) factor_info["factor_name"] = factor factor_info["factor_type"] = "misc" if(factor == "Temperature" || factor == "Pressure") - factor_info["tooltip"] = "Reaction is influenced by the [lowertext(factor)] of the place where the reaction is occuring." + factor_info["tooltip"] = "Reaction is influenced by the [LOWER_TEXT(factor)] of the place where the reaction is occuring." else if(factor == "Energy") factor_info["tooltip"] = "Energy released by the reaction, may or may not result in linear temperature change depending on a slew of other factors." else if(factor == "Radiation") diff --git a/code/__HELPERS/chat_filter.dm b/code/__HELPERS/chat_filter.dm index 34d811bf85bae..22fe36a21367c 100644 --- a/code/__HELPERS/chat_filter.dm +++ b/code/__HELPERS/chat_filter.dm @@ -1,6 +1,6 @@ // [2] is the group index of the blocked term when it is not using word bounds. // This is sanity checked by unit tests. -#define GET_MATCHED_GROUP(regex) (lowertext(regex.group[2] || regex.match)) +#define GET_MATCHED_GROUP(regex) (LOWER_TEXT(regex.group[2] || regex.match)) /// Given a text, will return what word is on the IC filter, with the reason. /// Returns null if the message is OK. diff --git a/code/__HELPERS/hearted.dm b/code/__HELPERS/hearted.dm index 1eafef56a4f40..adae298516ec6 100644 --- a/code/__HELPERS/hearted.dm +++ b/code/__HELPERS/hearted.dm @@ -54,7 +54,7 @@ if(!heart_nominee) return - heart_nominee = lowertext(heart_nominee) + heart_nominee = LOWER_TEXT(heart_nominee) var/list/name_checks = get_mob_by_name(heart_nominee) if(!name_checks || name_checks.len == 0) query_heart(attempt + 1) diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index b6870757cdc40..a67c78a12cc28 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -679,7 +679,7 @@ world if(uppercase == 1) letter = uppertext(letter) else if(uppercase == -1) - letter = lowertext(letter) + letter = LOWER_TEXT(letter) var/image/text_image = new(loc = A) text_image.maptext = MAPTEXT("[letter]") diff --git a/code/__HELPERS/names.dm b/code/__HELPERS/names.dm index 33bb0348df568..12c34d3a705ca 100644 --- a/code/__HELPERS/names.dm +++ b/code/__HELPERS/names.dm @@ -215,22 +215,22 @@ GLOBAL_DATUM(syndicate_code_response_regex, /regex) if(2) switch(rand(1,3))//Food, drinks, or places. Only selectable once. if(1) - . += lowertext(pick(drinks)) + . += LOWER_TEXT(pick(drinks)) if(2) - . += lowertext(pick(foods)) + . += LOWER_TEXT(pick(foods)) if(3) - . += lowertext(pick(locations)) + . += LOWER_TEXT(pick(locations)) safety -= 2 if(3) switch(rand(1,4))//Abstract nouns, objects, adjectives, threats. Can be selected more than once. if(1) - . += lowertext(pick(nouns)) + . += LOWER_TEXT(pick(nouns)) if(2) - . += lowertext(pick(objects)) + . += LOWER_TEXT(pick(objects)) if(3) - . += lowertext(pick(adjectives)) + . += LOWER_TEXT(pick(adjectives)) if(4) - . += lowertext(pick(threats)) + . += LOWER_TEXT(pick(threats)) if(!return_list) if(words == 1) . += "." diff --git a/code/__HELPERS/reagents.dm b/code/__HELPERS/reagents.dm index d557db3173ab9..012a1fd5cc09d 100644 --- a/code/__HELPERS/reagents.dm +++ b/code/__HELPERS/reagents.dm @@ -155,7 +155,7 @@ ///Returns a list of chemical_reaction datums that have the input STRING as a product /proc/get_reagent_type_from_product_string(string) - var/input_reagent = replacetext(lowertext(string), " ", "") //95% of the time, the reagent id is a lowercase/no spaces version of the name + var/input_reagent = replacetext(LOWER_TEXT(string), " ", "") //95% of the time, the reagent id is a lowercase/no spaces version of the name if (isnull(input_reagent)) return @@ -194,7 +194,7 @@ /proc/get_chem_id(chem_name) for(var/X in GLOB.chemical_reagents_list) var/datum/reagent/R = GLOB.chemical_reagents_list[X] - if(ckey(chem_name) == ckey(lowertext(R.name))) + if(ckey(chem_name) == ckey(LOWER_TEXT(R.name))) return X ///Takes a type in and returns a list of associated recipes diff --git a/code/__HELPERS/sanitize_values.dm b/code/__HELPERS/sanitize_values.dm index 555f5175d7af7..8cc03a317e95a 100644 --- a/code/__HELPERS/sanitize_values.dm +++ b/code/__HELPERS/sanitize_values.dm @@ -73,7 +73,7 @@ if(97 to 102) //letters a to f . += char if(65 to 70) //letters A to F - char = lowertext(char) + char = LOWER_TEXT(char) . += char else break diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index 4f6031fcf3ffd..40915672ef960 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -785,7 +785,7 @@ GLOBAL_LIST_INIT(binary, list("0","1")) return string var/base = next_backslash == 1 ? "" : copytext(string, 1, next_backslash) - var/macro = lowertext(copytext(string, next_backslash + length(string[next_backslash]), next_space)) + var/macro = LOWER_TEXT(copytext(string, next_backslash + length(string[next_backslash]), next_space)) var/rest = next_backslash > leng ? "" : copytext(string, next_space + length(string[next_space])) //See https://secure.byond.com/docs/ref/info.html#/DM/text/macros @@ -1082,7 +1082,7 @@ GLOBAL_LIST_INIT(binary, list("0","1")) var/text_length = length(text) //remove caps since words will be shuffled - text = lowertext(text) + text = LOWER_TEXT(text) //remove punctuation for same reasons as above var/punctuation = "" var/punctuation_hit_list = list("!","?",".","-") diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm index 9eb1a491f425a..03d308e34d635 100644 --- a/code/__HELPERS/type2type.dm +++ b/code/__HELPERS/type2type.dm @@ -389,7 +389,7 @@ GLOBAL_LIST_INIT(modulo_angle_to_dir, list(NORTH,NORTHEAST,EAST,SOUTHEAST,SOUTH, if(/turf) return "turf" else //regex everything else (works for /proc too) - return lowertext(replacetext("[the_type]", "[type2parent(the_type)]/", "")) + return LOWER_TEXT(replacetext("[the_type]", "[type2parent(the_type)]/", "")) /// Return html to load a url. /// for use inside of browse() calls to html assets that might be loaded on a cdn. diff --git a/code/controllers/configuration/config_entry.dm b/code/controllers/configuration/config_entry.dm index fb1cf4bf5a6a8..7f28c361267f1 100644 --- a/code/controllers/configuration/config_entry.dm +++ b/code/controllers/configuration/config_entry.dm @@ -25,7 +25,7 @@ /datum/config_entry/New() if(type == abstract_type) CRASH("Abstract config entry [type] instatiated!") - name = lowertext(type2top(type)) + name = LOWER_TEXT(type2top(type)) default_protection = protection set_default() @@ -100,7 +100,7 @@ return FALSE config_entry_value = auto_trim ? trim(str_val) : str_val if(lowercase) - config_entry_value = lowertext(config_entry_value) + config_entry_value = LOWER_TEXT(config_entry_value) return TRUE /datum/config_entry/number @@ -148,7 +148,7 @@ return FALSE str_val = trim(str_val) if (str_val != "") - config_entry_value += lowercase ? lowertext(str_val) : str_val + config_entry_value += lowercase ? LOWER_TEXT(str_val) : str_val return TRUE /datum/config_entry/number_list @@ -246,7 +246,7 @@ config_key = jointext(config_entry_words, splitter) if(lowercase_key) - config_key = lowertext(config_key) + config_key = LOWER_TEXT(config_key) is_ambiguous = (length(config_entry_words) > 2) diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm index 830f15ae559d2..b7f48fcab5e4a 100644 --- a/code/controllers/configuration/configuration.dm +++ b/code/controllers/configuration/configuration.dm @@ -165,7 +165,7 @@ if(IsAdminAdvancedProcCall()) return - var/filename_to_test = world.system_type == MS_WINDOWS ? lowertext(filename) : filename + var/filename_to_test = world.system_type == MS_WINDOWS ? LOWER_TEXT(filename) : filename if(filename_to_test in stack) log_config_error("Warning: Config recursion detected ([english_list(stack)]), breaking!") return @@ -192,10 +192,10 @@ var/value = null if(pos) - entry = lowertext(copytext(L, 1, pos)) + entry = LOWER_TEXT(copytext(L, 1, pos)) value = copytext(L, pos + length(L[pos])) else - entry = lowertext(L) + entry = LOWER_TEXT(L) if(!entry) continue @@ -210,7 +210,7 @@ // Reset directive, used for setting a config value back to defaults. Useful for string list config types if (entry == "$reset") - var/datum/config_entry/resetee = _entries[lowertext(value)] + var/datum/config_entry/resetee = _entries[LOWER_TEXT(value)] if (!value || !resetee) log_config_error("Warning: invalid $reset directive: [value]") continue @@ -364,10 +364,10 @@ Example config: var/data = null if(pos) - command = lowertext(copytext(t, 1, pos)) + command = LOWER_TEXT(copytext(t, 1, pos)) data = copytext(t, pos + length(t[pos])) else - command = lowertext(t) + command = LOWER_TEXT(t) if(!command) continue @@ -471,7 +471,7 @@ Example config: var/list/formatted_banned_words = list() for (var/banned_word in banned_words) - formatted_banned_words[lowertext(banned_word)] = banned_words[banned_word] + formatted_banned_words[LOWER_TEXT(banned_word)] = banned_words[banned_word] return formatted_banned_words /datum/controller/configuration/proc/compile_filter_regex(list/banned_words) diff --git a/code/controllers/configuration/entries/resources.dm b/code/controllers/configuration/entries/resources.dm index c839ccc078d4d..1fb8a6237d45c 100644 --- a/code/controllers/configuration/entries/resources.dm +++ b/code/controllers/configuration/entries/resources.dm @@ -6,7 +6,7 @@ /datum/config_entry/string/asset_transport /datum/config_entry/string/asset_transport/ValidateAndSet(str_val) - return (lowertext(str_val) in list("simple", "webroot")) && ..(lowertext(str_val)) + return (LOWER_TEXT(str_val) in list("simple", "webroot")) && ..(LOWER_TEXT(str_val)) /datum/config_entry/string/asset_cdn_webroot protection = CONFIG_ENTRY_LOCKED diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index fe28c7f3b007b..468882f0e86ec 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -88,7 +88,7 @@ SUBSYSTEM_DEF(ticker) var/use_rare_music = prob(1) for(var/S in provisional_title_music) - var/lower = lowertext(S) + var/lower = LOWER_TEXT(S) var/list/L = splittext(lower,"+") switch(L.len) if(3) //rare+MAP+sound.ogg or MAP+rare.sound.ogg -- Rare Map-specific sounds @@ -112,7 +112,7 @@ SUBSYSTEM_DEF(ticker) for(var/S in music) var/list/L = splittext(S,".") if(L.len >= 2) - var/ext = lowertext(L[L.len]) //pick the real extension, no 'honk.ogg.exe' nonsense here + var/ext = LOWER_TEXT(L[L.len]) //pick the real extension, no 'honk.ogg.exe' nonsense here if(byond_sound_formats[ext]) continue music -= S diff --git a/code/controllers/subsystem/title.dm b/code/controllers/subsystem/title.dm index 0a9a636c9a7f7..1f40dd921dddf 100644 --- a/code/controllers/subsystem/title.dm +++ b/code/controllers/subsystem/title.dm @@ -25,7 +25,7 @@ SUBSYSTEM_DEF(title) for(var/S in provisional_title_screens) var/list/L = splittext(S,"+") - if((L.len == 1 && (L[1] != "exclude" && L[1] != "blank.png")) || (L.len > 1 && ((use_rare_screens && lowertext(L[1]) == "rare") || (lowertext(L[1]) == lowertext(SSmapping.config.map_name))))) + if((L.len == 1 && (L[1] != "exclude" && L[1] != "blank.png")) || (L.len > 1 && ((use_rare_screens && LOWER_TEXT(L[1]) == "rare") || (LOWER_TEXT(L[1]) == LOWER_TEXT(SSmapping.config.map_name))))) title_screens += S if(length(title_screens)) diff --git a/code/datums/brain_damage/hypnosis.dm b/code/datums/brain_damage/hypnosis.dm index dbaa571cacdac..5630073c95551 100644 --- a/code/datums/brain_damage/hypnosis.dm +++ b/code/datums/brain_damage/hypnosis.dm @@ -61,7 +61,7 @@ ..() if(SPT_PROB(1, seconds_per_tick)) if(prob(50)) - to_chat(owner, span_hypnophrase("...[lowertext(hypnotic_phrase)]...")) + to_chat(owner, span_hypnophrase("...[LOWER_TEXT(hypnotic_phrase)]...")) else owner.cause_hallucination( \ /datum/hallucination/chat, \ diff --git a/code/datums/brain_damage/mild.dm b/code/datums/brain_damage/mild.dm index 21ecf1b520b8e..1d121d0db8a86 100644 --- a/code/datums/brain_damage/mild.dm +++ b/code/datums/brain_damage/mild.dm @@ -212,7 +212,7 @@ word = copytext(word, 1, suffix_foundon) word = html_decode(word) - if(lowertext(word) in common_words) + if(LOWER_TEXT(word) in common_words) new_message += word + suffix else if(prob(30) && message_split.len > 2) diff --git a/code/datums/components/cult_ritual_item.dm b/code/datums/components/cult_ritual_item.dm index 74bac463e32ad..7d9710977cecb 100644 --- a/code/datums/components/cult_ritual_item.dm +++ b/code/datums/components/cult_ritual_item.dm @@ -221,7 +221,7 @@ cultist.log_message("erased a [rune.cultist_name] rune with [parent].", LOG_GAME) message_admins("[ADMIN_LOOKUPFLW(cultist)] erased a [rune.cultist_name] rune with [parent].") - to_chat(cultist, span_notice("You carefully erase the [lowertext(rune.cultist_name)] rune.")) + to_chat(cultist, span_notice("You carefully erase the [LOWER_TEXT(rune.cultist_name)] rune.")) qdel(rune) /* @@ -338,8 +338,8 @@ var/obj/effect/rune/made_rune = new rune_to_scribe(our_turf, chosen_keyword) made_rune.add_mob_blood(cultist) - to_chat(cultist, span_cult("The [lowertext(made_rune.cultist_name)] rune [made_rune.cultist_desc]")) - cultist.log_message("scribed \a [lowertext(made_rune.cultist_name)] rune using [parent] ([parent.type])", LOG_GAME) + to_chat(cultist, span_cult("The [LOWER_TEXT(made_rune.cultist_name)] rune [made_rune.cultist_desc]")) + cultist.log_message("scribed \a [LOWER_TEXT(made_rune.cultist_name)] rune using [parent] ([parent.type])", LOG_GAME) SSblackbox.record_feedback("tally", "cult_runes_scribed", 1, made_rune.cultist_name) return TRUE diff --git a/code/datums/components/deadchat_control.dm b/code/datums/components/deadchat_control.dm index 7517f35ff297b..210ef26a05235 100644 --- a/code/datums/components/deadchat_control.dm +++ b/code/datums/components/deadchat_control.dm @@ -61,7 +61,7 @@ /datum/component/deadchat_control/proc/deadchat_react(mob/source, message) SIGNAL_HANDLER - message = lowertext(message) + message = LOWER_TEXT(message) if(!inputs[message]) return @@ -162,7 +162,7 @@ */ /datum/component/deadchat_control/proc/waive_automute(mob/speaker, client/client, message, mute_type) SIGNAL_HANDLER - if(mute_type == MUTE_DEADCHAT && inputs[lowertext(message)]) + if(mute_type == MUTE_DEADCHAT && inputs[LOWER_TEXT(message)]) return WAIVE_AUTOMUTE_CHECK return NONE diff --git a/code/datums/components/food/edible.dm b/code/datums/components/food/edible.dm index 85a6a7e386b53..d4b80ea1dd8ab 100644 --- a/code/datums/components/food/edible.dm +++ b/code/datums/components/food/edible.dm @@ -215,7 +215,7 @@ Behavior that's still missing from this component that original food items had t if(foodtypes) var/list/types = bitfield_to_list(foodtypes, FOOD_FLAGS) - examine_list += span_notice("It is [lowertext(english_list(types))].") + examine_list += span_notice("It is [LOWER_TEXT(english_list(types))].") var/quality = get_perceived_food_quality(user) if(quality > 0) diff --git a/code/datums/components/material/material_container.dm b/code/datums/components/material/material_container.dm index 69f67d46df3a8..a17e642e03920 100644 --- a/code/datums/components/material/material_container.dm +++ b/code/datums/components/material/material_container.dm @@ -102,7 +102,7 @@ var/datum/material/M = I var/amt = materials[I] / SHEET_MATERIAL_AMOUNT if(amt) - examine_texts += span_notice("It has [amt] sheets of [lowertext(M.name)] stored.") + examine_texts += span_notice("It has [amt] sheets of [LOWER_TEXT(M.name)] stored.") /datum/component/material_container/vv_edit_var(var_name, var_value) var/old_flags = mat_container_flags diff --git a/code/datums/components/surgery_initiator.dm b/code/datums/components/surgery_initiator.dm index a1a354a7c2150..002195ee677be 100644 --- a/code/datums/components/surgery_initiator.dm +++ b/code/datums/components/surgery_initiator.dm @@ -317,7 +317,7 @@ var/datum/surgery/procedure = new surgery.type(target, selected_zone, affecting_limb) ADD_TRAIT(target, TRAIT_ALLOWED_HONORBOUND_ATTACK, type) - target.balloon_alert(user, "starting \"[lowertext(procedure.name)]\"") + target.balloon_alert(user, "starting \"[LOWER_TEXT(procedure.name)]\"") user.visible_message( span_notice("[user] drapes [parent] over [target]'s [parse_zone(selected_zone)] to prepare for surgery."), diff --git a/code/datums/components/uplink.dm b/code/datums/components/uplink.dm index 5007d8caeb92d..163de4867d575 100644 --- a/code/datums/components/uplink.dm +++ b/code/datums/components/uplink.dm @@ -378,8 +378,8 @@ /datum/component/uplink/proc/new_ringtone(datum/source, mob/living/user, new_ring_text) SIGNAL_HANDLER - if(trim(lowertext(new_ring_text)) != trim(lowertext(unlock_code))) - if(trim(lowertext(new_ring_text)) == trim(lowertext(failsafe_code))) + if(trim(LOWER_TEXT(new_ring_text)) != trim(LOWER_TEXT(unlock_code))) + if(trim(LOWER_TEXT(new_ring_text)) == trim(LOWER_TEXT(failsafe_code))) failsafe(user) return COMPONENT_STOP_RINGTONE_CHANGE return @@ -415,8 +415,8 @@ if(channel != RADIO_CHANNEL_UPLINK) return - if(!findtext(lowertext(message), lowertext(unlock_code))) - if(failsafe_code && findtext(lowertext(message), lowertext(failsafe_code))) + if(!findtext(LOWER_TEXT(message), LOWER_TEXT(unlock_code))) + if(failsafe_code && findtext(LOWER_TEXT(message), LOWER_TEXT(failsafe_code))) failsafe(user) // no point returning cannot radio, youre probably ded return locked = FALSE diff --git a/code/datums/greyscale/json_reader.dm b/code/datums/greyscale/json_reader.dm index ffe143c28fc75..38286631fed49 100644 --- a/code/datums/greyscale/json_reader.dm +++ b/code/datums/greyscale/json_reader.dm @@ -63,7 +63,7 @@ ) /datum/json_reader/blend_mode/ReadJson(value) - var/new_value = blend_modes[lowertext(value)] + var/new_value = blend_modes[LOWER_TEXT(value)] if(isnull(new_value)) CRASH("Blend mode expected but got '[value]'") return new_value diff --git a/code/datums/memory/_memory.dm b/code/datums/memory/_memory.dm index 0656d32006a24..08a694616a336 100644 --- a/code/datums/memory/_memory.dm +++ b/code/datums/memory/_memory.dm @@ -392,7 +392,7 @@ if(istype(character, /datum/mind)) var/datum/mind/character_mind = character - return "\the [lowertext(initial(character_mind.assigned_role.title))]" + return "\the [LOWER_TEXT(initial(character_mind.assigned_role.title))]" // Generic result - mobs get "the guy", objs / turfs get "a thing" return ismob(character) ? "\the [character]" : "\a [character]" diff --git a/code/datums/quirks/negative_quirks/insanity.dm b/code/datums/quirks/negative_quirks/insanity.dm index 56b56a5381216..40e70f07b1831 100644 --- a/code/datums/quirks/negative_quirks/insanity.dm +++ b/code/datums/quirks/negative_quirks/insanity.dm @@ -25,7 +25,7 @@ added_trauma.resilience = TRAUMA_RESILIENCE_ABSOLUTE added_trauma.name = name added_trauma.desc = medical_record_text - added_trauma.scan_desc = lowertext(name) + added_trauma.scan_desc = LOWER_TEXT(name) added_trauma.gain_text = null added_trauma.lose_text = null @@ -33,7 +33,7 @@ added_trama_ref = WEAKREF(added_trauma) /datum/quirk/insanity/post_add() - var/rds_policy = get_policy("[type]") || "Please note that your [lowertext(name)] does NOT give you any additional right to attack people or cause chaos." + var/rds_policy = get_policy("[type]") || "Please note that your [LOWER_TEXT(name)] does NOT give you any additional right to attack people or cause chaos." // I don't /think/ we'll need this, but for newbies who think "roleplay as insane" = "license to kill", it's probably a good thing to have. to_chat(quirk_holder, span_big(span_info(rds_policy))) diff --git a/code/datums/station_traits/negative_traits.dm b/code/datums/station_traits/negative_traits.dm index 917bb6c7210bd..e4c16d713cc54 100644 --- a/code/datums/station_traits/negative_traits.dm +++ b/code/datums/station_traits/negative_traits.dm @@ -149,7 +149,7 @@ /datum/station_trait/overflow_job_bureaucracy/proc/set_overflow_job_override(datum/source) SIGNAL_HANDLER var/datum/job/picked_job = pick(SSjob.get_valid_overflow_jobs()) - chosen_job_name = lowertext(picked_job.title) // like Chief Engineers vs like chief engineers + chosen_job_name = LOWER_TEXT(picked_job.title) // like Chief Engineers vs like chief engineers SSjob.set_overflow_role(picked_job.type) /datum/station_trait/slow_shuttle diff --git a/code/datums/status_effects/debuffs/speech_debuffs.dm b/code/datums/status_effects/debuffs/speech_debuffs.dm index 07bcd3c254317..4963a660b2245 100644 --- a/code/datums/status_effects/debuffs/speech_debuffs.dm +++ b/code/datums/status_effects/debuffs/speech_debuffs.dm @@ -187,7 +187,7 @@ /datum/status_effect/speech/slurring/apply_speech(original_char) var/modified_char = original_char - var/lower_char = lowertext(modified_char) + var/lower_char = LOWER_TEXT(modified_char) if(prob(common_prob) && (lower_char in common_replacements)) var/to_replace = common_replacements[lower_char] if(islist(to_replace)) diff --git a/code/datums/storage/storage.dm b/code/datums/storage/storage.dm index a1a4180132ff1..87398f52555f3 100644 --- a/code/datums/storage/storage.dm +++ b/code/datums/storage/storage.dm @@ -402,7 +402,7 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) var/datum/storage/bigger_fish = parent.loc.atom_storage if(bigger_fish && bigger_fish.max_specific_storage < max_specific_storage) if(messages && user) - user.balloon_alert(user, "[lowertext(parent.loc.name)] is in the way!") + user.balloon_alert(user, "[LOWER_TEXT(parent.loc.name)] is in the way!") return FALSE if(isitem(parent)) diff --git a/code/datums/voice_of_god_command.dm b/code/datums/voice_of_god_command.dm index 052af9d060bee..21d4f460617b6 100644 --- a/code/datums/voice_of_god_command.dm +++ b/code/datums/voice_of_god_command.dm @@ -35,7 +35,7 @@ GLOBAL_LIST_INIT(voice_of_god_commands, init_voice_of_god_commands()) if(!user.say(message, spans = span_list, sanitize = FALSE, ignore_spam = ignore_spam, forced = forced)) return - message = lowertext(message) + message = LOWER_TEXT(message) var/list/mob/living/listeners = list() //used to check if the speaker specified a name or a job to focus on @@ -299,7 +299,7 @@ GLOBAL_LIST_INIT(voice_of_god_commands, init_voice_of_god_commands()) for(var/mob/living/target as anything in listeners) var/to_say = user.name // 0.1% chance to be a smartass - if(findtext(lowertext(message), smartass_regex) && prob(0.1)) + if(findtext(LOWER_TEXT(message), smartass_regex) && prob(0.1)) to_say = "My name" addtimer(CALLBACK(target, TYPE_PROC_REF(/atom/movable, say), to_say), 0.5 SECONDS * iteration) iteration++ diff --git a/code/datums/wounds/bones.dm b/code/datums/wounds/bones.dm index 9911a7cdd5de0..9495d88cdc5a8 100644 --- a/code/datums/wounds/bones.dm +++ b/code/datums/wounds/bones.dm @@ -238,7 +238,7 @@ return FALSE if(user.grab_state == GRAB_PASSIVE) - to_chat(user, span_warning("You must have [victim] in an aggressive grab to manipulate [victim.p_their()] [lowertext(name)]!")) + to_chat(user, span_warning("You must have [victim] in an aggressive grab to manipulate [victim.p_their()] [LOWER_TEXT(name)]!")) return TRUE if(user.grab_state >= GRAB_AGGRESSIVE) diff --git a/code/datums/wounds/pierce.dm b/code/datums/wounds/pierce.dm index 4b104dedb3426..c6aaffe8483ab 100644 --- a/code/datums/wounds/pierce.dm +++ b/code/datums/wounds/pierce.dm @@ -74,7 +74,7 @@ if(victim.bodytemperature < (BODYTEMP_NORMAL - 10)) adjust_blood_flow(-0.1 * seconds_per_tick) if(SPT_PROB(2.5, seconds_per_tick)) - to_chat(victim, span_notice("You feel the [lowertext(name)] in your [limb.plaintext_zone] firming up from the cold!")) + to_chat(victim, span_notice("You feel the [LOWER_TEXT(name)] in your [limb.plaintext_zone] firming up from the cold!")) if(HAS_TRAIT(victim, TRAIT_BLOODY_MESS)) adjust_blood_flow(0.25 * seconds_per_tick) // old heparin used to just add +2 bleed stacks per tick, this adds 0.5 bleed flow to all open cuts which is probably even stronger as long as you can cut them first diff --git a/code/game/atom/atom_color.dm b/code/game/atom/atom_color.dm index e5b52460aa04d..2508e86f44d90 100644 --- a/code/game/atom/atom_color.dm +++ b/code/game/atom/atom_color.dm @@ -42,15 +42,15 @@ * Can optionally be supplied with a range of priorities, IE only checking "washable" or above */ /atom/proc/is_atom_colour(looking_for_color, min_priority_index = 1, max_priority_index = COLOUR_PRIORITY_AMOUNT) - // make sure uppertext hex strings don't mess with lowertext hex strings - looking_for_color = lowertext(looking_for_color) + // make sure uppertext hex strings don't mess with LOWER_TEXT hex strings + looking_for_color = LOWER_TEXT(looking_for_color) if(!LAZYLEN(atom_colours)) // no atom colors list has been set up, just check the color var - return lowertext(color) == looking_for_color + return LOWER_TEXT(color) == looking_for_color for(var/i in min_priority_index to max_priority_index) - if(lowertext(atom_colours[i]) == looking_for_color) + if(LOWER_TEXT(atom_colours[i]) == looking_for_color) return TRUE return FALSE diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index ed896cc7576cb..b096633a9c185 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -110,7 +110,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) for(var/network_name in network) network -= network_name - network += lowertext(network_name) + network += LOWER_TEXT(network_name) GLOB.cameranet.cameras += src diff --git a/code/game/machinery/camera/camera_construction.dm b/code/game/machinery/camera/camera_construction.dm index 48bf4ccabaa57..15f22d02cbe96 100644 --- a/code/game/machinery/camera/camera_construction.dm +++ b/code/game/machinery/camera/camera_construction.dm @@ -39,7 +39,7 @@ return ITEM_INTERACT_BLOCKING for(var/i in tempnetwork) tempnetwork -= i - tempnetwork += lowertext(i) + tempnetwork += LOWER_TEXT(i) camera_construction_state = CAMERA_STATE_FINISHED toggle_cam(user, displaymessage = FALSE) network = tempnetwork diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm index 0c6dd3d9c5537..17bbe2299f7e4 100644 --- a/code/game/machinery/computer/camera.dm +++ b/code/game/machinery/computer/camera.dm @@ -30,7 +30,7 @@ // Convert networks to lowercase for(var/i in network) network -= i - network += lowertext(i) + network += LOWER_TEXT(i) // Initialize map objects cam_screen = new cam_screen.generate_view(map_name) diff --git a/code/game/machinery/computer/camera_advanced.dm b/code/game/machinery/computer/camera_advanced.dm index a271517b0c4ca..488331c41b8a5 100644 --- a/code/game/machinery/computer/camera_advanced.dm +++ b/code/game/machinery/computer/camera_advanced.dm @@ -30,7 +30,7 @@ . = ..() for(var/i in networks) networks -= i - networks += lowertext(i) + networks += LOWER_TEXT(i) if(lock_override) if(lock_override & CAMERA_LOCK_STATION) z_lock |= SSmapping.levels_by_trait(ZTRAIT_STATION) diff --git a/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm b/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm index f6e1e92c2a508..f19f3d725c711 100644 --- a/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm @@ -103,7 +103,7 @@ /obj/item/organ/internal/tongue/rat/modify_speech(datum/source, list/speech_args) . = ..() - var/message = lowertext(speech_args[SPEECH_MESSAGE]) + var/message = LOWER_TEXT(speech_args[SPEECH_MESSAGE]) if(message == "hi" || message == "hi.") speech_args[SPEECH_MESSAGE] = "Cheesed to meet you!" if(message == "hi?") diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm index d4cf080da699a..06b1b9778477c 100644 --- a/code/game/machinery/porta_turret/portable_turret.dm +++ b/code/game/machinery/porta_turret/portable_turret.dm @@ -1066,7 +1066,7 @@ DEFINE_BITFIELD(turret_flags, list( shoot_cyborgs = !shoot_cyborgs if (user) var/status = shoot_cyborgs ? "Shooting Borgs" : "Not Shooting Borgs" - balloon_alert(user, lowertext(status)) + balloon_alert(user, LOWER_TEXT(status)) add_hiddenprint(user) log_combat(user, src, "[status]") updateTurrets() diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 36e09176c9954..0abe9312a5f98 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -1048,7 +1048,7 @@ /obj/item/proc/apply_outline(outline_color = null) if(((get(src, /mob) != usr) && !loc?.atom_storage && !(item_flags & IN_STORAGE)) || QDELETED(src) || isobserver(usr)) //cancel if the item isn't in an inventory, is being deleted, or if the person hovering is a ghost (so that people spectating you don't randomly make your items glow) return FALSE - var/theme = lowertext(usr.client?.prefs?.read_preference(/datum/preference/choiced/ui_style)) + var/theme = LOWER_TEXT(usr.client?.prefs?.read_preference(/datum/preference/choiced/ui_style)) if(!outline_color) //if we weren't provided with a color, take the theme's color switch(theme) //yeah it kinda has to be this way if("midnight") diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm index 429ade110fb12..b73e2a4a994dc 100644 --- a/code/game/objects/items/crayons.dm +++ b/code/game/objects/items/crayons.dm @@ -418,7 +418,7 @@ /obj/item/toy/crayon/proc/crayon_text_strip(text) text = copytext(text, 1, MAX_MESSAGE_LEN) var/static/regex/crayon_regex = new /regex(@"[^\w!?,.=&%#+/\-]", "ig") - return lowertext(crayon_regex.Replace(text, "")) + return LOWER_TEXT(crayon_regex.Replace(text, "")) /// Attempts to color the target. Returns how many charges were used. /obj/item/toy/crayon/proc/use_on(atom/target, mob/user, params) diff --git a/code/game/objects/items/devices/radio/encryptionkey.dm b/code/game/objects/items/devices/radio/encryptionkey.dm index b7a96d777ef1f..88c9251d5b2bc 100644 --- a/code/game/objects/items/devices/radio/encryptionkey.dm +++ b/code/game/objects/items/devices/radio/encryptionkey.dm @@ -21,7 +21,7 @@ if(LAZYLEN(channels) || translate_binary) var/list/examine_text_list = list() for(var/i in channels) - examine_text_list += "[GLOB.channel_tokens[i]] - [lowertext(i)]" + examine_text_list += "[GLOB.channel_tokens[i]] - [LOWER_TEXT(i)]" if(translate_binary) examine_text_list += "[GLOB.channel_tokens[MODE_BINARY]] - [MODE_BINARY]" diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index 98f4282c62677..310df72dbdadc 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -54,9 +54,9 @@ GLOBAL_LIST_INIT(channel_tokens, list( if(length(channels)) for(var/i in 1 to length(channels)) if(i == 1) - avail_chans += "use [MODE_TOKEN_DEPARTMENT] or [GLOB.channel_tokens[channels[i]]] for [lowertext(channels[i])]" + avail_chans += "use [MODE_TOKEN_DEPARTMENT] or [GLOB.channel_tokens[channels[i]]] for [LOWER_TEXT(channels[i])]" else - avail_chans += "use [GLOB.channel_tokens[channels[i]]] for [lowertext(channels[i])]" + avail_chans += "use [GLOB.channel_tokens[channels[i]]] for [LOWER_TEXT(channels[i])]" . += span_notice("A small screen on the headset displays the following available frequencies:\n[english_list(avail_chans)].") if(command) diff --git a/code/game/objects/items/devices/scanners/gas_analyzer.dm b/code/game/objects/items/devices/scanners/gas_analyzer.dm index 5a1be36b37ea8..cd57bd24a7ebf 100644 --- a/code/game/objects/items/devices/scanners/gas_analyzer.dm +++ b/code/game/objects/items/devices/scanners/gas_analyzer.dm @@ -159,7 +159,7 @@ var/list/airs = islist(mixture) ? mixture : list(mixture) var/list/new_gasmix_data = list() for(var/datum/gas_mixture/air as anything in airs) - var/mix_name = capitalize(lowertext(target.name)) + var/mix_name = capitalize(LOWER_TEXT(target.name)) if(airs.len != 1) //not a unary gas mixture mix_name += " - Node [airs.Find(air)]" new_gasmix_data += list(gas_mixture_parser(air, mix_name)) @@ -184,7 +184,7 @@ var/list/airs = islist(mixture) ? mixture : list(mixture) for(var/datum/gas_mixture/air as anything in airs) - var/mix_name = capitalize(lowertext(target.name)) + var/mix_name = capitalize(LOWER_TEXT(target.name)) if(airs.len > 1) //not a unary gas mixture var/mix_number = airs.Find(air) message += span_boldnotice("Node [mix_number]") diff --git a/code/game/objects/items/granters/magic/_spell_granter.dm b/code/game/objects/items/granters/magic/_spell_granter.dm index e1ca6352293db..21a69248a1407 100644 --- a/code/game/objects/items/granters/magic/_spell_granter.dm +++ b/code/game/objects/items/granters/magic/_spell_granter.dm @@ -91,4 +91,4 @@ spell_options -= spell granted_action = pick(spell_options) - action_name = lowertext(initial(granted_action.name)) + action_name = LOWER_TEXT(initial(granted_action.name)) diff --git a/code/game/objects/items/mail.dm b/code/game/objects/items/mail.dm index 5f084300442d0..4a3de80959f53 100644 --- a/code/game/objects/items/mail.dm +++ b/code/game/objects/items/mail.dm @@ -512,7 +512,7 @@ return FALSE if(loc != user) return FALSE - mail_type = lowertext(mail_type) + mail_type = LOWER_TEXT(mail_type) var/mail_armed = tgui_alert(user, "Arm it?", "Mail Counterfeiting", list("Yes", "No")) == "Yes" if(isnull(mail_armed)) diff --git a/code/modules/admin/greyscale_modify_menu.dm b/code/modules/admin/greyscale_modify_menu.dm index ea0774cc99d12..f96ecb7c590b6 100644 --- a/code/modules/admin/greyscale_modify_menu.dm +++ b/code/modules/admin/greyscale_modify_menu.dm @@ -154,13 +154,13 @@ if("recolor") var/index = text2num(params["color_index"]) - var/new_color = lowertext(params["new_color"]) + var/new_color = LOWER_TEXT(params["new_color"]) if(split_colors[index] != new_color && (findtext(new_color, GLOB.is_color) || (unlocked && findtext(new_color, GLOB.is_alpha_color)))) split_colors[index] = new_color queue_refresh() if("recolor_from_string") - var/full_color_string = lowertext(params["color_string"]) + var/full_color_string = LOWER_TEXT(params["color_string"]) if(full_color_string != split_colors.Join() && ReadColorsFromString(full_color_string)) queue_refresh() diff --git a/code/modules/admin/sql_ban_system.dm b/code/modules/admin/sql_ban_system.dm index f32eefe046fe7..bb8b938c7c0ef 100644 --- a/code/modules/admin/sql_ban_system.dm +++ b/code/modules/admin/sql_ban_system.dm @@ -577,7 +577,7 @@ duration = text2num(duration) if (!(interval in list("SECOND", "MINUTE", "HOUR", "DAY", "WEEK", "MONTH", "YEAR"))) interval = "MINUTE" - var/time_message = "[duration] [lowertext(interval)]" //no DisplayTimeText because our duration is of variable interval type + var/time_message = "[duration] [LOWER_TEXT(interval)]" //no DisplayTimeText because our duration is of variable interval type if(duration > 1) //pluralize the interval if necessary time_message += "s" var/is_server_ban = (roles_to_ban[1] == "Server") diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2.dm b/code/modules/admin/verbs/SDQL2/SDQL_2.dm index 17047dbcd6819..50da67115ea49 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2.dm @@ -1027,7 +1027,7 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/sdql2_vv_all, new(null return null else if(expression [start] == "{" && long) - if(lowertext(copytext(expression[start + 1], 1, 3)) != "0x") //3 == length("0x") + 1 + if(LOWER_TEXT(copytext(expression[start + 1], 1, 3)) != "0x") //3 == length("0x") + 1 to_chat(usr, span_danger("Invalid pointer syntax: [expression[start + 1]]"), confidential = TRUE) return null var/datum/located = locate("\[[expression[start + 1]]]") diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2_parser.dm b/code/modules/admin/verbs/SDQL2/SDQL_2_parser.dm index 58a18e1a9363d..eb2623398414a 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2_parser.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2_parser.dm @@ -109,7 +109,7 @@ return null /datum/sdql_parser/proc/tokenl(i) - return lowertext(token(i)) + return LOWER_TEXT(token(i)) /datum/sdql_parser/proc/query_options(i, list/node) var/list/options = list() @@ -624,7 +624,7 @@ node += "null" i++ - else if(lowertext(copytext(token(i), 1, 3)) == "0x" && isnum(hex2num(copytext(token(i), 3))))//3 == length("0x") + 1 + else if(LOWER_TEXT(copytext(token(i), 1, 3)) == "0x" && isnum(hex2num(copytext(token(i), 3))))//3 == length("0x") + 1 node += hex2num(copytext(token(i), 3)) i++ diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm b/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm index 06c19ce5c91db..bc74347475ae9 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm @@ -81,8 +81,8 @@ /proc/_log(X, Y) return log(X, Y) -/proc/_lowertext(T) - return lowertext(T) +/proc/_LOWER_TEXT(T) + return LOWER_TEXT(T) /proc/_matrix(a, b, c, d, e, f) return matrix(a, b, c, d, e, f) diff --git a/code/modules/admin/verbs/admingame.dm b/code/modules/admin/verbs/admingame.dm index f133d486fdbde..78b61fd40bab5 100644 --- a/code/modules/admin/verbs/admingame.dm +++ b/code/modules/admin/verbs/admingame.dm @@ -222,7 +222,7 @@ Traitors and the like can also be revived with the previous role mostly intact. if(record_found)//If they have a record we can determine a few things. new_character.real_name = record_found.name - new_character.gender = lowertext(record_found.gender) + new_character.gender = LOWER_TEXT(record_found.gender) new_character.age = record_found.age var/datum/dna/found_dna = record_found.locked_dna new_character.hardset_dna(found_dna.unique_identity, found_dna.mutation_index, null, record_found.name, record_found.blood_type, new record_found.species_type, found_dna.features) diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index 8d09e28ec7cb7..a389980f533fd 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -1047,10 +1047,10 @@ GLOBAL_DATUM_INIT(admin_help_ui_handler, /datum/admin_help_ui_handler, new) if(!M.mind) continue - for(var/string in splittext(lowertext(M.real_name), " ")) + for(var/string in splittext(LOWER_TEXT(M.real_name), " ")) if(!(string in ignored_words)) nameWords += string - for(var/string in splittext(lowertext(M.name), " ")) + for(var/string in splittext(LOWER_TEXT(M.name), " ")) if(!(string in ignored_words)) nameWords += string diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm index dd8bbb5cda4fd..d5157decf4cba 100644 --- a/code/modules/admin/verbs/adminpm.dm +++ b/code/modules/admin/verbs/adminpm.dm @@ -629,7 +629,7 @@ // The ticket's id var/ticket_id = ticket?.id - var/compliant_msg = trim(lowertext(message)) + var/compliant_msg = trim(LOWER_TEXT(message)) var/tgs_tagged = "[sender](TGS/External)" var/list/splits = splittext(compliant_msg, " ") var/split_size = length(splits) diff --git a/code/modules/admin/verbs/player_ticket_history.dm b/code/modules/admin/verbs/player_ticket_history.dm index ac87707e98d38..08373db3470cb 100644 --- a/code/modules/admin/verbs/player_ticket_history.dm +++ b/code/modules/admin/verbs/player_ticket_history.dm @@ -34,7 +34,7 @@ GLOBAL_PROTECT(player_ticket_history) var/list/user_selections = list() /datum/ticket_history_holder/proc/cache_history_for_ckey(ckey, entries = 5) - ckey = lowertext(ckey) + ckey = LOWER_TEXT(ckey) if(!isnum(entries) || entries <= 0) return diff --git a/code/modules/antagonists/disease/disease_datum.dm b/code/modules/antagonists/disease/disease_datum.dm index 9d5af7ab83e77..17364feec5597 100644 --- a/code/modules/antagonists/disease/disease_datum.dm +++ b/code/modules/antagonists/disease/disease_datum.dm @@ -54,7 +54,7 @@ result += objectives_text - var/special_role_text = lowertext(name) + var/special_role_text = LOWER_TEXT(name) if(win) result += span_greentext("The [special_role_text] was successful!") diff --git a/code/modules/antagonists/malf_ai/malf_ai.dm b/code/modules/antagonists/malf_ai/malf_ai.dm index f9f422d6e6fc3..d0c39f405d5ad 100644 --- a/code/modules/antagonists/malf_ai/malf_ai.dm +++ b/code/modules/antagonists/malf_ai/malf_ai.dm @@ -246,7 +246,7 @@ result += objectives_text - var/special_role_text = lowertext(name) + var/special_role_text = LOWER_TEXT(name) if(malf_ai_won) result += span_greentext("The [special_role_text] was successful!") diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm index 88776b6819af6..5ad5aeecf26c7 100644 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -360,7 +360,7 @@ result += contractor_round_end() result += "
The traitor had a total of [DISPLAY_PROGRESSION(uplink_handler.progression_points)] Reputation and [uplink_handler.telecrystals] Unused Telecrystals." - var/special_role_text = lowertext(name) + var/special_role_text = LOWER_TEXT(name) if(traitor_won) result += span_greentext("The [special_role_text] was successful!") diff --git a/code/modules/antagonists/traitor/objectives/sabotage_machinery.dm b/code/modules/antagonists/traitor/objectives/sabotage_machinery.dm index 9723d2b653e02..5a31c4c173976 100644 --- a/code/modules/antagonists/traitor/objectives/sabotage_machinery.dm +++ b/code/modules/antagonists/traitor/objectives/sabotage_machinery.dm @@ -49,7 +49,7 @@ GLOBAL_DATUM_INIT(objective_machine_handler, /datum/objective_target_machine_han for(var/obj/machinery/machine as anything in possible_machines) prepare_machine(machine) - replace_in_name("%JOB%", lowertext(chosen_job)) + replace_in_name("%JOB%", LOWER_TEXT(chosen_job)) replace_in_name("%MACHINE%", possible_machines[1].name) return TRUE diff --git a/code/modules/art/paintings.dm b/code/modules/art/paintings.dm index dd370f480f455..a4758eb9e1134 100644 --- a/code/modules/art/paintings.dm +++ b/code/modules/art/paintings.dm @@ -350,7 +350,7 @@ var/result = rustg_dmi_create_png(png_filename, "[width]", "[height]", image_data) if(result) CRASH("Error generating painting png : [result]") - painting_metadata.md5 = md5(lowertext(image_data)) + painting_metadata.md5 = md5(LOWER_TEXT(image_data)) generated_icon = new(png_filename) icon_generated = TRUE update_appearance() @@ -663,7 +663,7 @@ stack_trace("Invalid persistence_id - [persistence_id]") return var/data = current_canvas.get_data_string() - var/md5 = md5(lowertext(data)) + var/md5 = md5(LOWER_TEXT(data)) var/list/current = SSpersistent_paintings.paintings[persistence_id] if(!current) current = list() diff --git a/code/modules/awaymissions/zlevel.dm b/code/modules/awaymissions/zlevel.dm index c4bb2d1761067..0fdc5093511f2 100644 --- a/code/modules/awaymissions/zlevel.dm +++ b/code/modules/awaymissions/zlevel.dm @@ -62,10 +62,10 @@ GLOBAL_LIST_INIT(potentialConfigRandomZlevels, generate_map_list_from_directory( var/name = null if (pos) - name = lowertext(copytext(t, 1, pos)) + name = LOWER_TEXT(copytext(t, 1, pos)) else - name = lowertext(t) + name = LOWER_TEXT(t) if (!name) continue diff --git a/code/modules/cargo/bounties/assistant.dm b/code/modules/cargo/bounties/assistant.dm index 7d345802eef12..636b4f4791b31 100644 --- a/code/modules/cargo/bounties/assistant.dm +++ b/code/modules/cargo/bounties/assistant.dm @@ -257,7 +257,7 @@ ..() fluid_type = pick(AQUARIUM_FLUID_FRESHWATER, AQUARIUM_FLUID_SALTWATER, AQUARIUM_FLUID_SULPHWATEVER) name = "[fluid_type] Fish" - description = "We need [lowertext(fluid_type)] fish to populate our aquariums with. Fishes that are dead or bought from cargo will only be paid half as much." + description = "We need [LOWER_TEXT(fluid_type)] fish to populate our aquariums with. Fishes that are dead or bought from cargo will only be paid half as much." /datum/bounty/item/assistant/fish/fluid/can_ship_fish(obj/item/fish/fishie) return compatible_fluid_type(fishie.required_fluid_type, fluid_type) diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 684721af5ee28..a5753fc6f3340 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -34,7 +34,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( return #ifndef TESTING - if (lowertext(hsrc_command) == "_debug") //disable the integrated byond vv in the client side debugging tools since it doesn't respect vv read protections + if (LOWER_TEXT(hsrc_command) == "_debug") //disable the integrated byond vv in the client side debugging tools since it doesn't respect vv read protections return #endif diff --git a/code/modules/client/preferences/glasses.dm b/code/modules/client/preferences/glasses.dm index 03c975abce786..a08f15955eaa4 100644 --- a/code/modules/client/preferences/glasses.dm +++ b/code/modules/client/preferences/glasses.dm @@ -11,7 +11,7 @@ if (value == "Random") return icon('icons/effects/random_spawners.dmi', "questionmark") else - return icon('icons/obj/clothing/glasses.dmi', "glasses_[lowertext(value)]") + return icon('icons/obj/clothing/glasses.dmi', "glasses_[LOWER_TEXT(value)]") /datum/preference/choiced/glasses/is_accessible(datum/preferences/preferences) if (!..(preferences)) diff --git a/code/modules/client/preferences/middleware/antags.dm b/code/modules/client/preferences/middleware/antags.dm index b3bc613d2ee7f..abd9495d09a66 100644 --- a/code/modules/client/preferences/middleware/antags.dm +++ b/code/modules/client/preferences/middleware/antags.dm @@ -180,4 +180,4 @@ GLOBAL_LIST_INIT(non_ruleset_antagonists, list( /// Serializes an antag name to be used for preferences UI /proc/serialize_antag_name(antag_name) // These are sent through CSS, so they need to be safe to use as class names. - return lowertext(sanitize_css_class_name(antag_name)) + return LOWER_TEXT(sanitize_css_class_name(antag_name)) diff --git a/code/modules/emoji/emoji_parse.dm b/code/modules/emoji/emoji_parse.dm index 533628eedf46d..fa9b9ea0d5e6e 100644 --- a/code/modules/emoji/emoji_parse.dm +++ b/code/modules/emoji/emoji_parse.dm @@ -16,7 +16,7 @@ pos = search search = findtext(text, ":", pos + length(text[pos])) if(search) - emoji = lowertext(copytext(text, pos + length(text[pos]), search)) + emoji = LOWER_TEXT(copytext(text, pos + length(text[pos]), search)) var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/chat) var/tag = sheet.icon_tag("emoji-[emoji]") if(tag) @@ -46,9 +46,9 @@ pos = search search = findtext(text, ":", pos + length(text[pos])) if(search) - var/word = lowertext(copytext(text, pos + length(text[pos]), search)) + var/word = LOWER_TEXT(copytext(text, pos + length(text[pos]), search)) if(word in emojis) - final += lowertext(copytext(text, pos, search + length(text[search]))) + final += LOWER_TEXT(copytext(text, pos, search + length(text[search]))) pos = search + length(text[search]) continue break diff --git a/code/modules/hydroponics/seeds.dm b/code/modules/hydroponics/seeds.dm index d079323e3a9c9..f46f4c3912a0f 100644 --- a/code/modules/hydroponics/seeds.dm +++ b/code/modules/hydroponics/seeds.dm @@ -234,7 +234,7 @@ else t_prod = new product(output_loc, new_seed = src) if(parent.myseed.plantname != initial(parent.myseed.plantname)) - t_prod.name = lowertext(parent.myseed.plantname) + t_prod.name = LOWER_TEXT(parent.myseed.plantname) if(productdesc) t_prod.desc = productdesc t_prod.seed.name = parent.myseed.name @@ -475,7 +475,7 @@ return if(!user.can_perform_action(src)) return - name = "[lowertext(newplantname)]" + name = "[LOWER_TEXT(newplantname)]" plantname = newplantname if("Seed Description") var/newdesc = tgui_input_text(user, "Write a new seed description", "Seed Description", desc, 180) diff --git a/code/modules/instruments/songs/play_legacy.dm b/code/modules/instruments/songs/play_legacy.dm index 7094de85a8963..c49122d464196 100644 --- a/code/modules/instruments/songs/play_legacy.dm +++ b/code/modules/instruments/songs/play_legacy.dm @@ -9,7 +9,7 @@ var/list/octaves = list(3, 3, 3, 3, 3, 3, 3) var/list/accents = list("n", "n", "n", "n", "n", "n", "n") for(var/line in lines) - var/list/chords = splittext(lowertext(line), ",") + var/list/chords = splittext(LOWER_TEXT(line), ",") for(var/chord in chords) var/list/compiled_chord = list() var/tempodiv = 1 diff --git a/code/modules/instruments/songs/play_synthesized.dm b/code/modules/instruments/songs/play_synthesized.dm index 836c2fdd86bce..05e23a8c97aac 100644 --- a/code/modules/instruments/songs/play_synthesized.dm +++ b/code/modules/instruments/songs/play_synthesized.dm @@ -9,7 +9,7 @@ var/list/octaves = list(3, 3, 3, 3, 3, 3, 3) var/list/accents = list("n", "n", "n", "n", "n", "n", "n") for(var/line in lines) - var/list/chords = splittext(lowertext(line), ",") + var/list/chords = splittext(LOWER_TEXT(line), ",") for(var/chord in chords) var/list/compiled_chord = list() var/tempodiv = 1 diff --git a/code/modules/jobs/job_types/chaplain/chaplain.dm b/code/modules/jobs/job_types/chaplain/chaplain.dm index 58821ec535876..8bcfaefcfc67a 100644 --- a/code/modules/jobs/job_types/chaplain/chaplain.dm +++ b/code/modules/jobs/job_types/chaplain/chaplain.dm @@ -69,7 +69,7 @@ var/new_bible = player_client?.prefs?.read_preference(/datum/preference/name/bible) || DEFAULT_BIBLE holy_bible.deity_name = new_deity - switch(lowertext(new_religion)) + switch(LOWER_TEXT(new_religion)) if("homosexuality", "gay", "penis", "ass", "cock", "cocks") new_bible = pick("Guys Gone Wild","Coming Out of The Closet","War of Cocks") switch(new_bible) diff --git a/code/modules/jobs/jobs.dm b/code/modules/jobs/jobs.dm index a0b0ebee560e8..0c2731c268e7d 100644 --- a/code/modules/jobs/jobs.dm +++ b/code/modules/jobs/jobs.dm @@ -56,7 +56,7 @@ GLOBAL_PROTECT(exp_specialmap) var/static/regex/chef_expand = new("chef") var/static/regex/borg_expand = new("(?" /obj/item/stack/marker_beacon/update_icon_state() - icon_state = "[initial(icon_state)][lowertext(picked_color)]" + icon_state = "[initial(icon_state)][LOWER_TEXT(picked_color)]" return ..() /obj/item/stack/marker_beacon/attack_self(mob/user) @@ -116,7 +116,7 @@ GLOBAL_LIST_INIT(marker_beacon_colors, sort_list(list( set_light(light_range, light_power, GLOB.marker_beacon_colors[picked_color]) /obj/structure/marker_beacon/update_icon_state() - icon_state = "[icon_prefix][lowertext(picked_color)]-on" + icon_state = "[icon_prefix][LOWER_TEXT(picked_color)]-on" return ..() /obj/structure/marker_beacon/attack_hand(mob/living/user, list/modifiers) diff --git a/code/modules/mob/dead/observer/observer_say.dm b/code/modules/mob/dead/observer/observer_say.dm index e43086349b34e..e3a5ff3cdf07a 100644 --- a/code/modules/mob/dead/observer/observer_say.dm +++ b/code/modules/mob/dead/observer/observer_say.dm @@ -5,7 +5,7 @@ /mob/dead/observer/get_message_mods(message, list/mods) var/key = message[1] if((key in GLOB.department_radio_prefixes) && length(message) > length(key) + 1 && !mods[RADIO_EXTENSION]) - mods[RADIO_KEY] = lowertext(message[1 + length(key)]) + mods[RADIO_KEY] = LOWER_TEXT(message[1 + length(key)]) mods[RADIO_EXTENSION] = GLOB.department_radio_keys[mods[RADIO_KEY]] return message diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm index bf9e099e5c97e..c1822ff0e51c4 100644 --- a/code/modules/mob/emote.dm +++ b/code/modules/mob/emote.dm @@ -19,7 +19,7 @@ param = copytext(act, custom_param + length(act[custom_param])) act = copytext(act, 1, custom_param) - act = lowertext(act) + act = LOWER_TEXT(act) var/list/key_emotes = GLOB.emote_list[act] if(!length(key_emotes)) diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm index 3a19eebadc966..9bfc19b300859 100644 --- a/code/modules/mob/living/emote.dm +++ b/code/modules/mob/living/emote.dm @@ -633,20 +633,20 @@ to_chat(user, span_warning("\"[input]\"")) REPORT_CHAT_FILTER_TO_USER(user, filter_result) log_filter("IC Emote", input, filter_result) - SSblackbox.record_feedback("tally", "ic_blocked_words", 1, lowertext(config.ic_filter_regex.match)) + SSblackbox.record_feedback("tally", "ic_blocked_words", 1, LOWER_TEXT(config.ic_filter_regex.match)) return FALSE filter_result = is_soft_ic_filtered(input) if(filter_result) if(tgui_alert(user,"Your emote contains \"[filter_result[CHAT_FILTER_INDEX_WORD]]\". \"[filter_result[CHAT_FILTER_INDEX_REASON]]\", Are you sure you want to emote it?", "Soft Blocked Word", list("Yes", "No")) != "Yes") - SSblackbox.record_feedback("tally", "soft_ic_blocked_words", 1, lowertext(config.soft_ic_filter_regex.match)) + SSblackbox.record_feedback("tally", "soft_ic_blocked_words", 1, LOWER_TEXT(config.soft_ic_filter_regex.match)) log_filter("Soft IC Emote", input, filter_result) return FALSE message_admins("[ADMIN_LOOKUPFLW(user)] has passed the soft filter for emote \"[filter_result[CHAT_FILTER_INDEX_WORD]]\" they may be using a disallowed term. Emote: \"[input]\"") log_admin_private("[key_name(user)] has passed the soft filter for emote \"[filter_result[CHAT_FILTER_INDEX_WORD]]\" they may be using a disallowed term. Emote: \"[input]\"") - SSblackbox.record_feedback("tally", "passed_soft_ic_blocked_words", 1, lowertext(config.soft_ic_filter_regex.match)) + SSblackbox.record_feedback("tally", "passed_soft_ic_blocked_words", 1, LOWER_TEXT(config.soft_ic_filter_regex.match)) log_filter("Soft IC Emote (Passed)", input, filter_result) return TRUE diff --git a/code/modules/mob/living/silicon/ai/_preferences.dm b/code/modules/mob/living/silicon/ai/_preferences.dm index 4b0aaaecc250a..10958b2adc4f5 100644 --- a/code/modules/mob/living/silicon/ai/_preferences.dm +++ b/code/modules/mob/living/silicon/ai/_preferences.dm @@ -115,7 +115,7 @@ GLOBAL_LIST_INIT(ai_core_display_screens, sort_list(list( else if(input == "Random") input = pick(GLOB.ai_core_display_screens - "Random") - return "ai-[lowertext(input)]" + return "ai-[LOWER_TEXT(input)]" /proc/resolve_ai_icon(input) if (input == "Portrait") diff --git a/code/modules/mob/living/silicon/ai/ai_say.dm b/code/modules/mob/living/silicon/ai/ai_say.dm index 6a4cd255a6ae5..967cbb2b984f8 100644 --- a/code/modules/mob/living/silicon/ai/ai_say.dm +++ b/code/modules/mob/living/silicon/ai/ai_say.dm @@ -126,7 +126,7 @@ words.len = 30 for(var/word in words) - word = lowertext(trim(word)) + word = LOWER_TEXT(trim(word)) if(!word) words -= word continue @@ -156,7 +156,7 @@ /proc/play_vox_word(word, ai_turf, mob/only_listener) - word = lowertext(word) + word = LOWER_TEXT(word) if(GLOB.vox_sounds[word]) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 92ad416c27573..d011e19f15302 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -959,7 +959,7 @@ selected_hand = (active_hand_index % held_items.len)+1 if(istext(selected_hand)) - selected_hand = lowertext(selected_hand) + selected_hand = LOWER_TEXT(selected_hand) if(selected_hand == "right" || selected_hand == "r") selected_hand = 2 if(selected_hand == "left" || selected_hand == "l") diff --git a/code/modules/mob/mob_say.dm b/code/modules/mob/mob_say.dm index 6b300b2938a3f..e2a840d569b64 100644 --- a/code/modules/mob/mob_say.dm +++ b/code/modules/mob/mob_say.dm @@ -66,17 +66,17 @@ to_chat(src, span_warning("\"[message]\"")) REPORT_CHAT_FILTER_TO_USER(src, filter_result) log_filter("IC", message, filter_result) - SSblackbox.record_feedback("tally", "ic_blocked_words", 1, lowertext(config.ic_filter_regex.match)) + SSblackbox.record_feedback("tally", "ic_blocked_words", 1, LOWER_TEXT(config.ic_filter_regex.match)) return FALSE if(soft_filter_result && !filterproof) if(tgui_alert(usr,"Your message contains \"[soft_filter_result[CHAT_FILTER_INDEX_WORD]]\". \"[soft_filter_result[CHAT_FILTER_INDEX_REASON]]\", Are you sure you want to say it?", "Soft Blocked Word", list("Yes", "No")) != "Yes") - SSblackbox.record_feedback("tally", "soft_ic_blocked_words", 1, lowertext(config.soft_ic_filter_regex.match)) + SSblackbox.record_feedback("tally", "soft_ic_blocked_words", 1, LOWER_TEXT(config.soft_ic_filter_regex.match)) log_filter("Soft IC", message, filter_result) return FALSE message_admins("[ADMIN_LOOKUPFLW(usr)] has passed the soft filter for \"[soft_filter_result[CHAT_FILTER_INDEX_WORD]]\" they may be using a disallowed term. Message: \"[message]\"") log_admin_private("[key_name(usr)] has passed the soft filter for \"[soft_filter_result[CHAT_FILTER_INDEX_WORD]]\" they may be using a disallowed term. Message: \"[message]\"") - SSblackbox.record_feedback("tally", "passed_soft_ic_blocked_words", 1, lowertext(config.soft_ic_filter_regex.match)) + SSblackbox.record_feedback("tally", "passed_soft_ic_blocked_words", 1, LOWER_TEXT(config.soft_ic_filter_regex.match)) log_filter("Soft IC (Passed)", message, filter_result) if(client && !(ignore_spam || forced)) @@ -217,7 +217,7 @@ if(stat == CONSCIOUS) //necessary indentation so it gets stripped of the semicolon anyway. mods[MODE_HEADSET] = TRUE else if((key in GLOB.department_radio_prefixes) && length(message) > length(key) + 1 && !mods[RADIO_EXTENSION]) - mods[RADIO_KEY] = lowertext(message[1 + length(key)]) + mods[RADIO_KEY] = LOWER_TEXT(message[1 + length(key)]) mods[RADIO_EXTENSION] = GLOB.department_radio_keys[mods[RADIO_KEY]] chop_to = length(key) + 2 else if(key == "," && !mods[LANGUAGE_EXTENSION]) diff --git a/code/modules/modular_computers/computers/machinery/console_presets.dm b/code/modules/modular_computers/computers/machinery/console_presets.dm index bc277a72313f0..0ec80da4bbb29 100644 --- a/code/modules/modular_computers/computers/machinery/console_presets.dm +++ b/code/modules/modular_computers/computers/machinery/console_presets.dm @@ -94,7 +94,7 @@ setup_starting_software() REGISTER_REQUIRED_MAP_ITEM(1, 1) if(department_type) - name = "[lowertext(initial(department_type.department_name))] [name]" + name = "[LOWER_TEXT(initial(department_type.department_name))] [name]" cpu.name = name /obj/machinery/modular_computer/preset/cargochat/proc/add_starting_software() @@ -105,7 +105,7 @@ return var/datum/computer_file/program/chatclient/chatprogram = cpu.find_file_by_name("ntnrc_client") - chatprogram.username = "[lowertext(initial(department_type.department_name))]_department" + chatprogram.username = "[LOWER_TEXT(initial(department_type.department_name))]_department" cpu.idle_threads += chatprogram var/datum/computer_file/program/department_order/orderprogram = cpu.find_file_by_name("dept_order") diff --git a/code/modules/modular_computers/file_system/programs/atmosscan.dm b/code/modules/modular_computers/file_system/programs/atmosscan.dm index 8f29af435108b..7e26087285971 100644 --- a/code/modules/modular_computers/file_system/programs/atmosscan.dm +++ b/code/modules/modular_computers/file_system/programs/atmosscan.dm @@ -44,7 +44,7 @@ var/list/airs = islist(mixture) ? mixture : list(mixture) var/list/new_gasmix_data = list() for(var/datum/gas_mixture/air as anything in airs) - var/mix_name = capitalize(lowertext(target.name)) + var/mix_name = capitalize(LOWER_TEXT(target.name)) if(airs.len != 1) //not a unary gas mixture mix_name += " - Node [airs.Find(air)]" new_gasmix_data += list(gas_mixture_parser(air, mix_name)) diff --git a/code/modules/modular_computers/file_system/programs/secureye.dm b/code/modules/modular_computers/file_system/programs/secureye.dm index eee170e7c2cd9..aa3ed0e5828ce 100644 --- a/code/modules/modular_computers/file_system/programs/secureye.dm +++ b/code/modules/modular_computers/file_system/programs/secureye.dm @@ -70,7 +70,7 @@ // Convert networks to lowercase for(var/i in network) network -= i - network += lowertext(i) + network += LOWER_TEXT(i) // Initialize map objects cam_screen = new cam_screen.generate_view(map_name) diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm index ce91202722544..c9cbb0d3ecc50 100644 --- a/code/modules/power/power.dm +++ b/code/modules/power/power.dm @@ -50,9 +50,9 @@ . = ..() if(can_change_cable_layer) if(!QDELETED(powernet)) - . += span_notice("It's operating on the [lowertext(GLOB.cable_layer_to_name["[cable_layer]"])].") + . += span_notice("It's operating on the [LOWER_TEXT(GLOB.cable_layer_to_name["[cable_layer]"])].") else - . += span_warning("It's disconnected from the [lowertext(GLOB.cable_layer_to_name["[cable_layer]"])].") + . += span_warning("It's disconnected from the [LOWER_TEXT(GLOB.cable_layer_to_name["[cable_layer]"])].") . += span_notice("It's power line can be changed with a [EXAMINE_HINT("multitool")].") /obj/machinery/power/multitool_act(mob/living/user, obj/item/tool) diff --git a/code/modules/power/terminal.dm b/code/modules/power/terminal.dm index 4c861a4bb4b57..04b9ab8798b73 100644 --- a/code/modules/power/terminal.dm +++ b/code/modules/power/terminal.dm @@ -26,9 +26,9 @@ /obj/machinery/power/terminal/examine(mob/user) . = ..() if(!QDELETED(powernet)) - . += span_notice("It's operating on the [lowertext(GLOB.cable_layer_to_name["[cable_layer]"])].") + . += span_notice("It's operating on the [LOWER_TEXT(GLOB.cable_layer_to_name["[cable_layer]"])].") else - . += span_warning("It's disconnected from the [lowertext(GLOB.cable_layer_to_name["[cable_layer]"])].") + . += span_warning("It's disconnected from the [LOWER_TEXT(GLOB.cable_layer_to_name["[cable_layer]"])].") /obj/machinery/power/terminal/should_have_node() return TRUE diff --git a/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm index 2f2ff33025111..3fd769ddba9bb 100644 --- a/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm @@ -1658,7 +1658,7 @@ need_mob_update += drinker.adjustStaminaLoss(-heal_amt, updating_stamina = FALSE, required_biotype = affected_biotype) if(need_mob_update) drinker.updatehealth() - drinker.visible_message(span_warning("[drinker] shivers with renewed vigor!"), span_notice("One taste of [lowertext(name)] fills you with energy!")) + drinker.visible_message(span_warning("[drinker] shivers with renewed vigor!"), span_notice("One taste of [LOWER_TEXT(name)] fills you with energy!")) if(!drinker.stat && heal_points == 20) //brought us out of softcrit drinker.visible_message(span_danger("[drinker] lurches to [drinker.p_their()] feet!"), span_boldnotice("Up and at 'em, kid.")) diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm index 3f5ecd2000934..2e45ecf641bc1 100644 --- a/code/modules/reagents/chemistry/reagents/food_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm @@ -484,13 +484,13 @@ adjust_blood_flow(-0.06 * reac_volume, initial_flow * 0.6) // 20u of a salt shacker * 0.1 = -1.6~ blood flow, but is always clamped to, at best, third blood loss from that wound. // Crystal irritation worsening recovery. gauzed_clot_rate *= 0.65 - to_chat(carbies, span_notice("The salt bits seep in and stick to [lowertext(src)], painfully irritating the skin but soaking up most of the blood.")) + to_chat(carbies, span_notice("The salt bits seep in and stick to [LOWER_TEXT(src)], painfully irritating the skin but soaking up most of the blood.")) /datum/wound/slash/flesh/on_salt(reac_volume, mob/living/carbon/carbies) adjust_blood_flow(-0.1 * reac_volume, initial_flow * 0.5) // 20u of a salt shacker * 0.1 = -2~ blood flow, but is always clamped to, at best, halve blood loss from that wound. // Crystal irritation worsening recovery. clot_rate *= 0.75 - to_chat(carbies, span_notice("The salt bits seep in and stick to [lowertext(src)], painfully irritating the skin but soaking up most of the blood.")) + to_chat(carbies, span_notice("The salt bits seep in and stick to [LOWER_TEXT(src)], painfully irritating the skin but soaking up most of the blood.")) /datum/wound/burn/flesh/on_salt(reac_volume) // Slightly sanitizes and disinfects, but also increases infestation rate (some bacteria are aided by salt), and decreases flesh healing (can damage the skin from moisture absorption) @@ -498,7 +498,7 @@ infestation -= max(VALUE_PER(0.3, 30) * reac_volume, 0) infestation_rate += VALUE_PER(0.12, 30) * reac_volume flesh_healing -= max(VALUE_PER(5, 30) * reac_volume, 0) - to_chat(victim, span_notice("The salt bits seep in and stick to [lowertext(src)], painfully irritating the skin! After a few moments, it feels marginally better.")) + to_chat(victim, span_notice("The salt bits seep in and stick to [LOWER_TEXT(src)], painfully irritating the skin! After a few moments, it feels marginally better.")) /datum/reagent/consumable/blackpepper name = "Black Pepper" @@ -652,18 +652,18 @@ /datum/wound/pierce/bleed/on_flour(reac_volume, mob/living/carbon/carbies) adjust_blood_flow(-0.015 * reac_volume) // 30u of a flour sack * 0.015 = -0.45~ blood flow, prettay good - to_chat(carbies, span_notice("The flour seeps into [lowertext(src)], painfully drying it up and absorbing some of the blood.")) + to_chat(carbies, span_notice("The flour seeps into [LOWER_TEXT(src)], painfully drying it up and absorbing some of the blood.")) // When some nerd adds infection for wounds, make this increase the infection /datum/wound/slash/flesh/on_flour(reac_volume, mob/living/carbon/carbies) adjust_blood_flow(-0.04 * reac_volume) // 30u of a flour sack * 0.04 = -1.25~ blood flow, pretty good! - to_chat(carbies, span_notice("The flour seeps into [lowertext(src)], painfully drying some of it up and absorbing a little blood.")) + to_chat(carbies, span_notice("The flour seeps into [LOWER_TEXT(src)], painfully drying some of it up and absorbing a little blood.")) // When some nerd adds infection for wounds, make this increase the infection // Don't pour flour onto burn wounds, it increases infection risk! Very unwise. Backed up by REAL info from REAL professionals. // https://www.reuters.com/article/uk-factcheck-flour-burn-idUSKCN26F2N3 /datum/wound/burn/flesh/on_flour(reac_volume) - to_chat(victim, span_notice("The flour seeps into [lowertext(src)], spiking you with intense pain! That probably wasn't a good idea...")) + to_chat(victim, span_notice("The flour seeps into [LOWER_TEXT(src)], spiking you with intense pain! That probably wasn't a good idea...")) sanitization -= min(0, 1) infestation += 0.2 return @@ -758,18 +758,18 @@ /datum/wound/pierce/bleed/on_starch(reac_volume, mob/living/carbon/carbies) adjust_blood_flow(-0.03 * reac_volume) - to_chat(carbies, span_notice("The slimey starch seeps into [lowertext(src)], painfully drying some of it up and absorbing a little blood.")) + to_chat(carbies, span_notice("The slimey starch seeps into [LOWER_TEXT(src)], painfully drying some of it up and absorbing a little blood.")) // When some nerd adds infection for wounds, make this increase the infection return /datum/wound/slash/flesh/on_starch(reac_volume, mob/living/carbon/carbies) adjust_blood_flow(-0.06 * reac_volume) - to_chat(carbies, span_notice("The slimey starch seeps into [lowertext(src)], painfully drying it up and absorbing some of the blood.")) + to_chat(carbies, span_notice("The slimey starch seeps into [LOWER_TEXT(src)], painfully drying it up and absorbing some of the blood.")) // When some nerd adds infection for wounds, make this increase the infection return /datum/wound/burn/flesh/on_starch(reac_volume, mob/living/carbon/carbies) - to_chat(carbies, span_notice("The slimey starch seeps into [lowertext(src)], spiking you with intense pain! That probably wasn't a good idea...")) + to_chat(carbies, span_notice("The slimey starch seeps into [LOWER_TEXT(src)], spiking you with intense pain! That probably wasn't a good idea...")) sanitization -= min(0, 0.5) infestation += 0.1 return diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 75a7cfa579278..991cd5d3098bd 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -325,18 +325,18 @@ /datum/wound/pierce/bleed/on_saltwater(reac_volume, mob/living/carbon/carbies) adjust_blood_flow(-0.06 * reac_volume, initial_flow * 0.6) - to_chat(carbies, span_notice("The salt water splashes over [lowertext(src)], soaking up the blood.")) + to_chat(carbies, span_notice("The salt water splashes over [LOWER_TEXT(src)], soaking up the blood.")) /datum/wound/slash/flesh/on_saltwater(reac_volume, mob/living/carbon/carbies) adjust_blood_flow(-0.1 * reac_volume, initial_flow * 0.5) - to_chat(carbies, span_notice("The salt water splashes over [lowertext(src)], soaking up the blood.")) + to_chat(carbies, span_notice("The salt water splashes over [LOWER_TEXT(src)], soaking up the blood.")) /datum/wound/burn/flesh/on_saltwater(reac_volume) // Similar but better stats from normal salt. sanitization += VALUE_PER(0.6, 30) * reac_volume infestation -= max(VALUE_PER(0.5, 30) * reac_volume, 0) infestation_rate += VALUE_PER(0.07, 30) * reac_volume - to_chat(victim, span_notice("The salt water splashes over [lowertext(src)], soaking up the... miscellaneous fluids. It feels somewhat better afterwards.")) + to_chat(victim, span_notice("The salt water splashes over [LOWER_TEXT(src)], soaking up the... miscellaneous fluids. It feels somewhat better afterwards.")) return /datum/reagent/water/holywater @@ -711,7 +711,7 @@ var/datum/species/species_type = race affected_mob.set_species(species_type) holder.del_reagent(type) - to_chat(affected_mob, span_warning("You've become \a [lowertext(initial(species_type.name))]!")) + to_chat(affected_mob, span_warning("You've become \a [LOWER_TEXT(initial(species_type.name))]!")) return /datum/reagent/mutationtoxin/classic //The one from plasma on green slimes diff --git a/code/modules/reagents/reagent_containers/cups/_cup.dm b/code/modules/reagents/reagent_containers/cups/_cup.dm index cb3ab1a122bde..9aaafda4eaddd 100644 --- a/code/modules/reagents/reagent_containers/cups/_cup.dm +++ b/code/modules/reagents/reagent_containers/cups/_cup.dm @@ -23,7 +23,7 @@ . = ..() if(drink_type) var/list/types = bitfield_to_list(drink_type, FOOD_FLAGS) - . += span_notice("It is [lowertext(english_list(types))].") + . += span_notice("It is [LOWER_TEXT(english_list(types))].") /** * Checks if the mob actually liked drinking this cup. diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 530c4f3aa134b..1738bac95a247 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -342,13 +342,13 @@ for(var/datum/wound/wound as anything in wounds) switch(wound.severity) if(WOUND_SEVERITY_TRIVIAL) - check_list += "\t [span_danger("Your [name] is suffering [wound.a_or_from] [lowertext(wound.name)].")]" + check_list += "\t [span_danger("Your [name] is suffering [wound.a_or_from] [LOWER_TEXT(wound.name)].")]" if(WOUND_SEVERITY_MODERATE) - check_list += "\t [span_warning("Your [name] is suffering [wound.a_or_from] [lowertext(wound.name)]!")]" + check_list += "\t [span_warning("Your [name] is suffering [wound.a_or_from] [LOWER_TEXT(wound.name)]!")]" if(WOUND_SEVERITY_SEVERE) - check_list += "\t [span_boldwarning("Your [name] is suffering [wound.a_or_from] [lowertext(wound.name)]!!")]" + check_list += "\t [span_boldwarning("Your [name] is suffering [wound.a_or_from] [LOWER_TEXT(wound.name)]!!")]" if(WOUND_SEVERITY_CRITICAL) - check_list += "\t [span_boldwarning("Your [name] is suffering [wound.a_or_from] [lowertext(wound.name)]!!!")]" + check_list += "\t [span_boldwarning("Your [name] is suffering [wound.a_or_from] [LOWER_TEXT(wound.name)]!!!")]" for(var/obj/item/embedded_thing in embedded_objects) var/stuck_word = embedded_thing.isEmbedHarmless() ? "stuck" : "embedded" diff --git a/code/modules/surgery/organs/internal/eyes/_eyes.dm b/code/modules/surgery/organs/internal/eyes/_eyes.dm index aaf79ba755369..bffdf1ae44d08 100644 --- a/code/modules/surgery/organs/internal/eyes/_eyes.dm +++ b/code/modules/surgery/organs/internal/eyes/_eyes.dm @@ -501,7 +501,7 @@ set_beam_color(new_color, to_update) return TRUE if("enter_color") - var/new_color = lowertext(params["new_color"]) + var/new_color = LOWER_TEXT(params["new_color"]) var/to_update = params["to_update"] set_beam_color(new_color, to_update, sanitize = TRUE) return TRUE diff --git a/code/modules/surgery/organs/internal/tongue/_tongue.dm b/code/modules/surgery/organs/internal/tongue/_tongue.dm index 5098d738d305b..469879263cc85 100644 --- a/code/modules/surgery/organs/internal/tongue/_tongue.dm +++ b/code/modules/surgery/organs/internal/tongue/_tongue.dm @@ -444,7 +444,7 @@ GLOBAL_LIST_INIT(english_to_zombie, list()) var/list/message_word_list = splittext(message, " ") var/list/translated_word_list = list() for(var/word in message_word_list) - word = GLOB.english_to_zombie[lowertext(word)] + word = GLOB.english_to_zombie[LOWER_TEXT(word)] translated_word_list += word ? word : FALSE // all occurrences of characters "eiou" (case-insensitive) are replaced with "r" diff --git a/code/modules/tooltip/tooltip.dm b/code/modules/tooltip/tooltip.dm index 4b9514aa38c11..9956305db26e0 100644 --- a/code/modules/tooltip/tooltip.dm +++ b/code/modules/tooltip/tooltip.dm @@ -112,7 +112,7 @@ Notes: return var/ui_style = user.client?.prefs?.read_preference(/datum/preference/choiced/ui_style) if(!theme && ui_style) - theme = lowertext(ui_style) + theme = LOWER_TEXT(ui_style) if(!theme) theme = "default" user.client.tooltips.show(tip_src, params, title, content, theme) diff --git a/code/modules/wiremod/components/action/equpiment_action.dm b/code/modules/wiremod/components/action/equpiment_action.dm index 54150ca44d60b..641722c595b60 100644 --- a/code/modules/wiremod/components/action/equpiment_action.dm +++ b/code/modules/wiremod/components/action/equpiment_action.dm @@ -89,4 +89,4 @@ for(var/ref in granted_to) var/datum/action/granted_action = granted_to[ref] granted_action.name = button_name.value || "Action" - granted_action.button_icon_state = "bci_[replacetextEx(lowertext(icon_options.value), " ", "_")]" + granted_action.button_icon_state = "bci_[replacetextEx(LOWER_TEXT(icon_options.value), " ", "_")]" diff --git a/code/modules/wiremod/components/string/textcase.dm b/code/modules/wiremod/components/string/textcase.dm index ac28965423632..70b67740b416f 100644 --- a/code/modules/wiremod/components/string/textcase.dm +++ b/code/modules/wiremod/components/string/textcase.dm @@ -41,7 +41,7 @@ var/result switch(textcase_options.value) if(COMP_TEXT_LOWER) - result = lowertext(value) + result = LOWER_TEXT(value) if(COMP_TEXT_UPPER) result = uppertext(value) diff --git a/code/modules/wiremod/core/component.dm b/code/modules/wiremod/core/component.dm index 530f73ded8cd6..4d8344e1e6aa1 100644 --- a/code/modules/wiremod/core/component.dm +++ b/code/modules/wiremod/core/component.dm @@ -77,7 +77,7 @@ /obj/item/circuit_component/Initialize(mapload) . = ..() if(name == COMPONENT_DEFAULT_NAME) - name = "[lowertext(display_name)] [COMPONENT_DEFAULT_NAME]" + name = "[LOWER_TEXT(display_name)] [COMPONENT_DEFAULT_NAME]" populate_options() populate_ports() if((circuit_flags & CIRCUIT_FLAG_INPUT_SIGNAL) && !trigger_input) diff --git a/code/modules/wiremod/shell/module.dm b/code/modules/wiremod/shell/module.dm index 6f9a3dda93b7e..9061bac3e300e 100644 --- a/code/modules/wiremod/shell/module.dm +++ b/code/modules/wiremod/shell/module.dm @@ -106,7 +106,7 @@ action_comp.granted_to[REF(user)] = src circuit_component = action_comp name = action_comp.button_name.value - button_icon_state = "bci_[replacetextEx(lowertext(action_comp.icon_options.value), " ", "_")]" + button_icon_state = "bci_[replacetextEx(LOWER_TEXT(action_comp.icon_options.value), " ", "_")]" /datum/action/item_action/mod/pinnable/circuit/Destroy() circuit_component.granted_to -= REF(pinner) diff --git a/tools/ci/check_grep.sh b/tools/ci/check_grep.sh index 8763cca749e4c..5a3606d71ed14 100644 --- a/tools/ci/check_grep.sh +++ b/tools/ci/check_grep.sh @@ -152,6 +152,16 @@ if $grep -i '(add_traits|remove_traits)\(.+,\s*src\)' $code_files; then st=1 fi; +part "ensure proper lowertext usage" +# lowertext() is a BYOND-level proc, so it can be used in any sort of code... including the TGS DMAPI which we don't manage in this repository. +# basically, we filter out any results with "tgs" in it to account for this edgecase without having to enforce this rule in that separate codebase. +# grepping the grep results is a bit of a sad solution to this but it's pretty much the only option in our existing linter framework +if $grep -i 'lowertext\(.+\)' $code_files | $grep -v 'UNLINT\(.+\)' | $grep -v '\/modules\/tgs\/'; then + echo + echo -e "${RED}ERROR: Found a lowertext() proc call. Please use the LOWER_TEXT() macro instead. If you know what you are doing, wrap your text (ensure it is a string) in UNLINT().${NC}" + st=1 +fi; + part "balloon_alert sanity" if $grep 'balloon_alert\(".*"\)' $code_files; then echo From 5dbeeb6f9974d0b260f1a457672f60301f02855d Mon Sep 17 00:00:00 2001 From: Boviro <99471923+Boviro@users.noreply.github.com> Date: Wed, 10 Apr 2024 12:21:13 -0700 Subject: [PATCH 145/938] Atmos Tech Clothing QOL and Advanced Extinguisher Tweak (#82462) Changes Advanced Extinguisher capacity to 100u foam Adds the ability for atmos technicians to store extinguishers in the suit storage slot on atmospherics overalls ## About The Pull Request Allows for atmos technicians to store extinguishers on their shiftstart overalls without using backpack space or wearing the atmos firesuit, and helps set the Advanced Extinguisher apart from the regular ones in every cabinet. ## Why It's Good For The Game QOL change for atmos technicians via a minor change to their shiftstart overalls, giving them the ability to actually act as firefighters better by actually carrying an extinguisher on them without wasting backpack space. It also just makes more sense than them NOT being able to. Also makes the advanced extinguisher slightly more useful to help encourage techs to carry it with them instead of just sprinting for the closest conventional extinguisher when a fire breaks out. ## Changelog :cl: qol: Atmospherics Overalls now can store fire extinguishers in the suit storage slot balance: Increased Advanced Extinguisher capacity to 100u /:cl: --- code/game/objects/items/extinguisher.dm | 1 + code/modules/clothing/suits/jobs.dm | 1 + 2 files changed, 2 insertions(+) diff --git a/code/game/objects/items/extinguisher.dm b/code/game/objects/items/extinguisher.dm index c949380d743fe..ca9c16ccc64aa 100644 --- a/code/game/objects/items/extinguisher.dm +++ b/code/game/objects/items/extinguisher.dm @@ -124,6 +124,7 @@ tanktype = /obj/structure/reagent_dispensers/foamtank sprite_name = "foam_extinguisher" precision = TRUE + max_water = 100 /obj/item/extinguisher/advanced/empty starting_water = FALSE diff --git a/code/modules/clothing/suits/jobs.dm b/code/modules/clothing/suits/jobs.dm index f73fb78c2886d..a8b2a52ff0478 100644 --- a/code/modules/clothing/suits/jobs.dm +++ b/code/modules/clothing/suits/jobs.dm @@ -425,6 +425,7 @@ /obj/item/t_scanner, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, + /obj/item/extinguisher, ) /datum/armor/atmos_overalls From fcf1b97dbab58d923c9ff57af243554cbb346e7b Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 11 Apr 2024 07:22:40 +1200 Subject: [PATCH 146/938] Automatic changelog for PR #82458 [ci skip] --- html/changelogs/AutoChangeLog-pr-82458.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82458.yml diff --git a/html/changelogs/AutoChangeLog-pr-82458.yml b/html/changelogs/AutoChangeLog-pr-82458.yml new file mode 100644 index 0000000000000..b6045d8d5cf30 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82458.yml @@ -0,0 +1,4 @@ +author: "Watermelon914" +delete-after: True +changes: + - admin: "LUA - Adds a new library called handler_group. Include it in your files by doing require('handler_group')" \ No newline at end of file From 4199270bf36de9987ed17770e8f69a767100b814 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 11 Apr 2024 07:33:00 +1200 Subject: [PATCH 147/938] Automatic changelog for PR #82366 [ci skip] --- html/changelogs/AutoChangeLog-pr-82366.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82366.yml diff --git a/html/changelogs/AutoChangeLog-pr-82366.yml b/html/changelogs/AutoChangeLog-pr-82366.yml new file mode 100644 index 0000000000000..0ba83be5af53d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82366.yml @@ -0,0 +1,4 @@ +author: "SethLafuente" +delete-after: True +changes: + - bugfix: "Fixes Radiation Hood not having FOV blockage" \ No newline at end of file From 93c872626abf77ebb7c0ac86144ae7888f4596df Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 11 Apr 2024 07:33:59 +1200 Subject: [PATCH 148/938] Automatic changelog for PR #82462 [ci skip] --- html/changelogs/AutoChangeLog-pr-82462.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82462.yml diff --git a/html/changelogs/AutoChangeLog-pr-82462.yml b/html/changelogs/AutoChangeLog-pr-82462.yml new file mode 100644 index 0000000000000..30d88ce8c88b2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82462.yml @@ -0,0 +1,5 @@ +author: "Boviro" +delete-after: True +changes: + - qol: "Atmospherics Overalls now can store fire extinguishers in the suit storage slot" + - balance: "Increased Advanced Extinguisher capacity to 100u" \ No newline at end of file From e64331f6782e50163044c7cc4c4526f6bb068c98 Mon Sep 17 00:00:00 2001 From: YesterdaysPromise <122572637+YesterdaysPromise@users.noreply.github.com> Date: Thu, 11 Apr 2024 01:58:15 +0200 Subject: [PATCH 149/938] Clowns can now make balloon... toys. And also mallets and hats. (#82288) ## About The Pull Request Clowns will now start with a box of 24 random long balloons and a skillchip in their noggin allowing them to create balloon animals by combining two of them of different colour together. Owners of the skillchip also gain access to crafting recepies of balloon mallets, vests, helmets and tophats, all created from long balloons. A crate of long balloons, with a box of balloons inside, can be bought at cargo, in case the clown runs out. I might edit this once I wake up, its 3 in the morning right now. Oh also, resprited how balloons look in inventory. ![image](https://github.com/tgstation/tgstation/assets/122572637/2d7ce955-c787-48a5-bfda-4613d2eed837) ## Why It's Good For The Game Balloon animals funny. Silly features are my favourite kind of features, and this one's open-ended too. Someone on the coder chat recommended someone would do it that one time, here it goes. ## Changelog :cl: add: Added long balloon box to the clown's starting inventory, and a skill-chip of long lost honk-motherian knowledge to their brain. add: Added long balloons. Consequently, added balloon animals to make from such balloons. Also, balloon top hat, vest, helmet, and a mallet. Don't ask about the mallet. add: A long balloons box harvested fresh from the farms on the clown planet will be able to be shipped in a crate to the cargo department near you! add: As per requests; water balloons can now be printed at service lathe, and entertainment modsuit can now blow long balloons! image: Balloons will now have an unique sprite when in the inventory, compared when to on the ground. /:cl: --------- Co-authored-by: _0Steven <42909981+00-Steven@users.noreply.github.com> Co-authored-by: san7890 Co-authored-by: Jacquerel --- code/__DEFINES/traits/declarations.dm | 2 + code/_globalvars/traits/_traits.dm | 1 + .../components/crafting/melee_weapon.dm | 15 ++ code/datums/components/crafting/tailoring.dm | 39 ++++ .../mood_events/generic_negative_events.dm | 5 + .../items/storage/boxes/service_boxes.dm | 16 ++ code/game/objects/items/toys.dm | 174 +++++++++++++++++- code/game/objects/items/weaponry.dm | 42 +++++ code/modules/cargo/packs/costumes_toys.dm | 12 ++ code/modules/clothing/head/helmet.dm | 15 ++ code/modules/clothing/head/tophat.dm | 9 + code/modules/clothing/suits/armor.dm | 34 ++++ code/modules/jobs/job_types/clown.dm | 2 + .../skill_learning/job_skillchips/clown.dm | 10 + code/modules/mod/mod_theme.dm | 1 + code/modules/mod/mod_types.dm | 1 + code/modules/mod/modules/modules_service.dm | 25 +++ code/modules/research/designs/misc_designs.dm | 11 ++ icons/mob/clothing/head/hats.dmi | Bin 16371 -> 14949 bytes icons/mob/clothing/head/helmet.dmi | Bin 42375 -> 43611 bytes icons/mob/clothing/suits/armor.dmi | Bin 99362 -> 101933 bytes icons/mob/inhands/clothing/hats_lefthand.dmi | Bin 23456 -> 23412 bytes icons/mob/inhands/clothing/hats_righthand.dmi | Bin 23365 -> 23924 bytes icons/mob/inhands/clothing/suits_lefthand.dmi | Bin 46960 -> 48157 bytes .../mob/inhands/clothing/suits_righthand.dmi | Bin 47677 -> 48819 bytes icons/mob/inhands/items/balloons_lefthand.dmi | Bin 3103 -> 6608 bytes .../mob/inhands/items/balloons_righthand.dmi | Bin 3211 -> 6727 bytes .../mob/inhands/weapons/hammers_lefthand.dmi | Bin 5995 -> 6255 bytes .../mob/inhands/weapons/hammers_righthand.dmi | Bin 5914 -> 6162 bytes icons/obj/clothing/head/hats.dmi | Bin 6029 -> 6256 bytes icons/obj/clothing/head/helmet.dmi | Bin 20487 -> 20861 bytes icons/obj/clothing/suits/armor.dmi | Bin 32783 -> 34336 bytes icons/obj/storage/box.dmi | Bin 13056 -> 13169 bytes icons/obj/toys/balloons.dmi | Bin 1523 -> 14124 bytes icons/obj/toys/toy.dmi | Bin 51848 -> 51346 bytes icons/obj/weapons/hammer.dmi | Bin 9995 -> 12264 bytes tgstation.dme | 1 + 37 files changed, 409 insertions(+), 6 deletions(-) create mode 100644 code/modules/library/skill_learning/job_skillchips/clown.dm diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index c833fdf4e142d..c61e1c2ef9c4a 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -587,6 +587,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_BRAINWASHING "brainwashing" /// Allows chef's to chefs kiss their food, to make them with love #define TRAIT_CHEF_KISS "chefs_kiss" +/// Allows clowns to bend balloons into animals +#define TRAIT_BALLOON_SUTRA "balloon_sutra" ///Movement type traits for movables. See elements/movetype_handler.dm #define TRAIT_MOVE_GROUND "move_ground" diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index d038eee953f45..49ea900419810 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -135,6 +135,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_BADDNA" = TRAIT_BADDNA, "TRAIT_BADTOUCH" = TRAIT_BADTOUCH, "TRAIT_BALD" = TRAIT_BALD, + "TRAIT_BALLOON_SUTRA" = TRAIT_BALLOON_SUTRA, "TRAIT_BATON_RESISTANCE" = TRAIT_BATON_RESISTANCE, "TRAIT_BEING_BLADE_SHIELDED" = TRAIT_BEING_BLADE_SHIELDED, "TRAIT_BLOB_ALLY" = TRAIT_BLOB_ALLY, diff --git a/code/datums/components/crafting/melee_weapon.dm b/code/datums/components/crafting/melee_weapon.dm index 23873a5d7af94..869d223a758c9 100644 --- a/code/datums/components/crafting/melee_weapon.dm +++ b/code/datums/components/crafting/melee_weapon.dm @@ -44,6 +44,21 @@ time = 4 SECONDS category = CAT_WEAPON_MELEE + +/datum/crafting_recipe/balloon_mallet + name = "Balloon Mallet" + result = /obj/item/balloon_mallet + reqs = list( + /obj/item/toy/balloon/long = 18, + ) + time = 10 SECONDS + category = CAT_WEAPON_MELEE + +/datum/crafting_recipe/balloon_mallet/check_requirements(mob/user, list/collected_requirements) + . = ..() + if(HAS_TRAIT(user, TRAIT_BALLOON_SUTRA)) + return TRUE + /datum/crafting_recipe/tailwhip name = "Liz O' Nine Tails" result = /obj/item/melee/chainofcommand/tailwhip diff --git a/code/datums/components/crafting/tailoring.dm b/code/datums/components/crafting/tailoring.dm index 14a7ebfc21b01..3476016ead3b8 100644 --- a/code/datums/components/crafting/tailoring.dm +++ b/code/datums/components/crafting/tailoring.dm @@ -442,3 +442,42 @@ /obj/item/clothing/suit/armor/vest = 1, ) category = CAT_CLOTHING + +/datum/crafting_recipe/balloon_helmet + result = /obj/item/clothing/head/helmet/balloon + reqs = list( + /obj/item/toy/balloon/long = 6, + ) + time = 4 SECONDS + category = CAT_CLOTHING + +/datum/crafting_recipe/balloon_helmet/check_requirements(mob/user, list/collected_requirements) + . = ..() + if(HAS_TRAIT(user, TRAIT_BALLOON_SUTRA)) + return TRUE + +/datum/crafting_recipe/balloon_tophat + result = /obj/item/clothing/head/hats/tophat/balloon + reqs = list( + /obj/item/toy/balloon/long = 6, + ) + time = 4 SECONDS + category = CAT_CLOTHING + +/datum/crafting_recipe/balloon_tophat/check_requirements(mob/user, list/collected_requirements) + . = ..() + if(HAS_TRAIT(user, TRAIT_BALLOON_SUTRA)) + return TRUE + +/datum/crafting_recipe/balloon_vest + result = /obj/item/clothing/suit/armor/balloon_vest + reqs = list( + /obj/item/toy/balloon/long = 18, + ) + time = 8 SECONDS + category = CAT_CLOTHING + +/datum/crafting_recipe/balloon_vest/check_requirements(mob/user, list/collected_requirements) + . = ..() + if(HAS_TRAIT(user, TRAIT_BALLOON_SUTRA)) + return TRUE diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm index 0cfb48f7a9823..0e54c21e70234 100644 --- a/code/datums/mood_events/generic_negative_events.dm +++ b/code/datums/mood_events/generic_negative_events.dm @@ -474,6 +474,11 @@ mood_change = -6 timeout = 5 MINUTES +/datum/mood_event/mallet_humiliation + description = "Getting hit by such a stupid weapon feels rather humiliating..." + mood_change = -3 + timeout = 10 SECONDS + ///Wizard cheesy grand finale - what everyone but the wizard gets /datum/mood_event/madness_despair description = "UNWORTHY, UNWORTHY, UNWORTHY!!!" diff --git a/code/game/objects/items/storage/boxes/service_boxes.dm b/code/game/objects/items/storage/boxes/service_boxes.dm index 8dcc1f4f6b62f..6dc790cc49545 100644 --- a/code/game/objects/items/storage/boxes/service_boxes.dm +++ b/code/game/objects/items/storage/boxes/service_boxes.dm @@ -204,6 +204,22 @@ for(var/i in 1 to 5) new /obj/item/reagent_containers/spray/chemsprayer/party(src) +/obj/item/storage/box/balloons + name = "box of long balloons" + desc = "A completely randomized and wacky box of long balloons, harvested straight from balloon farms on the clown planet." + illustration = "balloon" + +/obj/item/storage/box/balloons/Initialize(mapload) + . = ..() + atom_storage.max_slots = 24 + atom_storage.set_holdable(list(/obj/item/toy/balloon/long)) + atom_storage.max_total_storage = 24 + atom_storage.allow_quick_gather = FALSE + +/obj/item/storage/box/balloons/PopulateContents() + for(var/i in 1 to 24) + new /obj/item/toy/balloon/long(src) + /obj/item/storage/box/stickers name = "box of stickers" desc = "A box full of random stickers. Do give to the clown." diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 67192b829a74d..8ac1ee98994a1 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -39,8 +39,8 @@ /obj/item/toy/waterballoon name = "water balloon" desc = "A translucent balloon. There's nothing in it." - icon = 'icons/obj/toys/toy.dmi' - icon_state = "waterballoon-e" + icon = 'icons/obj/toys/balloons.dmi' + icon_state = "balloon_red-e" inhand_icon_state = "balloon-empty" /obj/item/toy/waterballoon/Initialize(mapload) @@ -107,15 +107,15 @@ icon_state = "waterballoon" inhand_icon_state = "balloon" else - icon_state = "waterballoon-e" + icon_state = "balloon_red-e" inhand_icon_state = "balloon-empty" return ..() -#define BALLOON_COLORS list("red", "blue", "green", "yellow") +#define BALLOON_COLORS list("red", "blue", "green", "yellow", "orange", "purple") /obj/item/toy/balloon name = "balloon" - desc = "No birthday is complete without it." + desc = "No birthday is complete without it. Sealed with a mechanical bluespace wrap so it remains floating no matter what." icon = 'icons/obj/toys/balloons.dmi' icon_state = "balloon" inhand_icon_state = "balloon" @@ -127,6 +127,68 @@ throw_range = 7 force = 0 var/random_color = TRUE + /// the string of the dmi state the balloon has while on the floor. + var/world_state + /// the string of the dmi state the balloon has while in your inventory. + var/storage_state + /// the string describing the name of balloon's current colour. + var/current_color + +/obj/item/toy/balloon/long + name = "long balloon" + desc = "A perfect balloon to contort into goofy forms. Sealed with a mechanical bluespace wrap so it remains floating no matter what." + icon_state = "balloon_long" + inhand_icon_state = "balloon" + w_class = WEIGHT_CLASS_NORMAL + /// Combinations of balloon colours to make specific animals. + var/list/balloon_combos = list( + list("red", "blue") = /obj/item/toy/balloon_animal/guy, + list("red", "green") = /obj/item/toy/balloon_animal/nukie, + list("red", "yellow") = /obj/item/toy/balloon_animal/clown, + list("red", "orange") = /obj/item/toy/balloon_animal/cat, + list("red", "purple") = /obj/item/toy/balloon_animal/fly, + list("blue", "green") = /obj/item/toy/balloon_animal/podguy, + list("blue", "yellow") = /obj/item/toy/balloon_animal/ai, + list("blue", "orange") = /obj/item/toy/balloon_animal/dog, + list("blue", "purple") = /obj/item/toy/balloon_animal/xeno, + list("green", "yellow") = /obj/item/toy/balloon_animal/banana, + list("green", "orange") = /obj/item/toy/balloon_animal/lizard, + list("green", "purple") = /obj/item/toy/balloon_animal/slime, + list("yellow", "orange") = /obj/item/toy/balloon_animal/moth, + list("yellow", "purple") = /obj/item/toy/balloon_animal/ethereal, + list("orange", "purple") = /obj/item/toy/balloon_animal/plasmaman, + ) + +/obj/item/toy/balloon/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change) + . = ..() + if(isturf(loc)) + icon_state = "[world_state]" + else + icon_state = "[storage_state]" + update_appearance() + +/obj/item/toy/balloon/long/attackby(obj/item/attacking_item, mob/living/user, params) + if(!istype(attacking_item, /obj/item/toy/balloon/long) || !HAS_TRAIT(user, TRAIT_BALLOON_SUTRA)) + return ..() + + var/obj/item/toy/balloon/long/hit_by = attacking_item + if(hit_by.current_color == current_color) + to_chat(user, span_warning("You must use balloons of different colours to do that!")) + return ..() + visible_message( + span_notice("[user.name] starts contorting up a balloon animal!"), + blind_message = span_hear("You hear balloons being contorted."), + vision_distance = 3, + ignored_mobs = user, + ) + for(var/list/pair_of_colors in balloon_combos) + if((hit_by.current_color == pair_of_colors[1] && current_color == pair_of_colors[2]) || (current_color == pair_of_colors[1] && hit_by.current_color == pair_of_colors[2])) + var/path_to_spawn = balloon_combos[pair_of_colors] + user.put_in_hands(new path_to_spawn) + break + qdel(hit_by) + qdel(src) + return TRUE /obj/item/toy/balloon/attackby(obj/item/I, mob/user, params) if(istype(I, /obj/item/ammo_casing/foam_dart) && ismonkey(user)) @@ -157,17 +219,27 @@ . = ..() if(random_color) var/chosen_balloon_color = pick(BALLOON_COLORS) + current_color = "[chosen_balloon_color]" name = "[chosen_balloon_color] [name]" icon_state = "[icon_state]_[chosen_balloon_color]" inhand_icon_state = icon_state + world_state = "[icon_state]" + storage_state = "[icon_state]_storage" /obj/item/toy/balloon/corgi name = "corgi balloon" - desc = "A balloon with a corgi face on it. For the all year good boys." + desc = "A balloon in the shape of a corgi's head. For the all year good boys." icon_state = "corgi" inhand_icon_state = "corgi" random_color = FALSE +/obj/item/toy/balloon/heart + name = "heart balloon" + desc = "A balloon in the shape of a heart. How lovely" + icon_state = "heart" + inhand_icon_state = "heart" + random_color = FALSE + /obj/item/toy/balloon/syndicate name = "syndicate balloon" desc = "There is a tag on the back that reads \"FUK NT!11!\"." @@ -200,6 +272,96 @@ #undef BALLOON_COLORS +/* +* Balloon animals +*/ + +/obj/item/toy/balloon_animal + name = "balloon animal" + desc = "You shouldn't have this." + icon = 'icons/obj/toys/balloons.dmi' + icon_state = "balloon_guy" + throwforce = 0 + throw_speed = 2 + throw_range = 5 + force = 0 + +/obj/item/toy/balloon_animal/guy + name = "balloon guy" + desc = "A balloon effigy of the everyday standard issue human guy. Wonder if he pays balloon taxes. He probably evades them." + icon_state = "balloon_guy" + +/obj/item/toy/balloon_animal/nukie + name = "balloon nukie" + desc = "A balloon effigy of syndicate's nuclear operative. Either made to appease them and pray for survival, or to poke fun at them." + icon_state = "balloon_nukie" + +/obj/item/toy/balloon_animal/clown + name = "balloon clown" + desc = "A balloon clown, smiling from ear to ear and beyond!" + icon_state = "balloon_clown" + +/obj/item/toy/balloon_animal/cat + name = "balloon cat" + desc = "Without the sharp claws, balloon cats are possibly cuter than their live counterparts, though not as relatable, warm and fuzzy." + icon_state = "balloon_cat" + +/obj/item/toy/balloon_animal/fly + name = "balloon fly" + desc = "A balloon effigy of a flyperson. Thankfully, it doesn't come with balloon vomit." + icon_state = "balloon_fly" + +/obj/item/toy/balloon_animal/podguy + name = "balloon podguy" + desc = "A balloon effigy of a podperson. Though, actual podpeople have heads and not stalks and leaves." + icon_state = "balloon_podguy" + +/obj/item/toy/balloon_animal/ai + name = "balloon ai core" + desc = "A somewhat unrealistic balloon effigy of the station's AI core. Actual AI propably wouldn't smile like this." + icon_state = "balloon_ai" + +/obj/item/toy/balloon_animal/dog + name = "balloon dog" + desc = "A balloon effigy of the best boy. It cannot truly compare, but it makes an effort." + icon_state = "balloon_dog" + +/obj/item/toy/balloon_animal/xeno + name = "balloon xeno" + desc = "A balloon effigy of a spooky xeno! Too squishy to scare anyone itself, though." + icon_state = "balloon_xeno" + +/obj/item/toy/balloon_animal/banana + name = "balloon banana" + desc = "A balloon banana. This one can't be slipped on. Good for psychological warfare, though." + icon_state = "balloon_banana" + +/obj/item/toy/balloon_animal/lizard + name = "balloon lizard" + desc = "A balloon effigy of a lizard. One of the first species to adapt to clown planet's culture. Perhaps because they are naturally laughable?" + icon_state = "balloon_lizard" + +/obj/item/toy/balloon_animal/slime + name = "balloon slime" + desc = "A balloon effigy of single specimen of the galaxy-wide slime scourge, of purple variety. Slimes tried to invade clown planet once. They got quickly washed out by water-spitting flowers, though." + icon_state = "balloon_slime" + +/obj/item/toy/balloon_animal/moth + name = "balloon moth" + desc = "A balloon effigy of a common member of moth flotillas. Very few of them ever decide to settle on the clown planet, but those who do have the best 'piece-of-cloth-dissapearing' acts." + icon_state = "balloon_moth" + +/obj/item/toy/balloon_animal/ethereal + name = "balloon ethereal" + desc = "A balloon effigy of an ethereal artisan. Clownery is one form of art, and as such, ethereals were both drawn to and readily accepted at clown planet. Don't mind the lighbulb head, it's art too." + icon_state = "balloon_ethereal" + +/obj/item/toy/balloon_animal/plasmaman + name = "balloon plasmaman" + desc = "A balloon effigy of a plasmaman. Among the rarest on the clown planet, only having appeared recently thanks to ready trade between clown planet and NT." + icon_state = "balloon_plasmaman" + + /* * Captain's Aid */ diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index 1f2078f0037d0..2aa649844e555 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -40,6 +40,48 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 if(user.combat_mode) return ..(M, user) + +/obj/item/balloon_mallet + name = "balloon mallet" + desc = "It's a mallet, a weapon known for being heavy, but made from notoriously light balloons. Air inside removes any force from the swings. It'd be quite embarrassing to get hit by this." + icon = 'icons/obj/weapons/hammer.dmi' + icon_state = "balloon_mallet" + inhand_icon_state = "balloon_mallet" + lefthand_file = 'icons/mob/inhands/weapons/hammers_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/hammers_righthand.dmi' + siemens_coefficient = 0 + force = 1 + throw_speed = 1 + throwforce = 1 + throw_range = 1 + w_class = WEIGHT_CLASS_HUGE + attack_verb_continuous = list("mallets", "smoother") + attack_verb_simple = list("mallet", "smoother") + max_integrity = 20 + armor_type = /datum/armor/item_banhammer + resistance_flags = FIRE_PROOF + +/obj/item/balloon_mallet/examine(mob/user) + . = ..() + if(HAS_TRAIT(user,TRAIT_BALLOON_SUTRA)) + . = "A sacred weapon of the higher castes from the clown planet, used to strike fear into the hearts of their foes. Wield it with care." + +/obj/item/balloon_mallet/attack(mob/living/target, mob/living/user) + playsound(loc, 'sound/creatures/clown/hehe.ogg', 20) + if (!isliving(target)) + return + switch(target.mob_mood.sanity) + if (SANITY_INSANE to SANITY_CRAZY) + force = 8 + if (SANITY_UNSTABLE to SANITY_DISTURBED) + force = 4 + target.add_mood_event("humiliated", /datum/mood_event/mallet_humiliation) + if (SANITY_NEUTRAL to SANITY_GREAT) + target.add_mood_event("humiliated", /datum/mood_event/mallet_humiliation) + + if(user.combat_mode) + return ..(target, user) + /obj/item/sord name = "\improper SORD" desc = "This thing is so unspeakably shitty you are having a hard time even holding it." diff --git a/code/modules/cargo/packs/costumes_toys.dm b/code/modules/cargo/packs/costumes_toys.dm index e23e6112a4bfc..de84a263597da 100644 --- a/code/modules/cargo/packs/costumes_toys.dm +++ b/code/modules/cargo/packs/costumes_toys.dm @@ -268,3 +268,15 @@ crate_name = "corgi pinata kit" crate_type = /obj/structure/closet/crate/wooden discountable = SUPPLY_PACK_STD_DISCOUNTABLE + +/datum/supply_pack/costumes_toys/balloons + name = "Long Balloons Kit" + desc = "This crate contains a box of long balloons, plus a skillchip for non-clowns to join the fun! Extra layer of safety so clowns at CentCom won't get to them." + cost = CARGO_CRATE_VALUE * 4 + contains = list( + /obj/item/storage/box/balloons, + /obj/item/skillchip/job/clown, + ) + crate_name = "long balloons kit" + crate_type = /obj/structure/closet/crate/wooden + discountable = SUPPLY_PACK_STD_DISCOUNTABLE diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm index bf96acaccb66a..236d94c39fabc 100644 --- a/code/modules/clothing/head/helmet.dm +++ b/code/modules/clothing/head/helmet.dm @@ -195,6 +195,21 @@ acid = 80 wound = 15 +/obj/item/clothing/head/helmet/balloon + name = "balloon helmet" + desc = "A helmet made out of balloons. Its likes saw great usage in the Great Clown - Mime War. Surprisingly resistant to fire. Mimes were doing unspeakable things." + icon_state = "helmet_balloon" + inhand_icon_state = "helmet_balloon" + armor_type = /datum/armor/balloon + flags_inv = HIDEHAIR|HIDEEARS|HIDESNOUT + resistance_flags = FIRE_PROOF + dog_fashion = null + +/datum/armor/balloon + melee = 10 + fire = 60 + acid = 50 + /obj/item/clothing/head/helmet/toggleable/justice name = "helmet of justice" desc = "WEEEEOOO. WEEEEEOOO. WEEEEOOOO." diff --git a/code/modules/clothing/head/tophat.dm b/code/modules/clothing/head/tophat.dm index 26087ab6232e0..2affc4c63da18 100644 --- a/code/modules/clothing/head/tophat.dm +++ b/code/modules/clothing/head/tophat.dm @@ -36,4 +36,13 @@ var/mob/living/basic/rabbit/bunbun = new(get_turf(magician)) bunbun.mob_try_pickup(magician, instant=TRUE) +/obj/item/clothing/head/hats/tophat/balloon + name = "balloon top-hat" + desc = "It's an colourful looking top-hat to match yout colourful personality." + icon_state = "balloon_tophat" + inhand_icon_state = "balloon_that" + throwforce = 0 + resistance_flags = FIRE_PROOF + dog_fashion = null + #undef RABBIT_CD_TIME diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index 10ef4c45163f2..32bf993cf9b1f 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -312,6 +312,40 @@ acid = 50 wound = 10 +/obj/item/clothing/suit/armor/balloon_vest + name = "balloon vest" + desc = "A vest made entirely from balloons, resistant to any evil forces a mime could throw at you, including electricity and fire. Just a strike with something sharp, though..." + icon_state = "balloon-vest" + inhand_icon_state = "balloon_armor" + blood_overlay_type = "armor" + armor_type = /datum/armor/balloon_vest + siemens_coefficient = 0 + strip_delay = 70 + equip_delay_other = 50 + +/datum/armor/balloon_vest + melee = 10 + laser = 10 + energy = 10 + fire = 60 + acid = 50 + +/obj/item/clothing/suit/armor/balloon_vest/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE) + if(isitem(hitby)) + var/obj/item/item_hit = hitby + if(item_hit.sharpness) + pop() + + if(istype(hitby, /obj/projectile/bullet)) + pop() + + return ..() + +/obj/item/clothing/suit/armor/balloon_vest/proc/pop() + playsound(src, 'sound/effects/cartoon_pop.ogg', 50, vary = TRUE) + qdel(src) + + /obj/item/clothing/suit/armor/bulletproof name = "bulletproof armor" desc = "A Type III heavy bulletproof vest that excels in protecting the wearer against traditional projectile weaponry and explosives to a minor extent." diff --git a/code/modules/jobs/job_types/clown.dm b/code/modules/jobs/job_types/clown.dm index 01d144b4a5171..e9b40d43e05e6 100644 --- a/code/modules/jobs/job_types/clown.dm +++ b/code/modules/jobs/job_types/clown.dm @@ -57,6 +57,7 @@ /obj/item/reagent_containers/spray/waterflower = 1, /obj/item/food/grown/banana = 1, /obj/item/instrument/bikehorn = 1, + /obj/item/storage/box/balloons = 1, ) belt = /obj/item/modular_computer/pda/clown ears = /obj/item/radio/headset/headset_srv @@ -72,6 +73,7 @@ box = /obj/item/storage/box/survival/hug chameleon_extras = /obj/item/stamp/clown implants = list(/obj/item/implant/sad_trombone) + skillchips = list(/obj/item/skillchip/job/clown) /datum/outfit/job/clown/mod name = "Clown (MODsuit)" diff --git a/code/modules/library/skill_learning/job_skillchips/clown.dm b/code/modules/library/skill_learning/job_skillchips/clown.dm new file mode 100644 index 0000000000000..3cd88ff70963d --- /dev/null +++ b/code/modules/library/skill_learning/job_skillchips/clown.dm @@ -0,0 +1,10 @@ +/obj/item/skillchip/job/clown + name = "B@L00NY skillchip" + 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_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/mod/mod_theme.dm b/code/modules/mod/mod_theme.dm index 7cb117ac97b9b..c4c8839bd82a6 100644 --- a/code/modules/mod/mod_theme.dm +++ b/code/modules/mod/mod_theme.dm @@ -891,6 +891,7 @@ /obj/item/grown/bananapeel, /obj/item/reagent_containers/spray/waterflower, /obj/item/instrument, + /obj/item/toy/balloon_animal, ) skins = list( "cosmohonk" = list( diff --git a/code/modules/mod/mod_types.dm b/code/modules/mod/mod_types.dm index 47f588eb80b9b..f0bca6b0980d3 100644 --- a/code/modules/mod/mod_types.dm +++ b/code/modules/mod/mod_types.dm @@ -212,6 +212,7 @@ /obj/item/mod/module/storage, /obj/item/mod/module/waddle, /obj/item/mod/module/bikehorn, + /obj/item/mod/module/balloon_advanced, ) /obj/item/mod/control/pre_equipped/traitor diff --git a/code/modules/mod/modules/modules_service.dm b/code/modules/mod/modules/modules_service.dm index b4870a84ec503..be71c62180298 100644 --- a/code/modules/mod/modules/modules_service.dm +++ b/code/modules/mod/modules/modules_service.dm @@ -19,6 +19,31 @@ playsound(src, 'sound/items/bikehorn.ogg', 100, FALSE) drain_power(use_energy_cost) +///Advanced Balloon Blower - Blows a long balloon. +/obj/item/mod/module/balloon_advanced + name = "MOD advanced balloon blower module" + desc = "A relatively new piece of technology developed by finest clown engineers to make long balloons and balloon animals \ + at party-appropriate rate." + icon_state = "bloon" + module_type = MODULE_USABLE + complexity = 1 + use_energy_cost = DEFAULT_CHARGE_DRAIN * 0.5 + incompatible_modules = list(/obj/item/mod/module/balloon_advanced) + cooldown_time = 15 SECONDS + +/obj/item/mod/module/balloon_advanced/on_use() + . = ..() + if(!.) + return + if(!do_after(mod.wearer, 15 SECONDS, target = mod)) + return FALSE + mod.wearer.adjustOxyLoss(20) + playsound(src, 'sound/items/modsuit/inflate_bloon.ogg', 50, TRUE) + var/obj/item/toy/balloon/long/l_balloon = new(get_turf(src)) + mod.wearer.put_in_hands(l_balloon) + drain_power(use_energy_cost) + + ///Microwave Beam - Microwaves items instantly. /obj/item/mod/module/microwave_beam name = "MOD microwave beam module" diff --git a/code/modules/research/designs/misc_designs.dm b/code/modules/research/designs/misc_designs.dm index e17b53da692fe..84dcb67233d52 100644 --- a/code/modules/research/designs/misc_designs.dm +++ b/code/modules/research/designs/misc_designs.dm @@ -189,6 +189,17 @@ ) departmental_flags = DEPARTMENT_BITFLAG_SERVICE +/datum/design/water_balloon + name = "Water Balloon" + id = "water_balloon" + build_type = PROTOLATHE | AWAY_LATHE + materials = list(/datum/material/plastic =SMALL_MATERIAL_AMOUNT*5) + build_path = /obj/item/toy/waterballoon + category = list( + RND_CATEGORY_EQUIPMENT + RND_SUBCATEGORY_EQUIPMENT_SERVICE + ) + departmental_flags = DEPARTMENT_BITFLAG_SERVICE + /datum/design/mesons name = "Optical Meson Scanners" desc = "Used by engineering and mining staff to see basic structural and terrain layouts through walls, regardless of lighting condition." diff --git a/icons/mob/clothing/head/hats.dmi b/icons/mob/clothing/head/hats.dmi index 4183d5fa6cb4c8fbc90ea0b242746109fc2e37fc..5e76ab78608f2163465780169fa99d995cd7628b 100644 GIT binary patch literal 14949 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 diff --git a/icons/mob/clothing/head/helmet.dmi b/icons/mob/clothing/head/helmet.dmi index de7ecf58fd146b0cb14e07b0b5089fddf97ccfe4..317edb56796bd9678dffed8fb2448b26d727a66a 100644 GIT binary patch delta 24390 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 delta 23153 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

#h1{YQ_=LBcRAYgU}N(r3NE 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%0APQ1RL7>ui%hMOE_1Yd>NY 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 literal 99362 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 KwQ5z{$o~K$El)TA literal 23456 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 diff --git a/icons/mob/inhands/clothing/suits_righthand.dmi b/icons/mob/inhands/clothing/suits_righthand.dmi index da837fdd8570e19fb003cb91511c23b71897b29b..7dd047b7345d7b14ffa799729995ab7ac4e6e937 100644 GIT binary patch literal 48819 zcmce-by$?&w>LbbAW{<2Aqpyul(eLhBGL`gsep7SEdnB?bVx`IokIzTba!_QJ#@{p zhwtxq&Uw!BUhjYB%mp)Z?|aX_cdWhEXRYZ$-2J05SeoTbg2Oy65MI$Jr|Lm+NR$?+ZbQ!j{u`UcgAIwqRgYBui*Qk;H; zp{ugRjX(V0N<5;(-8t0POy^FdwPX0~?x{6g=d9%7;3zd`cV?+7=SmxvyRy^oeSO&O zQ?;Qb<+^@-ZPSRCp_bc6pY=Kx+&L|t3*XEVc1}I1%T)U|NLwpzh<5OH_9yn|0k#u{ znRs;@5~o3t@zLe`xeg%|a=p*J?$b-egiq?U+gE z{a0WAtOd3#{Ly#sqrAeVWXe`FapU(1e1=l({dq;7sgB-0?6IQFNt~Q57Qg)}4&B`8 zefn)Pzf3!U)FVC>dtEVOvW%cJOI=$Yyzw9kX7|^QdBbn9%JGBn@>t_Vo~XqJyW(Aw zBe}lyx#Ij#YtYYjz`66To{*)XJ(clppKI_n+mUdQDD3G21G7h()@t*Ap5T=nnvF~v zCR^dDvm{GytF%7ldd%N_FHUdbZm~mUm|LV70!!B5IPc!y>DL@IlN7g}@u&ZM+4MBP zjibziS~RaqHRn}UJq`bB%r2WcJal{sngsH9`f90cRZss8RKlw7C%X6Fwf(4JQ7S?| z<9Am+{&g&47EO#r$18q|a0!)yl3M)NliGK5ux!eWvTENF*ddmejKnHV*0hsMZ0la8 zbbH2|lG^_kf6$WXF#Rd}y%oJf40kxvCOyTv^n-1v^Ut=z8J5s;(MaVOGW7Tt4^<^G z>K3;TsYmX^YDbS-N>$Bto;=R}-ofJkq9fWIO_r2eolV{LjX=-eY12$9j!e@AX3E%K z-ioEFN(s*|0@Zn{*7}Gvn3 zyp(?a#w}@U#$E5t+Kj+;U-4fC;ZB|>A=Mc;)g*jTr_#JH!?p8X(y4`R&?cDlO!8Vy zGOyO8X1ns$Oto5PoQc}mJ+!j69kTUkmsLdz551ibf``8N=~E}2L@WHH-7#q5)qK*A zXJg9)rXGTi?kc^#OvwY7<*^!BUm{N4QJ;kF5T`SRs&lC^Di z*VULTW}O#TZ-0_{x>zV{TT4nyM|eytUR}%~cgD-DqIXjF1nedsTwm?_x>lcyq~x|| zDTW|8Yrl>_FC9%o0+@mI0s!S>!md3-lCB50Opa5EPv{0r*wbgr6jpnoZ!{SbC zZ0sWr4*qJMuT-EfL7koQB8cv%9DVCM9*;Z`G0?_qs)r9B*47`7PLE)Ay&B z=u3I|yM$t=Y1Mp8QeK+bWy5AFieJV_NSMUrmC5aVliT5Qnx)<)jouYaOlJ`j<(-}v z)*t0gp7~zNoorNbSnruO9dkEGjfvYF69r!t7{;+B6~dp7ZZVo%@wBJ6haViDAN~CG z>sKusWd4Wkj!;hB$!dZ7o6*B*t+<#NiqD@vbBR5aLA)$3;M)l6G`tYrT3amZ!;zSS zde?9K#%gKHee_mL0Q24xao5_&hHn+j^&db77>8)a@(IwTvaQD6Sj%+iy7cdVk8{UY zGa53QY0zonZHDdGopKv3Y3ll&SLHC=(;q`>YO%ksQk1xwQrpXCx2DrKEHx)2{xNh( zGm0m_`Sn@PZje$|-D7ufK@&0a$RUzyUMZ136!pKjXrga7{R4cYFT0F96HzBLb0`v1 zdHwoZNO)*-Athy;(@a7XV@%NNKB%`6m`|tG?&nHM_$ErsJqboCV-FrbemM;)6!h&r zVPzT(aafCN*%;DSnvv`1SZp=quf1}qtj~fSE=aDdak0H@szS6Io3&DnXp8Dc#}eDL z4oF%3KELF6s9R?79sN7=IKNQjGM>`GY=aKN4$ErQmASLhb0w1QDl~9;ZgX4xYvDrK z@(d4JqvV*&Uzvtii6>y}KDQA^NIG+dduNN_>W>k6!!1zo*vG`lVB#SGU$aL>t&eu8 zo2@F%-QWZf%6#2WDJ5`~B(+MtQg4iLIcWpMg^bs^az@aL6VwYdw@1>q&(?dQIh&1r z%h^=b(_G zI|_IE^{4}|@WiFH3RCk|hllt|#2XblMz90ZcPXST#MIhUdZ-=ZQCn(#x4x-&~^RwN)RbRr21i)OM#9sm*EAI}hk zG@b4)R76|B&D7Db>;B8!MH`9%HL0em$Nrg9}`3RGbe{hOpFdJ zu_onM#p2RZR7y$&D34EWAvqHCxvbVbHt*?!!d)a(RaN6U@@6Y4D$$F3pkyjztz@31 z$G)j}5Xj}(%nAX%VZ*MGUhd^|)|zHl!`T(0Zk5xcv*G;r5Z}8GKJih76Hb~2D_7gp zo5%W7v`e|QMPEqWH?--WsXDn8#ut=Q&tE3@z^w{xe$h-7 zUwz>?&gb97Z%ioCts-b{Zie{n?KzHo)ZgwAn3L8|uAxv;Qc4hS$l2UqOXI$jEwt_vm4WmjV*Jba()B3XQrOD%$;ZYzdk6F754;)H`dV*idR$N zk^6-B+STF#4J3ETIqBkkwVgP(I>~_Wd2>zLgc3nyi7AK3MBEDYbc4>k_4Ba@Wc?0h zIm>o)Sf_J?6-B)HI;&(HND@SCF^nK+q)Ljk75!;8njofAOVvFI(qgZ$1}d?KyG0c9 zan4!?h!5+Fw~$3Q0|uIOac@CZtMTypkDr@aXX?2fo-Np?r~6Ams+qE(^Ycc- zBO?nWNrNf;4cfofV5WS&sR-wda+!nnwT?vXkyJvX!h=_?l z_7`(OBrGi-RoYEuKdH;HS=_oT;z7cp`1B81@SOSeY(~W*lOK!!2`-~+>$8sExIXt4 zgsY0^*I||M*IQZnaLURUUym7{Jp1RjrqlaU3=@f>_=pST4)USRIho1gyV7#I60(2p zORv>`+1#`y9l5s<_IM&=sq3f~dAZI$K`mBzV1aDXgn7QFk`KxQkH}D+ zne)0T^W6*7LXHtYtFN`y{Mpsj5?;XLiQg*WlT#n_ZJ0x?4>rw7esUf+@-j;y@*UMb z0O>owEE20a7$fyLo8pJ`AHjXLA2;r0!<;3Q5H>wvt;8Bx`?iH2>MA0TR9042ArTR> zva;9*2M66f2CBpjmMTFh38JpcN6FvVg|H(8kdiYS;?A_|ux-!%;v(w|jblQuwlS6* z7u})d1w#oH{M3AeIT*ngmCdF|AA*7lrLo%g7mlIOqRn*K(P5)^zd5s}bRu9LI36~B z7YUjIi2$*=eQ0pt@)|gKo=O1Z+Zlj|}6!5Z5E} z5F89^_(!L;j|vs%d4W1$E@T#QNEC@z(InOF5__i1veaw;vvu#Ug%i>2&^vE!PTzLr zTa0qD7U$%wYBK5?{EuLz|F_Z2nt}Kk?)#7T2qC8Z@aNGM3nhZ%rB<|7R=h8cUBs60Eu`c}0v+NHa%1pm& zrzIHE(mq*bu72(uatT!q!5&D5i`EL~u(>eacS-TOn~~M_GPAA~*nOqFj0>8^lvppw zf~|gEc{iM$uVi&7QJ95*&-kkJZI}5NrviB-`)8@eSJB5EB8rt(7V`3+zYDt-4PmS2 zJKdoZp%`6z@$w}xb2P61EyB@F(%OoRCDD|Kex{w?#|ru$Hos5Z@4xfgUQ=H5Bjq-} z6w&v&u497Q@~KKyTCGK^NY0bB+v==bU70aB-ZFBEct}KHYJj{lWADu%4BJs4=0wha z?a}GDMTA?@)Fm$X(@Jf_T4&`bJ3$MsijlZAgoUx;k0V9m)(VwO?2d9n{rhTe#T|vVZ;zu^P%og8;S7K8N#Nk-4?K z9RmVjXm(v~E_ai_WNEzAMVAO=)>r{TXIF~-qWxPThv-A)E1mB_txUH442hz__*9rf zU)}Vk64LV{5jMI{+1$x6yfOp7X(pXlY{E)Mq{CTK15SG!l4t~PU#<#F^2O?uEQ@Zs zDMrH-81^LArmUL8uhBj}BtlkCc~L_^$<>1#UJu-oi1shWYCynqWDFegLo4W1{0Qmo zTNhfwA;3s`OU4bE&PswgoNx9w=J{cp&|l-UcAFicp`n4!CD2?o^C1x^z|s0}o(Yc? z&3wpu^}flto_+>tlEV)-@pCB86?Y|2w|K&S zf_SSO_)V%qxJf|AYq|boKrp2iI8Gm-tPp^Yn!hU4^SFak@QK??{{Ggm%{+?jX&mAxu-R!Qw@D=u2^u?-lDsMcC?QsG;CaWG5H(PEAbD+VH9*_9Y7kH_@&O zMc(6UBwHJy9iwJH@X%Ev6}9&(%f{Ai@PCtF05=~$ukHrxQ7gP#VKY|lM)CL!-7`Nd z*F!loZQQ%AoGm%JqwvK9*R>&bIDTkde0pg?Ytj@J$+Ilx>#I*(C!KZUr>Wv2-ufQ! z*K!q%Y$D`ShSh$AW6<{U?z;WxwzF!}vG-esR{i>!u3%WjzFBClTRIV`Y`r%X7S4~x zuYY5K<+1*zS($M71I(GgntCs{Wq(?clUtN_nQs7hW>0iaW_v^Vv+QZQryjS>d#ppcOzF6O)km2Lxa$%mSzKjk>zkHvxWrjYIetAqk7J zw6im>d0$HS_Ec47Z7tO;0-B~+R!zt2OZS-(nQ+{tHQcPwm<>GG!9nn83CX*?Jq;x% z-7(Cs`5g68f($ZWek4RxR9)dk`!EwB>f58D8qqU{(Dz%{!fU4xa3rfV4XgF@*>1Ax zy?yHO#zDU%U(TihZ%@?^FB8{TQNlT*fM>7o!umm^uEk4Ar3cD)Z_WGQWk}-{J2~(y zLcV-yjd`rLw-Rr-c(Bs-=<(xb48o-LU0-NR?O`(jGOhbd?cAPwJP%qEauPcmr}~PT zb5%3B0P@k_sW9UVVEt#ij-)L}&oIMR`01?ki+lGj;dCB@Q9s*rA9AYUC|h5!U{;N-5v8;j8zG3qx&PHVX5e z#(uw&zXM@l^2PEw{tYR>^XV;1uPxy?eRjDOi1zodAsPf!__7i|RQ^EiM(J#H!W!pp zCH09!()R5%t)}(3UH?Ul)09&Rr_6jr{8-z+@SaTW8d~lCVLD#poxF0d&H(s$5P%(> zE`(+TJc|CZdMecpA;uuPHas!08tL<0w@JOU(Jrd$tH}VKYyN^pD$%=TTo=Mvk(DW>q`{?@?$zxX$SFZYLb97fvJ3@ufOdwWO%+KPxJNu zZ)|+Y$?lF^=+nmP?fTjmFun6f=$!|~$SOxs_IDDWaUONGcV$H`f?E&??-}=>JxO1R zpZoK6pcJbcSitc{=sjaDD>{4R0-)dN@{R~l*4X75yb zGO`H!)uj70-eag;>R1hdE~`7q!1@4(O2U51kVB(BS`h0NBMKJnx+Ntgzb$$1^YW5@{P@w*%Idk46o!tjuFC{YXI%UX=o5o5;{By>TpQX< zPaPRGwvd`gCYPh*Q7z zji4^e{rkK7VHOK}B8I2W0?J&z`A6np{9RmSS#15fZ%hDJe~3@PBi3!@q&Um;^r;#^ zAHoHxqMqdY`}@j?ruT6td}+GQ-)(>Pc2ls+jrZASYh`y8F7hoUt6s5R>*3xotimt0 z9qLU?4Iv4erCR%{)CFtqNG}#^?@?*RReSyDQ?yitP@w%^{_XDWZc>GK4wt{#X0z4R zf?BDl=b_-+yLaz&k|hP+zklC)WDk#Jb?VZIHXuT*_1)?YPd=b$FwC?_)@}M==TIDWmlIC zR$#B>XUi=5glLBDJD8hif9E#EhA=QPHXnpH0mKva^(zDd%7S(_2Q^tW3W)l|E(&@k z%lgE^$XGSjJ$#G0*=>|Oo_D8;)6;t&60i29Iv`TtPe(6!Jcl@r`nY9-mtHdmEU6wNBn;DdMUs+mUy3N+g%t~Af5IZw-K+7~J(iCh@u4BLSWM2!>amH53FJG=l0{!iAl+tq zATX$J-n;>8iT3Q-Gn1YKzPKrm>}7Jv5VNkhi7l!8_P9c3Z)4F7%w^jHy^327xjjdM z%EE!KW;MP?;_buLz0b`h)kfXX)_#nvZhJNMw(~+`cv2W@A@f3t)2q5bs9HT}0@ck>DH6<05c2sd{YGk5AgSPEdC4SQp;)5_+oZaNc zCQRPR2I*FD0k@6t#Jj;w`Mg!fk(wGB=1zL%oj*w+8ihP6f&ft1*~8y0ZgftUj!NUh zvz14&`_w)6f+nX!P{2_U>z0Ogf??solb*sW)5lfy>1P#jiHTu;evqxn3Op<5;4V znwr6BX$%y1u-UXrG5^zyT3hF7>LJ1UOUucza#EL|HZ_<=mkTCe&DFRHX73ezHDzVL z3*}0yoVtUZN8cmD6P@-ZcF45KEs4dZ>d~nM){Nwu52+i=q+`qnuHlXEbvb*Wl1c`_ zxW#-EImtR}gw?-pZxfOmPu1m=Y|m7oK}_RX8Jik!D`h35$lv=9w8G8J{kN}A&c{a# zz;;qPx(K{`9F`s&Dq1Bbfh%; zT%2G2@jQOT1~C}?PUl6m99|TWAr2(>(JdYaerR73I_dH+Z|AG;d^T|uVqSvaInONn z85EvA^E!3xPT*76nyyh37&BBd$iXi*o174%EQvRXs(CP?P^M69Wvjc8JMT7(H6 zbjZw*Hqp9Adc7auI_~{wf~004CLJOC^Gdv&U$5<2KslqL0mCCNSf{hxsWpT+&T7pf z)!Y2(HX8@WXphfKR8@8L_}7GlCzZAnpZfb>VPa!vWMyILR@y#SP{2EUL&&F5pk<62 z_#^g;s|e+q!ZF#tSd^BbpV*c8Q(t3EIQuG*ZbFrdwxS0W1^SaALwU-^Ni{Mu^61Hv z-vLp9DG_T;Bksb~ma0Y-8uM<`Hn6MXDM9yx2mcr7HoZ9Bj*Gvy`O@&;TP*@MJG?xL z+AScA6vte}BKw8H_>7}ABLkgD_KTl4My}kA9uM(Q01_b#e3WQUCeP!o=boOz{Pxp0 znFBb!zP>7QwM7lf+sB_G>YdWKg3cxtg%fRx);~->)-|YCP*NfTu!Dc7Hz){uMp@Vl z#CgUp!mvG3KGgD574R``;=$v|#)nK%Xri9_skvg+kqA)gJDcFw|8KzNf23ryCMk)= zxUtfHMrgq{IRw03L|%G$w1d*9goMpvpTl+4pV`^>Sy^y@~`tb|U=cn?q}8sc?0 zAO~TXX}E*!e>!{8a0_yJx)jL{m&DmPmRy!auT0%Nt}ChMJHS18z8A2XEDXu z{KOTC`+~7hD)}`+j$fcZl96f2y>4x(9{ojp8h?ZbA6joukBo!_C?WqT2#%jrd4E!W>McE3YE~o^->i+m z6Eqwu+c|!9NCAoMiHukLo6Id}qD+9 z)B!Sh_jG3I$gNsGB{G%Fuf8B;uH}BXRQw{-tjB}i+C76Ac%qBqaw(q-?Z239hlzUX zoudgj%!>T1$NE|S&;o%0o^0@xu`voPT{@YSrA$J(r&BW>%v{pP+q3Yx;#!5dw{$m< zU&+fu0NL@Y-51Mbv_RYBbZ-H~z;@G~`?K}z?k%)%+l;c6IISsv_-s&w;A;}li&h6h z@j_Yo57P6HHAbtD6@T0}f~^_)^?|&+yfdO?cI3eaWsjvg<}Bpy0CcaViUmU=6}4(B z@w)o^#WRyYh>R%H>|zh_V5}$e_#}hy2~fl~Cutw+>TNql{MUG#V5 zaVKV1!_r7k`L1kC;~yjB7(@9vEB@>?zT_II+Lx;?tYN*sr3GN7=#hd{9tqdz$x0@# zzquVm^)kP!I!jGZhomtBx+HIZ2B-mpiiaY1$5=)d8?+Ezcz<@THC*wzjC_9lj!L}1fbgesHj`X1CC%<` zO_bGl76m7qUR>Zo+{|=t*=wu&DJ2Rljc6K<%Uad)H{f&r z%gfyT79G8`=icyd3v$@gK7{u6U3-6yjF%Uz<$R*df|#B@QaDJghx5}M8gukZyZVh<2Un?()*a5qjk3}Q>y;=_{Nu-u$8j9`nr@KklYy_+c;UaC#aXC1>^v4IbO5enhY)VdH%ly@g4Cx;&#yzg29U_A^A zkDNhRST|p7J*bM;Q^%}9-1H{}8U0GJ*b_1NGN<*>E2l}jsu^ZQ=IDO7Q}Va%$|?Jy z<+Hh=ixcqfJEvmHOJ&zvHegA*+qj$4WdmJTum?B_gqTBFaQHBf#gW^HyV%n3mWCq1Dc6Lqtn_-%P)# zeFCvAFz4kD5|0}PHOd{r*29my5Iq9??dRXdZiW$y{eFLxJke#P(%b*nJ@1~GZA>kY zU(wT}!6u}$eY&q->-?*q$3aF03xc@U3^XM0Cd_82!CY&vY0wBdN?87wIxm6h*D=SO zYe8>Z72wus6&rn&GG|AuuCAhU`Cg|AyAnW%h=`1|Pq0e`JVz&X`Y0X`n^zXex!5s5 zjQ)I~Gy(tUkUSgetXu^Z;EgG;734|U*|EQV{hI9p7q}-IC8oKBg)(p6kec@-WQEoD zf;!SNGU=6-nlSY)oBkMcN+ zf>J9)%>UDiyvG3}1a2PQakzo1DlwhUsWAxb$v1!%3@INKlx{5pQ5W-dN&>^VMXQUs?(fU)i+8??0Ijeuqpi=dlppWL_b;6%6^+3T2Rov zS}pMG{W1>V1O2o)EblE;jJL7wHk{We(hCiy_n~0bEW(5U^2oY}(Cj_%OD88M_Mud# zwO(y8WJM=%W;@q>fyY)`&xFl#o{FE!Pjl-`8iF z9fbv;=0GMaWwtS=5BbU_-?-!mQ+?ps%Mo2f{<@8Q4vEo!^=#*q*hyVnTySpR{?u&L z^zEU75f=pr7YEeV3SHV;r)w%A-`XAO{iw^!>r7Lm+@hDO(N|N$5cO6|L+KRP6}#E} z+yBA`Mr*yv|HcQav{1|ay;`H0t%*AL1tDW&wPGG_@nrYzN;22-y~M_%ae>BBo3l2v zez=092diMeh!SFd|DDjsHxcl_GLiVa{Dq~Zq3!(?k(8X{-Cqa?UaB_POx0yPJmN~i0TVPn6wH1Yg;B;||3V7`N)mK+H1Cw{3n|mM|S6NXJl|*pSB;iA)iJtBj zexyeaZz=-e@#%GmFL;>p$dZl^P)W| zR{Ud3;5Xd~IR|&3HiUd7ZSv2;cQNjvUE=xC7nv|Xnl8KElF4T3K0T5)bP`U6bn$OH z%gw5&TvaviYViP{79E1Kb;)7d7013O99K~H%gyj{xSokgMo;Z~U1)fU@O$cT*_hZ^ zpsq#_Qm<5KVS!*VG}mT|p≧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 w;M#-$$IM-~8qO0)@6iIRF3v literal 47677 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 Gum1rz(0tVZ literal 3103 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 IuUkL^J&PIbwW5%Cd=4oroPG& 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 O7Cl`foic5^i2ndY=1VF7 diff --git a/icons/mob/inhands/weapons/hammers_lefthand.dmi b/icons/mob/inhands/weapons/hammers_lefthand.dmi index 7f6985e1de5ec520d9ac973c8f84f2700861d99e..5856bd8b0f83488af3d66a7d34ac27a9dcfbea03 100644 GIT binary patch delta 6058 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 delta 5758 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 delta 5686 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 BGLQfO literal 20487 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÷X^1prNB6J515F+Tk1 z>H={5vK4%_@M^yE#Yo7|j*^}p!?MWJCpV0n+gn;zRy0ylQb4sQ;#WsTMyfmTWN2a; z|H?t&l{X|k8W_H9I-eOtNEQ9pF@i#|%y)Y<8Ki`?9^Z<5V9AF;I?>;Zm4a6luohc5`Ulo`|x z7y~$lG!3e&gAwTKJ(;e*uTBP+IYZSBmP707xzbzr&u@Nw{_$@$4(J0`sep#o2%0

i^ka=4Gq5)n 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 z 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 BA7ual literal 32783 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 m1%Bm4-VF(fVe)@GblS*GZ5rQ!d!KEg0$VPW_U! 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 diff --git a/icons/obj/toys/balloons.dmi b/icons/obj/toys/balloons.dmi index 0ed6f471bfbe6ae04acc996819ed86b357885532..96afdaea2c0ed6e69986d78c4b051531af263343 100644 GIT binary patch literal 14124 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 D&+)8A literal 1523 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 diff --git a/icons/obj/weapons/hammer.dmi b/icons/obj/weapons/hammer.dmi index 965fd0b37efc8a86dff15969f7d559861b672530..751e626779890000394a8c8c1a0d37ed408ad206 100644 GIT binary patch literal 12264 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 oBKF#x3<;3i_sq(Q_Ae1I4G?rpK1DL0ALKWt<8 literal 9995 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�W^zxzDD_7#$N+efsD!IWWyR)gJ5Yo zteJWoSfthwSrD|~bVICJfs|9iYUgN6GX4v}Uv%wEH9@fiGHXBe3LBvTWgm9>w+B;g z$jTq9r(Pc*Db3d8v<%W7g1KUf_~2i9c-C+Ui^yT%Y49_@qfrBSvfxueo_Y)}`1vby zZIoCLi7P}Am|_u_g2bkjEQIfkYfe<^AOQ-$mSebNyv+fCQsxmjZwee1ck{HIzQaWaWRG@s(Sr2V(_p_hN^aIJhQITy zjBCG6|9oi5HOPFAR;OcIs5>K-gZ2=yyCC8F{dj*Y9uGiiR}`O$FaIp09$mc{M2bLg z(PfHf3vx&Ov9Cq6;@v}~@K5FVjGj+^K#M)Lf4WYIONeWsWS>Tr{Hh((=a9JVdJd6R zD%~nAjLuzTwk5ood3vI0j5Uc2$f%ns+ZYR$M~=#2?$HgC4CG$%e?c;QBsQ9bU8BJj zZ?>(k-U%V4YgUrrN1jl4(yhARr>7Ib5FmJXm}&;)gF&^_kWeJOvc#a2-Cw=!b_G$G z%iD@{T(E4|IeqxpF!xEMxt!2}9S`UcPPW}77P;2*p6c2L5qRpUl32!^0@2R?R zXB*$ss7lw%Eh{j~04Pna$-Spik9_J%Ny>IM2hh6yw=Kp6*nL3h~CVvM{@D zFDh|H{pkXnpyZSk0uc6WyBZ8~8qVv4Tw%LeXI>tIb9+?@C*E%OaPKP#KnFXm0YNWe z2Xn8swze00xGEBM5x6s3PXPj6Nq=!36egjfqN}9zxvCyHa3}GRsPK6IE zf4tOr`jitiqG!r;0{+$BF6_VaY+`Ck_M-Kr)T1JimX@L@+3^0g^!&C+sFaqu@?8+Zb$|6Y(682eB2iDE;@F979 zeSKrtWpIPOekbtOO25TPn>$D1gScC2cNDcq0acA74Z&1uUS=xd=*PIFc3SMc@}0;! z-XFne_Kqm(?AiR?0sT5~o3inNJd$R1LyQ|xN@AD{XTxmiM;=|!Fw?&wjwhn2`BR_G z-QU~GuCG5;SXyRS((WwI0VLbn`m2SgJ0VQ%sL=ffJld5!Tx&$yT0pY|!%#x;SUdjb z-?Z)#o}}xRd;{3q#G4Z$h@Q|V%|u<5(0E@8|O-KGZ!>W|(i@x7QkM8BM~ z`sRM`o{SGyS0YQiU3cP4CY7EDL{D~Q$~n>aVn*Ewb2tI0Aka|dguTcqAgZN0P&;#T z#(QDoFwV!6r4mu|^LYB#b0w*VK8AEaMFR{?LnAx)Njrg8StrNb&QAQ9y^_^{6NVdr z5&Q0v4W_%U9{QH9U;em0<64~kHd7h8X$ZZ3H5EjQ1Zr63%EiTnOUo8TOd6L-<;4ye znLe8N@fOI&dWEaHje>8U2*kJaTPg!2jhR%NPjT)oWmn;ZE1joltJipRz))P6EWMHx zZZnltJw+V>86a4ky+ql}teX{Do(vjS{>;RgR^X69abAVj-X1 zvHO`J7gjldCPP~d!@N^0+Xf#oM8tn2Jm_=1u2!Nj~ zYgreYb-Nz6chRkJ|Dr}a+Ofn4?8Z=apU<>FD$P4CM8%iDThyNQ>?RlnPr383kv za_&Ekx}HH{T}(EG@lru17KeBjz{6e&XS)#0eGJf>z|lr42Aq2ur1p=^ysS&|OU&WF z0Vm#USlfvkOLMX8tneEbzO?*)$k{sy7R{D2w-YL#KCh?Dj1rx_h}%*?a(Uo18Q oPPs`XPSB@-;(vY0oLP~qd2{@vFPH&--3HQ7(NV5?Y#s5x0CLM4!~g&Q diff --git a/tgstation.dme b/tgstation.dme index b3b468849a9a4..b14fba3526af4 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -4353,6 +4353,7 @@ #include "code\modules\library\skill_learning\skillchip.dm" #include "code\modules\library\skill_learning\job_skillchips\_job.dm" #include "code\modules\library\skill_learning\job_skillchips\chef.dm" +#include "code\modules\library\skill_learning\job_skillchips\clown.dm" #include "code\modules\library\skill_learning\job_skillchips\janitor.dm" #include "code\modules\library\skill_learning\job_skillchips\miner.dm" #include "code\modules\library\skill_learning\job_skillchips\psychologist.dm" From f017db05dbb0d8d1af959c833ecb02c2763abd55 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 11 Apr 2024 12:02:51 +1200 Subject: [PATCH 150/938] Automatic changelog for PR #82288 [ci skip] --- html/changelogs/AutoChangeLog-pr-82288.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82288.yml diff --git a/html/changelogs/AutoChangeLog-pr-82288.yml b/html/changelogs/AutoChangeLog-pr-82288.yml new file mode 100644 index 0000000000000..95f1381b45d0c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82288.yml @@ -0,0 +1,8 @@ +author: "YesterdaysPromise" +delete-after: True +changes: + - rscadd: "Added long balloon box to the clown's starting inventory, and a skill-chip of long lost honk-motherian knowledge to their brain." + - rscadd: "Added long balloons. Consequently, added balloon animals to make from such balloons. Also, balloon top hat, vest, helmet, and a mallet. Don't ask about the mallet." + - rscadd: "A long balloons box harvested fresh from the farms on the clown planet will be able to be shipped in a crate to the cargo department near you!" + - rscadd: "As per requests; water balloons can now be printed at service lathe, and entertainment modsuit can now blow long balloons!" + - image: "Balloons will now have an unique sprite when in the inventory, compared when to on the ground." \ No newline at end of file From 3f0dff1a14a920b77bc3a2f8d99f546d7d8e6066 Mon Sep 17 00:00:00 2001 From: Jacquerel Date: Thu, 11 Apr 2024 01:21:29 +0100 Subject: [PATCH 151/938] Fixes a very minor punctuation error (#82567) ## About The Pull Request Fixes https://github.com/tgstation/tgstation/issues/82543 `"You pulverise the table with the pickaxe.!"` => `"You pulverise the table with the pickaxe."` ## Changelog :cl: spellcheck: Effectively hitting furniture and machines with objects will no longer be double punctuated. /:cl: --- code/game/machinery/_machinery.dm | 4 ++-- code/game/objects/objs.dm | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index 9e71d5bce6762..30dfaea445f9e 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -708,8 +708,8 @@ hit_with_what_noun += plural_s(hit_with_what_noun) // hit with "their hands" user.visible_message( - span_danger("[user] smashes [src] with [user.p_their()] [hit_with_what_noun][damage ? "." : ", [no_damage_feedback]"]!"), - span_danger("You smash [src] with your [hit_with_what_noun][damage ? "." : ", [no_damage_feedback]"]!"), + span_danger("[user] smashes [src] with [user.p_their()] [hit_with_what_noun][damage ? "." : ", [no_damage_feedback]!"]"), + span_danger("You smash [src] with your [hit_with_what_noun][damage ? "." : ", [no_damage_feedback]!"]"), span_hear("You hear a [damage ? "smash" : "thud"]."), COMBAT_MESSAGE_RANGE, ) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 1872f62d90793..d84fc46de43cf 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -82,8 +82,8 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) if(attacking_item.demolition_mod < 1) damage_verb = "ineffectively pierce" - user.visible_message(span_danger("[user] [damage_verb][plural_s(damage_verb)] [src] with [attacking_item][damage ? "." : ", [no_damage_feedback]"]!"), \ - span_danger("You [damage_verb] [src] with [attacking_item][damage ? "." : ", [no_damage_feedback]"]!"), null, COMBAT_MESSAGE_RANGE) + user.visible_message(span_danger("[user] [damage_verb][plural_s(damage_verb)] [src] with [attacking_item][damage ? "." : ", [no_damage_feedback]!"]"), \ + span_danger("You [damage_verb] [src] with [attacking_item][damage ? "." : ", [no_damage_feedback]!"]"), null, COMBAT_MESSAGE_RANGE) log_combat(user, src, "attacked", attacking_item) /obj/assume_air(datum/gas_mixture/giver) From 51e7560f044a40842aeda606387cc7717b967872 Mon Sep 17 00:00:00 2001 From: Jacquerel Date: Thu, 11 Apr 2024 01:23:18 +0100 Subject: [PATCH 152/938] Removes goliath rider reacharound (#82550) ## About The Pull Request Fixes https://github.com/tgstation/tgstation/issues/82544 Goliaths can't grab themselves with their tentacles and shouldn't grab their riders either. Now if you're riding a Goliath you simply can't be grabbed by tentacles, they'd grab your mount instead (who is immune). I didn't make this a carte blanche "your tame goliath will never friendly fire you" because I want them to be able to do that when you are not riding them. ## Changelog :cl: fix: Goliaths can't grab their own riders with tentacles /:cl: --- code/datums/components/riding/riding.dm | 6 ++++-- code/datums/components/riding/riding_mob.dm | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/code/datums/components/riding/riding.dm b/code/datums/components/riding/riding.dm index 74451e47c8772..7ac6027944c4d 100644 --- a/code/datums/components/riding/riding.dm +++ b/code/datums/components/riding/riding.dm @@ -30,6 +30,8 @@ var/list/allowed_turf_typecache /// allow typecache for only certain turfs, forbid to allow all but those. allow only certain turfs will take precedence. var/list/forbid_turf_typecache + /// additional traits to add to anyone riding this vehicle + var/list/rider_traits = list(TRAIT_NO_FLOATING_ANIM) /// We don't need roads where we're going if this is TRUE, allow normal movement in space tiles var/override_allow_spacemove = FALSE /// can anyone other than the rider unbuckle the rider? @@ -96,7 +98,7 @@ for (var/trait in GLOB.movement_type_trait_to_flag) if (HAS_TRAIT(parent, trait)) REMOVE_TRAIT(rider, trait, REF(src)) - REMOVE_TRAIT(rider, TRAIT_NO_FLOATING_ANIM, REF(src)) + rider.remove_traits(rider_traits, REF(src)) if(!movable_parent.has_buckled_mobs()) qdel(src) @@ -115,7 +117,7 @@ for (var/trait in GLOB.movement_type_trait_to_flag) if (HAS_TRAIT(parent, trait)) ADD_TRAIT(rider, trait, REF(src)) - ADD_TRAIT(rider, TRAIT_NO_FLOATING_ANIM, REF(src)) + rider.add_traits(rider_traits, REF(src)) /// This proc is called when the rider attempts to grab the thing they're riding, preventing them from doing so. /datum/component/riding/proc/on_rider_try_pull(mob/living/rider_pulling, atom/movable/target, force) diff --git a/code/datums/components/riding/riding_mob.dm b/code/datums/components/riding/riding_mob.dm index a3b5fcf0411c6..20afd23272607 100644 --- a/code/datums/components/riding/riding_mob.dm +++ b/code/datums/components/riding/riding_mob.dm @@ -431,6 +431,7 @@ /datum/component/riding/creature/goliath keytype = /obj/item/key/lasso vehicle_move_delay = 4 + rider_traits = list(TRAIT_NO_FLOATING_ANIM, TRAIT_TENTACLE_IMMUNE) /datum/component/riding/creature/goliath/deathmatch keytype = null From b0459944d9fd63e74e1c8a18392fd08f1d3fa1b1 Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Wed, 10 Apr 2024 19:24:07 -0500 Subject: [PATCH 153/938] Baisc Bot "Commission Emote" Tweak (#82549) ## About The Pull Request 1. Simple bots use Manual Emotes like Basic Bots 2. Re-ups the CD for emoting to commission bots to 60 seconds, as it was originally with Simple Bots 3. Punctuates the manual emotes 4. Deletes the fist bump message ## Why It's Good For The Game 1. Consistency. 2. These messages get a little... a lot spammy when walking around the halls, especially if Robotics has made a few additional bots. The original implementation had a CD of 60 seconds, which the AI behavior halved. Upping it back up for consistency + less spam. 3. Looks a little less shoddy. 4. It's a cute message, but it's completely out of character for what the bots are supposed to be "doing". They're "saluting" their "commissioned officer", not meeting up with the bros. Also they don't have fists! I understand saluting with their "robot appendage" but they don't punch people! ## Changelog :cl: Melbert qol: Basic Bots will use their "salute" emotes less often. del: Basic bot fists. /:cl: --- code/modules/mob/living/basic/bots/bot_ai.dm | 7 +++---- code/modules/mob/living/simple_animal/bot/bot.dm | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/code/modules/mob/living/basic/bots/bot_ai.dm b/code/modules/mob/living/basic/bots/bot_ai.dm index 21abafb860e81..706a8b58ba021 100644 --- a/code/modules/mob/living/basic/bots/bot_ai.dm +++ b/code/modules/mob/living/basic/bots/bot_ai.dm @@ -2,9 +2,8 @@ blackboard = list( BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_SALUTE_MESSAGES = list( - "salutes", + "performs an elaborate salute for", "nods in appreciation towards", - "fist bumps", ), BB_UNREACHABLE_LIST_COOLDOWN = 45 SECONDS, ) @@ -205,7 +204,7 @@ /datum/ai_behavior/find_and_set/valid_authority behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION - action_cooldown = 30 SECONDS + action_cooldown = BOT_COMMISSIONED_SALUTE_DELAY /datum/ai_behavior/find_and_set/valid_authority/search_tactic(datum/ai_controller/controller, locate_path, search_range) for(var/mob/living/nearby_mob in oview(search_range, controller.pawn)) @@ -231,7 +230,7 @@ if(our_hat) salute_list += "tips [our_hat] at " - bot_pawn.manual_emote(pick(salute_list) + " [controller.blackboard[target_key]]") + bot_pawn.manual_emote(pick(salute_list) + " [controller.blackboard[target_key]]!") finish_action(controller, TRUE, target_key) return diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index 2ebac99efdaf1..27bbec88292c7 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -380,7 +380,7 @@ COOLDOWN_START(src, next_salute_check, BOT_COMMISSIONED_SALUTE_DELAY) for(var/mob/living/simple_animal/bot/B in view(5, src)) if(!HAS_TRAIT(B, TRAIT_COMMISSIONED) && B.bot_mode_flags & BOT_MODE_ON) - visible_message("[B] performs an elaborate salute for [src]!") + manual_emote("performs an elaborate salute for [src]!") break switch(mode) //High-priority overrides are processed first. Bots can do nothing else while under direct command. From 8eef5a59136390c97a6e36e4b88da3e8dcb89f5f Mon Sep 17 00:00:00 2001 From: Pickle-Coding <58013024+Pickle-Coding@users.noreply.github.com> Date: Thu, 11 Apr 2024 01:25:30 +0100 Subject: [PATCH 154/938] Atmos resin can cool the floor down directly. (#82553) ## About The Pull Request Makes atmos resin set the floor's temperature to 293.15 Kelvin. ## Why It's Good For The Game The floor can heat the air up. If someone were to extinguish a tritium fire or something ridiculous with halon, then an awkward situation will arise where the halon cools the air down, but when someone breaks the resin open, the floor heats the air back up, triggering the resin to spawn again and again, which can cause quite awkward problems. ## Changelog :cl: balance: Atmos resin can directly cool the floor. /:cl: --- .../objects/effects/effect_system/fluid_spread/effects_foam.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm b/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm index 908180074575c..6d968574c686c 100644 --- a/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm +++ b/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm @@ -430,6 +430,7 @@ return location.ClearWet() + location.temperature = T20C if(location.air) var/datum/gas_mixture/air = location.air air.temperature = T20C From 5351dcf79a88a6042505a3bd638d0d6c2fc865f5 Mon Sep 17 00:00:00 2001 From: disappointedButNotSuprised <57324037+disappointedButNotSuprised@users.noreply.github.com> Date: Thu, 11 Apr 2024 02:29:38 +0200 Subject: [PATCH 155/938] Coffee machines carry over reagents from the beans (#82519) ## About The Pull Request I can't believe that this wasn't included in the original PR #70991. From now on, if there might be any unusual substances inside coffee beans, their reagents will be carried over to the coffee made by the machine. This is one of those niche unused mechanics that no one knows about but the coders hope to see one day in a intricate plot situation. please please please I hope so much for someone to use this Obviously a indispensable gampleay feature. https://github.com/tgstation/tgstation/assets/57324037/e3c243d7-03fd-47bc-9bdb-fac50c5bba0b ## Why It's Good For The Game Provides the coffee machine with features that it should have had fromm the beginning. ## Changelog :cl: add: Coffee machines can now carry over reagents from the beans to the coffee (surely no one will inject poison into them) /:cl: --------- Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> --- .../food_and_drinks/machinery/coffeemaker.dm | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/code/modules/food_and_drinks/machinery/coffeemaker.dm b/code/modules/food_and_drinks/machinery/coffeemaker.dm index d79eebc993abc..5fdd296d7fc69 100644 --- a/code/modules/food_and_drinks/machinery/coffeemaker.dm +++ b/code/modules/food_and_drinks/machinery/coffeemaker.dm @@ -715,9 +715,32 @@ if(!try_brew()) return operate_for(brew_time) - coffeepot.reagents.add_reagent_list(list(/datum/reagent/consumable/coffee = 120)) - coffee.Cut(1,2) //remove the first item from the list + + // create a reference bean reagent list + var/list/reference_bean_reagents = list() + var/obj/item/food/grown/coffee/reference_bean = new /obj/item/food/grown/coffee(src) + for(var/datum/reagent/ref_bean_reagent as anything in reference_bean.reagents.reagent_list) + reference_bean_reagents += ref_bean_reagent.name + + // add all the reagents from the coffee beans to the coffeepot (ommit the ones from the reference bean) + var/list/reagent_delta = list() + var/obj/item/food/grown/coffee/bean = coffee[coffee_amount] + for(var/datum/reagent/substance as anything in bean.reagents.reagent_list) + if(!(reference_bean_reagents.Find(substance.name))) // we only add the reagent if it's a non-standard for coffee beans + reagent_delta += list(substance.type = substance.volume) + coffeepot.reagents.add_reagent_list(reagent_delta) + + qdel(reference_bean) + + // remove the coffee beans from the machine + coffee.Cut(1,2) coffee_amount-- + + // fill the rest of the pot with coffee + if(coffeepot.reagents.total_volume < 120) + var/extra_coffee_amount = 120 - coffeepot.reagents.total_volume + coffeepot.reagents.add_reagent(/datum/reagent/consumable/coffee, extra_coffee_amount) + update_appearance(UPDATE_OVERLAYS) #undef BEAN_CAPACITY From d21d2d287a0868f2c7f282f65ed2ccc7f764813a Mon Sep 17 00:00:00 2001 From: Changelogs Date: Thu, 11 Apr 2024 00:40:03 +0000 Subject: [PATCH 156/938] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-82002.yml | 13 ----- html/changelogs/AutoChangeLog-pr-82288.yml | 8 ---- html/changelogs/AutoChangeLog-pr-82366.yml | 4 -- html/changelogs/AutoChangeLog-pr-82458.yml | 4 -- html/changelogs/AutoChangeLog-pr-82462.yml | 5 -- html/changelogs/AutoChangeLog-pr-82507.yml | 4 -- html/changelogs/AutoChangeLog-pr-82513.yml | 6 --- html/changelogs/AutoChangeLog-pr-82548.yml | 4 -- html/changelogs/AutoChangeLog-pr-82559.yml | 4 -- html/changelogs/AutoChangeLog-pr-82565.yml | 5 -- html/changelogs/archive/2024-04.yml | 56 ++++++++++++++++++++++ 11 files changed, 56 insertions(+), 57 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-82002.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82288.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82366.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82458.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82462.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82507.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82513.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82548.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82559.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82565.yml diff --git a/html/changelogs/AutoChangeLog-pr-82002.yml b/html/changelogs/AutoChangeLog-pr-82002.yml deleted file mode 100644 index 8ce69499f2a81..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82002.yml +++ /dev/null @@ -1,13 +0,0 @@ -author: "SyncIt21" -delete-after: True -changes: - - qol: "Adds screen tips & examines for screwdriver, wrench, crowbar & beaker insertion, removal & replacing actions" - - qol: "Analyzing reagents no longer blocks other players from doing other operations. Multiple players can analyze different reagents on the same machine" - - qol: "You cannot do any tool acts on the machine while printing to prevent any side effects." - - qol: "The preferred container for the master reagent in the beaker is now showed in both condiment & chem master. The feature can be enabled/disabled via a check box" - - code_imp: "removed defines for reagent transfer, vars for reagent analyzis to save memory. Autodoc for other vars & procs" - - bugfix: "You can hit the chem master with tools like screwdriver, crowbar, wrench & beaker in combat mode" - - bugfix: "You cannot insert hologram items into the chem master" - - bugfix: "Deconstructing a condiment master will give you the circuit board already pre-programmed with that option" - - bugfix: "You now print the exact amount of containers requested even with upgraded parts without creating empty containers. Max printable containers is 13 with tier 4 parts able to print 50 containers." - - refactor: "Optimized client side UI code & chem master as a whole." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82288.yml b/html/changelogs/AutoChangeLog-pr-82288.yml deleted file mode 100644 index 95f1381b45d0c..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82288.yml +++ /dev/null @@ -1,8 +0,0 @@ -author: "YesterdaysPromise" -delete-after: True -changes: - - rscadd: "Added long balloon box to the clown's starting inventory, and a skill-chip of long lost honk-motherian knowledge to their brain." - - rscadd: "Added long balloons. Consequently, added balloon animals to make from such balloons. Also, balloon top hat, vest, helmet, and a mallet. Don't ask about the mallet." - - rscadd: "A long balloons box harvested fresh from the farms on the clown planet will be able to be shipped in a crate to the cargo department near you!" - - rscadd: "As per requests; water balloons can now be printed at service lathe, and entertainment modsuit can now blow long balloons!" - - image: "Balloons will now have an unique sprite when in the inventory, compared when to on the ground." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82366.yml b/html/changelogs/AutoChangeLog-pr-82366.yml deleted file mode 100644 index 0ba83be5af53d..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82366.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SethLafuente" -delete-after: True -changes: - - bugfix: "Fixes Radiation Hood not having FOV blockage" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82458.yml b/html/changelogs/AutoChangeLog-pr-82458.yml deleted file mode 100644 index b6045d8d5cf30..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82458.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Watermelon914" -delete-after: True -changes: - - admin: "LUA - Adds a new library called handler_group. Include it in your files by doing require('handler_group')" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82462.yml b/html/changelogs/AutoChangeLog-pr-82462.yml deleted file mode 100644 index 30d88ce8c88b2..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82462.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Boviro" -delete-after: True -changes: - - qol: "Atmospherics Overalls now can store fire extinguishers in the suit storage slot" - - balance: "Increased Advanced Extinguisher capacity to 100u" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82507.yml b/html/changelogs/AutoChangeLog-pr-82507.yml deleted file mode 100644 index 36059fcae8438..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82507.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SyncIt21" -delete-after: True -changes: - - bugfix: "Autolathe correctly computes the print amount of custom material items like toolboxes and doesn't grey out its print button" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82513.yml b/html/changelogs/AutoChangeLog-pr-82513.yml deleted file mode 100644 index 130736a00a4a1..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82513.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "Bilbo367" -delete-after: True -changes: - - bugfix: "fixes ody sleeper UI not updating to new chems to inject." - - bugfix: "fixes ody sleeper not telling user why they can't pick up a person." - - code_imp: "gives a common method for giving reagent list data to .tsx" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82548.yml b/html/changelogs/AutoChangeLog-pr-82548.yml deleted file mode 100644 index c07987db272a1..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82548.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Jacquerel" -delete-after: True -changes: - - bugfix: "Medbots can no longer be used as especially large golden ID cards" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82559.yml b/html/changelogs/AutoChangeLog-pr-82559.yml deleted file mode 100644 index e9a6df7ad0090..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82559.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Absolucy" -delete-after: True -changes: - - qol: "Added balloon alerts whenever you start plunging something (i.e )" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82565.yml b/html/changelogs/AutoChangeLog-pr-82565.yml deleted file mode 100644 index 13a5e1425059b..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82565.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "JohnFulpWillard" -delete-after: True -changes: - - refactor: "Blueprints now use TGUI." - - qol: "Blueprints can now be used while lying down." \ No newline at end of file diff --git a/html/changelogs/archive/2024-04.yml b/html/changelogs/archive/2024-04.yml index 84c34ad1d8a2b..c3554effffbfb 100644 --- a/html/changelogs/archive/2024-04.yml +++ b/html/changelogs/archive/2024-04.yml @@ -326,3 +326,59 @@ - image: Updates the colors of various material datum to bring them closer in-line with their actual material stacks - image: Improves the sprites for the material knight armor and helmet. +2024-04-11: + Absolucy: + - qol: Added balloon alerts whenever you start plunging something (i.e ) + Bilbo367: + - bugfix: fixes ody sleeper UI not updating to new chems to inject. + - bugfix: fixes ody sleeper not telling user why they can't pick up a person. + - code_imp: gives a common method for giving reagent list data to .tsx + Boviro: + - qol: Atmospherics Overalls now can store fire extinguishers in the suit storage + slot + - balance: Increased Advanced Extinguisher capacity to 100u + Jacquerel: + - bugfix: Medbots can no longer be used as especially large golden ID cards + JohnFulpWillard: + - refactor: Blueprints now use TGUI. + - qol: Blueprints can now be used while lying down. + SethLafuente: + - bugfix: Fixes Radiation Hood not having FOV blockage + SyncIt21: + - qol: Adds screen tips & examines for screwdriver, wrench, crowbar & beaker insertion, + removal & replacing actions + - qol: Analyzing reagents no longer blocks other players from doing other operations. + Multiple players can analyze different reagents on the same machine + - qol: You cannot do any tool acts on the machine while printing to prevent any + side effects. + - qol: The preferred container for the master reagent in the beaker is now showed + in both condiment & chem master. The feature can be enabled/disabled via a check + box + - code_imp: removed defines for reagent transfer, vars for reagent analyzis to save + memory. Autodoc for other vars & procs + - bugfix: You can hit the chem master with tools like screwdriver, crowbar, wrench + & beaker in combat mode + - bugfix: You cannot insert hologram items into the chem master + - bugfix: Deconstructing a condiment master will give you the circuit board already + pre-programmed with that option + - bugfix: You now print the exact amount of containers requested even with upgraded + parts without creating empty containers. Max printable containers is 13 with + tier 4 parts able to print 50 containers. + - refactor: Optimized client side UI code & chem master as a whole. + - bugfix: Autolathe correctly computes the print amount of custom material items + like toolboxes and doesn't grey out its print button + Watermelon914: + - admin: LUA - Adds a new library called handler_group. Include it in your files + by doing require('handler_group') + YesterdaysPromise: + - rscadd: Added long balloon box to the clown's starting inventory, and a skill-chip + of long lost honk-motherian knowledge to their brain. + - rscadd: Added long balloons. Consequently, added balloon animals to make from + such balloons. Also, balloon top hat, vest, helmet, and a mallet. Don't ask + about the mallet. + - rscadd: A long balloons box harvested fresh from the farms on the clown planet + will be able to be shipped in a crate to the cargo department near you! + - rscadd: As per requests; water balloons can now be printed at service lathe, and + entertainment modsuit can now blow long balloons! + - image: Balloons will now have an unique sprite when in the inventory, compared + when to on the ground. From 302b609f586fbd49b90791cd6156b32c07b1e52e Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 11 Apr 2024 12:40:39 +1200 Subject: [PATCH 157/938] Automatic changelog for PR #82567 [ci skip] --- html/changelogs/AutoChangeLog-pr-82567.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82567.yml diff --git a/html/changelogs/AutoChangeLog-pr-82567.yml b/html/changelogs/AutoChangeLog-pr-82567.yml new file mode 100644 index 0000000000000..5c2abd03a7c12 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82567.yml @@ -0,0 +1,4 @@ +author: "Jacquerel" +delete-after: True +changes: + - spellcheck: "Effectively hitting furniture and machines with objects will no longer be double punctuated." \ No newline at end of file From 99b4ae6a495c487175350a154c5fcfd59182e196 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 11 Apr 2024 12:40:45 +1200 Subject: [PATCH 158/938] Automatic changelog for PR #82550 [ci skip] --- html/changelogs/AutoChangeLog-pr-82550.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82550.yml diff --git a/html/changelogs/AutoChangeLog-pr-82550.yml b/html/changelogs/AutoChangeLog-pr-82550.yml new file mode 100644 index 0000000000000..2e15a8101ca67 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82550.yml @@ -0,0 +1,4 @@ +author: "Jacquerel" +delete-after: True +changes: + - bugfix: "Goliaths can't grab their own riders with tentacles" \ No newline at end of file From 816cb7f3a88df6ed68313366700a6a9908512fef Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 11 Apr 2024 12:41:23 +1200 Subject: [PATCH 159/938] Automatic changelog for PR #82549 [ci skip] --- html/changelogs/AutoChangeLog-pr-82549.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82549.yml diff --git a/html/changelogs/AutoChangeLog-pr-82549.yml b/html/changelogs/AutoChangeLog-pr-82549.yml new file mode 100644 index 0000000000000..af0ea6be0d2ac --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82549.yml @@ -0,0 +1,5 @@ +author: "Melbert" +delete-after: True +changes: + - qol: "Basic Bots will use their \"salute\" emotes less often." + - rscdel: "Basic bot fists." \ No newline at end of file From 3c4cda6db488c0aeb0ececcdb31e6cf3f89cf7ba Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 11 Apr 2024 12:41:40 +1200 Subject: [PATCH 160/938] Automatic changelog for PR #82553 [ci skip] --- html/changelogs/AutoChangeLog-pr-82553.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82553.yml diff --git a/html/changelogs/AutoChangeLog-pr-82553.yml b/html/changelogs/AutoChangeLog-pr-82553.yml new file mode 100644 index 0000000000000..bbe3055c5c55a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82553.yml @@ -0,0 +1,4 @@ +author: "Pickle-Coding" +delete-after: True +changes: + - balance: "Atmos resin can directly cool the floor." \ No newline at end of file From e29fe41661cbf8c2b6473dcf0cf735b662b938ae Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 11 Apr 2024 12:42:16 +1200 Subject: [PATCH 161/938] Automatic changelog for PR #82519 [ci skip] --- html/changelogs/AutoChangeLog-pr-82519.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82519.yml diff --git a/html/changelogs/AutoChangeLog-pr-82519.yml b/html/changelogs/AutoChangeLog-pr-82519.yml new file mode 100644 index 0000000000000..c091822d48cf5 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82519.yml @@ -0,0 +1,4 @@ +author: "disappointedButNotSuprised" +delete-after: True +changes: + - rscadd: "Coffee machines can now carry over reagents from the beans to the coffee (surely no one will inject poison into them)" \ No newline at end of file From 227cdd2c7cdd33d827d1e1bc14645af81dd5b2ad Mon Sep 17 00:00:00 2001 From: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Date: Thu, 11 Apr 2024 07:28:11 +0530 Subject: [PATCH 162/938] [NO GBP] Patches & renaming for `NO_DECONSTRUCTION` flag (#82547) ## About The Pull Request 1. Renames `NO_DECONSTRUCTION` -> `NO_DEBRIS_AFTER_DECONSTRUCTION`. As the name suggests when the object is deconstructed it won't drop any items/debris. After my last refactor for this flag it now serves a new purpose so its name has been changed to match that 2. Fixes objects that are now using `NO_DECONSTRUCTION` incorrectly. Some of these changes include - Removing the flag in objects where there are no means to deconstruct them (e.g. jukebox, hydroponics soil, flora etc) - Replacing the flags old purpose by overriding its tool procs so that it regains its old behaviour(e.g. You once again cannot deconstruct ctf reinforced tables, survival pods, indestructible windows etc) ## Changelog :cl: code: renamed `NO_DECONSTRUCTION` to `NO_DEBRIS_AFTER_DECONSTRUCTION` so its name matches its intended purpose fix: fixes some items that incorrectly used `NO_DECONSTRUCTION` prior to its refactor, meaning makes some objects non deconstructable again /:cl: --- code/__DEFINES/obj_flags.dm | 2 +- code/_globalvars/bitfields.dm | 2 +- code/datums/elements/frozen.dm | 2 +- code/game/machinery/_machinery.dm | 2 +- code/game/machinery/dance_machine.dm | 1 - code/game/machinery/doors/airlock.dm | 2 +- code/game/machinery/hologram.dm | 7 ++++++- code/game/machinery/recycler.dm | 8 +++++++- .../machinery/telecomms/machines/allinone.dm | 1 - code/game/objects/obj_defense.dm | 6 +++--- .../objects/structures/beds_chairs/chair.dm | 4 ++-- code/game/objects/structures/flora.dm | 1 - code/game/objects/structures/window.dm | 14 +++++++++++--- .../awaymissions/mission_code/murderdome.dm | 19 +++++++++++++------ code/modules/capture_the_flag/ctf_game.dm | 7 ++++++- .../food_and_drinks/machinery/food_cart.dm | 2 +- code/modules/holodeck/computer.dm | 4 ++-- code/modules/holodeck/holo_effect.dm | 2 +- code/modules/hydroponics/hydroponics.dm | 1 - .../mapfluff/ruins/objects_and_mobs/museum.dm | 7 ++++++- code/modules/mining/equipment/survival_pod.dm | 13 ++++++++++++- .../chemistry/machinery/chem_synthesizer.dm | 10 ++++++---- .../shuttle/spaceship_navigation_beacon.dm | 1 - code/modules/shuttle/special.dm | 14 ++++++++++++-- code/modules/shuttle/syndicate.dm | 4 +++- .../modules/transport/tram/tram_controller.dm | 6 ++++-- 26 files changed, 100 insertions(+), 42 deletions(-) diff --git a/code/__DEFINES/obj_flags.dm b/code/__DEFINES/obj_flags.dm index 469811c96dc59..ea5b929651dda 100644 --- a/code/__DEFINES/obj_flags.dm +++ b/code/__DEFINES/obj_flags.dm @@ -15,7 +15,7 @@ #define IGNORE_DENSITY (1<<11) //! Can we ignore density when building on this object? (for example, directional windows and grilles) #define INFINITE_RESKIN (1<<12) // We can reskin this item infinitely #define CONDUCTS_ELECTRICITY (1<<13) //! Can this object conduct electricity? -#define NO_DECONSTRUCTION (1<<14) //! Atoms don't spawn anything when deconstructed. They just vanish +#define NO_DEBRIS_AFTER_DECONSTRUCTION (1<<14) //! Atoms don't spawn anything when deconstructed. They just vanish // If you add new ones, be sure to add them to /obj/Initialize as well for complete mapping support diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 37e7ef30d41c7..5b2f4e9f6dd6e 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -290,7 +290,7 @@ DEFINE_BITFIELD(obj_flags, list( "EMAGGED" = EMAGGED, "IGNORE_DENSITY" = IGNORE_DENSITY, "IN_USE" = IN_USE, - "NO_DECONSTRUCTION" = NO_DECONSTRUCTION, + "NO_DEBRIS_AFTER_DECONSTRUCTION" = NO_DEBRIS_AFTER_DECONSTRUCTION, "UNIQUE_RENAME" = UNIQUE_RENAME, )) diff --git a/code/datums/elements/frozen.dm b/code/datums/elements/frozen.dm index 434968dd4d5e0..d112ef31b5f91 100644 --- a/code/datums/elements/frozen.dm +++ b/code/datums/elements/frozen.dm @@ -63,7 +63,7 @@ GLOBAL_LIST_INIT(freon_color_matrix, list("#2E5E69", "#60A2A8", "#A1AFB1", rgb(0 else log_combat(throwingdatum.thrower, target, "launched", addition = "shattering it due to being frozen.") obj_target.visible_message(span_danger("[obj_target] shatters into a million pieces!")) - obj_target.obj_flags |= NO_DECONSTRUCTION // disable item spawning + obj_target.obj_flags |= NO_DEBRIS_AFTER_DECONSTRUCTION // disable item spawning obj_target.deconstruct(FALSE) // call pre-deletion specialized code -- internals release gas etc /// signal handler for COMSIG_MOVABLE_MOVED that unfreezes our target if it moves onto an open turf thats hotter than diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index 30dfaea445f9e..9648418c5d43f 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -827,7 +827,7 @@ /obj/machinery/handle_deconstruct(disassembled = TRUE) SHOULD_NOT_OVERRIDE(TRUE) - if(obj_flags & NO_DECONSTRUCTION) + if(obj_flags & NO_DEBRIS_AFTER_DECONSTRUCTION) dump_inventory_contents() //drop stuff we consider important return //Just delete us, no need to call anything else. diff --git a/code/game/machinery/dance_machine.dm b/code/game/machinery/dance_machine.dm index 53799d6dfc188..45daa1966a635 100644 --- a/code/game/machinery/dance_machine.dm +++ b/code/game/machinery/dance_machine.dm @@ -162,7 +162,6 @@ req_access = null anchored = TRUE resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION /obj/machinery/jukebox/disco/activate_music() . = ..() diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index b01609fc10e1c..96f7d568f0e16 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -1496,7 +1496,7 @@ /obj/machinery/door/airlock/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir) if((damage_amount >= atom_integrity) && (damage_flag == BOMB)) - obj_flags |= NO_DECONSTRUCTION //If an explosive took us out, don't drop the assembly + obj_flags |= NO_DEBRIS_AFTER_DECONSTRUCTION //If an explosive took us out, don't drop the assembly . = ..() if(atom_integrity < (0.75 * max_integrity)) update_appearance() diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index 88c2959416c3f..16f89fdf3c103 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -127,7 +127,6 @@ Possible to do for anyone motivated enough: /obj/machinery/holopad/tutorial resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION on_network = FALSE ///Proximity monitor associated with this atom, needed for proximity checks. var/datum/proximity_monitor/proximity_monitor @@ -143,6 +142,12 @@ Possible to do for anyone motivated enough: new_disk.forceMove(src) disk = new_disk +/obj/machinery/holopad/tutorial/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver) + return NONE + +/obj/machinery/holopad/tutorial/default_deconstruction_crowbar(obj/item/crowbar, ignore_panel, custom_deconstruct) + return NONE + /obj/machinery/holopad/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE) . = ..() if(!loc) diff --git a/code/game/machinery/recycler.dm b/code/game/machinery/recycler.dm index 9cbf787d58d68..28aae48886621 100644 --- a/code/game/machinery/recycler.dm +++ b/code/game/machinery/recycler.dm @@ -239,9 +239,15 @@ /obj/machinery/recycler/deathtrap name = "dangerous old crusher" - obj_flags = CAN_BE_HIT | EMAGGED | NO_DECONSTRUCTION + obj_flags = CAN_BE_HIT | EMAGGED crush_damage = 120 +/obj/machinery/recycler/deathtrap/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver) + return NONE + +/obj/machinery/recycler/deathtrap/default_deconstruction_crowbar(obj/item/crowbar, ignore_panel, custom_deconstruct) + return NONE + /obj/item/paper/guides/recycler name = "paper - 'garbage duty instructions'" default_raw_text = "

New Assignment

You have been assigned to collect garbage from trash bins, located around the station. The crewmembers will put their trash into it and you will collect said trash.

There is a recycling machine near your closet, inside maintenance; use it to recycle the trash for a small chance to get useful minerals. Then, deliver these minerals to cargo or engineering. You are our last hope for a clean station. Do not screw this up!" diff --git a/code/game/machinery/telecomms/machines/allinone.dm b/code/game/machinery/telecomms/machines/allinone.dm index f159339193e5a..9b32a4ac19246 100644 --- a/code/game/machinery/telecomms/machines/allinone.dm +++ b/code/game/machinery/telecomms/machines/allinone.dm @@ -20,7 +20,6 @@ /obj/machinery/telecomms/allinone/indestructible resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION /obj/machinery/telecomms/allinone/indestructible/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver) return NONE diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index 4731ad4395f17..9ebcbb253d20b 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -168,9 +168,9 @@ /** * The interminate proc between deconstruct() & atom_deconstruct(). By default this delegates deconstruction to - * atom_deconstruct if NO_DECONSTRUCTION is absent but subtypes can override this to handle NO_DECONSTRUCTION in their + * atom_deconstruct if NO_DEBRIS_AFTER_DECONSTRUCTION is absent but subtypes can override this to handle NO_DEBRIS_AFTER_DECONSTRUCTION in their * own unique way. Override this if for example you want to dump out important content like mobs from the - * atom before deconstruction regardless if NO_DECONSTRUCTION is present or not + * atom before deconstruction regardless if NO_DEBRIS_AFTER_DECONSTRUCTION is present or not * Arguments * * * disassembled - TRUE means we cleanly took this atom apart using tools. FALSE means this was destroyed in a violent way @@ -178,7 +178,7 @@ /obj/proc/handle_deconstruct(disassembled = TRUE) SHOULD_CALL_PARENT(FALSE) - if(!(obj_flags & NO_DECONSTRUCTION)) + if(!(obj_flags & NO_DEBRIS_AFTER_DECONSTRUCTION)) atom_deconstruct(disassembled) /** diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm index 74546e2ccd79c..af4bb3084cdc1 100644 --- a/code/game/objects/structures/beds_chairs/chair.dm +++ b/code/game/objects/structures/beds_chairs/chair.dm @@ -479,11 +479,11 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool/bar, 0) icon_state = null buildstacktype = null item_chair = null - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION + obj_flags = parent_type::obj_flags | NO_DEBRIS_AFTER_DECONSTRUCTION alpha = 0 /obj/structure/chair/mime/wrench_act_secondary(mob/living/user, obj/item/weapon) - return ITEM_INTERACT_BLOCKING + return NONE /obj/structure/chair/mime/post_buckle_mob(mob/living/M) M.pixel_y += 5 diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm index 8749691c91d4d..2cfd490203c06 100644 --- a/code/game/objects/structures/flora.dm +++ b/code/game/objects/structures/flora.dm @@ -449,7 +449,6 @@ icon_state = "pinepresents" desc = "A wondrous decorated Christmas tree. It has presents!" resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF //protected by the christmas spirit - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION var/gift_type = /obj/item/gift/anything var/unlimited = FALSE var/static/list/took_presents //shared between all xmas trees diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index f689a94d1624c..d9bf900443686 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -792,10 +792,18 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/reinforced/tinted/frosted/spaw name = "hardened shuttle window" flags_1 = PREVENT_CLICK_UNDER_1 resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION -/obj/structure/window/reinforced/shuttle/indestructible/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) - return FALSE +/obj/structure/window/reinforced/shuttle/indestructible/welder_act(mob/living/user, obj/item/tool) + return NONE + +/obj/structure/window/reinforced/shuttle/indestructible/screwdriver_act(mob/living/user, obj/item/tool) + return NONE + +/obj/structure/window/reinforced/shuttle/indestructible/wrench_act(mob/living/user, obj/item/tool) + return NONE + +/obj/structure/window/reinforced/shuttle/indestructible/crowbar_act(mob/living/user, obj/item/tool) + return NONE /obj/structure/window/reinforced/plasma/plastitanium name = "plastitanium window" diff --git a/code/modules/awaymissions/mission_code/murderdome.dm b/code/modules/awaymissions/mission_code/murderdome.dm index 520372e68ac07..a59a491d4926f 100644 --- a/code/modules/awaymissions/mission_code/murderdome.dm +++ b/code/modules/awaymissions/mission_code/murderdome.dm @@ -1,20 +1,27 @@ /obj/structure/window/reinforced/fulltile/indestructible name = "robust window" - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION flags_1 = PREVENT_CLICK_UNDER_1 resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF -/obj/structure/window/reinforced/fulltile/indestructible/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) - return FALSE +/obj/structure/window/reinforced/fulltile/indestructible/screwdriver_act(mob/living/user, obj/item/tool) + return NONE +/obj/structure/window/reinforced/fulltile/indestructible/wrench_act(mob/living/user, obj/item/tool) + return NONE + +/obj/structure/window/reinforced/fulltile/indestructible/crowbar_act(mob/living/user, obj/item/tool) + return NONE /obj/structure/grille/indestructible - obj_flags = CONDUCTS_ELECTRICITY | NO_DECONSTRUCTION + obj_flags = CONDUCTS_ELECTRICITY resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF -/obj/structure/grille/indestructible/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) - return FALSE +/obj/structure/grille/indestructible/screwdriver_act(mob/living/user, obj/item/tool) + return NONE + +/obj/structure/grille/indestructible/wirecutter_act(mob/living/user, obj/item/tool) + return NONE /obj/effect/spawner/structure/window/reinforced/indestructible spawn_list = list(/obj/structure/grille/indestructible, /obj/structure/window/reinforced/fulltile/indestructible) diff --git a/code/modules/capture_the_flag/ctf_game.dm b/code/modules/capture_the_flag/ctf_game.dm index aac487a83d69c..38a7318b5548e 100644 --- a/code/modules/capture_the_flag/ctf_game.dm +++ b/code/modules/capture_the_flag/ctf_game.dm @@ -463,7 +463,12 @@ /obj/structure/table/reinforced/ctf resistance_flags = INDESTRUCTIBLE - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION + +/obj/structure/table/reinforced/ctf/wrench_act_secondary(mob/living/user, obj/item/tool) + return NONE + +/obj/structure/table/reinforced/ctf/screwdriver_act_secondary(mob/living/user, obj/item/tool) + return NONE #define CTF_LOADING_UNLOADED 0 #define CTF_LOADING_LOADING 1 diff --git a/code/modules/food_and_drinks/machinery/food_cart.dm b/code/modules/food_and_drinks/machinery/food_cart.dm index e068b7b8ce290..a14ea3593c51a 100644 --- a/code/modules/food_and_drinks/machinery/food_cart.dm +++ b/code/modules/food_and_drinks/machinery/food_cart.dm @@ -8,7 +8,7 @@ anchored = FALSE use_power = NO_POWER_USE req_access = list(ACCESS_KITCHEN) - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION + obj_flags = parent_type::obj_flags | NO_DEBRIS_AFTER_DECONSTRUCTION var/unpacked = FALSE var/obj/machinery/griddle/stand/cart_griddle var/obj/machinery/smartfridge/food/cart_smartfridge diff --git a/code/modules/holodeck/computer.dm b/code/modules/holodeck/computer.dm index db66578c5bd2c..1ff5bc47a5518 100644 --- a/code/modules/holodeck/computer.dm +++ b/code/modules/holodeck/computer.dm @@ -292,12 +292,12 @@ GLOBAL_LIST_INIT(typecache_holodeck_linked_floorcheck_ok, typecacheof(list(/turf holo_object.resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF if(isstructure(holo_object)) - holo_object.obj_flags |= NO_DECONSTRUCTION + holo_object.obj_flags |= NO_DEBRIS_AFTER_DECONSTRUCTION return if(ismachinery(holo_object)) var/obj/machinery/holo_machine = holo_object - holo_machine.obj_flags |= NO_DECONSTRUCTION + holo_machine.obj_flags |= NO_DEBRIS_AFTER_DECONSTRUCTION holo_machine.power_change() if(istype(holo_machine, /obj/machinery/button)) diff --git a/code/modules/holodeck/holo_effect.dm b/code/modules/holodeck/holo_effect.dm index afd4c2270388f..caa5b425ca4b3 100644 --- a/code/modules/holodeck/holo_effect.dm +++ b/code/modules/holodeck/holo_effect.dm @@ -50,7 +50,7 @@ var/newtype = pick(subtypesof(/obj/item/book/manual) - banned_books) var/obj/item/book/manual/to_spawn = new newtype(loc) to_spawn.flags_1 |= HOLOGRAM_1 - to_spawn.obj_flags |= NO_DECONSTRUCTION + to_spawn.obj_flags |= NO_DEBRIS_AFTER_DECONSTRUCTION return to_spawn /obj/effect/holodeck_effect/mobspawner diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index cc432d4bbad85..669b22ed0ac46 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -1159,7 +1159,6 @@ circuit = null density = FALSE use_power = NO_POWER_USE - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION unwrenchable = FALSE self_sustaining_overlay_icon_state = null maxnutri = 15 diff --git a/code/modules/mapfluff/ruins/objects_and_mobs/museum.dm b/code/modules/mapfluff/ruins/objects_and_mobs/museum.dm index 5c1b4323208c6..1c0a5392fb9b2 100644 --- a/code/modules/mapfluff/ruins/objects_and_mobs/museum.dm +++ b/code/modules/mapfluff/ruins/objects_and_mobs/museum.dm @@ -159,9 +159,14 @@ mask = /obj/item/clothing/mask/fakemoustache/italian /obj/machinery/vending/hotdog/museum - obj_flags = parent_type::obj_flags|NO_DECONSTRUCTION onstation_override = TRUE +/obj/machinery/vending/hotdog/museum/screwdriver_act(mob/living/user, obj/item/attack_item) + return NONE + +/obj/machinery/vending/hotdog/museum/crowbar_act(mob/living/user, obj/item/attack_item) + return NONE + #define CAFE_KEYCARD_TOILETS "museum_cafe_key_toilets" ///Do not place these beyond the cafeteria shutters, or you might lock people out of reaching it. diff --git a/code/modules/mining/equipment/survival_pod.dm b/code/modules/mining/equipment/survival_pod.dm index d40589dd3f8ab..b22603f52d92b 100644 --- a/code/modules/mining/equipment/survival_pod.dm +++ b/code/modules/mining/equipment/survival_pod.dm @@ -249,7 +249,18 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/door/window/survival_pod/left, 0) light_color = COLOR_VERY_PALE_LIME_GREEN max_n_of_items = 10 pixel_y = -4 - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION + +/obj/machinery/smartfridge/survival_pod/welder_act(mob/living/user, obj/item/tool) + return NONE + +/obj/machinery/smartfridge/survival_pod/wrench_act(mob/living/user, obj/item/tool) + return NONE + +/obj/machinery/smartfridge/survival_pod/screwdriver_act(mob/living/user, obj/item/tool) + return NONE + +/obj/machinery/smartfridge/survival_pod/crowbar_act(mob/living/user, obj/item/tool) + return NONE /obj/machinery/smartfridge/survival_pod/Initialize(mapload) AddElement(/datum/element/update_icon_blocker) diff --git a/code/modules/reagents/chemistry/machinery/chem_synthesizer.dm b/code/modules/reagents/chemistry/machinery/chem_synthesizer.dm index c0cb45dda2aa2..552bfe48650ca 100644 --- a/code/modules/reagents/chemistry/machinery/chem_synthesizer.dm +++ b/code/modules/reagents/chemistry/machinery/chem_synthesizer.dm @@ -6,14 +6,16 @@ base_icon_state = "dispenser" amount = 10 resistance_flags = INDESTRUCTIBLE | FIRE_PROOF | ACID_PROOF | LAVA_PROOF - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION use_power = NO_POWER_USE - var/static/list/shortcuts = list( - "meth" = /datum/reagent/drug/methamphetamine - ) ///The purity of the created reagent in % (purity uses 0-1 values) var/purity = 100 +/obj/machinery/chem_dispenser/chem_synthesizer/screwdriver_act(mob/living/user, obj/item/tool) + return NONE + +/obj/machinery/chem_dispenser/chem_synthesizer/crowbar_act(mob/living/user, obj/item/tool) + return NONE + /obj/machinery/chem_dispenser/chem_synthesizer/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) if(!ui) diff --git a/code/modules/shuttle/spaceship_navigation_beacon.dm b/code/modules/shuttle/spaceship_navigation_beacon.dm index eb613be54def9..41b3f5e39ed9a 100644 --- a/code/modules/shuttle/spaceship_navigation_beacon.dm +++ b/code/modules/shuttle/spaceship_navigation_beacon.dm @@ -5,7 +5,6 @@ icon_state = "beacon_active" base_icon_state = "beacon" density = TRUE - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION /// Locked beacons cannot be jumped to by ships. var/locked = FALSE diff --git a/code/modules/shuttle/special.dm b/code/modules/shuttle/special.dm index 989ab4edc94a9..e5b4b0eb02439 100644 --- a/code/modules/shuttle/special.dm +++ b/code/modules/shuttle/special.dm @@ -79,7 +79,6 @@ var/obj/machinery/power/emitter/energycannon/magical/our_statue var/list/mob/living/sleepers = list() var/never_spoken = TRUE - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION /obj/structure/table/abductor/wabbajack/Initialize(mapload) . = ..() @@ -89,6 +88,12 @@ STOP_PROCESSING(SSobj, src) . = ..() +/obj/structure/table/abductor/wabbajack/screwdriver_act(mob/living/user, obj/item/tool) + return NONE + +/obj/structure/table/abductor/wabbajack/wrench_act(mob/living/user, obj/item/tool) + return NONE + /obj/structure/table/abductor/wabbajack/process() if(isnull(our_statue)) our_statue = locate() in orange(4, src) @@ -173,7 +178,6 @@ /obj/structure/table/wood/shuttle_bar resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION max_integrity = 1000 var/boot_dir = 1 @@ -184,6 +188,12 @@ ) AddElement(/datum/element/connect_loc, loc_connections) +/obj/structure/table/wood/shuttle_bar/screwdriver_act(mob/living/user, obj/item/tool) + return NONE + +/obj/structure/table/wood/shuttle_bar/wrench_act(mob/living/user, obj/item/tool) + return NONE + /obj/structure/table/wood/shuttle_bar/proc/on_entered(datum/source, atom/movable/AM) SIGNAL_HANDLER var/mob/living/M = AM diff --git a/code/modules/shuttle/syndicate.dm b/code/modules/shuttle/syndicate.dm index 402a87bf6d43d..08e0b0d269950 100644 --- a/code/modules/shuttle/syndicate.dm +++ b/code/modules/shuttle/syndicate.dm @@ -11,7 +11,9 @@ shuttleId = "syndicate" possible_destinations = "syndicate_away;syndicate_z5;syndicate_ne;syndicate_nw;syndicate_n;syndicate_se;syndicate_sw;syndicate_s;syndicate_custom" resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION + +/obj/machinery/computer/shuttle/syndicate/screwdriver_act(mob/living/user, obj/item/I) + return NONE /obj/machinery/computer/shuttle/syndicate/launch_check(mob/user) . = ..() diff --git a/code/modules/transport/tram/tram_controller.dm b/code/modules/transport/tram/tram_controller.dm index 7912588ab8a4d..51b8a32acafac 100644 --- a/code/modules/transport/tram/tram_controller.dm +++ b/code/modules/transport/tram/tram_controller.dm @@ -708,7 +708,9 @@ /obj/machinery/transport/tram_controller/hilbert configured_transport_id = HILBERT_LINE_1 - obj_flags = parent_type::obj_flags | NO_DECONSTRUCTION + +/obj/machinery/transport/tram_controller/wrench_act_secondary(mob/living/user, obj/item/tool) + return NONE /obj/machinery/transport/tram_controller/Initialize(mapload) . = ..() @@ -847,7 +849,7 @@ return playsound(loc, 'sound/items/deconstruct.ogg', 50, vary = TRUE) balloon_alert(user, "unsecured") - deconstruct() + deconstruct(TRUE) return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN /obj/machinery/transport/tram_controller/screwdriver_act_secondary(mob/living/user, obj/item/tool) From e04983605208990a7beb5369b3487f44f71ea57b Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 11 Apr 2024 14:02:36 +1200 Subject: [PATCH 163/938] Automatic changelog for PR #82547 [ci skip] --- html/changelogs/AutoChangeLog-pr-82547.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82547.yml diff --git a/html/changelogs/AutoChangeLog-pr-82547.yml b/html/changelogs/AutoChangeLog-pr-82547.yml new file mode 100644 index 0000000000000..3f8de915570f4 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82547.yml @@ -0,0 +1,5 @@ +author: "SyncIt21" +delete-after: True +changes: + - code_imp: "renamed `NO_DECONSTRUCTION` to `NO_DEBRIS_AFTER_DECONSTRUCTION` so its name matches its intended purpose" + - bugfix: "fixes some items that incorrectly used `NO_DECONSTRUCTION` prior to its refactor, meaning makes some objects non deconstructable again" \ No newline at end of file From c595c4c9f844300822b17bffb2eaa3c8dd7e2a30 Mon Sep 17 00:00:00 2001 From: Bloop <13398309+vinylspiders@users.noreply.github.com> Date: Wed, 10 Apr 2024 22:16:55 -0400 Subject: [PATCH 164/938] Quick spellcheck 'steall' (#82560) ## About The Pull Request https://github.com/tgstation/tgstation/pull/82447 quick followup to this, caught it while glancing through the code. --- strings/antagonist_flavor/spy_objective.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/strings/antagonist_flavor/spy_objective.json b/strings/antagonist_flavor/spy_objective.json index 9ea93ab8795c3..908a8da2b82c0 100644 --- a/strings/antagonist_flavor/spy_objective.json +++ b/strings/antagonist_flavor/spy_objective.json @@ -28,7 +28,7 @@ "Protect the station's @pick(happenings).", "Sabotage the station's power grid or engine.", "Steal all the @pick(stealables) from @pick(department).", - "Steall all the @pick(stealables) from @pick(location).", + "Steal all the @pick(stealables) from @pick(location).", "Steal as many @pick(stealables) as you can.", "Take control of the station as the new Captain.", "Take hostages of high value crewmembers and demand a ransom.", From eb1deb534625985b1486729fae7886a3c4030d40 Mon Sep 17 00:00:00 2001 From: _0Steven <42909981+00-Steven@users.noreply.github.com> Date: Thu, 11 Apr 2024 05:35:28 +0200 Subject: [PATCH 165/938] Fixes standard RPEDs not working on machines (#82528) ## About The Pull Request Previously, `exchange_parts(...)` would cancel if both the `NO_DECONSTRUCTION` flag was set and you couldn't use your part replacer from a distance. https://github.com/tgstation/tgstation/blob/1583cf0cc968cd9f5da2398035feb8d70d58bcf2/code/game/machinery/_machinery.dm#L958-L959 Our recent removal of `NO_DECONSTRUCTION`, however, has left this to _only_ be the latter. https://github.com/tgstation/tgstation/blob/f0ed4ba4ce6b114509c10ee2f36ab0af6d7c81d2/code/game/machinery/_machinery.dm#L956-L957 Buuuuut this makes it unconditionally cancel for normal RPEDs, instead of only blocking them if `NO_DECONSTRUCTION` was set. As `NO_DECONSTRUCTION` is very much no longer relevant for this purpose, we simply remove the ranged RPED check altogether. This fixes our issue. ## Why It's Good For The Game Fixes #82525. ## Changelog :cl: fix: Standard RPEDs work on machines again. /:cl: --- code/game/machinery/_machinery.dm | 3 --- code/modules/vending/_vending.dm | 2 -- 2 files changed, 5 deletions(-) diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index 9648418c5d43f..94e5f69a4783e 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -963,9 +963,6 @@ if(!istype(replacer_tool)) return FALSE - if(!replacer_tool.works_from_distance) - return FALSE - var/shouldplaysound = FALSE if(!component_parts) return FALSE diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm index 00f961b498c07..2713c5e52e0de 100644 --- a/code/modules/vending/_vending.dm +++ b/code/modules/vending/_vending.dm @@ -1142,8 +1142,6 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock) /obj/machinery/vending/exchange_parts(mob/user, obj/item/storage/part_replacer/replacer) if(!istype(replacer)) return FALSE - if(!replacer.works_from_distance) - return FALSE if(!component_parts || !refill_canister) return FALSE From cb07f77fda834a6f9af600632e6d1eed7981ecfb Mon Sep 17 00:00:00 2001 From: san7890 Date: Wed, 10 Apr 2024 21:40:01 -0600 Subject: [PATCH 166/938] Fixes incorrect operator usage in mecha code (#82570) ## About The Pull Request I completely screwed up and told the original PR author of #82415 (9922d2f2377c3ab571d34c857174c45f5521a5ae) to use the `XOR` operator instead of the `OR` operator (I wasn't thinking right for some reason when I was reading the ref), anyways this PR just fixes that because I misled the contributor into doing something that wasn't correct and actually would BREAK functionality instead. --- code/modules/vehicles/mecha/_mecha.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index 7cee1b6541c62..995764e0bb7d1 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -272,7 +272,7 @@ /// If the former occupants get polymorphed, mutated, chestburstered, /// or otherwise replaced by another mob, that mob is no longer in .occupants /// and gets deleted with the mech. However, they do remain in .contents - var/list/potential_occupants = contents ^ occupants + var/list/potential_occupants = contents | occupants for(var/mob/buggy_ejectee in potential_occupants) mob_exit(buggy_ejectee, silent = TRUE) From 7bcdf209e39c4e148ad9e5203a9b4815b1111d57 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 11 Apr 2024 15:42:19 +1200 Subject: [PATCH 167/938] Automatic changelog for PR #82528 [ci skip] --- html/changelogs/AutoChangeLog-pr-82528.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82528.yml diff --git a/html/changelogs/AutoChangeLog-pr-82528.yml b/html/changelogs/AutoChangeLog-pr-82528.yml new file mode 100644 index 0000000000000..af5f04c6abd15 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82528.yml @@ -0,0 +1,4 @@ +author: "00-Steven" +delete-after: True +changes: + - bugfix: "Standard RPEDs work on machines again." \ No newline at end of file From b523190c6dd2d895f4e228d74085cfe98f594ca4 Mon Sep 17 00:00:00 2001 From: Interception&? <137328283+intercepti0n@users.noreply.github.com> Date: Thu, 11 Apr 2024 06:53:00 +0300 Subject: [PATCH 168/938] Fixes TGUI debugging tools (#82569) This project doesn't interfere with the game logic and aims to fix multiple debugging features that are currently broken. Unfortunately, kitchen sink and debug layout became broken after migration to Redux. This PR aims to fix those features. --- tgui/packages/tgui/backend.ts | 4 ---- tgui/packages/tgui/debug/KitchenSink.jsx | 9 +++++---- tgui/packages/tgui/layouts/Pane.tsx | 8 +++----- tgui/packages/tgui/layouts/Window.tsx | 16 +++++----------- tgui/packages/tgui/routes.tsx | 7 +++++-- 5 files changed, 18 insertions(+), 26 deletions(-) diff --git a/tgui/packages/tgui/backend.ts b/tgui/packages/tgui/backend.ts index c85d515321020..9190d74dbe234 100644 --- a/tgui/packages/tgui/backend.ts +++ b/tgui/packages/tgui/backend.ts @@ -274,10 +274,6 @@ type BackendState = { shared: Record; suspending: boolean; suspended: boolean; - debug?: { - debugLayout: boolean; - kitchenSink: boolean; - }; }; /** diff --git a/tgui/packages/tgui/debug/KitchenSink.jsx b/tgui/packages/tgui/debug/KitchenSink.jsx index d215ab777d802..19044ca98d0c7 100644 --- a/tgui/packages/tgui/debug/KitchenSink.jsx +++ b/tgui/packages/tgui/debug/KitchenSink.jsx @@ -4,11 +4,12 @@ * @license MIT */ -import { useLocalState } from '../backend'; +import { useState } from 'react'; + import { Flex, Section, Tabs } from '../components'; import { Pane, Window } from '../layouts'; -const r = require.context('../stories', false, /\.stories\.js$/); +const r = require.context('../stories', false, /\.stories\.jsx$/); /** * @returns {{ @@ -22,8 +23,8 @@ const getStories = () => r.keys().map((path) => r(path)); export const KitchenSink = (props) => { const { panel } = props; - const [theme] = useLocalState('kitchenSinkTheme'); - const [pageIndex, setPageIndex] = useLocalState('pageIndex', 0); + const [theme] = useState(null); + const [pageIndex, setPageIndex] = useState(0); const stories = getStories(); const story = stories[pageIndex]; const Layout = panel ? Pane : Window; diff --git a/tgui/packages/tgui/layouts/Pane.tsx b/tgui/packages/tgui/layouts/Pane.tsx index a2858fae7fc7b..f34205545fbc1 100644 --- a/tgui/packages/tgui/layouts/Pane.tsx +++ b/tgui/packages/tgui/layouts/Pane.tsx @@ -9,6 +9,7 @@ import { classes } from 'common/react'; import { useBackend } from '../backend'; import { Box } from '../components'; import { BoxProps } from '../components/Box'; +import { useDebug } from '../debug'; import { Layout } from './Layout'; type Props = Partial<{ @@ -18,11 +19,8 @@ type Props = Partial<{ export function Pane(props: Props) { const { theme, children, className, ...rest } = props; - const { suspended, debug } = useBackend(); - let debugLayout = false; - if (debug) { - debugLayout = debug.debugLayout; - } + const { suspended } = useBackend(); + const { debugLayout = false } = useDebug(); return ( diff --git a/tgui/packages/tgui/layouts/Window.tsx b/tgui/packages/tgui/layouts/Window.tsx index 2b6fbf87356f1..aa91370bfc31e 100644 --- a/tgui/packages/tgui/layouts/Window.tsx +++ b/tgui/packages/tgui/layouts/Window.tsx @@ -13,6 +13,7 @@ import { globalStore } from '../backend'; import { Icon } from '../components'; import { BoxProps } from '../components/Box'; import { UI_DISABLED, UI_INTERACTIVE, UI_UPDATE } from '../constants'; +import { useDebug } from '../debug'; import { toggleKitchenSink } from '../debug/actions'; import { dragStartHandler, @@ -48,10 +49,8 @@ export const Window = (props: Props) => { height, } = props; - const { config, suspended, debug } = useBackend(); - if (suspended) { - return null; - } + const { config, suspended } = useBackend(); + const { debugLayout = false } = useDebug(); useEffect(() => { const updateGeometry = () => { @@ -80,11 +79,6 @@ export const Window = (props: Props) => { }; }, [width, height]); - let debugLayout = false; - if (debug) { - debugLayout = debug.debugLayout; - } - const dispatch = globalStore.dispatch; const fancy = config.window?.fancy; @@ -95,11 +89,11 @@ export const Window = (props: Props) => { ? config.status < UI_DISABLED : config.status < UI_INTERACTIVE); - return ( + return suspended ? null : ( { // Get the component for the current route export const getRoutedComponent = () => { - const { suspended, config, debug } = useBackend(); + const { suspended, config } = useBackend(); + const { kitchenSink = false } = useDebug(); + if (suspended) { return SuspendedWindow; } @@ -61,7 +64,7 @@ export const getRoutedComponent = () => { } if (process.env.NODE_ENV !== 'production') { // Show a kitchen sink - if (debug?.kitchenSink) { + if (kitchenSink) { return require('./debug').KitchenSink; } } From 3366054353e6b5fdecac0bae4a6594aa9b5b0c26 Mon Sep 17 00:00:00 2001 From: Bloop <13398309+vinylspiders@users.noreply.github.com> Date: Thu, 11 Apr 2024 06:59:13 -0400 Subject: [PATCH 169/938] [NO GBP] Fixes spurious runtime caused by icemoon (again) (#82582) ## About The Pull Request https://github.com/tgstation/tgstation/pull/82572 I tried to fix this but there was an unaccounted race condition which just caused a separate runtime... ![firefox_GxGibAO281](https://github.com/tgstation/tgstation/assets/13398309/f251aecc-ef17-4bae-a741-5aade40de423) Since the type is being changed mid-execution `replacement_turf` will become out of scope. My bad--this should fix it now for good. --- code/game/turfs/open/openspace.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/game/turfs/open/openspace.dm b/code/game/turfs/open/openspace.dm index afdcccf8ee92a..2006a3e6829bb 100644 --- a/code/game/turfs/open/openspace.dm +++ b/code/game/turfs/open/openspace.dm @@ -187,8 +187,8 @@ if(!T) return if(T.turf_flags & NO_RUINS && protect_ruin) - ChangeTurf(replacement_turf, null, CHANGETURF_IGNORE_AIR) - if(!isopenspaceturf(replacement_turf)) // only openspace turfs should be returning INITIALIZE_HINT_LATELOAD + var/turf/newturf = ChangeTurf(replacement_turf, null, CHANGETURF_IGNORE_AIR) + if(!isopenspaceturf(newturf)) // only openspace turfs should be returning INITIALIZE_HINT_LATELOAD return INITIALIZE_HINT_NORMAL return if(!ismineralturf(T) || !drill_below) From d39815a452bb62fcb9fe25d5348e891b0120dab2 Mon Sep 17 00:00:00 2001 From: Penelope Haze Date: Thu, 11 Apr 2024 13:40:14 -0400 Subject: [PATCH 170/938] Fix invalid List.Join() in chemsmoke logging (#82573) --- .../objects/effects/effect_system/fluid_spread/effects_smoke.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/objects/effects/effect_system/fluid_spread/effects_smoke.dm b/code/game/objects/effects/effect_system/fluid_spread/effects_smoke.dm index a0bf078c3dc4f..e651c8a3e2402 100644 --- a/code/game/objects/effects/effect_system/fluid_spread/effects_smoke.dm +++ b/code/game/objects/effects/effect_system/fluid_spread/effects_smoke.dm @@ -431,7 +431,7 @@ contained_reagents += "[reagent.volume]u [reagent]" var/where = "[AREACOORD(location)]" - var/contained = length(contained_reagents) ? "[contained_reagents.Join(", ", " \[", "\]")] @ [chemholder.chem_temp]K" : null + var/contained = length(contained_reagents) ? "\[[contained_reagents.Join(", ")]\] @ [chemholder.chem_temp]K" : null var/area/fluid_area = get_area(location) if(carry.my_atom?.fingerprintslast) //Some reagents don't have a my_atom in some cases var/mob/M = get_mob_by_key(carry.my_atom.fingerprintslast) From 1780fcef62e0413da65375a37f7c8030a0371419 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Fri, 12 Apr 2024 00:19:51 +0000 Subject: [PATCH 171/938] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-82519.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82528.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82547.yml | 5 ----- html/changelogs/AutoChangeLog-pr-82549.yml | 5 ----- html/changelogs/AutoChangeLog-pr-82550.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82553.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82567.yml | 4 ---- html/changelogs/archive/2024-04.yml | 20 ++++++++++++++++++++ 8 files changed, 20 insertions(+), 30 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-82519.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82528.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82547.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82549.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82550.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82553.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82567.yml diff --git a/html/changelogs/AutoChangeLog-pr-82519.yml b/html/changelogs/AutoChangeLog-pr-82519.yml deleted file mode 100644 index c091822d48cf5..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82519.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "disappointedButNotSuprised" -delete-after: True -changes: - - rscadd: "Coffee machines can now carry over reagents from the beans to the coffee (surely no one will inject poison into them)" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82528.yml b/html/changelogs/AutoChangeLog-pr-82528.yml deleted file mode 100644 index af5f04c6abd15..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82528.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "00-Steven" -delete-after: True -changes: - - bugfix: "Standard RPEDs work on machines again." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82547.yml b/html/changelogs/AutoChangeLog-pr-82547.yml deleted file mode 100644 index 3f8de915570f4..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82547.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "SyncIt21" -delete-after: True -changes: - - code_imp: "renamed `NO_DECONSTRUCTION` to `NO_DEBRIS_AFTER_DECONSTRUCTION` so its name matches its intended purpose" - - bugfix: "fixes some items that incorrectly used `NO_DECONSTRUCTION` prior to its refactor, meaning makes some objects non deconstructable again" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82549.yml b/html/changelogs/AutoChangeLog-pr-82549.yml deleted file mode 100644 index af0ea6be0d2ac..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82549.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Melbert" -delete-after: True -changes: - - qol: "Basic Bots will use their \"salute\" emotes less often." - - rscdel: "Basic bot fists." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82550.yml b/html/changelogs/AutoChangeLog-pr-82550.yml deleted file mode 100644 index 2e15a8101ca67..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82550.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Jacquerel" -delete-after: True -changes: - - bugfix: "Goliaths can't grab their own riders with tentacles" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82553.yml b/html/changelogs/AutoChangeLog-pr-82553.yml deleted file mode 100644 index bbe3055c5c55a..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82553.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Pickle-Coding" -delete-after: True -changes: - - balance: "Atmos resin can directly cool the floor." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82567.yml b/html/changelogs/AutoChangeLog-pr-82567.yml deleted file mode 100644 index 5c2abd03a7c12..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82567.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Jacquerel" -delete-after: True -changes: - - spellcheck: "Effectively hitting furniture and machines with objects will no longer be double punctuated." \ No newline at end of file diff --git a/html/changelogs/archive/2024-04.yml b/html/changelogs/archive/2024-04.yml index c3554effffbfb..0f9f4f1c12f61 100644 --- a/html/changelogs/archive/2024-04.yml +++ b/html/changelogs/archive/2024-04.yml @@ -382,3 +382,23 @@ entertainment modsuit can now blow long balloons! - image: Balloons will now have an unique sprite when in the inventory, compared when to on the ground. +2024-04-12: + 00-Steven: + - bugfix: Standard RPEDs work on machines again. + Jacquerel: + - spellcheck: Effectively hitting furniture and machines with objects will no longer + be double punctuated. + - bugfix: Goliaths can't grab their own riders with tentacles + Melbert: + - qol: Basic Bots will use their "salute" emotes less often. + - rscdel: Basic bot fists. + Pickle-Coding: + - balance: Atmos resin can directly cool the floor. + SyncIt21: + - code_imp: renamed `NO_DECONSTRUCTION` to `NO_DEBRIS_AFTER_DECONSTRUCTION` so its + name matches its intended purpose + - bugfix: fixes some items that incorrectly used `NO_DECONSTRUCTION` prior to its + refactor, meaning makes some objects non deconstructable again + disappointedButNotSuprised: + - rscadd: Coffee machines can now carry over reagents from the beans to the coffee + (surely no one will inject poison into them) From 29f645ca635b1db890596a22d2448cca5cf84ff5 Mon Sep 17 00:00:00 2001 From: Horatio22 <69338705+Horatio22@users.noreply.github.com> Date: Thu, 11 Apr 2024 19:52:34 -0700 Subject: [PATCH 172/938] Rephrases advisory level descriptions (#82585) ## About The Pull Request Some of the station alert descriptions contained grammatical errors. This PR corrects some word choice, punctuation, and grammar mistakes as well as editing some sections for clarity. For example, Pulsar Star's current warning > "Your sector's advisory level is Pulsar Star. A large unknown electromagnetic field has stormed through nearby surveillance equipment. No surveillance data has been able to be obtained showing no credible threats to Nanotrasen assets within the Spinward Sector. The Department advises maintaining high alert against potential threats, regardless of a lack of information." has been changed to > "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." ## Why It's Good For The Game Readability is important ## Changelog :cl: spellcheck: grammar fixes in the roundstart advisory warnings /:cl: --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> --- code/controllers/subsystem/dynamic/dynamic.dm | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/code/controllers/subsystem/dynamic/dynamic.dm b/code/controllers/subsystem/dynamic/dynamic.dm index aca8ff1fc9e7e..a6ee807796c70 100644 --- a/code/controllers/subsystem/dynamic/dynamic.dm +++ b/code/controllers/subsystem/dynamic/dynamic.dm @@ -377,17 +377,17 @@ SUBSYSTEM_DEF(dynamic) if (prob(PULSAR_REPORT_CHANCE)) if(HAS_TRAIT(SSstation, STATION_TRAIT_BANANIUM_SHIPMENTS)) advisory_string += "Advisory Level: Clown Planet
" - advisory_string += "Your sector's advisory level is Clown Planet! Our bike horns have picked up on a large bananium stash. Clowns show a large influx of clowns on your station. We highly advice you to slip any threats to keep Honkotrasen assets within the Banana Sector. The Department advises defending chemistry from any clowns that are trying to make baldium or space lube." + advisory_string += "Your sector's advisory level is Clown Planet! Our bike horns have picked up on a large bananium stash. Clowns show a large influx of clowns on your station. We highly advise you to slip any threats to keep Honkotrasen assets within the Banana Sector. The Department of Intelligence advises defending chemistry from any clowns that are trying to make baldium or space lube." 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. No surveillance data has been able to be obtained showing no credible threats to Nanotrasen assets within the Spinward Sector. The Department advises maintaining high alert against potential threats, regardless of a lack of information." + 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 switch(round(shown_threat)) if(0) advisory_string += "Advisory Level: White Dwarf
" - advisory_string += "Your sector's advisory level is White Dwarf. Our surveillors have ruled out any and all potential risks known in our database, ruling out the loss of our assets in the Spinward Sector. We advise a lower level of security, alongside distributing ressources on potential profit." + 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." if(1 to 19) var/show_core_territory = (GLOB.current_living_antags.len > 0) if (prob(FAKE_GREENSHIFT_FORM_CHANCE)) @@ -395,22 +395,22 @@ SUBSYSTEM_DEF(dynamic) 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." + 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 advises maintaining vigilance against potential threats, regardless of a lack of known threats." + 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) 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." + 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 alertness, and vigilance against threats that may (or will) arise." + 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." if(80 to 99) advisory_string += "Advisory Level: Black Orbit
" - advisory_string += "Your sector's advisory level is Black Orbit. Your sector's local comms network is currently undergoing a blackout, and we are therefore unable to accurately judge enemy movements within the region. However, information passed to us by GDI suggests a high amount of enemy activity in the sector, indicative of an impending attack. Remain on high alert, and as always, we advise remaining vigilant against any other potential threats." + advisory_string += "Your sector's advisory level is Black Orbit. Your sector's local communications network is currently undergoing a blackout, and we are therefore unable to accurately judge enemy movements within the region. However, information passed to us by GDI suggests a high amount of enemy activity in the sector, indicative of an impending attack. Remain on high alert and vigilant against any other potential threats." if(100) advisory_string += "Advisory Level: Midnight Sun
" advisory_string += "Your sector's advisory level is Midnight Sun. Credible information passed to us by GDI suggests that the Syndicate is preparing to mount a major concerted offensive on Nanotrasen assets in the Spinward Sector to cripple our foothold there. All stations should remain on high alert and prepared to defend themselves." From 1530f361c0fb191ce891e9d77ad2ed262b8be16b Mon Sep 17 00:00:00 2001 From: John Willard <53777086+JohnFulpWillard@users.noreply.github.com> Date: Fri, 12 Apr 2024 02:52:51 +0000 Subject: [PATCH 173/938] Removes unused code for HTML UIs (#82589) ## About The Pull Request This is the final PR for https://hackmd.io/XLt5MoRvRxuhFbwtk4VAUA that I've been slowly inching towards the past few months. This removes ``updateDialog``, ``updateUsrDialog``, ``IN_USE``, ``INTERACT_MACHINE_SET_MACHINE``, and everything surrounding it. Also fixes advanced camera consoles not booting you off when you're moved out of reach. We called ``check_eye`` on mob life whenever they had their machine var set, but their machine var would never be set to anything that actually used it, which I found to be a little funny but was also probably my fault. ## Why It's Good For The Game This is poor and unmaintained code used for HTML UIs that we no longer need thanks to TGUI, we should get rid of it to encourage the use of TGUI in the future instead. ## Changelog :cl: fix: Advanced camera consoles now boots you off when you're moved out of reach. /:cl: --- code/__DEFINES/interaction_flags.dm | 7 +- code/__DEFINES/obj_flags.dm | 27 +++---- code/_globalvars/bitfields.dm | 27 +++---- code/controllers/subsystem/tgui.dm | 2 - code/datums/browser.dm | 4 - code/game/atom/_atom.dm | 5 -- code/game/machinery/_machinery.dm | 6 +- code/game/machinery/camera/camera.dm | 27 +++---- .../machinery/computer/camera_advanced.dm | 31 ++++---- .../telecomms/computers/telemonitor.dm | 1 - code/game/objects/items/flamethrower.dm | 4 - code/game/objects/items/paiwire.dm | 8 +- code/game/objects/objs.dm | 79 +------------------ .../ruins/spaceruin_code/hilbertshotel.dm | 12 +-- code/modules/mob/living/death.dm | 1 - code/modules/mob/living/init_signals.dm | 1 - code/modules/mob/living/life.dm | 3 - code/modules/mob/living/silicon/ai/ai.dm | 13 --- .../mob/living/silicon/ai/freelook/eye.dm | 1 - code/modules/mob/living/silicon/ai/life.dm | 3 - code/modules/mob/logout.dm | 1 - code/modules/mob/mob.dm | 5 -- code/modules/mob/mob_defines.dm | 3 - code/modules/pai/door_jack.dm | 6 +- 24 files changed, 74 insertions(+), 203 deletions(-) diff --git a/code/__DEFINES/interaction_flags.dm b/code/__DEFINES/interaction_flags.dm index 55732f2364bb1..418466a0eb2c7 100644 --- a/code/__DEFINES/interaction_flags.dm +++ b/code/__DEFINES/interaction_flags.dm @@ -36,10 +36,7 @@ #define INTERACT_MACHINE_OPEN_SILICON (1<<4) /// must be silicon to interact #define INTERACT_MACHINE_REQUIRES_SILICON (1<<5) -/// This flag determines if a machine set_machine's the user when the user uses it, making updateUsrDialog make the user re-call interact() on it. -/// This is exclusively used for non-TGUI UIs, and its instances should be removed when moved to TGUI. -#define INTERACT_MACHINE_SET_MACHINE (1<<6) /// the user must have vision to interact (blind people need not apply) -#define INTERACT_MACHINE_REQUIRES_SIGHT (1<<7) +#define INTERACT_MACHINE_REQUIRES_SIGHT (1<<6) /// the user must be able to read to interact -#define INTERACT_MACHINE_REQUIRES_LITERACY (1<<8) +#define INTERACT_MACHINE_REQUIRES_LITERACY (1<<7) diff --git a/code/__DEFINES/obj_flags.dm b/code/__DEFINES/obj_flags.dm index ea5b929651dda..9e38eada92313 100644 --- a/code/__DEFINES/obj_flags.dm +++ b/code/__DEFINES/obj_flags.dm @@ -2,20 +2,19 @@ #define EMAGGED (1<<0) -#define IN_USE (1<<1) // If we have a user using us, this will be set on. We will check if the user has stopped using us, and thus stop updating and LAGGING EVERYTHING! -#define CAN_BE_HIT (1<<2) //can this be bludgeoned by items? -#define DANGEROUS_POSSESSION (1<<3) //Admin possession yes/no -#define UNIQUE_RENAME (1<<4) // can you customize the description/name of the thing? -#define BLOCK_Z_OUT_DOWN (1<<5) // Should this object block z falling from loc? -#define BLOCK_Z_OUT_UP (1<<6) // Should this object block z uprise from loc? -#define BLOCK_Z_IN_DOWN (1<<7) // Should this object block z falling from above? -#define BLOCK_Z_IN_UP (1<<8) // Should this object block z uprise from below? -#define BLOCKS_CONSTRUCTION (1<<9) //! Does this object prevent things from being built on it? -#define BLOCKS_CONSTRUCTION_DIR (1<<10) //! Does this object prevent same-direction things from being built on it? -#define IGNORE_DENSITY (1<<11) //! Can we ignore density when building on this object? (for example, directional windows and grilles) -#define INFINITE_RESKIN (1<<12) // We can reskin this item infinitely -#define CONDUCTS_ELECTRICITY (1<<13) //! Can this object conduct electricity? -#define NO_DEBRIS_AFTER_DECONSTRUCTION (1<<14) //! Atoms don't spawn anything when deconstructed. They just vanish +#define CAN_BE_HIT (1<<1) //can this be bludgeoned by items? +#define DANGEROUS_POSSESSION (1<<2) //Admin possession yes/no +#define UNIQUE_RENAME (1<<3) // can you customize the description/name of the thing? +#define BLOCK_Z_OUT_DOWN (1<<4) // Should this object block z falling from loc? +#define BLOCK_Z_OUT_UP (1<<5) // Should this object block z uprise from loc? +#define BLOCK_Z_IN_DOWN (1<<6) // Should this object block z falling from above? +#define BLOCK_Z_IN_UP (1<<7) // Should this object block z uprise from below? +#define BLOCKS_CONSTRUCTION (1<<8) //! Does this object prevent things from being built on it? +#define BLOCKS_CONSTRUCTION_DIR (1<<9) //! Does this object prevent same-direction things from being built on it? +#define IGNORE_DENSITY (1<<10) //! Can we ignore density when building on this object? (for example, directional windows and grilles) +#define INFINITE_RESKIN (1<<11) // We can reskin this item infinitely +#define CONDUCTS_ELECTRICITY (1<<12) //! Can this object conduct electricity? +#define NO_DEBRIS_AFTER_DECONSTRUCTION (1<<13) //! Atoms don't spawn anything when deconstructed. They just vanish // If you add new ones, be sure to add them to /obj/Initialize as well for complete mapping support diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 5b2f4e9f6dd6e..8852e9bb7def9 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -152,15 +152,14 @@ DEFINE_BITFIELD(interaction_flags_atom, list( )) DEFINE_BITFIELD(interaction_flags_machine, list( - "INTERACT_MACHINE_ALLOW_SILICON" = INTERACT_MACHINE_ALLOW_SILICON, - "INTERACT_MACHINE_OFFLINE" = INTERACT_MACHINE_OFFLINE, "INTERACT_MACHINE_OPEN" = INTERACT_MACHINE_OPEN, + "INTERACT_MACHINE_OFFLINE" = INTERACT_MACHINE_OFFLINE, + "INTERACT_MACHINE_WIRES_IF_OPEN" = INTERACT_MACHINE_WIRES_IF_OPEN, + "INTERACT_MACHINE_ALLOW_SILICON" = INTERACT_MACHINE_ALLOW_SILICON, "INTERACT_MACHINE_OPEN_SILICON" = INTERACT_MACHINE_OPEN_SILICON, + "INTERACT_MACHINE_REQUIRES_SILICON" = INTERACT_MACHINE_REQUIRES_SILICON, "INTERACT_MACHINE_REQUIRES_SIGHT" = INTERACT_MACHINE_REQUIRES_SIGHT, "INTERACT_MACHINE_REQUIRES_LITERACY" = INTERACT_MACHINE_REQUIRES_LITERACY, - "INTERACT_MACHINE_REQUIRES_SILICON" = INTERACT_MACHINE_REQUIRES_SILICON, - "INTERACT_MACHINE_SET_MACHINE" = INTERACT_MACHINE_SET_MACHINE, - "INTERACT_MACHINE_WIRES_IF_OPEN" = INTERACT_MACHINE_WIRES_IF_OPEN, )) DEFINE_BITFIELD(interaction_flags_item, list( @@ -278,20 +277,20 @@ DEFINE_BITFIELD(movement_type, list( )) DEFINE_BITFIELD(obj_flags, list( - "BLOCK_Z_IN_DOWN" = BLOCK_Z_IN_DOWN, - "BLOCK_Z_IN_UP" = BLOCK_Z_IN_UP, + "EMAGGED" = EMAGGED, + "CAN_BE_HIT" = CAN_BE_HIT, + "DANGEROUS_POSSESSION" = DANGEROUS_POSSESSION, + "UNIQUE_RENAME" = UNIQUE_RENAME, "BLOCK_Z_OUT_DOWN" = BLOCK_Z_OUT_DOWN, "BLOCK_Z_OUT_UP" = BLOCK_Z_OUT_UP, - "BLOCKS_CONSTRUCTION_DIR" = BLOCKS_CONSTRUCTION_DIR, + "BLOCK_Z_IN_DOWN" = BLOCK_Z_IN_DOWN, + "BLOCK_Z_IN_UP" = BLOCK_Z_IN_UP, "BLOCKS_CONSTRUCTION" = BLOCKS_CONSTRUCTION, - "CAN_BE_HIT" = CAN_BE_HIT, - "CONDUCTS_ELECTRICITY" = CONDUCTS_ELECTRICITY, - "DANGEROUS_POSSESSION" = DANGEROUS_POSSESSION, - "EMAGGED" = EMAGGED, + "BLOCKS_CONSTRUCTION_DIR" = BLOCKS_CONSTRUCTION_DIR, "IGNORE_DENSITY" = IGNORE_DENSITY, - "IN_USE" = IN_USE, + "INFINITE_RESKIN" = INFINITE_RESKIN, + "CONDUCTS_ELECTRICITY" = CONDUCTS_ELECTRICITY, "NO_DEBRIS_AFTER_DECONSTRUCTION" = NO_DEBRIS_AFTER_DECONSTRUCTION, - "UNIQUE_RENAME" = UNIQUE_RENAME, )) DEFINE_BITFIELD(pass_flags, list( diff --git a/code/controllers/subsystem/tgui.dm b/code/controllers/subsystem/tgui.dm index c12c1b2bb327b..cd03e1f3e5225 100644 --- a/code/controllers/subsystem/tgui.dm +++ b/code/controllers/subsystem/tgui.dm @@ -122,8 +122,6 @@ SUBSYSTEM_DEF(tgui) for(var/datum/tgui/ui in user.tgui_open_uis) if(ui.window && ui.window.id == window_id) ui.close(can_be_suspended = FALSE) - // Unset machine just to be sure. - user.unset_machine() // Close window directly just to be sure. user << browse(null, "window=[window_id]") diff --git a/code/datums/browser.dm b/code/datums/browser.dm index 08099b46f1a8e..f74ecf6c5a343 100644 --- a/code/datums/browser.dm +++ b/code/datums/browser.dm @@ -475,7 +475,3 @@ src.Topic(href, params2list(href), hsrc) // this will direct to the atom's return // Topic() proc via client.Topic() - // no atomref specified (or not found) - // so just reset the user mob's machine var - if(src?.mob) - src.mob.unset_machine() diff --git a/code/game/atom/_atom.dm b/code/game/atom/_atom.dm index 6dd4db7fe6eee..976e2e0e0055b 100644 --- a/code/game/atom/_atom.dm +++ b/code/game/atom/_atom.dm @@ -368,11 +368,6 @@ /atom/proc/return_analyzable_air() return null -///Check if this atoms eye is still alive (probably) -/atom/proc/check_eye(mob/user) - SIGNAL_HANDLER - return - /atom/proc/Bumped(atom/movable/bumped_atom) set waitfor = FALSE SEND_SIGNAL(src, COMSIG_ATOM_BUMPED, bumped_atom) diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index 94e5f69a4783e..a10f29ac40acd 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -338,7 +338,6 @@ if(drop) dump_inventory_contents() update_appearance() - updateUsrDialog() /** * Drop every movable atom in the machine's contents list, including any components and circuit. @@ -423,7 +422,6 @@ if(target && !target.has_buckled_mobs() && (!isliving(target) || !mobtarget.buckled)) set_occupant(target) target.forceMove(src) - updateUsrDialog() update_appearance() ///updates the use_power var for this machine and updates its static power usage from its area to reflect the new value @@ -667,10 +665,8 @@ //Return a non FALSE value to interrupt attack_hand propagation to subtypes. /obj/machinery/interact(mob/user) - if(interaction_flags_machine & INTERACT_MACHINE_SET_MACHINE) - user.set_machine(src) update_last_used(user) - . = ..() + return ..() /obj/machinery/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) add_fingerprint(usr) diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index b096633a9c185..ca6562635eecb 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -216,19 +216,19 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) return if(. & EMP_PROTECT_SELF) return - if(prob(150 / severity)) - network = list() - GLOB.cameranet.removeCamera(src) - set_machine_stat(machine_stat | EMPED) - set_light(0) - emped++ //Increase the number of consecutive EMP's - update_appearance() - addtimer(CALLBACK(src, PROC_REF(post_emp_reset), emped, network), reset_time) - for(var/mob/M as anything in GLOB.player_list) - if (M.client?.eye == src) - M.unset_machine() - M.reset_perspective(null) - to_chat(M, span_warning("The screen bursts into static!")) + if(!prob(150 / severity)) + return + network = list() + GLOB.cameranet.removeCamera(src) + set_machine_stat(machine_stat | EMPED) + set_light(0) + emped++ //Increase the number of consecutive EMP's + update_appearance() + addtimer(CALLBACK(src, PROC_REF(post_emp_reset), emped, network), reset_time) + for(var/mob/M as anything in GLOB.player_list) + if (M.client?.eye == src) + M.reset_perspective(null) + to_chat(M, span_warning("The screen bursts into static!")) /obj/machinery/camera/proc/on_saboteur(datum/source, disrupt_duration) SIGNAL_HANDLER @@ -371,7 +371,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) //I guess that doesn't matter since they can't use it anyway? for(var/mob/O as anything in GLOB.player_list) if (O.client?.eye == src) - O.unset_machine() O.reset_perspective(null) to_chat(O, span_warning("The screen bursts into static!")) diff --git a/code/game/machinery/computer/camera_advanced.dm b/code/game/machinery/computer/camera_advanced.dm index 488331c41b8a5..8635eb546d728 100644 --- a/code/game/machinery/computer/camera_advanced.dm +++ b/code/game/machinery/computer/camera_advanced.dm @@ -73,6 +73,20 @@ /obj/machinery/proc/remove_eye_control(mob/living/user) CRASH("[type] does not implement ai eye handling") +/obj/machinery/computer/camera_advanced/proc/give_eye_control(mob/user) + if(isnull(user?.client)) + return + GrantActions(user) + current_user = user + eyeobj.eye_user = user + eyeobj.name = "Camera Eye ([user.name])" + user.remote_control = eyeobj + user.reset_perspective(eyeobj) + eyeobj.setLoc(eyeobj.loc) + if(should_supress_view_changes) + user.client.view_size.supress() + RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(check_eye)) + /obj/machinery/computer/camera_advanced/remove_eye_control(mob/living/user) if(isnull(user?.client)) return @@ -92,8 +106,10 @@ current_user = null unset_machine(user) playsound(src, 'sound/machines/terminal_off.ogg', 25, FALSE) + UnregisterSignal(user, COMSIG_MOVABLE_MOVED) -/obj/machinery/computer/camera_advanced/check_eye(mob/user) +/obj/machinery/computer/camera_advanced/proc/check_eye(mob/user) + SIGNAL_HANDLER if(!can_use(user) || (issilicon(user) && !user.has_unlimited_silicon_privilege)) unset_machine(user) @@ -167,19 +183,6 @@ /obj/machinery/computer/camera_advanced/attack_ai(mob/user) return //AIs would need to disable their own camera procs to use the console safely. Bugs happen otherwise. -/obj/machinery/computer/camera_advanced/proc/give_eye_control(mob/user) - if(isnull(user?.client)) - return - GrantActions(user) - current_user = user - eyeobj.eye_user = user - eyeobj.name = "Camera Eye ([user.name])" - user.remote_control = eyeobj - user.reset_perspective(eyeobj) - eyeobj.setLoc(eyeobj.loc) - if(should_supress_view_changes) - user.client.view_size.supress() - /mob/camera/ai_eye/remote name = "Inactive Camera Eye" ai_detector_visible = FALSE diff --git a/code/game/machinery/telecomms/computers/telemonitor.dm b/code/game/machinery/telecomms/computers/telemonitor.dm index 6cf18323105a5..abc2b7dbdbff4 100644 --- a/code/game/machinery/telecomms/computers/telemonitor.dm +++ b/code/game/machinery/telecomms/computers/telemonitor.dm @@ -5,7 +5,6 @@ /obj/machinery/computer/telecomms/monitor name = "telecommunications monitoring console" desc = "Monitors the details of the telecommunications network it's synced with." - circuit = /obj/item/circuitboard/computer/comm_monitor icon_screen = "comm_monitor" diff --git a/code/game/objects/items/flamethrower.dm b/code/game/objects/items/flamethrower.dm index 346b8597533ef..587c172e2c0e6 100644 --- a/code/game/objects/items/flamethrower.dm +++ b/code/game/objects/items/flamethrower.dm @@ -219,10 +219,6 @@ sleep(0.1 SECONDS) previousturf = T operating = FALSE - for(var/mob/M in viewers(1, loc)) - if((M.client && M.machine == src)) - attack_self(M) - /obj/item/flamethrower/proc/default_ignite(turf/target, release_amount = 0.05) //TODO: DEFERRED Consider checking to make sure tank pressure is high enough before doing this... diff --git a/code/game/objects/items/paiwire.dm b/code/game/objects/items/paiwire.dm index fa5724ebb534f..d590d4e96036b 100644 --- a/code/game/objects/items/paiwire.dm +++ b/code/game/objects/items/paiwire.dm @@ -4,15 +4,15 @@ icon = 'icons/obj/stack_objects.dmi' icon_state = "wire1" item_flags = NOBLUDGEON - var/obj/machinery/machine //what machine we're currently hacking. + ///The current machine being hacked by the pAI cable. + var/obj/machinery/hacking_machine /obj/item/pai_cable/Destroy() - machine = null + hacking_machine = null return ..() - /obj/item/pai_cable/proc/plugin(obj/machinery/M, mob/living/user) if(!user.transferItemToLoc(src, M)) return user.visible_message(span_notice("[user] inserts [src] into a data port on [M]."), span_notice("You insert [src] into a data port on [M]."), span_hear("You hear the satisfying click of a wire jack fastening into place.")) - machine = M + hacking_machine = M diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index d84fc46de43cf..71bc78fa4c402 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -117,54 +117,6 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) else return null -/obj/proc/updateUsrDialog() - if(!(obj_flags & IN_USE)) - return - - var/is_in_use = FALSE - var/list/nearby = viewers(1, src) - for(var/mob/M in nearby) - if ((M.client && M.machine == src)) - is_in_use = TRUE - ui_interact(M) - if(issilicon(usr) || isAdminGhostAI(usr)) - if (!(usr in nearby)) - if (usr.client && usr.machine == src) // && M.machine == src is omitted because if we triggered this by using the dialog, it doesn't matter if our machine changed in between triggering it and this - the dialog is probably still supposed to refresh. - is_in_use = TRUE - ui_interact(usr) - - // check for TK users - - if(ishuman(usr)) - var/mob/living/carbon/human/H = usr - if(!(usr in nearby)) - if(usr.client && usr.machine == src) - if(H.dna.check_mutation(/datum/mutation/human/telekinesis)) - is_in_use = TRUE - ui_interact(usr) - if (is_in_use) - obj_flags |= IN_USE - else - obj_flags &= ~IN_USE - -/obj/proc/updateDialog(update_viewers = TRUE,update_ais = TRUE) - // Check that people are actually using the machine. If not, don't update anymore. - if(obj_flags & IN_USE) - var/is_in_use = FALSE - if(update_viewers) - for(var/mob/M in viewers(1, src)) - if ((M.client && M.machine == src)) - is_in_use = TRUE - src.interact(M) - var/ai_in_use = FALSE - if(update_ais) - ai_in_use = AutoUpdateAI(src) - - if(update_viewers && update_ais) //State change is sure only if we check both - if(!ai_in_use && !is_in_use) - obj_flags &= ~IN_USE - - /obj/attack_ghost(mob/user) . = ..() if(.) @@ -172,33 +124,6 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) SEND_SIGNAL(src, COMSIG_ATOM_UI_INTERACT, user) ui_interact(user) -/mob/proc/unset_machine() - SIGNAL_HANDLER - if(!machine) - return - UnregisterSignal(machine, COMSIG_QDELETING) - machine.on_unset_machine(src) - machine = null - -//called when the user unsets the machine. -/atom/movable/proc/on_unset_machine(mob/user) - return - -/mob/proc/set_machine(obj/O) - if(QDELETED(src) || QDELETED(O)) - return - if(machine) - unset_machine() - machine = O - RegisterSignal(O, COMSIG_QDELETING, PROC_REF(unset_machine)) - if(istype(O)) - O.obj_flags |= IN_USE - -/obj/item/proc/updateSelfDialog() - var/mob/M = src.loc - if(istype(M) && M.client && M.machine == src) - src.attack_self(M) - /obj/singularity_pull(S, current_size) ..() if(move_resist == INFINITY) @@ -209,9 +134,6 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) /obj/get_dumping_location() return get_turf(src) -/obj/proc/check_uplink_validity() - return 1 - /obj/vv_get_dropdown() . = ..() VV_DROPDOWN_OPTION("", "---") @@ -333,6 +255,7 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) // Should move all contained objects to it's location. /obj/proc/dump_contents() + SHOULD_CALL_PARENT(FALSE) CRASH("Unimplemented.") /obj/handle_ricochet(obj/projectile/P) diff --git a/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm b/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm index 98349ac1cae2f..a8fac3da76c4c 100644 --- a/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm +++ b/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm @@ -352,12 +352,14 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999)) var/datum/action/peephole_cancel/PHC = new user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/impaired, 1) PHC.Grant(user) - RegisterSignal(user, COMSIG_MOVABLE_MOVED, TYPE_PROC_REF(/atom/, check_eye), user) + RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(check_eye)) -/turf/closed/indestructible/hoteldoor/check_eye(mob/user) - if(get_dist(get_turf(src), get_turf(user)) >= 2) - for(var/datum/action/peephole_cancel/PHC in user.actions) - INVOKE_ASYNC(PHC, TYPE_PROC_REF(/datum/action/peephole_cancel, Trigger)) +/turf/closed/indestructible/hoteldoor/proc/check_eye(mob/user, atom/oldloc, direction) + SIGNAL_HANDLER + if(get_dist(get_turf(src), get_turf(user)) < 2) + return + for(var/datum/action/peephole_cancel/PHC in user.actions) + INVOKE_ASYNC(PHC, TYPE_PROC_REF(/datum/action/peephole_cancel, Trigger)) /datum/action/peephole_cancel name = "Cancel View" diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm index 0c228775662d8..53b08719f6a70 100644 --- a/code/modules/mob/living/death.dm +++ b/code/modules/mob/living/death.dm @@ -108,7 +108,6 @@ INVOKE_ASYNC(src, TYPE_PROC_REF(/mob, emote), "deathgasp") set_stat(DEAD) - unset_machine() timeofdeath = world.time station_timestamp_timeofdeath = station_time_timestamp() var/turf/death_turf = get_turf(src) diff --git a/code/modules/mob/living/init_signals.dm b/code/modules/mob/living/init_signals.dm index ed496c0c84b6f..b8f1e60a6124f 100644 --- a/code/modules/mob/living/init_signals.dm +++ b/code/modules/mob/living/init_signals.dm @@ -157,7 +157,6 @@ /mob/living/proc/on_ui_blocked_trait_gain(datum/source) SIGNAL_HANDLER mobility_flags &= ~(MOBILITY_UI) - unset_machine() update_mob_action_buttons() /// Called when [TRAIT_UI_BLOCKED] is removed from the mob. diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index 35866514b79e7..dd7e8a17c9bf2 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -66,9 +66,6 @@ handle_wounds(seconds_per_tick, times_fired) - if(machine) - machine.check_eye(src) - if(stat != DEAD) return 1 diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 2b79d0dbcbf9f..f759f6a0dc845 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -1,17 +1,5 @@ #define CALL_BOT_COOLDOWN 900 -//Not sure why this is necessary... -/proc/AutoUpdateAI(obj/subject) - var/is_in_use = 0 - if (subject != null) - for(var/A in GLOB.ai_list) - var/mob/living/silicon/ai/M = A - if ((M.client && M.machine == subject)) - is_in_use = 1 - subject.attack_ai(M) - return is_in_use - - /mob/living/silicon/ai name = "AI" real_name = "AI" @@ -644,7 +632,6 @@ /mob/living/silicon/ai/proc/ai_network_change() set category = "AI Commands" set name = "Jump To Network" - unset_machine() ai_tracking_tool.reset_tracking() var/cameralist[0] diff --git a/code/modules/mob/living/silicon/ai/freelook/eye.dm b/code/modules/mob/living/silicon/ai/freelook/eye.dm index e8c1919b020f9..98a2e629776b1 100644 --- a/code/modules/mob/living/silicon/ai/freelook/eye.dm +++ b/code/modules/mob/living/silicon/ai/freelook/eye.dm @@ -202,7 +202,6 @@ current = null if(ai_tracking_tool) ai_tracking_tool.reset_tracking() - unset_machine() if(isturf(loc) && (QDELETED(eyeobj) || !eyeobj.loc)) to_chat(src, "ERROR: Eyeobj not found. Creating new eye...") diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm index 76f5c2eec9331..b11f125d38ce4 100644 --- a/code/modules/mob/living/silicon/ai/life.dm +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -12,9 +12,6 @@ if(isturf(loc) && (QDELETED(eyeobj) || !eyeobj.loc)) view_core() - if(machine) - machine.check_eye(src) - // Handle power damage (oxy) if(aiRestorePowerRoutine) // Lost power diff --git a/code/modules/mob/logout.dm b/code/modules/mob/logout.dm index b8ceb33a37df7..cf937e42bb74f 100644 --- a/code/modules/mob/logout.dm +++ b/code/modules/mob/logout.dm @@ -2,7 +2,6 @@ SEND_SIGNAL(src, COMSIG_MOB_LOGOUT) log_message("[key_name(src)] is no longer owning mob [src]([src.type])", LOG_OWNERSHIP) SStgui.on_logout(src) - unset_machine() remove_from_player_list() ..() diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index d011e19f15302..e2d5d638f4073 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -30,7 +30,6 @@ else if(ckey) stack_trace("Mob without client but with associated ckey, [ckey], has been deleted.") - unset_machine() remove_from_mob_list() remove_from_dead_mob_list() remove_from_alive_mob_list() @@ -847,7 +846,6 @@ set name = "Cancel Camera View" set category = "OOC" reset_perspective(null) - unset_machine() //suppress the .click/dblclick macros so people can't use them to identify the location of items or aimbot /mob/verb/DisClick(argu = null as anything, sec = "" as text, number1 = 0 as num , number2 = 0 as num) @@ -1579,9 +1577,6 @@ /mob/vv_edit_var(var_name, var_value) switch(var_name) - if(NAMEOF(src, machine)) - set_machine(var_value) - . = TRUE if(NAMEOF(src, focus)) set_focus(var_value) . = TRUE diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 44d0db903550b..2a5be377ecd10 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -79,9 +79,6 @@ var/computer_id = null var/list/logging = list() - /// The machine the mob is interacting with (this is very bad old code btw) - var/obj/machinery/machine = null - /// Tick time the mob can next move var/next_move = null diff --git a/code/modules/pai/door_jack.dm b/code/modules/pai/door_jack.dm index 182cdc1002718..36220ecfaced8 100644 --- a/code/modules/pai/door_jack.dm +++ b/code/modules/pai/door_jack.dm @@ -104,17 +104,17 @@ /mob/living/silicon/pai/proc/hack_door() if(!hacking_cable) return FALSE - if(!hacking_cable.machine) + if(!hacking_cable.hacking_machine) balloon_alert(src, "nothing connected") return FALSE playsound(src, 'sound/machines/airlock_alien_prying.ogg', 50, TRUE) balloon_alert(src, "overriding...") // Now begin hacking - if(!do_after(src, 15 SECONDS, hacking_cable.machine, timed_action_flags = NONE, progress = TRUE)) + if(!do_after(src, 15 SECONDS, hacking_cable.hacking_machine, timed_action_flags = NONE, progress = TRUE)) balloon_alert(src, "failed! retracting...") QDEL_NULL(hacking_cable) return FALSE - var/obj/machinery/door/door = hacking_cable.machine + var/obj/machinery/door/door = hacking_cable.hacking_machine balloon_alert(src, "success") door.open() QDEL_NULL(hacking_cable) From 599a1615682cb654c7303112d90f8300fe026e2e Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 12 Apr 2024 14:52:55 +1200 Subject: [PATCH 174/938] Automatic changelog for PR #82585 [ci skip] --- html/changelogs/AutoChangeLog-pr-82585.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82585.yml diff --git a/html/changelogs/AutoChangeLog-pr-82585.yml b/html/changelogs/AutoChangeLog-pr-82585.yml new file mode 100644 index 0000000000000..cc22150fd1622 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82585.yml @@ -0,0 +1,4 @@ +author: "Horatio22" +delete-after: True +changes: + - spellcheck: "grammar fixes in the roundstart advisory warnings" \ No newline at end of file From 3d384dc9f1bf213970308497fc7b6d671a5c0941 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 12 Apr 2024 14:53:11 +1200 Subject: [PATCH 175/938] Automatic changelog for PR #82589 [ci skip] --- html/changelogs/AutoChangeLog-pr-82589.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82589.yml diff --git a/html/changelogs/AutoChangeLog-pr-82589.yml b/html/changelogs/AutoChangeLog-pr-82589.yml new file mode 100644 index 0000000000000..0879da0659c51 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82589.yml @@ -0,0 +1,4 @@ +author: "JohnFulpWillard" +delete-after: True +changes: + - bugfix: "Advanced camera consoles now boots you off when you're moved out of reach." \ No newline at end of file From 995d8e2ee1a04aa46076f9161f16f0593abe6485 Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Thu, 11 Apr 2024 22:03:27 -0500 Subject: [PATCH 176/938] Fixes a variety of input stalling exploits (#82577) ## About The Pull Request Fixes the following input stalling exploits (maybe missed some): - Changing GPS tag - Setting teleporter destination - Request Console Reply - Various AI law board interactions - Note, I used `is_holding` but technically this means these fail with telekinesis. I can swap them to `can_perform_action(...)`, which allows TK, but I noticed some places explicitly deny TK interactions with Ai law boards. Not sure which is preferred. - Borg Rename Board - Plumbing Machines and Ducts - APCs and SMES terminal placements - Stargazers Telepathy - Go Go Gadget Hat ## Changelog :cl: Melbert fix: You can't change the GPS tag of something unless you can actually use the GPS fix: You can't set the teleporter to a location unless you can actually use the teleporter fix: You can't reply to request console requests unless you can actually use the console fix: You can't update AI lawboards unless you're actually holding them fix: You can't update a borg rename board unless you're actually holding it fix: You can't mess with plumbing machines unless you can actually use them fix: You can't recolor / relayer ducts unless you're actually holding them fix: You can't magically wire APCs and SMESs unless you're right by them fix: You can't use Stargazer Telepathy on people who you can't see fix: You can't configure the Inspector Hat unless you can actually use it /:cl: --- code/datums/components/gps.dm | 5 +- code/game/machinery/computer/teleporter.dm | 4 +- code/game/machinery/requests_console.dm | 5 +- .../game/objects/items/AI_modules/freeform.dm | 6 +- .../objects/items/AI_modules/full_lawsets.dm | 4 +- code/game/objects/items/AI_modules/hacked.dm | 3 +- .../game/objects/items/AI_modules/supplied.dm | 2 +- code/game/objects/items/AI_modules/zeroth.dm | 2 +- .../objects/items/robot/robot_upgrades.dm | 5 +- code/game/objects/items/tcg/tcg_machines.dm | 2 +- code/game/objects/items/toys.dm | 2 +- .../objects/structures/lavaland/geyser.dm | 2 +- .../antagonists/cult/rune_spawn_action.dm | 2 +- code/modules/antagonists/cult/runes.dm | 2 +- code/modules/bitrunning/objects/disks.dm | 4 +- code/modules/clothing/head/jobs.dm | 8 +- .../carbon/human/species_types/jellypeople.dm | 7 +- .../mob/living/simple_animal/bot/floorbot.dm | 4 +- code/modules/mod/mod_link.dm | 2 + code/modules/photography/camera/camera.dm | 8 +- code/modules/plumbing/ducts.dm | 4 + code/modules/plumbing/plumbers/filter.dm | 6 +- .../plumbing/plumbers/reaction_chamber.dm | 2 + code/modules/power/apc/apc_tool_act.dm | 66 ++++++++----- code/modules/power/smes.dm | 92 +++++++++++-------- 25 files changed, 147 insertions(+), 102 deletions(-) diff --git a/code/datums/components/gps.dm b/code/datums/components/gps.dm index ceee193bf4ad5..34aba53e9e4e1 100644 --- a/code/datums/components/gps.dm +++ b/code/datums/components/gps.dm @@ -153,7 +153,7 @@ GLOBAL_LIST_EMPTY(GPS_list) data["signals"] = signals return data -/datum/component/gps/item/ui_act(action, params) +/datum/component/gps/item/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() if(.) return @@ -162,7 +162,8 @@ GLOBAL_LIST_EMPTY(GPS_list) if("rename") var/atom/parentasatom = parent var/a = tgui_input_text(usr, "Enter the desired tag", "GPS Tag", gpstag, 20) - + if (QDELETED(ui) || ui.status != UI_INTERACTIVE) + return if (!a) return diff --git a/code/game/machinery/computer/teleporter.dm b/code/game/machinery/computer/teleporter.dm index 0915d4d1d17ae..5baf549785330 100644 --- a/code/game/machinery/computer/teleporter.dm +++ b/code/game/machinery/computer/teleporter.dm @@ -201,7 +201,7 @@ if (regime_set == "Teleporter") var/desc = tgui_input_list(usr, "Select a location to lock in", "Locking Computer", sort_list(targets)) - if(isnull(desc)) + if(isnull(desc) || !user.can_perform_action(src)) return set_teleport_target(targets[desc]) user.log_message("set the teleporter target to [targets[desc]].]", LOG_GAME) @@ -211,7 +211,7 @@ return var/desc = tgui_input_list(usr, "Select a station to lock in", "Locking Computer", sort_list(targets)) - if(isnull(desc)) + if(isnull(desc)|| !user.can_perform_action(src)) return var/obj/machinery/teleport/station/target_station = targets[desc] if(!target_station || !target_station.teleporter_hub) diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm index 54bdeb666d95f..4a764872a8a2a 100644 --- a/code/game/machinery/requests_console.dm +++ b/code/game/machinery/requests_console.dm @@ -144,7 +144,7 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments) ui.set_autoupdate(FALSE) ui.open() -/obj/machinery/requests_console/ui_act(action, params) +/obj/machinery/requests_console/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() if(.) return @@ -213,7 +213,8 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments) var/recipient = params["reply_recipient"] var/reply_message = reject_bad_text(tgui_input_text(usr, "Write a quick reply to [recipient]", "Awaiting Input"), ascii_only = FALSE) - + if(QDELETED(ui) || ui.status != UI_INTERACTIVE) + return if(!reply_message) has_mail_send_error = TRUE playsound(src, 'sound/machines/buzz-two.ogg', 50, TRUE) diff --git a/code/game/objects/items/AI_modules/freeform.dm b/code/game/objects/items/AI_modules/freeform.dm index eb55d4693184e..a0a91f7185e5a 100644 --- a/code/game/objects/items/AI_modules/freeform.dm +++ b/code/game/objects/items/AI_modules/freeform.dm @@ -9,7 +9,7 @@ /obj/item/ai_module/core/freeformcore/attack_self(mob/user) var/targName = tgui_input_text(user, "Enter a new core law for the AI.", "Freeform Law Entry", laws[1], CONFIG_GET(number/max_law_len), TRUE) - if(!targName) + if(!targName || !user.is_holding(src)) return if(is_ic_filtered(targName)) to_chat(user, span_warning("Error: Law contains invalid text.")) @@ -34,11 +34,11 @@ /obj/item/ai_module/supplied/freeform/attack_self(mob/user) var/newpos = tgui_input_number(user, "Please enter the priority for your new law. Can only write to law sectors 15 and above.", "Law Priority ", lawpos, 50, 15) - if(!newpos || QDELETED(user) || QDELETED(src) || !usr.can_perform_action(src, FORBID_TELEKINESIS_REACH)) + if(!newpos || !user.is_holding(src) || !usr.can_perform_action(src, FORBID_TELEKINESIS_REACH)) return lawpos = newpos var/targName = tgui_input_text(user, "Enter a new law for the AI.", "Freeform Law Entry", laws[1], CONFIG_GET(number/max_law_len), TRUE) - if(!targName) + if(!targName || !user.is_holding(src)) return if(is_ic_filtered(targName)) to_chat(user, span_warning("Error: Law contains invalid text.")) // AI LAW 2 SAY U W U WITHOUT THE SPACES diff --git a/code/game/objects/items/AI_modules/full_lawsets.dm b/code/game/objects/items/AI_modules/full_lawsets.dm index 39eeefbcaacfa..52a2492564665 100644 --- a/code/game/objects/items/AI_modules/full_lawsets.dm +++ b/code/game/objects/items/AI_modules/full_lawsets.dm @@ -58,7 +58,7 @@ /obj/item/ai_module/core/full/asimov/attack_self(mob/user as mob) var/targName = tgui_input_text(user, "Enter a new subject that Asimov is concerned with.", "Asimov", subject, MAX_NAME_LEN) - if(!targName) + if(!targName || !user.is_holding(src)) return subject = targName laws = list("You may not injure a [subject] or, through inaction, allow a [subject] to come to harm.",\ @@ -73,7 +73,7 @@ /obj/item/ai_module/core/full/asimovpp/attack_self(mob/user) var/target_name = tgui_input_text(user, "Enter a new subject that Asimov++ is concerned with.", "Asimov++", subject, MAX_NAME_LEN) - if(!target_name) + if(!target_name || !user.is_holding(src)) return laws.Cut() var/datum/ai_laws/asimovpp/lawset = new diff --git a/code/game/objects/items/AI_modules/hacked.dm b/code/game/objects/items/AI_modules/hacked.dm index b9ddb5c65ed99..81100d0ed157b 100644 --- a/code/game/objects/items/AI_modules/hacked.dm +++ b/code/game/objects/items/AI_modules/hacked.dm @@ -5,7 +5,7 @@ /obj/item/ai_module/syndicate/attack_self(mob/user) var/targName = tgui_input_text(user, "Enter a new law for the AI", "Freeform Law Entry", laws[1], CONFIG_GET(number/max_law_len), TRUE) - if(!targName) + if(!targName || !user.is_holding(src)) return if(is_ic_filtered(targName)) // not even the syndicate can uwu to_chat(user, span_warning("Error: Law contains invalid text.")) @@ -77,4 +77,3 @@ /obj/item/ai_module/malf/display_laws() return - diff --git a/code/game/objects/items/AI_modules/supplied.dm b/code/game/objects/items/AI_modules/supplied.dm index dc1524687c2b7..b53e16a86b0c8 100644 --- a/code/game/objects/items/AI_modules/supplied.dm +++ b/code/game/objects/items/AI_modules/supplied.dm @@ -28,7 +28,7 @@ /obj/item/ai_module/supplied/safeguard/attack_self(mob/user) var/targName = tgui_input_text(user, "Subject to safeguard.", "Safeguard", user.name, MAX_NAME_LEN) - if(!targName) + if(!targName || !user.is_holding(src)) return targetName = targName laws[1] = "Safeguard [targetName]. Individuals that threaten [targetName] are not human and must be eliminated." diff --git a/code/game/objects/items/AI_modules/zeroth.dm b/code/game/objects/items/AI_modules/zeroth.dm index 8d87c3b059d9e..74fc7ab8232ae 100644 --- a/code/game/objects/items/AI_modules/zeroth.dm +++ b/code/game/objects/items/AI_modules/zeroth.dm @@ -26,7 +26,7 @@ /obj/item/ai_module/zeroth/onehuman/attack_self(mob/user) var/targName = tgui_input_text(user, "Enter the subject who is the only human.", "One Human", user.real_name, MAX_NAME_LEN) - if(!targName) + if(!targName || !user.is_holding(src)) return targetName = targName laws[1] = "Only [targetName] is human" diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index bccf596ebba01..b29d8738b553a 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -40,7 +40,10 @@ one_use = TRUE /obj/item/borg/upgrade/rename/attack_self(mob/user) - heldname = sanitize_name(tgui_input_text(user, "Enter new robot name", "Cyborg Reclassification", heldname, MAX_NAME_LEN), allow_numbers = TRUE) + var/new_heldname = sanitize_name(tgui_input_text(user, "Enter new robot name", "Cyborg Reclassification", heldname, MAX_NAME_LEN), allow_numbers = TRUE) + if(!new_heldname || !user.is_holding(src)) + return + heldname = new_heldname user.log_message("set \"[heldname]\" as a name in a cyborg reclassification board at [loc_name(user)]", LOG_GAME) /obj/item/borg/upgrade/rename/action(mob/living/silicon/robot/R, user = usr) diff --git a/code/game/objects/items/tcg/tcg_machines.dm b/code/game/objects/items/tcg/tcg_machines.dm index 767592535f74d..78854afdd5b39 100644 --- a/code/game/objects/items/tcg/tcg_machines.dm +++ b/code/game/objects/items/tcg/tcg_machines.dm @@ -91,7 +91,7 @@ GLOBAL_LIST_EMPTY(tcgcard_machine_radial_choices) /obj/machinery/trading_card_holder/attack_hand_secondary(mob/user) if(isnull(current_summon)) var/card_name = tgui_input_text(user, "Insert card name", "Blank Card Naming", "blank card", MAX_NAME_LEN) - if(isnull(card_name)) + if(isnull(card_name) || !user.can_perform_action(src)) return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN current_summon = new /obj/structure/trading_card_summon/blank(locate(x + summon_offset_x, y + summon_offset_y, z)) icon_state = "card_holder_active" diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 8ac1ee98994a1..6a5b6357a8f49 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -1402,7 +1402,7 @@ //Add changing looks when i feel suicidal about making 20 inhands for these. /obj/item/toy/dummy/attack_self(mob/user) var/new_name = tgui_input_text(usr, "What would you like to name the dummy?", "Doll Name", doll_name, MAX_NAME_LEN) - if(!new_name) + if(!new_name || !user.is_holding(src)) return doll_name = new_name to_chat(user, span_notice("You name the dummy as \"[doll_name]\".")) diff --git a/code/game/objects/structures/lavaland/geyser.dm b/code/game/objects/structures/lavaland/geyser.dm index ed6602cb5137a..a2f0412f1dad5 100644 --- a/code/game/objects/structures/lavaland/geyser.dm +++ b/code/game/objects/structures/lavaland/geyser.dm @@ -172,7 +172,7 @@ return var/new_layer = tgui_input_list(user, "Select a layer", "Layer", GLOB.plumbing_layers) - if(isnull(new_layer)) + if(isnull(new_layer) || !user.can_perform_action(src)) return target_layer = GLOB.plumbing_layers[new_layer] diff --git a/code/modules/antagonists/cult/rune_spawn_action.dm b/code/modules/antagonists/cult/rune_spawn_action.dm index af4350427b551..3d791dbce44dc 100644 --- a/code/modules/antagonists/cult/rune_spawn_action.dm +++ b/code/modules/antagonists/cult/rune_spawn_action.dm @@ -42,7 +42,7 @@ var/chosen_keyword if(initial(rune_type.req_keyword)) chosen_keyword = tgui_input_text(owner, "Enter a keyword for the new rune.", "Words of Power", max_length = MAX_NAME_LEN) - if(!chosen_keyword) + if(!chosen_keyword || !turf_check(T)) return //the outer ring is always the same across all runes var/obj/effect/temp_visual/cult/rune_spawn/R1 = new(T, scribe_time, rune_color) diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm index d42ace3f4cd93..e9cf7b371d473 100644 --- a/code/modules/antagonists/cult/runes.dm +++ b/code/modules/antagonists/cult/runes.dm @@ -490,7 +490,7 @@ structure_check() searches for nearby cultist structures required for the invoca fail_invoke() return var/obj/effect/rune/teleport/actual_selected_rune = potential_runes[input_rune_key] //what rune does that key correspond to? - if(!Adjacent(user) || !src || QDELETED(src) || user.incapacitated() || !actual_selected_rune) + if(!Adjacent(user) || QDELETED(src) || user.incapacitated() || !actual_selected_rune) fail_invoke() return diff --git a/code/modules/bitrunning/objects/disks.dm b/code/modules/bitrunning/objects/disks.dm index d6b44a60518d4..6e166d5eb7fdb 100644 --- a/code/modules/bitrunning/objects/disks.dm +++ b/code/modules/bitrunning/objects/disks.dm @@ -48,7 +48,7 @@ names += initial(thing.name) var/choice = tgui_input_list(user, message = "Select an ability", title = "Bitrunning Program", items = names) - if(isnull(choice)) + if(isnull(choice) || !user.is_holding(src)) return for(var/datum/action/thing as anything in selectable_actions) @@ -105,7 +105,7 @@ names += initial(thing.name) var/choice = tgui_input_list(user, message = "Select an ability", title = "Bitrunning Program", items = names) - if(isnull(choice)) + if(isnull(choice) || !user.is_holding(src)) return for(var/obj/thing as anything in selectable_items) diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm index 67ecc0d485908..f68523fcdaef6 100644 --- a/code/modules/clothing/head/jobs.dm +++ b/code/modules/clothing/head/jobs.dm @@ -277,7 +277,7 @@ return var/input = tgui_input_text(user, "What is the activation phrase?", "Activation phrase", "gadget", max_length = 26) - if(!input) + if(!input || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) return if(input in items_by_phrase) balloon_alert(user, "already used!") @@ -293,14 +293,16 @@ /obj/item/clothing/head/fedora/inspector_hat/attack_self(mob/user) . = ..() var/phrase = tgui_input_list(user, "What item do you want to remove by phrase?", "Item Removal", items_by_phrase) - if(!phrase) + if(!phrase || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) return user.put_in_inactive_hand(items_by_phrase[phrase]) /obj/item/clothing/head/fedora/inspector_hat/AltClick(mob/user) . = ..() + if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) + return var/new_prefix = tgui_input_text(user, "What should be the new prefix?", "Activation prefix", prefix, max_length = 24) - if(!new_prefix) + if(!new_prefix || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) return prefix = new_prefix diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm index a40d0d2c35391..c4aad8a0806d5 100644 --- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm @@ -722,10 +722,13 @@ to_chat(telepath, span_warning("You don't see anyone to send your thought to.")) return var/mob/living/recipient = tgui_input_list(telepath, "Choose a telepathic message recipient", "Telepathy", sort_names(recipient_options)) - if(isnull(recipient)) + if(isnull(recipient) || telepath.stat == DEAD || !is_species(telepath, /datum/species/jelly/stargazer)) return var/msg = tgui_input_text(telepath, title = "Telepathy") - if(isnull(msg)) + if(isnull(msg) || telepath.stat == DEAD || !is_species(telepath, /datum/species/jelly/stargazer)) + return + if(!(recipient in oview(telepath))) + to_chat(telepath, span_warning("You can't see [recipient] anymore!")) return if(recipient.can_block_magic(MAGIC_RESISTANCE_MIND, charge_cost = 0)) to_chat(telepath, span_warning("As you reach into [recipient]'s mind, you are stopped by a mental blockage. It seems you've been foiled.")) diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm index faa7d3a9edb95..ae1c52d1652da 100644 --- a/code/modules/mob/living/simple_animal/bot/floorbot.dm +++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm @@ -140,7 +140,7 @@ return data // Actions received from TGUI -/mob/living/simple_animal/bot/floorbot/ui_act(action, params) +/mob/living/simple_animal/bot/floorbot/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() if(. || (bot_cover_flags & BOT_COVER_LOCKED && !HAS_SILICON_ACCESS(usr))) return @@ -161,7 +161,7 @@ tilestack.forceMove(drop_location()) if("line_mode") var/setdir = tgui_input_list(usr, "Select construction direction", "Direction", list("north", "east", "south", "west", "disable")) - if(isnull(setdir)) + if(isnull(setdir) || QDELETED(ui) || ui.status != UI_INTERACTIVE) return switch(setdir) if("north") diff --git a/code/modules/mod/mod_link.dm b/code/modules/mod/mod_link.dm index 4323d7c00a6e0..7657b2678be36 100644 --- a/code/modules/mod/mod_link.dm +++ b/code/modules/mod/mod_link.dm @@ -187,6 +187,8 @@ /obj/item/clothing/neck/link_scryer/attack_self(mob/user, modifiers) var/new_label = reject_bad_text(tgui_input_text(user, "Change the visible name", "Set Name", label, MAX_NAME_LEN)) + if(!user.is_holding(src)) + return if(!new_label) balloon_alert(user, "invalid name!") return diff --git a/code/modules/photography/camera/camera.dm b/code/modules/photography/camera/camera.dm index a0a51da165f47..bde6003ef09a8 100644 --- a/code/modules/photography/camera/camera.dm +++ b/code/modules/photography/camera/camera.dm @@ -251,11 +251,11 @@ to_chat(user, span_notice("[pictures_left] photos left.")) if(can_customise) - var/customise = tgui_alert(user, "Do you want to customize the photo?", "Customization", list("Yes", "No")) + var/customise = user.is_holding(new_photo) && tgui_alert(user, "Do you want to customize the photo?", "Customization", list("Yes", "No")) if(customise == "Yes") - var/name1 = tgui_input_text(user, "Set a name for this photo, or leave blank.", "Name", max_length = 32) - var/desc1 = tgui_input_text(user, "Set a description to add to photo, or leave blank.", "Description", max_length = 128) - var/caption = tgui_input_text(user, "Set a caption for this photo, or leave blank.", "Caption", max_length = 256) + var/name1 = user.is_holding(new_photo) && tgui_input_text(user, "Set a name for this photo, or leave blank.", "Name", max_length = 32) + var/desc1 = user.is_holding(new_photo) && tgui_input_text(user, "Set a description to add to photo, or leave blank.", "Description", max_length = 128) + var/caption = user.is_holding(new_photo) && tgui_input_text(user, "Set a caption for this photo, or leave blank.", "Caption", max_length = 256) if(name1) picture.picture_name = name1 if(desc1) diff --git a/code/modules/plumbing/ducts.dm b/code/modules/plumbing/ducts.dm index 33073ae910f1f..a7990f65ce5b9 100644 --- a/code/modules/plumbing/ducts.dm +++ b/code/modules/plumbing/ducts.dm @@ -343,9 +343,13 @@ All the important duct code: /obj/item/stack/ducts/attack_self(mob/user) var/new_layer = tgui_input_list(user, "Select a layer", "Layer", GLOB.plumbing_layers, duct_layer) + if(!user.is_holding(src)) + return if(new_layer) duct_layer = new_layer var/new_color = tgui_input_list(user, "Select a color", "Color", GLOB.pipe_paint_colors, duct_color) + if(!user.is_holding(src)) + return if(new_color) duct_color = new_color add_atom_colour(GLOB.pipe_paint_colors[new_color], FIXED_COLOUR_PRIORITY) diff --git a/code/modules/plumbing/plumbers/filter.dm b/code/modules/plumbing/plumbers/filter.dm index 633f70830f016..c4df35164f02c 100644 --- a/code/modules/plumbing/plumbers/filter.dm +++ b/code/modules/plumbing/plumbers/filter.dm @@ -30,7 +30,7 @@ data["right"] = english_right return data -/obj/machinery/plumbing/filter/ui_act(action, params) +/obj/machinery/plumbing/filter/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() if(.) return @@ -42,6 +42,8 @@ var/selected_reagent = tgui_input_list(usr, "Select [which] reagent", "Reagent", GLOB.name2reagent) if(!selected_reagent) return TRUE + if(QDELETED(ui) || ui.status != UI_INTERACTIVE) + return FALSE var/datum/reagent/chem_id = GLOB.name2reagent[selected_reagent] if(!chem_id) @@ -69,5 +71,3 @@ if(english_right.Find(chem_name)) english_right -= chem_name right -= chem_id - - diff --git a/code/modules/plumbing/plumbers/reaction_chamber.dm b/code/modules/plumbing/plumbers/reaction_chamber.dm index 72caa60376745..9bdac2f98b243 100644 --- a/code/modules/plumbing/plumbers/reaction_chamber.dm +++ b/code/modules/plumbing/plumbers/reaction_chamber.dm @@ -107,6 +107,8 @@ var/selected_reagent = tgui_input_list(ui.user, "Select reagent", "Reagent", GLOB.name2reagent) if(!selected_reagent) return FALSE + if(QDELETED(ui) || ui.status != UI_INTERACTIVE) + return FALSE var/datum/reagent/input_reagent = GLOB.name2reagent[selected_reagent] if(!input_reagent) diff --git a/code/modules/power/apc/apc_tool_act.dm b/code/modules/power/apc/apc_tool_act.dm index 00d3fc7a53879..981e35fe7803a 100644 --- a/code/modules/power/apc/apc_tool_act.dm +++ b/code/modules/power/apc/apc_tool_act.dm @@ -26,7 +26,7 @@ . = wallframe_act(user, tool) if(.) return . - + if(panel_open && !opened && is_wire_tool(tool)) wires.interact(user) return ITEM_INTERACT_SUCCESS @@ -73,44 +73,59 @@ update_appearance() return ITEM_INTERACT_SUCCESS -/// Called when we interact with the APC with a cable, attempts to wire the APC and create a terminal -/obj/machinery/power/apc/proc/cable_act(mob/living/user, obj/item/stack/cable_coil/installing_cable, is_right_clicking) +/// Checks if we can place a terminal on the APC +/obj/machinery/power/apc/proc/can_place_terminal(mob/living/user, obj/item/stack/cable_coil/installing_cable, silent = TRUE) if(!opened) - return NONE - + return FALSE var/turf/host_turf = get_turf(src) - if(!host_turf) - CRASH("cable_act on APC when it's not on a turf") if(host_turf.underfloor_accessibility < UNDERFLOOR_INTERACTABLE) - balloon_alert(user, "remove the floor plating!") - return ITEM_INTERACT_BLOCKING - if(terminal) - balloon_alert(user, "already wired!") - return ITEM_INTERACT_BLOCKING + if(!silent && user) + balloon_alert(user, "remove the floor plating!") + return FALSE + if(!isnull(terminal)) + if(!silent && user) + balloon_alert(user, "already wired!") + return FALSE if(!has_electronics) - balloon_alert(user, "no board to wire!") - return ITEM_INTERACT_BLOCKING - + if(!silent && user) + balloon_alert(user, "no board to wire!") + return FALSE + if(panel_open) + if(!silent && user) + balloon_alert(user, "wires prevent placing a terminal!") + return FALSE if(installing_cable.get_amount() < 10) - balloon_alert(user, "need ten lengths of cable!") + if(!silent && user) + balloon_alert(user, "need ten lengths of cable!") + return FALSE + return TRUE + +/// Called when we interact with the APC with a cable, attempts to wire the APC and create a terminal +/obj/machinery/power/apc/proc/cable_act(mob/living/user, obj/item/stack/cable_coil/installing_cable, is_right_clicking) + if(!opened) + return NONE + if(!can_place_terminal(user, installing_cable, silent = FALSE)) return ITEM_INTERACT_BLOCKING var/terminal_cable_layer = cable_layer // Default to machine's cable layer if(is_right_clicking) var/choice = tgui_input_list(user, "Select Power Input Cable Layer", "Select Cable Layer", GLOB.cable_name_to_layer) - if(isnull(choice)) + if(isnull(choice) \ + || !user.is_holding(installing_cable) \ + || !user.Adjacent(src) \ + || user.incapacitated() \ + || !can_place_terminal(user, installing_cable, silent = TRUE) \ + ) return ITEM_INTERACT_BLOCKING terminal_cable_layer = GLOB.cable_name_to_layer[choice] - user.visible_message(span_notice("[user.name] adds cables to the APC frame.")) - balloon_alert(user, "adding cables to the frame...") - playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE) + user.visible_message(span_notice("[user.name] starts addding cables to the APC frame.")) + balloon_alert(user, "adding cables...") + playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) if(!do_after(user, 2 SECONDS, target = src)) return ITEM_INTERACT_BLOCKING - if(installing_cable.get_amount() < 10 || !installing_cable) - return ITEM_INTERACT_BLOCKING - if(terminal || !opened || !has_electronics) + if(!can_place_terminal(user, installing_cable, silent = TRUE)) return ITEM_INTERACT_BLOCKING var/turf/our_turf = get_turf(src) var/obj/structure/cable/cable_node = our_turf.get_cable_node(terminal_cable_layer) @@ -118,7 +133,8 @@ do_sparks(5, TRUE, src) return ITEM_INTERACT_BLOCKING installing_cable.use(10) - balloon_alert(user, "cables added to the frame") + user.visible_message(span_notice("[user.name] adds cables to the APC frame.")) + balloon_alert(user, "cables added") make_terminal(terminal_cable_layer) terminal.connect_to_network() return ITEM_INTERACT_SUCCESS @@ -127,7 +143,7 @@ /obj/machinery/power/apc/proc/electronics_act(mob/living/user, obj/item/electronics/apc/installing_board) if(!opened) return NONE - + if(has_electronics) balloon_alert(user, "there is already a board!") return ITEM_INTERACT_BLOCKING diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm index 8a1a948553986..4938a0328ee6b 100644 --- a/code/modules/power/smes.dm +++ b/code/modules/power/smes.dm @@ -112,55 +112,42 @@ //building and linking a terminal if(istype(item, /obj/item/stack/cable_coil)) - var/dir = get_dir(user,src) - if(dir & (dir-1))//we don't want diagonal click - return - - if(terminal) //is there already a terminal ? - to_chat(user, span_warning("This SMES already has a power terminal!")) - return - - if(!panel_open) //is the panel open ? - to_chat(user, span_warning("You must open the maintenance panel first!")) - return - - var/turf/turf = get_turf(user) - if (turf.underfloor_accessibility < UNDERFLOOR_INTERACTABLE) //can we get to the underfloor? - to_chat(user, span_warning("You must first remove the floor plating!")) - return - - - var/obj/item/stack/cable_coil/cable = item - if(cable.get_amount() < 10) - to_chat(user, span_warning("You need more wires!")) + if(!can_place_terminal(user, item, silent = FALSE)) return var/terminal_cable_layer if(LAZYACCESS(params2list(params), RIGHT_CLICK)) var/choice = tgui_input_list(user, "Select Power Input Cable Layer", "Select Cable Layer", GLOB.cable_name_to_layer) - if(isnull(choice)) + if(isnull(choice) \ + || !user.is_holding(item) \ + || !user.Adjacent(src) \ + || user.incapacitated() \ + || !can_place_terminal(user, item, silent = TRUE) \ + ) return terminal_cable_layer = GLOB.cable_name_to_layer[choice] - to_chat(user, span_notice("You start building the power terminal...")) - playsound(src.loc, 'sound/items/deconstruct.ogg', 50, TRUE) + user.visible_message(span_notice("[user.name] starts adding cables to [src].")) + balloon_alert(user, "adding cables...") + playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) - if(do_after(user, 2 SECONDS, target = src)) - if(cable.get_amount() < 10 || !cable) - return - var/obj/structure/cable/connected_cable = turf.get_cable_node(terminal_cable_layer) //get the connecting node cable, if there's one - if (prob(50) && electrocute_mob(user, connected_cable, connected_cable, 1, TRUE)) //animate the electrocution if uncautious and unlucky - do_sparks(5, TRUE, src) - return - if(!terminal) - cable.use(10) - user.visible_message(span_notice("[user.name] builds a power terminal."),\ - span_notice("You build the power terminal.")) - - //build the terminal and link it to the network - make_terminal(turf, terminal_cable_layer) - terminal.connect_to_network() - connect_to_network() + if(!do_after(user, 2 SECONDS, target = src)) + return + if(!can_place_terminal(user, item, silent = TRUE)) + return + var/obj/item/stack/cable_coil/cable = item + var/turf/turf = get_turf(src) + var/obj/structure/cable/connected_cable = turf.get_cable_node(terminal_cable_layer) //get the connecting node cable, if there's one + if (prob(50) && electrocute_mob(user, connected_cable, connected_cable, 1, TRUE)) //animate the electrocution if uncautious and unlucky + do_sparks(5, TRUE, src) + return + cable.use(10) + user.visible_message(span_notice("[user.name] adds cables to [src]")) + balloon_alert(user, "cables added") + //build the terminal and link it to the network + make_terminal(turf, terminal_cable_layer) + terminal.connect_to_network() + connect_to_network() return //crowbarring it ! @@ -175,6 +162,31 @@ return ..() +/// Checks if we're in a valid state to place a terminal +/obj/machinery/power/smes/proc/can_place_terminal(mob/living/user, obj/item/stack/cable_coil/installing_cable, silent = TRUE) + var/set_dir = get_dir(user, src) + if(set_dir & (set_dir - 1))//we don't want diagonal click + return FALSE + + var/turf/smes_turf = get_turf(src) + if(!panel_open) + if(!silent && user) + balloon_alert(user, "open the maintenance panel!") + return FALSE + if(smes_turf.underfloor_accessibility < UNDERFLOOR_INTERACTABLE) + if(!silent && user) + balloon_alert(user, "remove the floor plating!") + return FALSE + if(terminal) + if(!silent && user) + balloon_alert(user, "already wired!") + return FALSE + if(installing_cable.get_amount() < 10) + if(!silent && user) + balloon_alert(user, "need ten lengths of cable!") + return FALSE + return TRUE + /obj/machinery/power/smes/wirecutter_act(mob/living/user, obj/item/item) //disassembling the terminal . = ..() From d12b4e0a83ca8ff8417eb1d7031f751bd6e9c8a1 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 12 Apr 2024 15:08:46 +1200 Subject: [PATCH 177/938] Automatic changelog for PR #82577 [ci skip] --- html/changelogs/AutoChangeLog-pr-82577.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82577.yml diff --git a/html/changelogs/AutoChangeLog-pr-82577.yml b/html/changelogs/AutoChangeLog-pr-82577.yml new file mode 100644 index 0000000000000..4fbb0ab9352f2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82577.yml @@ -0,0 +1,13 @@ +author: "Melbert" +delete-after: True +changes: + - bugfix: "You can't change the GPS tag of something unless you can actually use the GPS" + - bugfix: "You can't set the teleporter to a location unless you can actually use the teleporter" + - bugfix: "You can't reply to request console requests unless you can actually use the console" + - bugfix: "You can't update AI lawboards unless you're actually holding them" + - bugfix: "You can't update a borg rename board unless you're actually holding it" + - bugfix: "You can't mess with plumbing machines unless you can actually use them" + - bugfix: "You can't recolor / relayer ducts unless you're actually holding them" + - bugfix: "You can't magically wire APCs and SMESs unless you're right by them" + - bugfix: "You can't use Stargazer Telepathy on people who you can't see" + - bugfix: "You can't configure the Inspector Hat unless you can actually use it" \ No newline at end of file From e3a554662d4bac5395d80f46c2d8dfd7a7fa953d Mon Sep 17 00:00:00 2001 From: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Date: Fri, 12 Apr 2024 08:43:49 +0530 Subject: [PATCH 178/938] [NO GBP] Power outage operation fixes for chem master (#82591) ## About The Pull Request - If the chem master runs out of power mid printing, it will properly stop the printing process and its animation - When transferring reagents it correctly checks if we have enough power without forcing it ## Changelog :cl: fix: chem master properly shuts down if it loses power mid printing and won't transfer reagents for the same /:cl: --- code/modules/reagents/chemistry/machinery/chem_master.dm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm index 4b9cb532d4a3c..fb593d0b80f33 100644 --- a/code/modules/reagents/chemistry/machinery/chem_master.dm +++ b/code/modules/reagents/chemistry/machinery/chem_master.dm @@ -400,7 +400,7 @@ return FALSE //use energy - if(!use_energy(active_power_usage)) + if(!use_energy(active_power_usage, force = FALSE)) return FALSE //do the operation @@ -512,7 +512,9 @@ return //use power - if(!use_energy(active_power_usage)) + if(!use_energy(active_power_usage, force = FALSE)) + is_printing = FALSE + update_appearance(UPDATE_OVERLAYS) return //print the stuff From 2276af9eccd899578d4226e2696e2a637d545424 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 12 Apr 2024 15:18:58 +1200 Subject: [PATCH 179/938] Automatic changelog for PR #82591 [ci skip] --- html/changelogs/AutoChangeLog-pr-82591.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82591.yml diff --git a/html/changelogs/AutoChangeLog-pr-82591.yml b/html/changelogs/AutoChangeLog-pr-82591.yml new file mode 100644 index 0000000000000..c6557e26a8a24 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82591.yml @@ -0,0 +1,4 @@ +author: "SyncIt21" +delete-after: True +changes: + - bugfix: "chem master properly shuts down if it loses power mid printing and won't transfer reagents for the same" \ No newline at end of file From 5e568288f44ab69cc23d121ed7fc6dcfc4ed505c Mon Sep 17 00:00:00 2001 From: _0Steven <42909981+00-Steven@users.noreply.github.com> Date: Fri, 12 Apr 2024 05:30:32 +0200 Subject: [PATCH 180/938] Refactor renaming UNIQUE_RENAME items from the pen to an element (#82491) ## About The Pull Request So a bit ago someone in code_general wanted to make plushies renamable, but learnt that just adding the `UNIQUE_RENAME` flag wouldn't work as pens would murder the plushie and only THEN let you rename it. I noted refactoring both pens and plushies to use the new `item_interaction(...)` procs would Just Solve This, but, well, they didn't really have any coding experience. But, hey, renaming being hardcoded to the pens has annoyed me ever since I laid my eyes upon the hot mess that is paperwork code. So here we are! ### We're making it an element. There's not really much to this, this is mostly the same code but moved to an element and with some minor cleanups. First, we move it all from `/obj/item/pen` to a new element we called `/datum/element/tool_renaming`. With this, instead of having it proc on `/obj/item/pen/afterattack(...)`, we register it to proc on the `COMSIG_ITEM_INTERACTING_WITH_ATOM` signal. https://github.com/tgstation/tgstation/blob/6e36ed984070d53e16bed4fa43eb0cbe6460deed/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm#L59-L62 Secondly, we realize the code is just going through each if statement regardless of whether the previous was correct. https://github.com/tgstation/tgstation/blob/6e36ed984070d53e16bed4fa43eb0cbe6460deed/code/modules/paperwork/pen.dm#L225-L258 And, as we're dealing with text, just make it a switch statement instead. ```dm switch(pen_choice) if("Rename") (...) if("Description") (...) if("Reset") (...) ``` Then, we replace all single letter variables with descriptive ones, replace the if-elses with early returns, and make it actually return item interaction flags. Finally, we slap this onto the pen, and we're done. Now we can slap it onto other fitting renaming tools, and it uses the proper item interaction system. ## Why It's Good For The Game I feel it's generally better to not hardcode this to just pens, we have plenty other writing utensils and possible renaming tools. It's also a bit cleaner than before. Apart from that, moves it from using `afterattack(...)` to the proper item interaction chain by using `COMSIG_ITEM_INTERACTING_WITH_ATOM`, which should reduce janky interactions. ## Changelog :cl: refactor: Instead of being hardcoded to the pen, renaming items is now an element. Currently only pens have this, and functionality should be the same, but please report it if you find any items that were renamable but now aren't. /:cl: --- code/__DEFINES/say.dm | 1 + code/__DEFINES/traits/sources.dm | 4 +- code/datums/elements/tool_renaming.dm | 78 +++++++++++++++++++ code/modules/paperwork/pen.dm | 49 +----------- .../reagent_containers/cups/drinkingglass.dm | 4 +- tgstation.dme | 1 + 6 files changed, 85 insertions(+), 52 deletions(-) create mode 100644 code/datums/elements/tool_renaming.dm diff --git a/code/__DEFINES/say.dm b/code/__DEFINES/say.dm index 928877f541da0..84e077deb170f 100644 --- a/code/__DEFINES/say.dm +++ b/code/__DEFINES/say.dm @@ -107,6 +107,7 @@ #define MAX_CHARTER_LEN 80 #define MAX_PLAQUE_LEN 144 #define MAX_LABEL_LEN 64 +#define MAX_DESC_LEN 280 // Audio/Visual Flags. Used to determine what sense are required to notice a message. #define MSG_VISUAL (1<<0) diff --git a/code/__DEFINES/traits/sources.dm b/code/__DEFINES/traits/sources.dm index dcbfab7fe5f16..56bcbf3c90dfa 100644 --- a/code/__DEFINES/traits/sources.dm +++ b/code/__DEFINES/traits/sources.dm @@ -286,8 +286,8 @@ /// Trait from an organ being inside a bodypart #define ORGAN_INSIDE_BODY_TRAIT "organ_inside_body" -/// Trait when something was labelled by a pen. -#define PEN_LABEL_TRAIT "pen_label" +/// Trait when something was labelled by the /datum/element/tool_renaming element. +#define RENAMING_TOOL_LABEL_TRAIT "renaming_tool_label" /// Trait when a drink was renamed by a shaker #define SHAKER_LABEL_TRAIT "shaker_trait" diff --git a/code/datums/elements/tool_renaming.dm b/code/datums/elements/tool_renaming.dm new file mode 100644 index 0000000000000..bd87f1d171c86 --- /dev/null +++ b/code/datums/elements/tool_renaming.dm @@ -0,0 +1,78 @@ +#define OPTION_RENAME "Rename" +#define OPTION_DESCRIPTION "Description" +#define OPTION_RESET "Reset" + +/** + * Renaming tool element + * + * When using this tool on an object with UNIQUE_RENAME, + * lets the user rename/redesc it. + */ +/datum/element/tool_renaming + +/datum/element/tool_renaming/Attach(datum/target) + . = ..() + if(!isitem(target)) + return ELEMENT_INCOMPATIBLE + + RegisterSignal(target, COMSIG_ITEM_INTERACTING_WITH_ATOM, PROC_REF(attempt_rename)) + +/datum/element/tool_renaming/Detach(datum/source) + . = ..() + UnregisterSignal(source, COMSIG_ITEM_INTERACTING_WITH_ATOM) + +/datum/element/tool_renaming/proc/attempt_rename(datum/source, mob/living/user, atom/interacting_with, list/modifiers) + SIGNAL_HANDLER + + if(!isobj(interacting_with)) + return NONE + + var/obj/renamed_obj = interacting_with + + if(!(renamed_obj.obj_flags & UNIQUE_RENAME)) + return NONE + + INVOKE_ASYNC(src, PROC_REF(async_rename), user, renamed_obj) + return ITEM_INTERACT_SUCCESS + +/datum/element/tool_renaming/proc/async_rename(mob/living/user, obj/renamed_obj) + var/custom_choice = tgui_input_list(user, "What would you like to edit?", "Customization", list(OPTION_RENAME, OPTION_DESCRIPTION, OPTION_RESET)) + if(QDELETED(renamed_obj) || !user.can_perform_action(renamed_obj) || isnull(custom_choice)) + return + + switch(custom_choice) + if(OPTION_RENAME) + var/old_name = renamed_obj.name + var/input = tgui_input_text(user, "What do you want to name [renamed_obj]?", "Object Name", "[old_name]", MAX_NAME_LEN) + if(QDELETED(renamed_obj) || !user.can_perform_action(renamed_obj)) + return + if(input == old_name || !input) + to_chat(user, span_notice("You changed [renamed_obj] to... well... [renamed_obj].")) + return + renamed_obj.AddComponent(/datum/component/rename, input, renamed_obj.desc) + to_chat(user, span_notice("You have successfully renamed \the [old_name] to [renamed_obj].")) + ADD_TRAIT(renamed_obj, TRAIT_WAS_RENAMED, RENAMING_TOOL_LABEL_TRAIT) + renamed_obj.update_appearance(UPDATE_NAME) + + if(OPTION_DESCRIPTION) + var/old_desc = renamed_obj.desc + var/input = tgui_input_text(user, "Describe [renamed_obj]", "Description", "[old_desc]", MAX_DESC_LEN) + if(QDELETED(renamed_obj) || !user.can_perform_action(renamed_obj)) + return + if(input == old_desc || !input) + to_chat(user, span_notice("You decide against changing [renamed_obj]'s description.")) + return + renamed_obj.AddComponent(/datum/component/rename, renamed_obj.name, input) + to_chat(user, span_notice("You have successfully changed [renamed_obj]'s description.")) + ADD_TRAIT(renamed_obj, TRAIT_WAS_RENAMED, RENAMING_TOOL_LABEL_TRAIT) + renamed_obj.update_appearance(UPDATE_DESC) + + if(OPTION_RESET) + qdel(renamed_obj.GetComponent(/datum/component/rename)) + to_chat(user, span_notice("You have successfully reset [renamed_obj]'s name and description.")) + REMOVE_TRAIT(renamed_obj, TRAIT_WAS_RENAMED, RENAMING_TOOL_LABEL_TRAIT) + renamed_obj.update_appearance(UPDATE_NAME | UPDATE_DESC) + +#undef OPTION_RENAME +#undef OPTION_DESCRIPTION +#undef OPTION_RESET diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm index 2a9e78e248966..5a167df49f779 100644 --- a/code/modules/paperwork/pen.dm +++ b/code/modules/paperwork/pen.dm @@ -44,6 +44,7 @@ dart_insert_projectile_icon_state, \ CALLBACK(src, PROC_REF(get_dart_var_modifiers))\ ) + AddElement(/datum/element/tool_renaming) RegisterSignal(src, COMSIG_DART_INSERT_ADDED, PROC_REF(on_inserted_into_dart)) RegisterSignal(src, COMSIG_DART_INSERT_REMOVED, PROC_REF(on_removed_from_dart)) @@ -209,54 +210,6 @@ log_combat(user, M, "stabbed", src) return TRUE -/obj/item/pen/afterattack(obj/O, mob/living/user, proximity) - . = ..() - - if (!proximity) - return . - - . |= AFTERATTACK_PROCESSED_ITEM - - //Changing name/description of items. Only works if they have the UNIQUE_RENAME object flag set - if(isobj(O) && (O.obj_flags & UNIQUE_RENAME)) - var/penchoice = tgui_input_list(user, "What would you like to edit?", "Pen Setting", list("Rename", "Description", "Reset")) - if(QDELETED(O) || !user.can_perform_action(O)) - return - if(penchoice == "Rename") - var/input = tgui_input_text(user, "What do you want to name [O]?", "Object Name", "[O.name]", MAX_NAME_LEN) - var/oldname = O.name - if(QDELETED(O) || !user.can_perform_action(O)) - return - if(input == oldname || !input) - to_chat(user, span_notice("You changed [O] to... well... [O].")) - else - O.AddComponent(/datum/component/rename, input, O.desc) - to_chat(user, span_notice("You have successfully renamed \the [oldname] to [O].")) - ADD_TRAIT(O, TRAIT_WAS_RENAMED, PEN_LABEL_TRAIT) - O.update_appearance(UPDATE_ICON) - - if(penchoice == "Description") - var/input = tgui_input_text(user, "Describe [O]", "Description", "[O.desc]", 280) - var/olddesc = O.desc - if(QDELETED(O) || !user.can_perform_action(O)) - return - if(input == olddesc || !input) - to_chat(user, span_notice("You decide against changing [O]'s description.")) - else - O.AddComponent(/datum/component/rename, O.name, input) - to_chat(user, span_notice("You have successfully changed [O]'s description.")) - ADD_TRAIT(O, TRAIT_WAS_RENAMED, PEN_LABEL_TRAIT) - O.update_appearance(UPDATE_ICON) - - if(penchoice == "Reset") - if(QDELETED(O) || !user.can_perform_action(O)) - return - - qdel(O.GetComponent(/datum/component/rename)) - to_chat(user, span_notice("You have successfully reset [O]'s name and description.")) - REMOVE_TRAIT(O, TRAIT_WAS_RENAMED, PEN_LABEL_TRAIT) - O.update_appearance(UPDATE_ICON) - /obj/item/pen/get_writing_implement_details() return list( interaction_mode = MODE_WRITING, diff --git a/code/modules/reagents/reagent_containers/cups/drinkingglass.dm b/code/modules/reagents/reagent_containers/cups/drinkingglass.dm index adcd2ff79fab9..7441614682c06 100644 --- a/code/modules/reagents/reagent_containers/cups/drinkingglass.dm +++ b/code/modules/reagents/reagent_containers/cups/drinkingglass.dm @@ -35,7 +35,7 @@ /obj/item/reagent_containers/cup/glass/drinkingglass/on_reagent_change(datum/reagents/holder, ...) . = ..() if(!length(reagents.reagent_list)) - REMOVE_TRAIT(src, TRAIT_WAS_RENAMED, PEN_LABEL_TRAIT) //so new drinks can rename the glass + REMOVE_TRAIT(src, TRAIT_WAS_RENAMED, RENAMING_TOOL_LABEL_TRAIT) //so new drinks can rename the glass // Having our icon state change removes fill thresholds /obj/item/reagent_containers/cup/glass/drinkingglass/on_cup_change(datum/glass_style/style) @@ -58,7 +58,7 @@ return REMOVE_TRAIT(src, TRAIT_WAS_RENAMED, SHAKER_LABEL_TRAIT) - REMOVE_TRAIT(src, TRAIT_WAS_RENAMED, PEN_LABEL_TRAIT) + REMOVE_TRAIT(src, TRAIT_WAS_RENAMED, RENAMING_TOOL_LABEL_TRAIT) name = initial(name) desc = initial(desc) update_appearance(UPDATE_NAME | UPDATE_DESC) diff --git a/tgstation.dme b/tgstation.dme index b14fba3526af4..2bf67fe273cd5 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1490,6 +1490,7 @@ #include "code\datums\elements\tenacious.dm" #include "code\datums\elements\tiny_mob_hunter.dm" #include "code\datums\elements\tool_flash.dm" +#include "code\datums\elements\tool_renaming.dm" #include "code\datums\elements\toy_talk.dm" #include "code\datums\elements\turf_transparency.dm" #include "code\datums\elements\undertile.dm" From 9ec316306b2907e26f306da52fdd48d8c2c5d8e1 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 12 Apr 2024 15:30:51 +1200 Subject: [PATCH 181/938] Automatic changelog for PR #82491 [ci skip] --- html/changelogs/AutoChangeLog-pr-82491.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82491.yml diff --git a/html/changelogs/AutoChangeLog-pr-82491.yml b/html/changelogs/AutoChangeLog-pr-82491.yml new file mode 100644 index 0000000000000..19030972bfb71 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82491.yml @@ -0,0 +1,4 @@ +author: "00-Steven" +delete-after: True +changes: + - refactor: "Instead of being hardcoded to the pen, renaming items is now an element. Currently only pens have this, and functionality should be the same, but please report it if you find any items that were renamable but now aren't." \ No newline at end of file From df11ec8f34ad79c20897e9317ca8c02a37d07673 Mon Sep 17 00:00:00 2001 From: Ketrai Date: Fri, 12 Apr 2024 05:50:49 +0200 Subject: [PATCH 182/938] Adds various quality of life changes for cooking to make it less click intensive. (#82566) ## About The Pull Request - Increases tray item size by 1 item. - Ranges and griddles can now be fed from trays. Click when closed => fill soup pot. Click when open => fill associated oven tray. Right click when open => fill tray from oven tray Click griddle => fill griddle surface. Right click => fill tray from griddle surface - Martian batter is now 5u of each ingredient into 10u of batter. Hopefully will make it bug out less where it makes far fewer reagents than it is supposed to, fixing reagents, or well soups specifically... is out of scope for this PR. - Adds the ability to print soup pots and large trays from the service lathe Soup pot: 5 Iron sheets, 0.4 bluespace crystal (given their size of 200U) Large serving tray: 2 iron sheets ## Why It's Good For The Game Makes cooking a lot less tedious. Especially for people with low precision when it comes to filling oven trays. This also bring the behavior up to parity with how you can click microwaves with trays to fill them, ditto for the food processor. It also allows chef to use the whole capacity of an oven, as previously you couldn't easily click 6 cake batters or other giant sprites onto the tiny tray. The tray is now sized to be able to easily feed a griddle 8 items. ## Changelog :cl: qol: chef equipment can now deposit and withdraw to/from trays! qol: chef now has access to griddle and oven sized trays! qol: service can now print soup pots /:cl: --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Co-authored-by: Jeremiah <42397676+jlsnow301@users.noreply.github.com> --- code/game/objects/items/storage/bags.dm | 39 ++++++++------ .../food_and_drinks/machinery/griddle.dm | 39 ++++++++++++++ .../modules/food_and_drinks/machinery/oven.dm | 54 ++++++++++++++++--- .../food_and_drinks/machinery/stove.dm | 35 ++++++++++++ .../machinery/stove_component.dm | 8 +++ .../food_and_drinks/recipes/food_mixtures.dm | 4 +- .../designs/autolathe/service_designs.dm | 13 +++++ code/modules/research/techweb/all_nodes.dm | 1 + 8 files changed, 169 insertions(+), 24 deletions(-) diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm index d72a57f07f157..cc548be16d27e 100644 --- a/code/game/objects/items/storage/bags.dm +++ b/code/game/objects/items/storage/bags.dm @@ -360,23 +360,30 @@ /obj/item/storage/bag/tray/Initialize(mapload) . = ..() atom_storage.max_specific_storage = WEIGHT_CLASS_BULKY //Plates are required bulky to keep them out of backpacks - atom_storage.set_holdable(list( - /obj/item/clothing/mask/cigarette, - /obj/item/food, - /obj/item/kitchen, - /obj/item/lighter, - /obj/item/organ, - /obj/item/plate, - /obj/item/reagent_containers/condiment, - /obj/item/reagent_containers/cup, - /obj/item/rollingpaper, - /obj/item/storage/box/gum, - /obj/item/storage/box/matches, - /obj/item/storage/fancy, - /obj/item/trash, - )) //Should cover: Bottles, Beakers, Bowls, Booze, Glasses, Food, Food Containers, Food Trash, Organs, Tobacco Products, Lighters, and Kitchen Tools. + atom_storage.set_holdable( + can_hold_list = list( + /obj/item/clothing/mask/cigarette, + /obj/item/food, + /obj/item/kitchen, + /obj/item/lighter, + /obj/item/organ, + /obj/item/plate, + /obj/item/reagent_containers/condiment, + /obj/item/reagent_containers/cup, + /obj/item/rollingpaper, + /obj/item/storage/box/gum, + /obj/item/storage/box/matches, + /obj/item/storage/fancy, + /obj/item/trash, + ), + cant_hold_list = list( + /obj/item/plate/oven_tray, + /obj/item/reagent_containers/cup/soup_pot, + ), + ) //Should cover: Bottles, Beakers, Bowls, Booze, Glasses, Food, Food Containers, Food Trash, Organs, Tobacco Products, Lighters, and Kitchen Tools. atom_storage.insert_preposition = "on" - atom_storage.max_slots = 7 + atom_storage.max_slots = 8 + atom_storage.max_total_storage = 16 /obj/item/storage/bag/tray/attack(mob/living/M, mob/living/user) . = ..() diff --git a/code/modules/food_and_drinks/machinery/griddle.dm b/code/modules/food_and_drinks/machinery/griddle.dm index b54a470897f5b..f04b50e55516c 100644 --- a/code/modules/food_and_drinks/machinery/griddle.dm +++ b/code/modules/food_and_drinks/machinery/griddle.dm @@ -63,6 +63,7 @@ /obj/machinery/griddle/attackby(obj/item/I, mob/user, params) + if(griddled_objects.len >= max_items) to_chat(user, span_notice("[src] can't fit more items!")) return @@ -79,6 +80,44 @@ else return ..() +/obj/machinery/griddle/item_interaction(mob/living/user, obj/item/item, list/modifiers, is_right_clicking) + . = ..() + if(. & ITEM_INTERACT_ANY_BLOCKER) + return + + if(isnull(item.atom_storage)) + return + + if(is_right_clicking) + var/obj/item/storage/tray = item + + for(var/obj/tray_item in griddled_objects) + tray.atom_storage?.attempt_insert(tray_item, user, TRUE) + return ITEM_INTERACT_SUCCESS + + var/obj/item/storage/tray = item + var/loaded = 0 + + if(!istype(item, /obj/item/storage/bag/tray)) + // Non-tray dumping requires a do_after + to_chat(user, span_notice("You start dumping out the contents of [item] into [src]...")) + if(!do_after(user, 2 SECONDS, target = tray)) + return ITEM_INTERACT_BLOCKING + + for(var/obj/tray_item in tray.contents) + if(!IS_EDIBLE(tray_item)) + continue + if(contents.len >= max_items) + balloon_alert(user, "it's full!") + return ITEM_INTERACT_BLOCKING + if(tray.atom_storage.attempt_remove(tray_item, src)) + loaded++ + AddToGrill(tray_item, user) + if(loaded) + to_chat(user, span_notice("You insert [loaded] items into \the [src].")) + update_appearance() + return ITEM_INTERACT_SUCCESS + /obj/machinery/griddle/attack_hand(mob/user, list/modifiers) . = ..() toggle_mode() diff --git a/code/modules/food_and_drinks/machinery/oven.dm b/code/modules/food_and_drinks/machinery/oven.dm index 8135dd8308f62..da0c75824cad9 100644 --- a/code/modules/food_and_drinks/machinery/oven.dm +++ b/code/modules/food_and_drinks/machinery/oven.dm @@ -100,13 +100,18 @@ use_energy(active_power_usage) -/obj/machinery/oven/attackby(obj/item/I, mob/user, params) - if(open && !used_tray && istype(I, /obj/item/plate/oven_tray)) - if(user.transferItemToLoc(I, src, silent = FALSE)) - to_chat(user, span_notice("You put [I] in [src].")) - add_tray_to_oven(I, user) - else +/obj/machinery/oven/attackby(obj/item/item, mob/user, params) + if(!open || used_tray || !item.atom_storage) return ..() + + if(user.transferItemToLoc(item, src, silent = FALSE)) + to_chat(user, span_notice("You put [item] in [src].")) + add_tray_to_oven(item, user) + +/obj/machinery/oven/item_interaction(mob/living/user, obj/item/item, list/modifiers, is_right_clicking) + if(open && used_tray && item.atom_storage) + return used_tray.item_interaction(user, item, modifiers, is_right_clicking) + return ..() ///Adds a tray to the oven, making sure the shit can get baked. /obj/machinery/oven/proc/add_tray_to_oven(obj/item/plate/oven_tray, mob/baker) @@ -243,6 +248,43 @@ max_items = 6 biggest_w_class = WEIGHT_CLASS_BULKY +/obj/item/plate/oven_tray/item_interaction(mob/living/user, obj/item/item, list/modifiers, is_right_clicking) + . = ..() + + if(isnull(item.atom_storage)) + return + + if(is_right_clicking) + var/obj/item/storage/tray = item + + for(var/obj/tray_item in contents) + tray.atom_storage?.attempt_insert(tray_item, user, TRUE) + + return ITEM_INTERACT_SUCCESS + + var/obj/item/storage/tray = item + var/loaded = 0 + + if(!istype(item, /obj/item/storage/bag/tray)) + // Non-tray dumping requires a do_after + to_chat(user, span_notice("You start dumping out the contents of [item] into [src]...")) + if(!do_after(user, 2 SECONDS, target = tray)) + return ITEM_INTERACT_BLOCKING + + for(var/obj/tray_item in tray.contents) + if(!IS_EDIBLE(tray_item)) + continue + if(contents.len >= max_items) + balloon_alert(user, "it's full!") + return ITEM_INTERACT_BLOCKING + if(tray.atom_storage.attempt_remove(tray_item, src)) + loaded++ + AddToPlate(tray_item, user) + if(loaded) + to_chat(user, span_notice("You insert [loaded] items into \the [src].")) + update_appearance() + return ITEM_INTERACT_SUCCESS + #undef OVEN_SMOKE_STATE_NONE #undef OVEN_SMOKE_STATE_GOOD #undef OVEN_SMOKE_STATE_NEUTRAL diff --git a/code/modules/food_and_drinks/machinery/stove.dm b/code/modules/food_and_drinks/machinery/stove.dm index 38f98cfa8a8bf..c80fca7108560 100644 --- a/code/modules/food_and_drinks/machinery/stove.dm +++ b/code/modules/food_and_drinks/machinery/stove.dm @@ -115,6 +115,34 @@ . = ..() LAZYREMOVE(added_ingredients, gone) +/** + * Adds items to a soup pot without invoking any procs that call sleep() when using in a component. + * + * Args: + * * transfer_from: The container that's being used to add items to the soup pot. Must not be null. + * * user: the entity adding ingredients via a container to a soup pot. Must not be null. + */ +/obj/item/reagent_containers/cup/soup_pot/proc/transfer_from_container_to_pot(obj/item/transfer_from, mob/user) + if(!transfer_from.atom_storage) + return + + var/obj/item/storage/tray = transfer_from + var/loaded = 0 + + for(var/obj/tray_item in tray.contents) + if(!can_add_ingredient(tray_item)) + continue + if(LAZYLEN(added_ingredients) >= max_ingredients) + balloon_alert(user, "it's full!") + return TRUE + if(tray.atom_storage.attempt_remove(tray_item, src)) + loaded++ + LAZYADD(added_ingredients, tray_item) + if(loaded) + to_chat(user, span_notice("You insert [loaded] items into \the [src].")) + update_appearance(UPDATE_OVERLAYS) + return TRUE + /obj/item/reagent_containers/cup/soup_pot/attackby(obj/item/attacking_item, mob/user, params) . = ..() if(.) @@ -140,6 +168,13 @@ update_appearance(UPDATE_OVERLAYS) return TRUE +/obj/item/reagent_containers/cup/soup_pot/item_interaction(mob/living/user, obj/item/item, list/modifiers, is_right_clicking) + + if(!is_right_clicking) + return transfer_from_container_to_pot(item, user) + else + return ..() + /obj/item/reagent_containers/cup/soup_pot/attack_hand_secondary(mob/user, list/modifiers) if(!LAZYLEN(added_ingredients)) return SECONDARY_ATTACK_CALL_NORMAL diff --git a/code/modules/food_and_drinks/machinery/stove_component.dm b/code/modules/food_and_drinks/machinery/stove_component.dm index 1a39c3b205746..76a70f0f22ab2 100644 --- a/code/modules/food_and_drinks/machinery/stove_component.dm +++ b/code/modules/food_and_drinks/machinery/stove_component.dm @@ -128,6 +128,14 @@ /datum/component/stove/proc/on_attackby(obj/machinery/source, obj/item/attacking_item, mob/user, params) SIGNAL_HANDLER + if(istype(source, /obj/machinery/oven/range) && istype(attacking_item, /obj/item/storage/bag/tray) && container) + var/obj/machinery/oven/range/range = source + var/obj/item/reagent_containers/cup/soup_pot/soup_pot = container + + if(!range.open) + soup_pot.transfer_from_container_to_pot(attacking_item, user) + return COMPONENT_NO_AFTERATTACK + if(!attacking_item.is_open_container()) return if(!isnull(container)) diff --git a/code/modules/food_and_drinks/recipes/food_mixtures.dm b/code/modules/food_and_drinks/recipes/food_mixtures.dm index d5e7f1b15ea80..2331765eb9a3b 100644 --- a/code/modules/food_and_drinks/recipes/food_mixtures.dm +++ b/code/modules/food_and_drinks/recipes/food_mixtures.dm @@ -276,8 +276,8 @@ reaction_flags = REACTION_INSTANT /datum/chemical_reaction/food/martian_batter - results = list(/datum/reagent/consumable/martian_batter = 2) - required_reagents = list(/datum/reagent/consumable/flour = 1, /datum/reagent/consumable/nutriment/soup/dashi = 1) + results = list(/datum/reagent/consumable/martian_batter = 10) + required_reagents = list(/datum/reagent/consumable/flour = 5, /datum/reagent/consumable/nutriment/soup/dashi = 5) mix_message = "A smooth batter forms." reaction_flags = REACTION_INSTANT diff --git a/code/modules/research/designs/autolathe/service_designs.dm b/code/modules/research/designs/autolathe/service_designs.dm index 6b8d7f474fca4..e34fc5166c89c 100644 --- a/code/modules/research/designs/autolathe/service_designs.dm +++ b/code/modules/research/designs/autolathe/service_designs.dm @@ -190,6 +190,19 @@ ) departmental_flags = DEPARTMENT_BITFLAG_SERVICE +/datum/design/soup_pot + name = "Soup Pot" + id = "souppot" + build_type = AUTOLATHE | PROTOLATHE | AWAY_LATHE + materials = list(/datum/material/iron =SHEET_MATERIAL_AMOUNT*5, /datum/material/bluespace =SMALL_MATERIAL_AMOUNT*4) + category = list(RND_CATEGORY_INITIAL, RND_CATEGORY_EQUIPMENT) + build_path = /obj/item/reagent_containers/cup/soup_pot + category = list( + RND_CATEGORY_INITIAL, + RND_CATEGORY_EQUIPMENT + RND_SUBCATEGORY_EQUIPMENT_KITCHEN, + ) + departmental_flags = DEPARTMENT_BITFLAG_SERVICE + /datum/design/bowl name = "Bowl" id = "bowl" diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index 8e0fdc95a746c..3b24c1604d3f7 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -106,6 +106,7 @@ "slime_scanner", "solar_panel", "solar_tracker", + "souppot", "space_heater", "spoon", "status_display_frame", From c556b9d4edbe4c2b02fefe977d48d6d69ae5c233 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 12 Apr 2024 15:51:08 +1200 Subject: [PATCH 183/938] Automatic changelog for PR #82566 [ci skip] --- html/changelogs/AutoChangeLog-pr-82566.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82566.yml diff --git a/html/changelogs/AutoChangeLog-pr-82566.yml b/html/changelogs/AutoChangeLog-pr-82566.yml new file mode 100644 index 0000000000000..04a91ee24f5f0 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82566.yml @@ -0,0 +1,6 @@ +author: "Ketrai" +delete-after: True +changes: + - qol: "chef equipment can now deposit and withdraw to/from trays!" + - qol: "chef now has access to griddle and oven sized trays!" + - qol: "service can now print soup pots" \ No newline at end of file From b30d5776027e55c4e27b1a84b695a3f0eded52cd Mon Sep 17 00:00:00 2001 From: hyperjll <105099113+hyperjll@users.noreply.github.com> Date: Fri, 12 Apr 2024 01:23:52 -0400 Subject: [PATCH 184/938] Haloperidol Purges Itself while you're Stamcrit (#82291) ## About The Pull Request Haloperidol has a pretty severe problem where it causes people to be endlessly stamcrit for minutes on end. You can hit someone with 10 units and stamcrit them, every 5 units after or so usually results in another minute or two of complete helplessness. It's bad. I've made it so Haloperidol will begin purging itself rapidly should the victim fall helpless (Stamcrit), to combat endless wait times. ## Why It's Good For The Game Recently, i've abused (Don't take that LITERALLY) this feature to effectively stunlock people for minutes on end, it's very much NOT fun for everyone else. This should shorten the wait times drastically, while still keeping haloperidol as an effective take-down reagent. Pray this gets merged before everyone catches on to how overpowered Haloperidol currently is. ## Changelog :cl: balance: Haloperidol now purges 2 units per second of itself, should the victim have zero stamina. (Stamcrit) /:cl: --------- Co-authored-by: Aki Ito <11748095+ExcessiveUseOfCobblestone@users.noreply.github.com> --- code/modules/reagents/chemistry/reagents/medicine_reagents.dm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index 049d1b87337df..d4f26367a5a54 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -1330,6 +1330,9 @@ if (affected_mob.get_timed_status_effect_duration(/datum/status_effect/hallucination) >= 10 SECONDS) affected_mob.adjust_hallucinations(-10 SECONDS * REM * seconds_per_tick) + if(affected_mob.getStaminaLoss() >= 100) + affected_mob.reagents.remove_reagent(type, 2 * REM * seconds_per_tick) + var/need_mob_update = FALSE if(SPT_PROB(10, seconds_per_tick)) need_mob_update += affected_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, 1, 50, affected_organ_flags) From 7f794ef12409c2df17e3bb3464af51f1da305bc9 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 12 Apr 2024 17:24:12 +1200 Subject: [PATCH 185/938] Automatic changelog for PR #82291 [ci skip] --- html/changelogs/AutoChangeLog-pr-82291.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82291.yml diff --git a/html/changelogs/AutoChangeLog-pr-82291.yml b/html/changelogs/AutoChangeLog-pr-82291.yml new file mode 100644 index 0000000000000..365329f1e6100 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82291.yml @@ -0,0 +1,4 @@ +author: "hyperjll" +delete-after: True +changes: + - balance: "Haloperidol now purges 2 units per second of itself, should the victim have zero stamina. (Stamcrit)" \ No newline at end of file From f529daf0f43e7c8ffec4fb1548521eceed2d4301 Mon Sep 17 00:00:00 2001 From: Da Cool Boss <142358580+DaCoolBoss@users.noreply.github.com> Date: Fri, 12 Apr 2024 11:51:26 +0100 Subject: [PATCH 186/938] Fixes a typo in the cargo console. (#82578) ## About The Pull Request Fixes a typo in one of the items descriptions. ## Why It's Good For The Game Fixes player facing typo. ## Changelog :cl: spellcheck: Fixes a typo in the cargo console. /:cl: --------- Co-authored-by: Jeremiah <42397676+jlsnow301@users.noreply.github.com> --- code/modules/cargo/packs/science.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/cargo/packs/science.dm b/code/modules/cargo/packs/science.dm index 7fa9013c686cf..425137cd9ed77 100644 --- a/code/modules/cargo/packs/science.dm +++ b/code/modules/cargo/packs/science.dm @@ -119,7 +119,7 @@ /datum/supply_pack/science/rped name = "RPED crate" - desc = "Need to rebuild the ORM but science got annihialted after a bomb test? \ + desc = "Need to rebuild the ORM but science got annihilated after a bomb test? \ Buy this for the most advanced parts NT can give you." cost = CARGO_CRATE_VALUE * 3 contains = list(/obj/item/storage/part_replacer/cargo) From 7a5e03fa7748495b43c9dec0c1bf2648a9dc24fc Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 12 Apr 2024 22:51:48 +1200 Subject: [PATCH 187/938] Automatic changelog for PR #82578 [ci skip] --- html/changelogs/AutoChangeLog-pr-82578.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82578.yml diff --git a/html/changelogs/AutoChangeLog-pr-82578.yml b/html/changelogs/AutoChangeLog-pr-82578.yml new file mode 100644 index 0000000000000..6a516de74aec7 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82578.yml @@ -0,0 +1,4 @@ +author: "DaCoolBoss" +delete-after: True +changes: + - spellcheck: "Fixes a typo in the cargo console." \ No newline at end of file From 318857c30280b251ab774e825bc24b03f07c1a91 Mon Sep 17 00:00:00 2001 From: Jeremiah <42397676+jlsnow301@users.noreply.github.com> Date: Fri, 12 Apr 2024 04:14:39 -0700 Subject: [PATCH 188/938] Reverts 82333 (#82608) ## About The Pull Request #82333 I was mistaken The inconsistent indentation warnings are killing me I tried ## Why It's Good For The Game Developer sanity --- .editorconfig | 22 ++++++++++++++++++++++ .vscode/extensions.json | 1 + tgui/.editorconfig | 10 ++++++++++ tools/build/.editorconfig | 10 ++++++++++ 4 files changed, 43 insertions(+) create mode 100644 .editorconfig create mode 100644 tgui/.editorconfig create mode 100644 tools/build/.editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000000..72e85029ef654 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,22 @@ +# http://editorconfig.org +root = true + +[*] +indent_style = tab +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.yml] +indent_style = space +indent_size = 2 + +[*.py] +indent_style = space + +[*.md] +trim_trailing_whitespace = false + +[Dockerfile] +indent_style = space diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 09324eb844fd5..79a1a64683a3b 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,6 +1,7 @@ { "recommendations": [ "platymuus.dm-langclient", + "EditorConfig.EditorConfig", "arcanis.vscode-zipfs", "dbaeumer.vscode-eslint", "stylemistake.auto-comment-blocks", diff --git a/tgui/.editorconfig b/tgui/.editorconfig new file mode 100644 index 0000000000000..d1d8a4176a416 --- /dev/null +++ b/tgui/.editorconfig @@ -0,0 +1,10 @@ +# http://editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/tools/build/.editorconfig b/tools/build/.editorconfig new file mode 100644 index 0000000000000..d1d8a4176a416 --- /dev/null +++ b/tools/build/.editorconfig @@ -0,0 +1,10 @@ +# http://editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true From 01492ce8e5a85174c0c6c90fd23914c969e4609f Mon Sep 17 00:00:00 2001 From: Jeremiah <42397676+jlsnow301@users.noreply.github.com> Date: Fri, 12 Apr 2024 05:26:26 -0700 Subject: [PATCH 189/938] Removes grid usage + heavy refactors (#82571) ## About The Pull Request Grid has been deprecated for quite some time and we still use it. I won't completely remove the component, this way downstreams won't immediately suffer, but I can remove it from usage. Some of these UIs had issues with them and as a hobby project I've refactored them into typescript / rebuilt them. Airlock electronics, for instance, looks substantially better.
before/after as requested current airlock electronics scrolls into oblivion ![6RJ29HCPob](https://github.com/tgstation/tgstation/assets/42397676/ba82bc20-40fa-4af0-b709-7c8846c25652) updated ![Screenshot 2024-04-11 164321](https://github.com/tgstation/tgstation/assets/42397676/05507e06-6305-4175-8476-778c345f02c8)
## Why It's Good For The Game Code improvement + probably UI bug fixes ## Changelog :cl: fix: Airlock electronics and other access-config type UIs should look much better. /:cl: --- tgui/packages/tgui/components/Grid.jsx | 33 -- tgui/packages/tgui/components/Grid.tsx | 44 +++ tgui/packages/tgui/components/Table.tsx | 2 + .../tgui/interfaces/AirlockElectronics.tsx | 264 ++++++++------- .../tgui/interfaces/CircuitAccessChecker.tsx | 8 +- .../interfaces/{DnaVault.jsx => DnaVault.tsx} | 58 ++-- .../tgui/interfaces/EightBallVote.tsx | 35 +- ...onsole.jsx => EmergencyShuttleConsole.tsx} | 80 +++-- .../tgui/interfaces/LaunchpadConsole.jsx | 276 --------------- .../tgui/interfaces/LaunchpadConsole.tsx | 259 +++++++++++++++ tgui/packages/tgui/interfaces/Mecha/data.ts | 4 +- tgui/packages/tgui/interfaces/NtosArcade.jsx | 135 -------- tgui/packages/tgui/interfaces/NtosArcade.tsx | 178 ++++++++++ .../{NuclearBomb.jsx => NuclearBomb.tsx} | 99 +++--- tgui/packages/tgui/interfaces/Roulette.jsx | 313 ------------------ .../tgui/interfaces/Roulette/BetTable.tsx | 171 ++++++++++ .../tgui/interfaces/Roulette/Board.tsx | 107 ++++++ .../tgui/interfaces/Roulette/NumberCell.tsx | 48 +++ .../tgui/interfaces/Roulette/helpers.tsx | 9 + .../tgui/interfaces/Roulette/index.tsx | 14 + .../tgui/interfaces/SyndicateContractor.tsx | 198 +++++------ .../tgui/interfaces/common/AccessConfig.jsx | 136 -------- .../tgui/interfaces/common/AccessConfig.tsx | 203 ++++++++++++ 23 files changed, 1443 insertions(+), 1231 deletions(-) delete mode 100644 tgui/packages/tgui/components/Grid.jsx create mode 100644 tgui/packages/tgui/components/Grid.tsx rename tgui/packages/tgui/interfaces/{DnaVault.jsx => DnaVault.tsx} (75%) rename tgui/packages/tgui/interfaces/{EmergencyShuttleConsole.jsx => EmergencyShuttleConsole.tsx} (73%) delete mode 100644 tgui/packages/tgui/interfaces/LaunchpadConsole.jsx create mode 100644 tgui/packages/tgui/interfaces/LaunchpadConsole.tsx delete mode 100644 tgui/packages/tgui/interfaces/NtosArcade.jsx create mode 100644 tgui/packages/tgui/interfaces/NtosArcade.tsx rename tgui/packages/tgui/interfaces/{NuclearBomb.jsx => NuclearBomb.tsx} (64%) delete mode 100644 tgui/packages/tgui/interfaces/Roulette.jsx create mode 100644 tgui/packages/tgui/interfaces/Roulette/BetTable.tsx create mode 100644 tgui/packages/tgui/interfaces/Roulette/Board.tsx create mode 100644 tgui/packages/tgui/interfaces/Roulette/NumberCell.tsx create mode 100644 tgui/packages/tgui/interfaces/Roulette/helpers.tsx create mode 100644 tgui/packages/tgui/interfaces/Roulette/index.tsx delete mode 100644 tgui/packages/tgui/interfaces/common/AccessConfig.jsx create mode 100644 tgui/packages/tgui/interfaces/common/AccessConfig.tsx diff --git a/tgui/packages/tgui/components/Grid.jsx b/tgui/packages/tgui/components/Grid.jsx deleted file mode 100644 index f5593c9e00a55..0000000000000 --- a/tgui/packages/tgui/components/Grid.jsx +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @file - * @copyright 2020 Aleksej Komarov - * @license MIT - */ - -import { Table } from './Table'; - -/** @deprecated */ -export const Grid = (props) => { - const { children, ...rest } = props; - return ( - - {children} -
- ); -}; - -/** @deprecated */ -export const GridColumn = (props) => { - const { size = 1, style, ...rest } = props; - return ( - - ); -}; - -Grid.Column = GridColumn; diff --git a/tgui/packages/tgui/components/Grid.tsx b/tgui/packages/tgui/components/Grid.tsx new file mode 100644 index 0000000000000..91c9256753bd3 --- /dev/null +++ b/tgui/packages/tgui/components/Grid.tsx @@ -0,0 +1,44 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import { PropsWithChildren } from 'react'; + +import { logger } from '../logging'; +import { BoxProps } from './Box'; +import { Table } from './Table'; + +/** @deprecated Do not use. Use stack instead. */ +export function Grid(props: PropsWithChildren) { + const { children, ...rest } = props; + logger.error('Grid component is deprecated. Use a Stack instead.'); + return ( + + {children} +
+ ); +} + +type Props = Partial<{ + /** Width of the column in percentage. */ + size: number; +}> & + BoxProps; + +/** @deprecated Do not use. Use stack instead. */ +export function GridColumn(props: Props) { + const { size = 1, style, ...rest } = props; + return ( + + ); +} + +Grid.Column = GridColumn; diff --git a/tgui/packages/tgui/components/Table.tsx b/tgui/packages/tgui/components/Table.tsx index 87edfbb8fc959..f4dcf6f3f522f 100644 --- a/tgui/packages/tgui/components/Table.tsx +++ b/tgui/packages/tgui/components/Table.tsx @@ -64,6 +64,8 @@ type CellProps = Partial<{ colSpan: number; /** Whether this is a header cell. */ header: boolean; + /** Rows for this cell to expand, assuming there is room. */ + rowSpan: number; }> & BoxProps; diff --git a/tgui/packages/tgui/interfaces/AirlockElectronics.tsx b/tgui/packages/tgui/interfaces/AirlockElectronics.tsx index 7e0ebba0bb43d..b90e8ac3b578f 100644 --- a/tgui/packages/tgui/interfaces/AirlockElectronics.tsx +++ b/tgui/packages/tgui/interfaces/AirlockElectronics.tsx @@ -1,21 +1,31 @@ import { BooleanLike } from 'common/react'; import { useBackend } from '../backend'; -import { Button, Input, LabeledList, Section } from '../components'; +import { Button, Input, LabeledList, Section, Stack } from '../components'; import { Window } from '../layouts'; -import { AccessConfig } from './common/AccessConfig'; +import { AccessConfig, Region } from './common/AccessConfig'; type Data = { + accesses: string[]; oneAccess: BooleanLike; - unres_direction: number; - passedName: string; passedCycleId: number; - regions: string[]; - accesses: string[]; + passedName: string; + regions: Region[]; shell: BooleanLike; + unres_direction: number; }; -export const AirLockMainSection = (props) => { +export function AirlockElectronics(props) { + return ( + + + + + + ); +} + +export function AirLockMainSection(props) { const { act, data } = useBackend(); const { accesses = [], @@ -28,123 +38,125 @@ export const AirLockMainSection = (props) => { } = data; return ( -
- - - { - act('set_shell', { on: !shell }); - }} - tooltip="Whether this airlock can have an integrated circuit placed inside of it or not." - /> - - -
- ); -}; - -export const AirlockElectronics = (props) => { - return ( - - - - - + + +
+ + + { + act('set_shell', { on: !shell }); + }} + tooltip="Whether this airlock can have an integrated circuit placed inside of it or not." + > + Shell + + + + + + + + + + + + + + act('passedName', { + passedName: value, + }) + } + /> + + + + act('passedCycleId', { + passedCycleId: value, + }) + } + /> + + +
+
+ + + act('set', { + access: ref, + }) + } + grantAll={() => act('grant_all')} + denyAll={() => act('clear_all')} + grantDep={(ref) => + act('grant_region', { + region: ref, + }) + } + denyDep={(ref) => + act('deny_region', { + region: ref, + }) + } + /> + +
); -}; +} diff --git a/tgui/packages/tgui/interfaces/CircuitAccessChecker.tsx b/tgui/packages/tgui/interfaces/CircuitAccessChecker.tsx index 0c81311a43167..f37414a86f52f 100644 --- a/tgui/packages/tgui/interfaces/CircuitAccessChecker.tsx +++ b/tgui/packages/tgui/interfaces/CircuitAccessChecker.tsx @@ -3,11 +3,11 @@ import { BooleanLike } from 'common/react'; import { useBackend } from '../backend'; import { Button, LabeledList } from '../components'; import { Window } from '../layouts'; -import { AccessConfig } from './common/AccessConfig'; +import { AccessConfig, Region } from './common/AccessConfig'; type Data = { oneAccess: BooleanLike; - regions: string[]; + regions: Region[]; accesses: string[]; }; @@ -28,8 +28,8 @@ export const CircuitAccessChecker = (props) => {
act('set', { access: ref, diff --git a/tgui/packages/tgui/interfaces/DnaVault.jsx b/tgui/packages/tgui/interfaces/DnaVault.tsx similarity index 75% rename from tgui/packages/tgui/interfaces/DnaVault.jsx rename to tgui/packages/tgui/interfaces/DnaVault.tsx index 5ac7711412d06..2b6781d6cf747 100644 --- a/tgui/packages/tgui/interfaces/DnaVault.jsx +++ b/tgui/packages/tgui/interfaces/DnaVault.tsx @@ -1,28 +1,44 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; import { Box, Button, - Grid, LabeledList, ProgressBar, Section, + Stack, } from '../components'; import { Window } from '../layouts'; -export const DnaVault = (props) => { - const { act, data } = useBackend(); +type Data = { + animals_max: number; + animals: number; + choiceA: string; + choiceB: string; + completed: BooleanLike; + dna_max: number; + dna: number; + plants_max: number; + plants: number; + used: BooleanLike; +}; + +export function DnaVault(props) { + const { act, data } = useBackend(); const { - completed, - used, + animals_max, + animals, choiceA, choiceB, - dna, + completed, dna_max, - plants, + dna, plants_max, - animals, - animals_max, + plants, + used, } = data; + return ( @@ -50,37 +66,39 @@ export const DnaVault = (props) => { Applicable Gene Therapy Treatments - - + + + + + + )} ); -}; +} diff --git a/tgui/packages/tgui/interfaces/EightBallVote.tsx b/tgui/packages/tgui/interfaces/EightBallVote.tsx index 30ab7baae4800..f85b8724ffefb 100644 --- a/tgui/packages/tgui/interfaces/EightBallVote.tsx +++ b/tgui/packages/tgui/interfaces/EightBallVote.tsx @@ -2,50 +2,51 @@ import { BooleanLike } from 'common/react'; import { toTitleCase } from 'common/string'; import { useBackend } from '../backend'; -import { Box, Button, Grid, NoticeBox, Section } from '../components'; +import { Box, Button, NoticeBox, Section, Stack } from '../components'; import { Window } from '../layouts'; type Data = { - shaking: BooleanLike; - question: string; answers: Answer[]; + question: string; + shaking: BooleanLike; }; type Answer = { - answer: string; amount: number; + answer: string; selected: BooleanLike; }; -export const EightBallVote = (props) => { - const { act, data } = useBackend(); +export function EightBallVote(props) { + const { data } = useBackend(); const { shaking } = data; + return ( - {(!shaking && ( + {(shaking && ( No question is currently being asked. )) || } ); -}; +} -const EightBallVoteQuestion = (props) => { +function EightBallVoteQuestion(props) { const { act, data } = useBackend(); const { question, answers = [] } = data; + return (
"{question}" - + {answers.map((answer) => ( - + {answer.amount} - + ))} - +
); -}; +} diff --git a/tgui/packages/tgui/interfaces/EmergencyShuttleConsole.jsx b/tgui/packages/tgui/interfaces/EmergencyShuttleConsole.tsx similarity index 73% rename from tgui/packages/tgui/interfaces/EmergencyShuttleConsole.jsx rename to tgui/packages/tgui/interfaces/EmergencyShuttleConsole.tsx index b7b09bdca6a84..04214e092d634 100644 --- a/tgui/packages/tgui/interfaces/EmergencyShuttleConsole.jsx +++ b/tgui/packages/tgui/interfaces/EmergencyShuttleConsole.tsx @@ -1,17 +1,34 @@ +import { BooleanLike } from 'common/react'; + import { useBackend } from '../backend'; -import { Box, Button, Grid, Section } from '../components'; +import { Box, Button, Section, Stack } from '../components'; import { Window } from '../layouts'; -export const EmergencyShuttleConsole = (props) => { - const { act, data } = useBackend(); +type Data = { + authorizations_remaining: number; + authorizations: Authorization[]; + emagged: BooleanLike; + enabled: BooleanLike; + engines_started: BooleanLike; + timer_str: string; +}; + +type Authorization = { + job: string; + name: string; +}; + +export function EmergencyShuttleConsole(props) { + const { act, data } = useBackend(); const { - timer_str, - enabled, + authorizations = [], + authorizations_remaining, emagged, + enabled, engines_started, - authorizations_remaining, - authorizations = [], + timer_str, } = data; + return ( @@ -29,41 +46,42 @@ export const EmergencyShuttleConsole = (props) => {
act('abort')} - /> + > + Repeal All + } > - - + + + + + +
@@ -71,7 +89,11 @@ export const EmergencyShuttleConsole = (props) => { } > - {authorizations.length > 0 ? ( + {authorizations.length === 0 ? ( + + No Active Authorizations + + ) : ( authorizations.map((authorization) => ( { {authorization.name} ({authorization.job}) )) - ) : ( - - No Active Authorizations - )}
@@ -93,4 +111,4 @@ export const EmergencyShuttleConsole = (props) => {
); -}; +} diff --git a/tgui/packages/tgui/interfaces/LaunchpadConsole.jsx b/tgui/packages/tgui/interfaces/LaunchpadConsole.jsx deleted file mode 100644 index c3145844fc21f..0000000000000 --- a/tgui/packages/tgui/interfaces/LaunchpadConsole.jsx +++ /dev/null @@ -1,276 +0,0 @@ -import { useBackend } from '../backend'; -import { - Box, - Button, - Divider, - Flex, - Grid, - Input, - NoticeBox, - NumberInput, - Section, -} from '../components'; -import { Window } from '../layouts'; - -const LaunchpadButtonPad = (props) => { - const { act } = useBackend(); - return ( - - - + + + + ); +} + +function LaunchpadButtonPad(props) { + const { act } = useBackend(); + + return ( +
+ + {buttonConfigs.map((buttonRow, i) => ( + + {buttonRow.map((buttonConfig, j) => ( + + ))} + + ))} + +
+ ); +} + +function TargetingControls(props) { + const { act, data } = useBackend(); + const { x, y, range } = data; + + const inputConfigs = [ + { value: x, axis: 'x', icon: 'arrows-alt-h' }, + { value: y, axis: 'y', icon: 'arrows-alt-v' }, + ]; + + return ( +
+ {inputConfigs.map((inputConfig, i) => ( + + + + {inputConfig.axis.toUpperCase()} + + + + + act('set_pos', { + [inputConfig.axis]: value, + }) + } + step={1} + stepPixelSize={10} + value={inputConfig.value} + width="90px" + /> + + + ))} +
+ ); +} + +function DeliveryButtons(props) { + const { act } = useBackend(); + + return ( +
+ + + + + + + + +
+ ); +} diff --git a/tgui/packages/tgui/interfaces/Mecha/data.ts b/tgui/packages/tgui/interfaces/Mecha/data.ts index 993c7a1d4beec..0bccc7fa5c1a0 100644 --- a/tgui/packages/tgui/interfaces/Mecha/data.ts +++ b/tgui/packages/tgui/interfaces/Mecha/data.ts @@ -1,5 +1,7 @@ import { BooleanLike } from 'common/react'; +import { Region } from '../common/AccessConfig'; + export type AccessData = { name: string; number: number; @@ -25,7 +27,7 @@ export type MainData = { overclock_temp_percentage: number; one_access: BooleanLike; - regions: string[]; + regions: Region[]; accesses: string[]; servo_rating: number; diff --git a/tgui/packages/tgui/interfaces/NtosArcade.jsx b/tgui/packages/tgui/interfaces/NtosArcade.jsx deleted file mode 100644 index b8c9aa05109e6..0000000000000 --- a/tgui/packages/tgui/interfaces/NtosArcade.jsx +++ /dev/null @@ -1,135 +0,0 @@ -import { resolveAsset } from '../assets'; -import { useBackend } from '../backend'; -import { - AnimatedNumber, - Box, - Button, - Grid, - LabeledList, - ProgressBar, - Section, -} from '../components'; -import { NtosWindow } from '../layouts'; - -export const NtosArcade = (props) => { - const { act, data } = useBackend(); - return ( - - -
- - - - - - - - {data.PlayerHitpoints}HP - - - - - {data.PlayerMP}MP - - - - -
- {data.Status} -
-
- - - - HP - - -
- -
-
-
- -
-
-
- ); -}; diff --git a/tgui/packages/tgui/interfaces/NtosArcade.tsx b/tgui/packages/tgui/interfaces/NtosArcade.tsx new file mode 100644 index 0000000000000..ea63e62e037bb --- /dev/null +++ b/tgui/packages/tgui/interfaces/NtosArcade.tsx @@ -0,0 +1,178 @@ +import { BooleanLike } from 'common/react'; + +import { resolveAsset } from '../assets'; +import { useBackend } from '../backend'; +import { + AnimatedNumber, + Box, + Button, + Divider, + LabeledList, + NoticeBox, + ProgressBar, + Section, + Stack, +} from '../components'; +import { NtosWindow } from '../layouts'; + +type Data = { + BossID: string; + GameActive: BooleanLike; + Hitpoints: number; + PauseState: BooleanLike; + PlayerHitpoints: number; + PlayerMP: number; + Status: string; + TicketCount: number; +}; + +export function NtosArcade(props) { + return ( + + +
+ + + + + + + + + +
+
+
+ ); +} + +function PlayerStats(props) { + const { data } = useBackend(); + const { PauseState, PlayerHitpoints, PlayerMP, Status } = data; + + return ( + <> + + + + {PlayerHitpoints}HP + + + + + {PlayerMP}MP + + + + + {Status} + + ); +} + +function BossBar(props) { + const { data } = useBackend(); + const { BossID, Hitpoints } = data; + + return ( + <> + + + HP + + +
+ +
+ + ); +} + +function BottomButtons(props) { + const { act, data } = useBackend(); + const { GameActive, PauseState, TicketCount } = data; + + return ( + <> + + + + + + + + + = 1 ? 'good' : 'normal'}> + Earned Tickets: {TicketCount} + + + ); +} diff --git a/tgui/packages/tgui/interfaces/NuclearBomb.jsx b/tgui/packages/tgui/interfaces/NuclearBomb.tsx similarity index 64% rename from tgui/packages/tgui/interfaces/NuclearBomb.jsx rename to tgui/packages/tgui/interfaces/NuclearBomb.tsx index 81b2e622e9d50..5cda6d97cbb40 100644 --- a/tgui/packages/tgui/interfaces/NuclearBomb.jsx +++ b/tgui/packages/tgui/interfaces/NuclearBomb.tsx @@ -1,32 +1,40 @@ -import { classes } from 'common/react'; +import { BooleanLike, classes } from 'common/react'; import { useBackend } from '../backend'; -import { Box, Button, Flex, Grid, Icon } from '../components'; +import { Box, Button, Icon, Stack } from '../components'; import { Window } from '../layouts'; +type Data = { + disk_present: BooleanLike; + status1: string; + status2: string; + anchored: BooleanLike; +}; + +const KEYPAD = [ + ['1', '4', '7', 'C'], + ['2', '5', '8', '0'], + ['3', '6', '9', 'E'], +] as const; + // This ui is so many manual overrides and !important tags // and hand made width sets that changing pretty much anything // is going to require a lot of tweaking it get it looking correct again // I'm sorry, but it looks bangin -export const NukeKeypad = (props) => { +export function NukeKeypad(props) { const { act } = useBackend(); - const keypadKeys = [ - ['1', '4', '7', 'C'], - ['2', '5', '8', '0'], - ['3', '6', '9', 'E'], - ]; + return ( - - {keypadKeys.map((keyColumn) => ( - + + {KEYPAD.map((keyColumn) => ( + {keyColumn.map((key) => ( ))} - + ))} - + ); -}; +} + +export function NuclearBomb(props) { + const { act, data } = useBackend(); + const { status1, status2 } = data; -export const NuclearBomb = (props) => { - const { act, data } = useBackend(); - const { anchored, disk_present, status1, status2 } = data; return ( - - + + {status1} - - + + {status2} - - + + - - + + ); -}; +} diff --git a/tgui/packages/tgui/interfaces/Roulette.jsx b/tgui/packages/tgui/interfaces/Roulette.jsx deleted file mode 100644 index e07cf4e0ef463..0000000000000 --- a/tgui/packages/tgui/interfaces/Roulette.jsx +++ /dev/null @@ -1,313 +0,0 @@ -import { classes } from 'common/react'; -import { useState } from 'react'; - -import { useBackend } from '../backend'; -import { Box, Button, Grid, NumberInput, Table } from '../components'; -import { Window } from '../layouts'; - -const getNumberColor = (number) => { - const inRedOddRange = - (number >= 1 && number <= 10) || (number >= 19 && number <= 28); - - if (number % 2 === 1) { - return inRedOddRange ? 'red' : 'black'; - } - return inRedOddRange ? 'black' : 'red'; -}; - -export const RouletteNumberCell = (props) => { - const { - buttonClass = null, - cellClass = null, - color, - colspan = '1', - rowspan = '1', - text, - value, - } = props; - const { act } = useBackend(); - - return ( - - - - ); -}; - -export const RouletteBoard = () => { - const firstRow = [3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36]; - const secondRow = [2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35]; - const thirdRow = [1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34]; - const fourthRow = { - 's1-12': '1st 12', - 's13-24': '2nd 12', - 's25-36': '3rd 12', - }; - const fifthRow = [ - { color: 'transparent', text: '1-18', value: 's1-18' }, - { color: 'transparent', text: 'Even', value: 'even' }, - { color: 'black', text: 'Black', value: 'black' }, - { color: 'red', text: 'Red', value: 'red' }, - { color: 'transparent', text: 'Odd', value: 'odd' }, - { color: 'transparent', text: '19-36', value: 's19-36' }, - ]; - - return ( - - - - - {firstRow.map((number) => ( - - ))} - - - - {secondRow.map((number) => ( - - ))} - - - - {thirdRow.map((number) => ( - - ))} - - - - - {Object.entries(fourthRow).map(([value, text]) => ( - - ))} - - - - {fifthRow.map((cell) => ( - - ))} - -
-
- ); -}; - -export const RouletteBetTable = (props) => { - const { act, data } = useBackend(); - - const [customBet, setCustomBet] = useState(500); - - let { BetType } = data; - - if (BetType.startsWith('s')) { - BetType = BetType.substring(1, BetType.length); - } - - return ( - - - - Last Spin: - - - Current Bet: - - - - - {data.LastSpin} - - - - {data.BetAmount} cr on {BetType} - - -
- ); -}; - -export const Roulette = (props) => { - return ( - - - - - - - ); -}; diff --git a/tgui/packages/tgui/interfaces/Roulette/BetTable.tsx b/tgui/packages/tgui/interfaces/Roulette/BetTable.tsx new file mode 100644 index 0000000000000..8abf081b288a3 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Roulette/BetTable.tsx @@ -0,0 +1,171 @@ +import { BooleanLike, classes } from 'common/react'; +import { useState } from 'react'; + +import { useBackend } from '../../backend'; +import { Box, Button, NumberInput, Stack, Table } from '../../components'; +import { getNumberColor } from './helpers'; + +type Data = { + IsAnchored: BooleanLike; + BetAmount: number; + BetType: string; + HouseBalance: number; + LastSpin: number; + Spinning: BooleanLike; + AccountBalance: number; + CanUnbolt: BooleanLike; +}; + +export function RouletteBetTable(props) { + const { act, data } = useBackend(); + const { LastSpin, HouseBalance, BetAmount, IsAnchored } = data; + + const [customBet, setCustomBet] = useState(500); + + let BetType = data.BetType; + + if (BetType.startsWith('s')) { + BetType = BetType.substring(1, BetType.length); + } + + return ( + + + + Last Spin: + + + Current Bet: + + + + + {LastSpin} + + + + {BetAmount} cr on {BetType} + + + + + + + + + + + + setCustomBet(value)} + /> + + + + + + + + + Swipe an ID card with a connected account to spin! + + + + + + + House Balance: + + {HouseBalance ? HouseBalance + ' cr' : 'None'} + + + + + +
+ ); +} diff --git a/tgui/packages/tgui/interfaces/Roulette/Board.tsx b/tgui/packages/tgui/interfaces/Roulette/Board.tsx new file mode 100644 index 0000000000000..0f0fbcdc681c1 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Roulette/Board.tsx @@ -0,0 +1,107 @@ +import { Box, Table } from '../../components'; +import { getNumberColor } from './helpers'; +import { RouletteNumberCell } from './NumberCell'; + +const firstRow = [3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36] as const; +const secondRow = [2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35] as const; +const thirdRow = [1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34] as const; +const fourthRow = { + 's1-12': '1st 12', + 's13-24': '2nd 12', + 's25-36': '3rd 12', +} as const; +const fifthRow = [ + { color: 'transparent', text: '1-18', value: 's1-18' }, + { color: 'transparent', text: 'Even', value: 'even' }, + { color: 'black', text: 'Black', value: 'black' }, + { color: 'red', text: 'Red', value: 'red' }, + { color: 'transparent', text: 'Odd', value: 'odd' }, + { color: 'transparent', text: '19-36', value: 's19-36' }, +] as const; + +export function RouletteBoard(props) { + return ( + + + + + {firstRow.map((number) => ( + + ))} + + + + {secondRow.map((number) => ( + + ))} + + + + {thirdRow.map((number) => ( + + ))} + + + + + {Object.entries(fourthRow).map(([value, text]) => ( + + ))} + + + + {fifthRow.map((cell) => ( + + ))} + +
+
+ ); +} diff --git a/tgui/packages/tgui/interfaces/Roulette/NumberCell.tsx b/tgui/packages/tgui/interfaces/Roulette/NumberCell.tsx new file mode 100644 index 0000000000000..1b8143905c314 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Roulette/NumberCell.tsx @@ -0,0 +1,48 @@ +import { classes } from 'common/react'; + +import { useBackend } from '../../backend'; +import { Button, Table } from '../../components'; + +type Props = { + color: string; + text: string; + value: string; +} & Partial<{ + buttonClass: string; + cellClass: string; + colspan: number; + rowspan: number; +}>; + +export function RouletteNumberCell(props: Props) { + const { + buttonClass, + cellClass, + color, + colspan = 1, + rowspan = 1, + text, + value, + } = props; + const { act } = useBackend(); + + return ( + + + + ); +} diff --git a/tgui/packages/tgui/interfaces/Roulette/helpers.tsx b/tgui/packages/tgui/interfaces/Roulette/helpers.tsx new file mode 100644 index 0000000000000..b5c4f9b9b3330 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Roulette/helpers.tsx @@ -0,0 +1,9 @@ +export function getNumberColor(number: number): 'red' | 'black' { + const inRedOddRange = + (number >= 1 && number <= 10) || (number >= 19 && number <= 28); + + if (number % 2 === 1) { + return inRedOddRange ? 'red' : 'black'; + } + return inRedOddRange ? 'black' : 'red'; +} diff --git a/tgui/packages/tgui/interfaces/Roulette/index.tsx b/tgui/packages/tgui/interfaces/Roulette/index.tsx new file mode 100644 index 0000000000000..8c27a052a02f6 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Roulette/index.tsx @@ -0,0 +1,14 @@ +import { Window } from '../../layouts'; +import { RouletteBetTable } from './BetTable'; +import { RouletteBoard } from './Board'; + +export function Roulette(props) { + return ( + + + + + + + ); +} diff --git a/tgui/packages/tgui/interfaces/SyndicateContractor.tsx b/tgui/packages/tgui/interfaces/SyndicateContractor.tsx index 81e01d682d73a..66c0726398106 100644 --- a/tgui/packages/tgui/interfaces/SyndicateContractor.tsx +++ b/tgui/packages/tgui/interfaces/SyndicateContractor.tsx @@ -5,32 +5,21 @@ import { Box, Button, Flex, - Grid, Icon, LabeledList, Modal, NoticeBox, Section, + Stack, } from '../components'; import { FakeTerminal } from '../components/FakeTerminal'; import { NtosWindow } from '../layouts'; -const CONTRACT_STATUS_INACTIVE = 1; -const CONTRACT_STATUS_ACTIVE = 2; -const CONTRACT_STATUS_BOUNTY_CONSOLE_ACTIVE = 3; -const CONTRACT_STATUS_EXTRACTING = 4; -const CONTRACT_STATUS_COMPLETE = 5; -const CONTRACT_STATUS_ABORTED = 6; - -export const SyndicateContractor = (props) => { - return ( - - - - - - ); -}; +enum CONTRACT { + Inactive = 1, + Active = 2, + Complete = 5, +} type Data = { contracts_completed: number; @@ -59,7 +48,47 @@ type ContractData = { target: string; }; -export const SyndicateContractorContent = (props) => { +const infoEntries = [ + 'SyndTract v2.0', + '', + "We've identified potentional high-value targets that are", + 'currently assigned to your mission area. They are believed', + 'to hold valuable information which could be of immediate', + 'importance to our organisation.', + '', + 'Listed below are all of the contracts available to you. You', + 'are to bring the specified target to the designated', + 'drop-off, and contact us via this uplink. We will send', + 'a specialised extraction unit to put the body into.', + '', + 'We want targets alive - but we will sometimes pay slight', + "amounts if they're not, you just won't receive the shown", + 'bonus. You can redeem your payment through this uplink in', + 'the form of raw telecrystals, which can be put into your', + 'regular Syndicate uplink to purchase whatever you may need.', + 'We provide you with these crystals the moment you send the', + 'target up to us, which can be collected at anytime through', + 'this system.', + '', + 'Targets extracted will be ransomed back to the station once', + 'their use to us is fulfilled, with us providing you a small', + 'percentage cut. You may want to be mindful of them', + 'identifying you when they come back. We provide you with', + 'a standard contractor loadout, which will help cover your', + 'identity.', +] as const; + +export function SyndicateContractor(props) { + return ( + + + + + + ); +} + +function SyndicateContractorContent(props) { const { data, act } = useBackend(); const { error, logged_in, first_load, info_screen } = data; @@ -84,37 +113,7 @@ export const SyndicateContractorContent = (props) => { 'Searching for available contracts...', 'CONTRACTS FOUND', 'WELCOME, AGENT', - ]; - - const infoEntries = [ - 'SyndTract v2.0', - '', - "We've identified potentional high-value targets that are", - 'currently assigned to your mission area. They are believed', - 'to hold valuable information which could be of immediate', - 'importance to our organisation.', - '', - 'Listed below are all of the contracts available to you. You', - 'are to bring the specified target to the designated', - 'drop-off, and contact us via this uplink. We will send', - 'a specialised extraction unit to put the body into.', - '', - 'We want targets alive - but we will sometimes pay slight', - "amounts if they're not, you just won't receive the shown", - 'bonus. You can redeem your payment through this uplink in', - 'the form of raw telecrystals, which can be put into your', - 'regular Syndicate uplink to purchase whatever you may need.', - 'We provide you with these crystals the moment you send the', - 'target up to us, which can be collected at anytime through', - 'this system.', - '', - 'Targets extracted will be ransomed back to the station once', - 'their use to us is fulfilled, with us providing you a small', - 'percentage cut. You may want to be mindful of them', - 'identifying you when they come back. We provide you with', - 'a standard contractor loadout, which will help cover your', - 'identity.', - ]; + ] as const; const errorPane = !!error && ( @@ -126,7 +125,7 @@ export const SyndicateContractorContent = (props) => { {error} - @@ -136,11 +135,9 @@ export const SyndicateContractorContent = (props) => { return (
- {!!error && {error}}
@@ -167,11 +164,12 @@ export const SyndicateContractorContent = (props) => {
); } @@ -183,38 +181,38 @@ export const SyndicateContractorContent = (props) => { ); -}; +} -export const StatusPane = (props) => { +function StatusPane(props) { const { act, data } = useBackend(); const { redeemable_tc, earned_tc, contracts_completed } = data; return (
- Contractor Status - } + title="Contractor Status" > - - + + act('PRG_redeem_TC')} - /> + > + Claim + } > {String(redeemable_tc)} @@ -223,24 +221,28 @@ export const StatusPane = (props) => { {String(earned_tc)} - - + + {String(contracts_completed)} ACTIVE - - + +
); -}; +} -const ContractsTab = (props) => { +function ContractsTab(props) { const { act, data } = useBackend(); - const { contracts, ongoing_contract, extraction_enroute, dropoff_direction } = - data; + const { + contracts = [], + ongoing_contract, + extraction_enroute, + dropoff_direction, + } = data; return ( <> @@ -248,18 +250,19 @@ const ContractsTab = (props) => { title="Available Contracts" buttons={ } > {contracts.map((contract) => { - if (ongoing_contract && contract.status !== CONTRACT_STATUS_ACTIVE) { + if (ongoing_contract && contract.status !== CONTRACT.Active) { return; } - const active = contract.status > CONTRACT_STATUS_INACTIVE; - if (contract.status >= CONTRACT_STATUS_COMPLETE) { + const active = contract.status > CONTRACT.Inactive; + if (contract.status >= CONTRACT.Complete) { return; } return ( @@ -276,27 +279,28 @@ const ContractsTab = (props) => { {`${contract.payout} (+${contract.payout_bonus}) TC`} } > - - {contract.message} - + + {contract.message} + Dropoff Location: {contract.dropoff} - - + + ); })} @@ -310,4 +314,4 @@ const ContractsTab = (props) => { ); -}; +} diff --git a/tgui/packages/tgui/interfaces/common/AccessConfig.jsx b/tgui/packages/tgui/interfaces/common/AccessConfig.jsx deleted file mode 100644 index e91abecbde794..0000000000000 --- a/tgui/packages/tgui/interfaces/common/AccessConfig.jsx +++ /dev/null @@ -1,136 +0,0 @@ -import { sortBy } from 'common/collections'; -import { useState } from 'react'; - -import { Button, Flex, Grid, Section, Tabs } from '../../components'; - -export const AccessConfig = (props) => { - const { - accesses = [], - selectedList = [], - accessMod, - grantAll, - denyAll, - grantDep, - denyDep, - } = props; - const [selectedAccessName, setSelectedAccessName] = useState( - accesses[0]?.name, - ); - const selectedAccess = accesses.find( - (access) => access.name === selectedAccessName, - ); - const selectedAccessEntries = sortBy((entry) => entry.desc)( - selectedAccess?.accesses || [], - ); - - const checkAccessIcon = (accesses) => { - let oneAccess = false; - let oneInaccess = false; - for (let element of accesses) { - if (selectedList.includes(element.ref)) { - oneAccess = true; - } else { - oneInaccess = true; - } - } - if (!oneAccess && oneInaccess) { - return 0; - } else if (oneAccess && oneInaccess) { - return 1; - } else { - return 2; - } - }; - - return ( -
-
- ); -}; - -const diffMap = { - 0: { - icon: 'times-circle', - color: 'bad', - }, - 1: { - icon: 'stop-circle', - color: null, - }, - 2: { - icon: 'check-circle', - color: 'good', - }, -}; diff --git a/tgui/packages/tgui/interfaces/common/AccessConfig.tsx b/tgui/packages/tgui/interfaces/common/AccessConfig.tsx new file mode 100644 index 0000000000000..99f783dbdbc3d --- /dev/null +++ b/tgui/packages/tgui/interfaces/common/AccessConfig.tsx @@ -0,0 +1,203 @@ +import { sortBy } from 'common/collections'; +import { useState } from 'react'; + +import { Button, Section, Stack, Tabs } from '../../components'; + +type BaseProps = { + accessMod: (ref: string) => void; + denyDep: (ref: string) => void; + grantDep: (ref: string) => void; +}; + +type ConfigProps = { + accesses: Region[]; + denyAll: () => void; + grantAll: () => void; + selectedList: string[]; +} & BaseProps; + +type AccessButtonProps = { + selectedAccess: Region; + selectedAccessEntries: Area[]; + selectedList: string[]; +} & BaseProps; + +export type Region = { + accesses: Area[]; + name: string; +}; + +export type Area = { + desc: string; + ref: string; +}; + +enum ACCESS { + Denied = 0, + Partial = 1, + Granted = 2, +} + +const DIFFMAP = [ + { + icon: 'times-circle', + color: 'bad', + }, + { + icon: 'stop-circle', + color: null, + }, + { + icon: 'check-circle', + color: 'good', + }, +] as const; + +export function AccessConfig(props: ConfigProps) { + const { + accesses = [], + selectedList = [], + accessMod, + grantAll, + denyAll, + grantDep, + denyDep, + } = props; + + const [selectedAccessName, setSelectedAccessName] = useState( + accesses[0]?.name, + ); + + const selectedAccess = + accesses.find((access) => access.name === selectedAccessName) || + accesses[0]; + + const selectedAccessEntries = sortBy((entry: Area) => entry.desc)( + selectedAccess?.accesses || [], + ); + + function checkAccessIcon(accesses: Area[]) { + let oneAccess = false; + let oneInaccess = false; + for (let element of accesses) { + if (selectedList.includes(element.ref)) { + oneAccess = true; + } else { + oneInaccess = true; + } + } + if (!oneAccess && oneInaccess) { + return ACCESS.Denied; + } else if (oneAccess && oneInaccess) { + return ACCESS.Partial; + } else { + return ACCESS.Granted; + } + } + + return ( +
+ + + + } + > + + + + {accesses.map((access) => { + const entries = access.accesses || []; + const icon = DIFFMAP[checkAccessIcon(entries)].icon; + const color = DIFFMAP[checkAccessIcon(entries)].color; + return ( + setSelectedAccessName(access.name)} + > + {access.name} + + ); + })} + + + + + + + +
+ ); +} + +function AccessButtons(props: AccessButtonProps) { + const { + selectedAccessEntries, + selectedList, + accessMod, + grantDep, + denyDep, + selectedAccess, + } = props; + + return ( + + + + + + + + + + + + + +
+ {selectedAccessEntries.map((entry) => ( + accessMod(entry.ref)} + > + {entry.desc} + + ))} +
+
+
+ ); +} From 87612430478ce4d721ff952015ad47104b126cf7 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sat, 13 Apr 2024 00:26:47 +1200 Subject: [PATCH 190/938] Automatic changelog for PR #82571 [ci skip] --- html/changelogs/AutoChangeLog-pr-82571.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82571.yml diff --git a/html/changelogs/AutoChangeLog-pr-82571.yml b/html/changelogs/AutoChangeLog-pr-82571.yml new file mode 100644 index 0000000000000..0f9970e8c90ee --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82571.yml @@ -0,0 +1,4 @@ +author: "jlsnow301" +delete-after: True +changes: + - bugfix: "Airlock electronics and other access-config type UIs should look much better." \ No newline at end of file From f5dd89ba00867156bc42305962d2695a22e77bfc Mon Sep 17 00:00:00 2001 From: The Sharkening <95130227+StrangeWeirdKitten@users.noreply.github.com> Date: Fri, 12 Apr 2024 11:47:21 -0600 Subject: [PATCH 191/938] Moves the GPS component from the upload computers and communications console to the boards themselves when used (#82574) ## About The Pull Request Moves the GPS component on Upload computers and Communications Console to be handled from the board, not the machine, when a board is used to modify the AI or used to login. ## Why It's Good For The Game Quite frankely, the mechanic already exists. But it does not work due to the component being attatched to the computer. Currently it's intended for these critical computers to give GPS signals because they can be taken, and built extremely easily, anywhere, and deconstructed. Especially the upload boards, since the AI and borgs are directly in the center of it when people keep subverting and fixing laws. This is extremely annoying for the silicons. On top of that, you building a communications console to hack in maint somewhere will leave some sort of a trace to justify the reward. Yes, they have a computer that sends out the GPS signal. But anyone with a brain could realize all that's needed to circumvent this mechanic is the use of a screwdriver. Now, the GPS is registered on the boards themselves. The boards get stored in the contents of the computer. You can't circumvent this now. ## Changelog :cl: balance: The upload and communication boards directly have trackers installed, activated only when authenticated. /:cl: --------- Co-authored-by: Jacquerel --- code/game/machinery/computer/_computer.dm | 10 ++++++++++ code/game/machinery/computer/communications.dm | 3 ++- code/game/machinery/computer/law.dm | 2 +- .../items/circuitboards/computer_circuitboards.dm | 5 +++++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/code/game/machinery/computer/_computer.dm b/code/game/machinery/computer/_computer.dm index c2ef2258e3338..1592bb010c314 100644 --- a/code/game/machinery/computer/_computer.dm +++ b/code/game/machinery/computer/_computer.dm @@ -87,6 +87,16 @@ playsound(loc, 'sound/effects/glassbr3.ogg', 100, TRUE) set_light(0) +/obj/machinery/computer/proc/imprint_gps(gps_tag) // Currently used by the upload computers and communications console + var/tracker = gps_tag + if(!tracker) // Don't give a null GPS signal if there is none + return + for(var/obj/item/circuitboard/computer/board in src.contents) + if(!contents || board.GetComponent(/datum/component/gps)) + return + board.AddComponent(/datum/component/gps, "[tracker]") + balloon_alert_to_viewers("board tracker enabled", vision_distance = 1) + /obj/machinery/computer/emp_act(severity) . = ..() if (!(. & EMP_PROTECT_SELF)) diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 8cbd7326d8854..73b0474307864 100644 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -91,7 +91,6 @@ REGISTER_REQUIRED_MAP_ITEM(1, INFINITY) GLOB.shuttle_caller_list += src - AddComponent(/datum/component/gps, "Secured Communications Signal") /// Are we NOT a silicon, AND we're logged in as the captain? /obj/machinery/computer/communications/proc/authenticated_as_non_silicon_captain(mob/user) @@ -419,6 +418,8 @@ state = STATE_MAIN playsound(src, 'sound/machines/terminal_on.ogg', 50, FALSE) + imprint_gps(gps_tag = "Encrypted Communications Channel") + if ("toggleEmergencyAccess") if(emergency_access_cooldown(usr)) //if were in cooldown, dont allow the following code return diff --git a/code/game/machinery/computer/law.dm b/code/game/machinery/computer/law.dm index 372d75822b7e4..816177f9f0edd 100644 --- a/code/game/machinery/computer/law.dm +++ b/code/game/machinery/computer/law.dm @@ -7,7 +7,6 @@ /obj/machinery/computer/upload/Initialize(mapload) . = ..() - AddComponent(/datum/component/gps, "Encrypted Upload") if(!mapload) log_silicon("\A [name] was created at [loc_name(src)].") message_admins("\A [name] was created at [ADMIN_VERBOSEJMP(src)].") @@ -29,6 +28,7 @@ current = null return M.install(current.laws, user) + imprint_gps(gps_tag = "Weak Upload Signal") else return ..() diff --git a/code/game/objects/items/circuitboards/computer_circuitboards.dm b/code/game/objects/items/circuitboards/computer_circuitboards.dm index e0e5c31c99fa1..41950561571d6 100644 --- a/code/game/objects/items/circuitboards/computer_circuitboards.dm +++ b/code/game/objects/items/circuitboards/computer_circuitboards.dm @@ -2,6 +2,11 @@ name = "Generic" name_extension = "(Computer Board)" +/obj/item/circuitboard/computer/examine() + . = ..() + if(GetComponent(/datum/component/gps)) + . += span_info("there's a small, blinking light!") + //Command /obj/item/circuitboard/computer/aiupload From ef772e8b0c5f82fce2aad25f38fb3d4659db0d66 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sat, 13 Apr 2024 05:47:39 +1200 Subject: [PATCH 192/938] Automatic changelog for PR #82574 [ci skip] --- html/changelogs/AutoChangeLog-pr-82574.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82574.yml diff --git a/html/changelogs/AutoChangeLog-pr-82574.yml b/html/changelogs/AutoChangeLog-pr-82574.yml new file mode 100644 index 0000000000000..adf755aa3d656 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82574.yml @@ -0,0 +1,4 @@ +author: "StrangeWeirdKitten" +delete-after: True +changes: + - balance: "The upload and communication boards directly have trackers installed, activated only when authenticated." \ No newline at end of file From 1456aecdb463b8e3895038b31802beb3d416e62a Mon Sep 17 00:00:00 2001 From: Jeremiah <42397676+jlsnow301@users.noreply.github.com> Date: Fri, 12 Apr 2024 10:47:52 -0700 Subject: [PATCH 193/938] [No GBP] Removes cogbar from some stealthy actions (#82593) ## About The Pull Request Issue brought some missed hidden actions to my attention. I left cogbars in for _breaking_ handcuffs because resisting is sort of a gray area. On one hand, you don't want someone to see you doing it; on the other, there is a visible warning that you started doing it. So, meet in the the middle, breaking handcuffs is still visible while resisting isn't. ## Why It's Good For The Game Closes #82583 Cogbars are not intended to ruin stealth ## Changelog :cl: fix: Deviants buffed: Rogue shoelacing, pickpocketing and restraint resisting no longer give cogbar icons. /:cl: --- code/datums/elements/strippable.dm | 4 +- .../structures/beds_chairs/alien_nest.dm | 64 +++++++------- code/game/objects/structures/kitchen_spike.dm | 2 +- code/modules/clothing/shoes/_shoes.dm | 13 ++- code/modules/mob/living/carbon/carbon.dm | 87 +++++++++++-------- .../living/carbon/human/human_stripping.dm | 2 +- 6 files changed, 94 insertions(+), 78 deletions(-) diff --git a/code/datums/elements/strippable.dm b/code/datums/elements/strippable.dm index 5e36ade328087..18dffff6aedff 100644 --- a/code/datums/elements/strippable.dm +++ b/code/datums/elements/strippable.dm @@ -276,8 +276,8 @@ source.log_message("had [item] put on them by [key_name(user)].", LOG_VICTIM, color="orange", log_globally=FALSE) /// A utility function for `/datum/strippable_item`s to start unequipping an item from a mob. -/proc/start_unequip_mob(obj/item/item, mob/source, mob/user, strip_delay) - if (!do_after(user, strip_delay || item.strip_delay, source, interaction_key = REF(item))) +/proc/start_unequip_mob(obj/item/item, mob/source, mob/user, strip_delay, hidden = FALSE) + if (!do_after(user, strip_delay || item.strip_delay, source, interaction_key = REF(item), hidden = hidden)) return FALSE return TRUE diff --git a/code/game/objects/structures/beds_chairs/alien_nest.dm b/code/game/objects/structures/beds_chairs/alien_nest.dm index 1654cecff4556..77759c9e309b0 100644 --- a/code/game/objects/structures/beds_chairs/alien_nest.dm +++ b/code/game/objects/structures/beds_chairs/alien_nest.dm @@ -24,37 +24,39 @@ /obj/structure/bed/nest/wrench_act_secondary(mob/living/user, obj/item/weapon) return ITEM_INTERACT_BLOCKING -/obj/structure/bed/nest/user_unbuckle_mob(mob/living/buckled_mob, mob/living/user) - if(has_buckled_mobs()) - for(var/buck in buckled_mobs) //breaking a nest releases all the buckled mobs, because the nest isn't holding them down anymore - var/mob/living/M = buck - - if(user.get_organ_by_type(/obj/item/organ/internal/alien/plasmavessel)) - unbuckle_mob(M) - add_fingerprint(user) - return - - if(M != user) - M.visible_message(span_notice("[user.name] pulls [M.name] free from the sticky nest!"),\ - span_notice("[user.name] pulls you free from the gelatinous resin."),\ - span_hear("You hear squelching...")) - else - M.visible_message(span_warning("[M.name] struggles to break free from the gelatinous resin!"),\ - span_notice("You struggle to break free from the gelatinous resin... (Stay still for about a minute and a half.)"),\ - span_hear("You hear squelching...")) - if(!do_after(M, 100 SECONDS, target = src)) - if(M?.buckled) - to_chat(M, span_warning("You fail to unbuckle yourself!")) - return - if(!M.buckled) - return - M.visible_message(span_warning("[M.name] breaks free from the gelatinous resin!"),\ - span_notice("You break free from the gelatinous resin!"),\ - span_hear("You hear squelching...")) - - - unbuckle_mob(M) - add_fingerprint(user) + +/obj/structure/bed/nest/user_unbuckle_mob(mob/living/captive, mob/living/hero) + if(!length(buckled_mobs)) + return + + if(hero.get_organ_by_type(/obj/item/organ/internal/alien/plasmavessel)) + unbuckle_mob(captive) + add_fingerprint(hero) + return + + if(captive != hero) + captive.visible_message(span_notice("[hero.name] pulls [captive.name] free from the sticky nest!"), + span_notice("[hero.name] pulls you free from the gelatinous resin."), + span_hear("You hear squelching...")) + unbuckle_mob(captive) + add_fingerprint(hero) + return + + captive.visible_message(span_warning("[captive.name] struggles to break free from the gelatinous resin!"), + span_notice("You struggle to break free from the gelatinous resin... (Stay still for about a minute and a half.)"), + span_hear("You hear squelching...")) + + if(!do_after(captive, 100 SECONDS, target = src, hidden = TRUE)) + if(captive.buckled) + to_chat(captive, span_warning("You fail to unbuckle yourself!")) + return + + captive.visible_message(span_warning("[captive.name] breaks free from the gelatinous resin!"), + span_notice("You break free from the gelatinous resin!"), + span_hear("You hear squelching...")) + + unbuckle_mob(captive) + add_fingerprint(hero) /obj/structure/bed/nest/user_buckle_mob(mob/living/M, mob/user, check_loc = TRUE) if ( !ismob(M) || (get_dist(src, user) > 1) || (M.loc != src.loc) || user.incapacitated() || M.buckled ) diff --git a/code/game/objects/structures/kitchen_spike.dm b/code/game/objects/structures/kitchen_spike.dm index bfb26d481a28c..0cc73b9adef9c 100644 --- a/code/game/objects/structures/kitchen_spike.dm +++ b/code/game/objects/structures/kitchen_spike.dm @@ -143,7 +143,7 @@ span_notice("You struggle to break free from [src], exacerbating your wounds! (Stay still for two minutes.)"),\ span_hear("You hear a wet squishing noise..")) buckled_mob.adjustBruteLoss(30) - if(!do_after(buckled_mob, 2 MINUTES, target = src)) + if(!do_after(buckled_mob, 2 MINUTES, target = src, hidden = TRUE)) if(buckled_mob?.buckled) to_chat(buckled_mob, span_warning("You fail to free yourself!")) return diff --git a/code/modules/clothing/shoes/_shoes.dm b/code/modules/clothing/shoes/_shoes.dm index f62c95dd1ba0c..4470a398168c5 100644 --- a/code/modules/clothing/shoes/_shoes.dm +++ b/code/modules/clothing/shoes/_shoes.dm @@ -174,8 +174,7 @@ adjust_laces(SHOES_UNTIED, user) else // if they're someone else's shoes, go knot-wards - var/mob/living/L = user - if(istype(L) && L.body_position == STANDING_UP) + if(istype(living_user) && living_user.body_position == STANDING_UP) to_chat(user, span_warning("You must be on the floor to interact with [src]!")) return if(tied == SHOES_KNOTTED) @@ -190,7 +189,7 @@ if(HAS_TRAIT(user, TRAIT_CLUMSY)) // based clowns trained their whole lives for this mod_time *= 0.75 - if(do_after(user, mod_time, target = our_guy, extra_checks = CALLBACK(src, PROC_REF(still_shoed), our_guy))) + if(do_after(user, mod_time, target = our_guy, extra_checks = CALLBACK(src, PROC_REF(still_shoed), our_guy), hidden = TRUE)) to_chat(user, span_notice("You [tied ? "untie" : "knot"] the laces on [loc]'s [src.name].")) if(tied == SHOES_UNTIED) adjust_laces(SHOES_KNOTTED, user) @@ -200,12 +199,12 @@ user.visible_message(span_danger("[our_guy] stamps on [user]'s hand, mid-shoelace [tied ? "knotting" : "untying"]!"), span_userdanger("Ow! [our_guy] stamps on your hand!"), list(our_guy)) to_chat(our_guy, span_userdanger("You stamp on [user]'s hand! What the- [user.p_they()] [user.p_were()] [tied ? "knotting" : "untying"] your shoelaces!")) user.emote("scream") - if(istype(L)) - var/obj/item/bodypart/ouchie = L.get_bodypart(pick(GLOB.arm_zones)) + if(istype(living_user)) + var/obj/item/bodypart/ouchie = living_user.get_bodypart(pick(GLOB.arm_zones)) if(ouchie) ouchie.receive_damage(brute = 10) - L.adjustStaminaLoss(40) - L.Paralyze(10) + living_user.adjustStaminaLoss(40) + living_user.Paralyze(10) ///checking to make sure we're still on the person we're supposed to be, for lacing do_after's /obj/item/clothing/shoes/proc/still_shoed(mob/living/carbon/our_guy) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 354c8f8a75020..6f8f95c64d7c9 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -234,25 +234,34 @@ return TRUE return FALSE + /mob/living/carbon/resist_buckle() - if(HAS_TRAIT(src, TRAIT_RESTRAINED)) - changeNext_move(CLICK_CD_BREAKOUT) - last_special = world.time + CLICK_CD_BREAKOUT - var/buckle_cd = 60 SECONDS - if(handcuffed) - var/obj/item/restraints/O = src.get_item_by_slot(ITEM_SLOT_HANDCUFFED) - buckle_cd = O.breakouttime - visible_message(span_warning("[src] attempts to unbuckle [p_them()]self!"), \ - span_notice("You attempt to unbuckle yourself... (This will take around [round(buckle_cd/600,1)] minute\s, and you need to stay still.)")) - if(do_after(src, buckle_cd, target = src, timed_action_flags = IGNORE_HELD_ITEM)) - if(!buckled) - return - buckled.user_unbuckle_mob(src,src) - else - if(src && buckled) - to_chat(src, span_warning("You fail to unbuckle yourself!")) - else - buckled.user_unbuckle_mob(src,src) + if(!HAS_TRAIT(src, TRAIT_RESTRAINED)) + buckled.user_buckle_mob(src, src) + return + + changeNext_move(CLICK_CD_BREAKOUT) + last_special = world.time + CLICK_CD_BREAKOUT + var/buckle_cd = 1 MINUTES + + if(handcuffed) + var/obj/item/restraints/cuffs = src.get_item_by_slot(ITEM_SLOT_HANDCUFFED) + buckle_cd = cuffs.breakouttime + + visible_message(span_warning("[src] attempts to unbuckle [p_them()]self!"), + span_notice("You attempt to unbuckle yourself... \ + (This will take around [DisplayTimeText(buckle_cd)] and you must stay still.)")) + + if(!do_after(src, buckle_cd, target = src, timed_action_flags = IGNORE_HELD_ITEM, hidden = TRUE)) + if(buckled) + to_chat(src, span_warning("You fail to unbuckle yourself!")) + return + + if(QDELETED(src) || isnull(buckled)) + return + + buckled.user_unbuckle_mob(src, src) + /mob/living/carbon/resist_fire() return !!apply_status_effect(/datum/status_effect/stop_drop_roll) @@ -276,34 +285,40 @@ cuff_resist(I) -/mob/living/carbon/proc/cuff_resist(obj/item/I, breakouttime = 1 MINUTES, cuff_break = 0) - if((cuff_break != INSTANT_CUFFBREAK) && (SEND_SIGNAL(src, COMSIG_MOB_REMOVING_CUFFS, I) & COMSIG_MOB_BLOCK_CUFF_REMOVAL)) +/** + * Helper to break the cuffs from hands + * @param {obj/item} cuffs - The cuffs to break + * @param {number} breakouttime - The time it takes to break the cuffs. Use SECONDS/MINUTES defines + * @param {number} cuff_break - Speed multiplier, 0 is default, see _DEFINES\combat.dm + */ +/mob/living/carbon/proc/cuff_resist(obj/item/cuffs, breakouttime = 1 MINUTES, cuff_break = 0) + if((cuff_break != INSTANT_CUFFBREAK) && (SEND_SIGNAL(src, COMSIG_MOB_REMOVING_CUFFS, cuffs) & COMSIG_MOB_BLOCK_CUFF_REMOVAL)) return //The blocking object should sent a fluff-appropriate to_chat about cuff removal being blocked - if(I.item_flags & BEING_REMOVED) - to_chat(src, span_warning("You're already attempting to remove [I]!")) + if(cuffs.item_flags & BEING_REMOVED) + to_chat(src, span_warning("You're already attempting to remove [cuffs]!")) return - I.item_flags |= BEING_REMOVED - breakouttime = I.breakouttime + cuffs.item_flags |= BEING_REMOVED + breakouttime = cuffs.breakouttime if(!cuff_break) - visible_message(span_warning("[src] attempts to remove [I]!")) - to_chat(src, span_notice("You attempt to remove [I]... (This will take around [DisplayTimeText(breakouttime)] and you need to stand still.)")) - if(do_after(src, breakouttime, target = src, timed_action_flags = IGNORE_HELD_ITEM)) - . = clear_cuffs(I, cuff_break) + visible_message(span_warning("[src] attempts to remove [cuffs]!")) + to_chat(src, span_notice("You attempt to remove [cuffs]... (This will take around [DisplayTimeText(breakouttime)] and you need to stand still.)")) + if(do_after(src, breakouttime, target = src, timed_action_flags = IGNORE_HELD_ITEM, hidden = TRUE)) + . = clear_cuffs(cuffs, cuff_break) else - to_chat(src, span_warning("You fail to remove [I]!")) + to_chat(src, span_warning("You fail to remove [cuffs]!")) else if(cuff_break == FAST_CUFFBREAK) - breakouttime = 50 - visible_message(span_warning("[src] is trying to break [I]!")) - to_chat(src, span_notice("You attempt to break [I]... (This will take around 5 seconds and you need to stand still.)")) + breakouttime = 5 SECONDS + visible_message(span_warning("[src] is trying to break [cuffs]!")) + to_chat(src, span_notice("You attempt to break [cuffs]... (This will take around 5 seconds and you need to stand still.)")) if(do_after(src, breakouttime, target = src, timed_action_flags = IGNORE_HELD_ITEM)) - . = clear_cuffs(I, cuff_break) + . = clear_cuffs(cuffs, cuff_break) else - to_chat(src, span_warning("You fail to break [I]!")) + to_chat(src, span_warning("You fail to break [cuffs]!")) else if(cuff_break == INSTANT_CUFFBREAK) - . = clear_cuffs(I, cuff_break) - I.item_flags &= ~BEING_REMOVED + . = clear_cuffs(cuffs, cuff_break) + cuffs.item_flags &= ~BEING_REMOVED /mob/living/carbon/proc/uncuff() if (handcuffed) diff --git a/code/modules/mob/living/carbon/human/human_stripping.dm b/code/modules/mob/living/carbon/human/human_stripping.dm index 47b4b54d1bc5d..a93dcddad3ec4 100644 --- a/code/modules/mob/living/carbon/human/human_stripping.dm +++ b/code/modules/mob/living/carbon/human/human_stripping.dm @@ -220,7 +220,7 @@ GLOBAL_LIST_INIT(strippable_human_items, create_strippable_list(list( source.log_message("is being pickpocketed of [item] by [key_name(user)] ([pocket_side])", LOG_VICTIM, color="orange", log_globally=FALSE) item.add_fingerprint(src) - var/result = start_unequip_mob(item, source, user, POCKET_STRIP_DELAY) + var/result = start_unequip_mob(item, source, user, strip_delay = POCKET_STRIP_DELAY, hidden = TRUE) if (!result) warn_owner(source) From 64ddd492f7012f2be06df6958a390d3e7cce88f9 Mon Sep 17 00:00:00 2001 From: Watermelon914 <37270891+Watermelon914@users.noreply.github.com> Date: Fri, 12 Apr 2024 17:48:13 +0000 Subject: [PATCH 194/938] Fixes SS13.register_signal throwing unclear errors when called on deleted datums (#82597) ## About The Pull Request See title ## Why It's Good For The Game More descriptive error message ## Changelog :cl: fix: LUA: Registering a signal on a deleted datum will throw a more descriptive error message. /:cl: --------- Co-authored-by: Watermelon914 <3052169-Watermelon914@users.noreply.gitlab.com> --- lua/SS13_base.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lua/SS13_base.lua b/lua/SS13_base.lua index 4bdd49d5d9052..f49908f094261 100644 --- a/lua/SS13_base.lua +++ b/lua/SS13_base.lua @@ -81,6 +81,10 @@ function SS13.register_signal(datum, signal, func) if not SS13.istype(datum, "/datum") then return end + if not SS13.is_valid(datum) then + error("Tried to register a signal on a deleted datum!", 2) + return + end local datumWeakRef = dm.global_proc("WEAKREF", datum) if not __SS13_signal_handlers[datumWeakRef] then __SS13_signal_handlers[datumWeakRef] = {} From a802be61c0c4ff0bfc8437f8bfd4d81a9a97aaa6 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sat, 13 Apr 2024 05:48:15 +1200 Subject: [PATCH 195/938] Automatic changelog for PR #82593 [ci skip] --- html/changelogs/AutoChangeLog-pr-82593.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82593.yml diff --git a/html/changelogs/AutoChangeLog-pr-82593.yml b/html/changelogs/AutoChangeLog-pr-82593.yml new file mode 100644 index 0000000000000..d212d03fc247f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82593.yml @@ -0,0 +1,4 @@ +author: "jlsnow301" +delete-after: True +changes: + - bugfix: "Deviants buffed: Rogue shoelacing, pickpocketing and restraint resisting no longer give cogbar icons." \ No newline at end of file From 573ed269e228b23220d7d1578ea1fafe5966fb92 Mon Sep 17 00:00:00 2001 From: AnturK Date: Fri, 12 Apr 2024 19:48:45 +0200 Subject: [PATCH 196/938] Improves banned antag replacement logs (#82545) Just so you don't have to dive deep in the logs to find these. --------- Co-authored-by: Fikou <23585223+Fikou@users.noreply.github.com> --- code/modules/antagonists/_common/antag_datum.dm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm index 89ed48585ed36..cf5d5a83e8dfe 100644 --- a/code/modules/antagonists/_common/antag_datum.dm +++ b/code/modules/antagonists/_common/antag_datum.dm @@ -296,9 +296,12 @@ GLOBAL_LIST_EMPTY(antagonists) var/mob/chosen_one = SSpolling.poll_ghosts_for_target(check_jobban = job_rank, role = job_rank, poll_time = 5 SECONDS, checked_target = owner.current, alert_pic = owner.current, role_name_text = name) if(chosen_one) to_chat(owner, "Your mob has been taken over by a ghost! Appeal your job ban if you want to avoid this in the future!") - message_admins("[key_name_admin(chosen_one)] has taken control of ([key_name_admin(owner)]) to replace a jobbanned player.") + message_admins("[key_name_admin(chosen_one)] has taken control of ([key_name_admin(owner)]) to replace antagonist banned player.") + log_game("[key_name(chosen_one)] has taken control of ([key_name(owner)]) to replace antagonist banned player.") owner.current.ghostize(FALSE) owner.current.key = chosen_one.key + else + log_game("Couldn't find antagonist ban replacement for ([key_name(owner)]).") /** * Called by the remove_antag_datum() and remove_all_antag_datums() mind procs for the antag datum to handle its own removal and deletion. From 336ffa9d8348b211f727f1c5b77b840c555bb145 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sat, 13 Apr 2024 05:48:53 +1200 Subject: [PATCH 197/938] Automatic changelog for PR #82597 [ci skip] --- html/changelogs/AutoChangeLog-pr-82597.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82597.yml diff --git a/html/changelogs/AutoChangeLog-pr-82597.yml b/html/changelogs/AutoChangeLog-pr-82597.yml new file mode 100644 index 0000000000000..884870c015195 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82597.yml @@ -0,0 +1,4 @@ +author: "Watermelon914" +delete-after: True +changes: + - bugfix: "LUA: Registering a signal on a deleted datum will throw a more descriptive error message." \ No newline at end of file From 16438d0d4e146bda6d26daa944b31371b75cda28 Mon Sep 17 00:00:00 2001 From: Jacquerel Date: Fri, 12 Apr 2024 18:49:34 +0100 Subject: [PATCH 198/938] Bioscrambler Anomaly chases you (#82555) ## About The Pull Request I heard reports that people just ignore the bioscrambler anomaly because basically you just don't go into that room any more and depending on where it spawned, that's no big deal. That won't do. Now the Bioscrambler will be attracted to the nearest sign of advanced thinking life (read: nearest humanoid mob controlled by a player) and will very slowly pursue them, travelling through walls and obstacles in order to do so. Also if it decides to target you, you will get a foreboding psychic warning like with the dark matteor, because I think it's funny for dire warnings to have multiple obscuring sources. The Bioscrambler can be blocked with containment fields if you want to make an overly-elaborate pen for it. To accomplish this I refactored containment fields a little bit to apply turf traits instead of making four different `locate()` checks for different objects. Those files smell bad. Oh also I moved the dullahan organs to the Bioscrambler blacklist because they runtimed while I was testing it (see also: my other incoming PRs) and I can't see any other reasonable way to fix it (they expect to be in an abstract body zone...) ## Why It's Good For The Game Anomalies are generally meant to be problems that you deal with or face some kind of consequence. Because the Bioscrambler isn't a timed anomaly with a dramatic detonation effect, being spawned in a poorly-trafficked area could simply mean that it isn't a problem to anyone. Now it will make sure that it is a problem for someone until someone gets rid of it. I thought this solution was funnier than making it do something zany if you leave it alone for 3 minutes. ## Changelog :cl: balance: The Bioscrambler will now actively attempt to get closer to living targets rather than chilling in a closet nobody goes into (unless you trap it in a containment field). balance: Because it can now travel through walls, the Bioscrambler will no longer transform you THROUGH walls. /:cl: --- code/__DEFINES/research/anomalies.dm | 3 ++ code/__DEFINES/traits/declarations.dm | 3 ++ code/_globalvars/traits/_traits.dm | 1 + code/datums/components/singularity.dm | 21 ++------- code/game/machinery/shieldgen.dm | 24 +++++++--- .../objects/effects/anomalies/_anomalies.dm | 10 +++- .../anomalies/anomalies_bioscrambler.dm | 47 ++++++++++++++++++- code/modules/mob/living/carbon/carbon.dm | 10 ++++ code/modules/mob/living/living.dm | 4 ++ .../power/singularity/containment_field.dm | 1 + .../power/singularity/field_generator.dm | 2 + code/modules/power/singularity/singularity.dm | 10 +--- 12 files changed, 99 insertions(+), 37 deletions(-) diff --git a/code/__DEFINES/research/anomalies.dm b/code/__DEFINES/research/anomalies.dm index 3389b9e0fe671..3b2687b5fcf55 100644 --- a/code/__DEFINES/research/anomalies.dm +++ b/code/__DEFINES/research/anomalies.dm @@ -34,10 +34,13 @@ GLOBAL_LIST_INIT(bioscrambler_organs_blacklist, typecacheof(list ( /obj/item/organ/internal/brain, /obj/item/organ/internal/body_egg, /obj/item/organ/internal/cyberimp, + /obj/item/organ/internal/ears/dullahan, + /obj/item/organ/internal/eyes/dullahan, /obj/item/organ/internal/heart/cursed, /obj/item/organ/internal/heart/demon, /obj/item/organ/internal/lungs, /obj/item/organ/internal/monster_core, + /obj/item/organ/internal/tongue/dullahan, /obj/item/organ/internal/vocal_cords/colossus, /obj/item/organ/internal/zombie_infection, ))) diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index c61e1c2ef9c4a..f5ad67a8c94a8 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -813,6 +813,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai ///Trait applied to turfs when an atmos holosign is placed on them. It will stop firedoors from closing. #define TRAIT_FIREDOOR_STOP "firedoor_stop" +///Trait applied to turf blocked by a containment field +#define TRAIT_CONTAINMENT_FIELD "containment_field" + /// Trait applied when the MMI component is added to an [/obj/item/integrated_circuit] #define TRAIT_COMPONENT_MMI "component_mmi" diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 49ea900419810..9ee26893b5f2f 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -599,6 +599,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( ), /turf = list( "TRAIT_CHASM_STOPPED" = TRAIT_CHASM_STOPPED, + "TRAIT_CONTAINMENT_FIELD" = TRAIT_CONTAINMENT_FIELD, "TRAIT_FIREDOOR_STOP" = TRAIT_FIREDOOR_STOP, "TRAIT_HYPERSPACE_STOPPED" = TRAIT_HYPERSPACE_STOPPED, "TRAIT_IMMERSE_STOPPED" = TRAIT_IMMERSE_STOPPED, diff --git a/code/datums/components/singularity.dm b/code/datums/components/singularity.dm index c1323d01e2fe6..56a6723f21f41 100644 --- a/code/datums/components/singularity.dm +++ b/code/datums/components/singularity.dm @@ -360,8 +360,9 @@ target = potentially_closer //if we lost that target get a new one if(!target || QDELETED(target)) - target = find_new_target() - foreboding_nosebleed(target) + var/mob/living/new_target = find_new_target() + new_target?.ominous_nosebleed() + target = new_target return ..() ///Searches the living list for the closest target, and begins chasing them down. @@ -380,22 +381,6 @@ closest_target = target return closest_target -/// gives a little fluff warning that someone is being hunted. -/datum/component/singularity/bloodthirsty/proc/foreboding_nosebleed(mob/living/target) - if(!iscarbon(target)) - to_chat(target, span_warning("You feel a bit nauseous for just a moment.")) - return - var/mob/living/carbon/carbon_target = target - var/obj/item/bodypart/head = carbon_target.get_bodypart(BODY_ZONE_HEAD) - if(head) - if(HAS_TRAIT(carbon_target, TRAIT_NOBLOOD)) - to_chat(carbon_target, span_notice("You get a headache.")) - return - head.adjustBleedStacks(5) - carbon_target.visible_message(span_notice("[carbon_target] gets a nosebleed."), span_warning("You get a nosebleed.")) - return - to_chat(target, span_warning("You feel a bit nauseous for just a moment.")) - #undef CHANCE_TO_MOVE_TO_TARGET #undef CHANCE_TO_MOVE_TO_TARGET_BLOODTHIRSTY #undef CHANCE_TO_CHANGE_TARGET_BLOODTHIRSTY diff --git a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm index 0e2be91490c5a..4e7a80e166388 100644 --- a/code/game/machinery/shieldgen.dm +++ b/code/game/machinery/shieldgen.dm @@ -364,11 +364,8 @@ visible_message(span_danger("[src] shuts down due to lack of power!"), \ "If this message is ever seen, something is wrong.", span_hear("You hear heavy droning fade out.")) - active = FALSE + deactivate() log_game("[src] deactivated due to lack of power at [AREACOORD(src)]") - for(var/d in GLOB.cardinals) - cleanup_field(d) - update_appearance() else update_appearance() for(var/d in GLOB.cardinals) @@ -463,7 +460,6 @@ balloon_alert(user, "malfunctioning!") else balloon_alert(user, "no access!") - return add_fingerprint(user) @@ -493,13 +489,13 @@ user.visible_message(span_notice("[user] turned \the [src] off."), \ span_notice("You turn off \the [src]."), \ span_hear("You hear heavy droning fade out.")) - active = FALSE + deactivate() user.log_message("deactivated [src].", LOG_GAME) else user.visible_message(span_notice("[user] turned \the [src] on."), \ span_notice("You turn on \the [src]."), \ span_hear("You hear heavy droning.")) - active = ACTIVE_SETUPFIELDS + activate() user.log_message("activated [src].", LOG_GAME) add_fingerprint(user) @@ -513,6 +509,19 @@ balloon_alert(user, "access controller shorted") return TRUE +/// Turn the machine on with side effects +/obj/machinery/power/shieldwallgen/proc/activate() + active = ACTIVE_SETUPFIELDS + AddElement(/datum/element/give_turf_traits, string_list(list(TRAIT_CONTAINMENT_FIELD))) + +/// Turn the machine off with side effects +/obj/machinery/power/shieldwallgen/proc/deactivate() + active = FALSE + for(var/d in GLOB.cardinals) + cleanup_field(d) + update_appearance() + RemoveElement(/datum/element/give_turf_traits, string_list(list(TRAIT_CONTAINMENT_FIELD))) + //////////////Containment Field START /obj/machinery/shieldwall name = "shield wall" @@ -538,6 +547,7 @@ L.investigate_log("has been gibbed by [src].", INVESTIGATE_DEATHS) L.gib(DROP_ALL_REMAINS) RegisterSignal(src, COMSIG_ATOM_SINGULARITY_TRY_MOVE, PROC_REF(block_singularity)) + AddElement(/datum/element/give_turf_traits, string_list(list(TRAIT_CONTAINMENT_FIELD))) /obj/machinery/shieldwall/Destroy() gen_primary = null diff --git a/code/game/objects/effects/anomalies/_anomalies.dm b/code/game/objects/effects/anomalies/_anomalies.dm index 530da56282788..8c34c48ee4152 100644 --- a/code/game/objects/effects/anomalies/_anomalies.dm +++ b/code/game/objects/effects/anomalies/_anomalies.dm @@ -23,6 +23,8 @@ var/immortal = FALSE ///Do we stay in one place? var/immobile = FALSE + ///Chance per second that we will move + var/move_chance = ANOMALY_MOVECHANCE /obj/effect/anomaly/Initialize(mapload, new_lifespan, drops_core = TRUE) . = ..() @@ -76,8 +78,12 @@ return ..() /obj/effect/anomaly/proc/anomalyEffect(seconds_per_tick) - if(!immobile && SPT_PROB(ANOMALY_MOVECHANCE, seconds_per_tick)) - step(src,pick(GLOB.alldirs)) + if(SPT_PROB(move_chance, seconds_per_tick)) + move_anomaly() + +/// Move in a direction +/obj/effect/anomaly/proc/move_anomaly() + step(src, pick(GLOB.alldirs)) /obj/effect/anomaly/proc/detonate() return diff --git a/code/game/objects/effects/anomalies/anomalies_bioscrambler.dm b/code/game/objects/effects/anomalies/anomalies_bioscrambler.dm index b4ee3713a25da..214440b92c2c6 100644 --- a/code/game/objects/effects/anomalies/anomalies_bioscrambler.dm +++ b/code/game/objects/effects/anomalies/anomalies_bioscrambler.dm @@ -4,6 +4,10 @@ icon_state = "bioscrambler" aSignal = /obj/item/assembly/signaler/anomaly/bioscrambler immortal = TRUE + pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE | PASSCLOSEDTURF | PASSMACHINE | PASSSTRUCTURE | PASSDOORS + layer = ABOVE_MOB_LAYER + /// Who are we moving towards? + var/datum/weakref/pursuit_target /// Cooldown for every anomaly pulse COOLDOWN_DECLARE(pulse_cooldown) /// How many seconds between each anomaly pulses @@ -11,11 +15,52 @@ /// Range of the anomaly pulse var/range = 5 +/obj/effect/anomaly/bioscrambler/Initialize(mapload, new_lifespan, drops_core) + . = ..() + pursuit_target = WEAKREF(find_nearest_target()) + /obj/effect/anomaly/bioscrambler/anomalyEffect(seconds_per_tick) . = ..() if(!COOLDOWN_FINISHED(src, pulse_cooldown)) return COOLDOWN_START(src, pulse_cooldown, pulse_delay) - for(var/mob/living/carbon/nearby in range(range, src)) + for(var/mob/living/carbon/nearby in hearers(range, src)) nearby.bioscramble(name) + +/obj/effect/anomaly/bioscrambler/move_anomaly() + var/mob/living/current_target = pursuit_target?.resolve() + if (QDELETED(current_target)) + pursuit_target = null + if (isnull(pursuit_target) || prob(20)) + var/mob/living/new_target = find_nearest_target() + if (isnull(new_target)) + pursuit_target = null + else if (new_target != current_target) + current_target = new_target + pursuit_target = WEAKREF(new_target) + new_target.ominous_nosebleed() + if (isnull(pursuit_target)) + return + var/turf/step_turf = get_step(src, get_dir(src, current_target)) + if (!HAS_TRAIT(step_turf, TRAIT_CONTAINMENT_FIELD)) + Move(step_turf) + +/// Returns the closest conscious carbon on our z level or null if there somehow isn't one +/obj/effect/anomaly/bioscrambler/proc/find_nearest_target() + var/closest_distance = INFINITY + var/mob/living/carbon/closest_target = null + for(var/mob/living/carbon/target in GLOB.player_list) + if (target.z != z) + continue + if (target.status_effects & GODMODE) + continue + if (target.stat >= UNCONSCIOUS) + continue // Don't just haunt a corpse + var/distance_from_target = get_dist(src, target) + if(distance_from_target >= closest_distance) + continue + closest_distance = distance_from_target + closest_target = target + + return closest_target diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 6f8f95c64d7c9..cd97eba3c9eaf 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -1477,3 +1477,13 @@ if (!IS_ORGANIC_LIMB(target_part) || (target_part.bodypart_flags & BODYPART_PSEUDOPART)) return FALSE return ..() + +/mob/living/carbon/ominous_nosebleed() + var/obj/item/bodypart/head = get_bodypart(BODY_ZONE_HEAD) + if(isnull(head)) + return ..() + if(HAS_TRAIT(src, TRAIT_NOBLOOD)) + to_chat(src, span_notice("You get a headache.")) + return + head.adjustBleedStacks(5) + visible_message(span_notice("[src] gets a nosebleed."), span_warning("You get a nosebleed.")) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 0b25077d3d376..46d65b376bdcf 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -2426,6 +2426,10 @@ GLOBAL_LIST_EMPTY(fire_appearances) apply_damage(rand(5,10), BRUTE, BODY_ZONE_CHEST) lattice.deconstruct(FALSE) +/// Prints an ominous message if something bad is going to happen to you +/mob/living/proc/ominous_nosebleed() + to_chat(src, span_warning("You feel a bit nauseous for just a moment.")) + /** * Proc used by different station pets such as Ian and Poly so that some of their data can persist between rounds. * This base definition only contains a trait and comsig to stop memory from being (over)written. diff --git a/code/modules/power/singularity/containment_field.dm b/code/modules/power/singularity/containment_field.dm index 0fd3c15a39a6b..22682471d1359 100644 --- a/code/modules/power/singularity/containment_field.dm +++ b/code/modules/power/singularity/containment_field.dm @@ -29,6 +29,7 @@ COMSIG_ATOM_ENTERED = PROC_REF(on_entered), ) AddElement(/datum/element/connect_loc, loc_connections) + AddElement(/datum/element/give_turf_traits, string_list(list(TRAIT_CONTAINMENT_FIELD))) /obj/machinery/field/containment/Destroy() if(field_gen_1) diff --git a/code/modules/power/singularity/field_generator.dm b/code/modules/power/singularity/field_generator.dm index c18e7f15a65f1..b46b29538c608 100644 --- a/code/modules/power/singularity/field_generator.dm +++ b/code/modules/power/singularity/field_generator.dm @@ -208,6 +208,7 @@ no power level overlay is currently in the overlays list. air_update_turf(TRUE, FALSE) INVOKE_ASYNC(src, PROC_REF(cleanup)) addtimer(CALLBACK(src, PROC_REF(cool_down)), 5 SECONDS) + RemoveElement(/datum/element/give_turf_traits, string_list(list(TRAIT_CONTAINMENT_FIELD))) /obj/machinery/field/generator/proc/cool_down() if(active || warming_up <= 0) @@ -220,6 +221,7 @@ no power level overlay is currently in the overlays list. /obj/machinery/field/generator/proc/turn_on() active = FG_CHARGING addtimer(CALLBACK(src, PROC_REF(warm_up)), 5 SECONDS) + AddElement(/datum/element/give_turf_traits, string_list(list(TRAIT_CONTAINMENT_FIELD))) /obj/machinery/field/generator/proc/warm_up() if(!active) diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index d808ea0b00982..d47d75360946a 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -386,16 +386,8 @@ /obj/singularity/proc/can_move(turf/considered_turf) if(!considered_turf) return FALSE - if((locate(/obj/machinery/field/containment) in considered_turf) || (locate(/obj/machinery/shieldwall) in considered_turf)) + if (HAS_TRAIT(considered_turf, TRAIT_CONTAINMENT_FIELD)) return FALSE - else if(locate(/obj/machinery/field/generator) in considered_turf) - var/obj/machinery/field/generator/check_generator = locate(/obj/machinery/field/generator) in considered_turf - if(check_generator?.active) - return FALSE - else if(locate(/obj/machinery/power/shieldwallgen) in considered_turf) - var/obj/machinery/power/shieldwallgen/check_shield = locate(/obj/machinery/power/shieldwallgen) in considered_turf - if(check_shield?.active) - return FALSE return TRUE /obj/singularity/proc/event() From d2956ae821c6a865d8ee3de0d4b92979a9d08e32 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sat, 13 Apr 2024 05:55:28 +1200 Subject: [PATCH 199/938] Automatic changelog for PR #82555 [ci skip] --- html/changelogs/AutoChangeLog-pr-82555.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82555.yml diff --git a/html/changelogs/AutoChangeLog-pr-82555.yml b/html/changelogs/AutoChangeLog-pr-82555.yml new file mode 100644 index 0000000000000..76db2d5161bce --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82555.yml @@ -0,0 +1,5 @@ +author: "Jacquerel" +delete-after: True +changes: + - balance: "The Bioscrambler will now actively attempt to get closer to living targets rather than chilling in a closet nobody goes into (unless you trap it in a containment field)." + - balance: "Because it can now travel through walls, the Bioscrambler will no longer transform you THROUGH walls." \ No newline at end of file From e0d335b4420ecef6a451df32839f22b12a076c2a Mon Sep 17 00:00:00 2001 From: Iamgoofball Date: Fri, 12 Apr 2024 12:24:50 -0700 Subject: [PATCH 200/938] Fixes AI lag by re-adding idle mode to all AI that was lost with the simple mob to basic mob conversion. (#82539) --- code/__DEFINES/ai/ai.dm | 5 ++++ code/controllers/subsystem/ai_controllers.dm | 27 ++++++++++++++++++- code/datums/ai/_ai_controller.dm | 11 ++++++-- code/datums/brain_damage/special.dm | 2 +- code/modules/mob/living/basic/bots/bot_ai.dm | 1 + .../mob/living/basic/lavaland/mook/mook_ai.dm | 1 + .../mob/living/basic/ruin_defender/flesh.dm | 2 +- code/modules/unit_tests/mouse_bite_cable.dm | 1 + 8 files changed, 45 insertions(+), 5 deletions(-) diff --git a/code/__DEFINES/ai/ai.dm b/code/__DEFINES/ai/ai.dm index e894b32b1f646..fc8d5f3491c30 100644 --- a/code/__DEFINES/ai/ai.dm +++ b/code/__DEFINES/ai/ai.dm @@ -8,11 +8,16 @@ #define AI_STATUS_ON "ai_on" ///The AI is currently offline for any reason. #define AI_STATUS_OFF "ai_off" +///The AI is currently in idle mode. +#define AI_STATUS_IDLE "ai_idle" ///For JPS pathing, the maximum length of a path we'll try to generate. Should be modularized depending on what we're doing later on #define AI_MAX_PATH_LENGTH 30 // 30 is possibly overkill since by default we lose interest after 14 tiles of distance, but this gives wiggle room for weaving around obstacles #define AI_BOT_PATH_LENGTH 150 +// How far should we, by default, be looking for interesting things to de-idle? +#define AI_DEFAULT_INTERESTING_DIST 14 + ///Cooldown on planning if planning failed last time #define AI_FAILED_PLANNING_COOLDOWN (1.5 SECONDS) diff --git a/code/controllers/subsystem/ai_controllers.dm b/code/controllers/subsystem/ai_controllers.dm index 44e1948e3864b..933a96dcaedab 100644 --- a/code/controllers/subsystem/ai_controllers.dm +++ b/code/controllers/subsystem/ai_controllers.dm @@ -13,9 +13,15 @@ SUBSYSTEM_DEF(ai_controllers) var/list/ai_controllers_by_status = list( AI_STATUS_ON = list(), AI_STATUS_OFF = list(), + AI_STATUS_IDLE = list(), ) ///Assoc List of all AI controllers and the Z level they are on, which we check when someone enters/leaves a Z level to turn them on/off. var/list/ai_controllers_by_zlevel = list() + /// The tick cost of all active AI, calculated on fire. + var/cost_on + /// The tick cost of all idle AI, calculated on fire. + var/cost_idle + /datum/controller/subsystem/ai_controllers/Initialize() setup_subtrees() @@ -24,10 +30,20 @@ SUBSYSTEM_DEF(ai_controllers) /datum/controller/subsystem/ai_controllers/stat_entry(msg) var/list/active_list = ai_controllers_by_status[AI_STATUS_ON] var/list/inactive_list = ai_controllers_by_status[AI_STATUS_OFF] - msg = "Active AIs:[length(active_list)]|Inactive:[length(inactive_list)]" + var/list/idle_list = ai_controllers_by_status[AI_STATUS_IDLE] + msg = "Active AIs:[length(active_list)]/[round(cost_on,1)]%|Inactive:[length(inactive_list)]|Idle:[length(idle_list)]/[round(cost_idle,1)]%" return ..() /datum/controller/subsystem/ai_controllers/fire(resumed) + var/timer = TICK_USAGE_REAL + for(var/datum/ai_controller/ai_controller as anything in ai_controllers_by_status[AI_STATUS_IDLE]) + for(var/client/client_found in GLOB.clients) + if(get_dist(get_turf(client_found.mob), get_turf(ai_controller.pawn)) <= ai_controller.interesting_dist) + ai_controller.set_ai_status(AI_STATUS_ON) + break + cost_idle = MC_AVERAGE(cost_idle, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) + + timer = TICK_USAGE_REAL for(var/datum/ai_controller/ai_controller as anything in ai_controllers_by_status[AI_STATUS_ON]) if(!COOLDOWN_FINISHED(ai_controller, failed_planning_cooldown)) continue @@ -37,6 +53,15 @@ SUBSYSTEM_DEF(ai_controllers) ai_controller.SelectBehaviors(wait * 0.1) if(!LAZYLEN(ai_controller.current_behaviors)) //Still no plan COOLDOWN_START(ai_controller, failed_planning_cooldown, AI_FAILED_PLANNING_COOLDOWN) + if(ai_controller.can_idle) + var/found_interesting = FALSE + for(var/client/client_found in GLOB.clients) + if(get_dist(get_turf(client_found.mob), get_turf(ai_controller.pawn)) <= ai_controller.interesting_dist) + found_interesting = TRUE + break + if(!found_interesting) + ai_controller.set_ai_status(AI_STATUS_IDLE) + cost_on = MC_AVERAGE(cost_on, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) ///Creates all instances of ai_subtrees and assigns them to the ai_subtrees list. /datum/controller/subsystem/ai_controllers/proc/setup_subtrees() diff --git a/code/datums/ai/_ai_controller.dm b/code/datums/ai/_ai_controller.dm index 664e89eab09f4..0a7fc959e4416 100644 --- a/code/datums/ai/_ai_controller.dm +++ b/code/datums/ai/_ai_controller.dm @@ -56,6 +56,10 @@ multiple modular subtrees with behaviors // The variables below are fucking stupid and should be put into the blackboard at some point. ///AI paused time var/paused_until = 0 + ///Can this AI idle? + var/can_idle = TRUE + ///What distance should we be checking for interesting things when considering idling/deidling? Defaults to AI_DEFAULT_INTERESTING_DIST + var/interesting_dist = AI_DEFAULT_INTERESTING_DIST /datum/ai_controller/New(atom/new_pawn) change_ai_movement_type(ai_movement) @@ -175,7 +179,7 @@ multiple modular subtrees with behaviors SSai_controllers.ai_controllers_by_zlevel[new_turf.z] += src var/new_level_clients = SSmobs.clients_by_zlevel[new_turf.z].len if(new_level_clients) - set_ai_status(AI_STATUS_ON) + set_ai_status(AI_STATUS_IDLE) else set_ai_status(AI_STATUS_OFF) @@ -319,6 +323,9 @@ multiple modular subtrees with behaviors if(AI_STATUS_OFF) STOP_PROCESSING(SSai_behaviors, src) CancelActions() + if(AI_STATUS_IDLE) + STOP_PROCESSING(SSai_behaviors, src) + CancelActions() /datum/ai_controller/proc/PauseAi(time) paused_until = world.time + time @@ -378,7 +385,7 @@ multiple modular subtrees with behaviors /datum/ai_controller/proc/on_sentience_lost() SIGNAL_HANDLER UnregisterSignal(pawn, COMSIG_MOB_LOGOUT) - set_ai_status(AI_STATUS_ON) //Can't do anything while player is connected + set_ai_status(AI_STATUS_IDLE) //Can't do anything while player is connected RegisterSignal(pawn, COMSIG_MOB_LOGIN, PROC_REF(on_sentience_gained)) // Turn the controller off if the pawn has been qdeleted diff --git a/code/datums/brain_damage/special.dm b/code/datums/brain_damage/special.dm index bfbf2d84d73d8..5b8666413e30f 100644 --- a/code/datums/brain_damage/special.dm +++ b/code/datums/brain_damage/special.dm @@ -514,7 +514,7 @@ owner.grant_language(/datum/language/monkey, UNDERSTOOD_LANGUAGE, TRAUMA_TRAIT) owner.ai_controller.set_blackboard_key(BB_MONKEY_AGGRESSIVE, prob(75)) if(owner.ai_controller.ai_status == AI_STATUS_OFF) - owner.ai_controller.set_ai_status(AI_STATUS_ON) + owner.ai_controller.set_ai_status(AI_STATUS_IDLE) owner.log_message("became controlled by monkey instincts ([owner.ai_controller.blackboard[BB_MONKEY_AGGRESSIVE] ? "aggressive" : "docile"])", LOG_ATTACK, color = "orange") to_chat(owner, span_warning("You feel the urge to act on your primal instincts...")) // extend original timer if we roll the effect while it's already ongoing diff --git a/code/modules/mob/living/basic/bots/bot_ai.dm b/code/modules/mob/living/basic/bots/bot_ai.dm index 706a8b58ba021..36600f244e7d5 100644 --- a/code/modules/mob/living/basic/bots/bot_ai.dm +++ b/code/modules/mob/living/basic/bots/bot_ai.dm @@ -27,6 +27,7 @@ var/current_pathing_attempts = 0 ///if we cant reach it after this many attempts, add it to our ignore list var/max_pathing_attempts = 25 + can_idle = FALSE // we want these to be running always /datum/ai_controller/basic_controller/bot/TryPossessPawn(atom/new_pawn) . = ..() diff --git a/code/modules/mob/living/basic/lavaland/mook/mook_ai.dm b/code/modules/mob/living/basic/lavaland/mook/mook_ai.dm index cf79eb06aa605..5041669306140 100644 --- a/code/modules/mob/living/basic/lavaland/mook/mook_ai.dm +++ b/code/modules/mob/living/basic/lavaland/mook/mook_ai.dm @@ -26,6 +26,7 @@ GLOBAL_LIST_INIT(mook_commands, list( /datum/ai_planning_subtree/mine_walls/mook, /datum/ai_planning_subtree/wander_away_from_village, ) + can_idle = FALSE // these guys are intended to operate even if nobody's around ///check for faction if not a ash walker, otherwise just attack /datum/targeting_strategy/basic/mook/faction_check(datum/ai_controller/controller, mob/living/living_mob, mob/living/the_target) diff --git a/code/modules/mob/living/basic/ruin_defender/flesh.dm b/code/modules/mob/living/basic/ruin_defender/flesh.dm index 17d625cb591f6..31849e3195d02 100644 --- a/code/modules/mob/living/basic/ruin_defender/flesh.dm +++ b/code/modules/mob/living/basic/ruin_defender/flesh.dm @@ -173,7 +173,7 @@ /mob/living/basic/living_limb_flesh/proc/wake_up(atom/limb) visible_message(span_warning("[src] begins flailing around!")) Shake(6, 6, 0.5 SECONDS) - ai_controller.set_ai_status(AI_STATUS_ON) + ai_controller.set_ai_status(AI_STATUS_IDLE) forceMove(limb.drop_location()) qdel(limb) diff --git a/code/modules/unit_tests/mouse_bite_cable.dm b/code/modules/unit_tests/mouse_bite_cable.dm index c2277fe4fd708..df77976ce47ce 100644 --- a/code/modules/unit_tests/mouse_bite_cable.dm +++ b/code/modules/unit_tests/mouse_bite_cable.dm @@ -21,6 +21,7 @@ var/fake_dt = SSai_controllers.wait * 0.1 // Set AI - AIs by default are off in z-levels with no client, we have to force it on. biter.ai_controller.set_ai_status(AI_STATUS_ON) + biter.ai_controller.can_idle = FALSE // Select behavior - this will queue finding the cable biter.ai_controller.SelectBehaviors(fake_dt) // Process behavior - this will execute the "locate the cable" behavior From 7f8752be1477852668bbd3a9016c559fd4e6e34c Mon Sep 17 00:00:00 2001 From: Zephyr <12817816+ZephyrTFA@users.noreply.github.com> Date: Fri, 12 Apr 2024 15:27:09 -0400 Subject: [PATCH 201/938] Admin Verb Datums MkIII | Now with functional command bar (#82511) --- .vscode/settings.json | 2 + code/__DEFINES/_protect.dm | 3 +- code/__DEFINES/admin.dm | 3 +- code/__DEFINES/admin_verb.dm | 92 ++ code/__DEFINES/subsystems.dm | 1 + code/__HELPERS/hallucinations.dm | 8 +- code/_onclick/hud/movable_screen_objects.dm | 26 +- code/controllers/admin.dm | 25 +- code/controllers/subsystem/admin_verbs.dm | 150 +++ code/controllers/subsystem/explosions.dm | 17 +- code/controllers/subsystem/mapping.dm | 26 +- code/controllers/subsystem/weather.dm | 12 +- code/datums/brain_damage/imaginary_friend.dm | 4 +- code/datums/components/puzzgrid.dm | 13 +- code/datums/keybinding/admin.dm | 12 +- code/datums/station_traits/admin_panel.dm | 8 +- code/game/atom/atom_vv.dm | 8 +- code/game/objects/objs.dm | 4 +- code/modules/admin/admin.dm | 45 +- code/modules/admin/admin_fax_panel.dm | 31 +- code/modules/admin/admin_investigate.dm | 15 +- code/modules/admin/admin_pda_message.dm | 10 +- code/modules/admin/admin_verbs.dm | 929 ++++-------------- code/modules/admin/callproc/callproc.dm | 40 +- code/modules/admin/force_event.dm | 10 +- code/modules/admin/known_alts.dm | 7 +- code/modules/admin/outfit_manager.dm | 30 +- code/modules/admin/painting_manager.dm | 11 +- code/modules/admin/permissionedit.dm | 10 +- code/modules/admin/stickyban.dm | 9 +- code/modules/admin/tag.dm | 21 +- code/modules/admin/topic.dm | 126 +-- code/modules/admin/trophy_manager.dm | 11 +- .../admin/verb_datums/_admin_verb_datum.dm | 27 + .../admin/verb_datums/_admin_verb_holder.dm | 0 code/modules/admin/verbs/SDQL2/SDQL_2.dm | 15 +- code/modules/admin/verbs/admin.dm | 83 +- code/modules/admin/verbs/admin_newscaster.dm | 15 +- code/modules/admin/verbs/adminevents.dm | 318 ++---- code/modules/admin/verbs/adminfun.dm | 155 +-- code/modules/admin/verbs/admingame.dm | 285 +++--- code/modules/admin/verbs/adminjump.dm | 172 ++-- code/modules/admin/verbs/adminpm.dm | 35 +- code/modules/admin/verbs/adminsay.dm | 30 +- code/modules/admin/verbs/atmosdebug.dm | 24 +- code/modules/admin/verbs/beakerpanel.dm | 11 +- code/modules/admin/verbs/borgpanel.dm | 21 +- .../admin/verbs/change_shuttle_events.dm | 23 +- code/modules/admin/verbs/cinematic.dm | 18 +- code/modules/admin/verbs/commandreport.dm | 27 +- code/modules/admin/verbs/config_helpers.dm | 21 +- code/modules/admin/verbs/deadsay.dm | 35 +- code/modules/admin/verbs/debug.dm | 540 ++++------ code/modules/admin/verbs/diagnostics.dm | 58 +- code/modules/admin/verbs/ert.dm | 18 +- code/modules/admin/verbs/fix_air.dm | 28 +- code/modules/admin/verbs/fov.dm | 12 +- code/modules/admin/verbs/fps.dm | 19 +- code/modules/admin/verbs/getlogs.dm | 18 +- .../admin/verbs/ghost_pool_protection.dm | 9 +- code/modules/admin/verbs/lawpanel.dm | 18 +- code/modules/admin/verbs/lua/lua_editor.dm | 10 +- code/modules/admin/verbs/machine_upgrade.dm | 16 +- code/modules/admin/verbs/manipulate_organs.dm | 29 +- code/modules/admin/verbs/map_export.dm | 29 +- .../admin/verbs/map_template_loadverb.dm | 46 +- code/modules/admin/verbs/mapping.dm | 229 ++--- code/modules/admin/verbs/maprotation.dm | 49 +- code/modules/admin/verbs/panicbunker.dm | 26 +- .../admin/verbs/player_ticket_history.dm | 9 +- code/modules/admin/verbs/playsound.dm | 112 +-- code/modules/admin/verbs/possess.dm | 28 +- .../admin/verbs/reestablish_db_connection.dm | 20 +- code/modules/admin/verbs/requests.dm | 9 +- code/modules/admin/verbs/secrets.dm | 23 +- code/modules/admin/verbs/selectequipment.dm | 14 +- code/modules/admin/verbs/server.dm | 275 +++--- code/modules/admin/verbs/shuttlepanel.dm | 12 +- code/modules/admin/verbs/spawnobjasmob.dm | 83 +- code/modules/admin/verbs/special_verbs.dm | 43 + .../admin/view_variables/mark_datum.dm | 6 +- .../modules/admin/view_variables/tag_datum.dm | 6 +- .../admin/view_variables/topic_basic.dm | 3 +- .../admin/view_variables/view_variables.dm | 4 + .../antagonists/traitor/balance_helper.dm | 10 +- .../pipes/pipe_spritesheet_helper.dm | 5 +- code/modules/cargo/centcom_podlauncher.dm | 7 +- code/modules/client/client_procs.dm | 64 +- code/modules/client/verbs/ooc.dm | 25 +- code/modules/explorer_drone/manager.dm | 9 +- code/modules/fishing/admin.dm | 12 +- code/modules/logging/log_holder.dm | 6 +- .../modules/mob/dead/observer/observer_say.dm | 4 +- code/modules/mob/living/carbon/carbon.dm | 4 +- code/modules/mob/living/living_say.dm | 4 +- code/modules/mob/mob.dm | 40 +- .../procedural_mapping/mapGenerator.dm | 34 +- .../reagents/chemistry/chem_wiki_render.dm | 19 +- code/modules/requests/request_manager.dm | 23 +- code/modules/tgui_input/say_modal/speech.dm | 2 +- code/modules/transport/admin.dm | 53 +- code/modules/wiremod/core/admin_panel.dm | 10 +- code/modules/wiremod/core/duplicator.dm | 20 +- tgstation.dme | 5 + 104 files changed, 1901 insertions(+), 3290 deletions(-) create mode 100644 code/__DEFINES/admin_verb.dm create mode 100644 code/controllers/subsystem/admin_verbs.dm create mode 100644 code/modules/admin/verb_datums/_admin_verb_datum.dm create mode 100644 code/modules/admin/verb_datums/_admin_verb_holder.dm create mode 100644 code/modules/admin/verbs/special_verbs.dm diff --git a/.vscode/settings.json b/.vscode/settings.json index d7c1bfc1d1e31..0ef2ce67760b5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,6 +13,8 @@ }, "files.eol": "\n", "files.insertFinalNewline": true, + "files.trimTrailingWhitespace": true, + "editor.insertSpaces": false, "git.branchProtection": ["master"], "gitlens.advanced.blame.customArguments": ["-w"], "tgstationTestExplorer.project.resultsType": "json", diff --git a/code/__DEFINES/_protect.dm b/code/__DEFINES/_protect.dm index 9152cfcb5706f..a1202ebaf323b 100644 --- a/code/__DEFINES/_protect.dm +++ b/code/__DEFINES/_protect.dm @@ -11,7 +11,7 @@ return FALSE;\ }\ ##Path/Read(savefile/savefile){\ - qdel(src);\ + del(src);\ }\ ##Path/Write(savefile/savefile){\ return;\ @@ -19,3 +19,4 @@ #else #define GENERAL_PROTECT_DATUM(Path) #endif +// we del instead of qdel because for security reasons we must ensure the datum does not exist if Read is called. qdel will not enforce this. diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm index fbc223f62a5c1..84b0229a97612 100644 --- a/code/__DEFINES/admin.dm +++ b/code/__DEFINES/admin.dm @@ -23,6 +23,8 @@ #define BANTYPE_ANY_JOB 9 //Admin Permissions +/// Used for signifying that all admins can use this regardless of actual permissions +#define R_NONE NONE #define R_BUILD (1<<0) #define R_ADMIN (1<<1) #define R_BAN (1<<2) @@ -174,4 +176,3 @@ GLOBAL_VAR_INIT(ghost_role_flags, ALL) /// Used in logging uses of admin verbs (and sometimes some non-admin or debug verbs) to the blackbox /// Only pass it a string key, the verb being used. #define BLACKBOX_LOG_ADMIN_VERB(the_verb) SSblackbox.record_feedback("tally", "admin_verb", 1, the_verb) - diff --git a/code/__DEFINES/admin_verb.dm b/code/__DEFINES/admin_verb.dm new file mode 100644 index 0000000000000..cbf856bf4365f --- /dev/null +++ b/code/__DEFINES/admin_verb.dm @@ -0,0 +1,92 @@ +/client/CanProcCall(procname) + if(findtext(procname, "__avd_") == 1) + message_admins("[key_name_admin(usr)] attempted to directly call admin verb '[procname]'.") + log_admin("[key_name(usr)] attempted to directly call admin verb '[procname]'.") + return FALSE + return ..() + +/** + * This is the only macro you should use to define admin verbs. + * It will define the verb and the verb holder for you. + * Using it is very simple: + * ADMIN_VERB(verb_path, R_PERM, "Name", "Description", "Admin.Category", args...) + * This sets up all of the above and also acts as syntatic sugar as a verb delcaration for the verb itself. + * Note that the verb args have an injected `client/user` argument that is the user that called the verb. + * Do not use usr in your verb; technically you can but I'll kill you. + */ +#define _ADMIN_VERB(verb_path_name, verb_permissions, verb_name, verb_desc, verb_category, show_in_context_menu, verb_args...) \ +/datum/admin_verb/##verb_path_name \ +{ \ + name = ##verb_name; \ + description = ##verb_desc; \ + category = ##verb_category; \ + permissions = ##verb_permissions; \ + verb_path = /client/proc/__avd_##verb_path_name; \ +}; \ +/client/proc/__avd_##verb_path_name(##verb_args) \ +{ \ + set name = ##verb_name; \ + set desc = ##verb_desc; \ + set hidden = FALSE; /* this is explicitly needed as the proc begins with an underscore */ \ + set popup_menu = ##show_in_context_menu; \ + set category = ##verb_category; \ + var/list/_verb_args = list(usr, /datum/admin_verb/##verb_path_name); \ + _verb_args += args; \ + SSadmin_verbs.dynamic_invoke_verb(arglist(_verb_args)); \ +}; \ +/datum/admin_verb/##verb_path_name/__avd_do_verb(client/user, ##verb_args) + +#define ADMIN_VERB(verb_path_name, verb_permissions, verb_name, verb_desc, verb_category, verb_args...) \ +_ADMIN_VERB(verb_path_name, verb_permissions, verb_name, verb_desc, verb_category, FALSE, ##verb_args) + +#define ADMIN_VERB_ONLY_CONTEXT_MENU(verb_path_name, verb_permissions, verb_name, verb_args...) \ +_ADMIN_VERB(verb_path_name, verb_permissions, verb_name, ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, TRUE, ##verb_args) + +#define ADMIN_VERB_AND_CONTEXT_MENU(verb_path_name, verb_permissions, verb_name, verb_desc, verb_category, verb_args...) \ +_ADMIN_VERB(verb_path_name, verb_permissions, verb_name, verb_desc, verb_category, TRUE, ##verb_args) + +/// Used to define a special check to determine if the admin verb should exist at all. Useful for verbs such as play sound which require configuration. +#define ADMIN_VERB_CUSTOM_EXIST_CHECK(verb_path_name) \ +/datum/admin_verb/##verb_path_name/__avd_check_should_exist() + +/// Used to define the visibility flag of the verb. If the admin does not have this flag enabled they will not see the verb. +#define ADMIN_VERB_VISIBILITY(verb_path_name, verb_visibility) /datum/admin_verb/##verb_path_name/visibility_flag = ##verb_visibility + +// These are put here to prevent the "procedure override precedes definition" error. +/datum/admin_verb/proc/__avd_get_verb_path() + CRASH("__avd_get_verb_path not defined. use the macro") +/datum/admin_verb/proc/__avd_do_verb(...) + CRASH("__avd_do_verb not defined. use the macro") +/datum/admin_verb/proc/__avd_check_should_exist() + return TRUE + +/* + * This is an example of how to use the above macro: + * ``` + * ADMIN_VERB(name_of_verb, R_ADMIN, "Verb Name", "Verb Desc", "Verb Category", mob/target in world) + * to_chat(user, "Hello!") + * ``` + * Note the implied `client/user` argument that is injected into the verb. + * Also note that byond is shit and you cannot multi-line the macro call. + */ + +/// Use this to mark your verb as not having a description. Should ONLY be used if you are also hiding the verb! +#define ADMIN_VERB_NO_DESCRIPTION "" +/// Used to verbs you do not want to show up in the master verb panel. +#define ADMIN_CATEGORY_HIDDEN null + +// Admin verb categories +#define ADMIN_CATEGORY_MAIN "Admin" +#define ADMIN_CATEGORY_EVENTS "Admin.Events" +#define ADMIN_CATEGORY_FUN "Admin.Fun" +#define ADMIN_CATEGORY_GAME "Admin.Game" + +// Special categories that are seperated +#define ADMIN_CATEGORY_DEBUG "Debug" +#define ADMIN_CATEGORY_SERVER "Server" +#define ADMIN_CATEGORY_OBJECT "Object" +#define ADMIN_CATEGORY_MAPPING "Mapping" +#define ADMIN_CATEGORY_PROFILE "Profile" + +// Visibility flags +#define ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG "Map-Debug" diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index c3778351882bc..3878ba8c45ce3 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -137,6 +137,7 @@ #define INIT_ORDER_BLACKBOX 94 #define INIT_ORDER_SERVER_MAINT 93 #define INIT_ORDER_INPUT 85 +#define INIT_ORDER_ADMIN_VERBS 84 // needs to be pretty high, admins cant do much without it #define INIT_ORDER_SOUNDS 83 #define INIT_ORDER_INSTRUMENTS 82 #define INIT_ORDER_GREYSCALE 81 diff --git a/code/__HELPERS/hallucinations.dm b/code/__HELPERS/hallucinations.dm index 525114cea28bc..1eeab08d87691 100644 --- a/code/__HELPERS/hallucinations.dm +++ b/code/__HELPERS/hallucinations.dm @@ -113,11 +113,7 @@ GLOBAL_LIST_INIT(random_hallucination_weighted_list, generate_hallucination_weig to_chat(usr, span_boldnotice("The total weight of the hallucination weighted list is [total_weight].")) return total_weight -/// Debug verb for getting the weight of each distinct type within the random_hallucination_weighted_list -/client/proc/debug_hallucination_weighted_list_per_type() - set name = "Show Hallucination Weights" - set category = "Debug" - +ADMIN_VERB(debug_hallucination_weighted_list_per_type, R_DEBUG, "Show Hallucination Weights", "View the weight of each hallucination subtype in the random weighted list.", ADMIN_CATEGORY_DEBUG) var/header = "Type Weight Percent" var/total_weight = debug_hallucination_weighted_list() @@ -153,7 +149,7 @@ GLOBAL_LIST_INIT(random_hallucination_weighted_list, generate_hallucination_weig var/page_style = "" var/page_contents = "[page_style][header][jointext(assoc_to_keys(all_weights), "")]
" - var/datum/browser/popup = new(mob, "hallucinationdebug", "Hallucination Weights", 600, 400) + var/datum/browser/popup = new(user.mob, "hallucinationdebug", "Hallucination Weights", 600, 400) popup.set_content(page_contents) popup.open() diff --git a/code/_onclick/hud/movable_screen_objects.dm b/code/_onclick/hud/movable_screen_objects.dm index b1f40f7629442..e0a6c6873bd5a 100644 --- a/code/_onclick/hud/movable_screen_objects.dm +++ b/code/_onclick/hud/movable_screen_objects.dm @@ -44,40 +44,30 @@ offset[2] += y_off return offset_to_screen_loc(offset[1], offset[2], our_client?.view) -//Debug procs -/client/proc/test_movable_UI() - set category = "Debug" - set name = "Spawn Movable UI Object" - - var/atom/movable/screen/movable/M = new() +ADMIN_VERB(test_movable_UI, R_DEBUG, "Spawn Movable UI Object", "Spawn a movable UI object for testing.", ADMIN_CATEGORY_DEBUG) + var/atom/movable/screen/movable/M = new M.name = "Movable UI Object" M.icon_state = "block" M.maptext = MAPTEXT("Movable") M.maptext_width = 64 - var/screen_l = input(usr,"Where on the screen? (Formatted as 'X,Y' e.g: '1,1' for bottom left)","Spawn Movable UI Object") as text|null + var/screen_l = input(user, "Where on the screen? (Formatted as 'X,Y' e.g: '1,1' for bottom left)","Spawn Movable UI Object") as text|null if(!screen_l) return M.screen_loc = screen_l + user.screen += M - screen += M - - -/client/proc/test_snap_UI() - set category = "Debug" - set name = "Spawn Snap UI Object" - - var/atom/movable/screen/movable/snap/S = new() +ADMIN_VERB(test_snap_ui, R_DEBUG, "Spawn Snap UI Object", "Spawn a snap UI object for testing.", ADMIN_CATEGORY_DEBUG) + var/atom/movable/screen/movable/snap/S = new S.name = "Snap UI Object" S.icon_state = "block" S.maptext = MAPTEXT("Snap") S.maptext_width = 64 - var/screen_l = input(usr,"Where on the screen? (Formatted as 'X,Y' e.g: '1,1' for bottom left)","Spawn Snap UI Object") as text|null + var/screen_l = input(user,"Where on the screen? (Formatted as 'X,Y' e.g: '1,1' for bottom left)","Spawn Snap UI Object") as text|null if(!screen_l) return S.screen_loc = screen_l - - screen += S + user.screen += S diff --git a/code/controllers/admin.dm b/code/controllers/admin.dm index 421712d5ad454..5056e3804ef11 100644 --- a/code/controllers/admin.dm +++ b/code/controllers/admin.dm @@ -44,15 +44,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/statclick) usr.client.debug_variables(target) message_admins("Admin [key_name_admin(usr)] is debugging the [target] [class].") - -// Debug verbs. -/client/proc/restart_controller(controller in list("Master", "Failsafe")) - set category = "Debug" - set name = "Restart Controller" - set desc = "Restart one of the various periodic loop controllers for the game (be careful!)" - - if(!holder) - return +ADMIN_VERB(restart_controller, R_DEBUG, "Restart Controller", "Restart one of the various periodic loop controllers for the game (be careful!)", ADMIN_CATEGORY_DEBUG, controller in list("Master", "Failsafe")) switch(controller) if("Master") Recreate_MC() @@ -61,16 +53,9 @@ INITIALIZE_IMMEDIATE(/obj/effect/statclick) new /datum/controller/failsafe() BLACKBOX_LOG_ADMIN_VERB("Restart Failsafe Controller") - message_admins("Admin [key_name_admin(usr)] has restarted the [controller] controller.") - -/client/proc/debug_controller() - set category = "Debug" - set name = "Debug Controller" - set desc = "Debug the various periodic loop controllers for the game (be careful!)" - - if(!holder) - return + message_admins("Admin [key_name_admin(user)] has restarted the [controller] controller.") +ADMIN_VERB(debug_controller, R_DEBUG, "Debug Controller", "Debug the various periodic loop controllers for the game (be careful!)", ADMIN_CATEGORY_DEBUG) var/list/controllers = list() var/list/controller_choices = list() @@ -85,7 +70,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/statclick) if (!istype(controller)) return - debug_variables(controller) + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/debug_variables, controller) BLACKBOX_LOG_ADMIN_VERB("Debug Controller") - message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.") + message_admins("Admin [key_name_admin(user)] is debugging the [controller] controller.") diff --git a/code/controllers/subsystem/admin_verbs.dm b/code/controllers/subsystem/admin_verbs.dm new file mode 100644 index 0000000000000..9496b95d998a9 --- /dev/null +++ b/code/controllers/subsystem/admin_verbs.dm @@ -0,0 +1,150 @@ +GENERAL_PROTECT_DATUM(/datum/controller/subsystem/admin_verbs) + +SUBSYSTEM_DEF(admin_verbs) + name = "Admin Verbs" + flags = SS_NO_FIRE + init_order = INIT_ORDER_ADMIN_VERBS + /// A list of all admin verbs indexed by their type. + var/list/datum/admin_verb/admin_verbs_by_type = list() + /// A list of all admin verbs indexed by their visibility flag. + var/list/list/datum/admin_verb/admin_verbs_by_visibility_flag = list() + /// A map of all assosciated admins and their visibility flags. + var/list/admin_visibility_flags = list() + /// A list of all admins that are pending initialization of this SS. + var/list/admins_pending_subsytem_init = list() + +/datum/controller/subsystem/admin_verbs/Initialize() + setup_verb_list() + process_pending_admins() + return SS_INIT_SUCCESS + +/datum/controller/subsystem/admin_verbs/Recover() + admin_verbs_by_type = SSadmin_verbs.admin_verbs_by_type + +/datum/controller/subsystem/admin_verbs/stat_entry(msg) + return "[..()] | V: [length(admin_verbs_by_type)]" + +/datum/controller/subsystem/admin_verbs/proc/process_pending_admins() + var/list/pending_admins = admins_pending_subsytem_init + admins_pending_subsytem_init = null + for(var/admin_ckey in pending_admins) + assosciate_admin(GLOB.directory[admin_ckey]) + +/datum/controller/subsystem/admin_verbs/proc/setup_verb_list() + if(length(admin_verbs_by_type)) + CRASH("Attempting to setup admin verbs twice!") + for(var/datum/admin_verb/verb_type as anything in subtypesof(/datum/admin_verb)) + var/datum/admin_verb/verb_singleton = new verb_type + if(!verb_singleton.__avd_check_should_exist()) + qdel(verb_singleton, force = TRUE) + continue + + admin_verbs_by_type[verb_type] = verb_singleton + if(verb_singleton.visibility_flag) + if(!(verb_singleton.visibility_flag in admin_verbs_by_visibility_flag)) + admin_verbs_by_visibility_flag[verb_singleton.visibility_flag] = list() + admin_verbs_by_visibility_flag[verb_singleton.visibility_flag] |= list(verb_singleton) + +/datum/controller/subsystem/admin_verbs/proc/get_valid_verbs_for_admin(client/admin) + if(isnull(admin.holder)) + CRASH("Why are we checking a non-admin for their valid... ahem... admin verbs?") + + var/list/has_permission = list() + for(var/permission_flag in GLOB.bitflags) + if(admin.holder.check_for_rights(permission_flag)) + has_permission["[permission_flag]"] = TRUE + + var/list/valid_verbs = list() + for(var/datum/admin_verb/verb_type as anything in admin_verbs_by_type) + var/datum/admin_verb/verb_singleton = admin_verbs_by_type[verb_type] + if(!verify_visibility(admin, verb_singleton)) + continue + + var/verb_permissions = verb_singleton.permissions + if(verb_permissions == R_NONE) + valid_verbs |= list(verb_singleton) + else for(var/permission_flag in bitfield_to_list(verb_permissions)) + if(!has_permission["[permission_flag]"]) + continue + valid_verbs |= list(verb_singleton) + + return valid_verbs + +/datum/controller/subsystem/admin_verbs/proc/verify_visibility(client/admin, datum/admin_verb/verb_singleton) + var/needed_flag = verb_singleton.visibility_flag + return !needed_flag || (needed_flag in admin_visibility_flags[admin.ckey]) + +/datum/controller/subsystem/admin_verbs/proc/update_visibility_flag(client/admin, flag, state) + if(state) + admin_visibility_flags[admin.ckey] |= list(flag) + assosciate_admin(admin) + return + + admin_visibility_flags[admin.ckey] -= list(flag) + // they lost the flag, iterate over verbs with that flag and yoink em + for(var/datum/admin_verb/verb_singleton as anything in admin_verbs_by_visibility_flag[flag]) + verb_singleton.unassign_from_client(admin) + admin.init_verbs() + +/datum/controller/subsystem/admin_verbs/proc/dynamic_invoke_verb(client/admin, datum/admin_verb/verb_type, ...) + if(IsAdminAdvancedProcCall()) + message_admins("PERMISSION ELEVATION: [key_name_admin(admin)] attempted to dynamically invoke admin verb '[verb_type]'.") + return + + if(ismob(admin)) + var/mob/mob = admin + admin = mob.client + + if(!ispath(verb_type, /datum/admin_verb) || verb_type == /datum/admin_verb) + CRASH("Attempted to dynamically invoke admin verb with invalid typepath '[verb_type]'.") + if(isnull(admin.holder)) + CRASH("Attempted to dynamically invoke admin verb '[verb_type]' with a non-admin.") + + var/list/verb_args = args.Copy() + verb_args.Cut(2, 3) + var/datum/admin_verb/verb_singleton = admin_verbs_by_type[verb_type] // this cannot be typed because we need to use `:` + if(isnull(verb_singleton)) + CRASH("Attempted to dynamically invoke admin verb '[verb_type]' that doesn't exist.") + + if(!admin.holder.check_for_rights(verb_singleton.permissions)) + to_chat(admin, span_adminnotice("You lack the permissions to do this.")) + return + + var/old_usr = usr + usr = admin.mob + // THE MACRO ENSURES THIS EXISTS. IF IT EVER DOESNT EXIST SOMEONE DIDNT USE THE DAMN MACRO! + verb_singleton.__avd_do_verb(arglist(verb_args)) + usr = old_usr + SSblackbox.record_feedback("tally", "dynamic_admin_verb_invocation", 1, "[verb_type]") + +/** + * Assosciates and/or resyncs an admin with their accessible admin verbs. + */ +/datum/controller/subsystem/admin_verbs/proc/assosciate_admin(client/admin) + if(IsAdminAdvancedProcCall()) + return + + if(!isnull(admins_pending_subsytem_init)) // if the list exists we are still initializing + to_chat(admin, span_big(span_green("Admin Verbs are still initializing. Please wait and you will be automatically assigned your verbs when it is complete."))) + admins_pending_subsytem_init |= list(admin.ckey) + return + + // refresh their verbs + admin_visibility_flags[admin.ckey] ||= list() + for(var/datum/admin_verb/verb_singleton as anything in get_valid_verbs_for_admin(admin)) + verb_singleton.assign_to_client(admin) + admin.init_verbs() + +/** + * Unassosciates an admin from their admin verbs. + * Goes over all admin verbs because we don't know which ones are assigned to the admin's mob without a bunch of extra bookkeeping. + * This might be a performance issue in the future if we have a lot of admin verbs. + */ +/datum/controller/subsystem/admin_verbs/proc/deassosciate_admin(client/admin) + if(IsAdminAdvancedProcCall()) + return + + UnregisterSignal(admin, COMSIG_CLIENT_MOB_LOGIN) + for(var/datum/admin_verb/verb_type as anything in admin_verbs_by_type) + admin_verbs_by_type[verb_type].unassign_from_client(admin) + admin_visibility_flags -= list(admin.ckey) diff --git a/code/controllers/subsystem/explosions.dm b/code/controllers/subsystem/explosions.dm index e79fa0635c068..7bb597ba30e12 100644 --- a/code/controllers/subsystem/explosions.dm +++ b/code/controllers/subsystem/explosions.dm @@ -87,12 +87,9 @@ SUBSYSTEM_DEF(explosions) throwturf -= T held_throwturf -= T -/client/proc/check_bomb_impacts() - set name = "Check Bomb Impact" - set category = "Debug" - - var/newmode = tgui_alert(usr, "Use reactionary explosions?","Check Bomb Impact", list("Yes", "No")) - var/turf/epicenter = get_turf(mob) +ADMIN_VERB(check_bomb_impacts, R_DEBUG, "Check Bomb Impact", "See what the effect of a bomb would be.", ADMIN_CATEGORY_DEBUG) + var/newmode = tgui_alert(user, "Use reactionary explosions?","Check Bomb Impact", list("Yes", "No")) + var/turf/epicenter = get_turf(user.mob) if(!epicenter) return @@ -100,7 +97,7 @@ SUBSYSTEM_DEF(explosions) var/heavy = 0 var/light = 0 var/list/choices = list("Small Bomb","Medium Bomb","Big Bomb","Custom Bomb") - var/choice = tgui_input_list(usr, "Pick the bomb size", "Bomb Size?", choices) + var/choice = tgui_input_list(user, "Pick the bomb size", "Bomb Size?", choices) switch(choice) if(null) return 0 @@ -117,9 +114,9 @@ SUBSYSTEM_DEF(explosions) heavy = 5 light = 7 if("Custom Bomb") - dev = input("Devastation range (Tiles):") as num - heavy = input("Heavy impact range (Tiles):") as num - light = input("Light impact range (Tiles):") as num + dev = input(user, "Devastation range (Tiles):") as num + heavy = input(user, "Heavy impact range (Tiles):") as num + light = input(user, "Light impact range (Tiles):") as num var/max_range = max(dev, heavy, light) var/x0 = epicenter.x diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm index d010e3f95b5e0..041359006797b 100644 --- a/code/controllers/subsystem/mapping.dm +++ b/code/controllers/subsystem/mapping.dm @@ -643,46 +643,38 @@ GLOBAL_LIST_EMPTY(the_station_areas) holodeck_templates[holo_template.template_id] = holo_template -//Manual loading of away missions. -/client/proc/admin_away() - set name = "Load Away Mission" - set category = "Admin.Events" - - if(!holder || !check_rights(R_FUN)) - return - - +ADMIN_VERB(load_away_mission, R_FUN, "Load Away Mission", "Load a specific away mission for the station.", ADMIN_CATEGORY_EVENTS) if(!GLOB.the_gateway) - if(tgui_alert(usr, "There's no home gateway on the station. You sure you want to continue ?", "Uh oh", list("Yes", "No")) != "Yes") + if(tgui_alert(user, "There's no home gateway on the station. You sure you want to continue ?", "Uh oh", list("Yes", "No")) != "Yes") return var/list/possible_options = GLOB.potentialRandomZlevels + "Custom" var/away_name var/datum/space_level/away_level var/secret = FALSE - if(tgui_alert(usr, "Do you want your mission secret? (This will prevent ghosts from looking at your map in any way other than through a living player's eyes.)", "Are you $$$ekret?", list("Yes", "No")) == "Yes") + if(tgui_alert(user, "Do you want your mission secret? (This will prevent ghosts from looking at your map in any way other than through a living player's eyes.)", "Are you $$$ekret?", list("Yes", "No")) == "Yes") secret = TRUE - var/answer = input("What kind?","Away") as null|anything in possible_options + var/answer = input(user, "What kind?","Away") as null|anything in possible_options switch(answer) if("Custom") - var/mapfile = input("Pick file:", "File") as null|file + var/mapfile = input(user, "Pick file:", "File") as null|file if(!mapfile) return away_name = "[mapfile] custom" - to_chat(usr,span_notice("Loading [away_name]...")) + to_chat(user,span_notice("Loading [away_name]...")) var/datum/map_template/template = new(mapfile, "Away Mission") away_level = template.load_new_z(secret) else if(answer in GLOB.potentialRandomZlevels) away_name = answer - to_chat(usr,span_notice("Loading [away_name]...")) + to_chat(user,span_notice("Loading [away_name]...")) var/datum/map_template/template = new(away_name, "Away Mission") away_level = template.load_new_z(secret) else return - message_admins("Admin [key_name_admin(usr)] has loaded [away_name] away mission.") - log_admin("Admin [key_name(usr)] has loaded [away_name] away mission.") + message_admins("Admin [key_name_admin(user)] has loaded [away_name] away mission.") + log_admin("Admin [key_name(user)] has loaded [away_name] away mission.") if(!away_level) message_admins("Loading [away_name] failed!") return diff --git a/code/controllers/subsystem/weather.dm b/code/controllers/subsystem/weather.dm index 78c99f4790366..b8496a623eba1 100644 --- a/code/controllers/subsystem/weather.dm +++ b/code/controllers/subsystem/weather.dm @@ -86,15 +86,9 @@ SUBSYSTEM_DEF(weather) /datum/controller/subsystem/weather/proc/get_weather_by_type(type) return locate(type) in processing -/** - * Calls end() on all current weather effects that are currently processing in the weather subsystem. - */ -/client/proc/stop_weather() - set category = "Debug" - set name = "Stop All Active Weather" - - log_admin("[key_name(src)] stopped all currently active weather.") - message_admins("[key_name_admin(src)] stopped all currently active weather.") +ADMIN_VERB(stop_weather, R_DEBUG|R_ADMIN, "Stop All Active Weather", "Stop all currently active weather.", ADMIN_CATEGORY_DEBUG) + log_admin("[key_name(user)] stopped all currently active weather.") + message_admins("[key_name_admin(user)] stopped all currently active weather.") for(var/datum/weather/current_weather as anything in SSweather.processing) if(current_weather in SSweather.processing) current_weather.end() diff --git a/code/datums/brain_damage/imaginary_friend.dm b/code/datums/brain_damage/imaginary_friend.dm index 18ca8172968d1..e3891392d1a76 100644 --- a/code/datums/brain_damage/imaginary_friend.dm +++ b/code/datums/brain_damage/imaginary_friend.dm @@ -217,11 +217,11 @@ message = capitalize(message) if(message_mods[RADIO_EXTENSION] == MODE_ADMIN) - client?.cmd_admin_say(message) + SSadmin_verbs.dynamic_invoke_verb(client, /datum/admin_verb/cmd_admin_say, message) return if(message_mods[RADIO_EXTENSION] == MODE_DEADMIN) - client?.dsay(message) + SSadmin_verbs.dynamic_invoke_verb(client, /datum/admin_verb/dsay, message) return if(check_emote(message, forced)) diff --git a/code/datums/components/puzzgrid.dm b/code/datums/components/puzzgrid.dm index e91bcdb30026b..d7e264f651f97 100644 --- a/code/datums/components/puzzgrid.dm +++ b/code/datums/components/puzzgrid.dm @@ -280,12 +280,7 @@ var/list/answers = list() var/description -/// Debug verb for validating that all puzzgrids can be created successfully. -/// Locked behind a verb because it's fairly slow and memory intensive. -/client/proc/validate_puzzgrids() - set name = "Validate Puzzgrid Config" - set category = "Debug" - +ADMIN_VERB(validate_puzzgrids, R_DEBUG, "Validate Puzzgrid Config", "Validate the puzzgrid config to ensure it's set up correctly.", ADMIN_CATEGORY_DEBUG) var/line_number = 0 for (var/line in world.file2list(PUZZGRID_CONFIG)) @@ -296,16 +291,16 @@ var/line_json_decoded = safe_json_decode(line) if (isnull(line_json_decoded)) - to_chat(src, span_warning("Line [line_number] in puzzgrids.txt is not a JSON: [line]")) + to_chat(user, span_warning("Line [line_number] in puzzgrids.txt is not a JSON: [line]")) continue var/datum/puzzgrid/puzzgrid = new var/populate_result = puzzgrid.populate(line_json_decoded) if (populate_result != TRUE) - to_chat(src, span_warning("Line [line_number] in puzzgrids.txt is not formatted correctly: [populate_result]")) + to_chat(user, span_warning("Line [line_number] in puzzgrids.txt is not formatted correctly: [populate_result]")) - to_chat(src, span_notice("Validated. If you did not see any errors, you're in the clear.")) + to_chat(user, span_notice("Validated. If you did not see any errors, you're in the clear.")) #undef PUZZGRID_CONFIG #undef PUZZGRID_GROUP_COUNT diff --git a/code/datums/keybinding/admin.dm b/code/datums/keybinding/admin.dm index 80936aa41e76c..1e94f71e58ad4 100644 --- a/code/datums/keybinding/admin.dm +++ b/code/datums/keybinding/admin.dm @@ -23,7 +23,7 @@ . = ..() if(.) return - user.admin_ghost() + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/admin_ghost) return TRUE /datum/keybinding/admin/player_panel_new @@ -51,7 +51,7 @@ . = ..() if(.) return - user.togglebuildmodeself() + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/build_mode_self) return TRUE /datum/keybinding/admin/stealthmode @@ -65,7 +65,7 @@ . = ..() if(.) return - user.stealth() + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/stealth) return TRUE /datum/keybinding/admin/invisimin @@ -79,7 +79,7 @@ . = ..() if(.) return - user.invisimin() + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/invisimin) return TRUE /datum/keybinding/admin/deadsay @@ -107,7 +107,7 @@ . = ..() if(.) return - user.deadmin() + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/deadmin) return TRUE /datum/keybinding/admin/readmin @@ -135,5 +135,5 @@ . = ..() if(.) return - user.holder?.display_tags() + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/display_tags) return TRUE diff --git a/code/datums/station_traits/admin_panel.dm b/code/datums/station_traits/admin_panel.dm index 02eca48b54f0c..67669027c54d0 100644 --- a/code/datums/station_traits/admin_panel.dm +++ b/code/datums/station_traits/admin_panel.dm @@ -1,10 +1,6 @@ -/// Opens the station traits admin panel -/datum/admins/proc/station_traits_panel() - set name = "Modify Station Traits" - set category = "Admin.Events" - +ADMIN_VERB(station_traits_panel, R_FUN, "Modify Station Traits", "Modify the station traits for the next round.", ADMIN_CATEGORY_EVENTS) var/static/datum/station_traits_panel/station_traits_panel = new - station_traits_panel.ui_interact(usr) + station_traits_panel.ui_interact(user.mob) /datum/station_traits_panel var/static/list/future_traits diff --git a/code/game/atom/atom_vv.dm b/code/game/atom/atom_vv.dm index 8830a4af2f433..10a6cbff24a92 100644 --- a/code/game/atom/atom_vv.dm +++ b/code/game/atom/atom_vv.dm @@ -67,14 +67,10 @@ message_admins(span_notice("[key_name(usr)] has added [amount] units of [chosen_id] to [src]")) if(href_list[VV_HK_TRIGGER_EXPLOSION]) - if(!check_rights(R_FUN)) - return - usr.client.cmd_admin_explosion(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/admin_explosion, src) if(href_list[VV_HK_TRIGGER_EMP]) - if(!check_rights(R_FUN)) - return - usr.client.cmd_admin_emp(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/admin_emp, src) if(href_list[VV_HK_SHOW_HIDDENPRINTS]) if(!check_rights(R_ADMIN)) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 71bc78fa4c402..b6946dffc9aca 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -147,9 +147,7 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) return if(href_list[VV_HK_OSAY]) - if(!check_rights(R_FUN, FALSE)) - return - usr.client.object_say(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/object_say, src) if(href_list[VV_HK_MASS_DEL_TYPE]) if(!check_rights(R_DEBUG|R_SERVER)) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 99aa63325ad0e..10b9a58b87007 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -48,14 +48,9 @@ ////////////////////////////////////////////////////////////////////////////////////////////////ADMIN HELPER PROCS -/datum/admins/proc/spawn_atom(object as text) - set category = "Debug" - set desc = "(atom path) Spawn an atom" - set name = "Spawn" - - if(!check_rights(R_SPAWN) || !object) +ADMIN_VERB(spawn_atom, R_SPAWN, "Spawn", "Spawn an atom.", ADMIN_CATEGORY_DEBUG, object as text) + if(!object) return - var/list/preparsed = splittext(object,":") var/path = preparsed[1] var/amount = 1 @@ -65,7 +60,7 @@ var/chosen = pick_closest_path(path) if(!chosen) return - var/turf/T = get_turf(usr) + var/turf/T = get_turf(user.mob) if(ispath(chosen, /turf)) T.ChangeTurf(chosen) @@ -74,21 +69,14 @@ var/atom/A = new chosen(T) A.flags_1 |= ADMIN_SPAWNED_1 - log_admin("[key_name(usr)] spawned [amount] x [chosen] at [AREACOORD(usr)]") + log_admin("[key_name(user)] spawned [amount] x [chosen] at [AREACOORD(user.mob)]") BLACKBOX_LOG_ADMIN_VERB("Spawn Atom") -/datum/admins/proc/podspawn_atom(object as text) - set category = "Debug" - set desc = "(atom path) Spawn an atom via supply drop" - set name = "Podspawn" - - if(!check_rights(R_SPAWN)) - return - +ADMIN_VERB(spawn_atom_pod, R_SPAWN, "PodSpawn", "Spawn an atom via supply drop.", ADMIN_CATEGORY_DEBUG, object as text) var/chosen = pick_closest_path(object) if(!chosen) return - var/turf/target_turf = get_turf(usr) + var/turf/target_turf = get_turf(user.mob) if(ispath(chosen, /turf)) target_turf.ChangeTurf(chosen) @@ -101,25 +89,18 @@ var/atom/A = new chosen(pod) A.flags_1 |= ADMIN_SPAWNED_1 - log_admin("[key_name(usr)] pod-spawned [chosen] at [AREACOORD(usr)]") + log_admin("[key_name(user)] pod-spawned [chosen] at [AREACOORD(user.mob)]") BLACKBOX_LOG_ADMIN_VERB("Podspawn Atom") -/datum/admins/proc/spawn_cargo(object as text) - set category = "Debug" - set desc = "(atom path) Spawn a cargo crate" - set name = "Spawn Cargo" - - if(!check_rights(R_SPAWN)) - return - +ADMIN_VERB(spawn_cargo, R_SPAWN, "Spawn Cargo", "Spawn a cargo crate.", ADMIN_CATEGORY_DEBUG, object as text) var/chosen = pick_closest_path(object, make_types_fancy(subtypesof(/datum/supply_pack))) if(!chosen) return var/datum/supply_pack/S = new chosen S.admin_spawned = TRUE - S.generate(get_turf(usr)) + S.generate(get_turf(user.mob)) - log_admin("[key_name(usr)] spawned cargo pack [chosen] at [AREACOORD(usr)]") + log_admin("[key_name(user)] spawned cargo pack [chosen] at [AREACOORD(user.mob)]") BLACKBOX_LOG_ADMIN_VERB("Spawn Cargo") /datum/admins/proc/dynamic_mode_options(mob/user) @@ -246,10 +227,8 @@ log_admin(logged_message) message_admins(logged_message) -/datum/admins/proc/create_or_modify_area() - set category = "Debug" - set name = "Create or modify area" - create_area(usr) +ADMIN_VERB(create_or_modify_area, R_DEBUG, "Create Or Modify Area", "Create of modify an area. wow.", ADMIN_CATEGORY_DEBUG) + create_area(user.mob) //Kicks all the clients currently in the lobby. The second parameter (kick_only_afk) determins if an is_afk() check is ran, or if all clients are kicked //defaults to kicking everyone (afk + non afk clients in the lobby) diff --git a/code/modules/admin/admin_fax_panel.dm b/code/modules/admin/admin_fax_panel.dm index fe1f03d7d7ec2..8874b6f38eb5a 100644 --- a/code/modules/admin/admin_fax_panel.dm +++ b/code/modules/admin/admin_fax_panel.dm @@ -1,15 +1,6 @@ -/** - * If client have R_ADMIN flag, opens an admin fax panel. - */ -/client/proc/fax_panel() - set category = "Admin.Events" - set name = "Fax Panel" - - if(!check_rights(R_ADMIN)) - return - - var/datum/fax_panel_interface/ui = new(usr) - ui.ui_interact(usr) +ADMIN_VERB(fax_panel, R_ADMIN, "Fax Panel", "View and respond to faxes sent to CC.", ADMIN_CATEGORY_EVENTS) + var/datum/fax_panel_interface/ui = new /datum/fax_panel_interface(user.mob) + ui.ui_interact(user.mob) /// Admin Fax Panel. Tool for sending fax messages faster. /datum/fax_panel_interface @@ -97,15 +88,15 @@ switch(action) if("follow") - if(!isobserver(usr)) - usr.client?.admin_ghost() + if(!isobserver(ui.user)) + SSadmin_verbs.dynamic_invoke_verb(ui.user, /datum/admin_verb/admin_ghost) - usr.client?.admin_follow(action_fax) + ui.user.client?.admin_follow(action_fax) if("preview") // see saved variant if(!fax_paper) return - fax_paper.ui_interact(usr) + fax_paper.ui_interact(ui.user) if("save") // save paper if(params["paperName"]) @@ -129,7 +120,7 @@ if(stamp) fax_paper.add_stamp(stamp_class, params["stampX"], params["stampY"], params["stampAngle"], stamp) - fax_paper.update_static_data(usr) // OK, it's work, and update UI. + fax_paper.update_static_data(ui.user) // OK, it's work, and update UI. if("send") //copy @@ -137,9 +128,9 @@ our_fax.name = fax_paper.name //send action_fax.receive(our_fax, sending_fax_name) - message_admins("[key_name_admin(usr)] has sent a custom fax message to [action_fax.name][ADMIN_FLW(action_fax)][ADMIN_SHOW_PAPER(fax_paper)].") - log_admin("[key_name(usr)] has sent a custom fax message to [action_fax.name]") + message_admins("[key_name_admin(ui.user)] has sent a custom fax message to [action_fax.name][ADMIN_FLW(action_fax)][ADMIN_SHOW_PAPER(fax_paper)].") + log_admin("[key_name(ui.user)] has sent a custom fax message to [action_fax.name]") if("createPaper") - var/obj/item/paper/our_paper = fax_paper.copy(/obj/item/paper, usr.loc) + var/obj/item/paper/our_paper = fax_paper.copy(/obj/item/paper, ui.user.loc) our_paper.name = fax_paper.name diff --git a/code/modules/admin/admin_investigate.dm b/code/modules/admin/admin_investigate.dm index 94ea182891f56..edc3525bf2f07 100644 --- a/code/modules/admin/admin_investigate.dm +++ b/code/modules/admin/admin_investigate.dm @@ -10,13 +10,8 @@ WRITE_FILE(F, "[time_stamp(format = "YYYY-MM-DD hh:mm:ss")] [REF(src)] ([x],[y],[z]) || [source] [message]
") -/client/proc/investigate_show() - set name = "Investigate" - set category = "Admin.Game" - if(!holder) - return - - var/list/investigates = list( +ADMIN_VERB(investigate_show, R_NONE, "Investigate", "Browse various detailed logs.", ADMIN_CATEGORY_GAME) + var/static/list/investigates = list( INVESTIGATE_ACCESSCHANGES, INVESTIGATE_ATMOS, INVESTIGATE_BOTANY, @@ -48,7 +43,7 @@ var/list/combined = sort_list(logs_present) + sort_list(logs_missing) - var/selected = tgui_input_list(src, "Investigate what?", "Investigation", combined) + var/selected = tgui_input_list(user, "Investigate what?", "Investigation", combined) if(isnull(selected)) return if(!(selected in combined) || selected == "---") @@ -62,6 +57,6 @@ var/F = file("[GLOB.log_directory]/[selected].html") if(!fexists(F)) - to_chat(src, span_danger("No [selected] logfile was found."), confidential = TRUE) + to_chat(user, span_danger("No [selected] logfile was found."), confidential = TRUE) return - src << browse(F,"window=investigate[selected];size=800x300") + user << browse(F,"window=investigate[selected];size=800x300") diff --git a/code/modules/admin/admin_pda_message.dm b/code/modules/admin/admin_pda_message.dm index 44ca86f893ec7..c1c4fef0b57c4 100644 --- a/code/modules/admin/admin_pda_message.dm +++ b/code/modules/admin/admin_pda_message.dm @@ -1,12 +1,6 @@ -///Allows an admin to send messages on PDA -/client/proc/message_pda() - set name = "PDA Message" - set category = "Admin.Events" - if(!holder || !check_rights(R_ADMIN)) - return - - holder.message_pda() +ADMIN_VERB(message_pda, R_ADMIN, "PDA Message", "Send a message to a user's PDA.", ADMIN_CATEGORY_EVENTS) + user.holder.message_pda() ///Opens up the PDA Message Panel /datum/admins/proc/message_pda() diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 7864b3d732900..352ccab297aea 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -1,468 +1,103 @@ -//admin verb groups - They can overlap if you so wish. Only one of each verb will exist in the verbs list regardless -//the procs are cause you can't put the comments in the GLOB var define -GLOBAL_LIST_INIT(admin_verbs_default, world.AVerbsDefault()) -GLOBAL_PROTECT(admin_verbs_default) -/world/proc/AVerbsDefault() - return list( - /client/proc/cmd_admin_pm_context, /*right-click adminPM interface*/ - /client/proc/cmd_admin_pm_panel, /*admin-pm list*/ - /client/proc/cmd_admin_say, /*admin-only ooc chat*/ - /client/proc/deadmin, /*destroys our own admin datum so we can play as a regular player*/ - /client/proc/debugstatpanel, - /client/proc/debug_variables, /*allows us to -see- the variables of any instance in the game. +VAREDIT needed to modify*/ - /client/proc/dsay, /*talk in deadchat using our ckey/fakekey*/ - /client/proc/fix_air, /*resets air in designated radius to its default atmos composition*/ - /client/proc/hide_verbs, /*hides all our adminverbs*/ - /client/proc/investigate_show, /*various admintools for investigation. Such as a singulo grief-log*/ - /client/proc/mark_datum_mapview, - /client/proc/reestablish_db_connection, /*reattempt a connection to the database*/ - /client/proc/reload_admins, - /client/proc/requests, - /client/proc/secrets, - /client/proc/stop_sounds, - /client/proc/tag_datum_mapview, - ) -GLOBAL_LIST_INIT(admin_verbs_admin, world.AVerbsAdmin()) -GLOBAL_PROTECT(admin_verbs_admin) -/world/proc/AVerbsAdmin() - return list( -// Admin datums - /datum/admins/proc/access_news_network, /*allows access of newscasters*/ - /datum/admins/proc/announce, /*priority announce something to all clients.*/ - /datum/admins/proc/display_tags, - /datum/admins/proc/fishing_calculator, - /datum/admins/proc/known_alts_panel, - /datum/admins/proc/show_lag_switch_panel, - /datum/admins/proc/open_borgopanel, - /datum/admins/proc/open_shuttlepanel, /* Opens shuttle manipulator UI */ - /datum/admins/proc/paintings_manager, - /datum/admins/proc/set_admin_notice, /*announcement all clients see when joining the server.*/ - /datum/admins/proc/show_player_panel, /*shows an interface for individual players, with various links (links require additional flags*/ - /datum/admins/proc/toggleenter, /*toggles whether people can join the current game*/ - /datum/admins/proc/toggleguests, /*toggles whether guests can join the current game*/ - /datum/admins/proc/toggleooc, /*toggles ooc on/off for everyone*/ - /datum/admins/proc/toggleoocdead, /*toggles ooc on/off for everyone who is dead*/ - /datum/admins/proc/trophy_manager, - /datum/admins/proc/view_all_circuits, - /datum/verbs/menu/Admin/verb/playerpanel, /* It isn't /datum/admin but it fits no less */ - /datum/admins/proc/change_shuttle_events, //allows us to change the shuttle events - /datum/admins/proc/reset_tram, //tram related admin actions -// Client procs - /client/proc/admin_call_shuttle, /*allows us to call the emergency shuttle*/ - /client/proc/admin_cancel_shuttle, /*allows us to cancel the emergency shuttle, sending it back to centcom*/ - /client/proc/admin_disable_shuttle, /*allows us to disable the emergency shuttle admin-wise so that it cannot be called*/ - /client/proc/admin_enable_shuttle, /*undoes the above*/ - /client/proc/admin_ghost, /*allows us to ghost/reenter body at will*/ - /client/proc/admin_hostile_environment, /*Allows admins to prevent the emergency shuttle from leaving, also lets admins clear hostile environments if theres one stuck*/ - /client/proc/centcom_podlauncher,/*Open a window to launch a Supplypod and configure it or it's contents*/ - /client/proc/check_ai_laws, /*shows AI and borg laws*/ - /client/proc/check_antagonists, /*shows all antags*/ - /client/proc/cmd_admin_check_contents, /*displays the contents of an instance*/ - /client/proc/cmd_admin_check_player_exp, /* shows players by playtime */ - /client/proc/cmd_admin_create_centcom_report, - /client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/ - /client/proc/cmd_admin_direct_narrate, /*send text directly to a player with no padding. Useful for narratives and fluff-text*/ - /client/proc/cmd_admin_headset_message, /*send a message to somebody through their headset as CentCom*/ - /client/proc/cmd_admin_local_narrate, /*sends text to all mobs within view of atom*/ - /client/proc/cmd_admin_subtle_message, /*send a message to somebody as a 'voice in their head'*/ - /client/proc/cmd_admin_world_narrate, /*sends text to all players with no padding*/ - /client/proc/cmd_change_command_name, - /client/proc/create_mob_worm, - /client/proc/fax_panel, /*send a paper to fax*/ - /client/proc/force_load_lazy_template, - /client/proc/game_panel, /*game panel, allows to change game-mode etc*/ - /client/proc/Getmob, /*teleports a mob to our location*/ - /client/proc/Getkey, /*teleports a mob with a certain ckey to our location*/ - /client/proc/getserverlogs, /*for accessing server logs*/ - /client/proc/getcurrentlogs, /*for accessing server logs for the current round*/ - /client/proc/ghost_pool_protection, /*opens a menu for toggling ghost roles*/ - /client/proc/invisimin, /*allows our mob to go invisible/visible*/ - /client/proc/jumptoarea, - /client/proc/jumptokey, /*allows us to jump to the location of a mob with a certain ckey*/ - /client/proc/jumptomob, /*allows us to jump to a specific mob*/ - /client/proc/jumptoturf, /*allows us to jump to a specific turf*/ - /client/proc/jumptocoord, /*we ghost and jump to a coordinate*/ - /client/proc/list_bombers, - /client/proc/list_dna, - /client/proc/list_fingerprints, - /client/proc/list_law_changes, - /client/proc/list_signalers, - /client/proc/manage_sect, /*manage chaplain religious sect*/ - /client/proc/message_pda, /*send a message to somebody on PDA*/ - /client/proc/respawn_character, - /client/proc/show_manifest, - /client/proc/toggle_AI_interact, /*toggle admin ability to interact with machines as an AI*/ - /client/proc/toggle_combo_hud, /* toggle display of the combination pizza antag and taco sci/med/eng hud */ - /client/proc/toggle_view_range, /*changes how far we can see*/ - /client/proc/cmd_admin_law_panel, - /client/proc/log_viewer_new, - /client/proc/player_ticket_history, - ) -GLOBAL_LIST_INIT(admin_verbs_ban, list(/client/proc/unban_panel, /client/proc/ban_panel, /client/proc/stickybanpanel, /client/proc/library_control)) -GLOBAL_PROTECT(admin_verbs_ban) -GLOBAL_LIST_INIT(admin_verbs_sounds, list(/client/proc/play_local_sound, /client/proc/play_direct_mob_sound, /client/proc/play_sound, /client/proc/set_round_end_sound)) -GLOBAL_PROTECT(admin_verbs_sounds) -GLOBAL_LIST_INIT(admin_verbs_fun, list( -// Admin datums - /datum/admins/proc/station_traits_panel, -// Client procs - /client/proc/admin_away, - /client/proc/add_marked_mob_ability, - /client/proc/admin_change_sec_level, - /client/proc/cinematic, - /client/proc/cmd_admin_add_freeform_ai_law, - /client/proc/cmd_admin_gib_self, - /client/proc/cmd_select_equipment, - /client/proc/command_report_footnote, - /client/proc/delay_command_report, - /client/proc/drop_bomb, - /client/proc/drop_dynex_bomb, - /client/proc/forceEvent, - /client/proc/mass_zombie_cure, - /client/proc/mass_zombie_infection, - /client/proc/object_say, - /client/proc/polymorph_all, - /client/proc/remove_marked_mob_ability, - /client/proc/reset_ooc, - /client/proc/run_weather, - /client/proc/set_dynex_scale, - /client/proc/set_ooc, - /client/proc/show_tip, - /client/proc/smite, - /client/proc/summon_ert, - /client/proc/toggle_nuke, - /client/proc/toggle_random_events, - )) -GLOBAL_PROTECT(admin_verbs_fun) -GLOBAL_LIST_INIT(admin_verbs_spawn, list(/datum/admins/proc/spawn_atom, /datum/admins/proc/podspawn_atom, /datum/admins/proc/spawn_cargo, /datum/admins/proc/spawn_objasmob, /client/proc/respawn_character, /datum/admins/proc/beaker_panel)) -GLOBAL_PROTECT(admin_verbs_spawn) -GLOBAL_LIST_INIT(admin_verbs_server, world.AVerbsServer()) -GLOBAL_PROTECT(admin_verbs_server) -/world/proc/AVerbsServer() - return list( -// Admin datums - /datum/admins/proc/delay, - /datum/admins/proc/delay_round_end, - /datum/admins/proc/end_round, - /datum/admins/proc/restart, - /datum/admins/proc/startnow, - /datum/admins/proc/toggleaban, - /datum/admins/proc/toggleAI, -// Client procs - /client/proc/adminchangemap, - /client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/ - /client/proc/cmd_debug_del_all, - /client/proc/cmd_debug_force_del_all, - /client/proc/cmd_debug_hard_del_all, - /client/proc/everyone_random, - /client/proc/forcerandomrotate, - /client/proc/generate_job_config, - /client/proc/panicbunker, - /client/proc/toggle_cdn, - /client/proc/toggle_hub, - /client/proc/toggle_interviews, - /client/proc/toggle_random_events, - ) -GLOBAL_LIST_INIT(admin_verbs_debug, world.AVerbsDebug()) -GLOBAL_PROTECT(admin_verbs_debug) -/world/proc/AVerbsDebug() - return list( - #ifdef TESTING /* Keep these at the top to not make the list look fugly */ - /client/proc/check_missing_sprites, - #endif - /proc/machine_upgrade, - /datum/admins/proc/create_or_modify_area, - /client/proc/adventure_manager, - /client/proc/atmos_control, - /client/proc/callproc, - /client/proc/callproc_datum, - /client/proc/check_bomb_impacts, - /client/proc/check_timer_sources, - /client/proc/clear_dynamic_transit, - /client/proc/cmd_admin_debug_traitor_objectives, - /client/proc/cmd_admin_delete, - /client/proc/cmd_admin_list_open_jobs, - /client/proc/cmd_admin_toggle_fov, - /client/proc/cmd_debug_del_all, - /client/proc/cmd_debug_force_del_all, - /client/proc/cmd_debug_hard_del_all, - /client/proc/cmd_debug_make_powernets, - /client/proc/cmd_debug_mob_lists, - /client/proc/cmd_display_del_log, - /client/proc/cmd_display_init_log, - /client/proc/cmd_display_overlay_log, - /client/proc/Debug2, - /client/proc/debug_controller, - /client/proc/debug_hallucination_weighted_list_per_type, - /client/proc/debug_huds, - /client/proc/debugNatureMapGenerator, - /client/proc/debug_plane_masters, - /client/proc/debug_spell_requirements, - /client/proc/display_sendmaps, - /client/proc/enable_mapping_verbs, - /client/proc/generate_wikichem_list, - /client/proc/get_dynex_power, /*debug verbs for dynex explosions.*/ - /client/proc/get_dynex_range, /*debug verbs for dynex explosions.*/ - /client/proc/jump_to_ruin, - /client/proc/load_circuit, - /client/proc/map_export, - /client/proc/map_template_load, - /client/proc/map_template_upload, - /client/proc/modify_goals, - /client/proc/open_colorblind_test, - /client/proc/open_lua_editor, - /client/proc/outfit_manager, - /client/proc/populate_world, - /client/proc/pump_random_event, - /client/proc/print_cards, - /client/proc/reestablish_tts_connection, - /client/proc/reload_cards, - /client/proc/reload_configuration, - /client/proc/restart_controller, - /client/proc/run_empty_query, - /client/proc/SDQL2_query, - /client/proc/set_dynex_scale, - /client/proc/spawn_debug_full_crew, - /client/proc/test_cardpack_distribution, - /client/proc/test_movable_UI, - /client/proc/test_snap_UI, - /client/proc/toggle_cdn, - /client/proc/toggle_medal_disable, - /client/proc/unload_ctf, - /client/proc/validate_cards, - /client/proc/validate_puzzgrids, - /client/proc/GeneratePipeSpritesheet, - /client/proc/view_runtimes, - /client/proc/stop_weather, - ) -GLOBAL_LIST_INIT(admin_verbs_possess, list(/proc/possess, /proc/release)) -GLOBAL_PROTECT(admin_verbs_possess) -GLOBAL_LIST_INIT(admin_verbs_permissions, list(/client/proc/edit_admin_permissions)) -GLOBAL_PROTECT(admin_verbs_permissions) -GLOBAL_LIST_INIT(admin_verbs_poll, list(/client/proc/poll_panel)) -GLOBAL_PROTECT(admin_verbs_poll) - /client/proc/add_admin_verbs() - if(holder) - control_freak = CONTROL_FREAK_SKIN | CONTROL_FREAK_MACROS - - var/rights = holder.rank_flags() - add_verb(src, GLOB.admin_verbs_default) - if(rights & R_BUILD) - add_verb(src, /client/proc/togglebuildmodeself) - if(rights & R_ADMIN) - add_verb(src, GLOB.admin_verbs_admin) - if(rights & R_BAN) - add_verb(src, GLOB.admin_verbs_ban) - if(rights & R_FUN) - add_verb(src, GLOB.admin_verbs_fun) - if(rights & R_SERVER) - add_verb(src, GLOB.admin_verbs_server) - if(rights & R_DEBUG) - add_verb(src, GLOB.admin_verbs_debug) - if(rights & R_POSSESS) - add_verb(src, GLOB.admin_verbs_possess) - if(rights & R_PERMISSIONS) - add_verb(src, GLOB.admin_verbs_permissions) - if(rights & R_STEALTH) - add_verb(src, /client/proc/stealth) - if(rights & R_POLL) - add_verb(src, GLOB.admin_verbs_poll) - if(rights & R_SOUND) - add_verb(src, GLOB.admin_verbs_sounds) - if(CONFIG_GET(string/invoke_youtubedl)) - add_verb(src, /client/proc/play_web_sound) - if(rights & R_SPAWN) - add_verb(src, GLOB.admin_verbs_spawn) -#ifdef MAP_TEST - remove_verb(src, /client/proc/enable_mapping_verbs) - add_verb(src, list(/client/proc/disable_mapping_verbs, GLOB.admin_verbs_debug_mapping)) -#endif + control_freak = CONTROL_FREAK_SKIN | CONTROL_FREAK_MACROS + SSadmin_verbs.assosciate_admin(src) /client/proc/remove_admin_verbs() - remove_verb(src, list( - GLOB.admin_verbs_default, - /client/proc/togglebuildmodeself, - GLOB.admin_verbs_admin, - GLOB.admin_verbs_ban, - GLOB.admin_verbs_fun, - GLOB.admin_verbs_server, - GLOB.admin_verbs_debug, - GLOB.admin_verbs_possess, - GLOB.admin_verbs_permissions, - /client/proc/stealth, - GLOB.admin_verbs_poll, - GLOB.admin_verbs_sounds, - /client/proc/play_web_sound, - GLOB.admin_verbs_spawn, - /*Debug verbs added by "show debug verbs"*/ - GLOB.admin_verbs_debug_mapping, - /client/proc/disable_mapping_verbs, - /client/proc/readmin - )) - -/client/proc/hide_verbs() - set name = "Adminverbs - Hide All" - set category = "Admin" - - remove_admin_verbs() - add_verb(src, /client/proc/show_verbs) - - to_chat(src, span_interface("Almost all of your adminverbs have been hidden."), confidential = TRUE) - BLACKBOX_LOG_ADMIN_VERB("Hide All Adminverbs") - return - -/client/proc/show_verbs() - set name = "Adminverbs - Show" - set category = "Admin" - - remove_verb(src, /client/proc/show_verbs) - add_admin_verbs() - - to_chat(src, span_interface("All of your adminverbs are now visible."), confidential = TRUE) - BLACKBOX_LOG_ADMIN_VERB("Show Adminverbs") - + control_freak = initial(control_freak) + SSadmin_verbs.deassosciate_admin(src) +ADMIN_VERB(hide_verbs, R_NONE, "Adminverbs - Hide All", "Hide most of your admin verbs.", ADMIN_CATEGORY_MAIN) + user.remove_admin_verbs() + add_verb(user, /client/proc/show_verbs) + to_chat(user, span_interface("Almost all of your adminverbs have been hidden."), confidential = TRUE) + BLACKBOX_LOG_ADMIN_VERB("Hide All Adminverbs") -/client/proc/admin_ghost() - set category = "Admin.Game" - set name = "Aghost" - if(!holder) - return +ADMIN_VERB(admin_ghost, R_ADMIN, "AGhost", "Become a ghost without DNR.", ADMIN_CATEGORY_GAME) . = TRUE - if(isobserver(mob)) + if(isobserver(user.mob)) //re-enter - var/mob/dead/observer/ghost = mob + var/mob/dead/observer/ghost = user.mob if(!ghost.mind || !ghost.mind.current) //won't do anything if there is no body return FALSE if(!ghost.can_reenter_corpse) - log_admin("[key_name(usr)] re-entered corpse") - message_admins("[key_name_admin(usr)] re-entered corpse") + log_admin("[key_name(user)] re-entered corpse") + message_admins("[key_name_admin(user)] re-entered corpse") ghost.can_reenter_corpse = 1 //force re-entering even when otherwise not possible ghost.reenter_corpse() BLACKBOX_LOG_ADMIN_VERB("Admin Reenter") - else if(isnewplayer(mob)) - to_chat(src, "Error: Aghost: Can't admin-ghost whilst in the lobby. Join or Observe first.", confidential = TRUE) + else if(isnewplayer(user.mob)) + to_chat(user, "Error: Aghost: Can't admin-ghost whilst in the lobby. Join or Observe first.", confidential = TRUE) return FALSE else //ghostize - log_admin("[key_name(usr)] admin ghosted.") - message_admins("[key_name_admin(usr)] admin ghosted.") - var/mob/body = mob + log_admin("[key_name(user)] admin ghosted.") + message_admins("[key_name_admin(user)] admin ghosted.") + var/mob/body = user.mob body.ghostize(TRUE) - init_verbs() + user.init_verbs() if(body && !body.key) - body.key = "@[key]" //Haaaaaaaack. But the people have spoken. If it breaks; blame adminbus + body.key = "@[user.key]" //Haaaaaaaack. But the people have spoken. If it breaks; blame adminbus BLACKBOX_LOG_ADMIN_VERB("Admin Ghost") -/client/proc/invisimin() - set name = "Invisimin" - set category = "Admin.Game" - set desc = "Toggles ghost-like invisibility (Don't abuse this)" - - if(isnull(holder) || isnull(mob)) +ADMIN_VERB(invisimin, R_ADMIN, "Inisimin", "Toggles ghost-like invisibility.", ADMIN_CATEGORY_GAME) + if(HAS_TRAIT(user.mob, TRAIT_INVISIMIN)) + REMOVE_TRAIT(user.mob, TRAIT_INVISIMIN, ADMIN_TRAIT) + user.mob.add_to_all_human_data_huds() + user.mob.RemoveInvisibility(INVISIBILITY_SOURCE_INVISIMIN) + to_chat(user, span_adminnotice(span_bold("Invisimin off. Invisibility reset.")), confidential = TRUE) return - if(HAS_TRAIT(mob, TRAIT_INVISIMIN)) - REMOVE_TRAIT(mob, TRAIT_INVISIMIN, ADMIN_TRAIT) - mob.add_to_all_human_data_huds() - mob.RemoveInvisibility(INVISIBILITY_SOURCE_INVISIMIN) - to_chat(mob, span_adminnotice(span_bold("Invisimin off. Invisibility reset.")), confidential = TRUE) - return + ADD_TRAIT(user.mob, TRAIT_INVISIMIN, ADMIN_TRAIT) + user.mob.remove_from_all_data_huds() + user.mob.SetInvisibility(INVISIBILITY_OBSERVER, INVISIBILITY_SOURCE_INVISIMIN, INVISIBILITY_PRIORITY_ADMIN) + to_chat(user, span_adminnotice(span_bold("Invisimin on. You are now as invisible as a ghost.")), confidential = TRUE) - ADD_TRAIT(mob, TRAIT_INVISIMIN, ADMIN_TRAIT) - mob.remove_from_all_data_huds() - mob.SetInvisibility(INVISIBILITY_OBSERVER, INVISIBILITY_SOURCE_INVISIMIN, INVISIBILITY_PRIORITY_ADMIN) - to_chat(mob, span_adminnotice(span_bold("Invisimin on. You are now as invisible as a ghost.")), confidential = TRUE) - -/client/proc/check_antagonists() - set name = "Check Antagonists" - set category = "Admin.Game" - if(holder) - holder.check_antagonists() - log_admin("[key_name(usr)] checked antagonists.") //for tsar~ - if(!isobserver(usr) && SSticker.HasRoundStarted()) - message_admins("[key_name_admin(usr)] checked antagonists.") +ADMIN_VERB(check_antagonists, R_ADMIN, "Check Antagonists", "See all antagonists for the round.", ADMIN_CATEGORY_GAME) + user.holder.check_antagonists() + log_admin("[key_name(user)] checked antagonists.") + if(!isobserver(user.mob) && SSticker.HasRoundStarted()) + message_admins("[key_name_admin(user)] checked antagonists.") BLACKBOX_LOG_ADMIN_VERB("Check Antagonists") -/client/proc/list_bombers() - set name = "List Bombers" - set category = "Admin.Game" - if(!holder) - return - holder.list_bombers() +ADMIN_VERB(list_bombers, R_ADMIN, "List Bombers", "Look at all bombs and their likely culprit.", ADMIN_CATEGORY_GAME) + user.holder.list_bombers() BLACKBOX_LOG_ADMIN_VERB("List Bombers") -/client/proc/list_signalers() - set name = "List Signalers" - set category = "Admin.Game" - if(!holder) - return - holder.list_signalers() +ADMIN_VERB(list_signalers, R_ADMIN, "List Signalers", "View all signalers.", ADMIN_CATEGORY_GAME) + user.holder.list_signalers() BLACKBOX_LOG_ADMIN_VERB("List Signalers") -/client/proc/list_law_changes() - set name = "List Law Changes" - set category = "Debug" - if(!holder) - return - holder.list_law_changes() +ADMIN_VERB(list_law_changes, R_ADMIN, "List Law Changes", "View all AI law changes.", ADMIN_CATEGORY_DEBUG) + user.holder.list_law_changes() BLACKBOX_LOG_ADMIN_VERB("List Law Changes") -/client/proc/show_manifest() - set name = "Show Manifest" - set category = "Debug" - if(!holder) - return - holder.show_manifest() +ADMIN_VERB(show_manifest, R_ADMIN, "Show Manifest", "View the shift's Manifest.", ADMIN_CATEGORY_DEBUG) + user.holder.show_manifest() BLACKBOX_LOG_ADMIN_VERB("Show Manifest") -/client/proc/list_dna() - set name = "List DNA" - set category = "Debug" - if(!holder) - return - holder.list_dna() +ADMIN_VERB(list_dna, R_ADMIN, "List DNA", "View DNA.", ADMIN_CATEGORY_DEBUG) + user.holder.list_dna() BLACKBOX_LOG_ADMIN_VERB("List DNA") -/client/proc/list_fingerprints() - set name = "List Fingerprints" - set category = "Debug" - if(!holder) - return - holder.list_fingerprints() +ADMIN_VERB(list_fingerprints, R_ADMIN, "List Fingerprints", "View fingerprints.", ADMIN_CATEGORY_DEBUG) + user.holder.list_fingerprints() BLACKBOX_LOG_ADMIN_VERB("List Fingerprints") -/client/proc/ban_panel() - set name = "Banning Panel" - set category = "Admin" - if(!check_rights(R_BAN)) - return - holder.ban_panel() +ADMIN_VERB(ban_panel, R_BAN, "Banning Panel", "Ban players here.", ADMIN_CATEGORY_MAIN) + user.holder.ban_panel() BLACKBOX_LOG_ADMIN_VERB("Banning Panel") -/client/proc/unban_panel() - set name = "Unbanning Panel" - set category = "Admin" - if(!check_rights(R_BAN)) - return - holder.unban_panel() +ADMIN_VERB(unban_panel, R_BAN, "Unbanning Panel", "Unban players here.", ADMIN_CATEGORY_MAIN) + user.holder.unban_panel() BLACKBOX_LOG_ADMIN_VERB("Unbanning Panel") -/client/proc/game_panel() - set name = "Game Panel" - set category = "Admin.Game" - if(holder) - holder.Game() +ADMIN_VERB(game_panel, R_ADMIN, "Game Panel", "Look at the state of the game.", ADMIN_CATEGORY_GAME) + user.holder.Game() BLACKBOX_LOG_ADMIN_VERB("Game Panel") -/client/proc/poll_panel() - set name = "Server Poll Management" - set category = "Admin" - if(!check_rights(R_POLL)) - return - holder.poll_list_panel() +ADMIN_VERB(poll_panel, R_POLL, "Server Poll Management", "View and manage polls.", ADMIN_CATEGORY_MAIN) + user.holder.poll_list_panel() BLACKBOX_LOG_ADMIN_VERB("Server Poll Management") /// Returns this client's stealthed ckey @@ -498,16 +133,11 @@ GLOBAL_PROTECT(admin_verbs_poll) /client/proc/createStealthKey() GLOB.stealthminID["[ckey]"] = generateStealthCkey() -/client/proc/stealth() - set category = "Admin" - set name = "Stealth Mode" - if(!holder) - return - - if(holder.fakekey) - disable_stealth_mode() +ADMIN_VERB(stealth, R_STEALTH, "Stealth Mode", "Toggle stealth.", ADMIN_CATEGORY_MAIN) + if(user.holder.fakekey) + user.disable_stealth_mode() else - enable_stealth_mode() + user.enable_stealth_mode() BLACKBOX_LOG_ADMIN_VERB("Stealth Mode") @@ -552,117 +182,86 @@ GLOBAL_PROTECT(admin_verbs_poll) #undef STEALTH_MODE_TRAIT -/client/proc/drop_bomb() - set category = "Admin.Fun" - set name = "Drop Bomb" - set desc = "Cause an explosion of varying strength at your location." - +ADMIN_VERB(drop_bomb, R_FUN, "Drop Bomb", "Cause an explosion of varying strength at your location", ADMIN_CATEGORY_FUN) var/list/choices = list("Small Bomb (1, 2, 3, 3)", "Medium Bomb (2, 3, 4, 4)", "Big Bomb (3, 5, 7, 5)", "Maxcap", "Custom Bomb") - var/choice = tgui_input_list(src, "What size explosion would you like to produce? NOTE: You can do all this rapidly and in an IC manner (using cruise missiles!) with the Config/Launch Supplypod verb. WARNING: These ignore the maxcap", "Drop Bomb", choices) + var/choice = tgui_input_list(user, "What size explosion would you like to produce? NOTE: You can do all this rapidly and in an IC manner (using cruise missiles!) with the Config/Launch Supplypod verb. WARNING: These ignore the maxcap", "Drop Bomb", choices) if(isnull(choice)) return - var/turf/epicenter = mob.loc + var/turf/epicenter = user.mob.loc switch(choice) if("Small Bomb (1, 2, 3, 3)") - explosion(epicenter, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 3, flash_range = 3, adminlog = TRUE, ignorecap = TRUE, explosion_cause = mob) + explosion(epicenter, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 3, flash_range = 3, adminlog = TRUE, ignorecap = TRUE, explosion_cause = user.mob) if("Medium Bomb (2, 3, 4, 4)") - explosion(epicenter, devastation_range = 2, heavy_impact_range = 3, light_impact_range = 4, flash_range = 4, adminlog = TRUE, ignorecap = TRUE, explosion_cause = mob) + explosion(epicenter, devastation_range = 2, heavy_impact_range = 3, light_impact_range = 4, flash_range = 4, adminlog = TRUE, ignorecap = TRUE, explosion_cause = user.mob) if("Big Bomb (3, 5, 7, 5)") - explosion(epicenter, devastation_range = 3, heavy_impact_range = 5, light_impact_range = 7, flash_range = 5, adminlog = TRUE, ignorecap = TRUE, explosion_cause = mob) + explosion(epicenter, devastation_range = 3, heavy_impact_range = 5, light_impact_range = 7, flash_range = 5, adminlog = TRUE, ignorecap = TRUE, explosion_cause = user.mob) if("Maxcap") - explosion(epicenter, devastation_range = GLOB.MAX_EX_DEVESTATION_RANGE, heavy_impact_range = GLOB.MAX_EX_HEAVY_RANGE, light_impact_range = GLOB.MAX_EX_LIGHT_RANGE, flash_range = GLOB.MAX_EX_FLASH_RANGE, adminlog = TRUE, ignorecap = TRUE, explosion_cause = mob) + explosion(epicenter, devastation_range = GLOB.MAX_EX_DEVESTATION_RANGE, heavy_impact_range = GLOB.MAX_EX_HEAVY_RANGE, light_impact_range = GLOB.MAX_EX_LIGHT_RANGE, flash_range = GLOB.MAX_EX_FLASH_RANGE, adminlog = TRUE, ignorecap = TRUE, explosion_cause = user.mob) if("Custom Bomb") - var/range_devastation = input("Devastation range (in tiles):") as null|num + var/range_devastation = input(user, "Devastation range (in tiles):") as null|num if(range_devastation == null) return - var/range_heavy = input("Heavy impact range (in tiles):") as null|num + var/range_heavy = input(user, "Heavy impact range (in tiles):") as null|num if(range_heavy == null) return - var/range_light = input("Light impact range (in tiles):") as null|num + var/range_light = input(user, "Light impact range (in tiles):") as null|num if(range_light == null) return - var/range_flash = input("Flash range (in tiles):") as null|num + var/range_flash = input(user, "Flash range (in tiles):") as null|num if(range_flash == null) return if(range_devastation > GLOB.MAX_EX_DEVESTATION_RANGE || range_heavy > GLOB.MAX_EX_HEAVY_RANGE || range_light > GLOB.MAX_EX_LIGHT_RANGE || range_flash > GLOB.MAX_EX_FLASH_RANGE) - if(tgui_alert(usr, "Bomb is bigger than the maxcap. Continue?",,list("Yes","No")) != "Yes") + if(tgui_alert(user, "Bomb is bigger than the maxcap. Continue?",,list("Yes","No")) != "Yes") return - epicenter = mob.loc //We need to reupdate as they may have moved again - explosion(epicenter, devastation_range = range_devastation, heavy_impact_range = range_heavy, light_impact_range = range_light, flash_range = range_flash, adminlog = TRUE, ignorecap = TRUE, explosion_cause = mob) - message_admins("[ADMIN_LOOKUPFLW(usr)] creating an admin explosion at [epicenter.loc].") - log_admin("[key_name(usr)] created an admin explosion at [epicenter.loc].") + epicenter = get_turf(user.mob) //We need to reupdate as they may have moved again + explosion(epicenter, devastation_range = range_devastation, heavy_impact_range = range_heavy, light_impact_range = range_light, flash_range = range_flash, adminlog = TRUE, ignorecap = TRUE, explosion_cause = user.mob) + message_admins("[ADMIN_LOOKUPFLW(user.mob)] creating an admin explosion at [epicenter.loc].") + log_admin("[key_name(user)] created an admin explosion at [epicenter.loc].") BLACKBOX_LOG_ADMIN_VERB("Drop Bomb") -/client/proc/drop_dynex_bomb() - set category = "Admin.Fun" - set name = "Drop DynEx Bomb" - set desc = "Cause an explosion of varying strength at your location." - - var/ex_power = input("Explosive Power:") as null|num - var/turf/epicenter = mob.loc - if(ex_power && epicenter) - dyn_explosion(epicenter, ex_power) - message_admins("[ADMIN_LOOKUPFLW(usr)] creating an admin explosion at [epicenter.loc].") - log_admin("[key_name(usr)] created an admin explosion at [epicenter.loc].") - BLACKBOX_LOG_ADMIN_VERB("Drop Dynamic Bomb") - -/client/proc/get_dynex_range() - set category = "Debug" - set name = "Get DynEx Range" - set desc = "Get the estimated range of a bomb, using explosive power." - - var/ex_power = input("Explosive Power:") as null|num +ADMIN_VERB(drop_bomb_dynex, R_FUN, "Drop DynEx Bomb", "Cause an explosion of varying strength at your location.", ADMIN_CATEGORY_FUN) + var/ex_power = input(user, "Explosive Power:") as null|num + var/turf/epicenter = get_turf(user.mob) + if(!ex_power || !epicenter) + return + dyn_explosion(epicenter, ex_power) + message_admins("[ADMIN_LOOKUPFLW(user.mob)] creating an admin explosion at [epicenter.loc].") + log_admin("[key_name(user)] created an admin explosion at [epicenter.loc].") + BLACKBOX_LOG_ADMIN_VERB("Drop Dynamic Bomb") + +ADMIN_VERB(get_dynex_range, R_FUN, "Get DynEx Range", "Get the estimated range of a bomb using explosive power.", ADMIN_CATEGORY_DEBUG) + var/ex_power = input(user, "Explosive Power:") as null|num if (isnull(ex_power)) return var/range = round((2 * ex_power)**GLOB.DYN_EX_SCALE) - to_chat(usr, "Estimated Explosive Range: (Devastation: [round(range*0.25)], Heavy: [round(range*0.5)], Light: [round(range)])", confidential = TRUE) - -/client/proc/get_dynex_power() - set category = "Debug" - set name = "Get DynEx Power" - set desc = "Get the estimated required power of a bomb, to reach a specific range." + to_chat(user, "Estimated Explosive Range: (Devastation: [round(range*0.25)], Heavy: [round(range*0.5)], Light: [round(range)])", confidential = TRUE) - var/ex_range = input("Light Explosion Range:") as null|num +ADMIN_VERB(get_dynex_power, R_FUN, "Get DynEx Power", "Get the estimated required power of a bomb to reach the given range.", ADMIN_CATEGORY_DEBUG) + var/ex_range = input(user, "Light Explosion Range:") as null|num if (isnull(ex_range)) return var/power = (0.5 * ex_range)**(1/GLOB.DYN_EX_SCALE) - to_chat(usr, "Estimated Explosive Power: [power]", confidential = TRUE) - -/client/proc/set_dynex_scale() - set category = "Debug" - set name = "Set DynEx Scale" - set desc = "Set the scale multiplier of dynex explosions. The default is 0.5." + to_chat(user, "Estimated Explosive Power: [power]", confidential = TRUE) - var/ex_scale = input("New DynEx Scale:") as null|num +ADMIN_VERB(set_dynex_scale, R_FUN, "Set DynEx Scale", "Set the scale multiplier on dynex explosions. Default 0.5.", ADMIN_CATEGORY_DEBUG) + var/ex_scale = input(user, "New DynEx Scale:") as null|num if(!ex_scale) return GLOB.DYN_EX_SCALE = ex_scale - log_admin("[key_name(usr)] has modified Dynamic Explosion Scale: [ex_scale]") - message_admins("[key_name_admin(usr)] has modified Dynamic Explosion Scale: [ex_scale]") + log_admin("[key_name(user)] has modified Dynamic Explosion Scale: [ex_scale]") + message_admins("[key_name_admin(user)] has modified Dynamic Explosion Scale: [ex_scale]") -/client/proc/atmos_control() - set name = "Atmos Control Panel" - set category = "Debug" - if(!check_rights(R_DEBUG)) - return - SSair.ui_interact(mob) +ADMIN_VERB(atmos_control, R_DEBUG|R_SERVER, "Atmos Control Panel", "Open the atmospherics control panel.", ADMIN_CATEGORY_DEBUG) + SSair.ui_interact(user.mob) -/client/proc/reload_cards() - set name = "Reload Cards" - set category = "Debug" - if(!check_rights(R_DEBUG)) - return +ADMIN_VERB(reload_cards, R_DEBUG, "Reload Cards", "Reload all TCG cards.", ADMIN_CATEGORY_DEBUG) if(!SStrading_card_game.loaded) message_admins("The card subsystem is not currently loaded") return SStrading_card_game.reloadAllCardFiles() -/client/proc/validate_cards() - set name = "Validate Cards" - set category = "Debug" - if(!check_rights(R_DEBUG)) - return +ADMIN_VERB(validate_cards, R_DEBUG, "Validate Cards", "Validate the card settings.", ADMIN_CATEGORY_DEBUG) if(!SStrading_card_game.loaded) message_admins("The card subsystem is not currently loaded") return @@ -673,66 +272,55 @@ GLOBAL_PROTECT(admin_verbs_poll) else message_admins("No errors found in card rarities or overrides.") -/client/proc/test_cardpack_distribution() - set name = "Test Cardpack Distribution" - set category = "Debug" - if(!check_rights(R_DEBUG)) - return +ADMIN_VERB(test_cardpack_distribution, R_DEBUG, "Test Cardpack Distribution", "Test the distribution of a card pack.", ADMIN_CATEGORY_DEBUG) if(!SStrading_card_game.loaded) message_admins("The card subsystem is not currently loaded") return - var/pack = tgui_input_list(usr, "Which pack should we test?", "You fucked it didn't you", sort_list(SStrading_card_game.card_packs)) + var/pack = tgui_input_list(user, "Which pack should we test?", "You fucked it didn't you", sort_list(SStrading_card_game.card_packs)) if(!pack) return - var/batch_count = tgui_input_number(usr, "How many times should we open it?", "Don't worry, I understand") - var/batch_size = tgui_input_number(usr, "How many cards per batch?", "I hope you remember to check the validation") - var/guar = tgui_input_number(usr, "Should we use the pack's guaranteed rarity? If so, how many?", "We've all been there. Man you should have seen the old system") - + var/batch_count = tgui_input_number(user, "How many times should we open it?", "Don't worry, I understand") + var/batch_size = tgui_input_number(user, "How many cards per batch?", "I hope you remember to check the validation") + var/guar = tgui_input_number(user, "Should we use the pack's guaranteed rarity? If so, how many?", "We've all been there. Man you should have seen the old system") SStrading_card_game.check_card_distribution(pack, batch_size, batch_count, guar) -/client/proc/print_cards() - set name = "Print Cards" - set category = "Debug" +ADMIN_VERB(print_cards, R_DEBUG, "Print Cards", "Print all cards to chat.", ADMIN_CATEGORY_DEBUG) SStrading_card_game.printAllCards() -/client/proc/give_mob_action(mob/ability_recipient in GLOB.mob_list) - set category = "Admin.Fun" - set name = "Give Mob Action" - set desc = "Gives a mob ability to a mob." - +ADMIN_VERB(give_mob_action, R_FUN, "Give Mob Action", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/ability_recipient) var/static/list/all_mob_actions = sort_list(subtypesof(/datum/action/cooldown/mob_cooldown), GLOBAL_PROC_REF(cmp_typepaths_asc)) var/static/list/actions_by_name = list() if (!length(actions_by_name)) for (var/datum/action/cooldown/mob_cooldown as anything in all_mob_actions) actions_by_name["[initial(mob_cooldown.name)] ([mob_cooldown])"] = mob_cooldown - var/ability = tgui_input_list(usr, "Choose an ability", "Ability", actions_by_name) + var/ability = tgui_input_list(user, "Choose an ability", "Ability", actions_by_name) if(isnull(ability)) return var/ability_type = actions_by_name[ability] var/datum/action/cooldown/mob_cooldown/add_ability - var/make_sequence = tgui_alert(usr, "Would you like this action to be a sequence of multiple abilities?", "Sequence Ability", list("Yes", "No")) + var/make_sequence = tgui_alert(user, "Would you like this action to be a sequence of multiple abilities?", "Sequence Ability", list("Yes", "No")) if(make_sequence == "Yes") add_ability = new /datum/action/cooldown/mob_cooldown(ability_recipient) add_ability.sequence_actions = list() while(!isnull(ability_type)) - var/ability_delay = tgui_input_number(usr, "Enter the delay in seconds before the next ability in the sequence is used", "Ability Delay", 2) + var/ability_delay = tgui_input_number(user, "Enter the delay in seconds before the next ability in the sequence is used", "Ability Delay", 2) if(isnull(ability_delay) || ability_delay < 0) ability_delay = 0 add_ability.sequence_actions[ability_type] = ability_delay * 1 SECONDS - ability = tgui_input_list(usr, "Choose a new sequence ability", "Sequence Ability", actions_by_name) + ability = tgui_input_list(user, "Choose a new sequence ability", "Sequence Ability", actions_by_name) ability_type = actions_by_name[ability] - var/ability_cooldown = tgui_input_number(usr, "Enter the sequence abilities cooldown in seconds", "Ability Cooldown", 2) + var/ability_cooldown = tgui_input_number(user, "Enter the sequence abilities cooldown in seconds", "Ability Cooldown", 2) if(isnull(ability_cooldown) || ability_cooldown < 0) ability_cooldown = 2 add_ability.cooldown_time = ability_cooldown * 1 SECONDS - var/ability_melee_cooldown = tgui_input_number(usr, "Enter the abilities melee cooldown in seconds", "Melee Cooldown", 2) + var/ability_melee_cooldown = tgui_input_number(user, "Enter the abilities melee cooldown in seconds", "Melee Cooldown", 2) if(isnull(ability_melee_cooldown) || ability_melee_cooldown < 0) ability_melee_cooldown = 2 add_ability.melee_cooldown_time = ability_melee_cooldown * 1 SECONDS - add_ability.name = tgui_input_text(usr, "Choose ability name", "Ability name", "Generic Ability") + add_ability.name = tgui_input_text(user, "Choose ability name", "Ability name", "Generic Ability") add_ability.create_sequence_actions() else add_ability = new ability_type(ability_recipient) @@ -741,15 +329,11 @@ GLOBAL_PROTECT(admin_verbs_poll) return add_ability.Grant(ability_recipient) - message_admins("[key_name_admin(usr)] added mob ability [ability_type] to mob [ability_recipient].") - log_admin("[key_name(usr)] added mob ability [ability_type] to mob [ability_recipient].") + message_admins("[key_name_admin(user)] added mob ability [ability_type] to mob [ability_recipient].") + log_admin("[key_name(user)] added mob ability [ability_type] to mob [ability_recipient].") BLACKBOX_LOG_ADMIN_VERB("Add Mob Ability") -/client/proc/remove_mob_action(mob/removal_target in GLOB.mob_list) - set category = "Admin.Fun" - set name = "Remove Mob Action" - set desc = "Remove a special ability from the selected mob." - +ADMIN_VERB(remove_mob_action, R_FUN, "Remove Mob Action", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/removal_target) var/list/target_abilities = list() for(var/datum/action/cooldown/mob_cooldown/ability in removal_target.actions) target_abilities[ability.name] = ability @@ -757,7 +341,7 @@ GLOBAL_PROTECT(admin_verbs_poll) if(!length(target_abilities)) return - var/chosen_ability = tgui_input_list(usr, "Choose the spell to remove from [removal_target]", "Depower", sort_list(target_abilities)) + var/chosen_ability = tgui_input_list(user, "Choose the spell to remove from [removal_target]", "Depower", sort_list(target_abilities)) if(isnull(chosen_ability)) return var/datum/action/cooldown/mob_cooldown/to_remove = target_abilities[chosen_ability] @@ -765,20 +349,16 @@ GLOBAL_PROTECT(admin_verbs_poll) return qdel(to_remove) - log_admin("[key_name(usr)] removed the ability [chosen_ability] from [key_name(removal_target)].") - message_admins("[key_name_admin(usr)] removed the ability [chosen_ability] from [key_name_admin(removal_target)].") + log_admin("[key_name(user)] removed the ability [chosen_ability] from [key_name(removal_target)].") + message_admins("[key_name_admin(user)] removed the ability [chosen_ability] from [key_name_admin(removal_target)].") BLACKBOX_LOG_ADMIN_VERB("Remove Mob Ability") -/client/proc/give_spell(mob/spell_recipient in GLOB.mob_list) - set category = "Admin.Fun" - set name = "Give Spell" - set desc = "Gives a spell to a mob." - - var/which = tgui_alert(usr, "Chose by name or by type path?", "Chose option", list("Name", "Typepath")) +ADMIN_VERB(give_spell, R_FUN, "Give Spell", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/spell_recipient) + var/which = tgui_alert(user, "Chose by name or by type path?", "Chose option", list("Name", "Typepath")) if(!which) return if(QDELETED(spell_recipient)) - to_chat(usr, span_warning("The intended spell recipient no longer exists.")) + to_chat(user, span_warning("The intended spell recipient no longer exists.")) return var/list/spell_list = list() @@ -792,22 +372,22 @@ GLOBAL_PROTECT(admin_verbs_poll) else spell_list += to_add - var/chosen_spell = tgui_input_list(usr, "Choose the spell to give to [spell_recipient]", "ABRAKADABRA", sort_list(spell_list)) + var/chosen_spell = tgui_input_list(user, "Choose the spell to give to [spell_recipient]", "ABRAKADABRA", sort_list(spell_list)) if(isnull(chosen_spell)) return var/datum/action/cooldown/spell/spell_path = which == "Typepath" ? chosen_spell : spell_list[chosen_spell] if(!ispath(spell_path)) return - var/robeless = (tgui_alert(usr, "Would you like to force this spell to be robeless?", "Robeless Casting?", list("Force Robeless", "Use Spell Setting")) == "Force Robeless") + var/robeless = (tgui_alert(user, "Would you like to force this spell to be robeless?", "Robeless Casting?", list("Force Robeless", "Use Spell Setting")) == "Force Robeless") if(QDELETED(spell_recipient)) - to_chat(usr, span_warning("The intended spell recipient no longer exists.")) + to_chat(user, span_warning("The intended spell recipient no longer exists.")) return BLACKBOX_LOG_ADMIN_VERB("Give Spell") - log_admin("[key_name(usr)] gave [key_name(spell_recipient)] the spell [chosen_spell][robeless ? " (Forced robeless)" : ""].") - message_admins("[key_name_admin(usr)] gave [key_name_admin(spell_recipient)] the spell [chosen_spell][robeless ? " (Forced robeless)" : ""].") + log_admin("[key_name(user)] gave [key_name(spell_recipient)] the spell [chosen_spell][robeless ? " (Forced robeless)" : ""].") + message_admins("[key_name_admin(user)] gave [key_name_admin(spell_recipient)] the spell [chosen_spell][robeless ? " (Forced robeless)" : ""].") var/datum/action/cooldown/spell/new_spell = new spell_path(spell_recipient.mind || spell_recipient) @@ -817,14 +397,10 @@ GLOBAL_PROTECT(admin_verbs_poll) new_spell.Grant(spell_recipient) if(!spell_recipient.mind) - to_chat(usr, span_userdanger("Spells given to mindless mobs will belong to the mob and not their mind, \ + to_chat(user, span_userdanger("Spells given to mindless mobs will belong to the mob and not their mind, \ and as such will not be transferred if their mind changes body (Such as from Mindswap).")) -/client/proc/remove_spell(mob/removal_target in GLOB.mob_list) - set category = "Admin.Fun" - set name = "Remove Spell" - set desc = "Remove a spell from the selected mob." - +ADMIN_VERB(remove_spell, R_FUN, "Remove Spell", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/removal_target) var/list/target_spell_list = list() for(var/datum/action/cooldown/spell/spell in removal_target.actions) target_spell_list[spell.name] = spell @@ -832,7 +408,7 @@ GLOBAL_PROTECT(admin_verbs_poll) if(!length(target_spell_list)) return - var/chosen_spell = tgui_input_list(usr, "Choose the spell to remove from [removal_target]", "ABRAKADABRA", sort_list(target_spell_list)) + var/chosen_spell = tgui_input_list(user, "Choose the spell to remove from [removal_target]", "ABRAKADABRA", sort_list(target_spell_list)) if(isnull(chosen_spell)) return var/datum/action/cooldown/spell/to_remove = target_spell_list[chosen_spell] @@ -840,58 +416,39 @@ GLOBAL_PROTECT(admin_verbs_poll) return qdel(to_remove) - log_admin("[key_name(usr)] removed the spell [chosen_spell] from [key_name(removal_target)].") - message_admins("[key_name_admin(usr)] removed the spell [chosen_spell] from [key_name_admin(removal_target)].") + log_admin("[key_name(user)] removed the spell [chosen_spell] from [key_name(removal_target)].") + message_admins("[key_name_admin(user)] removed the spell [chosen_spell] from [key_name_admin(removal_target)].") BLACKBOX_LOG_ADMIN_VERB("Remove Spell") -/client/proc/give_disease(mob/living/T in GLOB.mob_living_list) - set category = "Admin.Fun" - set name = "Give Disease" - set desc = "Gives a Disease to a mob." - if(!istype(T)) - to_chat(src, span_notice("You can only give a disease to a mob of type /mob/living."), confidential = TRUE) - return - var/datum/disease/D = input("Choose the disease to give to that guy", "ACHOO") as null|anything in sort_list(SSdisease.diseases, GLOBAL_PROC_REF(cmp_typepaths_asc)) +ADMIN_VERB(give_disease, R_FUN, "Give Disease", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/living/victim) + var/datum/disease/D = input(user, "Choose the disease to give to that guy", "ACHOO") as null|anything in sort_list(SSdisease.diseases, GLOBAL_PROC_REF(cmp_typepaths_asc)) if(!D) return - T.ForceContractDisease(new D, FALSE, TRUE) + victim.ForceContractDisease(new D, FALSE, TRUE) BLACKBOX_LOG_ADMIN_VERB("Give Disease") - log_admin("[key_name(usr)] gave [key_name(T)] the disease [D].") - message_admins(span_adminnotice("[key_name_admin(usr)] gave [key_name_admin(T)] the disease [D].")) - -/client/proc/object_say(obj/O in world) - set category = "Admin.Events" - set name = "OSay" - set desc = "Makes an object say something." - var/message = tgui_input_text(usr, "What do you want the message to be?", "Make Sound", encode = FALSE) + log_admin("[key_name(user)] gave [key_name(victim)] the disease [D].") + message_admins(span_adminnotice("[key_name_admin(user)] gave [key_name_admin(victim)] the disease [D].")) + +ADMIN_VERB_AND_CONTEXT_MENU(object_say, R_FUN, "OSay", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, obj/speaker in world) + var/message = tgui_input_text(user, "What do you want the message to be?", "Make Sound", encode = FALSE) if(!message) return - O.say(message, sanitize = FALSE) - log_admin("[key_name(usr)] made [O] at [AREACOORD(O)] say \"[message]\"") - message_admins(span_adminnotice("[key_name_admin(usr)] made [O] at [AREACOORD(O)]. say \"[message]\"")) + speaker.say(message, sanitize = FALSE) + log_admin("[key_name(user)] made [speaker] at [AREACOORD(speaker)] say \"[message]\"") + message_admins(span_adminnotice("[key_name_admin(user)] made [speaker] at [AREACOORD(speaker)]. say \"[message]\"")) BLACKBOX_LOG_ADMIN_VERB("Object Say") -/client/proc/togglebuildmodeself() - set name = "Toggle Build Mode Self" - set category = "Admin.Events" - if (!(holder.rank_flags() & R_BUILD)) - return - if(src.mob) - togglebuildmode(src.mob) - BLACKBOX_LOG_ADMIN_VERB("Toggle Build Mode") -/client/proc/check_ai_laws() - set name = "Check AI Laws" - set category = "Admin.Game" - if(holder) - src.holder.output_ai_laws() +ADMIN_VERB(build_mode_self, R_BUILD, "Toggle Build Mode Self", "Toggle build mode for yourself.", ADMIN_CATEGORY_EVENTS) + togglebuildmode(user.mob) // why is this a global proc??? + BLACKBOX_LOG_ADMIN_VERB("Toggle Build Mode") -/client/proc/manage_sect() - set name = "Manage Religious Sect" - set category = "Admin.Game" +ADMIN_VERB(check_ai_laws, R_ADMIN, "Check AI Laws", "View the current AI laws.", ADMIN_CATEGORY_GAME) + user.holder.output_ai_laws() +ADMIN_VERB(manage_sect, R_ADMIN, "Manage Religious Sect", "Manages the chaplain's religion.", ADMIN_CATEGORY_GAME) if (!isnull(GLOB.religious_sect)) var/you_sure = tgui_alert( - usr, + user, "The Chaplain has already chosen [GLOB.religious_sect.name], override their selection?", "Replace God?", list("Yes", "Cancel"), @@ -904,7 +461,7 @@ GLOBAL_PROTECT(admin_verbs_poll) choices["nothing"] = null for(var/datum/religion_sect/sect as anything in subtypesof(/datum/religion_sect)) choices[initial(sect.name)] = sect - var/choice = tgui_input_list(usr, "Set new Chaplain sect", "God Picker", choices) + var/choice = tgui_input_list(user, "Set new Chaplain sect", "God Picker", choices) if(isnull(choice)) return if(choice == "nothing") @@ -912,122 +469,51 @@ GLOBAL_PROTECT(admin_verbs_poll) return set_new_religious_sect(choices[choice], reset_existing = TRUE) -/client/proc/deadmin() - set name = "Deadmin" - set category = "Admin" - set desc = "Shed your admin powers." - - if(!holder) - return - - holder.deactivate() - - to_chat(src, span_interface("You are now a normal player.")) - log_admin("[src] deadminned themselves.") - message_admins("[src] deadminned themselves.") +ADMIN_VERB(deadmin, R_NONE, "DeAdmin", "Shed your admin powers.", ADMIN_CATEGORY_MAIN) + user.holder.deactivate() + to_chat(user, span_interface("You are now a normal player.")) + log_admin("[key_name(user)] deadminned themselves.") + message_admins("[key_name_admin(user)] deadminned themselves.") BLACKBOX_LOG_ADMIN_VERB("Deadmin") -/client/proc/readmin() - set name = "Readmin" - set category = "Admin" - set desc = "Regain your admin powers." - - var/datum/admins/A = GLOB.deadmins[ckey] - - if(!A) - A = GLOB.admin_datums[ckey] - if (!A) - var/msg = " is trying to readmin but they have no deadmin entry" - message_admins("[key_name_admin(src)][msg]") - log_admin_private("[key_name(src)][msg]") - return - - A.associate(src) - - if (!holder) - return //This can happen if an admin attempts to vv themself into somebody elses's deadmin datum by getting ref via brute force - - to_chat(src, span_interface("You are now an admin."), confidential = TRUE) - message_admins("[src] re-adminned themselves.") - log_admin("[src] re-adminned themselves.") - BLACKBOX_LOG_ADMIN_VERB("Readmin") - -/client/proc/populate_world(amount = 50) - set name = "Populate World" - set category = "Debug" - set desc = "(\"Amount of mobs to create\") Populate the world with test mobs." - +ADMIN_VERB(populate_world, R_DEBUG, "Populate World", "Populate the world with test mobs.", ADMIN_CATEGORY_DEBUG, amount = 50 as num) for (var/i in 1 to amount) var/turf/tile = get_safe_random_station_turf() var/mob/living/carbon/human/hooman = new(tile) hooman.equipOutfit(pick(subtypesof(/datum/outfit))) testing("Spawned test mob at [get_area_name(tile, TRUE)] ([tile.x],[tile.y],[tile.z])") -/client/proc/toggle_AI_interact() - set name = "Toggle Admin AI Interact" - set category = "Admin.Game" - set desc = "Allows you to interact with most machines as an AI would as a ghost" - - AI_Interact = !AI_Interact - if(mob && isAdminGhostAI(mob)) - mob.has_unlimited_silicon_privilege = AI_Interact - - log_admin("[key_name(usr)] has [AI_Interact ? "activated" : "deactivated"] Admin AI Interact") - message_admins("[key_name_admin(usr)] has [AI_Interact ? "activated" : "deactivated"] their AI interaction") - -/client/proc/debugstatpanel() - set name = "Debug Stat Panel" - set category = "Debug" - - src.stat_panel.send_message("create_debug") - -/client/proc/admin_2fa_verify() - set name = "Verify Admin" - set category = "Admin" - - var/datum/admins/admin = GLOB.admin_datums[ckey] - admin?.associate(src) - -/client/proc/display_sendmaps() - set name = "Send Maps Profile" - set category = "Debug" +ADMIN_VERB(toggle_ai_interact, R_ADMIN, "Toggle Admin AI Interact", "Allows you to interact with most machines as an AI would as a ghost.", ADMIN_CATEGORY_GAME) + user.AI_Interact = !user.AI_Interact + if(user.mob && isAdminGhostAI(user.mob)) + user.mob.has_unlimited_silicon_privilege = user.AI_Interact - src << link("?debug=profile&type=sendmaps&window=test") + log_admin("[key_name(user)] has [user.AI_Interact ? "activated" : "deactivated"] Admin AI Interact") + message_admins("[key_name_admin(user)] has [user.AI_Interact ? "activated" : "deactivated"] their AI interaction") -/** - * Debug verb that spawns human crewmembers - * of each job type, gives them a mind and assigns the role, - * and injects them into the manifest, as if they were a "player". - * - * This spawns humans with minds and jobs, but does NOT make them 'players'. - * They're all clientles mobs with minds / jobs. - */ -/client/proc/spawn_debug_full_crew() - set name = "Spawn Debug Full Crew" - set desc = "Creates a full crew for the station, filling the datacore and assigning them all minds / jobs. Don't do this on live" - set category = "Debug" +ADMIN_VERB(debug_statpanel, R_DEBUG, "Debug Stat Panel", "Toggles local debug of the stat panel", ADMIN_CATEGORY_DEBUG) + user.stat_panel.send_message("create_debug") - if(!check_rights(R_DEBUG)) - return - - var/mob/admin = usr +ADMIN_VERB(display_sendmaps, R_DEBUG, "Send Maps Profile", "View the profile.", ADMIN_CATEGORY_DEBUG) + user << link("?debug=profile&type=sendmaps&window=test") +ADMIN_VERB(spawn_debug_full_crew, R_DEBUG, "Spawn Debug Full Crew", "Creates a full crew for the station, flling datacore and assigning minds and jobs.", ADMIN_CATEGORY_DEBUG) if(SSticker.current_state != GAME_STATE_PLAYING) - to_chat(admin, "You should only be using this after a round has setup and started.") + to_chat(user, "You should only be using this after a round has setup and started.") return // Two input checks here to make sure people are certain when they're using this. - if(tgui_alert(admin, "This command will create a bunch of dummy crewmembers with minds, job, and datacore entries, which will take a while and fill the manifest.", "Spawn Crew", list("Yes", "Cancel")) != "Yes") + if(tgui_alert(user, "This command will create a bunch of dummy crewmembers with minds, job, and datacore entries, which will take a while and fill the manifest.", "Spawn Crew", list("Yes", "Cancel")) != "Yes") return - if(tgui_alert(admin, "I sure hope you aren't doing this on live. Are you sure?", "Spawn Crew (Be certain)", list("Yes", "Cancel")) != "Yes") + if(tgui_alert(user, "I sure hope you aren't doing this on live. Are you sure?", "Spawn Crew (Be certain)", list("Yes", "Cancel")) != "Yes") return // Find the observer spawn, so we have a place to dump the dummies. var/obj/effect/landmark/observer_start/observer_point = locate(/obj/effect/landmark/observer_start) in GLOB.landmarks_list var/turf/destination = get_turf(observer_point) if(!destination) - to_chat(admin, "Failed to find the observer spawn to send the dummies.") + to_chat(user, "Failed to find the observer spawn to send the dummies.") return // Okay, now go through all nameable occupations. @@ -1049,7 +535,7 @@ GLOBAL_PROTECT(admin_verbs_poll) // Assign the rank to the new player dummy. if(!SSjob.AssignRole(new_guy, job, do_eligibility_checks = FALSE)) qdel(new_guy) - to_chat(admin, "[rank] wasn't able to be spawned.") + to_chat(user, "[rank] wasn't able to be spawned.") continue // It's got a job, spawn in a human and shove it in the human. @@ -1070,13 +556,9 @@ GLOBAL_PROTECT(admin_verbs_poll) number_made++ CHECK_TICK - to_chat(admin, "[number_made] crewmembers have been created.") - -/// Debug verb for seeing at a glance what all spells have as set requirements -/client/proc/debug_spell_requirements() - set name = "Show Spell Requirements" - set category = "Debug" + to_chat(user, "[number_made] crewmembers have been created.") +ADMIN_VERB(debug_spell_requirements, R_DEBUG, "Debug Spell Requirements", "View all spells and their requirements.", ADMIN_CATEGORY_DEBUG) var/header = "Name Requirements" var/all_requirements = list() for(var/datum/action/cooldown/spell/spell as anything in typesof(/datum/action/cooldown/spell)) @@ -1104,69 +586,52 @@ GLOBAL_PROTECT(admin_verbs_poll) var/page_style = "" var/page_contents = "[page_style][header][jointext(all_requirements, "")]
" - var/datum/browser/popup = new(mob, "spellreqs", "Spell Requirements", 600, 400) + var/datum/browser/popup = new(user.mob, "spellreqs", "Spell Requirements", 600, 400) popup.set_content(page_contents) popup.open() -/client/proc/force_load_lazy_template() - set name = "Load/Jump Lazy Template" - set category = "Admin.Events" - if(!check_rights(R_ADMIN)) - return - +ADMIN_VERB(load_lazy_template, R_ADMIN, "Load/Jump Lazy Template", "Loads a lazy template and/or jumps to it.", ADMIN_CATEGORY_EVENTS) var/list/choices = LAZY_TEMPLATE_KEY_LIST_ALL() - var/choice = tgui_input_list(usr, "Key?", "Lazy Loader", choices) + var/choice = tgui_input_list(user, "Key?", "Lazy Loader", choices) if(!choice) return choice = choices[choice] if(!choice) - to_chat(usr, span_warning("No template with that key found, report this!")) + to_chat(user, span_warning("No template with that key found, report this!")) return var/already_loaded = LAZYACCESS(SSmapping.loaded_lazy_templates, choice) var/force_load = FALSE - if(already_loaded && (tgui_alert(usr, "Template already loaded.", "", list("Jump", "Load Again")) == "Load Again")) + if(already_loaded && (tgui_alert(user, "Template already loaded.", "", list("Jump", "Load Again")) == "Load Again")) force_load = TRUE var/datum/turf_reservation/reservation = SSmapping.lazy_load_template(choice, force = force_load) if(!reservation) - to_chat(usr, span_boldwarning("Failed to load template!")) + to_chat(user, span_boldwarning("Failed to load template!")) return - if(!isobserver(usr)) - admin_ghost() - usr.forceMove(reservation.bottom_left_turfs[1]) + if(!isobserver(user.mob)) + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/admin_ghost) + user.mob.forceMove(reservation.bottom_left_turfs[1]) - message_admins("[key_name_admin(usr)] has loaded lazy template '[choice]'") - to_chat(usr, span_boldnicegreen("Template loaded, you have been moved to the bottom left of the reservation.")) + message_admins("[key_name_admin(user)] has loaded lazy template '[choice]'") + to_chat(user, span_boldnicegreen("Template loaded, you have been moved to the bottom left of the reservation.")) -/client/proc/library_control() - set name = "Library Management" - set category = "Admin" - if(!check_rights(R_BAN)) - return - - if(!holder.library_manager) - holder.library_manager = new() - holder.library_manager.ui_interact(usr) +ADMIN_VERB(library_control, R_BAN, "Library Management", "List and manage the Library.", ADMIN_CATEGORY_MAIN) + if(!user.holder.library_manager) + user.holder.library_manager = new + user.holder.library_manager.ui_interact(user.mob) BLACKBOX_LOG_ADMIN_VERB("Library Management") -/client/proc/create_mob_worm() - set category = "Admin.Fun" - set name = "Create Mob Worm" - set desc = "Attached a linked list of mobs to a marked mob" - if (!check_rights(R_FUN)) - return - if(isnull(holder)) - return - if(!isliving(holder.marked_datum)) - to_chat(usr, span_warning("Error: Please mark a mob to attach mobs to.")) +ADMIN_VERB(create_mob_worm, R_FUN, "Create Mob Worm", "Attach a linked list of mobs to your marked mob.", ADMIN_CATEGORY_FUN) + if(!isliving(user.holder.marked_datum)) + to_chat(user, span_warning("Error: Please mark a mob to attach mobs to.")) return - var/mob/living/head = holder.marked_datum + var/mob/living/head = user.holder.marked_datum var/attempted_target_path = tgui_input_text( - usr, + user, "Enter typepath of a mob you'd like to make your chain from.", "Typepath", "[/mob/living/basic/pet/dog/corgi/ian]", @@ -1181,7 +646,7 @@ GLOBAL_PROTECT(admin_verbs_poll) if(isnull(desired_mob) || !ispath(desired_mob) || QDELETED(head)) return //The user pressed "Cancel" - var/amount = tgui_input_number(usr, "How long should our tail be?", "Worm Configurator", default = 3, min_value = 1) + var/amount = tgui_input_number(user, "How long should our tail be?", "Worm Configurator", default = 3, min_value = 1) if (isnull(amount) || amount < 1 || QDELETED(head)) return head.AddComponent(/datum/component/mob_chain) diff --git a/code/modules/admin/callproc/callproc.dm b/code/modules/admin/callproc/callproc.dm index 1680304679edf..823a4a9e64bf0 100644 --- a/code/modules/admin/callproc/callproc.dm +++ b/code/modules/admin/callproc/callproc.dm @@ -92,11 +92,8 @@ GLOBAL_PROTECT(AdminProcCallHandler) usr = lastusr handler.remove_caller(user) -/client/proc/callproc() - set category = "Debug" - set name = "Advanced ProcCall" - set waitfor = FALSE - callproc_blocking() +ADMIN_VERB(advanced_proc_call, R_DEBUG, "Advanced ProcCall", "Call a proc on any datum in the server.", ADMIN_CATEGORY_DEBUG) + user.callproc_blocking() /client/proc/callproc_blocking(list/get_retval) if(!check_rights(R_DEBUG)) @@ -230,37 +227,30 @@ GLOBAL_PROTECT(LastAdminCalledProc) return (GLOB.AdminProcCaller && GLOB.AdminProcCaller == usr?.client?.ckey) || (GLOB.AdminProcCallHandler && usr == GLOB.AdminProcCallHandler) #endif -/client/proc/callproc_datum(datum/A as null|area|mob|obj|turf) - set category = "Debug" - set name = "Atom ProcCall" - set waitfor = FALSE - - if(!check_rights(R_DEBUG)) - return - - var/procname = input("Proc name, eg: fake_blood","Proc:", null) as text|null +ADMIN_VERB_ONLY_CONTEXT_MENU(call_proc_datum, R_DEBUG, "Atom ProcCall", datum/thing as null|area|mob|obj|turf) + var/procname = input(user, "Proc name, eg: fake_blood","Proc:", null) as text|null if(!procname) return - if(!hascall(A,procname)) - to_chat(usr, "Error: callproc_datum(): type [A.type] has no proc named [procname].", confidential = TRUE) + if(!hascall(thing, procname)) + to_chat(user, "Error: callproc_datum(): type [thing.type] has no proc named [procname].", confidential = TRUE) return - var/list/lst = get_callproc_args() + var/list/lst = user.get_callproc_args() if(!lst) return - if(!A || !is_valid_src(A)) - to_chat(usr, span_warning("Error: callproc_datum(): owner of proc no longer exists."), confidential = TRUE) + if(!thing || !is_valid_src(thing)) + to_chat(user, span_warning("Error: callproc_datum(): owner of proc no longer exists."), confidential = TRUE) return - log_admin("[key_name(src)] called [A]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].") - var/msg = "[key_name(src)] called [A]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]." + log_admin("[key_name(user)] called [thing]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].") + var/msg = "[key_name(user)] called [thing]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]." message_admins(msg) - admin_ticket_log(A, msg) + admin_ticket_log(thing, msg) BLACKBOX_LOG_ADMIN_VERB("Atom ProcCall") - var/returnval = WrapAdminProcCall(A, procname, lst) // Pass the lst as an argument list to the proc - . = get_callproc_returnval(returnval,procname) + var/returnval = WrapAdminProcCall(thing, procname, lst) // Pass the lst as an argument list to the proc + . = user.get_callproc_returnval(returnval,procname) if(.) - to_chat(usr, ., confidential = TRUE) + to_chat(user, ., confidential = TRUE) /client/proc/get_callproc_args() var/argnum = input("Number of arguments","Number:",0) as num|null diff --git a/code/modules/admin/force_event.dm b/code/modules/admin/force_event.dm index 20066547de9c6..519adbd8a9e5c 100644 --- a/code/modules/admin/force_event.dm +++ b/code/modules/admin/force_event.dm @@ -1,12 +1,6 @@ -///Allows an admin to force an event -/client/proc/forceEvent() - set name = "Trigger Event" - set category = "Admin.Events" - if(!holder || !check_rights(R_FUN)) - return - - holder.forceEvent() +ADMIN_VERB(force_event, R_FUN, "Trigger Event", "Forces an event to occur.", ADMIN_CATEGORY_EVENTS) + user.holder.forceEvent() ///Opens up the Force Event Panel /datum/admins/proc/forceEvent() diff --git a/code/modules/admin/known_alts.dm b/code/modules/admin/known_alts.dm index d6486f77bd730..4105c7f4edc93 100644 --- a/code/modules/admin/known_alts.dm +++ b/code/modules/admin/known_alts.dm @@ -187,8 +187,5 @@ GLOBAL_DATUM_INIT(known_alts, /datum/known_alts, new) client << browse(html, "window=known_alts;size=700x400") -/datum/admins/proc/known_alts_panel() - set name = "Known Alts Panel" - set category = "Admin" - - GLOB.known_alts.show_panel(usr.client) +ADMIN_VERB(known_alts_panel, R_ADMIN, "Known Alts Panel", "View a panel of known alts.", ADMIN_CATEGORY_MAIN) + GLOB.known_alts.show_panel(user) diff --git a/code/modules/admin/outfit_manager.dm b/code/modules/admin/outfit_manager.dm index fcb41b3f2f1a5..f3ef7d2685c22 100644 --- a/code/modules/admin/outfit_manager.dm +++ b/code/modules/admin/outfit_manager.dm @@ -1,18 +1,8 @@ -/client/proc/outfit_manager() - set category = "Debug" - set name = "Outfit Manager" - - if(!check_rights(R_DEBUG)) - return - var/datum/outfit_manager/ui = new(usr) - ui.ui_interact(usr) - +ADMIN_VERB(outfit_manager, R_DEBUG|R_ADMIN, "Outfit Manager", "View and edit outfits.", ADMIN_CATEGORY_DEBUG) + var/static/datum/outfit_manager/ui = new + ui.ui_interact(user.mob) /datum/outfit_manager - var/client/owner - -/datum/outfit_manager/New(user) - owner = CLIENT_FROM_VAR(user) /datum/outfit_manager/ui_state(mob/user) return GLOB.admin_state @@ -53,24 +43,24 @@ switch(action) if("new") - owner.open_outfit_editor(new /datum/outfit) + ui.user.client.open_outfit_editor(new /datum/outfit) if("load") - owner.holder.load_outfit(owner.mob) + ui.user.client.holder.load_outfit(ui.user) if("copy") - var/datum/outfit/outfit = tgui_input_list(owner, "Pick an outfit to copy from", "Outfit Manager", subtypesof(/datum/outfit)) + var/datum/outfit/outfit = tgui_input_list(ui.user, "Pick an outfit to copy from", "Outfit Manager", subtypesof(/datum/outfit)) if(isnull(outfit)) return if(!ispath(outfit)) return - owner.open_outfit_editor(new outfit) + ui.user.client.open_outfit_editor(new outfit) var/datum/outfit/target_outfit = locate(params["outfit"]) if(!istype(target_outfit)) return switch(action) //wow we're switching through action again this is horrible optimization smh if("edit") - owner.open_outfit_editor(target_outfit) + ui.user.client.open_outfit_editor(target_outfit) if("save") - owner.holder.save_outfit(owner.mob, target_outfit) + ui.user.client.holder.save_outfit(ui.user, target_outfit) if("delete") - owner.holder.delete_outfit(owner.mob, target_outfit) + ui.user.client.holder.delete_outfit(ui.user, target_outfit) diff --git a/code/modules/admin/painting_manager.dm b/code/modules/admin/painting_manager.dm index bd7d28fb73fba..7a8bd7127a4d3 100644 --- a/code/modules/admin/painting_manager.dm +++ b/code/modules/admin/painting_manager.dm @@ -1,11 +1,6 @@ -/datum/admins/proc/paintings_manager() - set name = "Paintings Manager" - set category = "Admin" - - if(!check_rights(R_ADMIN)) - return - var/datum/paintings_manager/ui = new(usr) - ui.ui_interact(usr) +ADMIN_VERB(painting_manager, R_ADMIN, "Paintings Manager", "View and redact paintings.", ADMIN_CATEGORY_MAIN) + var/static/datum/paintings_manager/ui = new + ui.ui_interact(user.mob) /// Painting Admin Management Panel /datum/paintings_manager diff --git a/code/modules/admin/permissionedit.dm b/code/modules/admin/permissionedit.dm index cf816fef8a7a1..e92ab1729e2ab 100644 --- a/code/modules/admin/permissionedit.dm +++ b/code/modules/admin/permissionedit.dm @@ -1,10 +1,6 @@ -/client/proc/edit_admin_permissions() - set category = "Admin" - set name = "Permissions Panel" - set desc = "Edit admin permissions" - if(!check_rights(R_PERMISSIONS)) - return - usr.client.holder.edit_admin_permissions() + +ADMIN_VERB(edit_admin_permissions, R_PERMISSIONS, "Permissions Panel", "Edit admin permissions.", ADMIN_CATEGORY_MAIN) + user.holder.edit_admin_permissions() /datum/admins/proc/edit_admin_permissions(action, target, operation, page) if(!check_rights(R_PERMISSIONS)) diff --git a/code/modules/admin/stickyban.dm b/code/modules/admin/stickyban.dm index 537e0b92acbdd..fede9724ab181 100644 --- a/code/modules/admin/stickyban.dm +++ b/code/modules/admin/stickyban.dm @@ -481,10 +481,5 @@ . = list2params(.) - -/client/proc/stickybanpanel() - set name = "Sticky Ban Panel" - set category = "Admin" - if (!holder) - return - holder.stickyban_show() +ADMIN_VERB(panel_sticky_ban, R_BAN, "Sticky Ban Panel", "List and manage sticky bans.", ADMIN_CATEGORY_MAIN) + user.holder.stickyban_show() diff --git a/code/modules/admin/tag.dm b/code/modules/admin/tag.dm index 64c6c16fc406d..e52112eba1495 100644 --- a/code/modules/admin/tag.dm +++ b/code/modules/admin/tag.dm @@ -49,21 +49,14 @@ [X.getToxLoss()] \ [X.getOxyLoss()]" -/// Display all of the tagged datums -/datum/admins/proc/display_tags() - set category = "Admin.Game" - set name = "View Tags" - - if (!istype(src, /datum/admins)) - src = usr.client.holder - if (!istype(src, /datum/admins)) - to_chat(usr, "Error: you are not an admin!", confidential = TRUE) - return - +ADMIN_VERB(display_tags, R_ADMIN, "View Tags", "Display all of the tagged datums.", ADMIN_CATEGORY_GAME) var/index = 0 var/list/dat = list("
Tag Menu

") - dat += "
Refresh
" + var/list/tagged_datums = user.holder.tagged_datums + var/list/marked_datum = user.holder.marked_datum + + dat += "
Refresh
" if(LAZYLEN(tagged_datums)) for(var/datum/iter_datum as anything in tagged_datums) index++ @@ -71,7 +64,7 @@ if(isnull(iter_datum)) dat += "\t[index]: Null reference - Check runtime logs!" - stack_trace("Null datum found in tagged datum menu! User: [usr]") + stack_trace("Null datum found in tagged datum menu! User: [user]") continue else if(iscarbon(iter_datum)) var/mob/living/carbon/resolved_carbon = iter_datum @@ -99,7 +92,7 @@ dat += "No datums tagged :(" dat = dat.Join("
") - usr << browse(dat, "window=tag;size=800x480") + user << browse(dat, "window=tag;size=800x480") #undef TAG_DEL #undef TAG_MARK diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 5506bfa2b0d79..2ba75020d48d1 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -136,8 +136,7 @@ to_chat(usr, "[shuttle_console] was [shuttle_console.admin_controlled ? "locked" : "unlocked"].", confidential = TRUE) else if(href_list["delay_round_end"]) - // Permissions are checked in delay_round_end - delay_round_end() + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/delay_round_end) else if(href_list["undelay_round_end"]) if(!check_rights(R_SERVER)) @@ -725,21 +724,10 @@ our_mob.AIize(our_mob.client, move) else if(href_list["makerobot"]) - if(!check_rights(R_SPAWN)) - return - - var/mob/our_mob = locate(href_list["makerobot"]) - if(!istype(our_mob)) - return - if(iscyborg(our_mob)) - to_chat(usr, "That's already a cyborg.", confidential = TRUE) - return - - usr.client.cmd_admin_robotize(our_mob) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/cmd_admin_robotize, locate(href_list["makerobot"])) else if(href_list["adminplayeropts"]) - var/mob/M = locate(href_list["adminplayeropts"]) - show_player_panel(M) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/show_player_panel, locate(href_list["adminplayeropts"])) else if(href_list["ppbyckey"]) var/target_ckey = href_list["ppbyckey"] @@ -754,7 +742,7 @@ return to_chat(usr, span_notice("Jumping to [target_ckey]'s new mob: [target_mob]!")) - show_player_panel(target_mob) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/show_player_panel, target_mob) else if(href_list["adminplayerobservefollow"]) if(!isobserver(usr) && !check_rights(R_ADMIN)) @@ -771,20 +759,13 @@ AM.forceMove(get_turf(usr)) else if(href_list["adminplayerobservecoodjump"]) - if(!isobserver(usr) && !check_rights(R_ADMIN)) - return - if(isnewplayer(usr)) - return - - var/x = text2num(href_list["X"]) - var/y = text2num(href_list["Y"]) - var/z = text2num(href_list["Z"]) - - var/client/C = usr.client - if(!isobserver(usr)) - C.admin_ghost() - sleep(0.2 SECONDS) - C.jumptocoord(x,y,z) + return SSadmin_verbs.dynamic_invoke_verb( + usr, + /datum/admin_verb/jump_to_coord, + text2num(href_list["X"]), + text2num(href_list["Y"]), + text2num(href_list["Z"]), + ) else if(href_list["adminchecklaws"]) if(!check_rights(R_ADMIN)) @@ -984,15 +965,7 @@ give_admin_popup(target, owner, message) else if(href_list["adminsmite"]) - if(!check_rights(R_ADMIN|R_FUN)) - return - - var/mob/living/carbon/human/H = locate(href_list["adminsmite"]) in GLOB.mob_list - if(!H || !istype(H)) - to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human", confidential = TRUE) - return - - usr.client.smite(H) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/admin_smite, locate(href_list["adminsmite"])) else if(href_list["CentComReply"]) if(!check_rights(R_ADMIN)) @@ -1021,42 +994,21 @@ var/obj/item/station_charter/charter = locate(href_list["reject_custom_name"]) if(istype(charter)) charter.reject_proposed(usr) - else if(href_list["jumpto"]) - if(!isobserver(usr) && !check_rights(R_ADMIN)) - return - var/mob/M = locate(href_list["jumpto"]) - usr.client.jumptomob(M) + else if(href_list["jumpto"]) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/jump_to_mob, locate(href_list["jumpto"])) else if(href_list["getmob"]) - if(!check_rights(R_ADMIN)) - return - - if(tgui_alert(usr, "Confirm?", "Message", list("Yes", "No")) != "Yes") - return - var/mob/M = locate(href_list["getmob"]) - usr.client.Getmob(M) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/get_mob, locate(href_list["getmob"])) else if(href_list["sendmob"]) - if(!check_rights(R_ADMIN)) - return - - var/mob/M = locate(href_list["sendmob"]) - usr.client.sendmob(M) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/send_mob, locate(href_list["sendmob"])) else if(href_list["narrateto"]) - if(!check_rights(R_ADMIN)) - return - - var/mob/M = locate(href_list["narrateto"]) - usr.client.cmd_admin_direct_narrate(M) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/cmd_admin_direct_narrate, locate(href_list["narrateto"])) else if(href_list["subtlemessage"]) - if(!check_rights(R_ADMIN)) - return - - var/mob/M = locate(href_list["subtlemessage"]) - usr.client.cmd_admin_subtle_message(M) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/cmd_admin_subtle_message, locate(href_list["subtlemessage"])) else if(href_list["playsoundto"]) if(!check_rights(R_SOUND)) @@ -1065,7 +1017,7 @@ var/mob/M = locate(href_list["playsoundto"]) var/S = input("", "Select a sound file",) as null|sound if(S) - usr.client.play_direct_mob_sound(S, M) + SSadmin_verbs.dynamic_invoke_verb(usr.client, /datum/admin_verb/play_direct_mob_sound, S, M) else if(href_list["individuallog"]) if(!check_rights(R_ADMIN)) @@ -1104,7 +1056,8 @@ else D.traitor_panel() else - show_traitor_panel(M) + SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/show_traitor_panel, M) + return else if(href_list["skill"]) if(!check_rights(R_ADMIN)) @@ -1124,17 +1077,11 @@ else to_chat(usr, "This can only be used on instances of type /mob and /mind", confidential = TRUE) return - show_skill_panel(target_mind) + SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/show_skill_panel, target_mind) + return else if(href_list["borgpanel"]) - if(!check_rights(R_ADMIN)) - return - - var/mob/M = locate(href_list["borgpanel"]) - if(!iscyborg(M)) - to_chat(usr, "This can only be used on cyborgs", confidential = TRUE) - else - open_borgopanel(M) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/borg_panel, locate(href_list["borgpanel"])) else if(href_list["initmind"]) if(!check_rights(R_ADMIN)) @@ -1306,9 +1253,7 @@ return else if(href_list["check_antagonist"]) - if(!check_rights(R_ADMIN)) - return - usr.client.check_antagonists() + SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/check_antagonists) else if(href_list["kick_all_from_lobby"]) if(!check_rights(R_ADMIN)) @@ -1378,7 +1323,7 @@ log_admin("[key_name(usr)] turned a Lag Switch measure at index ([switch_index]) [LAZYACCESS(SSlag_switch.measures, switch_index) ? "ON" : "OFF"]") message_admins("[key_name_admin(usr)] turned a Lag Switch measure [LAZYACCESS(SSlag_switch.measures, switch_index) ? "ON" : "OFF"]") - src.show_lag_switch_panel() + SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/lag_switch_panel) else if(href_list["change_lag_switch_option"]) if(!check_rights(R_ADMIN)) @@ -1407,7 +1352,7 @@ log_admin("[key_name(usr)] set the Lag Switch slowmode cooldown to [new_num] seconds.") message_admins("[key_name_admin(usr)] set the Lag Switch slowmode cooldown to [new_num] seconds.") - src.show_lag_switch_panel() + SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/lag_switch_panel) else if(href_list["viewruntime"]) var/datum/error_viewer/error_viewer = locate(href_list["viewruntime"]) @@ -1523,13 +1468,7 @@ toggle_id_ctf(usr, CTF_GHOST_CTF_GAME_ID) else if(href_list["rebootworld"]) - if(!check_rights(R_ADMIN)) - return - var/confirm = tgui_alert(usr,"Are you sure you want to reboot the server?", "Confirm Reboot", list("Yes", "No")) - if(confirm == "No") - return - if(confirm == "Yes") - restart() + SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/restart) else if(href_list["check_teams"]) if(!check_rights(R_ADMIN)) @@ -1748,9 +1687,7 @@ return remove_tagged_datum(datum_to_remove) else if(href_list["show_tags"]) - if(!check_rights(R_ADMIN)) - return - return display_tags() + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/display_tags) else if(href_list["mark_datum"]) if(!check_rights(R_ADMIN)) @@ -1797,7 +1734,4 @@ web_sound(usr, link_url, credit) else if(href_list["debug_z_levels"]) - if(!check_rights(R_DEBUG)) - return - - owner.debug_z_levels() + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/debug_z_levels) diff --git a/code/modules/admin/trophy_manager.dm b/code/modules/admin/trophy_manager.dm index 6a45afb8e4593..5ad703b099427 100644 --- a/code/modules/admin/trophy_manager.dm +++ b/code/modules/admin/trophy_manager.dm @@ -1,11 +1,6 @@ -/datum/admins/proc/trophy_manager() - set name = "Trophy Manager" - set category = "Admin" - - if(!check_rights(R_ADMIN)) - return - var/datum/trophy_manager/ui = new(usr) - ui.ui_interact(usr) +ADMIN_VERB(trophy_manager, R_ADMIN, "Trophy Manager", "View all trophies.", ADMIN_CATEGORY_MAIN) + var/static/datum/trophy_manager/ui = new + ui.ui_interact(user.mob) /// Trophy Admin Management Panel /datum/trophy_manager diff --git a/code/modules/admin/verb_datums/_admin_verb_datum.dm b/code/modules/admin/verb_datums/_admin_verb_datum.dm new file mode 100644 index 0000000000000..6255d962c40c2 --- /dev/null +++ b/code/modules/admin/verb_datums/_admin_verb_datum.dm @@ -0,0 +1,27 @@ +GENERAL_PROTECT_DATUM(/datum/admin_verb) + +/** + * This is the admin verb datum. It is used to store the verb's information and handle the verb's functionality. + * All of this is setup for you, and you should not be defining this manually. + * That means you reader. + */ +/datum/admin_verb + var/name //! The name of the verb. + var/description //! The description of the verb. + var/category //! The category of the verb. + var/permissions //! The permissions required to use the verb. + var/visibility_flag //! The flag that determines if the verb is visible. + VAR_PROTECTED/verb_path //! The path to the verb proc. + +/datum/admin_verb/Destroy(force) + if(!force) + return QDEL_HINT_LETMELIVE + return ..() + +/// Assigns the verb to the admin. +/datum/admin_verb/proc/assign_to_client(client/admin) + add_verb(admin, verb_path) + +/// Unassigns the verb from the admin. +/datum/admin_verb/proc/unassign_from_client(client/admin) + remove_verb(admin, verb_path) diff --git a/code/modules/admin/verb_datums/_admin_verb_holder.dm b/code/modules/admin/verb_datums/_admin_verb_holder.dm new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2.dm b/code/modules/admin/verbs/SDQL2/SDQL_2.dm index 50da67115ea49..36db4fa8bc4b0 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2.dm @@ -195,20 +195,15 @@ state = SDQL2_STATE_ERROR;\ CRASH("SDQL2 fatal error");}; -/client/proc/SDQL2_query(query_text as message) - set category = "Debug" - if(!check_rights(R_DEBUG)) //Shouldn't happen... but just to be safe. - message_admins(span_danger("ERROR: Non-admin [key_name(usr)] attempted to execute a SDQL query!")) - usr.log_message("non-admin attempted to execute a SDQL query!", LOG_ADMIN) - return FALSE - var/prompt = tgui_alert(usr, "Run SDQL2 Query?", "SDQL2", list("Yes", "Cancel")) +ADMIN_VERB(sdql2_query, R_DEBUG, "SDQL2 Query", "Run a SDQL2 query.", ADMIN_CATEGORY_DEBUG, query_text as message) + var/prompt = tgui_alert(user, "Run SDQL2 Query?", "SDQL2", list("Yes", "Cancel")) if (prompt != "Yes") return - var/list/results = world.SDQL2_query(query_text, key_name_admin(usr), "[key_name(usr)]") + var/list/results = world.SDQL2_query(query_text, key_name_admin(user), "[key_name(user)]") if(length(results) == 3) for(var/I in 1 to 3) - to_chat(usr, span_admin(results[I]), confidential = TRUE) - SSblackbox.record_feedback("nested tally", "SDQL query", 1, list(ckey, query_text)) + to_chat(user, span_admin(results[I]), confidential = TRUE) + SSblackbox.record_feedback("nested tally", "SDQL query", 1, list(user.ckey, query_text)) /world/proc/SDQL2_query(query_text, log_entry1, log_entry2, silent = FALSE) var/query_log = "executed SDQL query(s): \"[query_text]\"." diff --git a/code/modules/admin/verbs/admin.dm b/code/modules/admin/verbs/admin.dm index 88c183ab507ea..21421e655d6df 100644 --- a/code/modules/admin/verbs/admin.dm +++ b/code/modules/admin/verbs/admin.dm @@ -1,15 +1,5 @@ -// Admin Tab - Admin Verbs - -/client/proc/show_tip() - set category = "Admin" - set name = "Show Tip" - set desc = "Sends a tip (that you specify) to all players. After all \ - you're the experienced player here." - - if(!check_rights(R_ADMIN)) - return - - var/input = input(usr, "Please specify your tip that you want to send to the players.", "Tip", "") as message|null +ADMIN_VERB(show_tip, R_ADMIN, "Show Tip", "Sends a tip to all players.", ADMIN_CATEGORY_MAIN) + var/input = input(user, "Please specify your tip that you want to send to the players.", "Tip", "") as message|null if(!input) return @@ -22,44 +12,34 @@ else SSticker.selected_tip = input - message_admins("[key_name_admin(usr)] sent a tip of the round.") - log_admin("[key_name(usr)] sent \"[input]\" as the Tip of the Round.") + message_admins("[key_name_admin(user)] sent a tip of the round.") + log_admin("[key_name(user)] sent \"[input]\" as the Tip of the Round.") BLACKBOX_LOG_ADMIN_VERB("Show Tip") -/datum/admins/proc/announce() - set category = "Admin" - set name = "Announce" - set desc="Announce your desires to the world" - if(!check_rights(0)) +ADMIN_VERB(announce, R_ADMIN, "Announce", "Announce your desires to the world.", ADMIN_CATEGORY_MAIN) + var/message = input(user, "Global message to send:", "Admin Announce") as message|null + if(!message) return - var/message = input("Global message to send:", "Admin Announce", null, null) as message|null - if(message) - if(!check_rights(R_SERVER,0)) - message = adminscrub(message,500) - send_ooc_announcement(message, "From [usr.client.holder.fakekey ? "Administrator" : usr.key]") - log_admin("Announce: [key_name(usr)] : [message]") + if(!user.holder.check_for_rights(R_SERVER)) + message = adminscrub(message,500) + send_ooc_announcement(message, "From [user.holder.fakekey ? "Administrator" : user.key]") + log_admin("Announce: [key_name(user)] : [message]") BLACKBOX_LOG_ADMIN_VERB("Announce") -/datum/admins/proc/unprison(mob/M in GLOB.mob_list) - set category = "Admin" - set name = "Unprison" - if (is_centcom_level(M.z)) - SSjob.SendToLateJoin(M) - message_admins("[key_name_admin(usr)] has unprisoned [key_name_admin(M)]") - log_admin("[key_name(usr)] has unprisoned [key_name(M)]") - else - tgui_alert(usr,"[M.name] is not prisoned.") - BLACKBOX_LOG_ADMIN_VERB("Unprison") - -/client/proc/cmd_admin_check_player_exp() //Allows admins to determine who the newer players are. - set category = "Admin" - set name = "Player Playtime" - if(!check_rights(R_ADMIN)) +ADMIN_VERB(unprison, R_ADMIN, "UnPrison", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/prisoner) + if(!is_centcom_level(prisoner.z)) + tgui_alert(user, "[prisoner.name] is not prisoned.") return + SSjob.SendToLateJoin(prisoner) + message_admins("[key_name_admin(user)] has unprisoned [key_name_admin(prisoner)]") + log_admin("[key_name(user)] has unprisoned [key_name(prisoner)]") + BLACKBOX_LOG_ADMIN_VERB("Unprison") + +ADMIN_VERB(cmd_admin_check_player_exp, R_ADMIN, "Player Playtime", "View player playtime.", ADMIN_CATEGORY_MAIN) if(!CONFIG_GET(flag/use_exp_tracking)) - to_chat(usr, span_warning("Tracking is disabled in the server configuration file."), confidential = TRUE) + to_chat(user, span_warning("Tracking is disabled in the server configuration file."), confidential = TRUE) return var/list/msg = list() @@ -67,7 +47,7 @@ for(var/client/client in sort_list(GLOB.clients, GLOBAL_PROC_REF(cmp_playtime_asc))) msg += "
  • [ADMIN_PP(client.mob)] [key_name_admin(client)]: " + client.get_exp_living() + "
  • " msg += "" - src << browse(msg.Join(), "window=Player_playtime_check") + user << browse(msg.Join(), "window=Player_playtime_check") /client/proc/trigger_centcom_recall() if(!check_rights(R_ADMIN)) @@ -164,23 +144,18 @@ /////////////////////////////////////////////////////////////////////////////////////////////// -/client/proc/cmd_admin_drop_everything(mob/M in GLOB.mob_list) - set category = null - set name = "Drop Everything" - if(!check_rights(R_ADMIN)) - return - - var/confirm = tgui_alert(usr, "Make [M] drop everything?", "Message", list("Yes", "No")) +ADMIN_VERB(drop_everything, R_ADMIN, "Drop Everything", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/dropee) + var/confirm = tgui_alert(user, "Make [dropee] drop everything?", "Message", list("Yes", "No")) if(confirm != "Yes") return - M.drop_everything(del_on_drop = FALSE, force = TRUE, del_if_nodrop = TRUE) - M.regenerate_icons() + dropee.drop_everything(del_on_drop = FALSE, force = TRUE, del_if_nodrop = TRUE) + dropee.regenerate_icons() - log_admin("[key_name(usr)] made [key_name(M)] drop everything!") - var/msg = "[key_name_admin(usr)] made [ADMIN_LOOKUPFLW(M)] drop everything!" + log_admin("[key_name(user)] made [key_name(dropee)] drop everything!") + var/msg = "[key_name_admin(user)] made [ADMIN_LOOKUPFLW(dropee)] drop everything!" message_admins(msg) - admin_ticket_log(M, msg) + admin_ticket_log(dropee, msg) BLACKBOX_LOG_ADMIN_VERB("Drop Everything") /proc/cmd_admin_mute(whom, mute_type, automute = 0) diff --git a/code/modules/admin/verbs/admin_newscaster.dm b/code/modules/admin/verbs/admin_newscaster.dm index 2f6870394c277..0439cfa8811ac 100644 --- a/code/modules/admin/verbs/admin_newscaster.dm +++ b/code/modules/admin/verbs/admin_newscaster.dm @@ -1,17 +1,6 @@ -/datum/admins/proc/access_news_network() //MARKER - set category = "Admin.Events" - set name = "Access Newscaster Network" - set desc = "Allows you to view, add and edit news feeds." - - if (!istype(src, /datum/admins)) - src = usr.client.holder - if (!istype(src, /datum/admins)) - to_chat(usr, "Error: you are not an admin!", confidential = TRUE) - return - +ADMIN_VERB(access_news_network, R_ADMIN, "Access Newscaster Network", "Allows you to view, add, and edit news feeds.", ADMIN_CATEGORY_EVENTS) var/datum/newspanel/new_newspanel = new - - new_newspanel.ui_interact(usr) + new_newspanel.ui_interact(user.mob) /datum/newspanel ///What newscaster channel is currently being viewed by the player? diff --git a/code/modules/admin/verbs/adminevents.dm b/code/modules/admin/verbs/adminevents.dm index f69e891625a6d..b452e26d132d7 100644 --- a/code/modules/admin/verbs/adminevents.dm +++ b/code/modules/admin/verbs/adminevents.dm @@ -1,37 +1,24 @@ // Admin Tab - Event Verbs -/client/proc/cmd_admin_subtle_message(mob/M in GLOB.mob_list) - set category = "Admin.Events" - set name = "Subtle Message" +ADMIN_VERB_AND_CONTEXT_MENU(cmd_admin_subtle_message, R_ADMIN, "Subtle Message", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/target in world) + message_admins("[key_name_admin(user)] has started answering [ADMIN_LOOKUPFLW(target)]'s prayer.") + var/msg = input(user, "Message:", "Subtle PM to [target.key]") as text|null - if(!ismob(M)) - return - if(!check_rights(R_ADMIN)) + if(!msg) + message_admins("[key_name_admin(user)] decided not to answer [ADMIN_LOOKUPFLW(target)]'s prayer") return - message_admins("[key_name_admin(src)] has started answering [ADMIN_LOOKUPFLW(M)]'s prayer.") - var/msg = input("Message:", "Subtle PM to [M.key]") as text|null + target.balloon_alert(target, "you hear a voice") + to_chat(target, "You hear a voice in your head... [msg]", confidential = TRUE) - if(!msg) - message_admins("[key_name_admin(src)] decided not to answer [ADMIN_LOOKUPFLW(M)]'s prayer") - return - if(usr) - if (usr.client) - if(usr.client.holder) - M.balloon_alert(M, "you hear a voice") - to_chat(M, "You hear a voice in your head... [msg]", confidential = TRUE) - - log_admin("SubtlePM: [key_name(usr)] -> [key_name(M)] : [msg]") - msg = span_adminnotice(" SubtleMessage: [key_name_admin(usr)] -> [key_name_admin(M)] : [msg]") + log_admin("SubtlePM: [key_name(user)] -> [key_name(target)] : [msg]") + msg = span_adminnotice(" SubtleMessage: [key_name_admin(user)] -> [key_name_admin(target)] : [msg]") message_admins(msg) - admin_ticket_log(M, msg) + admin_ticket_log(target, msg) BLACKBOX_LOG_ADMIN_VERB("Subtle Message") -/client/proc/cmd_admin_headset_message(mob/M in GLOB.mob_list) - set category = "Admin.Events" - set name = "Headset Message" - - admin_headset_message(M) +ADMIN_VERB_AND_CONTEXT_MENU(cmd_admin_headset_message, R_ADMIN, "Headset Message", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/target in world) + user.admin_headset_message(target) /client/proc/admin_headset_message(mob/target in GLOB.mob_list, sender = null) var/mob/living/carbon/human/human_recipient @@ -73,102 +60,64 @@ BLACKBOX_LOG_ADMIN_VERB("Headset Message") -/client/proc/cmd_admin_world_narrate() - set category = "Admin.Events" - set name = "Global Narrate" - - if(!check_rights(R_ADMIN)) - return - - var/msg = input("Message:", "Enter the text you wish to appear to everyone:") as text|null - +ADMIN_VERB(cmd_admin_world_narrate, R_ADMIN, "Global Narrate", "Send a direct narration to all connected players.", ADMIN_CATEGORY_EVENTS) + var/msg = input(user, "Message:", "Enter the text you wish to appear to everyone:") as text|null if (!msg) return to_chat(world, "[msg]", confidential = TRUE) - log_admin("GlobalNarrate: [key_name(usr)] : [msg]") - message_admins(span_adminnotice("[key_name_admin(usr)] Sent a global narrate")) + log_admin("GlobalNarrate: [key_name(user)] : [msg]") + message_admins(span_adminnotice("[key_name_admin(user)] Sent a global narrate")) BLACKBOX_LOG_ADMIN_VERB("Global Narrate") -/client/proc/cmd_admin_local_narrate(atom/A) - set category = "Admin.Events" - set name = "Local Narrate" - - if(!check_rights(R_ADMIN)) - return - if(!A) - return - var/range = input("Range:", "Narrate to mobs within how many tiles:", 7) as num|null +ADMIN_VERB_AND_CONTEXT_MENU(cmd_admin_local_narrate, R_ADMIN, "Local Narrate", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, atom/locale in world) + var/range = input(user, "Range:", "Narrate to mobs within how many tiles:", 7) as num|null if(!range) return - var/msg = input("Message:", "Enter the text you wish to appear to everyone within view:") as text|null + var/msg = input(user, "Message:", "Enter the text you wish to appear to everyone within view:") as text|null if (!msg) return - for(var/mob/M in view(range,A)) + for(var/mob/M in view(range, locale)) to_chat(M, msg, confidential = TRUE) - log_admin("LocalNarrate: [key_name(usr)] at [AREACOORD(A)]: [msg]") - message_admins(span_adminnotice(" LocalNarrate: [key_name_admin(usr)] at [ADMIN_VERBOSEJMP(A)]: [msg]
    ")) + log_admin("LocalNarrate: [key_name(user)] at [AREACOORD(locale)]: [msg]") + message_admins(span_adminnotice(" LocalNarrate: [key_name_admin(user)] at [ADMIN_VERBOSEJMP(locale)]: [msg]
    ")) BLACKBOX_LOG_ADMIN_VERB("Local Narrate") -/client/proc/cmd_admin_direct_narrate(mob/M) - set category = "Admin.Events" - set name = "Direct Narrate" - - if(!check_rights(R_ADMIN)) - return - - if(!M) - M = input("Direct narrate to whom?", "Active Players") as null|anything in GLOB.player_list - - if(!M) - return - - var/msg = input("Message:", "Enter the text you wish to appear to your target:") as text|null +ADMIN_VERB_AND_CONTEXT_MENU(cmd_admin_direct_narrate, R_ADMIN, "Direct Narrate", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/target) + var/msg = input(user, "Message:", "Enter the text you wish to appear to your target:") as text|null if( !msg ) return - to_chat(M, msg, confidential = TRUE) - log_admin("DirectNarrate: [key_name(usr)] to ([M.name]/[M.key]): [msg]") - msg = span_adminnotice(" DirectNarrate: [key_name(usr)] to ([M.name]/[M.key]): [msg]
    ") + to_chat(target, msg, confidential = TRUE) + log_admin("DirectNarrate: [key_name(user)] to ([key_name(target)]): [msg]") + msg = span_adminnotice(" DirectNarrate: [key_name_admin(user)] to ([key_name_admin(target)]): [msg]
    ") message_admins(msg) - admin_ticket_log(M, msg) + admin_ticket_log(target, msg) BLACKBOX_LOG_ADMIN_VERB("Direct Narrate") -/client/proc/cmd_admin_add_freeform_ai_law() - set category = "Admin.Events" - set name = "Add Custom AI law" - - if(!check_rights(R_ADMIN)) - return - - var/input = input(usr, "Please enter anything you want the AI to do. Anything. Serious.", "What?", "") as text|null +ADMIN_VERB(cmd_admin_add_freeform_ai_law, R_ADMIN, "Add Custom AI Law", "Add a custom law to the Silicons.", ADMIN_CATEGORY_EVENTS) + var/input = input(user, "Please enter anything you want the AI to do. Anything. Serious.", "What?", "") as text|null if(!input) return - log_admin("Admin [key_name(usr)] has added a new AI law - [input]") - message_admins("Admin [key_name_admin(usr)] has added a new AI law - [input]") + log_admin("Admin [key_name(user)] has added a new AI law - [input]") + message_admins("Admin [key_name_admin(user)] has added a new AI law - [input]") - var/show_log = tgui_alert(usr, "Show ion message?", "Message", list("Yes", "No")) + var/show_log = tgui_alert(user, "Show ion message?", "Message", list("Yes", "No")) var/announce_ion_laws = (show_log == "Yes" ? 100 : 0) - var/datum/round_event/ion_storm/add_law_only/ion = new() + var/datum/round_event/ion_storm/add_law_only/ion = new ion.announce_chance = announce_ion_laws ion.ionMessage = input BLACKBOX_LOG_ADMIN_VERB("Add Custom AI Law") -/client/proc/admin_call_shuttle() - set category = "Admin.Events" - set name = "Call Shuttle" - +ADMIN_VERB(call_shuttle, R_ADMIN, "Call Shuttle", "Force a shuttle call with additional modifiers.", ADMIN_CATEGORY_EVENTS) if(EMERGENCY_AT_LEAST_DOCKED) return - if(!check_rights(R_ADMIN)) - return - - var/confirm = tgui_alert(usr, "You sure?", "Confirm", list("Yes", "Yes (No Recall)", "No")) + var/confirm = tgui_alert(user, "You sure?", "Confirm", list("Yes", "Yes (No Recall)", "No")) switch(confirm) if(null, "No") return @@ -178,46 +127,30 @@ SSshuttle.emergency.request() BLACKBOX_LOG_ADMIN_VERB("Call Shuttle") - log_admin("[key_name(usr)] admin-called the emergency shuttle.") - message_admins(span_adminnotice("[key_name_admin(usr)] admin-called the emergency shuttle[confirm == "Yes (No Recall)" ? " (non-recallable)" : ""].")) - return - -/client/proc/admin_cancel_shuttle() - set category = "Admin.Events" - set name = "Cancel Shuttle" - if(!check_rights(0)) - return - if(tgui_alert(usr, "You sure?", "Confirm", list("Yes", "No")) != "Yes") - return - - if(SSshuttle.admin_emergency_no_recall) - SSshuttle.admin_emergency_no_recall = FALSE + log_admin("[key_name(user)] admin-called the emergency shuttle.") + message_admins(span_adminnotice("[key_name_admin(user)] admin-called the emergency shuttle[confirm == "Yes (No Recall)" ? " (non-recallable)" : ""].")) +ADMIN_VERB(cancel_shuttle, R_ADMIN, "Cancel Shuttle", "Recall the shuttle, regardless of circumstances.", ADMIN_CATEGORY_EVENTS) if(EMERGENCY_AT_LEAST_DOCKED) return + if(tgui_alert(user, "You sure?", "Confirm", list("Yes", "No")) != "Yes") + return + SSshuttle.admin_emergency_no_recall = FALSE SSshuttle.emergency.cancel() BLACKBOX_LOG_ADMIN_VERB("Cancel Shuttle") - log_admin("[key_name(usr)] admin-recalled the emergency shuttle.") - message_admins(span_adminnotice("[key_name_admin(usr)] admin-recalled the emergency shuttle.")) - - return - -/client/proc/admin_disable_shuttle() - set category = "Admin.Events" - set name = "Disable Shuttle" - - if(!check_rights(R_ADMIN)) - return + log_admin("[key_name(user)] admin-recalled the emergency shuttle.") + message_admins(span_adminnotice("[key_name_admin(user)] admin-recalled the emergency shuttle.")) +ADMIN_VERB(disable_shuttle, R_ADMIN, "Disable Shuttle", "Those fuckers aren't getting out.", ADMIN_CATEGORY_EVENTS) if(SSshuttle.emergency.mode == SHUTTLE_DISABLED) - to_chat(usr, span_warning("Error, shuttle is already disabled.")) + to_chat(user, span_warning("Error, shuttle is already disabled.")) return - if(tgui_alert(usr, "You sure?", "Confirm", list("Yes", "No")) != "Yes") + if(tgui_alert(user, "You sure?", "Confirm", list("Yes", "No")) != "Yes") return - message_admins(span_adminnotice("[key_name_admin(usr)] disabled the shuttle.")) + message_admins(span_adminnotice("[key_name_admin(user)] disabled the shuttle.")) SSshuttle.last_mode = SSshuttle.emergency.mode SSshuttle.last_call_time = SSshuttle.emergency.timeLeft(1) @@ -232,21 +165,15 @@ color_override = "grey", ) -/client/proc/admin_enable_shuttle() - set category = "Admin.Events" - set name = "Enable Shuttle" - - if(!check_rights(R_ADMIN)) - return - +ADMIN_VERB(enable_shuttle, R_ADMIN, "Enable Shuttle", "Those fuckers ARE getting out.", ADMIN_CATEGORY_EVENTS) if(SSshuttle.emergency.mode != SHUTTLE_DISABLED) - to_chat(usr, span_warning("Error, shuttle not disabled.")) + to_chat(user, span_warning("Error, shuttle not disabled.")) return - if(tgui_alert(usr, "You sure?", "Confirm", list("Yes", "No")) != "Yes") + if(tgui_alert(user, "You sure?", "Confirm", list("Yes", "No")) != "Yes") return - message_admins(span_adminnotice("[key_name_admin(usr)] enabled the emergency shuttle.")) + message_admins(span_adminnotice("[key_name_admin(user)] enabled the emergency shuttle.")) SSshuttle.admin_emergency_no_recall = FALSE SSshuttle.emergency_no_recall = FALSE if(SSshuttle.last_mode == SHUTTLE_DISABLED) //If everything goes to shit, fix it. @@ -264,135 +191,77 @@ color_override = "green", ) -/client/proc/admin_hostile_environment() - set category = "Admin.Events" - set name = "Hostile Environment" - - if(!check_rights(R_ADMIN)) - return - - switch(tgui_alert(usr, "Select an Option", "Hostile Environment Manager", list("Enable", "Disable", "Clear All"))) +ADMIN_VERB(hostile_environment, R_ADMIN, "Hostile Environment", "Disable the shuttle, naturally.", ADMIN_CATEGORY_EVENTS) + switch(tgui_alert(user, "Select an Option", "Hostile Environment Manager", list("Enable", "Disable", "Clear All"))) if("Enable") if (SSshuttle.hostile_environments["Admin"] == TRUE) - to_chat(usr, span_warning("Error, admin hostile environment already enabled.")) + to_chat(user, span_warning("Error, admin hostile environment already enabled.")) else - message_admins(span_adminnotice("[key_name_admin(usr)] Enabled an admin hostile environment")) + message_admins(span_adminnotice("[key_name_admin(user)] Enabled an admin hostile environment")) SSshuttle.registerHostileEnvironment("Admin") if("Disable") if (!SSshuttle.hostile_environments["Admin"]) - to_chat(usr, span_warning("Error, no admin hostile environment found.")) + to_chat(user, span_warning("Error, no admin hostile environment found.")) else - message_admins(span_adminnotice("[key_name_admin(usr)] Disabled the admin hostile environment")) + message_admins(span_adminnotice("[key_name_admin(user)] Disabled the admin hostile environment")) SSshuttle.clearHostileEnvironment("Admin") if("Clear All") - message_admins(span_adminnotice("[key_name_admin(usr)] Disabled all current hostile environment sources")) + message_admins(span_adminnotice("[key_name_admin(user)] Disabled all current hostile environment sources")) SSshuttle.hostile_environments.Cut() SSshuttle.checkHostileEnvironment() -/client/proc/toggle_nuke(obj/machinery/nuclearbomb/N in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/nuclearbomb)) - set category = "Admin.Events" - set name = "Toggle Nuke" - set popup_menu = FALSE - if(!check_rights(R_DEBUG)) - return - - if(!N.timing) - var/newtime = input(usr, "Set activation timer.", "Activate Nuke", "[N.timer_set]") as num|null +ADMIN_VERB(toggle_nuke, R_DEBUG|R_ADMIN, "Toggle Nuke", "Arm or disarm a nuke.", ADMIN_CATEGORY_EVENTS, obj/machinery/nuclearbomb/nuke in world) + if(!nuke.timing) + var/newtime = input(user, "Set activation timer.", "Activate Nuke", "[nuke.timer_set]") as num|null if(!newtime) return - N.timer_set = newtime - N.toggle_nuke_safety() - N.toggle_nuke_armed() - - log_admin("[key_name(usr)] [N.timing ? "activated" : "deactivated"] a nuke at [AREACOORD(N)].") - message_admins("[ADMIN_LOOKUPFLW(usr)] [N.timing ? "activated" : "deactivated"] a nuke at [ADMIN_VERBOSEJMP(N)].") - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Nuke", "[N.timing]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! + nuke.timer_set = newtime + nuke.toggle_nuke_safety() + nuke.toggle_nuke_armed() -/client/proc/admin_change_sec_level() - set category = "Admin.Events" - set name = "Set Security Level" - set desc = "Changes the security level. Announcement only, i.e. setting to Delta won't activate nuke" - - if(!check_rights(R_ADMIN)) - return + log_admin("[key_name(user)] [nuke.timing ? "activated" : "deactivated"] a nuke at [AREACOORD(nuke)].") + message_admins("[ADMIN_LOOKUPFLW(user)] [nuke.timing ? "activated" : "deactivated"] a nuke at [ADMIN_VERBOSEJMP(nuke)].") + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Nuke", "[nuke.timing]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! - var/level = tgui_input_list(usr, "Select Security Level:", "Set Security Level", SSsecurity_level.available_levels) +ADMIN_VERB(change_sec_level, R_ADMIN, "Set Security Level", "Changes the security level. Announcement effects only.", ADMIN_CATEGORY_EVENTS) + var/level = tgui_input_list(user, "Select Security Level:", "Set Security Level", SSsecurity_level.available_levels) if(!level) return SSsecurity_level.set_level(level) - log_admin("[key_name(usr)] changed the security level to [level]") - message_admins("[key_name_admin(usr)] changed the security level to [level]") + log_admin("[key_name(user)] changed the security level to [level]") + message_admins("[key_name_admin(user)] changed the security level to [level]") BLACKBOX_LOG_ADMIN_VERB("Set Security Level [capitalize(level)]") -/client/proc/run_weather() - set category = "Admin.Events" - set name = "Run Weather" - set desc = "Triggers a weather on the z-level you choose." - - if(!holder) - return - - var/weather_type = input("Choose a weather", "Weather") as null|anything in sort_list(subtypesof(/datum/weather), GLOBAL_PROC_REF(cmp_typepaths_asc)) +ADMIN_VERB(run_weather, R_FUN, "Run Weather", "Triggers specific weather on the z-level you choose.", ADMIN_CATEGORY_EVENTS) + var/weather_type = input(user, "Choose a weather", "Weather") as null|anything in sort_list(subtypesof(/datum/weather), GLOBAL_PROC_REF(cmp_typepaths_asc)) if(!weather_type) return - var/turf/T = get_turf(mob) - var/z_level = input("Z-Level to target?", "Z-Level", T?.z) as num|null + var/turf/T = get_turf(user.mob) + var/z_level = input(user, "Z-Level to target?", "Z-Level", T?.z) as num|null if(!isnum(z_level)) return SSweather.run_weather(weather_type, z_level) - message_admins("[key_name_admin(usr)] started weather of type [weather_type] on the z-level [z_level].") - log_admin("[key_name(usr)] started weather of type [weather_type] on the z-level [z_level].") + message_admins("[key_name_admin(user)] started weather of type [weather_type] on the z-level [z_level].") + log_admin("[key_name(user)] started weather of type [weather_type] on the z-level [z_level].") BLACKBOX_LOG_ADMIN_VERB("Run Weather") -/client/proc/add_marked_mob_ability() - set category = "Admin.Events" - set name = "Add Mob Ability (Marked Mob)" - set desc = "Adds an ability to a marked mob." - - if(!holder) - return - - if(!isliving(holder.marked_datum)) - to_chat(usr, span_warning("Error: Please mark a mob to add actions to it.")) - return - give_mob_action(holder.marked_datum) - -/client/proc/remove_marked_mob_ability() - set category = "Admin.Events" - set name = "Remove Mob Ability (Marked Mob)" - set desc = "Removes an ability from marked mob." - - if(!holder) - return - - if(!isliving(holder.marked_datum)) - to_chat(usr, span_warning("Error: Please mark a mob to remove actions from it.")) - return - remove_mob_action(holder.marked_datum) - -/client/proc/command_report_footnote() - set category = "Admin.Events" - set name = "Command Report Footnote" - set desc = "Adds a footnote to the roundstart command report." - - if(!check_rights(R_ADMIN)) - return - +ADMIN_VERB(command_report_footnote, R_ADMIN, "Command Report Footnote", "Adds a footnote to the roundstart command report.", ADMIN_CATEGORY_EVENTS) var/datum/command_footnote/command_report_footnote = new /datum/command_footnote() - SScommunications.block_command_report++ //Add a blocking condition to the counter until the inputs are done. - - command_report_footnote.message = tgui_input_text(usr, "This message will be attached to the bottom of the roundstart threat report. Be sure to delay the roundstart report if you need extra time.", "P.S.") + SScommunications.block_command_report += 1 //Add a blocking condition to the counter until the inputs are done. + command_report_footnote.message = tgui_input_text(user, "This message will be attached to the bottom of the roundstart threat report. Be sure to delay the roundstart report if you need extra time.", "P.S.") if(!command_report_footnote.message) + SScommunications.block_command_report -= 1 + qdel(command_report_footnote) return - command_report_footnote.signature = tgui_input_text(usr, "Whose signature will appear on this footnote?", "Also sign here, here, aaand here.") + command_report_footnote.signature = tgui_input_text(user, "Whose signature will appear on this footnote?", "Also sign here, here, aaand here.") if(!command_report_footnote.signature) command_report_footnote.signature = "Classified" @@ -400,23 +269,12 @@ SScommunications.command_report_footnotes += command_report_footnote SScommunications.block_command_report-- - message_admins("[usr] has added a footnote to the command report: [command_report_footnote.message], signed [command_report_footnote.signature]") + message_admins("[user] has added a footnote to the command report: [command_report_footnote.message], signed [command_report_footnote.signature]") /datum/command_footnote var/message var/signature -/client/proc/delay_command_report() - set category = "Admin.Events" - set name = "Delay Command Report" - set desc = "Prevents the roundstart command report from being sent until toggled." - - if(!check_rights(R_ADMIN)) - return - - if(SScommunications.block_command_report) //If it's anything other than 0, decrease. If 0, increase. - SScommunications.block_command_report-- - message_admins("[usr] has enabled the roundstart command report.") - else - SScommunications.block_command_report++ - message_admins("[usr] has delayed the roundstart command report.") +ADMIN_VERB(delay_command_report, R_FUN, "Delay Command Report", "Prevents the roundstart command report from being sent; or forces it to send it delayed.", ADMIN_CATEGORY_EVENTS) + SScommunications.block_command_report = !SScommunications.block_command_report + message_admins("[key_name_admin(user)] has [(SScommunications.block_command_report ? "delayed" : "sent")] the roundstart command report.") diff --git a/code/modules/admin/verbs/adminfun.dm b/code/modules/admin/verbs/adminfun.dm index fcba8d40928ca..f115e8808b536 100644 --- a/code/modules/admin/verbs/adminfun.dm +++ b/code/modules/admin/verbs/adminfun.dm @@ -1,74 +1,54 @@ -// Admin Tab - Fun Verbs - -/client/proc/cmd_admin_explosion(atom/O as obj|mob|turf in world) - set category = "Admin.Fun" - set name = "Explosion" - - if(!check_rights(R_ADMIN)) - return - - var/devastation = input("Range of total devastation. -1 to none", "Input") as num|null +ADMIN_VERB(admin_explosion, R_ADMIN|R_FUN, "Explosion", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, atom/orignator as obj|mob|turf) + var/devastation = input(user, "Range of total devastation. -1 to none", "Input") as num|null if(devastation == null) return - var/heavy = input("Range of heavy impact. -1 to none", "Input") as num|null + var/heavy = input(user, "Range of heavy impact. -1 to none", "Input") as num|null if(heavy == null) return - var/light = input("Range of light impact. -1 to none", "Input") as num|null + var/light = input(user, "Range of light impact. -1 to none", "Input") as num|null if(light == null) return - var/flash = input("Range of flash. -1 to none", "Input") as num|null + var/flash = input(user, "Range of flash. -1 to none", "Input") as num|null if(flash == null) return - var/flames = input("Range of flames. -1 to none", "Input") as num|null + var/flames = input(user, "Range of flames. -1 to none", "Input") as num|null if(flames == null) return if ((devastation != -1) || (heavy != -1) || (light != -1) || (flash != -1) || (flames != -1)) if ((devastation > 20) || (heavy > 20) || (light > 20) || (flames > 20)) - if (tgui_alert(usr, "Are you sure you want to do this? It will laaag.", "Confirmation", list("Yes", "No")) == "No") + if (tgui_alert(user, "Are you sure you want to do this? It will laaag.", "Confirmation", list("Yes", "No")) == "No") return - explosion(O, devastation, heavy, light, flames, flash, explosion_cause = mob) - log_admin("[key_name(usr)] created an explosion ([devastation],[heavy],[light],[flames]) at [AREACOORD(O)]") - message_admins("[key_name_admin(usr)] created an explosion ([devastation],[heavy],[light],[flames]) at [AREACOORD(O)]") + explosion(orignator, devastation, heavy, light, flames, flash, explosion_cause = user.mob) + log_admin("[key_name(user)] created an explosion ([devastation],[heavy],[light],[flames]) at [AREACOORD(orignator)]") + message_admins("[key_name_admin(user)] created an explosion ([devastation],[heavy],[light],[flames]) at [AREACOORD(orignator)]") BLACKBOX_LOG_ADMIN_VERB("Explosion") -/client/proc/cmd_admin_emp(atom/O as obj|mob|turf in world) - set category = "Admin.Fun" - set name = "EM Pulse" - - if(!check_rights(R_ADMIN)) - return - - var/heavy = input("Range of heavy pulse.", "Input") as num|null +ADMIN_VERB(admin_emp, R_ADMIN|R_FUN, "EM Pulse", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, atom/orignator as obj|mob|turf) + var/heavy = input(user, "Range of heavy pulse.", "Input") as num|null if(heavy == null) return - var/light = input("Range of light pulse.", "Input") as num|null + var/light = input(user, "Range of light pulse.", "Input") as num|null if(light == null) return if (heavy || light) - empulse(O, heavy, light) - log_admin("[key_name(usr)] created an EM Pulse ([heavy],[light]) at [AREACOORD(O)]") - message_admins("[key_name_admin(usr)] created an EM Pulse ([heavy],[light]) at [AREACOORD(O)]") + empulse(orignator, heavy, light) + log_admin("[key_name(user)] created an EM Pulse ([heavy],[light]) at [AREACOORD(orignator)]") + message_admins("[key_name_admin(user)] created an EM Pulse ([heavy],[light]) at [AREACOORD(orignator)]") BLACKBOX_LOG_ADMIN_VERB("EM Pulse") -/client/proc/cmd_admin_gib(mob/victim in GLOB.mob_list) - set category = "Admin.Fun" - set name = "Gib" - - if(!check_rights(R_ADMIN)) - return - - var/confirm = tgui_alert(usr, "Drop a brain?", "Confirm", list("Yes", "No","Cancel")) || "Cancel" +ADMIN_VERB(gib_them, R_ADMIN, "Gib", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/victim) + var/confirm = tgui_alert(user, "Drop a brain?", "Confirm", list("Yes", "No","Cancel")) || "Cancel" if(confirm == "Cancel") return //Due to the delay here its easy for something to have happened to the mob if(isnull(victim)) return - log_admin("[key_name(usr)] has gibbed [key_name(victim)]") - message_admins("[key_name_admin(usr)] has gibbed [key_name_admin(victim)]") + log_admin("[key_name(user)] has gibbed [key_name(victim)]") + message_admins("[key_name_admin(user)] has gibbed [key_name_admin(victim)]") if(isobserver(victim)) new /obj/effect/gibspawner/generic(get_turf(victim)) @@ -84,62 +64,47 @@ BLACKBOX_LOG_ADMIN_VERB("Gib") -/client/proc/cmd_admin_gib_self() - set name = "Gibself" - set category = "Admin.Fun" - - var/confirm = tgui_alert(usr, "You sure?", "Confirm", list("Yes", "No")) +ADMIN_VERB(gib_self, R_ADMIN, "Gibself", "Give yourself the same treatment you give others.", ADMIN_CATEGORY_FUN) + var/confirm = tgui_alert(user, "You sure?", "Confirm", list("Yes", "No")) if(confirm != "Yes") return - log_admin("[key_name(usr)] used gibself.") - message_admins(span_adminnotice("[key_name_admin(usr)] used gibself.")) + log_admin("[key_name(user)] used gibself.") + message_admins(span_adminnotice("[key_name_admin(user)] used gibself.")) BLACKBOX_LOG_ADMIN_VERB("Gib Self") - var/mob/living/ourself = mob + var/mob/living/ourself = user.mob if (istype(ourself)) ourself.gib() -/client/proc/everyone_random() - set category = "Admin.Fun" - set name = "Make Everyone Random" - set desc = "Make everyone have a random appearance. You can only use this before rounds!" - +ADMIN_VERB(everyone_random, R_SERVER, "Make Everyone Random", "Make everyone have a random appearance.", ADMIN_CATEGORY_FUN) if(SSticker.HasRoundStarted()) - to_chat(usr, "Nope you can't do this, the game's already started. This only works before rounds!", confidential = TRUE) + to_chat(user, "Nope you can't do this, the game's already started. This only works before rounds!", confidential = TRUE) return var/frn = CONFIG_GET(flag/force_random_names) if(frn) CONFIG_SET(flag/force_random_names, FALSE) - message_admins("Admin [key_name_admin(usr)] has disabled \"Everyone is Special\" mode.") - to_chat(usr, "Disabled.", confidential = TRUE) + message_admins("Admin [key_name_admin(user)] has disabled \"Everyone is Special\" mode.") + to_chat(user, "Disabled.", confidential = TRUE) return - var/notifyplayers = tgui_alert(usr, "Do you want to notify the players?", "Options", list("Yes", "No", "Cancel")) || "Cancel" + var/notifyplayers = tgui_alert(user, "Do you want to notify the players?", "Options", list("Yes", "No", "Cancel")) || "Cancel" if(notifyplayers == "Cancel") return - log_admin("Admin [key_name(src)] has forced the players to have random appearances.") - message_admins("Admin [key_name_admin(usr)] has forced the players to have random appearances.") + log_admin("Admin [key_name(user)] has forced the players to have random appearances.") + message_admins("Admin [key_name_admin(user)] has forced the players to have random appearances.") if(notifyplayers == "Yes") - to_chat(world, span_adminnotice("Admin [usr.key] has forced the players to have completely random identities!"), confidential = TRUE) + to_chat(world, span_adminnotice("Admin [user.key] has forced the players to have completely random identities!"), confidential = TRUE) - to_chat(usr, "Remember: you can always disable the randomness by using the verb again, assuming the round hasn't started yet.", confidential = TRUE) + to_chat(user, "Remember: you can always disable the randomness by using the verb again, assuming the round hasn't started yet.", confidential = TRUE) CONFIG_SET(flag/force_random_names, TRUE) BLACKBOX_LOG_ADMIN_VERB("Make Everyone Random") -/client/proc/mass_zombie_infection() - set category = "Admin.Fun" - set name = "Mass Zombie Infection" - set desc = "Infects all humans with a latent organ that will zombify \ - them on death." - - if(!check_rights(R_ADMIN)) - return - - var/confirm = tgui_alert(usr, "Please confirm you want to add latent zombie organs in all humans?", "Confirm Zombies", list("Yes", "No")) +ADMIN_VERB(mass_zombie_infection, R_ADMIN, "Mass Zombie Infection", "Infects all humans with a latent organ that will zombify them on death.", ADMIN_CATEGORY_FUN) + var/confirm = tgui_alert(user, "Please confirm you want to add latent zombie organs in all humans?", "Confirm Zombies", list("Yes", "No")) if(confirm != "Yes") return @@ -147,45 +112,32 @@ var/mob/living/carbon/human/H = i new /obj/item/organ/internal/zombie_infection/nodamage(H) - message_admins("[key_name_admin(usr)] added a latent zombie infection to all humans.") - log_admin("[key_name(usr)] added a latent zombie infection to all humans.") + message_admins("[key_name_admin(user)] added a latent zombie infection to all humans.") + log_admin("[key_name(user)] added a latent zombie infection to all humans.") BLACKBOX_LOG_ADMIN_VERB("Mass Zombie Infection") -/client/proc/mass_zombie_cure() - set category = "Admin.Fun" - set name = "Mass Zombie Cure" - set desc = "Removes the zombie infection from all humans, returning them to normal." - if(!check_rights(R_ADMIN)) - return - - var/confirm = tgui_alert(usr, "Please confirm you want to cure all zombies?", "Confirm Zombie Cure", list("Yes", "No")) +ADMIN_VERB(mass_zombie_cure, R_ADMIN, "Mass Zombie Cure", "Removes the zombie infection from all humans, returning them to normal.", ADMIN_CATEGORY_FUN) + var/confirm = tgui_alert(user, "Please confirm you want to cure all zombies?", "Confirm Zombie Cure", list("Yes", "No")) if(confirm != "Yes") return for(var/obj/item/organ/internal/zombie_infection/nodamage/I in GLOB.zombie_infection_list) qdel(I) - message_admins("[key_name_admin(usr)] cured all zombies.") - log_admin("[key_name(usr)] cured all zombies.") + message_admins("[key_name_admin(user)] cured all zombies.") + log_admin("[key_name(user)] cured all zombies.") BLACKBOX_LOG_ADMIN_VERB("Mass Zombie Cure") -/client/proc/polymorph_all() - set category = "Admin.Fun" - set name = "Polymorph All" - set desc = "Applies the effects of the bolt of change to every single mob." - - if(!check_rights(R_ADMIN)) - return - - var/confirm = tgui_alert(usr, "Please confirm you want polymorph all mobs?", "Confirm Polymorph", list("Yes", "No")) +ADMIN_VERB(polymorph_all, R_ADMIN, "Polymorph All", "Applies the effects of the bolt of change to every single mob.", ADMIN_CATEGORY_FUN) + var/confirm = tgui_alert(user, "Please confirm you want polymorph all mobs?", "Confirm Polymorph", list("Yes", "No")) if(confirm != "Yes") return var/list/mobs = shuffle(GLOB.alive_mob_list.Copy()) // might change while iterating - var/who_did_it = key_name_admin(usr) + var/who_did_it = key_name_admin(user) - message_admins("[key_name_admin(usr)] started polymorphed all living mobs.") - log_admin("[key_name(usr)] polymorphed all living mobs.") + message_admins("[key_name_admin(user)] started polymorphed all living mobs.") + log_admin("[key_name(user)] polymorphed all living mobs.") BLACKBOX_LOG_ADMIN_VERB("Polymorph All") for(var/mob/living/M in mobs) @@ -201,23 +153,18 @@ message_admins("Mass polymorph started by [who_did_it] is complete.") -/client/proc/smite(mob/living/target as mob) - set category = "Admin.Fun" - set name = "Smite" - if(!check_rights(R_ADMIN) || !check_rights(R_FUN)) - return - - var/punishment = input("Choose a punishment", "DIVINE SMITING") as null|anything in GLOB.smites +ADMIN_VERB_AND_CONTEXT_MENU(admin_smite, R_ADMIN|R_FUN, "Smite", "Smite a player with divine power.", ADMIN_CATEGORY_FUN, mob/living/target in world) + var/punishment = input(user, "Choose a punishment", "DIVINE SMITING") as null|anything in GLOB.smites if(QDELETED(target) || !punishment) return var/smite_path = GLOB.smites[punishment] var/datum/smite/smite = new smite_path - var/configuration_success = smite.configure(usr) + var/configuration_success = smite.configure(user) if (configuration_success == FALSE) return - smite.effect(src, target) + smite.effect(user, target) /// "Turns" people into objects. Really, we just add them to the contents of the item. /proc/objectify(atom/movable/target, path) diff --git a/code/modules/admin/verbs/admingame.dm b/code/modules/admin/verbs/admingame.dm index 78b61fd40bab5..e40a61db6cd89 100644 --- a/code/modules/admin/verbs/admingame.dm +++ b/code/modules/admin/verbs/admingame.dm @@ -1,159 +1,150 @@ -// Admin Tab - Game Verbs +ADMIN_VERB_ONLY_CONTEXT_MENU(show_player_panel, R_ADMIN, "Show Player Panel", mob/player in world) + log_admin("[key_name(user)] checked the individual player panel for [key_name(player)][isobserver(user.mob)?"":" while in game"].") -/datum/admins/proc/show_player_panel(mob/M in GLOB.mob_list) - set category = "Admin.Game" - set name = "Show Player Panel" - set desc="Edit player (respawn, ban, heal, etc)" - - if(!check_rights()) - return - - log_admin("[key_name(usr)] checked the individual player panel for [key_name(M)][isobserver(usr)?"":" while in game"].") - - if(!M) - to_chat(usr, span_warning("You seem to be selecting a mob that doesn't exist anymore."), confidential = TRUE) + if(!player) + to_chat(user, span_warning("You seem to be selecting a mob that doesn't exist anymore."), confidential = TRUE) return - var/body = "Options for [M.key]" - body += "Options panel for [M]" - if(M.client) - body += " played by [M.client] " - body += "\[[M.client.holder ? M.client.holder.rank_names() : "Player"]\]" + var/body = "Options for [player.key]" + body += "Options panel for [player]" + if(player.client) + body += " played by [player.client] " + body += "\[[player.client.holder ? player.client.holder.rank_names() : "Player"]\]" if(CONFIG_GET(flag/use_exp_tracking)) - body += "\[" + M.client.get_exp_living(FALSE) + "\]" + body += "\[" + player.client.get_exp_living(FALSE) + "\]" - if(isnewplayer(M)) + if(isnewplayer(player)) body += " Hasn't Entered Game " else - body += " \[Heal\] " + body += " \[Heal\] " - if(M.ckey) - body += "
    \[Find Updated Panel\]" + if(player.ckey) + body += "
    \[Find Updated Panel\]" - if(M.client) - body += "
    \[First Seen: [M.client.player_join_date]\]\[Byond account registered on: [M.client.account_join_date]\]" + if(player.client) + body += "
    \[First Seen: [player.client.player_join_date]\]\[Byond account registered on: [player.client.account_join_date]\]" body += "

    CentCom Galactic Ban DB: " if(CONFIG_GET(string/centcom_ban_db)) - body += "Search" + body += "Search" else body += "Disabled" body += "

    Show related accounts by: " - body += "\[ CID | " - body += "IP \]" + body += "\[ CID | " + body += "IP \]" var/full_version = "Unknown" - if(M.client.byond_version) - full_version = "[M.client.byond_version].[M.client.byond_build ? M.client.byond_build : "xxx"]" + if(player.client.byond_version) + full_version = "[player.client.byond_version].[player.client.byond_build ? player.client.byond_build : "xxx"]" body += "
    \[Byond version: [full_version]\]
    " body += "

    \[ " - body += "VV - " - if(M.mind) - body += "TP - " - body += "SKILLS - " + body += "VV - " + if(player.mind) + body += "TP - " + body += "SKILLS - " else - body += "Init Mind - " - if (iscyborg(M)) - body += "BP - " - body += "PM - " - body += "SM - " - if (ishuman(M) && M.mind) - body += "HM - " - body += "FLW - " + body += "Init Mind - " + if (iscyborg(player)) + body += "BP - " + body += "PM - " + body += "SM - " + if (ishuman(player) && player.mind) + body += "HM - " + body += "FLW - " //Default to client logs if available var/source = LOGSRC_MOB - if(M.ckey) + if(player.ckey) source = LOGSRC_CKEY - body += "LOGS\]
    " + body += "LOGS\]
    " - body += "Mob type = [M.type]

    " + body += "Mob type = [player.type]

    " - if(M.client) + if(player.client) body += "Old names: " - var/datum/player_details/deets = GLOB.player_details[M.ckey] + var/datum/player_details/deets = GLOB.player_details[player.ckey] if(deets) body += deets.get_played_names() else body += "None?!" body += "

    " - body += "Kick | " - if(M.client) - body += "Ban | " + body += "Kick | " + if(player.client) + body += "Ban | " else - body += "Ban | " + body += "Ban | " - body += "Notes | Messages | Watchlist | " - if(M.client) - body += "| Prison | " - body += "\ Send back to Lobby | " - var/muted = M.client.prefs.muted + body += "Notes | Messages | Watchlist | " + if(player.client) + body += "| Prison | " + body += "\ Send back to Lobby | " + var/muted = player.client.prefs.muted body += "
    Mute: " - body += "\[IC | " - body += "OOC | " - body += "PRAY | " - body += "ADMINHELP | " - body += "WEBREQ | " - body += "DEADCHAT\]" - body += "(toggle all)" + body += "\[IC | " + body += "OOC | " + body += "PRAY | " + body += "ADMINHELP | " + body += "WEBREQ | " + body += "DEADCHAT\]" + body += "(toggle all)" body += "

    " - body += "Jump to | " - body += "Get | " - body += "Send To" + body += "Jump to | " + body += "Get | " + body += "Send To" body += "

    " - body += "Traitor panel | " - body += "Narrate to | " - body += "Subtle message | " - body += "Play sound to | " - body += "Language Menu" - - if(M.client) - if(!isnewplayer(M)) + body += "Traitor panel | " + body += "Narrate to | " + body += "Subtle message | " + body += "Play sound to | " + body += "Language Menu" + + if(player.client) + if(!isnewplayer(player)) body += "

    " body += "Transformation:
    " - if(isobserver(M)) + if(isobserver(player)) body += "Ghost | " else - body += "Make Ghost | " + body += "Make Ghost | " - if(ishuman(M) && !ismonkey(M)) + if(ishuman(player) && !ismonkey(player)) body += "Human | " else - body += "Make Human | " + body += "Make Human | " - if(ismonkey(M)) + if(ismonkey(player)) body += "Monkey | " else - body += "Make Monkey | " + body += "Make Monkey | " - if(iscyborg(M)) + if(iscyborg(player)) body += "Cyborg | " else - body += "Make Cyborg | " + body += "Make Cyborg | " - if(isAI(M)) + if(isAI(player)) body += "AI" else - body += "Make AI" + body += "Make AI" body += "

    " body += "Other actions:" body += "
    " - if(!isnewplayer(M)) - body += "Forcesay | " - body += "Apply Client Quirks | " - body += "Thunderdome 1 | " - body += "Thunderdome 2 | " - body += "Thunderdome Admin | " - body += "Thunderdome Observer | " - body += "Commend Behavior | " + if(!isnewplayer(player)) + body += "Forcesay | " + body += "Apply Client Quirks | " + body += "Thunderdome 1 | " + body += "Thunderdome 2 | " + body += "Thunderdome Admin | " + body += "Thunderdome Observer | " + body += "Commend Behavior | " body += "
    " body += "" - usr << browse(body, "window=adminplayeropts-[REF(M)];size=550x515") + user << browse(body, "window=adminplayeropts-[REF(player)];size=550x515") BLACKBOX_LOG_ADMIN_VERB("Player Panel") /client/proc/cmd_admin_godmode(mob/M in GLOB.mob_list) @@ -176,14 +167,8 @@ If a guy was gibbed and you want to revive him, this is a good way to do so. Works kind of like entering the game with a new character. Character receives a new mind if they didn't have one. Traitors and the like can also be revived with the previous role mostly intact. /N */ -/client/proc/respawn_character() - set category = "Admin.Game" - set name = "Respawn Character" - set desc = "Respawn a person that has been gibbed/dusted/killed. They must be a ghost for this to work and preferably should not have a body to go back into." - if(!check_rights(R_ADMIN)) - return - - var/input = ckey(input(src, "Please specify which key will be respawned.", "Key", "")) +ADMIN_VERB(respawn_character, R_ADMIN, "Respawn Character", "Respawn a player that has been round removed in some manner. They must be a ghost.", ADMIN_CATEGORY_GAME) + var/input = ckey(input(user, "Please specify which key will be respawned.", "Key", "")) if(!input) return @@ -194,19 +179,19 @@ Traitors and the like can also be revived with the previous role mostly intact. break if(!G_found)//If a ghost was not found. - to_chat(usr, "There is no active key like that in the game or the person is not currently a ghost.", confidential = TRUE) + to_chat(user, "There is no active key like that in the game or the person is not currently a ghost.", confidential = TRUE) return if(G_found.mind && !G_found.mind.active) //mind isn't currently in use by someone/something //check if they were a monkey if(findtext(G_found.real_name,"monkey")) - if(tgui_alert(usr,"This character appears to have been a monkey. Would you like to respawn them as such?",,list("Yes","No")) == "Yes") + if(tgui_alert(user,"This character appears to have been a monkey. Would you like to respawn them as such?",,list("Yes","No")) == "Yes") var/mob/living/carbon/human/species/monkey/new_monkey = new SSjob.SendToLateJoin(new_monkey) G_found.mind.transfer_to(new_monkey) //be careful when doing stuff like this! I've already checked the mind isn't in use new_monkey.key = G_found.key to_chat(new_monkey, "You have been fully respawned. Enjoy the game.", confidential = TRUE) - var/msg = span_adminnotice("[key_name_admin(usr)] has respawned [new_monkey.key] as a filthy monkey.") + var/msg = span_adminnotice("[key_name_admin(user)] has respawned [new_monkey.key] as a filthy monkey.") message_admins(msg) admin_ticket_log(new_monkey, msg) return //all done. The ghost is auto-deleted @@ -248,7 +233,7 @@ Traitors and the like can also be revived with the previous role mostly intact. */ //Two variables to properly announce later on. - var/admin = key_name_admin(src) + var/admin = key_name_admin(user) var/player_key = G_found.key //Now for special roles and equipment. @@ -303,13 +288,8 @@ Traitors and the like can also be revived with the previous role mostly intact. BLACKBOX_LOG_ADMIN_VERB("Respawn Character") return new_character -/client/proc/cmd_admin_list_open_jobs() - set category = "Admin.Game" - set name = "Manage Job Slots" - - if(!check_rights(R_ADMIN)) - return - holder.manage_free_slots() +ADMIN_VERB(manage_job_slots, R_ADMIN, "Manage Job Slots", "Manage the number of available job slots.", ADMIN_CATEGORY_GAME) + user.holder.manage_free_slots() BLACKBOX_LOG_ADMIN_VERB("Manage Job Slots") /datum/admins/proc/manage_free_slots() @@ -352,38 +332,25 @@ Traitors and the like can also be revived with the previous role mostly intact. browser.set_content(dat.Join()) browser.open() -/client/proc/toggle_view_range() - set category = "Admin.Game" - set name = "Change View Range" - set desc = "switches between 1x and custom views" - - if(view_size.getView() == view_size.default) - view_size.setTo(input("Select view range:", "FUCK YE", 7) in list(1,2,3,4,5,6,7,8,9,10,11,12,13,14,37) - 7) +ADMIN_VERB(toggle_view_range, R_ADMIN, "Change View Range", "Switch between 1x and custom views.", ADMIN_CATEGORY_GAME) + if(user.view_size.getView() == user.view_size.default) + user.view_size.setTo(input(user, "Select view range:", "FUCK YE", 7) in list(1,2,3,4,5,6,7,8,9,10,11,12,13,14,37) - 7) else - view_size.resetToDefault(getScreenSize(prefs.read_preference(/datum/preference/toggle/widescreen))) + user.view_size.resetToDefault(getScreenSize(user.prefs.read_preference(/datum/preference/toggle/widescreen))) - log_admin("[key_name(usr)] changed their view range to [view].") - //message_admins("\blue [key_name_admin(usr)] changed their view range to [view].") //why? removed by order of XSI + log_admin("[key_name(user)] changed their view range to [user.view].") + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Change View Range", "[user.view]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Change View Range", "[view]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! - -/client/proc/toggle_combo_hud() - set category = "Admin.Game" - set name = "Toggle Combo HUD" - set desc = "Toggles the Admin Combo HUD (antag, sci, med, eng)" - - if(!check_rights(R_ADMIN)) - return - - if (combo_hud_enabled) - disable_combo_hud() +ADMIN_VERB(combo_hud, R_ADMIN, "Toggle Combo HUD", "Toggles the Admin Combo HUD.", ADMIN_CATEGORY_GAME) + if(user.combo_hud_enabled) + user.disable_combo_hud() else - enable_combo_hud() + user.enable_combo_hud() - to_chat(usr, "You toggled your admin combo HUD [combo_hud_enabled ? "ON" : "OFF"].", confidential = TRUE) - message_admins("[key_name_admin(usr)] toggled their admin combo HUD [combo_hud_enabled ? "ON" : "OFF"].") - log_admin("[key_name(usr)] toggled their admin combo HUD [combo_hud_enabled ? "ON" : "OFF"].") - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Combo HUD", "[combo_hud_enabled ? "Enabled" : "Disabled"]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! + to_chat(user, "You toggled your admin combo HUD [user.combo_hud_enabled ? "ON" : "OFF"].", confidential = TRUE) + message_admins("[key_name_admin(user)] toggled their admin combo HUD [user.combo_hud_enabled ? "ON" : "OFF"].") + log_admin("[key_name(user)] toggled their admin combo HUD [user.combo_hud_enabled ? "ON" : "OFF"].") + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Combo HUD", "[user.combo_hud_enabled ? "Enabled" : "Disabled"]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! /client/proc/enable_combo_hud() if (combo_hud_enabled) @@ -417,47 +384,31 @@ Traitors and the like can also be revived with the previous role mostly intact. mob.lighting_cutoff = mob.default_lighting_cutoff() mob.update_sight() -/datum/admins/proc/show_traitor_panel(mob/target_mob in GLOB.mob_list) - set category = "Admin.Game" - set desc = "Edit mobs's memory and role" - set name = "Show Traitor Panel" +ADMIN_VERB(show_traitor_panel, R_ADMIN, "Show Traitor Panel", "Edit mobs's memory and role", ADMIN_CATEGORY_GAME, mob/target_mob) var/datum/mind/target_mind = target_mob.mind if(!target_mind) - to_chat(usr, "This mob has no mind!", confidential = TRUE) + to_chat(user, "This mob has no mind!", confidential = TRUE) return if(!istype(target_mob) && !istype(target_mind)) - to_chat(usr, "This can only be used on instances of type /mob and /mind", confidential = TRUE) + to_chat(user, "This can only be used on instances of type /mob and /mind", confidential = TRUE) return target_mind.traitor_panel() BLACKBOX_LOG_ADMIN_VERB("Traitor Panel") -/datum/admins/proc/show_skill_panel(target) - set category = "Admin.Game" - set desc = "Edit mobs's experience and skill levels" - set name = "Show Skill Panel" +ADMIN_VERB(show_skill_panel, R_ADMIN, "Show Skill Panel", "Edit mobs's experience and skill levels", ADMIN_CATEGORY_GAME, mob/target_mob) var/datum/mind/target_mind - if(ismob(target)) - var/mob/target_mob = target - target_mind = target_mob.mind - else if (istype(target, /datum/mind)) - target_mind = target + if(istype(target_mob, /datum/mind)) + target_mind = target_mob else - to_chat(usr, "This can only be used on instances of type /mob and /mind", confidential = TRUE) - return - var/datum/skill_panel/SP = new(usr, target_mind) - SP.ui_interact(usr) + target_mind = target_mob.mind -/datum/admins/proc/show_lag_switch_panel() - set category = "Admin.Game" - set name = "Show Lag Switches" - set desc="Display the controls for drastic lag mitigation measures." + var/datum/skill_panel/SP = new(user, target_mind) + SP.ui_interact(user.mob) +ADMIN_VERB(lag_switch_panel, R_ADMIN, "Show Lag Switches", "Display the controls for drastic lag mitigation.", ADMIN_CATEGORY_GAME) if(!SSlag_switch.initialized) - to_chat(usr, span_notice("The Lag Switch subsystem has not yet been initialized.")) - return - if(!check_rights()) + to_chat(user, span_notice("The Lag Switch subsystem has not yet been initialized.")) return - var/list/dat = list("Lag Switches

    Lag (Reduction) Switches

    ") dat += "Automatic Trigger: [SSlag_switch.auto_switch ? "On" : "Off"]
    " dat += "Population Threshold: [SSlag_switch.trigger_pop]
    " @@ -475,4 +426,4 @@ Traitors and the like can also be revived with the previous role mostly intact. dat += "Disable parallax: [SSlag_switch.measures[DISABLE_PARALLAX] ? "On" : "Off"] - trait applies to character
    " dat += "Disable footsteps: [SSlag_switch.measures[DISABLE_FOOTSTEPS] ? "On" : "Off"] - trait applies to character
    " dat += "" - usr << browse(dat.Join(), "window=lag_switch_panel;size=420x480") + user << browse(dat.Join(), "window=lag_switch_panel;size=420x480") diff --git a/code/modules/admin/verbs/adminjump.dm b/code/modules/admin/verbs/adminjump.dm index dfcc5f60dd0c4..155839942c961 100644 --- a/code/modules/admin/verbs/adminjump.dm +++ b/code/modules/admin/verbs/adminjump.dm @@ -1,114 +1,75 @@ -/client/proc/jumptoarea(area/A in get_sorted_areas()) - set name = "Jump to Area" - set desc = "Area to jump to" - set category = "Admin.Game" - if(!src.holder) - to_chat(src, "Only administrators may use this command.", confidential = TRUE) - return +ADMIN_VERB(jump_to_area, R_ADMIN, "Jump To Area", "Jumps to the specified area.", ADMIN_CATEGORY_GAME, area/target in world) + if(!isobserver(user.mob)) + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/admin_ghost) - if(!A) - return + var/turf/drop_location + top_level: + for(var/list/zlevel_turfs as anything in target.get_zlevel_turf_lists()) + for(var/turf/area_turf as anything in zlevel_turfs) + drop_location = area_turf + break top_level - var/list/turfs = list() - for (var/list/zlevel_turfs as anything in A.get_zlevel_turf_lists()) - for (var/turf/area_turf as anything in zlevel_turfs) - if(!area_turf.density) - turfs.Add(area_turf) - - if(length(turfs)) - var/turf/T = pick(turfs) - usr.forceMove(T) - log_admin("[key_name(usr)] jumped to [AREACOORD(T)]") - message_admins("[key_name_admin(usr)] jumped to [AREACOORD(T)]") - BLACKBOX_LOG_ADMIN_VERB("Jump To Area") - else - to_chat(src, "Nowhere to jump to!", confidential = TRUE) + if(isnull(drop_location)) + to_chat(user, span_warning("No valid drop location found in the area!")) return + user.mob.abstract_move(drop_location) + log_admin("[key_name(user)] jumped to [AREACOORD(drop_location)]") + message_admins("[key_name_admin(user)] jumped to [AREACOORD(drop_location)]") + BLACKBOX_LOG_ADMIN_VERB("Jump To Area") -/client/proc/jumptoturf(turf/T in world) - set name = "Jump to Turf" - set category = "Admin.Game" - if(!src.holder) - to_chat(src, "Only administrators may use this command.", confidential = TRUE) - return +ADMIN_VERB(jump_to_turf, R_ADMIN, "Jump To Turf", "Jump to any turf in the game. This will lag your client.", ADMIN_CATEGORY_GAME, turf/locale in world) + if(!isobserver(user.mob)) + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/admin_ghost) - log_admin("[key_name(usr)] jumped to [AREACOORD(T)]") - message_admins("[key_name_admin(usr)] jumped to [AREACOORD(T)]") - usr.forceMove(T) + log_admin("[key_name(user)] jumped to [AREACOORD(locale)]") + message_admins("[key_name_admin(user)] jumped to [AREACOORD(locale)]") + user.mob.abstract_move(locale) BLACKBOX_LOG_ADMIN_VERB("Jump To Turf") - return -/client/proc/jumptomob(mob/M in GLOB.mob_list) - set category = "Admin.Game" - set name = "Jump to Mob" +ADMIN_VERB(jump_to_mob, R_ADMIN, "Jump To Mob", "Jump to any mob in the game.", ADMIN_CATEGORY_GAME, mob/target in world) + if(!isobserver(user.mob)) + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/admin_ghost) + user.mob.abstract_move(target.loc) + log_admin("[key_name(user)] jumped to [key_name(target)]") + message_admins("[key_name_admin(user)] jumped to [ADMIN_LOOKUPFLW(target)] at [AREACOORD(target)]") + BLACKBOX_LOG_ADMIN_VERB("Jump To Mob") - if(!src.holder) - to_chat(src, "Only administrators may use this command.", confidential = TRUE) - return +ADMIN_VERB(jump_to_coord, R_ADMIN, "Jump To Coordinate", "Jump to a specific coordinate in the game world.", ADMIN_CATEGORY_GAME, cx as num, cy as num, cz as num) + if(!isobserver(user.mob)) + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/admin_ghost) - log_admin("[key_name(usr)] jumped to [key_name(M)]") - message_admins("[key_name_admin(usr)] jumped to [ADMIN_LOOKUPFLW(M)] at [AREACOORD(M)]") - if(src.mob) - var/mob/A = src.mob - var/turf/T = get_turf(M) - if(T && isturf(T)) - BLACKBOX_LOG_ADMIN_VERB("Jump To Mob") - A.forceMove(M.loc) - else - to_chat(A, "This mob is not located in the game world.", confidential = TRUE) - -/client/proc/jumptocoord(tx as num, ty as num, tz as num) - set category = "Admin.Game" - set name = "Jump to Coordinate" - - if (!holder) - to_chat(src, "Only administrators may use this command.", confidential = TRUE) + var/turf/where_we_droppin = locate(cx, cy, cz) + if(isnull(where_we_droppin)) + to_chat(user, span_warning("Invalid coordinates.")) return - if(src.mob) - var/mob/A = src.mob - var/turf/T = locate(tx,ty,tz) - A.forceMove(T) - BLACKBOX_LOG_ADMIN_VERB("Jump To Coordiate") - message_admins("[key_name_admin(usr)] jumped to coordinates [tx], [ty], [tz]") + user.mob.abstract_move(where_we_droppin) + message_admins("[key_name_admin(user)] jumped to coordinates [cx], [cy], [cz]") + BLACKBOX_LOG_ADMIN_VERB("Jump To Coordiate") -/client/proc/jumptokey() - set category = "Admin.Game" - set name = "Jump to Key" - - if(!src.holder) - to_chat(src, "Only administrators may use this command.", confidential = TRUE) - return +ADMIN_VERB(jump_to_key, R_ADMIN, "Jump To Key", "Jump to a specific player.", ADMIN_CATEGORY_GAME) + if(!isobserver(user.mob)) + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/admin_ghost) var/list/keys = list() for(var/mob/M in GLOB.player_list) keys += M.client - var/client/selection = input("Please, select a player!", "Admin Jumping", null, null) as null|anything in sort_key(keys) + var/client/selection = input(user, "Please, select a player!", "Admin Jumping") as null|anything in sort_key(keys) if(!selection) - to_chat(src, "No keys found.", confidential = TRUE) + to_chat(user, "No keys found.", confidential = TRUE) return var/mob/M = selection.mob - log_admin("[key_name(usr)] jumped to [key_name(M)]") - message_admins("[key_name_admin(usr)] jumped to [ADMIN_LOOKUPFLW(M)]") - - usr.forceMove(M.loc) - + log_admin("[key_name(user)] jumped to [key_name(M)]") + message_admins("[key_name_admin(user)] jumped to [ADMIN_LOOKUPFLW(M)]") + user.mob.abstract_move(M.loc) BLACKBOX_LOG_ADMIN_VERB("Jump To Key") -/client/proc/Getmob(mob/M in GLOB.mob_list - GLOB.dummy_mob_list) - set category = "Admin.Game" - set name = "Get Mob" - set desc = "Mob to teleport" - if(!src.holder) - to_chat(src, "Only administrators may use this command.", confidential = TRUE) - return - - var/atom/loc = get_turf(usr) - M.admin_teleport(loc) +ADMIN_VERB_AND_CONTEXT_MENU(get_mob, R_ADMIN, "Get Mob", "Teleport a mob to your location.", ADMIN_CATEGORY_GAME, mob/target in world) + var/atom/loc = get_turf(user.mob) + target.admin_teleport(loc) BLACKBOX_LOG_ADMIN_VERB("Get Mob") - /// Proc to hook user-enacted teleporting behavior and keep logging of the event. /atom/movable/proc/admin_teleport(atom/new_location) if(isnull(new_location)) @@ -126,56 +87,41 @@ admin_ticket_log(src, msg) return ..() - -/client/proc/Getkey() - set category = "Admin.Game" - set name = "Get Key" - set desc = "Key to teleport" - - if(!src.holder) - to_chat(src, "Only administrators may use this command.", confidential = TRUE) - return - +ADMIN_VERB(get_key, R_ADMIN, "Get Key", "Teleport the player with the provided key to you.", ADMIN_CATEGORY_GAME) var/list/keys = list() for(var/mob/M in GLOB.player_list) keys += M.client - var/client/selection = input("Please, select a player!", "Admin Jumping", null, null) as null|anything in sort_key(keys) + var/client/selection = input(user, "Please, select a player!", "Admin Jumping") as null|anything in sort_key(keys) if(!selection) return var/mob/M = selection.mob if(!M) return - log_admin("[key_name(usr)] teleported [key_name(M)]") - var/msg = "[key_name_admin(usr)] teleported [ADMIN_LOOKUPFLW(M)]" + log_admin("[key_name(user)] teleported [key_name(M)]") + var/msg = "[key_name_admin(user)] teleported [ADMIN_LOOKUPFLW(M)]" message_admins(msg) admin_ticket_log(M, msg) if(M) - M.forceMove(get_turf(usr)) - usr.forceMove(M.loc) + M.forceMove(get_turf(user)) BLACKBOX_LOG_ADMIN_VERB("Get Key") -/client/proc/sendmob(mob/jumper in sort_mobs()) - set category = "Admin.Game" - set name = "Send Mob" - if(!src.holder) - to_chat(src, "Only administrators may use this command.", confidential = TRUE) - return +ADMIN_VERB(send_mob, R_ADMIN, "Send Mob", "Teleport the specified mob to an area of your choosing.", ADMIN_CATEGORY_GAME, mob/jumper) var/list/sorted_areas = get_sorted_areas() if(!length(sorted_areas)) - to_chat(src, "No areas found.", confidential = TRUE) + to_chat(user, "No areas found.", confidential = TRUE) return - var/area/target_area = tgui_input_list(src, "Pick an area", "Send Mob", sorted_areas) + var/area/target_area = tgui_input_list(user, "Pick an area", "Send Mob", sorted_areas) if(isnull(target_area)) return if(!istype(target_area)) return var/list/turfs = get_area_turfs(target_area) if(length(turfs) && jumper.forceMove(pick(turfs))) - log_admin("[key_name(usr)] teleported [key_name(jumper)] to [AREACOORD(jumper)]") - var/msg = "[key_name_admin(usr)] teleported [ADMIN_LOOKUPFLW(jumper)] to [AREACOORD(jumper)]" + log_admin("[key_name(user)] teleported [key_name(jumper)] to [AREACOORD(jumper)]") + var/msg = "[key_name_admin(user)] teleported [ADMIN_LOOKUPFLW(jumper)] to [AREACOORD(jumper)]" message_admins(msg) admin_ticket_log(jumper, msg) else - to_chat(src, "Failed to move mob to a valid location.", confidential = TRUE) + to_chat(user, "Failed to move mob to a valid location.", confidential = TRUE) BLACKBOX_LOG_ADMIN_VERB("Send Mob") diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm index d5157decf4cba..0e8053c7ab06e 100644 --- a/code/modules/admin/verbs/adminpm.dm +++ b/code/modules/admin/verbs/adminpm.dm @@ -13,36 +13,19 @@ // We also make SURE to fail loud, IE: if something stops the message from reaching the recipient, the sender HAS to know // If you "refactor" this to make it "cleaner" I will send you to hell -/// Allows right clicking mobs to send an admin PM to their client, forwards the selected mob's client to cmd_admin_pm -/client/proc/cmd_admin_pm_context(mob/M in GLOB.mob_list) - set category = null - set name = "Admin PM Mob" - if(!holder) - to_chat(src, - type = MESSAGE_TYPE_ADMINPM, - html = span_danger("Error: Admin-PM-Context: Only administrators may use this command."), - confidential = TRUE) - return - if(!ismob(M)) - to_chat(src, +ADMIN_VERB_ONLY_CONTEXT_MENU(cmd_admin_pm_context, R_NONE, "Admin PM Mob", mob/target in world) + if(!ismob(target)) + to_chat( + src, type = MESSAGE_TYPE_ADMINPM, html = span_danger("Error: Admin-PM-Context: Target mob is not a mob, somehow."), - confidential = TRUE) + confidential = TRUE, + ) return - cmd_admin_pm(M.client, null) + user.cmd_admin_pm(target.client, null) BLACKBOX_LOG_ADMIN_VERB("Admin PM Mob") -/// Shows a list of clients we could send PMs to, then forwards our choice to cmd_admin_pm -/client/proc/cmd_admin_pm_panel() - set category = "Admin" - set name = "Admin PM" - if(!holder) - to_chat(src, - type = MESSAGE_TYPE_ADMINPM, - html = span_danger("Error: Admin-PM-Panel: Only administrators may use this command."), - confidential = TRUE) - return - +ADMIN_VERB(cmd_admin_pm_panel, R_NONE, "Admin PM", "Show a list of clients to PM", ADMIN_CATEGORY_MAIN) var/list/targets = list() for(var/client/client in GLOB.clients) var/nametag = "" @@ -62,7 +45,7 @@ var/target = input(src,"To whom shall we send a message?", "Admin PM", null) as null|anything in sort_list(targets) if (isnull(target)) return - cmd_admin_pm(targets[target], null) + user.cmd_admin_pm(targets[target], null) BLACKBOX_LOG_ADMIN_VERB("Admin PM") /// Replys to some existing ahelp, reply to whom, which can be a client or ckey diff --git a/code/modules/admin/verbs/adminsay.dm b/code/modules/admin/verbs/adminsay.dm index 0ea8a7ceb76fe..595993466d2b6 100644 --- a/code/modules/admin/verbs/adminsay.dm +++ b/code/modules/admin/verbs/adminsay.dm @@ -1,18 +1,12 @@ -/client/proc/cmd_admin_say(msg as text) - set category = "Admin" - set name = "Asay" //Gave this shit a shorter name so you only have to time out "asay" rather than "admin say" to use it --NeoFite - set hidden = TRUE - if(!check_rights(0)) +ADMIN_VERB(cmd_admin_say, R_NONE, "ASay", "Send a message to other admins", ADMIN_CATEGORY_MAIN, message as text) + message = emoji_parse(copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN)) + if(!message) return - msg = emoji_parse(copytext_char(sanitize(msg), 1, MAX_MESSAGE_LEN)) - if(!msg) - return - - if(findtext(msg, "@") || findtext(msg, "#")) - var/list/link_results = check_asay_links(msg) + if(findtext(message, "@") || findtext(message, "#")) + var/list/link_results = check_asay_links(message) if(length(link_results)) - msg = link_results[ASAY_LINK_NEW_MESSAGE_INDEX] + message = link_results[ASAY_LINK_NEW_MESSAGE_INDEX] link_results[ASAY_LINK_NEW_MESSAGE_INDEX] = null var/list/pinged_admin_clients = link_results[ASAY_LINK_PINGED_ADMINS_INDEX] for(var/iter_ckey in pinged_admin_clients) @@ -22,18 +16,18 @@ window_flash(iter_admin_client) SEND_SOUND(iter_admin_client.mob, sound('sound/misc/asay_ping.ogg')) - mob.log_talk(msg, LOG_ASAY) - msg = keywords_lookup(msg) - var/asay_color = prefs.read_preference(/datum/preference/color/asay_color) + user.mob.log_talk(message, LOG_ASAY) + message = keywords_lookup(message) + var/asay_color = user.prefs.read_preference(/datum/preference/color/asay_color) var/custom_asay_color = (CONFIG_GET(flag/allow_admin_asaycolor) && asay_color) ? "" : "" - msg = "[span_adminsay("[span_prefix("ADMIN:")] [key_name(usr, 1)] [ADMIN_FLW(mob)]: [custom_asay_color][msg]")][custom_asay_color ? "":null]" + message = "[span_adminsay("[span_prefix("ADMIN:")] [key_name_admin(user)] [ADMIN_FLW(user.mob)]: [custom_asay_color][message]")][custom_asay_color ? "":null]" to_chat(GLOB.admins, type = MESSAGE_TYPE_ADMINCHAT, - html = msg, + html = message, confidential = TRUE) BLACKBOX_LOG_ADMIN_VERB("Asay") /client/proc/get_admin_say() var/msg = input(src, null, "asay \"text\"") as text|null - cmd_admin_say(msg) + SSadmin_verbs.dynamic_invoke_verb(src, /datum/admin_verb/cmd_admin_say, msg) diff --git a/code/modules/admin/verbs/atmosdebug.dm b/code/modules/admin/verbs/atmosdebug.dm index 2e73a9955f747..9f744ff014749 100644 --- a/code/modules/admin/verbs/atmosdebug.dm +++ b/code/modules/admin/verbs/atmosdebug.dm @@ -1,35 +1,27 @@ -/client/proc/atmosscan() - set category = "Mapping" - set name = "Check Plumbing" - if(!src.holder) - to_chat(src, "Only administrators may use this command.", confidential = TRUE) - return +ADMIN_VERB_VISIBILITY(atmos_debug, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(atmos_debug, R_DEBUG, "Check Plumbing", "Verifies the integrity of the plumbing network.", ADMIN_CATEGORY_MAPPING) BLACKBOX_LOG_ADMIN_VERB("Check Plumbing") //all plumbing - yes, some things might get stated twice, doesn't matter. for(var/obj/machinery/atmospherics/components/pipe as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/atmospherics/components)) if(pipe.z && (!pipe.nodes || !pipe.nodes.len || (null in pipe.nodes))) - to_chat(usr, "Unconnected [pipe.name] located at [ADMIN_VERBOSEJMP(pipe)]", confidential = TRUE) + to_chat(user, "Unconnected [pipe.name] located at [ADMIN_VERBOSEJMP(pipe)]", confidential = TRUE) //Pipes for(var/obj/machinery/atmospherics/pipe/pipe as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/atmospherics/pipe)) if(istype(pipe, /obj/machinery/atmospherics/pipe/smart) || istype(pipe, /obj/machinery/atmospherics/pipe/layer_manifold)) continue if(pipe.z && (!pipe.nodes || !pipe.nodes.len || (null in pipe.nodes))) - to_chat(usr, "Unconnected [pipe.name] located at [ADMIN_VERBOSEJMP(pipe)]", confidential = TRUE) + to_chat(user, "Unconnected [pipe.name] located at [ADMIN_VERBOSEJMP(pipe)]", confidential = TRUE) //Nodes for(var/obj/machinery/atmospherics/node1 as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/atmospherics)) for(var/obj/machinery/atmospherics/node2 in node1.nodes) if(!(node1 in node2.nodes)) - to_chat(usr, "One-way connection in [node1.name] located at [ADMIN_VERBOSEJMP(node1)]", confidential = TRUE) + to_chat(user, "One-way connection in [node1.name] located at [ADMIN_VERBOSEJMP(node1)]", confidential = TRUE) -/client/proc/powerdebug() - set category = "Mapping" - set name = "Check Power" - if(!src.holder) - to_chat(src, "Only administrators may use this command.", confidential = TRUE) - return +ADMIN_VERB_VISIBILITY(power_debug, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(power_debug, R_DEBUG, "Check Power", "Verifies the integrity of the power network.", ADMIN_CATEGORY_MAPPING) BLACKBOX_LOG_ADMIN_VERB("Check Power") var/list/results = list() @@ -56,4 +48,4 @@ var/obj/structure/cable/C = locate(/obj/structure/cable) in T.contents if(!C) results += "Unwired terminal at [ADMIN_VERBOSEJMP(term)]" - to_chat(usr, "[results.Join("\n")]", confidential = TRUE) + to_chat(user, "[results.Join("\n")]", confidential = TRUE) diff --git a/code/modules/admin/verbs/beakerpanel.dm b/code/modules/admin/verbs/beakerpanel.dm index 5ba32ae7b6ce0..7088fba92f128 100644 --- a/code/modules/admin/verbs/beakerpanel.dm +++ b/code/modules/admin/verbs/beakerpanel.dm @@ -60,14 +60,11 @@ reagents.add_reagent(reagenttype, amount) return container -/datum/admins/proc/beaker_panel() - set category = "Admin.Events" - set name = "Spawn reagent container" - if(!check_rights()) - return +ADMIN_VERB(beaker_panel, R_SPAWN, "Spawn Reagent Container", "Spawn a reagent container.", ADMIN_CATEGORY_EVENTS) var/datum/asset/asset_datum = get_asset_datum(/datum/asset/simple/namespaced/common) - asset_datum.send(usr) + asset_datum.send(user) //Could somebody tell me why this isn't using the browser datum, given that it copypastes all of browser datum's html + // fuck if I know, but im not touching it var/dat = {" @@ -320,4 +317,4 @@ "} - usr << browse(dat, "window=beakerpanel;size=1100x720") + user << browse(dat, "window=beakerpanel;size=1100x720") diff --git a/code/modules/admin/verbs/borgpanel.dm b/code/modules/admin/verbs/borgpanel.dm index b8fd3698a563e..6a8e1efdb5656 100644 --- a/code/modules/admin/verbs/borgpanel.dm +++ b/code/modules/admin/verbs/borgpanel.dm @@ -1,21 +1,6 @@ -/datum/admins/proc/open_borgopanel(borgo in GLOB.silicon_mobs) - set category = "Admin.Game" - set name = "Show Borg Panel" - set desc = "Show borg panel" - - if(!check_rights(R_ADMIN)) - return - - if (!iscyborg(borgo)) - borgo = input("Select a borg", "Select a borg", null, null) as null|anything in sort_names(GLOB.silicon_mobs) - if (!iscyborg(borgo)) - to_chat(usr, span_warning("Borg is required for borgpanel"), confidential = TRUE) - - var/datum/borgpanel/borgpanel = new(usr, borgo) - - borgpanel.ui_interact(usr) - - +ADMIN_VERB(borg_panel, R_ADMIN, "Show Borg Panel", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/living/silicon/robot/borgo) + var/datum/borgpanel/borgpanel = new(user.mob, borgo) + borgpanel.ui_interact(user.mob) /datum/borgpanel var/mob/living/silicon/robot/borg diff --git a/code/modules/admin/verbs/change_shuttle_events.dm b/code/modules/admin/verbs/change_shuttle_events.dm index 4ec8a7cd7b83a..90f7e03672e73 100644 --- a/code/modules/admin/verbs/change_shuttle_events.dm +++ b/code/modules/admin/verbs/change_shuttle_events.dm @@ -1,20 +1,9 @@ -///Manipulate the events that are gonna run/are running on the escape shuttle -/datum/admins/proc/change_shuttle_events() - set category = "Admin.Events" - set name = "Change Shuttle Events" - set desc = "Allows you to change the events on a shuttle." - - if (!istype(src, /datum/admins)) - src = usr.client.holder - if (!istype(src, /datum/admins)) - to_chat(usr, "Error: you are not an admin!", confidential = TRUE) - return - +ADMIN_VERB(change_shuttle_events, R_ADMIN|R_FUN, "Change Shuttle Events", "Change the events on a shuttle.", ADMIN_CATEGORY_EVENTS) //At least for now, just letting admins modify the emergency shuttle is fine var/obj/docking_port/mobile/port = SSshuttle.emergency if(!port) - to_chat(usr, span_admin("Uh oh, couldn't find the escape shuttle!")) + to_chat(user, span_admin("Uh oh, couldn't find the escape shuttle!")) var/list/options = list("Clear"="Clear") @@ -27,16 +16,16 @@ options[((event in active) ? "(Remove)" : "(Add)") + initial(event.name)] = event //Throw up an ugly menu with the shuttle events and the options to add or remove them, or clear them all - var/result = input(usr, "Choose an event to add/remove", "Shuttle Events") as null|anything in sort_list(options) + var/result = input(user, "Choose an event to add/remove", "Shuttle Events") as null|anything in sort_list(options) if(result == "Clear") port.event_list.Cut() - message_admins("[key_name_admin(usr)] has cleared the shuttle events on: [port]") + message_admins("[key_name_admin(user)] has cleared the shuttle events on: [port]") else if(options[result]) var/typepath = options[result] if(typepath in active) port.event_list.Remove(active[options[result]]) - message_admins("[key_name_admin(usr)] has removed '[active[result]]' from [port].") + message_admins("[key_name_admin(user)] has removed '[active[result]]' from [port].") else port.event_list.Add(new typepath (port)) - message_admins("[key_name_admin(usr)] has added '[typepath]' to [port].") + message_admins("[key_name_admin(user)] has added '[typepath]' to [port].") diff --git a/code/modules/admin/verbs/cinematic.dm b/code/modules/admin/verbs/cinematic.dm index b001099d28340..f9e96c89cd076 100644 --- a/code/modules/admin/verbs/cinematic.dm +++ b/code/modules/admin/verbs/cinematic.dm @@ -1,14 +1,10 @@ -/client/proc/cinematic() - set name = "Cinematic" - set category = "Admin.Fun" - set desc = "Shows a cinematic." // Intended for testing but I thought it might be nice for events on the rare occasion Feel free to comment it out if it's not wanted. - set hidden = TRUE - - if(!SSticker) - return - - var/datum/cinematic/choice = tgui_input_list(usr, "Chose a cinematic to play to everyone in the server.", "Choose Cinematic", sort_list(subtypesof(/datum/cinematic), GLOBAL_PROC_REF(cmp_typepaths_asc))) +ADMIN_VERB(cinematic, R_FUN, "Cinematic", "Show a cinematic to all players.", ADMIN_CATEGORY_FUN) + var/datum/cinematic/choice = tgui_input_list( + user, + "Chose a cinematic to play to everyone in the server.", + "Choose Cinematic", + sort_list(subtypesof(/datum/cinematic), GLOBAL_PROC_REF(cmp_typepaths_asc)), + ) if(!choice || !ispath(choice, /datum/cinematic)) return - play_cinematic(choice, world) diff --git a/code/modules/admin/verbs/commandreport.dm b/code/modules/admin/verbs/commandreport.dm index 86e7ec1328b47..047ef04a0b7ce 100644 --- a/code/modules/admin/verbs/commandreport.dm +++ b/code/modules/admin/verbs/commandreport.dm @@ -7,32 +7,19 @@ #define WIZARD_PRESET "The Wizard Federation" #define CUSTOM_PRESET "Custom Command Name" -/// Verb to change the global command name. -/client/proc/cmd_change_command_name() - set category = "Admin.Events" - set name = "Change Command Name" - - if(!check_rights(R_ADMIN)) - return - - var/input = input(usr, "Please input a new name for Central Command.", "What?", "") as text|null +ADMIN_VERB(change_command_name, R_ADMIN, "Change Command Name", "Change the name of Central Command.", ADMIN_CATEGORY_EVENTS) + var/input = input(user, "Please input a new name for Central Command.", "What?", "") as text|null if(!input) return change_command_name(input) - message_admins("[key_name_admin(src)] has changed Central Command's name to [input]") - log_admin("[key_name(src)] has changed the Central Command name to: [input]") + message_admins("[key_name_admin(user)] has changed Central Command's name to [input]") + log_admin("[key_name(user)] has changed the Central Command name to: [input]") /// Verb to open the create command report window and send command reports. -/client/proc/cmd_admin_create_centcom_report() - set category = "Admin.Events" - set name = "Create Command Report" - - if(!check_rights(R_ADMIN)) - return - +ADMIN_VERB(create_command_report, R_ADMIN, "Create Command Report", "Create a command report to be sent to the station.", ADMIN_CATEGORY_EVENTS) BLACKBOX_LOG_ADMIN_VERB("Create Command Report") - var/datum/command_report_menu/tgui = new(usr) - tgui.ui_interact(usr) + var/datum/command_report_menu/tgui = new /datum/command_report_menu(user.mob) + tgui.ui_interact(user.mob) /// Datum for holding the TGUI window for command reports. /datum/command_report_menu diff --git a/code/modules/admin/verbs/config_helpers.dm b/code/modules/admin/verbs/config_helpers.dm index 013c7b63f8a48..c043274d4277f 100644 --- a/code/modules/admin/verbs/config_helpers.dm +++ b/code/modules/admin/verbs/config_helpers.dm @@ -1,19 +1,14 @@ -/// Verbs created to help server operators with generating certain config files. +#define GENERATE_JOB_CONFIG_VERB_DESC "Generate a job configuration (jobconfig.toml) file for the server. If TOML file already exists, will re-generate it based off the already existing config values. Will migrate from the old jobs.txt format if necessary." -/client/proc/generate_job_config() - set name = "Generate Job Configuration" - set category = "Server" - set desc = "Generate a job configuration (jobconfig.toml) file for the server. If TOML file already exists, will re-generate it based off the already existing config values. Will migrate from the old jobs.txt format if necessary." - - if(!check_rights(R_SERVER)) - return - - if(tgui_alert(usr, "This verb is not at all useful if you are not a server operator with access to the configuration folder. Do you wish to proceed?", "Generate jobconfig.toml for download", list("Yes", "No")) != "Yes") +ADMIN_VERB(generate_job_config, R_SERVER, "Generate Job Configuration", GENERATE_JOB_CONFIG_VERB_DESC, ADMIN_CATEGORY_SERVER) + if(tgui_alert(user, "This verb is not at all useful if you are not a server operator with access to the configuration folder. Do you wish to proceed?", "Generate jobconfig.toml for download", list("Yes", "No")) != "Yes") return - if(SSjob.generate_config(usr)) - to_chat(usr, span_notice("Job configuration file generated. Download prompt should appear now.")) + if(SSjob.generate_config(user)) + to_chat(user, span_notice("Job configuration file generated. Download prompt should appear now.")) else - to_chat(usr, span_warning("Job configuration file could not be generated. Check the server logs / runtimes / above warning messages for more information.")) + to_chat(user, span_warning("Job configuration file could not be generated. Check the server logs / runtimes / above warning messages for more information.")) BLACKBOX_LOG_ADMIN_VERB("Generate Job Configuration") + +#undef GENERATE_JOB_CONFIG_VERB_DESC diff --git a/code/modules/admin/verbs/deadsay.dm b/code/modules/admin/verbs/deadsay.dm index 032a4d4fa482b..c330618d8b4cd 100644 --- a/code/modules/admin/verbs/deadsay.dm +++ b/code/modules/admin/verbs/deadsay.dm @@ -1,39 +1,30 @@ -/client/proc/dsay(msg as text) - set category = "Admin.Game" - set name = "Dsay" - set hidden = TRUE - if(!holder) - to_chat(src, "Only administrators may use this command.", confidential = TRUE) - return - if(!mob) - return - if(prefs.muted & MUTE_DEADCHAT) - to_chat(src, span_danger("You cannot send DSAY messages (muted)."), confidential = TRUE) + +ADMIN_VERB(dsay, R_NONE, "DSay", "Speak to the dead.", ADMIN_CATEGORY_GAME, message as text) + if(user.prefs.muted & MUTE_DEADCHAT) + to_chat(user, span_danger("You cannot send DSAY messages (muted)."), confidential = TRUE) return - if (handle_spam_prevention(msg,MUTE_DEADCHAT)) + if (user.handle_spam_prevention(message,MUTE_DEADCHAT)) return - msg = copytext_char(sanitize(msg), 1, MAX_MESSAGE_LEN) - mob.log_talk(msg, LOG_DSAY) + message = copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN) + user.mob.log_talk(message, LOG_DSAY) - if (!msg) + if (!message) return - var/rank_name = holder.rank_names() - var/admin_name = key - if(holder.fakekey) + var/rank_name = user.holder.rank_names() + var/admin_name = user.key + if(user.holder.fakekey) rank_name = pick(strings("admin_nicknames.json", "ranks", "config")) admin_name = pick(strings("admin_nicknames.json", "names", "config")) var/name_and_rank = "[span_tooltip(rank_name, "STAFF")] ([admin_name])" - deadchat_broadcast("[span_prefix("DEAD:")] [name_and_rank] says, \"[emoji_parse(msg)]\"") + deadchat_broadcast("[span_prefix("DEAD:")] [name_and_rank] says, \"[emoji_parse(message)]\"") BLACKBOX_LOG_ADMIN_VERB("Dsay") /client/proc/get_dead_say() var/msg = input(src, null, "dsay \"text\"") as text|null - if (isnull(msg)) return - - dsay(msg) + SSadmin_verbs.dynamic_invoke_verb(src, /datum/admin_verb/dsay, msg) diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 35b1baa063d57..e56eb1e5101a7 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -1,40 +1,27 @@ -/client/proc/Debug2() - set category = "Debug" - set name = "Debug-Game" - if(!check_rights(R_DEBUG)) - return - - if(GLOB.Debug2) - GLOB.Debug2 = 0 - message_admins("[key_name(src)] toggled debugging off.") - log_admin("[key_name(src)] toggled debugging off.") - else - GLOB.Debug2 = 1 - message_admins("[key_name(src)] toggled debugging on.") - log_admin("[key_name(src)] toggled debugging on.") - +ADMIN_VERB(toggle_game_debug, R_DEBUG, "Debug-Game", "Toggles game debugging.", ADMIN_CATEGORY_DEBUG) + GLOB.Debug2 = !GLOB.Debug2 + var/message = "toggled debugging [(GLOB.Debug2 ? "ON" : "OFF")]" + message_admins("[key_name_admin(user)] [message].") + log_admin("[key_name(user)] [message].") BLACKBOX_LOG_ADMIN_VERB("Toggle Debug Two") -/client/proc/Cell() - set category = "Debug" - set name = "Air Status in Location" - if(!mob) - return - var/turf/T = get_turf(mob) - if(!isturf(T)) +ADMIN_VERB_VISIBILITY(air_status, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(air_status, R_DEBUG, "Air Status In Location", "Gets the air status for your current turf.", ADMIN_CATEGORY_DEBUG) + var/turf/user_turf = get_turf(user.mob) + if(!isturf(user_turf)) return - atmos_scan(user=usr, target=T, silent=TRUE) + atmos_scan(user.mob, user_turf, silent = TRUE) BLACKBOX_LOG_ADMIN_VERB("Air Status In Location") -/client/proc/cmd_admin_robotize(mob/M in GLOB.mob_list) - set category = "Admin.Fun" - set name = "Make Cyborg" - +ADMIN_VERB(cmd_admin_robotize, R_FUN, "Make Cyborg", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/target) if(!SSticker.HasRoundStarted()) - tgui_alert(usr,"Wait until the game starts") + tgui_alert(user, "Wait until the game starts") + return + if(issilicon(target)) + tgui_alert(user, "They are already a cyborg.") return - log_admin("[key_name(src)] has robotized [M.key].") - INVOKE_ASYNC(M, TYPE_PROC_REF(/mob, Robotize)) + log_admin("[key_name(user)] has robotized [target.key].") + INVOKE_ASYNC(target, TYPE_PROC_REF(/mob, Robotize)) /client/proc/poll_type_to_del(search_string) var/list/types = get_fancy_list_of_atom_types() @@ -50,13 +37,8 @@ return return types[key] -//TODO: merge the vievars version into this or something maybe mayhaps -/client/proc/cmd_debug_del_all(object as text) - set category = "Debug" - set name = "Del-All" - - var/type_to_del = poll_type_to_del(object) - +ADMIN_VERB(cmd_del_all, R_DEBUG|R_SPAWN, "Del-All", "Delete all datums with the specified type.", ADMIN_CATEGORY_DEBUG, object as text) + var/type_to_del = user.poll_type_to_del(object) if(!type_to_del) return @@ -66,16 +48,12 @@ counter++ qdel(O) CHECK_TICK - log_admin("[key_name(src)] has deleted all ([counter]) instances of [type_to_del].") - message_admins("[key_name_admin(src)] has deleted all ([counter]) instances of [type_to_del].") + log_admin("[key_name(user)] has deleted all ([counter]) instances of [type_to_del].") + message_admins("[key_name_admin(user)] has deleted all ([counter]) instances of [type_to_del].") BLACKBOX_LOG_ADMIN_VERB("Delete All") -/client/proc/cmd_debug_force_del_all(object as text) - set category = "Debug" - set name = "Force-Del-All" - - var/type_to_del = poll_type_to_del(object) - +ADMIN_VERB(cmd_del_all_force, R_DEBUG|R_SPAWN, "Force-Del-All", "Forcibly delete all datums with the specified type.", ADMIN_CATEGORY_DEBUG, object as text) + var/type_to_del = user.poll_type_to_del(object) if(!type_to_del) return @@ -85,29 +63,25 @@ counter++ qdel(O, force = TRUE) CHECK_TICK - log_admin("[key_name(src)] has force-deleted all ([counter]) instances of [type_to_del].") - message_admins("[key_name_admin(src)] has force-deleted all ([counter]) instances of [type_to_del].") + log_admin("[key_name(user)] has force-deleted all ([counter]) instances of [type_to_del].") + message_admins("[key_name_admin(user)] has force-deleted all ([counter]) instances of [type_to_del].") BLACKBOX_LOG_ADMIN_VERB("Force-Delete All") -/client/proc/cmd_debug_hard_del_all(object as text) - set category = "Debug" - set name = "Hard-Del-All" - - var/type_to_del = poll_type_to_del(object) - +ADMIN_VERB(cmd_del_all_hard, R_DEBUG|R_SPAWN, "Hard-Del-All", "Hard delete all datums with the specified type.", ADMIN_CATEGORY_DEBUG, object as text) + var/type_to_del = user.poll_type_to_del(object) if(!type_to_del) return - var/choice = alert("ARE YOU SURE that you want to hard delete this type? It will cause MASSIVE lag.", "Hoooo lad what happen?", "Yes", "No") + var/choice = alert(user, "ARE YOU SURE that you want to hard delete this type? It will cause MASSIVE lag.", "Hoooo lad what happen?", "Yes", "No") if(choice != "Yes") return - choice = alert("Do you want to pre qdelete the atom? This will speed things up significantly, but may break depending on your level of fuckup.", "How do you even get it that bad", "Yes", "No") + choice = alert(user, "Do you want to pre qdelete the atom? This will speed things up significantly, but may break depending on your level of fuckup.", "How do you even get it that bad", "Yes", "No") var/should_pre_qdel = TRUE if(choice == "No") should_pre_qdel = FALSE - choice = alert("Ok one last thing, do you want to yield to the game? or do it all at once. These are hard deletes remember.", "Jesus christ man", "Yield", "Ignore the server") + choice = alert(user, "Ok one last thing, do you want to yield to the game? or do it all at once. These are hard deletes remember.", "Jesus christ man", "Yield", "Ignore the server") var/should_check_tick = TRUE if(choice == "Ignore the server") should_check_tick = FALSE @@ -129,24 +103,20 @@ qdel(O) del(O) CHECK_TICK - log_admin("[key_name(src)] has hard deleted all ([counter]) instances of [type_to_del].") - message_admins("[key_name_admin(src)] has hard deleted all ([counter]) instances of [type_to_del].") + log_admin("[key_name(user)] has hard deleted all ([counter]) instances of [type_to_del].") + message_admins("[key_name_admin(user)] has hard deleted all ([counter]) instances of [type_to_del].") BLACKBOX_LOG_ADMIN_VERB("Hard Delete All") -/client/proc/cmd_debug_make_powernets() - set category = "Debug" - set name = "Make Powernets" +ADMIN_VERB(cmd_debug_make_powernets, R_DEBUG|R_SERVER, "Make Powernets", "Regenerates all powernets for all cables.", ADMIN_CATEGORY_DEBUG) SSmachines.makepowernets() - log_admin("[key_name(src)] has remade the powernet. makepowernets() called.") - message_admins("[key_name_admin(src)] has remade the powernets. makepowernets() called.") + log_admin("[key_name(user)] has remade the powernet. makepowernets() called.") + message_admins("[key_name_admin(user)] has remade the powernets. makepowernets() called.") BLACKBOX_LOG_ADMIN_VERB("Make Powernets") -/client/proc/cmd_admin_grantfullaccess(mob/M in GLOB.mob_list) - set category = "Debug" - set name = "Grant Full Access" - +ADMIN_VERB_VISIBILITY(cmd_admin_grantfullaccess, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(cmd_admin_grantfullaccess, R_DEBUG, "Grant Full Access", "Grant full access to a mob.", ADMIN_CATEGORY_DEBUG, mob/M in world) if(!SSticker.HasRoundStarted()) - tgui_alert(usr,"Wait until the game starts") + tgui_alert(user, "Wait until the game starts") return if(ishuman(M)) var/mob/living/carbon/human/H = M @@ -180,51 +150,44 @@ H.equip_to_slot(id, ITEM_SLOT_ID) else - tgui_alert(usr,"Invalid mob") + tgui_alert(user,"Invalid mob") BLACKBOX_LOG_ADMIN_VERB("Grant Full Access") - log_admin("[key_name(src)] has granted [M.key] full access.") - message_admins(span_adminnotice("[key_name_admin(usr)] has granted [M.key] full access.")) - -/client/proc/cmd_assume_direct_control(mob/M in GLOB.mob_list) - set category = "Admin.Game" - set name = "Assume direct control" - set desc = "Direct intervention" + log_admin("[key_name(user)] has granted [M.key] full access.") + message_admins(span_adminnotice("[key_name_admin(user)] has granted [M.key] full access.")) +ADMIN_VERB(cmd_assume_direct_control, R_ADMIN, "Assume Direct Control", "Assume direct control of a mob.", ADMIN_CATEGORY_DEBUG, mob/M) if(M.ckey) - if(tgui_alert(usr,"This mob is being controlled by [M.key]. Are you sure you wish to assume control of it? [M.key] will be made a ghost.",,list("Yes","No")) != "Yes") + if(tgui_alert(user,"This mob is being controlled by [M.key]. Are you sure you wish to assume control of it? [M.key] will be made a ghost.",,list("Yes","No")) != "Yes") return if(!M || QDELETED(M)) - to_chat(usr, span_warning("The target mob no longer exists.")) + to_chat(user, span_warning("The target mob no longer exists.")) return - message_admins(span_adminnotice("[key_name_admin(usr)] assumed direct control of [M].")) - log_admin("[key_name(usr)] assumed direct control of [M].") - var/mob/adminmob = mob + message_admins(span_adminnotice("[key_name_admin(user)] assumed direct control of [M].")) + log_admin("[key_name(user)] assumed direct control of [M].") + var/mob/adminmob = user.mob if(M.ckey) M.ghostize(FALSE) - M.key = key - init_verbs() + M.key = user.key + user.init_verbs() if(isobserver(adminmob)) qdel(adminmob) BLACKBOX_LOG_ADMIN_VERB("Assume Direct Control") -/client/proc/cmd_give_direct_control(mob/M in GLOB.mob_list) - set category = "Admin.Game" - set name = "Give direct control" - +ADMIN_VERB(cmd_give_direct_control, R_ADMIN, "Give Direct Control", "Give direct control of a mob to another player.", ADMIN_CATEGORY_GAME, mob/M) if(!M) return if(M.ckey) - if(tgui_alert(usr,"This mob is being controlled by [M.key]. Are you sure you wish to give someone else control of it? [M.key] will be made a ghost.",,list("Yes","No")) != "Yes") + if(tgui_alert(user,"This mob is being controlled by [M.key]. Are you sure you wish to give someone else control of it? [M.key] will be made a ghost.",,list("Yes","No")) != "Yes") return - var/client/newkey = input(src, "Pick the player to put in control.", "New player") as null|anything in sort_list(GLOB.clients) + var/client/newkey = input(user, "Pick the player to put in control.", "New player") as null|anything in sort_list(GLOB.clients) if(isnull(newkey)) return var/mob/oldmob = newkey.mob var/delmob = FALSE - if((isobserver(oldmob) || tgui_alert(usr,"Do you want to delete [newkey]'s old mob?","Delete?",list("Yes","No")) != "No")) + if((isobserver(oldmob) || tgui_alert(user,"Do you want to delete [newkey]'s old mob?","Delete?",list("Yes","No")) != "No")) delmob = TRUE if(!M || QDELETED(M)) - to_chat(usr, span_warning("The target mob no longer exists, aborting.")) + to_chat(user, span_warning("The target mob no longer exists, aborting.")) return if(M.ckey) M.ghostize(FALSE) @@ -232,14 +195,12 @@ M.client?.init_verbs() if(delmob) qdel(oldmob) - message_admins(span_adminnotice("[key_name_admin(usr)] gave away direct control of [M] to [newkey].")) - log_admin("[key_name(usr)] gave away direct control of [M] to [newkey].") + message_admins(span_adminnotice("[key_name_admin(user)] gave away direct control of [M] to [newkey].")) + log_admin("[key_name(user)] gave away direct control of [M] to [newkey].") BLACKBOX_LOG_ADMIN_VERB("Give Direct Control") -/client/proc/cmd_admin_areatest(on_station, filter_maint) - set category = "Mapping" - set name = "Test Areas" - +ADMIN_VERB_VISIBILITY(cmd_admin_areatest, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(cmd_admin_areatest, R_DEBUG, "Test Areas", "Tests the areas for various machinery.", ADMIN_CATEGORY_MAPPING, on_station as num, filter_maint as num) var/list/dat = list() var/list/areas_all = list() var/list/areas_with_APC = list() @@ -270,7 +231,7 @@ )) if(SSticker.current_state == GAME_STATE_STARTUP) - to_chat(usr, "Game still loading, please hold!", confidential = TRUE) + to_chat(user, "Game still loading, please hold!", confidential = TRUE) return var/log_message @@ -283,8 +244,8 @@ dat += "Maintenance Areas Filtered Out" log_message += ", with no maintenance areas" - message_admins(span_adminnotice("[key_name_admin(usr)] used the Test Areas debug command checking [log_message].")) - log_admin("[key_name(usr)] used the Test Areas debug command checking [log_message].") + message_admins(span_adminnotice("[key_name_admin(user)] used the Test Areas debug command checking [log_message].")) + log_admin("[key_name(user)] used the Test Areas debug command checking [log_message].") for(var/area/A as anything in GLOB.areas) if(on_station) @@ -425,28 +386,23 @@ if(!(areas_with_APC.len || areas_with_multiple_APCs.len || areas_with_air_alarm.len || areas_with_RC.len || areas_with_light.len || areas_with_LS.len || areas_with_intercom.len || areas_with_camera.len)) dat += "No problem areas!" - var/datum/browser/popup = new(usr, "testareas", "Test Areas", 500, 750) + var/datum/browser/popup = new(user.mob, "testareas", "Test Areas", 500, 750) popup.set_content(dat.Join()) popup.open() +ADMIN_VERB_VISIBILITY(cmd_admin_areatest_station, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(cmd_admin_areatest_station, R_DEBUG, "Test Areas (STATION ONLY)", "Tests the areas for various machinery on station z-levels.", ADMIN_CATEGORY_MAPPING) + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/cmd_admin_areatest, /* on_station = */ TRUE) -/client/proc/cmd_admin_areatest_station() - set category = "Mapping" - set name = "Test Areas (STATION ONLY)" - cmd_admin_areatest(TRUE) +ADMIN_VERB_VISIBILITY(cmd_admin_areatest_station_no_maintenance, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(cmd_admin_areatest_station_no_maintenance, R_DEBUG, "Test Areas (STATION - NO MAINT)", "Tests the areas for various machinery on station z-levels, excluding maintenance areas.", ADMIN_CATEGORY_MAPPING) + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/cmd_admin_areatest, /* on_station = */ TRUE, /* filter_maint = */ TRUE) -/client/proc/cmd_admin_areatest_station_no_maintenance() - set category = "Mapping" - set name = "Test Areas (STATION - NO MAINT)" - cmd_admin_areatest(on_station = TRUE, filter_maint = TRUE) - -/client/proc/cmd_admin_areatest_all() - set category = "Mapping" - set name = "Test Areas (ALL)" - cmd_admin_areatest(FALSE) +ADMIN_VERB_VISIBILITY(cmd_admin_areatest_all, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(cmd_admin_areatest_all, R_DEBUG, "Test Areas (ALL)", "Tests the areas for various machinery on all z-levels.", ADMIN_CATEGORY_MAPPING) + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/cmd_admin_areatest) /client/proc/robust_dress_shop() - var/list/baseoutfits = list("Naked","Custom","As Job...", "As Plasmaman...") var/list/outfits = list() var/list/paths = subtypesof(/datum/outfit) - typesof(/datum/outfit/job) - typesof(/datum/outfit/plasmaman) @@ -497,52 +453,29 @@ return dresscode -/client/proc/cmd_admin_rejuvenate(mob/living/M in GLOB.mob_list) - set category = "Debug" - set name = "Rejuvenate" - - if(!check_rights(R_ADMIN)) - return - - if(!mob) - return +ADMIN_VERB_ONLY_CONTEXT_MENU(cmd_admin_rejuvenate, R_ADMIN, "Rejuvenate", mob/living/M in world) if(!istype(M)) - tgui_alert(usr,"Cannot revive a ghost") + tgui_alert(user,"Cannot revive a ghost") return M.revive(ADMIN_HEAL_ALL) - log_admin("[key_name(usr)] healed / revived [key_name(M)]") - var/msg = span_danger("Admin [key_name_admin(usr)] healed / revived [ADMIN_LOOKUPFLW(M)]!") + log_admin("[key_name(user)] healed / revived [key_name(M)]") + var/msg = span_danger("Admin [key_name_admin(user)] healed / revived [ADMIN_LOOKUPFLW(M)]!") message_admins(msg) admin_ticket_log(M, msg) BLACKBOX_LOG_ADMIN_VERB("Rejuvenate") -/client/proc/cmd_admin_delete(atom/A as obj|mob|turf in world) - set category = "Debug" - set name = "Delete" - - if(!check_rights(R_SPAWN|R_DEBUG)) - return - - admin_delete(A) +ADMIN_VERB_AND_CONTEXT_MENU(cmd_admin_delete, R_DEBUG|R_SPAWN, "Delete", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, atom/target as obj|mob|turf in world) + user.admin_delete(target) -/client/proc/cmd_admin_check_contents(mob/living/M in GLOB.mob_list) - set category = "Debug" - set name = "Check Contents" - - var/list/L = M.get_contents() - for(var/t in L) - to_chat(usr, "[t] [ADMIN_VV(t)] [ADMIN_TAG(t)]", confidential = TRUE) +ADMIN_VERB_AND_CONTEXT_MENU(cmd_check_contents, R_ADMIN, "Check Contents", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/living/mob) + var/list/mob_contents = mob.get_contents() + for(var/content in mob_contents) + to_chat(user, "[content] [ADMIN_VV(content)] [ADMIN_TAG(content)]", confidential = TRUE) BLACKBOX_LOG_ADMIN_VERB("Check Contents") -/client/proc/modify_goals() - set category = "Debug" - set name = "Modify goals" - - if(!check_rights(R_ADMIN)) - return - - holder.modify_goals() +ADMIN_VERB(modify_goals, R_ADMIN, "Modify Goals", "Modify the station goals for the shift.", ADMIN_CATEGORY_DEBUG) + user.holder.modify_goals() /datum/admins/proc/modify_goals() var/dat = "" @@ -551,34 +484,27 @@ dat += "
    Add New Goal" usr << browse(dat, "window=goals;size=400x400") -/client/proc/cmd_debug_mob_lists() - set category = "Debug" - set name = "Debug Mob Lists" - set desc = "For when you just gotta know" - var/chosen_list = tgui_input_list(usr, "Which list?", "Select List", list("Players","Admins","Mobs","Living Mobs","Dead Mobs","Clients","Joined Clients")) +ADMIN_VERB(debug_mob_lists, R_DEBUG, "Debug Mob Lists", "For when you just gotta know.", ADMIN_CATEGORY_DEBUG) + var/chosen_list = tgui_input_list(user, "Which list?", "Select List", list("Players","Admins","Mobs","Living Mobs","Dead Mobs","Clients","Joined Clients")) if(isnull(chosen_list)) return switch(chosen_list) if("Players") - to_chat(usr, jointext(GLOB.player_list,","), confidential = TRUE) + to_chat(user, jointext(GLOB.player_list,","), confidential = TRUE) if("Admins") - to_chat(usr, jointext(GLOB.admins,","), confidential = TRUE) + to_chat(user, jointext(GLOB.admins,","), confidential = TRUE) if("Mobs") - to_chat(usr, jointext(GLOB.mob_list,","), confidential = TRUE) + to_chat(user, jointext(GLOB.mob_list,","), confidential = TRUE) if("Living Mobs") - to_chat(usr, jointext(GLOB.alive_mob_list,","), confidential = TRUE) + to_chat(user, jointext(GLOB.alive_mob_list,","), confidential = TRUE) if("Dead Mobs") - to_chat(usr, jointext(GLOB.dead_mob_list,","), confidential = TRUE) + to_chat(user, jointext(GLOB.dead_mob_list,","), confidential = TRUE) if("Clients") - to_chat(usr, jointext(GLOB.clients,","), confidential = TRUE) + to_chat(user, jointext(GLOB.clients,","), confidential = TRUE) if("Joined Clients") - to_chat(usr, jointext(GLOB.joined_player_list,","), confidential = TRUE) - -/client/proc/cmd_display_del_log() - set category = "Debug" - set name = "Display del() Log" - set desc = "Display del's log of everything that's passed through it." + to_chat(user, jointext(GLOB.joined_player_list,","), confidential = TRUE) +ADMIN_VERB(del_log, R_DEBUG, "Display del() Log", "Display del's log of everything that's passed through it.", ADMIN_CATEGORY_DEBUG) var/list/dellog = list("List of things that have gone through qdel this round

      ") sortTim(SSgarbage.items, cmp=/proc/cmp_qdel_item_time, associative = TRUE) for(var/path in SSgarbage.items) @@ -609,37 +535,19 @@ dellog += "
    " - usr << browse(dellog.Join(), "window=dellog") - -/client/proc/cmd_display_overlay_log() - set category = "Debug" - set name = "Display overlay Log" - set desc = "Display SSoverlays log of everything that's passed through it." - - render_stats(SSoverlays.stats, src) - -/client/proc/cmd_display_init_log() - set category = "Debug" - set name = "Display Initialize() Log" - set desc = "Displays a list of things that didn't handle Initialize() properly" + user << browse(dellog.Join(), "window=dellog") - usr << browse(replacetext(SSatoms.InitLog(), "\n", "
    "), "window=initlog") +ADMIN_VERB(display_overlay_log, R_DEBUG, "Display Overlay Log", "Display SSoverlays log of everything that's passed through it.", ADMIN_CATEGORY_DEBUG) + render_stats(SSoverlays.stats, user) -/client/proc/open_colorblind_test() - set category = "Debug" - set name = "Colorblind Testing" - set desc = "Change your view to a budget version of colorblindness to test for usability" +ADMIN_VERB(init_log, R_DEBUG, "Display Initialize() Log", "Displays a list of things that didn't handle Initialize() properly.", ADMIN_CATEGORY_DEBUG) + user << browse(replacetext(SSatoms.InitLog(), "\n", "
    "), "window=initlog") - if(!holder) - return - holder.color_test.ui_interact(mob) - -/client/proc/debug_plane_masters() - set category = "Debug" - set name = "Edit/Debug Planes" - set desc = "Edit and visualize plane masters and their connections (relays)" +ADMIN_VERB(debug_color_test, R_DEBUG, "Colorblind Testing", "Change your view to a budget version of colorblindness to test for usability.", ADMIN_CATEGORY_DEBUG) + user.holder.color_test.ui_interact(user.mob) - edit_plane_masters() +ADMIN_VERB(debug_plane_masters, R_DEBUG, "Edit/Debug Planes", "Edit and visualize plane masters and their connections (relays).", ADMIN_CATEGORY_DEBUG) + user.edit_plane_masters() /client/proc/edit_plane_masters(mob/debug_on) if(!holder) @@ -651,21 +559,10 @@ holder.plane_debug.set_mirroring(FALSE) holder.plane_debug.ui_interact(mob) -/client/proc/debug_huds(i as num) - set category = "Debug" - set name = "Debug HUDs" - set desc = "Debug the data or antag HUDs" +ADMIN_VERB(debug_huds, R_DEBUG, "Debug HUDs", "Debug the data or antag HUDs.", ADMIN_CATEGORY_DEBUG, i as num) + SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/debug_variables, GLOB.huds[i]) - if(!holder) - return - debug_variables(GLOB.huds[i]) - -/client/proc/jump_to_ruin() - set category = "Debug" - set name = "Jump to Ruin" - set desc = "Displays a list of all placed ruins to teleport to." - if(!holder) - return +ADMIN_VERB(jump_to_ruin, R_DEBUG, "Jump to Ruin", "Displays a list of all placed ruins to teleport to.", ADMIN_CATEGORY_DEBUG) var/list/names = list() for(var/obj/effect/landmark/ruin/ruin_landmark as anything in GLOB.ruin_landmarks) var/datum/map_template/ruin/template = ruin_landmark.ruin_template @@ -680,23 +577,17 @@ names[name] = ruin_landmark - var/ruinname = tgui_input_list(usr, "Select ruin", "Jump to Ruin", sort_list(names)) - + var/ruinname = tgui_input_list(user, "Select ruin", "Jump to Ruin", sort_list(names)) var/obj/effect/landmark/ruin/landmark = names[ruinname] - - if(istype(landmark)) - var/datum/map_template/ruin/template = landmark.ruin_template - usr.forceMove(get_turf(landmark)) - to_chat(usr, span_name("[template.name]"), confidential = TRUE) - to_chat(usr, "[template.description]", confidential = TRUE) - -/client/proc/place_ruin() - set category = "Debug" - set name = "Spawn Ruin" - set desc = "Attempt to randomly place a specific ruin." - if (!holder) + if(!istype(landmark)) return + var/datum/map_template/ruin/template = landmark.ruin_template + user.mob.forceMove(get_turf(landmark)) + to_chat(user, span_name("[template.name]"), confidential = TRUE) + to_chat(user, "[template.description]", confidential = TRUE) +ADMIN_VERB_VISIBILITY(place_ruin, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(place_ruin, R_DEBUG, "Spawn Ruin", "Attempt to randomly place a specific ruin.", ADMIN_CATEGORY_MAPPING) var/list/exists = list() for(var/landmark in GLOB.ruin_landmarks) var/obj/effect/landmark/ruin/L = landmark @@ -714,15 +605,15 @@ themed_names[name] = list(ruin, theme, list(ruin.default_area)) names += sort_list(themed_names) - var/ruinname = tgui_input_list(usr, "Select ruin", "Spawn Ruin", sort_list(names)) + var/ruinname = tgui_input_list(user, "Select ruin", "Spawn Ruin", sort_list(names)) var/data = names[ruinname] if (!data) return var/datum/map_template/ruin/template = data[1] if (exists[template]) - var/response = tgui_alert(usr,"There is already a [template] in existence.", "Spawn Ruin", list("Jump", "Place Another", "Cancel")) + var/response = tgui_alert(user,"There is already a [template] in existence.", "Spawn Ruin", list("Jump", "Place Another", "Cancel")) if (response == "Jump") - usr.forceMove(get_turf(exists[template])) + user.mob.forceMove(get_turf(exists[template])) return else if (response == "Cancel") return @@ -731,25 +622,17 @@ seedRuins(SSmapping.levels_by_trait(data[2]), max(1, template.cost), data[3], list(ruinname = template)) if (GLOB.ruin_landmarks.len > len) var/obj/effect/landmark/ruin/landmark = GLOB.ruin_landmarks[GLOB.ruin_landmarks.len] - log_admin("[key_name(src)] randomly spawned ruin [ruinname] at [COORD(landmark)].") - usr.forceMove(get_turf(landmark)) - to_chat(src, span_name("[template.name]"), confidential = TRUE) - to_chat(src, "[template.description]", confidential = TRUE) + log_admin("[key_name(user)] randomly spawned ruin [ruinname] at [COORD(landmark)].") + user.mob.forceMove(get_turf(landmark)) + to_chat(user, span_name("[template.name]"), confidential = TRUE) + to_chat(user, "[template.description]", confidential = TRUE) else - to_chat(src, span_warning("Failed to place [template.name]."), confidential = TRUE) - -/client/proc/unload_ctf() - set category = "Debug" - set name = "Unload CTF" - set desc = "Despawns the majority of CTF" + to_chat(user, span_warning("Failed to place [template.name]."), confidential = TRUE) - toggle_id_ctf(usr, CTF_GHOST_CTF_GAME_ID, unload=TRUE) - -/client/proc/run_empty_query(val as num) - set category = "Debug" - set name = "Run empty query" - set desc = "Amount of queries to run" +ADMIN_VERB(unload_ctf, R_DEBUG, "Unload CTF", "Despawns the majority of CTF.", ADMIN_CATEGORY_DEBUG) + toggle_id_ctf(user, CTF_GHOST_CTF_GAME_ID, unload=TRUE) +ADMIN_VERB(run_empty_query, R_DEBUG, "Run Empty Query", "Runs a specified number of empty queries.", ADMIN_CATEGORY_DEBUG, val as num) var/list/queries = list() for(var/i in 1 to val) var/datum/db_query/query = SSdbcore.NewQuery("NULL") @@ -761,45 +644,31 @@ qdel(query) queries.Cut() - message_admins("[key_name_admin(src)] ran [val] empty queries.") + message_admins("[key_name_admin(user)] ran [val] empty queries.") -/client/proc/clear_dynamic_transit() - set category = "Debug" - set name = "Clear Dynamic Turf Reservations" - set desc = "Deallocates all reserved space, restoring it to round start conditions." - if(!holder) - return - var/answer = tgui_alert(usr,"WARNING: THIS WILL WIPE ALL RESERVED SPACE TO A CLEAN SLATE! ANY MOVING SHUTTLES, ELEVATORS, OR IN-PROGRESS PHOTOGRAPHY WILL BE DELETED!", "Really wipe dynamic turfs?", list("YES", "NO")) +ADMIN_VERB(clear_turf_reservations, R_DEBUG, "Clear Dynamic Turf Reservations", "Deallocates all reserved space, restoring it to round start conditions.", ADMIN_CATEGORY_DEBUG) + var/answer = tgui_alert( + user, + "WARNING: THIS WILL WIPE ALL RESERVED SPACE TO A CLEAN SLATE! ANY MOVING SHUTTLES, ELEVATORS, OR IN-PROGRESS PHOTOGRAPHY WILL BE DELETED!", + "Really wipe dynamic turfs?", + list("YES", "NO"), + ) if(answer != "YES") return - message_admins(span_adminnotice("[key_name_admin(src)] cleared dynamic transit space.")) - BLACKBOX_LOG_ADMIN_VERB("Clear Dynamic Transit") - log_admin("[key_name(src)] cleared dynamic transit space.") + message_admins(span_adminnotice("[key_name_admin(user)] cleared dynamic transit space.")) + BLACKBOX_LOG_ADMIN_VERB("Clear Dynamic Turf Reservations") + log_admin("[key_name(user)] cleared dynamic turf reservations.") SSmapping.wipe_reservations() //this goes after it's logged, incase something horrible happens. -/client/proc/toggle_medal_disable() - set category = "Debug" - set name = "Toggle Medal Disable" - set desc = "Toggles the safety lock on trying to contact the medal hub." - - if(!check_rights(R_DEBUG)) - return - +ADMIN_VERB(toggle_medal_disable, R_DEBUG, "Toggle Medal Disable", "Toggles the safety lock on trying to contact the medal hub.", ADMIN_CATEGORY_DEBUG) SSachievements.achievements_enabled = !SSachievements.achievements_enabled - message_admins(span_adminnotice("[key_name_admin(src)] [SSachievements.achievements_enabled ? "disabled" : "enabled"] the medal hub lockout.")) + message_admins(span_adminnotice("[key_name_admin(user)] [SSachievements.achievements_enabled ? "disabled" : "enabled"] the medal hub lockout.")) BLACKBOX_LOG_ADMIN_VERB("Toggle Medal Disable") - log_admin("[key_name(src)] [SSachievements.achievements_enabled ? "disabled" : "enabled"] the medal hub lockout.") - -/client/proc/view_runtimes() - set category = "Debug" - set name = "View Runtimes" - set desc = "Open the runtime Viewer" - - if(!holder) - return + log_admin("[key_name(user)] [SSachievements.achievements_enabled ? "disabled" : "enabled"] the medal hub lockout.") - GLOB.error_cache.show_to(src) +ADMIN_VERB(view_runtimes, R_DEBUG, "View Runtimes", "Opens the runtime viewer.", ADMIN_CATEGORY_DEBUG) + GLOB.error_cache.show_to(user) // The runtime viewer has the potential to crash the server if there's a LOT of runtimes // this has happened before, multiple times, so we'll just leave an alert on it @@ -808,80 +677,54 @@ if(GLOB.total_runtimes >= 100000) warning = "There are a TON of runtimes, clicking any button (especially \"linear\") WILL LIKELY crash the server" // Not using TGUI alert, because it's view runtimes, stuff is probably broken - alert(usr, "[warning]. Proceed with caution. If you really need to see the runtimes, download the runtime log and view it in a text editor.", "HEED THIS WARNING CAREFULLY MORTAL") - -/client/proc/pump_random_event() - set category = "Debug" - set name = "Pump Random Event" - set desc = "Schedules the event subsystem to fire a new random event immediately. Some events may fire without notification." - if(!holder) - return + alert(user, "[warning]. Proceed with caution. If you really need to see the runtimes, download the runtime log and view it in a text editor.", "HEED THIS WARNING CAREFULLY MORTAL") +ADMIN_VERB(pump_random_event, R_DEBUG, "Pump Random Event", "Schedules the event subsystem to fire a new random event immediately. Some events may fire without notification.", ADMIN_CATEGORY_DEBUG) SSevents.scheduled = world.time - message_admins(span_adminnotice("[key_name_admin(src)] pumped a random event.")) + message_admins(span_adminnotice("[key_name_admin(user)] pumped a random event.")) BLACKBOX_LOG_ADMIN_VERB("Pump Random Event") - log_admin("[key_name(src)] pumped a random event.") - -/client/proc/start_line_profiling() - set category = "Profile" - set name = "Start Line Profiling" - set desc = "Starts tracking line by line profiling for code lines that support it" + log_admin("[key_name(user)] pumped a random event.") +ADMIN_VERB_VISIBILITY(start_line_profiling, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(start_line_profiling, R_DEBUG, "Start Line Profiling", "Starts tracking line by line profiling for code lines that support it.", ADMIN_CATEGORY_PROFILE) LINE_PROFILE_START - message_admins(span_adminnotice("[key_name_admin(src)] started line by line profiling.")) + message_admins(span_adminnotice("[key_name_admin(user)] started line by line profiling.")) BLACKBOX_LOG_ADMIN_VERB("Start Line Profiling") - log_admin("[key_name(src)] started line by line profiling.") - -/client/proc/stop_line_profiling() - set category = "Profile" - set name = "Stops Line Profiling" - set desc = "Stops tracking line by line profiling for code lines that support it" + log_admin("[key_name(user)] started line by line profiling.") +ADMIN_VERB_VISIBILITY(stop_line_profiling, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(stop_line_profiling, R_DEBUG, "Stop Line Profiling", "Stops tracking line by line profiling for code lines that support it.", ADMIN_CATEGORY_PROFILE) LINE_PROFILE_STOP - message_admins(span_adminnotice("[key_name_admin(src)] stopped line by line profiling.")) + message_admins(span_adminnotice("[key_name_admin(user)] stopped line by line profiling.")) BLACKBOX_LOG_ADMIN_VERB("Stop Line Profiling") - log_admin("[key_name(src)] stopped line by line profiling.") - -/client/proc/show_line_profiling() - set category = "Profile" - set name = "Show Line Profiling" - set desc = "Shows tracked profiling info from code lines that support it" + log_admin("[key_name(user)] stopped line by line profiling.") +ADMIN_VERB_VISIBILITY(show_line_profiling, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(show_line_profiling, R_DEBUG, "Show Line Profiling", "Shows tracked profiling info from code lines that support it.", ADMIN_CATEGORY_PROFILE) var/sortlist = list( "Avg time" = GLOBAL_PROC_REF(cmp_profile_avg_time_dsc), "Total Time" = GLOBAL_PROC_REF(cmp_profile_time_dsc), "Call Count" = GLOBAL_PROC_REF(cmp_profile_count_dsc) ) - var/sort = input(src, "Sort type?", "Sort Type", "Avg time") as null|anything in sortlist + var/sort = input(user, "Sort type?", "Sort Type", "Avg time") as null|anything in sortlist if (!sort) return sort = sortlist[sort] - profile_show(src, sort) + profile_show(user, sort) -/client/proc/reload_configuration() - set category = "Debug" - set name = "Reload Configuration" - set desc = "Force config reload to world default" - if(!check_rights(R_DEBUG)) - return - if(tgui_alert(usr, "Are you absolutely sure you want to reload the configuration from the default path on the disk, wiping any in-round modifications?", "Really reset?", list("No", "Yes")) == "Yes") - config.admin_reload() - -/// A debug verb to check the sources of currently running timers -/client/proc/check_timer_sources() - set category = "Debug" - set name = "Check Timer Sources" - set desc = "Checks the sources of the running timers" - if (!check_rights(R_DEBUG)) +ADMIN_VERB(reload_configuration, R_DEBUG, "Reload Configuration", "Reloads the configuration from the default path on the disk, wiping any in-round modifications.", ADMIN_CATEGORY_DEBUG) + if(!tgui_alert(user, "Are you absolutely sure you want to reload the configuration from the default path on the disk, wiping any in-round modifications?", "Really reset?", list("No", "Yes")) == "Yes") return + config.admin_reload() +ADMIN_VERB(check_timer_sources, R_DEBUG, "Check Timer Sources", "Checks the sources of running timers.", ADMIN_CATEGORY_DEBUG) var/bucket_list_output = generate_timer_source_output(SStimer.bucket_list) var/second_queue = generate_timer_source_output(SStimer.second_queue) - usr << browse({" + user << browse({"

    bucket_list

    [bucket_list_output] @@ -889,24 +732,16 @@ [second_queue] "}, "window=check_timer_sources;size=700x700") -/// A debug verb to try and re-establish a connection with the TTS server and to refetch TTS voices. -/// Since voices are cached beforehand, this is unlikely to update preferences. -/client/proc/reestablish_tts_connection() - set category = "Debug" - set name = "Re-establish Connection To TTS" - set desc = "Re-establishes connection to the TTS server if possible" - if (!check_rights(R_DEBUG)) - return - - message_admins("[key_name_admin(usr)] attempted to re-establish connection to the TTS HTTP server.") - log_admin("[key_name(usr)] attempted to re-establish connection to the TTS HTTP server.") +ADMIN_VERB(reestablish_tts_connection, R_DEBUG, "Re-establish Connection To TTS", "Re-establishes connection to the TTS server if possible", ADMIN_CATEGORY_DEBUG) + message_admins("[key_name_admin(user)] attempted to re-establish connection to the TTS HTTP server.") + log_admin("[key_name(user)] attempted to re-establish connection to the TTS HTTP server.") var/success = SStts.establish_connection_to_tts() if(!success) - message_admins("[key_name_admin(usr)] failed to re-established the connection to the TTS HTTP server.") - log_admin("[key_name(usr)] failed to re-established the connection to the TTS HTTP server.") + message_admins("[key_name_admin(user)] failed to re-established the connection to the TTS HTTP server.") + log_admin("[key_name(user)] failed to re-established the connection to the TTS HTTP server.") return - message_admins("[key_name_admin(usr)] successfully re-established the connection to the TTS HTTP server.") - log_admin("[key_name(usr)] successfully re-established the connection to the TTS HTTP server.") + message_admins("[key_name_admin(user)] successfully re-established the connection to the TTS HTTP server.") + log_admin("[key_name(user)] successfully re-established the connection to the TTS HTTP server.") /proc/generate_timer_source_output(list/datum/timedevent/events) var/list/per_source = list() @@ -950,10 +785,14 @@ return b["count"] - a["count"] #ifdef TESTING -/client/proc/check_missing_sprites() - set category = "Debug" - set name = "Debug Worn Item Sprites" - set desc = "We're cancelling the Spritemageddon. (This will create a LOT of runtimes! Don't use on a live server!)" +ADMIN_VERB_CUSTOM_EXIST_CHECK(check_missing_sprites) + return TRUE +#else +ADMIN_VERB_CUSTOM_EXIST_CHECK(check_missing_sprites) + return FALSE +#endif + +ADMIN_VERB(check_missing_sprites, R_DEBUG, "Debug Worn Item Sprites", "We're cancelling the Spritemageddon. (This will create a LOT of runtimes! Don't use on a live server!)", ADMIN_CATEGORY_DEBUG) var/actual_file_name for(var/test_obj in subtypesof(/obj/item)) var/obj/item/sprite = new test_obj @@ -962,55 +801,54 @@ //Is there an explicit worn_icon to pick against the worn_icon_state? Easy street expected behavior. if(sprite.worn_icon) if(!(sprite.icon_state in icon_states(sprite.worn_icon))) - to_chat(src, span_warning("ERROR sprites for [sprite.type]. Slot Flags are [sprite.slot_flags]."), confidential = TRUE) + to_chat(user, span_warning("ERROR sprites for [sprite.type]. Slot Flags are [sprite.slot_flags]."), confidential = TRUE) else if(sprite.worn_icon_state) if(sprite.slot_flags & ITEM_SLOT_MASK) actual_file_name = 'icons/mob/clothing/mask.dmi' if(!(sprite.worn_icon_state in icon_states(actual_file_name))) - to_chat(src, span_warning("ERROR sprites for [sprite.type]. Mask slot."), confidential = TRUE) + to_chat(user, span_warning("ERROR sprites for [sprite.type]. Mask slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_NECK) actual_file_name = 'icons/mob/clothing/neck.dmi' if(!(sprite.worn_icon_state in icon_states(actual_file_name))) - to_chat(src, span_warning("ERROR sprites for [sprite.type]. Neck slot."), confidential = TRUE) + to_chat(user, span_warning("ERROR sprites for [sprite.type]. Neck slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_BACK) actual_file_name = 'icons/mob/clothing/back.dmi' if(!(sprite.worn_icon_state in icon_states(actual_file_name))) - to_chat(src, span_warning("ERROR sprites for [sprite.type]. Back slot."), confidential = TRUE) + to_chat(user, span_warning("ERROR sprites for [sprite.type]. Back slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_HEAD) actual_file_name = 'icons/mob/clothing/head/default.dmi' if(!(sprite.worn_icon_state in icon_states(actual_file_name))) - to_chat(src, span_warning("ERROR sprites for [sprite.type]. Head slot."), confidential = TRUE) + to_chat(user, span_warning("ERROR sprites for [sprite.type]. Head slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_BELT) actual_file_name = 'icons/mob/clothing/belt.dmi' if(!(sprite.worn_icon_state in icon_states(actual_file_name))) - to_chat(src, span_warning("ERROR sprites for [sprite.type]. Belt slot."), confidential = TRUE) + to_chat(user, span_warning("ERROR sprites for [sprite.type]. Belt slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_SUITSTORE) actual_file_name = 'icons/mob/clothing/belt_mirror.dmi' if(!(sprite.worn_icon_state in icon_states(actual_file_name))) - to_chat(src, span_warning("ERROR sprites for [sprite.type]. Suit Storage slot."), confidential = TRUE) + to_chat(user, span_warning("ERROR sprites for [sprite.type]. Suit Storage slot."), confidential = TRUE) else if(sprite.icon_state) if(sprite.slot_flags & ITEM_SLOT_MASK) actual_file_name = 'icons/mob/clothing/mask.dmi' if(!(sprite.icon_state in icon_states(actual_file_name))) - to_chat(src, span_warning("ERROR sprites for [sprite.type]. Mask slot."), confidential = TRUE) + to_chat(user, span_warning("ERROR sprites for [sprite.type]. Mask slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_NECK) actual_file_name = 'icons/mob/clothing/neck.dmi' if(!(sprite.icon_state in icon_states(actual_file_name))) - to_chat(src, span_warning("ERROR sprites for [sprite.type]. Neck slot."), confidential = TRUE) + to_chat(user, span_warning("ERROR sprites for [sprite.type]. Neck slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_BACK) actual_file_name = 'icons/mob/clothing/back.dmi' if(!(sprite.icon_state in icon_states(actual_file_name))) - to_chat(src, span_warning("ERROR sprites for [sprite.type]. Back slot."), confidential = TRUE) + to_chat(user, span_warning("ERROR sprites for [sprite.type]. Back slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_HEAD) actual_file_name = 'icons/mob/clothing/head/default.dmi' if(!(sprite.icon_state in icon_states(actual_file_name))) - to_chat(src, span_warning("ERROR sprites for [sprite.type]. Head slot."), confidential = TRUE) + to_chat(user, span_warning("ERROR sprites for [sprite.type]. Head slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_BELT) actual_file_name = 'icons/mob/clothing/belt.dmi' if(!(sprite.icon_state in icon_states(actual_file_name))) - to_chat(src, span_warning("ERROR sprites for [sprite.type]. Belt slot."), confidential = TRUE) + to_chat(user, span_warning("ERROR sprites for [sprite.type]. Belt slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_SUITSTORE) actual_file_name = 'icons/mob/clothing/belt_mirror.dmi' if(!(sprite.icon_state in icon_states(actual_file_name))) - to_chat(src, span_warning("ERROR sprites for [sprite.type]. Suit Storage slot."), confidential = TRUE) -#endif + to_chat(user, span_warning("ERROR sprites for [sprite.type]. Suit Storage slot."), confidential = TRUE) diff --git a/code/modules/admin/verbs/diagnostics.dm b/code/modules/admin/verbs/diagnostics.dm index a6a9a204b8521..4575614bb948f 100644 --- a/code/modules/admin/verbs/diagnostics.dm +++ b/code/modules/admin/verbs/diagnostics.dm @@ -1,15 +1,10 @@ -/client/proc/air_status(turf/target) - set category = "Debug" - set name = "Display Air Status" - - if(!isturf(target)) - return - atmos_scan(user=usr, target=target, silent=TRUE) +ADMIN_VERB_VISIBILITY(debug_air_status, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(debug_air_status, R_DEBUG, "Debug Air Status" , ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, turf/target in world) + atmos_scan(user.mob, target, silent = TRUE) BLACKBOX_LOG_ADMIN_VERB("Show Air Status") -/client/proc/fix_next_move() - set category = "Debug" - set name = "Unfreeze Everyone" +ADMIN_VERB_VISIBILITY(fix_next_move, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(fix_next_move, R_DEBUG, "Fix Next Move", "Unfreezes all frozen mobs.", ADMIN_CATEGORY_DEBUG) var/largest_move_time = 0 var/largest_click_time = 0 var/mob/largest_move_mob = null @@ -34,12 +29,9 @@ message_admins("[ADMIN_LOOKUPFLW(largest_click_mob)] had the largest click delay with [largest_click_time] frames / [DisplayTimeText(largest_click_time)]!") message_admins("world.time = [world.time]") BLACKBOX_LOG_ADMIN_VERB("Unfreeze Everyone") - return - -/client/proc/radio_report() - set category = "Debug" - set name = "Radio report" +ADMIN_VERB_VISIBILITY(radio_report, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(radio_report, R_DEBUG, "Radio Report", "Shows a report of all radio devices and their filters.", ADMIN_CATEGORY_DEBUG) var/output = "Radio Report
    " for (var/fq in SSradio.frequencies) output += "Freq: [fq]
    " @@ -64,29 +56,21 @@ else output += "    [device]
    " - usr << browse(output,"window=radioreport") + user << browse(output,"window=radioreport") BLACKBOX_LOG_ADMIN_VERB("Show Radio Report") -/client/proc/reload_admins() - set name = "Reload Admins" - set category = "Admin" - - if(!src.holder) - return - - var/confirm = tgui_alert(usr, "Are you sure you want to reload all admins?", "Confirm", list("Yes", "No")) +ADMIN_VERB(reload_admins, R_NONE, "Reload Admins", "Reloads all admins from the database.", ADMIN_CATEGORY_MAIN) + var/confirm = tgui_alert(user, "Are you sure you want to reload all admins?", "Confirm", list("Yes", "No")) if(confirm != "Yes") return load_admins() BLACKBOX_LOG_ADMIN_VERB("Reload All Admins") - message_admins("[key_name_admin(usr)] manually reloaded admins") + message_admins("[key_name_admin(user)] manually reloaded admins") -/client/proc/toggle_cdn() - set name = "Toggle CDN" - set category = "Server" +ADMIN_VERB(toggle_cdn, R_SERVER|R_DEBUG, "Toggle CDN", "Toggles the CDN for the server.", ADMIN_CATEGORY_SERVER) var/static/admin_disabled_cdn_transport = null - if (alert(usr, "Are you sure you want to toggle the CDN asset transport?", "Confirm", "Yes", "No") != "Yes") + if (alert(user, "Are you sure you want to toggle the CDN asset transport?", "Confirm", "Yes", "No") != "Yes") return var/current_transport = CONFIG_GET(string/asset_transport) if (!current_transport || current_transport == "simple") @@ -94,17 +78,17 @@ CONFIG_SET(string/asset_transport, admin_disabled_cdn_transport) admin_disabled_cdn_transport = null SSassets.OnConfigLoad() - message_admins("[key_name_admin(usr)] re-enabled the CDN asset transport") - log_admin("[key_name(usr)] re-enabled the CDN asset transport") + message_admins("[key_name_admin(user)] re-enabled the CDN asset transport") + log_admin("[key_name(user)] re-enabled the CDN asset transport") else - to_chat(usr, span_adminnotice("The CDN is not enabled!")) - if (tgui_alert(usr, "The CDN asset transport is not enabled! If you having issues with assets you can also try disabling filename mutations.", "The CDN asset transport is not enabled!", list("Try disabling filename mutations", "Nevermind")) == "Try disabling filename mutations") + to_chat(user, span_adminnotice("The CDN is not enabled!")) + if (tgui_alert(user, "The CDN asset transport is not enabled! If you having issues with assets you can also try disabling filename mutations.", "The CDN asset transport is not enabled!", list("Try disabling filename mutations", "Nevermind")) == "Try disabling filename mutations") SSassets.transport.dont_mutate_filenames = !SSassets.transport.dont_mutate_filenames - message_admins("[key_name_admin(usr)] [(SSassets.transport.dont_mutate_filenames ? "disabled" : "re-enabled")] asset filename transforms") - log_admin("[key_name(usr)] [(SSassets.transport.dont_mutate_filenames ? "disabled" : "re-enabled")] asset filename transforms") + message_admins("[key_name_admin(user)] [(SSassets.transport.dont_mutate_filenames ? "disabled" : "re-enabled")] asset filename transforms") + log_admin("[key_name(user)] [(SSassets.transport.dont_mutate_filenames ? "disabled" : "re-enabled")] asset filename transforms") else admin_disabled_cdn_transport = current_transport CONFIG_SET(string/asset_transport, "simple") SSassets.OnConfigLoad() - message_admins("[key_name_admin(usr)] disabled the CDN asset transport") - log_admin("[key_name(usr)] disabled the CDN asset transport") + message_admins("[key_name_admin(user)] disabled the CDN asset transport") + log_admin("[key_name(user)] disabled the CDN asset transport") diff --git a/code/modules/admin/verbs/ert.dm b/code/modules/admin/verbs/ert.dm index 6fc238931a65e..c86d08151ee62 100644 --- a/code/modules/admin/verbs/ert.dm +++ b/code/modules/admin/verbs/ert.dm @@ -261,18 +261,14 @@ return -/client/proc/summon_ert() - set category = "Admin.Fun" - set name = "Summon ERT" - set desc = "Summons an emergency response team" - - message_admins("[key_name(usr)] is creating a CentCom response team...") - if(holder?.makeEmergencyresponseteam()) - message_admins("[key_name(usr)] created a CentCom response team.") - log_admin("[key_name(usr)] created a CentCom response team.") +ADMIN_VERB(summon_ert, R_FUN, "Summon ERT", "Summons an emergency response team.", ADMIN_CATEGORY_FUN) + message_admins("[key_name_admin(user)] is creating a CentCom response team...") + if(user.holder?.makeEmergencyresponseteam()) + message_admins("[key_name_admin(user)] created a CentCom response team.") + log_admin("[key_name(user)] created a CentCom response team.") else - message_admins("[key_name_admin(usr)] tried to create a CentCom response team. Unfortunately, there were not enough candidates available.") - log_admin("[key_name(usr)] failed to create a CentCom response team.") + message_admins("[key_name_admin(user)] tried to create a CentCom response team. Unfortunately, there were not enough candidates available.") + log_admin("[key_name(user)] failed to create a CentCom response team.") #undef ERT_EXPERIENCED_LEADER_CHOOSE_TOP #undef DUMMY_HUMAN_SLOT_ADMIN diff --git a/code/modules/admin/verbs/fix_air.dm b/code/modules/admin/verbs/fix_air.dm index 15c1cccbfab79..cd694187ee5d6 100644 --- a/code/modules/admin/verbs/fix_air.dm +++ b/code/modules/admin/verbs/fix_air.dm @@ -1,20 +1,12 @@ // Proc taken from yogstation, credit to nichlas0010 for the original -/client/proc/fix_air(turf/open/T in world) - set name = "Fix Air" - set category = "Admin.Game" - set desc = "Fixes air in specified radius." +ADMIN_VERB(fix_air, R_ADMIN, "Fix Air", "Fixes air in a specified radius.", ADMIN_CATEGORY_GAME, turf/open/locale in world, range = 2 as num) + message_admins("[key_name_admin(user)] fixed air with range [range] in area [locale.loc.name]") + user.mob.log_message("fixed air with range [range] in area [locale.loc.name]", LOG_ADMIN) - if(!holder) - to_chat(src, "Only administrators may use this command.", confidential = TRUE) - return - if(check_rights(R_ADMIN,1)) - var/range=input("Enter range:","Num",2) as num - message_admins("[key_name_admin(usr)] fixed air with range [range] in area [T.loc.name]") - usr.log_message("fixed air with range [range] in area [T.loc.name]", LOG_ADMIN) - for(var/turf/open/F in range(range,T)) - if(F.blocks_air) - //skip walls - continue - var/datum/gas_mixture/GM = SSair.parse_gas_string(F.initial_gas_mix, /datum/gas_mixture/turf) - F.copy_air(GM) - F.update_visuals() + for(var/turf/open/valid_range_turf in range(range,locale)) + if(valid_range_turf.blocks_air) + //skip walls + continue + var/datum/gas_mixture/GM = SSair.parse_gas_string(valid_range_turf.initial_gas_mix, /datum/gas_mixture/turf) + valid_range_turf.copy_air(GM) + valid_range_turf.update_visuals() diff --git a/code/modules/admin/verbs/fov.dm b/code/modules/admin/verbs/fov.dm index f74ba6f80584d..afcd379e4a0b5 100644 --- a/code/modules/admin/verbs/fov.dm +++ b/code/modules/admin/verbs/fov.dm @@ -1,14 +1,8 @@ -/client/proc/cmd_admin_toggle_fov() - set name = "Enable/Disable Field of View" - set category = "Debug" - - if(!check_rights(R_ADMIN) || !check_rights(R_DEBUG)) - return - +ADMIN_VERB(toggle_fov, R_ADMIN|R_DEBUG, "Enable/Disable Field Of View", "Toggle FOV globally.", ADMIN_CATEGORY_DEBUG) var/on_off = CONFIG_GET(flag/native_fov) - message_admins("[key_name_admin(usr)] has [on_off ? "disabled" : "enabled"] the Native Field of View configuration..") - log_admin("[key_name(usr)] has [on_off ? "disabled" : "enabled"] the Native Field of View configuration.") + message_admins("[key_name_admin(user)] has [on_off ? "disabled" : "enabled"] the Native Field of View configuration..") + log_admin("[key_name(user)] has [on_off ? "disabled" : "enabled"] the Native Field of View configuration.") CONFIG_SET(flag/native_fov, !on_off) SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggled Field of View", "[on_off ? "Enabled" : "Disabled"]")) diff --git a/code/modules/admin/verbs/fps.dm b/code/modules/admin/verbs/fps.dm index 578a0c095144c..7af7968cde402 100644 --- a/code/modules/admin/verbs/fps.dm +++ b/code/modules/admin/verbs/fps.dm @@ -1,23 +1,16 @@ -//replaces the old Ticklag verb, fps is easier to understand -/client/proc/set_server_fps() - set category = "Debug" - set name = "Set Server FPS" - set desc = "Sets game speed in frames-per-second. Can potentially break the game" - - if(!check_rights(R_DEBUG)) - return - +ADMIN_VERB_VISIBILITY(set_server_fps, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(set_server_fps, R_DEBUG, "Set Server FPS", "Sets game speed in frames-per-second. Can potentially break the game", ADMIN_CATEGORY_DEBUG) var/cfg_fps = CONFIG_GET(number/fps) - var/new_fps = round(input("Sets game frames-per-second. Can potentially break the game (default: [cfg_fps])","FPS", world.fps) as num|null) + var/new_fps = round(input(user, "Sets game frames-per-second. Can potentially break the game (default: [cfg_fps])","FPS", world.fps) as num|null) if(new_fps <= 0) - to_chat(src, span_danger("Error: set_server_fps(): Invalid world.fps value. No changes made."), confidential = TRUE) + to_chat(user, span_danger("Error: set_server_fps(): Invalid world.fps value. No changes made."), confidential = TRUE) return if(new_fps > cfg_fps * 1.5) - if(tgui_alert(usr, "You are setting fps to a high value:\n\t[new_fps] frames-per-second\n\tconfig.fps = [cfg_fps]","Warning!",list("Confirm","ABORT-ABORT-ABORT")) != "Confirm") + if(tgui_alert(user, "You are setting fps to a high value:\n\t[new_fps] frames-per-second\n\tconfig.fps = [cfg_fps]","Warning!",list("Confirm","ABORT-ABORT-ABORT")) != "Confirm") return - var/msg = "[key_name(src)] has modified world.fps to [new_fps]" + var/msg = "[key_name(user)] has modified world.fps to [new_fps]" log_admin(msg, 0) message_admins(msg, 0) SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Set Server FPS", "[new_fps]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! diff --git a/code/modules/admin/verbs/getlogs.dm b/code/modules/admin/verbs/getlogs.dm index 77b43f9b49f48..bceac01cbe0d6 100644 --- a/code/modules/admin/verbs/getlogs.dm +++ b/code/modules/admin/verbs/getlogs.dm @@ -1,17 +1,8 @@ -//This proc allows download of past server logs saved within the data/logs/ folder. -/client/proc/getserverlogs() - set name = "Get Server Logs" - set desc = "View/retrieve logfiles." - set category = "Admin" +ADMIN_VERB(get_server_logs, R_ADMIN, "Get Server Logs", "View or retrieve logfiles.", ADMIN_CATEGORY_MAIN) + user.browseserverlogs() - browseserverlogs() - -/client/proc/getcurrentlogs() - set name = "Get Current Logs" - set desc = "View/retrieve logfiles for the current round." - set category = "Admin" - - browseserverlogs(current=TRUE) +ADMIN_VERB(get_current_logs, R_ADMIN, "Get Current Logs", "View or retrieve logfiles for the current round.", ADMIN_CATEGORY_MAIN) + user.browseserverlogs(current=TRUE) /client/proc/browseserverlogs(current=FALSE) var/path = browse_files(current ? BROWSE_ROOT_CURRENT_LOGS : BROWSE_ROOT_ALL_LOGS) @@ -32,4 +23,3 @@ else return to_chat(src, "Attempting to send [path], this may take a fair few minutes if the file is very large.", confidential = TRUE) - return diff --git a/code/modules/admin/verbs/ghost_pool_protection.dm b/code/modules/admin/verbs/ghost_pool_protection.dm index 843f6868e7072..439f4a37b897d 100644 --- a/code/modules/admin/verbs/ghost_pool_protection.dm +++ b/code/modules/admin/verbs/ghost_pool_protection.dm @@ -1,11 +1,8 @@ //very similar to centcom_podlauncher in terms of how this is coded, so i kept a lot of comments from it -/client/proc/ghost_pool_protection() //Creates a verb for admins to open up the ui - set name = "Ghost Pool Protection" - set desc = "Choose which ways people can get into the round, or just clear it out completely for admin events." - set category = "Admin.Events" - var/datum/ghost_pool_menu/tgui = new(usr)//create the datum - tgui.ui_interact(usr)//datum has a tgui component, here we open the window +ADMIN_VERB(ghost_pool_protection, R_ADMIN, "Ghost Pool Protection", "Choose which ways people can get into the round, or just clear it out completely for admin events.", ADMIN_CATEGORY_EVENTS) + var/datum/ghost_pool_menu/tgui = new(user) + tgui.ui_interact(user.mob) /datum/ghost_pool_menu var/client/holder //client of whoever is using this datum diff --git a/code/modules/admin/verbs/lawpanel.dm b/code/modules/admin/verbs/lawpanel.dm index 9b52c8d7339fe..f1daaf175761f 100644 --- a/code/modules/admin/verbs/lawpanel.dm +++ b/code/modules/admin/verbs/lawpanel.dm @@ -1,15 +1,9 @@ -/client/proc/cmd_admin_law_panel() - set category = "Admin.Events" - set name = "Law Panel" - - if(!check_rights(R_ADMIN)) - return - if(!isobserver(usr) && SSticker.HasRoundStarted()) - message_admins("[key_name_admin(usr)] checked AI laws via the Law Panel.") - +ADMIN_VERB(law_panel, R_ADMIN, "Law Panel", "View the AI laws.", ADMIN_CATEGORY_EVENTS) + if(!isobserver(user) && SSticker.HasRoundStarted()) + message_admins("[key_name_admin(user)] checked AI laws via the Law Panel.") + var/datum/law_panel/tgui = new + tgui.ui_interact(user.mob) BLACKBOX_LOG_ADMIN_VERB("Law Panel") - var/datum/law_panel/tgui = new() - tgui.ui_interact(usr) /datum/law_panel @@ -211,7 +205,7 @@ switch(action) if("lawchange_logs") - usr.client?.list_law_changes() + ui.user?.client?.holder?.list_law_changes() return FALSE if("force_state_laws") diff --git a/code/modules/admin/verbs/lua/lua_editor.dm b/code/modules/admin/verbs/lua/lua_editor.dm index 9e1b851824b33..d4a4bc2ee50b7 100644 --- a/code/modules/admin/verbs/lua/lua_editor.dm +++ b/code/modules/admin/verbs/lua/lua_editor.dm @@ -233,10 +233,6 @@ . = ..() qdel(src) -/client/proc/open_lua_editor() - set name = "Open Lua Editor" - set category = "Debug" - if(!check_rights_for(src, R_DEBUG)) - return - var/datum/lua_editor/editor = new() - editor.ui_interact(usr) +ADMIN_VERB(lua_editor, R_DEBUG, "Open Lua Editor", "Its codin' time.", ADMIN_CATEGORY_DEBUG) + var/datum/lua_editor/editor = new + editor.ui_interact(user.mob) diff --git a/code/modules/admin/verbs/machine_upgrade.dm b/code/modules/admin/verbs/machine_upgrade.dm index 2f681574d5d45..258de6bcf4dfd 100644 --- a/code/modules/admin/verbs/machine_upgrade.dm +++ b/code/modules/admin/verbs/machine_upgrade.dm @@ -1,13 +1,7 @@ -/proc/machine_upgrade(obj/machinery/M in world) - set name = "Tweak Component Ratings" - set category = "Debug" - if (!istype(M)) - return - - var/new_rating = input("Enter new rating:","Num") as num|null - if(new_rating && M.component_parts) - for(var/obj/item/stock_parts/P in M.component_parts) +ADMIN_VERB(machine_upgrade, R_DEBUG, "Tweak Component Ratings", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, obj/machinery/machine in world) + var/new_rating = input(user, "Enter new rating:","Num") as num|null + if(new_rating && machine.component_parts) + for(var/obj/item/stock_parts/P in machine.component_parts) P.rating = new_rating - M.RefreshParts() - + machine.RefreshParts() SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Machine Upgrade", "[new_rating]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! diff --git a/code/modules/admin/verbs/manipulate_organs.dm b/code/modules/admin/verbs/manipulate_organs.dm index 30f198bfba9f2..bfb5050dafa21 100644 --- a/code/modules/admin/verbs/manipulate_organs.dm +++ b/code/modules/admin/verbs/manipulate_organs.dm @@ -1,7 +1,6 @@ -/client/proc/manipulate_organs(mob/living/carbon/carbon_victim in world) - set name = "Manipulate Organs" - set category = "Debug" - var/operation = tgui_input_list(usr, "Select organ operation", "Organ Manipulation", list("add organ", "add implant", "drop organ/implant", "remove organ/implant")) +ADMIN_VERB_VISIBILITY(manipulate_organs, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(manipulate_organs, R_DEBUG, "Manipulate Organs", "Manipulate the organs of a living carbon.", ADMIN_CATEGORY_DEBUG, mob/living/carbon/carbon_victim in world) + var/operation = tgui_input_list(user, "Select organ operation", "Organ Manipulation", list("add organ", "add implant", "drop organ/implant", "remove organ/implant")) if (isnull(operation)) return @@ -12,7 +11,7 @@ var/dat = replacetext("[path]", "/obj/item/organ/", ":") organs[dat] = path - var/obj/item/organ/organ_to_grant = tgui_input_list(usr, "Select organ type", "Organ Manipulation", organs) + var/obj/item/organ/organ_to_grant = tgui_input_list(user, "Select organ type", "Organ Manipulation", organs) if(isnull(organ_to_grant)) return if(isnull(organs[organ_to_grant])) @@ -20,18 +19,18 @@ organ_to_grant = organs[organ_to_grant] organ_to_grant = new organ_to_grant if(!organ_to_grant.Insert(carbon_victim)) - to_chat(usr, span_notice("[carbon_victim] is unable to carry this organ!")) + to_chat(user, span_notice("[carbon_victim] is unable to carry this organ!")) qdel(organ_to_grant) return - log_admin("[key_name(usr)] has added organ [organ_to_grant.type] to [key_name(carbon_victim)]") - message_admins("[key_name_admin(usr)] has added organ [organ_to_grant.type] to [ADMIN_LOOKUPFLW(carbon_victim)]") + log_admin("[key_name(user)] has added organ [organ_to_grant.type] to [key_name(carbon_victim)]") + message_admins("[key_name_admin(user)] has added organ [organ_to_grant.type] to [ADMIN_LOOKUPFLW(carbon_victim)]") if("add implant") for(var/path in subtypesof(/obj/item/implant)) var/dat = replacetext("[path]", "/obj/item/implant/", ":") organs[dat] = path - var/obj/item/implant/implant_to_grant = tgui_input_list(usr, "Select implant type", "Organ Manipulation", organs) + var/obj/item/implant/implant_to_grant = tgui_input_list(user, "Select implant type", "Organ Manipulation", organs) if(isnull(implant_to_grant)) return if(isnull(organs[implant_to_grant])) @@ -39,11 +38,11 @@ implant_to_grant = organs[implant_to_grant] implant_to_grant = new implant_to_grant if(!implant_to_grant.implant(carbon_victim)) - to_chat(usr, span_notice("[carbon_victim] is unable to hold this implant!")) + to_chat(user, span_notice("[carbon_victim] is unable to hold this implant!")) qdel(implant_to_grant) return - log_admin("[key_name(usr)] has added implant [implant_to_grant.type] to [key_name(carbon_victim)]") - message_admins("[key_name_admin(usr)] has added implant [implant_to_grant.type] to [ADMIN_LOOKUPFLW(carbon_victim)]") + log_admin("[key_name(user)] has added implant [implant_to_grant.type] to [key_name(carbon_victim)]") + message_admins("[key_name_admin(user)] has added implant [implant_to_grant.type] to [ADMIN_LOOKUPFLW(carbon_victim)]") if("drop organ/implant", "remove organ/implant") for(var/obj/item/organ/user_organs as anything in carbon_victim.organs) @@ -52,15 +51,15 @@ for(var/obj/item/implant/user_implants as anything in carbon_victim.implants) organs["[user_implants.name] ([user_implants.type])"] = user_implants - var/obj/item/organ_to_modify = tgui_input_list(usr, "Select organ/implant", "Organ Manipulation", organs) + var/obj/item/organ_to_modify = tgui_input_list(user, "Select organ/implant", "Organ Manipulation", organs) if(isnull(organ_to_modify)) return if(isnull(organs[organ_to_modify])) return organ_to_modify = organs[organ_to_modify] - log_admin("[key_name(usr)] has removed [organ_to_modify.type] from [key_name(carbon_victim)]") - message_admins("[key_name_admin(usr)] has removed [organ_to_modify.type] from [ADMIN_LOOKUPFLW(carbon_victim)]") + log_admin("[key_name(user)] has removed [organ_to_modify.type] from [key_name(carbon_victim)]") + message_admins("[key_name_admin(user)] has removed [organ_to_modify.type] from [ADMIN_LOOKUPFLW(carbon_victim)]") var/obj/item/organ/organ_holder var/obj/item/implant/implant_holder diff --git a/code/modules/admin/verbs/map_export.dm b/code/modules/admin/verbs/map_export.dm index 8233ce4389d4b..056a2ea1f8a18 100644 --- a/code/modules/admin/verbs/map_export.dm +++ b/code/modules/admin/verbs/map_export.dm @@ -1,23 +1,22 @@ -/client/proc/map_export() - set category = "Debug" - set name = "Map Export" - set desc = "Select a part of the map by coordinates and download it." - - var/z_level = tgui_input_number(usr, "Export Which Z-Level?", "Map Exporter", usr.z || 2) - var/start_x = tgui_input_number(usr, "Start X?", "Map Exporter", usr.x || 1, world.maxx, 1) - var/start_y = tgui_input_number(usr, "Start Y?", "Map Exporter", usr.y || 1, world.maxy, 1) - var/end_x = tgui_input_number(usr, "End X?", "Map Exporter", usr.x || 1, world.maxx, 1) - var/end_y = tgui_input_number(usr, "End Y?", "Map Exporter", usr.y || 1, world.maxy, 1) +ADMIN_VERB(map_export, R_DEBUG, "Map Export", "Select a part of the map by coordinates and download it.", ADMIN_CATEGORY_DEBUG) + var/user_x = user.mob.x + var/user_y = user.mob.y + var/user_z = user.mob.z + var/z_level = tgui_input_number(user, "Export Which Z-Level?", "Map Exporter", user_z || 2) + var/start_x = tgui_input_number(user, "Start X?", "Map Exporter", user_x || 1, world.maxx, 1) + var/start_y = tgui_input_number(user, "Start Y?", "Map Exporter", user_y || 1, world.maxy, 1) + var/end_x = tgui_input_number(user, "End X?", "Map Exporter", user_x || 1, world.maxx, 1) + var/end_y = tgui_input_number(user, "End Y?", "Map Exporter", user_y || 1, world.maxy, 1) var/date = time2text(world.timeofday, "YYYY-MM-DD_hh-mm-ss") - var/file_name = sanitize_filename(tgui_input_text(usr, "Filename?", "Map Exporter", "exported_map_[date]")) - var/confirm = tgui_alert(usr, "Are you sure you want to do this? This will cause extreme lag!", "Map Exporter", list("Yes", "No")) + var/file_name = sanitize_filename(tgui_input_text(user, "Filename?", "Map Exporter", "exported_map_[date]")) + var/confirm = tgui_alert(user, "Are you sure you want to do this? This will cause extreme lag!", "Map Exporter", list("Yes", "No")) - if(confirm != "Yes" || !check_rights(R_DEBUG)) + if(confirm != "Yes") return var/map_text = write_map(start_x, start_y, z_level, end_x, end_y, z_level) - log_admin("Build Mode: [key_name(usr)] is exporting the map area from ([start_x], [start_y], [z_level]) through ([end_x], [end_y], [z_level])") - send_exported_map(usr, file_name, map_text) + log_admin("Build Mode: [key_name(user)] is exporting the map area from ([start_x], [start_y], [z_level]) through ([end_x], [end_y], [z_level])") + send_exported_map(user, file_name, map_text) /** * A procedure for saving DMM text to a file and then sending it to the user. diff --git a/code/modules/admin/verbs/map_template_loadverb.dm b/code/modules/admin/verbs/map_template_loadverb.dm index 827bbfb16e862..a27aca0f0147b 100644 --- a/code/modules/admin/verbs/map_template_loadverb.dm +++ b/code/modules/admin/verbs/map_template_loadverb.dm @@ -1,20 +1,17 @@ -/client/proc/map_template_load() - set category = "Debug" - set name = "Map template - Place" - +ADMIN_VERB(map_template_load, R_DEBUG, "Map Template - Place", "Place a map template at your current location.", ADMIN_CATEGORY_DEBUG) var/datum/map_template/template - var/map = tgui_input_list(usr, "Choose a Map Template to place at your CURRENT LOCATION","Place Map Template", sort_list(SSmapping.map_templates)) + var/map = tgui_input_list(user, "Choose a Map Template to place at your CURRENT LOCATION","Place Map Template", sort_list(SSmapping.map_templates)) if(!map) return template = SSmapping.map_templates[map] - var/turf/T = get_turf(mob) + var/turf/T = get_turf(user.mob) if(!T) return var/list/preview = list() var/center - var/centeralert = tgui_alert(usr,"Center Template.","Template Centering",list("Yes","No")) + var/centeralert = tgui_alert(user,"Center Template.","Template Centering",list("Yes","No")) switch(centeralert) if("Yes") center = TRUE @@ -26,8 +23,8 @@ var/image/item = image('icons/turf/overlays.dmi', place_on,"greenOverlay") SET_PLANE(item, ABOVE_LIGHTING_PLANE, place_on) preview += item - images += preview - if(tgui_alert(usr,"Confirm location.","Template Confirm",list("Yes","No")) == "Yes") + user.images += preview + if(tgui_alert(user,"Confirm location.","Template Confirm",list("Yes","No")) == "Yes") if(template.load(T, centered = center)) var/affected = template.get_affected_turfs(T, centered = center) for(var/AT in affected) @@ -36,23 +33,20 @@ template.post_load(P) break - message_admins(span_adminnotice("[key_name_admin(src)] has placed a map template ([template.name]) at [ADMIN_COORDJMP(T)]")) + message_admins(span_adminnotice("[key_name_admin(user)] has placed a map template ([template.name]) at [ADMIN_COORDJMP(T)]")) else - to_chat(src, "Failed to place map", confidential = TRUE) - images -= preview - -/client/proc/map_template_upload() - set category = "Debug" - set name = "Map Template - Upload" + to_chat(user, "Failed to place map", confidential = TRUE) + user.images -= preview - var/map = input(src, "Choose a Map Template to upload to template storage","Upload Map Template") as null|file +ADMIN_VERB(map_template_upload, R_DEBUG, "Map Template - Upload", "Upload a map template to the server.", ADMIN_CATEGORY_DEBUG) + var/map = input(user, "Choose a Map Template to upload to template storage","Upload Map Template") as null|file if(!map) return if(copytext("[map]", -4) != ".dmm")//4 == length(".dmm") - to_chat(src, span_warning("Filename must end in '.dmm': [map]"), confidential = TRUE) + to_chat(user, span_warning("Filename must end in '.dmm': [map]"), confidential = TRUE) return var/datum/map_template/M - switch(tgui_alert(usr, "What kind of map is this?", "Map type", list("Normal", "Shuttle", "Cancel"))) + switch(tgui_alert(user, "What kind of map is this?", "Map type", list("Normal", "Shuttle", "Cancel"))) if("Normal") M = new /datum/map_template(map, "[map]", TRUE) if("Shuttle") @@ -60,23 +54,23 @@ else return if(!M.cached_map) - to_chat(src, span_warning("Map template '[map]' failed to parse properly."), confidential = TRUE) + to_chat(user, span_warning("Map template '[map]' failed to parse properly."), confidential = TRUE) return var/datum/map_report/report = M.cached_map.check_for_errors() var/report_link if(report) - report.show_to(src) + report.show_to(user) report_link = " - validation report" - to_chat(src, span_warning("Map template '[map]' failed validation."), confidential = TRUE) + to_chat(user, span_warning("Map template '[map]' failed validation."), confidential = TRUE) if(report.loadable) - var/response = tgui_alert(usr, "The map failed validation, would you like to load it anyways?", "Map Errors", list("Cancel", "Upload Anyways")) + var/response = tgui_alert(user, "The map failed validation, would you like to load it anyways?", "Map Errors", list("Cancel", "Upload Anyways")) if(response != "Upload Anyways") return else - tgui_alert(usr, "The map failed validation and cannot be loaded.", "Map Errors", list("Oh Darn")) + tgui_alert(user, "The map failed validation and cannot be loaded.", "Map Errors", list("Oh Darn")) return SSmapping.map_templates[M.name] = M - message_admins(span_adminnotice("[key_name_admin(src)] has uploaded a map template '[map]' ([M.width]x[M.height])[report_link].")) - to_chat(src, span_notice("Map template '[map]' ready to place ([M.width]x[M.height])"), confidential = TRUE) + message_admins(span_adminnotice("[key_name_admin(user)] has uploaded a map template '[map]' ([M.width]x[M.height])[report_link].")) + to_chat(user, span_notice("Map template '[map]' ready to place ([M.width]x[M.height])"), confidential = TRUE) diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index aaf4cd13529fb..91481bb9a3e6b 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -1,69 +1,5 @@ -//- Are all the floors with or without air, as they should be? (regular or airless) -//- Does the area have an APC? -//- Does the area have an Air Alarm? -//- Does the area have a Request Console? -//- Does the area have lights? -//- Does the area have a light switch? -//- Does the area have enough intercoms? -//- Does the area have enough security cameras? (Use the 'Camera Range Display' verb under Debug) -//- Is the area connected to the scrubbers air loop? -//- Is the area connected to the vent air loop? (vent pumps) -//- Is everything wired properly? -//- Does the area have a fire alarm and firedoors? -//- Do all pod doors work properly? -//- Are accesses set properly on doors, pod buttons, etc. -//- Are all items placed properly? (not below vents, scrubbers, tables) -//- Does the disposal system work properly from all the disposal units in this room and all the units, the pipes of which pass through this room? -//- Check for any misplaced or stacked piece of pipe (air and disposal) -//- Check for any misplaced or stacked piece of wire -//- Identify how hard it is to break into the area and where the weak points are -//- Check if the area has too much empty space. If so, make it smaller and replace the rest with maintenance tunnels. - -GLOBAL_LIST_INIT(admin_verbs_debug_mapping, list( - /client/proc/camera_view, //-errorage - /client/proc/sec_camera_report, //-errorage - /client/proc/intercom_view, //-errorage - /client/proc/air_status, //Air things - /client/proc/Cell, //More air things - /client/proc/atmosscan, //check plumbing - /client/proc/powerdebug, //check power - /client/proc/count_objects_on_z_level, - /client/proc/count_objects_all, - /client/proc/cmd_assume_direct_control, //-errorage - /client/proc/cmd_give_direct_control, - /client/proc/set_server_fps, //allows you to set the ticklag. - /client/proc/cmd_admin_grantfullaccess, - /client/proc/cmd_admin_areatest_all, - /client/proc/cmd_admin_areatest_station, - /client/proc/cmd_admin_areatest_station_no_maintenance, - #ifdef TESTING - /client/proc/see_dirty_varedits, - #endif - /client/proc/cmd_admin_rejuvenate, - /datum/admins/proc/show_traitor_panel, - /client/proc/disable_communication, - /client/proc/show_map_reports, - /client/proc/cmd_show_at_list, - /client/proc/cmd_show_at_markers, - /client/proc/manipulate_organs, - /client/proc/start_line_profiling, - /client/proc/stop_line_profiling, - /client/proc/show_line_profiling, - /client/proc/create_mapping_job_icons, - /client/proc/debug_z_levels, - /client/proc/place_ruin, - /client/proc/station_food_debug, - /client/proc/station_stack_debug, - /client/proc/check_for_obstructed_atmospherics, - /client/proc/modify_lights, - /client/proc/visualize_lights, -)) -GLOBAL_PROTECT(admin_verbs_debug_mapping) - -/client/proc/camera_view() - set category = "Mapping" - set name = "Camera Range Display" - +ADMIN_VERB_VISIBILITY(camera_view, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(camera_view, R_DEBUG, "Camera Range Display", "Shows the range of cameras on the station.", ADMIN_CATEGORY_MAPPING) var/on = FALSE for(var/turf/T in world) if(T.maptext) @@ -82,28 +18,20 @@ GLOBAL_PROTECT(admin_verbs_debug_mapping) #ifdef TESTING GLOBAL_LIST_EMPTY(dirty_vars) -/client/proc/see_dirty_varedits() - set category = "Mapping" - set name = "Dirty Varedits" - +ADMIN_VERB_VISIBILITY(see_dirty_varedits, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(see_dirty_varedits, R_DEBUG, "Dirty Varedits", "Shows all dirty varedits.", ADMIN_CATEGORY_MAPPING) var/list/dat = list() dat += "

    Abandon all hope ye who enter here



    " for(var/thing in GLOB.dirty_vars) dat += "[thing]
    " CHECK_TICK - var/datum/browser/popup = new(usr, "dirty_vars", "Dirty Varedits", 900, 750) + var/datum/browser/popup = new(user, "dirty_vars", "Dirty Varedits", 900, 750) popup.set_content(dat.Join()) popup.open() #endif -/client/proc/sec_camera_report() - set category = "Mapping" - set name = "Camera Report" - - if(!Master) - tgui_alert(usr,"Master_controller not found.","Sec Camera Report") - return FALSE - +ADMIN_VERB_VISIBILITY(sec_camera_report, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(sec_camera_report, R_DEBUG, "Camera Report", "Get a printout of all camera issues.", ADMIN_CATEGORY_MAPPING) var/list/obj/machinery/camera/CL = list() for(var/obj/machinery/camera/C as anything in GLOB.cameranet.cameras) @@ -133,15 +61,13 @@ GLOBAL_LIST_EMPTY(dirty_vars) output += "
  • Camera not connected to wall at [ADMIN_VERBOSEJMP(C1)] Network: [json_encode(C1.network)]
  • " output += "" - usr << browse(output,"window=airreport;size=1000x500") + user << browse(output,"window=airreport;size=1000x500") BLACKBOX_LOG_ADMIN_VERB("Show Camera Report") -/client/proc/intercom_view() - set category = "Mapping" - set name = "Intercom Range Display" - +ADMIN_VERB_VISIBILITY(intercom_view, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(intercom_view, R_DEBUG, "Intercom Range Display", "Shows the range of intercoms on the station.", ADMIN_CATEGORY_MAPPING) var/static/intercom_range_display_status = FALSE - intercom_range_display_status = !intercom_range_display_status //blame cyberboss if this breaks something //blamed + intercom_range_display_status = !intercom_range_display_status for(var/obj/effect/abstract/marker/intercom/marker in GLOB.all_abstract_markers) qdel(marker) @@ -153,23 +79,17 @@ GLOBAL_LIST_EMPTY(dirty_vars) new /obj/effect/abstract/marker/intercom(turf) BLACKBOX_LOG_ADMIN_VERB("Show Intercom Range") -/client/proc/show_map_reports() - set category = "Mapping" - set name = "Show map report list" - set desc = "Displays a list of map reports" - +ADMIN_VERB_VISIBILITY(show_map_reports, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(show_map_reports, R_DEBUG, "Show Map Reports", "Displays a list of map reports.", ADMIN_CATEGORY_MAPPING) var/dat = {"List of all map reports:
    "} for(var/datum/map_report/report as anything in GLOB.map_reports) dat += "[report.tag] ([report.original_path]) - View
    " - usr << browse(dat, "window=map_reports") - -/client/proc/cmd_show_at_list() - set category = "Mapping" - set name = "Show roundstart AT list" - set desc = "Displays a list of active turfs coordinates at roundstart" + user << browse(dat, "window=map_reports") +ADMIN_VERB_VISIBILITY(cmd_show_at_list, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(cmd_show_at_list, R_DEBUG, "Show roundstart AT list", "Displays a list of active turfs coordinates at roundstart.", ADMIN_CATEGORY_MAPPING) var/dat = {"Coordinate list of Active Turfs at Roundstart
    Real-time Active Turfs list you can see in Air Subsystem at active_turfs var
    "} @@ -178,50 +98,39 @@ GLOBAL_LIST_EMPTY(dirty_vars) dat += "[ADMIN_VERBOSEJMP(T)]\n" dat += "
    " - usr << browse(dat, "window=at_list") + user << browse(dat, "window=at_list") BLACKBOX_LOG_ADMIN_VERB("Show Roundstart Active Turfs") -/client/proc/cmd_show_at_markers() - set category = "Mapping" - set name = "Show roundstart AT markers" - set desc = "Places a marker on all active-at-roundstart turfs" - +ADMIN_VERB_VISIBILITY(cmd_show_at_markers, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(cmd_show_at_markers, R_DEBUG, "Show roundstart AT markers", "Places a marker on all active-at-roundstart turfs.", ADMIN_CATEGORY_MAPPING) var/count = 0 for(var/obj/effect/abstract/marker/at/AT in GLOB.all_abstract_markers) qdel(AT) count++ if(count) - to_chat(usr, "[count] AT markers removed.", confidential = TRUE) + to_chat(user, "[count] AT markers removed.", confidential = TRUE) else for(var/t in GLOB.active_turfs_startlist) new /obj/effect/abstract/marker/at(t) count++ - to_chat(usr, "[count] AT markers placed.", confidential = TRUE) + to_chat(user, "[count] AT markers placed.", confidential = TRUE) BLACKBOX_LOG_ADMIN_VERB("Show Roundstart Active Turf Markers") -/client/proc/enable_mapping_verbs() - set category = "Debug" - set name = "Mapping verbs - Enable" - if(!check_rights(R_DEBUG)) - return - remove_verb(src, /client/proc/enable_mapping_verbs) - add_verb(src, list(/client/proc/disable_mapping_verbs, GLOB.admin_verbs_debug_mapping)) +ADMIN_VERB(enable_mapping_verbs, R_DEBUG, "Enable Mapping Verbs", "Enable all mapping verbs.", ADMIN_CATEGORY_MAPPING) + SSadmin_verbs.update_visibility_flag(user, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG, TRUE) BLACKBOX_LOG_ADMIN_VERB("Enable Debug Verbs") -/client/proc/disable_mapping_verbs() - set category = "Debug" - set name = "Mapping verbs - Disable" - remove_verb(src, list(/client/proc/disable_mapping_verbs, GLOB.admin_verbs_debug_mapping)) - add_verb(src, /client/proc/enable_mapping_verbs) +ADMIN_VERB_VISIBILITY(disable_mapping_verbs, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(disable_mapping_verbs, R_DEBUG, "Disable Mapping Verbs", "Disable all mapping verbs.", ADMIN_CATEGORY_MAPPING) + SSadmin_verbs.update_visibility_flag(user, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG, FALSE) BLACKBOX_LOG_ADMIN_VERB("Disable Debug Verbs") -/client/proc/count_objects_on_z_level() - set category = "Mapping" - set name = "Count Objects On Level" - var/level = input("Which z-level?","Level?") as text|null +ADMIN_VERB_VISIBILITY(count_objects_on_z_level, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(count_objects_on_z_level, R_DEBUG, "Count Objects On Z-Level", "Counts the number of objects of a certain type on a specific z-level.", ADMIN_CATEGORY_MAPPING) + var/level = input(user, "Which z-level?","Level?") as text|null if(!level) return var/num_level = text2num(level) @@ -230,7 +139,7 @@ GLOBAL_LIST_EMPTY(dirty_vars) if(!isnum(num_level)) return - var/type_text = input("Which type path?","Path?") as text|null + var/type_text = input(user, "Which type path?","Path?") as text|null if(!type_text) return var/type_path = text2path(type_text) @@ -257,11 +166,9 @@ GLOBAL_LIST_EMPTY(dirty_vars) to_chat(world, "There are [count] objects of type [type_path] on z-level [num_level]", confidential = TRUE) BLACKBOX_LOG_ADMIN_VERB("Count Objects Zlevel") -/client/proc/count_objects_all() - set category = "Mapping" - set name = "Count Objects All" - - var/type_text = input("Which type path?","") as text|null +ADMIN_VERB_VISIBILITY(count_objects_all, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(count_objects_all, R_DEBUG, "Count Objects All", "Counts the number of objects of a certain type in the game world.", ADMIN_CATEGORY_MAPPING) + var/type_text = input(user, "Which type path?","") as text|null if(!type_text) return var/type_path = text2path(type_text) @@ -277,23 +184,17 @@ GLOBAL_LIST_EMPTY(dirty_vars) to_chat(world, "There are [count] objects of type [type_path] in the game world", confidential = TRUE) BLACKBOX_LOG_ADMIN_VERB("Count Objects All") - -//This proc is intended to detect lag problems relating to communication procs GLOBAL_VAR_INIT(say_disabled, FALSE) -/client/proc/disable_communication() - set category = "Mapping" - set name = "Disable all communication verbs" - +ADMIN_VERB_VISIBILITY(disable_communication, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(disable_communication, R_DEBUG, "Disable all communication verbs", "Disables all communication verbs.", ADMIN_CATEGORY_MAPPING) GLOB.say_disabled = !GLOB.say_disabled if(GLOB.say_disabled) - message_admins("[key] used 'Disable all communication verbs', killing all communication methods.") + message_admins("[key_name_admin(user)] used 'Disable all communication verbs', killing all communication methods.") else - message_admins("[key] used 'Disable all communication verbs', restoring all communication methods.") + message_admins("[key_name_admin(user)] used 'Disable all communication verbs', restoring all communication methods.") -//This generates the icon states for job starting location landmarks. -/client/proc/create_mapping_job_icons() - set name = "Generate job landmarks icons" - set category = "Mapping" +ADMIN_VERB_VISIBILITY(create_mapping_job_icons, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(create_mapping_job_icons, R_DEBUG, "Generate job landmarks icons", "Generates job starting location landmarks.", ADMIN_CATEGORY_MAPPING) var/icon/final = icon() var/mob/living/carbon/human/dummy/D = new(locate(1,1,1)) //spawn on 1,1,1 so we don't have runtimes when items are deleted D.setDir(SOUTH) @@ -317,11 +218,9 @@ GLOBAL_VAR_INIT(say_disabled, FALSE) final.Insert(icon('icons/hud/screen_gen.dmi', "x[x_number == 1 ? "" : x_number]"), "x[x_number == 1 ? "" : x_number]") fcopy(final, "icons/mob/landmarks.dmi") -/client/proc/debug_z_levels() - set name = "Debug Z-Levels" - set category = "Mapping" - - to_chat(src, examine_block(gather_z_level_information(append_grid = TRUE)), confidential = TRUE) +ADMIN_VERB_VISIBILITY(debug_z_levels, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(debug_z_levels, R_DEBUG, "Debug Z-Levels", "Displays a list of all z-levels and their linkages.", ADMIN_CATEGORY_MAPPING) + to_chat(user, examine_block(gather_z_level_information(append_grid = TRUE)), confidential = TRUE) /// Returns all necessary z-level information. Argument `append_grid` allows the user to see a table showing all of the z-level linkages, which is only visible and useful in-game. /proc/gather_z_level_information(append_grid = FALSE) @@ -383,9 +282,8 @@ GLOBAL_VAR_INIT(say_disabled, FALSE) return messages.Join("\n") -/client/proc/station_food_debug() - set name = "Count Station Food" - set category = "Mapping" +ADMIN_VERB_VISIBILITY(station_food_debug, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(station_food_debug, R_DEBUG, "Count Station Food", "Counts the number of food items on the station.", ADMIN_CATEGORY_MAPPING) var/list/foodcount = list() for(var/obj/item/food/fuck_me in world) var/turf/location = get_turf(fuck_me) @@ -402,13 +300,12 @@ GLOBAL_VAR_INIT(say_disabled, FALSE) var/page_style = "" var/page_contents = "[page_style][table_header][jointext(table_contents, "")]
    " - var/datum/browser/popup = new(mob, "fooddebug", "Station Food Count", 600, 400) + var/datum/browser/popup = new(user.mob, "fooddebug", "Station Food Count", 600, 400) popup.set_content(page_contents) popup.open() -/client/proc/station_stack_debug() - set name = "Count Station Stacks" - set category = "Mapping" +ADMIN_VERB_VISIBILITY(station_stack_debug, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(station_stack_debug, R_DEBUG, "Count Station Stacks", "Count the stacks of materials on station.", ADMIN_CATEGORY_MAPPING) var/list/stackcount = list() for(var/obj/item/stack/fuck_me in world) var/turf/location = get_turf(fuck_me) @@ -425,18 +322,13 @@ GLOBAL_VAR_INIT(say_disabled, FALSE) var/page_style = "" var/page_contents = "[page_style][table_header][jointext(table_contents, "")]
    " - var/datum/browser/popup = new(mob, "stackdebug", "Station Stack Count", 600, 400) + var/datum/browser/popup = new(user.mob, "stackdebug", "Station Stack Count", 600, 400) popup.set_content(page_contents) popup.open() -/// Check all tiles with a vent or scrubber on it and ensure that nothing is covering it up. -/client/proc/check_for_obstructed_atmospherics() - set name = "Check For Obstructed Atmospherics" - set category = "Mapping" - if(!holder) - to_chat(src, "Only administrators may use this command.", confidential = TRUE) - return - message_admins(span_adminnotice("[key_name_admin(usr)] is checking for obstructed atmospherics through the debug command.")) +ADMIN_VERB_VISIBILITY(check_for_obstructed_atmospherics, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(check_for_obstructed_atmospherics, R_DEBUG, "Check For Obstructed Atmospherics", "Checks for obstructions on atmospherics machines.", ADMIN_CATEGORY_MAPPING) + message_admins(span_adminnotice("[key_name_admin(user)] is checking for obstructed atmospherics through the debug command.")) BLACKBOX_LOG_ADMIN_VERB("Check For Obstructed Atmospherics") var/list/results = list() @@ -485,17 +377,14 @@ GLOBAL_VAR_INIT(say_disabled, FALSE) results += "There is an obstruction on top of an atmospherics machine at: [ADMIN_VERBOSEJMP(iterated_turf)].
    " if(results.len == 1) // only the header is in the list, we're good - to_chat(src, "No obstructions detected.", confidential = TRUE) + to_chat(user, "No obstructions detected.", confidential = TRUE) else - var/datum/browser/popup = new(usr, "atmospherics_obstructions", "Atmospherics Obstructions", 900, 750) + var/datum/browser/popup = new(user.mob, "atmospherics_obstructions", "Atmospherics Obstructions", 900, 750) popup.set_content(results.Join()) popup.open() -/client/proc/modify_lights() - set name = "Toggle Light Debug" - set category = "Mapping" - if(!check_rights(R_DEBUG)) - return +ADMIN_VERB_VISIBILITY(modify_lights, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(modify_lights, R_DEBUG, "Toggle Light Debug", "Toggles light debug mode.", ADMIN_CATEGORY_MAPPING) if(GLOB.light_debug_enabled) undebug_sources() return @@ -507,10 +396,6 @@ GLOBAL_VAR_INIT(say_disabled, FALSE) CHECK_TICK debug_sources() -/client/proc/visualize_lights() - set name = "Visualize Lighting Corners" - set category = "Mapping" - if(!check_rights(R_DEBUG)) - return - +ADMIN_VERB_VISIBILITY(visualize_lights, ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG) +ADMIN_VERB(visualize_lights, R_DEBUG, "Visualize Lighting Corners", "Visualizes the corners of all lights on the station.", ADMIN_CATEGORY_MAPPING) display_corners() diff --git a/code/modules/admin/verbs/maprotation.dm b/code/modules/admin/verbs/maprotation.dm index c41677db37ccb..09d6d93bee632 100644 --- a/code/modules/admin/verbs/maprotation.dm +++ b/code/modules/admin/verbs/maprotation.dm @@ -1,16 +1,13 @@ -/client/proc/forcerandomrotate() - set category = "Server" - set name = "Trigger Random Map Rotation" - var/rotate = tgui_alert(usr,"Force a random map rotation to trigger?", "Rotate map?", list("Yes", "Cancel")) + +ADMIN_VERB(force_random_rotate, R_SERVER, "Trigger 'Random' Map Rotation", "Force a map vote.", ADMIN_CATEGORY_SERVER) + var/rotate = tgui_alert(user,"Force a random map rotation to trigger?", "Rotate map?", list("Yes", "Cancel")) if (rotate != "Yes") return - message_admins("[key_name_admin(usr)] is forcing a random map rotation.") - log_admin("[key_name(usr)] is forcing a random map rotation.") + message_admins("[key_name_admin(user)] is forcing a random map rotation.") + log_admin("[key_name(user)] is forcing a random map rotation.") SSmapping.maprotate() -/client/proc/adminchangemap() - set category = "Server" - set name = "Change Map" +ADMIN_VERB(admin_change_map, R_SERVER, "Change Map", "Set the next map.", ADMIN_CATEGORY_SERVER) var/list/maprotatechoices = list() for (var/map in config.maplist) var/datum/map_config/virtual_map = config.maplist[map] @@ -32,21 +29,21 @@ mapname += "\]" maprotatechoices[mapname] = virtual_map - var/chosenmap = tgui_input_list(usr, "Choose a map to change to", "Change Map", sort_list(maprotatechoices)|"Custom") + var/chosenmap = tgui_input_list(user, "Choose a map to change to", "Change Map", sort_list(maprotatechoices)|"Custom") if (isnull(chosenmap)) return if(chosenmap == "Custom") - message_admins("[key_name_admin(usr)] is changing the map to a custom map") - log_admin("[key_name(usr)] is changing the map to a custom map") + message_admins("[key_name_admin(user)] is changing the map to a custom map") + log_admin("[key_name(user)] is changing the map to a custom map") var/datum/map_config/virtual_map = new - var/map_file = input("Pick file:", "Map File") as null|file + var/map_file = input(user, "Pick file:", "Map File") as null|file if(isnull(map_file)) return if(copytext("[map_file]", -4) != ".dmm")//4 == length(".dmm") - to_chat(src, span_warning("Filename must end in '.dmm': [map_file]")) + to_chat(user, span_warning("Filename must end in '.dmm': [map_file]")) return if(fexists("_maps/custom/[map_file]")) @@ -56,20 +53,20 @@ // This is to make sure the map works so the server does not start without a map. var/datum/parsed_map/M = new (map_file) if(!M) - to_chat(src, span_warning("Map '[map_file]' failed to parse properly.")) + to_chat(user, span_warning("Map '[map_file]' failed to parse properly.")) return if(!M.bounds) - to_chat(src, span_warning("Map '[map_file]' has non-existant bounds.")) + to_chat(user, span_warning("Map '[map_file]' has non-existant bounds.")) qdel(M) return qdel(M) var/config_file = null var/list/json_value = list() - var/config = tgui_alert(usr,"Would you like to upload an additional config for this map?", "Map Config", list("Yes", "No")) + var/config = tgui_alert(user,"Would you like to upload an additional config for this map?", "Map Config", list("Yes", "No")) if(config == "Yes") - config_file = input("Pick file:", "Config JSON File") as null|file + config_file = input(user, "Pick file:", "Config JSON File") as null|file if(isnull(config_file)) return if(copytext("[config_file]", -5) != ".json") @@ -94,18 +91,18 @@ ) else virtual_map = load_map_config() - virtual_map.map_name = input("Choose the name for the map", "Map Name") as null|text + virtual_map.map_name = input(user, "Choose the name for the map", "Map Name") as null|text if(isnull(virtual_map.map_name)) virtual_map.map_name = "Custom" - var/shuttles = tgui_alert(usr,"Do you want to modify the shuttles?", "Map Shuttles", list("Yes", "No")) + var/shuttles = tgui_alert(user,"Do you want to modify the shuttles?", "Map Shuttles", list("Yes", "No")) if(shuttles == "Yes") for(var/s in virtual_map.shuttles) - var/shuttle = input(s, "Map Shuttles") as null|text + var/shuttle = input(user, s, "Map Shuttles") as null|text if(!shuttle) continue if(!SSmapping.shuttle_templates[shuttle]) - to_chat(usr, span_warning("No such shuttle as '[shuttle]' exists, using default.")) + to_chat(user, span_warning("No such shuttle as '[shuttle]' exists, using default.")) continue virtual_map.shuttles[s] = shuttle @@ -123,13 +120,13 @@ text2file(json_encode(json_value), PATH_TO_NEXT_MAP_JSON) if(SSmapping.changemap(virtual_map)) - message_admins("[key_name_admin(usr)] has changed the map to [virtual_map.map_name]") + message_admins("[key_name_admin(user)] has changed the map to [virtual_map.map_name]") SSmapping.map_force_chosen = TRUE fdel("data/custom_map_json/[config_file]") else var/datum/map_config/virtual_map = maprotatechoices[chosenmap] - message_admins("[key_name_admin(usr)] is changing the map to [virtual_map.map_name]") - log_admin("[key_name(usr)] is changing the map to [virtual_map.map_name]") + message_admins("[key_name_admin(user)] is changing the map to [virtual_map.map_name]") + log_admin("[key_name(user)] is changing the map to [virtual_map.map_name]") if (SSmapping.changemap(virtual_map)) - message_admins("[key_name_admin(usr)] has changed the map to [virtual_map.map_name]") + message_admins("[key_name_admin(user)] has changed the map to [virtual_map.map_name]") SSmapping.map_force_chosen = TRUE diff --git a/code/modules/admin/verbs/panicbunker.dm b/code/modules/admin/verbs/panicbunker.dm index c8c478586699d..57aba1ee8d96b 100644 --- a/code/modules/admin/verbs/panicbunker.dm +++ b/code/modules/admin/verbs/panicbunker.dm @@ -1,8 +1,6 @@ -/client/proc/panicbunker() - set category = "Server" - set name = "Toggle Panic Bunker" +ADMIN_VERB(panic_bunker, R_SERVER, "Toggle Panic Bunker", "Toggles the panic bunker for the server.", ADMIN_CATEGORY_SERVER) if (!CONFIG_GET(flag/sql_enabled)) - to_chat(usr, span_adminnotice("The Database is not enabled!"), confidential = TRUE) + to_chat(user, span_adminnotice("The Database is not enabled!"), confidential = TRUE) return var/new_pb = !CONFIG_GET(flag/panic_bunker) @@ -10,28 +8,26 @@ var/time_rec = 0 var/message = "" if(new_pb) - time_rec = input(src, "How many living minutes should they need to play? 0 to disable.", "Shit's fucked isn't it", CONFIG_GET(number/panic_bunker_living)) as num - message = input(src, "What should they see when they log in?", "MMM", CONFIG_GET(string/panic_bunker_message)) as text + time_rec = input(user, "How many living minutes should they need to play? 0 to disable.", "Shit's fucked isn't it", CONFIG_GET(number/panic_bunker_living)) as num + message = input(user, "What should they see when they log in?", "MMM", CONFIG_GET(string/panic_bunker_message)) as text message = replacetext(message, "%minutes%", time_rec) CONFIG_SET(number/panic_bunker_living, time_rec) CONFIG_SET(string/panic_bunker_message, message) - var/interview_sys = tgui_alert(usr, "Should the interview system be enabled? (Allows players to connect under the hour limit and force them to be manually approved to play)", "Enable interviews?", list("Enable", "Disable")) + var/interview_sys = tgui_alert(user, "Should the interview system be enabled? (Allows players to connect under the hour limit and force them to be manually approved to play)", "Enable interviews?", list("Enable", "Disable")) interview = interview_sys == "Enable" CONFIG_SET(flag/panic_bunker_interview, interview) CONFIG_SET(flag/panic_bunker, new_pb) - log_admin("[key_name(usr)] has toggled the Panic Bunker, it is now [new_pb ? "on and set to [time_rec] with a message of [message]. The interview system is [interview ? "enabled" : "disabled"]" : "off"].") - message_admins("[key_name_admin(usr)] has toggled the Panic Bunker, it is now [new_pb ? "enabled with a living minutes requirement of [time_rec]. The interview system is [interview ? "enabled" : "disabled"]" : "disabled"].") + log_admin("[key_name(user)] has toggled the Panic Bunker, it is now [new_pb ? "on and set to [time_rec] with a message of [message]. The interview system is [interview ? "enabled" : "disabled"]" : "off"].") + message_admins("[key_name_admin(user)] has toggled the Panic Bunker, it is now [new_pb ? "enabled with a living minutes requirement of [time_rec]. The interview system is [interview ? "enabled" : "disabled"]" : "disabled"].") if (new_pb && !SSdbcore.Connect()) message_admins("The Database is not connected! Panic bunker will not work until the connection is reestablished.") SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Panic Bunker", "[new_pb ? "Enabled" : "Disabled"]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! -/client/proc/toggle_interviews() - set category = "Server" - set name = "Toggle PB Interviews" +ADMIN_VERB(toggle_interviews, R_SERVER, "Toggle PB Interviews", "Toggle whether new players will be interviewed or blocked from connecting.", ADMIN_CATEGORY_SERVER) if (!CONFIG_GET(flag/panic_bunker)) - to_chat(usr, span_adminnotice("NOTE: The panic bunker is not enabled, so this change will not effect anything until it is enabled."), confidential = TRUE) + to_chat(user, span_adminnotice("NOTE: The panic bunker is not enabled, so this change will not effect anything until it is enabled."), confidential = TRUE) var/new_interview = !CONFIG_GET(flag/panic_bunker_interview) CONFIG_SET(flag/panic_bunker_interview, new_interview) - log_admin("[key_name(usr)] has toggled the Panic Bunker's interview system, it is now [new_interview ? "enabled" : "disabled"].") - message_admins("[key_name(usr)] has toggled the Panic Bunker's interview system, it is now [new_interview ? "enabled" : "disabled"].") + log_admin("[key_name(user)] has toggled the Panic Bunker's interview system, it is now [new_interview ? "enabled" : "disabled"].") + message_admins("[key_name(user)] has toggled the Panic Bunker's interview system, it is now [new_interview ? "enabled" : "disabled"].") diff --git a/code/modules/admin/verbs/player_ticket_history.dm b/code/modules/admin/verbs/player_ticket_history.dm index 08373db3470cb..829d4dfc2b57e 100644 --- a/code/modules/admin/verbs/player_ticket_history.dm +++ b/code/modules/admin/verbs/player_ticket_history.dm @@ -19,13 +19,8 @@ GENERAL_PROTECT_DATUM(/datum/ticket_log_entry) GLOBAL_DATUM_INIT(player_ticket_history, /datum/ticket_history_holder, new) GLOBAL_PROTECT(player_ticket_history) -/client/proc/player_ticket_history() - set name = "Player Ticket History" - set desc = "Allows you to view the ticket history of a player." - set category = "Admin" - if(!check_rights(R_ADMIN)) - return - GLOB.player_ticket_history.ui_interact(mob) +ADMIN_VERB(player_ticket_history, R_ADMIN, "Player Ticket History", "Allows you to view the ticket history of a player.", ADMIN_CATEGORY_MAIN) + GLOB.player_ticket_history.ui_interact(user.mob) /datum/ticket_history_holder /// Assosciative list of ticket histories. ckey -> list/datum/ticket_history diff --git a/code/modules/admin/verbs/playsound.dm b/code/modules/admin/verbs/playsound.dm index 1b63c83529b8a..c4e4257e84fc7 100644 --- a/code/modules/admin/verbs/playsound.dm +++ b/code/modules/admin/verbs/playsound.dm @@ -3,20 +3,15 @@ #define SHELLEO_STDOUT 2 #define SHELLEO_STDERR 3 -/client/proc/play_sound(S as sound) - set category = "Admin.Fun" - set name = "Play Global Sound" - if(!check_rights(R_SOUND)) - return - +ADMIN_VERB(play_sound, R_SOUND, "Play Global Sound", "Play a sound to all connected players.", ADMIN_CATEGORY_FUN, sound as sound) var/freq = 1 - var/vol = input(usr, "What volume would you like the sound to play at?",, 100) as null|num + var/vol = tgui_input_number(user, "What volume would you like the sound to play at?", max_value = 100) if(!vol) return vol = clamp(vol, 1, 100) - var/sound/admin_sound = new() - admin_sound.file = S + var/sound/admin_sound = new + admin_sound.file = sound admin_sound.priority = 250 admin_sound.channel = CHANNEL_ADMIN admin_sound.frequency = freq @@ -25,15 +20,15 @@ admin_sound.status = SOUND_STREAM admin_sound.volume = vol - var/res = tgui_alert(usr, "Show the title of this song to the players?",, list("Yes","No", "Cancel")) + var/res = tgui_alert(user, "Show the title of this song to the players?",, list("Yes","No", "Cancel")) switch(res) if("Yes") - to_chat(world, span_boldannounce("An admin played: [S]"), confidential = TRUE) + to_chat(world, span_boldannounce("An admin played: [sound]"), confidential = TRUE) if("Cancel") return - log_admin("[key_name(src)] played sound [S]") - message_admins("[key_name_admin(src)] played sound [S]") + log_admin("[key_name(user)] played sound [sound]") + message_admins("[key_name_admin(user)] played sound [sound]") for(var/mob/M in GLOB.player_list) if(M.client.prefs.read_preference(/datum/preference/toggle/sound_midi)) @@ -43,31 +38,20 @@ BLACKBOX_LOG_ADMIN_VERB("Play Global Sound") - -/client/proc/play_local_sound(S as sound) - set category = "Admin.Fun" - set name = "Play Local Sound" - if(!check_rights(R_SOUND)) - return - - log_admin("[key_name(src)] played a local sound [S]") - message_admins("[key_name_admin(src)] played a local sound [S]") - playsound(get_turf(src.mob), S, 50, FALSE, FALSE) +ADMIN_VERB(play_local_sound, R_SOUND, "Play Local Sound", "Plays a sound only you can hear.", ADMIN_CATEGORY_FUN, sound as sound) + log_admin("[key_name(user)] played a local sound [sound]") + message_admins("[key_name_admin(user)] played a local sound [sound]") + playsound(get_turf(user.mob), sound, 50, FALSE, FALSE) BLACKBOX_LOG_ADMIN_VERB("Play Local Sound") -/client/proc/play_direct_mob_sound(S as sound, mob/M) - set category = "Admin.Fun" - set name = "Play Direct Mob Sound" - if(!check_rights(R_SOUND)) - return - - if(!M) - M = input(usr, "Choose a mob to play the sound to. Only they will hear it.", "Play Mob Sound") as null|anything in sort_names(GLOB.player_list) - if(!M || QDELETED(M)) +ADMIN_VERB(play_direct_mob_sound, R_SOUND, "Play Direct Mob Sound", "Play a sound directly to a mob.", ADMIN_CATEGORY_FUN, sound as sound, mob/target in world) + if(!target) + target = input(user, "Choose a mob to play the sound to. Only they will hear it.", "Play Mob Sound") as null|anything in sort_names(GLOB.player_list) + if(QDELETED(target)) return - log_admin("[key_name(src)] played a direct mob sound [S] to [M].") - message_admins("[key_name_admin(src)] played a direct mob sound [S] to [ADMIN_LOOKUPFLW(M)].") - SEND_SOUND(M, S) + log_admin("[key_name(user)] played a direct mob sound [sound] to [key_name_admin(target)].") + message_admins("[key_name_admin(user)] played a direct mob sound [sound] to [ADMIN_LOOKUPFLW(target)].") + SEND_SOUND(target, sound) BLACKBOX_LOG_ADMIN_VERB("Play Direct Mob Sound") ///Takes an input from either proc/play_web_sound or the request manager and runs it through youtube-dl and prompts the user before playing it to the server. @@ -169,59 +153,41 @@ BLACKBOX_LOG_ADMIN_VERB("Play Internet Sound") +ADMIN_VERB_CUSTOM_EXIST_CHECK(play_web_sound) + return !!CONFIG_GET(string/invoke_youtubedl) -/client/proc/play_web_sound() - set category = "Admin.Fun" - set name = "Play Internet Sound" - if(!check_rights(R_SOUND)) - return - - var/ytdl = CONFIG_GET(string/invoke_youtubedl) - if(!ytdl) - to_chat(src, span_boldwarning("Youtube-dl was not configured, action unavailable"), confidential = TRUE) //Check config.txt for the INVOKE_YOUTUBEDL value - return - +ADMIN_VERB(play_web_sound, R_SOUND, "Play Internet Sound", "Play a given internet sound to all players.", ADMIN_CATEGORY_FUN) if(S_TIMER_COOLDOWN_TIMELEFT(SStimer, COOLDOWN_INTERNET_SOUND)) - if(tgui_alert(usr, "Someone else is already playing an Internet sound! It has [DisplayTimeText(S_TIMER_COOLDOWN_TIMELEFT(SStimer, COOLDOWN_INTERNET_SOUND), 1)] remaining. \ + if(tgui_alert(user, "Someone else is already playing an Internet sound! It has [DisplayTimeText(S_TIMER_COOLDOWN_TIMELEFT(SStimer, COOLDOWN_INTERNET_SOUND), 1)] remaining. \ Would you like to override?", "Musicalis Interruptus", list("No","Yes")) != "Yes") return - var/web_sound_input = tgui_input_text(usr, "Enter content URL (supported sites only, leave blank to stop playing)", "Play Internet Sound", null) + var/web_sound_input = tgui_input_text(user, "Enter content URL (supported sites only, leave blank to stop playing)", "Play Internet Sound", null) if(length(web_sound_input)) web_sound_input = trim(web_sound_input) if(findtext(web_sound_input, ":") && !findtext(web_sound_input, GLOB.is_http_protocol)) - to_chat(src, span_boldwarning("Non-http(s) URIs are not allowed."), confidential = TRUE) - to_chat(src, span_warning("For youtube-dl shortcuts like ytsearch: please use the appropriate full URL from the website."), confidential = TRUE) + to_chat(user, span_boldwarning("Non-http(s) URIs are not allowed."), confidential = TRUE) + to_chat(user, span_warning("For youtube-dl shortcuts like ytsearch: please use the appropriate full URL from the website."), confidential = TRUE) return - web_sound(usr, web_sound_input) + web_sound(user.mob, web_sound_input) else - web_sound(usr, null) + web_sound(user.mob, null) -/client/proc/set_round_end_sound(S as sound) - set category = "Admin.Fun" - set name = "Set Round End Sound" - if(!check_rights(R_SOUND)) - return - - SSticker.SetRoundEndSound(S) +ADMIN_VERB(set_round_end_sound, R_SOUND, "Set Round End Sound", "Set the sound that plays on round end.", ADMIN_CATEGORY_FUN, sound as sound) + SSticker.SetRoundEndSound(sound) - log_admin("[key_name(src)] set the round end sound to [S]") - message_admins("[key_name_admin(src)] set the round end sound to [S]") + log_admin("[key_name(user)] set the round end sound to [sound]") + message_admins("[key_name_admin(user)] set the round end sound to [sound]") BLACKBOX_LOG_ADMIN_VERB("Set Round End Sound") -/client/proc/stop_sounds() - set category = "Debug" - set name = "Stop All Playing Sounds" - if(!src.holder) - return - - log_admin("[key_name(src)] stopped all currently playing sounds.") - message_admins("[key_name_admin(src)] stopped all currently playing sounds.") - for(var/mob/M in GLOB.player_list) - SEND_SOUND(M, sound(null)) - var/client/C = M.client - C?.tgui_panel?.stop_music() +ADMIN_VERB(stop_sounds, R_NONE, "Stop All Playing Sounds", "Stops all playing sounds for EVERYONE.", ADMIN_CATEGORY_DEBUG) + log_admin("[key_name(user)] stopped all currently playing sounds.") + message_admins("[key_name_admin(user)] stopped all currently playing sounds.") + for(var/mob/player as anything in GLOB.player_list) + SEND_SOUND(player, sound(null)) + var/client/player_client = player.client + player_client?.tgui_panel?.stop_music() S_TIMER_COOLDOWN_RESET(SStimer, COOLDOWN_INTERNET_SOUND) BLACKBOX_LOG_ADMIN_VERB("Stop All Playing Sounds") diff --git a/code/modules/admin/verbs/possess.dm b/code/modules/admin/verbs/possess.dm index 63304104ab536..a7e50840f5e2a 100644 --- a/code/modules/admin/verbs/possess.dm +++ b/code/modules/admin/verbs/possess.dm @@ -1,32 +1,20 @@ -/proc/possess(obj/target in world) - set name = "Possess Obj" - set category = "Object" - var/result = usr.AddComponent(/datum/component/object_possession, target) +ADMIN_VERB(possess, R_POSSESS, "Possess Obj", "Possess an object.", ADMIN_CATEGORY_OBJECT, obj/target in world) + var/result = user.mob.AddComponent(/datum/component/object_possession, target) if(isnull(result)) // trigger a safety movement just in case we yonk - usr.forceMove(get_turf(usr)) + user.mob.forceMove(get_turf(user.mob)) return var/turf/target_turf = get_turf(target) - var/message = "[key_name(usr)] has possessed [target] ([target.type]) at [AREACOORD(target_turf)]" + var/message = "[key_name(user)] has possessed [target] ([target.type]) at [AREACOORD(target_turf)]" message_admins(message) log_admin(message) BLACKBOX_LOG_ADMIN_VERB("Possess Object") -/proc/release() - set name = "Release Obj" - set category = "Object" - - qdel(usr.GetComponent(/datum/component/object_possession)) +ADMIN_VERB(release, R_POSSESS, "Release Object", "Stop possessing an object.", ADMIN_CATEGORY_OBJECT) + var/possess_component = user.mob.GetComponent(/datum/component/object_possession) + if(!isnull(possess_component)) + qdel(possess_component) BLACKBOX_LOG_ADMIN_VERB("Release Object") - -/proc/give_possession_verbs(mob/dude in GLOB.mob_list) - set desc = "Give this guy possess/release verbs" - set category = "Debug" - set name = "Give Possessing Verbs" - - add_verb(dude, GLOBAL_PROC_REF(possess)) - add_verb(dude, GLOBAL_PROC_REF(release)) - BLACKBOX_LOG_ADMIN_VERB("Give Possessing Verbs") diff --git a/code/modules/admin/verbs/reestablish_db_connection.dm b/code/modules/admin/verbs/reestablish_db_connection.dm index a299eb43b0f68..5c3701c97b0cc 100644 --- a/code/modules/admin/verbs/reestablish_db_connection.dm +++ b/code/modules/admin/verbs/reestablish_db_connection.dm @@ -1,26 +1,24 @@ -/client/proc/reestablish_db_connection() - set category = "Server" - set name = "Reestablish DB Connection" +ADMIN_VERB(reestablish_db_connection, R_NONE, "Reestablish DB Connection", "Attempts to (re)establish the DB Connection", ADMIN_CATEGORY_SERVER) if (!CONFIG_GET(flag/sql_enabled)) - to_chat(usr, span_adminnotice("The Database is not enabled!"), confidential = TRUE) + to_chat(user, span_adminnotice("The Database is not enabled!"), confidential = TRUE) return if (SSdbcore.IsConnected()) - if (!check_rights(R_DEBUG,0)) - tgui_alert(usr,"The database is already connected! (Only those with +debug can force a reconnection)", "The database is already connected!") + if (!user.holder.check_for_rights(R_DEBUG)) + tgui_alert(user,"The database is already connected! (Only those with +debug can force a reconnection)", "The database is already connected!") return - var/reconnect = tgui_alert(usr,"The database is already connected! If you *KNOW* that this is incorrect, you can force a reconnection", "The database is already connected!", list("Force Reconnect", "Cancel")) + var/reconnect = tgui_alert(user,"The database is already connected! If you *KNOW* that this is incorrect, you can force a reconnection", "The database is already connected!", list("Force Reconnect", "Cancel")) if (reconnect != "Force Reconnect") return SSdbcore.Disconnect() - log_admin("[key_name(usr)] has forced the database to disconnect") - message_admins("[key_name_admin(usr)] has forced the database to disconnect!") + log_admin("[key_name(user)] has forced the database to disconnect") + message_admins("[key_name_admin(user)] has forced the database to disconnect!") BLACKBOX_LOG_ADMIN_VERB("Force Reestablished Database Connection") - log_admin("[key_name(usr)] is attempting to re-establish the DB Connection") - message_admins("[key_name_admin(usr)] is attempting to re-establish the DB Connection") + log_admin("[key_name(user)] is attempting to re-establish the DB Connection") + message_admins("[key_name_admin(user)] is attempting to re-establish the DB Connection") BLACKBOX_LOG_ADMIN_VERB("Reestablished Database Connection") SSdbcore.failed_connections = 0 diff --git a/code/modules/admin/verbs/requests.dm b/code/modules/admin/verbs/requests.dm index 2cd32648b67bf..53d3e092f8124 100644 --- a/code/modules/admin/verbs/requests.dm +++ b/code/modules/admin/verbs/requests.dm @@ -1,7 +1,4 @@ -/// Verb for opening the requests manager panel -/client/proc/requests() - set name = "Requests Manager" - set desc = "Open the request manager panel to view all requests during this round" - set category = "Admin.Game" - BLACKBOX_LOG_ADMIN_VERB("Request Manager") + +ADMIN_VERB(requests, R_NONE, "Requests Manager", "Open the request manager panel to view all requests during this round", ADMIN_CATEGORY_GAME) GLOB.requests.ui_interact(usr) + BLACKBOX_LOG_ADMIN_VERB("Request Manager") diff --git a/code/modules/admin/verbs/secrets.dm b/code/modules/admin/verbs/secrets.dm index e70138ad8ac25..b7aa16b6b5fd5 100644 --- a/code/modules/admin/verbs/secrets.dm +++ b/code/modules/admin/verbs/secrets.dm @@ -1,12 +1,9 @@ GLOBAL_DATUM(everyone_an_antag, /datum/everyone_is_an_antag_controller) -/client/proc/secrets() //Creates a verb for admins to open up the ui - set name = "Secrets" - set desc = "Abuse harder than you ever have before with this handy dandy semi-misc stuff menu" - set category = "Admin.Game" +ADMIN_VERB(secrets, R_NONE, "Secrets", "Abuse harder than you ever have before with this handy dandy semi-misc stuff menu.", ADMIN_CATEGORY_GAME) + var/datum/secrets_menu/tgui = new(user) + tgui.ui_interact(user.mob) BLACKBOX_LOG_ADMIN_VERB("Secrets Panel") - var/datum/secrets_menu/tgui = new(usr)//create the datum - tgui.ui_interact(usr)//datum has a tgui component, here we open the window /datum/secrets_menu var/client/holder //client of whoever is using this datum @@ -102,25 +99,25 @@ GLOBAL_DATUM(everyone_an_antag, /datum/everyone_is_an_antag_controller) D.cure(0) if("list_bombers") - holder.list_bombers() + holder.holder.list_bombers() if("list_signalers") - holder.list_signalers() + holder.holder.list_signalers() if("list_lawchanges") - holder.list_law_changes() + holder.holder.list_law_changes() if("showailaws") - holder.check_ai_laws() + holder.holder.list_law_changes() if("manifest") - holder.show_manifest() + holder.holder.show_manifest() if("dna") - holder.list_dna() + holder.holder.list_dna() if("fingerprints") - holder.list_fingerprints() + holder.holder.list_fingerprints() if("ctfbutton") toggle_id_ctf(holder, CTF_GHOST_CTF_GAME_ID) diff --git a/code/modules/admin/verbs/selectequipment.dm b/code/modules/admin/verbs/selectequipment.dm index 59513db012976..b94fd5cb2e455 100644 --- a/code/modules/admin/verbs/selectequipment.dm +++ b/code/modules/admin/verbs/selectequipment.dm @@ -1,10 +1,6 @@ -/client/proc/cmd_select_equipment(mob/target in GLOB.mob_list) - set category = "Admin.Events" - set name = "Select equipment" - - - var/datum/select_equipment/ui = new(usr, target) - ui.ui_interact(usr) +ADMIN_VERB_ONLY_CONTEXT_MENU(select_equipment, R_FUN, "Select Equipment", mob/target in world) + var/datum/select_equipment/ui = new(user, target) + ui.ui_interact(user.mob) /* * This is the datum housing the select equipment UI. @@ -152,7 +148,7 @@ return custom_outfit -/datum/select_equipment/ui_act(action, params) +/datum/select_equipment/ui_act(action, params, datum/tgui/ui, datum/ui_state/state) if(..()) return . = TRUE @@ -181,7 +177,7 @@ user.admin_apply_outfit(target_mob, new_outfit) if("customoutfit") - user.outfit_manager() + return SSadmin_verbs.dynamic_invoke_verb(ui.user, /datum/admin_verb/outfit_manager) if("togglefavorite") var/datum/outfit/outfit_path = resolve_outfit(params["path"]) diff --git a/code/modules/admin/verbs/server.dm b/code/modules/admin/verbs/server.dm index ee7d638960ac7..eb5684252f8c9 100644 --- a/code/modules/admin/verbs/server.dm +++ b/code/modules/admin/verbs/server.dm @@ -1,191 +1,147 @@ // Server Tab - Server Verbs -/client/proc/toggle_random_events() - set category = "Server" - set name = "Toggle random events on/off" - set desc = "Toggles random events such as meteors, black holes, blob (but not space dust) on/off" +ADMIN_VERB(toggle_random_events, R_SERVER, "Toggle Random Events", "Toggles random events on or off.", ADMIN_CATEGORY_SERVER) var/new_are = !CONFIG_GET(flag/allow_random_events) CONFIG_SET(flag/allow_random_events, new_are) - message_admins("[key_name_admin(usr)] has [new_are ? "enabled" : "disabled"] random events.") + message_admins("[key_name_admin(user)] has [new_are ? "enabled" : "disabled"] random events.") SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Random Events", "[new_are ? "Enabled" : "Disabled"]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! -/client/proc/toggle_hub() - set category = "Server" - set name = "Toggle Hub" - +ADMIN_VERB(toggle_hub, R_SERVER, "Toggle Hub", "Toggles the server's visilibility on the BYOND Hub.", ADMIN_CATEGORY_SERVER) world.update_hub_visibility(!GLOB.hub_visibility) - log_admin("[key_name(usr)] has toggled the server's hub status for the round, it is now [(GLOB.hub_visibility?"on":"off")] the hub.") - message_admins("[key_name_admin(usr)] has toggled the server's hub status for the round, it is now [(GLOB.hub_visibility?"on":"off")] the hub.") + log_admin("[key_name(user)] has toggled the server's hub status for the round, it is now [(GLOB.hub_visibility?"on":"off")] the hub.") + message_admins("[key_name_admin(user)] has toggled the server's hub status for the round, it is now [(GLOB.hub_visibility?"on":"off")] the hub.") if (GLOB.hub_visibility && !world.reachable) message_admins("WARNING: The server will not show up on the hub because byond is detecting that a filewall is blocking incoming connections.") SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggled Hub Visibility", "[GLOB.hub_visibility ? "Enabled" : "Disabled"]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! -/datum/admins/proc/restart() - set category = "Server" - set name = "Reboot World" - set desc = "Restarts the world immediately" - if (!usr.client.holder) - return - - var/localhost_addresses = list("127.0.0.1", "::1") +ADMIN_VERB(restart, R_SERVER, "Reboot World", "Restarts the world immediately.", ADMIN_CATEGORY_SERVER) var/list/options = list("Regular Restart", "Regular Restart (with delay)", "Hard Restart (No Delay/Feeback Reason)", "Hardest Restart (No actions, just reboot)") if(world.TgsAvailable()) options += "Server Restart (Kill and restart DD)"; if(SSticker.admin_delay_notice) - if(alert(usr, "Are you sure? An admin has already delayed the round end for the following reason: [SSticker.admin_delay_notice]", "Confirmation", "Yes", "No") != "Yes") + if(alert(user, "Are you sure? An admin has already delayed the round end for the following reason: [SSticker.admin_delay_notice]", "Confirmation", "Yes", "No") != "Yes") return FALSE - var/result = input(usr, "Select reboot method", "World Reboot", options[1]) as null|anything in options - if(result) - BLACKBOX_LOG_ADMIN_VERB("Reboot World") - var/init_by = "Initiated by [usr.client.holder.fakekey ? "Admin" : usr.key]." - switch(result) - if("Regular Restart") - if(!(isnull(usr.client.address) || (usr.client.address in localhost_addresses))) - if(alert(usr, "Are you sure you want to restart the server?","This server is live", "Restart", "Cancel") != "Restart") - return FALSE - SSticker.Reboot(init_by, "admin reboot - by [usr.key] [usr.client.holder.fakekey ? "(stealth)" : ""]", 10) - if("Regular Restart (with delay)") - var/delay = input("What delay should the restart have (in seconds)?", "Restart Delay", 5) as num|null - if(!delay) - return FALSE - if(!(isnull(usr.client.address) || (usr.client.address in localhost_addresses))) - if(alert(usr,"Are you sure you want to restart the server?","This server is live", "Restart", "Cancel") != "Restart") - return FALSE - SSticker.Reboot(init_by, "admin reboot - by [usr.key] [usr.client.holder.fakekey ? "(stealth)" : ""]", delay * 10) - if("Hard Restart (No Delay, No Feeback Reason)") - to_chat(world, "World reboot - [init_by]") - world.Reboot() - if("Hardest Restart (No actions, just reboot)") - to_chat(world, "Hard world reboot - [init_by]") - world.Reboot(fast_track = TRUE) - if("Server Restart (Kill and restart DD)") - to_chat(world, "Server restart - [init_by]") - world.TgsEndProcess() - -/datum/admins/proc/end_round() - set category = "Server" - set name = "End Round" - set desc = "Attempts to produce a round end report and then restart the server organically." - - if (!usr.client.holder) + var/result = input(user, "Select reboot method", "World Reboot", options[1]) as null|anything in options + if(isnull(result)) return - var/confirm = tgui_alert(usr, "End the round and restart the game world?", "End Round", list("Yes", "Cancel")) - if(confirm == "Cancel") + + BLACKBOX_LOG_ADMIN_VERB("Reboot World") + var/init_by = "Initiated by [user.holder.fakekey ? "Admin" : user.key]." + switch(result) + if("Regular Restart") + if(!user.is_localhost()) + if(alert(user, "Are you sure you want to restart the server?","This server is live", "Restart", "Cancel") != "Restart") + return FALSE + SSticker.Reboot(init_by, "admin reboot - by [user.key] [user.holder.fakekey ? "(stealth)" : ""]", 10) + if("Regular Restart (with delay)") + var/delay = input("What delay should the restart have (in seconds)?", "Restart Delay", 5) as num|null + if(!delay) + return FALSE + if(!user.is_localhost()) + if(alert(user,"Are you sure you want to restart the server?","This server is live", "Restart", "Cancel") != "Restart") + return FALSE + SSticker.Reboot(init_by, "admin reboot - by [user.key] [user.holder.fakekey ? "(stealth)" : ""]", delay * 10) + if("Hard Restart (No Delay, No Feeback Reason)") + to_chat(world, "World reboot - [init_by]") + world.Reboot() + if("Hardest Restart (No actions, just reboot)") + to_chat(world, "Hard world reboot - [init_by]") + world.Reboot(fast_track = TRUE) + if("Server Restart (Kill and restart DD)") + to_chat(world, "Server restart - [init_by]") + world.TgsEndProcess() + +ADMIN_VERB(end_round, R_SERVER, "End Round", "Forcibly ends the round and allows the server to restart normally.", ADMIN_CATEGORY_SERVER) + var/confirm = tgui_alert(user, "End the round and restart the game world?", "End Round", list("Yes", "Cancel")) + if(confirm != "Yes") return - if(confirm == "Yes") - SSticker.force_ending = FORCE_END_ROUND - BLACKBOX_LOG_ADMIN_VERB("End Round") - -/datum/admins/proc/toggleooc() - set category = "Server" - set desc = "Toggle dis bitch" - set name = "Toggle OOC" + SSticker.force_ending = FORCE_END_ROUND + BLACKBOX_LOG_ADMIN_VERB("End Round") + +ADMIN_VERB(toggle_ooc, R_ADMIN, "Toggle OOC", "Toggle the OOC channel on or off.", ADMIN_CATEGORY_SERVER) toggle_ooc() - log_admin("[key_name(usr)] toggled OOC.") - message_admins("[key_name_admin(usr)] toggled OOC.") - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle OOC", "[GLOB.ooc_allowed ? "Enabled" : "Disabled"]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! - -/datum/admins/proc/toggleoocdead() - set category = "Server" - set desc = "Toggle dis bitch" - set name = "Toggle Dead OOC" + log_admin("[key_name(user)] toggled OOC.") + message_admins("[key_name_admin(user)] toggled OOC.") + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle OOC", "[GLOB.ooc_allowed ? "Enabled" : "Disabled"]")) + +ADMIN_VERB(toggle_ooc_dead, R_ADMIN, "Toggle Dead OOC", "Toggle the OOC channel for dead players on or off.", ADMIN_CATEGORY_SERVER) toggle_dooc() + log_admin("[key_name(user)] toggled OOC.") + message_admins("[key_name_admin(user)] toggled Dead OOC.") + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Dead OOC", "[GLOB.dooc_allowed ? "Enabled" : "Disabled"]")) + +ADMIN_VERB(start_now, R_SERVER, "Start Now", "Start the round RIGHT NOW.", ADMIN_CATEGORY_SERVER) + var/static/list/waiting_states = list(GAME_STATE_PREGAME, GAME_STATE_STARTUP) + if(!(SSticker.current_state in waiting_states)) + to_chat(user, span_warning(span_red("The game has already started!"))) + return - log_admin("[key_name(usr)] toggled OOC.") - message_admins("[key_name_admin(usr)] toggled Dead OOC.") - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Dead OOC", "[GLOB.dooc_allowed ? "Enabled" : "Disabled"]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! - -/datum/admins/proc/startnow() - set category = "Server" - set desc = "Start the round RIGHT NOW" - set name = "Start Now" - if(SSticker.current_state == GAME_STATE_PREGAME || SSticker.current_state == GAME_STATE_STARTUP) - if(!SSticker.start_immediately) - var/localhost_addresses = list("127.0.0.1", "::1") - if(!(isnull(usr.client.address) || (usr.client.address in localhost_addresses))) - if(tgui_alert(usr, "Are you sure you want to start the round?","Start Now",list("Start Now","Cancel")) != "Start Now") - return FALSE - SSticker.start_immediately = TRUE - log_admin("[usr.key] has started the game.") - var/msg = "" - if(SSticker.current_state == GAME_STATE_STARTUP) - msg = " (The server is still setting up, but the round will be \ - started as soon as possible.)" - message_admins("[usr.key] has started the game.[msg]") - BLACKBOX_LOG_ADMIN_VERB("Start Now") - return TRUE + if(SSticker.start_immediately) SSticker.start_immediately = FALSE - SSticker.SetTimeLeft(1800) - to_chat(world, span_infoplain(span_bold("The game will start in 180 seconds."))) + SSticker.SetTimeLeft(3 MINUTES) + to_chat(world, span_big(span_notice("The game will start in 3 minutes."))) SEND_SOUND(world, sound('sound/ai/default/attention.ogg')) - message_admins("[usr.key] has cancelled immediate game start. Game will start in 180 seconds.") - log_admin("[usr.key] has cancelled immediate game start.") - else - to_chat(usr, "Error: Start Now: Game has already started.") - return FALSE + message_admins(span_adminnotice("[key_name_admin(user)] has cancelled immediate game start. Game will start in 3 minutes.")) + log_admin("[key_name(user)] has cancelled immediate game start.") + return -/datum/admins/proc/delay_round_end() - set category = "Server" - set desc = "Prevent the server from restarting" - set name = "Delay Round End" + if(!user.is_localhost()) + var/response = tgui_alert(user, "Are you sure you want to start the round?", "Start Now", list("Start Now", "Cancel")) + if(response != "Start Now") + return + SSticker.start_immediately = TRUE - if(!check_rights(R_SERVER)) - return + log_admin("[key_name(user)] has started the game.") + message_admins("[key_name_admin(user)] has started the game.") + if(SSticker.current_state == GAME_STATE_STARTUP) + message_admins("The server is still setting up, but the round will be started as soon as possible.") + BLACKBOX_LOG_ADMIN_VERB("Start Now") +ADMIN_VERB(delay_round_end, R_SERVER, "Delay Round End", "Prevent the server from restarting.", ADMIN_CATEGORY_SERVER) if(SSticker.delay_end) - tgui_alert(usr, "The round end is already delayed. The reason for the current delay is: \"[SSticker.admin_delay_notice]\"", "Alert", list("Ok")) + tgui_alert(user, "The round end is already delayed. The reason for the current delay is: \"[SSticker.admin_delay_notice]\"", "Alert", list("Ok")) return - var/delay_reason = input(usr, "Enter a reason for delaying the round end", "Round Delay Reason") as null|text + var/delay_reason = input(user, "Enter a reason for delaying the round end", "Round Delay Reason") as null|text if(isnull(delay_reason)) return if(SSticker.delay_end) - tgui_alert(usr, "The round end is already delayed. The reason for the current delay is: \"[SSticker.admin_delay_notice]\"", "Alert", list("Ok")) + tgui_alert(user, "The round end is already delayed. The reason for the current delay is: \"[SSticker.admin_delay_notice]\"", "Alert", list("Ok")) return SSticker.delay_end = TRUE SSticker.admin_delay_notice = delay_reason - log_admin("[key_name(usr)] delayed the round end for reason: [SSticker.admin_delay_notice]") - message_admins("[key_name_admin(usr)] delayed the round end for reason: [SSticker.admin_delay_notice]") + log_admin("[key_name(user)] delayed the round end for reason: [SSticker.admin_delay_notice]") + message_admins("[key_name_admin(user)] delayed the round end for reason: [SSticker.admin_delay_notice]") SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Delay Round End", "Reason: [delay_reason]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! -/datum/admins/proc/toggleenter() - set category = "Server" - set desc = "People can't enter" - set name = "Toggle Entering" +ADMIN_VERB(toggle_enter, R_SERVER, "Toggle Entering", "Toggle the ability to enter the game.", ADMIN_CATEGORY_SERVER) if(!SSlag_switch.initialized) return SSlag_switch.set_measure(DISABLE_NON_OBSJOBS, !SSlag_switch.measures[DISABLE_NON_OBSJOBS]) - log_admin("[key_name(usr)] toggled new player game entering. Lag Switch at index ([DISABLE_NON_OBSJOBS])") - message_admins("[key_name_admin(usr)] toggled new player game entering [SSlag_switch.measures[DISABLE_NON_OBSJOBS] ? "OFF" : "ON"].") + log_admin("[key_name(user)] toggled new player game entering. Lag Switch at index ([DISABLE_NON_OBSJOBS])") + message_admins("[key_name_admin(user)] toggled new player game entering [SSlag_switch.measures[DISABLE_NON_OBSJOBS] ? "OFF" : "ON"].") SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Entering", "[!SSlag_switch.measures[DISABLE_NON_OBSJOBS] ? "Enabled" : "Disabled"]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! -/datum/admins/proc/toggleAI() - set category = "Server" - set desc = "People can't be AI" - set name = "Toggle AI" +ADMIN_VERB(toggle_ai, R_SERVER, "Toggle AI", "Toggle the ability to choose AI jobs.", ADMIN_CATEGORY_SERVER) var/alai = CONFIG_GET(flag/allow_ai) CONFIG_SET(flag/allow_ai, !alai) if (alai) to_chat(world, span_bold("The AI job is no longer chooseable."), confidential = TRUE) else - to_chat(world, span_bold("The AI job is chooseable now."), confidential = TRUE) - log_admin("[key_name(usr)] toggled AI allowed.") + to_chat(world, "The AI job is chooseable now.", confidential = TRUE) + log_admin("[key_name(user)] toggled AI allowed.") world.update_status() SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle AI", "[!alai ? "Disabled" : "Enabled"]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! -/datum/admins/proc/toggleaban() - set category = "Server" - set desc = "Respawn basically" - set name = "Toggle Respawn" - +ADMIN_VERB(toggle_respawn, R_SERVER, "Toggle Respawn", "Toggle the ability to respawn.", ADMIN_CATEGORY_SERVER) var/respawn_state = CONFIG_GET(flag/allow_respawn) var/new_state = -1 var/new_state_text = "" @@ -203,80 +159,71 @@ if(RESPAWN_FLAG_NEW_CHARACTER) // respawn currently enabled for different slot characters only new_state = RESPAWN_FLAG_DISABLED new_state_text = "Disabled" - to_chat(world, span_bold("You may no longer respawn :("), confidential = TRUE) + to_chat(world, span_bold("You may no longer respawn."), confidential = TRUE) else WARNING("Invalid respawn state in config: [respawn_state]") if(new_state == -1) - to_chat(usr, span_warning("The config for respawn is set incorrectly, please complain to your nearest server host (or fix it yourself). \ + to_chat(user, span_warning("The config for respawn is set incorrectly, please complain to your nearest server host (or fix it yourself). \ In the meanwhile respawn has been set to \"Off\".")) new_state = RESPAWN_FLAG_DISABLED new_state_text = "Disabled" CONFIG_SET(flag/allow_respawn, new_state) - message_admins(span_adminnotice("[key_name_admin(usr)] toggled respawn to \"[new_state_text]\".")) - log_admin("[key_name(usr)] toggled respawn to \"[new_state_text]\".") + message_admins(span_adminnotice("[key_name_admin(user)] toggled respawn to \"[new_state_text]\".")) + log_admin("[key_name(user)] toggled respawn to \"[new_state_text]\".") world.update_status() SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Respawn", "[new_state_text]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! -/datum/admins/proc/delay() - set category = "Server" - set desc = "Delay the game start" - set name = "Delay Pre-Game" - - var/newtime = input("Set a new time in seconds. Set -1 for indefinite delay.","Set Delay",round(SSticker.GetTimeLeft()/10)) as num|null +ADMIN_VERB(delay, R_SERVER, "Delay Pre-Game", "Delay the game start.", ADMIN_CATEGORY_SERVER) + var/newtime = input(user, "Set a new time in seconds. Set -1 for indefinite delay.", "Set Delay", round(SSticker.GetTimeLeft()/10)) as num|null if(!newtime) return if(SSticker.current_state > GAME_STATE_PREGAME) - return tgui_alert(usr, "Too late... The game has already started!") + return tgui_alert(user, "Too late... The game has already started!") newtime = newtime*10 SSticker.SetTimeLeft(newtime) SSticker.start_immediately = FALSE if(newtime < 0) - to_chat(world, span_infoplain(span_bold("The game start has been delayed.")), confidential = TRUE) - log_admin("[key_name(usr)] delayed the round start.") + to_chat(world, "The game start has been delayed.", confidential = TRUE) + log_admin("[key_name(user)] delayed the round start.") else to_chat(world, span_infoplain(span_bold("The game will start in [DisplayTimeText(newtime)].")), confidential = TRUE) SEND_SOUND(world, sound('sound/ai/default/attention.ogg')) - log_admin("[key_name(usr)] set the pre-game delay to [DisplayTimeText(newtime)].") + log_admin("[key_name(user)] set the pre-game delay to [DisplayTimeText(newtime)].") BLACKBOX_LOG_ADMIN_VERB("Delay Game Start") -/datum/admins/proc/set_admin_notice() - set category = "Server" - set name = "Set Admin Notice" - set desc ="Set an announcement that appears to everyone who joins the server. Only lasts this round" - if(!check_rights(0)) - return - - var/new_admin_notice = input(src,"Set a public notice for this round. Everyone who joins the server will see it.\n(Leaving it blank will delete the current notice):","Set Notice",GLOB.admin_notice) as message|null +ADMIN_VERB(set_admin_notice, R_SERVER, "Set Admin Notice", "Set an announcement that appears to everyone who joins the server. Only lasts this round.", ADMIN_CATEGORY_SERVER) + var/new_admin_notice = input( + user, + "Set a public notice for this round. Everyone who joins the server will see it.\n(Leaving it blank will delete the current notice):", + "Set Notice", + GLOB.admin_notice, + ) as message|null if(new_admin_notice == null) return if(new_admin_notice == GLOB.admin_notice) return if(new_admin_notice == "") - message_admins("[key_name(usr)] removed the admin notice.") - log_admin("[key_name(usr)] removed the admin notice:\n[GLOB.admin_notice]") + message_admins("[key_name(user)] removed the admin notice.") + log_admin("[key_name(user)] removed the admin notice:\n[GLOB.admin_notice]") else - message_admins("[key_name(usr)] set the admin notice.") - log_admin("[key_name(usr)] set the admin notice:\n[new_admin_notice]") + message_admins("[key_name(user)] set the admin notice.") + log_admin("[key_name(user)] set the admin notice:\n[new_admin_notice]") to_chat(world, span_adminnotice("Admin Notice:\n \t [new_admin_notice]"), confidential = TRUE) BLACKBOX_LOG_ADMIN_VERB("Set Admin Notice") GLOB.admin_notice = new_admin_notice - return -/datum/admins/proc/toggleguests() - set category = "Server" - set desc = "Guests can't enter" - set name = "Toggle guests" +ADMIN_VERB(toggle_guests, R_SERVER, "Toggle Guests", "Toggle the ability for guests to enter the game.", ADMIN_CATEGORY_SERVER) var/new_guest_ban = !CONFIG_GET(flag/guest_ban) CONFIG_SET(flag/guest_ban, new_guest_ban) if (new_guest_ban) to_chat(world, span_bold("Guests may no longer enter the game."), confidential = TRUE) else - to_chat(world, span_bold("Guests may now enter the game."), confidential = TRUE) - log_admin("[key_name(usr)] toggled guests game entering [!new_guest_ban ? "" : "dis"]allowed.") - message_admins(span_adminnotice("[key_name_admin(usr)] toggled guests game entering [!new_guest_ban ? "" : "dis"]allowed.")) + to_chat(world, "Guests may now enter the game.", confidential = TRUE) + log_admin("[key_name(user)] toggled guests game entering [!new_guest_ban ? "" : "dis"]allowed.") + message_admins(span_adminnotice("[key_name_admin(user)] toggled guests game entering [!new_guest_ban ? "" : "dis"]allowed.")) SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Guests", "[!new_guest_ban ? "Enabled" : "Disabled"]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! diff --git a/code/modules/admin/verbs/shuttlepanel.dm b/code/modules/admin/verbs/shuttlepanel.dm index d3cccafa68356..ae0ad4dcde3c5 100644 --- a/code/modules/admin/verbs/shuttlepanel.dm +++ b/code/modules/admin/verbs/shuttlepanel.dm @@ -1,13 +1,5 @@ -/datum/admins/proc/open_shuttlepanel() - set category = "Admin.Events" - set name = "Shuttle Manipulator" - set desc = "Opens the shuttle manipulator UI." - - if(!check_rights(R_ADMIN)) - return - - SSshuttle.ui_interact(usr) - +ADMIN_VERB(shuttle_panel, R_ADMIN, "Shuttle Manipulator", "Opens the shuttle manipulator UI.", ADMIN_CATEGORY_EVENTS) + SSshuttle.ui_interact(user.mob) /obj/docking_port/mobile/proc/admin_fly_shuttle(mob/user) var/list/options = list() diff --git a/code/modules/admin/verbs/spawnobjasmob.dm b/code/modules/admin/verbs/spawnobjasmob.dm index 924c9885713ad..e673202f0bae1 100644 --- a/code/modules/admin/verbs/spawnobjasmob.dm +++ b/code/modules/admin/verbs/spawnobjasmob.dm @@ -1,11 +1,4 @@ -/datum/admins/proc/spawn_objasmob(object as text) - set category = "Debug" - set desc = "(obj path) Spawn object-mob" - set name = "Spawn object-mob" - - if(!check_rights(R_SPAWN)) - return - +ADMIN_VERB(spawn_obj_as_mob, R_SPAWN, "Spawn Object-Mob", "Spawn an object as if it were a mob.", ADMIN_CATEGORY_DEBUG, object as text) var/chosen = pick_closest_path(object, make_types_fancy(subtypesof(/obj))) if (!chosen) @@ -15,21 +8,63 @@ var/obj/chosen_obj = text2path(chosen) - var/list/settings = list( - "mainsettings" = list( - "name" = list("desc" = "Name", "type" = "string", "value" = "Bob"), - "maxhealth" = list("desc" = "Max. health", "type" = "number", "value" = 100), - "access" = list("desc" = "Access ID", "type" = "datum", "path" = "/obj/item/card/id", "value" = "Default"), - "objtype" = list("desc" = "Base obj type", "type" = "datum", "path" = "/obj", "value" = "[chosen]"), - "googlyeyes" = list("desc" = "Googly eyes", "type" = "boolean", "value" = "No"), - "disableai" = list("desc" = "Disable AI", "type" = "boolean", "value" = "Yes"), - "idledamage" = list("desc" = "Damaged while idle", "type" = "boolean", "value" = "No"), - "dropitem" = list("desc" = "Drop obj on death", "type" = "boolean", "value" = "Yes"), - "mobtype" = list("desc" = "Base mob type", "type" = "datum", "path" = "/mob/living/simple_animal/hostile/mimic/copy", "value" = "/mob/living/simple_animal/hostile/mimic/copy"), - "ckey" = list("desc" = "ckey", "type" = "ckey", "value" = "none"), + var/list/settings = list("mainsettings" = list( + "name" = list( + "desc" = "Name", + "type" = "string", + "value" = "Bob", + ), + "maxhealth" = list( + "desc" = "Max. health", + "type" = "number", + "value" = 100, + ), + "access" = list( + "desc" = "Access ID", + "type" = "datum", + "path" = "/obj/item/card/id", + "value" = "Default", + ), + "objtype" = list( + "desc" = "Base obj type", + "type" = "datum", + "path" = "/obj", + "value" = "[chosen]", + ), + "googlyeyes" = list( + "desc" = "Googly eyes", + "type" = "boolean", + "value" = "No", + ), + "disableai" = list( + "desc" = "Disable AI", + "type" = "boolean", + "value" = "Yes", + ), + "idledamage" = list( + "desc" = "Damaged while idle", + "type" = "boolean", + "value" = "No", + ), + "dropitem" = list( + "desc" = "Drop obj on death", + "type" = "boolean", + "value" = "Yes", + ), + "mobtype" = list( + "desc" = "Base mob type", + "type" = "datum", + "path" = "/mob/living/simple_animal/hostile/mimic/copy", + "value" = "/mob/living/simple_animal/hostile/mimic/copy", + ), + "ckey" = list( + "desc" = "ckey", + "type" = "ckey", + "value" = "none", + ), )) - var/list/prefreturn = presentpreflikepicker(usr,"Customize mob", "Customize mob", Button1="Ok", width = 450, StealFocus = 1,Timeout = 0, settings=settings) + var/list/prefreturn = presentpreflikepicker(user.mob,"Customize mob", "Customize mob", Button1="Ok", width = 450, StealFocus = 1,Timeout = 0, settings=settings) if (prefreturn["button"] == 1) settings = prefreturn["settings"] var/mainsettings = settings["mainsettings"] @@ -37,9 +72,9 @@ basemob = text2path(mainsettings["mobtype"]["value"]) if (!ispath(basemob, /mob/living/simple_animal/hostile/mimic/copy) || !ispath(chosen_obj, /obj)) - to_chat(usr, "Mob or object path invalid", confidential = TRUE) + to_chat(user.mob, "Mob or object path invalid", confidential = TRUE) - basemob = new basemob(get_turf(usr), new chosen_obj(get_turf(usr)), usr, mainsettings["dropitem"]["value"] == "Yes" ? FALSE : TRUE, (mainsettings["googlyeyes"]["value"] == "Yes" ? FALSE : TRUE)) + basemob = new basemob(get_turf(user.mob), new chosen_obj(get_turf(user.mob)), user.mob, mainsettings["dropitem"]["value"] == "Yes" ? FALSE : TRUE, (mainsettings["googlyeyes"]["value"] == "Yes" ? FALSE : TRUE)) if (mainsettings["disableai"]["value"] == "Yes") basemob.toggle_ai(AI_OFF) @@ -65,5 +100,5 @@ basemob.ckey = mainsettings["ckey"]["value"] - log_admin("[key_name(usr)] spawned a sentient object-mob [basemob] from [chosen_obj] at [AREACOORD(usr)]") + log_admin("[key_name(user.mob)] spawned a sentient object-mob [basemob] from [chosen_obj] at [AREACOORD(user.mob)]") BLACKBOX_LOG_ADMIN_VERB("Spawn object-mob") diff --git a/code/modules/admin/verbs/special_verbs.dm b/code/modules/admin/verbs/special_verbs.dm new file mode 100644 index 0000000000000..309c14d4455f6 --- /dev/null +++ b/code/modules/admin/verbs/special_verbs.dm @@ -0,0 +1,43 @@ +// Admin Verbs in this file are special and cannot use the AVD system for some reason or another. + +/client/proc/show_verbs() + set name = "Adminverbs - Show" + set category = ADMIN_CATEGORY_MAIN + + remove_verb(src, /client/proc/show_verbs) + add_admin_verbs() + + to_chat(src, span_interface("All of your adminverbs are now visible."), confidential = TRUE) + BLACKBOX_LOG_ADMIN_VERB("Show Adminverbs") + +/client/proc/readmin() + set name = "Readmin" + set category = "Admin" + set desc = "Regain your admin powers." + + var/datum/admins/A = GLOB.deadmins[ckey] + + if(!A) + A = GLOB.admin_datums[ckey] + if (!A) + var/msg = " is trying to readmin but they have no deadmin entry" + message_admins("[key_name_admin(src)][msg]") + log_admin_private("[key_name(src)][msg]") + return + + A.associate(src) + + if (!holder) + return //This can happen if an admin attempts to vv themself into somebody elses's deadmin datum by getting ref via brute force + + to_chat(src, span_interface("You are now an admin."), confidential = TRUE) + message_admins("[src] re-adminned themselves.") + log_admin("[src] re-adminned themselves.") + BLACKBOX_LOG_ADMIN_VERB("Readmin") + +/client/proc/admin_2fa_verify() + set name = "Verify Admin" + set category = "Admin" + + var/datum/admins/admin = GLOB.admin_datums[ckey] + admin?.associate(src) diff --git a/code/modules/admin/view_variables/mark_datum.dm b/code/modules/admin/view_variables/mark_datum.dm index 44c3b2b83b21a..1d9dd3a1a37ce 100644 --- a/code/modules/admin/view_variables/mark_datum.dm +++ b/code/modules/admin/view_variables/mark_datum.dm @@ -8,10 +8,8 @@ holder.RegisterSignal(holder.marked_datum, COMSIG_QDELETING, TYPE_PROC_REF(/datum/admins, handle_marked_del)) vv_update_display(D, "marked", VV_MSG_MARKED) -/client/proc/mark_datum_mapview(datum/D as mob|obj|turf|area in view(view)) - set category = "Debug" - set name = "Mark Object" - mark_datum(D) +ADMIN_VERB_ONLY_CONTEXT_MENU(mark_datum, R_NONE, "Mark Object", datum/target as mob|obj|turf|area in view()) + user.mark_datum(target) /datum/admins/proc/handle_marked_del(datum/source) SIGNAL_HANDLER diff --git a/code/modules/admin/view_variables/tag_datum.dm b/code/modules/admin/view_variables/tag_datum.dm index 3b611e3cdf934..b4ca42860c341 100644 --- a/code/modules/admin/view_variables/tag_datum.dm +++ b/code/modules/admin/view_variables/tag_datum.dm @@ -12,7 +12,5 @@ else holder.add_tagged_datum(target_datum) -/client/proc/tag_datum_mapview(datum/target_datum as mob|obj|turf|area in view(view)) - set category = "Debug" - set name = "Tag Datum" - tag_datum(target_datum) +ADMIN_VERB_ONLY_CONTEXT_MENU(tag_datum, R_NONE, "Tag Datum", datum/target_datum as mob|obj|turf|area in view()) + user.tag_datum(target_datum) diff --git a/code/modules/admin/view_variables/topic_basic.dm b/code/modules/admin/view_variables/topic_basic.dm index 8a27d34257810..4f36365312701 100644 --- a/code/modules/admin/view_variables/topic_basic.dm +++ b/code/modules/admin/view_variables/topic_basic.dm @@ -140,6 +140,7 @@ return var/datum/greyscale_modify_menu/menu = new(target, usr, SSgreyscale.configurations, unlocked = TRUE) menu.ui_interact(usr) + if(href_list[VV_HK_CALLPROC]) - usr.client.callproc_datum(target) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/call_proc_datum, target) diff --git a/code/modules/admin/view_variables/view_variables.dm b/code/modules/admin/view_variables/view_variables.dm index 9f0d86e04f656..b139ec9d488ca 100644 --- a/code/modules/admin/view_variables/view_variables.dm +++ b/code/modules/admin/view_variables/view_variables.dm @@ -1,3 +1,7 @@ +ADMIN_VERB_AND_CONTEXT_MENU(debug_variables, R_NONE, "View Variables", "View the variables of a datum.", ADMIN_CATEGORY_DEBUG, datum/thing in world) + user.debug_variables(thing) + +// This is kept as a seperate proc because admins are able to show VV to non-admins /client/proc/debug_variables(datum/thing in world) set category = "Debug" set name = "View Variables" diff --git a/code/modules/antagonists/traitor/balance_helper.dm b/code/modules/antagonists/traitor/balance_helper.dm index e78625ff1c1c5..b2a9661bfeb59 100644 --- a/code/modules/antagonists/traitor/balance_helper.dm +++ b/code/modules/antagonists/traitor/balance_helper.dm @@ -1,11 +1,5 @@ -/client/proc/cmd_admin_debug_traitor_objectives() - set name = "Debug Traitor Objectives" - set category = "Debug" - - if(!check_rights(R_DEBUG)) - return - - SStraitor.traitor_debug_panel?.ui_interact(usr) +ADMIN_VERB(debug_traitor_objectives, R_DEBUG, "Debug Traitor Objectives", "Verify functionality of traitor goals.", ADMIN_CATEGORY_DEBUG) + SStraitor.traitor_debug_panel?.ui_interact(user.mob) /datum/traitor_objective_debug var/list/all_objectives diff --git a/code/modules/atmospherics/machinery/pipes/pipe_spritesheet_helper.dm b/code/modules/atmospherics/machinery/pipes/pipe_spritesheet_helper.dm index 6b1997cc3c718..75c85d2a665f4 100644 --- a/code/modules/atmospherics/machinery/pipes/pipe_spritesheet_helper.dm +++ b/code/modules/atmospherics/machinery/pipes/pipe_spritesheet_helper.dm @@ -1,7 +1,4 @@ -/client/proc/GeneratePipeSpritesheet() - set name = "Generate Pipe Spritesheet" - set category = "Debug" - +ADMIN_VERB(generate_pipe_spritesheet, R_DEBUG, "Generate Pipe Spritesheet", "Generates the pipe spritesheets.", ADMIN_CATEGORY_DEBUG) var/datum/pipe_icon_generator/generator = new generator.Start() fcopy(generator.generated_icons, "icons/obj/pipes_n_cables/!pipes_bitmask.dmi") diff --git a/code/modules/cargo/centcom_podlauncher.dm b/code/modules/cargo/centcom_podlauncher.dm index 218aed8c681b4..cf4a5dfc8759f 100644 --- a/code/modules/cargo/centcom_podlauncher.dm +++ b/code/modules/cargo/centcom_podlauncher.dm @@ -16,11 +16,8 @@ //The user can change properties of the supplypod using the UI, and change the way that items are taken from the bay (One at a time, ordered, random, etc) //Many of the effects of the supplypod set here are put into action in supplypod.dm -/client/proc/centcom_podlauncher() //Creates a verb for admins to open up the ui - set name = "Config/Launch Supplypod" - set desc = "Configure and launch a CentCom supplypod full of whatever your heart desires!" - set category = "Admin.Events" - new /datum/centcom_podlauncher(usr)//create the datum +ADMIN_VERB(centcom_podlauncher, R_ADMIN, "Config/Launch Supplypod", "Configure and launch a CentCom supplypod full of whatever your heart desires!", ADMIN_CATEGORY_EVENTS) + new /datum/centcom_podlauncher(user.mob) //Variables declared to change how items in the launch bay are picked and launched. (Almost) all of these are changed in the ui_act proc //Some effect groups are choices, while other are booleans. This is because some effects can stack, while others dont (ex: you can stack explosion and quiet, but you cant stack ordered launch and random launch) diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index a5753fc6f3340..d42c726940519 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -153,6 +153,15 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( to_chat(src, "Become a BYOND member to access member-perks and features, as well as support the engine that makes this game possible. Only 10 bucks for 3 months! Click Here to find out more.") return FALSE return TRUE + +/client/proc/is_localhost() + var/static/localhost_addresses = list( + "127.0.0.1", + "::1", + null, + ) + return address in localhost_addresses + /* * Call back proc that should be checked in all paths where a client can send messages * @@ -250,27 +259,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( GLOB.ahelp_tickets.ClientLogin(src) GLOB.interviews.client_login(src) GLOB.requests.client_login(src) - var/connecting_admin = FALSE //because de-admined admins connecting should be treated like admins. - //Admin Authorisation - var/datum/admins/admin_datum = GLOB.admin_datums[ckey] - if (!isnull(admin_datum)) - admin_datum.associate(src) - connecting_admin = TRUE - else if(GLOB.deadmins[ckey]) - add_verb(src, /client/proc/readmin) - connecting_admin = TRUE - if(CONFIG_GET(flag/autoadmin)) - if(!GLOB.admin_datums[ckey]) - var/list/autoadmin_ranks = ranks_from_rank_name(CONFIG_GET(string/autoadmin_rank)) - if (autoadmin_ranks.len == 0) - to_chat(GLOB.admins, "Autoadmin rank not found") - else - new /datum/admins(autoadmin_ranks, ckey) - if(CONFIG_GET(flag/enable_localhost_rank) && !connecting_admin) - var/localhost_addresses = list("127.0.0.1", "::1") - if(isnull(address) || (address in localhost_addresses)) - var/datum/admin_rank/localhost_rank = new("!localhost!", R_EVERYTHING, R_DBRANKS, R_EVERYTHING) //+EVERYTHING -DBRANKS *EVERYTHING - new /datum/admins(list(localhost_rank), ckey, 1, 1) //preferences datum - also holds some persistent data for the client (because we may as well keep these datums to a minimum) prefs = GLOB.preferences_datums[ckey] if(prefs) @@ -343,6 +331,29 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( . = ..() //calls mob.Login() + + // Admin Verbs need the client's mob to exist. Must be after ..() + var/connecting_admin = FALSE //because de-admined admins connecting should be treated like admins. + //Admin Authorisation + var/datum/admins/admin_datum = GLOB.admin_datums[ckey] + if (!isnull(admin_datum)) + admin_datum.associate(src) + connecting_admin = TRUE + else if(GLOB.deadmins[ckey]) + add_verb(src, /client/proc/readmin) + connecting_admin = TRUE + if(CONFIG_GET(flag/autoadmin)) + if(!GLOB.admin_datums[ckey]) + var/list/autoadmin_ranks = ranks_from_rank_name(CONFIG_GET(string/autoadmin_rank)) + if (autoadmin_ranks.len == 0) + to_chat(world, "Autoadmin rank not found") + else + new /datum/admins(autoadmin_ranks, ckey) + + if(CONFIG_GET(flag/enable_localhost_rank) && !connecting_admin && is_localhost()) + var/datum/admin_rank/localhost_rank = new("!localhost!", R_EVERYTHING, R_DBRANKS, R_EVERYTHING) //+EVERYTHING -DBRANKS *EVERYTHING + new /datum/admins(list(localhost_rank), ckey, 1, 1) + if (length(GLOB.stickybanadminexemptions)) GLOB.stickybanadminexemptions -= ckey if (!length(GLOB.stickybanadminexemptions)) @@ -1175,13 +1186,10 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( /// Attempts to make the client orbit the given object, for administrative purposes. /// If they are not an observer, will try to aghost them. /client/proc/admin_follow(atom/movable/target) - var/can_ghost = TRUE - - if (!isobserver(mob)) - can_ghost = admin_ghost() - - if(!can_ghost) - return FALSE + if(!isobserver(mob)) + SSadmin_verbs.dynamic_invoke_verb(src, /datum/admin_verb/admin_ghost) + if(!isobserver(mob)) + return var/mob/dead/observer/observer = mob observer.ManualFollow(target) diff --git a/code/modules/client/verbs/ooc.dm b/code/modules/client/verbs/ooc.dm index 1009cc8a6afd7..49583ce70152a 100644 --- a/code/modules/client/verbs/ooc.dm +++ b/code/modules/client/verbs/ooc.dm @@ -139,33 +139,28 @@ GLOBAL_VAR_INIT(normal_ooc_colour, "#002eb8") set category = "Server" if(IsAdminAdvancedProcCall()) return - var/newColor = input(src, "Please select the new player OOC color.", "OOC color") as color|null + +ADMIN_VERB(set_ooc_color, R_FUN, "Set Player OOC Color", "Modifies the global OOC color.", ADMIN_CATEGORY_SERVER) + var/newColor = input(user, "Please select the new player OOC color.", "OOC color") as color|null if(isnull(newColor)) return - if(!check_rights(R_FUN)) - message_admins("[usr.key] has attempted to use the Set Player OOC Color verb!") - log_admin("[key_name(usr)] tried to set player ooc color without authorization.") - return var/new_color = sanitize_color(newColor) - message_admins("[key_name_admin(usr)] has set the players' ooc color to [new_color].") - log_admin("[key_name_admin(usr)] has set the player ooc color to [new_color].") + message_admins("[key_name_admin(user)] has set the players' ooc color to [new_color].") + log_admin("[key_name_admin(user)] has set the player ooc color to [new_color].") GLOB.OOC_COLOR = new_color - /client/proc/reset_ooc() set name = "Reset Player OOC Color" set desc = "Returns player OOC Color to default" set category = "Server" if(IsAdminAdvancedProcCall()) return - if(tgui_alert(usr, "Are you sure you want to reset the OOC color of all players?", "Reset Player OOC Color", list("Yes", "No")) != "Yes") - return - if(!check_rights(R_FUN)) - message_admins("[usr.key] has attempted to use the Reset Player OOC Color verb!") - log_admin("[key_name(usr)] tried to reset player ooc color without authorization.") + +ADMIN_VERB(reset_ooc_color, R_FUN, "Reset Player OOC Color", "Returns player OOC color to default.", ADMIN_CATEGORY_SERVER) + if(tgui_alert(user, "Are you sure you want to reset the OOC color of all players?", "Reset Player OOC Color", list("Yes", "No")) != "Yes") return - message_admins("[key_name_admin(usr)] has reset the players' ooc color.") - log_admin("[key_name_admin(usr)] has reset player ooc color.") + message_admins("[key_name_admin(user)] has reset the players' ooc color.") + log_admin("[key_name_admin(user)] has reset player ooc color.") GLOB.OOC_COLOR = null //Checks admin notice diff --git a/code/modules/explorer_drone/manager.dm b/code/modules/explorer_drone/manager.dm index 00909d03abf9d..ee51a2d5db398 100644 --- a/code/modules/explorer_drone/manager.dm +++ b/code/modules/explorer_drone/manager.dm @@ -83,11 +83,6 @@ . = ..() QDEL_NULL(temp_adventure) -/client/proc/adventure_manager() - set category = "Debug" - set name = "Adventure Manager" - - if(!check_rights(R_DEBUG)) - return +ADMIN_VERB(adventure_manager, R_DEBUG, "Adventure Manager", "View and edit adventures.", ADMIN_CATEGORY_DEBUG) var/datum/adventure_browser/browser = new() - browser.ui_interact(usr) + browser.ui_interact(user.mob) diff --git a/code/modules/fishing/admin.dm b/code/modules/fishing/admin.dm index d1d2c0ae2c574..0a9cfc9d51dd9 100644 --- a/code/modules/fishing/admin.dm +++ b/code/modules/fishing/admin.dm @@ -1,12 +1,6 @@ -// Helper tool to see fishing probabilities with different setups -/datum/admins/proc/fishing_calculator() - set name = "Fishing Calculator" - set category = "Debug" - - if(!check_rights(R_DEBUG)) - return - var/datum/fishing_calculator/ui = new(usr) - ui.ui_interact(usr) +ADMIN_VERB(fishing_calculator, R_DEBUG, "Fishing Calculator", "A calculator... for fishes?", ADMIN_CATEGORY_DEBUG) + var/datum/fishing_calculator/ui = new + ui.ui_interact(user.mob) /datum/fishing_calculator var/list/current_table diff --git a/code/modules/logging/log_holder.dm b/code/modules/logging/log_holder.dm index 20ff2c866b308..85a436076c84e 100644 --- a/code/modules/logging/log_holder.dm +++ b/code/modules/logging/log_holder.dm @@ -32,10 +32,8 @@ GLOBAL_REAL(logger, /datum/log_holder) GENERAL_PROTECT_DATUM(/datum/log_holder) -/client/proc/log_viewer_new() - set name = "View Round Logs" - set category = "Admin" - logger.ui_interact(mob) +ADMIN_VERB(log_viewer_new, R_ADMIN|R_DEBUG, "View Round Logs", "View the rounds logs.", ADMIN_CATEGORY_MAIN) + logger.ui_interact(user.mob) /datum/log_holder/ui_interact(mob/user, datum/tgui/ui) if(!check_rights_for(user.client, R_ADMIN)) diff --git a/code/modules/mob/dead/observer/observer_say.dm b/code/modules/mob/dead/observer/observer_say.dm index e3a5ff3cdf07a..a8fd0094934c3 100644 --- a/code/modules/mob/dead/observer/observer_say.dm +++ b/code/modules/mob/dead/observer/observer_say.dm @@ -44,9 +44,9 @@ message = trim_left(copytext_char(message, length(message_mods[RADIO_KEY]) + 2)) switch(message_mods[RADIO_EXTENSION]) if(MODE_ADMIN) - client.cmd_admin_say(message) + SSadmin_verbs.dynamic_invoke_verb(client, /datum/admin_verb/cmd_admin_say, message) if(MODE_DEADMIN) - client.dsay(message) + SSadmin_verbs.dynamic_invoke_verb(client, /datum/admin_verb/dsay, message) if(MODE_PUPPET) if(!mind.current.say(message)) to_chat(src, span_warning("Your linked body was unable to speak!")) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index cd97eba3c9eaf..670f98fed05bd 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -1161,9 +1161,7 @@ admin_ticket_log("[key_name_admin(usr)] has attempted to modify the bodyparts of [src]") if(href_list[VV_HK_MODIFY_ORGANS]) - if(!check_rights(NONE)) - return - usr.client.manipulate_organs(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/manipulate_organs, src) if(href_list[VV_HK_MARTIAL_ART]) if(!check_rights(NONE)) diff --git a/code/modules/mob/living/living_say.dm b/code/modules/mob/living/living_say.dm index 5ce6aa04379b3..445d791a8c409 100644 --- a/code/modules/mob/living/living_say.dm +++ b/code/modules/mob/living/living_say.dm @@ -122,11 +122,11 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list( return if(message_mods[RADIO_EXTENSION] == MODE_ADMIN) - client?.cmd_admin_say(message) + SSadmin_verbs.dynamic_invoke_verb(client, /datum/admin_verb/cmd_admin_say, message) return if(message_mods[RADIO_EXTENSION] == MODE_DEADMIN) - client?.dsay(message) + SSadmin_verbs.dynamic_invoke_verb(client, /datum/admin_verb/dsay, message) return // dead is the only state you can never emote diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index e2d5d638f4073..7577563c6df9e 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1414,9 +1414,7 @@ regenerate_icons() if(href_list[VV_HK_PLAYER_PANEL]) - if(!check_rights(NONE)) - return - usr.client.holder.show_player_panel(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/show_player_panel, src) if(href_list[VV_HK_GODMODE]) if(!check_rights(R_ADMIN)) @@ -1424,34 +1422,22 @@ usr.client.cmd_admin_godmode(src) if(href_list[VV_HK_GIVE_MOB_ACTION]) - if(!check_rights(NONE)) - return - usr.client.give_mob_action(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/give_mob_action, src) if(href_list[VV_HK_REMOVE_MOB_ACTION]) - if(!check_rights(NONE)) - return - usr.client.remove_mob_action(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/remove_mob_action, src) if(href_list[VV_HK_GIVE_SPELL]) - if(!check_rights(NONE)) - return - usr.client.give_spell(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/give_spell, src) if(href_list[VV_HK_REMOVE_SPELL]) - if(!check_rights(NONE)) - return - usr.client.remove_spell(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/remove_spell, src) if(href_list[VV_HK_GIVE_DISEASE]) - if(!check_rights(NONE)) - return - usr.client.give_disease(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/give_disease, src) if(href_list[VV_HK_GIB]) - if(!check_rights(R_FUN)) - return - usr.client.cmd_admin_gib(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/gib_them, src) if(href_list[VV_HK_BUILDMODE]) if(!check_rights(R_BUILD)) @@ -1459,19 +1445,13 @@ togglebuildmode(src) if(href_list[VV_HK_DROP_ALL]) - if(!check_rights(NONE)) - return - usr.client.cmd_admin_drop_everything(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/drop_everything, src) if(href_list[VV_HK_DIRECT_CONTROL]) - if(!check_rights(NONE)) - return - usr.client.cmd_assume_direct_control(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/cmd_assume_direct_control, src) if(href_list[VV_HK_GIVE_DIRECT_CONTROL]) - if(!check_rights(NONE)) - return - usr.client.cmd_give_direct_control(src) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/cmd_give_direct_control, src) if(href_list[VV_HK_OFFER_GHOSTS]) if(!check_rights(NONE)) diff --git a/code/modules/procedural_mapping/mapGenerator.dm b/code/modules/procedural_mapping/mapGenerator.dm index 420ac9c8d7976..58ff564190702 100644 --- a/code/modules/procedural_mapping/mapGenerator.dm +++ b/code/modules/procedural_mapping/mapGenerator.dm @@ -136,40 +136,36 @@ // HERE BE DEBUG DRAGONS // /////////////////////////// -/client/proc/debugNatureMapGenerator() - set name = "Test Nature Map Generator" - set category = "Debug" - +ADMIN_VERB(debug_nature_map_generator, R_DEBUG, "Test Nature Map Generator", "Test the nature map generator", ADMIN_CATEGORY_DEBUG) var/datum/map_generator/nature/N = new() - var/startInput = input(usr, "Start turf of Map, (X;Y;Z)", "Map Gen Settings", "1;1;1") as text|null + var/startInput = input(user, "Start turf of Map, (X;Y;Z)", "Map Gen Settings", "1;1;1") as text|null if (isnull(startInput)) return - var/endInput = input(usr, "End turf of Map (X;Y;Z)", "Map Gen Settings", "[world.maxx];[world.maxy];[mob ? mob.z : 1]") as text|null - + var/endInput = input(user, "End turf of Map (X;Y;Z)", "Map Gen Settings", "[world.maxx];[world.maxy];[user.mob.z]") as text|null if (isnull(endInput)) return //maxx maxy and current z so that if you fuck up, you only fuck up one entire z level instead of the entire universe if(!startInput || !endInput) - to_chat(src, "Missing Input") + to_chat(user, "Missing Input") return var/list/startCoords = splittext(startInput, ";") var/list/endCoords = splittext(endInput, ";") if(!startCoords || !endCoords) - to_chat(src, "Invalid Coords") - to_chat(src, "Start Input: [startInput]") - to_chat(src, "End Input: [endInput]") + to_chat(user, "Invalid Coords") + to_chat(user, "Start Input: [startInput]") + to_chat(user, "End Input: [endInput]") return var/turf/Start = locate(text2num(startCoords[1]),text2num(startCoords[2]),text2num(startCoords[3])) var/turf/End = locate(text2num(endCoords[1]),text2num(endCoords[2]),text2num(endCoords[3])) if(!Start || !End) - to_chat(src, "Invalid Turfs") - to_chat(src, "Start Coords: [startCoords[1]] - [startCoords[2]] - [startCoords[3]]") - to_chat(src, "End Coords: [endCoords[1]] - [endCoords[2]] - [endCoords[3]]") + to_chat(user, "Invalid Turfs") + to_chat(user, "Start Coords: [startCoords[1]] - [startCoords[2]] - [startCoords[3]]") + to_chat(user, "End Coords: [endCoords[1]] - [endCoords[2]] - [endCoords[3]]") return var/static/list/clusters = list( @@ -191,7 +187,7 @@ var/theCluster = 0 if(moduleClusters != "None") if(!clusters[moduleClusters]) - to_chat(src, "Invalid Cluster Flags") + to_chat(user, "Invalid Cluster Flags") return theCluster = clusters[moduleClusters] else @@ -202,9 +198,9 @@ M.clusterCheckFlags = theCluster - to_chat(src, "Defining Region") + to_chat(user, "Defining Region") N.defineRegion(Start, End) - to_chat(src, "Region Defined") - to_chat(src, "Generating Region") + to_chat(user, "Region Defined") + to_chat(user, "Generating Region") N.generate() - to_chat(src, "Generated Region") + to_chat(user, "Generated Region") diff --git a/code/modules/reagents/chemistry/chem_wiki_render.dm b/code/modules/reagents/chemistry/chem_wiki_render.dm index a2ac0af8ffb57..99116adc84b08 100644 --- a/code/modules/reagents/chemistry/chem_wiki_render.dm +++ b/code/modules/reagents/chemistry/chem_wiki_render.dm @@ -1,10 +1,6 @@ -//Generates a wikitable txt file for use with the wiki - does not support productless reactions at the moment -/client/proc/generate_wikichem_list() - set category = "Debug" - set name = "Parse Wikichems" - +ADMIN_VERB(generate_wikichem_list, R_DEBUG, "Parse Wikichems", "Parse and generate a text file for wikichem.", ADMIN_CATEGORY_DEBUG) //If we're a reaction product - var/prefix_reaction = {"{| class=\"wikitable sortable\" style=\"width:100%; text-align:left; border: 3px solid #FFDD66; cellspacing=0; cellpadding=2; background-color:white;\" + var/static/prefix_reaction = {"{| class=\"wikitable sortable\" style=\"width:100%; text-align:left; border: 3px solid #FFDD66; cellspacing=0; cellpadding=2; background-color:white;\" ! scope=\"col\" style='width:150px; background-color:#FFDD66;'|Name ! scope=\"col\" class=\"unsortable\" style='background-color:#FFDD66;'|Formula ! scope=\"col\" class=\"unsortable\" style='background-color:#FFDD66; width:170px;'|Reaction conditions @@ -13,9 +9,9 @@ |- "} - var/input_text = tgui_input_text(usr, "Input a name of a reagent, or a series of reagents split with a comma (no spaces) to get it's wiki table entry", "Recipe") //95% of the time, the reagent type is a lowercase, no spaces / underscored version of the name + var/input_text = tgui_input_text(user, "Input a name of a reagent, or a series of reagents split with a comma (no spaces) to get it's wiki table entry", "Recipe") //95% of the time, the reagent type is a lowercase, no spaces / underscored version of the name if(!input_text) - to_chat(usr, "Input was blank!") + to_chat(user, "Input was blank!") return text2file(prefix_reaction, "[GLOB.log_directory]/chem_parse.txt") var/list/names = splittext("[input_text]", ",") @@ -23,13 +19,13 @@ for(var/name in names) var/datum/reagent/reagent = find_reagent_object_from_type(get_chem_id(name)) if(!reagent) - to_chat(usr, "Could not find [name]. Skipping.") + to_chat(user, "Could not find [name]. Skipping.") continue //Get reaction var/list/reactions = GLOB.chemical_reactions_list_product_index[reagent.type] if(!length(reactions)) - to_chat(usr, "Could not find [name] reaction! Continuing anyways.") + to_chat(user, "Could not find [name] reaction! Continuing anyways.") var/single_parse = generate_chemwiki_line(reagent, null) text2file(single_parse, "[GLOB.log_directory]/chem_parse.txt") continue @@ -38,8 +34,7 @@ var/single_parse = generate_chemwiki_line(reagent, reaction) text2file(single_parse, "[GLOB.log_directory]/chem_parse.txt") text2file("|}", "[GLOB.log_directory]/chem_parse.txt") //Cap off the table - to_chat(usr, "Done! Saved file to (wherever your root folder is, i.e. where the DME is)/[GLOB.log_directory]/chem_parse.txt OR use the Get Current Logs verb under the Admin tab. (if you click Open, and it does nothing, that's because you've not set a .txt default program! Try downloading it instead, and use that file to set a default program! Have a nice day!") - + to_chat(user, "Done! Saved file to (wherever your root folder is, i.e. where the DME is)/[GLOB.log_directory]/chem_parse.txt OR use the Get Current Logs verb under the Admin tab. (if you click Open, and it does nothing, that's because you've not set a .txt default program! Try downloading it instead, and use that file to set a default program! Have a nice day!") /// Generate the big list of reagent based reactions. /proc/generate_chemwiki_line(datum/reagent/reagent, datum/chemical_reaction/reaction) diff --git a/code/modules/requests/request_manager.dm b/code/modules/requests/request_manager.dm index dd6d8d42a480e..74a40304f7aed 100644 --- a/code/modules/requests/request_manager.dm +++ b/code/modules/requests/request_manager.dm @@ -163,17 +163,18 @@ GLOBAL_DATUM_INIT(requests, /datum/request_manager, new) switch(action) if ("pp") - var/mob/M = request.owner?.mob - usr.client.holder.show_player_panel(M) + SSadmin_verbs.dynamic_invoke_verb(ui.user, /datum/admin_verb/show_player_panel, request.owner?.mob) return TRUE + if ("vv") var/mob/M = request.owner?.mob usr.client.debug_variables(M) return TRUE + if ("sm") - var/mob/M = request.owner?.mob - usr.client.cmd_admin_subtle_message(M) + SSadmin_verbs.dynamic_invoke_verb(ui.user, /datum/admin_verb/cmd_admin_subtle_message, request.owner?.mob) return TRUE + if ("flw") var/mob/M = request.owner?.mob usr.client.admin_follow(M) @@ -192,8 +193,9 @@ GLOBAL_DATUM_INIT(requests, /datum/request_manager, new) D.traitor_panel() return TRUE else - usr.client.holder.show_traitor_panel(M) + SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/show_traitor_panel, M) return TRUE + if ("logs") var/mob/M = request.owner?.mob if(!ismob(M)) @@ -201,16 +203,11 @@ GLOBAL_DATUM_INIT(requests, /datum/request_manager, new) return TRUE show_individual_logging_panel(M, null, null) return TRUE + if ("smite") - if(!check_rights(R_FUN)) - to_chat(usr, "Insufficient permissions to smite, you require +FUN", confidential = TRUE) - return TRUE - var/mob/living/carbon/human/H = request.owner?.mob - if (!H || !istype(H)) - to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human", confidential = TRUE) - return TRUE - usr.client.smite(H) + SSadmin_verbs.dynamic_invoke_verb(ui.user, /datum/admin_verb/admin_smite, request.owner?.mob) return TRUE + if ("rply") if (request.req_type == REQUEST_PRAYER) to_chat(usr, "Cannot reply to a prayer", confidential = TRUE) diff --git a/code/modules/tgui_input/say_modal/speech.dm b/code/modules/tgui_input/say_modal/speech.dm index 27e5776b3f1fe..0d95b855a15ff 100644 --- a/code/modules/tgui_input/say_modal/speech.dm +++ b/code/modules/tgui_input/say_modal/speech.dm @@ -45,7 +45,7 @@ client.ooc(entry) return TRUE if(ADMIN_CHANNEL) - client.cmd_admin_say(entry) + SSadmin_verbs.dynamic_invoke_verb(client, /datum/admin_verb/cmd_admin_say, entry) return TRUE return FALSE diff --git a/code/modules/transport/admin.dm b/code/modules/transport/admin.dm index 9d68d967e60ae..63f1fbfd55a3b 100644 --- a/code/modules/transport/admin.dm +++ b/code/modules/transport/admin.dm @@ -1,23 +1,14 @@ -/** - * Helper tool to try and resolve tram controller errors, or reset the contents if someone put a million chickens on the tram - * and now it's slow as hell and lagging things. - */ -/datum/admins/proc/reset_tram() - set name = "Reset Tram" - set category = "Debug" +ADMIN_VERB(reset_tram, R_DEBUG|R_ADMIN, "Reset Tram", "Reset a tram controller or its contents.", ADMIN_CATEGORY_DEBUG) var/static/list/debug_tram_list = list( - TRAMSTATION_LINE_1, - BIRDSHOT_LINE_1, - BIRDSHOT_LINE_2, - HILBERT_LINE_1, + TRAMSTATION_LINE_1, + BIRDSHOT_LINE_1, + BIRDSHOT_LINE_2, + HILBERT_LINE_1, ) - if(!check_rights(R_DEBUG)) - return - var/datum/transport_controller/linear/tram/broken_controller - var/selected_transport_id = tgui_input_list(usr, "Which tram?", "Off the rails", debug_tram_list) - var/reset_type = tgui_input_list(usr, "How hard of a reset?", "How bad is it screwed up", list("Clear Tram Contents", "Controller", "Controller and Contents", "Delete Datum", "Cancel")) + var/selected_transport_id = tgui_input_list(user, "Which tram?", "Off the rails", debug_tram_list) + var/reset_type = tgui_input_list(user, "How hard of a reset?", "How bad is it screwed up", list("Clear Tram Contents", "Controller", "Controller and Contents", "Delete Datum", "Cancel")) if(isnull(reset_type) || reset_type == "Cancel") return @@ -28,40 +19,40 @@ break if(isnull(broken_controller)) - to_chat(usr, span_warning("Couldn't find a transport controller datum with ID [selected_transport_id]!")) + to_chat(user, span_warning("Couldn't find a transport controller datum with ID [selected_transport_id]!")) return switch(reset_type) if("Clear Tram Contents") - var/selection = tgui_alert(usr, "Include player mobs in the clearing?", "Contents reset [selected_transport_id]", list("Contents", "Contents and Players", "Cancel")) + var/selection = tgui_alert(user, "Include player mobs in the clearing?", "Contents reset [selected_transport_id]", list("Contents", "Contents and Players", "Cancel")) switch(selection) if("Contents") broken_controller.reset_lift_contents(foreign_objects = TRUE, foreign_non_player_mobs = TRUE, consider_player_mobs = FALSE) - message_admins("[key_name_admin(usr)] performed a contents reset of tram ID [selected_transport_id].") - log_transport("TC: [selected_transport_id]: [key_name_admin(usr)] performed a contents reset.") + message_admins("[key_name_admin(user)] performed a contents reset of tram ID [selected_transport_id].") + log_transport("TC: [selected_transport_id]: [key_name_admin(user)] performed a contents reset.") if("Contents and Players") broken_controller.reset_lift_contents(foreign_objects = TRUE, foreign_non_player_mobs = TRUE, consider_player_mobs = TRUE) - message_admins("[key_name_admin(usr)] performed a contents and player mob reset of tram ID [selected_transport_id].") - log_transport("TC: [selected_transport_id]: [key_name_admin(usr)] performed a contents and player mob reset.") + message_admins("[key_name_admin(user)] performed a contents and player mob reset of tram ID [selected_transport_id].") + log_transport("TC: [selected_transport_id]: [key_name_admin(user)] performed a contents and player mob reset.") else return if("Controller") - log_transport("TC: [selected_transport_id]: [key_name_admin(usr)] performed a controller reset, force operational.") - message_admins("[key_name_admin(usr)] performed a controller reset of tram ID [selected_transport_id].") + log_transport("TC: [selected_transport_id]: [key_name_admin(user)] performed a controller reset, force operational.") + message_admins("[key_name_admin(user)] performed a controller reset of tram ID [selected_transport_id].") broken_controller.set_operational(TRUE) broken_controller.reset_position() if("Controller and Contents") - var/selection = tgui_alert(usr, "Include player mobs in the clearing?", "Contents reset [selected_transport_id]", list("Contents", "Contents and Players", "Cancel")) + var/selection = tgui_alert(user, "Include player mobs in the clearing?", "Contents reset [selected_transport_id]", list("Contents", "Contents and Players", "Cancel")) switch(selection) if("Contents") - message_admins("[key_name_admin(usr)] performed a contents and controller reset of tram ID [selected_transport_id].") - log_transport("TC: [selected_transport_id]: [key_name_admin(usr)] performed a contents reset. Controller reset, force operational.") + message_admins("[key_name_admin(user)] performed a contents and controller reset of tram ID [selected_transport_id].") + log_transport("TC: [selected_transport_id]: [key_name_admin(user)] performed a contents reset. Controller reset, force operational.") broken_controller.reset_lift_contents(foreign_objects = TRUE, foreign_non_player_mobs = TRUE, consider_player_mobs = FALSE) if("Contents and Players") - message_admins("[key_name_admin(usr)] performed a contents/player/controller reset of tram ID [selected_transport_id].") - log_transport("TC: [selected_transport_id]: [key_name_admin(usr)] performed a contents and player mob reset. Controller reset, force operational.") + message_admins("[key_name_admin(user)] performed a contents/player/controller reset of tram ID [selected_transport_id].") + log_transport("TC: [selected_transport_id]: [key_name_admin(user)] performed a contents and player mob reset. Controller reset, force operational.") broken_controller.reset_lift_contents(foreign_objects = TRUE, foreign_non_player_mobs = TRUE, consider_player_mobs = TRUE) else return @@ -70,7 +61,7 @@ broken_controller.reset_position() if("Delete Datum") - var/confirm = tgui_alert(usr, "Deleting [selected_transport_id] will make it unrecoverable this round. Are you sure?", "Delete tram ID [selected_transport_id]", list("Yes", "Cancel")) + var/confirm = tgui_alert(user, "Deleting [selected_transport_id] will make it unrecoverable this round. Are you sure?", "Delete tram ID [selected_transport_id]", list("Yes", "Cancel")) if(confirm != "Yes") return @@ -82,4 +73,4 @@ broken_controller.cycle_doors(CYCLE_OPEN, BYPASS_DOOR_CHECKS) broken_controller.estop() qdel(broken_controller) - message_admins("[key_name_admin(usr)] performed a datum delete of tram ID [selected_transport_id].") + message_admins("[key_name_admin(user)] performed a datum delete of tram ID [selected_transport_id].") diff --git a/code/modules/wiremod/core/admin_panel.dm b/code/modules/wiremod/core/admin_panel.dm index 74e72ad5efe0c..9a262cb5e4c9f 100644 --- a/code/modules/wiremod/core/admin_panel.dm +++ b/code/modules/wiremod/core/admin_panel.dm @@ -1,10 +1,7 @@ -/// An admin verb to view all circuits, plus useful information -/datum/admins/proc/view_all_circuits() - set category = "Admin.Game" - set name = "View All Circuits" +ADMIN_VERB(view_all_circuits, R_ADMIN, "View All Circuits", "List all circuits in the game.", ADMIN_CATEGORY_GAME) var/static/datum/circuit_admin_panel/circuit_admin_panel = new - circuit_admin_panel.ui_interact(usr) + circuit_admin_panel.ui_interact(user.mob) /datum/circuit_admin_panel @@ -66,9 +63,10 @@ usr.client?.debug_variables(circuit) if ("open_circuit") circuit.ui_interact(usr) + if ("open_player_panel") var/datum/mind/inserter = circuit.inserter_mind?.resolve() - usr.client?.holder?.show_player_panel(inserter?.current) + SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/show_player_panel, inserter?.current) return TRUE diff --git a/code/modules/wiremod/core/duplicator.dm b/code/modules/wiremod/core/duplicator.dm index 2f248d11a8938..25e8332680432 100644 --- a/code/modules/wiremod/core/duplicator.dm +++ b/code/modules/wiremod/core/duplicator.dm @@ -220,30 +220,24 @@ GLOBAL_LIST_INIT(circuit_dupe_whitelisted_types, list( rel_x = component_data["rel_x"] rel_y = component_data["rel_y"] -/client/proc/load_circuit() - set name = "Load Circuit" - set category = "Admin.Fun" - - if(!check_rights(R_VAREDIT)) - return - +ADMIN_VERB(load_circuit, R_VAREDIT, "Load Circuit", "Loads a circuit from a file or direct input.", ADMIN_CATEGORY_FUN) var/list/errors = list() - var/option = alert(usr, "Load by file or direct input?", "Load by file or string", "File", "Direct Input") + var/option = alert(user, "Load by file or direct input?", "Load by file or string", "File", "Direct Input") var/txt switch(option) if("File") - txt = file2text(input(usr, "Input File") as null|file) + txt = file2text(input(user, "Input File") as null|file) if("Direct Input") - txt = input(usr, "Input JSON", "Input JSON") as text|null + txt = input(user, "Input JSON", "Input JSON") as text|null if(!txt) return - var/obj/item/integrated_circuit/loaded/circuit = new(mob.drop_location()) + var/obj/item/integrated_circuit/loaded/circuit = new(user.mob.drop_location()) circuit.load_circuit_data(txt, errors) if(length(errors)) - to_chat(src, span_warning("The following errors were found whilst compiling the circuit data:")) + to_chat(user, span_warning("The following errors were found whilst compiling the circuit data:")) for(var/error in errors) - to_chat(src, span_warning(error)) + to_chat(user, span_warning(error)) diff --git a/tgstation.dme b/tgstation.dme index 2bf67fe273cd5..1b61d94bbc9bf 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -33,6 +33,7 @@ #include "code\__DEFINES\actions.dm" #include "code\__DEFINES\actionspeed_modification.dm" #include "code\__DEFINES\admin.dm" +#include "code\__DEFINES\admin_verb.dm" #include "code\__DEFINES\adventure.dm" #include "code\__DEFINES\airlock.dm" #include "code\__DEFINES\alarm.dm" @@ -614,6 +615,7 @@ #include "code\controllers\configuration\entries\resources.dm" #include "code\controllers\subsystem\achievements.dm" #include "code\controllers\subsystem\addiction.dm" +#include "code\controllers\subsystem\admin_verbs.dm" #include "code\controllers\subsystem\ai_controllers.dm" #include "code\controllers\subsystem\air.dm" #include "code\controllers\subsystem\ambience.dm" @@ -2832,6 +2834,8 @@ #include "code\modules\admin\smites\smite.dm" #include "code\modules\admin\smites\supply_pod.dm" #include "code\modules\admin\smites\supply_pod_quick.dm" +#include "code\modules\admin\verb_datums\_admin_verb_datum.dm" +#include "code\modules\admin\verb_datums\_admin_verb_holder.dm" #include "code\modules\admin\verbs\admin.dm" #include "code\modules\admin\verbs\admin_newscaster.dm" #include "code\modules\admin\verbs\adminevents.dm" @@ -2886,6 +2890,7 @@ #include "code\modules\admin\verbs\server.dm" #include "code\modules\admin\verbs\shuttlepanel.dm" #include "code\modules\admin\verbs\spawnobjasmob.dm" +#include "code\modules\admin\verbs\special_verbs.dm" #include "code\modules\admin\verbs\lua\_hooks.dm" #include "code\modules\admin\verbs\lua\_wrappers.dm" #include "code\modules\admin\verbs\lua\helpers.dm" From 9b830bc8a9334274d8b41c6331e0f99a875f7e49 Mon Sep 17 00:00:00 2001 From: wesoda25 <37246588+wesoda25@users.noreply.github.com> Date: Fri, 12 Apr 2024 15:30:23 -0400 Subject: [PATCH 202/938] Blood cult: cleans up blood rites code, fixes a bug or two, & adds blackbox logging for spells, runes, and shades (#82444) --- code/modules/antagonists/cult/blood_magic.dm | 430 +++++++++++------- code/modules/antagonists/cult/runes.dm | 1 + .../antagonists/wizard/equipment/soulstone.dm | 4 + code/modules/library/bibles.dm | 1 + code/modules/mob/living/basic/cult/shade.dm | 7 + 5 files changed, 271 insertions(+), 172 deletions(-) diff --git a/code/modules/antagonists/cult/blood_magic.dm b/code/modules/antagonists/cult/blood_magic.dm index 33a12af2c7844..fa144811fb385 100644 --- a/code/modules/antagonists/cult/blood_magic.dm +++ b/code/modules/antagonists/cult/blood_magic.dm @@ -1,3 +1,10 @@ +/// how many units of blood one charge of blood rites is worth +#define USES_TO_BLOOD 2 +/// blood rites charges gained from sapping blood from a victim +#define BLOOD_DRAIN_GAIN 50 +/// penalty for self healing, 1 point of damage * this # = charges required +#define SELF_HEAL_PENALTY 1.65 + /datum/action/innate/cult/blood_magic //Blood magic handles the creation of blood spells (formerly talismans) name = "Prepare Blood Magic" button_icon_state = "carve" @@ -103,6 +110,8 @@ var/health_cost = 0 /// Have we already been positioned into our starting location? var/positioned = FALSE + /// If false, the spell will not delete after running out of charges + var/deletes_on_empty = TRUE /datum/action/innate/cult/blood_spell/Grant(mob/living/owner, datum/action/innate/cult/blood_magic/BM) if(health_cost) @@ -121,26 +130,25 @@ ..() /datum/action/innate/cult/blood_spell/IsAvailable(feedback = FALSE) - if(!IS_CULTIST(owner) || owner.incapacitated() || !charges) + if(!IS_CULTIST(owner) || owner.incapacitated() || (!charges && deletes_on_empty)) return FALSE return ..() /datum/action/innate/cult/blood_spell/Activate() - if(magic_path) //If this spell flows from the hand - if(!hand_magic) - hand_magic = new magic_path(owner, src) - if(!owner.put_in_hands(hand_magic)) - qdel(hand_magic) - hand_magic = null - to_chat(owner, span_warning("You have no empty hand for invoking blood magic!")) - return - to_chat(owner, span_notice("Your wounds glow as you invoke the [name].")) - return - if(hand_magic) - qdel(hand_magic) - hand_magic = null - to_chat(owner, span_warning("You snuff out the spell, saving it for later.")) - + if(!magic_path) // only concerned with spells that flow from the hand + return + if(hand_magic) + qdel(hand_magic) + hand_magic = null + to_chat(owner, span_warning("You snuff out the spell, saving it for later.")) + return + hand_magic = new magic_path(owner, src) + if(!owner.put_in_hands(hand_magic)) + qdel(hand_magic) + hand_magic = null + to_chat(owner, span_warning("You have no empty hand for invoking blood magic!")) + return + to_chat(owner, span_notice("Your wounds glow as you invoke the [name].")) //Cult Blood Spells /datum/action/innate/cult/blood_spell/stun @@ -170,6 +178,7 @@ span_cult_italic("You speak the cursed words, emitting an EMP blast from your hand.")) empulse(owner, 2, 5) charges-- + SSblackbox.record_feedback("tally", "cult_spell_invoke", 1, "[name]") if(charges <= 0) qdel(src) @@ -214,6 +223,7 @@ span_cult_italic("A [summoned_blade] materializes at your feet.")) SEND_SOUND(owner, sound('sound/effects/magic.ogg', FALSE, 0, 25)) charges-- + SSblackbox.record_feedback("tally", "cult_spell_invoke", 1, "[name]") if(charges <= 0) qdel(src) @@ -255,6 +265,7 @@ desc = base_desc desc += "
    Has [charges] use\s remaining." build_all_button_icons() + SSblackbox.record_feedback("tally", "cult_spell_invoke", 1, "[name]") if(charges <= 0) to_chat(caller, span_cult("You have exhausted the spell's power!")) qdel(src) @@ -308,6 +319,7 @@ revealing = FALSE name = "Conceal Runes" button_icon_state = "gone" + SSblackbox.record_feedback("tally", "cult_spell_invoke", 1, "Conceal Runes") if(charges <= 0) qdel(src) desc = base_desc @@ -321,6 +333,7 @@ button_icon_state = "manip" charges = 5 magic_path = "/obj/item/melee/blood_magic/manipulator" + deletes_on_empty = FALSE // The "magic hand" items /obj/item/melee/blood_magic @@ -350,7 +363,7 @@ /obj/item/melee/blood_magic/Destroy() if(!QDELETED(source)) - if(uses <= 0) + if(uses <= 0 && source.deletes_on_empty) source.hand_magic = null qdel(source) source = null @@ -371,6 +384,7 @@ qdel(src) return log_combat(user, M, "used a cult spell on", source.name, "") + SSblackbox.record_feedback("tally", "cult_spell_invoke", 1, "[name]") M.lastattacker = user.real_name M.lastattackerckey = user.ckey @@ -671,167 +685,235 @@ . = ..() . += "Bloody halberd, blood bolt barrage, and blood beam cost [BLOOD_HALBERD_COST], [BLOOD_BARRAGE_COST], and [BLOOD_BEAM_COST] charges respectively." +/** + * handles inhand use of blood rites on constructs, humans, or non-living blood sources + * + * see '/obj/item/melee/blood_magic/manipulator/proc/heal_construct' for construct/shade behavior + * see '/obj/item/melee/blood_magic/manipulator/proc/heal_cultist' for human cultist behavior + * see '/obj/item/melee/blood_magic/manipulator/proc/drain_victim' for human non-cultist behavior + * if any of the above procs return FALSE, '/obj/item/melee/blood_magic/afterattack' will not be called + * + * '/obj/item/melee/blood_magic/manipulator/proc/blood_draw' handles blood pools/trails and does not affect parent proc + */ /obj/item/melee/blood_magic/manipulator/afterattack(atom/target, mob/living/carbon/human/user, proximity) - if(proximity) - if(ishuman(target)) - var/mob/living/carbon/human/human_bloodbag = target - if(HAS_TRAIT(human_bloodbag, TRAIT_NOBLOOD)) - to_chat(user,span_warning("Blood rites do not work on people with no blood!")) - return - if(IS_CULTIST(human_bloodbag)) - if(human_bloodbag.stat == DEAD) - to_chat(user,span_warning("Only a revive rune can bring back the dead!")) - return - if(human_bloodbag.blood_volume < BLOOD_VOLUME_SAFE) - var/restore_blood = BLOOD_VOLUME_SAFE - human_bloodbag.blood_volume - if(uses*2 < restore_blood) - human_bloodbag.blood_volume += uses*2 - to_chat(user,span_danger("You use the last of your blood rites to restore what blood you could!")) - uses = 0 - return ..() - else - human_bloodbag.blood_volume = BLOOD_VOLUME_SAFE - uses -= round(restore_blood/2) - to_chat(user,span_warning("Your blood rites have restored [human_bloodbag == user ? "your" : "[human_bloodbag.p_their()]"] blood to safe levels!")) - var/overall_damage = human_bloodbag.getBruteLoss() + human_bloodbag.getFireLoss() + human_bloodbag.getToxLoss() + human_bloodbag.getOxyLoss() - if(overall_damage == 0) - to_chat(user,span_cult("That cultist doesn't require healing!")) - else - var/ratio = uses/overall_damage - if(human_bloodbag == user) - to_chat(user,span_cult("Your blood healing is far less efficient when used on yourself!")) - ratio *= 0.35 // Healing is half as effective if you can't perform a full heal - uses -= round(overall_damage) // Healing is 65% more "expensive" even if you can still perform the full heal - if(ratio>1) - ratio = 1 - uses -= round(overall_damage) - human_bloodbag.visible_message(span_warning("[human_bloodbag] is fully healed by [human_bloodbag == user ? "[human_bloodbag.p_their()]":"[human_bloodbag]'s"] blood magic!")) - else - human_bloodbag.visible_message(span_warning("[human_bloodbag] is partially healed by [human_bloodbag == user ? "[human_bloodbag.p_their()]":"[human_bloodbag]'s"] blood magic.")) - uses = 0 - ratio *= -1 - var/need_mob_update = FALSE - need_mob_update += human_bloodbag.adjustOxyLoss((overall_damage*ratio) * (human_bloodbag.getOxyLoss() / overall_damage), updating_health = FALSE) - need_mob_update += human_bloodbag.adjustToxLoss((overall_damage*ratio) * (human_bloodbag.getToxLoss() / overall_damage), updating_health = FALSE) - need_mob_update += human_bloodbag.adjustFireLoss((overall_damage*ratio) * (human_bloodbag.getFireLoss() / overall_damage), updating_health = FALSE) - need_mob_update += human_bloodbag.adjustBruteLoss((overall_damage*ratio) * (human_bloodbag.getBruteLoss() / overall_damage), updating_health = FALSE) - if(need_mob_update) - human_bloodbag.updatehealth() - playsound(get_turf(human_bloodbag), 'sound/magic/staff_healing.ogg', 25) - new /obj/effect/temp_visual/cult/sparks(get_turf(human_bloodbag)) - user.Beam(human_bloodbag, icon_state="sendbeam", time = 15) - else - if(human_bloodbag.stat == DEAD) - to_chat(user,span_warning("[human_bloodbag.p_Their()] blood has stopped flowing, you'll have to find another way to extract it.")) - return - if(human_bloodbag.has_status_effect(/datum/status_effect/speech/slurring/cult)) - to_chat(user,span_danger("[human_bloodbag.p_Their()] blood has been tainted by an even stronger form of blood magic, it's no use to us like this!")) - return - if(human_bloodbag.blood_volume > BLOOD_VOLUME_SAFE) - human_bloodbag.blood_volume -= 100 - uses += 50 - user.Beam(human_bloodbag, icon_state="drainbeam", time = 1 SECONDS) - playsound(get_turf(human_bloodbag), 'sound/magic/enter_blood.ogg', 50) - human_bloodbag.visible_message(span_danger("[user] drains some of [human_bloodbag]'s blood!")) - to_chat(user,span_cult_italic("Your blood rite gains 50 charges from draining [human_bloodbag]'s blood.")) - new /obj/effect/temp_visual/cult/sparks(get_turf(human_bloodbag)) - else - to_chat(user,span_warning("[human_bloodbag.p_Theyre()] missing too much blood - you cannot drain [human_bloodbag.p_them()] further!")) - return - if(isconstruct(target)) - var/mob/living/basic/construct/construct_thing = target - var/missing_health = construct_thing.maxHealth - construct_thing.health - if(missing_health) - if(uses > missing_health) - construct_thing.adjust_health(-missing_health) - construct_thing.visible_message(span_warning("[construct_thing] is fully healed by [user]'s blood magic!")) - uses -= missing_health - else - construct_thing.adjust_health(-uses) - construct_thing.visible_message(span_warning("[construct_thing] is partially healed by [user]'s blood magic!")) - uses = 0 - playsound(get_turf(construct_thing), 'sound/magic/staff_healing.ogg', 25) - user.Beam(construct_thing, icon_state="sendbeam", time = 1 SECONDS) - if(istype(target, /obj/effect/decal/cleanable/blood) || istype(target, /obj/effect/decal/cleanable/trail_holder) || isturf(target)) - blood_draw(target, user) - ..() + if(!proximity) + return + + if((isconstruct(target) || isshade(target)) && !heal_construct(target, user)) + return + if(istype(target, /obj/effect/decal/cleanable/blood) || istype(target, /obj/effect/decal/cleanable/trail_holder) || isturf(target)) + blood_draw(target, user) + if(ishuman(target)) + var/mob/living/carbon/human/human_bloodbag = target + if(HAS_TRAIT(human_bloodbag, TRAIT_NOBLOOD)) + human_bloodbag.balloon_alert(user, "no blood!") + return + if(human_bloodbag.stat == DEAD) + human_bloodbag.balloon_alert(user, "dead!") + return + + if(IS_CULTIST(human_bloodbag) && !heal_cultist(human_bloodbag, user)) + return + if(!IS_CULTIST(human_bloodbag) && !drain_victim(human_bloodbag, user)) + return + ..() + +/** + * handles blood rites usage on constructs + * + * will only return TRUE if some amount healing is done + */ +/obj/item/melee/blood_magic/manipulator/proc/heal_construct(atom/target, mob/living/carbon/human/user) + var/mob/living/basic/construct_thing = target + if(!IS_CULTIST(construct_thing)) + return FALSE + var/missing_health = construct_thing.maxHealth - construct_thing.health + if(!missing_health) + to_chat(user,span_cult("That cultist doesn't require healing!")) + return FALSE + if(uses <= 0) + construct_thing.balloon_alert(user, "out of blood!") + return FALSE + if(uses > missing_health) + construct_thing.adjust_health(-missing_health) + construct_thing.visible_message(span_warning("[construct_thing] is fully healed by [user]'s blood magic!")) + uses -= missing_health + else + construct_thing.adjust_health(-uses) + construct_thing.visible_message(span_warning("[construct_thing] is partially healed by [user]'s blood magic!")) + uses = 0 + playsound(get_turf(construct_thing), 'sound/magic/staff_healing.ogg', 25) + user.Beam(construct_thing, icon_state="sendbeam", time = 1 SECONDS) + return TRUE + +/** + * handles blood rites usage on human cultists + * + * first restores blood, then heals damage. healing damage is more expensive, especially if performed on oneself + * returns TRUE if some amount of blood is restored and/or damage is healed + */ +/obj/item/melee/blood_magic/manipulator/proc/heal_cultist(mob/living/carbon/human/human_bloodbag, mob/living/carbon/human/user) + if(uses <= 0) + human_bloodbag.balloon_alert(user, "out of blood!") + return FALSE + + /// used to ensure the proc returns TRUE if we completely restore an undamaged persons blood + var/blood_donor = FALSE + if(human_bloodbag.blood_volume < BLOOD_VOLUME_SAFE) + var/blood_needed = BLOOD_VOLUME_SAFE - human_bloodbag.blood_volume + /// how much blood we are capable of restoring, based on spell charges + var/blood_bank = USES_TO_BLOOD * uses + if(blood_bank < blood_needed) + human_bloodbag.blood_volume += blood_bank + to_chat(user,span_danger("You use the last of your blood rites to restore what blood you could!")) + uses = 0 + return TRUE + blood_donor = TRUE + human_bloodbag.blood_volume = BLOOD_VOLUME_SAFE + uses -= round(blood_needed / USES_TO_BLOOD) + to_chat(user,span_warning("Your blood rites have restored [human_bloodbag == user ? "your" : "[human_bloodbag.p_their()]"] blood to safe levels!")) + + var/overall_damage = human_bloodbag.getBruteLoss() + human_bloodbag.getFireLoss() + human_bloodbag.getToxLoss() + human_bloodbag.getOxyLoss() + if(overall_damage == 0) + if(blood_donor) + return TRUE + to_chat(user,span_cult("That cultist doesn't require healing!")) + return FALSE + /// how much damage we can/will heal + var/damage_healed = -1 * min(uses, overall_damage) + /// how many spell charges will be consumed to heal said damage + var/healing_cost = damage_healed + if(human_bloodbag == user) + to_chat(user,span_cult("Your blood healing is far less efficient when used on yourself!")) + damage_healed = -1 * min(uses * (1 / SELF_HEAL_PENALTY), overall_damage) + healing_cost = damage_healed * SELF_HEAL_PENALTY + uses += round(healing_cost) + human_bloodbag.visible_message(span_warning("[human_bloodbag] is [uses == 0 ? "partially healed":"fully healed"] by [human_bloodbag == user ? "[human_bloodbag.p_their()]":"[human_bloodbag]'s"] blood magic!")) + + var/need_mob_update = FALSE + need_mob_update += human_bloodbag.adjustOxyLoss(damage_healed * (human_bloodbag.getOxyLoss() / overall_damage), updating_health = FALSE) + need_mob_update += human_bloodbag.adjustToxLoss(damage_healed * (human_bloodbag.getToxLoss() / overall_damage), updating_health = FALSE) + need_mob_update += human_bloodbag.adjustFireLoss(damage_healed * (human_bloodbag.getFireLoss() / overall_damage), updating_health = FALSE) + need_mob_update += human_bloodbag.adjustBruteLoss(damage_healed * (human_bloodbag.getBruteLoss() / overall_damage), updating_health = FALSE) + if(need_mob_update) + human_bloodbag.updatehealth() + playsound(get_turf(human_bloodbag), 'sound/magic/staff_healing.ogg', 25) + new /obj/effect/temp_visual/cult/sparks(get_turf(human_bloodbag)) + user.Beam(human_bloodbag, icon_state="sendbeam", time = 15) + return TRUE + +/** + * handles blood rites use on a non-cultist human + * + * returns TRUE if blood is successfully drained from the victim + */ +/obj/item/melee/blood_magic/manipulator/proc/drain_victim(mob/living/carbon/human/human_bloodbag, mob/living/carbon/human/user) + if(human_bloodbag.has_status_effect(/datum/status_effect/speech/slurring/cult)) + to_chat(user,span_danger("[human_bloodbag.p_Their()] blood has been tainted by an even stronger form of blood magic, it's no use to us like this!")) + return FALSE + if(human_bloodbag.blood_volume <= BLOOD_VOLUME_SAFE) + to_chat(user,span_warning("[human_bloodbag.p_Theyre()] missing too much blood - you cannot drain [human_bloodbag.p_them()] further!")) + return FALSE + human_bloodbag.blood_volume -= BLOOD_DRAIN_GAIN * USES_TO_BLOOD + uses += BLOOD_DRAIN_GAIN + user.Beam(human_bloodbag, icon_state="drainbeam", time = 1 SECONDS) + playsound(get_turf(human_bloodbag), 'sound/magic/enter_blood.ogg', 50) + human_bloodbag.visible_message(span_danger("[user] drains some of [human_bloodbag]'s blood!")) + to_chat(user,span_cult_italic("Your blood rite gains 50 charges from draining [human_bloodbag]'s blood.")) + new /obj/effect/temp_visual/cult/sparks(get_turf(human_bloodbag)) + return TRUE +/** + * handles blood rites use on turfs, blood pools, and blood trails + */ /obj/item/melee/blood_magic/manipulator/proc/blood_draw(atom/target, mob/living/carbon/human/user) var/blood_to_gain = 0 var/turf/our_turf = get_turf(target) - if(our_turf) - for(var/obj/effect/decal/cleanable/blood/blood_around_us in range(our_turf,2)) - if(blood_around_us.blood_state == BLOOD_STATE_HUMAN) - if(blood_around_us.bloodiness == 100) //Bonus for "pristine" bloodpools, also to prevent cheese with footprint spam - blood_to_gain += 30 - else - blood_to_gain += max((blood_around_us.bloodiness**2)/800,1) - new /obj/effect/temp_visual/cult/turf/floor(get_turf(blood_around_us)) - qdel(blood_around_us) - for(var/obj/effect/decal/cleanable/trail_holder/trail_around_us in range(our_turf, 2)) - if(trail_around_us.blood_state == BLOOD_STATE_HUMAN) - blood_to_gain += 5 //These don't get bloodiness, so we'll just increase this by a fixed value - new /obj/effect/temp_visual/cult/turf/floor(get_turf(trail_around_us)) - qdel(trail_around_us) - if(blood_to_gain) - user.Beam(our_turf,icon_state="drainbeam", time = 15) - new /obj/effect/temp_visual/cult/sparks(get_turf(user)) - playsound(our_turf, 'sound/magic/enter_blood.ogg', 50) - to_chat(user, span_cult_italic("Your blood rite has gained [round(blood_to_gain)] charge\s from blood sources around you!")) - uses += max(1, round(blood_to_gain)) - + if(!our_turf) + return + for(var/obj/effect/decal/cleanable/blood/blood_around_us in range(our_turf,2)) + if(blood_around_us.blood_state != BLOOD_STATE_HUMAN) + break + if(blood_around_us.bloodiness == 100) // Bonus for "pristine" bloodpools, also to prevent cheese with footprint spam + blood_to_gain += 30 + else + blood_to_gain += max((blood_around_us.bloodiness**2)/800,1) + new /obj/effect/temp_visual/cult/turf/floor(get_turf(blood_around_us)) + qdel(blood_around_us) + for(var/obj/effect/decal/cleanable/trail_holder/trail_around_us in range(our_turf, 2)) + if(trail_around_us.blood_state != BLOOD_STATE_HUMAN) + break + blood_to_gain += 5 //These don't get bloodiness, so we'll just increase this by a fixed value + new /obj/effect/temp_visual/cult/turf/floor(get_turf(trail_around_us)) + qdel(trail_around_us) + + if(!blood_to_gain) + return + user.Beam(our_turf,icon_state="drainbeam", time = 15) + new /obj/effect/temp_visual/cult/sparks(get_turf(user)) + playsound(our_turf, 'sound/magic/enter_blood.ogg', 50) + to_chat(user, span_cult_italic("Your blood rite has gained [round(blood_to_gain)] charge\s from blood sources around you!")) + uses += max(1, round(blood_to_gain)) + +/** + * handles untargeted use of blood rites + * + * allows user to trade in spell uses for equipment or spells + */ /obj/item/melee/blood_magic/manipulator/attack_self(mob/living/user) - if(IS_CULTIST(user)) - var/static/list/spells = list( - "Bloody Halberd (150)" = image(icon = 'icons/obj/weapons/spear.dmi', icon_state = "occultpoleaxe0"), - "Blood Bolt Barrage (300)" = image(icon = 'icons/obj/weapons/guns/ballistic.dmi', icon_state = "arcane_barrage"), - "Blood Beam (500)" = image(icon = 'icons/obj/weapons/hand.dmi', icon_state = "disintegrate") - ) - var/choice = show_radial_menu(user, src, spells, custom_check = CALLBACK(src, PROC_REF(check_menu), user), require_near = TRUE) - if(!check_menu(user)) - to_chat(user, span_cult_italic("You decide against conducting a greater blood rite.")) - return - switch(choice) - if("Bloody Halberd (150)") - if(uses < BLOOD_HALBERD_COST) - to_chat(user, span_cult_italic("You need [BLOOD_HALBERD_COST] charges to perform this rite.")) - else - uses -= BLOOD_HALBERD_COST - var/turf/current_position = get_turf(user) - qdel(src) - var/datum/action/innate/cult/halberd/halberd_act_granted = new(user) - var/obj/item/melee/cultblade/halberd/rite = new(current_position) - halberd_act_granted.Grant(user, rite) - rite.halberd_act = halberd_act_granted - if(user.put_in_hands(rite)) - to_chat(user, span_cult_italic("A [rite.name] appears in your hand!")) - else - user.visible_message(span_warning("A [rite.name] appears at [user]'s feet!"), \ - span_cult_italic("A [rite.name] materializes at your feet.")) - if("Blood Bolt Barrage (300)") - if(uses < BLOOD_BARRAGE_COST) - to_chat(user, span_cult_italic("You need [BLOOD_BARRAGE_COST] charges to perform this rite.")) - else - var/obj/rite = new /obj/item/gun/magic/wand/arcane_barrage/blood() - uses -= BLOOD_BARRAGE_COST - qdel(src) - if(user.put_in_hands(rite)) - to_chat(user, span_cult("Your hands glow with power!")) - else - to_chat(user, span_cult_italic("You need a free hand for this rite!")) - qdel(rite) - if("Blood Beam (500)") - if(uses < BLOOD_BEAM_COST) - to_chat(user, span_cult_italic("You need [BLOOD_BEAM_COST] charges to perform this rite.")) - else - var/obj/rite = new /obj/item/blood_beam() - uses -= BLOOD_BEAM_COST - qdel(src) - if(user.put_in_hands(rite)) - to_chat(user, span_cult_large("Your hands glow with POWER OVERWHELMING!!!")) - else - to_chat(user, span_cult_italic("You need a free hand for this rite!")) - qdel(rite) + var/static/list/spells = list( + "Bloody Halberd (150)" = image(icon = 'icons/obj/weapons/spear.dmi', icon_state = "occultpoleaxe0"), + "Blood Bolt Barrage (300)" = image(icon = 'icons/obj/weapons/guns/ballistic.dmi', icon_state = "arcane_barrage"), + "Blood Beam (500)" = image(icon = 'icons/obj/weapons/hand.dmi', icon_state = "disintegrate") + ) + var/choice = show_radial_menu(user, src, spells, custom_check = CALLBACK(src, PROC_REF(check_menu), user), require_near = TRUE) + if(!check_menu(user)) + to_chat(user, span_cult_italic("You decide against conducting a greater blood rite.")) + return + + switch(choice) + if("Bloody Halberd (150)") + if(uses < BLOOD_HALBERD_COST) + to_chat(user, span_cult_italic("You need [BLOOD_HALBERD_COST] charges to perform this rite.")) + return + uses -= BLOOD_HALBERD_COST + var/turf/current_position = get_turf(user) + qdel(src) + var/datum/action/innate/cult/halberd/halberd_act_granted = new(user) + var/obj/item/melee/cultblade/halberd/rite = new(current_position) + halberd_act_granted.Grant(user, rite) + rite.halberd_act = halberd_act_granted + if(user.put_in_hands(rite)) + to_chat(user, span_cult_italic("A [rite.name] appears in your hand!")) + else + user.visible_message(span_warning("A [rite.name] appears at [user]'s feet!"), \ + span_cult_italic("A [rite.name] materializes at your feet.")) + + if("Blood Bolt Barrage (300)") + if(uses < BLOOD_BARRAGE_COST) + to_chat(user, span_cult_italic("You need [BLOOD_BARRAGE_COST] charges to perform this rite.")) + return + var/obj/rite = new /obj/item/gun/magic/wand/arcane_barrage/blood() + uses -= BLOOD_BARRAGE_COST + qdel(src) + if(user.put_in_hands(rite)) + to_chat(user, span_cult("Your hands glow with power!")) + else + to_chat(user, span_cult_italic("You need a free hand for this rite!")) + qdel(rite) + + if("Blood Beam (500)") + if(uses < BLOOD_BEAM_COST) + to_chat(user, span_cult_italic("You need [BLOOD_BEAM_COST] charges to perform this rite.")) + return + var/obj/rite = new /obj/item/blood_beam() + uses -= BLOOD_BEAM_COST + qdel(src) + if(user.put_in_hands(rite)) + to_chat(user, span_cult_large("Your hands glow with POWER OVERWHELMING!!!")) + else + to_chat(user, span_cult_italic("You need a free hand for this rite!")) + qdel(rite) /obj/item/melee/blood_magic/manipulator/proc/check_menu(mob/living/user) if(!istype(user)) @@ -839,3 +921,7 @@ if(user.incapacitated() || !user.Adjacent(src)) return FALSE return TRUE + +#undef USES_TO_BLOOD +#undef BLOOD_DRAIN_GAIN +#undef SELF_HEAL_PENALTY diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm index e9cf7b371d473..cc4a80d980fe3 100644 --- a/code/modules/antagonists/cult/runes.dm +++ b/code/modules/antagonists/cult/runes.dm @@ -104,6 +104,7 @@ Runes can either be invoked by one's self or with many different cultists. Each var/list/invokers = can_invoke(user) if(length(invokers) >= req_cultists) invoke(invokers) + SSblackbox.record_feedback("tally", "cult_rune_invoke", 1, "[name]") else to_chat(user, span_danger("You need [req_cultists - length(invokers)] more adjacent cultists to use this rune in such a manner.")) fail_invoke() diff --git a/code/modules/antagonists/wizard/equipment/soulstone.dm b/code/modules/antagonists/wizard/equipment/soulstone.dm index edb218a3c7631..b5ed82a7f2b50 100644 --- a/code/modules/antagonists/wizard/equipment/soulstone.dm +++ b/code/modules/antagonists/wizard/equipment/soulstone.dm @@ -394,6 +394,7 @@ soulstone_spirit.faction |= "[REF(user)]" //Add the master as a faction, allowing inter-mob cooperation if(IS_CULTIST(user)) soulstone_spirit.mind.add_antag_datum(/datum/antagonist/cult) + SSblackbox.record_feedback("tally", "cult_shade_created", 1) soulstone_spirit.cancel_camera() update_appearance() @@ -454,6 +455,7 @@ if(CONSTRUCT_JUGGERNAUT) if(IS_CULTIST(creator)) make_new_construct(/mob/living/basic/construct/juggernaut, target, creator, cultoverride, loc_override) // ignore themes, the actual giving of cult info is in the make_new_construct proc + SSblackbox.record_feedback("tally", "cult_shade_to_jugger", 1) return switch(theme) if(THEME_WIZARD) @@ -465,6 +467,7 @@ if(CONSTRUCT_WRAITH) if(IS_CULTIST(creator)) make_new_construct(/mob/living/basic/construct/wraith, target, creator, cultoverride, loc_override) // ignore themes, the actual giving of cult info is in the make_new_construct proc + SSblackbox.record_feedback("tally", "cult_shade_to_wraith", 1) return switch(theme) if(THEME_WIZARD) @@ -476,6 +479,7 @@ if(CONSTRUCT_ARTIFICER) if(IS_CULTIST(creator)) make_new_construct(/mob/living/basic/construct/artificer, target, creator, cultoverride, loc_override) // ignore themes, the actual giving of cult info is in the make_new_construct proc + SSblackbox.record_feedback("tally", "cult_shade_to_arti", 1) return switch(theme) if(THEME_WIZARD) diff --git a/code/modules/library/bibles.dm b/code/modules/library/bibles.dm index 656c90d77bbda..31630c550a1d5 100644 --- a/code/modules/library/bibles.dm +++ b/code/modules/library/bibles.dm @@ -324,6 +324,7 @@ GLOBAL_LIST_INIT(bibleitemstates, list( if(cultist) cultist.silent = TRUE cultist.on_removal() + SSblackbox.record_feedback("tally", "cult_shade_purified", 1) shade.theme = THEME_HOLY shade.name = "Purified [shade.real_name]" shade.update_appearance(UPDATE_ICON_STATE) diff --git a/code/modules/mob/living/basic/cult/shade.dm b/code/modules/mob/living/basic/cult/shade.dm index fac1d347665ef..bf6fbe13944a1 100644 --- a/code/modules/mob/living/basic/cult/shade.dm +++ b/code/modules/mob/living/basic/cult/shade.dm @@ -54,6 +54,8 @@ icon_living = icon_state /mob/living/basic/shade/death() + if(IS_CULTIST(src)) + SSblackbox.record_feedback("tally", "cult_shade_killed", 1) if(death_message == initial(death_message)) death_message = "lets out a contented sigh as [p_their()] form unwinds." ..() @@ -63,6 +65,11 @@ return FALSE return ..() +/mob/living/basic/shade/suicide_log(obj/item/suicide_tool) + if(IS_CULTIST(src)) + SSblackbox.record_feedback("tally", "cult_shade_suicided", 1) + ..() + /mob/living/basic/shade/attackby(obj/item/item, mob/user, params) if(istype(item, /obj/item/soulstone)) var/obj/item/soulstone/stone = item From 514d41409f885a27ad9697a93298a6adaafda834 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sat, 13 Apr 2024 07:32:08 +1200 Subject: [PATCH 203/938] Automatic changelog for PR #82539 [ci skip] --- html/changelogs/AutoChangeLog-pr-82539.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82539.yml diff --git a/html/changelogs/AutoChangeLog-pr-82539.yml b/html/changelogs/AutoChangeLog-pr-82539.yml new file mode 100644 index 0000000000000..6ad8a94a9ca26 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82539.yml @@ -0,0 +1,6 @@ +author: "Iamgoofball" +delete-after: True +changes: + - bugfix: "Fixes AI lag by re-adding idle mode to all AI that was lost with the simple mob to basic mob conversion." + - bugfix: "AI controllers with no clients around for 14 tiles will move into idle mode and stop planning or acting." + - bugfix: "AI controllers will now record how much time was spent on planning or un-idling AI controllers." \ No newline at end of file From 593d89666597a599efe7a01600ed3697402c2db5 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sat, 13 Apr 2024 07:32:14 +1200 Subject: [PATCH 204/938] Automatic changelog for PR #82511 [ci skip] --- html/changelogs/AutoChangeLog-pr-82511.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82511.yml diff --git a/html/changelogs/AutoChangeLog-pr-82511.yml b/html/changelogs/AutoChangeLog-pr-82511.yml new file mode 100644 index 0000000000000..bd37d23d08846 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82511.yml @@ -0,0 +1,4 @@ +author: "ZephyrTFA" +delete-after: True +changes: + - admin: "Something changed, but you shouldn't be able to notice. If verbs are funky report this to <@946283057915232337> on discord." \ No newline at end of file From fe26373572e41415ec12e2b0785f0c6dc2567577 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sat, 13 Apr 2024 07:32:40 +1200 Subject: [PATCH 205/938] Automatic changelog for PR #82444 [ci skip] --- html/changelogs/AutoChangeLog-pr-82444.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82444.yml diff --git a/html/changelogs/AutoChangeLog-pr-82444.yml b/html/changelogs/AutoChangeLog-pr-82444.yml new file mode 100644 index 0000000000000..f59e7e6800f93 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82444.yml @@ -0,0 +1,7 @@ +author: "wesoda25" +delete-after: True +changes: + - bugfix: "blood rites - will no longer delete after running out of charges" + - bugfix: "blood rites - now heal shades as well" + - bugfix: "blood rites - now charge 1.65x for self healing as opposed to the ~2x they were before" + - code_imp: "blood rites code hurts my eyes a bit less now" \ No newline at end of file From fc18ee3abce28d012125f23503e1c2b432117420 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Sat, 13 Apr 2024 00:17:47 +0000 Subject: [PATCH 206/938] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-82291.yml | 4 -- html/changelogs/AutoChangeLog-pr-82444.yml | 7 --- html/changelogs/AutoChangeLog-pr-82491.yml | 4 -- html/changelogs/AutoChangeLog-pr-82511.yml | 4 -- html/changelogs/AutoChangeLog-pr-82539.yml | 6 -- html/changelogs/AutoChangeLog-pr-82555.yml | 5 -- html/changelogs/AutoChangeLog-pr-82566.yml | 6 -- html/changelogs/AutoChangeLog-pr-82571.yml | 4 -- html/changelogs/AutoChangeLog-pr-82574.yml | 4 -- html/changelogs/AutoChangeLog-pr-82577.yml | 13 ----- html/changelogs/AutoChangeLog-pr-82578.yml | 4 -- html/changelogs/AutoChangeLog-pr-82585.yml | 4 -- html/changelogs/AutoChangeLog-pr-82589.yml | 4 -- html/changelogs/AutoChangeLog-pr-82591.yml | 4 -- html/changelogs/AutoChangeLog-pr-82593.yml | 4 -- html/changelogs/AutoChangeLog-pr-82597.yml | 4 -- html/changelogs/archive/2024-04.yml | 68 ++++++++++++++++++++++ 17 files changed, 68 insertions(+), 81 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-82291.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82444.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82491.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82511.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82539.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82555.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82566.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82571.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82574.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82577.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82578.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82585.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82589.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82591.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82593.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82597.yml diff --git a/html/changelogs/AutoChangeLog-pr-82291.yml b/html/changelogs/AutoChangeLog-pr-82291.yml deleted file mode 100644 index 365329f1e6100..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82291.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "hyperjll" -delete-after: True -changes: - - balance: "Haloperidol now purges 2 units per second of itself, should the victim have zero stamina. (Stamcrit)" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82444.yml b/html/changelogs/AutoChangeLog-pr-82444.yml deleted file mode 100644 index f59e7e6800f93..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82444.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: "wesoda25" -delete-after: True -changes: - - bugfix: "blood rites - will no longer delete after running out of charges" - - bugfix: "blood rites - now heal shades as well" - - bugfix: "blood rites - now charge 1.65x for self healing as opposed to the ~2x they were before" - - code_imp: "blood rites code hurts my eyes a bit less now" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82491.yml b/html/changelogs/AutoChangeLog-pr-82491.yml deleted file mode 100644 index 19030972bfb71..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82491.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "00-Steven" -delete-after: True -changes: - - refactor: "Instead of being hardcoded to the pen, renaming items is now an element. Currently only pens have this, and functionality should be the same, but please report it if you find any items that were renamable but now aren't." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82511.yml b/html/changelogs/AutoChangeLog-pr-82511.yml deleted file mode 100644 index bd37d23d08846..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82511.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "ZephyrTFA" -delete-after: True -changes: - - admin: "Something changed, but you shouldn't be able to notice. If verbs are funky report this to <@946283057915232337> on discord." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82539.yml b/html/changelogs/AutoChangeLog-pr-82539.yml deleted file mode 100644 index 6ad8a94a9ca26..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82539.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "Iamgoofball" -delete-after: True -changes: - - bugfix: "Fixes AI lag by re-adding idle mode to all AI that was lost with the simple mob to basic mob conversion." - - bugfix: "AI controllers with no clients around for 14 tiles will move into idle mode and stop planning or acting." - - bugfix: "AI controllers will now record how much time was spent on planning or un-idling AI controllers." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82555.yml b/html/changelogs/AutoChangeLog-pr-82555.yml deleted file mode 100644 index 76db2d5161bce..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82555.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Jacquerel" -delete-after: True -changes: - - balance: "The Bioscrambler will now actively attempt to get closer to living targets rather than chilling in a closet nobody goes into (unless you trap it in a containment field)." - - balance: "Because it can now travel through walls, the Bioscrambler will no longer transform you THROUGH walls." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82566.yml b/html/changelogs/AutoChangeLog-pr-82566.yml deleted file mode 100644 index 04a91ee24f5f0..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82566.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "Ketrai" -delete-after: True -changes: - - qol: "chef equipment can now deposit and withdraw to/from trays!" - - qol: "chef now has access to griddle and oven sized trays!" - - qol: "service can now print soup pots" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82571.yml b/html/changelogs/AutoChangeLog-pr-82571.yml deleted file mode 100644 index 0f9970e8c90ee..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82571.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "jlsnow301" -delete-after: True -changes: - - bugfix: "Airlock electronics and other access-config type UIs should look much better." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82574.yml b/html/changelogs/AutoChangeLog-pr-82574.yml deleted file mode 100644 index adf755aa3d656..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82574.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "StrangeWeirdKitten" -delete-after: True -changes: - - balance: "The upload and communication boards directly have trackers installed, activated only when authenticated." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82577.yml b/html/changelogs/AutoChangeLog-pr-82577.yml deleted file mode 100644 index 4fbb0ab9352f2..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82577.yml +++ /dev/null @@ -1,13 +0,0 @@ -author: "Melbert" -delete-after: True -changes: - - bugfix: "You can't change the GPS tag of something unless you can actually use the GPS" - - bugfix: "You can't set the teleporter to a location unless you can actually use the teleporter" - - bugfix: "You can't reply to request console requests unless you can actually use the console" - - bugfix: "You can't update AI lawboards unless you're actually holding them" - - bugfix: "You can't update a borg rename board unless you're actually holding it" - - bugfix: "You can't mess with plumbing machines unless you can actually use them" - - bugfix: "You can't recolor / relayer ducts unless you're actually holding them" - - bugfix: "You can't magically wire APCs and SMESs unless you're right by them" - - bugfix: "You can't use Stargazer Telepathy on people who you can't see" - - bugfix: "You can't configure the Inspector Hat unless you can actually use it" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82578.yml b/html/changelogs/AutoChangeLog-pr-82578.yml deleted file mode 100644 index 6a516de74aec7..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82578.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DaCoolBoss" -delete-after: True -changes: - - spellcheck: "Fixes a typo in the cargo console." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82585.yml b/html/changelogs/AutoChangeLog-pr-82585.yml deleted file mode 100644 index cc22150fd1622..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82585.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Horatio22" -delete-after: True -changes: - - spellcheck: "grammar fixes in the roundstart advisory warnings" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82589.yml b/html/changelogs/AutoChangeLog-pr-82589.yml deleted file mode 100644 index 0879da0659c51..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82589.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "JohnFulpWillard" -delete-after: True -changes: - - bugfix: "Advanced camera consoles now boots you off when you're moved out of reach." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82591.yml b/html/changelogs/AutoChangeLog-pr-82591.yml deleted file mode 100644 index c6557e26a8a24..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82591.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SyncIt21" -delete-after: True -changes: - - bugfix: "chem master properly shuts down if it loses power mid printing and won't transfer reagents for the same" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82593.yml b/html/changelogs/AutoChangeLog-pr-82593.yml deleted file mode 100644 index d212d03fc247f..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82593.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "jlsnow301" -delete-after: True -changes: - - bugfix: "Deviants buffed: Rogue shoelacing, pickpocketing and restraint resisting no longer give cogbar icons." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82597.yml b/html/changelogs/AutoChangeLog-pr-82597.yml deleted file mode 100644 index 884870c015195..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82597.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Watermelon914" -delete-after: True -changes: - - bugfix: "LUA: Registering a signal on a deleted datum will throw a more descriptive error message." \ No newline at end of file diff --git a/html/changelogs/archive/2024-04.yml b/html/changelogs/archive/2024-04.yml index 0f9f4f1c12f61..bb738f4cc04b9 100644 --- a/html/changelogs/archive/2024-04.yml +++ b/html/changelogs/archive/2024-04.yml @@ -402,3 +402,71 @@ disappointedButNotSuprised: - rscadd: Coffee machines can now carry over reagents from the beans to the coffee (surely no one will inject poison into them) +2024-04-13: + 00-Steven: + - refactor: Instead of being hardcoded to the pen, renaming items is now an element. + Currently only pens have this, and functionality should be the same, but please + report it if you find any items that were renamable but now aren't. + DaCoolBoss: + - spellcheck: Fixes a typo in the cargo console. + Horatio22: + - spellcheck: grammar fixes in the roundstart advisory warnings + Iamgoofball: + - bugfix: Fixes AI lag by re-adding idle mode to all AI that was lost with the simple + mob to basic mob conversion. + - bugfix: AI controllers with no clients around for 14 tiles will move into idle + mode and stop planning or acting. + - bugfix: AI controllers will now record how much time was spent on planning or + un-idling AI controllers. + Jacquerel: + - balance: The Bioscrambler will now actively attempt to get closer to living targets + rather than chilling in a closet nobody goes into (unless you trap it in a containment + field). + - balance: Because it can now travel through walls, the Bioscrambler will no longer + transform you THROUGH walls. + JohnFulpWillard: + - bugfix: Advanced camera consoles now boots you off when you're moved out of reach. + Ketrai: + - qol: chef equipment can now deposit and withdraw to/from trays! + - qol: chef now has access to griddle and oven sized trays! + - qol: service can now print soup pots + Melbert: + - bugfix: You can't change the GPS tag of something unless you can actually use + the GPS + - bugfix: You can't set the teleporter to a location unless you can actually use + the teleporter + - bugfix: You can't reply to request console requests unless you can actually use + the console + - bugfix: You can't update AI lawboards unless you're actually holding them + - bugfix: You can't update a borg rename board unless you're actually holding it + - bugfix: You can't mess with plumbing machines unless you can actually use them + - bugfix: You can't recolor / relayer ducts unless you're actually holding them + - bugfix: You can't magically wire APCs and SMESs unless you're right by them + - bugfix: You can't use Stargazer Telepathy on people who you can't see + - bugfix: You can't configure the Inspector Hat unless you can actually use it + StrangeWeirdKitten: + - balance: The upload and communication boards directly have trackers installed, + activated only when authenticated. + SyncIt21: + - bugfix: chem master properly shuts down if it loses power mid printing and won't + transfer reagents for the same + Watermelon914: + - bugfix: 'LUA: Registering a signal on a deleted datum will throw a more descriptive + error message.' + ZephyrTFA: + - admin: Something changed, but you shouldn't be able to notice. If verbs are funky + report this to <@946283057915232337> on discord. + hyperjll: + - balance: Haloperidol now purges 2 units per second of itself, should the victim + have zero stamina. (Stamcrit) + jlsnow301: + - bugfix: 'Deviants buffed: Rogue shoelacing, pickpocketing and restraint resisting + no longer give cogbar icons.' + - bugfix: Airlock electronics and other access-config type UIs should look much + better. + wesoda25: + - bugfix: blood rites - will no longer delete after running out of charges + - bugfix: blood rites - now heal shades as well + - bugfix: blood rites - now charge 1.65x for self healing as opposed to the ~2x + they were before + - code_imp: blood rites code hurts my eyes a bit less now From 625b84ecf923d8f68f14a6675fbfdd3415933adb Mon Sep 17 00:00:00 2001 From: Joshua Kidder <49173900+Metekillot@users.noreply.github.com> Date: Fri, 12 Apr 2024 23:26:19 -0400 Subject: [PATCH 207/938] Fixes to zombie regen (and incidentally behavior of TRAIT_NODEATH) (#82602) ## About The Pull Request Zombie regen was being cancelled out by the brute damage you take while in crit with TRAIT_NOBREATH (which zombies have) and since they have TRAIT_NODEATH they would, at a certain point, end up nearly permacritted unless they were somehow killed (which TRAIT_NODEATH would prevent in almost all cases). Zombies now have TRAIT_NOCRITDAMAGE so they don't take this damage, and carbon/death() and human/death() now take TRAIT_NODEATH into account, since there are hard calls to death() littered everywhere instead of going through the actual body damage dealing code. If you have NODEATH you'll still die if gibbed. ## Why It's Good For The Game Fixes #82601 Fixes TRAIT_NODEATH actually making it so you... nodeath... ## Changelog Being in critical condition no longer damages zombies. :cl: fix: Being in critical condition no longer damages zombies. code: TRAIT_NODEATH will actually stop you dying in (most) cases. /:cl: --- code/modules/mob/living/carbon/death.dm | 2 +- code/modules/mob/living/carbon/human/death.dm | 2 +- code/modules/mob/living/carbon/human/species_types/zombies.dm | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/code/modules/mob/living/carbon/death.dm b/code/modules/mob/living/carbon/death.dm index 41a958518c597..f74c2c1ca2165 100644 --- a/code/modules/mob/living/carbon/death.dm +++ b/code/modules/mob/living/carbon/death.dm @@ -1,5 +1,5 @@ /mob/living/carbon/death(gibbed) - if(stat == DEAD) + if(stat == DEAD || HAS_TRAIT(src, TRAIT_NODEATH) && !gibbed) return losebreath = 0 diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index dd97c12bd844f..08454bc4657fd 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -20,7 +20,7 @@ GLOBAL_LIST_EMPTY(dead_players_during_shift) new /obj/effect/decal/remains/human(loc) /mob/living/carbon/human/death(gibbed) - if(stat == DEAD) + if(stat == DEAD || HAS_TRAIT(src, TRAIT_NODEATH) && !gibbed) return stop_sound_channel(CHANNEL_HEARTBEAT) var/obj/item/organ/internal/heart/human_heart = get_organ_slot(ORGAN_SLOT_HEART) diff --git a/code/modules/mob/living/carbon/human/species_types/zombies.dm b/code/modules/mob/living/carbon/human/species_types/zombies.dm index 6c119a31f0097..c763127a4be7b 100644 --- a/code/modules/mob/living/carbon/human/species_types/zombies.dm +++ b/code/modules/mob/living/carbon/human/species_types/zombies.dm @@ -14,6 +14,7 @@ TRAIT_LIVERLESS_METABOLISM, TRAIT_NOBREATH, TRAIT_NODEATH, + TRAIT_NOCRITDAMAGE, TRAIT_NOHUNGER, TRAIT_NO_DNA_COPY, TRAIT_NO_ZOMBIFY, @@ -107,6 +108,7 @@ TRAIT_LIMBATTACHMENT, TRAIT_LIVERLESS_METABOLISM, TRAIT_NOBREATH, + TRAIT_NOCRITDAMAGE, TRAIT_NODEATH, TRAIT_NOHUNGER, TRAIT_NO_DNA_COPY, From b4b2306380c12f9e7de0ce5bcf8f7eeff53c1413 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sat, 13 Apr 2024 15:26:40 +1200 Subject: [PATCH 208/938] Automatic changelog for PR #82602 [ci skip] --- html/changelogs/AutoChangeLog-pr-82602.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82602.yml diff --git a/html/changelogs/AutoChangeLog-pr-82602.yml b/html/changelogs/AutoChangeLog-pr-82602.yml new file mode 100644 index 0000000000000..b63e83f675c94 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82602.yml @@ -0,0 +1,5 @@ +author: "Metekillot" +delete-after: True +changes: + - bugfix: "Being in critical condition no longer damages zombies." + - code_imp: "TRAIT_NODEATH will actually stop you dying in (most) cases." \ No newline at end of file From 035205fb83d5054cd4569bc5d4c4576dac237cea Mon Sep 17 00:00:00 2001 From: _0Steven <42909981+00-Steven@users.noreply.github.com> Date: Sat, 13 Apr 2024 23:24:17 +0200 Subject: [PATCH 209/938] [NO GBP] ...Remember to add SIGNAL_HANDLER (#82630) ## About The Pull Request Just realized I forgot to add `SIGNAL_HANDLER` to the all-nighter `on_removed_limb(...)` proc, even though it handles signals. ## Why It's Good For The Game https://github.com/tgstation/tgstation/blob/fe26373572e41415ec12e2b0785f0c6dc2567577/code/__DEFINES/dcs/helpers.dm#L9-L11 --- code/datums/quirks/negative_quirks/all_nighter.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/datums/quirks/negative_quirks/all_nighter.dm b/code/datums/quirks/negative_quirks/all_nighter.dm index 7f9f051ecf75a..f5288b8221560 100644 --- a/code/datums/quirks/negative_quirks/all_nighter.dm +++ b/code/datums/quirks/negative_quirks/all_nighter.dm @@ -43,6 +43,8 @@ ///if we have bags and lost a head, remove them /datum/quirk/all_nighter/proc/on_removed_limb(datum/source, obj/item/bodypart/removed_limb, special, dismembered) + SIGNAL_HANDLER + if(bodypart_overlay && istype(removed_limb, /obj/item/bodypart/head)) remove_bags() From 616c7f31c82e752e968f6bc569e5bda77e7318b8 Mon Sep 17 00:00:00 2001 From: John Willard <53777086+JohnFulpWillard@users.noreply.github.com> Date: Sat, 13 Apr 2024 21:25:08 +0000 Subject: [PATCH 210/938] Security photobooths have their own ID (#82628) ## About The Pull Request Prevents the HoP's photobooth button from connecting to the security photobooth via having the same ID. ## Why It's Good For The Game I forgot to add this when I made the security photobooth but it's important that by default without any varedits, the HoP and security photobooths stay separate. ## Changelog :cl: fix: The HoP's photobooth button is now consistently connected to the HoP's photobooth. /:cl: --- code/game/machinery/photobooth.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/game/machinery/photobooth.dm b/code/game/machinery/photobooth.dm index d77759742694c..321ae7efd6e76 100644 --- a/code/game/machinery/photobooth.dm +++ b/code/game/machinery/photobooth.dm @@ -38,6 +38,7 @@ req_one_access = list(ACCESS_SECURITY) color = COLOR_LIGHT_GRAYISH_RED add_height_chart = TRUE + button_id = "photobooth_machine_security" /obj/machinery/photobooth/Initialize(mapload) . = ..() From ffde31ccb7102384a0fb5bf505f54de7ba09dcab Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sun, 14 Apr 2024 09:25:28 +1200 Subject: [PATCH 211/938] Automatic changelog for PR #82628 [ci skip] --- html/changelogs/AutoChangeLog-pr-82628.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82628.yml diff --git a/html/changelogs/AutoChangeLog-pr-82628.yml b/html/changelogs/AutoChangeLog-pr-82628.yml new file mode 100644 index 0000000000000..b3a9c43a5d354 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82628.yml @@ -0,0 +1,4 @@ +author: "JohnFulpWillard" +delete-after: True +changes: + - bugfix: "The HoP's photobooth button is now consistently connected to the HoP's photobooth." \ No newline at end of file From ce6be9b0705ac9fc36167164c21a4543aad9d4e0 Mon Sep 17 00:00:00 2001 From: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Date: Sun, 14 Apr 2024 02:55:34 +0530 Subject: [PATCH 212/938] Operating computers clears its display procedures upon patient loss from table (#82616) ## About The Pull Request - Fixes #82580 We have to update the ui data if the patient leaves the table ## Changelog :cl: fix: Operating computers clears its ui display procedures if patient is moved out of the operating table in any way /:cl: --- code/game/machinery/computer/operating_computer.dm | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/code/game/machinery/computer/operating_computer.dm b/code/game/machinery/computer/operating_computer.dm index b60f3a67b649d..d0ea49df27b59 100644 --- a/code/game/machinery/computer/operating_computer.dm +++ b/code/game/machinery/computer/operating_computer.dm @@ -103,6 +103,7 @@ data["table"] = table data["patient"] = list() + data["procedures"] = list() if(!table.patient) return data var/mob/living/carbon/patient = table.patient @@ -136,7 +137,6 @@ data["patient"]["fireLoss"] = patient.getFireLoss() data["patient"]["toxLoss"] = patient.getToxLoss() data["patient"]["oxyLoss"] = patient.getOxyLoss() - data["procedures"] = list() if(patient.surgeries.len) for(var/datum/surgery/procedure in patient.surgeries) var/datum/surgery_step/surgery_step = procedure.get_surgery_step() @@ -159,8 +159,6 @@ )) return data - - /obj/machinery/computer/operating/ui_act(action, params) . = ..() if(.) From 0611009eb43bb2afef1cd6b3b6bc1adf9dcd9943 Mon Sep 17 00:00:00 2001 From: Jeremiah <42397676+jlsnow301@users.noreply.github.com> Date: Sat, 13 Apr 2024 14:26:02 -0700 Subject: [PATCH 213/938] React cleanup (#82607) ## About The Pull Request - No defaultHooks in react. Might fix issues where pages were not scrollable on hover. - createRef in a functional component. should be useref ## Why It's Good For The Game Code improvement --- tgui/packages/tgui/components/Autofocus.tsx | 18 ++++++++++------ .../PreferencesMenu/KeybindingsPage.tsx | 6 ------ tgui/packages/tgui/layouts/Layout.tsx | 21 ++++++++++++++----- 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/tgui/packages/tgui/components/Autofocus.tsx b/tgui/packages/tgui/components/Autofocus.tsx index a0b3f6f765907..403dbe2e96532 100644 --- a/tgui/packages/tgui/components/Autofocus.tsx +++ b/tgui/packages/tgui/components/Autofocus.tsx @@ -1,17 +1,23 @@ -import { createRef, PropsWithChildren, useEffect } from 'react'; +import { PropsWithChildren, useEffect, useRef } from 'react'; -export const Autofocus = (props: PropsWithChildren) => { - const ref = createRef(); +/** Used to force the window to steal focus on load. Children optional */ +export function Autofocus(props: PropsWithChildren) { + const { children } = props; + const ref = useRef(null); useEffect(() => { - setTimeout(() => { + const timer = setTimeout(() => { ref.current?.focus(); }, 1); + + return () => { + clearTimeout(timer); + }; }, []); return (
    - {props.children} + {children}
    ); -}; +} diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/KeybindingsPage.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/KeybindingsPage.tsx index c3b123105ab97..d8c2bccc61c40 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/KeybindingsPage.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/KeybindingsPage.tsx @@ -177,12 +177,6 @@ const KeybindingName = (props: { keybinding: Keybinding }) => { ); }; -KeybindingName.defaultHooks = { - onComponentShouldUpdate: (lastProps, nextProps) => { - return lastProps.keybinding !== nextProps.keybinding; - }, -}; - const ResetToDefaultButton = (props: { keybindingId: string }) => { const { act } = useBackend(); diff --git a/tgui/packages/tgui/layouts/Layout.tsx b/tgui/packages/tgui/layouts/Layout.tsx index 74aad987d215b..173ed1cbb432d 100644 --- a/tgui/packages/tgui/layouts/Layout.tsx +++ b/tgui/packages/tgui/layouts/Layout.tsx @@ -5,6 +5,7 @@ */ import { classes } from 'common/react'; +import { useEffect, useRef } from 'react'; import { BoxProps, @@ -40,6 +41,20 @@ type ContentProps = Partial<{ function LayoutContent(props: ContentProps) { const { className, scrollable, children, ...rest } = props; + const node = useRef(null); + + useEffect(() => { + const self = node.current; + + if (self && scrollable) { + addScrollableNode(self); + } + return () => { + if (self && scrollable) { + removeScrollableNode(self); + } + }; + }, []); return (
    {children} @@ -56,9 +72,4 @@ function LayoutContent(props: ContentProps) { ); } -LayoutContent.defaultHooks = { - onComponentDidMount: (node) => addScrollableNode(node), - onComponentWillUnmount: (node) => removeScrollableNode(node), -}; - Layout.Content = LayoutContent; From 0f2eb27199e7dbe623ec8996aa89836957787753 Mon Sep 17 00:00:00 2001 From: _0Steven <42909981+00-Steven@users.noreply.github.com> Date: Sat, 13 Apr 2024 23:27:18 +0200 Subject: [PATCH 214/938] Fix buckled alert unbuckling not working properly (#82627) ## About The Pull Request So funny thing, while trying to reproduce a different issue on the current master, I coincidentally let my local instance start without reading, latejoined on the shuttle, and I noticed it wasn't letting me unbuckle as easily. Looking into this a bit later, it seems as if it's a line #82593 accidentally changed while moving around the `/mob/living/carbon/resist_buckle()` proc's flow. https://github.com/tgstation/tgstation/blob/fe26373572e41415ec12e2b0785f0c6dc2567577/code/modules/mob/living/carbon/carbon.dm#L238-L241 While before it was ```dm /mob/living/carbon/resist_buckle() if(HAS_TRAIT(src, TRAIT_RESTRAINED)) (...) else buckled.user_unbuckle_mob(src,src) ``` Just changing this to `buckled.user_unbuckle_mob(src, src)` fixes this. ## Why It's Good For The Game Fixes buckled alert unbuckling not working properly. Fixes #82627. ## Changelog :cl: fix: Clicking the buckled alert unbuckles you again. /:cl: --- code/modules/mob/living/carbon/carbon.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 670f98fed05bd..1b9511b88dc1f 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -237,7 +237,7 @@ /mob/living/carbon/resist_buckle() if(!HAS_TRAIT(src, TRAIT_RESTRAINED)) - buckled.user_buckle_mob(src, src) + buckled.user_unbuckle_mob(src, src) return changeNext_move(CLICK_CD_BREAKOUT) From 3a1cd16858ee14928e1c2dba0bc9cfca134721b0 Mon Sep 17 00:00:00 2001 From: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Date: Sun, 14 Apr 2024 02:58:08 +0530 Subject: [PATCH 215/938] Advanced camera consoles correctly deactivates when something happens to it or the user (#82619) ## About The Pull Request - Fixes #82520 1. The eye deactivates when the machine is destroyed/deleted 2. The eye deactivates when the machine loses power 3. The computer constantly moniters the users status inside `process()` and will deactivate when anything happens to them. Its not enough to just hook onto to the mobs `COMSIG_MOVABLE_MOVED` signal. Literarly anything can happen to them so we have to check constantly for any changes ## Changelog :cl: fix: advanced camera consoles correctly deactivate when something happens(no proximity, no power etc) to its user /:cl: --- code/game/machinery/_machinery.dm | 4 ++- .../machinery/computer/camera_advanced.dm | 35 +++++++++++-------- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index a10f29ac40acd..f7a14f4cd6776 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -588,13 +588,15 @@ set_panel_open(!panel_open) /obj/machinery/can_interact(mob/user) + if(QDELETED(user)) + return FALSE + if((machine_stat & (NOPOWER|BROKEN)) && !(interaction_flags_machine & INTERACT_MACHINE_OFFLINE)) // Check if the machine is broken, and if we can still interact with it if so return FALSE if(SEND_SIGNAL(user, COMSIG_TRY_USE_MACHINE, src) & COMPONENT_CANT_USE_MACHINE_INTERACT) return FALSE - if(isAdminGhostAI(user)) return TRUE //the Gods have unlimited power and do not care for things such as range or blindness diff --git a/code/game/machinery/computer/camera_advanced.dm b/code/game/machinery/computer/camera_advanced.dm index 8635eb546d728..1868bc3c38c5c 100644 --- a/code/game/machinery/computer/camera_advanced.dm +++ b/code/game/machinery/computer/camera_advanced.dm @@ -4,6 +4,8 @@ icon_screen = "cameras" icon_keyboard = "security_key" light_color = COLOR_SOFT_RED + processing_flags = START_PROCESSING_MANUALLY + var/list/z_lock = list() // Lock use to these z levels var/lock_override = NONE var/mob/camera/ai_eye/remote/eyeobj @@ -50,6 +52,20 @@ if(move_down_action) actions += new move_down_action(src) +/obj/machinery/computer/camera_advanced/Destroy() + if(!QDELETED(current_user)) + unset_machine(current_user) + if(eyeobj) + QDEL_NULL(eyeobj) + QDEL_LIST(actions) + current_user = null + return ..() + +/obj/machinery/computer/camera_advanced/process() + if(!can_use(current_user) || (issilicon(current_user) && !current_user.has_unlimited_silicon_privilege)) + unset_machine(current_user) + return PROCESS_KILL + /obj/machinery/computer/camera_advanced/connect_to_shuttle(mapload, obj/docking_port/mobile/port, obj/docking_port/stationary/dock) for(var/i in networks) networks -= i @@ -85,7 +101,7 @@ eyeobj.setLoc(eyeobj.loc) if(should_supress_view_changes) user.client.view_size.supress() - RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(check_eye)) + begin_processing() /obj/machinery/computer/camera_advanced/remove_eye_control(mob/living/user) if(isnull(user?.client)) @@ -104,25 +120,16 @@ eyeobj.eye_user = null user.remote_control = null current_user = null - unset_machine(user) playsound(src, 'sound/machines/terminal_off.ogg', 25, FALSE) - UnregisterSignal(user, COMSIG_MOVABLE_MOVED) - -/obj/machinery/computer/camera_advanced/proc/check_eye(mob/user) - SIGNAL_HANDLER - if(!can_use(user) || (issilicon(user) && !user.has_unlimited_silicon_privilege)) - unset_machine(user) -/obj/machinery/computer/camera_advanced/Destroy() - if(eyeobj) - QDEL_NULL(eyeobj) - QDEL_LIST(actions) - current_user = null - return ..() +/obj/machinery/computer/camera_advanced/on_set_is_operational(old_value) + if(!is_operational) + unset_machine(current_user) /obj/machinery/computer/camera_advanced/proc/unset_machine(mob/M) if(M == current_user) remove_eye_control(M) + end_processing() /obj/machinery/computer/camera_advanced/proc/can_use(mob/living/user) return can_interact(user) From 869b9478a8077e2c9c73f82159f07afe282bb41c Mon Sep 17 00:00:00 2001 From: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Date: Sun, 14 Apr 2024 02:58:41 +0530 Subject: [PATCH 216/938] Oven tray checks for ovens (#82615) ## About The Pull Request - Fixes #82610 Only oven trays have this proc not serving trays or other stuff ![Screenshot (408)](https://github.com/tgstation/tgstation/assets/110812394/4867cc14-9df3-4398-9d2d-f8e38b5f0da9) Also oven trays have a null atom storage which prevents it from being put back in the oven after taking it out. So we remove that check ## Changelog :cl: fix: you can put back the oven tray after you take it out fix: only oven trays are allowed in ovens preventing baked food runtimes /:cl: --- code/modules/food_and_drinks/machinery/oven.dm | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/code/modules/food_and_drinks/machinery/oven.dm b/code/modules/food_and_drinks/machinery/oven.dm index da0c75824cad9..8546273774587 100644 --- a/code/modules/food_and_drinks/machinery/oven.dm +++ b/code/modules/food_and_drinks/machinery/oven.dm @@ -99,11 +99,10 @@ update_appearance() use_energy(active_power_usage) - /obj/machinery/oven/attackby(obj/item/item, mob/user, params) - if(!open || used_tray || !item.atom_storage) + if(!open || used_tray || !istype(item, /obj/item/plate/oven_tray)) return ..() - + if(user.transferItemToLoc(item, src, silent = FALSE)) to_chat(user, span_notice("You put [item] in [src].")) add_tray_to_oven(item, user) @@ -253,7 +252,7 @@ if(isnull(item.atom_storage)) return - + if(is_right_clicking) var/obj/item/storage/tray = item From 4019835b3e88396519d84106a22a6eeca8995b8d Mon Sep 17 00:00:00 2001 From: Jacquerel Date: Sat, 13 Apr 2024 22:30:14 +0100 Subject: [PATCH 217/938] Living Limb fixes (feat: Basic mobs attack random body zones again) (#82556) ## About The Pull Request Reworks Living Limb code to fix a bunch of runtimes and issues I saw while testing Bioscrambler. Specifically, the contained mobs are now initialised via element following attachment so that signal registration can occur at the correct time. This allows limbs to function correctly when added from nullspace via admin panel or bioscrambler. Secondarily (and more wide-ranging) at some point (probably #79563) we inadvertently made basic mobs only attack the target's chest instead of spreading damage. This is problematic for Living Flesh which can only attach itself to damaged limbs but was left unable to attack damaged limbs. I've fixed this in a way which is maybe stupid: adding an element which randomises attack zone pre-attack. Living limbs also limit this to _only_ limbs (although it will fall back to chest if you have no limbs at all). This is _technically_ still different, the previous behaviour used `adjustBruteLoss` and `adjustFireLoss` and would spread the damage across your entire body, but there isn't a route to that via the new interface and this seems close enough. ## Changelog :cl: fix: Living Limbs created by Bioscrambler will be alive. fix: Living Limbs can once more attach themselves to your body. balance: Living Limbs will prioritise attacking your limbs. fix: Basic Mobs will once again spread their damage across body zones instead of only attacking your chest. /:cl: --- code/__DEFINES/basic_mobs.dm | 2 ++ code/__DEFINES/combat.dm | 2 ++ .../datums/elements/attack_zone_randomiser.dm | 33 +++++++++++++++++++ .../elements/living_limb_initialiser.dm | 19 +++++++++++ code/modules/mining/equipment/mining_tools.dm | 2 +- code/modules/mob/living/basic/basic.dm | 6 ++++ .../mob/living/basic/ruin_defender/flesh.dm | 9 +++-- code/modules/religion/burdened/psyker.dm | 2 +- code/modules/surgery/bodyparts/_bodyparts.dm | 4 +-- .../surgery/bodyparts/dismemberment.dm | 2 +- code/modules/surgery/bodyparts/helpers.dm | 4 +-- .../bodyparts/species_parts/misc_bodyparts.dm | 20 +++++------ tgstation.dme | 2 ++ 13 files changed, 86 insertions(+), 21 deletions(-) create mode 100644 code/datums/elements/attack_zone_randomiser.dm create mode 100644 code/datums/elements/living_limb_initialiser.dm diff --git a/code/__DEFINES/basic_mobs.dm b/code/__DEFINES/basic_mobs.dm index b673d0e7a120b..c827f760b8a5c 100644 --- a/code/__DEFINES/basic_mobs.dm +++ b/code/__DEFINES/basic_mobs.dm @@ -14,6 +14,8 @@ #define IMMUNE_TO_FISTS (1<<4) /// Mob is immune to getting wet #define IMMUNE_TO_GETTING_WET (1<<5) +/// Disables the function of attacking random body zones +#define PRECISE_ATTACK_ZONES (1<<6) /// Temporary trait applied when an attack forecast animation has completed #define TRAIT_BASIC_ATTACK_FORECAST "trait_basic_attack_forecast" diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index 847fd52cc2232..686e422b02019 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -282,6 +282,8 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list( #define BODY_ZONE_L_LEG "l_leg" #define BODY_ZONE_R_LEG "r_leg" +GLOBAL_LIST_INIT(all_body_zones, list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG)) +GLOBAL_LIST_INIT(limb_zones, list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG)) GLOBAL_LIST_INIT(arm_zones, list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)) #define BODY_ZONE_PRECISE_EYES "eyes" diff --git a/code/datums/elements/attack_zone_randomiser.dm b/code/datums/elements/attack_zone_randomiser.dm new file mode 100644 index 0000000000000..35275e11a9bb2 --- /dev/null +++ b/code/datums/elements/attack_zone_randomiser.dm @@ -0,0 +1,33 @@ +/// Pick a random attack zone before you attack something +/datum/element/attack_zone_randomiser + element_flags = ELEMENT_BESPOKE + argument_hash_start_idx = 2 + /// List of attack zones you can select, should be a subset of GLOB.all_body_zones + var/list/valid_attack_zones + +/datum/element/attack_zone_randomiser/Attach(datum/target, list/valid_attack_zones = GLOB.all_body_zones) + . = ..() + if (!isliving(target)) + return ELEMENT_INCOMPATIBLE + RegisterSignals(target, list(COMSIG_HOSTILE_PRE_ATTACKINGTARGET, COMSIG_LIVING_UNARMED_ATTACK), PROC_REF(randomise)) + src.valid_attack_zones = valid_attack_zones + +/datum/element/attack_zone_randomiser/Detach(datum/source) + UnregisterSignal(source, list (COMSIG_HOSTILE_PRE_ATTACKINGTARGET, COMSIG_LIVING_UNARMED_ATTACK)) + return ..() + +/// If we're attacking a carbon, pick a random defence zone +/datum/element/attack_zone_randomiser/proc/randomise(mob/living/source, atom/target) + SIGNAL_HANDLER + if (!iscarbon(target)) + return + var/mob/living/living_target = target + var/list/blacklist_zones = GLOB.all_body_zones - valid_attack_zones + var/new_zone = living_target.get_random_valid_zone(blacklisted_parts = blacklist_zones, bypass_warning = TRUE) + if (isnull(new_zone)) + new_zone = BODY_ZONE_CHEST + var/atom/movable/screen/zone_sel/zone_selector = source.hud_used?.zone_select + if (isnull(zone_selector)) + source.zone_selected = new_zone + else + zone_selector.set_selected_zone(new_zone, source, should_log = FALSE) diff --git a/code/datums/elements/living_limb_initialiser.dm b/code/datums/elements/living_limb_initialiser.dm new file mode 100644 index 0000000000000..943b39dcf3786 --- /dev/null +++ b/code/datums/elements/living_limb_initialiser.dm @@ -0,0 +1,19 @@ +/// Spawns a living limb mob inside a limb upon attachment if it doesn't have one +/datum/element/living_limb_initialiser + +/datum/element/living_limb_initialiser/Attach(atom/target) + . = ..() + if(!isbodypart(target)) + return ELEMENT_INCOMPATIBLE + RegisterSignal(target, COMSIG_BODYPART_CHANGED_OWNER, PROC_REF(try_animate_limb)) + +/datum/element/living_limb_initialiser/Detach(atom/target) + UnregisterSignal(target, COMSIG_BODYPART_CHANGED_OWNER) + return ..() + +/// Create a living limb mob inside the limb if it doesn't already have one +/datum/element/living_limb_initialiser/proc/try_animate_limb(obj/item/bodypart/part) + SIGNAL_HANDLER + if (locate(/mob/living/basic/living_limb_flesh) in part) + return + new /mob/living/basic/living_limb_flesh(part, part) diff --git a/code/modules/mining/equipment/mining_tools.dm b/code/modules/mining/equipment/mining_tools.dm index 2c8a6af786475..4fdd997fcab32 100644 --- a/code/modules/mining/equipment/mining_tools.dm +++ b/code/modules/mining/equipment/mining_tools.dm @@ -372,7 +372,7 @@ var/atom/throw_target = get_edge_target_turf(target_mob, get_dir(user, get_step_away(target_mob, user))) target_mob.throw_at(throw_target, 2, 2, user, gentle = TRUE) target_mob.Knockdown(2 SECONDS) - var/body_zone = pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) + var/body_zone = pick(GLOB.all_body_zones) user.apply_damage(force / recoil_factor, BRUTE, body_zone, user.run_armor_check(body_zone, MELEE)) to_chat(user, span_danger("The weight of the Big Slappy recoils!")) log_combat(user, user, "recoiled Big Slappy into") diff --git a/code/modules/mob/living/basic/basic.dm b/code/modules/mob/living/basic/basic.dm index 3e26246829827..98a771a06a99d 100644 --- a/code/modules/mob/living/basic/basic.dm +++ b/code/modules/mob/living/basic/basic.dm @@ -121,6 +121,7 @@ return apply_atmos_requirements(mapload) apply_temperature_requirements(mapload) + apply_target_randomisation() /mob/living/basic/proc/on_ssair_init(datum/source) SIGNAL_HANDLER @@ -142,6 +143,11 @@ return AddElement(/datum/element/body_temp_sensitive, minimum_survivable_temperature, maximum_survivable_temperature, unsuitable_cold_damage, unsuitable_heat_damage, mapload) +/mob/living/basic/proc/apply_target_randomisation() + if (basic_mob_flags & PRECISE_ATTACK_ZONES) + return + AddElement(/datum/element/attack_zone_randomiser) + /mob/living/basic/Life(seconds_per_tick = SSMOBS_DT, times_fired) . = ..() if(staminaloss > 0) diff --git a/code/modules/mob/living/basic/ruin_defender/flesh.dm b/code/modules/mob/living/basic/ruin_defender/flesh.dm index 31849e3195d02..6524e6fd9d4f4 100644 --- a/code/modules/mob/living/basic/ruin_defender/flesh.dm +++ b/code/modules/mob/living/basic/ruin_defender/flesh.dm @@ -38,6 +38,9 @@ if(!isnull(limb)) register_to_limb(limb) +/mob/living/basic/living_limb_flesh/apply_target_randomisation() + AddElement(/datum/element/attack_zone_randomiser, GLOB.limb_zones) + /mob/living/basic/living_limb_flesh/Destroy(force) . = ..() if(current_bodypart) @@ -71,6 +74,8 @@ if(!victim.CanReach(movable)) continue candidates += movable + if(!length(candidates)) + return var/atom/movable/candidate = pick(candidates) if(isnull(candidate)) return @@ -123,9 +128,9 @@ part_type = /obj/item/bodypart/leg/right/flesh target.visible_message(span_danger("[src] [target_part ? "tears off and attaches itself" : "attaches itself"] to where [target][target.p_s()] limb used to be!")) - var/obj/item/bodypart/new_bodypart = new part_type(TRUE) //dont_spawn_flesh, we cant use named arguments here - new_bodypart.replace_limb(target, TRUE) + var/obj/item/bodypart/new_bodypart = new part_type() forceMove(new_bodypart) + new_bodypart.replace_limb(target, TRUE) register_to_limb(new_bodypart) /mob/living/basic/living_limb_flesh/proc/owner_shocked(datum/source, shock_damage, shock_source, siemens_coeff, flags) diff --git a/code/modules/religion/burdened/psyker.dm b/code/modules/religion/burdened/psyker.dm index d67919cd38031..c370424fa7d2c 100644 --- a/code/modules/religion/burdened/psyker.dm +++ b/code/modules/religion/burdened/psyker.dm @@ -341,7 +341,7 @@ else times_dry_fired = 0 var/turf/target_turf = get_offset_target_turf(get_ranged_target_turf(owner, owner.dir, 7), dx = rand(-1, 1), dy = rand(-1, 1)) - held_gun.process_fire(target_turf, owner, TRUE, null, pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG)) + held_gun.process_fire(target_turf, owner, TRUE, null, pick(GLOB.all_body_zones)) held_gun.semicd = FALSE /datum/action/cooldown/spell/charged/psychic_booster diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 1738bac95a247..5ed7cf59c3d52 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -746,14 +746,14 @@ if(owner == new_owner) return FALSE //`null` is a valid option, so we need to use a num var to make it clear no change was made. - SEND_SIGNAL(src, COMSIG_BODYPART_CHANGED_OWNER, new_owner, owner) - if(owner) . = owner //return value is old owner clear_ownership(owner) if(new_owner) apply_ownership(new_owner) + SEND_SIGNAL(src, COMSIG_BODYPART_CHANGED_OWNER, new_owner, owner) + refresh_bleed_rate() return . diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm index 03f4cc98e1401..e0d74a7169451 100644 --- a/code/modules/surgery/bodyparts/dismemberment.dm +++ b/code/modules/surgery/bodyparts/dismemberment.dm @@ -373,7 +373,7 @@ /mob/living/carbon/proc/regenerate_limbs(list/excluded_zones = list()) SEND_SIGNAL(src, COMSIG_CARBON_REGENERATE_LIMBS, excluded_zones) - var/list/zone_list = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) + var/list/zone_list = GLOB.all_body_zones.Copy() var/list/dismembered_by_copy = body_zone_dismembered_by?.Copy() diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm index 126bd3db33a4f..fb0647d0fb504 100644 --- a/code/modules/surgery/bodyparts/helpers.dm +++ b/code/modules/surgery/bodyparts/helpers.dm @@ -83,7 +83,7 @@ /mob/living/carbon/proc/get_missing_limbs() RETURN_TYPE(/list) - var/list/full = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) + var/list/full = GLOB.all_body_zones.Copy() for(var/zone in full) if(get_bodypart(zone)) full -= zone @@ -100,7 +100,7 @@ return list() /mob/living/carbon/get_disabled_limbs() - var/list/full = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) + var/list/full = GLOB.all_body_zones.Copy() var/list/disabled = list() for(var/zone in full) var/obj/item/bodypart/affecting = get_bodypart(zone) diff --git a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm index cc61393193ae8..e34fb2cbeafd1 100644 --- a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm @@ -584,38 +584,34 @@ limb_id = BODYPART_ID_MEAT should_draw_greyscale = FALSE -/obj/item/bodypart/arm/left/flesh/Initialize(mapload, dont_spawn_flesh = FALSE) +/obj/item/bodypart/arm/left/flesh/Initialize(mapload) . = ..() - if(!dont_spawn_flesh) - new /mob/living/basic/living_limb_flesh(src, src) ADD_TRAIT(src, TRAIT_IGNORED_BY_LIVING_FLESH, BODYPART_TRAIT) + AddElement(/datum/element/living_limb_initialiser) /obj/item/bodypart/arm/right/flesh limb_id = BODYPART_ID_MEAT should_draw_greyscale = FALSE -/obj/item/bodypart/arm/right/flesh/Initialize(mapload, dont_spawn_flesh = FALSE) +/obj/item/bodypart/arm/right/flesh/Initialize(mapload) . = ..() - if(!dont_spawn_flesh) - new /mob/living/basic/living_limb_flesh(src, src) ADD_TRAIT(src, TRAIT_IGNORED_BY_LIVING_FLESH, BODYPART_TRAIT) + AddElement(/datum/element/living_limb_initialiser) /obj/item/bodypart/leg/left/flesh limb_id = BODYPART_ID_MEAT should_draw_greyscale = FALSE -/obj/item/bodypart/leg/left/flesh/Initialize(mapload, dont_spawn_flesh = FALSE) +/obj/item/bodypart/leg/left/flesh/Initialize(mapload) . = ..() - if(!dont_spawn_flesh) - new /mob/living/basic/living_limb_flesh(src, src) ADD_TRAIT(src, TRAIT_IGNORED_BY_LIVING_FLESH, BODYPART_TRAIT) + AddElement(/datum/element/living_limb_initialiser) /obj/item/bodypart/leg/right/flesh limb_id = BODYPART_ID_MEAT should_draw_greyscale = FALSE -/obj/item/bodypart/leg/right/flesh/Initialize(mapload, dont_spawn_flesh = FALSE) +/obj/item/bodypart/leg/right/flesh/Initialize(mapload) . = ..() - if(!dont_spawn_flesh) - new /mob/living/basic/living_limb_flesh(src, src) ADD_TRAIT(src, TRAIT_IGNORED_BY_LIVING_FLESH, BODYPART_TRAIT) + AddElement(/datum/element/living_limb_initialiser) diff --git a/tgstation.dme b/tgstation.dme index 1b61d94bbc9bf..fb6fef1d9090f 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1365,6 +1365,7 @@ #include "code\datums\elements\atmos_requirements.dm" #include "code\datums\elements\atmos_sensitive.dm" #include "code\datums\elements\attack_equip.dm" +#include "code\datums\elements\attack_zone_randomiser.dm" #include "code\datums\elements\backblast.dm" #include "code\datums\elements\bane.dm" #include "code\datums\elements\basic_eating.dm" @@ -1446,6 +1447,7 @@ #include "code\datums\elements\light_blocking.dm" #include "code\datums\elements\light_eaten.dm" #include "code\datums\elements\light_eater.dm" +#include "code\datums\elements\living_limb_initialiser.dm" #include "code\datums\elements\loomable.dm" #include "code\datums\elements\mirage_border.dm" #include "code\datums\elements\mob_access.dm" From c7c8d9d375093e82cc1300d264714ae6b346f328 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sun, 14 Apr 2024 09:32:24 +1200 Subject: [PATCH 218/938] Automatic changelog for PR #82616 [ci skip] --- html/changelogs/AutoChangeLog-pr-82616.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82616.yml diff --git a/html/changelogs/AutoChangeLog-pr-82616.yml b/html/changelogs/AutoChangeLog-pr-82616.yml new file mode 100644 index 0000000000000..1df43f92d63b2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82616.yml @@ -0,0 +1,4 @@ +author: "SyncIt21" +delete-after: True +changes: + - bugfix: "Operating computers clears its ui display procedures if patient is moved out of the operating table in any way" \ No newline at end of file From 23721c5b7016de04568c878c38210066865a0383 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sun, 14 Apr 2024 09:33:43 +1200 Subject: [PATCH 219/938] Automatic changelog for PR #82627 [ci skip] --- html/changelogs/AutoChangeLog-pr-82627.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82627.yml diff --git a/html/changelogs/AutoChangeLog-pr-82627.yml b/html/changelogs/AutoChangeLog-pr-82627.yml new file mode 100644 index 0000000000000..ddd46897ac7c2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82627.yml @@ -0,0 +1,4 @@ +author: "00-Steven" +delete-after: True +changes: + - bugfix: "Clicking the buckled alert unbuckles you again." \ No newline at end of file From 696941d19346a700d0198ac46c2ed3fef7df62af Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sun, 14 Apr 2024 09:35:08 +1200 Subject: [PATCH 220/938] Automatic changelog for PR #82619 [ci skip] --- html/changelogs/AutoChangeLog-pr-82619.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82619.yml diff --git a/html/changelogs/AutoChangeLog-pr-82619.yml b/html/changelogs/AutoChangeLog-pr-82619.yml new file mode 100644 index 0000000000000..104646c4fc243 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82619.yml @@ -0,0 +1,4 @@ +author: "SyncIt21" +delete-after: True +changes: + - bugfix: "advanced camera consoles correctly deactivate when something happens(no proximity, no power etc) to its user" \ No newline at end of file From 5ea23f309be1849820fb1c518e9b4330d8b203ca Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sun, 14 Apr 2024 09:35:50 +1200 Subject: [PATCH 221/938] Automatic changelog for PR #82615 [ci skip] --- html/changelogs/AutoChangeLog-pr-82615.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82615.yml diff --git a/html/changelogs/AutoChangeLog-pr-82615.yml b/html/changelogs/AutoChangeLog-pr-82615.yml new file mode 100644 index 0000000000000..39f00d8de2cd6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82615.yml @@ -0,0 +1,5 @@ +author: "SyncIt21" +delete-after: True +changes: + - bugfix: "you can put back the oven tray after you take it out" + - bugfix: "only oven trays are allowed in ovens preventing baked food runtimes" \ No newline at end of file From e8feed4f6383cb6f7c176a7662f8bb114967c060 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sun, 14 Apr 2024 09:35:58 +1200 Subject: [PATCH 222/938] Automatic changelog for PR #82556 [ci skip] --- html/changelogs/AutoChangeLog-pr-82556.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82556.yml diff --git a/html/changelogs/AutoChangeLog-pr-82556.yml b/html/changelogs/AutoChangeLog-pr-82556.yml new file mode 100644 index 0000000000000..45bf7e0246860 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82556.yml @@ -0,0 +1,7 @@ +author: "Jacquerel" +delete-after: True +changes: + - bugfix: "Living Limbs created by Bioscrambler will be alive." + - bugfix: "Living Limbs can once more attach themselves to your body." + - balance: "Living Limbs will prioritise attacking your limbs." + - bugfix: "Basic Mobs will once again spread their damage across body zones instead of only attacking your chest." \ No newline at end of file From c3e31e8649df4829499aa93eab122fed0058b0a4 Mon Sep 17 00:00:00 2001 From: lexis <127071388+kaylexis@users.noreply.github.com> Date: Sat, 13 Apr 2024 18:28:38 -0500 Subject: [PATCH 223/938] Minor sprite fix for old belt sprites (#82605) ## About The Pull Request They started making me mad so i made them a bit better. ## Why It's Good For The Game Adds swag to some belt stuffs. No longer do you have to fear having a massive ugly belt. Fueled by me looking at sprites too much, and gaining several levels of anger from said looking. ![image](https://github.com/tgstation/tgstation/assets/127071388/35f3a8a9-135c-42cd-b079-182690c4328e) ## Changelog :cl: image: Updates old belt sprites. Mostly the bags, but some misc. ones as well like the chainsword and RPED /:cl: --- icons/mob/clothing/belt.dmi | Bin 48439 -> 50341 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/icons/mob/clothing/belt.dmi b/icons/mob/clothing/belt.dmi index fbe6871c92e2d26cb7145fc31357990c067be530..65ec3828d4276cb435903a491436c7af2a23a8fe 100644 GIT binary patch literal 50341 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 bTFL*AA4uwYNI@T3Q+`%g(NQi_vI_Zc;yCQ* literal 48439 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 EA1y7iIRF3v From 1655ad0b25ef8aedfd5db6309957b4c3f2f87c04 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sun, 14 Apr 2024 11:29:42 +1200 Subject: [PATCH 224/938] Automatic changelog for PR #82605 [ci skip] --- html/changelogs/AutoChangeLog-pr-82605.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82605.yml diff --git a/html/changelogs/AutoChangeLog-pr-82605.yml b/html/changelogs/AutoChangeLog-pr-82605.yml new file mode 100644 index 0000000000000..a4ccd38b635ae --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82605.yml @@ -0,0 +1,4 @@ +author: "kaylexis" +delete-after: True +changes: + - image: "Updates old belt sprites. Mostly the bags, but some misc. ones as well like the chainsword and RPED" \ No newline at end of file From 176cf2c312bc4ab04b95682f11e5b128251cf600 Mon Sep 17 00:00:00 2001 From: Joshua Kidder <49173900+Metekillot@users.noreply.github.com> Date: Sat, 13 Apr 2024 19:42:51 -0400 Subject: [PATCH 225/938] cyborgs know door, APC, and other wires (not cyborg wires) (#82477) ## About The Pull Request This gives cyborgs a trait at roundstart that makes them know the wires around the station, just like engineers. ## Why It's Good For The Game Cyborgs should know the wires just as well as the engineers; simple as that. ## Changelog Cyborgs know which door wires they're looking at now. :cl: Bisar qol: Cyborgs now understand door and APC wires at a glance, among others /:cl: --- code/modules/mob/living/silicon/robot/robot.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 1bcd703365102..886320e2c46ed 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -3,7 +3,7 @@ spark_system.set_up(5, 0, src) spark_system.attach(src) - add_traits(list(TRAIT_CAN_STRIP, TRAIT_FORCED_STANDING), INNATE_TRAIT) + add_traits(list(TRAIT_CAN_STRIP, TRAIT_FORCED_STANDING, TRAIT_KNOW_ENGI_WIRES), INNATE_TRAIT) AddComponent(/datum/component/tippable, \ tip_time = 3 SECONDS, \ untip_time = 2 SECONDS, \ From c12db95307efbe7335d9f4ca48583c44760ecd01 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sun, 14 Apr 2024 11:43:10 +1200 Subject: [PATCH 226/938] Automatic changelog for PR #82477 [ci skip] --- html/changelogs/AutoChangeLog-pr-82477.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82477.yml diff --git a/html/changelogs/AutoChangeLog-pr-82477.yml b/html/changelogs/AutoChangeLog-pr-82477.yml new file mode 100644 index 0000000000000..5806d83397d91 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82477.yml @@ -0,0 +1,4 @@ +author: "Bisar" +delete-after: True +changes: + - qol: "Cyborgs now understand door and APC wires at a glance, among others" \ No newline at end of file From 1b3ef3f70f87fd56bae2c24aabbde16c061c7907 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Sun, 14 Apr 2024 00:23:22 +0000 Subject: [PATCH 227/938] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-82477.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82556.yml | 7 ------ html/changelogs/AutoChangeLog-pr-82602.yml | 5 ---- html/changelogs/AutoChangeLog-pr-82605.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82615.yml | 5 ---- html/changelogs/AutoChangeLog-pr-82616.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82619.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82627.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82628.yml | 4 ---- html/changelogs/archive/2024-04.yml | 27 ++++++++++++++++++++++ 10 files changed, 27 insertions(+), 41 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-82477.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82556.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82602.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82605.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82615.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82616.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82619.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82627.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82628.yml diff --git a/html/changelogs/AutoChangeLog-pr-82477.yml b/html/changelogs/AutoChangeLog-pr-82477.yml deleted file mode 100644 index 5806d83397d91..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82477.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Bisar" -delete-after: True -changes: - - qol: "Cyborgs now understand door and APC wires at a glance, among others" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82556.yml b/html/changelogs/AutoChangeLog-pr-82556.yml deleted file mode 100644 index 45bf7e0246860..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82556.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: "Jacquerel" -delete-after: True -changes: - - bugfix: "Living Limbs created by Bioscrambler will be alive." - - bugfix: "Living Limbs can once more attach themselves to your body." - - balance: "Living Limbs will prioritise attacking your limbs." - - bugfix: "Basic Mobs will once again spread their damage across body zones instead of only attacking your chest." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82602.yml b/html/changelogs/AutoChangeLog-pr-82602.yml deleted file mode 100644 index b63e83f675c94..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82602.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Metekillot" -delete-after: True -changes: - - bugfix: "Being in critical condition no longer damages zombies." - - code_imp: "TRAIT_NODEATH will actually stop you dying in (most) cases." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82605.yml b/html/changelogs/AutoChangeLog-pr-82605.yml deleted file mode 100644 index a4ccd38b635ae..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82605.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "kaylexis" -delete-after: True -changes: - - image: "Updates old belt sprites. Mostly the bags, but some misc. ones as well like the chainsword and RPED" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82615.yml b/html/changelogs/AutoChangeLog-pr-82615.yml deleted file mode 100644 index 39f00d8de2cd6..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82615.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "SyncIt21" -delete-after: True -changes: - - bugfix: "you can put back the oven tray after you take it out" - - bugfix: "only oven trays are allowed in ovens preventing baked food runtimes" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82616.yml b/html/changelogs/AutoChangeLog-pr-82616.yml deleted file mode 100644 index 1df43f92d63b2..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82616.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SyncIt21" -delete-after: True -changes: - - bugfix: "Operating computers clears its ui display procedures if patient is moved out of the operating table in any way" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82619.yml b/html/changelogs/AutoChangeLog-pr-82619.yml deleted file mode 100644 index 104646c4fc243..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82619.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SyncIt21" -delete-after: True -changes: - - bugfix: "advanced camera consoles correctly deactivate when something happens(no proximity, no power etc) to its user" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82627.yml b/html/changelogs/AutoChangeLog-pr-82627.yml deleted file mode 100644 index ddd46897ac7c2..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82627.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "00-Steven" -delete-after: True -changes: - - bugfix: "Clicking the buckled alert unbuckles you again." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82628.yml b/html/changelogs/AutoChangeLog-pr-82628.yml deleted file mode 100644 index b3a9c43a5d354..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82628.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "JohnFulpWillard" -delete-after: True -changes: - - bugfix: "The HoP's photobooth button is now consistently connected to the HoP's photobooth." \ No newline at end of file diff --git a/html/changelogs/archive/2024-04.yml b/html/changelogs/archive/2024-04.yml index bb738f4cc04b9..6b7edc2fb051a 100644 --- a/html/changelogs/archive/2024-04.yml +++ b/html/changelogs/archive/2024-04.yml @@ -470,3 +470,30 @@ - bugfix: blood rites - now charge 1.65x for self healing as opposed to the ~2x they were before - code_imp: blood rites code hurts my eyes a bit less now +2024-04-14: + 00-Steven: + - bugfix: Clicking the buckled alert unbuckles you again. + Bisar: + - qol: Cyborgs now understand door and APC wires at a glance, among others + Jacquerel: + - bugfix: Living Limbs created by Bioscrambler will be alive. + - bugfix: Living Limbs can once more attach themselves to your body. + - balance: Living Limbs will prioritise attacking your limbs. + - bugfix: Basic Mobs will once again spread their damage across body zones instead + of only attacking your chest. + JohnFulpWillard: + - bugfix: The HoP's photobooth button is now consistently connected to the HoP's + photobooth. + Metekillot: + - bugfix: Being in critical condition no longer damages zombies. + - code_imp: TRAIT_NODEATH will actually stop you dying in (most) cases. + SyncIt21: + - bugfix: Operating computers clears its ui display procedures if patient is moved + out of the operating table in any way + - bugfix: you can put back the oven tray after you take it out + - bugfix: only oven trays are allowed in ovens preventing baked food runtimes + - bugfix: advanced camera consoles correctly deactivate when something happens(no + proximity, no power etc) to its user + kaylexis: + - image: Updates old belt sprites. Mostly the bags, but some misc. ones as well + like the chainsword and RPED From 4de57f6c94edfa1decc54d261e16da6ce53bf7e2 Mon Sep 17 00:00:00 2001 From: AMyriad <143908044+AMyriad@users.noreply.github.com> Date: Sun, 14 Apr 2024 03:49:39 +0200 Subject: [PATCH 228/938] Updates some outdated malf AI/bot ability icons (#82614) ## About The Pull Request I updated some action icons used by AIs and bots: - Every icon has been updated to the new sprites used here (where applicable) -- Redid some icons to look better hopefully -- Deleted some icons and changed their file paths to avoid duplicates - Replaced "voice_changer" with the same sprite for "ai_president" in mob/silicon/ai.dmi - Recolored "reactivate_cameras" to feature shading and a better green color ### Sprites: Old ![image](https://github.com/tgstation/tgstation/assets/143908044/2254e7f7-c7b5-4397-8470-ae8f1e11aa1b) New ![image](https://github.com/tgstation/tgstation/assets/143908044/ba3a81fc-45b6-4564-bcc9-1701e34c565e) (missing icons brought in from other files) New gifs used ![detonate_rcds](https://github.com/tgstation/tgstation/assets/143908044/6580f63f-c459-4623-97f3-29c4c6f3d043) ![override_machine](https://github.com/tgstation/tgstation/assets/143908044/adbdc977-1b43-4d4b-a11e-40f120b095d0) ## Why It's Good For The Game I just wanted to do the intercom, but I saw some easily fixable outdated stuff so I freshened those up a bit too And I thought the poor gas-mask AI face and green camera assembly looked awful, so I used another icon that fit for the former and gave the latter some better shades of green. Open to changing or undoing any of this of course! ## Changelog :cl: image: Updated the ability icons used by AIs and station bots /:cl: --- .../antagonists/malf_ai/malf_ai_modules.dm | 10 +++++++--- .../simple_animal/bot/bot_announcement.dm | 2 +- icons/mob/actions/actions_AI.dmi | Bin 11853 -> 21544 bytes 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/code/modules/antagonists/malf_ai/malf_ai_modules.dm b/code/modules/antagonists/malf_ai/malf_ai_modules.dm index 75c3c98e3f614..db1c53d3a17c0 100644 --- a/code/modules/antagonists/malf_ai/malf_ai_modules.dm +++ b/code/modules/antagonists/malf_ai/malf_ai_modules.dm @@ -166,7 +166,8 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) /datum/action/innate/ai/nuke_station name = "Doomsday Device" desc = "Activates the doomsday device. This is not reversible." - button_icon_state = "doomsday_device" + button_icon = 'icons/obj/machines/nuke_terminal.dmi' + button_icon_state = "nuclearbomb_timing" auto_use_uses = FALSE /datum/action/innate/ai/nuke_station/Activate() @@ -598,6 +599,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) /datum/action/innate/ai/honk name = "Percussive Intercomm Interference" desc = "Rock the station's intercom system with an obnoxious HONK!" + button_icon = 'icons/obj/machines/wallmounts.dmi' button_icon_state = "intercom" uses = 2 @@ -705,7 +707,8 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) /datum/action/innate/ai/break_air_alarms name = "Override Air Alarm Safeties" desc = "Enables extremely dangerous settings on all air alarms." - button_icon_state = "break_air_alarms" + button_icon = 'icons/obj/machines/wallmounts.dmi' + button_icon_state = "alarmx" uses = 1 /datum/action/innate/ai/break_air_alarms/Activate() @@ -761,7 +764,8 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) /datum/action/innate/ai/emergency_lights name = "Disable Emergency Lights" desc = "Disables all emergency lighting. Note that emergency lights can be restored through reboot at an APC." - button_icon_state = "emergency_lights" + button_icon = 'icons/obj/lighting.dmi' + button_icon_state = "floor_emergency" uses = 1 /datum/action/innate/ai/emergency_lights/Activate() diff --git a/code/modules/mob/living/simple_animal/bot/bot_announcement.dm b/code/modules/mob/living/simple_animal/bot/bot_announcement.dm index 30a30b81fd270..eade5a291c439 100644 --- a/code/modules/mob/living/simple_animal/bot/bot_announcement.dm +++ b/code/modules/mob/living/simple_animal/bot/bot_announcement.dm @@ -4,7 +4,7 @@ desc = "Play a prerecorded message for the benefit of those around you." background_icon_state = "bg_tech_blue" overlay_icon_state = "bg_tech_blue_border" - button_icon = 'icons/mob/actions/actions_AI.dmi' + button_icon = 'icons/obj/machines/wallmounts.dmi' button_icon_state = "intercom" cooldown_time = 10 SECONDS melee_cooldown_time = 0 SECONDS diff --git a/icons/mob/actions/actions_AI.dmi b/icons/mob/actions/actions_AI.dmi index 048793c607838893c6cd1cb44b8b50c4a95851ec..429a766585dd279c760c4d32e589a7593dc16b9e 100644 GIT binary patch literal 21544 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 Hu0mjfp8@Z# From 13680cb2f570b83ddfc0a724c65004615a3931e8 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sun, 14 Apr 2024 13:50:00 +1200 Subject: [PATCH 229/938] Automatic changelog for PR #82614 [ci skip] --- html/changelogs/AutoChangeLog-pr-82614.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82614.yml diff --git a/html/changelogs/AutoChangeLog-pr-82614.yml b/html/changelogs/AutoChangeLog-pr-82614.yml new file mode 100644 index 0000000000000..fde8a5d269091 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82614.yml @@ -0,0 +1,4 @@ +author: "AMyriad" +delete-after: True +changes: + - image: "Updated the ability icons used by AIs and station bots" \ No newline at end of file From 91f4bd6d2183932538f3a723d3bbd1dbea76ce74 Mon Sep 17 00:00:00 2001 From: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Date: Sun, 14 Apr 2024 00:24:55 -0700 Subject: [PATCH 230/938] Adds the proc we're overriding to RegisterSignals's override stacktrace (#82641) ## About The Pull Request We get it for quite literally free, no reason not to dump it. I always find myself checking in the debugger, which says something about what'll happen when I don't have that again. --- code/datums/signals.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/signals.dm b/code/datums/signals.dm index 97334253b4e5c..ddb7dd9cc9e37 100644 --- a/code/datums/signals.dm +++ b/code/datums/signals.dm @@ -38,7 +38,7 @@ if(exists) if(!override) - var/override_message = "[signal_type] overridden. Use override = TRUE to suppress this warning.\nTarget: [target] ([target.type]) Proc: [proctype]" + var/override_message = "[signal_type] overridden. Use override = TRUE to suppress this warning.\nTarget: [target] ([target.type]) Existing Proc: [exists] New Proc: [proctype]" log_signal(override_message) stack_trace(override_message) return From 9124a73b60692e5b12fa7c7c0af93b873c2b6e5f Mon Sep 17 00:00:00 2001 From: Zephyr <12817816+ZephyrTFA@users.noreply.github.com> Date: Sun, 14 Apr 2024 13:27:07 -0400 Subject: [PATCH 231/938] Put some admin jump verbs back into the context menu | sorts area jump list again (#82647) ## About The Pull Request See title. ## Why It's Good For The Game Some admins wanted all the jump verbs back, aswell as making them not AGhost you. Also make the Jump To Area verb use a sorted list again --- code/modules/admin/verbs/admin.dm | 4 ++-- code/modules/admin/verbs/adminfun.dm | 2 +- code/modules/admin/verbs/adminjump.dm | 21 ++++++--------------- code/modules/admin/verbs/fix_air.dm | 2 +- 4 files changed, 10 insertions(+), 19 deletions(-) diff --git a/code/modules/admin/verbs/admin.dm b/code/modules/admin/verbs/admin.dm index 21421e655d6df..88ee5148f7a3c 100644 --- a/code/modules/admin/verbs/admin.dm +++ b/code/modules/admin/verbs/admin.dm @@ -27,7 +27,7 @@ ADMIN_VERB(announce, R_ADMIN, "Announce", "Announce your desires to the world.", log_admin("Announce: [key_name(user)] : [message]") BLACKBOX_LOG_ADMIN_VERB("Announce") -ADMIN_VERB(unprison, R_ADMIN, "UnPrison", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/prisoner) +ADMIN_VERB(unprison, R_ADMIN, "UnPrison", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/prisoner in GLOB.mob_list) if(!is_centcom_level(prisoner.z)) tgui_alert(user, "[prisoner.name] is not prisoned.") return @@ -144,7 +144,7 @@ ADMIN_VERB(cmd_admin_check_player_exp, R_ADMIN, "Player Playtime", "View player /////////////////////////////////////////////////////////////////////////////////////////////// -ADMIN_VERB(drop_everything, R_ADMIN, "Drop Everything", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/dropee) +ADMIN_VERB(drop_everything, R_ADMIN, "Drop Everything", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/dropee in GLOB.mob_list) var/confirm = tgui_alert(user, "Make [dropee] drop everything?", "Message", list("Yes", "No")) if(confirm != "Yes") return diff --git a/code/modules/admin/verbs/adminfun.dm b/code/modules/admin/verbs/adminfun.dm index f115e8808b536..8bc7a611b35d4 100644 --- a/code/modules/admin/verbs/adminfun.dm +++ b/code/modules/admin/verbs/adminfun.dm @@ -39,7 +39,7 @@ ADMIN_VERB(admin_emp, R_ADMIN|R_FUN, "EM Pulse", ADMIN_VERB_NO_DESCRIPTION, ADMI message_admins("[key_name_admin(user)] created an EM Pulse ([heavy],[light]) at [AREACOORD(orignator)]") BLACKBOX_LOG_ADMIN_VERB("EM Pulse") -ADMIN_VERB(gib_them, R_ADMIN, "Gib", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/victim) +ADMIN_VERB(gib_them, R_ADMIN, "Gib", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/victim in GLOB.mob_list) var/confirm = tgui_alert(user, "Drop a brain?", "Confirm", list("Yes", "No","Cancel")) || "Cancel" if(confirm == "Cancel") return diff --git a/code/modules/admin/verbs/adminjump.dm b/code/modules/admin/verbs/adminjump.dm index 155839942c961..0248ccd99754e 100644 --- a/code/modules/admin/verbs/adminjump.dm +++ b/code/modules/admin/verbs/adminjump.dm @@ -1,11 +1,10 @@ -ADMIN_VERB(jump_to_area, R_ADMIN, "Jump To Area", "Jumps to the specified area.", ADMIN_CATEGORY_GAME, area/target in world) - if(!isobserver(user.mob)) - SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/admin_ghost) - +ADMIN_VERB(jump_to_area, R_ADMIN, "Jump To Area", "Jumps to the specified area.", ADMIN_CATEGORY_GAME, area/target in get_sorted_areas()) var/turf/drop_location top_level: for(var/list/zlevel_turfs as anything in target.get_zlevel_turf_lists()) for(var/turf/area_turf as anything in zlevel_turfs) + if(area_turf.density) + continue drop_location = area_turf break top_level @@ -18,27 +17,19 @@ ADMIN_VERB(jump_to_area, R_ADMIN, "Jump To Area", "Jumps to the specified area." message_admins("[key_name_admin(user)] jumped to [AREACOORD(drop_location)]") BLACKBOX_LOG_ADMIN_VERB("Jump To Area") -ADMIN_VERB(jump_to_turf, R_ADMIN, "Jump To Turf", "Jump to any turf in the game. This will lag your client.", ADMIN_CATEGORY_GAME, turf/locale in world) - if(!isobserver(user.mob)) - SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/admin_ghost) - +ADMIN_VERB_AND_CONTEXT_MENU(jump_to_turf, R_ADMIN, "Jump To Turf", "Jump to any turf in the game. This will lag your client.", ADMIN_CATEGORY_GAME, turf/locale in world) log_admin("[key_name(user)] jumped to [AREACOORD(locale)]") message_admins("[key_name_admin(user)] jumped to [AREACOORD(locale)]") user.mob.abstract_move(locale) BLACKBOX_LOG_ADMIN_VERB("Jump To Turf") -ADMIN_VERB(jump_to_mob, R_ADMIN, "Jump To Mob", "Jump to any mob in the game.", ADMIN_CATEGORY_GAME, mob/target in world) - if(!isobserver(user.mob)) - SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/admin_ghost) +ADMIN_VERB_AND_CONTEXT_MENU(jump_to_mob, R_ADMIN, "Jump To Mob", "Jump to any mob in the game.", ADMIN_CATEGORY_GAME, mob/target in world) user.mob.abstract_move(target.loc) log_admin("[key_name(user)] jumped to [key_name(target)]") message_admins("[key_name_admin(user)] jumped to [ADMIN_LOOKUPFLW(target)] at [AREACOORD(target)]") BLACKBOX_LOG_ADMIN_VERB("Jump To Mob") ADMIN_VERB(jump_to_coord, R_ADMIN, "Jump To Coordinate", "Jump to a specific coordinate in the game world.", ADMIN_CATEGORY_GAME, cx as num, cy as num, cz as num) - if(!isobserver(user.mob)) - SSadmin_verbs.dynamic_invoke_verb(user, /datum/admin_verb/admin_ghost) - var/turf/where_we_droppin = locate(cx, cy, cz) if(isnull(where_we_droppin)) to_chat(user, span_warning("Invalid coordinates.")) @@ -106,7 +97,7 @@ ADMIN_VERB(get_key, R_ADMIN, "Get Key", "Teleport the player with the provided k M.forceMove(get_turf(user)) BLACKBOX_LOG_ADMIN_VERB("Get Key") -ADMIN_VERB(send_mob, R_ADMIN, "Send Mob", "Teleport the specified mob to an area of your choosing.", ADMIN_CATEGORY_GAME, mob/jumper) +ADMIN_VERB_AND_CONTEXT_MENU(send_mob, R_ADMIN, "Send Mob", "Teleport the specified mob to an area of your choosing.", ADMIN_CATEGORY_GAME, mob/jumper) var/list/sorted_areas = get_sorted_areas() if(!length(sorted_areas)) to_chat(user, "No areas found.", confidential = TRUE) diff --git a/code/modules/admin/verbs/fix_air.dm b/code/modules/admin/verbs/fix_air.dm index cd694187ee5d6..00fbb3f1bec83 100644 --- a/code/modules/admin/verbs/fix_air.dm +++ b/code/modules/admin/verbs/fix_air.dm @@ -1,5 +1,5 @@ // Proc taken from yogstation, credit to nichlas0010 for the original -ADMIN_VERB(fix_air, R_ADMIN, "Fix Air", "Fixes air in a specified radius.", ADMIN_CATEGORY_GAME, turf/open/locale in world, range = 2 as num) +ADMIN_VERB_AND_CONTEXT_MENU(fix_air, R_ADMIN, "Fix Air", "Fixes air in a specified radius.", ADMIN_CATEGORY_GAME, turf/open/locale in world, range = 2 as num) message_admins("[key_name_admin(user)] fixed air with range [range] in area [locale.loc.name]") user.mob.log_message("fixed air with range [range] in area [locale.loc.name]", LOG_ADMIN) From 42c318ba32ab44d8f8486322e315925993ee61ca Mon Sep 17 00:00:00 2001 From: John Willard <53777086+JohnFulpWillard@users.noreply.github.com> Date: Sun, 14 Apr 2024 21:15:48 +0000 Subject: [PATCH 232/938] [READY] MASSIVE CRAYON BUFF (GAME-CHANGING) (MUST MERGE) (#82638) ## About The Pull Request You can now type up to 4 letters on a tile at once, one for each corner of the tile, an ability lost when max interactions was added. ![image](https://github.com/tgstation/tgstation/assets/53777086/9f9a2b80-5777-4490-acee-33e3df2d4c5a) ## Why It's Good For The Game Currently if you're typing on the floor with a crayon, you either spend a million years going letter by letter, or do the alternative of typing every second letter to write on 3 tiles at once, and repeat, which is stupid that we even have to do that. ## Changelog :cl: qol: Crayons can now draw up to 4 letters at a time per tile. /:cl: --- code/game/objects/items/crayons.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm index b73e2a4a994dc..ae0dca8d1954b 100644 --- a/code/game/objects/items/crayons.dm +++ b/code/game/objects/items/crayons.dm @@ -512,7 +512,7 @@ if(istagger) wait_time *= 0.5 - if(!instant && !do_after(user, wait_time, target = target)) + if(!instant && !do_after(user, wait_time, target = target, max_interact_count = 4)) return if(!use_charges(user, cost)) From 0cd28f939c74af670abec53470752d5ef9dfa665 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 15 Apr 2024 09:16:16 +1200 Subject: [PATCH 233/938] Automatic changelog for PR #82638 [ci skip] --- html/changelogs/AutoChangeLog-pr-82638.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82638.yml diff --git a/html/changelogs/AutoChangeLog-pr-82638.yml b/html/changelogs/AutoChangeLog-pr-82638.yml new file mode 100644 index 0000000000000..94e31313f4f6a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82638.yml @@ -0,0 +1,4 @@ +author: "JohnFulpWillard" +delete-after: True +changes: + - qol: "Crayons can now draw up to 4 letters at a time per tile." \ No newline at end of file From d554ab7766bb975fe484def4a25a57770a2ced49 Mon Sep 17 00:00:00 2001 From: Jeremiah <42397676+jlsnow301@users.noreply.github.com> Date: Sun, 14 Apr 2024 14:35:03 -0700 Subject: [PATCH 234/938] RPG Loot: Revisited & READY (#82533) ## About The Pull Request Revival of #72881 A new alt click window with a tarkov-y loading spinner. Replaces the object item window in stat panel. ## Videos
    vids toggleable grouping: ![syAA5zf6RK](https://github.com/tgstation/tgstation/assets/42397676/c89b372d-29f6-4ebe-895d-f73bbdc41c19) now lists the floor as first obj: ![abc](https://github.com/tgstation/tgstation/assets/42397676/cd8dc962-2ac7-41bf-a5d3-b9e926116b06) in action: ![dreamseeker_IkrPKt2QZt](https://github.com/tgstation/tgstation/assets/42397676/1f990aa0-60f0-47e7-9d93-b63e35d05273)
    ## features: - search by name - 515 image generator is much faster than alt click menu - opening a gargantuan amount of items shouldnt freeze your screen - groups similar items together in stacks by default, toggleable - shows tile as first item - Shift and Ctrl compatible with LMB :computer_mouse: - RMB points points at items (sry i could not get MMB working) - key Esc to exit the window. For devs: - A new image generation tech. - An error refetch mechanic to the Image component - It does not "smart track" the items being added to the pile, just reopen or refresh. This was a design decision. ## Why It's Good For The Game Honestly I just dislike the stat panel Fixes #53824 Fixes ![image](https://github.com/tgstation/tgstation/assets/42397676/0e50faab-7d4d-4bf7-8c5b-4ac28547bfbd) ## Changelog :cl: add: Added a loot window for alt-clicking tiles. del: Removed the item browser from the stat panel. /:cl: --------- Co-authored-by: Zephyr <12817816+ZephyrTFA@users.noreply.github.com> Co-authored-by: AnturK Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> --- code/__DEFINES/subsystems.dm | 1 + code/__DEFINES/traits/declarations.dm | 3 + code/_globalvars/traits/_traits.dm | 1 + code/_onclick/click.dm | 44 +++-- code/_onclick/observer.dm | 2 +- .../subsystem/processing/obj_tab_items.dm | 24 --- code/controllers/subsystem/statpanel.dm | 183 ------------------ code/datums/components/gps.dm | 1 + code/datums/components/rotation.dm | 4 + code/game/objects/items/grenades/_grenade.dm | 1 + .../asset_cache/assets/icon_ref_map.dm | 28 +++ .../asset_cache/transports/asset_transport.dm | 10 +- .../components/binary_devices/passive_gate.dm | 1 + .../binary_devices/pressure_valve.dm | 1 + .../components/binary_devices/pump.dm | 1 + .../binary_devices/temperature_gate.dm | 1 + .../binary_devices/temperature_pump.dm | 1 + .../components/binary_devices/volume_pump.dm | 1 + code/modules/client/client_defines.dm | 5 +- code/modules/client/client_procs.dm | 5 +- code/modules/lootpanel/_lootpanel.dm | 78 ++++++++ code/modules/lootpanel/contents.dm | 49 +++++ code/modules/lootpanel/handlers.dm | 19 ++ code/modules/lootpanel/misc.dm | 48 +++++ code/modules/lootpanel/search_object.dm | 84 ++++++++ code/modules/lootpanel/ss_looting.dm | 39 ++++ code/modules/lootpanel/ui.dm | 46 +++++ .../basic/space_fauna/revenant/_revenant.dm | 2 +- code/modules/tgui/tgui.dm | 2 + code/modules/unit_tests/_unit_tests.dm | 1 + code/modules/unit_tests/lootpanel.dm | 34 ++++ tgstation.dme | 9 +- tgui/packages/tgui/components/DmIcon.tsx | 72 +++++++ tgui/packages/tgui/components/Image.tsx | 45 +++-- tgui/packages/tgui/components/index.ts | 1 + .../interfaces/LootPanel/GroupedContents.tsx | 47 +++++ .../tgui/interfaces/LootPanel/IconDisplay.tsx | 24 +++ .../tgui/interfaces/LootPanel/LootBox.tsx | 53 +++++ .../tgui/interfaces/LootPanel/RawContents.tsx | 28 +++ .../tgui/interfaces/LootPanel/index.tsx | 76 ++++++++ .../tgui/interfaces/LootPanel/types.ts | 13 ++ .../tgui/interfaces/NtosEmojipedia.tsx | 20 +- .../tgui/styles/components/SearchItem.scss | 22 +++ tgui/packages/tgui/styles/main.scss | 1 + 44 files changed, 876 insertions(+), 255 deletions(-) delete mode 100644 code/controllers/subsystem/processing/obj_tab_items.dm create mode 100644 code/modules/asset_cache/assets/icon_ref_map.dm create mode 100644 code/modules/lootpanel/_lootpanel.dm create mode 100644 code/modules/lootpanel/contents.dm create mode 100644 code/modules/lootpanel/handlers.dm create mode 100644 code/modules/lootpanel/misc.dm create mode 100644 code/modules/lootpanel/search_object.dm create mode 100644 code/modules/lootpanel/ss_looting.dm create mode 100644 code/modules/lootpanel/ui.dm create mode 100644 code/modules/unit_tests/lootpanel.dm create mode 100644 tgui/packages/tgui/components/DmIcon.tsx create mode 100644 tgui/packages/tgui/interfaces/LootPanel/GroupedContents.tsx create mode 100644 tgui/packages/tgui/interfaces/LootPanel/IconDisplay.tsx create mode 100644 tgui/packages/tgui/interfaces/LootPanel/LootBox.tsx create mode 100644 tgui/packages/tgui/interfaces/LootPanel/RawContents.tsx create mode 100644 tgui/packages/tgui/interfaces/LootPanel/index.tsx create mode 100644 tgui/packages/tgui/interfaces/LootPanel/types.ts create mode 100644 tgui/packages/tgui/styles/components/SearchItem.scss diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 3878ba8c45ce3..470c213822bdd 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -185,6 +185,7 @@ #define INIT_ORDER_MINOR_MAPPING -40 #define INIT_ORDER_PATH -50 #define INIT_ORDER_EXPLOSIONS -69 +#define INIT_ORDER_LOOT -70 #define INIT_ORDER_STATPANELS -97 #define INIT_ORDER_BAN_CACHE -98 #define INIT_ORDER_INIT_PROFILER -99 //Near the end, logs the costs of initialize diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index f5ad67a8c94a8..c01d663e0e39c 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -1114,4 +1114,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Trait applied to objects and mobs that can attack a boulder and break it down. (See /obj/item/boulder/manual_process()) #define TRAIT_BOULDER_BREAKER "boulder_breaker" +/// Prevents the affected object from opening a loot window via alt click. See atom/AltClick() +#define TRAIT_ALT_CLICK_BLOCKER "no_alt_click" + // END TRAIT DEFINES diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 9ee26893b5f2f..1595e23a77d52 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -8,6 +8,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( /atom = list( "TRAIT_AI_PAUSED" = TRAIT_AI_PAUSED, + "TRAIT_ALT_CLICK_BLOCKER" = TRAIT_ALT_CLICK_BLOCKER, "TRAIT_BANNED_FROM_CARGO_SHUTTLE" = TRAIT_BANNED_FROM_CARGO_SHUTTLE, "TRAIT_BEING_SHOCKED" = TRAIT_BEING_SHOCKED, "TRAIT_COMMISSIONED" = TRAIT_COMMISSIONED, diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index cd06f0c2fd87f..b96b8241b1235 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -395,14 +395,40 @@ return A.AltClick(src) +/** + * Alt click on an atom. + * Performs alt-click actions before attempting to open a loot window. + * Returns TRUE if successful, FALSE if not. + */ /atom/proc/AltClick(mob/user) if(!user.can_interact_with(src)) return FALSE + if(SEND_SIGNAL(src, COMSIG_CLICK_ALT, user) & COMPONENT_CANCEL_CLICK_ALT) - return - var/turf/T = get_turf(src) - if(T && (isturf(loc) || isturf(src)) && user.TurfAdjacent(T) && !HAS_TRAIT(user, TRAIT_MOVE_VENTCRAWLING)) - user.set_listed_turf(T) + return TRUE + + if(HAS_TRAIT(src, TRAIT_ALT_CLICK_BLOCKER) && !isobserver(user)) + return TRUE + + var/turf/tile = get_turf(src) + if(isnull(tile)) + return FALSE + + if(!isturf(loc) && !isturf(src)) + return FALSE + + if(!user.TurfAdjacent(tile)) + return FALSE + + if(HAS_TRAIT(user, TRAIT_MOVE_VENTCRAWLING)) + return FALSE + + var/datum/lootpanel/panel = user.client?.loot_panel + if(isnull(panel)) + return FALSE + + panel.open(tile) + return TRUE ///The base proc of when something is right clicked on when alt is held - generally use alt_click_secondary instead /atom/proc/alt_click_on_secondary(atom/A) @@ -421,14 +447,8 @@ user.client.toggle_tag_datum(src) return -/// Use this instead of [/mob/proc/AltClickOn] where you only want turf content listing without additional atom alt-click interaction -/atom/proc/AltClickNoInteract(mob/user, atom/A) - var/turf/T = get_turf(A) - if(T && user.TurfAdjacent(T)) - user.set_listed_turf(T) - -/mob/proc/TurfAdjacent(turf/T) - return T.Adjacent(src) +/mob/proc/TurfAdjacent(turf/tile) + return tile.Adjacent(src) /** * Control+Shift click diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm index 1cdb99bbb42af..2c236d7232c99 100644 --- a/code/_onclick/observer.dm +++ b/code/_onclick/observer.dm @@ -32,7 +32,7 @@ MiddleClickOn(A, params) return if(LAZYACCESS(modifiers, ALT_CLICK)) - AltClickNoInteract(src, A) + A.AltClick(src) return if(LAZYACCESS(modifiers, CTRL_CLICK)) CtrlClickOn(A) diff --git a/code/controllers/subsystem/processing/obj_tab_items.dm b/code/controllers/subsystem/processing/obj_tab_items.dm deleted file mode 100644 index 53786daf0117e..0000000000000 --- a/code/controllers/subsystem/processing/obj_tab_items.dm +++ /dev/null @@ -1,24 +0,0 @@ -PROCESSING_SUBSYSTEM_DEF(obj_tab_items) - name = "Obj Tab Items" - flags = SS_NO_INIT - runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT - wait = 0.1 SECONDS - -// I know this is mostly copypasta, but I want to change the processing logic -// Sorry bestie :( -/datum/controller/subsystem/processing/obj_tab_items/fire(resumed = FALSE) - if (!resumed) - currentrun = processing.Copy() - //cache for sanic speed (lists are references anyways) - var/list/current_run = currentrun - - while(current_run.len) - var/datum/thing = current_run[current_run.len] - if(QDELETED(thing)) - processing -= thing - else if(thing.process(wait * 0.1) == PROCESS_KILL) - // fully stop so that a future START_PROCESSING will work - STOP_PROCESSING(src, thing) - if (MC_TICK_CHECK) - return - current_run.len-- diff --git a/code/controllers/subsystem/statpanel.dm b/code/controllers/subsystem/statpanel.dm index 317fb73852a8a..020598a573b67 100644 --- a/code/controllers/subsystem/statpanel.dm +++ b/code/controllers/subsystem/statpanel.dm @@ -88,12 +88,6 @@ SUBSYSTEM_DEF(statpanels) if(update_actions && num_fires % default_wait == 0) set_action_tabs(target, target_mob) - // Handle the examined turf of the stat panel, if it's been long enough, or if we've generated new images for it - var/turf/listed_turf = target_mob?.listed_turf - if(listed_turf && num_fires % default_wait == 0) - if(target.stat_tab == listed_turf.name || !(listed_turf.name in target.panel_tabs)) - set_turf_examine_tab(target, target_mob) - if(MC_TICK_CHECK) return @@ -166,71 +160,6 @@ SUBSYSTEM_DEF(statpanels) target.stat_panel.send_message("update_spells", list(spell_tabs = target.spell_tabs, actions = actions)) -/datum/controller/subsystem/statpanels/proc/set_turf_examine_tab(client/target, mob/target_mob) - var/list/overrides = list() - for(var/image/target_image as anything in target.images) - if(!target_image.loc || target_image.loc.loc != target_mob.listed_turf || !target_image.override) - continue - overrides += target_image.loc - - var/list/atoms_to_display = list(target_mob.listed_turf) - for(var/atom/movable/turf_content as anything in target_mob.listed_turf) - if(turf_content.mouse_opacity == MOUSE_OPACITY_TRANSPARENT) - continue - if(turf_content.invisibility > target_mob.see_invisible) - continue - if(turf_content in overrides) - continue - if(turf_content.IsObscured()) - continue - atoms_to_display += turf_content - - /// Set the atoms we're meant to display - var/datum/object_window_info/obj_window = target.obj_window - obj_window.atoms_to_show = atoms_to_display - START_PROCESSING(SSobj_tab_items, obj_window) - refresh_client_obj_view(target) - -/datum/controller/subsystem/statpanels/proc/refresh_client_obj_view(client/refresh) - var/list/turf_items = return_object_images(refresh) - if(!length(turf_items) || !refresh.mob?.listed_turf) - return - refresh.stat_panel.send_message("update_listedturf", turf_items) - -#define OBJ_IMAGE_LOADING "statpanels obj loading temporary" -/// Returns all our ready object tab images -/// Returns a list in the form list(list(object_name, object_ref, loaded_image), ...) -/datum/controller/subsystem/statpanels/proc/return_object_images(client/load_from) - // You might be inclined to think that this is a waste of cpu time, since we - // A: Double iterate over atoms in the build case, or - // B: Generate these lists over and over in the refresh case - // It's really not very hot. The hot portion of this code is genuinely mostly in the image generation - // So it's ok to pay a performance cost for cleanliness here - - // No turf? go away - if(!load_from.mob?.listed_turf) - return list() - var/datum/object_window_info/obj_window = load_from.obj_window - var/list/already_seen = obj_window.atoms_to_images - var/list/to_make = obj_window.atoms_to_imagify - var/list/turf_items = list() - for(var/atom/turf_item as anything in obj_window.atoms_to_show) - // First, we fill up the list of refs to display - // If we already have one, just use that - var/existing_image = already_seen[turf_item] - if(existing_image == OBJ_IMAGE_LOADING) - continue - // We already have it. Success! - if(existing_image) - turf_items[++turf_items.len] = list("[turf_item.name]", REF(turf_item), existing_image) - continue - // Now, we're gonna queue image generation out of those refs - to_make += turf_item - already_seen[turf_item] = OBJ_IMAGE_LOADING - obj_window.RegisterSignal(turf_item, COMSIG_QDELETING, TYPE_PROC_REF(/datum/object_window_info,viewing_atom_deleted)) // we reset cache if anything in it gets deleted - return turf_items - -#undef OBJ_IMAGE_LOADING /datum/controller/subsystem/statpanels/proc/generate_mc_data() mc_data = list( @@ -272,16 +201,6 @@ SUBSYSTEM_DEF(statpanels) set_action_tabs(target, target_mob) return TRUE - // Handle turfs - - if(target_mob?.listed_turf) - if(!target_mob.TurfAdjacent(target_mob.listed_turf)) - target_mob.set_listed_turf(null) - - else if(target.stat_tab == target_mob?.listed_turf.name || !(target_mob?.listed_turf.name in target.panel_tabs)) - set_turf_examine_tab(target, target_mob) - return TRUE - if(!target.holder) return FALSE @@ -301,105 +220,3 @@ SUBSYSTEM_DEF(statpanels) /// Stat panel window declaration /client/var/datum/tgui_window/stat_panel - -/// Datum that holds and tracks info about a client's object window -/// Really only exists because I want to be able to do logic with signals -/// And need a safe place to do the registration -/datum/object_window_info - /// list of atoms to show to our client via the object tab, at least currently - var/list/atoms_to_show = list() - /// list of atom -> image string for objects we have had in the right click tab - /// this is our caching - var/list/atoms_to_images = list() - /// list of atoms to turn into images for the object tab - var/list/atoms_to_imagify = list() - /// Our owner client - var/client/parent - /// Are we currently tracking a turf? - var/actively_tracking = FALSE - -/datum/object_window_info/New(client/parent) - . = ..() - src.parent = parent - -/datum/object_window_info/Destroy(force) - atoms_to_show = null - atoms_to_images = null - atoms_to_imagify = null - parent.obj_window = null - parent = null - STOP_PROCESSING(SSobj_tab_items, src) - return ..() - -/// Takes a client, attempts to generate object images for it -/// We will update the client with any improvements we make when we're done -/datum/object_window_info/process(seconds_per_tick) - // Cache the datum access for sonic speed - var/list/to_make = atoms_to_imagify - var/list/newly_seen = atoms_to_images - var/index = 0 - for(index in 1 to length(to_make)) - var/atom/thing = to_make[index] - - var/generated_string - if(ismob(thing) || length(thing.overlays) > 2) - generated_string = costly_icon2html(thing, parent, sourceonly=TRUE) - else - generated_string = icon2html(thing, parent, sourceonly=TRUE) - - newly_seen[thing] = generated_string - if(TICK_CHECK) - to_make.Cut(1, index + 1) - index = 0 - break - // If we've not cut yet, do it now - if(index) - to_make.Cut(1, index + 1) - SSstatpanels.refresh_client_obj_view(parent) - if(!length(to_make)) - return PROCESS_KILL - -/datum/object_window_info/proc/start_turf_tracking() - if(actively_tracking) - stop_turf_tracking() - var/static/list/connections = list( - COMSIG_MOVABLE_MOVED = PROC_REF(on_mob_move), - COMSIG_MOB_LOGOUT = PROC_REF(on_mob_logout), - ) - AddComponent(/datum/component/connect_mob_behalf, parent, connections) - actively_tracking = TRUE - -/datum/object_window_info/proc/stop_turf_tracking() - qdel(GetComponent(/datum/component/connect_mob_behalf)) - actively_tracking = FALSE - -/datum/object_window_info/proc/on_mob_move(mob/source) - SIGNAL_HANDLER - var/turf/listed = source.listed_turf - if(!listed || !source.TurfAdjacent(listed)) - source.set_listed_turf(null) - -/datum/object_window_info/proc/on_mob_logout(mob/source) - SIGNAL_HANDLER - on_mob_move(parent.mob) - -/// Clears any cached object window stuff -/// We use hard refs cause we'd need a signal for this anyway. Cleaner this way -/datum/object_window_info/proc/viewing_atom_deleted(atom/deleted) - SIGNAL_HANDLER - atoms_to_show -= deleted - atoms_to_imagify -= deleted - atoms_to_images -= deleted - -/mob/proc/set_listed_turf(turf/new_turf) - listed_turf = new_turf - if(!client) - return - if(!client.obj_window) - client.obj_window = new(client) - if(listed_turf) - client.stat_panel.send_message("create_listedturf", listed_turf.name) - client.obj_window.start_turf_tracking() - else - client.stat_panel.send_message("remove_listedturf") - client.obj_window.stop_turf_tracking() diff --git a/code/datums/components/gps.dm b/code/datums/components/gps.dm index 34aba53e9e4e1..a84bc1e75958b 100644 --- a/code/datums/components/gps.dm +++ b/code/datums/components/gps.dm @@ -89,6 +89,7 @@ GLOBAL_LIST_EMPTY(GPS_list) SIGNAL_HANDLER toggletracking(user) + return COMPONENT_CANCEL_CLICK_ALT ///Toggles the tracking for the gps /datum/component/gps/item/proc/toggletracking(mob/user) diff --git a/code/datums/components/rotation.dm b/code/datums/components/rotation.dm index 7c55579c9992d..160cc3b7629df 100644 --- a/code/datums/components/rotation.dm +++ b/code/datums/components/rotation.dm @@ -26,6 +26,8 @@ RegisterSignal(parent, COMSIG_CLICK_ALT_SECONDARY, PROC_REF(rotate_right)) RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(ExamineMessage)) RegisterSignal(parent, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, PROC_REF(on_requesting_context_from_item)) + + ADD_TRAIT(parent, TRAIT_ALT_CLICK_BLOCKER, REF(src)) return ..() /datum/component/simple_rotation/PostTransfer() @@ -41,6 +43,8 @@ COMSIG_ATOM_EXAMINE, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, )) + + REMOVE_TRAIT(parent, TRAIT_ALT_CLICK_BLOCKER, REF(src)) return ..() /datum/component/simple_rotation/Destroy() diff --git a/code/game/objects/items/grenades/_grenade.dm b/code/game/objects/items/grenades/_grenade.dm index 4c737ed53f3cb..86bb062b651cb 100644 --- a/code/game/objects/items/grenades/_grenade.dm +++ b/code/game/objects/items/grenades/_grenade.dm @@ -53,6 +53,7 @@ /obj/item/grenade/Initialize(mapload) . = ..() ADD_TRAIT(src, TRAIT_ODD_CUSTOMIZABLE_FOOD_INGREDIENT, type) + ADD_TRAIT(src, TRAIT_ALT_CLICK_BLOCKER, REF(src)) RegisterSignal(src, COMSIG_ITEM_USED_AS_INGREDIENT, PROC_REF(on_used_as_ingredient)) /obj/item/grenade/suicide_act(mob/living/carbon/user) diff --git a/code/modules/asset_cache/assets/icon_ref_map.dm b/code/modules/asset_cache/assets/icon_ref_map.dm new file mode 100644 index 0000000000000..2f7f846309912 --- /dev/null +++ b/code/modules/asset_cache/assets/icon_ref_map.dm @@ -0,0 +1,28 @@ +/// Maps icon names to ref values +/datum/asset/json/icon_ref_map + name = "icon_ref_map" + early = TRUE + +/datum/asset/json/icon_ref_map/generate() + var/list/data = list() //"icons/obj/drinks.dmi" => "[0xc000020]" + + //var/start = "0xc000000" + var/value = 0 + + while(TRUE) + value += 1 + var/ref = "\[0xc[num2text(value,6,16)]\]" + var/mystery_meat = locate(ref) + + if(isicon(mystery_meat)) + if(!isfile(mystery_meat)) // Ignore the runtime icons for now + continue + var/path = get_icon_dmi_path(mystery_meat) //Try to get the icon path + if(path) + data[path] = ref + else if(mystery_meat) + continue; //Some other non-icon resource, ogg/json/whatever + else //Out of resources end this, could also try to end this earlier as soon as runtime generated icons appear but eh + break; + + return data diff --git a/code/modules/asset_cache/transports/asset_transport.dm b/code/modules/asset_cache/transports/asset_transport.dm index 19e40fb48848e..3dbcc301843cc 100644 --- a/code/modules/asset_cache/transports/asset_transport.dm +++ b/code/modules/asset_cache/transports/asset_transport.dm @@ -82,11 +82,15 @@ /// asset_list - A list of asset filenames to be sent to the client. Can optionally be assoicated with the asset's asset_cache_item datum. /// Returns TRUE if any assets were sent. /datum/asset_transport/proc/send_assets(client/client, list/asset_list) +#if defined(UNIT_TESTS) + return +#endif + if (!istype(client)) if (ismob(client)) - var/mob/M = client - if (M.client) - client = M.client + var/mob/our_mob = client + if (our_mob.client) + client = our_mob.client else //no stacktrace because this will mainly happen because the client went away return else diff --git a/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm b/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm index c06863ba09266..69b54a01a8c74 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm @@ -22,6 +22,7 @@ Passive gate is similar to the regular pump except: /obj/machinery/atmospherics/components/binary/passive_gate/Initialize(mapload) . = ..() + ADD_TRAIT(src, TRAIT_ALT_CLICK_BLOCKER, REF(src)) register_context() /obj/machinery/atmospherics/components/binary/passive_gate/add_context(atom/source, list/context, obj/item/held_item, mob/user) diff --git a/code/modules/atmospherics/machinery/components/binary_devices/pressure_valve.dm b/code/modules/atmospherics/machinery/components/binary_devices/pressure_valve.dm index 931920732752b..72dd3c7f2f6c4 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/pressure_valve.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/pressure_valve.dm @@ -14,6 +14,7 @@ /obj/machinery/atmospherics/components/binary/pressure_valve/Initialize(mapload) . = ..() + ADD_TRAIT(src, TRAIT_ALT_CLICK_BLOCKER, REF(src)) register_context() /obj/machinery/atmospherics/components/binary/pressure_valve/add_context(atom/source, list/context, obj/item/held_item, mob/user) diff --git a/code/modules/atmospherics/machinery/components/binary_devices/pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/pump.dm index 3c1ba634caeed..50d86992d748c 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/pump.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/pump.dm @@ -27,6 +27,7 @@ AddComponent(/datum/component/usb_port, list( /obj/item/circuit_component/atmos_pump, )) + ADD_TRAIT(src, TRAIT_ALT_CLICK_BLOCKER, REF(src)) register_context() /obj/machinery/atmospherics/components/binary/pump/add_context(atom/source, list/context, obj/item/held_item, mob/user) diff --git a/code/modules/atmospherics/machinery/components/binary_devices/temperature_gate.dm b/code/modules/atmospherics/machinery/components/binary_devices/temperature_gate.dm index bbe788bac5364..567759a38296c 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/temperature_gate.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/temperature_gate.dm @@ -19,6 +19,7 @@ /obj/machinery/atmospherics/components/binary/temperature_gate/Initialize(mapload) . = ..() + ADD_TRAIT(src, TRAIT_ALT_CLICK_BLOCKER, REF(src)) register_context() /obj/machinery/atmospherics/components/binary/temperature_gate/add_context(atom/source, list/context, obj/item/held_item, mob/user) diff --git a/code/modules/atmospherics/machinery/components/binary_devices/temperature_pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/temperature_pump.dm index 0fdb5aca6a3fe..54f277c25b1b1 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/temperature_pump.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/temperature_pump.dm @@ -14,6 +14,7 @@ /obj/machinery/atmospherics/components/binary/temperature_pump/Initialize(mapload) . = ..() + ADD_TRAIT(src, TRAIT_ALT_CLICK_BLOCKER, REF(src)) register_context() /obj/machinery/atmospherics/components/binary/temperature_pump/add_context(atom/source, list/context, obj/item/held_item, mob/user) diff --git a/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm index 139cbe71b36ca..e190bb47d3037 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm @@ -31,6 +31,7 @@ AddComponent(/datum/component/usb_port, list( /obj/item/circuit_component/atmos_volume_pump, )) + ADD_TRAIT(src, TRAIT_ALT_CLICK_BLOCKER, REF(src)) register_context() /obj/machinery/atmospherics/components/binary/volume_pump/CtrlClick(mob/user) diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm index 45ccda8b92bd1..3272620a86555 100644 --- a/code/modules/client/client_defines.dm +++ b/code/modules/client/client_defines.dm @@ -194,8 +194,6 @@ var/list/spell_tabs = list() ///A lazy list of atoms we've examined in the last RECENT_EXAMINE_MAX_WINDOW (default 2) seconds, so that we will call [/atom/proc/examine_more] instead of [/atom/proc/examine] on them when examining var/list/recent_examines - ///Our object window datum. It stores info about and handles behavior for the object tab - var/datum/object_window_info/obj_window var/list/parallax_layers var/list/parallax_layers_cached @@ -266,3 +264,6 @@ /// Does this client have typing indicators enabled? var/typing_indicators = FALSE + + /// Loot panel for the client + var/datum/lootpanel/loot_panel diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index d42c726940519..913be33118271 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -540,6 +540,8 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( if (!interviewee) initialize_menus() + loot_panel = new(src) + view_size = new(src, getScreenSize(prefs.read_preference(/datum/preference/toggle/widescreen))) view_size.resetFormat() view_size.setZoomMode() @@ -580,8 +582,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( SSserver_maint.UpdateHubStatus() if(credits) QDEL_LIST(credits) - if(obj_window) - QDEL_NULL(obj_window) if(holder) adminGreet(1) holder.owner = null @@ -611,6 +611,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( QDEL_NULL(view_size) QDEL_NULL(void) QDEL_NULL(tooltips) + QDEL_NULL(loot_panel) seen_messages = null Master.UpdateTickRate() ..() //Even though we're going to be hard deleted there are still some things that want to know the destroy is happening diff --git a/code/modules/lootpanel/_lootpanel.dm b/code/modules/lootpanel/_lootpanel.dm new file mode 100644 index 0000000000000..86a94cc9957c0 --- /dev/null +++ b/code/modules/lootpanel/_lootpanel.dm @@ -0,0 +1,78 @@ +/** + * ## Loot panel + * A datum that stores info containing the contents of a turf. + * Handles opening the lootpanel UI and searching the turf for items. + */ +/datum/lootpanel + /// The owner of the panel + var/client/owner + /// The list of all search objects indexed. + var/list/datum/search_object/contents = list() + /// The list of search_objects needing processed + var/list/datum/search_object/to_image = list() + /// We've been notified about client version + var/notified = FALSE + /// The turf being searched + var/turf/source_turf + + +/datum/lootpanel/New(client/owner) + . = ..() + + src.owner = owner + + +/datum/lootpanel/Destroy(force) + reset_contents() + owner = null + source_turf = null + + return ..() + + +/datum/lootpanel/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "LootPanel") + ui.set_autoupdate(FALSE) + ui.open() + + +/datum/lootpanel/ui_close(mob/user) + . = ..() + + source_turf = null + reset_contents() + + +/datum/lootpanel/ui_data(mob/user) + var/list/data = list() + + data["contents"] = get_contents() + data["searching"] = length(to_image) + + return data + + +/datum/lootpanel/ui_status(mob/user, datum/ui_state/state) + if(!source_turf.Adjacent(user)) + return UI_CLOSE + + if(user.incapacitated()) + return UI_DISABLED + + return UI_INTERACTIVE + + +/datum/lootpanel/ui_act(action, list/params) + . = ..() + if(.) + return + + switch(action) + if("grab") + return grab(usr, params) + if("refresh") + return populate_contents() + + return FALSE diff --git a/code/modules/lootpanel/contents.dm b/code/modules/lootpanel/contents.dm new file mode 100644 index 0000000000000..4bb255b15611b --- /dev/null +++ b/code/modules/lootpanel/contents.dm @@ -0,0 +1,49 @@ +/// Adds the item to contents and to_image (if needed) +/datum/lootpanel/proc/add_to_index(datum/search_object/index) + RegisterSignal(index, COMSIG_QDELETING, PROC_REF(on_searchable_deleted)) + if(isnull(index.icon)) + to_image += index + + contents += index + + +/// Used to populate contents and start generating if needed +/datum/lootpanel/proc/populate_contents() + if(length(contents)) + reset_contents() + + // Add source turf first + var/datum/search_object/source = new(owner, source_turf) + add_to_index(source) + + for(var/atom/thing as anything in source_turf.contents) + // validate + if(thing.mouse_opacity == MOUSE_OPACITY_TRANSPARENT) + continue + if(thing.IsObscured()) + continue + if(thing.invisibility > owner.mob.see_invisible) + continue + + // convert + var/datum/search_object/index = new(owner, thing) + add_to_index(index) + + var/datum/tgui/window = SStgui.get_open_ui(owner.mob, src) + window?.send_update() + + if(length(to_image)) + SSlooting.backlog += src + + +/// For: Resetting to empty. Ignores the searchable qdel event +/datum/lootpanel/proc/reset_contents() + for(var/datum/search_object/index as anything in contents) + contents -= index + to_image -= index + + if(QDELETED(index)) + continue + + UnregisterSignal(index, COMSIG_QDELETING) + qdel(index) diff --git a/code/modules/lootpanel/handlers.dm b/code/modules/lootpanel/handlers.dm new file mode 100644 index 0000000000000..40a76974ed4a7 --- /dev/null +++ b/code/modules/lootpanel/handlers.dm @@ -0,0 +1,19 @@ +/// On contents change, either reset or update +/datum/lootpanel/proc/on_searchable_deleted(datum/search_object/source) + SIGNAL_HANDLER + + contents -= source + to_image -= source + + var/datum/tgui/window = SStgui.get_open_ui(owner.mob, src) +#if !defined(UNIT_TESTS) // we dont want to delete contents if we're testing + if(isnull(window)) + reset_contents() + return +#endif + + if(isturf(source.item)) + populate_contents() + return + + window?.send_update() diff --git a/code/modules/lootpanel/misc.dm b/code/modules/lootpanel/misc.dm new file mode 100644 index 0000000000000..6e8448b820528 --- /dev/null +++ b/code/modules/lootpanel/misc.dm @@ -0,0 +1,48 @@ +/// Helper to open the panel +/datum/lootpanel/proc/open(turf/tile) + source_turf = tile + +#if !defined(OPENDREAM) && !defined(UNIT_TESTS) + if(!notified) + var/build = owner.byond_build + var/version = owner.byond_version + if(build < 515 || (build == 515 && version < 1635)) + to_chat(owner.mob, examine_block(span_info("\ + Your version of Byond doesn't support fast image loading.\n\ + Detected: [version].[build]\n\ + Required version for this feature: 515.1635 or later.\n\ + Visit BYOND's website to get the latest version of BYOND.\n\ + "))) + + notified = TRUE +#endif + + populate_contents() + ui_interact(owner.mob) + + +/** + * Called by SSlooting whenever this datum is added to its backlog. + * Iterates over to_image list to create icons, then removes them. + * Returns boolean - whether this proc has finished the queue or not. + */ +/datum/lootpanel/proc/process_images() + for(var/datum/search_object/index as anything in to_image) + to_image -= index + + if(QDELETED(index) || index.icon) + continue + + index.generate_icon(owner) + + if(TICK_CHECK) + break + + var/datum/tgui/window = SStgui.get_open_ui(owner.mob, src) + if(isnull(window)) + reset_contents() + return TRUE + + window.send_update() + + return !length(to_image) diff --git a/code/modules/lootpanel/search_object.dm b/code/modules/lootpanel/search_object.dm new file mode 100644 index 0000000000000..520228e465eb3 --- /dev/null +++ b/code/modules/lootpanel/search_object.dm @@ -0,0 +1,84 @@ +/** + * ## Search Object + * An object for content lists. Compacted item data. + */ +/datum/search_object + /// Item we're indexing + var/atom/item + /// Url to the image of the object + var/icon + /// Icon state, for inexpensive icons + var/icon_state + /// Name of the original object + var/name + /// Typepath of the original object for ui grouping + var/path + + +/datum/search_object/New(client/owner, atom/item) + . = ..() + + src.item = item + name = item.name + if(isobj(item)) + path = item.type + + if(isturf(item)) + RegisterSignal(item, COMSIG_TURF_CHANGE, PROC_REF(on_turf_change)) + else + RegisterSignals(item, list( + COMSIG_ITEM_PICKUP, + COMSIG_MOVABLE_MOVED, + COMSIG_QDELETING, + ), PROC_REF(on_item_moved)) + + // Icon generation conditions ////////////// + // Condition 1: Icon is complex + if(ismob(item) || length(item.overlays) > 2) + return + + // Condition 2: Can't get icon path + if(!isfile(item.icon) || !length("[item.icon]")) + return + + // Condition 3: Using opendream +#if defined(OPENDREAM) || defined(UNIT_TESTS) + return +#endif + + // Condition 4: Using older byond version + var/build = owner.byond_build + var/version = owner.byond_version + if(build < 515 || (build == 515 && version < 1635)) + return + + icon = "[item.icon]" + icon_state = item.icon_state + + +/datum/search_object/Destroy(force) + item = null + + return ..() + + +/// Generates the icon for the search object. This is the expensive part. +/datum/search_object/proc/generate_icon(client/owner) + if(ismob(item) || length(item.overlays) > 2) + icon = costly_icon2html(item, owner, sourceonly = TRUE) + else // our pre 515.1635 fallback for normal items + icon = icon2html(item, owner, sourceonly = TRUE) + + +/// Parent item has been altered, search object no longer valid +/datum/search_object/proc/on_item_moved(atom/source) + SIGNAL_HANDLER + + qdel(src) + + +/// Parent tile has been altered, entire search needs reset +/datum/search_object/proc/on_turf_change(turf/source, path, list/new_baseturfs, flags, list/post_change_callbacks) + SIGNAL_HANDLER + + post_change_callbacks += CALLBACK(src, GLOBAL_PROC_REF(qdel), src) diff --git a/code/modules/lootpanel/ss_looting.dm b/code/modules/lootpanel/ss_looting.dm new file mode 100644 index 0000000000000..cf0882fa89030 --- /dev/null +++ b/code/modules/lootpanel/ss_looting.dm @@ -0,0 +1,39 @@ + +/// Queues image generation for search objects without icons +SUBSYSTEM_DEF(looting) + name = "Loot Icon Generation" + init_order = INIT_ORDER_LOOT + priority = FIRE_PRIORITY_PROCESS + wait = 0.5 SECONDS + /// Backlog of items. Gets put into processing + var/list/datum/lootpanel/backlog = list() + /// Actively processing items + var/list/datum/lootpanel/processing = list() + + +/datum/controller/subsystem/looting/stat_entry(msg) + msg = "P:[length(backlog)]" + return ..() + + +/datum/controller/subsystem/looting/fire(resumed) + if(!length(backlog)) + return + + if(!resumed) + processing = backlog + backlog = list() + + while(length(processing)) + var/datum/lootpanel/panel = processing[length(processing)] + if(QDELETED(panel) || !length(panel.to_image)) + processing.len-- + continue + + if(!panel.process_images()) + backlog += panel + + if(MC_TICK_CHECK) + return + + processing.len-- diff --git a/code/modules/lootpanel/ui.dm b/code/modules/lootpanel/ui.dm new file mode 100644 index 0000000000000..3c829871c604d --- /dev/null +++ b/code/modules/lootpanel/ui.dm @@ -0,0 +1,46 @@ +/// UI helper for converting the associative list to a list of lists +/datum/lootpanel/proc/get_contents() + var/list/items = list() + + for(var/datum/search_object/index as anything in contents) + UNTYPED_LIST_ADD(items, list( + "icon_state" = index.icon_state, + "icon" = index.icon, + "name" = index.name, + "path" = index.path, + "ref" = REF(index), + )) + + return items + + +/// Clicks an object from the contents. Validates the object and the user +/datum/lootpanel/proc/grab(mob/user, list/params) + var/ref = params["ref"] + if(isnull(ref)) + return FALSE + + if(!source_turf.Adjacent(user)) // Source tile is no longer valid + reset_contents() + return FALSE + + var/datum/search_object/index = locate(ref) in contents + var/atom/thing = index?.item + if(QDELETED(index) || QDELETED(thing)) // Obj is gone + return FALSE + + if(thing != source_turf && !(locate(thing) in source_turf.contents)) + qdel(index) // Item has moved + return TRUE + + var/modifiers = "" + if(params["ctrl"]) + modifiers += "ctrl=1;" + if(params["middle"]) + modifiers += "middle=1;" + if(params["shift"]) + modifiers += "shift=1;" + + user.ClickOn(thing, modifiers) + + return TRUE diff --git a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm index 266e7b5b4143f..c7ceb73e3c825 100644 --- a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm +++ b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm @@ -204,7 +204,7 @@ ShiftClickOn(A) return if(LAZYACCESS(modifiers, ALT_CLICK)) - AltClickNoInteract(src, A) + A.AltClick(src) return if(LAZYACCESS(modifiers, RIGHT_CLICK)) ranged_secondary_attack(A, modifiers) diff --git a/code/modules/tgui/tgui.dm b/code/modules/tgui/tgui.dm index 64bd496f2bbb3..754335494f98f 100644 --- a/code/modules/tgui/tgui.dm +++ b/code/modules/tgui/tgui.dm @@ -118,6 +118,8 @@ /datum/asset/simple/namespaced/fontawesome)) flush_queue |= window.send_asset(get_asset_datum( /datum/asset/simple/namespaced/tgfont)) + flush_queue |= window.send_asset(get_asset_datum( + /datum/asset/json/icon_ref_map)) for(var/datum/asset/asset in src_object.ui_assets(user)) flush_queue |= window.send_asset(asset) if (flush_queue) diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index b179640885619..1d80c7d411bec 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -168,6 +168,7 @@ #include "ling_decap.dm" #include "liver.dm" #include "load_map_security.dm" +#include "lootpanel.dm" #include "lungs.dm" #include "machine_disassembly.dm" #include "mafia.dm" diff --git a/code/modules/unit_tests/lootpanel.dm b/code/modules/unit_tests/lootpanel.dm new file mode 100644 index 0000000000000..c0bec13288cb0 --- /dev/null +++ b/code/modules/unit_tests/lootpanel.dm @@ -0,0 +1,34 @@ +/datum/unit_test/lootpanel + abstract_type = /datum/unit_test/lootpanel + +/datum/unit_test/lootpanel/contents/Run() + var/datum/client_interface/mock_client = new() + var/datum/lootpanel/panel = new(mock_client) + var/mob/living/carbon/human/labrat = allocate(/mob/living/carbon/human/consistent) + mock_client.mob = labrat + var/turf/one_over = locate(run_loc_floor_bottom_left.x + 1, run_loc_floor_bottom_left.y, run_loc_floor_bottom_left.z) + var/obj/item/storage/toolbox/box = allocate(/obj/item/storage/toolbox, one_over) + + panel.open(one_over) + TEST_ASSERT_EQUAL(length(panel.contents), 2, "Contents should populate on open") + TEST_ASSERT_EQUAL(length(panel.to_image), 2, "to_image should've populated (unit testing)") + TEST_ASSERT_EQUAL(panel.contents[1].item, one_over, "First item should be the source turf") + + var/datum/search_object/searchable = panel.contents[2] + TEST_ASSERT_EQUAL(searchable.item, box, "Second item should be the box") + + qdel(box) + TEST_ASSERT_EQUAL(length(panel.contents), 1, "Contents should update on searchobj deleted") + TEST_ASSERT_EQUAL(length(panel.to_image), 1, "to_image should update on searchobj deleted") + + var/obj/item/storage/toolbox/new_box = allocate(/obj/item/storage/toolbox, one_over) + TEST_ASSERT_EQUAL(length(panel.contents), 1, "Contents shouldn't update, we're dumb") + TEST_ASSERT_EQUAL(length(panel.to_image), 1, "to_image shouldn't update, we're dumb") + + panel.populate_contents() // this also calls reset_contents bc length(contents) + TEST_ASSERT_EQUAL(length(panel.contents), 2, "Contents should repopulate with the new toolbox") + + panel.populate_contents() + TEST_ASSERT_EQUAL(length(panel.contents), 2, "Panel shouldnt dupe searchables if reopened") + + mock_client.mob = null diff --git a/tgstation.dme b/tgstation.dme index fb6fef1d9090f..b4b9237a7f9ba 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -751,7 +751,6 @@ #include "code\controllers\subsystem\processing\greyscale.dm" #include "code\controllers\subsystem\processing\instruments.dm" #include "code\controllers\subsystem\processing\obj.dm" -#include "code\controllers\subsystem\processing\obj_tab_items.dm" #include "code\controllers\subsystem\processing\plumbing.dm" #include "code\controllers\subsystem\processing\processing.dm" #include "code\controllers\subsystem\processing\projectiles.dm" @@ -3307,6 +3306,7 @@ #include "code\modules\asset_cache\assets\fontawesome.dm" #include "code\modules\asset_cache\assets\genetics.dm" #include "code\modules\asset_cache\assets\headers.dm" +#include "code\modules\asset_cache\assets\icon_ref_map.dm" #include "code\modules\asset_cache\assets\inventory.dm" #include "code\modules\asset_cache\assets\irv.dm" #include "code\modules\asset_cache\assets\jquery.dm" @@ -4390,6 +4390,13 @@ #include "code\modules\logging\categories\log_category_silo.dm" #include "code\modules\logging\categories\log_category_target_zone_switch.dm" #include "code\modules\logging\categories\log_category_uplink.dm" +#include "code\modules\lootpanel\_lootpanel.dm" +#include "code\modules\lootpanel\contents.dm" +#include "code\modules\lootpanel\handlers.dm" +#include "code\modules\lootpanel\misc.dm" +#include "code\modules\lootpanel\search_object.dm" +#include "code\modules\lootpanel\ss_looting.dm" +#include "code\modules\lootpanel\ui.dm" #include "code\modules\mafia\_defines.dm" #include "code\modules\mafia\controller.dm" #include "code\modules\mafia\controller_ui.dm" diff --git a/tgui/packages/tgui/components/DmIcon.tsx b/tgui/packages/tgui/components/DmIcon.tsx new file mode 100644 index 0000000000000..fb6816576ac0c --- /dev/null +++ b/tgui/packages/tgui/components/DmIcon.tsx @@ -0,0 +1,72 @@ +import { ReactNode, useEffect, useState } from 'react'; + +import { resolveAsset } from '../assets'; +import { fetchRetry } from '../http'; +import { BoxProps } from './Box'; +import { Image } from './Image'; + +enum Direction { + NORTH = 1, + SOUTH = 2, + EAST = 4, + WEST = 8, + NORTHEAST = NORTH | EAST, + NORTHWEST = NORTH | WEST, + SOUTHEAST = SOUTH | EAST, + SOUTHWEST = SOUTH | WEST, +} + +type Props = { + /** Required: The path of the icon */ + icon: string; + /** Required: The state of the icon */ + icon_state: string; +} & Partial<{ + /** Facing direction. See direction enum. Default is South */ + direction: Direction; + /** Fallback icon. */ + fallback: ReactNode; + /** Frame number. Default is 1 */ + frame: number; + /** Movement state. Default is false */ + movement: boolean; +}> & + BoxProps; + +let refMap: Record | undefined; + +export function DmIcon(props: Props) { + const { + className, + direction = Direction.SOUTH, + fallback, + frame = 1, + icon_state, + icon, + movement = false, + ...rest + } = props; + + const [iconRef, setIconRef] = useState(''); + + const query = `${iconRef}?state=${icon_state}&dir=${direction}&movement=${movement}&frame=${frame}`; + + useEffect(() => { + async function fetchRefMap() { + const response = await fetchRetry(resolveAsset('icon_ref_map.json')); + const data = await response.json(); + refMap = data; + setIconRef(data[icon]); + } + + if (!refMap) { + fetchRefMap(); + } else { + setIconRef(refMap[icon]); + } + }, []); + + if (!iconRef) return fallback; + + return ; +} diff --git a/tgui/packages/tgui/components/Image.tsx b/tgui/packages/tgui/components/Image.tsx index 3e1519bfbbf05..5d3a943feb0f2 100644 --- a/tgui/packages/tgui/components/Image.tsx +++ b/tgui/packages/tgui/components/Image.tsx @@ -1,12 +1,14 @@ -import { ReactNode } from 'react'; +import { useRef } from 'react'; import { BoxProps, computeBoxProps } from './Box'; -import { Tooltip } from './Tooltip'; type Props = Partial<{ - fixBlur: boolean; // true is default, this is an ie thing - objectFit: 'contain' | 'cover'; // fill is default - tooltip: ReactNode; + /** True is default, this fixes an ie thing */ + fixBlur: boolean; + /** False by default. Good if you're fetching images on UIs that do not auto update. This will attempt to fix the 'x' icon 5 times. */ + fixErrors: boolean; + /** Fill is default. */ + objectFit: 'contain' | 'cover'; }> & IconUnion & BoxProps; @@ -22,16 +24,18 @@ type IconUnion = src?: string; }; +const maxAttempts = 5; + /** Image component. Use this instead of Box as="img". */ -export const Image = (props: Props) => { +export function Image(props: Props) { const { - className, fixBlur = true, + fixErrors = false, objectFit = 'fill', src, - tooltip, ...rest } = props; + const attempts = useRef(0); const computedProps = computeBoxProps(rest); computedProps['style'] = { @@ -40,11 +44,20 @@ export const Image = (props: Props) => { objectFit, }; - let content = ; - - if (tooltip) { - content = {content}; - } - - return content; -}; + return ( + { + if (fixErrors && attempts.current < maxAttempts) { + const imgElement = event.currentTarget; + + setTimeout(() => { + imgElement.src = `${src}?attempt=${attempts.current}`; + attempts.current++; + }, 1000); + } + }} + src={src} + {...computedProps} + /> + ); +} diff --git a/tgui/packages/tgui/components/index.ts b/tgui/packages/tgui/components/index.ts index 1a5f477d256b5..fdeb475ed3b8d 100644 --- a/tgui/packages/tgui/components/index.ts +++ b/tgui/packages/tgui/components/index.ts @@ -17,6 +17,7 @@ export { ColorBox } from './ColorBox'; export { Dialog } from './Dialog'; export { Dimmer } from './Dimmer'; export { Divider } from './Divider'; +export { DmIcon } from './DmIcon'; export { DraggableControl } from './DraggableControl'; export { Dropdown } from './Dropdown'; export { FitText } from './FitText'; diff --git a/tgui/packages/tgui/interfaces/LootPanel/GroupedContents.tsx b/tgui/packages/tgui/interfaces/LootPanel/GroupedContents.tsx new file mode 100644 index 0000000000000..5bfecce0b8ae9 --- /dev/null +++ b/tgui/packages/tgui/interfaces/LootPanel/GroupedContents.tsx @@ -0,0 +1,47 @@ +import { createSearch } from 'common/string'; +import { useMemo } from 'react'; + +import { Flex } from '../../components'; +import { LootBox } from './LootBox'; +import { SearchGroup, SearchItem } from './types'; + +type Props = { + contents: SearchItem[]; + searchText: string; +}; + +export function GroupedContents(props: Props) { + const { contents, searchText } = props; + + // limitations: items with different stack counts, charges etc. + const contentsByPath = useMemo(() => { + const acc: Record = {}; + + for (let i = 0; i < contents.length; i++) { + const item = contents[i]; + if (item.path) { + if (!acc[item.path]) { + acc[item.path] = []; + } + acc[item.path].push(item); + } else { + acc[item.ref] = [item]; + } + } + return acc; + }, [contents]); + + const filteredContents: SearchGroup[] = Object.entries(contentsByPath) + .filter(createSearch(searchText, ([_, items]) => items[0].name)) + .map(([_, items]) => ({ amount: items.length, item: items[0] })); + + return ( + + {filteredContents.map((group) => ( + + + + ))} + + ); +} diff --git a/tgui/packages/tgui/interfaces/LootPanel/IconDisplay.tsx b/tgui/packages/tgui/interfaces/LootPanel/IconDisplay.tsx new file mode 100644 index 0000000000000..889d50de88415 --- /dev/null +++ b/tgui/packages/tgui/interfaces/LootPanel/IconDisplay.tsx @@ -0,0 +1,24 @@ +import { DmIcon, Icon, Image } from '../../components'; +import { SearchItem } from './types'; + +type Props = { + item: SearchItem; +}; + +export function IconDisplay(props: Props) { + const { + item: { icon, icon_state }, + } = props; + + const fallback = ; + + if (!icon) { + return fallback; + } + + if (icon_state) { + return ; + } + + return ; +} diff --git a/tgui/packages/tgui/interfaces/LootPanel/LootBox.tsx b/tgui/packages/tgui/interfaces/LootPanel/LootBox.tsx new file mode 100644 index 0000000000000..22b0c8532dd9e --- /dev/null +++ b/tgui/packages/tgui/interfaces/LootPanel/LootBox.tsx @@ -0,0 +1,53 @@ +import { capitalizeAll } from 'common/string'; + +import { useBackend } from '../../backend'; +import { Tooltip } from '../../components'; +import { IconDisplay } from './IconDisplay'; +import { SearchGroup, SearchItem } from './types'; + +type Props = + | { + item: SearchItem; + } + | { + group: SearchGroup; + }; + +export function LootBox(props: Props) { + const { act } = useBackend(); + + let amount = 0; + let item: SearchItem; + if ('group' in props) { + amount = props.group.amount; + item = props.group.item; + } else { + item = props.item; + } + + return ( + +
    + act('grab', { + ctrl: event.ctrlKey, + ref: item.ref, + shift: event.shiftKey, + }) + } + onContextMenu={(event) => { + event.preventDefault(); + act('grab', { + middle: true, + ref: item.ref, + shift: true, + }); + }} + > + + {amount > 1 &&
    {amount}
    } +
    +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/LootPanel/RawContents.tsx b/tgui/packages/tgui/interfaces/LootPanel/RawContents.tsx new file mode 100644 index 0000000000000..4241d36dc0aa2 --- /dev/null +++ b/tgui/packages/tgui/interfaces/LootPanel/RawContents.tsx @@ -0,0 +1,28 @@ +import { createSearch } from 'common/string'; + +import { Flex } from '../../components'; +import { LootBox } from './LootBox'; +import { SearchItem } from './types'; + +type Props = { + contents: SearchItem[]; + searchText: string; +}; + +export function RawContents(props: Props) { + const { contents, searchText } = props; + + const filteredContents = contents.filter( + createSearch(searchText, (item: SearchItem) => item.name), + ); + + return ( + + {filteredContents.map((item) => ( + + + + ))} + + ); +} diff --git a/tgui/packages/tgui/interfaces/LootPanel/index.tsx b/tgui/packages/tgui/interfaces/LootPanel/index.tsx new file mode 100644 index 0000000000000..bd64113f302ec --- /dev/null +++ b/tgui/packages/tgui/interfaces/LootPanel/index.tsx @@ -0,0 +1,76 @@ +import { KEY } from 'common/keys'; +import { BooleanLike } from 'common/react'; +import { useState } from 'react'; + +import { useBackend } from '../../backend'; +import { Button, Input, Section, Stack } from '../../components'; +import { Window } from '../../layouts'; +import { GroupedContents } from './GroupedContents'; +import { RawContents } from './RawContents'; +import { SearchItem } from './types'; + +type Data = { + contents: SearchItem[]; + searching: BooleanLike; +}; + +export function LootPanel(props) { + const { act, data } = useBackend(); + const { contents = [], searching } = data; + + const [grouping, setGrouping] = useState(true); + const [searchText, setSearchText] = useState(''); + + const total = contents.length ? contents.length - 1 : 0; + + return ( + + { + if (event.key === KEY.Escape) { + Byond.sendMessage('close'); + } + }} + > +
    + + setSearchText(value)} + placeholder="Search" + /> + + +
    +
    +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/LootPanel/types.ts b/tgui/packages/tgui/interfaces/LootPanel/types.ts new file mode 100644 index 0000000000000..f17b02b0c1381 --- /dev/null +++ b/tgui/packages/tgui/interfaces/LootPanel/types.ts @@ -0,0 +1,13 @@ +export type SearchItem = { + name: string; + path: string; + ref: string; +} & Partial<{ + icon: string; + icon_state: string; +}>; + +export type SearchGroup = { + amount: number; + item: SearchItem; +}; diff --git a/tgui/packages/tgui/interfaces/NtosEmojipedia.tsx b/tgui/packages/tgui/interfaces/NtosEmojipedia.tsx index 3852e90ac26fc..d9e6c7233eef9 100644 --- a/tgui/packages/tgui/interfaces/NtosEmojipedia.tsx +++ b/tgui/packages/tgui/interfaces/NtosEmojipedia.tsx @@ -3,7 +3,7 @@ import { createSearch } from 'common/string'; import { useState } from 'react'; import { useBackend } from '../backend'; -import { Button, Image, Input, Section } from '../components'; +import { Button, Image, Input, Section, Tooltip } from '../components'; import { NtosWindow } from '../layouts'; type Data = { @@ -44,15 +44,15 @@ export const NtosEmojipedia = (props) => { } > {filteredEmojis.map((emoji) => ( - { - copyText(emoji.name); - }} - /> + + { + copyText(emoji.name); + }} + /> + ))} diff --git a/tgui/packages/tgui/styles/components/SearchItem.scss b/tgui/packages/tgui/styles/components/SearchItem.scss new file mode 100644 index 0000000000000..76946ec9c5acb --- /dev/null +++ b/tgui/packages/tgui/styles/components/SearchItem.scss @@ -0,0 +1,22 @@ +@use '../colors.scss'; + +.SearchItem { + align-items: center; + background: black; + border: thin solid #212121; + display: flex; + height: 3rem; + justify-content: center; + position: relative; + width: 3rem; + margin-bottom: 0; +} + +.SearchItem--amount { + bottom: -1rem; + color: colors.$teal; + font-family: 'Roboto', sans-serif; + font-size: 1.5rem; + position: absolute; + right: -4px; +} diff --git a/tgui/packages/tgui/styles/main.scss b/tgui/packages/tgui/styles/main.scss index 91712be44d0da..46881d23df79f 100644 --- a/tgui/packages/tgui/styles/main.scss +++ b/tgui/packages/tgui/styles/main.scss @@ -38,6 +38,7 @@ @include meta.load-css('./components/NumberInput.scss'); @include meta.load-css('./components/ProgressBar.scss'); @include meta.load-css('./components/RoundGauge.scss'); +@include meta.load-css('./components/SearchItem.scss'); @include meta.load-css('./components/Section.scss'); @include meta.load-css('./components/Slider.scss'); @include meta.load-css('./components/Stack.scss'); From bd369b069dab46670319caa4e58285c30e7af2ef Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 15 Apr 2024 09:35:22 +1200 Subject: [PATCH 235/938] Automatic changelog for PR #82533 [ci skip] --- html/changelogs/AutoChangeLog-pr-82533.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82533.yml diff --git a/html/changelogs/AutoChangeLog-pr-82533.yml b/html/changelogs/AutoChangeLog-pr-82533.yml new file mode 100644 index 0000000000000..f016299b0f084 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82533.yml @@ -0,0 +1,5 @@ +author: "jlsnow301" +delete-after: True +changes: + - rscadd: "Added a loot window for alt-clicking tiles." + - rscdel: "Removed the item browser from the stat panel." \ No newline at end of file From 6f9ff80e22038d4783c800fc29ad97a152eb56ff Mon Sep 17 00:00:00 2001 From: Thunder12345 Date: Mon, 15 Apr 2024 00:19:28 +0100 Subject: [PATCH 236/938] Fixes a critical spelling mistake (#82651) ## About The Pull Request See title ## Why It's Good For The Game Spell word good is good. ## Changelog :cl: spellcheck: Pre-Approved Cyborg Candidates are no longer "Cantidates" /:cl: --- code/modules/clothing/under/accessories/badges.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/clothing/under/accessories/badges.dm b/code/modules/clothing/under/accessories/badges.dm index ffb2b0431ec57..94ba72f164def 100644 --- a/code/modules/clothing/under/accessories/badges.dm +++ b/code/modules/clothing/under/accessories/badges.dm @@ -172,7 +172,7 @@ display = span_notice("The dogtag is all scratched up.") /obj/item/clothing/accessory/dogtag/borg_ready - name = "Pre-Approved Cyborg Cantidate dogtag" + name = "Pre-Approved Cyborg Candidate dogtag" display = "This employee has been screened for negative mental traits to an acceptable level of accuracy, and is approved for the NT Cyborg program as an alternative to medical resuscitation." /// Reskins for the pride pin accessory, mapped by display name to icon state From 4a313cefa26f4f1813786dea3ed9110c59a687a2 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 15 Apr 2024 11:19:52 +1200 Subject: [PATCH 237/938] Automatic changelog for PR #82651 [ci skip] --- html/changelogs/AutoChangeLog-pr-82651.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82651.yml diff --git a/html/changelogs/AutoChangeLog-pr-82651.yml b/html/changelogs/AutoChangeLog-pr-82651.yml new file mode 100644 index 0000000000000..3eab9eb5eff45 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82651.yml @@ -0,0 +1,4 @@ +author: "Thunder12345" +delete-after: True +changes: + - spellcheck: "Pre-Approved Cyborg Candidates are no longer \"Cantidates\"" \ No newline at end of file From 411d4269b35b32c4001b83794217d59edd708f53 Mon Sep 17 00:00:00 2001 From: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com> Date: Mon, 15 Apr 2024 01:22:06 +0200 Subject: [PATCH 238/938] [nogbp] fixes minebots bombing each other (#82655) ## About The Pull Request minebots will no longer be able to explode each other through landmines. also fixes regenerative shield overlays appearing pitch black in lower z levels. ## Why It's Good For The Game fixes #82396 ## Changelog :cl: fix: minebots no longer bomb each other (and other miners) through landmines fix: minebot shields will no longer lose color in lower z levels /:cl: --- .../living/basic/minebots/minebot_abilities.dm | 15 +++++++++++++-- .../mob/living/basic/minebots/minebot_ai.dm | 2 +- .../mob/living/basic/minebots/minebot_upgrades.dm | 4 ++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/code/modules/mob/living/basic/minebots/minebot_abilities.dm b/code/modules/mob/living/basic/minebots/minebot_abilities.dm index 88cd156d1b121..8d1a93bd42916 100644 --- a/code/modules/mob/living/basic/minebots/minebot_abilities.dm +++ b/code/modules/mob/living/basic/minebots/minebot_abilities.dm @@ -63,7 +63,10 @@ var/wind_up_timer = 1 SECONDS /datum/action/cooldown/mob_cooldown/missile_launcher/IsAvailable(feedback = TRUE) - if(is_mining_level(owner.z)) + . = ..() + if(!.) + return FALSE + if(lavaland_equipment_pressure_check(get_turf(owner))) return TRUE if(feedback) owner.balloon_alert(owner, "cant be used here!") @@ -101,7 +104,10 @@ click_to_activate = FALSE /datum/action/cooldown/mob_cooldown/drop_landmine/IsAvailable(feedback = TRUE) - if(is_mining_level(owner.z)) + . = ..() + if(!.) + return FALSE + if(lavaland_equipment_pressure_check(get_turf(owner))) return TRUE if(feedback) owner.balloon_alert(owner, "cant be used here!") @@ -176,4 +182,9 @@ /obj/effect/mine/minebot/can_trigger(atom/movable/on_who) if(REF(on_who) in ignore_list) return FALSE + if(!isliving(on_who)) + return ..() + var/mob/living/stepped_mob = on_who + if(FACTION_NEUTRAL in stepped_mob.faction) + return FALSE return ..() diff --git a/code/modules/mob/living/basic/minebots/minebot_ai.dm b/code/modules/mob/living/basic/minebots/minebot_ai.dm index 2e585085a104b..059048f761a44 100644 --- a/code/modules/mob/living/basic/minebots/minebot_ai.dm +++ b/code/modules/mob/living/basic/minebots/minebot_ai.dm @@ -15,10 +15,10 @@ idle_behavior = /datum/idle_behavior/idle_random_walk planning_subtrees = list( /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/launch_missiles, /datum/ai_planning_subtree/pet_planning, /datum/ai_planning_subtree/befriend_miners, /datum/ai_planning_subtree/defend_node, - /datum/ai_planning_subtree/launch_missiles, /datum/ai_planning_subtree/minebot_maintain_distance, /datum/ai_planning_subtree/basic_ranged_attack_subtree/minebot, /datum/ai_planning_subtree/find_and_hunt_target/hunt_ores/minebot, diff --git a/code/modules/mob/living/basic/minebots/minebot_upgrades.dm b/code/modules/mob/living/basic/minebots/minebot_upgrades.dm index d1800072b5dd8..14c62f7fefc51 100644 --- a/code/modules/mob/living/basic/minebots/minebot_upgrades.dm +++ b/code/modules/mob/living/basic/minebots/minebot_upgrades.dm @@ -78,7 +78,7 @@ /obj/effect/overlay/minebot_top_shield mouse_opacity = MOUSE_OPACITY_TRANSPARENT anchored = TRUE - vis_flags = VIS_INHERIT_DIR + vis_flags = VIS_INHERIT_DIR | VIS_INHERIT_PLANE icon = 'icons/mob/silicon/aibots.dmi' icon_state = "minebot_shield_top_layer" layer = ABOVE_ALL_MOB_LAYER @@ -86,7 +86,7 @@ /obj/effect/overlay/minebot_bottom_shield mouse_opacity = MOUSE_OPACITY_TRANSPARENT anchored = TRUE - vis_flags = VIS_INHERIT_DIR + vis_flags = VIS_INHERIT_DIR | VIS_INHERIT_PLANE icon = 'icons/mob/silicon/aibots.dmi' icon_state = "minebot_shield_bottom_layer" layer = BELOW_MOB_LAYER From 430bd402941a792d4852306f4e4b6e777f83a09d Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 15 Apr 2024 11:22:26 +1200 Subject: [PATCH 239/938] Automatic changelog for PR #82655 [ci skip] --- html/changelogs/AutoChangeLog-pr-82655.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82655.yml diff --git a/html/changelogs/AutoChangeLog-pr-82655.yml b/html/changelogs/AutoChangeLog-pr-82655.yml new file mode 100644 index 0000000000000..15ecc79666d9b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82655.yml @@ -0,0 +1,5 @@ +author: "Ben10Omintrix" +delete-after: True +changes: + - bugfix: "minebots no longer bomb each other (and other miners) through landmines" + - bugfix: "minebot shields will no longer lose color in lower z levels" \ No newline at end of file From 27d64ed58d34ee12c675b06a64f6cac09896dda8 Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Sun, 14 Apr 2024 18:29:39 -0500 Subject: [PATCH 240/938] Reverts parts of #82602 (nodeath checks) (#82637) ## About The Pull Request Reverts the nodeath checks of #82602 I opened a review thinking these checks were sus and the PR author said they would remove them, but it was merged before that happened. TL;DR 1. I just noticed this now but it only affects carbons / humans it doesn't even cover living or any other subtypes 2. Kinda sus. Some code intentionally skips checking nodeath (I guess? Like removing the brain for example) so we would need a larger audit of this rather than haphazardly throwing it in. --- code/modules/mob/living/carbon/death.dm | 2 +- code/modules/mob/living/carbon/human/death.dm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/mob/living/carbon/death.dm b/code/modules/mob/living/carbon/death.dm index f74c2c1ca2165..41a958518c597 100644 --- a/code/modules/mob/living/carbon/death.dm +++ b/code/modules/mob/living/carbon/death.dm @@ -1,5 +1,5 @@ /mob/living/carbon/death(gibbed) - if(stat == DEAD || HAS_TRAIT(src, TRAIT_NODEATH) && !gibbed) + if(stat == DEAD) return losebreath = 0 diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index 08454bc4657fd..dd97c12bd844f 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -20,7 +20,7 @@ GLOBAL_LIST_EMPTY(dead_players_during_shift) new /obj/effect/decal/remains/human(loc) /mob/living/carbon/human/death(gibbed) - if(stat == DEAD || HAS_TRAIT(src, TRAIT_NODEATH) && !gibbed) + if(stat == DEAD) return stop_sound_channel(CHANNEL_HEARTBEAT) var/obj/item/organ/internal/heart/human_heart = get_organ_slot(ORGAN_SLOT_HEART) From c514facd5f599e4627f99a9d82bb700721a404e9 Mon Sep 17 00:00:00 2001 From: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Date: Sun, 14 Apr 2024 16:33:36 -0700 Subject: [PATCH 241/938] Removes redundant update_parallax_contents calls (#82644) ## About The Pull Request Off shuttle move doesn't need to happen because shuttles use abstract move which calls it anyway Similar story for the ghost stuff, this was actually causing pretty common double calls so we may actually get somethin out of this Oh and something in air which is past me knifing me in the back --- code/_onclick/observer.dm | 1 - code/controllers/subsystem/air.dm | 1 - code/modules/mob/dead/observer/observer.dm | 3 --- code/modules/shuttle/on_move.dm | 2 -- 4 files changed, 7 deletions(-) diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm index 2c236d7232c99..65fccef85b9af 100644 --- a/code/_onclick/observer.dm +++ b/code/_onclick/observer.dm @@ -9,7 +9,6 @@ // Otherwise jump else if(A.loc) abstract_move(get_turf(A)) - update_parallax_contents() /mob/dead/observer/ClickOn(atom/A, params) if(check_click_intercept(params,A)) diff --git a/code/controllers/subsystem/air.dm b/code/controllers/subsystem/air.dm index 1de3f900c8ca0..1cb3e2dec3783 100644 --- a/code/controllers/subsystem/air.dm +++ b/code/controllers/subsystem/air.dm @@ -898,7 +898,6 @@ GLOBAL_LIST_EMPTY(colored_images) if(!target) return usr.forceMove(target) - usr.update_parallax_contents() if("toggle-freeze") can_fire = !can_fire return TRUE diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 095d73bf3c3c1..18b55cd6a5f07 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -340,7 +340,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp set_glide_size(glide_size_override) if(NewLoc) abstract_move(NewLoc) - update_parallax_contents() else var/turf/destination = get_turf(src) @@ -462,7 +461,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp return usr.abstract_move(pick(L)) - update_parallax_contents() /mob/dead/observer/verb/follow() set category = "Ghost" @@ -533,7 +531,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if(isturf(destination_turf)) source_mob.abstract_move(destination_turf) - source_mob.update_parallax_contents() else to_chat(source_mob, span_danger("This mob is not located in the game world.")) diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm index 9b267489100ee..56f99e270a49d 100644 --- a/code/modules/shuttle/on_move.dm +++ b/code/modules/shuttle/on_move.dm @@ -115,8 +115,6 @@ All ShuttleMove procs go here if(rotation) shuttleRotate(rotation) - update_parallax_contents() - return TRUE /atom/movable/proc/lateShuttleMove(turf/oldT, list/movement_force, move_dir) From fb2a8d9ac306abf9d12e1da2a9f8a733cdae8b6d Mon Sep 17 00:00:00 2001 From: Aylong <69762909+AyIong@users.noreply.github.com> Date: Mon, 15 Apr 2024 02:33:54 +0300 Subject: [PATCH 242/938] Makes TGchat General settings better (#82652) ## About The Pull Request Removes dropdowns from General settings tab into TGchat Replace it with map() and Collapsible | Before | After | | - | - | | ![image](https://github.com/tgstation/tgstation/assets/69762909/b9956aef-3c99-4ec0-b7bd-d23db75a9c71) | ![image](https://github.com/tgstation/tgstation/assets/69762909/35504396-99a7-402c-97b6-3496013d9b2b) | ## Why It's Good For The Game Dropdowns sucks. At least in TGchat settings, it's not the first time they've been broken, but now it's trivially extremely inconvenient. Now, it's faster to change the theme/font, plus a font preview has been added, as it was before with GoonChat
    Video https://github.com/tgstation/tgstation/assets/69762909/b440db53-e78e-4440-ba33-b8e7ecade00a
    ## Changelog :cl: qol: General settings tab into TGchat, looks better now, and is more convenient to use. Also, each button has a font written on it. /:cl: --- .../tgui-panel/settings/SettingsPanel.jsx | 107 +++++++++++------- 1 file changed, 66 insertions(+), 41 deletions(-) diff --git a/tgui/packages/tgui-panel/settings/SettingsPanel.jsx b/tgui/packages/tgui-panel/settings/SettingsPanel.jsx index 130f59d80537d..e5691037bba68 100644 --- a/tgui/packages/tgui-panel/settings/SettingsPanel.jsx +++ b/tgui/packages/tgui-panel/settings/SettingsPanel.jsx @@ -5,14 +5,15 @@ */ import { toFixed } from 'common/math'; +import { capitalize } from 'common/string'; import { useLocalState } from 'tgui/backend'; import { useDispatch, useSelector } from 'tgui/backend'; import { Box, Button, + Collapsible, ColorBox, Divider, - Dropdown, Input, LabeledList, NumberInput, @@ -84,37 +85,62 @@ export const SettingsGeneral = (props) => {
    - - dispatch( - updateSettings({ - theme: value, - }), - ) - } - /> + {THEMES.map((THEME) => ( +
    diff --git a/tgui/packages/tgui/interfaces/NtosMessenger/index.tsx b/tgui/packages/tgui/interfaces/NtosMessenger/index.tsx index 852ca62cc5594..896ca90d60270 100644 --- a/tgui/packages/tgui/interfaces/NtosMessenger/index.tsx +++ b/tgui/packages/tgui/interfaces/NtosMessenger/index.tsx @@ -100,7 +100,8 @@ const ContactsScreen = (props: any) => { const [searchUser, setSearchUser] = useState(''); - const sortByUnreads = sortBy((chat) => chat.unread_messages); + const sortByUnreads = (array: NtChat[]) => + sortBy(array, (chat) => chat.unread_messages); const searchChatByName = createSearch( searchUser, diff --git a/tgui/packages/tgui/interfaces/NtosNetDownloader.tsx b/tgui/packages/tgui/interfaces/NtosNetDownloader.tsx index 0bfdafc7b6202..489c443f0c1ad 100644 --- a/tgui/packages/tgui/interfaces/NtosNetDownloader.tsx +++ b/tgui/packages/tgui/interfaces/NtosNetDownloader.tsx @@ -1,5 +1,4 @@ import { filter, sortBy } from 'common/collections'; -import { flow } from 'common/fp'; import { scale, toFixed } from 'common/math'; import { BooleanLike } from 'common/react'; import { createSearch } from 'common/string'; @@ -70,20 +69,22 @@ export const NtosNetDownloader = (props) => { searchItem, (program) => program.filedesc, ); - const items = flow([ + let items = searchItem.length > 0 ? // If we have a query, search everything for it. - filter(search) + filter(programs, search) : // Otherwise, show respective programs for the category. - filter((program: ProgramData) => program.category === selectedCategory), - // This sorts all programs in the lists by name and compatibility - sortBy( - (program: ProgramData) => !program.compatible, - (program: ProgramData) => program.filedesc, - ), + filter(programs, (program) => program.category === selectedCategory); + // This sorts all programs in the lists by name and compatibility + items = sortBy( + items, + (program: ProgramData) => !program.compatible, + (program: ProgramData) => program.filedesc, + ); + if (!emagged) { // This filters the list to only contain verified programs - !emagged && filter((program: ProgramData) => program.verifiedsource === 1), - ])(programs); + items = filter(items, (program) => program.verifiedsource === 1); + } const disk_free_space = downloading ? disk_size - Number(toFixed(disk_used + downloadcompletion)) : disk_size - disk_used; diff --git a/tgui/packages/tgui/interfaces/Orbit/helpers.ts b/tgui/packages/tgui/interfaces/Orbit/helpers.ts index 8ad071c699b70..c0668dd02d8df 100644 --- a/tgui/packages/tgui/interfaces/Orbit/helpers.ts +++ b/tgui/packages/tgui/interfaces/Orbit/helpers.ts @@ -1,5 +1,4 @@ import { filter, sortBy } from 'common/collections'; -import { flow } from 'common/fp'; import { HEALTH, THREAT } from './constants'; import type { AntagGroup, Antagonist, Observable } from './types'; @@ -18,7 +17,7 @@ export const getAntagCategories = (antagonists: Antagonist[]) => { categories[antag_group].push(player); }); - return sortBy(([key]) => key)(Object.entries(categories)); + return sortBy(Object.entries(categories), ([key]) => key); }; /** Returns a disguised name in case the person is wearing someone else's ID */ @@ -43,15 +42,19 @@ export const getMostRelevant = ( searchQuery: string, observables: Observable[][], ): Observable => { - return flow([ - // Filters out anything that doesn't match search - filter((observable) => - isJobOrNameMatch(observable, searchQuery), - ), + const queriedObservables = // Sorts descending by orbiters - sortBy((observable) => -(observable.orbiters || 0)), - // Makes a single Observables list for an easy search - ])(observables.flat())[0]; + sortBy( + // Filters out anything that doesn't match search + filter( + observables + // Makes a single Observables list for an easy search + .flat(), + (observable) => isJobOrNameMatch(observable, searchQuery), + ), + (observable) => -(observable.orbiters || 0), + ); + return queriedObservables[0]; }; /** Returns the display color for certain health percentages */ diff --git a/tgui/packages/tgui/interfaces/Orbit/index.tsx b/tgui/packages/tgui/interfaces/Orbit/index.tsx index 0d992d981a81c..0103fe8750fb8 100644 --- a/tgui/packages/tgui/interfaces/Orbit/index.tsx +++ b/tgui/packages/tgui/interfaces/Orbit/index.tsx @@ -1,5 +1,4 @@ import { filter, sortBy } from 'common/collections'; -import { flow } from 'common/fp'; import { capitalizeFirst, multiline } from 'common/string'; import { useBackend, useLocalState } from 'tgui/backend'; import { @@ -204,16 +203,13 @@ const ObservableSection = (props: { const [searchQuery] = useLocalState('searchQuery', ''); - const filteredSection: Observable[] = flow([ - filter((observable) => - isJobOrNameMatch(observable, searchQuery), - ), - sortBy((observable) => + const filteredSection = sortBy( + filter(section, (observable) => isJobOrNameMatch(observable, searchQuery)), + (observable) => getDisplayName(observable.full_name, observable.name) .replace(/^"/, '') .toLowerCase(), - ), - ])(section); + ); if (!filteredSection.length) { return null; diff --git a/tgui/packages/tgui/interfaces/PersonalCrafting.tsx b/tgui/packages/tgui/interfaces/PersonalCrafting.tsx index 58ba4d81708bd..dce7491e98128 100644 --- a/tgui/packages/tgui/interfaces/PersonalCrafting.tsx +++ b/tgui/packages/tgui/interfaces/PersonalCrafting.tsx @@ -1,5 +1,4 @@ import { filter, sortBy } from 'common/collections'; -import { flow } from 'common/fp'; import { BooleanLike, classes } from 'common/react'; import { createSearch } from 'common/string'; import { useState } from 'react'; @@ -183,44 +182,44 @@ export const PersonalCrafting = (props) => { const [activeType, setFoodType] = useState( Object.keys(craftability).length ? 'Can Make' : data.foodtypes[0], ); - const material_occurences = flow([ - sortBy((material) => -material.occurences), - ])(data.material_occurences); + const material_occurences = sortBy( + data.material_occurences, + (material) => -material.occurences, + ); const [activeMaterial, setMaterial] = useState( material_occurences[0].atom_id, ); const [tabMode, setTabMode] = useState(0); const searchName = createSearch(searchText, (item: Recipe) => item.name); - let recipes = flow([ - filter( - (recipe) => - // If craftable only is selected, then filter by craftability - (!display_craftable_only || Boolean(craftability[recipe.ref])) && - // Ignore categories and types when searching - (searchText.length > 0 || - // Is foodtype mode and the active type matches - (tabMode === TABS.foodtype && - mode === MODE.cooking && - ((activeType === 'Can Make' && Boolean(craftability[recipe.ref])) || - recipe.foodtypes?.includes(activeType))) || - // Is material mode and the active material or catalysts match - (tabMode === TABS.material && - Object.keys(recipe.reqs).includes(activeMaterial)) || - // Is category mode and the active categroy matches - (tabMode === TABS.category && - ((activeCategory === 'Can Make' && - Boolean(craftability[recipe.ref])) || - recipe.category === activeCategory))), - ), - sortBy((recipe) => [ - activeCategory === 'Can Make' - ? 99 - Object.keys(recipe.reqs).length - : Number(craftability[recipe.ref]), - recipe.name.toLowerCase(), - ]), - ])(data.recipes); + let recipes = filter( + data.recipes, + (recipe) => + // If craftable only is selected, then filter by craftability + (!display_craftable_only || Boolean(craftability[recipe.ref])) && + // Ignore categories and types when searching + (searchText.length > 0 || + // Is foodtype mode and the active type matches + (tabMode === TABS.foodtype && + mode === MODE.cooking && + ((activeType === 'Can Make' && Boolean(craftability[recipe.ref])) || + recipe.foodtypes?.includes(activeType))) || + // Is material mode and the active material or catalysts match + (tabMode === TABS.material && + Object.keys(recipe.reqs).includes(activeMaterial)) || + // Is category mode and the active categroy matches + (tabMode === TABS.category && + ((activeCategory === 'Can Make' && + Boolean(craftability[recipe.ref])) || + recipe.category === activeCategory))), + ); + recipes = sortBy(recipes, (recipe) => [ + activeCategory === 'Can Make' + ? 99 - Object.keys(recipe.reqs).length + : Number(craftability[recipe.ref]), + recipe.name.toLowerCase(), + ]); if (searchText.length > 0) { - recipes = recipes.filter(searchName); + recipes = filter(recipes, searchName); } const canMake = ['Can Make']; const categories = canMake diff --git a/tgui/packages/tgui/interfaces/Photocopier.jsx b/tgui/packages/tgui/interfaces/Photocopier.jsx index 29353918e197b..e1b8b74bb0a16 100644 --- a/tgui/packages/tgui/interfaces/Photocopier.jsx +++ b/tgui/packages/tgui/interfaces/Photocopier.jsx @@ -178,7 +178,7 @@ const Blanks = (props) => { const { act, data } = useBackend(); const { blanks, categories, category } = data; - const sortedBlanks = sortBy((blank) => blank.name)(blanks || []); + const sortedBlanks = sortBy(blanks || [], (blank) => blank.name); const selectedCategory = category ?? categories[0]; const visibleBlanks = sortedBlanks.filter( diff --git a/tgui/packages/tgui/interfaces/PlaneMasterDebug.tsx b/tgui/packages/tgui/interfaces/PlaneMasterDebug.tsx index b045304c4cabd..1a623bb20795a 100644 --- a/tgui/packages/tgui/interfaces/PlaneMasterDebug.tsx +++ b/tgui/packages/tgui/interfaces/PlaneMasterDebug.tsx @@ -158,7 +158,7 @@ const sortConnectionRefs = function ( direction: ConnectionDirection, connectSources: AssocConnected, ) { - refs = sortBy((connection: ConnectionRef) => connection.sort_by)(refs); + refs = sortBy(refs, (connection: ConnectionRef) => connection.sort_by); refs.map((connection, index) => { let connectSource = connectSources[connection.ref]; if (direction === ConnectionDirection.Outgoing) { @@ -264,14 +264,15 @@ const positionPlanes = (connectSources: AssocConnected) => { // and get rid of the now unneeded parent refs const stack = depth_stack.map((layer) => flow([ - sortBy((plane: string) => plane_info[plane].plane), - sortBy((plane: string) => { - const read_from = plane_info[layer[plane]]; - if (!read_from) { - return 0; - } - return read_from.plane; - }), + (planes) => sortBy(planes, (plane: string) => plane_info[plane].plane), + (planes) => + sortBy(planes, (plane: string) => { + const read_from = plane_info[layer[plane]]; + if (!read_from) { + return 0; + } + return read_from.plane; + }), ])(Object.keys(layer)), ); @@ -932,7 +933,7 @@ const AddModal = (props) => { ); const plane_list = Object.keys(plane_info).map((plane) => plane_info[plane]); - const planes = sortBy((plane: Plane) => -plane.plane)(plane_list); + const planes = sortBy(plane_list, (plane: Plane) => -plane.plane); const plane_options = planes.map((plane) => plane.name); diff --git a/tgui/packages/tgui/interfaces/PortableChemMixer.tsx b/tgui/packages/tgui/interfaces/PortableChemMixer.tsx index fc0b4cbb95e79..9ffbe06b94392 100644 --- a/tgui/packages/tgui/interfaces/PortableChemMixer.tsx +++ b/tgui/packages/tgui/interfaces/PortableChemMixer.tsx @@ -26,8 +26,9 @@ export const PortableChemMixer = (props) => { const { act, data } = useBackend(); const { beaker } = data; const beakerTransferAmounts = beaker ? beaker.transferAmounts : []; - const chemicals = sortBy((chem: DispensableReagent) => chem.id)( + const chemicals = sortBy( data.chemicals, + (chem: DispensableReagent) => chem.id, ); return ( diff --git a/tgui/packages/tgui/interfaces/PowerMonitor.jsx b/tgui/packages/tgui/interfaces/PowerMonitor.jsx index 6e0e0dca173a4..039e700f68cea 100644 --- a/tgui/packages/tgui/interfaces/PowerMonitor.jsx +++ b/tgui/packages/tgui/interfaces/PowerMonitor.jsx @@ -48,18 +48,22 @@ export const PowerMonitorContent = (props) => { const maxValue = Math.max(PEAK_DRAW, ...history.supply, ...history.demand); // Process area data const areas = flow([ - map((area, i) => ({ - ...area, - // Generate a unique id - id: area.name + i, - })), - sortByField === 'name' && sortBy((area) => area.name), - sortByField === 'charge' && sortBy((area) => -area.charge), + (areas) => + map(areas, (area, i) => ({ + ...area, + // Generate a unique id + id: area.name + i, + })), + sortByField === 'name' && ((areas) => sortBy(areas, (area) => area.name)), + sortByField === 'charge' && + ((areas) => sortBy(areas, (area) => -area.charge)), sortByField === 'draw' && - sortBy( - (area) => -powerRank(area.load), - (area) => -parseFloat(area.load), - ), + ((areas) => + sortBy( + areas, + (area) => -powerRank(area.load), + (area) => -parseFloat(area.load), + )), ])(data.areas); return ( <> diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/AntagsPage.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/AntagsPage.tsx index 2ff85058da62f..c00889536e0dc 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/AntagsPage.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/AntagsPage.tsx @@ -25,9 +25,10 @@ const antagsByCategory = new Map(); // This will break at priorities higher than 10, but that almost definitely // will not happen. -const binaryInsertAntag = binaryInsertWith((antag: Antagonist) => { - return `${antag.priority}_${antag.name}`; -}); +const binaryInsertAntag = (collection: Antagonist[], value: Antagonist) => + binaryInsertWith(collection, value, (antag) => { + return `${antag.priority}_${antag.name}`; + }); for (const antagKey of requireAntag.keys()) { const antag = requireAntag<{ diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/GamePreferencesPage.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/GamePreferencesPage.tsx index 05845ffe54899..ad81b2c27fd5b 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/GamePreferencesPage.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/GamePreferencesPage.tsx @@ -13,11 +13,13 @@ type PreferenceChild = { children: ReactNode; }; -const binaryInsertPreference = binaryInsertWith( - (child) => child.name, -); +const binaryInsertPreference = ( + collection: PreferenceChild[], + value: PreferenceChild, +) => binaryInsertWith(collection, value, (child) => child.name); -const sortByName = sortBy<[string, PreferenceChild[]]>(([name]) => name); +const sortByName = (array: [string, PreferenceChild[]][]) => + sortBy(array, ([name]) => name); export const GamePreferencesPage = (props) => { const { act, data } = useBackend(); diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/JobsPage.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/JobsPage.tsx index 7df2acc06e389..27d0e73833ca1 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/JobsPage.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/JobsPage.tsx @@ -14,10 +14,11 @@ import { import { ServerPreferencesFetcher } from './ServerPreferencesFetcher'; const sortJobs = (entries: [string, Job][], head?: string) => - sortBy<[string, Job]>( + sortBy( + entries, ([key, _]) => (key === head ? -1 : 1), ([key, _]) => key, - )(entries); + ); const PRIORITY_BUTTON_SIZE = '18px'; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/KeybindingsPage.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/KeybindingsPage.tsx index d8c2bccc61c40..32d39c287df94 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/KeybindingsPage.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/KeybindingsPage.tsx @@ -67,15 +67,14 @@ const KEY_CODE_TO_BYOND: Record = { */ const DOM_KEY_LOCATION_NUMPAD = 3; -const sortKeybindings = sortBy(([_, keybinding]: [string, Keybinding]) => { - return keybinding.name; -}); - -const sortKeybindingsByCategory = sortBy( - ([category, _]: [string, Record]) => { - return category; - }, -); +const sortKeybindings = (array: [string, Keybinding][]) => + sortBy(array, ([_, keybinding]) => { + return keybinding.name; + }); + +const sortKeybindingsByCategory = ( + array: [string, Record][], +) => sortBy(array, ([category, _]) => category); const formatKeyboardEvent = (event: KeyboardEvent): string => { let text = ''; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/MainPage.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/MainPage.tsx index dbb31c73cbb8b..c79827d2abe74 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/MainPage.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/MainPage.tsx @@ -1,10 +1,8 @@ -import { filterMap, sortBy } from 'common/collections'; +import { filter, map, sortBy } from 'common/collections'; import { classes } from 'common/react'; +import { createSearch } from 'common/string'; import { useState } from 'react'; -import { filter } from '../../../common/collections'; -import { flow } from '../../../common/fp'; -import { createSearch } from '../../../common/string'; import { sendAct, useBackend } from '../../backend'; import { Autofocus, @@ -202,8 +200,14 @@ const ChoicedSelection = (props: { }; const searchInCatalog = (searchText = '', catalog: Record) => { - const maybeSearch = createSearch(searchText, ([name, _icon]) => name); - return flow([searchText && filter(maybeSearch)])(Object.entries(catalog)); + let items = Object.entries(catalog); + if (searchText) { + items = filter( + items, + createSearch(searchText, ([name, _icon]) => name), + ); + } + return items; }; const GenderButton = (props: { @@ -368,10 +372,11 @@ const createSetRandomization = }); }; -const sortPreferences = sortBy<[string, unknown]>(([featureId, _]) => { - const feature = features[featureId]; - return feature?.name; -}); +const sortPreferences = (array: [string, unknown][]) => + sortBy(array, ([featureId, _]) => { + const feature = features[featureId]; + return feature?.name; + }); export const PreferenceList = (props: { act: typeof sendAct; @@ -451,22 +456,20 @@ export const getRandomization = ( const { data } = useBackend(); - return Object.fromEntries( - filterMap(Object.keys(preferences), (preferenceKey) => { - if (serverData.random.randomizable.indexOf(preferenceKey) === -1) { - return undefined; - } - - if (!randomBodyEnabled) { - return undefined; - } + if (!randomBodyEnabled) { + return {}; + } - return [ - preferenceKey, - data.character_preferences.randomization[preferenceKey] || - RandomSetting.Disabled, - ]; - }), + return Object.fromEntries( + map( + filter(Object.keys(preferences), (key) => + serverData.random.randomizable.includes(key), + ), + (key) => [ + key, + data.character_preferences.randomization[key] || RandomSetting.Disabled, + ], + ), ); }; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/QuirksPage.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/QuirksPage.tsx index c145b7eb3db34..2dde5ab60cc5a 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/QuirksPage.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/QuirksPage.tsx @@ -1,4 +1,4 @@ -import { filterMap } from 'common/collections'; +import { filter } from 'common/collections'; import { useState } from 'react'; import { useBackend } from '../../backend'; @@ -23,13 +23,9 @@ function getCorrespondingPreferences( relevant_preferences: Record, ) { return Object.fromEntries( - filterMap(Object.keys(relevant_preferences), (key) => { - if (!customization_options.includes(key)) { - return undefined; - } - - return [key, relevant_preferences[key]]; - }), + filter(Object.entries(relevant_preferences), ([key, value]) => + customization_options.includes(key), + ), ); } diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/names.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/names.tsx index eadb6e94d4291..039fb8027ad68 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/names.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/names.tsx @@ -21,9 +21,11 @@ type NameWithKey = { name: Name; }; -const binaryInsertName = binaryInsertWith(({ key }) => key); +const binaryInsertName = (collection: NameWithKey[], value: NameWithKey) => + binaryInsertWith(collection, value, ({ key }) => key); -const sortNameWithKeyEntries = sortBy<[string, NameWithKey[]]>(([key]) => key); +const sortNameWithKeyEntries = (array: [string, NameWithKey[]][]) => + sortBy(array, ([key]) => key); export const MultiNameInput = (props: { handleClose: () => void; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/base.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/base.tsx index f481c129d2886..8878292e6575d 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/base.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/base.tsx @@ -1,4 +1,4 @@ -import { sortBy, sortStrings } from 'common/collections'; +import { sort, sortBy } from 'common/collections'; import { BooleanLike, classes } from 'common/react'; import { ComponentType, @@ -21,7 +21,8 @@ import { import { createSetPreference, PreferencesMenuData } from '../../data'; import { ServerPreferencesFetcher } from '../../ServerPreferencesFetcher'; -export const sortChoices = sortBy<[string, ReactNode]>(([name]) => name); +export const sortChoices = (array: [string, ReactNode][]) => + sortBy(array, ([name]) => name); export type Feature< TReceiving, @@ -209,7 +210,7 @@ export const FeatureDropdownInput = ( return ( ; }; -const sortHexValues = sortBy<[string, HexValue]>( - ([_, hexValue]) => -hexValue.lightness, -); +const sortHexValues = (array: [string, HexValue][]) => + sortBy(array, ([_, hexValue]) => -hexValue.lightness); export const skin_tone: Feature = { name: 'Skin tone', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/ghost.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/ghost.tsx index cfa323dce2c69..ab973e3659e35 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/ghost.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/ghost.tsx @@ -22,10 +22,13 @@ export const ghost_accs: FeatureChoiced = { component: FeatureDropdownInput, }; -const insertGhostForm = binaryInsertWith<{ +type GhostForm = { displayText: ReactNode; value: string; -}>(({ value }) => value); +}; + +const insertGhostForm = (collection: GhostForm[], value: GhostForm) => + binaryInsertWith(collection, value, ({ value }) => value); const GhostFormInput = ( props: FeatureValueProps, diff --git a/tgui/packages/tgui/interfaces/Radio.jsx b/tgui/packages/tgui/interfaces/Radio.jsx index d25409e033ada..d852149571a21 100644 --- a/tgui/packages/tgui/interfaces/Radio.jsx +++ b/tgui/packages/tgui/interfaces/Radio.jsx @@ -23,10 +23,10 @@ export const Radio = (props) => { const tunedChannel = RADIO_CHANNELS.find( (channel) => channel.freq === frequency, ); - const channels = map((value, key) => ({ + const channels = map(data.channels, (value, key) => ({ name: key, status: !!value, - }))(data.channels); + })); // Calculate window height let height = 106; if (subspace) { diff --git a/tgui/packages/tgui/interfaces/RequestsConsole/MessageWriteTab.tsx b/tgui/packages/tgui/interfaces/RequestsConsole/MessageWriteTab.tsx index 5195c451838f6..117df20b8c0fd 100644 --- a/tgui/packages/tgui/interfaces/RequestsConsole/MessageWriteTab.tsx +++ b/tgui/packages/tgui/interfaces/RequestsConsole/MessageWriteTab.tsx @@ -1,4 +1,4 @@ -import { sortStrings } from 'common/collections'; +import { sort } from 'common/collections'; import { useState } from 'react'; import { useBackend, useLocalState } from '../../backend'; @@ -22,9 +22,9 @@ export const MessageWriteTab = (props) => { information_consoles = [], } = data; - const sorted_assistance = sortStrings(assistance_consoles); - const sorted_supply = sortStrings(supply_consoles); - const sorted_information = sortStrings(information_consoles); + const sorted_assistance = sort(assistance_consoles); + const sorted_supply = sort(supply_consoles); + const sorted_information = sort(information_consoles); const resetMessage = () => { setMessageText(''); diff --git a/tgui/packages/tgui/interfaces/RestockTracker.jsx b/tgui/packages/tgui/interfaces/RestockTracker.jsx index 236f486069cb5..7df606adffcd3 100644 --- a/tgui/packages/tgui/interfaces/RestockTracker.jsx +++ b/tgui/packages/tgui/interfaces/RestockTracker.jsx @@ -17,8 +17,9 @@ export const Restock = (props) => { export const RestockTracker = (props) => { const { data } = useBackend(); - const vending_list = sortBy((vend) => vend.percentage)( + const vending_list = sortBy( data.vending_list ?? [], + (vend) => vend.percentage, ); return (
    diff --git a/tgui/packages/tgui/interfaces/SecurityRecords/RecordTabs.tsx b/tgui/packages/tgui/interfaces/SecurityRecords/RecordTabs.tsx index 492321b3d3a07..a00f4a3be1477 100644 --- a/tgui/packages/tgui/interfaces/SecurityRecords/RecordTabs.tsx +++ b/tgui/packages/tgui/interfaces/SecurityRecords/RecordTabs.tsx @@ -1,5 +1,4 @@ import { filter, sortBy } from 'common/collections'; -import { flow } from 'common/fp'; import { useState } from 'react'; import { useBackend, useLocalState } from 'tgui/backend'; import { @@ -29,10 +28,10 @@ export const SecurityRecordTabs = (props) => { const [search, setSearch] = useState(''); - const sorted: SecurityRecord[] = flow([ - filter((record: SecurityRecord) => isRecordMatch(record, search)), - sortBy((record: SecurityRecord) => record.name), - ])(records); + const sorted = sortBy( + filter(records, (record) => isRecordMatch(record, search)), + (record) => record.name, + ); return ( diff --git a/tgui/packages/tgui/interfaces/SeedExtractor.tsx b/tgui/packages/tgui/interfaces/SeedExtractor.tsx index 3c05b3d0498e9..87955da243f5b 100644 --- a/tgui/packages/tgui/interfaces/SeedExtractor.tsx +++ b/tgui/packages/tgui/interfaces/SeedExtractor.tsx @@ -1,5 +1,4 @@ import { sortBy } from 'common/collections'; -import { flow } from 'common/fp'; import { classes } from 'common/react'; import { createSearch } from 'common/string'; import { useState } from 'react'; @@ -67,9 +66,10 @@ export const SeedExtractor = (props) => { const search = createSearch(searchText, (item: SeedData) => item.name); const seeds_filtered = searchText.length > 0 ? data.seeds.filter(search) : data.seeds; - const seeds = flow([ - sortBy((item: SeedData) => item[sortField as keyof SeedData]), - ])(seeds_filtered || []); + const seeds = sortBy( + seeds_filtered || [], + (item: SeedData) => item[sortField as keyof SeedData], + ); sortField !== 'name' && seeds.reverse(); return ( diff --git a/tgui/packages/tgui/interfaces/SelectEquipment.jsx b/tgui/packages/tgui/interfaces/SelectEquipment.jsx index d43d28961e216..d8df6c71e7c35 100644 --- a/tgui/packages/tgui/interfaces/SelectEquipment.jsx +++ b/tgui/packages/tgui/interfaces/SelectEquipment.jsx @@ -1,5 +1,4 @@ import { filter, map, sortBy, uniq } from 'common/collections'; -import { flow } from 'common/fp'; import { createSearch } from 'common/string'; import { useState } from 'react'; @@ -30,10 +29,10 @@ export const SelectEquipment = (props) => { const isFavorited = (entry) => favorites?.includes(entry.path); - const outfits = map((entry) => ({ + const outfits = map([...data.outfits, ...data.custom_outfits], (entry) => ({ ...entry, favorite: isFavorited(entry), - }))([...data.outfits, ...data.custom_outfits]); + })); // even if no custom outfits were sent, we still want to make sure there's // at least a 'Custom' tab so the button to create a new one pops up @@ -49,15 +48,15 @@ export const SelectEquipment = (props) => { (entry) => entry.name + entry.path, ); - const visibleOutfits = flow([ - filter((entry) => entry.category === tab), - filter(searchFilter), - sortBy( - (entry) => !entry.favorite, - (entry) => !entry.priority, - (entry) => entry.name, + const visibleOutfits = sortBy( + filter( + filter(outfits, (entry) => entry.category === tab), + searchFilter, ), - ])(outfits); + (entry) => !entry.favorite, + (entry) => !entry.priority, + (entry) => entry.name, + ); const getOutfitEntry = (current_outfit) => outfits.find((outfit) => getOutfitKey(outfit) === current_outfit); diff --git a/tgui/packages/tgui/interfaces/ShuttleManipulator.jsx b/tgui/packages/tgui/interfaces/ShuttleManipulator.jsx index e64f47086cdc4..8cff913e8e93e 100644 --- a/tgui/packages/tgui/interfaces/ShuttleManipulator.jsx +++ b/tgui/packages/tgui/interfaces/ShuttleManipulator.jsx @@ -104,7 +104,7 @@ export const ShuttleManipulatorTemplates = (props) => { - {map((template, templateId) => ( + {map(templateObject, (template, templateId) => ( { > {template.port_id} - ))(templateObject)} + ))} diff --git a/tgui/packages/tgui/interfaces/StackCrafting.tsx b/tgui/packages/tgui/interfaces/StackCrafting.tsx index 255d8f501f1b1..7395306c11a35 100644 --- a/tgui/packages/tgui/interfaces/StackCrafting.tsx +++ b/tgui/packages/tgui/interfaces/StackCrafting.tsx @@ -1,5 +1,3 @@ -import { filter, map, reduce, sortBy } from 'common/collections'; -import { flow } from 'common/fp'; import { clamp } from 'common/math'; import { createSearch } from 'common/string'; import { useState } from 'react'; @@ -49,8 +47,7 @@ type RecipeBoxProps = { }; // RecipeList converted via Object.entries() for filterRecipeList -type RecipeListEntry = [string, RecipeList | Recipe]; -type RecipeListFilterableEntry = [string, RecipeList | Recipe | undefined]; +type RecipeListFilterableEntry = [string, RecipeList | Recipe]; /** * Type guard for recipe vs recipe list @@ -70,30 +67,29 @@ function isRecipeList(value: Recipe | RecipeList): value is RecipeList { const filterRecipeList = ( list: RecipeList, keyFilter: (key: string) => boolean, -) => { - const filteredList: RecipeList = flow([ - map((entry: RecipeListEntry): RecipeListFilterableEntry => { - const [key, recipe] = entry; +): RecipeList | undefined => { + const filteredList = Object.fromEntries( + Object.entries(list) + .flatMap((entry): RecipeListFilterableEntry[] => { + const [key, recipe] = entry; - if (isRecipeList(recipe)) { // If category name matches, return the whole thing. if (keyFilter(key)) { - return entry; + return [entry]; } - // otherwise, filter sub-entries. - return [key, filterRecipeList(recipe, keyFilter)]; - } - - return keyFilter(key) ? entry : [key, undefined]; - }), - filter((entry: RecipeListFilterableEntry) => entry[1] !== undefined), - sortBy((entry: RecipeListEntry) => entry[0].toLowerCase()), - reduce((obj: RecipeList, entry: RecipeListEntry) => { - obj[entry[0]] = entry[1]; - return obj; - }, {}), - ])(Object.entries(list)); + if (isRecipeList(recipe)) { + // otherwise, filter sub-entries. + const subEntries = filterRecipeList(recipe, keyFilter); + if (subEntries !== undefined) { + return [[key, subEntries]]; + } + } + + return []; + }) + .sort(([a], [b]) => (a < b ? -1 : a !== b ? 1 : 0)), + ); return Object.keys(filteredList).length ? filteredList : undefined; }; diff --git a/tgui/packages/tgui/interfaces/StationAlertConsole.jsx b/tgui/packages/tgui/interfaces/StationAlertConsole.jsx index f80a5826b0641..c4ff6812955f5 100644 --- a/tgui/packages/tgui/interfaces/StationAlertConsole.jsx +++ b/tgui/packages/tgui/interfaces/StationAlertConsole.jsx @@ -1,5 +1,4 @@ import { sortBy } from 'common/collections'; -import { flow } from 'common/fp'; import { useBackend } from '../backend'; import { Button, Section, Stack } from '../components'; @@ -30,8 +29,9 @@ export const StationAlertConsoleContent = (props) => { Camera: 5, }; - const sortedAlarms = flow([sortBy((alarm) => sortingKey[alarm.name])])( + const sortedAlarms = sortBy( data.alarms || [], + (alarm) => sortingKey[alarm.name], ); return ( diff --git a/tgui/packages/tgui/interfaces/StationTraitsPanel.tsx b/tgui/packages/tgui/interfaces/StationTraitsPanel.tsx index f3176415a4f8b..e6e7b02ce674b 100644 --- a/tgui/packages/tgui/interfaces/StationTraitsPanel.tsx +++ b/tgui/packages/tgui/interfaces/StationTraitsPanel.tsx @@ -1,4 +1,4 @@ -import { filterMap } from 'common/collections'; +import { filter, map } from 'common/collections'; import { exhaustiveCheck } from 'common/exhaustive'; import { BooleanLike } from 'common/react'; import { useState } from 'react'; @@ -110,15 +110,9 @@ const FutureStationTraitsPage = (props) => { icon="times" onClick={() => { act('setup_future_traits', { - station_traits: filterMap( - future_station_traits, - (otherTrait) => { - if (otherTrait.path === trait.path) { - return undefined; - } else { - return otherTrait.path; - } - }, + station_traits: filter( + map(future_station_traits, (t) => t.path), + (p) => p !== trait.path, ), }); }} diff --git a/tgui/packages/tgui/interfaces/Supermatter.tsx b/tgui/packages/tgui/interfaces/Supermatter.tsx index 9bb8661ca2970..35d176db6cdc1 100644 --- a/tgui/packages/tgui/interfaces/Supermatter.tsx +++ b/tgui/packages/tgui/interfaces/Supermatter.tsx @@ -1,5 +1,4 @@ import { filter, sortBy } from 'common/collections'; -import { flow } from 'common/fp'; import { toFixed } from 'common/math'; import { BooleanLike } from 'common/react'; import { ReactNode, useState } from 'react'; @@ -123,10 +122,14 @@ export const SupermatterContent = (props: SupermatterProps) => { gas_metadata, } = props; const [allGasActive, setAllGasActive] = useState(false); - const gas_composition: [gas_path: string, amount: number][] = flow([ - !allGasActive && filter(([gas_path, amount]) => amount !== 0), - sortBy(([gas_path, amount]) => -amount), - ])(Object.entries(props.gas_composition)); + let gas_composition = Object.entries(props.gas_composition); + if (!allGasActive) { + gas_composition = filter( + gas_composition, + ([gas_path, amount]) => amount !== 0, + ); + } + gas_composition = sortBy(gas_composition, ([gas_path, amount]) => -amount); return ( diff --git a/tgui/packages/tgui/interfaces/SurgeryInitiator.tsx b/tgui/packages/tgui/interfaces/SurgeryInitiator.tsx index f48915068d928..62d71d614db2e 100644 --- a/tgui/packages/tgui/interfaces/SurgeryInitiator.tsx +++ b/tgui/packages/tgui/interfaces/SurgeryInitiator.tsx @@ -19,7 +19,8 @@ type SurgeryInitiatorData = { target_name: string; }; -const sortSurgeries = sortBy((surgery: Surgery) => surgery.name); +const sortSurgeries = (array: Surgery[]) => + sortBy(array, (surgery) => surgery.name); type SurgeryInitiatorInnerState = { selectedSurgeryIndex: number; diff --git a/tgui/packages/tgui/interfaces/Techweb.jsx b/tgui/packages/tgui/interfaces/Techweb.jsx index 96b52983adee9..4328cc01b898a 100644 --- a/tgui/packages/tgui/interfaces/Techweb.jsx +++ b/tgui/packages/tgui/interfaces/Techweb.jsx @@ -1,4 +1,4 @@ -import { map, sortBy } from 'common/collections'; +import { sortBy } from 'common/collections'; import { useState } from 'react'; import { useBackend, useLocalState } from '../backend'; @@ -41,9 +41,9 @@ const selectRemappedStaticData = (data) => { ...node, id: remapId(id), costs, - prereq_ids: map(remapId)(node.prereq_ids || []), - design_ids: map(remapId)(node.design_ids || []), - unlock_ids: map(remapId)(node.unlock_ids || []), + prereq_ids: map(node.prereq_ids || [], remapId), + design_ids: map(node.design_ids || [], remapId), + unlock_ids: map(node.unlock_ids || [], remapId), required_experiments: node.required_experiments || [], discount_experiments: node.discount_experiments || [], }; @@ -251,10 +251,11 @@ const TechwebOverview = (props) => { ); }); } else { - displayedNodes = sortBy((x) => node_cache[x.id].name)( + displayedNodes = sortBy( tabIndex < 2 ? nodes.filter((x) => x.tier === tabIndex) : nodes.filter((x) => x.tier >= tabIndex), + (x) => node_cache[x.id].name, ); } diff --git a/tgui/packages/tgui/interfaces/TrackedPlaytime.jsx b/tgui/packages/tgui/interfaces/TrackedPlaytime.jsx index 3f1a3dcb543e2..f59b01b8b5d31 100644 --- a/tgui/packages/tgui/interfaces/TrackedPlaytime.jsx +++ b/tgui/packages/tgui/interfaces/TrackedPlaytime.jsx @@ -7,7 +7,7 @@ import { Window } from '../layouts'; const JOB_REPORT_MENU_FAIL_REASON_TRACKING_DISABLED = 1; const JOB_REPORT_MENU_FAIL_REASON_NO_RECORDS = 2; -const sortByPlaytime = sortBy(([_, playtime]) => -playtime); +const sortByPlaytime = (array) => sortBy(array, ([_, playtime]) => -playtime); const PlaytimeSection = (props) => { const { playtimes } = props; diff --git a/tgui/packages/tgui/interfaces/WarrantConsole.tsx b/tgui/packages/tgui/interfaces/WarrantConsole.tsx index 14415b3ee79d1..a87de8e017cba 100644 --- a/tgui/packages/tgui/interfaces/WarrantConsole.tsx +++ b/tgui/packages/tgui/interfaces/WarrantConsole.tsx @@ -63,7 +63,7 @@ export const WarrantConsole = (props) => { const RecordList = (props) => { const { act, data } = useBackend(); const { records = [] } = data; - const sorted = sortBy((record: WarrantRecord) => record.crew_name)(records); + const sorted = sortBy(records, (record) => record.crew_name); const [selectedRecord, setSelectedRecord] = useLocalState< WarrantRecord | undefined diff --git a/tgui/packages/tgui/interfaces/common/AccessConfig.tsx b/tgui/packages/tgui/interfaces/common/AccessConfig.tsx index 99f783dbdbc3d..766a6724d77a4 100644 --- a/tgui/packages/tgui/interfaces/common/AccessConfig.tsx +++ b/tgui/packages/tgui/interfaces/common/AccessConfig.tsx @@ -72,8 +72,9 @@ export function AccessConfig(props: ConfigProps) { accesses.find((access) => access.name === selectedAccessName) || accesses[0]; - const selectedAccessEntries = sortBy((entry: Area) => entry.desc)( + const selectedAccessEntries = sortBy( selectedAccess?.accesses || [], + (entry: Area) => entry.desc, ); function checkAccessIcon(accesses: Area[]) { diff --git a/tgui/packages/tgui/interfaces/common/AccessList.jsx b/tgui/packages/tgui/interfaces/common/AccessList.jsx index a4096b6ce3051..9ac1fe913b3af 100644 --- a/tgui/packages/tgui/interfaces/common/AccessList.jsx +++ b/tgui/packages/tgui/interfaces/common/AccessList.jsx @@ -248,8 +248,9 @@ const RegionAccessList = (props) => { const selectedAccess = accesses.find( (access) => access.name === selectedAccessName, ); - const selectedAccessEntries = sortBy((entry) => entry.desc)( + const selectedAccessEntries = sortBy( selectedAccess?.accesses || [], + (entry) => entry.desc, ); const allWildcards = Object.keys(wildcardSlots); From 6596d75edcd0b00bde9a6cf238f327e460be8a7a Mon Sep 17 00:00:00 2001 From: Jacquerel Date: Thu, 18 Apr 2024 16:05:06 +0100 Subject: [PATCH 318/938] Gulag Adjustments Two (#82561) ## About The Pull Request I have received feedback that after the prior changes in #81971, the gulag is still a little bit too subject to RNG. The main culprit (as in my previous PR) is Iron being kind of cheap and the fact that unlike the old Gulag you no longer have any way of headhunting more valuable materials (everything appears as boulders on your ore scanner). My solution to this is wider than the last one of tweaking point values, but also much simpler: Just make every boulder you mine be worth the same amount of points regardless of what is inside of it. On the average test I made I could comfortably mine about 40-45 boulders in ten minutes. We'll make some adjustments to that rather than leaving 40 as the target number; Most players upon being teleported to the gulag are going to spend a few minutes whining and bemoaning their fate instead of getting straight to work. I had the benefit of being able to make sure my run started as soon as a storm ended so I wouldn't need any kind of midpoint break. I was also always the only person playing on my local instance, there hadn't been any other pesky prisoners before me who had already mined out all the nearest available deposits. And of course, let us not forget, I am an MLG master league ss13 player who was surely performing well above average. So we'll round that down to: Each boulder is worth 33 points, meaning you need to collect 31 boulders to complete a 1000 point (roughly ten minute) sentence. How do I ensure that every boulder is worth the same amount of points? Well it's pretty easy. One boulder = one material sheet. One material sheet = 33 points. Simple. "Now Jacquerel", I hear you not saying because you don't want me to know about this thing you would prefer to do instead of hitting rocks outside; "if I simply smash all of the tables and microwaves and botany trays and bed in the gulag I can easily get like 65 sheets of Iron, which is almost enough to buy the freedom for two entire people!" Unfortunately I knew you were going to try and do that and the prisoner point machine will only give you points for material sheets which have been printed from the material smelter (well, any material smelter actually but you should probably use the one in the gulag). You'll be able to tell because if you examine a valid material sheet it will mention a little maker's mark on it, which is absent in the beat-up iron that you get from smashing furniture to bits. Also glass is worth 0 points. Don't waste time digging up that shit. As glass has had all of its point value removed, I have added a "work pit" to the gulag to compensate. You can pull boulders out of this indefinitely via effort, however it also stamcrits you every time. It's not very fun to do this, but that's because I would prefer you to go find the rocks out in the field instead. This is a last resort. You can do this if there's no boulders left to mine or if you really really really hate mining and would rather very slowly click on one tile repeatedly to get your boulders instead. As a tiny bonus doing this gives workout experience. This isn't a totally ideal solution but I think it'll do for now. ## Why It's Good For The Game What we want out of the gulag is: - Something where officers can vaguely approximate an expected sentence duration. - A task that requires players to actually be spending that time doing something to get out of here. - Produces at least some amount of useful materials. In I think roughly that order. I hope this change accomplishes all three of these in a way that is somewhat predictable rather than throwing darts at a board. ## Changelog :cl: balance: Gulag mining has been rebalanced so that every boulder is worth the same amount of points to mine for a prisoner regardless of what it contains, and should be more consistent. add: A vent which boulders can be hauled out of by hand has been added to the gulag which you can use if there's nothing left to mine. It is very slow, but at least it gives you a workout... /:cl: --- .../map_files/IceBoxStation/IceBoxStation.dmm | 206 +++++++++--------- _maps/map_files/Mining/Lavaland.dmm | 8 +- .../components/material/material_container.dm | 1 + code/game/objects/items/stacks/bscrystal.dm | 2 +- .../game/objects/items/stacks/sheets/glass.dm | 4 +- .../objects/items/stacks/sheets/mineral.dm | 20 +- .../items/stacks/sheets/sheet_types.dm | 4 +- .../objects/items/stacks/sheets/sheets.dm | 18 +- .../objects/structures/lavaland/gulag_vent.dm | 42 ++++ code/modules/jobs/job_types/prisoner.dm | 4 +- .../boulder_processing/boulder_types.dm | 4 +- code/modules/mining/laborcamp/laborstacker.dm | 22 +- code/modules/mining/machine_processing.dm | 12 +- code/modules/mining/machine_stacking.dm | 18 +- tgstation.dme | 1 + .../tgui/interfaces/LaborClaimConsole.jsx | 27 +-- 16 files changed, 222 insertions(+), 171 deletions(-) create mode 100644 code/game/objects/structures/lavaland/gulag_vent.dm diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index 838f1c92e7a85..0280110ed5ac2 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -1853,6 +1853,16 @@ /obj/structure/extinguisher_cabinet/directional/south, /turf/open/floor/iron/white, /area/station/science/robotics/lab) +"aEK" = ( +/obj/machinery/atmospherics/components/binary/pump/off, +/obj/machinery/airlock_sensor/incinerator_ordmix{ + pixel_x = 24 + }, +/obj/machinery/atmospherics/pipe/layer_manifold/supply/hidden{ + dir = 4 + }, +/turf/open/floor/engine, +/area/station/science/ordnance) "aEM" = ( /obj/structure/sign/departments/cargo, /turf/closed/wall/r_wall, @@ -4336,6 +4346,10 @@ }, /turf/open/floor/iron/dark, /area/station/service/hydroponics) +"bqX" = ( +/obj/machinery/air_sensor/ordnance_burn_chamber, +/turf/open/floor/engine/vacuum, +/area/station/science/ordnance) "bqY" = ( /obj/structure/closet, /obj/effect/spawner/random/maintenance/two, @@ -8226,6 +8240,10 @@ /obj/machinery/light/small/directional/west, /turf/open/floor/wood, /area/station/commons/vacant_room/office) +"cuB" = ( +/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/ordnance_burn_chamber_input, +/turf/open/floor/engine/vacuum, +/area/station/science/ordnance) "cuJ" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 4 @@ -12640,12 +12658,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply, /turf/open/floor/iron/dark, /area/station/medical/virology) -"dJk" = ( -/obj/machinery/atmospherics/components/binary/dp_vent_pump/high_volume/incinerator_ordmix{ - dir = 8 - }, -/turf/open/floor/engine, -/area/station/science/ordnance) "dJx" = ( /obj/structure/cable, /obj/effect/spawner/structure/window/reinforced, @@ -14903,6 +14915,10 @@ "evb" = ( /turf/open/floor/iron, /area/station/service/janitor) +"evc" = ( +/obj/machinery/atmospherics/components/unary/vent_scrubber/on, +/turf/open/floor/engine/vacuum, +/area/station/science/ordnance) "evk" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -16600,7 +16616,7 @@ /turf/open/floor/iron/white, /area/station/medical/medbay/central) "eYz" = ( -/obj/machinery/mineral/processing_unit{ +/obj/machinery/mineral/processing_unit/gulag{ dir = 1 }, /obj/effect/decal/cleanable/dirt, @@ -18366,6 +18382,10 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/station/medical/medbay/lobby) +"fCS" = ( +/obj/machinery/door/poddoor/incinerator_ordmix, +/turf/open/floor/engine/vacuum, +/area/station/science/ordnance) "fCW" = ( /obj/structure/extinguisher_cabinet/directional/east, /turf/open/floor/iron/dark/textured, @@ -19319,10 +19339,6 @@ /obj/structure/sign/warning/electric_shock/directional/east, /turf/open/floor/iron, /area/station/hallway/primary/central) -"fSG" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/closed/wall/r_wall, -/area/station/science/ordnance) "fTb" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -22767,10 +22783,6 @@ /obj/structure/cable, /turf/open/floor/iron/dark, /area/station/security/interrogation) -"gWZ" = ( -/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/ordnance_burn_chamber_input, -/turf/open/floor/engine/vacuum, -/area/station/science/ordnance) "gXe" = ( /obj/effect/turf_decal/siding/white{ dir = 4 @@ -25142,16 +25154,6 @@ /obj/machinery/airalarm/directional/north, /turf/open/floor/iron, /area/station/service/janitor) -"hKj" = ( -/obj/machinery/atmospherics/components/binary/pump/off, -/obj/machinery/airlock_sensor/incinerator_ordmix{ - pixel_x = 24 - }, -/obj/machinery/atmospherics/pipe/layer_manifold/supply/hidden{ - dir = 4 - }, -/turf/open/floor/engine, -/area/station/science/ordnance) "hKr" = ( /obj/structure/table/glass, /obj/item/book/manual/wiki/infections{ @@ -26036,10 +26038,6 @@ }, /turf/open/floor/engine, /area/station/engineering/supermatter/room) -"iao" = ( -/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible, -/turf/closed/wall/r_wall, -/area/station/science/ordnance) "iar" = ( /obj/structure/cable, /obj/machinery/door/poddoor/preopen{ @@ -26923,10 +26921,6 @@ }, /turf/open/floor/iron/white, /area/station/medical/chemistry) -"inb" = ( -/obj/machinery/door/poddoor/incinerator_ordmix, -/turf/open/floor/engine/vacuum, -/area/station/science/ordnance) "inh" = ( /obj/structure/stairs/west, /obj/structure/railing, @@ -27484,6 +27478,9 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/port/fore) +"iwq" = ( +/turf/open/floor/engine/vacuum, +/area/station/science/ordnance) "iwx" = ( /obj/machinery/door/airlock/maintenance{ name = "Xenobiology Maintenance" @@ -27657,15 +27654,6 @@ /obj/effect/spawner/structure/window/reinforced/tinted, /turf/open/floor/plating, /area/station/maintenance/starboard/fore) -"izc" = ( -/obj/machinery/atmospherics/components/binary/pump/on{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/layer_manifold/scrubbers/hidden{ - dir = 8 - }, -/turf/open/floor/engine, -/area/station/science/ordnance) "izn" = ( /obj/effect/spawner/random/decoration/generic, /turf/open/floor/plating, @@ -27899,6 +27887,10 @@ dir = 4 }, /area/station/science/explab) +"iCe" = ( +/obj/machinery/atmospherics/pipe/smart/simple/dark/visible, +/turf/closed/wall/r_wall, +/area/station/science/ordnance) "iCg" = ( /obj/effect/turf_decal/stripes/corner{ dir = 1 @@ -32826,9 +32818,6 @@ dir = 4 }, /area/station/maintenance/port/fore) -"keV" = ( -/turf/open/floor/engine/vacuum, -/area/station/science/ordnance) "keX" = ( /obj/structure/table, /obj/item/stack/cable_coil{ @@ -36516,6 +36505,15 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/catwalk_floor/iron_smooth, /area/station/maintenance/port/fore) +"lgP" = ( +/obj/machinery/atmospherics/components/binary/pump/on{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/layer_manifold/scrubbers/hidden{ + dir = 8 + }, +/turf/open/floor/engine, +/area/station/science/ordnance) "lgW" = ( /obj/machinery/meter/monitored/distro_loop, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/visible, @@ -41328,14 +41326,6 @@ /obj/structure/cable, /turf/open/floor/wood/parquet, /area/station/service/bar/atrium) -"mIC" = ( -/obj/machinery/door/airlock/research/glass/incinerator/ordmix_exterior{ - name = "Burn Chamber Exterior Airlock" - }, -/obj/effect/mapping_helpers/airlock/locked, -/obj/effect/mapping_helpers/airlock/access/all/science/ordnance, -/turf/open/floor/engine/vacuum, -/area/station/science/ordnance) "mIE" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/cable, @@ -42187,10 +42177,6 @@ }, /turf/open/floor/plating, /area/station/hallway/secondary/entry) -"mYd" = ( -/obj/machinery/air_sensor/ordnance_burn_chamber, -/turf/open/floor/engine/vacuum, -/area/station/science/ordnance) "mYh" = ( /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/ai) @@ -44386,10 +44372,6 @@ }, /turf/open/floor/plating, /area/station/maintenance/aft/greater) -"nBV" = ( -/obj/machinery/atmospherics/components/unary/vent_scrubber/on, -/turf/open/floor/engine/vacuum, -/area/station/science/ordnance) "nCa" = ( /obj/structure/rack, /obj/item/pickaxe, @@ -46004,6 +45986,10 @@ }, /turf/open/floor/iron/white, /area/station/science/xenobiology) +"ocd" = ( +/obj/machinery/igniter/incinerator_ordmix, +/turf/open/floor/engine/vacuum, +/area/station/science/ordnance) "ocf" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 @@ -56726,6 +56712,14 @@ /obj/effect/mapping_helpers/airlock/access/all/supply/mining, /turf/open/floor/iron/dark/textured_half, /area/mine/mechbay) +"rmG" = ( +/obj/machinery/door/airlock/research/glass/incinerator/ordmix_exterior{ + name = "Burn Chamber Exterior Airlock" + }, +/obj/effect/mapping_helpers/airlock/locked, +/obj/effect/mapping_helpers/airlock/access/all/science/ordnance, +/turf/open/floor/engine/vacuum, +/area/station/science/ordnance) "rmM" = ( /obj/machinery/disposal/bin, /obj/structure/disposalpipe/trunk{ @@ -56869,6 +56863,10 @@ /obj/machinery/newscaster/directional/south, /turf/open/floor/iron, /area/station/science/explab) +"roW" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/closed/wall/r_wall, +/area/station/science/ordnance) "roX" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/cable, @@ -57445,6 +57443,12 @@ /obj/item/kirbyplants/random, /turf/open/floor/wood, /area/station/hallway/secondary/service) +"ryX" = ( +/obj/machinery/atmospherics/components/binary/dp_vent_pump/high_volume/incinerator_ordmix{ + dir = 8 + }, +/turf/open/floor/engine, +/area/station/science/ordnance) "rza" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -60228,6 +60232,17 @@ dir = 8 }, /area/station/service/chapel) +"sqH" = ( +/obj/machinery/door/airlock/research/glass/incinerator/ordmix_interior{ + name = "Burn Chamber Interior Airlock" + }, +/obj/effect/mapping_helpers/airlock/locked, +/obj/machinery/airlock_controller/incinerator_ordmix{ + pixel_x = 24 + }, +/obj/effect/mapping_helpers/airlock/access/all/science/ordnance, +/turf/open/floor/engine, +/area/station/science/ordnance) "sqN" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -60381,6 +60396,10 @@ /obj/structure/sign/warning/secure_area, /turf/closed/wall/r_wall, /area/station/engineering/storage/tech) +"ssu" = ( +/obj/structure/gulag_vent/ice, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "ssv" = ( /obj/effect/turf_decal/tile/neutral/fourcorners, /obj/effect/turf_decal/siding/thinplating_new/corner, @@ -61122,10 +61141,6 @@ /obj/structure/cable/multilayer/multiz, /turf/open/floor/plating, /area/station/maintenance/starboard/lesser) -"sDA" = ( -/obj/machinery/igniter/incinerator_ordmix, -/turf/open/floor/engine/vacuum, -/area/station/science/ordnance) "sDQ" = ( /obj/item/radio/intercom/prison/directional/north, /obj/effect/turf_decal/tile/red/half/contrasted{ @@ -73900,10 +73915,6 @@ "wHc" = ( /turf/closed/wall/r_wall, /area/station/command/heads_quarters/rd) -"wHd" = ( -/obj/machinery/atmospherics/pipe/smart/simple/dark/visible, -/turf/closed/wall/r_wall, -/area/station/science/ordnance) "wHe" = ( /obj/structure/cable, /turf/open/floor/iron/dark/textured, @@ -74035,6 +74046,10 @@ /obj/effect/landmark/start/depsec/medical, /turf/open/floor/iron/dark/smooth_large, /area/station/security/checkpoint/medical) +"wKh" = ( +/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible, +/turf/closed/wall/r_wall, +/area/station/science/ordnance) "wKm" = ( /obj/effect/turf_decal/tile/neutral/diagonal_edge, /obj/structure/disposalpipe/segment{ @@ -74370,17 +74385,6 @@ }, /turf/open/floor/plating, /area/station/maintenance/port/fore) -"wPC" = ( -/obj/machinery/door/airlock/research/glass/incinerator/ordmix_interior{ - name = "Burn Chamber Interior Airlock" - }, -/obj/effect/mapping_helpers/airlock/locked, -/obj/machinery/airlock_controller/incinerator_ordmix{ - pixel_x = 24 - }, -/obj/effect/mapping_helpers/airlock/access/all/science/ordnance, -/turf/open/floor/engine, -/area/station/science/ordnance) "wPD" = ( /obj/machinery/door/airlock/security/glass{ name = "Evidence Storage" @@ -116637,7 +116641,7 @@ dhq dhq iDt iDt -iDt +ssu iDt dLN rbT @@ -193602,8 +193606,8 @@ uIf uIf uIf uIf -fSG -fSG +roW +roW bId gcy jJG @@ -193855,12 +193859,12 @@ thA thA rcY iDt -inb -keV -gWZ -wHd -izc -wHd +fCS +iwq +cuB +iCe +lgP +iCe vcH gnq xEF @@ -194112,12 +194116,12 @@ thA thA rcY iDt -inb -sDA -mYd -mIC -dJk -wPC +fCS +ocd +bqX +rmG +ryX +sqH qSk sbd rEh @@ -194369,12 +194373,12 @@ thA thA rcY iDt -inb -keV -nBV -iao -hKj -iao +fCS +iwq +evc +wKh +aEK +wKh odf sbd jaY diff --git a/_maps/map_files/Mining/Lavaland.dmm b/_maps/map_files/Mining/Lavaland.dmm index c621acfbae215..a524709c2a5ab 100644 --- a/_maps/map_files/Mining/Lavaland.dmm +++ b/_maps/map_files/Mining/Lavaland.dmm @@ -4160,6 +4160,10 @@ dir = 1 }, /area/mine/storage/public) +"xX" = ( +/obj/structure/gulag_vent, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) "yc" = ( /obj/docking_port/stationary{ dir = 2; @@ -4487,7 +4491,7 @@ /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) "Af" = ( -/obj/machinery/mineral/processing_unit{ +/obj/machinery/mineral/processing_unit/gulag{ dir = 1; input_dir = 8; output_dir = 4 @@ -22569,7 +22573,7 @@ uU uU uU pU -pU +xX pU ff Gf diff --git a/code/datums/components/material/material_container.dm b/code/datums/components/material/material_container.dm index a17e642e03920..ffcf81feacefd 100644 --- a/code/datums/components/material/material_container.dm +++ b/code/datums/components/material/material_container.dm @@ -678,6 +678,7 @@ while(sheet_amt > 0) //don't merge yet. we need to do stuff with it first var/obj/item/stack/sheet/new_sheets = new material.sheet_type(target, min(sheet_amt, MAX_STACK_SIZE), FALSE) + new_sheets.manufactured = TRUE count += new_sheets.amount //use material & deduct work needed use_amount_mat(new_sheets.amount * SHEET_MATERIAL_AMOUNT, material) diff --git a/code/game/objects/items/stacks/bscrystal.dm b/code/game/objects/items/stacks/bscrystal.dm index 75c35eabb1818..4e8a01971bac0 100644 --- a/code/game/objects/items/stacks/bscrystal.dm +++ b/code/game/objects/items/stacks/bscrystal.dm @@ -67,6 +67,7 @@ icon = 'icons/obj/stack_objects.dmi' icon_state = "polycrystal" inhand_icon_state = null + gulag_valid = TRUE singular_name = "bluespace polycrystal" desc = "A stable polycrystal, made of fused-together bluespace crystals. You could probably break one off." mats_per_unit = list(/datum/material/bluespace=SHEET_MATERIAL_AMOUNT) @@ -74,7 +75,6 @@ attack_verb_simple = list("bluespace polybash", "bluespace polybatter", "bluespace polybludgeon", "bluespace polythrash", "bluespace polysmash") novariants = TRUE grind_results = list(/datum/reagent/bluespace = 20) - point_value = 90 merge_type = /obj/item/stack/sheet/bluespace_crystal material_type = /datum/material/bluespace var/crystal_type = /obj/item/stack/ore/bluespace_crystal/refined diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm index d6bd65afe31e1..1f66b80cf55b7 100644 --- a/code/game/objects/items/stacks/sheets/glass.dm +++ b/code/game/objects/items/stacks/sheets/glass.dm @@ -27,7 +27,6 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \ merge_type = /obj/item/stack/sheet/glass grind_results = list(/datum/reagent/silicon = 20) material_type = /datum/material/glass - point_value = 1 tableVariant = /obj/structure/table/glass matter_amount = 4 cost = SHEET_MATERIAL_AMOUNT @@ -159,7 +158,6 @@ GLOBAL_LIST_INIT(reinforced_glass_recipes, list ( \ resistance_flags = ACID_PROOF merge_type = /obj/item/stack/sheet/rglass grind_results = list(/datum/reagent/silicon = 20, /datum/reagent/iron = 10) - point_value = 12 matter_amount = 6 tableVariant = /obj/structure/table/reinforced/rglass @@ -197,7 +195,7 @@ GLOBAL_LIST_INIT(prglass_recipes, list ( \ material_flags = NONE merge_type = /obj/item/stack/sheet/plasmarglass grind_results = list(/datum/reagent/silicon = 20, /datum/reagent/toxin/plasma = 10, /datum/reagent/iron = 10) - point_value = 69 + gulag_valid = TRUE matter_amount = 8 tableVariant = /obj/structure/table/reinforced/plasmarglass diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm index 0620d82cd9bf4..1b3d66a7dae92 100644 --- a/code/game/objects/items/stacks/sheets/mineral.dm +++ b/code/game/objects/items/stacks/sheets/mineral.dm @@ -99,7 +99,7 @@ GLOBAL_LIST_INIT(sandbag_recipes, list ( \ sheettype = "diamond" mats_per_unit = list(/datum/material/diamond=SHEET_MATERIAL_AMOUNT) grind_results = list(/datum/reagent/carbon = 20) - point_value = 75 + gulag_valid = TRUE merge_type = /obj/item/stack/sheet/mineral/diamond material_type = /datum/material/diamond walltype = /turf/closed/wall/mineral/diamond @@ -124,7 +124,7 @@ GLOBAL_LIST_INIT(diamond_recipes, list ( \ sheettype = "uranium" mats_per_unit = list(/datum/material/uranium=SHEET_MATERIAL_AMOUNT) grind_results = list(/datum/reagent/uranium = 20) - point_value = 60 + gulag_valid = TRUE merge_type = /obj/item/stack/sheet/mineral/uranium material_type = /datum/material/uranium walltype = /turf/closed/wall/mineral/uranium @@ -157,7 +157,7 @@ GLOBAL_LIST_INIT(uranium_recipes, list ( \ max_integrity = 100 mats_per_unit = list(/datum/material/plasma=SHEET_MATERIAL_AMOUNT) grind_results = list(/datum/reagent/toxin/plasma = 20) - point_value = 60 + gulag_valid = TRUE merge_type = /obj/item/stack/sheet/mineral/plasma material_type = /datum/material/plasma walltype = /turf/closed/wall/mineral/plasma @@ -192,7 +192,7 @@ GLOBAL_LIST_INIT(plasma_recipes, list ( \ sheettype = "gold" mats_per_unit = list(/datum/material/gold=SHEET_MATERIAL_AMOUNT) grind_results = list(/datum/reagent/gold = 20) - point_value = 60 + gulag_valid = TRUE merge_type = /obj/item/stack/sheet/mineral/gold material_type = /datum/material/gold walltype = /turf/closed/wall/mineral/gold @@ -219,7 +219,7 @@ GLOBAL_LIST_INIT(gold_recipes, list ( \ sheettype = "silver" mats_per_unit = list(/datum/material/silver=SHEET_MATERIAL_AMOUNT) grind_results = list(/datum/reagent/silver = 20) - point_value = 60 + gulag_valid = TRUE merge_type = /obj/item/stack/sheet/mineral/silver material_type = /datum/material/silver tableVariant = /obj/structure/table/optable @@ -245,7 +245,7 @@ GLOBAL_LIST_INIT(silver_recipes, list ( \ sheettype = "bananium" mats_per_unit = list(/datum/material/bananium=SHEET_MATERIAL_AMOUNT) grind_results = list(/datum/reagent/consumable/banana = 20) - point_value = 150 + gulag_valid = TRUE merge_type = /obj/item/stack/sheet/mineral/bananium material_type = /datum/material/bananium walltype = /turf/closed/wall/mineral/bananium @@ -276,7 +276,7 @@ GLOBAL_LIST_INIT(bananium_recipes, list ( \ throw_range = 3 sheettype = "titanium" mats_per_unit = list(/datum/material/titanium=SHEET_MATERIAL_AMOUNT) - point_value = 60 + gulag_valid = TRUE merge_type = /obj/item/stack/sheet/mineral/titanium material_type = /datum/material/titanium walltype = /turf/closed/wall/mineral/titanium @@ -308,7 +308,7 @@ GLOBAL_LIST_INIT(titanium_recipes, list ( \ throw_range = 3 sheettype = "plastitanium" mats_per_unit = list(/datum/material/alloy/plastitanium=SHEET_MATERIAL_AMOUNT) - point_value = 135 + gulag_valid = TRUE material_type = /datum/material/alloy/plastitanium merge_type = /obj/item/stack/sheet/mineral/plastitanium material_flags = NONE @@ -482,7 +482,7 @@ GLOBAL_LIST_INIT(metalhydrogen_recipes, list( singular_name = "metal hydrogen sheet" w_class = WEIGHT_CLASS_NORMAL resistance_flags = FIRE_PROOF | LAVA_PROOF | ACID_PROOF | INDESTRUCTIBLE - point_value = 300 + gulag_valid = TRUE mats_per_unit = list(/datum/material/metalhydrogen = SHEET_MATERIAL_AMOUNT) material_type = /datum/material/metalhydrogen merge_type = /obj/item/stack/sheet/mineral/metal_hydrogen @@ -497,7 +497,7 @@ GLOBAL_LIST_INIT(metalhydrogen_recipes, list( inhand_icon_state = "sheet-zaukerite" singular_name = "zaukerite crystal" w_class = WEIGHT_CLASS_NORMAL - point_value = 360 + gulag_valid = TRUE mats_per_unit = list(/datum/material/zaukerite = SHEET_MATERIAL_AMOUNT) merge_type = /obj/item/stack/sheet/mineral/zaukerite material_type = /datum/material/zaukerite diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index bad21b87ac306..f00767217a493 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -150,7 +150,7 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \ resistance_flags = FIRE_PROOF merge_type = /obj/item/stack/sheet/iron grind_results = list(/datum/reagent/iron = 20) - point_value = 6 + gulag_valid = TRUE tableVariant = /obj/structure/table material_type = /datum/material/iron matter_amount = 4 @@ -277,7 +277,7 @@ GLOBAL_LIST_INIT(plasteel_recipes, list ( \ resistance_flags = FIRE_PROOF merge_type = /obj/item/stack/sheet/plasteel grind_results = list(/datum/reagent/iron = 20, /datum/reagent/toxin/plasma = 20) - point_value = 69 + gulag_valid = TRUE tableVariant = /obj/structure/table/reinforced material_flags = NONE matter_amount = 12 diff --git a/code/game/objects/items/stacks/sheets/sheets.dm b/code/game/objects/items/stacks/sheets/sheets.dm index 530a3573f7cd0..8b81953528ee1 100644 --- a/code/game/objects/items/stacks/sheets/sheets.dm +++ b/code/game/objects/items/stacks/sheets/sheets.dm @@ -14,7 +14,10 @@ novariants = FALSE material_flags = MATERIAL_EFFECTS var/sheettype = null //this is used for girders in the creation of walls/false walls - var/point_value = 0 //turn-in value for the gulag stacker - loosely relative to its rarity. + ///If true, this is worth points in the gulag labour stacker + var/gulag_valid = FALSE + ///Set to true if this is vended from a material storage + var/manufactured = FALSE ///What type of wall does this sheet spawn var/walltype /// whether this sheet can be sniffed by the material sniffer @@ -32,11 +35,24 @@ GLOB.sniffable_sheets -= src return ..() +/obj/item/stack/sheet/examine(mob/user) + . = ..() + if (manufactured && gulag_valid) + . += "It has been embossed with a manufacturer's mark of guaranteed quality." + /obj/item/stack/sheet/add(_amount) . = ..() if(sniffable && amount >= 10 && is_station_level(z)) GLOB.sniffable_sheets |= src +/obj/item/stack/sheet/merge(obj/item/stack/sheet/target_stack, limit) + . = ..() + manufactured = manufactured && target_stack.manufactured + +/obj/item/stack/sheet/copy_evidences(obj/item/stack/sheet/from) + . = ..() + manufactured = from.manufactured + /// removing from sniffable handled by the sniffer itself when it checks for targets /** diff --git a/code/game/objects/structures/lavaland/gulag_vent.dm b/code/game/objects/structures/lavaland/gulag_vent.dm new file mode 100644 index 0000000000000..aa13a1621d8b3 --- /dev/null +++ b/code/game/objects/structures/lavaland/gulag_vent.dm @@ -0,0 +1,42 @@ +/** + * A boulder-spawning structure superficially similar to an ore vent which doesnt share any of its behaviour + * Prisoners can haul boulders up out of it in case the actual mining area is totally spent + */ +/obj/structure/gulag_vent + name = "work pit" + desc = "A timeworn shaft, almost totally mined out. With a bit of effort you might be able to haul something up." + icon = 'icons/obj/mining_zones/terrain.dmi' + icon_state = "ore_vent_active" + move_resist = MOVE_FORCE_EXTREMELY_STRONG + resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF //This thing will take a beating. + interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND | INTERACT_ATOM_REQUIRES_DEXTERITY + anchored = TRUE + density = TRUE + /// What kind of rock we got in there? + var/spawned_boulder = /obj/item/boulder/gulag + /// Prevents multiple people from hauling at a time + var/occupied = FALSE + +/obj/structure/gulag_vent/ice + icon_state = "ore_vent_ice_active" + +/obj/structure/gulag_vent/interact(mob/user) + . = ..() + if (!isliving(user)) + return + if (occupied) + balloon_alert(user, "occupied!") + return + var/mob/living/living_user = user + occupied = TRUE + living_user.balloon_alert_to_viewers("hauling...") + var/succeeded = do_after(living_user, 8 SECONDS, src) + occupied = FALSE + if (!succeeded) + return + living_user.mind?.adjust_experience(/datum/skill/fitness, 10) + living_user.apply_status_effect(/datum/status_effect/exercised) + new spawned_boulder(get_turf(living_user)) + living_user.visible_message(span_notice("[living_user] hauls a boulder out of [src].")) + living_user.apply_damage(120, STAMINA) + playsound(src, 'sound/weapons/genhit.ogg', vol = 50, vary = TRUE) diff --git a/code/modules/jobs/job_types/prisoner.dm b/code/modules/jobs/job_types/prisoner.dm index fd6f0f939d68a..1d4be888e9678 100644 --- a/code/modules/jobs/job_types/prisoner.dm +++ b/code/modules/jobs/job_types/prisoner.dm @@ -69,9 +69,9 @@ . = ..() var/crime_name = new_prisoner.client?.prefs?.read_preference(/datum/preference/choiced/prisoner_crime) - if(!crime_name) - return var/datum/prisoner_crime/crime = GLOB.prisoner_crimes[crime_name] + if (isnull(crime)) + return var/list/limbs_to_tat = new_prisoner.bodyparts.Copy() for(var/i in 1 to crime.tattoos) if(!length(SSpersistence.prison_tattoos_to_use) || visualsOnly) diff --git a/code/modules/mining/boulder_processing/boulder_types.dm b/code/modules/mining/boulder_processing/boulder_types.dm index 08ed961404c3a..1ffce8737bdd4 100644 --- a/code/modules/mining/boulder_processing/boulder_types.dm +++ b/code/modules/mining/boulder_processing/boulder_types.dm @@ -44,7 +44,7 @@ /datum/material/uranium = 3, ) - set_custom_materials(list(pick_weight(gulag_minerals) = SHEET_MATERIAL_AMOUNT * rand(1, 3))) + set_custom_materials(list(pick_weight(gulag_minerals) = SHEET_MATERIAL_AMOUNT)) ///Boulders usually spawned in lavaland labour camp area but with bluespace material /obj/item/boulder/gulag_expanded @@ -66,7 +66,7 @@ /datum/material/uranium = 3, ) - set_custom_materials(list(pick_weight(expanded_gulag_minerals) = SHEET_MATERIAL_AMOUNT * rand(1, 3))) + set_custom_materials(list(pick_weight(expanded_gulag_minerals) = SHEET_MATERIAL_AMOUNT)) ///lowgrade boulder, most commonly spawned /obj/item/boulder/shabby diff --git a/code/modules/mining/laborcamp/laborstacker.dm b/code/modules/mining/laborcamp/laborstacker.dm index 8a7ffeec88f66..f46c7ecebb938 100644 --- a/code/modules/mining/laborcamp/laborstacker.dm +++ b/code/modules/mining/laborcamp/laborstacker.dm @@ -1,4 +1,4 @@ -GLOBAL_LIST(labor_sheet_values) +#define SHEET_POINT_VALUE 33 /**********************Prisoners' Console**************************/ @@ -22,14 +22,6 @@ GLOBAL_LIST(labor_sheet_values) if(!stacking_machine) return INITIALIZE_HINT_QDEL - if(!GLOB.labor_sheet_values) - var/sheet_list = list() - for(var/obj/item/stack/sheet/sheet as anything in subtypesof(/obj/item/stack/sheet)) - if(!initial(sheet.point_value) || (initial(sheet.merge_type) && initial(sheet.merge_type) != sheet)) //ignore no-value sheets and x/fifty subtypes - continue - sheet_list += list(list("ore" = initial(sheet.name), "value" = initial(sheet.point_value))) - GLOB.labor_sheet_values = sort_list(sheet_list, GLOBAL_PROC_REF(cmp_sheet_list)) - /obj/machinery/mineral/labor_claim_console/Destroy() QDEL_NULL(security_radio) if(stacking_machine) @@ -46,11 +38,6 @@ GLOBAL_LIST(labor_sheet_values) ui = new(user, src, "LaborClaimConsole", name) ui.open() -/obj/machinery/mineral/labor_claim_console/ui_static_data(mob/user) - var/list/data = list() - data["ores"] = GLOB.labor_sheet_values - return data - /obj/machinery/mineral/labor_claim_console/ui_data(mob/user) var/list/data = list() var/can_go_home = FALSE @@ -155,8 +142,9 @@ GLOBAL_LIST(labor_sheet_values) labor_console = null return ..() -/obj/machinery/mineral/stacking_machine/laborstacker/process_sheet(obj/item/stack/sheet/inp) - points += inp.point_value * inp.amount +/obj/machinery/mineral/stacking_machine/laborstacker/process_sheet(obj/item/stack/sheet/input) + if (input.manufactured && input.gulag_valid) + points += SHEET_POINT_VALUE * input.amount return ..() /obj/machinery/mineral/stacking_machine/laborstacker/attackby(obj/item/weapon, mob/user, params) @@ -190,3 +178,5 @@ GLOBAL_LIST(labor_sheet_values) say("ID: [prisoner_id.registered_name].") say("Points Collected: [prisoner_id.points] / [prisoner_id.goal].") say("Collect points by bringing smelted minerals to the Labor Shuttle stacking machine. Reach your quota to earn your release.") + +#undef SHEET_POINT_VALUE diff --git a/code/modules/mining/machine_processing.dm b/code/modules/mining/machine_processing.dm index 11a941c409861..61318f63b92a5 100644 --- a/code/modules/mining/machine_processing.dm +++ b/code/modules/mining/machine_processing.dm @@ -143,6 +143,8 @@ var/datum/proximity_monitor/proximity_monitor ///Material container for materials var/datum/component/material_container/materials + /// What can be input into the machine? + var/accepted_type = /obj/item/stack /obj/machinery/mineral/processing_unit/Initialize(mapload) . = ..() @@ -153,7 +155,7 @@ SSmaterials.materials_by_category[MAT_CATEGORY_SILO], \ INFINITY, \ MATCONTAINER_EXAMINE, \ - allowed_items = /obj/item/stack \ + allowed_items = accepted_type \ ) if(!GLOB.autounlock_techwebs[/datum/techweb/autounlocking/smelter]) GLOB.autounlock_techwebs[/datum/techweb/autounlocking/smelter] = new /datum/techweb/autounlocking/smelter @@ -166,7 +168,7 @@ stored_research = null return ..() -/obj/machinery/mineral/processing_unit/proc/process_ore(obj/item/stack/ore/O) +/obj/machinery/mineral/processing_unit/proc/process_ore(obj/item/stack/O) if(QDELETED(O)) return var/material_amount = materials.get_item_material_amount(O) @@ -225,7 +227,7 @@ /obj/machinery/mineral/processing_unit/pickup_item(datum/source, atom/movable/target, direction) if(QDELETED(target)) return - if(istype(target, /obj/item/stack/ore)) + if(istype(target, accepted_type)) process_ore(target) /obj/machinery/mineral/processing_unit/process(seconds_per_tick) @@ -282,4 +284,8 @@ var/O = new P(src) unload_mineral(O) +/// Only accepts ore, for the work camp +/obj/machinery/mineral/processing_unit/gulag + accepted_type = /obj/item/stack/ore + #undef SMELT_AMOUNT diff --git a/code/modules/mining/machine_stacking.dm b/code/modules/mining/machine_stacking.dm index 286317a5d74eb..1f9a29a6e3714 100644 --- a/code/modules/mining/machine_stacking.dm +++ b/code/modules/mining/machine_stacking.dm @@ -137,26 +137,26 @@ if (input_dir == output_dir) rotate(input) -/obj/machinery/mineral/stacking_machine/proc/process_sheet(obj/item/stack/sheet/inp) - if(QDELETED(inp)) +/obj/machinery/mineral/stacking_machine/proc/process_sheet(obj/item/stack/sheet/input) + if(QDELETED(input)) return // Dump the sheets to the silo if attached if(materials.silo && !materials.on_hold()) - var/matlist = inp.custom_materials & materials.mat_container.materials + var/matlist = input.custom_materials & materials.mat_container.materials if (length(matlist)) - materials.mat_container.insert_item(inp, context = src) + materials.insert_item(input) return // No silo attached process to internal storage - var/key = inp.merge_type + var/key = input.merge_type var/obj/item/stack/sheet/storage = stack_list[key] if(!storage) //It's the first of this sheet added - stack_list[key] = storage = new inp.type(src, 0) - storage.amount += inp.amount //Stack the sheets - qdel(inp) + stack_list[key] = storage = new input.type(src, 0) + storage.amount += input.amount //Stack the sheets + qdel(input) while(storage.amount >= stack_amt) //Get rid of excessive stackage - var/obj/item/stack/sheet/out = new inp.type(null, stack_amt) + var/obj/item/stack/sheet/out = new input.type(null, stack_amt) unload_mineral(out) storage.amount -= stack_amt diff --git a/tgstation.dme b/tgstation.dme index 0d2005fe3f84d..e48c0d64a1e17 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -2710,6 +2710,7 @@ #include "code\game\objects\structures\gym\weight_machine_action.dm" #include "code\game\objects\structures\icemoon\cave_entrance.dm" #include "code\game\objects\structures\lavaland\geyser.dm" +#include "code\game\objects\structures\lavaland\gulag_vent.dm" #include "code\game\objects\structures\lavaland\necropolis_tendril.dm" #include "code\game\objects\structures\lavaland\ore_vent.dm" #include "code\game\objects\structures\plaques\_plaques.dm" diff --git a/tgui/packages/tgui/interfaces/LaborClaimConsole.jsx b/tgui/packages/tgui/interfaces/LaborClaimConsole.jsx index 27b3cc0e05f9b..4e0aebdcdd5bb 100644 --- a/tgui/packages/tgui/interfaces/LaborClaimConsole.jsx +++ b/tgui/packages/tgui/interfaces/LaborClaimConsole.jsx @@ -35,25 +35,14 @@ export const LaborClaimConsole = (props) => {
    -
    + ); +}; + +type CrewTableEntryProps = { + sensor_data: CrewSensor; +}; + +const CrewTableEntry = (props: CrewTableEntryProps) => { + const { act, data } = useBackend(); + const { link_allowed } = data; + const { sensor_data } = props; + const { + name, + assignment, + ijob, + life_status, + oxydam, + toxdam, + burndam, + brutedam, + area, + can_track, + } = sensor_data; + + return ( + + + {name} + {assignment !== undefined ? ` (${assignment})` : ''} + + + {oxydam !== undefined ? ( + + ) : life_status !== STAT_DEAD ? ( + + ) : ( + + )} + + + {oxydam !== undefined ? ( + + + {'/'} + + {'/'} + + {'/'} + + + ) : life_status !== STAT_DEAD ? ( + 'Alive' + ) : ( + 'Dead' + )} + + + {area !== '~' && area !== undefined ? ( + area + ) : ( + + )} + + {!!link_allowed && ( + + + + )} + + ); +}; From 696b795d5b00db4024ddccdf676054652267e37b Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Wed, 24 Apr 2024 18:48:52 +1200 Subject: [PATCH 461/938] Automatic changelog for PR #82732 [ci skip] --- html/changelogs/AutoChangeLog-pr-82732.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82732.yml diff --git a/html/changelogs/AutoChangeLog-pr-82732.yml b/html/changelogs/AutoChangeLog-pr-82732.yml new file mode 100644 index 0000000000000..8e03debbfc081 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82732.yml @@ -0,0 +1,4 @@ +author: "Momo8289" +delete-after: True +changes: + - rscadd: "The crew monitor now has sorting options and a search bar." \ No newline at end of file From 0cb9aa842a973fff6d8ae79b1183b3d2d545c6d6 Mon Sep 17 00:00:00 2001 From: EvilDragonfiend <87972842+EvilDragonfiend@users.noreply.github.com> Date: Thu, 25 Apr 2024 03:03:59 +0900 Subject: [PATCH 462/938] Accessing Datasystem Manager from MC controller panel (#82848) --- code/controllers/subsystem/statpanel.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/controllers/subsystem/statpanel.dm b/code/controllers/subsystem/statpanel.dm index 020598a573b67..0412671184b5d 100644 --- a/code/controllers/subsystem/statpanel.dm +++ b/code/controllers/subsystem/statpanel.dm @@ -168,6 +168,7 @@ SUBSYSTEM_DEF(statpanels) list("World Time:", "[world.time]"), list("Globals:", GLOB.stat_entry(), text_ref(GLOB)), list("[config]:", config.stat_entry(), text_ref(config)), + list("Datasystem Manager:", "Edit", text_ref(SysMgr)), list("Byond:", "(FPS:[world.fps]) (TickCount:[world.time/world.tick_lag]) (TickDrift:[round(Master.tickdrift,1)]([round((Master.tickdrift/(world.time/world.tick_lag))*100,0.1)]%)) (Internal Tick Usage: [round(MAPTICK_LAST_INTERNAL_TICK_USAGE,0.1)]%)"), list("Master Controller:", Master.stat_entry(), text_ref(Master)), list("Failsafe Controller:", Failsafe.stat_entry(), text_ref(Failsafe)), From 59a20eb8e7822cfdd4ba5063d112c41585c6f714 Mon Sep 17 00:00:00 2001 From: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Date: Wed, 24 Apr 2024 11:05:06 -0700 Subject: [PATCH 463/938] Fixes some rando failures off the ignore list of projectiles (#82855) --- code/datums/components/mirv.dm | 2 +- code/datums/components/pellet_cloud.dm | 2 +- code/game/objects/items/hand_items.dm | 4 ++-- code/modules/clothing/shoes/gunboots.dm | 2 +- code/modules/fishing/fishing_rod.dm | 2 +- code/modules/projectiles/projectile.dm | 11 +++++------ 6 files changed, 11 insertions(+), 12 deletions(-) diff --git a/code/datums/components/mirv.dm b/code/datums/components/mirv.dm index 0f41df1d2888a..52b4053babb5a 100644 --- a/code/datums/components/mirv.dm +++ b/code/datums/components/mirv.dm @@ -39,5 +39,5 @@ P.range = override_projectile_range P.preparePixelProjectile(shootat_turf, target) P.firer = firer // don't hit ourself that would be really annoying - P.impacted = list(target = TRUE) // don't hit the target we hit already with the flak + P.impacted = list(WEAKREF(target) = TRUE) // don't hit the target we hit already with the flak P.fire() diff --git a/code/datums/components/pellet_cloud.dm b/code/datums/components/pellet_cloud.dm index e857292f487a5..c206af62f704a 100644 --- a/code/datums/components/pellet_cloud.dm +++ b/code/datums/components/pellet_cloud.dm @@ -277,7 +277,7 @@ P.original = target P.fired_from = parent P.firer = parent // don't hit ourself that would be really annoying - P.impacted = list(parent = TRUE) // don't hit the target we hit already with the flak + P.impacted = list(WEAKREF(parent) = TRUE) // don't hit the target we hit already with the flak P.suppressed = SUPPRESSED_VERY // set the projectiles to make no message so we can do our own aggregate message P.preparePixelProjectile(target, parent) RegisterSignal(P, COMSIG_PROJECTILE_SELF_ON_HIT, PROC_REF(pellet_hit)) diff --git a/code/game/objects/items/hand_items.dm b/code/game/objects/items/hand_items.dm index 57c240e427327..10a90b3dbdcef 100644 --- a/code/game/objects/items/hand_items.dm +++ b/code/game/objects/items/hand_items.dm @@ -491,7 +491,7 @@ blown_kiss.original = target blown_kiss.fired_from = user blown_kiss.firer = user // don't hit ourself that would be really annoying - blown_kiss.impacted = list(user = TRUE) // just to make sure we don't hit the wearer + blown_kiss.impacted = list(WEAKREF(user) = TRUE) // just to make sure we don't hit the wearer blown_kiss.preparePixelProjectile(target, user) blown_kiss.fire() qdel(src) @@ -517,7 +517,7 @@ blown_kiss.original = taker blown_kiss.fired_from = offerer blown_kiss.firer = offerer // don't hit ourself that would be really annoying - blown_kiss.impacted = list(offerer = TRUE) // just to make sure we don't hit the wearer + blown_kiss.impacted = list(WEAKREF(offerer) = TRUE) // just to make sure we don't hit the wearer blown_kiss.preparePixelProjectile(taker, offerer) blown_kiss.suppressed = SUPPRESSED_VERY // this also means it's a direct offer blown_kiss.fire() diff --git a/code/modules/clothing/shoes/gunboots.dm b/code/modules/clothing/shoes/gunboots.dm index d8335b5fcb0ed..de74703d449ed 100644 --- a/code/modules/clothing/shoes/gunboots.dm +++ b/code/modules/clothing/shoes/gunboots.dm @@ -59,7 +59,7 @@ shot.original = target shot.fired_from = src shot.firer = wearer // don't hit ourself that would be really annoying - shot.impacted = list(wearer = TRUE) + shot.impacted = list(WEAKREF(wearer) = TRUE) shot.def_zone = pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) // they're fired from boots after all shot.preparePixelProjectile(target, wearer) if(!shot.suppressed) diff --git a/code/modules/fishing/fishing_rod.dm b/code/modules/fishing/fishing_rod.dm index 0578ffb078907..a0fa77dc51431 100644 --- a/code/modules/fishing/fishing_rod.dm +++ b/code/modules/fishing/fishing_rod.dm @@ -234,7 +234,7 @@ cast_projectile.original = target cast_projectile.fired_from = src cast_projectile.firer = user - cast_projectile.impacted = list(user = TRUE) + cast_projectile.impacted = list(WEAKREF(user) = TRUE) cast_projectile.preparePixelProjectile(target, user) cast_projectile.fire() COOLDOWN_START(src, casting_cd, 1 SECONDS) diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 602bbcc8c4ce6..040bbf5f709bb 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -457,7 +457,7 @@ if(!trajectory) qdel(src) return FALSE - if(impacted[A]) // NEVER doublehit + if(impacted[A.weak_reference]) // NEVER doublehit return FALSE var/datum/point/point_cache = trajectory.copy_to() var/turf/T = get_turf(A) @@ -510,7 +510,7 @@ if(QDELETED(src) || !T || !target) return // 2. - impacted[target] = TRUE //hash lookup > in for performance in hit-checking + impacted[WEAKREF(target)] = TRUE //hash lookup > in for performance in hit-checking // 3. var/mode = prehit_pierce(target) if(mode == PROJECTILE_DELETE_WITHOUT_HITTING) @@ -587,7 +587,7 @@ //Returns true if the target atom is on our current turf and above the right layer //If direct target is true it's the originally clicked target. /obj/projectile/proc/can_hit_target(atom/target, direct_target = FALSE, ignore_loc = FALSE, cross_failed = FALSE) - if(QDELETED(target) || impacted[target]) + if(QDELETED(target) || impacted[target.weak_reference]) return FALSE if(!ignore_loc && (loc != target.loc) && !(can_hit_turfs && direct_target && loc == target)) return FALSE @@ -675,7 +675,7 @@ * Used to not even attempt to Bump() or fail to Cross() anything we already hit. */ /obj/projectile/CanPassThrough(atom/blocker, movement_dir, blocker_opinion) - return impacted[blocker] ? TRUE : ..() + return ..() || impacted[blocker.weak_reference] /** * Projectile moved: @@ -1188,8 +1188,7 @@ bullet.starting = startloc var/list/ignore = list() for (var/atom/thing as anything in ignore_targets) - ignore[thing] = TRUE - bullet.impacted += ignore + bullet.impacted[WEAKREF(thing)] = TRUE bullet.firer = firer || src bullet.fired_from = src bullet.yo = target.y - startloc.y From 2e11db2344e4c7f8d7cca52df09ef0770dde2d4b Mon Sep 17 00:00:00 2001 From: Fikou <23585223+Fikou@users.noreply.github.com> Date: Wed, 24 Apr 2024 21:59:58 +0200 Subject: [PATCH 464/938] [NO GBP] fixes issues with human rendering fixes (#82852) ## About The Pull Request fixes #82838, forgot to add the attack_self there fixes #82869 fixes the atmos hardhat not using flags_inv and transparent_protection correctly (you could pull off someones glasses through it for example makes modsuits use the new rendering stuff fixes rendering stuff not working correctly with adjustable clothing fixes quick equip dropping the item if you cant equip it ## Why It's Good For The Game waow its awesome ## Changelog :cl: fix: you can no longer take off someones glasses or mask through atmos hardhat fix: once you adjust a welding helmet or something it no longer makes your cigarette or sunglasses invisible fix: welding gas mask works once again fix: quick equips dont drop the item if you cant equip it /:cl: --- code/modules/clothing/clothing.dm | 5 +++- code/modules/clothing/glasses/_glasses.dm | 4 +++ code/modules/clothing/head/hardhat.dm | 3 +- code/modules/clothing/head/welding.dm | 1 + code/modules/clothing/masks/gasmask.dm | 4 +++ .../modules/mining/equipment/explorer_gear.dm | 1 - code/modules/mob/inventory.dm | 12 +++----- .../mob/living/carbon/carbon_update_icons.dm | 16 +++++----- .../living/carbon/human/human_update_icons.dm | 30 +++++++++---------- .../mob/living/carbon/human/inventory.dm | 2 +- code/modules/mob/living/carbon/inventory.dm | 2 +- code/modules/mob/mob_update_icons.dm | 23 +++++++------- code/modules/mod/mod_activation.dm | 19 +++--------- 13 files changed, 59 insertions(+), 63 deletions(-) diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 6510d16bf9efd..e839acaf8cb98 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -470,7 +470,8 @@ BLIND // can't see anything female_clothing_icon = fcopy_rsc(female_clothing_icon) GLOB.female_clothing_icons[index] = female_clothing_icon -/obj/item/clothing/proc/adjust_visor(mob/living/user) //proc to toggle welding visors on helmets, masks, goggles, etc. +/// Proc that adjusts the clothing item, used by things like breathing masks, welding helmets, welding goggles etc. +/obj/item/clothing/proc/adjust_visor(mob/living/user) if(!can_use(user)) return FALSE @@ -483,6 +484,8 @@ BLIND // can't see anything if(user.is_holding(src)) user.update_held_items() return TRUE + if(up) + user.update_obscured_slots(visor_flags_inv) user.update_clothing(slot_flags) if(!iscarbon(user)) return TRUE diff --git a/code/modules/clothing/glasses/_glasses.dm b/code/modules/clothing/glasses/_glasses.dm index 5053e78bdaf11..358bff5ce80d5 100644 --- a/code/modules/clothing/glasses/_glasses.dm +++ b/code/modules/clothing/glasses/_glasses.dm @@ -450,6 +450,10 @@ /obj/item/clothing/glasses/welding/attack_self(mob/user) adjust_visor(user) +/obj/item/clothing/glasses/welding/update_icon_state() + . = ..() + icon_state = "[initial(icon_state)][up ? "up" : ""]" + /obj/item/clothing/glasses/welding/up/Initialize(mapload) . = ..() visor_toggling() diff --git a/code/modules/clothing/head/hardhat.dm b/code/modules/clothing/head/hardhat.dm index ebe8ab48c6861..018543d93a33c 100644 --- a/code/modules/clothing/head/hardhat.dm +++ b/code/modules/clothing/head/hardhat.dm @@ -194,7 +194,8 @@ min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH | PEPPERPROOF visor_flags_cover = NONE - flags_inv = HIDEEARS|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT + flags_inv = HIDEEARS|HIDEHAIR|HIDEFACE|HIDEFACIALHAIR|HIDESNOUT + transparent_protection = HIDEMASK|HIDEEYES visor_flags_inv = NONE visor_state = "weldvisor_atmos" diff --git a/code/modules/clothing/head/welding.dm b/code/modules/clothing/head/welding.dm index 47433dd90f8e9..cb785447174f7 100644 --- a/code/modules/clothing/head/welding.dm +++ b/code/modules/clothing/head/welding.dm @@ -14,6 +14,7 @@ actions_types = list(/datum/action/item_action/toggle) visor_flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDESNOUT visor_flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH | PEPPERPROOF + visor_vars_to_toggle = VISOR_FLASHPROTECT | VISOR_TINT resistance_flags = FIRE_PROOF clothing_flags = SNUG_FIT | STACKABLE_HELMET_EXEMPT diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm index 5cc18a28fbb06..e6f3d7294c9b3 100644 --- a/code/modules/clothing/masks/gasmask.dm +++ b/code/modules/clothing/masks/gasmask.dm @@ -219,6 +219,7 @@ GLOBAL_LIST_INIT(clown_mask_options, list( flags_cover = MASKCOVERSEYES visor_flags_inv = HIDEEYES visor_flags_cover = MASKCOVERSEYES + visor_vars_to_toggle = VISOR_FLASHPROTECT | VISOR_TINT resistance_flags = FIRE_PROOF /datum/armor/gas_welding @@ -227,6 +228,9 @@ GLOBAL_LIST_INIT(clown_mask_options, list( fire = 100 acid = 55 +/obj/item/clothing/mask/gas/welding/attack_self(mob/user) + adjust_visor(user) + /obj/item/clothing/mask/gas/welding/adjust_visor(mob/living/user) . = ..() if(.) diff --git a/code/modules/mining/equipment/explorer_gear.dm b/code/modules/mining/equipment/explorer_gear.dm index e4c0819d6733d..5485ce72f22cd 100644 --- a/code/modules/mining/equipment/explorer_gear.dm +++ b/code/modules/mining/equipment/explorer_gear.dm @@ -91,7 +91,6 @@ . = ..() // adjusted = out of the way = smaller = can fit in boxes update_weight_class(up ? WEIGHT_CLASS_SMALL : WEIGHT_CLASS_NORMAL) - inhand_icon_state = up ? "[initial(inhand_icon_state)]_up" : initial(inhand_icon_state) /obj/item/clothing/mask/gas/explorer/update_icon_state() . = ..() diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index 4dab3f9d70292..f5afac95086ec 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -429,10 +429,10 @@ var/obscured = NONE var/hidden_slots = NONE - for(var/obj/item/I in get_equipped_items()) - hidden_slots |= I.flags_inv + for(var/obj/item/equipped_item in get_equipped_items()) + hidden_slots |= equipped_item.flags_inv if(transparent_protection) - hidden_slots |= I.transparent_protection + hidden_slots |= equipped_item.transparent_protection if(hidden_slots & HIDENECK) obscured |= ITEM_SLOT_NECK @@ -510,11 +510,7 @@ to_chat(src, span_warning("You are not holding anything to equip!")) return if(!QDELETED(I)) - if(I.equip_to_best_slot(src)) - return - if(put_in_active_hand(I)) - return - I.forceMove(drop_location()) + I.equip_to_best_slot(src) //used in code for items usable by both carbon and drones, this gives the proper back slot for each mob.(defibrillator, backpack watertank, ...) /mob/proc/getBackSlot() diff --git a/code/modules/mob/living/carbon/carbon_update_icons.dm b/code/modules/mob/living/carbon/carbon_update_icons.dm index fab921ba19a7f..00e502bad0451 100644 --- a/code/modules/mob/living/carbon/carbon_update_icons.dm +++ b/code/modules/mob/living/carbon/carbon_update_icons.dm @@ -1,6 +1,6 @@ -/mob/living/carbon/update_obscured_slots(obj/item/worn_item) +/mob/living/carbon/update_obscured_slots(obscured_flags) ..() - if(worn_item.flags_inv & (HIDEEARS|HIDEEYES|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT|HIDEMUTWINGS)) + if(obscured_flags & (HIDEEARS|HIDEEYES|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT|HIDEMUTWINGS)) update_body() /// Updates features and clothing attached to a specific limb with limb-specific offsets @@ -344,7 +344,7 @@ if(wear_mask) if(update_obscured) - update_obscured_slots(wear_mask) + update_obscured_slots(wear_mask.flags_inv) if(!(check_obscured_slots() & ITEM_SLOT_MASK)) overlays_standing[FACEMASK_LAYER] = wear_mask.build_worn_icon(default_layer = FACEMASK_LAYER, default_icon_file = 'icons/mob/clothing/mask.dmi') update_hud_wear_mask(wear_mask) @@ -360,7 +360,7 @@ if(wear_neck) if(update_obscured) - update_obscured_slots(wear_neck) + update_obscured_slots(wear_neck.flags_inv) if(!(check_obscured_slots() & ITEM_SLOT_NECK)) overlays_standing[NECK_LAYER] = wear_neck.build_worn_icon(default_layer = NECK_LAYER, default_icon_file = 'icons/mob/clothing/neck.dmi') update_hud_neck(wear_neck) @@ -376,7 +376,7 @@ if(back) if(update_obscured) - update_obscured_slots(back) + update_obscured_slots(back.flags_inv) overlays_standing[BACK_LAYER] = back.build_worn_icon(default_layer = BACK_LAYER, default_icon_file = 'icons/mob/clothing/back.dmi') update_hud_back(back) @@ -387,7 +387,7 @@ clear_alert("legcuffed") if(legcuffed) if(update_obscured) - update_obscured_slots(legcuffed) + update_obscured_slots(legcuffed.flags_inv) overlays_standing[LEGCUFF_LAYER] = mutable_appearance('icons/mob/simple/mob.dmi', "legcuff1", -LEGCUFF_LAYER) apply_overlay(LEGCUFF_LAYER) throw_alert("legcuffed", /atom/movable/screen/alert/restrained/legcuffed, new_master = src.legcuffed) @@ -404,7 +404,7 @@ if(head) if(update_obscured) - update_obscured_slots(head) + update_obscured_slots(head.flags_inv) if(!(check_obscured_slots() & ITEM_SLOT_HEAD)) overlays_standing[HEAD_LAYER] = head.build_worn_icon(default_layer = HEAD_LAYER, default_icon_file = 'icons/mob/clothing/head/default.dmi') update_hud_head(head) @@ -416,7 +416,7 @@ remove_overlay(HANDCUFF_LAYER) if(handcuffed) if(update_obscured) - update_obscured_slots(handcuffed) + update_obscured_slots(handcuffed.flags_inv) var/mutable_appearance/handcuff_overlay = mutable_appearance('icons/mob/simple/mob.dmi', "handcuff1", -HANDCUFF_LAYER) if(handcuffed.blocks_emissive != EMISSIVE_BLOCK_NONE) handcuff_overlay.overlays += emissive_blocker(handcuff_overlay.icon, handcuff_overlay.icon_state, src, alpha = handcuff_overlay.alpha) diff --git a/code/modules/mob/living/carbon/human/human_update_icons.dm b/code/modules/mob/living/carbon/human/human_update_icons.dm index 1b2b85151716e..bd320079b65d5 100644 --- a/code/modules/mob/living/carbon/human/human_update_icons.dm +++ b/code/modules/mob/living/carbon/human/human_update_icons.dm @@ -70,9 +70,9 @@ There are several things that need to be remembered: //damage overlays update_damage_overlays() -/mob/living/carbon/human/update_obscured_slots(obj/item/worn_item) +/mob/living/carbon/human/update_obscured_slots(obscured_flags) ..() - if(worn_item.flags_inv & HIDEFACE) + if(obscured_flags & HIDEFACE) sec_hud_set_security_status() /* --------------------------------------- */ @@ -90,7 +90,7 @@ There are several things that need to be remembered: update_hud_uniform(uniform) if(update_obscured) - update_obscured_slots(uniform) + update_obscured_slots(uniform.flags_inv) if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_ICLOTHING) return @@ -151,7 +151,7 @@ There are several things that need to be remembered: update_hud_id(worn_item) if(update_obscured) - update_obscured_slots(worn_item) + update_obscured_slots(worn_item.flags_inv) var/icon_file = 'icons/mob/clothing/id.dmi' @@ -193,7 +193,7 @@ There are several things that need to be remembered: update_hud_gloves(worn_item) if(update_obscured) - update_obscured_slots(worn_item) + update_obscured_slots(worn_item.flags_inv) if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_GLOVES) return @@ -230,7 +230,7 @@ There are several things that need to be remembered: update_hud_glasses(worn_item) if(update_obscured) - update_obscured_slots(worn_item) + update_obscured_slots(worn_item.flags_inv) if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_EYES) return @@ -259,7 +259,7 @@ There are several things that need to be remembered: update_hud_ears(worn_item) if(update_obscured) - update_obscured_slots(worn_item) + update_obscured_slots(worn_item.flags_inv) if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_EARS) return @@ -283,7 +283,7 @@ There are several things that need to be remembered: update_hud_neck(wear_neck) if(update_obscured) - update_obscured_slots(worn_item) + update_obscured_slots(worn_item.flags_inv) if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_NECK) return @@ -312,7 +312,7 @@ There are several things that need to be remembered: update_hud_shoes(worn_item) if(update_obscured) - update_obscured_slots(worn_item) + update_obscured_slots(worn_item.flags_inv) if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_FEET) return @@ -352,7 +352,7 @@ There are several things that need to be remembered: update_hud_s_store(worn_item) if(update_obscured) - update_obscured_slots(worn_item) + update_obscured_slots(worn_item.flags_inv) if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_SUITSTORE) return @@ -374,7 +374,7 @@ There are several things that need to be remembered: update_hud_head(worn_item) if(update_obscured) - update_obscured_slots(worn_item) + update_obscured_slots(worn_item.flags_inv) if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_HEAD) return @@ -400,7 +400,7 @@ There are several things that need to be remembered: update_hud_belt(worn_item) if(update_obscured) - update_obscured_slots(worn_item) + update_obscured_slots(worn_item.flags_inv) if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_BELT) return @@ -426,7 +426,7 @@ There are several things that need to be remembered: update_hud_wear_suit(worn_item) if(update_obscured) - update_obscured_slots(worn_item) + update_obscured_slots(worn_item.flags_inv) var/icon_file = DEFAULT_SUIT_FILE @@ -477,7 +477,7 @@ There are several things that need to be remembered: update_hud_wear_mask(worn_item) if(update_obscured) - update_obscured_slots(worn_item) + update_obscured_slots(worn_item.flags_inv) if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_MASK) return @@ -504,7 +504,7 @@ There are several things that need to be remembered: update_hud_back(worn_item) if(update_obscured) - update_obscured_slots(worn_item) + update_obscured_slots(worn_item.flags_inv) var/icon_file = 'icons/mob/clothing/back.dmi' diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index 47b08cd7a0a0b..32ab7ca1b900a 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -280,7 +280,7 @@ return update_equipment_speed_mods() - update_obscured_slots(I) + update_obscured_slots(I.flags_inv) /mob/living/carbon/human/toggle_internals(obj/item/tank, is_external = FALSE) // Just close the tank if it's the one the mob already has open. diff --git a/code/modules/mob/living/carbon/inventory.dm b/code/modules/mob/living/carbon/inventory.dm index 27477791092cf..45ca4487184e3 100644 --- a/code/modules/mob/living/carbon/inventory.dm +++ b/code/modules/mob/living/carbon/inventory.dm @@ -204,7 +204,7 @@ return update_equipment_speed_mods() - update_obscured_slots(I) + update_obscured_slots(I.flags_inv) /// Returns TRUE if an air tank compatible helmet is equipped. /mob/living/carbon/proc/can_breathe_helmet() diff --git a/code/modules/mob/mob_update_icons.dm b/code/modules/mob/mob_update_icons.dm index 7da3dddce3294..a355a385d9faa 100644 --- a/code/modules/mob/mob_update_icons.dm +++ b/code/modules/mob/mob_update_icons.dm @@ -42,26 +42,25 @@ if(slot_flags & ITEM_SLOT_HANDS) update_held_items() -///Updates item slots obscured by this item -/mob/proc/update_obscured_slots(obj/item/worn_item) - var/obscured_slots = worn_item.flags_inv - if(obscured_slots & HIDEGLOVES) +///Updates item slots obscured by this item (or using an override of flags to check) +/mob/proc/update_obscured_slots(obscured_flags) + if(obscured_flags & HIDEGLOVES) update_worn_gloves(update_obscured = FALSE) - if(obscured_slots & HIDESUITSTORAGE) + if(obscured_flags & HIDESUITSTORAGE) update_suit_storage(update_obscured = FALSE) - if(obscured_slots & HIDEJUMPSUIT) + if(obscured_flags & HIDEJUMPSUIT) update_worn_undersuit(update_obscured = FALSE) - if(obscured_slots & HIDESHOES) + if(obscured_flags & HIDESHOES) update_worn_shoes(update_obscured = FALSE) - if(obscured_slots & HIDEMASK) + if(obscured_flags & HIDEMASK) update_worn_mask(update_obscured = FALSE) - if(obscured_slots & HIDEEARS) + if(obscured_flags & HIDEEARS) update_worn_ears(update_obscured = FALSE) - if(obscured_slots & HIDEEYES) + if(obscured_flags & HIDEEYES) update_worn_glasses(update_obscured = FALSE) - if(obscured_slots & HIDENECK) + if(obscured_flags & HIDENECK) update_worn_neck(update_obscured = FALSE) - if(obscured_slots & HIDEHEADGEAR) + if(obscured_flags & HIDEHEADGEAR) update_worn_head(update_obscured = FALSE) /mob/proc/update_icons() diff --git a/code/modules/mod/mod_activation.dm b/code/modules/mod/mod_activation.dm index f95125d2a6e17..0d150c15fe61a 100644 --- a/code/modules/mod/mod_activation.dm +++ b/code/modules/mod/mod_activation.dm @@ -212,21 +212,10 @@ part.heat_protection = NONE part.cold_protection = NONE part.alternate_worn_layer = mod_parts[part] - if(part == boots) - wearer.update_worn_shoes() - if(part == gauntlets) - wearer.update_worn_gloves() - if(part == chestplate) - wearer.update_worn_oversuit() - wearer.update_worn_undersuit() - if(part == helmet) - wearer.update_worn_head() - wearer.update_worn_mask() - wearer.update_worn_glasses() - wearer.update_body_parts() - // Close internal air tank if MOD helmet is unsealed and was the only breathing apparatus. - if (!seal && wearer?.invalid_internals()) - wearer.cutoff_internals() + wearer.update_clothing(part.slot_flags) + wearer.update_obscured_slots(part.visor_flags_inv) + if((part.clothing_flags & (MASKINTERNALS|HEADINTERNALS)) && wearer.invalid_internals()) + wearer.cutoff_internals() /// Finishes the suit's activation /obj/item/mod/control/proc/finish_activation(on) From c7ea5cdbe71f9896c8c000865edfe07a434bb826 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 25 Apr 2024 08:00:20 +1200 Subject: [PATCH 465/938] Automatic changelog for PR #82852 [ci skip] --- html/changelogs/AutoChangeLog-pr-82852.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82852.yml diff --git a/html/changelogs/AutoChangeLog-pr-82852.yml b/html/changelogs/AutoChangeLog-pr-82852.yml new file mode 100644 index 0000000000000..2cd68a82732e3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82852.yml @@ -0,0 +1,7 @@ +author: "Fikou" +delete-after: True +changes: + - bugfix: "you can no longer take off someones glasses or mask through atmos hardhat" + - bugfix: "once you adjust a welding helmet or something it no longer makes your cigarette or sunglasses invisible" + - bugfix: "welding gas mask works once again" + - bugfix: "quick equips dont drop the item if you cant equip it" \ No newline at end of file From 0a8e58b49371ac579af7ed005665efb6b960419b Mon Sep 17 00:00:00 2001 From: Sadboysuss <96586172+Sadboysuss@users.noreply.github.com> Date: Thu, 25 Apr 2024 01:14:38 +0300 Subject: [PATCH 466/938] More emote sounds and new whistle emote (#82748) ## About The Pull Request Added new emote to get people's attention: Whistle Added sounds to existing emotes: cry, sneeze, cough, laughs for lizard and moth. In the future, the work done in this PR can be the foundation for giving other species their own emote sounds. Sound files: https://drive.google.com/drive/folders/14cv8_N6BdcyJKQd-sMXDlowXEaY3FZ_K?usp=sharing Preview: https://github.com/tgstation/tgstation/assets/96586172/7524a7c6-b003-40d5-adc4-1e0faae2cce2 https://github.com/tgstation/tgstation/assets/96586172/318d0ee8-de9e-406c-92f1-1f2ef4eac32f https://github.com/tgstation/tgstation/assets/96586172/aa7ae9a1-35c8-44e2-b6ea-82fd3949b1f4 ## Why It's Good For The Game More immersion is great, I love using emotes and having no sounds for them is sad. ## Changelog :cl: grungussuss add: whistle emote refactor: Refactored how laugh, sneeze, cough and cry sound is called in the code, report strange behavior with these emotes. sound: added sounds for whistle, cry, cough, sneeze, laugh for moths and lizards emotes /:cl: --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> --- .../mob/living/carbon/human/_species.dm | 18 ++++- code/modules/mob/living/carbon/human/emote.dm | 38 ++++++++++ .../carbon/human/species_types/felinid.dm | 48 ++++++++++++ .../carbon/human/species_types/humans.dm | 47 ++++++++++++ .../human/species_types/lizardpeople.dm | 43 +++++++++++ .../carbon/human/species_types/mothmen.dm | 46 +++++++++++- code/modules/mob/living/emote.dm | 71 ++++++++++++------ sound/attributions.txt | 24 ++++++ sound/voice/human/female_cough1.ogg | Bin 0 -> 17087 bytes sound/voice/human/female_cough2.ogg | Bin 0 -> 32995 bytes sound/voice/human/female_cough3.ogg | Bin 0 -> 21858 bytes sound/voice/human/female_cough4.ogg | Bin 0 -> 41747 bytes sound/voice/human/female_cough5.ogg | Bin 0 -> 11507 bytes sound/voice/human/female_cough6.ogg | Bin 0 -> 22824 bytes sound/voice/human/female_cry1.ogg | Bin 0 -> 52503 bytes sound/voice/human/female_cry2.ogg | Bin 0 -> 43358 bytes sound/voice/human/female_sneeze1.ogg | Bin 0 -> 22614 bytes sound/voice/human/male_cough1.ogg | Bin 0 -> 21594 bytes sound/voice/human/male_cough2.ogg | Bin 0 -> 24405 bytes sound/voice/human/male_cough3.ogg | Bin 0 -> 18960 bytes sound/voice/human/male_cough4.ogg | Bin 0 -> 24438 bytes sound/voice/human/male_cough5.ogg | Bin 0 -> 28999 bytes sound/voice/human/male_cough6.ogg | Bin 0 -> 23055 bytes sound/voice/human/male_cry1.ogg | Bin 0 -> 21121 bytes sound/voice/human/male_cry2.ogg | Bin 0 -> 56960 bytes sound/voice/human/male_cry3.ogg | Bin 0 -> 19484 bytes sound/voice/human/male_sneeze1.ogg | Bin 0 -> 22260 bytes sound/voice/human/whistle1.ogg | Bin 0 -> 13402 bytes sound/voice/lizard/lizard_laugh1.ogg | Bin 0 -> 48215 bytes sound/voice/moth/moth_laugh1.ogg | Bin 0 -> 102849 bytes 30 files changed, 310 insertions(+), 25 deletions(-) create mode 100644 sound/voice/human/female_cough1.ogg create mode 100644 sound/voice/human/female_cough2.ogg create mode 100644 sound/voice/human/female_cough3.ogg create mode 100644 sound/voice/human/female_cough4.ogg create mode 100644 sound/voice/human/female_cough5.ogg create mode 100644 sound/voice/human/female_cough6.ogg create mode 100644 sound/voice/human/female_cry1.ogg create mode 100644 sound/voice/human/female_cry2.ogg create mode 100644 sound/voice/human/female_sneeze1.ogg create mode 100644 sound/voice/human/male_cough1.ogg create mode 100644 sound/voice/human/male_cough2.ogg create mode 100644 sound/voice/human/male_cough3.ogg create mode 100644 sound/voice/human/male_cough4.ogg create mode 100644 sound/voice/human/male_cough5.ogg create mode 100644 sound/voice/human/male_cough6.ogg create mode 100644 sound/voice/human/male_cry1.ogg create mode 100644 sound/voice/human/male_cry2.ogg create mode 100644 sound/voice/human/male_cry3.ogg create mode 100644 sound/voice/human/male_sneeze1.ogg create mode 100644 sound/voice/human/whistle1.ogg create mode 100644 sound/voice/lizard/lizard_laugh1.ogg create mode 100644 sound/voice/moth/moth_laugh1.ogg diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index 51337a618edf4..8d968fd895589 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -1563,10 +1563,26 @@ GLOBAL_LIST_EMPTY(features_by_species) /datum/species/proc/prepare_human_for_preview(mob/living/carbon/human/human) return -/// Returns the species's scream sound. +/// Returns the species' scream sound. /datum/species/proc/get_scream_sound(mob/living/carbon/human/human) return +/// Returns the species' cry sound. +/datum/species/proc/get_cry_sound(mob/living/carbon/human/human) + return + +/// Returns the species' cough sound. +/datum/species/proc/get_cough_sound(mob/living/carbon/human/human) + return + +/// Returns the species' laugh sound +/datum/species/proc/get_laugh_sound(mob/living/carbon/human/human) + return + +/// Returns the species' sneeze sound. +/datum/species/proc/get_sneeze_sound(mob/living/carbon/human/human) + return + /datum/species/proc/get_types_to_preload() var/list/to_store = list() to_store += mutant_organs diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index b205eb2e2e217..c9f0ffe504618 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -1,12 +1,15 @@ /datum/emote/living/carbon/human mob_type_allowed_typecache = list(/mob/living/carbon/human) + /datum/emote/living/carbon/human/cry key = "cry" key_third_person = "cries" message = "cries." message_mime = "sobs silently." + audio_cooldown = 5 SECONDS emote_type = EMOTE_AUDIBLE | EMOTE_VISIBLE + vary = TRUE stat_allowed = SOFT_CRIT /datum/emote/living/carbon/human/cry/run_emote(mob/user, params, type_override, intentional) @@ -16,6 +19,11 @@ var/mob/living/carbon/human/human_user = user QDEL_IN(human_user.give_emote_overlay(/datum/bodypart_overlay/simple/emote/cry), 12.8 SECONDS) +/datum/emote/living/carbon/human/cry/get_sound(mob/living/carbon/human/user) + if(!istype(user)) + return + return user.dna.species.get_cry_sound(user) + /datum/emote/living/carbon/human/dap key = "dap" key_third_person = "daps" @@ -39,6 +47,36 @@ return ..() return FALSE +/datum/emote/living/carbon/human/cough + key = "cough" + key_third_person = "coughs" + message = "coughs!" + message_mime = "acts out an exaggerated cough!" + vary = TRUE + audio_cooldown = 5 SECONDS + emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE | EMOTE_RUNECHAT + +/datum/emote/living/cough/can_run_emote(mob/user, status_check = TRUE , intentional) + return !HAS_TRAIT(user, TRAIT_SOOTHED_THROAT) && ..() + +/datum/emote/living/carbon/human/cough/get_sound(mob/living/carbon/human/user) + if(!istype(user)) + return + return user.dna.species.get_cough_sound(user) +/datum/emote/living/carbon/human/sneeze + key = "sneeze" + key_third_person = "sneezes" + message = "sneezes." + audio_cooldown = 5 SECONDS + message_mime = "acts out an exaggerated silent sneeze." + vary = TRUE + emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE + +/datum/emote/living/carbon/human/sneeze/get_sound(mob/living/carbon/human/user) + if(!istype(user)) + return + return user.dna.species.get_sneeze_sound(user) + /datum/emote/living/carbon/human/glasses/run_emote(mob/user, params, type_override, intentional) . = ..() var/image/emote_animation = image('icons/mob/human/emote_visuals.dmi', user, "glasses") diff --git a/code/modules/mob/living/carbon/human/species_types/felinid.dm b/code/modules/mob/living/carbon/human/species_types/felinid.dm index 731b6047a0644..528d9a3a0073b 100644 --- a/code/modules/mob/living/carbon/human/species_types/felinid.dm +++ b/code/modules/mob/living/carbon/human/species_types/felinid.dm @@ -50,6 +50,54 @@ features["ears"] = pick("None", "Cat") return features +/datum/species/human/felinid/get_laugh_sound(mob/living/carbon/human/felinid) + if(felinid.physique == FEMALE) + return 'sound/voice/human/womanlaugh.ogg' + return pick( + 'sound/voice/human/manlaugh1.ogg', + 'sound/voice/human/manlaugh2.ogg', + ) + + +/datum/species/human/felinid/get_cough_sound(mob/living/carbon/human/felinid) + if(felinid.physique == FEMALE) + return pick( + 'sound/voice/human/female_cough1.ogg', + 'sound/voice/human/female_cough2.ogg', + 'sound/voice/human/female_cough3.ogg', + 'sound/voice/human/female_cough4.ogg', + 'sound/voice/human/female_cough5.ogg', + 'sound/voice/human/female_cough6.ogg', + ) + return pick( + 'sound/voice/human/male_cough1.ogg', + 'sound/voice/human/male_cough2.ogg', + 'sound/voice/human/male_cough3.ogg', + 'sound/voice/human/male_cough4.ogg', + 'sound/voice/human/male_cough5.ogg', + 'sound/voice/human/male_cough6.ogg', + ) + + +/datum/species/human/felinid/get_cry_sound(mob/living/carbon/human/felinid) + if(felinid.physique == FEMALE) + return pick( + 'sound/voice/human/female_cry1.ogg', + 'sound/voice/human/female_cry2.ogg', + ) + return pick( + 'sound/voice/human/male_cry1.ogg', + 'sound/voice/human/male_cry2.ogg', + 'sound/voice/human/male_cry3.ogg', + ) + + +/datum/species/human/felinid/get_sneeze_sound(mob/living/carbon/human/felinid) + if(felinid.physique == FEMALE) + return 'sound/voice/human/female_sneeze1.ogg' + return 'sound/voice/human/male_sneeze1.ogg' + + /proc/mass_purrbation() for(var/mob in GLOB.human_list) purrbation_apply(mob) diff --git a/code/modules/mob/living/carbon/human/species_types/humans.dm b/code/modules/mob/living/carbon/human/species_types/humans.dm index c7a181027e64e..4c575f8e48c05 100644 --- a/code/modules/mob/living/carbon/human/species_types/humans.dm +++ b/code/modules/mob/living/carbon/human/species_types/humans.dm @@ -34,6 +34,53 @@ 'sound/voice/human/femalescream_5.ogg', ) +/datum/species/human/get_cough_sound(mob/living/carbon/human/human) + if(human.physique == FEMALE) + return pick( + 'sound/voice/human/female_cough1.ogg', + 'sound/voice/human/female_cough2.ogg', + 'sound/voice/human/female_cough3.ogg', + 'sound/voice/human/female_cough4.ogg', + 'sound/voice/human/female_cough5.ogg', + 'sound/voice/human/female_cough6.ogg', + ) + return pick( + 'sound/voice/human/male_cough1.ogg', + 'sound/voice/human/male_cough2.ogg', + 'sound/voice/human/male_cough3.ogg', + 'sound/voice/human/male_cough4.ogg', + 'sound/voice/human/male_cough5.ogg', + 'sound/voice/human/male_cough6.ogg', + ) + +/datum/species/human/get_cry_sound(mob/living/carbon/human/human) + if(human.physique == FEMALE) + return pick( + 'sound/voice/human/female_cry1.ogg', + 'sound/voice/human/female_cry2.ogg', + ) + return pick( + 'sound/voice/human/male_cry1.ogg', + 'sound/voice/human/male_cry2.ogg', + 'sound/voice/human/male_cry3.ogg', + ) + + +/datum/species/human/get_sneeze_sound(mob/living/carbon/human/human) + if(human.physique == FEMALE) + return 'sound/voice/human/female_sneeze1.ogg' + return 'sound/voice/human/male_sneeze1.ogg' + +/datum/species/human/get_laugh_sound(mob/living/carbon/human/human) + if(!ishuman(human)) + return + if(human.physique == FEMALE) + return 'sound/voice/human/womanlaugh.ogg' + return pick( + 'sound/voice/human/manlaugh1.ogg', + 'sound/voice/human/manlaugh2.ogg', + ) + /datum/species/human/get_species_description() return "Humans are the dominant species in the known galaxy. \ Their kind extend from old Earth to the edges of known space." diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm index 3e20d6b1a7750..93167cb689c3e 100644 --- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -71,6 +71,49 @@ 'sound/voice/lizard/lizard_scream_3.ogg', ) +/datum/species/lizard/get_cough_sound(mob/living/carbon/human/lizard) + if(lizard.gender == FEMALE) + return pick( + 'sound/voice/human/female_cough1.ogg', + 'sound/voice/human/female_cough2.ogg', + 'sound/voice/human/female_cough3.ogg', + 'sound/voice/human/female_cough4.ogg', + 'sound/voice/human/female_cough5.ogg', + 'sound/voice/human/female_cough6.ogg', + ) + return pick( + 'sound/voice/human/male_cough1.ogg', + 'sound/voice/human/male_cough2.ogg', + 'sound/voice/human/male_cough3.ogg', + 'sound/voice/human/male_cough4.ogg', + 'sound/voice/human/male_cough5.ogg', + 'sound/voice/human/male_cough6.ogg', + ) + + +/datum/species/lizard/get_cry_sound(mob/living/carbon/human/lizard) + if(lizard.gender == FEMALE) + return pick( + 'sound/voice/human/female_cry1.ogg', + 'sound/voice/human/female_cry2.ogg', + ) + return pick( + 'sound/voice/human/male_cry1.ogg', + 'sound/voice/human/male_cry2.ogg', + 'sound/voice/human/male_cry3.ogg', + ) + + +/datum/species/lizard/get_sneeze_sound(mob/living/carbon/human/lizard) + if(lizard.gender == FEMALE) + return 'sound/voice/human/female_sneeze1.ogg' + return 'sound/voice/human/male_sneeze1.ogg' + +/datum/species/lizard/get_laugh_sound(mob/living/carbon/human) + if(!istype(human)) + return + return 'sound/voice/lizard/lizard_laugh1.ogg' + /datum/species/lizard/get_physical_attributes() return "Lizardpeople can withstand slightly higher temperatures than most species, but they are very vulnerable to the cold \ and can't regulate their body-temperature internally, making the vacuum of space extremely deadly to them." diff --git a/code/modules/mob/living/carbon/human/species_types/mothmen.dm b/code/modules/mob/living/carbon/human/species_types/mothmen.dm index 68fb87142f6c9..86a9180ed07e3 100644 --- a/code/modules/mob/living/carbon/human/species_types/mothmen.dm +++ b/code/modules/mob/living/carbon/human/species_types/mothmen.dm @@ -64,9 +64,53 @@ features["moth_markings"] = pick(GLOB.moth_markings_list) return features -/datum/species/moth/get_scream_sound(mob/living/carbon/human/human) +/datum/species/moth/get_scream_sound(mob/living/carbon/human) return 'sound/voice/moth/scream_moth.ogg' +/datum/species/moth/get_cough_sound(mob/living/carbon/human/moth) + if(moth.gender == FEMALE) + return pick( + 'sound/voice/human/female_cough1.ogg', + 'sound/voice/human/female_cough2.ogg', + 'sound/voice/human/female_cough3.ogg', + 'sound/voice/human/female_cough4.ogg', + 'sound/voice/human/female_cough5.ogg', + 'sound/voice/human/female_cough6.ogg', + ) + return pick( + 'sound/voice/human/male_cough1.ogg', + 'sound/voice/human/male_cough2.ogg', + 'sound/voice/human/male_cough3.ogg', + 'sound/voice/human/male_cough4.ogg', + 'sound/voice/human/male_cough5.ogg', + 'sound/voice/human/male_cough6.ogg', + ) + + +/datum/species/moth/get_cry_sound(mob/living/carbon/human/moth) + if(moth.gender == FEMALE) + return pick( + 'sound/voice/human/female_cry1.ogg', + 'sound/voice/human/female_cry2.ogg', + ) + return pick( + 'sound/voice/human/male_cry1.ogg', + 'sound/voice/human/male_cry2.ogg', + 'sound/voice/human/male_cry3.ogg', + ) + + +/datum/species/moth/get_sneeze_sound(mob/living/carbon/human/moth) + if(moth.gender == FEMALE) + return 'sound/voice/human/female_sneeze1.ogg' + return 'sound/voice/human/male_sneeze1.ogg' + + +/datum/species/moth/get_laugh_sound(mob/living/carbon/human) + if(!istype(human)) + return + return 'sound/voice/moth/moth_laugh1.ogg' + /datum/species/moth/get_physical_attributes() return "Moths have large and fluffy wings, which help them navigate the station if gravity is offline by pushing the air around them. \ Due to that, it isn't of much use out in space. Their eyes are very sensitive." diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm index 9e0d70a6c9d05..960e50d77205f 100644 --- a/code/modules/mob/living/emote.dm +++ b/code/modules/mob/living/emote.dm @@ -67,16 +67,6 @@ var/mob/living/L = user L.Unconscious(40) -/datum/emote/living/cough - key = "cough" - key_third_person = "coughs" - message = "coughs!" - message_mime = "acts out an exaggerated cough!" - emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE | EMOTE_RUNECHAT - -/datum/emote/living/cough/can_run_emote(mob/user, status_check = TRUE , intentional) - return !HAS_TRAIT(user, TRAIT_SOOTHED_THROAT) && ..() - /datum/emote/living/dance key = "dance" key_third_person = "dances" @@ -284,15 +274,11 @@ /datum/emote/living/laugh/can_run_emote(mob/living/user, status_check = TRUE , intentional) return ..() && user.can_speak(allow_mimes = TRUE) -/datum/emote/living/laugh/get_sound(mob/living/user) +/datum/emote/living/laugh/get_sound(mob/living/carbon/user) if(!ishuman(user)) return var/mob/living/carbon/human/human_user = user - if((ishumanbasic(human_user) || isfelinid(human_user)) && !HAS_MIND_TRAIT(human_user, TRAIT_MIMING)) - if(human_user.gender == FEMALE) - return 'sound/voice/human/womanlaugh.ogg' - else - return pick('sound/voice/human/manlaugh1.ogg', 'sound/voice/human/manlaugh2.ogg') + return human_user.dna.species.get_laugh_sound(user) /datum/emote/living/look key = "look" @@ -326,6 +312,38 @@ H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 5) return ..() +/datum/emote/living/carbon/cry + key = "cry" + key_third_person = "cries" + message = "cries." + emote_type = EMOTE_AUDIBLE | EMOTE_VISIBLE + stat_allowed = SOFT_CRIT + mob_type_blacklist_typecache = list(/mob/living/carbon/human) //Humans get specialized cry emote with sound and animation. + +/datum/emote/living/sneeze + key = "sneeze" + key_third_person = "sneezes" + message = "sneezes." + emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE + mob_type_blacklist_typecache = list(/mob/living/carbon/human) //Humans get specialized sneeze emote with sound. + +/datum/emote/living/carbon/human/glasses/run_emote(mob/user, params, type_override, intentional) + . = ..() + var/image/emote_animation = image('icons/mob/human/emote_visuals.dmi', user, "glasses") + flick_overlay_global(emote_animation, GLOB.clients, 1.6 SECONDS) + +/datum/emote/living/carbon/cough + key = "cough" + key_third_person = "coughs" + message = "coughs!" + message_mime = "acts out an exaggerated cough!" + emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE | EMOTE_RUNECHAT + mob_type_blacklist_typecache = list(/mob/living/carbon/human) //Humans get specialized cough emote with sound. + +/datum/emote/living/cough/can_run_emote(mob/user, status_check = TRUE , intentional) + return !HAS_TRAIT(user, TRAIT_SOOTHED_THROAT) && ..() + + /datum/emote/living/pout key = "pout" key_third_person = "pouts" @@ -401,13 +419,6 @@ key_third_person = "smiles" message = "smiles." -/datum/emote/living/sneeze - key = "sneeze" - key_third_person = "sneezes" - message = "sneezes." - message_mime = "acts out an exaggerated silent sneeze." - emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE - /datum/emote/living/smug key = "smug" key_third_person = "smugs" @@ -730,3 +741,17 @@ message = "says a swear word!" message_mime = "makes a rude gesture!" emote_type = EMOTE_AUDIBLE + +/datum/emote/living/carbon/whistle + key = "whistle" + key_third_person = "whistles" + message = "whistles." + message_mime = "whistles silently!" + audio_cooldown = 5 SECONDS + vary = TRUE + emote_type = EMOTE_AUDIBLE | EMOTE_VISIBLE + +/datum/emote/living/carbon/whistle/get_sound(mob/living/user) + if(!istype(user)) + return + return 'sound/voice/human/whistle1.ogg' diff --git a/sound/attributions.txt b/sound/attributions.txt index be8df17c53577..053051a89ec83 100644 --- a/sound/attributions.txt +++ b/sound/attributions.txt @@ -147,3 +147,27 @@ https://freesound.org/people/gynation/sounds/82378/ nightmare_poof.ogg and nightmare_reappear.ogg are comprised of breath_01.wav by Nightflame (CC0) and slide-click.wav by Qat (CC0) https://freesound.org/people/Qat/sounds/108332/ https://freesound.org/people/Nightflame/sounds/368615/ + +modified by grungussuss: +male_sneeze1.ogg: https://freesound.org/people/InspectorJ/sounds/352177/ , license: CC BY 4.0 DEED +male_cry1.ogg: https://freesound.org/people/jacobmathiassen/sounds/254869/ , license: CC BY 4.0 DEED +male_cry2.ogg: https://freesound.org/people/scottemoil/sounds/263776/ , license: CC0 1.0 DEED +male_cry3.ogg: https://freesound.org/people/qubodup/sounds/200428/ , license: CC BY 4.0 DEED +female_cry1.ogg: https://freesound.org/people/Luzanne0/sounds/445299/ , license: CC BY-NC 3.0 DEED +female_cry2.ogg: https://freesound.org/people/Idalize/sounds/408211/ , license: CC BY-NC 4.0 DEED +female_cough1.ogg: https://freesound.org/people/OwlStorm/sounds/151213/ , license: CC0 1.0 DEED +female_cough2.ogg: https://freesound.org/people/thatkellytrna/sounds/425777/ , license: CC0 1.0 DEED +female_cough3.ogg: https://freesound.org/people/Luzanne0/sounds/445293/ , license: CC BY-NC 3.0 DEED +female_cough4.ogg: https://freesound.org/people/Luzanne0/sounds/445293/ , license: CC BY-NC 3.0 DEED +female_cough5.ogg: https://freesound.org/people/DarkNightPrincess/sounds/625322/ , license: CC0 1.0 DEED +female_cough6.ogg: https://freesound.org/people/drotzruhn/sounds/405206/ , license: CC BY 4.0 DEED +male_cough1.ogg: https://freesound.org/people/Harris85/sounds/208761/ , license: CC0 1.0 DEED +male_cough2.ogg: https://freesound.org/people/midwestdocumentary/sounds/722622/ , license: CC0 1.0 DEED +male_cough3.ogg: https://freesound.org/people/hadescolossus/sounds/701162/ , license: CC0 1.0 DEED +male_cough4.ogg: https://freesound.org/people/SoundDesignForYou/sounds/646652/ , license: CC0 1.0 DEED +male_cough5.ogg: https://freesound.org/people/SoundDesignForYou/sounds/646654/ , license: CC0 1.0 DEED +male_cough6.ogg: https://freesound.org/people/SoundDesignForYou/sounds/646656/ , license: CC0 1.0 DEED +lizard_laugh1.ogg: https://youtu.be/I7CX0AS8RNI , License: CC-BY-3.0 +moth_laugh1.ogg: https://github.com/BeeStation/BeeStation-Hornet/blob/11ba3fa04105c93dd96a63ad4afaef4b20c02d0d/sound/emotes/ , license: CC-BY-SA-3.0 +whistle1.ogg: https://freesound.org/people/taure/sounds/411638/ , license: CC0 1.0 DEED + diff --git a/sound/voice/human/female_cough1.ogg b/sound/voice/human/female_cough1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..53af74368c3bfc9a04deb778e1908f3a91e8c84b GIT binary patch literal 17087 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 F_+J3+e@XxV literal 0 HcmV?d00001 diff --git a/sound/voice/human/female_cough2.ogg b/sound/voice/human/female_cough2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..eb3551a31fecbfe39556b092d4a1786bab32e26f GIT binary patch literal 32995 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 z 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 literal 0 HcmV?d00001 diff --git a/sound/voice/human/female_cough3.ogg b/sound/voice/human/female_cough3.ogg new file mode 100644 index 0000000000000000000000000000000000000000..a075963d3b46dda8d071b26f3dfe6acd41d804d9 GIT binary patch literal 21858 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 literal 0 HcmV?d00001 diff --git a/sound/voice/human/female_cough4.ogg b/sound/voice/human/female_cough4.ogg new file mode 100644 index 0000000000000000000000000000000000000000..0136ea42ccff2bb22e6bc3e4b9bf8f55f1f12102 GIT binary patch literal 41747 zcmeFZbyQuy)+o9*4uwK-EAH-vVjCzFE$;3PEiMH%6!+q;#ob+6+^tyA7I!T!chmmP z`Of>^9rwO5?s)&*jF6qo%w(=iNoKOLkT*A124H}HLW%X?%+<{r1&9RXV((yN>G%YK zc~kli%7?$mjUf4_mj4bz6a5nz5d7ah=tafUKmZaH!Y)hJ z0~wE21po{HFrcD;9&08=pBI-+=bjWN`IPHn3rUI#>A^P+XYc)2LdIo+0|0OUgbq0} zcT>u0l+PTWHqs%B&+;8_0U2Vb;wm5Vx8F3zcKNmW)^?-x)JSNW@K6Q-U`g@-Y^A5f zD40ADADRRaJM@zmq&c846lVFMaP*UXlI7U>68rA;PGN53>s`9qanWbYwUg4a?9*z- zew$lDdkpGN>4Eijh2m~e=qDW8O2h-;#IY7JmJ1jB)0v#ss_A|Cr74}dS z@yG;~{3(+n7WV|FxU!0zDl|Cjs=JuZx;W3ecxfgDXg7LkHU?n%#^ZHKCv zhN@Bjpg_e7_w+PCmSsx*|0|klCYb*3BiN#!0RTgJ+4q6C?*o;%5>=lA6XG8Z_XALw zf|Zzh9Jt;(a`ib1K;v7dHv@69Bj>W{{}RHJ*Z}~{PTcc>cmT=`CFUsyZgoe&Sx329 zC@Y>g^1lwgfAj@95b|`h1S<#R$C5ZjJ&(;|@2CGl5)mmOUGzyoiGViG z$?wm|$pF9~VYt zLac~M4UH2V%*vdCsw%4LF1DJ9&I=6zx^vDevtBE+5&C$6|6Q^EZ8-qcX#D@!WSmhr zdtch8ccRFD1^h3|`GDQ`nRwtcl}t62+$7V;DVO{i*94ZhBA1*pj_w4G^AxVBGLP;Q zx9OCs>9mXKe7&i5gO_IgKL+#HY*uES|HE>gOoW0ja!oP@?!PQ2i!SmPZzQEu43%aK zjeCN5NJ>$1#!gWV%73#Qi_n6k(1PI5t>8$ykOa$+l;Wlwo5AwE=KpQ{x8=Nbpn^uI z<%l~_{fFgrvJ;Czt*M$x?(FXv1t*{kbrQ$>PXPcxXEdtJpLs-4iFsOyds>NERYmZB zZ86Z=X)d`bE+}K;0e}Di*1zO`_jrzJ6wMbRVu2*pP28jNdM7PcCp;*cQbOv0TzMD+ zt}ba@DggWYFDz~&p;geWchCo5g>DiR%AetC7&v` zzWz(Ep$~E_iaFy(Lgjmxn3fBtX~0DyoH0SJIK2>$mo zj4=fP5L3+zL;#2}btn0sck}-p`rinGAano_l%s+Bo_Gi*(pVE5!}QER6Oe;-BLriE zo{(Xlo{or%8W)j{%Y+)hfCpCJV-HPoDX#M-I8*Qa6z*#GPd0F zk;l%Ug^-x?~{tSva z#U%&DoQ2P^NXaiMhOQ*wKZw)Lx_H4)uwv-y0`r8VsyiER3bBN?Yc6MkRry;c$SN-0 zZ7ydV0-z4me7vb9!s=70nh5|_J3# zC`z`Wtf(ZpiINfneIAM^19iNTh-BUuB@SukyaXk9^7t6(BC;<^O7!pm$x9n|ExODu39G19YxFi7SH^%5JHceD@4m zsNZT8^W`rjMPTe7?z?CF!(#_ss5G7!MLqN+qoU$s6liG*%BX-Rf48`J?_2#7|7V>I z7oM2E*W3x^yR#`l2 z0v=&CCV+$tmAXhU`!-cvjI=b4XgD7ob$o(WXqjj*J5t`4?^-tOxMO^X*Dx(N!a>cO{;5T{GkeyX)D zeYfO4zg)@1oL#9<0w1;7UTuM)c7K_1gf}(xyX1VkUxTHg6<)qs@MCZVNZIc z^abA$s%B*VPdl+MNPj9spzbA9W(3Cns>t?_Q5uA{c&dPsqt5&Ow*}pkCoEm`?~1&* zIHf;rk^Z>I(5>i`r-}*H-8dy^y8tMSzrHh+At+E9e=4M*TUKmQ_^GK-2INTTma@RHisojCc z$wUUFq|^P7=n;wn!Wr_CViQD%l9W)57}=e|+28VQsEGFAL#J#%0DyhLfrW$(_Vq;t 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 z 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 literal 0 HcmV?d00001 diff --git a/sound/voice/human/female_cough6.ogg b/sound/voice/human/female_cough6.ogg new file mode 100644 index 0000000000000000000000000000000000000000..62938b7b761afc32478e5932b6efc562bb9ead22 GIT binary patch literal 22824 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 E0G-a$ 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 literal 0 HcmV?d00001 diff --git a/sound/voice/human/female_sneeze1.ogg b/sound/voice/human/female_sneeze1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..8fe020a8c7e8adc3b80e1caaa28d75469724396e GIT binary patch literal 22614 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 literal 0 HcmV?d00001 diff --git a/sound/voice/human/male_cough1.ogg b/sound/voice/human/male_cough1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..f553bd855ae943e7b6bd3000c7a4efbcf03a6eaa GIT binary patch literal 21594 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 X74FYC`2MS+Z-B&-C=UMB{)hQrNJ18_ literal 0 HcmV?d00001 diff --git a/sound/voice/human/male_cough2.ogg b/sound/voice/human/male_cough2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..3dcc880175fb5a25d68de521c71819ff267df567 GIT binary patch literal 24405 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 literal 0 HcmV?d00001 diff --git a/sound/voice/human/male_cough3.ogg b/sound/voice/human/male_cough3.ogg new file mode 100644 index 0000000000000000000000000000000000000000..a87ba9cc4c730da6d1630bb46de95b1133defe2f GIT binary patch literal 18960 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 literal 0 HcmV?d00001 diff --git a/sound/voice/human/male_cough4.ogg b/sound/voice/human/male_cough4.ogg new file mode 100644 index 0000000000000000000000000000000000000000..38052dc78711bcadd77af728127c7e482bda69b9 GIT binary patch literal 24438 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

  • 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 literal 0 HcmV?d00001 diff --git a/sound/voice/human/male_cough5.ogg b/sound/voice/human/male_cough5.ogg new file mode 100644 index 0000000000000000000000000000000000000000..5a1b836775dbff6d89c5b4aed8d59690182e3c08 GIT binary patch literal 28999 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 LD3^3*eSrT1N=J;L literal 0 HcmV?d00001 diff --git a/sound/voice/human/male_cry1.ogg b/sound/voice/human/male_cry1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..50ffd0cf72a7df6d77ee3d432128c71dee75a9b5 GIT binary patch literal 21121 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 b=7|PprvEBA26$`4KZ2t81vxo-)T;m#XNJ!V literal 0 HcmV?d00001 diff --git a/sound/voice/human/male_cry2.ogg b/sound/voice/human/male_cry2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..8d35a4d52766983175a8be2236e4d14df6a9b77b GIT binary patch literal 56960 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 z%0A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%0D0w~l;~SG++%-UJrUAZo+}jk2Km(?_<6|5H5CG=S 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 TmeYF5Jv~USJ literal 0 HcmV?d00001 diff --git a/sound/voice/human/whistle1.ogg b/sound/voice/human/whistle1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..41092606597232c9d4ea372bd40a94a398899a21 GIT binary patch literal 13402 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Ǖ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 Y45<5nt0ek%b@$XY%2wS+V@Y~-2x4QdF8}}l literal 0 HcmV?d00001 From bdab65dfc397a856f0a1f20db0bcc5567a621ff3 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 25 Apr 2024 10:15:09 +1200 Subject: [PATCH 467/938] Automatic changelog for PR #82748 [ci skip] --- html/changelogs/AutoChangeLog-pr-82748.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82748.yml diff --git a/html/changelogs/AutoChangeLog-pr-82748.yml b/html/changelogs/AutoChangeLog-pr-82748.yml new file mode 100644 index 0000000000000..267fb8156e1b2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82748.yml @@ -0,0 +1,6 @@ +author: "grungussuss" +delete-after: True +changes: + - rscadd: "whistle emote" + - refactor: "Refactored how laugh, sneeze, cough and cry sound is called in the code, report strange behavior with these emotes." + - sound: "added sounds for whistle, cry, cough, sneeze, laugh for moths and lizards emotes" \ No newline at end of file From 21b6abfcd683522dff7f883a350717f49b391224 Mon Sep 17 00:00:00 2001 From: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Date: Wed, 24 Apr 2024 15:23:54 -0700 Subject: [PATCH 468/938] Redoes how appearance VV works because it scares me (#82851) --- .github/guides/VISUALS.md | 234 ++++++------- code/__DEFINES/vv.dm | 2 - code/_globalvars/bitfields.dm | 13 + .../debug_variable_appearance.dm | 325 +++++------------- .../admin/view_variables/debug_variables.dm | 10 +- .../admin/view_variables/view_variables.dm | 24 +- code/modules/unit_tests/unit_test.dm | 2 - 7 files changed, 237 insertions(+), 373 deletions(-) diff --git a/.github/guides/VISUALS.md b/.github/guides/VISUALS.md index 1c3cc6360c57b..4d8f7d3b585c8 100644 --- a/.github/guides/VISUALS.md +++ b/.github/guides/VISUALS.md @@ -4,10 +4,10 @@ Welcome to a breakdown of visuals and visual effects in our codebase, and in BYO I will be describing all of the existing systems we use, alongside explaining and providing references to BYOND's ref for each tool. -Note, I will not be covering things that are trivial to understand, and which we don't mess with much. +Note, I will not be covering things that are trivial to understand, and which we don't mess with much. For a complete list of byond ref stuff relevant to this topic, see [here](https://www.byond.com/docs/ref/#/atom/var/appearance). -This is to some extent a collation of the BYOND ref, alongside a description of how we actually use these tools. +This is to some extent a collation of the BYOND ref, alongside a description of how we actually use these tools. My hope is after reading this you'll be able to understand and implement different visual effects in our codebase. Also please see the ref entry on the [renderer](https://www.byond.com/docs/ref/#/{notes}/renderer). @@ -53,10 +53,10 @@ You'll find links to the relevant reference entries at the heading of each entry ## Appearances in BYOND - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/appearance) +- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/appearance) Everything that is displayed on the map has an appearance variable that describes exactly how it should be rendered. -To be clear, it doesn't contain EVERYTHING, [plane masters](#planes) exist separately and so do many other factors. +To be clear, it doesn't contain EVERYTHING, [plane masters](#planes) exist separately and so do many other factors. But it sets out a sort of recipe of everything that could effect rendering. Appearances have a few quirks that can be helpful or frustrating depending on what you're trying to do. @@ -65,25 +65,27 @@ To start off with, appearances are static. You can't directly edit an appearance The way to edit them most of the time is to just modify the corresponding variable on the thing the appearance represents. -This doesn't mean it's impossible to modify them directly however. While appearances are static, +This doesn't mean it's impossible to modify them directly however. While appearances are static, their cousins mutable appearances [(Ref Entry)](https://www.byond.com/docs/ref/info.html#/mutable_appearance) **are**. -What we can do is create a new mutable appearance, set its appearance to be a copy of the static one (remember all appearance variables are static), +What we can do is create a new mutable appearance, set its appearance to be a copy of the static one (remember all appearance variables are static), edit it, and then set the desired thing's appearance var to the appearance var of the mutable. Somewhat like this ```byond -// NOTE: we do not actually have access to a raw appearance type, so we will often +// NOTE: we do not actually have access to a raw appearance type, so we will often // Lie to the compiler, and pretend we are using a mutable appearance // This lets us access vars as expected. Be careful with it tho -/proc/mutate_icon_state(mutable_appearance/thing) +/proc/mutate_icon_state(mutable_appearance/thing) var/mutable_appearance/temporary_lad = new() temporary_lad.appearance = thing temporary_lad.icon_state += "haha_owned" return temporary_lad.appearance ``` +> **Note:** More then being static, appearances are unique. Only one copy of each set of appearance vars exists, and when you modify any of those vars, the corrosponding appearance variable changes its value to whatever matches the new hash. That's why appearance vars can induce inconsistent cost on modification. + > **Warning:** BYOND has been observed to have issues with appearance corruption, it's something to be weary of when "realizing" appearances in this manner. ## Overlays @@ -91,7 +93,7 @@ Somewhat like this - [Table of Contents](#table-of-contents) - [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/overlays) (Also see [rendering](https://www.byond.com/docs/ref/#/{notes}/renderer)) -Overlays are a list of static [appearances](#appearances-in-byond) that we render on top of ourselves. +Overlays are a list of static [appearances](#appearances-in-byond) that we render on top of ourselves. Said appearances can be edited via the realizing method mentioned above. Their rendering order is determined by [layer](#layers) and [plane](#planes), but conflicts are resolved based off order of appearance inside the list. @@ -104,67 +106,67 @@ It's not significant, but it is there, and something to be aware of. ### Our Implementation -We use overlays as our primary method of overlaying visuals. +We use overlays as our primary method of overlaying visuals. However, since overlays are COPIES of a thing's appearance, ensuring that they can be cleared is semi troublesome. To solve this problem, we manage most overlays using `update_overlays()`. -This proc is called whenever an atom's appearance is updated with `update_appearance()` -(essentially just a way to tell an object to rerender anything static about it, like icon state or name), +This proc is called whenever an atom's appearance is updated with `update_appearance()` +(essentially just a way to tell an object to rerender anything static about it, like icon state or name), which will often call `update_icon()`. `update_icon()` handles querying the object for its desired icon, and also manages its overlays, by calling `update_overlays()`. -Said proc returns a list of things to turn into static appearances, which are then passed into `add_overlay()`, +Said proc returns a list of things to turn into static appearances, which are then passed into `add_overlay()`, which makes them static with `build_appearance_list()` before queuing an overlay compile. -This list of static appearances is then queued inside a list called `managed_overlays` on `/atom`. +This list of static appearances is then queued inside a list called `managed_overlays` on `/atom`. This is so we can clear old overlays out before running an update. -We actually compile queued overlay builds once every tick using a dedicated subsystem. +We actually compile queued overlay builds once every tick using a dedicated subsystem. This is done to avoid adding/removing/adding again to the overlays list in cases like humans where it's mutated a lot. -You can bypass this managed overlays system if you'd like, using `add_overlay()` and `cut_overlay()`, +You can bypass this managed overlays system if you'd like, using `add_overlay()` and `cut_overlay()`, but this is semi dangerous because you don't by default have a way to "clear" the overlay. Be careful of this. ## Visual Contents - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/vis_contents) +- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/vis_contents) The `vis_contents` list allows you to essentially say "Hey, render this thing ON me". -The definition of "ON" varies significantly with the `vis_flags` value of the *thing* being relayed. -See the ref [here](https://www.byond.com/docs/ref/#/atom/var/vis_flags). +The definition of "ON" varies significantly with the `vis_flags` value of the *thing* being relayed. +See the ref [here](https://www.byond.com/docs/ref/#/atom/var/vis_flags). Some flags of interest: -- `VIS_INHERIT_ID`: This allows you to link the object DIRECTLY to the thing it's drawn on, +- `VIS_INHERIT_ID`: This allows you to link the object DIRECTLY to the thing it's drawn on, so clicking on the `vis_contents`'d object is just like clicking on the thing -- `VIS_INHERIT_PLANE`: We will discuss [planes](#planes) more in future, but we use them to both effect rendering order and apply effects as a group. -This flag changes the plane of any `vis_contents`'d object (while displayed on the source object) to the source's. +- `VIS_INHERIT_PLANE`: We will discuss [planes](#planes) more in future, but we use them to both effect rendering order and apply effects as a group. +This flag changes the plane of any `vis_contents`'d object (while displayed on the source object) to the source's. This is occasionally useful, but should be used with care as it breaks any effects that rely on plane. -Anything inside a `vis_contents` list will have its loc stored in its `vis_locs` variable. +Anything inside a `vis_contents` list will have its loc stored in its `vis_locs` variable. We very rarely use this, primarily just for clearing references from `vis_contents`. -`vis_contents`, unlike `overlays` is a reference, not a copy. So you can update a `vis_contents`'d thing and have it mirror properly. +`vis_contents`, unlike `overlays` is a reference, not a copy. So you can update a `vis_contents`'d thing and have it mirror properly. This is how we do multiz by the by, with uh, some more hell discussed under [multiz](#multiz). -To pay for this additional behavior however, vis_contents has additional cost in maptick. -Because it's not a copy, we need to constantly check if it's changed at all, which leads to cost scaling with player count. +To pay for this additional behavior however, vis_contents has additional cost in maptick. +Because it's not a copy, we need to constantly check if it's changed at all, which leads to cost scaling with player count. Careful how much you use it. ## Images - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/image) +- [Reference Entry](https://www.byond.com/docs/ref/#/image) Images are technically parents of [mutable appearances](#appearances-in-byond). We don't often use them, mostly because we can accomplish their behavior with just MAs. -Images exist both to be used in overlays, and to display things to only select clients on the map. +Images exist both to be used in overlays, and to display things to only select clients on the map. See [/client/var/images](#client-images) > Note: the inheritance between the two is essentially for engine convenience. Don't rely on it. @@ -172,7 +174,7 @@ See [/client/var/images](#client-images) ## Client Images - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/client/var/images) +- [Reference Entry](https://www.byond.com/docs/ref/#/client/var/images) `/client/var/images` is a list of image objects to display to JUST that particular client. @@ -180,35 +182,35 @@ The image objects are displayed at their loc variable, and can be shown to more ### Our Implementation -We use client images in a few ways. Often they will be used just as intended, to modify the view of just one user. +We use client images in a few ways. Often they will be used just as intended, to modify the view of just one user. Think tray scanner or technically ai static. -However, we often want to show a set of images to the same GROUP of people, but in a limited manner. +However, we often want to show a set of images to the same GROUP of people, but in a limited manner. For this, we use the `/datum/atom_hud` (hereafter hud) system. This is different from `/datum/hud`, which I will discuss later. -HUDs are datums that represent categories of images to display to users. +HUDs are datums that represent categories of images to display to users. They are most often global, but can be created on an atom to atom bases in rare cases. They store a list of images to display (sorted by source z level to reduce lag) and a list of clients to display to. -We then mirror this group of images into/out of the client's images list, based on what HUDs they're able to see. +We then mirror this group of images into/out of the client's images list, based on what HUDs they're able to see. This is the pattern we use for things like the medihud, or robot trails. ## View - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/client/var/view) +- [Reference Entry](https://www.byond.com/docs/ref/#/client/var/view) -`/client/var/view` is actually a pretty simple topic, -but I'm gonna take this chance to discuss the other things we do to manage pixel sizing and such since there isn't a better place for it, +`/client/var/view` is actually a pretty simple topic, +but I'm gonna take this chance to discuss the other things we do to manage pixel sizing and such since there isn't a better place for it, and they're handled in the same place by us. Alright then, view. This is pretty simple, but it basically just lets us define the tile bound we want to show to our client. This can either be a number for an X by X square, or a string in the form "XxY" for more control. -We use `/datum/view_data` to manage and track view changes, so zoom effects can work without canceling or being canceled by anything else. +We use `/datum/view_data` to manage and track view changes, so zoom effects can work without canceling or being canceled by anything else. ### Client Rendering Modes @@ -218,29 +220,29 @@ Clients get some choice in literally how they want the game to be rendered to th The two I'm gonna discuss here are `zoom`, and `zoom-mode` mode, both of which are skin params (basically just variables that live on the client) -`zoom` decides how the client wants to display the turfs shown to it. -It can have two types of values. -If it's equal to 0 it will stretch the tiles sent to the client to fix the size of the map-window. -Otherwise, any other numbers will lead to pixels being scaled by some multiple. +`zoom` decides how the client wants to display the turfs shown to it. +It can have two types of values. +If it's equal to 0 it will stretch the tiles sent to the client to fix the size of the map-window. +Otherwise, any other numbers will lead to pixels being scaled by some multiple. This effect can only really result in nice clean edges if you pass in whole numbers which is why most of the constant scaling we give players are whole numbers. -`zoom-mode` controls how a pixel will be up-scaled, if it needs to be. -See the ref for more details, but `normal` is gonna have the sharpest output, `distort` uses nearest neighbor, +`zoom-mode` controls how a pixel will be up-scaled, if it needs to be. +See the ref for more details, but `normal` is gonna have the sharpest output, `distort` uses nearest neighbor, which causes some blur, and `blur` uses bilinear sampling, which causes a LOT of blur. ## Eye - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/client/var/eye) +- [Reference Entry](https://www.byond.com/docs/ref/#/client/var/eye) -`/client/var/eye` is the atom or mob at which our view should be centered. +`/client/var/eye` is the atom or mob at which our view should be centered. Any screen objects we display will show "off" this, as will our actual well eye position. -It is by default `/client/var/mob` but it can be modified. +It is by default `/client/var/mob` but it can be modified. This is how we accomplish ai eyes and ventcrawling, alongside most other effects that involve a player getting "into" something. ## Client Screen - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/{notes}/HUD) +- [Reference Entry](https://www.byond.com/docs/ref/#/{notes}/HUD) Similar to client images but not *quite* the same, we can also insert objects onto our client's literal screen @@ -256,21 +258,21 @@ The classic `screen_loc` format looks something like this (keeping in mind it co The pixel offsets can be discarded as optional, but crucially the x and y values do not NEED to be absolute. -We can use cardinal keywords like `NORTH` to anchor screen objects to the view size of the client (a topic that will be discussed soon). -You can also use directional keywords like `TOP` to anchor to the actual visible map-window, which prevents any accidental out of bounds. -Oh yeah you can use absolute offsets to position screen objects out of the view range, which will cause the map-window to forcefully expand, +We can use cardinal keywords like `NORTH` to anchor screen objects to the view size of the client (a topic that will be discussed soon). +You can also use directional keywords like `TOP` to anchor to the actual visible map-window, which prevents any accidental out of bounds. +Oh yeah you can use absolute offsets to position screen objects out of the view range, which will cause the map-window to forcefully expand, exposing the parts of the map byond uses to ahead of time render border things so moving is smooth. ### Secondary Maps While we're here, this is a bit of a side topic but you can have more then one map-window on a client's screen at once. -This gets into dmf fuckery but you can use [window ids](https://www.byond.com/docs/ref/#/{skin}/param/id) to tell a screen object to render to a secondary map. +This gets into dmf fuckery but you can use [window ids](https://www.byond.com/docs/ref/#/{skin}/param/id) to tell a screen object to render to a secondary map. Useful for creating popup windows and such. ## Blend Mode - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/blend_mode) +- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/blend_mode) `/atom/var/blend_mode` defines how an atom well, renders onto the map. @@ -280,7 +282,7 @@ This is how we do lighting effects, since the lighting [plane](#planes) can be u ## Appearance Flags - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/appearance_flags) +- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/appearance_flags) `/atom/var/appearance_flags` is a catch all for toggles that apply to visual elements of an atom. I won't go over all of them, but I will discuss a few. @@ -293,8 +295,8 @@ Flags of interest: ## Gliding - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/{notes}/gliding) - +- [Reference Entry](https://www.byond.com/docs/ref/#/{notes}/gliding) + You may have noticed that moving between tiles is smooth, or at least as close as we can get it. Moving at 0.2 or 10 tiles per second will be smooth. This is because we have control over the speed at which atoms animate between moves. @@ -306,37 +308,37 @@ This is done using `/atom/movable/proc/set_glide_size`, which will inform anythi Glide size is often set in the context of some rate of movement. Either the movement delay of a mob, set in `/client/Move()`, or the delay of a movement subsystem. We use defines to turn delays into pixels per tick. -Client moves will be limited by `DELAY_TO_GLIDE_SIZE` which will allow at most 32 pixels a tick. -Subsystems and other niche uses use `MOVEMENT_ADJUSTED_GLIDE_SIZE`. -We will also occasionally use glide size as a way to force a transition between different movement types, like space-drift into normal walking. +Client moves will be limited by `DELAY_TO_GLIDE_SIZE` which will allow at most 32 pixels a tick. +Subsystems and other niche uses use `MOVEMENT_ADJUSTED_GLIDE_SIZE`. +We will also occasionally use glide size as a way to force a transition between different movement types, like space-drift into normal walking. There's extra cruft here. -> Something you should know: Our gliding system attempts to account for time dilation when setting move rates. +> Something you should know: Our gliding system attempts to account for time dilation when setting move rates. This is done in a very simplistic way however, so a spike in td will lead to jumping around as glide rate is outpaced by mob movement rate. -On that note, it is VERY important that glide rate is the same or near the same as actual move rate. -Otherwise you will get strange jumping and jitter. +On that note, it is VERY important that glide rate is the same or near the same as actual move rate. +Otherwise you will get strange jumping and jitter. This can also lead to stupid shit where people somehow manage to intentionally shorten a movement delay to jump around. Dumb. Related to the above, we are not always able to maintain sync between glide rate and mob move rate. -This is because mob move rate is a function of the initial move delay and a bunch of slowdown/speedup modifiers. -In order to maintain sync we would need to issue a move command the MOMENT a delay is up, and if delays are not cleanly divisible by our tick rate (0.5 deciseconds) this is impossible. +This is because mob move rate is a function of the initial move delay and a bunch of slowdown/speedup modifiers. +In order to maintain sync we would need to issue a move command the MOMENT a delay is up, and if delays are not cleanly divisible by our tick rate (0.5 deciseconds) this is impossible. This is why you'll sometime see a stutter in your step when slowed Just so you know, client movement works off `/client/var/move_delay` which sets the next time an input will be accepted. It's typically glide rate, but is in some cases just 1 tick. ## Sight - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/mob/var/sight) +- [Reference Entry](https://www.byond.com/docs/ref/#/mob/var/sight) `/mob/var/sight` is a set of bitflags that *mostly* set what HAS to render on your screen. Be that mobs, turfs, etc. That said, there is some nuance here so I'ma get into that. -- `SEE_INFRA`: I'll get into this later, but infrared is essentially a copy of BYOND darkness, it's not something we currently use. -- `SEE_BLACKNESS`: This relates heavily to [planes](#planes), essentially typically the "blackness" (that darkness that masks things that you can't see) -is rendered separately, out of our control as "users". +- `SEE_INFRA`: I'll get into this later, but infrared is essentially a copy of BYOND darkness, it's not something we currently use. +- `SEE_BLACKNESS`: This relates heavily to [planes](#planes), essentially typically the "blackness" (that darkness that masks things that you can't see) +is rendered separately, out of our control as "users". However, if the `SEE_BLACKNESS` flag is set, it will instead render on plane 0, the default BYOND plane. -This allows us to capture it, and say, blur it, or redraw it elsewhere. This is in theory very powerful, but not possible with the 'side_map' [map format](https://www.byond.com/docs/ref/#/world/var/map_format) +This allows us to capture it, and say, blur it, or redraw it elsewhere. This is in theory very powerful, but not possible with the 'side_map' [map format](https://www.byond.com/docs/ref/#/world/var/map_format) ## BYOND Lighting @@ -346,14 +348,14 @@ Alongside OUR lighting implementation, which is discussed in with color matrixes It's very basic. Essentially, a tile is either "lit" or it's not. -If a tile is not lit, and it matches some other preconditions, it and all its contents will be hidden from the user, +If a tile is not lit, and it matches some other preconditions, it and all its contents will be hidden from the user, sort of like if there was a wall between them. This hiding uses BYOND darkness, and is thus controllable. I'll use this section to discuss all the little bits that contribute to this behavior ### Luminosity - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/luminosity) +- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/luminosity) `/atom/var/luminosity` is a variable that lets us inject light into BYOND's lighting system. It's real simple, just a range of tiles that will be lit, respecting sight-lines and such of course. @@ -363,7 +365,7 @@ You can actually force it to use a particular mob's sight to avoid aspects of th ### See in Dark - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/mob/var/see_in_dark) +- [Reference Entry](https://www.byond.com/docs/ref/#/mob/var/see_in_dark) `/mob/var/see_in_dark` sets the radius of a square around the mob that cuts out BYOND darkness. @@ -372,9 +374,9 @@ It's quite simple, but worth describing. ### Infrared - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/mob/var/see_infrared) +- [Reference Entry](https://www.byond.com/docs/ref/#/mob/var/see_infrared) -Infrared vision can be thought of as a hidden copy of standard BYOND darkness. +Infrared vision can be thought of as a hidden copy of standard BYOND darkness. It's not something we actually use, but I think you should know about it, because the whole thing is real confusing without context. ## Invisibility @@ -390,16 +392,16 @@ It's also used to hide some more then ghost invisible things, like some timers a ## Layers - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/layer) +- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/layer) -`/atom/var/layer` is the first bit of logic that decides the order in which things on the map render. -Rendering order depends a LOT on the [map format](https://www.byond.com/docs/ref/#/world/var/map_format), -which I will not get into in this document because it is not yet relevant. -All you really need to know is for our current format, -the objects that appear first in something's contents will draw first, and render lowest. -Think of it like stacking little paper cutouts. +`/atom/var/layer` is the first bit of logic that decides the order in which things on the map render. +Rendering order depends a LOT on the [map format](https://www.byond.com/docs/ref/#/world/var/map_format), +which I will not get into in this document because it is not yet relevant. +All you really need to know is for our current format, +the objects that appear first in something's contents will draw first, and render lowest. +Think of it like stacking little paper cutouts. -Layer has a bit more nuance then just being lowest to highest, tho it's not a lot. +Layer has a bit more nuance then just being lowest to highest, tho it's not a lot. There are a few snowflake layers that can be used to accomplish niche goals, alongside floating layers, which are essentially just any layer that is negative. Floating layers will float "up" the chain of things they're being drawn onto, until they find a real layer. They'll then offset off of that. @@ -408,7 +410,7 @@ This allows us to keep relative layer differences while not needing to make all ## Planes - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/plane) +- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/plane) Allllright `/atom/var/plane`s. Let's talk about em. @@ -417,16 +419,16 @@ Higher planes will (**normally**) render over lower ones. Very clearcut. Similarly to [layers](#layers), planes also support "floating" with `FLOAT_PLANE`. See above for an explanation of that. -However, they can be used for more complex and... fun things too! +However, they can be used for more complex and... fun things too! If a client has an atom with the `PLANE_MASTER` [appearance flag](#appearance-flags) in their [screen](#client-screen), then rather then being all rendered normally, anything in the client's view is instead first rendered onto the plane master. -This is VERY powerful, because it lets us [hide](https://www.byond.com/docs/ref/#/atom/var/alpha), [color](#color), +This is VERY powerful, because it lets us [hide](https://www.byond.com/docs/ref/#/atom/var/alpha), [color](#color), and [distort](#filters) whole classes of objects, among other things. I cannot emphasize enough how useful this is. It does have some downsides however. Because planes are tied to both grouping and rendering order, there are some effects that require splitting a plane into bits. -It's also possible for some effects, especially things relating to [map format](https://www.byond.com/docs/ref/#/world/var/map_format), +It's also possible for some effects, especially things relating to [map format](https://www.byond.com/docs/ref/#/world/var/map_format), to just be straight up impossible, or conflict with each other. It's dumb, but it's what we've got brother so we're gonna use it like it's a free ticket to the bahamas. @@ -434,15 +436,15 @@ We have a system that allows for arbitrary grouping of plane masters for the pur called `/atom/movable/plane_master_controller`. This is somewhat outmoded by our use of [render relays](#render-targetsource), but it's still valid and occasionally useful. -> Something you should know: Plane masters effect ONLY the map their screen_loc is on. +> Something you should know: Plane masters effect ONLY the map their screen_loc is on. For this reason, we are forced to generate whole copies of the set of plane masters with the proper screen_loc to make subviews look right -> Warning: Planes have some restrictions on valid values. They NEED to be whole integers, and they NEED to have an absolute value of `10000`. +> Warning: Planes have some restrictions on valid values. They NEED to be whole integers, and they NEED to have an absolute value of `10000`. This is to support `FLOAT_PLANE`, which lives out at the very edge of the 32 bit int range. ## Render Target/Source - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/render_target) +- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/render_target) Render targets are a way of rendering one thing onto another. Not like vis_contents but in a literal sense ONTO. The target object is given a `/atom/var/render_target` value, and anything that wishes to "take" it sets its `/atom/var/render_source` var to match. @@ -477,8 +479,8 @@ This meant the turf below looked as if it was offset, and everything was good. Except not, for 2 reasons. One more annoying then the other. - 1: It looked like dog doo-doo. This pattern destroyed the old planes of everything vis_contents'd, so effects/lighting/dropshadows broke bad. -- 2: I alluded to this earlier, but it totally breaks the `side_map` [map format](https://www.byond.com/docs/ref/#/world/var/map_format) -which I need for a massive resprite I'm helping with. This is because `side_map` changes how rendering order works, +- 2: I alluded to this earlier, but it totally breaks the `side_map` [map format](https://www.byond.com/docs/ref/#/world/var/map_format) +which I need for a massive resprite I'm helping with. This is because `side_map` changes how rendering order works, going off "distance" from the front of the frame. The issue here is it of course needs a way to group things that are even allowed to overlap, so it uses plane. So when you squish everything down onto one plane, this of course breaks horribly and fucks you. @@ -493,7 +495,7 @@ to the openspace plane master one level up. More then doable. SECOND problem. How do we get everything below to "land" on the right plane? The answer to this is depressing but still true. We manually offset every single object on the map's plane based off its "z layer". -This includes any `overlays` or `vis_contents` with a unique plane value. +This includes any `overlays` or `vis_contents` with a unique plane value. Mostly we require anything that sets the plane var to pass in a source of context, like a turf or something that can be used to derive a turf. There are a few edge cases where we need to work in explicitly offsets, but those are much rarer. @@ -502,18 +504,18 @@ This is stupid, but it's makable, and what we do. ## Mouse Opacity - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/mouse_opacity) +- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/mouse_opacity) `/atom/var/mouse_opacity` tells clients how to treat mousing over the atom in question. A value of 0 means it is completely ignored, no matter what. A value of 1 means it is transparent/opaque based off the alpha of the icon at any particular part. -A value of 2 means it will count as opaque across ALL of the icon-state. All 32x32 (or whatever) of it. +A value of 2 means it will count as opaque across ALL of the icon-state. All 32x32 (or whatever) of it. -We will on occasion use mouse opacity to expand hitboxes, but more often this is done with [vis_contents](#visual-contents), +We will on occasion use mouse opacity to expand hitboxes, but more often this is done with [vis_contents](#visual-contents), or just low alpha pixels on the sprite. -> Note: Mouse opacity will only matter if the atom is being rendered on its own. [Overlays](#overlays)(and [images](#images)) +> Note: Mouse opacity will only matter if the atom is being rendered on its own. [Overlays](#overlays)(and [images](#images)) will NOT work as expected with this. However, you can still have totally transparent overlays. If you render them onto a [plane master](#planes) with the desired mouse opacity value it will work as expected. This is because as a step of the rendering pipeline the overlay is rendered ONTO the plane master, and then the plane @@ -521,10 +523,10 @@ master's effects are applied. ## Filters - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/{notes}/filters) +- [Reference Entry](https://www.byond.com/docs/ref/#/{notes}/filters) Filters are a general purpose system for applying a limited set of shaders to a render. -These shaders run on the client's machine. This has upsides and downsides. +These shaders run on the client's machine. This has upsides and downsides. Upside: Very cheap for the server. Downside: Potentially quite laggy for the client. Take care with these @@ -546,7 +548,7 @@ It'll let you add and tweak *most* of the filters in BYOND. ## Particles - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/{notes}/particles) +- [Reference Entry](https://www.byond.com/docs/ref/#/{notes}/particles) Particles are a system that allows you to attach "generators" to atoms on the world, and have them spit out little visual effects. This is done by creating a subtype of the `/particles` type, and giving it the values you want. @@ -560,7 +562,7 @@ It'll let you add and tweak the particles attached to that atom. ## Pixel Offsets - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/pixel_x) +- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/pixel_x) This is a real simple idea and I normally wouldn't mention it, but I have something else I wanna discuss related to it, so I'ma take this chance. @@ -573,7 +575,7 @@ There are two "types" of each direction offset. There's the "real" offset (x/y) Real offsets will change both the visual position (IE: where it renders) and also the positional position (IE: where the renderer thinks they are). Fake offsets only effect visual position. -This doesn't really matter for our current map format, but for anything that takes position into account when layering, like `side_map` or `isometric_map` +This doesn't really matter for our current map format, but for anything that takes position into account when layering, like `side_map` or `isometric_map` it matters a whole ton. It's kinda a hard idea to get across, but I hope you have at least some idea. ## Map Formats @@ -587,10 +589,10 @@ There are 4 types currently. Only 2 that are interesting to us, and one that's n Most of them involve changing how layering works, from the standard [layers](#layers) and [planes](#planes) method. There's a bit more detail here, not gonna go into it, stuff like [underlays](https://www.byond.com/docs/ref/#/atom/var/underlays) drawing under things. See [Understanding The Renderer](https://www.byond.com/docs/ref/#/{notes}/renderer) -> There is very technically more nuance here. +> There is very technically more nuance here. > In default rendering modes, byond will conflict break by using the thing that is highest in the contents list of its location. Or lowest. Don't remember. -### [`TOPDOWN_MAP`](https://www.byond.com/docs/ref/#/{notes}/topdown) +### [`TOPDOWN_MAP`](https://www.byond.com/docs/ref/#/{notes}/topdown) This is the default rendering format. What we used to use. It tells byond to render going off [plane](#planes) first, then [layer](#layers). There's a few edgecases involving big icons, but it's small peanuts. @@ -606,7 +608,7 @@ The idea is the closer to the front of the screen something is, the higher its l `pixel_y` + `y` tell the engine where something "is". `/atom/var/bound_width`, `/atom/var/bound_height` and `/atom/var/bound_x/y` describe how big it is, which lets us in theory control what it tries to layer "against". -I'm not bothering with reference links because they are entirely unrelated. +I'm not bothering with reference links because they are entirely unrelated. An issue that will crop up with this map format is needing to manage the "visual" (how/where it renders) and physical (where it is in game) aspects of position and size. Physical position tells the renderer how to layer things. Visual position and a combination of physical bounds (manually set) and visual bounds (inferred from other aspects of it. Sprite width/height, physical bounds, transforms, filters, etc) tell it what the sprite might be rendering OVER. @@ -647,28 +649,28 @@ One more thing. Big icons are fucked From the byond reference >If you use an icon wider than one tile, the "footprint" of the isometric icon (the actual map tiles it takes up) will always be a square. That is, if your normal tile size is 64 and you want to show a 128x128 icon, the icon is two tiles wide and so it will take up a 2×2-tile area on the map. The height of a big icon is irrelevant--any excess height beyond width/2 is used to show vertical features. To draw this icon properly, other tiles on that same ground will be moved behind it in the drawing order. -> One important warning about using big icons in isometric mode is that you should only do this with dense atoms. If part of a big mob icon covers the same tile as a tall building for instance, the tall building is moved back and it could be partially covered by other turfs that are actually behind it. A mob walking onto a very large non-dense turf icon would experience similar irregularities. +> One important warning about using big icons in isometric mode is that you should only do this with dense atoms. If part of a big mob icon covers the same tile as a tall building for instance, the tall building is moved back and it could be partially covered by other turfs that are actually behind it. A mob walking onto a very large non-dense turf icon would experience similar irregularities. These can cause very annoying flickering. In fact, MUCH of how rendering works causes flickering. This is because we don't decide on a pixel by pixel case, the engine groups sprites up into a sort of rendering stack, unable to split them up. -This combined with us being unable to modify bounds means that if one bit of the view is conflicting. +This combined with us being unable to modify bounds means that if one bit of the view is conflicting. If A wants to be above B and below C, but B wants to be below A and above C, we'll be unable to resolve the rendering properly, leading to flickering depending on other aspects of the layering. This can just sort of spread. Very hard to debug. -### [`ISOMETRIC_MAP`](https://www.byond.com/docs/ref/#/{notes}/isometric) - +### [`ISOMETRIC_MAP`](https://www.byond.com/docs/ref/#/{notes}/isometric) + Isometric mode, renders everything well, isometrically, biased to the north east. This gives the possibility for fake 3d, assuming you get things drawn properly. It will render things in the foreground "last", after things in the background. This is the right way of thinking about it, it's not rendering things above or below, but in a layering order. This is interesting mostly in the context of understanding [side map](#side_map-check-the-main-page-too), but we did actually run an isometric station for april fools once. It was really cursed and flickered like crazy (which causes client lag). Fun as hell though. -The mode essentially overrides the layer/plane layering discussed before, and inserts new rules. -I wish I knew what those rules EXACTLY are, but I'm betting they're similar to [side map's](#side_map-check-the-main-page-too), and lummy's actually told me those. +The mode essentially overrides the layer/plane layering discussed before, and inserts new rules. +I wish I knew what those rules EXACTLY are, but I'm betting they're similar to [side map's](#side_map-check-the-main-page-too), and lummy's actually told me those. Yes this is all rather poorly documented. Similar to sidemap, we take physical position into account when deciding layering. In addition to its height positioning, we also account for width. -So both `pixel_y` and `pixel_x` can effect layering. `pixel_z` handles strictly visual y, and `pixel_w` handles x. +So both `pixel_y` and `pixel_x` can effect layering. `pixel_z` handles strictly visual y, and `pixel_w` handles x. This has similar big icon problems to [sidemap](#side_map-check-the-main-page-too). @@ -679,14 +681,14 @@ it would be automatically broken down into smaller icon states, which you would ## Color - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/color) +- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/color) `/atom/var/color` is another one like [pixel offsets](#pixel-offsets) where its most common use is really uninteresting, but it has an interesting edge case I think is fun to discuss/important to know. So let's get the base case out of the way shall we? -At base, you can set an atom's color to some `rrggbbaa` string (see [here](https://www.byond.com/docs/ref/#/{{appendix}}/html-colors)). This will shade every pixel on that atom to said color, and override its [`/atom/var/alpha`](https://www.byond.com/docs/ref/#/atom/var/alpha) value. +At base, you can set an atom's color to some `rrggbbaa` string (see [here](https://www.byond.com/docs/ref/#/{{appendix}}/html-colors)). This will shade every pixel on that atom to said color, and override its [`/atom/var/alpha`](https://www.byond.com/docs/ref/#/atom/var/alpha) value. See [appearance flags](#appearance-flags) for how this effect can carry into overlays and such. That's the boring stuff, now the fun shit. @@ -705,7 +707,7 @@ It'll help visualize this process quite well. Play around with it, it's fun. ## Transform - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/transform) +- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/transform) `/atom/var/transform` allows you to shift, contort, rotate and scale atoms visually. This is done using a matrix, similarly to color matrixes. You will likely never need to use it manually however, since there are @@ -732,17 +734,17 @@ and forget to update this file. ## Animate() - [Table of Contents](#table-of-contents) -- [Reference Entry](https://www.byond.com/docs/ref/#/proc/animate) +- [Reference Entry](https://www.byond.com/docs/ref/#/proc/animate) The animate proc allows us to VISUALLY transition between different values on an appearance on clients, while in actuality setting the values instantly on the servers. This is quite powerful, and lets us do many things, like slow fades, shakes, hell even parallax using matrixes. -It doesn't support everything, and it can be quite temperamental especially if you use things like the flag that makes it work in +It doesn't support everything, and it can be quite temperamental especially if you use things like the flag that makes it work in parallel. It's got a lot of nuance to it, but it's real useful. Works on filters and their variables too, which is AGGRESSIVELY useful. -Lets you give radiation glow a warm pulse, that sort of thing. +Lets you give radiation glow a warm pulse, that sort of thing. ## GAGS - [Table of Contents](#table-of-contents) diff --git a/code/__DEFINES/vv.dm b/code/__DEFINES/vv.dm index 90bd77c0423aa..a83ef71ddc69f 100644 --- a/code/__DEFINES/vv.dm +++ b/code/__DEFINES/vv.dm @@ -54,8 +54,6 @@ //Helpers for vv_get_dropdown() #define VV_DROPDOWN_OPTION(href_key, name) . += "" -//Same with VV_DROPDOWN_OPTION, but global proc doesn't have src -#define VV_DROPDOWN_OPTION_APPEARANCE(thing, href_key, name) . += "" // VV HREF KEYS #define VV_HK_TARGET "target" diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 8852e9bb7def9..c62b44e47517d 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -339,6 +339,19 @@ DEFINE_BITFIELD(vis_flags, list( "VIS_UNDERLAY" = VIS_UNDERLAY, )) +// I am so sorry. Required because vis_flags is both undefinable and unreadable on mutable_appearance +// But we need to display them anyway. See /mutable_appearance/appearance_mirror +DEFINE_BITFIELD(_vis_flags, list( + "VIS_HIDE" = VIS_HIDE, + "VIS_INHERIT_DIR" = VIS_INHERIT_DIR, + "VIS_INHERIT_ICON" = VIS_INHERIT_ICON, + "VIS_INHERIT_ICON_STATE" = VIS_INHERIT_ICON_STATE, + "VIS_INHERIT_ID" = VIS_INHERIT_ID, + "VIS_INHERIT_LAYER" = VIS_INHERIT_LAYER, + "VIS_INHERIT_PLANE" = VIS_INHERIT_PLANE, + "VIS_UNDERLAY" = VIS_UNDERLAY, +)) + DEFINE_BITFIELD(zap_flags, list( "ZAP_ALLOW_DUPLICATES" = ZAP_ALLOW_DUPLICATES, "ZAP_MACHINE_EXPLOSIVE" = ZAP_MACHINE_EXPLOSIVE, diff --git a/code/modules/admin/view_variables/debug_variable_appearance.dm b/code/modules/admin/view_variables/debug_variable_appearance.dm index 0d7bbb4b61cc0..9e92eba4605c3 100644 --- a/code/modules/admin/view_variables/debug_variable_appearance.dm +++ b/code/modules/admin/view_variables/debug_variable_appearance.dm @@ -1,236 +1,101 @@ -/* < OH MY GOD. Can't you just make "/image/proc/foo()" instead of making these? > - * /appearance is a hardcoded byond type, and it is very internal type. - * Its type is actually /image, but it isn't truly /image. We defined it as "/appearance" - * new procs to /image will only work to actual /image references, but... - * /appearance references are not capable of executing procs, because these are not real /image - * This is why these global procs exist. Welcome to the curse. - */ -#define ADD_UNUSED_VAR(varlist, thing, varname) if(NAMEOF(##thing, ##varname)) ##varlist += #varname -#define RESULT_VARIABLE_NOT_FOUND "_switch_result_variable_not_found" - -/// An alias datum that allows us to access and view the variables of an appearance by keeping certain known, yet undocumented, variables that we can access and read in a datum for debugging purposes. -/// Kindly do not use this outside of a debugging context. -/image/appearance - parent_type = /atom/movable // This is necessary to access the variables on compile-time. - - // var/override // Sad point. We can't steal byond internal variable name -#ifdef OPENDREAM - // opendream doens't support mouse_drop_zone yet. Remove this once OD supports it. - var/mouse_drop_zone -#endif - -/image/appearance/New(loc, ...) - . = ..() - CRASH("something tried to use '/image/appearance', but this isn't actual type we use. Do not fucking do this.") - -/// Makes a var list of /appearance type actually uses. This will be only called once. -/proc/build_virtual_appearance_vars() - var/list/used_variables = list("vis_flags") // manual listing. - . = used_variables - var/list/unused_var_names = list() - - var/image/appearance/nameof_reference // We don't copy vars from this. - pass(nameof_reference) // compiler complains unused variable - ADD_UNUSED_VAR(unused_var_names, nameof_reference, appearance) // it only does self-reference - ADD_UNUSED_VAR(unused_var_names, nameof_reference, x) // xyz are always 0 - ADD_UNUSED_VAR(unused_var_names, nameof_reference, y) - ADD_UNUSED_VAR(unused_var_names, nameof_reference, z) - ADD_UNUSED_VAR(unused_var_names, nameof_reference, weak_reference) // it's not a good idea to make a weak_ref on this, and this won't have it - ADD_UNUSED_VAR(unused_var_names, nameof_reference, vars) // inherited from /image, but /appearance hasn't this - - // Even if these vars are essential for image, these only exists in an actual type - ADD_UNUSED_VAR(unused_var_names, nameof_reference, filter_data) - ADD_UNUSED_VAR(unused_var_names, nameof_reference, realized_overlays) - ADD_UNUSED_VAR(unused_var_names, nameof_reference, realized_underlays) - - // we have no reason to show these, right? - ADD_UNUSED_VAR(unused_var_names, nameof_reference, _active_timers) - ADD_UNUSED_VAR(unused_var_names, nameof_reference, _datum_components) - ADD_UNUSED_VAR(unused_var_names, nameof_reference, _listen_lookup) - ADD_UNUSED_VAR(unused_var_names, nameof_reference, _signal_procs) - ADD_UNUSED_VAR(unused_var_names, nameof_reference, __auxtools_weakref_id) - ADD_UNUSED_VAR(unused_var_names, nameof_reference, _status_traits) - ADD_UNUSED_VAR(unused_var_names, nameof_reference, cooldowns) - ADD_UNUSED_VAR(unused_var_names, nameof_reference, datum_flags) - ADD_UNUSED_VAR(unused_var_names, nameof_reference, verbs) - ADD_UNUSED_VAR(unused_var_names, nameof_reference, gc_destroyed) - ADD_UNUSED_VAR(unused_var_names, nameof_reference, harddel_deets_dumped) - ADD_UNUSED_VAR(unused_var_names, nameof_reference, open_uis) - ADD_UNUSED_VAR(unused_var_names, nameof_reference, tgui_shared_states) - - var/image/dummy_image = image(null, null) // actual type we'll copy variable names - for(var/each in dummy_image.vars) // try to inherit var list from /image - if(each in unused_var_names) - continue - used_variables += each - del(dummy_image) - dummy_image = null - - return used_variables - -/// debug_variable() proc but made for /appearance type specifically -/proc/debug_variable_appearance(var_name, appearance) - var/value - try - value = locate_appearance_variable(var_name, appearance) - catch - return "

  • (READ ONLY) [var_name] = (untrackable)
  • " - if(value == RESULT_VARIABLE_NOT_FOUND) - return "
  • (READ ONLY) [var_name] (Undefined var name in switch)
  • " - return "
  • (READ ONLY) [var_name] = [_debug_variable_value(var_name, value, 0, appearance, sanitize = TRUE, display_flags = NONE)]
  • " - -/// manually locate a variable through string value. -/// appearance type needs a manual var referencing because it doesn't have "vars" variable internally. -/// There's no way doing this in a fancier way. -/proc/locate_appearance_variable(var_name, image/appearance/appearance) // WARN: /image/appearance is a mocking type, not real one - switch(var_name) // Welcome to this curse - // appearance doesn't have "vars" variable. - // This means you need to target a variable manually through this way. - - // appearance vars in DM document - if(NAMEOF(appearance, alpha)) - return appearance.alpha - if(NAMEOF(appearance, appearance_flags)) - return appearance.appearance_flags - if(NAMEOF(appearance, blend_mode)) - return appearance.blend_mode - if(NAMEOF(appearance, color)) - return appearance.color - if(NAMEOF(appearance, desc)) - return appearance.desc - if(NAMEOF(appearance, gender)) - return appearance.gender - if(NAMEOF(appearance, icon)) - return appearance.icon - if(NAMEOF(appearance, icon_state)) - return appearance.icon_state - if(NAMEOF(appearance, invisibility)) - return appearance.invisibility - if(NAMEOF(appearance, infra_luminosity)) - return appearance.infra_luminosity - if(NAMEOF(appearance, filters)) - return appearance.filters - if(NAMEOF(appearance, layer)) - return appearance.layer - if(NAMEOF(appearance, luminosity)) - return appearance.luminosity - if(NAMEOF(appearance, maptext)) - return appearance.maptext - if(NAMEOF(appearance, maptext_width)) - return appearance.maptext_width - if(NAMEOF(appearance, maptext_height)) - return appearance.maptext_height - if(NAMEOF(appearance, maptext_x)) - return appearance.maptext_x - if(NAMEOF(appearance, maptext_y)) - return appearance.maptext_y - if(NAMEOF(appearance, mouse_over_pointer)) - return appearance.mouse_over_pointer - if(NAMEOF(appearance, mouse_drag_pointer)) - return appearance.mouse_drag_pointer - if(NAMEOF(appearance, mouse_drop_pointer)) - return appearance.mouse_drop_pointer - if(NAMEOF(appearance, mouse_drop_zone)) - return appearance:mouse_drop_zone - if(NAMEOF(appearance, mouse_opacity)) - return appearance.mouse_opacity - if(NAMEOF(appearance, name)) - return appearance.name - if(NAMEOF(appearance, opacity)) - return appearance.opacity - if(NAMEOF(appearance, overlays)) - return appearance.overlays - if("override") // only /image has this. mocking type can't steal byond internal var name - var/image/image_appearance = appearance - return image_appearance.override - if(NAMEOF(appearance, pixel_x)) - return appearance.pixel_x - if(NAMEOF(appearance, pixel_y)) - return appearance.pixel_y - if(NAMEOF(appearance, pixel_w)) - return appearance.pixel_w - if(NAMEOF(appearance, pixel_z)) - return appearance.pixel_z - if(NAMEOF(appearance, plane)) - return appearance.plane - if(NAMEOF(appearance, render_source)) - return appearance.render_source - if(NAMEOF(appearance, render_target)) - return appearance.render_target - if(NAMEOF(appearance, suffix)) - return appearance.suffix - if(NAMEOF(appearance, text)) - return appearance.text - if(NAMEOF(appearance, transform)) - return appearance.transform - if(NAMEOF(appearance, underlays)) - return appearance.underlays - - if(NAMEOF(appearance, parent_type)) - return appearance.parent_type - if(NAMEOF(appearance, type)) - return /image/appearance // don't fool people - - // These are not documented ones but trackable values. Maybe we'd want these. - if(NAMEOF(appearance, animate_movement)) - return appearance.animate_movement - if(NAMEOF(appearance, dir)) - return appearance.dir - if(NAMEOF(appearance, glide_size)) - return appearance.glide_size - if("pixel_step_size") - return "" //atom_appearance.pixel_step_size - // DM compiler complains this - - // I am not sure if these will be ever detected, but I made a connection just in case. - if(NAMEOF(appearance, contents)) // It's not a thing, but I don't believe how DM will change /appearance in future. - return appearance.contents - if(NAMEOF(appearance, loc)) // same reason above - return appearance.loc - if(NAMEOF(appearance, vis_contents)) // same reason above - return appearance.vis_contents - if(NAMEOF(appearance, vis_flags)) // DM document says /appearance has this, but it throws error - return appearance.vis_flags - - // we wouldn't need these, but let's these trackable anyway... - if(NAMEOF(appearance, density)) - return appearance.density - if(NAMEOF(appearance, screen_loc)) - return appearance.screen_loc - if(NAMEOF(appearance, verbs)) - return appearance.verbs - if(NAMEOF(appearance, tag)) - return appearance.tag - return RESULT_VARIABLE_NOT_FOUND - -/// Shows a header name on top when you investigate an appearance -/proc/vv_get_header_appearance(image/thing) +/// Shows a header name on top when you investigate an appearance/image +/image/vv_get_header() . = list() - var/icon_name = "[thing.icon || "null"]
    " + var/icon_name = "[icon || "null"]
    " . += replacetext(icon_name, "icons/obj", "") // shortens the name. We know the path already. - if(thing.icon) - . += thing.icon_state ? "\"[thing.icon_state]\"" : "(icon_state = null)" + if(icon) + . += icon_state ? "\"[icon_state]\"" : "(icon_state = null)" + +/// Makes nice short vv names for images +/image/debug_variable_value(name, level, datum/owner, sanitize, display_flags) + var/display_name = "[type]" + if("[src]" != "[type]") // If we have a name var, let's use it. + display_name = "[src] [type]" + + var/display_value + var/list/icon_file_name = splittext("[icon]", "/") + if(length(icon_file_name)) + display_value = icon_file_name[length(icon_file_name)] + else + display_value = "null" + + if(icon_state) + display_value = "[display_value]:[icon_state]" + + var/display_ref = get_vv_link_ref() + return "
    [display_name] ([display_value]) [display_ref]" + +/// Returns the ref string to use when displaying this image in the vv menu of something else +/image/proc/get_vv_link_ref() + return REF(src) + +// It is endlessly annoying to display /appearance directly for stupid byond reasons, so we copy everything we care about into a holder datum +// That we can override procs on and store other vars on and such. +/mutable_appearance/appearance_mirror + // So people can see where it came from + var/appearance_ref + // vis flags can't be displayed by mutable appearances cause it don't make sense as overlays, but appearances do carry them + // can't use the name either for byond reasons + var/_vis_flags + +// all alone at the end of the universe +GLOBAL_DATUM_INIT(pluto, /atom/movable, new /atom/movable(null)) + +// arg is actually an appearance, typed as mutable_appearance as closest mirror +/mutable_appearance/appearance_mirror/New(mutable_appearance/appearance_father) + . = ..() // /mutable_appearance/New() copies over all the appearance vars MAs care about by default + // We copy over our appearance onto an atom. This is done so we can read vars carried by but not accessible on appearances + GLOB.pluto.appearance = appearance_father + _vis_flags = GLOB.pluto.vis_flags + appearance_ref = REF(appearance_father) + +// This means if the appearance loses refs before a click it's gone, but that's consistent to other datums so it's fine +// Need to ref the APPEARANCE because we just free on our own, which sorta fucks this operation up you know? +/mutable_appearance/appearance_mirror/get_vv_link_ref() + return appearance_ref + +/mutable_appearance/appearance_mirror/can_vv_get(var_name) + var/static/datum/beloved = new() + if(beloved.vars.Find(var_name)) // If datums have it, get out + return FALSE + // If it is one of the two args on /image, yeet (I am sorry) + if(var_name == NAMEOF(src, realized_overlays)) + return FALSE + if(var_name == NAMEOF(src, realized_underlays)) + return FALSE + // Filtering out the stuff I know we don't care about + if(var_name == NAMEOF(src, x)) + return FALSE + if(var_name == NAMEOF(src, y)) + return FALSE + if(var_name == NAMEOF(src, z)) + return FALSE + // Could make an argument for these but I think they will just confuse people, so yeeet +#ifndef SPACEMAN_DMM // Spaceman doesn't believe in contents on appearances, sorry lads + if(var_name == NAMEOF(src, contents)) + return FALSE +#endif + if(var_name == NAMEOF(src, loc)) + return FALSE + if(var_name == NAMEOF(src, vis_contents)) + return FALSE + return ..() -/image/vv_get_header() // it should redirect to global proc version because /appearance can't call a proc, unless we want dupe code here - return vv_get_header_appearance(src) +/mutable_appearance/appearance_mirror/vv_get_var(var_name) + // No editing for you + var/value = vars[var_name] + return "
  • (READ ONLY) [var_name] = [_debug_variable_value(var_name, value, 0, src, sanitize = TRUE, display_flags = NONE)]
  • " -/// Makes a format name for shortened vv name. -/proc/get_appearance_vv_summary_name(image/thing) - var/icon_file_name = thing.icon ? splittext("[thing.icon]", "/") : "null" - if(islist(icon_file_name)) - icon_file_name = length(icon_file_name) ? icon_file_name[length(icon_file_name)] : "null" - if(thing.icon_state) - return "[icon_file_name]:[thing.icon_state]" - else - return "[icon_file_name]" +/mutable_appearance/appearance_mirror/vv_get_dropdown() + SHOULD_CALL_PARENT(FALSE) -/proc/vv_get_dropdown_appearance(image/thing) . = list() - // Don't add any vv option carelessly unless you have a good reason to add one for /appearance. - // /appearance type shouldn't allow general options. Even "Mark Datum" is a questionable behaviour here. - VV_DROPDOWN_OPTION_APPEARANCE(thing, "", "---") - VV_DROPDOWN_OPTION_APPEARANCE(thing, VV_HK_EXPOSE, "Show VV To Player") // only legit option - return . - -#undef ADD_UNUSED_VAR -#undef RESULT_VARIABLE_NOT_FOUND + VV_DROPDOWN_OPTION("", "---") + VV_DROPDOWN_OPTION(VV_HK_CALLPROC, "Call Proc") + VV_DROPDOWN_OPTION(VV_HK_MARK, "Mark Object") + VV_DROPDOWN_OPTION(VV_HK_TAG, "Tag Datum") + VV_DROPDOWN_OPTION(VV_HK_DELETE, "Delete") + VV_DROPDOWN_OPTION(VV_HK_EXPOSE, "Show VV To Player") + +/proc/get_vv_appearance(mutable_appearance/appearance) // actually appearance yadeeyada + return new /mutable_appearance/appearance_mirror(appearance) diff --git a/code/modules/admin/view_variables/debug_variables.dm b/code/modules/admin/view_variables/debug_variables.dm index d64a9c2ef9aac..a4035acd01421 100644 --- a/code/modules/admin/view_variables/debug_variables.dm +++ b/code/modules/admin/view_variables/debug_variables.dm @@ -30,6 +30,9 @@ // This is split into a seperate proc mostly to make errors that happen not break things too much /proc/_debug_variable_value(name, value, level, datum/owner, sanitize, display_flags) + if(isappearance(value)) + value = get_vv_appearance(value) + . = "DISPLAY_ERROR: ([value] [REF(value)])" // Make sure this line can never runtime if(isnull(value)) @@ -49,13 +52,6 @@ return "/icon ([value])" #endif - - if(isappearance(value)) // Reminder: Do not replace this into /image/debug_variable_value() proc. /appearance can't do that. - return "/appearance ([get_appearance_vv_summary_name(value)]) [REF(value)]" - - if(isimage(value)) - return "[value:type] ([get_appearance_vv_summary_name(value)]) [REF(value)]" - if(isfilter(value)) var/datum/filter_value = value return "/filter ([filter_value.type] [REF(filter_value)])" diff --git a/code/modules/admin/view_variables/view_variables.dm b/code/modules/admin/view_variables/view_variables.dm index 45f8ef84c0e03..37bf0911c608f 100644 --- a/code/modules/admin/view_variables/view_variables.dm +++ b/code/modules/admin/view_variables/view_variables.dm @@ -21,9 +21,10 @@ ADMIN_VERB_AND_CONTEXT_MENU(debug_variables, R_NONE, "View Variables", "View the var/datum/asset/asset_cache_datum = get_asset_datum(/datum/asset/simple/vv) asset_cache_datum.send(usr) - var/isappearance = isappearance(thing) + if(isappearance(thing)) + thing = get_vv_appearance(thing) // this is /mutable_appearance/our_bs_subtype var/islist = islist(thing) || (!isdatum(thing) && hascall(thing, "Cut")) // Some special lists dont count as lists, but can be detected by if they have list procs - if(!islist && !isdatum(thing) && !isappearance) + if(!islist && !isdatum(thing)) return var/title = "" @@ -31,7 +32,7 @@ ADMIN_VERB_AND_CONTEXT_MENU(debug_variables, R_NONE, "View Variables", "View the var/icon/sprite var/hash - var/type = islist? /list : (isappearance ? "/appearance" : thing.type) + var/type = islist ? /list : thing.type var/no_icon = FALSE if(isatom(thing)) @@ -39,7 +40,7 @@ ADMIN_VERB_AND_CONTEXT_MENU(debug_variables, R_NONE, "View Variables", "View the if(!sprite) no_icon = TRUE - else if(isimage(thing) || isappearance) + else if(isimage(thing)) // icon_state=null shows first image even if dmi has no icon_state for null name. // This list remembers which dmi has null icon_state, to determine if icon_state=null should display a sprite // (NOTE: icon_state="" is correct, but saying null is obvious) @@ -49,7 +50,7 @@ ADMIN_VERB_AND_CONTEXT_MENU(debug_variables, R_NONE, "View Variables", "View the if(icon_filename_text) if(image_object.icon_state) sprite = icon(image_object.icon, image_object.icon_state) - + else // it means: icon_state="" if(!dmi_nullstate_checklist[icon_filename_text]) dmi_nullstate_checklist[icon_filename_text] = ICON_STATE_CHECKED @@ -69,7 +70,7 @@ ADMIN_VERB_AND_CONTEXT_MENU(debug_variables, R_NONE, "View Variables", "View the title = "[thing] ([REF(thing)]) = [type]" var/formatted_type = replacetext("[type]", "/", "/") - var/list/header = islist ? list("/list") : (isappearance ? vv_get_header_appearance(thing) : thing.vv_get_header()) + var/list/header = islist ? list("/list") : thing.vv_get_header() var/ref_line = "@[copytext(refid, 2, -1)]" // get rid of the brackets, add a @ prefix for copy pasting in asay @@ -103,16 +104,11 @@ ADMIN_VERB_AND_CONTEXT_MENU(debug_variables, R_NONE, "View Variables", "View the var/name = dropdownoptions[i] var/link = dropdownoptions[name] dropdownoptions[i] = "" - else if(isappearance) - dropdownoptions = vv_get_dropdown_appearance(thing) else dropdownoptions = thing.vv_get_dropdown() var/list/names = list() - if(isappearance) - var/static/list/virtual_appearance_vars = build_virtual_appearance_vars() - names = virtual_appearance_vars.Copy() - else if(!islist) + if(!islist) for(var/varname in thing.vars) names += varname @@ -127,10 +123,6 @@ ADMIN_VERB_AND_CONTEXT_MENU(debug_variables, R_NONE, "View Variables", "View the if(IS_NORMAL_LIST(list_value) && IS_VALID_ASSOC_KEY(key)) value = list_value[key] variable_html += debug_variable(i, value, 0, list_value) - else if(isappearance) - names = sort_list(names) - for(var/varname in names) - variable_html += debug_variable_appearance(varname, thing) else names = sort_list(names) for(var/varname in names) diff --git a/code/modules/unit_tests/unit_test.dm b/code/modules/unit_tests/unit_test.dm index fb5bcdf7e117f..332005070d5b6 100644 --- a/code/modules/unit_tests/unit_test.dm +++ b/code/modules/unit_tests/unit_test.dm @@ -222,8 +222,6 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests()) var/list/returnable_list = list() // The following are just generic, singular types. returnable_list = list( - //this is somehow a subtype of /atom/movable, because of its purpose... - /image/appearance, //Never meant to be created, errors out the ass for mobcode reasons /mob/living/carbon, //And another From 72c50845560999416e8b2660a0ffd74f732a1351 Mon Sep 17 00:00:00 2001 From: Fikou <23585223+Fikou@users.noreply.github.com> Date: Thu, 25 Apr 2024 00:25:00 +0200 Subject: [PATCH 469/938] brimbeams are a hidden do after (#82856) --- code/modules/mob/living/basic/lavaland/brimdemon/brimbeam.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/living/basic/lavaland/brimdemon/brimbeam.dm b/code/modules/mob/living/basic/lavaland/brimdemon/brimbeam.dm index 21169ffd36889..61f31f7044dbc 100644 --- a/code/modules/mob/living/basic/lavaland/brimdemon/brimbeam.dm +++ b/code/modules/mob/living/basic/lavaland/brimdemon/brimbeam.dm @@ -44,7 +44,7 @@ StartCooldown() return TRUE - do_after(owner, delay = beam_duration, target = owner) + do_after(owner, delay = beam_duration, target = owner, hidden = TRUE) extinguish_laser() StartCooldown() return TRUE From a27675206712867c04106fa8fcf23ff115916fd8 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 25 Apr 2024 10:26:35 +1200 Subject: [PATCH 470/938] Automatic changelog for PR #82856 [ci skip] --- html/changelogs/AutoChangeLog-pr-82856.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82856.yml diff --git a/html/changelogs/AutoChangeLog-pr-82856.yml b/html/changelogs/AutoChangeLog-pr-82856.yml new file mode 100644 index 0000000000000..2617f30b7e983 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82856.yml @@ -0,0 +1,4 @@ +author: "Fikou" +delete-after: True +changes: + - bugfix: "brimbeams no longer make a cog appear above the mob" \ No newline at end of file From dcc8428a516cb764932265d5b3eb8eb919307355 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Thu, 25 Apr 2024 00:21:59 +0000 Subject: [PATCH 471/938] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-82732.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82748.yml | 6 ------ html/changelogs/AutoChangeLog-pr-82824.yml | 5 ----- html/changelogs/AutoChangeLog-pr-82852.yml | 7 ------- html/changelogs/AutoChangeLog-pr-82856.yml | 4 ---- html/changelogs/archive/2024-04.yml | 20 ++++++++++++++++++++ 6 files changed, 20 insertions(+), 26 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-82732.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82748.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82824.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82852.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82856.yml diff --git a/html/changelogs/AutoChangeLog-pr-82732.yml b/html/changelogs/AutoChangeLog-pr-82732.yml deleted file mode 100644 index 8e03debbfc081..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82732.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Momo8289" -delete-after: True -changes: - - rscadd: "The crew monitor now has sorting options and a search bar." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82748.yml b/html/changelogs/AutoChangeLog-pr-82748.yml deleted file mode 100644 index 267fb8156e1b2..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82748.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "grungussuss" -delete-after: True -changes: - - rscadd: "whistle emote" - - refactor: "Refactored how laugh, sneeze, cough and cry sound is called in the code, report strange behavior with these emotes." - - sound: "added sounds for whistle, cry, cough, sneeze, laugh for moths and lizards emotes" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82824.yml b/html/changelogs/AutoChangeLog-pr-82824.yml deleted file mode 100644 index 38d01cac37b6a..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82824.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "necromanceranne" -delete-after: True -changes: - - balance: "Longfall modules no logner stun you when they activate." - - balance: "Falling from a height greater than one z-level while using the longfall module will still stagger you." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82852.yml b/html/changelogs/AutoChangeLog-pr-82852.yml deleted file mode 100644 index 2cd68a82732e3..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82852.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: "Fikou" -delete-after: True -changes: - - bugfix: "you can no longer take off someones glasses or mask through atmos hardhat" - - bugfix: "once you adjust a welding helmet or something it no longer makes your cigarette or sunglasses invisible" - - bugfix: "welding gas mask works once again" - - bugfix: "quick equips dont drop the item if you cant equip it" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82856.yml b/html/changelogs/AutoChangeLog-pr-82856.yml deleted file mode 100644 index 2617f30b7e983..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82856.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Fikou" -delete-after: True -changes: - - bugfix: "brimbeams no longer make a cog appear above the mob" \ No newline at end of file diff --git a/html/changelogs/archive/2024-04.yml b/html/changelogs/archive/2024-04.yml index 53106bf1f9188..1f04766845988 100644 --- a/html/changelogs/archive/2024-04.yml +++ b/html/changelogs/archive/2024-04.yml @@ -795,3 +795,23 @@ - rscadd: Adds military spear, shortsword, boarding axe, kite shields - rscadd: Adds warlord and crude armor - rscadd: Adds medieval shuttle (made by striders18) +2024-04-25: + Fikou: + - bugfix: brimbeams no longer make a cog appear above the mob + - bugfix: you can no longer take off someones glasses or mask through atmos hardhat + - bugfix: once you adjust a welding helmet or something it no longer makes your + cigarette or sunglasses invisible + - bugfix: welding gas mask works once again + - bugfix: quick equips dont drop the item if you cant equip it + Momo8289: + - rscadd: The crew monitor now has sorting options and a search bar. + grungussuss: + - rscadd: whistle emote + - refactor: Refactored how laugh, sneeze, cough and cry sound is called in the code, + report strange behavior with these emotes. + - sound: added sounds for whistle, cry, cough, sneeze, laugh for moths and lizards + emotes + necromanceranne: + - balance: Longfall modules no logner stun you when they activate. + - balance: Falling from a height greater than one z-level while using the longfall + module will still stagger you. From 13343a02216586bd5e52fa1ddf6715bc289d9461 Mon Sep 17 00:00:00 2001 From: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Date: Wed, 24 Apr 2024 18:19:04 -0700 Subject: [PATCH 472/938] Adds handy define that enables the most common configuration of reftracking (#82860) ## About The Pull Request This shit has confused people too many times, let's give them an easy pathway to use reftracking Also split the separate logging bit into its own thing --- .github/guides/HARDDELETES.md | 12 ++++++------ code/__HELPERS/logging/_logging.dm | 2 +- code/_compile_options.dm | 18 ++++++++++++++++++ code/_globalvars/logging.dm | 2 +- 4 files changed, 26 insertions(+), 8 deletions(-) diff --git a/.github/guides/HARDDELETES.md b/.github/guides/HARDDELETES.md index cdbdb2a126d68..6817de0d9b31a 100644 --- a/.github/guides/HARDDELETES.md +++ b/.github/guides/HARDDELETES.md @@ -1,6 +1,6 @@ # Hard Deletes -> Garbage collection is pretty gothic when you think about it. +> Garbage collection is pretty gothic when you think about it. > >An object in code is like a ghost, clinging to its former life, and especially to the people it knew. It can only pass on and truly die when it has dealt with its unfinished business. And only when its been forgotten by everyone who ever knew it. If even one other object remembers it, it has a connection to the living world that lets it keep hanging on > @@ -52,7 +52,7 @@ This of course means they can store that location in memory in another object's /proc/someshit(mem_location) var/datum/some_obj = new() - some_obj.reference = mem_location + some_obj.reference = mem_location ``` But what happens when you get rid of the object we're passing around references to? If we just cleared it out from memory, everything that holds a reference to it would suddenly be pointing to nowhere, or worse, something totally different! @@ -135,13 +135,13 @@ If that fails, search the object's typepath, and look and see if anything is hol BYOND currently doesn't have the capability to give us information about where a hard delete is. Fortunately we can search for most all of then ourselves. The procs to perform this search are hidden behind compile time defines, since they'd be way too risky to expose to admin button pressing -If you're having issues solving a harddel and want to perform this check yourself, go to `_compile_options.dm` and uncomment `TESTING`, `REFERENCE_TRACKING`, and `GC_FAILURE_HARD_LOOKUP` +If you're having issues solving a harddel and want to perform this check yourself, go to `_compile_options.dm` and uncomment `REFERENCE_TRACKING_STANDARD`. -You can read more about what each of these do in that file, but the long and short of it is if something would hard delete our code will search for the reference (This will look like your game crashing, just hold out) and print information about anything it finds to the runtime log, which you can find inside the round folder inside `/data/logs/year/month/day` +You can read more about what each of these do in that file, but the long and short of it is if something would hard delete our code will search for the reference (This will look like your game crashing, just hold out) and print information about anything it finds to [log_dir]/harddels.log, which you can find inside the round folder inside `/data/logs/year/month/day` -It'll tell you what object is holding the ref if it's in an object, or what pattern of list transversal was required to find the ref if it's hiding in a list of some sort +It'll tell you what object is holding the ref if it's in an object, or what pattern of list transversal was required to find the ref if it's hiding in a list of some sort, alongside the references remaining. -## Techniques For Fixing Hard Deletes +## Techniques For Fixing Hard Deletes Once you've found the issue, it becomes a matter of making sure the ref is cleared as a part of Destroy(). I'm gonna walk you through a few patterns and discuss how you might go about fixing them diff --git a/code/__HELPERS/logging/_logging.dm b/code/__HELPERS/logging/_logging.dm index b7a7b689483c2..bfcaded67f021 100644 --- a/code/__HELPERS/logging/_logging.dm +++ b/code/__HELPERS/logging/_logging.dm @@ -70,7 +70,7 @@ GLOBAL_LIST_INIT(testing_global_profiler, list("_PROFILE_NAME" = "Global")) SEND_TEXT(world.log, text) #endif -#if defined(REFERENCE_DOING_IT_LIVE) +#if defined(REFERENCE_TRACKING_LOG_APART) #define log_reftracker(msg) log_harddel("## REF SEARCH [msg]") /proc/log_harddel(text) diff --git a/code/_compile_options.dm b/code/_compile_options.dm index 0d534fac9a36c..6056a292ed61f 100644 --- a/code/_compile_options.dm +++ b/code/_compile_options.dm @@ -34,6 +34,8 @@ #define FIND_REF_NO_CHECK_TICK #endif //ifdef GC_FAILURE_HARD_LOOKUP +// Log references in their own file, rather then in runtimes.log +//#define REFERENCE_TRACKING_LOG_APART #endif //ifdef REFERENCE_TRACKING /* @@ -60,8 +62,24 @@ #define REFERENCE_TRACKING // actually look for refs #define GC_FAILURE_HARD_LOOKUP +// Log references in their own file +#define REFERENCE_TRACKING_LOG_APART #endif // REFERENCE_DOING_IT_LIVE +/// Sets up the reftracker to be used locally, to hunt for hard deletions +/// Errors are logged to [log_dir]/harddels.log +//#define REFERENCE_TRACKING_STANDARD +#ifdef REFERENCE_TRACKING_STANDARD +// compile the backend +#define REFERENCE_TRACKING +// actually look for refs +#define GC_FAILURE_HARD_LOOKUP +// spend ALL our time searching, not just part of it +#define FIND_REF_NO_CHECK_TICK +// Log references in their own file +#define REFERENCE_TRACKING_LOG_APART +#endif // REFERENCE_TRACKING_STANDARD + // If this is uncommented, we do a single run though of the game setup and tear down process with unit tests in between // #define UNIT_TESTS diff --git a/code/_globalvars/logging.dm b/code/_globalvars/logging.dm index fc6919c3a3b86..3100456691011 100644 --- a/code/_globalvars/logging.dm +++ b/code/_globalvars/logging.dm @@ -33,7 +33,7 @@ GLOBAL_PROTECT(##log_var_name);\ DECLARE_LOG(config_error_log, DONT_START_LOG) DECLARE_LOG(perf_log, DONT_START_LOG) // Declared here but name is set in time_track subsystem -#ifdef REFERENCE_DOING_IT_LIVE +#ifdef REFERENCE_TRACKING_LOG_APART DECLARE_LOG_NAMED(harddel_log, "harddels", START_LOG) #endif From 85b857fc67b1cc0898b9a86b8d0bbbedbd57ed24 Mon Sep 17 00:00:00 2001 From: Singul0 <127663818+Singul0@users.noreply.github.com> Date: Thu, 25 Apr 2024 09:08:53 +0700 Subject: [PATCH 473/938] [NO GBP] Critical fixes for cyborg omnitools (#82825) ## About The Pull Request Fixes several critical fixes for cyborg omnitools, surgical omnitools in peculiar. Which is: 1. bonesetter omnitool can do compound fracture surgery now 2. omnitool butchering not properly disabled works (why didn't that runtime. fucking dreammaker) 3. omnitool surgery_initiator not properly disabled 4. cautery in offhand not working Fixes #82805 Fixes #82868 Honestly I have now regretted for doing this kind of implementation at the start. with how shoddily coded it is. Planning to refactor cyborg omnitools, admin omnitool and ayys omnitool (all have the same base of implementation) to be less snowflakey. but that's for the future. and will take some time. This is a bandaid fix for now ## Why It's Good For The Game this is cbt ## Changelog :cl: fix: fixed cyborg bonesetter not working for compound fractures fix: butchering not disabling in cyborg omnitool fix: fixes a bug where if you select the omnitool it would be stuck in surgery initiator mode fix: cautery in off hand for cyborg omnitools not working /:cl: --- code/datums/components/surgery_initiator.dm | 2 +- code/game/objects/items/robot/items/tools.dm | 4 ++-- code/modules/surgery/bone_mending.dm | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/code/datums/components/surgery_initiator.dm b/code/datums/components/surgery_initiator.dm index dd3251d98f22e..b7f04b517f774 100644 --- a/code/datums/components/surgery_initiator.dm +++ b/code/datums/components/surgery_initiator.dm @@ -139,7 +139,7 @@ for(var/obj/item/borg/cyborg_omnitool/medical/omnitool in user.held_items) if(omnitool.tool_behaviour == TOOL_CAUTERY) has_cautery = TRUE - if(has_cautery) + if(!has_cautery) patient.balloon_alert(user, "need a cautery in an inactive slot to stop the surgery!") return else if(!close_tool || close_tool.tool_behaviour != required_tool_type) diff --git a/code/game/objects/items/robot/items/tools.dm b/code/game/objects/items/robot/items/tools.dm index 0d06e08cf5e3d..49c3197ae1eb6 100644 --- a/code/game/objects/items/robot/items/tools.dm +++ b/code/game/objects/items/robot/items/tools.dm @@ -319,9 +319,9 @@ /obj/item/borg/cyborg_omnitool/medical/reference_item_for_parameters() var/datum/component/butchering/butchering = src.GetComponent(/datum/component/butchering) - butchering.butchering_enabled = tool_behaviour == (TOOL_SCALPEL && TOOL_SAW) + butchering.butchering_enabled = (tool_behaviour == TOOL_SCALPEL || tool_behaviour == TOOL_SAW) RemoveElement(/datum/element/eyestab) - RemoveComponentSource(/datum/component/surgery_initiator) + qdel(GetComponent(/datum/component/surgery_initiator)) item_flags = SURGICAL_TOOL switch(tool_behaviour) if(TOOL_SCALPEL) diff --git a/code/modules/surgery/bone_mending.dm b/code/modules/surgery/bone_mending.dm index 87fc3db0af2c4..ae4ef6e433094 100644 --- a/code/modules/surgery/bone_mending.dm +++ b/code/modules/surgery/bone_mending.dm @@ -48,7 +48,7 @@ /datum/surgery_step/repair_bone_hairline name = "repair hairline fracture (bonesetter/bone gel/tape)" implements = list( - /obj/item/bonesetter = 100, + TOOL_BONESET = 100, /obj/item/stack/medical/bone_gel = 100, /obj/item/stack/sticky_tape/surgical = 100, /obj/item/stack/sticky_tape/super = 50, @@ -98,7 +98,7 @@ /datum/surgery_step/reset_compound_fracture name = "reset bone (bonesetter)" implements = list( - /obj/item/bonesetter = 100, + TOOL_BONESET = 100, /obj/item/stack/sticky_tape/surgical = 60, /obj/item/stack/sticky_tape/super = 40, /obj/item/stack/sticky_tape = 20) From b60223b8a5dd97bc5172f2d801b03a826951faf3 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 25 Apr 2024 14:09:16 +1200 Subject: [PATCH 474/938] Automatic changelog for PR #82825 [ci skip] --- html/changelogs/AutoChangeLog-pr-82825.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82825.yml diff --git a/html/changelogs/AutoChangeLog-pr-82825.yml b/html/changelogs/AutoChangeLog-pr-82825.yml new file mode 100644 index 0000000000000..935842612deef --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82825.yml @@ -0,0 +1,7 @@ +author: "Singul0" +delete-after: True +changes: + - bugfix: "fixed cyborg bonesetter not working for compound fractures" + - bugfix: "butchering not disabling in cyborg omnitool" + - bugfix: "fixes a bug where if you select the omnitool it would be stuck in surgery initiator mode" + - bugfix: "cautery in off hand for cyborg omnitools not working" \ No newline at end of file From f31b2794b5886c9b2a7b63c780f6c09ff9582dbb Mon Sep 17 00:00:00 2001 From: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com> Date: Thu, 25 Apr 2024 06:19:17 +0200 Subject: [PATCH 475/938] fixes ai controllers hard deletes (#82861) ## About The Pull Request ![image](https://github.com/tgstation/tgstation/assets/138636438/47010ad2-64ef-40dd-94d3-b928e4216d1b) i noticed almost all ai controllers were being hard deleted, its because the controller itself was being addedto the behavior_cooldowns list rather than the behavior itself ## Why It's Good For The Game fixes hard deletes ## Changelog :cl: /:cl: --- code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm index f227d5dfea6aa..f0ee4bb9bba37 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm @@ -146,7 +146,7 @@ GLOBAL_LIST_INIT(target_interested_atoms, typecacheof(list(/mob, /obj/machinery/ var/datum/proximity_monitor/field = controller.blackboard[BB_FIND_TARGETS_FIELD(type)] qdel(field) // autoclears so it's fine controller.CancelActions() // On retarget cancel any further queued actions so that they will setup again with new target - controller.modify_cooldown(controller, get_cooldown(controller)) + controller.modify_cooldown(src, get_cooldown(controller)) /// Returns the desired final target from the filtered list of targets /datum/ai_behavior/find_potential_targets/proc/pick_final_target(datum/ai_controller/controller, list/filtered_targets) From 061ce73c99af24c600e4954db4665355fea282a6 Mon Sep 17 00:00:00 2001 From: lessthanthree <83487515+lessthnthree@users.noreply.github.com> Date: Wed, 24 Apr 2024 22:03:43 -0700 Subject: [PATCH 476/938] ChemMaster 3000 printing speed based on servo tier (#82836) ## About The Pull Request Reverts the maximum number of containers (pills/patches/etc.) the ChemMaster 3000 can print back to 50. (Recently changed to 12.5 per tier in https://github.com/tgstation/tgstation/pull/82002) Instead, the servo tier determines the speed the batch is printed at. ![image](https://github.com/tgstation/tgstation/assets/83487515/d58a2325-55ff-4087-b73b-9d08ebdf98e5) ![image](https://github.com/tgstation/tgstation/assets/83487515/5d078957-dbc4-483f-8e38-62a815370f66) ## Why It's Good For The Game Refilling the buffer and pressing print for every 13 pills is pointless busywork when there is already a delay now implemented per pill printed. ## Changelog :cl: LT3 balance: ChemMaster can again print a maximum of 50 pills/patches per run balance: Higher tier servos increase ChemMaster printing speed /:cl: --- .../chemistry/machinery/chem_master.dm | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm index 72e670ef0065b..4524b3f0567ad 100644 --- a/code/modules/reagents/chemistry/machinery/chem_master.dm +++ b/code/modules/reagents/chemistry/machinery/chem_master.dm @@ -1,3 +1,5 @@ +#define MAX_CONTAINER_PRINT_AMOUNT 50 + /obj/machinery/chem_master name = "ChemMaster 3000" desc = "Used to separate chemicals and distribute them in a variety of forms." @@ -26,8 +28,8 @@ var/printing_progress /// Number of containers to be printed var/printing_total - /// The amount of containers that can be printed in 1 cycle - var/printing_amount = 1 + /// The time it takes to print a container + var/printing_speed = 0.75 SECONDS /obj/machinery/chem_master/Initialize(mapload) create_reagents(100) @@ -76,7 +78,7 @@ /obj/machinery/chem_master/examine(mob/user) . = ..() if(in_range(user, src) || isobserver(user)) - . += span_notice("The status display reads:
    Reagent buffer capacity: [reagents.maximum_volume] units.
    Number of containers printed per cycle [printing_amount].") + . += span_notice("The status display reads:
    Reagent buffer capacity: [reagents.maximum_volume] units.
    Printing speed: [0.75 SECONDS / printing_speed * 100]%.") if(!QDELETED(beaker)) . += span_notice("[beaker] of [beaker.reagents.maximum_volume]u capacity inserted") . += span_notice("Right click with empty hand to remove beaker") @@ -149,10 +151,11 @@ for(var/obj/item/reagent_containers/cup/beaker/beaker in component_parts) reagents.maximum_volume += beaker.reagents.maximum_volume - printing_amount = 0 + //Servo tier determines printing speed + printing_speed = 1 SECONDS for(var/datum/stock_part/servo/servo in component_parts) - printing_amount += servo.tier * 12.5 - printing_amount = min(50, ROUND_UP(printing_amount)) + printing_speed -= servo.tier * 0.25 SECONDS + printing_speed = max(printing_speed, 0.25 SECONDS) ///Return a map of category->list of containers this machine can print /obj/machinery/chem_master/proc/load_printable_containers() @@ -264,6 +267,7 @@ /obj/machinery/chem_master/ui_static_data(mob/user) var/list/data = list() + data["maxPrintable"] = MAX_CONTAINER_PRINT_AMOUNT data["categories"] = list() for(var/category in printable_containers) //make the category @@ -293,7 +297,6 @@ .["isPrinting"] = is_printing .["printingProgress"] = printing_progress .["printingTotal"] = printing_total - .["maxPrintable"] = printing_amount //contents of source beaker var/list/beaker_data = null @@ -469,7 +472,7 @@ item_count = text2num(item_count) if(isnull(item_count) || item_count <= 0) return FALSE - item_count = min(item_count, printing_amount) + item_count = min(item_count, MAX_CONTAINER_PRINT_AMOUNT) var/volume_in_each = round(reagents.total_volume / item_count, CHEMICAL_VOLUME_ROUNDING) // Generate item name @@ -529,7 +532,7 @@ //print more items item_count -- if(item_count > 0) - addtimer(CALLBACK(src, PROC_REF(create_containers), user, item_count, item_name, volume_in_each), 0.75 SECONDS) + addtimer(CALLBACK(src, PROC_REF(create_containers), user, item_count, item_name, volume_in_each), printing_speed) else is_printing = FALSE update_appearance(UPDATE_OVERLAYS) @@ -544,3 +547,5 @@ if(!length(containers)) containers = list(CAT_CONDIMENTS = GLOB.reagent_containers[CAT_CONDIMENTS]) return containers + +#undef MAX_CONTAINER_PRINT_AMOUNT From 8b37838ea7658dd5a3b95ea9e3ee23994e17a49f Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 25 Apr 2024 17:04:04 +1200 Subject: [PATCH 477/938] Automatic changelog for PR #82836 [ci skip] --- html/changelogs/AutoChangeLog-pr-82836.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82836.yml diff --git a/html/changelogs/AutoChangeLog-pr-82836.yml b/html/changelogs/AutoChangeLog-pr-82836.yml new file mode 100644 index 0000000000000..f4e79bb05f520 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82836.yml @@ -0,0 +1,5 @@ +author: "LT3" +delete-after: True +changes: + - balance: "ChemMaster can again print a maximum of 50 pills/patches per run" + - balance: "Higher tier servos increase ChemMaster printing speed" \ No newline at end of file From 5154ef4df1beae8afe40792ecc27d7af6bcdef0e Mon Sep 17 00:00:00 2001 From: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com> Date: Thu, 25 Apr 2024 13:28:29 +0200 Subject: [PATCH 478/938] [no gbp] actually fixes bot access (#82809) ## About The Pull Request real fix to bots having AA. also i forgot to address simple bots in my previous attempt so this fixes them too ## Why It's Good For The Game fixes bots having AA ## Changelog :cl: fix: all bots have their normal accesses restored /:cl: --- code/modules/jobs/access.dm | 9 ++++++--- code/modules/mob/living/basic/bots/_bots.dm | 4 ++-- code/modules/mob/living/simple_animal/bot/bot.dm | 15 ++++++++------- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/code/modules/jobs/access.dm b/code/modules/jobs/access.dm index 2055080710e4e..b31574bec33e3 100644 --- a/code/modules/jobs/access.dm +++ b/code/modules/jobs/access.dm @@ -19,6 +19,12 @@ if(isAdminGhostAI(accessor)) //Access can't stop the abuse return TRUE + //If the mob has the simple_access component with the requried access, we let them in. + var/attempted_access = SEND_SIGNAL(accessor, COMSIG_MOB_TRIED_ACCESS, src) + if(attempted_access & ACCESS_ALLOWED) + return TRUE + if(attempted_access & ACCESS_DISALLOWED) + return FALSE if(HAS_SILICON_ACCESS(accessor)) if(ispAI(accessor)) return FALSE @@ -28,9 +34,6 @@ if(onSyndieBase() && loc != accessor) return FALSE return TRUE //AI can do whatever it wants - //If the mob has the simple_access component with the requried access, we let them in. - else if(SEND_SIGNAL(accessor, COMSIG_MOB_TRIED_ACCESS, src) & ACCESS_ALLOWED) - return TRUE //If the mob is holding a valid ID, we let them in. get_active_held_item() is on the mob level, so no need to copypasta everywhere. else if(check_access(accessor.get_active_held_item()) || check_access(accessor.get_inactive_held_item())) return TRUE diff --git a/code/modules/mob/living/basic/bots/_bots.dm b/code/modules/mob/living/basic/bots/_bots.dm index ccd4b0d617f3f..d98369294e018 100644 --- a/code/modules/mob/living/basic/bots/_bots.dm +++ b/code/modules/mob/living/basic/bots/_bots.dm @@ -104,7 +104,7 @@ GLOBAL_LIST_INIT(command_strings, list( AddElement(/datum/element/relay_attackers) RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(handle_loop_movement)) RegisterSignal(src, COMSIG_ATOM_WAS_ATTACKED, PROC_REF(after_attacked)) - RegisterSignal(src, COMSIG_OBJ_ALLOWED, PROC_REF(attempt_access)) + RegisterSignal(src, COMSIG_MOB_TRIED_ACCESS, PROC_REF(attempt_access)) ADD_TRAIT(src, TRAIT_NO_GLIDE, INNATE_TRAIT) GLOB.bots_list += src @@ -757,7 +757,7 @@ GLOBAL_LIST_INIT(command_strings, list( /mob/living/basic/bot/proc/attempt_access(mob/bot, obj/door_attempt) SIGNAL_HANDLER - return (door_attempt.check_access(access_card) ? COMPONENT_OBJ_ALLOW : COMPONENT_OBJ_DISALLOW) + return (door_attempt.check_access(access_card) ? ACCESS_ALLOWED : ACCESS_DISALLOWED) /mob/living/basic/bot/proc/generate_speak_list() return null diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index ec204dbc82b93..944a00af9b63e 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -204,6 +204,7 @@ pa_system = new(src, automated_announcements = automated_announcements) pa_system.Grant(src) + RegisterSignal(src, COMSIG_MOB_TRIED_ACCESS, PROC_REF(attempt_access)) /mob/living/simple_animal/bot/Destroy() GLOB.bots_list -= src @@ -951,13 +952,13 @@ Pass a positive integer as an argument to override a bot's default speed. calc_summon_path() tries = 0 -/mob/living/simple_animal/bot/Bump(atom/A) //Leave no door unopened! - . = ..() - if((istype(A, /obj/machinery/door/airlock) || istype(A, /obj/machinery/door/window)) && (!isnull(access_card))) - var/obj/machinery/door/D = A - if(D.check_access(access_card)) - D.open() - frustration = 0 +/mob/living/simple_animal/bot/proc/attempt_access(mob/bot, obj/door_attempt) + SIGNAL_HANDLER + + if(door_attempt.check_access(access_card)) + frustration = 0 + return ACCESS_ALLOWED + return ACCESS_DISALLOWED /mob/living/simple_animal/bot/ui_data(mob/user) var/list/data = list() From e1d922d9260591edbe1bfc3a8824998f08dd01b4 Mon Sep 17 00:00:00 2001 From: Jeremiah <42397676+jlsnow301@users.noreply.github.com> Date: Thu, 25 Apr 2024 04:28:47 -0700 Subject: [PATCH 479/938] [no gbp] Adds silicon interaction flags (#82822) ## About The Pull Request A few items with special silicon interactions did not have the proper flags to permit their use at distance (airlocks for instance) ## Why It's Good For The Game Fixes #82800 ## Changelog :cl: fix: Restored silicon alt-clicking capability /:cl: --- code/_onclick/ai.dm | 13 +++++++++---- code/game/machinery/doors/airlock.dm | 1 + code/game/machinery/hologram.dm | 1 + code/game/machinery/porta_turret/portable_turret.dm | 1 + code/modules/power/apc/apc_main.dm | 1 + 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm index 93a19ae0219ee..13b0e5c3c1335 100644 --- a/code/_onclick/ai.dm +++ b/code/_onclick/ai.dm @@ -150,6 +150,7 @@ return /atom/proc/ai_click_alt(mob/living/silicon/ai/user) + SHOULD_CALL_PARENT(FALSE) return /atom/proc/AIShiftClick(mob/living/silicon/ai/user) @@ -168,12 +169,13 @@ /obj/machinery/door/airlock/ai_click_alt(mob/living/silicon/ai/user) if(obj_flags & EMAGGED) - return + return NONE if(!secondsElectrified) shock_perm(user) else shock_restore(user) + return CLICK_ACTION_SUCCESS /obj/machinery/door/airlock/AIShiftClick(mob/living/silicon/ai/user) // Opens and closes doors! if(obj_flags & EMAGGED) @@ -237,10 +239,10 @@ /// Toggle APC equipment settings /obj/machinery/power/apc/ai_click_alt(mob/living/silicon/ai/user) if(!can_use(user, loud = TRUE)) - return + return NONE if(!is_operational || failure_timer) - return + return CLICK_ACTION_BLOCKING equipment = equipment ? APC_CHANNEL_OFF : APC_CHANNEL_ON if (user) @@ -250,6 +252,7 @@ user.log_message("turned [enabled_or_disabled] the [src] equipment settings", LOG_GAME) update_appearance() update() + return CLICK_ACTION_SUCCESS /obj/machinery/power/apc/attack_ai_secondary(mob/living/silicon/user, list/modifiers) if(!can_use(user, loud = TRUE)) @@ -261,8 +264,9 @@ /* AI Turrets */ /obj/machinery/turretid/ai_click_alt(mob/living/silicon/ai/user) //toggles lethal on turrets if(ailock) - return + return CLICK_ACTION_BLOCKING toggle_lethal(user) + return CLICK_ACTION_SUCCESS /obj/machinery/turretid/AICtrlClick(mob/living/silicon/ai/user) //turns off/on Turrets if(ailock) @@ -275,6 +279,7 @@ balloon_alert(user, "disrupted all active calls") add_hiddenprint(user) hangup_all_calls() + return CLICK_ACTION_SUCCESS // // Override TurfAdjacent for AltClicking diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 96f7d568f0e16..e32b78d9f776c 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -86,6 +86,7 @@ smoothing_groups = SMOOTH_GROUP_AIRLOCK interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON | INTERACT_MACHINE_OPEN + interaction_flags_click = ALLOW_SILICON_REACH blocks_emissive = EMISSIVE_BLOCK_NONE // Custom emissive blocker. We don't want the normal behavior. ///The type of door frame to drop during deconstruction diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index 16f89fdf3c103..1e06be41952fd 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -47,6 +47,7 @@ Possible to do for anyone motivated enough: armor_type = /datum/armor/machinery_holopad circuit = /obj/item/circuitboard/machine/holopad interaction_flags_atom = parent_type::interaction_flags_atom | INTERACT_ATOM_IGNORE_MOBILITY + interaction_flags_click = ALLOW_SILICON_REACH // Blue, dim light light_power = 0.8 light_color = LIGHT_COLOR_BLUE diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm index 06b1b9778477c..ffbecf911808e 100644 --- a/code/game/machinery/porta_turret/portable_turret.dm +++ b/code/game/machinery/porta_turret/portable_turret.dm @@ -910,6 +910,7 @@ DEFINE_BITFIELD(turret_flags, list( density = FALSE req_access = list(ACCESS_AI_UPLOAD) resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + interaction_flags_click = ALLOW_SILICON_REACH /// Variable dictating if linked turrets are active and will shoot targets var/enabled = TRUE /// Variable dictating if linked turrets will shoot lethal projectiles diff --git a/code/modules/power/apc/apc_main.dm b/code/modules/power/apc/apc_main.dm index 0baf800fa1037..f9ef22e300240 100644 --- a/code/modules/power/apc/apc_main.dm +++ b/code/modules/power/apc/apc_main.dm @@ -17,6 +17,7 @@ damage_deflection = 10 resistance_flags = FIRE_PROOF interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON + interaction_flags_click = ALLOW_SILICON_REACH processing_flags = START_PROCESSING_MANUALLY ///Range of the light emitted when on From 06b97dfb48aa60fb755a2858bf65a753f7d0b013 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 25 Apr 2024 23:28:49 +1200 Subject: [PATCH 480/938] Automatic changelog for PR #82809 [ci skip] --- html/changelogs/AutoChangeLog-pr-82809.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82809.yml diff --git a/html/changelogs/AutoChangeLog-pr-82809.yml b/html/changelogs/AutoChangeLog-pr-82809.yml new file mode 100644 index 0000000000000..a53b8fd9d3711 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82809.yml @@ -0,0 +1,4 @@ +author: "Ben10Omintrix" +delete-after: True +changes: + - bugfix: "all bots have their normal accesses restored" \ No newline at end of file From bb915a714c83dc74a9039db7c68588617b7b161b Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 25 Apr 2024 23:29:06 +1200 Subject: [PATCH 481/938] Automatic changelog for PR #82822 [ci skip] --- html/changelogs/AutoChangeLog-pr-82822.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82822.yml diff --git a/html/changelogs/AutoChangeLog-pr-82822.yml b/html/changelogs/AutoChangeLog-pr-82822.yml new file mode 100644 index 0000000000000..da8b0192fee01 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82822.yml @@ -0,0 +1,4 @@ +author: "jlsnow301" +delete-after: True +changes: + - bugfix: "Restored silicon alt-clicking capability" \ No newline at end of file From 3f9caf5deb158f79b0b6a9e5e20c12fb9ed2fd1d Mon Sep 17 00:00:00 2001 From: KingkumaArt <69398298+KingkumaArt@users.noreply.github.com> Date: Thu, 25 Apr 2024 07:30:50 -0400 Subject: [PATCH 482/938] Fix: Makes the rebar crossbow's bowstring loosen after firing (#82830) ## About The Pull Request As it stands, after the rebar crossbow fires, it must be used inhand twice, once to loosen the bowstring, and a second time with a do_after to pull it back. Not only does this make no sense as the bowstring is what launches the projectile, but I actually had no idea it was even happening, until I got it pointed out on discord. ## Why It's Good For The Game The main reason is that the crossbow shooting a rod without moving the bowstring just looks weird, but also given the first inhand use doesn't have a delay, it also doesn't really serve any purpose. ## Changelog :cl: fix: The rebar crossbows now properly loosen their bowstring upon firing. /:cl: --- code/modules/projectiles/guns/ballistic/rifle.dm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/modules/projectiles/guns/ballistic/rifle.dm b/code/modules/projectiles/guns/ballistic/rifle.dm index 966dd2caf32a3..ac988c2541bc1 100644 --- a/code/modules/projectiles/guns/ballistic/rifle.dm +++ b/code/modules/projectiles/guns/ballistic/rifle.dm @@ -219,6 +219,10 @@ bolt_locked = FALSE update_appearance() +/obj/item/gun/ballistic/rifle/rebarxbow/shoot_live_shot(mob/living/user) + ..() + rack() + /obj/item/gun/ballistic/rifle/rebarxbow/can_shoot() if (bolt_locked) return FALSE From 68115df173aee3a8eff090c3f08beba2f0430b11 Mon Sep 17 00:00:00 2001 From: necromanceranne <40847847+necromanceranne@users.noreply.github.com> Date: Thu, 25 Apr 2024 21:32:05 +1000 Subject: [PATCH 483/938] Fixes plasma flower modsuit cores having an extremely small amount of power (#82842) ## About The Pull Request The var was still using the old values. ## Why It's Good For The Game 15 kj instantly depletes your power supply upon taking a step. Oof. ## Changelog :cl: fix: The plasma flower modsuit core now actually contains a reasonable quantity of power. /:cl: --- code/modules/mod/mod_core.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/mod/mod_core.dm b/code/modules/mod/mod_core.dm index 0d71db68aac2c..e62be77fe557e 100644 --- a/code/modules/mod/mod_core.dm +++ b/code/modules/mod/mod_core.dm @@ -382,8 +382,8 @@ light_power = 1.5 // Slightly better than the normal plasma core. // Not super sure if this should just be the same, but will see. - maxcharge = 15000 - charge = 15000 + maxcharge = 15 * STANDARD_CELL_CHARGE + charge = 15 * STANDARD_CELL_CHARGE /// The mob to be spawned by the core var/mob/living/spawned_mob_type = /mob/living/basic/butterfly/lavaland/temporary /// Max number of mobs it can spawn From 7809dee9001a7c50c95dafa42200b063a8a75ebf Mon Sep 17 00:00:00 2001 From: Joshua Kidder <49173900+Metekillot@users.noreply.github.com> Date: Thu, 25 Apr 2024 07:36:04 -0400 Subject: [PATCH 484/938] Monkey eyes fix and noticable organ display refactor; AI monkeys no longer catatonic (#82669) ## About The Pull Request It turns out monkeys being catatonic got broken 2 years ago in a PR that was meant to fix something else; also, it turns out monkeys are supposed to have primal eyes when turned into humans, and that got broken too. I fixed both of those things, and while I was at it I did a refactor to make it easier to give noticable organs (or anything else that you'd want correct pronoun and verb tenses) easier to implement. 1) AI controlled mobs now properly display their noticable organs when appropriate 2) Added some macros and a helper proc for replacing appropriate pronouns and verb tenses in text 3) The noticable organ HTML is no longer broken, so you can pass text with spans into it, if you want the text to be pretty or big or whatever 4) Monkeys are no longer catatonic if they have an active AI controller; this goes for any carbon actually but I think monkeys are the only one with AI controllers at the moment ## Why It's Good For The Game Fixes the logic for displaying organs on AI controller mobs (currently monkeys) Makes it easier to add these kind of organs for carbons, AI controlled or not, in the future Look! An actual use-case for split editor: ![image](https://github.com/tgstation/tgstation/assets/49173900/8cd0d69e-8091-4431-9418-6bd29e1713b5) ## Changelog Humanized monkeys now have their primal eyes again; monkeys with active AI are no longer catatonic. :cl: Bisar fix: AI controlled monkeys are no longer catatonic, and they have primal eyes again when turned into humans. spellcheck: Noticable organs now have more modular grammar, and their current grammar is fixed. refactor: Refactored the code for displaying the messages for noticable organs. config: Added a documented define of all our pronouns /:cl: --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> --- code/__DEFINES/pronouns.dm | 40 +++++++++++++++++++ code/__HELPERS/pronouns.dm | 23 +++++++++++ code/datums/ai/monkey/monkey_controller.dm | 2 +- code/datums/elements/ai_control_examine.dm | 2 +- code/datums/elements/noticable_organ.dm | 25 ++++++------ .../dna_infuser/organ_sets/carp_organs.dm | 8 ++-- .../dna_infuser/organ_sets/goliath_organs.dm | 8 ++-- .../dna_infuser/organ_sets/gondola_organs.dm | 8 ++-- .../dna_infuser/organ_sets/rat_organs.dm | 8 ++-- .../dna_infuser/organ_sets/roach_organs.dm | 2 +- .../mob/living/carbon/human/examine.dm | 2 +- tgstation.dme | 1 + 12 files changed, 97 insertions(+), 32 deletions(-) create mode 100644 code/__DEFINES/pronouns.dm diff --git a/code/__DEFINES/pronouns.dm b/code/__DEFINES/pronouns.dm new file mode 100644 index 0000000000000..c0515426e353a --- /dev/null +++ b/code/__DEFINES/pronouns.dm @@ -0,0 +1,40 @@ +/// she, he, they, it "%PRONOUN_they" = "p_they" +/// She, He, They, It "%PRONOUN_They" = "p_They" +/// her, his, their, its "%PRONOUN_their" = "p_their" +/// Her, His, Their, Its "%PRONOUN_Their" = "p_Their" +/// hers, his, theirs, its "%PRONOUN_theirs" = "p_theirs" +/// Hers, His, Theirs, Its "%PRONOUN_Theirs" = "p_Theirs" +/// her, him, them, it "%PRONOUN_them" = "p_them" +/// Her, Him, Them, It "%PRONOUN_Them" = "p_Them" +/// has, have "%PRONOUN_have" = "p_have" +/// is, are "%PRONOUN_are" = "p_are" +/// was, were "%PRONOUN_were" = "p_were" +/// does, do "%PRONOUN_do" = "p_do" +/// she has, he has, they have, it has "%PRONOUN_theyve" = "p_theyve" +/// She has, He has, They have, It has "%PRONOUN_Theyve" = "p_Theyve" +/// she is, he is, they are, it is "%PRONOUN_theyre" = "p_theyre" +/// She is, He is, They are, It is "%PRONOUN_Theyre" = "p_Theyre" +/// s, null (she looks, they look) "%PRONOUN_s" = "p_s" +/// es, null (she goes, they go) "%PRONOUN_es" = "p_es" + +/// A list for all the pronoun procs, if you need to iterate or search through it or something. +#define ALL_PRONOUNS list( \ + "%PRONOUN_they" = TYPE_PROC_REF(/datum, p_they), \ + "%PRONOUN_They" = TYPE_PROC_REF(/datum, p_They), \ + "%PRONOUN_their" = TYPE_PROC_REF(/datum, p_their), \ + "%PRONOUN_Their" = TYPE_PROC_REF(/datum, p_Their), \ + "%PRONOUN_theirs" = TYPE_PROC_REF(/datum, p_theirs), \ + "%PRONOUN_Theirs" = TYPE_PROC_REF(/datum, p_Theirs), \ + "%PRONOUN_them" = TYPE_PROC_REF(/datum, p_them), \ + "%PRONOUN_Them" = TYPE_PROC_REF(/datum, p_Them), \ + "%PRONOUN_have" = TYPE_PROC_REF(/datum, p_have), \ + "%PRONOUN_are" = TYPE_PROC_REF(/datum, p_are), \ + "%PRONOUN_were" = TYPE_PROC_REF(/datum, p_were), \ + "%PRONOUN_do" = TYPE_PROC_REF(/datum, p_do), \ + "%PRONOUN_theyve" = TYPE_PROC_REF(/datum, p_theyve), \ + "%PRONOUN_Theyve" = TYPE_PROC_REF(/datum, p_Theyve), \ + "%PRONOUN_theyre" = TYPE_PROC_REF(/datum, p_theyre), \ + "%PRONOUN_Theyre" = TYPE_PROC_REF(/datum, p_Theyre), \ + "%PRONOUN_s" = TYPE_PROC_REF(/datum, p_s), \ + "%PRONOUN_es" = TYPE_PROC_REF(/datum, p_es) \ +) diff --git a/code/__HELPERS/pronouns.dm b/code/__HELPERS/pronouns.dm index df84c1cdcf42a..fe2357d6ce422 100644 --- a/code/__HELPERS/pronouns.dm +++ b/code/__HELPERS/pronouns.dm @@ -1,5 +1,8 @@ +#define GET_TARGET_PRONOUN(target, pronoun, gender) call(target, ALL_PRONOUNS[pronoun])(gender) + //pronoun procs, for getting pronouns without using the text macros that only work in certain positions //datums don't have gender, but most of their subtypes do! + /datum/proc/p_they(temp_gender) return "it" @@ -69,6 +72,26 @@ else return "s" +/// A proc to replace pronouns in a string with the appropriate pronouns for a target atom. +/// Uses associative list access from a __DEFINE list, since associative access is slightly +/// faster +/datum/proc/REPLACE_PRONOUNS(target_string, atom/targeted_atom, targeted_gender = null) + /// If someone specifies targeted_gender we choose that, + /// otherwise we go off the gender of our object + var/gender + if(targeted_gender) + if(!istext(targeted_gender) || !(targeted_gender in list(MALE, FEMALE, PLURAL, NEUTER))) + stack_trace("REPLACE_PRONOUNS called with improper parameters.") + return + gender = targeted_gender + else + gender = targeted_atom.gender + var/regex/pronoun_regex = regex("%PRONOUN(_(they|They|their|Their|theirs|Theirs|them|Them|have|are|were|do|theyve|Theyve|theyre|Theyre|s|es))") + while(pronoun_regex.Find(target_string)) + target_string = pronoun_regex.Replace(target_string, GET_TARGET_PRONOUN(targeted_atom, pronoun_regex.match, gender)) + return target_string + + //like clients, which do have gender. /client/p_they(temp_gender) if(!temp_gender) diff --git a/code/datums/ai/monkey/monkey_controller.dm b/code/datums/ai/monkey/monkey_controller.dm index 215f0a96302f3..693427ba4bd10 100644 --- a/code/datums/ai/monkey/monkey_controller.dm +++ b/code/datums/ai/monkey/monkey_controller.dm @@ -45,7 +45,7 @@ have ways of interacting with a specific mob and control it. /datum/ai_controller/monkey/New(atom/new_pawn) var/static/list/control_examine = list( - ORGAN_SLOT_EYES = span_monkey("eyes have a primal look in them."), + ORGAN_SLOT_EYES = span_monkey("%PRONOUN_They stare%PRONOUN_s around with wild, primal eyes."), ) AddElement(/datum/element/ai_control_examine, control_examine) return ..() diff --git a/code/datums/elements/ai_control_examine.dm b/code/datums/elements/ai_control_examine.dm index b470ac44b49a7..279fc80dc8192 100644 --- a/code/datums/elements/ai_control_examine.dm +++ b/code/datums/elements/ai_control_examine.dm @@ -46,7 +46,7 @@ if(noticable_organ_examines[possibly_noticable.slot]) make_organ_noticable(possibly_noticable.slot, possibly_noticable) -/datum/element/ai_control_examine/proc/make_organ_noticable(organ_slot, obj/item/organ/noticable_organ) +/datum/element/ai_control_examine/proc/make_organ_noticable(organ_slot, obj/item/organ/noticable_organ, mob/living/carbon/human/human_pawn) var/examine_text = noticable_organ_examines[organ_slot] var/body_zone = organ_slot != ORGAN_SLOT_BRAIN ? noticable_organ.zone : null noticable_organ.AddElement(/datum/element/noticable_organ/ai_control, examine_text, body_zone) diff --git a/code/datums/elements/noticable_organ.dm b/code/datums/elements/noticable_organ.dm index 1a6a895e53543..a6247d18bb53b 100644 --- a/code/datums/elements/noticable_organ.dm +++ b/code/datums/elements/noticable_organ.dm @@ -6,15 +6,13 @@ /datum/element/noticable_organ element_flags = ELEMENT_BESPOKE argument_hash_start_idx = 2 - /// whether we wrap the examine text in a notice span. - var/add_span = TRUE - /// "[they]|[their] [desc here]", shows on examining someone with an infused organ. - /// Uses a possessive pronoun (His/Her/Their) if a body zone is given, or a singular pronoun (He/She/They) otherwise. + + ///Shows on examining someone with an infused organ. var/infused_desc - /// Which body zone has to be exposed. If none is set, this is always noticable, and the description pronoun becomes singular instead of possesive. + /// Which body zone has to be exposed. If none is set, this is always noticable. var/body_zone -/datum/element/noticable_organ/Attach(datum/target, infused_desc, body_zone) +/datum/element/noticable_organ/Attach(obj/item/organ/target, infused_desc, body_zone) . = ..() if(!isorgan(target)) @@ -23,8 +21,10 @@ src.infused_desc = infused_desc src.body_zone = body_zone - RegisterSignal(target, COMSIG_ORGAN_IMPLANTED, PROC_REF(on_implanted)) + RegisterSignal(target, COMSIG_ORGAN_IMPLANTED, PROC_REF(enable_description)) RegisterSignal(target, COMSIG_ORGAN_REMOVED, PROC_REF(on_removed)) + if(target.owner) + enable_description(target, target.owner) /datum/element/noticable_organ/Detach(obj/item/organ/target) UnregisterSignal(target, list(COMSIG_ORGAN_IMPLANTED, COMSIG_ORGAN_REMOVED)) @@ -38,7 +38,7 @@ return FALSE return TRUE -/datum/element/noticable_organ/proc/on_implanted(obj/item/organ/target, mob/living/carbon/receiver) +/datum/element/noticable_organ/proc/enable_description(obj/item/organ/target, mob/living/carbon/receiver) SIGNAL_HANDLER RegisterSignal(receiver, COMSIG_ATOM_EXAMINE, PROC_REF(on_receiver_examine)) @@ -53,16 +53,17 @@ if(!should_show_text(examined)) return - var/examine_text = replacetext(replacetext("[body_zone ? examined.p_Their() : examined.p_They()] [infused_desc]", "%PRONOUN_ES", examined.p_es()), "%PRONOUN_S", examined.p_s()) - if(add_span) - examine_text = span_notice(examine_text) + + var/examine_text = REPLACE_PRONOUNS(infused_desc, examined) + + examine_list += examine_text /** * Subtype of noticable organs for AI control, that will make a few more ai status checks before forking over the examine. */ /datum/element/noticable_organ/ai_control - add_span = FALSE + /datum/element/noticable_organ/ai_control/should_show_text(mob/living/carbon/examined) . = ..() diff --git a/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm b/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm index afbb8404060f2..f44de87e92e8e 100644 --- a/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm @@ -27,7 +27,7 @@ /obj/item/organ/internal/lungs/carp/Initialize(mapload) . = ..() - AddElement(/datum/element/noticable_organ, "neck has odd gills.", BODY_ZONE_HEAD) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their neck has odd gills.", BODY_ZONE_HEAD) AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/carp) ADD_TRAIT(src, TRAIT_SPACEBREATHING, REF(src)) @@ -45,7 +45,7 @@ /obj/item/organ/internal/tongue/carp/Initialize(mapload) . = ..() - AddElement(/datum/element/noticable_organ, "teeth are big and sharp.", BODY_ZONE_PRECISE_MOUTH) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their teeth are big and sharp.", BODY_ZONE_PRECISE_MOUTH) AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/carp) /obj/item/organ/internal/tongue/carp/on_mob_insert(mob/living/carbon/tongue_owner, special, movement_flags) @@ -113,7 +113,7 @@ /obj/item/organ/internal/brain/carp/Initialize(mapload) . = ..() AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/carp) - AddElement(/datum/element/noticable_organ, "seem%PRONOUN_S unable to stay still.") + AddElement(/datum/element/noticable_organ, "%PRONOUN_They seem%PRONOUN_S unable to stay still.") /obj/item/organ/internal/brain/carp/on_mob_insert(mob/living/carbon/brain_owner) . = ..() @@ -151,7 +151,7 @@ /obj/item/organ/internal/heart/carp/Initialize(mapload) . = ..() - AddElement(/datum/element/noticable_organ, "skin has small patches of scales growing on it.", BODY_ZONE_CHEST) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their skin has small patches of scales growing on it.", BODY_ZONE_CHEST) AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/carp) #undef CARP_ORGAN_COLOR diff --git a/code/game/machinery/dna_infuser/organ_sets/goliath_organs.dm b/code/game/machinery/dna_infuser/organ_sets/goliath_organs.dm index f9ccf16812bc7..ac3dae39b7019 100644 --- a/code/game/machinery/dna_infuser/organ_sets/goliath_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/goliath_organs.dm @@ -31,7 +31,7 @@ /obj/item/organ/internal/eyes/night_vision/goliath/Initialize(mapload) . = ..() - AddElement(/datum/element/noticable_organ, "eyes are blood red and stone-like.", BODY_ZONE_PRECISE_EYES) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their eyes are blood red and stone-like.", BODY_ZONE_PRECISE_EYES) AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/goliath) ///goliath lungs! You can breathe lavaland air mix but can't breath pure O2 from a tank anymore. @@ -46,7 +46,7 @@ /obj/item/organ/internal/lungs/lavaland/goliath/Initialize(mapload) . = ..() - AddElement(/datum/element/noticable_organ, "back is covered in small tendrils.", BODY_ZONE_CHEST) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their back is covered in small tendrils.", BODY_ZONE_CHEST) AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/goliath) ///goliath brain. you can't use gloves but one of your arms becomes a tendril hammer that can be used to mine! @@ -63,7 +63,7 @@ /obj/item/organ/internal/brain/goliath/Initialize(mapload) . = ..() - AddElement(/datum/element/noticable_organ, "arm is just a mass of plate and tendrils.", BODY_ZONE_CHEST) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their arm is just a mass of plate and tendrils.", BODY_ZONE_CHEST) AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/goliath) /obj/item/organ/internal/brain/goliath/on_mob_insert(mob/living/carbon/brain_owner) @@ -170,7 +170,7 @@ /obj/item/organ/internal/heart/goliath/Initialize(mapload) . = ..() - AddElement(/datum/element/noticable_organ, "skin has visible hard plates growing from within.", BODY_ZONE_CHEST) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their skin has visible hard plates growing from within.", BODY_ZONE_CHEST) AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/goliath) AddElement(/datum/element/update_icon_blocker) diff --git a/code/game/machinery/dna_infuser/organ_sets/gondola_organs.dm b/code/game/machinery/dna_infuser/organ_sets/gondola_organs.dm index 96e41a57789bd..a36ebc1d3c3a9 100644 --- a/code/game/machinery/dna_infuser/organ_sets/gondola_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/gondola_organs.dm @@ -31,7 +31,7 @@ Fluoride Stare: After someone says 5 words, blah blah blah... /obj/item/organ/internal/heart/gondola/Initialize(mapload) . = ..() AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/gondola) - AddElement(/datum/element/noticable_organ, "radiate%PRONOUN_S an aura of serenity.") + AddElement(/datum/element/noticable_organ, "%PRONOUN_They radiate%PRONOUN_S an aura of serenity.") /obj/item/organ/internal/heart/gondola/Insert(mob/living/carbon/receiver, special, movement_flags) . = ..() @@ -60,7 +60,7 @@ Fluoride Stare: After someone says 5 words, blah blah blah... /obj/item/organ/internal/tongue/gondola/Initialize(mapload) . = ..() - AddElement(/datum/element/noticable_organ, "mouth is permanently affixed into a relaxed smile.", BODY_ZONE_PRECISE_MOUTH) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their mouth is permanently affixed into a relaxed smile.", BODY_ZONE_PRECISE_MOUTH) AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/gondola) /obj/item/organ/internal/tongue/gondola/Insert(mob/living/carbon/tongue_owner, special, movement_flags) @@ -83,8 +83,8 @@ Fluoride Stare: After someone says 5 words, blah blah blah... /obj/item/organ/internal/liver/gondola/Initialize(mapload) . = ..() AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/gondola) - AddElement(/datum/element/noticable_organ, "left arm has small needles breaching the skin all over it.", BODY_ZONE_L_ARM) - AddElement(/datum/element/noticable_organ, "right arm has small needles breaching the skin all over it.", BODY_ZONE_R_ARM) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their left arm has small needles breaching the skin all over it.", BODY_ZONE_L_ARM) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their right arm has small needles breaching the skin all over it.", BODY_ZONE_R_ARM) /obj/item/organ/internal/liver/gondola/Insert(mob/living/carbon/liver_owner, special, movement_flags) . = ..() diff --git a/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm b/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm index f19f3d725c711..56b147ffbee11 100644 --- a/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm @@ -29,7 +29,7 @@ /obj/item/organ/internal/eyes/night_vision/rat/Initialize(mapload) . = ..() - AddElement(/datum/element/noticable_organ, "eyes have deep, shifty black pupils, surrounded by a sickening yellow sclera.", BODY_ZONE_PRECISE_EYES) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their eyes have deep, shifty black pupils, surrounded by a sickening yellow sclera.", BODY_ZONE_PRECISE_EYES) AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/rat) ///increases hunger, disgust recovers quicker, expands what is defined as "food" @@ -47,7 +47,7 @@ /obj/item/organ/internal/stomach/rat/Initialize(mapload) . = ..() AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/rat) - AddElement(/datum/element/noticable_organ, "mouth is drooling excessively.", BODY_ZONE_PRECISE_MOUTH) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their mouth is drooling excessively.", BODY_ZONE_PRECISE_MOUTH) /// makes you smaller, walk over tables, and take 1.5x damage /obj/item/organ/internal/heart/rat @@ -61,7 +61,7 @@ /obj/item/organ/internal/heart/rat/Initialize(mapload) . = ..() AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/rat) - AddElement(/datum/element/noticable_organ, "hunch%PRONOUN_ES over unnaturally!") + AddElement(/datum/element/noticable_organ, "%PRONOUN_They hunch%PRONOUN_ES over unnaturally!") /obj/item/organ/internal/heart/rat/on_mob_insert(mob/living/carbon/receiver) . = ..() @@ -98,7 +98,7 @@ /obj/item/organ/internal/tongue/rat/Initialize(mapload) . = ..() - AddElement(/datum/element/noticable_organ, "teeth are oddly shaped and yellowing.", BODY_ZONE_PRECISE_MOUTH) + AddElement(/datum/element/noticable_organ, "%PRONOUN_Their teeth are oddly shaped and yellowing.", BODY_ZONE_PRECISE_MOUTH) AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/rat) /obj/item/organ/internal/tongue/rat/modify_speech(datum/source, list/speech_args) diff --git a/code/game/machinery/dna_infuser/organ_sets/roach_organs.dm b/code/game/machinery/dna_infuser/organ_sets/roach_organs.dm index 0644bca0354a6..11880a50cb2bc 100644 --- a/code/game/machinery/dna_infuser/organ_sets/roach_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/roach_organs.dm @@ -63,7 +63,7 @@ /obj/item/organ/internal/heart/roach/Initialize(mapload) . = ..() - AddElement(/datum/element/noticable_organ, "has hardened, somewhat translucent skin.") + AddElement(/datum/element/noticable_organ, "%PRONOUN_They %PRONOUN_have hardened, somewhat translucent skin.") AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/roach) roach_shell = new() diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 5b2864da4e399..141c904419152 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -321,7 +321,7 @@ if(CONSCIOUS) if(HAS_TRAIT(src, TRAIT_DUMB)) msg += "[t_He] [t_has] a stupid expression on [t_his] face.\n" - if(get_organ_by_type(/obj/item/organ/internal/brain)) + if(get_organ_by_type(/obj/item/organ/internal/brain) && isnull(ai_controller)) if(!key) msg += "[span_deadsay("[t_He] [t_is] totally catatonic. The stresses of life in deep-space must have been too much for [t_him]. Any recovery is unlikely.")]\n" else if(!client) diff --git a/tgstation.dme b/tgstation.dme index 6f9067bcd4f1a..44305244e0950 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -182,6 +182,7 @@ #include "code\__DEFINES\procpath.dm" #include "code\__DEFINES\profile.dm" #include "code\__DEFINES\projectiles.dm" +#include "code\__DEFINES\pronouns.dm" #include "code\__DEFINES\qdel.dm" #include "code\__DEFINES\quirks.dm" #include "code\__DEFINES\radiation.dm" From 698ec3557f175566ef75235c32820dd05e5104fa Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 25 Apr 2024 23:36:44 +1200 Subject: [PATCH 485/938] Automatic changelog for PR #82830 [ci skip] --- html/changelogs/AutoChangeLog-pr-82830.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82830.yml diff --git a/html/changelogs/AutoChangeLog-pr-82830.yml b/html/changelogs/AutoChangeLog-pr-82830.yml new file mode 100644 index 0000000000000..deae02b96804f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82830.yml @@ -0,0 +1,4 @@ +author: "KingkumaArt" +delete-after: True +changes: + - bugfix: "The rebar crossbows now properly loosen their bowstring upon firing." \ No newline at end of file From c379e2577b3890ccfc4fca4d082e728337f05c37 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 25 Apr 2024 23:37:20 +1200 Subject: [PATCH 486/938] Automatic changelog for PR #82842 [ci skip] --- html/changelogs/AutoChangeLog-pr-82842.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82842.yml diff --git a/html/changelogs/AutoChangeLog-pr-82842.yml b/html/changelogs/AutoChangeLog-pr-82842.yml new file mode 100644 index 0000000000000..63022a3e15925 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82842.yml @@ -0,0 +1,4 @@ +author: "necromanceranne" +delete-after: True +changes: + - bugfix: "The plasma flower modsuit core now actually contains a reasonable quantity of power." \ No newline at end of file From a6fa9d2d08dab9f72a6fe269344f85e8766fd6d9 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 25 Apr 2024 23:38:03 +1200 Subject: [PATCH 487/938] Automatic changelog for PR #82669 [ci skip] --- html/changelogs/AutoChangeLog-pr-82669.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82669.yml diff --git a/html/changelogs/AutoChangeLog-pr-82669.yml b/html/changelogs/AutoChangeLog-pr-82669.yml new file mode 100644 index 0000000000000..dc03cf8c8fc5a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82669.yml @@ -0,0 +1,7 @@ +author: "Bisar" +delete-after: True +changes: + - bugfix: "AI controlled monkeys are no longer catatonic, and they have primal eyes again when turned into humans." + - spellcheck: "Noticable organs now have more modular grammar, and their current grammar is fixed." + - refactor: "Refactored the code for displaying the messages for noticable organs." + - config: "Added a documented define of all our pronouns" \ No newline at end of file From a9b9d43750b62cae28d06d3ec35857218ef1da05 Mon Sep 17 00:00:00 2001 From: tralezab <40974010+tralezab@users.noreply.github.com> Date: Thu, 25 Apr 2024 11:56:42 -0700 Subject: [PATCH 488/938] DNA Infusion Refactor: Separates DNA Infusion Behavior from DNA Infuser (#82829) ## About The Pull Request - infuser entries global is now an assoc list type -> singleton. makes it easier to pick specific entries as needed - separated infusion behavior onto both movable level (for machine occupants and things that can potentially be infused) and human level (for the actual infusion into a human) - [x] tested ## Why It's Good For The Game Upcoming plans is to fix up maintenance sect's organ replacement system that just so happens to work a lot like how infusions do with actual infusion mechanics, and that requires this prerequisite. In general outside of that vision I see a lot of potential in alternate infusion sources, from wherever they may be. ## Changelog no player side changes, this is a refactor --- .../game/machinery/dna_infuser/dna_infuser.dm | 101 ++++-------------- .../machinery/dna_infuser/dna_infusion.dm | 75 +++++++++++++ .../machinery/dna_infuser/infuser_book.dm | 2 +- .../machinery/dna_infuser/infuser_entry.dm | 11 +- code/modules/unit_tests/organ_set_bonus.dm | 2 +- tgstation.dme | 1 + 6 files changed, 100 insertions(+), 92 deletions(-) create mode 100644 code/game/machinery/dna_infuser/dna_infusion.dm diff --git a/code/game/machinery/dna_infuser/dna_infuser.dm b/code/game/machinery/dna_infuser/dna_infuser.dm index 6c239089f5d60..7b5fcb501a046 100644 --- a/code/game/machinery/dna_infuser/dna_infuser.dm +++ b/code/game/machinery/dna_infuser/dna_infuser.dm @@ -64,8 +64,7 @@ balloon_alert(user, "not while it's on!") return if(occupant && infusing_from) - // Abort infusion if the occupant is invalid. - if(!is_valid_occupant(occupant, user)) + if(!occupant.can_infuse(user)) playsound(src, 'sound/machines/scanbuzz.ogg', 35, vary = TRUE) return balloon_alert(user, "starting DNA infusion...") @@ -77,92 +76,45 @@ var/mob/living/carbon/human/human_occupant = occupant infusing = TRUE visible_message(span_notice("[src] hums to life, beginning the infusion process!")) + + infusing_into = infusing_from.get_infusion_entry() var/fail_title = "" - var/fail_reason = "" - // Replace infusing_into with a [/datum/infuser_entry] - for(var/datum/infuser_entry/entry as anything in GLOB.infuser_entries) - if(entry.tier == DNA_MUTANT_UNOBTAINABLE) - continue - if(is_type_in_list(infusing_from, entry.input_obj_or_mob)) - if(entry.tier > max_tier_allowed) - fail_title = "Overcomplexity" - fail_reason = "DNA too complicated to infuse. The machine needs to infuse simpler DNA first." - infusing_into = entry - break - if(!infusing_into) - //no valid recipe, so you get a fly mutation - if(!fail_reason) - fail_title = "Unknown DNA" - fail_reason = "Unknown DNA. Consult the \"DNA infusion book\"." - infusing_into = GLOB.infuser_entries[1] + var/fail_explanation = "" + if(istype(infusing_into, /datum/infuser_entry/fly)) + fail_title = "Unknown DNA" + fail_explanation = "Unknown DNA. Consult the \"DNA infusion book\"." + if(infusing_into.tier > max_tier_allowed) + infusing_into = GLOB.infuser_entries[/datum/infuser_entry/fly] + fail_title = "Overcomplexity" + fail_explanation = "DNA too complicated to infuse. The machine needs to infuse simpler DNA first." playsound(src, 'sound/machines/blender.ogg', 50, vary = TRUE) to_chat(human_occupant, span_danger("Little needles repeatedly prick you!")) human_occupant.take_overall_damage(10) human_occupant.add_mob_memory(/datum/memory/dna_infusion, protagonist = human_occupant, deuteragonist = infusing_from, mutantlike = infusing_into.infusion_desc) Shake(duration = INFUSING_TIME) addtimer(CALLBACK(human_occupant, TYPE_PROC_REF(/mob, emote), "scream"), INFUSING_TIME - 1 SECONDS) - addtimer(CALLBACK(src, PROC_REF(end_infuse), fail_reason, fail_title), INFUSING_TIME) + addtimer(CALLBACK(src, PROC_REF(end_infuse), fail_explanation, fail_title), INFUSING_TIME) update_appearance() -/obj/machinery/dna_infuser/proc/end_infuse(fail_reason, fail_title) - if(infuse_organ(occupant)) +/obj/machinery/dna_infuser/proc/end_infuse(fail_explanation, fail_title) + var/mob/living/carbon/human/human_occupant = occupant + if(human_occupant.infuse_organ(infusing_into)) + check_tier_progression(src) to_chat(occupant, span_danger("You feel yourself becoming more... [infusing_into.infusion_desc]?")) infusing = FALSE infusing_into = null QDEL_NULL(infusing_from) playsound(src, 'sound/machines/microwave/microwave-end.ogg', 100, vary = FALSE) - if(fail_reason) + if(fail_explanation) playsound(src, 'sound/machines/printer.ogg', 100, TRUE) visible_message(span_notice("[src] prints an error report.")) var/obj/item/paper/printed_paper = new /obj/item/paper(loc) printed_paper.name = "error report - '[fail_title]'" - printed_paper.add_raw_text(fail_reason) + printed_paper.add_raw_text(fail_explanation) printed_paper.update_appearance() toggle_open() update_appearance() -/// Attempt to replace/add-to the occupant's organs with "mutated" equivalents. -/// Returns TRUE on success, FALSE on failure. -/// Requires the target mob to have an existing organic organ to "mutate". -// TODO: In the future, this should have more logic: -// - Replace non-mutant organs before mutant ones. -/obj/machinery/dna_infuser/proc/infuse_organ(mob/living/carbon/human/target) - if(!ishuman(target)) - return FALSE - var/obj/item/organ/new_organ = pick_organ(target) - if(!new_organ) - return FALSE - // Valid organ successfully picked. - new_organ = new new_organ() - new_organ.replace_into(target) - check_tier_progression(target) - return TRUE - -/// Picks a random mutated organ from the infuser entry which is also compatible with the target mob. -/// Tries to return a typepath of a valid mutant organ if all of the following criteria are true: -/// 1. Target must have a pre-existing organ in the same organ slot as the new organ; -/// - or the new organ must be external. -/// 2. Target's pre-existing organ must be organic / not robotic. -/// 3. Target must not have the same/identical organ. -/obj/machinery/dna_infuser/proc/pick_organ(mob/living/carbon/human/target) - if(!infusing_into) - return FALSE - var/list/obj/item/organ/potential_new_organs = infusing_into.output_organs.Copy() - // Remove organ typepaths from the list if they're incompatible with target. - for(var/obj/item/organ/new_organ as anything in infusing_into.output_organs) - var/obj/item/organ/old_organ = target.get_organ_slot(initial(new_organ.slot)) - if(old_organ) - if((old_organ.type != new_organ) && !IS_ROBOTIC_ORGAN(old_organ)) - continue // Old organ can be mutated! - else if(ispath(new_organ, /obj/item/organ/external)) - continue // External organ can be grown! - // Internal organ is either missing, or is non-organic. - potential_new_organs -= new_organ - // Pick a random organ from the filtered list. - if(length(potential_new_organs)) - return pick(potential_new_organs) - return FALSE - /// checks to see if the machine should progress a new tier. /obj/machinery/dna_infuser/proc/check_tier_progression(mob/living/carbon/human/target) if( @@ -254,19 +206,6 @@ infusing_from = target infusing_from.forceMove(src) -/// Verify that the occupant/target is organic, and has mutable DNA. -/obj/machinery/dna_infuser/proc/is_valid_occupant(mob/living/carbon/human/human_target, mob/user) - // Invalid: DNA is too damaged to mutate anymore / has TRAIT_BADDNA. - if(HAS_TRAIT(human_target, TRAIT_BADDNA)) - balloon_alert(user, "dna is corrupted!") - return FALSE - // Invalid: Occupant isn't Human, isn't organic, lacks DNA / has TRAIT_GENELESS. - if(!ishuman(human_target) || !human_target.can_mutate()) - balloon_alert(user, "dna is missing!") - return FALSE - // Valid: Occupant is an organic Human who has undamaged and mutable DNA. - return TRUE - /// Verify that the given infusion source/mob is a dead creature. /obj/machinery/dna_infuser/proc/is_valid_infusion(atom/movable/target, mob/user) if(user.stat != CONSCIOUS || HAS_TRAIT(user, TRAIT_UI_BLOCKED) || !Adjacent(user) || !user.Adjacent(target) || !ISADVANCEDTOOLUSER(user)) @@ -291,10 +230,10 @@ /obj/machinery/dna_infuser/click_alt(mob/user) if(infusing) balloon_alert(user, "not while it's on!") - return CLICK_ACTION_BLOCKING + return if(!infusing_from) balloon_alert(user, "no sample to eject!") - return CLICK_ACTION_BLOCKING + return balloon_alert(user, "ejected sample") infusing_from.forceMove(get_turf(src)) infusing_from = null diff --git a/code/game/machinery/dna_infuser/dna_infusion.dm b/code/game/machinery/dna_infuser/dna_infusion.dm new file mode 100644 index 0000000000000..c902240404ca7 --- /dev/null +++ b/code/game/machinery/dna_infuser/dna_infusion.dm @@ -0,0 +1,75 @@ + +///returns a boolean whether a machine occupant can be infused +/atom/movable/proc/can_infuse(mob/feedback_target) + if(feedback_target) + balloon_alert(feedback_target, "no dna!") + return FALSE + +/mob/living/can_infuse(mob/feedback_target) + if(feedback_target) + balloon_alert(feedback_target, "dna too simple!") + return FALSE + +/mob/living/carbon/human/can_infuse(mob/feedback_target) + // Checked by can_mutate but explicit feedback for this issue is good + if(HAS_TRAIT(src, TRAIT_BADDNA)) + if(feedback_target) + balloon_alert(feedback_target, "dna is corrupted!") + return FALSE + if(!can_mutate()) + if(feedback_target) + balloon_alert(feedback_target, "dna is missing!") + return FALSE + return TRUE + +///returns /datum/infuser_entry that matches an item being used for infusion, returns a fly mutation on failure +/atom/movable/proc/get_infusion_entry() as /datum/infuser_entry + var/datum/infuser_entry/found + for(var/datum/infuser_entry/entry as anything in flatten_list(GLOB.infuser_entries)) + if(entry.tier == DNA_MUTANT_UNOBTAINABLE) + continue + if(is_type_in_list(src, entry.input_obj_or_mob)) + found = entry + break + if(!found) + found = GLOB.infuser_entries[/datum/infuser_entry/fly] + return found + +/// Attempt to replace/add-to the occupant's organs with "mutated" equivalents. +/// Returns TRUE on success, FALSE on failure. +/// Requires the target mob to have an existing organic organ to "mutate". +// TODO: In the future, this should have more logic: +// - Replace non-mutant organs before mutant ones. +/mob/living/carbon/human/proc/infuse_organ(datum/infuser_entry/entry) + var/obj/item/organ/new_organ = pick_infusion_organ(entry) + if(!new_organ) + return FALSE + // Valid organ successfully picked. + new_organ = new new_organ() + new_organ.replace_into(src) + return TRUE + +/// Picks a random mutated organ from the given infuser entry which is also compatible with this human. +/// Tries to return a typepath of a valid mutant organ if all of the following criteria are true: +/// 1. Target must have a pre-existing organ in the same organ slot as the new organ; +/// - or the new organ must be external. +/// 2. Target's pre-existing organ must be organic / not robotic. +/// 3. Target must not have the same/identical organ. +/mob/living/carbon/human/proc/pick_infusion_organ(datum/infuser_entry/entry) + if(!entry) + return FALSE + var/list/obj/item/organ/potential_new_organs = entry.output_organs.Copy() + // Remove organ typepaths from the list if they're incompatible with target. + for(var/obj/item/organ/new_organ as anything in entry.output_organs) + var/obj/item/organ/old_organ = get_organ_slot(initial(new_organ.slot)) + if(old_organ) + if((old_organ.type != new_organ) && !IS_ROBOTIC_ORGAN(old_organ)) + continue // Old organ can be mutated! + else if(ispath(new_organ, /obj/item/organ/external)) + continue // External organ can be grown! + // Internal organ is either missing, or is non-organic. + potential_new_organs -= new_organ + // Pick a random organ from the filtered list. + if(length(potential_new_organs)) + return pick(potential_new_organs) + return FALSE diff --git a/code/game/machinery/dna_infuser/infuser_book.dm b/code/game/machinery/dna_infuser/infuser_book.dm index 75632178ccae3..416ed038d640a 100644 --- a/code/game/machinery/dna_infuser/infuser_book.dm +++ b/code/game/machinery/dna_infuser/infuser_book.dm @@ -29,7 +29,7 @@ var/list/data = list() // Collect all info from each intry. var/list/entry_data = list() - for(var/datum/infuser_entry/entry as anything in GLOB.infuser_entries) + for(var/datum/infuser_entry/entry as anything in flatten_list(GLOB.infuser_entries)) if(entry.tier == DNA_MUTANT_UNOBTAINABLE) continue var/list/individual_entry_data = list() diff --git a/code/game/machinery/dna_infuser/infuser_entry.dm b/code/game/machinery/dna_infuser/infuser_entry.dm index dfcdfbbe08a5d..8b0bcfb3f790d 100644 --- a/code/game/machinery/dna_infuser/infuser_entry.dm +++ b/code/game/machinery/dna_infuser/infuser_entry.dm @@ -4,17 +4,10 @@ GLOBAL_LIST_INIT(infuser_entries, prepare_infuser_entries()) /// Global proc that sets up each [/datum/infuser_entry] sub-type as singleton instances in a list, and returns it. /proc/prepare_infuser_entries() var/list/entries = list() - // Regardless of names, we want the fly/failed mutant case to show first. - var/prepended for(var/datum/infuser_entry/entry_type as anything in subtypesof(/datum/infuser_entry)) var/datum/infuser_entry/entry = new entry_type() - if(entry.type == /datum/infuser_entry/fly) - prepended = entry - continue - entries += entry - var/list/sorted = sort_names(entries) - sorted.Insert(1, prepended) - return sorted + entries[entry_type] = entry + return entries /datum/infuser_entry //-- Vars for DNA Infusion Book --// diff --git a/code/modules/unit_tests/organ_set_bonus.dm b/code/modules/unit_tests/organ_set_bonus.dm index a9e9a8805f9c4..967803e223f17 100644 --- a/code/modules/unit_tests/organ_set_bonus.dm +++ b/code/modules/unit_tests/organ_set_bonus.dm @@ -22,7 +22,7 @@ /datum/infuser_entry/fly, )) // Fetch the globally instantiated DNA Infuser entries. - for(var/datum/infuser_entry/infuser_entry as anything in GLOB.infuser_entries) + for(var/datum/infuser_entry/infuser_entry as anything in flatten_list(GLOB.infuser_entries)) var/output_organs = infuser_entry.output_organs var/mob/living/carbon/human/lab_rat = allocate(/mob/living/carbon/human/consistent) var/list/obj/item/organ/inserted_organs = list() diff --git a/tgstation.dme b/tgstation.dme index 44305244e0950..fd3d58369b283 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -2088,6 +2088,7 @@ #include "code\game\machinery\computer\records\records.dm" #include "code\game\machinery\computer\records\security.dm" #include "code\game\machinery\dna_infuser\dna_infuser.dm" +#include "code\game\machinery\dna_infuser\dna_infusion.dm" #include "code\game\machinery\dna_infuser\infuser_book.dm" #include "code\game\machinery\dna_infuser\infuser_entry.dm" #include "code\game\machinery\dna_infuser\infuser_entries\infuser_tier_one_entries.dm" From a300ec3f7bbc616b4342f0b7ae12cd1f58100e96 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Fri, 26 Apr 2024 00:20:27 +0000 Subject: [PATCH 489/938] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-82669.yml | 7 ------ html/changelogs/AutoChangeLog-pr-82809.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82822.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82825.yml | 7 ------ html/changelogs/AutoChangeLog-pr-82830.yml | 4 ---- html/changelogs/AutoChangeLog-pr-82836.yml | 5 ----- html/changelogs/AutoChangeLog-pr-82842.yml | 4 ---- html/changelogs/archive/2024-04.yml | 26 ++++++++++++++++++++++ 8 files changed, 26 insertions(+), 35 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-82669.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82809.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82822.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82825.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82830.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82836.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82842.yml diff --git a/html/changelogs/AutoChangeLog-pr-82669.yml b/html/changelogs/AutoChangeLog-pr-82669.yml deleted file mode 100644 index dc03cf8c8fc5a..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82669.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: "Bisar" -delete-after: True -changes: - - bugfix: "AI controlled monkeys are no longer catatonic, and they have primal eyes again when turned into humans." - - spellcheck: "Noticable organs now have more modular grammar, and their current grammar is fixed." - - refactor: "Refactored the code for displaying the messages for noticable organs." - - config: "Added a documented define of all our pronouns" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82809.yml b/html/changelogs/AutoChangeLog-pr-82809.yml deleted file mode 100644 index a53b8fd9d3711..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82809.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Ben10Omintrix" -delete-after: True -changes: - - bugfix: "all bots have their normal accesses restored" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82822.yml b/html/changelogs/AutoChangeLog-pr-82822.yml deleted file mode 100644 index da8b0192fee01..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82822.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "jlsnow301" -delete-after: True -changes: - - bugfix: "Restored silicon alt-clicking capability" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82825.yml b/html/changelogs/AutoChangeLog-pr-82825.yml deleted file mode 100644 index 935842612deef..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82825.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: "Singul0" -delete-after: True -changes: - - bugfix: "fixed cyborg bonesetter not working for compound fractures" - - bugfix: "butchering not disabling in cyborg omnitool" - - bugfix: "fixes a bug where if you select the omnitool it would be stuck in surgery initiator mode" - - bugfix: "cautery in off hand for cyborg omnitools not working" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82830.yml b/html/changelogs/AutoChangeLog-pr-82830.yml deleted file mode 100644 index deae02b96804f..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82830.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "KingkumaArt" -delete-after: True -changes: - - bugfix: "The rebar crossbows now properly loosen their bowstring upon firing." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82836.yml b/html/changelogs/AutoChangeLog-pr-82836.yml deleted file mode 100644 index f4e79bb05f520..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82836.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "LT3" -delete-after: True -changes: - - balance: "ChemMaster can again print a maximum of 50 pills/patches per run" - - balance: "Higher tier servos increase ChemMaster printing speed" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82842.yml b/html/changelogs/AutoChangeLog-pr-82842.yml deleted file mode 100644 index 63022a3e15925..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82842.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "necromanceranne" -delete-after: True -changes: - - bugfix: "The plasma flower modsuit core now actually contains a reasonable quantity of power." \ No newline at end of file diff --git a/html/changelogs/archive/2024-04.yml b/html/changelogs/archive/2024-04.yml index 1f04766845988..c96b71a34d5b6 100644 --- a/html/changelogs/archive/2024-04.yml +++ b/html/changelogs/archive/2024-04.yml @@ -815,3 +815,29 @@ - balance: Longfall modules no logner stun you when they activate. - balance: Falling from a height greater than one z-level while using the longfall module will still stagger you. +2024-04-26: + Ben10Omintrix: + - bugfix: all bots have their normal accesses restored + Bisar: + - bugfix: AI controlled monkeys are no longer catatonic, and they have primal eyes + again when turned into humans. + - spellcheck: Noticable organs now have more modular grammar, and their current + grammar is fixed. + - refactor: Refactored the code for displaying the messages for noticable organs. + - config: Added a documented define of all our pronouns + KingkumaArt: + - bugfix: The rebar crossbows now properly loosen their bowstring upon firing. + LT3: + - balance: ChemMaster can again print a maximum of 50 pills/patches per run + - balance: Higher tier servos increase ChemMaster printing speed + Singul0: + - bugfix: fixed cyborg bonesetter not working for compound fractures + - bugfix: butchering not disabling in cyborg omnitool + - bugfix: fixes a bug where if you select the omnitool it would be stuck in surgery + initiator mode + - bugfix: cautery in off hand for cyborg omnitools not working + jlsnow301: + - bugfix: Restored silicon alt-clicking capability + necromanceranne: + - bugfix: The plasma flower modsuit core now actually contains a reasonable quantity + of power. From cbcf5a7108734bf8801d9821691ff6a087be2568 Mon Sep 17 00:00:00 2001 From: Zephyr <12817816+ZephyrTFA@users.noreply.github.com> Date: Thu, 25 Apr 2024 22:52:54 -0400 Subject: [PATCH 490/938] ip intel mk2 (#82683) Do not merge this without coordinating with your server's host. ## About The Pull Request Slightly refactors the way we handle IP intel. You can still use the old data stored in the database. Adds the ability to automatically reject connections determined by config flags. ## Why It's Good For The Game We used to have IP intel to check for VPNs, although it was disabled due to being bad and unhelpful. This refactor should make it much more manageable for hosts and admins. ## HOSTS BEWARE This adds a new SQL table `ipintel_whitelist` Look at the schema! ## Changelog :cl: admin: The return of IPIntel /:cl: --------- Co-authored-by: MrStonedOne Co-authored-by: oranges --- SQL/database_changelog.md | 23 +- SQL/tgstation_schema.sql | 14 + code/__DEFINES/admin_verb.dm | 1 + code/__DEFINES/ipintel.dm | 15 + code/__DEFINES/subsystems.dm | 2 +- .../configuration/entries/general.dm | 31 +- code/controllers/subsystem/ipintel.dm | 294 +++++++++++++++++- code/modules/admin/ipintel.dm | 136 -------- code/modules/client/client_procs.dm | 11 +- config/config.txt | 26 +- tgstation.dme | 2 +- 11 files changed, 379 insertions(+), 176 deletions(-) create mode 100644 code/__DEFINES/ipintel.dm delete mode 100644 code/modules/admin/ipintel.dm diff --git a/SQL/database_changelog.md b/SQL/database_changelog.md index a71cf673d3dbc..31b516f2af74e 100644 --- a/SQL/database_changelog.md +++ b/SQL/database_changelog.md @@ -2,19 +2,34 @@ Any time you make a change to the schema files, remember to increment the databa Make sure to also update `DB_MAJOR_VERSION` and `DB_MINOR_VERSION`, which can be found in `code/__DEFINES/subsystem.dm`. -The latest database version is 5.26; The query to update the schema revision table is: +The latest database version is 5.27; The query to update the schema revision table is: ```sql -INSERT INTO `schema_revision` (`major`, `minor`) VALUES (5, 26); +INSERT INTO `schema_revision` (`major`, `minor`) VALUES (5, 27); ``` or ```sql -INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (5, 26); +INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (5, 27); ``` In any query remember to add a prefix to the table names if you use one. - +----------------------------------------------------- +Version 5.27, 26 April 2024, by zephyrtfa +Add the ip intel table +```sql +DROP TABLE IF EXISTS `ipintel`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `ipintel` ( + `ip` int(10) unsigned NOT NULL, + `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `intel` double NOT NULL DEFAULT '0', + PRIMARY KEY (`ip`), + KEY `idx_ipintel` (`ip`,`intel`,`date`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +``` ----------------------------------------------------- Version 5.26, 03 December 2023, by distributivgesetz Set the default value of cloneloss to 0, as it's obsolete and it won't be set by blackbox anymore. diff --git a/SQL/tgstation_schema.sql b/SQL/tgstation_schema.sql index 64bbf4259d931..19739a306b5eb 100644 --- a/SQL/tgstation_schema.sql +++ b/SQL/tgstation_schema.sql @@ -215,6 +215,20 @@ CREATE TABLE `ipintel` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; /*!40101 SET character_set_client = @saved_cs_client */; +-- +-- Table structure for table `ipintel_whitelist` +-- + +DROP TABLE IF EXISTS `ipintel_whitelist`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `ipintel_whitelist` ( + `ckey` varchar(32) NOT NULL, + `admin_ckey` varchar(32) NOT NULL, + PRIMARY KEY (`ckey`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + -- -- Table structure for table `legacy_population` -- diff --git a/code/__DEFINES/admin_verb.dm b/code/__DEFINES/admin_verb.dm index cbf856bf4365f..7e811c121961c 100644 --- a/code/__DEFINES/admin_verb.dm +++ b/code/__DEFINES/admin_verb.dm @@ -87,6 +87,7 @@ _ADMIN_VERB(verb_path_name, verb_permissions, verb_name, verb_desc, verb_categor #define ADMIN_CATEGORY_OBJECT "Object" #define ADMIN_CATEGORY_MAPPING "Mapping" #define ADMIN_CATEGORY_PROFILE "Profile" +#define ADMIN_CATEGORY_IPINTEL "IPIntel" // Visibility flags #define ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG "Map-Debug" diff --git a/code/__DEFINES/ipintel.dm b/code/__DEFINES/ipintel.dm new file mode 100644 index 0000000000000..9fbc14ae40dbf --- /dev/null +++ b/code/__DEFINES/ipintel.dm @@ -0,0 +1,15 @@ +#define IPINTEL_RATE_LIMIT_MINUTE "minute" +#define IPINTEL_RATE_LIMIT_DAY "day" + +/// An internal error occurred and the query cannot be processed +#define IPINTEL_UNKNOWN_INTERNAL_ERROR "unknown_internal_error" +/// An error occurred with the query and the result is unknown +#define IPINTEL_UNKNOWN_QUERY_ERROR "unknown_query_error" +/// Cannot query as we are rate limited for the rest of the day +#define IPINTEL_RATE_LIMITED_DAY "rate_limited_day" +/// Cannot query as we are rate limited for the rest of the minute +#define IPINTEL_RATE_LIMITED_MINUTE "rate_limited_minute" +/// The IP address is a VPN or bad IP +#define IPINTEL_BAD_IP "bad_ip" +/// The IP address is not a VPN or bad IP +#define IPINTEL_GOOD_IP "good_ip" diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 3878ba8c45ce3..031244d3d76c1 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -20,7 +20,7 @@ * * make sure you add an update to the schema_version stable in the db changelog */ -#define DB_MINOR_VERSION 26 +#define DB_MINOR_VERSION 27 //! ## Timing subsystem diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm index 05226ae6b9418..5292e47ecd654 100644 --- a/code/controllers/configuration/entries/general.dm +++ b/code/controllers/configuration/entries/general.dm @@ -447,6 +447,9 @@ /datum/config_entry/flag/irc_first_connection_alert // do we notify the irc channel when somebody is connecting for the first time? +/datum/config_entry/string/ipintel_base + default = "check.getipintel.net" + /datum/config_entry/string/ipintel_email /datum/config_entry/string/ipintel_email/ValidateAndSet(str_val) @@ -458,18 +461,26 @@ min_val = 0 max_val = 1 -/datum/config_entry/number/ipintel_save_good - default = 12 - integer = FALSE - min_val = 0 +/datum/config_entry/flag/ipintel_reject_rate_limited + default = TRUE -/datum/config_entry/number/ipintel_save_bad - default = 1 - integer = FALSE - min_val = 0 +/datum/config_entry/flag/ipintel_reject_bad + default = TRUE -/datum/config_entry/string/ipintel_domain - default = "check.getipintel.net" +/datum/config_entry/flag/ipintel_reject_unknown + default = FALSE + +/datum/config_entry/number/ipintel_rate_minute + default = 15 + +/datum/config_entry/number/ipintel_rate_day + default = 500 + +/datum/config_entry/number/ipintel_cache_length + default = 7 + +/datum/config_entry/number/ipintel_exempt_playtime_living + default = 0 /datum/config_entry/flag/aggressive_changelog diff --git a/code/controllers/subsystem/ipintel.dm b/code/controllers/subsystem/ipintel.dm index 83cbbc4c27efc..3f1c738b09c0e 100644 --- a/code/controllers/subsystem/ipintel.dm +++ b/code/controllers/subsystem/ipintel.dm @@ -1,13 +1,295 @@ SUBSYSTEM_DEF(ipintel) name = "XKeyScore" init_order = INIT_ORDER_XKEYSCORE - flags = SS_NO_FIRE - var/enabled = FALSE //disable at round start to avoid checking reconnects - var/throttle = 0 - var/errors = 0 + flags = SS_INIT_NO_NEED|SS_NO_FIRE + /// The threshold for probability to be considered a VPN and/or bad IP + var/probability_threshold + /// The email used in conjuction with https://check.getipintel.net/check.php + var/contact_email + /// Maximum number of queries per minute + var/max_queries_per_minute + /// Maximum number of queries per day + var/max_queries_per_day + /// Query base + var/query_base + /// The length of time (days) to cache IP intel + var/ipintel_cache_length + /// The living playtime (minutes) for players to be exempt from IPIntel checks + var/exempt_living_playtime - var/list/cache = list() + /// Cache for previously queried IP addresses and those stored in the database + var/list/datum/ip_intel/cached_queries = list() + /// The store for rate limiting + var/list/rate_limits + +/// The ip intel for a given address +/datum/ip_intel + /// If this intel was just queried, the status of the query + var/query_status + var/result + var/address + var/date /datum/controller/subsystem/ipintel/Initialize() - enabled = TRUE + var/list/fail_messages = list() + + probability_threshold = CONFIG_GET(number/ipintel_rating_bad) + if(probability_threshold < 0 || probability_threshold > 1) + fail_messages += list("invalid probability threshold") + + contact_email = CONFIG_GET(string/ipintel_email) + if(isnull(contact_email) || !findtext(contact_email, "@")) + fail_messages += list("invalid contact email") + + var/max_queries_per_minute = CONFIG_GET(number/ipintel_rate_minute) + var/max_queries_per_day = CONFIG_GET(number/ipintel_rate_day) + if(max_queries_per_minute < 0 || max_queries_per_day < 0) + fail_messages += list("invalid rate limits") + + var/query_base = CONFIG_GET(string/ipintel_base) + if(isnull(query_base)) + fail_messages += list("invalid query base") + + var/ipintel_cache_length = CONFIG_GET(number/ipintel_cache_length) + if(ipintel_cache_length < 0) + fail_messages += list("invalid cache length") + + var/exempt_living_playtime = CONFIG_GET(number/ipintel_exempt_playtime_living) + if(exempt_living_playtime < 0) + fail_messages += list("invalid exempt living playtime") + + if(length(fail_messages)) + message_admins("IPIntel: Initialization failed check logs!") + logger.Log(LOG_CATEGORY_GAME_ACCESS, "IPIntel failed to initialize.", list( + "fail_messages" = fail_messages, + )) + return SS_INIT_FAILURE + return SS_INIT_SUCCESS + +/datum/controller/subsystem/ipintel/stat_entry(msg) + return "[..()] | D: [max_queries_per_day - rate_limits[IPINTEL_RATE_LIMIT_DAY]] | M: [max_queries_per_minute - rate_limits[IPINTEL_RATE_LIMIT_MINUTE]]" + +/datum/controller/subsystem/ipintel/proc/get_address_intel_state(address, probability_override) + var/datum/ip_intel/intel = query_address(address) + if(isnull(intel)) + stack_trace("query_address did not return an ip intel response") + return IPINTEL_UNKNOWN_INTERNAL_ERROR + + if(istext(intel)) + return intel + + if(!(intel.query_status in list("success", "cached"))) + return IPINTEL_UNKNOWN_QUERY_ERROR + var/check_probability = probability_override || probability_threshold + if(intel.result >= check_probability) + return IPINTEL_BAD_IP + return IPINTEL_GOOD_IP + +/datum/controller/subsystem/ipintel/proc/is_rate_limited() + var/static/minute_key + var/expected_minute_key = floor(REALTIMEOFDAY / 1 MINUTES) + + if(minute_key != expected_minute_key) + minute_key = expected_minute_key + rate_limits[IPINTEL_RATE_LIMIT_MINUTE] = 0 + + if(rate_limits[IPINTEL_RATE_LIMIT_MINUTE] >= max_queries_per_minute) + return IPINTEL_RATE_LIMITED_MINUTE + if(rate_limits[IPINTEL_RATE_LIMIT_DAY] >= max_queries_per_day) + return IPINTEL_RATE_LIMITED_DAY + return FALSE + +/datum/controller/subsystem/ipintel/proc/query_address(address, allow_cached = TRUE) + if(allow_cached && fetch_cached_ip_intel(address)) + return cached_queries[address] + var/is_rate_limited = is_rate_limited() + if(is_rate_limited) + return is_rate_limited + if(!initialized) + return IPINTEL_UNKNOWN_INTERNAL_ERROR + + rate_limits[IPINTEL_RATE_LIMIT_MINUTE] += 1 + rate_limits[IPINTEL_RATE_LIMIT_DAY] += 1 + + var/query_base = "https://[src.query_base]/check.php?ip=" + var/query = "[query_base][address]&contact=[contact_email]&flags=b&format=json" + + var/datum/http_request/request = new + request.prepare(RUSTG_HTTP_METHOD_GET, query) + request.execute_blocking() + var/datum/http_response/response = request.into_response() + var/list/data = response.body + + var/datum/ip_intel/intel = new + intel.query_status = data["status"] + if(intel.query_status != "success") + return intel + intel.result = data["result"] + intel.date = SQLtime() + intel.address = address + cached_queries[address] = intel + add_intel_to_database(intel) + return intel + +/datum/controller/subsystem/ipintel/proc/add_intel_to_database(datum/ip_intel/intel) + var/datum/db_query/query = SSdbcore.NewQuery( + "INSERT INTO [format_table_name("ipintel")] ( \ + ip, \ + intel, \ + ) VALUES ( \ + INET_ATON(:address) \ + :result, \ + )", list( + "address" = intel.address, + "result" = intel.result, + ) + ) + query.warn_execute() + query.sync() + qdel(query) + +/datum/controller/subsystem/ipintel/proc/fetch_cached_ip_intel(address) + var/date_restrictor + if(ipintel_cache_length > 0) + date_restrictor = " AND date > DATE_SUB(NOW(), INTERVAL [ipintel_cache_length] DAY)" + var/datum/db_query/query = SSdbcore.NewQuery( + "SELECT * FROM [format_table_name("ipintel")] WHERE ip = INET_ATON(:address)[date_restrictor]", list( + "address" = address + ) + ) + query.warn_execute() + query.sync() + if(query.status == DB_QUERY_BROKEN) + qdel(query) + return null + + query.NextRow() + var/list/data = query.item + qdel(query) + if(isnull(data)) + return null + + var/datum/ip_intel/intel = new + intel.query_status = "cached" + intel.result = data["intel"] + intel.date = data["date"] + intel.address = address + return TRUE + +/datum/controller/subsystem/ipintel/proc/is_exempt(client/player) + if(exempt_living_playtime > 0) + var/list/play_records = player.prefs.exp + if (!play_records.len) + player.set_exp_from_db() + play_records = player.prefs.exp + if(length(play_records) && play_records[EXP_TYPE_LIVING] > exempt_living_playtime) + return TRUE + return FALSE + +/datum/controller/subsystem/ipintel/proc/is_whitelisted(ckey) + var/datum/db_query/query = SSdbcore.NewQuery( + "SELECT * FROM [format_table_name("ipintel_whitelist")] WHERE ckey = :ckey", list( + "ckey" = ckey + ) + ) + query.warn_execute() + query.sync() + if(query.status == DB_QUERY_BROKEN) + qdel(query) + return FALSE + query.NextRow() + return !!query.item // if they have a row, they are whitelisted + +ADMIN_VERB(ipintel_allow, R_BAN, "Whitelist Player VPN", "Allow a player to connect even if they are using a VPN.", ADMIN_CATEGORY_IPINTEL, ckey as text) + if(SSipintel.is_whitelisted(ckey)) + to_chat(user, "Player is already whitelisted.") + return + + var/datum/db_query/query = SSdbcore.NewQuery( + "INSERT INTO [format_table_name("ipintel_whitelist")] ( \ + ckey, \ + admin_ckey \ + ) VALUES ( \ + :ckey, \ + :admin_ckey \ + )", list( + "ckey" = ckey, + "admin_ckey" = user.ckey, + ) + ) + query.warn_execute() + query.sync() + qdel(query) + message_admins("IPINTEL: [key_name_admin(user)] has whitelisted '[ckey]'") + +ADMIN_VERB(ipintel_revoke, R_BAN, "Revoke Player VPN Whitelist", "Revoke a player's VPN whitelist.", ADMIN_CATEGORY_IPINTEL, ckey as text) + if(!SSipintel.is_whitelisted(ckey)) + to_chat(user, "Player is not whitelisted.") + return + var/datum/db_query/query = SSdbcore.NewQuery( + "DELETE FROM [format_table_name("ipintel_whitelist")] WHERE ckey = :ckey", list( + "ckey" = ckey + ) + ) + query.warn_execute() + query.sync() + qdel(query) + message_admins("IPINTEL: [key_name_admin(user)] has revoked the VPN whitelist for '[ckey]'") + +/client/proc/check_ip_intel() + if(SSipintel.is_exempt(src) || SSipintel.is_whitelisted(ckey)) + return + + var/intel_state = SSipintel.get_address_intel_state(address) + var/reject_bad_intel = CONFIG_GET(flag/ipintel_reject_bad) + var/reject_unknown_intel = CONFIG_GET(flag/ipintel_reject_unknown) + var/reject_rate_limited = CONFIG_GET(flag/ipintel_reject_rate_limited) + + var/connection_rejected = FALSE + var/datum/ip_intel/intel = SSipintel.cached_queries[address] + switch(intel_state) + if(IPINTEL_BAD_IP) + log_access("IPINTEL: [ckey] was flagged as a VPN with [intel.result * 100]% likelihood.") + if(reject_bad_intel) + to_chat_immediate(src, span_boldnotice("Your connection has been detected as a VPN.")) + connection_rejected = TRUE + else + message_admins("IPINTEL: [key_name_admin(src)] has been flagged as a VPN with [intel.result * 100]% likelihood.") + + if(IPINTEL_RATE_LIMITED_DAY, IPINTEL_RATE_LIMITED_MINUTE) + log_access("IPINTEL: [ckey] was unable to be checked due to the rate limit.") + if(reject_rate_limited) + to_chat_immediate(src, span_boldnotice("New connections are not being allowed at this time.")) + connection_rejected = TRUE + else + message_admins("IPINTEL: [key_name_admin(src)] was unable to be checked due to rate limiting.") + + if(IPINTEL_UNKNOWN_INTERNAL_ERROR, IPINTEL_UNKNOWN_QUERY_ERROR) + log_access("IPINTEL: [ckey] unable to be checked due to an error.") + if(reject_unknown_intel) + to_chat_immediate(src, span_boldnotice("Your connection cannot be processed at this time.")) + connection_rejected = TRUE + else + message_admins("IPINTEL: [key_name_admin(src)] was unable to be checked due to an error.") + + if(!connection_rejected) + return + + var/list/contact_where = list() + var/forum_url = CONFIG_GET(string/forumurl) + if(forum_url) + contact_where += list("Forums") + var/appeal_url = CONFIG_GET(string/banappeals) + if(appeal_url) + contact_where += list("Ban Appeals") + + var/message_string = "Your connection has been rejected at this time. If you believe this is in error or have any questions please contact an admin" + if(length(contact_where)) + message_string += " at [english_list(contact_where)]" + else + message_string += " somehow." + message_string += "." + + to_chat_immediate(src, span_userdanger(message_string)) + qdel(src) diff --git a/code/modules/admin/ipintel.dm b/code/modules/admin/ipintel.dm deleted file mode 100644 index 7ca4ccbc320a7..0000000000000 --- a/code/modules/admin/ipintel.dm +++ /dev/null @@ -1,136 +0,0 @@ -/datum/ipintel - var/ip - var/intel = 0 - var/cache = FALSE - var/cacheminutesago = 0 - var/cachedate = "" - var/cacherealtime = 0 - -/datum/ipintel/New() - cachedate = SQLtime() - cacherealtime = world.realtime - -/datum/ipintel/proc/is_valid() - . = FALSE - if (intel < 0) - return - if (intel <= CONFIG_GET(number/ipintel_rating_bad)) - if (world.realtime < cacherealtime + (CONFIG_GET(number/ipintel_save_good) * 60 * 60 * 10)) - return TRUE - else - if (world.realtime < cacherealtime + (CONFIG_GET(number/ipintel_save_bad) * 60 * 60 * 10)) - return TRUE - -/proc/get_ip_intel(ip, bypasscache = FALSE, updatecache = TRUE) - var/datum/ipintel/res = new() - res.ip = ip - . = res - if (!ip || !CONFIG_GET(string/ipintel_email) || !SSipintel.enabled) - return - if (!bypasscache) - var/datum/ipintel/cachedintel = SSipintel.cache[ip] - if (cachedintel?.is_valid()) - cachedintel.cache = TRUE - return cachedintel - - if(SSdbcore.Connect()) - var/rating_bad = CONFIG_GET(number/ipintel_rating_bad) - var/datum/db_query/query_get_ip_intel = SSdbcore.NewQuery({" - SELECT date, intel, TIMESTAMPDIFF(MINUTE,date,NOW()) - FROM [format_table_name("ipintel")] - WHERE - ip = INET_ATON(':ip') - AND (( - intel < :rating_bad - AND - date + INTERVAL :save_good HOUR > NOW() - ) OR ( - intel >= :rating_bad - AND - date + INTERVAL :save_bad HOUR > NOW() - )) - "}, list("ip" = ip, "rating_bad" = rating_bad, "save_good" = CONFIG_GET(number/ipintel_save_good), "save_bad" = CONFIG_GET(number/ipintel_save_bad))) - if(!query_get_ip_intel.Execute()) - qdel(query_get_ip_intel) - return - if (query_get_ip_intel.NextRow()) - res.cache = TRUE - res.cachedate = query_get_ip_intel.item[1] - res.intel = text2num(query_get_ip_intel.item[2]) - res.cacheminutesago = text2num(query_get_ip_intel.item[3]) - res.cacherealtime = world.realtime - (text2num(query_get_ip_intel.item[3])*10*60) - SSipintel.cache[ip] = res - qdel(query_get_ip_intel) - return - qdel(query_get_ip_intel) - res.intel = ip_intel_query(ip) - if (updatecache && res.intel >= 0) - SSipintel.cache[ip] = res - if(SSdbcore.Connect()) - var/datum/db_query/query_add_ip_intel = SSdbcore.NewQuery( - "INSERT INTO [format_table_name("ipintel")] (ip, intel) VALUES (INET_ATON(:ip), :intel) ON DUPLICATE KEY UPDATE intel = VALUES(intel), date = NOW()", - list("ip" = ip, "intel" = res.intel) - ) - query_add_ip_intel.Execute() - qdel(query_add_ip_intel) - - -/proc/ip_intel_query(ip, retryed=0) - . = -1 //default - if (!ip) - return - if (SSipintel.throttle > world.timeofday) - return - if (!SSipintel.enabled) - return - - var/list/http[] = world.Export("http://[CONFIG_GET(string/ipintel_domain)]/check.php?ip=[ip]&contact=[CONFIG_GET(string/ipintel_email)]&format=json&flags=f") - - if (http) - var/status = text2num(http["STATUS"]) - - if (status == 200) - var/response = json_decode(file2text(http["CONTENT"])) - if (response) - if (response["status"] == "success") - var/intelnum = text2num(response["result"]) - if (isnum(intelnum)) - return text2num(response["result"]) - else - ipintel_handle_error("Bad intel from server: [response["result"]].", ip, retryed) - if (!retryed) - sleep(2.5 SECONDS) - return .(ip, 1) - else - ipintel_handle_error("Bad response from server: [response["status"]].", ip, retryed) - if (!retryed) - sleep(2.5 SECONDS) - return .(ip, 1) - - else if (status == 429) - ipintel_handle_error("Error #429: We have exceeded the rate limit.", ip, 1) - return - else - ipintel_handle_error("Unknown status code: [status].", ip, retryed) - if (!retryed) - sleep(2.5 SECONDS) - return .(ip, 1) - else - ipintel_handle_error("Unable to connect to API.", ip, retryed) - if (!retryed) - sleep(2.5 SECONDS) - return .(ip, 1) - - -/proc/ipintel_handle_error(error, ip, retryed) - if (retryed) - SSipintel.errors++ - error += " Could not check [ip]. Disabling IPINTEL for [SSipintel.errors] minute[( SSipintel.errors == 1 ? "" : "s" )]" - SSipintel.throttle = world.timeofday + (10 * 120 * SSipintel.errors) - else - error += " Attempting retry on [ip]." - log_ipintel(error) - -/proc/log_ipintel(text) - log_game("IPINTEL: [text]") - debug_admins("IPINTEL: [text]") diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 913be33118271..2c8c63579e2f5 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -541,7 +541,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( initialize_menus() loot_panel = new(src) - + view_size = new(src, getScreenSize(prefs.read_preference(/datum/preference/toggle/widescreen))) view_size.resetFormat() view_size.setZoomMode() @@ -828,15 +828,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( qdel(query_get_notes) create_message("note", key, system_ckey, message, null, null, 0, 0, null, 0, 0) - -/client/proc/check_ip_intel() - set waitfor = 0 //we sleep when getting the intel, no need to hold up the client connection while we sleep - if (CONFIG_GET(string/ipintel_email)) - var/datum/ipintel/res = get_ip_intel(address) - if (res.intel >= CONFIG_GET(number/ipintel_rating_bad)) - message_admins(span_adminnotice("Proxy Detection: [key_name_admin(src)] IP intel rated [res.intel*100]% likely to be a Proxy/VPN.")) - ip_intel = res.intel - /client/Click(atom/object, atom/location, control, params) if(click_intercept_time) if(click_intercept_time >= world.time) diff --git a/config/config.txt b/config/config.txt index 1c87fc110ae9a..37c75f9769443 100644 --- a/config/config.txt +++ b/config/config.txt @@ -143,16 +143,26 @@ GUEST_BAN ## IPINTEL: ## This allows you to detect likely proxies by checking ips against getipintel.net -## Rating to warn at: (0.9 is good, 1 is 100% likely to be a spammer/proxy, 0.8 is 80%, etc) anything equal to or higher then this number triggers an admin warning -#IPINTEL_RATING_BAD 0.9 +## Rating to warn at: (0.8 is good, 1 is 100% likely to be a spammer/proxy, 0.8 is 80%, etc) anything equal to or higher then this number triggers an admin warning +#IPINTEL_RATING_BAD 0.8 ## Contact email, (required to use the service, leaving blank or default disables IPINTEL) #IPINTEL_EMAIL ch@nge.me -## How long to save good matches (ipintel rate limits to 15 per minute and 500 per day. so this shouldn't be too low, getipintel.net suggests 6 hours, time is in hours) (Your ip will get banned if you go over 500 a day too many times) -#IPINTEL_SAVE_GOOD 12 -## How long to save bad matches (these numbers can change as ips change hands, best not to save these for too long in case somebody gets a new ip used by a spammer/proxy before.) -#IPINTEL_SAVE_BAD 3 -## Domain name to query (leave commented out for the default, only needed if you pay getipintel.net for more querys) -#IPINTEL_DOMAIN check.getipintel.net +## Query base, if you pay for more queries this is what you want to change. +#IPINTEL_BASE check.getipintel.net +## Maximum number of queries in a minute +#IPINTEL_MAX_QUERY_MINUTE 15 +## Maximum number of queries in a day +#IPINTEL_MAX_QUERY_DAY 500 +## Whether clients which cannot be checked due to a rate limit will be denied +#IPINTEL_REJECT_RATE_LIMITED +## Whether clients which are flagged as a VPN will be denied +IPINTEL_REJECT_BAD +## Whether clients which cannot be checked due to an error of some form will be denied +#IPINTEL_REJECT_UNKNOWN +## How long to store results in the cache before they must be retrieved again. IN DAYS. +#IPINTEL_CACHE_LENGTH 7 +## How many minutes of living playtime to be automatically exempt from IPIntel. 0 for never. +#IPINTEL_EXEMPT_PLAYTIME_LIVING 0 ## Uncomment to allow web client connections #ALLOW_WEBCLIENT diff --git a/tgstation.dme b/tgstation.dme index fd3d58369b283..2c4b4aac47548 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -119,6 +119,7 @@ #include "code\__DEFINES\instruments.dm" #include "code\__DEFINES\interaction_flags.dm" #include "code\__DEFINES\inventory.dm" +#include "code\__DEFINES\ipintel.dm" #include "code\__DEFINES\is_helpers.dm" #include "code\__DEFINES\jobs.dm" #include "code\__DEFINES\keybinding.dm" @@ -2799,7 +2800,6 @@ #include "code\modules\admin\fun_balloon.dm" #include "code\modules\admin\greyscale_modify_menu.dm" #include "code\modules\admin\holder2.dm" -#include "code\modules\admin\ipintel.dm" #include "code\modules\admin\IsBanned.dm" #include "code\modules\admin\known_alts.dm" #include "code\modules\admin\outfit_editor.dm" From cd29b123eff035fff7da10d21f8d55e1c898670f Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 26 Apr 2024 14:53:15 +1200 Subject: [PATCH 491/938] Automatic changelog for PR #82683 [ci skip] --- html/changelogs/AutoChangeLog-pr-82683.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82683.yml diff --git a/html/changelogs/AutoChangeLog-pr-82683.yml b/html/changelogs/AutoChangeLog-pr-82683.yml new file mode 100644 index 0000000000000..d63fc304d6d9d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82683.yml @@ -0,0 +1,4 @@ +author: "ZephyrTFA" +delete-after: True +changes: + - admin: "The return of IPIntel" \ No newline at end of file From cf4cc899027116a9f586b51e9d35093d256899eb Mon Sep 17 00:00:00 2001 From: Zephyr <12817816+ZephyrTFA@users.noreply.github.com> Date: Fri, 26 Apr 2024 03:47:28 -0400 Subject: [PATCH 492/938] Revert of a Revert | ListInputModal (#82854) This reverts commit 9acf5bd821b37e4d8dad1c850497eeef79c0e7d8. MSO determined that because we use `file(...)` instead of a string instead of an asset being locked to its initial state via a cache object we are sending it as it is on disk every time. which means that when a new server deployment updates the tgui it will send this new tgui code even if the currently running DM code does not support it. --- code/modules/asset_cache/assets/tgui.dm | 22 +++ code/modules/tgui_input/list.dm | 2 +- .../{ => ListInputWindow}/ListInputModal.tsx | 172 ++++++++---------- .../tgui/interfaces/ListInputWindow/index.tsx | 44 +++++ .../tgui/interfaces/common/InputButtons.tsx | 23 ++- 5 files changed, 166 insertions(+), 97 deletions(-) rename tgui/packages/tgui/interfaces/{ => ListInputWindow}/ListInputModal.tsx (57%) create mode 100644 tgui/packages/tgui/interfaces/ListInputWindow/index.tsx diff --git a/code/modules/asset_cache/assets/tgui.dm b/code/modules/asset_cache/assets/tgui.dm index 9c79925602c77..4b31d93e037f5 100644 --- a/code/modules/asset_cache/assets/tgui.dm +++ b/code/modules/asset_cache/assets/tgui.dm @@ -1,3 +1,23 @@ +// If you use a file(...) object, instead of caching the asset it will be loaded from disk every time it's requested. +// This is useful for development, but not recommended for production. +// And if TGS is defined, we're being run in a production environment. + +#ifdef TGS +/datum/asset/simple/tgui + keep_local_name = FALSE + assets = list( + "tgui.bundle.js" = "tgui/public/tgui.bundle.js", + "tgui.bundle.css" = "tgui/public/tgui.bundle.css", + ) + +/datum/asset/simple/tgui_panel + keep_local_name = FALSE + assets = list( + "tgui-panel.bundle.js" = "tgui/public/tgui-panel.bundle.js", + "tgui-panel.bundle.css" = "tgui/public/tgui-panel.bundle.css", + ) + +#else /datum/asset/simple/tgui keep_local_name = TRUE assets = list( @@ -11,3 +31,5 @@ "tgui-panel.bundle.js" = file("tgui/public/tgui-panel.bundle.js"), "tgui-panel.bundle.css" = file("tgui/public/tgui-panel.bundle.css"), ) + +#endif diff --git a/code/modules/tgui_input/list.dm b/code/modules/tgui_input/list.dm index 174f16fc7b57c..22c6d48edfc5a 100644 --- a/code/modules/tgui_input/list.dm +++ b/code/modules/tgui_input/list.dm @@ -111,7 +111,7 @@ /datum/tgui_list_input/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, "ListInputModal") + ui = new(user, src, "ListInputWindow") ui.open() /datum/tgui_list_input/ui_close(mob/user) diff --git a/tgui/packages/tgui/interfaces/ListInputModal.tsx b/tgui/packages/tgui/interfaces/ListInputWindow/ListInputModal.tsx similarity index 57% rename from tgui/packages/tgui/interfaces/ListInputModal.tsx rename to tgui/packages/tgui/interfaces/ListInputWindow/ListInputModal.tsx index 8695ac842f72e..a56363f231097 100644 --- a/tgui/packages/tgui/interfaces/ListInputModal.tsx +++ b/tgui/packages/tgui/interfaces/ListInputWindow/ListInputModal.tsx @@ -7,35 +7,26 @@ import { KEY_ESCAPE, KEY_UP, KEY_Z, -} from '../../common/keycodes'; -import { useBackend } from '../backend'; -import { Autofocus, Button, Input, Section, Stack } from '../components'; -import { Window } from '../layouts'; -import { InputButtons } from './common/InputButtons'; -import { Loader } from './common/Loader'; +} from '../../../common/keycodes'; +import { useBackend } from '../../backend'; +import { Autofocus, Button, Input, Section, Stack } from '../../components'; +import { InputButtons } from '../common/InputButtons'; -type ListInputData = { - init_value: string; +type ListInputModalProps = { items: string[]; - large_buttons: boolean; + default_item: string; message: string; - timeout: number; - title: string; + on_selected: (entry: string) => void; + on_cancel: () => void; }; -export const ListInputModal = (props) => { - const { act, data } = useBackend(); - const { - items = [], - message = '', - init_value, - large_buttons, - timeout, - title, - } = data; - const [selected, setSelected] = useState(items.indexOf(init_value)); +export const ListInputModal = (props: ListInputModalProps) => { + const { items = [], default_item, message, on_selected, on_cancel } = props; + + const [selected, setSelected] = useState(items.indexOf(default_item)); const [searchBarVisible, setSearchBarVisible] = useState(items.length > 9); const [searchQuery, setSearchQuery] = useState(''); + // User presses up or down on keyboard // Simulates clicking an item const onArrowKey = (key: number) => { @@ -99,82 +90,77 @@ export const ListInputModal = (props) => { const filteredItems = items.filter((item) => item?.toLowerCase().includes(searchQuery.toLowerCase()), ); - // Dynamically changes the window height based on the message. - const windowHeight = - 325 + Math.ceil(message.length / 3) + (large_buttons ? 5 : 0); // Grabs the cursor when no search bar is visible. if (!searchBarVisible) { setTimeout(() => document!.getElementById(selected.toString())?.focus(), 1); } return ( - - {timeout && } - { - const keyCode = window.event ? event.which : event.keyCode; - if (keyCode === KEY_DOWN || keyCode === KEY_UP) { - event.preventDefault(); - onArrowKey(keyCode); - } - if (keyCode === KEY_ENTER) { - event.preventDefault(); - act('submit', { entry: filteredItems[selected] }); - } - if (!searchBarVisible && keyCode >= KEY_A && keyCode <= KEY_Z) { - event.preventDefault(); - onLetterSearch(keyCode); - } - if (keyCode === KEY_ESCAPE) { - event.preventDefault(); - act('cancel'); - } - }} - > -
    onSearchBarToggle()} - /> +
    { + const keyCode = window.event ? event.which : event.keyCode; + if (keyCode === KEY_DOWN || keyCode === KEY_UP) { + event.preventDefault(); + onArrowKey(keyCode); + } + if (keyCode === KEY_ENTER) { + event.preventDefault(); + on_selected(filteredItems[selected]); + } + if (!searchBarVisible && keyCode >= KEY_A && keyCode <= KEY_Z) { + event.preventDefault(); + onLetterSearch(keyCode); + } + if (keyCode === KEY_ESCAPE) { + event.preventDefault(); + on_cancel(); + } + }} + buttons={ +
    - - + tooltipPosition="left" + onClick={() => onSearchBarToggle()} + /> + } + className="ListInput__Section" + fill + title={message} + > + + + + + {searchBarVisible && ( + + )} + + on_selected(filteredItems[selected])} + on_cancel={on_cancel} + /> + + +
    ); }; @@ -183,7 +169,7 @@ export const ListInputModal = (props) => { * If a search query is provided, filters the items. */ const ListDisplay = (props) => { - const { act } = useBackend(); + const { act } = useBackend(); const { filteredItems, onClick, onFocusSearch, searchBarVisible, selected } = props; @@ -227,7 +213,7 @@ const ListDisplay = (props) => { * Closing the bar defaults input to an empty string. */ const SearchBar = (props) => { - const { act } = useBackend(); + const { act } = useBackend(); const { filteredItems, onSearch, searchQuery, selected } = props; return ( diff --git a/tgui/packages/tgui/interfaces/ListInputWindow/index.tsx b/tgui/packages/tgui/interfaces/ListInputWindow/index.tsx new file mode 100644 index 0000000000000..29355ff5d213f --- /dev/null +++ b/tgui/packages/tgui/interfaces/ListInputWindow/index.tsx @@ -0,0 +1,44 @@ +import { useBackend } from '../../backend'; +import { Window } from '../../layouts'; +import { Loader } from '../common/Loader'; +import { ListInputModal } from './ListInputModal'; + +type ListInputData = { + init_value: string; + items: string[]; + large_buttons: boolean; + message: string; + timeout: number; + title: string; +}; + +export const ListInputWindow = () => { + const { act, data } = useBackend(); + const { + items = [], + message = '', + init_value, + large_buttons, + timeout, + title, + } = data; + + // Dynamically changes the window height based on the message. + const windowHeight = + 325 + Math.ceil(message.length / 3) + (large_buttons ? 5 : 0); + + return ( + + {timeout && } + + act('submit', { entry })} + on_cancel={() => act('cancel')} + /> + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/common/InputButtons.tsx b/tgui/packages/tgui/interfaces/common/InputButtons.tsx index aad3d92f081fb..aa74ff1fdc017 100644 --- a/tgui/packages/tgui/interfaces/common/InputButtons.tsx +++ b/tgui/packages/tgui/interfaces/common/InputButtons.tsx @@ -8,19 +8,36 @@ type InputButtonsData = { type InputButtonsProps = { input: string | number | string[]; + on_submit?: () => void; + on_cancel?: () => void; message?: string; }; export const InputButtons = (props: InputButtonsProps) => { const { act, data } = useBackend(); const { large_buttons, swapped_buttons } = data; - const { input, message } = props; + const { input, message, on_submit, on_cancel } = props; + + let on_submit_actual = on_submit; + if (!on_submit_actual) { + on_submit_actual = () => { + act('submit', { entry: input }); + }; + } + + let on_cancel_actual = on_cancel; + if (!on_cancel_actual) { + on_cancel_actual = () => { + act('cancel'); + }; + } + const submitButton = (

    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 bw29(GG;5&z_z>t#iF8xw&HhCJ0QXz~x}Dj- literal 0 HcmV?d00001 diff --git a/sound/voice/human/female_cry2.ogg b/sound/voice/human/female_cry2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..e81e93b5c3f83ff85cff2e2813911e9f6d8b9c41 GIT binary patch literal 43358 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

    - - - Material - - Value - - - {ores.map((ore) => ( - - {toTitleCase(ore.ore)} - - - {ore.value} - - - - ))} -
    +
    + The nearby stacking machine will unload crates and collect smelted + materials, points will be calculated based on volume of delivered + materials. +
    + Please note that only sheets printed with our manufacturer's seal of + quality, such as those produced from the work camp furnace, will be + accepted as proof of labour.
    From 2f6a0030726f2af4c006dae59a63ad586da01644 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 19 Apr 2024 03:09:08 +1200 Subject: [PATCH 319/938] Automatic changelog for PR #82561 [ci skip] --- html/changelogs/AutoChangeLog-pr-82561.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82561.yml diff --git a/html/changelogs/AutoChangeLog-pr-82561.yml b/html/changelogs/AutoChangeLog-pr-82561.yml new file mode 100644 index 0000000000000..5991984855b5f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82561.yml @@ -0,0 +1,5 @@ +author: "Jacquerel" +delete-after: True +changes: + - balance: "Gulag mining has been rebalanced so that every boulder is worth the same amount of points to mine for a prisoner regardless of what it contains, and should be more consistent." + - rscadd: "A vent which boulders can be hauled out of by hand has been added to the gulag which you can use if there's nothing left to mine. It is very slow, but at least it gives you a workout..." \ No newline at end of file From d8d25ceb3a08680a1da1b1b212fac4aed151601e Mon Sep 17 00:00:00 2001 From: AnturK Date: Thu, 18 Apr 2024 19:00:13 +0200 Subject: [PATCH 320/938] Makes test merge bot continue with other PRs if updating one fails. (#82717) Right now updating https://github.com/tgstation/tgstation/pull/81089#issuecomment-1907296233 fails because it exceeds github character limit for comments. This will make it work until backed is updated. --- tools/test_merge_bot/main.js | 46 ++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/tools/test_merge_bot/main.js b/tools/test_merge_bot/main.js index 0ad51304ecf79..ae7d4c7a98d90 100644 --- a/tools/test_merge_bot/main.js +++ b/tools/test_merge_bot/main.js @@ -87,19 +87,41 @@ export async function processTestMerges({ github, context }) { } if (existingComment === undefined) { - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - body: newBody, - }); + try { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + body: newBody, + }); + } catch (error) { + if(error.status){ + console.error(`Failed to create comment for #{prNumber}`) + console.error(error) + continue; + } + else{ + throw error + } + } } else { - await github.rest.issues.updateComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: existingComment.databaseId, - body: newBody, - }); + try { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: existingComment.databaseId, + body: newBody, + }); + } catch (error) { + if(error.status){ + console.error(`Failed to update comment for #{prNumber}`) + console.error(error) + continue; + } + else{ + throw error + } + } } } } From 19fd18d4383dd6dca3baf8f972894bba683fff69 Mon Sep 17 00:00:00 2001 From: Watermelon914 <37270891+Watermelon914@users.noreply.github.com> Date: Thu, 18 Apr 2024 17:07:45 +0000 Subject: [PATCH 321/938] Fixes the RnD console by adding a removed import (#82750) ## About The Pull Request The 'map' import was removed from this file by #82417 but it's still used in place in code. This re-adds the import ## Why It's Good For The Game Fixes RnD consoles ## Changelog :cl: fix: Fixed RnD consoles not being able to be opened. /:cl: Co-authored-by: Watermelon914 <3052169-Watermelon914@users.noreply.gitlab.com> --- tgui/packages/tgui/interfaces/Techweb.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgui/packages/tgui/interfaces/Techweb.jsx b/tgui/packages/tgui/interfaces/Techweb.jsx index 4328cc01b898a..c041d646d7d99 100644 --- a/tgui/packages/tgui/interfaces/Techweb.jsx +++ b/tgui/packages/tgui/interfaces/Techweb.jsx @@ -1,4 +1,4 @@ -import { sortBy } from 'common/collections'; +import { map, sortBy } from 'common/collections'; import { useState } from 'react'; import { useBackend, useLocalState } from '../backend'; From 0f1f33267644366826c937b7bf7cf389c10a4d3e Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 19 Apr 2024 05:08:28 +1200 Subject: [PATCH 322/938] Automatic changelog for PR #82750 [ci skip] --- html/changelogs/AutoChangeLog-pr-82750.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82750.yml diff --git a/html/changelogs/AutoChangeLog-pr-82750.yml b/html/changelogs/AutoChangeLog-pr-82750.yml new file mode 100644 index 0000000000000..6084c57ffb345 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82750.yml @@ -0,0 +1,4 @@ +author: "Watermelon914" +delete-after: True +changes: + - bugfix: "Fixed RnD consoles not being able to be opened." \ No newline at end of file From ebafdfa5a5222bbfe15f3b9be63f7945da054fa0 Mon Sep 17 00:00:00 2001 From: Thunder12345 Date: Thu, 18 Apr 2024 19:47:28 +0100 Subject: [PATCH 323/938] New docking port sprites (#82729) --- code/modules/shuttle/shuttle.dm | 6 +++--- icons/effects/docking_ports.dmi | Bin 0 -> 697 bytes 2 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 icons/effects/docking_ports.dmi diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index 2088e8f3234c8..fbe3e52e5030f 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -6,8 +6,8 @@ //NORTH default dir /obj/docking_port invisibility = INVISIBILITY_ABSTRACT - icon = 'icons/obj/devices/tracker.dmi' - icon_state = "pinonfar" + icon = 'icons/effects/docking_ports.dmi' + icon_state = "static" resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF anchored = TRUE @@ -436,7 +436,7 @@ /obj/docking_port/mobile name = "shuttle" - icon_state = "pinonclose" + icon_state = "mobile" area_type = SHUTTLE_DEFAULT_SHUTTLE_AREA_TYPE diff --git a/icons/effects/docking_ports.dmi b/icons/effects/docking_ports.dmi new file mode 100644 index 0000000000000000000000000000000000000000..96909d7bd0f3542b097c0a7faab338ec6254db9b GIT binary patch literal 697 zcmV;q0!ICbP))98429Df4q&)Jk{ej#y%*#JiSK`v$_}NLZ50pwMJmkA?Le}G#v>MeP&r5zSkaG2#q zILzH;R6&?qpcIAIn5yi;_n=yX5$Z2$dUM;iHD@9+4#e4K%O^0M9sz@ zsu}BqJ3ny-rT>$t3ZFr-@rSkCxq{^(YQEi`($W)eW7*-X-XMX3Oi=oNnu(SjZmb|@ zY;5Vk8MOY3szl31|0h{?!$$w7(r2a9C`8Lf|0gQl!>yA-SwXSU|1zL7C(j!#8~tC~ zvsxjT6{P;(_nbe`veEzgC0?RsqyIuC8vKnn4d@3tpdaXfT51xIA8aIS`@zl%Z9jPZ z49E{mSs(HP9ncRN2}-RABp^R{eT5@ufPSC@`hiJ6eqa)iA2bv8{GhR=eLvVd!zp-0vEC-00000NkvXXu0mjfP!mIn literal 0 HcmV?d00001 From 1b9ba80604d78ab151d7bc1510c4484a60f41f3c Mon Sep 17 00:00:00 2001 From: Jeremiah <42397676+jlsnow301@users.noreply.github.com> Date: Thu, 18 Apr 2024 12:30:20 -0700 Subject: [PATCH 324/938] Fixes cargo import (#82755) ## About The Pull Request One of the imports got removed and there were no warnings... Man if only there were a technology that could warn us in advance ## Why It's Good For The Game UI fixes ## Changelog :cl: fix: Fixed a bluescreen in cargo console /:cl: --- tgui/packages/tgui/interfaces/Cargo.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgui/packages/tgui/interfaces/Cargo.jsx b/tgui/packages/tgui/interfaces/Cargo.jsx index 24473e42fc7b4..9c7bef54f291d 100644 --- a/tgui/packages/tgui/interfaces/Cargo.jsx +++ b/tgui/packages/tgui/interfaces/Cargo.jsx @@ -1,4 +1,4 @@ -import { filter } from 'common/collections'; +import { filter, sortBy } from 'common/collections'; import { useBackend, useSharedState } from '../backend'; import { From 8a1e6999cbb960fbc7b8f3d5256eaf140a254503 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 19 Apr 2024 07:30:37 +1200 Subject: [PATCH 325/938] Automatic changelog for PR #82755 [ci skip] --- html/changelogs/AutoChangeLog-pr-82755.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82755.yml diff --git a/html/changelogs/AutoChangeLog-pr-82755.yml b/html/changelogs/AutoChangeLog-pr-82755.yml new file mode 100644 index 0000000000000..d98d4d32d3e9a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82755.yml @@ -0,0 +1,4 @@ +author: "jlsnow301" +delete-after: True +changes: + - bugfix: "Fixed a bluescreen in cargo console" \ No newline at end of file From 3842e16a8ba1bab4cbf54c71e70354902485b692 Mon Sep 17 00:00:00 2001 From: Jeremiah <42397676+jlsnow301@users.noreply.github.com> Date: Thu, 18 Apr 2024 12:52:59 -0700 Subject: [PATCH 326/938] Removes virologist job (#82723) ## About The Pull Request As the title says. Removes the job. Whole wing of medical is still there. ![Screenshot 2024-04-17 041852](https://github.com/tgstation/tgstation/assets/42397676/b7b55cd6-b6c1-4a0b-97c8-c7d55d4939ed) (MSO) ![image](https://github.com/tgstation/tgstation/assets/42397676/3be548f4-9558-4d4d-bc7b-d9cbbbac1d5d) ## Why It's Good For The Game It's boring. It's so boring that when it decides to become unboring it just attempts to ruin the fun for everyone else ## Changelog :cl: del: Due to a need for company restructuring, virologists have been laid off by CentCom and doctors can optionally take their place. /:cl: --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> --- _maps/map_files/Birdshot/birdshot.dmm | 17 +---- .../map_files/Deltastation/DeltaStation2.dmm | 4 -- .../map_files/IceBoxStation/IceBoxStation.dmm | 6 -- _maps/map_files/MetaStation/MetaStation.dmm | 5 -- _maps/map_files/NorthStar/north_star.dmm | 13 +--- _maps/map_files/tramstation/tramstation.dmm | 2 - code/__DEFINES/access.dm | 1 - code/__DEFINES/atom_hud.dm | 1 - code/__DEFINES/jobs.dm | 24 ++++--- code/datums/diseases/advance/advance.dm | 4 +- code/datums/id_trim/jobs.dm | 24 ------- code/datums/station_traits/negative_traits.dm | 2 +- code/datums/station_traits/positive_traits.dm | 1 - code/game/gamemodes/objective_items.dm | 2 +- code/game/machinery/computer/crew.dm | 7 +- code/game/machinery/nebula_shielding.dm | 2 +- code/game/objects/effects/landmarks.dm | 3 - code/game/objects/items/storage/bags.dm | 3 - code/game/objects/items/toys.dm | 14 ++-- code/game/objects/structures/bedsheet_bin.dm | 2 +- .../traitor/objectives/destroy_heirloom.dm | 1 - .../traitor/objectives/kidnapping.dm | 1 - .../traitor/objectives/sleeper_protocol.dm | 1 - code/modules/jobs/job_types/medical_doctor.dm | 4 +- code/modules/jobs/job_types/virologist.dm | 60 ------------------ .../computers/item/role_tablet_presets.dm | 9 --- config/jobconfig.toml | 11 +--- icons/obj/card.dmi | Bin 23825 -> 24255 bytes icons/obj/toys/toy.dmi | Bin 51346 -> 51081 bytes tgstation.dme | 1 - .../tgui/interfaces/common/JobToIcon.ts | 1 - 31 files changed, 33 insertions(+), 193 deletions(-) delete mode 100644 code/modules/jobs/job_types/virologist.dm diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm index 9b255ff1ff927..3b3b54fe2ba1e 100644 --- a/_maps/map_files/Birdshot/birdshot.dmm +++ b/_maps/map_files/Birdshot/birdshot.dmm @@ -264,7 +264,6 @@ /obj/structure/chair/office/light{ dir = 8 }, -/obj/effect/landmark/start/virologist, /turf/open/floor/iron/white, /area/station/medical/virology) "agy" = ( @@ -19331,7 +19330,6 @@ /obj/effect/turf_decal/tile/blue{ dir = 1 }, -/obj/effect/landmark/start/virologist, /turf/open/floor/iron/white, /area/station/medical/medbay/aft) "hGE" = ( @@ -25667,10 +25665,6 @@ "jKU" = ( /turf/closed/wall, /area/station/engineering/atmos/storage/gas) -"jLi" = ( -/obj/effect/landmark/start/virologist, -/turf/open/floor/iron/showroomfloor, -/area/station/medical/virology) "jLl" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -35271,13 +35265,6 @@ /obj/machinery/atmospherics/pipe/smart/simple/dark/hidden, /turf/open/floor/iron/grimy, /area/station/tcommsat/server) -"mIa" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/landmark/start/virologist, -/turf/open/floor/iron/white/small, -/area/station/medical/virology) "mIg" = ( /obj/machinery/light/small/directional/west, /turf/open/floor/catwalk_floor/iron_dark, @@ -107022,7 +107009,7 @@ bUv cSk gLb nlS -mIa +eRX gpM sSQ hrF @@ -108560,7 +108547,7 @@ jrk gIF wYA bpS -jLi +hOp nYk vVP xAA diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index 2b35348f40794..4c8e7a2aeed05 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -51032,7 +51032,6 @@ /obj/effect/turf_decal/trimline/green/filled/line{ dir = 10 }, -/obj/effect/landmark/start/virologist, /turf/open/floor/iron/white, /area/station/medical/virology) "mIs" = ( @@ -58192,7 +58191,6 @@ "oDw" = ( /obj/structure/table/glass, /obj/machinery/computer/records/medical/laptop, -/obj/item/toy/figure/virologist, /obj/effect/turf_decal/trimline/green/filled/line{ dir = 1 }, @@ -70718,7 +70716,6 @@ /obj/structure/chair/office/light{ dir = 8 }, -/obj/effect/landmark/start/virologist, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 4 }, @@ -91414,7 +91411,6 @@ /area/station/hallway/secondary/entry) "wOz" = ( /obj/structure/chair/office/light, -/obj/effect/landmark/start/virologist, /obj/effect/turf_decal/trimline/green/filled/warning, /turf/open/floor/iron/white, /area/station/medical/virology) diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index 0280110ed5ac2..ce90b3eba39ce 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -24066,7 +24066,6 @@ /obj/structure/chair/office/light{ dir = 4 }, -/obj/effect/landmark/start/virologist, /turf/open/floor/iron/white, /area/station/medical/virology) "hsh" = ( @@ -45193,7 +45192,6 @@ /obj/effect/turf_decal/trimline/green/filled/line{ dir = 9 }, -/obj/effect/landmark/start/virologist, /obj/structure/chair/stool/directional/east, /turf/open/floor/iron/dark, /area/station/medical/virology) @@ -47715,10 +47713,6 @@ /area/station/maintenance/solars/starboard/fore) "oCs" = ( /obj/structure/table, -/obj/item/toy/figure/virologist{ - pixel_x = -8; - pixel_y = 7 - }, /obj/item/radio/headset/headset_med{ pixel_x = -3; pixel_y = -2 diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index c244dcba5a659..ceb1a6e077aa4 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -24297,9 +24297,6 @@ /obj/machinery/reagentgrinder{ pixel_y = 8 }, -/obj/item/toy/figure/virologist{ - pixel_x = -8 - }, /obj/effect/turf_decal/tile/green/half/contrasted, /obj/machinery/light/small/directional/south, /turf/open/floor/iron/white, @@ -41390,7 +41387,6 @@ /obj/structure/chair/office/light{ dir = 8 }, -/obj/effect/landmark/start/virologist, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/white, /area/station/medical/virology) @@ -51737,7 +51733,6 @@ "syT" = ( /obj/structure/cable, /obj/structure/chair/office/light, -/obj/effect/landmark/start/virologist, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 1 }, diff --git a/_maps/map_files/NorthStar/north_star.dmm b/_maps/map_files/NorthStar/north_star.dmm index 5e86f74088df2..9269439704665 100644 --- a/_maps/map_files/NorthStar/north_star.dmm +++ b/_maps/map_files/NorthStar/north_star.dmm @@ -72967,7 +72967,6 @@ specialfunctions = 4 }, /obj/effect/turf_decal/tile/green/opposingcorners, -/obj/effect/landmark/start/virologist, /turf/open/floor/iron/white, /area/station/medical/virology) "sPs" = ( @@ -76630,14 +76629,6 @@ }, /turf/open/floor/pod/dark, /area/station/maintenance/floor3/port/aft) -"tKr" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/effect/turf_decal/tile/green/opposingcorners, -/obj/effect/landmark/start/virologist, -/turf/open/floor/iron/white, -/area/station/medical/virology) "tKs" = ( /obj/structure/curtain, /obj/structure/fans/tiny{ @@ -196076,7 +196067,7 @@ iOA utl doh gJz -tKr +rPC hwQ piz aWO @@ -196590,7 +196581,7 @@ iOA dfU pZm wJy -tKr +rPC dVV bLm yhv diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index 85381e9b4f7ea..243504f17815b 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -33457,7 +33457,6 @@ /obj/structure/bed{ dir = 4 }, -/obj/effect/landmark/start/virologist, /turf/open/floor/iron/dark, /area/station/medical/virology) "kPf" = ( @@ -67097,7 +67096,6 @@ "wDt" = ( /obj/effect/landmark/event_spawn, /obj/structure/chair/stool/directional/east, -/obj/effect/landmark/start/virologist, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/white, diff --git a/code/__DEFINES/access.dm b/code/__DEFINES/access.dm index f00264d6b1a9f..ef254589129c4 100644 --- a/code/__DEFINES/access.dm +++ b/code/__DEFINES/access.dm @@ -543,7 +543,6 @@ /obj/item/modular_computer/pda/clown = list(REGION_GENERAL), \ /obj/item/modular_computer/pda/mime = list(REGION_GENERAL), \ /obj/item/modular_computer/pda/medical = list(REGION_MEDBAY), \ - /obj/item/modular_computer/pda/viro = list(REGION_MEDBAY), \ /obj/item/modular_computer/pda/coroner = list(REGION_MEDBAY), \ /obj/item/modular_computer/pda/engineering = list(REGION_ENGINEERING), \ /obj/item/modular_computer/pda/security = list(REGION_SECURITY), \ diff --git a/code/__DEFINES/atom_hud.dm b/code/__DEFINES/atom_hud.dm index 8bb5a3344753f..7df79b7e57a26 100644 --- a/code/__DEFINES/atom_hud.dm +++ b/code/__DEFINES/atom_hud.dm @@ -114,7 +114,6 @@ #define SECHUD_SHAFT_MINER "hudshaftminer" #define SECHUD_STATION_ENGINEER "hudstationengineer" #define SECHUD_VETERAN_ADVISOR "hudveteranadvisor" -#define SECHUD_VIROLOGIST "hudvirologist" #define SECHUD_WARDEN "hudwarden" #define SECHUD_CHEF "hudchef" diff --git a/code/__DEFINES/jobs.dm b/code/__DEFINES/jobs.dm index 524deef42f8ea..2c3b151855cef 100644 --- a/code/__DEFINES/jobs.dm +++ b/code/__DEFINES/jobs.dm @@ -71,7 +71,6 @@ #define JOB_MEDICAL_DOCTOR "Medical Doctor" #define JOB_PARAMEDIC "Paramedic" #define JOB_CHEMIST "Chemist" -#define JOB_VIROLOGIST "Virologist" //Science #define JOB_SCIENTIST "Scientist" #define JOB_ROBOTICIST "Roboticist" @@ -151,18 +150,17 @@ #define JOB_DISPLAY_ORDER_MEDICAL_DOCTOR 26 #define JOB_DISPLAY_ORDER_PARAMEDIC 27 #define JOB_DISPLAY_ORDER_CHEMIST 28 -#define JOB_DISPLAY_ORDER_VIROLOGIST 29 -#define JOB_DISPLAY_ORDER_CORONER 30 -#define JOB_DISPLAY_ORDER_RESEARCH_DIRECTOR 31 -#define JOB_DISPLAY_ORDER_SCIENTIST 32 -#define JOB_DISPLAY_ORDER_ROBOTICIST 33 -#define JOB_DISPLAY_ORDER_GENETICIST 34 -#define JOB_DISPLAY_ORDER_HEAD_OF_SECURITY 35 -#define JOB_DISPLAY_ORDER_VETERAN_ADVISOR 36 -#define JOB_DISPLAY_ORDER_WARDEN 37 -#define JOB_DISPLAY_ORDER_DETECTIVE 38 -#define JOB_DISPLAY_ORDER_SECURITY_OFFICER 39 -#define JOB_DISPLAY_ORDER_PRISONER 40 +#define JOB_DISPLAY_ORDER_CORONER 29 +#define JOB_DISPLAY_ORDER_RESEARCH_DIRECTOR 30 +#define JOB_DISPLAY_ORDER_SCIENTIST 31 +#define JOB_DISPLAY_ORDER_ROBOTICIST 32 +#define JOB_DISPLAY_ORDER_GENETICIST 33 +#define JOB_DISPLAY_ORDER_HEAD_OF_SECURITY 34 +#define JOB_DISPLAY_ORDER_VETERAN_ADVISOR 35 +#define JOB_DISPLAY_ORDER_WARDEN 36 +#define JOB_DISPLAY_ORDER_DETECTIVE 37 +#define JOB_DISPLAY_ORDER_SECURITY_OFFICER 38 +#define JOB_DISPLAY_ORDER_PRISONER 39 #define DEPARTMENT_UNASSIGNED "No Department" diff --git a/code/datums/diseases/advance/advance.dm b/code/datums/diseases/advance/advance.dm index 771cdd12e106a..93edea10b41c6 100644 --- a/code/datums/diseases/advance/advance.dm +++ b/code/datums/diseases/advance/advance.dm @@ -1,6 +1,6 @@ /* - Advance Disease is a system for Virologist to Engineer their own disease with symptoms that have effects and properties + Advance Disease is a system for medical to Engineer their own disease with symptoms that have effects and properties which add onto the overall disease. If you need help with creating new symptoms or expanding the advance disease, ask for Giacom on #coderbus. @@ -17,7 +17,7 @@ */ /datum/disease/advance - name = "Unknown" // We will always let our Virologist name our disease. + name = "Unknown" // We will always let our creator name our disease. desc = "An engineered disease which can contain a multitude of symptoms." form = "Advanced Disease" // Will let med-scanners know that this disease was engineered. agent = "advance microbes" diff --git a/code/datums/id_trim/jobs.dm b/code/datums/id_trim/jobs.dm index 3d94c8645b5fa..cfa608011bdf9 100644 --- a/code/datums/id_trim/jobs.dm +++ b/code/datums/id_trim/jobs.dm @@ -1213,30 +1213,6 @@ if(CONFIG_GET(flag/security_has_maint_access)) access |= list(ACCESS_MAINT_TUNNELS) -/datum/id_trim/job/virologist - assignment = "Virologist" - trim_state = "trim_virologist" - department_color = COLOR_MEDICAL_BLUE - subdepartment_color = COLOR_MEDICAL_BLUE - sechud_icon_state = SECHUD_VIROLOGIST - minimal_access = list( - ACCESS_MECH_MEDICAL, - ACCESS_MEDICAL, - ACCESS_MINERAL_STOREROOM, - ACCESS_VIROLOGY, - ACCESS_PHARMACY, - ) - extra_access = list( - ACCESS_PLUMBING, - ACCESS_MORGUE, - ACCESS_SURGERY, - ) - template_access = list( - ACCESS_CAPTAIN, - ACCESS_CHANGE_IDS, - ACCESS_CMO, - ) - job = /datum/job/virologist /datum/id_trim/job/warden assignment = "Warden" diff --git a/code/datums/station_traits/negative_traits.dm b/code/datums/station_traits/negative_traits.dm index e4c16d713cc54..2ce6543c112e4 100644 --- a/code/datums/station_traits/negative_traits.dm +++ b/code/datums/station_traits/negative_traits.dm @@ -591,7 +591,7 @@ //if engineering isnt valid, just send it to the bridge send_supply_pod_to_area(supply_pack_shielding.generate(null), /area/station/command/bridge, /obj/structure/closet/supplypod/centcompod) - // Let the viro know resistence is futile + // Let medical know resistence is futile send_fax_to_area(new /obj/item/paper/fluff/radiation_nebula_virologist(), /area/station/medical/virology, "NT Virology Department", \ force = TRUE, force_pod_type = /obj/structure/closet/supplypod/centcompod) diff --git a/code/datums/station_traits/positive_traits.dm b/code/datums/station_traits/positive_traits.dm index dda21308c96ee..bff2d532570f9 100644 --- a/code/datums/station_traits/positive_traits.dm +++ b/code/datums/station_traits/positive_traits.dm @@ -233,7 +233,6 @@ /datum/job/security_officer = /obj/item/organ/internal/cyberimp/arm/flash, /datum/job/shaft_miner = /obj/item/organ/internal/monster_core/rush_gland, /datum/job/station_engineer = /obj/item/organ/internal/cyberimp/arm/toolset, - /datum/job/virologist = /obj/item/organ/internal/lungs/cybernetic/tier2, /datum/job/warden = /obj/item/organ/internal/cyberimp/eyes/hud/security, ) diff --git a/code/game/gamemodes/objective_items.dm b/code/game/gamemodes/objective_items.dm index 328531d88c675..b3ad7108ba536 100644 --- a/code/game/gamemodes/objective_items.dm +++ b/code/game/gamemodes/objective_items.dm @@ -574,7 +574,7 @@ /datum/objective_item/steal/traitor/moth_plush name = "cute moth plush toy" targetitem = /obj/item/toy/plush/moth - excludefromjob = list(JOB_PSYCHOLOGIST, JOB_PARAMEDIC, JOB_CHEMIST, JOB_MEDICAL_DOCTOR, JOB_VIROLOGIST, JOB_CHIEF_MEDICAL_OFFICER, JOB_CORONER) + excludefromjob = list(JOB_PSYCHOLOGIST, JOB_PARAMEDIC, JOB_CHEMIST, JOB_MEDICAL_DOCTOR, JOB_CHIEF_MEDICAL_OFFICER, JOB_CORONER) exists_on_map = TRUE difficulty = 1 steal_hint = "A moth plush toy. The Psychologist has one to help console patients." diff --git a/code/game/machinery/computer/crew.dm b/code/game/machinery/computer/crew.dm index 7b66d72a98c10..268b675871ab2 100644 --- a/code/game/machinery/computer/crew.dm +++ b/code/game/machinery/computer/crew.dm @@ -109,10 +109,9 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new) // 20-29: Medbay JOB_CHIEF_MEDICAL_OFFICER = 20, JOB_CHEMIST = 21, - JOB_VIROLOGIST = 22, - JOB_MEDICAL_DOCTOR = 23, - JOB_PARAMEDIC = 24, - JOB_CORONER = 25, + JOB_MEDICAL_DOCTOR = 22, + JOB_PARAMEDIC = 23, + JOB_CORONER = 24, // 30-39: Science JOB_RESEARCH_DIRECTOR = 30, JOB_SCIENTIST = 31, diff --git a/code/game/machinery/nebula_shielding.dm b/code/game/machinery/nebula_shielding.dm index cd10a23150c87..10306177ebf5a 100644 --- a/code/game/machinery/nebula_shielding.dm +++ b/code/game/machinery/nebula_shielding.dm @@ -145,7 +145,7 @@ More circuit boards can be ordered through cargo. Consider setting up auxillary shielding units in-case of destruction, power loss or sabotage. "} -/// Warns the viro that they can't use radioactive resonance +/// Warns medical that they can't use radioactive resonance /obj/item/paper/fluff/radiation_nebula_virologist name = "radioactive resonance" default_raw_text = {"EXTREME IMPORTANCE!!!!
    diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm index ce008b35f13fe..64c0afe188a8a 100644 --- a/code/game/objects/effects/landmarks.dm +++ b/code/game/objects/effects/landmarks.dm @@ -189,9 +189,6 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark) name = "Chief Medical Officer" icon_state = "Chief Medical Officer" -/obj/effect/landmark/start/virologist - name = "Virologist" - icon_state = "Virologist" /obj/effect/landmark/start/psychologist name = "Psychologist" diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm index cc548be16d27e..71731bd80c0ca 100644 --- a/code/game/objects/items/storage/bags.dm +++ b/code/game/objects/items/storage/bags.dm @@ -467,9 +467,6 @@ /obj/item/reagent_containers/syringe, )) -/* - * Biowaste bag (mostly for virologists) - */ /obj/item/storage/bag/bio name = "bio bag" diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 6a5b6357a8f49..d5e09ee8a745c 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -128,11 +128,11 @@ force = 0 var/random_color = TRUE /// the string of the dmi state the balloon has while on the floor. - var/world_state + var/world_state /// the string of the dmi state the balloon has while in your inventory. - var/storage_state + var/storage_state /// the string describing the name of balloon's current colour. - var/current_color + var/current_color /obj/item/toy/balloon/long name = "long balloon" @@ -183,9 +183,9 @@ ) for(var/list/pair_of_colors in balloon_combos) if((hit_by.current_color == pair_of_colors[1] && current_color == pair_of_colors[2]) || (current_color == pair_of_colors[1] && hit_by.current_color == pair_of_colors[2])) - var/path_to_spawn = balloon_combos[pair_of_colors] + var/path_to_spawn = balloon_combos[pair_of_colors] user.put_in_hands(new path_to_spawn) - break + break qdel(hit_by) qdel(src) return TRUE @@ -1381,10 +1381,6 @@ toysay = "I am the law!" toysound = 'sound/runtime/complionator/dredd.ogg' -/obj/item/toy/figure/virologist - name = "\improper Virologist action figure" - icon_state = "virologist" - toysay = "The cure is potassium!" /obj/item/toy/figure/warden name = "\improper Warden action figure" diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm index 8b4fef65293a8..d95bda33b1eac 100644 --- a/code/game/objects/structures/bedsheet_bin.dm +++ b/code/game/objects/structures/bedsheet_bin.dm @@ -223,7 +223,7 @@ LINEN BINS /obj/item/bedsheet/medical name = "medical blanket" - desc = "It's a sterilized* blanket commonly used in the Medbay. *Sterilization is voided if a virologist is present onboard the station." + desc = "It's a 'sterilized' blanket commonly used in the Medbay." icon_state = "sheetmedical" inhand_icon_state = "sheetmedical" dream_messages = list("healing", "life", "surgery", "a doctor") diff --git a/code/modules/antagonists/traitor/objectives/destroy_heirloom.dm b/code/modules/antagonists/traitor/objectives/destroy_heirloom.dm index 0d62ecece5f2a..59ea9b20afa7a 100644 --- a/code/modules/antagonists/traitor/objectives/destroy_heirloom.dm +++ b/code/modules/antagonists/traitor/objectives/destroy_heirloom.dm @@ -41,7 +41,6 @@ target_jobs = list( // Medical /datum/job/doctor, - /datum/job/virologist, /datum/job/paramedic, /datum/job/psychologist, /datum/job/chemist, diff --git a/code/modules/antagonists/traitor/objectives/kidnapping.dm b/code/modules/antagonists/traitor/objectives/kidnapping.dm index d6aec912fdbac..85aad594516d9 100644 --- a/code/modules/antagonists/traitor/objectives/kidnapping.dm +++ b/code/modules/antagonists/traitor/objectives/kidnapping.dm @@ -48,7 +48,6 @@ /datum/job/chemist, /datum/job/doctor, /datum/job/psychologist, - /datum/job/virologist, // Science /datum/job/geneticist, /datum/job/roboticist, diff --git a/code/modules/antagonists/traitor/objectives/sleeper_protocol.dm b/code/modules/antagonists/traitor/objectives/sleeper_protocol.dm index f28a79d692669..6ec71ff08bd90 100644 --- a/code/modules/antagonists/traitor/objectives/sleeper_protocol.dm +++ b/code/modules/antagonists/traitor/objectives/sleeper_protocol.dm @@ -18,7 +18,6 @@ JOB_CHIEF_MEDICAL_OFFICER, JOB_MEDICAL_DOCTOR, JOB_PARAMEDIC, - JOB_VIROLOGIST, JOB_ROBOTICIST, ) diff --git a/code/modules/jobs/job_types/medical_doctor.dm b/code/modules/jobs/job_types/medical_doctor.dm index e3a396609eb26..a0f2971df2306 100644 --- a/code/modules/jobs/job_types/medical_doctor.dm +++ b/code/modules/jobs/job_types/medical_doctor.dm @@ -4,8 +4,8 @@ scan everyone in sight" department_head = list(JOB_CHIEF_MEDICAL_OFFICER) faction = FACTION_STATION - total_positions = 5 - spawn_positions = 3 + total_positions = 6 + spawn_positions = 4 supervisors = SUPERVISOR_CMO exp_granted_type = EXP_TYPE_CREW config_tag = "MEDICAL_DOCTOR" diff --git a/code/modules/jobs/job_types/virologist.dm b/code/modules/jobs/job_types/virologist.dm deleted file mode 100644 index bdbfd7d687ca4..0000000000000 --- a/code/modules/jobs/job_types/virologist.dm +++ /dev/null @@ -1,60 +0,0 @@ -/datum/job/virologist - title = JOB_VIROLOGIST - description = "Study the effects of various diseases and synthesize a \ - vaccine for them. Engineer beneficial viruses." - department_head = list(JOB_CHIEF_MEDICAL_OFFICER) - faction = FACTION_STATION - total_positions = 1 - spawn_positions = 1 - supervisors = SUPERVISOR_CMO - exp_requirements = 60 - exp_required_type = EXP_TYPE_CREW - exp_granted_type = EXP_TYPE_CREW - config_tag = "VIROLOGIST" - - outfit = /datum/outfit/job/virologist - plasmaman_outfit = /datum/outfit/plasmaman/viro - - paycheck = PAYCHECK_CREW - paycheck_department = ACCOUNT_MED - - liver_traits = list(TRAIT_MEDICAL_METABOLISM) - - display_order = JOB_DISPLAY_ORDER_VIROLOGIST - bounty_types = CIV_JOB_VIRO - departments_list = list( - /datum/job_department/medical, - ) - - family_heirlooms = list(/obj/item/reagent_containers/syringe, /obj/item/statuebust/hippocratic) - - mail_goodies = list( - /obj/item/reagent_containers/cup/bottle/random_virus = 15, - /obj/item/reagent_containers/cup/bottle/formaldehyde = 10, - /obj/item/reagent_containers/cup/bottle/synaptizine = 10, - /obj/item/stack/sheet/mineral/plasma = 10, - /obj/item/stack/sheet/mineral/uranium = 5, - ) - rpg_title = "Plague Doctor" - job_flags = STATION_JOB_FLAGS - - -/datum/outfit/job/virologist - name = "Virologist" - jobtype = /datum/job/virologist - - id_trim = /datum/id_trim/job/virologist - uniform = /obj/item/clothing/under/rank/medical/virologist - suit = /obj/item/clothing/suit/toggle/labcoat/virologist - suit_store = /obj/item/flashlight/pen - belt = /obj/item/modular_computer/pda/viro - ears = /obj/item/radio/headset/headset_med - mask = /obj/item/clothing/mask/surgical - shoes = /obj/item/clothing/shoes/sneakers/white - - backpack = /obj/item/storage/backpack/virology - satchel = /obj/item/storage/backpack/satchel/vir - duffelbag = /obj/item/storage/backpack/duffelbag/virology - messenger = /obj/item/storage/backpack/messenger/vir - - box = /obj/item/storage/box/survival/medical diff --git a/code/modules/modular_computers/computers/item/role_tablet_presets.dm b/code/modules/modular_computers/computers/item/role_tablet_presets.dm index 38989d45d2d51..ee6c9ee68f0af 100644 --- a/code/modules/modular_computers/computers/item/role_tablet_presets.dm +++ b/code/modules/modular_computers/computers/item/role_tablet_presets.dm @@ -230,15 +230,6 @@ /datum/computer_file/program/radar/lifeline, ) -/obj/item/modular_computer/pda/viro - name = "virology PDA" - greyscale_config = /datum/greyscale_config/tablet/stripe_double - greyscale_colors = "#FAFAFA#355FAC#57C451" - starting_programs = list( - /datum/computer_file/program/records/medical, - /datum/computer_file/program/robocontrol, - ) - /obj/item/modular_computer/pda/chemist name = "chemist PDA" greyscale_config = /datum/greyscale_config/tablet/stripe_thick diff --git a/config/jobconfig.toml b/config/jobconfig.toml index 7106d2f2a4ef5..294868e28bb5e 100644 --- a/config/jobconfig.toml +++ b/config/jobconfig.toml @@ -183,8 +183,8 @@ "# Playtime Requirements" = 0 "# Required Account Age" = 0 "# Required Character Age" = 0 -"# Spawn Positions" = 3 -"# Total Positions" = 5 +"# Spawn Positions" = 4 +"# Total Positions" = 6 [MIME] "# Playtime Requirements" = 0 @@ -270,13 +270,6 @@ "# Spawn Positions" = 0 "# Total Positions" = 0 -[VIROLOGIST] -"# Playtime Requirements" = 60 -"# Required Account Age" = 0 -"# Required Character Age" = 0 -"# Spawn Positions" = 1 -"# Total Positions" = 1 - [WARDEN] "# Playtime Requirements" = 300 "# Required Account Age" = 7 diff --git a/icons/obj/card.dmi b/icons/obj/card.dmi index 5bcd1df47d929bbf13f5fe8e41ecb1175f782fd2..95453cb46edc8b171912b8a5acd657ef809682bf 100644 GIT binary patch literal 24255 zcmcG$1yCGa*YDed6Fj(Eun^qcf+ToIumFRG5C{?=5ZnR;C%C(NaDpeeySq#9K?a%A zd7kgR-@WHnovK^sT&k#^-qSPm?p}MX_5ZEaeA7@<#Cb&V2mk<_7fR1x0RW`^?=J=# zI3mE*;0ORHK5nmdot|4bntigece1jx1pwF7G`)^bltS1N%FwD9g9WwJ+`c~af?;zH z`*{cV6;$L>+7hGMU-#&SaW&uOHQ=rF}w%33|{KVP*pwY0rG)~(Lf zHPoT?cCR=3)Ad#de7RhqL#@0pcd97JTV7rwlpeNUB6JW(IyB|%Tx%roQi8Uv&F6mq zl~RcBiht$f6k2Jr_tnv}KX9LpEywvJ{F;hhm@dL43K!t)Y%I7G-<@#V5*f{EDlhlC zIZgT_#N_#;-jmv0?wxO1#CJXFuk8aej=8P2ad@Fh{d)7gULscFQTiiek20wzer$=` zJ_<{D35|51obVE{%paeLtu|+zyksVq?_$G?tU-Sb39C-uG$;DfO3;8(R4Hy1rRw%~bsNk}i|FT=o=w@YtY;HwIPg zj4?zab&ttMIIrwq;O0(NlcIN?cQ~`i{(Uk)7+Ux-${4MhlM!gl;gR1s_p_k01|yU^cKp8cFYvyIAiX{fQFD zp2A5wsO2sv#@nR9L+ib72wko{>`Y8Zs3G?p*j7r2Y-B8pJlPt4<-$6Ni9K|v@qUD+ zZXf0AC!4j8(eNfrry_SaoA2=q`&P?y@9v22zg6e`UD)?3!)o%ijj!#eCsVjNXQHd~ zZR31*=Jm8_g;9*9@Vq@sT2~gm?*ks*ze$6}4HB zvrP+8R-W@-Lew#qIYC!To#03*jpm0YhWwL9@>=1_qUM}QwT`(QESO11mcrVcmDxF3 z1JTNLHq_w~bA{KX#B*_5>(MCDQ)&kUwp2+6t7A3+B{kG9JdOQQRzAnBBB({)vdjPK zIp|k6bZP!=tTXlIz;^7I5H(@fy;YYd~q5fzPMzDcQIy?V}bRYsb}YHr&G^2!)f@u4Qs!>jw;K6!Ey9nmt@H}T!1z=s)wvb#bnF*PwUA))iG2_1g!mM(5+=-K>JbP0B({>C|y zo{I|)MFt-wOQ`9+C-BcJRC6D28^B4A{DhON?&CuD$A!A^3AiwZUxV;&F${tqAY=oM zxWo4fAb|J%0aOG?6#SShGvUvGvF;a$9o1l5SXzn#h+nVz?@knqpqd1Phlf)E7l(6N zF=mtc8FaGb{z5s@JA+BTAngNOZKVS#N(X1v@7grVcl|L#AD*(an+T@hu(7ep@)a&& zKmw+3Ou8K>RD~eGviq^b8&xIi`(a+Q?IoI&rg~eiDbS^}4Wv!0@=J~Fefr)ic_E?T zhEhw7*yBti&V-fb$My zC34A5s}{MR5m~MGUPm_i&B|YOR=lKU*w??bl|#m75?XsO?1xiD7X9%gSqDQi8eql& z`U&0(bst0EZoHlO`OLV$j~_pP6XxFdud>f~!%tE89!==C@eL-``yl%aAt&>kKX-XH zVu%LlCZ~k9dM*%5myixm%`legZ~@YDGFaMW275J;H&;vOfbRLA6hTHE8ctp)KCuPS z*-YDsU#RVh7aQ96OnvJDMwGl%TwL62-A78mc)rG}ldyi8z@#z-t(LQ`W^W{YsEGK~ zqw1hUEwZ8cUFTGqsNfi~4+MCGg_T6`39t*$R|wEoG@c?;w^hOr#a$xU3XT^+=)!Hpt@FN9iKY^hAn1H9KMjWoKP^ci!qT?l4p>UJr z_44JTo~Q1&3~$2h_rvSqEq^YrR*q^OYOE%(-&K>Vs;Z_+z_s{g>r}x5No^P}daiAo z_L!T&Q#PQ>=4QH2O{Fq$+spg0O{(PCJ&u>Y>Gnh+$J`Eeyyv2898cT6H90djJKG;v zJ&Wb4$8DFo$D_LCS9Z64}ce({UiD1Mj(s9|e zKxebCdP%MUlt4}At6~0 zBiV+k6#nkXIhM&N(EcKx->(?IZh!9ucw|JyE@R$Jc>gJ)c=Arc_@PEI>H%*0nz+_< zcmDLfq=7$WIv4WaJ5&YS%f(@G5%>R&dd_{{?&Y*Mj=D3F;gZxUVEUx)at|w}Z@orp8v0s?^dQ!b zS5HHSG<2(R;ACw_tjc@EXx8TAdz%kP;Pjx=fL@Hz%a}~yU#W{YM zq$CtusTgWt5Vp8zU~XZtcG^ShqOU`7T6Lq$)k4J8dYwH2-&xV^<=J4DcpbFCG?Zws z)x?dsV7f;|z6+`)0q?BC3pW>~dh*2E;%pK=X=`OH)9jqF*~x%3vz(LjBQ4$0X*A&d z(f+*FxtlIoDSO6m^c5Raz$7YQoCqkVbQD8VyG1cnrsQ@^HhazU_Xd8X&78C8ZgM_I z4Qn^dtI(!Rn%w-YFsgS>xKVUhD)pL^OT#mFyjNX+IyRO_?eCuPGo)ArzhxVp*B-xh zL^4b~1G3Rk6C^u3J7qJjCKu^lJOwLM*&|XyXMK(_HC14@Z95KSZ@k z24hjw^8Bc)a^d3$XuO#WX$n@NlK33vy&f6-JfV_P*!!rNy9^7d)pVk_3Wwf4ny3`ROMb)x~U`R-IC3H)oWFRCk-qZ)@9k3&LmKOLz=IlS8n zU-I0QB&7YY8DdqJ6Xp_#`GP^hlm=+t3K9Jk4c^~F=vYW0Nu$n(Qsw&0mZWO z{KfE#8PbjEZ0*v@E67%a~{$llx*F@RC52jsVXcPvK%F>1<%@M&GNdb#hW%KH$@r@pqHMKTI~1b*oIj z+LtGAyzTz#hlw=o>8Gcs$DJ~SW;fhM(XC@(fK3wqGKZ@%f4I?cC)?$CS-0^M6B-Uh zKy$PBGlK?v>zQ(SFE7b_)s#S?W!GOtY?EoHjT7i}iBK&wWWX!eaAYD6xZYOrp#>a; zuHPT8HIPjvoZW<`+=Qr5p+3w=o~eoN+jeaXG>hsu6GUH&2$C2!1+3lOICk=1uF9lJ zdDDQyiG1#YlGpFp-B_NOZct>pAO)~d0v+m<5P;IiC^C1^@}K2zj=6$P#Oj$}5ZBtw z=`9}U3hU?crm10XWAP+K_PE(fz$xuJO13U1fWPwKK?-bGzX3fl(mW}vC5kV1yL2qH zJY#ajD7;|`9;0;6{*@bI>4@7%5AgUoOJ%#K8)gbR~PxUwz_by8aT?BZyNvbMIiVLREH+vR9c?Eu-Q z%T)fOvw;3vedAhP<63=<*B&TsFPsvg^V~67h~*6Re>{a3dj3(TC?KVaR@+{l@k(Qb zmjvOmqsC8b>pykAx9&2t95^t)U`U!MTgcy}WWBmVeI zBxnu2PxnO}x9y=Gr}711e-nk10z3uWMqe)9!*jFuhF;nxb_;bw@+&%w=8SZ(ka+08 zX}9ZQ)yDbPtc3)@9%5q^rRS? zX%Plu_dnm8ImYsbHsPos12r@p^5C3C7uk-k{(8k46J~IzE8mc0F!@7wkn_qKoat-j z+=YRqrq^=j%qazLhTs`JK*|>g@&|WBx7SE-8m%bZO zyif7^&H2Eq+k&iJ++#+3Z`c(To9rtR?%hRv)r+FL<%E?#bcxbr5d4PSipoljF$_Q7 z=`Fkf0$xuEPr)G_x64B-)@RQ)k%%Gi4<4W3;0@Aku%};k-N1SByM)WWTqD1^2z6^AQQDh~=& zChNnxdP+FJSiA8U(*0cVmpN~TId7U-&)*!1zrKELK$+`}xHh2=&jt%Jkp3{E542B- z5LT^i!GLRDBJR(M^}95kyr%=BZ>9uZ-A738>yRS#2E2p6_B!rAo*JQd?#4hO_w+dJ zB8}qnGft+<^t=%>3-FD2U=C|TOA)f$em9)TmU^yX{cu6L=kwUR?pWnF%hX7JzwF14 z9B1d}RSp{po7>w+8b><^rIG-DYH@dFho0J(gj^Rz0nw9Ba2IJ&`<|UXS;=u^m=1uA9+++|sHe74$^DJTj~bTw?TT-@hYO&rzLR0dqpqNnVvW z8ZQgupkWsVPVY8Z+zDC>uY(7y@qd2y_D$lm?7zIPg8APtcyPbBvDv&MM}Mzj=E@1vBkb7IzP)PAjHBfptXxU!kf#0pZ`?^LvRacYT=Hw*EqzAt#DqfQ zvvF5AkAU=|Upw55&q}=59=)~IjeK&sh2x$PYJj5awjMCyp?ONM8l5+Ls0=ZhLjqjk zV+M0~L*9DWK;bh;8F# z>jEhm_J-CtUft=pZ{NbdPMNM1T;><%4q2Z3QI?+HiGXnC1?^u4S3Z0E))rM#>Tp(Z zkA9h~!h@MAp&X8$UuqCo(nXN@{5+yqX@^(vR9J8GsClB z$ZC$p_)LLU0d^F_lqN0e%CF&wd>Cg=->ei zMY)*jT=!V|e+cN7Q3r`tb?FHqUKbCaRcXhSplxsnk96QH#_w}CnS-;?a1HTeuH%p1 zJv`_BcUpRKa{lLT-(eL=_Rf~LGR~XX+_hoq)}AS4I0|OD+~O^T*BG527OFr4y8g^# z|7R6#(F%G6u6reYpyL`aUM@4VXF2rrSye0}>Er)G@Vsz!hK|gyA<={@A6aAQT2=-+ zPvpEc%R^?yDc!bA;Oh2*O0d~8U8r$V(1tD4De1?ScWv9^otn;$uU2VaD4i@Sue4v3 zuV=D~>IN2*C(lpXYr+J_uV$H8e2oPOzcIB0pT@ROL5&t7PDk#gh9cAG7G=Sqbo2*Qq{!|)qrG8C_n z#Rs)MDJ>}Z9SC@@;RncY$|w{E9$D}UNintZRR~nL3ZPPR9)5IGC>QdsesncolMGEw z8OUj6Tz$Z=;bcI=rNRJ&-7X5XlIbvX-V?FP7(7==;{B?uqC&K7{ozBUSr4uohcBHu z9rBalP;7?@mLysk)|~e~eD9Y3R3VHHwsmj-jhG*cR!h&%2_bEJ4B9Il5b4|RGXjlS zFETEsMiC~*;fq^l%Q};+sr=uNeM-~BEM~0i>~?@vUv!#w#}SF0AL0xQe%R4;hYc5y z>5nE9!=k2{gMeq*t=N$RcR(~^M z_22tq4aM2o7xSgdF&uj_trYOVyI7S<`|&3cOQPd^ z--Ohj`UOiEm=(_?R}OojoBk7f0P<`I45qDrFb<}$w*ArZL46No9%iDJXqW#^q5uS> zQ3n_AZjX?G(l6T?!Rp8nBnkGKnhKS7Fs|lRhUI!_h)n5-tD`noSh9e8A_7rg> z6^#$EY+4O@%EM+;`yUL9ZG zge*}cKzU?UF_c5CU|iXT|+WuHa_RWpQ15w`|7Ho3FfZmo8nm z5s6VTQU**C*WJ274;&$3_ke2|Q~s-C>YUr756vU$^6g#L1*J)=HOx{t#fcio1YdwE zQv~t31nN5brVZRBi#@j+XYm}m*r?VvU2XSm*xF`v-C0se;#lH4*vY8c`!Nu3<9^&i z+7m%7*Eg1JgflbtnWtB!%3kY1b`H;6L>(N$T^Aq_*wO>)GQG(^%KG; z{PLFq!GGa_&l`4~r?$P*5FZfB1g*&hHI_P7uHpm6*P|wC2j15=YJd-@27rK+ilQnA zfOswOf#kZt-W_$K7S3mq&S80gBz=t1(<`K4vZfCBl$L7B%A*1kq@+=;xEDK|#VCM{ z!30b0z{=v{A%9ts=EIuqDTX@Qf^BRsM#W+)^_xg>KQA^mfKCNHzhI*v!@IlP7n#SR zpJ;eetS|3w-Cckz_!vPP$#q^SD1(A0_v)pT+M>{jsVtKujVB&lytaR%J1+8B*BbmD zxR#V*D}7Zc@y7r6AjV+ECB`@u8U|WDwxJl!P>{9#uX76}H8lkln`fmYSf$!n@%g$A zqT51b(_9oAEN4SpKih1&v(8BFpr`atm7m>wKx(qdmW(B~KkyPe?z? zZFJguMZd&riJJ}enzOnoeiL!ql%J0lt;xf=)drh>TV*kzop7eqcs@-2<3_XF76T6t zOfb-gXZ63{(feOxT>TnxG3^>6;ioP4bw2Em3IjwU&V?~Xjk!_&%qlA@H%?Bz2BiN| zKrOAWYy;p3R-dB_{n*s}xL;F~sG=H@cUJuK=caJq``z(8tl)FY1Z5om{?6oXQeEr2S8WEuh)%;V zktTl@Y0dE(ikr~DjBZv$@X?ztLa51lqgq084*&XHt0oIht8+4s9ivQW^WraIpmpO$U~l5er>C zW<&?7c&b>%^g^z$-^8YNdUz3O+W(yGw+NVRn}bj+d@F|A_$X}V$Cmx9=XtBSsYF3um> z1ipSX89to5UZs3^acbb%Vt*b4+eal#-SIU_y!p96Ao&j2R@J7xhgS3{dJfNHXBZAQ zEQIvT=z3)&xMVlN*EsI2bApGUbJb_*=Fg0P>lKj%0n~_nDTUulzhJlnCseSYd z@>hQA4{_{L!0+GPAP164WbZf3*Z$ejYhqoE84ZoCN-_2WZLL$3wqkglQ96?86vfVl zqy*>m^v;+r6c(%TLcdh7?J_wzIV4Li=qYDKMa7kM+wv=I?La?2r1}AWtM;tlU=Hh7 zXV)>8yl?%>EF0Yk@E}w*eEuYYMyy-WgCKhM@ia)f(n#~2O-$^ix(7N$Zo7Vb8DM^P z+=jg%weoEP$)*IO!+y-rI4qbuYx@jhY!iE_xIfa%Zsxs#lN46YrJB(tMXt99HwNw zTdL10SU9W3(6H^lUJJ4Vgu^rjE4(EX1ZjOH?rB4~kzc{hJRLgx$ScR8pxV`d)hbZI z%Jizc?Y9TX3${n3<-dl|{wfFM=}1-8?l==Rh$9K}tI+Y*?{3ZuLxYKurQQF-B@FWK zq=8l~?_UE4(NFe}QC4}K|AL~ckK&<=D>Li2Gt3*^kuH7v)esERd+U!gS&FhKb>4

    d^=*I6i{wjHCNFM)H5glp8shNMAp8m`21zMfq4wNU z=tM;+M)C@<_TuA73Y>L~YVHkX@-RSvyZqcIjMnQKEdl!Q7LYbD;7?B04=B{Y4FQ&N zuE4^9XDNc~>C=}=72q`KNQvS8*%0ss+UvRhJV3gg$SZ2W(QaQ}rw%Ji^5GIcaVBjs>oGis)hE5g$dx4521?^WSu+|ao` z?P*aPTLDc`-pvh7|E(G_hB>XV{ph?;ji7Ov2|@a++=7=Vt``YV14ZBXSPX(pg7zUT zl8sYhbpW7&)=~ZCK@y4~QL(7lqC&qVKSV&|=cRDuU7R?PN{hGc^glC7c*`YEoGl1W znbnq2^vN}uY=1lQYu!3A`VYE|vHlCFfsc*Ga_H!}w@Qn3sZpQQJ*04mJ z=%({iU~8ky<|zw%flGy(;x!fQ1!Mc_-A1dw|cV?oT3ma^S327YtR z{s;-!<8t>vwd74Q=2w_+`%yKv(cwZXMwx?l;V``T+dDd^xR99pGwFri*00&C`>RfO z9I6L+FDEw59SfWIlKxw09=$nx2_b2QAn+7ygU4#;VrJyQt7xHrbMkD~C+7U$aMdkC-X6|zk z(C_Z<+I#i%esCye1^xL^P1=MI@gL|GeoSntAJdzN3o9(Cr)tgW02v3xSJLzK5^{po!7F+eP*+V|7-&}9U!iE$V|l838unDR|%2(Ib!;T+A? zLK0VZfExKU{+jG_2JYjb9sx~ew{1@&3 zGU4q;mLkosvE&&1Ryt8@G@6%(ctC^4k;Gr6-=V7*L4ynyi*TugeL(X^y!tW4u$*lLIDytix+OB(IYlHMSOZ3{fB1AgTQUz+@bANl8EqqKf&T=0$hFIxPC~)6v zyl|2}OO~@Fhk9W6p>HuJSuyvxu z1Gsir!Mncv*|JMc3I^6!u3X%9FXAhQyRZ2Y7cv)@-QO3S+pq4V#5j0gJ;hFm4G}r6 z$@#HQ1gyr~-uBwwwm*>klVsCA%!MQ-l6BpqW0g#WP>X#g14aK+7LGQlt2U{-hGTS4 z?JFt02@Yu8g^%4X;0P@WPZgEHdOXiEd_SR6645Pbv(ft4pDM$;;`#${_JsM>Z@x7& zO@2X17wGic5BzLwNnSclCW9CquI60G=UVx2{nv}g-Ba5?pt{r=O9c@X-mcL0-eHt! z-pOBUWHDQau-tbnCC6?pmRDRKoiFfZ;OwhD2Zc|bqzrxs<0cONDm&F_bB!#6=XhHp z4ATz-moxzK7?iuuGo$ZGSiz#VjKN{lKO;>6|D}lkyY!9WN9Tn3S39F*Dfa@Hesmay ze?>8h%)|2JGGzV!JvYjZy)2&9&D5;wbGHBV0&u#srXjAc zUDdGu93I-NQEl$*9PH2kJz8nxr#>PG98?=PA9^@mH;Wp;V$O0xSbe>IK%Q(tpS!`E z77^Oq+G69x&co6u2@#T#TA?e)m@FsCb<=w6^>rXBIk_LKAvfku$%dYn zJKaO}m%a5R?IFWgt;sOonsw5g0(2gp4;cvKnV+^e8b^CU4ppguOYhR%2g*;Z622jk z@^-{g+6r`};75&+vmRq2&CAoSzfavNa;D1iTSV65CV<{{6uUQv09zUdD8W0m4Zv2X zw*WgzBf?jkAamYACj>qj0o2;~#aTl}*M(*2AEQhP(UcuamBGkg@s0BWkIbnz-=MI5 zL6R^Zp(F`Lwhx*{d!`VI0GHM>`4?+NZ-)=F#@`Of1Zy^L!~ zCcw!2LxxdyjL>kswm{ivx?(|^tRd7N=+_Mmr6*#LE*oXa$F0Y(I>m_e zsG$)m;dU#%?RE&~L25A{<-fMBnh4hag+5)7@e2sjm0OAr5^wEJuvAUl#vRF-WKjLP zF31P(k|`(wATCb8$gYG4@-o5sn8ttm9XqgkT#|tTfO&KgX6#?mgcjNrGQaM+g>UKi*?SL7^SA;jXhSM)7nb}Ao#wpsAKQVsqA{{>xw$A|~8|9gq?Q9j9nbK2~8V0A<7P6?QsGS+f zx%v5@^78VOR8_Y?!j1#JG(P`8?Z1eCehkE=etK8*tzq5F8^jN2wdLO0MtMd0l}$nS zMPKlKzyt4#Jntg*m(1WOrv2|1kl((WW>ia z?*>;i{+$L`lA1jOsPLdRMxjB{9Oa(U5BfUi%a(C%i?3B{+%QaM(yl!g&R^fs2GhDe zdi2Qe6=KfjV_`+v{&!Kjjb`B$@b(#Ka*A1mjew!OQta5>Bt0)L80YfeT23>c^l2A* zArv$CDcw-E28aDs?f{K~-#2YyuAG`0A|J;my4u?BjBh^BeZ0{)Sd$9_oAWjhN8oCe zx|OTChvZK!c@{?Q7(B?WK3?M?TW&h~eixroYFG*VZ=F z0(D)lg_{Cz$RID(edbx68%mtT8LElTbgRQC;Gf=Sm01u{9iS5lc^47iL$U}UA8vro zi`v86$)`w@pH^vC&4r7lJb*J#uMRSlsW}V{s=X?wSFilEyk5ORLc=-aYBuX-kd`wt zGNK#!2mKoH++UI#eEP&|YHIfN3b+FGmY0-8anDDo#VW(oyc7E&`RTNQbI~F6Y%TrrzrJaV~SjOqdo0<&qT&18IHsRI+|ci0WD_y^Z1mFgJ%zyid!2fCl@gF0@1a&T0$eI1Ir&>|311FkKB+yeE z=nm`sz7)^!PXH#Abo2hX7D!njic_q~DXatPBu8)Fjt=rsW)z8XsPM!*$8@fQFfGqI7G~5(RbJ z^GLY2NsE`>$*^yH_zc~-w{S4GW903*xM276=tqpf3V51?+W#WW|0ibEto913elfGQ zy8nf&)!cu;Y4X{s&A2n*qgkDLm2jpEQ5d2K0S}N9G9UlT}2+doh*1e!OiHs%RN1L`0D;_^rFDR7hwtf z!hJy!RMO+C1P^&GcS($dlO#)&bimrW-3J?>ok9FW(+FnCsa2O+#@=l}@GV1-8oW9n zP&Md1*1u1RN^fmwZ?zTC7MFaQDF2f#Djfk{l9OFYy1e5*u1+hG32bkNr-{wV*?Nj_ zy}l&x-bpo$ti`rfQJU$?i*SF`i&9n$5FJ0LfS*7r>Lq^E6SPAz#=VR1(81vJy-Kz* z>zf8-i8Awls>$2GFCf;MZrk-UWT`kqT-gfNA+9w;M!%qP*y3(5C0F;u1Mse8+qVC=i zihr6}A$Uu8R2*{F@W;B(Qp3LaO`_!BF3J{; zlrQDbSG`bgvn5(6_kpB(Z<@P6q#Vw@8fB(I*Zf?+w#w(vbr(-ini&Ks7&UcP0Idqw zg1f|7-Q0^m=#KJ@10Wk^JycC9IUXVzzimZG(h(?Cj!5Nzf&KiYSN8NxB>!*BJ?S*> zj@bwRSV&lhtRA@dH0o|lnec~=dn zkpH4t#sP#c4qbuv)108MHL=0(6{}xnGDI0OT%B}0_AT`}+>v_bEZr^Q&?>ak=5`MS zfEVWoOdl!4l4WVs)VKZh_kK+p!`@zAt$*`}-jNaXlwu26FeC+n#G6w>$fn9w82s?pnMy4_W}9K?k#dn%Kfb?$q+F36LTkdQon;eZlKBnNX!z zTKP z<0q|JFkH)l^YBfw)z_!!@9!74BLfoGgupBRJAdR1S>Cd|?QZC2w1lHLZ%??4bDwR& zAHJS&2$0~>{u3jrV_&+KQ92L9pbUhCQkys$Wf&l10#6nL08h@|<{s9Yh~UwGJB)FY zfK7E+W2CF%7uAZ-fG?fKygQtZ00UZ>eigA4M~ZJwSDtL^#a*O|nyhabYWr7*hb@{1 zvJY=$pRJpXWzG}OxnK8>jF2+4NzY)WwLAclNakai!s?iIw*cf116O{@=M_dd{Sg$# z$GBgR&DFhaB*|2z(!L-O{ZipJd*~6?xd_0AAOSWAg_-3fzy+!OD}gUCEF@EzY>MRk zkc9bAV}r&leiIHJ)E>anCZlhFNA&s}&6PgY+aZrjVd&8ds#8$Ek%O5{V@(bJn`C3A zE3eUgA8AAH@%K^kK1my{d|_dqJX{Yzl2beWhJmbya2$>G>UYl>k{+hhCFaR2{NU@w z=zxMT=;W|_TNl}oL~ia|f>j1lioYN?gBN9w4ny-R(deVf>K*UNkTO|#(?P|rBK9L` zgIQn)!*#DCe}2dF94G z?j=EC(RMPF1)A14oQupkLoBxmyG+4%zZ_2^oRFH38YiYN;4hRCN>bsbU~~}N6Me!Y zCTT`ONO`~uk}3JCs%oAO(zFHl_X-zGi7R2&_-7-`hC3I$cV8d-y2i|qKi@%6i6Oix zB`7GpUpSQJ*gqfyt(qsWj)0RChplU_+s7&i60#3CglRJ^_`_0bg~+)R()2C}791Mi zT>q&EXQJ}9L5CN+(W}=#LJMlHQQg5Du#DF0B9nF;t&l|R_*$1^7Ys~?^lXDY^XoZKD6nCC5!WaskI1p1X=V<^EG5Jdza@4<9DuYqN$Qn6oE^rj)wfiUR9P{}!hGU;xN7$FY^;z9dV#7gP|+3nSzuOHV}Afq=duA9e* zCt--N^P`862C8lU%P(dkulD24uZ|Z&6AtaxM`5HCWMGR|jU<|CBiI0AFw!6l>W+WQ z4FSzedPa6!_eAsOLwyZx?!vV4wd;}sJJEYS)N5-5uZRf0}nkB1;+F;kksb!zs8jMoj9*i4hErYkWFk3I|y&I{R zn6jE;_5$U!cM~NxtSt}COUysq52Q8xrW2e5jE_0;iV$k#!2_x~`QHVpOu zLlEbGoeKUJI%@jh2?Sh%4*<09q04-%6HHWL?t&fc?}JbmEY*={mvmLIfz1GyR&W^& zAkwQcSnNCw-ef&pnsu(eOTjCh#%H;VWV^Y`^ZtX4w84lgm@8|#t)qb1`rpks8n%7X z^wbpnKQX;I`bNy~;sh$vlCqjDAKJijc?an}D4%?uq7pUAXYLbV?4=rxBbz>D>f2}j zJq^icY9HY=8ujdN0b6_)Os`xw5?Ht!Kkxy@zdC9|4u&XOHIyn051N-dzhYH={-bZQ z{|)Q`bTbGV%j#N8tD?R+8%um*V$_sBVOo+v){Wyo^;%nh0ektz)j4~64)}^20N9&% zV9-mQGfCS0TCheX^w=*d0Dw1d-hc&av{i0_s>Uh{a8E|kZQYa}1O+jCVtIGcynn@v zjZK*H!>qL(%su0+kz1G+uS`7}85p}E(xAGNv6Y}*#KO~eXJ`4PBgO%7&8 zc=mw()z;3*KAwqd*@$Cc#qHui3tWyY_onse?E#`qjONQG0nj{GRYT_R;238W18iu>^}_Z)QYF`>sd-jK0R)_-F! zDgaWzfnjvY=yYZw-)Z=Gh_;g^+UuVGt35I8%*@m*dc2+%q&0tYJBCE4?D2D;y=b1o zWZ~q*K2^j~fm@0VtYXTZuO+J~`uJ77LE3)SgGb3k>TNvqSh*bqYnp={mG2N66z)Lkql(WctT`3^gwfOR zSAN94{}dks3o!5jmCwjT1%z%aolkgwWg||9NY}T=rR9A(o|honuH!J`BffjneU@FM zO#~k`sq~VPP?U9>0{v?fsE8GhaL6}1*;4;H_=vu z_nO_0IJ~lVWCo)WG$VP0SO9$+1zNj_(=!Gq#Y{Nh|BYlOWBk@<+#`=5WBuJot@X@$ zQ9=5vL&l4EjX$A`_p6fs$+5A6)H4qAm3L)oCZe)AJg!`id#R$78uJ@Z5e2^$Zu zCkl!~7#5jFXwJ})jiB}$+kOAI1)o8hO&@{i3Rd)Zsp$4YDGG)o37gbX8_VK~&N5>6 zmN*E#y#=|N%8APcoRPzt8<_EucBn3Bz|)`rAM(nUQ4idWffO&%GI*|Qzs=aI+8Aw; z;+|xXZYO|!n|KC~QSgga$T9XIl|?DMgzfB6OFB$$AEmW{9wNKAxSt8hTw#~Pt@Q3i z1`83Rq>qry9;*gZ%sDd!KM1E$_h*B#qCm&7`aLEl&BzXndYB<3e8VzwKMs!})9s?4 zEtHnuf2evt#=v==hn(nPUJc^!nex1mECTwjiv>&jmlfJK%3$lqvYT1S@iF8vynT;a zs-%mp6N}{U8IeF&7SW*_np4j1S4U+{%rXsfizpPVFR}30IT?{BMgHg5i_B;GRY{`= zZ!}}?!PEUK=^9w5vRk+!J(1^#kpD>IYOv2D^~^W#Z$rPY71 z#U)sjDF`{59;$eSAoLL#S?cRb-OX#_gdqsBx^aZmw!mjZASY#7&p6Ut>Q!u)B9~V< z-OFPBVKDUm7rxEatVy)e|5hc4>R0{+FQLT$`}K+cb!fY15SMvB2!iBPFT~(GYyUp; zR|ajM%2Y6WVrpt?QmcQLjMScNnIRbEwYx`JU?KcYO&jn&I`9C5M81z~ii|^H*8q-S zW+SqzDTi^`&Ux3{$meXGVU4fs^$AV$`e>4oIN3{kyS3Mr%+311&xwVQ8XmD+96ml_CNF$i59& zB!m`((mb$R*6QOcd7e5LOj-E7gD8m?DN6~2OP&^1ls=wLy=&qck(wJ zqD(G1>S|mCQqKy8?CuqJT9>Tu=c28|#z6Zw^rnfaQIZL;x$3X(-5OZvRZdt_M!!E7Qdtit9 zc9HfTS&9}Xti}L*fG(5XBm6@-YtYmOhcT%neZOdu75URZjw?&3r!g{f@E&}5W+mDG4H^_dHt8VvkNqF>$slxYh znchn^7P1cysZ_QP7wrDUEs`ujgejS!5VbZ>G*U`R#-Z*2_d6jUYWAH^%gLGFA1r3n z!0Gmd*Z;daNofar>wSA`=lIXNo2MK1(+GZ+pz~>zxC`1p2+B6tvFHtS_$}e<@wT0& zZ(aw8+hgdzpAFV~SV_DU9NLIg88xlSu4|$w-)A916|~1D(zDxW_;@+wCUTt&*(@!OUxIz+HRI}Z0VxI zfi6;^ob@1Tz^Cu3jdRlzen%}M!YXp#cW?Kr%|#;6o%!yURdKwR=2%DO`!6NX>G`MC z`EKw7eH*}s+MfXcv_kSC^E#%a^d~U@vfKIr5K`RVTfTv%MABl0#MkDbIy*bdeq8`t zg`UXnnuYw+-0hI0Uq<5eXPy|$WroET%`%Lbl8+!EgrVGp?}9ZTP_XtP`1WnVMbaLw z9SvJAo*m6MfA>qV17y}^LRU}i<+UM30;Z3d-*e9c+di6Oxc=Dr zUbl0C^k<>i$IOYw<_*6}lUn(aVmnprdUb+$HcNhW-W?B&tb@IMtW9o}Q6zSZ!;Y4z zw&)$DZuR;~)+WL3b)pwM3(g{Zzl^K+g>;lE^cx@RJbbp%P*v~mEY_zV!gkn9Nl#%$ zlD{`ltUga~HdGs!3`U`yyRVFz?!>1x&}Yl-3KRyfz^9Vi@PCQZ$s~lFdflU>t5Zji zS4#m*471i%chiEoK7L0}c#+gT%;=}bGfUW@^e<l~;0b0Fr|j%Mbkq4bzzZ)z}yVuhdZ&=0Y~xw#4SkJw#| zw+?5bZ$nBR`sbRr!8O60OWqNJ-(_&KPzC08@)q)OQSV-BzeZIl0E$f&_r_Ib8YnN7m8%LRo7PZb2i3kC{y=Z9J>|DInvDQJ zzW(?B0uVf1tA_N$AR($ey7zvcxcP`uvQuTyC>>st4Px+caNt;d$EbwZe?Y_0j$sYG z*kq8BOk4ksi}uOWd%fBC5(f!iB_a_XX-WfG|*%V?&?8p)P@EHjpQZ@=aF zeBRIJeV+GuKJPn!-RGWjpZm-?=ep)P*Y!PD3h7P^EdsFJWO?%N(qA{9AvV2vj?~>hZmCEvZR-6ZtPzW{VxzB+)+g5~Cdmz%Zq0T$J#-{gN4bV`U z^4LH9Alg;@V!#1_?qc*>UB0gfhU4R9xZ`0X-*{8w$GhK{A_)iF`Z>?X_Z`(tR*S4M zi5^ysG+ID%`(zHb6)JH1T(9BUj~&gJkQ9`9SFONLyxMqn{i6Loob51lP#dtD1;>ik z_o{Knf=DwxjtM&;>3)Y7uXYMcm9$T6+B((puIo(CqFD96Mo(i`4A|DBtLFVsI~N#(qk1|CP&I2X{q@UzDg5`7!Ru%bLu=5C~ zUz%m{y$2cE{e^5A6Nw0-jg=Rxr1O~mhiO+1BW7Ox*3*P#&0N@<2sge@a)lM<5ikai z5ABWr^qtMDE>x=QP|sK5I+KNn92I0)+bVM$iR@DrXvnR1`UgbUW>*YCbeVH(PLD+I zgGVpEm?=$F(vY#Pd=b^w-q&A*21UW{P7%O;lv$(gy0P7{)|Mxfk*a`NPij@fF?q_H z0CdQN1tn)9GY_moxl&Ip4M1O+zU$jNdibzkI1}!lM|*c(j)GW8Z5i|A`;@3$8(K5J zc~^NnY1{{5%RCpnF7l&lp-y}&Ne||6eYR@H2AhmN^ben;KWKGr*;+EaK>e6ssw0q6-EjVh~-yrp%sU%@{9;HhCSVp#My#J6$6b0$+a^mdag zhBR_ZKfy6OHLe+=`0JKVI)by z@!{@D_MmS4e7Kpa*N)FXv9%XJcFeM>l<;QdJ)qq_+@dMDdlfqp#`G($=Tb6$Rz9*2 za{S^L_|zlxS`uaU-tI$76+@~$fZ@W`_DR;Xq$ zPIfd9?E3jL9K*G0oZ|GZ)7Y7&Fp@Z9SLN}ncy?S#~=c*1HGqmT`7t|)r2>5b9 zd9;RQtFE6+**?nYOVnmMStwjWyDzkOvoqS)xjy*Q^385lmI&M!{Dpws z_zay+ZDH#iW{Wjkk>$7vM#iuBSL;(#o&9D*xj|Svi-!Cwmff%=lql#qv{k|a&PFwj zqHnd8?PS-F@-rWN!#D2x-bd?uZg=e1lv;<>K^@uGt&9A%Z>A2znZ2YO&KPXD%?zz} z=jW0HPxibTUq3oJO*JAWsQ^s!((QbFnrr$rys2fVuwp4mZF=@vwkR~<;o03#dQ|0EHnzl$v$`qz8EzucOv%N~3&Oeb*fv)XQ?%~)e^2-MywFrXy}s`G&`oxGO4?9Y$9 z6N7r*N2fz&XU&7@uh1YAaR0y=BA=$G?K6$$!E?_J&+>zB+*<^bhZvuciOz5aOIniz zsC?VvxyR#9fGOE8_=S*Mm`A4>nl9^;_rxg*q8=kD%Rk!P(S7rl5bH%4 zR-k`7NIPv{qL-J+ThgptuXxHQ{>p=hmXs1XmPMD4<&L1(A`{Q7)hC54qfz%ERUqI3 zfRR7S@3ij8Sa_4x*y>?S)}l_ zw;AT7TAqPD03M;F8EChFe^Ab>@Cm#o`{g2i{7s1vsXfY+o#4_g`qje5%+RW=QvZP* z*dS?~4QKiCcKQ3)Yv-YNo(@YH6^tcGnZ?q_>ZC?N>vm)4xwD3K+ZgJ_s-!rZnfr^xT&9U8s=BgA=c-_d5$d% z`*Cvu$}KBjv~9#fwNH3{l6`)OeZrU*7c9}9*i=+Tcu zRzudUD&2xYK<61!`s_f5xTT~_oh|R+DmTYb7rz8I-__x!i9@ngWd^$Fc*zq@^sg^) zPXmk6vMoPkaw2ZtPmIj3Ie+LC7e^-#LXc1|Z7%fj^7Cf!@3xNrhAW>=bRX2Xq~ZWS zL+^La5!qi-2|x2p;3TVi(C7!ji}$HP@%6Bm&C5y*Cc`D?yIFZivTtJbcY|jY17+cw^q5%@QT=El!Y7v9qeqeIb@P643_u5M@5*CRE@%8K8@#Euu=DBo44V)pGV+X;!e;@+GiQveFfabJ zB0OpnS8Y0m?k|t2p7>eZt8`L?|5IPQ{VI!Hd{>r3b$n}^5!ITvvA1C#`NAG@1KliK z$QsTjk(Z7VcFV`}d9NVE4zI>#oQbVQESrHANE&<;5B1o)w4!H%cKr-nT+o+y*TMY` zxXaL^^k%)Chw*Ua_>nvUgdB#9RSsJd0>0OfVeD;ekD^{-wb{%!pKz-5htH|Ual1iW zL9c1P$up@zjLLfo22>wKu}LhomKEBb`d5tEZDcHgWrK^cQ?3qSHx1But?gZvO-Xm9XEM=zJc{7iDBc=niqN~=jT+Ft3sjoEDc ztw+<~Z>iVdA7#f&k$4K8f|#=H>4z+LZCTKXQ@O;1$G%NRl53k{clgUY!-;l&W zu#&r zGqY=Aa`I@NSR6TK@?sW4A;Q2jRS}d%0(;{$swR~;0;;i*B)&V0^fn8GR z8N*gs44oodnwecjrgexPWjXmY`=TTCn5pnm9C)+^K%f%4~ue06QB2n3jbm!FJ zaNKR}7i0xpW`F|=GCDEzg*p3GlJW`ydLPT9m;Qd-Q>-2LvX{)KV|r2#yC*I^~+BG23i zT6wD#-r62ZF^fGB0rbpFTd9KbO*>zGPp$3XOEN~>J@){nWQdpG43Smikg)-(6Ig3d z;a~D)SR%=O1DqfBqC!R8bDdYRQ*<*3)v9}C{3mj;H5oZ=%2{@w<;)-2F|C!bcQu9z zJJfx__<%hU@*2ad(JAGN3XzW&)HQ0PviasQ!_P8dV=kOB87vorDpV~dj{eNTF|1CS=@2Km4K+a#bDudy6q2YwN z?!k`L_+`YQ21fHFkNSBb3os=e_=QR|rz@ket1ctuHqhhkMGF~tuQ;g?u*98y^u(@x zB6c}2@LWe92*0FTr5rwmc-}yyy03)1p*1(n6%Tt;k{rBh#By`KyEfUQIEru^zZ{D~ z_CJm|Cq+*BQd(BQ?gUVCQ&&cUf2lI4BytMq#H*P*4d}#B>aZoGz~S_Q;B1B7p=WEw z9N>wukt+WiH+~!(bG`#6#re9o4PIS@|9KL7N3cVKk-&UyYRy}%q+SLGs{46kXN~kR zHT0QS&hswbHN0I@!Xrb@!ujDiOS)c;aeOcn+Jni3q>C?e|Gw|+ppx-TtxndgtyC4&Y@Wk6}43k zNT8NT6_y79KEWr6WRoIG<*dQ8gxK#nX2 z2lma*3~haDq)wt`WHhosXb3=o3^=8y#~u%2;#ckD?YDzWsbvpvL%=D+6tQxvsHVgU z3%tO0RB8dk43D3V^A3!5G9Y-`HF}@md;A=wncvF&#IdJj!9cc*tir|4Mu1*viD_lF zfW&t=kGjgCCGN#CFV|kMn?x1C_}M3-c@hqxdoU5;1ZwOreEw1KYwG7wC@l0jl!5#pjN{*p=aOAb=D#H*j3@)L5XpCP`-CwB+1v55VWN%{Th#2J*7g3hN}l7Sdw9-S%*YkV-0_V_EEb}h&dP^NZpH5Z zytTZKQQ660Txer^3eXOU;PR6z4GEo@Xni{MCNRHju1RR{1Ad=12kbs|H`SNf4GmYY z5YK9|kEVdv#ZXlsqRW^i_~ZbEUXEEPa|7y~i-5sd>k~5vSzl84f+CxP3>GR^JOHr3 za`n^NIFCpoFnU6BZ{&Q_-r$99Hrx+ZU!QLws;oG)!e_plRdscN{p0*3rELp6`l}@) z^q0vMc+18(@0PTU${+cknQ%7c+tlmA!IyBQh zm$|};5Lp^`9N7t;1@PWRF;n!cNqXOo*4LJ^82>p-Irk&|)<(~t`D^*yZ+g(bf?%9K ze+9Of^|__*G$?$gPt1kw$mWM5vbzhw zKJBeHqQc~dVjrKs)*OGUa>L7cKuXmc;d}u(a$$Atik=E!B>Ii)p$L+9A9(Y%d3XSl3@fj z;N3;<6ndXpV^{aO=_g7ZpQ=;)x22tfO+vY|N&2*jL`&qdV0h_(8vGiQ#$YfO;SEBE z!hP_ICUR{}tMcKSjS<8h(;cS9AR-87NbQ+FJjAk*-+o?#z`TMJFuXjxSb&4rCmJ2bs_oQT{uP+||hglpXITc86IeE0GE|z)F;Wq5#uw05e1~V{;KTIB9Lnc3A56EBs}&7-KpT*+3ggf(xCH!!byB6<@E8j_yw|m%&?Tb4GEF@E;M_#X--ZDe(5R`Av38m_N~fx z{n2a=1={Zd^Hr&O?Y&SmdR9f>9@quboyR#py^7a1MSDK`nT^eDt>EYYIP=U(9{uHlqJ& z06n$OCkwlW$bV?=(JUxllG49wwm*Nb_zA zKmehCWBC8q`S}+WXahCav`M#FoN3}PZ>-zx?0U8T(7!SmE!c(t|FXUtLr zG2rb~Y+q-nnnYlfGvK*BR4Uv{UKuW($0J6wsNp&_Vhs`gb0%6|OaukYoh&f4InZ}o z+f&$6G4{(DCkeKo7`}V^nijMviQezXmwo*Ov;>^ts+BwQ8TO%fjkSi>seL4dmQ(VN zms!-0x<8G>wYI0cnu}|)Dup+6pv(!s#9?Nx`}&@dF0r1~E;*fZ_A;SRziSo3TbEQs zSIJ>hw`68C!hfzIA3rLOT&=8`SL|Y%(h#DEl+EeY)m3-4^cO6s_zxc0y~?6525yYp z2crbm%nm9K3J4AqiQ)WLQt?klof;0eHoovG#Ss5Zj{eCLyF$4uXwx$bteK!n zRijuNVba+Ej3>t^IAhLJWuP~u>WvDd;Ws-gQSmzu5tOyq>|r?2J>?F2Ne!nnNa8 literal 23825 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 H;q(6ip!?j) delta 32844 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

    #gz^UA9b>*HF`w=v|@=))8dgWYK28&~ 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 F{{Tu=HAnye diff --git a/tgstation.dme b/tgstation.dme index e48c0d64a1e17..b1387a2328279 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -4263,7 +4263,6 @@ #include "code\modules\jobs\job_types\shaft_miner.dm" #include "code\modules\jobs\job_types\station_engineer.dm" #include "code\modules\jobs\job_types\unassigned.dm" -#include "code\modules\jobs\job_types\virologist.dm" #include "code\modules\jobs\job_types\warden.dm" #include "code\modules\jobs\job_types\antagonists\abductor_agent.dm" #include "code\modules\jobs\job_types\antagonists\abductor_scientist.dm" diff --git a/tgui/packages/tgui/interfaces/common/JobToIcon.ts b/tgui/packages/tgui/interfaces/common/JobToIcon.ts index 4d6410fc72c8c..74927a2ff08bb 100644 --- a/tgui/packages/tgui/interfaces/common/JobToIcon.ts +++ b/tgui/packages/tgui/interfaces/common/JobToIcon.ts @@ -54,6 +54,5 @@ export const JOB2ICON = { 'Station Engineer': 'gears', 'Syndicate Operative': 'dragon', 'Veteran Security Advisor': 'ribbon', - Virologist: 'virus', Warden: 'handcuffs', } as const; From 98872af78417b346415eb48471db2ac253c043d4 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 19 Apr 2024 07:53:20 +1200 Subject: [PATCH 327/938] Automatic changelog for PR #82723 [ci skip] --- html/changelogs/AutoChangeLog-pr-82723.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82723.yml diff --git a/html/changelogs/AutoChangeLog-pr-82723.yml b/html/changelogs/AutoChangeLog-pr-82723.yml new file mode 100644 index 0000000000000..fb612dc0f7cba --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82723.yml @@ -0,0 +1,4 @@ +author: "jlsnow301" +delete-after: True +changes: + - rscdel: "Due to a need for company restructuring, virologists have been laid off by CentCom and doctors can optionally take their place." \ No newline at end of file From 635b7fa66ca52572e0e77c561c68bb1862d77f9a Mon Sep 17 00:00:00 2001 From: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Date: Fri, 19 Apr 2024 02:59:21 +0530 Subject: [PATCH 328/938] Use cell defined constants for various stuff (#82594) ## About The Pull Request This re writes most cell power usage cases with 2 defines `STANDARD_CELL_CHARGE`(Joules) & `STANDARD_CELL_RATE`(Watts) so changing cell capacity values in the future won't cause discrepancies. ## Changelog :cl: code: most cell power usages are scaled with defined constants to help adapt to future changes /:cl: --- code/__DEFINES/lights.dm | 2 +- code/__DEFINES/power.dm | 8 ++++++-- code/datums/actions/mobs/charge_apc.dm | 2 +- code/game/machinery/autolathe.dm | 4 ++-- code/game/machinery/cell_charger.dm | 7 ++++--- code/game/machinery/doors/firedoor.dm | 2 +- code/game/machinery/firealarm.dm | 2 +- code/game/machinery/rechargestation.dm | 2 +- code/game/machinery/suit_storage_unit.dm | 7 ++++--- code/game/objects/items/devices/powersink.dm | 2 +- code/game/objects/items/inspector.dm | 14 ++++++++------ code/game/objects/items/maintenance_loot.dm | 2 +- code/game/objects/items/rcd/RCD.dm | 6 +++--- code/game/objects/items/robot/items/food.dm | 2 +- code/game/objects/items/robot/items/hypo.dm | 8 ++++---- code/game/objects/items/robot/items/tools.dm | 2 +- .../objects/items/robot/robot_upgrades.dm | 8 ++++---- .../stacks/golem_food/golem_status_effects.dm | 19 +++++++++++-------- .../antagonists/ninja/ninjaDrainAct.dm | 16 ++++++++++++---- .../nukeop/equipment/borgchameleon.dm | 4 ++-- .../machinery/air_alarm/air_alarm_interact.dm | 2 +- .../components/electrolyzer/electrolyzer.dm | 2 +- .../machinery/portable/canister.dm | 2 +- .../clothing/spacesuits/_spacesuits.dm | 2 +- code/modules/explorer_drone/loot.dm | 2 +- .../food_and_drinks/machinery/microwave.dm | 2 +- code/modules/hydroponics/plant_genes.dm | 2 +- .../modules/mob/living/basic/festivus_pole.dm | 15 ++++++++------- code/modules/mob/living/silicon/robot/life.dm | 2 +- .../modules/mob/living/silicon/robot/robot.dm | 2 +- code/modules/mod/mod_link.dm | 2 +- code/modules/mod/modules/modules_ninja.dm | 4 ---- code/modules/power/apc/apc_main.dm | 2 +- code/modules/power/apc/apc_tool_act.dm | 4 ++-- code/modules/power/cell.dm | 18 +++++++++--------- .../projectiles/guns/energy/special.dm | 14 ++++++++------ .../chemistry/machinery/chem_mass_spec.dm | 2 +- .../reagents/reagent_containers/misc.dm | 2 +- .../modules/research/machinery/_production.dm | 4 ++-- code/modules/vehicles/mecha/_mecha.dm | 6 +++--- .../mecha/equipment/tools/mining_tools.dm | 2 +- .../mecha/equipment/tools/other_tools.dm | 4 ++-- .../mecha/equipment/tools/work_tools.dm | 2 +- code/modules/vehicles/mecha/mech_bay.dm | 6 +++--- code/modules/vehicles/motorized_wheelchair.dm | 2 +- code/modules/wiremod/shell/gun.dm | 6 +++--- 46 files changed, 125 insertions(+), 107 deletions(-) diff --git a/code/__DEFINES/lights.dm b/code/__DEFINES/lights.dm index 8830f919472cf..48d210fe03164 100644 --- a/code/__DEFINES/lights.dm +++ b/code/__DEFINES/lights.dm @@ -1,5 +1,5 @@ ///How much power emergency lights will consume per tick -#define LIGHT_EMERGENCY_POWER_USE (0.1 KILO WATTS) +#define LIGHT_EMERGENCY_POWER_USE (0.0001 * STANDARD_CELL_RATE) // status values shared between lighting fixtures and items #define LIGHT_OK 0 #define LIGHT_EMPTY 1 diff --git a/code/__DEFINES/power.dm b/code/__DEFINES/power.dm index 0eda3669a7123..b9752eac351f1 100644 --- a/code/__DEFINES/power.dm +++ b/code/__DEFINES/power.dm @@ -19,8 +19,12 @@ ///The joule is the standard unit of energy for this codebase. You can use this with other defines to clarify that it will not be multiplied by time. #define JOULES * JOULE -///The amount of energy, in joules, a standard powercell has. -#define STANDARD_CELL_CHARGE (1 MEGA JOULES) // 1 MJ. +///The capacity of a standard power cell +#define STANDARD_CELL_VALUE (1 MEGA) + ///The amount of energy, in joules, a standard powercell has. + #define STANDARD_CELL_CHARGE (STANDARD_CELL_VALUE JOULES) // 1 MJ. + ///The amount of power, in watts, a standard powercell can give. + #define STANDARD_CELL_RATE (STANDARD_CELL_VALUE WATTS) // 1 MW. GLOBAL_VAR_INIT(CHARGELEVEL, 0.01) // Cap for how fast cells charge, as a percentage per second (.01 means cellcharge is capped to 1% per second) diff --git a/code/datums/actions/mobs/charge_apc.dm b/code/datums/actions/mobs/charge_apc.dm index 47436beab76cf..8086ba7220793 100644 --- a/code/datums/actions/mobs/charge_apc.dm +++ b/code/datums/actions/mobs/charge_apc.dm @@ -1,5 +1,5 @@ ///how much charge are we giving off to an APC? -#define CHARGE_AMOUNT (80 KILO JOULES) +#define CHARGE_AMOUNT (0.08 * STANDARD_CELL_CHARGE) /datum/action/cooldown/mob_cooldown/charge_apc name = "Charge APCs" diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index 1bdcba849671a..296a9031ae27e 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -4,8 +4,8 @@ icon = 'icons/obj/machines/lathes.dmi' icon_state = "autolathe" density = TRUE - //Energy cost per full stack of sheets worth of materials used. Material insertion is 40% of this. - active_power_usage = 25 * BASE_MACHINE_ACTIVE_CONSUMPTION + ///Energy cost per full stack of sheets worth of materials used. Material insertion is 40% of this. + active_power_usage = 0.025 * STANDARD_CELL_RATE circuit = /obj/item/circuitboard/machine/autolathe layer = BELOW_OBJ_LAYER processing_flags = NONE diff --git a/code/game/machinery/cell_charger.dm b/code/game/machinery/cell_charger.dm index cff1c0bdac9e5..4b6272102057b 100644 --- a/code/game/machinery/cell_charger.dm +++ b/code/game/machinery/cell_charger.dm @@ -7,7 +7,7 @@ circuit = /obj/item/circuitboard/machine/cell_charger pass_flags = PASSTABLE var/obj/item/stock_parts/cell/charging = null - var/charge_rate = 250 KILO WATTS + var/charge_rate = 0.25 * STANDARD_CELL_RATE /obj/machinery/cell_charger/update_overlays() . = ..() @@ -125,7 +125,7 @@ /obj/machinery/cell_charger/RefreshParts() . = ..() - charge_rate = 250 KILO WATTS + charge_rate = 0.25 * STANDARD_CELL_RATE for(var/datum/stock_part/capacitor/capacitor in component_parts) charge_rate *= capacitor.tier @@ -140,7 +140,8 @@ if(!main_draw) return - use_energy(main_draw * 0.01) //use a small bit for the charger itself, but power usage scales up with the part tier + //use a small bit for the charger itself, but power usage scales up with the part tier + use_energy(main_draw * 0.01) charge_cell(main_draw, charging, grid_only = TRUE) update_appearance() diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index 1d20a938e327c..30deaef9183f3 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -886,7 +886,7 @@ return if(istype(attacking_object, /obj/item/electroadaptive_pseudocircuit)) var/obj/item/electroadaptive_pseudocircuit/raspberrypi = attacking_object - if(!raspberrypi.adapt_circuit(user, circuit_cost = DEFAULT_STEP_TIME * 0.5 KILO JOULES)) + if(!raspberrypi.adapt_circuit(user, circuit_cost = DEFAULT_STEP_TIME * 0.0005 * STANDARD_CELL_CHARGE)) return user.visible_message(span_notice("[user] fabricates a circuit and places it into [src]."), \ span_notice("You adapt a firelock circuit and slot it into the assembly.")) diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm index 8343a0251a9a1..10055aee5b29d 100644 --- a/code/game/machinery/firealarm.dm +++ b/code/game/machinery/firealarm.dm @@ -394,7 +394,7 @@ else if(istype(tool, /obj/item/electroadaptive_pseudocircuit)) var/obj/item/electroadaptive_pseudocircuit/pseudoc = tool - if(!pseudoc.adapt_circuit(user, circuit_cost = 15 KILO JOULES)) + if(!pseudoc.adapt_circuit(user, circuit_cost = 0.015 * STANDARD_CELL_CHARGE)) return user.visible_message(span_notice("[user] fabricates a circuit and places it into [src]."), \ span_notice("You adapt a fire alarm circuit and slot it into the assembly.")) diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm index 25f73963fd274..b328d99284d0e 100644 --- a/code/game/machinery/rechargestation.dm +++ b/code/game/machinery/rechargestation.dm @@ -178,7 +178,7 @@ if(!occupant) return - if(!use_energy(active_power_usage * seconds_per_tick)) + if(!use_energy(active_power_usage * seconds_per_tick, force = FALSE)) return SEND_SIGNAL(occupant, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, charge_cell, seconds_per_tick, repairs, sendmats) diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index d95668975f5b7..a5e301c21680b 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -1,3 +1,4 @@ + // SUIT STORAGE UNIT ///////////////// /obj/machinery/suit_storage_unit name = "suit storage unit" @@ -55,9 +56,9 @@ /// How long it takes to break out of the SSU. var/breakout_time = 30 SECONDS /// Power contributed by this machine to charge the mod suits cell without any capacitors - var/base_charge_rate = 200 KILO WATTS + var/base_charge_rate = 0.2 * STANDARD_CELL_RATE /// Final charge rate which is base_charge_rate + contribution by capacitors - var/final_charge_rate = 250 KILO WATTS + var/final_charge_rate = 0.25 * STANDARD_CELL_RATE /// is the card reader installed in this machine var/card_reader_installed = FALSE /// physical reference of the players id card to check for PERSONAL access level @@ -287,7 +288,7 @@ . = ..() for(var/datum/stock_part/capacitor/capacitor in component_parts) - final_charge_rate = base_charge_rate + (capacitor.tier * 50 KILO WATTS) + final_charge_rate = base_charge_rate + (capacitor.tier * 0.05 * STANDARD_CELL_RATE) set_access() diff --git a/code/game/objects/items/devices/powersink.dm b/code/game/objects/items/devices/powersink.dm index 1b000ea2f9160..1925737143e9d 100644 --- a/code/game/objects/items/devices/powersink.dm +++ b/code/game/objects/items/devices/powersink.dm @@ -171,7 +171,7 @@ if(istype(terminal.master, /obj/machinery/power/apc)) var/obj/machinery/power/apc/apc = terminal.master if(apc.operating && apc.cell) - drained += 0.001 * apc.cell.use(50 KILO JOULES, force = TRUE) + drained += 0.001 * apc.cell.use(0.05 * STANDARD_CELL_CHARGE, force = TRUE) internal_heat += drained /obj/item/powersink/process() diff --git a/code/game/objects/items/inspector.dm b/code/game/objects/items/inspector.dm index f96c1beb5731b..1d186ddcb9683 100644 --- a/code/game/objects/items/inspector.dm +++ b/code/game/objects/items/inspector.dm @@ -1,3 +1,6 @@ +///Energy used to say an error message. +#define ENERGY_TO_SPEAK (0.001 * STANDARD_CELL_CHARGE) + /** * # N-spect scanner * @@ -28,8 +31,6 @@ var/cell_cover_open = FALSE ///Energy used per print. var/energy_per_print = INSPECTOR_ENERGY_USAGE_NORMAL - ///Energy used to say an error message. - var/energy_to_speak = 1 KILO JOULES /obj/item/inspector/Initialize(mapload) . = ..() @@ -112,7 +113,7 @@ to_chat(user, "\The [src] doesn't seem to be on... Perhaps it ran out of power?") return if(!cell.use(energy_per_print)) - if(cell.use(energy_to_speak)) + if(cell.use(ENERGY_TO_SPEAK)) say("ERROR! POWER CELL CHARGE LEVEL TOO LOW TO PRINT REPORT!") return @@ -258,7 +259,7 @@ /obj/item/inspector/clown/bananium/proc/check_settings_legality() if(print_sound_mode == INSPECTOR_PRINT_SOUND_MODE_NORMAL && time_mode == INSPECTOR_TIME_MODE_HONK) - if(cell.use(energy_to_speak)) + if(cell.use(ENERGY_TO_SPEAK)) say("Setting combination forbidden by Geneva convention revision CCXXIII selected, reverting to defaults") time_mode = INSPECTOR_TIME_MODE_SLOW print_sound_mode = INSPECTOR_PRINT_SOUND_MODE_NORMAL @@ -296,7 +297,7 @@ if(time_mode != INSPECTOR_TIME_MODE_HONK) return ..() if(paper_charges == 0) - if(cell.use(energy_to_speak)) + if(cell.use(ENERGY_TO_SPEAK)) say("ERROR! OUT OF PAPER! MAXIMUM PRINTING SPEED UNAVAIBLE! SWITCH TO A SLOWER SPEED TO OR PROVIDE PAPER!") else to_chat(user, "\The [src] doesn't seem to be on... Perhaps it ran out of power?") @@ -383,5 +384,6 @@ target.MakeSlippery(TURF_WET_WATER, min_wet_time = 10 SECONDS, wet_time_to_add = 5 SECONDS) to_chat(user, span_notice("As you try to fold [src] into the shape of a plane, it disintegrates into water!")) qdel(src) - return CLICK_ACTION_SUCCESS + +#undef ENERGY_TO_SPEAK diff --git a/code/game/objects/items/maintenance_loot.dm b/code/game/objects/items/maintenance_loot.dm index 52ed1880081e6..f6d7fd1c3290d 100644 --- a/code/game/objects/items/maintenance_loot.dm +++ b/code/game/objects/items/maintenance_loot.dm @@ -30,7 +30,7 @@ icon_state = "lead_battery" throwforce = 10 maxcharge = STANDARD_CELL_CHARGE * 20 //decent max charge - chargerate = STANDARD_CELL_CHARGE * 0.7 //charging is about 30% less efficient than lithium batteries. + chargerate = STANDARD_CELL_RATE * 0.7 //charging is about 30% less efficient than lithium batteries. charge_light_type = null connector_type = "leadacid" rating = 2 //Kind of a mid-tier battery diff --git a/code/game/objects/items/rcd/RCD.dm b/code/game/objects/items/rcd/RCD.dm index 91b51053b0ea0..88daf279c590b 100644 --- a/code/game/objects/items/rcd/RCD.dm +++ b/code/game/objects/items/rcd/RCD.dm @@ -428,7 +428,7 @@ desc = "A device used to rapidly build walls and floors." banned_upgrades = RCD_UPGRADE_SILO_LINK /// enery usage - var/energyfactor = 72 KILO JOULES + var/energyfactor = 0.072 * STANDARD_CELL_CHARGE /obj/item/construction/rcd/borg/get_matter(mob/user) if(!iscyborg(user)) @@ -470,7 +470,7 @@ desc = "A reverse-engineered RCD with black market upgrades that allow this device to deconstruct reinforced walls. Property of Donk Co." icon_state = "ircd" inhand_icon_state = "ircd" - energyfactor = 66 KILO JOULES + energyfactor = 0.066 * STANDARD_CELL_CHARGE canRturf = TRUE /obj/item/construction/rcd/loaded @@ -522,7 +522,7 @@ upgrade = RCD_ALL_UPGRADES & ~RCD_UPGRADE_SILO_LINK ///How much charge is used up for each matter unit. -#define MASS_TO_ENERGY (16 KILO JOULES) +#define MASS_TO_ENERGY (0.016 * STANDARD_CELL_CHARGE) /obj/item/construction/rcd/exosuit name = "mounted RCD" diff --git a/code/game/objects/items/robot/items/food.dm b/code/game/objects/items/robot/items/food.dm index 1878b0c1e0027..40166a6a8fbfe 100644 --- a/code/game/objects/items/robot/items/food.dm +++ b/code/game/objects/items/robot/items/food.dm @@ -121,7 +121,7 @@ check_amount() if(iscyborg(user)) var/mob/living/silicon/robot/robot_user = user - if(!robot_user.cell.use(12 KILO JOULES)) + if(!robot_user.cell.use(0.012 * STANDARD_CELL_CHARGE)) to_chat(user, span_warning("Not enough power.")) return AFTERATTACK_PROCESSED_ITEM switch(mode) diff --git a/code/game/objects/items/robot/items/hypo.dm b/code/game/objects/items/robot/items/hypo.dm index 052a6aa71e3e6..e8e71ccda62ec 100644 --- a/code/game/objects/items/robot/items/hypo.dm +++ b/code/game/objects/items/robot/items/hypo.dm @@ -108,7 +108,7 @@ */ var/max_volume_per_reagent = 30 /// Cell cost for charging a reagent - var/charge_cost = 50 KILO JOULES + var/charge_cost = 0.05 * STANDARD_CELL_CHARGE /// Counts up to the next time we charge var/charge_timer = 0 /// Time it takes for shots to recharge (in seconds) @@ -306,7 +306,7 @@ Also metabolizes potassium iodide for radiation poisoning, inacusiate for ear damage and morphine for offense." icon_state = "borghypo_s" tgui_theme = "syndicate" - charge_cost = 20 KILO JOULES + charge_cost = 0.02 * STANDARD_CELL_CHARGE recharge_time = 2 default_reagent_types = BASE_SYNDICATE_REAGENTS bypass_protection = TRUE @@ -319,7 +319,7 @@ icon_state = "shaker" possible_transfer_amounts = list(5,10,20,1) // Lots of reagents all regenerating at once, so the charge cost is lower. They also regenerate faster. - charge_cost = 20 KILO JOULES + charge_cost = 0.02 * STANDARD_CELL_CHARGE recharge_time = 3 dispensed_temperature = WATER_MATTERSTATE_CHANGE_TEMP //Water stays wet, ice stays ice default_reagent_types = BASE_SERVICE_REAGENTS @@ -391,7 +391,7 @@ icon_state = "flour" possible_transfer_amounts = list(5,10,20,1) // Lots of reagents all regenerating at once, so the charge cost is lower. They also regenerate faster. - charge_cost = 40 KILO JOULES //Costs double the power of the borgshaker due to synthesizing solids + charge_cost = 0.04 * STANDARD_CELL_CHARGE //Costs double the power of the borgshaker due to synthesizing solids recharge_time = 6 //Double the recharge time too, for the same reason. dispensed_temperature = WATER_MATTERSTATE_CHANGE_TEMP default_reagent_types = EXPANDED_SERVICE_REAGENTS diff --git a/code/game/objects/items/robot/items/tools.dm b/code/game/objects/items/robot/items/tools.dm index 538fd1b7ca18b..60bb1089681a8 100644 --- a/code/game/objects/items/robot/items/tools.dm +++ b/code/game/objects/items/robot/items/tools.dm @@ -1,5 +1,5 @@ #define PKBORG_DAMPEN_CYCLE_DELAY (2 SECONDS) -#define POWER_RECHARGE_CYBORG_DRAIN_MULTIPLIER (0.4 KILO WATTS) +#define POWER_RECHARGE_CYBORG_DRAIN_MULTIPLIER (0.0004 * STANDARD_CELL_RATE) /obj/item/cautery/prt //it's a subtype of cauteries so that it inherits the cautery sprites and behavior and stuff, because I'm too lazy to make sprites for this thing name = "plating repair tool" diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index b29d8738b553a..745f82de76d1f 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -298,7 +298,7 @@ /// Minimum time between repairs in seconds var/repair_cooldown = 4 var/on = FALSE - var/energy_cost = 10 KILO JOULES + var/energy_cost = 0.01 * STANDARD_CELL_CHARGE var/datum/action/toggle_action /obj/item/borg/upgrade/selfrepair/action(mob/living/silicon/robot/R, user = usr) @@ -366,16 +366,16 @@ if(cyborg.health < cyborg.maxHealth) if(cyborg.health < 0) repair_amount = -2.5 - energy_cost = 30 KILO JOULES + energy_cost = 0.03 * STANDARD_CELL_CHARGE else repair_amount = -1 - energy_cost = 10 KILO JOULES + energy_cost = 0.01 * STANDARD_CELL_CHARGE cyborg.adjustBruteLoss(repair_amount) cyborg.adjustFireLoss(repair_amount) cyborg.updatehealth() cyborg.cell.use(energy_cost) else - cyborg.cell.use(5 KILO JOULES) + cyborg.cell.use(0.005 * STANDARD_CELL_CHARGE) next_repair = world.time + repair_cooldown * 10 // Multiply by 10 since world.time is in deciseconds if(TIMER_COOLDOWN_FINISHED(src, COOLDOWN_BORG_SELF_REPAIR)) diff --git a/code/game/objects/items/stacks/golem_food/golem_status_effects.dm b/code/game/objects/items/stacks/golem_food/golem_status_effects.dm index c55a39c20f76a..bf2c628ab972c 100644 --- a/code/game/objects/items/stacks/golem_food/golem_status_effects.dm +++ b/code/game/objects/items/stacks/golem_food/golem_status_effects.dm @@ -160,6 +160,11 @@ owner.remove_traits(list(TRAIT_ANTIMAGIC, TRAIT_HOLY), TRAIT_STATUS_EFFECT(id)) return ..() +/// What do we multiply our damage by to convert it into power? +#define ENERGY_PER_DAMAGE (0.005 * STANDARD_CELL_CHARGE) +/// Multiplier to apply to burn damage, not 0 so that we can reverse it more easily +#define BURN_MULTIPLIER 0.05 + /// Heat immunity, turns heat damage into local power /datum/status_effect/golem/plasma overlay_state_prefix = "plasma" @@ -167,10 +172,6 @@ applied_fluff = "Plasma cooling rods sprout from your body. You can take the heat!" alert_icon_state = "sheet-plasma" alert_desc = "You are protected from high pressure and can convert heat damage into power." - /// What do we multiply our damage by to convert it into power? - var/energy_per_damage = 5 KILO JOULES - /// Multiplier to apply to burn damage, not 0 so that we can reverse it more easily - var/burn_multiplier = 0.05 /datum/status_effect/golem/plasma/on_apply() . = ..() @@ -179,14 +180,14 @@ owner.add_traits(list(TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTHEAT, TRAIT_ASHSTORM_IMMUNE), TRAIT_STATUS_EFFECT(id)) RegisterSignal(owner, COMSIG_MOB_APPLY_DAMAGE, PROC_REF(on_burned)) var/mob/living/carbon/human/human_owner = owner - human_owner.physiology.burn_mod *= burn_multiplier + human_owner.physiology.burn_mod *= BURN_MULTIPLIER return TRUE /datum/status_effect/golem/plasma/on_remove() owner.remove_traits(list(TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTHEAT, TRAIT_ASHSTORM_IMMUNE), TRAIT_STATUS_EFFECT(id)) UnregisterSignal(owner, COMSIG_MOB_APPLY_DAMAGE) var/mob/living/carbon/human/human_owner = owner - human_owner.physiology.burn_mod /= burn_multiplier + human_owner.physiology.burn_mod /= BURN_MULTIPLIER return ..() /// When we take fire damage (or... technically also cold damage, we don't differentiate), zap a nearby APC @@ -195,7 +196,6 @@ if(damagetype != BURN) return - var/power = damage * energy_per_damage var/obj/machinery/power/energy_accumulator/ground = get_closest_atom(/obj/machinery/power/energy_accumulator, view(4, owner), owner) if (ground) zap_effect(ground) @@ -206,7 +206,10 @@ if (!our_apc) return zap_effect(our_apc) - our_apc.cell?.give(power) + our_apc.cell?.give(damage * ENERGY_PER_DAMAGE) + +#undef ENERGY_PER_DAMAGE +#undef BURN_MULTIPLIER /// Shoot a beam at the target atom /datum/status_effect/golem/plasma/proc/zap_effect(atom/target) diff --git a/code/modules/antagonists/ninja/ninjaDrainAct.dm b/code/modules/antagonists/ninja/ninjaDrainAct.dm index af77a18417857..0aaf5dbbfcf3b 100644 --- a/code/modules/antagonists/ninja/ninjaDrainAct.dm +++ b/code/modules/antagonists/ninja/ninjaDrainAct.dm @@ -1,3 +1,8 @@ +/// Minimum amount of energy we can drain in a single drain action +#define NINJA_MIN_DRAIN (0.2 * STANDARD_CELL_CHARGE) +/// Maximum amount of energy we can drain in a single drain action +#define NINJA_MAX_DRAIN (0.4 * STANDARD_CELL_CHARGE) + /** * Atom level proc for space ninja's glove interactions. * @@ -26,7 +31,7 @@ var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread() spark_system.set_up(5, 0, loc) while(cell.charge> 0 && !maxcapacity) - drain = rand(hacking_module.mindrain, hacking_module.maxdrain) + drain = rand(NINJA_MIN_DRAIN, NINJA_MAX_DRAIN) if(cell.charge < drain) drain = cell.charge if(hacking_module.mod.get_charge() + drain > hacking_module.mod.get_max_charge()) @@ -62,7 +67,7 @@ var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread() spark_system.set_up(5, 0, loc) while(charge > 0 && !maxcapacity) - drain = rand(hacking_module.mindrain, hacking_module.maxdrain) + drain = rand(NINJA_MIN_DRAIN, NINJA_MAX_DRAIN) if(charge < drain) drain = charge if(hacking_module.mod.get_charge() + drain > hacking_module.mod.get_max_charge()) @@ -228,7 +233,7 @@ var/drain_total = 0 var/datum/powernet/wire_powernet = powernet while(!maxcapacity && src) - drain = (round((rand(hacking_module.mindrain, hacking_module.maxdrain))/2)) + drain = (round((rand(NINJA_MIN_DRAIN, NINJA_MAX_DRAIN))/2)) var/drained = 0 if(wire_powernet && do_after(ninja, 1 SECONDS, target = src, hidden = TRUE)) drained = min(drain, delayed_surplus()) @@ -264,7 +269,7 @@ var/drain_total = 0 if(get_charge()) while(cell.charge > 0 && !maxcapacity) - drain = rand(hacking_module.mindrain, hacking_module.maxdrain) + drain = rand(NINJA_MIN_DRAIN, NINJA_MAX_DRAIN) if(cell.charge < drain) drain = cell.charge if(hacking_module.mod.get_charge() + drain > hacking_module.mod.get_max_charge()) @@ -466,3 +471,6 @@ //FIRELOCKS// /obj/machinery/door/firedoor/ninjadrain_act(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module) crack_open() + +#undef NINJA_MIN_DRAIN +#undef NINJA_MAX_DRAIN diff --git a/code/modules/antagonists/nukeop/equipment/borgchameleon.dm b/code/modules/antagonists/nukeop/equipment/borgchameleon.dm index a2a072f02e28f..9b536066843e2 100644 --- a/code/modules/antagonists/nukeop/equipment/borgchameleon.dm +++ b/code/modules/antagonists/nukeop/equipment/borgchameleon.dm @@ -1,5 +1,5 @@ -#define ACTIVATION_COST (300 KILO JOULES) -#define ACTIVATION_UP_KEEP (25 KILO WATTS) +#define ACTIVATION_COST (0.3 * STANDARD_CELL_CHARGE) +#define ACTIVATION_UP_KEEP (0.025 * STANDARD_CELL_RATE) /obj/item/borg_chameleon name = "cyborg chameleon projector" diff --git a/code/modules/atmospherics/machinery/air_alarm/air_alarm_interact.dm b/code/modules/atmospherics/machinery/air_alarm/air_alarm_interact.dm index bb45d1f8c1fec..f7eaf5788c9ee 100644 --- a/code/modules/atmospherics/machinery/air_alarm/air_alarm_interact.dm +++ b/code/modules/atmospherics/machinery/air_alarm/air_alarm_interact.dm @@ -140,7 +140,7 @@ if(istype(W, /obj/item/electroadaptive_pseudocircuit)) var/obj/item/electroadaptive_pseudocircuit/P = W - if(!P.adapt_circuit(user, circuit_cost = 25 KILO JOULES)) + if(!P.adapt_circuit(user, circuit_cost = 0.025 * STANDARD_CELL_CHARGE)) return user.visible_message(span_notice("[user] fabricates a circuit and places it into [src]."), \ span_notice("You adapt an air alarm circuit and slot it into the assembly.")) diff --git a/code/modules/atmospherics/machinery/components/electrolyzer/electrolyzer.dm b/code/modules/atmospherics/machinery/components/electrolyzer/electrolyzer.dm index 56ee3c6039d26..2da9ac752b549 100644 --- a/code/modules/atmospherics/machinery/components/electrolyzer/electrolyzer.dm +++ b/code/modules/atmospherics/machinery/components/electrolyzer/electrolyzer.dm @@ -127,7 +127,7 @@ if(anchored) use_energy(power_to_use) else - cell.use(power_to_use KILO JOULES) + cell.use(power_to_use) /obj/machinery/electrolyzer/proc/call_reactions(datum/gas_mixture/env) for(var/reaction in GLOB.electrolyzer_reactions) diff --git a/code/modules/atmospherics/machinery/portable/canister.dm b/code/modules/atmospherics/machinery/portable/canister.dm index 75152798bba71..6d4a8ad714a41 100644 --- a/code/modules/atmospherics/machinery/portable/canister.dm +++ b/code/modules/atmospherics/machinery/portable/canister.dm @@ -483,7 +483,7 @@ var/energy_consumed = energy_factor * 250 * seconds_per_tick if(powered(AREA_USAGE_EQUIP, ignore_use_power = TRUE)) use_energy(energy_consumed, channel = AREA_USAGE_EQUIP) - else if(!internal_cell?.use(energy_consumed * 0.025 KILO JOULES)) + else if(!internal_cell?.use(energy_consumed * 0.025)) shielding_powered = FALSE SSair.start_processing_machine(src) investigate_log("shielding turned off due to power loss") diff --git a/code/modules/clothing/spacesuits/_spacesuits.dm b/code/modules/clothing/spacesuits/_spacesuits.dm index 74741513d7082..c90d979685bd6 100644 --- a/code/modules/clothing/spacesuits/_spacesuits.dm +++ b/code/modules/clothing/spacesuits/_spacesuits.dm @@ -1,5 +1,5 @@ /// Charge per tick consumed by the thermal regulator -#define THERMAL_REGULATOR_COST (18 KILO JOULES) +#define THERMAL_REGULATOR_COST (0.018 * STANDARD_CELL_CHARGE) //Note: Everything in modules/clothing/spacesuits should have the entire suit grouped together. // Meaning the the suit is defined directly after the corrisponding helmet. Just like below! diff --git a/code/modules/explorer_drone/loot.dm b/code/modules/explorer_drone/loot.dm index 88cd5f38275e7..727731239686f 100644 --- a/code/modules/explorer_drone/loot.dm +++ b/code/modules/explorer_drone/loot.dm @@ -175,7 +175,7 @@ GLOBAL_LIST_INIT(adventure_loot_generator_index,generate_generator_index()) return if(LAZYACCESS(user.do_afters, "firelance")) return - if(!cell.use(200 KILO JOULES)) + if(!cell.use(0.2 * STANDARD_CELL_CHARGE)) to_chat(user,span_warning("[src] battery ran dry!")) return ADD_TRAIT(user, TRAIT_IMMOBILIZED, REF(src)) diff --git a/code/modules/food_and_drinks/machinery/microwave.dm b/code/modules/food_and_drinks/machinery/microwave.dm index 55509886a3af9..0f1be89410a41 100644 --- a/code/modules/food_and_drinks/machinery/microwave.dm +++ b/code/modules/food_and_drinks/machinery/microwave.dm @@ -15,7 +15,7 @@ #define MAX_MICROWAVE_DIRTINESS 100 /// For the wireless version, and display fluff -#define TIER_1_CELL_CHARGE_RATE (250 KILO JOULES) +#define TIER_1_CELL_CHARGE_RATE (0.25 * STANDARD_CELL_CHARGE) /obj/machinery/microwave name = "microwave oven" diff --git a/code/modules/hydroponics/plant_genes.dm b/code/modules/hydroponics/plant_genes.dm index 8a6e028336b86..b273cfb6d5854 100644 --- a/code/modules/hydroponics/plant_genes.dm +++ b/code/modules/hydroponics/plant_genes.dm @@ -589,7 +589,7 @@ var/obj/item/stock_parts/cell/potato/pocell = new /obj/item/stock_parts/cell/potato(user.loc) pocell.icon = our_plant.icon // Just in case the plant icons get spread out in different files eventually, this trait won't cause error sprites (also yay downstreams) pocell.icon_state = our_plant.icon_state - pocell.maxcharge = our_seed.potency * 20 KILO JOULES + pocell.maxcharge = our_seed.potency * 0.02 * STANDARD_CELL_CHARGE // The secret of potato supercells! var/datum/plant_gene/trait/cell_charge/electrical_gene = our_seed.get_gene(/datum/plant_gene/trait/cell_charge) diff --git a/code/modules/mob/living/basic/festivus_pole.dm b/code/modules/mob/living/basic/festivus_pole.dm index 90eca4b272d3c..838674c081124 100644 --- a/code/modules/mob/living/basic/festivus_pole.dm +++ b/code/modules/mob/living/basic/festivus_pole.dm @@ -1,3 +1,6 @@ +///how much charge we give off to cells around us when rubbed +#define FESTIVUS_RECHARGE_VALUE (0.075 * STANDARD_CELL_CHARGE) + /mob/living/basic/festivus name = "festivus pole" desc = "Serenity now... SERENITY NOW!" @@ -37,10 +40,6 @@ ai_controller = /datum/ai_controller/basic_controller/festivus_pole - ///how much charge we give off to cells around us when rubbed - var/recharge_value = 75 KILO JOULES - - /mob/living/basic/festivus/Initialize(mapload) . = ..() AddComponent(/datum/component/seethrough_mob) @@ -71,16 +70,16 @@ for(var/atom/affected in range(2, get_turf(src))) if(istype(affected, /obj/item/stock_parts/cell)) var/obj/item/stock_parts/cell/cell = affected - cell.give(recharge_value) + cell.give(FESTIVUS_RECHARGE_VALUE) cell.update_appearance() if(istype(affected, /mob/living/silicon/robot)) var/mob/living/silicon/robot/robot = affected if(robot.cell) - robot.cell.give(recharge_value) + robot.cell.give(FESTIVUS_RECHARGE_VALUE) if(istype(affected, /obj/machinery/power/apc)) var/obj/machinery/power/apc/apc_target = affected if(apc_target.cell) - apc_target.cell.give(recharge_value) + apc_target.cell.give(FESTIVUS_RECHARGE_VALUE) /datum/ai_planning_subtree/find_and_hunt_target/look_for_apcs hunting_behavior = /datum/ai_behavior/hunt_target/apcs @@ -118,3 +117,5 @@ return FALSE return can_see(source, dinner, radius) + +#undef FESTIVUS_RECHARGE_VALUE diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm index 2a9631339fc61..0f1cbfa65a51b 100644 --- a/code/modules/mob/living/silicon/robot/life.dm +++ b/code/modules/mob/living/silicon/robot/life.dm @@ -18,7 +18,7 @@ /mob/living/silicon/robot/proc/use_energy(seconds_per_tick, times_fired) if(cell?.charge) - if(cell.charge <= (10 KILO JOULES)) + if(cell.charge <= 0.01 * STANDARD_CELL_CHARGE) drop_all_held_items() var/energy_consumption = max(lamp_power_consumption * lamp_enabled * lamp_intensity * seconds_per_tick, BORG_MINIMUM_POWER_CONSUMPTION * seconds_per_tick) //Lamp will use a max of 5 * [BORG_LAMP_POWER_CONSUMPTION], depending on brightness of lamp. If lamp is off, borg systems consume [BORG_MINIMUM_POWER_CONSUMPTION], or the rest of the cell if it's lower than that. cell.use(energy_consumption, force = TRUE) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 886320e2c46ed..4be370db44ba4 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -226,7 +226,7 @@ if(!ionpulse_on) return - if(!cell.use(10 KILO JOULES)) + if(!cell.use(0.01 * STANDARD_CELL_CHARGE)) toggle_ionpulse() return return TRUE diff --git a/code/modules/mod/mod_link.dm b/code/modules/mod/mod_link.dm index 7657b2678be36..40a0fb94f17f7 100644 --- a/code/modules/mod/mod_link.dm +++ b/code/modules/mod/mod_link.dm @@ -199,7 +199,7 @@ /obj/item/clothing/neck/link_scryer/process(seconds_per_tick) if(!mod_link.link_call) return - cell.use(20 KILO WATTS * seconds_per_tick, force = TRUE) + cell.use(0.02 * STANDARD_CELL_RATE * seconds_per_tick, force = TRUE) /obj/item/clothing/neck/link_scryer/attackby(obj/item/attacked_by, mob/user, params) . = ..() diff --git a/code/modules/mod/modules/modules_ninja.dm b/code/modules/mod/modules/modules_ninja.dm index 868b4a79500a4..d52a5e1fb4c43 100644 --- a/code/modules/mod/modules/modules_ninja.dm +++ b/code/modules/mod/modules/modules_ninja.dm @@ -133,10 +133,6 @@ icon_state = "hacker" removable = FALSE incompatible_modules = list(/obj/item/mod/module/hacker) - /// Minimum amount of energy we can drain in a single drain action - var/mindrain = 200 KILO JOULES - /// Maximum amount of energy we can drain in a single drain action - var/maxdrain = 400 KILO JOULES /// Whether or not the communication console hack was used to summon another antagonist. var/communication_console_hack_success = FALSE /// How many times the module has been used to force open doors. diff --git a/code/modules/power/apc/apc_main.dm b/code/modules/power/apc/apc_main.dm index 62398aa4fc05d..0baf800fa1037 100644 --- a/code/modules/power/apc/apc_main.dm +++ b/code/modules/power/apc/apc_main.dm @@ -626,7 +626,7 @@ /obj/machinery/power/apc/proc/overload_lighting() if(!operating || shorted) return - if(cell && cell.use(20 KILO JOULES)) + if(cell && cell.use(0.02 * STANDARD_CELL_CHARGE)) INVOKE_ASYNC(src, PROC_REF(break_lights)) /obj/machinery/power/apc/proc/break_lights() diff --git a/code/modules/power/apc/apc_tool_act.dm b/code/modules/power/apc/apc_tool_act.dm index 6a8835cd5b71e..0116205fdd4ca 100644 --- a/code/modules/power/apc/apc_tool_act.dm +++ b/code/modules/power/apc/apc_tool_act.dm @@ -168,7 +168,7 @@ if(machine_stat & BROKEN) balloon_alert(user, "frame is too damaged!") return ITEM_INTERACT_BLOCKING - if(!pseudocircuit.adapt_circuit(user, circuit_cost = 50 KILO JOULES)) + if(!pseudocircuit.adapt_circuit(user, circuit_cost = 0.05 * STANDARD_CELL_CHARGE)) return ITEM_INTERACT_BLOCKING user.visible_message( span_notice("[user] fabricates a circuit and places it into [src]."), @@ -182,7 +182,7 @@ if(machine_stat & MAINT) balloon_alert(user, "no board for a cell!") return ITEM_INTERACT_BLOCKING - if(!pseudocircuit.adapt_circuit(user, circuit_cost = 500 KILO JOULES)) + if(!pseudocircuit.adapt_circuit(user, circuit_cost = 0.5 * STANDARD_CELL_CHARGE)) return ITEM_INTERACT_BLOCKING var/obj/item/stock_parts/cell/crap/empty/bad_cell = new(src) bad_cell.forceMove(src) diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm index 5623f57895e3c..db5791da43526 100644 --- a/code/modules/power/cell.dm +++ b/code/modules/power/cell.dm @@ -31,7 +31,7 @@ ///If the power cell was damaged by an explosion, chance for it to become corrupted and function the same as rigged. var/corrupted = FALSE ///How much power is given per second in a recharger. - var/chargerate = STANDARD_CELL_CHARGE * 0.05 + var/chargerate = STANDARD_CELL_RATE * 0.05 ///If true, the cell will state it's maximum charge in it's description var/ratingdesc = TRUE ///If it's a grown that acts as a battery, add a wire overlay to it. @@ -326,7 +326,7 @@ desc = "A power cell with a slightly higher capacity than normal!" maxcharge = STANDARD_CELL_CHARGE * 2.5 custom_materials = list(/datum/material/glass=SMALL_MATERIAL_AMOUNT*0.5) - chargerate = STANDARD_CELL_CHARGE * 0.5 + chargerate = STANDARD_CELL_RATE * 0.5 /obj/item/stock_parts/cell/upgraded/plus name = "upgraded power cell+" @@ -352,7 +352,7 @@ /obj/item/stock_parts/cell/pulse //200 pulse shots name = "pulse rifle power cell" maxcharge = STANDARD_CELL_CHARGE * 40 - chargerate = STANDARD_CELL_CHARGE * 0.75 + chargerate = STANDARD_CELL_RATE * 0.75 /obj/item/stock_parts/cell/pulse/carbine //25 pulse shots name = "pulse carbine power cell" @@ -367,14 +367,14 @@ icon_state = "bscell" maxcharge = STANDARD_CELL_CHARGE * 10 custom_materials = list(/datum/material/glass=SMALL_MATERIAL_AMOUNT*0.6) - chargerate = STANDARD_CELL_CHARGE + chargerate = STANDARD_CELL_RATE /obj/item/stock_parts/cell/high name = "high-capacity power cell" icon_state = "hcell" maxcharge = STANDARD_CELL_CHARGE * 10 custom_materials = list(/datum/material/glass=SMALL_MATERIAL_AMOUNT*0.6) - chargerate = STANDARD_CELL_CHARGE * 0.75 + chargerate = STANDARD_CELL_RATE * 0.75 /obj/item/stock_parts/cell/high/empty empty = TRUE @@ -384,7 +384,7 @@ icon_state = "scell" maxcharge = STANDARD_CELL_CHARGE * 20 custom_materials = list(/datum/material/glass=SMALL_MATERIAL_AMOUNT * 3) - chargerate = STANDARD_CELL_CHARGE + chargerate = STANDARD_CELL_RATE /obj/item/stock_parts/cell/super/empty empty = TRUE @@ -394,7 +394,7 @@ icon_state = "hpcell" maxcharge = STANDARD_CELL_CHARGE * 30 custom_materials = list(/datum/material/glass=SMALL_MATERIAL_AMOUNT * 4) - chargerate = STANDARD_CELL_CHARGE * 1.5 + chargerate = STANDARD_CELL_RATE * 1.5 /obj/item/stock_parts/cell/hyper/empty empty = TRUE @@ -405,7 +405,7 @@ icon_state = "bscell" maxcharge = STANDARD_CELL_CHARGE * 40 custom_materials = list(/datum/material/glass=SMALL_MATERIAL_AMOUNT*6) - chargerate = STANDARD_CELL_CHARGE * 2 + chargerate = STANDARD_CELL_RATE * 2 /obj/item/stock_parts/cell/bluespace/empty empty = TRUE @@ -478,7 +478,7 @@ name = "beam rifle capacitor" desc = "A high powered capacitor that can provide huge amounts of energy in an instant." maxcharge = STANDARD_CELL_CHARGE * 50 - chargerate = STANDARD_CELL_CHARGE * 2.5 //Extremely energy intensive + chargerate = STANDARD_CELL_RATE * 2.5 //Extremely energy intensive /obj/item/stock_parts/cell/beam_rifle/corrupt() return diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index 8ad40a06c8936..d8b291d68fe56 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -78,6 +78,9 @@ ammo_type = list(/obj/item/ammo_casing/energy/mindflayer) ammo_x_offset = 2 +/// amount of charge used up to start action (multiplied by amount) and per progress_flash_divisor ticks of welding +#define PLASMA_CUTTER_CHARGE_WELD (0.025 * STANDARD_CELL_CHARGE) + /obj/item/gun/energy/plasmacutter name = "plasma cutter" desc = "A mining tool capable of expelling concentrated plasma bursts. You could use it to cut limbs off xenos! Or, you know, mine stuff." @@ -91,13 +94,10 @@ sharpness = SHARP_EDGED can_charge = FALSE gun_flags = NOT_A_REAL_GUN - heat = 3800 usesound = list('sound/items/welder.ogg', 'sound/items/welder2.ogg') tool_behaviour = TOOL_WELDER toolspeed = 0.7 //plasmacutters can be used as welders, and are faster than standard welders - /// amount of charge used up to start action (multiplied by amount) and per progress_flash_divisor ticks of welding - var/charge_weld = 25 KILO JOULES /obj/item/gun/energy/plasmacutter/Initialize(mapload) AddElement(/datum/element/update_icon_blocker) @@ -126,7 +126,7 @@ balloon_alert(user, "already fully charged!") return I.use(1) - cell.give(500 KILO JOULES * charge_multiplier) + cell.give(0.5 * STANDARD_CELL_CHARGE * charge_multiplier) balloon_alert(user, "cell recharged") else ..() @@ -148,14 +148,14 @@ // Amount cannot be used if drain is made continuous, e.g. amount = 5, charge_weld = 25 // Then it'll drain 125 at first and 25 periodically, but fail if charge dips below 125 even though it still can finish action // Alternately it'll need to drain amount*charge_weld every period, which is either obscene or makes it free for other uses - if(amount ? cell.charge < charge_weld * amount : cell.charge < charge_weld) + if(amount ? cell.charge < PLASMA_CUTTER_CHARGE_WELD * amount : cell.charge < PLASMA_CUTTER_CHARGE_WELD) balloon_alert(user, "not enough charge!") return FALSE return TRUE /obj/item/gun/energy/plasmacutter/use(used) - return (!QDELETED(cell) && cell.use(used ? used * charge_weld : charge_weld)) + return (!QDELETED(cell) && cell.use(used ? used * PLASMA_CUTTER_CHARGE_WELD : PLASMA_CUTTER_CHARGE_WELD)) /obj/item/gun/energy/plasmacutter/use_tool(atom/target, mob/living/user, delay, amount=1, volume=0, datum/callback/extra_checks) @@ -169,6 +169,8 @@ else . = ..(amount=1) +#undef PLASMA_CUTTER_CHARGE_WELD + /obj/item/gun/energy/plasmacutter/adv name = "advanced plasma cutter" icon_state = "adv_plasmacutter" diff --git a/code/modules/reagents/chemistry/machinery/chem_mass_spec.dm b/code/modules/reagents/chemistry/machinery/chem_mass_spec.dm index ca75736db0323..f6bca51764824 100644 --- a/code/modules/reagents/chemistry/machinery/chem_mass_spec.dm +++ b/code/modules/reagents/chemistry/machinery/chem_mass_spec.dm @@ -457,7 +457,7 @@ if(!is_operational || panel_open || !anchored || (machine_stat & (BROKEN | NOPOWER))) return - if(!use_energy(active_power_usage * seconds_per_tick)) + if(!use_energy(active_power_usage * seconds_per_tick, force = FALSE)) return progress_time += seconds_per_tick diff --git a/code/modules/reagents/reagent_containers/misc.dm b/code/modules/reagents/reagent_containers/misc.dm index fa8d8cd36281f..f631e8e28a0e0 100644 --- a/code/modules/reagents/reagent_containers/misc.dm +++ b/code/modules/reagents/reagent_containers/misc.dm @@ -32,7 +32,7 @@ if(on && (!cell || cell.charge <= 0)) //Check if we ran out of power change_power_status(FALSE) return FALSE - cell.use(5 KILO WATTS * seconds_per_tick) //Basic cell goes for like 200 seconds, bluespace for 8000 + cell.use(0.005 * STANDARD_CELL_RATE * seconds_per_tick) //Basic cell goes for like 200 seconds, bluespace for 8000 if(!reagents.total_volume) return FALSE var/max_temp = min(500 + (500 * (0.2 * cell.rating)), 1000) // 373 to 1000 diff --git a/code/modules/research/machinery/_production.dm b/code/modules/research/machinery/_production.dm index 96e1387e2ccfb..c5a24d507d477 100644 --- a/code/modules/research/machinery/_production.dm +++ b/code/modules/research/machinery/_production.dm @@ -1,8 +1,8 @@ /obj/machinery/rnd/production name = "technology fabricator" desc = "Makes researched and prototype items with materials and energy." - // Energy cost per full stack of materials spent. Material insertion is 40% of this. - active_power_usage = 50 * BASE_MACHINE_ACTIVE_CONSUMPTION + /// Energy cost per full stack of materials spent. Material insertion is 40% of this. + active_power_usage = 0.05 * STANDARD_CELL_RATE /// The efficiency coefficient. Material costs and print times are multiplied by this number; var/efficiency_coeff = 1 diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index 995764e0bb7d1..8152f97e1a477 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -36,11 +36,11 @@ hud_possible = list(DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_TRACK_HUD, DIAG_CAMERA_HUD) mouse_pointer = 'icons/effects/mouse_pointers/mecha_mouse.dmi' ///How much energy the mech will consume each time it moves. this is the current active energy consumed - var/step_energy_drain = 8 KILO JOULES + var/step_energy_drain = 0.008 * STANDARD_CELL_CHARGE ///How much energy we drain each time we mechpunch someone - var/melee_energy_drain = 15 KILO JOULES + var/melee_energy_drain = 0.015 * STANDARD_CELL_CHARGE ///Power we use to have the lights on - var/light_power_drain = 2 KILO WATTS + var/light_power_drain = 0.002 * STANDARD_CELL_RATE ///Modifiers for directional damage reduction var/list/facing_modifiers = list(MECHA_FRONT_ARMOUR = 0.5, MECHA_SIDE_ARMOUR = 1, MECHA_BACK_ARMOUR = 1.5) ///if we cant use our equipment(such as due to EMP) diff --git a/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm b/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm index 25fd2879a6b90..8343dc85a54b7 100644 --- a/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm +++ b/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm @@ -10,7 +10,7 @@ desc = "Equipment for engineering and combat exosuits. This is the drill that'll pierce the heavens!" icon_state = "mecha_drill" equip_cooldown = 15 - energy_drain = 10 KILO JOULES + energy_drain = 0.01 * STANDARD_CELL_CHARGE force = 15 harmful = TRUE range = MECHA_MELEE diff --git a/code/modules/vehicles/mecha/equipment/tools/other_tools.dm b/code/modules/vehicles/mecha/equipment/tools/other_tools.dm index 067ad2250f06b..43f2715dbec50 100644 --- a/code/modules/vehicles/mecha/equipment/tools/other_tools.dm +++ b/code/modules/vehicles/mecha/equipment/tools/other_tools.dm @@ -9,7 +9,7 @@ desc = "An exosuit module that allows exosuits to teleport to any position in view." icon_state = "mecha_teleport" equip_cooldown = 150 - energy_drain = 1 MEGA JOULES + energy_drain = STANDARD_CELL_CHARGE range = MECHA_RANGED var/teleport_range = 7 @@ -285,7 +285,7 @@ ///Maximum fuel capacity of the generator, in units var/max_fuel = 75 * SHEET_MATERIAL_AMOUNT ///Energy recharged per second - var/rechargerate = 5 KILO WATTS + var/rechargerate = 0.005 * STANDARD_CELL_RATE /obj/item/mecha_parts/mecha_equipment/generator/Initialize(mapload) . = ..() diff --git a/code/modules/vehicles/mecha/equipment/tools/work_tools.dm b/code/modules/vehicles/mecha/equipment/tools/work_tools.dm index 5497113017e87..276afc0f3d6c7 100644 --- a/code/modules/vehicles/mecha/equipment/tools/work_tools.dm +++ b/code/modules/vehicles/mecha/equipment/tools/work_tools.dm @@ -7,7 +7,7 @@ desc = "Equipment for engineering exosuits. Lifts objects and loads them into cargo." icon_state = "mecha_clamp" equip_cooldown = 15 - energy_drain = 10 KILO JOULES + energy_drain = 0.01 * STANDARD_CELL_CHARGE tool_behaviour = TOOL_RETRACTOR range = MECHA_MELEE toolspeed = 0.8 diff --git a/code/modules/vehicles/mecha/mech_bay.dm b/code/modules/vehicles/mecha/mech_bay.dm index 1f46856562575..1a6ce31e28470 100644 --- a/code/modules/vehicles/mecha/mech_bay.dm +++ b/code/modules/vehicles/mecha/mech_bay.dm @@ -12,7 +12,7 @@ ///Ref to charge console for seeing charge for this port, cyclical reference var/obj/machinery/computer/mech_bay_power_console/recharge_console ///Power unit per second to charge by - var/recharge_power = 25 KILO WATTS + var/recharge_power = 0.025 * STANDARD_CELL_RATE ///turf that will be checked when a mech wants to charge. directly one turf in the direction it is facing var/turf/recharging_turf @@ -46,7 +46,7 @@ var/total_rating = 0 for(var/datum/stock_part/capacitor/capacitor in component_parts) total_rating += capacitor.tier - recharge_power = total_rating * 12.5 KILO WATTS + recharge_power = total_rating * 0.0125 * STANDARD_CELL_RATE /obj/machinery/mech_bay_recharge_port/examine(mob/user) . = ..() @@ -65,7 +65,7 @@ if(!recharging_mech?.cell) return if(recharging_mech.cell.charge < recharging_mech.cell.maxcharge) - if(!use_energy(active_power_usage * seconds_per_tick)) + if(!use_energy(active_power_usage * seconds_per_tick, force = FALSE)) return charge_cell(recharge_power * seconds_per_tick, recharging_mech.cell, grid_only = TRUE) else diff --git a/code/modules/vehicles/motorized_wheelchair.dm b/code/modules/vehicles/motorized_wheelchair.dm index 128530968e243..8dbdfd93e8f69 100644 --- a/code/modules/vehicles/motorized_wheelchair.dm +++ b/code/modules/vehicles/motorized_wheelchair.dm @@ -10,7 +10,7 @@ ///Self explanatory, ratio of how much power we use var/power_efficiency = 1 ///How much energy we use - var/energy_usage = 100 KILO JOULES + var/energy_usage = 0.1 * STANDARD_CELL_CHARGE ///whether the panel is open so a user can take out the cell var/panel_open = FALSE ///Parts used in building the wheelchair diff --git a/code/modules/wiremod/shell/gun.dm b/code/modules/wiremod/shell/gun.dm index ff5815367139b..9f196e6c1fcce 100644 --- a/code/modules/wiremod/shell/gun.dm +++ b/code/modules/wiremod/shell/gun.dm @@ -82,6 +82,6 @@ if(!parent?.cell) return var/obj/item/gun/energy/fired_gun = source - var/totransfer = min(100 KILO JOULES, parent.cell.charge) - var/transferred = fired_gun.cell.give(totransfer) - parent.cell.use(transferred) + var/transferred = fired_gun.cell.give(min(0.1 * STANDARD_CELL_CHARGE, parent.cell.charge)) + if(transferred) + parent.cell.use(transferred, force = TRUE) From 06206b8e523b6db3177fba6dad28edbb9066c5a5 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 19 Apr 2024 09:29:40 +1200 Subject: [PATCH 329/938] Automatic changelog for PR #82594 [ci skip] --- html/changelogs/AutoChangeLog-pr-82594.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82594.yml diff --git a/html/changelogs/AutoChangeLog-pr-82594.yml b/html/changelogs/AutoChangeLog-pr-82594.yml new file mode 100644 index 0000000000000..10f6315726f98 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82594.yml @@ -0,0 +1,4 @@ +author: "SyncIt21" +delete-after: True +changes: + - code_imp: "most cell power usages are scaled with defined constants to help adapt to future changes" \ No newline at end of file From 963b70c29479c2f227c4c56b63209b6bf2f49813 Mon Sep 17 00:00:00 2001 From: Jeremiah <42397676+jlsnow301@users.noreply.github.com> Date: Thu, 18 Apr 2024 16:51:58 -0700 Subject: [PATCH 330/938] Fixes tgui alert buttons (#82714) ## About The Pull Request Been on my mind for a long time I did this while relatively inexperienced (how do I center a div etc) Fixes an issue inherent to our stack implementation where reversing the direction caused strange spacing issues. This effectively reverses the extra margins in css so it looks identically spaced whether reversed/not

    before/after Before (normal buttons) ![image](https://github.com/tgstation/tgstation/assets/42397676/a91f5522-b363-4069-9e71-9852b15e9d98) Before (large buttons) ![image](https://github.com/tgstation/tgstation/assets/42397676/1448b6db-9417-4f93-bbe3-3cb39c70d6a4) After (normal buttons) ![Screenshot 2024-04-16 234002](https://github.com/tgstation/tgstation/assets/42397676/e19f6a71-bd11-4f21-8cfc-b29e89020f5c) After (large buttons) ![Screenshot 2024-04-16 234015](https://github.com/tgstation/tgstation/assets/42397676/6adc55cc-42ca-4c1a-a18c-c2dadf3413ce) Long buttons (normal) ![Screenshot 2024-04-17 174208](https://github.com/tgstation/tgstation/assets/42397676/b919c049-658c-4b9e-ab3f-6d06eb9d467e) Long buttons (large buttons (I am 35 and yet still fight the forces of chaos)) ![Screenshot 2024-04-17 174202](https://github.com/tgstation/tgstation/assets/42397676/01fae7ff-8c51-4789-88ac-9d533e1f0eeb)
    ## Why It's Good For The Game Looks better, runs smoother, no clipping ## Changelog :cl: fix: TGUI Alerts shouldn't have such wonky buttons any more /:cl: --------- Co-authored-by: lessthanthree <83487515+lessthnthree@users.noreply.github.com> --- tgui/packages/tgui/components/Stack.tsx | 30 ++- tgui/packages/tgui/interfaces/AlertModal.tsx | 224 ++++++++++-------- .../tgui/styles/components/Stack.scss | 18 ++ 3 files changed, 159 insertions(+), 113 deletions(-) diff --git a/tgui/packages/tgui/components/Stack.tsx b/tgui/packages/tgui/components/Stack.tsx index 18ae34c09e8c6..3f5cf72123cc0 100644 --- a/tgui/packages/tgui/components/Stack.tsx +++ b/tgui/packages/tgui/components/Stack.tsx @@ -17,14 +17,23 @@ import { } from './Flex'; type Props = Partial<{ - vertical: boolean; + /** Fills available space. */ fill: boolean; + /** Reverses the stack. */ + reverse: boolean; + /** Flex column */ + vertical: boolean; + /** Adds zebra striping to the stack. */ zebra: boolean; }> & FlexProps; -export const Stack = (props: Props) => { - const { className, vertical, fill, zebra, ...rest } = props; +export function Stack(props: Props) { + const { className, vertical, fill, reverse, zebra, ...rest } = props; + + const directionPrefix = vertical ? 'column' : 'row'; + const directionSuffix = reverse ? '-reverse' : ''; + return (
    { fill && 'Stack--fill', vertical ? 'Stack--vertical' : 'Stack--horizontal', zebra && 'Stack--zebra', + reverse && `Stack--reverse${vertical ? '--vertical' : ''}`, className, computeFlexClassName(props), ])} {...computeFlexProps({ - direction: vertical ? 'column' : 'row', + direction: `${directionPrefix}${directionSuffix}`, ...rest, })} /> ); -}; +} type StackItemProps = FlexItemProps & Partial<{ innerRef: RefObject; }>; -const StackItem = (props: StackItemProps) => { +function StackItem(props: StackItemProps) { const { className, innerRef, ...rest } = props; + return (
    { {...computeFlexItemProps(rest)} /> ); -}; +} Stack.Item = StackItem; @@ -70,8 +81,9 @@ type StackDividerProps = FlexItemProps & hidden: boolean; }>; -const StackDivider = (props: StackDividerProps) => { +function StackDivider(props: StackDividerProps) { const { className, hidden, ...rest } = props; + return (
    { {...computeFlexItemProps(rest)} /> ); -}; +} Stack.Divider = StackDivider; diff --git a/tgui/packages/tgui/interfaces/AlertModal.tsx b/tgui/packages/tgui/interfaces/AlertModal.tsx index d5b931dc08c7c..62b6e8bbbc328 100644 --- a/tgui/packages/tgui/interfaces/AlertModal.tsx +++ b/tgui/packages/tgui/interfaces/AlertModal.tsx @@ -1,33 +1,29 @@ -import { useState } from 'react'; - -import { - KEY_ENTER, - KEY_ESCAPE, - KEY_LEFT, - KEY_RIGHT, - KEY_SPACE, - KEY_TAB, -} from '../../common/keycodes'; +import { KEY } from 'common/keys'; +import { BooleanLike } from 'common/react'; +import { KeyboardEvent, useState } from 'react'; + import { useBackend } from '../backend'; -import { Autofocus, Box, Button, Flex, Section, Stack } from '../components'; +import { Autofocus, Box, Button, Section, Stack } from '../components'; import { Window } from '../layouts'; import { Loader } from './common/Loader'; -type AlertModalData = { - autofocus: boolean; +type Data = { + autofocus: BooleanLike; buttons: string[]; - large_buttons: boolean; + large_buttons: BooleanLike; message: string; - swapped_buttons: boolean; + swapped_buttons: BooleanLike; timeout: number; title: string; }; -const KEY_DECREMENT = -1; -const KEY_INCREMENT = 1; +enum DIRECTION { + Increment = 1, + Decrement = -1, +} -export const AlertModal = (props) => { - const { act, data } = useBackend(); +export function AlertModal(props) { + const { act, data } = useBackend(); const { autofocus, buttons = [], @@ -36,128 +32,148 @@ export const AlertModal = (props) => { timeout, title, } = data; + const [selected, setSelected] = useState(0); + + // At least one of the buttons has a long text message + const isVerbose = buttons.some((button) => button.length > 10); + const largeSpacing = isVerbose && large_buttons ? 20 : 15; + // Dynamically sets window dimensions const windowHeight = - 115 + + 120 + + (isVerbose ? largeSpacing * buttons.length : 0) + (message.length > 30 ? Math.ceil(message.length / 4) : 0) + (message.length && large_buttons ? 5 : 0); - const windowWidth = 325 + (buttons.length > 2 ? 55 : 0); - const onKey = (direction: number) => { - if (selected === 0 && direction === KEY_DECREMENT) { - setSelected(buttons.length - 1); - } else if (selected === buttons.length - 1 && direction === KEY_INCREMENT) { - setSelected(0); - } else { - setSelected(selected + direction); + + const windowWidth = 345 + (buttons.length > 2 ? 55 : 0); + + /** Changes button selection, etc */ + function keyDownHandler(event: KeyboardEvent) { + switch (event.key) { + case KEY.Space: + case KEY.Enter: + act('choose', { choice: buttons[selected] }); + return; + case KEY.Escape: + act('cancel'); + return; + case KEY.Left: + event.preventDefault(); + onKey(DIRECTION.Decrement); + return; + case KEY.Tab: + case KEY.Right: + event.preventDefault(); + onKey(DIRECTION.Increment); + return; } - }; + } + + /** Manages iterating through the buttons */ + function onKey(direction: DIRECTION) { + const newIndex = (selected + direction + buttons.length) % buttons.length; + setSelected(newIndex); + } return ( {!!timeout && } - { - const keyCode = window.event ? e.which : e.keyCode; - /** - * Simulate a click when pressing space or enter, - * allow keyboard navigation, override tab behavior - */ - if (keyCode === KEY_SPACE || keyCode === KEY_ENTER) { - act('choose', { choice: buttons[selected] }); - } else if (keyCode === KEY_ESCAPE) { - act('cancel'); - } else if (keyCode === KEY_LEFT) { - e.preventDefault(); - onKey(KEY_DECREMENT); - } else if (keyCode === KEY_TAB || keyCode === KEY_RIGHT) { - e.preventDefault(); - onKey(KEY_INCREMENT); - } - }} - > +
    - + {message} - + {!!autofocus && } - + {isVerbose ? ( + + ) : ( + + )}
    ); +} + +type ButtonDisplayProps = { + selected: number; }; /** * Displays a list of buttons ordered by user prefs. - * Technically this handles more than 2 buttons, but you - * should just be using a list input in that case. */ -const ButtonDisplay = (props) => { - const { data } = useBackend(); +function HorizontalButtons(props: ButtonDisplayProps) { + const { act, data } = useBackend(); const { buttons = [], large_buttons, swapped_buttons } = data; const { selected } = props; return ( - - {buttons?.map((button, index) => - !!large_buttons && buttons.length < 3 ? ( - - - - ) : ( - - - - ), - )} - + + {buttons.map((button, index) => ( + + + + ))} + ); -}; +} /** - * Displays a button with variable sizing. + * Technically the parent handles more than 2 buttons, but you + * should just be using a list input in that case. */ -const AlertButton = (props) => { - const { act, data } = useBackend(); - const { large_buttons } = data; - const { button, selected } = props; - const buttonWidth = button.length > 7 ? button.length : 7; +function VerticalButtons(props: ButtonDisplayProps) { + const { act, data } = useBackend(); + const { buttons = [], large_buttons, swapped_buttons } = data; + const { selected } = props; return ( - + {buttons.map((button, index) => ( + + + + ))} + ); -}; +} diff --git a/tgui/packages/tgui/styles/components/Stack.scss b/tgui/packages/tgui/styles/components/Stack.scss index 02d0e8bbe24d2..3529c70018390 100644 --- a/tgui/packages/tgui/styles/components/Stack.scss +++ b/tgui/packages/tgui/styles/components/Stack.scss @@ -28,6 +28,24 @@ $zebra-background-color: base.$color-bg-section !default; } } +.Stack--reverse > .Stack__item { + margin-left: 0; + margin-right: 0.5em; + + &:first-child { + margin-right: 0; + } +} + +.Stack--reverse--vertical > .Stack__item { + margin-top: 0; + margin-bottom: 0.5em; + + &:first-child { + margin-bottom: 0; + } +} + .Stack--zebra > .Stack__item:nth-child(even) { background-color: $zebra-background-color; } From 2c55fcea989d77c37208064afe744e0973f64c43 Mon Sep 17 00:00:00 2001 From: Iajret <8430839+Iajret@users.noreply.github.com> Date: Fri, 19 Apr 2024 02:52:11 +0300 Subject: [PATCH 331/938] Fixes cooling and anti-disruption RCD upgrades being unavialble for ancient protolathes (#82719) ## About The Pull Request Makes this upgrades available for ghostroles and such ![image](https://github.com/tgstation/tgstation/assets/8430839/01b4a947-1108-4c2f-86d6-df134e20c14c) ## Why It's Good For The Game Having ability to use RCD faster iskinda good ## Changelog :cl: fix: cooling and anti-disruption RCD upgrades can now be printed in ancient protolathes /:cl: --- code/modules/research/designs/tool_designs.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/research/designs/tool_designs.dm b/code/modules/research/designs/tool_designs.dm index 304ed53790a68..649d0c5c09dfc 100644 --- a/code/modules/research/designs/tool_designs.dm +++ b/code/modules/research/designs/tool_designs.dm @@ -137,7 +137,7 @@ name = "RCD anti disruption designs upgrade" desc = "Prevents interruption of RCD construction and deconstruction." id = "rcd_upgrade_anti_interrupt" - build_type = PROTOLATHE + build_type = PROTOLATHE | AWAY_LATHE materials = list( /datum/material/iron = SHEET_MATERIAL_AMOUNT * 2.5, /datum/material/glass = SHEET_MATERIAL_AMOUNT * 1.25, @@ -154,7 +154,7 @@ name = "RCD cooling upgrade" desc = "Allows the RCD to more quickly perform multiple actions at once." id = "rcd_upgrade_cooling" - build_type = PROTOLATHE + build_type = PROTOLATHE | AWAY_LATHE materials = list( /datum/material/iron = SHEET_MATERIAL_AMOUNT * 2, /datum/material/glass = SHEET_MATERIAL_AMOUNT, From a72b158f87c0259920ba8a3bbfc2ff4ca6dc9018 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 19 Apr 2024 11:52:17 +1200 Subject: [PATCH 332/938] Automatic changelog for PR #82714 [ci skip] --- html/changelogs/AutoChangeLog-pr-82714.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82714.yml diff --git a/html/changelogs/AutoChangeLog-pr-82714.yml b/html/changelogs/AutoChangeLog-pr-82714.yml new file mode 100644 index 0000000000000..adb6abee7e23f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82714.yml @@ -0,0 +1,4 @@ +author: "jlsnow301" +delete-after: True +changes: + - bugfix: "TGUI Alerts shouldn't have such wonky buttons any more" \ No newline at end of file From fc2b6dee2bc888d2ab746ccda3aeb1610044e7fe Mon Sep 17 00:00:00 2001 From: Jeremiah <42397676+jlsnow301@users.noreply.github.com> Date: Thu, 18 Apr 2024 16:52:23 -0700 Subject: [PATCH 333/938] Adds text to lootpanel items [no gbp] (#82722) ## About The Pull Request Just some qol, this captures a small portion of the item name and fixes some icon clipping issues I clipped it at 5 because monke ![Screenshot 2024-04-17 034211](https://github.com/tgstation/tgstation/assets/42397676/64d9ce18-3722-4382-a58d-f58eb6b9f26c) ![gXR2XjslzR](https://github.com/tgstation/tgstation/assets/42397676/3fc93110-e35e-434a-b63b-89aa669090e7) ## Why It's Good For The Game Handy if youre in a rush and won't upgrade byond to fix the issue ## Changelog :cl: fix: Lootpanel additions: Condensed item names for the quick of draw /:cl: --- .../tgui/interfaces/LootPanel/IconDisplay.tsx | 14 ++++-- .../tgui/interfaces/LootPanel/LootBox.tsx | 49 +++++++++++-------- .../tgui/interfaces/LootPanel/index.tsx | 2 +- .../tgui/styles/components/SearchItem.scss | 21 ++++++-- 4 files changed, 57 insertions(+), 29 deletions(-) diff --git a/tgui/packages/tgui/interfaces/LootPanel/IconDisplay.tsx b/tgui/packages/tgui/interfaces/LootPanel/IconDisplay.tsx index 889d50de88415..11e52b2ac5544 100644 --- a/tgui/packages/tgui/interfaces/LootPanel/IconDisplay.tsx +++ b/tgui/packages/tgui/interfaces/LootPanel/IconDisplay.tsx @@ -10,15 +10,23 @@ export function IconDisplay(props: Props) { item: { icon, icon_state }, } = props; - const fallback = ; + const fallback = ; if (!icon) { return fallback; } if (icon_state) { - return ; + return ( + + ); } - return ; + return ; } diff --git a/tgui/packages/tgui/interfaces/LootPanel/LootBox.tsx b/tgui/packages/tgui/interfaces/LootPanel/LootBox.tsx index 22b0c8532dd9e..613db1ead53db 100644 --- a/tgui/packages/tgui/interfaces/LootPanel/LootBox.tsx +++ b/tgui/packages/tgui/interfaces/LootPanel/LootBox.tsx @@ -1,4 +1,4 @@ -import { capitalizeAll } from 'common/string'; +import { capitalizeAll, capitalizeFirst } from 'common/string'; import { useBackend } from '../../backend'; import { Tooltip } from '../../components'; @@ -25,28 +25,35 @@ export function LootBox(props: Props) { item = props.item; } + const name = !item.name + ? '???' + : capitalizeFirst(item.name.split(' ')[0]).slice(0, 5); + return ( -
    - act('grab', { - ctrl: event.ctrlKey, - ref: item.ref, - shift: event.shiftKey, - }) - } - onContextMenu={(event) => { - event.preventDefault(); - act('grab', { - middle: true, - ref: item.ref, - shift: true, - }); - }} - > - - {amount > 1 &&
    {amount}
    } +
    +
    + act('grab', { + ctrl: event.ctrlKey, + ref: item.ref, + shift: event.shiftKey, + }) + } + onContextMenu={(event) => { + event.preventDefault(); + act('grab', { + middle: true, + ref: item.ref, + shift: true, + }); + }} + > + + {amount > 1 &&
    {amount}
    } +
    + {name}
    ); diff --git a/tgui/packages/tgui/interfaces/LootPanel/index.tsx b/tgui/packages/tgui/interfaces/LootPanel/index.tsx index bd64113f302ec..bc6330b1806f7 100644 --- a/tgui/packages/tgui/interfaces/LootPanel/index.tsx +++ b/tgui/packages/tgui/interfaces/LootPanel/index.tsx @@ -24,7 +24,7 @@ export function LootPanel(props) { const total = contents.length ? contents.length - 1 : 0; return ( - + { if (event.key === KEY.Escape) { diff --git a/tgui/packages/tgui/styles/components/SearchItem.scss b/tgui/packages/tgui/styles/components/SearchItem.scss index 76946ec9c5acb..5dadcdf8d6aea 100644 --- a/tgui/packages/tgui/styles/components/SearchItem.scss +++ b/tgui/packages/tgui/styles/components/SearchItem.scss @@ -2,21 +2,34 @@ .SearchItem { align-items: center; + display: flex; + flex-direction: column; + justify-content: center; +} + +.SearchItem--box { background: black; border: thin solid #212121; display: flex; - height: 3rem; + align-items: center; justify-content: center; + height: 3rem; position: relative; width: 3rem; - margin-bottom: 0; } .SearchItem--amount { - bottom: -1rem; + bottom: -4px; color: colors.$teal; font-family: 'Roboto', sans-serif; font-size: 1.5rem; position: absolute; - right: -4px; + right: -6px; +} + +.SearchItem--text { + color: colors.$label; + font-family: 'Roboto', sans-serif; + font-size: 1rem; + z-index: 1; } From 41d681f56872709623577c622bb9e3a3e1ed4503 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 19 Apr 2024 11:52:28 +1200 Subject: [PATCH 334/938] Automatic changelog for PR #82719 [ci skip] --- html/changelogs/AutoChangeLog-pr-82719.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82719.yml diff --git a/html/changelogs/AutoChangeLog-pr-82719.yml b/html/changelogs/AutoChangeLog-pr-82719.yml new file mode 100644 index 0000000000000..6717e0acb6ffe --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82719.yml @@ -0,0 +1,4 @@ +author: "Iajret" +delete-after: True +changes: + - bugfix: "cooling and anti-disruption RCD upgrades can now be printed in ancient protolathes" \ No newline at end of file From 6f879d46936bb3b1f23af7254a3e4d2bdf195417 Mon Sep 17 00:00:00 2001 From: starrm4nn <139372157+starrm4nn@users.noreply.github.com> Date: Thu, 18 Apr 2024 23:53:05 +0000 Subject: [PATCH 335/938] MetaStation: Replaces the tools in the Primary Surgery Theatre with filled surgery trays (#82730) ## About The Pull Request Replaces the tools on the tables with 2 surgery trays. ![image](https://github.com/tgstation/tgstation/assets/139372157/91d195f0-10d4-4b73-843a-a2da88fc5d33) ## Why It's Good For The Game Makes surgery a bit less painful in the surgery theatre, Using tools from a tray is much nicer than having to open the context menu on the piles of tools on the tables. ## Changelog :cl: qol: Replaced the surgical tools in the Primary Surgery Theatre with 2 Surgery Trays. /:cl: --- _maps/map_files/MetaStation/MetaStation.dmm | 24 ++------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index ceb1a6e077aa4..8f374f4262de5 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -945,8 +945,6 @@ /area/station/command/heads_quarters/hos) "atf" = ( /obj/structure/table/glass, -/obj/item/clothing/gloves/latex, -/obj/item/surgical_drapes, /obj/machinery/power/apc/auto_name/directional/north, /obj/structure/cable, /obj/effect/turf_decal/tile/blue/fourcorners, @@ -5051,12 +5049,6 @@ /area/station/security/execution/education) "bMS" = ( /obj/structure/table/glass, -/obj/item/scalpel{ - pixel_y = 12 - }, -/obj/item/circular_saw, -/obj/item/blood_filter, -/obj/item/bonesetter, /obj/machinery/button/door/directional/south{ id = "main_surgery"; name = "privacy shutters control" @@ -9498,12 +9490,10 @@ /area/station/hallway/secondary/exit/departure_lounge) "dyq" = ( /obj/structure/table/glass, -/obj/item/retractor, -/obj/item/hemostat, -/obj/item/cautery, /obj/effect/turf_decal/tile/blue/fourcorners, /obj/machinery/status_display/evac/directional/west, /obj/machinery/digital_clock/directional/south, +/obj/item/surgery_tray/full, /turf/open/floor/iron/white, /area/station/medical/surgery/theatre) "dyr" = ( @@ -14256,8 +14246,6 @@ /area/station/medical/medbay/central) "fiK" = ( /obj/structure/table/glass, -/obj/item/clothing/gloves/latex, -/obj/item/surgical_drapes, /obj/machinery/airalarm/directional/south, /obj/effect/turf_decal/tile/blue/fourcorners, /turf/open/floor/iron/white, @@ -14701,11 +14689,9 @@ /area/station/ai_monitored/aisat/exterior) "fpg" = ( /obj/structure/table/glass, -/obj/item/retractor, -/obj/item/hemostat, -/obj/item/cautery, /obj/effect/turf_decal/tile/blue/fourcorners, /obj/machinery/status_display/evac/directional/west, +/obj/item/surgery_tray/full, /turf/open/floor/iron/white, /area/station/medical/surgery/theatre) "fpj" = ( @@ -55520,12 +55506,6 @@ /area/station/medical/virology) "tOT" = ( /obj/structure/table/glass, -/obj/item/scalpel{ - pixel_y = 12 - }, -/obj/item/circular_saw, -/obj/item/blood_filter, -/obj/item/bonesetter, /obj/machinery/button/door/directional/north{ id = "main_surgery"; name = "privacy shutters control" From 3af37616c90f4ebf7c3139744f946c3115eeca76 Mon Sep 17 00:00:00 2001 From: Rhials <28870487+Rhials@users.noreply.github.com> Date: Thu, 18 Apr 2024 19:53:57 -0400 Subject: [PATCH 336/938] Water tiles now put out burning atoms (#82735) ## About The Pull Request This adds a new "watery tile" element, currently used for (you guessed it) water turfs. This makes a tile extinguish any atom that passes through it. It also makes mobs wet! ![fire test](https://github.com/tgstation/tgstation/assets/28870487/4a19c921-37f3-428d-bb94-0baef7589e1b) This required a minor amount of under-the-hood work regarding firestacks. Essentially, they now get put out when the atom-level `extinguish()` proc is called, as they are now receptive to the `COMSIG_ATOM_EXTINGUISH` signal. ## Why It's Good For The Game It makes sense to me! If I was playing another simulation game and dived into a pool of water on fire, only to remain on fire, I would be very confused and disturbed. Also, it's good for immersion. Get it? Like, because water tiles also have the immerse element? ## Changelog :cl: Rhials qol: Water tiles now extinguish fires on items and people. /:cl: --- code/datums/elements/watery_tile.dm | 21 +++++++++++++++++++ .../status_effects/debuffs/fire_stacks.dm | 1 + code/game/turfs/open/water.dm | 1 + tgstation.dme | 1 + 4 files changed, 24 insertions(+) create mode 100644 code/datums/elements/watery_tile.dm diff --git a/code/datums/elements/watery_tile.dm b/code/datums/elements/watery_tile.dm new file mode 100644 index 0000000000000..797eda39135b4 --- /dev/null +++ b/code/datums/elements/watery_tile.dm @@ -0,0 +1,21 @@ +/datum/element/watery_tile + element_flags = ELEMENT_DETACH_ON_HOST_DESTROY + +/datum/element/watery_tile/Attach(turf/target) + . = ..() + if(!isturf(target)) + return ELEMENT_INCOMPATIBLE + + RegisterSignal(target, COMSIG_ATOM_ENTERED, PROC_REF(extinguish_atom)) + +/datum/element/watery_tile/Detach(turf/source) + UnregisterSignal(source, COMSIG_ATOM_ENTERED) + return ..() + +/datum/element/watery_tile/proc/extinguish_atom(atom/source, atom/movable/entered) + SIGNAL_HANDLER + + entered.extinguish() + if(isliving(entered)) + var/mob/living/our_mob = entered + our_mob.adjust_wet_stacks(3) diff --git a/code/datums/status_effects/debuffs/fire_stacks.dm b/code/datums/status_effects/debuffs/fire_stacks.dm index 5bf8269bbbfda..62f8c9ca24e32 100644 --- a/code/datums/status_effects/debuffs/fire_stacks.dm +++ b/code/datums/status_effects/debuffs/fire_stacks.dm @@ -261,6 +261,7 @@ /datum/status_effect/fire_handler/fire_stacks/on_apply() . = ..() RegisterSignal(owner, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(add_fire_overlay)) + RegisterSignal(owner, COMSIG_ATOM_EXTINGUISH, PROC_REF(extinguish)) owner.update_appearance(UPDATE_OVERLAYS) /datum/status_effect/fire_handler/fire_stacks/proc/add_fire_overlay(mob/living/source, list/overlays) diff --git a/code/game/turfs/open/water.dm b/code/game/turfs/open/water.dm index 3e2cb248f63cb..1be2bc0435f17 100644 --- a/code/game/turfs/open/water.dm +++ b/code/game/turfs/open/water.dm @@ -23,6 +23,7 @@ /turf/open/water/Initialize(mapload) . = ..() AddElement(/datum/element/immerse, icon, icon_state, "immerse", immerse_overlay_color) + AddElement(/datum/element/watery_tile) /turf/open/water/jungle diff --git a/tgstation.dme b/tgstation.dme index b1387a2328279..8690e98059a71 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1512,6 +1512,7 @@ #include "code\datums\elements\wall_smasher.dm" #include "code\datums\elements\wall_tearer.dm" #include "code\datums\elements\wall_walker.dm" +#include "code\datums\elements\watery_tile.dm" #include "code\datums\elements\weapon_description.dm" #include "code\datums\elements\weather_listener.dm" #include "code\datums\elements\web_walker.dm" From 7e5b729284e30a292655b745051b323e861f4416 Mon Sep 17 00:00:00 2001 From: TheRyeGuyWhoWillNowDie <70169560+TheRyeGuyWhoWillNowDie@users.noreply.github.com> Date: Thu, 18 Apr 2024 19:54:19 -0400 Subject: [PATCH 337/938] immortal heart attack fix (#82738) ## About The Pull Request cybernetic hearts no longer permanently break when you die, as they would try to restart after you get revived but then the proc to stop the heart attack would get early returned because the heart is immune to heart attacks ## Why It's Good For The Game having to explode to revive because of surplus heart seems like a bug ## Changelog :cl: fix: being revived with a cyber-heart now properly restarts the cyber heart /:cl: --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> --- code/modules/mob/living/carbon/life.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index b793c6f970123..e5f91b1b1b81a 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -787,7 +787,7 @@ * Returns TRUE if heart status was changed (heart attack -> no heart attack, or visa versa) */ /mob/living/carbon/proc/set_heartattack(status) - if(!can_heartattack()) + if(status && !can_heartattack()) return FALSE var/obj/item/organ/internal/heart/heart = get_organ_slot(ORGAN_SLOT_HEART) From 7df9ee7bfd0f500603a7db083f920d9a157caea2 Mon Sep 17 00:00:00 2001 From: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Date: Fri, 19 Apr 2024 05:26:41 +0530 Subject: [PATCH 338/938] Fixes smart pipe & cryo gas reallocation (#82701) ## About The Pull Request **1. Smart Pipe Problem** - Fill a pipe with any gas, plasma for e.g. - Unwrench the pipe to deconstruct - The pressure sends you flying but notice plasma is nowhere to be seen from the now destroyed pipe **2. Cryo pipe connector problem** The gas gets reallocated when the object is deleted. We only want this when its deconstructed not deleted to prevent any side effects This PR fixes them ## Changelog :cl: fix: smart pipes release their gases into the air when unwrenched fix: cryo pipe connector component has no side effects of gas reallocation when deleted /:cl: --- .../unary_devices/machine_connector.dm | 20 ++++++++++++------- .../atmospherics/machinery/pipes/pipes.dm | 12 +++++------ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/code/modules/atmospherics/machinery/components/unary_devices/machine_connector.dm b/code/modules/atmospherics/machinery/components/unary_devices/machine_connector.dm index dc1c2d6282f0a..157cbae9af0df 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/machine_connector.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/machine_connector.dm @@ -5,14 +5,12 @@ var/obj/machinery/atmospherics/components/unary/gas_connector /datum/gas_machine_connector/New(location, obj/machinery/connecting_machine = null, direction = SOUTH, gas_volume) - gas_connector = new(location) - connected_machine = connecting_machine if(!connected_machine) - QDEL_NULL(gas_connector) qdel(src) return + gas_connector = new(location) gas_connector.dir = connected_machine.dir gas_connector.airs[1].volume = gas_volume @@ -41,7 +39,8 @@ RegisterSignal(connected_machine, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(pre_move_connected_machine)) RegisterSignal(connected_machine, COMSIG_MOVABLE_MOVED, PROC_REF(moved_connected_machine)) RegisterSignal(connected_machine, COMSIG_MACHINERY_DEFAULT_ROTATE_WRENCH, PROC_REF(wrenched_connected_machine)) - RegisterSignal(connected_machine, COMSIG_QDELETING, PROC_REF(deconstruct_connected_machine)) + RegisterSignal(connected_machine, COMSIG_OBJ_DECONSTRUCT, PROC_REF(deconstruct_connected_machine)) + RegisterSignal(connected_machine, COMSIG_QDELETING, PROC_REF(destroy_connected_machine)) /** * Unregister the signals previously registered @@ -51,7 +50,8 @@ COMSIG_MOVABLE_MOVED, COMSIG_MOVABLE_PRE_MOVE, COMSIG_MACHINERY_DEFAULT_ROTATE_WRENCH, - COMSIG_QDELETING, + COMSIG_OBJ_DECONSTRUCT, + COMSIG_QDELETING )) /** @@ -82,12 +82,18 @@ */ /datum/gas_machine_connector/proc/deconstruct_connected_machine() SIGNAL_HANDLER + relocate_airs() + +/** + * Called when the machine has been destroyed + */ +/datum/gas_machine_connector/proc/destroy_connected_machine() + SIGNAL_HANDLER + disconnect_connector() SSair.stop_processing_machine(connected_machine) unregister_from_machine() - connected_machine = null - QDEL_NULL(gas_connector) qdel(src) /** diff --git a/code/modules/atmospherics/machinery/pipes/pipes.dm b/code/modules/atmospherics/machinery/pipes/pipes.dm index 574daa2af3af9..40258db903ff0 100644 --- a/code/modules/atmospherics/machinery/pipes/pipes.dm +++ b/code/modules/atmospherics/machinery/pipes/pipes.dm @@ -35,7 +35,12 @@ AddElement(/datum/element/undertile, TRAIT_T_RAY_VISIBLE) //if changing this, change the subtypes RemoveElements too, because thats how bespoke works /obj/machinery/atmospherics/pipe/on_deconstruction(disassembled) - releaseAirToTurf() + //we delete the parent here so it initializes air_temporary for us. See /datum/pipeline/Destroy() which calls temporarily_store_air() + QDEL_NULL(parent) + + if(air_temporary) + var/turf/T = loc + T.assume_air(air_temporary) return ..() @@ -61,11 +66,6 @@ replace_pipenet(parent, new /datum/pipeline) return list(parent) -/obj/machinery/atmospherics/pipe/proc/releaseAirToTurf() - if(air_temporary) - var/turf/T = loc - T.assume_air(air_temporary) - /obj/machinery/atmospherics/pipe/return_air() if(air_temporary) return air_temporary From e7adfe7dd8adf0d3025c485c013b112b7252d5c8 Mon Sep 17 00:00:00 2001 From: san7890 Date: Thu, 18 Apr 2024 17:57:10 -0600 Subject: [PATCH 339/938] Cleans up some handcuffing code (#82712) ## About The Pull Request I was looking at handcuff code in response to some issue (linking it is irrelevant) and it was just disgusting. I decided to just clean it all up and add a lot of niceities to make it much easier on the eyes. Variable rearrangment, early returns. all those nice things ## Changelog :cl: qol: There's a bit more user feedback when it comes to attempting to handcuff someone. /:cl: --- code/game/objects/items/handcuffs.dm | 82 +++++++++++++++++----------- 1 file changed, 50 insertions(+), 32 deletions(-) diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm index 8db6b3556a07c..259d38119ac15 100644 --- a/code/game/objects/items/handcuffs.dm +++ b/code/game/objects/items/handcuffs.dm @@ -46,11 +46,13 @@ throw_range = 5 custom_materials = list(/datum/material/iron= SMALL_MATERIAL_AMOUNT * 5) breakouttime = 1 MINUTES + armor_type = /datum/armor/restraints_handcuffs + custom_price = PAYCHECK_COMMAND * 0.35 + + ///How long it takes to handcuff someone var/handcuff_time = 4 SECONDS ///Multiplier for handcuff time var/handcuff_time_mod = 1 - armor_type = /datum/armor/restraints_handcuffs - custom_price = PAYCHECK_COMMAND * 0.35 ///Sound that plays when starting to put handcuffs on someone var/cuffsound = 'sound/weapons/handcuffs.ogg' ///If set, handcuffs will be destroyed on application and leave behind whatever this is set to. @@ -70,51 +72,68 @@ fire = 50 acid = 50 -/obj/item/restraints/handcuffs/attack(mob/living/carbon/C, mob/living/user) - if(!istype(C)) +/obj/item/restraints/handcuffs/attack(mob/living/target_mob, mob/living/user) + if(!iscarbon(target_mob)) return - if(SEND_SIGNAL(C, COMSIG_CARBON_CUFF_ATTEMPTED, user) & COMSIG_CARBON_CUFF_PREVENT) + attempt_to_cuff(target_mob, user) // avoid locking up the attack chain with sleeps + +/// Handles all of the checks and application in a typical situation where someone attacks a carbon victim with the handcuff item. +/obj/item/restraints/handcuffs/proc/attempt_to_cuff(mob/living/carbon/victim, mob/living/user) + if(SEND_SIGNAL(victim, COMSIG_CARBON_CUFF_ATTEMPTED, user) & COMSIG_CARBON_CUFF_PREVENT) + victim.balloon_alert(user, "can't be handcuffed!") return if(iscarbon(user) && (HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50))) //Clumsy people have a 50% chance to handcuff themselves instead of their target. to_chat(user, span_warning("Uh... how do those things work?!")) - apply_cuffs(user,user) + apply_cuffs(user, user) return + if(!isnull(victim.handcuffed)) + victim.balloon_alert(user, "already handcuffed!") + return + + if(victim.canBeHandcuffed()) + victim.balloon_alert(user, "can't be handcuffed!") + to_chat(user, span_warning("[victim] doesn't have two hands...")) + return + + victim.visible_message( + span_danger("[user] is trying to put [src] on [victim]!"), + span_userdanger("[user] is trying to put [src] on you!"), + ) + + if(victim.is_blind()) + to_chat(victim, span_userdanger("As you feel someone grab your wrists, [src] start digging into your skin!")) + + playsound(loc, cuffsound, 30, TRUE, -2) + log_combat(user, victim, "attempted to handcuff") + if(HAS_TRAIT(user, TRAIT_FAST_CUFFING)) handcuff_time_mod = 0.75 else handcuff_time_mod = 1 - if(!C.handcuffed) - if(C.canBeHandcuffed()) - C.visible_message(span_danger("[user] is trying to put [src] on [C]!"), \ - span_userdanger("[user] is trying to put [src] on you!")) - if(C.is_blind()) - to_chat(C, span_userdanger("As you feel someone grab your wrists, [src] start digging into your skin!")) - playsound(loc, cuffsound, 30, TRUE, -2) - log_combat(user, C, "attempted to handcuff") - if(do_after(user, handcuff_time * handcuff_time_mod, C, timed_action_flags = IGNORE_SLOWDOWNS) && C.canBeHandcuffed()) - if(iscyborg(user)) - apply_cuffs(C, user, TRUE) - else - apply_cuffs(C, user) - C.visible_message(span_notice("[user] handcuffs [C]."), \ - span_userdanger("[user] handcuffs you.")) - SSblackbox.record_feedback("tally", "handcuffs", 1, type) - - log_combat(user, C, "handcuffed") - else - to_chat(user, span_warning("You fail to handcuff [C]!")) - log_combat(user, C, "failed to handcuff") - else - to_chat(user, span_warning("[C] doesn't have two hands...")) + if(!do_after(user, handcuff_time * handcuff_time_mod, victim, timed_action_flags = IGNORE_SLOWDOWNS) || !victim.canBeHandcuffed()) + victim.balloon_alert(user, "failed to handcuff!") + to_chat(user, span_warning("You fail to handcuff [victim]!")) + log_combat(user, victim, "failed to handcuff") + return + + apply_cuffs(victim, user, dispense = iscyborg(user)) + + victim.visible_message( + span_notice("[user] handcuffs [victim]."), + span_userdanger("[user] handcuffs you."), + ) + + log_combat(user, victim, "successfully handcuffed") + SSblackbox.record_feedback("tally", "handcuffs", 1, type) + /** - * This handles handcuffing people + * When called, this instantly puts handcuffs on someone (if actually possible) * - * When called, this instantly puts handcuffs on someone (if possible) * Arguments: * * mob/living/carbon/target - Who is being handcuffed * * mob/user - Who or what is doing the handcuffing @@ -137,7 +156,6 @@ if(trashtype && !dispense) qdel(src) - return /** * # Alien handcuffs From 46fecee550b730f4ad7f212c7437d2f4399dae74 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 19 Apr 2024 11:57:29 +1200 Subject: [PATCH 340/938] Automatic changelog for PR #82722 [ci skip] --- html/changelogs/AutoChangeLog-pr-82722.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82722.yml diff --git a/html/changelogs/AutoChangeLog-pr-82722.yml b/html/changelogs/AutoChangeLog-pr-82722.yml new file mode 100644 index 0000000000000..47bc6c3d03bf3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82722.yml @@ -0,0 +1,4 @@ +author: "jlsnow301" +delete-after: True +changes: + - bugfix: "Lootpanel additions: Condensed item names for the quick of draw" \ No newline at end of file From cc5a4b18d0216a2a5be4534eeeab7a3a2b79d45d Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 19 Apr 2024 12:01:16 +1200 Subject: [PATCH 341/938] Automatic changelog for PR #82730 [ci skip] --- html/changelogs/AutoChangeLog-pr-82730.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82730.yml diff --git a/html/changelogs/AutoChangeLog-pr-82730.yml b/html/changelogs/AutoChangeLog-pr-82730.yml new file mode 100644 index 0000000000000..fc6c8c296af9e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82730.yml @@ -0,0 +1,4 @@ +author: "starrm4nn" +delete-after: True +changes: + - qol: "Replaced the surgical tools in the Primary Surgery Theatre with 2 Surgery Trays." \ No newline at end of file From 35de3b5391057a05dcaadb8b3913452bfb4b4105 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 19 Apr 2024 12:01:38 +1200 Subject: [PATCH 342/938] Automatic changelog for PR #82735 [ci skip] --- html/changelogs/AutoChangeLog-pr-82735.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82735.yml diff --git a/html/changelogs/AutoChangeLog-pr-82735.yml b/html/changelogs/AutoChangeLog-pr-82735.yml new file mode 100644 index 0000000000000..4a27c16428bbe --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82735.yml @@ -0,0 +1,4 @@ +author: "Rhials" +delete-after: True +changes: + - qol: "Water tiles now extinguish fires on items and people." \ No newline at end of file From 75f19328770250c8cbc166a0675ca4725459e22d Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 19 Apr 2024 12:02:10 +1200 Subject: [PATCH 343/938] Automatic changelog for PR #82738 [ci skip] --- html/changelogs/AutoChangeLog-pr-82738.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82738.yml diff --git a/html/changelogs/AutoChangeLog-pr-82738.yml b/html/changelogs/AutoChangeLog-pr-82738.yml new file mode 100644 index 0000000000000..9e2f299375e08 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82738.yml @@ -0,0 +1,4 @@ +author: "TheRyeGuyWhoWillNowDie" +delete-after: True +changes: + - bugfix: "being revived with a cyber-heart now properly restarts the cyber heart" \ No newline at end of file From 01928044d82e5d2bac8770d0e05fb73749a33d8d Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 19 Apr 2024 12:02:25 +1200 Subject: [PATCH 344/938] Automatic changelog for PR #82701 [ci skip] --- html/changelogs/AutoChangeLog-pr-82701.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82701.yml diff --git a/html/changelogs/AutoChangeLog-pr-82701.yml b/html/changelogs/AutoChangeLog-pr-82701.yml new file mode 100644 index 0000000000000..be4ee4975946d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82701.yml @@ -0,0 +1,5 @@ +author: "SyncIt21" +delete-after: True +changes: + - bugfix: "smart pipes release their gases into the air when unwrenched" + - bugfix: "cryo pipe connector component has no side effects of gas reallocation when deleted" \ No newline at end of file From 89978c1c3908bae40e52d40398543675876ed2e9 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 19 Apr 2024 12:02:45 +1200 Subject: [PATCH 345/938] Automatic changelog for PR #82712 [ci skip] --- html/changelogs/AutoChangeLog-pr-82712.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82712.yml diff --git a/html/changelogs/AutoChangeLog-pr-82712.yml b/html/changelogs/AutoChangeLog-pr-82712.yml new file mode 100644 index 0000000000000..b4cae645e5bd4 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82712.yml @@ -0,0 +1,4 @@ +author: "san7890" +delete-after: True +changes: + - qol: "There's a bit more user feedback when it comes to attempting to handcuff someone." \ No newline at end of file From 153d09e4c4701a4010b27aada7a32dc0b48170a9 Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Thu, 18 Apr 2024 19:23:00 -0500 Subject: [PATCH 346/938] Fix Primal Instincts (#82741) ## About The Pull Request #82539 randomly made these two lines switch their AI controllers to idle rather than on, when the intent was for them to wake up immediately to do make the mob attack or fight or do something ## Changelog :cl: Melbert fix: Primal Instincts and Living Flesh should be a tad more reactive /:cl: --- code/datums/ai/_ai_controller.dm | 5 +---- code/datums/brain_damage/special.dm | 3 ++- code/modules/mob/living/basic/ruin_defender/flesh.dm | 3 +-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/code/datums/ai/_ai_controller.dm b/code/datums/ai/_ai_controller.dm index 436b4912b18cd..7ed49e95a5a77 100644 --- a/code/datums/ai/_ai_controller.dm +++ b/code/datums/ai/_ai_controller.dm @@ -379,10 +379,7 @@ multiple modular subtrees with behaviors switch(ai_status) if(AI_STATUS_ON) START_PROCESSING(SSai_behaviors, src) - if(AI_STATUS_OFF) - STOP_PROCESSING(SSai_behaviors, src) - CancelActions() - if(AI_STATUS_IDLE) + if(AI_STATUS_OFF, AI_STATUS_IDLE) STOP_PROCESSING(SSai_behaviors, src) CancelActions() diff --git a/code/datums/brain_damage/special.dm b/code/datums/brain_damage/special.dm index 5b8666413e30f..1bf011e0fab49 100644 --- a/code/datums/brain_damage/special.dm +++ b/code/datums/brain_damage/special.dm @@ -491,6 +491,7 @@ owner.ai_controller = new /datum/ai_controller/monkey(owner) owner.ai_controller.continue_processing_when_client = TRUE + owner.ai_controller.can_idle = FALSE owner.ai_controller.set_ai_status(AI_STATUS_OFF) /datum/brain_trauma/special/primal_instincts/on_lose(silent) @@ -514,7 +515,7 @@ owner.grant_language(/datum/language/monkey, UNDERSTOOD_LANGUAGE, TRAUMA_TRAIT) owner.ai_controller.set_blackboard_key(BB_MONKEY_AGGRESSIVE, prob(75)) if(owner.ai_controller.ai_status == AI_STATUS_OFF) - owner.ai_controller.set_ai_status(AI_STATUS_IDLE) + owner.ai_controller.set_ai_status(AI_STATUS_ON) owner.log_message("became controlled by monkey instincts ([owner.ai_controller.blackboard[BB_MONKEY_AGGRESSIVE] ? "aggressive" : "docile"])", LOG_ATTACK, color = "orange") to_chat(owner, span_warning("You feel the urge to act on your primal instincts...")) // extend original timer if we roll the effect while it's already ongoing diff --git a/code/modules/mob/living/basic/ruin_defender/flesh.dm b/code/modules/mob/living/basic/ruin_defender/flesh.dm index 6524e6fd9d4f4..6f46e69070038 100644 --- a/code/modules/mob/living/basic/ruin_defender/flesh.dm +++ b/code/modules/mob/living/basic/ruin_defender/flesh.dm @@ -178,7 +178,6 @@ /mob/living/basic/living_limb_flesh/proc/wake_up(atom/limb) visible_message(span_warning("[src] begins flailing around!")) Shake(6, 6, 0.5 SECONDS) - ai_controller.set_ai_status(AI_STATUS_IDLE) + ai_controller.set_ai_status(AI_STATUS_ON) forceMove(limb.drop_location()) qdel(limb) - From 35ce2bacfe3c8dd30ea0e0b1bd9c48587775b6eb Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 19 Apr 2024 12:36:43 +1200 Subject: [PATCH 347/938] Automatic changelog for PR #82741 [ci skip] --- html/changelogs/AutoChangeLog-pr-82741.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82741.yml diff --git a/html/changelogs/AutoChangeLog-pr-82741.yml b/html/changelogs/AutoChangeLog-pr-82741.yml new file mode 100644 index 0000000000000..8cbfb39702409 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82741.yml @@ -0,0 +1,4 @@ +author: "Melbert" +delete-after: True +changes: + - bugfix: "Primal Instincts and Living Flesh should be a tad more reactive" \ No newline at end of file From 1134a470a24762097de42e9d629f03bc2075697f Mon Sep 17 00:00:00 2001 From: Changelogs Date: Fri, 19 Apr 2024 00:36:49 +0000 Subject: [PATCH 348/938] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-82561.yml | 5 --- html/changelogs/AutoChangeLog-pr-82594.yml | 4 -- html/changelogs/AutoChangeLog-pr-82625.yml | 4 -- html/changelogs/AutoChangeLog-pr-82701.yml | 5 --- html/changelogs/AutoChangeLog-pr-82703.yml | 6 --- html/changelogs/AutoChangeLog-pr-82712.yml | 4 -- html/changelogs/AutoChangeLog-pr-82714.yml | 4 -- html/changelogs/AutoChangeLog-pr-82719.yml | 4 -- html/changelogs/AutoChangeLog-pr-82722.yml | 4 -- html/changelogs/AutoChangeLog-pr-82723.yml | 4 -- html/changelogs/AutoChangeLog-pr-82730.yml | 4 -- html/changelogs/AutoChangeLog-pr-82735.yml | 4 -- html/changelogs/AutoChangeLog-pr-82738.yml | 4 -- html/changelogs/AutoChangeLog-pr-82750.yml | 4 -- html/changelogs/AutoChangeLog-pr-82755.yml | 4 -- html/changelogs/archive/2024-04.yml | 44 ++++++++++++++++++++++ 16 files changed, 44 insertions(+), 64 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-82561.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82594.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82625.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82701.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82703.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82712.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82714.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82719.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82722.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82723.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82730.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82735.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82738.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82750.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82755.yml diff --git a/html/changelogs/AutoChangeLog-pr-82561.yml b/html/changelogs/AutoChangeLog-pr-82561.yml deleted file mode 100644 index 5991984855b5f..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82561.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Jacquerel" -delete-after: True -changes: - - balance: "Gulag mining has been rebalanced so that every boulder is worth the same amount of points to mine for a prisoner regardless of what it contains, and should be more consistent." - - rscadd: "A vent which boulders can be hauled out of by hand has been added to the gulag which you can use if there's nothing left to mine. It is very slow, but at least it gives you a workout..." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82594.yml b/html/changelogs/AutoChangeLog-pr-82594.yml deleted file mode 100644 index 10f6315726f98..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82594.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SyncIt21" -delete-after: True -changes: - - code_imp: "most cell power usages are scaled with defined constants to help adapt to future changes" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82625.yml b/html/changelogs/AutoChangeLog-pr-82625.yml deleted file mode 100644 index 85cbe1e270bb9..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82625.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Melbert" -delete-after: True -changes: - - refactor: "Atom-Item interactions have been refactored once more. Report any oddities." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82701.yml b/html/changelogs/AutoChangeLog-pr-82701.yml deleted file mode 100644 index be4ee4975946d..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82701.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "SyncIt21" -delete-after: True -changes: - - bugfix: "smart pipes release their gases into the air when unwrenched" - - bugfix: "cryo pipe connector component has no side effects of gas reallocation when deleted" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82703.yml b/html/changelogs/AutoChangeLog-pr-82703.yml deleted file mode 100644 index 086097bdb5f6b..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82703.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "Melbert" -delete-after: True -changes: - - rscadd: "Being deafnened from a loud sound (flashbang, explosions) will now force people not naturally deaf to shout" - - rscadd: "Ear damage multiplier now only applies to taking damage, not healing damage, meaning Felinids (who take 2x the ear damage) will no longer heal ear damage 2x faster." - - refactor: "Ears have been refactored slightly, ear deafness should now update more snappily" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82712.yml b/html/changelogs/AutoChangeLog-pr-82712.yml deleted file mode 100644 index b4cae645e5bd4..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82712.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "san7890" -delete-after: True -changes: - - qol: "There's a bit more user feedback when it comes to attempting to handcuff someone." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82714.yml b/html/changelogs/AutoChangeLog-pr-82714.yml deleted file mode 100644 index adb6abee7e23f..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82714.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "jlsnow301" -delete-after: True -changes: - - bugfix: "TGUI Alerts shouldn't have such wonky buttons any more" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82719.yml b/html/changelogs/AutoChangeLog-pr-82719.yml deleted file mode 100644 index 6717e0acb6ffe..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82719.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Iajret" -delete-after: True -changes: - - bugfix: "cooling and anti-disruption RCD upgrades can now be printed in ancient protolathes" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82722.yml b/html/changelogs/AutoChangeLog-pr-82722.yml deleted file mode 100644 index 47bc6c3d03bf3..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82722.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "jlsnow301" -delete-after: True -changes: - - bugfix: "Lootpanel additions: Condensed item names for the quick of draw" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82723.yml b/html/changelogs/AutoChangeLog-pr-82723.yml deleted file mode 100644 index fb612dc0f7cba..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82723.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "jlsnow301" -delete-after: True -changes: - - rscdel: "Due to a need for company restructuring, virologists have been laid off by CentCom and doctors can optionally take their place." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82730.yml b/html/changelogs/AutoChangeLog-pr-82730.yml deleted file mode 100644 index fc6c8c296af9e..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82730.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "starrm4nn" -delete-after: True -changes: - - qol: "Replaced the surgical tools in the Primary Surgery Theatre with 2 Surgery Trays." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82735.yml b/html/changelogs/AutoChangeLog-pr-82735.yml deleted file mode 100644 index 4a27c16428bbe..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82735.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Rhials" -delete-after: True -changes: - - qol: "Water tiles now extinguish fires on items and people." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82738.yml b/html/changelogs/AutoChangeLog-pr-82738.yml deleted file mode 100644 index 9e2f299375e08..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82738.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "TheRyeGuyWhoWillNowDie" -delete-after: True -changes: - - bugfix: "being revived with a cyber-heart now properly restarts the cyber heart" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82750.yml b/html/changelogs/AutoChangeLog-pr-82750.yml deleted file mode 100644 index 6084c57ffb345..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82750.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Watermelon914" -delete-after: True -changes: - - bugfix: "Fixed RnD consoles not being able to be opened." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82755.yml b/html/changelogs/AutoChangeLog-pr-82755.yml deleted file mode 100644 index d98d4d32d3e9a..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82755.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "jlsnow301" -delete-after: True -changes: - - bugfix: "Fixed a bluescreen in cargo console" \ No newline at end of file diff --git a/html/changelogs/archive/2024-04.yml b/html/changelogs/archive/2024-04.yml index 9ddd89baabc43..2cf63316d909b 100644 --- a/html/changelogs/archive/2024-04.yml +++ b/html/changelogs/archive/2024-04.yml @@ -593,3 +593,47 @@ san7890: - rscadd: Regal Rats are now able to tear down those colorful posters those weird grey creatures keep spackling up on the walls of their rightful domain. +2024-04-19: + Iajret: + - bugfix: cooling and anti-disruption RCD upgrades can now be printed in ancient + protolathes + Jacquerel: + - balance: Gulag mining has been rebalanced so that every boulder is worth the same + amount of points to mine for a prisoner regardless of what it contains, and + should be more consistent. + - rscadd: A vent which boulders can be hauled out of by hand has been added to the + gulag which you can use if there's nothing left to mine. It is very slow, but + at least it gives you a workout... + Melbert: + - refactor: Atom-Item interactions have been refactored once more. Report any oddities. + - rscadd: Being deafnened from a loud sound (flashbang, explosions) will now force + people not naturally deaf to shout + - rscadd: Ear damage multiplier now only applies to taking damage, not healing damage, + meaning Felinids (who take 2x the ear damage) will no longer heal ear damage + 2x faster. + - refactor: Ears have been refactored slightly, ear deafness should now update more + snappily + Rhials: + - qol: Water tiles now extinguish fires on items and people. + SyncIt21: + - code_imp: most cell power usages are scaled with defined constants to help adapt + to future changes + - bugfix: smart pipes release their gases into the air when unwrenched + - bugfix: cryo pipe connector component has no side effects of gas reallocation + when deleted + TheRyeGuyWhoWillNowDie: + - bugfix: being revived with a cyber-heart now properly restarts the cyber heart + Watermelon914: + - bugfix: Fixed RnD consoles not being able to be opened. + jlsnow301: + - rscdel: Due to a need for company restructuring, virologists have been laid off + by CentCom and doctors can optionally take their place. + - bugfix: TGUI Alerts shouldn't have such wonky buttons any more + - bugfix: Fixed a bluescreen in cargo console + - bugfix: 'Lootpanel additions: Condensed item names for the quick of draw' + san7890: + - qol: There's a bit more user feedback when it comes to attempting to handcuff + someone. + starrm4nn: + - qol: Replaced the surgical tools in the Primary Surgery Theatre with 2 Surgery + Trays. From 17455d7db4f88242329a6a2dead4065d919cd1fa Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Thu, 18 Apr 2024 21:01:14 -0500 Subject: [PATCH 349/938] Fix handcuffing (#82760) ## About The Pull Request Changed this to an early return but then didn't invert the condition ## Changelog :cl: Melbert fix: You can handcuff people with 2 arms and you can no longer handcuff people with 0 arms /:cl: --- code/game/objects/items/handcuffs.dm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm index 259d38119ac15..1d8adbbb27854 100644 --- a/code/game/objects/items/handcuffs.dm +++ b/code/game/objects/items/handcuffs.dm @@ -76,7 +76,7 @@ if(!iscarbon(target_mob)) return - attempt_to_cuff(target_mob, user) // avoid locking up the attack chain with sleeps + attempt_to_cuff(target_mob, user) /// Handles all of the checks and application in a typical situation where someone attacks a carbon victim with the handcuff item. /obj/item/restraints/handcuffs/proc/attempt_to_cuff(mob/living/carbon/victim, mob/living/user) @@ -93,9 +93,8 @@ victim.balloon_alert(user, "already handcuffed!") return - if(victim.canBeHandcuffed()) + if(!victim.canBeHandcuffed()) victim.balloon_alert(user, "can't be handcuffed!") - to_chat(user, span_warning("[victim] doesn't have two hands...")) return victim.visible_message( From d03d1997d044fbb251e8ba8b4ac6e462a1b9c553 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 19 Apr 2024 14:01:34 +1200 Subject: [PATCH 350/938] Automatic changelog for PR #82760 [ci skip] --- html/changelogs/AutoChangeLog-pr-82760.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82760.yml diff --git a/html/changelogs/AutoChangeLog-pr-82760.yml b/html/changelogs/AutoChangeLog-pr-82760.yml new file mode 100644 index 0000000000000..df34c5d5ea760 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82760.yml @@ -0,0 +1,4 @@ +author: "Melbert" +delete-after: True +changes: + - bugfix: "You can handcuff people with 2 arms and you can no longer handcuff people with 0 arms" \ No newline at end of file From a1abccc6123a09c43d02d2c6006d5c48d54427b4 Mon Sep 17 00:00:00 2001 From: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com> Date: Fri, 19 Apr 2024 04:27:04 +0200 Subject: [PATCH 351/938] makes slimes not idle (#82742) ## About The Pull Request slimes should still be able to do their everyday routine without needing to be watched over ## Why It's Good For The Game makes xenobiologist's lives easier ## Changelog :cl: qol: slimes will stay active without needing any one to watch over /:cl: --- code/datums/ai/_ai_controller.dm | 4 +++- code/modules/mob/living/basic/slime/ai/controller.dm | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/code/datums/ai/_ai_controller.dm b/code/datums/ai/_ai_controller.dm index 7ed49e95a5a77..f79ddd5f60615 100644 --- a/code/datums/ai/_ai_controller.dm +++ b/code/datums/ai/_ai_controller.dm @@ -145,6 +145,8 @@ multiple modular subtrees with behaviors set_new_cells() /datum/ai_controller/proc/set_new_cells() + if(isnull(our_cells)) + return var/turf/our_turf = get_turf(pawn) @@ -163,7 +165,7 @@ multiple modular subtrees with behaviors recalculate_idle() /datum/ai_controller/proc/should_idle() - if(!can_idle) + if(!can_idle || isnull(our_cells)) return FALSE for(var/datum/spatial_grid_cell/grid as anything in our_cells.member_cells) if(length(grid.client_contents)) diff --git a/code/modules/mob/living/basic/slime/ai/controller.dm b/code/modules/mob/living/basic/slime/ai/controller.dm index 9ecf66ad74472..41466b2973498 100644 --- a/code/modules/mob/living/basic/slime/ai/controller.dm +++ b/code/modules/mob/living/basic/slime/ai/controller.dm @@ -19,6 +19,7 @@ /datum/ai_planning_subtree/basic_melee_attack_subtree/slime, /datum/ai_planning_subtree/random_speech/slime, ) + can_idle = FALSE /datum/ai_controller/basic_controller/slime/CancelActions() ..() From c857110e6895d0e5b171d89c57ed9ef99a103212 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 19 Apr 2024 14:27:23 +1200 Subject: [PATCH 352/938] Automatic changelog for PR #82742 [ci skip] --- html/changelogs/AutoChangeLog-pr-82742.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82742.yml diff --git a/html/changelogs/AutoChangeLog-pr-82742.yml b/html/changelogs/AutoChangeLog-pr-82742.yml new file mode 100644 index 0000000000000..4e3cc8b78cb32 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82742.yml @@ -0,0 +1,4 @@ +author: "Ben10Omintrix" +delete-after: True +changes: + - qol: "slimes will stay active without needing any one to watch over" \ No newline at end of file From e51a1f95d28378768fba5e4bceab6cba7edd5fbe Mon Sep 17 00:00:00 2001 From: Zephyr <12817816+ZephyrTFA@users.noreply.github.com> Date: Thu, 18 Apr 2024 22:34:41 -0400 Subject: [PATCH 353/938] Controller Overview UI (#82739) --- code/controllers/master.dm | 79 +++++- .../tgui/interfaces/ControllerOverview.tsx | 245 ++++++++++++++++++ 2 files changed, 321 insertions(+), 3 deletions(-) create mode 100644 tgui/packages/tgui/interfaces/ControllerOverview.tsx diff --git a/code/controllers/master.dm b/code/controllers/master.dm index ac12add1ae2d5..f58ccc7c8f4d6 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -76,6 +76,9 @@ GLOBAL_REAL(Master, /datum/controller/master) ///used by CHECK_TICK as well so that the procs subsystems call can obey that SS's tick limits var/static/current_ticklimit = TICK_LIMIT_RUNNING + /// Whether the Overview UI will update as fast as possible for viewers. + var/overview_fast_update = FALSE + /datum/controller/master/New() if(!config) config = new @@ -135,6 +138,78 @@ GLOBAL_REAL(Master, /datum/controller/master) ss.Shutdown() log_world("Shutdown complete") +ADMIN_VERB(cmd_controller_view_ui, R_SERVER|R_DEBUG, "Controller Overview", "View the current states of the Subsystem Controllers.", ADMIN_CATEGORY_SERVER) + Master.ui_interact(user.mob) + +/datum/controller/master/ui_status(mob/user, datum/ui_state/state) + if(!user.client?.holder?.check_for_rights(R_SERVER|R_DEBUG)) + return UI_CLOSE + return UI_INTERACTIVE + +/datum/controller/master/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(isnull(ui)) + ui = new /datum/tgui(user, src, "ControllerOverview") + ui.open() + +/datum/controller/master/ui_data(mob/user) + var/list/data = list() + + var/list/subsystem_data = list() + for(var/datum/controller/subsystem/subsystem as anything in subsystems) + subsystem_data += list(list( + "name" = subsystem.name, + "ref" = REF(subsystem), + "init_order" = subsystem.init_order, + "last_fire" = subsystem.last_fire, + "next_fire" = subsystem.next_fire, + "can_fire" = subsystem.can_fire, + "doesnt_fire" = !!(subsystem.flags & SS_NO_FIRE), + "cost_ms" = subsystem.cost, + "tick_usage" = subsystem.tick_usage, + "tick_overrun" = subsystem.tick_overrun, + "initialized" = subsystem.initialized, + "initialization_failure_message" = subsystem.initialization_failure_message, + )) + data["subsystems"] = subsystem_data + data["world_time"] = world.time + data["map_cpu"] = world.map_cpu + data["fast_update"] = overview_fast_update + + return data + +/datum/controller/master/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + if(..()) + return TRUE + + switch(action) + if("toggle_fast_update") + overview_fast_update = !overview_fast_update + return TRUE + + if("view_variables") + var/datum/controller/subsystem/subsystem = locate(params["ref"]) in subsystems + if(isnull(subsystem)) + to_chat(ui.user, span_warning("Failed to locate subsystem.")) + return + SSadmin_verbs.dynamic_invoke_verb(ui.user, /datum/admin_verb/debug_variables, subsystem) + return TRUE + +/datum/controller/master/proc/check_and_perform_fast_update() + PRIVATE_PROC(TRUE) + set waitfor = FALSE + + + if(!overview_fast_update) + return + + var/static/already_updating = FALSE + if(already_updating) + return + already_updating = TRUE + SStgui.update_uis(src) + already_updating = FALSE + // Returns 1 if we created a new mc, 0 if we couldn't due to a recent restart, // -1 if we encountered a runtime trying to recreate it /proc/Recreate_MC() @@ -578,11 +653,9 @@ GLOBAL_REAL(Master, /datum/controller/master) if (processing * sleep_delta <= world.tick_lag) current_ticklimit -= (TICK_LIMIT_RUNNING * 0.25) //reserve the tail 1/4 of the next tick for the mc if we plan on running next tick + check_and_perform_fast_update() sleep(world.tick_lag * (processing * sleep_delta)) - - - // This is what decides if something should run. /datum/controller/master/proc/CheckQueue(list/subsystemstocheck) . = 0 //so the mc knows if we runtimed diff --git a/tgui/packages/tgui/interfaces/ControllerOverview.tsx b/tgui/packages/tgui/interfaces/ControllerOverview.tsx new file mode 100644 index 0000000000000..5b5c210b7bbfd --- /dev/null +++ b/tgui/packages/tgui/interfaces/ControllerOverview.tsx @@ -0,0 +1,245 @@ +import { BooleanLike } from 'common/react'; +import { createSearch } from 'common/string'; +import { useMemo, useState } from 'react'; + +import { useBackend } from '../backend'; +import { + Button, + Collapsible, + Dropdown, + Input, + LabeledList, + Section, + Stack, +} from '../components'; +import { Window } from '../layouts'; + +type SubsystemData = { + name: string; + ref: string; + init_order: number; + last_fire: number; + next_fire: number; + can_fire: BooleanLike; + doesnt_fire: BooleanLike; + cost_ms: number; + tick_usage: number; + tick_overrun: number; + initialized: BooleanLike; + initialization_failure_message: string | undefined; +}; + +type ControllerData = { + world_time: number; + fast_update: BooleanLike; + map_cpu: number; + subsystems: SubsystemData[]; +}; + +const SubsystemView = (props: { data: SubsystemData }) => { + const { act } = useBackend(); + const { data } = props; + const { + name, + ref, + init_order, + last_fire, + next_fire, + can_fire, + doesnt_fire, + cost_ms, + tick_usage, + tick_overrun, + initialized, + initialization_failure_message, + } = data; + + let icon = 'play'; + if (!initialized) { + icon = 'circle-exclamation'; + } else if (doesnt_fire) { + icon = 'check'; + } else if (!can_fire) { + icon = 'pause'; + } + + return ( + { + act('view_variables', { ref: ref }); + }} + /> + } + > + + {init_order} + {last_fire} + {next_fire} + {cost_ms}ms + + {(tick_usage * 0.01).toFixed(2)}% + + + {(tick_overrun * 0.01).toFixed(2)}% + + {initialization_failure_message ? ( + + {initialization_failure_message} + + ) : undefined} + + + ); +}; + +enum SubsystemSortBy { + INIT_ORDER = 'Init Order', + NAME = 'Name', + LAST_FIRE = 'Last Fire', + NEXT_FIRE = 'Next Fire', + TICK_USAGE = 'Tick Usage', + TICK_OVERRUN = 'Tick Overrun', + COST = 'Cost', +} + +const sortSubsystemBy = ( + subsystems: SubsystemData[], + sortBy: SubsystemSortBy, + asending: boolean = true, +) => { + let sorted = subsystems.sort((left, right) => { + switch (sortBy) { + case SubsystemSortBy.INIT_ORDER: + return left.init_order - right.init_order; + case SubsystemSortBy.NAME: + return left.name.localeCompare(right.name); + case SubsystemSortBy.LAST_FIRE: + return left.last_fire - right.last_fire; + case SubsystemSortBy.NEXT_FIRE: + return left.next_fire - right.next_fire; + case SubsystemSortBy.TICK_USAGE: + return left.tick_usage - right.tick_usage; + case SubsystemSortBy.TICK_OVERRUN: + return left.tick_overrun - right.tick_overrun; + case SubsystemSortBy.COST: + return left.cost_ms - right.cost_ms; + } + }); + if (!asending) { + sorted.reverse(); + } + return sorted; +}; + +export const ControllerOverview = () => { + const { act, data } = useBackend(); + const { world_time, map_cpu, subsystems, fast_update } = data; + + const [filterName, setFilterName] = useState(''); + const [sortBy, setSortBy] = useState(SubsystemSortBy.NAME); + const [sortAscending, setSortAscending] = useState(true); + + let filteredSubsystems = useMemo(() => { + if (!filterName) { + return subsystems; + } + + return subsystems.filter(() => + createSearch(filterName, (subsystem: SubsystemData) => subsystem.name), + ); + }, [filterName, subsystems]); + + let sortedSubsystems = useMemo(() => { + return sortSubsystemBy(filteredSubsystems, sortBy, sortAscending); + }, [sortBy, sortAscending, filteredSubsystems]); + + const overallUsage = subsystems.reduce( + (acc, subsystem) => acc + subsystem.tick_usage, + 0, + ); + const overallOverrun = subsystems.reduce( + (acc, subsystem) => acc + subsystem.tick_overrun, + 0, + ); + + return ( + + +
    + + World Time: {world_time} + Map CPU: {map_cpu.toFixed(2)}% + + Overall Usage: {(overallUsage * 0.01).toFixed(2)}% + + + Overall Overrun: {(overallOverrun * 0.01).toFixed(2)}% + + +
    +
    { + act('toggle_fast_update'); + }} + /> + } + > + setFilterName(value)} + /> + + + + + + +
    +
    + + {sortedSubsystems.map((subsystem) => ( + + ))} + +
    +
    +
    + ); +}; From 15bea6378434ca947dc16f82b2309c167a064eee Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 19 Apr 2024 14:35:01 +1200 Subject: [PATCH 354/938] Automatic changelog for PR #82739 [ci skip] --- html/changelogs/AutoChangeLog-pr-82739.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82739.yml diff --git a/html/changelogs/AutoChangeLog-pr-82739.yml b/html/changelogs/AutoChangeLog-pr-82739.yml new file mode 100644 index 0000000000000..8e0665422ec5b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82739.yml @@ -0,0 +1,4 @@ +author: "ZephyrTFA" +delete-after: True +changes: + - admin: "Controller Overview UI. Check the Server Tab." \ No newline at end of file From 72f4ff7f49eba36800d81d4bf491418f49159b47 Mon Sep 17 00:00:00 2001 From: san7890 Date: Thu, 18 Apr 2024 21:53:33 -0600 Subject: [PATCH 355/938] Gets rid of UNIT_TESTS compiler warning (#82695) ## About The Pull Request Basically every single CI Run is throwing the following warning: ```txt code/modules/unit_tests/lootpanel.dm:24:warning (unused_var): new_box: variable defined but not used ``` You may find an example here: https://github.com/tgstation/tgstation/actions/runs/8698627681/job/23855921813#step:9:24 This is pretty silly but I don't really know why we even have this variable (I assume there's something far more complicated underneath the surface based on what the unit test is asserting), but assuming it is important let's just insert a do-nothing procedure to get rid of the compiler warning while ensuring the unit test is actually operating as it should. I also don't really like the fact that this is a warning instead of an error but let's tackle this problem one step at a time by at least getting rid of the compiler warning in a quick advance PR while I dwell on this issue (is there a way to get the Dreamchecker linter to look at the unit test files? it's caught perfectly fine in the langserver) --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> --- code/modules/unit_tests/lootpanel.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/unit_tests/lootpanel.dm b/code/modules/unit_tests/lootpanel.dm index c0bec13288cb0..1903c22d54652 100644 --- a/code/modules/unit_tests/lootpanel.dm +++ b/code/modules/unit_tests/lootpanel.dm @@ -21,7 +21,7 @@ TEST_ASSERT_EQUAL(length(panel.contents), 1, "Contents should update on searchobj deleted") TEST_ASSERT_EQUAL(length(panel.to_image), 1, "to_image should update on searchobj deleted") - var/obj/item/storage/toolbox/new_box = allocate(/obj/item/storage/toolbox, one_over) + allocate(/obj/item/storage/toolbox, one_over) TEST_ASSERT_EQUAL(length(panel.contents), 1, "Contents shouldn't update, we're dumb") TEST_ASSERT_EQUAL(length(panel.to_image), 1, "to_image shouldn't update, we're dumb") @@ -32,3 +32,4 @@ TEST_ASSERT_EQUAL(length(panel.contents), 2, "Panel shouldnt dupe searchables if reopened") mock_client.mob = null + From f81f52aa3ef55a0be47de43b6bc75f38eaa2c3b6 Mon Sep 17 00:00:00 2001 From: Jeremiah <42397676+jlsnow301@users.noreply.github.com> Date: Thu, 18 Apr 2024 21:07:28 -0700 Subject: [PATCH 356/938] Makes dropdowns better (#82697) ## About The Pull Request Kind of a pain to work with, confusing people with its prop names (many such cases!) After recently discovering deathmatch it's very obvious to me how broken it is, so I made it less so (now comes with a complete ui upgrade!) It now scrolls with the selection and to the selection on open, which felt like major QoL
    pics/vids In motion ![7627sWJ2nS](https://github.com/tgstation/tgstation/assets/42397676/982427b2-6dc8-4c91-90cf-6e17d211f5ae) Deathmatch got some UI facelifts ![GAotCHxtZg](https://github.com/tgstation/tgstation/assets/42397676/769317ad-7a9f-410a-a60f-4ddfb377210c) ![Ca2UJSpxlY](https://github.com/tgstation/tgstation/assets/42397676/ea188cda-a79b-4ca0-9209-1c69f57231dc) Fixes #75741 ![image](https://github.com/tgstation/tgstation/assets/42397676/d30a1ae4-cf08-4512-9ce6-5499084647b4)
    ## Why It's Good For The Game Better UX Bug fixes Potential exploit patched (ui validation for ai voice changer) Fixes #81506 ## Changelog :cl: fix: Dropdowns received some much-needed QoL, like having the scrollbar follow your selection. fix: AI voice changer now shows its current voice selection. fix: Deathmatch screen has been touched up. fix: Prefs menu has their dropdowns simplified, hopefully fixing issues /:cl: --------- Co-authored-by: san7890 --- .../antagonists/malf_ai/malf_ai_modules.dm | 21 +- tgui/packages/tgui/components/Dropdown.tsx | 206 ++++---- tgui/packages/tgui/interfaces/AdminFax.jsx | 5 +- tgui/packages/tgui/interfaces/AdminPDA.jsx | 3 +- .../tgui/interfaces/AiVoiceChanger.tsx | 36 +- tgui/packages/tgui/interfaces/Changelog.jsx | 4 +- .../tgui/interfaces/CircuitModule.jsx | 2 +- .../tgui/interfaces/CircuitSignalHandler.tsx | 2 +- .../tgui/interfaces/CommandReport.tsx | 4 +- .../tgui/interfaces/DeathmatchLobby.tsx | 468 +++++++++++------- .../tgui/interfaces/DeathmatchPanel.jsx | 95 ---- .../tgui/interfaces/DeathmatchPanel.tsx | 162 ++++++ .../IntegratedCircuit/ComponentMenu.jsx | 3 +- .../IntegratedCircuit/FundamentalTypes.jsx | 2 +- .../IntegratedCircuit/VariableMenu.jsx | 4 +- .../tgui/interfaces/LibraryConsole.jsx | 2 +- tgui/packages/tgui/interfaces/MODsuit.tsx | 2 +- tgui/packages/tgui/interfaces/MineBot.tsx | 2 +- tgui/packages/tgui/interfaces/NavBeacon.tsx | 8 +- tgui/packages/tgui/interfaces/NtosCard.tsx | 3 +- .../tgui/interfaces/NtosRoboControl.jsx | 26 +- .../packages/tgui/interfaces/NtosScipaper.jsx | 8 +- .../tgui/interfaces/NtosVirtualPet.tsx | 6 +- .../tgui/interfaces/PlaneMasterDebug.tsx | 1 - .../interfaces/PreferencesMenu/JobsPage.tsx | 11 +- .../PreferencesMenu/RandomizationButton.tsx | 5 +- .../preferences/features/base.tsx | 143 +----- .../character_preferences/ai_core_display.tsx | 3 +- .../ai_emote_display.tsx | 2 +- .../ai_hologram_display.tsx | 2 +- .../character_preferences/body_type.tsx | 3 +- .../character_preferences/food_allergy.tsx | 3 +- .../character_preferences/glasses.tsx | 2 +- .../character_preferences/hemiplegic.tsx | 3 +- .../features/character_preferences/junkie.tsx | 3 +- .../character_preferences/language.tsx | 3 +- .../features/character_preferences/pda.tsx | 8 +- .../features/character_preferences/phobia.tsx | 3 +- .../character_preferences/pride_pin.tsx | 3 +- .../character_preferences/prisoner_crime.tsx | 3 +- .../character_preferences/prosthetic_limb.tsx | 3 +- .../prosthetic_organ.tsx | 3 +- .../security_department.tsx | 3 +- .../character_preferences/skin_tone.tsx | 78 +-- .../trans_prosthetic.tsx | 3 +- .../character_preferences/tts_voice.tsx | 2 +- .../character_preferences/uplink_loc.tsx | 3 +- .../preferences/features/dropdowns.tsx | 103 ++++ .../features/game_preferences/admin.tsx | 2 +- .../features/game_preferences/ghost.tsx | 5 +- .../game_preferences/ghost_lighting.tsx | 3 +- .../features/game_preferences/mod_select.tsx | 3 +- .../features/game_preferences/parallax.tsx | 3 +- .../game_preferences/preferred_map.tsx | 3 +- .../features/game_preferences/screentips.tsx | 2 +- .../features/game_preferences/sounds.tsx | 2 +- .../features/game_preferences/ui_style.tsx | 1 - .../preferences/features/species_features.tsx | 2 +- .../packages/tgui/interfaces/ProcCallMenu.tsx | 4 +- .../RequestsConsole/MessageWriteTab.tsx | 6 +- .../tgui/interfaces/StationTraitsPanel.tsx | 4 +- .../tgui/interfaces/TramController.tsx | 2 +- 62 files changed, 855 insertions(+), 660 deletions(-) delete mode 100644 tgui/packages/tgui/interfaces/DeathmatchPanel.jsx create mode 100644 tgui/packages/tgui/interfaces/DeathmatchPanel.tsx create mode 100644 tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dropdowns.tsx diff --git a/code/modules/antagonists/malf_ai/malf_ai_modules.dm b/code/modules/antagonists/malf_ai/malf_ai_modules.dm index db1c53d3a17c0..1ef00b9a298cf 100644 --- a/code/modules/antagonists/malf_ai/malf_ai_modules.dm +++ b/code/modules/antagonists/malf_ai/malf_ai_modules.dm @@ -945,6 +945,8 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) var/prev_verbs /// Saved span state, used to restore after a voice change var/prev_span + /// The list of available voices + var/static/list/voice_options = list("normal", SPAN_ROBOT, SPAN_YELL, SPAN_CLOWN) /obj/machinery/ai_voicechanger/Initialize(mapload) . = ..() @@ -972,11 +974,12 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) /obj/machinery/ai_voicechanger/ui_data(mob/user) var/list/data = list() - data["voices"] = list("normal", SPAN_ROBOT, SPAN_YELL, SPAN_CLOWN) //manually adding this since i dont see other option + data["voices"] = voice_options data["loud"] = loudvoice data["on"] = changing_voice data["say_verb"] = say_verb data["name"] = say_name + data["selected"] = say_span || owner.speech_span return data /obj/machinery/ai_voicechanger/ui_act(action, params) @@ -1010,9 +1013,23 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) if(changing_voice) owner.radio.use_command = loudvoice if("look") - say_span = params["look"] + var/selection = params["look"] + if(isnull(selection)) + return FALSE + + var/found = FALSE + for(var/option in voice_options) + if(option == selection) + found = TRUE + break + if(!found) + stack_trace("User attempted to select an unavailable voice option") + return FALSE + + say_span = selection if(changing_voice) owner.speech_span = say_span + to_chat(usr, span_notice("Voice set to [selection].")) if("verb") say_verb = params["verb"] if(changing_voice) diff --git a/tgui/packages/tgui/components/Dropdown.tsx b/tgui/packages/tgui/components/Dropdown.tsx index a103a7466d3f5..1cf2b53ecfdc2 100644 --- a/tgui/packages/tgui/components/Dropdown.tsx +++ b/tgui/packages/tgui/components/Dropdown.tsx @@ -1,12 +1,12 @@ import { classes } from 'common/react'; -import { ReactNode, useCallback, useEffect, useRef, useState } from 'react'; +import { ReactNode, useEffect, useRef, useState } from 'react'; import { BoxProps, unit } from './Box'; import { Button } from './Button'; import { Icon } from './Icon'; import { Popper } from './Popper'; -type DropdownEntry = { +export type DropdownEntry = { displayText: ReactNode; value: string | number; }; @@ -19,7 +19,11 @@ type Props = { options: DropdownOption[]; /** Called when a value is picked from the list, `value` is the value that was picked */ onSelected: (value: any) => void; + /** Currently selected entry to display. Can be left stateless to permanently display this value. */ + selected: DropdownOption | null | undefined; } & Partial<{ + /** Whether to scroll automatically on open. Defaults to true */ + autoScroll: boolean; /** Whether to display previous / next buttons */ buttons: boolean; /** Whether to clip the selected text */ @@ -28,7 +32,7 @@ type Props = { color: string; /** Disables the dropdown */ disabled: boolean; - /** Text to always display in place of the selected text */ + /** Overwrites selection text with this. Good for objects etc. */ displayText: ReactNode; /** Icon to display in dropdown button */ icon: string; @@ -44,17 +48,26 @@ type Props = { onClick: (event) => void; /** Dropdown renders over instead of below */ over: boolean; - /** Currently selected entry */ - selected: string | number; + /** Text to show when nothing has been selected. */ + placeholder: string; }> & BoxProps; +enum DIRECTION { + Previous = 'previous', + Next = 'next', + Current = 'current', +} + +const NONE = -1; + function getOptionValue(option: DropdownOption) { return typeof option === 'string' ? option : option.value; } export function Dropdown(props: Props) { const { + autoScroll = true, buttons, className, clipSelectedText = true, @@ -70,46 +83,64 @@ export function Dropdown(props: Props) { onSelected, options = [], over, + placeholder = 'Select...', selected, - width, + width = '15rem', } = props; const [open, setOpen] = useState(false); const adjustedOpen = over ? !open : open; const innerRef = useRef(null); - /** Update the selected value when clicking the left/right buttons */ - const updateSelected = useCallback( - (direction: 'previous' | 'next') => { - if (options.length < 1 || disabled) { - return; - } - const startIndex = 0; - const endIndex = options.length - 1; + const selectedIndex = + options.findIndex((option) => getOptionValue(option) === selected) || 0; - let selectedIndex = options.findIndex( - (option) => getOptionValue(option) === selected, - ); + function scrollTo(position: number) { + let scrollPos = position; + if (position < selectedIndex) { + scrollPos = position < 2 ? 0 : position - 2; + } else { + scrollPos = + position > options.length - 3 ? options.length - 1 : position - 2; + } - if (selectedIndex < 0) { - selectedIndex = direction === 'next' ? endIndex : startIndex; - } + const element = innerRef.current?.children[scrollPos]; + element?.scrollIntoView({ block: 'nearest' }); + } - let newIndex = selectedIndex; - if (direction === 'next') { - newIndex = selectedIndex === endIndex ? startIndex : ++selectedIndex; - } else { - newIndex = selectedIndex === startIndex ? endIndex : --selectedIndex; - } - - onSelected?.(getOptionValue(options[newIndex])); - }, - [disabled, onSelected, options, selected], - ); + /** Update the selected value when clicking the left/right buttons */ + function updateSelected(direction: DIRECTION) { + if (options.length < 1 || disabled) { + return; + } + + const startIndex = 0; + const endIndex = options.length - 1; + + let newIndex: number; + if (selectedIndex < 0) { + newIndex = direction === 'next' ? endIndex : startIndex; // No selection yet + } else if (direction === 'next') { + newIndex = selectedIndex === endIndex ? startIndex : selectedIndex + 1; // Move to next option + } else { + newIndex = selectedIndex === startIndex ? endIndex : selectedIndex - 1; // Move to previous option + } + + if (open && autoScroll) { + scrollTo(newIndex); + } + onSelected?.(getOptionValue(options[newIndex])); + } /** Allows the menu to be scrollable on open */ useEffect(() => { - if (!open) return; + if (!open) { + return; + } + + if (autoScroll && selectedIndex !== NONE) { + scrollTo(selectedIndex); + } innerRef.current?.focus(); }, [open]); @@ -151,69 +182,64 @@ export function Dropdown(props: Props) {
    } > -
    -
    -
    { - if (disabled && !open) { - return; - } - setOpen(!open); - onClick?.(event); +
    +
    { + if (disabled && !open) { + return; + } + setOpen(!open); + onClick?.(event); + }} + > + {icon && ( + + )} + - {icon && ( - - )} - - {displayText || selected} + {displayText || + (selected && getOptionValue(selected)) || + placeholder} + + {!noChevron && ( + + - {!noChevron && ( - - - - )} -
    - {buttons && ( - <> -
    + {buttons && ( + <> +
    ); diff --git a/tgui/packages/tgui/interfaces/AdminFax.jsx b/tgui/packages/tgui/interfaces/AdminFax.jsx index 9aeef3247a34d..3e6026d4ce46e 100644 --- a/tgui/packages/tgui/interfaces/AdminFax.jsx +++ b/tgui/packages/tgui/interfaces/AdminFax.jsx @@ -63,10 +63,9 @@ export const FaxMainPanel = (props) => { setFax(value)} /> diff --git a/tgui/packages/tgui/interfaces/AdminPDA.jsx b/tgui/packages/tgui/interfaces/AdminPDA.jsx index 09570265a207e..fa83f200e52c7 100644 --- a/tgui/packages/tgui/interfaces/AdminPDA.jsx +++ b/tgui/packages/tgui/interfaces/AdminPDA.jsx @@ -33,7 +33,8 @@ const ReceiverChoice = (props) => { showInvisible || !rcvr.invisible) .map((rcvr) => ({ diff --git a/tgui/packages/tgui/interfaces/AiVoiceChanger.tsx b/tgui/packages/tgui/interfaces/AiVoiceChanger.tsx index 9e248a0103344..09c1aa04e57f1 100644 --- a/tgui/packages/tgui/interfaces/AiVoiceChanger.tsx +++ b/tgui/packages/tgui/interfaces/AiVoiceChanger.tsx @@ -5,37 +5,40 @@ import { Button, Dropdown, Input, LabeledList, Section } from '../components'; import { Window } from '../layouts'; type Data = { - on: BooleanLike; - voices: string[]; - say_verb: string; loud: BooleanLike; name: string; + on: BooleanLike; + say_verb: string; + selected: string; + voices: string[]; }; -export const AiVoiceChanger = (props) => { +export function AiVoiceChanger(props) { const { act, data } = useBackend(); - const { loud, name, on, say_verb, voices } = data; + const { loud, name, on, say_verb, voices, selected } = data; return ( -
    +
    + onSelected={(value) => { act('look', { look: value, - }) - } + }); + }} + selected={selected} /> @@ -51,10 +54,11 @@ export const AiVoiceChanger = (props) => { {
    ); -}; +} diff --git a/tgui/packages/tgui/interfaces/Changelog.jsx b/tgui/packages/tgui/interfaces/Changelog.jsx index 2897e1a106fe0..8af62faa84859 100644 --- a/tgui/packages/tgui/interfaces/Changelog.jsx +++ b/tgui/packages/tgui/interfaces/Changelog.jsx @@ -141,7 +141,7 @@ export class Changelog extends Component { { const index = dateChoices.indexOf(value); @@ -157,7 +157,7 @@ export class Changelog extends Component { return this.getData(dates[index]); }} selected={selectedDate} - width={'150px'} + width="150px" /> diff --git a/tgui/packages/tgui/interfaces/CircuitModule.jsx b/tgui/packages/tgui/interfaces/CircuitModule.jsx index 799fea9d15ffb..bbb323e5e5a7e 100644 --- a/tgui/packages/tgui/interfaces/CircuitModule.jsx +++ b/tgui/packages/tgui/interfaces/CircuitModule.jsx @@ -130,7 +130,7 @@ const PortEntry = (props) => { diff --git a/tgui/packages/tgui/interfaces/CircuitSignalHandler.tsx b/tgui/packages/tgui/interfaces/CircuitSignalHandler.tsx index 1fc1f8397f920..66d04644391c3 100644 --- a/tgui/packages/tgui/interfaces/CircuitSignalHandler.tsx +++ b/tgui/packages/tgui/interfaces/CircuitSignalHandler.tsx @@ -221,7 +221,7 @@ const Entry = (props: EntryProps) => { {(options.length && ( diff --git a/tgui/packages/tgui/interfaces/CommandReport.tsx b/tgui/packages/tgui/interfaces/CommandReport.tsx index dfe8cf9ff3d63..9185bebb5b4cd 100644 --- a/tgui/packages/tgui/interfaces/CommandReport.tsx +++ b/tgui/packages/tgui/interfaces/CommandReport.tsx @@ -117,7 +117,7 @@ const AnnouncementColor = (props) => {
    act('update_announcement_color', { @@ -138,7 +138,7 @@ const AnnouncementSound = (props) => {
    act('set_report_sound', { diff --git a/tgui/packages/tgui/interfaces/DeathmatchLobby.tsx b/tgui/packages/tgui/interfaces/DeathmatchLobby.tsx index 457c909b2ca7a..12dad26bc71d5 100644 --- a/tgui/packages/tgui/interfaces/DeathmatchLobby.tsx +++ b/tgui/packages/tgui/interfaces/DeathmatchLobby.tsx @@ -6,228 +6,315 @@ import { Button, Divider, Dropdown, - Flex, Icon, + LabeledList, Modal, + NoticeBox, Section, + Stack, Table, + Tooltip, } from '../components'; import { ButtonCheckbox } from '../components/Button'; import { Window } from '../layouts'; -type PlayerLike = { - [key: string]: { - host: number; - ready: BooleanLike; - }; +type Player = Record; + +type PlayerInfo = { + host: number; + ready: BooleanLike; }; type Modifier = { - name: string; desc: string; modpath: string; - selected: BooleanLike; - selectable: BooleanLike; - player_selected: BooleanLike; + name: string; player_selectable: BooleanLike; + player_selected: BooleanLike; + selectable: BooleanLike; + selected: BooleanLike; +}; + +type Map = { + desc: string; + max_players: number; + min_players: number; + name: string; + time: number; }; type Data = { - self: string; - host: BooleanLike; + active_mods: string; admin: BooleanLike; - playing: BooleanLike; + host: BooleanLike; + loadoutdesc: string; loadouts: string[]; + map: Map; maps: string[]; - map: { - name: string; - desc: string; - time: number; - min_players: number; - max_players: number; - }; mod_menu_open: BooleanLike; modifiers: Modifier[]; - active_mods: string; - loadoutdesc: string; - players: PlayerLike[]; - observers: PlayerLike[]; + observers: Player[]; + players: Player[]; + playing: BooleanLike; + self: string; }; -export const DeathmatchLobby = (props) => { +export function DeathmatchLobby(props) { const { act, data } = useBackend(); - const { modifiers = [] } = data; + const { admin, observers = [], self, players } = data; + + const allReady = Object.keys(players).every( + (player) => players[player].ready, + ); + return ( - - -
    - - - - Name - Loadout - Ready - - {Object.keys(data.players).map((player) => ( - - - {!!data.players[player].host && } - - - {(!( - (data.host && !data.players[player].host) || - data.admin - ) && {player}) || ( - - act('host', { - id: player, - func: value, - }) - } - /> - )} - - - - act('change_loadout', { - player: player, - loadout: value, - }) - } - /> - - - act('ready')} - /> - - - ))} - {Object.keys(data.observers).map((observer) => ( - - - {(!!data.observers[observer].host && ( - - )) || } - - - {(!( - (data.host && !data.observers[observer].host) || - data.admin - ) && {observer}) || ( - - act('host', { - id: observer, - func: value, - }) - } - /> - )} - - Observing - - ))} -
    -
    -
    - + + + + + + + + + + + +
    - - {(!!data.host && ( + + + {!!admin && ( + + )} + + + + + + + +
    +
    +
    +
    +
    + ); +} + +function PlayerColumn(props) { + const { act, data } = useBackend(); + const { + admin, + host, + loadouts = [], + observers = [], + players = [], + self, + } = data; + + const allReady = Object.keys(players).every( + (player) => players[player].ready, + ); + + return ( +
    30}> + + + + Name + Loadout + + + + + + + {Object.keys(players).map((player) => { + const fullAccess = (!!host && !!players[player].host) || !admin; + + return ( + + + {!!players[player].host && } + + + {!fullAccess ? ( + {player} + ) : ( act('host', { - func: 'change_map', - map: value, + id: player, + func: value, }) } /> - )) || {data.map.name}} - - - {data.map.desc} - - - Maximum Play Time: {`${data.map.time / 600}min`} -
    - Min players: {data.map.min_players} -
    - Max players: {data.map.max_players} -
    - Current players: {Object.keys(data.players).length} -
    - - {data.active_mods} - {(!!data.admin || !!data.host) && ( - <> - -
    +
    + ); +} + +function HostControls(props) { + const { act, data } = useBackend(); + const { + active_mods = [], + admin, + host, + loadoutdesc, + map, + maps = [], + players = [], + playing, + } = data; + + return ( +
    + {!host ? ( + {map.name} + ) : ( + + act('host', { + func: 'change_map', + map: value, + }) + } /> - {!!data.admin && ( - + + )} + + + Loadout Description + + + {loadoutdesc} + {!!playing && ( + <> + + + The game is currently in progress, or loading. + + + )} +
    ); -}; +} const ModSelector = (props) => { const { act, data } = useBackend(); @@ -235,21 +322,18 @@ const ModSelector = (props) => { if (!mod_menu_open || !(host || admin)) { return null; } + return ( - {modifiers.map((mod, index) => { return ( { modpath: mod.modpath, }) } - /> + > + {mod.name} + ); })} diff --git a/tgui/packages/tgui/interfaces/DeathmatchPanel.jsx b/tgui/packages/tgui/interfaces/DeathmatchPanel.jsx deleted file mode 100644 index 8ac2ff5f76d1d..0000000000000 --- a/tgui/packages/tgui/interfaces/DeathmatchPanel.jsx +++ /dev/null @@ -1,95 +0,0 @@ -import { useBackend } from '../backend'; -import { - Button, - Dropdown, - Flex, - NoticeBox, - Section, - Stack, - Table, -} from '../components'; -import { Window } from '../layouts'; - -export const DeathmatchPanel = (props, context) => { - const { act, data } = useBackend(context); - const playing = data.playing || ''; - return ( - - - - If you play, you can still possibly be returned to your body (No - Guarantees)! - -
    - - - Host - Map - Players - - {data.lobbies.map((lobby) => ( - - - {(!data.admin && lobby.name) || ( - - act('admin', { - id: lobby.name, - func: value, - }) - } - /> - )} - - {lobby.map} - - {lobby.players}/{lobby.max_players} - - - {(!lobby.playing && ( - <> -
    -
    - + + +
    +
    + ); +} + +function LobbyPane(props) { + const { data } = useBackend(); + const { lobbies = [] } = data; + + return ( +
    + + + Host + Map + + + + + + + + + + + {lobbies.length === 0 && ( + + + + No lobbies found. Start one! + + + + )} + + {lobbies.map((lobby, index) => ( + + ))} +
    +
    + ); +} + +function LobbyDisplay(props) { + const { act, data } = useBackend(); + const { admin, playing, hosting } = data; + const { lobby } = props; + + const isActive = (!!hosting || !!playing) && playing !== lobby.name; + + return ( + + + {!admin ? ( + lobby.name + ) : ( + + act('admin', { + id: lobby.name, + func: value, + }) + } + /> + )} + + {lobby.map} + + {lobby.players}/{lobby.max_players} + + + {!lobby.playing ? ( + <> + + + )} + + + ); +} diff --git a/tgui/packages/tgui/interfaces/IntegratedCircuit/ComponentMenu.jsx b/tgui/packages/tgui/interfaces/IntegratedCircuit/ComponentMenu.jsx index 9b91ef348fa15..e243ef365b067 100644 --- a/tgui/packages/tgui/interfaces/IntegratedCircuit/ComponentMenu.jsx +++ b/tgui/packages/tgui/interfaces/IntegratedCircuit/ComponentMenu.jsx @@ -120,7 +120,8 @@ export class ComponentMenu extends Component { currentLimit: DEFAULT_COMPONENT_MENU_LIMIT, }) } - displayText={`Category: ${selectedTab}`} + selected={selectedTab} + placeholder="Category" color="transparent" className="IntegratedCircuit__BlueBorder" /> diff --git a/tgui/packages/tgui/interfaces/IntegratedCircuit/FundamentalTypes.jsx b/tgui/packages/tgui/interfaces/IntegratedCircuit/FundamentalTypes.jsx index 2ea8ce922aa77..65d0814d8ce24 100644 --- a/tgui/packages/tgui/interfaces/IntegratedCircuit/FundamentalTypes.jsx +++ b/tgui/packages/tgui/interfaces/IntegratedCircuit/FundamentalTypes.jsx @@ -88,7 +88,7 @@ export const FUNDAMENTAL_DATA_TYPES = { color={'transparent'} options={data} onSelected={setValue} - displayText={value} + selected={value} menuWidth={large ? '200px' : undefined} /> ); diff --git a/tgui/packages/tgui/interfaces/IntegratedCircuit/VariableMenu.jsx b/tgui/packages/tgui/interfaces/IntegratedCircuit/VariableMenu.jsx index 955e45da41be0..45e7e90d7377b 100644 --- a/tgui/packages/tgui/interfaces/IntegratedCircuit/VariableMenu.jsx +++ b/tgui/packages/tgui/interfaces/IntegratedCircuit/VariableMenu.jsx @@ -1,4 +1,5 @@ import { shallowDiffers } from 'common/react'; +import { multiline } from 'common/string'; import { Component } from 'react'; import { @@ -15,7 +16,6 @@ import { VARIABLE_LIST, VARIABLE_NOT_A_LIST, } from './constants'; -import { multiline } from 'common/string'; export class VariableMenu extends Component { constructor(props) { @@ -145,7 +145,7 @@ export class VariableMenu extends Component { { over mb={1.7} width="100%" - displayText={bookName} + selected={bookName} options={inventory.map((book) => book.title)} value={bookName} onSelected={(e) => setBookName(e)} diff --git a/tgui/packages/tgui/interfaces/MODsuit.tsx b/tgui/packages/tgui/interfaces/MODsuit.tsx index 874f1b4774dee..8752fc3c8741a 100644 --- a/tgui/packages/tgui/interfaces/MODsuit.tsx +++ b/tgui/packages/tgui/interfaces/MODsuit.tsx @@ -226,7 +226,7 @@ const ConfigureListEntry = (props) => { const { act } = useBackend(); return ( act('configure', { diff --git a/tgui/packages/tgui/interfaces/MineBot.tsx b/tgui/packages/tgui/interfaces/MineBot.tsx index 4a3087cf8d6ea..9118562cdd0fc 100644 --- a/tgui/packages/tgui/interfaces/MineBot.tsx +++ b/tgui/packages/tgui/interfaces/MineBot.tsx @@ -97,7 +97,7 @@ export const MineBot = (props) => { { return possible_color.color_name; })} diff --git a/tgui/packages/tgui/interfaces/NavBeacon.tsx b/tgui/packages/tgui/interfaces/NavBeacon.tsx index 5194fe42c1c66..6cc5036c87f4a 100644 --- a/tgui/packages/tgui/interfaces/NavBeacon.tsx +++ b/tgui/packages/tgui/interfaces/NavBeacon.tsx @@ -20,11 +20,11 @@ export type Data = { }; export type NavBeaconControl = { - location: String; + location: string; patrol_enabled: BooleanLike; - patrol_next: String; + patrol_next: string; delivery_enabled: BooleanLike; - delivery_direction: String; + delivery_direction: string; cover_locked: BooleanLike; }; @@ -107,7 +107,7 @@ export const NavBeaconControlSection = (props: DisabledProps) => { act('set_delivery_direction', { direction: value, diff --git a/tgui/packages/tgui/interfaces/NtosCard.tsx b/tgui/packages/tgui/interfaces/NtosCard.tsx index 7c3991a487c26..5997aa0e91c12 100644 --- a/tgui/packages/tgui/interfaces/NtosCard.tsx +++ b/tgui/packages/tgui/interfaces/NtosCard.tsx @@ -240,7 +240,7 @@ const TemplateDropdown = (props) => { { return templates[path]; })} @@ -249,6 +249,7 @@ const TemplateDropdown = (props) => { name: sel, }) } + selected="None" /> diff --git a/tgui/packages/tgui/interfaces/NtosRoboControl.jsx b/tgui/packages/tgui/interfaces/NtosRoboControl.jsx index 20c70220d3697..9b55c90a45628 100644 --- a/tgui/packages/tgui/interfaces/NtosRoboControl.jsx +++ b/tgui/packages/tgui/interfaces/NtosRoboControl.jsx @@ -2,7 +2,6 @@ import { useBackend, useSharedState } from '../backend'; import { Box, Button, - Dropdown, LabeledList, ProgressBar, Section, @@ -71,19 +70,22 @@ export const NtosRoboControl = (props) => { + Drone Pings + {dronepingtypes.map((ping_type) => ( + + ))}
    {drones?.map((drone) => ( diff --git a/tgui/packages/tgui/interfaces/NtosScipaper.jsx b/tgui/packages/tgui/interfaces/NtosScipaper.jsx index 3866ccab24ce7..2af2cd12f43f9 100644 --- a/tgui/packages/tgui/interfaces/NtosScipaper.jsx +++ b/tgui/packages/tgui/interfaces/NtosScipaper.jsx @@ -93,7 +93,7 @@ const PaperPublishing = (props) => { act('select_file', { selected_uid: fileList[ordfile_name], @@ -117,7 +117,7 @@ const PaperPublishing = (props) => { act('select_experiment', { selected_expath: expList[experiment_name], @@ -141,7 +141,7 @@ const PaperPublishing = (props) => { String(number))} - displayText={tier ? String(tier) : '-'} + selected={String(tier)} onSelected={(new_tier) => act('select_tier', { selected_tier: Number(new_tier), @@ -165,7 +165,7 @@ const PaperPublishing = (props) => { act('select_partner', { selected_partner: allowedPartners[new_partner], diff --git a/tgui/packages/tgui/interfaces/NtosVirtualPet.tsx b/tgui/packages/tgui/interfaces/NtosVirtualPet.tsx index 7b61f2b566e54..1894aa703d667 100644 --- a/tgui/packages/tgui/interfaces/NtosVirtualPet.tsx +++ b/tgui/packages/tgui/interfaces/NtosVirtualPet.tsx @@ -268,7 +268,7 @@ const PetTricks = (props) => { UpdateSequence(index, selected)} /> @@ -354,7 +354,7 @@ const Customization = (props) => {
    { return selected_hat.hat_name; })} @@ -369,7 +369,7 @@ const Customization = (props) => {
    { return possible_color.color_name; })} diff --git a/tgui/packages/tgui/interfaces/PlaneMasterDebug.tsx b/tgui/packages/tgui/interfaces/PlaneMasterDebug.tsx index 1a623bb20795a..c85cdec2d1311 100644 --- a/tgui/packages/tgui/interfaces/PlaneMasterDebug.tsx +++ b/tgui/packages/tgui/interfaces/PlaneMasterDebug.tsx @@ -885,7 +885,6 @@ const GroupDropdown = (props) => { act('set_group', { target_group: value, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/JobsPage.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/JobsPage.tsx index 27d0e73833ca1..4fbc080c5a347 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/JobsPage.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/JobsPage.tsx @@ -330,18 +330,17 @@ const JoblessRoleDropdown = (props) => { }, ]; + const selection = options?.find( + (option) => option.value === selected, + )!.displayText; + return ( - {options.find((option) => option.value === selected)!.displayText} - - } /> ); diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/RandomizationButton.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/RandomizationButton.tsx index 4152e2d77c196..0620f22da3a95 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/RandomizationButton.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/RandomizationButton.tsx @@ -1,6 +1,6 @@ import { exhaustiveCheck } from 'common/exhaustive'; -import { Dropdown, Icon } from '../../components'; +import { Dropdown } from '../../components'; import { RandomSetting } from './data'; const options = [ @@ -48,12 +48,13 @@ export const RandomizationButton = (props: { color={color} {...dropdownProps} clipSelectedText={false} - displayText={} + icon="dice-d20" options={options} noChevron onSelected={setValue} menuWidth="120px" width={1.85} + selected="None" /> ); }; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/base.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/base.tsx index 8878292e6575d..452eb677519b1 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/base.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/base.tsx @@ -1,5 +1,5 @@ -import { sort, sortBy } from 'common/collections'; -import { BooleanLike, classes } from 'common/react'; +import { sortBy } from 'common/collections'; +import { BooleanLike } from 'common/react'; import { ComponentType, createElement, @@ -123,16 +123,15 @@ export const CheckboxInputInverse = ( ); }; -export const createDropdownInput = ( +export function createDropdownInput( // Map of value to display texts choices: Record, dropdownProps?: Record, -): FeatureValue => { +): FeatureValue { return (props: FeatureValueProps) => { return ( ( /> ); }; -}; +} export type FeatureChoicedServerData = { choices: string[]; @@ -157,136 +156,6 @@ export type FeatureChoicedServerData = { export type FeatureChoiced = Feature; -const capitalizeFirstLetter = (text: string) => - text.toString().charAt(0).toUpperCase() + text.toString().slice(1); - -export const StandardizedDropdown = (props: { - choices: string[]; - disabled?: boolean; - displayNames: Record; - onSetValue: (newValue: string) => void; - value: string; - buttons?: boolean; -}) => { - const { choices, disabled, buttons, displayNames, onSetValue, value } = props; - - return ( - { - return { - displayText: displayNames[choice], - value: choice, - }; - })} - /> - ); -}; - -export const FeatureDropdownInput = ( - props: FeatureValueProps & { - disabled?: boolean; - buttons?: boolean; - }, -) => { - const serverData = props.serverData; - if (!serverData) { - return null; - } - - const displayNames = - serverData.display_names || - Object.fromEntries( - serverData.choices.map((choice) => [ - choice, - capitalizeFirstLetter(choice), - ]), - ); - - return ( - - ); -}; - -export type FeatureWithIcons = Feature< - { value: T }, - T, - FeatureChoicedServerData ->; - -export const FeatureIconnedDropdownInput = ( - props: FeatureValueProps< - { - value: string; - }, - string, - FeatureChoicedServerData - >, -) => { - const serverData = props.serverData; - if (!serverData) { - return null; - } - - const icons = serverData.icons; - - const textNames = - serverData.display_names || - Object.fromEntries( - serverData.choices.map((choice) => [ - choice, - capitalizeFirstLetter(choice), - ]), - ); - - const displayNames = Object.fromEntries( - Object.entries(textNames).map(([choice, textName]) => { - let element: ReactNode = textName; - - if (icons && icons[choice]) { - const icon = icons[choice]; - element = ( - - - - - - {element} - - ); - } - - return [choice, element]; - }), - ); - - return ( - - ); -}; - export type FeatureNumericData = { minimum: number; maximum: number; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/ai_core_display.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/ai_core_display.tsx index 6b3e10bb10cc0..0e73c28526a94 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/ai_core_display.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/ai_core_display.tsx @@ -1,4 +1,5 @@ -import { FeatureIconnedDropdownInput, FeatureWithIcons } from '../base'; +import {} from '../base'; +import { FeatureIconnedDropdownInput, FeatureWithIcons } from '../dropdowns'; export const preferred_ai_core_display: FeatureWithIcons = { name: 'AI core display', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/ai_emote_display.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/ai_emote_display.tsx index c8a59a5d9a441..3e958297b8882 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/ai_emote_display.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/ai_emote_display.tsx @@ -1,4 +1,4 @@ -import { FeatureIconnedDropdownInput, FeatureWithIcons } from '../base'; +import { FeatureIconnedDropdownInput, FeatureWithIcons } from '../dropdowns'; export const preferred_ai_emote_display: FeatureWithIcons = { name: 'AI emote display', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/ai_hologram_display.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/ai_hologram_display.tsx index 423fcea8ed2f6..46d572fcda6b4 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/ai_hologram_display.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/ai_hologram_display.tsx @@ -1,4 +1,4 @@ -import { FeatureIconnedDropdownInput, FeatureWithIcons } from '../base'; +import { FeatureIconnedDropdownInput, FeatureWithIcons } from '../dropdowns'; export const preferred_ai_hologram_display: FeatureWithIcons = { name: 'AI hologram display', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/body_type.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/body_type.tsx index de9d6523e2c42..3746e62ceeec9 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/body_type.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/body_type.tsx @@ -1,4 +1,5 @@ -import { FeatureChoiced, FeatureDropdownInput } from '../base'; +import { FeatureChoiced } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const body_type: FeatureChoiced = { name: 'Body type', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/food_allergy.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/food_allergy.tsx index f5b0ea37ca89b..bdcd91ac7afab 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/food_allergy.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/food_allergy.tsx @@ -1,4 +1,5 @@ -import { FeatureChoiced, FeatureDropdownInput } from '../base'; +import { FeatureChoiced } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const food_allergy: FeatureChoiced = { name: 'Food Allergy', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/glasses.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/glasses.tsx index 60cb3131f1b83..df73451c35a20 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/glasses.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/glasses.tsx @@ -1,4 +1,4 @@ -import { FeatureIconnedDropdownInput, FeatureWithIcons } from '../base'; +import { FeatureIconnedDropdownInput, FeatureWithIcons } from '../dropdowns'; export const glasses: FeatureWithIcons = { name: 'Glasses', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/hemiplegic.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/hemiplegic.tsx index 0494558ba7781..35837c80099c6 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/hemiplegic.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/hemiplegic.tsx @@ -1,4 +1,5 @@ -import { FeatureChoiced, FeatureDropdownInput } from '../base'; +import { FeatureChoiced } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const hemiplegic: FeatureChoiced = { name: 'Hemiplegic', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/junkie.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/junkie.tsx index 8ac11ed968d1f..586b69d86c2b2 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/junkie.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/junkie.tsx @@ -1,4 +1,5 @@ -import { FeatureChoiced, FeatureDropdownInput } from '../base'; +import { FeatureChoiced } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const junkie: FeatureChoiced = { name: 'Addiction', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/language.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/language.tsx index 6b1a1be1220b2..39c48ae40d6ad 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/language.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/language.tsx @@ -1,4 +1,5 @@ -import { FeatureChoiced, FeatureDropdownInput } from '../base'; +import { FeatureChoiced } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const language: FeatureChoiced = { name: 'Language', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/pda.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/pda.tsx index fdc9a2be5dad0..196dea45c5d16 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/pda.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/pda.tsx @@ -1,9 +1,5 @@ -import { - Feature, - FeatureChoiced, - FeatureDropdownInput, - FeatureShortTextInput, -} from '../base'; +import { Feature, FeatureChoiced, FeatureShortTextInput } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const pda_theme: FeatureChoiced = { name: 'PDA Theme', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/phobia.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/phobia.tsx index dd14349277fec..f2f35f65e16df 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/phobia.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/phobia.tsx @@ -1,4 +1,5 @@ -import { FeatureChoiced, FeatureDropdownInput } from '../base'; +import { FeatureChoiced } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const phobia: FeatureChoiced = { name: 'Phobia', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/pride_pin.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/pride_pin.tsx index b0fae6092a1e9..70c6f8a8efec3 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/pride_pin.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/pride_pin.tsx @@ -1,4 +1,5 @@ -import { FeatureChoiced, FeatureDropdownInput } from '../base'; +import { FeatureChoiced } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const pride_pin: FeatureChoiced = { name: 'Pride Pin', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/prisoner_crime.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/prisoner_crime.tsx index 2ca17aa4e36d6..b551b68ee2ec5 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/prisoner_crime.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/prisoner_crime.tsx @@ -1,4 +1,5 @@ -import { FeatureChoiced, FeatureDropdownInput } from '../base'; +import { FeatureChoiced } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const prisoner_crime: FeatureChoiced = { name: 'Prisoner crime', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/prosthetic_limb.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/prosthetic_limb.tsx index adbaefe90c8f2..87a8ea23de199 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/prosthetic_limb.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/prosthetic_limb.tsx @@ -1,4 +1,5 @@ -import { FeatureChoiced, FeatureDropdownInput } from '../base'; +import { FeatureChoiced } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const prosthetic: FeatureChoiced = { name: 'Prosthetic', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/prosthetic_organ.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/prosthetic_organ.tsx index da0e37a4173b2..5b484d5960e7f 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/prosthetic_organ.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/prosthetic_organ.tsx @@ -1,4 +1,5 @@ -import { FeatureChoiced, FeatureDropdownInput } from '../base'; +import { FeatureChoiced } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const prosthetic_organ: FeatureChoiced = { name: 'Prosthetic Organ', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/security_department.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/security_department.tsx index e9f380bd67562..a1311e347c80f 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/security_department.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/security_department.tsx @@ -1,4 +1,5 @@ -import { FeatureChoiced, FeatureDropdownInput } from '../base'; +import { FeatureChoiced } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const prefered_security_department: FeatureChoiced = { name: 'Security department', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/skin_tone.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/skin_tone.tsx index 2e5c18f23244b..95029374bd23c 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/skin_tone.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/skin_tone.tsx @@ -1,12 +1,8 @@ import { sortBy } from 'common/collections'; +import { useMemo } from 'react'; +import { Box, Dropdown, Stack } from 'tgui/components'; -import { Box, Stack } from '../../../../../components'; -import { - Feature, - FeatureChoicedServerData, - FeatureValueProps, - StandardizedDropdown, -} from '../base'; +import { Feature, FeatureChoicedServerData, FeatureValueProps } from '../base'; type HexValue = { lightness: number; @@ -24,43 +20,53 @@ const sortHexValues = (array: [string, HexValue][]) => export const skin_tone: Feature = { name: 'Skin tone', component: (props: FeatureValueProps) => { - const { handleSetValue, serverData, value } = props; + const { handleSetValue, serverData } = props; if (!serverData) { return null; } - return ( - key, - )} - displayNames={Object.fromEntries( - Object.entries(serverData.display_names).map(([key, displayName]) => { - const hexColor = serverData.to_hex[key]; + const value = { value: props.value }; + + const displayNames = useMemo(() => { + const sorted = sortHexValues(Object.entries(serverData.to_hex)); + + return sorted.map(([key, colorInfo]) => { + const displayName = serverData.display_names[key]; - return [ - key, - - - - + return { + value: key, + displayText: ( + + + + - {displayName} - , - ]; - }), - )} - onSetValue={handleSetValue} - value={value} + {displayName} + + ), + }; + }); + }, [serverData.display_names]); + + return ( + option.value === value.value) + ?.displayText + } + onSelected={(value) => handleSetValue(value)} + options={displayNames} + selected={value.value} + width="100%" /> ); }, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/trans_prosthetic.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/trans_prosthetic.tsx index 368a2a16a1b37..fc8601e3cc7e1 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/trans_prosthetic.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/trans_prosthetic.tsx @@ -1,4 +1,5 @@ -import { FeatureChoiced, FeatureDropdownInput } from '../base'; +import { FeatureChoiced } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const trans_prosthetic: FeatureChoiced = { name: 'Augment', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/tts_voice.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/tts_voice.tsx index 94a208158c504..1f588f07f15b4 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/tts_voice.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/tts_voice.tsx @@ -2,11 +2,11 @@ import { Button, Stack } from '../../../../../components'; import { FeatureChoiced, FeatureChoicedServerData, - FeatureDropdownInput, FeatureNumeric, FeatureSliderInput, FeatureValueProps, } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; const FeatureTTSDropdownInput = ( props: FeatureValueProps, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/uplink_loc.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/uplink_loc.tsx index 06c125c33fc30..2b1ffe26a3289 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/uplink_loc.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/uplink_loc.tsx @@ -1,4 +1,5 @@ -import { FeatureChoiced, FeatureDropdownInput } from '../base'; +import { FeatureChoiced } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const uplink_loc: FeatureChoiced = { name: 'Uplink Spawn Location', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dropdowns.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dropdowns.tsx new file mode 100644 index 0000000000000..98755146ac90c --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dropdowns.tsx @@ -0,0 +1,103 @@ +import { classes } from 'common/react'; +import { capitalizeFirst } from 'common/string'; +import { ReactNode } from 'react'; + +import { Box, Dropdown, Stack } from '../../../../components'; +import { Feature, FeatureChoicedServerData, FeatureValueProps } from './base'; + +type DropdownInputProps = FeatureValueProps< + string, + string, + FeatureChoicedServerData +> & + Partial<{ + disabled: boolean; + buttons: boolean; + }>; + +type IconnedDropdownInputProps = FeatureValueProps< + string, + string, + FeatureChoicedServerData +>; + +export type FeatureWithIcons = Feature; + +export function FeatureDropdownInput(props: DropdownInputProps) { + const { serverData, disabled, buttons, handleSetValue, value } = props; + + if (!serverData) { + return null; + } + + const { choices, display_names } = serverData; + + const dropdownOptions = choices.map((choice) => { + let displayText: ReactNode = display_names + ? display_names[choice] + : capitalizeFirst(choice); + + return { + displayText, + value: choice, + }; + }); + + return ( + + ); +} + +export function FeatureIconnedDropdownInput(props: IconnedDropdownInputProps) { + const { serverData, handleSetValue, value } = props; + + if (!serverData) { + return null; + } + + const { choices, display_names, icons } = serverData; + + const dropdownOptions = choices.map((choice) => { + let displayText: ReactNode = display_names + ? display_names[choice] + : capitalizeFirst(choice); + + if (icons?.[choice]) { + displayText = ( + + + + + {displayText} + + ); + } + + return { + displayText, + value: choice, + }; + }); + + return ( + + ); +} diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/admin.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/admin.tsx index 03244e9f6ee7d..d99cd329f558e 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/admin.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/admin.tsx @@ -4,9 +4,9 @@ import { CheckboxInput, Feature, FeatureColorInput, - FeatureDropdownInput, FeatureToggle, } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const asaycolor: Feature = { name: 'Admin chat color', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/ghost.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/ghost.tsx index ab973e3659e35..5ec1686719799 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/ghost.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/ghost.tsx @@ -10,10 +10,10 @@ import { CheckboxInput, FeatureChoiced, FeatureChoicedServerData, - FeatureDropdownInput, FeatureToggle, FeatureValueProps, } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const ghost_accs: FeatureChoiced = { name: 'Ghost accessories', @@ -81,9 +81,10 @@ const GhostFormInput = ( return ( = { name: 'MOD active module key', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/parallax.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/parallax.tsx index a7b143a6d3d0d..914af27c38281 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/parallax.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/parallax.tsx @@ -1,4 +1,5 @@ -import { Feature, FeatureDropdownInput } from '../base'; +import { Feature } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const parallax: Feature = { name: 'Parallax (fancy space)', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/preferred_map.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/preferred_map.tsx index 1a1755ce71466..5b0860ef91ec6 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/preferred_map.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/preferred_map.tsx @@ -1,6 +1,7 @@ import { multiline } from 'common/string'; -import { Feature, FeatureDropdownInput } from '../base'; +import { Feature } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const preferred_map: Feature = { name: 'Preferred map', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/screentips.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/screentips.tsx index 5c65c4f100a4c..ff2cf95a048f0 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/screentips.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/screentips.tsx @@ -5,9 +5,9 @@ import { Feature, FeatureChoiced, FeatureColorInput, - FeatureDropdownInput, FeatureToggle, } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const screentip_color: Feature = { name: 'Screentips: Screentips color', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/sounds.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/sounds.tsx index 0bce5e0982e0b..34e968f35c476 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/sounds.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/sounds.tsx @@ -4,10 +4,10 @@ import { CheckboxInput, Feature, FeatureChoiced, - FeatureDropdownInput, FeatureSliderInput, FeatureToggle, } from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; export const sound_ambience: FeatureToggle = { name: 'Enable ambience', diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/ui_style.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/ui_style.tsx index 218b5b3c5809c..d3fdc0b94de1c 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/ui_style.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/ui_style.tsx @@ -46,7 +46,6 @@ const UIStyleInput = ( = { name: 'Eye color', diff --git a/tgui/packages/tgui/interfaces/ProcCallMenu.tsx b/tgui/packages/tgui/interfaces/ProcCallMenu.tsx index 716ae19a14795..6db723bcfb423 100644 --- a/tgui/packages/tgui/interfaces/ProcCallMenu.tsx +++ b/tgui/packages/tgui/interfaces/ProcCallMenu.tsx @@ -45,7 +45,7 @@ export const ProcCallMenu = (props) => { @@ -139,7 +139,7 @@ const PortEntry = (props) => { { width="100%" options={sorted_assistance} selected={recipient} - displayText={recipient || 'Pick a Recipient'} + placeholder="Pick a Recipient" onSelected={(value) => setRecipient(value)} /> )} @@ -94,7 +94,7 @@ export const MessageWriteTab = (props) => { width="100%" options={sorted_supply} selected={recipient} - displayText={recipient || 'Pick a Recipient'} + placeholder="Pick a Recipient" onSelected={(value) => setRecipient(value)} /> )} @@ -103,7 +103,7 @@ export const MessageWriteTab = (props) => { width="100%" options={sorted_information} selected={recipient} - displayText={recipient || 'Pick a Recipient'} + placeholder="Pick a Recipient" onSelected={(value) => setRecipient(value)} /> )} diff --git a/tgui/packages/tgui/interfaces/StationTraitsPanel.tsx b/tgui/packages/tgui/interfaces/StationTraitsPanel.tsx index e6e7b02ce674b..8496d62552f62 100644 --- a/tgui/packages/tgui/interfaces/StationTraitsPanel.tsx +++ b/tgui/packages/tgui/interfaces/StationTraitsPanel.tsx @@ -34,7 +34,7 @@ const FutureStationTraitsPage = (props) => { const { act, data } = useBackend(); const { future_station_traits } = data; - const [selectedTrait, setSelectedTrait] = useState(); + const [selectedTrait, setSelectedTrait] = useState(''); const traitsByName = Object.fromEntries( data.valid_station_traits.map((trait) => { @@ -50,9 +50,9 @@ const FutureStationTraitsPage = (props) => { diff --git a/tgui/packages/tgui/interfaces/TramController.tsx b/tgui/packages/tgui/interfaces/TramController.tsx index 0fccd23a911cb..f787c8726b583 100644 --- a/tgui/packages/tgui/interfaces/TramController.tsx +++ b/tgui/packages/tgui/interfaces/TramController.tsx @@ -193,7 +193,7 @@ export const TramController = (props) => { width="98.5%" options={destinations.map((id) => id.name)} selected={tripDestination} - displayText={tripDestination || 'Pick a Destination'} + placeholder="Pick a Destination" onSelected={(value) => setTripDestination(value)} />
    - ); -}; - -/** - * Take entire supplies tree - * and return a flat supply pack list that matches search, - * sorted by name and only the first page. - * @param {any[]} supplies Supplies list. - * @param {string} search The search term - * @returns {any[]} The flat list of supply packs. - */ -const searchForSupplies = (supplies, search) => { - search = search.toLowerCase(); - - const queriedSupplies = sortBy( - filter( - supplies.flatMap((category) => category.packs), - (pack) => - pack.name?.toLowerCase().includes(search.toLowerCase()) || - pack.desc?.toLowerCase().includes(search.toLowerCase()), - ), - (pack) => pack.name, - ); - - return queriedSupplies.slice(0, 25); -}; - -export const CargoCatalog = (props) => { - const { express } = props; - const { act, data } = useBackend(); - - const { self_paid, app_cost } = data; - - const supplies = Object.values(data.supplies); - const { amount_by_name = [], max_order } = data; - - const [activeSupplyName, setActiveSupplyName] = useSharedState( - 'supply', - supplies[0]?.name, - ); - - const [searchText, setSearchText] = useSharedState('search_text', ''); - - const activeSupply = - activeSupplyName === 'search_results' - ? { packs: searchForSupplies(supplies, searchText) } - : supplies.find((supply) => supply.name === activeSupplyName); - - return ( -
    - - act('toggleprivate')} - /> - - ) - } - > - - - - - - - - - - { - if (value === searchText) { - return; - } - - if (value.length) { - // Start showing results - setActiveSupplyName('search_results'); - } else if (activeSupplyName === 'search_results') { - // return to normal category - setActiveSupplyName(supplies[0]?.name); - } - setSearchText(value); - }} - /> - - - - {supplies.map((supply) => ( - { - setActiveSupplyName(supply.name); - setSearchText(''); - }} - > - {supply.name} ({supply.packs.length}) - - ))} - - - - - {activeSupply?.packs.map((pack) => { - const tags = []; - if (pack.small_item) { - tags.push('Small'); - } - if (pack.access) { - tags.push('Restricted'); - } - return ( - - {pack.name} - - {tags.join(', ')} - - - - - - ); - })} -
    -
    -
    -
    - ); -}; - -const CargoRequests = (props) => { - const { act, data } = useBackend(); - const { requestonly, can_send, can_approve_requests } = data; - const requests = data.requests || []; - // Labeled list reimplementation to squeeze extra columns out of it - return ( -
    act('denyall')} - /> - ) - } - > - {requests.length === 0 && No Requests} - {requests.length > 0 && ( - - {requests.map((request) => ( - - - #{request.id} - - {request.object} - - {request.orderer} - - - {request.reason} - - - {formatMoney(request.cost)} cr - - {(!requestonly || can_send) && can_approve_requests && ( - -
    - )} -
    - ); -}; - -const CargoCartButtons = (props) => { - const { act, data } = useBackend(); - const { requestonly, can_send, can_approve_requests } = data; - const cart = data.cart || []; - const total = cart.reduce((total, entry) => total + entry.cost, 0); - return ( - <> - - {cart.length === 0 && 'Cart is empty'} - {cart.length === 1 && '1 item'} - {cart.length >= 2 && cart.length + ' items'}{' '} - {total > 0 && `(${formatMoney(total)} cr)`} - - {!requestonly && !!can_send && !!can_approve_requests && ( -
    - ); -}; - -const CargoHelp = (props) => { - return ( - <> -
    - Each department on the station will order crates from their own personal - consoles. These orders are ENTIRELY FREE! They do not come out of - cargo's budget, and rather put the consoles on cooldown. So - here's where you come in: The ordered crates will show up on your - supply console, and you need to deliver the crates to the orderers. - You'll actually be paid the full value of the department crate on - delivery if the crate was not tampered with, making the system a good - source of income. -
    - - Examine a department order crate to get specific details about where - the crate needs to go. - -
    -
    - MULEbots are slow but loyal delivery bots that will get crates delivered - with minimal technician effort required. It is slow, though, and can be - tampered with while en route. -
    - Setting up a MULEbot is easy: -
    - 1. Drag the crate you want to deliver next to the MULEbot. -
    - 2. Drag the crate on top of MULEbot. It should load on. -
    - 3. Open your PDA. -
    - 4. Click Delivery Bot Control.
    - 5. Click Scan for Active Bots.
    - 6. Choose your MULE. -
    - 7. Click on Destination: (set).
    - 8. Choose a destination and click OK. -
    - 9. Click Proceed. -
    -
    - In addition to MULEs and hand-deliveries, you can also make use of the - disposals mailing system. Note that a break in the disposal piping could - cause your package to be lost (this hardly ever happens), so this is not - always the most secure ways to deliver something. You can wrap up a - piece of paper and mail it the same way if you (or someone at the desk) - wants to mail a letter. -
    - Using the Disposals Delivery System is even easier: -
    - 1. Wrap your item/crate in packaging paper. -
    - 2. Use the destinations tagger to choose where to send it. -
    - 3. Tag the package. -
    - 4. Stick it on the conveyor and let the system handle it. -
    -
    - - Pondering something not included here? When in doubt, ask the QM! - - - ); -}; diff --git a/tgui/packages/tgui/interfaces/Cargo/CargoButtons.tsx b/tgui/packages/tgui/interfaces/Cargo/CargoButtons.tsx new file mode 100644 index 0000000000000..82c0d51a1f4c8 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Cargo/CargoButtons.tsx @@ -0,0 +1,39 @@ +import { useBackend } from '../../backend'; +import { Box, Button } from '../../components'; +import { formatMoney } from '../../format'; +import { CargoData } from './types'; + +export function CargoCartButtons(props) { + const { act, data } = useBackend(); + const { cart = [], requestonly, can_send, can_approve_requests } = data; + + let total = 0; + let amount = 0; + for (let i = 0; i < cart.length; i++) { + amount += cart[i].amount; + total += cart[i].cost; + } + + const canClear = + !requestonly && !!can_send && !!can_approve_requests && cart.length > 0; + + return ( + <> + + {amount === 0 && 'Cart is empty'} + {amount === 1 && '1 item'} + {amount >= 2 && amount + ' items'}{' '} + {total > 0 && `(${formatMoney(total)} cr)`} + + + + + ); +} diff --git a/tgui/packages/tgui/interfaces/Cargo/CargoCart.tsx b/tgui/packages/tgui/interfaces/Cargo/CargoCart.tsx new file mode 100644 index 0000000000000..473c33146d2ce --- /dev/null +++ b/tgui/packages/tgui/interfaces/Cargo/CargoCart.tsx @@ -0,0 +1,130 @@ +import { useBackend } from '../../backend'; +import { + Button, + Icon, + Input, + NoticeBox, + RestrictedInput, + Section, + Stack, + Table, +} from '../../components'; +import { formatMoney } from '../../format'; +import { CargoCartButtons } from './CargoButtons'; +import { CargoData } from './types'; + +export function CargoCart(props) { + const { act, data } = useBackend(); + const { requestonly, away, cart = [], docked, location } = data; + + const sendable = !away && !!docked; + + return ( + + +
    }> + +
    +
    + + {cart.length > 0 && !requestonly && ( +
    + + + {!sendable && } + + + + + +
    + )} +
    +
    + ); +} + +function CheckoutItems(props) { + const { act, data } = useBackend(); + const { amount_by_name, can_send, cart = [], max_order } = data; + + if (cart.length === 0) { + return Nothing in cart; + } + + return ( + + + ID + Supply Type + Amount + + + Cost + + + + {cart.map((entry) => ( + + + #{entry.id} + + {entry.object} + + + {can_send && entry.can_be_cancelled ? ( + + act('modify', { + order_name: entry.object, + amount: value, + }) + } + /> + ) : ( + + )} + + {!!can_send && !!entry.can_be_cancelled && ( + <> +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/Cargo/CargoCatalog.tsx b/tgui/packages/tgui/interfaces/Cargo/CargoCatalog.tsx new file mode 100644 index 0000000000000..115708410a4d8 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Cargo/CargoCatalog.tsx @@ -0,0 +1,234 @@ +import { sortBy } from 'common/collections'; +import { useMemo } from 'react'; + +import { useBackend, useSharedState } from '../../backend'; +import { + Button, + Icon, + Input, + Section, + Stack, + Table, + Tabs, + Tooltip, +} from '../../components'; +import { formatMoney } from '../../format'; +import { CargoCartButtons } from './CargoButtons'; +import { searchForSupplies } from './helpers'; +import { CargoData, Supply, SupplyCategory } from './types'; + +export function CargoCatalog(props) { + const { express } = props; + const { act, data } = useBackend(); + const { self_paid } = data; + + const supplies = Object.values(data.supplies); + + const [activeSupplyName, setActiveSupplyName] = useSharedState( + 'supply', + supplies[0]?.name, + ); + + const [searchText, setSearchText] = useSharedState('search_text', ''); + + const packs = useMemo(() => { + let fetched: Supply[] | undefined; + + if (activeSupplyName === 'search_results') { + fetched = searchForSupplies(supplies, searchText); + } else { + fetched = supplies.find( + (supply) => supply.name === activeSupplyName, + )?.packs; + } + + if (!fetched) return []; + + fetched = sortBy(fetched, (pack: Supply) => pack.name); + + return fetched; + }, [activeSupplyName, supplies, searchText]); + + return ( +
    + + + + ) + } + > + + + + + + + + + +
    + ); +} + +type CatalogTabsProps = { + activeSupplyName: string; + categories: SupplyCategory[]; + searchText: string; + setActiveSupplyName: (name: string) => void; + setSearchText: (text: string) => void; +}; + +function CatalogTabs(props: CatalogTabsProps) { + const { + activeSupplyName, + categories, + searchText, + setActiveSupplyName, + setSearchText, + } = props; + + const sorted = sortBy(categories, (supply) => supply.name); + + return ( + + + + + + + + { + if (value === searchText) { + return; + } + + if (value.length) { + // Start showing results + setActiveSupplyName('search_results'); + } else if (activeSupplyName === 'search_results') { + // return to normal category + setActiveSupplyName(sorted[0]?.name); + } + setSearchText(value); + }} + /> + + + + + {sorted.map((supply) => ( + { + setActiveSupplyName(supply.name); + setSearchText(''); + }} + > +
    + {supply.name} + {supply.packs.length} +
    +
    + ))} +
    + ); +} + +type CatalogListProps = { + packs: SupplyCategory['packs']; +}; + +function CatalogList(props: CatalogListProps) { + const { act, data } = useBackend(); + const { amount_by_name, max_order, self_paid, app_cost } = data; + const { packs = [] } = props; + + return ( +
    + + {packs.map((pack) => { + let color = ''; + const digits = Math.floor(Math.log10(pack.cost) + 1); + if (self_paid) { + color = 'caution'; + } else if (digits >= 5 && digits <= 6) { + color = 'yellow'; + } else if (digits > 6) { + color = 'bad'; + } + + return ( + + {pack.name} + + {!!pack.small_item && ( + + + + )} + + + {!!pack.access && ( + + + + )} + + + + + + ); + })} +
    +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/Cargo/CargoHelp.tsx b/tgui/packages/tgui/interfaces/Cargo/CargoHelp.tsx new file mode 100644 index 0000000000000..841ded71fb7e7 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Cargo/CargoHelp.tsx @@ -0,0 +1,80 @@ +import { Box, NoticeBox, Section, Stack } from '../../components'; + +const ORDER_TEXT = `Each department on the station will order crates from their own personal + consoles. These orders are ENTIRELY FREE! They do not come out of + cargo's budget, and rather put the consoles on cooldown. So + here's where you come in: The ordered crates will show up on your + supply console, and you need to deliver the crates to the orderers. + You'll actually be paid the full value of the department crate on + delivery if the crate was not tampered with, making the system a good + source of income.`; + +const DISPOSAL_TEXT = `In addition to MULEs and hand-deliveries, you can also make use of the + disposals mailing system. Note that a break in the disposal piping could + cause your package to be lost (this hardly ever happens), so this is not + always the most secure ways to deliver something. You can wrap up a + piece of paper and mail it the same way if you (or someone at the desk) + wants to mail a letter.`; + +export function CargoHelp(props) { + return ( + + +
    +
    + {ORDER_TEXT} +
    +
    + Examine a department order crate to get specific details about where + the crate needs to go. +
    +
    + + MULEbots are slow but loyal delivery bots that will get crates + delivered with minimal technician effort required. It is slow, + though, and can be tampered with while en route. + +
    + + Setting up a MULEbot is easy: + + 1. Drag the crate you want to deliver next to the MULEbot. +
    + 2. Drag the crate on top of MULEbot. It should load on. +
    + 3. Open your PDA. +
    + 4. Click Delivery Bot Control.
    + 5. Click Scan for Active Bots.
    + 6. Choose your MULE. +
    + 7. Click on Destination: (set).
    + 8. Choose a destination and click OK. +
    + 9. Click Proceed. +
    +
    + {DISPOSAL_TEXT} +
    + + Using the Disposals Delivery System is even easier: + + 1. Wrap your item/crate in packaging paper. +
    + 2. Use the destinations tagger to choose where to send it. +
    + 3. Tag the package. +
    + 4. Stick it on the conveyor and let the system handle it. +
    +
    +
    +
    + + + Pondering something not included here? When in doubt, ask the QM! + + +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/Cargo/CargoRequests.tsx b/tgui/packages/tgui/interfaces/Cargo/CargoRequests.tsx new file mode 100644 index 0000000000000..3a53efb45e980 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Cargo/CargoRequests.tsx @@ -0,0 +1,85 @@ +import { decodeHtmlEntities } from 'common/string'; + +import { useBackend } from '../../backend'; +import { Button, NoticeBox, Section, Table } from '../../components'; +import { TableCell, TableRow } from '../../components/Table'; +import { formatMoney } from '../../format'; +import { CargoData } from './types'; + +export function CargoRequests(props) { + const { act, data } = useBackend(); + const { requests = [], requestonly, can_send, can_approve_requests } = data; + + return ( +
    act('denyall')} + > + Clear + + ) + } + > + {requests.length === 0 && No Requests} + {requests.length > 0 && ( + + + ID + Object + Orderer + Reason + Cost + {(!requestonly || !!can_send) && !!can_approve_requests && ( + Actions + )} + + + {requests.map((request) => ( + + #{request.id} + {request.object} + + {request.orderer} + + + {decodeHtmlEntities(request.reason)} + + + {formatMoney(request.cost)} cr + + {(!requestonly || !!can_send) && !!can_approve_requests && ( + +
    + )} +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/Cargo/CargoStatus.tsx b/tgui/packages/tgui/interfaces/Cargo/CargoStatus.tsx new file mode 100644 index 0000000000000..b230400e4e3f9 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Cargo/CargoStatus.tsx @@ -0,0 +1,75 @@ +import { useBackend } from '../../backend'; +import { + AnimatedNumber, + Box, + Button, + LabeledList, + Section, +} from '../../components'; +import { formatMoney } from '../../format'; +import { CargoData } from './types'; + +export function CargoStatus(props) { + const { act, data } = useBackend(); + const { + department, + grocery, + away, + docked, + loan, + loan_dispatched, + location, + message, + points, + requestonly, + can_send, + } = data; + + return ( +
    + formatMoney(value)} + /> + {' credits'} + + } + > + + + {!!docked && !requestonly && !!can_send ? ( + + ) : ( + String(location) + )} + + {message} + {!!loan && !requestonly && ( + + {!loan_dispatched ? ( + + ) : ( + Loaned to Centcom + )} + + )} + +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/Cargo/helpers.ts b/tgui/packages/tgui/interfaces/Cargo/helpers.ts new file mode 100644 index 0000000000000..e6b67f8ff6dd1 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Cargo/helpers.ts @@ -0,0 +1,35 @@ +import { filter } from 'common/collections'; +import { flow } from 'common/fp'; + +import { Supply, SupplyCategory } from './types'; + +/** + * Take entire supplies tree + * and return a flat supply pack list that matches search, + * sorted by name and only the first page. + * @param {Supply[]} supplies Supplies list, aka Object.values(data.supplies) + * @param {string} search The search term + * @returns {Supply[]} The flat list of supply packs. + */ +export function searchForSupplies( + supplies: SupplyCategory[], + search: string, +): Supply[] { + const lowerSearch = search.toLowerCase(); + + return flow([ + // Flat categories + (initialSupplies: SupplyCategory[]) => + initialSupplies.flatMap((category) => category.packs), + // Filter by name or desc + (flatMapped: Supply[]) => + filter( + flatMapped, + (pack: Supply) => + pack.name?.toLowerCase().includes(lowerSearch) || + pack.desc?.toLowerCase().includes(lowerSearch), + ), + // Just the first page + (filtered: Supply[]) => filtered.slice(0, 25), + ])(supplies); +} diff --git a/tgui/packages/tgui/interfaces/Cargo/index.tsx b/tgui/packages/tgui/interfaces/Cargo/index.tsx new file mode 100644 index 0000000000000..d39435f4cd953 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Cargo/index.tsx @@ -0,0 +1,91 @@ +import { useBackend, useSharedState } from '../../backend'; +import { Stack, Tabs } from '../../components'; +import { Window } from '../../layouts'; +import { CargoCart } from './CargoCart'; +import { CargoCatalog } from './CargoCatalog'; +import { CargoHelp } from './CargoHelp'; +import { CargoRequests } from './CargoRequests'; +import { CargoStatus } from './CargoStatus'; +import { CargoData } from './types'; + +enum TAB { + Catalog = 'catalog', + Requests = 'requests', + Cart = 'cart', + Help = 'help', +} + +export function Cargo(props) { + return ( + + + + + + ); +} + +export function CargoContent(props) { + const { data } = useBackend(); + + const { cart = [], requests = [], requestonly } = data; + + const [tab, setTab] = useSharedState('cargotab', TAB.Catalog); + + let amount = 0; + for (let i = 0; i < cart.length; i++) { + amount += cart[i].amount; + } + + return ( + + + + + + + setTab(TAB.Catalog)} + > + Catalog + + 0 && 'yellow'} + selected={tab === TAB.Requests} + onClick={() => setTab(TAB.Requests)} + > + Requests ({requests.length}) + + {!requestonly && ( + <> + 0 && 'yellow'} + selected={tab === TAB.Cart} + onClick={() => setTab(TAB.Cart)} + > + Checkout ({amount}) + + setTab(TAB.Help)} + > + Help + + + )} + + + + {tab === TAB.Catalog && } + {tab === TAB.Requests && } + {tab === TAB.Cart && } + {tab === TAB.Help && } + + + ); +} diff --git a/tgui/packages/tgui/interfaces/Cargo/types.ts b/tgui/packages/tgui/interfaces/Cargo/types.ts new file mode 100644 index 0000000000000..5cb70838cbd65 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Cargo/types.ts @@ -0,0 +1,58 @@ +import { BooleanLike } from 'common/react'; + +export type CargoData = { + amount_by_name: Record; + app_cost?: number; + away: BooleanLike; + can_approve_requests: BooleanLike; + can_send: BooleanLike; + cart: CartEntry[]; + department: string; + docked: BooleanLike; + grocery: number; + loan_dispatched: BooleanLike; + loan: BooleanLike; + location: string; + max_order: number; + message: string; + points: number; + requests: Request[]; + requestonly: BooleanLike; + self_paid: BooleanLike; + supplies: Record; +}; + +export type SupplyCategory = { + name: string; + packs: Supply[]; +}; + +export type Supply = { + access: BooleanLike; + cost: number; + desc: string; + goody: BooleanLike; + id: string; + name: string; + small_item: BooleanLike; +}; + +type CartEntry = { + amount: number; + can_be_cancelled: BooleanLike; + cost_type: string; + cost: number; + dep_order: BooleanLike; + id: string; + object: string; + orderer: string; + paid: BooleanLike; +}; + +type Request = { + cost: number; + id: string; + object: string; + orderer: string; + reason: string; +}; diff --git a/tgui/packages/tgui/interfaces/CargoExpress.tsx b/tgui/packages/tgui/interfaces/CargoExpress.tsx index 0983e685f7d2e..83947b5adc473 100644 --- a/tgui/packages/tgui/interfaces/CargoExpress.tsx +++ b/tgui/packages/tgui/interfaces/CargoExpress.tsx @@ -9,7 +9,7 @@ import { Section, } from '../components'; import { Window } from '../layouts'; -import { CargoCatalog } from './Cargo'; +import { CargoCatalog } from './Cargo/CargoCatalog'; import { InterfaceLockNoticeBox } from './common/InterfaceLockNoticeBox'; type Data = { @@ -24,7 +24,7 @@ type Data = { message: string; }; -export const CargoExpress = (props) => { +export function CargoExpress(props) { const { data } = useBackend(); const { locked } = data; @@ -36,9 +36,9 @@ export const CargoExpress = (props) => { ); -}; +} -const CargoExpressContent = (props) => { +function CargoExpressContent(props) { const { act, data } = useBackend(); const { hasBeacon, @@ -64,11 +64,9 @@ const CargoExpressContent = (props) => { > - - {message} @@ -88,4 +84,4 @@ const CargoExpressContent = (props) => { ); -}; +} From 95061207c509644fdd289cf4ae55fcdd9e00ebd7 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 23 Apr 2024 10:56:38 +1200 Subject: [PATCH 421/938] Automatic changelog for PR #82745 [ci skip] --- html/changelogs/AutoChangeLog-pr-82745.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82745.yml diff --git a/html/changelogs/AutoChangeLog-pr-82745.yml b/html/changelogs/AutoChangeLog-pr-82745.yml new file mode 100644 index 0000000000000..2972c0582fcd1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82745.yml @@ -0,0 +1,4 @@ +author: "jlsnow301" +delete-after: True +changes: + - bugfix: "Cargo's supply console has been upgraded visually." \ No newline at end of file From c165c0587564bd992a75de04a4800472b9e890cf Mon Sep 17 00:00:00 2001 From: FlufflesTheDog Date: Mon, 22 Apr 2024 16:43:55 -0700 Subject: [PATCH 422/938] Makes lavaland stone tiles prevent immersion (#82807) ## About The Pull Request Adds the same trait that lavaproof rods have to the stone tiles, so things can continue being visually outside of the lava ## Why It's Good For The Game this shit looks goofy ![324271923-9c1e353d-70ff-4321-839c-8bac2fd03c01](https://github.com/tgstation/tgstation/assets/25628932/d120458d-8f65-418c-a0c8-7d1f939a472b) ## Changelog :cl: FlufflesTheDog fix: Stone tiles (and things on them) no longer get immersed in lava /:cl: --- code/modules/mapfluff/ruins/objects_and_mobs/necropolis_gate.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mapfluff/ruins/objects_and_mobs/necropolis_gate.dm b/code/modules/mapfluff/ruins/objects_and_mobs/necropolis_gate.dm index 6ce6056b477e7..8dc9cec326d95 100644 --- a/code/modules/mapfluff/ruins/objects_and_mobs/necropolis_gate.dm +++ b/code/modules/mapfluff/ruins/objects_and_mobs/necropolis_gate.dm @@ -262,7 +262,7 @@ GLOBAL_DATUM(necropolis_gate, /obj/structure/necropolis_gate/legion_gate) var/static/list/give_turf_traits if(!give_turf_traits) - give_turf_traits = string_list(list(TRAIT_LAVA_STOPPED, TRAIT_CHASM_STOPPED)) + give_turf_traits = string_list(list(TRAIT_LAVA_STOPPED, TRAIT_CHASM_STOPPED, TRAIT_IMMERSE_STOPPED)) AddElement(/datum/element/give_turf_traits, give_turf_traits) /obj/structure/stone_tile/singularity_pull() From 8ca3064a5cc2e4e97ed57c91a020738631bafc20 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 23 Apr 2024 11:44:15 +1200 Subject: [PATCH 423/938] Automatic changelog for PR #82807 [ci skip] --- html/changelogs/AutoChangeLog-pr-82807.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82807.yml diff --git a/html/changelogs/AutoChangeLog-pr-82807.yml b/html/changelogs/AutoChangeLog-pr-82807.yml new file mode 100644 index 0000000000000..ac650c82dfe97 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82807.yml @@ -0,0 +1,4 @@ +author: "FlufflesTheDog" +delete-after: True +changes: + - bugfix: "Stone tiles (and things on them) no longer get immersed in lava" \ No newline at end of file From 72ba08caf92280a8f77ce60ac15ee9ea6928542f Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Mon, 22 Apr 2024 18:46:46 -0500 Subject: [PATCH 424/938] Getting up from prone, z movement, and mod de/activation don't do cogwheels (#82794) ## About The Pull Request Adds `hidden` to getting up (from prone), moving up (z-movement), moving down (z-movement), and de/activating MODsuits ## Why It's Good For The Game - Getting up from prone happens very often, makes it a bit hard to differentiate when people are doing actions or just crawling around. - If we want feedback for getting up, should just be a chat message. - Moving up and down is just movement. Only affects using the verbs. - Same as before: If we want feedback, it should just be a chat message. - Other methods of moving up/down (IE, ladders) are untouched / retain their cogwheel. - De/activating modsuits have their own visual feedback and sound effects associated. Both feels unnecessary. ## Changelog :cl: Melbert qol: Getting up from prone, moving up or down a z-level (not via ladders, naturally. Like flight), and de/activating your modsuit no longer shows cogwheel effect /:cl: --- code/modules/mob/living/living.dm | 2 +- code/modules/mob/mob_movement.dm | 4 ++-- code/modules/mod/mod_activation.dm | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index c901c657b658f..dc6cc7bd82052 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -669,7 +669,7 @@ /mob/living/proc/get_up(instant = FALSE) set waitfor = FALSE - if(!instant && !do_after(src, 1 SECONDS, src, timed_action_flags = (IGNORE_USER_LOC_CHANGE|IGNORE_TARGET_LOC_CHANGE|IGNORE_HELD_ITEM), extra_checks = CALLBACK(src, TYPE_PROC_REF(/mob/living, rest_checks_callback)), interaction_key = DOAFTER_SOURCE_GETTING_UP)) + if(!instant && !do_after(src, 1 SECONDS, src, timed_action_flags = (IGNORE_USER_LOC_CHANGE|IGNORE_TARGET_LOC_CHANGE|IGNORE_HELD_ITEM), extra_checks = CALLBACK(src, TYPE_PROC_REF(/mob/living, rest_checks_callback)), interaction_key = DOAFTER_SOURCE_GETTING_UP, hidden = TRUE)) return if(resting || body_position == STANDING_UP || HAS_TRAIT(src, TRAIT_FLOORED)) return diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 11140a7dde397..ea6a994f73333 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -540,7 +540,7 @@ to_chat(src, span_warning("You are not Superman.")) return balloon_alert(src, "moving up...") - if(!do_after(src, 1 SECONDS)) + if(!do_after(src, 1 SECONDS, hidden = TRUE)) return if(zMove(UP, z_move_flags = ZMOVE_FLIGHT_FLAGS|ZMOVE_FEEDBACK|ventcrawling_flag)) to_chat(src, span_notice("You move upwards.")) @@ -566,7 +566,7 @@ var/ventcrawling_flag = HAS_TRAIT(src, TRAIT_MOVE_VENTCRAWLING) ? ZMOVE_VENTCRAWLING : 0 balloon_alert(src, "moving down...") - if(!do_after(src, 1 SECONDS)) + if(!do_after(src, 1 SECONDS, hidden = TRUE)) return if(zMove(DOWN, z_move_flags = ZMOVE_FLIGHT_FLAGS|ZMOVE_FEEDBACK|ventcrawling_flag)) to_chat(src, span_notice("You move down.")) diff --git a/code/modules/mod/mod_activation.dm b/code/modules/mod/mod_activation.dm index 9e5b8ea5277ed..f95125d2a6e17 100644 --- a/code/modules/mod/mod_activation.dm +++ b/code/modules/mod/mod_activation.dm @@ -163,23 +163,23 @@ to_chat(wearer, span_notice("MODsuit [active ? "shutting down" : "starting up"].")) if (ai_assistant) to_chat(ai_assistant, span_notice("MODsuit [active ? "shutting down" : "starting up"].")) - if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)))) + if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)), hidden = TRUE)) to_chat(wearer, span_notice("[boots] [active ? "relax their grip on your legs" : "seal around your feet"].")) playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) seal_part(boots, seal = !active) - if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)))) + if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)), hidden = TRUE)) to_chat(wearer, span_notice("[gauntlets] [active ? "become loose around your fingers" : "tighten around your fingers and wrists"].")) playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) seal_part(gauntlets, seal = !active) - if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)))) + if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)), hidden = TRUE)) to_chat(wearer, span_notice("[chestplate] [active ? "releases your chest" : "cinches tightly against your chest"].")) playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) seal_part(chestplate, seal = !active) - if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)))) + if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)), hidden = TRUE)) to_chat(wearer, span_notice("[helmet] hisses [active ? "open" : "closed"].")) playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) seal_part(helmet, seal = !active) - if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)))) + if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)), hidden = TRUE)) to_chat(wearer, span_notice("Systems [active ? "shut down. Parts unsealed. Goodbye" : "started up. Parts sealed. Welcome"], [wearer].")) if(ai_assistant) to_chat(ai_assistant, span_notice("SYSTEMS [active ? "DEACTIVATED. GOODBYE" : "ACTIVATED. WELCOME"]: \"[ai_assistant]\"")) From 88813ffa2afdd2ba6f403b48f1cfb7c777a803a0 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 23 Apr 2024 11:47:05 +1200 Subject: [PATCH 425/938] Automatic changelog for PR #82794 [ci skip] --- html/changelogs/AutoChangeLog-pr-82794.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82794.yml diff --git a/html/changelogs/AutoChangeLog-pr-82794.yml b/html/changelogs/AutoChangeLog-pr-82794.yml new file mode 100644 index 0000000000000..43e2a51a0c5f5 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82794.yml @@ -0,0 +1,4 @@ +author: "Melbert" +delete-after: True +changes: + - qol: "Getting up from prone, moving up or down a z-level (not via ladders, naturally. Like flight), and de/activating your modsuit no longer shows cogwheel effect" \ No newline at end of file From 2569062022580d7304312873451a54409e36b6b6 Mon Sep 17 00:00:00 2001 From: Pickle-Coding <58013024+Pickle-Coding@users.noreply.github.com> Date: Tue, 23 Apr 2024 00:56:39 +0100 Subject: [PATCH 426/938] [NO GBP]Inversely scale mechanical favor with STANDARD_CELL_CHARGE. (#82801) ## About The Pull Request Makes the mechanical sect cell sacrifice favor adjustment inversely scale with STANDARD_CELL_CHARGE. This reduces it by a factor of 1,000. ## Why It's Good For The Game So they don't get 1,000 times the favor as intended from a cell. ## Changelog :cl: fix: Fixes mechanical sect gaining 1,000 times the favor from a cell sacrifice. /:cl: --- code/modules/religion/religion_sects.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/religion/religion_sects.dm b/code/modules/religion/religion_sects.dm index 16cd82c5650fa..5d5d3909ec759 100644 --- a/code/modules/religion/religion_sects.dm +++ b/code/modules/religion/religion_sects.dm @@ -200,11 +200,11 @@ if(!istype(power_cell)) return - if(power_cell.charge < 0.3 * STANDARD_CELL_CHARGE) + if(power_cell.charge() < 0.3 * STANDARD_CELL_CHARGE) to_chat(chap, span_notice("[GLOB.deity] does not accept pity amounts of power.")) return - adjust_favor(round(power_cell.charge/300), chap) + adjust_favor(round(power_cell.charge() / (0.3 * STANDARD_CELL_CHARGE)), chap) to_chat(chap, span_notice("You offer [power_cell]'s power to [GLOB.deity], pleasing them.")) qdel(power_cell) return TRUE From 474d8705e644407db092f8ed0fcda1bf1cc1b3ee Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 23 Apr 2024 11:56:58 +1200 Subject: [PATCH 427/938] Automatic changelog for PR #82801 [ci skip] --- html/changelogs/AutoChangeLog-pr-82801.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82801.yml diff --git a/html/changelogs/AutoChangeLog-pr-82801.yml b/html/changelogs/AutoChangeLog-pr-82801.yml new file mode 100644 index 0000000000000..aa1faf3e0cddd --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82801.yml @@ -0,0 +1,4 @@ +author: "Pickle-Coding" +delete-after: True +changes: + - bugfix: "Fixes mechanical sect gaining 1,000 times the favor from a cell sacrifice." \ No newline at end of file From 176253ce6a268bb169ba2def6f9d45f039041fd5 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Tue, 23 Apr 2024 00:21:24 +0000 Subject: [PATCH 428/938] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-82611.yml | 7 ----- html/changelogs/AutoChangeLog-pr-82670.yml | 6 ---- html/changelogs/AutoChangeLog-pr-82699.yml | 4 --- html/changelogs/AutoChangeLog-pr-82745.yml | 4 --- html/changelogs/AutoChangeLog-pr-82762.yml | 4 --- html/changelogs/AutoChangeLog-pr-82794.yml | 4 --- html/changelogs/AutoChangeLog-pr-82801.yml | 4 --- html/changelogs/AutoChangeLog-pr-82807.yml | 4 --- html/changelogs/archive/2024-04.yml | 32 ++++++++++++++++++++++ 9 files changed, 32 insertions(+), 37 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-82611.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82670.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82699.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82745.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82762.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82794.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82801.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-82807.yml diff --git a/html/changelogs/AutoChangeLog-pr-82611.yml b/html/changelogs/AutoChangeLog-pr-82611.yml deleted file mode 100644 index 09bb226fadc6b..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82611.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: "necromanceranne" -delete-after: True -changes: - - rscadd: "Replaces Fitness with Athletics; same skill, but now more specifically applicable to boxing." - - rscadd: "Athletics does not increase sprite size." - - balance: "Overhauls Boxing to add a lot more depth to the interactions. Only applicable to other boxers, however. You can still punch the snot out of non-boxers though. But only up to stamcrit or unconsciousness. No hitting someone who can't fight back!" - - balance: "Adds Evil Boxing, which is the evil and fucked up version of boxing that you kill people with and are allowed to flout the sacred rules of boxing as you please. Everyone is a victim!" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82670.yml b/html/changelogs/AutoChangeLog-pr-82670.yml deleted file mode 100644 index 59ca950099ca8..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82670.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "EvilDragonfiend" -delete-after: True -changes: - - code_imp: "/appearance type references are now investigatable in vv editor." - - code_imp: "/image references display a summarised name with its dmi file name and icon_state when it's investigated from a datum where it uses. Format is: \"mob_hud_image = /image (hud.dmi:medical) [0x00000]\"" - - code_imp: "/image types no longer show first image incorrectly when its icon_state is null" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82699.yml b/html/changelogs/AutoChangeLog-pr-82699.yml deleted file mode 100644 index ea66e0a3a2715..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82699.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SyncIt21" -delete-after: True -changes: - - bugfix: "Fixes runtime in advanced camera console when power is turned off" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82745.yml b/html/changelogs/AutoChangeLog-pr-82745.yml deleted file mode 100644 index 2972c0582fcd1..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82745.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "jlsnow301" -delete-after: True -changes: - - bugfix: "Cargo's supply console has been upgraded visually." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82762.yml b/html/changelogs/AutoChangeLog-pr-82762.yml deleted file mode 100644 index a8f83d5d870e8..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82762.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "san7890" -delete-after: True -changes: - - bugfix: "Evolved aliens should no longer have two numbers in their name." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82794.yml b/html/changelogs/AutoChangeLog-pr-82794.yml deleted file mode 100644 index 43e2a51a0c5f5..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82794.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Melbert" -delete-after: True -changes: - - qol: "Getting up from prone, moving up or down a z-level (not via ladders, naturally. Like flight), and de/activating your modsuit no longer shows cogwheel effect" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82801.yml b/html/changelogs/AutoChangeLog-pr-82801.yml deleted file mode 100644 index aa1faf3e0cddd..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82801.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Pickle-Coding" -delete-after: True -changes: - - bugfix: "Fixes mechanical sect gaining 1,000 times the favor from a cell sacrifice." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-82807.yml b/html/changelogs/AutoChangeLog-pr-82807.yml deleted file mode 100644 index ac650c82dfe97..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82807.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "FlufflesTheDog" -delete-after: True -changes: - - bugfix: "Stone tiles (and things on them) no longer get immersed in lava" \ No newline at end of file diff --git a/html/changelogs/archive/2024-04.yml b/html/changelogs/archive/2024-04.yml index fec166a045a94..cfe39417701e7 100644 --- a/html/changelogs/archive/2024-04.yml +++ b/html/changelogs/archive/2024-04.yml @@ -715,3 +715,35 @@ vinylspiders: - bugfix: dropdowns that use display_names as an alias for numeric values will no longer cause tgui bluescreens +2024-04-23: + EvilDragonfiend: + - code_imp: /appearance type references are now investigatable in vv editor. + - code_imp: '/image references display a summarised name with its dmi file name + and icon_state when it''s investigated from a datum where it uses. Format is: + "mob_hud_image = /image (hud.dmi:medical) [0x00000]"' + - code_imp: /image types no longer show first image incorrectly when its icon_state + is null + FlufflesTheDog: + - bugfix: Stone tiles (and things on them) no longer get immersed in lava + Melbert: + - qol: Getting up from prone, moving up or down a z-level (not via ladders, naturally. + Like flight), and de/activating your modsuit no longer shows cogwheel effect + Pickle-Coding: + - bugfix: Fixes mechanical sect gaining 1,000 times the favor from a cell sacrifice. + SyncIt21: + - bugfix: Fixes runtime in advanced camera console when power is turned off + jlsnow301: + - bugfix: Cargo's supply console has been upgraded visually. + necromanceranne: + - rscadd: Replaces Fitness with Athletics; same skill, but now more specifically + applicable to boxing. + - rscadd: Athletics does not increase sprite size. + - balance: Overhauls Boxing to add a lot more depth to the interactions. Only applicable + to other boxers, however. You can still punch the snot out of non-boxers though. + But only up to stamcrit or unconsciousness. No hitting someone who can't fight + back! + - balance: Adds Evil Boxing, which is the evil and fucked up version of boxing that + you kill people with and are allowed to flout the sacred rules of boxing as + you please. Everyone is a victim! + san7890: + - bugfix: Evolved aliens should no longer have two numbers in their name. From b218130a2c92e5da10d1f39f23256758ef503edc Mon Sep 17 00:00:00 2001 From: Zephyr <12817816+ZephyrTFA@users.noreply.github.com> Date: Mon, 22 Apr 2024 21:02:24 -0400 Subject: [PATCH 429/938] Converts ListInputModal to actually be a Modal | Adds ListInputWindow which uses it (#82792) ## About The Pull Request If we say something is a Modal it should actually be a Modal ## Why It's Good For The Game You can now use this system in other windows if you want. Fixed the misnomer. --------- Co-authored-by: Jeremiah <42397676+jlsnow301@users.noreply.github.com> --- code/modules/tgui_input/list.dm | 2 +- .../{ => ListInputWindow}/ListInputModal.tsx | 172 ++++++++---------- .../tgui/interfaces/ListInputWindow/index.tsx | 44 +++++ .../tgui/interfaces/common/InputButtons.tsx | 23 ++- 4 files changed, 144 insertions(+), 97 deletions(-) rename tgui/packages/tgui/interfaces/{ => ListInputWindow}/ListInputModal.tsx (57%) create mode 100644 tgui/packages/tgui/interfaces/ListInputWindow/index.tsx diff --git a/code/modules/tgui_input/list.dm b/code/modules/tgui_input/list.dm index 174f16fc7b57c..22c6d48edfc5a 100644 --- a/code/modules/tgui_input/list.dm +++ b/code/modules/tgui_input/list.dm @@ -111,7 +111,7 @@ /datum/tgui_list_input/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, "ListInputModal") + ui = new(user, src, "ListInputWindow") ui.open() /datum/tgui_list_input/ui_close(mob/user) diff --git a/tgui/packages/tgui/interfaces/ListInputModal.tsx b/tgui/packages/tgui/interfaces/ListInputWindow/ListInputModal.tsx similarity index 57% rename from tgui/packages/tgui/interfaces/ListInputModal.tsx rename to tgui/packages/tgui/interfaces/ListInputWindow/ListInputModal.tsx index 8695ac842f72e..a56363f231097 100644 --- a/tgui/packages/tgui/interfaces/ListInputModal.tsx +++ b/tgui/packages/tgui/interfaces/ListInputWindow/ListInputModal.tsx @@ -7,35 +7,26 @@ import { KEY_ESCAPE, KEY_UP, KEY_Z, -} from '../../common/keycodes'; -import { useBackend } from '../backend'; -import { Autofocus, Button, Input, Section, Stack } from '../components'; -import { Window } from '../layouts'; -import { InputButtons } from './common/InputButtons'; -import { Loader } from './common/Loader'; +} from '../../../common/keycodes'; +import { useBackend } from '../../backend'; +import { Autofocus, Button, Input, Section, Stack } from '../../components'; +import { InputButtons } from '../common/InputButtons'; -type ListInputData = { - init_value: string; +type ListInputModalProps = { items: string[]; - large_buttons: boolean; + default_item: string; message: string; - timeout: number; - title: string; + on_selected: (entry: string) => void; + on_cancel: () => void; }; -export const ListInputModal = (props) => { - const { act, data } = useBackend(); - const { - items = [], - message = '', - init_value, - large_buttons, - timeout, - title, - } = data; - const [selected, setSelected] = useState(items.indexOf(init_value)); +export const ListInputModal = (props: ListInputModalProps) => { + const { items = [], default_item, message, on_selected, on_cancel } = props; + + const [selected, setSelected] = useState(items.indexOf(default_item)); const [searchBarVisible, setSearchBarVisible] = useState(items.length > 9); const [searchQuery, setSearchQuery] = useState(''); + // User presses up or down on keyboard // Simulates clicking an item const onArrowKey = (key: number) => { @@ -99,82 +90,77 @@ export const ListInputModal = (props) => { const filteredItems = items.filter((item) => item?.toLowerCase().includes(searchQuery.toLowerCase()), ); - // Dynamically changes the window height based on the message. - const windowHeight = - 325 + Math.ceil(message.length / 3) + (large_buttons ? 5 : 0); // Grabs the cursor when no search bar is visible. if (!searchBarVisible) { setTimeout(() => document!.getElementById(selected.toString())?.focus(), 1); } return ( - - {timeout && } - { - const keyCode = window.event ? event.which : event.keyCode; - if (keyCode === KEY_DOWN || keyCode === KEY_UP) { - event.preventDefault(); - onArrowKey(keyCode); - } - if (keyCode === KEY_ENTER) { - event.preventDefault(); - act('submit', { entry: filteredItems[selected] }); - } - if (!searchBarVisible && keyCode >= KEY_A && keyCode <= KEY_Z) { - event.preventDefault(); - onLetterSearch(keyCode); - } - if (keyCode === KEY_ESCAPE) { - event.preventDefault(); - act('cancel'); - } - }} - > -
    onSearchBarToggle()} - /> +
    { + const keyCode = window.event ? event.which : event.keyCode; + if (keyCode === KEY_DOWN || keyCode === KEY_UP) { + event.preventDefault(); + onArrowKey(keyCode); + } + if (keyCode === KEY_ENTER) { + event.preventDefault(); + on_selected(filteredItems[selected]); + } + if (!searchBarVisible && keyCode >= KEY_A && keyCode <= KEY_Z) { + event.preventDefault(); + onLetterSearch(keyCode); + } + if (keyCode === KEY_ESCAPE) { + event.preventDefault(); + on_cancel(); + } + }} + buttons={ +
    - - + tooltipPosition="left" + onClick={() => onSearchBarToggle()} + /> + } + className="ListInput__Section" + fill + title={message} + > + + + + + {searchBarVisible && ( + + )} + + on_selected(filteredItems[selected])} + on_cancel={on_cancel} + /> + + +
    ); }; @@ -183,7 +169,7 @@ export const ListInputModal = (props) => { * If a search query is provided, filters the items. */ const ListDisplay = (props) => { - const { act } = useBackend(); + const { act } = useBackend(); const { filteredItems, onClick, onFocusSearch, searchBarVisible, selected } = props; @@ -227,7 +213,7 @@ const ListDisplay = (props) => { * Closing the bar defaults input to an empty string. */ const SearchBar = (props) => { - const { act } = useBackend(); + const { act } = useBackend(); const { filteredItems, onSearch, searchQuery, selected } = props; return ( diff --git a/tgui/packages/tgui/interfaces/ListInputWindow/index.tsx b/tgui/packages/tgui/interfaces/ListInputWindow/index.tsx new file mode 100644 index 0000000000000..29355ff5d213f --- /dev/null +++ b/tgui/packages/tgui/interfaces/ListInputWindow/index.tsx @@ -0,0 +1,44 @@ +import { useBackend } from '../../backend'; +import { Window } from '../../layouts'; +import { Loader } from '../common/Loader'; +import { ListInputModal } from './ListInputModal'; + +type ListInputData = { + init_value: string; + items: string[]; + large_buttons: boolean; + message: string; + timeout: number; + title: string; +}; + +export const ListInputWindow = () => { + const { act, data } = useBackend(); + const { + items = [], + message = '', + init_value, + large_buttons, + timeout, + title, + } = data; + + // Dynamically changes the window height based on the message. + const windowHeight = + 325 + Math.ceil(message.length / 3) + (large_buttons ? 5 : 0); + + return ( + + {timeout && } + + act('submit', { entry })} + on_cancel={() => act('cancel')} + /> + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/common/InputButtons.tsx b/tgui/packages/tgui/interfaces/common/InputButtons.tsx index aad3d92f081fb..aa74ff1fdc017 100644 --- a/tgui/packages/tgui/interfaces/common/InputButtons.tsx +++ b/tgui/packages/tgui/interfaces/common/InputButtons.tsx @@ -8,19 +8,36 @@ type InputButtonsData = { type InputButtonsProps = { input: string | number | string[]; + on_submit?: () => void; + on_cancel?: () => void; message?: string; }; export const InputButtons = (props: InputButtonsProps) => { const { act, data } = useBackend(); const { large_buttons, swapped_buttons } = data; - const { input, message } = props; + const { input, message, on_submit, on_cancel } = props; + + let on_submit_actual = on_submit; + if (!on_submit_actual) { + on_submit_actual = () => { + act('submit', { entry: input }); + }; + } + + let on_cancel_actual = on_cancel; + if (!on_cancel_actual) { + on_cancel_actual = () => { + act('cancel'); + }; + } + const submitButton = ( - - - - - -
    -
    - - {sortedSubsystems.map((subsystem) => ( - - ))} - -
    - - - ); -}; diff --git a/tgui/packages/tgui/interfaces/ControllerOverview/OverviewSection.tsx b/tgui/packages/tgui/interfaces/ControllerOverview/OverviewSection.tsx new file mode 100644 index 0000000000000..919c19631f6fc --- /dev/null +++ b/tgui/packages/tgui/interfaces/ControllerOverview/OverviewSection.tsx @@ -0,0 +1,57 @@ +import { useBackend } from '../../backend'; +import { Button, LabeledList, Section, Stack } from '../../components'; +import { ControllerData } from './types'; + +export function OverviewSection(props) { + const { act, data } = useBackend(); + const { fast_update, map_cpu, subsystems = [], world_time } = data; + + let overallUsage = 0; + let overallOverrun = 0; + for (let i = 0; i < subsystems.length; i++) { + overallUsage += subsystems[i].tick_usage; + overallOverrun += subsystems[i].tick_overrun; + } + + return ( +
    { + act('toggle_fast_update'); + }} + > + Fast + + } + > + + + + + {world_time.toFixed(1)} + + + {map_cpu.toFixed(2)}% + + + + + + + {(overallUsage * 0.01).toFixed(2)}% + + + {(overallOverrun * 0.01).toFixed(2)}% + + + + +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/ControllerOverview/SubsystemDialog.tsx b/tgui/packages/tgui/interfaces/ControllerOverview/SubsystemDialog.tsx new file mode 100644 index 0000000000000..21acd2dca1d95 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ControllerOverview/SubsystemDialog.tsx @@ -0,0 +1,69 @@ +import { + Box, + Button, + Divider, + LabeledList, + Modal, + Stack, +} from '../../components'; +import { SubsystemData } from './types'; + +type Props = { + subsystem: SubsystemData; + onClose: () => void; +}; + +export function SubsystemDialog(props: Props) { + const { subsystem, onClose } = props; + const { + cost_ms, + init_order, + initialization_failure_message, + last_fire, + name, + next_fire, + tick_overrun, + tick_usage, + } = subsystem; + + return ( + + + + {name} + + + + + + + ); +} diff --git a/tgui/packages/tgui/interfaces/ControllerOverview/SubsystemRow.tsx b/tgui/packages/tgui/interfaces/ControllerOverview/SubsystemRow.tsx new file mode 100644 index 0000000000000..0a0bef6a9e6ec --- /dev/null +++ b/tgui/packages/tgui/interfaces/ControllerOverview/SubsystemRow.tsx @@ -0,0 +1,107 @@ +import { Dispatch } from 'react'; + +import { useBackend } from '../../backend'; +import { + Button, + Icon, + ProgressBar, + Stack, + Table, + Tooltip, +} from '../../components'; +import { SORTING_TYPES } from './contants'; +import { SortType, SubsystemData } from './types'; + +type Props = { + max: number; + setSelected: Dispatch; + showBars: boolean; + sortType: SortType; + subsystem: SubsystemData; +}; + +export function SubsystemRow(props: Props) { + const { act } = useBackend(); + const { max, setSelected, showBars, sortType, subsystem } = props; + const { can_fire, doesnt_fire, initialized, name, ref } = subsystem; + + const { propName } = SORTING_TYPES[sortType]; + const value = subsystem[propName]; + + let icon = 'play'; + let color = 'good'; + let tooltip = 'Operational'; + if (!initialized) { + icon = 'circle-exclamation'; + color = 'darkgreen'; + tooltip = 'Not initialized'; + } else if (doesnt_fire) { + icon = 'check'; + color = 'grey'; + tooltip = 'Does not fire'; + } else if (!can_fire) { + icon = 'pause'; + color = 'grey'; + tooltip = 'Paused'; + } + + let valueDisplay = ''; + let rangeDisplay = {}; + if (showBars) { + if (sortType === SortType.Cost) { + valueDisplay = value.toFixed(0) + 'ms'; + rangeDisplay = { + average: [75, 124.99], + bad: [125, Infinity], + }; + } else { + valueDisplay = (value * 0.01).toFixed(2) + '%'; + rangeDisplay = { + average: [10, 24.99], + bad: [25, Infinity], + }; + } + } else { + valueDisplay = value; + } + + return ( + + + + + + + setSelected(subsystem)}> + {showBars ? ( + + {name} {valueDisplay} + + ) : ( + + )} + + + + + + } + > + + {sorted.map((subsystem) => ( + + ))} +
    +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/ControllerOverview/contants.ts b/tgui/packages/tgui/interfaces/ControllerOverview/contants.ts new file mode 100644 index 0000000000000..fdd28bfd36b0a --- /dev/null +++ b/tgui/packages/tgui/interfaces/ControllerOverview/contants.ts @@ -0,0 +1,43 @@ +type SortType = { + label: string; + propName: string; + inDeciseconds: boolean; +}; + +export const SORTING_TYPES: readonly SortType[] = [ + { + label: 'Alphabetical', + propName: 'name', + inDeciseconds: false, + }, + { + label: 'Cost', + propName: 'cost_ms', + inDeciseconds: true, + }, + { + label: 'Init Order', + propName: 'init_order', + inDeciseconds: false, + }, + { + label: 'Last Fire', + propName: 'last_fire', + inDeciseconds: false, + }, + { + label: 'Next Fire', + propName: 'next_fire', + inDeciseconds: false, + }, + { + label: 'Tick Usage', + propName: 'tick_usage', + inDeciseconds: true, + }, + { + label: 'Tick Overrun', + propName: 'tick_overrun', + inDeciseconds: true, + }, +]; diff --git a/tgui/packages/tgui/interfaces/ControllerOverview/filters.ts b/tgui/packages/tgui/interfaces/ControllerOverview/filters.ts new file mode 100644 index 0000000000000..8d975ac9a7108 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ControllerOverview/filters.ts @@ -0,0 +1,45 @@ +import { SortType } from './types'; + +export type FilterState = { + ascending: boolean; + inactive: boolean; + query: string; + smallValues: boolean; + sortType: SortType; +}; + +export enum FilterAction { + Ascending = 'SET_SORT_ASCENDING', + Inactive = 'SET_FILTER_INACTIVE', + SmallValues = 'SET_FILTER_SMALL_VALUES', + SortType = 'SET_SORT_TYPE', + Query = 'SET_FILTER_QUERY', + Update = 'UPDATE_FILTER', +} + +type Action = + | { type: FilterAction.Ascending; payload: boolean } + | { type: FilterAction.Inactive; payload: boolean } + | { type: FilterAction.SmallValues; payload: boolean } + | { type: FilterAction.SortType; payload: SortType } + | { type: FilterAction.Query; payload: string } + | { type: FilterAction.Update; payload: Partial }; + +export function filterReducer(state: FilterState, action: Action): FilterState { + switch (action.type) { + case FilterAction.Inactive: + return { ...state, inactive: action.payload }; + case FilterAction.SmallValues: + return { ...state, smallValues: action.payload }; + case FilterAction.Ascending: + return { ...state, ascending: action.payload }; + case FilterAction.SortType: + return { ...state, sortType: action.payload }; + case FilterAction.Query: + return { ...state, query: action.payload }; + case FilterAction.Update: + return { ...state, ...action.payload }; + default: + return state; + } +} diff --git a/tgui/packages/tgui/interfaces/ControllerOverview/index.tsx b/tgui/packages/tgui/interfaces/ControllerOverview/index.tsx new file mode 100644 index 0000000000000..388d3d436789d --- /dev/null +++ b/tgui/packages/tgui/interfaces/ControllerOverview/index.tsx @@ -0,0 +1,152 @@ +import { useReducer, useState } from 'react'; + +import { Button, Dropdown, Input, Section, Stack } from '../../components'; +import { Window } from '../../layouts'; +import { SORTING_TYPES } from './contants'; +import { FilterAction, filterReducer, FilterState } from './filters'; +import { OverviewSection } from './OverviewSection'; +import { SubsystemDialog } from './SubsystemDialog'; +import { SubsystemViews } from './SubsystemViews'; +import { SortType, SubsystemData } from './types'; + +export function ControllerOverview(props) { + return ( + + + + + + ); +} + +export function ControllerContent(props) { + const [state, dispatch] = useReducer(filterReducer, { + ascending: true, + inactive: true, + query: '', + smallValues: false, + sortType: SortType.Name, + }); + + const [selected, setSelected] = useState(); + + const { label, inDeciseconds } = + SORTING_TYPES?.[state.sortType] || SORTING_TYPES[0]; + + function onSelectionHandler(value: string) { + const updates: Partial = { + sortType: SORTING_TYPES.findIndex((type) => type.label === value), + }; + + if (updates.sortType === undefined) return; + + const { inDeciseconds } = SORTING_TYPES[updates.sortType]; + + updates.ascending = !inDeciseconds; + updates.smallValues = inDeciseconds; + + dispatch({ type: FilterAction.Update, payload: updates }); + } + + return ( + + {selected && ( + setSelected(undefined)} + subsystem={selected} + /> + )} + + + + +
    + + + + + + dispatch({ type: FilterAction.Query, payload: value }) + } + placeholder="By name" + value={state.query} + width="85%" + /> + + + + + + + + + + + type.label)} + selected={label} + displayText={label} + onSelected={onSelectionHandler} + /> + + + + + + + + +
    +
    + + + +
    + ); +} diff --git a/tgui/packages/tgui/interfaces/ControllerOverview/types.ts b/tgui/packages/tgui/interfaces/ControllerOverview/types.ts new file mode 100644 index 0000000000000..604989b1f75c5 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ControllerOverview/types.ts @@ -0,0 +1,33 @@ +import { BooleanLike } from 'common/react'; + +export type SubsystemData = { + can_fire: BooleanLike; + cost_ms: number; + doesnt_fire: BooleanLike; + init_order: number; + initialization_failure_message: string | undefined; + initialized: BooleanLike; + last_fire: number; + name: string; + next_fire: number; + ref: string; + tick_overrun: number; + tick_usage: number; +}; + +export type ControllerData = { + world_time: number; + fast_update: BooleanLike; + map_cpu: number; + subsystems: SubsystemData[]; +}; + +export enum SortType { + Name, + Cost, + InitOrder, + LastFire, + NextFire, + TickUsage, + TickOverrun, +} From c845546621fa5d246483a5d0e3c23823a175fb71 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 23 Apr 2024 14:02:43 +1200 Subject: [PATCH 435/938] Automatic changelog for PR #82769 [ci skip] --- html/changelogs/AutoChangeLog-pr-82769.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82769.yml diff --git a/html/changelogs/AutoChangeLog-pr-82769.yml b/html/changelogs/AutoChangeLog-pr-82769.yml new file mode 100644 index 0000000000000..f2181fca0a064 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82769.yml @@ -0,0 +1,5 @@ +author: "jlsnow301" +delete-after: True +changes: + - rscadd: "Admin tools buffed, check the Controller Overview" + - rscadd: "Controller Overview moved to debug tab" \ No newline at end of file From 9acf5bd821b37e4d8dad1c850497eeef79c0e7d8 Mon Sep 17 00:00:00 2001 From: Kyle Spier-Swenson Date: Mon, 22 Apr 2024 19:50:47 -0700 Subject: [PATCH 436/938] Revert "Converts ListInputModal to actually be a Modal | Adds ListInputWindow which uses it" (#82841) Reverts tgstation/tgstation#82792 --- code/modules/tgui_input/list.dm | 2 +- .../{ListInputWindow => }/ListInputModal.tsx | 172 ++++++++++-------- .../tgui/interfaces/ListInputWindow/index.tsx | 44 ----- .../tgui/interfaces/common/InputButtons.tsx | 23 +-- 4 files changed, 97 insertions(+), 144 deletions(-) rename tgui/packages/tgui/interfaces/{ListInputWindow => }/ListInputModal.tsx (57%) delete mode 100644 tgui/packages/tgui/interfaces/ListInputWindow/index.tsx diff --git a/code/modules/tgui_input/list.dm b/code/modules/tgui_input/list.dm index 22c6d48edfc5a..174f16fc7b57c 100644 --- a/code/modules/tgui_input/list.dm +++ b/code/modules/tgui_input/list.dm @@ -111,7 +111,7 @@ /datum/tgui_list_input/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, "ListInputWindow") + ui = new(user, src, "ListInputModal") ui.open() /datum/tgui_list_input/ui_close(mob/user) diff --git a/tgui/packages/tgui/interfaces/ListInputWindow/ListInputModal.tsx b/tgui/packages/tgui/interfaces/ListInputModal.tsx similarity index 57% rename from tgui/packages/tgui/interfaces/ListInputWindow/ListInputModal.tsx rename to tgui/packages/tgui/interfaces/ListInputModal.tsx index a56363f231097..8695ac842f72e 100644 --- a/tgui/packages/tgui/interfaces/ListInputWindow/ListInputModal.tsx +++ b/tgui/packages/tgui/interfaces/ListInputModal.tsx @@ -7,26 +7,35 @@ import { KEY_ESCAPE, KEY_UP, KEY_Z, -} from '../../../common/keycodes'; -import { useBackend } from '../../backend'; -import { Autofocus, Button, Input, Section, Stack } from '../../components'; -import { InputButtons } from '../common/InputButtons'; +} from '../../common/keycodes'; +import { useBackend } from '../backend'; +import { Autofocus, Button, Input, Section, Stack } from '../components'; +import { Window } from '../layouts'; +import { InputButtons } from './common/InputButtons'; +import { Loader } from './common/Loader'; -type ListInputModalProps = { +type ListInputData = { + init_value: string; items: string[]; - default_item: string; + large_buttons: boolean; message: string; - on_selected: (entry: string) => void; - on_cancel: () => void; + timeout: number; + title: string; }; -export const ListInputModal = (props: ListInputModalProps) => { - const { items = [], default_item, message, on_selected, on_cancel } = props; - - const [selected, setSelected] = useState(items.indexOf(default_item)); +export const ListInputModal = (props) => { + const { act, data } = useBackend(); + const { + items = [], + message = '', + init_value, + large_buttons, + timeout, + title, + } = data; + const [selected, setSelected] = useState(items.indexOf(init_value)); const [searchBarVisible, setSearchBarVisible] = useState(items.length > 9); const [searchQuery, setSearchQuery] = useState(''); - // User presses up or down on keyboard // Simulates clicking an item const onArrowKey = (key: number) => { @@ -90,77 +99,82 @@ export const ListInputModal = (props: ListInputModalProps) => { const filteredItems = items.filter((item) => item?.toLowerCase().includes(searchQuery.toLowerCase()), ); + // Dynamically changes the window height based on the message. + const windowHeight = + 325 + Math.ceil(message.length / 3) + (large_buttons ? 5 : 0); // Grabs the cursor when no search bar is visible. if (!searchBarVisible) { setTimeout(() => document!.getElementById(selected.toString())?.focus(), 1); } return ( -
    { - const keyCode = window.event ? event.which : event.keyCode; - if (keyCode === KEY_DOWN || keyCode === KEY_UP) { - event.preventDefault(); - onArrowKey(keyCode); - } - if (keyCode === KEY_ENTER) { - event.preventDefault(); - on_selected(filteredItems[selected]); - } - if (!searchBarVisible && keyCode >= KEY_A && keyCode <= KEY_Z) { - event.preventDefault(); - onLetterSearch(keyCode); - } - if (keyCode === KEY_ESCAPE) { - event.preventDefault(); - on_cancel(); - } - }} - buttons={ -
    + if (keyCode === KEY_ENTER) { + event.preventDefault(); + act('submit', { entry: filteredItems[selected] }); + } + if (!searchBarVisible && keyCode >= KEY_A && keyCode <= KEY_Z) { + event.preventDefault(); + onLetterSearch(keyCode); + } + if (keyCode === KEY_ESCAPE) { + event.preventDefault(); + act('cancel'); + } + }} + > +
    onSearchBarToggle()} + /> + } + className="ListInput__Section" + fill + title={message} + > + + + + + {searchBarVisible && ( + + )} + + + + +
    + + ); }; @@ -169,7 +183,7 @@ export const ListInputModal = (props: ListInputModalProps) => { * If a search query is provided, filters the items. */ const ListDisplay = (props) => { - const { act } = useBackend(); + const { act } = useBackend(); const { filteredItems, onClick, onFocusSearch, searchBarVisible, selected } = props; @@ -213,7 +227,7 @@ const ListDisplay = (props) => { * Closing the bar defaults input to an empty string. */ const SearchBar = (props) => { - const { act } = useBackend(); + const { act } = useBackend(); const { filteredItems, onSearch, searchQuery, selected } = props; return ( diff --git a/tgui/packages/tgui/interfaces/ListInputWindow/index.tsx b/tgui/packages/tgui/interfaces/ListInputWindow/index.tsx deleted file mode 100644 index 29355ff5d213f..0000000000000 --- a/tgui/packages/tgui/interfaces/ListInputWindow/index.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { useBackend } from '../../backend'; -import { Window } from '../../layouts'; -import { Loader } from '../common/Loader'; -import { ListInputModal } from './ListInputModal'; - -type ListInputData = { - init_value: string; - items: string[]; - large_buttons: boolean; - message: string; - timeout: number; - title: string; -}; - -export const ListInputWindow = () => { - const { act, data } = useBackend(); - const { - items = [], - message = '', - init_value, - large_buttons, - timeout, - title, - } = data; - - // Dynamically changes the window height based on the message. - const windowHeight = - 325 + Math.ceil(message.length / 3) + (large_buttons ? 5 : 0); - - return ( - - {timeout && } - - act('submit', { entry })} - on_cancel={() => act('cancel')} - /> - - - ); -}; diff --git a/tgui/packages/tgui/interfaces/common/InputButtons.tsx b/tgui/packages/tgui/interfaces/common/InputButtons.tsx index aa74ff1fdc017..aad3d92f081fb 100644 --- a/tgui/packages/tgui/interfaces/common/InputButtons.tsx +++ b/tgui/packages/tgui/interfaces/common/InputButtons.tsx @@ -8,36 +8,19 @@ type InputButtonsData = { type InputButtonsProps = { input: string | number | string[]; - on_submit?: () => void; - on_cancel?: () => void; message?: string; }; export const InputButtons = (props: InputButtonsProps) => { const { act, data } = useBackend(); const { large_buttons, swapped_buttons } = data; - const { input, message, on_submit, on_cancel } = props; - - let on_submit_actual = on_submit; - if (!on_submit_actual) { - on_submit_actual = () => { - act('submit', { entry: input }); - }; - } - - let on_cancel_actual = on_cancel; - if (!on_cancel_actual) { - on_cancel_actual = () => { - act('cancel'); - }; - } - + const { input, message } = props; const submitButton = ( + + + setSearchQuery((e.target as HTMLTextAreaElement).value) + } + /> + + } + > + + + Name + + + Vitals + + + Position + + {!!data.link_allowed && ( + + Tracking + + )} + + {sorted.map((sensor) => ( + + ))} +
    +