From 20a50993d72ad462345fabccefe964f108b5c5a5 Mon Sep 17 00:00:00 2001 From: Sadhorizon <108196626+Sadhorizon@users.noreply.github.com> Date: Thu, 11 Apr 2024 21:30:22 +0200 Subject: [PATCH 01/32] Blood pack variety crates now contain Elzu and IPC blood. (#2875) ## About The Pull Request Title. Also, "random blood pack" now can roll Elzu and IPC blood. ## Why It's Good For The Game You would expect the blood pack variety crate to contain blood for ALL the species!!! Same with the random blood pack. ## Changelog :cl: tweak: "Blood pack variety crate" now contains Elzu and IPC blood. tweak: Random blood packs now can roll Elzu and IPC blood. /:cl: --- code/modules/cargo/packs/medical.dm | 4 +++- code/modules/reagents/reagent_containers/blood_pack.dm | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/code/modules/cargo/packs/medical.dm b/code/modules/cargo/packs/medical.dm index 090041f06382..d49e9760da81 100644 --- a/code/modules/cargo/packs/medical.dm +++ b/code/modules/cargo/packs/medical.dm @@ -92,7 +92,9 @@ /obj/item/reagent_containers/blood/BMinus, /obj/item/reagent_containers/blood/OPlus, /obj/item/reagent_containers/blood/OMinus, - /obj/item/reagent_containers/blood/lizard) + /obj/item/reagent_containers/blood/lizard, + /obj/item/reagent_containers/blood/elzuose, + /obj/item/reagent_containers/blood/synthetic) crate_name = "blood freezer" crate_type = /obj/structure/closet/crate/freezer diff --git a/code/modules/reagents/reagent_containers/blood_pack.dm b/code/modules/reagents/reagent_containers/blood_pack.dm index d72389224fd9..6c5691f83f73 100644 --- a/code/modules/reagents/reagent_containers/blood_pack.dm +++ b/code/modules/reagents/reagent_containers/blood_pack.dm @@ -38,7 +38,7 @@ /obj/item/reagent_containers/blood/random/Initialize() icon_state = "bloodpack" - blood_type = pick("A+", "A-", "B+", "B-", "O+", "O-", "L") + blood_type = pick("A+", "A-", "B+", "B-", "O+", "O-", "L", "E", "Coolant") return ..() /obj/item/reagent_containers/blood/APlus From 54dbb55d730f06abce54c75d02a6306bdebeb229 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Thu, 11 Apr 2024 14:51:31 -0500 Subject: [PATCH 02/32] Automatic changelog generation for PR #2875 [ci skip] --- html/changelogs/AutoChangeLog-pr-2875.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2875.yml diff --git a/html/changelogs/AutoChangeLog-pr-2875.yml b/html/changelogs/AutoChangeLog-pr-2875.yml new file mode 100644 index 000000000000..e0b1b326f569 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2875.yml @@ -0,0 +1,4 @@ +author: Sadhorizon +changes: + - {tweak: Random blood packs now can roll Elzu and IPC blood.} +delete-after: true From 268f27d2f4bbd7d827f3e8ae031ad94f58209add Mon Sep 17 00:00:00 2001 From: Theos Date: Thu, 11 Apr 2024 15:34:26 -0400 Subject: [PATCH 03/32] N2O no longer puts you into a coma (#2850) ## About The Pull Request Replaces add sleep with set sleep for nitrous so the current sleep +4 seconds doesnt stack with itself to comically high numbers ## Why It's Good For The Game If i wanted to sleep id get a blanket not a silly tank ## Changelog :cl: fix: anesthetic can no longer semi permanently knock people out /:cl: --------- Signed-off-by: Theos --- code/modules/surgery/organs/lungs.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm index fc5de4be3049..05ca5131e0f9 100644 --- a/code/modules/surgery/organs/lungs.dm +++ b/code/modules/surgery/organs/lungs.dm @@ -226,7 +226,7 @@ if(SA_pp > SA_para_min) // Enough to make us stunned for a bit H.Unconscious(60) // 60 gives them one second to wake up and run away a bit! if(SA_pp > SA_sleep_min) // Enough to make us sleep as well - H.Sleeping(max(H.AmountSleeping() + 40, 200)) + H.Sleeping(200) else if(SA_pp > 0.01) // There is sleeping gas in their lungs, but only a little, so give them a bit of a warning if(prob(20)) H.emote(pick("giggle", "laugh")) From 18498d953f5bb77f9c6d1b41bc6909a0fd003e43 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Thu, 11 Apr 2024 15:04:27 -0500 Subject: [PATCH 04/32] Automatic changelog generation for PR #2850 [ci skip] --- html/changelogs/AutoChangeLog-pr-2850.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2850.yml diff --git a/html/changelogs/AutoChangeLog-pr-2850.yml b/html/changelogs/AutoChangeLog-pr-2850.yml new file mode 100644 index 000000000000..7269f7dc9dc6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2850.yml @@ -0,0 +1,4 @@ +author: SomeguyManperson +changes: + - {bugfix: anesthetic can no longer semi permanently knock people out} +delete-after: true From b25ec1852794fafc0fced17c97c87ebec1b6ebf6 Mon Sep 17 00:00:00 2001 From: Yata9arasu_alt <58084138+Yata9ar4su@users.noreply.github.com> Date: Fri, 12 Apr 2024 02:35:17 +0700 Subject: [PATCH 05/32] Adds Fullscreen (#2878) ## About The Pull Request Added fullscreen as hotkey F11 and on OOC -> Toggle Fullscreen ![image](https://github.com/shiptest-ss13/Shiptest/assets/58084138/3db51657-c491-423a-a4e2-1e70647897b3) ![image](https://github.com/shiptest-ss13/Shiptest/assets/58084138/8136e422-922a-4937-8c59-50993d1a8bc1) ## Why It's Good For The Game You can play in fullscreen without annoying borders. ## Changelog :cl: add: Fullscreen on F11 /:cl: --- code/__DEFINES/keybinding.dm | 1 + code/datums/keybinding/client.dm | 36 ++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/code/__DEFINES/keybinding.dm b/code/__DEFINES/keybinding.dm index 97b9c9d82aad..50a16edc350a 100644 --- a/code/__DEFINES/keybinding.dm +++ b/code/__DEFINES/keybinding.dm @@ -31,6 +31,7 @@ #define COMSIG_KB_CLIENT_GETHELP_DOWN "keybinding_client_gethelp_down" #define COMSIG_KB_CLIENT_SCREENSHOT_DOWN "keybinding_client_screenshot_down" #define COMSIG_KB_CLIENT_MINIMALHUD_DOWN "keybinding_client_minimalhud_down" +#define COMSIG_KB_CLIENT_FULLSCREEN_DOWN "keybinding_client_fullscreen_down" //Communication #define COMSIG_KB_CLIENT_OOC_DOWN "keybinding_client_ooc_down" diff --git a/code/datums/keybinding/client.dm b/code/datums/keybinding/client.dm index e4b940c7f722..3e78c4ac4c23 100644 --- a/code/datums/keybinding/client.dm +++ b/code/datums/keybinding/client.dm @@ -45,3 +45,39 @@ return user.mob.button_pressed_F12() return TRUE + +/client + var/fullscreen = FALSE +/datum/keybinding/client/t_fullscreen + hotkey_keys = list("F11") + name = "change_fullscreen" + full_name = "Toggle Fullscreen" + description = "Change window to Fullscreen or back" + keybind_signal = COMSIG_KB_CLIENT_FULLSCREEN_DOWN + +/datum/keybinding/client/t_fullscreen/down(client/C) + . = ..() + C.toggle_fullscreen() + + +/client/verb/toggle_fullscreen() + set name = "Toggle Fullscreen" + set category = "OOC" + + fullscreen = !fullscreen + + if (fullscreen) + winset(usr, "mainwindow", "on-size=") + winset(usr, "mainwindow", "titlebar=false") + winset(usr, "mainwindow", "can-resize=false") + winset(usr, "mainwindow", "menu=") + winset(usr, "mainwindow", "is-maximized=false") + winset(usr, "mainwindow", "is-maximized=true") + else + winset(usr, "mainwindow", "titlebar=true") + winset(usr, "mainwindow", "can-resize=true") + winset(usr, "mainwindow", "menu=menu") + winset(usr, "mainwindow", "is-maximized=false") + winset(usr, "mainwindow", "on-size=fitviewport") + + fit_viewport() From aa66226021feb753758ff7c464af0180a7a2c719 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Thu, 11 Apr 2024 15:17:36 -0500 Subject: [PATCH 06/32] Automatic changelog generation for PR #2878 [ci skip] --- html/changelogs/AutoChangeLog-pr-2878.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2878.yml diff --git a/html/changelogs/AutoChangeLog-pr-2878.yml b/html/changelogs/AutoChangeLog-pr-2878.yml new file mode 100644 index 000000000000..2ed39362f2b1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2878.yml @@ -0,0 +1,4 @@ +author: Yata9ar4su +changes: + - {rscadd: Fullscreen on F11} +delete-after: true From 8446fff2646e41811213f206ea6b6a66724db459 Mon Sep 17 00:00:00 2001 From: meem <75212565+meemofcourse@users.noreply.github.com> Date: Thu, 11 Apr 2024 15:36:08 -0400 Subject: [PATCH 07/32] Send photos to admin faxes (#2842) ## About The Pull Request ![imagen](https://github.com/shiptest-ss13/Shiptest/assets/75212565/5c32c7bb-94f3-4b06-bd32-1deeeeddb4a7) This pull requests allows you to send photos to admin faxes. ## Why It's Good For The Game You can send photos of events happening to your high command, so you don't have to describe everything in text! You can send them cool art you made. Maybe even use it for some strategic plans you drew on a napkin, and you want HighComm to see them. ## Changelog :cl: add: Long-range bluespace technologies in fax machines now allow the faxing of photos. I am not responsible for any consequences that might result from sending your faction's command personnel a photo of your character's ass. /:cl: --- code/__DEFINES/admin.dm | 3 ++- code/modules/admin/topic.dm | 9 +++++++++ code/modules/paperwork/fax.dm | 35 +++++++++++++++++++++-------------- 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm index 44f0893cd9a5..e1590614b6be 100644 --- a/code/__DEFINES/admin.dm +++ b/code/__DEFINES/admin.dm @@ -67,8 +67,9 @@ #define ADMIN_COORDJMP(src) "[src ? "[COORD(src)] [ADMIN_JMP(src)]" : "nonexistent location"]" #define ADMIN_VERBOSEJMP(src) "[src ? "[AREACOORD(src)] [ADMIN_JMP(src)]" : "nonexistent location"]" #define ADMIN_INDIVIDUALLOG(user) "(LOGS)" -/// Displays "(SHOW)" in the chat, when clicked it tries to show atom(paper). First you need to set the request_state variable to TRUE for the paper. +/// Displays "(SHOW)" in the chat, when clicked it tries to show atom(paper) or atom(photo). First you need to set the request_state variable to TRUE for the paper. #define ADMIN_SHOW_PAPER(atom) "(SHOW)" +#define ADMIN_SHOW_PHOTO(atom) "(PHOTO)" #define ADMIN_PUNISHMENT_BREAK_BONES "Break all bones" #define ADMIN_PUNISHMENT_LIGHTNING "Lightning bolt" diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index b917501d0bb8..13d4c814f2fe 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -2227,6 +2227,15 @@ return paper_to_show.ui_interact(usr) + else if(href_list["show_photo"]) + if(!check_rights(R_ADMIN)) + return + + var/obj/item/photo/photo_to_show = locate(href_list["show_photo"]) + if(!istype(photo_to_show)) + return + photo_to_show.show(usr) + /datum/admins/proc/HandleCMode() if(!check_rights(R_ADMIN)) return diff --git a/code/modules/paperwork/fax.dm b/code/modules/paperwork/fax.dm index cb5a025da475..bce7a3f322c5 100644 --- a/code/modules/paperwork/fax.dm +++ b/code/modules/paperwork/fax.dm @@ -308,27 +308,34 @@ update_icon() return TRUE if("send_special") - var/obj/item/paper/fax_paper = loaded_item_ref?.resolve() - if(!fax_paper) + var/obj/item/loaded = loaded_item_ref?.resolve() + var/obj/thing_to_send + if(!loaded) return - if(!istype(fax_paper)) + if(istype(loaded, /obj/item/paper)) + var/obj/item/paper/fax_paper = loaded + fax_paper.request_state = TRUE + thing_to_send = fax_paper + else if(istype(loaded, /obj/item/photo)) + thing_to_send = loaded + else to_chat(usr, icon2html(src.icon, usr) + "ERROR: Failed to send fax.") return - fax_paper.request_state = TRUE - fax_paper.loc = null - - INVOKE_ASYNC(src, PROC_REF(animate_object_travel), fax_paper, "fax_receive", find_overlay_state(fax_paper, "send")) + if(!thing_to_send) + return + thing_to_send.loc = null + INVOKE_ASYNC(src, PROC_REF(animate_object_travel), thing_to_send, "fax_receive", find_overlay_state(thing_to_send, "send")) history_add("Send", params["name"]) - GLOB.requests.fax_request(usr.client, "sent a fax message from [fax_name]/[fax_id] to [params["name"]]", fax_paper) - to_chat(GLOB.admins, "[icon2html(src.icon, GLOB.admins)]FAX REQUEST: [ADMIN_FULLMONTY(usr)]: sent a fax message from [fax_name]/[fax_id][ADMIN_FLW(src)] to [html_encode(params["name"])] [ADMIN_SHOW_PAPER(fax_paper)]") - log_fax(fax_paper, params["id"], params["name"]) + GLOB.requests.fax_request(usr.client, "sent a fax message from [fax_name]/[fax_id] to [params["name"]]", thing_to_send) + to_chat(GLOB.admins, "[icon2html(src.icon, GLOB.admins)]FAX REQUEST: [ADMIN_FULLMONTY(usr)]: sent a fax message from [fax_name]/[fax_id][ADMIN_FLW(src)] to [html_encode(params["name"])] [istype(thing_to_send, /obj/item/paper) ? ADMIN_SHOW_PAPER(thing_to_send) : ADMIN_SHOW_PHOTO(thing_to_send)]") + log_fax(thing_to_send, params["id"], params["name"]) loaded_item_ref = null for(var/obj/machinery/fax/fax as anything in GLOB.fax_machines) if(fax.admin_fax_id == params["id"]) - fax.receive(fax_paper, fax_name) + fax.receive(thing_to_send, fax_name) break update_appearance() @@ -360,7 +367,7 @@ * * loaded - The object to be sent. * * id - The network ID of the fax machine you want to send the item to. */ -/obj/machinery/fax/proc/send(obj/item/loaded, id) +/obj/machinery/fax/proc/send(atom/movable/loaded, id) for(var/obj/machinery/fax/fax as anything in GLOB.fax_machines) if(fax.fax_id != id) continue @@ -385,7 +392,7 @@ * * loaded - The object to be printed. * * sender_name - The sender's name, which will be displayed in the message and recorded in the history of operations. */ -/obj/machinery/fax/proc/receive(obj/item/loaded, sender_name, important = FALSE) +/obj/machinery/fax/proc/receive(atom/movable/loaded, sender_name, important = FALSE) playsound(src, 'sound/items/poster_being_created.ogg', 20, FALSE) INVOKE_ASYNC(src, PROC_REF(animate_object_travel), loaded, "fax_receive", find_overlay_state(loaded, "receive")) say("Received correspondence from [sender_name].") @@ -442,7 +449,7 @@ * Arguments: * * vend - Item to vend from the fax machine. */ -/obj/machinery/fax/proc/vend_item(obj/item/vend) +/obj/machinery/fax/proc/vend_item(atom/movable/vend) vend.forceMove(drop_location()) if(hurl_contents) vend.throw_at(get_edge_target_turf(drop_location(), pick(GLOB.alldirs)), rand(1, 4), EMBED_THROWSPEED_THRESHOLD) From 2bc621f5c3e1724a83e20fa115e12cd7edbdff50 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Thu, 11 Apr 2024 15:31:07 -0500 Subject: [PATCH 08/32] Automatic changelog generation for PR #2842 [ci skip] --- html/changelogs/AutoChangeLog-pr-2842.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2842.yml diff --git a/html/changelogs/AutoChangeLog-pr-2842.yml b/html/changelogs/AutoChangeLog-pr-2842.yml new file mode 100644 index 000000000000..97812c9c1871 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2842.yml @@ -0,0 +1,6 @@ +author: meemofcourse +changes: + - {rscadd: Long-range bluespace technologies in fax machines now allow the faxing + of photos. I am not responsible for any consequences that might result from + sending your faction's command personnel a photo of your character's ass.} +delete-after: true From 1f8da5fbff7ac2e06b15fd43f1541faadf2fa900 Mon Sep 17 00:00:00 2001 From: Gristlebee <56049844+Gristlebee@users.noreply.github.com> Date: Thu, 11 Apr 2024 12:37:57 -0700 Subject: [PATCH 09/32] Constructable exercise equipment (#2839) ## About The Pull Request - Punching bags can now be constructed from 5 cloth and deconstructed with a wirecutter. - Bench presses and chest presses can be constructed from 5 metal and deconstructed with a wrench. ## Why It's Good For The Game You no longer need to smash apart the exercise equipment like a caveman, and offers players some more freedom in how they want to decorate or arrange their ships. ## Changelog :cl: add: Punching bags can be built with 5 cloth. add: Bench press and chest press can be built with 5 metal. add: Exercise equipment can be deconstructed. /:cl: --- .../items/stacks/sheets/sheet_types.dm | 5 ++ code/modules/mining/lavaland/ruins/gym.dm | 85 ++++++++++++++++++- 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 09b2338b244f..cf4824f20fbe 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -118,6 +118,10 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \ new/datum/stack_recipe("mortar", /obj/item/reagent_containers/glass/mortar/metal, 3), \ new/datum/stack_recipe("pestle", /obj/item/pestle, 1, time = 50), \ new/datum/stack_recipe("hygienebot assembly", /obj/item/bot_assembly/hygienebot, 2, time = 50), \ + new/datum/stack_recipe_list("weight machines", list( \ + new/datum/stack_recipe("chest press", /obj/structure/weightmachine/stacklifter, 5, time = 25, one_per_turf = TRUE, on_floor = TRUE), \ + new/datum/stack_recipe("bench press", /obj/structure/weightmachine/weightlifter, 5, time = 25, one_per_turf = TRUE, on_floor = TRUE), \ + )), \ new/datum/stack_recipe("shower", /obj/machinery/shower, 3, time = 25) )) @@ -367,6 +371,7 @@ GLOBAL_LIST_INIT(cloth_recipes, list ( \ new/datum/stack_recipe("19x19 canvas", /obj/item/canvas/nineteenXnineteen, 3), \ new/datum/stack_recipe("23x19 canvas", /obj/item/canvas/twentythreeXnineteen, 4), \ new/datum/stack_recipe("23x23 canvas", /obj/item/canvas/twentythreeXtwentythree, 5), \ + new/datum/stack_recipe("punching bag", /obj/structure/punching_bag, 5, time = 25, one_per_turf = TRUE, on_floor = TRUE), \ )) /obj/item/stack/sheet/cotton/cloth diff --git a/code/modules/mining/lavaland/ruins/gym.dm b/code/modules/mining/lavaland/ruins/gym.dm index 8a73aff51a69..63b220828f81 100644 --- a/code/modules/mining/lavaland/ruins/gym.dm +++ b/code/modules/mining/lavaland/ruins/gym.dm @@ -7,6 +7,47 @@ layer = WALL_OBJ_LAYER var/list/hit_sounds = list('sound/weapons/genhit1.ogg', 'sound/weapons/genhit2.ogg', 'sound/weapons/genhit3.ogg',\ 'sound/weapons/punch1.ogg', 'sound/weapons/punch2.ogg', 'sound/weapons/punch3.ogg', 'sound/weapons/punch4.ogg') + var/buildstacktype = /obj/item/stack/sheet/cotton/cloth + var/buildstackamount = 5 + +/obj/structure/punching_bag/deconstruct(disassembled = TRUE) + if(!(flags_1 & NODECONSTRUCT_1)) + if(buildstacktype) + new buildstacktype(loc,buildstackamount) + return..() + +/obj/structure/punching_bag/wrench_act(mob/living/user, obj/item/W) + if(..()) + return TRUE + add_fingerprint(user) + var/action = anchored ? "unbolts [src] from" : "bolts [src] to" + var/uraction = anchored ? "unbolt [src] from" : "bolt [src] to" + user.visible_message(span_warning("[user] [action] the floor."), span_notice("You start to [uraction] the floor..."), span_hear("You hear rustling noises.")) + if(W.use_tool(src, user, 50, volume=100, extra_checks = CALLBACK(src, PROC_REF(check_anchored_state), anchored))) + set_anchored(!anchored) + to_chat(user, span_notice("You [anchored ? "bolt" : "unbolt"] [src] from the floor.")) + return TRUE + +/obj/structure/punching_bag/wirecutter_act(mob/living/user, obj/item/W) + . = ..() + if(!anchored) + user.visible_message(span_warning("[user] cuts apart [src]."), span_notice("You start to cut apart [src]."), span_hear("You hear cutting.")) + if(W.use_tool(src, user, 50, volume=100)) + if(anchored) + return TRUE + to_chat(user, span_notice("You cut apart [src].")) + deconstruct(TRUE) + return TRUE + +/obj/structure/punching_bag/proc/check_anchored_state(check_anchored) + return anchored == check_anchored + +/obj/structure/punching_bag/examine(mob/user) + . = ..() + if(anchored) + . += span_notice("[src] is bolted to the floor.") + else + . += span_notice("[src] is no longer bolted to the floor, and the seams can be cut apart.") /obj/structure/punching_bag/attack_hand(mob/user as mob) . = ..() @@ -25,6 +66,8 @@ icon = 'icons/obj/gym_equipment.dmi' density = TRUE anchored = TRUE + var/buildstacktype = /obj/item/stack/sheet/metal + var/buildstackamount = 5 /obj/structure/weightmachine/proc/AnimateMachine(mob/living/user) return @@ -33,6 +76,45 @@ . = ..() icon_state = (obj_flags & IN_USE) ? "[base_icon_state]-u" : base_icon_state +/obj/structure/weightmachine/deconstruct(disassembled = TRUE) + if(!(flags_1 & NODECONSTRUCT_1)) + if(buildstacktype) + new buildstacktype(loc,buildstackamount) + return..() + +/obj/structure/weightmachine/wrench_act(mob/living/user, obj/item/W) + if(..()) + return TRUE + add_fingerprint(user) + var/action = anchored ? "unbolts [src] from" : "bolts [src] to" + var/uraction = anchored ? "unbolt [src] from" : "bolt [src] to" + user.visible_message(span_warning("[user] [action] the floor."), span_notice("You start to [uraction] the floor..."), span_hear("You hear rustling noises.")) + if(W.use_tool(src, user, 50, volume=100, extra_checks = CALLBACK(src, PROC_REF(check_anchored_state), anchored))) + set_anchored(!anchored) + to_chat(user, span_notice("You [anchored ? "bolt" : "unbolt"] [src] from the floor.")) + return TRUE + +/obj/structure/weightmachine/screwdriver_act(mob/living/user, obj/item/W) + . = ..() + if(!anchored) + user.visible_message(span_warning("[user] screws apart [src]."), span_notice("You start to screw apart [src]."), span_hear("You hear screwing.")) + if(W.use_tool(src, user, 50, volume=100)) + if(anchored) + return TRUE + to_chat(user, span_notice("You screw apart [src].")) + deconstruct(TRUE) + return TRUE + +/obj/structure/weightmachine/proc/check_anchored_state(check_anchored) + return anchored == check_anchored + +/obj/structure/weightmachine/examine(mob/user) + . = ..() + if(anchored) + . += span_notice("[src] is bolted to the floor.") + else + . += span_notice("[src] is no longer bolted to the floor, and the screws are exposed.") + /obj/structure/weightmachine/update_overlays() . = ..() @@ -44,7 +126,7 @@ if(.) return if(obj_flags & IN_USE) - to_chat(user, "It's already in use - wait a bit!") + to_chat(user, span_warning("It's already in use - wait a bit!")) return else obj_flags |= IN_USE @@ -100,3 +182,4 @@ sleep(3) animate(user, pixel_y = 2, time = 3) sleep(3) + From eee583c567e650b218f9d883f2ba6c4b95306372 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Thu, 11 Apr 2024 15:45:18 -0500 Subject: [PATCH 10/32] Automatic changelog generation for PR #2839 [ci skip] --- html/changelogs/AutoChangeLog-pr-2839.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2839.yml diff --git a/html/changelogs/AutoChangeLog-pr-2839.yml b/html/changelogs/AutoChangeLog-pr-2839.yml new file mode 100644 index 000000000000..f877777a0a31 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2839.yml @@ -0,0 +1,6 @@ +author: Gristlebee +changes: + - {rscadd: Punching bags can be built with 5 cloth.} + - {rscadd: Bench press and chest press can be built with 5 metal.} + - {rscadd: Exercise equipment can be deconstructed.} +delete-after: true From e0385e2acdcc9aca2f83ec566c89309781a59bc8 Mon Sep 17 00:00:00 2001 From: thgvr <81882910+thgvr@users.noreply.github.com> Date: Thu, 11 Apr 2024 12:38:31 -0700 Subject: [PATCH 11/32] Brings back old gun suicide_act behavior (#2784) ## About The Pull Request Brings back old suicide_act on handle_suicide proc of guns. https://github.com/shiptest-ss13/Shiptest/assets/81882910/a5363807-0b49-46fc-aae6-cc1253cc1dbf ## Changelog :cl: add: Suicide & Execution with a damaging firearm is now more deadly and gruesome. /:cl: --- code/modules/projectiles/gun.dm | 51 ++++++++++++++++++++------ code/modules/projectiles/projectile.dm | 2 +- 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index e9354e68d9d4..9aa8ac60326f 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -744,6 +744,9 @@ safety_overlay.icon_state = "[safety_wording]-off" . += safety_overlay +#define BRAINS_BLOWN_THROW_RANGE 2 +#define BRAINS_BLOWN_THROW_SPEED 1 + /obj/item/gun/proc/handle_suicide(mob/living/carbon/human/user, mob/living/carbon/human/target, params, bypass_timer) if(!ishuman(user) || !ishuman(target)) return @@ -751,32 +754,58 @@ if(semicd) return + if(!can_shoot()) //Just because you can pull the trigger doesn't mean it can shoot. + shoot_with_empty_chamber(user) + return + if(user == target) - target.visible_message("[user] sticks [src] in [user.p_their()] mouth, ready to pull the trigger...", \ - "You stick [src] in your mouth, ready to pull the trigger...") + target.visible_message(span_warning("[user] sticks [src] in [user.p_their()] mouth, ready to pull the trigger..."), \ + span_userdanger("You stick [src] in your mouth, ready to pull the trigger...")) else - target.visible_message("[user] points [src] at [target]'s head, ready to pull the trigger...", \ - "[user] points [src] at your head, ready to pull the trigger...") + target.visible_message(span_warning("[user] points [src] at [target]'s head, ready to pull the trigger..."), \ + span_userdanger("[user] points [src] at your head, ready to pull the trigger...")) semicd = TRUE - if(!bypass_timer && (!do_mob(user, target, 120) || user.zone_selected != BODY_ZONE_PRECISE_MOUTH)) + if(!bypass_timer && (!do_mob(user, target, 100) || user.zone_selected != BODY_ZONE_PRECISE_MOUTH)) if(user) if(user == target) - user.visible_message("[user] decided not to shoot.") + user.visible_message(span_notice("[user] decided not to shoot.")) else if(target && target.Adjacent(user)) - target.visible_message("[user] has decided to spare [target]", "[user] has decided to spare your life!") + target.visible_message(span_notice("[user] has decided to spare [target]."), span_notice("[user] has decided to spare your life!")) semicd = FALSE return semicd = FALSE - target.visible_message("[user] pulls the trigger!", "[(user == target) ? "You pull" : "[user] pulls"] the trigger!") + target.visible_message(span_warning("[user] pulls the trigger!"), span_userdanger("[(user == target) ? "You pull" : "[user] pulls"] the trigger!")) - if(chambered && chambered.BB) - chambered.BB.damage *= 5 + if(chambered && chambered.BB && can_trigger_gun(user)) + chambered.BB.damage *= 3 + //Check is here for safeties and such, brain will be removed after + process_fire(target, user, TRUE, params, BODY_ZONE_HEAD) + + var/obj/item/organ/brain/brain_to_blast = target.getorganslot(ORGAN_SLOT_BRAIN) + if(brain_to_blast) + + //Check if the projectile is actually damaging and not of type STAMINA + if(chambered.BB.nodamage || !chambered.BB.damage || chambered.BB.damage_type == STAMINA) + return + + //Remove brain of the mob shot + brain_to_blast.Remove(target) + + var/turf/splat_turf = get_turf(target) + //Move the brain of the person shot to selected turf + brain_to_blast.forceMove(splat_turf) + + var/turf/splat_target = get_ranged_target_turf(target, REVERSE_DIR(target.dir), BRAINS_BLOWN_THROW_RANGE) + var/datum/callback/gibspawner = CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(spawn_atom_to_turf), /obj/effect/gibspawner/generic, brain_to_blast, 1, FALSE, target) + //Throw the brain that has been removed away and place a gibspawner on landing + brain_to_blast.throw_at(splat_target, BRAINS_BLOWN_THROW_RANGE, BRAINS_BLOWN_THROW_SPEED, callback = gibspawner) - process_fire(target, user, TRUE, params, BODY_ZONE_HEAD) +#undef BRAINS_BLOWN_THROW_RANGE +#undef BRAINS_BLOWN_THROW_SPEED /obj/item/gun/proc/unlock() //used in summon guns and as a convience for admins if(pin) diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 7cc9b1c6ebb4..85c4558343d9 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -133,7 +133,7 @@ var/homing_offset_y = 0 var/damage = 10 - var/damage_type = BRUTE //BRUTE, BURN, TOX, OXY, CLONE are the only things that should be in here + var/damage_type = BRUTE //BRUTE, BURN, TOX, OXY, CLONE, STAMINA are the only things that should be in here var/nodamage = FALSE //Determines if the projectile will skip any damage inflictions var/flag = "bullet" //Defines what armor to use when it hits things. Must be set to bullet, laser, energy,or bomb ///How much armor this projectile pierces. From 16d95f6db8865257b391629fe7596770e7ceac16 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Thu, 11 Apr 2024 15:59:28 -0500 Subject: [PATCH 12/32] Automatic changelog generation for PR #2784 [ci skip] --- html/changelogs/AutoChangeLog-pr-2784.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2784.yml diff --git a/html/changelogs/AutoChangeLog-pr-2784.yml b/html/changelogs/AutoChangeLog-pr-2784.yml new file mode 100644 index 000000000000..057247d90928 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2784.yml @@ -0,0 +1,4 @@ +author: thgvr +changes: + - {rscadd: Suicide & Execution with a damaging firearm is now more deadly and gruesome.} +delete-after: true From a8c77d257acc01680e45bf892371f8ff91008afa Mon Sep 17 00:00:00 2001 From: thgvr <81882910+thgvr@users.noreply.github.com> Date: Thu, 11 Apr 2024 12:39:26 -0700 Subject: [PATCH 13/32] Improves cyber implant UX (#2741) ## About The Pull Request Ports: https://github.com/tgstation/tgstation/pull/53893 https://github.com/tgstation/tgstation/pull/54914 Adds custom sound capability for deploy/retract ## Changelog :cl: Zxaber tweak: You can now use drop / use inhand hotkey to retract and deploy arm implants /:cl: --- code/__DEFINES/colors.dm | 2 - code/game/atoms.dm | 1 + code/modules/mob/living/carbon/human/human.dm | 6 ++ code/modules/mob/mob.dm | 11 ++++ code/modules/surgery/organs/augments_arms.dm | 55 +++++++++++++----- .../surgery/organs/augments_internal.dm | 3 +- icons/mob/inhands/weapons/axes_lefthand.dmi | Bin 1900 -> 1901 bytes icons/obj/implants/implant.dmi | Bin 0 -> 5573 bytes icons/obj/surgery.dmi | Bin 50545 -> 44762 bytes 9 files changed, 58 insertions(+), 20 deletions(-) create mode 100644 icons/obj/implants/implant.dmi diff --git a/code/__DEFINES/colors.dm b/code/__DEFINES/colors.dm index c428e1e7dd53..5c6f14c887eb 100644 --- a/code/__DEFINES/colors.dm +++ b/code/__DEFINES/colors.dm @@ -3,7 +3,6 @@ #define COLOR_INPUT_DISABLED "#F0F0F0" #define COLOR_INPUT_ENABLED "#D3B5B5" -//BeginWS #define COLOR_DARKMODE_DARKBACKGROUND "#383838" #define COLOR_DARKMODE_BACKGROUND "#272727" #define COLOR_DARKMODE_HEADER "#ffffff" @@ -23,7 +22,6 @@ #define WOOD_COLOR_BLACK "#332521" #define WOOD_COLOR_CHOCOLATE "#543C30" #define WOOD_COLOR_YELLOW "#E3994E" -//EndWS #define COLOR_WHITE "#FFFFFF" #define COLOR_OFF_WHITE "#FFF5ED" diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 6c6849724bde..8299d389fb18 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -160,6 +160,7 @@ var/hitsound_type = PROJECTILE_HITSOUND_NON_LIVING ///volume wanted for being hit var/hitsound_volume = 50 + /** * Called when an atom is created in byond (built in engine proc) * diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index f3802e381c55..9ae7034366dc 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1057,6 +1057,12 @@ else if(can_be_firemanned(target)) fireman_carry(target) +/mob/living/carbon/human/limb_attack_self() + var/obj/item/bodypart/arm = hand_bodyparts[active_hand_index] + if(arm) + arm.attack_self(src) + return ..() + /mob/living/carbon/human/MouseDrop(mob/over) . = ..() if(ishuman(over)) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index d475891fc28f..7e246dd2d7ac 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -565,6 +565,15 @@ var/msg = "[src] makes eye contact with you." addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), examined_mob, msg), 3) +/** + * Called by using Activate Held Object with an empty hand/limb + * + * Does nothing by default. The intended use is to allow limbs to call their + * own attack_self procs. It is up to the individual mob to override this + * parent and actually use it. + */ +/mob/proc/limb_attack_self() + return ///Can this mob resist (default FALSE) /mob/proc/can_resist() @@ -622,6 +631,8 @@ if(I) I.attack_self(src) update_inv_hands() + return + limb_attack_self() /mob/verb/do_unique_action() set name = "Do Unique Action" diff --git a/code/modules/surgery/organs/augments_arms.dm b/code/modules/surgery/organs/augments_arms.dm index d9d3d6b0b717..5d6fac852d51 100644 --- a/code/modules/surgery/organs/augments_arms.dm +++ b/code/modules/surgery/organs/augments_arms.dm @@ -13,6 +13,10 @@ var/list/items_list = list()// I would use contents, but they shuffle on every activation/deactivation leading to interface inconsistencies. /// You can use this var for item path, it would be converted into an item on New(). var/obj/item/active_item + /// Sound played when extending + var/extend_sound = 'sound/mecha/mechmove03.ogg' + /// Sound played when retracting + var/retract_sound = 'sound/mecha/mechmove03.ogg' /obj/item/organ/cyberimp/arm/Initialize() . = ..() @@ -68,18 +72,34 @@ to_chat(user, "You modify [src] to be installed on the [zone == BODY_ZONE_R_ARM ? "right" : "left"] arm.") update_appearance() +/obj/item/organ/cyberimp/arm/Insert(mob/living/carbon/M, special = FALSE, drop_if_replaced = TRUE) + . = ..() + var/side = zone == BODY_ZONE_R_ARM? RIGHT_HANDS : LEFT_HANDS + hand = owner.hand_bodyparts[side] + if(hand) + RegisterSignal(hand, COMSIG_ITEM_ATTACK_SELF, PROC_REF(ui_action_click)) //If the limb gets an attack-self, open the menu. Only happens when hand is empty + RegisterSignal(M, COMSIG_KB_MOB_DROPITEM_DOWN, PROC_REF(dropkey)) //We're nodrop, but we'll watch for the drop hotkey anyway and then stow if possible. + /obj/item/organ/cyberimp/arm/Remove(mob/living/carbon/M, special = 0) Retract() + if(hand) + UnregisterSignal(hand, COMSIG_ITEM_ATTACK_SELF) + UnregisterSignal(M, COMSIG_KB_MOB_DROPITEM_DOWN) ..() -/obj/item/organ/cyberimp/arm/emp_act(severity) - . = ..() - if(. & EMP_PROTECT_SELF) - return - if(prob(15/severity) && owner) - to_chat(owner, "[src] is hit by EMP!") - // give the owner an idea about why his implant is glitching - Retract() +/** + * Called when the mob uses the "drop item" hotkey + * + * Items inside toolset implants have TRAIT_NODROP, but we can still use the drop item hotkey as a + * quick way to store implant items. In this case, we check to make sure the user has the correct arm + * selected, and that the item is actually owned by us, and then we'll hand off the rest to Retract() +**/ +/obj/item/organ/cyberimp/arm/proc/dropkey(mob/living/carbon/host) + if(!host) + return //How did we even get here + if(hand != host.hand_bodyparts[host.active_hand_index]) + return //wrong hand + Retract() /obj/item/organ/cyberimp/arm/proc/Retract() if(!active_item || (active_item in src)) @@ -89,13 +109,9 @@ "[active_item] snaps back into your [zone == BODY_ZONE_R_ARM ? "right" : "left"] arm.", "You hear a short mechanical noise.") - if(istype(active_item, /obj/item/assembly/flash/armimplant)) - var/obj/item/assembly/flash/F = active_item - F.set_light(0) - owner.transferItemToLoc(active_item, src, TRUE) + playsound(get_turf(owner), retract_sound, 50, TRUE) active_item = null - playsound(get_turf(owner), 'sound/mecha/mechmove03.ogg', 50, TRUE) /obj/item/organ/cyberimp/arm/proc/Extend(obj/item/item) if(!(item in src)) @@ -135,7 +151,7 @@ owner.visible_message("[owner] extends [active_item] from [owner.p_their()] [zone == BODY_ZONE_R_ARM ? "right" : "left"] arm.", "You extend [active_item] from your [zone == BODY_ZONE_R_ARM ? "right" : "left"] arm.", "You hear a short mechanical noise.") - playsound(get_turf(owner), 'sound/mecha/mechmove03.ogg', 50, TRUE) + playsound(get_turf(owner), extend_sound, 50, TRUE) /obj/item/organ/cyberimp/arm/ui_action_click() if((organ_flags & ORGAN_FAILING) || (!active_item && !contents.len)) @@ -161,6 +177,14 @@ else Retract() +/obj/item/organ/cyberimp/arm/emp_act(severity) + . = ..() + if(. & EMP_PROTECT_SELF) + return + if(prob(15/severity) && owner) + to_chat(owner, "[src] is hit by EMP!") + // give the owner an idea about why his implant is glitching + Retract() /obj/item/organ/cyberimp/arm/gun/emp_act(severity) . = ..() @@ -225,7 +249,6 @@ desc = "A cybernetic implant that allows the user to project a healing beam from their hand." items_to_create = list(/obj/item/gun/medbeam) - /obj/item/organ/cyberimp/arm/flash name = "integrated high-intensity photon projector" //Why not desc = "An integrated projector mounted onto a user's arm that is able to be used as a powerful flash." @@ -277,4 +300,4 @@ name = "power cord implant" desc = "An internal power cord hooked up to a battery. Useful if you run on volts." items_to_create = list(/obj/item/apc_powercord) - zone = "l_arm" + zone = BODY_ZONE_L_ARM diff --git a/code/modules/surgery/organs/augments_internal.dm b/code/modules/surgery/organs/augments_internal.dm index ae6f1cf43d39..f623bb67606b 100644 --- a/code/modules/surgery/organs/augments_internal.dm +++ b/code/modules/surgery/organs/augments_internal.dm @@ -2,6 +2,7 @@ /obj/item/organ/cyberimp name = "cybernetic implant" desc = "A state-of-the-art implant that improves a baseline's functionality." + icon = 'icons/obj/implants/implant.dmi' status = ORGAN_ROBOTIC organ_flags = ORGAN_SYNTHETIC var/implant_color = "#FFFFFF" @@ -17,8 +18,6 @@ add_overlay(overlay) return ..() - - //[[[[BRAIN]]]] /obj/item/organ/cyberimp/brain diff --git a/icons/mob/inhands/weapons/axes_lefthand.dmi b/icons/mob/inhands/weapons/axes_lefthand.dmi index 810455a611bdeddf2ebc139dabbaa42a6487d7f2..3b95d17cdc78f766b7c3d91477802abcdfd729d3 100644 GIT binary patch delta 1644 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�h4(i}i9?)b z4MBjgO>>zLmVaZI0?V?xs2uw8a?s`6BZKBXl&4c4SemSwzJ|2FDT=g{4}%e%AfR?I z$07F1wHzL5Jqo9|;ON%D@P{$;4}VJ0myP`Ea5jPA4)|I8^!NyZ zAP9mW2x0(!kDKdT&Q0K~9DYlhW>L{vk}^w;<-2n*Su*%GHMn%D`qRN1}-yD z$bc8vDu414<8LZ}8I&`XSML?hAk-hn1XM#{B1HUkz+7fv@s#BW;9cEssC9}g0)c%-%fyfx==s+$ZkjXaB|SE)t$eTtVx>qqg}M`M|%SNZSM p`k!I*sQAL4$;(4e00@GR{0Ghdk+4h@_Uixu002ovPDHLkV1iv(Co}*6 diff --git a/icons/obj/implants/implant.dmi b/icons/obj/implants/implant.dmi new file mode 100644 index 0000000000000000000000000000000000000000..31bd68db0caf1db32150db31d293ca9f6ca1eae3 GIT binary patch literal 5573 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 F{{YZpd_MpH literal 0 HcmV?d00001 diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi index d94097ddf2e55ef23bbca7a66ac9aaf92e8f59e1..8f2566a98f8ae01a1fd14b2500cf4d6459570462 100644 GIT binary patch literal 44762 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�IeB*Gpmdf4%-|5CKbu;RSzNAYsdToe!ldkotQ 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�!o+w>uT)@-QsjGUi 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 From 206829be14297e298fdd2a954e303825e08c6875 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Thu, 11 Apr 2024 16:13:41 -0500 Subject: [PATCH 14/32] Automatic changelog generation for PR #2741 [ci skip] --- html/changelogs/AutoChangeLog-pr-2741.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2741.yml diff --git a/html/changelogs/AutoChangeLog-pr-2741.yml b/html/changelogs/AutoChangeLog-pr-2741.yml new file mode 100644 index 000000000000..591dae64290a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2741.yml @@ -0,0 +1,4 @@ +author: Zxaber +changes: + - {tweak: You can now use drop / use inhand hotkey to retract and deploy arm implants} +delete-after: true From 1cd05b6a9e7527eb871321926a6c16da899a336e Mon Sep 17 00:00:00 2001 From: SapphicOverload <93578146+SapphicOverload@users.noreply.github.com> Date: Thu, 11 Apr 2024 15:41:21 -0400 Subject: [PATCH 15/32] Reworks the turbine to be an actual engine (#2585) ## About The Pull Request This PR allows the turbine to provide thrust like a real engine while it's running (equivalent to around 4 plasma thrusters while running at maximum power) and fixes a few things like being able to make power from nothing and disconnecting when docking or undocking. Also updates the sprites to make it nicer to look at. ![260364787-c289bee8-8389-48de-a6da-29b305bed64d](https://github.com/shiptest-ss13/Shiptest/assets/93578146/5d8a1d2b-0771-4267-859d-900a8a7d62c9) Sprites are from BeeStation/BeeStation-Hornet#7634, by PestoVerde322 and PacifistDalek ## Why It's Good For The Game For how much worse and less efficient the turbine is at power generation compared to the TEG, I thought it deserved a secondary use to make it more interesting. This also allows for the possibility of a new ship that uses one (or more!) as its main engine, which would be cool. Also turbines violating the laws of thermodynamics to make power from nowhere is maybe bad or something. ## Changelog :cl: sapphicoverload, PestoVerde322, PacifistDalek add: turbines now provide thrust for ships tweak: turbines respect conservation of energy instead of moving gas around for free tweak: turbine control console now shows the internal pressure of the turbine code: refactored how gas flows through the turbine fix: fixed turbines making free energy from nowhere at low RPM fix: fixed turbines forcing air into the output turf when it's blocked fix: fixed turbines not updating air at the input and output turfs fix: fixed turbines disconnecting when docking and undocking imageadd: new turbine sprites /:cl: --- .../whitesands_surface_waterplant.dmm | 2 +- code/game/machinery/shuttle/shuttle_engine.dm | 2 +- .../machinery/shuttle}/turbine.dm | 248 ++++++++++++------ .../circuitboards/machine_circuitboards.dm | 2 +- icons/obj/atmospherics/components/turbine.dmi | Bin 0 -> 9793 bytes shiptest.dme | 2 +- .../tgui/interfaces/TurbineComputer.js | 6 +- 7 files changed, 176 insertions(+), 86 deletions(-) rename code/{modules/power => game/machinery/shuttle}/turbine.dm (54%) create mode 100644 icons/obj/atmospherics/components/turbine.dmi diff --git a/_maps/RandomRuins/SandRuins/whitesands_surface_waterplant.dmm b/_maps/RandomRuins/SandRuins/whitesands_surface_waterplant.dmm index 0babadd59a8d..fe95fca0e82b 100644 --- a/_maps/RandomRuins/SandRuins/whitesands_surface_waterplant.dmm +++ b/_maps/RandomRuins/SandRuins/whitesands_surface_waterplant.dmm @@ -1482,7 +1482,7 @@ /turf/open/floor/plating, /area/ruin/powered) "LM" = ( -/obj/machinery/power/turbine, +/obj/machinery/power/shuttle/engine/turbine, /turf/open/floor/plating/asteroid/whitesands, /area/overmap_encounter/planetoid/sand/explored) "LN" = ( diff --git a/code/game/machinery/shuttle/shuttle_engine.dm b/code/game/machinery/shuttle/shuttle_engine.dm index 267c8d102918..c4fd424d4076 100644 --- a/code/game/machinery/shuttle/shuttle_engine.dm +++ b/code/game/machinery/shuttle/shuttle_engine.dm @@ -12,7 +12,7 @@ var/enabled = TRUE ///How much thrust this engine generates when burned fully. var/thrust = 0 - ///I don't really know what this is but it's used a lot + ///Whether this engine is actively providing thrust to the ship var/thruster_active = FALSE /** diff --git a/code/modules/power/turbine.dm b/code/game/machinery/shuttle/turbine.dm similarity index 54% rename from code/modules/power/turbine.dm rename to code/game/machinery/shuttle/turbine.dm index ba390b1cf873..7d310d37cd30 100644 --- a/code/modules/power/turbine.dm +++ b/code/game/machinery/shuttle/turbine.dm @@ -25,48 +25,60 @@ /obj/machinery/power/compressor name = "compressor" desc = "The compressor stage of a gas turbine generator." - icon = 'icons/obj/atmospherics/pipes/simple.dmi' + icon = 'icons/obj/atmospherics/components/turbine.dmi' icon_state = "compressor" density = TRUE resistance_flags = FIRE_PROOF CanAtmosPass = ATMOS_PASS_DENSITY + use_power = NO_POWER_USE // powered by gas flow + interacts_with_air = TRUE circuit = /obj/item/circuitboard/machine/power_compressor - var/obj/machinery/power/turbine/turbine + var/obj/machinery/power/shuttle/engine/turbine/turbine var/datum/gas_mixture/gas_contained - var/turf/inturf var/starter = 0 var/rpm = 0 var/rpmtarget = 0 var/capacity = 1e6 var/comp_id = 0 - var/efficiency + var/efficiency = 1 + var/intake_ratio = 0.1 // might add a way to adjust this in-game later -/obj/machinery/power/turbine/lavaland +/obj/machinery/power/shuttle/engine/turbine/lavaland destroy_output = TRUE /obj/machinery/power/compressor/Destroy() + SSair.stop_processing_machine(src) if (turbine && turbine.compressor == src) turbine.compressor = null + if(isopenturf(loc)) + loc.assume_air(gas_contained) + loc.air_update_turf() turbine = null return ..() -/obj/machinery/power/turbine +/obj/machinery/power/shuttle/engine/turbine name = "gas turbine generator" desc = "A gas turbine used for backup power generation." - icon = 'icons/obj/atmospherics/pipes/simple.dmi' + icon = 'icons/obj/atmospherics/components/turbine.dmi' icon_state = "turbine" density = TRUE resistance_flags = FIRE_PROOF CanAtmosPass = ATMOS_PASS_DENSITY + use_power = NO_POWER_USE // powered by gas flow + interacts_with_air = TRUE circuit = /obj/item/circuitboard/machine/power_turbine + thrust = 0 // no thrust by default + icon_state_closed = "turbine" + icon_state_open = "turbine" + icon_state_off = "turbine" var/opened = 0 var/obj/machinery/power/compressor/compressor - var/turf/outturf - var/lastgen + var/lastgen = 0 var/productivity = 1 var/destroy_output = FALSE //Destroy the output gas instead of actually outputting it. Used on lavaland to prevent cooking the zlevel -/obj/machinery/power/turbine/Destroy() +/obj/machinery/power/shuttle/engine/turbine/Destroy() + SSair.stop_processing_machine(src) if (compressor && compressor.turbine == src) compressor.turbine = null compressor = null @@ -74,29 +86,39 @@ // the inlet stage of the gas turbine electricity generator -/obj/machinery/power/compressor/Initialize() +/obj/machinery/power/compressor/Initialize(mapload) . = ..() // The inlet of the compressor is the direction it faces gas_contained = new - inturf = get_step(src, dir) + SSair.start_processing_machine(src, mapload) locate_machinery() if(!turbine) obj_break() + return INITIALIZE_HINT_LATELOAD + +/obj/machinery/power/compressor/LateInitialize() + . = ..() + var/turf/comp_turf = get_turf(src) + comp_turf.ImmediateCalculateAdjacentTurfs() // turbine blocks atmos so update the turf it's on or stuff breaks #define COMPFRICTION 5e5 /obj/machinery/power/compressor/locate_machinery() if(turbine) return - turbine = locate() in get_step(src, get_dir(inturf, src)) + turbine = locate() in get_step(src, turn(dir, 180)) if(turbine) + set_machine_stat(machine_stat & ~BROKEN) turbine.locate_machinery() + else + turbine = null + obj_break() /obj/machinery/power/compressor/RefreshParts() var/E = 0 for(var/obj/item/stock_parts/manipulator/M in component_parts) E += M.rating - efficiency = E / 6 + efficiency = max(E / 6, 1) /obj/machinery/power/compressor/examine(mob/user) . = ..() @@ -108,49 +130,63 @@ return if(default_change_direction_wrench(user, I)) - turbine = null - inturf = get_step(src, dir) - locate_machinery() if(turbine) to_chat(user, "Turbine connected.") set_machine_stat(machine_stat & ~BROKEN) else to_chat(user, "Turbine not connected.") - obj_break() return default_deconstruction_crowbar(I) -/obj/machinery/power/compressor/process() - if(!starter) - return - if(!turbine || (turbine.machine_stat & BROKEN)) - starter = FALSE - if(machine_stat & BROKEN || panel_open) - starter = FALSE - return - cut_overlays() - - rpm = 0.9* rpm + 0.1 * rpmtarget +/obj/machinery/power/compressor/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/I) + . = ..() + if(panel_open) + set_machine_stat(machine_stat | MAINT) + else + set_machine_stat(machine_stat & ~MAINT) - // It's a simplified version taking only 1/10 of the moles from the turf nearby. It should be later changed into a better version - // above todo 7 years and counting +//update when moved or changing direction +/obj/machinery/power/compressor/setDir(newdir) + . = ..() + locate_machinery() - inturf.transfer_air_ratio(gas_contained, 0.1) +/obj/machinery/power/compressor/Move(atom/newloc, direct, glide_size_override) + . = ..() + locate_machinery() -// RPM function to include compression friction - be advised that too low/high of a compfriction value can make things screwy +/obj/machinery/power/compressor/process(delta_time) + return +/obj/machinery/power/compressor/process_atmos(delta_time) + // RPM function to include compression friction - be advised that too low/high of a compfriction value can make things screwy + rpm -= 1 + rpm = (0.9 * rpm) + (0.1 * rpmtarget) rpm = min(rpm, (COMPFRICTION*efficiency)/2) - rpm = max(0, rpm - (rpm*rpm)/(COMPFRICTION*efficiency)) + rpm = max(0, rpm - (rpm**2)/(COMPFRICTION*efficiency)) - if(starter && !(machine_stat & NOPOWER)) - use_power(2800) - if(rpm<1000) - rpmtarget = 1000 - else - if(rpm<1000) - rpmtarget = 0 + update_overlays() + + if(!turbine || (turbine.machine_stat & BROKEN)) + locate_machinery() // try to find the other part if we somehow got disconnected + + if((machine_stat & (BROKEN|MAINT)) || !starter) // if we didn't find it... + rpmtarget = 0 + return + + var/turf/inturf = get_step(src, dir) + var/datum/gas_mixture/environment = inturf.return_air() + var/external_pressure = environment.return_pressure() + var/pressure_delta = external_pressure - gas_contained.return_pressure() + + // Equalize the gas between the environment and the internal gas mix + if(pressure_delta > 0) + var/datum/gas_mixture/removed = environment.remove_ratio((1 - ((1 - intake_ratio)**delta_time)) * pressure_delta / (external_pressure * 2)) // silly math to keep it consistent with delta_time + gas_contained.merge(removed) + inturf.air_update_turf() +/obj/machinery/power/compressor/update_overlays() + . = ..() if(rpm>50000) add_overlay(mutable_appearance(icon, "comp-o4", FLY_LAYER)) else if(rpm>10000) @@ -159,91 +195,122 @@ add_overlay(mutable_appearance(icon, "comp-o2", FLY_LAYER)) else if(rpm>500) add_overlay(mutable_appearance(icon, "comp-o1", FLY_LAYER)) - //TODO: DEFERRED // These are crucial to working of a turbine - the stats modify the power output. TurbGenQ modifies how much raw energy can you get from // rpms, TurbGenG modifies the shape of the curve - the lower the value the less straight the curve is. #define TURBGENQ 100000 #define TURBGENG 0.5 +#define POWER_TO_THRUST 0.001 // power production to thrust ratio -/obj/machinery/power/turbine/Initialize() +/obj/machinery/power/shuttle/engine/turbine/Initialize(mapload) . = ..() -// The outlet is pointed at the direction of the turbine component - outturf = get_step(src, dir) + SSair.start_processing_machine(src, mapload) locate_machinery() if(!compressor) obj_break() connect_to_network() + return INITIALIZE_HINT_LATELOAD + +/obj/machinery/power/shuttle/engine/turbine/LateInitialize() + . = ..() + var/turf/comp_turf = get_turf(src) + comp_turf.ImmediateCalculateAdjacentTurfs() // turbine blocks atmos so update the turf it's on or stuff breaks -/obj/machinery/power/turbine/RefreshParts() +/obj/machinery/power/shuttle/engine/turbine/RefreshParts() var/P = 0 for(var/obj/item/stock_parts/capacitor/C in component_parts) P += C.rating productivity = P / 6 -/obj/machinery/power/turbine/examine(mob/user) +/obj/machinery/power/shuttle/engine/turbine/examine(mob/user) . = ..() if(in_range(user, src) || isobserver(user)) . += "The status display reads: Productivity at [productivity*100]%." -/obj/machinery/power/turbine/locate_machinery() +/obj/machinery/power/shuttle/engine/turbine/locate_machinery() if(compressor) return - compressor = locate() in get_step(src, get_dir(outturf, src)) + compressor = locate() in get_step(src, turn(dir, 180)) if(compressor) + set_machine_stat(machine_stat & ~BROKEN) compressor.locate_machinery() + else + compressor = null + obj_break() -/obj/machinery/power/turbine/process() +/obj/machinery/power/shuttle/engine/turbine/process(delta_time) + add_avail(lastgen) // add power in process() so it doesn't update power output separately from the rest of the powernet (bad) + update_overlays() +/obj/machinery/power/shuttle/engine/turbine/process_atmos(delta_time) if(!compressor) set_machine_stat(BROKEN) + locate_machinery() // try to find the missing piece - if((machine_stat & BROKEN) || panel_open) + if(machine_stat & (BROKEN|MAINT)) // we're only running half a turbine, don't continue return - if(!compressor.starter) - return - cut_overlays() // This is the power generation function. If anything is needed it's good to plot it in EXCEL before modifying // the TURBGENQ and TURBGENG values lastgen = ((compressor.rpm / TURBGENQ)**TURBGENG) * TURBGENQ * productivity + thrust = lastgen * POWER_TO_THRUST // second law - add_avail(lastgen) - - // Weird function but it works. Should be something else... - - var/newrpm = ((compressor.gas_contained.return_temperature()) * compressor.gas_contained.total_moles())/4 + var/turf/outturf = get_step(src, dir) + if(!LAZYLEN(outturf.atmos_adjacent_turfs)) + compressor.rpmtarget = 0 + return - newrpm = max(0, newrpm) + // Move gas from the compressor to the outlet + var/datum/gas_mixture/environment = outturf.return_air() + var/internal_pressure = compressor.gas_contained.return_pressure() + var/pressure_delta = internal_pressure - environment.return_pressure() - if(!compressor.starter || newrpm > 1000) - compressor.rpmtarget = newrpm + // Now set the compressor's RPM target based on how much gas is flowing through + compressor.rpmtarget = max(0, pressure_delta * compressor.gas_contained.return_volume() / (R_IDEAL_GAS_EQUATION * 4)) - if(compressor.gas_contained.total_moles()>0) - var/oamount = min(compressor.gas_contained.total_moles(), (compressor.rpm+100)/35000*compressor.capacity) + // Equalize the gas between the internal gas mix and the environment + if(pressure_delta > 0) + var/datum/gas_mixture/removed = compressor.gas_contained.remove_ratio(pressure_delta / (internal_pressure * 2)) if(destroy_output) - compressor.gas_contained.set_moles(compressor.gas_contained.get_moles() - oamount) - else - outturf.assume_air_moles(compressor.gas_contained, oamount) + qdel(removed) + return + outturf.assume_air(removed) + outturf.air_update_turf() + +// Return the current thrust amount +/obj/machinery/power/shuttle/engine/turbine/burn_engine(percentage, deltatime) + return thrust * deltatime * (percentage / 100) + +// Return the current power output +/obj/machinery/power/shuttle/engine/turbine/return_fuel() + return lastgen + +// Return the maximum power output +/obj/machinery/power/shuttle/engine/turbine/return_fuel_cap() + return ((COMPFRICTION*(compressor ? compressor.efficiency : 1) / (TURBGENQ*4))**TURBGENG) * TURBGENQ * productivity + +// Return the maximum power output +/obj/machinery/power/shuttle/engine/turbine/update_engine() + if(!(flags_1 & INITIALIZED_1)) + return FALSE + thruster_active = !panel_open && compressor + return thruster_active // If it works, put an overlay that it works! - +/obj/machinery/power/shuttle/engine/turbine/update_overlays() + . = ..() if(lastgen > 100) add_overlay(mutable_appearance(icon, "turb-o", FLY_LAYER)) -/obj/machinery/power/turbine/attackby(obj/item/I, mob/user, params) +/obj/machinery/power/shuttle/engine/turbine/attackby(obj/item/I, mob/user, params) if(default_deconstruction_screwdriver(user, initial(icon_state), initial(icon_state), I)) return if(default_change_direction_wrench(user, I)) - compressor = null - outturf = get_step(src, dir) - locate_machinery() if(compressor) to_chat(user, "Compressor connected.") - set_machine_stat(machine_stat & ~BROKEN) else to_chat(user, "Compressor not connected.") obj_break() @@ -251,25 +318,42 @@ default_deconstruction_crowbar(I) -/obj/machinery/power/turbine/ui_interact(mob/user, datum/tgui/ui) +/obj/machinery/power/shuttle/engine/turbine/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/I) + . = ..() + if(panel_open) + set_machine_stat(machine_stat | MAINT) + else + set_machine_stat(machine_stat & ~MAINT) + +// update if it moves or changes direction +/obj/machinery/power/shuttle/engine/turbine/setDir(newdir) + . = ..() + locate_machinery() + +/obj/machinery/power/shuttle/engine/turbine/Move(atom/newloc, direct, glide_size_override) + . = ..() + locate_machinery() + +/obj/machinery/power/shuttle/engine/turbine/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) if(!ui) ui = new(user, src, "TurbineComputer", name) ui.open() -/obj/machinery/power/turbine/ui_data(mob/user) +/obj/machinery/power/shuttle/engine/turbine/ui_data(mob/user) var/list/data = list() data["compressor"] = compressor ? TRUE : FALSE - data["compressor_broke"] = (!compressor || (compressor.machine_stat & BROKEN)) ? TRUE : FALSE + data["compressor_broke"] = (!compressor || (compressor.machine_stat & (BROKEN|MAINT))) ? TRUE : FALSE data["turbine"] = compressor?.turbine ? TRUE : FALSE - data["turbine_broke"] = (!compressor || !compressor.turbine || (compressor.turbine.machine_stat & BROKEN)) ? TRUE : FALSE + data["turbine_broke"] = (!compressor || !compressor.turbine || (compressor.turbine.machine_stat & (BROKEN|MAINT))) ? TRUE : FALSE data["online"] = compressor?.starter data["power"] = DisplayPower(compressor?.turbine?.lastgen) data["rpm"] = compressor?.rpm data["temp"] = compressor?.gas_contained.return_temperature() + data["pressure"] = compressor?.gas_contained.return_pressure() return data -/obj/machinery/power/turbine/ui_act(action, params) +/obj/machinery/power/shuttle/engine/turbine/ui_act(action, params) . = ..() if(.) return @@ -306,7 +390,7 @@ /obj/machinery/computer/turbine_computer/locate_machinery() if(id) - for(var/obj/machinery/power/compressor/C in GLOB.machines) + for(var/obj/machinery/power/compressor/C in SSair.atmos_air_machinery) if(C.comp_id == id) compressor = C return @@ -322,13 +406,14 @@ /obj/machinery/computer/turbine_computer/ui_data(mob/user) var/list/data = list() data["compressor"] = compressor ? TRUE : FALSE - data["compressor_broke"] = (!compressor || (compressor.machine_stat & BROKEN)) ? TRUE : FALSE + data["compressor_broke"] = (!compressor || (compressor.machine_stat & (BROKEN|MAINT))) ? TRUE : FALSE data["turbine"] = compressor?.turbine ? TRUE : FALSE - data["turbine_broke"] = (!compressor || !compressor.turbine || (compressor.turbine.machine_stat & BROKEN)) ? TRUE : FALSE + data["turbine_broke"] = (!compressor || !compressor.turbine || (compressor.turbine.machine_stat & (BROKEN|MAINT))) ? TRUE : FALSE data["online"] = compressor?.starter data["power"] = DisplayPower(compressor?.turbine?.lastgen) data["rpm"] = compressor?.rpm data["temp"] = compressor?.gas_contained.return_temperature() + data["pressure"] = compressor?.gas_contained.return_pressure() return data /obj/machinery/computer/turbine_computer/ui_act(action, params) @@ -345,6 +430,7 @@ locate_machinery() . = TRUE +#undef POWER_TO_THRUST #undef COMPFRICTION #undef TURBGENQ #undef TURBGENG diff --git a/code/game/objects/items/circuitboards/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machine_circuitboards.dm index 7b2724f9e53f..9f7831577d4c 100644 --- a/code/game/objects/items/circuitboards/machine_circuitboards.dm +++ b/code/game/objects/items/circuitboards/machine_circuitboards.dm @@ -257,7 +257,7 @@ /obj/item/circuitboard/machine/power_turbine name = "Power Turbine (Machine Board)" icon_state = "engineering" - build_path = /obj/machinery/power/turbine + build_path = /obj/machinery/power/shuttle/engine/turbine req_components = list( /obj/item/stack/cable_coil = 5, /obj/item/stock_parts/capacitor = 6) diff --git a/icons/obj/atmospherics/components/turbine.dmi b/icons/obj/atmospherics/components/turbine.dmi new file mode 100644 index 0000000000000000000000000000000000000000..6e499911a75b7dacc75b3183701b2285ed5bed27 GIT binary patch literal 9793 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 { @@ -11,7 +12,7 @@ export const TurbineComputer = (props, context) => { !data.turbine_broke ); return ( - +
{ {data.temp} K + + {formatSiUnit(data.pressure * 1000, 1, 'Pa')} + {data.power} From 2ff652afdc6b4f3bf26d7ca1f57e40d87b4b28de Mon Sep 17 00:00:00 2001 From: Changelogs Date: Thu, 11 Apr 2024 16:27:39 -0500 Subject: [PATCH 16/32] Automatic changelog generation for PR #2585 [ci skip] --- html/changelogs/AutoChangeLog-pr-2585.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2585.yml diff --git a/html/changelogs/AutoChangeLog-pr-2585.yml b/html/changelogs/AutoChangeLog-pr-2585.yml new file mode 100644 index 000000000000..2e878e3ea310 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2585.yml @@ -0,0 +1,13 @@ +author: sapphicoverload, PestoVerde322, PacifistDalek +changes: + - {rscadd: turbines now provide thrust for ships} + - {tweak: turbines respect conservation of energy instead of moving gas around for + free} + - {tweak: turbine control console now shows the internal pressure of the turbine} + - {code_imp: refactored how gas flows through the turbine} + - {bugfix: fixed turbines making free energy from nowhere at low RPM} + - {bugfix: fixed turbines forcing air into the output turf when it's blocked} + - {bugfix: fixed turbines not updating air at the input and output turfs} + - {bugfix: fixed turbines disconnecting when docking and undocking} + - {imageadd: new turbine sprites} +delete-after: true From aade1d8b4af253bad43909046e6209f333731c05 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Fri, 12 Apr 2024 00:49:16 +0000 Subject: [PATCH 17/32] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-2585.yml | 13 --------- html/changelogs/AutoChangeLog-pr-2696.yml | 4 --- html/changelogs/AutoChangeLog-pr-2741.yml | 4 --- html/changelogs/AutoChangeLog-pr-2784.yml | 4 --- html/changelogs/AutoChangeLog-pr-2839.yml | 6 ---- html/changelogs/AutoChangeLog-pr-2842.yml | 6 ---- html/changelogs/AutoChangeLog-pr-2850.yml | 4 --- html/changelogs/AutoChangeLog-pr-2870.yml | 5 ---- html/changelogs/AutoChangeLog-pr-2875.yml | 4 --- html/changelogs/AutoChangeLog-pr-2878.yml | 4 --- html/changelogs/archive/2024-04.yml | 35 +++++++++++++++++++++++ 11 files changed, 35 insertions(+), 54 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-2585.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-2696.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-2741.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-2784.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-2839.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-2842.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-2850.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-2870.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-2875.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-2878.yml diff --git a/html/changelogs/AutoChangeLog-pr-2585.yml b/html/changelogs/AutoChangeLog-pr-2585.yml deleted file mode 100644 index 2e878e3ea310..000000000000 --- a/html/changelogs/AutoChangeLog-pr-2585.yml +++ /dev/null @@ -1,13 +0,0 @@ -author: sapphicoverload, PestoVerde322, PacifistDalek -changes: - - {rscadd: turbines now provide thrust for ships} - - {tweak: turbines respect conservation of energy instead of moving gas around for - free} - - {tweak: turbine control console now shows the internal pressure of the turbine} - - {code_imp: refactored how gas flows through the turbine} - - {bugfix: fixed turbines making free energy from nowhere at low RPM} - - {bugfix: fixed turbines forcing air into the output turf when it's blocked} - - {bugfix: fixed turbines not updating air at the input and output turfs} - - {bugfix: fixed turbines disconnecting when docking and undocking} - - {imageadd: new turbine sprites} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-2696.yml b/html/changelogs/AutoChangeLog-pr-2696.yml deleted file mode 100644 index 05b6fa459451..000000000000 --- a/html/changelogs/AutoChangeLog-pr-2696.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: Martinpachu -changes: - - {bugfix: Fixes MAA on the Colossus not being able to access the bridge.} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-2741.yml b/html/changelogs/AutoChangeLog-pr-2741.yml deleted file mode 100644 index 591dae64290a..000000000000 --- a/html/changelogs/AutoChangeLog-pr-2741.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: Zxaber -changes: - - {tweak: You can now use drop / use inhand hotkey to retract and deploy arm implants} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-2784.yml b/html/changelogs/AutoChangeLog-pr-2784.yml deleted file mode 100644 index 057247d90928..000000000000 --- a/html/changelogs/AutoChangeLog-pr-2784.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: thgvr -changes: - - {rscadd: Suicide & Execution with a damaging firearm is now more deadly and gruesome.} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-2839.yml b/html/changelogs/AutoChangeLog-pr-2839.yml deleted file mode 100644 index f877777a0a31..000000000000 --- a/html/changelogs/AutoChangeLog-pr-2839.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: Gristlebee -changes: - - {rscadd: Punching bags can be built with 5 cloth.} - - {rscadd: Bench press and chest press can be built with 5 metal.} - - {rscadd: Exercise equipment can be deconstructed.} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-2842.yml b/html/changelogs/AutoChangeLog-pr-2842.yml deleted file mode 100644 index 97812c9c1871..000000000000 --- a/html/changelogs/AutoChangeLog-pr-2842.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: meemofcourse -changes: - - {rscadd: Long-range bluespace technologies in fax machines now allow the faxing - of photos. I am not responsible for any consequences that might result from - sending your faction's command personnel a photo of your character's ass.} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-2850.yml b/html/changelogs/AutoChangeLog-pr-2850.yml deleted file mode 100644 index 7269f7dc9dc6..000000000000 --- a/html/changelogs/AutoChangeLog-pr-2850.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: SomeguyManperson -changes: - - {bugfix: anesthetic can no longer semi permanently knock people out} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-2870.yml b/html/changelogs/AutoChangeLog-pr-2870.yml deleted file mode 100644 index da114a147340..000000000000 --- a/html/changelogs/AutoChangeLog-pr-2870.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: phoaly -changes: - - {rscdel: Removed some old ships} - - {tweak: Aspawned the Lagoon and Junker} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-2875.yml b/html/changelogs/AutoChangeLog-pr-2875.yml deleted file mode 100644 index e0b1b326f569..000000000000 --- a/html/changelogs/AutoChangeLog-pr-2875.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: Sadhorizon -changes: - - {tweak: Random blood packs now can roll Elzu and IPC blood.} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-2878.yml b/html/changelogs/AutoChangeLog-pr-2878.yml deleted file mode 100644 index 2ed39362f2b1..000000000000 --- a/html/changelogs/AutoChangeLog-pr-2878.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: Yata9ar4su -changes: - - {rscadd: Fullscreen on F11} -delete-after: true diff --git a/html/changelogs/archive/2024-04.yml b/html/changelogs/archive/2024-04.yml index 4554d939d8b3..ae6b53f8ebdc 100644 --- a/html/changelogs/archive/2024-04.yml +++ b/html/changelogs/archive/2024-04.yml @@ -19,3 +19,38 @@ Imaginos16, spookywastaken: - rscadd: Resprites a ton of gun magazines - bugfix: Changes how magainzes with only a empty and loaded state are +2024-04-12: + Gristlebee: + - rscadd: Punching bags can be built with 5 cloth. + - rscadd: Bench press and chest press can be built with 5 metal. + - rscadd: Exercise equipment can be deconstructed. + Martinpachu: + - bugfix: Fixes MAA on the Colossus not being able to access the bridge. + Sadhorizon: + - tweak: Random blood packs now can roll Elzu and IPC blood. + SomeguyManperson: + - bugfix: anesthetic can no longer semi permanently knock people out + Yata9ar4su: + - rscadd: Fullscreen on F11 + Zxaber: + - tweak: You can now use drop / use inhand hotkey to retract and deploy arm implants + meemofcourse: + - rscadd: Long-range bluespace technologies in fax machines now allow the faxing + of photos. I am not responsible for any consequences that might result from + sending your faction's command personnel a photo of your character's ass. + phoaly: + - rscdel: Removed some old ships + - tweak: Aspawned the Lagoon and Junker + sapphicoverload, PestoVerde322, PacifistDalek: + - rscadd: turbines now provide thrust for ships + - tweak: turbines respect conservation of energy instead of moving gas around for + free + - tweak: turbine control console now shows the internal pressure of the turbine + - code_imp: refactored how gas flows through the turbine + - bugfix: fixed turbines making free energy from nowhere at low RPM + - bugfix: fixed turbines forcing air into the output turf when it's blocked + - bugfix: fixed turbines not updating air at the input and output turfs + - bugfix: fixed turbines disconnecting when docking and undocking + - imageadd: new turbine sprites + thgvr: + - rscadd: Suicide & Execution with a damaging firearm is now more deadly and gruesome. From 7b6da277229c727b179bc8dfd2df3adf58657aeb Mon Sep 17 00:00:00 2001 From: FalloutFalcon <86381784+FalloutFalcon@users.noreply.github.com> Date: Fri, 12 Apr 2024 03:47:43 -0500 Subject: [PATCH 18/32] Survival boxes now have radios (#2852) ## About The Pull Request All radios now start turned off. All survival boxes now have radios. Also some random cleanup. like 100 radios varedited radios in the exact same way. Removed some boxes originally designed to give radios ## Why It's Good For The Game Less lag. now every ship densest need 700 radios ## Changelog :cl: tweak: all radios start off tweak: all survival boxs start with a radio /:cl: --- .../BeachRuins/beach_crashed_starwalker.dmm | 7 +-- .../JungleRuins/jungle_paradise.dmm | 5 +- .../RockRuins/rockplanet_budgetcuts.dmm | 5 +- .../RockRuins/rockplanet_crash.dmm | 2 +- .../whitesands_surface_pubbyslopcrash.dmm | 2 +- _maps/RandomRuins/SpaceRuins/scav_mining.dmm | 2 +- _maps/map_files/generic/CentCom.dmm | 4 +- _maps/outpost/nanotrasen_asteroid.dmm | 5 +- .../independent/independent_dwayne.dmm | 4 +- .../shuttles/independent/independent_kilo.dmm | 4 +- .../shuttles/nanotrasen/nanotrasen_heron.dmm | 42 +++---------- _maps/shuttles/nanotrasen/nanotrasen_meta.dmm | 6 +- _maps/shuttles/pirate/pirate_ember.dmm | 60 ++++--------------- code/_globalvars/lists/maintenance_loot.dm | 2 +- .../game/objects/effects/spawners/lootdrop.dm | 2 +- .../game/objects/items/devices/radio/radio.dm | 8 +-- code/game/objects/items/storage/boxes.dm | 18 +----- code/game/objects/items/storage/toolbox.dm | 2 +- .../objects/structures/ghost_role_spawners.dm | 2 +- .../modules/client/loadout/loadout_general.dm | 4 -- .../clothing/outfits/ert/nanotrasen_ert.dm | 7 +-- .../clothing/outfits/factions/minutemen.dm | 2 +- .../hostile/mining_mobs/hivelord.dm | 4 +- .../research/designs/autolathe_designs.dm | 2 +- 24 files changed, 52 insertions(+), 149 deletions(-) diff --git a/_maps/RandomRuins/BeachRuins/beach_crashed_starwalker.dmm b/_maps/RandomRuins/BeachRuins/beach_crashed_starwalker.dmm index 346458a87daf..0839518362b4 100644 --- a/_maps/RandomRuins/BeachRuins/beach_crashed_starwalker.dmm +++ b/_maps/RandomRuins/BeachRuins/beach_crashed_starwalker.dmm @@ -1159,10 +1159,7 @@ /obj/item/flashlight/lantern{ pixel_x = 8 }, -/obj/item/radio{ - desc = "An old handheld radio. You could use it, if you really wanted to."; - icon_state = "radio"; - name = "old radio"; +/obj/item/radio/old{ pixel_x = -5; pixel_y = -2 }, @@ -3103,7 +3100,7 @@ /obj/structure/cable/blue{ icon_state = "2-8" }, -/obj/item/radio/off{ +/obj/item/radio{ pixel_x = -7 }, /turf/open/floor/plating{ diff --git a/_maps/RandomRuins/JungleRuins/jungle_paradise.dmm b/_maps/RandomRuins/JungleRuins/jungle_paradise.dmm index cda541385b56..bc462784bca8 100644 --- a/_maps/RandomRuins/JungleRuins/jungle_paradise.dmm +++ b/_maps/RandomRuins/JungleRuins/jungle_paradise.dmm @@ -2879,10 +2879,7 @@ /obj/structure/railing{ layer = 3.9 }, -/obj/item/radio{ - desc = "An old handheld radio. You could use it, if you really wanted to."; - icon_state = "radio"; - name = "old radio"; +/obj/item/radio/old{ pixel_x = 4; pixel_y = 5 }, diff --git a/_maps/RandomRuins/RockRuins/rockplanet_budgetcuts.dmm b/_maps/RandomRuins/RockRuins/rockplanet_budgetcuts.dmm index b1ccc301325d..8d066f6f04b4 100644 --- a/_maps/RandomRuins/RockRuins/rockplanet_budgetcuts.dmm +++ b/_maps/RandomRuins/RockRuins/rockplanet_budgetcuts.dmm @@ -760,10 +760,7 @@ /obj/structure/table/reinforced{ color = "#c1b6a5" }, -/obj/item/radio{ - desc = "An old handheld radio. You could use it, if you really wanted to."; - icon_state = "radio"; - name = "old radio"; +/obj/item/radio/old{ pixel_x = -5; pixel_y = 2 }, diff --git a/_maps/RandomRuins/RockRuins/rockplanet_crash.dmm b/_maps/RandomRuins/RockRuins/rockplanet_crash.dmm index 2d69be814e35..43db217f9dcb 100644 --- a/_maps/RandomRuins/RockRuins/rockplanet_crash.dmm +++ b/_maps/RandomRuins/RockRuins/rockplanet_crash.dmm @@ -906,7 +906,7 @@ /area/ruin/unpowered) "BX" = ( /obj/structure/table, -/obj/item/radio/off{ +/obj/item/radio{ pixel_x = 6; pixel_y = 14 }, diff --git a/_maps/RandomRuins/SandRuins/whitesands_surface_pubbyslopcrash.dmm b/_maps/RandomRuins/SandRuins/whitesands_surface_pubbyslopcrash.dmm index 244eef61fa03..e4d83a8eb842 100644 --- a/_maps/RandomRuins/SandRuins/whitesands_surface_pubbyslopcrash.dmm +++ b/_maps/RandomRuins/SandRuins/whitesands_surface_pubbyslopcrash.dmm @@ -686,7 +686,7 @@ "oO" = ( /obj/structure/table/reinforced, /obj/item/laser_pointer, -/obj/item/radio/off{ +/obj/item/radio{ pixel_x = 6; pixel_y = 14 }, diff --git a/_maps/RandomRuins/SpaceRuins/scav_mining.dmm b/_maps/RandomRuins/SpaceRuins/scav_mining.dmm index 48476edb1b82..cc1e434dc75b 100644 --- a/_maps/RandomRuins/SpaceRuins/scav_mining.dmm +++ b/_maps/RandomRuins/SpaceRuins/scav_mining.dmm @@ -347,7 +347,7 @@ /turf/open/floor/plating/airless, /area/ruin/space/has_grav/scav_mining/core) "xC" = ( -/obj/item/radio/off, +/obj/item/radio, /obj/effect/decal/cleanable/dirt/dust, /obj/structure/cable{ icon_state = "1-2" diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm index 2901c166a10c..bd6d72b49562 100644 --- a/_maps/map_files/generic/CentCom.dmm +++ b/_maps/map_files/generic/CentCom.dmm @@ -3929,7 +3929,7 @@ /area/centcom/evac) "aLE" = ( /obj/structure/table, -/obj/item/radio/off, +/obj/item/radio, /turf/open/floor/mineral/titanium/blue, /area/centcom/evac) "aLF" = ( @@ -3955,7 +3955,7 @@ /area/centcom/evac) "aLJ" = ( /obj/structure/table, -/obj/item/radio/off, +/obj/item/radio, /obj/machinery/light/directional/east, /turf/open/floor/mineral/titanium/blue, /area/centcom/evac) diff --git a/_maps/outpost/nanotrasen_asteroid.dmm b/_maps/outpost/nanotrasen_asteroid.dmm index 800ea0cf0cbb..2ea6c907e80e 100644 --- a/_maps/outpost/nanotrasen_asteroid.dmm +++ b/_maps/outpost/nanotrasen_asteroid.dmm @@ -3191,10 +3191,7 @@ /area/outpost/crew/bar) "lS" = ( /obj/structure/table/reinforced, -/obj/item/radio{ - desc = "An old handheld radio. You could use it, if you really wanted to."; - icon_state = "radio"; - name = "old radio"; +/obj/item/radio/old{ pixel_x = 2; pixel_y = 4 }, diff --git a/_maps/shuttles/independent/independent_dwayne.dmm b/_maps/shuttles/independent/independent_dwayne.dmm index 4e7e52e85dff..f72fb5396d21 100644 --- a/_maps/shuttles/independent/independent_dwayne.dmm +++ b/_maps/shuttles/independent/independent_dwayne.dmm @@ -563,7 +563,7 @@ pixel_x = -9; pixel_y = 7 }, -/obj/item/radio/off{ +/obj/item/radio{ pixel_x = 6; pixel_y = 7 }, @@ -2125,7 +2125,7 @@ "WL" = ( /obj/structure/table, /obj/item/storage/belt/utility, -/obj/item/radio/off{ +/obj/item/radio{ pixel_x = 6; pixel_y = 7 }, diff --git a/_maps/shuttles/independent/independent_kilo.dmm b/_maps/shuttles/independent/independent_kilo.dmm index 29264dd2958f..556b235dafc5 100644 --- a/_maps/shuttles/independent/independent_kilo.dmm +++ b/_maps/shuttles/independent/independent_kilo.dmm @@ -2267,11 +2267,11 @@ /obj/effect/decal/cleanable/dirt/dust, /obj/structure/rack, /obj/item/storage/belt/utility, -/obj/item/radio/off{ +/obj/item/radio{ pixel_x = -3; pixel_y = 3 }, -/obj/item/radio/off, +/obj/item/radio, /obj/effect/turf_decal/industrial/hatch/yellow, /turf/open/floor/mineral/plastitanium, /area/ship/cargo) diff --git a/_maps/shuttles/nanotrasen/nanotrasen_heron.dmm b/_maps/shuttles/nanotrasen/nanotrasen_heron.dmm index 24e603883385..ba2c8c61533e 100644 --- a/_maps/shuttles/nanotrasen/nanotrasen_heron.dmm +++ b/_maps/shuttles/nanotrasen/nanotrasen_heron.dmm @@ -3851,7 +3851,7 @@ "oa" = ( /obj/item/multitool, /obj/item/clothing/glasses/meson/engine/tray, -/obj/item/radio/off, +/obj/item/radio, /obj/item/storage/belt/utility/atmostech, /obj/item/holosign_creator/atmos, /obj/item/analyzer, @@ -8660,52 +8660,31 @@ /obj/item/flashlight, /obj/item/flashlight, /obj/item/flashlight, -/obj/item/radio{ - desc = "An old handheld radio. You could use it, if you really wanted to."; - icon_state = "radio"; - name = "old radio"; +/obj/item/radio/old{ pixel_x = -5; pixel_y = 2 }, -/obj/item/radio{ - desc = "An old handheld radio. You could use it, if you really wanted to."; - icon_state = "radio"; - name = "old radio"; +/obj/item/radio/old{ pixel_x = -5; pixel_y = 2 }, -/obj/item/radio{ - desc = "An old handheld radio. You could use it, if you really wanted to."; - icon_state = "radio"; - name = "old radio"; +/obj/item/radio/old{ pixel_x = -5; pixel_y = 2 }, -/obj/item/radio{ - desc = "An old handheld radio. You could use it, if you really wanted to."; - icon_state = "radio"; - name = "old radio"; +/obj/item/radio/old{ pixel_x = -5; pixel_y = 2 }, -/obj/item/radio{ - desc = "An old handheld radio. You could use it, if you really wanted to."; - icon_state = "radio"; - name = "old radio"; +/obj/item/radio/old{ pixel_x = -5; pixel_y = 2 }, -/obj/item/radio{ - desc = "An old handheld radio. You could use it, if you really wanted to."; - icon_state = "radio"; - name = "old radio"; +/obj/item/radio/old{ pixel_x = -5; pixel_y = 2 }, -/obj/item/radio{ - desc = "An old handheld radio. You could use it, if you really wanted to."; - icon_state = "radio"; - name = "old radio"; +/obj/item/radio/old{ pixel_x = -5; pixel_y = 2 }, @@ -10507,10 +10486,7 @@ "MM" = ( /obj/effect/turf_decal/corner/transparent/beige/full, /obj/structure/table, -/obj/item/radio{ - desc = "An old handheld radio. You could use it, if you really wanted to."; - icon_state = "radio"; - name = "old radio"; +/obj/item/radio/old{ pixel_x = -5; pixel_y = 10 }, diff --git a/_maps/shuttles/nanotrasen/nanotrasen_meta.dmm b/_maps/shuttles/nanotrasen/nanotrasen_meta.dmm index 70be6e034c6c..e01ceabaf3b3 100644 --- a/_maps/shuttles/nanotrasen/nanotrasen_meta.dmm +++ b/_maps/shuttles/nanotrasen/nanotrasen_meta.dmm @@ -227,7 +227,7 @@ pixel_x = -2; pixel_y = -4 }, -/obj/item/radio/off{ +/obj/item/radio{ pixel_x = 6; pixel_y = 7 }, @@ -2237,8 +2237,8 @@ /obj/item/storage/belt/utility{ pixel_y = 6 }, -/obj/item/radio/off, -/obj/item/radio/off{ +/obj/item/radio, +/obj/item/radio{ pixel_x = -3; pixel_y = 3 }, diff --git a/_maps/shuttles/pirate/pirate_ember.dmm b/_maps/shuttles/pirate/pirate_ember.dmm index 8ab4711581dc..2694926c67ae 100644 --- a/_maps/shuttles/pirate/pirate_ember.dmm +++ b/_maps/shuttles/pirate/pirate_ember.dmm @@ -7756,87 +7756,51 @@ pixel_y = -28; dir = 1 }, -/obj/item/radio{ - desc = "An old handheld radio. You could use it, if you really wanted to."; - icon_state = "radio"; - name = "old radio"; +/obj/item/radio/old{ pixel_x = 2; pixel_y = 9 }, -/obj/item/radio{ - desc = "An old handheld radio. You could use it, if you really wanted to."; - icon_state = "radio"; - name = "old radio"; +/obj/item/radio/old{ pixel_x = 2; pixel_y = 9 }, -/obj/item/radio{ - desc = "An old handheld radio. You could use it, if you really wanted to."; - icon_state = "radio"; - name = "old radio"; +/obj/item/radio/old{ pixel_x = 2; pixel_y = 9 }, -/obj/item/radio{ - desc = "An old handheld radio. You could use it, if you really wanted to."; - icon_state = "radio"; - name = "old radio"; +/obj/item/radio/old{ pixel_x = 2; pixel_y = 9 }, -/obj/item/radio{ - desc = "An old handheld radio. You could use it, if you really wanted to."; - icon_state = "radio"; - name = "old radio"; +/obj/item/radio/old{ pixel_x = 2; pixel_y = 9 }, -/obj/item/radio{ - desc = "An old handheld radio. You could use it, if you really wanted to."; - icon_state = "radio"; - name = "old radio"; +/obj/item/radio/old{ pixel_x = 2; pixel_y = 9 }, -/obj/item/radio{ - desc = "An old handheld radio. You could use it, if you really wanted to."; - icon_state = "radio"; - name = "old radio"; +/obj/item/radio/old{ pixel_x = 2; pixel_y = 9 }, -/obj/item/radio{ - desc = "An old handheld radio. You could use it, if you really wanted to."; - icon_state = "radio"; - name = "old radio"; +/obj/item/radio/old{ pixel_x = 2; pixel_y = 9 }, -/obj/item/radio{ - desc = "An old handheld radio. You could use it, if you really wanted to."; - icon_state = "radio"; - name = "old radio"; +/obj/item/radio/old{ pixel_x = 2; pixel_y = 9 }, -/obj/item/radio{ - desc = "An old handheld radio. You could use it, if you really wanted to."; - icon_state = "radio"; - name = "old radio"; +/obj/item/radio/old{ pixel_x = 2; pixel_y = 9 }, -/obj/item/radio{ - desc = "An old handheld radio. You could use it, if you really wanted to."; - icon_state = "radio"; - name = "old radio"; +/obj/item/radio/old{ pixel_x = 2; pixel_y = 9 }, -/obj/item/radio{ - desc = "An old handheld radio. You could use it, if you really wanted to."; - icon_state = "radio"; - name = "old radio"; +/obj/item/radio/old{ pixel_x = 2; pixel_y = 9 }, diff --git a/code/_globalvars/lists/maintenance_loot.dm b/code/_globalvars/lists/maintenance_loot.dm index 0091b88fa15f..59f25efe9823 100644 --- a/code/_globalvars/lists/maintenance_loot.dm +++ b/code/_globalvars/lists/maintenance_loot.dm @@ -138,7 +138,7 @@ GLOBAL_LIST_INIT(common_loot, list( //common: basic items ) = 1, list(//misc - /obj/item/radio/off = 1, + /obj/item/radio = 1, /obj/item/extinguisher = 1, /obj/item/tank/internals/emergency_oxygen = 1, /obj/item/bodybag = 1, diff --git a/code/game/objects/effects/spawners/lootdrop.dm b/code/game/objects/effects/spawners/lootdrop.dm index 3370c8b4543d..d763c46e84e9 100644 --- a/code/game/objects/effects/spawners/lootdrop.dm +++ b/code/game/objects/effects/spawners/lootdrop.dm @@ -87,7 +87,7 @@ /obj/item/assembly/flash/handheld = 1, /obj/item/restraints/handcuffs/cable/zipties = 1, /obj/item/restraints/handcuffs = 1, - /obj/item/radio/off = 1, + /obj/item/radio = 1, /obj/item/lighter = 3, /obj/item/storage/box/matches = 3, /obj/item/reagent_containers/syringe/contraband/space_drugs = 1, diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index dc35bebb1e30..cc528f103fe2 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -27,7 +27,7 @@ var/last_chatter_time // The time since we last played a radio chatter sound. (WS edit - Radio Chatter #434) var/broadcasting = FALSE // Whether the radio will transmit dialogue it hears nearby. - var/listening = TRUE // Whether the radio is currently receiving. + var/listening = FALSE // Whether the radio is currently receiving. var/prison_radio = FALSE // If true, the transmit wire starts cut. var/unscrewed = FALSE // Whether wires are accessible. Toggleable by screwdrivering. var/freerange = FALSE // If true, the radio has access to the full spectrum. @@ -436,12 +436,6 @@ recalculateChannels() - -/obj/item/radio/off // Station bounced radios, their only difference is spawning with the speakers off, this was made to help the lag. - listening = 0 // And it's nice to have a subtype too for future features. - dog_fashion = /datum/dog_fashion/back - - /obj/item/radio/old name = "old radio" icon_state = "radio" diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm index 3c9395208fad..d3b5913bbd86 100644 --- a/code/game/objects/items/storage/boxes.dm +++ b/code/game/objects/items/storage/boxes.dm @@ -121,9 +121,11 @@ var/mask_type = /obj/item/clothing/mask/breath var/internal_type = /obj/item/tank/internals/emergency_oxygen var/medipen_type = /obj/item/reagent_containers/hypospray/medipen + var/radio_type = /obj/item/radio /obj/item/storage/box/survival/PopulateContents() new mask_type(src) + new radio_type(src) if(!isnull(medipen_type)) new medipen_type(src) @@ -132,10 +134,6 @@ else new /obj/item/tank/internals/plasmaman/belt(src) -/obj/item/storage/box/survival/radio/PopulateContents() - ..() // we want the survival stuff too. - new /obj/item/radio/off(src) - // Mining survival box /obj/item/storage/box/survival/mining mask_type = /obj/item/clothing/mask/gas/explorer @@ -148,10 +146,6 @@ /obj/item/storage/box/survival/engineer internal_type = /obj/item/tank/internals/emergency_oxygen/engi -/obj/item/storage/box/survival/engineer/radio/PopulateContents() - ..() // we want the regular items too. - new /obj/item/radio/off(src) - // Syndie survival box /obj/item/storage/box/survival/syndie mask_type = /obj/item/clothing/mask/gas/syndicate @@ -162,10 +156,6 @@ /obj/item/storage/box/survival/security mask_type = /obj/item/clothing/mask/gas/sechailer -/obj/item/storage/box/survival/security/radio/PopulateContents() - ..() // we want the regular stuff too - new /obj/item/radio/off(src) - // Medical survival box /obj/item/storage/box/survival/medical mask_type = /obj/item/clothing/mask/breath/medical @@ -173,10 +163,6 @@ /obj/item/storage/box/survival/clip internal_type = /obj/item/tank/internals/emergency_oxygen/engi //clip actually cares about their personnel -/obj/item/storage/box/survival/clip/PopulateContents() - . = ..() - new /obj/item/radio/off(src) - /obj/item/storage/box/survival/clip/balaclava mask_type = /obj/item/clothing/mask/gas/sechailer/balaclava diff --git a/code/game/objects/items/storage/toolbox.dm b/code/game/objects/items/storage/toolbox.dm index 7b02bd6b19d3..c703aeb38a0d 100644 --- a/code/game/objects/items/storage/toolbox.dm +++ b/code/game/objects/items/storage/toolbox.dm @@ -56,7 +56,7 @@ new /obj/item/flashlight/glowstick(src) if(3) new /obj/item/flashlight/flare(src) - new /obj/item/radio/off(src) + new /obj/item/radio(src) /obj/item/storage/toolbox/emergency/old name = "rusty red toolbox" diff --git a/code/game/objects/structures/ghost_role_spawners.dm b/code/game/objects/structures/ghost_role_spawners.dm index abc67e252d52..112218650f85 100644 --- a/code/game/objects/structures/ghost_role_spawners.dm +++ b/code/game/objects/structures/ghost_role_spawners.dm @@ -149,7 +149,7 @@ name = "Demonic Friend" uniform = /obj/item/clothing/under/misc/assistantformal shoes = /obj/item/clothing/shoes/laceup - r_pocket = /obj/item/radio/off + r_pocket = /obj/item/radio back = /obj/item/storage/backpack implants = list(/obj/item/implant/mindshield) //No revolutionaries, he's MY friend. id = /obj/item/card/id diff --git a/code/modules/client/loadout/loadout_general.dm b/code/modules/client/loadout/loadout_general.dm index 042315cc981f..5b8df328e6e2 100644 --- a/code/modules/client/loadout/loadout_general.dm +++ b/code/modules/client/loadout/loadout_general.dm @@ -102,10 +102,6 @@ display_name = "cane" path = /obj/item/cane -/datum/gear/radio - display_name = "hand radio" - path = /obj/item/radio - /datum/gear/lizard display_name = "toy, lizard plushie" path = /obj/item/toy/plush/lizardplushie diff --git a/code/modules/clothing/outfits/ert/nanotrasen_ert.dm b/code/modules/clothing/outfits/ert/nanotrasen_ert.dm index 7e39f0b2f32a..36445abcdb5a 100644 --- a/code/modules/clothing/outfits/ert/nanotrasen_ert.dm +++ b/code/modules/clothing/outfits/ert/nanotrasen_ert.dm @@ -282,7 +282,7 @@ suit = /obj/item/clothing/suit/armor/vest/marine back = /obj/item/storage/backpack/ert backpack_contents = list( - /obj/item/storage/box/survival/engineer/radio = 1, + /obj/item/storage/box/survival/engineer = 1, /obj/item/gun_voucher/nanotrasen = 1 ) belt = /obj/item/storage/belt/military/assault @@ -332,7 +332,7 @@ l_pocket = /obj/item/healthanalyzer head = /obj/item/clothing/head/helmet/marine/medic backpack_contents = list( - /obj/item/storage/box/survival/engineer/radio = 1, + /obj/item/storage/box/survival/engineer = 1, /obj/item/gun_voucher/nanotrasen = 1, /obj/item/reagent_containers/hypospray/combat = 1, /obj/item/storage/firstaid/regular = 1, @@ -359,7 +359,7 @@ head = /obj/item/clothing/head/helmet/marine/engineer back = /obj/item/storage/backpack/ert/engineer backpack_contents = list( - /obj/item/storage/box/survival/engineer/radio = 1, + /obj/item/storage/box/survival/engineer = 1, /obj/item/gun_voucher/nanotrasen = 1, /obj/item/rcd_ammo/large = 2, ) @@ -460,6 +460,5 @@ glasses = /obj/item/clothing/glasses/hud/security/sunglasses back = /obj/item/storage/backpack/ert - box = /obj/item/storage/box/survival/radio l_pocket = /obj/item/megaphone/command r_pocket = /obj/item/binoculars diff --git a/code/modules/clothing/outfits/factions/minutemen.dm b/code/modules/clothing/outfits/factions/minutemen.dm index 9de9c0d152c3..a8ce0907a35a 100644 --- a/code/modules/clothing/outfits/factions/minutemen.dm +++ b/code/modules/clothing/outfits/factions/minutemen.dm @@ -308,7 +308,7 @@ suit = /obj/item/clothing/suit/armor/vest/capcarapace/clip shoes = /obj/item/clothing/shoes/combat - box = /obj/item/storage/box/survival/engineer/radio + box = /obj/item/storage/box/survival/engineer backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1, /obj/item/gun/ballistic/revolver/mateba=1) /datum/outfit/job/clip/minutemen/captain/general/admiral // for flavor, might remove outright diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm index b602e948af98..3137933fa124 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm @@ -756,7 +756,7 @@ r_pocket = pickweight(list( /obj/item/reagent_containers/hypospray/medipen/stimpack = 1, /obj/item/kitchen/knife/letter_opener = 3, - /obj/item/radio/off = 3, + /obj/item/radio = 3, /obj/item/grenade/syndieminibomb/concussion = 1, /obj/item/melee/transforming/energy/ctf/solgov = 1 ) @@ -765,7 +765,7 @@ l_pocket = pickweight(list( /obj/item/reagent_containers/hypospray/medipen/stimpack = 1, /obj/item/kitchen/knife/letter_opener = 3, - /obj/item/radio/off = 3, + /obj/item/radio = 3, /obj/item/grenade/syndieminibomb/concussion = 1, /obj/item/melee/transforming/energy/ctf/solgov = 1 ) diff --git a/code/modules/research/designs/autolathe_designs.dm b/code/modules/research/designs/autolathe_designs.dm index f580502e0b7a..7c43c3fc5acb 100644 --- a/code/modules/research/designs/autolathe_designs.dm +++ b/code/modules/research/designs/autolathe_designs.dm @@ -647,7 +647,7 @@ id = "bounced_radio" build_type = AUTOLATHE materials = list(/datum/material/iron = 75, /datum/material/glass = 25) - build_path = /obj/item/radio/off + build_path = /obj/item/radio category = list("initial", "T-Comm") /datum/design/intercom_frame From 7b83f4eacef247f54af2c8cbf4d0dbf5b0cb60f2 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Fri, 12 Apr 2024 03:58:50 -0500 Subject: [PATCH 19/32] Automatic changelog generation for PR #2852 [ci skip] --- html/changelogs/AutoChangeLog-pr-2852.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2852.yml diff --git a/html/changelogs/AutoChangeLog-pr-2852.yml b/html/changelogs/AutoChangeLog-pr-2852.yml new file mode 100644 index 000000000000..733e4972678f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2852.yml @@ -0,0 +1,5 @@ +author: FalloutFalcon +changes: + - {tweak: all radios start off} + - {tweak: all survival boxs start with a radio} +delete-after: true From 0b6db23a35a4b6e712ff0175c3d0377ff27f9c0d Mon Sep 17 00:00:00 2001 From: Sun-Soaked <45698967+Sun-Soaked@users.noreply.github.com> Date: Fri, 12 Apr 2024 04:47:59 -0400 Subject: [PATCH 20/32] Landmine Rework (#2759) ## About The Pull Request Comprehensive rework of landmines. - [x] Turn mines into an item - [x] Port a bunch of tg improvements - [x] Port tg shrapnel fixes - [x] Add inhand mine deploying - [x] Mines now take time to arm - [x] Add mine disarming - [x] Delayed explosion - [x] fix shrapnel runtime - [x] Actually MOVE the Mines file to code/items - [x] Write a bunch of new mine types - [x] Implement new mines in spawners - [x] YOU THOUGHT IT WAS OVER. Proximity Mines & full pressure mine code edit - [x] Embeds now work as intended - [ ] Sprites (need help) ## Why It's Good For The Game Pipe bomb.... Crew mortality grew two sizes that day ## Changelog :cl: add: Redesigns landmines as an item that can be picked up, disarmed, deployed. Some logic courtesy of /tg/. add: Adds a proximity explosive variant of landmines. fix: shrapnel embedding once again respects targeted limb and no longer runtimes on hitting a wall or destroying an object. fix: storage can no longer pick up anchored objects, causing them to get stuck inside balance: Nerfs the ability of heavy explosions to immediately breach to space soundadd: adds two mine detonation noises code: moves weapon manufacturer defines to a DEFINE file /:cl: --------- Signed-off-by: Sun-Soaked <45698967+Sun-Soaked@users.noreply.github.com> Co-authored-by: Sun-Soaked <45698967+MemedHams@users.noreply.github.com> --- .../RockRuins/rockplanet_boxsci.dmm | 2 +- .../RockRuins/rockplanet_budgetcuts.dmm | 2 +- .../SpaceRuins/cryocontainment.dmm | 4 +- _maps/RandomRuins/SpaceRuins/hellfactory.dmm | 4 +- .../RandomRuins/SpaceRuins/provinggrounds.dmm | 4 +- .../wasteplanet_abandoned_mechbay.dmm | 2 +- .../wasteplanet_fortress_of_solitide.dmm | 2 +- code/__DEFINES/dcs/signals.dm | 4 +- code/__DEFINES/guns.dm | 16 + code/__DEFINES/is_helpers.dm | 2 +- code/__DEFINES/wires.dm | 4 + code/controllers/subsystem/explosions.dm | 6 +- code/datums/components/gunpoint.dm | 2 +- code/datums/components/pellet_cloud.dm | 107 +-- code/datums/components/storage/storage.dm | 3 + code/datums/elements/embed.dm | 23 +- code/datums/mapgen/planetary/LavaGenerator.dm | 19 +- code/datums/mapgen/planetary/RockGenerator.dm | 34 +- code/datums/mapgen/planetary/SnowGenerator.dm | 50 +- .../datums/mapgen/planetary/WasteGenerator.dm | 31 +- .../mapgen/single_biome/WasteplanetCaves.dm | 4 +- code/datums/wires/mines.dm | 82 ++ code/game/objects/effects/mines.dm | 217 ------ code/game/objects/items.dm | 2 +- code/game/objects/items/devices/mines.dm | 708 ++++++++++++++++++ code/game/objects/items/shrapnel.dm | 73 +- code/game/turfs/open/floor.dm | 28 +- code/modules/admin/fun_balloon.dm | 4 +- .../blood_contract/blood_contract.dm | 4 +- code/modules/mining/abandoned_crates.dm | 4 +- .../mining/lavaland/necropolis_chests.dm | 4 +- code/modules/movespeed/modifiers/items.dm | 1 + code/modules/projectiles/gun.dm | 15 - code/modules/projectiles/projectile.dm | 8 +- .../projectiles/projectile/energy/misc.dm | 19 + icons/obj/landmine.dmi | Bin 0 -> 2821 bytes shiptest.dme | 4 +- sound/items/mine_activate.ogg | Bin 0 -> 63468 bytes sound/items/mine_activate_short.ogg | Bin 0 -> 8955 bytes 39 files changed, 1097 insertions(+), 401 deletions(-) create mode 100644 code/__DEFINES/guns.dm create mode 100644 code/datums/wires/mines.dm delete mode 100644 code/game/objects/effects/mines.dm create mode 100644 code/game/objects/items/devices/mines.dm create mode 100644 icons/obj/landmine.dmi create mode 100644 sound/items/mine_activate.ogg create mode 100644 sound/items/mine_activate_short.ogg diff --git a/_maps/RandomRuins/RockRuins/rockplanet_boxsci.dmm b/_maps/RandomRuins/RockRuins/rockplanet_boxsci.dmm index 7af7b29b6de2..1e3c1d7ce293 100644 --- a/_maps/RandomRuins/RockRuins/rockplanet_boxsci.dmm +++ b/_maps/RandomRuins/RockRuins/rockplanet_boxsci.dmm @@ -409,7 +409,7 @@ /turf/open/floor/plasteel, /area/ruin/unpowered) "Fk" = ( -/obj/effect/mine/shrapnel, +/obj/item/mine/pressure/explosive/shrapnel/live, /turf/open/floor/plating/asteroid/rockplanet/lit, /area/overmap_encounter/planetoid/rockplanet/explored) "FH" = ( diff --git a/_maps/RandomRuins/RockRuins/rockplanet_budgetcuts.dmm b/_maps/RandomRuins/RockRuins/rockplanet_budgetcuts.dmm index 8d066f6f04b4..c596392f89a4 100644 --- a/_maps/RandomRuins/RockRuins/rockplanet_budgetcuts.dmm +++ b/_maps/RandomRuins/RockRuins/rockplanet_budgetcuts.dmm @@ -511,7 +511,7 @@ /turf/open/floor/plasteel/tech, /area/ruin/rockplanet/nanotrasen) "ix" = ( -/obj/effect/mine/shrapnel/human_only, +/obj/item/mine/pressure/explosive/shrapnel/live, /turf/open/floor/plating/asteroid/rockplanet/lit, /area/overmap_encounter/planetoid/rockplanet/explored) "iE" = ( diff --git a/_maps/RandomRuins/SpaceRuins/cryocontainment.dmm b/_maps/RandomRuins/SpaceRuins/cryocontainment.dmm index 01606dfa8a35..f381d0375e46 100644 --- a/_maps/RandomRuins/SpaceRuins/cryocontainment.dmm +++ b/_maps/RandomRuins/SpaceRuins/cryocontainment.dmm @@ -326,7 +326,7 @@ /turf/open/floor/plating/airless, /area/ruin/unpowered) "iA" = ( -/obj/effect/mine/stun, +/obj/item/mine/proximity/explosive/sting/live, /obj/effect/decal/cleanable/dirt/dust, /turf/open/floor/plating/airless, /area/ruin/unpowered) @@ -803,7 +803,7 @@ /turf/open/floor/engine/airless, /area/ruin/unpowered) "ET" = ( -/obj/effect/mine/stun, +/obj/item/mine/proximity/explosive/sting/live, /turf/open/floor/plating/airless, /area/ruin/unpowered) "Fb" = ( diff --git a/_maps/RandomRuins/SpaceRuins/hellfactory.dmm b/_maps/RandomRuins/SpaceRuins/hellfactory.dmm index f425c41bccf3..700511e2e132 100644 --- a/_maps/RandomRuins/SpaceRuins/hellfactory.dmm +++ b/_maps/RandomRuins/SpaceRuins/hellfactory.dmm @@ -264,7 +264,7 @@ /turf/open/floor/plating, /area/ruin/space/has_grav/hellfactory) "aT" = ( -/obj/effect/mine/gas/water_vapor, +/obj/item/mine/pressure/gas/live, /obj/machinery/door/window, /turf/open/floor/plastic, /area/ruin/space/has_grav/hellfactory) @@ -272,7 +272,7 @@ /turf/open/floor/plastic, /area/ruin/space/has_grav/hellfactory) "aV" = ( -/obj/effect/mine/gas/water_vapor, +/obj/item/mine/pressure/gas/live, /turf/open/floor/plastic, /area/ruin/space/has_grav/hellfactory) "aW" = ( diff --git a/_maps/RandomRuins/SpaceRuins/provinggrounds.dmm b/_maps/RandomRuins/SpaceRuins/provinggrounds.dmm index 4e7fe7fd9c58..1b31a059567b 100644 --- a/_maps/RandomRuins/SpaceRuins/provinggrounds.dmm +++ b/_maps/RandomRuins/SpaceRuins/provinggrounds.dmm @@ -323,7 +323,7 @@ /turf/closed/wall/r_wall, /area/ruin/space/has_grav/syndicircle/winter) "iR" = ( -/obj/effect/mine/shrapnel, +/obj/item/mine/pressure/explosive/shrapnel/live, /obj/item/stack/tile/mineral/snow, /obj/machinery/light/dim/directional/west, /obj/effect/decal/cleanable/dirt/dust, @@ -648,7 +648,7 @@ /turf/open/floor/plating/airless, /area/ruin/space/has_grav/syndicircle/winter) "tf" = ( -/obj/effect/mine/shrapnel, +/obj/item/mine/pressure/explosive/shrapnel/live, /obj/item/stack/tile/mineral/snow, /obj/effect/decal/cleanable/dirt/dust, /turf/open/floor/plating/asteroid/snow/atmosphere, diff --git a/_maps/RandomRuins/WasteRuins/wasteplanet_abandoned_mechbay.dmm b/_maps/RandomRuins/WasteRuins/wasteplanet_abandoned_mechbay.dmm index 554816ddc75d..570af22f6ced 100644 --- a/_maps/RandomRuins/WasteRuins/wasteplanet_abandoned_mechbay.dmm +++ b/_maps/RandomRuins/WasteRuins/wasteplanet_abandoned_mechbay.dmm @@ -3425,7 +3425,7 @@ /turf/open/floor/plasteel/tech/techmaint, /area/ruin/wasteplanet/abandoned_mechbay/bay1) "Og" = ( -/obj/effect/mine/shrapnel/human_only, +/obj/item/mine/pressure/explosive/shrapnel/live, /turf/open/floor/plating/asteroid/wasteplanet, /area/overmap_encounter/planetoid/cave/explored) "Oj" = ( diff --git a/_maps/RandomRuins/WasteRuins/wasteplanet_fortress_of_solitide.dmm b/_maps/RandomRuins/WasteRuins/wasteplanet_fortress_of_solitide.dmm index e931e0091d26..7756fdfa1fd6 100644 --- a/_maps/RandomRuins/WasteRuins/wasteplanet_fortress_of_solitide.dmm +++ b/_maps/RandomRuins/WasteRuins/wasteplanet_fortress_of_solitide.dmm @@ -4083,7 +4083,7 @@ /turf/open/floor/plating/rust, /area/ruin/powered) "LY" = ( -/obj/effect/mine/sound/bwoink, +/obj/item/mine/pressure/sound/live, /obj/structure/grille, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{ dir = 1 diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 2b8dc67cb684..c0aabd909f59 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -537,7 +537,7 @@ #define COMSIG_TOOL_IN_USE "tool_in_use" ///from base of [/obj/item/proc/tool_check_callback]: (mob/living/user) #define COMSIG_TOOL_START_USE "tool_start_use" ///from base of [/obj/item/proc/tool_start_check]: (mob/living/user) #define COMSIG_ITEM_DISABLE_EMBED "item_disable_embed" ///from [/obj/item/proc/disableEmbedding]: -#define COMSIG_MINE_TRIGGERED "minegoboom" ///from [/obj/effect/mine/proc/triggermine]: +#define COMSIG_MINE_TRIGGERED "minegoboom" ///from [/obj/item/mine/proc/trigger_mine]: ///from [/obj/structure/closet/supplypod/proc/endlaunch]: #define COMSIG_SUPPLYPOD_LANDED "supplypodgoboom" @@ -610,7 +610,7 @@ #define COMSIG_PROJECTILE_PREHIT "com_proj_prehit" // sent to targets during the process_hit proc of projectiles #define COMSIG_PROJECTILE_RANGE_OUT "projectile_range_out" // sent to targets during the process_hit proc of projectiles #define COMSIG_EMBED_TRY_FORCE "item_try_embed" // sent when trying to force an embed (mainly for projectiles, only used in the embed element) - + #define COMPONENT_EMBED_SUCCESS (1<<1) #define COMSIG_PELLET_CLOUD_INIT "pellet_cloud_init" // sent to targets during the process_hit proc of projectiles // /obj/mecha signals diff --git a/code/__DEFINES/guns.dm b/code/__DEFINES/guns.dm new file mode 100644 index 000000000000..0256ed11bedd --- /dev/null +++ b/code/__DEFINES/guns.dm @@ -0,0 +1,16 @@ +//weapon manufacturers +#define MANUFACTURER_NONE null +#define MANUFACTURER_SHARPLITE "the Sharplite Defense logo" +#define MANUFACTURER_SHARPLITE_NEW "the Nanotrasen-Sharplite logo" +#define MANUFACTURER_HUNTERSPRIDE "the Hunter's Pride Arms and Ammunition logo" +#define MANUFACTURER_SOLARARMORIES "the Solarbundswaffenkammer emblem" +#define MANUFACTURER_SCARBOROUGH "the Scarborough Arms logo" +#define MANUFACTURER_EOEHOMA "the Eoehoma Firearms emblem" +#define MANUFACTURER_NANOTRASEN_OLD "an outdated Nanotrasen logo" +#define MANUFACTURER_NANOTRASEN "the Nanotrasen logo" +#define MANUFACTURER_BRAZIL "a green flag with a blue circle and a yellow diamond around it" +#define MANUFACTURER_INTEQ "an orange crest with the letters 'IRMG'" +#define MANUFACTURER_MINUTEMAN "the Lanchester City Firearms Plant logo" +#define MANUFACTURER_DONKCO "the Donk! Co. logo" +#define MANUFACTURER_PGF "the Etherbor Industries emblem" +#define MANUFACTURER_IMPORT "Lanchester Import Co." diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index c0a4d30aba8b..80c400e5864c 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -167,7 +167,7 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list( #define isgrenade(A) (istype(A, /obj/item/grenade)) -#define islandmine(A) (istype(A, /obj/effect/mine)) +#define islandmine(A) (istype(A, /obj/item/mine)) #define issupplypod(A) (istype(A, /obj/structure/closet/supplypod)) diff --git a/code/__DEFINES/wires.dm b/code/__DEFINES/wires.dm index 5623b5f52b4a..5c35c1f6b5a9 100644 --- a/code/__DEFINES/wires.dm +++ b/code/__DEFINES/wires.dm @@ -51,4 +51,8 @@ #define WIRE_PRIZEVEND "Emergency Prize Vend" #define WIRE_RESETOWNER "Reset Owner" #define WIRE_AGELIMIT "Age Limit" +#define WIRE_PIN "Trigger Pin" +#define WIRE_FUSE "Fuse" +#define WIRE_RESET "Factory Reset" +#define WIRE_DELAYBOOM "Delayed Boom" diff --git a/code/controllers/subsystem/explosions.dm b/code/controllers/subsystem/explosions.dm index f163553f5f9b..3e044a441c0a 100644 --- a/code/controllers/subsystem/explosions.dm +++ b/code/controllers/subsystem/explosions.dm @@ -164,7 +164,7 @@ SUBSYSTEM_DEF(explosions) // 5 explosion power is a (0, 1, 3) explosion. // 1 explosion power is a (0, 0, 1) explosion. -/proc/explosion(atom/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog = TRUE, ignorecap = FALSE, flame_range = 0, silent = FALSE, smoke = FALSE) +/proc/explosion(atom/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog = TRUE, ignorecap = FALSE, flame_range = 0, silent = FALSE, smoke = FALSE, gentle = FALSE) . = SSexplosions.explode(arglist(args)) #define CREAK_DELAY 5 SECONDS //Time taken for the creak to play after explosion, if applicable. @@ -177,7 +177,7 @@ SUBSYSTEM_DEF(explosions) #define FREQ_UPPER 40 //The upper limit for the randomly selected frequency. #define FREQ_LOWER 25 //The lower of the above. -/datum/controller/subsystem/explosions/proc/explode(atom/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog, ignorecap, flame_range, silent, smoke) +/datum/controller/subsystem/explosions/proc/explode(atom/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog, ignorecap, flame_range, silent, smoke, gentle) epicenter = get_turf(epicenter) if(!epicenter) return @@ -550,6 +550,8 @@ SUBSYSTEM_DEF(explosions) var/throw_dir = L[2] var/max_range = L[3] for(var/atom/movable/A in T) + if(QDELETED(A)) + continue if(!A.anchored && A.move_resist != INFINITY) var/atom_throw_range = rand(throw_range, max_range) var/turf/throw_at = get_ranged_target_turf(A, throw_dir, atom_throw_range) diff --git a/code/datums/components/gunpoint.dm b/code/datums/components/gunpoint.dm index 2865865c98ab..9167bbe224b4 100644 --- a/code/datums/components/gunpoint.dm +++ b/code/datums/components/gunpoint.dm @@ -40,7 +40,7 @@ if(istype(weapon, /obj/item/gun/ballistic/rocketlauncher) && weapon.chambered) shooter.client.give_award(/datum/award/achievement/misc/rocket_holdup, shooter) - target.do_alert_animation(target) + target.do_alert_animation() target.playsound_local(target.loc, 'sound/machines/chime.ogg', 50, TRUE) SEND_SIGNAL(target, COMSIG_ADD_MOOD_EVENT, "gunpoint", /datum/mood_event/gunpoint) diff --git a/code/datums/components/pellet_cloud.dm b/code/datums/components/pellet_cloud.dm index e7f5174c9102..19b1e2094993 100644 --- a/code/datums/components/pellet_cloud.dm +++ b/code/datums/components/pellet_cloud.dm @@ -1,20 +1,19 @@ -/* - * This component is used when you want to create a bunch of shrapnel or projectiles (say, shrapnel from a fragmentation grenade, or buckshot from a shotgun) from a central point, - * without necessarily printing a separate message for every single impact. This component should be instantiated right when you need it (like the moment of firing), then activated - * by signal. - * - * Pellet cloud currently works on two classes of sources: directed (ammo casings), and circular (grenades, landmines). - * -Directed: This means you're shooting multiple pellets, like buckshot. If an ammo casing is defined as having multiple pellets, it will automatically create a pellet cloud - * and call COMSIG_PELLET_CLOUD_INIT (see [/obj/item/ammo_casing/proc/fire_casing]). Thus, the only projectiles fired will be the ones fired here. - * The magnitude var controls how many pellets are created. - * -Circular: This results in a big spray of shrapnel flying all around the detonation point when the grenade fires COMSIG_GRENADE_PRIME or landmine triggers COMSIG_MINE_TRIGGERED. - * The magnitude var controls how big the detonation radius is (the bigger the magnitude, the more shrapnel is created). Grenades can be covered with bodies to reduce shrapnel output. - * - * Once all of the fired projectiles either hit a target or disappear due to ranging out/whatever else, we resolve the list of all the things we hit and print aggregate messages so we get - * one "You're hit by 6 buckshot pellets" vs 6x "You're hit by the buckshot blah blah" messages. - * - * Note that this is how all guns handle shooting ammo casings with multiple pellets, in case such a thing comes up. -*/ + + //This component is used when you want to create a bunch of shrapnel or projectiles (say, shrapnel from a fragmentation grenade, or buckshot from a shotgun) from a central point, + //without necessarily printing a separate message for every single impact. This component should be instantiated right when you need it (like the moment of firing), then activated + //by signal. + + //Pellet cloud currently works on two classes of sources: directed (ammo casings), and circular (grenades, landmines). + //Directed: This means you're shooting multiple pellets, like buckshot. If an ammo casing is defined as having multiple pellets, it will automatically create a pellet cloud + //and call COMSIG_PELLET_CLOUD_INIT (see [/obj/item/ammo_casing/proc/fire_casing]). Thus, the only projectiles fired will be the ones fired here. + //The magnitude var controls how many pellets are created. + //Circular: This results in a big spray of shrapnel flying all around the detonation point when the grenade fires COMSIG_GRENADE_PRIME or landmine triggers COMSIG_MINE_TRIGGERED. + //The magnitude var controls how big the detonation radius is (the bigger the magnitude, the more shrapnel is created). Grenades can be covered with bodies to reduce shrapnel output. + + //Once all of the fired projectiles either hit a target or disappear due to ranging out/whatever else, we resolve the list of all the things we hit and print aggregate messages so we get + //one "You're hit by 6 buckshot pellets" vs 6x "You're hit by the buckshot blah blah" messages. + + //Note that this is how all guns handle shooting ammo casings with multiple pellets, in case such a thing comes up. /datum/component/pellet_cloud /// What's the projectile path of the shrapnel we're shooting? @@ -83,12 +82,13 @@ /datum/component/pellet_cloud/UnregisterFromParent() UnregisterSignal(parent, list(COMSIG_PARENT_PREQDELETED, COMSIG_PELLET_CLOUD_INIT, COMSIG_GRENADE_PRIME, COMSIG_GRENADE_ARMED, COMSIG_MOVABLE_MOVED, COMSIG_MINE_TRIGGERED, COMSIG_ITEM_DROPPED)) -/** - * create_casing_pellets() is for directed pellet clouds for ammo casings that have multiple pellets (buckshot and scatter lasers for instance) - * - * Honestly this is mostly just a rehash of [/obj/item/ammo_casing/proc/fire_casing()] for pellet counts > 1, except this lets us tamper with the pellets and hook onto them for tracking purposes. - * The arguments really don't matter, this proc is triggered by COMSIG_PELLET_CLOUD_INIT which is only for this really, it's just a big mess of the state vars we need for doing the stuff over here. - */ + +//create_casing_pellets() is for directed pellet clouds for ammo casings that have multiple pellets (buckshot and scatter lasers for instance) +// +//Honestly this is mostly just a rehash of [/obj/item/ammo_casing/proc/fire_casing()] for pellet counts > 1, except this lets us tamper with the pellets and hook onto them for tracking purposes. +//The arguments really don't matter, this proc is triggered by COMSIG_PELLET_CLOUD_INIT which is only for this really, it's just a big mess of the state vars we need for doing the stuff over here. + + /datum/component/pellet_cloud/proc/create_casing_pellets(obj/item/ammo_casing/shell, atom/target, mob/living/user, fired_from, randomspread, spread, zone_override, params, distro) shooter = user var/targloc = get_turf(target) @@ -111,16 +111,27 @@ if(i != num_pellets) shell.newshot() -/** - * create_blast_pellets() is for when we have a central point we want to shred the surroundings of with a ring of shrapnel, namely frag grenades and landmines. - * - * Note that grenades have extra handling for someone throwing themselves/being thrown on top of it, while landmines do not (obviously, it's a landmine!). See [/datum/component/pellet_cloud/proc/handle_martyrs()] - */ -/datum/component/pellet_cloud/proc/create_blast_pellets(obj/O, mob/living/lanced_by) +//create_blast_pellets() is for when we have a central point we want to shred the surroundings of with a ring of shrapnel, namely frag grenades and landmines. + +//Note that grenades have extra handling for someone throwing themselves/being thrown on top of it, see [/datum/component/pellet_cloud/proc/handle_martyrs] +//Landmines just have a small check for [/obj/item/mine/pressure/explosive/shrapnel/var/shred_triggerer], and spawn extra shrapnel for them if so + +//Arguments: +////O- Our parent, the thing making the shrapnel obviously (grenade or landmine) +////punishable_triggerer- For grenade lances or people who step on the landmines (if we shred the triggerer), we spawn extra shrapnel for them in addition to the normal spread +// +/datum/component/pellet_cloud/proc/create_blast_pellets(obj/O, mob/living/punishable_triggerer) var/atom/A = parent if(isgrenade(parent)) // handle_martyrs can reduce the radius and thus the number of pellets we produce if someone dives on top of a frag grenade - handle_martyrs(lanced_by) // note that we can modify radius in this proc + handle_martyrs(punishable_triggerer) // note that we can modify radius in this proc + else if(istype(parent, /obj/item/mine/pressure/explosive)) + var/obj/item/mine/pressure/explosive/triggered_mine = parent + if(triggered_mine.shred_triggerer && istype(punishable_triggerer)) // free shrapnel for the idiot who stepped on it if we're a mine that shreds the triggerer + pellet_delta += radius // so they don't count against the later total + if(punishable_triggerer.loc == triggered_mine.loc)//only trigger this if they're actually on the tile + for(var/i in 1 to radius) + pew(punishable_triggerer, TRUE) if(radius < 1) return @@ -132,27 +143,27 @@ var/turf/shootat_turf = T pew(shootat_turf) -/** - * handle_martyrs() is used for grenades that shoot shrapnel to check if anyone threw themselves/were thrown on top of the grenade, thus absorbing a good chunk of the shrapnel - * - * Between the time the grenade is armed and the actual detonation, we set var/list/bodies to the list of mobs currently on the new tile, as if the grenade landed on top of them, tracking if any of them move off the tile and removing them from the "under" list - * Once the grenade detonates, handle_martyrs() is called and gets all the new mobs on the tile, and add the ones not in var/list/bodies to var/list/martyrs - * We then iterate through the martyrs and reduce the shrapnel magnitude for each mob on top of it, shredding each of them with some of the shrapnel they helped absorb. This can snuff out all of the shrapnel if there's enough bodies - * - * Note we track anyone who's alive and client'd when they get shredded in var/list/purple_hearts, for achievement checking later - */ -/datum/component/pellet_cloud/proc/handle_martyrs(mob/living/lanced_by) + +// handle_martyrs() is used for grenades that shoot shrapnel to check if anyone threw themselves/were thrown on top of the grenade, thus absorbing a good chunk of the shrapnel +// +// Between the time the grenade is armed and the actual detonation, we set var/list/bodies to the list of mobs currently on the new tile, as if the grenade landed on top of them, tracking if any of them move off the tile and removing them from the "under" list +// Once the grenade detonates, handle_martyrs() is called and gets all the new mobs on the tile, and add the ones not in var/list/bodies to var/list/martyrs +// We then iterate through the martyrs and reduce the shrapnel magnitude for each mob on top of it, shredding each of them with some of the shrapnel they helped absorb. This can snuff out all of the shrapnel if there's enough bodies + +// Note we track anyone who's alive and client'd when they get shredded in var/list/purple_hearts, for achievement checking later + +/datum/component/pellet_cloud/proc/handle_martyrs(mob/living/punishable_triggerer) var/magnitude_absorbed var/list/martyrs = list() var/self_harm_radius_mult = 3 - if(lanced_by && prob(60)) - to_chat(lanced_by, "Your plan to whack someone with a grenade on a stick backfires on you, literally!") + if(punishable_triggerer && prob(60)) + to_chat(punishable_triggerer, "Your plan to whack someone with a grenade on a stick backfires on you, literally!") self_harm_radius_mult = 1 // we'll still give the guy who got hit some extra shredding, but not 3*radius pellet_delta += radius for(var/i in 1 to radius) - pew(lanced_by) // thought you could be tricky and lance someone with no ill effects!! + pew(punishable_triggerer) // thought you could be tricky and lance someone with no ill effects!! for(var/mob/living/body in get_turf(parent)) if(body == shooter) @@ -209,11 +220,11 @@ finalize() /// Minor convenience function for creating each shrapnel piece with circle explosions, mostly stolen from the MIRV component -/datum/component/pellet_cloud/proc/pew(atom/target, spread=0) +/datum/component/pellet_cloud/proc/pew(atom/target, landmine_victim) var/obj/projectile/P = new projectile_type(get_turf(parent)) //Shooting Code: - P.spread = spread + P.spread = 0 P.original = target P.fired_from = parent P.firer = parent // don't hit ourself that would be really annoying @@ -224,6 +235,8 @@ RegisterSignal(P, list(COMSIG_PROJECTILE_RANGE_OUT, COMSIG_PARENT_QDELETING), PROC_REF(pellet_range)) pellets += P P.fire() + if(landmine_victim) + P.process_hit(get_turf(target), target) ///All of our pellets are accounted for, time to go target by target and tell them how many things they got hit by. /datum/component/pellet_cloud/proc/finalize() @@ -286,7 +299,9 @@ /// Someone who was originally "under" the grenade has moved off the tile and is now eligible for being a martyr and "covering" it /datum/component/pellet_cloud/proc/on_target_qdel(atom/target) + SIGNAL_HANDLER + UnregisterSignal(target, COMSIG_PARENT_QDELETING) targets_hit -= target LAZYREMOVE(bodies, target) - purple_hearts -= target + LAZYREMOVE(purple_hearts, target) diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm index ced0b0e79ff7..bb79bbd282fa 100644 --- a/code/datums/components/storage/storage.dm +++ b/code/datums/components/storage/storage.dm @@ -227,6 +227,9 @@ if(!len) to_chat(M, "You failed to pick up anything with [parent]!") return + if(I.anchored) + to_chat(M, "\The [I] is stuck to the ground and cannot be picked up by [parent]!") + return var/datum/progressbar/progress = new(M, len, I.loc) var/list/rejections = list() while(do_after(M, 10, TRUE, parent, FALSE, CALLBACK(src, PROC_REF(handle_mass_pickup), things, I.loc, rejections, progress))) diff --git a/code/datums/elements/embed.dm b/code/datums/elements/embed.dm index 9b427b6b80c5..11072c771bab 100644 --- a/code/datums/elements/embed.dm +++ b/code/datums/elements/embed.dm @@ -176,23 +176,20 @@ * If we hit a valid target (carbon or closed turf), we create the shrapnel_type object and immediately call tryEmbed() on it, targeting what we impacted. That will lead * it to call tryForceEmbed() on its own embed element (it's out of our hands here, our projectile is done), where it will run through all the checks it needs to. */ -/datum/element/embed/proc/checkEmbedProjectile(obj/projectile/P, atom/movable/firer, atom/hit) +/datum/element/embed/proc/checkEmbedProjectile(obj/projectile/P, atom/movable/firer, atom/hit, angle, hit_zone) SIGNAL_HANDLER - if(!iscarbon(hit) && !isclosedturf(hit)) + if(!iscarbon(hit)) Detach(P) return // we don't care var/obj/item/payload = new payload_type(get_turf(hit)) - var/did_embed - if(iscarbon(hit)) - var/mob/living/carbon/C = hit - var/obj/item/bodypart/limb = C.get_bodypart(C.check_limb_hit(P.def_zone)) - did_embed = payload.tryEmbed(limb) - else - did_embed = payload.tryEmbed(hit) + var/mob/living/carbon/C = hit + var/obj/item/bodypart/limb = C.get_bodypart(hit_zone) + if(!limb) + limb = C.get_bodypart() - if(!did_embed) + if(!payload.tryEmbed(limb)) payload.failedEmbed() Detach(P) @@ -213,7 +210,6 @@ var/obj/item/bodypart/limb var/mob/living/carbon/C - var/turf/closed/T if(!forced && !prob(embed_chance)) return @@ -225,11 +221,8 @@ hit_zone = limb.body_zone else if(isbodypart(target)) limb = target + hit_zone = limb.body_zone C = limb.owner - else if(isclosedturf(target)) - T = target if(C) return checkEmbedMob(I, C, hit_zone, forced=TRUE) - else if(T) - return checkEmbedOther(I, T, forced=TRUE) diff --git a/code/datums/mapgen/planetary/LavaGenerator.dm b/code/datums/mapgen/planetary/LavaGenerator.dm index c244f3ef2560..ef66cca1103f 100644 --- a/code/datums/mapgen/planetary/LavaGenerator.dm +++ b/code/datums/mapgen/planetary/LavaGenerator.dm @@ -84,7 +84,7 @@ /datum/biome/lavaland open_turf_types = list( - /turf/open/floor/plating/asteroid/basalt/lava_land_surface/lit = 1 + /turf/open/floor/plating/asteroid/basalt/lava_land_surface/lit = 1, ) flora_spawn_chance = 1 flora_spawn_list = list( @@ -93,17 +93,22 @@ /obj/structure/flora/ash/fern = 5, /obj/structure/flora/ash/fireblossom = 1, /obj/structure/flora/ash/puce = 5, + /obj/item/mine/pressure/explosive/rusty/live = 1, ) feature_spawn_chance = 0.3 feature_spawn_list = list( + /obj/structure/flora/rock/hell = 20, + /obj/structure/elite_tumor = 4, + /obj/structure/geyser/random = 4, + /obj/effect/spawner/lootdrop/anomaly/lava = 2, /obj/structure/flora/rock/hell = 14, /obj/structure/vein = 5, /obj/structure/vein/classtwo = 2, /obj/structure/elite_tumor = 2, /obj/structure/geyser/random = 2, /obj/structure/vein/classthree = 1, + /obj/effect/spawner/minefield = 1, /obj/effect/spawner/lootdrop/anomaly/lava = 1, - ) mob_spawn_chance = 4 mob_spawn_list = list( @@ -250,14 +255,17 @@ /obj/structure/flora/ash/cacti = 1, /obj/structure/flora/ash/tall_shroom = 2, /obj/structure/flora/ash/fern = 2, - /obj/structure/flora/ash/puce = 2 + /obj/structure/flora/ash/puce = 2, + /obj/item/mine/proximity/explosive/live = 1, + /obj/item/mine/pressure/explosive/rusty/live = 1 ) /datum/biome/cave/lavaland/rocky open_turf_types = list(/turf/open/floor/plating/asteroid/purple = 1) flora_spawn_list = list( - /obj/structure/flora/rock/pile/lava = 1, - /obj/structure/flora/rock/lava = 1 + /obj/structure/flora/rock/pile/lava = 3, + /obj/structure/flora/rock/lava = 3, + /obj/item/mine/pressure/explosive/rusty/live = 1 ) flora_spawn_chance = 5 @@ -271,6 +279,7 @@ /obj/structure/flora/ash/cap_shroom = 2, /obj/structure/flora/ash/stem_shroom = 2, /obj/structure/flora/ash/cacti = 1, + /obj/item/mine/pressure/explosive/rusty/live = 1, /obj/structure/flora/ash/tall_shroom = 2 ) diff --git a/code/datums/mapgen/planetary/RockGenerator.dm b/code/datums/mapgen/planetary/RockGenerator.dm index 95e1273bb9d7..c675c87714f5 100644 --- a/code/datums/mapgen/planetary/RockGenerator.dm +++ b/code/datums/mapgen/planetary/RockGenerator.dm @@ -91,6 +91,7 @@ /obj/structure/vein/classtwo = 40, /obj/effect/spawner/lootdrop/anomaly/rock = 10, /obj/structure/vein/classthree = 10, + /obj/effect/spawner/minefield = 2, /obj/effect/spawner/lootdrop/anomaly/big = 1 //get out of here stalker ) @@ -98,10 +99,11 @@ mob_spawn_chance = 3 flora_spawn_list = list( - /obj/structure/flora/rock/rockplanet = 3, - /obj/structure/flora/tree/cactus = 4, - /obj/structure/flora/ash/cacti = 1, - /obj/structure/flora/ash/garden/arid = 1, + /obj/structure/flora/rock/rockplanet = 6, + /obj/structure/flora/tree/cactus = 8, + /obj/structure/flora/ash/cacti = 2, + /obj/structure/flora/ash/garden/arid = 2, + /obj/item/mine/pressure/explosive/rusty/live = 1 ) mob_spawn_list = list( @@ -136,6 +138,7 @@ /obj/structure/flora/ash/cacti = 2, /obj/structure/flora/grass/rockplanet/dead = 8, /obj/structure/flora/ash/garden/arid = 1, + /obj/item/mine/pressure/explosive/rusty/live = 1 ) /datum/biome/cave/rock @@ -143,10 +146,12 @@ open_turf_types = list(/turf/open/floor/plating/asteroid/rockplanet/cracked = 1) flora_spawn_chance = 4 flora_spawn_list = list( - /obj/structure/flora/rock/rockplanet = 4, - /obj/structure/flora/rock/pile/rockplanet = 4, - /obj/structure/flora/ash/fern = 2, - /obj/structure/flora/ash/puce = 1, + /obj/structure/flora/rock/rockplanet = 8, + /obj/structure/flora/rock/pile/rockplanet = 8, + /obj/structure/flora/ash/fern = 4, + /obj/structure/flora/ash/puce = 2, + /obj/item/mine/pressure/explosive/rusty/live = 1, + /obj/item/mine/proximity/explosive/live = 1, ) feature_spawn_chance = 0.5 feature_spawn_list = list( @@ -155,6 +160,7 @@ /obj/structure/vein/classtwo = 2, /obj/structure/elite_tumor = 1, /obj/structure/vein/classthree = 1, + /obj/effect/spawner/minefield = 1, /obj/structure/spawner/ice_moon/rockplanet = 4, /obj/effect/spawner/lootdrop/anomaly/rock/cave = 1, ) @@ -172,11 +178,13 @@ open_turf_types = list(/turf/open/floor/plating/asteroid/rockplanet/cracked = 1) flora_spawn_chance = 5 flora_spawn_list = list( - /obj/structure/flora/rock/rockplanet = 4, - /obj/structure/flora/rock/pile/rockplanet = 4, - /obj/structure/flora/ash/fern = 4, - /obj/structure/flora/ash/puce = 2, - /obj/structure/flora/ash/garden/arid = 1, + /obj/structure/flora/rock/rockplanet = 8, + /obj/structure/flora/rock/pile/rockplanet = 8, + /obj/structure/flora/ash/fern = 6, + /obj/structure/flora/ash/puce = 4, + /obj/structure/flora/ash/garden/arid = 2, + /obj/item/mine/proximity/explosive/live = 1, + /obj/item/mine/pressure/explosive/rusty/live = 1 ) mob_spawn_list = list( /mob/living/simple_animal/hostile/netherworld/asteroid = 30, diff --git a/code/datums/mapgen/planetary/SnowGenerator.dm b/code/datums/mapgen/planetary/SnowGenerator.dm index a066647a0e4d..8489cbb970ba 100644 --- a/code/datums/mapgen/planetary/SnowGenerator.dm +++ b/code/datums/mapgen/planetary/SnowGenerator.dm @@ -90,12 +90,13 @@ /turf/open/floor/plating/asteroid/snow/lit = 25 ) flora_spawn_list = list( - /obj/structure/flora/tree/pine = 2, - /obj/structure/flora/rock/icy = 2, - /obj/structure/flora/rock/pile/icy = 2, - /obj/structure/flora/grass/both = 6, - /obj/structure/flora/ash/chilly = 2, - /obj/structure/flora/ash/garden/frigid = 1, + /obj/structure/flora/tree/pine = 4, + /obj/structure/flora/rock/icy = 4, + /obj/structure/flora/rock/pile/icy = 4, + /obj/structure/flora/grass/both = 12, + /obj/structure/flora/ash/chilly = 4, + /obj/structure/flora/ash/garden/frigid = 2, + /obj/item/mine/pressure/explosive/rusty/live = 1 ) flora_spawn_chance = 10 mob_spawn_chance = 1 @@ -118,6 +119,7 @@ /obj/structure/spawner/ice_moon/demonic_portal/medium_threat = 50, /obj/structure/spawner/ice_moon/demonic_portal/high_threat = 13, /obj/structure/vein/ice = 25, + /obj/effect/spawner/minefield = 2, /obj/structure/vein/ice/classtwo = 50, /obj/structure/vein/ice/classthree = 10, ) @@ -148,9 +150,10 @@ /datum/biome/snow/forest flora_spawn_chance = 15 flora_spawn_list = list( - /obj/structure/flora/tree/pine = 10, - /obj/structure/flora/tree/dead = 3, - /obj/structure/flora/grass/both = 4 + /obj/structure/flora/tree/pine = 20, + /obj/structure/flora/tree/dead = 6, + /obj/structure/flora/grass/both = 8, + /obj/item/mine/pressure/explosive/rusty/live = 1, ) /datum/biome/snow/forest/dense @@ -159,6 +162,7 @@ /obj/structure/flora/tree/pine = 20, /obj/structure/flora/grass/both = 6, /obj/structure/flora/tree/dead = 3, + /obj/item/mine/pressure/explosive/rusty/live = 1, ) /datum/biome/arctic @@ -242,15 +246,17 @@ ) flora_spawn_chance = 6 flora_spawn_list = list( - /obj/structure/flora/grass/both = 5, - /obj/structure/flora/rock/pile/icy = 1, - /obj/structure/flora/rock/icy = 1, - /obj/structure/flora/ash/space = 1, - /obj/structure/flora/ash/leaf_shroom = 1, - /obj/structure/flora/ash/cap_shroom = 1, - /obj/structure/flora/ash/stem_shroom = 1, - /obj/structure/flora/ash/puce = 1, - /obj/structure/flora/ash/garden/frigid = 1, + /obj/structure/flora/grass/both = 10, + /obj/structure/flora/rock/pile/icy = 2, + /obj/structure/flora/rock/icy = 2, + /obj/structure/flora/ash/space = 2, + /obj/structure/flora/ash/leaf_shroom = 2, + /obj/structure/flora/ash/cap_shroom = 2, + /obj/structure/flora/ash/stem_shroom = 2, + /obj/structure/flora/ash/puce = 2, + /obj/structure/flora/ash/garden/frigid = 2, + /obj/item/mine/proximity/explosive/live = 1, + /obj/item/mine/pressure/explosive/rusty/live = 1 ) closed_turf_types = list( /turf/closed/mineral/random/snow = 1 @@ -279,6 +285,7 @@ /obj/structure/vein/ice = 30, /obj/structure/vein/ice/classtwo = 50, /obj/structure/vein/ice/classthree = 6, + /obj/effect/spawner/minefield = 2, ) /datum/biome/cave/snow/thawed @@ -317,9 +324,10 @@ ) flora_spawn_chance = 3 flora_spawn_list = list( - /obj/structure/flora/ash/leaf_shroom = 1, - /obj/structure/flora/ash/cap_shroom = 1, - /obj/structure/flora/ash/stem_shroom = 1, + /obj/structure/flora/ash/leaf_shroom = 3, + /obj/structure/flora/ash/cap_shroom = 3, + /obj/structure/flora/ash/stem_shroom = 3, + /obj/item/mine/pressure/explosive/fire/live = 1, ) feature_spawn_chance = 0.2 diff --git a/code/datums/mapgen/planetary/WasteGenerator.dm b/code/datums/mapgen/planetary/WasteGenerator.dm index d0243740bc3b..c6e1244be129 100644 --- a/code/datums/mapgen/planetary/WasteGenerator.dm +++ b/code/datums/mapgen/planetary/WasteGenerator.dm @@ -125,7 +125,9 @@ //the illusive shrapnel plant - /obj/effect/mine/shrapnel/human_only = 10 + /obj/item/mine/pressure/explosive/shrapnel/live = 30, + /obj/effect/spawner/lootdrop/mine = 8, + /obj/effect/spawner/minefield = 2 ) feature_spawn_list = list( @@ -202,7 +204,9 @@ /obj/effect/spawner/lootdrop/maintenance/four = 20, /obj/structure/flora/ash/garden/waste = 300, /obj/structure/flora/ash/glowshroom = 1800, - /obj/effect/mine/shrapnel/human_only = 10 + /obj/item/mine/pressure/explosive/shrapnel/live = 30, + /obj/effect/spawner/lootdrop/mine = 8, + /obj/effect/spawner/minefield = 2 ) /datum/biome/waste/tar_bed //tar colorings @@ -246,7 +250,10 @@ /obj/structure/closet/crate/secure/loot = 30, /obj/effect/spawner/lootdrop/waste/atmos_can = 180, /obj/effect/spawner/lootdrop/waste/atmos_can/rare = 1, - /obj/effect/spawner/lootdrop/waste/salvageable = 300 + /obj/effect/spawner/lootdrop/waste/salvageable = 300, + /obj/item/mine/pressure/explosive/rad/live = 30, + /obj/effect/spawner/lootdrop/mine = 8, + /obj/effect/spawner/minefield = 2 ) mob_spawn_list = list( //nor organics, more biased towards hivebots though /mob/living/simple_animal/hostile/hivebot/wasteplanet/strong = 80, @@ -308,7 +315,9 @@ /obj/effect/spawner/lootdrop/waste/salvageable = 400, /obj/structure/flora/ash/garden/waste = 70, /obj/structure/flora/ash/glowshroom = 400, //more common in caves - /obj/effect/mine/shrapnel/human_only = 10 + /obj/item/mine/pressure/explosive/rad/live = 10, + /obj/effect/spawner/lootdrop/mine = 8, + /obj/effect/spawner/minefield = 2 ) feature_spawn_list = list( @@ -362,7 +371,10 @@ /obj/effect/spawner/lootdrop/maintenance/two = 50, /obj/effect/spawner/lootdrop/maintenance/three = 100, /obj/effect/spawner/lootdrop/maintenance/four = 200, - /obj/structure/flora/ash/glowshroom = 1800 + /obj/structure/flora/ash/glowshroom = 1800, + /obj/item/mine/pressure/explosive/rad/live = 30, + /obj/effect/spawner/lootdrop/mine = 8, + /obj/effect/spawner/minefield = 2 ) feature_spawn_chance = 12 @@ -397,6 +409,9 @@ /obj/effect/spawner/lootdrop/maintenance/three = 20, /obj/effect/spawner/lootdrop/maintenance/four = 40, /obj/effect/spawner/lootdrop/waste/salvageable = 80, + /obj/item/mine/proximity/spawner/manhack/live = 40, + /obj/effect/spawner/lootdrop/mine = 8, + /obj/effect/spawner/minefield/manhack = 2 ) mob_spawn_list = list( //nor organics, more biased towards hivebots though /mob/living/simple_animal/hostile/hivebot/wasteplanet/strong = 80, @@ -427,7 +442,8 @@ /obj/effect/spawner/lootdrop/maintenance/three = 10, /obj/effect/spawner/lootdrop/maintenance/four = 20, /obj/effect/spawner/lootdrop/waste/salvageable = 40, - /obj/structure/foamedmetal = 100 + /obj/structure/foamedmetal = 100, + /obj/item/mine/proximity/spawner/manhack/live = 20 ) mob_spawn_list = list( //Whoops! All hivebots! /mob/living/simple_animal/hostile/hivebot/wasteplanet/strong = 80, @@ -440,6 +456,7 @@ /obj/structure/spawner/wasteplanet/hivebot/low_threat = 20, /obj/structure/spawner/wasteplanet/hivebot/medium_threat = 10, /obj/structure/spawner/wasteplanet/hivebot/high_threat = 5, - /obj/structure/spawner/wasteplanet/hivebot/extreme_threat = 2 + /obj/structure/spawner/wasteplanet/hivebot/extreme_threat = 2, + /obj/effect/spawner/minefield/manhack = 2 ) feature_spawn_chance = 2 //hivebot biomes should have their dongles diff --git a/code/datums/mapgen/single_biome/WasteplanetCaves.dm b/code/datums/mapgen/single_biome/WasteplanetCaves.dm index 472a5cf4d54b..08f63ba3149a 100644 --- a/code/datums/mapgen/single_biome/WasteplanetCaves.dm +++ b/code/datums/mapgen/single_biome/WasteplanetCaves.dm @@ -39,10 +39,12 @@ /obj/structure/salvageable/circuit_imprinter = 8, /obj/structure/salvageable/destructive_analyzer = 8, /obj/structure/salvageable/server = 8, + /obj/item/mine/pressure/explosive/rusty/live = 30, + /obj/effect/spawner/lootdrop/mine = 8 ) feature_spawn_list = list( /obj/structure/geyser/random = 1, - /obj/effect/mine/shrapnel/human_only = 1 + /obj/effect/spawner/minefield = 1 ) mob_spawn_list = list( //hivebots, not too difficult diff --git a/code/datums/wires/mines.dm b/code/datums/wires/mines.dm new file mode 100644 index 000000000000..4c856cf99d3f --- /dev/null +++ b/code/datums/wires/mines.dm @@ -0,0 +1,82 @@ +/datum/wires/mine + holder_type = /obj/item/mine/pressure + randomize = TRUE + +/datum/wires/mine/New(atom/holder) + wires = list( + WIRE_BOOM, WIRE_DELAYBOOM, WIRE_PIN, WIRE_RESET + ) + ..() + +/datum/wires/mine/interactable(mob/user) + var/obj/item/mine/pressure/ourmine = holder + if(ourmine.open_panel) + return TRUE + +//are you feelin lucky, punk? +/datum/wires/mine/on_pulse(wire) + var/obj/item/mine/pressure/ourmine = holder + switch(wire) + if(WIRE_BOOM)//oopsies + holder.visible_message(span_userdanger("[icon2html(ourmine, viewers(holder))] \The [ourmine] makes a shrill noise! It's go-")) + ourmine.trigger_mine() + if(WIRE_DELAYBOOM)//oopsies but you get to run + ourmine.blast_delay = clamp(ourmine.blast_delay * 5, 8, 50) + holder.visible_message(span_userdanger("[icon2html(ourmine, viewers(holder))] \The [ourmine] makes a shrill noise! It's go-")) + ourmine.trigger_mine() + //Resets the detonation pin, allowing someone to step off the mine. Minor success. + if(WIRE_PIN) + if(ourmine.clicked == TRUE) + holder.visible_message(span_notice("[icon2html(ourmine, viewers(holder))] You hear something inside \the [ourmine] click softly.")) + playsound(ourmine, 'sound/weapons/empty.ogg', 30, TRUE) + ourmine.clicked = FALSE + else + holder.visible_message(span_notice("[icon2html(ourmine, viewers(holder))] \The [ourmine]'s detonation pad shifts slightly. Nothing happens.")) + if(WIRE_RESET)//Disarms the mine, allowing it to be picked up. Major success. + if(ourmine.armed && ourmine.anchored) + holder.visible_message(span_notice("[icon2html(ourmine, viewers(holder))] \The [ourmine]'s arming lights fade, and the securing bolts loosen. ")) + playsound(ourmine, 'sound/machines/click.ogg', 100, TRUE) + ourmine.disarm() + else if(ourmine.anchored) + holder.visible_message(span_notice("[icon2html(ourmine, viewers(holder))] \The [ourmine]'s yellow arming light flickers.")) + else + holder.visible_message(span_notice("[icon2html(ourmine, viewers(holder))] \The [ourmine]'s securing bolt shifts. Nothing happens.")) + +/datum/wires/mine/on_cut(wire, mend) + var/obj/item/mine/pressure/ourmine = holder + switch(wire) + if(WIRE_BOOM) + if(!mend) + holder.visible_message(span_userdanger("[icon2html(ourmine, viewers(holder))] \The [ourmine] makes a shrill noise! It's go-")) + ourmine.trigger_mine() + if(WIRE_DELAYBOOM) + if(!mend) + ourmine.blast_delay = clamp(ourmine.blast_delay * 5, 8, 50) + holder.visible_message(span_userdanger("[icon2html(ourmine, viewers(holder))] \The [ourmine] makes a shrill noise! It's go-")) + ourmine.trigger_mine() + //Disables the detonation pin. Nothing will happen when the mine is triggered. + //Mine can still be exploded by cutting wires & damage. + if(WIRE_PIN) + if(!mend) + ourmine.dud = TRUE + if(ourmine.clicked == TRUE) + holder.visible_message(span_notice("[icon2html(ourmine, viewers(holder))] You hear something inside \the [ourmine] shift out of place.")) + playsound(ourmine, 'sound/weapons/empty.ogg', 30, TRUE) + ourmine.clicked = FALSE + else + holder.visible_message(span_notice("[icon2html(ourmine, viewers(holder))] \The [ourmine]'s detonation pad goes loose.")) + ourmine.foot_on_mine = null + else + ourmine.dud = FALSE + ourmine.clicked = FALSE + holder.visible_message(span_notice("[icon2html(ourmine, viewers(holder))] You hear something inside \the [ourmine] shift back into place.")) + if(WIRE_RESET) + if(!mend) + if(ourmine.armed && ourmine.anchored) + holder.visible_message(span_notice("[icon2html(ourmine, viewers(holder))] \The [ourmine]'s arming lights fade, and the securing bolts loosen. Disarmed. ")) + playsound(ourmine, 'sound/machines/click.ogg', 100, TRUE) + ourmine.disarm() + else if(ourmine.anchored) + holder.visible_message(span_notice("[icon2html(ourmine, viewers(holder))] \The [ourmine]'s yellow arming light flickers.")) + else + holder.visible_message(span_notice("[icon2html(ourmine, viewers(holder))] \The [ourmine]'s securing bolt shifts. Nothing happens.")) diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm deleted file mode 100644 index 0ca73652857c..000000000000 --- a/code/game/objects/effects/mines.dm +++ /dev/null @@ -1,217 +0,0 @@ - -/obj/effect/mine - name = "dummy mine" - desc = "Better stay away from that thing." - density = FALSE - anchored = TRUE - icon = 'icons/obj/items_and_weapons.dmi' - icon_state = "uglymine" - var/triggered = 0 - -/obj/effect/mine/Initialize() - . = ..() - var/static/list/loc_connections = list( - COMSIG_ATOM_ENTERED = PROC_REF(on_entered), - ) - AddElement(/datum/element/connect_loc, loc_connections) - -/obj/effect/mine/proc/mineEffect(mob/victim) - to_chat(victim, "*click*") - -/obj/effect/mine/proc/on_entered(datum/source, atom/movable/AM) - SIGNAL_HANDLER - if(isturf(loc)) - if(ismob(AM)) - var/mob/MM = AM - if(!(MM.movement_type & FLYING)) - INVOKE_ASYNC(src, PROC_REF(triggermine), AM) - else - INVOKE_ASYNC(src, PROC_REF(triggermine), AM) - -/obj/effect/mine/proc/triggermine(mob/victim) - if(triggered) - return - visible_message("[victim] sets off [icon2html(src, viewers(src))] [src]!") - var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread - s.set_up(3, 1, src) - s.start() - mineEffect(victim) - SEND_SIGNAL(src, COMSIG_MINE_TRIGGERED) - triggered = 1 - qdel(src) - - -/obj/effect/mine/explosive - name = "explosive mine" - var/range_devastation = 0 - var/range_heavy = 1 - var/range_light = 2 - var/range_flash = 3 - -/obj/effect/mine/explosive/mineEffect(mob/victim) - explosion(loc, range_devastation, range_heavy, range_light, range_flash) - -/obj/effect/mine/stun - name = "stun mine" - var/stun_time = 80 - -/obj/effect/mine/shrapnel - name = "shrapnel mine" - var/shrapnel_type = /obj/projectile/bullet/shrapnel - var/shrapnel_magnitude = 3 - -/obj/effect/mine/shrapnel/mineEffect(mob/victim) - AddComponent(/datum/component/pellet_cloud, projectile_type=shrapnel_type, magnitude=shrapnel_magnitude) - -/obj/effect/mine/shrapnel/human_only - name = "sophisticated shrapnel mine" - desc = "A deadly mine, this one seems to be modified to trigger for humans only?" - -/obj/effect/mine/shrapnel/human_only/on_entered(datum/source, atom/movable/AM) - if(!ishuman(AM)) - return - . = ..() - -/obj/effect/mine/shrapnel/sting - name = "stinger mine" - shrapnel_type = /obj/projectile/bullet/pellet/stingball - -/obj/effect/mine/stun/mineEffect(mob/living/victim) - if(isliving(victim)) - victim.Paralyze(stun_time) - -/obj/effect/mine/kickmine - name = "kick mine" - -/obj/effect/mine/kickmine/mineEffect(mob/victim) - if(isliving(victim) && victim.client) - to_chat(victim, "You have been kicked FOR NO REISIN!") - qdel(victim.client) - - -/obj/effect/mine/gas - name = "oxygen mine" - var/gas_amount = 360 - var/gas_type = "o2" - -/obj/effect/mine/gas/mineEffect(mob/victim) - atmos_spawn_air("[gas_type]=[gas_amount]") - - -/obj/effect/mine/gas/plasma - name = "plasma mine" - gas_type = "plasma" - - -/obj/effect/mine/gas/n2o - name = "\improper N2O mine" - gas_type = "n2o" - - -/obj/effect/mine/gas/water_vapor - name = "chilled vapor mine" - gas_amount = 500 - gas_type = "water_vapor" - -/obj/effect/mine/sound - name = "honkblaster 1000" - var/sound = 'sound/items/bikehorn.ogg' - -/obj/effect/mine/sound/mineEffect(mob/victim) - playsound(loc, sound, 100, TRUE) - - -/obj/effect/mine/sound/bwoink - name = "bwoink mine" - sound = 'sound/effects/adminhelp.ogg' - -/obj/effect/mine/pickup - name = "He" - desc = "He." - icon = 'icons/obj/marg.dmi' - icon_state = "marg" - density = FALSE - var/duration = 0 - pixel_x = -8 - pixel_y = 1 - -/obj/effect/mine/pickup/Initialize() - . = ..() - animate(src, time = 20, loop = -1) - -/obj/effect/mine/pickup/triggermine(mob/victim) - if(triggered) - return - triggered = 1 - invisibility = INVISIBILITY_ABSTRACT - mineEffect(victim) - qdel(src) - - -/obj/effect/mine/pickup/bloodbath - name = "His Odium" - desc = "Embrace my righteous fury." - duration = 1200 //2min - color = "#FF0000" - var/mob/living/doomslayer - var/obj/item/chainsaw/doomslayer/chainsaw - -/obj/effect/mine/pickup/bloodbath/mineEffect(mob/living/carbon/victim) - if(!victim.client || !istype(victim)) - return - to_chat(victim, "RIP AND TEAR") - - INVOKE_ASYNC(src, PROC_REF(blood_delusion), victim) - - chainsaw = new(victim.loc) - victim.log_message("entered a marg frenzy", LOG_ATTACK) - - ADD_TRAIT(chainsaw, TRAIT_NODROP, CHAINSAW_FRENZY_TRAIT) - victim.drop_all_held_items() - victim.put_in_hands(chainsaw, forced = TRUE) - chainsaw.attack_self(victim) - victim.reagents.add_reagent(/datum/reagent/medicine/adminordrazine,25) - to_chat(victim, "KILL, KILL, KILL! YOU HAVE NO ALLIES ANYMORE, KILL THEM ALL!") - - var/datum/client_colour/colour = victim.add_client_colour(/datum/client_colour/bloodlust) - QDEL_IN(colour, 11) - doomslayer = victim - RegisterSignal(src, COMSIG_PARENT_QDELETING, PROC_REF(end_blood_frenzy)) - QDEL_IN(WEAKREF(src), duration) - -/obj/effect/mine/pickup/bloodbath/proc/end_blood_frenzy() - if(doomslayer) - to_chat(doomslayer, "Your bloodlust seeps back into the bog of your subconscious and you regain self control.") - doomslayer.log_message("exited a blood frenzy", LOG_ATTACK) - if(chainsaw) - qdel(chainsaw) - -/obj/effect/mine/pickup/bloodbath/proc/blood_delusion(mob/living/carbon/victim) - new /datum/hallucination/delusion(victim, TRUE, "demon", duration, 0) - -/obj/effect/mine/pickup/healing - name = "His Benevolence" - desc = "Come, come. Your wounds shall be undone by my mercy." - - -/obj/effect/mine/pickup/healing/mineEffect(mob/living/carbon/victim) - if(!victim.client || !istype(victim)) - return - to_chat(victim, "You feel great!") - victim.revive(full_heal = TRUE, admin_revive = TRUE) - -/obj/effect/mine/pickup/speed - name = "His Purpose" - desc = "Come, let me quicken you to brilliance." - duration = 300 - -/obj/effect/mine/pickup/speed/mineEffect(mob/living/carbon/victim) - if(!victim.client || !istype(victim)) - return - to_chat(victim, "You feel fast!") - victim.add_movespeed_modifier(/datum/movespeed_modifier/yellow_orb) - addtimer(CALLBACK(src, PROC_REF(finish_effect), victim), duration) - -/obj/effect/mine/pickup/speed/proc/finish_effect(mob/living/carbon/victim) - victim.remove_movespeed_modifier(/datum/movespeed_modifier/yellow_orb) - to_chat(victim, "You slow down.") diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index df7c5ae431c5..437aa7625d71 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -1025,7 +1025,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb * * forced- Do we want this to go through 100%? */ /obj/item/proc/tryEmbed(atom/target, forced=FALSE, silent=FALSE) - if(!isbodypart(target) && !iscarbon(target) && !isclosedturf(target)) + if(!isbodypart(target) && !iscarbon(target)) return if(!forced && !LAZYLEN(embedding)) return diff --git a/code/game/objects/items/devices/mines.dm b/code/game/objects/items/devices/mines.dm new file mode 100644 index 000000000000..112e26e1303b --- /dev/null +++ b/code/game/objects/items/devices/mines.dm @@ -0,0 +1,708 @@ + +/obj/item/mine + name = "mine" + desc = "An anti-personnel mine. This one explodes into nothing and does nothing. Why can you see this? You should't be able to see this. Stop looking at this." + icon = 'icons/obj/landmine.dmi' + w_class = WEIGHT_CLASS_SMALL + throw_speed = 3 + throw_range = 5 + lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi' + righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi' + icon_state = "mine" + item_state = "assembly"//when we get custom sprites replace this. please + base_icon_state = "mine" + + /// Is our mine live? + var/armed = FALSE + /// Is our mine currently exploding? + var/triggered = FALSE + + /// Sets a delay for mines going live after being planted + var/arm_delay = 5 SECONDS + /// Use to set a delay after activation to trigger the explosion. + var/blast_delay = 1 DECISECONDS + + var/manufacturer = MANUFACTURER_NONE + + +/obj/item/mine/Initialize(mapload) + . = ..() + if(armed) + now_armed() + + +/obj/item/mine/examine(mob/user) + . = ..() + if(!armed) + . += span_info("It appears to be inactive...") + else + . += span_info("It looks ready to explode.") + + if(manufacturer) + . += span_notice("It has [manufacturer] engraved on it.") + +/obj/item/mine/update_icon_state() + . = ..() + icon_state = "[base_icon_state][triggered ? "_exploding" : null][!armed && anchored ? "_arming" : null][armed && anchored && !triggered ? "_armed" : null]" + +//mines have a small chance to be triggered by damage, but they take longer to explode +/obj/item/mine/take_damage(damage_amount, damage_type, damage_flag, sound_effect, attack_dir) + . = ..() + if(prob(35) & obj_integrity > 0) + blast_delay = blast_delay * 2 + trigger_mine() + +//insert your horrible fate here +/obj/item/mine/proc/mine_effect(mob/victim) + return + +//handles controlled deactivation +/obj/item/mine/proc/disarm() + if(triggered) //no turning back now + return + anchored = FALSE + armed = FALSE + update_appearance(UPDATE_ICON_STATE) + return + +//using an unarmed mine inhand deploys it. +/obj/item/mine/attack_self(mob/user) + if(!armed) + user.visible_message(span_danger("[user] deploys the [src]."), span_notice("You deploy the [src].")) + + user.dropItemToGround(src) + anchored = TRUE + playsound(src, 'sound/machines/click.ogg', 60, TRUE) + + if(arm_delay) + armed = FALSE + update_appearance(UPDATE_ICON_STATE) + addtimer(CALLBACK(src, PROC_REF(now_armed)), arm_delay) + else + armed = TRUE + message_admins("[key_name(user)] has placed \a [src] at ([x],[y],[z]).") + +//let them know the mine's done cooking +/obj/item/mine/proc/now_armed() + armed = TRUE + update_appearance(UPDATE_ICON_STATE) + playsound(src, 'sound/machines/nuke/angry_beep.ogg', 55, FALSE, 1) + visible_message("\The [src] beeps softly, indicating it is now active.", vision_distance = COMBAT_MESSAGE_RANGE) + +/// Can this mine trigger on the passed movable? +/obj/item/mine/proc/can_trigger(atom/movable/on_who) + //var/badtype = typecacheof(list(/obj/effect, /obj/item/mine)) + if(triggered || !isturf(loc) || !armed || iseffect(on_who) || istype(on_who, /obj/item/mine)) + return FALSE + //if(on_who == badtype)//no recursive self triggering. Bad landmine + // return FALSE + return TRUE + +/// When something sets off a mine +/obj/item/mine/proc/trigger_mine(atom/movable/triggerer) + if(obj_integrity <= 0) + return + if(triggered) //too busy detonating to detonate again + return + if(triggerer) + triggerer.visible_message(span_danger("[icon2html(src, viewers(src))] [triggerer] sets off \the [src]. It's gonna blow!"), span_danger("[icon2html(src, viewers(src))] \The [src] activates.")) + else + visible_message(span_danger("[icon2html(src, viewers(src))] \the [src] begins to flash bright red!")) + triggered = TRUE + update_appearance(UPDATE_ICON_STATE) + if(blast_delay >= 5 DECISECONDS) + playsound(src, 'sound/items/mine_activate.ogg', 70, FALSE) + else + playsound(src, 'sound/items/mine_activate_short.ogg', 80, FALSE) + light_color = "#FF0000" + light_power = 5 + light_range = 3 + if(!blast_delay)//addtimer gets mad if the delay is 0 + blast_now(triggerer) + else + addtimer(CALLBACK(src, PROC_REF(blast_now), triggerer), blast_delay) + +//NOW we actually blow up +/obj/item/mine/proc/blast_now(atom/movable/triggerer) + var/datum/effect_system/spark_spread/sporks = new /datum/effect_system/spark_spread + sporks.set_up(3, 1, src) + sporks.start() + if(ismob(triggerer)) + mine_effect(triggerer) + else + mine_effect() + visible_message(span_danger("[icon2html(src, viewers(src))] \the [src] detonates!")) + SEND_SIGNAL(src, COMSIG_MINE_TRIGGERED, triggerer) + if(triggered)//setting triggered to false in mine_effect() creates a reusable mine + qdel(src) + +//trying to pick up a live mine is probably up there when it comes to terrible ideas +/obj/item/mine/attack_hand(mob/user) + if(armed) + user.visible_message(span_warning("[user] extends their hand towards \the [src]!"), span_userdanger("You extend your arms to pick up \the [src], knowing that it will likely blow up when you touch it!")) + if(do_after(user, 5 SECONDS, target = src))//SO SO generous. You can still step back from the edge. + if(prob(10)) + user.visible_message(span_notice("[user] picks up \the [src], which miraculously doesn't explode!"), span_notice("You pick up \the [src], which miraculously doesn't explode!")) + disarm() + else + user.visible_message(span_danger("[user] attempts to pick up \the [src] only to hear a beep as it activates in their hand!"), span_danger("You attempt to pick up \the [src] only to hear a beep as it activates in your hands!")) + anchored = FALSE + trigger_mine(user) + return . =..() + else + user.visible_message(span_notice("[user] withdraws their hand from \the [src]."), span_notice("You decide against picking up \the [src].")) + . =..() + +//just don't. +/obj/item/mine/attackby(obj/item/I, mob/user) + if(!armed) + to_chat(user, span_notice("You smack \the [src] with [I]. Thankfully, nothing happens.")) + return + else//please stop hitting the live mine with a rock + if(user.a_intent != INTENT_HARM)//are you SURE you want to hit the live mine with a rock + user.visible_message(user, span_notice("[user] gently pokes \the [src] with [I]. Nothing seems to happen."), span_notice("You gently prod \the [src] with [I]. Thankfully, nothing happens.")) + else//at this point it's just natural selection + user.visible_message(span_danger("[user] hits \the [src] with [I], activating it!"), span_userdanger("[icon2html(src, viewers(src))]You hit \the [src] with [I]. The light goes red.")) + trigger_mine(user) + +// +//PRESSURE BASED MINE: +//Mine that explodes when stepped on. +/obj/item/mine/pressure + name = "dummy landmine" + /// When true, mines trigger instantly on being stepped upon + var/hair_trigger = FALSE + /// Has the mine loc been entered? + var/clicked = FALSE + /// Prevents a mine from being screwdrivable (e.g. cannot be disarmed) + var/sealed = FALSE + /// Disables the mine without disarming it. perfect for practical jokes + var/dud = FALSE + + /// Are the wires exposed? + var/open_panel = FALSE + + /// Who's got their foot on the mine's pressure plate + /// Stepping on the mine will set this to the first mob who stepped over it + /// The mine will not detonate via movement unless the first mob steps off of it + var/datum/weakref/foot_on_mine + +/obj/item/mine/pressure/Initialize() + . = ..() + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_entered), + COMSIG_ATOM_EXITED = PROC_REF(on_exited), + ) + AddElement(/datum/element/connect_loc, loc_connections) + wires = new /datum/wires/mine(src) + +/obj/item/mine/pressure/examine(mob/user) + . = ..() + if(hair_trigger) + . += span_danger("It's been rigged to detonate as soon as someone steps on it.") + else + var/atom/movable/unlucky_sod = foot_on_mine?.resolve() + if(user == unlucky_sod) + . += span_bolddanger("The pressure plate is depressed. Any movement you make will set it off now.") + else if(!isnull(unlucky_sod)) + . += span_danger("The pressure plate is depressed by [unlucky_sod]. Any move they make'll set it off now.") + +//step 1: the mistake +/obj/item/mine/pressure/proc/on_entered(datum/source, atom/movable/arrived) + SIGNAL_HANDLER + if(!can_trigger(arrived)) + return + // Flying = can't step on a mine + if(arrived.movement_type & FLYING) + return + //no cheap disarming + if(arrived.throwing && isitem(arrived)) + return + // Someone already on it + if(foot_on_mine?.resolve()) + return + + if(dud == FALSE)//we don't actually need this if the mine's been disabled + foot_on_mine = WEAKREF(arrived) + + if(ismob(arrived)) + var/mob/living/fool = arrived + fool.do_alert_animation(fool) + if(!hair_trigger) + fool.Immobilize(25 DECISECONDS, TRUE) + to_chat(fool, span_userdanger("You step on \the [src] and freeze.")) + visible_message(span_danger("[icon2html(src, viewers(src))] *click*")) + if(dud == FALSE)//see wirecutting + clicked = TRUE + if(hair_trigger) + trigger_mine(arrived) + playsound(src, 'sound/machines/click.ogg', 100, TRUE) + +//step 2: the consequences +/obj/item/mine/pressure/proc/on_exited(datum/source, atom/movable/gone) + SIGNAL_HANDLER + if(hair_trigger) + return + if(!clicked) + return + if(!can_trigger(gone)) + return + // Check that the guy who's on it is stepping off + if(foot_on_mine && !IS_WEAKREF_OF(gone, foot_on_mine)) + return + INVOKE_ASYNC(src, PROC_REF(trigger_mine), gone) + foot_on_mine = null + +/obj/item/mine/pressure/disarm() + clicked = FALSE + . = ..() + +//handles disarming(and failing to disarm) +/obj/item/mine/pressure/attackby(obj/item/I, mob/user) + if(I.tool_behaviour == TOOL_SCREWDRIVER) + if(sealed) + to_chat(user, "You can't see any way to access \the [src]'s wiring.") + return + open_panel = !open_panel + update_appearance(UPDATE_ICON_STATE) + to_chat(user, "You [open_panel ? "reveal" : "hide"] \the [src]'s wiring.") + I.play_tool_sound(src, 50) + return + else if(is_wire_tool(I) && open_panel) + wires.interact(user) + return + else + . = ..() + +// +//PROXIMITY MINES +//Mines that explode when someone moves nearby. Simpler, because I don't have to worry about saving step info or disarming logic +// + +/obj/item/mine/proximity + name = "dummy proximity mine" + blast_delay = 15 DECISECONDS + arm_delay = 10 SECONDS//clear the area + ///needed for the proximity checks. + var/datum/proximity_monitor/proximity_monitor + var/proximity_range = 2 + +/obj/item/mine/proximity/Initialize(mapload) + . = ..() + START_PROCESSING(SSfastprocess, src) + +/obj/item/mine/proximity/examine(mob/user) + . = ..() + if(armed) + . += span_danger("It's been rigged to detonate as soon as someone moves nearby...") + else + . += span_notice("When armed, it activates based on the proximity of living targets.") + +/obj/item/mine/proximity/now_armed() + . = ..() + proximity_monitor = new(src, proximity_range) + light_color = "#FF0000" + light_power = 1 + light_range = 1 + +/obj/item/mine/proximity/disarm() + . = ..() + QDEL_NULL(proximity_monitor) + +/obj/item/mine/proximity/Destroy() + STOP_PROCESSING(SSfastprocess, src) + QDEL_NULL(proximity_monitor) + . = ..() + +/obj/item/mine/proximity/HasProximity(atom/movable/triggerer) + if(!iscarbon(triggerer))//let's keep these on player movements for now. + return + if(!can_trigger(triggerer)) + return + var/mob/living/clueless = triggerer + clueless.do_alert_animation(clueless) + trigger_mine(triggerer) + QDEL_NULL(proximity_monitor) + return + +// +//LANDMINE TYPES +//Rylie please help me make these more immersive +// + +/obj/item/mine/pressure/explosive + name = "\improper G-80 Landmine" + desc = "An anti-infantry explosive produced during the corporate wars. Watch your step." + + //customize explosive power + var/range_devastation = 0 + var/range_heavy = 1 + var/range_light = 5 + var/range_flame = 1 + + //using this to indicate pb + var/range_flash = 1 + + //customize shrapnel. Magnitude zero prevents them from spawning + var/shrapnel_type = /obj/projectile/bullet/shrapnel + var/shrapnel_magnitude = 3 + + /// If TRUE, we spawn extra pellets to eviscerate a person still sitting on it, otherwise it just spawns a ring of pellets around the tile we're on (making setting it off an offensive move) + var/shred_triggerer = TRUE + + manufacturer = MANUFACTURER_SCARBOROUGH + +/obj/item/mine/pressure/explosive/mine_effect(mob/victim) + explosion(loc, range_devastation, range_heavy, range_light, range_flash, 1, 0, range_flame, 0, 1) + if(shrapnel_magnitude > 0) + AddComponent(/datum/component/pellet_cloud, projectile_type=shrapnel_type, magnitude=shrapnel_magnitude) + + +/obj/item/mine/pressure/explosive/rusty + name = "\improper Rusted Landmine" + desc = "An anti-infantry explosive, designed to go off underfoot. This one has seen better days." + manufacturer = MANUFACTURER_NONE + range_heavy = 0 + range_light = 3 + shrapnel_type = /obj/projectile/bullet/shrapnel/rusty + + +/obj/item/mine/pressure/explosive/fire + name = "\improper G-82 Incindeary" + desc = "An anti-infantry explosive produced during the corporate wars. Transforms into superheated slag and a ball of fire on detonation. " + + range_flame = 6 + range_light = 3 + range_flash = 3 + + shrapnel_type = /obj/projectile/bullet/shrapnel/hot + shrapnel_magnitude = 4 + +/obj/item/mine/pressure/explosive/fire/mine_effect(mob/victim) + if(victim.is_holding(src))//in case it's been picked up + for(var/turf/T in view(4,victim)) + T.IgniteTurf(15) + new /obj/effect/hotspot(T) + else + for(var/turf/T in view(4,src)) + T.IgniteTurf(15) + new /obj/effect/hotspot(T) + . = ..() + + +/obj/item/mine/pressure/explosive/heavy + name = "\improper G-81 Anti-Tank Mine" + desc = "An immense anti-vehicle explosive built during the corporate wars. Someone has recklessly switched out the detonator for one that activates for lighter targets." + w_class = WEIGHT_CLASS_BULKY + range_heavy = 6 + range_light = 9 + shrapnel_magnitude = 7 + shrapnel_type = /obj/projectile/bullet/shrapnel/mega + blast_delay = 50//run. + sealed = TRUE//unless we specifically give it to people disarmed, we probably don't want them stealing this + + +/obj/item/mine/pressure/explosive/shrapnel + name = "\improper G-84 Fragmentation" + desc = "An anti-infantry explosive built during the corporate wars. Metal banding inside creates additional deadly shrapnel on detonation. " + + range_heavy = 1 + range_light = 4 + + shrapnel_magnitude = 6 + shred_triggerer = TRUE + +/obj/item/mine/pressure/explosive/rad + name = "\improper G-85 Fission" + desc = "An anti-infantry explosive produced during the corporate wars. This one detonates a small microfission core, creating a bloom of deadly radiation. " + range_light = 4 + range_flame = 2 + shrapnel_magnitude = 7 + shrapnel_type = /obj/projectile/bullet/shrapnel/spicy + var/radpower = 750 + +/obj/item/mine/pressure/explosive/rad/mine_effect(mob/victim) + radiation_pulse(src, radpower, 1) + . = ..() + +//put this on military ships for disarming practice +/obj/item/mine/pressure/training + name = "\improper G-MTH Defusal Trainer" + desc = "A mothballed anti-personnel explosive, equipped with VISCERAL DEFUSAL ACTION for training purposes. Though Scarborough was forced to decomission their stockpiles of mines as part of the ceasefire, the deployed minefields remain." + arm_delay = 2 SECONDS + manufacturer = MANUFACTURER_SCARBOROUGH + +/obj/item/mine/pressure/training/mine_effect(mob/living/victim) + src.say("BOOM! Better luck next time!") + src.visible_message(span_notice("The mine resets itself for another disarming attempt.")) + triggered = FALSE + disarm() + . = ..() + +/obj/item/mine/pressure/gas + name = "chilled vapor mine" + desc = "A non-lethal security deterrent." + var/gas_amount = 500 + var/gas_type = "water_vapor" + hair_trigger = TRUE + +/obj/item/mine/pressure/gas/mine_effect(mob/victim) + atmos_spawn_air("[gas_type]=[gas_amount]") + + +/obj/item/mine/proximity/explosive + name = "\improper G-80P Bouncer" + desc = "An anti-infantry explosive produced during the corporate wars. This one has been rearmed with a proximity movement detector." + + var/range_devastation = 0 + var/range_heavy = 2 + var/range_light = 4 + var/range_flame = 1 + + var/range_flash = 1 + + var/shrapnel_type = /obj/projectile/bullet/shrapnel + var/shrapnel_magnitude = 5 + + manufacturer = MANUFACTURER_SCARBOROUGH + +/obj/item/mine/proximity/explosive/mine_effect(mob/victim) + explosion(loc, range_devastation, range_heavy, range_light, range_flash, 1, 0, range_flame, 0, 1) + if(shrapnel_magnitude > 0) + AddComponent(/datum/component/pellet_cloud, projectile_type=shrapnel_type, magnitude=shrapnel_magnitude) + + +//like all real 'less' than lethal crowd control options this is, in fact, not very good at being nonlethal +/obj/item/mine/proximity/explosive/sting + name = "\improper'Stinger' Crowd Management Device" + desc = "A \"less\" than lethal crowd control weapon, designed to demoralise and scatter anti-NT protestors. The bands of ballistic gel inside strike targets and incapacitate without causing serious maiming. In Theory." + + range_heavy = 0 + range_light = 1 + range_flash = 3 + range_flame = 0 + + shrapnel_magnitude = 8 + shrapnel_type = /obj/projectile/bullet/pellet/stingball + manufacturer = MANUFACTURER_NANOTRASEN_OLD + + +/obj/item/mine/proximity/explosive/plasma + name = "\improper Etherbor EP-3" + desc = "An anti-infantry explosive designed by the PGF for denial of territory to enemy forces. Radiates high energy plasma to eradicate nearby targets." + range_light = 2 + range_flame = 3 + range_heavy = 0 + shrapnel_magnitude = 8 + shrapnel_type = /obj/projectile/energy/plasmabolt + manufacturer = MANUFACTURER_PGF + +/obj/item/mine/proximity/explosive/plasma/mine_effect(mob/victim) + if(victim.is_holding(src))//in case it's been picked up + for(var/turf/T in view(3,victim)) + T.IgniteTurf(25, "green") + else + for(var/turf/T in view(3,src)) + T.IgniteTurf(25, "green") + . = ..() + +//Manhacks... so pretty... +/obj/item/mine/proximity/spawner + name = "debug spawner mine" + desc = "Real no Virus. 100% free. Coders hate him!" + var/spawn_type = null //manhacks go here :) + var/spawn_number = 5 + +/obj/item/mine/proximity/spawner/mine_effect(mob/victim) + if(isturf(loc)) + var/turf/T = get_turf(src) + playsound(T, 'sound/effects/phasein.ogg', 100, TRUE) + spawn_and_random_walk(spawn_type, T, spawn_number, walk_chance=50, admin_spawn=((flags_1 & ADMIN_SPAWNED_1) ? TRUE : FALSE)) + . = ..() + +/obj/item/mine/proximity/spawner/manhack + name = "\improper P-83 Lacerator" + desc = "An anti-infantry device produced during the corporate wars. The explosive payload has been swapped out for 'viscerator'-type antipersonnel drones." + spawn_type = /mob/living/simple_animal/hostile/viscerator + +// +//GIMMICK MINES// +//pretty much exclusively for adminbus & code dependencies +// + +/obj/item/mine/pressure/kickmine + name = "\improper A-00 'Adminbus'" + desc = "An Anti-Griefer proximity expulsive. Delivers Justice." + blast_delay = null//funnier this way + hair_trigger = TRUE + +/obj/item/mine/pressure/kickmine/mine_effect(mob/victim) + if(isliving(victim) && victim.client && Adjacent(victim)) + to_chat(victim, span_userdanger("You have been kicked from the game. Take this time to think about what you've done.")) + qdel(victim.client) + +/obj/item/mine/pressure/sound + name = "sonic mine" + desc = "A potent tool of psychological warfare." + var/sound = 'sound/effects/adminhelp.ogg' + blast_delay = null + hair_trigger = TRUE + +/obj/item/mine/pressure/sound/mine_effect(mob/victim) + playsound(loc, sound, 100, TRUE) + +/obj/item/mine/pressure/pickup + name = "pickup mine" + desc = "does nothing" + icon = 'icons/obj/marg.dmi' + icon_state = "marg" + density = FALSE + var/duration = 0 + pixel_x = -8 + pixel_y = 1 + anchored = TRUE + armed = TRUE + blast_delay = null + hair_trigger = TRUE + +/obj/item/mine/pressure/pickup/Initialize() + . = ..() + animate(src, time = 20, loop = -1) + +/obj/item/mine/pressure/pickup/trigger_mine(mob/victim) + if(triggered) + return + triggered = TRUE + invisibility = INVISIBILITY_ABSTRACT + mine_effect(victim) + qdel(src) + + +/obj/item/mine/pressure/pickup/bloodbath + name = "bloody orb" + desc = "Embrace righteous fury." + duration = 1200 //2min + color = "#FF0000" + var/mob/living/doomslayer + var/obj/item/chainsaw/doomslayer/chainsaw + +/obj/item/mine/pressure/pickup/bloodbath/mine_effect(mob/living/carbon/victim) + if(!victim.client || !istype(victim)) + return + to_chat(victim, "RIP AND TEAR") + + INVOKE_ASYNC(src, PROC_REF(blood_delusion), victim) + + chainsaw = new(victim.loc) + victim.log_message("entered a marg frenzy", LOG_ATTACK) + + ADD_TRAIT(chainsaw, TRAIT_NODROP, CHAINSAW_FRENZY_TRAIT) + victim.drop_all_held_items() + victim.put_in_hands(chainsaw, forced = TRUE) + chainsaw.attack_self(victim) + victim.reagents.add_reagent(/datum/reagent/medicine/adminordrazine,25) + to_chat(victim, "KILL, KILL, KILL! YOU HAVE NO ALLIES ANYMORE, KILL THEM ALL!") + + var/datum/client_colour/colour = victim.add_client_colour(/datum/client_colour/bloodlust) + QDEL_IN(colour, 11) + doomslayer = victim + RegisterSignal(src, COMSIG_PARENT_QDELETING, PROC_REF(end_blood_frenzy)) + QDEL_IN(WEAKREF(src), duration) + +/obj/item/mine/pressure/pickup/bloodbath/proc/end_blood_frenzy() + if(doomslayer) + to_chat(doomslayer, "Your bloodlust seeps back into the bog of your subconscious and you regain self control.") + doomslayer.log_message("exited a blood frenzy", LOG_ATTACK) + if(chainsaw) + qdel(chainsaw) + +/obj/item/mine/pressure/pickup/bloodbath/proc/blood_delusion(mob/living/carbon/victim) + new /datum/hallucination/delusion(victim, TRUE, "demon", duration, 0) + +/obj/item/mine/pressure/pickup/healing + name = "healing orb" + desc = "Your wounds shall be undone." + +/obj/item/mine/pressure/pickup/healing/mine_effect(mob/living/carbon/victim) + if(!victim.client || !istype(victim)) + return + to_chat(victim, "You feel great!") + victim.revive(full_heal = TRUE, admin_revive = TRUE) + +/obj/item/mine/pressure/pickup/speed + name = "quick orb" + desc = "Quickens you." + duration = 300 + +/obj/item/mine/pressure/pickup/speed/mine_effect(mob/living/carbon/victim) + if(!victim.client || !istype(victim)) + return + to_chat(victim, "You feel fast!") + victim.add_movespeed_modifier(/datum/movespeed_modifier/yellow_orb) + addtimer(CALLBACK(src, PROC_REF(finish_effect), victim), duration) + +/obj/item/mine/pressure/pickup/speed/proc/finish_effect(mob/living/carbon/victim) + victim.remove_movespeed_modifier(/datum/movespeed_modifier/yellow_orb) + to_chat(victim, "You slow down.") + + + +// +//mapping tool that generates "live" variants of all mine subtypes, which are anchored and ready to blow. +//Add new mine variants you make below as a LIVE_MINE_HELPER define containing their subtyping. +// + +#define LIVE_MINE_HELPER(mine_type) \ + /obj/item/mine/##mine_type/live { \ + anchored = TRUE; \ + armed = TRUE; \ + } + +LIVE_MINE_HELPER(pressure/explosive) +LIVE_MINE_HELPER(pressure/explosive/fire) +LIVE_MINE_HELPER(pressure/explosive/rusty) +LIVE_MINE_HELPER(pressure/explosive/rad) +LIVE_MINE_HELPER(pressure/explosive/heavy) +LIVE_MINE_HELPER(pressure/explosive/shrapnel) + +LIVE_MINE_HELPER(proximity/explosive) +LIVE_MINE_HELPER(proximity/explosive/sting) +LIVE_MINE_HELPER(proximity/spawner/manhack) +LIVE_MINE_HELPER(proximity/explosive/plasma) + +LIVE_MINE_HELPER(pressure/gas) +LIVE_MINE_HELPER(pressure/kickmine) +LIVE_MINE_HELPER(pressure/sound) + +// +// spawners (random mines, minefields, non-guaranteed mine) +// + +/obj/effect/spawner/lootdrop/mine + name = "live mine spawner (random)" + lootcount = 1 + fan_out_items = TRUE + loot = list( + /obj/item/mine/pressure/explosive/live = 10, + /obj/item/mine/pressure/explosive/shrapnel/live = 3, + /obj/item/mine/pressure/explosive/rad/live = 3, + /obj/item/mine/pressure/explosive/fire/live = 3) + +/obj/effect/spawner/minefield + name = "minefield spawner" + var/minerange = 9 + var/minetype = /obj/item/mine/pressure/explosive/rusty/live + +/obj/effect/spawner/minefield/Initialize(mapload) + . = ..() + for(var/turf/open/T in view(minerange,loc)) + if(prob(5)) + new minetype(T) + +/obj/effect/spawner/minefield/random + name = "random minefield spawner" + minetype = /obj/effect/spawner/lootdrop/mine + +/obj/effect/spawner/minefield/manhack + name = "manhack field spawner" + minetype = /obj/item/mine/proximity/spawner/manhack/live diff --git a/code/game/objects/items/shrapnel.dm b/code/game/objects/items/shrapnel.dm index 8bf29c9a807a..959649c8c59b 100644 --- a/code/game/objects/items/shrapnel.dm +++ b/code/game/objects/items/shrapnel.dm @@ -1,6 +1,6 @@ /obj/item/shrapnel // frag grenades name = "shrapnel shard" - embedding = list(embed_chance=70, ignore_throwspeed_threshold=TRUE, fall_chance=4, embed_chance_turf_mod=-100) + embedding = list(embed_chance=70, ignore_throwspeed_threshold=TRUE, fall_chance=2, embed_chance_turf_mod=-100) custom_materials = list(/datum/material/iron=50) armour_penetration = -20 icon = 'icons/obj/shards.dmi' @@ -8,9 +8,14 @@ w_class = WEIGHT_CLASS_TINY item_flags = DROPDEL -/obj/item/shrapnel/stingball // stingbang grenades - name = "stingball" - embedding = list(embed_chance=90, fall_chance=3, jostle_chance=7, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.7, pain_mult=5, jostle_pain_mult=6, rip_time=15, embed_chance_turf_mod=-100) +/obj/item/shrapnel/hot + name = "molten slag" + embedding = list(embed_chance=70, ignore_throwspeed_threshold=TRUE, fall_chance=2, embed_chance_turf_mod=-100) + damtype = BURN + +/obj/item/shrapnel/stingball + name = "clump of ballistic gel" + embedding = list(embed_chance=15, fall_chance=2, jostle_chance=7, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.8, pain_mult=3, jostle_pain_mult=5, rip_time=15, embed_chance_turf_mod=-100) icon_state = "tiny" /obj/item/shrapnel/bullet // bullets @@ -28,35 +33,79 @@ /obj/projectile/bullet/shrapnel name = "flying shrapnel shard" - damage = 9 + damage = 10 range = 10 - armour_penetration = -30 - dismemberment = 5 + armour_penetration = -20 + dismemberment = 25 ricochets_max = 2 ricochet_chance = 40 shrapnel_type = /obj/item/shrapnel ricochet_incidence_leeway = 60 hit_stunned_targets = TRUE +/obj/projectile/bullet/shrapnel/Initialize() + . = ..() + def_zone = pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_CHEST, BODY_ZONE_HEAD, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) + +/obj/projectile/bullet/shrapnel/rusty + damage = 8 + armour_penetration = -35 + dismemberment = 15 + ricochets_max = 3//duller = less likely to stick in a wall + ricochet_chance = 60 + /obj/projectile/bullet/shrapnel/mega + damage = 20 name = "flying shrapnel hunk" range = 25 - dismemberment = 10 + dismemberment = 35 ricochets_max = 4 ricochet_chance = 90 ricochet_decay_chance = 0.9 +/obj/projectile/bullet/shrapnel/hot + name = "white-hot metal slag" + damage = 8 + range = 8 + armour_penetration = -35 + dismemberment = 10 + shrapnel_type = /obj/item/shrapnel/hot + damage_type = BURN + +/obj/projectile/bullet/shrapnel/hot/on_hit(atom/target, blocked = FALSE) + . = ..() + if(iscarbon(target)) + var/mob/living/carbon/M = target + M.adjust_fire_stacks(15) + M.IgniteMob() + +/obj/projectile/bullet/shrapnel/spicy + name = "radioactive slag" + damage_type = BURN + damage = 10 + range = 8 + dismemberment = 10 + armour_penetration = -35 + shrapnel_type = /obj/item/shrapnel/hot + +/obj/projectile/bullet/shrapnel/spicy/on_hit(atom/target, blocked = FALSE) + . = ..() + if(iscarbon(target)) + var/mob/living/carbon/M = target + M.apply_effect(250,EFFECT_IRRADIATE,0) + /obj/projectile/bullet/pellet/stingball - name = "stingball pellet" - damage = 3 - stamina = 8 - ricochets_max = 4 + name = "ballistic gel clump" + damage = 5 + stamina = 15 + ricochets_max = 6 ricochet_chance = 66 ricochet_decay_chance = 1 ricochet_decay_damage = 0.9 ricochet_auto_aim_angle = 10 ricochet_auto_aim_range = 2 ricochet_incidence_leeway = 0 + knockdown = 20 shrapnel_type = /obj/item/shrapnel/stingball /obj/projectile/bullet/pellet/stingball/mega diff --git a/code/game/turfs/open/floor.dm b/code/game/turfs/open/floor.dm index f4bfa034fa12..d74edb27a658 100644 --- a/code/game/turfs/open/floor.dm +++ b/code/game/turfs/open/floor.dm @@ -62,27 +62,15 @@ if(1) ScrapeAway(2, flags = CHANGETURF_INHERIT_AIR) if(2) - switch(rand(1, 3)) - if(1) - if(!length(baseturfs) || !ispath(baseturfs[baseturfs.len-1], /turf/open/floor)) - ScrapeAway(flags = CHANGETURF_INHERIT_AIR) - ReplaceWithLattice() - else - ScrapeAway(2, flags = CHANGETURF_INHERIT_AIR) - if(prob(33)) - new /obj/item/stack/sheet/metal(src) - if(2) - ScrapeAway(2, flags = CHANGETURF_INHERIT_AIR) - if(3) - if(prob(80)) - ScrapeAway(flags = CHANGETURF_INHERIT_AIR) - else - break_tile() - hotspot_expose(1000,CELL_VOLUME) - if(prob(33)) - new /obj/item/stack/sheet/metal(src) + if(prob(60)) + ScrapeAway(flags = CHANGETURF_INHERIT_AIR) + else + break_tile() + hotspot_expose(1000,CELL_VOLUME) + if(prob(33)) + new /obj/item/stack/sheet/metal(src) if(3) - if (prob(50)) + if(prob(50)) src.break_tile() src.hotspot_expose(1000,CELL_VOLUME) diff --git a/code/modules/admin/fun_balloon.dm b/code/modules/admin/fun_balloon.dm index 99e7b1692ecc..04e84097f6d1 100644 --- a/code/modules/admin/fun_balloon.dm +++ b/code/modules/admin/fun_balloon.dm @@ -134,8 +134,8 @@ INVOKE_ASYNC(src, PROC_REF(do_bloodbath), M) /obj/effect/forcefield/arena_shuttle_entrance/proc/do_bloodbath(mob/living/L) - var/obj/effect/mine/pickup/bloodbath/B = new (L) - B.mineEffect(L) + var/obj/item/mine/pressure/pickup/bloodbath/B = new (L) + B.mine_effect(L) /area/shuttle_arena name = "arena" diff --git a/code/modules/antagonists/blood_contract/blood_contract.dm b/code/modules/antagonists/blood_contract/blood_contract.dm index 01039a77623d..edd8aba60422 100644 --- a/code/modules/antagonists/blood_contract/blood_contract.dm +++ b/code/modules/antagonists/blood_contract/blood_contract.dm @@ -26,10 +26,10 @@ H.add_atom_colour("#FF0000", ADMIN_COLOUR_PRIORITY) - var/obj/effect/mine/pickup/bloodbath/B = new(H) + var/obj/item/mine/pressure/pickup/bloodbath/B = new(H) B.duration = duration - INVOKE_ASYNC(B, TYPE_PROC_REF(/obj/effect/mine/pickup/bloodbath, mineEffect), H) //could use moving out from the mine + INVOKE_ASYNC(B, TYPE_PROC_REF(/obj/item/mine/pressure/pickup/bloodbath, mine_effect), H) //could use moving out from the mine for(var/mob/living/carbon/human/P in GLOB.player_list) if(P == H) diff --git a/code/modules/mining/abandoned_crates.dm b/code/modules/mining/abandoned_crates.dm index 140b87c1707f..e274009d07e0 100644 --- a/code/modules/mining/abandoned_crates.dm +++ b/code/modules/mining/abandoned_crates.dm @@ -222,9 +222,7 @@ if(96) new /obj/item/banhammer(src) for(var/i in 1 to 3) - var/obj/effect/mine/sound/bwoink/mine = new (src) - mine.set_anchored(FALSE) - mine.move_resist = MOVE_RESIST_DEFAULT + new /obj/item/mine/pressure/sound(src) if(97) for(var/i in 1 to 4) new /obj/item/clothing/mask/balaclava(src) diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index 985c5212299b..42cc2a74d6a4 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -1517,8 +1517,8 @@ /obj/item/mayhem/attack_self(mob/user) for(var/mob/living/carbon/human/H in range(7,user)) - var/obj/effect/mine/pickup/bloodbath/B = new(H) - INVOKE_ASYNC(B, TYPE_PROC_REF(/obj/effect/mine/pickup/bloodbath, mineEffect), H) + var/obj/item/mine/pressure/pickup/bloodbath/B = new(H) + INVOKE_ASYNC(B, TYPE_PROC_REF(/obj/item/mine/pressure/pickup/bloodbath, mine_effect), H) to_chat(user, "You shatter the bottle!") playsound(user.loc, 'sound/effects/glassbr1.ogg', 100, TRUE) message_admins("[ADMIN_LOOKUPFLW(user)] has activated a bottle of mayhem!") diff --git a/code/modules/movespeed/modifiers/items.dm b/code/modules/movespeed/modifiers/items.dm index b10e25c84e7a..c858582af6a3 100644 --- a/code/modules/movespeed/modifiers/items.dm +++ b/code/modules/movespeed/modifiers/items.dm @@ -17,3 +17,4 @@ /datum/movespeed_modifier/berserk multiplicative_slowdown = -0.2 + diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 9aa8ac60326f..8ca8f0bc05c8 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -2,21 +2,6 @@ #define DUALWIELD_PENALTY_EXTRA_MULTIPLIER 1.6 #define FIRING_PIN_REMOVAL_DELAY 50 -#define MANUFACTURER_NONE null -#define MANUFACTURER_SHARPLITE "the Sharplite Defense logo" -#define MANUFACTURER_SHARPLITE_NEW "the Nanotrasen-Sharplite logo" -#define MANUFACTURER_HUNTERSPRIDE "the Hunter's Pride Arms and Ammunition logo" -#define MANUFACTURER_SOLARARMORIES "the Solarbundswaffenkammer emblem" -#define MANUFACTURER_SCARBOROUGH "the Scarborough Arms logo" -#define MANUFACTURER_EOEHOMA "the Eoehoma Firearms emblem" -#define MANUFACTURER_NANOTRASEN_OLD "an outdated Nanotrasen logo" -#define MANUFACTURER_NANOTRASEN "the Nanotrasen logo" -#define MANUFACTURER_BRAZIL "a green flag with a blue circle and a yellow diamond around it" -#define MANUFACTURER_INTEQ "an orange crest with the letters 'IRMG'" -#define MANUFACTURER_MINUTEMAN "the Lanchester City Firearms Plant logo" -#define MANUFACTURER_DONKCO "the Donk! Co. logo" -#define MANUFACTURER_PGF "the Etherbor Industries emblem" -#define MANUFACTURER_IMPORT "Lanchester Import Co." /obj/item/gun name = "gun" desc = "It's a gun. It's pretty terrible, though." diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 85c4558343d9..06698ca53982 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -209,7 +209,11 @@ SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_ON_HIT, firer, target, Angle) // i know that this is probably more with wands and gun mods in mind, but it's a bit silly that the projectile on_hit signal doesn't ping the projectile itself. // maybe we care what the projectile thinks! See about combining these via args some time when it's not 5AM - SEND_SIGNAL(src, COMSIG_PROJECTILE_SELF_ON_HIT, firer, target, Angle) + var/obj/item/bodypart/hit_limb + if(isliving(target)) + var/mob/living/L = target + hit_limb = L.check_limb_hit(def_zone) + SEND_SIGNAL(src, COMSIG_PROJECTILE_SELF_ON_HIT, firer, target, Angle, hit_limb) var/turf/target_loca = get_turf(target) var/hitx @@ -259,7 +263,7 @@ new impact_effect_type(target_loca, hitx, hity) var/organ_hit_text = "" - var/limb_hit = L.check_limb_hit(def_zone)//to get the correct message info. + var/limb_hit = hit_limb if(limb_hit) organ_hit_text = " in \the [parse_zone(limb_hit)]" if(suppressed==SUPPRESSED_VERY) diff --git a/code/modules/projectiles/projectile/energy/misc.dm b/code/modules/projectiles/projectile/energy/misc.dm index 81fed69d516a..11f948ddb415 100644 --- a/code/modules/projectiles/projectile/energy/misc.dm +++ b/code/modules/projectiles/projectile/energy/misc.dm @@ -23,3 +23,22 @@ icon_state = "pulse1" damage = 0 damage_type = BURN + +/obj/projectile/energy/plasmabolt + name = "ionized plasma" + damage = 25 + armour_penetration = -10 + range = 8 + damage_type = BURN + icon_state = "blastwave" + color = "#00ff00" + hitsound = 'sound/weapons/sear.ogg' + +/obj/projectile/energy/plasmabolt/on_hit(atom/target, blocked = FALSE) + . = ..() + if(iscarbon(target)) + var/mob/living/carbon/M = target + M.adjust_bodytemperature(350) + if(prob(35)) + M.adjust_fire_stacks(15) + M.IgniteMob() diff --git a/icons/obj/landmine.dmi b/icons/obj/landmine.dmi new file mode 100644 index 0000000000000000000000000000000000000000..dd19fd9d3991a7ab6066d70f467cbd9d60140f3c GIT binary patch literal 2821 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 RvgcZW)fHQ_W>XKue*h~EmDT_N literal 0 HcmV?d00001 diff --git a/shiptest.dme b/shiptest.dme index 142dfc49155f..dd099108f6d7 100644 --- a/shiptest.dme +++ b/shiptest.dme @@ -65,6 +65,7 @@ #include "code\__DEFINES\food.dm" #include "code\__DEFINES\footsteps.dm" #include "code\__DEFINES\forensics.dm" +#include "code\__DEFINES\guns.dm" #include "code\__DEFINES\hud.dm" #include "code\__DEFINES\icon_smoothing.dm" #include "code\__DEFINES\important_recursive_contents.dm" @@ -772,6 +773,7 @@ #include "code\datums\wires\explosive.dm" #include "code\datums\wires\fax.dm" #include "code\datums\wires\microwave.dm" +#include "code\datums\wires\mines.dm" #include "code\datums\wires\mulebot.dm" #include "code\datums\wires\particle_accelerator.dm" #include "code\datums\wires\r_n_d.dm" @@ -1029,7 +1031,6 @@ #include "code\game\objects\effects\forcefields.dm" #include "code\game\objects\effects\glowshroom.dm" #include "code\game\objects\effects\landmarks.dm" -#include "code\game\objects\effects\mines.dm" #include "code\game\objects\effects\misc.dm" #include "code\game\objects\effects\overlays.dm" #include "code\game\objects\effects\particle_emitter.dm" @@ -1199,6 +1200,7 @@ #include "code\game\objects\items\devices\laserpointer.dm" #include "code\game\objects\items\devices\lightreplacer.dm" #include "code\game\objects\items\devices\megaphone.dm" +#include "code\game\objects\items\devices\mines.dm" #include "code\game\objects\items\devices\multitool.dm" #include "code\game\objects\items\devices\paicard.dm" #include "code\game\objects\items\devices\pipe_painter.dm" diff --git a/sound/items/mine_activate.ogg b/sound/items/mine_activate.ogg new file mode 100644 index 0000000000000000000000000000000000000000..ed39ba283be7444fa318ba96f2b9644224888e6c GIT binary patch literal 63468 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 SPX`Mf$i7{?T2bi%?!N#R02|i; literal 0 HcmV?d00001 From 22b2077341afbff35b22bffcbaef6c134c1d83bf Mon Sep 17 00:00:00 2001 From: Changelogs Date: Fri, 12 Apr 2024 04:12:56 -0500 Subject: [PATCH 21/32] Automatic changelog generation for PR #2759 [ci skip] --- html/changelogs/AutoChangeLog-pr-2759.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2759.yml diff --git a/html/changelogs/AutoChangeLog-pr-2759.yml b/html/changelogs/AutoChangeLog-pr-2759.yml new file mode 100644 index 000000000000..8d4bb30fa458 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2759.yml @@ -0,0 +1,13 @@ +author: Sun-Soaked +changes: + - {rscadd: 'Redesigns landmines as an item that can be picked up, disarmed, deployed. + Some logic courtesy of /tg/.'} + - {rscadd: Adds a proximity explosive variant of landmines.} + - {bugfix: shrapnel embedding once again respects targeted limb and no longer runtimes + on hitting a wall or destroying an object.} + - {bugfix: 'storage can no longer pick up anchored objects, causing them to get + stuck inside'} + - {balance: Nerfs the ability of heavy explosions to immediately breach to space} + - {soundadd: adds two mine detonation noises} + - {code_imp: moves weapon manufacturer defines to a DEFINE file} +delete-after: true From f2d7376d0969897f143094ee559f2d19e467a531 Mon Sep 17 00:00:00 2001 From: generalthrax <139387950+generalthrax@users.noreply.github.com> Date: Fri, 12 Apr 2024 13:13:40 -0500 Subject: [PATCH 22/32] Adds Etherbor civilian weapons to cargo (#2891) ## About The Pull Request Adds the civilian Etherbor weapons (SG-8 pistol and BG-12 semi-automatic rifle) to the cargo console. ## Why It's Good For The Game Etherbor supposedly sells these weapons on the civilian market but they don't. Even not considering that, there doesn't seem to be any non-NT energy weapon at all on the cargo console and I want to give independents or crews that don't like NT some options. Open to changing the price on the crates but I think its more or less pretty fair to how the weapons perform. ## Changelog :cl: add: Etherbor SG-8 Beam Pistol to cargo for 1000 credits add: Etherbor BG-12 Beam Rifle to cargo for 3000 credits add: Etherbor civilian weapon cells for 600 credits, slightly higher capacity than the generic cells /:cl: --- code/modules/cargo/packs/ammo.dm | 6 ++++++ code/modules/cargo/packs/gun.dm | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/code/modules/cargo/packs/ammo.dm b/code/modules/cargo/packs/ammo.dm index 28d5ad1ec248..53bfd35974e7 100644 --- a/code/modules/cargo/packs/ammo.dm +++ b/code/modules/cargo/packs/ammo.dm @@ -281,6 +281,12 @@ contains = list(/obj/item/stock_parts/cell/gun) cost = 500 +/datum/supply_pack/ammo/guncell/kalix + name = "Etherbor Cell Crate" + desc = "Contains an Etherbor weapon cell, compatible with Etherbor armaments with a slightly higher capacity." + contains = list(/obj/item/stock_parts/cell/gun/kalix) + cost = 600 + /datum/supply_pack/ammo/c46x30mm_boxcrate name = "4.6x30mm Ammo Box Crate" desc = "Contains a fifty-round 4.6x30mm box for PDWs such as the WT-550." diff --git a/code/modules/cargo/packs/gun.dm b/code/modules/cargo/packs/gun.dm index 8ed63f7cfb47..ea6bbbe7671d 100644 --- a/code/modules/cargo/packs/gun.dm +++ b/code/modules/cargo/packs/gun.dm @@ -83,6 +83,20 @@ crate_name = "ion rifle crate" crate_type = /obj/structure/closet/crate/secure/plasma +/datum/supply_pack/gun/laser/kalix/pistol + name = "Etherbor SG-8 Beam Pistol Crate" + desc = "Contains a single SG-8 Beam Pistol, a civilian-grade sidearm developed in the PGF, manufactured by Etherbor Industries." + cost = 1000 + contains = list(/obj/item/gun/energy/kalix/pistol) + crate_name = "beam pistol crate" + +/datum/supply_pack/gun/laser/kalix + name = "Etherbor BG-12 Beam Rifle Crate" + desc = "Contains a single BG-12 Beam Rifle, a civilian-grade semi-automatic developed in the PGF, manufactured by Etherbor Industries." + cost = 3000 + contains = list(/obj/item/gun/energy/kalix) + crate_name = "beam rifle crate" + /* Shotguns */ From e25063bd65f586de5de31e07eb04382c07c8ae4f Mon Sep 17 00:00:00 2001 From: Changelogs Date: Fri, 12 Apr 2024 13:25:45 -0500 Subject: [PATCH 23/32] Automatic changelog generation for PR #2891 [ci skip] --- html/changelogs/AutoChangeLog-pr-2891.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2891.yml diff --git a/html/changelogs/AutoChangeLog-pr-2891.yml b/html/changelogs/AutoChangeLog-pr-2891.yml new file mode 100644 index 000000000000..626c45699940 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2891.yml @@ -0,0 +1,7 @@ +author: generalthrax +changes: + - {rscadd: Etherbor SG-8 Beam Pistol to cargo for 1000 credits} + - {rscadd: Etherbor BG-12 Beam Rifle to cargo for 3000 credits} + - {rscadd: 'Etherbor civilian weapon cells for 600 credits, slightly higher capacity + than the generic cells'} +delete-after: true From 6ff0b69bd30e0e8f5b0984bb29d55d963924a0c2 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Sat, 13 Apr 2024 00:39:35 +0000 Subject: [PATCH 24/32] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-2759.yml | 13 ------------- html/changelogs/AutoChangeLog-pr-2852.yml | 5 ----- html/changelogs/AutoChangeLog-pr-2891.yml | 7 ------- html/changelogs/archive/2024-04.yml | 20 ++++++++++++++++++++ 4 files changed, 20 insertions(+), 25 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-2759.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-2852.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-2891.yml diff --git a/html/changelogs/AutoChangeLog-pr-2759.yml b/html/changelogs/AutoChangeLog-pr-2759.yml deleted file mode 100644 index 8d4bb30fa458..000000000000 --- a/html/changelogs/AutoChangeLog-pr-2759.yml +++ /dev/null @@ -1,13 +0,0 @@ -author: Sun-Soaked -changes: - - {rscadd: 'Redesigns landmines as an item that can be picked up, disarmed, deployed. - Some logic courtesy of /tg/.'} - - {rscadd: Adds a proximity explosive variant of landmines.} - - {bugfix: shrapnel embedding once again respects targeted limb and no longer runtimes - on hitting a wall or destroying an object.} - - {bugfix: 'storage can no longer pick up anchored objects, causing them to get - stuck inside'} - - {balance: Nerfs the ability of heavy explosions to immediately breach to space} - - {soundadd: adds two mine detonation noises} - - {code_imp: moves weapon manufacturer defines to a DEFINE file} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-2852.yml b/html/changelogs/AutoChangeLog-pr-2852.yml deleted file mode 100644 index 733e4972678f..000000000000 --- a/html/changelogs/AutoChangeLog-pr-2852.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: FalloutFalcon -changes: - - {tweak: all radios start off} - - {tweak: all survival boxs start with a radio} -delete-after: true diff --git a/html/changelogs/AutoChangeLog-pr-2891.yml b/html/changelogs/AutoChangeLog-pr-2891.yml deleted file mode 100644 index 626c45699940..000000000000 --- a/html/changelogs/AutoChangeLog-pr-2891.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: generalthrax -changes: - - {rscadd: Etherbor SG-8 Beam Pistol to cargo for 1000 credits} - - {rscadd: Etherbor BG-12 Beam Rifle to cargo for 3000 credits} - - {rscadd: 'Etherbor civilian weapon cells for 600 credits, slightly higher capacity - than the generic cells'} -delete-after: true diff --git a/html/changelogs/archive/2024-04.yml b/html/changelogs/archive/2024-04.yml index ae6b53f8ebdc..277ae650feb3 100644 --- a/html/changelogs/archive/2024-04.yml +++ b/html/changelogs/archive/2024-04.yml @@ -54,3 +54,23 @@ - imageadd: new turbine sprites thgvr: - rscadd: Suicide & Execution with a damaging firearm is now more deadly and gruesome. +2024-04-13: + FalloutFalcon: + - tweak: all radios start off + - tweak: all survival boxs start with a radio + Sun-Soaked: + - rscadd: Redesigns landmines as an item that can be picked up, disarmed, deployed. + Some logic courtesy of /tg/. + - rscadd: Adds a proximity explosive variant of landmines. + - bugfix: shrapnel embedding once again respects targeted limb and no longer runtimes + on hitting a wall or destroying an object. + - bugfix: storage can no longer pick up anchored objects, causing them to get stuck + inside + - balance: Nerfs the ability of heavy explosions to immediately breach to space + - soundadd: adds two mine detonation noises + - code_imp: moves weapon manufacturer defines to a DEFINE file + generalthrax: + - rscadd: Etherbor SG-8 Beam Pistol to cargo for 1000 credits + - rscadd: Etherbor BG-12 Beam Rifle to cargo for 3000 credits + - rscadd: Etherbor civilian weapon cells for 600 credits, slightly higher capacity + than the generic cells From 2d8d3d62d72a3f5ae37b5ff9354ad8f7c2920149 Mon Sep 17 00:00:00 2001 From: Mark Suckerberg Date: Mon, 15 Apr 2024 09:24:00 -0500 Subject: [PATCH 25/32] Update RUNNING_A_SERVER.md Signed-off-by: Mark Suckerberg --- .github/RUNNING_A_SERVER.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/RUNNING_A_SERVER.md b/.github/RUNNING_A_SERVER.md index 7ee48e872cd1..766085313174 100644 --- a/.github/RUNNING_A_SERVER.md +++ b/.github/RUNNING_A_SERVER.md @@ -4,9 +4,9 @@ First-time installation should be fairly straightforward. First, you'll need BYOND installed. You can get it from https://www.byond.com/download. Once you've done that, extract the game files to wherever you want to keep them. This is a sourcecode-only release, so the next step is to compile the server files. -Open shiptest.dme by double-clicking it, open the Build menu, and click -compile. This'll take a little while, and if everything's done right you'll get -a message like this: + +Double-click `BUILD.bat` in the root directory of the source code. This'll take +a little while, and if everything's done right you'll get a message like this: ``` saving shiptest.dmb (DEBUG mode) @@ -17,6 +17,9 @@ If you see any errors or warnings, something has gone wrong - possibly a corrupt download or the files extracted wrong. If problems persist, ask for assistance in [the discord](https://shiptest.net/discord) +**Unlike other servers,** Shiptest uses an external library called Auxmos, which + + Once that's done, open up the config folder. You'll want to edit config.txt to set the probabilities for different gamemodes in Secret and to set your server location so that all your players don't get disconnected at the end of each From 917da9b5b48d5d9226c3c95c0afdabd27e56c78a Mon Sep 17 00:00:00 2001 From: Mark Suckerberg Date: Mon, 15 Apr 2024 09:30:50 -0500 Subject: [PATCH 26/32] Update RUNNING_A_SERVER.md Signed-off-by: Mark Suckerberg --- .github/RUNNING_A_SERVER.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/RUNNING_A_SERVER.md b/.github/RUNNING_A_SERVER.md index 766085313174..9a0c19a7e530 100644 --- a/.github/RUNNING_A_SERVER.md +++ b/.github/RUNNING_A_SERVER.md @@ -17,17 +17,6 @@ If you see any errors or warnings, something has gone wrong - possibly a corrupt download or the files extracted wrong. If problems persist, ask for assistance in [the discord](https://shiptest.net/discord) -**Unlike other servers,** Shiptest uses an external library called Auxmos, which - - -Once that's done, open up the config folder. You'll want to edit config.txt to -set the probabilities for different gamemodes in Secret and to set your server -location so that all your players don't get disconnected at the end of each -round. It's recommended you don't turn on the gamemodes with probability 0, -except Extended, as they have various issues and aren't currently being tested, -so they may have unknown and bizarre bugs. Extended is essentially no mode, and -isn't in the Secret rotation by default as it's just not very fun. - You'll also want to edit config/admins.txt to remove the default admins and add your own. "Game Master" is the highest level of access, and probably the one you'll want to use for now. You can set up your own ranks and find out more in @@ -46,9 +35,15 @@ Windows DLL is included in this repository, but Linux users will need to build and install it themselves. Directions can be found at the [rust-g repo](https://github.com/tgstation/rust-g). +**Unlike other servers,** Shiptest also uses an external library called Auxmos, which +needs to be compiled on linux systems. Like with rust-g, Windows hosts should be fine, as the DLL +it needs is shipped with the repository. Please download and install [auxmos](https://github.com/Putnam3145/auxmos) +using the instructions provided if you're running a linux system. +`tools/ci/build_auxmos.sh` can also be used if you're in a rush. + Finally, to start the server, run Dream Daemon and enter the path to your compiled shiptest.dmb file. Make sure to set the port to the one you -specified in the config.txt, and set the Security box to 'Safe'. Then press GO +specified in the config.txt, and set the Security box to 'Trusted'. Then press GO and the server should start up and be ready to join. It is also recommended that you set up the SQL backend (see below). @@ -71,9 +66,14 @@ https://github.com/tgstation/tgstation-server ## SQL SETUP -The SQL backend requires a Mariadb server running 10.2 or later. Mysql is not supported but Mariadb is a drop in replacement for mysql. SQL is required for the library, stats tracking, admin notes, and job-only bans, among other features, mostly related to server administration. Your server details go in /config/dbconfig.txt, and the SQL schema is in /SQL/tgstation_schema.sql and /SQL/tgstation_schema_prefix.sql depending on if you want table prefixes. More detailed setup instructions are located here: https://shiptest.net/wiki/Downloading_the_source_code#Setting_up_the_database +The SQL backend requires a Mariadb server running 10.2 or later. Mysql is not +supported, but Mariadb is a drop in replacement for mysql. SQL is required for the +library, stats tracking, admin notes, and job-only bans, among other features, +mostly related to server administration. Your server details go in /config/dbconfig.txt, +and the SQL schema is in /SQL/tgstation_schema.sql and /SQL/tgstation_schema_prefix.sql +depending on if you want table prefixes. -If you are hosting a testing server on windows you can use a standalone version of MariaDB pre load with a blank (but initialized) tgdb database. Find them here: https://tgstation13.download/database/ Just unzip and run for a working (but insecure) database server. Includes a zipped copy of the data folder for easy resetting back to square one. +More detailed setup instructions are located here: https://shiptest.net/wiki/Downloading_the_source_code#Setting_up_the_database ## WEB/CDN RESOURCE DELIVERY From 1b27b00d5ae7523a539e21368906b24d4cb4fc01 Mon Sep 17 00:00:00 2001 From: goober3 <118859017+goober3@users.noreply.github.com> Date: Tue, 16 Apr 2024 02:48:12 +0100 Subject: [PATCH 27/32] Clears up the graffiti list, adds hobocode graffiti. (#2887) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## About The Pull Request This PR: Removes these graffiti sprites. ![73a8f5806f023f6444d442b37162fced](https://github.com/shiptest-ss13/Shiptest/assets/118859017/866e500a-ad54-4209-b33f-547444b1e0e0) Adds a new set of codersprite graffiti, which is based on hobo symbols. ![74bd1076299c63cafd7822ced40010e5](https://github.com/shiptest-ss13/Shiptest/assets/118859017/ce57deb2-b42a-4e0e-8cd3-7b37b924267b) ![image](https://github.com/shiptest-ss13/Shiptest/assets/118859017/6b8ea581-b26e-4cc4-9e40-93c6207973de) ## Why It's Good For The Game We've got a bunch of cruft in spraycan graffiti, including a ton of weird anti-furry stuff, and references that don't make sense in our setting. This PR removes the bad stuff, and adds some new graffiti to fill the space. ## Changelog 🆑 add: A new graffiti section for code symbols has been added. del: Some graffiti has been removed from the spraycan list. /🆑 --- code/game/objects/effects/decals/crayon.dm | 2 +- code/game/objects/items/crayons.dm | 33 +++++++-------------- icons/effects/crayondecal.dmi | Bin 40891 -> 11040 bytes 3 files changed, 11 insertions(+), 24 deletions(-) diff --git a/code/game/objects/effects/decals/crayon.dm b/code/game/objects/effects/decals/crayon.dm index c14086ff0f3b..7ff53391f6e0 100644 --- a/code/game/objects/effects/decals/crayon.dm +++ b/code/game/objects/effects/decals/crayon.dm @@ -4,7 +4,7 @@ GLOBAL_LIST(gang_tags) name = "rune" desc = "Graffiti. Damn kids." icon = 'icons/effects/crayondecal.dmi' - icon_state = "rune1" + icon_state = "firedanger" gender = NEUTER plane = GAME_PLANE //makes the graffiti visible over a wall. mergeable_decal = FALSE diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm index 5ca8fa313c60..d703ae86ca7d 100644 --- a/code/game/objects/items/crayons.dm +++ b/code/game/objects/items/crayons.dm @@ -43,16 +43,15 @@ var/drawtype var/text_buffer = "" - var/static/list/graffiti = list("amyjon","face","matt","revolution","engie","guy","end","dwarf","uboa","body","cyka","star","poseur tag","prolizard","antilizard") + var/static/list/graffiti = list("face","guy","end","body") + var/static/list/code = list("getout","empty","unsafe","camp","safepath","jackpot","dismantle") var/static/list/symbols = list("danger","firedanger","electricdanger","biohazard","radiation","safe","evac","space","med","trade","shop","food","peace","like","skull","nay","heart","credit") - var/static/list/drawings = list("smallbrush","brush","largebrush","splatter","snake","stickman","carp","ghost","clown","taser","disk","fireaxe","toolbox","corgi","cat","toilet","blueprint","beepsky","scroll","bottle","shotgun") - var/static/list/oriented = list("arrow","line","thinline","shortline","body","chevron","footprint","clawprint","pawprint") // These turn to face the same way as the drawer - var/static/list/runes = list("rune1","rune2","rune3","rune4","rune5","rune6") + var/static/list/drawings = list("smallbrush","brush","splatter","snake","carp","ghost","taser","disk","fireaxe","toolbox","corgi","cat","toilet","blueprint","beepsky","scroll","bottle","shotgun") + var/static/list/oriented = list("arrow","line","thinline","shortline","body","chevron","footprint","clawprint","pawprint","dogo","nogo") // These turn to face the same way as the drawer var/static/list/randoms = list(RANDOM_ANY, RANDOM_RUNE, RANDOM_ORIENTED, RANDOM_NUMBER, RANDOM_GRAFFITI, RANDOM_LETTER, RANDOM_SYMBOL, RANDOM_PUNCTUATION, RANDOM_DRAWING) - var/static/list/graffiti_large_h = list("yiffhell", "secborg", "paint") - var/static/list/all_drawables = graffiti + symbols + drawings + oriented + runes + graffiti_large_h + var/static/list/all_drawables = graffiti + code + symbols + drawings + oriented var/paint_mode = PAINT_NORMAL @@ -176,15 +175,15 @@ . = list() - var/list/g_items = list() + var/list/g_items = list() //i hate tgcode . += list(list("name" = "Graffiti", "items" = g_items)) for(var/g in graffiti) g_items += list(list("item" = g)) - var/list/glh_items = list() - . += list(list("name" = "Graffiti Large Horizontal", "items" = glh_items)) - for(var/glh in graffiti_large_h) - glh_items += list(list("item" = glh)) + var/list/c_items = list() + . += list(list("name" = "Code", "items" = c_items)) + for(var/c in code) + c_items += list(list("item" = c)) var/list/S_items = list() . += list(list("name" = "Symbols", "items" = S_items)) @@ -201,11 +200,6 @@ for(var/O in oriented) O_items += list(list("item" = O)) - var/list/R_items = list() - . += list(list(name = "Runes", "items" = R_items)) - for(var/R in runes) - R_items += list(list("item" = R)) - var/list/rand_items = list() . += list(list(name = "Random", "items" = rand_items)) for(var/i in randoms) @@ -245,9 +239,6 @@ drawtype = stencil . = TRUE text_buffer = "" - if(stencil in graffiti_large_h) - paint_mode = PAINT_LARGE_HORIZONTAL - text_buffer = "" else paint_mode = PAINT_NORMAL if("select_colour") @@ -281,8 +272,6 @@ var/istagger = HAS_TRAIT(user, TRAIT_TAGGER) var/cost = 1 - if(paint_mode == PAINT_LARGE_HORIZONTAL) - cost = 5 if(istype(target, /obj/item/canvas)) cost = 0 if(ishuman(user)) @@ -311,8 +300,6 @@ drawing = pick(drawings) if(RANDOM_GRAFFITI) drawing = pick(graffiti) - if(RANDOM_RUNE) - drawing = pick(runes) if(RANDOM_ORIENTED) drawing = pick(oriented) if(RANDOM_NUMBER) diff --git a/icons/effects/crayondecal.dmi b/icons/effects/crayondecal.dmi index c9e7f880c8092afb2479ea87eb90d2bce616b011..d18ba51ae40f213acae14180287b0d4027ae1a87 100644 GIT binary patch literal 11040 zcmZ{KWl$VUyDaYRz665HE)d*Zg1fuBJ7IAr5Flu<5Hwf_?iO5vyDsj!$O7kmzf7OLS2P_rcdh1 z+Olu|X+1qX*Vor~cXx+}hYt@A>+9>Mr>7em8*6K8CnqQO_xCq9HxLM9dwcuw@$vcj z`Q_yW27|4xu5NB_-rn9`U0pprJ?-r5tgNi;@9$q+T%4buzrMci?d>fuFCQHpL7~ut zgM+iPv&+lNt*x!&;7eP(j`LZ%2PDMM5HrCIgG`#H^kJnDcpR z52@a*^AofR+yZ+K%Yn=FFItlB4Sz z>#Wd%pL!w8J^?~zwZ5`)A&)Op_Q!uu2UvZckq zMD+2IblWX}jl*mjY z?@H0RZ|IIA9?EQ5^boy6G3Z3(rrsg#5pS8WgE*u-Y?@!b{|XEMdCxO*`P$S3&o);u+o)4g|K7_k%ew9%z1ax&&Z8(`VxsrE%~Kw^ zN@R2}PC)f|X7S?sdJbTCIiPjpZ-(-RzB#?YTjrf!d+YK#!sS%Crj~$ z>1`LtPepY>4<|qmqm^r6q&5a-#}v+8mC_F937>E~uu&ooDtRDjav+o}k-YB86>TM` zU78@0G}&(9n&Jn$M6Hz<6wS7 zxg0g&&No_nKj3)UKqp-Hh@yyXcc>ZLkZr?cj8Uje(ucw!l^`rWUzMO@2m z76K_r3fa@BRg-T`;vHN^s0naIc8W3dFE1a9s%%jGUMd5H8M{DyEie*)LQT^iIvpD{ zTY_KdYTEuWY3U-1U!r2?-4np{V3|5DVKm5d!8PsZvnd5da0tLZu7<`)PVI*>5+#3{ z%OQEPCw0=pGJ7;!w*B|bEn1t;&8}enZD06qh3|OGoE2tT8i%ADA?7Z_==+#=pZ(~k zgZuJ7V!KeFUF?${97F&QE;$d}oI}|w>wm;MpL939=`yMdxFKJUt;oU$cfj9*{nF+{ zIWOp0po;gYKB+e$W1mO=l7=gnlom0VYj}bVDK|V>`2Y~ zaQB2oWqom{JJvPlDhf-$u39~1T}Dq3+7H^?#zMCFPlPeVA)&lg#K!EzNL2BlIIh^) zsAnW!K!Oh6RvuOrIH^E56G(8?H?~N$c`urmnd4%=FK@jorXe}6$}hd~hZT^Lp+Qy& zMP>RP^+EF;2halD%7OO!J%nFbA&mSRv8{4A*?AF-(hD8%xIr;&~!v2Ee^EKV;0dv{Ab6))B=iWCr3D*cO zEsv=r{?8C0k?^2>Iw6rLO553g$NdQ5f4MImgG2qFL+~#+N1WvUdGweUlieALEH=Ar z&I_rCnXI0T?b88F3$s3Uac3s7of0u#P};4KQItecS5$#oWsK>58QEOt5*9S5H6_=f z#%`
  • Ornx^zP(r{WV{l83$QFLE$~vBinUG{g;9WH@+Br zhCjz3^WT#lf3dtm5$Rl@{dV;@l(RZaI2?pt;AV3IXEaDxBtM(ECI z08bb8?a_Vzd=b586|bS3K8?pSy4V}}ql;jVZ415|@l4=Wt{*Pt*S564wo^4jiM{<~ z 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 AQ2+n{ literal 40891 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 CLE4%C From d54ba13e7d99b76b254bd202f4c2f0b6816597cc Mon Sep 17 00:00:00 2001 From: Gristlebee <56049844+Gristlebee@users.noreply.github.com> Date: Mon, 15 Apr 2024 18:50:30 -0700 Subject: [PATCH 28/32] Granularizes the space suits and armor tab in Outpost cargo, and reduces the cost of specialized space suits (#2894) ## About The Pull Request Granularizes the Spacesuits and Armor tab at outpost cargo, and adjusts the descriptions accordingly. Removes a mention of pods in the pilot suit since those don't exist anymore. Reduces the costs of the specialized space suits. ## Why It's Good For The Game More fine control over the amount of suits or armor you want to buy is probably good. As for the space suit prices, they were incredibly high and prohibitively expensive for what they were to the point you would almost never see any of them bought unless you were just drowning in money. ## Changelog :cl: tweak: Granularizes Outpost Spacesuits and Armor balance: Reduces the cost of specialized space suits /:cl: --- code/modules/cargo/packs/spacesuit_armor.dm | 88 ++++++++------------- 1 file changed, 32 insertions(+), 56 deletions(-) diff --git a/code/modules/cargo/packs/spacesuit_armor.dm b/code/modules/cargo/packs/spacesuit_armor.dm index c873a7e2dac4..78e7d0fb1ff0 100644 --- a/code/modules/cargo/packs/spacesuit_armor.dm +++ b/code/modules/cargo/packs/spacesuit_armor.dm @@ -8,39 +8,32 @@ /datum/supply_pack/spacesuit_armor/spacesuit name = "Space Suit Crate" - desc = "Contains three basic space suits. Although the technology is centuries old, they should protect you from the vacuum of space." - cost = 1500 + desc = "Contains one basic space suit. Although the technology is centuries old, it should protect you from the vacuum of space." + cost = 500 contains = list(/obj/item/clothing/suit/space, - /obj/item/clothing/suit/space, - /obj/item/clothing/suit/space, - /obj/item/clothing/head/helmet/space, - /obj/item/clothing/head/helmet/space, /obj/item/clothing/head/helmet/space) crate_name = "space suit crate" /datum/supply_pack/spacesuit_armor/pilot_spacesuit name = "Pilot Space Suit Crate" - desc = "Two pilot space suits, for improved mobility in mechs and pods." - cost = 3500 + desc = "One pilot space suit, for improved mobility in mechs." + cost = 750 contains = list(/obj/item/clothing/suit/space/pilot, - /obj/item/clothing/suit/space/pilot, - /obj/item/clothing/head/helmet/space/pilot/random, /obj/item/clothing/head/helmet/space/pilot/random) crate_name = "pilot space suit crate" /datum/supply_pack/spacesuit_armor/mining_hardsuits_indie name = "Mining Hardsuit Crate" - desc = "Two independent branded mining hardsuits for when explorer suits just dont cut it." - cost = 4000 - contains = list(/obj/item/clothing/suit/space/hardsuit/mining/independent, - /obj/item/clothing/suit/space/hardsuit/mining/independent) + desc = "One independent branded mining hardsuit for when explorer suits just dont cut it." + cost = 1500 + contains = list(/obj/item/clothing/suit/space/hardsuit/mining/independent) crate_name = "mining hardsuit crate" crate_type = /obj/structure/closet/crate/secure/plasma /datum/supply_pack/spacesuit_armor/med_hardsuit name = "Medical Hardsuit Crate" - desc = "Two medical hardsuits, resistant to diseases and useful for retrieving patients in space." - cost = 5000 + desc = "One medical hardsuit, resistant to diseases and useful for retrieving patients in space." + cost = 1500 contains = list(/obj/item/clothing/suit/space/hardsuit/medical, /obj/item/clothing/suit/space/hardsuit/medical) crate_name = "medical hardsuit crate" @@ -49,7 +42,7 @@ /datum/supply_pack/spacesuit_armor/mining_hardsuit_heavy name = "Heavy Mining Hardsuit Crate" desc = "One deluxe heavy mining hardsuit for dangerous frontier operations. Comes with a pair of EXOCOM jet boots." - cost = 6000 + cost = 3500 contains = list(/obj/item/clothing/suit/space/hardsuit/mining/heavy, /obj/item/clothing/shoes/bhop) crate_name = "heavy mining hardsuit crate" @@ -57,53 +50,43 @@ /datum/supply_pack/spacesuit_armor/sec_hardsuit_bundle name = "Security Hardsuit Crate" - desc = "Contains two security hardsuits for light combat duty." - cost = 7500 - contains = list(/obj/item/clothing/suit/space/hardsuit/security/independent, - /obj/item/clothing/suit/space/hardsuit/security/independent) + desc = "Contains one security hardsuit for light combat duty." + cost = 2500 + contains = list(/obj/item/clothing/suit/space/hardsuit/security/independent) crate_name = "security hardsuit crate" crate_type = /obj/structure/closet/crate/secure/gear /datum/supply_pack/spacesuit_armor/sci_hardsuit name = "Science Hardsuit Crate" - desc = "Contains two science hardsuits, designed to provide safety under advanced experimental conditions." - cost = 8500 - contains = list(/obj/item/clothing/suit/space/hardsuit/rd, - /obj/item/clothing/suit/space/hardsuit/rd) + desc = "Contains one science hardsuit, designed to provide safety under advanced experimental conditions." + cost = 2000 + contains = list(/obj/item/clothing/suit/space/hardsuit/rd) crate_name = "science hardsuit crate" crate_type = /obj/structure/closet/crate/secure/science /datum/supply_pack/spacesuit_armor/engi_spacesuit_bundle name = "Engineering Space Suit Crate" - desc = "Need to turn your ship into a safety hazard? Not a problem! These three engineering space suits will help get the job done." - cost = 9000 + desc = "Need to turn your ship into a safety hazard? Not a problem! This engineering space suit will help get the job done." + cost = 1500 contains = list(/obj/item/clothing/suit/space/engineer, - /obj/item/clothing/suit/space/engineer, - /obj/item/clothing/suit/space/engineer, - /obj/item/clothing/head/helmet/space/light/engineer, - /obj/item/clothing/head/helmet/space/light/engineer, /obj/item/clothing/head/helmet/space/light/engineer) crate_name = "engineering space suit crate" crate_type = /obj/structure/closet/crate/secure/engineering /datum/supply_pack/spacesuit_armor/atmos_hardsuit name = "Atmospherics Hardsuit Crate" - desc = "The iconic hardsuit of Nanotrasen's Atmosphere Corps, these two hardsuits are known across space as a symbol of defiance in the face of sudden decompression. Smells faintly of plasma." - cost = 12000 - contains = list(/obj/item/clothing/suit/space/hardsuit/engine/atmos, - /obj/item/clothing/suit/space/hardsuit/engine/atmos) + desc = "The iconic hardsuit of Nanotrasen's Atmosphere Corps, this hardsuit is known across space as a symbol of defiance in the face of sudden decompression. Smells faintly of plasma." + cost = 2500 + contains = list(/obj/item/clothing/suit/space/hardsuit/engine/atmos) crate_name = "atmospherics hardsuit crate" crate_type = /obj/structure/closet/crate/secure/engineering /datum/supply_pack/spacesuit_armor/swat name = "SWAT Crate" - desc = "Contains two fullbody sets of tough, fireproof, pressurized suits designed in a joint effort by IS-ERI and Nanotrasen. Each set contains a suit, helmet, and combat belt." - cost = 12000 + desc = "Contains one fullbody set of tough, fireproof, pressurized suit designed in a joint effort by IS-ERI and Nanotrasen. The set contains a suit, helmet, and combat belt." + cost = 3500 contains = list(/obj/item/clothing/head/helmet/swat/nanotrasen, - /obj/item/clothing/head/helmet/swat/nanotrasen, - /obj/item/clothing/suit/space/swat, /obj/item/clothing/suit/space/swat, - /obj/item/storage/belt/military/assault, /obj/item/storage/belt/military/assault) crate_name = "swat crate" crate_type = /obj/structure/closet/crate/secure/gear @@ -114,42 +97,35 @@ /datum/supply_pack/spacesuit_armor/basic_armor name = "Armor Crate" - desc = "Two sets of well-rounded body armor. Each set includes a helmet and vest." - cost = 1500 + desc = "One set of well-rounded body armor. The set includes a helmet and vest." + cost = 750 contains = list(/obj/item/clothing/suit/armor/vest, - /obj/item/clothing/suit/armor/vest, - /obj/item/clothing/head/helmet/sec, /obj/item/clothing/head/helmet/sec) crate_name = "armor crate" crate_type = /obj/structure/closet/crate/secure/plasma /datum/supply_pack/spacesuit_armor/riot_armor name = "Riot Armor Crate" - desc = "Contains two full sets of riot armor. Although heavily padded to deal with close-quarters threats, they perform poorly against most firearms." - cost = 3000 + desc = "Contains one full set of riot armor. Although heavily padded to deal with close-quarters threats, they perform poorly against most firearms." + cost = 1500 contains = list(/obj/item/clothing/suit/armor/riot, - /obj/item/clothing/suit/armor/riot, - /obj/item/clothing/head/helmet/riot, /obj/item/clothing/head/helmet/riot) crate_name = "riot armor crate" crate_type = /obj/structure/closet/crate/secure/plasma /datum/supply_pack/spacesuit_armor/bullet_armor name = "Bulletproof Armor Crate" - desc = "Contains two full sets of bulletproof armor, guaranteed to reduce a bullet's stopping power by half but with limited protection against melee weaponry." - cost = 3500 + desc = "Contains one full set of bulletproof armor, guaranteed to reduce a bullet's stopping power by half but with limited protection against melee weaponry." + cost = 1750 contains = list(/obj/item/clothing/suit/armor/vest/bulletproof, - /obj/item/clothing/suit/armor/vest/bulletproof, - /obj/item/clothing/head/helmet/bulletproof, /obj/item/clothing/head/helmet/bulletproof) crate_name = "bulletproof armor crate" crate_type = /obj/structure/closet/crate/secure/plasma /datum/supply_pack/spacesuit_armor/laser_armor name = "Reflector Vest Crate" - desc = "Contains two vests of highly reflective material. Each armor piece diffuses a laser's energy by over half, as well as offering a good chance to reflect the laser entirely." - cost = 3000 - contains = list(/obj/item/clothing/suit/armor/laserproof, - /obj/item/clothing/suit/armor/laserproof) + desc = "Contains one vest made of highly reflective material. The armor piece diffuses a laser's energy by over half, as well as offering a good chance to reflect the laser entirely." + cost = 1500 + contains = list(/obj/item/clothing/suit/armor/laserproof) crate_name = "reflector vest crate" crate_type = /obj/structure/closet/crate/secure/plasma From f99cf954492665bd7ea9d3b232b549a5052ea97e Mon Sep 17 00:00:00 2001 From: Changelogs Date: Mon, 15 Apr 2024 21:44:11 -0500 Subject: [PATCH 29/32] Automatic changelog generation for PR #2894 [ci skip] --- html/changelogs/AutoChangeLog-pr-2894.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2894.yml diff --git a/html/changelogs/AutoChangeLog-pr-2894.yml b/html/changelogs/AutoChangeLog-pr-2894.yml new file mode 100644 index 000000000000..4d0b7771519f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2894.yml @@ -0,0 +1,5 @@ +author: Gristlebee +changes: + - {tweak: Granularizes Outpost Spacesuits and Armor} + - {balance: Reduces the cost of specialized space suits} +delete-after: true From 644b8cde5b69768fa5d82de9102891692288ca81 Mon Sep 17 00:00:00 2001 From: enkidienne <56667232+enkidienne@users.noreply.github.com> Date: Mon, 15 Apr 2024 21:52:12 -0400 Subject: [PATCH 30/32] Put the right magazines in the Comms Outpost ruin. (#2900) ## About The Pull Request switched 9mm to 10mm, the magazines actually used by the gun that spawns there. ## Why It's Good For The Game No more useless mags. ## Changelog :cl: tweak: changed the 3 9mm magazines in the lavaland comms outpost ruin to 10mm :cl: --- .../RandomRuins/LavaRuins/lavaland_surface_comm_outpost.dmm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_comm_outpost.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_comm_outpost.dmm index 6cad8f589b78..ac1c579eedb1 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_comm_outpost.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_comm_outpost.dmm @@ -202,9 +202,9 @@ /obj/structure/closet/crate, /obj/item/clothing/gloves/combat, /obj/item/gun/ballistic/automatic/pistol, -/obj/item/ammo_box/magazine/pistolm9mm, -/obj/item/ammo_box/magazine/pistolm9mm, -/obj/item/ammo_box/magazine/pistolm9mm, +/obj/item/ammo_box/magazine/m10mm, +/obj/item/ammo_box/magazine/m10mm, +/obj/item/ammo_box/magazine/m10mm, /turf/open/floor/carpet/black, /area/ruin/unpowered/syndicate_outpost) "To" = ( From be90b8e5af6de0c362bc0c813ffa66ce88170736 Mon Sep 17 00:00:00 2001 From: meem <75212565+meemofcourse@users.noreply.github.com> Date: Mon, 15 Apr 2024 21:56:41 -0400 Subject: [PATCH 31/32] [Needs Testmerge] Guestbook, from Mojave Sun (#2770) ## About The Pull Request This thing sucks to port, I'm going to be real with you. TODO: * [x] Make it sort of work * [x] Fix an error where adding a guest name doesn't work * [ ] ~~Make it so reading IDs only work at close range~~ out of scope * [x] Make it so you automatically know your ship's crewmates ~~and captains know other faction members~~ * [x] Something with ERTs * [ ] ~~Make the guestbook save across rounds~~ asked to not ![imagen](https://github.com/shiptest-ss13/Shiptest/assets/75212565/8943246e-145d-44b2-8284-3539fb09b565) ![imagen](https://github.com/shiptest-ss13/Shiptest/assets/75212565/8966bff4-8688-466e-88fa-2d73f71d2572) ![imagen](https://github.com/shiptest-ss13/Shiptest/assets/75212565/24e680be-e994-4aed-af3e-f4333d9b4a8d) This pull request ports the following: * https://github.com/Mojave-Sun/mojave-sun-13/pull/2415 * https://github.com/Mojave-Sun/mojave-sun-13/pull/2433 These PRs change how examining someone works. You have to walk up to someone and remember their face in order to recognize their voice. Names will still be displayed with people's IDs ## Why It's Good For The Game * The current anonymity system sucks for stealthy shit. You immediately know someone's real name. An improved system allows for more roleplay possibilities. * Kansatsu is more reliable. * You can rob people with a knife and a balaclava at the outpost, and they won't know who you are! ## Changelog :cl: tweak: Identification Cards are now Access Cards. The only real difference is that your name only shows up on a double examine. refactor: Anonymous mechanics. Characters no longer instantly recognize each other, and need to properly memorize each other in order. You can recognize an unmasked person by ctrl-shift-clicking them. /:cl: --------- Signed-off-by: meem <75212565+meemofcourse@users.noreply.github.com> Signed-off-by: Mark Suckerberg Co-authored-by: Mark Suckerberg Co-authored-by: goober3 <118859017+goober3@users.noreply.github.com> --- code/__DEFINES/dcs/signals.dm | 34 ++-- code/__DEFINES/mobs.dm | 2 +- code/__HELPERS/_lists.dm | 2 +- code/__HELPERS/mobs.dm | 6 + code/_globalvars/lists/names.dm | 2 + code/_onclick/click.dm | 1 - code/controllers/subsystem/pai.dm | 2 +- code/datums/chatmessage.dm | 2 +- code/datums/guestbook.dm | 148 ++++++++++++++++++ code/datums/mind.dm | 5 + code/datums/progressbar.dm | 2 +- code/game/atoms.dm | 6 +- code/game/atoms_movable.dm | 4 +- code/game/machinery/navbeacon.dm | 2 +- code/game/objects/effects/landmarks.dm | 2 +- code/game/objects/items/cards_ids.dm | 60 ++----- code/game/objects/items/toys.dm | 2 +- code/game/say.dm | 34 +++- code/modules/admin/admin.dm | 2 +- code/modules/admin/create_mob.dm | 1 + code/modules/admin/verbs/one_click_antag.dm | 10 ++ code/modules/client/preferences.dm | 17 +- code/modules/client/preferences_savefile.dm | 2 + code/modules/client/verbs/looc.dm | 29 ++-- code/modules/clothing/chameleon.dm | 2 +- code/modules/jobs/job_types/_job.dm | 1 - code/modules/mob/dead/dead.dm | 2 +- .../modules/mob/dead/new_player/new_player.dm | 3 +- .../mob/living/carbon/human/examine.dm | 40 ++--- code/modules/mob/living/carbon/human/human.dm | 17 ++ .../mob/living/carbon/human/human_defines.dm | 3 + .../mob/living/carbon/human/human_helpers.dm | 74 +++++++-- .../mob/living/carbon/human/human_say.dm | 25 ++- .../living/carbon/human/species_types/IPC.dm | 2 +- .../carbon/human/species_types/mothmen.dm | 2 +- .../carbon/human/species_types/plasmamen.dm | 2 +- code/modules/mob/living/login.dm | 2 +- code/modules/mob/living/silicon/ai/ai.dm | 1 + .../mob/living/simple_animal/simple_animal.dm | 2 +- code/modules/mob/living/status_procs.dm | 4 +- code/modules/mob/mob.dm | 59 +++++-- .../overmap/ships/controlled_ship_datum.dm | 19 +++ shiptest.dme | 1 + strings/ipc_preference_adjectives.txt | 71 +++++++++ strings/preference_adjectives.txt | 117 ++++++++++++++ tgui/packages/tgui/interfaces/Guestbook.tsx | 74 +++++++++ 46 files changed, 737 insertions(+), 163 deletions(-) create mode 100644 code/datums/guestbook.dm create mode 100644 strings/ipc_preference_adjectives.txt create mode 100644 strings/preference_adjectives.txt create mode 100644 tgui/packages/tgui/interfaces/Guestbook.tsx diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index c0aabd909f59..8f0a0d9b3c43 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -224,19 +224,29 @@ #define COMSIG_LIVING_GET_PULLED "living_start_pulled" ///////////////// - -#define COMSIG_ENTER_AREA "enter_area" //from base of area/Entered(): (/area). Sent to "area-sensitive" movables, see __DEFINES/traits.dm for info. -#define COMSIG_EXIT_AREA "exit_area" //from base of area/Exited(): (/area). Sent to "area-sensitive" movables, see __DEFINES/traits.dm for info. - -#define COMSIG_CLICK "atom_click" //from base of atom/Click(): (location, control, params, mob/user) -#define COMSIG_CLICK_SHIFT "shift_click" //from base of atom/ShiftClick(): (/mob) - #define COMPONENT_ALLOW_EXAMINATE 1 //Allows the user to examinate regardless of client.eye. -#define COMSIG_CLICK_CTRL "ctrl_click" //from base of atom/CtrlClickOn(): (/mob) -#define COMSIG_CLICK_ALT "alt_click" //from base of atom/AltClick(): (/mob) -#define COMSIG_CLICK_CTRL_SHIFT "ctrl_shift_click" //from base of atom/CtrlShiftClick(/mob) -#define COMSIG_MOUSEDROP_ONTO "mousedrop_onto" //from base of atom/MouseDrop(): (/atom/over, /mob/user) +//from base of area/Entered(): (/area). Sent to "area-sensitive" movables, see __DEFINES/traits.dm for info. +#define COMSIG_ENTER_AREA "enter_area" +//from base of area/Exited(): (/area). Sent to "area-sensitive" movables, see __DEFINES/traits.dm for info. +#define COMSIG_EXIT_AREA "exit_area" +//from base of atom/Click(): (location, control, params, mob/user) +#define COMSIG_CLICK "atom_click" +//from base of atom/ShiftClick(): (/mob) +#define COMSIG_CLICK_SHIFT "shift_click" +//Allows the user to examinate regardless of client.eye. + #define COMPONENT_ALLOW_EXAMINATE 1 +//from base of atom/CtrlClickOn(): (/mob) +#define COMSIG_CLICK_CTRL "ctrl_click" +//from base of atom/AltClick(): (/mob) +#define COMSIG_CLICK_ALT "alt_click" +//from base of atom/CtrlShiftClick(/mob) +#define COMSIG_CLICK_CTRL_SHIFT "ctrl_shift_click" +///from base of atom/CtrlShiftRightClick(/mob) +#define COMSIG_CLICK_CTRL_SHIFT_RIGHT "ctrl_shift_right_click" +//from base of atom/MouseDrop(): (/atom/over, /mob/user) +#define COMSIG_MOUSEDROP_ONTO "mousedrop_onto" #define COMPONENT_NO_MOUSEDROP 1 -#define COMSIG_MOUSEDROPPED_ONTO "mousedropped_onto" //from base of atom/MouseDrop_T: (/atom/from, /mob/user) +//from base of atom/MouseDrop_T: (/atom/from, /mob/user) +#define COMSIG_MOUSEDROPPED_ONTO "mousedropped_onto" ///from base of area/proc/power_change(): () #define COMSIG_AREA_POWER_CHANGE "area_power_change" diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index ad9d5ae5abc8..f0b505114646 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -335,7 +335,7 @@ #define SHADOW_SPECIES_LIGHT_THRESHOLD 0.2 //MINOR TWEAKS/MISC -#define AGE_MIN 17 //youngest a character can be +#define AGE_MIN 18 //youngest a character can be #define AGE_MAX 85 //oldest a character can be #define AGE_MINOR 20 //legal age of space drinking and smoking #define WIZARD_AGE_MIN 30 //youngest a wizard can be diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm index 376e023940de..28e2464aa8a9 100644 --- a/code/__HELPERS/_lists.dm +++ b/code/__HELPERS/_lists.dm @@ -24,7 +24,7 @@ #define LAZYCLEARLIST(L) if(L) L.Cut() #define SANITIZE_LIST(L) (islist(L) ? L : list()) #define reverseList(L) reverseRange(L.Copy()) -#define LAZYADDASSOC(L, K, V) if(!L) { L = list(); } L[K] += list(V); +#define LAZYADDASSOC(L, K, V) if(!L) { L = list(); } L[K] += V; #define LAZYADDASSOCLIST(L, K, V) if(!L) { L = list(); } L[K] += list(V); #define LAZYREMOVEASSOC(L, K, V) if(L) { if(L[K]) { L[K] -= V; if(!length(L[K])) L -= K; } if(!length(L)) L = null; } #define LAZYACCESSASSOC(L, I, K) L ? L[I] ? L[I][K] ? L[I][K] : null : null : null diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index fdeadc13b61a..8437730c3844 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -217,6 +217,12 @@ GLOBAL_LIST_INIT(skin_tones, sortList(list( "african2" ))) +/proc/pick_species_adjective(mob/living/carbon/human/H) + if(isipc(H)) + return pick(GLOB.ipc_preference_adjectives) + else + return pick(GLOB.preference_adjectives) + GLOBAL_LIST_EMPTY(species_list) /proc/age2agedescription(age) diff --git a/code/_globalvars/lists/names.dm b/code/_globalvars/lists/names.dm index ecc1acb6f0e1..ff452072fbec 100644 --- a/code/_globalvars/lists/names.dm +++ b/code/_globalvars/lists/names.dm @@ -27,6 +27,8 @@ GLOBAL_LIST_INIT(verbs, world.file2list("strings/names/verbs.txt")) GLOBAL_LIST_INIT(ing_verbs, world.file2list("strings/names/ing_verbs.txt")) GLOBAL_LIST_INIT(adverbs, world.file2list("strings/names/adverbs.txt")) GLOBAL_LIST_INIT(adjectives, world.file2list("strings/names/adjectives.txt")) +GLOBAL_LIST_INIT(preference_adjectives, world.file2list("strings/preference_adjectives.txt")) +GLOBAL_LIST_INIT(ipc_preference_adjectives, world.file2list("strings/ipc_preference_adjectives.txt")) GLOBAL_LIST_INIT(dream_strings, world.file2list("strings/dreamstrings.txt")) //loaded on startup because of " //would include in rsc if ' was used diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 81ce3ceec1eb..993026c0d5e0 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -356,7 +356,6 @@ /** * Control+Shift click - * Unused except for AI */ /mob/proc/CtrlShiftClickOn(atom/A) A.CtrlShiftClick(src) diff --git a/code/controllers/subsystem/pai.dm b/code/controllers/subsystem/pai.dm index 7c2bf71cad6a..b7ef35e63663 100644 --- a/code/controllers/subsystem/pai.dm +++ b/code/controllers/subsystem/pai.dm @@ -146,7 +146,7 @@ SUBSYSTEM_DEF(pai) continue if(!(ROLE_PAI in G.client.prefs.be_special)) continue - to_chat(G, "[user] is requesting a pAI personality! Use the pAI button to submit yourself as one.") + to_chat(G, "[user.real_name] is requesting a pAI personality! Use the pAI button to submit yourself as one.") addtimer(CALLBACK(src, PROC_REF(spam_again)), spam_delay) var/list/available = list() for(var/datum/paiCandidate/c in SSpai.candidates) diff --git a/code/datums/chatmessage.dm b/code/datums/chatmessage.dm index c27e0bd1b7ae..60b4db1d1ce9 100644 --- a/code/datums/chatmessage.dm +++ b/code/datums/chatmessage.dm @@ -182,7 +182,7 @@ message.maptext = complete_text // View the message - LAZYADDASSOC(owned_by.seen_messages, message_loc, src) + LAZYADDASSOCLIST(owned_by.seen_messages, message_loc, src) owned_by.images |= message animate(message, alpha = 255, time = CHAT_MESSAGE_SPAWN_TIME) diff --git a/code/datums/guestbook.dm b/code/datums/guestbook.dm new file mode 100644 index 000000000000..99104f09d715 --- /dev/null +++ b/code/datums/guestbook.dm @@ -0,0 +1,148 @@ +/** + * THE GUESTBOOK DATUM // ripped straight from mojave. + * + * Essentially, this datum handles the people that a given human knows, + * to handle getting the correct names on examine and saycode. + */ +/datum/guestbook + /// Associative list of known guests, real_name = known_name + var/list/known_names + +/datum/guestbook/Destroy(force) + known_names = null + return ..() + +/datum/guestbook/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Guestbook", "[user.real_name]'s Guestbook") + ui.set_autoupdate(FALSE) + ui.open() + +/datum/guestbook/ui_state(mob/user) + return GLOB.always_state + +/datum/guestbook/ui_data(mob/user) + var/list/data = list() + var/list/names = list() + for(var/real_name in known_names) + var/given_name = LAZYACCESS(known_names, real_name) + names += list(list("real_name" = real_name, "given_name" = given_name)) + data["names"] = names + return data + +/datum/guestbook/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return . + switch(action) + if("rename_guest") + var/real_name = params["real_name"] + var/new_name = params["new_name"] + new_name = reject_bad_name(new_name, max_length = 42) + if(!new_name) + to_chat(usr, span_warning("That's a pretty terrible name. You can do better.")) + return FALSE + if(!rename_guest(usr, null, real_name, new_name, silent = FALSE)) + return FALSE + return TRUE + if("delete_guest") + var/real_name = params["real_name"] + if(!remove_guest(usr, null, real_name, silent = FALSE)) + return FALSE + return TRUE + +/datum/guestbook/proc/try_add_guest(mob/user, mob/living/carbon/human/guest, silent = FALSE) + if(user == guest) + if(!silent) + to_chat(user, span_warning("That's you! You already know yourself plenty.")) + return FALSE + if(!visibility_checks(user, guest, silent)) + return FALSE + var/given_name = input(user, "What name do you want to give to [guest]?", "Guestbook Name", guest.get_visible_name()) + if(!given_name) + if(!silent) + to_chat(user, span_warning("Nevermind.")) + return FALSE + given_name = reject_bad_name(given_name) + if(!given_name) + if(!silent) + to_chat(user, span_warning("That's a pretty terrible name. You can do better.")) + return FALSE + if(!visibility_checks(user, guest, silent)) + return FALSE + var/face_name = guest.get_face_name("ForgetMeNot") + if(LAZYACCESS(known_names, face_name)) + if(!rename_guest(user, guest, face_name, given_name, silent)) + return FALSE + else + if(!add_guest(user, guest, face_name, given_name, silent)) + return FALSE + return TRUE + +/datum/guestbook/proc/add_guest(mob/user, mob/living/carbon/guest, real_name, given_name, silent = TRUE) + //Already exists, should be handled by rename_guest() + var/existing_name = LAZYACCESS(known_names, real_name) + if(existing_name) + if(!silent) + to_chat(user, span_warning("You already know them as \"[existing_name]\".")) + return FALSE + LAZYADDASSOC(known_names, real_name, given_name) + if(!silent) + to_chat(user, span_notice("You memorize the face of [guest] as \"[given_name]\".")) + return TRUE + +/datum/guestbook/proc/rename_guest(mob/user, mob/living/carbon/guest, real_name, given_name, silent = TRUE) + var/old_name = LAZYACCESS(known_names, real_name) + if(!old_name) + return FALSE + known_names[real_name] = given_name + if(!silent) + to_chat(user, span_notice("You re-memorize the face of \"[old_name]\" as \"[given_name]\".")) + return TRUE + +/datum/guestbook/proc/try_remove_guest(mob/user, mob/living/carbon/human/guest, silent = FALSE) + if(user == guest) + if(!silent) + to_chat(user, span_warning("That's you! You'll never forget yourself.")) + return + if(!visibility_checks(user, guest, silent)) + return FALSE + var/face_name = guest.get_face_name("ForgetMeNot") + if(!remove_guest(user, guest, face_name, silent)) + return FALSE + return TRUE + +/datum/guestbook/proc/remove_guest(mob/user, mob/living/carbon/guest, real_name, silent = TRUE) + //Already exists, should be handled by rename_guest() + var/existing_name = LAZYACCESS(known_names, real_name) + if(!existing_name) + if(!silent) + to_chat(user, span_warning("You don't know them in the first place.")) + return FALSE + LAZYREMOVE(known_names, real_name) + if(!silent) + to_chat(user, span_notice("You forget the face of \"[existing_name]\".")) + return TRUE + +/datum/guestbook/proc/get_known_name(mob/user, mob/living/carbon/guest, real_name) + if(user == guest || isAdminObserver(user)) + return real_name + return LAZYACCESS(known_names, real_name) + +/datum/guestbook/proc/visibility_checks(mob/user, mob/living/carbon/human/guest, silent = FALSE) + if(QDELETED(guest)) + if(!silent) + to_chat(user, span_warning("What?")) + return FALSE + var/visible_name = guest.get_visible_name("") + var/face_name = guest.get_face_name("") + if(!visible_name || !face_name) + if(!silent) + to_chat(user, span_warning("You can't see their face very well!")) + return FALSE + if(get_dist(user, guest) > 4) + if(!silent) + to_chat(user, span_warning("You need to take a closer look at them!")) + return FALSE + return TRUE diff --git a/code/datums/mind.dm b/code/datums/mind.dm index fc91d2c71de1..36ec4a1b5ae6 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -79,6 +79,9 @@ /// The index for our current scar slot, so we don't have to constantly check the savefile (unlike the slots themselves, this index is independent of selected char slot, and increments whenever a valid char is joined with) var/current_scar_slot_index + /// Guestbook datum, in case we actually make use of the guestbook mechanics + var/datum/guestbook/guestbook + ///Skill multiplier, adjusts how much xp you get/loose from adjust_xp. Dont override it directly, add your reason to experience_multiplier_reasons and use that as a key to put your value in there. var/experience_multiplier = 1 ///Skill multiplier list, just slap your multiplier change onto this with the type it is coming from as key. @@ -95,6 +98,7 @@ key = _key soulOwner = src martial_art = default_martial_art + guestbook = new() init_known_skills() /datum/mind/Destroy() @@ -102,6 +106,7 @@ if(islist(antag_datums)) QDEL_LIST(antag_datums) QDEL_NULL(language_holder) + QDEL_NULL(guestbook) set_current(null) soulOwner = null return ..() diff --git a/code/datums/progressbar.dm b/code/datums/progressbar.dm index 5ffa3778edc6..25621a613eeb 100644 --- a/code/datums/progressbar.dm +++ b/code/datums/progressbar.dm @@ -37,7 +37,7 @@ bar.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA user = User - LAZYADDASSOC(user.progressbars, bar_loc, src) + LAZYADDASSOCLIST(user.progressbars, bar_loc, src) var/list/bars = user.progressbars[bar_loc] listindex = bars.len diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 8299d389fb18..0c4cdb31c9be 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -1674,7 +1674,11 @@ active_hud.screentip_text.maptext = "" else //We inline a MAPTEXT() here, because there's no good way to statically add to a string like this - active_hud.screentip_text.maptext = "[name]" + active_hud.screentip_text.maptext = "[get_screentip_name(client)]" + +/// Returns the atom name that should be used on screentip +/atom/proc/get_screentip_name(client/hovering_client) + return name ///Called whenever a player is spawned on the same turf as this atom. /atom/proc/join_player_here(mob/M) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 7dd3d612ae81..989db20efd1f 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -560,7 +560,7 @@ if(!client) return if(new_virtual_z) - LAZYADDASSOC(SSmobs.players_by_virtual_z, "[new_virtual_z]", src) + LAZYADDASSOCLIST(SSmobs.players_by_virtual_z, "[new_virtual_z]", src) SSidlenpcpool.try_wakeup_virtual_z(new_virtual_z) /mob/dead/on_virtual_z_change(new_virtual_z, previous_virtual_z) @@ -570,7 +570,7 @@ if(!client) return if(new_virtual_z) - LAZYADDASSOC(SSmobs.dead_players_by_virtual_z, "[new_virtual_z]", src) + LAZYADDASSOCLIST(SSmobs.dead_players_by_virtual_z, "[new_virtual_z]", src) // Make sure you know what you're doing if you call this, this is intended to only be called by byond directly. // You probably want CanPass() diff --git a/code/game/machinery/navbeacon.dm b/code/game/machinery/navbeacon.dm index a847b44d39a1..b54c192f4407 100644 --- a/code/game/machinery/navbeacon.dm +++ b/code/game/machinery/navbeacon.dm @@ -49,7 +49,7 @@ if(previous_virtual_z) LAZYREMOVEASSOC(GLOB.navbeacons, "[previous_virtual_z]", src) if(new_virtual_z) - LAZYADDASSOC(GLOB.navbeacons, "[new_virtual_z]", src) + LAZYADDASSOCLIST(GLOB.navbeacons, "[new_virtual_z]", src) ..() // set the transponder codes assoc list from codes_txt diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm index b08d7bf6737c..078c435bd213 100644 --- a/code/game/objects/effects/landmarks.dm +++ b/code/game/objects/effects/landmarks.dm @@ -45,7 +45,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark) . = ..() GLOB.start_landmarks_list += src if(jobspawn_override) - LAZYADDASSOC(GLOB.jobspawn_overrides, name, src) + LAZYADDASSOCLIST(GLOB.jobspawn_overrides, name, src) if(name != "start") tag = "start*[name]" diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm index 630759c85afe..2e93b662799a 100644 --- a/code/game/objects/items/cards_ids.dm +++ b/code/game/objects/items/cards_ids.dm @@ -140,8 +140,8 @@ playsound(src, 'sound/items/bikehorn.ogg', 50, TRUE) /obj/item/card/id - name = "identification card" - desc = "A card used to provide ID and determine access across the station." + name = "access card" + desc = "These cards provide access to different sections of a ship." icon_state = "id" item_state = "card-id" lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi' @@ -159,7 +159,7 @@ var/obj/machinery/paystand/my_store var/uses_overlays = TRUE var/icon/cached_flat_icon - var/registered_age = 13 // default age for ss13 players + var/registered_age = 18 // default age for ss13 players var/job_icon var/faction_icon @@ -180,10 +180,7 @@ /obj/item/card/id/attack_self(mob/user) if(Adjacent(user)) - var/minor - if(registered_name && registered_age && registered_age < AGE_MINOR) - minor = " (MINOR)" - user.visible_message("[user] shows you: [icon2html(src, viewers(user))] [src.name][minor].", "You show \the [src.name][minor].") + user.visible_message("[user] shows you: [icon2html(src, viewers(user))] \the [initial(name)] [(!registered_name) ? "(" : "([registered_name]"][(!assignment) ? ")" : ", [assignment])"].", "You show \the [initial(name)] [(!registered_name) ? "(" : "([registered_name],"] [(!assignment) ? ")" : "[assignment])"].") add_fingerprint(user) /obj/item/card/id/vv_edit_var(var_name, var_value) @@ -324,12 +321,14 @@ /obj/item/card/id/examine(mob/user) . = ..() if(registered_account) - . += "The account linked to the ID belongs to '[registered_account.account_holder]' and reports a balance of [registered_account.account_balance] cr." + . += "The account linked to the card belongs to '[registered_account.account_holder]' and reports a balance of [registered_account.account_balance] cr." . += "There's more information below, you can look again to take a closer look..." /obj/item/card/id/examine_more(mob/user) var/list/msg = list("You examine [src] closer, and note the following...") + if(registered_name) + msg += "This access card is assigned to [registered_name]." if(registered_age) msg += "The card indicates that the holder is [registered_age] years old. [(registered_age < AGE_MINOR) ? "There's a holographic stripe that reads 'MINOR: DO NOT SERVE ALCOHOL OR TOBACCO' along the bottom of the card." : ""]" if(mining_points) @@ -407,16 +406,14 @@ /* Usage: update_label() - Sets the id name to whatever registered_name and assignment is + Sets the id name to whatever the assignment is */ /obj/item/card/id/proc/update_label() - var/blank = !registered_name - name = "[blank ? initial(name) : "[registered_name]'s ID Card"][(!assignment) ? "" : " ([assignment])"]" + name = "[(istype(src, /obj/item/card/id/syndicate)) ? "[initial(name)]" : "access card"][(!assignment) ? "" : " ([assignment])"]" /obj/item/card/id/silver - name = "silver identification card" - desc = "A silver card which shows honour and dedication." + desc = "A silver-colored card, usually given to higher-ranking officials in ships and stations." icon_state = "silver" item_state = "silver_id" lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi' @@ -428,8 +425,7 @@ update_label() access = list(ACCESS_CHANGE_IDS) /obj/item/card/id/gold - name = "gold identification card" - desc = "A golden card which shows power and might." + desc = "A golden-colored card, usually given to those at the top of the hierarchy in a ship." icon_state = "gold" item_state = "gold_id" lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi' @@ -532,10 +528,7 @@ update_label() access = list(ACCESS_MAINT_TUNNELS, ACCESS_SYNDICATE, ACCESS_SYNDICATE_LEADER) /obj/item/card/id/syndicate_command - name = "syndicate ID card" - desc = "An ID straight from the Syndicate." - registered_name = "Syndicate" - assignment = "Syndicate Overlord" + desc = "An access card widely utilized by Coalition splinters in the frontier." icon_state = "syndie" access = list(ACCESS_SYNDICATE) uses_overlays = FALSE @@ -569,15 +562,12 @@ update_label() /obj/item/card/id/patient //Aegis ID assignment = "Long Term Patient" uses_overlays = FALSE - access = list(ACCESS_SYNDICATE) /obj/item/card/id/captains_spare - desc = "The spare ID of the High Lord himself." icon_state = "gold" item_state = "gold_id" lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi' - registered_name = "Captain" assignment = "Captain" registered_age = null @@ -596,11 +586,9 @@ update_label() ..() /obj/item/card/id/centcom - name = "\improper CentCom ID" - desc = "An ID straight from Central Command." + name = "\improper Nanotrasen Central Command access card" + desc = "An access card sourced from Nanotrasen's Central Command." icon_state = "centcom" - registered_name = "Central Command" - assignment = "Central Command" uses_overlays = FALSE registered_age = null @@ -615,8 +603,6 @@ update_label() name = "\improper CentCom ID" desc = "An ERT ID card." icon_state = "ert_commander" - registered_name = "Emergency Response Team Commander" - assignment = "Emergency Response Team Commander" uses_overlays = FALSE registered_age = null @@ -625,8 +611,6 @@ update_label() . = ..() /obj/item/card/id/ert/security - registered_name = "Security Response Officer" - assignment = "Security Response Officer" icon_state = "ert_security" /obj/item/card/id/ert/security/Initialize() @@ -634,8 +618,6 @@ update_label() . = ..() /obj/item/card/id/ert/engineer - registered_name = "Engineering Response Officer" - assignment = "Engineering Response Officer" icon_state = "ert_engineer" /obj/item/card/id/ert/engineer/Initialize() @@ -643,8 +625,6 @@ update_label() . = ..() /obj/item/card/id/ert/medical - registered_name = "Medical Response Officer" - assignment = "Medical Response Officer" icon_state = "ert_medic" /obj/item/card/id/ert/medical/Initialize() @@ -652,8 +632,6 @@ update_label() . = ..() /obj/item/card/id/ert/chaplain - registered_name = "Religious Response Officer" - assignment = "Religious Response Officer" icon_state = "ert_chaplain" /obj/item/card/id/ert/chaplain/Initialize() @@ -661,8 +639,6 @@ update_label() . = ..() /obj/item/card/id/ert/janitor - registered_name = "Janitorial Response Officer" - assignment = "Janitorial Response Officer" icon_state = "ert_janitor" /obj/item/card/id/ert/janitor/Initialize() @@ -670,8 +646,6 @@ update_label() . = ..() /obj/item/card/id/ert/clown - registered_name = "Entertainment Response Officer" - assignment = "Entertainment Response Officer" icon_state = "ert_clown" /obj/item/card/id/ert/clown/Initialize() @@ -679,12 +653,10 @@ update_label() . = ..() /obj/item/card/id/ert/deathsquad - name = "\improper Death Squad ID" - desc = "A Death Squad ID card." + desc = "An access card colored in black and red." icon_state = "deathsquad" //NO NO SIR DEATH SQUADS ARENT A PART OF NANOTRASEN AT ALL - registered_name = "Death Commando" - assignment = "Death Commando" uses_overlays = FALSE + job_icon = "deathsquad" /obj/item/card/id/debug name = "\improper Debug ID" diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 00c619da8353..361358892520 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -1404,7 +1404,7 @@ say(message, language) return NOPASS -/obj/item/toy/dummy/GetVoice() +/obj/item/toy/dummy/GetVoice(if_no_voice = "Unknown") return doll_name /obj/item/toy/seashell diff --git a/code/game/say.dm b/code/game/say.dm index c3c8dca852f8..2d53eea65e75 100644 --- a/code/game/say.dm +++ b/code/game/say.dm @@ -52,10 +52,28 @@ GLOBAL_LIST_INIT(freqcolor, list()) //Radio freq/name display var/freqpart = radio_freq ? "\[[get_radio_name(radio_freq)]\] " : "" //Speaker name - var/namepart = "[speaker.GetVoice()][speaker.get_alt_name()]" - if(face_name && ishuman(speaker)) - var/mob/living/carbon/human/H = speaker - namepart = "[H.get_face_name()]" //So "fake" speaking like in hallucinations does not give the speaker away if disguised + + var/namepart = speaker.GetVoice() + var/atom/movable/reliable_narrator = speaker + if(istype(speaker, /atom/movable/virtualspeaker)) //ugh + var/atom/movable/virtualspeaker/fakespeaker = speaker + reliable_narrator = fakespeaker.source + if(ishuman(reliable_narrator)) + //So "fake" speaking like in hallucinations does not give the speaker away if disguised + if(face_name) + var/mob/living/carbon/human/human_narrator = reliable_narrator + namepart = human_narrator.name + //otherwise, do guestbook handling + else if(ismob(src)) + var/mob/mob_source = src + if(mob_source.mind?.guestbook) + var/known_name = mob_source.mind.guestbook.get_known_name(src, reliable_narrator, namepart) + if(known_name) + namepart = "[known_name]" + else + var/mob/living/carbon/human/human_narrator = reliable_narrator + namepart = "[human_narrator.get_generic_name(prefixed = TRUE, lowercase = FALSE)]" + //End name span. var/endspanpart = "" @@ -67,9 +85,9 @@ GLOBAL_LIST_INIT(freqcolor, list()) else messagepart = lang_treat(speaker, message_language, raw_message, spans, message_mods) - var/datum/language/D = GLOB.language_datum_instances[message_language] - if(istype(D) && D.display_icon(src)) - languageicon = "[D.get_icon()] " + var/datum/language/language = GLOB.language_datum_instances[message_language] + if(istype(language) && language.display_icon(src)) + languageicon = "[language.get_icon()] " messagepart = " [say_emphasis(messagepart)]" @@ -177,7 +195,7 @@ GLOBAL_LIST_INIT(freqcolor, list()) return "2" return "0" -/atom/movable/proc/GetVoice() +/atom/movable/proc/GetVoice(if_no_voice = "Unknown") return "[src]" //Returns the atom's name, prepended with 'The' if it's not a proper noun /atom/movable/proc/IsVocal() diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 82cb857576c1..5bb4b25cc1f1 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -39,7 +39,7 @@ return var/body = "Options for [M.key]" - body += "Options panel for [M]" + body += "Options panel for [M.real_name]" if(M.client) body += " played by [M.client] " body += "[M.client.holder ? M.client.holder.rank : "Player"]" diff --git a/code/modules/admin/create_mob.dm b/code/modules/admin/create_mob.dm index c1845945485f..7d5dfccf2804 100644 --- a/code/modules/admin/create_mob.dm +++ b/code/modules/admin/create_mob.dm @@ -23,6 +23,7 @@ H.facial_hair_color = H.hair_color H.eye_color = random_eye_color() H.dna.blood_type = random_blood_type() + H.generic_adjective = pick_species_adjective(H) // Mutant randomizing, doesn't affect the mob appearance unless it's the specific mutant. H.dna.features["mcolor"] = random_short_color() diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm index ac05c3afdd4f..dff0335b7e9e 100644 --- a/code/modules/admin/verbs/one_click_antag.dm +++ b/code/modules/admin/verbs/one_click_antag.dm @@ -493,6 +493,16 @@ teamSpawned++ if(teamSpawned) + // guestbook + for(var/datum/mind/member in ert_team.members) + var/member_mob = member.current + for(var/datum/mind/other_member in ert_team.members) + // skip yourself + if(other_member.name == member.name) + continue + var/mob/living/carbon/human/other_member_mob = other_member.current + member.guestbook.add_guest(member_mob, other_member_mob, other_member_mob.real_name, other_member_mob.real_name, TRUE) + message_admins("[ertemplate.rename_team] has spawned with the mission: [ertemplate.mission]") //Open the Armory doors diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index ebf32c163d89..901200f69928 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -158,7 +158,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/list/custom_names = list() var/preferred_ai_core_display = "Blue" var/prefered_security_department = SEC_DEPT_RANDOM - + var/generic_adjective = "Unremarkable" //Quirk list var/list/all_quirks = list() @@ -847,6 +847,11 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "[features["body_size"]]
    " + + dat += "

    Character Adjective

    " + + dat += "[generic_adjective]
    " + mutant_category++ if(mutant_category >= MAX_MUTANT_ROWS) dat += "" @@ -2074,6 +2079,15 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(phobiaType) phobia = phobiaType + if("generic_adjective") + var/selectAdj + if(istype(pref_species, /datum/species/ipc)) + selectAdj = input(user, "In one word, how would you describe your character's appereance?", "Character Preference", generic_adjective) as null|anything in GLOB.ipc_preference_adjectives + else + selectAdj = input(user, "In one word, how would you describe your character's appereance?", "Character Preference", generic_adjective) as null|anything in GLOB.preference_adjectives + if(selectAdj) + generic_adjective = selectAdj + if ("max_chat_length") var/desiredlength = input(user, "Choose the max character length of shown Runechat messages. Valid range is 1 to [CHAT_MESSAGE_MAX_LENGTH] (default: [initial(max_chat_length)]))", "Character Preference", max_chat_length) as null|num if (!isnull(desiredlength)) @@ -2473,6 +2487,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) character.set_species(chosen_species, icon_update = FALSE, pref_load = TRUE) //Because of how set_species replaces all bodyparts with new ones, hair needs to be set AFTER species. character.dna.real_name = character.real_name + character.generic_adjective = generic_adjective character.hair_color = hair_color character.facial_hair_color = facial_hair_color character.grad_color = features["grad_color"] diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 0b95e291b794..cce6b66ac612 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -405,6 +405,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car READ_FILE(S["jumpsuit_style"], jumpsuit_style) READ_FILE(S["uplink_loc"], uplink_spawn_loc) READ_FILE(S["phobia"], phobia) + READ_FILE(S["generic_adjective"], generic_adjective) READ_FILE(S["randomise"], randomise) READ_FILE(S["body_size"], features["body_size"]) READ_FILE(S["prosthetic_limbs"], prosthetic_limbs) @@ -594,6 +595,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["randomise"] , randomise) WRITE_FILE(S["species"] , pref_species.id) WRITE_FILE(S["phobia"] , phobia) + WRITE_FILE(S["generic_adjective"] , generic_adjective) WRITE_FILE(S["body_size"] , features["body_size"]) WRITE_FILE(S["prosthetic_limbs"] , prosthetic_limbs) WRITE_FILE(S["feature_mcolor"] , features["mcolor"]) diff --git a/code/modules/client/verbs/looc.dm b/code/modules/client/verbs/looc.dm index 47d4e0e82aec..1c66a077a065 100644 --- a/code/modules/client/verbs/looc.dm +++ b/code/modules/client/verbs/looc.dm @@ -59,32 +59,33 @@ GLOBAL_VAR_INIT(normal_looc_colour, "#6699CC") mob.log_talk(raw_msg, LOG_LOOC, tag = "(LOOC)") - var/list/heard = get_hearers_in_view(7, get_top_level_mob(src.mob)) - for(var/mob/M in heard) - if(!M.client) + var/list/heard = get_hearers_in_view(7, get_top_level_mob(mob)) + for(var/mob/hearer_mob in heard) + var/client/hearer = hearer_mob.client + + if(!hearer) continue - var/client/C = M.client - if(key in C.prefs.ignoring) + if(key in hearer.prefs.ignoring) continue - if(holder?.fakekey in C.prefs.ignoring) + if(holder?.fakekey in hearer.prefs.ignoring) continue - if(!(C.prefs.chat_toggles & CHAT_LOOC)) + if(!(hearer.prefs.chat_toggles & CHAT_LOOC)) continue //Handled before admins so that they see this if they're in range anyways - if(C.prefs.chat_on_map && mob.invisibility <= M.see_invisible) - M.create_chat_message(mob, null, "\[LOOC: [raw_msg]\]", null, LOOC_MESSAGE) + if(hearer.prefs.chat_on_map && mob.invisibility <= hearer_mob.see_invisible) + hearer_mob.create_chat_message(mob, null, "\[LOOC: [raw_msg]\]", null, LOOC_MESSAGE) - if(C in GLOB.admins) + if(hearer in GLOB.admins) continue //handled in the next loop if(GLOB.LOOC_COLOR) - to_chat(C, "LOOC: [src.mob.name]: [msg]", MESSAGE_TYPE_LOOC) + to_chat(hearer, "LOOC: [mob.get_screentip_name(hearer)]: [msg]", MESSAGE_TYPE_LOOC) else - to_chat(C, "LOOC: [src.mob.name]: [msg]", MESSAGE_TYPE_LOOC) + to_chat(hearer, "LOOC: [mob.get_screentip_name(hearer)]: [msg]", MESSAGE_TYPE_LOOC) for(var/client/C in GLOB.admins) if(key in C.prefs.ignoring) @@ -100,9 +101,9 @@ GLOBAL_VAR_INIT(normal_looc_colour, "#6699CC") if (C.mob in heard) prefix = "LOOC" if(GLOB.LOOC_COLOR) - to_chat(C, "[ADMIN_FLW(usr)] [prefix]: [src.key]/[src.mob.name]: [msg]", MESSAGE_TYPE_LOOC) + to_chat(C, "[ADMIN_FLW(usr)] [prefix]: [key]/[mob.real_name]: [msg]", MESSAGE_TYPE_LOOC) else - to_chat(C, "[ADMIN_FLW(usr)] [prefix]: [src.key]/[src.mob.name]: [msg]", MESSAGE_TYPE_LOOC) + to_chat(C, "[ADMIN_FLW(usr)] [prefix]: [key]/[mob.real_name]: [msg]", MESSAGE_TYPE_LOOC) /proc/toggle_looc(toggle = null) if(toggle == null) diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index 203bcf416b13..f5c37b18997d 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -150,7 +150,7 @@ card.assignment = J.name card.update_appearance() card.assignment = old_assignment - card.update_label() + card.name = "[(istype(src, /obj/item/card/id/syndicate)) ? "[initial(name)]" : "access card"][(!old_assignment) ? "" : " ([old_assignment])"]" H.sec_hud_set_ID() qdel(outfit) diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm index ee0d7789355e..20ad6e089730 100644 --- a/code/modules/jobs/job_types/_job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -25,7 +25,6 @@ var/display_order = JOB_DISPLAY_ORDER_DEFAULT - ///Levels unlocked at roundstart in physiology var/list/roundstart_experience diff --git a/code/modules/mob/dead/dead.dm b/code/modules/mob/dead/dead.dm index 5a1e5bbf3387..85c60a15b031 100644 --- a/code/modules/mob/dead/dead.dm +++ b/code/modules/mob/dead/dead.dm @@ -107,7 +107,7 @@ INITIALIZE_IMMEDIATE(/mob/dead) . = ..() if(!client) return - LAZYADDASSOC(SSmobs.dead_players_by_virtual_z, "[virtual_z()]", src) + LAZYADDASSOCLIST(SSmobs.dead_players_by_virtual_z, "[virtual_z()]", src) /mob/dead/Logout() . = ..() diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index 9baa46f526b5..5ccba743bb1b 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -249,8 +249,8 @@ observer.client.init_verbs() observer.update_appearance() observer.stop_sound_channel(CHANNEL_LOBBYMUSIC) - deadchat_broadcast(" has observed.", "[observer.real_name]", follow_target = observer, turf_target = get_turf(observer), message_type = DEADCHAT_DEATHRATTLE) QDEL_NULL(mind) + deadchat_broadcast(" has observed.", "[observer.real_name]", follow_target = observer, turf_target = get_turf(observer), message_type = DEADCHAT_DEATHRATTLE) qdel(src) return TRUE @@ -329,6 +329,7 @@ var/mob/living/carbon/human/humanc = character ship.manifest_inject(humanc, client, job) GLOB.data_core.manifest_inject(humanc, client) + ship.add_mob_to_crew_guestbook(humanc) AnnounceArrival(humanc, job.name, ship) AddEmploymentContract(humanc) SSblackbox.record_feedback("tally", "species_spawned", 1, humanc.dna.species.name) diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index b024be2f96f7..59f97d172ad1 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -8,7 +8,6 @@ var/t_has = p_have() var/t_is = p_are() var/obscure_name - var/list/obscured = check_obscured_slots() var/skipface = ((wear_mask?.flags_inv & HIDEFACE) || (head?.flags_inv & HIDEFACE)) @@ -16,10 +15,25 @@ var/mob/living/L = user if(HAS_TRAIT(L, TRAIT_PROSOPAGNOSIA)) obscure_name = TRUE - var/apparent_species - if(dna?.species && !skipface) - apparent_species = ", \an [dna.species.name]" - . = list("This is [!obscure_name ? name : "Unknown"][apparent_species]!") + + . = list(span_info("This is [name]!")) + + if(user != src) + if(!obscure_name && !skipface) + var/face_name = get_face_name("") + if(face_name) + //if we have no guestbook, we just KNOW okay? + var/known_name = user.mind?.guestbook ? user.mind.guestbook.get_known_name(user, src, face_name) : face_name + if(known_name) + . += "You know them as [known_name]." + else + . += "You don't recognize [t_him]. You can Ctrl-Shift click [t_him] to memorize their face." + else + . += "You can't see [t_his] face very well." + else + . += "You can't see [t_his] face very well." + else + . += "It's you, [real_name]." //uniform if(w_uniform && !(ITEM_SLOT_ICLOTHING in obscured)) @@ -402,18 +416,4 @@ . = ..() if ((wear_mask && (wear_mask.flags_inv & HIDEFACE)) || (head && (head.flags_inv & HIDEFACE))) return - var/age_text - switch(age) - if(-INFINITY to 25) - age_text = "very young" - if(26 to 35) - age_text = "of adult age" - if(36 to 55) - age_text = "middle-aged" - if(56 to 75) - age_text = "rather old" - if(76 to 100) - age_text = "very old" - if(101 to INFINITY) - age_text = "withering away" - . += list(span_notice("[p_they(TRUE)] appear[p_s()] to be [age_text].")) + . += list(span_notice("[p_they(TRUE)] appear[p_s()] to be [get_age()].")) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 9ae7034366dc..ecad7982b83a 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1264,6 +1264,23 @@ return FALSE return ..() +/mob/living/carbon/human/CtrlShiftClick(mob/user) + . = ..() + if(isobserver(user) || !user.mind?.guestbook) + return + INVOKE_ASYNC(user.mind.guestbook, TYPE_PROC_REF(/datum/guestbook, try_add_guest), user, src, FALSE) + +/mob/living/carbon/human/get_screentip_name(client/hovering_client) + . = ..() + var/mob/hovering_mob = hovering_client?.mob + if(!hovering_mob?.mind?.guestbook) + return . + var/face_name = get_face_name("") + var/known_name = hovering_mob.mind.guestbook.get_known_name(hovering_mob, src, face_name) + if(known_name) + return known_name + return . + /mob/living/carbon/human/species var/race = null diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 5b638d330690..8cc9e5002749 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -61,6 +61,9 @@ var/special_voice = "" // For changing our voice. Used by a symptom. + /// Adjective used in get_generic_name(), if any + var/generic_adjective + var/bleed_rate = 0 //how much are we bleeding var/bleedsuppress = 0 //for stopping bloodloss, eventually this will be limb-based like bleeding diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index 2f9814112711..b98466301f63 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -31,28 +31,19 @@ return pda.owner return if_no_id -//repurposed proc. Now it combines get_id_name() and get_face_name() to determine a mob's name variable. Made into a separate proc as it'll be useful elsewhere /mob/living/carbon/human/get_visible_name() - var/face_name = get_face_name("") - var/id_name = get_id_name("") if(name_override) return name_override - if(face_name) - if(id_name && (id_name != face_name)) - return "[face_name] (as [id_name])" - return face_name - if(id_name) - return id_name - return "Unknown" + return get_generic_name(lowercase = TRUE) //Returns "Unknown" if facially disfigured and real_name if not. Useful for setting name when Fluacided or when updating a human's name variable -/mob/living/carbon/human/proc/get_face_name(if_no_face="Unknown") - if(wear_mask && (wear_mask.flags_inv&HIDEFACE)) //Wearing a mask which hides our face, use id-name if possible +/mob/living/carbon/human/proc/get_face_name(if_no_face = get_generic_name(lowercase = TRUE)) + if(wear_mask && (wear_mask.flags_inv & HIDEFACE)) //Wearing a mask which hides our face, use id-name if possible return if_no_face - if(head && (head.flags_inv&HIDEFACE)) - return if_no_face //Likewise for hats + if(head && (head.flags_inv & HIDEFACE)) + return if_no_face //Likewise for hats var/obj/item/bodypart/O = get_bodypart(BODY_ZONE_HEAD) - if(!O || (HAS_TRAIT(src, TRAIT_DISFIGURED)) || (O.brutestate+O.burnstate)>2 || cloneloss>50 || !real_name) //disfigured. use id-name if possible + if(!O || (HAS_TRAIT(src, TRAIT_DISFIGURED)) || (O.brutestate+O.burnstate)>2 || cloneloss>50 || !real_name) //disfigured. use id-name if possible return if_no_face return real_name @@ -181,3 +172,56 @@ destination.socks = socks destination.socks_color = socks_color destination.jumpsuit_style = jumpsuit_style + +/mob/living/carbon/human/proc/get_age() + var/obscured = check_obscured_slots() + var/skipface = (wear_mask && (wear_mask.flags_inv & HIDEFACE)) || (head && (head.flags_inv & HIDEFACE)) + if((obscured & ITEM_SLOT_ICLOTHING) && skipface || isipc(src)) + return "" + switch(age) + if(70 to INFINITY) + return "Geriatric" + if(60 to 70) + return "Elderly" + if(50 to 60) + return "Old" + if(40 to 50) + return "Middle-Aged" + if(24 to 40) + return "" //not necessary because this is basically the most common age range + if(18 to 24) + return "Young" + else + return "Puzzling" + +/mob/living/carbon/human/proc/get_generic_name(prefixed = FALSE, lowercase = FALSE) + var/obscured = check_obscured_slots() + var/skipface = (wear_mask && (wear_mask.flags_inv & HIDEFACE)) || (head && (head.flags_inv & HIDEFACE)) + var/hide_features = (obscured & ITEM_SLOT_ICLOTHING) && skipface + var/visible_adjective + if(generic_adjective && !hide_features) + visible_adjective = "[generic_adjective] " + var/visible_age = get_age() + if(visible_age) + visible_age = "[visible_age] " + var/visible_gender = get_gender() + var/final_string = "[visible_adjective][visible_age][dna.species.name] [visible_gender]" + if(prefixed) + final_string = "\A [final_string]" + return lowercase ? lowertext(final_string) : final_string + +/mob/living/carbon/human/proc/get_gender() + var/visible_gender = p_they() + switch(visible_gender) + if("he") + visible_gender = "Man" + if("she") + visible_gender = "Woman" + if("they") + if(ishuman(src)) + visible_gender = "Person" + else + visible_gender = "Creature" + else + visible_gender = "Thing" + return visible_gender diff --git a/code/modules/mob/living/carbon/human/human_say.dm b/code/modules/mob/living/carbon/human/human_say.dm index 039141bb5fd5..6b0c1ff1c768 100644 --- a/code/modules/mob/living/carbon/human/human_say.dm +++ b/code/modules/mob/living/carbon/human/human_say.dm @@ -7,16 +7,14 @@ else . = ..() -/mob/living/carbon/human/GetVoice() +/mob/living/carbon/human/GetVoice(if_no_voice = get_generic_name()) if(istype(wear_mask, /obj/item/clothing/mask/chameleon)) - var/obj/item/clothing/mask/chameleon/V = wear_mask - if(V.voice_change && wear_id) + var/obj/item/clothing/mask/chameleon/chameleon_mask = wear_mask + if(chameleon_mask.voice_change && wear_id) var/obj/item/card/id/idcard = wear_id.GetID() if(istype(idcard)) return idcard.registered_name - else - return real_name - if(istype(wear_mask, /obj/item/clothing/mask/gas/syndicate/voicechanger)) + else if(istype(wear_mask, /obj/item/clothing/mask/gas/syndicate/voicechanger)) var/obj/item/clothing/mask/gas/syndicate/voicechanger/V = wear_mask if(V.voice_change && wear_id) var/obj/item/card/id/idcard = wear_id.GetID() @@ -26,18 +24,17 @@ return real_name else return real_name - if(istype(wear_mask, /obj/item/clothing/mask/infiltrator)) - var/obj/item/clothing/mask/infiltrator/V = wear_mask - if(V.voice_unknown) - return ("Unknown") - else - return real_name + else if(istype(wear_mask, /obj/item/clothing/mask/infiltrator)) + var/obj/item/clothing/mask/infiltrator/infiltrator_mask = wear_mask + if(infiltrator_mask.voice_unknown) + return if_no_voice if(mind) var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling) if(changeling && changeling.mimicing) return changeling.mimicing - if(GetSpecialVoice()) - return GetSpecialVoice() + var/special_voice = GetSpecialVoice() + if(special_voice) + return special_voice return real_name /mob/living/carbon/human/IsVocal() diff --git a/code/modules/mob/living/carbon/human/species_types/IPC.dm b/code/modules/mob/living/carbon/human/species_types/IPC.dm index 381708757fd1..6506ee40c086 100644 --- a/code/modules/mob/living/carbon/human/species_types/IPC.dm +++ b/code/modules/mob/living/carbon/human/species_types/IPC.dm @@ -1,5 +1,5 @@ /datum/species/ipc // im fucking lazy mk2 and cant get sprites to normally work - name = "\improper Integrated Positronic Chassis" //inherited from the real species, for health scanners and things + name = "\improper Positronic" //inherited from the real species, for health scanners and things id = SPECIES_IPC sexes = FALSE species_age_min = 0 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 02ddf79f6bc4..b512dc50b2bf 100644 --- a/code/modules/mob/living/carbon/human/species_types/mothmen.dm +++ b/code/modules/mob/living/carbon/human/species_types/mothmen.dm @@ -1,5 +1,5 @@ /datum/species/moth - name = "\improper Mothman" + name = "\improper Mothperson" id = SPECIES_MOTH default_color = "00FF00" species_traits = list(LIPS, NOEYESPRITES, TRAIT_ANTENNAE, HAIR, EMOTE_OVERLAY) 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 ec9afd777f2c..d3c900c56786 100644 --- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm +++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm @@ -1,5 +1,5 @@ /datum/species/plasmaman - name = "\improper Plasmaman" + name = "\improper Phorid" id = SPECIES_PLASMAMAN sexes = 0 meat = /obj/item/stack/sheet/mineral/plasma diff --git a/code/modules/mob/living/login.dm b/code/modules/mob/living/login.dm index d59e3f77781e..62098a940937 100644 --- a/code/modules/mob/living/login.dm +++ b/code/modules/mob/living/login.dm @@ -18,7 +18,7 @@ var/virtual_z = virtual_z() - LAZYADDASSOC(SSmobs.players_by_virtual_z, "[virtual_z]", src) + LAZYADDASSOCLIST(SSmobs.players_by_virtual_z, "[virtual_z]", src) SSidlenpcpool.try_wakeup_virtual_z(virtual_z) //Vents diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index daa987904737..cfd7d9153c8d 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -1063,3 +1063,4 @@ ghostize(1) QDEL_NULL(src) + diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index e4ead25880f9..3670e14a6405 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -636,7 +636,7 @@ switch(togglestatus) if(AI_Z_OFF) - LAZYADDASSOC(SSidlenpcpool.idle_mobs_by_virtual_level, virt_z, src) + LAZYADDASSOCLIST(SSidlenpcpool.idle_mobs_by_virtual_level, virt_z, src) else LAZYREMOVEASSOC(SSidlenpcpool.idle_mobs_by_virtual_level, virt_z, src) diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm index 8eb5bc620722..d60755693489 100644 --- a/code/modules/mob/living/status_procs.dm +++ b/code/modules/mob/living/status_procs.dm @@ -478,11 +478,11 @@ for(var/listed_type in slowdown_type) if(ispath(listed_type)) listed_type = "[listed_type]" //Path2String - LAZYADDASSOC(movespeed_mod_immunities, listed_type, source) + LAZYADDASSOCLIST(movespeed_mod_immunities, listed_type, source) else if(ispath(slowdown_type)) slowdown_type = "[slowdown_type]" //Path2String - LAZYADDASSOC(movespeed_mod_immunities, slowdown_type, source) + LAZYADDASSOCLIST(movespeed_mod_immunities, slowdown_type, source) if(update) update_movespeed() diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 7e246dd2d7ac..131e3f971113 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -204,27 +204,34 @@ if(self_message) hearers -= src - var/raw_msg = message - if(visible_message_flags & EMOTE_MESSAGE) - message = "[src][separation][message]" - for(var/mob/M in hearers) if(!M.client) continue - //This entire if/else chain could be in two lines but isn't for readibilties sake. var/msg = message + + //This entire if/else chain could be in two lines but isn't for readibilties sake. if(M.see_invisible < invisibility)//if src is invisible to M msg = blind_message else if(T != loc && T != src) //if src is inside something and not a turf. msg = blind_message else if(T.lighting_object && T.lighting_object.invisibility <= M.see_invisible && T.is_softly_lit()) //if it is too dark. msg = blind_message + else if(visible_message_flags & EMOTE_MESSAGE) + var/shown_name = name + if(M.mind?.guestbook && ishuman(src)) + var/mob/living/carbon/human/human_source = src + var/known_name = M.mind.guestbook.get_known_name(M, src, human_source.get_face_name()) + if(known_name) + shown_name = known_name + + msg = "[shown_name][separation][message]" + if(!msg) continue if(visible_message_flags & EMOTE_MESSAGE && runechat_prefs_check(M, visible_message_flags)) - M.create_chat_message(src, raw_message = raw_msg, runechat_flags = visible_message_flags) + M.create_chat_message(src, raw_message = message, runechat_flags = visible_message_flags) M.show_message(msg, MSG_VISUAL, blind_message, MSG_AUDIBLE) @@ -250,12 +257,24 @@ if(self_message) hearers -= src var/raw_msg = message - if(audible_message_flags & EMOTE_MESSAGE) - message = "[src][separation][message]" for(var/mob/M in hearers) - if(audible_message_flags & EMOTE_MESSAGE && runechat_prefs_check(M, audible_message_flags)) - M.create_chat_message(src, raw_message = raw_msg, runechat_flags = audible_message_flags) - M.show_message(message, MSG_AUDIBLE, deaf_message, MSG_VISUAL) + var/msg = raw_msg + + //emote handling + if(audible_message_flags & EMOTE_MESSAGE) + var/shown_name = name + if(M.mind?.guestbook && ishuman(src)) + var/mob/living/carbon/human/human_source = src + var/known_name = M.mind.guestbook.get_known_name(M, src, human_source.GetVoice()) + if(known_name) + shown_name = known_name + + msg = "[shown_name][separation][message]" + + if(runechat_prefs_check(M, audible_message_flags) && M.can_hear()) + M.create_chat_message(src, raw_message = raw_msg, runechat_flags = audible_message_flags) + + M.show_message(msg, MSG_AUDIBLE, deaf_message, MSG_VISUAL) /** * Show a message to all mobs in earshot of this one @@ -681,6 +700,24 @@ else to_chat(src, "You don't have a mind datum for some reason, so you can't add a note to it.") +///Shows guestbook tgui window +/mob/verb/guestbook() + set name = "Guestbook" + set category = "IC" + set desc = "View your character's Guestbook." + // the reason why there are two observer checks in here is because the mind datum sometimes carries over to ghosts. + // this is something i should probably fix instead of adding a fallback check, but... + if(isobserver(src)) + to_chat(src, span_warning("You have to be in the current round to do that!")) + return + if(!mind) + var/fail_message = "You have no mind!" + if(isobserver(src)) + fail_message += " You have to be in the current round at some point to have one." + to_chat(src, span_warning(fail_message)) + return + mind.guestbook.ui_interact(usr) + /** * Allows you to respawn, abandoning your current mob * diff --git a/code/modules/overmap/ships/controlled_ship_datum.dm b/code/modules/overmap/ships/controlled_ship_datum.dm index 8174a3e365f4..b87d3efda187 100644 --- a/code/modules/overmap/ships/controlled_ship_datum.dm +++ b/code/modules/overmap/ships/controlled_ship_datum.dm @@ -307,6 +307,25 @@ job_holder_refs[human_job] = list() job_holder_refs[human_job] += WEAKREF(H) +/** + * adds a mob's real name to a crew's guestbooks + * + * * H - human mob to add to the crew's guestbooks + */ +/datum/overmap/ship/controlled/proc/add_mob_to_crew_guestbook(mob/living/carbon/human/H) + // iterate over the human list to find crewmembers + for(var/mob/living/carbon/human/crewmember as anything in GLOB.human_list) + if(crewmember == H) + continue + if(!(crewmember.real_name in manifest)) + continue + if(!crewmember.mind?.guestbook) + continue + + // add the mob to the crewmember's guestbook and viceversa + crewmember.mind.guestbook.add_guest(crewmember, H, H.real_name, H.real_name, TRUE) + H.mind.guestbook.add_guest(H, crewmember, crewmember.real_name, crewmember.real_name, TRUE) + /datum/overmap/ship/controlled/proc/set_owner_mob(mob/new_owner) if(owner_mob) // we (hopefully) don't have to hook qdeletion, diff --git a/shiptest.dme b/shiptest.dme index dd099108f6d7..7ae5b4b1121e 100644 --- a/shiptest.dme +++ b/shiptest.dme @@ -404,6 +404,7 @@ #include "code\datums\emotes.dm" #include "code\datums\ert.dm" #include "code\datums\forced_movement.dm" +#include "code\datums\guestbook.dm" #include "code\datums\holocall.dm" #include "code\datums\http.dm" #include "code\datums\hud.dm" diff --git a/strings/ipc_preference_adjectives.txt b/strings/ipc_preference_adjectives.txt new file mode 100644 index 000000000000..a243b2d77fc5 --- /dev/null +++ b/strings/ipc_preference_adjectives.txt @@ -0,0 +1,71 @@ +Bedraggled +Brawny +Bulky +Burly +Calm +Chaotic +Charming +Delicate +Dignified +Disgusting +Disturbing +Dull +Effeminate +Elegant +Energetic +Exasperated +Exotic +Faint +Feisty +Flamboyant +Fragile +Frail +Friendly +Gentle +Hawkish +Hefty +Hobbling +Hyper +Imposing +Jaded +Lax +Lean +Limp +Lithe +Lopsided +Lovely +Mangled +Masculine +Messy +Nimble +Petite +Pompous +Pugnacious +Repulsive +Robust +Rough +Rusted +Scarred +Shifty +Sickly +Skittish +Sleek +Slender +Slovenly +Sluggish +Spacy +Stiff +Stony +Stylish +Unattractive +Unremarkable +Unsightly +Verbose +Vigorous +Waifish +Wilted +Wily +Withered +Worn-Out +Zealous +Zesty diff --git a/strings/preference_adjectives.txt b/strings/preference_adjectives.txt new file mode 100644 index 000000000000..0d67f16803f8 --- /dev/null +++ b/strings/preference_adjectives.txt @@ -0,0 +1,117 @@ +Angsty +Awkward +Bedraggled +Blemished +Bony +Brawny +Breathtaking +Bruised +Bulky +Burly +Calm +Chaotic +Charming +Chubby +Coarse +Deformed +Delicate +Despondent +Dignified +Disgusting +Disturbing +Dull +Effeminate +Elegant +Emaciated +Energetic +Energetic +Exasperated +Exotic +Faint +Feisty +Flabby +Flamboyant +Fragile +Frail +Frazzled +Friendly +Gap-toothed +Gaunt +Gentle +Gloomy +Gormless +Hawkish +Hawkish +Healthy +Hefty +Hobbling +Hyper +Imposing +Inscrutable +Jaded +Lax +Lean +Limp +Lithe +Lopsided +Lovely +Malnourished +Mangled +Mangled +Masculine +Messy +Muscular +Nimble +Pathetic +Peppy +Petite +Pompous +Pugnacious +Quievering +Radical +Repulsive +Robust +Roguish +Rough +Scarred +Scrawny +Sculpted +Shifty +Shrewd +Sickly +Skittish +Sleek +Sleepy +Slender +Slimy +Slovenly +Sluggish +Sly +Smooth +Sniveling +Soulrendered +Spacy +Stiff +Stony +Stout +Strapping +Sturdy +Stylish +Swarthy +Tense +Tubular +Unattractive +Unblemished +Unhealthy +Unremarkable +Unsightly +Verbose +Vigorous +Waifish +Wilted +Wily +Withered +Worn-Out +Wrinkly +Zealous +Zesty diff --git a/tgui/packages/tgui/interfaces/Guestbook.tsx b/tgui/packages/tgui/interfaces/Guestbook.tsx new file mode 100644 index 000000000000..d1fb09aa8499 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Guestbook.tsx @@ -0,0 +1,74 @@ +import { useBackend } from '../backend'; +import { useLocalState } from '../backend'; +import { Stack, Button, Input, Section, Box } from '../components'; +import { Window } from '../layouts'; + +type Info = { + names: NameData[]; +}; + +type NameData = { + real_name: string; + given_name: string; +}; + +export const Guestbook = (props, context) => { + const { act, data } = useBackend(context); + const { names = [] } = data; + + const [lastNameBeforeEdit, setLastNameBeforeEdit] = useLocalState< + string | null + >(context, 'lastNameBeforeEdit', null); + + return ( + + + {(!names.length &&
    {'No known names!'}
    ) || ( + + {names.map((name) => ( + +
    + + +
    +
    + ))} +
    + )} +
    +
    + ); +}; From 2edaf656f6f36a15118fcebe158155e6ba35125f Mon Sep 17 00:00:00 2001 From: Changelogs Date: Mon, 15 Apr 2024 22:12:47 -0500 Subject: [PATCH 32/32] Automatic changelog generation for PR #2770 [ci skip] --- html/changelogs/AutoChangeLog-pr-2770.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-2770.yml diff --git a/html/changelogs/AutoChangeLog-pr-2770.yml b/html/changelogs/AutoChangeLog-pr-2770.yml new file mode 100644 index 000000000000..60d70bf52dd5 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2770.yml @@ -0,0 +1,8 @@ +author: meemofcourse +changes: + - {tweak: Identification Cards are now Access Cards. The only real difference is + that your name only shows up on a double examine.} + - {refactor: 'Anonymous mechanics. Characters no longer instantly recognize each + other, and need to properly memorize each other in order. You can recognize + an unmasked person by ctrl-shift-clicking them.'} +delete-after: true