mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-22 04:30:44 +01:00
Merge branch 'master' of https://github.com/tgstation/tgstation into upstream-sync
This commit is contained in:
@@ -485,6 +485,15 @@
|
||||
default = 6
|
||||
min_val = -1
|
||||
|
||||
/// Freebie quirk points. Can't go negative because we have no way of enforcing a person has a quirk before they join.
|
||||
/datum/config_entry/number/default_quirk_points
|
||||
default = 2
|
||||
min_val = 0
|
||||
|
||||
/// Max personalities you can have at once
|
||||
/datum/config_entry/number/max_personalities
|
||||
default = 5
|
||||
|
||||
/**
|
||||
* A config that skews with the random spawners weights
|
||||
* If the value is lower than 1, it'll tend to even out the odds
|
||||
|
||||
@@ -77,6 +77,8 @@
|
||||
var/minimum_required_age = 0
|
||||
/// Templates necessary for this ruleset to be executed
|
||||
VAR_PROTECTED/list/ruleset_lazy_templates
|
||||
/// Extra logging information can be set here, to be output into any admin messaging and dynamic logs.
|
||||
VAR_FINAL/log_data
|
||||
|
||||
/datum/dynamic_ruleset/New(list/dynamic_config)
|
||||
for(var/new_var in dynamic_config?[config_tag])
|
||||
@@ -220,6 +222,7 @@
|
||||
|
||||
// This is (mostly) redundant, buuuut the (potential) sleep above makes it iffy, so let's just be safe
|
||||
if(!can_be_selected())
|
||||
log_data = "Reason: Ruleset cannot be selected."
|
||||
return FALSE
|
||||
|
||||
var/max_candidates = get_antag_cap(population_size, max_antag_cap || min_antag_cap)
|
||||
@@ -227,6 +230,7 @@
|
||||
|
||||
var/list/selected_candidates = select_candidates(antag_candidates, max_candidates)
|
||||
if(length(selected_candidates) < min_candidates)
|
||||
log_data = "Reason: Not enough eligible candidates. Have: [length(selected_candidates)], Need: [min_candidates]"
|
||||
return FALSE
|
||||
|
||||
for(var/mob/candidate as anything in selected_candidates)
|
||||
|
||||
@@ -149,7 +149,7 @@ SUBSYSTEM_DEF(dynamic)
|
||||
for(var/datum/dynamic_ruleset/roundstart/ruleset in queued_rulesets)
|
||||
// NOTE: !! THIS CAN SLEEP !!
|
||||
if(!ruleset.prepare_execution( num_real_players, antag_candidates ))
|
||||
log_dynamic("Roundstart: Selected ruleset [ruleset.config_tag], but preparation failed!")
|
||||
log_dynamic("Roundstart: Selected ruleset [ruleset.config_tag], but preparation failed! [ruleset.log_data]")
|
||||
queued_rulesets -= ruleset
|
||||
qdel(ruleset)
|
||||
continue
|
||||
@@ -368,7 +368,7 @@ SUBSYSTEM_DEF(dynamic)
|
||||
|
||||
// NOTE: !! THIS CAN SLEEP !!
|
||||
if(!picked_ruleset.prepare_execution(player_count, picked_ruleset.collect_candidates()))
|
||||
log_dynamic("Midround ([range]): Selected ruleset [picked_ruleset.config_tag], but preparation failed!")
|
||||
log_dynamic("Midround ([range]): Selected ruleset [picked_ruleset.config_tag], but preparation failed! [picked_ruleset.log_data]")
|
||||
QDEL_LIST(rulesets_weighted)
|
||||
return FALSE
|
||||
// Run the thing
|
||||
@@ -430,8 +430,8 @@ SUBSYSTEM_DEF(dynamic)
|
||||
// NOTE: !! THIS CAN SLEEP !!
|
||||
if(!running.prepare_execution(get_active_player_count(afk_check = TRUE), running.collect_candidates()))
|
||||
if(alert_admins_on_fail)
|
||||
message_admins("Midround (forced): Forced ruleset [running.config_tag], but preparation failed!")
|
||||
log_dynamic("Midround (forced): Forced ruleset [running.config_tag], but preparation failed!")
|
||||
message_admins("Midround (forced): Forced ruleset [running.config_tag], but preparation failed! [running.log_data]")
|
||||
log_dynamic("Midround (forced): Forced ruleset [running.config_tag], but preparation failed! [running.log_data]")
|
||||
qdel(running)
|
||||
return FALSE
|
||||
|
||||
@@ -493,7 +493,7 @@ SUBSYSTEM_DEF(dynamic)
|
||||
return FALSE
|
||||
// NOTE: !! THIS CAN SLEEP !!
|
||||
if(!picked_ruleset.prepare_execution(player_count, list(latejoiner)))
|
||||
log_dynamic("Latejoin: Selected ruleset [picked_ruleset.name] for [key_name(latejoiner)], but preparation failed! Latejoin chance has increased.")
|
||||
log_dynamic("Latejoin: Selected ruleset [picked_ruleset.name] for [key_name(latejoiner)], but preparation failed! Latejoin chance has increased. [picked_ruleset.log_data]")
|
||||
QDEL_LIST(rulesets_weighted)
|
||||
failed_latejoins++
|
||||
return FALSE
|
||||
|
||||
@@ -407,6 +407,9 @@
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/blob/false_alarm()
|
||||
priority_announce("Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", ANNOUNCER_OUTBREAK5)
|
||||
|
||||
// Set status displays to biohazard alert even for false alarm
|
||||
send_status_display_biohazard_alert()
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/xenomorph
|
||||
name = "Alien Infestation"
|
||||
config_tag = "Xenomorph"
|
||||
|
||||
@@ -463,8 +463,9 @@ ADMIN_VERB(check_bomb_impacts, R_DEBUG, "Check Bomb Impact", "See what the effec
|
||||
throwingturf[1] = max_range - dist
|
||||
throwingturf[2] = epicenter
|
||||
throwingturf[3] = max_range
|
||||
throwingturf[4] = severity
|
||||
else
|
||||
explode.explosion_throw_details = list(max_range - dist, epicenter, max_range)
|
||||
explode.explosion_throw_details = list(max_range - dist, epicenter, max_range, severity)
|
||||
held_throwturf += explode
|
||||
|
||||
|
||||
@@ -756,19 +757,28 @@ ADMIN_VERB(check_bomb_impacts, R_DEBUG, "Check Bomb Impact", "See what the effec
|
||||
var/turf/explode = thing
|
||||
var/list/details = explode.explosion_throw_details
|
||||
explode.explosion_throw_details = null
|
||||
if (length(details) != 3)
|
||||
if (length(details) != 4)
|
||||
continue
|
||||
var/throw_range = details[1]
|
||||
var/turf/center = details[2]
|
||||
var/max_range = details[3]
|
||||
for(var/atom/movable/A in explode)
|
||||
if(QDELETED(A))
|
||||
var/severity = details[4]
|
||||
var/required_resist = 0
|
||||
switch(severity)
|
||||
if(EXPLODE_DEVASTATE) // The jump from "very strong" to "overpowering" is intentional, more stuff should be thrown by point-blank explosions
|
||||
required_resist = MOVE_FORCE_OVERPOWERING
|
||||
if(EXPLODE_HEAVY)
|
||||
required_resist = MOVE_FORCE_VERY_STRONG
|
||||
if(EXPLODE_LIGHT)
|
||||
required_resist = MOVE_FORCE_STRONG
|
||||
for(var/atom/movable/movable as anything in explode)
|
||||
if(QDELETED(movable))
|
||||
continue
|
||||
if(!A.anchored && A.move_resist != INFINITY)
|
||||
if(!movable.anchored && movable.move_resist < required_resist)
|
||||
// We want to have our distance matter, but we do want to bias to a lot of throw, for the vibe
|
||||
var/atom_throw_range = rand(throw_range, max_range) + max_range * 0.3
|
||||
var/turf/throw_at = get_ranged_target_turf_direct(A, center, atom_throw_range, 180) // Throw 180 degrees away from the explosion source
|
||||
A.throw_at(throw_at, atom_throw_range, EXPLOSION_THROW_SPEED, quickstart = FALSE)
|
||||
var/turf/throw_at = get_ranged_target_turf_direct(movable, center, atom_throw_range, 180) // Throw 180 degrees away from the explosion source
|
||||
movable.throw_at(throw_at, atom_throw_range, EXPLOSION_THROW_SPEED, quickstart = FALSE)
|
||||
cost_throwturf = MC_AVERAGE(cost_throwturf, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
|
||||
|
||||
currentpart = SSEXPLOSIONS_TURFS
|
||||
|
||||
@@ -31,7 +31,7 @@ SUBSYSTEM_DEF(job)
|
||||
var/list/prioritized_jobs = list()
|
||||
var/list/latejoin_trackers = list()
|
||||
|
||||
var/overflow_role = /datum/job/assistant
|
||||
var/datum/job/overflow_role = /datum/job/assistant
|
||||
|
||||
var/list/level_order = list(JP_HIGH, JP_MEDIUM, JP_LOW)
|
||||
|
||||
@@ -747,7 +747,12 @@ SUBSYSTEM_DEF(job)
|
||||
|
||||
/atom/proc/JoinPlayerHere(mob/joining_mob, buckle)
|
||||
// By default, just place the mob on the same turf as the marker or whatever.
|
||||
joining_mob.forceMove(get_turf(src))
|
||||
// Set joining_mob as the new mob so subtypes can use it as a proper mob.
|
||||
if(ispath(joining_mob))
|
||||
joining_mob = new joining_mob(get_turf(src))
|
||||
else
|
||||
joining_mob.forceMove(get_turf(src))
|
||||
return joining_mob
|
||||
|
||||
/obj/structure/chair/JoinPlayerHere(mob/joining_mob, buckle)
|
||||
. = ..()
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
PROCESSING_SUBSYSTEM_DEF(personalities)
|
||||
name = "Personalities"
|
||||
runlevels = RUNLEVEL_GAME
|
||||
flags = SS_BACKGROUND|SS_POST_FIRE_TIMING
|
||||
wait = 3 SECONDS
|
||||
|
||||
/// All personality singletons indexed by their type
|
||||
VAR_FINAL/list/datum/personality/personalities_by_type
|
||||
/// All personality singletons indexed by their savefile key
|
||||
VAR_FINAL/list/datum/personality/personalities_by_key
|
||||
/// Assoc list of personality group to list of personality typepaths in that group
|
||||
VAR_FINAL/list/incompatibilities_by_group
|
||||
/// For personalities which process, this tracks all mobs we need to process for
|
||||
VAR_FINAL/list/processing_personalities
|
||||
|
||||
/datum/controller/subsystem/processing/personalities/Initialize()
|
||||
init_personalities()
|
||||
return SS_INIT_SUCCESS
|
||||
|
||||
/// Initialized personality singletons
|
||||
/datum/controller/subsystem/processing/personalities/proc/init_personalities()
|
||||
personalities_by_type = list()
|
||||
personalities_by_key = list()
|
||||
incompatibilities_by_group = list()
|
||||
processing_personalities = list()
|
||||
for(var/datum/personality/personality_type as anything in subtypesof(/datum/personality))
|
||||
var/personality_key = personality_type::savefile_key
|
||||
if(isnull(personality_key))
|
||||
// Abstract personality, ignore
|
||||
continue
|
||||
if(personalities_by_key[personality_key])
|
||||
stack_trace("Personality save key collision! \
|
||||
key: [personality_key] - \
|
||||
new: [personality_type::name] - \
|
||||
old: [personalities_by_key[personality_key].name]")
|
||||
continue
|
||||
|
||||
var/datum/personality/personality = new personality_type()
|
||||
personalities_by_type[personality_type] = personality
|
||||
personalities_by_key[personality.savefile_key] = personality
|
||||
for(var/group in personality.groups)
|
||||
incompatibilities_by_group[group] ||= list()
|
||||
incompatibilities_by_group[group] += personality_type
|
||||
|
||||
/// Helper to check if the new personality type is incompatible with the passed list of personality types
|
||||
/datum/controller/subsystem/processing/personalities/proc/is_incompatible(list/personality_types, new_personality_type)
|
||||
if(!length(incompatibilities_by_group))
|
||||
stack_trace("Checking personality incompatibilities before the incompatibility list was initialized?")
|
||||
return FALSE
|
||||
if(length(personality_types))
|
||||
// No incompatibilities possible with no personalities
|
||||
return FALSE
|
||||
var/datum/personality/new_personality = personalities_by_type[new_personality_type]
|
||||
if(!length(new_personality.groups))
|
||||
// No groups, so no incompatibilities
|
||||
return FALSE
|
||||
|
||||
// Filters all incompatibily groups against the new personality's groups
|
||||
for(var/group, incompatibility_list in incompatibilities_by_group & new_personality.groups)
|
||||
// Then checks if any personality type in the list is also in the group
|
||||
if(length(incompatibility_list & personality_types))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/// Helper to select a random list of personalities, respecting incompatibilities. REturns a list of typepaths
|
||||
/datum/controller/subsystem/processing/personalities/proc/select_random_personalities(lower_end = 1, upper_end = CONFIG_GET(number/max_personalities))
|
||||
var/list/personality_pool = personalities_by_type.Copy()
|
||||
var/list/selected_personalities = list()
|
||||
var/num = rand(lower_end, upper_end)
|
||||
var/i = 1
|
||||
while(i <= num)
|
||||
if(!length(personality_pool))
|
||||
break
|
||||
var/picked_type = pick(personality_pool)
|
||||
if(is_incompatible(selected_personalities, picked_type))
|
||||
continue
|
||||
selected_personalities += picked_type
|
||||
personality_pool -= picked_type
|
||||
i += 1
|
||||
return selected_personalities
|
||||
@@ -8,13 +8,11 @@ GLOBAL_LIST_INIT_TYPED(quirk_blacklist, /list/datum/quirk, list(
|
||||
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/apathetic, /datum/quirk/hypersensitive),
|
||||
list(/datum/quirk/jolly, /datum/quirk/depression, /datum/quirk/hypersensitive),
|
||||
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/bad_touch, /datum/quirk/friendly),
|
||||
list(/datum/quirk/extrovert, /datum/quirk/introvert),
|
||||
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),
|
||||
@@ -140,7 +138,7 @@ PROCESSING_SUBSYSTEM_DEF(quirks)
|
||||
*Randomises the quirks for a specified mob
|
||||
*/
|
||||
/datum/controller/subsystem/processing/quirks/proc/randomise_quirks(mob/living/user)
|
||||
var/bonus_quirks = max((length(user.quirks) + rand(-RANDOM_QUIRK_BONUS, RANDOM_QUIRK_BONUS)), MINIMUM_RANDOM_QUIRKS)
|
||||
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
|
||||
@@ -214,7 +212,7 @@ PROCESSING_SUBSYSTEM_DEF(quirks)
|
||||
var/list/positive_quirks = list()
|
||||
var/points_enabled = !CONFIG_GET(flag/disable_quirk_points)
|
||||
var/max_positive_quirks = CONFIG_GET(number/max_positive_quirks)
|
||||
var/balance = 0
|
||||
var/balance = -CONFIG_GET(number/default_quirk_points)
|
||||
|
||||
var/list/all_quirks = get_quirks()
|
||||
|
||||
|
||||
@@ -589,10 +589,15 @@ SUBSYSTEM_DEF(ticker)
|
||||
var/acting_captain = !is_captain_job(player_assigned_role)
|
||||
SSjob.promote_to_captain(new_player_living, acting_captain)
|
||||
OnRoundstart(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(minor_announce), player_assigned_role.get_captaincy_announcement(new_player_living)))
|
||||
if((player_assigned_role.job_flags & JOB_ASSIGN_QUIRKS) && ishuman(new_player_living) && CONFIG_GET(flag/roundstart_traits))
|
||||
if(new_player_mob.client?.prefs?.should_be_random_hardcore(player_assigned_role, new_player_living.mind))
|
||||
new_player_mob.client.prefs.hardcore_random_setup(new_player_living)
|
||||
SSquirks.AssignQuirks(new_player_living, new_player_mob.client)
|
||||
if(ishuman(new_player_living))
|
||||
if(player_assigned_role.job_flags & JOB_ASSIGN_QUIRKS)
|
||||
if(CONFIG_GET(flag/roundstart_traits))
|
||||
if(new_player_mob.client?.prefs?.should_be_random_hardcore(player_assigned_role, new_player_living.mind))
|
||||
new_player_mob.client.prefs.hardcore_random_setup(new_player_living)
|
||||
SSquirks.AssignQuirks(new_player_living, new_player_mob.client)
|
||||
else // clear any personalities the prefs added since our job clearly does not want them
|
||||
new_player_living.clear_personalities()
|
||||
|
||||
if(ishuman(new_player_living))
|
||||
SEND_SIGNAL(new_player_living, COMSIG_HUMAN_CHARACTER_SETUP_FINISHED)
|
||||
CHECK_TICK
|
||||
|
||||
Reference in New Issue
Block a user