Allows cursekin to load a preference slot instead of simply changing species. (#5568)

## About The Pull Request

Title.

Adds a new preference option that allows you to designate a character
slot as your lycan transformation. Does not transfer quirks and does not
change the name.

Additionally, allows peopel to use the lycan species as a prefs-only
species for customization.

### Note

This will likely transfer languages and a few other things, but nothing
gamechanging. If the SAD does it (excluding quirks), this probably also
does it.
## Why It's Good For The Game

Adds for customization of the lycan form. Hair, Augments (NOT IMPLANTS).
Even taur mode.
## Proof Of Testing
<details>
<summary>Screenshots/Videos</summary>

<img width="923" height="643" alt="image"
src="https://github.com/user-attachments/assets/92586859-0bc3-49f5-be8a-f39ac798b730"
/>

</details>

## Changelog
🆑
add: Cursekin can select a character slot to transform into rather than
just siwtching species.
/🆑
This commit is contained in:
nikothedude
2026-05-17 20:40:01 +02:00
committed by GitHub
parent 6f506bbb71
commit be4c58986c
6 changed files with 96 additions and 14 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

@@ -50,10 +50,12 @@
)
no_equip_flags = ITEM_SLOT_ICLOTHING | ITEM_SLOT_OCLOTHING | ITEM_SLOT_GLOVES | ITEM_SLOT_FEET | ITEM_SLOT_SUITSTORE | ITEM_SLOT_BACK | ITEM_SLOT_BELT | ITEM_SLOT_EARS | ITEM_SLOT_HEAD | ITEM_SLOT_MASK | ITEM_SLOT_EYES | ITEM_SLOT_BACK | ITEM_SLOT_NECK
always_customizable = TRUE
sort_bottom = TRUE
/datum/species/lycan/prepare_human_for_preview(mob/living/carbon/human/lycan)
var/main_color = "#362d23"
var/secondary_color = "#9c5852"
var/secondary_color = "#bb1607"
var/tertiary_color = "#CCF6E2"
lycan.dna.features["mcolor"] = main_color
lycan.dna.features["mcolor2"] = secondary_color
@@ -68,15 +70,24 @@
race = /datum/species/lycan
/datum/species/lycan/get_species_description()
return list(placeholder_description)
return list("The transformed version of a Cursekin. Only available for customization of a Cursekin's transformed form.")
/datum/species/lycan/get_species_lore()
return list(placeholder_lore)
return list("See Cursekin lore.")
/datum/species/lycan/on_species_gain(mob/living/carbon/human/gainer, datum/species/old_species, pref_load, regenerate_icons = TRUE)
. = ..()
gainer.AddElement(/datum/element/inorganic_rejection)
gainer.dna.features["body_size"] = 2
gainer.maptext_height = 32 * gainer.dna.features["body_size"] //Adjust runechat height
gainer.mob_size = MOB_SIZE_LARGE
gainer.dna.update_body_size()
/datum/species/lycan/on_species_loss(mob/living/carbon/human/loser, datum/species/new_species, pref_load)
. = ..()
loser.RemoveElement(/datum/element/inorganic_rejection)
if(!loser.has_quirk(/datum/quirk/oversized))
loser.dna.features["body_size"] = loser?.client?.prefs?.read_preference(/datum/preference/numeric/body_size) || 1
loser.maptext_height = 32 * loser.dna.features["body_size"]
loser.mob_size = MOB_SIZE_HUMAN
loser.dna.update_body_size()
@@ -0,0 +1,20 @@
/datum/preference/numeric/cursekin_char_slot
category = PREFERENCE_CATEGORY_CHARACTER_BASICS
savefile_identifier = PREFERENCE_CHARACTER
savefile_key = "cursekin_char_slot"
can_randomize = FALSE
minimum = 0
maximum = /datum/preferences::max_save_slots
/datum/preference/numeric/cursekin_char_slot/has_relevant_feature(datum/preferences/preferences)
. = ..()
if (!.)
return FALSE
return ispath(preferences.read_preference(/datum/preference/choiced/species), /datum/species/human/cursekin)
/datum/preference/numeric/cursekin_char_slot/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences)
return
/datum/preference/numeric/cursekin_char_slot/create_default_value()
return 0
@@ -3,6 +3,23 @@
desc = "A larger than average, albeit slightly smoother brain. The hypothalamus seems larger than normal." // I read in a random medical artical that the hypothalamus controls aggression.
actions_types = list(/datum/action/cooldown/spell/beast_form)
var/list/removed_quirks = list()
var/last_slot
/obj/item/organ/brain/lycan/on_mob_insert(mob/living/carbon/brain_owner, special, movement_flags)
. = ..()
addtimer(CALLBACK(src, PROC_REF(try_getting_slot)), 0.1 SECONDS)
// no remove. we want it to REMEMBER.
/// A delayed getter for the current slot of the mob. Used because theres no easy way to access the client when a mob is spawend...
/obj/item/organ/brain/lycan/proc/try_getting_slot()
if (last_slot)
return
var/client/target_client = owner?.client
if (!isnull(target_client))
last_slot = target_client.prefs.savefile.get_entry("default_slot")
/obj/item/organ/brain/lycan/proc/enter_beast_form()
var/datum/species/human/cursekin/current_wolf = owner.dna.species
@@ -15,12 +32,30 @@
removed_quirks += bad_quirk.type
owner.remove_quirk(bad_quirk.type)
owner.visible_message(span_warning("[owner] grows massive, their body quickly getting covered in fur!"))
owner.set_species(current_wolf.lycanthropy_species, TRUE, TRUE, FALSE)
var/client/target_client = owner.client
if (!isnull(target_client))
var/name = owner.real_name
var/slot = target_client.prefs.read_preference(/datum/preference/numeric/cursekin_char_slot)
var/transfer = TRUE
if (isnull(last_slot))
last_slot = target_client.prefs.savefile.get_entry("default_slot")
target_client.prefs.load_character(slot)
if (!ispath(target_client.prefs.read_preference(/datum.preference/choiced/species), current_wolf.lycanthropy_species))
to_chat(owner, span_warning("Your selected slot is not a lycan! Defaulting to simply changing your species..."))
target_client.prefs.load_character(last_slot)
owner.set_species(current_wolf.lycanthropy_species, TRUE, TRUE, FALSE)
last_slot = null // allows for easier switching in later procs
transfer = FALSE
if (transfer)
target_client.prefs.safe_transfer_prefs_to_with_damage(owner)
owner.real_name = name
owner.name = name
owner.dna.update_dna_identity()
target_client.prefs.load_character(last_slot)
ADD_TRAIT(owner, TRAIT_BEAST_FORM, SPECIES_TRAIT)
owner.dna.features["body_size"] = 2
owner.maptext_height = 32 * owner.dna.features["body_size"] //Adjust runechat height
owner.dna.update_body_size()
owner.mob_size = MOB_SIZE_LARGE
playsound(owner, 'modular_zubbers/code/modules/customization/species/lycans/transform.ogg', 50)
/obj/item/organ/brain/lycan/proc/leave_beast_form()
@@ -28,13 +63,16 @@
if(isnull(current_wolf) && !HAS_TRAIT_FROM(owner, TRAIT_BEAST_FORM, SPECIES_TRAIT))
return
owner.visible_message(span_warning("[owner] shrinks down, their fur receding!"))
owner.set_species(/datum/species/human/cursekin, TRUE, TRUE, FALSE)
if (last_slot)
var/client/target_client = owner.client
if (!isnull(target_client))
target_client.prefs.load_character(last_slot)
target_client.prefs.safe_transfer_prefs_to_with_damage(owner)
owner.dna.update_dna_identity()
else
owner.set_species(/datum/species/human/cursekin, TRUE, TRUE, FALSE)
REMOVE_TRAIT(owner, TRAIT_BEAST_FORM, SPECIES_TRAIT)
if(!owner.has_quirk(/datum/quirk/oversized))
owner.dna.features["body_size"] = owner?.client?.prefs ?owner?.client?.prefs?.read_preference(/datum/preference/numeric/body_size) : 1
owner.maptext_height = 32 * owner.dna.features["body_size"]
owner.dna.update_body_size()
owner.mob_size = MOB_SIZE_HUMAN
playsound(owner, 'modular_zubbers/code/modules/customization/species/lycans/transform.ogg', 50)
if(removed_quirks)
for(var/typepath in removed_quirks)
+1
View File
@@ -9502,6 +9502,7 @@
#include "modular_zubbers\code\modules\customization\species\lycans\_cursekin_species.dm"
#include "modular_zubbers\code\modules\customization\species\lycans\_lycan_species.dm"
#include "modular_zubbers\code\modules\customization\species\lycans\cursekin_blacklisted_quirks.dm"
#include "modular_zubbers\code\modules\customization\species\lycans\cursekin_prefs.dm"
#include "modular_zubbers\code\modules\customization\species\lycans\lycan_verbs.dm"
#include "modular_zubbers\code\modules\customization\species\lycans\bodyparts\lycan_bodyparts.dm"
#include "modular_zubbers\code\modules\customization\species\lycans\organs\lycan_brain.dm"
@@ -0,0 +1,12 @@
import {
type Feature,
FeatureNumberInput,
} from '../../base';
export const cursekin_char_slot: Feature<number> = {
name: 'Lycan Character Slot',
description:
"The index of the character slot, from top to bottom, of the lycan character slot that will be used when you transform. \
Does not use quirks, implants, or the set name. Set to a non-lycan slot to simply switch species instead of loading a slot.",
component: FeatureNumberInput,
};