mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 21:18:37 +01:00
## About The Pull Request The goal of this PR is twofold: 1. Remove hemophages as a species. 2. Allow anyone to be a hemophage through the use of a quirk. Currently, hemophages are somewhat limited in what they can look like bodyshape wise due to being tied to a species, yet almost all of their abilities and traits are tied to organs. To-Do: - [x] Properly implement the removal of the organs when the quirk gets removed. - [x] Test the quirk with the other hemophage specific quirks, possibly work them into toggles with this quirk. ## Why It's Good For The Game This helps shorten our list of playable species while keeping the core aspects of hemophage gameplay able to be done. It also increases customization potential, yippee. ## Proof Of Testing See below. <details> <summary>Screenshots/Videos</summary> <img width="1917" height="1004" alt="image" src="https://github.com/user-attachments/assets/f2b6cb97-1425-4888-a9c4-4a7ed30d74bf" /> <img width="619" height="154" alt="image" src="https://github.com/user-attachments/assets/de0c21f9-bca5-4171-8fc9-d6d28b7e3ea0" /> </details> ## Changelog 🆑 del: Removed the hemphage specific quirks Masquerade, Sol Weakness, and Pseudo-Respiration. They are now toggles on the hemophage quirk. refactor: Refactored the hemophage species into being a quirk: Hemophagia. /🆑 --------- Co-authored-by: Arturlang <24881678+Arturlang@users.noreply.github.com>
285 lines
11 KiB
Plaintext
285 lines
11 KiB
Plaintext
#define EXP_ASSIGN_WAYFINDER 1200
|
|
#define RANDOM_QUIRK_BONUS 3
|
|
#define MINIMUM_RANDOM_QUIRKS 3
|
|
|
|
// Shifted to glob so they are generated at world start instead of risking players doing preference stuff before the subsystem inits
|
|
GLOBAL_LIST_INIT_TYPED(quirk_blacklist, /list/datum/quirk, list(
|
|
list(/datum/quirk/item_quirk/blindness, /datum/quirk/item_quirk/nearsighted),
|
|
list(/datum/quirk/item_quirk/blindness, /datum/quirk/item_quirk/scarred_eye),
|
|
list(/datum/quirk/item_quirk/blindness, /datum/quirk/item_quirk/fluoride_stare),
|
|
list(/datum/quirk/item_quirk/blindness, /datum/quirk/touchy),
|
|
//list(/datum/quirk/jolly, /datum/quirk/depression, /datum/quirk/hypersensitive),
|
|
list(/datum/quirk/jolly, /datum/quirk/depression), // BUBBER EDIT ADD - no mood swings allowed
|
|
list(/datum/quirk/jolly, /datum/quirk/hypersensitive), // BUBBER EDIT ADD - we don't want players to be happy
|
|
list(/datum/quirk/no_taste, /datum/quirk/vegetarian, /datum/quirk/deviant_tastes, /datum/quirk/gamer),
|
|
list(/datum/quirk/pineapple_liker, /datum/quirk/pineapple_hater, /datum/quirk/gamer),
|
|
list(/datum/quirk/alcohol_tolerance, /datum/quirk/light_drinker),
|
|
list(/datum/quirk/item_quirk/clown_enjoyer, /datum/quirk/item_quirk/mime_fan),
|
|
list(/datum/quirk/prosthetic_limb, /datum/quirk/quadruple_amputee, /datum/quirk/body_purist),
|
|
list(/datum/quirk/transhumanist, /datum/quirk/body_purist),
|
|
list(/datum/quirk/prosthetic_organ, /datum/quirk/tin_man, /datum/quirk/body_purist),
|
|
list(/datum/quirk/quadruple_amputee, /datum/quirk/paraplegic, /datum/quirk/hemiplegic, /datum/quirk/permanent_limp), //BUBBER EDIT - Add Permanent Limp to this list.
|
|
//list(/datum/quirk/quadruple_amputee, /datum/quirk/frail), // SKYRAT EDIT REMOVAL- Since we have synth wounds now, frail has a large downside for prosthetics and such
|
|
list(/datum/quirk/social_anxiety, /datum/quirk/mute),
|
|
list(/datum/quirk/mute, /datum/quirk/softspoken),
|
|
//list(/datum/quirk/bilingual, /datum/quirk/foreigner, /datum/quirk/csl),
|
|
list(/datum/quirk/bilingual, /datum/quirk/foreigner), //BUBBER EDIT ADD
|
|
//BUBBER EDIT (item_quirk)
|
|
list(/datum/quirk/spacer_born, /datum/quirk/item_quirk/settler),
|
|
list(/datum/quirk/photophobia, /datum/quirk/nyctophobia),
|
|
//BUBBER EDIT (item_quirk)
|
|
list(/datum/quirk/item_quirk/settler, /datum/quirk/freerunning),
|
|
list(/datum/quirk/numb, /datum/quirk/selfaware),
|
|
list(/datum/quirk/empath, /datum/quirk/evil),
|
|
list(/datum/quirk/keen_nose, /datum/quirk/item_quirk/anosmia),
|
|
// BUBBER EDIT - ADDITION - START
|
|
list(/datum/quirk/equipping/nerve_staple, /datum/quirk/nonviolent),
|
|
list(/datum/quirk/equipping/nerve_staple, /datum/quirk/item_quirk/nearsighted),
|
|
list(/datum/quirk/no_guns, /datum/quirk/poor_aim),
|
|
list(/datum/quirk/no_guns, /datum/quirk/nonviolent),
|
|
list(/datum/quirk/spacer_born, /datum/quirk/oversized),
|
|
list(/datum/quirk/felinid_aspect, /datum/quirk/item_quirk/canine, /datum/quirk/item_quirk/avian),
|
|
list(/datum/quirk/all_nighter, /datum/quirk/heavy_sleeper),
|
|
list(/datum/quirk/light_drinker, /datum/quirk/drunkhealing),
|
|
list(/datum/quirk/oversized, /datum/quirk/freerunning),
|
|
list(/datum/quirk/echolocation, /datum/quirk/item_quirk/blindness, /datum/quirk/item_quirk/nearsighted, /datum/quirk/item_quirk/deafness),
|
|
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),
|
|
list(/datum/quirk/unblinking, /datum/quirk/item_quirk/fluoride_stare),
|
|
list(/datum/quirk/micro, /datum/quirk/micro/smaller, /datum/quirk/micro/smallest, /datum/quirk/oversized),
|
|
list(/datum/quirk/psionic_dampener, /datum/quirk/telepathic),
|
|
list(/datum/quirk/hemophage, /datum/quirk/prosthetic_organ, /datum/quirk/tin_man)
|
|
// BUBBER EDIT - ADDITION - END
|
|
))
|
|
|
|
GLOBAL_LIST_INIT(quirk_string_blacklist, generate_quirk_string_blacklist())
|
|
|
|
/proc/generate_quirk_string_blacklist()
|
|
var/list/string_blacklist = list()
|
|
for(var/blacklist in GLOB.quirk_blacklist)
|
|
var/list/string_list = list()
|
|
for(var/datum/quirk/typepath as anything in blacklist)
|
|
string_list += initial(typepath.name)
|
|
string_blacklist += list(string_list)
|
|
return string_blacklist
|
|
|
|
//Used to process and handle roundstart quirks
|
|
// - Quirk strings are used for faster checking in code
|
|
// - Quirk datums are stored and hold different effects, as well as being a vector for applying trait string
|
|
PROCESSING_SUBSYSTEM_DEF(quirks)
|
|
name = "Quirks"
|
|
ss_flags = SS_BACKGROUND
|
|
runlevels = RUNLEVEL_GAME
|
|
wait = 1 SECONDS
|
|
|
|
var/list/quirks = list() //Assoc. list of all roundstart quirk datum types; "name" = /path/
|
|
var/list/datum/quirk/quirk_prototypes = list()
|
|
var/list/quirk_points = list() //Assoc. list of quirk names and their "point cost"; positive numbers are good traits, and negative ones are bad
|
|
///An assoc list of quirks that can be obtained as a hardcore character, and their hardcore value.
|
|
var/list/hardcore_quirks = list()
|
|
/// Whether or not quirk points are enabled, per server config
|
|
var/points_enabled
|
|
/// The number of max positive quirks that we allow, per server config
|
|
var/max_positive_quirks
|
|
// The default number of quirk points that you get to spend, per server config
|
|
var/default_quirk_points
|
|
|
|
/datum/controller/subsystem/processing/quirks/Initialize()
|
|
points_enabled = !CONFIG_GET(flag/disable_quirk_points)
|
|
max_positive_quirks = CONFIG_GET(number/max_positive_quirks)
|
|
default_quirk_points = CONFIG_GET(number/default_quirk_points)
|
|
get_quirks()
|
|
return SS_INIT_SUCCESS
|
|
|
|
/// Returns the list of possible quirks
|
|
/datum/controller/subsystem/processing/quirks/proc/get_quirks()
|
|
RETURN_TYPE(/list)
|
|
if (!quirks.len)
|
|
SetupQuirks()
|
|
|
|
return quirks
|
|
|
|
/datum/controller/subsystem/processing/quirks/proc/SetupQuirks()
|
|
// Sort by Positive, Negative, Neutral; and then by name
|
|
var/list/quirk_list = sort_list(valid_subtypesof(/datum/quirk), GLOBAL_PROC_REF(cmp_quirk_asc))
|
|
|
|
for(var/type in quirk_list)
|
|
var/datum/quirk/quirk_type = type
|
|
// SKYRAT EDIT ADDITION START
|
|
|
|
if(initial(quirk_type.erp_quirk) && CONFIG_GET(flag/disable_erp_preferences))
|
|
continue
|
|
// Hidden quirks aren't visible to TGUI or the player
|
|
#if !defined(UNIT_TESTS)
|
|
if (initial(quirk_type.hidden_quirk))
|
|
continue
|
|
#endif
|
|
// SKYRAT EDIT ADDITION END
|
|
|
|
quirk_prototypes[type] = new type
|
|
quirks[initial(quirk_type.name)] = quirk_type
|
|
quirk_points[initial(quirk_type.name)] = initial(quirk_type.value)
|
|
|
|
var/hardcore_value = initial(quirk_type.hardcore_value)
|
|
|
|
if(!hardcore_value)
|
|
continue
|
|
hardcore_quirks[quirk_type] += hardcore_value
|
|
|
|
/datum/controller/subsystem/processing/quirks/proc/AssignQuirks(mob/living/user, client/applied_client)
|
|
var/badquirk = FALSE
|
|
for(var/quirk_name in applied_client.prefs.all_quirks)
|
|
var/datum/quirk/quirk_type = quirks[quirk_name]
|
|
if(ispath(quirk_type))
|
|
if(user.add_quirk(quirk_type, override_client = applied_client, announce = FALSE))
|
|
SSblackbox.record_feedback("tally", "quirks_taken", 1, "[quirk_name]")
|
|
else
|
|
stack_trace("Invalid quirk \"[quirk_name]\" in client [applied_client.ckey] preferences")
|
|
applied_client.prefs.all_quirks -= quirk_name
|
|
badquirk = TRUE
|
|
if(badquirk)
|
|
applied_client.prefs.save_character()
|
|
|
|
/*
|
|
*Randomises the quirks for a specified mob
|
|
*/
|
|
/datum/controller/subsystem/processing/quirks/proc/randomise_quirks(mob/living/user)
|
|
var/bonus_quirks = max((LAZYLEN(user.quirks) + rand(-RANDOM_QUIRK_BONUS, RANDOM_QUIRK_BONUS)), MINIMUM_RANDOM_QUIRKS)
|
|
var/added_quirk_count = 0 //How many we've added
|
|
var/list/quirks_to_add = list() //Quirks we're adding
|
|
var/good_count = 0
|
|
var/score //What point score we're at
|
|
///Cached list of possible quirks
|
|
var/list/possible_quirks = quirks.Copy()
|
|
|
|
if(max_positive_quirks < 0)
|
|
max_positive_quirks = 6
|
|
|
|
//Create a random list of stuff to start with
|
|
while(bonus_quirks > added_quirk_count)
|
|
var/quirk = pick(possible_quirks) //quirk is a string
|
|
if(quirk in GLOB.quirk_blacklist) //prevent blacklisted
|
|
possible_quirks -= quirk
|
|
continue
|
|
if(quirk_points[quirk] > 0)
|
|
good_count++
|
|
score += quirk_points[quirk]
|
|
quirks_to_add += quirk
|
|
possible_quirks -= quirk
|
|
added_quirk_count++
|
|
|
|
//But lets make sure we're balanced
|
|
while(score > 0)
|
|
if(!length(possible_quirks))//Lets not get stuck
|
|
break
|
|
var/quirk = pick(quirks)
|
|
if(quirk in GLOB.quirk_blacklist) //prevent blacklisted
|
|
possible_quirks -= quirk
|
|
continue
|
|
if(!quirk_points[quirk] < 0)//negative only
|
|
possible_quirks -= quirk
|
|
continue
|
|
good_count++
|
|
score += quirk_points[quirk]
|
|
quirks_to_add += quirk
|
|
|
|
//And have benefits too
|
|
if(max_positive_quirks > 0)
|
|
while(score < 0 && good_count <= max_positive_quirks)
|
|
if(!length(possible_quirks))//Lets not get stuck
|
|
break
|
|
var/quirk = pick(quirks)
|
|
if(quirk in GLOB.quirk_blacklist) //prevent blacklisted
|
|
possible_quirks -= quirk
|
|
continue
|
|
if(!(quirk_points[quirk] > 0)) //positive only
|
|
possible_quirks -= quirk
|
|
continue
|
|
good_count++
|
|
score += quirk_points[quirk]
|
|
quirks_to_add += quirk
|
|
|
|
for(var/datum/quirk/quirk as anything in user.quirks)
|
|
if(quirk.name in quirks_to_add) //Don't delete ones we keep
|
|
quirks_to_add -= quirk.name //Already there, no need to add.
|
|
continue
|
|
user.remove_quirk(quirk.type) //these quirks are objects
|
|
|
|
for(var/datum/quirk/quirk as anything in quirks_to_add)
|
|
user.add_quirk(quirks[quirk]) //these are typepaths converted from string
|
|
|
|
/// Takes a list of quirk names and returns a new list of quirks that would
|
|
/// be valid.
|
|
/// If no changes need to be made, will return the same list.
|
|
/// Expects all quirk names to be unique, but makes no other expectations.
|
|
/datum/controller/subsystem/processing/quirks/proc/filter_invalid_quirks(list/quirks, list/augments) // SKYRAT EDIT - AUGMENTS+
|
|
var/list/new_quirks = list()
|
|
var/list/positive_quirks = list()
|
|
var/balance = -default_quirk_points
|
|
|
|
var/list/all_quirks = get_quirks()
|
|
|
|
// SKYRAT EDIT BEGIN - AUGMENTS+
|
|
for(var/key in augments)
|
|
var/datum/augment_item/aug = GLOB.augment_items[augments[key]]
|
|
balance += aug.cost
|
|
// SKYRAT EDIT END
|
|
for (var/quirk_name in quirks)
|
|
var/datum/quirk/quirk = all_quirks[quirk_name]
|
|
if (isnull(quirk))
|
|
continue
|
|
|
|
if ((initial(quirk.quirk_flags) & QUIRK_MOODLET_BASED) && CONFIG_GET(flag/disable_human_mood))
|
|
continue
|
|
|
|
var/blacklisted = FALSE
|
|
|
|
for (var/list/blacklist as anything in GLOB.quirk_blacklist)
|
|
if (!(quirk in blacklist))
|
|
continue
|
|
|
|
for (var/other_quirk in blacklist)
|
|
if (other_quirk in new_quirks)
|
|
blacklisted = TRUE
|
|
break
|
|
|
|
if (blacklisted)
|
|
break
|
|
|
|
if (blacklisted)
|
|
continue
|
|
|
|
var/value = initial(quirk.value)
|
|
if (value > 0)
|
|
if (max_positive_quirks >= 0 && positive_quirks.len == max_positive_quirks)
|
|
continue
|
|
|
|
positive_quirks[quirk_name] = value
|
|
|
|
balance += value
|
|
new_quirks += quirk_name
|
|
|
|
if (points_enabled && balance > 0)
|
|
var/balance_left_to_remove = balance
|
|
|
|
for (var/positive_quirk in positive_quirks)
|
|
var/value = positive_quirks[positive_quirk]
|
|
balance_left_to_remove -= value
|
|
new_quirks -= positive_quirk
|
|
|
|
if (balance_left_to_remove <= 0)
|
|
break
|
|
|
|
// It is guaranteed that if no quirks are invalid, you can simply check through `==`
|
|
if (new_quirks.len == quirks.len)
|
|
return quirks
|
|
|
|
return new_quirks
|
|
|
|
#undef EXP_ASSIGN_WAYFINDER
|
|
#undef RANDOM_QUIRK_BONUS
|
|
#undef MINIMUM_RANDOM_QUIRKS
|