diff --git a/code/__DEFINES/~~bubber_defines/span.dm b/code/__DEFINES/~~bubber_defines/span.dm index ae88cc47010..37a8e8fcf66 100644 --- a/code/__DEFINES/~~bubber_defines/span.dm +++ b/code/__DEFINES/~~bubber_defines/span.dm @@ -4,3 +4,4 @@ #define span_velvet(str) ("" + str + "") #define vote_font(str) ("" + str + "") +#define span_yellow_flashy(str) ("" + str + "") diff --git a/code/controllers/subsystem/processing/quirks.dm b/code/controllers/subsystem/processing/quirks.dm index f7d32d2bf72..13b41ad9586 100644 --- a/code/controllers/subsystem/processing/quirks.dm +++ b/code/controllers/subsystem/processing/quirks.dm @@ -46,6 +46,7 @@ GLOBAL_LIST_INIT_TYPED(quirk_blacklist, /list/datum/quirk, list( list(/datum/quirk/featherweight, /datum/quirk/oversized), list(/datum/quirk/overweight, /datum/quirk/obese), list(/datum/quirk/dominant_aura, /datum/quirk/well_trained), + list(/datum/quirk/equipping/entombed, /datum/quirk/equipping/seamless_clothes), list(/datum/quirk/equipping/entombed, /datum/quirk/badback), //BUBBER EDIT ADDITION END )) diff --git a/html/changelogs/AutoChangeLog-pr-3132.yml b/html/changelogs/AutoChangeLog-pr-3132.yml deleted file mode 100644 index 44a38d61561..00000000000 --- a/html/changelogs/AutoChangeLog-pr-3132.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Alecksohs" -delete-after: True -changes: - - code_imp: "Vendors are now aware of sprite refits and will inform you if any are available." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3167.yml b/html/changelogs/AutoChangeLog-pr-3167.yml new file mode 100644 index 00000000000..1f2308b8e80 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3167.yml @@ -0,0 +1,4 @@ +author: "TealSeer" +delete-after: True +changes: + - bugfix: "fixed the SAD deleting wounds" \ No newline at end of file diff --git a/html/changelogs/archive/2025-02.yml b/html/changelogs/archive/2025-02.yml index 99303d6734e..dd83b31d8ab 100644 --- a/html/changelogs/archive/2025-02.yml +++ b/html/changelogs/archive/2025-02.yml @@ -369,3 +369,21 @@ - rscadd: Nurse costume suit now in loadout and medical vendor SpooksAnno: - rscadd: The ability to grab parts and cells as a borg. +2025-02-25: + ABoxFaux: + - code_imp: Teshari and Vox primalis can now use size collars in dorms/interlink + areas. + Alecksohs: + - code_imp: Vendors are now aware of sprite refits and will inform you if any are + available. + StrangeWeirdKitten: + - rscadd: Seamless heels quirk + - rscadd: Nameless Quirk + xPokee: + - rscadd: added the intern ghoul plushie to both in game and the loadouts +2025-02-26: + StrangeWeirdKitten: + - rscadd: Hypnotic Quirk + nikothedude: + - rscadd: Quirk; venemous bite. Allows you to bite people and inject them with a + venom, or medicine, of your choosing. diff --git a/modular_skyrat/master_files/code/datums/components/damage_tracker.dm b/modular_skyrat/master_files/code/datums/components/damage_tracker.dm index fe0b1cac095..33b111926df 100644 --- a/modular_skyrat/master_files/code/datums/components/damage_tracker.dm +++ b/modular_skyrat/master_files/code/datums/components/damage_tracker.dm @@ -76,6 +76,9 @@ /// What brain traumas does the owner currently have? var/list/trauma_list = list() + /// What wounds does the owner currently have? + var/list/wound_list = list() + /datum/component/damage_tracker/human/update_damage_values() . = ..() var/mob/living/carbon/human/human_parent = parent @@ -86,7 +89,13 @@ if(length(current_trauma_list)) trauma_list = current_trauma_list.Copy() - heart_damage = human_parent.check_organ_damage(/obj/item/organ/heart) + for(var/obj/item/bodypart/limb as anything in human_parent.get_wounded_bodyparts()) + for(var/datum/wound/limb_wound as anything in limb.wounds) + if(!islist(wound_list[limb.type])) + wound_list[limb.type] = list() + wound_list[limb.type] |= limb_wound.type + +heart_damage = human_parent.check_organ_damage(/obj/item/organ/heart) liver_damage = human_parent.check_organ_damage(/obj/item/organ/liver) lung_damage = human_parent.check_organ_damage(/obj/item/organ/lungs) stomach_damage = human_parent.check_organ_damage(/obj/item/organ/stomach) @@ -121,6 +130,14 @@ human_brain.gain_trauma(trauma_to_add) + for(var/obj/item/bodypart/limb_type as anything in wound_list) + var/obj/item/bodypart/limb_instance = locate(limb_type) in human_parent.bodyparts + if(!limb_instance) + continue + for(var/datum/wound/wound_type as anything in wound_list[limb_type]) + var/datum/wound/new_wound = new wound_type() + new_wound.apply_wound(limb_instance, TRUE) + return TRUE /datum/component/damage_tracker/human/Initialize(...) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/size_items.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/size_items.dm index 95bfa297c59..d50cf6342ff 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/size_items.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/size_items.dm @@ -116,13 +116,20 @@ if(!human_parent || !size_to_apply || (human_parent.dna.features["body_size"] == size_to_apply)) return FALSE + if(isteshari(human_parent) || isvoxprimalis(human_parent)) // We check if the human_parent is a Vox Primalis or Teshari & temporarily disable the bodysize restriction + human_parent.dna.species.body_size_restricted = FALSE + human_parent.dna.features["body_size"] = size_to_apply human_parent.maptext_height = 32 * human_parent.dna.features["body_size"] human_parent.dna.update_body_size() return TRUE /datum/component/temporary_size/Destroy(force, silent) + var/mob/living/carbon/human/human_parent = parent apply_size(original_size) + + if(isteshari(human_parent) || isvoxprimalis(human_parent)) // We reapply it on destroy if they were + human_parent.dna.species.body_size_restricted = TRUE UnregisterSignal(parent, COMSIG_ENTER_AREA) return ..() diff --git a/modular_zubbers/code/datums/quirks/neutral_quirks/entombed.dm b/modular_zubbers/code/datums/quirks/neutral_quirks/entombed.dm index caa19427537..d506bf1fef4 100644 --- a/modular_zubbers/code/datums/quirks/neutral_quirks/entombed.dm +++ b/modular_zubbers/code/datums/quirks/neutral_quirks/entombed.dm @@ -175,7 +175,8 @@ return "Civilian" /datum/preference/choiced/entombed_skin/is_accessible(datum/preferences/preferences) - if (!..()) + . = ..() + if(!.) return FALSE return "Entombed" in preferences.all_quirks @@ -191,7 +192,8 @@ maximum_value_length = 48 /datum/preference/text/entombed_mod_name/is_accessible(datum/preferences/preferences) - if (!..()) + . = ..() + if(!.) return FALSE return "Entombed" in preferences.all_quirks @@ -216,7 +218,8 @@ can_randomize = FALSE /datum/preference/text/entombed_mod_desc/is_accessible(datum/preferences/preferences) - if (!..()) + . = ..() + if(!.) return FALSE return "Entombed" in preferences.all_quirks @@ -242,7 +245,8 @@ maximum_value_length = 16 /datum/preference/text/entombed_mod_prefix/is_accessible(datum/preferences/preferences) - if (!..()) + . = ..() + if(!.) return FALSE return "Entombed" in preferences.all_quirks diff --git a/modular_zubbers/code/datums/quirks/neutral_quirks/hypnotic.dm b/modular_zubbers/code/datums/quirks/neutral_quirks/hypnotic.dm new file mode 100644 index 00000000000..9a8ee52dfc3 --- /dev/null +++ b/modular_zubbers/code/datums/quirks/neutral_quirks/hypnotic.dm @@ -0,0 +1,99 @@ +/datum/quirk/hypnotic + name = "Hypnotic" + desc = "You are extremely captivating to people who might be suspectable to fall into a stupor" + icon = FA_ICON_FACE_GRIN_HEARTS + value = 0 + quirk_flags = QUIRK_HUMAN_ONLY | QUIRK_HIDE_FROM_SCAN + gain_text = "Your presence grows richer." + lose_text = "Your potent presence dulls." + medical_record_text = "Patient shows signs of a far richer presence then normal." + erp_quirk = TRUE + var/hypnotic_text + var/hypnotic_color + +/datum/quirk/hypnotic/add(client/client_source) + RegisterSignal(quirk_holder, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) + +/datum/quirk/hypnotic/post_add() + hypnotic_text = quirk_holder.client.prefs.read_preference(/datum/preference/text/hypnotic_text) + hypnotic_color = quirk_holder.client.prefs.read_preference(/datum/preference/choiced/hypnotic_span) + +/datum/quirk/hypnotic/remove() + UnregisterSignal(quirk_holder, COMSIG_ATOM_EXAMINE) + +/datum/quirk/hypnotic/proc/on_examine(atom/source, mob/user, list/examine_list) + SIGNAL_HANDLER + + var/mob/living/examinee = source + if(!istype(user)) + return + if(!(examinee.client.prefs.read_preference(/datum/preference/toggle/erp/hypnosis))) + return + if(user.stat == DEAD) + return + if(isnull(hypnotic_color)) + return + examine_list += pick_color() + +/datum/quirk/hypnotic/proc/pick_color() + var/choice + switch(hypnotic_color) + if("Hypnophrase") + choice = "hypnophrase" + if("Velvet") + choice = "velvet" + if("Yellow Flashy") + choice = "glossy" + if("Pink") + choice = "pink" + if("Cult") + choice = "cult" + + return "[isnull(hypnotic_text) ? "Their eyes are enticing to stare at." : hypnotic_text]" + +/datum/quirk_constant_data/hypnotic + associated_typepath = /datum/quirk/hypnotic + customization_options = list( + /datum/preference/text/hypnotic_text, + /datum/preference/choiced/hypnotic_span, + ) + +/datum/preference/text/hypnotic_text + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + savefile_key = "hypnotic_quirk_text" + savefile_identifier = PREFERENCE_CHARACTER + can_randomize = FALSE + maximum_value_length = 100 + +/datum/preference/text/hypnotic_text/serialize(input) + return htmlrendertext(input) + +/datum/preference/text/hypnotic_text/deserialize(input, datum/preferences/preferences) + return htmlrendertext(input) + +/datum/preference/choiced/hypnotic_span + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + savefile_key = "flashy_text" + savefile_identifier = PREFERENCE_CHARACTER + can_randomize = FALSE + +/datum/preference/choiced/hypnotic_span/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences) + return + +/datum/preference/text/hypnotic_text/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences) + return + +/datum/preference/text/hypnotic_text/create_default_value() + return "Their eyes are inciticing to stare at." + +/datum/preference/choiced/hypnotic_span/create_default_value() + return "Hypnophrase" + +/datum/preference/choiced/hypnotic_span/init_possible_values() + return list( + "Hypnophrase", + "Velvet", + "Yellow Flashy", + "Pink", + "Cult", + ) diff --git a/modular_zubbers/code/datums/quirks/neutral_quirks/nameless.dm b/modular_zubbers/code/datums/quirks/neutral_quirks/nameless.dm new file mode 100644 index 00000000000..fc58e26b91d --- /dev/null +++ b/modular_zubbers/code/datums/quirks/neutral_quirks/nameless.dm @@ -0,0 +1,63 @@ +/datum/quirk/nameless + name = "Nameless" + desc = "You don't have a name. You are known only as a number." + medical_record_text = "Subject lacks a name in records." + value = 0 + icon = FA_ICON_USER_NINJA + gain_text = span_notice("You feel your name slip away.") + lose_text = span_notice("You spontaniously remember your full name!") + quirk_flags = QUIRK_HIDE_FROM_SCAN + var/character_name + var/new_name + +/datum/preference/text/nameless_quirk_option + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + savefile_key = "nameless_quirk_name" + savefile_identifier = PREFERENCE_CHARACTER + can_randomize = FALSE + maximum_value_length = 20 + +/// Some sanity to ensure you can't have " #1000" as your name. +/datum/preference/text/nameless_quirk_option/is_valid(value) + if(isnull(value)) + return TRUE + return !isnull(permissive_sanitize_name(value)) + +/datum/preference/text/nameless_quirk_option/serialize(input) + return htmlrendertext(input) + +/datum/preference/text/nameless_quirk_option/deserialize(input, datum/preferences/preferences) + return htmlrendertext(input) + +/datum/preference/text/nameless_quirk_option/apply_to_human(mob/living/carbon/human/target, value) + return + +/datum/quirk_constant_data/nameless + associated_typepath = /datum/quirk/nameless + customization_options = list( + /datum/preference/text/nameless_quirk_option + ) + +/datum/quirk/nameless/add(client/client_source) + character_name = client_source?.prefs.read_preference(/datum/preference/name/real_name) + new_name = generate_name() + quirk_holder.fully_replace_character_name(character_name, new_name) + +/datum/quirk/nameless/remove() + quirk_holder.fully_replace_character_name(new_name, character_name) + +/datum/quirk/nameless/proc/generate_name() + + var/prefix = quirk_holder.client?.prefs.read_preference(/datum/preference/text/nameless_quirk_option) + var/job + var/number = pick(rand(1000, 9999)) + + if(prefix) + job = prefix + else + job = isnull(quirk_holder.job) ? pick("Alpha", "Beta", "Delta", "Echo", "Zulu", "Omega") : quirk_holder.job + + return "[job] #[number]" + + + diff --git a/modular_zubbers/code/datums/quirks/neutral_quirks/seamless_clothes.dm b/modular_zubbers/code/datums/quirks/neutral_quirks/seamless_clothes.dm new file mode 100644 index 00000000000..2ad7ecb7f19 --- /dev/null +++ b/modular_zubbers/code/datums/quirks/neutral_quirks/seamless_clothes.dm @@ -0,0 +1,53 @@ +/datum/quirk/equipping/seamless_clothes + name = "Seamless Heels" + desc = "You come with heels stuck on you. Whether it be a freak accident or part of your design, you can't take them off." + medical_record_text = "Subject appears to have clothing attire fused to their body." + value = 0 + icon = FA_ICON_TSHIRT + gain_text = span_notice("You feel things stick to your body.") + lose_text = span_notice("You feel things loose their grip on your body.") + quirk_flags = QUIRK_HIDE_FROM_SCAN + forced_items = list(/obj/item/clothing/shoes/fancy_heels = list(ITEM_SLOT_FEET)) + var/prefix = "seamless" + var/obj/item/clothing/shoes/shoes + +/datum/quirk/equipping/seamless_clothes/on_equip_item(obj/item/equipped, success) + shoes = equipped + +/datum/quirk/equipping/seamless_clothes/post_add() // Quirks init on round start ready up before client does. + if(!istype(shoes, /obj/item/clothing/shoes/fancy_heels)) + CRASH("Type mismatch on [src] during on_equip_item. Tried to equip [shoes]") + shoes.name = "[prefix] [initial(shoes.name)]" + shoes.desc = "A pair of heels which refuse to come off your feet." + shoes.greyscale_colors = quirk_holder.client.prefs.read_preference(/datum/preference/color/seamless_shoe_color) + shoes.resistance_flags = ACID_PROOF | FIRE_PROOF + shoes.update_greyscale() + ADD_TRAIT(shoes, TRAIT_NODROP, CLOTHING_TRAIT) + RegisterSignal(shoes, COMSIG_ITEM_DROPPED, PROC_REF(remove_quirk)) + +/datum/quirk/equipping/seamless_clothes/remove() + if(isnull(shoes)) + return + UnregisterSignal(shoes, COMSIG_ITEM_DROPPED) + QDEL_NULL(shoes) + +/datum/quirk/equipping/seamless_clothes/proc/remove_quirk() + SIGNAL_HANDLER + qdel(src) + +/datum/quirk_constant_data/seamless_clothes + associated_typepath = /datum/quirk/equipping/seamless_clothes + customization_options = list( + /datum/preference/color/seamless_shoe_color + ) + +/datum/preference/color/seamless_shoe_color + savefile_key = "seamless_shoe_color" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + +/datum/preference/color/seamless_shoe_color/create_default_value() + return "#e7e7e7" + +/datum/preference/color/seamless_shoe_color/apply_to_human(mob/living/carbon/human/target, value) + return diff --git a/modular_zubbers/code/datums/quirks/positive_quirks/venemous_bite/venomous_bite.dm b/modular_zubbers/code/datums/quirks/positive_quirks/venemous_bite/venomous_bite.dm new file mode 100644 index 00000000000..8016ffc1a9b --- /dev/null +++ b/modular_zubbers/code/datums/quirks/positive_quirks/venemous_bite/venomous_bite.dm @@ -0,0 +1,145 @@ +#define VENOMOUS_BITE_DAMAGE 5 +#define VENOMOUS_BITE_WOUND_CHANCE 20 +#define VENOMOUS_BITE_WOUND_BONUS 40 + +/datum/action/cooldown/mob_cooldown/venomous_bite + name = "Inject Venom" + desc = "Sink your fangs into another and inject them with your venom. Ineffective against those wearing armor." + + button_icon = 'modular_zubbers/icons/mob/actions/quirks/venomous_bite.dmi' + button_icon_state = "venom" + + ranged_mousepointer = 'icons/effects/mouse_pointers/supplypod_pickturf.dmi' + + check_flags = AB_CHECK_CONSCIOUS | AB_CHECK_INCAPACITATED | AB_CHECK_HANDS_BLOCKED // cant use it if cuffed + + /// The reagent we will inject. + var/datum/reagent/reagent_typepath + /// How much of [reagent_typepath] we will inject. + var/to_inject = 0 + +/datum/action/cooldown/mob_cooldown/venomous_bite/New(Target, original, datum/reagent/our_reagent, quantity_override = null) + . = ..() + + set_reagent(our_reagent, quantity_override) + +/datum/action/cooldown/mob_cooldown/venomous_bite/proc/set_reagent(datum/reagent/new_reagent, quantity_override = null, cooldown_override = null) + reagent_typepath = new_reagent + + var/list/reagent_spec = /datum/preference/choiced/venomous_bite_venom::venomous_bite_choice_specs[new_reagent] + if (isnum(quantity_override)) + to_inject = quantity_override + else + to_inject = reagent_spec[1] + + if (isnum(cooldown_override)) + cooldown_time = cooldown_override + else + cooldown_time = reagent_spec[2] + +/datum/action/cooldown/mob_cooldown/venomous_bite/set_click_ability(mob/on_who) + . = ..() + if (!.) + return + + owner.visible_message("[owner] bares [owner.p_their()] fangs...", span_warning("You bare your fangs...")) + +/datum/action/cooldown/mob_cooldown/venomous_bite/Activate(atom/target_atom) + if (!isliving(target_atom)) + return FALSE + if (iscarbon(owner)) + var/mob/living/carbon/carbon_holder = owner + if (carbon_holder.is_mouth_covered()) + owner.balloon_alert(owner, "mouth covered!") + return FALSE + + if (!owner.Adjacent(target_atom)) + owner.balloon_alert(owner, "too far!") + return FALSE + + if (target_atom == owner) + owner.balloon_alert(owner, "can't bite yourself!") + return FALSE + + owner.visible_message(span_warning("[owner] starts to bite [target_atom]!"), span_warning("You start to bite [target_atom]!"), ignored_mobs = target_atom) + to_chat(target_atom, span_userdanger("[owner] starts to bite you!")) + owner.balloon_alert_to_viewers("biting...") + var/result = do_after(owner, 0.5 SECONDS, target_atom, IGNORE_HELD_ITEM) + if (!result) + return FALSE + + . = ..() + + var/penetrated = try_bite(target_atom) + if (penetrated) + inject(target_atom) + return TRUE + +/// Does NOT inject reagents; represents the initial bite. Can end in your teeth being broken by armor. Dumbass. +/datum/action/cooldown/mob_cooldown/venomous_bite/proc/try_bite(mob/living/target) + var/target_zone = check_zone(owner.zone_selected) + var/armor = target.run_armor_check(target_zone, MELEE) + var/obj/item/bodypart/part = target.get_bodypart(target_zone) + + var/text = "[owner] sinks [owner.p_their()] teeth into [target]'s [target.parse_zone_with_bodypart(target_zone)]!" + var/self_message = "You sink your teeth into [target]'s [target.parse_zone_with_bodypart(target_zone)]!" + var/victim_message = "[owner] sinks [owner.p_their()] teeth into your [target.parse_zone_with_bodypart(target_zone)]!" + + var/covered = FALSE + if (ishuman(target)) + var/mob/living/carbon/human/human_target = target + for (var/obj/item/clothing/iter_clothing as anything in human_target.get_clothing_on_part(part)) + if (iter_clothing.clothing_flags & THICKMATERIAL) + covered = TRUE + + text = "[owner] tries to bite [target], but breaks [owner.p_their()] teeth on [target]'s clothing! Ouch!" + self_message = "You try to bite [target], but you break your teeth on [target.p_their()] clothing! Ouch!" + victim_message = "[owner] tries to bite you, but breaks [owner.p_their()] teeth on your clothing! Ouch!" + + owner.emote("scream") + if (isliving(owner)) + var/mob/living/living_owner = owner + living_owner.apply_damage(1, BRUTE, BODY_ZONE_HEAD) + + break + + owner.visible_message(span_warning(text), span_warning(self_message), ignored_mobs = list(target)) + to_chat(target, span_userdanger(victim_message)) + + owner.do_attack_animation(target, ATTACK_EFFECT_BITE) + playsound(owner, 'sound/items/weapons/bite.ogg', 60, TRUE) + if (covered) + return FALSE + var/wound_bonus = 0 + if (prob(VENOMOUS_BITE_WOUND_CHANCE)) + wound_bonus = VENOMOUS_BITE_WOUND_BONUS + target.apply_damage(VENOMOUS_BITE_DAMAGE, BRUTE, target_zone, armor, wound_bonus = wound_bonus, sharpness = SHARP_POINTY) + if (iscarbon(owner)) + var/mob/living/carbon/carbon_owner = owner + for (var/datum/disease/our_disease as anything in carbon_owner.diseases) + if (our_disease.spread_flags & DISEASE_SPREAD_CONTACT_FLUIDS || our_disease.spread_flags & DISEASE_SPREAD_CONTACT_SKIN) + target.ContactContractDisease(our_disease, target_zone) + + if (iscarbon(target)) + var/mob/living/carbon/carbon_target = target + for (var/datum/disease/their_disease as anything in carbon_target.diseases) + if (their_disease.spread_flags & DISEASE_SPREAD_CONTACT_FLUIDS || their_disease.spread_flags & DISEASE_SPREAD_CONTACT_SKIN) + carbon_owner.ContactContractDisease(their_disease, target_zone) + + return TRUE + +/datum/action/cooldown/mob_cooldown/venomous_bite/proc/inject(mob/living/target) + var/target_zone = check_zone(owner.zone_selected) + if (!target.try_inject(owner, target_zone)) + return FALSE + var/temp + if (ishuman(owner)) + var/mob/living/carbon/human/human_holder = owner + temp = human_holder.coretemperature + target.reagents.add_reagent(reagent_typepath, to_inject, reagtemp = temp) + + return TRUE + +#undef VENOMOUS_BITE_DAMAGE +#undef VENOMOUS_BITE_WOUND_BONUS +#undef VENOMOUS_BITE_WOUND_CHANCE diff --git a/modular_zubbers/code/datums/quirks/positive_quirks/venemous_bite/venomous_bite_quirk.dm b/modular_zubbers/code/datums/quirks/positive_quirks/venemous_bite/venomous_bite_quirk.dm new file mode 100644 index 00000000000..86d169e8ec4 --- /dev/null +++ b/modular_zubbers/code/datums/quirks/positive_quirks/venemous_bite/venomous_bite_quirk.dm @@ -0,0 +1,84 @@ +/datum/quirk/venomous_bite + name = "Venomous Bite" + desc = "You have a venom gland, and can bite people to inject them with a toxin of your choosing." + icon = FA_ICON_TEETH_OPEN + value = 8 + gain_text = span_notice("You feel a venom gland in the back of your throat.") + lose_text = span_warning("Your venom gland vanishes.") + medical_record_text = "Patient possesses a venom gland." + +/datum/quirk/venomous_bite/add(client/client_source) + var/datum/reagent/reagent = text2path(client_source?.prefs?.read_preference(/datum/preference/choiced/venomous_bite_venom)) + + var/mob/living/carbon/human/human_holder = quirk_holder + var/datum/action/cooldown/mob_cooldown/venomous_bite/action = new /datum/action/cooldown/mob_cooldown/venomous_bite(human_holder, our_reagent = reagent) + action.Grant(human_holder) + +/datum/quirk/venomous_bite/remove() + var/datum/action/cooldown/mob_cooldown/venomous_bite/action = locate(/datum/action/cooldown/mob_cooldown/venomous_bite) in quirk_holder.actions + action.Remove() + + return ..() + +/datum/quirk_constant_data/venomous_bite + associated_typepath = /datum/quirk/venomous_bite + customization_options = list(/datum/preference/choiced/venomous_bite_venom) + +/datum/preference/choiced/venomous_bite_venom + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + savefile_key = "venomous_bite_venom" + savefile_identifier = PREFERENCE_CHARACTER + /// Format: (reagent typepath -> list(amount to inject per bite, cooldown)) + var/static/list/venomous_bite_choice_specs = list( + /datum/reagent/toxin = list(5, 80 SECONDS), + /datum/reagent/toxin/venom = list(5, 180 SECONDS), + /datum/reagent/toxin/carpotoxin = list(5, 60 SECONDS), // less powerful than toxin + // drugs + /datum/reagent/drug/space_drugs = list(5, 60 SECONDS), + /datum/reagent/toxin/mindbreaker = list(5, 60 SECONDS), + // erp stuff + /datum/reagent/drug/aphrodisiac/crocin = list(5, 2 SECONDS), + /datum/reagent/drug/aphrodisiac/crocin/hexacrocin = list(5, 5 SECONDS), + /datum/reagent/drug/aphrodisiac/succubus_milk = list(5, 2 SECONDS), + /datum/reagent/drug/aphrodisiac/incubus_draft = list(5, 2 SECONDS), +) + + +/datum/preference/choiced/venomous_bite_venom/init_possible_values() + var/list/choices = list() + for (var/entry in venomous_bite_choice_specs) + choices += "[entry]" + + return choices + +/datum/preference/choiced/venomous_bite_venom/create_default_value() + return "/datum/reagent/toxin" + +/datum/preference/choiced/venomous_bite_venom/compile_constant_data() + var/list/data = ..() + + var/list/titles = list() + + for (var/datum/reagent/entry as anything in venomous_bite_choice_specs) + var/list/specs = venomous_bite_choice_specs[entry] + + var/inject = specs[1] + var/cooldown = specs[2] + + var/name = entry::name + + titles["[entry]"] = "[name] ([inject]u, [cooldown / 10] second cooldown)" + + data[CHOICED_PREFERENCE_DISPLAY_NAMES] = titles + + return data + +/datum/preference/choiced/venomous_bite_venom/is_accessible(datum/preferences/preferences) + . = ..() + if (!.) + return FALSE + + return "Venomous Bite" in preferences.all_quirks + +/datum/preference/choiced/venomous_bite_venom/apply_to_human(mob/living/carbon/human/target, value) + return diff --git a/modular_zubbers/code/game/objects/items/plushes.dm b/modular_zubbers/code/game/objects/items/plushes.dm index e0256dd6341..40cbf750995 100644 --- a/modular_zubbers/code/game/objects/items/plushes.dm +++ b/modular_zubbers/code/game/objects/items/plushes.dm @@ -244,3 +244,12 @@ gender = FEMALE squeak_override = list('modular_zubbers/sound/emotes/arf.ogg' = 1) +// xPokee's plush +/obj/item/toy/plush/ghoul + name = "intern ghoul plushie" + desc = "Even the marketable plushie of this thing is utterly terrifying. At least it's cuddly..." + icon = 'modular_zubbers/icons/obj/toys/plushes.dmi' + icon_state = "johnghoul" + attack_verb_continuous = list("ghouls") + attack_verb_simple = list("ghoul") + squeak_override = list('modular_zubbers/code/modules/blooper/voice/bloopers/kazooie/ehh.ogg' = 1) diff --git a/modular_zubbers/code/modules/loadout/categories/toys.dm b/modular_zubbers/code/modules/loadout/categories/toys.dm index fb9246e6b23..a43073757fd 100644 --- a/modular_zubbers/code/modules/loadout/categories/toys.dm +++ b/modular_zubbers/code/modules/loadout/categories/toys.dm @@ -86,3 +86,7 @@ /datum/loadout_item/toys/androiddog name = "Android Dog Plushie" item_path = /obj/item/toy/plush/androiddog + +/datum/loadout_item/toys/ghoul + name = "Intern Ghoul Plushie" + item_path = /obj/item/toy/plush/ghoul diff --git a/modular_zubbers/icons/mob/actions/quirks/venomous_bite.dmi b/modular_zubbers/icons/mob/actions/quirks/venomous_bite.dmi new file mode 100644 index 00000000000..45761c4335f Binary files /dev/null and b/modular_zubbers/icons/mob/actions/quirks/venomous_bite.dmi differ diff --git a/modular_zubbers/icons/obj/toys/plushes.dmi b/modular_zubbers/icons/obj/toys/plushes.dmi index 8a2679cd87d..d3b9e66e7bf 100644 Binary files a/modular_zubbers/icons/obj/toys/plushes.dmi and b/modular_zubbers/icons/obj/toys/plushes.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 76d2290b478..10b6b0f112e 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -8832,15 +8832,20 @@ #include "modular_zubbers\code\datums\quirks\neutral_quirks\food.dm" #include "modular_zubbers\code\datums\quirks\neutral_quirks\hungry.dm" #include "modular_zubbers\code\datums\quirks\neutral_quirks\hydrophilic.dm" +#include "modular_zubbers\code\datums\quirks\neutral_quirks\hypnotic.dm" #include "modular_zubbers\code\datums\quirks\neutral_quirks\lungs.dm" +#include "modular_zubbers\code\datums\quirks\neutral_quirks\nameless.dm" #include "modular_zubbers\code\datums\quirks\neutral_quirks\oversized_quirk.dm" #include "modular_zubbers\code\datums\quirks\neutral_quirks\pet_owner.dm" +#include "modular_zubbers\code\datums\quirks\neutral_quirks\seamless_clothes.dm" #include "modular_zubbers\code\datums\quirks\neutral_quirks\waddle.dm" #include "modular_zubbers\code\datums\quirks\positive_quirks\dominant_aura.dm" #include "modular_zubbers\code\datums\quirks\positive_quirks\empath_override.dm" #include "modular_zubbers\code\datums\quirks\positive_quirks\featherweight.dm" #include "modular_zubbers\code\datums\quirks\positive_quirks\life_savings.dm" #include "modular_zubbers\code\datums\quirks\positive_quirks\masquerade_food.dm" +#include "modular_zubbers\code\datums\quirks\positive_quirks\venemous_bite\venomous_bite.dm" +#include "modular_zubbers\code\datums\quirks\positive_quirks\venemous_bite\venomous_bite_quirk.dm" #include "modular_zubbers\code\datums\shuttle\arena.dm" #include "modular_zubbers\code\datums\shuttles\emergency.dm" #include "modular_zubbers\code\datums\station_traits\disabled_traits.dm" diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/hypnotic_quirk.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/hypnotic_quirk.tsx new file mode 100644 index 00000000000..05b48e9f2dd --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/hypnotic_quirk.tsx @@ -0,0 +1,14 @@ +import { Feature, FeatureChoiced, FeatureShortTextInput } from '../../base'; +import { FeatureDropdownInput } from '../../dropdowns'; + +export const hypnotic_quirk_text: Feature = { + name: 'Hypnotic Text Examine', + description: + 'The examine text portrayed from your character. Use third person (Their, He, She, etc)', + component: FeatureShortTextInput, +}; + +export const flashy_text: FeatureChoiced = { + name: 'Text Color Selection', + component: FeatureDropdownInput, +}; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/nameless.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/nameless.tsx new file mode 100644 index 00000000000..d8b519a14c1 --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/nameless.tsx @@ -0,0 +1,8 @@ +import { Feature, FeatureShortTextInput } from '../../base'; + +export const nameless_quirk_name: Feature = { + name: 'Prefix Name', + description: + 'Example: (Prefix) #1334. Leave blank to default to job title. Minimum 3 characters.', + component: FeatureShortTextInput, +}; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/seamless_clothes.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/seamless_clothes.tsx new file mode 100644 index 00000000000..ac33c2a28a3 --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/seamless_clothes.tsx @@ -0,0 +1,6 @@ +import { Feature, FeatureColorInput } from '../../base'; + +export const seamless_shoe_color: Feature = { + name: 'Shoe Color', + component: FeatureColorInput, +}; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/venomous_bite.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/venomous_bite.tsx new file mode 100644 index 00000000000..ecbada22de9 --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/venomous_bite.tsx @@ -0,0 +1,7 @@ +import { FeatureChoiced } from '../../base'; +import { FeatureDropdownInput } from '../../dropdowns'; + +export const venomous_bite_venom: FeatureChoiced = { + name: 'Venom Type', + component: FeatureDropdownInput, +};