diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index 7f22ae63eeeb..588403bde53f 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -6,6 +6,8 @@ #define STATUS_EFFECT_REPLACE 2 /// if it only allows one, and new instances just instead refresh the timer #define STATUS_EFFECT_REFRESH 3 +/// if it only allows one, and new instances add to the timer +#define STATUS_EFFECT_EXTEND 4 ///Processing flags - used to define the speed at which the status will work ///This is fast - 0.2s between ticks (I believe!) diff --git a/code/_compile_options.dm b/code/_compile_options.dm index cc59b091b212..ff1e09cfbf39 100644 --- a/code/_compile_options.dm +++ b/code/_compile_options.dm @@ -162,7 +162,7 @@ /////////////////////// MISC PERFORMANCE //uncomment this to load centcom and runtime station and thats it. -// #define LOWMEMORYMODE +#define LOWMEMORYMODE //uncomment to enable the spatial grid debug proc. // #define SPATIAL_GRID_ZLEVEL_STATS @@ -243,6 +243,7 @@ #ifdef LOWMEMORYMODE #define FORCE_MAP "runtimestation" #define FORCE_MAP_DIRECTORY "_maps" +#warn LOW MEMORY MODE ENABLED. #endif #ifdef DEBUG diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 64840acd27c7..d35c02506d6b 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -36,6 +36,9 @@ var/mob/living/current var/active = FALSE + /// A copy of a corpse appearance, set when transferring a mind to a brainmob. + var/mutable_appearance/body_appearance + ///a list of /datum/memories. assoc type of memory = memory datum. only one type of memory will be stored, new ones of the same type overriding the last. var/list/memories = list() ///reference to the memory panel tgui diff --git a/code/datums/status_effects/_status_effect.dm b/code/datums/status_effects/_status_effect.dm index 438d498bb0b0..0bded6ef0486 100644 --- a/code/datums/status_effects/_status_effect.dm +++ b/code/datums/status_effects/_status_effect.dm @@ -129,12 +129,20 @@ /// Called when a status effect of status_type STATUS_EFFECT_REFRESH /// has its duration refreshed in apply_status_effect - is passed New() args -/datum/status_effect/proc/refresh(effect, ...) +/datum/status_effect/proc/refresh(mob/living/parent, effect_path, ...) var/original_duration = initial(duration) if(original_duration == -1) return duration = world.time + original_duration +/// Called when a status effect of status_type STATUS_EFFECT_EXTEND +/// has its duration extended in apply_status_effect - is passed New() args +/datum/status_effect/proc/extend(mob/living/parent, effect_path, ...) + var/original_duration = initial(duration) + if(original_duration == -1) + return + duration += original_duration + /// Adds nextmove modifier multiplicatively to the owner while applied /datum/status_effect/proc/nextmove_modifier() return 1 diff --git a/code/datums/status_effects/_status_effect_helpers.dm b/code/datums/status_effects/_status_effect_helpers.dm index 9cd5f4f3c866..4b6358c72ded 100644 --- a/code/datums/status_effects/_status_effect_helpers.dm +++ b/code/datums/status_effects/_status_effect_helpers.dm @@ -35,8 +35,13 @@ existing_effect.be_replaced() // Refresh the existing type, then early return if(STATUS_EFFECT_REFRESH) + arguments.Insert(1, new_effect) existing_effect.refresh(arglist(arguments)) return + if(STATUS_EFFECT_EXTEND) + arguments.Insert(1, new_effect) + existing_effect.extend(arglist(arguments)) + return // Create the status effect with our mob + our arguments var/datum/status_effect/new_instance = new new_effect(arguments) diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm index d7a939f18dea..bedee1a24d85 100644 --- a/code/datums/status_effects/debuffs/debuffs.dm +++ b/code/datums/status_effects/debuffs/debuffs.dm @@ -217,7 +217,7 @@ var/delta = world.time - last_dead_time var/new_timeofdeath = owner.timeofdeath + delta owner.timeofdeath = new_timeofdeath - owner.tod = stationtime2text(reference_time=new_timeofdeath) + owner.timeofdeath_as_ingame = stationtime2text(reference_time=new_timeofdeath) last_dead_time = null if(owner.stat == DEAD) last_dead_time = world.time diff --git a/code/datums/status_effects/skill_modifiers/negative.dm b/code/datums/status_effects/skill_modifiers/negative.dm index efe160a74d5f..7797b4c78b07 100644 --- a/code/datums/status_effects/skill_modifiers/negative.dm +++ b/code/datums/status_effects/skill_modifiers/negative.dm @@ -1,22 +1 @@ -/datum/status_effect/skill_mod/witness_death - status_type = STATUS_EFFECT_REFRESH - duration = 20 MINUTES - - skill_path = /datum/rpg_skill/willpower - modify_amt = -1 - source = SKILL_SOURCE_WITNESS_DEATH - -/datum/status_effect/skill_mod/witness_death/on_apply() - if(!owner.stats.cooldown_finished("death_resolve")) - return FALSE - return ..() - -/datum/status_effect/skill_mod/witness_death/on_remove() - var/datum/roll_result/result = owner.stat_roll(13, /datum/rpg_skill/willpower) - switch(result.outcome) - if(CRIT_SUCCESS, SUCCESS) - to_chat(owner, result.create_tooltip("You come to terms with past events, strengthing your resolve for the road ahead.")) - owner.stats.set_cooldown("death_resolve", INFINITY) - owner.stats.set_skill_modifier(1, /datum/rpg_skill/willpower, SKILL_SOURCE_DEATH_RESOLVE) - - return ..() +//placeholder file diff --git a/code/datums/status_effects/skill_modifiers/positive.dm b/code/datums/status_effects/skill_modifiers/positive.dm new file mode 100644 index 000000000000..e4185eef3f41 --- /dev/null +++ b/code/datums/status_effects/skill_modifiers/positive.dm @@ -0,0 +1,9 @@ +/// Reward for sanctifying corpses +/datum/status_effect/skill_mod/sanctify_corpse + duration = 20 MINUTES + status_type = STATUS_EFFECT_EXTEND + + skill_path = /datum/rpg_skill/willpower + modify_amt = 1 + source = "Sanctified a corpse." + diff --git a/code/datums/status_effects/skill_modifiers/rpg_modifiers.dm b/code/datums/status_effects/skill_modifiers/rpg_modifiers.dm index 1e5c4e82b4b7..671806011dbb 100644 --- a/code/datums/status_effects/skill_modifiers/rpg_modifiers.dm +++ b/code/datums/status_effects/skill_modifiers/rpg_modifiers.dm @@ -1,3 +1,12 @@ +/proc/status_effect_to_viewers(target, mod_path, message, range = world.view, exclude_mobs) + for(var/mob/living/carbon/human/M in viewers(target, range) - exclude_mobs) + if(M.is_blind() || M.stat != CONSCIOUS) + continue + + M.apply_status_effect(mod_path) + if(message) + to_chat(M, message) + /datum/status_effect/stat_mod tick_interval = -1 status_type = STATUS_EFFECT_MULTIPLE @@ -41,4 +50,3 @@ /datum/status_effect/skill_mod/on_remove() owner.stats.remove_skill_modifier(skill_path, source) - diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index b5b3b23602f3..69c92e4caa12 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -1397,7 +1397,6 @@ A.state = AIRLOCK_ASSEMBLY_NEEDS_ELECTRONICS A.created_name = name A.previous_assembly = previous_airlock - A.update_name() A.update_appearance() if(!disassembled) diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm index 2cbeedb09a30..0154703142c2 100644 --- a/code/game/objects/items/cigs_lighters.dm +++ b/code/game/objects/items/cigs_lighters.dm @@ -636,11 +636,11 @@ CIGARETTE PACKETS ARE IN FANCY.DM /obj/item/clothing/mask/cigarette/pipe/Initialize(mapload) . = ..() - update_name() + update_appearance(UPDATE_NAME) /obj/item/clothing/mask/cigarette/pipe/update_name() - . = ..() name = packeditem ? "[packeditem]-packed [initial(name)]" : "empty [initial(name)]" + return ..() /obj/item/clothing/mask/cigarette/pipe/put_out(mob/user, done_early = FALSE) lit = FALSE @@ -672,7 +672,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM to_chat(user, span_notice("You stuff [to_smoke] into [src].")) smoketime = 13 MINUTES packeditem = to_smoke.name - update_name() + update_appearance(UPDATE_NAME) if(to_smoke.reagents) to_smoke.reagents.trans_to(src, to_smoke.reagents.total_volume, transfered_by = user) qdel(to_smoke) @@ -686,7 +686,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM packeditem = null smoketime = 0 reagents.clear_reagents() - update_name() + update_appearance(UPDATE_NAME) return return ..() diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm index c0c5b6ad3ed4..43677ca85494 100644 --- a/code/game/objects/structures/door_assembly.dm +++ b/code/game/objects/structures/door_assembly.dm @@ -45,7 +45,6 @@ has_fill_overlays = initial(airlock_cast.has_fill_overlays) update_appearance() - update_name() AddComponent(/datum/component/simple_rotation) @@ -299,7 +298,7 @@ qdel(src) else return ..() - update_name() + update_appearance() /obj/structure/door_assembly/update_overlays() @@ -350,7 +349,6 @@ target.electronics = source.electronics source.electronics.forceMove(target) target.update_appearance() - target.update_name() qdel(source) /obj/structure/door_assembly/deconstruct(disassembled = TRUE) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 8aca4996bb23..823b82aa218a 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -111,6 +111,7 @@ GLOBAL_LIST_INIT(admin_verbs_fun, list( /client/proc/admin_away, /client/proc/add_mob_ability, /client/proc/set_title_music, + /client/proc/restore_ghost_character, /datum/admins/proc/station_traits_panel, )) GLOBAL_PROTECT(admin_verbs_fun) diff --git a/code/modules/admin/verbs/adminfun.dm b/code/modules/admin/verbs/adminfun.dm index cca3bd276521..8e9374ddbbb2 100644 --- a/code/modules/admin/verbs/adminfun.dm +++ b/code/modules/admin/verbs/adminfun.dm @@ -249,3 +249,28 @@ message_admins(msg) admin_ticket_log(whom, msg) log_admin("[key_name(src)] punished [key_name(whom)] with [punishment].") + +/client/proc/restore_ghost_character() + set category = "Admin.Fun" + set name = "Restore Ghost Character" + set desc = "Sets your deadchat name and ghost appearance to your \ + roundstart character." + + if(!check_rights()) + return + + if(!isobserver(mob)) + return + + var/mob/dead/observer/observer_mob = mob + var/mob/living/carbon/human/dummy/consistent/template = new + if(prefs) + var/real_name = prefs.read_preference(/datum/preference/name/real_name) + observer_mob.deadchat_name = real_name + if(observer_mob.mind) + observer_mob.mind.ghostname = real_name + observer_mob.set_real_name(real_name) + prefs.apply_prefs_to(template) + + observer_mob.set_ghost_appearance(template) + qdel(template) diff --git a/code/modules/admin/verbs/possess.dm b/code/modules/admin/verbs/possess.dm index bbc9e5ddc3e4..77580942e269 100644 --- a/code/modules/admin/verbs/possess.dm +++ b/code/modules/admin/verbs/possess.dm @@ -36,7 +36,7 @@ usr.name_archive = "" if(ishuman(usr)) var/mob/living/carbon/human/H = usr - H.update_name() + H.update_appearance(UPDATE_NAME) usr.forceMove(get_turf(usr.control_object)) usr.reset_perspective() diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm index 2e27df677ca1..0db1ed9d366e 100644 --- a/code/modules/atmospherics/machinery/atmosmachinery.dm +++ b/code/modules/atmospherics/machinery/atmosmachinery.dm @@ -66,7 +66,7 @@ /obj/machinery/atmospherics/LateInitialize() . = ..() - update_name() + update_appearance(UPDATE_NAME) /obj/machinery/atmospherics/examine(mob/user) . = ..() @@ -482,7 +482,7 @@ GLOBAL_REAL_VAR(atmos_machinery_default_armor) = list(BLUNT = 25, PUNCTURE = 10, if(can_unwrench) add_atom_colour(obj_color, FIXED_COLOUR_PRIORITY) pipe_color = obj_color - update_name() + update_appearance(UPDATE_NAME) set_piping_layer(set_layer) atmos_init() var/list/nodes = pipeline_expansion() diff --git a/code/modules/atmospherics/machinery/components/binary_devices/dp_vent_pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/dp_vent_pump.dm index 4307a6456d13..ed8a5b0f36f3 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/dp_vent_pump.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/dp_vent_pump.dm @@ -166,7 +166,7 @@ var/area/vent_area = get_area(src) if(!GLOB.air_vent_names[id_tag]) - update_name() + update_appearance(UPDATE_NAME) GLOB.air_vent_names[id_tag] = name vent_area.air_vent_info[id_tag] = signal.data diff --git a/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm b/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm index 79581bf2a7c7..f18cd3cc23ad 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm @@ -197,7 +197,7 @@ if(!GLOB.air_vent_names[id_tag]) // If we do not have a name, assign one. // Produces names like "Port Quarter Solar vent pump hZ2l6". - update_name() + update_appearance(UPDATE_NAME) GLOB.air_vent_names[id_tag] = name vent_area.air_vent_info[id_tag] = signal.data diff --git a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm index 15782cf01762..042e99dc3678 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm @@ -170,7 +170,7 @@ var/area/scrub_area = get_area(src) if(!GLOB.air_scrub_names[id_tag]) // If we do not have a name, assign one - update_name() + update_appearance(UPDATE_NAME) GLOB.air_scrub_names[id_tag] = name scrub_area.air_scrub_info[id_tag] = signal.data diff --git a/code/modules/client/preferences/monochrome_ghost.dm b/code/modules/client/preferences/monochrome_ghost.dm index 9bd55927b6d9..d1c894d91cf6 100644 --- a/code/modules/client/preferences/monochrome_ghost.dm +++ b/code/modules/client/preferences/monochrome_ghost.dm @@ -10,9 +10,4 @@ if(!istype(M)) return - if(value && !M.started_as_observer) - if(locate(/datum/client_colour/ghostmono) in M.client_colours) - return - M.add_client_colour(/datum/client_colour/ghostmono) - else - M.remove_client_colour(/datum/client_colour/ghostmono) + M.update_monochrome() diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index ac4571bbc85b..b7032a824cf3 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -60,7 +60,7 @@ if(QDELETED(src) || !src.client || (!skip_check && (this_is_like_playing_right != "Yes"))) ready = PLAYER_NOT_READY src << browse(null, "window=playersetup") //closes the player setup window - npp.open() + npp?.open() return FALSE var/mob/dead/observer/observer = new(null, TRUE) @@ -76,10 +76,11 @@ stack_trace("There's no freaking observer landmark available on this map or you're making observers before the map is initialised") observer.key = key observer.client = client - observer.restore_ghost_appearance() + if(observer.client && observer.client.prefs) observer.set_real_name(observer.client.prefs.read_preference(/datum/preference/name/real_name)) observer.client.init_verbs() + observer.stop_sound_channel(CHANNEL_LOBBYMUSIC) deadchat_broadcast(" has observed.", "[observer.real_name]", follow_target = observer, turf_target = get_turf(observer), message_type = DEADCHAT_DEATHRATTLE) QDEL_NULL(mind) diff --git a/code/modules/mob/dead/observer/login.dm b/code/modules/mob/dead/observer/login.dm index b49495836d0c..4ebc0f6a1b36 100644 --- a/code/modules/mob/dead/observer/login.dm +++ b/code/modules/mob/dead/observer/login.dm @@ -16,5 +16,4 @@ client.set_right_click_menu_mode(FALSE) lighting_alpha = default_lighting_alpha() update_sight() - - + update_monochrome() diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 180b95e9e03a..ed1844a20c05 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -3,6 +3,10 @@ GLOBAL_LIST_EMPTY(ghost_images_robust) //this is a list of all ghost images as a GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) +GLOBAL_VAR_INIT(ghost_adjectives, __ghost_adjectives()) +GLOBAL_VAR_INIT(ghost_synonyms, __ghost_synonyms()) +GLOBAL_VAR_INIT(fresh_ghost_adjectives, __fresh_ghost_adjectives()) + /mob/dead/observer name = "ghost" desc = "It's a g-g-g-g-ghooooost!" //jinkies! @@ -24,12 +28,25 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) light_on = FALSE shift_to_open_context_menu = FALSE simulated = FALSE + var/can_reenter_corpse var/datum/hud/living/carbon/hud = null // hud var/bootime = 0 - var/started_as_observer //This variable is set to 1 when you enter the game as an observer. - //If you died in the game and are a ghost - this will remain as null. - //Note that this is not a reliable way to determine if admins started as observers, since they change mobs a lot. + + /// Prefixed adjective to the ghost's name + var/ghost_adjective = "" + /// name = "[ghost_adjective] [ghost_term] of [real_name]" + var/ghost_term = "" + + //This variable is set to 1 when you enter the game as an observer. + //If you died in the game and are a ghost - this will remain false. + //Note that this is not a reliable way to determine if admins started as observers, since they change mobs a lot. + var/started_as_observer = FALSE + /// Was this ghost spawned using the admin ghost command. + var/admin_ghost = FALSE + #warn TODO + var/exorcised = FALSE + var/atom/movable/following = null var/fun_verbs = 0 @@ -48,8 +65,9 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) var/datum/spawners_menu/spawners_menu var/datum/minigames_menu/minigames_menu -/mob/dead/observer/Initialize(mapload, started_as_observer = FALSE) +/mob/dead/observer/Initialize(mapload, started_as_observer = FALSE, admin_ghost = FALSE) src.started_as_observer = started_as_observer + src.admin_ghost = admin_ghost set_invisibility(GLOB.observer_default_invisibility) @@ -59,27 +77,43 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) /mob/dead/observer/proc/tray_view, /mob/dead/observer/proc/open_minigames_menu)) + ghost_term = pick(GLOB.ghost_synonyms) + ghost_adjective = pick(GLOB.ghost_adjectives) + var/turf/T var/mob/body = loc + var/mind_or_body_name + if(ismob(body)) T = get_turf(body) //Where is the body located? + mind = body.mind //we don't transfer the mind but we keep a reference to it. + set_suicide(body.suiciding) // Transfer whether they committed suicide. + gender = body.gender + died_as_name = body.died_as_name + + // Pick a name if(body.mind && body.mind.name) if(body.mind.ghostname) - name = body.mind.ghostname + mind_or_body_name = body.mind.ghostname else - name = body.mind.name + mind_or_body_name = body.mind.name else if(body.real_name) - name = body.real_name + mind_or_body_name = body.real_name else - name = random_unique_name(gender) + mind_or_body_name = random_unique_name(gender) - mind = body.mind //we don't transfer the mind but we keep a reference to it. + // If they actually died in round, copy their body. + if(!(started_as_observer || admin_ghost)) + set_ghost_appearance(body) + ghost_adjective = pick(GLOB.fresh_ghost_adjectives) - set_suicide(body.suiciding) // Transfer whether they committed suicide. - set_ghost_appearance(body) + if(!mind_or_body_name) //To prevent nameless ghosts + mind_or_body_name = random_unique_name(gender) + + set_real_name(mind_or_body_name) if(!T || is_secret_level(T.z)) var/list/turfs = get_area_turfs(/area/shuttle/arrival) @@ -90,10 +124,6 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) abstract_move(T) - if(!name) //To prevent nameless ghosts - name = random_unique_name(gender) - real_name = name - if(!fun_verbs) remove_verb(src, /mob/dead/observer/verb/boo) remove_verb(src, /mob/dead/observer/verb/possess) @@ -129,6 +159,18 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) ) AddComponent(/datum/component/spooky_powers, powers) +/mob/dead/observer/Destroy() + if(data_huds_on) + remove_data_huds() + + // Update our old body's medhud since we're abandoning it + if(mind?.current) + mind.current.med_hud_set_status() + + QDEL_NULL(spawners_menu) + QDEL_NULL(minigames_menu) + return ..() + /mob/dead/observer/get_photo_description(obj/item/camera/camera) if(!invisibility || camera.see_ghosts) return "You can also see a g-g-g-g-ghooooost!" @@ -139,17 +181,61 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) animate(src, color = old_color, time = 10, flags = ANIMATION_PARALLEL) addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 10) -/mob/dead/observer/Destroy() - if(data_huds_on) - remove_data_huds() +/mob/dead/observer/get_visible_name() + return "[ghost_adjective] [ghost_term] of [real_name]" - // Update our old body's medhud since we're abandoning it - if(mind?.current) - mind.current.med_hud_set_status() +/mob/dead/observer/update_name(updates) + . = ..() + deadchat_name = name - QDEL_NULL(spawners_menu) - QDEL_NULL(minigames_menu) - return ..() +/// Helper for setting can_reenter_corpse to FALSE +/mob/dead/observer/proc/unset_reenter_corpse() + can_reenter_corpse = FALSE + mind = null + +/// Adds or removes the monochrome filter based on certain traits. +/mob/dead/observer/proc/update_monochrome() + if(admin_ghost || started_as_observer) + remove_client_colour(/datum/client_colour/ghostmono) + return + + if(exorcised || client?.prefs?.read_preference(/datum/preference/toggle/monochrome_ghost) == FALSE) // Null != false + remove_client_colour(/datum/client_colour/ghostmono) + return + + add_client_colour(/datum/client_colour/ghostmono) + +/// Exorcise the ghost. +/mob/dead/observer/proc/exorcise(mob/living/priest) + exorcised = TRUE + + unset_reenter_corpse() + update_monochrome() + qdel(GetComponent(/datum/component/spooky_powers)) + + ghost_adjective = pick(GLOB.ghost_adjectives) + verb_say = initial(verb_say) + verb_exclaim = initial(verb_exclaim) + verb_sing = initial(verb_sing) + verb_whisper = initial(verb_whisper) + verb_yell = initial(verb_yell) + + update_appearance(UPDATE_NAME) + set_ghost_appearance(null) + + if(client) + // tgchat displays doc strings with formatting, so we do stupid shit instead + var/list/text = list( + "
[span_statsgood("You were laid to rest.")]
", + "
", + span_obviousnotice("Your soul has moved on from the mortal realm, and may no longer interact with it. You may now return to the lobby, and begin anew."), + ) + to_chat(src, examine_block(jointext(text, ""))) + + playsound_local(src, 'goon/sounds/ghostrespawn.ogg', 50, FALSE, pressure_affected = FALSE) + + if(priest) + deadchat_broadcast("'s restless spirit has been put to rest by [priest.name].", real_name, priest, message_type = DEADCHAT_ANNOUNCEMENT) /* * Increase the brightness of a color by calculating the average distance between the R, G and B values, @@ -211,18 +297,19 @@ Works together with spawning an observer, noted above. ethereal_heart.stop_crystalization_process(crystal_fella) //stops the crystallization process stop_sound_channel(CHANNEL_HEARTBEAT) //Stop heartbeat sounds because You Are A Ghost Now - var/mob/dead/observer/ghost = new(src) // Transfer safety to observer spawning proc. + var/mob/dead/observer/ghost = new(src, FALSE, admin_ghost) // Transfer safety to observer spawning proc. SStgui.on_transfer(src, ghost) // Transfer NanoUIs. - ghost.can_reenter_corpse = can_reenter_corpse - ghost.key = key - ghost.client?.init_verbs() - if(!can_reenter_corpse)// Disassociates observer mind from the body mind - ghost.mind = null - if(!admin_ghost) - if(!ghost.client?.prefs || ghost.client.prefs.read_preference(/datum/preference/toggle/monochrome_ghost)) - ghost.add_client_colour(/datum/client_colour/ghostmono) + ghost.verb_say = verb_say + ghost.verb_exclaim = verb_exclaim + ghost.verb_sing = verb_sing + ghost.verb_whisper = verb_whisper + ghost.verb_yell = verb_yell + if(!can_reenter_corpse) + ghost.exorcise() + ghost.key = key + ghost.client?.init_verbs() return ghost /mob/living/ghostize(can_reenter_corpse = TRUE, admin_ghost) @@ -345,14 +432,11 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if(response != "DNR") return - can_reenter_corpse = FALSE // Update med huds var/mob/living/carbon/current = mind.current current.med_hud_set_status() - // Disassociates observer mind from the body mind - mind = null - to_chat(src, span_boldnotice("You can no longer be brought back into your body.")) + exorcise() return TRUE /mob/dead/observer/proc/notify_revival(message, sound, atom/source, flashwindow = TRUE) @@ -386,10 +470,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp to_chat(usr, span_warning("Not when you're not dead!")) return var/list/filtered = list() - for(var/V in GLOB.sortedAreas) - var/area/A = V + for(var/area/A in get_sorted_areas()) if(!(A.area_flags & HIDDEN_AREA)) filtered += A + var/area/thearea = tgui_input_list(usr, "Area to jump to", "BOOYEA", filtered) if(isnull(thearea)) @@ -701,34 +785,18 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp to_chat(src, span_notice("Gas scan enabled.")) gas_scan = TRUE -/mob/dead/observer/verb/restore_ghost_appearance() - set name = "Restore Ghost Character" - set desc = "Sets your deadchat name and ghost appearance to your \ - roundstart character." - set category = "Ghost" - - var/mob/living/carbon/human/dummy/consistent/template = new - if(client?.prefs) - var/real_name = client.prefs.read_preference(/datum/preference/name/real_name) - deadchat_name = real_name - if(mind) - mind.ghostname = real_name - name = real_name - client.prefs.apply_prefs_to(template) - - set_ghost_appearance(template) - qdel(template) - /mob/dead/observer/proc/set_ghost_appearance(mob/living/to_copy) - if(!to_copy || !to_copy.icon) + var/mutable_appearance/appearance = to_copy?.mind?.body_appearance || to_copy + + if(!appearance || !appearance.icon) icon = initial(icon) icon_state = "ghost" alpha = 255 overlays.Cut() else - icon = to_copy.icon - icon_state = to_copy.icon_state - overlays = to_copy.overlays + icon = appearance.icon + icon_state = appearance.icon_state + overlays = appearance.overlays alpha = 127 /mob/dead/observer/canUseTopic(atom/movable/target, flags) @@ -984,3 +1052,30 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp /mob/dead/observer/hear_location() return observetarget || orbit_target || ..() + +/proc/__ghost_synonyms() + return list( + "ghost", + "spirit", + "phantom", + ) + +/proc/__ghost_adjectives() + return list( + "fleeting", + "wayward", + "weak", + "fading", + "ephemeral", + "passing", + "wandering", + "restful", + ) + +/proc/__fresh_ghost_adjectives() + return list( + "restless", + "troubled", + "unruly", + "disturbed", + ) diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm index bc6e27d8a4ff..adca2e9fc94b 100644 --- a/code/modules/mob/living/brain/brain_item.dm +++ b/code/modules/mob/living/brain/brain_item.dm @@ -119,10 +119,12 @@ return if(!L.mind) return + brainmob = new(src) brainmob.set_real_name(L.real_name) brainmob.timeofhostdeath = L.timeofdeath brainmob.suiciding = suicided + if(L.has_dna()) var/mob/living/carbon/C = L if(!brainmob.stored_dna) @@ -130,8 +132,12 @@ C.dna.copy_dna(brainmob.stored_dna) if(HAS_TRAIT(L, TRAIT_BADDNA)) LAZYSET(brainmob.status_traits, TRAIT_BADDNA, L.status_traits[TRAIT_BADDNA]) + if(L.mind && L.mind.current) + if(!QDELETED(L)) + L.mind.body_appearance = L.appearance L.mind.transfer_to(brainmob) + to_chat(brainmob, span_notice("You feel slightly disoriented. That's normal when you're just a brain.")) /obj/item/organ/brain/attackby(obj/item/O, mob/user, params) diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index 53190de671e1..8cec1ce03139 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -49,16 +49,6 @@ GLOBAL_LIST_EMPTY(dead_players_during_shift) SSblackbox.ReportDeath(src) log_message("has died (BRUTE: [src.getBruteLoss()], BURN: [src.getFireLoss()], TOX: [src.getToxLoss()], OXY: [src.getOxyLoss()], CLONE: [src.getCloneLoss()])", LOG_ATTACK) - for(var/mob/living/L in viewers(src, world.view) - src) - if(L.is_blind() || L.stat != CONSCIOUS || !L.client) - continue - - var/datum/roll_result/result = L.stat_roll(7, /datum/rpg_skill/willpower) - switch(result.outcome) - if(FAILURE, CRIT_FAILURE) - if(L.apply_status_effect(/datum/status_effect/skill_mod/witness_death)) - to_chat(L, result.create_tooltip("For but a moment, there is nothing. Nothing but the gnawing realisation of what you have just witnessed.")) - /mob/living/carbon/human/proc/makeSkeleton() ADD_TRAIT(src, TRAIT_DISFIGURED, TRAIT_GENERIC) set_species(/datum/species/skeleton) @@ -79,6 +69,9 @@ GLOBAL_LIST_EMPTY(dead_players_during_shift) /mob/living/carbon/human/proc/show_death_stats(mob/user) var/list/scan = time_of_death_stats + if(!length(scan)) + return + var/list/ui_content = list() var/datum/browser/popup = new(user, "timeofdeathinfo", "Time of Death Information", 600, 800) diff --git a/code/modules/mob/living/carbon/human/init_signals.dm b/code/modules/mob/living/carbon/human/init_signals.dm index 8930a920b5c1..0a649c6fbe91 100644 --- a/code/modules/mob/living/carbon/human/init_signals.dm +++ b/code/modules/mob/living/carbon/human/init_signals.dm @@ -12,4 +12,4 @@ /mob/living/carbon/human/proc/do_name_update(datum/source) SIGNAL_HANDLER - update_name() + update_appearance(UPDATE_NAME) diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index 2e9d027d20db..f1985589f44e 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -317,14 +317,14 @@ belt = null if(!QDELETED(src)) update_slots_for_item(I, ITEM_SLOT_BELT) - update_name() + update_appearance(UPDATE_NAME) else if(I == wear_id) wear_id = null sec_hud_set_ID() if(!QDELETED(src)) update_slots_for_item(I, ITEM_SLOT_ID) - update_name() + update_appearance(UPDATE_NAME) else if(I == r_store) r_store = null @@ -389,7 +389,7 @@ if(I.flags_inv & HIDEEYES) update_worn_glasses() sec_hud_set_security_status() - update_name() + update_appearance(UPDATE_NAME) ..() /mob/living/carbon/human/proc/equipOutfit(outfit, visualsOnly = FALSE) diff --git a/code/modules/mob/living/carbon/human/status_procs.dm b/code/modules/mob/living/carbon/human/status_procs.dm index 3abf1865c581..8f1077fcb631 100644 --- a/code/modules/mob/living/carbon/human/status_procs.dm +++ b/code/modules/mob/living/carbon/human/status_procs.dm @@ -38,15 +38,3 @@ . = ..() if(.) update_body_parts() - -/mob/living/carbon/human/fakedeath(source, silent) - . = ..() - for(var/mob/living/L in viewers(src, world.view) - src) - if(L.is_blind() || L.stat != CONSCIOUS || !L.client) - continue - - var/datum/roll_result/result = L.stat_roll(6, /datum/rpg_skill/willpower) - switch(result.outcome) - if(FAILURE, CRIT_FAILURE) - if(L.apply_status_effect(/datum/status_effect/skill_mod/witness_death)) - to_chat(L, result.create_tooltip("For but a moment, there is nothing. Nothing but the gnawing realisation of what you have just witnessed.")) diff --git a/code/modules/mob/living/carbon/inventory.dm b/code/modules/mob/living/carbon/inventory.dm index c07590a4e1a6..c451784d7ad4 100644 --- a/code/modules/mob/living/carbon/inventory.dm +++ b/code/modules/mob/living/carbon/inventory.dm @@ -354,7 +354,7 @@ // Update name if we are changing face visibility var/face_coverage_changed = updated_slots & HIDEFACE if(face_coverage_changed) - update_name() + update_appearance(UPDATE_NAME) // Update body incase any bodyparts or organs changed visibility var/bodypart_coverage_changed = updated_slots & BODYPART_HIDE_FLAGS diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm index 227cfa0934f5..c44cfe8eb6f3 100644 --- a/code/modules/mob/living/death.dm +++ b/code/modules/mob/living/death.dm @@ -73,13 +73,14 @@ set_stat(DEAD) unset_machine() + died_as_name = name timeofdeath = world.time - tod = stationtime2text() + timeofdeath_as_ingame = stationtime2text() // tgchat displays doc strings with formatting, so we do stupid shit instead var/list/death_message = list( - "
[span_statsbad("You Died")]
", - "
[span_statsbad("Cause of Death: [cause_of_death]")]
", + "
[span_statsbad("You Died")]
", + "
[span_statsbad("Cause of Death: [cause_of_death]")]
", "
", span_obviousnotice("Your story may not be over yet. You are able to be resuscitated as long as your brain was not destroyed, and you have not been dead for 10 minutes."), ) @@ -92,10 +93,14 @@ death_message = examine_block(jointext(death_message, "")) to_chat(src, death_message) + playsound_local(src, 'goon/sounds/revfocus.ogg', 50, vary = FALSE, pressure_affected = FALSE) + var/turf/T = get_turf(src) - if(mind && mind.name && mind.active && !istype(T.loc, /area/centcom/ctf)) - deadchat_broadcast(" has died at [get_area_name(T)].", "[mind.name]", follow_target = src, turf_target = T, message_type=DEADCHAT_DEATHRATTLE) + if(mind && mind.name && mind.active) + if(!istype(T.loc, /area/centcom/ctf)) + deadchat_broadcast(" has died at [get_area_name(T)].", "[mind.name]", follow_target = src, turf_target = T, message_type=DEADCHAT_DEATHRATTLE) + if(SSlag_switch.measures[DISABLE_DEAD_KEYLOOP] && !client?.holder) to_chat(src, span_deadsay(span_big("Observer freelook is disabled.\nPlease use Orbit, Teleport, and Jump to look around."))) ghostize(TRUE) diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index 4ae25f4f7b56..6c87b3668707 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -64,13 +64,14 @@ DEFINE_INTERACTABLE(/mob/living) var/hallucination = 0 ///Directly affects how long a mob will hallucinate for var/last_special = 0 ///Used by the resist verb, likely used to prevent players from bypassing next_move by logging in/out. + /// Time of death as world.time var/timeofdeath = 0 /// Helper vars for quick access to firestacks, these should be updated every time firestacks are adjusted var/on_fire = FALSE var/fire_stacks = 0 - /** + /** mind.mob_appearance = appearance * Allows mobs to move through dense areas without restriction. For instance, in space or out of holder objects. * * FALSE is off, [INCORPOREAL_MOVE_BASIC] is normal, [INCORPOREAL_MOVE_SHADOW] is for ninjas @@ -90,8 +91,8 @@ DEFINE_INTERACTABLE(/mob/living) var/cameraFollow = null - /// Time of death - var/tod = null + /// Time of death in the in-game time format + var/timeofdeath_as_ingame = null var/limb_destroyer = 0 //1 Sets AI behavior that allows mobs to target and dismember limbs with their basic attack. diff --git a/code/modules/mob/living/simple_animal/slime/death.dm b/code/modules/mob/living/simple_animal/slime/death.dm index b9b03ba41c00..a690ea2d67a3 100644 --- a/code/modules/mob/living/simple_animal/slime/death.dm +++ b/code/modules/mob/living/simple_animal/slime/death.dm @@ -15,7 +15,7 @@ E.Grant(src) revive(full_heal = TRUE, admin_revive = FALSE) regenerate_icons() - update_name() + update_appearance(UPDATE_NAME) return if(buckled) diff --git a/code/modules/mob/living/simple_animal/slime/powers.dm b/code/modules/mob/living/simple_animal/slime/powers.dm index 4bfbc9cbd1f3..18c121f22e5b 100644 --- a/code/modules/mob/living/simple_animal/slime/powers.dm +++ b/code/modules/mob/living/simple_animal/slime/powers.dm @@ -144,7 +144,7 @@ var/datum/action/innate/slime/reproduce/reproduce_action = new reproduce_action.Grant(src) regenerate_icons() - update_name() + update_appearance(UPDATE_NAME) else to_chat(src, "I am not ready to evolve yet...") else diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm index b4a404092a97..5b453c604a99 100644 --- a/code/modules/mob/living/simple_animal/slime/slime.dm +++ b/code/modules/mob/living/simple_animal/slime/slime.dm @@ -119,7 +119,7 @@ /mob/living/simple_animal/slime/proc/set_colour(new_colour) colour = new_colour - update_name() + update_appearance(UPDATE_NAME) slime_mutation = mutation_table(colour) var/sanitizedcolour = replacetext(colour, " ", "") coretype = text2path("/obj/item/slime_extract/[sanitizedcolour]") diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm index 2072d982deb6..b0c13b9e69c0 100644 --- a/code/modules/mob/living/status_procs.dm +++ b/code/modules/mob/living/status_procs.dm @@ -657,7 +657,7 @@ REMOVE_TRAIT(src, TRAIT_FAKEDEATH, source) REMOVE_TRAIT(src, TRAIT_DEATHCOMA, source) if(stat != DEAD) - tod = null + timeofdeath_as_ingame = null /// Induces fake death on a living mob. /mob/living/proc/fakedeath(source, silent = FALSE) @@ -667,7 +667,7 @@ emote("deathgasp") ADD_TRAIT(src, TRAIT_FAKEDEATH, source) ADD_TRAIT(src, TRAIT_DEATHCOMA, source) - tod = stationtime2text() + timeofdeath_as_ingame = stationtime2text() ///Unignores all slowdowns that lack the IGNORE_NOSLOW flag. diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 77fbea26465f..6c85f5154f9e 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1178,7 +1178,7 @@ if(change_name) name = real_name if(update_name) - update_name() + update_appearance(UPDATE_NAME) /** * Fully update the name of a mob diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 8b8b8c8cab28..2d46f25bed14 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -93,6 +93,8 @@ var/eye_blurry = 0 //Carbon /// What is the mobs real name (name is overridden for disguises etc) var/real_name = null + /// The name this mob had when it died. Used by dead say. + var/died_as_name = "" /** * back up of the real name during admin possession diff --git a/code/modules/mob/mob_say.dm b/code/modules/mob/mob_say.dm index 62efd9e78949..8129c2f6118e 100644 --- a/code/modules/mob/mob_say.dm +++ b/code/modules/mob/mob_say.dm @@ -65,9 +65,6 @@ ///Speak as a dead person (ghost etc) /mob/proc/say_dead(message) - var/name = real_name - var/alt_name = "" - if(GLOB.say_disabled) //This is here to try to identify lag problems to_chat(usr, span_danger("Speech is currently admin-disabled.")) return @@ -94,19 +91,24 @@ if(src.client.handle_spam_prevention(message,MUTE_DEADCHAT)) return + var/display_name = real_name + var/name_append = "" var/mob/dead/observer/O = src if(isobserver(src) && O.deadchat_name) - name = "[O.deadchat_name]" + display_name = "[O.deadchat_name]" + if(died_as_name && (real_name != died_as_name)) + name_append = " (died as [died_as_name])" else if(mind?.name) - name = "[mind.name]" + display_name = "[mind.name]" else - name = real_name - if(name != real_name) - alt_name = " (died as [real_name])" + display_name = real_name + + if(display_name != died_as_name) + name_append = " (died as [died_as_name])" var/spanned = say_quote(say_emphasis(message)) - var/source = "DEAD: [name][alt_name]" + var/source = "DEAD: [display_name][name_append]" var/rendered = " [emoji_parse(spanned)]" log_talk(message, LOG_SAY, tag="DEAD") if(SEND_SIGNAL(src, COMSIG_MOB_DEADSAY, message) & MOB_DEADSAY_SIGNAL_INTERCEPT) diff --git a/code/modules/mod/mod_link.dm b/code/modules/mod/mod_link.dm index 7e913d6d1af1..bd0f982b87c9 100644 --- a/code/modules/mod/mod_link.dm +++ b/code/modules/mod/mod_link.dm @@ -190,7 +190,7 @@ return label = new_label balloon_alert(user, "name set") - update_name() + update_appearance(UPDATE_NAME) /obj/item/clothing/neck/link_scryer/process(delta_time) if(!mod_link.link_call) diff --git a/code/modules/reagents/chemistry/recipes/slime_extracts.dm b/code/modules/reagents/chemistry/recipes/slime_extracts.dm index 5a0c26afb685..c38eaca92dfe 100644 --- a/code/modules/reagents/chemistry/recipes/slime_extracts.dm +++ b/code/modules/reagents/chemistry/recipes/slime_extracts.dm @@ -326,7 +326,7 @@ if(slime.docile) //Undoes docility, but doesn't make rabid. slime.visible_message(span_danger("[slime] forgets its training, becoming wild once again!")) slime.docile = FALSE - slime.update_name() + slime.update_appearance(UPDATE_NAME) continue slime.rabid = 1 slime.visible_message(span_danger("The [slime] is driven into a frenzy!")) diff --git a/code/modules/reagents/reagent_containers/blood_pack.dm b/code/modules/reagents/reagent_containers/blood_pack.dm index aece6ffc508c..77767f20eb8f 100644 --- a/code/modules/reagents/reagent_containers/blood_pack.dm +++ b/code/modules/reagents/reagent_containers/blood_pack.dm @@ -91,6 +91,6 @@ balloon_alert(user, "new label set") else labelled = FALSE - update_name() + update_appearance(UPDATE_NAME) else return ..() diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm index 5a50f16ca43c..e83aa54587dd 100644 --- a/code/modules/surgery/bodyparts/dismemberment.dm +++ b/code/modules/surgery/bodyparts/dismemberment.dm @@ -318,7 +318,7 @@ var/mob/living/carbon/human/old_owner = owner . = ..() - old_owner.update_name() + old_owner.update_appearance(UPDATE_NAME) if(!special) if(brain?.brainmob) diff --git a/code/modules/surgery/new_surgery/sanctify.dm b/code/modules/surgery/new_surgery/sanctify.dm new file mode 100644 index 000000000000..c2df96e220f6 --- /dev/null +++ b/code/modules/surgery/new_surgery/sanctify.dm @@ -0,0 +1,52 @@ +/datum/surgery_step/sanctify + can_infect = 0 + surgery_flags = SURGERY_CANNOT_FAIL + min_duration = 1 SECOND + max_duration = 2 SECONDS + + allowed_tools = list() + +/datum/surgery_step/sanctify/assess_bodypart(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/bodypart/affected = ..() + if(!istype(affected, /obj/item/bodypart/chest)) + return FALSE + + return TRUE + +/datum/surgery_step/sanctify/pre_surgery_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if(target.stat != DEAD) + to_chat(user, span_warning("They are not yet ready to pass over.")) + return FALSE + + if(!target.getorganslot(ORGAN_SLOT_BRAIN)) + to_chat(user, span_warning("They cannot be sanctified without their brain.")) + return FALSE + + if(!istype(target.getorganslot(ORGAN_SLOT_HEART), /obj/item/organ/heart/fake)) + to_chat(user, span_warning("They cannot be sanctified without perennial heart.")) + return FALSE + return TRUE + +/datum/surgery_step/sanctify/succeed_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + . = ..() + var/mob/dead/observer/ghost = target.grab_ghost() || target.ghostize() + if(ghost) + ghost.exorcise() + + // Robots don't understand + var/list/exclude = list() + for(var/mob/living/carbon/human/H in viewers(world.view, target)) + if(isipc(H)) + exclude += H + + status_effect_to_viewers( + target, + /datum/status_effect/skill_mod/sanctify_corpse, + span_statsgood("You feel at peace."), + exclude_mobs = exclude, + ) + + + + + diff --git a/code/modules/surgery/organs/fake_heart.dm b/code/modules/surgery/organs/fake_heart.dm new file mode 100644 index 000000000000..2622726d2070 --- /dev/null +++ b/code/modules/surgery/organs/fake_heart.dm @@ -0,0 +1,17 @@ +/obj/item/organ/heart/fake + name = "perennial heart" + desc = "A symbollic heart made out of wood. To be placed inside those who have been laid to rest in the great pool." + icon_state = "heart-on" + base_icon_state = "heart" + + cosmetic_only = TRUE + relative_size = 0 + + organ_flags = ORGAN_DEAD | ORGAN_SYNTHETIC + maxHealth = 1 + +/obj/item/organ/heart/fake/is_working() + return FALSE + +/obj/item/organ/heart/fake/set_organ_dead(failing, cause_of_death) + return FALSE diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm index d5bfec45b211..67c8a2218150 100644 --- a/code/modules/surgery/organs/heart.dm +++ b/code/modules/surgery/organs/heart.dm @@ -212,7 +212,8 @@ /obj/item/organ/heart/cybernetic name = "basic cybernetic heart" desc = "A basic electronic device designed to mimic the functions of an organic human heart." - icon_state = "heart-c" + base_icon_state = "heart-c" + icon_state = "heart-c-on" organ_flags = ORGAN_SYNTHETIC var/dose_available = FALSE @@ -223,7 +224,8 @@ /obj/item/organ/heart/cybernetic/tier2 name = "cybernetic heart" desc = "An electronic device designed to mimic the functions of an organic human heart. Also holds an emergency dose of epinephrine, used automatically after facing severe trauma." - icon_state = "heart-c-u" + icon_state = "heart-c-u-on" + base_icon_state = "heart-c-u" maxHealth = 60 dose_available = TRUE emp_vulnerability = 40 @@ -231,7 +233,8 @@ /obj/item/organ/heart/cybernetic/tier3 name = "upgraded cybernetic heart" desc = "An electronic device designed to mimic the functions of an organic human heart. Also holds an emergency dose of epinephrine, used automatically after facing severe trauma. This upgraded model can regenerate its dose after use." - icon_state = "heart-c-u2" + icon_state = "heart-c-u2-on" + base_icon_state = "heart-c-u2" maxHealth = 90 dose_available = TRUE emp_vulnerability = 20 diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index 1bdd88087196..6b2d63d1eafd 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -1276,7 +1276,7 @@ A.rounds = A.rounds - ammo_needed if(A.custom_materials) A.set_custom_materials(A.custom_materials, A.rounds / initial(A.rounds)) - A.update_name() + A.update_appearance(UPDATE_NAME) return TRUE if(A.direct_load) @@ -1287,7 +1287,7 @@ to_chat(user, span_notice("You add [A.rounds] [A.ammo_type][A.rounds > 1?"s":""] to the [gun.name]")) A.rounds = 0 A.set_custom_materials(list(/datum/material/iron=2000)) - A.update_name() + A.update_appearance(UPDATE_NAME) return TRUE if(!fail_chat_override) if(found_gun) diff --git a/daedalus.dme b/daedalus.dme index 3d9e6b2fd266..e6ab01fbe12f 100644 --- a/daedalus.dme +++ b/daedalus.dme @@ -1200,6 +1200,7 @@ #include "code\datums\status_effects\debuffs\speech_debuffs.dm" #include "code\datums\status_effects\debuffs\strandling.dm" #include "code\datums\status_effects\skill_modifiers\negative.dm" +#include "code\datums\status_effects\skill_modifiers\positive.dm" #include "code\datums\status_effects\skill_modifiers\rpg_modifiers.dm" #include "code\datums\storage\storage.dm" #include "code\datums\storage\subtypes\backpack.dm" @@ -4358,6 +4359,7 @@ #include "code\modules\surgery\new_surgery\remove_embedded.dm" #include "code\modules\surgery\new_surgery\ribcage.dm" #include "code\modules\surgery\new_surgery\robotics.dm" +#include "code\modules\surgery\new_surgery\sanctify.dm" #include "code\modules\surgery\new_surgery\tend_wounds.dm" #include "code\modules\surgery\organs\_organ.dm" #include "code\modules\surgery\organs\appendix.dm" @@ -4369,6 +4371,7 @@ #include "code\modules\surgery\organs\cell.dm" #include "code\modules\surgery\organs\ears.dm" #include "code\modules\surgery\organs\eyes.dm" +#include "code\modules\surgery\organs\fake_heart.dm" #include "code\modules\surgery\organs\heart.dm" #include "code\modules\surgery\organs\helpers.dm" #include "code\modules\surgery\organs\kidneys.dm" diff --git a/goon/sounds/ghostrespawn.ogg b/goon/sounds/ghostrespawn.ogg new file mode 100644 index 000000000000..486be89527f0 Binary files /dev/null and b/goon/sounds/ghostrespawn.ogg differ diff --git a/goon/sounds/revfocus.ogg b/goon/sounds/revfocus.ogg new file mode 100644 index 000000000000..92a6a1839e12 Binary files /dev/null and b/goon/sounds/revfocus.ogg differ diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi index 368b9c5e5b34..3ca60ac525ab 100755 Binary files a/icons/obj/surgery.dmi and b/icons/obj/surgery.dmi differ