Ports a character customization option: Quirks (#28388)

* Makes the datum

* Initial Commit

* Gets TGUI menu not crashing

* Autodoc

* quirk menu bugged

* oh.

* Working menu + buttons

* trait defintes pt 1/?

* Moves traits around

* ACTUALLY START ON THE QUIRKS THEMSELVES

* TGUI Bundle Rebuild

* TGUI properly saves now

* Removes allergies for scope reasons, make foreigner work properly

* TGUI tweaks

* Reworks TGUI Menu

* quirks store the mob, not mind

* Adds asthma and mute

* minor tweaks

* Cloning re-adds quirks

* Adds functionality to frail

* Adds crafty

* TGUI fix

* Fixes a frail bug

* Makes sure the list is in the correct format

* TGUI size change

* Makes skittish work

* Adds glutton, removes unused traits

* Changes description and adds function to glutton

* Freerunner functioning

* Crafty buff

* Clear quirk list when changing species

* Forgot to remove light step

* Delete

* Refactor item-giving

* TGUI Bundle Rebuild

* whoops

* Apply quirks when changing species

* Removes some unneeded defines/paths

* Replaces improved charging cord with a bad charger

* coment

* Guard clause

* Changes how quirks add and remove organs

* unused var

* adding organs works, removing them doesn't yet

* oh that fixed it

* Hopefully finally once and for all fix the json issues

* Buffs asthma

* switches the processor to ssobj since it's slower

* actually spawns the items whoops

* maybe actually fixes json issues I really hope this doesn't come up again?

* moves sql to the right directory

* CULPRIT FOUND, JSON ISSUES ACTUALLY SOLVED

* adds admin tooling for quirks

* Ups the cost of lungs

* Adds removal for the drinking ones

* Fixes some duplicate code

* Removing foreigner works

* wops

* bumps sql version to 65

* prettier

* semicolon

* Foreigners can understand galcomm but not speak it, as per headmin request

* Different solution was agreed upon

* CC announcements now get auto-translated

* Apply suggestions from code review

Lewc quick suggestions

Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com>
Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com>

* Move alcohol tolerance basetype

* accomodates for reset_styles

* Swap to species flags, and being dead is a universal process stopper

* adds a foreigner trait

* Xenos and the like can't understand CC's translated announcements

* TGUI Bundle Rebuild

* Lewc quick fixes

Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com>
Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com>

* i forgor

* i forgor pt 2

* process properly returns true

* TGUI Bundle Rebuild

* sql update for fixing merge conflicts

* bundle changes

* actual sql fix

* Not test tiny in prod

* sql fix?

* tgui update, first pass

* Adds schema changes to main quirk branch

* persistent data works now

* TGUI Bundle Rebuild

* Fixes conflict with job assignment datumization

* TGUI Bundle Rebuild

* Adds pacifism by request, -3 points

* gives skittish a small cd

* Makes the lunch randomizer  I was thinking about doing

* GC returns a qdel hint now

* Removes hard refs

* SQL save fix

* Fixes admin tools

* Fixes wizards getting quirked up

* ragin too

* Lightweight is more lightweight

* Adds admin logging for when someone makes a languagesless character

* TGUI Bundle Rebuild

* Adds colorblind, hungry, and buffs asthma

* fixed vv post-merge conflict

* behold, my monster

* rebuild and merge master

* Adds more positive quirks, and makes monochrome give more points

* adds nearsighted, and no whispering

* sorry linter

* Adds the cool quirk, thanks to pumpkin312

* Oh dear that signal gets sent to everyone every time someone spawns in

* i forgot that slimes dont have eyes

* tgui fix

* bundle rebuild probably

* prettier

* prettier

* Skittish package fix

* force add bundle

* Makes plasmemes be unable to take foreigner

* Makes advanced lungs respect the owner's species

* makes breaking open wrapped crates/lockers a do_after_once

* Makes plasmeme/vox advanced lungs actually help

* You get glasses anyway whoops

* bundle rebuild

---------

Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com>
Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>
Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com>
Co-authored-by: warriorstar-orion <orion@snowfrost.garden>
This commit is contained in:
BiancaWilkson
2025-11-03 19:18:52 -05:00
committed by GitHub
parent 99d57fd35d
commit d558a69583
49 changed files with 971 additions and 78 deletions
@@ -185,7 +185,7 @@
var/shot_leg = pick("l_foot", "r_foot")
gun.process_fire(user, user, 0, params, zone_override = shot_leg)
user.drop_item()
else if(prob(50) && !HAS_TRAIT(user, TRAIT_BADASS))
else if(prob(50) && !(HAS_TRAIT(user, TRAIT_BADASS) || HAS_TRAIT(user, TRAIT_COOL)))
message = "attempts to twirl [thing] around in their hand, but fumbles!"
user.drop_item()
else
@@ -1226,7 +1226,8 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, list(/obj/machinery/atmospherics/unary/ven
return TRUE
/mob/living/carbon/proc/selfFeed(obj/item/food/to_eat, fullness)
if(to_eat.junkiness && satiety < -150 && nutrition > NUTRITION_LEVEL_STARVING + 50)
var/is_glutton = HAS_TRAIT(src, TRAIT_GLUTTON)
if(!is_glutton && to_eat.junkiness && satiety < -150 && nutrition > NUTRITION_LEVEL_STARVING + 50)
to_chat(src, "<span class='notice'>You don't feel like eating any more junk food at the moment.</span>")
return FALSE
@@ -1243,7 +1244,8 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, list(/obj/machinery/atmospherics/unary/ven
else if(fullness > (600 * (1 + overeatduration / 2000))) // The more you eat - the more you can eat
to_chat(src, "<span class='warning'>You cannot force any more of [to_eat] to go down your throat.</span>")
return FALSE
if(is_glutton)
src.changeNext_move(CLICK_CD_RAPID) // Hungry hungry spessman
to_chat(src, "<span class='notice'>[jointext(reaction_msg, " ")]</span>")
return TRUE
@@ -108,6 +108,10 @@
/// Lazylist of sources to track what our alpha should be, alpha is set to the minimum. Use the `set_alpha_tracking` and `get_alpha` helpers.
var/list/alpha_sources
/// List of quirk datums attached to the mob
var/list/quirks = list()
/// The cooldown for jumping into a closet or crate
COOLDOWN_DECLARE(skittish_cooldown)
/mob/living/carbon/human/fake
flags = ABSTRACT
@@ -487,7 +487,7 @@
to_chat(user, "You need at least one hand in good working order to snap your fingers.")
return TRUE
if(prob(5))
if(prob(5) && !HAS_TRAIT(user, TRAIT_COOL))
user.visible_message("<span class='danger'><b>[user]</b> snaps [user.p_their()] fingers right off!</span>")
playsound(user.loc, 'sound/effects/snap.ogg', 50, 1)
return TRUE
@@ -67,6 +67,7 @@
. = ..()
SSmobs.cubemonkeys -= src
QDEL_LIST_CONTENTS(bodyparts)
QDEL_LIST_CONTENTS(quirks)
splinted_limbs.Cut()
QDEL_NULL(physiology)
GLOB.human_list -= src
@@ -316,6 +317,9 @@
valid_limbs = list("l_hand", "l_foot", "r_hand", "r_foot")
limb_loss_chance = 25
if(HAS_TRAIT(src, TRAIT_FRAIL))
limb_loss_chance *= 2
//attempt to dismember bodyparts
for(var/X in valid_limbs)
var/obj/item/organ/external/BP = get_organ(X)
@@ -1235,10 +1239,8 @@
kept_items[I] = thing
item_flags[I] = I.flags
I.flags = 0 // Temporary set the flags to 0
if(!transformation) //Distinguish between creating a mob and switching species
dna.species.on_species_gain(src)
var/list/missing_bodyparts = list() // should line up here to pop out only what's missing
if(keep_missing_bodyparts)
for(var/organ_name as anything in bodyparts_by_name)
@@ -226,6 +226,8 @@ GLOBAL_LIST_INIT(soapy_words, list(
R.talk_into(src, message_pieces, null, verb)
if("whisper")
if(HAS_TRAIT(src, TRAIT_NO_WHISPERING))
return FALSE
whisper_say(message_pieces)
return 1
else
@@ -3,6 +3,8 @@
VV_DROPDOWN_OPTION(VV_HK_MAKE_SKELETON, "Make 2spooky")
VV_DROPDOWN_OPTION(VV_HK_HALLUCINATE, "Hallucinate")
VV_DROPDOWN_OPTION(VV_HK_ADDQUIRK, "Add Quirk")
VV_DROPDOWN_OPTION(VV_HK_REMQUIRK, "Remove Quirk")
/mob/living/carbon/human/vv_do_topic(list/href_list)
. = ..()
@@ -33,3 +35,29 @@
message_admins("[key_name(usr)] has given [key_name(src)] the [haltype] hallucination")
log_admin("[key_name_admin(usr)] has given [key_name_admin(src)] the [haltype] hallucination")
href_list["datumrefresh"] = UID()
else if(href_list[VV_HK_ADDQUIRK])
if(!check_rights(R_SPAWN))
return
if(QDELETED(src))
to_chat(usr, "<span class='notice'>Mob doesn't exist anymore.</span>")
return
var/quirk_name = tgui_input_list(usr, "What quirk do you want to add to [src]?", "Quirk to add", GLOB.quirk_paths)
if(!quirk_name)
return
var/datum/quirk/chosen_quirk = GLOB.quirk_paths[quirk_name]
var/datum/quirk/to_add = new chosen_quirk.type // Don't want hard refs to the global list
log_admin("[key_name_admin(usr)] has given [key_name_admin(src)] the [to_add] quirk.")
to_add.apply_quirk_effects(src)
else if(href_list[VV_HK_REMQUIRK])
if(!check_rights(R_SPAWN))
return
if(QDELETED(src))
to_chat(usr, "<span class='notice'>Mob doesn't exist anymore.</span>")
return
var/datum/quirk/to_remove = tgui_input_list(usr, "What quirk do you want to remove from [src]?", "Quirk to remove", src.quirks)
if(!to_remove)
return
log_admin("[key_name_admin(usr)] has removed the [to_remove] quirk from [key_name_admin(src)].")
qdel(to_remove)
@@ -43,6 +43,8 @@
var/hunger_mod = 1
/// Bonus damage added to melee attacks. NOTE: this is additive rather than multiplicative, trying to multiply this will break things.
var/melee_bonus = 0
/// % drunkenness modifier
var/alcohol_mod = 1
/datum/physiology/New()
@@ -258,7 +258,6 @@
LAZYREINITLIST(H.bodyparts)
LAZYREINITLIST(H.bodyparts_by_name)
LAZYREINITLIST(H.internal_organs)
for(var/limb_name in has_limbs)
if(bodyparts_to_omit && (limb_name in bodyparts_to_omit))
H.bodyparts_by_name[limb_name] = null // Null it out, but leave the name here so it's still "there"
@@ -384,7 +383,7 @@
var/hungry = (500 - H.nutrition) / 5 // So overeat would be 100 and default level would be 80
if((hungry >= 70) && !flight)
. += hungry/50
if(HAS_TRAIT(H, TRAIT_FAT))
if(HAS_TRAIT(H, TRAIT_FAT) && !HAS_TRAIT(H, TRAIT_GLUTTON))
. += (1.5 - flight)
if(H.bodytemperature < H.dna.species.cold_level_1 && !HAS_TRAIT(H, TRAIT_RESISTCOLD))
+3 -1
View File
@@ -320,7 +320,9 @@ GLOBAL_LIST_EMPTY(channel_to_radio_key)
/mob/living/whisper(message as text)
message = trim_strip_html_tags(message)
if(HAS_TRAIT(src, TRAIT_NO_WHISPERING) && !cannot_speak_loudly()) //If you're whispering cause you're out of breath, no blabbermouth will help with that
say(message)
return TRUE
//parse the language code and consume it
var/list/message_pieces = parse_languages(message)
if(istype(message_pieces, /datum/multilingual_say_piece)) // Little quirk to just easily deal with HIVEMIND languages
+2 -2
View File
@@ -166,7 +166,7 @@
borg.visible_message("<span class='warning'><span class='name'>[user]</span> drops their hat!</span>",
"<span class='warning'>As you flip your hat falls off!</span>")
if(prob(5) && ishuman(user))
if(prob(5) && ishuman(user) && !HAS_TRAIT(user, TRAIT_COOL))
var/turf = get_turf(L)
message = "attempts a flip and [isspaceturf(turf) ? "loses balance" : "crashes to the floor"]!"
if(istype(L))
@@ -190,7 +190,7 @@
if(!.)
return FALSE
if(prob(95) || isobserver(user) || !ishuman(user))
if(prob(95) || isobserver(user) || !ishuman(user) || HAS_TRAIT(user, TRAIT_COOL))
user.spin(20, 1)
return TRUE
+4 -1
View File
@@ -323,6 +323,9 @@
if(thisjob.barred_by_disability(client))
to_chat(src, alert("[rank] is not available due to your character's disability. Please try another."))
return 0
if(thisjob.barred_by_quirk(client))
to_chat(src, alert("[rank] is not available due to your character's quirk. Please try another."))
return 0
if(thisjob.barred_by_missing_limbs(client))
to_chat(src, alert("[rank] is not available due to your character having amputated limbs without a prosthetic replacement. Please try another."))
return 0
@@ -485,7 +488,7 @@
"Supply" = list(jobs = list(), titles = GLOB.supply_positions, color = "#ead4ae"),
)
for(var/datum/job/job in SSjobs.occupations)
if(job && IsJobAvailable(job.title) && !job.barred_by_disability(client) && !job.barred_by_missing_limbs(client))
if(job && IsJobAvailable(job.title) && !job.barred_by_disability(client) && !job.barred_by_missing_limbs(client) && !job.barred_by_quirk(client))
num_jobs_available++
activePlayers[job] = 0
var/categorized = 0