diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index a036a862371..c6bdc32cfed 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -325,6 +325,8 @@ #define COMSIG_PROJECTILE_ON_HIT "projectile_on_hit" ///from base of /obj/projectile/proc/fire(): (obj/projectile, atom/original_target) #define COMSIG_PROJECTILE_BEFORE_FIRE "projectile_before_fire" +///from base of /obj/projectile/proc/fire(): (obj/projectile, atom/firer, atom/original_target) +#define COMSIG_PROJECTILE_FIRER_BEFORE_FIRE "projectile_firer_before_fire" ///from the base of /obj/projectile/proc/fire(): () #define COMSIG_PROJECTILE_FIRE "projectile_fire" ///sent to targets during the process_hit proc of projectiles diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm index d68948ce0bd..f3a78ae88fd 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers.dm @@ -210,6 +210,7 @@ #define BLIND_LAYER 4 #define CRIT_LAYER 5 #define CURSE_LAYER 6 +#define ECHO_LAYER 7 #define FOV_EFFECT_LAYER 100 diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index b7b8a10e255..c80830f067e 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -120,6 +120,7 @@ #define BODYPART_ID_ROBOTIC "robotic" #define BODYPART_ID_DIGITIGRADE "digitigrade" #define BODYPART_ID_LARVA "larva" +#define BODYPART_ID_PSYKER "psyker" //See: datum/species/var/digitigrade_customization ///The species does not have digitigrade legs in generation. diff --git a/code/__DEFINES/projectiles.dm b/code/__DEFINES/projectiles.dm index 12ba1d90545..5fe001c8f05 100644 --- a/code/__DEFINES/projectiles.dm +++ b/code/__DEFINES/projectiles.dm @@ -22,6 +22,8 @@ #define CALIBER_357 ".357" /// The caliber used by the detective's revolver. #define CALIBER_38 ".38" +/// The caliber used by the chaplain's revolver. +#define CALIBER_77 ".77" /// The caliber used by the C-20r SMG, the tommygun, and the M1911 pistol. #define CALIBER_45 ".45" /// The caliber used by sniper rifles and the desert eagle. diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index fab32f7e245..7dc9d0f3656 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -609,6 +609,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_GRABWEAKNESS "grab_weakness" #define TRAIT_SNOB "snob" #define TRAIT_BALD "bald" +#define TRAIT_SHAVED "shaved" #define TRAIT_BADTOUCH "bad_touch" #define TRAIT_EXTROVERT "extrovert" #define TRAIT_INTROVERT "introvert" @@ -677,6 +678,12 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// this is used to bypass tongue language restrictions but not tongue disabilities #define TRAIT_TOWER_OF_BABEL "tower_of_babel" +/// This target has recently been shot by a marksman coin and is very briefly immune to being hit by one again to prevent recursion +#define TRAIT_RECENTLY_COINED "recently_coined" + +/// Receives echolocation images. +#define TRAIT_ECHOLOCATION_RECEIVER "echolocation_receiver" + //Medical Categories for quirks #define CAT_QUIRK_ALL 0 #define CAT_QUIRK_NOTES 1 @@ -987,5 +994,5 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define RIGHT_LEG_TRAIT "right_leg" #define LEFT_LEG_TRAIT "left_leg" -/// This target has recently been shot by a marksman coin and is very briefly immune to being hit by one again to prevent recursion -#define TRAIT_RECENTLY_COINED "trait_recently_coined" +/// Trait given by echolocation component. +#define ECHOLOCATION_TRAIT "echolocation" diff --git a/code/datums/components/anti_magic.dm b/code/datums/components/anti_magic.dm index 91cfe5c9b4a..13ec8725aa2 100644 --- a/code/datums/components/anti_magic.dm +++ b/code/datums/components/anti_magic.dm @@ -45,7 +45,8 @@ else if(ismob(parent)) RegisterSignal(parent, COMSIG_MOB_RECEIVE_MAGIC, PROC_REF(block_receiving_magic), override = TRUE) RegisterSignal(parent, COMSIG_MOB_RESTRICT_MAGIC, PROC_REF(restrict_casting_magic), override = TRUE) - to_chat(parent, span_warning("Magic seems to flee from you. You are immune to spells but are unable to cast magic.")) + if(!HAS_TRAIT(parent, TRAIT_ANTIMAGIC_NO_SELFBLOCK)) + to_chat(parent, span_warning("Magic seems to flee from you. You are immune to spells but are unable to cast magic.")) else return COMPONENT_INCOMPATIBLE diff --git a/code/datums/components/echolocation.dm b/code/datums/components/echolocation.dm new file mode 100644 index 00000000000..f7d58bb9a1b --- /dev/null +++ b/code/datums/components/echolocation.dm @@ -0,0 +1,183 @@ +/datum/component/echolocation + /// Radius of our view. + var/echo_range = 4 + /// Time between echolocations. + var/cooldown_time = 2 SECONDS + /// Time for the image to start fading out. + var/image_expiry_time = 1.5 SECONDS + /// Time for the image to fade in. + var/fade_in_time = 0.5 SECONDS + /// Time for the image to fade out and delete itself. + var/fade_out_time = 0.5 SECONDS + /// Are images static? If yes, spawns them on the turf and makes them not change location. Otherwise they change location and pixel shift with the original. + var/images_are_static = TRUE + /// With mobs that have this echo group in their echolocation receiver trait, we share echo images. + var/echo_group = null + /// Ref of the client color we give to the echolocator. + var/client_color + /// Associative list of world.time when created to a list of the images. + var/list/images = list() + /// Associative list of world.time when created to a list of receivers. + var/list/receivers = list() + /// All the saved appearances, keyed by icon-icon_state. + var/static/list/saved_appearances = list() + /// Typecache of all the allowed paths to render. + var/static/list/allowed_paths + /// Typecache of turfs that are dangerous, to give them a special icon. + var/static/list/danger_turfs + /// A matrix that turns everything except #ffffff into pure blackness, used for our images (the outlines are #ffffff). + var/static/list/black_white_matrix = list(85, 85, 85, 0, 85, 85, 85, 0, 85, 85, 85, 0, 0, 0, 0, 1, -254, -254, -254, 0) + /// Cooldown for the echolocation. + COOLDOWN_DECLARE(cooldown_last) + +/datum/component/echolocation/Initialize(echo_range, cooldown_time, image_expiry_time, fade_in_time, fade_out_time, images_are_static, echo_group, echo_icon, color_path) + . = ..() + var/mob/living/echolocator = parent + if(!istype(echolocator)) + return COMPONENT_INCOMPATIBLE + if(!danger_turfs) + danger_turfs = typecacheof(list(/turf/open/space, /turf/open/openspace, /turf/open/chasm, /turf/open/lava)) + if(!allowed_paths) + allowed_paths = typecacheof(list(/turf/closed, /obj, /mob/living)) + danger_turfs + if(!isnull(echo_range)) + src.echo_range = echo_range + if(!isnull(cooldown_time)) + src.cooldown_time = cooldown_time + if(!isnull(image_expiry_time)) + src.image_expiry_time = image_expiry_time + if(!isnull(fade_in_time)) + src.fade_in_time = fade_in_time + if(!isnull(fade_out_time)) + src.fade_out_time = fade_out_time + if(!isnull(images_are_static)) + src.images_are_static = images_are_static + if(!isnull(echo_group)) + src.echo_group = echo_group + if(!isnull(color_path)) + client_color = echolocator.add_client_colour(color_path) + ADD_TRAIT(echolocator, TRAIT_ECHOLOCATION_RECEIVER, echo_group || REF(src)) + echolocator.become_blind(ECHOLOCATION_TRAIT) + echolocator.overlay_fullscreen("echo", /atom/movable/screen/fullscreen/echo, echo_icon) + START_PROCESSING(SSfastprocess, src) + +/datum/component/echolocation/Destroy(force, silent) + STOP_PROCESSING(SSfastprocess, src) + var/mob/living/echolocator = parent + QDEL_NULL(client_color) + REMOVE_TRAIT(echolocator, TRAIT_ECHOLOCATION_RECEIVER, echo_group || REF(src)) + echolocator.cure_blind(ECHOLOCATION_TRAIT) + echolocator.clear_fullscreen("echo") + for(var/timeframe in images) + delete_images(timeframe) + return ..() + +/datum/component/echolocation/process() + var/mob/living/echolocator = parent + if(echolocator.stat == DEAD) + return + echolocate() + +/datum/component/echolocation/proc/echolocate() + if(!COOLDOWN_FINISHED(src, cooldown_last)) + return + COOLDOWN_START(src, cooldown_last, cooldown_time) + var/mob/living/echolocator = parent + var/list/filtered = list() + var/list/seen = dview(echo_range, echolocator.loc) + for(var/atom/seen_atom as anything in seen) + if(seen_atom.invisibility > echolocator.see_invisible || !seen_atom.alpha) + continue + if(allowed_paths[seen_atom.type]) + filtered += seen_atom + if(!length(filtered)) + return + var/current_time = "[world.time]" + images[current_time] = list() + receivers[current_time] = list() + for(var/mob/living/viewer in filtered) + if(HAS_TRAIT_FROM(viewer, TRAIT_ECHOLOCATION_RECEIVER, echo_group)) + receivers[current_time] += viewer + for(var/atom/filtered_atom as anything in filtered) + show_image(saved_appearances["[filtered_atom.icon]-[filtered_atom.icon_state]"] || generate_appearance(filtered_atom), filtered_atom, current_time) + addtimer(CALLBACK(src, .proc/fade_images, current_time), image_expiry_time) + +/datum/component/echolocation/proc/show_image(image/input_appearance, atom/input, current_time) + var/image/final_image = image(input_appearance) + final_image.layer += EFFECTS_LAYER + final_image.plane = FULLSCREEN_PLANE + final_image.loc = images_are_static ? get_turf(input) : input + final_image.dir = input.dir + final_image.alpha = 0 + if(images_are_static) + final_image.pixel_x = input.pixel_x + final_image.pixel_y = input.pixel_y + images[current_time] += final_image + for(var/mob/living/echolocate_receiver as anything in receivers[current_time]) + if(echolocate_receiver == input) + continue + if(echolocate_receiver.client) + echolocate_receiver.client.images += final_image + animate(final_image, alpha = 255, time = fade_in_time) + +/datum/component/echolocation/proc/generate_appearance(atom/input) + var/use_outline = TRUE + var/mutable_appearance/copied_appearance = new /mutable_appearance() + copied_appearance.appearance = input + if(istype(input, /obj/machinery/door/airlock)) //i hate you + copied_appearance.icon = 'icons/obj/doors/airlocks/station/public.dmi' + copied_appearance.icon_state = "closed" + else if(danger_turfs[input.type]) + copied_appearance.icon = 'icons/turf/floors.dmi' + copied_appearance.icon_state = "danger" + use_outline = FALSE + copied_appearance.color = black_white_matrix + if(use_outline) + copied_appearance.filters += outline_filter(size = 1, color = COLOR_WHITE) + if(!images_are_static) + copied_appearance.pixel_x = 0 + copied_appearance.pixel_y = 0 + copied_appearance.transform = matrix() + if(!iscarbon(input)) //wacky overlay people get generated everytime + saved_appearances["[input.icon]-[input.icon_state]"] = copied_appearance + return copied_appearance + +/datum/component/echolocation/proc/fade_images(from_when) + for(var/image_echo in images[from_when]) + animate(image_echo, alpha = 0, time = fade_out_time) + addtimer(CALLBACK(src, .proc/delete_images, from_when), fade_out_time) + +/datum/component/echolocation/proc/delete_images(from_when) + for(var/mob/living/echolocate_receiver as anything in receivers[from_when]) + if(!echolocate_receiver.client) + continue + for(var/image_echo in images[from_when]) + echolocate_receiver.client.images -= image_echo + images -= from_when + receivers -= from_when + +/atom/movable/screen/fullscreen/echo + icon_state = "echo" + layer = ECHO_LAYER + show_when_dead = TRUE + +/atom/movable/screen/fullscreen/echo/Initialize(mapload) + . = ..() + particles = new /particles/echo() + +/atom/movable/screen/fullscreen/echo/Destroy() + QDEL_NULL(particles) + return ..() + +/particles/echo + icon = 'icons/effects/particles/echo.dmi' + icon_state = list("echo1" = 1, "echo2" = 1, "echo3" = 2) + width = 480 + height = 480 + count = 1000 + spawning = 0.5 + lifespan = 2 SECONDS + fade = 1 SECONDS + gravity = list(0, -0.1) + position = generator(GEN_BOX, list(-240, -240), list(240, 240), NORMAL_RAND) + drift = generator(GEN_VECTOR, list(-0.1, 0), list(0.1, 0)) + rotation = generator(GEN_NUM, 0, 360, NORMAL_RAND) diff --git a/code/datums/components/religious_tool.dm b/code/datums/components/religious_tool.dm index f9dcd1164c0..1caab166048 100644 --- a/code/datums/components/religious_tool.dm +++ b/code/datums/components/religious_tool.dm @@ -171,13 +171,7 @@ */ /datum/component/religious_tool/proc/generate_available_sects(mob/user) var/list/sects_to_pick = list() - var/human_highpriest = ishuman(user) - var/mob/living/carbon/human/highpriest = user for(var/path in subtypesof(/datum/religion_sect)) - if(human_highpriest && initial(easy_access_sect.invalidating_qualities)) - var/datum/species/highpriest_species = highpriest.dna.species - if(initial(easy_access_sect.invalidating_qualities) in highpriest_species.inherent_traits) - continue var/list/sect = list() var/datum/religion_sect/not_a_real_instance_rs = path sect["name"] = initial(not_a_real_instance_rs.name) diff --git a/code/datums/dna.dm b/code/datums/dna.dm index 8a0e30a6de0..54ac36f838f 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -565,7 +565,10 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) skin_tone = GLOB.skin_tones[deconstruct_block(get_uni_identity_block(structure, DNA_SKIN_TONE_BLOCK), GLOB.skin_tones.len)] eye_color_left = sanitize_hexcolor(get_uni_identity_block(structure, DNA_EYE_COLOR_LEFT_BLOCK)) eye_color_right = sanitize_hexcolor(get_uni_identity_block(structure, DNA_EYE_COLOR_RIGHT_BLOCK)) - facial_hairstyle = GLOB.facial_hairstyles_list[deconstruct_block(get_uni_identity_block(structure, DNA_FACIAL_HAIRSTYLE_BLOCK), GLOB.facial_hairstyles_list.len)] + if(HAS_TRAIT(src, TRAIT_SHAVED)) + hairstyle = "Shaved" + else + facial_hairstyle = GLOB.facial_hairstyles_list[deconstruct_block(get_uni_identity_block(structure, DNA_FACIAL_HAIRSTYLE_BLOCK), GLOB.facial_hairstyles_list.len)] if(HAS_TRAIT(src, TRAIT_BALD)) hairstyle = "Bald" else @@ -836,7 +839,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) ForceContractDisease(new/datum/disease/gastrolosis()) to_chat(src, span_notice("Oh, I actually feel quite alright!")) else - switch(rand(0,5)) + switch(rand(0,6)) if(0) investigate_log("has been gibbed by DNA instability.", INVESTIGATE_DEATHS) gib() @@ -866,6 +869,8 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) if(5) to_chat(src, span_phobia("LOOK UP!")) addtimer(CALLBACK(src, PROC_REF(something_horrible_mindmelt)), 30) + if(6) + psykerize() /mob/living/carbon/human/proc/something_horrible_mindmelt() if(!is_blind()) diff --git a/code/game/objects/effects/forcefields.dm b/code/game/objects/effects/forcefields.dm index 64b2c013338..6d7f82a47e7 100644 --- a/code/game/objects/effects/forcefields.dm +++ b/code/game/objects/effects/forcefields.dm @@ -66,3 +66,13 @@ name = "invisible blockade" desc = "You're gonna be here awhile." initial_duration = 1 MINUTES + +/// Psyker forcefield +/obj/effect/forcefield/psychic + name = "psychic forcefield" + desc = "A wall of psychic energy powerful enough stop the motion of objects. Projectiles ricochet." + icon_state = "psychic" + can_atmos_pass = ATMOS_PASS_YES + flags_ricochet = RICOCHET_SHINY | RICOCHET_HARD + receive_ricochet_chance_mod = INFINITY //we do ricochet a lot! + initial_duration = 10 SECONDS diff --git a/code/game/objects/items/cosmetics.dm b/code/game/objects/items/cosmetics.dm index dae8eab25d5..4b17727f05e 100644 --- a/code/game/objects/items/cosmetics.dm +++ b/code/game/objects/items/cosmetics.dm @@ -166,6 +166,9 @@ if(!get_location_accessible(H, location)) to_chat(user, span_warning("The mask is in the way!")) return + if(HAS_TRAIT(H, TRAIT_SHAVED)) + to_chat(user, span_warning("[H] is just way too shaved. Like, really really shaved.")) + return user.visible_message(span_notice("[user] tries to change [H]'s facial hairstyle using [src]."), span_notice("You try to change [H]'s facial hairstyle using [src].")) if(new_style && do_after(user, 60, target = H)) user.visible_message(span_notice("[user] successfully changes [H]'s facial hairstyle using [src]."), span_notice("You successfully change [H]'s facial hairstyle using [src].")) @@ -215,7 +218,7 @@ to_chat(user, span_warning("The headgear is in the way!")) return if(HAS_TRAIT(H, TRAIT_BALD)) - to_chat(H, span_warning("[H] is just way too bald. Like, really really bald.")) + to_chat(user, span_warning("[H] is just way too bald. Like, really really bald.")) return user.visible_message(span_notice("[user] tries to change [H]'s hairstyle using [src]."), span_notice("You try to change [H]'s hairstyle using [src].")) if(new_style && do_after(user, 60, target = H)) diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index 9a736e3e27a..6bcd09a9dc1 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -34,6 +34,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror, 28) return TRUE if(!user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE)) return TRUE //no tele-grooming + if(HAS_TRAIT(hairdresser, TRAIT_SHAVED)) + to_chat(hairdresser, span_notice("If only growing back facial hair were that easy for you...")) hairdresser.facial_hairstyle = new_style else hairdresser.facial_hairstyle = "Shaved" diff --git a/code/modules/client/client_colour.dm b/code/modules/client/client_colour.dm index 1e4792317ff..9aed1d30072 100644 --- a/code/modules/client/client_colour.dm +++ b/code/modules/client/client_colour.dm @@ -213,6 +213,11 @@ /datum/client_colour/rave priority = PRIORITY_LOW +/datum/client_colour/psyker + priority = PRIORITY_ABSOLUTE + override = TRUE + colour = list(0.8,0,0,0, 0,0,0,0, 0,0,1,0, 0,0,0,1, 0,0,0,0) + #undef PRIORITY_ABSOLUTE #undef PRIORITY_HIGH #undef PRIORITY_NORMAL diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm index bcc85603902..f7a83637136 100644 --- a/code/modules/mob/living/brain/brain_item.dm +++ b/code/modules/mob/living/brain/brain_item.dm @@ -42,7 +42,7 @@ /obj/item/organ/internal/brain/Insert(mob/living/carbon/C, special = FALSE, drop_if_replaced = TRUE, no_id_transfer = FALSE) . = ..() - name = "brain" + name = initial(name) if(C.mind && C.mind.has_antag_datum(/datum/antagonist/changeling) && !no_id_transfer) //congrats, you're trapped in a body you don't control if(brainmob && !(C.stat == DEAD || (HAS_TRAIT(C, TRAIT_DEATHCOMA)))) @@ -88,11 +88,12 @@ /obj/item/organ/internal/brain/Remove(mob/living/carbon/C, special = 0, no_id_transfer = FALSE) // Delete skillchips first as parent proc sets owner to null, and skillchips need to know the brain's owner. if(!QDELETED(C) && length(skillchips)) - to_chat(C, span_notice("You feel your skillchips enable emergency power saving mode, deactivating as your brain leaves your body...")) + if(!special) + to_chat(C, span_notice("You feel your skillchips enable emergency power saving mode, deactivating as your brain leaves your body...")) for(var/chip in skillchips) var/obj/item/skillchip/skillchip = chip // Run the try_ proc with force = TRUE. - skillchip.try_deactivate_skillchip(FALSE, TRUE) + skillchip.try_deactivate_skillchip(silent = special, force = TRUE) . = ..() @@ -106,7 +107,7 @@ C.update_body_parts() /obj/item/organ/internal/brain/proc/transfer_identity(mob/living/L) - name = "[L.name]'s brain" + name = "[L.name]'s [initial(name)]" if(brainmob || decoy_override) return if(!L.mind) @@ -297,7 +298,7 @@ // If we have some sort of brain type or subtype change and have skillchips, engage the failsafe procedure! if(owner && length(skillchips) && (replacement_brain.type != type)) - activate_skillchip_failsafe(FALSE) + activate_skillchip_failsafe(silent = TRUE) // Check through all our skillchips, remove them from this brain, add them to the replacement brain. for(var/chip in skillchips) @@ -347,7 +348,7 @@ organ_traits = list(TRAIT_CAN_STRIP) /obj/item/organ/internal/brain/primitive //No like books and stompy metal men - name = "Primative Brain" + name = "primitive brain" desc = "This juicy piece of meat has a clearly underdeveloped frontal lobe." organ_traits = list(TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, TRAIT_PRIMITIVE) // No literacy diff --git a/code/modules/mob/living/living_fov.dm b/code/modules/mob/living/living_fov.dm index 4a12b07afee..d562b2cbb79 100644 --- a/code/modules/mob/living/living_fov.dm +++ b/code/modules/mob/living/living_fov.dm @@ -94,7 +94,7 @@ plane = FULLSCREEN_PLANE /// Plays a visual effect representing a sound cue for people with vision obstructed by FOV or blindness -/proc/play_fov_effect(atom/center, range, icon_state, dir = SOUTH, ignore_self = FALSE, angle = 0, list/override_list) +/proc/play_fov_effect(atom/center, range, icon_state, dir = SOUTH, ignore_self = FALSE, angle = 0, time = 1.5 SECONDS, list/override_list) var/turf/anchor_point = get_turf(center) var/image/fov_image/fov_image var/list/clients_shown @@ -123,7 +123,7 @@ //when added as an image mutable_appearances act identically. we just make it an MA becuase theyre faster to change appearance if(clients_shown) - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(remove_image_from_clients), fov_image, clients_shown), 30) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(remove_image_from_clients), fov_image, clients_shown), time) /atom/movable/screen/fov_blocker icon = 'icons/effects/fov/field_of_view.dmi' diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm index 6b67f53ce3a..483a481afed 100644 --- a/code/modules/projectiles/guns/ballistic.dm +++ b/code/modules/projectiles/guns/ballistic.dm @@ -327,7 +327,7 @@ update_appearance() /obj/item/gun/ballistic/can_shoot() - return chambered + return chambered?.loaded_projectile /obj/item/gun/ballistic/attackby(obj/item/A, mob/user, params) . = ..() diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 59d1008c567..542e03e2e93 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -701,6 +701,8 @@ LAZYINITLIST(impacted) if(fired_from) SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_BEFORE_FIRE, src, original) + if(firer) + SEND_SIGNAL(firer, COMSIG_PROJECTILE_FIRER_BEFORE_FIRE, src, fired_from, original) //If no angle needs to resolve it from xo/yo! if(shrapnel_type && LAZYLEN(embedding)) AddElement(/datum/element/embed, projectile_payload = shrapnel_type) diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 292434ff175..2a22fbd7c62 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -2052,7 +2052,7 @@ /datum/reagent/barbers_aid/expose_mob(mob/living/exposed_mob, methods=TOUCH, reac_volume, show_message=TRUE, touch_protection=FALSE) . = ..() - if(!(methods & (TOUCH|VAPOR)) || !ishuman(exposed_mob) || HAS_TRAIT(exposed_mob, TRAIT_BALD)) + if(!(methods & (TOUCH|VAPOR)) || !ishuman(exposed_mob) || HAS_TRAIT(exposed_mob, TRAIT_BALD) || HAS_TRAIT(exposed_mob, TRAIT_SHAVED)) return var/mob/living/carbon/human/exposed_human = exposed_mob @@ -2074,7 +2074,7 @@ /datum/reagent/concentrated_barbers_aid/expose_mob(mob/living/exposed_mob, methods=TOUCH, reac_volume, show_message=TRUE, touch_protection=FALSE) . = ..() - if(!(methods & (TOUCH|VAPOR)) || !ishuman(exposed_mob) || HAS_TRAIT(exposed_mob, TRAIT_BALD)) + if(!(methods & (TOUCH|VAPOR)) || !ishuman(exposed_mob) || HAS_TRAIT(exposed_mob, TRAIT_BALD) || HAS_TRAIT(exposed_mob, TRAIT_SHAVED)) return var/mob/living/carbon/human/exposed_human = exposed_mob diff --git a/code/datums/mutations/holy_mutation/burdened.dm b/code/modules/religion/burdened/burdened_trauma.dm similarity index 60% rename from code/datums/mutations/holy_mutation/burdened.dm rename to code/modules/religion/burdened/burdened_trauma.dm index 808109f7de0..eaf50c6cac3 100644 --- a/code/datums/mutations/holy_mutation/burdened.dm +++ b/code/modules/religion/burdened/burdened_trauma.dm @@ -1,20 +1,15 @@ - -///Burdened grants some more mutations upon injuring yourself sufficiently -/datum/mutation/human/burdened - name = "Burdened" - desc = "Less of a genome and more of a forceful rewrite of genes. Nothing Nanotrasen supplies allows for a genetic restructure like this... \ - The user feels compelled to injure themselves in various incapacitating and horrific ways. Oddly enough, this gene seems to be connected \ - to several other ones, possibly ready to trigger more genetic changes in the future." - quality = POSITIVE //so it gets carried over on revives - locked = TRUE - text_gain_indication = "You feel burdened!" - text_lose_indication = "You no longer feel the need to burden yourself!" - /// goes from 0 to 6 (but can be beyond 6, just does nothing) and gives rewards. increased by disabling yourself with debuffs +///Burdened grants some mutations upon injuring yourself sufficiently +/datum/brain_trauma/special/burdened + name = "Flagellating Compulsions" + desc = "Patient feels compelled to injure themselves in various incapacitating and horrific ways. There seems to be an odd genetic... trigger, following these compulsions may lead to?" + scan_desc = "damaged frontal lobe" + gain_text = span_notice("You feel burdened!") + lose_text = span_warning("You no longer feel the need to burden yourself!") + random_gain = FALSE + /// goes from 0 to 9 (but can be beyond 9, just does nothing) and gives rewards. increased by disabling yourself with debuffs var/burden_level = 0 -/datum/mutation/human/burdened/on_acquiring(mob/living/carbon/human/owner) - if(..()) - return +/datum/brain_trauma/special/burdened/on_gain() RegisterSignal(owner, COMSIG_CARBON_GAIN_ORGAN, PROC_REF(organ_added_burden)) RegisterSignal(owner, COMSIG_CARBON_LOSE_ORGAN, PROC_REF(organ_removed_burden)) @@ -29,9 +24,9 @@ RegisterSignal(owner, COMSIG_CARBON_GAIN_TRAUMA, PROC_REF(trauma_added_burden)) RegisterSignal(owner, COMSIG_CARBON_LOSE_TRAUMA, PROC_REF(trauma_removed_burden)) + return ..() -/datum/mutation/human/burdened/on_losing(mob/living/carbon/human/owner) - . = ..() +/datum/brain_trauma/special/burdened/on_lose() UnregisterSignal(owner, list( COMSIG_CARBON_GAIN_ORGAN, COMSIG_CARBON_LOSE_ORGAN, @@ -44,6 +39,7 @@ COMSIG_CARBON_GAIN_TRAUMA, COMSIG_CARBON_LOSE_TRAUMA, )) + return ..() /** * Called by hooked signals whenever burden_level var needs to go up or down by 1. @@ -52,11 +48,15 @@ * Arguments: * * increase: whether to tick burden_level up or down 1 */ -/datum/mutation/human/burdened/proc/update_burden(increase) +/datum/brain_trauma/special/burdened/proc/update_burden(increase) + var/datum/dna/dna = owner?.dna + if(!dna) + qdel(src) + return //adjust burden burden_level = increase ? burden_level + 1 : burden_level - 1 if(burden_level < 0) //basically a clamp with a stack on it, because this shouldn't be happening - stack_trace("somehow, burden mutation is removing more burden than it's adding.") + stack_trace("somehow, burden trauma is removing more burden than it's adding.") burden_level = 0 //send a message and handle rewards switch(burden_level) @@ -73,35 +73,54 @@ else to_chat(owner, span_warning("The weight on your shoulders feels lighter. You have lost some universal truths.")) dna.remove_mutation(/datum/mutation/human/telepathy) - dna.remove_mutation(/datum/mutation/human/mute) + dna.remove_mutation(/datum/mutation/human/unintelligible) owner.remove_filter("burden_outline") if(3) if(increase) to_chat(owner, span_notice("Your suffering is only a fraction of [GLOB.deity]'s, and yet the universal truths are coming to you.")) dna.add_mutation(/datum/mutation/human/telepathy) - dna.add_mutation(/datum/mutation/human/mute) + dna.add_mutation(/datum/mutation/human/unintelligible) owner.add_filter("burden_outline", 9, list("type" = "outline", "color" = "#6c6eff")) else to_chat(owner, span_warning("The weight on your shoulders feels lighter. You feel like you're about to forget.")) if(4) if(increase) - to_chat(owner, span_notice("The weight on your shoulders is immense. [GLOB.deity] is shattered across the cosmos.")) + to_chat(owner, span_notice("It hurts, each ounce of pain a lesson told. How does [GLOB.deity] bear this weight?")) else to_chat(owner, span_warning("The weight on your shoulders feels lighter. You're growing further from your goal.")) if(5) if(increase) - to_chat(owner, span_notice("You're on the cusp of another breakthrough. [GLOB.deity] lost everything.")) + to_chat(owner, span_notice("Your body is a canvas of loss. You are almost at a breakthrough.")) else to_chat(owner, span_warning("The weight on your shoulders feels lighter. You have lost some universal truths.")) dna.remove_mutation(/datum/mutation/human/telekinesis) dna.remove_mutation(/datum/mutation/human/mindreader) if(6) + if(increase) + to_chat(owner, span_notice("Your suffering is respectful, your scars immaculate. More universal truths are clear, but you do not fully understand yet.")) + dna.add_mutation(/datum/mutation/human/telekinesis) + dna.add_mutation(/datum/mutation/human/mindreader) + else + to_chat(owner, span_warning("The weight on your shoulders feels lighter. You feel like you're about to forget.")) + if(7) + if(increase) + to_chat(owner, span_notice("The weight on your shoulders is immense. [GLOB.deity] is shattered across the cosmos.")) + else + to_chat(owner, span_warning("The weight on your shoulders feels lighter. You're growing further from your goal.")) + if(8) + if(increase) + to_chat(owner, span_notice("You're on the cusp of another breakthrough. [GLOB.deity] lost everything.")) + else + to_chat(owner, span_warning("The weight on your shoulders feels lighter. You have lost some universal truths.")) + if(9) to_chat(owner, span_notice("You have finally broken yourself enough to understand [GLOB.deity]. It's all so clear to you.")) - dna.add_mutation(/datum/mutation/human/telekinesis) - dna.add_mutation(/datum/mutation/human/mindreader) + var/mob/living/carbon/human/knower = owner + if(!istype(knower)) + return + INVOKE_ASYNC(knower, TYPE_PROC_REF(/mob/living/carbon/human, psykerize)) /// Signal to decrease burden_level (see update_burden proc) if an organ is added -/datum/mutation/human/burdened/proc/organ_added_burden(mob/burdened, obj/item/organ/new_organ, special) +/datum/brain_trauma/special/burdened/proc/organ_added_burden(mob/burdened, obj/item/organ/new_organ, special) SIGNAL_HANDLER if(special) //aheals @@ -112,10 +131,13 @@ if(new_eyes.tint < TINT_BLIND) //unless you added unworking eyes (flashlight eyes), this is removing burden update_burden(FALSE) return - update_burden(FALSE)//working organ + else if(istype(new_organ, /obj/item/organ/internal/appendix)) + return + + update_burden(increase = FALSE)//working organ /// Signal to increase burden_level (see update_burden proc) if an organ is removed -/datum/mutation/human/burdened/proc/organ_removed_burden(mob/burdened, obj/item/organ/old_organ, special) +/datum/brain_trauma/special/burdened/proc/organ_removed_burden(mob/burdened, obj/item/organ/old_organ, special) SIGNAL_HANDLER if(special) //aheals @@ -125,65 +147,64 @@ var/obj/item/organ/internal/eyes/old_eyes = old_organ if(old_eyes.tint < TINT_BLIND) //unless you were already blinded by them (flashlight eyes), this is adding burden! update_burden(TRUE) + return + else if(istype(old_organ, /obj/item/organ/internal/appendix)) + return - update_burden(TRUE)//lost organ + update_burden(increase = TRUE)//lost organ /// Signal to decrease burden_level (see update_burden proc) if a limb is added -/datum/mutation/human/burdened/proc/limbs_added_burden(datum/source, obj/item/bodypart/new_limb, special) +/datum/brain_trauma/special/burdened/proc/limbs_added_burden(datum/source, obj/item/bodypart/new_limb, special) SIGNAL_HANDLER if(special) //something we don't wanna consider, like instaswapping limbs return - update_burden(FALSE) + update_burden(increase = FALSE) /// Signal to increase burden_level (see update_burden proc) if a limb is removed -/datum/mutation/human/burdened/proc/limbs_removed_burden(datum/source, obj/item/bodypart/old_limb, special) +/datum/brain_trauma/special/burdened/proc/limbs_removed_burden(datum/source, obj/item/bodypart/old_limb, special) SIGNAL_HANDLER if(special) //something we don't wanna consider, like instaswapping limbs return - update_burden(TRUE) + update_burden(increase = TRUE) /// Signal to increase burden_level (see update_burden proc) if an addiction is added -/datum/mutation/human/burdened/proc/addict_added_burden(datum/addiction/new_addiction, datum/mind/addict_mind) +/datum/brain_trauma/special/burdened/proc/addict_added_burden(datum/addiction/new_addiction, datum/mind/addict_mind) SIGNAL_HANDLER - update_burden(TRUE) + update_burden(increase = TRUE) /// Signal to decrease burden_level (see update_burden proc) if an addiction is removed -/datum/mutation/human/burdened/proc/addict_removed_burden(datum/addiction/old_addiction, datum/mind/nonaddict_mind) +/datum/brain_trauma/special/burdened/proc/addict_removed_burden(datum/addiction/old_addiction, datum/mind/nonaddict_mind) SIGNAL_HANDLER - update_burden(FALSE) + update_burden(increase = FALSE) /// Signal to increase burden_level (see update_burden proc) if a mutation is added -/datum/mutation/human/burdened/proc/mutation_added_burden(mob/living/carbon/burdened, datum/mutation/human/mutation_type, class) +/datum/brain_trauma/special/burdened/proc/mutation_added_burden(mob/living/carbon/burdened, datum/mutation/human/mutation_type, class) SIGNAL_HANDLER - if(class == MUT_OTHER) //getting a mutation can give a mutation as a reward, which in turn triggers this, which then rewards a mutation, which in turn... - return if(initial(mutation_type.quality) == NEGATIVE) - update_burden(TRUE) + update_burden(increase = TRUE) /// Signal to decrease burden_level (see update_burden proc) if a mutation is removed -/datum/mutation/human/burdened/proc/mutation_removed_burden(mob/living/carbon/burdened, datum/mutation/human/mutation_type) +/datum/brain_trauma/special/burdened/proc/mutation_removed_burden(mob/living/carbon/burdened, datum/mutation/human/mutation_type) SIGNAL_HANDLER - if(class == MUT_OTHER) //see above - return if(initial(mutation_type.quality) == NEGATIVE) - update_burden(FALSE) + update_burden(increase = FALSE) /// Signal to increase burden_level (see update_burden proc) if a trauma is added -/datum/mutation/human/burdened/proc/trauma_added_burden(mob/living/carbon/burdened, datum/brain_trauma/trauma_added) +/datum/brain_trauma/special/burdened/proc/trauma_added_burden(mob/living/carbon/burdened, datum/brain_trauma/trauma_added) SIGNAL_HANDLER if(istype(trauma_added, /datum/brain_trauma/severe)) - update_burden(TRUE) + update_burden(increase = TRUE) /// Signal to decrease burden_level (see update_burden proc) if a trauma is removed -/datum/mutation/human/burdened/proc/trauma_removed_burden(mob/living/carbon/burdened, datum/brain_trauma/trauma_removed) +/datum/brain_trauma/special/burdened/proc/trauma_removed_burden(mob/living/carbon/burdened, datum/brain_trauma/trauma_removed) SIGNAL_HANDLER if(istype(trauma_removed, /datum/brain_trauma/severe)) - update_burden(FALSE) + update_burden(increase = FALSE) diff --git a/code/modules/religion/burdened/psyker.dm b/code/modules/religion/burdened/psyker.dm new file mode 100644 index 00000000000..3a54e2e7530 --- /dev/null +++ b/code/modules/religion/burdened/psyker.dm @@ -0,0 +1,376 @@ +/obj/item/organ/internal/brain/psyker + name = "psyker brain" + desc = "This brain is blue, split into two hemispheres, and has immense psychic powers. What kind of monstrosity would use that?" + icon_state = "brain-psyker" + actions_types = list( + /datum/action/cooldown/spell/pointed/psychic_projection, + /datum/action/cooldown/spell/charged/psychic_booster, + /datum/action/cooldown/spell/forcewall/psychic_wall, + ) + organ_traits = list(TRAIT_ADVANCEDTOOLUSER, TRAIT_LITERATE, TRAIT_CAN_STRIP, TRAIT_ANTIMAGIC_NO_SELFBLOCK) + w_class = WEIGHT_CLASS_NORMAL + +/obj/item/organ/internal/brain/psyker/Insert(mob/living/carbon/inserted_into, special, drop_if_replaced, no_id_transfer) + . = ..() + inserted_into.AddComponent(/datum/component/echolocation, echo_group = "psyker", echo_icon = "psyker", color_path = /datum/client_colour/psyker) + inserted_into.AddComponent(/datum/component/anti_magic, antimagic_flags = MAGIC_RESISTANCE_MIND) + +/obj/item/organ/internal/brain/psyker/Remove(mob/living/carbon/removed_from, special, no_id_transfer) + . = ..() + qdel(removed_from.GetComponent(/datum/component/echolocation)) + qdel(removed_from.GetComponent(/datum/component/anti_magic)) + +/obj/item/organ/internal/brain/psyker/on_life(delta_time, times_fired) + . = ..() + var/obj/item/bodypart/head/psyker/psyker_head = owner.get_bodypart(zone) + if(istype(psyker_head)) + return + if(!DT_PROB(2, delta_time)) + return + to_chat(owner, span_userdanger("Your head hurts... It can't fit your brain!")) + owner.adjust_disgust(33 * delta_time) + applyOrganDamage(5 * delta_time, 199) + owner.adjustOrganLoss(ORGAN_SLOT_BRAIN, 5 * delta_time) + +/obj/item/bodypart/head/psyker + limb_id = BODYPART_ID_PSYKER + is_dimorphic = FALSE + should_draw_greyscale = FALSE + bodypart_traits = list(TRAIT_DISFIGURED, TRAIT_BALD, TRAIT_SHAVED, TRAIT_BLIND) + +/obj/item/bodypart/head/psyker/try_attach_limb(mob/living/carbon/new_head_owner, special, abort) + . = ..() + if(!. || !new_head_owner.dna?.species) + return + new_head_owner.dna.species.species_traits |= NOEYESPRITES //MAKE VISUALS TIED TO BODYPARTS ARGHH + new_head_owner.update_body() + +/// Makes us go through a transform sequency, to turn into a psyker. +/mob/living/carbon/human/proc/psykerize() + if(stat == DEAD || !get_bodypart(BODY_ZONE_HEAD) || istype(get_bodypart(BODY_ZONE_HEAD), /obj/item/bodypart/head/psyker)) + return + to_chat(src, span_userdanger("You feel unwell...")) + sleep(5 SECONDS) + if(stat == DEAD || !get_bodypart(BODY_ZONE_HEAD)) + return + to_chat(src, span_userdanger("You feel your skin ripping off!")) + emote("scream") + apply_damage(30, BRUTE, BODY_ZONE_HEAD) + sleep(5 SECONDS) + var/obj/item/bodypart/head/old_head = get_bodypart(BODY_ZONE_HEAD) + var/obj/item/organ/internal/brain/old_brain = getorganslot(ORGAN_SLOT_BRAIN) + var/obj/item/organ/internal/old_eyes = getorganslot(ORGAN_SLOT_EYES) + if(stat == DEAD || !old_head || !old_brain) + return + to_chat(src, span_userdanger("Your head splits open! Your brain mutates!")) + new /obj/effect/gibspawner/generic(drop_location(), src) + emote("scream") + var/obj/item/bodypart/head/psyker/psyker_head = new() + psyker_head.receive_damage(brute = 50) + if(!psyker_head.replace_limb(src, special = TRUE)) + return + qdel(old_head) + var/obj/item/organ/internal/brain/psyker/psyker_brain = new() + old_brain.before_organ_replacement(psyker_brain) + old_brain.Remove(src, special = TRUE, no_id_transfer = TRUE) + qdel(old_brain) + psyker_brain.Insert(src, special = TRUE, drop_if_replaced = FALSE) + if(old_eyes) + qdel(old_eyes) + +/datum/religion_rites/nullrod_transformation + name = "Transmogrify" + desc = "Your full power needs a firearm to be realized. You may transform your null rod into one." + ritual_length = 10 SECONDS + ///The rod that will be transmogrified. + var/obj/item/nullrod/transformation_target + +/datum/religion_rites/nullrod_transformation/perform_rite(mob/living/user, atom/religious_tool) + if(!ishuman(user)) + return FALSE + var/mob/living/carbon/human/human_user = user + var/datum/brain_trauma/special/burdened/burden = human_user.has_trauma_type(/datum/brain_trauma/special/burdened) + if(!burden || burden.burden_level < 9) + to_chat(human_user, span_warning("You aren't burdened enough.")) + return FALSE + for(var/obj/item/nullrod/null_rod in get_turf(religious_tool)) + transformation_target = null_rod + return ..() + to_chat(human_user, span_warning("You need to place a null rod on [religious_tool] to do this!")) + return FALSE + +/datum/religion_rites/nullrod_transformation/invoke_effect(mob/living/user, atom/movable/religious_tool) + ..() + var/obj/item/nullrod/null_rod = transformation_target + transformation_target = null + if(QDELETED(null_rod) || null_rod.loc != get_turf(religious_tool)) + to_chat(user, span_warning("Your target left the altar!")) + return FALSE + to_chat(user, span_warning("[null_rod] turns into a gun!")) + user.emote("smile") + qdel(null_rod) + new /obj/item/gun/ballistic/revolver/chaplain(get_turf(religious_tool)) + return TRUE + +/obj/item/gun/ballistic/revolver/chaplain + name = "chaplain's revolver" + desc = "Holy smokes." + icon_state = "chaplain" + force = 10 + fire_sound = 'sound/weapons/gun/revolver/shot.ogg' + mag_type = /obj/item/ammo_box/magazine/internal/cylinder/rev77 + obj_flags = UNIQUE_RENAME + custom_materials = null + actions_types = list(/datum/action/item_action/pray_refill) + /// Needs burden level nine to refill. + var/needs_burden = TRUE + /// List of all possible names and descriptions. + var/static/list/possible_names = list( + "Requiescat" = "May they rest in peace.", + "Requiem" = "They will never reach truth.", + "Vade Retro" = "Having a gun might make exorcisms more effective, who knows?", + "Extra Nos" = "Salvation is given externally.", + "Ordo Salutis" = "First step? Fire.", + "Absolution" = "Free of your sins.", + "Rod of God" = "Splitting the red sea again.", + "Holy Grail" = "You found it!", + "Burning Bush" = "Useful for any burning ambush.", + "Judgement" = "First of all, damn. Alpha much? Dude, so cool, and so are you! Strong, too!", + "Paradiso" = "A divine end to the comedy of life.", + "DVNO" = "Don't need to ask my name to figure out how cool I am.", + "Venus Supermax" = "Did you know nearly everyone working and living on Venus is involved in sulfur extraction? Quite fitting for this weapon of gunpowder.", + "Nirvana" = "The giver of quietude, freedom, and highest happiness.", + "Cerebrum Dispersio" = "Latin for \"brain splitting\". How fitting.", + "Ultimort" = "Your hope dies last.", + "Lifelight" = "No escape, no greater fate to be made.", + "Bendbreaker" = "FRAGILE: Please do not bend or break.", + "Pop Pop" = "The name referring to an onomatopeia (phonetic imitation) of a gun firing.", + "Justice" = "Justice is Splendor.", + "Splendor" = "Splendor is Justice.", + "Revelation" = "Awaken your faith.", + "New Safety M62" = "This model of firearm is popular hundreds of years later due to masculine associations created by the film industry.", + "Unmaker" = "What the !@#%* is this!", + "INKVD" = "Savior of the soul and fighter against dirty thoughts.", + "Life Leech" = "An artifact said to draw its power from the life energy of others.", + "Nullray" = "Starless metal on the barrel imbibes light and routes it to the null place. The grip acrylic is patterned after ley lines.", + "Mortis" = "Put your faith into this weapon working.", + "Ramiel" = "Literally meaning \"God has thundered\". You could even interpret the gunshot as a thunder.", + "Daredevil" = "Hey now, you won't be reckless with this, will you?", + "Lacytanga" = "Rules are written by the strong.", + "A10" = "The fist of God. Keep away from the terrible.", + ) + +/obj/item/gun/ballistic/revolver/chaplain/Initialize(mapload) + . = ..() + AddComponent(/datum/component/anti_magic, MAGIC_RESISTANCE_HOLY) + name = pick(possible_names) + desc = possible_names[name] + +/obj/item/gun/ballistic/revolver/chaplain/suicide_act(mob/living/user) + . = ..() + name = "Habemus Papam" + desc = "I announce to you a great joy." + +/obj/item/gun/ballistic/revolver/chaplain/attack_self(mob/living/user) + pray_refill(user) + +/obj/item/gun/ballistic/revolver/chaplain/proc/pray_refill(mob/living/carbon/human/user) + if(DOING_INTERACTION_WITH_TARGET(user, src) || !istype(user)) + return + var/datum/brain_trauma/special/burdened/burden = user.has_trauma_type(/datum/brain_trauma/special/burdened) + if(needs_burden && (!burden || burden.burden_level < 9)) + to_chat(user, span_warning("You aren't burdened enough.")) + return + user.manual_emote("presses [user.p_their()] palms together...") + if(!do_after(user, 5 SECONDS, src)) + balloon_alert(user, "interrupted!") + return + user.say("#Oh great [GLOB.deity], give me the ammunition I need!", forced = "ammo prayer") + magazine.top_off() + user.playsound_local(get_turf(src), 'sound/magic/magic_block_holy.ogg', 50, TRUE) + chamber_round() + +/datum/action/item_action/pray_refill + name = "Refill" + desc = "Perform a prayer, to refill your weapon." + +/obj/item/ammo_box/magazine/internal/cylinder/rev77 + name = "chaplain revolver cylinder" + ammo_type = /obj/item/ammo_casing/c77 + caliber = CALIBER_77 + max_ammo = 5 + +/obj/item/ammo_casing/c77 + name = ".77 bullet casing" + desc = "A .77 bullet casing." + caliber = CALIBER_77 + projectile_type = /obj/projectile/bullet/c77 + custom_materials = null + +/obj/projectile/bullet/c77 + name = ".77 bullet" + damage = 18 + ricochets_max = 2 + ricochet_chance = 50 + ricochet_auto_aim_angle = 10 + ricochet_auto_aim_range = 3 + wound_bonus = -10 + embedding = null + +/datum/action/cooldown/spell/pointed/psychic_projection + name = "Psychic Projection" + desc = "Project your psychics into a target to warp their view, and instill absolute terror that will cause them to fire their gun rapidly." + ranged_mousepointer = 'icons/effects/mouse_pointers/cult_target.dmi' + button_icon_state = "blind" + school = SCHOOL_HOLY + cooldown_time = 1 MINUTES + antimagic_flags = MAGIC_RESISTANCE_MIND + spell_max_level = 1 + invocation_type = INVOCATION_NONE + spell_requirements = SPELL_REQUIRES_NO_ANTIMAGIC + cast_range = 5 + active_msg = "You prepare to psychically project to a target..." + /// Duration of the effects. + var/projection_duration = 10 SECONDS + +/datum/action/cooldown/spell/pointed/psychic_projection/is_valid_target(atom/cast_on) + . = ..() + if(!.) + return FALSE + if(!isliving(cast_on)) + return FALSE + var/mob/living/living_target = cast_on + return !living_target.has_status_effect(/datum/status_effect/psychic_projection) + +/datum/action/cooldown/spell/pointed/psychic_projection/cast(mob/living/cast_on) + . = ..() + if(cast_on.can_block_magic(antimagic_flags)) + to_chat(cast_on, span_notice("Your mind feels weird, but it passes momentarily.")) + to_chat(owner, span_warning("The spell had no effect!")) + return FALSE + to_chat(cast_on, span_userdanger("Your mind gets twisted!")) + cast_on.emote("scream") + cast_on.apply_status_effect(/datum/status_effect/psychic_projection, projection_duration) + return TRUE + +/// Status effect that adds a weird view to its owner and causes them to rapidly shoot a firearm in their general direction. +/datum/status_effect/psychic_projection + id = "psychic_projection" + alert_type = null + remove_on_fullheal = TRUE + tick_interval = 0.1 SECONDS + /// Times the target has dry fired a weapon. + var/times_dry_fired = 0 + /// Needs to reach times_dry_fired for the next dry fire to happen. + var/firing_delay = 0 + +/datum/status_effect/psychic_projection/on_creation(mob/living/new_owner, duration = 10 SECONDS) + src.duration = duration + return ..() + +/datum/status_effect/psychic_projection/on_apply() + var/atom/movable/plane_master_controller/game_plane_master_controller = owner.hud_used?.plane_master_controllers[PLANE_MASTERS_GAME] + if(!game_plane_master_controller) + return FALSE + game_plane_master_controller.add_filter("psychic_wave", 10, wave_filter(240, 240, 3, 0, WAVE_SIDEWAYS)) + game_plane_master_controller.add_filter("psychic_blur", 10, angular_blur_filter(0, 0, 3)) + return TRUE + +/datum/status_effect/psychic_projection/on_remove() + var/atom/movable/plane_master_controller/game_plane_master_controller = owner.hud_used?.plane_master_controllers[PLANE_MASTERS_GAME] + if(!game_plane_master_controller) + return + game_plane_master_controller.remove_filter("psychic_blur") + game_plane_master_controller.remove_filter("psychic_wave") + +/datum/status_effect/psychic_projection/tick(delta_time, times_fired) + var/obj/item/gun/held_gun = owner?.is_holding_item_of_type(/obj/item/gun) + if(!held_gun) + return + if(!held_gun.can_shoot()) + if(firing_delay < times_dry_fired) + firing_delay++ + return + firing_delay = 0 + times_dry_fired++ + else + times_dry_fired = 0 + var/turf/target_turf = get_offset_target_turf(get_ranged_target_turf(owner, owner.dir, 7), dx = rand(-1, 1), dy = rand(-1, 1)) + held_gun.process_fire(target_turf, owner, TRUE, null, pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG)) + held_gun.semicd = FALSE + +/datum/action/cooldown/spell/charged/psychic_booster + name = "Psychic Booster" + desc = "Charge up your mind to shoot firearms faster and home in on your targets. Think smarter, not harder." + button_icon_state = "projectile" + sound = 'sound/weapons/gun/shotgun/rack.ogg' + school = SCHOOL_HOLY + cooldown_time = 1 MINUTES + antimagic_flags = MAGIC_RESISTANCE_MIND + spell_max_level = 1 + invocation_type = INVOCATION_NONE + spell_requirements = SPELL_REQUIRES_NO_ANTIMAGIC + channel_message = span_notice("You focus on your trigger fingers...") + charge_overlay_icon = 'icons/effects/effects.dmi' + charge_overlay_state = "purplesparkles" + channel_time = 5 SECONDS + /// Are we currently active? + var/boosted = FALSE + /// How long the effect lasts for? + var/effect_time = 10 SECONDS + +/datum/action/cooldown/spell/charged/psychic_booster/Destroy() + if(boosted) + stop_effects() + return ..() + +/datum/action/cooldown/spell/charged/psychic_booster/Remove(mob/living/remove_from) + if(boosted) + stop_effects() + return ..() + +/datum/action/cooldown/spell/charged/psychic_booster/cast(atom/cast_on) + . = ..() + if(boosted) + return + boosted = TRUE + to_chat(owner, span_boldnotice("Your trigger fingers feel stronger.")) + ADD_TRAIT(cast_on, TRAIT_DOUBLE_TAP, type) + RegisterSignal(cast_on, COMSIG_PROJECTILE_FIRER_BEFORE_FIRE, PROC_REF(modify_projectile)) + addtimer(CALLBACK(src, PROC_REF(stop_effects)), effect_time) + +/datum/action/cooldown/spell/charged/psychic_booster/proc/stop_effects() + boosted = FALSE + to_chat(owner, span_danger("Your trigger fingers feel weaker.")) + REMOVE_TRAIT(owner, TRAIT_DOUBLE_TAP, type) + UnregisterSignal(owner, COMSIG_PROJECTILE_FIRER_BEFORE_FIRE) + +/datum/action/cooldown/spell/charged/psychic_booster/proc/modify_projectile(datum/source, obj/projectile/bullet, atom/firer, atom/original_target) + var/atom/target = original_target + if(isturf(target) || (isobj(target) && !target.density)) //if weird target, we try to compensate in our homing + for(var/mob/living/shooting_target in range(1, get_turf(target))) + if(shooting_target == firer) + continue + target = shooting_target + break + if(!bullet.can_hit_target(target, direct_target = TRUE, ignore_loc = TRUE)) + return + bullet.original = target + bullet.homing_turn_speed = 30 + bullet.set_homing_target(target) + +/datum/action/cooldown/spell/forcewall/psychic_wall + name = "Psychic Wall" + desc = "Form a psychic wall, able to deflect projectiles and prevent things from going through." + school = SCHOOL_HOLY + cooldown_time = 30 SECONDS + cooldown_reduction_per_rank = 0 SECONDS + antimagic_flags = MAGIC_RESISTANCE_MIND + spell_requirements = SPELL_REQUIRES_NO_ANTIMAGIC + spell_max_level = 1 + invocation_type = INVOCATION_NONE + wall_type = /obj/effect/forcefield/psychic + +/datum/action/cooldown/spell/forcewall/psychic_wall/spawn_wall(turf/cast_turf) + . = ..() + play_fov_effect(cast_turf, 5, "forcefield", time = 10 SECONDS) diff --git a/code/modules/religion/honorbound/honorbound_rites.dm b/code/modules/religion/honorbound/honorbound_rites.dm new file mode 100644 index 00000000000..2546c8a0b5b --- /dev/null +++ b/code/modules/religion/honorbound/honorbound_rites.dm @@ -0,0 +1,174 @@ +///Makes the person holy, but they now also have to follow the honorbound code (CBT). Actually earns favor, convincing others to uphold the code (tm) is not easy +/datum/religion_rites/deaconize + name = "Join Crusade" + desc = "Converts someone to your sect. They must be willing, so the first invocation will instead prompt them to join. \ + They will become honorbound like you, and you will gain a massive favor boost!" + ritual_length = 30 SECONDS + ritual_invocations = list( + "A good, honorable crusade against evil is required.", + "We need the righteous ...", + "... the unflinching ...", + "... and the just.", + "Sinners must be silenced ...", + ) + invoke_msg = "... And the code must be upheld!" + ///the invited crusader + var/mob/living/carbon/human/new_crusader + +/datum/religion_rites/deaconize/perform_rite(mob/living/user, atom/religious_tool) + var/datum/religion_sect/honorbound/sect = GLOB.religious_sect + if(!ismovable(religious_tool)) + to_chat(user, span_warning("This rite requires a religious device that individuals can be buckled to.")) + return FALSE + var/atom/movable/movable_reltool = religious_tool + if(!movable_reltool) + return FALSE + if(!LAZYLEN(movable_reltool.buckled_mobs)) + to_chat(user, span_warning("Nothing is buckled to the altar!")) + return FALSE + for(var/mob/living/carbon/human/possible_crusader in movable_reltool.buckled_mobs) + if(possible_crusader.stat != CONSCIOUS) + to_chat(user, span_warning("[possible_crusader] needs to be alive and conscious to join the crusade!")) + return FALSE + if(TRAIT_GENELESS in possible_crusader.dna.species.inherent_traits) + to_chat(user, span_warning("This species disgusts [GLOB.deity]! They would never be allowed to join the crusade!")) + return FALSE + if(possible_crusader in sect.currently_asking) + to_chat(user, span_warning("Wait for them to decide on whether to join or not!")) + return FALSE + if(!(possible_crusader in sect.possible_crusaders)) + INVOKE_ASYNC(sect, /datum/religion_sect/honorbound.proc/invite_crusader, possible_crusader) + to_chat(user, span_notice("They have been given the option to consider joining the crusade against evil. Wait for them to decide and try again.")) + return FALSE + new_crusader = possible_crusader + return ..() + +/datum/religion_rites/deaconize/invoke_effect(mob/living/carbon/human/user, atom/movable/religious_tool) + ..() + var/mob/living/carbon/human/joining_now = new_crusader + new_crusader = null + if(!(joining_now in religious_tool.buckled_mobs)) //checks one last time if the right corpse is still buckled + to_chat(user, span_warning("The new member is no longer on the altar!")) + return FALSE + if(joining_now.stat != CONSCIOUS) + to_chat(user, span_warning("The new member has to stay alive for the rite to work!")) + return FALSE + if(!joining_now.mind) + to_chat(user, span_warning("The new member has no mind!")) + return FALSE + if(joining_now.mind.has_antag_datum(/datum/antagonist/cult))//what the fuck?! + to_chat(user, span_warning("[GLOB.deity] has seen a true, dark evil in [joining_now]'s heart, and they have been smitten!")) + playsound(get_turf(religious_tool), 'sound/effects/pray.ogg', 50, TRUE) + joining_now.gib(TRUE) + return FALSE + var/datum/brain_trauma/special/honorbound/honor = user.has_trauma_type(/datum/brain_trauma/special/honorbound) + if(joining_now in honor.guilty) + honor.guilty -= joining_now + GLOB.religious_sect.adjust_favor(200, user) + to_chat(user, span_notice("[GLOB.deity] has bound [joining_now] to the code! They are now a holy role! (albeit the lowest level of such)")) + joining_now.mind.holy_role = HOLY_ROLE_DEACON + GLOB.religious_sect.on_conversion(joining_now) + playsound(get_turf(religious_tool), 'sound/effects/pray.ogg', 50, TRUE) + return TRUE + +///Mostly useless funny rite for forgiving someone, making them innocent once again. +/datum/religion_rites/forgive + name = "Forgive" + desc = "Forgives someone, making them no longer considered guilty. A kind gesture, all things considered!" + invoke_msg = "You are absolved of sin." + var/mob/living/who + +/datum/religion_rites/forgive/perform_rite(mob/living/carbon/human/user, atom/religious_tool) + if(!ishuman(user)) + return FALSE + var/datum/brain_trauma/special/honorbound/honor = user.has_trauma_type(/datum/brain_trauma/special/honorbound) + if(!honor) + return FALSE + if(!length(honor.guilty)) + to_chat(user, span_warning("[GLOB.deity] is holding no grudges to forgive.")) + return FALSE + var/forgiven_choice = tgui_input_list(user, "Choose one of [GLOB.deity]'s guilty to forgive", "Forgive", honor.guilty) + if(isnull(forgiven_choice)) + return FALSE + who = forgiven_choice + return ..() + +/datum/religion_rites/forgive/invoke_effect(mob/living/carbon/human/user, atom/movable/religious_tool) + ..() + if(in_range(user, religious_tool)) + return FALSE + var/datum/brain_trauma/special/honorbound/honor = user.has_trauma_type(/datum/brain_trauma/special/honorbound) + if(!honor) //edge case + return FALSE + honor.guilty -= who + who = null + playsound(get_turf(religious_tool), 'sound/effects/pray.ogg', 50, TRUE) + return TRUE + +/datum/religion_rites/summon_rules + name = "Summon Honorbound Rules" + desc = "Enscribes a paper with the honorbound rules and regulations." + invoke_msg = "Bring forth the holy writ!" + ///paper to turn into holy writ + var/obj/item/paper/writ_target + +/datum/religion_rites/summon_rules/perform_rite(mob/living/user, atom/religious_tool) + for(var/obj/item/paper/could_writ in get_turf(religious_tool)) + if(istype(could_writ, /obj/item/paper/holy_writ)) + continue + if(could_writ.get_total_length()) //blank paper pls + continue + writ_target = could_writ //PLEASE SIGN MY AUTOGRAPH + return ..() + to_chat(user, span_warning("You need to place blank paper on [religious_tool] to do this!")) + return FALSE + +/datum/religion_rites/summon_rules/invoke_effect(mob/living/user, atom/movable/religious_tool) + ..() + var/obj/item/paper/autograph = writ_target + var/turf/tool_turf = get_turf(religious_tool) + writ_target = null + if(QDELETED(autograph) || !(tool_turf == autograph.loc)) //check if the same food is still there + to_chat(user, span_warning("Your target left the altar!")) + return FALSE + autograph.visible_message(span_notice("Words magically form on [autograph]!")) + playsound(tool_turf, 'sound/effects/pray.ogg', 50, TRUE) + new /obj/item/paper/holy_writ(tool_turf) + qdel(autograph) + return TRUE + +/obj/item/paper/holy_writ + icon = 'icons/obj/wizard.dmi' + icon_state = "scroll" + slot_flags = null + show_written_words = FALSE + +//info set in here because we need GLOB.deity +/obj/item/paper/holy_writ/Initialize(mapload) + add_filter("holy_outline", 9, list("type" = "outline", "color" = "#fdff6c")) + name = "[GLOB.deity]'s honorbound rules" + default_raw_text = {"[GLOB.deity]'s honorbound rules: +
+ 1.) Thou shalt not attack the unready!
+ Those who are not ready for battle should not be wrought low. The evil of this world must lose + in a fair battle if you are to conquer them completely. +
+
+ 2.) Thou shalt not attack the just!
+ Those who fight for justice and good must not be harmed. Security is uncorruptable and must + be respected. Healers are mostly uncorruptable and if you are truly sure Medical has fallen + to the scourge of evil, use a declaration of evil. +
+
+ 3.) Thou shalt not attack the innocent!
+ There is no honor on a pre-emptive strike, unless they are truly evil vermin. + Those who are guilty will either lay a hand on you first, or you may declare their evil. +
+
+ 4.) Thou shalt not use profane magicks!
+ You are not a warlock, you are an honorable warrior. There is nothing more corruptive than + the vile magicks used by witches, warlocks, and necromancers. There are exceptions to this rule.
+ You may use holy magic, and, if you recruit one, the mime may use holy mimery. Restoration has also + been allowed as it is a school focused on the light and mending of this world. + "} + return ..() diff --git a/code/datums/mutations/holy_mutation/honorbound.dm b/code/modules/religion/honorbound/honorbound_trauma.dm similarity index 75% rename from code/datums/mutations/holy_mutation/honorbound.dm rename to code/modules/religion/honorbound/honorbound_trauma.dm index e4112afd104..9a0d632522f 100644 --- a/code/datums/mutations/holy_mutation/honorbound.dm +++ b/code/modules/religion/honorbound/honorbound_trauma.dm @@ -1,21 +1,14 @@ - ///Honorbound prevents you from attacking the unready, the just, or the innocent -/datum/mutation/human/honorbound - name = "Honorbound" - desc = "Less of a genome and more of a forceful rewrite of genes. Nothing Nanotrasen supplies allows for a genetic restructure like this... \ - The user feels compelled to follow supposed \"rules of combat\" but in reality they physically are unable to. \ - Their brain is rewired to excuse any curious inabilities that arise from this odd effect." - quality = POSITIVE //so it gets carried over on revives - power_path = /datum/action/cooldown/spell/pointed/declare_evil - locked = TRUE - text_gain_indication = "You feel honorbound!" - text_lose_indication = "You feel unshackled from your code of honor!" +/datum/brain_trauma/special/honorbound + name = "Dogmatic Compulsions" + desc = "Patient feels compelled to follow supposed \"rules of combat\"." + scan_desc = "damaged frontal lobe" + gain_text = span_notice("You feel honorbound!") + lose_text = span_warning("You feel unshackled from your code of honor!") /// list of guilty people var/list/guilty = list() -/datum/mutation/human/honorbound/on_acquiring(mob/living/carbon/human/owner) - if(..()) - return +/datum/brain_trauma/special/honorbound/on_gain() //moodlet owner.add_mood_event("honorbound", /datum/mood_event/honorbound) //checking spells cast by honorbound @@ -31,8 +24,11 @@ //signal that checks for dishonorable attacks RegisterSignal(owner, COMSIG_MOB_CLICKON, PROC_REF(attack_honor)) + var/datum/action/cooldown/spell/pointed/declare_evil = new(src) + declare_evil.Grant(owner) + return ..() -/datum/mutation/human/honorbound/on_losing(mob/living/carbon/human/owner) +/datum/brain_trauma/special/honorbound/on_lose(silent) owner.clear_mood_event("honorbound") UnregisterSignal(owner, list( COMSIG_PARENT_ATTACKBY, @@ -44,11 +40,11 @@ COMSIG_MOB_CLICKON, COMSIG_MOB_CAST_SPELL, COMSIG_MOB_FIRED_GUN, - )) - . = ..() + )) + return ..() -/// Signal to see if the mutation allows us to attack a target -/datum/mutation/human/honorbound/proc/attack_honor(mob/living/carbon/human/honorbound, atom/clickingon, list/modifiers) +/// Signal to see if the trauma allows us to attack a target +/datum/brain_trauma/special/honorbound/proc/attack_honor(mob/living/carbon/human/honorbound, atom/clickingon, list/modifiers) SIGNAL_HANDLER if(modifiers[ALT_CLICK] || modifiers[SHIFT_CLICK] || modifiers[CTRL_CLICK] || modifiers[MIDDLE_CLICK]) @@ -69,14 +65,14 @@ return (COMSIG_MOB_CANCEL_CLICKON) /** - * Called by hooked signals whenever someone attacks the person with this mutation + * Called by hooked signals whenever someone attacks the person with this trauma * Checks if the attacker should be considered guilty and adds them to the guilty list if true * * Arguments: * * user: person who attacked the honorbound * * declaration: if this wasn't an attack, but instead the honorbound spending favor on declaring this person guilty */ -/datum/mutation/human/honorbound/proc/guilty(mob/living/user, declaration = FALSE) +/datum/brain_trauma/special/honorbound/proc/guilty(mob/living/user, declaration = FALSE) if(user in guilty) return var/datum/mind/guilty_conscience = user.mind @@ -95,10 +91,10 @@ * Called by attack_honor signal to check whether an attack should be allowed or not * * Arguments: - * * honorbound_human: typecasted owner of mutation + * * honorbound_human: typecasted owner of the trauma * * target_creature: person honorbound_human is attacking */ -/datum/mutation/human/honorbound/proc/is_honorable(mob/living/carbon/human/honorbound_human, mob/living/target_creature) +/datum/brain_trauma/special/honorbound/proc/is_honorable(mob/living/carbon/human/honorbound_human, mob/living/target_creature) var/is_guilty = (target_creature in guilty) //THE UNREADY (Applies over ANYTHING else!) if(honorbound_human == target_creature) @@ -124,25 +120,25 @@ return TRUE // SIGNALS THAT ARE FOR BEING ATTACKED FIRST (GUILTY) -/datum/mutation/human/honorbound/proc/attackby_guilt(datum/source, obj/item/I, mob/attacker) +/datum/brain_trauma/special/honorbound/proc/attackby_guilt(datum/source, obj/item/I, mob/attacker) SIGNAL_HANDLER if(I.force && I.damtype != STAMINA) guilty(attacker) -/datum/mutation/human/honorbound/proc/hulk_guilt(datum/source, mob/attacker) +/datum/brain_trauma/special/honorbound/proc/hulk_guilt(datum/source, mob/attacker) SIGNAL_HANDLER guilty(attacker) -/datum/mutation/human/honorbound/proc/hand_guilt(datum/source, mob/living/attacker) +/datum/brain_trauma/special/honorbound/proc/hand_guilt(datum/source, mob/living/attacker) SIGNAL_HANDLER if(attacker.combat_mode) guilty(attacker) -/datum/mutation/human/honorbound/proc/paw_guilt(datum/source, mob/living/attacker) +/datum/brain_trauma/special/honorbound/proc/paw_guilt(datum/source, mob/living/attacker) SIGNAL_HANDLER guilty(attacker) -/datum/mutation/human/honorbound/proc/bullet_guilt(datum/source, obj/projectile/proj) +/datum/brain_trauma/special/honorbound/proc/bullet_guilt(datum/source, obj/projectile/proj) SIGNAL_HANDLER var/mob/living/shot_honorbound = source var/static/list/guilty_projectiles = typecacheof(list( @@ -157,7 +153,7 @@ if(!proj.nodamage && proj.damage < shot_honorbound.health && isliving(proj.firer)) guilty(proj.firer) -/datum/mutation/human/honorbound/proc/thrown_guilt(datum/source, atom/movable/thrown_movable, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum) +/datum/brain_trauma/special/honorbound/proc/thrown_guilt(datum/source, atom/movable/thrown_movable, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum) SIGNAL_HANDLER if(isitem(thrown_movable)) var/mob/living/honorbound = source @@ -167,11 +163,11 @@ guilty(thrown_by) //spell checking -/datum/mutation/human/honorbound/proc/spell_check(mob/user, datum/action/cooldown/spell/spell_cast) +/datum/brain_trauma/special/honorbound/proc/spell_check(mob/user, datum/action/cooldown/spell/spell_cast) SIGNAL_HANDLER punishment(user, spell_cast.school) -/datum/mutation/human/honorbound/proc/staff_check(mob/user, obj/item/gun/gun_fired, target, params, zone_override) +/datum/brain_trauma/special/honorbound/proc/staff_check(mob/user, obj/item/gun/gun_fired, target, params, zone_override) SIGNAL_HANDLER if(!istype(gun_fired, /obj/item/gun/magic)) return @@ -182,19 +178,19 @@ * Called when a spell is casted or a magic gun is fired, checks the signal and punishes accordingly * * Arguments: - * * user: typecasted owner of mutation + * * user: typecasted owner of trauma * * school: school of magic casted from the staff/spell */ -/datum/mutation/human/honorbound/proc/punishment(mob/living/carbon/human/user, school) +/datum/brain_trauma/special/honorbound/proc/punishment(mob/living/carbon/human/user, school) switch(school) if(SCHOOL_HOLY, SCHOOL_MIME, SCHOOL_RESTORATION) return if(SCHOOL_NECROMANCY, SCHOOL_FORBIDDEN, SCHOOL_SANGUINE) to_chat(user, span_userdanger("[GLOB.deity] is enraged by your use of forbidden magic!")) lightningbolt(user) - owner.add_mood_event("honorbound", /datum/mood_event/banished) - user.dna.remove_mutation(/datum/mutation/human/honorbound) user.mind.holy_role = NONE + qdel(src) + owner.add_mood_event("honorbound", /datum/mood_event/banished) //add mood event after we already cleared our events to_chat(user, span_userdanger("You have been excommunicated! You are no longer holy!")) else to_chat(user, span_userdanger("[GLOB.deity] is angered by your use of [school] magic!")) @@ -219,8 +215,8 @@ /// The amount of favor required to declare on someone var/required_favor = 150 - /// A ref to our owner's honorbound mutation - var/datum/mutation/human/honorbound/honor_mutation + /// A ref to our owner's honorbound trauma + var/datum/brain_trauma/special/honorbound/honor_trauma /// The declaration that's shouted in invocation. Set in New() var/declaration = "By the divine light of my deity, you are an evil of this world that must be wrought low!" @@ -230,9 +226,9 @@ /datum/action/cooldown/spell/pointed/declare_evil/Destroy() // If we had an owner, Destroy() called Remove(), and already handled this - if(honor_mutation) - UnregisterSignal(honor_mutation, COMSIG_PARENT_QDELETING) - honor_mutation = null + if(honor_trauma) + UnregisterSignal(honor_trauma, COMSIG_PARENT_QDELETING) + honor_trauma = null return ..() /datum/action/cooldown/spell/pointed/declare_evil/Grant(mob/grant_to) @@ -240,21 +236,21 @@ return FALSE var/mob/living/carbon/human/human_owner = grant_to - var/datum/mutation/human/honorbound/honor_mut = human_owner.dna?.check_mutation(/datum/mutation/human/honorbound) - if(QDELETED(honor_mut)) + var/datum/brain_trauma/special/honorbound/honorbound = human_owner.has_trauma_type(/datum/brain_trauma/special/honorbound) + if(QDELETED(honorbound)) return FALSE - RegisterSignal(honor_mut, COMSIG_PARENT_QDELETING, PROC_REF(on_honor_mutation_lost)) - honor_mutation = honor_mut + RegisterSignal(honorbound, COMSIG_PARENT_QDELETING, PROC_REF(on_honor_trauma_lost)) + honor_trauma = honorbound return ..() /datum/action/cooldown/spell/pointed/declare_evil/Remove(mob/living/remove_from) . = ..() - UnregisterSignal(honor_mutation, COMSIG_PARENT_QDELETING) - honor_mutation = null + UnregisterSignal(honor_trauma, COMSIG_PARENT_QDELETING) + honor_trauma = null -/// If we lose our honor mutation somehow, self-delete (and clear references) -/datum/action/cooldown/spell/pointed/declare_evil/proc/on_honor_mutation_lost(datum/source) +/// If we lose our honor trauma somehow, self-delete (and clear references) +/datum/action/cooldown/spell/pointed/declare_evil/proc/on_honor_trauma_lost(datum/source) SIGNAL_HANDLER qdel(src) @@ -264,9 +260,6 @@ if(!.) return FALSE - // This shouldn't technically be a possible state, but you never know - if(!honor_mutation) - return FALSE if(GLOB.religious_sect.favor < required_favor) if(feedback) to_chat(owner, span_warning("You need at least 150 favor to declare someone evil!")) @@ -315,4 +308,4 @@ /datum/action/cooldown/spell/pointed/declare_evil/cast(mob/living/cast_on) . = ..() GLOB.religious_sect.adjust_favor(-required_favor, owner) - honor_mutation.guilty(cast_on, declaration = TRUE) + honor_trauma.guilty(cast_on, declaration = TRUE) diff --git a/code/modules/religion/religion_sects.dm b/code/modules/religion/religion_sects.dm index d5b3a7041cb..8dae39b1a62 100644 --- a/code/modules/religion/religion_sects.dm +++ b/code/modules/religion/religion_sects.dm @@ -20,8 +20,6 @@ var/alignment = ALIGNMENT_GOOD /// Does this require something before being available as an option? var/starter = TRUE - /// species traits that block you from picking - var/invalidating_qualities = NONE /// The Sect's 'Mana' var/favor = 0 //MANA! /// The max amount of favor the sect can have @@ -271,6 +269,33 @@ #undef GREEDY_HEAL_COST +/datum/religion_sect/burden + name = "Punished God" + quote = "To feel the freedom, you must first understand captivity." + desc = "Incapacitate yourself in any way possible. Bad mutations, lost limbs, traumas, \ + even addictions. You will learn the secrets of the universe from your defeated shell." + tgui_icon = "user-injured" + altar_icon_state = "convertaltar-burden" + alignment = ALIGNMENT_NEUT + candle_overlay = FALSE + rites_list = list(/datum/religion_rites/nullrod_transformation) + +/datum/religion_sect/burden/on_conversion(mob/living/carbon/human/new_convert) + ..() + if(!ishuman(new_convert)) + to_chat(new_convert, span_warning("[GLOB.deity] needs higher level creatures to fully comprehend the suffering. You are not burdened.")) + return + new_convert.gain_trauma(/datum/brain_trauma/special/burdened, TRAUMA_RESILIENCE_MAGIC) + +/datum/religion_sect/burden/tool_examine(mob/living/carbon/human/burdened) //display burden level + if(!ishuman(burdened)) + return FALSE + var/datum/brain_trauma/special/burdened/burden = burdened.has_trauma_type(/datum/brain_trauma/special/burdened) + if(burden) + return "You are at burden level [burden.burden_level]/9." + return "You are not burdened." + + /datum/religion_sect/honorbound name = "Honorbound God" quote = "A good, honorable crusade against evil is required." @@ -279,7 +304,6 @@ tgui_icon = "scroll" altar_icon_state = "convertaltar-white" alignment = ALIGNMENT_GOOD - invalidating_qualities = TRAIT_GENELESS rites_list = list(/datum/religion_rites/deaconize, /datum/religion_rites/forgive, /datum/religion_rites/summon_rules) ///people who have agreed to join the crusade, and can be deaconized var/list/possible_crusaders = list() @@ -302,41 +326,7 @@ if(!ishuman(new_convert)) to_chat(new_convert, span_warning("[GLOB.deity] has no respect for lower creatures, and refuses to make you honorbound.")) return FALSE - if(TRAIT_GENELESS in new_convert.dna.species.inherent_traits) - to_chat(new_convert, span_warning("[GLOB.deity] has deemed your species as one that could never show honor.")) - return FALSE - var/datum/dna/holy_dna = new_convert.dna - holy_dna.add_mutation(/datum/mutation/human/honorbound) - -/datum/religion_sect/burden - name = "Punished God" - quote = "To feel the freedom, you must first understand captivity." - desc = "Incapacitate yourself in any way possible. Bad mutations, lost limbs, traumas, \ - even addictions. You will learn the secrets of the universe from your defeated shell." - tgui_icon = "user-injured" - altar_icon_state = "convertaltar-burden" - alignment = ALIGNMENT_NEUT - invalidating_qualities = TRAIT_GENELESS - candle_overlay = FALSE - -/datum/religion_sect/burden/on_conversion(mob/living/carbon/human/new_convert) - ..() - if(!ishuman(new_convert)) - to_chat(new_convert, span_warning("[GLOB.deity] needs higher level creatures to fully comprehend the suffering. You are not burdened.")) - return - if(TRAIT_GENELESS in new_convert.dna.species.inherent_traits) - to_chat(new_convert, span_warning("[GLOB.deity] cannot help a species such as yourself comprehend the suffering. You are not burdened.")) - return - var/datum/dna/holy_dna = new_convert.dna - holy_dna.add_mutation(/datum/mutation/human/burdened) - -/datum/religion_sect/burden/tool_examine(mob/living/carbon/human/burdened) //display burden level - if(!ishuman(burdened)) - return FALSE - var/datum/mutation/human/burdened/burdenmut = burdened.dna.check_mutation(/datum/mutation/human/burdened) - if(burdenmut) - return "You are at burden level [burdenmut.burden_level]/6." - return "You are not burdened." + new_convert.gain_trauma(/datum/brain_trauma/special/honorbound, TRAUMA_RESILIENCE_MAGIC) #define MINIMUM_YUCK_REQUIRED 5 diff --git a/code/modules/religion/rites.dm b/code/modules/religion/rites.dm index 8bbc957a47b..f634f1380c0 100644 --- a/code/modules/religion/rites.dm +++ b/code/modules/religion/rites.dm @@ -129,14 +129,16 @@ ..() var/altar_turf = get_turf(religious_tool) var/blessing = pick( - /obj/item/organ/internal/cyberimp/arm/surgery, - /obj/item/organ/internal/cyberimp/eyes/hud/diagnostic, - /obj/item/organ/internal/cyberimp/eyes/hud/medical, - /obj/item/organ/internal/cyberimp/mouth/breathing_tube, - /obj/item/organ/internal/cyberimp/chest/thrusters, - /obj/item/organ/internal/eyes/robotic/glow) + /obj/item/organ/internal/cyberimp/arm/surgery, + /obj/item/organ/internal/cyberimp/eyes/hud/diagnostic, + /obj/item/organ/internal/cyberimp/eyes/hud/medical, + /obj/item/organ/internal/cyberimp/mouth/breathing_tube, + /obj/item/organ/internal/cyberimp/chest/thrusters, + /obj/item/organ/internal/eyes/robotic/glow, + ) new blessing(altar_turf) return TRUE + /**** Pyre God ****/ ///apply a bunch of fire immunity effect to clothing @@ -307,182 +309,6 @@ playsound(get_turf(religious_tool), 'sound/effects/cashregister.ogg', 60, TRUE) return TRUE -/*********Honorbound God**********/ - -///Makes the person holy, but they now also have to follow the honorbound code (CBT). Actually earns favor, convincing others to uphold the code (tm) is not easy -/datum/religion_rites/deaconize - name = "Join Crusade" - desc = "Converts someone to your sect. They must be willing, so the first invocation will instead prompt them to join. \ - They will become honorbound like you, and you will gain a massive favor boost!" - ritual_length = 30 SECONDS - ritual_invocations = list( - "A good, honorable crusade against evil is required.", - "We need the righteous ...", - "... the unflinching ...", - "... and the just.", - "Sinners must be silenced ...",) - invoke_msg = "... And the code must be upheld!" - ///the invited crusader - var/mob/living/carbon/human/new_crusader - -/datum/religion_rites/deaconize/perform_rite(mob/living/user, atom/religious_tool) - var/datum/religion_sect/honorbound/sect = GLOB.religious_sect - if(!ismovable(religious_tool)) - to_chat(user, span_warning("This rite requires a religious device that individuals can be buckled to.")) - return FALSE - var/atom/movable/movable_reltool = religious_tool - if(!movable_reltool) - return FALSE - if(!LAZYLEN(movable_reltool.buckled_mobs)) - to_chat(user, span_warning("Nothing is buckled to the altar!")) - return FALSE - for(var/mob/living/carbon/human/possible_crusader in movable_reltool.buckled_mobs) - if(possible_crusader.stat != CONSCIOUS) - to_chat(user, span_warning("[possible_crusader] needs to be alive and conscious to join the crusade!")) - return FALSE - if(TRAIT_GENELESS in possible_crusader.dna.species.inherent_traits) - to_chat(user, span_warning("This species disgusts [GLOB.deity]! They would never be allowed to join the crusade!")) - return FALSE - if(possible_crusader in sect.currently_asking) - to_chat(user, span_warning("Wait for them to decide on whether to join or not!")) - return FALSE - if(!(possible_crusader in sect.possible_crusaders)) - INVOKE_ASYNC(sect, TYPE_PROC_REF(/datum/religion_sect/honorbound, invite_crusader), possible_crusader) - to_chat(user, span_notice("They have been given the option to consider joining the crusade against evil. Wait for them to decide and try again.")) - return FALSE - new_crusader = possible_crusader - return ..() - -/datum/religion_rites/deaconize/invoke_effect(mob/living/carbon/human/user, atom/movable/religious_tool) - ..() - var/mob/living/carbon/human/joining_now = new_crusader - new_crusader = null - if(!(joining_now in religious_tool.buckled_mobs)) //checks one last time if the right corpse is still buckled - to_chat(user, span_warning("The new member is no longer on the altar!")) - return FALSE - if(joining_now.stat != CONSCIOUS) - to_chat(user, span_warning("The new member has to stay alive for the rite to work!")) - return FALSE - if(!joining_now.mind) - to_chat(user, span_warning("The new member has no mind!")) - return FALSE - if(joining_now.mind.has_antag_datum(/datum/antagonist/cult))//what the fuck?! - to_chat(user, span_warning("[GLOB.deity] has seen a true, dark evil in [joining_now]'s heart, and they have been smitten!")) - playsound(get_turf(religious_tool), 'sound/effects/pray.ogg', 50, TRUE) - joining_now.gib(TRUE) - return FALSE - var/datum/mutation/human/honorbound/honormut = user.dna.check_mutation(/datum/mutation/human/honorbound) - if(joining_now in honormut.guilty) - honormut.guilty -= joining_now - GLOB.religious_sect.adjust_favor(200, user) - to_chat(user, span_notice("[GLOB.deity] has bound [joining_now] to the code! They are now a holy role! (albeit the lowest level of such)")) - joining_now.mind.holy_role = HOLY_ROLE_DEACON - GLOB.religious_sect.on_conversion(joining_now) - playsound(get_turf(religious_tool), 'sound/effects/pray.ogg', 50, TRUE) - return TRUE - -///Mostly useless funny rite for forgiving someone, making them innocent once again. -/datum/religion_rites/forgive - name = "Forgive" - desc = "Forgives someone, making them no longer considered guilty. A kind gesture, all things considered!" - invoke_msg = "You are absolved of sin." - var/mob/living/who - -/datum/religion_rites/forgive/perform_rite(mob/living/carbon/human/user, atom/religious_tool) - if(!ishuman(user)) - return FALSE - var/datum/mutation/human/honorbound/honormut = user.dna.check_mutation(/datum/mutation/human/honorbound) - if(!honormut) - return FALSE - if(!length(honormut.guilty)) - to_chat(user, span_warning("[GLOB.deity] is holding no grudges to forgive.")) - return FALSE - var/forgiven_choice = tgui_input_list(user, "Choose one of [GLOB.deity]'s guilty to forgive", "Forgive", honormut.guilty) - if(isnull(forgiven_choice)) - return FALSE - who = forgiven_choice - return ..() - -/datum/religion_rites/forgive/invoke_effect(mob/living/carbon/human/user, atom/movable/religious_tool) - ..() - if(in_range(user, religious_tool)) - return FALSE - var/datum/mutation/human/honorbound/honormut = user.dna.check_mutation(/datum/mutation/human/honorbound) - if(!honormut) //edge case - return FALSE - honormut.guilty -= who - who = null - playsound(get_turf(religious_tool), 'sound/effects/pray.ogg', 50, TRUE) - return TRUE - -/datum/religion_rites/summon_rules - name = "Summon Honorbound Rules" - desc = "Enscribes a paper with the honorbound rules and regulations." - invoke_msg = "Bring forth the holy writ!" - ///paper to turn into holy writ - var/obj/item/paper/writ_target - -/datum/religion_rites/summon_rules/perform_rite(mob/living/user, atom/religious_tool) - for(var/obj/item/paper/could_writ in get_turf(religious_tool)) - if(istype(could_writ, /obj/item/paper/holy_writ)) - continue - if(could_writ.get_total_length()) //blank paper pls - continue - writ_target = could_writ //PLEASE SIGN MY AUTOGRAPH - return ..() - to_chat(user, span_warning("You need to place blank paper on [religious_tool] to do this!")) - return FALSE - -/datum/religion_rites/summon_rules/invoke_effect(mob/living/user, atom/movable/religious_tool) - ..() - var/obj/item/paper/autograph = writ_target - var/turf/tool_turf = get_turf(religious_tool) - writ_target = null - if(QDELETED(autograph) || !(tool_turf == autograph.loc)) //check if the same food is still there - to_chat(user, span_warning("Your target left the altar!")) - return FALSE - autograph.visible_message(span_notice("Words magically form on [autograph]!")) - playsound(tool_turf, 'sound/effects/pray.ogg', 50, TRUE) - new /obj/item/paper/holy_writ(tool_turf) - qdel(autograph) - return TRUE - -/obj/item/paper/holy_writ - icon = 'icons/obj/wizard.dmi' - icon_state = "scroll" - slot_flags = null - show_written_words = FALSE - - //info set in here because we need GLOB.deity -/obj/item/paper/holy_writ/Initialize(mapload) - add_filter("holy_outline", 9, list("type" = "outline", "color" = "#fdff6c")) - name = "[GLOB.deity]'s honorbound rules" - default_raw_text = {"[GLOB.deity]'s honorbound rules: -
- 1.) Thou shalt not attack the unready!
- Those who are not ready for battle should not be wrought low. The evil of this world must lose - in a fair battle if you are to conquer them completely. -
-
- 2.) Thou shalt not attack the just!
- Those who fight for justice and good must not be harmed. Security is uncorruptable and must - be respected. Healers are mostly uncorruptable and if you are truly sure Medical has fallen - to the scourge of evil, use a declaration of evil. -
-
- 3.) Thou shalt not attack the innocent!
- There is no honor on a pre-emptive strike, unless they are truly evil vermin. - Those who are guilty will either lay a hand on you first, or you may declare their evil. -
-
- 4.) Thou shalt not use profane magicks!
- You are not a warlock, you are an honorable warrior. There is nothing more corruptive than - the vile magicks used by witches, warlocks, and necromancers. There are exceptions to this rule.
- You may use holy magic, and, if you recruit one, the mime may use holy mimery. Restoration has also - been allowed as it is a school focused on the light and mending of this world. - "} - . = ..() - /*********Maintenance God**********/ /datum/religion_rites/maint_adaptation @@ -507,7 +333,7 @@ /datum/religion_rites/maint_adaptation/invoke_effect(mob/living/user, atom/movable/religious_tool) ..() to_chat(user, span_warning("You feel your genes rattled and reshaped. You're becoming something new.")) - user.emote("laughs") + user.emote("laugh") ADD_TRAIT(user, TRAIT_HOPELESSLY_ADDICTED, "maint_adaptation") //addiction sends some nasty mood effects but we want the maint adaption to be enjoyed like a fine wine user.add_mood_event("maint_adaptation", /datum/mood_event/maintenance_adaptation) @@ -574,7 +400,7 @@ to_chat(user, span_warning("Your target left the altar!")) return FALSE to_chat(user, span_warning("[moldify] becomes rancid!")) - user.emote("laughs") + user.emote("laugh") new /obj/item/food/badrecipe/moldy(get_turf(religious_tool)) qdel(moldify) return TRUE @@ -605,7 +431,7 @@ to_chat(user, span_warning("[padala] reshapes into a totem!")) if(!padala.use(1))//use one wood return - user.emote("laughs") + user.emote("laugh") new /obj/item/ritual_totem(altar_turf) return TRUE diff --git a/code/modules/spells/spell_types/charged/_charged.dm b/code/modules/spells/spell_types/charged/_charged.dm index 7646f763956..9cd81c0a834 100644 --- a/code/modules/spells/spell_types/charged/_charged.dm +++ b/code/modules/spells/spell_types/charged/_charged.dm @@ -11,6 +11,8 @@ var/currently_channeling = FALSE /// How long it takes to channel the spell. var/channel_time = 10 SECONDS + /// Flags of the do_after + var/channel_flags = IGNORE_USER_LOC_CHANGE|IGNORE_HELD_ITEM // Overlay optional, applied when we start channelling /// What icon should we use for our overlay @@ -75,7 +77,7 @@ currently_channeling = TRUE UpdateButtons(status_only = TRUE) - if(!do_after(cast_on, channel_time, timed_action_flags = (IGNORE_USER_LOC_CHANGE|IGNORE_HELD_ITEM))) + if(!do_after(cast_on, channel_time, timed_action_flags = channel_flags)) stop_channel_effect(cast_on) return . | SPELL_CANCEL_CAST diff --git a/code/modules/spells/spell_types/self/forcewall.dm b/code/modules/spells/spell_types/self/forcewall.dm index 150338a2db0..7a718949845 100644 --- a/code/modules/spells/spell_types/self/forcewall.dm +++ b/code/modules/spells/spell_types/self/forcewall.dm @@ -17,15 +17,16 @@ /datum/action/cooldown/spell/forcewall/cast(atom/cast_on) . = ..() - new wall_type(get_turf(owner), owner) + for(var/turf/cast_turf as anything in get_turfs()) + spawn_wall(cast_turf) - if(owner.dir == SOUTH || owner.dir == NORTH) - new wall_type(get_step(owner, EAST), owner, antimagic_flags) - new wall_type(get_step(owner, WEST), owner, antimagic_flags) +/// This proc returns all the turfs on which we will spawn the walls. +/datum/action/cooldown/spell/forcewall/proc/get_turfs() + return list(get_turf(owner), get_step(owner, turn(owner.dir, 90)), get_step(owner, turn(owner.dir, 270))) - else - new wall_type(get_step(owner, NORTH), owner, antimagic_flags) - new wall_type(get_step(owner, SOUTH), owner, antimagic_flags) +/// This proc spawns a wall on the given turf. +/datum/action/cooldown/spell/forcewall/proc/spawn_wall(turf/cast_turf) + new wall_type(cast_turf, owner, antimagic_flags) /datum/action/cooldown/spell/forcewall/cult name = "Shield" diff --git a/code/modules/surgery/organ_manipulation.dm b/code/modules/surgery/organ_manipulation.dm index 023aa4d414e..4c6ffba81b4 100644 --- a/code/modules/surgery/organ_manipulation.dm +++ b/code/modules/surgery/organ_manipulation.dm @@ -186,28 +186,31 @@ else return SURGERY_STEP_FAIL -/datum/surgery_step/manipulate_organs/success(mob/living/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results) +/datum/surgery_step/manipulate_organs/success(mob/living/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE) if (target_zone == BODY_ZONE_PRECISE_EYES) target_zone = check_zone(target_zone) if(current_type == "insert") + var/obj/item/apparatus if(istype(tool, /obj/item/borg/apparatus/organ_storage)) - target_organ = tool.contents[1] - tool.icon_state = initial(tool.icon_state) - tool.desc = initial(tool.desc) - tool.cut_overlays() - tool = target_organ - else - target_organ = tool + apparatus = tool + tool = tool.contents[1] + target_organ = tool user.temporarilyRemoveItemFromInventory(target_organ, TRUE) - target_organ.Insert(target) - display_results( - user, - target, - span_notice("You insert [tool] into [target]'s [parse_zone(target_zone)]."), - span_notice("[user] inserts [tool] into [target]'s [parse_zone(target_zone)]!"), - span_notice("[user] inserts something into [target]'s [parse_zone(target_zone)]!"), - ) - display_pain(target, "Your [parse_zone(target_zone)] throbs with pain as your new [tool] comes to life!") + if(target_organ.Insert(target)) + if(apparatus) + apparatus.icon_state = initial(apparatus.icon_state) + apparatus.desc = initial(apparatus.desc) + apparatus.cut_overlays() + display_results( + user, + target, + span_notice("You insert [tool] into [target]'s [parse_zone(target_zone)]."), + span_notice("[user] inserts [tool] into [target]'s [parse_zone(target_zone)]!"), + span_notice("[user] inserts something into [target]'s [parse_zone(target_zone)]!"), + ) + display_pain(target, "Your [parse_zone(target_zone)] throbs with pain as your new [tool] comes to life!") + else + target_organ.forceMove(target.loc) else if(current_type == "extract") if(target_organ && target_organ.owner == target) @@ -230,7 +233,7 @@ span_notice("[user] can't seem to extract anything from [target]'s [parse_zone(target_zone)]!"), span_notice("[user] can't seem to extract anything from [target]'s [parse_zone(target_zone)]!"), ) - return FALSE + return ..() ///You can never use this MUHAHAHAHAHAHAH (because its the byond version of abstract) /datum/surgery_step/manipulate_organs/proc/can_use_organ(mob/user, obj/item/organ/organ) diff --git a/code/modules/vehicles/cars/clowncar.dm b/code/modules/vehicles/cars/clowncar.dm index bdfbf8def77..c7f3828bfa3 100644 --- a/code/modules/vehicles/cars/clowncar.dm +++ b/code/modules/vehicles/cars/clowncar.dm @@ -201,9 +201,9 @@ visible_message(span_danger("[user] presses one of the colorful buttons on [src], and the clown car lets out a comedic toot.")) playsound(src, 'sound/vehicles/clowncar_fart.ogg', 100) for(var/mob/living/L in orange(loc, 6)) - L.emote("laughs") + L.emote("laugh") for(var/mob/living/L as anything in occupants) - L.emote("laughs") + L.emote("laugh") ///resets the icon and iconstate of the clowncar after it was set to singulo states /obj/vehicle/sealed/car/clowncar/proc/reset_icon() diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index 006679c3696..04fa29c44dc 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/icons/effects/fov/fov_effects.dmi b/icons/effects/fov/fov_effects.dmi index 2ba9d11f579..877f4ad8062 100644 Binary files a/icons/effects/fov/fov_effects.dmi and b/icons/effects/fov/fov_effects.dmi differ diff --git a/icons/effects/particles/echo.dmi b/icons/effects/particles/echo.dmi new file mode 100644 index 00000000000..a7a47e340d1 Binary files /dev/null and b/icons/effects/particles/echo.dmi differ diff --git a/icons/hud/screen_full.dmi b/icons/hud/screen_full.dmi index 1025f15e82f..0c2ed898030 100644 Binary files a/icons/hud/screen_full.dmi and b/icons/hud/screen_full.dmi differ diff --git a/icons/mob/species/human/bodyparts.dmi b/icons/mob/species/human/bodyparts.dmi index 187dd2738f5..642489e4787 100644 Binary files a/icons/mob/species/human/bodyparts.dmi and b/icons/mob/species/human/bodyparts.dmi differ diff --git a/icons/obj/medical/organs/organs.dmi b/icons/obj/medical/organs/organs.dmi index 8402814dcd0..90708c26cc2 100644 Binary files a/icons/obj/medical/organs/organs.dmi and b/icons/obj/medical/organs/organs.dmi differ diff --git a/icons/obj/weapons/guns/ballistic.dmi b/icons/obj/weapons/guns/ballistic.dmi index 74ad5d2ec80..f73f411f720 100644 Binary files a/icons/obj/weapons/guns/ballistic.dmi and b/icons/obj/weapons/guns/ballistic.dmi differ diff --git a/icons/turf/floors.dmi b/icons/turf/floors.dmi index a30071be427..024c3917161 100644 Binary files a/icons/turf/floors.dmi and b/icons/turf/floors.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 3c9fc0746ec..3e752cf7408 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -816,6 +816,7 @@ #include "code\datums\components\deployable.dm" #include "code\datums\components\drift.dm" #include "code\datums\components\earprotection.dm" +#include "code\datums\components\echolocation.dm" #include "code\datums\components\edit_complainer.dm" #include "code\datums\components\effect_remover.dm" #include "code\datums\components\egg_layer.dm" @@ -1220,8 +1221,6 @@ #include "code\datums\mutations\touch.dm" #include "code\datums\mutations\void_magnet.dm" #include "code\datums\mutations\webbing.dm" -#include "code\datums\mutations\holy_mutation\burdened.dm" -#include "code\datums\mutations\holy_mutation\honorbound.dm" #include "code\datums\proximity_monitor\field.dm" #include "code\datums\proximity_monitor\proximity_monitor.dm" #include "code\datums\proximity_monitor\fields\gravity.dm" @@ -4312,8 +4311,12 @@ #include "code\modules\religion\religion_sects.dm" #include "code\modules\religion\religion_structures.dm" #include "code\modules\religion\rites.dm" +#include "code\modules\religion\burdened\burdened_trauma.dm" +#include "code\modules\religion\burdened\psyker.dm" #include "code\modules\religion\festival\instrument_rites.dm" #include "code\modules\religion\festival\note_particles.dm" +#include "code\modules\religion\honorbound\honorbound_rites.dm" +#include "code\modules\religion\honorbound\honorbound_trauma.dm" #include "code\modules\religion\sparring\ceremonial_gear.dm" #include "code\modules\religion\sparring\sparring_contract.dm" #include "code\modules\religion\sparring\sparring_datum.dm"