diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index c46a75e4ac8..227256f4956 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -78,38 +78,40 @@ #define ALIEN_BODYPART "alien" #define LARVA_BODYPART "larva" -//Bodytype defines for how things can be worn, surgery, and other misc things. +//Bodytype defines for surgery, and other misc things. ///The limb is organic. #define BODYTYPE_ORGANIC (1<<0) ///The limb is robotic. #define BODYTYPE_ROBOTIC (1<<1) -///The limb fits the human mold. This is not meant to be literal, if the sprite "fits" on a human, it is "humanoid", regardless of origin. -#define BODYTYPE_HUMANOID (1<<2) -///The limb fits the monkey mold. -#define BODYTYPE_MONKEY (1<<3) -///The limb is digitigrade. -#define BODYTYPE_DIGITIGRADE (1<<4) -///The limb is snouted. -#define BODYTYPE_SNOUTED (1<<5) ///A placeholder bodytype for xeno larva, so their limbs cannot be attached to anything. -#define BODYTYPE_LARVA_PLACEHOLDER (1<<6) +#define BODYTYPE_LARVA_PLACEHOLDER (1<<2) ///The limb is from a xenomorph. -#define BODYTYPE_ALIEN (1<<7) +#define BODYTYPE_ALIEN (1<<3) ///The limb is from a golem -#define BODYTYPE_GOLEM (1<<8) +#define BODYTYPE_GOLEM (1<<4) // NOVA EDIT ADDITION ///The limb fits a modular custom shape -#define BODYTYPE_CUSTOM (1<<9) +#define BODYSHAPE_CUSTOM (1<<9) ///The limb fits a taur body -#define BODYTYPE_TAUR (1<<10) +#define BODYSHAPE_TAUR (1<<10) ///The limb causes shoes to no longer be displayed, useful for taurs. -#define BODYTYPE_HIDE_SHOES (1<<11) +#define BODYSHAPE_HIDE_SHOES (1<<11) ///The limb causes glasses and hats to be drawn on layers 5 and 4 respectively. Currently used for snouts with the (Top) suffix, which are drawn on layer 6 and would normally cover facewear -#define BODYTYPE_ALT_FACEWEAR_LAYER (1<<12) +#define BODYSHAPE_ALT_FACEWEAR_LAYER (1<<12) // NOVA EDIT END -#define BODYTYPE_BIOSCRAMBLE_COMPATIBLE (BODYTYPE_HUMANOID | BODYTYPE_MONKEY | BODYTYPE_ALIEN) -#define BODYTYPE_CAN_BE_BIOSCRAMBLED(bodytype) (!(bodytype & BODYTYPE_ROBOTIC) && (bodytype & BODYTYPE_BIOSCRAMBLE_COMPATIBLE)) +// Bodyshape defines for how things can be worn, i.e., what "shape" the mob sprite is +///The limb fits the human mold. This is not meant to be literal, if the sprite "fits" on a human, it is "humanoid", regardless of origin. +#define BODYSHAPE_HUMANOID (1<<0) +///The limb fits the monkey mold. +#define BODYSHAPE_MONKEY (1<<1) +///The limb is digitigrade. +#define BODYSHAPE_DIGITIGRADE (1<<2) +///The limb is snouted. +#define BODYSHAPE_SNOUTED (1<<3) + +#define BODYTYPE_BIOSCRAMBLE_INCOMPATIBLE (BODYTYPE_ROBOTIC | BODYTYPE_LARVA_PLACEHOLDER | BODYTYPE_GOLEM) +#define BODYTYPE_CAN_BE_BIOSCRAMBLED(bodytype) (!(bodytype & BODYTYPE_BIOSCRAMBLE_INCOMPATIBLE)) // Defines for Species IDs. Used to refer to the name of a species, for things like bodypart names or species preferences. #define SPECIES_ABDUCTOR "abductor" diff --git a/code/__DEFINES/~nova_defines/antag_optin_defines.dm b/code/__DEFINES/~nova_defines/antag_optin_defines.dm new file mode 100644 index 00000000000..50e750053b9 --- /dev/null +++ b/code/__DEFINES/~nova_defines/antag_optin_defines.dm @@ -0,0 +1,45 @@ +//defines for antag opt in objective checking +//objectives check for all players with a value equal or greater than the 'threat' level of an objective then pick from that list +//command + sec roles are always opted in regardless of opt in status + +/// For temporary or otherwise 'inconvenient' objectives like kidnapping or theft +#define OPT_IN_YES_TEMP 1 +/// Cool with being killed or otherwise occupied but not removed from the round +#define OPT_IN_YES_KILL 2 +/// Fine with being round removed. +#define OPT_IN_YES_ROUND_REMOVE 3 + +#define OPT_IN_YES_TEMP_STRING "Yes - Temporary/Inconvenience" +#define OPT_IN_YES_KILL_STRING "Yes - Kill" +#define OPT_IN_YES_ROUND_REMOVE_STRING "Yes - Round Remove" +#define OPT_IN_NOT_TARGET_STRING "No" + +/// Assoc list of stringified opt_in_## define to the front-end string to show users as a representation of the setting. +GLOBAL_LIST_INIT(antag_opt_in_strings, list( + "0" = OPT_IN_NOT_TARGET_STRING, + "1" = OPT_IN_YES_TEMP_STRING, + "2" = OPT_IN_YES_KILL_STRING, + "3" = OPT_IN_YES_ROUND_REMOVE_STRING, +)) + +/// Assoc list of stringified opt_in_## define to the color associated with it. +GLOBAL_LIST_INIT(antag_opt_in_colors, list( + OPT_IN_NOT_TARGET_STRING = COLOR_GRAY, + OPT_IN_YES_TEMP_STRING = COLOR_EMERALD, + OPT_IN_YES_KILL_STRING = COLOR_ORANGE, + OPT_IN_YES_ROUND_REMOVE_STRING = COLOR_RED +)) + +/// Prefers not to be a target. Will still be a potential target if playing sec or command. +#define OPT_IN_NOT_TARGET 0 + +/// The minimum opt-in level for people playing sec. +#define SECURITY_OPT_IN_LEVEL OPT_IN_YES_KILL +/// The minimum opt-in level for people playing command. +#define COMMAND_OPT_IN_LEVEL OPT_IN_YES_KILL + +/// The default opt in level for preferences and mindless mobs. +#define OPT_IN_DEFAULT_LEVEL OPT_IN_NOT_TARGET + +/// If the player has any non-ghost role antags enabled, they are forced to use a minimum of this. +#define OPT_IN_ANTAG_ENABLED_LEVEL OPT_IN_YES_TEMP diff --git a/code/__DEFINES/~nova_defines/jobs.dm b/code/__DEFINES/~nova_defines/jobs.dm index 7aa6486c9d5..a8cc61a9cf7 100644 --- a/code/__DEFINES/~nova_defines/jobs.dm +++ b/code/__DEFINES/~nova_defines/jobs.dm @@ -6,9 +6,11 @@ #define JOB_UNAVAILABLE_FLAVOUR (JOB_UNAVAILABLE_LANGUAGE + 1) #define JOB_UNAVAILABLE_AUGMENT (JOB_UNAVAILABLE_FLAVOUR + 1) -#define SEC_RESTRICTED_QUIRKS "Blind" = TRUE, "Brain Tumor" = TRUE, "Deaf" = TRUE, "Paraplegic" = TRUE, "Hemiplegic" = TRUE, "Mute" = TRUE, "Foreigner" = TRUE, "Pacifist" = TRUE, "No Guns" = TRUE, "Illiterate" = TRUE, "Nerve Stapled" = TRUE -#define HEAD_RESTRICTED_QUIRKS "Blind" = TRUE, "Deaf" = TRUE, "Mute" = TRUE, "Foreigner" = TRUE, "Brain Tumor" = TRUE, "Illiterate" = TRUE +#define SEC_RESTRICTED_QUIRKS "Blind" = TRUE, "Brain Tumor" = TRUE, "Deaf" = TRUE, "Paraplegic" = TRUE, "Hemiplegic" = TRUE, "Mute" = TRUE, "Foreigner" = TRUE, "Pacifist" = TRUE, "No Guns" = TRUE, "Illiterate" = TRUE, "Nerve Stapled" = TRUE, "Underworld Connections" = TRUE +#define HEAD_RESTRICTED_QUIRKS "Blind" = TRUE, "Deaf" = TRUE, "Mute" = TRUE, "Foreigner" = TRUE, "Brain Tumor" = TRUE, "Illiterate" = TRUE, "Underworld Connections" = TRUE +#define HEAD_RESTRICTED_QUIRKS_QM "Blind" = TRUE, "Deaf" = TRUE, "Mute" = TRUE, "Foreigner" = TRUE, "Brain Tumor" = TRUE, "Illiterate" = TRUE #define GUARD_RESTRICTED_QUIRKS "Blind" = TRUE, "Deaf" = TRUE, "Foreigner" = TRUE, "Pacifist" = TRUE, "Nerve Stapled" = TRUE +#define PRISONER_RESTRICTED_QUIRKS "Underworld Connections" = TRUE #define RESTRICTED_QUIRKS_EXCEPTIONS list("Mute" = "Signer") diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index a6a888e07b9..83eb942c2ad 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -378,10 +378,6 @@ DEFINE_BITFIELD(reaction_flags, list( DEFINE_BITFIELD(bodytype, list( "BODYTYPE_ORGANIC" = BODYTYPE_ORGANIC, "BODYTYPE_ROBOTIC" = BODYTYPE_ROBOTIC, - "BODYTYPE_HUMANOID" = BODYTYPE_HUMANOID, - "BODYTYPE_MONKEY" = BODYTYPE_MONKEY, - "BODYTYPE_DIGITIGRADE" = BODYTYPE_DIGITIGRADE, - "BODYTYPE_SNOUTED" = BODYTYPE_SNOUTED, "BODYTYPE_LARVA_PLACEHOLDER" = BODYTYPE_LARVA_PLACEHOLDER, "BODYTYPE_ALIEN" = BODYTYPE_ALIEN, "BODYTYPE_GOLEM" = BODYTYPE_GOLEM, @@ -390,18 +386,34 @@ DEFINE_BITFIELD(bodytype, list( DEFINE_BITFIELD(acceptable_bodytype, list( "BODYTYPE_ORGANIC" = BODYTYPE_ORGANIC, "BODYTYPE_ROBOTIC" = BODYTYPE_ROBOTIC, - "BODYTYPE_HUMANOID" = BODYTYPE_HUMANOID, - "BODYTYPE_MONKEY" = BODYTYPE_MONKEY, - "BODYTYPE_DIGITIGRADE" = BODYTYPE_DIGITIGRADE, - "BODYTYPE_SNOUTED" = BODYTYPE_SNOUTED, "BODYTYPE_LARVA_PLACEHOLDER" = BODYTYPE_LARVA_PLACEHOLDER, "BODYTYPE_ALIEN" = BODYTYPE_ALIEN, "BODYTYPE_GOLEM" = BODYTYPE_GOLEM, +)) + +DEFINE_BITFIELD(bodyshape, list( + "BODYSHAPE_HUMANOID" = BODYSHAPE_HUMANOID, + "BODYSHAPE_MONKEY" = BODYSHAPE_MONKEY, + "BODYSHAPE_DIGITIGRADE" = BODYSHAPE_DIGITIGRADE, + "BODYSHAPE_SNOUTED" = BODYSHAPE_SNOUTED, + // NOVA EDIT ADDITION - customization + "BODYSHAPE__CUSTOM" = BODYSHAPE_CUSTOM, + "BODYSHAPE__TAUR" = BODYSHAPE_TAUR, + "BODYSHAPE__HIDE_SHOES" = BODYSHAPE_HIDE_SHOES, + "BODYSHAPE__ALT_FACEWEAR_LAYER" = BODYSHAPE_ALT_FACEWEAR_LAYER, + // NOVA EDIT END +)) + +DEFINE_BITFIELD(acceptable_bodyshape, list( + "BODYSHAPE_HUMANOID" = BODYSHAPE_HUMANOID, + "BODYSHAPE_MONKEY" = BODYSHAPE_MONKEY, + "BODYSHAPE_DIGITIGRADE" = BODYSHAPE_DIGITIGRADE, + "BODYSHAPE_SNOUTED" = BODYSHAPE_SNOUTED, // NOVA EDIT ADDITION - customization - "BODYTYPE_CUSTOM" = BODYTYPE_CUSTOM, - "BODYTYPE_TAUR" = BODYTYPE_TAUR, - "BODYTYPE_HIDE_SHOES" = BODYTYPE_HIDE_SHOES, - "BODYTYPE_ALT_FACEWEAR_LAYER" = BODYTYPE_ALT_FACEWEAR_LAYER, + "BODYSHAPE__CUSTOM" = BODYSHAPE_CUSTOM, + "BODYSHAPE__TAUR" = BODYSHAPE_TAUR, + "BODYSHAPE__HIDE_SHOES" = BODYSHAPE_HIDE_SHOES, + "BODYSHAPE__ALT_FACEWEAR_LAYER" = BODYSHAPE_ALT_FACEWEAR_LAYER, // NOVA EDIT END )) diff --git a/code/controllers/subsystem/dynamic/dynamic_rulesets_midround.dm b/code/controllers/subsystem/dynamic/dynamic_rulesets_midround.dm index 036236b0a91..79e47cb3b3d 100644 --- a/code/controllers/subsystem/dynamic/dynamic_rulesets_midround.dm +++ b/code/controllers/subsystem/dynamic/dynamic_rulesets_midround.dm @@ -942,12 +942,16 @@ /datum/dynamic_ruleset/midround/from_ghosts/paradox_clone/proc/find_original() var/list/possible_targets = list() + var/opt_in_disabled = CONFIG_GET(flag/disable_antag_opt_in_preferences) // NOVA EDIT ADDITION - ANTAG OPT-IN for(var/mob/living/carbon/human/player in GLOB.player_list) if(!player.client || !player.mind || player.stat) continue if(!(player.mind.assigned_role.job_flags & JOB_CREW_MEMBER)) continue - possible_targets += player + // NOVA EDIT ADDITION START - Players in the interlink can't be obsession targets + Antag Optin + if (!opt_in_disabled && player.mind?.get_effective_opt_in_level() < OPT_IN_YES_ROUND_REMOVE) + continue + // NOVA EDIT ADDITION END if(possible_targets.len) return pick(possible_targets) diff --git a/code/controllers/subsystem/materials.dm b/code/controllers/subsystem/materials.dm index 4ae9272e970..25efd8695dc 100644 --- a/code/controllers/subsystem/materials.dm +++ b/code/controllers/subsystem/materials.dm @@ -33,6 +33,9 @@ SUBSYSTEM_DEF(materials) new /datum/stack_recipe("Carving block", /obj/structure/carving_block, 5, time = 3 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_STRUCTURE), ) + ///A list of dimensional themes used by the dimensional anomaly and other things, most of which require materials to function. + var/list/datum/dimension_theme/dimensional_themes + ///Ran on initialize, populated the materials and materials_by_category dictionaries with their appropiate vars (See these variables for more info) /datum/controller/subsystem/materials/proc/InitializeMaterials() materials = list() @@ -47,6 +50,8 @@ SUBSYSTEM_DEF(materials) continue // Do not initialize at mapload InitializeMaterial(list(mat_type)) + dimensional_themes = init_subtypes_w_path_keys(/datum/dimension_theme) + /** Creates and caches a material datum. * * Arugments: diff --git a/code/datums/brain_damage/creepy_trauma.dm b/code/datums/brain_damage/creepy_trauma.dm index b056ddfb8de..11283588543 100644 --- a/code/datums/brain_damage/creepy_trauma.dm +++ b/code/datums/brain_damage/creepy_trauma.dm @@ -131,15 +131,18 @@ var/list/special_pool = list() //The special list, for quirk-based var/chosen_victim //The obsession target + var/opt_in_disabled = CONFIG_GET(flag/disable_antag_opt_in_preferences) // NOVA EDIT ADDITION - ANTAG OPT-IN for(var/mob/player as anything in GLOB.player_list)//prevents crew members falling in love with nuke ops they never met, and other annoying hijinks if(!player.client || !player.mind || isnewplayer(player) || player.stat == DEAD || isbrain(player) || player == owner) continue if(!(player.mind.assigned_role.job_flags & JOB_CREW_MEMBER)) continue - // NOVA EDIT ADDITION START - Players in the interlink can't be obsession targets + // NOVA EDIT ADDITION START - Players in the interlink can't be obsession targets + Antag Optin if(SSticker.IsRoundInProgress() && istype(get_area(player), /area/centcom/interlink)) continue - // NOVA EDIT END + if (!opt_in_disabled && player.mind?.get_effective_opt_in_level() < OPT_IN_YES_KILL) + continue + // NOVA EDIT ADDITION END viable_minds += player.mind for(var/datum/mind/possible_target as anything in viable_minds) if(possible_target != owner && ishuman(possible_target.current)) diff --git a/code/datums/components/creamed.dm b/code/datums/components/creamed.dm index d1c76b4759d..be536bb792d 100644 --- a/code/datums/components/creamed.dm +++ b/code/datums/components/creamed.dm @@ -39,9 +39,9 @@ GLOBAL_LIST_INIT(creamable, typecacheof(list( qdel(src) return bodypart_overlay = new() - if(carbon_parent.bodytype & BODYTYPE_SNOUTED) //stupid, but external organ bodytypes are not stored on the limb + if(carbon_parent.bodyshape & BODYSHAPE_SNOUTED) //stupid, but external organ bodytypes are not stored on the limb bodypart_overlay.icon_state = "creampie_lizard" - else if(my_head.bodytype & BODYTYPE_MONKEY) + else if(my_head.bodyshape & BODYSHAPE_MONKEY) bodypart_overlay.icon_state = "creampie_monkey" else bodypart_overlay.icon_state = "creampie_human" diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index f8a2cbede01..7c7deb058f2 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -157,6 +157,7 @@ GLOBAL_LIST_EMPTY(objectives) //NOVA EDIT ADDITION var/datum/mind/O = I if(O.late_joiner) try_target_late_joiners = TRUE + var/opt_in_disabled = CONFIG_GET(flag/disable_antag_opt_in_preferences) // NOVA EDIT ADDITION - ANTAG OPT-IN for(var/datum/mind/possible_target in get_crewmember_minds()) if(possible_target in owners) continue @@ -166,6 +167,10 @@ GLOBAL_LIST_EMPTY(objectives) //NOVA EDIT ADDITION continue if(!is_valid_target(possible_target)) continue + // NOVA EDIT ADDITION START - Antag Opt In + if (!opt_in_disabled && !opt_in_valid(possible_target)) + continue + // NOVA EDIT ADDITION END possible_targets += possible_target if(try_target_late_joiners) var/list/all_possible_targets = possible_targets.Copy() @@ -871,7 +876,15 @@ GLOBAL_LIST_EMPTY(possible_items) /datum/objective/destroy/find_target(dupe_search_range, list/blacklist) var/list/possible_targets = active_ais(TRUE) possible_targets -= blacklist - var/mob/living/silicon/ai/target_ai = pick(possible_targets) + //var/mob/living/silicon/ai/target_ai = pick(possible_targets) // NOVA EDIT REMOVAL - Uses the below loop + // NOVA EDIT ADDITION BEGIN - ANTAG OPTIN + var/mob/living/silicon/ai/target_ai + var/opt_in_disabled = CONFIG_GET(flag/disable_antag_opt_in_preferences) // NOVA EDIT ADDITION - ANTAG OPT-IN + for (var/mob/living/silicon/ai/possible_target as anything in shuffle(possible_targets)) + if (!opt_in_disabled && !opt_in_valid(possible_target)) + continue + target_ai = possible_target + // NOVA EDIT ADDITION END target = target_ai.mind update_explanation_text() return target diff --git a/code/game/machinery/syndicatebomb.dm b/code/game/machinery/syndicatebomb.dm index 9f803020b55..ebe24b44974 100644 --- a/code/game/machinery/syndicatebomb.dm +++ b/code/game/machinery/syndicatebomb.dm @@ -584,8 +584,6 @@ qdel(src) -<<<<<<< HEAD -======= #define DIMENSION_CHOICE_RANDOM "None/Randomized" /obj/item/bombcore/dimensional @@ -650,7 +648,6 @@ #undef DIMENSION_CHOICE_RANDOM ->>>>>>> beb979d19ac ([MIRROR] [NO GBP] Fixing the multi-dimensional bomb payload (#1209)) ///Syndicate Detonator (aka the big red button)/// /obj/item/syndicatedetonator diff --git a/code/game/objects/effects/anomalies/anomalies_dimensional.dm b/code/game/objects/effects/anomalies/anomalies_dimensional.dm index 9aea9dfea6a..16dd5bafcfa 100644 --- a/code/game/objects/effects/anomalies/anomalies_dimensional.dm +++ b/code/game/objects/effects/anomalies/anomalies_dimensional.dm @@ -21,6 +21,11 @@ animate(src, transform = matrix()*0.85, time = 3, loop = -1) animate(transform = matrix(), time = 3, loop = -1) +/obj/effect/anomaly/dimensional/Destroy() + theme = null + target_turfs = null + return ..() + /obj/effect/anomaly/dimensional/anomalyEffect(seconds_per_tick) . = ..() transmute_area() @@ -36,8 +41,7 @@ return var/turf/affected_turf = target_turfs[1] - new /obj/effect/temp_visual/transmute_tile_flash(affected_turf) - theme.apply_theme(affected_turf) + theme.apply_theme(affected_turf, show_effect = TRUE) target_turfs -= affected_turf /** @@ -47,7 +51,7 @@ /obj/effect/anomaly/dimensional/proc/prepare_area(new_theme_path) if (!new_theme_path) new_theme_path = pick(subtypesof(/datum/dimension_theme)) - theme = new new_theme_path() + theme = SSmaterials.dimensional_themes[new_theme_path] apply_theme_icon() target_turfs = list() diff --git a/code/game/objects/effects/anomalies/anomalies_dimensional_themes.dm b/code/game/objects/effects/anomalies/anomalies_dimensional_themes.dm index 16408ea9ce6..c6190a0d84a 100644 --- a/code/game/objects/effects/anomalies/anomalies_dimensional_themes.dm +++ b/code/game/objects/effects/anomalies/anomalies_dimensional_themes.dm @@ -1,4 +1,3 @@ - /** * Datum which describes a theme and replaces turfs and objects in specified locations to match that theme */ @@ -44,12 +43,16 @@ * * Arguments * * affected_turf - Turf to transform. + * * skip_sound - If the sound shouldn't be played. + * * show_effect - if the temp visual effect should be shown. */ -/datum/dimension_theme/proc/apply_theme(turf/affected_turf, skip_sound = FALSE) +/datum/dimension_theme/proc/apply_theme(turf/affected_turf, skip_sound = FALSE, show_effect = FALSE) if (!replace_turf(affected_turf)) return if (!skip_sound) playsound(affected_turf, sound, 100, TRUE) + if(show_effect) + new /obj/effect/temp_visual/transmute_tile_flash(affected_turf) for (var/obj/object in affected_turf) replace_object(object) if (length(random_spawns) && prob(random_spawn_chance) && !affected_turf.is_blocked_turf(exclude_mobs = TRUE)) @@ -250,7 +253,7 @@ /datum/dimension_theme/radioactive name = "Radioactive" icon = 'icons/obj/ore.dmi' - icon_state = "Uranium ore" + icon_state = "uranium" material = /datum/material/uranium sound = 'sound/items/welder.ogg' @@ -353,7 +356,14 @@ name = "Fancy" icon = 'icons/obj/clothing/head/costume.dmi' icon_state = "fancycrown" + replace_floors = null replace_walls = /turf/closed/wall/mineral/wood/nonmetal + replace_objs = list( + /obj/structure/chair = list(/obj/structure/chair/comfy = 1), + /obj/machinery/door/airlock = list(/obj/machinery/door/airlock/wood = 1, /obj/machinery/door/airlock/wood/glass = 1), + ) + ///cooldown for changing carpets, It's kinda dull to always use the same one, but we also can't make it too random. + COOLDOWN_DECLARE(carpet_switch_cd) #define FANCY_CARPETS list(\ /turf/open/floor/eighties, \ @@ -369,14 +379,12 @@ /turf/open/floor/carpet/royalblack, \ /turf/open/floor/carpet/royalblue,) -/datum/dimension_theme/fancy/New() - . = ..() - replace_floors = list(pick(FANCY_CARPETS) = 1) - replace_objs = list( - /obj/structure/chair = list(/obj/structure/chair/comfy = 1), - /obj/machinery/door/airlock = list(/obj/machinery/door/airlock/wood = 1, /obj/machinery/door/airlock/wood/glass = 1), - /obj/structure/table/wood = list(pick(subtypesof(/obj/structure/table/wood/fancy)) = 1), - ) +/datum/dimension_theme/fancy/apply_theme(turf/affected_turf, skip_sound = FALSE, show_effect = FALSE) + if(COOLDOWN_FINISHED(src, carpet_switch_cd)) + replace_floors = list(pick(FANCY_CARPETS) = 1) + replace_objs[/obj/structure/table/wood] = list(pick(subtypesof(/obj/structure/table/wood/fancy)) = 1) + COOLDOWN_START(src, carpet_switch_cd, 90 SECONDS) + return ..() #undef FANCY_CARPETS diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm index 7ad2b14448c..1f3ac272d6f 100644 --- a/code/modules/antagonists/changeling/powers/mutations.dm +++ b/code/modules/antagonists/changeling/powers/mutations.dm @@ -90,8 +90,8 @@ chemical_cost = 1000 dna_cost = CHANGELING_POWER_UNOBTAINABLE - var/helmet_type = /obj/item - var/suit_type = /obj/item + var/helmet_type = null + var/suit_type = null var/suit_name_simple = " " var/helmet_name_simple = " " var/recharge_slowdown = 0 @@ -125,10 +125,14 @@ if(!ishuman(user) || !changeling) return 1 var/mob/living/carbon/human/H = user + if(istype(H.wear_suit, suit_type) || istype(H.head, helmet_type)) - H.visible_message(span_warning("[H] casts off [H.p_their()] [suit_name_simple]!"), span_warning("We cast off our [suit_name_simple]."), span_hear("You hear the organic matter ripping and tearing!")) - H.temporarilyRemoveItemFromInventory(H.head, TRUE) //The qdel on dropped() takes care of it - H.temporarilyRemoveItemFromInventory(H.wear_suit, TRUE) + var/name_to_use = (isnull(suit_type) ? helmet_name_simple : suit_name_simple) + H.visible_message(span_warning("[H] casts off [H.p_their()] [name_to_use]!"), span_warning("We cast off our [name_to_use]."), span_hear("You hear the organic matter ripping and tearing!")) + if(!isnull(helmet_type)) + H.temporarilyRemoveItemFromInventory(H.head, TRUE) //The qdel on dropped() takes care of it + if(!isnull(suit_type)) + H.temporarilyRemoveItemFromInventory(H.wear_suit, TRUE) H.update_worn_oversuit() H.update_worn_head() H.update_body_parts() @@ -141,18 +145,19 @@ return 1 /datum/action/changeling/suit/sting_action(mob/living/carbon/human/user) - if(!user.canUnEquip(user.wear_suit)) + if(!user.canUnEquip(user.wear_suit) && !isnull(suit_type)) user.balloon_alert(user, "body occupied!") return - if(!user.canUnEquip(user.head)) + if(!user.canUnEquip(user.head) && !isnull(helmet_type)) user.balloon_alert(user, "head occupied!") return ..() - user.dropItemToGround(user.head) - user.dropItemToGround(user.wear_suit) - - user.equip_to_slot_if_possible(new suit_type(user), ITEM_SLOT_OCLOTHING, 1, 1, 1) - user.equip_to_slot_if_possible(new helmet_type(user), ITEM_SLOT_HEAD, 1, 1, 1) + if(!isnull(suit_type)) + user.dropItemToGround(user.wear_suit) + user.equip_to_slot_if_possible(new suit_type(user), ITEM_SLOT_OCLOTHING, 1, 1, 1) + if(!isnull(helmet_type)) + user.dropItemToGround(user.head) + user.equip_to_slot_if_possible(new helmet_type(user), ITEM_SLOT_HEAD, 1, 1, 1) var/datum/antagonist/changeling/changeling = IS_CHANGELING(user) changeling.chem_recharge_slowdown += recharge_slowdown @@ -582,3 +587,130 @@ /obj/item/clothing/head/helmet/changeling/Initialize(mapload) . = ..() ADD_TRAIT(src, TRAIT_NODROP, CHANGELING_TRAIT) + +/datum/action/changeling/suit/hive_head + name = "Hive Head" + desc = "We coat our head in a waxy outing coating similar to a bee hive which can be used to manufacture bees to attack our enemies. Costs 15 chemicals." + helptext = "While the hive head does not provide much in the ways of armor, it does allow the user to send bees out to attack targets. Reagents can poured inside the hive to cause all bees released to inject said reagents." + button_icon_state = "hive_head" + chemical_cost = 15 + dna_cost = 2 + req_human = FALSE + blood_on_castoff = TRUE + + helmet_type = /obj/item/clothing/head/helmet/changeling_hivehead + helmet_name_simple = "hive head" + +/obj/item/clothing/head/helmet/changeling_hivehead + name = "hive head" + desc = "A strange, waxy outer coating covering your head. Gives you tinnitus." + icon_state = "hivehead" + inhand_icon_state = null + flash_protect = FLASH_PROTECTION_FLASH + item_flags = DROPDEL + armor_type = /datum/armor/changeling_hivehead + flags_inv = HIDEEARS|HIDEHAIR|HIDEEYES|HIDEFACIALHAIR|HIDEFACE|HIDESNOUT + actions_types = list(/datum/action/cooldown/hivehead_spawn_minions) + ///Does this hive head hold reagents? + var/holds_reagents = TRUE + +/obj/item/clothing/head/helmet/changeling_hivehead/Initialize(mapload) + . = ..() + if(holds_reagents) + create_reagents(50, REFILLABLE) + +/datum/armor/changeling_hivehead + melee = 10 + bullet = 10 + laser = 10 + energy = 10 + bio = 50 + +/obj/item/clothing/head/helmet/changeling_hivehead/Initialize(mapload) + . = ..() + ADD_TRAIT(src, TRAIT_NODROP, CHANGELING_TRAIT) + +/obj/item/clothing/head/helmet/changeling_hivehead/attackby(obj/item/attacking_item, mob/user, params) + . = ..() + if(!istype(attacking_item, /obj/item/organ/internal/monster_core/regenerative_core/legion) || !holds_reagents) + return + visible_message(span_boldwarning("As [user] shoves [attacking_item] into [src], [src] begins to mutate.")) + var/mob/living/carbon/wearer = loc + playsound(wearer, 'sound/effects/attackblob.ogg', 60, TRUE) + wearer.temporarilyRemoveItemFromInventory(wearer.head, TRUE) + wearer.equip_to_slot_if_possible(new /obj/item/clothing/head/helmet/changeling_hivehead/legion(wearer), ITEM_SLOT_HEAD, 1, 1, 1) + qdel(attacking_item) + + +/datum/action/cooldown/hivehead_spawn_minions + name = "Release Bees" + desc = "Release a group of bees to attack all other lifeforms." + background_icon_state = "bg_demon" + overlay_icon_state = "bg_demon_border" + button_icon = 'icons/mob/simple/bees.dmi' + button_icon_state = "queen_item" + cooldown_time = 30 SECONDS + ///The mob we're going to spawn + var/spawn_type = /mob/living/basic/bee + ///How many are we going to spawn + var/spawn_count = 6 + ///How long our summoned mobs last for + var/spawn_lifespan = 25 SECONDS + +/datum/action/cooldown/hivehead_spawn_minions/PreActivate(atom/target) + if(owner.movement_type & VENTCRAWLING) + owner.balloon_alert(owner, "unavailable here") + return + . = ..() + +/datum/action/cooldown/hivehead_spawn_minions/Activate(atom/target) + . = ..() + do_tell() + var/spawns = spawn_count + if(owner.stat >= HARD_CRIT) + spawns = 1 + for(var/i in 1 to spawns) + var/mob/living/basic/summoned_minion = new spawn_type(get_turf(owner)) + summoned_minion.faction = list("[REF(owner)]") + if(spawn_lifespan != 0 SECONDS) + QDEL_IN(summoned_minion, spawn_lifespan) + minion_additional_changes(summoned_minion) + +///Our tell that we're using this ability. Usually a sound and a visible message.area +/datum/action/cooldown/hivehead_spawn_minions/proc/do_tell() + owner.visible_message(span_warning("[owner]'s head begins to buzz as bees begin to pour out!"), span_warning("We release the bees."), span_hear("You hear a loud buzzing sound!")) + playsound(owner, 'sound/creatures/bee_swarm.ogg', 60, TRUE) + +///Stuff we want to do to our minions. This is in its own proc so subtypes can override this behaviour. +/datum/action/cooldown/hivehead_spawn_minions/proc/minion_additional_changes(mob/living/basic/minion) + var/mob/living/basic/bee/summoned_bee = minion + var/mob/living/carbon/wearer = owner + if(istype(summoned_bee) && length(wearer.head.reagents.reagent_list)) + summoned_bee.assign_reagent(pick(wearer.head.reagents.reagent_list)) + +/obj/item/clothing/head/helmet/changeling_hivehead/legion + name = "legion hive head" + desc = "A strange, boney coating covering your head with a fleshy inside. Surprisingly comfortable." + icon_state = "hivehead_legion" + actions_types = list(/datum/action/cooldown/hivehead_spawn_minions/legion) + holds_reagents = FALSE + +/datum/action/cooldown/hivehead_spawn_minions/legion + name = "Release Legion" + desc = "Release a group of legion to attack all other lifeforms." + button_icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi' + button_icon_state = "legion_head" + cooldown_time = 15 SECONDS + spawn_type = /mob/living/basic/legion_brood + spawn_count = 4 + //Legion heads go away by themselves, we don't have to handle that + spawn_lifespan = 0 SECONDS + +/datum/action/cooldown/hivehead_spawn_minions/legion/do_tell() + owner.visible_message(span_warning("[owner]'s head begins to shake as legion begin to pour out!"), span_warning("We release the legion."), span_hear("You hear a loud squishing sound!")) + playsound(owner, 'sound/effects/attackblob.ogg', 60, TRUE) + +/datum/action/cooldown/hivehead_spawn_minions/legion/minion_additional_changes(mob/living/basic/minion) + var/mob/living/basic/legion_brood/brood = minion + if (istype(brood)) + brood.assign_creator(owner, FALSE) diff --git a/code/modules/antagonists/cult/cult_objectives.dm b/code/modules/antagonists/cult/cult_objectives.dm index 7da5d095661..42312eea2dd 100644 --- a/code/modules/antagonists/cult/cult_objectives.dm +++ b/code/modules/antagonists/cult/cult_objectives.dm @@ -19,19 +19,24 @@ return var/datum/team/cult/cult = team var/list/target_candidates = list() + var/opt_in_disabled = CONFIG_GET(flag/disable_antag_opt_in_preferences) // NOVA EDIT ADDITION - ANTAG OPT-IN for(var/mob/living/carbon/human/player in GLOB.player_list) - // NOVA EDIT ADDITION START - Players in the interlink can't be obsession targets + // NOVA EDIT ADDITION START - Players in the interlink can't be obsession targets + Antag Optin if(SSticker.IsRoundInProgress() && istype(get_area(player), /area/centcom/interlink)) continue + if (!opt_in_disabled && !opt_in_valid(player)) + continue // NOVA EDIT END if(player.mind && !player.mind.has_antag_datum(/datum/antagonist/cult) && !is_convertable_to_cult(player) && player.stat != DEAD) target_candidates += player.mind if(target_candidates.len == 0) message_admins("Cult Sacrifice: Could not find unconvertible target, checking for convertible target.") for(var/mob/living/carbon/human/player in GLOB.player_list) - // NOVA EDIT ADDITION START - Players in the interlink can't be obsession targets + // NOVA EDIT ADDITION START - Players in the interlink can't be obsession targets + Antag Optin if(SSticker.IsRoundInProgress() && istype(get_area(player), /area/centcom/interlink)) continue + if (!opt_in_disabled && !opt_in_valid(player)) + continue // NOVA EDIT END if(player.mind && !player.mind.has_antag_datum(/datum/antagonist/cult) && player.stat != DEAD) target_candidates += player.mind diff --git a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm index 797d754ea0b..f515b3e25bd 100644 --- a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm +++ b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm @@ -113,6 +113,10 @@ continue if(possible_target.current.stat == DEAD) continue + // NOVA EDIT ADDITION BEGIN - Antag opt-in (Only security and command can be targetted) + if (!possible_target.assigned_role?.heretic_sac_target) + continue + // NOVA EDIT ADDITION END valid_targets += possible_target @@ -142,12 +146,14 @@ valid_targets -= sec_mind break + /* NOVA EDIT REMOVAL -- Antag Opt In (Only sec and command may be targetted) // Third target, someone in their department. for(var/datum/mind/department_mind as anything in shuffle(valid_targets)) if(department_mind.assigned_role?.departments_bitflags & user.mind.assigned_role?.departments_bitflags) final_targets += department_mind valid_targets -= department_mind break + */ // NOVA EDIT REMOVAL END // Now grab completely random targets until we'll full var/target_sanity = 0 diff --git a/code/modules/cargo/markets/market_items/weapons.dm b/code/modules/cargo/markets/market_items/weapons.dm index ee16daae7d5..052074a30b3 100644 --- a/code/modules/cargo/markets/market_items/weapons.dm +++ b/code/modules/cargo/markets/market_items/weapons.dm @@ -73,3 +73,12 @@ price_max = CARGO_CRATE_VALUE * 4 stock_max = 1 availability_prob = 75 + +/datum/market_item/weapon/dimensional_bomb + name = "Multi-Dimensional Bomb Core" + desc = "A special bomb core, one of a kind, for all your 'terraforming gone wrong' purposes." + item = /obj/item/bombcore/dimensional + price_min = CARGO_CRATE_VALUE * 40 + price_max = CARGO_CRATE_VALUE * 50 + stock_max = 1 + availability_prob = 15 diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm index 008c99e9e5f..8d4c948d99a 100644 --- a/code/modules/clothing/under/_under.dm +++ b/code/modules/clothing/under/_under.dm @@ -152,7 +152,7 @@ /* NOVA EDIT REMOVAL - This breaks jumpsuit adjustment. Plus, we don't support it. if((supports_variations_flags & CLOTHING_DIGITIGRADE_VARIATION) && ishuman(user)) var/mob/living/carbon/human/wearer = user - if(wearer.bodytype & BODYTYPE_DIGITIGRADE) + if(wearer.bodyshape & BODYSHAPE_DIGITIGRADE) adjusted = DIGITIGRADE_STYLE update_appearance() */ // NOVA EDIT END diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm index c0a56dc7a67..70bc9113150 100644 --- a/code/modules/jobs/job_types/_job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -312,6 +312,15 @@ info += span_boldnotice("As this station was initially staffed with a \ [CONFIG_GET(flag/jobs_have_minimal_access) ? "full crew, only your job's necessities" : "skeleton crew, additional access may"] \ have been added to your ID card.") + //NOVA EDIT ADDITION BEGIN - ANTAG OPT IN + if (!CONFIG_GET(flag/disable_antag_opt_in_preferences)) + if (isnum(minimum_opt_in_level) && minimum_opt_in_level > OPT_IN_NOT_TARGET) + info += span_bolddanger("This job forces a minimum opt-in setting of [GLOB.antag_opt_in_strings["[minimum_opt_in_level]"]].") + if (heretic_sac_target) + info += span_bolddanger("This job can be sacrificed by heretics.") + if (contractable) + info += span_bolddanger("This job can be targeted by contractors.") + //NOVA EDIT ADDITION END //NOVA EDIT ADDITION START - ALTERNATIVE_JOB_TITLES if(alt_title != title) info += span_warning("Remember that alternate titles are purely for flavor and roleplay.") diff --git a/code/modules/mob/living/basic/farm_animals/bee/_bee.dm b/code/modules/mob/living/basic/farm_animals/bee/_bee.dm index 66c0d129962..5510b81679e 100644 --- a/code/modules/mob/living/basic/farm_animals/bee/_bee.dm +++ b/code/modules/mob/living/basic/farm_animals/bee/_bee.dm @@ -25,10 +25,6 @@ response_harm_continuous = "squashes" response_harm_simple = "squash" - mob_size = MOB_SIZE_LARGE - pixel_x = -16 - base_pixel_x = -16 - speed = 1 maxHealth = 10 health = 10 diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 147419272a5..5fcfeec8d72 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -1045,6 +1045,7 @@ set_usable_hands(usable_hands + 1) synchronize_bodytypes() + synchronize_bodyshapes() ///Proc to hook behavior on bodypart removals. Do not directly call. You're looking for [/obj/item/bodypart/proc/drop_limb()]. /mob/living/carbon/proc/remove_bodypart(obj/item/bodypart/old_bodypart, special) @@ -1071,6 +1072,7 @@ set_usable_hands(usable_hands - 1) synchronize_bodytypes() + synchronize_bodyshapes() ///Updates the bodypart speed modifier based on our bodyparts. /mob/living/carbon/proc/update_bodypart_speed_modifier() diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm index 38571bccdb1..2e2168eca9d 100644 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -118,7 +118,10 @@ var/last_top_offset /// A bitfield of "bodytypes", updated by /obj/item/bodypart/proc/synchronize_bodytypes() - var/bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC + var/bodytype = BODYTYPE_ORGANIC + + /// A bitfield of "bodyshapes", updated by /obj/item/bodypart/proc/synchronize_bodyshapes() + var/bodyshape = BODYSHAPE_HUMANOID COOLDOWN_DECLARE(bleeding_message_cd) diff --git a/code/modules/mob/living/carbon/death.dm b/code/modules/mob/living/carbon/death.dm index 85a6b06a2d3..13d7b37e6b8 100644 --- a/code/modules/mob/living/carbon/death.dm +++ b/code/modules/mob/living/carbon/death.dm @@ -42,7 +42,7 @@ for(var/obj/item/organ/organ as anything in organs) if((drop_bitflags & DROP_BRAIN) && istype(organ, /obj/item/organ/internal/brain)) - if(drop_bitflags & DROP_BODYPARTS) + if(drop_bitflags & DROP_BODYPARTS && (check_zone(organ.zone) != BODY_ZONE_CHEST)) // NOVA EDIT CHANGE - sYNTH BRAINS - ORIGINAL: if(drop_bitflags & DROP_BODYPARTS) continue // the head will drop, so the brain should stay inside organ.Remove(src) diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index 504ceabe915..82ec5a6f311 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -693,7 +693,7 @@ GLOBAL_LIST_EMPTY(features_by_species) working_shirt.pixel_y += height_offset standing += working_shirt - if(species_human.socks && species_human.num_legs >= 2 && !(species_human.bodytype & BODYTYPE_DIGITIGRADE)) + if(species_human.socks && species_human.num_legs >= 2 && !(species_human.bodyshape & BODYSHAPE_DIGITIGRADE)) var/datum/sprite_accessory/socks/socks = GLOB.socks_list[species_human.socks] if(socks) standing += mutable_appearance(socks.icon, socks.icon_state, -BODY_LAYER) @@ -936,7 +936,7 @@ GLOBAL_LIST_EMPTY(features_by_species) if(H.num_legs < 2) return FALSE /* NOVA EDIT REMOVAL - if((H.bodytype & BODYTYPE_DIGITIGRADE) && !(I.item_flags & IGNORE_DIGITIGRADE)) + if((H.bodyshape & BODYSHAPE_DIGITIGRADE) && !(I.item_flags & IGNORE_DIGITIGRADE)) if(!(I.supports_variations_flags & (CLOTHING_DIGITIGRADE_VARIATION|CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON))) if(!disable_warning) to_chat(H, span_warning("The footwear around here isn't compatible with your feet!")) @@ -968,7 +968,7 @@ GLOBAL_LIST_EMPTY(features_by_species) return equip_delay_self_check(I, H, bypass_equip_delay_self) if(ITEM_SLOT_ICLOTHING) var/obj/item/bodypart/chest = H.get_bodypart(BODY_ZONE_CHEST) - if(chest && (chest.bodytype & BODYTYPE_MONKEY)) + if(chest && (chest.bodyshape & BODYSHAPE_MONKEY)) if(!(I.supports_variations_flags & CLOTHING_MONKEY_VARIATION)) if(!disable_warning) to_chat(H, span_warning("[I] doesn't fit your [chest.name]!")) diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 735d6f83cc1..c628b9ddcb8 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -505,6 +505,12 @@ if(erp_status_pref && !CONFIG_GET(flag/disable_erp_preferences)) . += span_notice("ERP STATUS: [erp_status_pref]") + if (!CONFIG_GET(flag/disable_antag_opt_in_preferences)) + var/opt_in_status = mind?.get_effective_opt_in_level() + if (!isnull(opt_in_status)) + var/stringified_optin = GLOB.antag_opt_in_strings["[opt_in_status]"] + . += span_notice("Antag Opt-in Status: [stringified_optin]") + //Temporary flavor text addition: if(temporary_flavor_text) if(length_char(temporary_flavor_text) < TEMPORARY_FLAVOR_PREVIEW_LIMIT) diff --git a/code/modules/mob/living/carbon/human/human_update_icons.dm b/code/modules/mob/living/carbon/human/human_update_icons.dm index 3ea41f2302b..802146d8435 100644 --- a/code/modules/mob/living/carbon/human/human_update_icons.dm +++ b/code/modules/mob/living/carbon/human/human_update_icons.dm @@ -93,29 +93,29 @@ There are several things that need to be remembered: var/mutable_appearance/uniform_overlay //This is how non-humanoid clothing works. You check if the mob has the right bodyflag, and the clothing has the corresponding clothing flag. - //handled_by_bodytype is used to track whether or not we successfully used an alternate sprite. It's set to TRUE to ease up on copy-paste. + //handled_by_bodyshape is used to track whether or not we successfully used an alternate sprite. It's set to TRUE to ease up on copy-paste. //icon_file MUST be set to null by default, or it causes issues. - //handled_by_bodytype MUST be set to FALSE under the if(!icon_exists()) statement, or everything breaks. - //"override_file = handled_by_bodytype ? icon_file : null" MUST be added to the arguments of build_worn_icon() + //handled_by_bodyshape MUST be set to FALSE under the if(!icon_exists()) statement, or everything breaks. + //"override_file = handled_by_bodyshape ? icon_file : null" MUST be added to the arguments of build_worn_icon() //Friendly reminder that icon_exists(file, state, scream = TRUE) is your friend when debugging this code. - var/handled_by_bodytype = TRUE + var/handled_by_bodyshape = TRUE var/icon_file var/woman var/digi // NOVA EDIT ADDITION - Digi female gender shaping var/female_sprite_flags = uniform.female_sprite_flags // NOVA EDIT ADDITION - Digi female gender shaping var/mutant_styles = NONE // NOVA EDIT ADDITON - mutant styles to pass down to build_worn_icon. //BEGIN SPECIES HANDLING - if((bodytype & BODYTYPE_MONKEY) && (uniform.supports_variations_flags & CLOTHING_MONKEY_VARIATION)) + if((bodyshape & BODYSHAPE_MONKEY) && (uniform.supports_variations_flags & CLOTHING_MONKEY_VARIATION)) icon_file = dna.species.generate_custom_worn_icon(LOADOUT_ITEM_UNIFORM, w_uniform, src) // NOVA EDIT CHANGE - ORIGINAL: icon_file = MONKEY_UNIFORM_FILE - else if((bodytype & BODYTYPE_DIGITIGRADE) && (uniform.supports_variations_flags & CLOTHING_DIGITIGRADE_VARIATION)) + else if((bodyshape & BODYSHAPE_DIGITIGRADE) && (uniform.supports_variations_flags & CLOTHING_DIGITIGRADE_VARIATION)) icon_file = uniform.worn_icon_digi || DIGITIGRADE_UNIFORM_FILE // NOVA EDIT CHANGE - ORIGINAL: icon_file = DIGITIGRADE_UNIFORM_FILE digi = TRUE // NOVA EDIT ADDITION - Digi female gender shaping // NOVA EDIT ADDITION - birbs - else if(bodytype & BODYTYPE_CUSTOM) + else if(bodyshape & BODYSHAPE_CUSTOM) icon_file = dna.species.generate_custom_worn_icon(LOADOUT_ITEM_UNIFORM, w_uniform, src) // Might have to refactor how this works eventually, maybe. // NOVA EDIT END //Female sprites have lower priority than digitigrade sprites - if(dna.species.sexes && (bodytype & BODYTYPE_HUMANOID) && physique == FEMALE && !(female_sprite_flags & NO_FEMALE_UNIFORM)) //Agggggggghhhhh // NOVA EDIT CHANGE - ORIGINAL: else if(dna.species.sexes && (bodytype & BODYTYPE_HUMANOID) && physique == FEMALE && !(uniform.female_sprite_flags & NO_FEMALE_UNIFORM)) + if(dna.species.sexes && (bodyshape & BODYSHAPE_HUMANOID) && physique == FEMALE && !(female_sprite_flags & NO_FEMALE_UNIFORM)) // NOVA EDIT CHANGE - ORIGINAL: else if(dna.species.sexes && (bodyshape & BODYSHAPE_HUMANOID) && physique == FEMALE && !(uniform.female_sprite_flags & NO_FEMALE_UNIFORM)) //Agggggggghhhhh woman = TRUE // NOVA EDIT ADDITION START - Digi female gender shaping if(digi) @@ -127,10 +127,10 @@ There are several things that need to be remembered: if(!icon_exists(icon_file, RESOLVE_ICON_STATE(uniform))) icon_file = DEFAULT_UNIFORM_FILE - handled_by_bodytype = FALSE + handled_by_bodyshape = FALSE // NOVA EDIT ADDITION START - Taur-friendly suits! - if(bodytype & BODYTYPE_TAUR) + if(bodyshape & BODYSHAPE_TAUR) if(istype(uniform) && uniform.gets_cropped_on_taurs) mutant_styles |= get_taur_mode() // NOVA EDIT END @@ -142,7 +142,7 @@ There are several things that need to be remembered: isinhands = FALSE, female_uniform = woman ? female_sprite_flags : null, // NOVA EDIT CHANGE - Digi female gender shaping - ORIGINAL: female_uniform = woman ? uniform.female_sprite_flags : null, override_state = target_overlay, - override_file = handled_by_bodytype ? icon_file : null, + override_file = handled_by_bodyshape ? icon_file : null, mutant_styles = mutant_styles, // NOVA EDIT ADDITION - Taur-friendly uniforms! ) @@ -209,7 +209,7 @@ There are several things that need to be remembered: // NOVA EDIT ADDITION var/mutant_override = FALSE - if(bodytype & BODYTYPE_CUSTOM) + if(bodyshape & BODYSHAPE_CUSTOM) var/species_icon_file = dna.species.generate_custom_worn_icon(LOADOUT_ITEM_GLOVES, gloves, src) if(species_icon_file) icon_file = species_icon_file @@ -252,7 +252,7 @@ There are several things that need to be remembered: // NOVA EDIT ADDITION var/mutant_override = FALSE - if(bodytype & BODYTYPE_CUSTOM) + if(bodyshape & BODYSHAPE_CUSTOM) var/species_icon_file = dna.species.generate_custom_worn_icon(LOADOUT_ITEM_GLASSES, glasses, src) if(species_icon_file) icon_file = species_icon_file @@ -291,7 +291,7 @@ There are several things that need to be remembered: // NOVA EDIT ADDITION var/mutant_override = FALSE - if(bodytype & BODYTYPE_CUSTOM) + if(bodyshape & BODYSHAPE_CUSTOM) var/species_icon_file = dna.species.generate_custom_worn_icon(LOADOUT_ITEM_EARS, ears, src) if(species_icon_file) icon_file = species_icon_file @@ -325,13 +325,13 @@ There are several things that need to be remembered: // NOVA EDIT ADDITION var/mutant_override = FALSE - if(bodytype & BODYTYPE_CUSTOM) + if(bodyshape & BODYSHAPE_CUSTOM) var/species_icon_file = dna.species.generate_custom_worn_icon(LOADOUT_ITEM_NECK, wear_neck, src) if(species_icon_file) icon_file = species_icon_file mutant_override = TRUE //On the off-chance we have a neck item that has to move around or cover the muzzle, it ALSO gets worn_icon_muzzled compatiability - if((bodytype & BODYTYPE_SNOUTED) && (worn_item.supports_variations_flags & CLOTHING_SNOUTED_VARIATION) && worn_item.worn_icon_muzzled) + if((bodyshape & BODYSHAPE_SNOUTED) && (worn_item.supports_variations_flags & CLOTHING_SNOUTED_VARIATION) && worn_item.worn_icon_muzzled) var/snout_icon_file = worn_item.worn_icon_muzzled if(snout_icon_file && icon_exists(snout_icon_file, RESOLVE_ICON_STATE(worn_item))) icon_file = snout_icon_file @@ -371,17 +371,17 @@ There are several things that need to be remembered: // NOVA EDIT ADDITION START var/mutant_override = FALSE - if((bodytype & BODYTYPE_DIGITIGRADE) && (worn_item.supports_variations_flags & CLOTHING_DIGITIGRADE_VARIATION)) + if((bodyshape & BODYSHAPE_DIGITIGRADE) && (worn_item.supports_variations_flags & CLOTHING_DIGITIGRADE_VARIATION)) var/obj/item/bodypart/leg = src.get_bodypart(BODY_ZONE_L_LEG) - if(leg.limb_id == "digitigrade" || leg.bodytype & BODYTYPE_DIGITIGRADE)//Snowflakey and bad. But it makes it look consistent. + if(leg.limb_id == "digitigrade" || leg.bodyshape & BODYSHAPE_DIGITIGRADE)//Snowflakey and bad. But it makes it look consistent. icon_file = worn_item.worn_icon_digi || DIGITIGRADE_SHOES_FILE // NOVA EDIT CHANGE mutant_override = TRUE // NOVA EDIT ADDITION - if(!mutant_override && bodytype & BODYTYPE_CUSTOM) + if(!mutant_override && bodyshape & BODYSHAPE_CUSTOM) var/species_icon_file = dna.species.generate_custom_worn_icon(LOADOUT_ITEM_SHOES, shoes, src) if(species_icon_file) icon_file = species_icon_file mutant_override = TRUE - if(bodytype & BODYTYPE_HIDE_SHOES) + if(bodyshape & BODYSHAPE_HIDE_SHOES) return // We just don't want shoes that float if we're not displaying legs (useful for taurs, for now) // NOVA EDIT END @@ -444,12 +444,12 @@ There are several things that need to be remembered: // NOVA EDIT ADDITION - This needs to be refactored. var/mutant_override = FALSE - if(bodytype & BODYTYPE_CUSTOM) + if(bodyshape & BODYSHAPE_CUSTOM) var/species_icon_file = dna.species.generate_custom_worn_icon(LOADOUT_ITEM_HEAD, head, src) if(species_icon_file) icon_file = species_icon_file mutant_override = TRUE - if((icon_file == 'icons/mob/clothing/head/default.dmi') && (bodytype & BODYTYPE_SNOUTED) && (worn_item.supports_variations_flags & CLOTHING_SNOUTED_VARIATION)) + if((icon_file == 'icons/mob/clothing/head/default.dmi') && (bodyshape & BODYSHAPE_SNOUTED) && (worn_item.supports_variations_flags & CLOTHING_SNOUTED_VARIATION)) var/snout_icon_file = worn_item.worn_icon_muzzled || SNOUTED_HEAD_FILE if(snout_icon_file && icon_exists(snout_icon_file, RESOLVE_ICON_STATE(worn_item))) icon_file = snout_icon_file @@ -486,7 +486,7 @@ There are several things that need to be remembered: // NOVA EDIT ADDITION var/mutant_override = FALSE - if(bodytype & BODYTYPE_CUSTOM) + if(bodyshape & BODYSHAPE_CUSTOM) var/species_icon_file = dna.species.generate_custom_worn_icon(LOADOUT_ITEM_BELT, belt, src) if(species_icon_file) icon_file = species_icon_file @@ -521,18 +521,18 @@ There are several things that need to be remembered: var/mutant_styles = NONE //More currently unused digitigrade handling - if(bodytype & BODYTYPE_DIGITIGRADE) + if(bodyshape & BODYSHAPE_DIGITIGRADE) if(worn_item.supports_variations_flags & CLOTHING_DIGITIGRADE_VARIATION) icon_file = worn_item.worn_icon_digi || DIGITIGRADE_SUIT_FILE // NOVA EDIT CHANGE mutant_override = TRUE - if(!mutant_override && bodytype & BODYTYPE_CUSTOM) + if(!mutant_override && bodyshape & BODYSHAPE_CUSTOM) var/species_icon_file = dna.species.generate_custom_worn_icon(LOADOUT_ITEM_SUIT, wear_suit, src) if(species_icon_file) icon_file = species_icon_file mutant_override = TRUE - if(bodytype & BODYTYPE_TAUR) + if(bodyshape & BODYSHAPE_TAUR) var/obj/item/clothing/suit/worn_suit = wear_suit if(istype(worn_suit) && worn_suit.gets_cropped_on_taurs) mutant_styles |= get_taur_mode() @@ -595,12 +595,12 @@ There are several things that need to be remembered: // NOVA EDIT ADDITION var/mutant_override = FALSE - if(bodytype & BODYTYPE_CUSTOM) + if(bodyshape & BODYSHAPE_CUSTOM) var/species_icon_file = dna.species.generate_custom_worn_icon(LOADOUT_ITEM_MASK, wear_mask, src) if(species_icon_file) icon_file = species_icon_file mutant_override = TRUE - if((icon_file == 'icons/mob/clothing/mask.dmi') && (bodytype & BODYTYPE_SNOUTED) && (worn_item.supports_variations_flags & CLOTHING_SNOUTED_VARIATION)) + if((icon_file == 'icons/mob/clothing/mask.dmi') && (bodyshape & BODYSHAPE_SNOUTED) && (worn_item.supports_variations_flags & CLOTHING_SNOUTED_VARIATION)) var/snout_icon_file = worn_item.worn_icon_muzzled || SNOUTED_MASK_FILE if(snout_icon_file && icon_exists(snout_icon_file, RESOLVE_ICON_STATE(worn_item))) icon_file = snout_icon_file @@ -633,7 +633,7 @@ There are several things that need to be remembered: // NOVA EDIT ADDITION var/mutant_override = FALSE - if(bodytype & BODYTYPE_CUSTOM) + if(bodyshape & BODYSHAPE_CUSTOM) var/species_icon_file = dna.species.generate_custom_worn_icon(LOADOUT_ITEM_MISC, back, src) if(species_icon_file) icon_file = species_icon_file diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm index ee0450f4075..92abcffd186 100644 --- a/code/modules/mob/living/death.dm +++ b/code/modules/mob/living/death.dm @@ -19,7 +19,7 @@ death(TRUE) ghostize() - spill_organs(drop_bitflags) + spill_organs(issynthetic(src) ? drop_bitflags|DROP_BRAIN : drop_bitflags) // NOVA EDIT CHANGE - Synths always drop brains - ORIGINAL: spill_organs(drop_bitflags) if(drop_bitflags & DROP_BODYPARTS) spread_bodyparts(drop_bitflags) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm index 9253448563b..ac9031f59c3 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -356,8 +356,7 @@ /obj/machinery/anomalous_crystal/theme_warp/Initialize(mapload) . = ..() - var/terrain_type = pick(subtypesof(/datum/dimension_theme)) - terrain_theme = new terrain_type() + terrain_theme = SSmaterials.dimensional_themes[pick(subtypesof(/datum/dimension_theme))] observer_desc = "This crystal changes the area around it to match the theme of \"[terrain_theme.name]\"." /obj/machinery/anomalous_crystal/theme_warp/ActivationReaction(mob/user, method) @@ -372,7 +371,7 @@ return TRUE /obj/machinery/anomalous_crystal/theme_warp/Destroy() - QDEL_NULL(terrain_theme) + terrain_theme = null converted_areas.Cut() return ..() diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 83d4200bb65..5b66789ad21 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -34,8 +34,10 @@ * Set to BIO_STANDARD_UNJOINTED because most species have both flesh bone and blood in their limbs. */ var/biological_state = BIO_STANDARD_UNJOINTED - ///A bitfield of bodytypes for clothing, surgery, and misc information - var/bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC + ///A bitfield of bodytypes for surgery, and misc information + var/bodytype = BODYTYPE_ORGANIC + ///A bitfield of bodyshapes for clothing and other sprite information + var/bodyshape = BODYSHAPE_HUMANOID ///Defines when a bodypart should not be changed. Example: BP_BLOCK_CHANGE_SPECIES prevents the limb from being overwritten on species gain var/change_exempt_flags = NONE ///Random flags that describe this bodypart diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm index dc107e973da..4b9bac87d16 100644 --- a/code/modules/surgery/bodyparts/dismemberment.dm +++ b/code/modules/surgery/bodyparts/dismemberment.dm @@ -274,7 +274,7 @@ return FALSE var/obj/item/bodypart/chest/mob_chest = new_limb_owner.get_bodypart(BODY_ZONE_CHEST) - if(mob_chest && !(mob_chest.acceptable_bodytype & bodytype) && !special) + if(mob_chest && !(mob_chest.acceptable_bodytype & bodytype) && !(mob_chest.acceptable_bodyshape & bodyshape) && !(mob_chest.acceptable_bodyshape & bodyshape) && !special) return FALSE return TRUE diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm index eb9a9f56df5..1defeecafe6 100644 --- a/code/modules/surgery/bodyparts/head.dm +++ b/code/modules/surgery/bodyparts/head.dm @@ -234,7 +234,7 @@ husk_type = "monkey" icon_state = "default_monkey_head" limb_id = SPECIES_MONKEY - bodytype = BODYTYPE_MONKEY | BODYTYPE_ORGANIC + bodyshape = BODYSHAPE_MONKEY should_draw_greyscale = FALSE dmg_overlay_type = SPECIES_MONKEY is_dimorphic = FALSE @@ -251,7 +251,8 @@ px_y = 0 bodypart_flags = BODYPART_UNREMOVABLE max_damage = LIMB_MAX_HP_ALIEN_CORE - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ALIEN | BODYTYPE_ORGANIC + bodytype = BODYTYPE_ALIEN | BODYTYPE_ORGANIC + bodyshape = BODYSHAPE_HUMANOID /obj/item/bodypart/head/larva icon = 'icons/mob/human/species/alien/bodyparts.dmi' diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm index 52671b5fbc1..126bd3db33a 100644 --- a/code/modules/surgery/bodyparts/helpers.dm +++ b/code/modules/surgery/bodyparts/helpers.dm @@ -179,6 +179,16 @@ bodytype = all_limb_flags +/// Makes sure that the owner's bodyshape flags match the flags of all of it's parts and organs +/mob/living/carbon/proc/synchronize_bodyshapes() + var/all_limb_flags = NONE + for(var/obj/item/bodypart/limb as anything in bodyparts) + for(var/obj/item/organ/external/ext_organ in limb) + all_limb_flags |= ext_organ.external_bodyshapes + all_limb_flags |= limb.bodyshape + + bodyshape = all_limb_flags + /proc/skintone2hex(skin_tone) . = 0 switch(skin_tone) diff --git a/code/modules/surgery/bodyparts/parts.dm b/code/modules/surgery/bodyparts/parts.dm index e13fef576ec..ead03aa0f70 100644 --- a/code/modules/surgery/bodyparts/parts.dm +++ b/code/modules/surgery/bodyparts/parts.dm @@ -13,8 +13,10 @@ grind_results = null wound_resistance = 10 bodypart_trait_source = CHEST_TRAIT + ///The bodyshape(s) allowed to attach to this chest. + var/acceptable_bodyshape = BODYSHAPE_HUMANOID ///The bodytype(s) allowed to attach to this chest. - var/acceptable_bodytype = BODYTYPE_HUMANOID + var/acceptable_bodytype = ALL var/obj/item/cavity_item @@ -78,8 +80,8 @@ should_draw_greyscale = FALSE is_dimorphic = FALSE wound_resistance = -10 - bodytype = BODYTYPE_MONKEY | BODYTYPE_ORGANIC - acceptable_bodytype = BODYTYPE_MONKEY + bodyshape = BODYSHAPE_MONKEY + acceptable_bodyshape = BODYSHAPE_MONKEY dmg_overlay_type = SPECIES_MONKEY /obj/item/bodypart/chest/alien @@ -87,12 +89,13 @@ icon_static = 'icons/mob/human/species/alien/bodyparts.dmi' icon_state = "alien_chest" limb_id = BODYPART_ID_ALIEN - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ALIEN | BODYTYPE_ORGANIC + bodytype = BODYTYPE_ALIEN | BODYTYPE_ORGANIC + bodyshape = BODYSHAPE_HUMANOID is_dimorphic = FALSE should_draw_greyscale = FALSE bodypart_flags = BODYPART_UNREMOVABLE max_damage = LIMB_MAX_HP_ALIEN_CORE - acceptable_bodytype = BODYTYPE_HUMANOID + acceptable_bodyshape = BODYSHAPE_HUMANOID wing_types = NONE /obj/item/bodypart/chest/larva @@ -245,7 +248,7 @@ icon_state = "default_monkey_l_arm" limb_id = SPECIES_MONKEY should_draw_greyscale = FALSE - bodytype = BODYTYPE_MONKEY | BODYTYPE_ORGANIC + bodyshape = BODYSHAPE_MONKEY wound_resistance = -10 px_x = -5 px_y = -3 @@ -260,7 +263,8 @@ icon_static = 'icons/mob/human/species/alien/bodyparts.dmi' icon_state = "alien_l_arm" limb_id = BODYPART_ID_ALIEN - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ALIEN | BODYTYPE_ORGANIC + bodytype = BODYTYPE_ALIEN | BODYTYPE_ORGANIC + bodyshape = BODYSHAPE_HUMANOID px_x = 0 px_y = 0 bodypart_flags = BODYPART_UNREMOVABLE @@ -341,7 +345,7 @@ husk_type = "monkey" icon_state = "default_monkey_r_arm" limb_id = SPECIES_MONKEY - bodytype = BODYTYPE_MONKEY | BODYTYPE_ORGANIC + bodyshape = BODYSHAPE_MONKEY should_draw_greyscale = FALSE wound_resistance = -10 px_x = 5 @@ -357,7 +361,8 @@ icon_static = 'icons/mob/human/species/alien/bodyparts.dmi' icon_state = "alien_r_arm" limb_id = BODYPART_ID_ALIEN - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ALIEN | BODYTYPE_ORGANIC + bodytype = BODYTYPE_ALIEN | BODYTYPE_ORGANIC + bodyshape = BODYSHAPE_HUMANOID px_x = 0 px_y = 0 bodypart_flags = BODYPART_UNREMOVABLE @@ -457,7 +462,7 @@ icon_state = "default_monkey_l_leg" limb_id = SPECIES_MONKEY should_draw_greyscale = FALSE - bodytype = BODYTYPE_MONKEY | BODYTYPE_ORGANIC + bodyshape = BODYSHAPE_MONKEY wound_resistance = -10 px_y = 4 dmg_overlay_type = SPECIES_MONKEY @@ -471,7 +476,8 @@ icon_static = 'icons/mob/human/species/alien/bodyparts.dmi' icon_state = "alien_l_leg" limb_id = BODYPART_ID_ALIEN - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ALIEN | BODYTYPE_ORGANIC + bodytype = BODYTYPE_ALIEN | BODYTYPE_ORGANIC + bodyshape = BODYSHAPE_HUMANOID px_x = 0 px_y = 0 bodypart_flags = BODYPART_UNREMOVABLE @@ -547,7 +553,7 @@ icon_state = "default_monkey_r_leg" limb_id = SPECIES_MONKEY should_draw_greyscale = FALSE - bodytype = BODYTYPE_MONKEY | BODYTYPE_ORGANIC + bodyshape = BODYSHAPE_MONKEY wound_resistance = -10 px_y = 4 dmg_overlay_type = SPECIES_MONKEY @@ -561,7 +567,8 @@ icon_static = 'icons/mob/human/species/alien/bodyparts.dmi' icon_state = "alien_r_leg" limb_id = BODYPART_ID_ALIEN - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ALIEN | BODYTYPE_ORGANIC + bodytype = BODYTYPE_ALIEN | BODYTYPE_ORGANIC + bodyshape = BODYSHAPE_HUMANOID px_x = 0 px_y = 0 bodypart_flags = BODYPART_UNREMOVABLE diff --git a/code/modules/surgery/bodyparts/robot_bodyparts.dm b/code/modules/surgery/bodyparts/robot_bodyparts.dm index 33b32778754..cdd92df7b88 100644 --- a/code/modules/surgery/bodyparts/robot_bodyparts.dm +++ b/code/modules/surgery/bodyparts/robot_bodyparts.dm @@ -23,7 +23,8 @@ icon_state = "borg_l_arm" is_dimorphic = FALSE should_draw_greyscale = FALSE - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC + bodytype = BODYTYPE_ROBOTIC + bodyshape = BODYSHAPE_HUMANOID change_exempt_flags = BP_BLOCK_CHANGE_SPECIES dmg_overlay_type = "robotic" @@ -56,7 +57,8 @@ icon_state = "borg_r_arm" is_dimorphic = FALSE should_draw_greyscale = FALSE - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC + bodytype = BODYTYPE_ROBOTIC + bodyshape = BODYSHAPE_HUMANOID change_exempt_flags = BP_BLOCK_CHANGE_SPECIES dmg_overlay_type = "robotic" @@ -90,7 +92,8 @@ icon_state = "borg_l_leg" is_dimorphic = FALSE should_draw_greyscale = FALSE - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC + bodytype = BODYTYPE_ROBOTIC + bodyshape = BODYSHAPE_HUMANOID change_exempt_flags = BP_BLOCK_CHANGE_SPECIES dmg_overlay_type = "robotic" @@ -137,7 +140,8 @@ icon_state = "borg_r_leg" is_dimorphic = FALSE should_draw_greyscale = FALSE - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC + bodytype = BODYTYPE_ROBOTIC + bodyshape = BODYSHAPE_HUMANOID change_exempt_flags = BP_BLOCK_CHANGE_SPECIES dmg_overlay_type = "robotic" @@ -183,7 +187,8 @@ icon_state = "borg_chest" is_dimorphic = FALSE should_draw_greyscale = FALSE - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC + bodytype = BODYTYPE_ROBOTIC + bodyshape = BODYSHAPE_HUMANOID change_exempt_flags = BP_BLOCK_CHANGE_SPECIES dmg_overlay_type = "robotic" @@ -361,7 +366,8 @@ icon_state = "borg_head" is_dimorphic = FALSE should_draw_greyscale = FALSE - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC + bodytype = BODYTYPE_ROBOTIC + bodyshape = BODYSHAPE_HUMANOID change_exempt_flags = BP_BLOCK_CHANGE_SPECIES dmg_overlay_type = "robotic" diff --git a/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm index 6cd42665d45..ec60375c8d1 100644 --- a/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm @@ -46,7 +46,7 @@ /obj/item/bodypart/leg/left/digitigrade icon_greyscale = 'icons/mob/human/species/lizard/bodyparts.dmi' limb_id = BODYPART_ID_DIGITIGRADE - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC | BODYTYPE_DIGITIGRADE + bodyshape = BODYSHAPE_HUMANOID | BODYSHAPE_DIGITIGRADE /obj/item/bodypart/leg/left/digitigrade/update_limb(dropping_limb = FALSE, is_creating = FALSE) . = ..() @@ -72,7 +72,7 @@ /obj/item/bodypart/leg/right/digitigrade icon_greyscale = 'icons/mob/human/species/lizard/bodyparts.dmi' limb_id = BODYPART_ID_DIGITIGRADE - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC | BODYTYPE_DIGITIGRADE + bodyshape = BODYSHAPE_HUMANOID | BODYSHAPE_DIGITIGRADE /obj/item/bodypart/leg/right/digitigrade/update_limb(dropping_limb = FALSE, is_creating = FALSE) . = ..() diff --git a/code/modules/surgery/organs/external/_external_organ.dm b/code/modules/surgery/organs/external/_external_organ.dm index 23b74ef9b4e..645caa630d7 100644 --- a/code/modules/surgery/organs/external/_external_organ.dm +++ b/code/modules/surgery/organs/external/_external_organ.dm @@ -25,6 +25,8 @@ var/use_mob_sprite_as_obj_sprite = FALSE ///Does this organ have any bodytypes to pass to it's bodypart_owner? var/external_bodytypes = NONE + ///Does this organ have any bodyshapes to pass to it's bodypart_owner? + var/external_bodyshapes = NONE ///Which flags does a 'modification tool' need to have to restyle us, if it all possible (located in code/_DEFINES/mobs) var/restyle_flags = NONE @@ -87,12 +89,15 @@ if(external_bodytypes) receiver.synchronize_bodytypes() + if(external_bodyshapes) + receiver.synchronize_bodyshapes() receiver.update_body_parts() /obj/item/organ/external/mob_remove(mob/living/carbon/organ_owner, special, moving) if(!special) organ_owner.synchronize_bodytypes() + organ_owner.synchronize_bodyshapes() organ_owner.update_body_parts() return ..() @@ -223,7 +228,7 @@ slot = ORGAN_SLOT_EXTERNAL_SNOUT preference = "feature_lizard_snout" - external_bodytypes = BODYTYPE_SNOUTED + external_bodyshapes = BODYSHAPE_SNOUTED //dna_block = DNA_SNOUT_BLOCK // NOVA EDIT REMOVAL - Customization - We have our own system to handle DNA. restyle_flags = EXTERNAL_RESTYLE_FLESH diff --git a/code/modules/surgery/prosthetic_replacement.dm b/code/modules/surgery/prosthetic_replacement.dm index 4b285d161bb..818c7a788d9 100644 --- a/code/modules/surgery/prosthetic_replacement.dm +++ b/code/modules/surgery/prosthetic_replacement.dm @@ -55,7 +55,7 @@ if(ishuman(target)) var/mob/living/carbon/human/human_target = target var/obj/item/bodypart/chest/target_chest = human_target.get_bodypart(BODY_ZONE_CHEST) - if(!(bodypart_to_attach.bodytype & target_chest.acceptable_bodytype)) + if((!(bodypart_to_attach.bodyshape & target_chest.acceptable_bodyshape)) && (!(bodypart_to_attach.bodytype & target_chest.acceptable_bodytype))) to_chat(user, span_warning("[bodypart_to_attach] doesn't match the patient's morphology.")) return SURGERY_STEP_FAIL if(bodypart_to_attach.check_for_frankenstein(target)) diff --git a/config/nova/config_nova.txt b/config/nova/config_nova.txt index deb7f925ea8..31f620888d9 100644 --- a/config/nova/config_nova.txt +++ b/config/nova/config_nova.txt @@ -146,3 +146,6 @@ VETERAN_LEGACY_SYSTEM ## How much time arrivals shuttle should stay at station after its engines recharged before returning to interlink. In deciseconds. 150 - 15 seconds. 0 - disables autoreturn. ARRIVALS_WAIT 150 + +## Uncomment to completely disable the opt-in system, which is a system that forces objectives to only roll on individuals who consent to it. +#DISABLE_ANTAG_OPT_IN_PREFERENCES diff --git a/html/changelogs/AutoChangeLog-pr-1891.yml b/html/changelogs/AutoChangeLog-pr-1891.yml new file mode 100644 index 00000000000..0c0adbabea4 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-1891.yml @@ -0,0 +1,4 @@ +author: "nikothedude" +delete-after: True +changes: + - rscadd: "Added antagonist opt-in! Brave crewmates wishing to be the target of nefarious evildoers now may indicate this desire in their character preferences." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2130.yml b/html/changelogs/AutoChangeLog-pr-2130.yml new file mode 100644 index 00000000000..d65d654f6d1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2130.yml @@ -0,0 +1,4 @@ +author: "13spacemen" +delete-after: True +changes: + - refactor: "Bodytypes to do with character sprite shape now have their own bodyshape var, all sprite handling is done with bodyshape and not bodytype anymore" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2137.yml b/html/changelogs/AutoChangeLog-pr-2137.yml deleted file mode 100644 index ab75566b57e..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2137.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "13spacemen" -delete-after: True -changes: - - bugfix: "Blood overlays on items no longer leak onto other objects" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2138.yml b/html/changelogs/AutoChangeLog-pr-2138.yml deleted file mode 100644 index 853a56fb32e..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2138.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Ben10Omintrix" -delete-after: True -changes: - - bugfix: "fixes pokemon ai still being active when inside the pokeball" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2144.yml b/html/changelogs/AutoChangeLog-pr-2144.yml deleted file mode 100644 index fdd83662978..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2144.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Melbert" -delete-after: True -changes: - - bugfix: "The Paddy's Claw should be properly unusable in situations which it should be properly unusable." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2145.yml b/html/changelogs/AutoChangeLog-pr-2145.yml deleted file mode 100644 index 9ed33509a78..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2145.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "yooriss" -delete-after: True -changes: - - rscadd: "The Entombed quirk has been added, allowing characters to start off with a permanently unremovable low-end MODsuit stuck to their back slot. Letting the suit's charge run low will eventually kill you, and the quirk has special interactions with both Ethereals and Plasmamen!" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2146.yml b/html/changelogs/AutoChangeLog-pr-2146.yml deleted file mode 100644 index 80cd9c987c3..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2146.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Absolucy" -delete-after: True -changes: - - qol: "Constructs now reuse the victim's mind instead of just moving their client" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2147.yml b/html/changelogs/AutoChangeLog-pr-2147.yml deleted file mode 100644 index a12ae26b8d3..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2147.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: "SyncIt21" -delete-after: True -changes: - - qol: "adds examines & screentips for building & deconstructing both machine & computer frames." - - qol: "Adding a circuitboard from a rped to n computer frame will automatically screw it in place like before." - - code_imp: "merged procs for computer & machine frames. autodocs them where possible." - - code_imp: "moved code for machine frame into its own file." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2148.yml b/html/changelogs/AutoChangeLog-pr-2148.yml deleted file mode 100644 index 5157e6ceeb2..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2148.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: "IndieanaJones" -delete-after: True -changes: - - balance: "Gorillas are faster, stronger, but not bigger too. Note while holding an item, they are the same speed as they were prior." - - balance: "Gorillas now have the understanding of languages as monkeys do." - - balance: "The Gorilla Cube Box for traitors has been replaced with a singular gorilla cube. Due to the aforementioned changes, this singular gorilla should be as scary if not scarier than 3 gorillas were prior." - - balance: " Magillitis Serum Autoinjector now grants the resulting gorilla a slow passive regeneration effect which kicks in after not taking damage for 12 seconds." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2149.yml b/html/changelogs/AutoChangeLog-pr-2149.yml deleted file mode 100644 index 84bf337648e..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2149.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "TJatPBnJ" -delete-after: True -changes: - - balance: "Power crepes are now finger food" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2150.yml b/html/changelogs/AutoChangeLog-pr-2150.yml deleted file mode 100644 index f8a4bc7cfea..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2150.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SyncIt21" -delete-after: True -changes: - - bugfix: "RCD converts miscellaneous turfs like basalt, sand, beach etc to plating first & not put a wall directly on top of them" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2151.yml b/html/changelogs/AutoChangeLog-pr-2151.yml deleted file mode 100644 index d7c9aa58f9c..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2151.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "mc-oofert" -delete-after: True -changes: - - rscadd: "Added an option to deathmatch loadout dropdown that allows you to pick a random loadout" - - bugfix: "In deathmatch, plasmamen are made humans and the UI supports more players" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2152.yml b/html/changelogs/AutoChangeLog-pr-2152.yml deleted file mode 100644 index c6d7b9e4633..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2152.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "00-Steven" -delete-after: True -changes: - - bugfix: "Newscasters no longer say \"No wanted issue posted. Have a secure day.\" when there is, in fact, an active wanted issue currently posted." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2157.yml b/html/changelogs/AutoChangeLog-pr-2157.yml deleted file mode 100644 index d88f979677a..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2157.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Knouli" -delete-after: True -changes: - - balance: "DeForest brand Civil Defense Medical Kits may now be repurposed to carry a limited selection of field-portable cheese rations." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2158.yml b/html/changelogs/AutoChangeLog-pr-2158.yml deleted file mode 100644 index 1e735fde359..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2158.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "00-Steven" -delete-after: True -changes: - - bugfix: "Medical/security records now show an icon based on the registered trim, rather than showing a question mark for records with customized titles." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2163.yml b/html/changelogs/AutoChangeLog-pr-2163.yml deleted file mode 100644 index ab0c85d5fd7..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2163.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "softcerv" -delete-after: True -changes: - - code_imp: "TRAIT_DEAF now works on non-carbon mobs" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2164.yml b/html/changelogs/AutoChangeLog-pr-2164.yml deleted file mode 100644 index 89d09d1d7bc..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2164.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "PapaMichael" -delete-after: True -changes: - - balance: "Fugitive hunters will spawn early if the emergency shuttle is called." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2165.yml b/html/changelogs/AutoChangeLog-pr-2165.yml deleted file mode 100644 index 0acb3c6a1bb..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2165.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "JohnFulpWillard" -delete-after: True -changes: - - qol: "Intelligent monkeys now punch people instead of biting them." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2166.yml b/html/changelogs/AutoChangeLog-pr-2166.yml deleted file mode 100644 index a100278dc54..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2166.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Iamgoofball" -delete-after: True -changes: - - balance: "xenomorph stomachs will no longer destroy items directly, refactored it to use acid_act()" - - bugfix: "fixes xenomorph vore accidentally destroying mobs it wasn't supposed to destroy, im thinking this was modified list in place shenanigans" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2167.yml b/html/changelogs/AutoChangeLog-pr-2167.yml deleted file mode 100644 index fb9957e2adb..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2167.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: "LT3" -delete-after: True -changes: - - code_imp: "Tram throwing now breaks grilles consistently" - - code_imp: "Tram malfunction lethality/throw chance are now a multiplier instead of flat value" - - code_imp: "Tram throw chance can be adjusted" - - code_imp: "Unlucky trait is now used in tram throw calculation" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2170.yml b/html/changelogs/AutoChangeLog-pr-2170.yml deleted file mode 100644 index cced53083f0..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2170.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "ArcaneMusic" -delete-after: True -changes: - - image: "New sprites for plant grafts!" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2171.yml b/html/changelogs/AutoChangeLog-pr-2171.yml deleted file mode 100644 index 60612d931ef..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2171.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "KingkumaArt" -delete-after: True -changes: - - rscadd: "a list of items called vendor_nocrush that vendors dont deal integrity damage to upon hitting them." - - bugfix: "Makes vending machines no longer crush chairs and conveyors." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2173.yml b/html/changelogs/AutoChangeLog-pr-2173.yml deleted file mode 100644 index 3e42a3e26b6..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2173.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Ghommie" -delete-after: True -changes: - - balance: "\"Freshness Jars full of Natural Bait\" is now a goodie and costs 200 credits instead of 2000" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2174.yml b/html/changelogs/AutoChangeLog-pr-2174.yml deleted file mode 100644 index 086180971c5..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2174.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "A.C.M.O." -delete-after: True -changes: - - bugfix: "Fixed the AI hologram's ability to copy the appearance of crew members." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2177.yml b/html/changelogs/AutoChangeLog-pr-2177.yml deleted file mode 100644 index bf9c3e68fa1..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2177.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "mc-oofert" -delete-after: True -changes: - - bugfix: "Grilles dont break by just walking into them under any circumstances" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2180.yml b/html/changelogs/AutoChangeLog-pr-2180.yml deleted file mode 100644 index bd5f7934fc9..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2180.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "necromanceranne" -delete-after: True -changes: - - bugfix: "Being in a Swat Suit appropriately protects you from collisions with a body, rather than the body thrown at you having these protections protecting YOU, the victim of the collision." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2181.yml b/html/changelogs/AutoChangeLog-pr-2181.yml new file mode 100644 index 00000000000..8dc7d10cbad --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2181.yml @@ -0,0 +1,4 @@ +author: "vinylspiders" +delete-after: True +changes: + - bugfix: "synths should now always drop their brains when gibbed" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2182.yml b/html/changelogs/AutoChangeLog-pr-2182.yml deleted file mode 100644 index 6814b22e910..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2182.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SyncIt21" -delete-after: True -changes: - - bugfix: "Cryostylane reaction now has a moderate & not extreme cooling effect. Helps you achieve more pure amounts of Cryostylane" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2183.yml b/html/changelogs/AutoChangeLog-pr-2183.yml deleted file mode 100644 index 8da2a1db267..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2183.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "13spacemen" -delete-after: True -changes: - - bugfix: "You can build material airlocks again" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2184.yml b/html/changelogs/AutoChangeLog-pr-2184.yml deleted file mode 100644 index 797744dae8e..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2184.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: "LT3" -delete-after: True -changes: - - qol: "Airlocks don't flash constantly on engineering override, override/overlay added for fire alarm" - - bugfix: "Airlock lighting should no longer render on top of player characters" - - bugfix: "Airlock emissives no longer overlap firedoors" - - bugfix: "Fixed missing overlays on various airlock types" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2186.yml b/html/changelogs/AutoChangeLog-pr-2186.yml deleted file mode 100644 index 85148425f8b..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2186.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "yooriss" -delete-after: True -changes: - - rscadd: "A new form of emoting is available called 'Do', accessible via the K and Ctrl-K keybinds by default (as well as the 'Do' verb). Do doesn't put your character name first and instead includes it in brackets at the end, so you can use it to write better prose and even narrate things in the environment around you with less clunkiness! Try it out today." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2189.yml b/html/changelogs/AutoChangeLog-pr-2189.yml deleted file mode 100644 index b0db2178347..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2189.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "TheVekter" -delete-after: True -changes: - - rscadd: "Added a new law to the Artist lawset in order to encourage Artist AIs to build an audience." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2191.yml b/html/changelogs/AutoChangeLog-pr-2191.yml deleted file mode 100644 index 09158f9debd..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2191.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Melbert" -delete-after: True -changes: - - bugfix: "Fixes grabbing yourself when you tackle someone." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2192.yml b/html/changelogs/AutoChangeLog-pr-2192.yml new file mode 100644 index 00000000000..67763b4fb43 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-2192.yml @@ -0,0 +1,5 @@ +author: "IndieanaJones" +delete-after: True +changes: + - rscadd: "New Changeling Ability: Hive Head" + - bugfix: "Fixed bees having an improper sprite offset" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-2195.yml b/html/changelogs/AutoChangeLog-pr-2195.yml deleted file mode 100644 index 57316c6d837..00000000000 --- a/html/changelogs/AutoChangeLog-pr-2195.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "TheSmallBlue" -delete-after: True -changes: - - qol: "added an HUD button to go up and down floors" \ No newline at end of file diff --git a/html/changelogs/archive/2024-03.yml b/html/changelogs/archive/2024-03.yml new file mode 100644 index 00000000000..1a02199135c --- /dev/null +++ b/html/changelogs/archive/2024-03.yml @@ -0,0 +1,112 @@ +2024-03-01: + 00-Steven: + - bugfix: Medical/security records now show an icon based on the registered trim, + rather than showing a question mark for records with customized titles. + - bugfix: Newscasters no longer say "No wanted issue posted. Have a secure day." + when there is, in fact, an active wanted issue currently posted. + 13spacemen: + - bugfix: You can build material airlocks again + - bugfix: Blood overlays on items no longer leak onto other objects + A.C.M.O.: + - bugfix: Fixed the AI hologram's ability to copy the appearance of crew members. + Absolucy: + - qol: Constructs now reuse the victim's mind instead of just moving their client + ArcaneMusic: + - image: New sprites for plant grafts! + Ben10Omintrix: + - bugfix: fixes pokemon ai still being active when inside the pokeball + Ghommie: + - balance: '"Freshness Jars full of Natural Bait" is now a goodie and costs 200 + credits instead of 2000' + Iamgoofball: + - balance: xenomorph stomachs will no longer destroy items directly, refactored + it to use acid_act() + - bugfix: fixes xenomorph vore accidentally destroying mobs it wasn't supposed to + destroy, im thinking this was modified list in place shenanigans + IndieanaJones: + - balance: Gorillas are faster, stronger, but not bigger too. Note while holding + an item, they are the same speed as they were prior. + - balance: Gorillas now have the understanding of languages as monkeys do. + - balance: The Gorilla Cube Box for traitors has been replaced with a singular gorilla + cube. Due to the aforementioned changes, this singular gorilla should be as + scary if not scarier than 3 gorillas were prior. + - balance: ' Magillitis Serum Autoinjector now grants the resulting gorilla a slow + passive regeneration effect which kicks in after not taking damage for 12 seconds.' + JohnFulpWillard: + - qol: Intelligent monkeys now punch people instead of biting them. + KingkumaArt: + - rscadd: a list of items called vendor_nocrush that vendors dont deal integrity + damage to upon hitting them. + - bugfix: Makes vending machines no longer crush chairs and conveyors. + Knouli: + - balance: DeForest brand Civil Defense Medical Kits may now be repurposed to carry + a limited selection of field-portable cheese rations. + LT3: + - code_imp: Tram throwing now breaks grilles consistently + - code_imp: Tram malfunction lethality/throw chance are now a multiplier instead + of flat value + - code_imp: Tram throw chance can be adjusted + - code_imp: Unlucky trait is now used in tram throw calculation + - qol: Airlocks don't flash constantly on engineering override, override/overlay + added for fire alarm + - bugfix: Airlock lighting should no longer render on top of player characters + - bugfix: Airlock emissives no longer overlap firedoors + - bugfix: Fixed missing overlays on various airlock types + Melbert: + - bugfix: The Paddy's Claw should be properly unusable in situations which it should + be properly unusable. + - bugfix: Fixes grabbing yourself when you tackle someone. + PapaMichael: + - balance: Fugitive hunters will spawn early if the emergency shuttle is called. + SyncIt21: + - qol: adds examines & screentips for building & deconstructing both machine & computer + frames. + - qol: Adding a circuitboard from a rped to n computer frame will automatically + screw it in place like before. + - code_imp: merged procs for computer & machine frames. autodocs them where possible. + - code_imp: moved code for machine frame into its own file. + - bugfix: RCD converts miscellaneous turfs like basalt, sand, beach etc to plating + first & not put a wall directly on top of them + - bugfix: Cryostylane reaction now has a moderate & not extreme cooling effect. + Helps you achieve more pure amounts of Cryostylane + TJatPBnJ: + - balance: Power crepes are now finger food + TheSmallBlue: + - qol: added an HUD button to go up and down floors + TheVekter: + - rscadd: Added a new law to the Artist lawset in order to encourage Artist AIs + to build an audience. + mc-oofert: + - rscadd: Added an option to deathmatch loadout dropdown that allows you to pick + a random loadout + - bugfix: In deathmatch, plasmamen are made humans and the UI supports more players + - bugfix: Grilles dont break by just walking into them under any circumstances + necromanceranne: + - bugfix: Being in a Swat Suit appropriately protects you from collisions with a + body, rather than the body thrown at you having these protections protecting + YOU, the victim of the collision. + softcerv: + - code_imp: TRAIT_DEAF now works on non-carbon mobs + yooriss: + - qol: 'The telepathy genetics mutation has had significant usability improvements: + it is now point-targeting based, and right-clicking the power allows for quick + resending to the same target, a feature mirrored by the new *treply emote. Telepathy + now also shows runechat messages.' + - rscadd: The Telepathic quirk has been added, allowing characters to start with + an unremovable (or activated) telepathy mutation. + - rscadd: A new form of emoting is available called 'Do', accessible via the K and + Ctrl-K keybinds by default (as well as the 'Do' verb). Do doesn't put your character + name first and instead includes it in brackets at the end, so you can use it + to write better prose and even narrate things in the environment around you + with less clunkiness! Try it out today. + - rscadd: The Underworld Connections quirk has been added, allowing dodgy characters + (including silicons!) to gain access to exploitable information at roundstart. + Non-silicons also receive a fully customizable black market uplink, too. + - qol: Prices at the galactic Black Market have now fallen drastically to be more + in line with general cargo costs, give or take, and should now be vastly more + affordable for most people. Pick up one and order some spuriously legal things + for you and your friends today! + - rscadd: The Entombed quirk has been added, allowing characters to start off with + a permanently unremovable low-end MODsuit stuck to their back slot. Letting + the suit's charge run low will eventually kill you, and the quirk has special + interactions with both Ethereals and Plasmamen! diff --git a/icons/mob/actions/actions_changeling.dmi b/icons/mob/actions/actions_changeling.dmi index bb3634a1dde..25a4e10aa57 100644 Binary files a/icons/mob/actions/actions_changeling.dmi and b/icons/mob/actions/actions_changeling.dmi differ diff --git a/icons/mob/clothing/head/helmet.dmi b/icons/mob/clothing/head/helmet.dmi index 5b30ae65b8f..49edcf8422f 100644 Binary files a/icons/mob/clothing/head/helmet.dmi and b/icons/mob/clothing/head/helmet.dmi differ diff --git a/icons/obj/clothing/head/helmet.dmi b/icons/obj/clothing/head/helmet.dmi index d9f02085e73..94d11e6b820 100644 Binary files a/icons/obj/clothing/head/helmet.dmi and b/icons/obj/clothing/head/helmet.dmi differ diff --git a/modular_nova/master_files/code/modules/cargo/markets/market_items/weapons.dm b/modular_nova/master_files/code/modules/cargo/markets/market_items/weapons.dm index 40ad5def7a4..64a09914c83 100644 --- a/modular_nova/master_files/code/modules/cargo/markets/market_items/weapons.dm +++ b/modular_nova/master_files/code/modules/cargo/markets/market_items/weapons.dm @@ -6,3 +6,8 @@ price_max = CARGO_CRATE_VALUE * 4 stock_max = 3 availability_prob = 80 + +// Makes this even more expensive +/datum/market_item/weapon/dimensional_bomb + price_min = CARGO_CRATE_VALUE * 180 + price_max = CARGO_CRATE_VALUE * 200 diff --git a/modular_nova/master_files/code/modules/client/preferences/mutant_parts.dm b/modular_nova/master_files/code/modules/client/preferences/mutant_parts.dm index 57c26e4dd37..b7d0f183f41 100644 --- a/modular_nova/master_files/code/modules/client/preferences/mutant_parts.dm +++ b/modular_nova/master_files/code/modules/client/preferences/mutant_parts.dm @@ -168,9 +168,9 @@ return if(.) - our_head.bodytype |= BODYTYPE_SNOUTED + our_head.bodyshape |= BODYSHAPE_SNOUTED else - our_head.bodytype &= ~BODYTYPE_SNOUTED + our_head.bodyshape &= ~BODYSHAPE_SNOUTED target.synchronize_bodytypes() /datum/preference/tri_color/snout diff --git a/modular_nova/master_files/code/modules/clothing/base_clothes.dm b/modular_nova/master_files/code/modules/clothing/base_clothes.dm index fbcdad4e997..f1e1bff17da 100644 --- a/modular_nova/master_files/code/modules/clothing/base_clothes.dm +++ b/modular_nova/master_files/code/modules/clothing/base_clothes.dm @@ -32,7 +32,7 @@ var/greyscale_config_worn_taur_paw var/greyscale_config_worn_taur_hoof - /// Used for BODYTYPE_CUSTOM: Needs to follow this syntax: a list() with the x and y coordinates of the pixel you want to get the color from. Colors are filled in as GAGs values for fallback. + /// Used for BODYSHAPE_CUSTOM: Needs to follow this syntax: a list() with the x and y coordinates of the pixel you want to get the color from. Colors are filled in as GAGs values for fallback. var/list/species_clothing_color_coords[3] /obj/item/clothing/head diff --git a/modular_nova/master_files/code/modules/clothing/glasses/_glasses.dm b/modular_nova/master_files/code/modules/clothing/glasses/_glasses.dm index 4b9ad40e929..b151b366d47 100644 --- a/modular_nova/master_files/code/modules/clothing/glasses/_glasses.dm +++ b/modular_nova/master_files/code/modules/clothing/glasses/_glasses.dm @@ -4,7 +4,7 @@ if(!ishuman(user)) return if(slot & ITEM_SLOT_EYES) - if(!(user.bodytype & BODYTYPE_ALT_FACEWEAR_LAYER)) + if(!(user.bodyshape & BODYSHAPE_ALT_FACEWEAR_LAYER)) return if(!isnull(alternate_worn_layer) && alternate_worn_layer < BODY_FRONT_LAYER) // if the alternate worn layer was already lower than snouts then leave it be return diff --git a/modular_nova/master_files/code/modules/clothing/head/_head.dm b/modular_nova/master_files/code/modules/clothing/head/_head.dm index f022fc99ac8..047abec8cd3 100644 --- a/modular_nova/master_files/code/modules/clothing/head/_head.dm +++ b/modular_nova/master_files/code/modules/clothing/head/_head.dm @@ -9,7 +9,7 @@ if(slot & ITEM_SLOT_HEAD) if(user.ears && (flags_inv & HIDEEARS)) user.update_inv_ears() - if(!(user.bodytype & BODYTYPE_ALT_FACEWEAR_LAYER)) + if(!(user.bodyshape & BODYSHAPE_ALT_FACEWEAR_LAYER)) return if(!isnull(alternate_worn_layer) && alternate_worn_layer < BODY_FRONT_LAYER) // if the alternate worn layer was already lower than snouts then leave it be return diff --git a/modular_nova/master_files/code/modules/clothing/masks/_masks.dm b/modular_nova/master_files/code/modules/clothing/masks/_masks.dm index 46fd2adeeed..8d29816c4fd 100644 --- a/modular_nova/master_files/code/modules/clothing/masks/_masks.dm +++ b/modular_nova/master_files/code/modules/clothing/masks/_masks.dm @@ -4,7 +4,7 @@ if(!ishuman(user)) return if(slot & ITEM_SLOT_MASK) - if(!(user.bodytype & BODYTYPE_ALT_FACEWEAR_LAYER)) + if(!(user.bodyshape & BODYSHAPE_ALT_FACEWEAR_LAYER)) return if(!isnull(alternate_worn_layer) && alternate_worn_layer < BODY_FRONT_LAYER) // if the alternate worn layer was already lower than snouts then leave it be return diff --git a/modular_nova/master_files/code/modules/mob/living/examine_tgui.dm b/modular_nova/master_files/code/modules/mob/living/examine_tgui.dm index 5648dda48d3..de181c91ffc 100644 --- a/modular_nova/master_files/code/modules/mob/living/examine_tgui.dm +++ b/modular_nova/master_files/code/modules/mob/living/examine_tgui.dm @@ -54,19 +54,30 @@ var/custom_species_lore var/obscured var/ooc_notes = "" + var/ideal_antag_optin_status + var/current_antag_optin_status var/headshot = "" // Handle OOC notes first - if(preferences && preferences.read_preference(/datum/preference/toggle/master_erp_preferences)) - var/e_prefs = preferences.read_preference(/datum/preference/choiced/erp_status) - var/e_prefs_nc = preferences.read_preference(/datum/preference/choiced/erp_status_nc) - var/e_prefs_v = preferences.read_preference(/datum/preference/choiced/erp_status_v) - var/e_prefs_mechanical = preferences.read_preference(/datum/preference/choiced/erp_status_mechanics) - ooc_notes += "ERP: [e_prefs]\n" - ooc_notes += "Non-Con: [e_prefs_nc]\n" - ooc_notes += "Vore: [e_prefs_v]\n" - ooc_notes += "ERP Mechanics: [e_prefs_mechanical]\n" - ooc_notes += "\n" + if(preferences) + if(preferences.read_preference(/datum/preference/toggle/master_erp_preferences)) + var/e_prefs = preferences.read_preference(/datum/preference/choiced/erp_status) + var/e_prefs_nc = preferences.read_preference(/datum/preference/choiced/erp_status_nc) + var/e_prefs_v = preferences.read_preference(/datum/preference/choiced/erp_status_v) + var/e_prefs_mechanical = preferences.read_preference(/datum/preference/choiced/erp_status_mechanics) + ooc_notes += "ERP: [e_prefs]\n" + ooc_notes += "Non-Con: [e_prefs_nc]\n" + ooc_notes += "Vore: [e_prefs_v]\n" + ooc_notes += "ERP Mechanics: [e_prefs_mechanical]\n" + ooc_notes += "\n" + + if(!CONFIG_GET(flag/disable_antag_opt_in_preferences)) + var/antag_prefs = holder.mind?.ideal_opt_in_level + var/effective_opt_in_level = holder.mind?.get_effective_opt_in_level() + if(isnull(antag_prefs)) + antag_prefs = preferences.read_preference(/datum/preference/choiced/antag_opt_in_status) + current_antag_optin_status = GLOB.antag_opt_in_strings[num2text(effective_opt_in_level)] + ideal_antag_optin_status = GLOB.antag_opt_in_strings[num2text(antag_prefs)] // Now we handle silicon and/or human, order doesn't really matter // If other variants of mob/living need to be handled at some point, put them here @@ -97,4 +108,14 @@ data["custom_species"] = custom_species data["custom_species_lore"] = custom_species_lore data["headshot"] = headshot + + data["ideal_antag_optin_status"] = ideal_antag_optin_status + data["current_antag_optin_status"] = current_antag_optin_status + return data + +/datum/examine_panel/ui_static_data(mob/user) + var/list/data = list() + + data["opt_in_colors"] = GLOB.antag_opt_in_colors + return data diff --git a/modular_nova/master_files/code/modules/mod/modules/_module.dm b/modular_nova/master_files/code/modules/mod/modules/_module.dm index 36ad7fb64c4..9997e2975cf 100644 --- a/modular_nova/master_files/code/modules/mod/modules/_module.dm +++ b/modular_nova/master_files/code/modules/mod/modules/_module.dm @@ -47,10 +47,10 @@ if(is_module_hidden()) // retracted modules can hide parts that aren't usable when inactive return - if(mod.chestplate && (mod.chestplate.supports_variations_flags & CLOTHING_DIGITIGRADE_VARIATION) && (mod.wearer.bodytype & BODYTYPE_DIGITIGRADE)) + if(mod.chestplate && (mod.chestplate.supports_variations_flags & CLOTHING_DIGITIGRADE_VARIATION) && (mod.wearer.bodyshape & BODYSHAPE_DIGITIGRADE)) suit_supports_variations_flags |= CLOTHING_DIGITIGRADE_VARIATION - if(mod.helmet && (mod.helmet.supports_variations_flags & CLOTHING_SNOUTED_VARIATION) && mod.wearer.bodytype & BODYTYPE_SNOUTED) + if(mod.helmet && (mod.helmet.supports_variations_flags & CLOTHING_SNOUTED_VARIATION) && mod.wearer.bodyshape & BODYSHAPE_SNOUTED) suit_supports_variations_flags |= CLOTHING_SNOUTED_VARIATION is_new_vox = isvoxprimalis(mod.wearer) is_old_vox = isvox(mod.wearer) diff --git a/modular_nova/modules/antag_opt_in/code/antag_optin_config.dm b/modular_nova/modules/antag_opt_in/code/antag_optin_config.dm new file mode 100644 index 00000000000..bff8c325131 --- /dev/null +++ b/modular_nova/modules/antag_opt_in/code/antag_optin_config.dm @@ -0,0 +1,2 @@ +/datum/config_entry/flag/disable_antag_opt_in_preferences + default = FALSE diff --git a/modular_nova/modules/antag_opt_in/code/antag_optin_preferences.dm b/modular_nova/modules/antag_opt_in/code/antag_optin_preferences.dm new file mode 100644 index 00000000000..eb6038e62e8 --- /dev/null +++ b/modular_nova/modules/antag_opt_in/code/antag_optin_preferences.dm @@ -0,0 +1,33 @@ +/datum/preference/choiced/antag_opt_in_status + category = PREFERENCE_CATEGORY_NON_CONTEXTUAL + savefile_identifier = PREFERENCE_CHARACTER + savefile_key = "antag_opt_in_status_pref" + +/datum/preference/choiced/antag_opt_in_status/init_possible_values() + return list(OPT_IN_YES_TEMP, OPT_IN_YES_KILL, OPT_IN_YES_ROUND_REMOVE, OPT_IN_NOT_TARGET) + +/datum/preference/choiced/antag_opt_in_status/create_default_value() + return OPT_IN_DEFAULT_LEVEL + +/datum/preference/choiced/antag_opt_in_status/is_accessible(datum/preferences/preferences) + if (!..(preferences)) + return FALSE + + return !(CONFIG_GET(flag/disable_antag_opt_in_preferences)) + +/datum/preference/choiced/antag_opt_in_status/deserialize(input, datum/preferences/preferences) + if(CONFIG_GET(flag/disable_antag_opt_in_preferences)) + return OPT_IN_DEFAULT_LEVEL + + return ..() + +/datum/preference/choiced/antag_opt_in_status/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences) + return FALSE + +/datum/preference/choiced/antag_opt_in_status/compile_constant_data() + var/list/data = ..() + + // An assoc list of values to display names so we don't show players numbers in their settings! + data[CHOICED_PREFERENCE_DISPLAY_NAMES] = GLOB.antag_opt_in_strings + + return data diff --git a/modular_nova/modules/antag_opt_in/code/job.dm b/modular_nova/modules/antag_opt_in/code/job.dm new file mode 100644 index 00000000000..1eb819d5c99 --- /dev/null +++ b/modular_nova/modules/antag_opt_in/code/job.dm @@ -0,0 +1,72 @@ +/datum/job + /// The minimum antag opt-in any holder of this job must use. If null, will defer to the mind's opt in level. + var/minimum_opt_in_level + /// Can this job be targetted as a heretic sacrifice target? + var/heretic_sac_target + /// Is this job targetable by contractors? + var/contractable + +/// Updates [minimum_opt_in_level] [heretic_sac_target] and [contractable]. +/datum/job/proc/update_opt_in_vars() + if(CONFIG_GET(flag/disable_antag_opt_in_preferences)) + return + + if(isnull(minimum_opt_in_level)) + minimum_opt_in_level = get_initial_opt_in_level() + if(isnull(heretic_sac_target)) + heretic_sac_target = initialize_heretic_target_status() + if(isnull(contractable)) + contractable = initialize_contractable_status() + + update_opt_in_desc_suffix() + +/// Returns this job's initial opt in level, taking into account departmental bitflags. +/datum/job/proc/get_initial_opt_in_level() + if (departments_bitflags & (DEPARTMENT_BITFLAG_SECURITY)) + return SECURITY_OPT_IN_LEVEL + if (departments_bitflags & (DEPARTMENT_BITFLAG_COMMAND)) + return COMMAND_OPT_IN_LEVEL + +/// Determines if this job should be sacrificable by heretics. +/datum/job/proc/initialize_heretic_target_status() + if (departments_bitflags & (DEPARTMENT_BITFLAG_SECURITY | DEPARTMENT_BITFLAG_COMMAND)) + return TRUE + + return FALSE + +/// Determines if this job should be targetable by contractors. +/datum/job/proc/initialize_contractable_status() + if (departments_bitflags & (DEPARTMENT_BITFLAG_SECURITY | DEPARTMENT_BITFLAG_COMMAND)) + return TRUE + + return FALSE + +/// Generates and sets a suffix appended to our description detailing our opt-in variables. +/datum/job/proc/update_opt_in_desc_suffix() + var/list/suffixes = list() + + if (minimum_opt_in_level) + suffixes += " Forces a minimum of [GLOB.antag_opt_in_strings["[minimum_opt_in_level]"]] antag opt-in." + if (contractable) + suffixes += " Targetable by contractors." + if (heretic_sac_target) + suffixes += " Targetable by heretics." + if (length(suffixes)) + var/suffix = jointext(suffixes, "") + set_opt_in_desc_suffix(suffix) + +/// Setter for [new_suffix]. Resets desc then appends the new suffix. +/datum/job/proc/set_opt_in_desc_suffix(new_suffix) + description = initial(description) + + if (new_suffix) + description += new_suffix + +/datum/controller/subsystem/job/SetupOccupations() + . = ..() + + if(CONFIG_GET(flag/disable_antag_opt_in_preferences)) + return + + for(var/datum/job/job as anything in all_occupations) + job.update_opt_in_vars() diff --git a/modular_nova/modules/antag_opt_in/code/mind.dm b/modular_nova/modules/antag_opt_in/code/mind.dm new file mode 100644 index 00000000000..91224664bf5 --- /dev/null +++ b/modular_nova/modules/antag_opt_in/code/mind.dm @@ -0,0 +1,92 @@ +/// If a player has any of these enabled, they are forced to use a minimum of OPT_IN_ANTAG_ENABLED_LEVEL antag optin. Dynamic - checked on the fly, not cached. +GLOBAL_LIST_INIT(optin_forcing_midround_antag_categories, list( + ROLE_CHANGELING_MIDROUND, + ROLE_MALF_MIDROUND, + ROLE_OBSESSED, + ROLE_SLEEPER_AGENT, +)) + +/// If a player has any of these enabled ON SPAWN, they are forced to use a minimum of OPT_IN_ANTAG_ENABLED_LEVEL antag optin for the rest of the round. +GLOBAL_LIST_INIT(optin_forcing_on_spawn_antag_categories, list( + ROLE_BROTHER, + ROLE_CHANGELING, + ROLE_CULTIST, + ROLE_HERETIC, + ROLE_MALF, + ROLE_OPERATIVE, + ROLE_TRAITOR, + ROLE_WIZARD, + ROLE_ASSAULT_OPERATIVE, + ROLE_CLOWN_OPERATIVE, + ROLE_NUCLEAR_OPERATIVE, + ROLE_HERETIC_SMUGGLER, + ROLE_PROVOCATEUR, + ROLE_STOWAWAY_CHANGELING, + ROLE_SYNDICATE_INFILTRATOR, +)) + +/datum/mind + /// The optin level set by preferences. + var/ideal_opt_in_level = OPT_IN_DEFAULT_LEVEL + /// Set on the FIRST mob login. Set by on-spawn antags (e.g. if you have traitor on and spawn, this will be set to OPT_IN_ANTAG_ENABLED_LEVEL and cannot change) + var/on_spawn_antag_opt_in_level = OPT_IN_NOT_TARGET + /// Set to TRUE on a successful transfer_mind() call. If TRUE, transfer_mind() will not refresh opt in. + var/opt_in_initialized + +/mob/living/Login() + . = ..() + + if (isnull(mind)) + return + if (isnull(client?.prefs)) + return + if (!mind.opt_in_initialized) + mind.update_opt_in(client.prefs) + mind.send_antag_optin_reminder() + mind.opt_in_initialized = TRUE + +/// Refreshes our ideal/on spawn antag opt in level by accessing preferences. +/datum/mind/proc/update_opt_in(datum/preferences/preference_instance = GLOB.preferences_datums[lowertext(key)]) + if (isnull(preference_instance)) + return + + ideal_opt_in_level = preference_instance.read_preference(/datum/preference/choiced/antag_opt_in_status) + + if (preference_instance.read_preference(/datum/preference/toggle/be_antag)) + for (var/antag_category in GLOB.optin_forcing_on_spawn_antag_categories) + if (antag_category in preference_instance.be_special) + on_spawn_antag_opt_in_level = OPT_IN_ANTAG_ENABLED_LEVEL + break + +/// Sends a bold message to our holder, telling them if their optin setting has been set to a minimum due to their antag preferences. +/datum/mind/proc/send_antag_optin_reminder() + var/datum/preferences/preference_instance = GLOB.preferences_datums[lowertext(key)] + var/client/our_client = preference_instance?.parent // that moment when /mind doesnt have a ref to client :) + if (our_client) + var/antag_level = get_antag_opt_in_level() + if (antag_level <= OPT_IN_NOT_TARGET) + return + var/stringified_level = GLOB.antag_opt_in_strings["[antag_level]"] + to_chat(our_client, span_boldnotice("Due to your antag preferences, your antag-optin status has been set to a minimum of [stringified_level].")) + +/// Gets the actual opt-in level used for determining targets. +/datum/mind/proc/get_effective_opt_in_level() + var/step_1 = max(ideal_opt_in_level, get_job_opt_in_level()) + var/step_2 = max(step_1, get_antag_opt_in_level()) + return step_2 + +/// Returns the opt in level of our job. +/datum/mind/proc/get_job_opt_in_level() + return assigned_role?.minimum_opt_in_level || OPT_IN_NOT_TARGET + +/// If we have any antags enabled in GLOB.optin_forcing_midround_antag_categories, returns OPT_IN_ANTAG_ENABLED_LEVEL. OPT_IN_NOT_TARGET otherwise. +/datum/mind/proc/get_antag_opt_in_level() + if (on_spawn_antag_opt_in_level > OPT_IN_NOT_TARGET) + return on_spawn_antag_opt_in_level + + var/datum/preferences/preference_instance = GLOB.preferences_datums[lowertext(key)] + if (!isnull(preference_instance) && preference_instance.read_preference(/datum/preference/toggle/be_antag)) + for (var/antag_category in GLOB.optin_forcing_midround_antag_categories) + if (antag_category in preference_instance.be_special) + return OPT_IN_ANTAG_ENABLED_LEVEL + return OPT_IN_NOT_TARGET diff --git a/modular_nova/modules/antag_opt_in/code/objective.dm b/modular_nova/modules/antag_opt_in/code/objective.dm new file mode 100644 index 00000000000..1c806b04957 --- /dev/null +++ b/modular_nova/modules/antag_opt_in/code/objective.dm @@ -0,0 +1,74 @@ +/datum/objective + /// The default opt in level of this objective. Only targets with opt in above or at this will be considered for this objective. + var/default_opt_in_level = OPT_IN_YES_KILL + +/// Simple getter for [default_opt_in_level]. Use for custom behavior. +/datum/objective/proc/get_opt_in_level(datum/mind/target_mind) + return default_opt_in_level + +/// Returns whether or not our opt in levels/variables are correct for the target. If true, they can be picked as a target. +/datum/objective/proc/opt_in_valid(datum/mind/target_mind) + return (get_opt_in_level(target_mind) <= target_mind.get_effective_opt_in_level()) + +// ROUND REMOVE +/datum/objective/maroon + default_opt_in_level = OPT_IN_YES_ROUND_REMOVE + +/datum/objective/assassinate/paradox_clone + default_opt_in_level = OPT_IN_YES_ROUND_REMOVE + +/datum/objective/capture + default_opt_in_level = OPT_IN_YES_ROUND_REMOVE + +/datum/objective/absorb + default_opt_in_level = OPT_IN_YES_ROUND_REMOVE + +/datum/objective/absorb_changeling + default_opt_in_level = OPT_IN_YES_ROUND_REMOVE + +/datum/objective/sacrifice + default_opt_in_level = OPT_IN_YES_ROUND_REMOVE + +/datum/objective/debrain + default_opt_in_level = OPT_IN_YES_ROUND_REMOVE + +// KILL + +/datum/objective/assassinate + default_opt_in_level = OPT_IN_YES_KILL + +/datum/objective/destroy + default_opt_in_level = OPT_IN_YES_KILL + +/datum/objective/mutiny + default_opt_in_level = OPT_IN_YES_KILL + +// TEMP + +/datum/objective/protect + default_opt_in_level = OPT_IN_YES_TEMP + +/datum/objective/protect/nonhuman + default_opt_in_level = OPT_IN_YES_TEMP + +/datum/objective/steal_n_of_type + default_opt_in_level = OPT_IN_YES_TEMP + +/datum/objective/steal + default_opt_in_level = OPT_IN_YES_TEMP + +/datum/objective/escape/escape_with_identity + default_opt_in_level = OPT_IN_YES_TEMP + +/datum/objective/jailbreak + default_opt_in_level = OPT_IN_YES_TEMP + +/datum/objective/contract + default_opt_in_level = OPT_IN_YES_TEMP + +/datum/objective/contract/opt_in_valid(datum/mind/target_mind) + var/datum/job/target_job = target_mind.assigned_role + if (!target_job?.contractable) + return FALSE + + return ..() diff --git a/modular_nova/modules/antag_opt_in/code/objective_item.dm b/modular_nova/modules/antag_opt_in/code/objective_item.dm new file mode 100644 index 00000000000..32c89aa9238 --- /dev/null +++ b/modular_nova/modules/antag_opt_in/code/objective_item.dm @@ -0,0 +1,20 @@ +/datum/objective_item + /// The opt in level all owners of the item must meet for this to be eligible as an objective target. + var/opt_in_level = OPT_IN_YES_TEMP + +/// Returns TRUE if we have no owners, or all owners's effective opt in level is above [opt_in_level]. FALSE otherwise. +/datum/objective_item/proc/owner_opted_in() + if (!length(item_owner)) + return TRUE + for (var/mob/living/player as anything in GLOB.player_list) + if ((player.mind?.assigned_role.title in item_owner) && player.stat != DEAD && !is_centcom_level(player.z)) // is an owner, copypasted from objective_items.dm owner_exists() + if (player.mind.get_effective_opt_in_level() < opt_in_level) + return FALSE + return TRUE + +/datum/objective_item/valid_objective_for(list/potential_thieves, require_owner) + var/opt_in_disabled = CONFIG_GET(flag/disable_antag_opt_in_preferences) + if (!opt_in_disabled && require_owner && !owner_opted_in()) + return FALSE + + return ..() diff --git a/modular_nova/modules/antag_opt_in/readme.md b/modular_nova/modules/antag_opt_in/readme.md new file mode 100644 index 00000000000..de41e00958b --- /dev/null +++ b/modular_nova/modules/antag_opt_in/readme.md @@ -0,0 +1,33 @@ +https://github.com/NovaSector/NovaSector/pull/121 + +## \