[answers_encoded.Join(", ")]
") + span_notice("[html_encode(puzzgrid_group.description)]
") + + var/message = answers.Join("-----
") + + for (var/mob/mob as anything in get_hearers_in_view(DEFAULT_MESSAGE_RANGE, src)) + to_chat(mob, message) + +/datum/component/puzzgrid/ui_data(mob/user) + return list( + "selected_answers" = selected_answers, + "time_left" = time_to_finish && (max(0, (time_to_finish - world.time) / (1 SECONDS))), + "wrong_group_select_cooldown" = !COOLDOWN_FINISHED(src, wrong_group_select_cooldown), + "lives" = lives, + ) + +/datum/component/puzzgrid/ui_static_data(mob/user) + var/list/data = list() + + data["answers"] = puzzgrid.answers + + var/list/serialized_solved_groups = list() + for (var/datum/puzzgrid_group/solved_group as anything in solved_groups) + serialized_solved_groups += list(list( + "answers" = solved_group.answers, + )) + + var/atom/atom_parent = parent + + data["host"] = atom_parent.name + data["solved_groups"] = serialized_solved_groups + + return data + +/// Returns a random puzzgrid from config. +/// If config is empty, or no valid puzzgrids can be found in time, will return null. +/proc/create_random_puzzgrid() + var/static/total_lines + + if (isnull(total_lines)) + total_lines = rustg_file_get_line_count(PUZZGRID_CONFIG) + + if (isnull(total_lines)) + // There was an error reading the file + total_lines = 0 + + if (total_lines == 0) + return null + + for (var/_ in 1 to PUZZGRID_MAX_ATTEMPTS) + var/line_number = rand(0, total_lines - 1) + var/line = rustg_file_seek_line(PUZZGRID_CONFIG, line_number) + if (!line) + continue + + var/line_json_decoded = safe_json_decode(line) + if (isnull(line_json_decoded)) + log_config("Line [line_number + 1] in puzzgrids.txt is not a JSON: [line]") + continue + + var/datum/puzzgrid/puzzgrid = new + var/populate_result = puzzgrid.populate(line_json_decoded) + + if (populate_result == TRUE) + return puzzgrid + else + log_config("Line [line_number + 1] in puzzgrids.txt is not formatted correctly: [populate_result]") + + stack_trace("No valid puzzgrid config could be found in [PUZZGRID_MAX_ATTEMPTS] attempts, please check config_error. If it is empty, then seek line is failing.") + return null + +/// Represents an individual puzzgrid +/datum/puzzgrid + var/list/answers = list() + var/list/datum/puzzgrid_group/groups = list() + +/// Will populate a puzzgrid with the information from the JSON. +/// Will return TRUE if the populate succeeded, or a string denoting the error otherwise. +/datum/puzzgrid/proc/populate(list/from_json) + if (!islist(from_json)) + return "Puzzgrid was not a list" + + var/list/answers = list() + var/list/groups = list() + + for (var/group_json in from_json) + if (!islist(group_json)) + return "Group was not a list (received [json_encode(group_json)])" + + if (!("cells" in group_json)) + return "Group did not have a 'cells' field (received [json_encode(group_json)])" + + if (!("description" in group_json)) + return "Group did not have a 'description' field (received [json_encode(group_json)])" + + var/datum/puzzgrid_group/group = new + group.answers = group_json["cells"] + group.description = group_json["description"] + + answers += group.answers + + groups += group + + src.answers = shuffle(answers) + src.groups = groups + + return TRUE + +/// Represents an individual group in a puzzgrid +/datum/puzzgrid_group + var/list/answers = list() + var/description + +/// Debug verb for validating that all puzzgrids can be created successfully. +/// Locked behind a verb because it's fairly slow and memory intensive. +/client/proc/validate_puzzgrids() + set name = "Validate Puzzgrid Config" + set category = "Debug" + + var/line_number = 0 + + for (var/line in world.file2list(PUZZGRID_CONFIG)) + line_number += 1 + + if (length(line) == 0) + continue + + var/line_json_decoded = safe_json_decode(line) + if (isnull(line_json_decoded)) + to_chat(src, span_warning("Line [line_number] in puzzgrids.txt is not a JSON: [line]")) + continue + + var/datum/puzzgrid/puzzgrid = new + var/populate_result = puzzgrid.populate(line_json_decoded) + + if (populate_result != TRUE) + to_chat(src, span_warning("Line [line_number] in puzzgrids.txt is not formatted correctly: [populate_result]")) + + to_chat(src, span_notice("Validated. If you did not see any errors, you're in the clear.")) + +#undef PUZZGRID_CONFIG +#undef PUZZGRID_GROUP_COUNT +#undef PUZZGRID_MAX_ATTEMPTS diff --git a/code/datums/components/reagent_refiller.dm b/code/datums/components/reagent_refiller.dm new file mode 100644 index 0000000000000..d8a48f778c980 --- /dev/null +++ b/code/datums/components/reagent_refiller.dm @@ -0,0 +1,68 @@ +/** + * ## Reagent refiller + * Refills any drinks poured out of the reagent container (and is allowed within the whitelisted reagents). + */ +/datum/component/reagent_refiller + /// Time to refill + var/time_to_refill + /// Callback to consume power + var/datum/callback/power_draw_callback + /// Amount of power to use from the cell + var/power_to_draw + /// Whitelist of reagents allowed to be synthesized + var/list/whitelisted_reagents + +/datum/component/reagent_refiller/Initialize( + time_to_refill = 60 SECONDS, + datum/callback/power_draw_callback, + power_to_draw = 30, + whitelisted_reagents = list(/datum/reagent/consumable) +) + if(!istype(parent, /obj/item/reagent_containers)) + return COMPONENT_INCOMPATIBLE + + src.time_to_refill = time_to_refill + src.power_draw_callback = power_draw_callback + src.power_to_draw = power_to_draw + src.whitelisted_reagents = whitelisted_reagents + + return ..() + +/datum/component/reagent_refiller/RegisterWithParent() + RegisterSignal(parent, COMSIG_ITEM_AFTERATTACK, .proc/refill) + RegisterSignal(parent, COMSIG_ATOM_EXITED, .proc/delete_self) + +/datum/component/reagent_refiller/UnregisterFromParent() + UnregisterSignal(parent, list(COMSIG_ITEM_AFTERATTACK, COMSIG_ATOM_EXITED)) + +/datum/component/reagent_refiller/proc/delete_self() + SIGNAL_HANDLER + + qdel(src) + +/// Preps the reagent container for being refilled +/datum/component/reagent_refiller/proc/refill() + SIGNAL_HANDLER + + var/obj/item/reagent_containers/container = parent + var/refill = container.reagents.get_master_reagent_id() + var/amount = min((container.amount_per_transfer_from_this + container.reagents.total_volume), container.reagents.total_volume) + + if (amount == 0) + return + if (!is_path_in_list(refill, whitelisted_reagents)) + return + + addtimer(CALLBACK(src, .proc/add_reagents, container, container.loc, refill, amount), time_to_refill) + +/// Refills the reagent container, and uses cell power if applicable +/datum/component/reagent_refiller/proc/add_reagents(obj/item/reagent_containers/target, oldloc, reagent_to_refill, amount) + if (QDELETED(src) || QDELETED(target)) + return + if (target.loc != oldloc) + return + + target.reagents.add_reagent(reagent_to_refill, amount) + + if (!isnull(power_draw_callback)) + power_draw_callback.Invoke(power_to_draw) diff --git a/code/datums/components/riding/riding.dm b/code/datums/components/riding/riding.dm index e6adb2d19c66f..340ffe1430256 100644 --- a/code/datums/components/riding/riding.dm +++ b/code/datums/components/riding/riding.dm @@ -235,7 +235,7 @@ /datum/component/riding/proc/Unbuckle(atom/movable/M) addtimer(CALLBACK(parent, /atom/movable/.proc/unbuckle_mob, M), 0, TIMER_UNIQUE) -/datum/component/riding/proc/Process_Spacemove(direction) +/datum/component/riding/proc/Process_Spacemove(direction, continuous_move) var/atom/movable/AM = parent return override_allow_spacemove || AM.has_gravity() diff --git a/code/datums/components/shy.dm b/code/datums/components/shy.dm index 8f788fcaef50b..0c379654091c5 100644 --- a/code/datums/components/shy.dm +++ b/code/datums/components/shy.dm @@ -89,7 +89,7 @@ for(var/mob/living/person in strangers) if(person == owner) continue - if(!is_type_in_typecache(person, mob_whitelist)) + if(is_type_in_typecache(person, mob_whitelist)) continue if(!person.key && !keyless_shy) continue diff --git a/code/datums/components/slippery.dm b/code/datums/components/slippery.dm index d594dff9483ab..9301d558f146f 100644 --- a/code/datums/components/slippery.dm +++ b/code/datums/components/slippery.dm @@ -95,7 +95,7 @@ holder = equipper qdel(GetComponent(/datum/component/connect_loc_behalf)) AddComponent(/datum/component/connect_loc_behalf, holder, holder_connections) - RegisterSignal(holder, COMSIG_PARENT_PREQDELETED, .proc/holder_deleted) + RegisterSignal(holder, COMSIG_PARENT_QDELETING, .proc/holder_deleted) /* * Detects if the holder mob is deleted. @@ -120,7 +120,7 @@ /datum/component/slippery/proc/on_drop(datum/source, mob/user) SIGNAL_HANDLER - UnregisterSignal(user, COMSIG_PARENT_PREQDELETED) + UnregisterSignal(user, COMSIG_PARENT_QDELETING) qdel(GetComponent(/datum/component/connect_loc_behalf)) add_connect_loc_behalf_to_parent() diff --git a/code/datums/components/smooth_tunes.dm b/code/datums/components/smooth_tunes.dm index 15248b768db47..b897e29f1a873 100644 --- a/code/datums/components/smooth_tunes.dm +++ b/code/datums/components/smooth_tunes.dm @@ -85,10 +85,15 @@ SIGNAL_HANDLER STOP_PROCESSING(SSobj, src) if(viable_for_final_effect) - if(!finished) - to_chat(parent, span_warning("The song was interrupted, you cannot activate the finishing ability!")) + if(finished && linked_songtuner_rite && linked_song) + for(var/mob/living/carbon/human/listener in linked_song.hearing_mobs) + if(listener == parent || listener.can_block_magic(MAGIC_RESISTANCE_HOLY, charge_cost = 1)) + continue + + linked_songtuner_rite.finish_effect(listener, parent) else - linked_songtuner_rite.finish_effect(parent, linked_song) + to_chat(parent, span_warning("The song was interrupted, you cannot activate the finishing ability!")) + linked_song.parent?.remove_filter("smooth_tunes_outline") UnregisterSignal(linked_song.parent, list( COMSIG_INSTRUMENT_TEMPO_CHANGE, @@ -99,8 +104,12 @@ qdel(src) /datum/component/smooth_tunes/process(delta_time = SSOBJ_DT) - if(linked_songtuner_rite) - linked_songtuner_rite.song_effect(parent, linked_song) + if(linked_songtuner_rite && linked_song) + for(var/mob/living/carbon/human/listener in linked_song.hearing_mobs) + if(listener == parent || listener.can_block_magic(MAGIC_RESISTANCE_HOLY, charge_cost = 0)) + continue + + linked_songtuner_rite.song_effect(listener, parent) else stop_singing() diff --git a/code/datums/components/squeak.dm b/code/datums/components/squeak.dm index 3cfff08064f66..c8427ee980d90 100644 --- a/code/datums/components/squeak.dm +++ b/code/datums/components/squeak.dm @@ -46,7 +46,7 @@ else if(isstructure(parent)) RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, .proc/use_squeak) - if(istype(parent, /obj/item/organ/liver)) + if(istype(parent, /obj/item/organ/internal/liver)) // Liver squeaking is depending on them functioning like a clown's liver RegisterSignal(parent, SIGNAL_REMOVETRAIT(TRAIT_COMEDY_METABOLISM), .proc/on_comedy_metabolism_removal) @@ -112,7 +112,7 @@ SIGNAL_HANDLER holder = equipper RegisterSignal(holder, COMSIG_MOVABLE_DISPOSING, .proc/disposing_react, override=TRUE) - RegisterSignal(holder, COMSIG_PARENT_PREQDELETED, .proc/holder_deleted, override=TRUE) + RegisterSignal(holder, COMSIG_PARENT_QDELETING, .proc/holder_deleted, override=TRUE) //override for the preqdeleted is necessary because putting parent in hands sends the signal that this proc is registered towards, //so putting an object in hands and then equipping the item on a clothing slot (without dropping it first) //will always runtime without override = TRUE @@ -120,7 +120,7 @@ /datum/component/squeak/proc/on_drop(datum/source, mob/user) SIGNAL_HANDLER UnregisterSignal(user, COMSIG_MOVABLE_DISPOSING) - UnregisterSignal(user, COMSIG_PARENT_PREQDELETED) + UnregisterSignal(user, COMSIG_PARENT_QDELETING) holder = null ///just gets rid of the reference to holder in the case that theyre qdeleted @@ -130,11 +130,11 @@ holder = null // Disposal pipes related shits -/datum/component/squeak/proc/disposing_react(datum/source, obj/structure/disposalholder/holder, obj/machinery/disposal/source) +/datum/component/squeak/proc/disposing_react(datum/source, obj/structure/disposalholder/disposal_holder, obj/machinery/disposal/disposal_source) SIGNAL_HANDLER //We don't need to worry about unregistering this signal as it will happen for us automaticaly when the holder is qdeleted - RegisterSignal(holder, COMSIG_ATOM_DIR_CHANGE, .proc/holder_dir_change) + RegisterSignal(disposal_holder, COMSIG_ATOM_DIR_CHANGE, .proc/holder_dir_change) /datum/component/squeak/proc/holder_dir_change(datum/source, old_dir, new_dir) SIGNAL_HANDLER diff --git a/code/datums/components/stationloving.dm b/code/datums/components/stationloving.dm index 8c3788895e28d..c0a4c30626897 100644 --- a/code/datums/components/stationloving.dm +++ b/code/datums/components/stationloving.dm @@ -77,7 +77,7 @@ /// Checks whether a given atom's turf is within bounds. Returns TRUE if it is, FALSE if it isn't. /datum/component/stationloving/proc/atom_in_bounds(atom/atom_to_check) var/static/list/allowed_shuttles = typecacheof(list(/area/shuttle/syndicate, /area/shuttle/escape, /area/shuttle/pod_1, /area/shuttle/pod_2, /area/shuttle/pod_3, /area/shuttle/pod_4)) - var/static/list/disallowed_centcom_areas = typecacheof(list(/area/abductor_ship, /area/awaymission/errorroom)) + var/static/list/disallowed_centcom_areas = typecacheof(list(/area/centcom/abductor_ship, /area/awaymission/errorroom)) var/turf/destination_turf = get_turf(atom_to_check) if (!destination_turf) return FALSE diff --git a/code/datums/components/storage/concrete/pockets.dm b/code/datums/components/storage/concrete/pockets.dm index 060ac625d2078..e6b6a3170f3ee 100644 --- a/code/datums/components/storage/concrete/pockets.dm +++ b/code/datums/components/storage/concrete/pockets.dm @@ -158,9 +158,24 @@ /datum/component/storage/concrete/pockets/void_cloak quickdraw = TRUE + max_combined_w_class = 5 // 2 small items + 1 tiny item, or 1 normal item + 1 small item max_items = 3 /datum/component/storage/concrete/pockets/void_cloak/Initialize() . = ..() - var/static/list/exception_cache = typecacheof(list(/obj/item/clothing/neck/heretic_focus, /obj/item/codex_cicatrix)) + set_holdable(list( + /obj/item/ammo_box/a762/lionhunter, + /obj/item/bodypart, // Bodyparts are often used in rituals. They're also often normal sized, so you can only fit one. + /obj/item/clothing/neck/eldritch_amulet, + /obj/item/clothing/neck/heretic_focus, + /obj/item/codex_cicatrix, + /obj/item/eldritch_potion, + /obj/item/food/grown/poppy, // Used to regain a Living Heart. + /obj/item/melee/rune_carver, + /obj/item/melee/sickly_blade, // Normal sized, so you can only fit one. + /obj/item/organ, // Organs are also often used in rituals. + /obj/item/reagent_containers/glass/beaker/eldritch, + )) + + var/static/list/exception_cache = typecacheof(list(/obj/item/bodypart, /obj/item/melee/sickly_blade)) exception_hold = exception_cache diff --git a/code/datums/components/supermatter_crystal.dm b/code/datums/components/supermatter_crystal.dm new file mode 100644 index 0000000000000..51c7e8e8a1d72 --- /dev/null +++ b/code/datums/components/supermatter_crystal.dm @@ -0,0 +1,326 @@ +/datum/component/supermatter_crystal + + ///Callback for the wrench act call + var/datum/callback/tool_act_callback + ///Callback used by the SM to get the damage and matter power increase/decrease + var/datum/callback/consume_callback + +/datum/component/supermatter_crystal/Initialize(datum/callback/tool_act_callback, datum/callback/consume_callback) + + RegisterSignal(parent, COMSIG_ATOM_BLOB_ACT, .proc/blob_hit) + RegisterSignal(parent, COMSIG_ATOM_ATTACK_PAW, .proc/paw_hit) + RegisterSignal(parent, COMSIG_ATOM_ATTACK_ANIMAL, .proc/animal_hit) + RegisterSignal(parent, COMSIG_ATOM_HULK_ATTACK, .proc/hulk_hit) + RegisterSignal(parent, COMSIG_LIVING_UNARMED_ATTACK, .proc/unarmed_hit) + RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, .proc/hand_hit) + RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/attackby_hit) + RegisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_WRENCH), .proc/tool_hit) + RegisterSignal(parent, COMSIG_ATOM_BUMPED, .proc/bumped_hit) + RegisterSignal(parent, COMSIG_MOVABLE_BUMP, .proc/bump_hit) + RegisterSignal(parent, COMSIG_ATOM_INTERCEPT_Z_FALL, .proc/intercept_z_fall) + + src.tool_act_callback = tool_act_callback + src.consume_callback = consume_callback + +/datum/component/supermatter_crystal/UnregisterFromParent(force, silent) + var/list/signals_to_remove = list( + COMSIG_ATOM_BLOB_ACT, + COMSIG_ATOM_ATTACK_PAW, + COMSIG_ATOM_ATTACK_ANIMAL, + COMSIG_ATOM_HULK_ATTACK, + COMSIG_LIVING_UNARMED_ATTACK, + COMSIG_ATOM_ATTACK_HAND, + COMSIG_PARENT_ATTACKBY, + COMSIG_ATOM_TOOL_ACT(TOOL_WRENCH), + COMSIG_ATOM_BUMPED, + COMSIG_MOVABLE_BUMP, + COMSIG_ATOM_INTERCEPT_Z_FALL, + ) + + UnregisterSignal(parent, signals_to_remove) + +/datum/component/supermatter_crystal/proc/blob_hit(datum/source, obj/structure/blob/blob) + SIGNAL_HANDLER + var/atom/atom_source = source + if(!blob || isspaceturf(atom_source)) //does nothing in space + return + playsound(get_turf(atom_source), 'sound/effects/supermatter.ogg', 50, TRUE) + consume_returns(damage_increase = blob.get_integrity() * 0.5) + if(blob.get_integrity() > 100) + blob.visible_message(span_danger("\The [blob] strikes at \the [atom_source] and flinches away!"), + span_hear("You hear a loud crack as you are washed with a wave of heat.")) + blob.take_damage(100, BURN) + else + blob.visible_message(span_danger("\The [blob] strikes at \the [atom_source] and rapidly flashes to ash."), + span_hear("You hear a loud crack as you are washed with a wave of heat.")) + consume(atom_source, blob) + +/datum/component/supermatter_crystal/proc/paw_hit(datum/source, mob/user, list/modifiers) + SIGNAL_HANDLER + if(isalien(user)) + dust_mob(source, user, cause = "alien attack") + return + dust_mob(source, user, cause = "monkey attack") + +/datum/component/supermatter_crystal/proc/animal_hit(datum/source, mob/living/simple_animal/user, list/modifiers) + SIGNAL_HANDLER + var/atom/atom_source = source + var/murder + if(!user.melee_damage_upper && !user.melee_damage_lower) + murder = user.friendly_verb_continuous + else + murder = user.attack_verb_continuous + dust_mob(source, user, \ + span_danger("[user] unwisely [murder] [atom_source], and [user.p_their()] body burns brilliantly before flashing into ash!"), \ + span_userdanger("You unwisely touch [atom_source], and your vision glows brightly as your body crumbles to dust. Oops."), \ + "simple animal attack") + +/datum/component/supermatter_crystal/proc/hulk_hit(datum/source, mob/user) + SIGNAL_HANDLER + dust_mob(source, user, cause = "hulk attack") + +/datum/component/supermatter_crystal/proc/unarmed_hit(datum/source, mob/user, list/modifiers) + SIGNAL_HANDLER + var/atom/atom_source = source + if(iscyborg(user) && atom_source.Adjacent(user)) + dust_mob(source, user, cause = "cyborg attack") + return + if(isaicamera(user)) + return + if(islarva(user)) + dust_mob(source, user, cause = "larva attack") + return + +/datum/component/supermatter_crystal/proc/hand_hit(datum/source, mob/living/user, list/modifiers) + SIGNAL_HANDLER + var/atom/atom_source = source + if(user.incorporeal_move || user.status_flags & GODMODE) + return + + if(user.zone_selected != BODY_ZONE_PRECISE_MOUTH) + dust_mob(source, user, cause = "hand") + return + + if(!user.is_mouth_covered()) + if(user.combat_mode) + dust_mob(source, user, + span_danger("As [user] tries to take a bite out of [atom_source] everything goes silent before [user.p_their()] body starts to glow and burst into flames before flashing to ash."), + span_userdanger("You try to take a bite out of [atom_source], but find [p_them()] far too hard to get anywhere before everything starts burning and your ears fill with ringing!"), + "attempted bite" + ) + return + + var/obj/item/organ/internal/tongue/licking_tongue = user.getorganslot(ORGAN_SLOT_TONGUE) + if(licking_tongue) + dust_mob(source, user, + span_danger("As [user] hesitantly leans in and licks [atom_source] everything goes silent before [user.p_their()] body starts to glow and burst into flames before flashing to ash!"), + span_userdanger("You tentatively lick [atom_source], but you can't figure out what it tastes like before everything starts burning and your ears fill with ringing!"), + "attempted lick" + ) + return + + var/obj/item/bodypart/head/forehead = user.get_bodypart(BODY_ZONE_HEAD) + if(forehead) + dust_mob(source, user, + span_danger("As [user]'s forehead bumps into [atom_source], inducing a resonance... Everything goes silent before [user.p_their()] [forehead] flashes to ash!"), + span_userdanger("You feel your forehead bump into [atom_source] and everything suddenly goes silent. As your head fills with ringing you come to realize that that was not a wise decision."), + "failed lick" + ) + return + + dust_mob(source, user, + span_danger("[user] leans in and tries to lick [atom_source], inducing a resonance... [user.p_their()] body starts to glow and burst into flames before flashing into dust!"), + span_userdanger("You lean in and try to lick [atom_source]. Everything starts burning and all you can hear is ringing. Your last thought is \"That was not a wise decision.\""), + "failed lick" + ) + +/datum/component/supermatter_crystal/proc/attackby_hit(datum/source, obj/item/item, mob/living/user, params) + SIGNAL_HANDLER + var/atom/atom_source = source + if(!istype(item) || (item.item_flags & ABSTRACT) || !istype(user)) + return + if(istype(item, /obj/item/melee/roastingstick)) + return FALSE + if(istype(item, /obj/item/clothing/mask/cigarette)) + var/obj/item/clothing/mask/cigarette/cig = item + var/clumsy = HAS_TRAIT(user, TRAIT_CLUMSY) + if(clumsy) + var/which_hand = BODY_ZONE_L_ARM + if(!(user.active_hand_index % 2)) + which_hand = BODY_ZONE_R_ARM + var/obj/item/bodypart/dust_arm = user.get_bodypart(which_hand) + dust_arm.dismember() + user.visible_message(span_danger("The [item] flashes out of existence on contact with \the [atom_source], resonating with a horrible sound..."),\ + span_danger("Oops! The [item] flashes out of existence on contact with \the [atom_source], taking your arm with it! That was clumsy of you!")) + playsound(atom_source, 'sound/effects/supermatter.ogg', 150, TRUE) + consume(atom_source, dust_arm) + qdel(item) + return + if(cig.lit || user.combat_mode) + user.visible_message(span_danger("A hideous sound echoes as [item] is ashed out on contact with \the [atom_source]. That didn't seem like a good idea...")) + playsound(atom_source, 'sound/effects/supermatter.ogg', 150, TRUE) + consume(atom_source, item) + radiation_pulse(atom_source, max_range = 3, threshold = 0.1, chance = 50) + return + else + cig.light() + user.visible_message(span_danger("As [user] lights \their [item] on \the [atom_source], silence fills the room..."),\ + span_danger("Time seems to slow to a crawl as you touch \the [atom_source] with \the [item].\n\The [item] flashes alight with an eerie energy as you nonchalantly lift your hand away from \the [atom_source]. Damn.")) + playsound(atom_source, 'sound/effects/supermatter.ogg', 50, TRUE) + radiation_pulse(atom_source, max_range = 1, threshold = 0, chance = 100) + return + + if(user.dropItemToGround(item)) + user.visible_message(span_danger("As [user] touches \the [atom_source] with \a [item], silence fills the room..."),\ + span_userdanger("You touch \the [atom_source] with \the [item], and everything suddenly goes silent.\n\The [item] flashes into dust as you flinch away from \the [atom_source]."),\ + span_hear("Everything suddenly goes silent.")) + user.investigate_log("has been attacked ([item]) by [key_name(user)]", INVESTIGATE_ENGINE) + consume(atom_source, item) + playsound(get_turf(atom_source), 'sound/effects/supermatter.ogg', 50, TRUE) + + radiation_pulse(atom_source, max_range = 3, threshold = 0.1, chance = 50) + return + + if(atom_source.Adjacent(user)) //if the item is stuck to the person, kill the person too instead of eating just the item. + var/vis_msg = span_danger("[user] reaches out and touches [atom_source] with [item], inducing a resonance... [item] starts to glow briefly before the light continues up to [user]'s body. [user.p_they(TRUE)] bursts into flames before flashing into dust!") + var/mob_msg = span_userdanger("You reach out and touch [atom_source] with [item]. Everything starts burning and all you can hear is ringing. Your last thought is \"That was not a wise decision.\"") + dust_mob(source, user, vis_msg, mob_msg) + +/datum/component/supermatter_crystal/proc/tool_hit(datum/source, mob/user, obj/item/tool) + SIGNAL_HANDLER + if(tool_act_callback) + tool_act_callback.Invoke(user, tool) + return COMPONENT_BLOCK_TOOL_ATTACK + attackby_hit(source, tool, user) + +/datum/component/supermatter_crystal/proc/bumped_hit(datum/source, atom/movable/hit_object) + SIGNAL_HANDLER + var/atom/atom_source = source + if(isliving(hit_object)) + hit_object.visible_message(span_danger("\The [hit_object] slams into \the [atom_source] inducing a resonance... [hit_object.p_their()] body starts to glow and burst into flames before flashing into dust!"), + span_userdanger("You slam into \the [atom_source] as your ears are filled with unearthly ringing. Your last thought is \"Oh, fuck.\""), + span_hear("You hear an unearthly noise as a wave of heat washes over you.")) + else if(isobj(hit_object) && !iseffect(hit_object)) + hit_object.visible_message(span_danger("\The [hit_object] smacks into \the [atom_source] and rapidly flashes to ash."), null, + span_hear("You hear a loud crack as you are washed with a wave of heat.")) + else + return + + playsound(get_turf(atom_source), 'sound/effects/supermatter.ogg', 50, TRUE) + consume(atom_source, hit_object) + +/datum/component/supermatter_crystal/proc/bump_hit(datum/source, atom/bumped_atom) + SIGNAL_HANDLER + var/atom/atom_source = source + if(isturf(bumped_atom)) + var/turf/bumped_turf = bumped_atom + var/bumped_name = "\the [bumped_atom]" + var/bumped_text = span_danger("\The [atom_source] smacks into [bumped_name] and [bumped_atom.p_they()] rapidly flashes to ash!") + if(!bumped_turf.Melt()) + return + + atom_source.visible_message( + bumped_text, + null, + span_hear("You hear a loud crack as you are washed with a wave of heat.") + ) + playsound(atom_source, 'sound/effects/supermatter.ogg', 50, TRUE) + + var/suspicion = null + if (atom_source.fingerprintslast) + suspicion = "- and was last touched by [atom_source.fingerprintslast]" + message_admins("\The [atom_source] has consumed [bumped_name][suspicion].") + atom_source.investigate_log("has consumed [bumped_name][suspicion].") + + radiation_pulse(atom_source, max_range = 6, threshold = 0.2, chance = 50) + return + + if(isliving(bumped_atom)) + atom_source.visible_message( + span_danger("\The [atom_source] slams into \the [bumped_atom] inducing a resonance... [bumped_atom.p_their()] body starts to glow and burst into flames before flashing into dust!"), + span_userdanger("\The [atom_source] slams into you as your ears are filled with unearthly ringing. Your last thought is \"Oh, fuck.\""), + span_hear("You hear an unearthly noise as a wave of heat washes over you.") + ) + else if(isobj(bumped_atom) && !iseffect(bumped_atom)) + atom_source.visible_message( + span_danger("\The [atom_source] smacks into \the [bumped_atom] and [bumped_atom.p_they()] rapidly flashes to ash."), + null, + span_hear("You hear a loud crack as you are washed with a wave of heat.") + ) + else + return + + playsound(atom_source, 'sound/effects/supermatter.ogg', 50, TRUE) + consume(atom_source, bumped_atom) + +/datum/component/supermatter_crystal/proc/intercept_z_fall(datum/source, list/falling_movables, levels) + SIGNAL_HANDLER + for(var/atom/movable/hit_object as anything in falling_movables) + bumped_hit(hit_object) + +/datum/component/supermatter_crystal/proc/dust_mob(datum/source, mob/living/nom, vis_msg, mob_msg, cause) + var/atom/atom_source = source + if(nom.incorporeal_move || nom.status_flags & GODMODE) //try to keep supermatter sliver's + hemostat's dust conditions in sync with this too + return + if(!vis_msg) + vis_msg = span_danger("[nom] reaches out and touches [atom_source], inducing a resonance... [nom.p_their()] body starts to glow and burst into flames before flashing into dust!") + if(!mob_msg) + mob_msg = span_userdanger("You reach out and touch [atom_source]. Everything starts burning and all you can hear is ringing. Your last thought is \"That was not a wise decision.\"") + if(!cause) + cause = "contact" + nom.visible_message(vis_msg, mob_msg, span_hear("You hear an unearthly noise as a wave of heat washes over you.")) + atom_source.investigate_log("has been attacked ([cause]) by [key_name(nom)]", INVESTIGATE_ENGINE) + add_memory_in_range(atom_source, 7, MEMORY_SUPERMATTER_DUSTED, list(DETAIL_PROTAGONIST = nom, DETAIL_WHAT_BY = atom_source), story_value = STORY_VALUE_OKAY, memory_flags = MEMORY_CHECK_BLIND_AND_DEAF) + playsound(get_turf(atom_source), 'sound/effects/supermatter.ogg', 50, TRUE) + consume(atom_source, nom) + +/datum/component/supermatter_crystal/proc/consume(atom/source, atom/movable/consumed_object) + var/atom/atom_source = source + var/object_size = 0 + var/matter_increase = 0 + var/damage_increase = 0 + if(isliving(consumed_object)) + var/mob/living/consumed_mob = consumed_object + object_size = consumed_mob.mob_size + 2 + if(consumed_mob.status_flags & GODMODE) + return + message_admins("[atom_source] has consumed [key_name_admin(consumed_mob)] [ADMIN_JMP(atom_source)].") + atom_source.investigate_log("has consumed [key_name(consumed_mob)].", INVESTIGATE_ENGINE) + consumed_mob.dust(force = TRUE) + matter_increase += 100 * object_size + if(is_clown_job(consumed_mob.mind?.assigned_role)) + damage_increase += rand(-300, 300) // HONK + consume_returns(matter_increase, damage_increase) + else if(consumed_object.flags_1 & SUPERMATTER_IGNORES_1) + return + else if(isobj(consumed_object)) + if(!iseffect(consumed_object)) + var/suspicion = "" + if(consumed_object.fingerprintslast) + suspicion = "last touched by [consumed_object.fingerprintslast]" + message_admins("[atom_source] has consumed [consumed_object], [suspicion] [ADMIN_JMP(atom_source)].") + atom_source.investigate_log("has consumed [consumed_object] - [suspicion].", INVESTIGATE_ENGINE) + qdel(consumed_object) + if(!iseffect(consumed_object) && isitem(consumed_object)) + var/obj/item/consumed_item = consumed_object + object_size = consumed_item.w_class + matter_increase += 70 * object_size + + //Some poor sod got eaten, go ahead and irradiate people nearby. + radiation_pulse(atom_source, max_range = 6, threshold = 1.2 / max(object_size, 1), chance = 10 * object_size) + for(var/mob/living/near_mob in range(10)) + atom_source.investigate_log("has irradiated [key_name(near_mob)] after consuming [consumed_object].", INVESTIGATE_ENGINE) + if (HAS_TRAIT(near_mob, TRAIT_RADIMMUNE) || issilicon(near_mob)) + continue + if(ishuman(near_mob) && SSradiation.wearing_rad_protected_clothing(near_mob)) + continue + if(near_mob in view()) + near_mob.show_message(span_danger("As \the [atom_source] slowly stops resonating, you find your skin covered in new radiation burns."), MSG_VISUAL, + span_danger("The unearthly ringing subsides and you find your skin covered in new radiation burns."), MSG_AUDIBLE) + else + near_mob.show_message(span_hear("An unearthly ringing fills your ears, and you find your skin covered in new radiation burns."), MSG_AUDIBLE) + consume_returns(matter_increase, damage_increase) + +/datum/component/supermatter_crystal/proc/consume_returns(matter_increase = 0, damage_increase = 0) + if(consume_callback) + consume_callback.Invoke(matter_increase, damage_increase) diff --git a/code/datums/components/tackle.dm b/code/datums/components/tackle.dm index 28991d60341a5..f09638867edaa 100644 --- a/code/datums/components/tackle.dm +++ b/code/datums/components/tackle.dm @@ -247,10 +247,14 @@ var/attack_mod = 0 // DE-FENSE - if(target.drunkenness > 60) // drunks are easier to knock off balance + + // Drunks are easier to knock off balance + var/target_drunkenness = target.get_drunk_amount() + if(target_drunkenness > 60) defense_mod -= 3 - else if(target.drunkenness > 30) + else if(target_drunkenness > 30) defense_mod -= 1 + if(HAS_TRAIT(target, TRAIT_CLUMSY)) defense_mod -= 2 if(HAS_TRAIT(target, TRAIT_FAT)) // chonkers are harder to knock over @@ -284,18 +288,20 @@ defense_mod += 2 if(islizard(T)) - if(!T.getorganslot(ORGAN_SLOT_TAIL)) // lizards without tails are off-balance + var/obj/item/organ/external/tail/el_tail = T.getorganslot(ORGAN_SLOT_EXTERNAL_TAIL) + if(!el_tail) // lizards without tails are off-balance defense_mod -= 1 - else if(T.dna.species.is_wagging_tail()) // lizard tail wagging is robust and can swat away assailants! + else if(el_tail.wag_flags & WAG_WAGGING) // lizard tail wagging is robust and can swat away assailants! defense_mod += 1 // OF-FENSE var/mob/living/carbon/sacker = parent - - if(sacker.drunkenness > 60) // you're far too drunk to hold back! + var/sacker_drunkenness = sacker.get_drunk_amount() + if(sacker_drunkenness > 60) // you're far too drunk to hold back! attack_mod += 1 - else if(sacker.drunkenness > 30) // if you're only a bit drunk though, you're just sloppy + else if(sacker_drunkenness > 30) // if you're only a bit drunk though, you're just sloppy attack_mod -= 1 + if(HAS_TRAIT(sacker, TRAIT_CLUMSY)) attack_mod -= 2 if(HAS_TRAIT(sacker, TRAIT_DWARF)) @@ -419,7 +425,7 @@ user.visible_message(span_danger("[user] slams head-first into [hit], suffering major cranial trauma!"), span_userdanger("You slam head-first into [hit], and the world explodes around you!")) user.adjustStaminaLoss(30, updating_health=FALSE) user.adjustBruteLoss(30) - user.add_confusion(15) + user.adjust_timed_status_effect(15 SECONDS, /datum/status_effect/confusion) if(prob(80)) user.gain_trauma(/datum/brain_trauma/mild/concussion) user.playsound_local(get_turf(user), 'sound/weapons/flashbang.ogg', 100, TRUE, 8) @@ -431,7 +437,7 @@ user.visible_message(span_danger("[user] slams hard into [hit], knocking [user.p_them()] senseless!"), span_userdanger("You slam hard into [hit], knocking yourself senseless!")) user.adjustStaminaLoss(30, updating_health=FALSE) user.adjustBruteLoss(10) - user.add_confusion(10) + user.adjust_timed_status_effect(10 SECONDS, /datum/status_effect/confusion) user.Knockdown(30) shake_camera(user, 3, 4) diff --git a/code/datums/components/twohanded.dm b/code/datums/components/twohanded.dm index d1f78b5611406..1b69c2108431f 100644 --- a/code/datums/components/twohanded.dm +++ b/code/datums/components/twohanded.dm @@ -17,6 +17,11 @@ var/icon_wielded = FALSE /// The icon that will be used when wielded var/obj/item/offhand/offhand_item = null /// Reference to the offhand created for the item var/sharpened_increase = 0 /// The amount of increase recived from sharpening the item + /// A callback on the parent to be called when the item is wielded + var/datum/callback/wield_callback + /// A callback on the parent to be called when the item is unwielded + var/datum/callback/unwield_callback + /** * Two Handed component @@ -32,7 +37,8 @@ * * icon_wielded (optional) The icon to be used when wielded */ /datum/component/two_handed/Initialize(require_twohands=FALSE, wieldsound=FALSE, unwieldsound=FALSE, attacksound=FALSE, \ - force_multiplier=0, force_wielded=0, force_unwielded=0, icon_wielded=FALSE) + force_multiplier=0, force_wielded=0, force_unwielded=0, icon_wielded=FALSE, \ + datum/callback/wield_callback, datum/callback/unwield_callback) if(!isitem(parent)) return COMPONENT_INCOMPATIBLE @@ -44,13 +50,16 @@ src.force_wielded = force_wielded src.force_unwielded = force_unwielded src.icon_wielded = icon_wielded + src.wield_callback = wield_callback + src.unwield_callback = unwield_callback if(require_twohands) ADD_TRAIT(parent, TRAIT_NEEDS_TWO_HANDS, ABSTRACT_ITEM_TRAIT) // Inherit the new values passed to the component /datum/component/two_handed/InheritComponent(datum/component/two_handed/new_comp, original, require_twohands, wieldsound, unwieldsound, \ - force_multiplier, force_wielded, force_unwielded, icon_wielded) + force_multiplier, force_wielded, force_unwielded, icon_wielded, \ + datum/callback/wield_callback, datum/callback/unwield_callback) if(!original) return if(require_twohands) @@ -69,6 +78,10 @@ src.force_unwielded = force_unwielded if(icon_wielded) src.icon_wielded = icon_wielded + if(wield_callback) + src.wield_callback = wield_callback + if(unwield_callback) + src.unwield_callback = unwield_callback // register signals withthe parent item /datum/component/two_handed/RegisterWithParent() @@ -160,6 +173,7 @@ wielded = TRUE ADD_TRAIT(parent,TRAIT_WIELDED,src) RegisterSignal(user, COMSIG_MOB_SWAP_HANDS, .proc/on_swap_hands) + wield_callback?.Invoke(parent, user) // update item stats and name var/obj/item/parent_item = parent @@ -207,6 +221,7 @@ UnregisterSignal(user, COMSIG_MOB_SWAP_HANDS) SEND_SIGNAL(parent, COMSIG_TWOHANDED_UNWIELD, user) REMOVE_TRAIT(parent,TRAIT_WIELDED,src) + unwield_callback?.Invoke(parent, user) // update item stats var/obj/item/parent_item = parent diff --git a/code/datums/components/wet_floor.dm b/code/datums/components/wet_floor.dm index e21750aec8da7..594ab849e039f 100644 --- a/code/datums/components/wet_floor.dm +++ b/code/datums/components/wet_floor.dm @@ -67,9 +67,11 @@ T.add_overlay(intended) current_overlay = intended -/datum/component/wet_floor/proc/AfterSlip(mob/living/L) - if(highest_strength == TURF_WET_LUBE) - L.set_confusion(max(L.get_confusion(), 8)) +/datum/component/wet_floor/proc/AfterSlip(mob/living/slipped) + if(highest_strength != TURF_WET_LUBE) + return + + slipped.set_timed_status_effect(8 SECONDS, /datum/status_effect/confusion, only_if_higher = TRUE) /datum/component/wet_floor/proc/update_flags() var/intensity diff --git a/code/datums/components/z_parallax.dm b/code/datums/components/z_parallax.dm new file mode 100644 index 0000000000000..3d4aa65d17899 --- /dev/null +++ b/code/datums/components/z_parallax.dm @@ -0,0 +1,60 @@ +/** + * Component that hooks into the client, listens for COMSIG_MOVABLE_Z_CHANGED, and depending on whether or not the + * Z-level has ZTRAIT_NOPARALLAX enabled, disable or reenable parallax. + */ + +/datum/component/zparallax + dupe_mode = COMPONENT_DUPE_UNIQUE + + var/client/tracked + var/mob/client_mob + +/datum/component/zparallax/Initialize(client/tracked) + . = ..() + if(!istype(tracked)) + stack_trace("Component zparallax has been initialized outside of a client. Deleting.") + return COMPONENT_INCOMPATIBLE + + src.tracked = tracked + client_mob = tracked.mob + + RegisterSignal(client_mob, COMSIG_MOB_LOGOUT, .proc/mob_change) + RegisterSignal(client_mob, COMSIG_MOVABLE_Z_CHANGED, .proc/ztrait_checks) + RegisterSignal(client_mob, COMSIG_MOB_LOGIN, .proc/refresh_client) + +/datum/component/zparallax/Destroy() + . = ..() + unregister_signals() + + tracked = null + client_mob = null + +/datum/component/zparallax/proc/unregister_signals() + if(!client_mob) + return + + UnregisterSignal(client_mob, list(COMSIG_MOB_LOGIN, COMSIG_MOB_LOGOUT, COMSIG_MOVABLE_Z_CHANGED)) + +/datum/component/zparallax/proc/refresh_client() + tracked = client_mob.client + +/datum/component/zparallax/proc/mob_change() + SIGNAL_HANDLER + + if(client_mob.key) + return + + unregister_signals() + + client_mob = tracked.mob + + RegisterSignal(client_mob, COMSIG_MOB_LOGOUT, .proc/mob_change) + RegisterSignal(client_mob, COMSIG_MOVABLE_Z_CHANGED, .proc/ztrait_checks) + RegisterSignal(client_mob, COMSIG_MOB_LOGIN, .proc/refresh_client) + +/datum/component/zparallax/proc/ztrait_checks() + SIGNAL_HANDLER + + var/datum/hud/hud = client_mob.hud_used + + hud.update_parallax_pref(client_mob) diff --git a/code/datums/dash_weapon.dm b/code/datums/dash_weapon.dm index d4251b414c9ca..f0062228e4b65 100644 --- a/code/datums/dash_weapon.dm +++ b/code/datums/dash_weapon.dm @@ -10,6 +10,7 @@ var/dash_sound = 'sound/magic/blink.ogg' var/recharge_sound = 'sound/magic/charge.ogg' var/beam_effect = "blur" + var/beam_length = 2 SECONDS var/phasein = /obj/effect/temp_visual/dir_setting/ninja/phase var/phaseout = /obj/effect/temp_visual/dir_setting/ninja/phase/out @@ -33,18 +34,19 @@ /// Teleports user to target using do_teleport. Returns TRUE if teleport successful, FALSE otherwise. /datum/action/innate/dash/proc/teleport(mob/user, atom/target) if(!IsAvailable()) + user.balloon_alert(user, "no charges!") return FALSE + var/turf/current_turf = get_turf(user) var/turf/target_turf = get_turf(target) if(target in view(user.client.view, user)) if(!do_teleport(user, target_turf, no_effects = TRUE)) user.balloon_alert(user, "dash blocked by location!") return FALSE - - var/obj/spot1 = new phaseout(get_turf(user), user.dir) + var/obj/spot1 = new phaseout(current_turf, user.dir) + var/obj/spot2 = new phasein(target_turf, user.dir) + spot1.Beam(spot2,beam_effect, time = beam_length) playsound(target_turf, dash_sound, 25, TRUE) - var/obj/spot2 = new phasein(get_turf(user), user.dir) - spot1.Beam(spot2,beam_effect,time=2 SECONDS) current_charges-- owner.update_action_buttons_icon() addtimer(CALLBACK(src, .proc/charge), charge_rate) diff --git a/code/datums/diseases/_MobProcs.dm b/code/datums/diseases/_MobProcs.dm index e20fb3ba1c9bb..024f1ee94f2c1 100644 --- a/code/datums/diseases/_MobProcs.dm +++ b/code/datums/diseases/_MobProcs.dm @@ -32,84 +32,68 @@ D.try_infect(src) -/mob/living/carbon/ContactContractDisease(datum/disease/D, target_zone) - if(!CanContractDisease(D)) +/mob/living/carbon/ContactContractDisease(datum/disease/disease, target_zone) + if(!CanContractDisease(disease)) return FALSE - var/obj/item/clothing/Cl = null var/passed = TRUE - var/head_ch = 80 - var/body_ch = 100 - var/hands_ch = 35 - var/feet_ch = 15 + var/head_chance = 80 + var/body_chance = 100 + var/hands_chance = 35/2 + var/feet_chance = 15/2 - if(prob(15/D.permeability_mod)) + if(prob(15/disease.spreading_modifier)) return if(satiety>0 && prob(satiety/10)) // positive satiety makes it harder to contract the disease. return - //Lefts and rights do not matter for arms and legs, they both run the same checks if(!target_zone) - target_zone = pick(head_ch;BODY_ZONE_HEAD,body_ch;BODY_ZONE_CHEST,hands_ch;BODY_ZONE_L_ARM,feet_ch;BODY_ZONE_L_LEG) + target_zone = pick_weight(list( + BODY_ZONE_HEAD = head_chance, + BODY_ZONE_CHEST = body_chance, + BODY_ZONE_R_ARM = hands_chance, + BODY_ZONE_L_ARM = hands_chance, + BODY_ZONE_R_LEG = feet_chance, + BODY_ZONE_L_LEG = feet_chance, + )) else target_zone = check_zone(target_zone) - - - if(ismonkey(src)) - var/mob/living/carbon/human/M = src - switch(target_zone) - if(BODY_ZONE_HEAD) - if(M.wear_mask && isobj(M.wear_mask)) - Cl = M.wear_mask - passed = prob((Cl.permeability_coefficient*100) - 1) - - else if(ishuman(src)) - var/mob/living/carbon/human/H = src + if(ishuman(src)) + var/mob/living/carbon/human/infecting_human = src switch(target_zone) if(BODY_ZONE_HEAD) - if(isobj(H.head) && !istype(H.head, /obj/item/paper)) - Cl = H.head - passed = prob((Cl.permeability_coefficient*100) - 1) - if(passed && isobj(H.wear_mask)) - Cl = H.wear_mask - passed = prob((Cl.permeability_coefficient*100) - 1) - if(passed && isobj(H.wear_neck)) - Cl = H.wear_neck - passed = prob((Cl.permeability_coefficient*100) - 1) + if(isobj(infecting_human.head)) + passed = prob(100-infecting_human.head.armor.getRating(BIO)) + if(passed && isobj(infecting_human.wear_mask)) + passed = prob(100-infecting_human.wear_mask.armor.getRating(BIO)) + if(passed && isobj(infecting_human.wear_neck)) + passed = prob(100-infecting_human.wear_neck.armor.getRating(BIO)) if(BODY_ZONE_CHEST) - if(isobj(H.wear_suit)) - Cl = H.wear_suit - passed = prob((Cl.permeability_coefficient*100) - 1) - if(passed && isobj(ITEM_SLOT_ICLOTHING)) - Cl = ITEM_SLOT_ICLOTHING - passed = prob((Cl.permeability_coefficient*100) - 1) + if(isobj(infecting_human.wear_suit)) + passed = prob(100-infecting_human.wear_suit.armor.getRating(BIO)) + if(passed && isobj(infecting_human.w_uniform)) + passed = prob(100-infecting_human.w_uniform.armor.getRating(BIO)) if(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM) - if(isobj(H.wear_suit) && H.wear_suit.body_parts_covered&HANDS) - Cl = H.wear_suit - passed = prob((Cl.permeability_coefficient*100) - 1) - - if(passed && isobj(H.gloves)) - Cl = H.gloves - passed = prob((Cl.permeability_coefficient*100) - 1) + if(isobj(infecting_human.wear_suit) && infecting_human.wear_suit.body_parts_covered&HANDS) + passed = prob(100-infecting_human.wear_suit.armor.getRating(BIO)) + if(passed && isobj(infecting_human.gloves)) + passed = prob(100-infecting_human.gloves.armor.getRating(BIO)) if(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) - if(isobj(H.wear_suit) && H.wear_suit.body_parts_covered&FEET) - Cl = H.wear_suit - passed = prob((Cl.permeability_coefficient*100) - 1) - - if(passed && isobj(H.shoes)) - Cl = H.shoes - passed = prob((Cl.permeability_coefficient*100) - 1) + if(isobj(infecting_human.wear_suit) && infecting_human.wear_suit.body_parts_covered&FEET) + passed = prob(100-infecting_human.wear_suit.armor.getRating(BIO)) + if(passed && isobj(infecting_human.shoes)) + passed = prob(100-infecting_human.shoes.armor.getRating(BIO)) if(passed) - D.try_infect(src) + disease.try_infect(src) -/mob/living/proc/AirborneContractDisease(datum/disease/D, force_spread) - if( ((D.spread_flags & DISEASE_SPREAD_AIRBORNE) || force_spread) && prob((50*D.permeability_mod) - 1)) - ForceContractDisease(D) +/mob/living/proc/AirborneContractDisease(datum/disease/disease, force_spread) + if(((disease.spread_flags & DISEASE_SPREAD_AIRBORNE) || force_spread) && prob((50*disease.spreading_modifier) - 1)) + ForceContractDisease(disease) /mob/living/carbon/AirborneContractDisease(datum/disease/D, force_spread) if(internal) diff --git a/code/datums/diseases/_disease.dm b/code/datums/diseases/_disease.dm index 2306f13407c61..f85b0a4ca89e9 100644 --- a/code/datums/diseases/_disease.dm +++ b/code/datums/diseases/_disease.dm @@ -28,7 +28,7 @@ var/cure_chance = 4 var/carrier = FALSE //If our host is only a carrier var/bypasses_immunity = FALSE //Does it skip species virus immunity check? Some things may diseases and not viruses - var/permeability_mod = 1 + var/spreading_modifier = 1 var/severity = DISEASE_SEVERITY_NONTHREAT var/list/required_organs = list() var/needs_all_cures = TRUE @@ -61,10 +61,6 @@ var/turf/source_turf = get_turf(infectee) log_virus("[key_name(infectee)] was infected by virus: [src.admin_details()] at [loc_name(source_turf)]") -//Return a string for admin logging uses, should describe the disease in detail -/datum/disease/proc/admin_details() - return "[src.name] : [src.type]" - ///Proc to process the disease and decide on whether to advance, cure or make the sympthoms appear. Returns a boolean on whether to continue acting on the symptoms or not. /datum/disease/proc/stage_act(delta_time, times_fired) @@ -147,7 +143,7 @@ //note that stage is not copied over - the copy starts over at stage 1 var/static/list/copy_vars = list("name", "visibility_flags", "disease_flags", "spread_flags", "form", "desc", "agent", "spread_text", "cure_text", "max_stages", "stage_prob", "viable_mobtypes", "cures", "infectivity", "cure_chance", - "bypasses_immunity", "permeability_mod", "severity", "required_organs", "needs_all_cures", "strain_data", + "bypasses_immunity", "spreading_modifier", "severity", "required_organs", "needs_all_cures", "strain_data", "infectable_biotypes", "process_dead") var/datum/disease/D = copy_type ? new copy_type() : new type() diff --git a/code/datums/diseases/adrenal_crisis.dm b/code/datums/diseases/adrenal_crisis.dm index 9fe40fb6354e0..011b76fdda3dd 100644 --- a/code/datums/diseases/adrenal_crisis.dm +++ b/code/datums/diseases/adrenal_crisis.dm @@ -7,7 +7,7 @@ cure_chance = 10 agent = "Shitty Adrenal Glands" viable_mobtypes = list(/mob/living/carbon/human) - permeability_mod = 1 + spreading_modifier = 1 desc = "If left untreated the subject will suffer from lethargy, dizziness and periodic loss of conciousness." severity = DISEASE_SEVERITY_MEDIUM disease_flags = CAN_CARRY|CAN_RESIST @@ -32,7 +32,7 @@ affected_mob.adjust_timed_status_effect(14 SECONDS, /datum/status_effect/speech/slurring/drunk) if(DT_PROB(7, delta_time)) - affected_mob.Dizzy(10) + affected_mob.set_timed_status_effect(20 SECONDS, /datum/status_effect/dizziness, only_if_higher = TRUE) if(DT_PROB(2.5, delta_time)) to_chat(affected_mob, span_warning(pick("You feel pain shoot down your legs!", "You feel like you are going to pass out at any moment.", "You feel really dizzy."))) diff --git a/code/datums/diseases/advance/advance.dm b/code/datums/diseases/advance/advance.dm index cf9b40693af81..265ed0e562070 100644 --- a/code/datums/diseases/advance/advance.dm +++ b/code/datums/diseases/advance/advance.dm @@ -155,19 +155,6 @@ //this is a new disease starting over at stage 1, so processing is not copied return A -//Describe this disease to an admin in detail (for logging) -/datum/disease/advance/admin_details() - var/list/name_symptoms = list() - for(var/datum/symptom/S in symptoms) - name_symptoms += S.name - return "[name] sym:[english_list(name_symptoms)] r:[totalResistance()] s:[totalStealth()] ss:[totalStageSpeed()] t:[totalTransmittable()]" - -/* - - NEW PROCS - - */ - // Mix the symptoms of two diseases (the src and the argument) /datum/disease/advance/proc/Mix(datum/disease/advance/D) if(!(IsSame(D))) @@ -253,7 +240,7 @@ else SetSpread(DISEASE_SPREAD_BLOOD) - permeability_mod = max(CEILING(0.4 * properties["transmittable"], 1), 1) + spreading_modifier = max(CEILING(0.4 * properties["transmittable"], 1), 1) cure_chance = clamp(7.5 - (0.5 * properties["resistance"]), 5, 10) // can be between 5 and 10 stage_prob = max(0.5 * properties["stage_rate"], 1) SetSeverity(properties["severity"]) diff --git a/code/datums/diseases/advance/symptoms/confusion.dm b/code/datums/diseases/advance/symptoms/confusion.dm index e1e7e1ba3986f..3e842ce2a0a0a 100644 --- a/code/datums/diseases/advance/symptoms/confusion.dm +++ b/code/datums/diseases/advance/symptoms/confusion.dm @@ -37,7 +37,7 @@ suppress_warning = TRUE /datum/symptom/confusion/End(datum/disease/advance/A) - A.affected_mob.set_confusion(0) + A.affected_mob.remove_status_effect(/datum/status_effect/confusion) return ..() /datum/symptom/confusion/Activate(datum/disease/advance/A) @@ -51,7 +51,7 @@ to_chat(M, span_warning("[pick("Your head hurts.", "Your mind blanks for a moment.")]")) else to_chat(M, span_userdanger("You can't think straight!")) - M.add_confusion(16 * power) + M.adjust_timed_status_effect(16 SECONDS * power, /datum/status_effect/confusion) if(brain_damage) M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 3 * power, 80) M.updatehealth() diff --git a/code/datums/diseases/advance/symptoms/deafness.dm b/code/datums/diseases/advance/symptoms/deafness.dm index c4176614054a8..2febbed6e9114 100644 --- a/code/datums/diseases/advance/symptoms/deafness.dm +++ b/code/datums/diseases/advance/symptoms/deafness.dm @@ -37,7 +37,7 @@ if(!.) return var/mob/living/carbon/M = A.affected_mob - var/obj/item/organ/ears/ears = M.getorganslot(ORGAN_SLOT_EARS) + var/obj/item/organ/internal/ears/ears = M.getorganslot(ORGAN_SLOT_EARS) if(!ears) return //cutting off your ears to cure the deafness: the ultimate own switch(A.stage) diff --git a/code/datums/diseases/advance/symptoms/dizzy.dm b/code/datums/diseases/advance/symptoms/dizzy.dm index ada4236f823e8..511455734454e 100644 --- a/code/datums/diseases/advance/symptoms/dizzy.dm +++ b/code/datums/diseases/advance/symptoms/dizzy.dm @@ -44,7 +44,6 @@ to_chat(M, span_warning("[pick("You feel dizzy.", "Your head spins.")]")) else to_chat(M, span_userdanger("A wave of dizziness washes over you!")) - if(M.dizziness <= 70) - M.dizziness += 30 + M.adjust_timed_status_effect(1 MINUTES, /datum/status_effect/dizziness, max_duration = 140 SECONDS) if(power >= 2) M.set_timed_status_effect(80 SECONDS, /datum/status_effect/drugginess) diff --git a/code/datums/diseases/advance/symptoms/fire.dm b/code/datums/diseases/advance/symptoms/fire.dm index f9e0555deb4bd..dbbe76abcf017 100644 --- a/code/datums/diseases/advance/symptoms/fire.dm +++ b/code/datums/diseases/advance/symptoms/fire.dm @@ -51,12 +51,12 @@ to_chat(M, span_warning("[pick("You feel hot.", "You hear a crackling noise.", "You smell smoke.")]")) if(4) Firestacks_stage_4(M, A) - M.IgniteMob() + M.ignite_mob() to_chat(M, span_userdanger("Your skin bursts into flames!")) M.emote("scream") if(5) Firestacks_stage_5(M, A) - M.IgniteMob() + M.ignite_mob() to_chat(M, span_userdanger("Your skin erupts into an inferno!")) M.emote("scream") @@ -134,7 +134,7 @@ Bonus M.visible_message(span_warning("[M]'s sweat sizzles and pops on contact with water!")) explosion(M, devastation_range = -1, heavy_impact_range = (-1 + explosion_power), light_impact_range = (2 * explosion_power), explosion_cause = src) Alkali_fire_stage_4(M, A) - M.IgniteMob() + M.ignite_mob() to_chat(M, span_userdanger("Your sweat bursts into flames!")) M.emote("scream") if(5) @@ -142,7 +142,7 @@ Bonus M.visible_message(span_warning("[M]'s sweat sizzles and pops on contact with water!")) explosion(M, devastation_range = -1, heavy_impact_range = (-1 + explosion_power), light_impact_range = (2 * explosion_power), explosion_cause = src) Alkali_fire_stage_5(M, A) - M.IgniteMob() + M.ignite_mob() to_chat(M, span_userdanger("Your skin erupts into an inferno!")) M.emote("scream") diff --git a/code/datums/diseases/advance/symptoms/heal.dm b/code/datums/diseases/advance/symptoms/heal.dm index da8cf315d82e9..f92cd30a927c8 100644 --- a/code/datums/diseases/advance/symptoms/heal.dm +++ b/code/datums/diseases/advance/symptoms/heal.dm @@ -455,7 +455,7 @@ . = 0 var/mob/living/M = A.affected_mob if(M.fire_stacks < 0) - M.set_fire_stacks(min(M.fire_stacks + 1 * absorption_coeff, 0)) + M.adjust_fire_stacks(min(absorption_coeff, -M.fire_stacks)) . += power if(M.reagents.has_reagent(/datum/reagent/water/holywater, needs_metabolizing = FALSE)) M.reagents.remove_reagent(/datum/reagent/water/holywater, 0.5 * absorption_coeff) diff --git a/code/datums/diseases/advance/symptoms/sensory.dm b/code/datums/diseases/advance/symptoms/sensory.dm index a77db16814415..2eab2b6a5bb4c 100644 --- a/code/datums/diseases/advance/symptoms/sensory.dm +++ b/code/datums/diseases/advance/symptoms/sensory.dm @@ -43,16 +43,13 @@ if(A.stage >= 3) - M.dizziness = max(0, M.dizziness - 2) + M.adjust_timed_status_effect(-4 SECONDS, /datum/status_effect/dizziness) M.adjust_drowsyness(-2) M.adjust_timed_status_effect(-1 SECONDS, /datum/status_effect/speech/slurring/drunk) - - M.set_confusion(max(0, M.get_confusion() - 2)) + M.adjust_timed_status_effect(-2 SECONDS, /datum/status_effect/confusion) if(purge_alcohol) M.reagents.remove_all_type(/datum/reagent/consumable/ethanol, 3) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - H.drunkenness = max(H.drunkenness - 5, 0) + M.adjust_drunk_effect(-5) if(A.stage >= 4) M.adjust_drowsyness(-2) @@ -93,12 +90,12 @@ var/mob/living/carbon/M = A.affected_mob switch(A.stage) if(4, 5) - var/obj/item/organ/ears/ears = M.getorganslot(ORGAN_SLOT_EARS) + var/obj/item/organ/internal/ears/ears = M.getorganslot(ORGAN_SLOT_EARS) if(ears) ears.adjustEarDamage(-4, -4) M.adjust_blindness(-2) M.adjust_blurriness(-2) - var/obj/item/organ/eyes/eyes = M.getorganslot(ORGAN_SLOT_EYES) + var/obj/item/organ/internal/eyes/eyes = M.getorganslot(ORGAN_SLOT_EYES) if(!eyes) // only dealing with eye stuff from here on out return eyes.applyOrganDamage(-2) diff --git a/code/datums/diseases/advance/symptoms/vision.dm b/code/datums/diseases/advance/symptoms/vision.dm index c171a0a2c390b..eb8ca5e87620d 100644 --- a/code/datums/diseases/advance/symptoms/vision.dm +++ b/code/datums/diseases/advance/symptoms/vision.dm @@ -38,7 +38,7 @@ if(!.) return var/mob/living/carbon/M = A.affected_mob - var/obj/item/organ/eyes/eyes = M.getorganslot(ORGAN_SLOT_EYES) + var/obj/item/organ/internal/eyes/eyes = M.getorganslot(ORGAN_SLOT_EYES) if(eyes) switch(A.stage) if(1, 2) diff --git a/code/datums/diseases/anxiety.dm b/code/datums/diseases/anxiety.dm index a177441f89037..37235d9f2e1f0 100644 --- a/code/datums/diseases/anxiety.dm +++ b/code/datums/diseases/anxiety.dm @@ -28,15 +28,15 @@ to_chat(affected_mob, span_notice("You feel panicky.")) if(DT_PROB(1, delta_time)) to_chat(affected_mob, span_danger("You're overtaken with panic!")) - affected_mob.add_confusion(rand(2,3)) + affected_mob.adjust_timed_status_effect(rand(2 SECONDS, 3 SECONDS), /datum/status_effect/confusion) if(4) if(DT_PROB(5, delta_time)) to_chat(affected_mob, span_danger("You feel butterflies in your stomach.")) if(DT_PROB(2.5, delta_time)) affected_mob.visible_message(span_danger("[affected_mob] stumbles around in a panic."), \ span_userdanger("You have a panic attack!")) - affected_mob.add_confusion(rand(6,8)) - affected_mob.jitteriness += (rand(6,8)) + affected_mob.adjust_timed_status_effect(rand(6 SECONDS, 8 SECONDS), /datum/status_effect/confusion) + affected_mob.adjust_timed_status_effect(rand(12 SECONDS, 16 SECONDS), /datum/status_effect/jitter) if(DT_PROB(1, delta_time)) affected_mob.visible_message(span_danger("[affected_mob] coughs up butterflies!"), \ span_userdanger("You cough up butterflies!")) diff --git a/code/datums/diseases/brainrot.dm b/code/datums/diseases/brainrot.dm index 89e6b085a236a..44cb3d7256ea2 100644 --- a/code/datums/diseases/brainrot.dm +++ b/code/datums/diseases/brainrot.dm @@ -9,7 +9,7 @@ viable_mobtypes = list(/mob/living/carbon/human) cure_chance = 7.5 //higher chance to cure, since two reagents are required desc = "This disease destroys the braincells, causing brain fever, brain necrosis and general intoxication." - required_organs = list(/obj/item/organ/brain) + required_organs = list(/obj/item/organ/internal/brain) severity = DISEASE_SEVERITY_HARMFUL diff --git a/code/datums/diseases/cold.dm b/code/datums/diseases/cold.dm index d40b307caf190..61b79b43e7de1 100644 --- a/code/datums/diseases/cold.dm +++ b/code/datums/diseases/cold.dm @@ -5,7 +5,7 @@ cures = list(/datum/reagent/medicine/spaceacillin) agent = "XY-rhinovirus" viable_mobtypes = list(/mob/living/carbon/human) - permeability_mod = 0.5 + spreading_modifier = 0.5 desc = "If left untreated the subject will contract the flu." severity = DISEASE_SEVERITY_NONTHREAT diff --git a/code/datums/diseases/flu.dm b/code/datums/diseases/flu.dm index 38f18fba44cd8..33335160e9c3d 100644 --- a/code/datums/diseases/flu.dm +++ b/code/datums/diseases/flu.dm @@ -7,7 +7,7 @@ cure_chance = 5 agent = "H13N1 flu virion" viable_mobtypes = list(/mob/living/carbon/human) - permeability_mod = 0.75 + spreading_modifier = 0.75 desc = "If left untreated the subject will feel quite unwell." severity = DISEASE_SEVERITY_MINOR diff --git a/code/datums/diseases/fluspanish.dm b/code/datums/diseases/fluspanish.dm index 85998123bdc63..d13352b760479 100644 --- a/code/datums/diseases/fluspanish.dm +++ b/code/datums/diseases/fluspanish.dm @@ -7,7 +7,7 @@ cure_chance = 5 agent = "1nqu1s1t10n flu virion" viable_mobtypes = list(/mob/living/carbon/human) - permeability_mod = 0.75 + spreading_modifier = 0.75 desc = "If left untreated the subject will burn to death for being a heretic." severity = DISEASE_SEVERITY_DANGEROUS diff --git a/code/datums/diseases/gastrolisis.dm b/code/datums/diseases/gastrolisis.dm index f5c26ea744f46..8a2c3992d1579 100644 --- a/code/datums/diseases/gastrolisis.dm +++ b/code/datums/diseases/gastrolisis.dm @@ -36,9 +36,9 @@ if(isopenturf(OT)) OT.MakeSlippery(TURF_WET_LUBE, 100) if(4) - var/obj/item/organ/eyes/eyes = locate(/obj/item/organ/eyes/snail) in affected_mob.internal_organs + var/obj/item/organ/internal/eyes/eyes = locate(/obj/item/organ/internal/eyes/snail) in affected_mob.internal_organs if(!eyes && DT_PROB(2.5, delta_time)) - var/obj/item/organ/eyes/snail/new_eyes = new() + var/obj/item/organ/internal/eyes/snail/new_eyes = new() new_eyes.Insert(affected_mob, drop_if_replaced = TRUE) affected_mob.visible_message(span_warning("[affected_mob]'s eyes fall out, with snail eyes taking its place!"), \ span_userdanger("You scream in pain as your eyes are pushed out by your new snail eyes!")) @@ -56,9 +56,9 @@ affected_mob.emote("scream") return - var/obj/item/organ/tongue/tongue = locate(/obj/item/organ/tongue/snail) in affected_mob.internal_organs + var/obj/item/organ/internal/tongue/tongue = locate(/obj/item/organ/internal/tongue/snail) in affected_mob.internal_organs if(!tongue && DT_PROB(2.5, delta_time)) - var/obj/item/organ/tongue/snail/new_tongue = new() + var/obj/item/organ/internal/tongue/snail/new_tongue = new() new_tongue.Insert(affected_mob) to_chat(affected_mob, span_userdanger("You feel your speech slow down...")) return @@ -83,13 +83,13 @@ . = ..() if(affected_mob && !is_species(affected_mob, /datum/species/snail)) //undo all the snail fuckening var/mob/living/carbon/human/H = affected_mob - var/obj/item/organ/tongue/tongue = locate(/obj/item/organ/tongue/snail) in H.internal_organs + var/obj/item/organ/internal/tongue/tongue = locate(/obj/item/organ/internal/tongue/snail) in H.internal_organs if(tongue) - var/obj/item/organ/tongue/new_tongue = new H.dna.species.mutanttongue () + var/obj/item/organ/internal/tongue/new_tongue = new H.dna.species.mutanttongue () new_tongue.Insert(H) - var/obj/item/organ/eyes/eyes = locate(/obj/item/organ/eyes/snail) in H.internal_organs + var/obj/item/organ/internal/eyes/eyes = locate(/obj/item/organ/internal/eyes/snail) in H.internal_organs if(eyes) - var/obj/item/organ/eyes/new_eyes = new H.dna.species.mutanteyes () + var/obj/item/organ/internal/eyes/new_eyes = new H.dna.species.mutanteyes () new_eyes.Insert(H) var/obj/item/storage/backpack/bag = H.get_item_by_slot(ITEM_SLOT_BACK) if(istype(bag, /obj/item/storage/backpack/snail)) diff --git a/code/datums/diseases/gbs.dm b/code/datums/diseases/gbs.dm index 524b547ac002f..df3889f06dfef 100644 --- a/code/datums/diseases/gbs.dm +++ b/code/datums/diseases/gbs.dm @@ -9,7 +9,7 @@ agent = "Gravitokinetic Bipotential SADS+" viable_mobtypes = list(/mob/living/carbon/human) disease_flags = CAN_CARRY|CAN_RESIST|CURABLE - permeability_mod = 1 + spreading_modifier = 1 severity = DISEASE_SEVERITY_BIOHAZARD /datum/disease/gbs/stage_act(delta_time, times_fired) diff --git a/code/datums/diseases/heart_failure.dm b/code/datums/diseases/heart_failure.dm index 8bf8c5e9475be..57be48b587942 100644 --- a/code/datums/diseases/heart_failure.dm +++ b/code/datums/diseases/heart_failure.dm @@ -6,13 +6,13 @@ cure_text = "Heart replacement surgery to cure. Defibrillation (or as a last resort, uncontrolled electric shocking) may also be effective after the onset of cardiac arrest. Penthrite can also mitigate cardiac arrest." agent = "Shitty Heart" viable_mobtypes = list(/mob/living/carbon/human) - permeability_mod = 1 + spreading_modifier = 1 desc = "If left untreated the subject will die!" severity = "Dangerous!" disease_flags = CAN_CARRY|CAN_RESIST spread_flags = DISEASE_SPREAD_NON_CONTAGIOUS visibility_flags = HIDDEN_PANDEMIC - required_organs = list(/obj/item/organ/heart) + required_organs = list(/obj/item/organ/internal/heart) bypasses_immunity = TRUE // Immunity is based on not having an appendix; this isn't a virus var/sound = FALSE @@ -37,7 +37,7 @@ to_chat(affected_mob, span_warning("You feel [pick("discomfort", "pressure", "a burning sensation", "pain")] in your chest.")) if(DT_PROB(1, delta_time)) to_chat(affected_mob, span_warning("You feel dizzy.")) - affected_mob.add_confusion(6) + affected_mob.adjust_timed_status_effect(6 SECONDS, /datum/status_effect/confusion) if(DT_PROB(1.5, delta_time)) to_chat(affected_mob, span_warning("You feel [pick("full", "nauseated", "sweaty", "weak", "tired", "short on breath", "uneasy")].")) if(3 to 4) @@ -53,7 +53,7 @@ affected_mob.losebreath += 4 if(DT_PROB(1.5, delta_time)) to_chat(affected_mob, span_danger("You feel very weak and dizzy...")) - affected_mob.add_confusion(8) + affected_mob.adjust_timed_status_effect(8 SECONDS, /datum/status_effect/confusion) affected_mob.adjustStaminaLoss(40, FALSE) affected_mob.emote("cough") if(5) diff --git a/code/datums/diseases/magnitis.dm b/code/datums/diseases/magnitis.dm index 243cdd56bc29d..8118dac6f60d2 100644 --- a/code/datums/diseases/magnitis.dm +++ b/code/datums/diseases/magnitis.dm @@ -7,7 +7,7 @@ agent = "Fukkos Miracos" viable_mobtypes = list(/mob/living/carbon/human) disease_flags = CAN_CARRY|CAN_RESIST|CURABLE - permeability_mod = 0.75 + spreading_modifier = 0.75 desc = "This disease disrupts the magnetic field of your body, making it act as if a powerful magnet. Injections of iron help stabilize the field." severity = DISEASE_SEVERITY_MEDIUM infectable_biotypes = MOB_ORGANIC|MOB_ROBOTIC diff --git a/code/datums/diseases/parasitic_infection.dm b/code/datums/diseases/parasitic_infection.dm index c3c83879286b2..fe9cffaaa4e08 100644 --- a/code/datums/diseases/parasitic_infection.dm +++ b/code/datums/diseases/parasitic_infection.dm @@ -6,12 +6,12 @@ agent = "Consuming Live Parasites" spread_text = "Non-Biological" viable_mobtypes = list(/mob/living/carbon/human) - permeability_mod = 1 + spreading_modifier = 1 desc = "If left untreated the subject will passively lose nutrients, and eventually lose their liver." severity = DISEASE_SEVERITY_HARMFUL disease_flags = CAN_CARRY|CAN_RESIST spread_flags = DISEASE_SPREAD_NON_CONTAGIOUS - required_organs = list(/obj/item/organ/liver) + required_organs = list(/obj/item/organ/internal/liver) bypasses_immunity = TRUE @@ -20,7 +20,7 @@ if(!.) return - var/obj/item/organ/liver/affected_liver = affected_mob.getorgan(/obj/item/organ/liver) + var/obj/item/organ/internal/liver/affected_liver = affected_mob.getorgan(/obj/item/organ/internal/liver) if(!affected_liver) affected_mob.visible_message(span_notice("[affected_mob]'s liver is covered in tiny larva! They quickly shrivel and die after being exposed to the open air.")) cure() diff --git a/code/datums/diseases/pierrot_throat.dm b/code/datums/diseases/pierrot_throat.dm index c725aa20a2956..8cb50a7073979 100644 --- a/code/datums/diseases/pierrot_throat.dm +++ b/code/datums/diseases/pierrot_throat.dm @@ -7,7 +7,7 @@ cure_chance = 50 agent = "H0NI<42 Virus" viable_mobtypes = list(/mob/living/carbon/human) - permeability_mod = 0.75 + spreading_modifier = 0.75 desc = "If left untreated the subject will probably drive others to insanity." severity = DISEASE_SEVERITY_MEDIUM diff --git a/code/datums/diseases/retrovirus.dm b/code/datums/diseases/retrovirus.dm index 7cbcbb97394cc..76f9cb2ed9c06 100644 --- a/code/datums/diseases/retrovirus.dm +++ b/code/datums/diseases/retrovirus.dm @@ -9,7 +9,7 @@ viable_mobtypes = list(/mob/living/carbon/human) desc = "A DNA-altering retrovirus that scrambles the structural and unique enzymes of a host constantly." severity = DISEASE_SEVERITY_HARMFUL - permeability_mod = 0.4 + spreading_modifier = 0.4 stage_prob = 1 var/restcure = 0 diff --git a/code/datums/diseases/rhumba_beat.dm b/code/datums/diseases/rhumba_beat.dm index f6ffe59ecc0d2..816fc191113d9 100644 --- a/code/datums/diseases/rhumba_beat.dm +++ b/code/datums/diseases/rhumba_beat.dm @@ -7,7 +7,7 @@ cures = list("plasma") agent = "Unknown" viable_mobtypes = list(/mob/living/carbon/human) - permeability_mod = 1 + spreading_modifier = 1 severity = DISEASE_SEVERITY_BIOHAZARD /datum/disease/rhumba_beat/stage_act(delta_time, times_fired) @@ -32,7 +32,7 @@ if(DT_PROB(10, delta_time)) if(prob(50)) affected_mob.adjust_fire_stacks(2) - affected_mob.IgniteMob() + affected_mob.ignite_mob() else affected_mob.emote("gasp") to_chat(affected_mob, span_danger("You feel a burning beat inside...")) diff --git a/code/datums/diseases/transformation.dm b/code/datums/diseases/transformation.dm index f344a3431c907..cfa0afad345db 100644 --- a/code/datums/diseases/transformation.dm +++ b/code/datums/diseases/transformation.dm @@ -104,7 +104,7 @@ spread_text = "Unknown" spread_flags = DISEASE_SPREAD_NON_CONTAGIOUS viable_mobtypes = list(/mob/living/carbon/human) - permeability_mod = 1 + spreading_modifier = 1 cure_chance = 0.5 disease_flags = CAN_CARRY|CAN_RESIST desc = "A neutered but still dangerous descendent of the ancient \"Jungle Fever\", victims will eventually genetically backtrack into a primate. \ @@ -137,7 +137,7 @@ if(3) if(DT_PROB(2, delta_time)) to_chat(affected_mob, span_danger("You feel a stabbing pain in your head.")) - affected_mob.add_confusion(10) + affected_mob.adjust_timed_status_effect(10 SECONDS, /datum/status_effect/confusion) if(4) if(DT_PROB(1.5, delta_time)) affected_mob.say(pick("Eeek, ook ook!", "Eee-eeek!", "Eeee!", "Ungh, ungh."), forced = "jungle fever") diff --git a/code/datums/diseases/tuberculosis.dm b/code/datums/diseases/tuberculosis.dm index edb45219c8454..55d039e7e3242 100644 --- a/code/datums/diseases/tuberculosis.dm +++ b/code/datums/diseases/tuberculosis.dm @@ -9,7 +9,7 @@ viable_mobtypes = list(/mob/living/carbon/human) cure_chance = 2.5 //like hell are you getting out of hell desc = "A rare highly transmissible virulent virus. Few samples exist, rumoured to be carefully grown and cultured by clandestine bio-weapon specialists. Causes fever, blood vomiting, lung damage, weight loss, and fatigue." - required_organs = list(/obj/item/organ/lungs) + required_organs = list(/obj/item/organ/internal/lungs) severity = DISEASE_SEVERITY_BIOHAZARD bypasses_immunity = TRUE // TB primarily impacts the lungs; it's also bacterial or fungal in nature; viral immunity should do nothing. @@ -30,7 +30,7 @@ if(4) if(DT_PROB(1, delta_time)) to_chat(affected_mob, span_userdanger("You see four of everything!")) - affected_mob.Dizzy(5) + affected_mob.set_timed_status_effect(10 SECONDS, /datum/status_effect/dizziness, only_if_higher = TRUE) if(DT_PROB(1, delta_time)) to_chat(affected_mob, span_danger("You feel a sharp pain from your lower chest!")) affected_mob.adjustOxyLoss(5, FALSE) @@ -49,7 +49,7 @@ affected_mob.AdjustSleeping(100) if(DT_PROB(1, delta_time)) to_chat(affected_mob, span_userdanger("You feel your mind relax and your thoughts drift!")) - affected_mob.set_confusion(min(100, affected_mob.get_confusion() + 8)) + affected_mob.adjust_timed_status_effect(8 SECONDS, /datum/status_effect/confusion, max_duration = 100 SECONDS) if(DT_PROB(5, delta_time)) affected_mob.vomit(20) if(DT_PROB(1.5, delta_time)) diff --git a/code/datums/diseases/wizarditis.dm b/code/datums/diseases/wizarditis.dm index 8dc530208b16a..9e098c80077af 100644 --- a/code/datums/diseases/wizarditis.dm +++ b/code/datums/diseases/wizarditis.dm @@ -8,7 +8,7 @@ agent = "Rincewindus Vulgaris" viable_mobtypes = list(/mob/living/carbon/human) disease_flags = CAN_CARRY|CAN_RESIST|CURABLE - permeability_mod = 0.75 + spreading_modifier = 0.75 desc = "Some speculate that this virus is the cause of the Space Wizard Federation's existence. Subjects affected show the signs of brain damage, yelling obscure sentences or total gibberish. On late stages subjects sometime express the feelings of inner power, and, cite, 'the ability to control the forces of cosmos themselves!' A gulp of strong, manly spirits usually reverts them to normal, humanlike, condition." severity = DISEASE_SEVERITY_HARMFUL required_organs = list(/obj/item/bodypart/head) diff --git a/code/datums/dna.dm b/code/datums/dna.dm index c7566579bea47..532acf5a58db2 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -11,7 +11,8 @@ GLOBAL_LIST_INIT(identity_block_lengths, list( "[DNA_HAIR_COLOR_BLOCK]" = DNA_BLOCK_SIZE_COLOR, "[DNA_FACIAL_HAIR_COLOR_BLOCK]" = DNA_BLOCK_SIZE_COLOR, - "[DNA_EYE_COLOR_BLOCK]" = DNA_BLOCK_SIZE_COLOR, + "[DNA_EYE_COLOR_LEFT_BLOCK]" = DNA_BLOCK_SIZE_COLOR, + "[DNA_EYE_COLOR_RIGHT_BLOCK]" = DNA_BLOCK_SIZE_COLOR, )) /** @@ -178,7 +179,8 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) L[DNA_FACIAL_HAIRSTYLE_BLOCK] = construct_block(GLOB.facial_hairstyles_list.Find(H.facial_hairstyle), GLOB.facial_hairstyles_list.len) L[DNA_FACIAL_HAIR_COLOR_BLOCK] = sanitize_hexcolor(H.facial_hair_color, include_crunch = FALSE) L[DNA_SKIN_TONE_BLOCK] = construct_block(GLOB.skin_tones.Find(H.skin_tone), GLOB.skin_tones.len) - L[DNA_EYE_COLOR_BLOCK] = sanitize_hexcolor(H.eye_color, include_crunch = FALSE) + L[DNA_EYE_COLOR_LEFT_BLOCK] = sanitize_hexcolor(H.eye_color_left, include_crunch = FALSE) + L[DNA_EYE_COLOR_RIGHT_BLOCK] = sanitize_hexcolor(H.eye_color_right, include_crunch = FALSE) for(var/blocknum in 1 to DNA_UNI_IDENTITY_BLOCKS) . += L[blocknum] || random_string(GET_UI_BLOCK_LEN(blocknum), GLOB.hex_characters) @@ -193,6 +195,8 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) L[DNA_ETHEREAL_COLOR_BLOCK] = sanitize_hexcolor(features["ethcolor"], include_crunch = FALSE) if(features["body_markings"]) L[DNA_LIZARD_MARKINGS_BLOCK] = construct_block(GLOB.body_markings_list.Find(features["body_markings"]), GLOB.body_markings_list.len) + if(features["tail_cat"]) + L[DNA_TAIL_BLOCK] = construct_block(GLOB.tails_list_human.Find(features["tail_cat"]), GLOB.tails_list_human.len) if(features["tail_lizard"]) L[DNA_LIZARD_TAIL_BLOCK] = construct_block(GLOB.tails_list_lizard.Find(features["tail_lizard"]), GLOB.tails_list_lizard.len) if(features["snout"]) @@ -203,8 +207,6 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) L[DNA_FRILLS_BLOCK] = construct_block(GLOB.frills_list.Find(features["frills"]), GLOB.frills_list.len) if(features["spines"]) L[DNA_SPINES_BLOCK] = construct_block(GLOB.spines_list.Find(features["spines"]), GLOB.spines_list.len) - if(features["tail_human"]) - L[DNA_HUMAN_TAIL_BLOCK] = construct_block(GLOB.tails_list_human.Find(features["tail_human"]), GLOB.tails_list_human.len) if(features["ears"]) L[DNA_EARS_BLOCK] = construct_block(GLOB.ears_list.Find(features["ears"]), GLOB.ears_list.len) if(features["moth_wings"] != "Burnt Off") @@ -215,8 +217,6 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) L[DNA_MOTH_MARKINGS_BLOCK] = construct_block(GLOB.moth_markings_list.Find(features["moth_markings"]), GLOB.moth_markings_list.len) if(features["caps"]) L[DNA_MUSHROOM_CAPS_BLOCK] = construct_block(GLOB.caps_list.Find(features["caps"]), GLOB.caps_list.len) - if(features["tail_monkey"]) - L[DNA_MONKEY_TAIL_BLOCK] = construct_block(GLOB.tails_list_monkey.Find(features["tail_monkey"]), GLOB.tails_list_monkey.len) if(features["pod_hair"]) L[DNA_POD_HAIR_BLOCK] = construct_block(GLOB.pod_hair_list.Find(features["pod_hair"]), GLOB.pod_hair_list.len) @@ -300,8 +300,10 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) set_uni_identity_block(blocknumber, sanitize_hexcolor(H.facial_hair_color, include_crunch = FALSE)) if(DNA_SKIN_TONE_BLOCK) set_uni_identity_block(blocknumber, construct_block(GLOB.skin_tones.Find(H.skin_tone), GLOB.skin_tones.len)) - if(DNA_EYE_COLOR_BLOCK) - set_uni_identity_block(blocknumber, sanitize_hexcolor(H.eye_color, include_crunch = FALSE)) + if(DNA_EYE_COLOR_LEFT_BLOCK) + set_uni_identity_block(blocknumber, sanitize_hexcolor(H.eye_color_left, include_crunch = FALSE)) + if(DNA_EYE_COLOR_RIGHT_BLOCK) + set_uni_identity_block(blocknumber, sanitize_hexcolor(H.eye_color_right, include_crunch = FALSE)) if(DNA_GENDER_BLOCK) switch(H.gender) if(MALE) @@ -327,8 +329,8 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) set_uni_feature_block(blocknumber, sanitize_hexcolor(features["ethcolor"], include_crunch = FALSE)) if(DNA_LIZARD_MARKINGS_BLOCK) set_uni_feature_block(blocknumber, construct_block(GLOB.body_markings_list.Find(features["body_markings"]), GLOB.body_markings_list.len)) - if(DNA_LIZARD_TAIL_BLOCK) - set_uni_feature_block(blocknumber, construct_block(GLOB.tails_list_lizard.Find(features["tail_lizard"]), GLOB.tails_list_lizard.len)) + if(DNA_TAIL_BLOCK) + set_uni_feature_block(blocknumber, construct_block(GLOB.tails_list.Find(features["tail_lizard"]), GLOB.tails_list.len)) if(DNA_SNOUT_BLOCK) set_uni_feature_block(blocknumber, construct_block(GLOB.snouts_list.Find(features["snout"]), GLOB.snouts_list.len)) if(DNA_HORNS_BLOCK) @@ -337,8 +339,6 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) set_uni_feature_block(blocknumber, construct_block(GLOB.frills_list.Find(features["frills"]), GLOB.frills_list.len)) if(DNA_SPINES_BLOCK) set_uni_feature_block(blocknumber, construct_block(GLOB.spines_list.Find(features["spines"]), GLOB.spines_list.len)) - if(DNA_HUMAN_TAIL_BLOCK) - set_uni_feature_block(blocknumber, construct_block(GLOB.tails_list_human.Find(features["tail_human"]), GLOB.tails_list_human.len)) if(DNA_EARS_BLOCK) set_uni_feature_block(blocknumber, construct_block(GLOB.ears_list.Find(features["ears"]), GLOB.ears_list.len)) if(DNA_MOTH_WINGS_BLOCK) @@ -349,8 +349,6 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) set_uni_feature_block(blocknumber, construct_block(GLOB.moth_markings_list.Find(features["moth_markings"]), GLOB.moth_markings_list.len)) if(DNA_MUSHROOM_CAPS_BLOCK) set_uni_feature_block(blocknumber, construct_block(GLOB.caps_list.Find(features["caps"]), GLOB.caps_list.len)) - if(DNA_MONKEY_TAIL_BLOCK) - set_uni_feature_block(blocknumber, construct_block(GLOB.tails_list_monkey.Find(features["tail_monkey"]), GLOB.tails_list_monkey.len)) if(DNA_POD_HAIR_BLOCK) set_uni_feature_block(blocknumber, construct_block(GLOB.pod_hair_list.Find(features["pod_hair"]), GLOB.pod_hair_list.len)) @@ -534,11 +532,9 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) update_body(is_creating = TRUE) update_mutations_overlay() - if(LAZYLEN(mutations)) - for(var/M in mutations) - var/datum/mutation/human/HM = M - if(HM.allow_transfer || force_transfer_mutations) - dna.force_give(new HM.type(HM.class, copymut=HM)) //using force_give since it may include exotic mutations that otherwise won't be handled properly + if(LAZYLEN(mutations) && force_transfer_mutations) + for(var/datum/mutation/human/mutation as anything in mutations) + dna.force_give(new mutation.type(mutation.class, copymut = mutation)) //using force_give since it may include exotic mutations that otherwise won't be handled properly /mob/living/carbon/proc/create_dna() dna = new /datum/dna(src) @@ -565,7 +561,8 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) hair_color = sanitize_hexcolor(get_uni_identity_block(structure, DNA_HAIR_COLOR_BLOCK)) facial_hair_color = sanitize_hexcolor(get_uni_identity_block(structure, DNA_FACIAL_HAIR_COLOR_BLOCK)) skin_tone = GLOB.skin_tones[deconstruct_block(get_uni_identity_block(structure, DNA_SKIN_TONE_BLOCK), GLOB.skin_tones.len)] - eye_color = sanitize_hexcolor(get_uni_identity_block(structure, DNA_EYE_COLOR_BLOCK)) + 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)] hairstyle = GLOB.hairstyles_list[deconstruct_block(get_uni_identity_block(structure, DNA_HAIRSTYLE_BLOCK), GLOB.hairstyles_list.len)] var/features = dna.unique_features @@ -575,8 +572,6 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) dna.features["ethcolor"] = sanitize_hexcolor(get_uni_feature_block(features, DNA_ETHEREAL_COLOR_BLOCK)) if(dna.features["body_markings"]) dna.features["body_markings"] = GLOB.body_markings_list[deconstruct_block(get_uni_feature_block(features, DNA_LIZARD_MARKINGS_BLOCK), GLOB.body_markings_list.len)] - if(dna.features["tail_lizard"]) - dna.features["tail_lizard"] = GLOB.tails_list_lizard[deconstruct_block(get_uni_feature_block(features, DNA_LIZARD_TAIL_BLOCK), GLOB.tails_list_lizard.len)] if(dna.features["snout"]) dna.features["snout"] = GLOB.snouts_list[deconstruct_block(get_uni_feature_block(features, DNA_SNOUT_BLOCK), GLOB.snouts_list.len)] if(dna.features["horns"]) @@ -585,8 +580,10 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) dna.features["frills"] = GLOB.frills_list[deconstruct_block(get_uni_feature_block(features, DNA_FRILLS_BLOCK), GLOB.frills_list.len)] if(dna.features["spines"]) dna.features["spines"] = GLOB.spines_list[deconstruct_block(get_uni_feature_block(features, DNA_SPINES_BLOCK), GLOB.spines_list.len)] - if(dna.features["tail_human"]) - dna.features["tail_human"] = GLOB.tails_list_human[deconstruct_block(get_uni_feature_block(features, DNA_HUMAN_TAIL_BLOCK), GLOB.tails_list_human.len)] + if(dna.features["tail_cat"]) + dna.features["tail_cat"] = GLOB.tails_list_human[deconstruct_block(get_uni_feature_block(features, DNA_TAIL_BLOCK), GLOB.tails_list_human.len)] + if(dna.features["tail_lizard"]) + dna.features["tail_cat"] = GLOB.tails_list_lizard[deconstruct_block(get_uni_feature_block(features, DNA_LIZARD_TAIL_BLOCK), GLOB.tails_list_lizard.len)] if(dna.features["ears"]) dna.features["ears"] = GLOB.ears_list[deconstruct_block(get_uni_feature_block(features, DNA_EARS_BLOCK), GLOB.ears_list.len)] if(dna.features["moth_wings"]) @@ -601,8 +598,6 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) dna.features["moth_markings"] = GLOB.moth_markings_list[deconstruct_block(get_uni_feature_block(features, DNA_MOTH_MARKINGS_BLOCK), GLOB.moth_markings_list.len)] if(dna.features["caps"]) dna.features["caps"] = GLOB.caps_list[deconstruct_block(get_uni_feature_block(features, DNA_MUSHROOM_CAPS_BLOCK), GLOB.caps_list.len)] - if(dna.features["tail_monkey"]) - dna.features["tail_monkey"] = GLOB.tails_list_monkey[deconstruct_block(get_uni_feature_block(features, DNA_MONKEY_TAIL_BLOCK), GLOB.tails_list_monkey.len)] if(dna.features["pod_hair"]) dna.features["pod_hair"] = GLOB.pod_hair_list[deconstruct_block(get_uni_feature_block(features, DNA_POD_HAIR_BLOCK), GLOB.pod_hair_list.len)] @@ -866,7 +861,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) /mob/living/carbon/human/proc/something_horrible_mindmelt() if(!is_blind()) - var/obj/item/organ/eyes/eyes = locate(/obj/item/organ/eyes) in internal_organs + var/obj/item/organ/internal/eyes/eyes = locate(/obj/item/organ/internal/eyes) in internal_organs if(!eyes) return eyes.Remove(src) diff --git a/code/datums/elements/atmos_requirements.dm b/code/datums/elements/atmos_requirements.dm index 94493a180973b..359c976718db0 100644 --- a/code/datums/elements/atmos_requirements.dm +++ b/code/datums/elements/atmos_requirements.dm @@ -47,7 +47,7 @@ return FALSE var/open_turf_gases = open_turf.air.gases - open_turf.air.assert_gases(arglist(GLOB.hardcoded_gases)) + open_turf.air.assert_gases(/datum/gas/oxygen, /datum/gas/nitrogen, /datum/gas/carbon_dioxide, /datum/gas/plasma) var/plas = open_turf_gases[/datum/gas/plasma][MOLES] var/oxy = open_turf_gases[/datum/gas/oxygen][MOLES] diff --git a/code/datums/elements/cult_eyes.dm b/code/datums/elements/cult_eyes.dm index 3ff5c8d646dfb..a15f01de850f9 100644 --- a/code/datums/elements/cult_eyes.dm +++ b/code/datums/elements/cult_eyes.dm @@ -26,8 +26,10 @@ ADD_TRAIT(target, TRAIT_UNNATURAL_RED_GLOWY_EYES, CULT_TRAIT) if (ishuman(target)) var/mob/living/carbon/human/human_parent = target - human_parent.eye_color = BLOODCULT_EYE - human_parent.dna.update_ui_block(DNA_EYE_COLOR_BLOCK) + human_parent.eye_color_left = BLOODCULT_EYE + human_parent.eye_color_right = BLOODCULT_EYE + human_parent.dna.update_ui_block(DNA_EYE_COLOR_LEFT_BLOCK) + human_parent.dna.update_ui_block(DNA_EYE_COLOR_RIGHT_BLOCK) human_parent.update_body() /** @@ -39,8 +41,10 @@ REMOVE_TRAIT(target, TRAIT_UNNATURAL_RED_GLOWY_EYES, CULT_TRAIT) if (ishuman(target)) var/mob/living/carbon/human/human_parent = target - human_parent.eye_color = initial(human_parent.eye_color) - human_parent.dna.update_ui_block(DNA_EYE_COLOR_BLOCK) + human_parent.eye_color_left = initial(human_parent.eye_color_left) + human_parent.eye_color_right = initial(human_parent.eye_color_right) + human_parent.dna.update_ui_block(DNA_EYE_COLOR_LEFT_BLOCK) + human_parent.dna.update_ui_block(DNA_EYE_COLOR_RIGHT_BLOCK) human_parent.update_body() UnregisterSignal(target, list(COMSIG_CHANGELING_TRANSFORM, COMSIG_HUMAN_MONKEYIZE, COMSIG_MONKEY_HUMANIZE)) return ..() diff --git a/code/datums/elements/digitalcamo.dm b/code/datums/elements/digitalcamo.dm index dcfbbd3b65002..ccd82b9c8be2a 100644 --- a/code/datums/elements/digitalcamo.dm +++ b/code/datums/elements/digitalcamo.dm @@ -44,7 +44,7 @@ to_chat(M, span_warning("[source.p_their()] skin seems to be shifting like something is moving below it.")) -/datum/element/digitalcamo/proc/can_track(datum/source) +/datum/element/digitalcamo/proc/can_track(datum/source, mob/user) SIGNAL_HANDLER return COMPONENT_CANT_TRACK diff --git a/code/datums/elements/earhealing.dm b/code/datums/elements/earhealing.dm index c487500dc7bc4..6d748f7e28e87 100644 --- a/code/datums/elements/earhealing.dm +++ b/code/datums/elements/earhealing.dm @@ -28,7 +28,7 @@ /datum/element/earhealing/process(delta_time) for(var/i in user_by_item) var/mob/living/carbon/user = user_by_item[i] - var/obj/item/organ/ears/ears = user.getorganslot(ORGAN_SLOT_EARS) + var/obj/item/organ/internal/ears/ears = user.getorganslot(ORGAN_SLOT_EARS) if(!ears || HAS_TRAIT_NOT_FROM(user, TRAIT_DEAF, EAR_DAMAGE)) continue ears.deaf = max(ears.deaf - 0.25 * delta_time, (ears.damage < ears.maxHealth ? 0 : 1)) // Do not clear deafness if our ears are too damaged diff --git a/code/datums/elements/eyestab.dm b/code/datums/elements/eyestab.dm index b7d73867ea8fb..8fb5714973429 100644 --- a/code/datums/elements/eyestab.dm +++ b/code/datums/elements/eyestab.dm @@ -80,7 +80,7 @@ log_combat(user, target, "attacked", "[item.name]", "(Combat mode: [user.combat_mode ? "On" : "Off"])") - var/obj/item/organ/eyes/eyes = target.getorganslot(ORGAN_SLOT_EYES) + var/obj/item/organ/internal/eyes/eyes = target.getorganslot(ORGAN_SLOT_EYES) if (!eyes) return diff --git a/code/datums/elements/kneejerk.dm b/code/datums/elements/kneejerk.dm index 4b4eff75e3e83..e0b443f28a9f7 100644 --- a/code/datums/elements/kneejerk.dm +++ b/code/datums/elements/kneejerk.dm @@ -29,7 +29,7 @@ var/selected_zone = user.zone_selected var/obj/item/bodypart/r_leg = target.get_bodypart(BODY_ZONE_R_LEG) var/obj/item/bodypart/l_leg = target.get_bodypart(BODY_ZONE_L_LEG) - var/obj/item/organ/brain/target_brain = target.getorganslot(ORGAN_SLOT_BRAIN) + var/obj/item/organ/internal/brain/target_brain = target.getorganslot(ORGAN_SLOT_BRAIN) if(!ishuman(target)) return diff --git a/code/datums/elements/pet_bonus.dm b/code/datums/elements/pet_bonus.dm index f6083feefacca..7936882b3cde3 100644 --- a/code/datums/elements/pet_bonus.dm +++ b/code/datums/elements/pet_bonus.dm @@ -35,4 +35,4 @@ new /obj/effect/temp_visual/heart(pet.loc) if(emote_message && prob(33)) pet.manual_emote(emote_message) - SEND_SIGNAL(petter, COMSIG_ADD_MOOD_EVENT, pet, moodlet, pet) + SEND_SIGNAL(petter, COMSIG_ADD_MOOD_EVENT, "petting_bonus", moodlet, pet) diff --git a/code/datums/elements/ridable.dm b/code/datums/elements/ridable.dm index 6b12870474d3b..240333125be42 100644 --- a/code/datums/elements/ridable.dm +++ b/code/datums/elements/ridable.dm @@ -30,9 +30,11 @@ RegisterSignal(target, COMSIG_MOVABLE_PREBUCKLE, .proc/check_mounting) if(isvehicle(target)) RegisterSignal(target, COMSIG_SPEED_POTION_APPLIED, .proc/check_potion) + if(ismob(target)) + RegisterSignal(target, COMSIG_LIVING_DEATH, .proc/handle_removal) /datum/element/ridable/Detach(datum/target) - UnregisterSignal(target, list(COMSIG_MOVABLE_PREBUCKLE, COMSIG_SPEED_POTION_APPLIED)) + UnregisterSignal(target, list(COMSIG_MOVABLE_PREBUCKLE, COMSIG_SPEED_POTION_APPLIED, COMSIG_LIVING_DEATH)) return ..() /// Someone is buckling to this movable, which is literally the only thing we care about (other than speed potions) @@ -40,7 +42,9 @@ SIGNAL_HANDLER if(HAS_TRAIT(potential_rider, TRAIT_CANT_RIDE)) - return + //Do not prevent buckle, but stop any riding, do not block buckle here + //There are things that are supposed to buckle (like slimes) but not ride the creature + return NONE var/arms_needed = 0 if(ride_check_flags & RIDER_NEEDS_ARMS) @@ -99,7 +103,7 @@ amount_equipped++ else qdel(inhand) - break + return FALSE if(amount_equipped >= amount_required) return TRUE @@ -143,8 +147,13 @@ qdel(O) return TRUE +/datum/element/ridable/proc/handle_removal(datum/source) + SIGNAL_HANDLER + var/atom/movable/ridden = source + ridden.unbuckle_all_mobs() + Detach(source) /obj/item/riding_offhand name = "offhand" diff --git a/code/datums/elements/spooky.dm b/code/datums/elements/spooky.dm index f1b68c6760ac9..40c30de1c6651 100644 --- a/code/datums/elements/spooky.dm +++ b/code/datums/elements/spooky.dm @@ -21,7 +21,7 @@ var/mob/living/carbon/human/U = user if(!istype(U.dna.species, /datum/species/skeleton)) U.adjustStaminaLoss(35) //Extra Damage - U.Jitter(35) + U.set_timed_status_effect(70 SECONDS, /datum/status_effect/jitter, only_if_higher = TRUE) U.set_timed_status_effect(40 SECONDS, /datum/status_effect/speech/stutter) if(U.getStaminaLoss() > 95) to_chat(U, "Your ears weren't meant for this spectral sound.") @@ -35,7 +35,7 @@ if(istype(H.dna.species, /datum/species/zombie)) H.adjustStaminaLoss(25) H.Paralyze(15) //zombies can't resist the doot - C.Jitter(35) + C.set_timed_status_effect(70 SECONDS, /datum/status_effect/jitter, only_if_higher = TRUE) C.set_timed_status_effect(40 SECONDS, /datum/status_effect/speech/stutter) if((!istype(H.dna.species, /datum/species/skeleton)) && (!istype(H.dna.species, /datum/species/golem)) && (!istype(H.dna.species, /datum/species/android)) && (!istype(H.dna.species, /datum/species/jelly))) C.adjustStaminaLoss(25) //boneless humanoids don't lose the will to live @@ -43,7 +43,7 @@ INVOKE_ASYNC(src, .proc/spectral_change, H) else //the sound will spook monkeys. - C.Jitter(15) + C.set_timed_status_effect(30 SECONDS, /datum/status_effect/jitter, only_if_higher = TRUE) C.set_timed_status_effect(40 SECONDS, /datum/status_effect/speech/stutter) /datum/element/spooky/proc/spectral_change(mob/living/carbon/human/H, mob/user) diff --git a/code/datums/elements/strippable.dm b/code/datums/elements/strippable.dm index 52ca10d51131d..ddfa26ac4b8ee 100644 --- a/code/datums/elements/strippable.dm +++ b/code/datums/elements/strippable.dm @@ -111,9 +111,8 @@ to_chat(user, span_notice("You try to put [equipping] on [source]...")) - var/log = "[key_name(source)] is having [equipping] put on them by [key_name(user)]" - user.log_message(log, LOG_ATTACK, color="red") - source.log_message(log, LOG_VICTIM, color="red", log_globally=FALSE) + user.log_message("is putting [equipping] on [key_name(source)]", LOG_ATTACK, color="red") + source.log_message("is having [equipping] put on them by [key_name(user)]", LOG_VICTIM, color="orange", log_globally=FALSE) return TRUE @@ -158,8 +157,8 @@ ) to_chat(user, span_danger("You try to remove [source]'s [item]...")) - user.log_message("[key_name(source)] is being stripped of [item] by [key_name(user)]", LOG_ATTACK, color="red") - source.log_message("[key_name(source)] is being stripped of [item] by [key_name(user)]", LOG_VICTIM, color="red", log_globally=FALSE) + user.log_message("is stripping [key_name(source)] of [item]", LOG_ATTACK, color="red") + source.log_message("is being stripped of [item] by [key_name(user)]", LOG_VICTIM, color="orange", log_globally=FALSE) item.add_fingerprint(src) if(ishuman(source)) @@ -262,6 +261,8 @@ var/mob/mob_source = source mob_source.equip_to_slot(equipping, item_slot) + return finish_equip_mob(equipping, source, user) + /datum/strippable_item/mob_item_slot/get_obscuring(atom/source) if (iscarbon(source)) var/mob/living/carbon/carbon_source = source @@ -292,6 +293,11 @@ /datum/strippable_item/mob_item_slot/proc/get_equip_delay(obj/item/equipping) return equipping.equip_delay_other +/// A utility function for `/datum/strippable_item`s to finish equipping an item to a mob. +/proc/finish_equip_mob(obj/item/item, mob/source, mob/user) + user.log_message("has put [item] on [key_name(source)]", LOG_ATTACK, color="red") + source.log_message("had [item] put on them by [key_name(user)]", LOG_VICTIM, color="orange", log_globally=FALSE) + /// A utility function for `/datum/strippable_item`s to start unequipping an item from a mob. /proc/start_unequip_mob(obj/item/item, mob/source, mob/user, strip_delay) if (!do_mob(user, source, strip_delay || item.strip_delay, interaction_key = REF(item))) @@ -304,8 +310,8 @@ if (!item.doStrip(user, source)) return FALSE - user.log_message("[key_name(source)] has been stripped of [item] by [key_name(user)]", LOG_ATTACK, color="red") - source.log_message("[key_name(source)] has been stripped of [item] by [key_name(user)]", LOG_VICTIM, color="red", log_globally=FALSE) + user.log_message("has stripped [key_name(source)] of [item]", LOG_ATTACK, color="red") + source.log_message("has been stripped of [item] by [key_name(user)]", LOG_VICTIM, color="orange", log_globally=FALSE) // Updates speed in case stripped speed affecting item source.update_equipment_speed_mods() diff --git a/code/datums/elements/wall_engraver.dm b/code/datums/elements/wall_engraver.dm index 307a22728922a..32a3b07ac6fdb 100644 --- a/code/datums/elements/wall_engraver.dm +++ b/code/datums/elements/wall_engraver.dm @@ -73,7 +73,7 @@ var/tattoo_story = memory_to_engrave.generate_story(STORY_TATTOO) - if(tattoo_story) + if(!tattoo_story) CRASH("Tried to submit a memory with an invalid story [memory_to_engrave]") tattoo_entry["story"] = tattoo_story diff --git a/code/datums/greyscale/config_types/greyscale_configs.dm b/code/datums/greyscale/config_types/greyscale_configs.dm index a217ca104e2fb..c4f560d8f5fba 100644 --- a/code/datums/greyscale/config_types/greyscale_configs.dm +++ b/code/datums/greyscale/config_types/greyscale_configs.dm @@ -517,3 +517,55 @@ name = "Material Airlock" icon_file = 'icons/obj/doors/airlocks/material/material.dmi' json_config = 'code/datums/greyscale/json_configs/material_airlock.json' + +/datum/greyscale_config/vape + name = "Vape" + icon_file = 'icons/obj/clothing/masks.dmi' + json_config = 'code/datums/greyscale/json_configs/vape.json' + +/datum/greyscale_config/vape/worn + name = "Worn Vape" + icon_file = 'icons/mob/clothing/mask.dmi' + json_config = 'code/datums/greyscale/json_configs/vape_worn.json' + +/datum/greyscale_config/vape/open_low + name = "Open Vape Low" + json_config = 'code/datums/greyscale/json_configs/vape_open_low.json' + +/datum/greyscale_config/vape/open_med + name = "Open Vape Medium" + json_config = 'code/datums/greyscale/json_configs/vape_open_med.json' + +/datum/greyscale_config/vape/open_high + name = "Open Vape High" + json_config = 'code/datums/greyscale/json_configs/vape_open_high.json' + +/datum/greyscale_config/ties + name = "Ties" + icon_file = 'icons/obj/clothing/neck.dmi' + json_config = 'code/datums/greyscale/json_configs/ties.json' + +/datum/greyscale_config/ties_worn + name = "Worn Ties" + icon_file = 'icons/mob/clothing/neck.dmi' + json_config = 'code/datums/greyscale/json_configs/ties_worn.json' + +/datum/greyscale_config/heck_suit + name = "H.E.C.K. Suit" + icon_file = 'icons/obj/clothing/suits.dmi' + json_config = 'code/datums/greyscale/json_configs/heck_suit.json' + +/datum/greyscale_config/heck_suit/worn + name = "H.E.C.K. Suit Worn" + icon_file = 'icons/mob/clothing/suit.dmi' + json_config = 'code/datums/greyscale/json_configs/heck_suit_worn.json' + +/datum/greyscale_config/heck_helmet + name = "H.E.C.K. Helmet" + icon_file = 'icons/obj/clothing/hats.dmi' + json_config = 'code/datums/greyscale/json_configs/heck_helmet.json' + +/datum/greyscale_config/heck_helmet/worn + name = "H.E.C.K. Helmet Worn" + icon_file = 'icons/mob/clothing/head.dmi' + json_config = 'code/datums/greyscale/json_configs/heck_helmet_worn.json' diff --git a/code/datums/greyscale/json_configs/heck_helmet.json b/code/datums/greyscale/json_configs/heck_helmet.json new file mode 100644 index 0000000000000..dd0649f30078d --- /dev/null +++ b/code/datums/greyscale/json_configs/heck_helmet.json @@ -0,0 +1,22 @@ +{ + "hostile_env": [ + { + "type": "icon_state", + "icon_state": "hostile_env_head", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "hostile_env_jaw", + "blend_mode": "overlay", + "color_ids": [ 2 ] + }, + { + "type": "icon_state", + "icon_state": "hostile_env_visor", + "blend_mode": "overlay", + "color_ids": [ 3 ] + } + ] +} diff --git a/code/datums/greyscale/json_configs/heck_helmet_worn.json b/code/datums/greyscale/json_configs/heck_helmet_worn.json new file mode 100644 index 0000000000000..dd0649f30078d --- /dev/null +++ b/code/datums/greyscale/json_configs/heck_helmet_worn.json @@ -0,0 +1,22 @@ +{ + "hostile_env": [ + { + "type": "icon_state", + "icon_state": "hostile_env_head", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "hostile_env_jaw", + "blend_mode": "overlay", + "color_ids": [ 2 ] + }, + { + "type": "icon_state", + "icon_state": "hostile_env_visor", + "blend_mode": "overlay", + "color_ids": [ 3 ] + } + ] +} diff --git a/code/datums/greyscale/json_configs/heck_suit.json b/code/datums/greyscale/json_configs/heck_suit.json new file mode 100644 index 0000000000000..72ad7f42b3d92 --- /dev/null +++ b/code/datums/greyscale/json_configs/heck_suit.json @@ -0,0 +1,30 @@ +{ + "hostile_env": [ + { + "type": "icon_state", + "icon_state": "hostile_env_plates", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "hostile_env_detail", + "blend_mode": "overlay", + "color_ids": [ 2 ] + } + ], + "hostile_env_t": [ + { + "type": "icon_state", + "icon_state": "hostile_env_plates", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "hostile_env_detail", + "blend_mode": "overlay", + "color_ids": [ 2 ] + } + ] +} diff --git a/code/datums/greyscale/json_configs/heck_suit_worn.json b/code/datums/greyscale/json_configs/heck_suit_worn.json new file mode 100644 index 0000000000000..72ad7f42b3d92 --- /dev/null +++ b/code/datums/greyscale/json_configs/heck_suit_worn.json @@ -0,0 +1,30 @@ +{ + "hostile_env": [ + { + "type": "icon_state", + "icon_state": "hostile_env_plates", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "hostile_env_detail", + "blend_mode": "overlay", + "color_ids": [ 2 ] + } + ], + "hostile_env_t": [ + { + "type": "icon_state", + "icon_state": "hostile_env_plates", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "hostile_env_detail", + "blend_mode": "overlay", + "color_ids": [ 2 ] + } + ] +} diff --git a/code/datums/greyscale/json_configs/ties.json b/code/datums/greyscale/json_configs/ties.json new file mode 100644 index 0000000000000..e9c1225d893b1 --- /dev/null +++ b/code/datums/greyscale/json_configs/ties.json @@ -0,0 +1,18 @@ +{ + "tie_greyscale_tied": [ + { + "type": "icon_state", + "icon_state": "tie_greyscale_tied", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], + "tie_greyscale_untied": [ + { + "type": "icon_state", + "icon_state": "tie_greyscale_untied", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ] +} diff --git a/code/datums/greyscale/json_configs/ties_worn.json b/code/datums/greyscale/json_configs/ties_worn.json new file mode 100644 index 0000000000000..e9c1225d893b1 --- /dev/null +++ b/code/datums/greyscale/json_configs/ties_worn.json @@ -0,0 +1,18 @@ +{ + "tie_greyscale_tied": [ + { + "type": "icon_state", + "icon_state": "tie_greyscale_tied", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], + "tie_greyscale_untied": [ + { + "type": "icon_state", + "icon_state": "tie_greyscale_untied", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ] +} diff --git a/code/datums/greyscale/json_configs/vape.json b/code/datums/greyscale/json_configs/vape.json new file mode 100644 index 0000000000000..36dcc765caeb4 --- /dev/null +++ b/code/datums/greyscale/json_configs/vape.json @@ -0,0 +1,15 @@ +{ + "vape": [ + { + "type": "icon_state", + "icon_state": "vapeOutlet", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "vapeInput", + "blend_mode": "overlay" + } + ] +} diff --git a/code/datums/greyscale/json_configs/vape_open_high.json b/code/datums/greyscale/json_configs/vape_open_high.json new file mode 100644 index 0000000000000..65a0400d00334 --- /dev/null +++ b/code/datums/greyscale/json_configs/vape_open_high.json @@ -0,0 +1,20 @@ +{ + "vape_open_high": [ + { + "type": "icon_state", + "icon_state": "vapeOutlet", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "vapeInput", + "blend_mode": "overlay" + }, + { + "type": "icon_state", + "icon_state": "vapeopen_high", + "blend_mode": "overlay" + } + ] +} diff --git a/code/datums/greyscale/json_configs/vape_open_low.json b/code/datums/greyscale/json_configs/vape_open_low.json new file mode 100644 index 0000000000000..3ad5971bc3783 --- /dev/null +++ b/code/datums/greyscale/json_configs/vape_open_low.json @@ -0,0 +1,20 @@ +{ + "vape_open_low": [ + { + "type": "icon_state", + "icon_state": "vapeOutlet", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "vapeInput", + "blend_mode": "overlay" + }, + { + "type": "icon_state", + "icon_state": "vapeopen_low", + "blend_mode": "overlay" + } + ] +} diff --git a/code/datums/greyscale/json_configs/vape_open_med.json b/code/datums/greyscale/json_configs/vape_open_med.json new file mode 100644 index 0000000000000..f26302edd77b3 --- /dev/null +++ b/code/datums/greyscale/json_configs/vape_open_med.json @@ -0,0 +1,20 @@ +{ + "vape_open_med": [ + { + "type": "icon_state", + "icon_state": "vapeOutlet", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "vapeInput", + "blend_mode": "overlay" + }, + { + "type": "icon_state", + "icon_state": "vapeopen_med", + "blend_mode": "overlay" + } + ] +} diff --git a/code/datums/greyscale/json_configs/vape_worn.json b/code/datums/greyscale/json_configs/vape_worn.json new file mode 100644 index 0000000000000..662083958ef4a --- /dev/null +++ b/code/datums/greyscale/json_configs/vape_worn.json @@ -0,0 +1,15 @@ +{ + "vape_worn": [ + { + "type": "icon_state", + "icon_state": "vapeWorn", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "vapeVapor", + "blend_mode": "overlay" + } + ] +} diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm index 4d61cd19702a5..3838901ed6b48 100644 --- a/code/datums/helper_datums/teleport.dm +++ b/code/datums/helper_datums/teleport.dm @@ -140,9 +140,10 @@ return var/list/floor_gases = floor_gas_mixture.gases + var/list/gases_to_check = list(/datum/gas/oxygen, /datum/gas/nitrogen, /datum/gas/carbon_dioxide, /datum/gas/plasma) var/trace_gases for(var/id in floor_gases) - if(id in GLOB.hardcoded_gases) + if(id in gases_to_check) continue trace_gases = TRUE break diff --git a/code/datums/hud.dm b/code/datums/hud.dm index 003ca63c5bc3e..232cc3f59b162 100644 --- a/code/datums/hud.dm +++ b/code/datums/hud.dm @@ -2,6 +2,10 @@ GLOBAL_LIST_EMPTY(all_huds) +///gets filled by each /datum/atom_hud/New(). +///associative list of the form: list(hud category = list(all global atom huds that use that category)) +GLOBAL_LIST_EMPTY(huds_by_category) + //GLOBAL HUD LIST GLOBAL_LIST_INIT(huds, list( DATA_HUD_SECURITY_BASIC = new/datum/atom_hud/data/human/security/basic(), @@ -17,116 +21,354 @@ GLOBAL_LIST_INIT(huds, list( )) /datum/atom_hud - var/list/atom/hudatoms = list() //list of all atoms which display this hud - var/list/hudusers = list() //list with all mobs who can see the hud - var/list/hud_icons = list() //these will be the indexes for the atom's hud_list + ///associative list of the form: list(z level = list(hud atom)). + ///tracks what hud atoms for this hud exists in what z level so we can only give users + ///the hud images that they can actually see. + var/list/atom/hud_atoms = list() + + ///associative list of the form: list(z level = list(hud user client mobs)). + ///tracks mobs that can "see" us + // by z level so when they change z's we can adjust what images they see from this hud. + var/list/hud_users = list() + + ///used for signal tracking purposes, associative list of the form: list(hud atom = TRUE) that isnt separated by z level + var/list/atom/hud_atoms_all_z_levels = list() + + ///used for signal tracking purposes, associative list of the form: list(hud user = number of times this hud was added to this user). + ///that isnt separated by z level + var/list/mob/hud_users_all_z_levels = list() - var/list/next_time_allowed = list() //mobs associated with the next time this hud can be added to them - var/list/queued_to_see = list() //mobs that have triggered the cooldown and are queued to see the hud, but do not yet - var/hud_exceptions = list() // huduser = list(ofatomswiththeirhudhidden) - aka everyone hates targeted invisiblity + ///these will be the indexes for the atom's hud_list + var/list/hud_icons = list() + + ///mobs associated with the next time this hud can be added to them + var/list/next_time_allowed = list() + ///mobs that have triggered the cooldown and are queued to see the hud, but do not yet + var/list/queued_to_see = list() + /// huduser = list(atoms with their hud hidden) - aka everyone hates targeted invisiblity + var/list/hud_exceptions = list() + ///whether or not this atom_hud type updates the global huds_by_category list. + ///some subtypes cant work like this since theyre supposed to "belong" to + ///one target atom each. it will still go in the other global hud lists. + var/uses_global_hud_category = TRUE /datum/atom_hud/New() GLOB.all_huds += src + for(var/z_level in 1 to world.maxz) + hud_atoms += list(list()) + hud_users += list(list()) + + RegisterSignal(SSdcs, COMSIG_GLOB_NEW_Z, .proc/add_z_level_huds) + + if(uses_global_hud_category) + for(var/hud_icon in hud_icons) + GLOB.huds_by_category[hud_icon] += list(src) /datum/atom_hud/Destroy() - for(var/v in hudusers) - remove_hud_from(v) - for(var/v in hudatoms) - remove_from_hud(v) + for(var/mob/mob as anything in hud_users_all_z_levels) + hide_from(mob) + + for(var/atom/atom as anything in hud_atoms_all_z_levels) + remove_atom_from_hud(atom) + + if(uses_global_hud_category) + for(var/hud_icon in hud_icons) + LAZYREMOVEASSOC(GLOB.huds_by_category, hud_icon, src) + GLOB.all_huds -= src return ..() -/datum/atom_hud/proc/remove_hud_from(mob/M, absolute = FALSE) - if(!M || !hudusers[M]) - return - if (absolute || !--hudusers[M]) - UnregisterSignal(M, COMSIG_PARENT_QDELETING) - hudusers -= M - if(next_time_allowed[M]) - next_time_allowed -= M - if(queued_to_see[M]) - queued_to_see -= M +/datum/atom_hud/proc/add_z_level_huds() + SIGNAL_HANDLER + hud_atoms += list(list()) + hud_users += list(list()) + +///returns a list of all hud atoms in the given z level and linked lower z levels (because hud users in higher z levels can see below) +/datum/atom_hud/proc/get_hud_atoms_for_z_level(z_level) + if(z_level <= 0) + return FALSE + if(z_level > length(hud_atoms)) + stack_trace("get_hud_atoms_for_z_level() was given a z level index out of bounds of hud_atoms!") + return FALSE + + . = list() + . += hud_atoms[z_level] + + var/max_number_of_linked_z_levels_i_care_to_support_here = 10 + + while(max_number_of_linked_z_levels_i_care_to_support_here) + var/lower_z_level_exists = SSmapping.level_trait(z_level, ZTRAIT_DOWN) + + if(lower_z_level_exists) + z_level-- + . += hud_atoms[z_level] + max_number_of_linked_z_levels_i_care_to_support_here-- + continue + else - for(var/atom/A in hudatoms) - remove_from_single_hud(M, A) + break -/datum/atom_hud/proc/remove_from_hud(atom/A) - if(!A) +///returns a list of all hud users in the given z level and linked upper z levels (because hud users in higher z levels can see below) +/datum/atom_hud/proc/get_hud_users_for_z_level(z_level) + if(z_level > length(hud_users) || z_level <= 0) + stack_trace("get_hud_atoms_for_z_level() was given a z level index [z_level] out of bounds 1->[length(hud_users)] of hud_atoms!") return FALSE - for(var/mob/M in hudusers) - remove_from_single_hud(M, A) - hudatoms -= A - return TRUE -/datum/atom_hud/proc/remove_from_single_hud(mob/M, atom/A) //unsafe, no sanity apart from client - if(!M || !M.client || !A) + . = list() + . += hud_users[z_level] + + var/max_number_of_linked_z_levels_i_care_to_support_here = 10 + + while(max_number_of_linked_z_levels_i_care_to_support_here) + var/upper_level_exists = SSmapping.level_trait(z_level, ZTRAIT_UP) + + if(upper_level_exists) + z_level++ + . += hud_users[z_level] + max_number_of_linked_z_levels_i_care_to_support_here-- + continue + + else + break + +///show this hud to the passed in user +/datum/atom_hud/proc/show_to(mob/new_viewer) + if(!new_viewer) return - for(var/i in hud_icons) - M.client.images -= A.hud_list[i] -/datum/atom_hud/proc/add_hud_to(mob/M) - if(!M) + var/turf/their_turf = get_turf(new_viewer) + if(!their_turf) return - if(!hudusers[M]) - hudusers[M] = 1 - RegisterSignal(M, COMSIG_PARENT_QDELETING, .proc/unregister_mob) - if(next_time_allowed[M] > world.time) - if(!queued_to_see[M]) - addtimer(CALLBACK(src, .proc/show_hud_images_after_cooldown, M), next_time_allowed[M] - world.time) - queued_to_see[M] = TRUE + + if(!hud_users[their_turf.z][new_viewer]) + hud_users[their_turf.z][new_viewer] = TRUE + hud_users_all_z_levels[new_viewer] = 1 + + RegisterSignal(new_viewer, COMSIG_PARENT_QDELETING, .proc/unregister_atom, override = TRUE) //both hud users and hud atoms use these signals + RegisterSignal(new_viewer, COMSIG_MOVABLE_Z_CHANGED, .proc/on_atom_or_user_z_level_changed, override = TRUE) + + if(next_time_allowed[new_viewer] > world.time) + if(!queued_to_see[new_viewer]) + addtimer(CALLBACK(src, .proc/show_hud_images_after_cooldown, new_viewer), next_time_allowed[new_viewer] - world.time) + queued_to_see[new_viewer] = TRUE + else - next_time_allowed[M] = world.time + ADD_HUD_TO_COOLDOWN - for(var/atom/A in hudatoms) - add_to_single_hud(M, A) + next_time_allowed[new_viewer] = world.time + ADD_HUD_TO_COOLDOWN + for(var/atom/hud_atom_to_add as anything in get_hud_atoms_for_z_level(their_turf.z)) + add_atom_to_single_mob_hud(new_viewer, hud_atom_to_add) else - hudusers[M]++ + hud_users_all_z_levels[new_viewer] += 1 //increment the number of times this hud has been added to this hud user + +///Hides the images in this hud from former_viewer +///If absolute is set to true, this will forcefully remove the hud, even if sources in theory remain +/datum/atom_hud/proc/hide_from(mob/former_viewer, absolute = FALSE) + if(!former_viewer || !hud_users_all_z_levels[former_viewer]) + return + + var/turf/their_turf = get_turf(former_viewer) + if(!their_turf) + return + + hud_users_all_z_levels[former_viewer] -= 1//decrement number of sources for this hud on this user (bad way to track i know) + + if (absolute || hud_users_all_z_levels[former_viewer] <= 0)//if forced or there arent any sources left, remove the user + + if(!hud_atoms_all_z_levels[former_viewer])//make sure we arent unregistering changes on a mob thats also a hud atom for this hud + UnregisterSignal(former_viewer, COMSIG_MOVABLE_Z_CHANGED) + UnregisterSignal(former_viewer, COMSIG_PARENT_QDELETING) + + hud_users[their_turf.z] -= former_viewer + hud_users_all_z_levels -= former_viewer + + if(next_time_allowed[former_viewer]) + next_time_allowed -= former_viewer + + if(queued_to_see[former_viewer]) + queued_to_see -= former_viewer + else + for(var/atom/hud_atom as anything in get_hud_atoms_for_z_level(their_turf.z)) + remove_atom_from_single_hud(former_viewer, hud_atom) + +/// add new_hud_atom to this hud +/datum/atom_hud/proc/add_atom_to_hud(atom/new_hud_atom) + if(!new_hud_atom) + return FALSE + var/turf/atom_turf = get_turf(new_hud_atom) + if(!atom_turf) + return + + RegisterSignal(new_hud_atom, COMSIG_MOVABLE_Z_CHANGED, .proc/on_atom_or_user_z_level_changed, override = TRUE) + RegisterSignal(new_hud_atom, COMSIG_PARENT_QDELETING, .proc/unregister_atom, override = TRUE) //both hud atoms and hud users use these signals + + hud_atoms[atom_turf.z] |= new_hud_atom + hud_atoms_all_z_levels[new_hud_atom] = TRUE + + for(var/mob/mob_to_show as anything in get_hud_users_for_z_level(atom_turf.z)) + if(!queued_to_see[mob_to_show]) + add_atom_to_single_mob_hud(mob_to_show, new_hud_atom) + return TRUE + +/// remove this atom from this hud completely +/datum/atom_hud/proc/remove_atom_from_hud(atom/hud_atom_to_remove) + if(!hud_atom_to_remove || !hud_atoms_all_z_levels[hud_atom_to_remove]) + return FALSE + + //make sure we arent unregistering a hud atom thats also a hud user mob + if(!hud_users_all_z_levels[hud_atom_to_remove]) + UnregisterSignal(hud_atom_to_remove, COMSIG_MOVABLE_Z_CHANGED) + UnregisterSignal(hud_atom_to_remove, COMSIG_PARENT_QDELETING) -/datum/atom_hud/proc/unregister_mob(datum/source, force) + for(var/mob/mob_to_remove as anything in hud_users_all_z_levels) + remove_atom_from_single_hud(mob_to_remove, hud_atom_to_remove) + + var/turf/atom_turf = get_turf(hud_atom_to_remove) + if(!atom_turf) + return + + hud_atoms[atom_turf.z] -= hud_atom_to_remove + hud_atoms_all_z_levels -= hud_atom_to_remove + + return TRUE + +///adds a newly active hud category's image on a hud atom to every mob that could see it +/datum/atom_hud/proc/add_single_hud_category_on_atom(atom/hud_atom, hud_category_to_add) + if(!hud_atom?.active_hud_list?[hud_category_to_add] || QDELING(hud_atom) || !(hud_category_to_add in hud_icons)) + return FALSE + + var/turf/atom_turf = get_turf(hud_atom) + if(!atom_turf) + return FALSE + + if(!hud_atoms_all_z_levels[hud_atom]) + add_atom_to_hud(hud_atom) + return TRUE + + for(var/mob/hud_user as anything in get_hud_users_for_z_level(atom_turf.z)) + if(!hud_user.client) + continue + if(!hud_exceptions[hud_user] || !(hud_atom in hud_exceptions[hud_user])) + hud_user.client.images |= hud_atom.active_hud_list[hud_category_to_add] + + return TRUE + +///removes the image or images in hud_atom.hud_list[hud_category_to_remove] from every mob that can see it but leaves every other image +///from that atom there. +/datum/atom_hud/proc/remove_single_hud_category_on_atom(atom/hud_atom, hud_category_to_remove) + if(QDELETED(hud_atom) || !(hud_category_to_remove in hud_icons) || !hud_atoms_all_z_levels[hud_atom]) + return FALSE + + if(!hud_atom.active_hud_list) + remove_atom_from_hud(hud_atom) + return TRUE + + var/turf/atom_turf = get_turf(hud_atom) + if(!atom_turf) + return FALSE + + for(var/mob/hud_user as anything in get_hud_users_for_z_level(atom_turf.z)) + if(!hud_user.client) + continue + hud_user.client.images -= hud_atom.active_hud_list[hud_category_to_remove]//by this point it shouldnt be in active_hud_list + + return TRUE + +///when a hud atom or hud user changes z levels this makes sure it gets the images it needs and removes the images it doesnt need. +///because of how signals work we need the same proc to handle both use cases because being a hud atom and being a hud user arent mutually exclusive +/datum/atom_hud/proc/on_atom_or_user_z_level_changed(atom/movable/moved_atom, turf/old_turf, turf/new_turf) SIGNAL_HANDLER - remove_hud_from(source, TRUE) -/datum/atom_hud/proc/hide_single_atomhud_from(hud_user,hidden_atom) - if(hudusers[hud_user]) - remove_from_single_hud(hud_user,hidden_atom) + if(old_turf) + if(hud_users_all_z_levels[moved_atom]) + hud_users[old_turf.z] -= moved_atom + + for(var/atom/formerly_seen_hud_atom as anything in get_hud_atoms_for_z_level(old_turf.z)) + remove_atom_from_single_hud(moved_atom, formerly_seen_hud_atom) + + if(hud_atoms_all_z_levels[moved_atom]) + hud_atoms[old_turf.z] -= moved_atom + + for(var/mob/formerly_seeing as anything in get_hud_users_for_z_level(old_turf.z))//this wont include moved_atom since its removed + remove_atom_from_single_hud(formerly_seeing, moved_atom) + + if(new_turf) + if(hud_users_all_z_levels[moved_atom]) + hud_users[new_turf.z][moved_atom] = TRUE //hud users is associative, hud atoms isnt + + for(var/atom/newly_seen_hud_atom as anything in get_hud_atoms_for_z_level(new_turf.z)) + add_atom_to_single_mob_hud(moved_atom, newly_seen_hud_atom) + + if(hud_atoms_all_z_levels[moved_atom]) + hud_atoms[new_turf.z] |= moved_atom + + for(var/mob/newly_seeing as anything in get_hud_users_for_z_level(new_turf.z)) + add_atom_to_single_mob_hud(newly_seeing, moved_atom) + +/// add just hud_atom's hud images (that are part of this atom_hud) to requesting_mob's client.images list +/datum/atom_hud/proc/add_atom_to_single_mob_hud(mob/requesting_mob, atom/hud_atom) //unsafe, no sanity apart from client + if(!requesting_mob || !requesting_mob.client || !hud_atom) + return + + for(var/hud_category in (hud_icons & hud_atom.active_hud_list)) + if(!hud_exceptions[requesting_mob] || !(hud_atom in hud_exceptions[requesting_mob])) + requesting_mob.client.images |= hud_atom.active_hud_list[hud_category] + +/// remove every hud image for this hud on atom_to_remove from client_mob's client.images list +/datum/atom_hud/proc/remove_atom_from_single_hud(mob/client_mob, atom/atom_to_remove) + if(!client_mob || !client_mob.client || !atom_to_remove?.active_hud_list) + return + for(var/hud_image in hud_icons) + client_mob.client.images -= atom_to_remove.active_hud_list[hud_image] + +/datum/atom_hud/proc/unregister_atom(datum/source, force) + SIGNAL_HANDLER + hide_from(source, TRUE) + remove_atom_from_hud(source) + +/datum/atom_hud/proc/hide_single_atomhud_from(mob/hud_user, atom/hidden_atom) + + if(hud_users_all_z_levels[hud_user]) + remove_atom_from_single_hud(hud_user, hidden_atom) + if(!hud_exceptions[hud_user]) hud_exceptions[hud_user] = list(hidden_atom) else hud_exceptions[hud_user] += hidden_atom -/datum/atom_hud/proc/unhide_single_atomhud_from(hud_user,hidden_atom) +/datum/atom_hud/proc/unhide_single_atomhud_from(mob/hud_user, atom/hidden_atom) hud_exceptions[hud_user] -= hidden_atom - if(hudusers[hud_user]) - add_to_single_hud(hud_user,hidden_atom) - -/datum/atom_hud/proc/show_hud_images_after_cooldown(M) - if(queued_to_see[M]) - queued_to_see -= M - next_time_allowed[M] = world.time + ADD_HUD_TO_COOLDOWN - for(var/atom/A in hudatoms) - add_to_single_hud(M, A) - -/datum/atom_hud/proc/add_to_hud(atom/A) - if(!A) - return FALSE - hudatoms |= A - for(var/mob/M in hudusers) - if(!queued_to_see[M]) - add_to_single_hud(M, A) - return TRUE -/datum/atom_hud/proc/add_to_single_hud(mob/M, atom/A) //unsafe, no sanity apart from client - if(!M || !M.client || !A) + var/turf/hud_atom_turf = get_turf(hidden_atom) + + if(!hud_atom_turf) + return + + if(hud_users[hud_atom_turf.z][hud_user]) + add_atom_to_single_mob_hud(hud_user, hidden_atom) + +/datum/atom_hud/proc/show_hud_images_after_cooldown(mob/queued_hud_user) + if(!queued_to_see[queued_hud_user]) return - for(var/i in hud_icons) - if(A.hud_list[i] && (!hud_exceptions[M] || !(A in hud_exceptions[M]))) - M.client.images |= A.hud_list[i] + + queued_to_see -= queued_hud_user + next_time_allowed[queued_hud_user] = world.time + ADD_HUD_TO_COOLDOWN + + var/turf/user_turf = get_turf(queued_hud_user) + if(!user_turf) + return + + for(var/atom/hud_atom_to_show as anything in get_hud_atoms_for_z_level(user_turf.z)) + add_atom_to_single_mob_hud(queued_hud_user, hud_atom_to_show) //MOB PROCS /mob/proc/reload_huds() + var/turf/our_turf = get_turf(src) + if(!our_turf) + return + for(var/datum/atom_hud/hud in GLOB.all_huds) - if(hud?.hudusers[src]) - for(var/atom/A in hud.hudatoms) - hud.add_to_single_hud(src, A) + if(hud?.hud_users_all_z_levels[src]) + for(var/atom/hud_atom as anything in hud.get_hud_atoms_for_z_level(our_turf.z)) + hud.add_atom_to_single_mob_hud(src, hud_atom) /mob/dead/new_player/reload_huds() return diff --git a/code/datums/id_trim/jobs.dm b/code/datums/id_trim/jobs.dm index e55d101cee39e..30c730450b12b 100644 --- a/code/datums/id_trim/jobs.dm +++ b/code/datums/id_trim/jobs.dm @@ -17,8 +17,6 @@ var/list/minimal_wildcard_access = list() /// Static list. Cache of any mapping config job changes. var/static/list/job_changes - /// What config entry relates to this job. Should be a lowercase job name with underscores for spaces, eg "prisoner" "research_director" "head_of_security" - var/config_job /// An ID card with an access in this list can apply this trim to IDs or use it as a job template when adding access to a card. If the list is null, cannot be used as a template. Should be Head of Staff or ID Console accesses or it may do nothing. var/list/template_access /// The typepath to the job datum from the id_trim. This is converted to one of the job singletons in New(). @@ -31,11 +29,11 @@ if(isnull(job_changes)) job_changes = SSmapping.config.job_changes - if(!length(job_changes) || !config_job) + if(!length(job_changes)) refresh_trim_access() return - var/list/access_changes = job_changes[config_job] + var/list/access_changes = job_changes[job.title] if(!length(access_changes)) refresh_trim_access() @@ -84,7 +82,6 @@ sechud_icon_state = SECHUD_ASSISTANT extra_access = list(ACCESS_MAINT_TUNNELS) minimal_access = list() - config_job = "assistant" template_access = list(ACCESS_CAPTAIN, ACCESS_HOP, ACCESS_CHANGE_IDS) job = /datum/job/assistant @@ -102,10 +99,9 @@ assignment = "Atmospheric Technician" trim_state = "trim_atmospherictechnician" sechud_icon_state = SECHUD_ATMOSPHERIC_TECHNICIAN - extra_access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_MINERAL_STOREROOM, ACCESS_TECH_STORAGE) - minimal_access = list(ACCESS_ATMOSPHERICS, ACCESS_AUX_BASE, ACCESS_CONSTRUCTION, ACCESS_EXTERNAL_AIRLOCKS, ACCESS_MAINT_TUNNELS, ACCESS_MECH_ENGINE, + extra_access = list(ACCESS_ENGINE_EQUIP, ACCESS_MINERAL_STOREROOM, ACCESS_TECH_STORAGE) + minimal_access = list(ACCESS_ENGINEERING, ACCESS_ATMOSPHERICS, ACCESS_AUX_BASE, ACCESS_CONSTRUCTION, ACCESS_EXTERNAL_AIRLOCKS, ACCESS_MAINT_TUNNELS, ACCESS_MECH_ENGINE, ACCESS_MINERAL_STOREROOM) - config_job = "atmospheric_technician" template_access = list(ACCESS_CAPTAIN, ACCESS_CE, ACCESS_CHANGE_IDS) job = /datum/job/atmospheric_technician @@ -115,7 +111,6 @@ sechud_icon_state = SECHUD_BARTENDER extra_access = list(ACCESS_HYDROPONICS, ACCESS_KITCHEN, ACCESS_MORGUE) minimal_access = list(ACCESS_BAR, ACCESS_MINERAL_STOREROOM, ACCESS_THEATRE, ACCESS_WEAPONS, ACCESS_SERVICE) - config_job = "bartender" template_access = list(ACCESS_CAPTAIN, ACCESS_HOP, ACCESS_CHANGE_IDS) job = /datum/job/bartender @@ -125,7 +120,6 @@ sechud_icon_state = SECHUD_BOTANIST extra_access = list(ACCESS_BAR, ACCESS_KITCHEN) minimal_access = list(ACCESS_HYDROPONICS, ACCESS_MINERAL_STOREROOM, ACCESS_MORGUE, ACCESS_SERVICE) - config_job = "botanist" template_access = list(ACCESS_CAPTAIN, ACCESS_HOP, ACCESS_CHANGE_IDS) job = /datum/job/botanist @@ -134,7 +128,6 @@ intern_alt_name = "Captain-in-Training" trim_state = "trim_captain" sechud_icon_state = SECHUD_CAPTAIN - config_job = "captain" template_access = list(ACCESS_CAPTAIN, ACCESS_CHANGE_IDS) job = /datum/job/captain @@ -152,8 +145,7 @@ trim_state = "trim_cargotechnician" sechud_icon_state = SECHUD_CARGO_TECHNICIAN extra_access = list(ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION) - minimal_access = list(ACCESS_CARGO, ACCESS_MAILSORTING, ACCESS_MAINT_TUNNELS, ACCESS_MECH_MINING, ACCESS_MINERAL_STOREROOM) - config_job = "cargo_technician" + minimal_access = list(ACCESS_CARGO, ACCESS_MAIL_SORTING, ACCESS_MAINT_TUNNELS, ACCESS_MECH_MINING, ACCESS_MINERAL_STOREROOM) template_access = list(ACCESS_CAPTAIN, ACCESS_HOP, ACCESS_CHANGE_IDS) job = /datum/job/cargo_technician @@ -163,7 +155,6 @@ sechud_icon_state = SECHUD_CHAPLAIN extra_access = list() minimal_access = list(ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_MORGUE, ACCESS_THEATRE, ACCESS_SERVICE) - config_job = "chaplain" template_access = list(ACCESS_CAPTAIN, ACCESS_HOP, ACCESS_CHANGE_IDS) job = /datum/job/chaplain @@ -172,8 +163,7 @@ trim_state = "trim_chemist" sechud_icon_state = SECHUD_CHEMIST extra_access = list(ACCESS_SURGERY, ACCESS_VIROLOGY) - minimal_access = list(ACCESS_CHEMISTRY, ACCESS_MECH_MEDICAL, ACCESS_MEDICAL, ACCESS_MINERAL_STOREROOM, ACCESS_MORGUE, ACCESS_PHARMACY) - config_job = "chemist" + minimal_access = list(ACCESS_PLUMBING, ACCESS_MECH_MEDICAL, ACCESS_MEDICAL, ACCESS_MINERAL_STOREROOM, ACCESS_MORGUE, ACCESS_PHARMACY) template_access = list(ACCESS_CAPTAIN, ACCESS_CMO, ACCESS_CHANGE_IDS) job = /datum/job/chemist @@ -184,11 +174,10 @@ sechud_icon_state = SECHUD_CHIEF_ENGINEER extra_access = list(ACCESS_TELEPORTER) extra_wildcard_access = list() - minimal_access = list(ACCESS_ATMOSPHERICS, ACCESS_AUX_BASE, ACCESS_CE, ACCESS_CONSTRUCTION, ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_EVA, - ACCESS_EXTERNAL_AIRLOCKS, ACCESS_HEADS, ACCESS_KEYCARD_AUTH, ACCESS_MAINT_TUNNELS, ACCESS_MECH_ENGINE, - ACCESS_MINERAL_STOREROOM, ACCESS_MINISAT, ACCESS_RC_ANNOUNCE, ACCESS_BRIG_ENTRANCE, ACCESS_TCOMSAT, ACCESS_TECH_STORAGE) + minimal_access = list(ACCESS_ATMOSPHERICS, ACCESS_AUX_BASE, ACCESS_CE, ACCESS_CONSTRUCTION, ACCESS_ENGINEERING, ACCESS_ENGINE_EQUIP, ACCESS_EVA, + ACCESS_EXTERNAL_AIRLOCKS, ACCESS_COMMAND, ACCESS_KEYCARD_AUTH, ACCESS_MAINT_TUNNELS, ACCESS_MECH_ENGINE, + ACCESS_MINERAL_STOREROOM, ACCESS_MINISAT, ACCESS_RC_ANNOUNCE, ACCESS_BRIG_ENTRANCE, ACCESS_TCOMMS, ACCESS_TECH_STORAGE) minimal_wildcard_access = list(ACCESS_CE) - config_job = "chief_engineer" template_access = list(ACCESS_CAPTAIN, ACCESS_CHANGE_IDS) job = /datum/job/chief_engineer @@ -199,11 +188,10 @@ sechud_icon_state = SECHUD_CHIEF_MEDICAL_OFFICER extra_access = list(ACCESS_TELEPORTER) extra_wildcard_access = list() - minimal_access = list(ACCESS_CHEMISTRY, ACCESS_EVA, ACCESS_HEADS, ACCESS_KEYCARD_AUTH, ACCESS_MAINT_TUNNELS, ACCESS_MECH_MEDICAL, + minimal_access = list(ACCESS_PLUMBING, ACCESS_EVA, ACCESS_COMMAND, ACCESS_KEYCARD_AUTH, ACCESS_MAINT_TUNNELS, ACCESS_MECH_MEDICAL, ACCESS_MEDICAL, ACCESS_MINERAL_STOREROOM, ACCESS_MORGUE, ACCESS_PHARMACY, ACCESS_PSYCHOLOGY, ACCESS_RC_ANNOUNCE, ACCESS_BRIG_ENTRANCE, ACCESS_SURGERY, ACCESS_VIROLOGY) minimal_wildcard_access = list(ACCESS_CMO) - config_job = "chief_medical_officer" template_access = list(ACCESS_CAPTAIN, ACCESS_CHANGE_IDS) job = /datum/job/chief_medical_officer @@ -213,7 +201,6 @@ sechud_icon_state = SECHUD_CLOWN extra_access = list() minimal_access = list(ACCESS_THEATRE, ACCESS_SERVICE) - config_job = "clown" template_access = list(ACCESS_CAPTAIN, ACCESS_HOP, ACCESS_CHANGE_IDS) job = /datum/job/clown @@ -223,7 +210,6 @@ sechud_icon_state = SECHUD_COOK extra_access = list(ACCESS_BAR, ACCESS_HYDROPONICS) minimal_access = list(ACCESS_KITCHEN, ACCESS_MINERAL_STOREROOM, ACCESS_MORGUE, ACCESS_SERVICE) - config_job = "cook" template_access = list(ACCESS_CAPTAIN, ACCESS_HOP, ACCESS_CHANGE_IDS) job = /datum/job/cook @@ -237,7 +223,6 @@ sechud_icon_state = SECHUD_CURATOR extra_access = list() minimal_access = list(ACCESS_AUX_BASE, ACCESS_LIBRARY, ACCESS_MINING_STATION, ACCESS_SERVICE) - config_job = "curator" template_access = list(ACCESS_CAPTAIN, ACCESS_HOP, ACCESS_CHANGE_IDS) job = /datum/job/curator @@ -245,10 +230,9 @@ assignment = "Detective" trim_state = "trim_detective" sechud_icon_state = SECHUD_DETECTIVE - extra_access = list() - minimal_access = list(ACCESS_BRIG, ACCESS_COURT, ACCESS_FORENSICS, ACCESS_BRIG_ENTRANCE,ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, + extra_access = list(ACCESS_BRIG) + minimal_access = list(ACCESS_SECURITY, ACCESS_COURT, ACCESS_DETECTIVE, ACCESS_BRIG_ENTRANCE,ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_MECH_SECURITY, ACCESS_MINERAL_STOREROOM, ACCESS_WEAPONS) - config_job = "detective" template_access = list(ACCESS_CAPTAIN, ACCESS_HOS, ACCESS_CHANGE_IDS) job = /datum/job/detective @@ -267,8 +251,7 @@ trim_state = "trim_geneticist" sechud_icon_state = SECHUD_GENETICIST extra_access = list(ACCESS_ROBOTICS, ACCESS_TECH_STORAGE, ACCESS_XENOBIOLOGY) - minimal_access = list(ACCESS_GENETICS, ACCESS_MECH_SCIENCE, ACCESS_MINERAL_STOREROOM, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_RND) - config_job = "geneticist" + minimal_access = list(ACCESS_GENETICS, ACCESS_MECH_SCIENCE, ACCESS_MINERAL_STOREROOM, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_SCIENCE) template_access = list(ACCESS_CAPTAIN, ACCESS_RD, ACCESS_CHANGE_IDS) job = /datum/job/geneticist @@ -280,13 +263,12 @@ extra_access = list() extra_wildcard_access = list() minimal_access = list(ACCESS_AI_UPLOAD, ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_AUX_BASE, ACCESS_BAR, ACCESS_CARGO, ACCESS_CHAPEL_OFFICE, - ACCESS_CHANGE_IDS, ACCESS_CONSTRUCTION, ACCESS_COURT, ACCESS_CREMATORIUM, ACCESS_ENGINE, ACCESS_EVA, ACCESS_GATEWAY, - ACCESS_HEADS, ACCESS_HYDROPONICS, ACCESS_JANITOR, ACCESS_KEYCARD_AUTH, ACCESS_KITCHEN, ACCESS_LAWYER, ACCESS_LIBRARY, - ACCESS_MAILSORTING, ACCESS_MAINT_TUNNELS, ACCESS_MECH_MINING, ACCESS_MEDICAL, ACCESS_MINERAL_STOREROOM, + ACCESS_CHANGE_IDS, ACCESS_CONSTRUCTION, ACCESS_COURT, ACCESS_CREMATORIUM, ACCESS_ENGINEERING, ACCESS_EVA, ACCESS_GATEWAY, + ACCESS_COMMAND, ACCESS_HYDROPONICS, ACCESS_JANITOR, ACCESS_KEYCARD_AUTH, ACCESS_KITCHEN, ACCESS_LAWYER, ACCESS_LIBRARY, + ACCESS_MAIL_SORTING, ACCESS_MAINT_TUNNELS, ACCESS_MECH_MINING, ACCESS_MEDICAL, ACCESS_MINERAL_STOREROOM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MORGUE, ACCESS_PSYCHOLOGY, ACCESS_QM, ACCESS_RC_ANNOUNCE, ACCESS_RESEARCH, ACCESS_BRIG_ENTRANCE, ACCESS_TELEPORTER, ACCESS_THEATRE, ACCESS_VAULT, ACCESS_WEAPONS, ACCESS_SERVICE) minimal_wildcard_access = list(ACCESS_HOP) - config_job = "head_of_personnel" template_access = list(ACCESS_CAPTAIN, ACCESS_CHANGE_IDS) job = /datum/job/head_of_personnel @@ -298,11 +280,10 @@ extra_access = list(ACCESS_TELEPORTER) extra_wildcard_access = list() minimal_access = list(ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_ARMORY, ACCESS_AUX_BASE, ACCESS_BRIG, ACCESS_CONSTRUCTION, ACCESS_COURT, - ACCESS_ENGINE, ACCESS_EVA, ACCESS_FORENSICS, ACCESS_GATEWAY, ACCESS_HEADS, ACCESS_KEYCARD_AUTH, - ACCESS_MAILSORTING, ACCESS_MAINT_TUNNELS, ACCESS_MECH_SECURITY, ACCESS_MEDICAL, ACCESS_MINERAL_STOREROOM, + ACCESS_ENGINEERING, ACCESS_EVA, ACCESS_DETECTIVE, ACCESS_GATEWAY, ACCESS_COMMAND, ACCESS_KEYCARD_AUTH, + ACCESS_MAIL_SORTING, ACCESS_MAINT_TUNNELS, ACCESS_MECH_SECURITY, ACCESS_MEDICAL, ACCESS_MINERAL_STOREROOM, ACCESS_MINING, ACCESS_MORGUE, ACCESS_RC_ANNOUNCE, ACCESS_RESEARCH, ACCESS_SECURITY, ACCESS_BRIG_ENTRANCE, ACCESS_WEAPONS) minimal_wildcard_access = list(ACCESS_HOS) - config_job = "head_of_security" template_access = list(ACCESS_CAPTAIN, ACCESS_CHANGE_IDS) job = /datum/job/head_of_security @@ -322,7 +303,6 @@ sechud_icon_state = SECHUD_JANITOR extra_access = list() minimal_access = list(ACCESS_JANITOR, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM, ACCESS_SERVICE) - config_job = "janitor" template_access = list(ACCESS_CAPTAIN, ACCESS_HOP, ACCESS_CHANGE_IDS) job = /datum/job/janitor @@ -332,7 +312,6 @@ sechud_icon_state = SECHUD_LAWYER extra_access = list() minimal_access = list(ACCESS_COURT, ACCESS_LAWYER, ACCESS_BRIG_ENTRANCE, ACCESS_SERVICE) - config_job = "lawyer" template_access = list(ACCESS_CAPTAIN, ACCESS_HOP, ACCESS_HOS, ACCESS_CHANGE_IDS) job = /datum/job/lawyer @@ -340,9 +319,8 @@ assignment = "Medical Doctor" trim_state = "trim_medicaldoctor" sechud_icon_state = SECHUD_MEDICAL_DOCTOR - extra_access = list(ACCESS_CHEMISTRY, ACCESS_VIROLOGY) + extra_access = list(ACCESS_PLUMBING, ACCESS_VIROLOGY) minimal_access = list(ACCESS_MECH_MEDICAL, ACCESS_MEDICAL, ACCESS_MINERAL_STOREROOM, ACCESS_MORGUE, ACCESS_PHARMACY, ACCESS_SURGERY) - config_job = "medical_doctor" template_access = list(ACCESS_CAPTAIN, ACCESS_CMO, ACCESS_CHANGE_IDS) job = /datum/job/doctor @@ -352,7 +330,6 @@ sechud_icon_state = SECHUD_MIME extra_access = list() minimal_access = list(ACCESS_THEATRE, ACCESS_SERVICE) - config_job = "mime" template_access = list(ACCESS_CAPTAIN, ACCESS_HOP, ACCESS_CHANGE_IDS) job = /datum/job/mime @@ -363,7 +340,6 @@ extra_access = list(ACCESS_SURGERY) minimal_access = list(ACCESS_CONSTRUCTION, ACCESS_HYDROPONICS, ACCESS_MAINT_TUNNELS, ACCESS_MECH_MEDICAL, ACCESS_MEDICAL, ACCESS_MINERAL_STOREROOM, ACCESS_MINING, ACCESS_MORGUE, ACCESS_RESEARCH) - config_job = "paramedic" template_access = list(ACCESS_CAPTAIN, ACCESS_CMO, ACCESS_CHANGE_IDS) job = /datum/job/paramedic @@ -371,7 +347,6 @@ assignment = "Prisoner" trim_state = "trim_prisoner" sechud_icon_state = SECHUD_PRISONER - config_job = "prisoner" template_access = list(ACCESS_CAPTAIN, ACCESS_HOP, ACCESS_HOS, ACCESS_CHANGE_IDS) job = /datum/job/prisoner @@ -409,7 +384,6 @@ sechud_icon_state = SECHUD_PSYCHOLOGIST extra_access = list() minimal_access = list(ACCESS_MEDICAL, ACCESS_PSYCHOLOGY, ACCESS_SERVICE) - config_job = "psychologist" template_access = list(ACCESS_CAPTAIN, ACCESS_HOP, ACCESS_CMO, ACCESS_CHANGE_IDS) job = /datum/job/psychologist @@ -418,9 +392,8 @@ trim_state = "trim_quartermaster" sechud_icon_state = SECHUD_QUARTERMASTER extra_access = list() - minimal_access = list(ACCESS_AUX_BASE, ACCESS_CARGO, ACCESS_MAILSORTING, ACCESS_MAINT_TUNNELS, ACCESS_MECH_MINING, ACCESS_MINING_STATION, + minimal_access = list(ACCESS_AUX_BASE, ACCESS_CARGO, ACCESS_MAIL_SORTING, ACCESS_MAINT_TUNNELS, ACCESS_MECH_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM, ACCESS_MINING, ACCESS_QM, ACCESS_RC_ANNOUNCE, ACCESS_VAULT) - config_job = "quartermaster" template_access = list(ACCESS_CAPTAIN, ACCESS_HOP, ACCESS_CHANGE_IDS) job = /datum/job/quartermaster @@ -431,13 +404,12 @@ sechud_icon_state = SECHUD_RESEARCH_DIRECTOR extra_access = list() extra_wildcard_access = list() - minimal_access = list(ACCESS_AI_UPLOAD, ACCESS_AUX_BASE, ACCESS_EVA, ACCESS_GATEWAY, ACCESS_GENETICS, ACCESS_HEADS, ACCESS_KEYCARD_AUTH, + minimal_access = list(ACCESS_AI_UPLOAD, ACCESS_AUX_BASE, ACCESS_EVA, ACCESS_GATEWAY, ACCESS_GENETICS, ACCESS_COMMAND, ACCESS_KEYCARD_AUTH, ACCESS_NETWORK, ACCESS_MAINT_TUNNELS, ACCESS_MECH_ENGINE, ACCESS_MECH_MINING, ACCESS_MECH_SECURITY, ACCESS_MECH_SCIENCE, ACCESS_MEDICAL, ACCESS_MINERAL_STOREROOM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINISAT, ACCESS_MORGUE, - ACCESS_ORDNANCE, ACCESS_ORDNANCE_STORAGE, ACCESS_RC_ANNOUNCE, ACCESS_RESEARCH, ACCESS_RND, ACCESS_ROBOTICS, + ACCESS_ORDNANCE, ACCESS_ORDNANCE_STORAGE, ACCESS_RC_ANNOUNCE, ACCESS_RESEARCH, ACCESS_SCIENCE, ACCESS_ROBOTICS, ACCESS_BRIG_ENTRANCE, ACCESS_TECH_STORAGE, ACCESS_TELEPORTER, ACCESS_XENOBIOLOGY) minimal_wildcard_access = list(ACCESS_RD) - config_job = "research_director" template_access = list(ACCESS_CAPTAIN, ACCESS_CHANGE_IDS) job = /datum/job/research_director @@ -446,9 +418,8 @@ trim_state = "trim_roboticist" sechud_icon_state = SECHUD_ROBOTICIST extra_access = list(ACCESS_GENETICS, ACCESS_ORDNANCE, ACCESS_ORDNANCE_STORAGE, ACCESS_XENOBIOLOGY) - minimal_access = list(ACCESS_AUX_BASE, ACCESS_MECH_SCIENCE, ACCESS_MINERAL_STOREROOM, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_RND, + minimal_access = list(ACCESS_AUX_BASE, ACCESS_MECH_SCIENCE, ACCESS_MINERAL_STOREROOM, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_SCIENCE, ACCESS_ROBOTICS, ACCESS_TECH_STORAGE) - config_job = "roboticist" template_access = list(ACCESS_CAPTAIN, ACCESS_RD, ACCESS_CHANGE_IDS) job = /datum/job/roboticist @@ -458,8 +429,7 @@ sechud_icon_state = SECHUD_SCIENTIST extra_access = list(ACCESS_GENETICS, ACCESS_ROBOTICS) minimal_access = list(ACCESS_AUX_BASE, ACCESS_MECH_SCIENCE, ACCESS_MINERAL_STOREROOM, ACCESS_ORDNANCE, ACCESS_ORDNANCE_STORAGE, - ACCESS_RESEARCH, ACCESS_RND, ACCESS_XENOBIOLOGY) - config_job = "scientist" + ACCESS_RESEARCH, ACCESS_SCIENCE, ACCESS_XENOBIOLOGY) template_access = list(ACCESS_CAPTAIN, ACCESS_RD, ACCESS_CHANGE_IDS) job = /datum/job/scientist @@ -468,14 +438,13 @@ assignment = "Security Officer" trim_state = "trim_securityofficer" sechud_icon_state = SECHUD_SECURITY_OFFICER - extra_access = list(ACCESS_FORENSICS, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE) + extra_access = list(ACCESS_DETECTIVE, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE) minimal_access = list(ACCESS_BRIG, ACCESS_COURT, ACCESS_SECURITY, ACCESS_BRIG_ENTRANCE, ACCESS_MECH_SECURITY, ACCESS_MINERAL_STOREROOM, ACCESS_WEAPONS) - /// List of bonus departmental accesses that departmental sec officers get. - var/department_access = list() - config_job = "security_officer" template_access = list(ACCESS_CAPTAIN, ACCESS_HOS, ACCESS_CHANGE_IDS) job = /datum/job/security_officer + /// List of bonus departmental accesses that departmental sec officers get. + var/department_access = list() /datum/id_trim/job/security_officer/refresh_trim_access() . = ..() @@ -492,38 +461,37 @@ /datum/id_trim/job/security_officer/supply assignment = "Security Officer (Cargo)" trim_state = "trim_securityofficer_car" - department_access = list(ACCESS_AUX_BASE, ACCESS_CARGO, ACCESS_MAILSORTING, ACCESS_MINING, ACCESS_MINING_STATION) + department_access = list(ACCESS_AUX_BASE, ACCESS_CARGO, ACCESS_MAIL_SORTING, ACCESS_MINING, ACCESS_MINING_STATION) /datum/id_trim/job/security_officer/engineering assignment = "Security Officer (Engineering)" trim_state = "trim_securityofficer_engi" - department_access = list(ACCESS_ATMOSPHERICS, ACCESS_AUX_BASE, ACCESS_CONSTRUCTION, ACCESS_ENGINE) + department_access = list(ACCESS_ATMOSPHERICS, ACCESS_AUX_BASE, ACCESS_CONSTRUCTION, ACCESS_ENGINEERING, ACCESS_ENGINE_EQUIP, ACCESS_TCOMMS) /datum/id_trim/job/security_officer/medical assignment = "Security Officer (Medical)" trim_state = "trim_securityofficer_med" - department_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY) + department_access = list(ACCESS_PHARMACY, ACCESS_PLUMBING, ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_VIROLOGY) /datum/id_trim/job/security_officer/science assignment = "Security Officer (Science)" trim_state = "trim_securityofficer_sci" - department_access = list(ACCESS_AUX_BASE, ACCESS_RESEARCH, ACCESS_RND) + department_access = list(ACCESS_AUX_BASE, ACCESS_GENETICS, ACCESS_ORDNANCE, ACCESS_ORDNANCE_STORAGE, ACCESS_RESEARCH, ACCESS_ROBOTICS, ACCESS_SCIENCE, ACCESS_XENOBIOLOGY) /datum/id_trim/job/shaft_miner assignment = "Shaft Miner" trim_state = "trim_shaftminer" sechud_icon_state = SECHUD_SHAFT_MINER - extra_access = list(ACCESS_CARGO, ACCESS_MAINT_TUNNELS, ACCESS_QM) - minimal_access = list(ACCESS_AUX_BASE, ACCESS_MAILSORTING, ACCESS_MECH_MINING, ACCESS_MINERAL_STOREROOM, ACCESS_MINING, + extra_access = list(ACCESS_MAINT_TUNNELS, ACCESS_QM) + minimal_access = list(ACCESS_CARGO, ACCESS_AUX_BASE, ACCESS_MAIL_SORTING, ACCESS_MECH_MINING, ACCESS_MINERAL_STOREROOM, ACCESS_MINING, ACCESS_MINING_STATION) - config_job = "shaft_miner" template_access = list(ACCESS_CAPTAIN, ACCESS_HOP, ACCESS_CHANGE_IDS) job = /datum/job/shaft_miner /// ID card obtained from the mining Disney dollar points vending machine. /datum/id_trim/job/shaft_miner/spare extra_access = list() - minimal_access = list(ACCESS_MAILSORTING, ACCESS_MECH_MINING, ACCESS_MINERAL_STOREROOM, ACCESS_MINING, ACCESS_MINING_STATION) + minimal_access = list(ACCESS_CARGO, ACCESS_MAIL_SORTING, ACCESS_MECH_MINING, ACCESS_MINERAL_STOREROOM, ACCESS_MINING, ACCESS_MINING_STATION) template_access = null /datum/id_trim/job/station_engineer @@ -531,9 +499,8 @@ trim_state = "trim_stationengineer" sechud_icon_state = SECHUD_STATION_ENGINEER extra_access = list(ACCESS_ATMOSPHERICS) - minimal_access = list(ACCESS_AUX_BASE, ACCESS_CONSTRUCTION, ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_EXTERNAL_AIRLOCKS, - ACCESS_MAINT_TUNNELS, ACCESS_MECH_ENGINE, ACCESS_MINERAL_STOREROOM, ACCESS_TCOMSAT, ACCESS_TECH_STORAGE) - config_job = "station_engineer" + minimal_access = list(ACCESS_AUX_BASE, ACCESS_CONSTRUCTION, ACCESS_ENGINEERING, ACCESS_ENGINE_EQUIP, ACCESS_EXTERNAL_AIRLOCKS, + ACCESS_MAINT_TUNNELS, ACCESS_MECH_ENGINE, ACCESS_MINERAL_STOREROOM, ACCESS_TCOMMS, ACCESS_TECH_STORAGE) template_access = list(ACCESS_CAPTAIN, ACCESS_CE, ACCESS_CHANGE_IDS) job = /datum/job/station_engineer @@ -541,9 +508,8 @@ assignment = "Virologist" trim_state = "trim_virologist" sechud_icon_state = SECHUD_VIROLOGIST - extra_access = list(ACCESS_CHEMISTRY, ACCESS_MORGUE, ACCESS_SURGERY) + extra_access = list(ACCESS_PLUMBING, ACCESS_MORGUE, ACCESS_SURGERY) minimal_access = list(ACCESS_MEDICAL, ACCESS_MECH_MEDICAL, ACCESS_MINERAL_STOREROOM, ACCESS_VIROLOGY) - config_job = "virologist" template_access = list(ACCESS_CAPTAIN, ACCESS_CMO, ACCESS_CHANGE_IDS) job = /datum/job/virologist @@ -551,10 +517,9 @@ assignment = "Warden" trim_state = "trim_warden" sechud_icon_state = SECHUD_WARDEN - extra_access = list(ACCESS_FORENSICS, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE) + extra_access = list(ACCESS_DETECTIVE, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE) minimal_access = list(ACCESS_ARMORY, ACCESS_BRIG, ACCESS_COURT, ACCESS_MECH_SECURITY, ACCESS_MINERAL_STOREROOM, ACCESS_SECURITY, ACCESS_BRIG_ENTRANCE, ACCESS_WEAPONS) // See /datum/job/warden/get_access() - config_job = "warden" template_access = list(ACCESS_CAPTAIN, ACCESS_HOS, ACCESS_CHANGE_IDS) job = /datum/job/warden diff --git a/code/datums/id_trim/ruins.dm b/code/datums/id_trim/ruins.dm index 67fdee55f7f0c..3d44cc2d7cb19 100644 --- a/code/datums/id_trim/ruins.dm +++ b/code/datums/id_trim/ruins.dm @@ -4,11 +4,11 @@ /// Trim for the hotel ruin. Not Hilbert's Hotel. /datum/id_trim/away/hotel - access = list(ACCESS_AWAY_GENERAL, ACCESS_AWAY_MAINT) + access = list(ACCESS_AWAY_GENERAL, ACCESS_AWAY_MAINTENANCE) /// Trim for the hotel ruin. Not Hilbert's Hotel. /datum/id_trim/away/hotel/security - access = list(ACCESS_AWAY_GENERAL, ACCESS_AWAY_MAINT, ACCESS_AWAY_SEC) + access = list(ACCESS_AWAY_GENERAL, ACCESS_AWAY_MAINTENANCE, ACCESS_AWAY_SEC) /// Trim for the oldstation ruin/Charlie station /datum/id_trim/away/old/sec @@ -22,18 +22,23 @@ /// Trim for the oldstation ruin/Charlie station /datum/id_trim/away/old/eng - access = list(ACCESS_AWAY_GENERAL, ACCESS_AWAY_ENGINE) + access = list(ACCESS_AWAY_GENERAL, ACCESS_AWAY_ENGINEERING) assignment = "Charlie Station Engineer" -/// Trim for the oldstation ruin/Charlie station +/// Trim for the oldstation ruin/Charlie station to access APCs and other equipment /datum/id_trim/away/old/apc - access = list(ACCESS_ENGINE_EQUIP) + access = list(ACCESS_ENGINEERING, ACCESS_ENGINE_EQUIP) + assignment = "Engineering Equipment Access" + +/// Trim for the oldstation ruin/Charlie station to access robots +/datum/id_trim/away/old/robo + access = list(ACCESS_AWAY_GENERAL, ACCESS_ROBOTICS) /// Trim for the cat surgeon ruin. /datum/id_trim/away/cat_surgeon assignment = "Cat Surgeon" trim_state = "trim_medicaldoctor" - access = list(ACCESS_AWAY_GENERAL, ACCESS_AWAY_MAINT) + access = list(ACCESS_AWAY_GENERAL, ACCESS_AWAY_MAINTENANCE) /// Trim for Hilber in Hilbert's Hotel. /datum/id_trim/away/hilbert @@ -79,7 +84,7 @@ /datum/id_trim/engioutpost assignment = "Senior Station Engineer" trim_state = "trim_stationengineer" - access = list(ACCESS_AWAY_GENERAL, ACCESS_AWAY_ENGINE, ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_MAINT_TUNNELS) + access = list(ACCESS_AWAY_GENERAL, ACCESS_AWAY_ENGINEERING, ACCESS_ENGINEERING, ACCESS_ENGINE_EQUIP, ACCESS_MAINT_TUNNELS) /// Trim for various various ruins. /datum/id_trim/job/station_engineer/gunner diff --git a/code/datums/map_config.dm b/code/datums/map_config.dm index 300e661be9744..c570e8be70624 100644 --- a/code/datums/map_config.dm +++ b/code/datums/map_config.dm @@ -1,7 +1,7 @@ -//used for holding information about unique properties of maps -//feed it json files that match the datum layout -//defaults to box -// -Cyberboss +//This file is used to contain unique properties of every map, and how we wish to alter them on a per-map basis. +//Use JSON files that match the datum layout and you should be set from there. +//Right now, we default to MetaStation to ensure something does indeed load by default. +// -san7890 (with regards to Cyberboss) /datum/map_config // Metadata @@ -28,13 +28,15 @@ var/shuttles = list( "cargo" = "cargo_box", "ferry" = "ferry_fancy", - "whiteship" = "whiteship_box", - "emergency" = "emergency_box") + "whiteship" = "whiteship_meta", + "emergency" = "emergency_meta") /// Dictionary of job sub-typepath to template changes dictionary var/job_changes = list() /// List of additional areas that count as a part of the library var/library_areas = list() + /// What message shows up when the orbit is shifted. + var/orbit_shift_replacement = "Attention crew, it appears that someone on your station has shifted your orbit into more dangerous territory." /** * Proc that simply loads the default map config, which should always be functional. @@ -166,6 +168,9 @@ log_world("map_config space_empty_levels is not a number!") return + if("orbit_shift_replacement" in json) + orbit_shift_replacement = json["orbit_shift_replacement"] + if ("minetype" in json) minetype = json["minetype"] @@ -176,7 +181,7 @@ log_world("map_config \"job_changes\" field is missing or invalid!") return job_changes = json["job_changes"] - + if("library_areas" in json) if(!islist(json["library_areas"])) log_world("map_config \"library_areas\" field is missing or invalid!") diff --git a/code/datums/mapgen/Cavegens/IcemoonCaves.dm b/code/datums/mapgen/Cavegens/IcemoonCaves.dm index ce5858fb0bde0..54e23c993199b 100644 --- a/code/datums/mapgen/Cavegens/IcemoonCaves.dm +++ b/code/datums/mapgen/Cavegens/IcemoonCaves.dm @@ -7,7 +7,7 @@ /mob/living/simple_animal/hostile/asteroid/polarbear = 30, /obj/structure/spawner/ice_moon/polarbear = 3, \ /mob/living/simple_animal/hostile/asteroid/hivelord/legion/snow = 50, /mob/living/simple_animal/hostile/asteroid/goldgrub = 10, \ /mob/living/simple_animal/hostile/asteroid/lobstrosity = 15) - flora_spawn_list = list(/obj/structure/flora/tree/pine = 2, /obj/structure/flora/rock/icy = 2, /obj/structure/flora/rock/pile/icy = 2, /obj/structure/flora/grass/both = 6, /obj/structure/flora/ash/chilly = 2) + flora_spawn_list = list(/obj/structure/flora/tree/pine/style_random = 2, /obj/structure/flora/rock/icy/style_random = 2, /obj/structure/flora/rock/pile/icy/style_random = 2, /obj/structure/flora/grass/both/style_random = 6, /obj/structure/flora/ash/chilly = 2) ///Note that this spawn list is also in the lavaland generator feature_spawn_list = list(/obj/structure/geyser/wittel = 6, /obj/structure/geyser/random = 2, /obj/structure/geyser/plasma_oxide = 10, /obj/structure/geyser/protozine = 10, /obj/structure/geyser/hollowwater = 10) @@ -28,4 +28,4 @@ /mob/living/simple_animal/hostile/asteroid/hivelord/legion/snow = 50, /obj/structure/spawner/ice_moon/demonic_portal/snowlegion = 3, \ SPAWN_MEGAFAUNA = 2) megafauna_spawn_list = list(/mob/living/simple_animal/hostile/megafauna/colossus = 1) - flora_spawn_list = list(/obj/structure/flora/rock/icy = 6, /obj/structure/flora/rock/pile/icy = 6, /obj/structure/flora/ash/chilly = 1) + flora_spawn_list = list(/obj/structure/flora/rock/icy/style_random = 6, /obj/structure/flora/rock/pile/icy/style_random = 6, /obj/structure/flora/ash/chilly = 1) diff --git a/code/datums/mapgen/biomes/_biome.dm b/code/datums/mapgen/biomes/_biome.dm index 5913e8986553b..025b904434d2f 100644 --- a/code/datums/mapgen/biomes/_biome.dm +++ b/code/datums/mapgen/biomes/_biome.dm @@ -7,7 +7,7 @@ ///Chance of having a mob from the fauna types list spawn var/fauna_density = 0 ///list of type paths of objects that can be spawned when the turf spawns flora - var/list/flora_types = list(/obj/structure/flora/grass/jungle) + var/list/flora_types = list(/obj/structure/flora/grass/jungle/a/style_random) ///list of type paths of mobs that can be spawned when the turf spawns fauna var/list/fauna_types = list() @@ -24,17 +24,17 @@ /datum/biome/mudlands turf_type = /turf/open/misc/dirt/jungle/dark - flora_types = list(/obj/structure/flora/grass/jungle,/obj/structure/flora/grass/jungle/b, /obj/structure/flora/rock/jungle, /obj/structure/flora/rock/pile/largejungle) + flora_types = list(/obj/structure/flora/grass/jungle/a/style_random,/obj/structure/flora/grass/jungle/b/style_random, /obj/structure/flora/rock/pile/jungle/style_random, /obj/structure/flora/rock/pile/jungle/large/style_random) flora_density = 3 /datum/biome/plains turf_type = /turf/open/misc/grass/jungle - flora_types = list(/obj/structure/flora/grass/jungle,/obj/structure/flora/grass/jungle/b, /obj/structure/flora/tree/jungle, /obj/structure/flora/rock/jungle, /obj/structure/flora/junglebush, /obj/structure/flora/junglebush/b, /obj/structure/flora/junglebush/c, /obj/structure/flora/junglebush/large, /obj/structure/flora/rock/pile/largejungle) + flora_types = list(/obj/structure/flora/grass/jungle/a/style_random,/obj/structure/flora/grass/jungle/b/style_random, /obj/structure/flora/tree/jungle/style_random, /obj/structure/flora/rock/pile/jungle/style_random, /obj/structure/flora/bush/jungle/a/style_random, /obj/structure/flora/bush/jungle/b/style_random, /obj/structure/flora/bush/jungle/c/style_random, /obj/structure/flora/bush/large/style_random, /obj/structure/flora/rock/pile/jungle/large/style_random) flora_density = 15 /datum/biome/jungle turf_type = /turf/open/misc/grass/jungle - flora_types = list(/obj/structure/flora/grass/jungle,/obj/structure/flora/grass/jungle/b, /obj/structure/flora/tree/jungle, /obj/structure/flora/rock/jungle, /obj/structure/flora/junglebush, /obj/structure/flora/junglebush/b, /obj/structure/flora/junglebush/c, /obj/structure/flora/junglebush/large, /obj/structure/flora/rock/pile/largejungle) + flora_types = list(/obj/structure/flora/grass/jungle/a/style_random,/obj/structure/flora/grass/jungle/b/style_random, /obj/structure/flora/tree/jungle/style_random, /obj/structure/flora/rock/pile/jungle/style_random, /obj/structure/flora/bush/jungle/a/style_random, /obj/structure/flora/bush/jungle/b/style_random, /obj/structure/flora/bush/jungle/c/style_random, /obj/structure/flora/bush/large/style_random, /obj/structure/flora/rock/pile/jungle/large/style_random) flora_density = 40 /datum/biome/jungle/deep diff --git a/code/datums/martial/cqc.dm b/code/datums/martial/cqc.dm index 3a1ae848281a8..273b0b0dc902e 100644 --- a/code/datums/martial/cqc.dm +++ b/code/datums/martial/cqc.dm @@ -183,7 +183,7 @@ playsound(get_turf(D), 'sound/weapons/cqchit1.ogg', 50, TRUE, -1) if(I && D.temporarilyRemoveItemFromInventory(I)) A.put_in_hands(I) - D.Jitter(2) + D.set_timed_status_effect(4 SECONDS, /datum/status_effect/jitter, only_if_higher = TRUE) D.apply_damage(5, A.get_attack_type()) else D.visible_message(span_danger("[A] fails to disarm [D]!"), \ @@ -222,12 +222,37 @@ ///Subtype of CQC. Only used for the chef. /datum/martial_art/cqc/under_siege name = "Close Quarters Cooking" - var/list/kitchen_areas + ///List of all areas that CQC will work in, defaults to Kitchen. + var/list/kitchen_areas = list(/area/station/service/kitchen) -/// Refreshes the valid areas from the cook job singleton, otherwise uses the default kitchen area as a fallback option. See also [/datum/job/cook/New]. +/// Refreshes the valid areas from the cook's mapping config, adding areas in config to the list of possible areas. /datum/martial_art/cqc/under_siege/proc/refresh_valid_areas() - var/datum/job/cook/cook_job = SSjob.GetJobType(/datum/job/cook) - kitchen_areas = cook_job.kitchen_areas.Copy() + var/list/job_changes = SSmapping.config.job_changes + + if(!length(job_changes)) + return + + var/list/cook_changes = job_changes[JOB_COOK] + + if(!length(cook_changes)) + return + + var/list/additional_cqc_areas = cook_changes["additional_cqc_areas"] + + if(!additional_cqc_areas) + return + + if(!islist(additional_cqc_areas)) + stack_trace("Incorrect CQC area format from mapping configs. Expected /list, got: \[[additional_cqc_areas.type]\]") + return + + for(var/path_as_text in additional_cqc_areas) + var/path = text2path(path_as_text) + if(!ispath(path, /area)) + stack_trace("Invalid path in mapping config for chef CQC: \[[path_as_text]\]") + continue + + kitchen_areas |= path /// Limits where the chef's CQC can be used to only whitelisted areas. /datum/martial_art/cqc/under_siege/can_use(mob/living/owner) diff --git a/code/datums/martial/krav_maga.dm b/code/datums/martial/krav_maga.dm index df491f5a0f7ca..488807dcfb3fc 100644 --- a/code/datums/martial/krav_maga.dm +++ b/code/datums/martial/krav_maga.dm @@ -209,11 +209,10 @@ icon_state = "black" inhand_icon_state = "blackgloves" siemens_coefficient = 0 - permeability_coefficient = 0.05 strip_delay = 80 cold_protection = HANDS min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT heat_protection = HANDS max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT resistance_flags = NONE - armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, FIRE = 80, ACID = 50) + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 90, FIRE = 80, ACID = 50) diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm index dda86b82ccc5d..767cf869ecc65 100644 --- a/code/datums/martial/sleeping_carp.dm +++ b/code/datums/martial/sleeping_carp.dm @@ -167,29 +167,11 @@ lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi' block_chance = 50 - var/wielded = FALSE // track wielded status on item - -/obj/item/staff/bostaff/Initialize(mapload) - . = ..() - RegisterSignal(src, COMSIG_TWOHANDED_WIELD, .proc/on_wield) - RegisterSignal(src, COMSIG_TWOHANDED_UNWIELD, .proc/on_unwield) /obj/item/staff/bostaff/ComponentInitialize() . = ..() AddComponent(/datum/component/two_handed, force_unwielded=10, force_wielded=24, icon_wielded="[base_icon_state]1") -/// triggered on wield of two handed item -/obj/item/staff/bostaff/proc/on_wield(obj/item/source, mob/user) - SIGNAL_HANDLER - - wielded = TRUE - -/// triggered on unwield of two handed item -/obj/item/staff/bostaff/proc/on_unwield(obj/item/source, mob/user) - SIGNAL_HANDLER - - wielded = FALSE - /obj/item/staff/bostaff/update_icon_state() icon_state = "[base_icon_state]0" return ..() @@ -215,7 +197,7 @@ return var/list/modifiers = params2list(params) if(LAZYACCESS(modifiers, RIGHT_CLICK)) - if(!wielded) + if(!HAS_TRAIT(src, TRAIT_WIELDED)) return ..() if(!ishuman(target)) return ..() @@ -242,6 +224,6 @@ return ..() /obj/item/staff/bostaff/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) - if(!wielded) + if(!HAS_TRAIT(src, TRAIT_WIELDED)) return ..() return FALSE diff --git a/code/datums/materials/alloys.dm b/code/datums/materials/alloys.dm index b656edf2002bd..419b42630c451 100644 --- a/code/datums/materials/alloys.dm +++ b/code/datums/materials/alloys.dm @@ -106,7 +106,7 @@ init_flags = MATERIAL_INIT_MAPLOAD armor_modifiers = list(MELEE = 1.2, BULLET = 1.2, LASER = 0.8, ENERGY = 0.8, BOMB = 0.5, BIO = 1.2, FIRE = 0.8, ACID = 2) sheet_type = /obj/item/stack/sheet/titaniumglass - shard_type = /obj/item/shard + shard_type = /obj/item/shard/titanium value_per_unit = 0.04 categories = list(MAT_CATEGORY_RIGID=TRUE, MAT_CATEGORY_BASE_RECIPES=TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) composition = list(/datum/material/glass=1, /datum/material/titanium=0.5) @@ -125,7 +125,7 @@ integrity_modifier = 1.1 armor_modifiers = list(MELEE = 1.2, BULLET = 1.2, LASER = 1.2, ENERGY = 1.2, BOMB = 0.5, BIO = 1.2, FIRE = 2, ACID = 2) sheet_type = /obj/item/stack/sheet/plastitaniumglass - shard_type = /obj/item/shard/plasma + shard_type = /obj/item/shard/plastitanium value_per_unit = 0.125 categories = list(MAT_CATEGORY_RIGID=TRUE, MAT_CATEGORY_BASE_RECIPES=TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) composition = list(/datum/material/glass=1, /datum/material/alloy/plastitanium=0.5) diff --git a/code/datums/materials/basemats.dm b/code/datums/materials/basemats.dm index 6526d4e1ff1f2..92e1afc283984 100644 --- a/code/datums/materials/basemats.dm +++ b/code/datums/materials/basemats.dm @@ -128,7 +128,6 @@ Unless you know what you're doing, only use the first three numbers. They're in greyscale_colors = "#c162ec" categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/mineral/plasma - shard_type = /obj/item/shard/plasma value_per_unit = 0.1 beauty_modifier = 0.15 armor_modifiers = list(MELEE = 1.4, BULLET = 0.7, LASER = 0, ENERGY = 1.2, BOMB = 0, BIO = 1.2, FIRE = 0, ACID = 0.5) diff --git a/code/datums/memory/memory.dm b/code/datums/memory/memory.dm index f2cbdd3bb3122..e1fe64e8f9f91 100644 --- a/code/datums/memory/memory.dm +++ b/code/datums/memory/memory.dm @@ -48,7 +48,7 @@ /mob/living/simple_animal/hostile/carp, /mob/living/simple_animal/hostile/bear, /mob/living/simple_animal/hostile/mushroom, - /mob/living/simple_animal/hostile/statue, + /mob/living/simple_animal/hostile/netherworld/statue, /mob/living/simple_animal/hostile/retaliate/bat, /mob/living/simple_animal/hostile/retaliate/goat, /mob/living/simple_animal/hostile/killertomato, diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 8a26ef8f2c863..9c5da09c43eff 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -52,11 +52,14 @@ var/static/default_martial_art = new/datum/martial_art var/miming = FALSE // Mime's vow of silence var/list/antag_datums - var/antag_hud_icon_state = null //this mind's ANTAG_HUD should have this icon_state - var/datum/atom_hud/alternate_appearance/basic/antagonist_hud/antag_hud = null //this mind's antag HUD + ///this mind's ANTAG_HUD should have this icon_state + var/antag_hud_icon_state = null + ///this mind's antag HUD + var/datum/atom_hud/alternate_appearance/basic/antagonist_hud/antag_hud = null var/holy_role = NONE //is this person a chaplain or admin role allowed to use bibles, Any rank besides 'NONE' allows for this. - var/mob/living/enslaved_to //If this mind's master is another mob (i.e. adamantine golems) + ///If this mind's master is another mob (i.e. adamantine golems) + var/mob/living/enslaved_to var/datum/language_holder/language_holder var/unconvertable = FALSE var/late_joiner = FALSE @@ -92,6 +95,8 @@ var/list/active_addictions ///List of objective-specific equipment that couldn't properly be given to the mind var/list/failed_special_equipment + /// A list to keep track of which books a person has read (to prevent people from reading the same book again and again for positive mood events) + var/list/book_titles_read /datum/mind/New(_key) key = _key @@ -805,7 +810,7 @@ if(istype(S, spell)) spell_list -= S qdel(S) - current?.client << output(null, "statbrowser:check_spells") + current?.client.stat_panel.send_message("check_spells") /datum/mind/proc/RemoveAllSpells() for(var/obj/effect/proc_holder/S in spell_list) diff --git a/code/datums/mocking/client.dm b/code/datums/mocking/client.dm index 4a665f828bed5..fd99e34520c36 100644 --- a/code/datums/mocking/client.dm +++ b/code/datums/mocking/client.dm @@ -5,3 +5,9 @@ /// The view of the client, similar to /client/var/view. var/view = "15x15" + + /// Objects on the screen of the client + var/list/screen = list() + + /// The mob the client controls + var/mob/mob diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm index 8b1073b5d07bb..050ff5ca16923 100644 --- a/code/datums/mood_events/generic_negative_events.dm +++ b/code/datums/mood_events/generic_negative_events.dm @@ -92,10 +92,9 @@ timeout = 2 MINUTES /datum/mood_event/table/add_effects() - if(isfelinid(owner)) + if(isfelinid(owner)) //Holy snowflake batman! var/mob/living/carbon/human/H = owner - H.dna.species.start_wagging_tail(H) - addtimer(CALLBACK(H.dna.species, /datum/species.proc/stop_wagging_tail, H), 3 SECONDS) + SEND_SIGNAL(H, COMSIG_ORGAN_WAG_TAIL, TRUE, 3 SECONDS) description = "They want to play on the table!" mood_change = 2 @@ -370,3 +369,8 @@ description = "If I'm not good at video games, can I truly call myself a gamer?" mood_change = -10 timeout = 10 MINUTES + +/datum/mood_event/lost_52_card_pickup + description = "This is really embarrassing! I'm ashamed to pick up all these cards off the floor..." + mood_change = -3 + timeout = 3 MINUTES diff --git a/code/datums/mood_events/generic_positive_events.dm b/code/datums/mood_events/generic_positive_events.dm index fbfdde4d70787..44acc5a322807 100644 --- a/code/datums/mood_events/generic_positive_events.dm +++ b/code/datums/mood_events/generic_positive_events.dm @@ -272,3 +272,24 @@ mood_change = 10 timeout = 5 MINUTES +/datum/mood_event/won_52_card_pickup + description = "HA! That loser will be picking cards up for a long time!" + mood_change = 3 + timeout = 3 MINUTES + +/datum/mood_event/playing_cards + description = "I'm enjoying playing cards with other people!" + mood_change = 2 + timeout = 3 MINUTES + +/datum/mood_event/playing_cards/add_effects(param) + var/card_players = 1 + for(var/mob/living/carbon/player in viewers(COMBAT_MESSAGE_RANGE, owner)) + var/player_has_cards = player.is_holding(/obj/item/toy/singlecard) || player.is_holding_item_of_type(/obj/item/toy/cards) + if(player_has_cards) + card_players++ + if(card_players > 5) + break + + mood_change *= card_players + return ..() diff --git a/code/datums/mutations/_mutations.dm b/code/datums/mutations/_mutations.dm index 460d5b58aac1d..20956b76be2f5 100644 --- a/code/datums/mutations/_mutations.dm +++ b/code/datums/mutations/_mutations.dm @@ -4,51 +4,82 @@ /datum/mutation/human name = "mutation" + /// Description of the mutation var/desc = "A mutation." + /// Is this mutation currently locked? var/locked + /// Quality of the mutation var/quality - var/get_chance = 100 - var/lowest_value = 256 * 8 + /// Message given to the user upon gaining this mutation var/text_gain_indication = "" + /// Message given to the user upon losing this mutation var/text_lose_indication = "" + /// Visual indicators upon the character of the owner of this mutation var/static/list/visual_indicators = list() + /// The proc holder (ew) o var/obj/effect/proc_holder/spell/power - var/layer_used = MUTATIONS_LAYER //which mutation layer to use - var/list/species_allowed //to restrict mutation to only certain species - var/health_req //minimum health required to acquire the mutation - var/limb_req //required limbs to acquire this mutation - var/time_coeff = 1 //coefficient for timed mutations + /// Which mutation layer to use + var/layer_used = MUTATIONS_LAYER + /// To restrict mutation to only certain species + var/list/species_allowed + /// Minimum health required to acquire the mutation + var/health_req + /// Required limbs to acquire this mutation + var/limb_req + /// The owner of this mutation's DNA var/datum/dna/dna + /// Owner of this mutation var/mob/living/carbon/human/owner - var/instability = 0 //instability the holder gets when the mutation is not native - var/blocks = 4 //Amount of those big blocks with gene sequences - var/difficulty = 8 //Amount of missing sequences. Sometimes it removes an entire pair for 2 points - var/timeout //Time between mutation creation and removal. If this exists, we have a timer - var/alias //'Mutation #49', decided every round to get some form of distinction between undiscovered mutations - var/scrambled = FALSE //Wheter we can read it if it's active. To avoid cheesing with mutagen - var/class //Decides player accesibility, sorta - var/list/conflicts //any mutations that might conflict. put mutation typepath defines in here. make sure to enter it both ways (so that A conflicts with B, and B with A) - var/allow_transfer //Do we transfer upon cloning? - //MUT_NORMAL - A mutation that can be activated and deactived by completing a sequence - //MUT_EXTRA - A mutation that is in the mutations tab, and can be given and taken away through though the DNA console. Has a 0 before it's name in the mutation section of the dna console - //MUT_OTHER Cannot be interacted with by players through normal means. I.E. wizards mutate - - - var/can_chromosome = CHROMOSOME_NONE //can we take chromosomes? 0: CHROMOSOME_NEVER never, 1:CHROMOSOME_NONE yeah, 2: CHROMOSOME_USED no, already have one - var/chromosome_name //purely cosmetic - var/modified = FALSE //ugly but we really don't want chromosomes and on_acquiring to overlap and apply double the powers + /// Instability the holder gets when the mutation is not native + var/instability = 0 + /// Amount of those big blocks with gene sequences + var/blocks = 4 + /// Amount of missing sequences. Sometimes it removes an entire pair for 2 points + var/difficulty = 8 + /// Time between mutation creation and removal. If this exists, we have a timer + var/timeout + /// 'Mutation #49', decided every round to get some form of distinction between undiscovered mutations + var/alias + /// Whether we can read it if it's active. To avoid cheesing with mutagen + var/scrambled = FALSE + /// The class of mutation (MUT_NORMAL, MUT_EXTRA, MUT_OTHER) + var/class + /** + * any mutations that might conflict. + * put mutation typepath defines in here. + * make sure to enter it both ways (so that A conflicts with B, and B with A) + */ + var/list/conflicts + + /** + * can we take chromosomes? + * 0: CHROMOSOME_NEVER never + * 1: CHROMOSOME_NONE yeah + * 2: CHROMOSOME_USED no, already have one + */ + var/can_chromosome = CHROMOSOME_NONE + /// Name of the chromosome + var/chromosome_name + /// Has the chromosome been modified + var/modified = FALSE //ugly but we really don't want chromosomes and on_acquiring to overlap and apply double the powers + /// Is this mutation mutadone proof var/mutadone_proof = FALSE //Chromosome stuff - set to -1 to prevent people from changing it. Example: It'd be a waste to decrease cooldown on mutism - var/stabilizer_coeff = 1 //genetic stability coeff - var/synchronizer_coeff = -1 //makes the mutation hurt the user less - var/power_coeff = -1 //boosts mutation strength - var/energy_coeff = -1 //lowers mutation cooldown - var/list/valid_chrom_list = list() //List of strings of valid chromosomes this mutation can accept. - -/datum/mutation/human/New(class_ = MUT_OTHER, timer, datum/mutation/human/copymut) + /// genetic stability coeff + var/stabilizer_coeff = 1 + /// Makes the mutation hurt the user less + var/synchronizer_coeff = -1 + /// Boosts mutation strength + var/power_coeff = -1 + /// Lowers mutation cooldown + var/energy_coeff = -1 + /// List of strings of valid chromosomes this mutation can accept. + var/list/valid_chrom_list = list() + +/datum/mutation/human/New(class = MUT_OTHER, timer, datum/mutation/human/copymut) . = ..() - class = class_ + src.class = class if(timer) addtimer(CALLBACK(src, .proc/remove), timer) timeout = timer @@ -56,23 +87,22 @@ copy_mutation(copymut) update_valid_chromosome_list() -/datum/mutation/human/proc/on_acquiring(mob/living/carbon/human/H) - if(!H || !istype(H) || H.stat == DEAD || (src in H.dna.mutations)) +/datum/mutation/human/proc/on_acquiring(mob/living/carbon/human/acquirer) + if(!acquirer || !istype(acquirer) || acquirer.stat == DEAD || (src in acquirer.dna.mutations)) return TRUE - if(species_allowed && !species_allowed.Find(H.dna.species.id)) + if(species_allowed && !species_allowed.Find(acquirer.dna.species.id)) return TRUE - if(health_req && H.health < health_req) + if(health_req && acquirer.health < health_req) return TRUE - if(limb_req && !H.get_bodypart(limb_req)) + if(limb_req && !acquirer.get_bodypart(limb_req)) return TRUE - for(var/M in H.dna.mutations)//check for conflicting powers - var/datum/mutation/human/mewtayshun = M + for(var/datum/mutation/human/mewtayshun as anything in acquirer.dna.mutations) //check for conflicting powers if(!(mewtayshun.type in conflicts) && !(type in mewtayshun.conflicts)) continue - to_chat(H, span_warning("You feel your genes resisting something.")) + to_chat(acquirer, span_warning("You feel your genes resisting something.")) return TRUE - owner = H - dna = H.dna + owner = acquirer + dna = acquirer.dna dna.mutations += src if(text_gain_indication) to_chat(owner, text_gain_indication) @@ -86,7 +116,7 @@ owner.apply_overlay(layer_used) grant_spell() //we do checks here so nothing about hulk getting magic if(!modified) - addtimer(CALLBACK(src, .proc/modify, 5)) //gonna want children calling ..() to run first + addtimer(CALLBACK(src, .proc/modify, 0.5 SECONDS)) //gonna want children calling ..() to run first /datum/mutation/human/proc/get_visual_indicator() return @@ -116,22 +146,23 @@ return /mob/living/carbon/human/update_mutations_overlay() - for(var/datum/mutation/human/CM in dna.mutations) - if(CM.species_allowed && !CM.species_allowed.Find(dna.species.id)) - dna.force_lose(CM) //shouldn't have that mutation at all + for(var/datum/mutation/human/mutation in dna.mutations) + if(mutation.species_allowed && !mutation.species_allowed.Find(dna.species.id)) + dna.force_lose(mutation) //shouldn't have that mutation at all + continue + if(mutation.visual_indicators.len == 0) continue - if(CM.visual_indicators.len) - var/list/mut_overlay = list() - if(overlays_standing[CM.layer_used]) - mut_overlay = overlays_standing[CM.layer_used] - var/mutable_appearance/V = CM.get_visual_indicator() - if(!mut_overlay.Find(V)) //either we lack the visual indicator or we have the wrong one - remove_overlay(CM.layer_used) - for(var/mutable_appearance/MA in CM.visual_indicators[CM.type]) - mut_overlay.Remove(MA) - mut_overlay |= V - overlays_standing[CM.layer_used] = mut_overlay - apply_overlay(CM.layer_used) + var/list/mut_overlay = list() + if(overlays_standing[mutation.layer_used]) + mut_overlay = overlays_standing[mutation.layer_used] + var/mutable_appearance/indicator_to_add = mutation.get_visual_indicator() + if(!mut_overlay.Find(indicator_to_add)) //either we lack the visual indicator or we have the wrong one + remove_overlay(mutation.layer_used) + for(var/mutable_appearance/indicator_to_remove in mutation.visual_indicators[mutation.type]) + mut_overlay.Remove(indicator_to_remove) + mut_overlay |= indicator_to_add + overlays_standing[mutation.layer_used] = mut_overlay + apply_overlay(mutation.layer_used) /datum/mutation/human/proc/modify() //called when a genome is applied so we can properly update some stats without having to remove and reapply the mutation from someone if(modified || !power || !owner) @@ -140,17 +171,17 @@ power.charge_counter *= GET_MUTATION_ENERGY(src) modified = TRUE -/datum/mutation/human/proc/copy_mutation(datum/mutation/human/HM) - if(!HM) +/datum/mutation/human/proc/copy_mutation(datum/mutation/human/mutation_to_copy) + if(!mutation_to_copy) return - chromosome_name = HM.chromosome_name - stabilizer_coeff = HM.stabilizer_coeff - synchronizer_coeff = HM.synchronizer_coeff - power_coeff = HM.power_coeff - energy_coeff = HM.energy_coeff - mutadone_proof = HM.mutadone_proof - can_chromosome = HM.can_chromosome - valid_chrom_list = HM.valid_chrom_list + chromosome_name = mutation_to_copy.chromosome_name + stabilizer_coeff = mutation_to_copy.stabilizer_coeff + synchronizer_coeff = mutation_to_copy.synchronizer_coeff + power_coeff = mutation_to_copy.power_coeff + energy_coeff = mutation_to_copy.energy_coeff + mutadone_proof = mutation_to_copy.mutadone_proof + can_chromosome = mutation_to_copy.can_chromosome + valid_chrom_list = mutation_to_copy.valid_chrom_list /datum/mutation/human/proc/remove_chromosome() stabilizer_coeff = initial(stabilizer_coeff) diff --git a/code/datums/mutations/actions.dm b/code/datums/mutations/actions.dm index 8096870697ef5..48e8c41b078b7 100644 --- a/code/datums/mutations/actions.dm +++ b/code/datums/mutations/actions.dm @@ -53,7 +53,7 @@ if(sniffed) var/old_target = tracking_target possible = list() - var/list/prints = sniffed.return_fingerprints() + var/list/prints = GET_ATOM_FINGERPRINTS(sniffed) if(prints) for(var/mob/living/carbon/C in GLOB.carbon_list) if(prints[md5(C.dna.unique_identity)]) @@ -146,7 +146,7 @@ return our_lizard.adjust_fire_stacks(cone_levels) - our_lizard.IgniteMob() + our_lizard.ignite_mob() to_chat(our_lizard, span_warning("Something in front of your mouth catches fire!")) /obj/effect/proc_holder/spell/cone/staggered/firebreath/cast(list/targets, mob/user) @@ -171,7 +171,7 @@ // The actual burn damage application is not blocked by fireproofing, like space dragons. target_mob.apply_damage(max(10, 40 - (5 * level)), BURN, spread_damage = TRUE) target_mob.adjust_fire_stacks(max(2, 5 - level)) - target_mob.IgniteMob() + target_mob.ignite_mob() /obj/effect/proc_holder/spell/cone/staggered/firebreath/do_obj_cone_effect(obj/target_obj, level) // Further out objects experience less exposed_temperature and exposed_volume @@ -280,9 +280,9 @@ var/mob/living/carbon/C = user if(HAS_TRAIT(C, TRAIT_NODISMEMBER)) return - var/obj/item/organ/tongue/tongue + var/obj/item/organ/internal/tongue/tongue for(var/org in C.internal_organs) - if(istype(org, /obj/item/organ/tongue)) + if(istype(org, /obj/item/organ/internal/tongue)) tongue = org break diff --git a/code/datums/mutations/adaptation.dm b/code/datums/mutations/adaptation.dm index e2ee98411bedd..e56d4cff06699 100644 --- a/code/datums/mutations/adaptation.dm +++ b/code/datums/mutations/adaptation.dm @@ -4,7 +4,6 @@ quality = POSITIVE difficulty = 16 text_gain_indication = "Your body feels warm!" - time_coeff = 5 instability = 25 conflicts = list(/datum/mutation/human/pressure_adaptation) @@ -34,7 +33,6 @@ quality = POSITIVE difficulty = 16 text_gain_indication = "Your body feels numb!" - time_coeff = 5 instability = 25 conflicts = list(/datum/mutation/human/temperature_adaptation) diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm index 466c6b328b828..0abb77a6a2db3 100644 --- a/code/datums/mutations/body.dm +++ b/code/datums/mutations/body.dm @@ -13,14 +13,15 @@ if(DT_PROB(0.5 * GET_MUTATION_SYNCHRONIZER(src), delta_time) && owner.stat == CONSCIOUS) owner.visible_message(span_danger("[owner] starts having a seizure!"), span_userdanger("You have a seizure!")) owner.Unconscious(200 * GET_MUTATION_POWER(src)) - owner.Jitter(1000 * GET_MUTATION_POWER(src)) + owner.set_timed_status_effect(2000 SECONDS * GET_MUTATION_POWER(src), /datum/status_effect/jitter) SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "epilepsy", /datum/mood_event/epilepsy) addtimer(CALLBACK(src, .proc/jitter_less), 90) /datum/mutation/human/epilepsy/proc/jitter_less() - if(owner) - owner.jitteriness = 10 + if(QDELETED(owner)) + return + owner.set_timed_status_effect(20 SECONDS, /datum/status_effect/jitter) //Unstable DNA induces random mutations! /datum/mutation/human/bad_dna @@ -178,7 +179,6 @@ text_gain_indication = "You feel unusually monkey-like." text_lose_indication = "You feel like your old self." quality = NEGATIVE - time_coeff = 2 locked = TRUE //Species specific, keep out of actual gene pool var/datum/species/original_species = /datum/species/human var/original_name @@ -293,7 +293,7 @@ /datum/mutation/human/fire/on_life(delta_time, times_fired) if(DT_PROB((0.05+(100-dna.stability)/19.5) * GET_MUTATION_SYNCHRONIZER(src), delta_time)) owner.adjust_fire_stacks(2 * GET_MUTATION_POWER(src)) - owner.IgniteMob() + owner.ignite_mob() /datum/mutation/human/fire/on_acquiring(mob/living/carbon/human/owner) if(..()) @@ -459,7 +459,7 @@ explosion(owner, light_impact_range = 2, adminlog = TRUE, explosion_cause = src) for(var/mob/living/carbon/human/H in view(2,owner)) - var/obj/item/organ/eyes/eyes = H.getorganslot(ORGAN_SLOT_EYES) + var/obj/item/organ/internal/eyes/eyes = H.getorganslot(ORGAN_SLOT_EYES) if(eyes) to_chat(H, span_userdanger("You are blinded by a shower of blood!")) else @@ -467,7 +467,7 @@ H.Stun(20) H.blur_eyes(20) eyes?.applyOrganDamage(5) - H.add_confusion(3) + H.adjust_timed_status_effect(3 SECONDS, /datum/status_effect/confusion) for(var/mob/living/silicon/S in view(2,owner)) to_chat(S, span_userdanger("Your sensors are disabled by a shower of blood!")) S.Paralyze(60) @@ -484,7 +484,7 @@ . = ..() if(.)//cant add return TRUE - var/obj/item/organ/brain/brain = owner.getorganslot(ORGAN_SLOT_BRAIN) + var/obj/item/organ/internal/brain/brain = owner.getorganslot(ORGAN_SLOT_BRAIN) if(brain) brain.zone = BODY_ZONE_CHEST @@ -502,7 +502,7 @@ . = ..() if(.) return TRUE - var/obj/item/organ/brain/brain = owner.getorganslot(ORGAN_SLOT_BRAIN) + var/obj/item/organ/internal/brain/brain = owner.getorganslot(ORGAN_SLOT_BRAIN) if(brain) //so this doesn't instantly kill you. we could delete the brain, but it lets people cure brain issues they /really/ shouldn't be brain.zone = BODY_ZONE_HEAD UnregisterSignal(owner, COMSIG_CARBON_ATTACH_LIMB) diff --git a/code/datums/mutations/chameleon.dm b/code/datums/mutations/chameleon.dm index 6d185e475e907..38f1e77656278 100644 --- a/code/datums/mutations/chameleon.dm +++ b/code/datums/mutations/chameleon.dm @@ -6,7 +6,6 @@ difficulty = 16 text_gain_indication = "You feel one with your surroundings." text_lose_indication = "You feel oddly exposed." - time_coeff = 5 instability = 25 /datum/mutation/human/chameleon/on_acquiring(mob/living/carbon/human/owner) diff --git a/code/datums/mutations/holy_mutation/burdened.dm b/code/datums/mutations/holy_mutation/burdened.dm index 955b0a9f8b649..404688ad7504a 100644 --- a/code/datums/mutations/holy_mutation/burdened.dm +++ b/code/datums/mutations/holy_mutation/burdened.dm @@ -107,8 +107,8 @@ if(special) //aheals return - if(istype(new_organ, /obj/item/organ/eyes)) - var/obj/item/organ/eyes/new_eyes = new_organ + if(istype(new_organ, /obj/item/organ/internal/eyes)) + var/obj/item/organ/internal/eyes/new_eyes = new_organ if(new_eyes.tint < TINT_BLIND) //unless you added unworking eyes (flashlight eyes), this is removing burden update_burden(FALSE) return @@ -121,8 +121,8 @@ if(special) //aheals return - if(istype(old_organ, /obj/item/organ/eyes)) - var/obj/item/organ/eyes/old_eyes = old_organ + if(istype(old_organ, /obj/item/organ/internal/eyes)) + 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) diff --git a/code/datums/mutations/hulk.dm b/code/datums/mutations/hulk.dm index c279e2fdf90ee..64b3c07d3c59d 100644 --- a/code/datums/mutations/hulk.dm +++ b/code/datums/mutations/hulk.dm @@ -109,7 +109,7 @@ return var/mob/living/carbon/possible_throwable = user.pulling - if(!possible_throwable.getorganslot(ORGAN_SLOT_TAIL)) + if(!possible_throwable.getorganslot(ORGAN_SLOT_EXTERNAL_TAIL)) return if(ishuman(possible_throwable)) diff --git a/code/datums/mutations/passive.dm b/code/datums/mutations/passive.dm index a8724dd137680..6024d212be00c 100644 --- a/code/datums/mutations/passive.dm +++ b/code/datums/mutations/passive.dm @@ -11,3 +11,21 @@ /datum/mutation/human/biotechcompat/on_losing(mob/living/carbon/human/owner) owner.adjust_skillchip_complexity_modifier(-1) return ..() + +/datum/mutation/human/clever + name = "Clever" + desc = "Causes the subject to feel just a little bit smarter. Most effective in specimens with low levels of intelligence." + quality = POSITIVE + instability = 20 + text_gain_indication = "You feel a little bit smarter." + text_lose_indication = "Your mind feels a little bit foggy." + +/datum/mutation/human/clever/on_acquiring(mob/living/carbon/human/owner) + if(..()) + return + ADD_TRAIT(owner, TRAIT_ADVANCEDTOOLUSER, GENETIC_MUTATION) + +/datum/mutation/human/clever/on_losing(mob/living/carbon/human/owner) + if(..()) + return + REMOVE_TRAIT(owner, TRAIT_ADVANCEDTOOLUSER, GENETIC_MUTATION) diff --git a/code/datums/mutations/radioactive.dm b/code/datums/mutations/radioactive.dm index cd61e0d2a66b0..b163a1f6c9eab 100644 --- a/code/datums/mutations/radioactive.dm +++ b/code/datums/mutations/radioactive.dm @@ -3,7 +3,6 @@ desc = "A volatile mutation that causes the host to sent out deadly beta radiation. This affects both the hosts and their surroundings." quality = NEGATIVE text_gain_indication = "You can feel it in your bones!" - time_coeff = 5 instability = 5 difficulty = 8 power_coeff = 1 diff --git a/code/datums/mutations/sight.dm b/code/datums/mutations/sight.dm index 198edc6d0d923..bc4995cb48588 100644 --- a/code/datums/mutations/sight.dm +++ b/code/datums/mutations/sight.dm @@ -41,7 +41,6 @@ difficulty = 18 text_gain_indication = "You can see the heat rising off of your skin..." text_lose_indication = "You can no longer see the heat rising off of your skin..." - time_coeff = 2 instability = 25 synchronizer_coeff = 1 power_coeff = 1 diff --git a/code/datums/mutations/touch.dm b/code/datums/mutations/touch.dm index b9ee9143fcb24..951d6edc6a70a 100644 --- a/code/datums/mutations/touch.dm +++ b/code/datums/mutations/touch.dm @@ -35,7 +35,7 @@ if(C.electrocute_act(15, user, 1, SHOCK_NOGLOVES | SHOCK_NOSTUN))//doesnt stun. never let this stun C.dropItemToGround(C.get_active_held_item()) C.dropItemToGround(C.get_inactive_held_item()) - C.add_confusion(15) + C.adjust_timed_status_effect(15 SECONDS, /datum/status_effect/confusion) C.visible_message(span_danger("[user] electrocutes [target]!"),span_userdanger("[user] electrocutes you!")) return ..() else diff --git a/code/datums/proximity_monitor/fields/peaceborg_dampener.dm b/code/datums/proximity_monitor/fields/projectile_dampener.dm similarity index 54% rename from code/datums/proximity_monitor/fields/peaceborg_dampener.dm rename to code/datums/proximity_monitor/fields/projectile_dampener.dm index 9d2549e89c20b..c66c74b779599 100644 --- a/code/datums/proximity_monitor/fields/peaceborg_dampener.dm +++ b/code/datums/proximity_monitor/fields/projectile_dampener.dm @@ -1,7 +1,7 @@ //Projectile dampening field that slows projectiles and lowers their damage for an energy cost deducted every 1/5 second. //Only use square radius for this! -/datum/proximity_monitor/advanced/peaceborg_dampener +/datum/proximity_monitor/advanced/projectile_dampener var/static/image/edgeturf_south = image('icons/effects/fields.dmi', icon_state = "projectile_dampen_south") var/static/image/edgeturf_north = image('icons/effects/fields.dmi', icon_state = "projectile_dampen_north") var/static/image/edgeturf_west = image('icons/effects/fields.dmi', icon_state = "projectile_dampen_west") @@ -11,43 +11,33 @@ var/static/image/northeast_corner = image('icons/effects/fields.dmi', icon_state = "projectile_dampen_northeast") var/static/image/southeast_corner = image('icons/effects/fields.dmi', icon_state = "projectile_dampen_southeast") var/static/image/generic_edge = image('icons/effects/fields.dmi', icon_state = "projectile_dampen_generic") - var/obj/item/borg/projectile_dampen/projector = null var/list/obj/projectile/tracked = list() var/list/obj/projectile/staging = list() // lazylist that keeps track of the overlays added to the edge of the field var/list/edgeturf_effects -/datum/proximity_monitor/advanced/peaceborg_dampener/New(atom/_host, range, _ignore_if_not_on_turf = TRUE, obj/item/borg/projectile_dampen/projector) +/datum/proximity_monitor/advanced/projectile_dampener/New(atom/_host, range, _ignore_if_not_on_turf = TRUE, atom/projector) ..() - src.projector = projector + RegisterSignal(projector, COMSIG_PARENT_QDELETING, .proc/on_projector_del) recalculate_field() START_PROCESSING(SSfastprocess, src) -/datum/proximity_monitor/advanced/peaceborg_dampener/Destroy() - projector = null +/datum/proximity_monitor/advanced/projectile_dampener/Destroy() STOP_PROCESSING(SSfastprocess, src) + for(var/obj/projectile/projectile in tracked) + release_projectile(projectile) return ..() -/datum/proximity_monitor/advanced/peaceborg_dampener/process() - if(!istype(projector)) - qdel(src) - return +/datum/proximity_monitor/advanced/projectile_dampener/process() var/list/ranged = list() - for(var/obj/projectile/P in range(current_range, get_turf(host))) - ranged += P - for(var/obj/projectile/P in tracked) - if(!(P in ranged) || !P.loc) - release_projectile(P) - for(var/mob/living/silicon/robot/R in range(current_range, get_turf(host))) - if(R.has_buckled_mobs()) - for(var/mob/living/L in R.buckled_mobs) - L.visible_message(span_warning("[L] is knocked off of [R] by the charge in [R]'s chassis induced by the hyperkinetic dampener field!")) //I know it's bad. - L.Paralyze(10) - R.unbuckle_mob(L) - do_sparks(5, 0, L) + for(var/obj/projectile/projectile in range(current_range, get_turf(host))) + ranged += projectile + for(var/obj/projectile/projectile in tracked) + if(!(projectile in ranged) || !projectile.loc) + release_projectile(projectile) ..() -/datum/proximity_monitor/advanced/peaceborg_dampener/setup_edge_turf(turf/target) +/datum/proximity_monitor/advanced/projectile_dampener/setup_edge_turf(turf/target) . = ..() var/image/overlay = get_edgeturf_overlay(get_edgeturf_direction(target)) var/obj/effect/abstract/effect = new(target) // Makes the field visible to players. @@ -58,14 +48,14 @@ effect.plane = ABOVE_GAME_PLANE LAZYSET(edgeturf_effects, target, effect) -/datum/proximity_monitor/advanced/peaceborg_dampener/cleanup_edge_turf(turf/target) +/datum/proximity_monitor/advanced/projectile_dampener/cleanup_edge_turf(turf/target) . = ..() var/obj/effect/abstract/effect = LAZYACCESS(edgeturf_effects, target) LAZYREMOVE(edgeturf_effects, target) if(effect) qdel(effect) -/datum/proximity_monitor/advanced/peaceborg_dampener/proc/get_edgeturf_overlay(direction) +/datum/proximity_monitor/advanced/projectile_dampener/proc/get_edgeturf_overlay(direction) switch(direction) if(NORTH) return edgeturf_north @@ -86,24 +76,37 @@ else return generic_edge -/datum/proximity_monitor/advanced/peaceborg_dampener/proc/capture_projectile(obj/projectile/P, track_projectile = TRUE) - if(P in tracked) +/datum/proximity_monitor/advanced/projectile_dampener/proc/capture_projectile(obj/projectile/projectile) + if(projectile in tracked) return - projector.dampen_projectile(P, track_projectile) - if(track_projectile) - tracked += P + SEND_SIGNAL(src, COMSIG_DAMPENER_CAPTURE, projectile) + tracked += projectile + +/datum/proximity_monitor/advanced/projectile_dampener/proc/release_projectile(obj/projectile/projectile) + SEND_SIGNAL(src, COMSIG_DAMPENER_RELEASE, projectile) + tracked -= projectile + +/datum/proximity_monitor/advanced/projectile_dampener/proc/on_projector_del(datum/source) + SIGNAL_HANDLER -/datum/proximity_monitor/advanced/peaceborg_dampener/proc/release_projectile(obj/projectile/P) - projector.restore_projectile(P) - tracked -= P + qdel(src) -/datum/proximity_monitor/advanced/peaceborg_dampener/field_edge_uncrossed(atom/movable/movable, turf/location) +/datum/proximity_monitor/advanced/projectile_dampener/field_edge_uncrossed(atom/movable/movable, turf/location) if(istype(movable, /obj/projectile) && get_dist(movable, host) > current_range) if(movable in tracked) release_projectile(movable) - else - capture_projectile(movable, FALSE) -/datum/proximity_monitor/advanced/peaceborg_dampener/field_edge_crossed(atom/movable/movable, turf/location) +/datum/proximity_monitor/advanced/projectile_dampener/field_edge_crossed(atom/movable/movable, turf/location) if(istype(movable, /obj/projectile) && !(movable in tracked)) capture_projectile(movable) + +/datum/proximity_monitor/advanced/projectile_dampener/peaceborg/process(delta_time) + for(var/mob/living/silicon/robot/borg in range(current_range, get_turf(host))) + if(!borg.has_buckled_mobs()) + continue + for(var/mob/living/buckled_mob in borg.buckled_mobs) + buckled_mob.visible_message(span_warning("[buckled_mob] is knocked off of [borg] by the charge in [borg]'s chassis induced by the hyperkinetic dampener field!")) //I know it's bad. + buckled_mob.Paralyze(1 SECONDS) + borg.unbuckle_mob(buckled_mob) + do_sparks(5, 0, buckled_mob) + ..() diff --git a/code/datums/proximity_monitor/proximity_monitor.dm b/code/datums/proximity_monitor/proximity_monitor.dm index 6bc78a39c835e..db3482f9a5a9d 100644 --- a/code/datums/proximity_monitor/proximity_monitor.dm +++ b/code/datums/proximity_monitor/proximity_monitor.dm @@ -10,7 +10,8 @@ ///The signals of the connect range component, needed to monitor the turfs in range. var/static/list/loc_connections = list( COMSIG_ATOM_ENTERED = .proc/on_entered, - COMSIG_ATOM_EXITED =.proc/on_uncrossed, + COMSIG_ATOM_EXITED = .proc/on_uncrossed, + COMSIG_ATOM_INITIALIZED_ON = .proc/on_entered, ) /datum/proximity_monitor/New(atom/_host, range, _ignore_if_not_on_turf = TRUE) diff --git a/code/datums/quirks/good.dm b/code/datums/quirks/good.dm index 053e65c61d3a9..ccb66016440da 100644 --- a/code/datums/quirks/good.dm +++ b/code/datums/quirks/good.dm @@ -40,17 +40,16 @@ processing_quirk = TRUE /datum/quirk/drunkhealing/process(delta_time) - var/mob/living/carbon/carbon_holder = quirk_holder - switch(carbon_holder.drunkenness) + switch(quirk_holder.get_drunk_amount()) if (6 to 40) - carbon_holder.adjustBruteLoss(-0.1*delta_time, FALSE) - carbon_holder.adjustFireLoss(-0.05*delta_time, FALSE) + quirk_holder.adjustBruteLoss(-0.1 * delta_time, FALSE) + quirk_holder.adjustFireLoss(-0.05 * delta_time) if (41 to 60) - carbon_holder.adjustBruteLoss(-0.4*delta_time, FALSE) - carbon_holder.adjustFireLoss(-0.2*delta_time, FALSE) + quirk_holder.adjustBruteLoss(-0.4 * delta_time, FALSE) + quirk_holder.adjustFireLoss(-0.2 * delta_time) if (61 to INFINITY) - carbon_holder.adjustBruteLoss(-0.8*delta_time, FALSE) - carbon_holder.adjustFireLoss(-0.4*delta_time, FALSE) + quirk_holder.adjustBruteLoss(-0.8 * delta_time, FALSE) + quirk_holder.adjustFireLoss(-0.4 * delta_time) /datum/quirk/empath name = "Empath" @@ -77,7 +76,7 @@ /datum/quirk/item_quirk/clown_enjoyer/add() var/datum/atom_hud/fan = GLOB.huds[DATA_HUD_FAN] - fan.add_hud_to(quirk_holder) + fan.show_to(quirk_holder) /datum/quirk/item_quirk/mime_fan name = "Mime Fan" @@ -94,7 +93,7 @@ /datum/quirk/item_quirk/mime_fan/add() var/datum/atom_hud/fan = GLOB.huds[DATA_HUD_FAN] - fan.add_hud_to(quirk_holder) + fan.show_to(quirk_holder) /datum/quirk/freerunning name = "Freerunning" @@ -167,7 +166,7 @@ /datum/quirk/night_vision/proc/refresh_quirk_holder_eyes() var/mob/living/carbon/human/human_quirk_holder = quirk_holder - var/obj/item/organ/eyes/eyes = human_quirk_holder.getorgan(/obj/item/organ/eyes) + var/obj/item/organ/internal/eyes/eyes = human_quirk_holder.getorgan(/obj/item/organ/internal/eyes) if(!eyes || eyes.lighting_alpha) return // We've either added or removed TRAIT_NIGHT_VISION before calling this proc. Just refresh the eyes. diff --git a/code/datums/quirks/negative.dm b/code/datums/quirks/negative.dm index aff999fcf2fa2..8579d956ba543 100644 --- a/code/datums/quirks/negative.dm +++ b/code/datums/quirks/negative.dm @@ -589,7 +589,7 @@ switch(rand(1,3)) if(1) - quirk_holder.Jitter(10) + quirk_holder.set_timed_status_effect(20 SECONDS, /datum/status_effect/jitter, only_if_higher = TRUE) msg += "causing you to start fidgeting!" if(2) quirk_holder.set_timed_status_effect(6 SECONDS, /datum/status_effect/speech/stutter, only_if_higher = TRUE) @@ -724,7 +724,7 @@ var/brand = initial(drug_container_type.name) quirk_holder.mind.add_memory(MEMORY_QUIRK_DRUG, list(DETAIL_FAV_BRAND = brand), memory_flags = MEMORY_FLAG_NOLOCATION | MEMORY_FLAG_NOPERSISTENCE, story_value = STORY_VALUE_SHIT) // smoker lungs have 25% less health and healing - var/obj/item/organ/lungs/smoker_lungs = quirk_holder.getorganslot(ORGAN_SLOT_LUNGS) + var/obj/item/organ/internal/lungs/smoker_lungs = quirk_holder.getorganslot(ORGAN_SLOT_LUNGS) if (smoker_lungs && !(smoker_lungs.organ_flags & ORGAN_SYNTHETIC)) // robotic lungs aren't affected smoker_lungs.maxHealth = smoker_lungs.maxHealth * 0.75 smoker_lungs.healing_factor = smoker_lungs.healing_factor * 0.75 @@ -826,12 +826,13 @@ hardcore_value = 1 /datum/quirk/bad_touch/add() - RegisterSignal(quirk_holder, list(COMSIG_LIVING_GET_PULLED, COMSIG_CARBON_HUGGED), .proc/uncomfortable_touch) + RegisterSignal(quirk_holder, list(COMSIG_LIVING_GET_PULLED, COMSIG_CARBON_HELP_ACT), .proc/uncomfortable_touch) /datum/quirk/bad_touch/remove() - UnregisterSignal(quirk_holder, list(COMSIG_LIVING_GET_PULLED, COMSIG_CARBON_HUGGED)) + UnregisterSignal(quirk_holder, list(COMSIG_LIVING_GET_PULLED, COMSIG_CARBON_HELP_ACT)) -/datum/quirk/bad_touch/proc/uncomfortable_touch() +/// Causes a negative moodlet to our quirk holder on signal +/datum/quirk/bad_touch/proc/uncomfortable_touch(datum/source) SIGNAL_HANDLER if(quirk_holder.stat == DEAD) @@ -894,3 +895,12 @@ return TRUE return FALSE + +/datum/quirk/illiterate + name = "Illiterate" + desc = "You dropped out of school and are unable to read or write. This affects reading, writing, using computers and other electronics." + icon = "graduation-cap" + value = -8 + mob_trait = TRAIT_ILLITERATE + medical_record_text = "Patient is not literate." + hardcore_value = 8 diff --git a/code/datums/quirks/neutral.dm b/code/datums/quirks/neutral.dm index 37e582b3fce29..53cf158d4ddb6 100644 --- a/code/datums/quirks/neutral.dm +++ b/code/datums/quirks/neutral.dm @@ -173,6 +173,60 @@ species.disliked_food = initial(species.disliked_food) UnregisterSignal(human_holder, COMSIG_SPECIES_GAIN) +/datum/quirk/heterochromatic + name = "Heterochromatic" + desc = "One of your eyes is a different color than the other!" + icon = "eye-low-vision" // Ignore the icon name, its actually a fairly good representation of different color eyes + value = 0 + var/color + +/datum/quirk/heterochromatic/add() + color = color || quirk_holder.client?.prefs?.read_preference(/datum/preference/color/heterochromatic) + if(!color) + return + + link_to_holder() + +/datum/quirk/heterochromatic/post_add() + if(color) + return + + color = quirk_holder.client?.prefs?.read_preference(/datum/preference/color/heterochromatic) + if(!color) + return + + link_to_holder() + +/datum/quirk/heterochromatic/remove() + UnregisterSignal(quirk_holder, COMSIG_CARBON_LOSE_ORGAN) + +/datum/quirk/heterochromatic/proc/link_to_holder() + var/mob/living/carbon/human/human_holder = quirk_holder + human_holder.eye_color_heterochromatic = TRUE + human_holder.eye_color_right = color + // We set override to TRUE as link to holder will be called whenever the preference is applied, given this quirk exists on the mob + RegisterSignal(human_holder, COMSIG_CARBON_LOSE_ORGAN, .proc/check_eye_removal, override=TRUE) + + var/obj/item/organ/internal/eyes/eyes_of_the_holder = quirk_holder.getorgan(/obj/item/organ/internal/eyes) + if(!eyes_of_the_holder) + return + + eyes_of_the_holder.eye_color_right = color + eyes_of_the_holder.old_eye_color_right = color + eyes_of_the_holder.refresh() + +/datum/quirk/heterochromatic/proc/check_eye_removal(datum/source, obj/item/organ/internal/eyes/removed) + SIGNAL_HANDLER + + if(!istype(removed)) + return + + // Eyes were removed, remove heterochromia from the human holder and bid them adieu + var/mob/living/carbon/human/human_holder = quirk_holder + human_holder.eye_color_heterochromatic = FALSE + human_holder.eye_color_right = initial(human_holder.eye_color_right) + UnregisterSignal(human_holder, COMSIG_CARBON_LOSE_ORGAN) + /datum/quirk/monochromatic name = "Monochromacy" desc = "You suffer from full colorblindness, and perceive nearly the entire world in blacks and whites." @@ -288,11 +342,11 @@ /datum/quirk/item_quirk/tongue_tied/add_unique() var/mob/living/carbon/human/human_holder = quirk_holder - var/obj/item/organ/tongue/old_tongue = human_holder.getorganslot(ORGAN_SLOT_TONGUE) + var/obj/item/organ/internal/tongue/old_tongue = human_holder.getorganslot(ORGAN_SLOT_TONGUE) old_tongue.Remove(human_holder) qdel(old_tongue) - var/obj/item/organ/tongue/tied/new_tongue = new(get_turf(human_holder)) + var/obj/item/organ/internal/tongue/tied/new_tongue = new(get_turf(human_holder)) new_tongue.Insert(human_holder) // Only tongues of people with this quirk can't be removed. Manually spawned or found tongues can be. new_tongue.organ_flags |= ORGAN_UNREMOVABLE diff --git a/code/datums/ruins/icemoon.dm b/code/datums/ruins/icemoon.dm index ebe5b786d53a7..5b30f8beaf633 100644 --- a/code/datums/ruins/icemoon.dm +++ b/code/datums/ruins/icemoon.dm @@ -6,6 +6,9 @@ cost = 5 ruin_type = ZTRAIT_ICE_RUINS default_area = /area/icemoon/surface/outdoors/unexplored + has_ceiling = TRUE + ceiling_turf = /turf/closed/mineral/random/snow + ceiling_baseturfs = list(/turf/open/misc/asteroid/snow/icemoon) // above ground only diff --git a/code/datums/ruins/space.dm b/code/datums/ruins/space.dm index 6bc15ca8f434d..c9c814fd1e79f 100644 --- a/code/datums/ruins/space.dm +++ b/code/datums/ruins/space.dm @@ -325,3 +325,9 @@ suffix = "space_billboard.dmm" name = "Space Billboard" description = "Frequently found alongside well-traversed sublight routes, space billboards have fallen out of favour in recent years as advertisers finally realised that people are incapable of reading billboards going by at over 2/3rds the speed of light." + +/datum/map_template/ruin/space/spinwardsmoothies + id = "spinwardsmoothies" + suffix = "spinwardsmoothies.dmm" + name = "Spinward Smoothies" + description = "A branch of the beloved Spinward Smoothies chain of smoothie bars." diff --git a/code/datums/saymode.dm b/code/datums/saymode.dm index 1533bdef7e306..154cf644016f8 100644 --- a/code/datums/saymode.dm +++ b/code/datums/saymode.dm @@ -26,7 +26,7 @@ /datum/saymode/vocalcords/handle_message(mob/living/user, message, datum/language/language) if(iscarbon(user)) var/mob/living/carbon/C = user - var/obj/item/organ/vocal_cords/V = C.getorganslot(ORGAN_SLOT_VOICE) + var/obj/item/organ/internal/vocal_cords/V = C.getorganslot(ORGAN_SLOT_VOICE) if(V?.can_speak_with()) V.handle_speech(message) //message V.speak_with(message) //action diff --git a/code/datums/shuttles.dm b/code/datums/shuttles.dm index 322f5efe1b6e4..c29daa8cc0d7f 100644 --- a/code/datums/shuttles.dm +++ b/code/datums/shuttles.dm @@ -409,6 +409,15 @@ admin_notes = "ONLY NINETIES KIDS REMEMBER. Uses the fun balloon and drone from the Emergency Bar." credit_cost = CARGO_CRATE_VALUE * 5 +/datum/map_template/shuttle/emergency/basketball + suffix = "bballhooper" + name = "Basketballer's Stadium" + description = "Hoop, man, hoop! Get your shooting game on with this sleek new basketball stadium! Do keep in mind that several other features \ + that you may expect to find common-place on other shuttles aren't present to give you this sleek stadium at an affordable cost. \ + It also wasn't manufactured to deal with the form-factor of some of your stations... good luck with that." + admin_notes = "A larger shuttle built around a basketball stadium: entirely impractical but just a complete blast!" + credit_cost = CARGO_CRATE_VALUE * 10 + /datum/map_template/shuttle/emergency/wabbajack suffix = "wabbajack" name = "NT Lepton Violet" diff --git a/code/datums/station_traits/negative_traits.dm b/code/datums/station_traits/negative_traits.dm index 8bec053b7eb99..b25216f05c48d 100644 --- a/code/datums/station_traits/negative_traits.dm +++ b/code/datums/station_traits/negative_traits.dm @@ -181,7 +181,7 @@ /datum/station_trait/revenge_of_pun_pun/proc/arm_monke() SIGNAL_HANDLER - var/mob/living/carbon/human/species/monkey/punpun/punpun = locate() + var/mob/living/carbon/human/species/monkey/punpun/punpun = GLOB.the_one_and_only_punpun if(!punpun) return var/weapon_type = pick_weight(weapon_types) diff --git a/code/datums/station_traits/neutral_traits.dm b/code/datums/station_traits/neutral_traits.dm index a7ad09cd8e847..99100e6244246 100644 --- a/code/datums/station_traits/neutral_traits.dm +++ b/code/datums/station_traits/neutral_traits.dm @@ -21,9 +21,15 @@ trait_type = STATION_TRAIT_NEUTRAL weight = 5 show_in_report = TRUE - report_message = "For experimental purposes, this station AI might show divergence from default lawset. Do not meddle with this experiment." + report_message = "For experimental purposes, this station AI might show divergence from default lawset. Do not meddle with this experiment, we've removed \ + access to your set of alternative upload modules because we know you're already thinking about meddling with this experiment." trait_to_give = STATION_TRAIT_UNIQUE_AI +/datum/station_trait/unique_ai/on_round_start() + . = ..() + for(var/mob/living/silicon/ai/ai as anything in GLOB.ai_list) + ai.show_laws() + /datum/station_trait/ian_adventure name = "Ian's Adventure" trait_type = STATION_TRAIT_NEUTRAL @@ -127,3 +133,59 @@ var/new_colored_assistant_type = pick(subtypesof(/datum/colored_assistant) - get_configured_colored_assistant_type()) GLOB.colored_assistant = new new_colored_assistant_type + +/datum/station_trait/cargorilla + name = "Cargo Gorilla" + trait_type = STATION_TRAIT_NEUTRAL + weight = 1 + show_in_report = FALSE // Selective attention test. Did you spot the gorilla? + + /// The gorilla we created, we only hold this ref until the round starts. + var/mob/living/simple_animal/hostile/gorilla/cargo_domestic/cargorilla + +/datum/station_trait/cargorilla/New() + . = ..() + RegisterSignal(SSatoms, COMSIG_SUBSYSTEM_POST_INITIALIZE, .proc/replace_cargo) + +/// Replace some cargo equipment and 'personnel' with a gorilla. +/datum/station_trait/cargorilla/proc/replace_cargo(datum/source) + SIGNAL_HANDLER + + var/mob/living/simple_animal/sloth/cargo_sloth = GLOB.cargo_sloth + if(!cargo_sloth) + return + + cargorilla = new(cargo_sloth.loc) + cargorilla.name = cargo_sloth.name + // We do a poll on roundstart, don't let ghosts in early + cargorilla.being_polled_for = TRUE + INVOKE_ASYNC(src, .proc/make_id_for_gorilla) + + // hm our sloth looks funny today + qdel(cargo_sloth) + + // monkey carries the crates, the age of robot is over + if(GLOB.cargo_ripley) + qdel(GLOB.cargo_ripley) + +/// Makes an ID card for the gorilla +/datum/station_trait/cargorilla/proc/make_id_for_gorilla() + var/obj/item/card/id/advanced/cargo_gorilla/gorilla_id = new(cargorilla.loc) + gorilla_id.registered_name = cargorilla.name + gorilla_id.update_label() + + cargorilla.put_in_hands(gorilla_id, del_on_fail = TRUE) + +/datum/station_trait/cargorilla/on_round_start() + if(!cargorilla) + return + + addtimer(CALLBACK(src, .proc/get_ghost_for_gorilla, cargorilla), 12 SECONDS) // give ghosts a bit of time to funnel in + cargorilla = null + +/// Get us a ghost for the gorilla. +/datum/station_trait/cargorilla/proc/get_ghost_for_gorilla(mob/living/simple_animal/hostile/gorilla/cargo_domestic/gorilla) + if(QDELETED(gorilla)) + return + + gorilla.poll_for_gorilla() diff --git a/code/datums/status_effects/_status_effect.dm b/code/datums/status_effects/_status_effect.dm index f760f10613017..32ea2eb8153d7 100644 --- a/code/datums/status_effects/_status_effect.dm +++ b/code/datums/status_effects/_status_effect.dm @@ -17,9 +17,6 @@ var/status_type = STATUS_EFFECT_UNIQUE /// If TRUE, we call [proc/on_remove] when owner is deleted. Otherwise, we call [proc/be_replaced]. var/on_remove_on_mob_delete = FALSE - /// If defined, this text will appear when the mob is examined - /// To use he, she etc. use "SUBJECTPRONOUN" and replace it in the examines themselves - var/examine_text /// The typepath to the alert thrown by the status effect when created. /// Status effect "name"s and "description"s are shown to the owner here. var/alert_type = /atom/movable/screen/alert/status_effect @@ -78,12 +75,12 @@ // Status effect process. Handles adjusting it's duration and ticks. // If you're adding processed effects, put them in [proc/tick] // instead of extending / overriding ththe process() proc. -/datum/status_effect/process(delta_time) +/datum/status_effect/process(delta_time, times_fired) if(QDELETED(owner)) qdel(src) return if(tick_interval < world.time) - tick() + tick(delta_time, times_fired) tick_interval = world.time + initial(tick_interval) if(duration != -1 && duration < world.time) qdel(src) @@ -93,8 +90,13 @@ /datum/status_effect/proc/on_apply() return TRUE +/// Gets and formats examine text associated with our status effect. +/// Return 'null' to have no examine text appear (default behavior). +/datum/status_effect/proc/get_examine_text() + return null + /// Called every tick from process(). -/datum/status_effect/proc/tick() +/datum/status_effect/proc/tick(delta_time, times_fired) return /// Called whenever the buff expires or is removed (qdeleted) diff --git a/code/datums/status_effects/_status_effect_helpers.dm b/code/datums/status_effects/_status_effect_helpers.dm index 3f21920f51630..9cd5f4f3c8663 100644 --- a/code/datums/status_effects/_status_effect_helpers.dm +++ b/code/datums/status_effects/_status_effect_helpers.dm @@ -40,7 +40,8 @@ // Create the status effect with our mob + our arguments var/datum/status_effect/new_instance = new new_effect(arguments) - return new_instance + if(!QDELETED(new_instance)) + return new_instance /** * Removes all instances of a given status effect from this mob diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm index 09c078b52bc85..ce8d5b6fbd4fc 100644 --- a/code/datums/status_effects/buffs.dm +++ b/code/datums/status_effects/buffs.dm @@ -210,7 +210,6 @@ status_type = STATUS_EFFECT_UNIQUE duration = -1 tick_interval = 25 - examine_text = "They seem to have an aura of healing and helpfulness about them." alert_type = null var/datum/component/aura_healing/aura_healing @@ -238,15 +237,18 @@ //Makes the user passive, it's in their oath not to harm! ADD_TRAIT(owner, TRAIT_PACIFISM, HIPPOCRATIC_OATH_TRAIT) - var/datum/atom_hud/H = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] - H.add_hud_to(owner) + var/datum/atom_hud/med_hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] + med_hud.show_to(owner) return ..() /datum/status_effect/hippocratic_oath/on_remove() QDEL_NULL(aura_healing) REMOVE_TRAIT(owner, TRAIT_PACIFISM, HIPPOCRATIC_OATH_TRAIT) - var/datum/atom_hud/H = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] - H.remove_hud_from(owner) + var/datum/atom_hud/med_hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] + med_hud.hide_from(owner) + +/datum/status_effect/hippocratic_oath/get_examine_text() + return span_notice("[owner.p_they(TRUE)] seem[owner.p_s()] to have an aura of healing and helpfulness about [owner.p_them()].") /datum/status_effect/hippocratic_oath/tick() if(owner.stat == DEAD) @@ -316,9 +318,9 @@ /datum/status_effect/good_music/tick() if(owner.can_hear()) - owner.dizziness = max(0, owner.dizziness - 2) - owner.jitteriness = max(0, owner.jitteriness - 2) - owner.set_confusion(max(0, owner.get_confusion() - 1)) + owner.adjust_timed_status_effect(-4 SECONDS, /datum/status_effect/dizziness) + owner.adjust_timed_status_effect(-4 SECONDS, /datum/status_effect/jitter) + owner.adjust_timed_status_effect(-1 SECONDS, /datum/status_effect/confusion) SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "goodmusic", /datum/mood_event/goodmusic) /atom/movable/screen/alert/status_effect/regenerative_core @@ -350,7 +352,6 @@ id = "Blessing of Crucible Soul" status_type = STATUS_EFFECT_REFRESH duration = 15 SECONDS - examine_text = "They don't seem to be all here." alert_type = /atom/movable/screen/alert/status_effect/crucible_soul var/turf/location @@ -368,6 +369,9 @@ owner.forceMove(location) location = null +/datum/status_effect/crucible_soul/get_examine_text() + return span_notice("[owner.p_they(TRUE)] [owner.p_do()]n't seem to be all here.") + /datum/status_effect/duskndawn id = "Blessing of Dusk and Dawn" status_type = STATUS_EFFECT_REFRESH @@ -513,6 +517,11 @@ if(!length(blades)) return + if(HAS_TRAIT(source, TRAIT_BEING_BLADE_SHIELDED)) + return + + ADD_TRAIT(source, TRAIT_BEING_BLADE_SHIELDED, type) + var/obj/effect/floating_blade/to_remove = blades[1] playsound(get_turf(source), 'sound/weapons/parry.ogg', 100, TRUE) @@ -524,6 +533,8 @@ qdel(to_remove) + addtimer(TRAIT_CALLBACK_REMOVE(source, TRAIT_BEING_BLADE_SHIELDED, type), 1) + return SHIELD_BLOCK /// Remove deleted blades from our blades list properly. diff --git a/code/datums/status_effects/debuffs/confusion.dm b/code/datums/status_effects/debuffs/confusion.dm new file mode 100644 index 0000000000000..ae115e4315d2b --- /dev/null +++ b/code/datums/status_effects/debuffs/confusion.dm @@ -0,0 +1,55 @@ +/// The threshold in which all of our movements are fully randomized, in seconds. +#define CONFUSION_FULL_THRESHOLD 40 +/// A multiplier applied on how much time is left (in seconds) that determines the chance of moving sideways randomly +#define CONFUSION_SIDEWAYS_MOVE_PROB_PER_SECOND 1.5 +/// A multiplier applied on how much time is left (in seconds) that determines the chance of moving diagonally randomly +#define CONFUSION_DIAGONAL_MOVE_PROB_PER_SECOND 3 + +/// A status effect used for adding confusion to a mob. +/datum/status_effect/confusion + id = "confusion" + alert_type = null + +/datum/status_effect/confusion/on_creation(mob/living/new_owner, duration = 10 SECONDS) + src.duration = duration + return ..() + +/datum/status_effect/confusion/on_apply() + RegisterSignal(owner, COMSIG_LIVING_POST_FULLY_HEAL, .proc/remove_confusion) + RegisterSignal(owner, COMSIG_MOB_CLIENT_PRE_MOVE, .proc/on_move) + return TRUE + +/datum/status_effect/confusion/on_remove() + UnregisterSignal(owner, list(COMSIG_LIVING_POST_FULLY_HEAL, COMSIG_MOB_CLIENT_PRE_MOVE)) + +/// Removes all of our confusion (self terminate) on signal +/datum/status_effect/confusion/proc/remove_confusion(datum/source) + SIGNAL_HANDLER + + qdel(src) + +/// Signal proc for [COMSIG_MOB_CLIENT_PRE_MOVE]. We have a chance to mix up our movement pre-move with confusion. +/datum/status_effect/confusion/proc/on_move(datum/source, list/move_args) + SIGNAL_HANDLER + + // How much time is left in the duration, in seconds. + var/time_left = (duration - world.time) / 10 + var/direction = move_args[MOVE_ARG_DIRECTION] + var/new_dir + + if(time_left > CONFUSION_FULL_THRESHOLD) + new_dir = pick(GLOB.alldirs) + + else if(prob(time_left * CONFUSION_SIDEWAYS_MOVE_PROB_PER_SECOND)) + new_dir = angle2dir(dir2angle(direction) + pick(90, -90)) + + else if(prob(time_left * CONFUSION_DIAGONAL_MOVE_PROB_PER_SECOND)) + new_dir = angle2dir(dir2angle(direction) + pick(45, -45)) + + if(!isnull(new_dir)) + move_args[MOVE_ARG_NEW_LOC] = get_step(owner, new_dir) + move_args[MOVE_ARG_DIRECTION] = new_dir + +#undef CONFUSION_FULL_THRESHOLD +#undef CONFUSION_SIDEWAYS_MOVE_PROB_PER_SECOND +#undef CONFUSION_DIAGONAL_MOVE_PROB_PER_SECOND diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm index 3709dc478364c..dd9c1e1457467 100644 --- a/code/datums/status_effects/debuffs/debuffs.dm +++ b/code/datums/status_effects/debuffs/debuffs.dm @@ -133,21 +133,6 @@ alert_type = /atom/movable/screen/alert/status_effect/asleep needs_update_stat = TRUE tick_interval = 2 SECONDS - var/mob/living/carbon/carbon_owner - var/mob/living/carbon/human/human_owner - -/datum/status_effect/incapacitating/sleeping/on_creation(mob/living/new_owner) - . = ..() - if(.) - if(iscarbon(owner)) //to avoid repeated istypes - carbon_owner = owner - if(ishuman(owner)) - human_owner = owner - -/datum/status_effect/incapacitating/sleeping/Destroy() - carbon_owner = null - human_owner = null - return ..() /datum/status_effect/incapacitating/sleeping/on_apply() . = ..() @@ -178,31 +163,71 @@ ADD_TRAIT(owner, TRAIT_KNOCKEDOUT, TRAIT_STATUS_EFFECT(id)) tick_interval = initial(tick_interval) +#define HEALING_SLEEP_DEFAULT 0.2 + /datum/status_effect/incapacitating/sleeping/tick() if(owner.maxHealth) var/health_ratio = owner.health / owner.maxHealth - var/healing = -0.2 + var/healing = HEALING_SLEEP_DEFAULT + + // having high spirits helps us recover + var/datum/component/mood/mood = owner.GetComponent(/datum/component/mood) + if(mood != null) + switch(mood.sanity_level) + if(SANITY_LEVEL_GREAT) + healing = 0.2 + if(SANITY_LEVEL_NEUTRAL) + healing = 0.1 + if(SANITY_LEVEL_DISTURBED) + healing = 0 + if(SANITY_LEVEL_UNSTABLE) + healing = 0 + if(SANITY_LEVEL_CRAZY) + healing = -0.1 + if(SANITY_LEVEL_INSANE) + healing = -0.2 + + var/turf/rest_turf = get_turf(owner) + var/is_sleeping_in_darkness = rest_turf.get_lumcount() <= LIGHTING_TILE_IS_DARK + + // sleeping with a blindfold or in the dark helps us rest + if(HAS_TRAIT_FROM(owner, TRAIT_BLIND, BLINDFOLD_TRAIT) || is_sleeping_in_darkness) + healing += 0.1 + + // sleeping with earmuffs helps blockout the noise as well + if(HAS_TRAIT_FROM(src, TRAIT_DEAF, CLOTHING_TRAIT)) + healing += 0.1 + + // check for beds if((locate(/obj/structure/bed) in owner.loc)) - healing -= 0.3 + healing += 0.2 else if((locate(/obj/structure/table) in owner.loc)) - healing -= 0.1 + healing += 0.1 + + // don't forget the bedsheet for(var/obj/item/bedsheet/bedsheet in range(owner.loc,0)) if(bedsheet.loc != owner.loc) //bedsheets in your backpack/neck don't give you comfort continue - healing -= 0.1 + healing += 0.1 break //Only count the first bedsheet - if(health_ratio > 0.8) - owner.adjustBruteLoss(healing) - owner.adjustFireLoss(healing) - owner.adjustToxLoss(healing * 0.5, TRUE, TRUE) - owner.adjustStaminaLoss(healing) - if(human_owner?.drunkenness) - human_owner.drunkenness *= 0.997 //reduce drunkenness by 0.3% per tick, 6% per 2 seconds - if(carbon_owner) + + if(healing > 0 && health_ratio > 0.8) + owner.adjustBruteLoss(-1 * healing) + owner.adjustFireLoss(-1 * healing) + owner.adjustToxLoss(-1 * healing * 0.5, TRUE, TRUE) + owner.adjustStaminaLoss(min(-1 * healing, -1 * HEALING_SLEEP_DEFAULT)) + // Drunkenness gets reduced by 0.3% per tick (6% per 2 seconds) + owner.set_drunk_effect(owner.get_drunk_amount() * 0.997) + + if(iscarbon(owner)) + var/mob/living/carbon/carbon_owner = owner carbon_owner.handle_dreams() + if(prob(2) && owner.health > owner.crit_threshold) owner.emote("snore") +#undef HEALING_SLEEP_DEFAULT + /atom/movable/screen/alert/status_effect/asleep name = "Asleep" desc = "You've fallen asleep. Wait a bit and you should wake up. Unless you don't, considering how helpless you are." @@ -239,7 +264,8 @@ ADD_TRAIT(owner, TRAIT_HANDS_BLOCKED, TRAIT_STATUS_EFFECT(id)) owner.add_filter("stasis_status_ripple", 2, list("type" = "ripple", "flags" = WAVE_BOUNDED, "radius" = 0, "size" = 2)) var/filter = owner.get_filter("stasis_status_ripple") - animate(filter, radius = 32, time = 15, size = 0, loop = -1) + animate(filter, radius = 0, time = 0.2 SECONDS, size = 2, easing = JUMP_EASING, loop = -1, flags = ANIMATION_PARALLEL) + animate(radius = 32, time = 1.5 SECONDS, size = 0) if(iscarbon(owner)) var/mob/living/carbon/carbon_owner = owner carbon_owner.update_bodypart_bleed_overlays() @@ -262,42 +288,6 @@ desc = "Your biological functions have halted. You could live forever this way, but it's pretty boring." icon_state = "stasis" -//GOLEM GANG - -//OTHER DEBUFFS -/datum/status_effect/strandling //get it, strand as in durathread strand + strangling = strandling hahahahahahahahahahhahahaha i want to die - id = "strandling" - examine_text = "SUBJECTPRONOUN seems to be being choked by some durathread strands. You may be able to cut them off." - status_type = STATUS_EFFECT_UNIQUE - alert_type = /atom/movable/screen/alert/status_effect/strandling - -/datum/status_effect/strandling/on_apply() - ADD_TRAIT(owner, TRAIT_MAGIC_CHOKE, STATUS_EFFECT_TRAIT) - return ..() - -/datum/status_effect/strandling/on_remove() - REMOVE_TRAIT(owner, TRAIT_MAGIC_CHOKE, STATUS_EFFECT_TRAIT) - return ..() - -/atom/movable/screen/alert/status_effect/strandling - name = "Choking strand" - desc = "A magical strand of Durathread is wrapped around your neck, preventing you from breathing! Click this icon to remove the strand." - icon_state = "his_grace" - alerttooltipstyle = "hisgrace" - -/atom/movable/screen/alert/status_effect/strandling/Click(location, control, params) - . = ..() - if(!.) - return - - to_chat(owner, span_notice("You attempt to remove the durathread strand from around your neck.")) - if(do_after(owner, 3.5 SECONDS, owner)) - if(isliving(owner)) - var/mob/living/living_owner = owner - to_chat(living_owner, span_notice("You succesfuly remove the durathread strand.")) - living_owner.remove_status_effect(/datum/status_effect/strandling) - -//OTHER DEBUFFS /datum/status_effect/pacify id = "pacify" status_type = STATUS_EFFECT_REPLACE @@ -524,21 +514,57 @@ /datum/status_effect/eldritch/blade/on_apply() . = ..() + RegisterSignal(owner, COMSIG_MOVABLE_PRE_THROW, .proc/on_pre_throw) RegisterSignal(owner, COMSIG_MOVABLE_TELEPORTED, .proc/on_teleport) RegisterSignal(owner, COMSIG_MOVABLE_MOVED, .proc/on_move) /datum/status_effect/eldritch/blade/on_remove() - UnregisterSignal(owner, list(COMSIG_MOVABLE_TELEPORTED, COMSIG_MOVABLE_MOVED)) + UnregisterSignal(owner, list( + COMSIG_MOVABLE_PRE_THROW, + COMSIG_MOVABLE_TELEPORTED, + COMSIG_MOVABLE_MOVED, + )) + return ..() -/// Signal proc for [COMSIG_MOVABLE_TELEPORTED] that blocks any teleports from our locked area -/datum/status_effect/eldritch/blade/proc/on_teleport(mob/living/source, atom/destination, channel) +/// Checks if the movement from moving_from to going_to leaves our [var/locked_to] area. Returns TRUE if so. +/datum/status_effect/eldritch/blade/proc/is_escaping_locked_area(atom/moving_from, atom/going_to) + if(!locked_to) + return FALSE + + // If moving_from isn't in our locked area, it means they've + // somehow completely escaped, so we'll opt not to act on them. + if(get_area(moving_from) != locked_to) + return FALSE + + // If going_to is in our locked area, + // they're just moving within the area like normal. + if(get_area(going_to) == locked_to) + return FALSE + + return TRUE + +/// Signal proc for [COMSIG_MOVABLE_PRE_THROW] that prevents people from escaping our locked area via throw. +/datum/status_effect/eldritch/blade/proc/on_pre_throw(mob/living/source, list/throw_args) SIGNAL_HANDLER - if(!locked_to) + var/atom/throw_dest = throw_args[1] + if(!is_escaping_locked_area(source, throw_dest)) return - if(get_area(destination) == locked_to) + var/mob/thrower = throw_args[4] + if(istype(thrower)) + to_chat(thrower, span_hypnophrase("An otherworldly force prevents you from throwing [source] out of [get_area_name(locked_to)]!")) + + to_chat(source, span_hypnophrase("An otherworldly force prevents you from being thrown out of [get_area_name(locked_to)]!")) + + return COMPONENT_CANCEL_THROW + +/// Signal proc for [COMSIG_MOVABLE_TELEPORTED] that blocks any teleports from our locked area. +/datum/status_effect/eldritch/blade/proc/on_teleport(mob/living/source, atom/destination, channel) + SIGNAL_HANDLER + + if(!is_escaping_locked_area(source, destination)) return to_chat(source, span_hypnophrase("An otherworldly force prevents your escape from [get_area_name(locked_to)]!")) @@ -550,32 +576,20 @@ /datum/status_effect/eldritch/blade/proc/on_move(mob/living/source, turf/old_loc, movement_dir, forced) SIGNAL_HANDLER - if(!locked_to) + // Let's not mess with heretics dragging a potential victim. + if(ismob(source.pulledby) && IS_HERETIC(source.pulledby)) return - if(get_area(source) == locked_to) + // If the movement's forced, just let it happen regardless. + if(forced || !is_escaping_locked_area(old_loc, source)) return to_chat(source, span_hypnophrase("An otherworldly force prevents your escape from [get_area_name(locked_to)]!")) - source.Stun(1 SECONDS) - source.throw_at(old_loc, 5, 1) + var/turf/further_behind_old_loc = get_edge_target_turf(old_loc, REVERSE_DIR(movement_dir)) -/// A status effect used for specifying confusion on a living mob. -/// Created automatically with /mob/living/set_confusion. -/datum/status_effect/confusion - id = "confusion" - alert_type = null - var/strength - -/datum/status_effect/confusion/tick() - strength -= 1 - if (strength <= 0) - owner.remove_status_effect(/datum/status_effect/confusion) - return - -/datum/status_effect/confusion/proc/set_strength(new_strength) - strength = new_strength + source.Stun(1 SECONDS) + source.throw_at(further_behind_old_loc, 3, 1, gentle = TRUE) // Keeping this gentle so they don't smack into the heretic max speed /datum/status_effect/stacking/saw_bleed id = "saw_bleed" @@ -744,7 +758,6 @@ status_type = STATUS_EFFECT_UNIQUE duration = 300 tick_interval = 10 - examine_text = span_warning("SUBJECTPRONOUN seems slow and unfocused.") var/stun = TRUE alert_type = /atom/movable/screen/alert/status_effect/trance @@ -755,8 +768,8 @@ /datum/status_effect/trance/tick() if(stun) - owner.Stun(60, TRUE) - owner.dizziness = 20 + owner.Stun(6 SECONDS, TRUE) + owner.set_timed_status_effect(40 SECONDS, /datum/status_effect/dizziness) /datum/status_effect/trance/on_apply() if(!iscarbon(owner)) @@ -776,10 +789,13 @@ /datum/status_effect/trance/on_remove() UnregisterSignal(owner, COMSIG_MOVABLE_HEAR) REMOVE_TRAIT(owner, TRAIT_MUTE, STATUS_EFFECT_TRAIT) - owner.dizziness = 0 + owner.remove_status_effect(/datum/status_effect/dizziness) owner.remove_client_colour(/datum/client_colour/monochrome/trance) to_chat(owner, span_warning("You snap out of your trance!")) +/datum/status_effect/trance/get_examine_text() + return span_warning("[owner.p_they(TRUE)] seem[owner.p_s()] slow and unfocused.") + /datum/status_effect/trance/proc/hypnotize(datum/source, list/hearing_args) SIGNAL_HANDLER @@ -869,8 +885,11 @@ if(prob(40)) var/obj/item/I = H.get_active_held_item() if(I && H.dropItemToGround(I)) - H.visible_message(span_notice("[H]'s hand convulses, and they drop their [I.name]!"),span_userdanger("Your hand convulses violently, and you drop what you were holding!")) - H.jitteriness += 5 + H.visible_message( + span_notice("[H]'s hand convulses, and they drop their [I.name]!"), + span_userdanger("Your hand convulses violently, and you drop what you were holding!"), + ) + H.adjust_timed_status_effect(10 SECONDS, /datum/status_effect/jitter) /atom/movable/screen/alert/status_effect/convulsing name = "Shaky Hands" @@ -989,8 +1008,8 @@ if(0 to 10) human_owner.vomit() if(20 to 30) - human_owner.Dizzy(50) - human_owner.Jitter(50) + human_owner.set_timed_status_effect(100 SECONDS, /datum/status_effect/dizziness, only_if_higher = TRUE) + human_owner.set_timed_status_effect(100 SECONDS, /datum/status_effect/jitter, only_if_higher = TRUE) if(30 to 40) human_owner.adjustOrganLoss(ORGAN_SLOT_LIVER, 5) if(40 to 50) @@ -1006,7 +1025,7 @@ if(90 to 95) human_owner.adjustOrganLoss(ORGAN_SLOT_BRAIN, 20, 190) if(95 to 100) - human_owner.add_confusion(12) + human_owner.adjust_timed_status_effect(12 SECONDS, /datum/status_effect/confusion) /datum/status_effect/amok id = "amok" @@ -1073,7 +1092,6 @@ status_type = STATUS_EFFECT_REFRESH alert_type = /atom/movable/screen/alert/status_effect/ants duration = 2 MINUTES //Keeping the normal timer makes sure people can't somehow dump 300+ ants on someone at once so they stay there for like 30 minutes. Max w/ 1 dump is 57.6 brute. - examine_text = span_warning("SUBJECTPRONOUN is covered in ants!") processing_speed = STATUS_EFFECT_NORMAL_PROCESS /// Will act as the main timer as well as changing how much damage the ants do. var/ants_remaining = 0 @@ -1117,6 +1135,9 @@ owner.remove_status_effect(/datum/status_effect/ants) return COMPONENT_CLEANED +/datum/status_effect/ants/get_examine_text() + return span_warning("[owner.p_they(TRUE)] [owner.p_are()] covered in ants!") + /datum/status_effect/ants/tick() var/mob/living/carbon/human/victim = owner victim.adjustBruteLoss(max(0.1, round((ants_remaining * 0.004),0.1))) //Scales with # of ants (lowers with time). Roughly 10 brute over 50 seconds. diff --git a/code/datums/status_effects/debuffs/dizziness.dm b/code/datums/status_effects/debuffs/dizziness.dm new file mode 100644 index 0000000000000..2ee73cef442a1 --- /dev/null +++ b/code/datums/status_effects/debuffs/dizziness.dm @@ -0,0 +1,77 @@ +/datum/status_effect/dizziness + id = "dizziness" + tick_interval = 2 SECONDS + alert_type = null + +/datum/status_effect/dizziness/on_creation(mob/living/new_owner, duration = 10 SECONDS) + src.duration = duration + return ..() + +/datum/status_effect/dizziness/on_apply() + RegisterSignal(owner, list(COMSIG_LIVING_POST_FULLY_HEAL, COMSIG_LIVING_DEATH), .proc/clear_dizziness) + return TRUE + +/datum/status_effect/dizziness/on_remove() + UnregisterSignal(owner, list(COMSIG_LIVING_POST_FULLY_HEAL, COMSIG_LIVING_DEATH)) + // In case our client's offset is somewhere wacky from the dizziness effect + owner.client?.pixel_x = initial(owner.client?.pixel_x) + owner.client?.pixel_y = initial(owner.client?.pixel_y) + +/// Signal proc that self deletes our dizziness effect +/datum/status_effect/dizziness/proc/clear_dizziness(datum/source) + SIGNAL_HANDLER + + qdel(src) + +/datum/status_effect/dizziness/tick() + // How much time is left, in seconds + var/amount = (duration - world.time) / 10 + if(amount <= 0) + return + + // How strong the dizziness effect is on us. + // If we're resting, the effect is 5x as strong, but also decays 5x fast. + // Meaning effectively, 1 tick is actually dizziness_strength ticks of duration + var/dizziness_strength = owner.resting ? 5 : 1 + var/time_between_ticks = initial(tick_interval) + + // How much time will be left, in seconds, next tick + var/next_amount = max((amount - (dizziness_strength * time_between_ticks * 0.1)), 0) + + // If we have a dizziness strength > 1, we will subtract ticks off of the total duration + duration -= ((dizziness_strength - 1) * time_between_ticks) + + // Now we can do the actual dizzy effects. + // Don't bother animating if they're clientless. + if(!owner.client) + return + + // Want to be able to offset things by the time the animation should be "playing" at + var/time = world.time + var/delay = 0 + var/pixel_x_diff = 0 + var/pixel_y_diff = 0 + + // This shit is annoying at high strengthvar/pixel_x_diff = 0 + var/list/view_range_list = getviewsize(owner.client.view) + var/view_range = view_range_list[1] + var/amplitude = amount * (sin(amount * (time)) + 1) + var/x_diff = clamp(amplitude * sin(amount * time), -view_range, view_range) + var/y_diff = clamp(amplitude * cos(amount * time), -view_range, view_range) + pixel_x_diff += x_diff + pixel_y_diff += y_diff + // Brief explanation. We're basically snapping between different pixel_x/ys instantly, with delays between + // Doing this with relative changes. This way we don't override any existing pixel_x/y values + // We use EASE_OUT here for similar reasons, we want to act at the end of the delay, not at its start + // Relative animations are weird, so we do actually need this + animate(owner.client, pixel_x = x_diff, pixel_y = y_diff, 3, easing = JUMP_EASING | EASE_OUT, flags = ANIMATION_RELATIVE) + delay += 0.3 SECONDS // This counts as a 0.3 second wait, so we need to shift the sine wave by that much + + x_diff = amplitude * sin(next_amount * (time + delay)) + y_diff = amplitude * cos(next_amount * (time + delay)) + pixel_x_diff += x_diff + pixel_y_diff += y_diff + animate(pixel_x = x_diff, pixel_y = y_diff, 3, easing = JUMP_EASING | EASE_OUT, flags = ANIMATION_RELATIVE) + + // Now we reset back to our old pixel_x/y, since these animates are relative + animate(pixel_x = -pixel_x_diff, pixel_y = -pixel_y_diff, 3, easing = JUMP_EASING | EASE_OUT, flags = ANIMATION_RELATIVE) diff --git a/code/datums/status_effects/debuffs/drunk.dm b/code/datums/status_effects/debuffs/drunk.dm new file mode 100644 index 0000000000000..7a7192d8a8368 --- /dev/null +++ b/code/datums/status_effects/debuffs/drunk.dm @@ -0,0 +1,223 @@ +// Defines for the ballmer peak. +#define BALLMER_PEAK_LOW_END 12.9 +#define BALLMER_PEAK_HIGH_END 13.8 +#define BALLMER_PEAK_WINDOWS_ME 26 + +/// The threshld which determine if someone is tipsy vs drunk +#define TIPSY_THRESHOLD 6 + +/** + * The drunk status effect. + * Slowly decreases in drunk_value over time, causing effects based on that value. + */ +/datum/status_effect/inebriated + id = "drunk" + tick_interval = 2 SECONDS + status_type = STATUS_EFFECT_REPLACE + /// The level of drunkness we are currently at. + var/drunk_value = 0 + +/datum/status_effect/inebriated/on_creation(mob/living/new_owner, drunk_value = 0) + . = ..() + set_drunk_value(drunk_value) + +/datum/status_effect/inebriated/on_apply() + RegisterSignal(owner, COMSIG_LIVING_POST_FULLY_HEAL, .proc/clear_drunkenness) + return TRUE + +/datum/status_effect/inebriated/on_remove() + UnregisterSignal(owner, COMSIG_LIVING_POST_FULLY_HEAL) + +/datum/status_effect/inebriated/get_examine_text() + // Dead people don't look drunk + if(owner.stat == DEAD || HAS_TRAIT(owner, TRAIT_FAKEDEATH)) + return null + + // Having your face covered conceals your drunkness + if(iscarbon(owner)) + var/mob/living/carbon/carbon_owner = owner + if(carbon_owner.wear_mask?.flags_inv & HIDEFACE) + return null + if(carbon_owner.head?.flags_inv & HIDEFACE) + return null + + // .01s are used in case the drunk value ends up to be a small decimal. + switch(drunk_value) + if(11 to 21) + return span_warning("[owner.p_they(TRUE)] [owner.p_are()] slightly flushed.") + if(21.01 to 41) + return span_warning("[owner.p_they(TRUE)] [owner.p_are()] flushed.") + if(41.01 to 51) + return span_warning("[owner.p_they(TRUE)] [owner.p_are()] quite flushed and [owner.p_their()] breath smells of alcohol.") + if(51.01 to 61) + return span_warning("[owner.p_they(TRUE)] [owner.p_are()] very flushed and [owner.p_their()] movements jerky, with breath reeking of alcohol.") + if(61.01 to 91) + return span_warning("[owner.p_they(TRUE)] look[owner.p_s()] like a drunken mess.") + if(91.01 to INFINITY) + return span_warning("[owner.p_they(TRUE)] [owner.p_are()] a shitfaced, slobbering wreck.") + + return null + +/// Removes all of our drunkenness (self-deletes) on signal. +/datum/status_effect/inebriated/proc/clear_drunkenness(mob/living/source) + SIGNAL_HANDLER + + qdel(src) + +/// Sets the drunk value to set_to, deleting if the value drops to 0 or lower +/datum/status_effect/inebriated/proc/set_drunk_value(set_to) + if(!isnum(set_to)) + CRASH("[type] - invalid value passed to set_drunk_value. (Got: [set_to])") + + drunk_value = set_to + if(drunk_value <= 0) + qdel(src) + +/datum/status_effect/inebriated/tick() + // Drunk value does not decrease while dead + if(owner.stat == DEAD) + return + + // Every tick, the drunk value decrases by + // 4% the current drunk_value + 0.01 + // (until it reaches 0 and terminates) + set_drunk_value(drunk_value - (0.01 + drunk_value * 0.04)) + if(QDELETED(src)) + return + + on_tick_effects() + +/// Side effects done by this level of drunkness on tick. +/datum/status_effect/inebriated/proc/on_tick_effects() + return + +/** + * Stage 1 of drunk, applied at drunk values between 0 and 6. + * Basically is the "drunk but no side effects" stage. + */ +/datum/status_effect/inebriated/tipsy + alert_type = null + +/datum/status_effect/inebriated/tipsy/set_drunk_value(set_to) + . = ..() + if(QDELETED(src)) + return + + // Become fully drunk at over than 6 drunk value + if(drunk_value >= TIPSY_THRESHOLD) + owner.apply_status_effect(/datum/status_effect/inebriated/drunk, drunk_value) + +/** + * Stage 2 of being drunk, applied at drunk values between 6 and onward. + * Has all the main side effects of being drunk, scaling up as they get more drunk. + */ +/datum/status_effect/inebriated/drunk + alert_type = /atom/movable/screen/alert/status_effect/drunk + +/datum/status_effect/inebriated/drunk/on_apply() + . = ..() + owner.sound_environment_override = SOUND_ENVIRONMENT_PSYCHOTIC + SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, id, /datum/mood_event/drunk) + +/datum/status_effect/inebriated/drunk/on_remove() + clear_effects() + return ..() + +// Going from "drunk" to "tipsy" should remove effects like on_remove +/datum/status_effect/inebriated/drunk/be_replaced() + clear_effects() + return ..() + +/// Clears any side effects we set due to being drunk. +/datum/status_effect/inebriated/drunk/proc/clear_effects() + SEND_SIGNAL(owner, COMSIG_CLEAR_MOOD_EVENT, id) + + if(owner.sound_environment_override == SOUND_ENVIRONMENT_PSYCHOTIC) + owner.sound_environment_override = SOUND_ENVIRONMENT_NONE + +/datum/status_effect/inebriated/drunk/set_drunk_value(set_to) + . = ..() + if(QDELETED(src)) + return + + // Return to "tipsyness" when we're below 6. + if(drunk_value < TIPSY_THRESHOLD) + owner.apply_status_effect(/datum/status_effect/inebriated/tipsy, drunk_value) + +/datum/status_effect/inebriated/drunk/on_tick_effects() + // Handle the Ballmer Peak. + // If our owner is a scientist (has the trait "TRAIT_BALLMER_SCIENTIST"), there's a 5% chance + // that they'll say one of the special "ballmer message" lines, depending their drunk-ness level. + if(HAS_TRAIT(owner, TRAIT_BALLMER_SCIENTIST) && prob(5)) + if(drunk_value >= BALLMER_PEAK_LOW_END && drunk_value <= BALLMER_PEAK_HIGH_END) + owner.say(pick_list_replacements(VISTA_FILE, "ballmer_good_msg"), forced = "ballmer") + + if(drunk_value > BALLMER_PEAK_WINDOWS_ME) // by this point you're into windows ME territory + owner.say(pick_list_replacements(VISTA_FILE, "ballmer_windows_me_msg"), forced = "ballmer") + + // There's always a 30% chance to gain some drunken slurring + if(prob(30)) + owner.adjust_timed_status_effect(4 SECONDS, /datum/status_effect/speech/slurring/drunk) + + // And drunk people will always lose jitteriness + owner.adjust_timed_status_effect(-6 SECONDS, /datum/status_effect/jitter) + + // Over 11, we will constantly gain slurring up to 10 seconds of slurring. + if(drunk_value >= 11) + owner.adjust_timed_status_effect(2.4 SECONDS, /datum/status_effect/speech/slurring/drunk, max_duration = 10 SECONDS) + + // Over 41, we have a 30% chance to gain confusion, and we will always have 20 seconds of dizziness. + if(drunk_value >= 41) + if(prob(30)) + owner.adjust_timed_status_effect(2 SECONDS, /datum/status_effect/confusion) + + owner.set_timed_status_effect(20 SECONDS, /datum/status_effect/dizziness, only_if_higher = TRUE) + + // Over 51, we have a 3% chance to gain a lot of confusion and vomit, and we will always have 50 seconds of dizziness + if(drunk_value >= 51) + owner.set_timed_status_effect(50 SECONDS, /datum/status_effect/dizziness, only_if_higher = TRUE) + if(prob(3)) + owner.adjust_timed_status_effect(15 SECONDS, /datum/status_effect/confusion) + if(iscarbon(owner)) + var/mob/living/carbon/carbon_owner = owner + carbon_owner.vomit() // Vomiting clears toxloss - consider this a blessing + + // Over 71, we will constantly have blurry eyes + if(drunk_value >= 71) + owner.blur_eyes(drunk_value - 70) + + // Over 81, we will gain constant toxloss + if(drunk_value >= 81) + owner.adjustToxLoss(1) + if(owner.stat == CONSCIOUS && prob(5)) + to_chat(owner, span_warning("Maybe you should lie down for a bit...")) + + // Over 91, we gain even more toxloss, brain damage, and have a chance of dropping into a long sleep + if(drunk_value >= 91) + owner.adjustToxLoss(1) + owner.adjustOrganLoss(ORGAN_SLOT_BRAIN, 0.4) + if(owner.stat == CONSCIOUS && prob(20)) + // Don't put us in a deep sleep if the shuttle's here. QoL, mainly. + if(SSshuttle.emergency.mode == SHUTTLE_DOCKED && is_station_level(owner.z)) + to_chat(owner, span_warning("You're so tired... but you can't miss that shuttle...")) + + else + to_chat(owner, span_warning("Just a quick nap...")) + owner.Sleeping(90 SECONDS) + + // And finally, over 100 - let's be honest, you shouldn't be alive by now. + if(drunk_value >= 101) + owner.adjustToxLoss(2) + +/// Status effect for being fully drunk (not tipsy). +/atom/movable/screen/alert/status_effect/drunk + name = "Drunk" + desc = "All that alcohol you've been drinking is impairing your speech, \ + motor skills, and mental cognition. Make sure to act like it." + icon_state = "drunk" + +#undef BALLMER_PEAK_LOW_END +#undef BALLMER_PEAK_HIGH_END +#undef BALLMER_PEAK_WINDOWS_ME + +#undef TIPSY_THRESHOLD diff --git a/code/datums/status_effects/debuffs/fire_stacks.dm b/code/datums/status_effects/debuffs/fire_stacks.dm new file mode 100644 index 0000000000000..598f38d3adfd3 --- /dev/null +++ b/code/datums/status_effects/debuffs/fire_stacks.dm @@ -0,0 +1,266 @@ +/datum/status_effect/fire_handler + duration = -1 + alert_type = null + status_type = STATUS_EFFECT_REFRESH //Custom code + on_remove_on_mob_delete = TRUE + tick_interval = 2 SECONDS + /// Current amount of stacks we have + var/stacks + /// Maximum of stacks that we could possibly get + var/stack_limit = 20 + /// What status effect types do we remove uppon being applied. These are just deleted without any deduction from our or their stacks when forced. + var/list/enemy_types + /// What status effect types do we merge into if they exist. Ignored when forced. + var/list/merge_types + /// What status effect types do we override if they exist. These are simply deleted when forced. + var/list/override_types + /// For how much firestacks does one our stack count + var/stack_modifier = 1 + +/datum/status_effect/fire_handler/refresh(mob/living/new_owner, new_stacks, forced = FALSE) + if(forced) + set_stacks(new_stacks) + else + adjust_stacks(new_stacks) + +/datum/status_effect/fire_handler/on_creation(mob/living/new_owner, new_stacks, forced = FALSE) + . = ..() + + if(isanimal(owner)) + qdel(src) + return + + owner = new_owner + set_stacks(new_stacks) + + for(var/enemy_type in enemy_types) + var/datum/status_effect/fire_handler/enemy_effect = owner.has_status_effect(enemy_type) + if(enemy_effect) + if(forced) + qdel(enemy_effect) + continue + + var/cur_stacks = stacks + adjust_stacks(-enemy_effect.stacks * enemy_effect.stack_modifier / stack_modifier) + enemy_effect.adjust_stacks(-cur_stacks * stack_modifier / enemy_effect.stack_modifier) + if(enemy_effect.stacks <= 0) + qdel(enemy_effect) + + if(stacks <= 0) + qdel(src) + return + + if(!forced) + var/list/merge_effects = list() + for(var/merge_type in merge_types) + var/datum/status_effect/fire_handler/merge_effect = owner.has_status_effect(merge_type) + if(merge_effect) + merge_effects += merge_effects + + if(LAZYLEN(merge_effects)) + for(var/datum/status_effect/fire_handler/merge_effect in merge_effects) + merge_effect.adjust_stacks(stacks * stack_modifier / merge_effect.stack_modifier / LAZYLEN(merge_effects)) + qdel(src) + return + + for(var/override_type in override_types) + var/datum/status_effect/fire_handler/override_effect = owner.has_status_effect(override_type) + if(override_effect) + if(forced) + qdel(override_effect) + continue + + adjust_stacks(override_effect.stacks) + qdel(override_effect) + +/** + * Setter and adjuster procs for firestacks + * + * Arguments: + * - new_stacks + * + */ + +/datum/status_effect/fire_handler/proc/set_stacks(new_stacks) + stacks = max(0, min(stack_limit, new_stacks)) + cache_stacks() + +/datum/status_effect/fire_handler/proc/adjust_stacks(new_stacks) + stacks = max(0, min(stack_limit, stacks + new_stacks)) + cache_stacks() + +/** + * Refresher for mob's fire_stacks + */ + +/datum/status_effect/fire_handler/proc/cache_stacks() + owner.fire_stacks = 0 + var/was_on_fire = owner.on_fire + owner.on_fire = FALSE + for(var/datum/status_effect/fire_handler/possible_fire in owner.status_effects) + owner.fire_stacks += possible_fire.stacks * possible_fire.stack_modifier + + if(!istype(possible_fire, /datum/status_effect/fire_handler/fire_stacks)) + continue + + var/datum/status_effect/fire_handler/fire_stacks/our_fire = possible_fire + if(our_fire.on_fire) + owner.on_fire = TRUE + + if(was_on_fire && !owner.on_fire) + owner.clear_alert(ALERT_FIRE) + else if(!was_on_fire && owner.on_fire) + owner.throw_alert(ALERT_FIRE, /atom/movable/screen/alert/fire) + +/** + * Used to update owner's effect overlay + */ + +/datum/status_effect/fire_handler/proc/update_overlay() + +/datum/status_effect/fire_handler/fire_stacks + id = "fire_stacks" //fire_stacks and wet_stacks should have different IDs or else has_status_effect won't work + + enemy_types = list(/datum/status_effect/fire_handler/wet_stacks) + stack_modifier = 1 + + /// If we're on fire + var/on_fire = FALSE + /// A weakref to the mob light emitter + var/datum/weakref/firelight_ref + /// Type of mob light emitter we use when on fire + var/firelight_type = /obj/effect/dummy/lighting_obj/moblight/fire + /// Stores current fire overlay icon state, for optimisation purposes + var/last_icon_state + +/datum/status_effect/fire_handler/fire_stacks/tick(delta_time, times_fired) + if(stacks <= 0) + qdel(src) + return TRUE + + if(!on_fire || isanimal(owner)) + return TRUE + + if(iscyborg(owner)) + adjust_stacks(-0.55 * delta_time) + else + adjust_stacks(-0.05 * delta_time) + + if(stacks <= 0) + qdel(src) + return TRUE + + var/datum/gas_mixture/air = owner.loc.return_air() + if(!air.gases[/datum/gas/oxygen] || air.gases[/datum/gas/oxygen][MOLES] < 1) + qdel(src) + return TRUE + + deal_damage(delta_time, times_fired) + update_overlay() + +/** + * Proc that handles damage dealing and all special effects + * + * Arguments: + * - delta_time + * - times_fired + * + */ + +/datum/status_effect/fire_handler/fire_stacks/proc/deal_damage(delta_time, times_fired) + owner.on_fire_stack(delta_time, times_fired, src) + + var/turf/location = get_turf(owner) + location.hotspot_expose(700, 25 * delta_time, TRUE) + +/** + * Used to deal damage to humans and count their protection. + * + * Arguments: + * - delta_time + * - times_fired + * - no_protection: When set to TRUE, fire will ignore any possible fire protection + * + */ + +/datum/status_effect/fire_handler/fire_stacks/proc/harm_human(delta_time, times_fired, no_protection = FALSE) + var/mob/living/carbon/human/victim = owner + var/thermal_protection = victim.get_thermal_protection() + + if(thermal_protection >= FIRE_IMMUNITY_MAX_TEMP_PROTECT && !no_protection) + return + + if(thermal_protection >= FIRE_SUIT_MAX_TEMP_PROTECT && !no_protection) + victim.adjust_bodytemperature(5.5 * delta_time) + return + + victim.adjust_bodytemperature((BODYTEMP_HEATING_MAX + (stacks * 12)) * 0.5 * delta_time) + SEND_SIGNAL(victim, COMSIG_ADD_MOOD_EVENT, "on_fire", /datum/mood_event/on_fire) + victim.mind?.add_memory(MEMORY_FIRE, list(DETAIL_PROTAGONIST = victim), story_value = STORY_VALUE_OKAY) + +/** + * Handles mob ignition, should be the only way to set on_fire to TRUE + * + * Arguments: + * - silent: When set to TRUE, no message is displayed + * + */ + +/datum/status_effect/fire_handler/fire_stacks/proc/ignite(silent = FALSE) + if(HAS_TRAIT(owner, TRAIT_NOFIRE)) + return FALSE + + on_fire = TRUE + if(!silent) + owner.visible_message(span_warning("[owner] catches fire!"), span_userdanger("You're set on fire!")) + + if(firelight_type) + firelight_ref = WEAKREF(new firelight_type(owner)) + + SEND_SIGNAL(owner, COMSIG_LIVING_IGNITED, owner) + cache_stacks() + update_overlay() + +/** + * Handles mob extinguishing, should be the only way to set on_fire to FALSE + */ + +/datum/status_effect/fire_handler/fire_stacks/proc/extinguish() + if(firelight_ref) + qdel(firelight_ref) + + on_fire = FALSE + SEND_SIGNAL(owner, COMSIG_CLEAR_MOOD_EVENT, "on_fire") + SEND_SIGNAL(owner, COMSIG_LIVING_EXTINGUISHED, owner) + cache_stacks() + update_overlay() + if(!iscarbon(owner)) + return + + for(var/obj/item/equipped in owner.get_equipped_items()) + equipped.wash(CLEAN_TYPE_ACID) + equipped.extinguish() + +/datum/status_effect/fire_handler/fire_stacks/on_remove() + if(on_fire) + extinguish() + set_stacks(0) + update_overlay() + +/datum/status_effect/fire_handler/fire_stacks/update_overlay() + last_icon_state = owner.update_fire_overlay(stacks, on_fire, last_icon_state) + +/datum/status_effect/fire_handler/fire_stacks/on_apply() + . = ..() + update_overlay() + +/datum/status_effect/fire_handler/wet_stacks + id = "wet_stacks" + + enemy_types = list(/datum/status_effect/fire_handler/fire_stacks) + stack_modifier = -1 + +/datum/status_effect/fire_handler/wet_stacks/tick(delta_time) + adjust_stacks(-0.5 * delta_time) + if(stacks <= 0) + qdel(src) diff --git a/code/datums/status_effects/debuffs/jitteriness.dm b/code/datums/status_effects/debuffs/jitteriness.dm new file mode 100644 index 0000000000000..d97748b43fc1f --- /dev/null +++ b/code/datums/status_effects/debuffs/jitteriness.dm @@ -0,0 +1,55 @@ +/datum/status_effect/jitter + id = "jitter" + tick_interval = 2 SECONDS + alert_type = null + +/datum/status_effect/jitter/on_creation(mob/living/new_owner, duration = 10 SECONDS) + src.duration = duration + return ..() + +/datum/status_effect/jitter/on_apply() + RegisterSignal(owner, list(COMSIG_LIVING_POST_FULLY_HEAL, COMSIG_LIVING_DEATH), .proc/remove_jitter) + SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, id, /datum/mood_event/jittery) + return TRUE + +/datum/status_effect/jitter/on_remove() + UnregisterSignal(owner, list(COMSIG_LIVING_POST_FULLY_HEAL, COMSIG_LIVING_DEATH)) + SEND_SIGNAL(owner, COMSIG_CLEAR_MOOD_EVENT, id) + // juuust in case, reset our x and y's from our jittering + owner.pixel_x = 0 + owner.pixel_y = 0 + +/datum/status_effect/jitter/get_examine_text() + switch(duration - world.time) + if(5 MINUTES to INFINITY) + return span_boldwarning("[owner.p_they(TRUE)] [owner.p_are()] convulsing violently!") + if(3 MINUTES to 5 MINUTES) + return span_warning("[owner.p_they(TRUE)] [owner.p_are()] extremely jittery.") + if(1 MINUTES to 3 MINUTES) + return span_warning("[owner.p_they(TRUE)] [owner.p_are()] twitching ever so slightly.") + + return null + +/// Removes all of our jitteriness on a signal +/datum/status_effect/jitter/proc/remove_jitter(datum/source) + SIGNAL_HANDLER + + qdel(src) + +/datum/status_effect/jitter/tick() + + var/time_left_in_seconds = (duration - world.time) / 10 + owner.do_jitter_animation(time_left_in_seconds) + + // Decrease the duration by our resting_modifier, effectively skipping resting_modifier ticks per tick + var/resting_modifier = owner.resting ? 5 : 1 + duration -= ((resting_modifier - 1) * initial(tick_interval)) + +/// Helper proc that causes the mob to do a jittering animation by jitter_amount. +/// jitter_amount will only apply up to 300 (maximum jitter effect). +/mob/living/proc/do_jitter_animation(jitter_amount = 100) + var/amplitude = min(4, (jitter_amount / 100) + 1) + var/pixel_x_diff = rand(-amplitude, amplitude) + var/pixel_y_diff = rand(-amplitude / 3, amplitude / 3) + animate(src, pixel_x = pixel_x_diff, pixel_y = pixel_y_diff , time = 0.2 SECONDS, loop = 6, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) + animate(pixel_x = -pixel_x_diff , pixel_y = -pixel_y_diff , time = 0.2 SECONDS, flags = ANIMATION_RELATIVE) diff --git a/code/datums/status_effects/debuffs/strandling.dm b/code/datums/status_effects/debuffs/strandling.dm new file mode 100644 index 0000000000000..9dc9ede90d663 --- /dev/null +++ b/code/datums/status_effects/debuffs/strandling.dm @@ -0,0 +1,106 @@ +/// A multiplier to the time it takes to remove durathread strangling when using a tool instead of your hands +#define STRANGLING_TOOL_MULTIPLIER 0.4 + +//get it, strand as in durathread strand + strangling = strandling hahahahahahahahahahhahahaha i want to die +/datum/status_effect/strandling + id = "strandling" + status_type = STATUS_EFFECT_UNIQUE + alert_type = /atom/movable/screen/alert/status_effect/strandling + /// How long it takes to remove the status effect via [proc/try_remove_effect] + var/time_to_remove = 3.5 SECONDS + +/datum/status_effect/strandling/on_apply() + RegisterSignal(owner, COMSIG_CARBON_PRE_BREATHE, .proc/on_breathe) + RegisterSignal(owner, COMSIG_ATOM_TOOL_ACT(TOOL_WIRECUTTER), .proc/on_cut) + RegisterSignal(owner, COMSIG_CARBON_PRE_HELP_ACT, .proc/on_self_check) + return TRUE + +/datum/status_effect/strandling/on_remove() + UnregisterSignal(owner, list(COMSIG_CARBON_PRE_BREATHE, COMSIG_ATOM_TOOL_ACT(TOOL_WIRECUTTER), COMSIG_CARBON_PRE_HELP_ACT)) + +/datum/status_effect/strandling/get_examine_text() + return span_warning("[owner.p_they(TRUE)] seem[owner.p_s()] to be being choked by some durathread strands. You may be able to cut them off.") + +/// Signal proc for [COMSIG_CARBON_PRE_BREATHE], causes losebreath whenever we're trying to breathe +/datum/status_effect/strandling/proc/on_breathe(mob/living/source) + SIGNAL_HANDLER + + if(source.getorganslot(ORGAN_SLOT_BREATHING_TUBE)) + return + + source.losebreath++ + +/// Signal proc for [COMSIG_ATOM_TOOL_ACT] with [TOOL_WIRECUTTER], allowing wirecutters to remove the effect (from others / themself) +/datum/status_effect/strandling/proc/on_cut(mob/living/source, mob/user, obj/item/tool) + SIGNAL_HANDLER + + if(DOING_INTERACTION(user, REF(src))) + return + + INVOKE_ASYNC(src, .proc/try_remove_effect, user, tool) + return COMPONENT_BLOCK_TOOL_ATTACK + +/// Signal proc for [COMSIG_CARBON_PRE_HELP_ACT], allowing someone to remove the effect by hand +/datum/status_effect/strandling/proc/on_self_check(mob/living/carbon/source, mob/living/helper) + SIGNAL_HANDLER + + if(DOING_INTERACTION(helper, REF(src))) + return + + INVOKE_ASYNC(src, .proc/try_remove_effect, helper) + return COMPONENT_BLOCK_HELP_ACT + +/** + * Attempts a do_after to remove the effect and stop the strangling. + * + * user - the mob attempting to remove the strangle. Can be the same as the owner. + * tool - the tool the user's using to remove the strange. Can be null. + */ +/datum/status_effect/strandling/proc/try_remove_effect(mob/user, obj/item/tool) + if(user.incapacitated() || HAS_TRAIT(user, TRAIT_HANDS_BLOCKED)) + return + + user.visible_message( + span_notice("[user] attempts to [tool ? "cut":"remove"] the strand from around [owner == user ? "[owner.p_their()]":"[owner]'s"] neck..."), + span_notice("You attempt to [tool ? "cut":"remove"] the strand from around [owner == user ? "your":"[owner]'s"] neck..."), + ) + + // Play a sound if we have a tool + tool?.play_tool_sound(owner) + + // Now try to remove the effect with a doafter. If we have a tool, we'll even remove it 60% faster. + if(!do_mob(user, owner, time_to_remove * (tool ? STRANGLING_TOOL_MULTIPLIER : 1), interaction_key = REF(src))) + to_chat(user, span_warning("You fail to [tool ? "cut":"remove"] the strand from around [owner == user ? "your":"[owner]'s"] neck!")) + return FALSE + + // Play another sound after we're done + tool?.play_tool_sound(owner) + + user.visible_message( + span_notice("[user] successfully [tool ? "cut":"remove"] the strand from around [owner == user ? "[owner.p_their()]":"[owner]'s"] neck."), + span_notice("You successfully [tool ? "cut":"remove"] the strand from around [owner == user ? "your":"[owner]'s"] neck."), + ) + qdel(src) + return TRUE + +/atom/movable/screen/alert/status_effect/strandling + name = "Choking strand" + desc = "Strands of Durathread are wrapped around your neck, preventing you from breathing! Click this icon to remove the strand." + icon_state = "his_grace" + alerttooltipstyle = "hisgrace" + +/atom/movable/screen/alert/status_effect/strandling/Click(location, control, params) + . = ..() + if(!.) + return + + if(!isliving(owner)) + return + + var/datum/status_effect/strandling/strangle_effect = attached_effect + if(!istype(strangle_effect)) + return + + strangle_effect.try_remove_effect(owner) + +#undef STRANGLING_TOOL_MULTIPLIER diff --git a/code/datums/status_effects/drug_effects.dm b/code/datums/status_effects/drug_effects.dm index 224182f16e3a3..6f6232adc2186 100644 --- a/code/datums/status_effects/drug_effects.dm +++ b/code/datums/status_effects/drug_effects.dm @@ -4,16 +4,14 @@ status_type = STATUS_EFFECT_UNIQUE alert_type = /atom/movable/screen/alert/status_effect/woozy - /datum/status_effect/woozy/nextmove_modifier() return 1.5 /atom/movable/screen/alert/status_effect/woozy name = "Woozy" - desc = "You feel a bit slower than usual, it seems doing things with your hands takes longer than it usually does" + desc = "You feel a bit slower than usual, it seems doing things with your hands takes longer than it usually does." icon_state = "woozy" - /datum/status_effect/high_blood_pressure id = "high_blood_pressure" tick_interval = -1 @@ -21,22 +19,25 @@ alert_type = /atom/movable/screen/alert/status_effect/high_blood_pressure /datum/status_effect/high_blood_pressure/on_apply() - if(ishuman(owner)) - var/mob/living/carbon/human/human_owner = owner - human_owner.physiology.bleed_mod *= 1.25 + if(!ishuman(owner)) + return FALSE + + var/mob/living/carbon/human/human_owner = owner + human_owner.physiology.bleed_mod *= 1.25 + return TRUE /datum/status_effect/high_blood_pressure/on_remove() - if(ishuman(owner)) - var/mob/living/carbon/human/human_owner = owner - human_owner.physiology.bleed_mod /= 1.25 + if(!ishuman(owner)) + return + + var/mob/living/carbon/human/human_owner = owner + human_owner.physiology.bleed_mod /= 1.25 /atom/movable/screen/alert/status_effect/high_blood_pressure name = "High blood pressure" desc = "Your blood pressure is real high right now ... You'd probably bleed like a stuck pig." icon_state = "highbloodpressure" - - /datum/status_effect/seizure id = "seizure" tick_interval = -1 @@ -48,7 +49,7 @@ return FALSE var/amplitude = rand(1 SECONDS, 3 SECONDS) duration = amplitude - owner.Jitter(50) + owner.set_timed_status_effect(100 SECONDS, /datum/status_effect/jitter, only_if_higher = TRUE) owner.Paralyze(duration) owner.visible_message(span_warning("[owner] drops to the ground as [owner.p_they()] start seizing up."), \ span_warning("[pick("You can't collect your thoughts...", "You suddenly feel extremely dizzy...", "You cant think straight...","You can't move your face properly anymore...")]")) @@ -64,15 +65,18 @@ duration = 10 SECONDS alert_type = /atom/movable/screen/alert/status_effect/stoned status_type = STATUS_EFFECT_REFRESH - var/original_eye_color + var/original_eye_color_left + var/original_eye_color_right /datum/status_effect/stoned/on_apply() if(!ishuman(owner)) CRASH("[type] status effect added to non-human owner: [owner ? owner.type : "null owner"]") var/mob/living/carbon/human/human_owner = owner - original_eye_color = human_owner.eye_color + original_eye_color_left = human_owner.eye_color_left + original_eye_color_right = human_owner.eye_color_right human_owner.add_movespeed_modifier(/datum/movespeed_modifier/reagent/cannabis) //slows you down - human_owner.eye_color = BLOODCULT_EYE //makes cult eyes less obvious + human_owner.eye_color_left = BLOODCULT_EYE //makes cult eyes less obvious + human_owner.eye_color_right = BLOODCULT_EYE //makes cult eyes less obvious human_owner.update_body() //updates eye color ADD_TRAIT(human_owner, TRAIT_BLOODSHOT_EYES, type) //dilates blood vessels in eyes ADD_TRAIT(human_owner, TRAIT_CLUMSY, type) //impairs motor coordination @@ -85,7 +89,8 @@ stack_trace("[type] status effect being removed from non-human owner: [owner ? owner.type : "null owner"]") var/mob/living/carbon/human/human_owner = owner human_owner.remove_movespeed_modifier(/datum/movespeed_modifier/reagent/cannabis) - human_owner.eye_color = original_eye_color + human_owner.eye_color_left = original_eye_color_left + human_owner.eye_color_right = original_eye_color_right human_owner.update_body() REMOVE_TRAIT(human_owner, TRAIT_BLOODSHOT_EYES, type) REMOVE_TRAIT(human_owner, TRAIT_CLUMSY, type) diff --git a/code/datums/status_effects/neutral.dm b/code/datums/status_effects/neutral.dm index dfc8ed396b242..e188b31c8d016 100644 --- a/code/datums/status_effects/neutral.dm +++ b/code/datums/status_effects/neutral.dm @@ -343,14 +343,14 @@ //phase 1 if(1 to EIGENSTASIUM_PHASE_1_END) - owner.Jitter(2) + owner.set_timed_status_effect(4 SECONDS, /datum/status_effect/jitter, only_if_higher = TRUE) owner.adjust_nutrition(-4) //phase 2 if(EIGENSTASIUM_PHASE_1_END to EIGENSTASIUM_PHASE_2_END) if(current_cycle == 51) to_chat(owner, span_userdanger("You start to convlse violently as you feel your consciousness merges across realities, your possessions flying wildy off your body!")) - owner.Jitter(200) + owner.set_timed_status_effect(400 SECONDS, /datum/status_effect/jitter, only_if_higher = TRUE) owner.Knockdown(10) var/list/items = list() @@ -378,7 +378,7 @@ //Clone function - spawns a clone then deletes it - simulates multiple copies of the player teleporting in switch(phase_3_cycle) //Loops 0 -> 1 -> 2 -> 1 -> 2 -> 1 ...ect. if(0) - owner.Jitter(100) + owner.set_timed_status_effect(200 SECONDS, /datum/status_effect/jitter, only_if_higher = TRUE) to_chat(owner, span_userdanger("Your eigenstate starts to rip apart, drawing in alternative reality versions of yourself!")) if(1) var/typepath = owner.type @@ -391,42 +391,7 @@ do_sparks(5,FALSE,alt_clone) alt_clone.emote("spin") owner.emote("spin") - var/static/list/say_phrases = list( - "Bugger me, whats all this then?", - "Sacre bleu! Ou suis-je?!", - "I knew powering the station using a singularity engine would lead to something like this...", - "Wow, I can't believe in your universe Cencomm got rid of cloning.", - "WHAT IS HAPPENING?!", - "YOU'VE CREATED A TIME PARADOX!", - "You trying to steal my job?", - "So that's what I'd look like if I was ugly...", - "So, two alternate universe twins walk into a bar...", - "YOU'VE DOOMED THE TIMELINE!", - "Ruffle a cat once in a while!", - "I'm starting to get why no one wants to hang out with me.", - "Why haven't you gotten around to starting that band?!", - "No!! I was just about to greentext!", - "Kept you waiting huh?", - "Oh god I think I'm ODing I'm seeing a fake version of me.", - "Hey, I remember that phase, glad I grew out of it.", - "Keep going lets see if more of us show up.", - "I bet we can finally take the clown now.", - "LING DISGUISED AS ME!", - "El psy congroo.", - "At long last! My evil twin!", - "Keep going lets see if more of us show up.", - "No! Dark spirits, do not torment me with these visions of my future self! It's horrible!", - "Good. Now that the council is assembled the meeting can begin.", - "Listen! I only have so much time before I'm ripped away. The secret behind the gas giants are...", - "Das ist nicht deutschland. Das ist nicht akzeptabel!!!", - "I've come from the future to warn you about eigenstasium! Oh no! I'm too late!", - "You fool! You took too much eigenstasium! You've doomed us all!", - "Don't trust any bagels you see until next month!", - "What...what's with these teleports? It's like one of my Japanese animes...!", - "Ik stond op het punt om mehki op tafel te zetten, en nu, waar ben ik?", - "Wake the fuck up spaceman we have a gas giant to burn", - "This is one hell of a beepsky smash.", - "Now neither of us will be virgins!") + var/list/say_phrases = strings(EIGENSTASIUM_FILE, "lines") alt_clone.say(pick(say_phrases)) if(2) phase_3_cycle = 0 //counter @@ -442,7 +407,7 @@ do_teleport(owner, get_turf(owner), 2, no_effects=TRUE) //teleports clone so it's hard to find the real one! do_sparks(5, FALSE, owner) owner.Sleeping(100) - owner.Jitter(50) + owner.set_timed_status_effect(100 SECONDS, /datum/status_effect/jitter, only_if_higher = TRUE) to_chat(owner, span_userdanger("You feel your eigenstate settle, as \"you\" become an alternative version of yourself!")) owner.emote("me",1,"flashes into reality suddenly, gasping as they gaze around in a bewildered and highly confused fashion!",TRUE) log_game("FERMICHEM: [owner] ckey: [owner.key] has become an alternative universe version of themselves.") @@ -456,7 +421,7 @@ if(QDELETED(human_mob)) return if(prob(1))//low chance of the alternative reality returning to monkey - var/obj/item/organ/tail/monkey/monkey_tail = new () + var/obj/item/organ/external/tail/monkey/monkey_tail = new () monkey_tail.Insert(human_mob, drop_if_replaced = FALSE) var/datum/species/human_species = human_mob.dna?.species if(human_species) diff --git a/code/datums/status_effects/song_effects.dm b/code/datums/status_effects/song_effects.dm index 7c6afd34bd2c1..baf646a2c7685 100644 --- a/code/datums/status_effects/song_effects.dm +++ b/code/datums/status_effects/song_effects.dm @@ -21,7 +21,6 @@ id = "antimagic" status_type = STATUS_EFFECT_REFRESH duration = 10 SECONDS - examine_text = "They seem to be covered in a dull, grey aura." aura_desc = "dull" /datum/status_effect/song/antimagic/on_apply() @@ -31,3 +30,7 @@ /datum/status_effect/song/antimagic/on_remove() REMOVE_TRAIT(owner, TRAIT_ANTIMAGIC, MAGIC_TRAIT) + return ..() + +/datum/status_effect/song/antimagic/get_examine_text() + return span_notice("[owner.p_they(TRUE)] seem[owner.p_s()] to be covered in a dull, grey aura.") diff --git a/code/datums/status_effects/wound_effects.dm b/code/datums/status_effects/wound_effects.dm index 216bfe6643db8..e29f093296717 100644 --- a/code/datums/status_effects/wound_effects.dm +++ b/code/datums/status_effects/wound_effects.dm @@ -3,7 +3,7 @@ /atom/movable/screen/alert/status_effect/determined name = "Determined" desc = "The serious wounds you've sustained have put your body into fight-or-flight mode! Now's the time to look for an exit!" - icon_state = "regenerative_core" + icon_state = "wounded" /datum/status_effect/determined id = "determined" diff --git a/code/datums/voice_of_god_command.dm b/code/datums/voice_of_god_command.dm index bf3117234a1f4..39113080f6213 100644 --- a/code/datums/voice_of_god_command.dm +++ b/code/datums/voice_of_god_command.dm @@ -213,7 +213,7 @@ GLOBAL_LIST_INIT(voice_of_god_commands, init_voice_of_god_commands()) /datum/voice_of_god_command/burn/execute(list/listeners, mob/living/user, power_multiplier = 1, message) for(var/mob/living/target as anything in listeners) target.adjust_fire_stacks(1 * power_multiplier) - target.IgniteMob() + target.ignite_mob() /// This command heats the listeners up like boiling water. /datum/voice_of_god_command/hot diff --git a/code/datums/votes/_vote_datum.dm b/code/datums/votes/_vote_datum.dm new file mode 100644 index 0000000000000..63bcd9cf22eff --- /dev/null +++ b/code/datums/votes/_vote_datum.dm @@ -0,0 +1,205 @@ + +/** + * # Vote Singleton + * + * A singleton datum that represents a type of vote for the voting subsystem. + */ +/datum/vote + /// The name of the vote. + var/name + /// If supplied, an override question will be displayed instead of the name of the vote. + var/override_question + /// The sound effect played to everyone when this vote is initiated. + var/vote_sound = 'sound/misc/bloop.ogg' + /// A list of default choices we have for this vote. + var/list/default_choices + + // Internal values used when tracking ongoing votes. + // Don't mess with these, change the above values / override procs for subtypes. + /// An assoc list of [all choices] to [number of votes in the current running vote]. + var/list/choices = list() + /// A assoc list of [ckey] to [what they voted for in the current running vote]. + var/list/choices_by_ckey = list() + /// The world time this vote was started. + var/started_time + /// The time remaining in this vote's run. + var/time_remaining + +/** + * Used to determine if this vote is a possible + * vote type for the vote subsystem. + * + * If FALSE is returned, this vote singleton + * will not be created when the vote subsystem initializes, + * meaning no one will be able to hold this vote. + */ +/datum/vote/proc/is_accessible_vote() + return !!length(default_choices) + +/** + * Resets our vote to its default state. + */ +/datum/vote/proc/reset() + SHOULD_CALL_PARENT(TRUE) + + choices.Cut() + choices_by_ckey.Cut() + started_time = null + time_remaining = null + +/** + * If this vote has a config associated, toggles it between enabled and disabled. + * Returns TRUE on a successful toggle, FALSE otherwise + */ +/datum/vote/proc/toggle_votable(mob/toggler) + return FALSE + +/** + * If this vote has a config associated, returns its value (True or False, usually). + * If it has no config, returns -1. + */ +/datum/vote/proc/is_config_enabled() + return -1 + +/** + * Checks if the passed mob can initiate this vote. + * + * Return TRUE if the mob can begin the vote, allowing anyone to actually vote on it. + * Return FALSE if the mob cannot initiate the vote. + */ +/datum/vote/proc/can_be_initiated(mob/by_who, forced = FALSE) + SHOULD_CALL_PARENT(TRUE) + + if(started_time) + var/next_allowed_time = (started_time + CONFIG_GET(number/vote_delay)) + if(next_allowed_time > world.time && !forced) + if(by_who) + to_chat(by_who, span_warning("A vote was initiated recently. You must wait [DisplayTimeText(next_allowed_time - world.time)] before a new vote can be started!")) + return FALSE + + return TRUE + +/** + * Called prior to the vote being initiated. + * + * Return FALSE to prevent the vote from being initiated. + */ +/datum/vote/proc/create_vote(mob/vote_creator) + SHOULD_CALL_PARENT(TRUE) + + for(var/key in default_choices) + choices[key] = 0 + + return TRUE + +/** + * Called when this vote is actually initiated. + * + * Return a string - the text displayed to the world when the vote is initiated. + */ +/datum/vote/proc/initiate_vote(initiator, duration) + SHOULD_CALL_PARENT(TRUE) + + started_time = world.time + time_remaining = round(duration / 10) + + return "[capitalize(name)] vote started by [initiator || "Central Command"]." + +/** + * Gets the result of the vote. + * + * non_voters - a list of all ckeys who didn't vote in the vote. + * + * Returns a list of all options that won. + * If there were no votes at all, the list will be length = 0, non-null. + * If only one option one, the list will be length = 1. + * If there was a tie, the list will be length > 1. + */ +/datum/vote/proc/get_vote_result(list/non_voters) + RETURN_TYPE(/list) + + var/list/winners = list() + var/highest_vote = 0 + + for(var/option in choices) + + var/vote_count = choices[option] + // If we currently have no winners... + if(!length(winners)) + // And the current option has any votes, it's the new highest. + if(vote_count > 0) + winners += option + highest_vote = vote_count + continue + + // If we're greater than, and NOT equal to, the highest vote, + // we are the new supreme winner - clear all others + if(vote_count > highest_vote) + winners.Cut() + winners += option + highest_vote = vote_count + + // If we're equal to the highest vote, we tie for winner + else if(vote_count == highest_vote) + winners += option + + return winners + +/** + * Gets the resulting text displayed when the vote is completed. + * + * all_winners - list of all options that won. Can be multiple, in the event of ties. + * real_winner - the option that actually won. + * non_voters - a list of all ckeys who didn't vote in the vote. + * + * Return a formatted string of text to be displayed to everyone. + */ +/datum/vote/proc/get_result_text(list/all_winners, real_winner, list/non_voters) + if(length(all_winners) <= 0 || !real_winner) + return span_bold("Vote Result: Inconclusive - No Votes!") + + var/returned_text = "" + if(override_question) + returned_text += span_bold(override_question) + else + returned_text += span_bold("[capitalize(name)] Vote") + + for(var/option in choices) + returned_text += "\n[span_bold(option)]: [choices[option]]" + + returned_text += "\n" + returned_text += get_winner_text(all_winners, real_winner, non_voters) + + return returned_text + +/** + * Gets the text that displays the winning options within the result text. + * + * all_winners - list of all options that won. Can be multiple, in the event of ties. + * real_winner - the option that actually won. + * non_voters - a list of all ckeys who didn't vote in the vote. + * + * Return a formatted string of text to be displayed to everyone. + */ +/datum/vote/proc/get_winner_text(list/all_winners, real_winner, list/non_voters) + var/returned_text = "" + if(length(all_winners) > 1) + returned_text += "\n[span_bold("Vote Tied Between:")]" + for(var/a_winner in all_winners) + returned_text += "\n\t[a_winner]" + + returned_text += span_bold("\nVote Result: [real_winner]") + return returned_text + +/** + * How this vote handles a tiebreaker between multiple winners. + */ +/datum/vote/proc/tiebreaker(list/winners) + return pick(winners) + +/** + * Called when a vote is actually all said and done. + * Apply actual vote effects here. + */ +/datum/vote/proc/finalize_vote(winning_option) + return diff --git a/code/datums/votes/custom_vote.dm b/code/datums/votes/custom_vote.dm new file mode 100644 index 0000000000000..753e2fef13aa9 --- /dev/null +++ b/code/datums/votes/custom_vote.dm @@ -0,0 +1,53 @@ +/// The max amount of options someone can have in a custom vote. +#define MAX_CUSTOM_VOTE_OPTIONS 10 + +/datum/vote/custom_vote + name = "Custom" + +// Custom votes ares always accessible. +/datum/vote/custom_vote/is_accessible_vote() + return TRUE + +/datum/vote/custom_vote/reset() + default_choices = null + override_question = null + return ..() + +/datum/vote/custom_vote/can_be_initiated(mob/by_who, forced = FALSE) + . = ..() + if(!.) + return FALSE + + // Custom votes can only be created if they're forced to be made. + // (Either an admin makes it, or otherwise.) + return forced + +/datum/vote/custom_vote/create_vote(mob/vote_creator) + override_question = tgui_input_text(vote_creator, "What is the vote for?", "Custom Vote") + if(!override_question) + return FALSE + + default_choices = list() + for(var/i in 1 to MAX_CUSTOM_VOTE_OPTIONS) + var/option = tgui_input_text(vote_creator, "Please enter an option, or hit cancel to finish. [MAX_CUSTOM_VOTE_OPTIONS] max.", "Options", max_length = MAX_NAME_LEN) + if(!vote_creator?.client) + return FALSE + if(!option) + break + + default_choices += capitalize(option) + + if(!length(default_choices)) + return FALSE + + return ..() + +/datum/vote/custom_vote/initiate_vote(initiator, duration) + . = ..() + . += "\n[override_question]" + +// There are no winners or losers for custom votes +/datum/vote/custom_vote/get_winner_text(list/all_winners, real_winner, list/non_voters) + return "[span_bold("Did not vote:")] [length(non_voters)]" + +#undef MAX_CUSTOM_VOTE_OPTIONS diff --git a/code/datums/votes/map_vote.dm b/code/datums/votes/map_vote.dm new file mode 100644 index 0000000000000..b55ee8419ee63 --- /dev/null +++ b/code/datums/votes/map_vote.dm @@ -0,0 +1,87 @@ +/datum/vote/map_vote + name = "Map" + +/datum/vote/map_vote/New() + . = ..() + + default_choices = list() + + // Fill in our default choices with all of the maps in our map config, if they are votable and not blocked. + var/list/maps = shuffle(global.config.maplist) + for(var/map in maps) + var/datum/map_config/possible_config = config.maplist[map] + if(!possible_config.votable || (possible_config.map_name in SSpersistence.blocked_maps)) + continue + + default_choices += possible_config.map_name + +/datum/vote/map_vote/create_vote() + . = ..() + + // Before we create a vote, remove all maps from our choices that are outside of our population range. + // Note that this can result in zero remaining choices for our vote, which is not ideal (but technically fine). + for(var/map in choices) + var/datum/map_config/possible_config = config.maplist[map] + if(possible_config.config_min_users > 0 && GLOB.clients.len < possible_config.config_min_users) + choices -= map + + else if(possible_config.config_max_users > 0 && GLOB.clients.len > possible_config.config_max_users) + choices -= map + +/datum/vote/map_vote/toggle_votable(mob/toggler) + if(!toggler) + CRASH("[type] wasn't passed a \"toggler\" mob to toggle_votable.") + if(!check_rights_for(toggler.client, R_ADMIN)) + return FALSE + + CONFIG_SET(flag/allow_vote_map, !CONFIG_GET(flag/allow_vote_map)) + return TRUE + +/datum/vote/map_vote/is_config_enabled() + return CONFIG_GET(flag/allow_vote_map) + +/datum/vote/map_vote/can_be_initiated(mob/by_who, forced = FALSE) + . = ..() + if(!.) + return FALSE + + if(forced) + return TRUE + + if(!CONFIG_GET(flag/allow_vote_map)) + if(by_who) + to_chat(by_who, span_warning("Map voting is disabled.")) + return FALSE + + if(SSmapping.map_voted) + if(by_who) + to_chat(by_who, span_warning("The next map has already been selected.")) + return FALSE + + return TRUE + +/datum/vote/map_vote/get_vote_result(list/non_voters) + // Even if we have default no vote off, + // if our default map is null for some reason, we shouldn't continue + if(CONFIG_GET(flag/default_no_vote) || isnull(global.config.defaultmap)) + return ..() + + for(var/non_voter_ckey in non_voters) + var/client/non_voter_client = non_voters[non_voter_ckey] + // Non-voters will have their preferred map voted for automatically. + var/their_preferred_map = non_voter_client?.prefs.read_preference(/datum/preference/choiced/preferred_map) + // If the non-voter's preferred map is null for some reason, we just use the default map. + var/voting_for = their_preferred_map || global.config.defaultmap.map_name + + if(voting_for in choices) + choices[voting_for] += 1 + + return ..() + +/datum/vote/map_vote/finalize_vote(winning_option) + var/datum/map_config/winning_map = global.config.maplist[winning_option] + if(!istype(winning_map)) + CRASH("[type] wasn't passed a valid winning map choice. (Got: [winning_option || "null"] - [winning_map || "null"])") + + SSmapping.changemap(winning_map) + SSmapping.map_voted = TRUE diff --git a/code/datums/votes/restart_vote.dm b/code/datums/votes/restart_vote.dm new file mode 100644 index 0000000000000..c71bdb8170e9b --- /dev/null +++ b/code/datums/votes/restart_vote.dm @@ -0,0 +1,61 @@ +#define CHOICE_RESTART "Restart Round" +#define CHOICE_CONTINUE "Continue Playing" + +/datum/vote/restart_vote + name = "Restart" + default_choices = list( + CHOICE_RESTART, + CHOICE_CONTINUE, + ) + +/datum/vote/restart_vote/toggle_votable(mob/toggler) + if(!toggler) + CRASH("[type] wasn't passed a \"toggler\" mob to toggle_votable.") + if(!check_rights_for(toggler.client, R_ADMIN)) + return FALSE + + CONFIG_SET(flag/allow_vote_restart, !CONFIG_GET(flag/allow_vote_restart)) + return TRUE + +/datum/vote/restart_vote/is_config_enabled() + return CONFIG_GET(flag/allow_vote_restart) + +/datum/vote/restart_vote/can_be_initiated(mob/by_who, forced) + . = ..() + if(!.) + return FALSE + + if(!forced && !CONFIG_GET(flag/allow_vote_restart)) + if(by_who) + to_chat(by_who, span_warning("Restart voting is disabled.")) + return FALSE + + return TRUE + +/datum/vote/restart_vote/get_vote_result(list/non_voters) + if(!CONFIG_GET(flag/default_no_vote)) + // Default no votes will add non-voters to "Continue Playing" + choices[CHOICE_CONTINUE] += length(non_voters) + + return ..() + +/datum/vote/restart_vote/finalize_vote(winning_option) + if(winning_option == CHOICE_CONTINUE) + return + + if(winning_option == CHOICE_RESTART) + for(var/client/online_admin as anything in GLOB.admins) + if(online_admin.is_afk() || !check_rights_for(online_admin, R_SERVER)) + continue + + to_chat(world, span_boldannounce("Notice: A restart vote will not restart the server automatically because there are active admins on.")) + message_admins("A restart vote has passed, but there are active admins on with +SERVER, so it has been canceled. If you wish, you may restart the server.") + return + + SSticker.Reboot("Restart vote successful.", "restart vote", 1) + return + + CRASH("[type] wasn't passed a valid winning choice. (Got: [winning_option || "null"])") + +#undef CHOICE_RESTART +#undef CHOICE_CONTINUE diff --git a/code/datums/weather/weather.dm b/code/datums/weather/weather.dm index 3ebd1e682ef1e..d665138ee2158 100644 --- a/code/datums/weather/weather.dm +++ b/code/datums/weather/weather.dm @@ -240,7 +240,7 @@ if(END_STAGE) N.color = null N.icon_state = "" - N.icon = 'icons/turf/areas.dmi' + N.icon = 'icons/area/areas_misc.dmi' N.layer = initial(N.layer) N.plane = initial(N.plane) N.set_opacity(FALSE) diff --git a/code/datums/weather/weather_types/radiation_storm.dm b/code/datums/weather/weather_types/radiation_storm.dm index 97ea8a835eaa2..83f3aa73c4891 100644 --- a/code/datums/weather/weather_types/radiation_storm.dm +++ b/code/datums/weather/weather_types/radiation_storm.dm @@ -17,8 +17,10 @@ end_message = "The air seems to be cooling off again." area_type = /area - protected_areas = list(/area/maintenance, /area/ai_monitored/turret_protected/ai_upload, /area/ai_monitored/turret_protected/ai_upload_foyer, /area/ai_monitored/turret_protected/aisat/maint, /area/ai_monitored/command/storage/satellite, - /area/ai_monitored/turret_protected/ai, /area/commons/storage/emergency/starboard, /area/commons/storage/emergency/port, /area/shuttle, /area/security/prison/safe, /area/security/prison/toilet, /area/icemoon/underground) + protected_areas = list(/area/station/maintenance, /area/station/ai_monitored/turret_protected/ai_upload, /area/station/ai_monitored/turret_protected/ai_upload_foyer, + /area/station/ai_monitored/turret_protected/aisat/maint, /area/station/ai_monitored/command/storage/satellite, + /area/station/ai_monitored/turret_protected/ai, /area/station/commons/storage/emergency/starboard, /area/station/commons/storage/emergency/port, + /area/shuttle, /area/station/security/prison/safe, /area/station/security/prison/toilet, /area/icemoon/underground) target_trait = ZTRAIT_STATION immunity_type = TRAIT_RADSTORM_IMMUNE @@ -36,7 +38,7 @@ return var/mob/living/carbon/human/H = L - if(!H.dna || HAS_TRAIT(H, TRAIT_GENELESS)) + if(!H.dna || HAS_TRAIT(H, TRAIT_GENELESS) || H.status_flags & GODMODE) return if(HAS_TRAIT(H, TRAIT_RADIMMUNE)) diff --git a/code/datums/wires/robot.dm b/code/datums/wires/robot.dm index 944399f6d4b66..42ae3a18b3468 100644 --- a/code/datums/wires/robot.dm +++ b/code/datums/wires/robot.dm @@ -42,7 +42,7 @@ R.notify_ai(AI_NOTIFICATION_CYBORG_DISCONNECTED) if(new_ai && (new_ai != R.connected_ai)) R.set_connected_ai(new_ai) - log_combat(usr, R, "synced cyborg [R.connected_ai ? "from [ADMIN_LOOKUP(R.connected_ai)]": ""] to [ADMIN_LOOKUP(new_ai)]") + log_silicon("[key_name(usr)] synced [key_name(R)] [R.connected_ai ? "from [ADMIN_LOOKUP(R.connected_ai)]": ""] to [ADMIN_LOOKUP(new_ai)]") if(R.shell) R.undeploy() //If this borg is an AI shell, disconnect the controlling AI and assign ti to a new AI R.notify_ai(AI_NOTIFICATION_AI_SHELL) @@ -52,17 +52,17 @@ if(!QDELETED(R.builtInCamera) && !R.scrambledcodes) R.builtInCamera.toggle_cam(usr, FALSE) R.visible_message(span_notice("[R]'s camera lens focuses loudly."), span_notice("Your camera lens focuses loudly.")) - log_combat(usr, R, "toggled cyborg camera to [R.builtInCamera.status ? "on" : "off"] via pulse") + log_silicon("[key_name(usr)] toggled [key_name(R)]'s camera to [R.builtInCamera.status ? "on" : "off"] via pulse") if(WIRE_LAWSYNC) // Forces a law update if possible. if(R.lawupdate) R.visible_message(span_notice("[R] gently chimes."), span_notice("LawSync protocol engaged.")) - log_combat(usr, R, "forcibly synced cyborg laws via pulse") + log_silicon("[key_name(usr)] forcibly synced [key_name(R)]'s laws via pulse") // TODO, log the laws they gained here R.lawsync() R.show_laws() if(WIRE_LOCKDOWN) R.SetLockdown(!R.lockcharge) // Toggle - log_combat(usr, R, "[!R.lockcharge ? "locked down" : "released"] via pulse") + log_silicon("[key_name(usr)] [!R.lockcharge ? "locked down" : "released"] [key_name(R)] via pulse") if(WIRE_RESET_MODEL) if(R.has_model()) @@ -74,7 +74,7 @@ if(WIRE_AI) // Cut the AI wire to reset AI control. if(!mend) R.notify_ai(AI_NOTIFICATION_CYBORG_DISCONNECTED) - log_combat(usr, R, "cut AI wire on cyborg[R.connected_ai ? " and disconnected from [ADMIN_LOOKUP(R.connected_ai)]": ""]") + log_silicon("[key_name(usr)] cut AI wire on [key_name(R)][R.connected_ai ? " and disconnected from [ADMIN_LOOKUP(R.connected_ai)]": ""]") if(R.shell) R.undeploy() R.set_connected_ai(null) @@ -83,26 +83,26 @@ if(mend) if(!R.emagged) R.lawupdate = TRUE - log_combat(usr, R, "enabled lawsync via wire") + log_silicon("[key_name(usr)] enabled [key_name(R)]'s lawsync via wire") else if(!R.deployed) //AI shells must always have the same laws as the AI R.lawupdate = FALSE - log_combat(usr, R, "disabled lawsync via wire") - R.logevent("Lawsync Module fault [mend?"cleared":"detected"]") + log_silicon("[key_name(usr)] disabled [key_name(R)]'s lawsync via wire") + R.logevent("Lawsync Module fault [mend ? "cleared" : "detected"]") if (WIRE_CAMERA) // Disable the camera. if(!QDELETED(R.builtInCamera) && !R.scrambledcodes) R.builtInCamera.status = mend R.builtInCamera.toggle_cam(usr, 0) R.visible_message(span_notice("[R]'s camera lens focuses loudly."), span_notice("Your camera lens focuses loudly.")) R.logevent("Camera Module fault [mend?"cleared":"detected"]") - log_combat(usr, R, "[mend ? "enabled" : "disabled"] cyborg camera via wire") + log_silicon("[key_name(usr)] [mend ? "enabled" : "disabled"] [key_name(R)]'s camera via wire") if(WIRE_LOCKDOWN) // Simple lockdown. R.SetLockdown(!mend) R.logevent("Motor Controller fault [mend?"cleared":"detected"]") - log_combat(usr, R, "[!R.lockcharge ? "locked down" : "released"] via wire") + log_silicon("[key_name(usr)] [!R.lockcharge ? "locked down" : "released"] [key_name(R)] via wire") if(WIRE_RESET_MODEL) if(R.has_model() && !mend) R.ResetModel() - log_combat(usr, R, "reset the cyborg module via wire") + log_silicon("[key_name(usr)] reset [key_name(R)]'s module via wire") /datum/wires/robot/can_reveal_wires(mob/user) if(HAS_TRAIT(user, TRAIT_KNOW_CYBORG_WIRES)) diff --git a/code/datums/wounds/_wounds.dm b/code/datums/wounds/_wounds.dm index 4b972cf373c44..30040d91f4027 100644 --- a/code/datums/wounds/_wounds.dm +++ b/code/datums/wounds/_wounds.dm @@ -147,14 +147,14 @@ return if(!silent && !demoted) - var/msg = span_danger("[victim]'s [limb.name] [occur_text]!") + var/msg = span_danger("[victim]'s [limb.plaintext_zone] [occur_text]!") var/vis_dist = COMBAT_MESSAGE_RANGE if(severity != WOUND_SEVERITY_MODERATE) msg = "[msg]" vis_dist = DEFAULT_MESSAGE_RANGE - victim.visible_message(msg, span_userdanger("Your [limb.name] [occur_text]!"), vision_distance = vis_dist) + victim.visible_message(msg, span_userdanger("Your [limb.plaintext_zone] [occur_text]!"), vision_distance = vis_dist) if(sound_effect) playsound(L.owner, sound_effect, 70 + 20 * severity, TRUE) @@ -405,7 +405,7 @@ * * mob/user: The user examining the wound's owner, if that matters */ /datum/wound/proc/get_examine_description(mob/user) - . = "[victim.p_their(TRUE)] [limb.name] [examine_desc]" + . = "[victim.p_their(TRUE)] [limb.plaintext_zone] [examine_desc]" . = severity <= WOUND_SEVERITY_MODERATE ? "[.]." : "[.]!" /datum/wound/proc/get_scanner_description(mob/user) diff --git a/code/datums/wounds/bones.dm b/code/datums/wounds/bones.dm index c481eb3eba623..706a033f8dcb7 100644 --- a/code/datums/wounds/bones.dm +++ b/code/datums/wounds/bones.dm @@ -48,7 +48,7 @@ I = victim.get_inactive_held_item() if(I && victim.dropItemToGround(I)) - victim.visible_message(span_danger("[victim] drops [I] in shock!"), span_warning("The force on your [parse_zone(limb.body_zone)] causes you to drop [I]!"), vision_distance=COMBAT_MESSAGE_RANGE) + victim.visible_message(span_danger("[victim] drops [I] in shock!"), span_warning("The force on your [limb.plaintext_zone] causes you to drop [I]!"), vision_distance=COMBAT_MESSAGE_RANGE) update_inefficiencies() @@ -91,7 +91,7 @@ if(!victim || !limb) qdel(src) return - to_chat(victim, span_green("Your [parse_zone(limb.body_zone)] has recovered from its [name]!")) + to_chat(victim, span_green("Your [limb.plaintext_zone] has recovered from its [name]!")) remove_wound() /// If we're a human who's punching something with a broken arm, we might hurt ourselves doing so @@ -105,11 +105,11 @@ if(prob((severity - 1) * 15)) // And you have a 70% or 50% chance to actually land the blow, respectively if(prob(70 - 20 * (severity - 1))) - to_chat(victim, span_userdanger("The fracture in your [parse_zone(limb.body_zone)] shoots with pain as you strike [target]!")) + to_chat(victim, span_userdanger("The fracture in your [limb.plaintext_zone] shoots with pain as you strike [target]!")) limb.receive_damage(brute=rand(1,5)) else - victim.visible_message(span_danger("[victim] weakly strikes [target] with [victim.p_their()] broken [parse_zone(limb.body_zone)], recoiling from pain!"), \ - span_userdanger("You fail to strike [target] as the fracture in your [parse_zone(limb.body_zone)] lights up in unbearable pain!"), vision_distance=COMBAT_MESSAGE_RANGE) + victim.visible_message(span_danger("[victim] weakly strikes [target] with [victim.p_their()] broken [limb.plaintext_zone], recoiling from pain!"), \ + span_userdanger("You fail to strike [target] as the fracture in your [limb.plaintext_zone] lights up in unbearable pain!"), vision_distance=COMBAT_MESSAGE_RANGE) INVOKE_ASYNC(victim, /mob.proc/emote, "scream") victim.Stun(0.5 SECONDS) limb.receive_damage(brute=rand(3,7)) @@ -149,7 +149,7 @@ var/list/msg = list() if(!limb.current_gauze) - msg += "[victim.p_their(TRUE)] [parse_zone(limb.body_zone)] [examine_desc]" + msg += "[victim.p_their(TRUE)] [limb.plaintext_zone] [examine_desc]" else var/sling_condition = "" // how much life we have left in these bandages @@ -163,7 +163,7 @@ if(4 to INFINITY) sling_condition = "tightly" - msg += "[victim.p_their(TRUE)] [parse_zone(limb.body_zone)] is [sling_condition] fastened in a sling of [limb.current_gauze.name]" + msg += "[victim.p_their(TRUE)] [limb.plaintext_zone] is [sling_condition] fastened in a sling of [limb.current_gauze.name]" if(taped) msg += ", [span_notice("and appears to be reforming itself under some surgical tape!")]" @@ -231,7 +231,7 @@ /datum/wound/blunt/moderate/proc/door_crush() SIGNAL_HANDLER if(prob(40)) - victim.visible_message(span_danger("[victim]'s dislocated [parse_zone(limb.body_zone)] pops back into place!"), span_userdanger("Your dislocated [parse_zone(limb.body_zone)] pops back into place! Ow!")) + victim.visible_message(span_danger("[victim]'s dislocated [limb.plaintext_zone] pops back into place!"), span_userdanger("Your dislocated [limb.plaintext_zone] pops back into place! Ow!")) remove_wound() /datum/wound/blunt/moderate/try_handling(mob/living/carbon/human/user) @@ -243,8 +243,8 @@ return TRUE if(user.grab_state >= GRAB_AGGRESSIVE) - user.visible_message(span_danger("[user] begins twisting and straining [victim]'s dislocated [parse_zone(limb.body_zone)]!"), span_notice("You begin twisting and straining [victim]'s dislocated [parse_zone(limb.body_zone)]..."), ignored_mobs=victim) - to_chat(victim, span_userdanger("[user] begins twisting and straining your dislocated [parse_zone(limb.body_zone)]!")) + user.visible_message(span_danger("[user] begins twisting and straining [victim]'s dislocated [limb.plaintext_zone]!"), span_notice("You begin twisting and straining [victim]'s dislocated [limb.plaintext_zone]..."), ignored_mobs=victim) + to_chat(victim, span_userdanger("[user] begins twisting and straining your dislocated [limb.plaintext_zone]!")) if(!user.combat_mode) chiropractice(user) else @@ -259,14 +259,14 @@ return if(prob(65)) - user.visible_message(span_danger("[user] snaps [victim]'s dislocated [parse_zone(limb.body_zone)] back into place!"), span_notice("You snap [victim]'s dislocated [parse_zone(limb.body_zone)] back into place!"), ignored_mobs=victim) - to_chat(victim, span_userdanger("[user] snaps your dislocated [parse_zone(limb.body_zone)] back into place!")) + user.visible_message(span_danger("[user] snaps [victim]'s dislocated [limb.plaintext_zone] back into place!"), span_notice("You snap [victim]'s dislocated [limb.plaintext_zone] back into place!"), ignored_mobs=victim) + to_chat(victim, span_userdanger("[user] snaps your dislocated [limb.plaintext_zone] back into place!")) victim.emote("scream") limb.receive_damage(brute=20, wound_bonus=CANT_WOUND) qdel(src) else - user.visible_message(span_danger("[user] wrenches [victim]'s dislocated [parse_zone(limb.body_zone)] around painfully!"), span_danger("You wrench [victim]'s dislocated [parse_zone(limb.body_zone)] around painfully!"), ignored_mobs=victim) - to_chat(victim, span_userdanger("[user] wrenches your dislocated [parse_zone(limb.body_zone)] around painfully!")) + user.visible_message(span_danger("[user] wrenches [victim]'s dislocated [limb.plaintext_zone] around painfully!"), span_danger("You wrench [victim]'s dislocated [limb.plaintext_zone] around painfully!"), ignored_mobs=victim) + to_chat(victim, span_userdanger("[user] wrenches your dislocated [limb.plaintext_zone] around painfully!")) limb.receive_damage(brute=10, wound_bonus=CANT_WOUND) chiropractice(user) @@ -278,33 +278,33 @@ return if(prob(65)) - user.visible_message(span_danger("[user] snaps [victim]'s dislocated [parse_zone(limb.body_zone)] with a sickening crack!"), span_danger("You snap [victim]'s dislocated [parse_zone(limb.body_zone)] with a sickening crack!"), ignored_mobs=victim) - to_chat(victim, span_userdanger("[user] snaps your dislocated [parse_zone(limb.body_zone)] with a sickening crack!")) + user.visible_message(span_danger("[user] snaps [victim]'s dislocated [limb.plaintext_zone] with a sickening crack!"), span_danger("You snap [victim]'s dislocated [limb.plaintext_zone] with a sickening crack!"), ignored_mobs=victim) + to_chat(victim, span_userdanger("[user] snaps your dislocated [limb.plaintext_zone] with a sickening crack!")) victim.emote("scream") limb.receive_damage(brute=25, wound_bonus=30) else - user.visible_message(span_danger("[user] wrenches [victim]'s dislocated [parse_zone(limb.body_zone)] around painfully!"), span_danger("You wrench [victim]'s dislocated [parse_zone(limb.body_zone)] around painfully!"), ignored_mobs=victim) - to_chat(victim, span_userdanger("[user] wrenches your dislocated [parse_zone(limb.body_zone)] around painfully!")) + user.visible_message(span_danger("[user] wrenches [victim]'s dislocated [limb.plaintext_zone] around painfully!"), span_danger("You wrench [victim]'s dislocated [limb.plaintext_zone] around painfully!"), ignored_mobs=victim) + to_chat(victim, span_userdanger("[user] wrenches your dislocated [limb.plaintext_zone] around painfully!")) limb.receive_damage(brute=10, wound_bonus=CANT_WOUND) malpractice(user) /datum/wound/blunt/moderate/treat(obj/item/I, mob/user) if(victim == user) - victim.visible_message(span_danger("[user] begins resetting [victim.p_their()] [parse_zone(limb.body_zone)] with [I]."), span_warning("You begin resetting your [parse_zone(limb.body_zone)] with [I]...")) + victim.visible_message(span_danger("[user] begins resetting [victim.p_their()] [limb.plaintext_zone] with [I]."), span_warning("You begin resetting your [limb.plaintext_zone] with [I]...")) else - user.visible_message(span_danger("[user] begins resetting [victim]'s [parse_zone(limb.body_zone)] with [I]."), span_notice("You begin resetting [victim]'s [parse_zone(limb.body_zone)] with [I]...")) + user.visible_message(span_danger("[user] begins resetting [victim]'s [limb.plaintext_zone] with [I]."), span_notice("You begin resetting [victim]'s [limb.plaintext_zone] with [I]...")) if(!do_after(user, base_treat_time * (user == victim ? 1.5 : 1), target = victim, extra_checks=CALLBACK(src, .proc/still_exists))) return if(victim == user) limb.receive_damage(brute=15, wound_bonus=CANT_WOUND) - victim.visible_message(span_danger("[user] finishes resetting [victim.p_their()] [parse_zone(limb.body_zone)]!"), span_userdanger("You reset your [parse_zone(limb.body_zone)]!")) + victim.visible_message(span_danger("[user] finishes resetting [victim.p_their()] [limb.plaintext_zone]!"), span_userdanger("You reset your [limb.plaintext_zone]!")) else limb.receive_damage(brute=10, wound_bonus=CANT_WOUND) - user.visible_message(span_danger("[user] finishes resetting [victim]'s [parse_zone(limb.body_zone)]!"), span_nicegreen("You finish resetting [victim]'s [parse_zone(limb.body_zone)]!"), ignored_mobs=victim) - to_chat(victim, span_userdanger("[user] resets your [parse_zone(limb.body_zone)]!")) + user.visible_message(span_danger("[user] finishes resetting [victim]'s [limb.plaintext_zone]!"), span_nicegreen("You finish resetting [victim]'s [limb.plaintext_zone]!"), ignored_mobs=victim) + to_chat(victim, span_userdanger("[user] resets your [limb.plaintext_zone]!")) victim.emote("scream") qdel(src) @@ -375,10 +375,10 @@ return if(gelled) - to_chat(user, span_warning("[user == victim ? "Your" : "[victim]'s"] [parse_zone(limb.body_zone)] is already coated with bone gel!")) + to_chat(user, span_warning("[user == victim ? "Your" : "[victim]'s"] [limb.plaintext_zone] is already coated with bone gel!")) return - user.visible_message(span_danger("[user] begins hastily applying [I] to [victim]'s' [parse_zone(limb.body_zone)]..."), span_warning("You begin hastily applying [I] to [user == victim ? "your" : "[victim]'s"] [parse_zone(limb.body_zone)], disregarding the warning label...")) + user.visible_message(span_danger("[user] begins hastily applying [I] to [victim]'s' [limb.plaintext_zone]..."), span_warning("You begin hastily applying [I] to [user == victim ? "your" : "[victim]'s"] [limb.plaintext_zone], disregarding the warning label...")) if(!do_after(user, base_treat_time * 1.5 * (user == victim ? 1.5 : 1), target = victim, extra_checks=CALLBACK(src, .proc/still_exists))) return @@ -386,11 +386,11 @@ I.use(1) victim.emote("scream") if(user != victim) - user.visible_message(span_notice("[user] finishes applying [I] to [victim]'s [parse_zone(limb.body_zone)], emitting a fizzing noise!"), span_notice("You finish applying [I] to [victim]'s [parse_zone(limb.body_zone)]!"), ignored_mobs=victim) - to_chat(victim, span_userdanger("[user] finishes applying [I] to your [parse_zone(limb.body_zone)], and you can feel the bones exploding with pain as they begin melting and reforming!")) + user.visible_message(span_notice("[user] finishes applying [I] to [victim]'s [limb.plaintext_zone], emitting a fizzing noise!"), span_notice("You finish applying [I] to [victim]'s [limb.plaintext_zone]!"), ignored_mobs=victim) + to_chat(victim, span_userdanger("[user] finishes applying [I] to your [limb.plaintext_zone], and you can feel the bones exploding with pain as they begin melting and reforming!")) else var/painkiller_bonus = 0 - if(victim.drunkenness > 10) + if(victim.get_drunk_amount() > 10) painkiller_bonus += 10 if(victim.reagents.has_reagent(/datum/reagent/medicine/morphine)) painkiller_bonus += 20 @@ -402,10 +402,10 @@ painkiller_bonus += 20 if(prob(25 + (20 * (severity - 2)) - painkiller_bonus)) // 25%/45% chance to fail self-applying with severe and critical wounds, modded by painkillers - victim.visible_message(span_danger("[victim] fails to finish applying [I] to [victim.p_their()] [parse_zone(limb.body_zone)], passing out from the pain!"), span_notice("You pass out from the pain of applying [I] to your [parse_zone(limb.body_zone)] before you can finish!")) + victim.visible_message(span_danger("[victim] fails to finish applying [I] to [victim.p_their()] [limb.plaintext_zone], passing out from the pain!"), span_notice("You pass out from the pain of applying [I] to your [limb.plaintext_zone] before you can finish!")) victim.AdjustUnconscious(5 SECONDS) return - victim.visible_message(span_notice("[victim] finishes applying [I] to [victim.p_their()] [parse_zone(limb.body_zone)], grimacing from the pain!"), span_notice("You finish applying [I] to your [parse_zone(limb.body_zone)], and your bones explode in pain!")) + victim.visible_message(span_notice("[victim] finishes applying [I] to [victim.p_their()] [limb.plaintext_zone], grimacing from the pain!"), span_notice("You finish applying [I] to your [limb.plaintext_zone], and your bones explode in pain!")) limb.receive_damage(25, stamina=100, wound_bonus=CANT_WOUND) gelled = TRUE @@ -416,20 +416,20 @@ return // poser if(gelled) - to_chat(user, span_warning("[user == victim ? "Your" : "[victim]'s"] [parse_zone(limb.body_zone)] is already coated with bone gel!")) + to_chat(user, span_warning("[user == victim ? "Your" : "[victim]'s"] [limb.plaintext_zone] is already coated with bone gel!")) return - user.visible_message(span_danger("[user] begins applying [I] to [victim]'s' [parse_zone(limb.body_zone)]..."), span_warning("You begin applying [I] to [user == victim ? "your" : "[victim]'s"] [parse_zone(limb.body_zone)]...")) + user.visible_message(span_danger("[user] begins applying [I] to [victim]'s' [limb.plaintext_zone]..."), span_warning("You begin applying [I] to [user == victim ? "your" : "[victim]'s"] [limb.plaintext_zone]...")) if(!do_after(user, base_treat_time * (user == victim ? 1.5 : 1), target = victim, extra_checks=CALLBACK(src, .proc/still_exists))) return I.use(1) if(user != victim) - user.visible_message(span_notice("[user] finishes applying [I] to [victim]'s [parse_zone(limb.body_zone)], emitting a fizzing noise!"), span_notice("You finish applying [I] to [victim]'s [parse_zone(limb.body_zone)]!"), ignored_mobs=victim) - to_chat(victim, span_userdanger("[user] finishes applying [I] to your [parse_zone(limb.body_zone)], and you feel a funny fizzy tickling as they begin to reform!")) + user.visible_message(span_notice("[user] finishes applying [I] to [victim]'s [limb.plaintext_zone], emitting a fizzing noise!"), span_notice("You finish applying [I] to [victim]'s [limb.plaintext_zone]!"), ignored_mobs=victim) + to_chat(victim, span_userdanger("[user] finishes applying [I] to your [limb.plaintext_zone], and you feel a funny fizzy tickling as they begin to reform!")) else - victim.visible_message(span_notice("[victim] finishes applying [I] to [victim.p_their()] [parse_zone(limb.body_zone)], emitting a funny fizzing sound!"), span_notice("You finish applying [I] to your [parse_zone(limb.body_zone)], and feel a funny fizzy tickling as the bone begins to reform!")) + victim.visible_message(span_notice("[victim] finishes applying [I] to [victim.p_their()] [limb.plaintext_zone], emitting a funny fizzing sound!"), span_notice("You finish applying [I] to your [limb.plaintext_zone], and feel a funny fizzy tickling as the bone begins to reform!")) gelled = TRUE processes = TRUE @@ -437,13 +437,13 @@ /// if someone is using surgical tape on our wound /datum/wound/blunt/proc/tape(obj/item/stack/sticky_tape/surgical/I, mob/user) if(!gelled) - to_chat(user, span_warning("[user == victim ? "Your" : "[victim]'s"] [parse_zone(limb.body_zone)] must be coated with bone gel to perform this emergency operation!")) + to_chat(user, span_warning("[user == victim ? "Your" : "[victim]'s"] [limb.plaintext_zone] must be coated with bone gel to perform this emergency operation!")) return if(taped) - to_chat(user, span_warning("[user == victim ? "Your" : "[victim]'s"] [parse_zone(limb.body_zone)] is already wrapped in [I.name] and reforming!")) + to_chat(user, span_warning("[user == victim ? "Your" : "[victim]'s"] [limb.plaintext_zone] is already wrapped in [I.name] and reforming!")) return - user.visible_message(span_danger("[user] begins applying [I] to [victim]'s' [parse_zone(limb.body_zone)]..."), span_warning("You begin applying [I] to [user == victim ? "your" : "[victim]'s"] [parse_zone(limb.body_zone)]...")) + user.visible_message(span_danger("[user] begins applying [I] to [victim]'s' [limb.plaintext_zone]..."), span_warning("You begin applying [I] to [user == victim ? "your" : "[victim]'s"] [limb.plaintext_zone]...")) if(!do_after(user, base_treat_time * (user == victim ? 1.5 : 1), target = victim, extra_checks=CALLBACK(src, .proc/still_exists))) return @@ -453,10 +453,10 @@ I.use(1) if(user != victim) - user.visible_message(span_notice("[user] finishes applying [I] to [victim]'s [parse_zone(limb.body_zone)], emitting a fizzing noise!"), span_notice("You finish applying [I] to [victim]'s [parse_zone(limb.body_zone)]!"), ignored_mobs=victim) - to_chat(victim, span_green("[user] finishes applying [I] to your [parse_zone(limb.body_zone)], you immediately begin to feel your bones start to reform!")) + user.visible_message(span_notice("[user] finishes applying [I] to [victim]'s [limb.plaintext_zone], emitting a fizzing noise!"), span_notice("You finish applying [I] to [victim]'s [limb.plaintext_zone]!"), ignored_mobs=victim) + to_chat(victim, span_green("[user] finishes applying [I] to your [limb.plaintext_zone], you immediately begin to feel your bones start to reform!")) else - victim.visible_message(span_notice("[victim] finishes applying [I] to [victim.p_their()] [parse_zone(limb.body_zone)], !"), span_green("You finish applying [I] to your [parse_zone(limb.body_zone)], and you immediately begin to feel your bones start to reform!")) + victim.visible_message(span_notice("[victim] finishes applying [I] to [victim.p_their()] [limb.plaintext_zone], !"), span_green("You finish applying [I] to your [limb.plaintext_zone], and you immediately begin to feel your bones start to reform!")) taped = TRUE processes = TRUE diff --git a/code/datums/wounds/burns.dm b/code/datums/wounds/burns.dm index b0fd2e5d8e8d2..2d70a85305edf 100644 --- a/code/datums/wounds/burns.dm +++ b/code/datums/wounds/burns.dm @@ -37,7 +37,7 @@ if(strikes_to_lose_limb == 0) // we've already hit sepsis, nothing more to do victim.adjustToxLoss(0.25 * delta_time) if(DT_PROB(0.5, delta_time)) - victim.visible_message(span_danger("The infection on the remnants of [victim]'s [limb.name] shift and bubble nauseatingly!"), span_warning("You can feel the infection on the remnants of your [limb.name] coursing through your veins!"), vision_distance = COMBAT_MESSAGE_RANGE) + victim.visible_message(span_danger("The infection on the remnants of [victim]'s [limb.plaintext_zone] shift and bubble nauseatingly!"), span_warning("You can feel the infection on the remnants of your [limb.plaintext_zone] coursing through your veins!"), vision_distance = COMBAT_MESSAGE_RANGE) return if(victim.reagents) @@ -63,7 +63,7 @@ // here's the check to see if we're cleared up if((flesh_damage <= 0) && (infestation <= WOUND_INFECTION_MODERATE)) - to_chat(victim, span_green("The burns on your [limb.name] have cleared up!")) + to_chat(victim, span_green("The burns on your [limb.plaintext_zone] have cleared up!")) qdel(src) return @@ -81,15 +81,15 @@ if(DT_PROB(15, delta_time)) victim.adjustToxLoss(0.2) if(prob(6)) - to_chat(victim, span_warning("The blisters on your [limb.name] ooze a strange pus...")) + to_chat(victim, span_warning("The blisters on your [limb.plaintext_zone] ooze a strange pus...")) if(WOUND_INFECTION_SEVERE to WOUND_INFECTION_CRITICAL) if(!disabling) if(DT_PROB(1, delta_time)) - to_chat(victim, span_warning("Your [limb.name] completely locks up, as you struggle for control against the infection!")) + to_chat(victim, span_warning("Your [limb.plaintext_zone] completely locks up, as you struggle for control against the infection!")) set_disabling(TRUE) return else if(DT_PROB(4, delta_time)) - to_chat(victim, span_notice("You regain sensation in your [limb.name], but it's still in terrible shape!")) + to_chat(victim, span_notice("You regain sensation in your [limb.plaintext_zone], but it's still in terrible shape!")) set_disabling(FALSE) return @@ -99,17 +99,17 @@ if(WOUND_INFECTION_CRITICAL to WOUND_INFECTION_SEPTIC) if(!disabling) if(DT_PROB(1.5, delta_time)) - to_chat(victim, span_warning("You suddenly lose all sensation of the festering infection in your [limb.name]!")) + to_chat(victim, span_warning("You suddenly lose all sensation of the festering infection in your [limb.plaintext_zone]!")) set_disabling(TRUE) return else if(DT_PROB(1.5, delta_time)) - to_chat(victim, span_notice("You can barely feel your [limb.name] again, and you have to strain to retain motor control!")) + to_chat(victim, span_notice("You can barely feel your [limb.plaintext_zone] again, and you have to strain to retain motor control!")) set_disabling(FALSE) return if(DT_PROB(2.48, delta_time)) if(prob(20)) - to_chat(victim, span_warning("You contemplate life without your [limb.name]...")) + to_chat(victim, span_warning("You contemplate life without your [limb.plaintext_zone]...")) victim.adjustToxLoss(0.75) else victim.adjustToxLoss(1) @@ -118,13 +118,13 @@ if(DT_PROB(0.5 * infestation, delta_time)) switch(strikes_to_lose_limb) if(3 to INFINITY) - to_chat(victim, span_deadsay("The skin on your [limb.name] is literally dripping off, you feel awful!")) + to_chat(victim, span_deadsay("The skin on your [limb.plaintext_zone] is literally dripping off, you feel awful!")) if(2) - to_chat(victim, span_deadsay("The infection in your [limb.name] is literally dripping off, you feel horrible!")) + to_chat(victim, span_deadsay("The infection in your [limb.plaintext_zone] is literally dripping off, you feel horrible!")) if(1) - to_chat(victim, span_deadsay("Infection has just about completely claimed your [limb.name]!")) + to_chat(victim, span_deadsay("Infection has just about completely claimed your [limb.plaintext_zone]!")) if(0) - to_chat(victim, span_deadsay("The last of the nerve endings in your [limb.name] wither away, as the infection completely paralyzes your joint connector.")) + to_chat(victim, span_deadsay("The last of the nerve endings in your [limb.plaintext_zone] wither away, as the infection completely paralyzes your joint connector.")) threshold_penalty = 120 // piss easy to destroy var/datum/brain_trauma/severe/paralysis/sepsis = new (limb.body_zone) victim.gain_trauma(sepsis) @@ -132,9 +132,9 @@ /datum/wound/burn/get_examine_description(mob/user) if(strikes_to_lose_limb <= 0) - return span_deadsay("[victim.p_their(TRUE)] [limb.name] has locked up completely and is non-functional.") + return span_deadsay("[victim.p_their(TRUE)] [limb.plaintext_zone] has locked up completely and is non-functional.") - var/list/condition = list("[victim.p_their(TRUE)] [limb.name] [examine_desc]") + var/list/condition = list("[victim.p_their(TRUE)] [limb.plaintext_zone] [examine_desc]") if(limb.current_gauze) var/bandage_condition switch(limb.current_gauze.absorption_capacity) @@ -157,7 +157,7 @@ if(WOUND_INFECTION_CRITICAL to WOUND_INFECTION_SEPTIC) condition += ", [span_deadsay("with streaks of rotten infection!")]" if(WOUND_INFECTION_SEPTIC to INFINITY) - return span_deadsay("[victim.p_their(TRUE)] [limb.name] is a mess of charred skin and infected rot!") + return span_deadsay("[victim.p_their(TRUE)] [limb.plaintext_zone] is a mess of charred skin and infected rot!") else condition += "!" @@ -197,20 +197,20 @@ /// if someone is using ointment or mesh on our burns /datum/wound/burn/proc/ointmentmesh(obj/item/stack/medical/I, mob/user) - user.visible_message(span_notice("[user] begins applying [I] to [victim]'s [limb.name]..."), span_notice("You begin applying [I] to [user == victim ? "your" : "[victim]'s"] [limb.name]...")) + user.visible_message(span_notice("[user] begins applying [I] to [victim]'s [limb.plaintext_zone]..."), span_notice("You begin applying [I] to [user == victim ? "your" : "[victim]'s"] [limb.plaintext_zone]...")) if (I.amount <= 0) return if(!do_after(user, (user == victim ? I.self_delay : I.other_delay), extra_checks = CALLBACK(src, .proc/still_exists))) return limb.heal_damage(I.heal_brute, I.heal_burn) - user.visible_message(span_green("[user] applies [I] to [victim]."), span_green("You apply [I] to [user == victim ? "your" : "[victim]'s"] [limb.name].")) + user.visible_message(span_green("[user] applies [I] to [victim]."), span_green("You apply [I] to [user == victim ? "your" : "[victim]'s"] [limb.plaintext_zone].")) I.use(1) sanitization += I.sanitization flesh_healing += I.flesh_regeneration if((infestation <= 0 || sanitization >= infestation) && (flesh_damage <= 0 || flesh_healing > flesh_damage)) - to_chat(user, span_notice("You've done all you can with [I], now you must wait for the flesh on [victim]'s [limb.name] to recover.")) + to_chat(user, span_notice("You've done all you can with [I], now you must wait for the flesh on [victim]'s [limb.plaintext_zone] to recover.")) else try_treating(I, user) @@ -220,10 +220,10 @@ to_chat(user, span_notice("[I] is still recharging!")) return if(infestation <= 0 || infestation < sanitization) - to_chat(user, span_notice("There's no infection to treat on [victim]'s [limb.name]!")) + to_chat(user, span_notice("There's no infection to treat on [victim]'s [limb.plaintext_zone]!")) return - user.visible_message(span_notice("[user] flashes the burns on [victim]'s [limb] with [I]."), span_notice("You flash the burns on [user == victim ? "your" : "[victim]'s"] [limb.name] with [I]."), vision_distance=COMBAT_MESSAGE_RANGE) + user.visible_message(span_notice("[user] flashes the burns on [victim]'s [limb] with [I]."), span_notice("You flash the burns on [user == victim ? "your" : "[victim]'s"] [limb.plaintext_zone] with [I]."), vision_distance=COMBAT_MESSAGE_RANGE) sanitization += I.uv_power COOLDOWN_START(I, uv_cooldown, I.uv_cooldown_length) @@ -245,7 +245,7 @@ if(flesh_healing > 0) flesh_damage = max(flesh_damage - (0.1 * delta_time), 0) if((flesh_damage <= 0) && (infestation <= 1)) - to_chat(victim, span_green("The burns on your [limb.name] have cleared up!")) + to_chat(victim, span_green("The burns on your [limb.plaintext_zone] have cleared up!")) qdel(src) return if(sanitization > 0) diff --git a/code/datums/wounds/pierce.dm b/code/datums/wounds/pierce.dm index 117385a92eaca..f96e4f27dce4f 100644 --- a/code/datums/wounds/pierce.dm +++ b/code/datums/wounds/pierce.dm @@ -40,14 +40,14 @@ if(1 to 6) victim.bleed(blood_bled, TRUE) if(7 to 13) - victim.visible_message("Blood droplets fly from the hole in [victim]'s [limb.name].", span_danger("You cough up a bit of blood from the blow to your [limb.name]."), vision_distance=COMBAT_MESSAGE_RANGE) + victim.visible_message("Blood droplets fly from the hole in [victim]'s [limb.plaintext_zone].", span_danger("You cough up a bit of blood from the blow to your [limb.plaintext_zone]."), vision_distance=COMBAT_MESSAGE_RANGE) victim.bleed(blood_bled, TRUE) if(14 to 19) - victim.visible_message("A small stream of blood spurts from the hole in [victim]'s [limb.name]!", span_danger("You spit out a string of blood from the blow to your [limb.name]!"), vision_distance=COMBAT_MESSAGE_RANGE) + victim.visible_message("A small stream of blood spurts from the hole in [victim]'s [limb.plaintext_zone]!", span_danger("You spit out a string of blood from the blow to your [limb.plaintext_zone]!"), vision_distance=COMBAT_MESSAGE_RANGE) new /obj/effect/temp_visual/dir_setting/bloodsplatter(victim.loc, victim.dir) victim.bleed(blood_bled) if(20 to INFINITY) - victim.visible_message(span_danger("A spray of blood streams from the gash in [victim]'s [limb.name]!"), span_danger("You choke up on a spray of blood from the blow to your [limb.name]!"), vision_distance=COMBAT_MESSAGE_RANGE) + victim.visible_message(span_danger("A spray of blood streams from the gash in [victim]'s [limb.plaintext_zone]!"), span_danger("You choke up on a spray of blood from the blow to your [limb.plaintext_zone]!"), vision_distance=COMBAT_MESSAGE_RANGE) victim.bleed(blood_bled) new /obj/effect/temp_visual/dir_setting/bloodsplatter(victim.loc, victim.dir) victim.add_splatter_floor(get_step(victim.loc, victim.dir)) @@ -65,7 +65,7 @@ if(victim.bodytemperature < (BODYTEMP_NORMAL - 10)) adjust_blood_flow(-0.1 * delta_time) if(DT_PROB(2.5, delta_time)) - to_chat(victim, span_notice("You feel the [lowertext(name)] in your [limb.name] firming up from the cold!")) + to_chat(victim, span_notice("You feel the [lowertext(name)] in your [limb.plaintext_zone] firming up from the cold!")) if(HAS_TRAIT(victim, TRAIT_BLOODY_MESS)) adjust_blood_flow(0.25 * delta_time) // old heparin used to just add +2 bleed stacks per tick, this adds 0.5 bleed flow to all open cuts which is probably even stronger as long as you can cut them first @@ -103,7 +103,7 @@ /// If someone is using a suture to close this puncture /datum/wound/pierce/proc/suture(obj/item/stack/medical/suture/I, mob/user) var/self_penalty_mult = (user == victim ? 1.4 : 1) - user.visible_message(span_notice("[user] begins stitching [victim]'s [limb.name] with [I]..."), span_notice("You begin stitching [user == victim ? "your" : "[victim]'s"] [limb.name] with [I]...")) + user.visible_message(span_notice("[user] begins stitching [victim]'s [limb.plaintext_zone] with [I]..."), span_notice("You begin stitching [user == victim ? "your" : "[victim]'s"] [limb.plaintext_zone] with [I]...")) if(!do_after(user, base_treat_time * self_penalty_mult, target=victim, extra_checks = CALLBACK(src, .proc/still_exists))) return user.visible_message(span_green("[user] stitches up some of the bleeding on [victim]."), span_green("You stitch up some of the bleeding on [user == victim ? "yourself" : "[victim]"].")) @@ -115,14 +115,14 @@ if(blood_flow > 0) try_treating(I, user) else - to_chat(user, span_green("You successfully close the hole in [user == victim ? "your" : "[victim]'s"] [limb.name].")) + to_chat(user, span_green("You successfully close the hole in [user == victim ? "your" : "[victim]'s"] [limb.plaintext_zone].")) /// If someone is using either a cautery tool or something with heat to cauterize this pierce /datum/wound/pierce/proc/tool_cauterize(obj/item/I, mob/user) var/improv_penalty_mult = (I.tool_behaviour == TOOL_CAUTERY ? 1 : 1.25) // 25% longer and less effective if you don't use a real cautery var/self_penalty_mult = (user == victim ? 1.5 : 1) // 50% longer and less effective if you do it to yourself - user.visible_message(span_danger("[user] begins cauterizing [victim]'s [limb.name] with [I]..."), span_warning("You begin cauterizing [user == victim ? "your" : "[victim]'s"] [limb.name] with [I]...")) + user.visible_message(span_danger("[user] begins cauterizing [victim]'s [limb.plaintext_zone] with [I]..."), span_warning("You begin cauterizing [user == victim ? "your" : "[victim]'s"] [limb.plaintext_zone] with [I]...")) if(!do_after(user, base_treat_time * self_penalty_mult * improv_penalty_mult, target=victim, extra_checks = CALLBACK(src, .proc/still_exists))) return diff --git a/code/datums/wounds/slash.dm b/code/datums/wounds/slash.dm index b81e03ab07d08..b2e32954b18a3 100644 --- a/code/datums/wounds/slash.dm +++ b/code/datums/wounds/slash.dm @@ -67,7 +67,7 @@ if(!limb.current_gauze) return ..() - var/list/msg = list("The cuts on [victim.p_their()] [limb.name] are wrapped with ") + var/list/msg = list("The cuts on [victim.p_their()] [limb.plaintext_zone] are wrapped with ") // how much life we have left in these bandages switch(limb.current_gauze.absorption_capacity) if(0 to 1.25) @@ -135,7 +135,7 @@ if(demotes_to) replace_wound(demotes_to) else - to_chat(victim, span_green("The cut on your [limb.name] has stopped bleeding!")) + to_chat(victim, span_green("The cut on your [limb.plaintext_zone] has stopped bleeding!")) qdel(src) @@ -188,13 +188,13 @@ continue user.ForceContractDisease(iter_disease) - user.visible_message(span_notice("[user] begins licking the wounds on [victim]'s [limb.name]."), span_notice("You begin licking the wounds on [victim]'s [limb.name]..."), ignored_mobs=victim) - to_chat(victim, span_notice("[user] begins to lick the wounds on your [limb.name].")) + user.visible_message(span_notice("[user] begins licking the wounds on [victim]'s [limb.plaintext_zone]."), span_notice("You begin licking the wounds on [victim]'s [limb.plaintext_zone]..."), ignored_mobs=victim) + to_chat(victim, span_notice("[user] begins to lick the wounds on your [limb.plaintext_zone].")) if(!do_after(user, base_treat_time, target=victim, extra_checks = CALLBACK(src, .proc/still_exists))) return - user.visible_message(span_notice("[user] licks the wounds on [victim]'s [limb.name]."), span_notice("You lick some of the wounds on [victim]'s [limb.name]"), ignored_mobs=victim) - to_chat(victim, span_green("[user] licks the wounds on your [limb.name]!")) + user.visible_message(span_notice("[user] licks the wounds on [victim]'s [limb.plaintext_zone]."), span_notice("You lick some of the wounds on [victim]'s [limb.plaintext_zone]"), ignored_mobs=victim) + to_chat(victim, span_green("[user] licks the wounds on your [limb.plaintext_zone]!")) adjust_blood_flow(-0.5) if(blood_flow > minimum_flow) @@ -213,7 +213,7 @@ /// If someone's putting a laser gun up to our cut to cauterize it /datum/wound/slash/proc/las_cauterize(obj/item/gun/energy/laser/lasgun, mob/user) var/self_penalty_mult = (user == victim ? 1.25 : 1) - user.visible_message(span_warning("[user] begins aiming [lasgun] directly at [victim]'s [limb.name]..."), span_userdanger("You begin aiming [lasgun] directly at [user == victim ? "your" : "[victim]'s"] [limb.name]...")) + user.visible_message(span_warning("[user] begins aiming [lasgun] directly at [victim]'s [limb.plaintext_zone]..."), span_userdanger("You begin aiming [lasgun] directly at [user == victim ? "your" : "[victim]'s"] [limb.plaintext_zone]...")) if(!do_after(user, base_treat_time * self_penalty_mult, target=victim, extra_checks = CALLBACK(src, .proc/still_exists))) return var/damage = lasgun.chambered.loaded_projectile.damage @@ -222,15 +222,15 @@ if(!lasgun.process_fire(victim, victim, TRUE, null, limb.body_zone)) return victim.emote("scream") - adjust_blood_flow(-damage / (5 * self_penalty_mult)) // 20 / 5 = 4 bloodflow removed, p good - victim.visible_message(span_warning("The cuts on [victim]'s [limb.name] scar over!")) + blood_flow -= damage / (5 * self_penalty_mult) // 20 / 5 = 4 bloodflow removed, p good + victim.visible_message(span_warning("The cuts on [victim]'s [limb.plaintext_zone] scar over!")) /// If someone is using either a cautery tool or something with heat to cauterize this cut /datum/wound/slash/proc/tool_cauterize(obj/item/I, mob/user) var/improv_penalty_mult = (I.tool_behaviour == TOOL_CAUTERY ? 1 : 1.25) // 25% longer and less effective if you don't use a real cautery var/self_penalty_mult = (user == victim ? 1.5 : 1) // 50% longer and less effective if you do it to yourself - user.visible_message(span_danger("[user] begins cauterizing [victim]'s [limb.name] with [I]..."), span_warning("You begin cauterizing [user == victim ? "your" : "[victim]'s"] [limb.name] with [I]...")) + user.visible_message(span_danger("[user] begins cauterizing [victim]'s [limb.plaintext_zone] with [I]..."), span_warning("You begin cauterizing [user == victim ? "your" : "[victim]'s"] [limb.plaintext_zone] with [I]...")) if(!do_after(user, base_treat_time * self_penalty_mult * improv_penalty_mult, target=victim, extra_checks = CALLBACK(src, .proc/still_exists))) return @@ -249,7 +249,7 @@ /// If someone is using a suture to close this cut /datum/wound/slash/proc/suture(obj/item/stack/medical/suture/I, mob/user) var/self_penalty_mult = (user == victim ? 1.4 : 1) - user.visible_message(span_notice("[user] begins stitching [victim]'s [limb.name] with [I]..."), span_notice("You begin stitching [user == victim ? "your" : "[victim]'s"] [limb.name] with [I]...")) + user.visible_message(span_notice("[user] begins stitching [victim]'s [limb.plaintext_zone] with [I]..."), span_notice("You begin stitching [user == victim ? "your" : "[victim]'s"] [limb.plaintext_zone] with [I]...")) if(!do_after(user, base_treat_time * self_penalty_mult, target=victim, extra_checks = CALLBACK(src, .proc/still_exists))) return diff --git a/code/game/alternate_appearance.dm b/code/game/alternate_appearance.dm index c5c8a72d4773f..f17315cdf2641 100644 --- a/code/game/alternate_appearance.dm +++ b/code/game/alternate_appearance.dm @@ -5,7 +5,7 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances) for(var/K in alternate_appearances) var/datum/atom_hud/alternate_appearance/AA = alternate_appearances[K] if(AA.appearance_key == key) - AA.remove_from_hud(src) + AA.remove_atom_from_hud(src) break /atom/proc/add_alt_appearance(type, key, ...) @@ -24,13 +24,16 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances) var/transfer_overlays = FALSE /datum/atom_hud/alternate_appearance/New(key) + // We use hud_icons to register our hud, so we need to do this before the parent call + appearance_key = key + hud_icons = list(appearance_key) ..() + GLOB.active_alternate_appearances += src - appearance_key = key for(var/mob in GLOB.player_list) if(mobShouldSee(mob)) - add_hud_to(mob) + show_to(mob) /datum/atom_hud/alternate_appearance/Destroy() GLOB.active_alternate_appearances -= src @@ -38,18 +41,18 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances) /datum/atom_hud/alternate_appearance/proc/onNewMob(mob/M) if(mobShouldSee(M)) - add_hud_to(M) + show_to(M) /datum/atom_hud/alternate_appearance/proc/mobShouldSee(mob/M) return FALSE -/datum/atom_hud/alternate_appearance/add_to_hud(atom/A, image/I) +/datum/atom_hud/alternate_appearance/add_atom_to_hud(atom/A, image/I) . = ..() if(.) LAZYINITLIST(A.alternate_appearances) A.alternate_appearances[appearance_key] = src -/datum/atom_hud/alternate_appearance/remove_from_hud(atom/A) +/datum/atom_hud/alternate_appearance/remove_atom_from_hud(atom/A) . = ..() if(.) LAZYREMOVE(A.alternate_appearances, appearance_key) @@ -63,6 +66,7 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances) var/image/image var/add_ghost_version = FALSE var/ghost_appearance + uses_global_hud_category = FALSE /datum/atom_hud/alternate_appearance/basic/New(key, image/I, options = AA_TARGET_SEE_APPEARANCE) ..() @@ -72,10 +76,11 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances) if(transfer_overlays) I.copy_overlays(target) - hud_icons = list(appearance_key) - add_to_hud(target, I) + add_atom_to_hud(target) + target.set_hud_image_active(appearance_key, exclusive_hud = src) + if((options & AA_TARGET_SEE_APPEARANCE) && ismob(target)) - add_hud_to(target) + show_to(target) if(add_ghost_version) var/image/ghost_image = image(icon = I.icon , icon_state = I.icon_state, loc = I.loc) ghost_image.override = FALSE @@ -89,14 +94,15 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances) if(ghost_appearance) QDEL_NULL(ghost_appearance) -/datum/atom_hud/alternate_appearance/basic/add_to_hud(atom/A) +/datum/atom_hud/alternate_appearance/basic/add_atom_to_hud(atom/A) LAZYINITLIST(A.hud_list) A.hud_list[appearance_key] = image . = ..() -/datum/atom_hud/alternate_appearance/basic/remove_from_hud(atom/A) +/datum/atom_hud/alternate_appearance/basic/remove_atom_from_hud(atom/A) . = ..() A.hud_list -= appearance_key + A.set_hud_image_inactive(appearance_key) if(. && !QDELETED(src)) qdel(src) diff --git a/code/game/area/ai_monitored.dm b/code/game/area/ai_monitored.dm index 7ca981cbcc090..84574d6badd27 100644 --- a/code/game/area/ai_monitored.dm +++ b/code/game/area/ai_monitored.dm @@ -1,10 +1,10 @@ -/area/ai_monitored +/area/station/ai_monitored name = "\improper AI Monitored Area" var/list/obj/machinery/camera/motioncameras = list() var/list/datum/weakref/motionTargets = list() sound_environment = SOUND_ENVIRONMENT_ROOM -/area/ai_monitored/Initialize(mapload) +/area/station/ai_monitored/Initialize(mapload) . = ..() if(mapload) for (var/obj/machinery/camera/M in src) @@ -14,7 +14,7 @@ //Only need to use one camera -/area/ai_monitored/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs) +/area/station/ai_monitored/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs) . = ..() if (ismob(arrived) && motioncameras.len) for(var/X in motioncameras) @@ -22,7 +22,7 @@ cam.newTarget(arrived) return -/area/ai_monitored/Exited(atom/movable/gone, atom/old_loc, list/atom/old_locs) +/area/station/ai_monitored/Exited(atom/movable/gone, atom/old_loc, list/atom/old_locs) ..() if (ismob(gone) && motioncameras.len) for(var/X in motioncameras) @@ -30,6 +30,6 @@ cam.lostTargetRef(WEAKREF(gone)) return -/area/ai_monitored/turret_protected/ai/Initialize(mapload) +/area/station/ai_monitored/turret_protected/ai/Initialize(mapload) . = ..() src.area_flags |= ABDUCTOR_PROOF diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 3e6dfc194de94..5970fc4851cd5 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -5,7 +5,7 @@ */ /area name = "Space" - icon = 'icons/turf/areas.dmi' + icon = 'icons/area/areas_misc.dmi' icon_state = "unknown" layer = AREA_LAYER //Keeping this on the default plane, GAME_PLANE, will make area overlays fail to render on FLOOR_PLANE. @@ -27,6 +27,8 @@ var/list/firealarms ///Alarm type to count of sources. Not usable for ^ because we handle fires differently var/list/active_alarms = list() + ///List of all lights in our area + var/list/lights = list() ///We use this just for fire alarms, because they're area based right now so one alarm going poof shouldn't prevent you from clearing your alarms listing. Fire alarms and fire locks will set and clear alarms. var/datum/alarm_handler/alarm_manager @@ -266,38 +268,22 @@ GLOBAL_LIST_EMPTY(teleportlocs) if (area_flags & NO_ALERTS) return //Trigger alarm effect - set_fire_alarm_effect() + set_fire_effect(TRUE) //Lockdown airlocks for(var/obj/machinery/door/door in src) close_and_lock_door(door) -/** - * Trigger the fire alarm visual affects in an area - * - * Updates the fire light on fire alarms in the area and sets all lights to emergency mode - */ -/area/proc/set_fire_alarm_effect() - if(fire) - return - fire = TRUE - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - for(var/obj/machinery/light/L in src) - L.update() - for(var/obj/machinery/firealarm/firepanel in firealarms) - firepanel.set_status() /** - * unset the fire alarm visual affects in an area + * Set the fire alarm visual affects in an area * - * Updates the fire light on fire alarms in the area and sets all lights to emergency mode + * Allows interested parties (lights and fire alarms) to react */ -/area/proc/unset_fire_alarm_effects() - fire = FALSE - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - for(var/obj/machinery/light/L in src) - L.update() - for(var/obj/machinery/firealarm/firepanel in firealarms) - firepanel.set_status() +/area/proc/set_fire_effect(new_fire) + if(new_fire == fire) + return + fire = new_fire + SEND_SIGNAL(src, COMSIG_AREA_FIRE_CHANGED, fire) /** * Update the icon state of the area diff --git a/code/game/area/areas/ai_monitored.dm b/code/game/area/areas/ai_monitored.dm new file mode 100644 index 0000000000000..19a3e50547310 --- /dev/null +++ b/code/game/area/areas/ai_monitored.dm @@ -0,0 +1,113 @@ +// Specfic AI monitored areas + +// Stub defined ai_monitored.dm +/area/station/ai_monitored + +/area/station/ai_monitored/turret_protected + +// AI +/area/station/ai_monitored + icon_state = "ai" + sound_environment = SOUND_AREA_STANDARD_STATION + +/area/station/ai_monitored/aisat/exterior + name = "\improper AI Satellite Exterior" + icon_state = "ai" + airlock_wires = /datum/wires/airlock/ai + +/area/station/ai_monitored/command/storage/satellite + name = "\improper AI Satellite Maint" + icon_state = "ai_storage" + ambience_index = AMBIENCE_DANGER + airlock_wires = /datum/wires/airlock/ai + +// Turret protected +/area/station/ai_monitored/turret_protected + ambientsounds = list('sound/ambience/ambitech.ogg', 'sound/ambience/ambitech2.ogg', 'sound/ambience/ambiatmos.ogg', 'sound/ambience/ambiatmos2.ogg') + ///Some sounds (like the space jam) are terrible when on loop. We use this varaible to add it to other AI areas, but override it to keep it from the AI's core. + var/ai_will_not_hear_this = list('sound/ambience/ambimalf.ogg') + airlock_wires = /datum/wires/airlock/ai + +/area/station/ai_monitored/turret_protected/Initialize(mapload) + . = ..() + if(ai_will_not_hear_this) + ambientsounds += ai_will_not_hear_this + +/area/station/ai_monitored/turret_protected/ai_upload + name = "\improper AI Upload Chamber" + icon_state = "ai_upload" + sound_environment = SOUND_AREA_SMALL_ENCLOSED + +/area/station/ai_monitored/turret_protected/ai_upload_foyer + name = "\improper AI Upload Access" + icon_state = "ai_upload_foyer" + sound_environment = SOUND_AREA_SMALL_ENCLOSED + +/area/station/ai_monitored/turret_protected/ai + name = "\improper AI Chamber" + icon_state = "ai_chamber" + ai_will_not_hear_this = null + +/area/station/ai_monitored/turret_protected/aisat + name = "\improper AI Satellite" + icon_state = "ai" + sound_environment = SOUND_ENVIRONMENT_ROOM + +/area/station/ai_monitored/turret_protected/aisat/atmos + name = "\improper AI Satellite Atmos" + icon_state = "ai" + +/area/station/ai_monitored/turret_protected/aisat/foyer + name = "\improper AI Satellite Foyer" + icon_state = "ai_foyer" + +/area/station/ai_monitored/turret_protected/aisat/service + name = "\improper AI Satellite Service" + icon_state = "ai" + +/area/station/ai_monitored/turret_protected/aisat/hallway + name = "\improper AI Satellite Hallway" + icon_state = "ai" + +/area/station/ai_monitored/turret_protected/aisat/maint + name = "\improper AI Satellite Maintenance" + icon_state = "ai_maint" + +/area/station/ai_monitored/turret_protected/aisat_interior + name = "\improper AI Satellite Antechamber" + icon_state = "ai_interior" + sound_environment = SOUND_AREA_LARGE_ENCLOSED + +/area/station/ai_monitored/turret_protected/ai_sat_ext_as + name = "\improper AI Sat Ext" + icon_state = "ai_sat_east" + +/area/station/ai_monitored/turret_protected/ai_sat_ext_ap + name = "\improper AI Sat Ext" + icon_state = "ai_sat_west" + +// Station specific ai monitored rooms, move here for consistenancy + +//Command - AI Monitored +/area/station/ai_monitored/command/storage/eva + name = "EVA Storage" + icon_state = "eva" + ambience_index = AMBIENCE_DANGER + +/area/station/ai_monitored/command/storage/eva/upper + name = "Upper EVA Storage" + +/area/station/ai_monitored/command/nuke_storage + name = "\improper Vault" + icon_state = "nuke_storage" + airlock_wires = /datum/wires/airlock/command + +//Security - AI Monitored +/area/station/ai_monitored/security/armory + name = "\improper Armory" + icon_state = "armory" + ambience_index = AMBIENCE_DANGER + airlock_wires = /datum/wires/airlock/security + +/area/station/ai_monitored/security/armory/upper + name = "Upper Armory" diff --git a/code/game/area/areas/away_content.dm b/code/game/area/areas/away_content.dm index b13cf4f8cbe80..5841f744ecd6f 100644 --- a/code/game/area/areas/away_content.dm +++ b/code/game/area/areas/away_content.dm @@ -6,6 +6,7 @@ Unused icons for new areas are "awaycontent1" ~ "awaycontent30" // Away Missions /area/awaymission name = "Strange Location" + icon = 'icons/area/areas_away_missions.dmi' icon_state = "away" has_gravity = STANDARD_GRAVITY ambience_index = AMBIENCE_AWAY diff --git a/code/game/area/areas/centcom.dm b/code/game/area/areas/centcom.dm index 0d82b3ffd403d..01e5282c48c60 100644 --- a/code/game/area/areas/centcom.dm +++ b/code/game/area/areas/centcom.dm @@ -1,12 +1,18 @@ // CENTCOM -// Side note, be sure to change the network_root_id of any areas that are not a part of centcom -// and just using the z space as safe harbor. It shouldn't matter much as centcom z is isolated -// from everything anyway +/* +Side note, be sure to change the network_root_id of any areas that are not a part of centcom +and just using the z space as safe harbor. It shouldn't matter much as centcom z is isolated +from everything anyway. +The areas used here are STRICTLY on the CC Z level. +*/ + +// CentCom itself /area/centcom name = "CentCom" + icon = 'icons/area/areas_centcom.dmi' icon_state = "centcom" static_lighting = TRUE requires_power = FALSE @@ -14,83 +20,86 @@ area_flags = UNIQUE_AREA | NOTELEPORT flags_1 = NONE -/area/centcom/control +// This is just to define the category +/area/centcom/central_command_areas + name = "Central Command Areas" + +/area/centcom/central_command_areas/control name = "CentCom Central Control" icon_state = "centcom_control" -/area/centcom/evacuation +/area/centcom/central_command_areas/evacuation name = "CentCom Recovery Wing" icon_state = "centcom_evacuation" -/area/centcom/evacuation/ship +/area/centcom/central_command_areas/evacuation/ship name = "CentCom Recovery Ship" icon_state = "centcom_evacuation_ship" -/area/centcom/fore +/area/centcom/central_command_areas/fore name = "Fore CentCom Dock" icon_state = "centcom_fore" -/area/centcom/supply +/area/centcom/central_command_areas/supply name = "CentCom Supply Wing" icon_state = "centcom_supply" -/area/centcom/ferry +/area/centcom/central_command_areas/ferry name = "CentCom Transport Shuttle Dock" icon_state = "centcom_ferry" -/area/centcom/briefing +/area/centcom/central_command_areas/briefing name = "CentCom Briefing Room" icon_state = "centcom_briefing" -/area/centcom/armory +/area/centcom/central_command_areas/armory name = "CentCom Armory" icon_state = "centcom_armory" -/area/centcom/admin +/area/centcom/central_command_areas/admin name = "CentCom Administrative Office" icon_state = "centcom_admin" -/area/centcom/admin/storage +/area/centcom/central_command_areas/admin/storage name = "CentCom Administrative Office Storage" icon_state = "centcom_admin_storage" -/area/centcom/prison +/area/centcom/central_command_areas/prison name = "Admin Prison" icon_state = "centcom_prison" -/area/centcom/prison/cells +/area/centcom/central_command_areas/prison/cells name = "Admin Prison Cells" icon_state = "centcom_cells" -/area/centcom/courtroom +/area/centcom/central_command_areas/courtroom name = "Nanotrasen Grand Courtroom" icon_state = "centcom_court" -/area/centcom/holding +/area/centcom/central_command_areas/holding name = "Holding Facility" icon_state = "centcom_holding" -/area/centcom/supplypod/supplypod_temp_holding +/area/centcom/central_command_areas/supplypod/supplypod_temp_holding name = "Supplypod Shipping Lane" icon_state = "supplypod_flight" -/area/centcom/supplypod +/area/centcom/central_command_areas/supplypod name = "Supplypod Facility" icon_state = "supplypod" static_lighting = FALSE - base_lighting_alpha = 255 -/area/centcom/supplypod/pod_storage +/area/centcom/central_command_areas/supplypod/pod_storage name = "Supplypod Storage" icon_state = "supplypod_holding" -/area/centcom/supplypod/loading +/area/centcom/central_command_areas/supplypod/loading name = "Supplypod Loading Facility" icon_state = "supplypod_loading" var/loading_id = "" -/area/centcom/supplypod/loading/Initialize(mapload) +/area/centcom/central_command_areas/supplypod/loading/Initialize(mapload) . = ..() if(!loading_id) CRASH("[type] created without a loading_id") @@ -98,71 +107,68 @@ CRASH("Duplicate loading bay area: [type] ([loading_id])") GLOB.supplypod_loading_bays[loading_id] = src -/area/centcom/supplypod/loading/one +/area/centcom/central_command_areas/supplypod/loading/one name = "Bay #1" loading_id = "1" -/area/centcom/supplypod/loading/two +/area/centcom/central_command_areas/supplypod/loading/two name = "Bay #2" loading_id = "2" -/area/centcom/supplypod/loading/three +/area/centcom/central_command_areas/supplypod/loading/three name = "Bay #3" loading_id = "3" -/area/centcom/supplypod/loading/four +/area/centcom/central_command_areas/supplypod/loading/four name = "Bay #4" loading_id = "4" -/area/centcom/supplypod/loading/ert +/area/centcom/central_command_areas/supplypod/loading/ert name = "ERT Bay" loading_id = "5" -//THUNDERDOME -/area/tdome +//THUNDERDOME +/area/centcom/tdome name = "Thunderdome" - icon_state = "yellow" + icon_state = "thunder" static_lighting = TRUE requires_power = FALSE has_gravity = STANDARD_GRAVITY flags_1 = NONE -/area/tdome/arena +/area/centcom/tdome/arena name = "Thunderdome Arena" icon_state = "thunder" static_lighting = FALSE base_lighting_alpha = 255 - -/area/tdome/arena_source +/area/centcom/tdome/arena_source name = "Thunderdome Arena Template" icon_state = "thunder" static_lighting = FALSE base_lighting_alpha = 255 - -/area/tdome/tdome1 +/area/centcom/tdome/tdome1 name = "Thunderdome (Team 1)" - icon_state = "green" + icon_state = "thunder_team_one" -/area/tdome/tdome2 +/area/centcom/tdome/tdome2 name = "Thunderdome (Team 2)" - icon_state = "green" + icon_state = "thunder_team_two" -/area/tdome/tdomeadmin //delete this -/area/tdome/administration +/area/centcom/tdome/administration name = "Thunderdome Administration" icon_state = "thunder_admin" -/area/tdome/observation +/area/centcom/tdome/observation name = "Thunderdome Observation" icon_state = "thunder_observe" -//ENEMY +// ENEMY -//Wizard -/area/wizard_station +// Wizard +/area/centcom/wizard_station name = "Wizard's Den" icon_state = "wizards_den" static_lighting = TRUE @@ -173,7 +179,7 @@ network_root_id = "MAGIC_NET" //Abductors -/area/abductor_ship +/area/centcom/abductor_ship name = "Abductor Ship" icon_state = "abductor_ship" requires_power = FALSE @@ -185,7 +191,7 @@ network_root_id = "ALIENS" //Syndicates -/area/syndicate_mothership +/area/centcom/syndicate_mothership name = "Syndicate Mothership" icon_state = "syndie-ship" requires_power = FALSE @@ -195,73 +201,103 @@ ambience_index = AMBIENCE_DANGER network_root_id = SYNDICATE_NETWORK_ROOT -/area/syndicate_mothership/control +/area/centcom/syndicate_mothership/control name = "Syndicate Control Room" icon_state = "syndie-control" static_lighting = TRUE -/area/syndicate_mothership/expansion_bombthreat +/area/centcom/syndicate_mothership/expansion_bombthreat name = "Syndicate Ordnance Laboratory" icon_state = "syndie-elite" static_lighting = TRUE ambience_index = AMBIENCE_ENGI -/area/syndicate_mothership/expansion_bioterrorism +/area/centcom/syndicate_mothership/expansion_bioterrorism name = "Syndicate Bio-Weapon Laboratory" icon_state = "syndie-elite" static_lighting = TRUE ambience_index = AMBIENCE_MEDICAL -/area/syndicate_mothership/expansion_chemicalwarfare +/area/centcom/syndicate_mothership/expansion_chemicalwarfare name = "Syndicate Chemical Weapon Manufacturing Plant" icon_state = "syndie-elite" static_lighting = TRUE ambience_index = AMBIENCE_REEBE -/area/syndicate_mothership/expansion_fridgerummage +/area/centcom/syndicate_mothership/expansion_fridgerummage name = "Syndicate Perishables and Foodstuffs Storage" icon_state = "syndie-elite" static_lighting = TRUE -/area/syndicate_mothership/elite_squad +/area/centcom/syndicate_mothership/elite_squad name = "Syndicate Elite Squad" icon_state = "syndie-elite" //CAPTURE THE FLAG - -/area/ctf +/area/centcom/ctf name = "Capture the Flag" - icon_state = "yellow" + icon_state = "ctf" requires_power = FALSE static_lighting = FALSE - base_lighting_alpha = 255 has_gravity = STANDARD_GRAVITY flags_1 = NONE -/area/ctf/control_room +/area/centcom/ctf/control_room name = "Control Room A" + icon_state = "ctf_room_a" -/area/ctf/control_room2 +/area/centcom/ctf/control_room2 name = "Control Room B" + icon_state = "ctf_room_b" -/area/ctf/central +/area/centcom/ctf/central name = "Central" + icon_state = "ctf_central" -/area/ctf/main_hall +/area/centcom/ctf/main_hall name = "Main Hall A" + icon_state = "ctf_hall_a" -/area/ctf/main_hall2 +/area/centcom/ctf/main_hall2 name = "Main Hall B" + icon_state = "ctf_hall_b" -/area/ctf/corridor +/area/centcom/ctf/corridor name = "Corridor A" + icon_state = "ctf_corr_a" -/area/ctf/corridor2 +/area/centcom/ctf/corridor2 name = "Corridor B" + icon_state = "ctf_corr_b" -/area/ctf/flag_room +/area/centcom/ctf/flag_room name = "Flag Room A" + icon_state = "ctf_flag_a" -/area/ctf/flag_room2 +/area/centcom/ctf/flag_room2 name = "Flag Room B" + icon_state = "ctf_flag_b" + +// Asteroid area stuff +/area/centcom/asteroid + name = "\improper Asteroid" + icon_state = "asteroid" + requires_power = FALSE + has_gravity = STANDARD_GRAVITY + area_flags = UNIQUE_AREA + ambience_index = AMBIENCE_MINING + flags_1 = CAN_BE_DIRTY_1 + sound_environment = SOUND_AREA_ASTEROID + min_ambience_cooldown = 70 SECONDS + max_ambience_cooldown = 220 SECONDS + +/area/centcom/asteroid/nearstation + static_lighting = TRUE + ambience_index = AMBIENCE_RUINS + always_unpowered = FALSE + requires_power = TRUE + area_flags = UNIQUE_AREA | BLOBS_ALLOWED + +/area/centcom/asteroid/nearstation/bomb_site + name = "\improper Bomb Testing Asteroid" diff --git a/code/game/area/areas/holodeck.dm b/code/game/area/areas/holodeck.dm index c900e99c89c20..ecd728e78316b 100644 --- a/code/game/area/areas/holodeck.dm +++ b/code/game/area/areas/holodeck.dm @@ -1,5 +1,6 @@ -/area/holodeck +/area/station/holodeck name = "Holodeck" + icon = 'icons/area/areas_station.dmi' icon_state = "Holodeck" static_lighting = FALSE @@ -15,7 +16,7 @@ Asserts are to avoid the inevitable infinite loops */ -/area/holodeck/powered(chan) +/area/station/holodeck/powered(chan) if(!requires_power) return TRUE if(always_unpowered) @@ -23,21 +24,21 @@ if(!linked) return FALSE var/area/A = get_area(linked) - ASSERT(!istype(A, /area/holodeck)) + ASSERT(!istype(A, /area/station/holodeck)) return A.powered(chan) -/area/holodeck/addStaticPower(value, powerchannel) +/area/station/holodeck/addStaticPower(value, powerchannel) if(!linked) return var/area/A = get_area(linked) - ASSERT(!istype(A, /area/holodeck)) + ASSERT(!istype(A, /area/station/holodeck)) return ..() -/area/holodeck/use_power(amount, chan) +/area/station/holodeck/use_power(amount, chan) if(!linked) return FALSE var/area/A = get_area(linked) - ASSERT(!istype(A, /area/holodeck)) + ASSERT(!istype(A, /area/station/holodeck)) return ..() @@ -46,8 +47,9 @@ blow off steam by doing stupid things like laying down, throwing spheres at holes, or bludgeoning people. */ -/area/holodeck/rec_center +/area/station/holodeck/rec_center name = "\improper Recreational Holodeck" -/area/holodeck/rec_center/offstation_one +// Don't move this to be organized like with most areas, theres too much touching holodeck code as is +/area/station/holodeck/rec_center/offstation_one name = "\improper Recreational Holodeck" diff --git a/code/game/area/areas/mining.dm b/code/game/area/areas/mining.dm index 038f9bc6efa3c..57ed48b9ce279 100644 --- a/code/game/area/areas/mining.dm +++ b/code/game/area/areas/mining.dm @@ -1,6 +1,7 @@ /**********************Mine areas**************************/ /area/mine + icon = 'icons/area/areas_station.dmi' icon_state = "mining" has_gravity = STANDARD_GRAVITY area_flags = VALID_TERRITORY | UNIQUE_AREA | FLORA_ALLOWED | CULT_PERMITTED @@ -97,6 +98,7 @@ /**********************Lavaland Areas**************************/ /area/lavaland + icon = 'icons/area/areas_station.dmi' icon_state = "mining" has_gravity = STANDARD_GRAVITY flags_1 = NONE @@ -151,6 +153,7 @@ /**********************Ice Moon Areas**************************/ /area/icemoon + icon = 'icons/area/areas_station.dmi' icon_state = "mining" has_gravity = STANDARD_GRAVITY flags_1 = NONE diff --git a/code/game/area/areas/misc.dm b/code/game/area/areas/misc.dm new file mode 100644 index 0000000000000..d31b978b6c630 --- /dev/null +++ b/code/game/area/areas/misc.dm @@ -0,0 +1,35 @@ +// Areas that don't fit any of the other files, or only serve one purpose. + +/area/space + icon_state = "space" + requires_power = TRUE + always_unpowered = TRUE + static_lighting = FALSE + + base_lighting_alpha = 255 + power_light = FALSE + power_equip = FALSE + power_environ = FALSE + area_flags = UNIQUE_AREA | NO_ALERTS + outdoors = TRUE + ambience_index = AMBIENCE_SPACE + flags_1 = CAN_BE_DIRTY_1 + sound_environment = SOUND_AREA_SPACE + +/area/space/nearstation + icon_state = "space_near" + area_flags = UNIQUE_AREA | NO_ALERTS | AREA_USES_STARLIGHT + +/area/misc/start + name = "start area" + icon_state = "start" + requires_power = FALSE + static_lighting = FALSE + base_lighting_alpha = 255 + has_gravity = STANDARD_GRAVITY + +/area/misc/testroom + requires_power = FALSE + has_gravity = STANDARD_GRAVITY + name = "Test Room" + icon_state = "test_room" diff --git a/code/game/area/areas/ruins/_ruins.dm b/code/game/area/areas/ruins/_ruins.dm index c77051d506eff..9fa3510b60b21 100644 --- a/code/game/area/areas/ruins/_ruins.dm +++ b/code/game/area/areas/ruins/_ruins.dm @@ -2,7 +2,8 @@ /area/ruin name = "\improper Unexplored Location" - icon_state = "away" + icon = 'icons/area/areas_ruins.dmi' + icon_state = "ruins" has_gravity = STANDARD_GRAVITY area_flags = HIDDEN_AREA | BLOBS_ALLOWED | UNIQUE_AREA | NO_ALERTS static_lighting = TRUE diff --git a/code/game/area/areas/ruins/icemoon.dm b/code/game/area/areas/ruins/icemoon.dm index 79875fdf3711c..5395c4d94916d 100644 --- a/code/game/area/areas/ruins/icemoon.dm +++ b/code/game/area/areas/ruins/icemoon.dm @@ -2,11 +2,9 @@ /area/ruin/unpowered/buried_library name = "\improper Buried Library" - icon_state = "dk_yellow" /area/ruin/powered/bathhouse name = "\improper Bath House" - icon_state = "dk_yellow" mood_bonus = 10 mood_message = "I wish I could stay here forever." @@ -20,36 +18,29 @@ /area/ruin/powered/mailroom name = "\improper Abandoned Post Office" - icon_state = "dk_yellow" /area/ruin/plasma_facility/commons name = "\improper Abandoned Plasma Facility Commons" - icon_state = "dk_yellow" sound_environment = SOUND_AREA_STANDARD_STATION mood_bonus = -5 mood_message = "I feel like I am being watched..." /area/ruin/plasma_facility/operations name = "\improper Abandoned Plasma Facility Operations" - icon_state = "dk_yellow" sound_environment = SOUND_AREA_SMALL_ENCLOSED mood_bonus = -5 mood_message = "I feel like I am being watched..." /area/ruin/bughabitat name = "\improper Entemology Outreach Center" - icon_state = "dk_yellow" mood_bonus = 1 mood_message = "This place seems strangely serene." /area/ruin/pizzeria name = "\improper Moffuchi's Pizzeria" - icon_state = "red" /area/ruin/pizzeria/kitchen name = "\improper Moffuchi's Kitchen" - icon_state = "dk_yellow" /area/ruin/planetengi name = "\improper Engineering Outpost" - icon_state = "red" diff --git a/code/game/area/areas/ruins/lavaland.dm b/code/game/area/areas/ruins/lavaland.dm index 7ed414c3cd7d2..514cb6ab624d1 100644 --- a/code/game/area/areas/ruins/lavaland.dm +++ b/code/game/area/areas/ruins/lavaland.dm @@ -2,51 +2,38 @@ //NOTICE: /unpowered means you never get power. Thanks Fikou /area/ruin/powered/beach - icon_state = "dk_yellow" /area/ruin/powered/clownplanet name = "\improper Clown Planet" - icon_state = "dk_yellow" ambientsounds = list('sound/ambience/clown.ogg') /area/ruin/unpowered/gaia name = "\improper Patch of Eden" - icon_state = "dk_yellow" /area/ruin/powered/snow_biodome - icon_state = "dk_yellow" /area/ruin/powered/gluttony - icon_state = "dk_yellow" /area/ruin/powered/golem_ship name = "\improper Free Golem Ship" - icon_state = "dk_yellow" /area/ruin/powered/greed - icon_state = "dk_yellow" /area/ruin/unpowered/hierophant name = "\improper Hierophant's Arena" - icon_state = "dk_yellow" /area/ruin/powered/pride - icon_state = "dk_yellow" /area/ruin/powered/seedvault - icon_state = "dk_yellow" /area/ruin/unpowered/elephant_graveyard name = "\improper Elephant Graveyard" - icon_state = "dk_yellow" /area/ruin/powered/graveyard_shuttle name = "\improper Elephant Graveyard" - icon_state = "green" /area/ruin/syndicate_lava_base name = "\improper Secret Base" - icon_state = "dk_yellow" ambience_index = AMBIENCE_DANGER /area/ruin/unpowered/cultaltar @@ -99,8 +86,6 @@ power_light = FALSE //ash walker nest /area/ruin/unpowered/ash_walkers - icon_state = "red" /area/ruin/unpowered/ratvar - icon_state = "dk_yellow" outdoors = TRUE diff --git a/code/game/area/areas/ruins/space.dm b/code/game/area/areas/ruins/space.dm index afc95bb257323..e71e84ddb7416 100644 --- a/code/game/area/areas/ruins/space.dm +++ b/code/game/area/areas/ruins/space.dm @@ -10,32 +10,34 @@ /area/ruin/space/has_grav/powered requires_power = FALSE -///////////// + +// Ruin solars define, /area/solars was moved to /area/station/solars, causing the solars specific areas to lose their properties +/area/ruin/solars + requires_power = FALSE + area_flags = UNIQUE_AREA | AREA_USES_STARLIGHT + flags_1 = NONE + ambience_index = AMBIENCE_ENGI + airlock_wires = /datum/wires/airlock/engineering + sound_environment = SOUND_AREA_SPACE + base_lighting_alpha = 255 /area/ruin/space/way_home name = "\improper Salvation" - icon_state = "away" always_unpowered = FALSE // Ruins of "onehalf" ship /area/ruin/space/has_grav/onehalf/hallway name = "\improper Hallway" - icon_state = "hallC" /area/ruin/space/has_grav/onehalf/drone_bay name = "\improper Mining Drone Bay" - icon_state = "engine" /area/ruin/space/has_grav/onehalf/dorms_med name = "\improper Crew Quarters" - icon_state = "Sleep" /area/ruin/space/has_grav/onehalf/bridge name = "\improper Bridge" - icon_state = "bridge" - - /area/ruin/space/has_grav/powered/dinner_for_two name = "Dinner for Two" @@ -58,7 +60,6 @@ /area/ruin/space/has_grav/hotel/guestroom name = "\improper Hotel Guest Room" - icon_state = "Sleep" /area/ruin/space/has_grav/hotel/guestroom/room_1 name = "\improper Hotel Guest Room 1" @@ -80,85 +81,65 @@ /area/ruin/space/has_grav/hotel/security name = "\improper Hotel Security Post" - icon_state = "security" /area/ruin/space/has_grav/hotel/pool name = "\improper Hotel Pool Room" - icon_state = "fitness" /area/ruin/space/has_grav/hotel/bar name = "\improper Hotel Bar" - icon_state = "cafeteria" /area/ruin/space/has_grav/hotel/power name = "\improper Hotel Power Room" - icon_state = "engine_smes" /area/ruin/space/has_grav/hotel/custodial name = "\improper Hotel Custodial Closet" - icon_state = "janitor" /area/ruin/space/has_grav/hotel/shuttle name = "\improper Hotel Shuttle" - icon_state = "shuttle" requires_power = FALSE /area/ruin/space/has_grav/hotel/dock name = "\improper Hotel Shuttle Dock" - icon_state = "start" /area/ruin/space/has_grav/hotel/workroom name = "\improper Hotel Staff Room" - icon_state = "crew_quarters" /area/ruin/space/has_grav/hotel/storeroom name = "\improper Hotel Staff Storage" - icon_state = "crew_quarters" - - - //Ruin of Derelict Oupost /area/ruin/space/has_grav/derelictoutpost name = "\improper Derelict Outpost" - icon_state = "green" /area/ruin/space/has_grav/derelictoutpost/cargostorage name = "\improper Derelict Outpost Cargo Storage" - icon_state = "storage" /area/ruin/space/has_grav/derelictoutpost/cargobay name = "\improper Derelict Outpost Cargo Bay" - icon_state = "quartstorage" /area/ruin/space/has_grav/derelictoutpost/powerstorage name = "\improper Derelict Outpost Power Storage" - icon_state = "engine_smes" /area/ruin/space/has_grav/derelictoutpost/dockedship name = "\improper Derelict Outpost Docked Ship" - icon_state = "red" //Ruin of turretedoutpost /area/ruin/space/has_grav/turretedoutpost name = "\improper Turreted Outpost" - icon_state = "red" //Ruin of old teleporter /area/ruin/space/oldteleporter name = "\improper Old Teleporter" - icon_state = "teleporter" //Ruin of mech transport /area/ruin/space/has_grav/powered/mechtransport name = "\improper Mech Transport" - icon_state = "green" //Ruin of The Lizard's Gas (Station) @@ -171,225 +152,212 @@ /area/ruin/space/has_grav/deepstorage name = "Deep Storage" - icon_state = "storage" /area/ruin/space/has_grav/deepstorage/airlock name = "\improper Deep Storage Airlock" - icon_state = "quart" /area/ruin/space/has_grav/deepstorage/power name = "\improper Deep Storage Power and Atmospherics Room" - icon_state = "engi_storage" /area/ruin/space/has_grav/deepstorage/hydroponics name = "Deep Storage Hydroponics" - icon_state = "garden" /area/ruin/space/has_grav/deepstorage/armory name = "\improper Deep Storage Secure Storage" - icon_state = "armory" /area/ruin/space/has_grav/deepstorage/storage name = "\improper Deep Storage Storage" - icon_state = "storage_wing" /area/ruin/space/has_grav/deepstorage/dorm name = "\improper Deep Storage Dormitory" - icon_state = "crew_quarters" /area/ruin/space/has_grav/deepstorage/kitchen name = "\improper Deep Storage Kitchen" - icon_state = "kitchen" /area/ruin/space/has_grav/deepstorage/crusher name = "\improper Deep Storage Recycler" - icon_state = "storage" - +/area/ruin/space/has_grav/deepstorage/pharmacy + name = "\improper Deep Storage Pharmacy" + //Ruin of Abandoned Zoo /area/ruin/space/has_grav/abandonedzoo name = "\improper Abandoned Zoo" - icon_state = "green" //Ruin of ancient Space Station (OldStation) -/area/ruin/space/has_grav/ancientstation +/area/ruin/space/ancientstation icon_state = "oldstation" - has_gravity = TRUE - -/area/ruin/space/has_grav/ancientstation/powered +/area/ruin/space/ancientstation/powered name = "Powered Tile" icon_state = "teleporter" requires_power = FALSE -/area/ruin/space/has_grav/ancientstation/space - name = "Exposed To Space" - icon_state = "teleporter" - has_gravity = FALSE - -/area/ruin/space/has_grav/ancientstation/beta +/area/ruin/space/ancientstation/beta icon_state = "betastation" -/area/ruin/space/has_grav/ancientstation/beta/atmos +/area/ruin/space/ancientstation/beta/atmos name = "Beta Station Atmospherics" icon_state = "os_beta_atmos" ambience_index = AMBIENCE_ENGI -/area/ruin/space/has_grav/ancientstation/beta/hall +/area/ruin/space/ancientstation/beta/supermatter + name = "Beta Station Supermatter chamber" + icon_state = "os_beta_engine" + +/area/ruin/space/ancientstation/beta/hall name = "Beta Station Main Corridor" icon_state = "os_beta_hall" -/area/ruin/space/has_grav/ancientstation/beta/mining +/area/ruin/space/ancientstation/beta/gravity + name = "Beta Station Gravity Generator" + icon_state = "os_beta_gravity" + +/area/ruin/space/ancientstation/beta/mining name = "Beta Station Mining Equipment" icon_state = "os_beta_mining" + ambience_index = AMBIENCE_MINING -/area/ruin/space/has_grav/ancientstation/beta/medbay +/area/ruin/space/ancientstation/beta/medbay name = "Beta Station Medbay" icon_state = "os_beta_medbay" + ambience_index = AMBIENCE_MEDICAL -/area/ruin/space/has_grav/ancientstation/beta/storage +/area/ruin/space/ancientstation/beta/storage name = "\improper Beta Station Storage" icon_state = "os_beta_storage" -/area/ruin/space/has_grav/ancientstation/charlie +/area/ruin/space/ancientstation/charlie icon_state = "charliestation" -/area/ruin/space/has_grav/ancientstation/charlie/hall +/area/ruin/space/ancientstation/charlie/hall name = "Charlie Station Main Corridor" icon_state = "os_charlie_hall" -/area/ruin/space/has_grav/ancientstation/charlie/engie +/area/ruin/space/ancientstation/charlie/engie name = "Charlie Station Engineering" icon_state = "os_charlie_engine" ambience_index = AMBIENCE_ENGI -/area/ruin/space/has_grav/ancientstation/charlie/bridge +/area/ruin/space/ancientstation/charlie/bridge name = "Charlie Station Command" icon_state = "os_charlie_bridge" -/area/ruin/space/has_grav/ancientstation/charlie/hydro +/area/ruin/space/ancientstation/charlie/hydro name = "Charlie Station Hydroponics" icon_state = "os_charlie_hydro" -/area/ruin/space/has_grav/ancientstation/charlie/kitchen +/area/ruin/space/ancientstation/charlie/kitchen name = "\improper Charlie Station Kitchen" icon_state = "os_charlie_kitchen" -/area/ruin/space/has_grav/ancientstation/charlie/sec +/area/ruin/space/ancientstation/charlie/sec name = "Charlie Station Security" icon_state = "os_charlie_sec" -/area/ruin/space/has_grav/ancientstation/charlie/dorms +/area/ruin/space/ancientstation/charlie/dorms name = "Charlie Station Dorms" icon_state = "os_charlie_dorms" -/area/solars/ancientstation/charlie/solars +/area/ruin/solars/ancientstation/charlie/solars name = "\improper Charlie Station Solar Array" + icon = 'icons/area/areas_ruins.dmi' // Solars inheriet areas_misc.dmi, not areas_ruin.dmi icon_state = "os_charlie_solars" + requires_power = FALSE + area_flags = UNIQUE_AREA | AREA_USES_STARLIGHT + sound_environment = SOUND_AREA_SPACE + base_lighting_alpha = 255 -/area/ruin/space/has_grav/ancientstation/charlie/storage +/area/ruin/space/ancientstation/charlie/storage name = "Charlie Station Storage" icon_state = "os_charlie_storage" -/area/ruin/space/has_grav/ancientstation/delta +/area/ruin/space/ancientstation/delta icon_state = "deltastation" -/area/ruin/space/has_grav/ancientstation/delta/hall +/area/ruin/space/ancientstation/delta/hall name = "Delta Station Main Corridor" icon_state = "os_delta_hall" -/area/ruin/space/has_grav/ancientstation/delta/proto +/area/ruin/space/ancientstation/delta/proto name = "\improper Delta Station Prototype Lab" icon_state = "os_delta_protolab" -/area/ruin/space/has_grav/ancientstation/delta/rnd +/area/ruin/space/ancientstation/delta/rnd name = "Delta Station Research and Development" icon_state = "os_delta_rnd" -/area/ruin/space/has_grav/ancientstation/delta/ai +/area/ruin/space/ancientstation/delta/ai name = "\improper Delta Station AI Core" icon_state = "os_delta_ai" ambientsounds = list('sound/ambience/ambimalf.ogg', 'sound/ambience/ambitech.ogg', 'sound/ambience/ambitech2.ogg', 'sound/ambience/ambiatmos.ogg', 'sound/ambience/ambiatmos2.ogg') -/area/ruin/space/has_grav/ancientstation/delta/storage +/area/ruin/space/ancientstation/delta/storage name = "\improper Delta Station Storage" icon_state = "os_delta_storage" +/area/ruin/space/ancientstation/delta/biolab + name = "Delta Station Biolab" + icon_state = "os_delta_biolab" + //DERELICT /area/ruin/space/derelict name = "\improper Derelict Station" - icon_state = "storage" /area/ruin/space/derelict/hallway/primary name = "\improper Derelict Primary Hallway" - icon_state = "hallP" /area/ruin/space/derelict/hallway/secondary name = "\improper Derelict Secondary Hallway" - icon_state = "hallS" /area/ruin/space/derelict/hallway/primary/port name = "\improper Derelict Port Hallway" - icon_state = "hallFP" /area/ruin/space/derelict/arrival name = "\improper Derelict Arrival Centre" - icon_state = "yellow" /area/ruin/space/derelict/storage/equipment name = "\improper Derelict Equipment Storage" /area/ruin/space/derelict/bridge name = "\improper Derelict Control Room" - icon_state = "bridge" /area/ruin/space/derelict/bridge/access name = "\improper Derelict Control Room Access" - icon_state = "auxstorage" /area/ruin/space/derelict/bridge/ai_upload name = "\improper Derelict Computer Core" - icon_state = "ai" /area/ruin/space/derelict/solar_control name = "\improper Derelict Solar Control" - icon_state = "engine" /area/ruin/space/derelict/se_solar name = "\improper South East Solars" - icon_state = "engine" /area/ruin/space/derelict/medical name = "\improper Derelict Medbay" - icon_state = "medbay" /area/ruin/space/derelict/medical/chapel name = "\improper Derelict Chapel" - icon_state = "chapel" -/area/solars/derelict_starboard +/area/ruin/solars/derelict_starboard name = "\improper Derelict Starboard Solar Array" - icon_state = "panelsS" -/area/solars/derelict_aft +/area/ruin/solars/derelict_aft name = "\improper Derelict Aft Solar Array" - icon_state = "yellow" /area/ruin/space/derelict/singularity_engine name = "\improper Derelict Singularity Engine" - icon_state = "engine" /area/ruin/space/derelict/gravity_generator name = "\improper Derelict Gravity Generator Room" - icon_state = "red" /area/ruin/space/derelict/atmospherics name = "Derelict Atmospherics" - icon_state = "red" //DJSTATION @@ -413,39 +381,41 @@ /area/ruin/space/abandoned_tele name = "\improper Abandoned Teleporter" - icon_state = "teleporter" ambientsounds = list('sound/ambience/ambimalf.ogg', 'sound/ambience/signal.ogg') //OLD AI SAT -/area/tcommsat/oldaisat +/area/ruin/tcommsat_oldaisat // Since tcommsat was moved to /area/station/, this turf doesn't inhereit its properties anymore name = "\improper Abandoned Satellite" - icon_state = "tcomsatcham" + ambientsounds = list('sound/ambience/ambisin2.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/ambigen10.ogg', 'sound/ambience/ambitech.ogg',\ + 'sound/ambience/ambitech2.ogg', 'sound/ambience/ambitech3.ogg', 'sound/ambience/ambimystery.ogg') + airlock_wires = /datum/wires/airlock/engineering + network_root_id = STATION_NETWORK_ROOT //ABANDONED BOX WHITESHIP /area/ruin/space/has_grav/whiteship/box name = "\improper Abandoned Ship" - icon_state = "red" //SYNDICATE LISTENING POST STATION /area/ruin/space/has_grav/listeningstation name = "\improper Listening Post" - icon_state = "yellow" /area/ruin/space/has_grav/powered/ancient_shuttle name = "\improper Ancient Shuttle" - icon_state = "yellow" //HELL'S FACTORY OPERATING FACILITY /area/ruin/space/has_grav/hellfactory name = "\improper Hell Factory" - icon_state = "yellow" /area/ruin/space/has_grav/hellfactoryoffice name = "\improper Hell Factory Office" - icon_state = "red" area_flags = VALID_TERRITORY | BLOBS_ALLOWED | UNIQUE_AREA | NOTELEPORT + +//Ruin of Spinward Smoothies + +/area/ruin/space/has_grav/spinwardsmoothies + name = "Spinward Smoothies" diff --git a/code/game/area/areas/shuttles.dm b/code/game/area/areas/shuttles.dm index 84c09a21f7049..cefbb4c1945aa 100644 --- a/code/game/area/areas/shuttles.dm +++ b/code/game/area/areas/shuttles.dm @@ -10,6 +10,7 @@ always_unpowered = FALSE // Loading the same shuttle map at a different time will produce distinct area instances. area_flags = NO_ALERTS + icon = 'icons/area/areas_station.dmi' icon_state = "shuttle" flags_1 = CAN_BE_DIRTY_1 area_limited_icon_smoothing = /area/shuttle @@ -238,7 +239,7 @@ name = "Tiny Freighter" // ----------- Arena Shuttle -/area/shuttle_arena +/area/shuttle/shuttle_arena name = "arena" has_gravity = STANDARD_GRAVITY requires_power = FALSE diff --git a/code/game/area/areas/station.dm b/code/game/area/areas/station.dm new file mode 100644 index 0000000000000..3ae23bfb262a7 --- /dev/null +++ b/code/game/area/areas/station.dm @@ -0,0 +1,1420 @@ +// Station areas and shuttles + +/area/station/ + name = "Station Areas" + icon = 'icons/area/areas_station.dmi' + icon_state = "station" + +//Maintenance + +/area/station/maintenance + name = "Generic Maintenance" + ambience_index = AMBIENCE_MAINT + area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED | PERSISTENT_ENGRAVINGS + airlock_wires = /datum/wires/airlock/maint + sound_environment = SOUND_AREA_TUNNEL_ENCLOSED + +//Maintenance - Departmental + +/area/station/maintenance/department/chapel + name = "Chapel Maintenance" + icon_state = "maint_chapel" + +/area/station/maintenance/department/chapel/monastery + name = "Monastery Maintenance" + icon_state = "maint_monastery" + +/area/station/maintenance/department/crew_quarters/bar + name = "Bar Maintenance" + icon_state = "maint_bar" + sound_environment = SOUND_AREA_WOODFLOOR + +/area/station/maintenance/department/crew_quarters/dorms + name = "Dormitory Maintenance" + icon_state = "maint_dorms" + +/area/station/maintenance/department/eva + name = "EVA Maintenance" + icon_state = "maint_eva" + +/area/station/maintenance/department/electrical + name = "Electrical Maintenance" + icon_state = "maint_electrical" + +/area/station/maintenance/department/engine/atmos + name = "Atmospherics Maintenance" + icon_state = "maint_atmos" + +/area/station/maintenance/department/security + name = "Security Maintenance" + icon_state = "maint_sec" + +/area/station/maintenance/department/security/upper + name = "Upper Security Maintenance" + +/area/station/maintenance/department/security/brig + name = "Brig Maintenance" + icon_state = "maint_brig" + +/area/station/maintenance/department/medical + name = "Medbay Maintenance" + icon_state = "medbay_maint" + +/area/station/maintenance/department/medical/central + name = "Central Medbay Maintenance" + icon_state = "medbay_maint_central" + +/area/station/maintenance/department/medical/morgue + name = "Morgue Maintenance" + icon_state = "morgue_maint" + +/area/station/maintenance/department/science + name = "Science Maintenance" + icon_state = "maint_sci" + +/area/station/maintenance/department/science/central + name = "Central Science Maintenance" + icon_state = "maint_sci_central" + +/area/station/maintenance/department/cargo + name = "Cargo Maintenance" + icon_state = "maint_cargo" + +/area/station/maintenance/department/bridge + name = "Bridge Maintenance" + icon_state = "maint_bridge" + +/area/station/maintenance/department/engine + name = "Engineering Maintenance" + icon_state = "maint_engi" + +/area/station/maintenance/department/science/xenobiology + name = "Xenobiology Maintenance" + icon_state = "xenomaint" + area_flags = VALID_TERRITORY | BLOBS_ALLOWED | UNIQUE_AREA | XENOBIOLOGY_COMPATIBLE | CULT_PERMITTED + +//Maintenance - Generic Tunnels + +/area/station/maintenance/aft + name = "Aft Maintenance" + icon_state = "aftmaint" + +/area/station/maintenance/aft/upper + name = "Upper Aft Maintenance" + icon_state = "upperaftmaint" + +/area/station/maintenance/aft/greater //use greater variants of area definitions for when the station has two different sections of maintenance on the same z-level. Can stand alone without "lesser". This one means that this goes more fore/north than the "lesser" maintenance area. + name = "Greater Aft Maintenance" + icon_state = "greateraftmaint" + +/area/station/maintenance/aft/lesser //use lesser variants of area definitions for when the station has two different sections of maintenance on the same z-level in conjunction with "greater" (just because it follows better). This one means that this goes more aft/south than the "greater" maintenance area. + name = "Lesser Aft Maintenance" + icon_state = "lesseraftmaint" + +/area/station/maintenance/central + name = "Central Maintenance" + icon_state = "centralmaint" + +/area/station/maintenance/central/greater + name = "Greater Central Maintenance" + icon_state = "greatercentralmaint" + +/area/station/maintenance/central/lesser + name = "Lesser Central Maintenance" + icon_state = "lessercentralmaint" + +/area/station/maintenance/fore + name = "Fore Maintenance" + icon_state = "foremaint" + +/area/station/maintenance/fore/upper + name = "Upper Fore Maintenance" + icon_state = "upperforemaint" + +/area/station/maintenance/fore/greater + name = "Greater Fore Maintenance" + icon_state = "greaterforemaint" + +/area/station/maintenance/fore/lesser + name = "Lesser Fore Maintenance" + icon_state = "lesserforemaint" + +/area/station/maintenance/starboard + name = "Starboard Maintenance" + icon_state = "starboardmaint" + +/area/station/maintenance/starboard/upper + name = "Upper Starboard Maintenance" + icon_state = "upperstarboardmaint" + +/area/station/maintenance/starboard/central + name = "Central Starboard Maintenance" + icon_state = "centralstarboardmaint" + +/area/station/maintenance/starboard/greater + name = "Greater Starboard Maintenance" + icon_state = "greaterstarboardmaint" + +/area/station/maintenance/starboard/lesser + name = "Lesser Starboard Maintenance" + icon_state = "lesserstarboardmaint" + +/area/station/maintenance/starboard/aft + name = "Aft Starboard Maintenance" + icon_state = "asmaint" + +/area/station/maintenance/starboard/fore + name = "Fore Starboard Maintenance" + icon_state = "fsmaint" + +/area/station/maintenance/port + name = "Port Maintenance" + icon_state = "portmaint" + +/area/station/maintenance/port/central + name = "Central Port Maintenance" + icon_state = "centralportmaint" + +/area/station/maintenance/port/greater + name = "Greater Port Maintenance" + icon_state = "greaterportmaint" + +/area/station/maintenance/port/lesser + name = "Lesser Port Maintenance" + icon_state = "lesserportmaint" + +/area/station/maintenance/port/aft + name = "Aft Port Maintenance" + icon_state = "apmaint" + +/area/station/maintenance/port/fore + name = "Fore Port Maintenance" + icon_state = "fpmaint" + +/area/station/maintenance/tram + name = "Primary Tram Maintenance" + +/area/station/maintenance/tram/left + name = "\improper Port Tram Underpass" + icon_state = "mainttramL" + +/area/station/maintenance/tram/mid + name = "\improper Central Tram Underpass" + icon_state = "mainttramM" + +/area/station/maintenance/tram/right + name = "\improper Starboard Tram Underpass" + icon_state = "mainttramR" + +//Maintenance - Discrete Areas +/area/station/maintenance/disposal + name = "Waste Disposal" + icon_state = "disposal" + +/area/station/maintenance/disposal/incinerator + name = "\improper Incinerator" + icon_state = "incinerator" + +/area/station/maintenance/space_hut + name = "\improper Space Hut" + icon_state = "spacehut" + +/area/station/maintenance/space_hut/cabin + name = "Abandoned Cabin" + +/area/station/maintenance/space_hut/plasmaman + name = "\improper Abandoned Plasmaman Friendly Startup" + +/area/station/maintenance/space_hut/observatory + name = "\improper Space Observatory" + +//Radation storm shelter +/area/station/maintenance/radshelter + name = "\improper Radstorm Shelter" + icon_state = "radstorm_shelter" + +/area/station/maintenance/radshelter/medical + name = "\improper Medical Radstorm Shelter" + +/area/station/maintenance/radshelter/sec + name = "\improper Security Radstorm Shelter" + +/area/station/maintenance/radshelter/service + name = "\improper Service Radstorm Shelter" + +/area/station/maintenance/radshelter/civil + name = "\improper Civilian Radstorm Shelter" + +/area/station/maintenance/radshelter/sci + name = "\improper Science Radstorm Shelter" + +/area/station/maintenance/radshelter/cargo + name = "\improper Cargo Radstorm Shelter" + + +//Hallway + +/area/station/hallway + icon_state = "hall" + sound_environment = SOUND_AREA_STANDARD_STATION + +/area/station/hallway/primary + name = "\improper Primary Hallway" + icon_state = "primaryhall" + +/area/station/hallway/primary/aft + name = "\improper Aft Primary Hallway" + icon_state = "afthall" + +/area/station/hallway/primary/fore + name = "\improper Fore Primary Hallway" + icon_state = "forehall" + +/area/station/hallway/primary/starboard + name = "\improper Starboard Primary Hallway" + icon_state = "starboardhall" + +/area/station/hallway/primary/port + name = "\improper Port Primary Hallway" + icon_state = "porthall" + +/area/station/hallway/primary/central + name = "\improper Central Primary Hallway" + icon_state = "centralhall" + +/area/station/hallway/primary/central/fore + name = "\improper Fore Central Primary Hallway" + icon_state = "hallCF" + +/area/station/hallway/primary/central/aft + name = "\improper Aft Central Primary Hallway" + icon_state = "hallCA" + +/area/station/hallway/primary/upper + name = "\improper Upper Central Primary Hallway" + icon_state = "centralhall" + +/area/station/hallway/primary/tram + name = "\improper Primary Tram" + +/area/station/hallway/primary/tram/left + name = "\improper Port Tram Dock" + icon_state = "halltramL" + +/area/station/hallway/primary/tram/center + name = "\improper Central Tram Dock" + icon_state = "halltramM" + +/area/station/hallway/primary/tram/right + name = "\improper Starboard Tram Dock" + icon_state = "halltramR" + +/area/station/hallway/secondary // This shouldn't be used, but it gives an icon for the enviornment tree in the map editor + icon_state = "secondaryhall" + +/area/station/hallway/secondary/command + name = "\improper Command Hallway" + icon_state = "bridge_hallway" + +/area/station/hallway/secondary/construction + name = "\improper Construction Area" + icon_state = "construction" + +/area/station/hallway/secondary/construction/engineering + name = "\improper Engineering Hallway" + +/area/station/hallway/secondary/exit + name = "\improper Escape Shuttle Hallway" + icon_state = "escape" + +/area/station/hallway/secondary/exit/departure_lounge + name = "\improper Departure Lounge" + icon_state = "escape_lounge" + +/area/station/hallway/secondary/entry + name = "\improper Arrival Shuttle Hallway" + icon_state = "entry" + +/area/station/hallway/secondary/service + name = "\improper Service Hallway" + icon_state = "hall_service" + +//Command + +/area/station/command + name = "Command" + icon_state = "command" + ambientsounds = list('sound/ambience/signal.ogg') + airlock_wires = /datum/wires/airlock/command + sound_environment = SOUND_AREA_STANDARD_STATION + +/area/station/command/bridge + name = "\improper Bridge" + icon_state = "bridge" + +/area/station/command/meeting_room + name = "\improper Heads of Staff Meeting Room" + icon_state = "meeting" + sound_environment = SOUND_AREA_MEDIUM_SOFTFLOOR + +/area/station/command/meeting_room/council + name = "\improper Council Chamber" + icon_state = "meeting" + sound_environment = SOUND_AREA_MEDIUM_SOFTFLOOR + +/area/station/command/corporate_showroom + name = "\improper Corporate Showroom" + icon_state = "showroom" + sound_environment = SOUND_AREA_MEDIUM_SOFTFLOOR + +/area/station/command/heads_quarters + icon_state = "heads_quarters" + +/area/station/command/heads_quarters/captain + name = "\improper Captain's Office" + icon_state = "captain" + sound_environment = SOUND_AREA_WOODFLOOR + +/area/station/command/heads_quarters/captain/private + name = "\improper Captain's Quarters" + icon_state = "captain_private" + sound_environment = SOUND_AREA_WOODFLOOR + +/area/station/command/heads_quarters/ce + name = "\improper Chief Engineer's Office" + icon_state = "ce_office" + +/area/station/command/heads_quarters/cmo + name = "\improper Chief Medical Officer's Office" + icon_state = "cmo_office" + +/area/station/command/heads_quarters/hop + name = "\improper Head of Personnel's Office" + icon_state = "hop_office" + +/area/station/command/heads_quarters/hos + name = "\improper Head of Security's Office" + icon_state = "hos_office" + +/area/station/command/heads_quarters/rd + name = "\improper Research Director's Office" + icon_state = "rd_office" + +//Command - Teleporters + +/area/station/command/teleporter + name = "\improper Teleporter Room" + icon_state = "teleporter" + ambience_index = AMBIENCE_ENGI + +/area/station/command/gateway + name = "\improper Gateway" + icon_state = "gateway" + ambience_index = AMBIENCE_ENGI + +//Commons + +/area/station/commons + name = "\improper Crew Facilities" + icon_state = "commons" + sound_environment = SOUND_AREA_STANDARD_STATION + area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED + +/area/station/commons/dorms + name = "\improper Dormitories" + icon_state = "dorms" + +/area/station/commons/dorms/barracks + name = "\improper Sleep Barracks" + +/area/station/commons/dorms/barracks/male + name = "\improper Male Sleep Barracks" + icon_state = "dorms_male" + +/area/station/commons/dorms/barracks/female + name = "\improper Female Sleep Barracks" + icon_state = "dorms_female" + +/area/station/commons/dorms/laundry + name = "\improper Laundry Room" + icon_state = "laundry_room" + +/area/station/commons/toilet + name = "\improper Dormitory Toilets" + icon_state = "toilet" + sound_environment = SOUND_AREA_SMALL_ENCLOSED + +/area/station/commons/toilet/auxiliary + name = "\improper Auxiliary Restrooms" + icon_state = "toilet" + +/area/station/commons/toilet/locker + name = "\improper Locker Toilets" + icon_state = "toilet" + +/area/station/commons/toilet/restrooms + name = "\improper Restrooms" + icon_state = "toilet" + +/area/station/commons/locker + name = "\improper Locker Room" + icon_state = "locker" + +/area/station/commons/lounge + name = "\improper Bar Lounge" + icon_state = "lounge" + mood_bonus = 5 + mood_message = "I love being in the bar!" + mood_trait = TRAIT_EXTROVERT + sound_environment = SOUND_AREA_SMALL_SOFTFLOOR + +/area/station/commons/fitness + name = "\improper Fitness Room" + icon_state = "fitness" + +/area/station/commons/fitness/locker_room + name = "\improper Unisex Locker Room" + icon_state = "locker" + +/area/station/commons/fitness/locker_room/male + name = "\improper Male Locker Room" + icon_state = "locker_male" + +/area/station/commons/fitness/locker_room/female + name = "\improper Female Locker Room" + icon_state = "locker_female" + +/area/station/commons/fitness/recreation + name = "\improper Recreation Area" + icon_state = "rec" + +/area/station/commons/fitness/recreation/entertainment + name = "\improper Entertainment Center" + icon_state = "entertainment" + +// Commons - Vacant Rooms +/area/station/commons/vacant_room + name = "\improper Vacant Room" + icon_state = "vacant_room" + ambience_index = AMBIENCE_MAINT + +/area/station/commons/vacant_room/office + name = "\improper Vacant Office" + icon_state = "vacant_office" + +/area/station/commons/vacant_room/commissary + name = "\improper Vacant Commissary" + icon_state = "vacant_commissary" + +//Commons - Storage +/area/station/commons/storage + sound_environment = SOUND_AREA_STANDARD_STATION + +/area/station/commons/storage/tools + name = "\improper Auxiliary Tool Storage" + icon_state = "tool_storage" + +/area/station/commons/storage/primary + name = "\improper Primary Tool Storage" + icon_state = "primary_storage" + +/area/station/commons/storage/art + name = "\improper Art Supply Storage" + icon_state = "art_storage" + +/area/station/commons/storage/emergency/starboard + name = "\improper Starboard Emergency Storage" + icon_state = "emergency_storage" + +/area/station/commons/storage/emergency/port + name = "\improper Port Emergency Storage" + icon_state = "emergency_storage" + +/area/station/commons/storage/mining + name = "\improper Public Mining Storage" + icon_state = "mining_storage" + +//Service + +/area/station/service + airlock_wires = /datum/wires/airlock/service + +/area/station/service/cafeteria + name = "\improper Cafeteria" + icon_state = "cafeteria" + +/area/station/service/kitchen + name = "\improper Kitchen" + icon_state = "kitchen" + +/area/station/service/kitchen/coldroom + name = "\improper Kitchen Cold Room" + icon_state = "kitchen_cold" + sound_environment = SOUND_AREA_SMALL_ENCLOSED + +/area/station/service/kitchen/diner + name = "\improper Diner" + icon_state = "diner" + +/area/station/service/kitchen/abandoned + name = "\improper Abandoned Kitchen" + icon_state = "abandoned_kitchen" + +/area/station/service/bar + name = "\improper Bar" + icon_state = "bar" + mood_bonus = 5 + mood_message = "I love being in the bar!" + mood_trait = TRAIT_EXTROVERT + airlock_wires = /datum/wires/airlock/service + sound_environment = SOUND_AREA_WOODFLOOR + +/area/station/service/bar/Initialize(mapload) + . = ..() + GLOB.bar_areas += src + +/area/station/service/bar/atrium + name = "\improper Atrium" + icon_state = "bar" + sound_environment = SOUND_AREA_WOODFLOOR + +/area/station/service/electronic_marketing_den + name = "\improper Electronic Marketing Den" + icon_state = "abandoned_marketing_den" + +/area/station/service/abandoned_gambling_den + name = "\improper Abandoned Gambling Den" + icon_state = "abandoned_gambling_den" + +/area/station/service/abandoned_gambling_den/gaming + name = "\improper Abandoned Gaming Den" + icon_state = "abandoned_gaming_den" + +/area/station/service/theater + name = "\improper Theater" + icon_state = "theatre" + sound_environment = SOUND_AREA_WOODFLOOR + +/area/station/service/theater/abandoned + name = "\improper Abandoned Theater" + icon_state = "abandoned_theatre" + +/area/station/service/library + name = "\improper Library" + icon_state = "library" + mood_bonus = 5 + mood_message = "I love being in the library!" + mood_trait = TRAIT_INTROVERT + area_flags = CULT_PERMITTED | BLOBS_ALLOWED | UNIQUE_AREA + sound_environment = SOUND_AREA_LARGE_SOFTFLOOR + +/area/station/service/library/lounge + name = "\improper Library Lounge" + icon_state = "library_lounge" + sound_environment = SOUND_AREA_SMALL_SOFTFLOOR + +/area/station/service/library/artgallery + name = "\improper Art Gallery" + icon_state = "library_gallery" + +/area/station/service/library/private + name = "\improper Library Private Study" + icon_state = "library_gallery_private" + +/area/station/service/library/upper + name = "\improper Library Upper Floor" + icon_state = "library" + +/area/station/service/library/printer + name = "\improper Library Printer Room" + icon_state = "library" + +/area/station/service/library/abandoned + name = "\improper Abandoned Library" + icon_state = "abandoned_library" + +/area/station/service/chapel + name = "\improper Chapel" + icon_state = "chapel" + mood_bonus = 5 + mood_message = "Being in the chapel brings me peace." + mood_trait = TRAIT_SPIRITUAL + ambience_index = AMBIENCE_HOLY + flags_1 = NONE + sound_environment = SOUND_AREA_LARGE_ENCLOSED + +/area/station/service/chapel/monastery + name = "\improper Monastery" + +/area/station/service/chapel/office + name = "\improper Chapel Office" + icon_state = "chapeloffice" + +/area/station/service/chapel/asteroid + name = "\improper Chapel Asteroid" + icon_state = "explored" + sound_environment = SOUND_AREA_ASTEROID + +/area/station/service/chapel/asteroid/monastery + name = "\improper Monastery Asteroid" + +/area/station/service/chapel/dock + name = "\improper Chapel Dock" + icon_state = "construction" + +/area/station/service/chapel/storage + name = "\improper Chapel Storage" + icon_state = "chapelstorage" + +/area/station/service/chapel/funeral + name = "\improper Chapel Funeral Room" + icon_state = "chapelfuneral" + +/area/station/service/lawoffice + name = "\improper Law Office" + icon_state = "law" + sound_environment = SOUND_AREA_SMALL_SOFTFLOOR + +/area/station/service/janitor + name = "\improper Custodial Closet" + icon_state = "janitor" + area_flags = CULT_PERMITTED | BLOBS_ALLOWED | UNIQUE_AREA + sound_environment = SOUND_AREA_SMALL_ENCLOSED + +/area/station/service/hydroponics + name = "Hydroponics" + icon_state = "hydro" + airlock_wires = /datum/wires/airlock/service + sound_environment = SOUND_AREA_STANDARD_STATION + +/area/station/service/hydroponics/upper + name = "Upper Hydroponics" + icon_state = "hydro" + +/area/station/service/hydroponics/garden + name = "Garden" + icon_state = "garden" + +/area/station/service/hydroponics/garden/abandoned + name = "\improper Abandoned Garden" + icon_state = "abandoned_garden" + sound_environment = SOUND_AREA_SMALL_ENCLOSED + +/area/station/service/hydroponics/garden/monastery + name = "\improper Monastery Garden" + icon_state = "hydro" + +//Engineering + +/area/station/engineering + icon_state = "engie" + ambience_index = AMBIENCE_ENGI + airlock_wires = /datum/wires/airlock/engineering + sound_environment = SOUND_AREA_LARGE_ENCLOSED + +/area/station/engineering/engine_smes + name = "\improper Engineering SMES" + icon_state = "engine_smes" + +/area/station/engineering/main + name = "Engineering" + icon_state = "engine" + +/area/station/engineering/hallway + name = "Engineering Hallway" + icon_state = "engine_hallway" + +/area/station/engineering/atmos + name = "Atmospherics" + icon_state = "atmos" + +/area/station/engineering/atmos/upper + name = "Upper Atmospherics" + +/area/station/engineering/atmos/project + name = "\improper Atmospherics Project Room" + icon_state = "atmos_projectroom" + +/area/station/engineering/atmos/pumproom + name = "\improper Atmospherics Pumping Room" + icon_state = "atmos_pump_room" + +/area/station/engineering/atmos/mix + name = "\improper Atmospherics Mixing Room" + icon_state = "atmos_mix" + +/area/station/engineering/atmos/storage + name = "\improper Atmospherics Storage Room" + icon_state = "atmos_storage" + +/area/station/engineering/atmos/storage/gas + name = "\improper Atmospherics Gas Storage" + icon_state = "atmos_storage_gas" + +/area/station/engineering/atmos/office + name = "\improper Atmospherics Office" + icon_state = "atmos_office" + +/area/station/engineering/atmos/hfr_room + name = "\improper Atmospherics HFR Room" + icon_state = "atmos_HFR" + +/area/station/engineering/atmospherics_engine + name = "\improper Atmospherics Engine" + icon_state = "atmos_engine" + area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED + +/area/station/engineering/lobby + name = "\improper Engineering Lobby" + icon_state = "engi_lobby" + +/area/station/engineering/supermatter + name = "\improper Supermatter Engine" + icon_state = "engine_sm" + area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED + sound_environment = SOUND_AREA_SMALL_ENCLOSED + +/area/station/engineering/supermatter/room + name = "\improper Supermatter Engine Room" + icon_state = "engine_sm_room" + sound_environment = SOUND_AREA_LARGE_ENCLOSED + +/area/station/engineering/break_room + name = "\improper Engineering Foyer" + icon_state = "engine_break" + sound_environment = SOUND_AREA_SMALL_ENCLOSED + +/area/station/engineering/gravity_generator + name = "\improper Gravity Generator Room" + icon_state = "grav_gen" + sound_environment = SOUND_AREA_SMALL_ENCLOSED + +/area/station/engineering/storage + name = "Engineering Storage" + icon_state = "engine_storage" + sound_environment = SOUND_AREA_SMALL_ENCLOSED + +/area/station/engineering/storage_shared + name = "Shared Engineering Storage" + icon_state = "engine_storage_shared" + +/area/station/engineering/transit_tube + name = "\improper Transit Tube" + icon_state = "transit_tube" + +/area/station/engineering/storage/tech + name = "Technical Storage" + icon_state = "tech_storage" + +/area/station/engineering/storage/tcomms + name = "Telecomms Storage" + icon_state = "tcom_storage" + area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED + +//Engineering - Construction + +/area/station/construction + name = "\improper Construction Area" + icon_state = "construction" + ambience_index = AMBIENCE_ENGI + sound_environment = SOUND_AREA_STANDARD_STATION + +/area/station/construction/mining/aux_base + name = "Auxiliary Base Construction" + icon_state = "aux_base_construction" + sound_environment = SOUND_AREA_MEDIUM_SOFTFLOOR + +/area/station/construction/storage_wing + name = "\improper Storage Wing" + icon_state = "storage_wing" + +//Solars + +/area/station/solars + icon_state = "panels" + requires_power = FALSE + area_flags = UNIQUE_AREA | AREA_USES_STARLIGHT + flags_1 = NONE + ambience_index = AMBIENCE_ENGI + airlock_wires = /datum/wires/airlock/engineering + sound_environment = SOUND_AREA_SPACE + base_lighting_alpha = 255 + +/area/station/solars/fore + name = "\improper Fore Solar Array" + icon_state = "panelsF" + sound_environment = SOUND_AREA_STANDARD_STATION + +/area/station/solars/aft + name = "\improper Aft Solar Array" + icon_state = "panelsAF" + +/area/station/solars/aux/port + name = "\improper Port Bow Auxiliary Solar Array" + icon_state = "panelsA" + +/area/station/solars/aux/starboard + name = "\improper Starboard Bow Auxiliary Solar Array" + icon_state = "panelsA" + +/area/station/solars/starboard + name = "\improper Starboard Solar Array" + icon_state = "panelsS" + +/area/station/solars/starboard/aft + name = "\improper Starboard Quarter Solar Array" + icon_state = "panelsAS" + +/area/station/solars/starboard/fore + name = "\improper Starboard Bow Solar Array" + icon_state = "panelsFS" + +/area/station/solars/port + name = "\improper Port Solar Array" + icon_state = "panelsP" + +/area/station/solars/port/aft + name = "\improper Port Quarter Solar Array" + icon_state = "panelsAP" + +/area/station/solars/port/fore + name = "\improper Port Bow Solar Array" + icon_state = "panelsFP" + +/area/station/solars/aisat + name = "\improper AI Satellite Solars" + icon_state = "panelsAI" + + +//Solar Maint + +/area/station/maintenance/solars + name = "Solar Maintenance" + icon_state = "yellow" + +/area/station/maintenance/solars/port + name = "Port Solar Maintenance" + icon_state = "SolarcontrolP" + +/area/station/maintenance/solars/port/aft + name = "Port Quarter Solar Maintenance" + icon_state = "SolarcontrolAP" + +/area/station/maintenance/solars/port/fore + name = "Port Bow Solar Maintenance" + icon_state = "SolarcontrolFP" + +/area/station/maintenance/solars/starboard + name = "Starboard Solar Maintenance" + icon_state = "SolarcontrolS" + +/area/station/maintenance/solars/starboard/aft + name = "Starboard Quarter Solar Maintenance" + icon_state = "SolarcontrolAS" + +/area/station/maintenance/solars/starboard/fore + name = "Starboard Bow Solar Maintenance" + icon_state = "SolarcontrolFS" + +//MedBay + +/area/station/medical + name = "Medical" + icon_state = "medbay" + ambience_index = AMBIENCE_MEDICAL + airlock_wires = /datum/wires/airlock/medbay + sound_environment = SOUND_AREA_STANDARD_STATION + min_ambience_cooldown = 90 SECONDS + max_ambience_cooldown = 180 SECONDS + +/area/station/medical/abandoned + name = "\improper Abandoned Medbay" + icon_state = "abandoned_medbay" + ambientsounds = list('sound/ambience/signal.ogg') + sound_environment = SOUND_AREA_SMALL_ENCLOSED + +/area/station/medical/medbay/central + name = "Medbay Central" + icon_state = "med_central" + +/area/station/medical/medbay/lobby + name = "\improper Medbay Lobby" + icon_state = "med_lobby" + +//Medbay is a large area, these additional areas help level out APC load. + +/area/station/medical/medbay/aft + name = "Medbay Aft" + icon_state = "med_aft" + +/area/station/medical/storage + name = "Medbay Storage" + icon_state = "med_storage" + +/area/station/medical/paramedic + name = "Paramedic Dispatch" + icon_state = "paramedic" + +/area/station/medical/office + name = "\improper Medical Office" + icon_state = "med_office" + +/area/station/medical/break_room + name = "\improper Medical Break Room" + icon_state = "med_break" + +/area/station/medical/coldroom + name = "\improper Medical Cold Room" + icon_state = "kitchen_cold" + +/area/station/medical/patients_rooms + name = "\improper Patients' Rooms" + icon_state = "patients" + sound_environment = SOUND_AREA_SMALL_SOFTFLOOR + +/area/station/medical/patients_rooms/room_a + name = "Patient Room A" + icon_state = "patients" + +/area/station/medical/patients_rooms/room_b + name = "Patient Room B" + icon_state = "patients" + +/area/station/medical/virology + name = "Virology" + icon_state = "virology" + +/area/station/medical/morgue + name = "\improper Morgue" + icon_state = "morgue" + ambience_index = AMBIENCE_SPOOKY + sound_environment = SOUND_AREA_SMALL_ENCLOSED + +/area/station/medical/chemistry + name = "Chemistry" + icon_state = "chem" + +/area/station/medical/pharmacy + name = "\improper Pharmacy" + icon_state = "pharmacy" + +/area/station/medical/surgery + name = "\improper Operating Room" + icon_state = "surgery" + +/area/station/medical/surgery/fore + name = "\improper Fore Operating Room" + icon_state = "foresurgery" + +/area/station/medical/surgery/aft + name = "\improper Aft Operating Room" + icon_state = "aftsurgery" + +/area/station/medical/surgery/theatre + name = "\improper Grand Surgery Theatre" + icon_state = "surgerytheatre" +/area/station/medical/cryo + name = "Cryogenics" + icon_state = "cryo" + +/area/station/medical/exam_room + name = "\improper Exam Room" + icon_state = "exam_room" + +/area/station/medical/treatment_center + name = "\improper Medbay Treatment Center" + icon_state = "exam_room" + +/area/station/medical/psychology + name = "\improper Psychology Office" + icon_state = "psychology" + mood_bonus = 3 + mood_message = "I feel at ease here." + ambientsounds = list('sound/ambience/aurora_caelus_short.ogg') + +//Security +///When adding a new area to the security areas, make sure to add it to /datum/bounty/item/security/paperwork as well! + +/area/station/security + name = "Security" + icon_state = "security" + ambience_index = AMBIENCE_DANGER + airlock_wires = /datum/wires/airlock/security + sound_environment = SOUND_AREA_STANDARD_STATION + +/area/station/security/office + name = "\improper Security Office" + icon_state = "security" + +/area/station/security/lockers + name = "\improper Security Locker Room" + icon_state = "securitylockerroom" + +/area/station/security/brig + name = "\improper Brig" + icon_state = "brig" + +/area/station/security/holding_cell + name = "\improper Holding Cell" + icon_state = "holding_cell" + +/area/station/security/medical + name = "\improper Security Medical" + icon_state = "security_medical" + +/area/station/security/brig/upper + name = "\improper Brig Overlook" + icon_state = "upperbrig" + +/area/station/security/courtroom + name = "\improper Courtroom" + icon_state = "courtroom" + sound_environment = SOUND_AREA_LARGE_ENCLOSED + +/area/station/security/prison + name = "\improper Prison Wing" + icon_state = "sec_prison" + area_flags = VALID_TERRITORY | BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED | PERSISTENT_ENGRAVINGS + +//Rad proof +/area/station/security/prison/toilet + name = "\improper Prison Toilet" + icon_state = "sec_prison_safe" + +// Rad proof +/area/station/security/prison/safe + name = "\improper Prison Wing Cells" + icon_state = "sec_prison_safe" + +/area/station/security/prison/upper + name = "\improper Upper Prison Wing" + icon_state = "prison_upper" + +/area/station/security/prison/visit + name = "\improper Prison Visitation Area" + icon_state = "prison_visit" + +/area/station/security/prison/rec + name = "\improper Prison Rec Room" + icon_state = "prison_rec" + +/area/station/security/prison/mess + name = "\improper Prison Mess Hall" + icon_state = "prison_mess" + +/area/station/security/prison/work + name = "\improper Prison Work Room" + icon_state = "prison_work" + +/area/station/security/prison/shower + name = "\improper Prison Shower" + icon_state = "prison_shower" + +/area/station/security/prison/workout + name = "\improper Prison Gym" + icon_state = "prison_workout" + +/area/station/security/prison/garden + name = "\improper Prison Garden" + icon_state = "prison_garden" + +/area/station/security/processing + name = "\improper Labor Shuttle Dock" + icon_state = "sec_labor_processing" + +/area/station/security/processing/cremation + name = "\improper Security Crematorium" + icon_state = "sec_cremation" + sound_environment = SOUND_AREA_SMALL_ENCLOSED + +/area/station/security/interrogation + name = "\improper Interrogation Room" + icon_state = "interrogation" + sound_environment = SOUND_AREA_SMALL_ENCLOSED + +/area/station/security/warden + name = "Brig Control" + icon_state = "warden" + sound_environment = SOUND_AREA_SMALL_SOFTFLOOR + +/area/station/security/detectives_office + name = "\improper Detective's Office" + icon_state = "detective" + ambientsounds = list('sound/ambience/ambidet1.ogg','sound/ambience/ambidet2.ogg') + +/area/station/security/detectives_office/private_investigators_office + name = "\improper Private Investigator's Office" + icon_state = "investigate_office" + sound_environment = SOUND_AREA_SMALL_SOFTFLOOR + +/area/station/security/range + name = "\improper Firing Range" + icon_state = "firingrange" + +/area/station/security/execution + icon_state = "execution_room" + +/area/station/security/execution/transfer + name = "\improper Transfer Centre" + icon_state = "sec_processing" + +/area/station/security/execution/education + name = "\improper Prisoner Education Chamber" + +/area/station/security/checkpoint + name = "\improper Security Checkpoint" + icon_state = "checkpoint" + +/area/station/security/checkpoint/auxiliary + icon_state = "checkpoint_aux" + +/area/station/security/checkpoint/escape + icon_state = "checkpoint_esc" + +/area/station/security/checkpoint/supply + name = "Security Post - Cargo Bay" + icon_state = "checkpoint_supp" + +/area/station/security/checkpoint/engineering + name = "Security Post - Engineering" + icon_state = "checkpoint_engi" + +/area/station/security/checkpoint/medical + name = "Security Post - Medbay" + icon_state = "checkpoint_med" + +/area/station/security/checkpoint/science + name = "Security Post - Science" + icon_state = "checkpoint_sci" + +/area/station/security/checkpoint/science/research + name = "Security Post - Research Division" + icon_state = "checkpoint_res" + +/area/station/security/checkpoint/customs + name = "Customs" + icon_state = "customs_point" + +/area/station/security/checkpoint/customs/auxiliary + name = "Auxiliary Customs" + icon_state = "customs_point_aux" + +/area/station/security/checkpoint/customs/fore + name = "Fore Customs" + icon_state = "customs_point_fore" + +/area/station/security/checkpoint/customs/aft + name = "Aft Customs" + icon_state = "customs_point_aft" + +//Cargo + +/area/station/cargo + name = "Quartermasters" + icon_state = "quart" + airlock_wires = /datum/wires/airlock/service + sound_environment = SOUND_AREA_STANDARD_STATION + +/area/station/cargo/sorting + name = "\improper Delivery Office" + icon_state = "cargo_delivery" + sound_environment = SOUND_AREA_STANDARD_STATION + +/area/station/cargo/warehouse + name = "\improper Warehouse" + icon_state = "cargo_warehouse" + sound_environment = SOUND_AREA_LARGE_ENCLOSED + +/area/station/cargo/drone_bay + name = "\improper Drone Bay" + icon_state = "cargo_drone" + +/area/station/cargo/warehouse/upper + name = "\improper Upper Warehouse" + +/area/station/cargo/office + name = "\improper Cargo Office" + icon_state = "cargo_office" + +/area/station/cargo/storage + name = "\improper Cargo Bay" + icon_state = "cargo_bay" + sound_environment = SOUND_AREA_LARGE_ENCLOSED + +/area/station/cargo/lobby + name = "\improper Cargo Lobby" + icon_state = "cargo_lobby" + +/area/station/cargo/qm + name = "\improper Quartermaster's Office" + icon_state = "quart_office" + +/area/station/cargo/miningdock + name = "\improper Mining Dock" + icon_state = "mining_dock" + +/area/station/cargo/miningdock/cafeteria + name = "\improper Mining Cafeteria" + icon_state = "mining_cafe" + +/area/station/cargo/miningdock/oresilo + name = "\improper Mining Ore Silo Storage" + icon_state = "mining_silo" + +/area/station/cargo/miningoffice + name = "\improper Mining Office" + icon_state = "mining" + +//Science + +/area/station/science + name = "\improper Science Division" + icon_state = "science" + airlock_wires = /datum/wires/airlock/science + sound_environment = SOUND_AREA_STANDARD_STATION + +/area/station/science/lobby + name = "\improper Science Lobby" + icon_state = "science_lobby" + +/area/station/science/lower + name = "\improper Lower Science Division" + icon_state = "lower_science" + +/area/station/science/breakroom + name = "\improper Science Break Room" + icon_state = "science_breakroom" + +/area/station/science/lab + name = "Research and Development" + icon_state = "research" + +/area/station/science/xenobiology + name = "\improper Xenobiology Lab" + icon_state = "xenobio" + +/area/station/science/xenobiology/hallway + name = "\improper Xenobiology Hallway" + icon_state = "xenobio_hall" + +/area/station/science/cytology + name = "\improper Cytology Lab" + icon_state = "cytology" + +// Use this for the main lab. If test equipment, storage, etc is also present use this one too. +/area/station/science/ordnance + name = "\improper Ordnance Lab" + icon_state = "ord_main" + +/area/station/science/ordnance/office + name = "\improper Ordnance Office" + icon_state = "ord_office" + +/area/station/science/ordnance/storage + name = "\improper Ordnance Storage" + icon_state = "ord_storage" + +/area/station/science/ordnance/burnchamber + name = "\improper Ordnance Burn Chamber" + icon_state = "ord_burn" + area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED + +/area/station/science/ordnance/freezerchamber + name = "\improper Ordnance Freezer Chamber" + icon_state = "ord_freeze" + area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED + +// Room for equipments and such +/area/station/science/ordnance/testlab + name = "\improper Ordnance Testing Lab" + icon_state = "ord_test" + area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED + +/area/station/science/ordnance/bomb + name = "\improper Ordnance Bomb Site" + icon_state = "ord_boom" + +/area/station/science/genetics + name = "\improper Genetics Lab" + icon_state = "geneticssci" + +/area/station/science/server + name = "\improper Research Division Server Room" + icon_state = "server" + +/area/station/science/explab + name = "\improper Experimentation Lab" + icon_state = "exp_lab" + +// Useless room +/area/station/science/auxlab + name = "\improper Auxillary Lab" + icon_state = "aux_lab" + +/area/station/science/robotics + name = "Robotics" + icon_state = "robotics" + +/area/station/science/robotics/mechbay + name = "\improper Mech Bay" + icon_state = "mechbay" + +/area/station/science/robotics/lab + name = "\improper Robotics Lab" + icon_state = "ass_line" + +/area/station/science/research + name = "\improper Research Division" + icon_state = "science" + +/area/station/science/research/abandoned + name = "\improper Abandoned Research Lab" + icon_state = "abandoned_sci" + sound_environment = SOUND_AREA_SMALL_ENCLOSED + +// Telecommunications Satellite + +/area/station/tcommsat + icon_state = "tcomsatcham" + ambientsounds = list('sound/ambience/ambisin2.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/ambigen10.ogg', 'sound/ambience/ambitech.ogg',\ + 'sound/ambience/ambitech2.ogg', 'sound/ambience/ambitech3.ogg', 'sound/ambience/ambimystery.ogg') + airlock_wires = /datum/wires/airlock/engineering + network_root_id = STATION_NETWORK_ROOT // They should of unpluged the router before they left + +/area/station/tcommsat/computer + name = "\improper Telecomms Control Room" + icon_state = "tcomsatcomp" + sound_environment = SOUND_AREA_MEDIUM_SOFTFLOOR + +/area/station/tcommsat/server + name = "\improper Telecomms Server Room" + icon_state = "tcomsatcham" + +/area/station/tcommsat/server/upper + name = "\improper Upper Telecomms Server Room" + +//Telecommunications - On Station + +/area/station/comms + name = "\improper Communications Relay" + icon_state = "tcomsatcham" + sound_environment = SOUND_AREA_STANDARD_STATION + +/area/station/server + name = "\improper Messaging Server Room" + icon_state = "server" + sound_environment = SOUND_AREA_STANDARD_STATION + +//External Hull Access +/area/station/maintenance/external + name = "\improper External Hull Access" + icon_state = "amaint" + +/area/station/maintenance/external/aft + name = "\improper Aft External Hull Access" + +/area/station/maintenance/external/port + name = "\improper Port External Hull Access" + +/area/station/maintenance/external/port/bow + name = "\improper Port Bow External Hull Access" diff --git a/code/game/area/space_station_13_areas.dm b/code/game/area/space_station_13_areas.dm index 26b808ec91276..ebf316ea57d27 100644 --- a/code/game/area/space_station_13_areas.dm +++ b/code/game/area/space_station_13_areas.dm @@ -4,7 +4,7 @@ /area/CATEGORY/OR/DESCRIPTOR/NAME (you can make as many subdivisions as you want) name = "NICE NAME" (not required but makes things really nice) - icon = 'ICON FILENAME' (defaults to 'icons/turf/areas.dmi') + icon = 'ICON FILENAME' (defaults to 'icons/area_misc.dmi') icon_state = "NAME OF ICON" (defaults to "unknown" (blank)) requires_power = FALSE (defaults to true) ambience_index = AMBIENCE_GENERIC (picks the ambience from an assoc list in ambience.dm) @@ -16,1572 +16,3 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /*-----------------------------------------------------------------------------*/ - -/area/ai_monitored //stub defined ai_monitored.dm - -/area/ai_monitored/turret_protected - -/area/space - icon_state = "space" - requires_power = TRUE - always_unpowered = TRUE - static_lighting = FALSE - - base_lighting_alpha = 255 - power_light = FALSE - power_equip = FALSE - power_environ = FALSE - area_flags = UNIQUE_AREA | NO_ALERTS - outdoors = TRUE - ambience_index = AMBIENCE_SPACE - flags_1 = CAN_BE_DIRTY_1 - sound_environment = SOUND_AREA_SPACE - -/area/space/nearstation - icon_state = "space_near" - area_flags = UNIQUE_AREA | NO_ALERTS | AREA_USES_STARLIGHT - -/area/start - name = "start area" - icon_state = "start" - requires_power = FALSE - static_lighting = FALSE - base_lighting_alpha = 255 - has_gravity = STANDARD_GRAVITY - - -/area/testroom - requires_power = FALSE - has_gravity = STANDARD_GRAVITY - name = "Test Room" - icon_state = "storage" - -//EXTRA - -/area/asteroid - name = "\improper Asteroid" - icon_state = "asteroid" - requires_power = FALSE - has_gravity = STANDARD_GRAVITY - area_flags = UNIQUE_AREA - ambience_index = AMBIENCE_MINING - flags_1 = CAN_BE_DIRTY_1 - sound_environment = SOUND_AREA_ASTEROID - min_ambience_cooldown = 70 SECONDS - max_ambience_cooldown = 220 SECONDS - -/area/asteroid/nearstation - static_lighting = TRUE - ambience_index = AMBIENCE_RUINS - always_unpowered = FALSE - requires_power = TRUE - area_flags = UNIQUE_AREA | BLOBS_ALLOWED - -/area/asteroid/nearstation/bomb_site - name = "\improper Bomb Testing Asteroid" - -//STATION13 - -//AI - -/area/ai_monitored - sound_environment = SOUND_AREA_STANDARD_STATION - -/area/ai_monitored/aisat/exterior - name = "\improper AI Satellite Exterior" - icon_state = "ai" - airlock_wires = /datum/wires/airlock/ai - -/area/ai_monitored/command/storage/satellite - name = "\improper AI Satellite Maint" - icon_state = "ai_storage" - ambience_index = AMBIENCE_DANGER - airlock_wires = /datum/wires/airlock/ai - -//AI - Turret_protected - -/area/ai_monitored/turret_protected - ambientsounds = list('sound/ambience/ambitech.ogg', 'sound/ambience/ambitech2.ogg', 'sound/ambience/ambiatmos.ogg', 'sound/ambience/ambiatmos2.ogg') - ///Some sounds (like the space jam) are terrible when on loop. We use this varaible to add it to other AI areas, but override it to keep it from the AI's core. - var/ai_will_not_hear_this = list('sound/ambience/ambimalf.ogg') - airlock_wires = /datum/wires/airlock/ai - -/area/ai_monitored/turret_protected/Initialize(mapload) - . = ..() - if(ai_will_not_hear_this) - ambientsounds += ai_will_not_hear_this - -/area/ai_monitored/turret_protected/ai_upload - name = "\improper AI Upload Chamber" - icon_state = "ai_upload" - sound_environment = SOUND_AREA_SMALL_ENCLOSED - -/area/ai_monitored/turret_protected/ai_upload_foyer - name = "\improper AI Upload Access" - icon_state = "ai_upload_foyer" - sound_environment = SOUND_AREA_SMALL_ENCLOSED - -/area/ai_monitored/turret_protected/ai - name = "\improper AI Chamber" - icon_state = "ai_chamber" - ai_will_not_hear_this = null - -/area/ai_monitored/turret_protected/aisat - name = "\improper AI Satellite" - icon_state = "ai" - sound_environment = SOUND_ENVIRONMENT_ROOM - -/area/ai_monitored/turret_protected/aisat/atmos - name = "\improper AI Satellite Atmos" - icon_state = "ai" - -/area/ai_monitored/turret_protected/aisat/foyer - name = "\improper AI Satellite Foyer" - icon_state = "ai_foyer" - -/area/ai_monitored/turret_protected/aisat/service - name = "\improper AI Satellite Service" - icon_state = "ai" - -/area/ai_monitored/turret_protected/aisat/hallway - name = "\improper AI Satellite Hallway" - icon_state = "ai" - -/area/ai_monitored/turret_protected/aisat/maint - name = "\improper AI Satellite Maintenance" - icon_state = "ai_maint" - -/area/ai_monitored/turret_protected/aisat_interior - name = "\improper AI Satellite Antechamber" - icon_state = "ai_interior" - sound_environment = SOUND_AREA_LARGE_ENCLOSED - -/area/ai_monitored/turret_protected/ai_sat_ext_as - name = "\improper AI Sat Ext" - icon_state = "ai_sat_east" - -/area/ai_monitored/turret_protected/ai_sat_ext_ap - name = "\improper AI Sat Ext" - icon_state = "ai_sat_west" - -//Maintenance - -/area/maintenance - name = "Generic Maintenance" - ambience_index = AMBIENCE_MAINT - area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED | PERSISTENT_ENGRAVINGS - airlock_wires = /datum/wires/airlock/maint - sound_environment = SOUND_AREA_TUNNEL_ENCLOSED - -//Maintenance - Departmental - -/area/maintenance/department/chapel - name = "Chapel Maintenance" - icon_state = "maint_chapel" - -/area/maintenance/department/chapel/monastery - name = "Monastery Maintenance" - icon_state = "maint_monastery" - -/area/maintenance/department/crew_quarters/bar - name = "Bar Maintenance" - icon_state = "maint_bar" - sound_environment = SOUND_AREA_WOODFLOOR - -/area/maintenance/department/crew_quarters/dorms - name = "Dormitory Maintenance" - icon_state = "maint_dorms" - -/area/maintenance/department/eva - name = "EVA Maintenance" - icon_state = "maint_eva" - -/area/maintenance/department/electrical - name = "Electrical Maintenance" - icon_state = "maint_electrical" - -/area/maintenance/department/engine/atmos - name = "Atmospherics Maintenance" - icon_state = "maint_atmos" - -/area/maintenance/department/security - name = "Security Maintenance" - icon_state = "maint_sec" - -/area/maintenance/department/security/upper - name = "Upper Security Maintenance" - -/area/maintenance/department/security/brig - name = "Brig Maintenance" - icon_state = "maint_brig" - -/area/maintenance/department/medical - name = "Medbay Maintenance" - icon_state = "medbay_maint" - -/area/maintenance/department/medical/central - name = "Central Medbay Maintenance" - icon_state = "medbay_maint_central" - -/area/maintenance/department/medical/morgue - name = "Morgue Maintenance" - icon_state = "morgue_maint" - -/area/maintenance/department/science - name = "Science Maintenance" - icon_state = "maint_sci" - -/area/maintenance/department/science/central - name = "Central Science Maintenance" - icon_state = "maint_sci_central" - -/area/maintenance/department/cargo - name = "Cargo Maintenance" - icon_state = "maint_cargo" - -/area/maintenance/department/bridge - name = "Bridge Maintenance" - icon_state = "maint_bridge" - -/area/maintenance/department/engine - name = "Engineering Maintenance" - icon_state = "maint_engi" - -/area/maintenance/department/science/xenobiology - name = "Xenobiology Maintenance" - icon_state = "xenomaint" - area_flags = VALID_TERRITORY | BLOBS_ALLOWED | UNIQUE_AREA | XENOBIOLOGY_COMPATIBLE | CULT_PERMITTED - -//Maintenance - Generic Tunnels - -/area/maintenance/aft - name = "Aft Maintenance" - icon_state = "aftmaint" - -/area/maintenance/aft/upper - name = "Upper Aft Maintenance" - icon_state = "upperaftmaint" - -/area/maintenance/aft/greater //use greater variants of area definitions for when the station has two different sections of maintenance on the same z-level. Can stand alone without "lesser". This one means that this goes more fore/north than the "lesser" maintenance area. - name = "Greater Aft Maintenance" - icon_state = "greateraftmaint" - -/area/maintenance/aft/lesser //use lesser variants of area definitions for when the station has two different sections of maintenance on the same z-level in conjunction with "greater" (just because it follows better). This one means that this goes more aft/south than the "greater" maintenance area. - name = "Lesser Aft Maintenance" - icon_state = "lesseraftmaint" - -/area/maintenance/central - name = "Central Maintenance" - icon_state = "centralmaint" - -/area/maintenance/central/greater - name = "Greater Central Maintenance" - icon_state = "greatercentralmaint" - -/area/maintenance/central/lesser - name = "Lesser Central Maintenance" - icon_state = "lessercentralmaint" - -/area/maintenance/fore - name = "Fore Maintenance" - icon_state = "foremaint" - -/area/maintenance/fore/upper - name = "Upper Fore Maintenance" - icon_state = "upperforemaint" - -/area/maintenance/fore/greater - name = "Greater Fore Maintenance" - icon_state = "greaterforemaint" - -/area/maintenance/fore/lesser - name = "Lesser Fore Maintenance" - icon_state = "lesserforemaint" - -/area/maintenance/starboard - name = "Starboard Maintenance" - icon_state = "starboardmaint" - -/area/maintenance/starboard/upper - name = "Upper Starboard Maintenance" - icon_state = "upperstarboardmaint" - -/area/maintenance/starboard/central - name = "Central Starboard Maintenance" - icon_state = "centralstarboardmaint" - -/area/maintenance/starboard/greater - name = "Greater Starboard Maintenance" - icon_state = "greaterstarboardmaint" - -/area/maintenance/starboard/lesser - name = "Lesser Starboard Maintenance" - icon_state = "lesserstarboardmaint" - -/area/maintenance/starboard/aft - name = "Aft Starboard Maintenance" - icon_state = "asmaint" - -/area/maintenance/starboard/fore - name = "Fore Starboard Maintenance" - icon_state = "fsmaint" - -/area/maintenance/port - name = "Port Maintenance" - icon_state = "portmaint" - -/area/maintenance/port/central - name = "Central Port Maintenance" - icon_state = "centralportmaint" - -/area/maintenance/port/greater - name = "Greater Port Maintenance" - icon_state = "greaterportmaint" - -/area/maintenance/port/lesser - name = "Lesser Port Maintenance" - icon_state = "lesserportmaint" - -/area/maintenance/port/aft - name = "Aft Port Maintenance" - icon_state = "apmaint" - -/area/maintenance/port/fore - name = "Fore Port Maintenance" - icon_state = "fpmaint" - -/area/maintenance/tram - name = "Primary Tram Maintenance" - -/area/maintenance/tram/left - name = "\improper Port Tram Underpass" - icon_state = "mainttramL" - -/area/maintenance/tram/mid - name = "\improper Central Tram Underpass" - icon_state = "mainttramM" - -/area/maintenance/tram/right - name = "\improper Starboard Tram Underpass" - icon_state = "mainttramR" - -//Maintenance - Discrete Areas -/area/maintenance/disposal - name = "Waste Disposal" - icon_state = "disposal" -/area/maintenance/disposal/incinerator - name = "\improper Incinerator" - icon_state = "incinerator" - -/area/maintenance/space_hut - name = "\improper Space Hut" - icon_state = "spacehut" - -/area/maintenance/space_hut/cabin - name = "Abandoned Cabin" - -/area/maintenance/space_hut/plasmaman - name = "\improper Abandoned Plasmaman Friendly Startup" - -/area/maintenance/space_hut/observatory - name = "\improper Space Observatory" - -//Radation storm shelter -/area/maintenance/radshelter - name = "\improper Radstorm Shelter" - icon_state = "radstorm_shelter" - -/area/maintenance/radshelter/medical - name = "\improper Medical Radstorm Shelter" - -/area/maintenance/radshelter/sec - name = "\improper Security Radstorm Shelter" - -/area/maintenance/radshelter/service - name = "\improper Service Radstorm Shelter" - -/area/maintenance/radshelter/civil - name = "\improper Civilian Radstorm Shelter" - -/area/maintenance/radshelter/sci - name = "\improper Science Radstorm Shelter" - -/area/maintenance/radshelter/cargo - name = "\improper Cargo Radstorm Shelter" - - -//Hallway - -/area/hallway - sound_environment = SOUND_AREA_STANDARD_STATION - -/area/hallway/primary - name = "\improper Primary Hallway" - -/area/hallway/primary/aft - name = "\improper Aft Primary Hallway" - icon_state = "hallA" - -/area/hallway/primary/fore - name = "\improper Fore Primary Hallway" - icon_state = "hallF" - -/area/hallway/primary/starboard - name = "\improper Starboard Primary Hallway" - icon_state = "hallS" - -/area/hallway/primary/port - name = "\improper Port Primary Hallway" - icon_state = "hallP" - -/area/hallway/primary/central - name = "\improper Central Primary Hallway" - icon_state = "hallC" - -/area/hallway/primary/central/fore - name = "\improper Fore Central Primary Hallway" - icon_state = "hallCF" - -/area/hallway/primary/central/aft - name = "\improper Aft Central Primary Hallway" - icon_state = "hallCA" - -/area/hallway/primary/upper - name = "\improper Upper Central Primary Hallway" - icon_state = "hallC" - -/area/hallway/primary/tram - name = "\improper Primary Tram" - -/area/hallway/primary/tram/left - name = "\improper Port Tram Dock" - icon_state = "halltramL" - -/area/hallway/primary/tram/center - name = "\improper Central Tram Dock" - icon_state = "halltramM" - -/area/hallway/primary/tram/right - name = "\improper Starboard Tram Dock" - icon_state = "halltramR" - -/area/hallway/secondary/command - name = "\improper Command Hallway" - icon_state = "bridge_hallway" - -/area/hallway/secondary/construction - name = "\improper Construction Area" - icon_state = "construction" - -/area/hallway/secondary/construction/engineering - name = "\improper Engineering Hallway" - -/area/hallway/secondary/exit - name = "\improper Escape Shuttle Hallway" - icon_state = "escape" - -/area/hallway/secondary/exit/departure_lounge - name = "\improper Departure Lounge" - icon_state = "escape_lounge" - -/area/hallway/secondary/entry - name = "\improper Arrival Shuttle Hallway" - icon_state = "entry" - -/area/hallway/secondary/service - name = "\improper Service Hallway" - icon_state = "hall_service" - -//Command - -/area/command - name = "Command" - icon_state = "Bridge" - ambientsounds = list('sound/ambience/signal.ogg') - airlock_wires = /datum/wires/airlock/command - sound_environment = SOUND_AREA_STANDARD_STATION - -/area/command/bridge - name = "\improper Bridge" - icon_state = "bridge" - -/area/command/meeting_room - name = "\improper Heads of Staff Meeting Room" - icon_state = "meeting" - sound_environment = SOUND_AREA_MEDIUM_SOFTFLOOR - -/area/command/meeting_room/council - name = "\improper Council Chamber" - icon_state = "meeting" - sound_environment = SOUND_AREA_MEDIUM_SOFTFLOOR - -/area/command/corporate_showroom - name = "\improper Corporate Showroom" - icon_state = "showroom" - sound_environment = SOUND_AREA_MEDIUM_SOFTFLOOR - -/area/command/heads_quarters - -/area/command/heads_quarters/captain - name = "\improper Captain's Office" - icon_state = "captain" - sound_environment = SOUND_AREA_WOODFLOOR - -/area/command/heads_quarters/captain/private - name = "\improper Captain's Quarters" - icon_state = "captain_private" - sound_environment = SOUND_AREA_WOODFLOOR - -/area/command/heads_quarters/ce - name = "\improper Chief Engineer's Office" - icon_state = "ce_office" - -/area/command/heads_quarters/cmo - name = "\improper Chief Medical Officer's Office" - icon_state = "cmo_office" - -/area/command/heads_quarters/hop - name = "\improper Head of Personnel's Office" - icon_state = "hop_office" - -/area/command/heads_quarters/hos - name = "\improper Head of Security's Office" - icon_state = "hos_office" - -/area/command/heads_quarters/rd - name = "\improper Research Director's Office" - icon_state = "rd_office" - -//Command - Teleporters - -/area/command/teleporter - name = "\improper Teleporter Room" - icon_state = "teleporter" - ambience_index = AMBIENCE_ENGI - -/area/command/gateway - name = "\improper Gateway" - icon_state = "gateway" - ambience_index = AMBIENCE_ENGI - -//Command - AI Monitored - -/area/ai_monitored/command/storage/eva - name = "EVA Storage" - icon_state = "eva" - ambience_index = AMBIENCE_DANGER - -/area/ai_monitored/command/storage/eva/upper - name = "Upper EVA Storage" - -/area/ai_monitored/command/nuke_storage - name = "\improper Vault" - icon_state = "nuke_storage" - airlock_wires = /datum/wires/airlock/command - -//Commons - -/area/commons - name = "\improper Crew Facilities" - icon_state = "commons" - sound_environment = SOUND_AREA_STANDARD_STATION - area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED - -/area/commons/dorms - name = "\improper Dormitories" - icon_state = "dorms" - -/area/commons/dorms/barracks - name = "\improper Sleep Barracks" - -/area/commons/dorms/barracks/male - name = "\improper Male Sleep Barracks" - icon_state = "dorms_male" - -/area/commons/dorms/barracks/female - name = "\improper Female Sleep Barracks" - icon_state = "dorms_female" - -/area/commons/dorms/laundry - name = "\improper Laundry Room" - icon_state = "laundry_room" - -/area/commons/toilet - name = "\improper Dormitory Toilets" - icon_state = "toilet" - sound_environment = SOUND_AREA_SMALL_ENCLOSED - -/area/commons/toilet/auxiliary - name = "\improper Auxiliary Restrooms" - icon_state = "toilet" - -/area/commons/toilet/locker - name = "\improper Locker Toilets" - icon_state = "toilet" - -/area/commons/toilet/restrooms - name = "\improper Restrooms" - icon_state = "toilet" - -/area/commons/locker - name = "\improper Locker Room" - icon_state = "locker" - -/area/commons/lounge - name = "\improper Bar Lounge" - icon_state = "lounge" - mood_bonus = 5 - mood_message = "I love being in the bar!" - mood_trait = TRAIT_EXTROVERT - sound_environment = SOUND_AREA_SMALL_SOFTFLOOR - -/area/commons/fitness - name = "\improper Fitness Room" - icon_state = "fitness" - -/area/commons/fitness/locker_room - name = "\improper Unisex Locker Room" - icon_state = "locker" - -/area/commons/fitness/locker_room/male - name = "\improper Male Locker Room" - icon_state = "locker_male" - -/area/commons/fitness/locker_room/female - name = "\improper Female Locker Room" - icon_state = "locker_female" - -/area/commons/fitness/recreation - name = "\improper Recreation Area" - icon_state = "rec" - -/area/commons/fitness/recreation/entertainment - name = "\improper Entertainment Center" - icon_state = "entertainment" - -// Commons - Vacant Rooms -/area/commons/vacant_room - name = "\improper Vacant Room" - icon_state = "vacant_room" - ambience_index = AMBIENCE_MAINT - -/area/commons/vacant_room/office - name = "\improper Vacant Office" - icon_state = "vacant_office" - -/area/commons/vacant_room/commissary - name = "\improper Vacant Commissary" - icon_state = "vacant_commissary" - -//Commons - Storage -/area/commons/storage - sound_environment = SOUND_AREA_STANDARD_STATION - -/area/commons/storage/tools - name = "\improper Auxiliary Tool Storage" - icon_state = "tool_storage" - -/area/commons/storage/primary - name = "\improper Primary Tool Storage" - icon_state = "primary_storage" - -/area/commons/storage/art - name = "\improper Art Supply Storage" - icon_state = "art_storage" - -/area/commons/storage/emergency/starboard - name = "\improper Starboard Emergency Storage" - icon_state = "emergency_storage" - -/area/commons/storage/emergency/port - name = "\improper Port Emergency Storage" - icon_state = "emergency_storage" - -/area/commons/storage/mining - name = "\improper Public Mining Storage" - icon_state = "mining_storage" - -//Service - -/area/service - airlock_wires = /datum/wires/airlock/service - -/area/service/cafeteria - name = "\improper Cafeteria" - icon_state = "cafeteria" - -/area/service/kitchen - name = "\improper Kitchen" - icon_state = "kitchen" - -/area/service/kitchen/coldroom - name = "\improper Kitchen Cold Room" - icon_state = "kitchen_cold" - sound_environment = SOUND_AREA_SMALL_ENCLOSED - -/area/service/kitchen/diner - name = "\improper Diner" - icon_state = "diner" - -/area/service/kitchen/abandoned - name = "\improper Abandoned Kitchen" - icon_state = "abandoned_kitchen" - -/area/service/bar - name = "\improper Bar" - icon_state = "bar" - mood_bonus = 5 - mood_message = "I love being in the bar!" - mood_trait = TRAIT_EXTROVERT - airlock_wires = /datum/wires/airlock/service - sound_environment = SOUND_AREA_WOODFLOOR - -/area/service/bar/Initialize(mapload) - . = ..() - GLOB.bar_areas += src - -/area/service/bar/atrium - name = "\improper Atrium" - icon_state = "bar" - sound_environment = SOUND_AREA_WOODFLOOR - -/area/service/electronic_marketing_den - name = "\improper Electronic Marketing Den" - icon_state = "abandoned_marketing_den" - -/area/service/abandoned_gambling_den - name = "\improper Abandoned Gambling Den" - icon_state = "abandoned_gambling_den" - -/area/service/abandoned_gambling_den/gaming - name = "\improper Abandoned Gaming Den" - icon_state = "abandoned_gaming_den" - -/area/service/theater - name = "\improper Theater" - icon_state = "theatre" - sound_environment = SOUND_AREA_WOODFLOOR - -/area/service/theater/abandoned - name = "\improper Abandoned Theater" - icon_state = "abandoned_theatre" - -/area/service/library - name = "\improper Library" - icon_state = "library" - mood_bonus = 5 - mood_message = "I love being in the library!" - mood_trait = TRAIT_INTROVERT - area_flags = CULT_PERMITTED | BLOBS_ALLOWED | UNIQUE_AREA - sound_environment = SOUND_AREA_LARGE_SOFTFLOOR - -/area/service/library/lounge - name = "\improper Library Lounge" - icon_state = "library_lounge" - sound_environment = SOUND_AREA_SMALL_SOFTFLOOR - -/area/service/library/artgallery - name = "\improper Art Gallery" - icon_state = "library_gallery" - -/area/service/library/private - name = "\improper Library Private Study" - icon_state = "library_gallery_private" - -/area/service/library/upper - name = "\improper Library Upper Floor" - icon_state = "library" - -/area/service/library/printer - name = "\improper Library Printer Room" - icon_state = "library" - -/area/service/library/abandoned - name = "\improper Abandoned Library" - icon_state = "abandoned_library" - -/area/service/chapel - name = "\improper Chapel" - icon_state = "chapel" - mood_bonus = 5 - mood_message = "Being in the chapel brings me peace." - mood_trait = TRAIT_SPIRITUAL - ambience_index = AMBIENCE_HOLY - flags_1 = NONE - sound_environment = SOUND_AREA_LARGE_ENCLOSED - -/area/service/chapel/monastery - name = "\improper Monastery" - -/area/service/chapel/office - name = "\improper Chapel Office" - icon_state = "chapeloffice" - -/area/service/chapel/asteroid - name = "\improper Chapel Asteroid" - icon_state = "explored" - sound_environment = SOUND_AREA_ASTEROID - -/area/service/chapel/asteroid/monastery - name = "\improper Monastery Asteroid" - -/area/service/chapel/dock - name = "\improper Chapel Dock" - icon_state = "construction" - -/area/service/chapel/storage - name = "\improper Chapel Storage" - icon_state = "chapelstorage" - -/area/service/chapel/funeral - name = "\improper Chapel Funeral Room" - icon_state = "chapelfuneral" - -/area/service/lawoffice - name = "\improper Law Office" - icon_state = "law" - sound_environment = SOUND_AREA_SMALL_SOFTFLOOR - -/area/service/janitor - name = "\improper Custodial Closet" - icon_state = "janitor" - area_flags = CULT_PERMITTED | BLOBS_ALLOWED | UNIQUE_AREA - sound_environment = SOUND_AREA_SMALL_ENCLOSED - -/area/service/hydroponics - name = "Hydroponics" - icon_state = "hydro" - airlock_wires = /datum/wires/airlock/service - sound_environment = SOUND_AREA_STANDARD_STATION - -/area/service/hydroponics/upper - name = "Upper Hydroponics" - icon_state = "hydro" - -/area/service/hydroponics/garden - name = "Garden" - icon_state = "garden" - -/area/service/hydroponics/garden/abandoned - name = "\improper Abandoned Garden" - icon_state = "abandoned_garden" - sound_environment = SOUND_AREA_SMALL_ENCLOSED - -/area/service/hydroponics/garden/monastery - name = "\improper Monastery Garden" - icon_state = "hydro" - -//Engineering - -/area/engineering - ambience_index = AMBIENCE_ENGI - airlock_wires = /datum/wires/airlock/engineering - sound_environment = SOUND_AREA_LARGE_ENCLOSED - -/area/engineering/engine_smes - name = "\improper Engineering SMES" - icon_state = "engine_smes" - -/area/engineering/main - name = "Engineering" - icon_state = "engine" - -/area/engineering/hallway - name = "Engineering Hallway" - icon_state = "engine_hallway" - -/area/engineering/atmos - name = "Atmospherics" - icon_state = "atmos" - -/area/engineering/atmos/upper - name = "Upper Atmospherics" - -/area/engineering/atmos/project - name = "\improper Atmospherics Project Room" - icon_state = "atmos_projectroom" - -/area/engineering/atmos/pumproom - name = "\improper Atmospherics Pumping Room" - icon_state = "atmos_pump_room" - -/area/engineering/atmos/mix - name = "\improper Atmospherics Mixing Room" - icon_state = "atmos_mix" - -/area/engineering/atmos/storage - name = "\improper Atmospherics Storage Room" - icon_state = "atmos_storage" - -/area/engineering/atmos/storage/gas - name = "\improper Atmospherics Gas Storage" - icon_state = "atmos_storage_gas" - -/area/engineering/atmos/office - name = "\improper Atmospherics Office" - icon_state = "atmos_office" - -/area/engineering/atmos/hfr_room - name = "\improper Atmospherics HFR Room" - icon_state = "atmos_HFR" - -/area/engineering/atmospherics_engine - name = "\improper Atmospherics Engine" - icon_state = "atmos_engine" - area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED - -/area/engineering/lobby - name = "\improper Engineering Lobby" - icon_state = "engi_lobby" - -/area/engineering/supermatter - name = "\improper Supermatter Engine" - icon_state = "engine_sm" - area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED - sound_environment = SOUND_AREA_SMALL_ENCLOSED - -/area/engineering/supermatter/room - name = "\improper Supermatter Engine Room" - icon_state = "engine_sm_room" - sound_environment = SOUND_AREA_LARGE_ENCLOSED - -/area/engineering/break_room - name = "\improper Engineering Foyer" - icon_state = "engine_break" - sound_environment = SOUND_AREA_SMALL_ENCLOSED - -/area/engineering/gravity_generator - name = "\improper Gravity Generator Room" - icon_state = "grav_gen" - sound_environment = SOUND_AREA_SMALL_ENCLOSED - -/area/engineering/storage - name = "Engineering Storage" - icon_state = "engine_storage" - sound_environment = SOUND_AREA_SMALL_ENCLOSED - -/area/engineering/storage_shared - name = "Shared Engineering Storage" - icon_state = "engine_storage_shared" - -/area/engineering/transit_tube - name = "\improper Transit Tube" - icon_state = "transit_tube" - -/area/engineering/storage/tech - name = "Technical Storage" - icon_state = "tech_storage" - -/area/engineering/storage/tcomms - name = "Telecomms Storage" - icon_state = "tcom_storage" - area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED - -//Engineering - Construction - -/area/construction - name = "\improper Construction Area" - icon_state = "construction" - ambience_index = AMBIENCE_ENGI - sound_environment = SOUND_AREA_STANDARD_STATION - -/area/construction/mining/aux_base - name = "Auxiliary Base Construction" - icon_state = "aux_base_construction" - sound_environment = SOUND_AREA_MEDIUM_SOFTFLOOR - -/area/construction/storage_wing - name = "\improper Storage Wing" - icon_state = "storage_wing" - -//Solars - -/area/solars - requires_power = FALSE - area_flags = UNIQUE_AREA | AREA_USES_STARLIGHT - flags_1 = NONE - ambience_index = AMBIENCE_ENGI - airlock_wires = /datum/wires/airlock/engineering - sound_environment = SOUND_AREA_SPACE - base_lighting_alpha = 255 - -/area/solars/fore - name = "\improper Fore Solar Array" - icon_state = "yellow" - sound_environment = SOUND_AREA_STANDARD_STATION - -/area/solars/aft - name = "\improper Aft Solar Array" - icon_state = "yellow" - -/area/solars/aux/port - name = "\improper Port Bow Auxiliary Solar Array" - icon_state = "panelsA" - -/area/solars/aux/starboard - name = "\improper Starboard Bow Auxiliary Solar Array" - icon_state = "panelsA" - -/area/solars/starboard - name = "\improper Starboard Solar Array" - icon_state = "panelsS" - -/area/solars/starboard/aft - name = "\improper Starboard Quarter Solar Array" - icon_state = "panelsAS" - -/area/solars/starboard/fore - name = "\improper Starboard Bow Solar Array" - icon_state = "panelsFS" - -/area/solars/port - name = "\improper Port Solar Array" - icon_state = "panelsP" - -/area/solars/port/aft - name = "\improper Port Quarter Solar Array" - icon_state = "panelsAP" - -/area/solars/port/fore - name = "\improper Port Bow Solar Array" - icon_state = "panelsFP" - -/area/solars/aisat - name = "\improper AI Satellite Solars" - icon_state = "yellow" - - -//Solar Maint - -/area/maintenance/solars - name = "Solar Maintenance" - icon_state = "yellow" - -/area/maintenance/solars/port - name = "Port Solar Maintenance" - icon_state = "SolarcontrolP" - -/area/maintenance/solars/port/aft - name = "Port Quarter Solar Maintenance" - icon_state = "SolarcontrolAP" - -/area/maintenance/solars/port/fore - name = "Port Bow Solar Maintenance" - icon_state = "SolarcontrolFP" - -/area/maintenance/solars/starboard - name = "Starboard Solar Maintenance" - icon_state = "SolarcontrolS" - -/area/maintenance/solars/starboard/aft - name = "Starboard Quarter Solar Maintenance" - icon_state = "SolarcontrolAS" - -/area/maintenance/solars/starboard/fore - name = "Starboard Bow Solar Maintenance" - icon_state = "SolarcontrolFS" - -//MedBay - -/area/medical - name = "Medical" - icon_state = "medbay" - ambience_index = AMBIENCE_MEDICAL - airlock_wires = /datum/wires/airlock/medbay - sound_environment = SOUND_AREA_STANDARD_STATION - min_ambience_cooldown = 90 SECONDS - max_ambience_cooldown = 180 SECONDS - -/area/medical/abandoned - name = "\improper Abandoned Medbay" - icon_state = "abandoned_medbay" - ambientsounds = list('sound/ambience/signal.ogg') - sound_environment = SOUND_AREA_SMALL_ENCLOSED - -/area/medical/medbay/central - name = "Medbay Central" - icon_state = "med_central" - -/area/medical/medbay/lobby - name = "\improper Medbay Lobby" - icon_state = "med_lobby" - - //Medbay is a large area, these additional areas help level out APC load. -/area/medical/medbay/aft - name = "Medbay Aft" - icon_state = "med_aft" - -/area/medical/storage - name = "Medbay Storage" - icon_state = "med_storage" - -/area/medical/paramedic - name = "Paramedic Dispatch" - icon_state = "paramedic" - -/area/medical/office - name = "\improper Medical Office" - icon_state = "med_office" - -/area/medical/break_room - name = "\improper Medical Break Room" - icon_state = "med_break" - -/area/medical/coldroom - name = "\improper Medical Cold Room" - icon_state = "kitchen_cold" - -/area/medical/patients_rooms - name = "\improper Patients' Rooms" - icon_state = "patients" - sound_environment = SOUND_AREA_SMALL_SOFTFLOOR - -/area/medical/patients_rooms/room_a - name = "Patient Room A" - icon_state = "patients" - -/area/medical/patients_rooms/room_b - name = "Patient Room B" - icon_state = "patients" - -/area/medical/virology - name = "Virology" - icon_state = "virology" - -/area/medical/morgue - name = "\improper Morgue" - icon_state = "morgue" - ambience_index = AMBIENCE_SPOOKY - sound_environment = SOUND_AREA_SMALL_ENCLOSED - -/area/medical/chemistry - name = "Chemistry" - icon_state = "chem" - -/area/medical/pharmacy - name = "\improper Pharmacy" - icon_state = "pharmacy" - -/area/medical/surgery - name = "\improper Operating Room" - icon_state = "surgery" - -/area/medical/surgery/fore - name = "\improper Fore Operating Room" - icon_state = "foresurgery" - -/area/medical/surgery/aft - name = "\improper Aft Operating Room" - icon_state = "aftsurgery" - -/area/medical/surgery/theatre - name = "\improper Grand Surgery Theatre" - icon_state = "surgerytheatre" -/area/medical/cryo - name = "Cryogenics" - icon_state = "cryo" - -/area/medical/exam_room - name = "\improper Exam Room" - icon_state = "exam_room" - -/area/medical/treatment_center - name = "\improper Medbay Treatment Center" - icon_state = "exam_room" - -/area/medical/psychology - name = "\improper Psychology Office" - icon_state = "psychology" - mood_bonus = 3 - mood_message = "I feel at ease here." - ambientsounds = list('sound/ambience/aurora_caelus_short.ogg') - -//Security -///When adding a new area to the security areas, make sure to add it to /datum/bounty/item/security/paperwork as well! - -/area/security - name = "Security" - icon_state = "security" - ambience_index = AMBIENCE_DANGER - airlock_wires = /datum/wires/airlock/security - sound_environment = SOUND_AREA_STANDARD_STATION - -/area/security/office - name = "\improper Security Office" - icon_state = "security" - -/area/security/lockers - name = "\improper Security Locker Room" - icon_state = "securitylockerroom" - -/area/security/brig - name = "\improper Brig" - icon_state = "brig" - -/area/security/holding_cell - name = "\improper Holding Cell" - icon_state = "holding_cell" - -/area/security/medical - name = "\improper Security Medical" - icon_state = "security_medical" - -/area/security/brig/upper - name = "\improper Brig Overlook" - icon_state = "upperbrig" - -/area/security/courtroom - name = "\improper Courtroom" - icon_state = "courtroom" - sound_environment = SOUND_AREA_LARGE_ENCLOSED - -/area/security/prison - name = "\improper Prison Wing" - icon_state = "sec_prison" - area_flags = VALID_TERRITORY | BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED | PERSISTENT_ENGRAVINGS - -/area/security/prison/toilet //radproof - name = "\improper Prison Toilet" - icon_state = "sec_prison_safe" - -/area/security/prison/safe //radproof - name = "\improper Prison Wing Cells" - icon_state = "sec_prison_safe" - -/area/security/prison/upper - name = "\improper Upper Prison Wing" - icon_state = "prison_upper" - -/area/security/prison/visit - name = "\improper Prison Visitation Area" - icon_state = "prison_visit" - -/area/security/prison/rec - name = "\improper Prison Rec Room" - icon_state = "prison_rec" - -/area/security/prison/mess - name = "\improper Prison Mess Hall" - icon_state = "prison_mess" - -/area/security/prison/work - name = "\improper Prison Work Room" - icon_state = "prison_work" - -/area/security/prison/shower - name = "\improper Prison Shower" - icon_state = "prison_shower" - -/area/security/prison/workout - name = "\improper Prison Gym" - icon_state = "prison_workout" - -/area/security/prison/garden - name = "\improper Prison Garden" - icon_state = "prison_garden" - -/area/security/processing - name = "\improper Labor Shuttle Dock" - icon_state = "sec_processing" - -/area/security/processing/cremation - name = "\improper Security Crematorium" - icon_state = "sec_cremation" - sound_environment = SOUND_AREA_SMALL_ENCLOSED - -/area/security/interrogation - name = "\improper Interrogation Room" - icon_state = "interrogation" - sound_environment = SOUND_AREA_SMALL_ENCLOSED - -/area/security/warden - name = "Brig Control" - icon_state = "warden" - sound_environment = SOUND_AREA_SMALL_SOFTFLOOR - -/area/security/detectives_office - name = "\improper Detective's Office" - icon_state = "detective" - ambientsounds = list('sound/ambience/ambidet1.ogg','sound/ambience/ambidet2.ogg') - -/area/security/detectives_office/private_investigators_office - name = "\improper Private Investigator's Office" - icon_state = "investigate_office" - sound_environment = SOUND_AREA_SMALL_SOFTFLOOR - -/area/security/range - name = "\improper Firing Range" - icon_state = "firingrange" - -/area/security/execution - icon_state = "execution_room" - -/area/security/execution/transfer - name = "\improper Transfer Centre" - icon_state = "sec_processing" - -/area/security/execution/education - name = "\improper Prisoner Education Chamber" - -/area/security/checkpoint - name = "\improper Security Checkpoint" - icon_state = "checkpoint" - -/area/security/checkpoint/auxiliary - icon_state = "checkpoint_aux" - -/area/security/checkpoint/escape - icon_state = "checkpoint_esc" - -/area/security/checkpoint/supply - name = "Security Post - Cargo Bay" - icon_state = "checkpoint_supp" - -/area/security/checkpoint/engineering - name = "Security Post - Engineering" - icon_state = "checkpoint_engi" - -/area/security/checkpoint/medical - name = "Security Post - Medbay" - icon_state = "checkpoint_med" - -/area/security/checkpoint/science - name = "Security Post - Science" - icon_state = "checkpoint_sci" - -/area/security/checkpoint/science/research - name = "Security Post - Research Division" - icon_state = "checkpoint_res" - -/area/security/checkpoint/customs - name = "Customs" - icon_state = "customs_point" - -/area/security/checkpoint/customs/auxiliary - name = "Auxiliary Customs" - icon_state = "customs_point_aux" - -/area/security/checkpoint/customs/fore - name = "Fore Customs" - icon_state = "customs_point_fore" - -/area/security/checkpoint/customs/aft - name = "Aft Customs" - icon_state = "customs_point_aft" - -//Security - AI Monitored -/area/ai_monitored/security/armory - name = "\improper Armory" - icon_state = "armory" - ambience_index = AMBIENCE_DANGER - airlock_wires = /datum/wires/airlock/security - -/area/ai_monitored/security/armory/upper - name = "Upper Armory" - -//Cargo - -/area/cargo - name = "Quartermasters" - icon_state = "quart" - airlock_wires = /datum/wires/airlock/service - sound_environment = SOUND_AREA_STANDARD_STATION - -/area/cargo/sorting - name = "\improper Delivery Office" - icon_state = "cargo_delivery" - sound_environment = SOUND_AREA_STANDARD_STATION - -/area/cargo/warehouse - name = "\improper Warehouse" - icon_state = "cargo_warehouse" - sound_environment = SOUND_AREA_LARGE_ENCLOSED - -/area/cargo/drone_bay - name = "\improper Drone Bay" - icon_state = "cargo_drone" - -/area/cargo/warehouse/upper - name = "\improper Upper Warehouse" - -/area/cargo/office - name = "\improper Cargo Office" - icon_state = "cargo_office" - -/area/cargo/storage - name = "\improper Cargo Bay" - icon_state = "cargo_bay" - sound_environment = SOUND_AREA_LARGE_ENCLOSED - -/area/cargo/lobby - name = "\improper Cargo Lobby" - icon_state = "cargo_lobby" - -/area/cargo/qm - name = "\improper Quartermaster's Office" - icon_state = "quart_office" - -/area/cargo/miningdock - name = "\improper Mining Dock" - icon_state = "mining_dock" - -/area/cargo/miningdock/cafeteria - name = "\improper Mining Cafeteria" - icon_state = "mining_cafe" - -/area/cargo/miningdock/oresilo - name = "\improper Mining Ore Silo Storage" - icon_state = "mining_silo" - -/area/cargo/miningoffice - name = "\improper Mining Office" - icon_state = "mining" - -//Science - -/area/science - name = "\improper Science Division" - icon_state = "science" - airlock_wires = /datum/wires/airlock/science - sound_environment = SOUND_AREA_STANDARD_STATION - -/area/science/lobby - name = "\improper Science Lobby" - icon_state = "science_lobby" - -/area/science/lower - name = "\improper Lower Science Division" - icon_state = "lower_science" - -/area/science/breakroom - name = "\improper Science Break Room" - icon_state = "science_breakroom" - -/area/science/lab - name = "Research and Development" - icon_state = "research" - -/area/science/xenobiology - name = "\improper Xenobiology Lab" - icon_state = "xenobio" - -/area/science/xenobiology/hallway - name = "\improper Xenobiology Hallway" - icon_state = "xenobio_hall" - -/area/science/cytology - name = "\improper Cytology Lab" - icon_state = "cytology" - -/area/science/storage - name = "Ordnance Storage" - icon_state = "ord_storage" - -/area/science/test_area - name = "\improper Ordnance Test Area" - icon_state = "ord_test" - area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED - -/area/science/mixing - name = "\improper Ordnance Mixing Lab" - icon_state = "ord_mix" - -/area/science/mixing/chamber - name = "\improper Ordnance Mixing Chamber" - icon_state = "ord_mix_chamber" - area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED - -/area/science/mixing/hallway - name = "\improper Ordnance Mixing Hallway" - icon_state = "ord_mix_hallway" - -/area/science/mixing/launch - name = "\improper Ordnance Mixing Launch Site" - icon_state = "ord_mix_launch" - -/area/science/genetics - name = "\improper Genetics Lab" - icon_state = "geneticssci" - -/area/science/misc_lab - name = "\improper Testing Lab" - icon_state = "ord_misc" - -/area/science/misc_lab/range - name = "\improper Research Testing Range" - icon_state = "ord_range" - -/area/science/server - name = "\improper Research Division Server Room" - icon_state = "server" - -/area/science/explab - name = "\improper Experimentation Lab" - icon_state = "exp_lab" - -/area/science/robotics - name = "Robotics" - icon_state = "robotics" - -/area/science/robotics/mechbay - name = "\improper Mech Bay" - icon_state = "mechbay" - -/area/science/robotics/lab - name = "\improper Robotics Lab" - icon_state = "ass_line" - -/area/science/research - name = "\improper Research Division" - icon_state = "science" - -/area/science/research/abandoned - name = "\improper Abandoned Research Lab" - icon_state = "abandoned_sci" - sound_environment = SOUND_AREA_SMALL_ENCLOSED - -// Telecommunications Satellite - -/area/tcommsat - ambientsounds = list('sound/ambience/ambisin2.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/ambigen10.ogg', 'sound/ambience/ambitech.ogg',\ - 'sound/ambience/ambitech2.ogg', 'sound/ambience/ambitech3.ogg', 'sound/ambience/ambimystery.ogg') - airlock_wires = /datum/wires/airlock/engineering - network_root_id = STATION_NETWORK_ROOT // They should of unpluged the router before they left - -/area/tcommsat/computer - name = "\improper Telecomms Control Room" - icon_state = "tcomsatcomp" - sound_environment = SOUND_AREA_MEDIUM_SOFTFLOOR - -/area/tcommsat/server - name = "\improper Telecomms Server Room" - icon_state = "tcomsatcham" - -/area/tcommsat/server/upper - name = "\improper Upper Telecomms Server Room" - -//Telecommunications - On Station - -/area/comms - name = "\improper Communications Relay" - icon_state = "tcomsatcham" - sound_environment = SOUND_AREA_STANDARD_STATION - -/area/server - name = "\improper Messaging Server Room" - icon_state = "server" - sound_environment = SOUND_AREA_STANDARD_STATION - -//External Hull Access -/area/maintenance/external - name = "\improper External Hull Access" - icon_state = "amaint" - -/area/maintenance/external/aft - name = "\improper Aft External Hull Access" - -/area/maintenance/external/port - name = "\improper Port External Hull Access" - -/area/maintenance/external/port/bow - name = "\improper Port Bow External Hull Access" diff --git a/code/game/atoms.dm b/code/game/atoms.dm index ef716bdc2d9a7..ee9ff67cd46a6 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -7,7 +7,7 @@ /atom layer = TURF_LAYER plane = GAME_PLANE - appearance_flags = TILE_BOUND + appearance_flags = TILE_BOUND|LONG_GLIDE /// pass_flags that we are. If any of this matches a pass_flag on a moving thing, by default, we let them through. var/pass_flags_self = NONE @@ -30,8 +30,12 @@ ///Reagents holder var/datum/reagents/reagents = null - ///This atom's HUD (med/sec, etc) images. Associative list. + ///all of this atom's HUD (med/sec, etc) images. Associative list of the form: list(hud category = hud image or images for that category). + ///most of the time hud category is associated with a single image, sometimes its associated with a list of images. + ///not every hud in this list is actually used. for ones available for others to see, look at active_hud_list. var/list/image/hud_list = null + ///all of this atom's HUD images which can actually be seen by players with that hud + var/list/image/active_hud_list = null ///HUD images that this atom can provide. var/list/hud_possible @@ -155,6 +159,8 @@ var/damage_deflection = 0 var/resistance_flags = NONE // INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ON_FIRE | UNACIDABLE | ACID_PROOF + /// forensics datum, contains fingerprints, fibres, blood_dna and hiddenprints on this atom + var/datum/forensics/forensics /** * Called when an atom is created in byond (built in engine proc) @@ -300,11 +306,14 @@ if(alternate_appearances) for(var/current_alternate_appearance in alternate_appearances) var/datum/atom_hud/alternate_appearance/selected_alternate_appearance = alternate_appearances[current_alternate_appearance] - selected_alternate_appearance.remove_from_hud(src) + selected_alternate_appearance.remove_atom_from_hud(src) if(reagents) QDEL_NULL(reagents) + if(forensics) + QDEL_NULL(forensics) + orbiters = null // The component is attached to us normaly and will be deleted elsewhere LAZYCLEARLIST(overlays) @@ -407,7 +416,7 @@ if(!is_centcom_level(current_turf.z))//if not, don't bother return FALSE - if(istype(current_turf.loc, /area/shuttle/syndicate) || istype(current_turf.loc, /area/syndicate_mothership) || istype(current_turf.loc, /area/shuttle/assault_pod)) + if(istype(current_turf.loc, /area/shuttle/syndicate) || istype(current_turf.loc, /area/centcom/syndicate_mothership) || istype(current_turf.loc, /area/shuttle/assault_pod)) return TRUE return FALSE @@ -884,9 +893,9 @@ var/new_blood_dna = injected_mob.get_blood_dna_list() if(!new_blood_dna) return FALSE - var/old_length = blood_DNA_length() + var/old_length = GET_ATOM_BLOOD_DNA_LENGTH(src) add_blood_DNA(new_blood_dna) - if(blood_DNA_length() == old_length) + if(GET_ATOM_BLOOD_DNA_LENGTH(src) == old_length) return FALSE return TRUE @@ -1376,7 +1385,10 @@ /atom/proc/tool_act(mob/living/user, obj/item/tool, tool_type, is_right_clicking) var/act_result var/signal_result - if(!is_right_clicking) // Left click first for sensibility + + var/is_left_clicking = !is_right_clicking + + if(is_left_clicking) // Left click first for sensibility var/list/processing_recipes = list() //List of recipes that can be mutated by sending the signal signal_result = SEND_SIGNAL(src, COMSIG_ATOM_TOOL_ACT(tool_type), user, tool, processing_recipes) if(signal_result & COMPONENT_BLOCK_TOOL_ATTACK) // The COMSIG_ATOM_TOOL_ACT signal is blocking the act @@ -1385,43 +1397,37 @@ process_recipes(user, tool, processing_recipes) if(QDELETED(tool)) return TRUE - switch(tool_type) - if(TOOL_CROWBAR) - act_result = crowbar_act(user, tool) - if(TOOL_MULTITOOL) - act_result = multitool_act(user, tool) - if(TOOL_SCREWDRIVER) - act_result = screwdriver_act(user, tool) - if(TOOL_WRENCH) - act_result = wrench_act(user, tool) - if(TOOL_WIRECUTTER) - act_result = wirecutter_act(user, tool) - if(TOOL_WELDER) - act_result = welder_act(user, tool) - if(TOOL_ANALYZER) - act_result = analyzer_act(user, tool) else signal_result = SEND_SIGNAL(src, COMSIG_ATOM_SECONDARY_TOOL_ACT(tool_type), user, tool) if(signal_result & COMPONENT_BLOCK_TOOL_ATTACK) // The COMSIG_ATOM_TOOL_ACT signal is blocking the act return TOOL_ACT_SIGNAL_BLOCKING - switch(tool_type) - if(TOOL_CROWBAR) - act_result = crowbar_act_secondary(user, tool) - if(TOOL_MULTITOOL) - act_result = multitool_act_secondary(user, tool) - if(TOOL_SCREWDRIVER) - act_result = screwdriver_act_secondary(user, tool) - if(TOOL_WRENCH) - act_result = wrench_act_secondary(user, tool) - if(TOOL_WIRECUTTER) - act_result = wirecutter_act_secondary(user, tool) - if(TOOL_WELDER) - act_result = welder_act_secondary(user, tool) - if(TOOL_ANALYZER) - act_result = analyzer_act_secondary(user, tool) - if(act_result) // A tooltype_act has completed successfully - log_tool("[key_name(user)] used [tool] on [src][is_right_clicking ? "(right click)" : ""] at [AREACOORD(src)]") - return TOOL_ACT_TOOLTYPE_SUCCESS + + switch(tool_type) + if(TOOL_CROWBAR) + act_result = is_left_clicking ? crowbar_act(user, tool) : crowbar_act_secondary(user, tool) + if(TOOL_MULTITOOL) + act_result = is_left_clicking ? multitool_act(user, tool) : multitool_act_secondary(user, tool) + if(TOOL_SCREWDRIVER) + act_result = is_left_clicking ? screwdriver_act(user, tool) : screwdriver_act_secondary(user, tool) + if(TOOL_WRENCH) + act_result = is_left_clicking ? wrench_act(user, tool) : wrench_act_secondary(user, tool) + if(TOOL_WIRECUTTER) + act_result = is_left_clicking ? wirecutter_act(user, tool) : wirecutter_act_secondary(user, tool) + if(TOOL_WELDER) + act_result = is_left_clicking ? welder_act(user, tool) : welder_act_secondary(user, tool) + if(TOOL_ANALYZER) + act_result = is_left_clicking ? analyzer_act(user, tool) : analyzer_act_secondary(user, tool) + if(!act_result) + return + + // A tooltype_act has completed successfully + if(is_left_clicking) + log_tool("[key_name(user)] used [tool] on [src] at [AREACOORD(src)]") + SEND_SIGNAL(tool, COMSIG_TOOL_ATOM_ACTED_PRIMARY(tool_type), src) + else + log_tool("[key_name(user)] used [tool] on [src] (right click) at [AREACOORD(src)]") + SEND_SIGNAL(tool, COMSIG_TOOL_ATOM_ACTED_SECONDARY(tool_type), src) + return TOOL_ACT_TOOLTYPE_SUCCESS /atom/proc/process_recipes(mob/living/user, obj/item/processed_object, list/processing_recipes) @@ -1555,160 +1561,6 @@ /atom/proc/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock) return -/** - * Generic logging helper - * - * reads the type of the log - * and writes it to the respective log file - * unless log_globally is FALSE - * Arguments: - * * message - The message being logged - * * message_type - the type of log the message is(ATTACK, SAY, etc) - * * color - color of the log text - * * log_globally - boolean checking whether or not we write this log to the log file - */ -/atom/proc/log_message(message, message_type, color=null, log_globally=TRUE) - if(!log_globally) - return - - var/log_text = "[key_name(src)] [message] [loc_name(src)]" - switch(message_type) - if(LOG_ATTACK) - log_attack(log_text) - if(LOG_SAY) - log_say(log_text) - if(LOG_WHISPER) - log_whisper(log_text) - if(LOG_EMOTE) - log_emote(log_text) - if(LOG_RADIO_EMOTE) - log_radio_emote(log_text) - if(LOG_DSAY) - log_dsay(log_text) - if(LOG_PDA) - log_pda(log_text) - if(LOG_CHAT) - log_chat(log_text) - if(LOG_COMMENT) - log_comment(log_text) - if(LOG_TELECOMMS) - log_telecomms(log_text) - if(LOG_ECON) - log_econ(log_text) - if(LOG_OOC) - log_ooc(log_text) - if(LOG_ADMIN) - log_admin(log_text) - if(LOG_ADMIN_PRIVATE) - log_admin_private(log_text) - if(LOG_ASAY) - log_adminsay(log_text) - if(LOG_OWNERSHIP) - log_game(log_text) - if(LOG_GAME) - log_game(log_text) - if(LOG_MECHA) - log_mecha(log_text) - if(LOG_SHUTTLE) - log_shuttle(log_text) - else - stack_trace("Invalid individual logging type: [message_type]. Defaulting to [LOG_GAME] (LOG_GAME).") - log_game(log_text) - -/** - * Helper for logging chat messages or other logs with arbitrary inputs(e.g. announcements) - * - * This proc compiles a log string by prefixing the tag to the message - * and suffixing what it was forced_by if anything - * if the message lacks a tag and suffix then it is logged on its own - * Arguments: - * * message - The message being logged - * * message_type - the type of log the message is(ATTACK, SAY, etc) - * * tag - tag that indicates the type of text(announcement, telepathy, etc) - * * log_globally - boolean checking whether or not we write this log to the log file - * * forced_by - source that forced the dialogue if any - */ -/atom/proc/log_talk(message, message_type, tag = null, log_globally = TRUE, forced_by = null, custom_say_emote = null) - var/prefix = tag ? "([tag]) " : "" - var/suffix = forced_by ? " FORCED by [forced_by]" : "" - log_message("[prefix][custom_say_emote ? "*[custom_say_emote]*, " : ""]\"[message]\"[suffix]", message_type, log_globally=log_globally) - -/// Helper for logging of messages with only one sender and receiver -/proc/log_directed_talk(atom/source, atom/target, message, message_type, tag) - if(!tag) - stack_trace("Unspecified tag for private message") - tag = "UNKNOWN" - - source.log_talk(message, message_type, tag="[tag] to [key_name(target)]") - if(source != target) - target.log_talk(message, LOG_VICTIM, tag="[tag] from [key_name(source)]", log_globally=FALSE) - -/** - * Log a combat message in the attack log - * - * Arguments: - * * atom/user - argument is the actor performing the action - * * atom/target - argument is the target of the action - * * what_done - is a verb describing the action (e.g. punched, throwed, kicked, etc.) - * * atom/object - is a tool with which the action was made (usually an item) - * * addition - is any additional text, which will be appended to the rest of the log line - */ -/proc/log_combat(atom/user, atom/target, what_done, atom/object=null, addition=null) - var/ssource = key_name(user) - var/starget = key_name(target) - - var/mob/living/living_target = target - var/hp = istype(living_target) ? " (NEWHP: [living_target.health]) " : "" - - var/sobject = "" - if(object) - sobject = " with [object]" - var/saddition = "" - if(addition) - saddition = " [addition]" - - var/postfix = "[sobject][saddition][hp]" - - var/message = "has [what_done] [starget][postfix]" - user.log_message(message, LOG_ATTACK, color="red") - - if(user != target) - var/reverse_message = "has been [what_done] by [ssource][postfix]" - target.log_message(reverse_message, LOG_VICTIM, color="orange", log_globally=FALSE) - -/** - * log_wound() is for when someone is *attacked* and suffers a wound. Note that this only captures wounds from damage, so smites/forced wounds aren't logged, as well as demotions like cuts scabbing over - * - * Note that this has no info on the attack that dealt the wound: information about where damage came from isn't passed to the bodypart's damaged proc. When in doubt, check the attack log for attacks at that same time - * TODO later: Add logging for healed wounds, though that will require some rewriting of healing code to prevent admin heals from spamming the logs. Not high priority - * - * Arguments: - * * victim- The guy who got wounded - * * suffered_wound- The wound, already applied, that we're logging. It has to already be attached so we can get the limb from it - * * dealt_damage- How much damage is associated with the attack that dealt with this wound. - * * dealt_wound_bonus- The wound_bonus, if one was specified, of the wounding attack - * * dealt_bare_wound_bonus- The bare_wound_bonus, if one was specified *and applied*, of the wounding attack. Not shown if armor was present - * * base_roll- Base wounding ability of an attack is a random number from 1 to (dealt_damage ** WOUND_DAMAGE_EXPONENT). This is the number that was rolled in there, before mods - */ -/proc/log_wound(atom/victim, datum/wound/suffered_wound, dealt_damage, dealt_wound_bonus, dealt_bare_wound_bonus, base_roll) - if(QDELETED(victim) || !suffered_wound) - return - var/message = "has suffered: [suffered_wound][suffered_wound.limb ? " to [suffered_wound.limb.name]" : null]"// maybe indicate if it's a promote/demote? - - if(dealt_damage) - message += " | Damage: [dealt_damage]" - // The base roll is useful since it can show how lucky someone got with the given attack. For example, dealing a cut - if(base_roll) - message += " (rolled [base_roll]/[dealt_damage ** WOUND_DAMAGE_EXPONENT])" - - if(dealt_wound_bonus) - message += " | WB: [dealt_wound_bonus]" - - if(dealt_bare_wound_bonus) - message += " | BWB: [dealt_bare_wound_bonus]" - - victim.log_message(message, LOG_ATTACK, color="blue") - /atom/proc/add_filter(name,priority,list/params) LAZYINITLIST(filter_data) var/list/copied_parameters = params.Copy() @@ -2207,8 +2059,9 @@ * * ID- An ID card representing what access we have (and thus if we can open things like airlocks or windows to pass through them). The ID card's physical location does not matter, just the reference * * to_dir- What direction we're trying to move in, relevant for things like directional windows that only block movement in certain directions * * caller- The movable we're checking pass flags for, if we're making any such checks + * * no_id: When true, doors with public access will count as impassible **/ -/atom/proc/CanAStarPass(obj/item/card/id/ID, to_dir, atom/movable/caller) +/atom/proc/CanAStarPass(obj/item/card/id/ID, to_dir, atom/movable/caller, no_id = FALSE) if(caller && (caller.pass_flags & pass_flags_self)) return TRUE . = !density diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 79ddce1ff1282..ce8539a8dd09d 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -1,7 +1,7 @@ /atom/movable layer = OBJ_LAYER glide_size = 8 - appearance_flags = TILE_BOUND|PIXEL_SCALE + appearance_flags = TILE_BOUND|PIXEL_SCALE|LONG_GLIDE ///how many times a this movable had movement procs called on it since Moved() was last called var/move_stacks = 0 @@ -29,6 +29,9 @@ var/inertia_moving = FALSE ///Delay in deciseconds between inertia based movement var/inertia_move_delay = 5 + ///The last time we pushed off something + ///This is a hack to get around dumb him him me scenarios + var/last_pushoff /// Things we can pass through while moving. If any of this matches the thing we're trying to pass's [pass_flags_self], then we can pass through. var/pass_flags = NONE /// If false makes [CanPass][/atom/proc/CanPass] call [CanPassThrough][/atom/movable/proc/CanPassThrough] on this type instead of using default behaviour @@ -48,6 +51,11 @@ ///only the last container of a client eye has this list assuming no movement since SSparallax's last fire var/list/client_mobs_in_contents + /// String representing the spatial grid groups we want to be held in. + /// acts as a key to the list of spatial grid contents types we exist in via SSspatial_grid.spatial_grid_categories. + /// We do it like this to prevent people trying to mutate them and to save memory on holding the lists ourselves + var/spatial_grid_key + /** * In case you have multiple types, you automatically use the most useful one. * IE: Skating on ice, flippers on water, flying over chasm/space, etc. @@ -138,7 +146,7 @@ qdel(move_packet) move_packet = null - if(important_recursive_contents && (important_recursive_contents[RECURSIVE_CONTENTS_CLIENT_MOBS] || important_recursive_contents[RECURSIVE_CONTENTS_HEARING_SENSITIVE])) + if(spatial_grid_key) SSspatial_grid.force_remove_from_cell(src) LAZYCLEARLIST(client_mobs_in_contents) @@ -368,12 +376,14 @@ return TRUE /atom/movable/proc/stop_pulling() - if(pulling) - SEND_SIGNAL(pulling, COMSIG_ATOM_NO_LONGER_PULLED, src) - pulling.set_pulledby(null) - setGrabState(GRAB_PASSIVE) - pulling = null - + if(!pulling) + return + pulling.set_pulledby(null) + setGrabState(GRAB_PASSIVE) + var/atom/movable/old_pulling = pulling + pulling = null + SEND_SIGNAL(old_pulling, COMSIG_ATOM_NO_LONGER_PULLED, src) + SEND_SIGNAL(src, COMSIG_ATOM_NO_LONGER_PULLING, old_pulling) ///Reports the event of the change in value of the pulledby variable. /atom/movable/proc/set_pulledby(new_pulledby) @@ -427,7 +437,6 @@ if(!only_pulling && pulledby && moving_diagonally != FIRST_DIAG_STEP && (get_dist(src, pulledby) > 1 || z != pulledby.z)) //separated from our puller and not in the middle of a diagonal move. pulledby.stop_pulling() - /atom/movable/proc/set_glide_size(target = 8) SEND_SIGNAL(src, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE, target) glide_size = target @@ -590,6 +599,8 @@ setDir(first_step_dir) else if (!inertia_moving) newtonian_move(direct) + if(client_mobs_in_contents) // We're done moving, update our parallax now + update_parallax_contents() moving_diagonally = 0 return @@ -656,7 +667,10 @@ if (!inertia_moving) newtonian_move(movement_dir) - if (client_mobs_in_contents) + // If we ain't moving diagonally right now, update our parallax + // We don't do this all the time because diag movements should trigger one call to this, not two + // Waste of cpu time, and it fucks the animate + if (!moving_diagonally && client_mobs_in_contents) update_parallax_contents() move_stacks-- @@ -676,8 +690,8 @@ if(HAS_SPATIAL_GRID_CONTENTS(src)) if(old_turf && new_turf && (old_turf.z != new_turf.z \ - || ROUND_UP(old_turf.x / SPATIAL_GRID_CELLSIZE) != ROUND_UP(new_turf.x / SPATIAL_GRID_CELLSIZE) \ - || ROUND_UP(old_turf.y / SPATIAL_GRID_CELLSIZE) != ROUND_UP(new_turf.y / SPATIAL_GRID_CELLSIZE))) + || GET_SPATIAL_INDEX(old_turf.x) != GET_SPATIAL_INDEX(new_turf.x) \ + || GET_SPATIAL_INDEX(old_turf.y) != GET_SPATIAL_INDEX(new_turf.y))) SSspatial_grid.exit_cell(src, old_turf) SSspatial_grid.enter_cell(src, new_turf) @@ -752,36 +766,54 @@ /atom/movable/Exited(atom/movable/gone, direction) . = ..() - if(LAZYLEN(gone.important_recursive_contents)) - var/list/nested_locs = get_nested_locs(src) + src - for(var/channel in gone.important_recursive_contents) - for(var/atom/movable/location as anything in nested_locs) - LAZYREMOVEASSOC(location.important_recursive_contents, channel, gone.important_recursive_contents[channel]) + if(!LAZYLEN(gone.important_recursive_contents)) + return + var/list/nested_locs = get_nested_locs(src) + src + for(var/channel in gone.important_recursive_contents) + for(var/atom/movable/location as anything in nested_locs) + var/list/recursive_contents = location.important_recursive_contents // blue hedgehog velocity + recursive_contents[channel] -= gone.important_recursive_contents[channel] + switch(channel) + if(RECURSIVE_CONTENTS_CLIENT_MOBS, RECURSIVE_CONTENTS_HEARING_SENSITIVE) + if(!length(recursive_contents[channel])) + // This relies on a nice property of the linked recursive and gridmap types + // They're defined in relation to each other, so they have the same value + SSspatial_grid.remove_grid_awareness(location, channel) + ASSOC_UNSETEMPTY(recursive_contents, channel) + UNSETEMPTY(location.important_recursive_contents) /atom/movable/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs) . = ..() - if(LAZYLEN(arrived.important_recursive_contents)) - var/list/nested_locs = get_nested_locs(src) + src - for(var/channel in arrived.important_recursive_contents) - for(var/atom/movable/location as anything in nested_locs) - LAZYORASSOCLIST(location.important_recursive_contents, channel, arrived.important_recursive_contents[channel]) + if(!LAZYLEN(arrived.important_recursive_contents)) + return + var/list/nested_locs = get_nested_locs(src) + src + for(var/channel in arrived.important_recursive_contents) + for(var/atom/movable/location as anything in nested_locs) + LAZYINITLIST(location.important_recursive_contents) + var/list/recursive_contents = location.important_recursive_contents // blue hedgehog velocity + LAZYINITLIST(recursive_contents[channel]) + switch(channel) + if(RECURSIVE_CONTENTS_CLIENT_MOBS, RECURSIVE_CONTENTS_HEARING_SENSITIVE) + if(!length(recursive_contents[channel])) + SSspatial_grid.add_grid_awareness(location, channel) + recursive_contents[channel] |= arrived.important_recursive_contents[channel] ///allows this movable to hear and adds itself to the important_recursive_contents list of itself and every movable loc its in /atom/movable/proc/become_hearing_sensitive(trait_source = TRAIT_GENERIC) + ADD_TRAIT(src, TRAIT_HEARING_SENSITIVE, trait_source) if(!HAS_TRAIT(src, TRAIT_HEARING_SENSITIVE)) - //RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_HEARING_SENSITIVE), .proc/on_hearing_sensitive_trait_loss) - for(var/atom/movable/location as anything in get_nested_locs(src) + src) - LAZYADDASSOCLIST(location.important_recursive_contents, RECURSIVE_CONTENTS_HEARING_SENSITIVE, src) - - var/turf/our_turf = get_turf(src) - if(our_turf && SSspatial_grid.initialized) - SSspatial_grid.enter_cell(src, our_turf) + return - else if(our_turf && !SSspatial_grid.initialized)//SSspatial_grid isnt init'd yet, add ourselves to the queue - SSspatial_grid.enter_pre_init_queue(src, RECURSIVE_CONTENTS_HEARING_SENSITIVE) + for(var/atom/movable/location as anything in get_nested_locs(src) + src) + LAZYINITLIST(location.important_recursive_contents) + var/list/recursive_contents = location.important_recursive_contents // blue hedgehog velocity + if(!length(recursive_contents[RECURSIVE_CONTENTS_HEARING_SENSITIVE])) + SSspatial_grid.add_grid_awareness(location, SPATIAL_GRID_CONTENTS_TYPE_HEARING) + recursive_contents[RECURSIVE_CONTENTS_HEARING_SENSITIVE] += list(src) - ADD_TRAIT(src, TRAIT_HEARING_SENSITIVE, trait_source) + var/turf/our_turf = get_turf(src) + SSspatial_grid.add_grid_membership(src, our_turf, SPATIAL_GRID_CONTENTS_TYPE_HEARING) /** * removes the hearing sensitivity channel from the important_recursive_contents list of this and all nested locs containing us if there are no more sources of the trait left @@ -797,13 +829,16 @@ return var/turf/our_turf = get_turf(src) - if(our_turf && SSspatial_grid.initialized) - SSspatial_grid.exit_cell(src, our_turf) - else if(our_turf && !SSspatial_grid.initialized) - SSspatial_grid.remove_from_pre_init_queue(src, RECURSIVE_CONTENTS_HEARING_SENSITIVE) + /// We get our awareness updated by the important recursive contents stuff, here we remove our membership + SSspatial_grid.remove_grid_membership(src, our_turf, SPATIAL_GRID_CONTENTS_TYPE_HEARING) for(var/atom/movable/location as anything in get_nested_locs(src) + src) - LAZYREMOVEASSOC(location.important_recursive_contents, RECURSIVE_CONTENTS_HEARING_SENSITIVE, src) + var/list/recursive_contents = location.important_recursive_contents // blue hedgehog velocity + recursive_contents[RECURSIVE_CONTENTS_HEARING_SENSITIVE] -= src + if(!length(recursive_contents[RECURSIVE_CONTENTS_HEARING_SENSITIVE])) + SSspatial_grid.remove_grid_awareness(location, SPATIAL_GRID_CONTENTS_TYPE_HEARING) + ASSOC_UNSETEMPTY(recursive_contents, RECURSIVE_CONTENTS_HEARING_SENSITIVE) + UNSETEMPTY(location.important_recursive_contents) ///allows this movable to know when it has "entered" another area no matter how many movable atoms its stuffed into, uses important_recursive_contents /atom/movable/proc/become_area_sensitive(trait_source = TRAIT_GENERIC) @@ -827,27 +862,30 @@ ///propogates ourselves through our nested contents, similar to other important_recursive_contents procs ///main difference is that client contents need to possibly duplicate recursive contents for the clients mob AND its eye /mob/proc/enable_client_mobs_in_contents() - var/turf/our_turf = get_turf(src) - - if(our_turf && SSspatial_grid.initialized) - SSspatial_grid.enter_cell(src, our_turf, RECURSIVE_CONTENTS_CLIENT_MOBS) - else if(our_turf && !SSspatial_grid.initialized) - SSspatial_grid.enter_pre_init_queue(src, RECURSIVE_CONTENTS_CLIENT_MOBS) - for(var/atom/movable/movable_loc as anything in get_nested_locs(src) + src) - LAZYORASSOCLIST(movable_loc.important_recursive_contents, RECURSIVE_CONTENTS_CLIENT_MOBS, src) + LAZYINITLIST(movable_loc.important_recursive_contents) + var/list/recursive_contents = movable_loc.important_recursive_contents // blue hedgehog velocity + if(!length(recursive_contents[RECURSIVE_CONTENTS_CLIENT_MOBS])) + SSspatial_grid.add_grid_awareness(movable_loc, SPATIAL_GRID_CONTENTS_TYPE_CLIENTS) + LAZYINITLIST(recursive_contents[RECURSIVE_CONTENTS_CLIENT_MOBS]) + recursive_contents[RECURSIVE_CONTENTS_CLIENT_MOBS] |= src + + var/turf/our_turf = get_turf(src) + /// We got our awareness updated by the important recursive contents stuff, now we add our membership + SSspatial_grid.add_grid_membership(src, our_turf, SPATIAL_GRID_CONTENTS_TYPE_CLIENTS) ///Clears the clients channel of this mob /mob/proc/clear_important_client_contents() var/turf/our_turf = get_turf(src) - - if(our_turf && SSspatial_grid.initialized) - SSspatial_grid.exit_cell(src, our_turf, RECURSIVE_CONTENTS_CLIENT_MOBS) - else if(our_turf && !SSspatial_grid.initialized) - SSspatial_grid.remove_from_pre_init_queue(src, RECURSIVE_CONTENTS_CLIENT_MOBS) + SSspatial_grid.remove_grid_membership(src, our_turf, SPATIAL_GRID_CONTENTS_TYPE_CLIENTS) for(var/atom/movable/movable_loc as anything in get_nested_locs(src) + src) - LAZYREMOVEASSOC(movable_loc.important_recursive_contents, RECURSIVE_CONTENTS_CLIENT_MOBS, src) + var/list/recursive_contents = movable_loc.important_recursive_contents // blue hedgehog velocity + recursive_contents[RECURSIVE_CONTENTS_CLIENT_MOBS] -= src + if(!length(recursive_contents[RECURSIVE_CONTENTS_CLIENT_MOBS])) + SSspatial_grid.remove_grid_awareness(movable_loc, SPATIAL_GRID_CONTENTS_TYPE_CLIENTS) + ASSOC_UNSETEMPTY(recursive_contents, RECURSIVE_CONTENTS_CLIENT_MOBS) + UNSETEMPTY(movable_loc.important_recursive_contents) ///Sets the anchored var and returns if it was sucessfully changed or not. /atom/movable/proc/set_anchored(anchorvalue) @@ -943,9 +981,10 @@ * * Arguments: * * movement_dir - 0 when stopping or any dir when trying to move + * * continuous_move - If this check is coming from something in the context of already drifting */ -/atom/movable/proc/Process_Spacemove(movement_dir = 0) - if(SEND_SIGNAL(src, COMSIG_MOVABLE_SPACEMOVE, movement_dir) & COMSIG_MOVABLE_STOP_SPACEMOVE) +/atom/movable/proc/Process_Spacemove(movement_dir = 0, continuous_move = FALSE) + if(SEND_SIGNAL(src, COMSIG_MOVABLE_SPACEMOVE, movement_dir, continuous_move) & COMSIG_MOVABLE_STOP_SPACEMOVE) return TRUE if(has_gravity(src)) @@ -967,16 +1006,15 @@ /// Only moves the object if it's under no gravity -/// Accepts the direction to move, and if the push should be instant -/atom/movable/proc/newtonian_move(direction, instant = FALSE) - if(!isturf(loc) || Process_Spacemove(0)) +/// Accepts the direction to move, if the push should be instant, and an optional parameter to fine tune the start delay +/atom/movable/proc/newtonian_move(direction, instant = FALSE, start_delay = 0) + if(!isturf(loc) || Process_Spacemove(direction, continuous_move = TRUE)) return FALSE - if(SEND_SIGNAL(src, COMSIG_MOVABLE_NEWTONIAN_MOVE, direction) & COMPONENT_MOVABLE_NEWTONIAN_BLOCK) + if(SEND_SIGNAL(src, COMSIG_MOVABLE_NEWTONIAN_MOVE, direction, start_delay) & COMPONENT_MOVABLE_NEWTONIAN_BLOCK) return TRUE - set_glide_size(MOVEMENT_ADJUSTED_GLIDE_SIZE(inertia_move_delay, SSspacedrift.visual_delay)) - AddComponent(/datum/component/drift, direction, instant) + AddComponent(/datum/component/drift, direction, instant, start_delay) return TRUE @@ -1131,23 +1169,19 @@ SEND_SIGNAL(src, COMSIG_STORAGE_ENTERED, master_storage) /atom/movable/proc/get_spacemove_backup() - var/atom/movable/dense_object_backup for(var/checked_range in orange(1, get_turf(src))) if(isarea(checked_range)) continue - else if(isturf(checked_range)) + if(isturf(checked_range)) var/turf/turf = checked_range if(!turf.density) continue return turf - else - var/atom/movable/checked_atom = checked_range - if(checked_atom.density || !checked_atom.CanPass(src, get_dir(src, checked_atom))) - if(checked_atom.anchored) - return checked_atom - dense_object_backup = checked_atom - break - . = dense_object_backup + var/atom/movable/checked_atom = checked_range + if(checked_atom.density || !checked_atom.CanPass(src, get_dir(src, checked_atom))) + if(checked_atom.last_pushoff == world.time) + continue + return checked_atom ///called when a mob resists while inside a container that is itself inside something. /atom/movable/proc/relay_container_resist_act(mob/living/user, obj/container) diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm index 89dbe87a97635..72a2003eb0482 100644 --- a/code/game/data_huds.dm +++ b/code/game/data_huds.dm @@ -9,11 +9,11 @@ /atom/proc/add_to_all_human_data_huds() for(var/datum/atom_hud/data/human/hud in GLOB.huds) - hud.add_to_hud(src) + hud.add_atom_to_hud(src) /atom/proc/remove_from_all_data_huds() for(var/datum/atom_hud/data/hud in GLOB.huds) - hud.remove_from_hud(src) + hud.remove_atom_from_hud(src) /datum/atom_hud/data @@ -32,12 +32,12 @@ return FALSE return TRUE -/datum/atom_hud/data/human/medical/basic/add_to_single_hud(mob/M, mob/living/carbon/H) +/datum/atom_hud/data/human/medical/basic/add_atom_to_single_mob_hud(mob/M, mob/living/carbon/H) if(check_sensors(H)) ..() /datum/atom_hud/data/human/medical/basic/proc/update_suit_sensors(mob/living/carbon/H) - check_sensors(H) ? add_to_hud(H) : remove_from_hud(H) + check_sensors(H) ? add_atom_to_hud(H) : remove_atom_from_hud(H) /datum/atom_hud/data/human/medical/advanced @@ -61,6 +61,8 @@ hud_icons = list(DIAG_HUD, DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_BOT_HUD, DIAG_CIRCUIT_HUD, DIAG_TRACK_HUD, DIAG_AIRLOCK_HUD, DIAG_LAUNCHPAD_HUD, DIAG_PATH_HUD) /datum/atom_hud/data/bot_path + // This hud exists so the bot can see itself, that's all + uses_global_hud_category = FALSE hud_icons = list(DIAG_PATH_HUD) /datum/atom_hud/abductor @@ -72,12 +74,12 @@ /datum/atom_hud/ai_detector hud_icons = list(AI_DETECT_HUD) -/datum/atom_hud/ai_detector/add_hud_to(mob/M) +/datum/atom_hud/ai_detector/show_to(mob/new_viewer) ..() - if(M && (hudusers.len == 1)) - for(var/V in GLOB.aiEyes) - var/mob/camera/ai_eye/E = V - E.update_ai_detect_hud() + if(!new_viewer || hud_users.len != 1) + return + for(var/mob/camera/ai_eye/eye as anything in GLOB.aiEyes) + eye.update_ai_detect_hud() /* MED/SEC/DIAG HUD HOOKS */ @@ -229,11 +231,19 @@ FAN HUDs! For identifying other fans on-sight. holder.pixel_y = I.Height() - world.icon_size holder.icon_state = "hudfan_no" var/obj/item/clothing/under/U = get_item_by_slot(ITEM_SLOT_ICLOTHING) - if(U) - if(istype(U.attached_accessory, /obj/item/clothing/accessory/mime_fan_pin)) - holder.icon_state = "mime_fan_pin" - else if(istype(U.attached_accessory, /obj/item/clothing/accessory/clown_enjoyer_pin)) - holder.icon_state = "clown_enjoyer_pin" + if(!U) + set_hud_image_inactive(FAN_HUD) + return + + if(istype(U.attached_accessory, /obj/item/clothing/accessory/mime_fan_pin)) + holder.icon_state = "mime_fan_pin" + + else if(istype(U.attached_accessory, /obj/item/clothing/accessory/clown_enjoyer_pin)) + holder.icon_state = "clown_enjoyer_pin" + set_hud_image_active(FAN_HUD) + return + + /*********************************************** Security HUDs! Basic mode shows only the job. @@ -256,22 +266,29 @@ Security HUDs! Basic mode shows only the job. for(var/i in list(IMPTRACK_HUD, IMPLOYAL_HUD, IMPCHEM_HUD)) holder = hud_list[i] holder.icon_state = null + set_hud_image_inactive(i) + for(var/obj/item/implant/I in implants) if(istype(I, /obj/item/implant/tracking)) holder = hud_list[IMPTRACK_HUD] var/icon/IC = icon(icon, icon_state, dir) holder.pixel_y = IC.Height() - world.icon_size holder.icon_state = "hud_imp_tracking" + set_hud_image_active(IMPTRACK_HUD) + else if(istype(I, /obj/item/implant/chem)) holder = hud_list[IMPCHEM_HUD] var/icon/IC = icon(icon, icon_state, dir) holder.pixel_y = IC.Height() - world.icon_size holder.icon_state = "hud_imp_chem" + set_hud_image_active(IMPCHEM_HUD) + if(HAS_TRAIT(src, TRAIT_MINDSHIELD)) holder = hud_list[IMPLOYAL_HUD] var/icon/IC = icon(icon, icon_state, dir) holder.pixel_y = IC.Height() - world.icon_size holder.icon_state = "hud_imp_loyal" + set_hud_image_active(IMPLOYAL_HUD) /mob/living/carbon/human/proc/sec_hud_set_security_status() var/image/holder = hud_list[WANTED_HUD] @@ -281,23 +298,26 @@ Security HUDs! Basic mode shows only the job. if(perpname && GLOB.data_core) var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.security) if(R) + var/has_criminal_entry = TRUE switch(R.fields["criminal"]) if("*Arrest*") holder.icon_state = "hudwanted" - return if("Incarcerated") holder.icon_state = "hudincarcerated" - return if("Suspected") holder.icon_state = "hudsuspected" - return if("Paroled") holder.icon_state = "hudparolled" - return if("Discharged") holder.icon_state = "huddischarged" - return + else + has_criminal_entry = FALSE + if(has_criminal_entry) + set_hud_image_active(WANTED_HUD) + return + holder.icon_state = null + set_hud_image_inactive(WANTED_HUD) /*********************************************** Diagnostic HUDs! @@ -361,10 +381,13 @@ Diagnostic HUDs! holder.pixel_y = I.Height() - world.icon_size if(!shell) //Not an AI shell holder.icon_state = null + set_hud_image_inactive(DIAG_TRACK_HUD) + return else if(deployed) //AI shell in use by an AI holder.icon_state = "hudtrackingai" else //Empty AI shell holder.icon_state = "hudtracking" + set_hud_image_active(DIAG_TRACK_HUD) //AI side tracking of AI shell control /mob/living/silicon/ai/proc/diag_hud_set_deployed() //Shows tracking beacons on the mech @@ -373,8 +396,10 @@ Diagnostic HUDs! holder.pixel_y = I.Height() - world.icon_size if(!deployed_shell) holder.icon_state = null + set_hud_image_inactive(DIAG_TRACK_HUD) else //AI is currently controlling a shell holder.icon_state = "hudtrackingai" + set_hud_image_active(DIAG_TRACK_HUD) /*~~~~~~~~~~~~~~~~~~~~ BIG STOMPY MECHS @@ -401,11 +426,14 @@ Diagnostic HUDs! var/image/holder = hud_list[DIAG_STAT_HUD] var/icon/I = icon(icon, icon_state, dir) holder.pixel_y = I.Height() - world.icon_size - holder.icon_state = null if(internal_damage) holder.icon_state = "hudwarn" + set_hud_image_active(DIAG_STAT_HUD) + holder.icon_state = null + set_hud_image_inactive(DIAG_STAT_HUD) -/obj/vehicle/sealed/mecha/proc/diag_hud_set_mechtracking() //Shows tracking beacons on the mech +///Shows tracking beacons on the mech +/obj/vehicle/sealed/mecha/proc/diag_hud_set_mechtracking() var/image/holder = hud_list[DIAG_TRACK_HUD] var/icon/I = icon(icon, icon_state, dir) holder.pixel_y = I.Height() - world.icon_size @@ -474,8 +502,10 @@ Diagnostic HUDs! Airlocks! ~~~~~~~~~~~~~*/ /obj/machinery/door/airlock/proc/diag_hud_set_electrified() + if(secondsElectrified == MACHINE_NOT_ELECTRIFIED) + set_hud_image_inactive(DIAG_AIRLOCK_HUD) + return + var/image/holder = hud_list[DIAG_AIRLOCK_HUD] - if(secondsElectrified != MACHINE_NOT_ELECTRIFIED) - holder.icon_state = "electrified" - else - holder.icon_state = "" + holder.icon_state = "electrified" + set_hud_image_active(DIAG_AIRLOCK_HUD) diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm index bcde127b47339..b05802b536269 100644 --- a/code/game/gamemodes/dynamic/dynamic.dm +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -78,26 +78,29 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) /// The maximum time the recurring latejoin ruleset timer is allowed to be. var/latejoin_delay_max = (25 MINUTES) - /// When world.time is over this number the mode tries to inject a midround ruleset. - var/midround_injection_cooldown = 0 - - /// The minimum time the recurring midround ruleset timer is allowed to be. - var/midround_delay_min = (15 MINUTES) - - /// The maximum time the recurring midround ruleset timer is allowed to be. - var/midround_delay_max = (35 MINUTES) - - /// If above this threat, increase the chance of injection - var/higher_injection_chance_minimum_threat = 70 - - /// The chance of injection increase when above higher_injection_chance_minimum_threat - var/higher_injection_chance = 15 - - /// If below this threat, decrease the chance of injection - var/lower_injection_chance_minimum_threat = 10 - - /// The chance of injection decrease when above lower_injection_chance_minimum_threat - var/lower_injection_chance = 15 + /// The low bound for the midround roll time splits. + /// This number influences where to place midround rolls, making this smaller + /// will make midround rolls more frequent, and vice versa. + /// A midround will never be able to roll before this. + var/midround_lower_bound = 10 MINUTES + + /// The upper bound for the midround roll time splits. + /// This number influences where to place midround rolls, making this larger + /// will make midround rolls less frequent, and vice versa. + /// A midround will never be able to roll farther than this. + var/midround_upper_bound = 100 MINUTES + + /// The distance between the chosen midround roll point (which is deterministic), + /// and when it can actually roll. + /// Basically, if this is set to 5 minutes, and a midround roll point is decided to be at 20 minutes, + /// then it can roll anywhere between 15 and 25 minutes. + var/midround_roll_distance = 3 MINUTES + + /// The amount of threat per midround roll. + /// Basically, if this is set to 5, then for every 5 threat, one midround roll will be added. + /// The equation this is used in rounds up, meaning that if this is set to 5, and you have 6 + /// threat, then you will get 2 midround rolls. + var/threat_per_midround_roll = 6.5 /// A number between -5 and +5. /// A negative value will give a more peaceful round and @@ -127,15 +130,49 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) /// The maximum amount of time for antag random events to be hijacked. var/random_event_hijack_maximum = 18 MINUTES + /// What is the lower bound of when the roundstart annoucement is sent out? + var/waittime_l = 600 + + /// What is the higher bound of when the roundstart annoucement is sent out? + var/waittime_h = 1800 + + /// Maximum amount of threat allowed to generate. + var/max_threat_level = 100 + + /// The extra chance multiplier that a heavy impact midround ruleset will run next time. + /// For example, if this is set to 50, then the next heavy roll will be about 50% more likely to happen. + var/hijacked_random_event_injection_chance_modifier = 50 + + /// Any midround before this point is guaranteed to be light + var/midround_light_upper_bound = 25 MINUTES + + /// Any midround after this point is guaranteed to be heavy + var/midround_heavy_lower_bound = 55 MINUTES + + /// If there are less than this many players readied, threat level will be lowered. + /// This number should be kept fairly low, as there are other measures that population + /// impacts Dynamic, such as the requirements variable on rulesets. + var/low_pop_player_threshold = 20 + + /// The maximum threat that can roll with *zero* players. + /// As the number of players approaches `low_pop_player_threshold`, the maximum + /// threat level will increase. + /// For example, if `low_pop_minimum_threat` is 50, `low_pop_player_threshold` is 20, + /// and the number of readied players is 10, then the highest threat that can roll is + /// lerp(50, 100, 10 / 20), AKA 75. + var/low_pop_minimum_threat = 50 + + /// The chance for latejoins to roll when ready + var/latejoin_roll_chance = 50 + + // == EVERYTHING BELOW THIS POINT SHOULD NOT BE CONFIGURED == + /// A list of recorded "snapshots" of the round, stored in the dynamic.json log var/list/datum/dynamic_snapshot/snapshots /// The time when the last midround injection was attempted, whether or not it was successful var/last_midround_injection_attempt = 0 - /// The amount to inject when a round event is hijacked - var/hijacked_random_event_injection_chance = 50 - /// Whether or not a random event has been hijacked this midround cycle var/random_event_hijacked = HIJACKED_NOTHING @@ -150,14 +187,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) /// Can differ from the actual threat amount. var/shown_threat - /// What is the lower bound of when the roundstart annoucement is sent out? - var/waittime_l = 600 - /// What is the higher bound of when the roundstart annoucement is sent out? - var/waittime_h = 1800 - - /// Maximum amount of threat allowed to generate. - var/max_threat_level = 100 - + VAR_PRIVATE/next_midround_injection /datum/game_mode/dynamic/admin_panel() var/list/dat = list("" dat += " |