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-04 00:18:52 +00:00
committed by GitHub
co-authored by Luc Burzah warriorstar-orion
parent 99d57fd35d
commit d558a69583
49 changed files with 971 additions and 78 deletions
+1
View File
@@ -135,6 +135,7 @@
var/mob/living/carbon/human/new_character = new(pick(GLOB.latejoin))
G.client.prefs.active_character.copy_to(new_character)
new_character.key = G.key
new_character.clear_quirks()
return new_character
/datum/game_mode/wizard/raginmages/declare_completion()
+2
View File
@@ -33,6 +33,8 @@
for(var/datum/mind/wiz in pre_wizards)
wiz.add_antag_datum(/datum/antagonist/wizard)
wiz.current.forceMove(pick(GLOB.wizardstart))
var/mob/living/carbon/human/human_wizard = wiz.current // Honestly if the wizard isn't a human then someone else has gone horribly wrong
human_wizard.clear_quirks()
pre_wizards.Cut()
..()
+31 -17
View File
@@ -130,6 +130,13 @@
return TRUE
return FALSE
/datum/job/proc/barred_by_quirk(client/C)
if(!C || !length(blacklisted_disabilities)) // If there's no disability locks, there won't be a quirk lock either.
return FALSE
for(var/datum/quirk/quirk in C.prefs.active_character.quirks)
if(quirk.blacklisted)
return TRUE
return FALSE
/// Returns true if the character has amputated limbs when their selected job doesn't allow it
/datum/job/proc/barred_by_missing_limbs(client/C)
if(!C || missing_limbs_allowed)
@@ -234,24 +241,31 @@
H.sec_hud_set_ID()
imprint_pda(H)
var/list/leftover_items = list()
for(var/datum/quirk/quirk as anything in H.quirks)
if(quirk.item_to_give)
var/obj/item/new_item = new quirk.item_to_give
leftover_items += new_item
if(length(gear_leftovers))
for(var/datum/gear/G in gear_leftovers)
var/atom/placed_in = H.equip_or_collect(G.spawn_item(null, H.client.prefs.active_character.get_gear_metadata(G)))
if(istype(placed_in))
if(isturf(placed_in))
to_chat(H, "<span class='notice'>Placing [G.display_name] on [placed_in]!</span>")
else
to_chat(H, "<span class='notice'>Placing [G.display_name] in your [placed_in.name].</span>")
continue
if(H.equip_to_appropriate_slot(G))
to_chat(H, "<span class='notice'>Placing [G.display_name] in your inventory!</span>")
continue
if(H.put_in_hands(G))
to_chat(H, "<span class='notice'>Placing [G.display_name] in your hands!</span>")
continue
to_chat(H, "<span class='danger'>Failed to locate a storage object on your mob, either you spawned with no hands free and no backpack or this is a bug.</span>")
qdel(G)
for(var/datum/gear/G in gear_leftovers)
leftover_items += G.spawn_item(null, H.client.prefs.active_character.get_gear_metadata(G))
for(var/obj/item/item in leftover_items)
var/atom/placed_in = H.equip_or_collect(item)
if(istype(placed_in))
if(isturf(placed_in))
to_chat(H, "<span class='notice'>Placing [item] on [placed_in]!</span>")
else
to_chat(H, "<span class='notice'>Placing [item] in your [placed_in.name].</span>")
continue
if(H.equip_to_appropriate_slot(item))
to_chat(H, "<span class='notice'>Placing [item] in your inventory!</span>")
continue
if(H.put_in_hands(item))
to_chat(H, "<span class='notice'>Placing [item] in your hands!</span>")
continue
to_chat(H, "<span class='danger'>Failed to locate a storage object on your mob, either you spawned with no hands free and no backpack or this is a bug.</span>")
qdel(item)
gear_leftovers.Cut()
+3 -1
View File
@@ -353,7 +353,9 @@
organ.damage = desired_data.organs[candidate_for_insertion][1]
organ.status = desired_data.organs[candidate_for_insertion][2]
for(var/datum/quirk/quirk as anything in patient_data.quirks)
quirk.apply_quirk_effects(clone)
clone.updatehealth("droplimb")
clone.regenerate_icons()
+3
View File
@@ -15,6 +15,8 @@
/// The patient's DNA
var/datum/dna/genetic_info
/// What quirks the patient has
var/list/quirks = list()
//The cloning scanner itself.
/obj/machinery/clonescanner
@@ -125,6 +127,7 @@
scan_result.name = scanned.dna.real_name
scan_result.mindUID = scanned.mind.UID()
scan_result.genetic_info = scanned.dna.Clone()
scan_result.quirks = scanned.quirks.Copy()
for(var/limb in scanned.dna.species.has_limbs)
if(scanned.bodyparts_by_name[limb])
+1 -1
View File
@@ -58,7 +58,7 @@
/obj/item/lighter/proc/attempt_light(mob/living/user)
if(prob(75) || issilicon(user)) // Robots can never burn themselves trying to light it.
to_chat(user, "<span class='notice'>You light [src].</span>")
else if(HAS_TRAIT(user, TRAIT_BADASS))
else if(HAS_TRAIT(user, TRAIT_BADASS) || HAS_TRAIT(user, TRAIT_COOL))
to_chat(user, "<span class='notice'>[src]'s flames lick your hand as you light it, but you don't flinch.</span>")
else
var/mob/living/carbon/human/H = user
+1 -1
View File
@@ -86,7 +86,7 @@
/obj/structure/holohoop/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
if(isitem(AM) && !isprojectile(AM))
var/atom/movable/thrower = throwingdatum?.get_thrower()
if(prob(50) || HAS_TRAIT(thrower, TRAIT_BADASS))
if(prob(50) || HAS_TRAIT(thrower, TRAIT_BADASS) || HAS_TRAIT(thrower, TRAIT_COOL))
AM.forceMove(get_turf(src))
visible_message("<span class='notice'>Swish! [AM] lands in [src].</span>")
else
+3 -3
View File
@@ -83,14 +83,14 @@
if(!isturf(loc))
return FALSE
var/freerunner_multiplier = HAS_TRAIT(user, TRAIT_FREERUNNER) ? 0.8 : 1
if(HAS_MIND_TRAIT(user, TRAIT_TABLE_LEAP))
user.visible_message("<span class='warning'>[user] gets ready to vault up onto [src]!</span>")
if(!do_after(user, 0.5 SECONDS, target = src))
if(!do_after(user, 0.5 SECONDS * freerunner_multiplier, target = src))
return FALSE
else
user.visible_message("<span class='warning'>[user] starts climbing onto [src]!</span>")
if(!do_after(user, 5 SECONDS, target = src))
if(!do_after(user, 5 SECONDS * freerunner_multiplier, target = src))
return FALSE
if(!can_touch(user) || !climbable)
@@ -172,6 +172,26 @@
return TRUE
return (!density)
/obj/structure/closet/Bumped(atom/movable/AM)
..()
if(!iscarbon(AM))
return
var/mob/living/carbon/human/user = AM
if(!HAS_TRAIT(user, TRAIT_SKITTISH))
return
if(user.m_intent != MOVE_INTENT_RUN)
return
if(!COOLDOWN_FINISHED(user, skittish_cooldown))
to_chat(user, "<span class='notice'>Wait a few seconds to do that again.</span>")
return
if(locked && !allowed(user))
return
locked = FALSE
if(opened || open())
user.forceMove(src)
close()
COOLDOWN_START(user, skittish_cooldown, 2 SECONDS)
/obj/structure/closet/proc/can_open()
if(welded)
return FALSE
@@ -47,7 +47,8 @@
if(L.electrocute_act(17, src))
do_sparks(5, 1, src)
return 2
if(climbable)
structure_shaken()
playsound(loc, open_sound, open_sound_volume, TRUE, -3)
for(var/obj/O in src) //Objects
O.forceMove(loc)
@@ -56,9 +57,6 @@
icon_state = icon_opened
opened = TRUE
if(climbable)
structure_shaken()
return TRUE
/obj/structure/closet/crate/close()
@@ -74,9 +72,9 @@
break
if(O.density || O.anchored || istype(O,/obj/structure/closet))
continue
if(ismob(O) && !HAS_TRAIT(O, TRAIT_CONTORTED_BODY))
if(ismob(O) && !(HAS_TRAIT(O, TRAIT_CONTORTED_BODY) || HAS_TRAIT(O, TRAIT_SKITTISH)))
continue
if(O.has_buckled_mobs()) // You can't put mobs into crates, so naturally if a mob is attached to something, it shouldn't be able to go in the crate
if(O.has_buckled_mobs()) // You can't put (most) mobs into crates, so naturally if a mob is attached to something, it shouldn't be able to go in the crate
continue
O.forceMove(src)
itemcount++
@@ -216,6 +214,9 @@
if(broken)
to_chat(user, "<span class='warning'>The crate appears to be broken.</span>")
return FALSE
if(user.loc == src)
to_chat(user, "<span class='notice'>You can't reach the lock from inside.</span>")
return FALSE
if(allowed(user))
locked = !locked
visible_message("<span class='notice'>The crate has been [locked ? null : "un"]locked by [user].</span>")