diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm
index e09ebcb1..e24870cf 100644
--- a/code/__HELPERS/cmp.dm
+++ b/code/__HELPERS/cmp.dm
@@ -81,3 +81,21 @@ GLOBAL_VAR_INIT(cmp_field, "name")
/proc/cmp_advdisease_resistance_asc(datum/disease/advance/A, datum/disease/advance/B)
return A.totalResistance() - B.totalResistance()
+
+/proc/cmp_quirk_asc(datum/quirk/A, datum/quirk/B)
+ var/a_sign = num2sign(initial(A.value) * -1)
+ var/b_sign = num2sign(initial(B.value) * -1)
+
+ // Neutral traits go last
+ if(a_sign == 0)
+ a_sign = 2
+ if(b_sign == 0)
+ b_sign = 2
+
+ var/a_name = initial(A.name)
+ var/b_name = initial(B.name)
+
+ if(a_sign != b_sign)
+ return a_sign - b_sign
+ else
+ return sorttext(b_name, a_name)
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index c8ebfa1d..09fd94b6 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -1564,3 +1564,11 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
for(var/i in L)
if(condition.Invoke(i))
. |= i
+
+/proc/num2sign(numeric)
+ if(numeric > 0)
+ return 1
+ else if(numeric < 0)
+ return -1
+ else
+ return 0
diff --git a/code/controllers/subsystem/processing/quirks.dm b/code/controllers/subsystem/processing/quirks.dm
index 4af54b8c..d62edb23 100644
--- a/code/controllers/subsystem/processing/quirks.dm
+++ b/code/controllers/subsystem/processing/quirks.dm
@@ -19,7 +19,10 @@ PROCESSING_SUBSYSTEM_DEF(quirks)
return ..()
/datum/controller/subsystem/processing/quirks/proc/SetupQuirks()
- for(var/V in subtypesof(/datum/quirk))
+// Sort by Positive, Negative, Neutral; and then by name
+ var/list/quirk_list = sortList(subtypesof(/datum/quirk), /proc/cmp_quirk_asc)
+
+ for(var/V in quirk_list)
var/datum/quirk/T = V
quirks[initial(T.name)] = T
quirk_points[initial(T.name)] = initial(T.value)
diff --git a/code/datums/ruins/lavaland.dm b/code/datums/ruins/lavaland.dm
index c040ef21..0397f813 100644
--- a/code/datums/ruins/lavaland.dm
+++ b/code/datums/ruins/lavaland.dm
@@ -194,14 +194,6 @@
allow_duplicates = FALSE
cost = 10
-/datum/map_template/ruin/lavaland/duohermit
- name = "Makeshift Big Shelter"
- id = "duohermitcave"
- description = "A place of shelter for a couple of stranded hermits, scraping by to live another day."
- suffix = "lavaland_surface_duohermit.dmm"
- allow_duplicates = FALSE
- cost = 5
-
/datum/map_template/ruin/lavaland/hermit
name = "Makeshift Shelter"
id = "hermitcave"
diff --git a/code/datums/traits/good.dm b/code/datums/traits/good.dm
index a83ddb2d..74276f17 100644
--- a/code/datums/traits/good.dm
+++ b/code/datums/traits/good.dm
@@ -276,63 +276,3 @@
/datum/quirk/slimespeaker/remove()
var/mob/living/M = quirk_holder
M.remove_language(/datum/language/slime)
-
-/datum/quirk/narsianspeaker
- name = "Nar-Sian speaker"
- desc = "Obsessed with forbidden knowledge regarding the blood cult, you've learned how to speak their ancient language."
- value = 1
- gain_text = "Your mind feels sensitive to the slurred, ancient language of Nar'Sian cultists."
- lose_text = "You forget how to speak Nar'Sian!"
-
-/datum/quirk/narsianspeaker/add()
- var/mob/living/M = quirk_holder
- M.grant_language(/datum/language/narsie)
-
-/datum/quirk/narsianspeaker/remove()
- var/mob/living/M = quirk_holder
- M.remove_language(/datum/language/narsie)
-
-/datum/quirk/ratvarianspeaker
- name = "Ratvarian speaker"
- desc = "Obsessed with the inner workings of the clock cult, you've learned how to speak their language."
- value = 1
- gain_text = "Your mind feels sensitive to the ancient language of Ratvarian cultists."
- lose_text = "You forget how to speak Ratvarian!"
-
-/datum/quirk/ratvarianspeaker/add()
- var/mob/living/M = quirk_holder
- M.grant_language(/datum/language/ratvar)
-
-/datum/quirk/ratvarianspeaker/remove()
- var/mob/living/M = quirk_holder
- M.remove_language(/datum/language/ratvar)
-
-/datum/quirk/encodedspeaker
- name = "Encoded Audio speaker"
- desc = "You've been augmented with language encoders, allowing you to understand encoded audio."
- value = 1
- gain_text = "Your mouth feels a little weird for a moment as your language encoder kicks in."
- lose_text = "You feel your encoded audio chip malfunction. You can no longer speak or understand the language of fax machines."
-
-/datum/quirk/encodedspeaker/add()
- var/mob/living/M = quirk_holder
- M.grant_language(/datum/language/machine)
-
-/datum/quirk/encodedspeaker/remove()
- var/mob/living/M = quirk_holder
- M.remove_language(/datum/language/machine)
-
-/datum/quirk/xenospeaker
- name = "Xenocommon speaker"
- desc = "Through time observing and interacting with xenos and xeno hybrids, you've learned the intricate hissing patterns of their language."
- value = 1
- gain_text = "You feel that you are now able to hiss in the same way xenomorphs do."
- lose_text = "You seem to no longer know how to speak xenocommon."
-
-/datum/quirk/xenospeaker/add()
- var/mob/living/M = quirk_holder
- M.grant_language(/datum/language/xenocommon)
-
-/datum/quirk/xenospeaker/remove()
- var/mob/living/M = quirk_holder
- M.remove_language(/datum/language/xenocommon)
diff --git a/code/datums/traits/neutral.dm b/code/datums/traits/neutral.dm
index 84779190..61b54ca7 100644
--- a/code/datums/traits/neutral.dm
+++ b/code/datums/traits/neutral.dm
@@ -109,22 +109,3 @@
mob_trait = TRAIT_HEADPAT_SLUT
value = 0
medical_record_text = "Patient seems overly affectionate"
-
-//Skyrat port start
-/datum/quirk/alcohol_lightweight
- name = "Alcoholic Lightweight"
- desc = "Alcohol really goes straight to your head, gotta be careful with what you drink."
- value = 0
- mob_trait = TRAIT_ALCOHOL_LIGHTWEIGHT
- gain_text = "You feel woozy thinking of alcohol."
- lose_text = "You regain your stomach for drinks."
-//Skyrat port stop
-
-/datum/quirk/cursed_blood
- name = "Cursed Blood"
- desc = "Your lineage is cursed with the paleblood curse. Best to stay away from holy water... Hell water, on the other hand..."
- value = 0
- mob_trait = TRAIT_CURSED_BLOOD
- gain_text = "A curse from a land where men return as beasts runs deep in your blood. Best to stay away from holy water... Hell water, on the other hand..."
- lose_text = "You feel the weight of the curse in your blood finally gone."
- medical_record_text = "Patient suffers from an unknown type of aversion to holy reagents. Keep them away from a chaplain."
diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm
index 8f8bf16a..aef7a704 100644
--- a/code/game/gamemodes/dynamic/dynamic.dm
+++ b/code/game/gamemodes/dynamic/dynamic.dm
@@ -351,8 +351,8 @@ GLOBAL_VAR_INIT(dynamic_chaos_level, 1.5)
if (ruleset.weight)
midround_rules += ruleset
if ("Event")
- if(ruleset.weight)
- event_rules += ruleset
+ //if(ruleset.weight)
+ event_rules += ruleset
for(var/mob/dead/new_player/player in GLOB.player_list)
if(player.ready == PLAYER_READY_TO_PLAY && player.mind)
roundstart_pop_ready++
@@ -644,7 +644,7 @@ GLOBAL_VAR_INIT(dynamic_chaos_level, 1.5)
if (prob(get_injection_chance()))
var/list/drafted_rules = list()
for (var/datum/dynamic_ruleset/midround/rule in midround_rules)
- if (rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && threat >= rule.cost)
+ if (rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level))
// Classic secret : only autotraitor/minor roles
if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)))
continue
@@ -665,10 +665,10 @@ GLOBAL_VAR_INIT(dynamic_chaos_level, 1.5)
update_playercounts()
var/list/drafted_rules = list()
for (var/datum/dynamic_ruleset/event/rule in event_rules)
- if (rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && threat >= rule.cost)
+ if (rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level))
// Classic secret : only autotraitor/minor roles
- if (!GLOB.master_mode == "dynamic")
- continue
+ //if (!GLOB.master_mode == "dynamic")
+ //continue
if (world.time < rule.earliest_start)
continue
if(rule.occurances_current >= rule.occurances_max && rule.occurances_max)
@@ -676,8 +676,9 @@ GLOBAL_VAR_INIT(dynamic_chaos_level, 1.5)
rule.candidates = list()
rule.candidates = current_players.Copy()
rule.trim_candidates()
- if (rule.ready() && rule.candidates.len > 0)
- drafted_rules[rule] = rule.get_weight()
+ //if(rule.needs_players)
+ //if (rule.ready() && rule.candidates.len > 0)
+ drafted_rules[rule] = rule.get_weight()
if(drafted_rules.len > 0)
picking_midround_latejoin_rule(drafted_rules)
@@ -727,13 +728,14 @@ GLOBAL_VAR_INIT(dynamic_chaos_level, 1.5)
chance += 25-10*(max_pop_per_antag-current_pop_per_antag)
*/
//Hyper change - Base injection chance based on chaos.
- chance = (GLOB.dynamic_chaos_level * 10) //Base chance from 0 to 50
+ chance = (GLOB.dynamic_chaos_level * 12) //Base chance from 0 to 60
if (current_players[CURRENT_DEAD_PLAYERS].len > current_players[CURRENT_LIVING_PLAYERS].len)
chance -= 30 // More than half the crew died? ew, let's calm down on antags
- if (threat > 70)
- chance += 15
- if (threat < 30)
- chance -= 15
+ //if (threat > 70)
+ // chance += 15
+ //if (threat < 30)
+ // chance -= 15
+ chance += ((threat-40)*0.4) //threat influence injection chance more gradually
if (chance > 100) //I don't know what would happen if we returned a probability greater than 100%
return 100 //So I won't
return round(max(0,chance))
diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_events.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_events.dm
index d4028c43..ecefbb51 100644
--- a/code/game/gamemodes/dynamic/dynamic_rulesets_events.dm
+++ b/code/game/gamemodes/dynamic/dynamic_rulesets_events.dm
@@ -3,9 +3,10 @@
var/typepath // typepath of the event
var/controller //round event controller for the event - Required for certain events dependendant on variables within their controllers
var/triggering
- var/earliest_start = 20 MINUTES
+ var/earliest_start = 20 MINUTES
var/occurances_current = 0 //Don't touch this. Skyrat Change.
var/occurances_max = 0 //Maximum occurances for this event. Set to 0 to allow an infinite amount of this event. Skyrat change.
+ var/needs_players = FALSE //If an event needs players, living or ghosts, set to TRUE. Bypasses the trim_candidates otherwise
var/restrict_ghost_roles = TRUE
var/required_type = /mob/living/carbon/human
var/list/living_players = list()
@@ -26,7 +27,7 @@
if (M.mind && M.mind.assigned_role && (M.mind.assigned_role in enemy_roles) && (!(M in candidates) || (M.mind.assigned_role in restricted_roles)))
job_check++ // Checking for "enemies" (such as sec officers). To be counters, they must either not be candidates to that rule, or have a job that restricts them from it
- var/threat = round(mode.threat_level/10)
+ var/threat = max(min(round(mode.threat_level/10),9),1) //min() to stop index errors at 100 threat //Max to stop breaking at 0 threat.
if (job_check < required_enemies[threat])
return FALSE
return ..()
@@ -420,16 +421,22 @@
/datum/dynamic_ruleset/event/operative
name = "Lone Operative"
+ controller = /datum/round_event_control/operative
typepath = /datum/round_event/ghost_role/operative
+ required_enemies = list(0,0,0,0,0,0,0,0,0,0)
weight = 0 //This is changed in nuclearbomb.dm
occurances_max = 1
requirements = list(10,5,0,0,0,0,0,0,0,0) //SECURE THAT DISK
cost = 50
-/datum/dynamic_ruleset/event/operative/ready()
+/datum/dynamic_ruleset/event/operative/get_weight()
var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control
if(istype(loneop))
weight = loneop.weight //Get the weight whenever it's called.
+ to_chat(GLOB.admins, "Current LoneOP weight [weight]")
+ else
+ to_chat(GLOB.admins, "LoneOP is fucking broken.")
+ return weight
//////////////////////////////////////////////
// //
@@ -463,7 +470,7 @@
cost = 4
requirements = list(101,5,5,1,1,1,1,1,1,1)
high_population_requirement = 10
- earliest_start = 10 MINUTES
+ earliest_start = 0 MINUTES
repeatable = TRUE
//property_weights = list("extended" = 1)
occurances_max = 3
@@ -565,7 +572,7 @@
//config_tag = "radiation_storm"
typepath = /datum/round_event/radiation_storm
cost = 3
- weight = 3
+ weight = 2
repeatable_weight_decrease = 2
enemy_roles = list("Chemist","Chief Medical Officer","Geneticist","Medical Doctor","AI","Captain")
required_enemies = list(1,1,1,1,1,1,1,1,1,1)
@@ -715,7 +722,7 @@
weight = 100
repeatable_weight_decrease = 1 //Slightly drop the weight each time it is called to keep the pool from getting too diluted as the round goes on.
repeatable = TRUE
- //occurances_max = 20 //Our rounds can go for a WHILE
+ occurances_max = 200 //Our rounds can go for a WHILE
/datum/dynamic_ruleset/event/disease_outbreak
name = "Disease Outbreak"
diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm
index a51cd078..8ba449c9 100644
--- a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm
+++ b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm
@@ -31,8 +31,7 @@
continue // Dead players cannot count as opponents
if (M.mind && M.mind.assigned_role && (M.mind.assigned_role in enemy_roles) && (!(M in candidates) || (M.mind.assigned_role in restricted_roles)))
job_check++ // Checking for "enemies" (such as sec officers). To be counters, they must either not be candidates to that rule, or have a job that restricts them from it
-
- var/threat = round(mode.threat_level/10)
+ var/threat = min(round(mode.threat_level/10),9)
if (job_check < required_enemies[threat])
return FALSE
return ..()
diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm
index 376f4127..c40e04d6 100644
--- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm
+++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm
@@ -100,7 +100,7 @@
if (M.mind && M.mind.assigned_role && (M.mind.assigned_role in enemy_roles) && (!(M in candidates) || (M.mind.assigned_role in restricted_roles)))
job_check++ // Checking for "enemies" (such as sec officers). To be counters, they must either not be candidates to that rule, or have a job that restricts them from it
- var/threat = round(mode.threat_level/10)
+ var/threat = min(round(mode.threat_level/10),9)
if (job_check < required_enemies[threat])
return FALSE
return TRUE
@@ -258,6 +258,112 @@
return TRUE
+//////////////////////////////////////////
+// //
+// LEWD //
+// //
+//////////////////////////////////////////
+
+/datum/dynamic_ruleset/midround/autotraitor/lewd
+ name = "Horny Traitor"
+ persistent = TRUE
+ antag_flag = ROLE_LEWD_TRAITOR
+ antag_datum = /datum/antagonist/traitor/lewd
+ //minimum_required_age = 7
+ protected_roles = list("AI","Cyborg")
+ restricted_roles = list("Cyborg","AI")
+ required_candidates = 1
+ weight = 2
+ cost = 0
+ requirements = list(10,10,10,10,10,10,10,10,10,10)
+ high_population_requirement = 10
+ chaos_min = 0.1
+ chaos_max = 2.5
+ admin_required = TRUE
+ //vars for execution
+ var/list/mob/living/carbon/human/lewd_candidates = list()
+ var/list/mob/living/carbon/human/targets = list()
+ var/numTraitors = 1
+
+/datum/dynamic_ruleset/midround/autotraitor/lewd/acceptable(population = 0, threat = 0) //copy paste to bypass parent
+ if(minimum_players > population)
+ return FALSE
+ if(maximum_players > 0 && population > maximum_players)
+ return FALSE
+ if(GLOB.dynamic_chaos_level < chaos_min || GLOB.dynamic_chaos_level > chaos_max)
+ return FALSE
+ if(admin_required && !GLOB.admins.len)
+ return FALSE
+ if (population >= GLOB.dynamic_high_pop_limit)
+ return (mode.threat_level >= high_population_requirement)
+ else
+ pop_per_requirement = pop_per_requirement > 0 ? pop_per_requirement : mode.pop_per_requirement
+ var/indice_pop = min(10,round(population/pop_per_requirement)+1)
+ return (mode.threat_level >= requirements[indice_pop])
+
+/datum/dynamic_ruleset/midround/autotraitor/lewd/trim_candidates()
+ ..()
+ lewd_candidates = living_players
+ for(var/mob/living/player in lewd_candidates)
+ if(issilicon(player)) // Your assigned role doesn't change when you are turned into a silicon.
+ lewd_candidates -= player
+ continue
+ if(is_centcom_level(player.z))
+ lewd_candidates -= player // We don't autotator people in CentCom
+ continue
+ if(player.mind && (player.mind.special_role || player.mind.antag_datums?.len > 0))
+ lewd_candidates -= player // We don't autotator people with roles already
+
+/datum/dynamic_ruleset/midround/autotraitor/lewd/trim_list(list/L = list())
+ var/list/trimmed_list = L.Copy()
+ var/antag_name = initial(antag_flag)
+ for(var/mob/living/M in trimmed_list)
+ if (!istype(M, required_type))
+ trimmed_list.Remove(M)
+ continue
+ if (!M.client) // Are they connected?
+ trimmed_list.Remove(M)
+ continue
+ if(!mode.check_age(M.client, minimum_required_age))
+ trimmed_list.Remove(M)
+ continue
+ if (!(antag_name in M.client.prefs.be_special) || jobban_isbanned(M.ckey, list(antag_name, ROLE_SYNDICATE)))//are they willing and not antag-banned?
+ trimmed_list.Remove(M)
+ continue
+ if (M.mind)
+ if (restrict_ghost_roles && M.mind.assigned_role in GLOB.exp_specialmap[EXP_TYPE_SPECIAL]) // Are they playing a ghost role?
+ trimmed_list.Remove(M)
+ continue
+ if (M.mind.assigned_role in restricted_roles) // All this work to bypass mindshield restriction
+ trimmed_list.Remove(M)
+ continue
+ if ((exclusive_roles.len > 0) && !(M.mind.assigned_role in exclusive_roles)) // Is the rule exclusive to their job?
+ trimmed_list.Remove(M)
+ continue
+ return trimmed_list
+
+/datum/dynamic_ruleset/midround/autotraitor/lewd/ready()
+ for(var/mob/living/target in living_players)
+ if(target.client.prefs.noncon)
+ targets += target
+
+ if(lewd_candidates.len)
+ numTraitors = min(lewd_candidates.len, targets.len, numTraitors)
+ if(numTraitors == 0)
+ to_chat(GLOB.admins, "No lewd traitors created. Are there any valid targets?")
+ return 0
+ return 1
+
+ return 0
+
+/datum/dynamic_ruleset/midround/autotraitor/lewd/execute()
+ var/mob/M = pick(lewd_candidates)
+ lewd_candidates -= M
+ assigned += M.mind
+ var/datum/antagonist/traitor/lewd/newTraitor = new
+ M.mind.add_antag_datum(newTraitor)
+ return TRUE
+
//////////////////////////////////////////////
// //
// Malfunctioning AI //
@@ -268,7 +374,7 @@
name = "Malfunctioning AI"
antag_datum = /datum/antagonist/traitor
antag_flag = ROLE_MALF
- enemy_roles = list("Security Officer", "Warden","Detective","Head of Security", "Captain", "Scientist", "Research Director", "Chief Engineer")
+ enemy_roles = list("Security Officer", "Warden","Detective","Head of Security", "Captain", "Scientist", "Research Director", "Chief Engineer", "Engineer", "Shaft Miner")
exclusive_roles = list("AI")
required_enemies = list(4,4,4,4,4,4,2,2,2,0)
required_candidates = 1
diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm
index 495b0980..30586ee2 100644
--- a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm
+++ b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm
@@ -61,7 +61,6 @@
mode.picking_specific_rule(/datum/dynamic_ruleset/midround/autotraitor)
*/
-/* //Not currently functional
//////////////////////////////////////////
// //
// LEWD //
@@ -77,25 +76,24 @@
protected_roles = list("AI","Cyborg")
restricted_roles = list("Cyborg","AI")
required_candidates = 1
- weight = 5
+ weight = 3
cost = 0
- requirements = list(10,10,10,10,10,10,10,10,10,10)
+ requirements = list(101,10,10,10,10,10,10,10,10,10)
high_population_requirement = 10
chaos_min = 0.1
- chaos_max = 2.0
+ chaos_max = 2.5
admin_required = TRUE
//vars for execution
var/list/mob/living/carbon/human/lewd_candidates = list()
- var/numTraitors = 0
+ var/numTraitors = 1
-/datum/dynamic_ruleset/roundstart/traitor/lewd/pre_execute()
+/datum/dynamic_ruleset/roundstart/traitor/lewd/ready()
var/list/mob/living/carbon/human/targets = list()
- for(var/mob/living/carbon/human/target in GLOB.player_list)
+ for(var/mob/dead/new_player/target in GLOB.player_list)
if(target.client.prefs.noncon)
- if(!(target.job in restricted_roles))
- targets += target
+ targets += target
if(candidates.len)
var/numTraitors = min(candidates.len, targets.len, 1) //This number affects the maximum number of traitors. We want 1 for right now.
@@ -105,14 +103,26 @@
return 1
return 0
+
+/datum/dynamic_ruleset/roundstart/traitor/lewd/pre_execute()
+ var/traitor_scaling_coeff = 10 - max(0,round(mode.threat_level/10)-5) // Above 50 threat level, coeff goes down by 1 for every 10 levels
+ var/num_traitors = min(round(mode.candidates.len / traitor_scaling_coeff) + 1, candidates.len)
+ for (var/i = 1 to num_traitors)
+ var/mob/M = pick(candidates)
+ candidates -= M
+ assigned += M.mind
+ M.mind.special_role = ROLE_LEWD_TRAITOR
+ M.mind.restricted_roles = restricted_roles
+ return TRUE
+/*
/datum/dynamic_ruleset/roundstart/traitor/lewd/execute()
- var/mob/living/carbon/human/H = null
+ var/datum/mind/M = null
if(numTraitors)
for(var/i = 0, i"
- outfit.uniform = /obj/item/clothing/under/assistantformal
- outfit.shoes = /obj/item/clothing/shoes/sneakers/black
- outfit.back = /obj/item/storage/backpack
- if(2)
- flavour_text += "you were a volunteer test subject for a state of the art deep space facility. You didn't care much about who you were working with, but in the end, the paycheck \
- was really, really good. To this day, you're not quite sure which sort of prototype implants were used on you, as you seem to remember little but the headache that struck you once \
- the escape pod finally hit the ground and your seatbelt failed to keep you buckled."
- outfit.uniform = /obj/item/clothing/under/rank/scientist
- outfit.suit = /obj/item/clothing/suit/toggle/labcoat
- outfit.shoes = /obj/item/clothing/shoes/sneakers/black
- outfit.back = /obj/item/storage/backpack
- if(3)
- flavour_text += "you were a doctor at a state of the art deep space facility. For who exactly you were conducting research for, not even you are quite sure. Only that the paycheck \
- at the end of the month was good enough. In the end, when said facility was attacked by Nanotransen, you and another were the only ones to have made it out alive. Or so it seemed."
- outfit.uniform = /obj/item/clothing/under/rank/medical
- outfit.suit = /obj/item/clothing/suit/toggle/labcoat
- outfit.back = /obj/item/storage/backpack/medic
- outfit.shoes = /obj/item/clothing/shoes/sneakers/black
-
-/obj/effect/mob_spawn/human/duohermit/Destroy()
- new/obj/structure/fluff/empty_cryostasis_sleeper(get_turf(src))
- return ..()
-
-//Exiles: Stranded exiles that have been left in Snowdin. Can be easily adapted for other roles as well.
-/obj/effect/mob_spawn/human/exiled
- name = "used bed"
- desc = "Still warm."
- mob_name = "exiled"
- job_description = "Exiles"
- icon = 'icons/obj/objects.dmi'
- icon_state = "bed"
- roundstart = FALSE
- death = FALSE
- random = TRUE
- mob_species = /datum/species/human
- flavour_text = "As the last escape shuttle left the sector, you were left for dead, stranded in a cold hell where you make do, until hopefully someone finds you. \
- Every day, you pause and recollect your memories from before it all happened... "
- assignedrole = "Arctic Exile"
- mirrorcanloadappearance = TRUE
- ghost_usable = FALSE
-
-/obj/effect/mob_spawn/human/exiled/Initialize(mapload)
- . = ..()
- delayusability(9000, FALSE) //Probably should not show up on the menu? It gives it away that snowdin is the away mission.
- var/arrpee = rand(1,3)
- switch(arrpee)
- if(1)
- flavour_text += "You were a lowly engineer, hired by Kinaris to make sure the turbines from their mining operation remained functional. \
- You remember the day the mining team descended for the very last time into the depths of the shafts, only to never return. \
- The agonizing screams from whatever now haunts those mines still brings a shiver down your spine."
- outfit.uniform = /obj/item/clothing/under/rank/engineer
- outfit.suit = /obj/item/clothing/suit/hooded/wintercoat/engineering
- outfit.shoes = /obj/item/clothing/shoes/sneakers/black
- outfit.back = /obj/item/storage/backpack/industrial
- outfit.id = /obj/item/card/id/away/snowdin/eng
- outfit.implants = list(/obj/item/implant/exile) //Made it so they cannot simply exit through the gateway at will.
- if(2)
- flavour_text += "You were a plasma researcher, hired by Kinaris to oversee a small research division in a remote, isolated little icy planet, \
- you remember the day the mining team descended for the very last time into the depths of the shafts, only to never return. \
- While you haven't heard them yourself, reports say the sounds that were heard over radio were likely not of this world."
- outfit.uniform = /obj/item/clothing/under/rank/scientist
- outfit.suit = /obj/item/clothing/suit/hooded/wintercoat/science
- outfit.shoes = /obj/item/clothing/shoes/sneakers/black
- outfit.back = /obj/item/storage/backpack/science
- outfit.id = /obj/item/card/id/away/snowdin/sci
- outfit.implants = list(/obj/item/implant/exile) //Made it so they cannot simply exit through the gateway at will.
- if(3)
- flavour_text += "You were a junior doctor, hired by Kinaris to oversee the mental state of a plasma mining operation's miners. \
- Over and over you reported that the miners were having constant, similar types of hallucinations and that perhaps the whole operation should pause \
- until further investigation was concluded, but command shrugged it off as an episode of mass hallucination... Until the miners never came back."
- outfit.uniform = /obj/item/clothing/under/rank/medical
- outfit.suit = /obj/item/clothing/suit/hooded/wintercoat/medical
- outfit.shoes = /obj/item/clothing/shoes/sneakers/black
- outfit.back = /obj/item/storage/backpack/medic
- outfit.id = /obj/item/card/id/away/snowdin/med
- outfit.implants = list(/obj/item/implant/exile) //Made it so they cannot simply exit through the gateway at will.
-
-/obj/effect/mob_spawn/human/exiled/Destroy()
- new/obj/structure/bed(get_turf(src))
- return ..()
-
//Broken rejuvenation pod: Spawns in animal hospitals in lavaland. Ghosts become disoriented interns and are advised to search for help.
/obj/effect/mob_spawn/human/doctor/alive/lavaland
name = "broken rejuvenation pod"
diff --git a/code/modules/antagonists/nukeop/nukeop.dm b/code/modules/antagonists/nukeop/nukeop.dm
index fade96e6..65986105 100644
--- a/code/modules/antagonists/nukeop/nukeop.dm
+++ b/code/modules/antagonists/nukeop/nukeop.dm
@@ -36,7 +36,6 @@
var/mob/living/carbon/human/H = owner.current
H.set_species(/datum/species/human) //Plasamen burn up otherwise, and lizards are vulnerable to asimov AIs
H.equipOutfit(nukeop_outfit)
- H.checkloadappearance()
return TRUE
/datum/antagonist/nukeop/greet()
@@ -53,6 +52,8 @@
memorize_code()
if(send_to_spawnpoint)
move_to_spawnpoint()
+ var/mob/living/carbon/human/H = owner.current
+ H.checkloadappearance()
/datum/antagonist/nukeop/get_team()
return nuke_team
diff --git a/code/modules/clothing/head/soft_caps.dm b/code/modules/clothing/head/soft_caps.dm
index a87b0f30..414ba2c9 100644
--- a/code/modules/clothing/head/soft_caps.dm
+++ b/code/modules/clothing/head/soft_caps.dm
@@ -124,7 +124,7 @@
dog_fashion = null
/obj/item/clothing/head/soft/emt
- name = "EMT cap"
+ name = "paramedic cap"
desc = "It's a baseball hat with a dark turquoise color and a reflective cross on the top."
icon_state = "emtsoft"
item_color = "emt"
diff --git a/code/modules/clothing/suits/labcoat.dm b/code/modules/clothing/suits/labcoat.dm
index 022bc7c9..aab9040a 100644
--- a/code/modules/clothing/suits/labcoat.dm
+++ b/code/modules/clothing/suits/labcoat.dm
@@ -38,10 +38,10 @@
item_state = "labcoat_cmo"
/obj/item/clothing/suit/toggle/labcoat/emt
- name = "\improper EMT's jacket"
- desc = "A dark blue jacket with reflective strips for emergency medical technicians."
+ name = "paramedic's jacket"
+ desc = "A dark blue jacket for paramedics with reflective stripes."
icon_state = "labcoat_emt"
- item_state = "labcoat_cmo"
+ item_state = "labcoat_emt"
/obj/item/clothing/suit/toggle/labcoat/mad
name = "\proper The Mad's labcoat"
diff --git a/code/modules/clothing/under/jobs/medsci.dm b/code/modules/clothing/under/jobs/medsci.dm
index ced2d636..ddb23a83 100644
--- a/code/modules/clothing/under/jobs/medsci.dm
+++ b/code/modules/clothing/under/jobs/medsci.dm
@@ -204,4 +204,21 @@
item_color = "medical_skirt"
body_parts_covered = CHEST|GROIN|ARMS
can_adjust = FALSE
- fitted = FEMALE_UNIFORM_TOP
+ fitted = FEMALE_UNIFORM_TOP
+
+/obj/item/clothing/under/rank/medical/emt
+ desc = "It's made of a special fiber that provides minor protection against biohazards. It has a dark blue cross on the chest denoting that the wearer is a trained paramedic."
+ name = "paramedic jumpsuit"
+ icon_state = "emt"
+ item_state = "w_suit"
+ item_color = "emt"
+
+/obj/item/clothing/under/rank/medical/emt/skirt
+ name = "paramedic jumpskirt"
+ desc = "It's made of a special fiber that provides minor protection against biohazards. It has a dark blue cross on the chest denoting that the wearer is a trained paramedic."
+ icon_state = "emt_skirt"
+ item_state = "w_suit"
+ item_color = "emt_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index dc887651..04a0aa40 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -506,31 +506,3 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
. = BLOOD_COLOR_BUG
//add more stuff to the switch if you have more blood colors for different types
// the defines are in _DEFINES/misc.dm
-
-mob/proc/checkloadappearance()
- var/mob/living/carbon/human/H = src
- //This will be where the person gets to select their appearance instead of the random character
- if (world.time <= (H.time_initialized + 900) && H.mirrorcanloadappearance == TRUE)
- SEND_SOUND(H, 'sound/misc/server-ready.ogg')
- to_chat(H, "This ghost role allows you to select your loaded character's appearance. Make sure you have your ID in your ID slot, if you have one.")
- if(alert(H, "Would you like to load your currently loaded character's appearance?", "This can only be done up until 90s after you spawn.", "Yes", "No") == "Yes" && world.time <= (H.time_initialized + 900))
- H.client.prefs.copy_to(H)
- if (H.custom_body_size) //Do they have a custom size set?
- H.resize(H.custom_body_size * 0.01)
- H.real_name = H.client.prefs.real_name
- H.mind.name = H.real_name //Makes sure to change their mind name to their real name.
- SSquirks.AssignQuirks(H, H.client, TRUE, FALSE, H.job, FALSE)//This Assigns the selected character's quirks
- H.dna.update_dna_identity() //This makes sure their DNA is updated.
- var/obj/item/card/id/idCard = H.get_idcard() //Time to change their ID card as well if they have one.
- if (idCard != null)
- idCard.update_label(H.real_name, idCard.assignment)
- idCard.registered_name = H.real_name
- H.mirrorcanloadappearance = FALSE //Prevents them from using the mirror again.
- SEND_SOUND(H, 'sound/magic/charge.ogg') //Fluff
- to_chat(H, "Your head aches for a second. You feel like this is how things should have been.")
- log_game("[key_name(H)] has loaded their default appearance for a ghost role.")
- message_admins("[ADMIN_LOOKUPFLW(H)] has loaded their default appearance for a ghost role.")
- return
- else
- to_chat(H, "You either took too long or chose not to change. Alrighty. Remember, you have 90 seconds from spawn to get to a mirror and still do it if you wish.")
- return
diff --git a/code/modules/projectiles/ammunition/energy/stun.dm b/code/modules/projectiles/ammunition/energy/stun.dm
index 60b3ad63..fcf69c32 100644
--- a/code/modules/projectiles/ammunition/energy/stun.dm
+++ b/code/modules/projectiles/ammunition/energy/stun.dm
@@ -13,7 +13,7 @@
e_cost = 100
/obj/item/ammo_casing/energy/electrode/hos
- e_cost = 200
+ e_cost = 100
/obj/item/ammo_casing/energy/electrode/old
e_cost = 1000
diff --git a/code/modules/projectiles/guns/energy/energy_gun.dm b/code/modules/projectiles/guns/energy/energy_gun.dm
index de738c90..33feb5e3 100644
--- a/code/modules/projectiles/guns/energy/energy_gun.dm
+++ b/code/modules/projectiles/guns/energy/energy_gun.dm
@@ -54,6 +54,7 @@
name = "\improper X-01 MultiPhase Energy Gun"
desc = "This is an expensive, modern recreation of an antique laser gun. This gun has several unique firemodes, but lacks the ability to recharge over time."
icon_state = "hoslaser"
+ cell_type = /obj/item/stock_parts/cell{charge = 1600; maxcharge = 1600; chargerate = 160}
force = 10
ammo_type = list(/obj/item/ammo_casing/energy/electrode/hos, /obj/item/ammo_casing/energy/laser/hos, /obj/item/ammo_casing/energy/disabler)
ammo_x_offset = 4
diff --git a/code/modules/vending/wardrobes.dm b/code/modules/vending/wardrobes.dm
index e8f94efc..b88ad3d1 100644
--- a/code/modules/vending/wardrobes.dm
+++ b/code/modules/vending/wardrobes.dm
@@ -52,10 +52,13 @@
/obj/item/clothing/under/rank/medical/blue = 2,
/obj/item/clothing/under/rank/medical/green = 2,
/obj/item/clothing/under/rank/medical/purple = 2,
+ /obj/item/clothing/under/rank/medical/emt = 5,
+ /obj/item/clothing/under/rank/medical/emt/skirt = 5,
/obj/item/clothing/under/rank/medical = 5,
/obj/item/clothing/suit/toggle/labcoat = 5,
/obj/item/clothing/suit/toggle/labcoat/emt = 5,
/obj/item/clothing/shoes/sneakers/white = 5,
+ /obj/item/clothing/shoes/sneakers/blue = 5,
/obj/item/clothing/head/soft/emt = 5,
/obj/item/clothing/suit/apron/surgical = 3,
/obj/item/clothing/mask/surgical = 5)
diff --git a/hyperstation/code/datums/ruins/lavaland.dm b/hyperstation/code/datums/ruins/lavaland.dm
new file mode 100644
index 00000000..72b46ef6
--- /dev/null
+++ b/hyperstation/code/datums/ruins/lavaland.dm
@@ -0,0 +1,8 @@
+/datum/map_template/ruin/lavaland/duohermit
+ name = "Makeshift Big Shelter"
+ id = "duohermitcave"
+ description = "A place of shelter for a couple of stranded hermits, scraping by to live another day."
+ suffix = "lavaland_surface_duohermit.dmm"
+ allow_duplicates = FALSE
+ never_spawn_with = list(/datum/map_template/ruin/lavaland/hermit)
+ cost = 5
diff --git a/hyperstation/code/datums/traits/good.dm b/hyperstation/code/datums/traits/good.dm
new file mode 100644
index 00000000..0d0721a2
--- /dev/null
+++ b/hyperstation/code/datums/traits/good.dm
@@ -0,0 +1,59 @@
+/datum/quirk/narsianspeaker
+ name = "Nar-Sian speaker"
+ desc = "Obsessed with forbidden knowledge regarding the blood cult, you've learned how to speak their ancient language."
+ value = 1
+ gain_text = "Your mind feels sensitive to the slurred, ancient language of Nar'Sian cultists."
+ lose_text = "You forget how to speak Nar'Sian!"
+
+/datum/quirk/narsianspeaker/add()
+ var/mob/living/M = quirk_holder
+ M.grant_language(/datum/language/narsie)
+
+/datum/quirk/narsianspeaker/remove()
+ var/mob/living/M = quirk_holder
+ M.remove_language(/datum/language/narsie)
+
+/datum/quirk/ratvarianspeaker
+ name = "Ratvarian speaker"
+ desc = "Obsessed with the inner workings of the clock cult, you've learned how to speak their language."
+ value = 1
+ gain_text = "Your mind feels sensitive to the ancient language of Ratvarian cultists."
+ lose_text = "You forget how to speak Ratvarian!"
+
+/datum/quirk/ratvarianspeaker/add()
+ var/mob/living/M = quirk_holder
+ M.grant_language(/datum/language/ratvar)
+
+/datum/quirk/ratvarianspeaker/remove()
+ var/mob/living/M = quirk_holder
+ M.remove_language(/datum/language/ratvar)
+
+/datum/quirk/encodedspeaker
+ name = "Encoded Audio speaker"
+ desc = "You've been augmented with language encoders, allowing you to understand encoded audio."
+ value = 1
+ gain_text = "Your mouth feels a little weird for a moment as your language encoder kicks in."
+ lose_text = "You feel your encoded audio chip malfunction. You can no longer speak or understand the language of fax machines."
+
+/datum/quirk/encodedspeaker/add()
+ var/mob/living/M = quirk_holder
+ M.grant_language(/datum/language/machine)
+
+/datum/quirk/encodedspeaker/remove()
+ var/mob/living/M = quirk_holder
+ M.remove_language(/datum/language/machine)
+
+/datum/quirk/xenospeaker
+ name = "Xenocommon speaker"
+ desc = "Through time observing and interacting with xenos and xeno hybrids, you've learned the intricate hissing patterns of their language."
+ value = 1
+ gain_text = "You feel that you are now able to hiss in the same way xenomorphs do."
+ lose_text = "You seem to no longer know how to speak xenocommon."
+
+/datum/quirk/xenospeaker/add()
+ var/mob/living/M = quirk_holder
+ M.grant_language(/datum/language/xenocommon)
+
+/datum/quirk/xenospeaker/remove()
+ var/mob/living/M = quirk_holder
+ M.remove_language(/datum/language/xenocommon)
diff --git a/hyperstation/code/datums/traits/neutral.dm b/hyperstation/code/datums/traits/neutral.dm
new file mode 100644
index 00000000..dc7cbe3c
--- /dev/null
+++ b/hyperstation/code/datums/traits/neutral.dm
@@ -0,0 +1,18 @@
+//Skyrat port start
+/datum/quirk/alcohol_lightweight
+ name = "Alcoholic Lightweight"
+ desc = "Alcohol really goes straight to your head, gotta be careful with what you drink."
+ value = 0
+ mob_trait = TRAIT_ALCOHOL_LIGHTWEIGHT
+ gain_text = "You feel woozy thinking of alcohol."
+ lose_text = "You regain your stomach for drinks."
+//Skyrat port stop
+
+/datum/quirk/cursed_blood
+ name = "Cursed Blood"
+ desc = "Your lineage is cursed with the paleblood curse. Best to stay away from holy water... Hell water, on the other hand..."
+ value = 0
+ mob_trait = TRAIT_CURSED_BLOOD
+ gain_text = "A curse from a land where men return as beasts runs deep in your blood. Best to stay away from holy water... Hell water, on the other hand..."
+ lose_text = "You feel the weight of the curse in your blood finally gone."
+ medical_record_text = "Patient suffers from an unknown type of aversion to holy reagents. Keep them away from a chaplain."
\ No newline at end of file
diff --git a/hyperstation/code/game/objects/structures/ghost_role_spawners.dm b/hyperstation/code/game/objects/structures/ghost_role_spawners.dm
new file mode 100644
index 00000000..4fc26e61
--- /dev/null
+++ b/hyperstation/code/game/objects/structures/ghost_role_spawners.dm
@@ -0,0 +1,105 @@
+//Duo malfunctioning cryostasis sleepers: Spawns in big makeshift shelters in lavaland.
+/obj/effect/mob_spawn/human/duohermit
+ name = "malfunctioning cryostasis sleeper"
+ desc = "A humming sleeper with a silhouetted occupant inside. Its stasis function is broken and it's likely being used as a bed."
+ mob_name = "a stranded hermit"
+ job_description = "Lavaland Hermit"
+ icon = 'icons/obj/lavaland/spawners.dmi'
+ icon_state = "cryostasis_sleeper"
+ roundstart = FALSE
+ death = FALSE
+ random = TRUE
+ mob_species = /datum/species/human
+ flavour_text = "You and another have been stranded in this planet for quite some time now. Each day you barely scrape by, and between the terrible \
+ conditions of your makeshift shelter, the hostile creatures, and the ash drakes swooping down from the cloudless skies, all you can wish for is the feel of soft grass between your toes and \
+ the fresh air of Earth. These thoughts are dispelled by yet another recollection of how you and your friend got here... "
+ assignedrole = "Hermit"
+ mirrorcanloadappearance = TRUE
+
+/obj/effect/mob_spawn/human/duohermit/Initialize(mapload)
+ . = ..()
+ var/arrpee = rand(1,3)
+ switch(arrpee)
+ if(1)
+ flavour_text += "you were an intern at a rather odd deep space facility. You weren't quite sure how things worked or what they were doing there, but it was your first day on the \
+ job. A day that was abruptly interrupted by gunfire and alarms. Luckily enough, your handy crowbar skills managed to get you to an escape pod before it was too late."
+ outfit.uniform = /obj/item/clothing/under/assistantformal
+ outfit.shoes = /obj/item/clothing/shoes/sneakers/black
+ outfit.back = /obj/item/storage/backpack
+ if(2)
+ flavour_text += "you were a volunteer test subject for a state of the art deep space facility. You didn't care much about who you were working with, but in the end, the paycheck \
+ was really, really good. To this day, you're not quite sure which sort of prototype implants were used on you, as you seem to remember little but the headache that struck you once \
+ the escape pod finally hit the ground and your seatbelt failed to keep you buckled."
+ outfit.uniform = /obj/item/clothing/under/rank/scientist
+ outfit.suit = /obj/item/clothing/suit/toggle/labcoat
+ outfit.shoes = /obj/item/clothing/shoes/sneakers/black
+ outfit.back = /obj/item/storage/backpack
+ if(3)
+ flavour_text += "you were a doctor at a state of the art deep space facility. For who exactly you were conducting research for, not even you are quite sure. Only that the paycheck \
+ at the end of the month was good enough. In the end, when said facility was attacked by Nanotransen, you and another were the only ones to have made it out alive. Or so it seemed."
+ outfit.uniform = /obj/item/clothing/under/rank/medical
+ outfit.suit = /obj/item/clothing/suit/toggle/labcoat
+ outfit.back = /obj/item/storage/backpack/medic
+ outfit.shoes = /obj/item/clothing/shoes/sneakers/black
+
+/obj/effect/mob_spawn/human/duohermit/Destroy()
+ new/obj/structure/fluff/empty_cryostasis_sleeper(get_turf(src))
+ return ..()
+
+//Exiles: Stranded exiles that have been left in Snowdin. Can be easily adapted for other roles as well.
+/obj/effect/mob_spawn/human/exiled
+ name = "used bed"
+ desc = "Still warm."
+ mob_name = "exiled"
+ job_description = "Exiles"
+ icon = 'icons/obj/objects.dmi'
+ icon_state = "bed"
+ roundstart = FALSE
+ death = FALSE
+ random = TRUE
+ mob_species = /datum/species/human
+ flavour_text = "As the last escape shuttle left the sector, you were left for dead, stranded in a cold hell where you make do, until hopefully someone finds you. \
+ Every day, you pause and recollect your memories from before it all happened... "
+ assignedrole = "Arctic Exile"
+ mirrorcanloadappearance = TRUE
+ ghost_usable = FALSE
+
+/obj/effect/mob_spawn/human/exiled/Initialize(mapload)
+ . = ..()
+ delayusability(9000, FALSE) //Probably should not show up on the menu? It gives it away that snowdin is the away mission.
+ var/arrpee = rand(1,3)
+ switch(arrpee)
+ if(1)
+ flavour_text += "You were a lowly engineer, hired by Kinaris to make sure the turbines from their mining operation remained functional. \
+ You remember the day the mining team descended for the very last time into the depths of the shafts, only to never return. \
+ The agonizing screams from whatever now haunts those mines still brings a shiver down your spine."
+ outfit.uniform = /obj/item/clothing/under/rank/engineer
+ outfit.suit = /obj/item/clothing/suit/hooded/wintercoat/engineering
+ outfit.shoes = /obj/item/clothing/shoes/sneakers/black
+ outfit.back = /obj/item/storage/backpack/industrial
+ outfit.id = /obj/item/card/id/away/snowdin/eng
+ outfit.implants = list(/obj/item/implant/exile) //Made it so they cannot simply exit through the gateway at will.
+ if(2)
+ flavour_text += "You were a plasma researcher, hired by Kinaris to oversee a small research division in a remote, isolated little icy planet, \
+ you remember the day the mining team descended for the very last time into the depths of the shafts, only to never return. \
+ While you haven't heard them yourself, reports say the sounds that were heard over radio were likely not of this world."
+ outfit.uniform = /obj/item/clothing/under/rank/scientist
+ outfit.suit = /obj/item/clothing/suit/hooded/wintercoat/science
+ outfit.shoes = /obj/item/clothing/shoes/sneakers/black
+ outfit.back = /obj/item/storage/backpack/science
+ outfit.id = /obj/item/card/id/away/snowdin/sci
+ outfit.implants = list(/obj/item/implant/exile) //Made it so they cannot simply exit through the gateway at will.
+ if(3)
+ flavour_text += "You were a junior doctor, hired by Kinaris to oversee the mental state of a plasma mining operation's miners. \
+ Over and over you reported that the miners were having constant, similar types of hallucinations and that perhaps the whole operation should pause \
+ until further investigation was concluded, but command shrugged it off as an episode of mass hallucination... Until the miners never came back."
+ outfit.uniform = /obj/item/clothing/under/rank/medical
+ outfit.suit = /obj/item/clothing/suit/hooded/wintercoat/medical
+ outfit.shoes = /obj/item/clothing/shoes/sneakers/black
+ outfit.back = /obj/item/storage/backpack/medic
+ outfit.id = /obj/item/card/id/away/snowdin/med
+ outfit.implants = list(/obj/item/implant/exile) //Made it so they cannot simply exit through the gateway at will.
+
+/obj/effect/mob_spawn/human/exiled/Destroy()
+ new/obj/structure/bed(get_turf(src))
+ return ..()
diff --git a/hyperstation/code/modules/mob/mob_helpers.dm b/hyperstation/code/modules/mob/mob_helpers.dm
new file mode 100644
index 00000000..5c5229ab
--- /dev/null
+++ b/hyperstation/code/modules/mob/mob_helpers.dm
@@ -0,0 +1,27 @@
+mob/proc/checkloadappearance()
+ var/mob/living/carbon/human/H = src
+ //This will be where the person gets to select their appearance instead of the random character
+ if (world.time <= (H.time_initialized + 900) && H.mirrorcanloadappearance == TRUE)
+ SEND_SOUND(H, 'sound/misc/server-ready.ogg')
+ to_chat(H, "This ghost role allows you to select your loaded character's appearance. Make sure you have your ID in your ID slot, if you have one.")
+ if(alert(H, "Would you like to load your currently loaded character's appearance?", "This can only be done up until 90s after you spawn.", "Yes", "No") == "Yes" && world.time <= (H.time_initialized + 900))
+ H.client.prefs.copy_to(H)
+ if (H.custom_body_size) //Do they have a custom size set?
+ H.resize(H.custom_body_size * 0.01)
+ H.real_name = H.client.prefs.real_name
+ H.mind.name = H.real_name //Makes sure to change their mind name to their real name.
+ SSquirks.AssignQuirks(H, H.client, TRUE, FALSE, H.job, FALSE)//This Assigns the selected character's quirks
+ H.dna.update_dna_identity() //This makes sure their DNA is updated.
+ var/obj/item/card/id/idCard = H.get_idcard() //Time to change their ID card as well if they have one.
+ if (idCard != null)
+ idCard.update_label(H.real_name, idCard.assignment)
+ idCard.registered_name = H.real_name
+ H.mirrorcanloadappearance = FALSE //Prevents them from using the mirror again.
+ SEND_SOUND(H, 'sound/magic/charge.ogg') //Fluff
+ to_chat(H, "Your head aches for a second. You feel like this is how things should have been.")
+ log_game("[key_name(H)] has loaded their default appearance for a ghost role.")
+ message_admins("[ADMIN_LOOKUPFLW(H)] has loaded their default appearance for a ghost role.")
+ return
+ else
+ to_chat(H, "You either took too long or chose not to change. Alrighty. Remember, you have 90 seconds from spawn to get to a mirror and still do it if you wish.")
+ return
diff --git a/icons/mob/uniform.dmi b/icons/mob/uniform.dmi
index 657881d2..9529a33d 100644
Binary files a/icons/mob/uniform.dmi and b/icons/mob/uniform.dmi differ
diff --git a/icons/obj/clothing/uniforms.dmi b/icons/obj/clothing/uniforms.dmi
index 6e957f1f..b7252068 100644
Binary files a/icons/obj/clothing/uniforms.dmi and b/icons/obj/clothing/uniforms.dmi differ
diff --git a/modular_citadel/code/modules/mob/dead/new_player/sprite_accessories.dm b/modular_citadel/code/modules/mob/dead/new_player/sprite_accessories.dm
index 8292b947..25c982bf 100644
--- a/modular_citadel/code/modules/mob/dead/new_player/sprite_accessories.dm
+++ b/modular_citadel/code/modules/mob/dead/new_player/sprite_accessories.dm
@@ -920,11 +920,6 @@ datum/sprite_accessory/ears/human/gret
name = "Synthetic Lizard - Snout Under"
icon_state = "synthliz_under"
-/datum/sprite_accessory/mam_snouts/synthliz/synthliz_over
- color_src = MATRIXED
- name = "Synthetic Lizard - Snout Tertiary Face Plate"
- icon_state = "synthliz_over"
-
/datum/sprite_accessory/mam_snouts/synthliz/synthliz_tert
color_src = MATRIXED
name = "Synthetic Lizard - Snout Tertiary"
@@ -935,7 +930,55 @@ datum/sprite_accessory/ears/human/gret
name = "Synthetic Lizard - Snout Tertiary Under"
icon_state = "synthliz_tertunder"
+/datum/sprite_accessory/mam_snouts/synthliz/synthlizalt_basic
+ color_src = MUTCOLORS
+ name = "Synthetic Lizard Alt - Snout"
+ icon_state = "synthlizalt_basic"
+/datum/sprite_accessory/mam_snouts/synthliz/synthlizalt_under
+ color_src = MATRIXED
+ name = "Synthetic Lizard Alt - Snout Under"
+ icon_state = "synthlizalt_under"
+
+/datum/sprite_accessory/mam_snouts/synthliz/synthlizalt_over
+ color_src = MATRIXED
+ name = "Synthetic Lizard Alt - Snout Over"
+ icon_state = "synthlizalt_over"
+
+/datum/sprite_accessory/mam_snouts/synthliz/synthlizalt_tert
+ color_src = MATRIXED
+ name = "Synthetic Lizard Alt - Snout Tertiary"
+ icon_state = "synthlizalt_tert"
+
+/datum/sprite_accessory/mam_snouts/synthliz/synthlizalt_tertunder
+ color_src = MATRIXED
+ name = "Synthetic Lizard Alt - Snout Tertiary Under"
+ icon_state = "synthlizalt_tertunder"
+
+/datum/sprite_accessory/mam_snouts/synthliz/synthlizbarlessalt_basic
+ color_src = MUTCOLORS
+ name = "Synthetic Lizard Barless Alt - Snout"
+ icon_state = "synthlizbarlessalt_basic"
+
+/datum/sprite_accessory/mam_snouts/synthliz/synthlizbarlessalt_under
+ color_src = MATRIXED
+ name = "Synthetic Lizard Barless Alt - Snout Under"
+ icon_state = "synthlizbarlessalt_under"
+
+/datum/sprite_accessory/mam_snouts/synthliz/synthlizbarlessalt_over
+ color_src = MATRIXED
+ name = "Synthetic Lizard Barless Alt - Snout Over"
+ icon_state = "synthlizbarlessalt_over"
+
+/datum/sprite_accessory/mam_snouts/synthliz/synthlizbarlessalt_tert
+ color_src = MATRIXED
+ name = "Synthetic Lizard Barless Alt - Snout Tertiary"
+ icon_state = "synthlizbarlessalt_tert"
+
+/datum/sprite_accessory/mam_snouts/synthliz/synthlizbarlessalt_tertunder
+ color_src = MATRIXED
+ name = "Synthetic Lizard Barless Alt - Snout Tertiary Under"
+ icon_state = "synthlizbarlessalt_tertunder"
/******************************************
**************** Snouts *******************
diff --git a/modular_citadel/icons/mob/ipc_antennas.dmi b/modular_citadel/icons/mob/ipc_antennas.dmi
index 0fd5b44f..9880e0cd 100644
Binary files a/modular_citadel/icons/mob/ipc_antennas.dmi and b/modular_citadel/icons/mob/ipc_antennas.dmi differ
diff --git a/modular_citadel/icons/mob/mam_snouts.dmi b/modular_citadel/icons/mob/mam_snouts.dmi
index 5d7185dd..b2383576 100644
Binary files a/modular_citadel/icons/mob/mam_snouts.dmi and b/modular_citadel/icons/mob/mam_snouts.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index 4979ae49..79220544 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -2941,6 +2941,10 @@
#include "code\modules\zombie\items.dm"
#include "code\modules\zombie\organs.dm"
#include "hyperstation\code\datums\elements\holder_micro.dm"
+#include "hyperstation\code\datums\ruins\lavaland.dm"
+#include "hyperstation\code\datums\traits\good.dm"
+#include "hyperstation\code\datums\traits\neutral.dm"
+#include "hyperstation\code\game\objects\structures\ghost_role_spawners.dm"
#include "hyperstation\code\gamemode\traitor_lewd.dm"
#include "hyperstation\code\gamemode\traitor_thief.dm"
#include "hyperstation\code\gamemode\werewolf\werewolf.dm"
@@ -2948,16 +2952,17 @@
#include "hyperstation\code\mobs\hugbot.dm"
#include "hyperstation\code\mobs\mimic.dm"
#include "hyperstation\code\mobs\werewolf.dm"
-#include "hyperstation\code\modules\traits.dm"
#include "hyperstation\code\modules\antagonists\werewolf\werewolf.dm"
#include "hyperstation\code\modules\clothing\head.dm"
#include "hyperstation\code\modules\crafting\bounties.dm"
#include "hyperstation\code\modules\crafting\recipes.dm"
#include "hyperstation\code\modules\integrated_electronics\input.dm"
+#include "hyperstation\code\modules\mob\mob_helpers.dm"
#include "hyperstation\code\modules\patreon\patreon.dm"
#include "hyperstation\code\modules\resize\resizing.dm"
#include "hyperstation\code\modules\resize\sizechems.dm"
#include "hyperstation\code\modules\resize\sizegun.dm"
+#include "hyperstation\code\modules\traits.dm"
#include "hyperstation\code\obj\bluespace sewing kit.dm"
#include "hyperstation\code\obj\condom.dm"
#include "hyperstation\code\obj\decal.dm"