diff --git a/code/__DEFINES/DNA.dm b/code/__DEFINES/DNA.dm
index 9f3e6b4db0..aea7d42be6 100644
--- a/code/__DEFINES/DNA.dm
+++ b/code/__DEFINES/DNA.dm
@@ -97,6 +97,7 @@
#define NO_DNA_COPY 14
#define DRINKSBLOOD 15
#define NOEYES 16
+#define MARKINGS 17
#define ORGAN_SLOT_BRAIN "brain"
#define ORGAN_SLOT_APPENDIX "appendix"
diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm
index f642791224..c7daff49ed 100644
--- a/code/__DEFINES/citadel_defines.dm
+++ b/code/__DEFINES/citadel_defines.dm
@@ -93,6 +93,7 @@
#define MUTCOLORS3 36
#define NOAROUSAL 37 //Stops all arousal effects
#define NOGENITALS 38 //Cannot create, use, or otherwise have genitals
+#define MATRIXED 39 //if icon is color matrix'd
//Citadel istypes
#define isborer(A) (istype(A, /mob/living/simple_animal/borer))
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index 7301284ee4..709a4daeba 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -51,10 +51,11 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s
//Human Overlays Indexes/////////
//LOTS OF CIT CHANGES HERE. BE CAREFUL WHEN UPSTREAM ADDS MORE LAYERS
-#define MUTATIONS_LAYER 30 //mutations. Tk headglows, cold resistance glow, etc
-#define GENITALS_BEHIND_LAYER 29 //Some genitalia needs to be behind everything, such as with taurs (Taurs use body_behind_layer
-#define BODY_BEHIND_LAYER 28 //certain mutantrace features (tail when looking south) that must appear behind the body parts
-#define BODYPARTS_LAYER 27 //Initially "AUGMENTS", this was repurposed to be a catch-all bodyparts flag
+#define MUTATIONS_LAYER 31 //mutations. Tk headglows, cold resistance glow, etc
+#define GENITALS_BEHIND_LAYER 30 //Some genitalia needs to be behind everything, such as with taurs (Taurs use body_behind_layer
+#define BODY_BEHIND_LAYER 29 //certain mutantrace features (tail when looking south) that must appear behind the body parts
+#define BODYPARTS_LAYER 28 //Initially "AUGMENTS", this was repurposed to be a catch-all bodyparts flag
+#define MARKING_LAYER 27 //Matrixed body markings because clashing with snouts?
#define BODY_ADJ_LAYER 26 //certain mutantrace features (snout, body markings) that must appear above the body parts
#define GENITALS_ADJ_LAYER 25
#define BODY_LAYER 24 //underwear, undershirts, socks, eyes, lips(makeup)
@@ -82,7 +83,7 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s
#define HANDS_LAYER 3
#define BODY_FRONT_LAYER 2
#define FIRE_LAYER 1 //If you're on fire
-#define TOTAL_LAYERS 30 //KEEP THIS UP-TO-DATE OR SHIT WILL BREAK ;_;
+#define TOTAL_LAYERS 31 //KEEP THIS UP-TO-DATE OR SHIT WILL BREAK ;_;
//Human Overlay Index Shortcuts for alternate_worn_layer, layers
//Because I *KNOW* somebody will think layer+1 means "above"
diff --git a/code/__DEFINES/shuttles.dm b/code/__DEFINES/shuttles.dm
index c8a583a55e..36ecebb699 100644
--- a/code/__DEFINES/shuttles.dm
+++ b/code/__DEFINES/shuttles.dm
@@ -35,7 +35,7 @@
#define TRANSIT_REQUEST 1
#define TRANSIT_READY 2
-#define SHUTTLE_TRANSIT_BORDER 8
+#define SHUTTLE_TRANSIT_BORDER 10
#define PARALLAX_LOOP_TIME 25
#define HYPERSPACE_END_TIME 5
diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm
index 2455d373ab..a5617e6148 100644
--- a/code/__DEFINES/traits.dm
+++ b/code/__DEFINES/traits.dm
@@ -57,6 +57,7 @@
#define TRAIT_HEAVY_SLEEPER "heavy_sleeper"
#define TRAIT_NIGHT_VISION "night_vision"
#define TRAIT_LIGHT_STEP "light_step"
+#define TRAIT_SPEEDY_STEP "speedy_step"
#define TRAIT_SPIRITUAL "spiritual"
#define TRAIT_VORACIOUS "voracious"
#define TRAIT_SELF_AWARE "self_aware"
@@ -90,4 +91,4 @@
#define STASIS_MUTE "stasis"
#define GENETICS_SPELL "genetics_spell"
#define EYES_COVERED "eyes_covered"
-#define CULT_EYES "cult_eyes"
\ No newline at end of file
+#define CULT_EYES "cult_eyes"
diff --git a/code/__HELPERS/_cit_helpers.dm b/code/__HELPERS/_cit_helpers.dm
index 9e38d9cf1e..b6c968b163 100644
--- a/code/__HELPERS/_cit_helpers.dm
+++ b/code/__HELPERS/_cit_helpers.dm
@@ -37,6 +37,7 @@ GLOBAL_LIST_EMPTY(mam_ears_list)
GLOBAL_LIST_EMPTY(mam_tails_list)
GLOBAL_LIST_EMPTY(mam_tails_animated_list)
GLOBAL_LIST_EMPTY(taur_list)
+GLOBAL_LIST_EMPTY(mam_snouts_list)
//Exotic Species
GLOBAL_LIST_EMPTY(exotic_tails_list)
@@ -242,7 +243,7 @@ GLOBAL_VAR_INIT(miscreants_allowed, FALSE)
if("Wolf")
hdna.features["mam_tail"] = "Wolf"
hdna.features["mam_ears"] = "Wolf"
- hdna.features["snout"] = "Wolf"
+ hdna.features["mam_snouts"] = "Wolf"
hdna.features["mam_body_markings"] = "Wolf"
hdna.features["mcolor"] = "555"
hdna.features["mcolor2"] = "999"
@@ -250,7 +251,7 @@ GLOBAL_VAR_INIT(miscreants_allowed, FALSE)
if("Fox")
hdna.features["mam_tail"] = "Fox"
hdna.features["mam_ears"] = "Fox"
- hdna.features["snout"] = "Fox, Long"
+ hdna.features["mam_snouts"] = "Fox, Long"
hdna.features["mam_body_markings"] = "Fox"
hdna.features["mcolor"] = "f60"
hdna.features["mcolor2"] = "fff"
@@ -258,6 +259,6 @@ GLOBAL_VAR_INIT(miscreants_allowed, FALSE)
if("Fennec")
hdna.features["mam_tail"] = "Fennec"
hdna.features["mam_ears"] = "Fennec"
- hdna.features["snout"] = "Fox, Short"
+ hdna.features["mam_snouts"] = "Fox, Short"
hdna.features["mam_body_markings"] = "Fox"
H.regenerate_icons()
diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm
index c590c844eb..7d578337bc 100644
--- a/code/__HELPERS/game.dm
+++ b/code/__HELPERS/game.dm
@@ -511,6 +511,13 @@
var/obj/machinery/announcement_system/announcer = pick(GLOB.announcement_systems)
announcer.announce("ARRIVAL", character.real_name, rank, list()) //make the list empty to make it announce it in common
+/proc/GetHexColors(const/hexa)
+ return list(
+ GetRedPart(hexa)/ 255,
+ GetGreenPart(hexa)/ 255,
+ GetBluePart(hexa)/ 255
+ )
+
/proc/GetRedPart(const/hexa)
return hex2num(copytext(hexa, 2, 4))
diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm
index 4a7f2fdbc1..f6ef08fe0d 100644
--- a/code/__HELPERS/global_lists.dm
+++ b/code/__HELPERS/global_lists.dm
@@ -37,13 +37,9 @@
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_body_markings, GLOB.mam_body_markings_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails, GLOB.mam_tails_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_ears, GLOB.mam_ears_list)
+ init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_snouts, GLOB.mam_snouts_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails_animated, GLOB.mam_tails_animated_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/taur, GLOB.taur_list)
- //avian bodyparts (i swear this isn't starbound)
-// init_sprite_accessory_subtypes(/datum/sprite_accessory/beaks/avian, GLOB.avian_beaks_list)
-// init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/avian, GLOB.avian_tails_list)
-// init_sprite_accessory_subtypes(/datum/sprite_accessory/avian_wings, GLOB.avian_wings_list)
-// init_sprite_accessory_subtypes(/datum/sprite_accessory/avian_open_wings, GLOB.avian_open_wings_list)
//xeno parts (hiss?)
init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_head, GLOB.xeno_head_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_tail, GLOB.xeno_tail_list)
diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm
index d2cb3baa6a..5fb64004c0 100644
--- a/code/__HELPERS/icons.dm
+++ b/code/__HELPERS/icons.dm
@@ -712,7 +712,19 @@ world
var/static/icon/flat_template = icon('icons/effects/effects.dmi', "nothing")
#define BLANK icon(flat_template)
- #define SET_SELF(SETVAR) var/icon/SELF_ICON=icon(icon(curicon, curstate, base_icon_dir),"",SOUTH,no_anim?1:null);if(A.alpha<255)SELF_ICON.Blend(rgb(255,255,255,A.alpha),ICON_MULTIPLY);if(A.color)SELF_ICON.Blend(A.color,ICON_MULTIPLY);;##SETVAR=SELF_ICON;
+ #define SET_SELF(SETVAR) do { \
+ var/icon/SELF_ICON=icon(icon(curicon, curstate, base_icon_dir),"",SOUTH,no_anim?1:null); \
+ if(A.alpha<255) { \
+ SELF_ICON.Blend(rgb(255,255,255,A.alpha),ICON_MULTIPLY);\
+ } \
+ if(A.color) { \
+ if(islist(A.color)){ \
+ SELF_ICON.MapColors(arglist(A.color))} \
+ else{ \
+ SELF_ICON.Blend(A.color,ICON_MULTIPLY)} \
+ } \
+ ##SETVAR=SELF_ICON;\
+ } while (0)
#define INDEX_X_LOW 1
#define INDEX_X_HIGH 2
@@ -860,7 +872,11 @@ world
flat.Blend(add, blendMode2iconMode(curblend), I.pixel_x + 2 - flatX1, I.pixel_y + 2 - flatY1)
if(A.color)
- flat.Blend(A.color, ICON_MULTIPLY)
+ if(islist(A.color))
+ flat.MapColors(arglist(A.color))
+ else
+ flat.Blend(A.color, ICON_MULTIPLY)
+
if(A.alpha < 255)
flat.Blend(rgb(255, 255, 255, A.alpha), ICON_MULTIPLY)
diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm
index 92132b092e..eff6f54653 100644
--- a/code/__HELPERS/mobs.dm
+++ b/code/__HELPERS/mobs.dm
@@ -91,6 +91,8 @@
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails, GLOB.mam_tails_list)
if(!GLOB.mam_ears_list.len)
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_ears, GLOB.mam_ears_list)
+ if(!GLOB.mam_snouts_list.len)
+ init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_snouts, GLOB.mam_snouts_list)
// if(ishuman(src))
// var/mob/living/carbon/human/H = src
@@ -113,11 +115,11 @@
"mcolor2" = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F"),
"mcolor3" = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F"),
"tail_lizard" = pick(GLOB.tails_list_lizard),
- "tail_human" = "None",
+ "tail_human" = pick(GLOB.tails_list_human),
"wings" = "None",
"snout" = pick(GLOB.snouts_list),
"horns" = pick(GLOB.horns_list),
- "ears" = "None",
+ "ears" = pick(GLOB.ears_list),
"frills" = pick(GLOB.frills_list),
"spines" = pick(GLOB.spines_list),
"body_markings" = pick(GLOB.body_markings_list),
@@ -127,6 +129,7 @@
"taur" = "None",
"mam_body_markings" = pick(GLOB.mam_body_markings_list),
"mam_ears" = pick(GLOB.mam_ears_list),
+ "mam_snouts" = pick(GLOB.mam_snouts_list),
"mam_tail" = pick(GLOB.mam_tails_list),
"mam_tail_animated" = "None",
"xenodorsal" = "Standard",
diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm
index f216b025f8..4cd317318f 100644
--- a/code/controllers/configuration/entries/game_options.dm
+++ b/code/controllers/configuration/entries/game_options.dm
@@ -62,6 +62,8 @@
/datum/config_entry/flag/allow_ai // allow ai job
+/datum/config_entry/flag/allow_ai_multicam //whether the AI can use their multicam
+
/datum/config_entry/flag/disable_human_mood
/datum/config_entry/flag/disable_secborg // disallow secborg module to be chosen.
diff --git a/code/datums/browser.dm b/code/datums/browser.dm
index 358f2bfe29..4c501a3e7f 100644
--- a/code/datums/browser.dm
+++ b/code/datums/browser.dm
@@ -463,4 +463,3 @@
// so just reset the user mob's machine var
if(src && src.mob)
src.mob.unset_machine()
- return
diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm
index 2a93f74fa7..4021d11128 100644
--- a/code/datums/mood_events/generic_negative_events.dm
+++ b/code/datums/mood_events/generic_negative_events.dm
@@ -109,6 +109,10 @@
description = "It sure is dark around here...\n"
mood_change = -3
+/datum/mood_event/brightlight
+ description = "The light feels unbearable...\n"
+ mood_change = -3
+
/datum/mood_event/family_heirloom_missing
description = "I'm missing my family heirloom...\n"
mood_change = -4
diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm
index 9904a28d84..1c77520108 100644
--- a/code/datums/status_effects/debuffs.dm
+++ b/code/datums/status_effects/debuffs.dm
@@ -458,7 +458,7 @@
var/old_health
/datum/status_effect/kindle/tick()
- owner.Knockdown(15)
+ owner.Knockdown(15, TRUE, FALSE, 15)
if(iscarbon(owner))
var/mob/living/carbon/C = owner
C.silent = max(2, C.silent)
diff --git a/code/datums/traits/good.dm b/code/datums/traits/good.dm
index c7a8fa5f55..bd55869c99 100644
--- a/code/datums/traits/good.dm
+++ b/code/datums/traits/good.dm
@@ -58,6 +58,14 @@
gain_text = "You walk with a little more litheness."
lose_text = "You start tromping around like a barbarian."
+/datum/quirk/quick_step
+ name = "Quick Step"
+ desc = "You walk with determined strides, and out-pace most people when walking."
+ value = 2
+ mob_trait = TRAIT_SPEEDY_STEP
+ gain_text = "You feel determined. No time to lose."
+ lose_text = "You feel less determined. What's the rush, man?"
+
/datum/quirk/musician
name = "Musician"
desc = "You can tune handheld musical instruments to play melodies that clear certain negative effects and soothe the soul."
diff --git a/code/datums/traits/negative.dm b/code/datums/traits/negative.dm
index a98e172018..45f4a32c50 100644
--- a/code/datums/traits/negative.dm
+++ b/code/datums/traits/negative.dm
@@ -154,6 +154,21 @@
else
SEND_SIGNAL(quirk_holder, COMSIG_CLEAR_MOOD_EVENT, "nyctophobia")
+/datum/quirk/lightless
+ name = "Light Sensitivity"
+ desc = "Bright lights irritate you. Your eyes start to water, your skin feels itchy against the photon radiation, and your hair gets dry and frizzy. Maybe it's a medical condition. If only Nanotrasen was more considerate of your needs..."
+ value = -1
+ gain_text = "The safty of light feels off..."
+ lose_text = "Enlighing."
+
+/datum/quirk/lightless/on_process()
+ var/turf/T = get_turf(quirk_holder)
+ var/lums = T.get_lumcount()
+ if(lums >= 0.8)
+ SEND_SIGNAL(quirk_holder, COMSIG_ADD_MOOD_EVENT, "brightlight", /datum/mood_event/brightlight)
+ else
+ SEND_SIGNAL(quirk_holder, COMSIG_CLEAR_MOOD_EVENT, "brightlight")
+
/datum/quirk/nonviolent
name = "Pacifist"
desc = "The thought of violence makes you sick. So much so, in fact, that you can't hurt anyone."
diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm
index 07e31cb24d..feb81d44e0 100644
--- a/code/game/gamemodes/changeling/changeling.dm
+++ b/code/game/gamemodes/changeling/changeling.dm
@@ -56,19 +56,6 @@ GLOBAL_VAR(changeling_team_objective_type) //If this is not null, we hand our th
return 0
/datum/game_mode/changeling/post_setup()
- //Decide if it's ok for the lings to have a team objective
- //And then set it up to be handed out in forge_changeling_objectives
- var/list/team_objectives = subtypesof(/datum/objective/changeling_team_objective)
- var/list/possible_team_objectives = list()
- for(var/T in team_objectives)
- var/datum/objective/changeling_team_objective/CTO = T
-
- if(changelings.len >= initial(CTO.min_lings))
- possible_team_objectives += T
-
- if(possible_team_objectives.len && prob(20*changelings.len))
- GLOB.changeling_team_objective_type = pick(possible_team_objectives)
-
for(var/datum/mind/changeling in changelings)
log_game("[key_name(changeling)] has been selected as a changeling")
var/datum/antagonist/changeling/new_antag = new()
diff --git a/code/game/objects/items/plushes.dm b/code/game/objects/items/plushes.dm
index 742237df38..5fe8e71d5d 100644
--- a/code/game/objects/items/plushes.dm
+++ b/code/game/objects/items/plushes.dm
@@ -835,6 +835,14 @@
icon_state = "drew"
item_state = "drew"
+/obj/item/toy/plush/catgirl/fermis
+ name = "medcat plushie"
+ desc = "An affectionate stuffed toy that resembles a certain medcat, comes complete with battery operated wagging tail!! You get the impression she's cheering you on to to find happiness and be kind to people."
+ icon_state = "fermis"
+ item_state = "fermis"
+ attack_verb = list("cuddled", "petpatted", "wigglepurred")
+ squeak_override = list('modular_citadel/sound/voice/merowr.ogg' = 1)
+
/obj/item/toy/plush/awakenedplushie/ComponentInitialize()
. = ..()
AddComponent(/datum/component/edit_complainer)
diff --git a/code/game/sound.dm b/code/game/sound.dm
index 1fafb4f34d..cceed31cfb 100644
--- a/code/game/sound.dm
+++ b/code/game/sound.dm
@@ -1,4 +1,4 @@
-/proc/playsound(atom/source, soundin, vol as num, vary, extrarange as num, falloff, frequency = null, channel = 0, pressure_affected = TRUE, ignore_walls = TRUE)
+/proc/playsound(atom/source, soundin, vol as num, vary, extrarange as num, falloff, frequency = null, channel = 0, pressure_affected = TRUE, ignore_walls = TRUE, soundenvwet = -10000, soundenvdry = 0)
if(isarea(source))
throw EXCEPTION("playsound(): source is an area")
return
@@ -21,13 +21,16 @@
for(var/P in listeners)
var/mob/M = P
if(get_dist(M, turf_source) <= maxdistance)
- M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, channel, pressure_affected, S)
+ M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, channel, pressure_affected, S, soundenvwet, soundenvdry)
for(var/P in SSmobs.dead_players_by_zlevel[z])
var/mob/M = P
if(get_dist(M, turf_source) <= maxdistance)
- M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, channel, pressure_affected, S)
+ M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, channel, pressure_affected, S, soundenvwet, soundenvdry)
-/mob/proc/playsound_local(turf/turf_source, soundin, vol as num, vary, frequency, falloff, channel = 0, pressure_affected = TRUE, sound/S, envwet = -10000, envdry = 0)
+/mob/proc/playsound_local(turf/turf_source, soundin, vol as num, vary, frequency, falloff, channel = 0, pressure_affected = TRUE, sound/S, envwet = -10000, envdry = 0, manual_x, manual_y)
+ if(audiovisual_redirect)
+ var/turf/T = get_turf(src)
+ audiovisual_redirect.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, channel, pressure_affected, S, 0, -1000, turf_source.x - T.x, turf_source.y - T.y)
if(!client || !can_hear())
return
@@ -49,7 +52,9 @@
var/turf/T = get_turf(src)
//sound volume falloff with distance
- var/distance = get_dist(T, turf_source)
+ var/distance = 0
+ if(!manual_x && !manual_y)
+ distance = get_dist(T, turf_source)
S.volume -= max(distance - world.view, 0) * 2 //multiplicative falloff to add on top of natural audio falloff.
@@ -77,9 +82,17 @@
if(S.volume <= 0)
return //No sound
- var/dx = turf_source.x - T.x // Hearing from the right/left
+ var/dx = 0 // Hearing from the right/left
+ if(!manual_x)
+ dx = turf_source.x - T.x
+ else
+ dx = manual_x
S.x = dx
- var/dz = turf_source.y - T.y // Hearing from infront/behind
+ var/dz = 0 // Hearing from infront/behind
+ if(!manual_x)
+ dz = turf_source.y - T.y
+ else
+ dz = manual_y
S.z = dz
// The y value is for above your head, but there is no ceiling in 2d spessmens.
S.y = 1
diff --git a/code/modules/VR/vr_human.dm b/code/modules/VR/vr_human.dm
index 56f0986fef..53a4bbe540 100644
--- a/code/modules/VR/vr_human.dm
+++ b/code/modules/VR/vr_human.dm
@@ -35,6 +35,7 @@
/mob/living/carbon/human/virtual_reality/proc/revert_to_reality(deathchecks = TRUE)
if(real_mind && mind)
+ real_mind.current.audiovisual_redirect = null
real_mind.current.ckey = ckey
real_mind.current.stop_sound_channel(CHANNEL_HEARTBEAT)
if(deathchecks && vr_sleeper)
diff --git a/code/modules/VR/vr_sleeper.dm b/code/modules/VR/vr_sleeper.dm
index eed6f9b3ae..7169378179 100644
--- a/code/modules/VR/vr_sleeper.dm
+++ b/code/modules/VR/vr_sleeper.dm
@@ -93,6 +93,7 @@
to_chat(occupant, "Transferring to virtual reality...")
if(vr_human && vr_human.stat == CONSCIOUS && !vr_human.real_mind)
SStgui.close_user_uis(occupant, src)
+ human_occupant.audiovisual_redirect = vr_human
vr_human.real_mind = human_occupant.mind
vr_human.ckey = human_occupant.ckey
to_chat(vr_human, "Transfer successful! You are now playing as [vr_human] in VR!")
@@ -171,6 +172,7 @@
O.equip(vr_human)
if(transfer && H.mind)
SStgui.close_user_uis(H, src)
+ H.audiovisual_redirect = vr_human
vr_human.ckey = H.ckey
/obj/machinery/vr_sleeper/proc/cleanup_vr_human()
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index 76cc17b791..1a398f56fc 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -605,6 +605,24 @@
world.update_status()
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle AI", "[!alai ? "Disabled" : "Enabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+/datum/admins/proc/toggleMulticam()
+ set category = "Server"
+ set desc="Turns mutlicam on and off."
+ set name="Toggle Multicam"
+ var/almcam = CONFIG_GET(flag/allow_ai_multicam)
+ CONFIG_SET(flag/allow_ai_multicam, !almcam)
+ if (almcam)
+ to_chat(world, "The AI no longer has multicam.")
+ for(var/i in GLOB.ai_list)
+ var/mob/living/silicon/ai/aiPlayer = i
+ if(aiPlayer.multicam_on)
+ aiPlayer.end_multicam()
+ else
+ to_chat(world, "The AI now has multicam.")
+ log_admin("[key_name(usr)] toggled AI multicam.")
+ world.update_status()
+ SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Multicam", "[!almcam ? "Disabled" : "Enabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+
/datum/admins/proc/toggleaban()
set category = "Server"
set desc="Respawn basically"
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 9311adfbea..47ddd0aef3 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -118,6 +118,7 @@ GLOBAL_LIST_INIT(admin_verbs_server, world.AVerbsServer())
/datum/admins/proc/toggleaban,
/client/proc/everyone_random,
/datum/admins/proc/toggleAI,
+ /datum/admins/proc/toggleMulticam,
/client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/
/client/proc/cmd_debug_del_all,
/client/proc/toggle_random_events,
diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm
index cc3b3a3057..7e0ae3c08c 100644
--- a/code/modules/antagonists/changeling/changeling.dm
+++ b/code/modules/antagonists/changeling/changeling.dm
@@ -34,6 +34,8 @@
var/mimicing = ""
var/canrespec = 0
var/changeling_speak = 0
+ var/loudfactor = 0 //Used for blood tests. At 4, blood tests will succeed. At 10, blood tests will result in an explosion.
+ var/bloodtestwarnings = 0 //Used to track if the ling has been notified that they will pass blood tests.
var/datum/dna/chosen_dna
var/obj/effect/proc_holder/changeling/sting/chosen_sting
var/datum/cellular_emporium/cellular_emporium
@@ -71,8 +73,6 @@
reset_powers()
create_initial_profile()
if(give_objectives)
- if(team_mode)
- forge_team_objectives()
forge_objectives()
remove_clownmut()
. = ..()
@@ -123,6 +123,8 @@
/datum/antagonist/changeling/proc/reset_powers()
if(purchasedpowers)
remove_changeling_powers()
+ loudfactor = 0
+ bloodtestwarnings = 0
//Repurchase free powers.
for(var/path in all_powers)
var/obj/effect/proc_holder/changeling/S = new path()
@@ -174,6 +176,13 @@
geneticpoints -= thepower.dna_cost
purchasedpowers += thepower
thepower.on_purchase(owner.current)
+ loudfactor += thepower.loudness
+ if(loudfactor >= 4 && !bloodtestwarnings)
+ to_chat(owner.current, "Our blood is growing flammable. Our blood will react violently to heat.")
+ bloodtestwarnings = 1
+ if(loudfactor >= 10 && bloodtestwarnings < 2)
+ to_chat(owner.current, "Our blood has grown extremely flammable. Our blood will react explosively to heat.")
+ bloodtestwarnings = 2
/datum/antagonist/changeling/proc/readapt()
if(!ishuman(owner.current))
@@ -182,6 +191,7 @@
if(canrespec)
to_chat(owner.current, "We have removed our evolutions from this form, and are now ready to readapt.")
reset_powers()
+ playsound(get_turf(owner.current), 'sound/effects/lingreadapt.ogg', 75, TRUE, 5, soundenvwet = 0)
canrespec = 0
SSblackbox.record_feedback("tally", "changeling_power_purchase", 1, "Readapt")
return 1
diff --git a/code/modules/antagonists/changeling/changeling_power.dm b/code/modules/antagonists/changeling/changeling_power.dm
index ae255a04f8..c89dc50cec 100644
--- a/code/modules/antagonists/changeling/changeling_power.dm
+++ b/code/modules/antagonists/changeling/changeling_power.dm
@@ -16,6 +16,7 @@
var/req_stat = CONSCIOUS // CONSCIOUS, UNCONSCIOUS or DEAD
var/always_keep = 0 // important for abilities like revive that screw you if you lose them.
var/ignores_fakedeath = FALSE // usable with the FAKEDEATH flag
+ var/loudness = 0 //Determines how much having this ability will affect changeling blood tests. At 4, the blood will react violently and turn to ash, creating a unique message in the process. At 10, the blood will explode when heated.
/obj/effect/proc_holder/changeling/proc/on_purchase(mob/user, is_respec)
diff --git a/code/modules/antagonists/changeling/powers/biodegrade.dm b/code/modules/antagonists/changeling/powers/biodegrade.dm
index 1e8eaed383..d1a2cc3891 100644
--- a/code/modules/antagonists/changeling/powers/biodegrade.dm
+++ b/code/modules/antagonists/changeling/powers/biodegrade.dm
@@ -1,8 +1,9 @@
/obj/effect/proc_holder/changeling/biodegrade
name = "Biodegrade"
desc = "Dissolves restraints or other objects preventing free movement."
- helptext = "This is obvious to nearby people, and can destroy standard restraints and closets."
+ helptext = "This is obvious to nearby people, and can destroy standard restraints and closets. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
chemical_cost = 30 //High cost to prevent spam
+ loudness = 1
dna_cost = 2
req_human = 1
diff --git a/code/modules/antagonists/changeling/powers/digitalcamo.dm b/code/modules/antagonists/changeling/powers/digitalcamo.dm
index 68a1fa4add..e8bad0e215 100644
--- a/code/modules/antagonists/changeling/powers/digitalcamo.dm
+++ b/code/modules/antagonists/changeling/powers/digitalcamo.dm
@@ -1,8 +1,9 @@
/obj/effect/proc_holder/changeling/digitalcamo
name = "Digital Camouflage"
desc = "By evolving the ability to distort our form and proportions, we defeat common algorithms used to detect lifeforms on cameras."
- helptext = "We cannot be tracked by camera or seen by AI units while using this skill. However, humans looking at us will find us... uncanny."
+ helptext = "We cannot be tracked by camera or seen by AI units while using this skill. However, humans looking at us will find us... uncanny. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
dna_cost = 1
+ loudness = 1
//Prevents AIs tracking you but makes you easily detectable to the human-eye.
/obj/effect/proc_holder/changeling/digitalcamo/sting_action(mob/user)
diff --git a/code/modules/antagonists/changeling/powers/headcrab.dm b/code/modules/antagonists/changeling/powers/headcrab.dm
index 70edf1e788..8a932dbd62 100644
--- a/code/modules/antagonists/changeling/powers/headcrab.dm
+++ b/code/modules/antagonists/changeling/powers/headcrab.dm
@@ -1,9 +1,10 @@
/obj/effect/proc_holder/changeling/headcrab
name = "Last Resort"
desc = "We sacrifice our current body in a moment of need, placing us in control of a vessel."
- helptext = "We will be placed in control of a small, fragile creature. We may attack a corpse like this to plant an egg which will slowly mature into a new form for us."
+ helptext = "We will be placed in control of a small, fragile creature. We may attack a corpse like this to plant an egg which will slowly mature into a new form for us. This ability is loud, and might cause our blood to react violently to heat."
chemical_cost = 20
dna_cost = 1
+ loudness = 2
req_human = 1
/obj/effect/proc_holder/changeling/headcrab/sting_action(mob/user)
diff --git a/code/modules/antagonists/changeling/powers/hivemind.dm b/code/modules/antagonists/changeling/powers/hivemind.dm
index c84adc6e8f..86926f51a9 100644
--- a/code/modules/antagonists/changeling/powers/hivemind.dm
+++ b/code/modules/antagonists/changeling/powers/hivemind.dm
@@ -3,7 +3,7 @@
name = "Hivemind Communication"
desc = "We tune our senses to the airwaves to allow us to discreetly communicate and exchange DNA with other changelings."
helptext = "We will be able to talk with other changelings with :g. Exchanged DNA do not count towards absorb objectives."
- dna_cost = 0
+ dna_cost = 1
chemical_cost = -1
/obj/effect/proc_holder/changeling/hivemind_comms/on_purchase(mob/user, is_respec)
@@ -17,6 +17,9 @@
var/obj/effect/proc_holder/changeling/hivemind_download/S2 = new
if(!changeling.has_sting(S2))
changeling.purchasedpowers+=S2
+ var/obj/effect/proc_holder/changeling/linglink/S3 = new
+ if(!changeling.has_sting(S3))
+ changeling.purchasedpowers+=S3
// HIVE MIND UPLOAD/DOWNLOAD DNA
GLOBAL_LIST_EMPTY(hivemind_bank)
diff --git a/code/modules/antagonists/changeling/powers/lesserform.dm b/code/modules/antagonists/changeling/powers/lesserform.dm
index 06824f9bed..24403b406c 100644
--- a/code/modules/antagonists/changeling/powers/lesserform.dm
+++ b/code/modules/antagonists/changeling/powers/lesserform.dm
@@ -1,8 +1,9 @@
/obj/effect/proc_holder/changeling/lesserform
name = "Lesser Form"
- desc = "We debase ourselves and become lesser. We become a monkey."
+ desc = "We debase ourselves and become lesser. We become a monkey. This ability is loud, and might cause our blood to react violently to heat."
chemical_cost = 5
dna_cost = 1
+ loudness = 2
req_human = 1
//Transform into a monkey.
diff --git a/code/modules/antagonists/changeling/powers/linglink.dm b/code/modules/antagonists/changeling/powers/linglink.dm
index cd7c944137..baa02ea7c8 100644
--- a/code/modules/antagonists/changeling/powers/linglink.dm
+++ b/code/modules/antagonists/changeling/powers/linglink.dm
@@ -2,7 +2,7 @@
name = "Hivemind Link"
desc = "Link your victim's mind into the hivemind for personal interrogation."
chemical_cost = 0
- dna_cost = 0
+ dna_cost = -1
req_human = 1
/obj/effect/proc_holder/changeling/linglink/can_sting(mob/living/carbon/user)
diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm
index 6a952d09f8..9e353a1855 100644
--- a/code/modules/antagonists/changeling/powers/mutations.dm
+++ b/code/modules/antagonists/changeling/powers/mutations.dm
@@ -134,9 +134,10 @@
/obj/effect/proc_holder/changeling/weapon/arm_blade
name = "Arm Blade"
desc = "We reform one of our arms into a deadly blade."
- helptext = "We may retract our armblade in the same manner as we form it. Cannot be used while in lesser form."
+ helptext = "We may retract our armblade in the same manner as we form it. Cannot be used while in lesser form. This ability is loud, and might cause our blood to react violently to heat."
chemical_cost = 20
dna_cost = 2
+ loudness = 2
req_human = 1
weapon_type = /obj/item/melee/arm_blade
weapon_name_simple = "blade"
@@ -215,9 +216,11 @@
desc = "We ready a tentacle to grab items or victims with."
helptext = "We can use it once to retrieve a distant item. If used on living creatures, the effect depends on the intent: \
Help will simply drag them closer, Disarm will grab whatever they're holding instead of them, Grab will put the victim in our hold after catching it, \
- and Harm will stun it, and stab it if we're also holding a sharp weapon. Cannot be used while in lesser form."
+ and Harm will stun it, and stab it if we're also holding a sharp weapon. Cannot be used while in lesser form.\
+ This ability is loud, and might cause our blood to react violently to heat."
chemical_cost = 10
dna_cost = 2
+ loudness = 2
req_human = 1
weapon_type = /obj/item/gun/magic/tentacle
weapon_name_simple = "tentacle"
@@ -393,9 +396,10 @@
/obj/effect/proc_holder/changeling/weapon/shield
name = "Organic Shield"
desc = "We reform one of our arms into a hard shield."
- helptext = "Organic tissue cannot resist damage forever; the shield will break after it is hit too much. The more genomes we absorb, the stronger it is. Cannot be used while in lesser form."
+ helptext = "Organic tissue cannot resist damage forever; the shield will break after it is hit too much. The more genomes we absorb, the stronger it is. Cannot be used while in lesser form. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
chemical_cost = 20
dna_cost = 1
+ loudness = 1
req_human = 1
weapon_type = /obj/item/shield/changeling
@@ -445,9 +449,10 @@
/obj/effect/proc_holder/changeling/suit/organic_space_suit
name = "Organic Space Suit"
desc = "We grow an organic suit to protect ourselves from space exposure."
- helptext = "We must constantly repair our form to make it space-proof, reducing chemical production while we are protected. Cannot be used in lesser form."
+ helptext = "We must constantly repair our form to make it space-proof, reducing chemical production while we are protected. Cannot be used in lesser form. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
chemical_cost = 20
dna_cost = 2
+ loudness = 1
req_human = 1
suit_type = /obj/item/clothing/suit/space/changeling
@@ -492,9 +497,10 @@
/obj/effect/proc_holder/changeling/suit/armor
name = "Chitinous Armor"
desc = "We turn our skin into tough chitin to protect us from damage."
- helptext = "Upkeep of the armor requires a low expenditure of chemicals. The armor is strong against brute force, but does not provide much protection from lasers. Cannot be used in lesser form."
+ helptext = "Upkeep of the armor requires a low expenditure of chemicals. The armor is strong against brute force, but does not provide much protection from lasers. Cannot be used in lesser form. This ability is loud, and might cause our blood to react violently to heat."
chemical_cost = 20
dna_cost = 1
+ loudness = 2
req_human = 1
recharge_slowdown = 0.25
diff --git a/code/modules/antagonists/changeling/powers/shriek.dm b/code/modules/antagonists/changeling/powers/shriek.dm
index ca79562081..60c4dd546e 100644
--- a/code/modules/antagonists/changeling/powers/shriek.dm
+++ b/code/modules/antagonists/changeling/powers/shriek.dm
@@ -1,9 +1,10 @@
/obj/effect/proc_holder/changeling/resonant_shriek
name = "Resonant Shriek"
desc = "Our lungs and vocal cords shift, allowing us to briefly emit a noise that deafens and confuses the weak-minded."
- helptext = "Emits a high-frequency sound that confuses and deafens humans, blows out nearby lights and overloads cyborg sensors."
+ helptext = "Emits a high-frequency sound that confuses and deafens humans, blows out nearby lights and overloads cyborg sensors. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
chemical_cost = 20
dna_cost = 1
+ loudness = 1
req_human = 1
//A flashy ability, good for crowd control and sewing chaos.
@@ -30,8 +31,10 @@
/obj/effect/proc_holder/changeling/dissonant_shriek
name = "Dissonant Shriek"
desc = "We shift our vocal cords to release a high-frequency sound that overloads nearby electronics."
+ helptext = "Emits a high-frequency sound that overloads nearby electronics. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
chemical_cost = 20
dna_cost = 1
+ loudness = 1
//A flashy ability, good for crowd control and sewing chaos.
/obj/effect/proc_holder/changeling/dissonant_shriek/sting_action(mob/user)
diff --git a/code/modules/antagonists/changeling/powers/spiders.dm b/code/modules/antagonists/changeling/powers/spiders.dm
index 685767f601..2bd1bc8a35 100644
--- a/code/modules/antagonists/changeling/powers/spiders.dm
+++ b/code/modules/antagonists/changeling/powers/spiders.dm
@@ -1,9 +1,10 @@
/obj/effect/proc_holder/changeling/spiders
name = "Spread Infestation"
desc = "Our form divides, creating arachnids which will grow into deadly beasts."
- helptext = "The spiders are thoughtless creatures, and may attack their creators when fully grown. Requires at least 3 DNA gained through Absorb, and not through DNA sting."
+ helptext = "The spiders are thoughtless creatures, and may attack their creators when fully grown. Requires at least 3 DNA gained through Absorb, and not through DNA sting. This ability is very loud, and will guarantee that our blood will react violently to heat."
chemical_cost = 45
dna_cost = 1
+ loudness = 4
req_absorbs = 3
//Makes some spiderlings. Good for setting traps and causing general trouble.
diff --git a/code/modules/antagonists/changeling/powers/tiny_prick.dm b/code/modules/antagonists/changeling/powers/tiny_prick.dm
index 9bf4a76454..6c9e0c6599 100644
--- a/code/modules/antagonists/changeling/powers/tiny_prick.dm
+++ b/code/modules/antagonists/changeling/powers/tiny_prick.dm
@@ -64,10 +64,11 @@
/obj/effect/proc_holder/changeling/sting/transformation
name = "Transformation Sting"
desc = "We silently sting a human, injecting a retrovirus that forces them to transform."
- helptext = "The victim will transform much like a changeling would. Does not provide a warning to others. Mutations will not be transferred, and monkeys will become human."
+ helptext = "The victim will transform much like a changeling would. Does not provide a warning to others. Mutations will not be transferred, and monkeys will become human. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
sting_icon = "sting_transform"
chemical_cost = 50
dna_cost = 3
+ loudness = 1
var/datum/changelingprofile/selected_dna = null
/obj/effect/proc_holder/changeling/sting/transformation/Click()
@@ -111,10 +112,11 @@
/obj/effect/proc_holder/changeling/sting/false_armblade
name = "False Armblade Sting"
desc = "We silently sting a human, injecting a retrovirus that mutates their arm to temporarily appear as an armblade."
- helptext = "The victim will form an armblade much like a changeling would, except the armblade is dull and useless."
+ helptext = "The victim will form an armblade much like a changeling would, except the armblade is dull and useless. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
sting_icon = "sting_armblade"
chemical_cost = 20
dna_cost = 1
+ loudness = 1
/obj/item/melee/arm_blade/false
desc = "A grotesque mass of flesh that used to be your arm. Although it looks dangerous at first, you can tell it's actually quite dull and useless."
@@ -183,10 +185,11 @@
/obj/effect/proc_holder/changeling/sting/mute
name = "Mute Sting"
desc = "We silently sting a human, completely silencing them for a short time."
- helptext = "Does not provide a warning to the victim that they have been stung, until they try to speak and cannot."
+ helptext = "Does not provide a warning to the victim that they have been stung, until they try to speak and cannot. This ability is loud, and might cause our blood to react violently to heat."
sting_icon = "sting_mute"
chemical_cost = 20
dna_cost = 2
+ loudness = 2
/obj/effect/proc_holder/changeling/sting/mute/sting_action(mob/user, mob/living/carbon/target)
log_combat(user, target, "stung", "mute sting")
@@ -196,10 +199,11 @@
/obj/effect/proc_holder/changeling/sting/blind
name = "Blind Sting"
desc = "Temporarily blinds the target."
- helptext = "This sting completely blinds a target for a short time."
+ helptext = "This sting completely blinds a target for a short time. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
sting_icon = "sting_blind"
chemical_cost = 25
dna_cost = 1
+ loudness = 1
/obj/effect/proc_holder/changeling/sting/blind/sting_action(mob/user, mob/living/carbon/target)
log_combat(user, target, "stung", "blind sting")
@@ -229,10 +233,11 @@
/obj/effect/proc_holder/changeling/sting/cryo
name = "Cryogenic Sting"
desc = "We silently sting a human with a cocktail of chemicals that freeze them."
- helptext = "Does not provide a warning to the victim, though they will likely realize they are suddenly freezing."
+ helptext = "Does not provide a warning to the victim, though they will likely realize they are suddenly freezing. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
sting_icon = "sting_cryo"
chemical_cost = 15
dna_cost = 2
+ loudness = 1
/obj/effect/proc_holder/changeling/sting/cryo/sting_action(mob/user, mob/target)
log_combat(user, target, "stung", "cryo sting")
diff --git a/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm b/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm
index 41f501e346..530c4c5662 100644
--- a/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm
+++ b/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm
@@ -194,10 +194,12 @@
else
L.visible_message("[L]'s eyes blaze with brilliant light!", \
"Your vision suddenly screams with white-hot light!")
- L.Knockdown(160)
- L.adjustStaminaLoss(140) // now kindle works pretty much like bloodcult stun knockdown and stamcrit wise
+ L.Knockdown(15, TRUE, FALSE, 15)
L.apply_status_effect(STATUS_EFFECT_KINDLE)
L.flash_act(1, 1)
+ if(issilicon(target))
+ var/mob/living/silicon/S = L
+ S.emp_act(EMP_HEAVY)
if(iscultist(L))
L.adjustFireLoss(15)
..()
diff --git a/code/modules/cargo/bounties/engineering.dm b/code/modules/cargo/bounties/engineering.dm
index 8b73ebac4b..eb1764d482 100644
--- a/code/modules/cargo/bounties/engineering.dm
+++ b/code/modules/cargo/bounties/engineering.dm
@@ -24,6 +24,19 @@
description = "Station 49 is looking to kickstart their research program. Ship them a tank full of Tritium."
gas_type = /datum/gas/tritium
+/datum/bounty/item/engineering/pacman
+ name = "P.A.C.M.A.N.-type portable generator"
+ description = "A neighboring station had a problem with their SMES, and now need something to power their communications console. Can you send them a P.AC.M.A.N.?"
+ reward = 3500 //2500 for the cargo one
+ wanted_types = list(/obj/machinery/power/port_gen/pacman)
+
+/datum/bounty/item/engineering/canisters
+ name = "Gas Canisters"
+ description = "After a recent debacle in a nearby sector, 10 gas canisters are needed for containing an experimental aerosol before it kills all the local fauna."
+ reward = 5000
+ required_count = 10 //easy to make
+ wanted_types = list(/obj/machinery/portable_atmospherics/canister)
+
/datum/bounty/item/engineering/energy_ball
name = "Contained Tesla Ball"
description = "Station 24 is being overrun by hordes of angry Mothpeople. They are requesting the ultimate bug zapper."
diff --git a/code/modules/cargo/bounties/medical.dm b/code/modules/cargo/bounties/medical.dm
index d139775969..3129051754 100644
--- a/code/modules/cargo/bounties/medical.dm
+++ b/code/modules/cargo/bounties/medical.dm
@@ -57,3 +57,71 @@
description = "Central Command has run out of heavy duty pipe cleaners. Can you ship over a cat tail to help us out?"
reward = 3000
wanted_types = list(/obj/item/organ/tail/cat)
+
+/datum/bounty/item/medical/blood
+ name = "Generic Blood"
+ description = "Nanotrasen's annual blood drive is back up to full speed, following the garlic incident. Good blood in good volumes accepted for Credit returns."
+ reward = 3500
+ required_count = 600
+ wanted_types = list(/datum/reagent/blood)
+
+/* If anyone wants to try and fix/work, go for it
+/datum/bounty/item/medical/medibot // Mob so this dosn't work yet*
+ name = "Medibot"
+ description = "A sister station is dealing with um problem, they need a medibot to help treat their wounded..."
+ reward = 3000
+ wanted_types = list(/mob/living/simple_animal/bot/medbot)
+
+/datum/bounty/item/medical/bloodl //Dosnt work do to how blood is yet*
+ name = "L-type Blood"
+ description = "After a small scuffle, a few of our lizard employees need another blood transfusion."
+ reward = 4000
+ required_count = 200
+ wanted_types = (L,/datum/reagent/blood)
+ if(istype(L,/datum/reagent/blood))
+ wanted_types += L
+
+/datum/bounty/item/medical/bloodu //Dosnt work do to how blood is yet*
+ name = "U-Type Blood"
+ description = "After dealing with a small revolt in a local penal colony, the colony's anemic CMO needs blood, urgently. With his compromised immune system, only the best blood can be used."
+ reward = 5500 // Rarer blood
+ required_count = 200
+ wanted_types = (U,/datum/reagent/blood)
+ if(istype(U,/datum/reagent/blood))
+ wanted_types += U
+
+*/
+
+/datum/bounty/item/medical/surgery
+ name = "Surgery tool implants"
+ description = "Our medical interns keep dropping their Shambler's Juice while they're performing open heart surgery. One of them even had the audacity to say he only had two hands!"
+ reward = 10000
+ required_count = 3
+ wanted_types = list(/obj/item/organ/cyberimp/arm/surgery)
+
+/datum/bounty/item/medical/chemmaker
+ name = "Portable Chem Dispenser"
+ description = "After a new chemist mixed up some water and a banana, we lost our only chem dispenser. Please send us a replacement and you will be compensated."
+ reward = 7000
+ wanted_types = list(/obj/machinery/chem_dispenser)
+
+/datum/bounty/item/medical/advhealthscaner
+ name = "Advanced Health Analyzer"
+ description = "A ERT Medical unit needs the new 'advanced health analyzer', for a mission at a Station 4. Can you send some?."
+ reward = 4000
+ required_count = 5
+ wanted_types = list(/obj/item/healthanalyzer/advanced)
+
+/datum/bounty/item/medical/wallmounts
+ name = "Defibrillator wall mounts"
+ description = "New Space OSHA regulation state that are new cloning medical wing needs a few 'Easy to access defibrillartors'. Can you send a few before we get a lawsuit?"
+ reward = 5000
+ required_count = 3
+ wanted_types = list(/obj/machinery/defibrillator_mount)
+
+/datum/bounty/item/medical/defibrillator
+ name = "New defibillators"
+ description = "After years of storge are defibrillator units have become more liabilities then we want. Please send us some new ones to replace these old ones."
+ reward = 5000
+ required_count = 5
+ wanted_types = list(/obj/item/defibrillator)
diff --git a/code/modules/cargo/bounties/mining.dm b/code/modules/cargo/bounties/mining.dm
index 1b8b46734f..51d93f83b5 100644
--- a/code/modules/cargo/bounties/mining.dm
+++ b/code/modules/cargo/bounties/mining.dm
@@ -49,3 +49,17 @@
reward = 5000
required_count = 3
wanted_types = list(/obj/item/kitchen/knife/combat/bone)
+
+/datum/bounty/item/mining/basalt
+ name = "Artificial Basalt Tiles"
+ description = "Central Command's Ash Walker exhibit needs to be expanded again, we just need some more basalt flooring."
+ reward = 5000
+ required_count = 60
+ wanted_types = list(/obj/item/stack/tile/basalt)
+
+/datum/bounty/item/mining/fruit
+ name = "Cactus Fruit"
+ description = "Central Command's Ash Walker habitat needs more fauna, send us some local fruit seeds!"
+ reward = 2000
+ required_count = 1
+ wanted_types = list(/obj/item/seeds/lavaland/cactus)
diff --git a/code/modules/cargo/bounties/science.dm b/code/modules/cargo/bounties/science.dm
index 33f334ac47..2ac79f6ee8 100644
--- a/code/modules/cargo/bounties/science.dm
+++ b/code/modules/cargo/bounties/science.dm
@@ -64,3 +64,55 @@
description = "With the price of rechargers on the rise, upper management is interested in purchasing guns that are self-powered. If you ship one, they'll pay."
reward = 10000
wanted_types = list(/obj/item/gun/energy/e_gun/nuclear)
+
+/datum/bounty/item/science/bscells
+ name = "Bluespace Power Cells"
+ description = "Someone in upper management keeps using the excuse that his tablet battery dies when he's in the middle of work. This will be the last time he doesn't have his presentation, I swear to -"
+ reward = 7000
+ required_count = 10 //Easy to make
+ wanted_types = list(/obj/item/stock_parts/cell/bluespace)
+
+/datum/bounty/item/science/t4manip
+ name = "Femto-Manipulators"
+ description = "One of our Chief Engineers has OCD. Can you send us some femto-manipulators so he stops complaining that his ID doesn't fit perfectly in the PDA slot?"
+ reward = 7000
+ required_count = 20 //Easy to make
+ wanted_types = list(/obj/item/stock_parts/manipulator/femto)
+
+/datum/bounty/item/science/t4bins
+ name = "Bluespace Matter Bins"
+ description = "The local Janitorial union has gone on strike. Can you send us some bluespace bins so we don't have to take out our own trash?"
+ reward = 7000
+ required_count = 20 //Easy to make
+ wanted_types = list(/obj/item/stock_parts/matter_bin/bluespace)
+
+/datum/bounty/item/science/t4capacitor
+ name = "Quadratic Capacitor"
+ description = "One of our linguists doesn't understand why they're called Quadratic capacitors. Can you give him a few so he leaves us alone about it?"
+ reward = 7000
+ required_count = 20 //Easy to make
+ wanted_types = list(/obj/item/stock_parts/capacitor/quadratic)
+
+/datum/bounty/item/science/t4triphasic
+ name = "Triphasic Scanning Module"
+ description = "One of our scientists got into the liberty caps and is demanding new scanning modules so he can talk to ghosts. At this point we just want him out of our office."
+ reward = 7000
+ required_count = 20 //Easy to make
+ wanted_types = list(/obj/item/stock_parts/scanning_module/triphasic)
+
+/datum/bounty/item/science/t4microlaser
+ name = "Quad-Ultra Micro-Laser"
+ description = "The cats on Vega 9 are breeding out of control. We need something to corral them into one area so we can saturation bomb it."
+ reward = 7000
+ required_count = 20 //Easy to make
+ wanted_types = list(/obj/item/stock_parts/micro_laser/quadultra)
+
+/datum/bounty/item/science/fakecrystals
+ name = "synthetic bluespace crystals"
+ description = "Don't, uh, tell anyone, but one of our BSA arrays might have had a little... accident. Send us some bluespace crystals so we can recalibrate it before anyone realizes. The whole set uses artificial bluespace crystals, so we need and not any other type of bluespace crystals..."
+ reward = 10000
+ required_count = 5
+ wanted_types = list(/obj/item/stack/ore/bluespace_crystal/artificial)
+ exclude_types = list(/obj/item/stack/ore/bluespace_crystal,
+ /obj/item/stack/sheet/bluespace_crystal,
+ /obj/item/stack/ore/bluespace_crystal/refined)
diff --git a/code/modules/cargo/bounties/security.dm b/code/modules/cargo/bounties/security.dm
index bcf7b89f3a..cae8d10c61 100644
--- a/code/modules/cargo/bounties/security.dm
+++ b/code/modules/cargo/bounties/security.dm
@@ -11,3 +11,44 @@
reward = 2000
required_count = 3
wanted_types = list(/obj/machinery/recharger)
+
+/datum/bounty/item/security/practice
+ name = "Practice Laser Gun"
+ description = "Nanotrasen Military Academy is conducting routine marksmanship exercises. The clown hid all the practice lasers, and we're not using live weapons after last time."
+ reward = 3000
+ required_count = 3
+ wanted_types = list(/obj/item/gun/energy/laser/practice)
+
+/datum/bounty/item/security/flashshield
+ name = "Strobe Shield"
+ description = "One of our Emergency Response Agents thinks there's vampires in a local station. Send him something to help with his fear of the dark and protect him, too."
+ reward = 5000
+ wanted_types = list(/obj/item/assembly/flash/shield)
+
+/datum/bounty/item/security/sechuds
+ name = "Sec HUDs"
+ description = "Nanotrasen military academy has started to train officers how to use Sec HUDs to the fullest affect. Please send spare Sec HUDs so we can teach the men."
+ reward = 3000
+ required_count = 5
+ wanted_types = list(/obj/item/clothing/glasses/hud/security)
+
+/datum/bounty/item/security/techslugs
+ name = "Tech Slugs"
+ description = "Nanotrasen Military Academy is conducting an ammo loading and use lessons, on the new 'Tech Slugs'. Problem is we don't have any, please fix this..."
+ reward = 7500
+ required_count = 15
+ wanted_types = list(/obj/item/ammo_casing/shotgun/techshell)
+
+/datum/bounty/item/security/WT550
+ name = "Spare WT-550 clips"
+ description = "Nanotrasen Military Academy's ammunition is running low, please send in spare ammo for practice."
+ reward = 7500
+ required_count = 5
+ wanted_types = list(/obj/item/ammo_box/magazine/wt550m9)
+
+/datum/bounty/item/security/pins
+ name = "Test range firing pins"
+ description = "Nanotrasen Military Academy just got a new set of guns, sadly they didn't come with any pins. Can you send us some Test range locked firing pins?"
+ reward = 5000
+ required_count = 3
+ wanted_types = list(/obj/item/firing_pin/test_range)
diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm
index c85eb95b05..7216b73af6 100644
--- a/code/modules/client/client_defines.dm
+++ b/code/modules/client/client_defines.dm
@@ -72,4 +72,6 @@
var/list/credits //lazy list of all credit object bound to this client
- var/datum/player_details/player_details //these persist between logins/logouts during the same round.
\ No newline at end of file
+ var/datum/player_details/player_details //these persist between logins/logouts during the same round.
+
+ var/list/char_render_holders //Should only be a key-value list of north/south/east/west = obj/screen.
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index 85d1b4f150..f93b799e8d 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -454,6 +454,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
GLOB.ahelp_tickets.ClientLogout(src)
GLOB.directory -= ckey
GLOB.clients -= src
+ QDEL_LIST_ASSOC_VAL(char_render_holders)
if(movingmob != null)
movingmob.client_mobs_in_contents -= mob
UNSETEMPTY(movingmob.client_mobs_in_contents)
@@ -877,3 +878,23 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
/client/proc/AnnouncePR(announcement)
if(prefs && prefs.chat_toggles & CHAT_PULLR)
to_chat(src, announcement)
+
+/client/proc/show_character_previews(mutable_appearance/MA)
+ var/pos = 0
+ for(var/D in GLOB.cardinals)
+ pos++
+ var/obj/screen/O = LAZYACCESS(char_render_holders, "[D]")
+ if(!O)
+ O = new
+ LAZYSET(char_render_holders, "[D]", O)
+ screen |= O
+ O.appearance = MA
+ O.dir = D
+ O.screen_loc = "character_preview_map:0,[pos]"
+
+/client/proc/clear_character_previews()
+ for(var/index in char_render_holders)
+ var/obj/screen/S = char_render_holders[index]
+ screen -= S
+ qdel(S)
+ char_render_holders = null
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index a11c1497c2..f245dd330e 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -1,2125 +1,2212 @@
- /* CAUTION! CAUTION! CAUTION! CAUTION! CAUTION! *\
- | THIS FILE CONTAINS HOOKS FOR FOR |
- | CHANGES SPECIFIC TO CITADEL. IF |
- | YOU'RE FIXING A MERGE CONFLICT |
- | HERE, PLEASE ASK FOR REVIEW FROM |
- | ANOTHER MAINTAINER TO ENSURE YOU |
- | DON'T INTRODUCE REGRESSIONS. |
- \* */
-
-GLOBAL_LIST_EMPTY(preferences_datums)
-
-/datum/preferences
- var/client/parent
- //doohickeys for savefiles
- var/path
- var/default_slot = 1 //Holder so it doesn't default to slot 1, rather the last one used
- var/max_save_slots = 8
-
- //non-preference stuff
- var/muted = 0
- var/last_ip
- var/last_id
-
- //game-preferences
- var/lastchangelog = "" //Saved changlog filesize to detect if there was a change
- var/ooccolor = null
- var/enable_tips = TRUE
- var/tip_delay = 500 //tip delay in milliseconds
-
- //Antag preferences
- var/list/be_special = list() //Special role selection
- var/tmp/old_be_special = 0 //Bitflag version of be_special, used to update old savefiles and nothing more
- //If it's 0, that's good, if it's anything but 0, the owner of this prefs file's antag choices were,
- //autocorrected this round, not that you'd need to check that.
-
-
- var/UI_style = null
- var/buttons_locked = FALSE
- var/hotkeys = FALSE
- var/tgui_fancy = TRUE
- var/tgui_lock = TRUE
- var/windowflashing = TRUE
- var/toggles = TOGGLES_DEFAULT
- var/db_flags
- var/chat_toggles = TOGGLES_DEFAULT_CHAT
- var/ghost_form = "ghost"
- var/ghost_orbit = GHOST_ORBIT_CIRCLE
- var/ghost_accs = GHOST_ACCS_DEFAULT_OPTION
- var/ghost_others = GHOST_OTHERS_DEFAULT_OPTION
- var/ghost_hud = 1
- var/inquisitive_ghost = 1
- var/allow_midround_antag = 1
- var/preferred_map = null
- var/pda_style = MONO
- var/pda_color = "#808000"
-
- var/uses_glasses_colour = 0
-
- //character preferences
- var/real_name //our character's name
- var/nameless = FALSE //whether or not our character is nameless
- var/be_random_name = 0 //whether we'll have a random name every round
- var/be_random_body = 0 //whether we'll have a random body every round
- var/gender = MALE //gender of character (well duh)
- var/age = 30 //age of character
- var/underwear = "Nude" //underwear type
- var/undershirt = "Nude" //undershirt type
- var/socks = "Nude" //socks type
- var/backbag = DBACKPACK //backpack type
- var/hair_style = "Bald" //Hair type
- var/hair_color = "000" //Hair color
- var/facial_hair_style = "Shaved" //Face hair type
- var/facial_hair_color = "000" //Facial hair color
- var/skin_tone = "caucasian1" //Skin color
- var/eye_color = "000" //Eye color
- var/datum/species/pref_species = new /datum/species/human() //Mutant race
- var/list/features = list("mcolor" = "FFF",
- "tail_lizard" = "Smooth", "tail_human" = "None",
- "snout" = "Round", "horns" = "None", "ears" = "None",
- "wings" = "None", "frills" = "None", "spines" = "None",
- "body_markings" = "None", "legs" = "Normal Legs", "moth_wings" = "Plain")
-
- var/list/custom_names = list()
- var/prefered_security_department = SEC_DEPT_RANDOM
-
- //Mob preview
- var/icon/preview_icon = null
-
- //Quirk list
- var/list/positive_quirks = list()
- var/list/negative_quirks = list()
- var/list/neutral_quirks = list()
- var/list/all_quirks = list()
- var/list/character_quirks = list()
-
- //Jobs, uses bitflags
- var/job_civilian_high = 0
- var/job_civilian_med = 0
- var/job_civilian_low = 0
-
- var/job_medsci_high = 0
- var/job_medsci_med = 0
- var/job_medsci_low = 0
-
- var/job_engsec_high = 0
- var/job_engsec_med = 0
- var/job_engsec_low = 0
-
- // Want randomjob if preferences already filled - Donkie
- var/joblessrole = BERANDOMJOB //defaults to 1 for fewer assistants
-
- // 0 = character settings, 1 = game preferences
- var/current_tab = 0
-
- var/unlock_content = 0
-
- var/list/ignoring = list()
-
- var/clientfps = 0
-
- var/parallax
-
- var/ambientocclusion = TRUE
- var/auto_fit_viewport = TRUE
-
- var/uplink_spawn_loc = UPLINK_PDA
-
- var/list/exp = list()
- var/list/menuoptions
-
- var/action_buttons_screen_locs = list()
-
-/datum/preferences/New(client/C)
- parent = C
-
- for(var/custom_name_id in GLOB.preferences_custom_names)
- custom_names[custom_name_id] = get_default_name(custom_name_id)
-
- UI_style = GLOB.available_ui_styles[1]
- if(istype(C))
- if(!IsGuestKey(C.key))
- load_path(C.ckey)
- unlock_content = C.IsByondMember()
- if(unlock_content)
- max_save_slots = 16
- var/loaded_preferences_successfully = load_preferences()
- if(loaded_preferences_successfully)
- if(load_character())
- return
- //we couldn't load character data so just randomize the character appearance + name
- random_character() //let's create a random character then - rather than a fat, bald and naked man.
- real_name = pref_species.random_name(gender,1)
- if(!loaded_preferences_successfully)
- save_preferences()
- save_character() //let's save this new random character so it doesn't keep generating new ones.
- menuoptions = list()
- return
-
-#define APPEARANCE_CATEGORY_COLUMN "
"
-#define MAX_MUTANT_ROWS 4
-
-/datum/preferences/proc/ShowChoices(mob/user)
- if(!user || !user.client)
- return
- if(current_tab == 2) //CITADEL EDIT, for muh nudies
- update_preview_icon(nude=TRUE)
- else
- update_preview_icon(nude=FALSE) //EDIT END
- user << browse_rsc(preview_icon, "previewicon.png")
- var/list/dat = list("")
-
- dat += "Character Settings"
- dat += "Character Appearance"
- dat += "Loadout"
- dat += "Game Preferences"
-
- if(!path)
- dat += " Please create an account to save your preferences "
-
- dat += ""
-
- dat += " "
-
- switch(current_tab)
- if (0) // Character Settings#
- if(path)
- var/savefile/S = new /savefile(path)
- if(S)
- dat += ""
- var/name
- var/unspaced_slots = 0
- for(var/i=1, i<=max_save_slots, i++)
- unspaced_slots++
- if(unspaced_slots > 4)
- dat += " "
- unspaced_slots = 0
- S.cd = "/character[i]"
- S["real_name"] >> name
- if(!name)
- name = "Character[i]"
- dat += "[name] "
- dat += ""
-
- dat += "Occupation Choices"
- dat += "Set Occupation Preferences "
- if(CONFIG_GET(flag/roundstart_traits))
- dat += "Quirk Setup"
- dat += "Configure Quirks "
- dat += "Current Quirks: [all_quirks.len ? all_quirks.Join(", ") : "None"]"
- dat += "Identity"
- dat += ""
-
- //Character Appearance
- if(2)
- update_preview_icon(nude=TRUE)
- user << browse_rsc(preview_icon, "previewicon.png")
- dat += ""
- dat += ""
- dat += "Set Flavor Text "
- if(lentext(features["flavor_text"]) <= 40)
- if(!lentext(features["flavor_text"]))
- dat += "\[...\]"
- else
- dat += "[features["flavor_text"]]"
- else
- dat += "[TextPreview(features["flavor_text"])]... "
- dat += "Body"
- dat += "Gender: [gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))] "
- dat += "Species:[pref_species.id] "
- dat += "Random Body "
- dat += "Always Random Body: [be_random_body ? "Yes" : "No"] "
-
- var/use_skintones = pref_species.use_skintones
- if(use_skintones)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Skin Tone"
-
- dat += "[skin_tone] "
-
- var/mutant_colors
- if((MUTCOLORS in pref_species.species_traits) || (MUTCOLORS_PARTSONLY in pref_species.species_traits))
- if(!use_skintones)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Body Colors "
- dat += "Primary Color: Change "
- dat += "Secondary Color: Change "
- dat += "Tertiary Color: Change "
- mutant_colors = TRUE
-
- if((EYECOLOR in pref_species.species_traits) && !(NOEYES in pref_species.species_traits))
-
- if(!use_skintones && !mutant_colors)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Eye Color"
-
- dat += " Change "
-
- dat += " | "
- else if(use_skintones || mutant_colors)
- dat += ""
-
- if(HAIR in pref_species.species_traits)
-
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Hair Style"
-
- dat += "[hair_style] "
- dat += "< > "
- dat += " Change "
-
- dat += "Facial Hair Style"
-
- dat += "[facial_hair_style] "
- dat += "< > "
- dat += " Change "
-
- dat += ""
- //Mutant stuff
- var/mutant_category = 0
-
- if("tail_lizard" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Tail"
-
- dat += "[features["tail_lizard"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
-
- if("mam_tail" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Tail"
-
- dat += "[features["mam_tail"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("tail_human" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Tail"
-
- dat += "[features["tail_human"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("snout" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Snout"
-
- dat += "[features["snout"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("horns" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Horns"
-
- dat += "[features["horns"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- if("frills" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Frills"
-
- dat += "[features["frills"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
-
- if("spines" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Spines"
-
- dat += "[features["spines"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
-
- if("body_markings" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Body Markings"
-
- dat += "[features["body_markings"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("mam_body_markings" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Species Markings"
-
- dat += "[features["mam_body_markings"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
-
- if("mam_ears" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Ears"
-
- dat += "[features["mam_ears"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("ears" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Ears"
-
- dat += "[features["ears"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("legs" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Legs"
-
- dat += "[features["legs"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("moth_wings" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Moth wings"
-
- dat += "[features["moth_wings"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("taur" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Tauric Body"
-
- dat += "[features["taur"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("wings" in pref_species.mutant_bodyparts && GLOB.r_wings_list.len >1)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Wings"
-
- dat += "[features["wings"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("xenohead" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Caste Head"
-
- dat += "[features["xenohead"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("xenotail" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Tail"
-
- dat += "[features["xenotail"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("xenodorsal" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Dorsal Spines"
-
- dat += "[features["xenodorsal"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("ipc_screen" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Screen"
-
- dat += "[features["ipc_screen"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
- if("ipc_antenna" in pref_species.default_features)
- if(!mutant_category)
- dat += APPEARANCE_CATEGORY_COLUMN
-
- dat += "Antenna"
-
- dat += "[features["ipc_antenna"]] "
-
- mutant_category++
- if(mutant_category >= MAX_MUTANT_ROWS)
- dat += ""
- mutant_category = 0
-
- if(mutant_category)
- dat += ""
- mutant_category = 0
-
- dat += " "
-
- dat += " | "
-
- dat += "Clothing & Equipment"
-
- dat += "Underwear:[underwear] "
- dat += "Undershirt:[undershirt] "
- dat += "Socks:[socks] "
- dat += "Backpack:[backbag] "
- dat += "Uplink Location:[uplink_spawn_loc] "
-
- dat += "Genitals"
- if(NOGENITALS in pref_species.species_traits)
- dat += "Your species ([pref_species.name]) does not support genitals! "
- else
- if(pref_species.use_skintones)
- dat += "Genitals use skintone:[features["genitals_use_skintone"] == TRUE ? "Yes" : "No"] "
- dat += "Has Penis:[features["has_cock"] == TRUE ? "Yes" : "No"] "
- if(features["has_cock"] == TRUE)
- if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE)
- dat += "Penis Color: (Skin tone overriding) "
- else
- dat += "Penis Color: Change "
- dat += "Penis Shape: [features["cock_shape"]] "
- dat += "Penis Length: [features["cock_length"]] inch(es) "
- dat += "Has Testicles:[features["has_balls"] == TRUE ? "Yes" : "No"] "
- if(features["has_balls"] == TRUE)
- if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE)
- dat += "Testicles Color: (Skin tone overriding) "
- else
- dat += "Testicles Color: Change "
- dat += "Has Vagina:[features["has_vag"] == TRUE ? "Yes" : "No"] "
- if(features["has_vag"])
- dat += "Vagina Type: [features["vag_shape"]] "
- if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE)
- dat += "Vagina Color: (Skin tone overriding) "
- else
- dat += "Vagina Color: Change "
- dat += "Has Womb:[features["has_womb"] == TRUE ? "Yes" : "No"] "
- dat += "Has Breasts:[features["has_breasts"] == TRUE ? "Yes" : "No"] "
- if(features["has_breasts"])
- if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE)
- dat += "Color: (Skin tone overriding) "
- else
- dat += "Color: Change "
- dat += "Cup Size:[features["breasts_size"]] "
- dat += "Breast Shape:[features["breasts_shape"]] "
- dat += " | "
-
- if (1) // Game Preferences
- dat += ""
- if(unlock_content)
- dat += "Ghost Form: [ghost_form]
"
- dat += "Ghost Orbit: [ghost_orbit]
"
- var/button_name = "If you see this something went wrong."
- switch(ghost_accs)
- if(GHOST_ACCS_FULL)
- button_name = GHOST_ACCS_FULL_NAME
- if(GHOST_ACCS_DIR)
- button_name = GHOST_ACCS_DIR_NAME
- if(GHOST_ACCS_NONE)
- button_name = GHOST_ACCS_NONE_NAME
-
- dat += "Ghost Accessories: [button_name]
"
- switch(ghost_others)
- if(GHOST_OTHERS_THEIR_SETTING)
- button_name = GHOST_OTHERS_THEIR_SETTING_NAME
- if(GHOST_OTHERS_DEFAULT_SPRITE)
- button_name = GHOST_OTHERS_DEFAULT_SPRITE_NAME
- if(GHOST_OTHERS_SIMPLE)
- button_name = GHOST_OTHERS_SIMPLE_NAME
-
- dat += "Ghosts of Others: [button_name]
"
- dat += "
"
- dat += "FPS: [clientfps]
"
- dat += "Parallax (Fancy Space): "
- switch (parallax)
- if (PARALLAX_LOW)
- dat += "Low"
- if (PARALLAX_MED)
- dat += "Medium"
- if (PARALLAX_INSANE)
- dat += "Insane"
- if (PARALLAX_DISABLE)
- dat += "Disabled"
- else
- dat += "High"
- dat += "
"
- dat += "Ambient Occlusion: [ambientocclusion ? "Enabled" : "Disabled"]
"
- dat += "Fit Viewport: [auto_fit_viewport ? "Auto" : "Manual"]
"
-
- if (CONFIG_GET(flag/maprotation) && CONFIG_GET(flag/tgstyle_maprotation))
- var/p_map = preferred_map
- if (!p_map)
- p_map = "Default"
- if (config.defaultmap)
- p_map += " ([config.defaultmap.map_name])"
- else
- if (p_map in config.maplist)
- var/datum/map_config/VM = config.maplist[p_map]
- if (!VM)
- p_map += " (No longer exists)"
- else
- p_map = VM.map_name
- else
- p_map += " (No longer exists)"
- if(CONFIG_GET(flag/allow_map_voting))
- dat += "Preferred Map: [p_map]
"
-
- dat += ""
-
- dat += "Special Role Settings"
-
- if(jobban_isbanned(user, ROLE_SYNDICATE))
- dat += "You are banned from antagonist roles."
- src.be_special = list()
-
-
- for (var/i in GLOB.special_roles)
- if(jobban_isbanned(user, i))
- dat += "Be [capitalize(i)]: BANNED "
- else
- var/days_remaining = null
- if(ispath(GLOB.special_roles[i]) && CONFIG_GET(flag/use_age_restriction_for_jobs)) //If it's a game mode antag, check if the player meets the minimum age
- var/mode_path = GLOB.special_roles[i]
- var/datum/game_mode/temp_mode = new mode_path
- days_remaining = temp_mode.get_remaining_days(user.client)
-
- if(days_remaining)
- dat += "Be [capitalize(i)]: \[IN [days_remaining] DAYS] "
- else
- dat += "Be [capitalize(i)]: [(i in be_special) ? "Enabled" : "Disabled"] "
- dat += "Midround Antagonist: [(toggles & MIDROUND_ANTAG) ? "Enabled" : "Disabled"] "
-
- dat += " "
- dat += "Citadel Preferences" //Because fuck me if preferences can't be fucking modularized and expected to update in a reasonable timeframe.
- dat += "Arousal:[arousable == TRUE ? "Enabled" : "Disabled"] "
- dat += "Exhibitionist:[features["exhibitionist"] == TRUE ? "Yes" : "No"] "
- dat += "Voracious MediHound sleepers: [(cit_toggles & MEDIHOUND_SLEEPER) ? "Yes" : "No"] "
- dat += "Hear Vore Sounds: [(cit_toggles & EATING_NOISES) ? "Yes" : "No"] "
- dat += "Hear Vore Digestion Sounds: [(cit_toggles & DIGESTION_NOISES) ? "Yes" : "No"] "
- dat += "Widescreen: [widescreenpref ? "Enabled ([CONFIG_GET(string/default_view)])" : "Disabled (15x15)"] "
- dat += "Auto stand: [autostand ? "Enabled" : "Disabled"] "
- dat += "Screen Shake: [(screenshake==100) ? "Full" : ((screenshake==0) ? "None" : "[screenshake]")] "
- if (user && user.client && !user.client.prefs.screenshake==0)
- dat += "Damage Screen Shake: [(damagescreenshake==1) ? "On" : ((damagescreenshake==0) ? "Off" : "Only when down")] "
- dat += " "
-
- if(3)
- if(!gear_tab)
- gear_tab = GLOB.loadout_items[1]
- dat += ""
- dat += "| [gear_points] loadout points remaining. \[Clear Loadout\] | "
- dat += "| You can only choose one item per category, unless it's an item that spawns in your backpack or hands. | "
- dat += "| "
- var/firstcat = TRUE
- for(var/i in GLOB.loadout_items)
- if(firstcat)
- firstcat = FALSE
- else
- dat += " |"
- if(i == gear_tab)
- dat += " [i] "
- else
- dat += " [i] "
- dat += " | "
- dat += "
| "
- dat += "| [gear_tab] | "
- dat += "
| "
- dat += "| Name | "
- dat += "Cost | "
- dat += "Restrictions | "
- dat += "Description | "
- for(var/j in GLOB.loadout_items[gear_tab])
- var/datum/gear/gear = GLOB.loadout_items[gear_tab][j]
- var/donoritem
- if(gear.ckeywhitelist && gear.ckeywhitelist.len)
- donoritem = TRUE
- if(!(user.ckey in gear.ckeywhitelist))
- continue
- var/class_link = ""
- if(gear.type in chosen_gear)
- class_link = "style='white-space:normal;' class='linkOn' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(j)];toggle_gear=0'"
- else if(gear_points <= 0)
- class_link = "style='white-space:normal;' class='linkOff'"
- else if(donoritem)
- class_link = "style='white-space:normal;background:#ebc42e;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(j)];toggle_gear=1'"
- else
- class_link = "style='white-space:normal;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(j)];toggle_gear=1'"
- dat += "| [j] | "
- dat += "[gear.cost] | "
- if(islist(gear.restricted_roles))
- if(gear.restricted_roles.len)
- dat += ""
- dat += gear.restricted_roles.Join(";")
- dat += ""
- dat += " | [gear.description] | "
- dat += " "
-
- dat += " "
-
- if(!IsGuestKey(user.key))
- dat += "Undo "
- dat += "Save Setup "
-
- dat += "Reset Setup"
- dat += ""
-
- var/datum/browser/popup = new(user, "preferences", "Character Setup ", 640, 770)
- popup.set_content(dat.Join())
- popup.open(0)
-
-#undef APPEARANCE_CATEGORY_COLUMN
-#undef MAX_MUTANT_ROWS
-
-/datum/preferences/proc/SetChoices(mob/user, limit = 17, list/splitJobs = list("Chief Engineer"), widthPerColumn = 295, height = 620)
- if(!SSjob)
- return
-
- //limit - The amount of jobs allowed per column. Defaults to 17 to make it look nice.
- //splitJobs - Allows you split the table by job. You can make different tables for each department by including their heads. Defaults to CE to make it look nice.
- //widthPerColumn - Screen's width for every column.
- //height - Screen's height.
-
- var/width = widthPerColumn
-
- var/HTML = ""
- if(SSjob.occupations.len <= 0)
- HTML += "The job SSticker is not yet finished creating jobs, please try again later"
- HTML += "Done " // Easier to press up here.
-
- else
- HTML += "Choose occupation chances "
- HTML += "Left-click to raise an occupation preference, right-click to lower it.
"
- HTML += "Done " // Easier to press up here.
- HTML += ""
- HTML += "" // Table within a table for alignment, also allows you to easily add more colomns.
- HTML += ""
- var/index = -1
-
- //The job before the current job. I only use this to get the previous jobs color when I'm filling in blank rows.
- var/datum/job/lastJob
-
- var/datum/job/overflow = SSjob.GetJob(SSjob.overflow_role)
-
- for(var/datum/job/job in SSjob.occupations)
-
- index += 1
- if((index >= limit) || (job.title in splitJobs))
- width += widthPerColumn
- if((index < limit) && (lastJob != null))
- //If the cells were broken up by a job in the splitJob list then it will fill in the rest of the cells with
- //the last job's selection color. Creating a rather nice effect.
- for(var/i = 0, i < (limit - index), i += 1)
- HTML += "|   |   | "
- HTML += " | "
- index = 0
-
- HTML += "| "
- var/rank = job.title
- lastJob = job
- if(jobban_isbanned(user, rank))
- HTML += "[rank] | BANNED | "
- continue
- var/required_playtime_remaining = job.required_playtime_remaining(user.client)
- if(required_playtime_remaining)
- HTML += "[rank] \[ [get_exp_format(required_playtime_remaining)] as [job.get_exp_req_type()] \] | "
- continue
- if(!job.player_old_enough(user.client))
- var/available_in_days = job.available_in_days(user.client)
- HTML += "[rank] \[IN [(available_in_days)] DAYS\] | "
- continue
- if((job_civilian_low & overflow.flag) && (rank != SSjob.overflow_role) && !jobban_isbanned(user, SSjob.overflow_role))
- HTML += "[rank] | "
- continue
- if((rank in GLOB.command_positions) || (rank == "AI"))//Bold head jobs
- HTML += "[rank]"
- else
- HTML += "[rank]"
-
- HTML += ""
-
- var/prefLevelLabel = "ERROR"
- var/prefLevelColor = "pink"
- var/prefUpperLevel = -1 // level to assign on left click
- var/prefLowerLevel = -1 // level to assign on right click
-
- if(GetJobDepartment(job, 1) & job.flag)
- prefLevelLabel = "High"
- prefLevelColor = "slateblue"
- prefUpperLevel = 4
- prefLowerLevel = 2
- else if(GetJobDepartment(job, 2) & job.flag)
- prefLevelLabel = "Medium"
- prefLevelColor = "green"
- prefUpperLevel = 1
- prefLowerLevel = 3
- else if(GetJobDepartment(job, 3) & job.flag)
- prefLevelLabel = "Low"
- prefLevelColor = "orange"
- prefUpperLevel = 2
- prefLowerLevel = 4
- else
- prefLevelLabel = "NEVER"
- prefLevelColor = "red"
- prefUpperLevel = 3
- prefLowerLevel = 1
-
-
- HTML += ""
-
- if(rank == SSjob.overflow_role)//Overflow is special
- if(job_civilian_low & overflow.flag)
- HTML += "Yes"
- else
- HTML += "No"
- HTML += " | "
- continue
-
- HTML += "[prefLevelLabel]"
- HTML += ""
-
- for(var/i = 1, i < (limit - index), i += 1) // Finish the column so it is even
- HTML += "|   |   | "
-
- HTML += " "
- HTML += " | "
-
- var/message = "Be an [SSjob.overflow_role] if preferences unavailable"
- if(joblessrole == BERANDOMJOB)
- message = "Get random job if preferences unavailable"
- else if(joblessrole == RETURNTOLOBBY)
- message = "Return to lobby if preferences unavailable"
- HTML += " [message]"
- HTML += "Reset Preferences"
-
- user << browse(null, "window=preferences")
- var/datum/browser/popup = new(user, "mob_occupation", "Occupation Preferences ", width, height)
- popup.set_window_options("can_close=0")
- popup.set_content(HTML)
- popup.open(0)
- return
-
-/datum/preferences/proc/SetJobPreferenceLevel(datum/job/job, level)
- if (!job)
- return 0
-
- if (level == 1) // to high
- // remove any other job(s) set to high
- job_civilian_med |= job_civilian_high
- job_engsec_med |= job_engsec_high
- job_medsci_med |= job_medsci_high
- job_civilian_high = 0
- job_engsec_high = 0
- job_medsci_high = 0
-
- if (job.department_flag == CIVILIAN)
- job_civilian_low &= ~job.flag
- job_civilian_med &= ~job.flag
- job_civilian_high &= ~job.flag
-
- switch(level)
- if (1)
- job_civilian_high |= job.flag
- if (2)
- job_civilian_med |= job.flag
- if (3)
- job_civilian_low |= job.flag
-
- return 1
- else if (job.department_flag == ENGSEC)
- job_engsec_low &= ~job.flag
- job_engsec_med &= ~job.flag
- job_engsec_high &= ~job.flag
-
- switch(level)
- if (1)
- job_engsec_high |= job.flag
- if (2)
- job_engsec_med |= job.flag
- if (3)
- job_engsec_low |= job.flag
-
- return 1
- else if (job.department_flag == MEDSCI)
- job_medsci_low &= ~job.flag
- job_medsci_med &= ~job.flag
- job_medsci_high &= ~job.flag
-
- switch(level)
- if (1)
- job_medsci_high |= job.flag
- if (2)
- job_medsci_med |= job.flag
- if (3)
- job_medsci_low |= job.flag
-
- return 1
-
- return 0
-
-/datum/preferences/proc/UpdateJobPreference(mob/user, role, desiredLvl)
- if(!SSjob || SSjob.occupations.len <= 0)
- return
- var/datum/job/job = SSjob.GetJob(role)
-
- if(!job)
- user << browse(null, "window=mob_occupation")
- ShowChoices(user)
- return
-
- if (!isnum(desiredLvl))
- to_chat(user, "UpdateJobPreference - desired level was not a number. Please notify coders!")
- ShowChoices(user)
- return
-
- if(role == SSjob.overflow_role)
- if(job_civilian_low & job.flag)
- job_civilian_low &= ~job.flag
- else
- job_civilian_low |= job.flag
- SetChoices(user)
- return 1
-
- SetJobPreferenceLevel(job, desiredLvl)
- SetChoices(user)
-
- return 1
-
-
-/datum/preferences/proc/ResetJobs()
-
- job_civilian_high = 0
- job_civilian_med = 0
- job_civilian_low = 0
-
- job_medsci_high = 0
- job_medsci_med = 0
- job_medsci_low = 0
-
- job_engsec_high = 0
- job_engsec_med = 0
- job_engsec_low = 0
-
-
-/datum/preferences/proc/GetJobDepartment(datum/job/job, level)
- if(!job || !level)
- return 0
- switch(job.department_flag)
- if(CIVILIAN)
- switch(level)
- if(1)
- return job_civilian_high
- if(2)
- return job_civilian_med
- if(3)
- return job_civilian_low
- if(MEDSCI)
- switch(level)
- if(1)
- return job_medsci_high
- if(2)
- return job_medsci_med
- if(3)
- return job_medsci_low
- if(ENGSEC)
- switch(level)
- if(1)
- return job_engsec_high
- if(2)
- return job_engsec_med
- if(3)
- return job_engsec_low
- return 0
-
-/datum/preferences/proc/SetQuirks(mob/user)
- if(!SSquirks)
- to_chat(user, "The quirk subsystem is still initializing! Try again in a minute.")
- return
-
- var/list/dat = list()
- if(!SSquirks.quirks.len)
- dat += "The quirk subsystem hasn't finished initializing, please hold..."
- dat += "Done "
-
- else
- dat += "Choose quirk setup "
- dat += "Left-click to add or remove quirks. You need negative quirks to have positive ones. \
- Quirks are applied at roundstart and cannot normally be removed. "
- dat += "Done"
- dat += " "
- dat += "Current quirks: [all_quirks.len ? all_quirks.Join(", ") : "None"]"
- dat += "[positive_quirks.len] / [MAX_QUIRKS] max positive quirks \
- Quirk balance remaining: [GetQuirkBalance()] "
- for(var/V in SSquirks.quirks)
- var/datum/quirk/T = SSquirks.quirks[V]
- var/quirk_name = initial(T.name)
- var/has_quirk
- var/quirk_cost = initial(T.value) * -1
- var/lock_reason = "This trait is unavailable."
- var/quirk_conflict = FALSE
- for(var/_V in all_quirks)
- if(_V == quirk_name)
- has_quirk = TRUE
- if(initial(T.mood_quirk) && CONFIG_GET(flag/disable_human_mood))
- lock_reason = "Mood is disabled."
- quirk_conflict = TRUE
- if(has_quirk)
- if(quirk_conflict)
- all_quirks -= quirk_name
- has_quirk = FALSE
- else
- quirk_cost *= -1 //invert it back, since we'd be regaining this amount
- if(quirk_cost > 0)
- quirk_cost = "+[quirk_cost]"
- var/font_color = "#AAAAFF"
- if(initial(T.value) != 0)
- font_color = initial(T.value) > 0 ? "#AAFFAA" : "#FFAAAA"
- if(quirk_conflict)
- dat += "[quirk_name] - [initial(T.desc)] \
- LOCKED: [lock_reason] "
- else
- if(has_quirk)
- dat += "[quirk_name] - [initial(T.desc)] \
- [has_quirk ? "Lose" : "Take"] ([quirk_cost] pts.) "
- else
- dat += "[quirk_name] - [initial(T.desc)] \
- [has_quirk ? "Lose" : "Take"] ([quirk_cost] pts.) "
- dat += " Reset Traits"
-
- user << browse(null, "window=preferences")
- var/datum/browser/popup = new(user, "mob_occupation", "Quirk Preferences ", 900, 600) //no reason not to reuse the occupation window, as it's cleaner that way
- popup.set_window_options("can_close=0")
- popup.set_content(dat.Join())
- popup.open(0)
- return
-
-/datum/preferences/proc/GetQuirkBalance()
- var/bal = 0
- for(var/V in all_quirks)
- var/datum/quirk/T = SSquirks.quirks[V]
- bal -= initial(T.value)
- return bal
-
-/datum/preferences/proc/process_link(mob/user, list/href_list)
- if(href_list["jobbancheck"])
- var/job = sanitizeSQL(href_list["jobbancheck"])
- var/sql_ckey = sanitizeSQL(user.ckey)
- var/datum/DBQuery/query_get_jobban = SSdbcore.NewQuery("SELECT reason, bantime, duration, expiration_time, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].a_ckey), a_ckey) FROM [format_table_name("ban")] WHERE ckey = '[sql_ckey]' AND (bantype = 'JOB_PERMABAN' OR (bantype = 'JOB_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned) AND job = '[job]'")
- if(!query_get_jobban.warn_execute())
- qdel(query_get_jobban)
- return
- if(query_get_jobban.NextRow())
- var/reason = query_get_jobban.item[1]
- var/bantime = query_get_jobban.item[2]
- var/duration = query_get_jobban.item[3]
- var/expiration_time = query_get_jobban.item[4]
- var/admin_key = query_get_jobban.item[5]
- var/text
- text = "You, or another user of this computer, ([user.key]) is banned from playing [job]. The ban reason is: [reason] This ban was applied by [admin_key] on [bantime]"
- if(text2num(duration) > 0)
- text += ". The ban is for [duration] minutes and expires on [expiration_time] (server time)"
- text += "."
- to_chat(user, text)
- qdel(query_get_jobban)
- return
-
- if(href_list["preference"] == "job")
- switch(href_list["task"])
- if("close")
- user << browse(null, "window=mob_occupation")
- ShowChoices(user)
- if("reset")
- ResetJobs()
- SetChoices(user)
- if("random")
- switch(joblessrole)
- if(RETURNTOLOBBY)
- if(jobban_isbanned(user, SSjob.overflow_role))
- joblessrole = BERANDOMJOB
- else
- joblessrole = BEOVERFLOW
- if(BEOVERFLOW)
- joblessrole = BERANDOMJOB
- if(BERANDOMJOB)
- joblessrole = RETURNTOLOBBY
- SetChoices(user)
- if("setJobLevel")
- UpdateJobPreference(user, href_list["text"], text2num(href_list["level"]))
- else
- SetChoices(user)
- return 1
-
- else if(href_list["preference"] == "trait")
- switch(href_list["task"])
- if("close")
- user << browse(null, "window=mob_occupation")
- ShowChoices(user)
- if("update")
- var/quirk = href_list["trait"]
- if(!SSquirks.quirks[quirk])
- return
- var/value = SSquirks.quirk_points[quirk]
- if(value == 0)
- if(quirk in neutral_quirks)
- neutral_quirks -= quirk
- all_quirks -= quirk
- else
- neutral_quirks += quirk
- all_quirks += quirk
- else
- var/balance = GetQuirkBalance()
- if(quirk in positive_quirks)
- positive_quirks -= quirk
- all_quirks -= quirk
- else if(quirk in negative_quirks)
- if(balance + value < 0)
- to_chat(user, "Refunding this would cause you to go below your balance!")
- return
- negative_quirks -= quirk
- all_quirks -= quirk
- else if(value > 0)
- if(positive_quirks.len >= MAX_QUIRKS)
- to_chat(user, "You can't have more than [MAX_QUIRKS] positive quirks!")
- return
- if(balance - value < 0)
- to_chat(user, "You don't have enough balance to gain this quirk!")
- return
- positive_quirks += quirk
- all_quirks += quirk
- else
- negative_quirks += quirk
- all_quirks += quirk
- SetQuirks(user)
- if("reset")
- all_quirks = list()
- positive_quirks = list()
- negative_quirks = list()
- neutral_quirks = list()
- SetQuirks(user)
- else
- SetQuirks(user)
- return TRUE
-
- switch(href_list["task"])
- if("random")
- switch(href_list["preference"])
- if("name")
- real_name = pref_species.random_name(gender,1)
- if("age")
- age = rand(AGE_MIN, AGE_MAX)
- if("hair")
- hair_color = random_short_color()
- if("hair_style")
- hair_style = random_hair_style(gender)
- if("facial")
- facial_hair_color = random_short_color()
- if("facial_hair_style")
- facial_hair_style = random_facial_hair_style(gender)
- if("underwear")
- underwear = random_underwear(gender)
- if("undershirt")
- undershirt = random_undershirt(gender)
- if("socks")
- socks = random_socks()
- if(BODY_ZONE_PRECISE_EYES)
- eye_color = random_eye_color()
- if("s_tone")
- skin_tone = random_skin_tone()
- if("bag")
- backbag = pick(GLOB.backbaglist)
- if("all")
- random_character()
-
- if("input")
-
- if(href_list["preference"] in GLOB.preferences_custom_names)
- ask_for_custom_name(user,href_list["preference"])
-
-
- switch(href_list["preference"])
- if("ghostform")
- if(unlock_content)
- var/new_form = input(user, "Thanks for supporting BYOND - Choose your ghostly form:","Thanks for supporting BYOND",null) as null|anything in GLOB.ghost_forms
- if(new_form)
- ghost_form = new_form
- if("ghostorbit")
- if(unlock_content)
- var/new_orbit = input(user, "Thanks for supporting BYOND - Choose your ghostly orbit:","Thanks for supporting BYOND", null) as null|anything in GLOB.ghost_orbits
- if(new_orbit)
- ghost_orbit = new_orbit
-
- if("ghostaccs")
- var/new_ghost_accs = alert("Do you want your ghost to show full accessories where possible, hide accessories but still use the directional sprites where possible, or also ignore the directions and stick to the default sprites?",,GHOST_ACCS_FULL_NAME, GHOST_ACCS_DIR_NAME, GHOST_ACCS_NONE_NAME)
- switch(new_ghost_accs)
- if(GHOST_ACCS_FULL_NAME)
- ghost_accs = GHOST_ACCS_FULL
- if(GHOST_ACCS_DIR_NAME)
- ghost_accs = GHOST_ACCS_DIR
- if(GHOST_ACCS_NONE_NAME)
- ghost_accs = GHOST_ACCS_NONE
-
- if("ghostothers")
- var/new_ghost_others = alert("Do you want the ghosts of others to show up as their own setting, as their default sprites or always as the default white ghost?",,GHOST_OTHERS_THEIR_SETTING_NAME, GHOST_OTHERS_DEFAULT_SPRITE_NAME, GHOST_OTHERS_SIMPLE_NAME)
- switch(new_ghost_others)
- if(GHOST_OTHERS_THEIR_SETTING_NAME)
- ghost_others = GHOST_OTHERS_THEIR_SETTING
- if(GHOST_OTHERS_DEFAULT_SPRITE_NAME)
- ghost_others = GHOST_OTHERS_DEFAULT_SPRITE
- if(GHOST_OTHERS_SIMPLE_NAME)
- ghost_others = GHOST_OTHERS_SIMPLE
-
- if("name")
- var/new_name = input(user, "Choose your character's name:", "Character Preference") as text|null
- if(new_name)
- new_name = reject_bad_name(new_name)
- if(new_name)
- real_name = new_name
- else
- to_chat(user, "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and .")
-
- if("age")
- var/new_age = input(user, "Choose your character's age:\n([AGE_MIN]-[AGE_MAX])", "Character Preference") as num|null
- if(new_age)
- age = max(min( round(text2num(new_age)), AGE_MAX),AGE_MIN)
-
- if("flavor_text")
- var/msg = stripped_multiline_input(usr,"Set the flavor text in your 'examine' verb. This can also be used for OOC notes and preferences!","Flavor Text",html_decode(features["flavor_text"]), MAX_MESSAGE_LEN*2, TRUE) as null|message
- if(!isnull(msg))
- msg = copytext(msg, 1, MAX_MESSAGE_LEN*2)
- features["flavor_text"] = msg
-
- if("hair")
- var/new_hair = input(user, "Choose your character's hair colour:", "Character Preference","#"+hair_color) as color|null
- if(new_hair)
- hair_color = sanitize_hexcolor(new_hair)
-
- if("hair_style")
- var/new_hair_style
- if(gender == MALE)
- new_hair_style = input(user, "Choose your character's hair style:", "Character Preference") as null|anything in GLOB.hair_styles_male_list
- else
- new_hair_style = input(user, "Choose your character's hair style:", "Character Preference") as null|anything in GLOB.hair_styles_female_list
- if(new_hair_style)
- hair_style = new_hair_style
-
- if("next_hair_style")
- if (gender == MALE)
- hair_style = next_list_item(hair_style, GLOB.hair_styles_male_list)
- else
- hair_style = next_list_item(hair_style, GLOB.hair_styles_female_list)
-
- if("previous_hair_style")
- if (gender == MALE)
- hair_style = previous_list_item(hair_style, GLOB.hair_styles_male_list)
- else
- hair_style = previous_list_item(hair_style, GLOB.hair_styles_female_list)
-
- if("facial")
- var/new_facial = input(user, "Choose your character's facial-hair colour:", "Character Preference","#"+facial_hair_color) as color|null
- if(new_facial)
- facial_hair_color = sanitize_hexcolor(new_facial)
- if("facial_hair_style")
- var/new_facial_hair_style
- if(gender == MALE)
- new_facial_hair_style = input(user, "Choose your character's facial-hair style:", "Character Preference") as null|anything in GLOB.facial_hair_styles_male_list
- else
- new_facial_hair_style = input(user, "Choose your character's facial-hair style:", "Character Preference") as null|anything in GLOB.facial_hair_styles_female_list
- if(new_facial_hair_style)
- facial_hair_style = new_facial_hair_style
-
- if("next_facehair_style")
- if (gender == MALE)
- facial_hair_style = next_list_item(facial_hair_style, GLOB.facial_hair_styles_male_list)
- else
- facial_hair_style = next_list_item(facial_hair_style, GLOB.facial_hair_styles_female_list)
- if("previous_facehair_style")
- if (gender == MALE)
- facial_hair_style = previous_list_item(facial_hair_style, GLOB.facial_hair_styles_male_list)
- else
- facial_hair_style = previous_list_item(facial_hair_style, GLOB.facial_hair_styles_female_list)
-
- if("underwear")
- var/new_underwear
- if(gender == MALE)
- new_underwear = input(user, "Choose your character's underwear:", "Character Preference") as null|anything in GLOB.underwear_m
- else
- new_underwear = input(user, "Choose your character's underwear:", "Character Preference") as null|anything in GLOB.underwear_f
- if(new_underwear)
- underwear = new_underwear
-
- if("undershirt")
- var/new_undershirt
- if(gender == MALE)
- new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in GLOB.undershirt_m
- else
- new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in GLOB.undershirt_f
- if(new_undershirt)
- undershirt = new_undershirt
-
- if("socks")
- var/new_socks
- new_socks = input(user, "Choose your character's socks:", "Character Preference") as null|anything in GLOB.socks_list
- if(new_socks)
- socks = new_socks
-
- if("eyes")
- var/new_eyes = input(user, "Choose your character's eye colour:", "Character Preference","#"+eye_color) as color|null
- if(new_eyes)
- eye_color = sanitize_hexcolor(new_eyes)
-
- if("species")
- var/result = input(user, "Select a species", "Species Selection") as null|anything in GLOB.roundstart_races
- if(result)
- var/newtype = GLOB.species_list[result]
- pref_species = new newtype()
- //Now that we changed our species, we must verify that the mutant colour is still allowed.
- var/temp_hsv = RGBtoHSV(features["mcolor"])
- if(features["mcolor"] == "#000" || (!(MUTCOLORS_PARTSONLY in pref_species.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#202020")[3]))
- features["mcolor"] = pref_species.default_color
- if(features["mcolor2"] == "#000" || (!(MUTCOLORS_PARTSONLY in pref_species.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#202020")[3]))
- features["mcolor2"] = pref_species.default_color
- if(features["mcolor3"] == "#000" || (!(MUTCOLORS_PARTSONLY in pref_species.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#202020")[3]))
- features["mcolor3"] = pref_species.default_color
-
- if("mutant_color")
- var/new_mutantcolor = input(user, "Choose your character's alien/mutant color:", "Character Preference","#"+features["mcolor"]) as color|null
- if(new_mutantcolor)
- var/temp_hsv = RGBtoHSV(new_mutantcolor)
- if(new_mutantcolor == "#000000")
- features["mcolor"] = pref_species.default_color
- else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) // mutantcolors must be bright, but only if they affect the skin
- features["mcolor"] = sanitize_hexcolor(new_mutantcolor)
- else
- to_chat(user, "Invalid color. Your color is not bright enough.")
-
- if("mutant_color2")
- var/new_mutantcolor = input(user, "Choose your character's secondary alien/mutant color:", "Character Preference") as color|null
- if(new_mutantcolor)
- var/temp_hsv = RGBtoHSV(new_mutantcolor)
- if(new_mutantcolor == "#000000")
- features["mcolor2"] = pref_species.default_color
- else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) // mutantcolors must be bright, but only if they affect the skin
- features["mcolor2"] = sanitize_hexcolor(new_mutantcolor)
- else
- to_chat(user, "Invalid color. Your color is not bright enough.")
-
- if("mutant_color3")
- var/new_mutantcolor = input(user, "Choose your character's tertiary alien/mutant color:", "Character Preference") as color|null
- if(new_mutantcolor)
- var/temp_hsv = RGBtoHSV(new_mutantcolor)
- if(new_mutantcolor == "#000000")
- features["mcolor3"] = pref_species.default_color
- else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) // mutantcolors must be bright, but only if they affect the skin
- features["mcolor3"] = sanitize_hexcolor(new_mutantcolor)
- else
- to_chat(user, "Invalid color. Your color is not bright enough.")
-
- if("ipc_screen")
- var/new_ipc_screen
- new_ipc_screen = input(user, "Choose your character's screen:", "Character Preference") as null|anything in GLOB.ipc_screens_list
- if(new_ipc_screen)
- features["ipc_screen"] = new_ipc_screen
-
- if("ipc_antenna")
- var/new_ipc_antenna
- new_ipc_antenna = input(user, "Choose your character's antenna:", "Character Preference") as null|anything in GLOB.ipc_antennas_list
- if(new_ipc_antenna)
- features["ipc_antenna"] = new_ipc_antenna
-
- if("tail_lizard")
- var/new_tail
- new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in GLOB.tails_list_lizard
- if(new_tail)
- features["tail_lizard"] = new_tail
- if(new_tail != "None")
- features["taur"] = "None"
- features["tail_human"] = "None"
- features["mam_tail"] = "None"
-
- if("tail_human")
- var/list/snowflake_tails_list = list()
- for(var/path in GLOB.tails_list_human)
- var/datum/sprite_accessory/tails/human/instance = GLOB.tails_list_human[path]
- if(istype(instance, /datum/sprite_accessory))
- var/datum/sprite_accessory/S = instance
- if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
- snowflake_tails_list[S.name] = path
- var/new_tail
- new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in snowflake_tails_list
- if(new_tail)
- features["tail_human"] = new_tail
- if(new_tail != "None")
- features["taur"] = "None"
- features["tail_lizard"] = "None"
- features["mam_tail"] = "None"
-
- if("mam_tail")
- var/list/snowflake_tails_list = list()
- for(var/path in GLOB.mam_tails_list)
- var/datum/sprite_accessory/mam_tails/instance = GLOB.mam_tails_list[path]
- if(istype(instance, /datum/sprite_accessory))
- var/datum/sprite_accessory/S = instance
- if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
- snowflake_tails_list[S.name] = path
- var/new_tail
- new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in snowflake_tails_list
- if(new_tail)
- features["mam_tail"] = new_tail
- if(new_tail != "None")
- features["taur"] = "None"
- features["tail_human"] = "None"
- features["tail_lizard"] = "None"
-
- if("snout")
- var/new_snout
- new_snout = input(user, "Choose your character's snout:", "Character Preference") as null|anything in GLOB.snouts_list
- if(new_snout)
- features["snout"] = new_snout
-
- if("horns")
- var/new_horns
- new_horns = input(user, "Choose your character's horns:", "Character Preference") as null|anything in GLOB.horns_list
- if(new_horns)
- features["horns"] = new_horns
-
- if("ears")
- var/new_ears
- new_ears = input(user, "Choose your character's ears:", "Character Preference") as null|anything in GLOB.ears_list
- if(new_ears)
- features["ears"] = new_ears
-
- if("wings")
- var/new_wings
- new_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.r_wings_list
- if(new_wings)
- features["wings"] = new_wings
-
- if("frills")
- var/new_frills
- new_frills = input(user, "Choose your character's frills:", "Character Preference") as null|anything in GLOB.frills_list
- if(new_frills)
- features["frills"] = new_frills
-
- if("spines")
- var/new_spines
- new_spines = input(user, "Choose your character's spines:", "Character Preference") as null|anything in GLOB.spines_list
- if(new_spines)
- features["spines"] = new_spines
-
- if("body_markings")
- var/new_body_markings
- new_body_markings = input(user, "Choose your character's body markings:", "Character Preference") as null|anything in GLOB.body_markings_list
- if(new_body_markings)
- features["body_markings"] = new_body_markings
-
- if("legs")
- var/new_legs
- new_legs = input(user, "Choose your character's legs:", "Character Preference") as null|anything in GLOB.legs_list
- if(new_legs)
- features["legs"] = new_legs
-
- if("moth_wings")
- var/new_moth_wings
- new_moth_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.moth_wings_list
- if(new_moth_wings)
- features["moth_wings"] = new_moth_wings
-
- if("s_tone")
- var/new_s_tone = input(user, "Choose your character's skin-tone:", "Character Preference") as null|anything in GLOB.skin_tones
- if(new_s_tone)
- skin_tone = new_s_tone
-
- if("taur")
- var/list/snowflake_taur_list = list()
- for(var/path in GLOB.taur_list)
- var/datum/sprite_accessory/taur/instance = GLOB.taur_list[path]
- if(istype(instance, /datum/sprite_accessory))
- var/datum/sprite_accessory/S = instance
- if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
- snowflake_taur_list[S.name] = path
- var/new_taur
- new_taur = input(user, "Choose your character's tauric body:", "Character Preference") as null|anything in snowflake_taur_list
- if(new_taur)
- features["taur"] = new_taur
- if(new_taur != "None")
- features["mam_tail"] = "None"
- features["xenotail"] = "None"
- features["tail_human"] = "None"
- features["tail_lizard"] = "None"
-
- if("ears")
- var/list/snowflake_ears_list = list()
- for(var/path in GLOB.ears_list)
- var/datum/sprite_accessory/ears/instance = GLOB.ears_list[path]
- if(istype(instance, /datum/sprite_accessory))
- var/datum/sprite_accessory/S = instance
- if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
- snowflake_ears_list[S.name] = path
- var/new_ears
- new_ears = input(user, "Choose your character's ears:", "Character Preference") as null|anything in snowflake_ears_list
- if(new_ears)
- features["ears"] = new_ears
-
- if("mam_ears")
- var/list/snowflake_ears_list = list()
- for(var/path in GLOB.mam_ears_list)
- var/datum/sprite_accessory/mam_ears/instance = GLOB.mam_ears_list[path]
- if(istype(instance, /datum/sprite_accessory))
- var/datum/sprite_accessory/S = instance
- if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
- snowflake_ears_list[S.name] = path
- var/new_ears
- new_ears = input(user, "Choose your character's ears:", "Character Preference") as null|anything in snowflake_ears_list
- if(new_ears)
- features["mam_ears"] = new_ears
-
- if("mam_body_markings")
- var/list/snowflake_markings_list = list()
- for(var/path in GLOB.mam_body_markings_list)
- var/datum/sprite_accessory/mam_body_markings/instance = GLOB.mam_body_markings_list[path]
- if(istype(instance, /datum/sprite_accessory))
- var/datum/sprite_accessory/S = instance
- if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
- snowflake_markings_list[S.name] = path
- var/new_mam_body_markings
- new_mam_body_markings = input(user, "Choose your character's body markings:", "Character Preference") as null|anything in snowflake_markings_list
- if(new_mam_body_markings)
- features["mam_body_markings"] = new_mam_body_markings
-
- //Xeno Bodyparts
- if("xenohead")//Head or caste type
- var/new_head
- new_head = input(user, "Choose your character's caste:", "Character Preference") as null|anything in GLOB.xeno_head_list
- if(new_head)
- features["xenohead"] = new_head
-
- if("xenotail")//Currently one one type, more maybe later if someone sprites them. Might include animated variants in the future.
- var/new_tail
- new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in GLOB.xeno_tail_list
- if(new_tail)
- features["xenotail"] = new_tail
- if(new_tail != "None")
- features["mam_tail"] = "None"
- features["taur"] = "None"
- features["tail_human"] = "None"
- features["tail_lizard"] = "None"
-
- if("xenodorsal")
- var/new_dors
- new_dors = input(user, "Choose your character's dorsal tube type:", "Character Preference") as null|anything in GLOB.xeno_dorsal_list
- if(new_dors)
- features["xenodorsal"] = new_dors
- //Genital code
- if("cock_color")
- var/new_cockcolor = input(user, "Penis color:", "Character Preference") as color|null
- if(new_cockcolor)
- var/temp_hsv = RGBtoHSV(new_cockcolor)
- if(new_cockcolor == "#000000")
- features["cock_color"] = pref_species.default_color
- else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
- features["cock_color"] = sanitize_hexcolor(new_cockcolor)
- else
- user << "Invalid color. Your color is not bright enough."
-
- if("cock_length")
- var/new_length = input(user, "Penis length in inches:\n([COCK_SIZE_MIN]-[COCK_SIZE_MAX])", "Character Preference") as num|null
- if(new_length)
- features["cock_length"] = max(min( round(text2num(new_length)), COCK_SIZE_MAX),COCK_SIZE_MIN)
-
- if("cock_shape")
- var/new_shape
- new_shape = input(user, "Penis shape:", "Character Preference") as null|anything in GLOB.cock_shapes_list
- if(new_shape)
- features["cock_shape"] = new_shape
-
- if("balls_color")
- var/new_ballscolor = input(user, "Testicle Color:", "Character Preference") as color|null
- if(new_ballscolor)
- var/temp_hsv = RGBtoHSV(new_ballscolor)
- if(new_ballscolor == "#000000")
- features["balls_color"] = pref_species.default_color
- else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
- features["balls_color"] = sanitize_hexcolor(new_ballscolor)
- else
- user << "Invalid color. Your color is not bright enough."
-
- if("egg_size")
- var/new_size
- var/list/egg_sizes = list(1,2,3)
- new_size = input(user, "Egg Diameter(inches):", "Egg Size") as null|anything in egg_sizes
- if(new_size)
- features["eggsack_egg_size"] = new_size
-
- if("egg_color")
- var/new_egg_color = input(user, "Egg Color:", "Character Preference") as color|null
- if(new_egg_color)
- var/temp_hsv = RGBtoHSV(new_egg_color)
- if(ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
- features["eggsack_egg_color"] = sanitize_hexcolor(new_egg_color)
- else
- user << "Invalid color. Your color is not bright enough."
-
- if("breasts_size")
- var/new_size
- new_size = input(user, "Breast Size", "Character Preference") as null|anything in GLOB.breasts_size_list
- if(new_size)
- features["breasts_size"] = new_size
-
- if("breasts_shape")
- var/new_shape
- new_shape = input(user, "Breast Shape", "Character Preference") as null|anything in GLOB.breasts_shapes_list
- if(new_shape)
- features["breasts_shape"] = new_shape
-
- if("breasts_color")
- var/new_breasts_color = input(user, "Breast Color:", "Character Preference") as color|null
- if(new_breasts_color)
- var/temp_hsv = RGBtoHSV(new_breasts_color)
- if(new_breasts_color == "#000000")
- features["breasts_color"] = pref_species.default_color
- else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
- features["breasts_color"] = sanitize_hexcolor(new_breasts_color)
- else
- user << "Invalid color. Your color is not bright enough."
-
- if("vag_shape")
- var/new_shape
- new_shape = input(user, "Vagina Type", "Character Preference") as null|anything in GLOB.vagina_shapes_list
- if(new_shape)
- features["vag_shape"] = new_shape
-
- if("vag_color")
- var/new_vagcolor = input(user, "Vagina color:", "Character Preference") as color|null
- if(new_vagcolor)
- var/temp_hsv = RGBtoHSV(new_vagcolor)
- if(new_vagcolor == "#000000")
- features["vag_color"] = pref_species.default_color
- else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
- features["vag_color"] = sanitize_hexcolor(new_vagcolor)
- else
- user << "Invalid color. Your color is not bright enough."
-
- if("ooccolor")
- var/new_ooccolor = input(user, "Choose your OOC colour:", "Game Preference",ooccolor) as color|null
- if(new_ooccolor)
- ooccolor = new_ooccolor
-
- if("bag")
- var/new_backbag = input(user, "Choose your character's style of bag:", "Character Preference") as null|anything in GLOB.backbaglist
- if(new_backbag)
- backbag = new_backbag
-
- if("uplink_loc")
- var/new_loc = input(user, "Choose your character's traitor uplink spawn location:", "Character Preference") as null|anything in GLOB.uplink_spawn_loc_list
- if(new_loc)
- uplink_spawn_loc = new_loc
-
- if("sec_dept")
- var/department = input(user, "Choose your prefered security department:", "Security Departments") as null|anything in GLOB.security_depts_prefs
- if(department)
- prefered_security_department = department
-
- if ("preferred_map")
- var/maplist = list()
- var/default = "Default"
- if (config.defaultmap)
- default += " ([config.defaultmap.map_name])"
- for (var/M in config.maplist)
- var/datum/map_config/VM = config.maplist[M]
- var/friendlyname = "[VM.map_name] "
- if (VM.voteweight <= 0)
- friendlyname += " (disabled)"
- maplist[friendlyname] = VM.map_name
- maplist[default] = null
- var/pickedmap = input(user, "Choose your preferred map. This will be used to help weight random map selection.", "Character Preference") as null|anything in maplist
- if (pickedmap)
- preferred_map = maplist[pickedmap]
-
- if ("clientfps")
- var/desiredfps = input(user, "Choose your desired fps. (0 = synced with server tick rate (currently:[world.fps]))", "Character Preference", clientfps) as null|num
- if (!isnull(desiredfps))
- clientfps = desiredfps
- parent.fps = desiredfps
- if("ui")
- var/pickedui = input(user, "Choose your UI style.", "Character Preference", UI_style) as null|anything in GLOB.available_ui_styles
- if(pickedui)
- UI_style = pickedui
- if (parent && parent.mob && parent.mob.hud_used)
- parent.mob.hud_used.update_ui_style(ui_style2icon(UI_style))
- if("pda_style")
- var/pickedPDAStyle = input(user, "Choose your PDA style.", "Character Preference", pda_style) as null|anything in GLOB.pda_styles
- if(pickedPDAStyle)
- pda_style = pickedPDAStyle
- if("pda_color")
- var/pickedPDAColor = input(user, "Choose your PDA Interface color.", "Character Preference",pda_color) as color|null
- if(pickedPDAColor)
- pda_color = pickedPDAColor
-
- else
- switch(href_list["preference"])
- //CITADEL PREFERENCES EDIT - I can't figure out how to modularize these, so they have to go here. :c -Pooj
- if("genital_colour")
- features["genitals_use_skintone"] = !features["genitals_use_skintone"]
- if("arousable")
- arousable = !arousable
- if("has_cock")
- features["has_cock"] = !features["has_cock"]
- if("has_balls")
- features["has_balls"] = !features["has_balls"]
- if("has_ovi")
- features["has_ovi"] = !features["has_ovi"]
- if("has_eggsack")
- features["has_eggsack"] = !features["has_eggsack"]
- if("balls_internal")
- features["balls_internal"] = !features["balls_internal"]
- if("eggsack_internal")
- features["eggsack_internal"] = !features["eggsack_internal"]
- if("has_breasts")
- features["has_breasts"] = !features["has_breasts"]
- if("has_vag")
- features["has_vag"] = !features["has_vag"]
- if("has_womb")
- features["has_womb"] = !features["has_womb"]
- if("exhibitionist")
- features["exhibitionist"] = !features["exhibitionist"]
- if("widescreenpref")
- widescreenpref = !widescreenpref
- user.client.change_view(CONFIG_GET(string/default_view))
- if("autostand")
- autostand = !autostand
- if ("screenshake")
- var/desiredshake = input(user, "Set the amount of screenshake you want. \n(0 = disabled, 100 = full, 200 = maximum.)", "Character Preference", screenshake) as null|num
- if (!isnull(desiredshake))
- screenshake = desiredshake
- if("damagescreenshake")
- switch(damagescreenshake)
- if(0)
- damagescreenshake = 1
- if(1)
- damagescreenshake = 2
- if(2)
- damagescreenshake = 0
- else
- damagescreenshake = 1
- if("nameless")
- nameless = !nameless
- //END CITADEL EDIT
- if("publicity")
- if(unlock_content)
- toggles ^= MEMBER_PUBLIC
- if("gender")
- var/chosengender = input(user, "Select your character's gender.", "Gender Selection", gender) in list(MALE,FEMALE,"nonbinary","object")
- switch(chosengender)
- if("nonbinary")
- chosengender = PLURAL
- if("object")
- chosengender = NEUTER
- gender = chosengender
- facial_hair_style = random_facial_hair_style(gender)
- hair_style = random_hair_style(gender)
-
- if("hotkeys")
- hotkeys = !hotkeys
- if(hotkeys)
- winset(user, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=default")
- else
- winset(user, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=old_default")
- if("action_buttons")
- buttons_locked = !buttons_locked
- if("tgui_fancy")
- tgui_fancy = !tgui_fancy
- if("tgui_lock")
- tgui_lock = !tgui_lock
- if("winflash")
- windowflashing = !windowflashing
- if("hear_adminhelps")
- toggles ^= SOUND_ADMINHELP
- if("announce_login")
- toggles ^= ANNOUNCE_LOGIN
- if("combohud_lighting")
- toggles ^= COMBOHUD_LIGHTING
-
- if("be_special")
- var/be_special_type = href_list["be_special_type"]
- if(be_special_type in be_special)
- be_special -= be_special_type
- else
- be_special += be_special_type
-
- if("name")
- be_random_name = !be_random_name
-
- if("all")
- be_random_body = !be_random_body
-
- if("hear_midis")
- toggles ^= SOUND_MIDI
-
- if("lobby_music")
- toggles ^= SOUND_LOBBY
- if((toggles & SOUND_LOBBY) && user.client && isnewplayer(user))
- user.client.playtitlemusic()
- else
- user.stop_sound_channel(CHANNEL_LOBBYMUSIC)
-
- if("ghost_ears")
- chat_toggles ^= CHAT_GHOSTEARS
-
- if("ghost_sight")
- chat_toggles ^= CHAT_GHOSTSIGHT
-
- if("ghost_whispers")
- chat_toggles ^= CHAT_GHOSTWHISPER
-
- if("ghost_radio")
- chat_toggles ^= CHAT_GHOSTRADIO
-
- if("ghost_pda")
- chat_toggles ^= CHAT_GHOSTPDA
-
- if("pull_requests")
- chat_toggles ^= CHAT_PULLR
-
- if("allow_midround_antag")
- toggles ^= MIDROUND_ANTAG
-
- if("parallaxup")
- parallax = WRAP(parallax + 1, PARALLAX_INSANE, PARALLAX_DISABLE + 1)
- if (parent && parent.mob && parent.mob.hud_used)
- parent.mob.hud_used.update_parallax_pref(parent.mob)
-
- if("parallaxdown")
- parallax = WRAP(parallax - 1, PARALLAX_INSANE, PARALLAX_DISABLE + 1)
- if (parent && parent.mob && parent.mob.hud_used)
- parent.mob.hud_used.update_parallax_pref(parent.mob)
-
- // Citadel edit - Prefs don't work outside of this. :c
- if("hound_sleeper")
- cit_toggles ^= MEDIHOUND_SLEEPER
-
- if("toggleeatingnoise")
- cit_toggles ^= EATING_NOISES
-
- if("toggledigestionnoise")
- cit_toggles ^= DIGESTION_NOISES
- //END CITADEL EDIT
-
- if("ambientocclusion")
- ambientocclusion = !ambientocclusion
- if(parent && parent.screen && parent.screen.len)
- var/obj/screen/plane_master/game_world/PM = locate(/obj/screen/plane_master/game_world) in parent.screen
- PM.backdrop(parent.mob)
-
- if("auto_fit_viewport")
- auto_fit_viewport = !auto_fit_viewport
- if(auto_fit_viewport && parent)
- parent.fit_viewport()
-
- if("save")
- save_preferences()
- save_character()
-
- if("load")
- load_preferences()
- load_character()
- if(parent && parent.prefs_vr)
- attempt_vr(parent.prefs_vr,"load_vore","")
-
- if("changeslot")
- if(!load_character(text2num(href_list["num"])))
- random_character()
- real_name = random_unique_name(gender)
- save_character()
- if(parent && parent.prefs_vr)
- attempt_vr(parent.prefs_vr,"load_vore","")
-
- if("tab")
- if (href_list["tab"])
- current_tab = text2num(href_list["tab"])
- if(href_list["preference"] == "gear")
- if(href_list["clear_loadout"])
- LAZYCLEARLIST(chosen_gear)
- gear_points = initial(gear_points)
- save_preferences()
- if(href_list["select_category"])
- for(var/i in GLOB.loadout_items)
- if(i == href_list["select_category"])
- gear_tab = i
- if(href_list["toggle_gear_path"])
- var/datum/gear/G = GLOB.loadout_items[gear_tab][html_decode(href_list["toggle_gear_path"])]
- if(!G)
- return
- var/toggle = text2num(href_list["toggle_gear"])
- if(!toggle && (G.type in chosen_gear))//toggling off and the item effectively is in chosen gear)
- LAZYREMOVE(chosen_gear, G.type)
- gear_points += initial(G.cost)
- else if(toggle && (!(is_type_in_ref_list(G, chosen_gear))))
- if(!is_loadout_slot_available(G.category))
- to_chat(user, "You cannot take this loadout, as you've already chosen too many of the same category!")
- return
- if(G.ckeywhitelist && G.ckeywhitelist.len && !(user.ckey in G.ckeywhitelist))
- to_chat(user, "This is an item intended for donator use only. You are not authorized to use this item.")
- return
- if(gear_points >= initial(G.cost))
- LAZYADD(chosen_gear, G.type)
- gear_points -= initial(G.cost)
-
- ShowChoices(user)
- return 1
-
-/datum/preferences/proc/copy_to(mob/living/carbon/human/character, icon_updates = 1, roundstart_checks = TRUE)
- if(be_random_name)
- real_name = pref_species.random_name(gender)
-
- if(be_random_body)
- random_character(gender)
-
- if(roundstart_checks)
- if(CONFIG_GET(flag/humans_need_surnames) && (pref_species.id == "human"))
- var/firstspace = findtext(real_name, " ")
- var/name_length = length(real_name)
- if(!firstspace) //we need a surname
- real_name += " [pick(GLOB.last_names)]"
- else if(firstspace == name_length)
- real_name += "[pick(GLOB.last_names)]"
-
- character.real_name = nameless ? "[real_name] #[rand(10000, 99999)]" : real_name
- character.name = character.real_name
- character.nameless = nameless
-
- character.gender = gender
- character.age = age
-
- character.eye_color = eye_color
- var/obj/item/organ/eyes/organ_eyes = character.getorgan(/obj/item/organ/eyes)
- if(organ_eyes)
- if(!initial(organ_eyes.eye_color))
- organ_eyes.eye_color = eye_color
- organ_eyes.old_eye_color = eye_color
- character.hair_color = hair_color
- character.facial_hair_color = facial_hair_color
-
- character.skin_tone = skin_tone
- character.hair_style = hair_style
- character.facial_hair_style = facial_hair_style
- character.underwear = underwear
- character.undershirt = undershirt
- character.socks = socks
-
- character.backbag = backbag
-
- var/datum/species/chosen_species
- if(!roundstart_checks || (pref_species.id in GLOB.roundstart_races))
- chosen_species = pref_species.type
- else
- chosen_species = /datum/species/human
- pref_species = new /datum/species/human
- save_character()
-
- character.set_species(chosen_species, icon_update = FALSE, pref_load = TRUE)
- character.dna.features = features.Copy()
- character.dna.real_name = character.real_name
- character.dna.nameless = character.nameless
-
- if("tail_lizard" in pref_species.default_features)
- character.dna.species.mutant_bodyparts |= "tail_lizard"
- else if("mam_tail" in pref_species.default_features)
- character.dna.species.mutant_bodyparts |= "mam_tail"
- else if("xenotail" in pref_species.default_features)
- character.dna.species.mutant_bodyparts |= "xenotail"
-
- if("legs" in pref_species.default_features)
- if(character.dna.features["legs"] == "Digitigrade Legs")
- pref_species.species_traits += DIGITIGRADE
- character.Digitigrade_Leg_Swap(FALSE)
-
- if(character.dna.features["legs"] == "Normal Legs" && DIGITIGRADE in pref_species.species_traits)
- pref_species.species_traits -= DIGITIGRADE
- character.Digitigrade_Leg_Swap(TRUE)
-
- else if((!"legs" in pref_species.default_features) && DIGITIGRADE in pref_species.species_traits)
- pref_species.species_traits -= DIGITIGRADE
- character.Digitigrade_Leg_Swap(TRUE)
-
- if(DIGITIGRADE in pref_species.species_traits)
- character.Digitigrade_Leg_Swap(FALSE)
-
- if(icon_updates)
- character.update_body()
- character.update_hair()
- character.update_body_parts()
-
-/datum/preferences/proc/get_default_name(name_id)
- switch(name_id)
- if("human")
- return random_unique_name()
- if("ai")
- return pick(GLOB.ai_names)
- if("cyborg")
- return DEFAULT_CYBORG_NAME
- if("clown")
- return pick(GLOB.clown_names)
- if("mime")
- return pick(GLOB.mime_names)
- return random_unique_name()
-
-/datum/preferences/proc/ask_for_custom_name(mob/user,name_id)
- var/namedata = GLOB.preferences_custom_names[name_id]
- if(!namedata)
- return
-
- var/raw_name = input(user, "Choose your character's [namedata["qdesc"]]:","Character Preference") as text|null
- if(!raw_name)
- if(namedata["allow_null"])
- custom_names[name_id] = get_default_name(name_id)
- else
- return
- else
- var/sanitized_name = reject_bad_name(raw_name,namedata["allow_numbers"])
- if(!sanitized_name)
- to_chat(user, "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z,[namedata["allow_numbers"] ? ",0-9," : ""] -, ' and .")
- return
- else
- custom_names[name_id] = sanitized_name
+ /* CAUTION! CAUTION! CAUTION! CAUTION! CAUTION! *\
+ | THIS FILE CONTAINS HOOKS FOR FOR |
+ | CHANGES SPECIFIC TO CITADEL. IF |
+ | YOU'RE FIXING A MERGE CONFLICT |
+ | HERE, PLEASE ASK FOR REVIEW FROM |
+ | ANOTHER MAINTAINER TO ENSURE YOU |
+ | DON'T INTRODUCE REGRESSIONS. |
+ \* */
+
+GLOBAL_LIST_EMPTY(preferences_datums)
+
+/datum/preferences
+ var/client/parent
+ //doohickeys for savefiles
+ var/path
+ var/default_slot = 1 //Holder so it doesn't default to slot 1, rather the last one used
+ var/max_save_slots = 8
+
+ //non-preference stuff
+ var/muted = 0
+ var/last_ip
+ var/last_id
+
+ //game-preferences
+ var/lastchangelog = "" //Saved changlog filesize to detect if there was a change
+ var/ooccolor = null
+ var/enable_tips = TRUE
+ var/tip_delay = 500 //tip delay in milliseconds
+
+ //Antag preferences
+ var/list/be_special = list() //Special role selection
+ var/tmp/old_be_special = 0 //Bitflag version of be_special, used to update old savefiles and nothing more
+ //If it's 0, that's good, if it's anything but 0, the owner of this prefs file's antag choices were,
+ //autocorrected this round, not that you'd need to check that.
+
+
+ var/UI_style = null
+ var/buttons_locked = FALSE
+ var/hotkeys = FALSE
+ var/tgui_fancy = TRUE
+ var/tgui_lock = TRUE
+ var/windowflashing = TRUE
+ var/toggles = TOGGLES_DEFAULT
+ var/db_flags
+ var/chat_toggles = TOGGLES_DEFAULT_CHAT
+ var/ghost_form = "ghost"
+ var/ghost_orbit = GHOST_ORBIT_CIRCLE
+ var/ghost_accs = GHOST_ACCS_DEFAULT_OPTION
+ var/ghost_others = GHOST_OTHERS_DEFAULT_OPTION
+ var/ghost_hud = 1
+ var/inquisitive_ghost = 1
+ var/allow_midround_antag = 1
+ var/preferred_map = null
+ var/pda_style = MONO
+ var/pda_color = "#808000"
+
+ var/uses_glasses_colour = 0
+
+ //character preferences
+ var/real_name //our character's name
+ var/nameless = FALSE //whether or not our character is nameless
+ var/be_random_name = 0 //whether we'll have a random name every round
+ var/be_random_body = 0 //whether we'll have a random body every round
+ var/gender = MALE //gender of character (well duh)
+ var/age = 30 //age of character
+ var/underwear = "Nude" //underwear type
+ var/undershirt = "Nude" //undershirt type
+ var/socks = "Nude" //socks type
+ var/backbag = DBACKPACK //backpack type
+ var/hair_style = "Bald" //Hair type
+ var/hair_color = "000" //Hair color
+ var/facial_hair_style = "Shaved" //Face hair type
+ var/facial_hair_color = "000" //Facial hair color
+ var/skin_tone = "caucasian1" //Skin color
+ var/eye_color = "000" //Eye color
+ var/datum/species/pref_species = new /datum/species/human() //Mutant race
+ var/list/features = list("mcolor" = "FFF",
+ "tail_lizard" = "Smooth", "tail_human" = "Cat",
+ "snout" = "Round", "horns" = "None", "ears" = "Cat",
+ "wings" = "None", "frills" = "None", "spines" = "None",
+ "body_markings" = "None", "legs" = "Normal Legs", "moth_wings" = "Plain")
+
+ var/list/custom_names = list()
+ var/prefered_security_department = SEC_DEPT_RANDOM
+
+ //Quirk list
+ var/list/positive_quirks = list()
+ var/list/negative_quirks = list()
+ var/list/neutral_quirks = list()
+ var/list/all_quirks = list()
+ var/list/character_quirks = list()
+
+ //Jobs, uses bitflags
+ var/job_civilian_high = 0
+ var/job_civilian_med = 0
+ var/job_civilian_low = 0
+
+ var/job_medsci_high = 0
+ var/job_medsci_med = 0
+ var/job_medsci_low = 0
+
+ var/job_engsec_high = 0
+ var/job_engsec_med = 0
+ var/job_engsec_low = 0
+
+ // Want randomjob if preferences already filled - Donkie
+ var/joblessrole = BERANDOMJOB //defaults to 1 for fewer assistants
+
+ // 0 = character settings, 1 = game preferences
+ var/current_tab = 0
+
+ var/unlock_content = 0
+
+ var/list/ignoring = list()
+
+ var/clientfps = 0
+
+ var/parallax
+
+ var/ambientocclusion = TRUE
+ var/auto_fit_viewport = TRUE
+
+ var/uplink_spawn_loc = UPLINK_PDA
+
+ var/list/exp = list()
+ var/list/menuoptions
+
+ var/action_buttons_screen_locs = list()
+
+/datum/preferences/New(client/C)
+ parent = C
+
+ for(var/custom_name_id in GLOB.preferences_custom_names)
+ custom_names[custom_name_id] = get_default_name(custom_name_id)
+
+ UI_style = GLOB.available_ui_styles[1]
+ if(istype(C))
+ if(!IsGuestKey(C.key))
+ load_path(C.ckey)
+ unlock_content = C.IsByondMember()
+ if(unlock_content)
+ max_save_slots = 16
+ var/loaded_preferences_successfully = load_preferences()
+ if(loaded_preferences_successfully)
+ if(load_character())
+ return
+ //we couldn't load character data so just randomize the character appearance + name
+ random_character() //let's create a random character then - rather than a fat, bald and naked man.
+ real_name = pref_species.random_name(gender,1)
+ if(!loaded_preferences_successfully)
+ save_preferences()
+ save_character() //let's save this new random character so it doesn't keep generating new ones.
+ menuoptions = list()
+ return
+
+#define APPEARANCE_CATEGORY_COLUMN ""
+#define MAX_MUTANT_ROWS 4
+
+/datum/preferences/proc/ShowChoices(mob/user)
+ if(!user || !user.client)
+ return
+ update_preview_icon()
+ var/list/dat = list("")
+
+ dat += "Character Settings"
+ dat += "Character Appearance"
+ dat += "Loadout"
+ dat += "Game Preferences"
+
+ if(!path)
+ dat += " Please create an account to save your preferences "
+
+ dat += ""
+
+ dat += " "
+
+ switch(current_tab)
+ if (0) // Character Settings#
+ if(path)
+ var/savefile/S = new /savefile(path)
+ if(S)
+ dat += ""
+ var/name
+ var/unspaced_slots = 0
+ for(var/i=1, i<=max_save_slots, i++)
+ unspaced_slots++
+ if(unspaced_slots > 4)
+ dat += " "
+ unspaced_slots = 0
+ S.cd = "/character[i]"
+ S["real_name"] >> name
+ if(!name)
+ name = "Character[i]"
+ dat += "[name] "
+ dat += ""
+
+ dat += "Occupation Choices"
+ dat += "Set Occupation Preferences "
+ if(CONFIG_GET(flag/roundstart_traits))
+ dat += "Quirk Setup"
+ dat += "Configure Quirks "
+ dat += "Current Quirks: [all_quirks.len ? all_quirks.Join(", ") : "None"]"
+ dat += "Identity"
+ dat += ""
+
+ //Character Appearance
+ if(2)
+ if(path)
+ var/savefile/S = new /savefile(path)
+ if(S)
+ dat += ""
+ var/name
+ var/unspaced_slots = 0
+ for(var/i=1, i<=max_save_slots, i++)
+ unspaced_slots++
+ if(unspaced_slots > 4)
+ dat += " "
+ unspaced_slots = 0
+ S.cd = "/character[i]"
+ S["real_name"] >> name
+ if(!name)
+ name = "Character[i]"
+ dat += "[name] "
+ dat += ""
+
+ update_preview_icon()
+ dat += ""
+ dat += "Flavor Text"
+ dat += "Set Examine Text "
+ if(lentext(features["flavor_text"]) <= 40)
+ if(!lentext(features["flavor_text"]))
+ dat += "\[...\]"
+ else
+ dat += "[features["flavor_text"]]"
+ else
+ dat += "[TextPreview(features["flavor_text"])]... "
+ dat += "Body"
+ dat += "Gender:[gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))] "
+ dat += "Species:[pref_species.id] "
+ dat += "Random Body "
+ dat += "Always Random Body:[be_random_body ? "Yes" : "No"] "
+
+ var/use_skintones = pref_species.use_skintones
+ if(use_skintones)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Skin Tone"
+
+ dat += "[skin_tone] "
+
+ var/mutant_colors
+ if((MUTCOLORS in pref_species.species_traits) || (MUTCOLORS_PARTSONLY in pref_species.species_traits))
+ if(!use_skintones)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Body Colors"
+
+ dat += "Primary Color: "
+ dat += " Change "
+
+ dat += "Secondary Color: "
+ dat += " Change "
+
+ dat += "Tertiary Color: "
+ dat += " Change "
+ mutant_colors = TRUE
+
+ if((EYECOLOR in pref_species.species_traits) && !(NOEYES in pref_species.species_traits))
+
+ if(!use_skintones && !mutant_colors)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Eye Color"
+
+ dat += " Change "
+
+ dat += " | "
+ else if(use_skintones || mutant_colors)
+ dat += ""
+
+ if(HAIR in pref_species.species_traits)
+
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Hair Style"
+
+ dat += "[hair_style]"
+ dat += "< > "
+ dat += " Change "
+
+ dat += "Facial Hair Style"
+
+ dat += "[facial_hair_style]"
+ dat += "< > "
+ dat += " Change "
+
+ dat += ""
+ //Mutant stuff
+ var/mutant_category = 0
+
+ if("tail_lizard" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Tail"
+
+ dat += "[features["tail_lizard"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+
+ if("mam_tail" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Tail"
+
+ dat += "[features["mam_tail"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("tail_human" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Tail"
+
+ dat += "[features["tail_human"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("snout" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Snout"
+
+ dat += "[features["snout"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("horns" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Horns"
+
+ dat += "[features["horns"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ if("frills" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Frills"
+
+ dat += "[features["frills"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+
+ if("spines" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Spines"
+
+ dat += "[features["spines"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+
+ if("body_markings" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Body Markings"
+
+ dat += "[features["body_markings"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("mam_body_markings" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Species Markings"
+
+ dat += "[features["mam_body_markings"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+
+ if("mam_ears" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Ears"
+
+ dat += "[features["mam_ears"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("ears" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Ears"
+
+ dat += "[features["ears"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("mam_snouts" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Snout"
+
+ dat += "[features["mam_snouts"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("legs" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Legs"
+
+ dat += "[features["legs"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("moth_wings" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Moth wings"
+
+ dat += "[features["moth_wings"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("taur" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Tauric Body"
+
+ dat += "[features["taur"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("wings" in pref_species.mutant_bodyparts && GLOB.r_wings_list.len >1)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Wings"
+
+ dat += "[features["wings"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("xenohead" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Caste Head"
+
+ dat += "[features["xenohead"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("xenotail" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Tail"
+
+ dat += "[features["xenotail"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("xenodorsal" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Dorsal Spines"
+
+ dat += "[features["xenodorsal"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("ipc_screen" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Screen"
+
+ dat += "[features["ipc_screen"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+ if("ipc_antenna" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "Antenna"
+
+ dat += "[features["ipc_antenna"]]"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+
+ if(mutant_category)
+ dat += ""
+ mutant_category = 0
+
+ dat += " "
+
+ dat += " | "
+ dat += ""
+
+ if (1) // Game Preferences
+ dat += ""
+ if(unlock_content)
+ dat += "Ghost Form: [ghost_form] "
+ dat += "Ghost Orbit: [ghost_orbit] "
+ var/button_name = "If you see this something went wrong."
+ switch(ghost_accs)
+ if(GHOST_ACCS_FULL)
+ button_name = GHOST_ACCS_FULL_NAME
+ if(GHOST_ACCS_DIR)
+ button_name = GHOST_ACCS_DIR_NAME
+ if(GHOST_ACCS_NONE)
+ button_name = GHOST_ACCS_NONE_NAME
+
+ dat += "Ghost Accessories: [button_name] "
+ switch(ghost_others)
+ if(GHOST_OTHERS_THEIR_SETTING)
+ button_name = GHOST_OTHERS_THEIR_SETTING_NAME
+ if(GHOST_OTHERS_DEFAULT_SPRITE)
+ button_name = GHOST_OTHERS_DEFAULT_SPRITE_NAME
+ if(GHOST_OTHERS_SIMPLE)
+ button_name = GHOST_OTHERS_SIMPLE_NAME
+
+ dat += "Ghosts of Others: [button_name] "
+ dat += " "
+ dat += "FPS: [clientfps] "
+ dat += "Parallax (Fancy Space): "
+ switch (parallax)
+ if (PARALLAX_LOW)
+ dat += "Low"
+ if (PARALLAX_MED)
+ dat += "Medium"
+ if (PARALLAX_INSANE)
+ dat += "Insane"
+ if (PARALLAX_DISABLE)
+ dat += "Disabled"
+ else
+ dat += "High"
+ dat += " "
+ dat += "Ambient Occlusion: [ambientocclusion ? "Enabled" : "Disabled"] "
+ dat += "Fit Viewport: [auto_fit_viewport ? "Auto" : "Manual"] "
+
+ if (CONFIG_GET(flag/maprotation) && CONFIG_GET(flag/tgstyle_maprotation))
+ var/p_map = preferred_map
+ if (!p_map)
+ p_map = "Default"
+ if (config.defaultmap)
+ p_map += " ([config.defaultmap.map_name])"
+ else
+ if (p_map in config.maplist)
+ var/datum/map_config/VM = config.maplist[p_map]
+ if (!VM)
+ p_map += " (No longer exists)"
+ else
+ p_map = VM.map_name
+ else
+ p_map += " (No longer exists)"
+ if(CONFIG_GET(flag/allow_map_voting))
+ dat += "Preferred Map: [p_map] "
+
+ dat += " | "
+
+ dat += "Special Role Settings"
+
+ if(jobban_isbanned(user, ROLE_SYNDICATE))
+ dat += "You are banned from antagonist roles."
+ src.be_special = list()
+
+
+ for (var/i in GLOB.special_roles)
+ if(jobban_isbanned(user, i))
+ dat += "Be [capitalize(i)]: BANNED "
+ else
+ var/days_remaining = null
+ if(ispath(GLOB.special_roles[i]) && CONFIG_GET(flag/use_age_restriction_for_jobs)) //If it's a game mode antag, check if the player meets the minimum age
+ var/mode_path = GLOB.special_roles[i]
+ var/datum/game_mode/temp_mode = new mode_path
+ days_remaining = temp_mode.get_remaining_days(user.client)
+
+ if(days_remaining)
+ dat += "Be [capitalize(i)]: \[IN [days_remaining] DAYS] "
+ else
+ dat += "Be [capitalize(i)]: [(i in be_special) ? "Enabled" : "Disabled"] "
+ dat += "Midround Antagonist: [(toggles & MIDROUND_ANTAG) ? "Enabled" : "Disabled"] "
+
+ dat += " "
+
+ if(3)
+ if(!gear_tab)
+ gear_tab = GLOB.loadout_items[1]
+ dat += ""
+ dat += "| [gear_points] loadout points remaining. \[Clear Loadout\] | "
+ dat += "| You can only choose one item per category, unless it's an item that spawns in your backpack or hands. | "
+ dat += "| "
+ var/firstcat = TRUE
+ for(var/i in GLOB.loadout_items)
+ if(firstcat)
+ firstcat = FALSE
+ else
+ dat += " |"
+ if(i == gear_tab)
+ dat += " [i] "
+ else
+ dat += " [i] "
+ dat += " | "
+ dat += "
| "
+ dat += "| [gear_tab] | "
+ dat += "
| "
+ dat += "| Name | "
+ dat += "Cost | "
+ dat += "Restrictions | "
+ dat += "Description | "
+ for(var/j in GLOB.loadout_items[gear_tab])
+ var/datum/gear/gear = GLOB.loadout_items[gear_tab][j]
+ var/donoritem
+ if(gear.ckeywhitelist && gear.ckeywhitelist.len)
+ donoritem = TRUE
+ if(!(user.ckey in gear.ckeywhitelist))
+ continue
+ var/class_link = ""
+ if(gear.type in chosen_gear)
+ class_link = "style='white-space:normal;' class='linkOn' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(j)];toggle_gear=0'"
+ else if(gear_points <= 0)
+ class_link = "style='white-space:normal;' class='linkOff'"
+ else if(donoritem)
+ class_link = "style='white-space:normal;background:#ebc42e;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(j)];toggle_gear=1'"
+ else
+ class_link = "style='white-space:normal;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(j)];toggle_gear=1'"
+ dat += "| [j] | "
+ dat += "[gear.cost] | "
+ if(islist(gear.restricted_roles))
+ if(gear.restricted_roles.len)
+ dat += ""
+ dat += gear.restricted_roles.Join(";")
+ dat += ""
+ dat += " | [gear.description] | "
+ dat += " "
+
+ dat += " "
+
+ if(!IsGuestKey(user.key))
+ dat += "Undo "
+ dat += "Save Setup "
+
+ dat += "Reset Setup"
+ dat += ""
+
+ winshow(user, "preferences_window", TRUE)
+ var/datum/browser/popup = new(user, "preferences_browser", "Character Setup ", 640, 770)
+ popup.set_content(dat.Join())
+ popup.open(FALSE)
+ onclose(user, "preferences_window", src)
+
+#undef APPEARANCE_CATEGORY_COLUMN
+#undef MAX_MUTANT_ROWS
+
+/datum/preferences/proc/SetChoices(mob/user, limit = 17, list/splitJobs = list("Chief Engineer"), widthPerColumn = 295, height = 620)
+ if(!SSjob)
+ return
+
+ //limit - The amount of jobs allowed per column. Defaults to 17 to make it look nice.
+ //splitJobs - Allows you split the table by job. You can make different tables for each department by including their heads. Defaults to CE to make it look nice.
+ //widthPerColumn - Screen's width for every column.
+ //height - Screen's height.
+
+ var/width = widthPerColumn
+
+ var/HTML = ""
+ if(SSjob.occupations.len <= 0)
+ HTML += "The job SSticker is not yet finished creating jobs, please try again later"
+ HTML += "Done " // Easier to press up here.
+
+ else
+ HTML += "Choose occupation chances "
+ HTML += "Left-click to raise an occupation preference, right-click to lower it.
"
+ HTML += "Done " // Easier to press up here.
+ HTML += ""
+ HTML += "" // Table within a table for alignment, also allows you to easily add more colomns.
+ HTML += ""
+ var/index = -1
+
+ //The job before the current job. I only use this to get the previous jobs color when I'm filling in blank rows.
+ var/datum/job/lastJob
+
+ var/datum/job/overflow = SSjob.GetJob(SSjob.overflow_role)
+
+ for(var/datum/job/job in SSjob.occupations)
+
+ index += 1
+ if((index >= limit) || (job.title in splitJobs))
+ width += widthPerColumn
+ if((index < limit) && (lastJob != null))
+ //If the cells were broken up by a job in the splitJob list then it will fill in the rest of the cells with
+ //the last job's selection color. Creating a rather nice effect.
+ for(var/i = 0, i < (limit - index), i += 1)
+ HTML += "|   |   | "
+ HTML += " | "
+ index = 0
+
+ HTML += "| "
+ var/rank = job.title
+ lastJob = job
+ if(jobban_isbanned(user, rank))
+ HTML += "[rank] | BANNED | "
+ continue
+ var/required_playtime_remaining = job.required_playtime_remaining(user.client)
+ if(required_playtime_remaining)
+ HTML += "[rank] \[ [get_exp_format(required_playtime_remaining)] as [job.get_exp_req_type()] \] | "
+ continue
+ if(!job.player_old_enough(user.client))
+ var/available_in_days = job.available_in_days(user.client)
+ HTML += "[rank] \[IN [(available_in_days)] DAYS\] | "
+ continue
+ if((job_civilian_low & overflow.flag) && (rank != SSjob.overflow_role) && !jobban_isbanned(user, SSjob.overflow_role))
+ HTML += "[rank] | "
+ continue
+ if((rank in GLOB.command_positions) || (rank == "AI"))//Bold head jobs
+ HTML += "[rank]"
+ else
+ HTML += "[rank]"
+
+ HTML += ""
+
+ var/prefLevelLabel = "ERROR"
+ var/prefLevelColor = "pink"
+ var/prefUpperLevel = -1 // level to assign on left click
+ var/prefLowerLevel = -1 // level to assign on right click
+
+ if(GetJobDepartment(job, 1) & job.flag)
+ prefLevelLabel = "High"
+ prefLevelColor = "slateblue"
+ prefUpperLevel = 4
+ prefLowerLevel = 2
+ else if(GetJobDepartment(job, 2) & job.flag)
+ prefLevelLabel = "Medium"
+ prefLevelColor = "green"
+ prefUpperLevel = 1
+ prefLowerLevel = 3
+ else if(GetJobDepartment(job, 3) & job.flag)
+ prefLevelLabel = "Low"
+ prefLevelColor = "orange"
+ prefUpperLevel = 2
+ prefLowerLevel = 4
+ else
+ prefLevelLabel = "NEVER"
+ prefLevelColor = "red"
+ prefUpperLevel = 3
+ prefLowerLevel = 1
+
+
+ HTML += ""
+
+ if(rank == SSjob.overflow_role)//Overflow is special
+ if(job_civilian_low & overflow.flag)
+ HTML += "Yes"
+ else
+ HTML += "No"
+ HTML += " | "
+ continue
+
+ HTML += "[prefLevelLabel]"
+ HTML += ""
+
+ for(var/i = 1, i < (limit - index), i += 1) // Finish the column so it is even
+ HTML += "|   |   | "
+
+ HTML += " "
+ HTML += " | "
+
+ var/message = "Be an [SSjob.overflow_role] if preferences unavailable"
+ if(joblessrole == BERANDOMJOB)
+ message = "Get random job if preferences unavailable"
+ else if(joblessrole == RETURNTOLOBBY)
+ message = "Return to lobby if preferences unavailable"
+ HTML += " [message]"
+ HTML += "Reset Preferences"
+
+ var/datum/browser/popup = new(user, "mob_occupation", "Occupation Preferences ", width, height)
+ popup.set_window_options("can_close=0")
+ popup.set_content(HTML)
+ popup.open(FALSE)
+
+/datum/preferences/proc/SetJobPreferenceLevel(datum/job/job, level)
+ if (!job)
+ return 0
+
+ if (level == 1) // to high
+ // remove any other job(s) set to high
+ job_civilian_med |= job_civilian_high
+ job_engsec_med |= job_engsec_high
+ job_medsci_med |= job_medsci_high
+ job_civilian_high = 0
+ job_engsec_high = 0
+ job_medsci_high = 0
+
+ if (job.department_flag == CIVILIAN)
+ job_civilian_low &= ~job.flag
+ job_civilian_med &= ~job.flag
+ job_civilian_high &= ~job.flag
+
+ switch(level)
+ if (1)
+ job_civilian_high |= job.flag
+ if (2)
+ job_civilian_med |= job.flag
+ if (3)
+ job_civilian_low |= job.flag
+
+ return 1
+ else if (job.department_flag == ENGSEC)
+ job_engsec_low &= ~job.flag
+ job_engsec_med &= ~job.flag
+ job_engsec_high &= ~job.flag
+
+ switch(level)
+ if (1)
+ job_engsec_high |= job.flag
+ if (2)
+ job_engsec_med |= job.flag
+ if (3)
+ job_engsec_low |= job.flag
+
+ return 1
+ else if (job.department_flag == MEDSCI)
+ job_medsci_low &= ~job.flag
+ job_medsci_med &= ~job.flag
+ job_medsci_high &= ~job.flag
+
+ switch(level)
+ if (1)
+ job_medsci_high |= job.flag
+ if (2)
+ job_medsci_med |= job.flag
+ if (3)
+ job_medsci_low |= job.flag
+
+ return 1
+
+ return 0
+
+/datum/preferences/proc/UpdateJobPreference(mob/user, role, desiredLvl)
+ if(!SSjob || SSjob.occupations.len <= 0)
+ return
+ var/datum/job/job = SSjob.GetJob(role)
+
+ if(!job)
+ user << browse(null, "window=mob_occupation")
+ ShowChoices(user)
+ return
+
+ if (!isnum(desiredLvl))
+ to_chat(user, "UpdateJobPreference - desired level was not a number. Please notify coders!")
+ ShowChoices(user)
+ return
+
+ if(role == SSjob.overflow_role)
+ if(job_civilian_low & job.flag)
+ job_civilian_low &= ~job.flag
+ else
+ job_civilian_low |= job.flag
+ SetChoices(user)
+ return 1
+
+ SetJobPreferenceLevel(job, desiredLvl)
+ SetChoices(user)
+
+ return 1
+
+
+/datum/preferences/proc/ResetJobs()
+
+ job_civilian_high = 0
+ job_civilian_med = 0
+ job_civilian_low = 0
+
+ job_medsci_high = 0
+ job_medsci_med = 0
+ job_medsci_low = 0
+
+ job_engsec_high = 0
+ job_engsec_med = 0
+ job_engsec_low = 0
+
+
+/datum/preferences/proc/GetJobDepartment(datum/job/job, level)
+ if(!job || !level)
+ return 0
+ switch(job.department_flag)
+ if(CIVILIAN)
+ switch(level)
+ if(1)
+ return job_civilian_high
+ if(2)
+ return job_civilian_med
+ if(3)
+ return job_civilian_low
+ if(MEDSCI)
+ switch(level)
+ if(1)
+ return job_medsci_high
+ if(2)
+ return job_medsci_med
+ if(3)
+ return job_medsci_low
+ if(ENGSEC)
+ switch(level)
+ if(1)
+ return job_engsec_high
+ if(2)
+ return job_engsec_med
+ if(3)
+ return job_engsec_low
+ return 0
+
+/datum/preferences/proc/SetQuirks(mob/user)
+ if(!SSquirks)
+ to_chat(user, "The quirk subsystem is still initializing! Try again in a minute.")
+ return
+
+ var/list/dat = list()
+ if(!SSquirks.quirks.len)
+ dat += "The quirk subsystem hasn't finished initializing, please hold..."
+ dat += "Done "
+
+ else
+ dat += "Choose quirk setup "
+ dat += "Left-click to add or remove quirks. You need negative quirks to have positive ones. \
+ Quirks are applied at roundstart and cannot normally be removed. "
+ dat += "Done"
+ dat += " "
+ dat += "Current quirks: [all_quirks.len ? all_quirks.Join(", ") : "None"]"
+ dat += "[positive_quirks.len] / [MAX_QUIRKS] max positive quirks \
+ Quirk balance remaining: [GetQuirkBalance()] "
+ for(var/V in SSquirks.quirks)
+ var/datum/quirk/T = SSquirks.quirks[V]
+ var/quirk_name = initial(T.name)
+ var/has_quirk
+ var/quirk_cost = initial(T.value) * -1
+ var/lock_reason = "This trait is unavailable."
+ var/quirk_conflict = FALSE
+ for(var/_V in all_quirks)
+ if(_V == quirk_name)
+ has_quirk = TRUE
+ if(initial(T.mood_quirk) && CONFIG_GET(flag/disable_human_mood))
+ lock_reason = "Mood is disabled."
+ quirk_conflict = TRUE
+ if(has_quirk)
+ if(quirk_conflict)
+ all_quirks -= quirk_name
+ has_quirk = FALSE
+ else
+ quirk_cost *= -1 //invert it back, since we'd be regaining this amount
+ if(quirk_cost > 0)
+ quirk_cost = "+[quirk_cost]"
+ var/font_color = "#AAAAFF"
+ if(initial(T.value) != 0)
+ font_color = initial(T.value) > 0 ? "#AAFFAA" : "#FFAAAA"
+ if(quirk_conflict)
+ dat += "[quirk_name] - [initial(T.desc)] \
+ LOCKED: [lock_reason] "
+ else
+ if(has_quirk)
+ dat += "[quirk_name] - [initial(T.desc)] \
+ [has_quirk ? "Lose" : "Take"] ([quirk_cost] pts.) "
+ else
+ dat += "[quirk_name] - [initial(T.desc)] \
+ [has_quirk ? "Lose" : "Take"] ([quirk_cost] pts.) "
+ dat += " Reset Traits"
+
+ var/datum/browser/popup = new(user, "mob_occupation", "Quirk Preferences ", 900, 600) //no reason not to reuse the occupation window, as it's cleaner that way
+ popup.set_window_options("can_close=0")
+ popup.set_content(dat.Join())
+ popup.open(FALSE)
+
+/datum/preferences/proc/GetQuirkBalance()
+ var/bal = 0
+ for(var/V in all_quirks)
+ var/datum/quirk/T = SSquirks.quirks[V]
+ bal -= initial(T.value)
+ return bal
+
+/datum/preferences/Topic(href, href_list, hsrc) //yeah, gotta do this I guess..
+ . = ..()
+ if(href_list["close"])
+ var/client/C = usr.client
+ if(C)
+ C.clear_character_previews()
+
+/datum/preferences/proc/process_link(mob/user, list/href_list)
+ if(href_list["jobbancheck"])
+ var/job = sanitizeSQL(href_list["jobbancheck"])
+ var/sql_ckey = sanitizeSQL(user.ckey)
+ var/datum/DBQuery/query_get_jobban = SSdbcore.NewQuery("SELECT reason, bantime, duration, expiration_time, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].a_ckey), a_ckey) FROM [format_table_name("ban")] WHERE ckey = '[sql_ckey]' AND (bantype = 'JOB_PERMABAN' OR (bantype = 'JOB_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned) AND job = '[job]'")
+ if(!query_get_jobban.warn_execute())
+ qdel(query_get_jobban)
+ return
+ if(query_get_jobban.NextRow())
+ var/reason = query_get_jobban.item[1]
+ var/bantime = query_get_jobban.item[2]
+ var/duration = query_get_jobban.item[3]
+ var/expiration_time = query_get_jobban.item[4]
+ var/admin_key = query_get_jobban.item[5]
+ var/text
+ text = "You, or another user of this computer, ([user.key]) is banned from playing [job]. The ban reason is: [reason] This ban was applied by [admin_key] on [bantime]"
+ if(text2num(duration) > 0)
+ text += ". The ban is for [duration] minutes and expires on [expiration_time] (server time)"
+ text += "."
+ to_chat(user, text)
+ qdel(query_get_jobban)
+ return
+
+ if(href_list["preference"] == "job")
+ switch(href_list["task"])
+ if("close")
+ user << browse(null, "window=mob_occupation")
+ ShowChoices(user)
+ if("reset")
+ ResetJobs()
+ SetChoices(user)
+ if("random")
+ switch(joblessrole)
+ if(RETURNTOLOBBY)
+ if(jobban_isbanned(user, SSjob.overflow_role))
+ joblessrole = BERANDOMJOB
+ else
+ joblessrole = BEOVERFLOW
+ if(BEOVERFLOW)
+ joblessrole = BERANDOMJOB
+ if(BERANDOMJOB)
+ joblessrole = RETURNTOLOBBY
+ SetChoices(user)
+ if("setJobLevel")
+ UpdateJobPreference(user, href_list["text"], text2num(href_list["level"]))
+ else
+ SetChoices(user)
+ return 1
+
+ else if(href_list["preference"] == "trait")
+ switch(href_list["task"])
+ if("close")
+ user << browse(null, "window=mob_occupation")
+ ShowChoices(user)
+ if("update")
+ var/quirk = href_list["trait"]
+ if(!SSquirks.quirks[quirk])
+ return
+ var/value = SSquirks.quirk_points[quirk]
+ if(value == 0)
+ if(quirk in neutral_quirks)
+ neutral_quirks -= quirk
+ all_quirks -= quirk
+ else
+ neutral_quirks += quirk
+ all_quirks += quirk
+ else
+ var/balance = GetQuirkBalance()
+ if(quirk in positive_quirks)
+ positive_quirks -= quirk
+ all_quirks -= quirk
+ else if(quirk in negative_quirks)
+ if(balance + value < 0)
+ to_chat(user, "Refunding this would cause you to go below your balance!")
+ return
+ negative_quirks -= quirk
+ all_quirks -= quirk
+ else if(value > 0)
+ if(positive_quirks.len >= MAX_QUIRKS)
+ to_chat(user, "You can't have more than [MAX_QUIRKS] positive quirks!")
+ return
+ if(balance - value < 0)
+ to_chat(user, "You don't have enough balance to gain this quirk!")
+ return
+ positive_quirks += quirk
+ all_quirks += quirk
+ else
+ negative_quirks += quirk
+ all_quirks += quirk
+ SetQuirks(user)
+ if("reset")
+ all_quirks = list()
+ positive_quirks = list()
+ negative_quirks = list()
+ neutral_quirks = list()
+ SetQuirks(user)
+ else
+ SetQuirks(user)
+ return TRUE
+
+ switch(href_list["task"])
+ if("random")
+ switch(href_list["preference"])
+ if("name")
+ real_name = pref_species.random_name(gender,1)
+ if("age")
+ age = rand(AGE_MIN, AGE_MAX)
+ if("hair")
+ hair_color = random_short_color()
+ if("hair_style")
+ hair_style = random_hair_style(gender)
+ if("facial")
+ facial_hair_color = random_short_color()
+ if("facial_hair_style")
+ facial_hair_style = random_facial_hair_style(gender)
+ if("underwear")
+ underwear = random_underwear(gender)
+ if("undershirt")
+ undershirt = random_undershirt(gender)
+ if("socks")
+ socks = random_socks()
+ if(BODY_ZONE_PRECISE_EYES)
+ eye_color = random_eye_color()
+ if("s_tone")
+ skin_tone = random_skin_tone()
+ if("bag")
+ backbag = pick(GLOB.backbaglist)
+ if("all")
+ random_character()
+
+ if("input")
+
+ if(href_list["preference"] in GLOB.preferences_custom_names)
+ ask_for_custom_name(user,href_list["preference"])
+
+
+ switch(href_list["preference"])
+ if("ghostform")
+ if(unlock_content)
+ var/new_form = input(user, "Thanks for supporting BYOND - Choose your ghostly form:","Thanks for supporting BYOND",null) as null|anything in GLOB.ghost_forms
+ if(new_form)
+ ghost_form = new_form
+ if("ghostorbit")
+ if(unlock_content)
+ var/new_orbit = input(user, "Thanks for supporting BYOND - Choose your ghostly orbit:","Thanks for supporting BYOND", null) as null|anything in GLOB.ghost_orbits
+ if(new_orbit)
+ ghost_orbit = new_orbit
+
+ if("ghostaccs")
+ var/new_ghost_accs = alert("Do you want your ghost to show full accessories where possible, hide accessories but still use the directional sprites where possible, or also ignore the directions and stick to the default sprites?",,GHOST_ACCS_FULL_NAME, GHOST_ACCS_DIR_NAME, GHOST_ACCS_NONE_NAME)
+ switch(new_ghost_accs)
+ if(GHOST_ACCS_FULL_NAME)
+ ghost_accs = GHOST_ACCS_FULL
+ if(GHOST_ACCS_DIR_NAME)
+ ghost_accs = GHOST_ACCS_DIR
+ if(GHOST_ACCS_NONE_NAME)
+ ghost_accs = GHOST_ACCS_NONE
+
+ if("ghostothers")
+ var/new_ghost_others = alert("Do you want the ghosts of others to show up as their own setting, as their default sprites or always as the default white ghost?",,GHOST_OTHERS_THEIR_SETTING_NAME, GHOST_OTHERS_DEFAULT_SPRITE_NAME, GHOST_OTHERS_SIMPLE_NAME)
+ switch(new_ghost_others)
+ if(GHOST_OTHERS_THEIR_SETTING_NAME)
+ ghost_others = GHOST_OTHERS_THEIR_SETTING
+ if(GHOST_OTHERS_DEFAULT_SPRITE_NAME)
+ ghost_others = GHOST_OTHERS_DEFAULT_SPRITE
+ if(GHOST_OTHERS_SIMPLE_NAME)
+ ghost_others = GHOST_OTHERS_SIMPLE
+
+ if("name")
+ var/new_name = input(user, "Choose your character's name:", "Character Preference") as text|null
+ if(new_name)
+ new_name = reject_bad_name(new_name)
+ if(new_name)
+ real_name = new_name
+ else
+ to_chat(user, "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and .")
+
+ if("age")
+ var/new_age = input(user, "Choose your character's age:\n([AGE_MIN]-[AGE_MAX])", "Character Preference") as num|null
+ if(new_age)
+ age = max(min( round(text2num(new_age)), AGE_MAX),AGE_MIN)
+
+ if("flavor_text")
+ var/msg = stripped_multiline_input(usr,"Set the flavor text in your 'examine' verb. This can also be used for OOC notes and preferences!","Flavor Text",html_decode(features["flavor_text"]), MAX_MESSAGE_LEN*2, TRUE) as null|message
+ if(!isnull(msg))
+ msg = copytext(msg, 1, MAX_MESSAGE_LEN*2)
+ features["flavor_text"] = msg
+
+ if("hair")
+ var/new_hair = input(user, "Choose your character's hair colour:", "Character Preference","#"+hair_color) as color|null
+ if(new_hair)
+ hair_color = sanitize_hexcolor(new_hair)
+
+ if("hair_style")
+ var/new_hair_style
+ if(gender == MALE)
+ new_hair_style = input(user, "Choose your character's hair style:", "Character Preference") as null|anything in GLOB.hair_styles_male_list
+ else
+ new_hair_style = input(user, "Choose your character's hair style:", "Character Preference") as null|anything in GLOB.hair_styles_female_list
+ if(new_hair_style)
+ hair_style = new_hair_style
+
+ if("next_hair_style")
+ if (gender == MALE)
+ hair_style = next_list_item(hair_style, GLOB.hair_styles_male_list)
+ else
+ hair_style = next_list_item(hair_style, GLOB.hair_styles_female_list)
+
+ if("previous_hair_style")
+ if (gender == MALE)
+ hair_style = previous_list_item(hair_style, GLOB.hair_styles_male_list)
+ else
+ hair_style = previous_list_item(hair_style, GLOB.hair_styles_female_list)
+
+ if("facial")
+ var/new_facial = input(user, "Choose your character's facial-hair colour:", "Character Preference","#"+facial_hair_color) as color|null
+ if(new_facial)
+ facial_hair_color = sanitize_hexcolor(new_facial)
+ if("facial_hair_style")
+ var/new_facial_hair_style
+ if(gender == MALE)
+ new_facial_hair_style = input(user, "Choose your character's facial-hair style:", "Character Preference") as null|anything in GLOB.facial_hair_styles_male_list
+ else
+ new_facial_hair_style = input(user, "Choose your character's facial-hair style:", "Character Preference") as null|anything in GLOB.facial_hair_styles_female_list
+ if(new_facial_hair_style)
+ facial_hair_style = new_facial_hair_style
+
+ if("next_facehair_style")
+ if (gender == MALE)
+ facial_hair_style = next_list_item(facial_hair_style, GLOB.facial_hair_styles_male_list)
+ else
+ facial_hair_style = next_list_item(facial_hair_style, GLOB.facial_hair_styles_female_list)
+ if("previous_facehair_style")
+ if (gender == MALE)
+ facial_hair_style = previous_list_item(facial_hair_style, GLOB.facial_hair_styles_male_list)
+ else
+ facial_hair_style = previous_list_item(facial_hair_style, GLOB.facial_hair_styles_female_list)
+
+ if("underwear")
+ var/new_underwear
+ if(gender == MALE)
+ new_underwear = input(user, "Choose your character's underwear:", "Character Preference") as null|anything in GLOB.underwear_m
+ else
+ new_underwear = input(user, "Choose your character's underwear:", "Character Preference") as null|anything in GLOB.underwear_f
+ if(new_underwear)
+ underwear = new_underwear
+
+ if("undershirt")
+ var/new_undershirt
+ if(gender == MALE)
+ new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in GLOB.undershirt_m
+ else
+ new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in GLOB.undershirt_f
+ if(new_undershirt)
+ undershirt = new_undershirt
+
+ if("socks")
+ var/new_socks
+ new_socks = input(user, "Choose your character's socks:", "Character Preference") as null|anything in GLOB.socks_list
+ if(new_socks)
+ socks = new_socks
+
+ if("eyes")
+ var/new_eyes = input(user, "Choose your character's eye colour:", "Character Preference","#"+eye_color) as color|null
+ if(new_eyes)
+ eye_color = sanitize_hexcolor(new_eyes)
+
+ if("species")
+ var/result = input(user, "Select a species", "Species Selection") as null|anything in GLOB.roundstart_races
+ if(result)
+ var/newtype = GLOB.species_list[result]
+ pref_species = new newtype()
+ //let's ensure that no weird shit happens on species swapping.
+ if(!("body_markings" in pref_species.default_features))
+ features["body_markings"] = "None"
+ if(!("mam_body_markings" in pref_species.default_features))
+ features["mam_body_markings"] = "None"
+ if("mam_body_markings" in pref_species.default_features && features["mam_body_markings"] == "None")
+ features["mam_body_markings"] = "Plain"
+ if("tail_lizard" in pref_species.default_features)
+ features["tail_lizard"] = "Smooth"
+ if("mam_tail" in pref_species.default_features)
+ features["mam_tail"] = "None"
+ if("mam_ears" in pref_species.default_features)
+ features["mam_ears"] = "None"
+ if(pref_species.id == "felinid")
+ features["mam_tail"] = "Cat"
+ features["mam_ears"] = "Cat"
+
+ //Now that we changed our species, we must verify that the mutant colour is still allowed.
+ var/temp_hsv = RGBtoHSV(features["mcolor"])
+ if(features["mcolor"] == "#000" || (!(MUTCOLORS_PARTSONLY in pref_species.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#202020")[3]))
+ features["mcolor"] = pref_species.default_color
+ if(features["mcolor2"] == "#000" || (!(MUTCOLORS_PARTSONLY in pref_species.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#202020")[3]))
+ features["mcolor2"] = pref_species.default_color
+ if(features["mcolor3"] == "#000" || (!(MUTCOLORS_PARTSONLY in pref_species.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#202020")[3]))
+ features["mcolor3"] = pref_species.default_color
+
+ if("mutant_color")
+ var/new_mutantcolor = input(user, "Choose your character's alien/mutant color:", "Character Preference","#"+features["mcolor"]) as color|null
+ if(new_mutantcolor)
+ var/temp_hsv = RGBtoHSV(new_mutantcolor)
+ if(new_mutantcolor == "#000000")
+ features["mcolor"] = pref_species.default_color
+ update_preview_icon()
+ else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) // mutantcolors must be bright, but only if they affect the skin
+ features["mcolor"] = sanitize_hexcolor(new_mutantcolor)
+ update_preview_icon()
+ else
+ to_chat(user, "Invalid color. Your color is not bright enough.")
+
+ if("mutant_color2")
+ var/new_mutantcolor = input(user, "Choose your character's secondary alien/mutant color:", "Character Preference") as color|null
+ if(new_mutantcolor)
+ var/temp_hsv = RGBtoHSV(new_mutantcolor)
+ if(new_mutantcolor == "#000000")
+ features["mcolor2"] = pref_species.default_color
+ update_preview_icon()
+ else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) // mutantcolors must be bright, but only if they affect the skin
+ features["mcolor2"] = sanitize_hexcolor(new_mutantcolor)
+ update_preview_icon()
+ else
+ to_chat(user, "Invalid color. Your color is not bright enough.")
+
+ if("mutant_color3")
+ var/new_mutantcolor = input(user, "Choose your character's tertiary alien/mutant color:", "Character Preference") as color|null
+ if(new_mutantcolor)
+ var/temp_hsv = RGBtoHSV(new_mutantcolor)
+ if(new_mutantcolor == "#000000")
+ features["mcolor3"] = pref_species.default_color
+ update_preview_icon()
+ else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) // mutantcolors must be bright, but only if they affect the skin
+ features["mcolor3"] = sanitize_hexcolor(new_mutantcolor)
+ update_preview_icon()
+ else
+ to_chat(user, "Invalid color. Your color is not bright enough.")
+
+ if("ipc_screen")
+ var/new_ipc_screen
+ new_ipc_screen = input(user, "Choose your character's screen:", "Character Preference") as null|anything in GLOB.ipc_screens_list
+ if(new_ipc_screen)
+ features["ipc_screen"] = new_ipc_screen
+
+ if("ipc_antenna")
+ var/new_ipc_antenna
+ new_ipc_antenna = input(user, "Choose your character's antenna:", "Character Preference") as null|anything in GLOB.ipc_antennas_list
+ if(new_ipc_antenna)
+ features["ipc_antenna"] = new_ipc_antenna
+
+ if("tail_lizard")
+ var/new_tail
+ new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in GLOB.tails_list_lizard
+ if(new_tail)
+ features["tail_lizard"] = new_tail
+ if(new_tail != "None")
+ features["taur"] = "None"
+ features["tail_human"] = "None"
+ features["mam_tail"] = "None"
+
+ if("tail_human")
+ var/list/snowflake_tails_list = list()
+ for(var/path in GLOB.tails_list_human)
+ var/datum/sprite_accessory/tails/human/instance = GLOB.tails_list_human[path]
+ if(istype(instance, /datum/sprite_accessory))
+ var/datum/sprite_accessory/S = instance
+ if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
+ snowflake_tails_list[S.name] = path
+ var/new_tail
+ new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in snowflake_tails_list
+ if(new_tail)
+ features["tail_human"] = new_tail
+ if(new_tail != "None")
+ features["taur"] = "None"
+ features["tail_lizard"] = "None"
+ features["mam_tail"] = "None"
+
+ if("mam_tail")
+ var/list/snowflake_tails_list = list()
+ for(var/path in GLOB.mam_tails_list)
+ var/datum/sprite_accessory/mam_tails/instance = GLOB.mam_tails_list[path]
+ if(istype(instance, /datum/sprite_accessory))
+ var/datum/sprite_accessory/S = instance
+ if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
+ snowflake_tails_list[S.name] = path
+ var/new_tail
+ new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in snowflake_tails_list
+ if(new_tail)
+ features["mam_tail"] = new_tail
+ if(new_tail != "None")
+ features["taur"] = "None"
+ features["tail_human"] = "None"
+ features["tail_lizard"] = "None"
+
+ if("snout")
+ var/new_snout
+ new_snout = input(user, "Choose your character's snout:", "Character Preference") as null|anything in GLOB.snouts_list
+ if(new_snout)
+ features["snout"] = new_snout
+
+ if("mam_snouts")
+ var/new_mam_snouts
+ new_mam_snouts = input(user, "Choose your character's snout:", "Character Preference") as null|anything in GLOB.mam_snouts_list
+ if(new_mam_snouts)
+ features["mam_snouts"] = new_mam_snouts
+
+ if("horns")
+ var/new_horns
+ new_horns = input(user, "Choose your character's horns:", "Character Preference") as null|anything in GLOB.horns_list
+ if(new_horns)
+ features["horns"] = new_horns
+
+ if("ears")
+ var/new_ears
+ new_ears = input(user, "Choose your character's ears:", "Character Preference") as null|anything in GLOB.ears_list
+ if(new_ears)
+ features["ears"] = new_ears
+
+ if("wings")
+ var/new_wings
+ new_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.r_wings_list
+ if(new_wings)
+ features["wings"] = new_wings
+
+ if("frills")
+ var/new_frills
+ new_frills = input(user, "Choose your character's frills:", "Character Preference") as null|anything in GLOB.frills_list
+ if(new_frills)
+ features["frills"] = new_frills
+
+ if("spines")
+ var/new_spines
+ new_spines = input(user, "Choose your character's spines:", "Character Preference") as null|anything in GLOB.spines_list
+ if(new_spines)
+ features["spines"] = new_spines
+
+ if("body_markings")
+ var/new_body_markings
+ new_body_markings = input(user, "Choose your character's body markings:", "Character Preference") as null|anything in GLOB.body_markings_list
+ if(new_body_markings)
+ features["body_markings"] = new_body_markings
+ if(new_body_markings != "None")
+ features["mam_body_markings"] = "None"
+ update_preview_icon()
+
+ if("legs")
+ var/new_legs
+ new_legs = input(user, "Choose your character's legs:", "Character Preference") as null|anything in GLOB.legs_list
+ if(new_legs)
+ features["legs"] = new_legs
+ update_preview_icon()
+
+ if("moth_wings")
+ var/new_moth_wings
+ new_moth_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.moth_wings_list
+ if(new_moth_wings)
+ features["moth_wings"] = new_moth_wings
+
+ if("s_tone")
+ var/new_s_tone = input(user, "Choose your character's skin-tone:", "Character Preference") as null|anything in GLOB.skin_tones
+ if(new_s_tone)
+ skin_tone = new_s_tone
+
+ if("taur")
+ var/list/snowflake_taur_list = list()
+ for(var/path in GLOB.taur_list)
+ var/datum/sprite_accessory/taur/instance = GLOB.taur_list[path]
+ if(istype(instance, /datum/sprite_accessory))
+ var/datum/sprite_accessory/S = instance
+ if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
+ snowflake_taur_list[S.name] = path
+ var/new_taur
+ new_taur = input(user, "Choose your character's tauric body:", "Character Preference") as null|anything in snowflake_taur_list
+ if(new_taur)
+ features["taur"] = new_taur
+ if(new_taur != "None")
+ features["mam_tail"] = "None"
+ features["xenotail"] = "None"
+ features["tail_human"] = "None"
+ features["tail_lizard"] = "None"
+
+ if("ears")
+ var/list/snowflake_ears_list = list()
+ for(var/path in GLOB.ears_list)
+ var/datum/sprite_accessory/ears/instance = GLOB.ears_list[path]
+ if(istype(instance, /datum/sprite_accessory))
+ var/datum/sprite_accessory/S = instance
+ if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
+ snowflake_ears_list[S.name] = path
+ var/new_ears
+ new_ears = input(user, "Choose your character's ears:", "Character Preference") as null|anything in snowflake_ears_list
+ if(new_ears)
+ features["ears"] = new_ears
+
+ if("mam_ears")
+ var/list/snowflake_ears_list = list()
+ for(var/path in GLOB.mam_ears_list)
+ var/datum/sprite_accessory/mam_ears/instance = GLOB.mam_ears_list[path]
+ if(istype(instance, /datum/sprite_accessory))
+ var/datum/sprite_accessory/S = instance
+ if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
+ snowflake_ears_list[S.name] = path
+ var/new_ears
+ new_ears = input(user, "Choose your character's ears:", "Character Preference") as null|anything in snowflake_ears_list
+ if(new_ears)
+ features["mam_ears"] = new_ears
+
+ if("mam_body_markings")
+ var/list/snowflake_markings_list = list()
+ for(var/path in GLOB.mam_body_markings_list)
+ var/datum/sprite_accessory/mam_body_markings/instance = GLOB.mam_body_markings_list[path]
+ if(istype(instance, /datum/sprite_accessory))
+ var/datum/sprite_accessory/S = instance
+ if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
+ snowflake_markings_list[S.name] = path
+ var/new_mam_body_markings
+ new_mam_body_markings = input(user, "Choose your character's body markings:", "Character Preference") as null|anything in snowflake_markings_list
+ if(new_mam_body_markings)
+ features["mam_body_markings"] = new_mam_body_markings
+ if(new_mam_body_markings != "None")
+ features["body_markings"] = "None"
+ else if(new_mam_body_markings == "None")
+ features["mam_body_markings"] = "Plain"
+ features["body_markings"] = "None"
+ update_preview_icon()
+
+ //Xeno Bodyparts
+ if("xenohead")//Head or caste type
+ var/new_head
+ new_head = input(user, "Choose your character's caste:", "Character Preference") as null|anything in GLOB.xeno_head_list
+ if(new_head)
+ features["xenohead"] = new_head
+
+ if("xenotail")//Currently one one type, more maybe later if someone sprites them. Might include animated variants in the future.
+ var/new_tail
+ new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in GLOB.xeno_tail_list
+ if(new_tail)
+ features["xenotail"] = new_tail
+ if(new_tail != "None")
+ features["mam_tail"] = "None"
+ features["taur"] = "None"
+ features["tail_human"] = "None"
+ features["tail_lizard"] = "None"
+
+ if("xenodorsal")
+ var/new_dors
+ new_dors = input(user, "Choose your character's dorsal tube type:", "Character Preference") as null|anything in GLOB.xeno_dorsal_list
+ if(new_dors)
+ features["xenodorsal"] = new_dors
+ //Genital code
+ if("cock_color")
+ var/new_cockcolor = input(user, "Penis color:", "Character Preference") as color|null
+ if(new_cockcolor)
+ var/temp_hsv = RGBtoHSV(new_cockcolor)
+ if(new_cockcolor == "#000000")
+ features["cock_color"] = pref_species.default_color
+ else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
+ features["cock_color"] = sanitize_hexcolor(new_cockcolor)
+ else
+ user << "Invalid color. Your color is not bright enough."
+
+ if("cock_length")
+ var/new_length = input(user, "Penis length in inches:\n([COCK_SIZE_MIN]-[COCK_SIZE_MAX])", "Character Preference") as num|null
+ if(new_length)
+ features["cock_length"] = max(min( round(text2num(new_length)), COCK_SIZE_MAX),COCK_SIZE_MIN)
+
+ if("cock_shape")
+ var/new_shape
+ new_shape = input(user, "Penis shape:", "Character Preference") as null|anything in GLOB.cock_shapes_list
+ if(new_shape)
+ features["cock_shape"] = new_shape
+
+ if("balls_color")
+ var/new_ballscolor = input(user, "Testicle Color:", "Character Preference") as color|null
+ if(new_ballscolor)
+ var/temp_hsv = RGBtoHSV(new_ballscolor)
+ if(new_ballscolor == "#000000")
+ features["balls_color"] = pref_species.default_color
+ else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
+ features["balls_color"] = sanitize_hexcolor(new_ballscolor)
+ else
+ user << "Invalid color. Your color is not bright enough."
+
+ if("egg_size")
+ var/new_size
+ var/list/egg_sizes = list(1,2,3)
+ new_size = input(user, "Egg Diameter(inches):", "Egg Size") as null|anything in egg_sizes
+ if(new_size)
+ features["eggsack_egg_size"] = new_size
+
+ if("egg_color")
+ var/new_egg_color = input(user, "Egg Color:", "Character Preference") as color|null
+ if(new_egg_color)
+ var/temp_hsv = RGBtoHSV(new_egg_color)
+ if(ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
+ features["eggsack_egg_color"] = sanitize_hexcolor(new_egg_color)
+ else
+ user << "Invalid color. Your color is not bright enough."
+
+ if("breasts_size")
+ var/new_size
+ new_size = input(user, "Breast Size", "Character Preference") as null|anything in GLOB.breasts_size_list
+ if(new_size)
+ features["breasts_size"] = new_size
+
+ if("breasts_shape")
+ var/new_shape
+ new_shape = input(user, "Breast Shape", "Character Preference") as null|anything in GLOB.breasts_shapes_list
+ if(new_shape)
+ features["breasts_shape"] = new_shape
+
+ if("breasts_color")
+ var/new_breasts_color = input(user, "Breast Color:", "Character Preference") as color|null
+ if(new_breasts_color)
+ var/temp_hsv = RGBtoHSV(new_breasts_color)
+ if(new_breasts_color == "#000000")
+ features["breasts_color"] = pref_species.default_color
+ else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
+ features["breasts_color"] = sanitize_hexcolor(new_breasts_color)
+ else
+ user << "Invalid color. Your color is not bright enough."
+
+ if("vag_shape")
+ var/new_shape
+ new_shape = input(user, "Vagina Type", "Character Preference") as null|anything in GLOB.vagina_shapes_list
+ if(new_shape)
+ features["vag_shape"] = new_shape
+
+ if("vag_color")
+ var/new_vagcolor = input(user, "Vagina color:", "Character Preference") as color|null
+ if(new_vagcolor)
+ var/temp_hsv = RGBtoHSV(new_vagcolor)
+ if(new_vagcolor == "#000000")
+ features["vag_color"] = pref_species.default_color
+ else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
+ features["vag_color"] = sanitize_hexcolor(new_vagcolor)
+ else
+ user << "Invalid color. Your color is not bright enough."
+
+ if("ooccolor")
+ var/new_ooccolor = input(user, "Choose your OOC colour:", "Game Preference",ooccolor) as color|null
+ if(new_ooccolor)
+ ooccolor = new_ooccolor
+
+ if("bag")
+ var/new_backbag = input(user, "Choose your character's style of bag:", "Character Preference") as null|anything in GLOB.backbaglist
+ if(new_backbag)
+ backbag = new_backbag
+
+ if("uplink_loc")
+ var/new_loc = input(user, "Choose your character's traitor uplink spawn location:", "Character Preference") as null|anything in GLOB.uplink_spawn_loc_list
+ if(new_loc)
+ uplink_spawn_loc = new_loc
+
+ if("sec_dept")
+ var/department = input(user, "Choose your prefered security department:", "Security Departments") as null|anything in GLOB.security_depts_prefs
+ if(department)
+ prefered_security_department = department
+
+ if ("preferred_map")
+ var/maplist = list()
+ var/default = "Default"
+ if (config.defaultmap)
+ default += " ([config.defaultmap.map_name])"
+ for (var/M in config.maplist)
+ var/datum/map_config/VM = config.maplist[M]
+ var/friendlyname = "[VM.map_name] "
+ if (VM.voteweight <= 0)
+ friendlyname += " (disabled)"
+ maplist[friendlyname] = VM.map_name
+ maplist[default] = null
+ var/pickedmap = input(user, "Choose your preferred map. This will be used to help weight random map selection.", "Character Preference") as null|anything in maplist
+ if (pickedmap)
+ preferred_map = maplist[pickedmap]
+
+ if ("clientfps")
+ var/desiredfps = input(user, "Choose your desired fps. (0 = synced with server tick rate (currently:[world.fps]))", "Character Preference", clientfps) as null|num
+ if (!isnull(desiredfps))
+ clientfps = desiredfps
+ parent.fps = desiredfps
+ if("ui")
+ var/pickedui = input(user, "Choose your UI style.", "Character Preference", UI_style) as null|anything in GLOB.available_ui_styles
+ if(pickedui)
+ UI_style = pickedui
+ if (parent && parent.mob && parent.mob.hud_used)
+ parent.mob.hud_used.update_ui_style(ui_style2icon(UI_style))
+ if("pda_style")
+ var/pickedPDAStyle = input(user, "Choose your PDA style.", "Character Preference", pda_style) as null|anything in GLOB.pda_styles
+ if(pickedPDAStyle)
+ pda_style = pickedPDAStyle
+ if("pda_color")
+ var/pickedPDAColor = input(user, "Choose your PDA Interface color.", "Character Preference",pda_color) as color|null
+ if(pickedPDAColor)
+ pda_color = pickedPDAColor
+
+ else
+ switch(href_list["preference"])
+ //CITADEL PREFERENCES EDIT - I can't figure out how to modularize these, so they have to go here. :c -Pooj
+ if("genital_colour")
+ features["genitals_use_skintone"] = !features["genitals_use_skintone"]
+ if("arousable")
+ arousable = !arousable
+ if("has_cock")
+ features["has_cock"] = !features["has_cock"]
+ if("has_balls")
+ features["has_balls"] = !features["has_balls"]
+ if("has_ovi")
+ features["has_ovi"] = !features["has_ovi"]
+ if("has_eggsack")
+ features["has_eggsack"] = !features["has_eggsack"]
+ if("balls_internal")
+ features["balls_internal"] = !features["balls_internal"]
+ if("eggsack_internal")
+ features["eggsack_internal"] = !features["eggsack_internal"]
+ if("has_breasts")
+ features["has_breasts"] = !features["has_breasts"]
+ if("has_vag")
+ features["has_vag"] = !features["has_vag"]
+ if("has_womb")
+ features["has_womb"] = !features["has_womb"]
+ if("exhibitionist")
+ features["exhibitionist"] = !features["exhibitionist"]
+ if("widescreenpref")
+ widescreenpref = !widescreenpref
+ user.client.change_view(CONFIG_GET(string/default_view))
+ if("autostand")
+ autostand = !autostand
+ if ("screenshake")
+ var/desiredshake = input(user, "Set the amount of screenshake you want. \n(0 = disabled, 100 = full, 200 = maximum.)", "Character Preference", screenshake) as null|num
+ if (!isnull(desiredshake))
+ screenshake = desiredshake
+ if("damagescreenshake")
+ switch(damagescreenshake)
+ if(0)
+ damagescreenshake = 1
+ if(1)
+ damagescreenshake = 2
+ if(2)
+ damagescreenshake = 0
+ else
+ damagescreenshake = 1
+ if("nameless")
+ nameless = !nameless
+ //END CITADEL EDIT
+ if("publicity")
+ if(unlock_content)
+ toggles ^= MEMBER_PUBLIC
+ if("gender")
+ var/chosengender = input(user, "Select your character's gender.", "Gender Selection", gender) in list(MALE,FEMALE,"nonbinary","object")
+ switch(chosengender)
+ if("nonbinary")
+ chosengender = PLURAL
+ if("object")
+ chosengender = NEUTER
+ gender = chosengender
+ facial_hair_style = random_facial_hair_style(gender)
+ hair_style = random_hair_style(gender)
+
+ if("hotkeys")
+ hotkeys = !hotkeys
+ if(hotkeys)
+ winset(user, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=default")
+ else
+ winset(user, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=old_default")
+ if("action_buttons")
+ buttons_locked = !buttons_locked
+ if("tgui_fancy")
+ tgui_fancy = !tgui_fancy
+ if("tgui_lock")
+ tgui_lock = !tgui_lock
+ if("winflash")
+ windowflashing = !windowflashing
+ if("hear_adminhelps")
+ toggles ^= SOUND_ADMINHELP
+ if("announce_login")
+ toggles ^= ANNOUNCE_LOGIN
+ if("combohud_lighting")
+ toggles ^= COMBOHUD_LIGHTING
+
+ if("be_special")
+ var/be_special_type = href_list["be_special_type"]
+ if(be_special_type in be_special)
+ be_special -= be_special_type
+ else
+ be_special += be_special_type
+
+ if("name")
+ be_random_name = !be_random_name
+
+ if("all")
+ be_random_body = !be_random_body
+
+ if("hear_midis")
+ toggles ^= SOUND_MIDI
+
+ if("lobby_music")
+ toggles ^= SOUND_LOBBY
+ if((toggles & SOUND_LOBBY) && user.client && isnewplayer(user))
+ user.client.playtitlemusic()
+ else
+ user.stop_sound_channel(CHANNEL_LOBBYMUSIC)
+
+ if("ghost_ears")
+ chat_toggles ^= CHAT_GHOSTEARS
+
+ if("ghost_sight")
+ chat_toggles ^= CHAT_GHOSTSIGHT
+
+ if("ghost_whispers")
+ chat_toggles ^= CHAT_GHOSTWHISPER
+
+ if("ghost_radio")
+ chat_toggles ^= CHAT_GHOSTRADIO
+
+ if("ghost_pda")
+ chat_toggles ^= CHAT_GHOSTPDA
+
+ if("pull_requests")
+ chat_toggles ^= CHAT_PULLR
+
+ if("allow_midround_antag")
+ toggles ^= MIDROUND_ANTAG
+
+ if("parallaxup")
+ parallax = WRAP(parallax + 1, PARALLAX_INSANE, PARALLAX_DISABLE + 1)
+ if (parent && parent.mob && parent.mob.hud_used)
+ parent.mob.hud_used.update_parallax_pref(parent.mob)
+
+ if("parallaxdown")
+ parallax = WRAP(parallax - 1, PARALLAX_INSANE, PARALLAX_DISABLE + 1)
+ if (parent && parent.mob && parent.mob.hud_used)
+ parent.mob.hud_used.update_parallax_pref(parent.mob)
+
+ // Citadel edit - Prefs don't work outside of this. :c
+ if("hound_sleeper")
+ cit_toggles ^= MEDIHOUND_SLEEPER
+
+ if("toggleeatingnoise")
+ cit_toggles ^= EATING_NOISES
+
+ if("toggledigestionnoise")
+ cit_toggles ^= DIGESTION_NOISES
+ //END CITADEL EDIT
+
+ if("ambientocclusion")
+ ambientocclusion = !ambientocclusion
+ if(parent && parent.screen && parent.screen.len)
+ var/obj/screen/plane_master/game_world/PM = locate(/obj/screen/plane_master/game_world) in parent.screen
+ PM.backdrop(parent.mob)
+
+ if("auto_fit_viewport")
+ auto_fit_viewport = !auto_fit_viewport
+ if(auto_fit_viewport && parent)
+ parent.fit_viewport()
+
+ if("save")
+ save_preferences()
+ save_character()
+
+ if("load")
+ load_preferences()
+ load_character()
+ if(parent && parent.prefs_vr)
+ attempt_vr(parent.prefs_vr,"load_vore","")
+
+ if("changeslot")
+ if(!load_character(text2num(href_list["num"])))
+ random_character()
+ real_name = random_unique_name(gender)
+ save_character()
+ if(parent && parent.prefs_vr)
+ attempt_vr(parent.prefs_vr,"load_vore","")
+
+ if("tab")
+ if (href_list["tab"])
+ current_tab = text2num(href_list["tab"])
+ if(href_list["preference"] == "gear")
+ if(href_list["clear_loadout"])
+ LAZYCLEARLIST(chosen_gear)
+ gear_points = initial(gear_points)
+ save_preferences()
+ if(href_list["select_category"])
+ for(var/i in GLOB.loadout_items)
+ if(i == href_list["select_category"])
+ gear_tab = i
+ if(href_list["toggle_gear_path"])
+ var/datum/gear/G = GLOB.loadout_items[gear_tab][html_decode(href_list["toggle_gear_path"])]
+ if(!G)
+ return
+ var/toggle = text2num(href_list["toggle_gear"])
+ if(!toggle && (G.type in chosen_gear))//toggling off and the item effectively is in chosen gear)
+ LAZYREMOVE(chosen_gear, G.type)
+ gear_points += initial(G.cost)
+ else if(toggle && (!(is_type_in_ref_list(G, chosen_gear))))
+ if(!is_loadout_slot_available(G.category))
+ to_chat(user, "You cannot take this loadout, as you've already chosen too many of the same category!")
+ return
+ if(G.ckeywhitelist && G.ckeywhitelist.len && !(user.ckey in G.ckeywhitelist))
+ to_chat(user, "This is an item intended for donator use only. You are not authorized to use this item.")
+ return
+ if(gear_points >= initial(G.cost))
+ LAZYADD(chosen_gear, G.type)
+ gear_points -= initial(G.cost)
+
+ ShowChoices(user)
+ return 1
+
+/datum/preferences/proc/copy_to(mob/living/carbon/human/character, icon_updates = 1, roundstart_checks = TRUE)
+ if(be_random_name)
+ real_name = pref_species.random_name(gender)
+
+ if(be_random_body)
+ random_character(gender)
+
+ if(roundstart_checks)
+ if(CONFIG_GET(flag/humans_need_surnames) && (pref_species.id == "human"))
+ var/firstspace = findtext(real_name, " ")
+ var/name_length = length(real_name)
+ if(!firstspace) //we need a surname
+ real_name += " [pick(GLOB.last_names)]"
+ else if(firstspace == name_length)
+ real_name += "[pick(GLOB.last_names)]"
+
+ character.real_name = nameless ? "[real_name] #[rand(10000, 99999)]" : real_name
+ character.name = character.real_name
+ character.nameless = nameless
+
+ character.gender = gender
+ character.age = age
+
+ character.eye_color = eye_color
+ var/obj/item/organ/eyes/organ_eyes = character.getorgan(/obj/item/organ/eyes)
+ if(organ_eyes)
+ if(!initial(organ_eyes.eye_color))
+ organ_eyes.eye_color = eye_color
+ organ_eyes.old_eye_color = eye_color
+ character.hair_color = hair_color
+ character.facial_hair_color = facial_hair_color
+
+ character.skin_tone = skin_tone
+ character.hair_style = hair_style
+ character.facial_hair_style = facial_hair_style
+ character.underwear = underwear
+ character.undershirt = undershirt
+ character.socks = socks
+
+ character.backbag = backbag
+
+ var/datum/species/chosen_species
+ if(!roundstart_checks || (pref_species.id in GLOB.roundstart_races))
+ chosen_species = pref_species.type
+ else
+ chosen_species = /datum/species/human
+ pref_species = new /datum/species/human
+ save_character()
+
+ character.set_species(chosen_species, icon_update = FALSE, pref_load = TRUE)
+ character.dna.features = features.Copy()
+ character.dna.real_name = character.real_name
+ character.dna.nameless = character.nameless
+
+ if("tail_lizard" in pref_species.default_features)
+ character.dna.species.mutant_bodyparts |= "tail_lizard"
+ else if("mam_tail" in pref_species.default_features)
+ character.dna.species.mutant_bodyparts |= "mam_tail"
+ else if("xenotail" in pref_species.default_features)
+ character.dna.species.mutant_bodyparts |= "xenotail"
+
+ if("legs" in pref_species.default_features)
+ if(character.dna.features["legs"] == "Digitigrade Legs")
+ pref_species.species_traits += DIGITIGRADE
+ character.Digitigrade_Leg_Swap(FALSE)
+
+ if(character.dna.features["legs"] == "Normal Legs" && DIGITIGRADE in pref_species.species_traits)
+ pref_species.species_traits -= DIGITIGRADE
+ character.Digitigrade_Leg_Swap(TRUE)
+
+ else if((!"legs" in pref_species.default_features) && DIGITIGRADE in pref_species.species_traits)
+ pref_species.species_traits -= DIGITIGRADE
+ character.Digitigrade_Leg_Swap(TRUE)
+
+ if(DIGITIGRADE in pref_species.species_traits)
+ character.Digitigrade_Leg_Swap(FALSE)
+
+ if(icon_updates)
+ character.update_body()
+ character.update_hair()
+ character.update_body_parts()
+
+/datum/preferences/proc/get_default_name(name_id)
+ switch(name_id)
+ if("human")
+ return random_unique_name()
+ if("ai")
+ return pick(GLOB.ai_names)
+ if("cyborg")
+ return DEFAULT_CYBORG_NAME
+ if("clown")
+ return pick(GLOB.clown_names)
+ if("mime")
+ return pick(GLOB.mime_names)
+ return random_unique_name()
+
+/datum/preferences/proc/ask_for_custom_name(mob/user,name_id)
+ var/namedata = GLOB.preferences_custom_names[name_id]
+ if(!namedata)
+ return
+
+ var/raw_name = input(user, "Choose your character's [namedata["qdesc"]]:","Character Preference") as text|null
+ if(!raw_name)
+ if(namedata["allow_null"])
+ custom_names[name_id] = get_default_name(name_id)
+ else
+ return
+ else
+ var/sanitized_name = reject_bad_name(raw_name,namedata["allow_numbers"])
+ if(!sanitized_name)
+ to_chat(user, "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z,[namedata["allow_numbers"] ? ",0-9," : ""] -, ' and .")
+ return
+ else
+ custom_names[name_id] = sanitized_name
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index fdcc01f7c8..9e19ab65a2 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -302,6 +302,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["feature_mam_ears"] >> features["mam_ears"]
S["feature_mam_tail_animated"] >> features["mam_tail_animated"]
S["feature_taur"] >> features["taur"]
+ S["feature_mam_snouts"] >> features["mam_snouts"]
//Xeno features
S["feature_xeno_tail"] >> features["xenotail"]
S["feature_xeno_dors"] >> features["xenodorsal"]
diff --git a/code/modules/mob/dead/new_player/preferences_setup.dm b/code/modules/mob/dead/new_player/preferences_setup.dm
index c9710a5457..6b67ada775 100644
--- a/code/modules/mob/dead/new_player/preferences_setup.dm
+++ b/code/modules/mob/dead/new_player/preferences_setup.dm
@@ -20,17 +20,19 @@
features = random_features()
age = rand(AGE_MIN,AGE_MAX)
-/datum/preferences/proc/update_preview_icon(nude = FALSE)
+/datum/preferences/proc/update_preview_icon()
// Silicons only need a very basic preview since there is no customization for them.
+// var/wide_icon = FALSE //CITDEL THINGS
+// if(features["taur"] != "None")
+// wide_icon = TRUE
+
if(job_engsec_high)
switch(job_engsec_high)
if(AI_JF)
- preview_icon = icon('icons/mob/ai.dmi', "AI", SOUTH)
- preview_icon.Scale(64, 64)
+ parent.show_character_previews(image('icons/mob/ai.dmi', icon_state = "AI", dir = SOUTH))
return
if(CYBORG)
- preview_icon = icon('icons/mob/robots.dmi', "robot", SOUTH)
- preview_icon.Scale(64, 64)
+ parent.show_character_previews(image('icons/mob/robots.dmi', icon_state = "robot", dir = SOUTH))
return
// Set up the dummy for its photoshoot
@@ -57,30 +59,11 @@
previewJob = job
break
- if(previewJob && !nude)
- mannequin.job = previewJob.title
- previewJob.equip(mannequin, TRUE)
- COMPILE_OVERLAYS(mannequin)
- CHECK_TICK
- preview_icon = icon('icons/effects/effects.dmi', "nothing")
- preview_icon.Scale(48+32, 16+32)
- CHECK_TICK
- mannequin.setDir(NORTH)
+ if(previewJob)
+ if(current_tab != 2)
+ mannequin.job = previewJob.title
+ previewJob.equip(mannequin, TRUE)
- var/icon/stamp = getFlatIcon(mannequin)
- CHECK_TICK
- preview_icon.Blend(stamp, ICON_OVERLAY, 25, 17)
- CHECK_TICK
- mannequin.setDir(WEST)
- stamp = getFlatIcon(mannequin)
- CHECK_TICK
- preview_icon.Blend(stamp, ICON_OVERLAY, 1, 9)
- CHECK_TICK
- mannequin.setDir(SOUTH)
- stamp = getFlatIcon(mannequin)
- CHECK_TICK
- preview_icon.Blend(stamp, ICON_OVERLAY, 49, 1)
- CHECK_TICK
- preview_icon.Scale(preview_icon.Width() * 2, preview_icon.Height() * 2) // Scaling here to prevent blurring in the browser.
- CHECK_TICK
+ COMPILE_OVERLAYS(mannequin)
+ parent.show_character_previews(new /mutable_appearance(mannequin))
unset_busy_human_dummy(DUMMY_HUMAN_SLOT_PREFERENCES)
diff --git a/code/modules/mob/dead/new_player/sprite_accessories.dm b/code/modules/mob/dead/new_player/sprite_accessories.dm
index 76fa1cefe1..2778e3e29c 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories.dm
@@ -1522,18 +1522,3 @@
/datum/sprite_accessory/moth_wings/snow
name = "Snow"
icon_state = "snow"
-
-//Lunasune
-/datum/sprite_accessory/mam_ears/lunasune
- name = "lunasune"
- icon_state = "lunasune"
- hasinner = 1
- extra = TRUE
- extra_color_src = MUTCOLORS2
- ckeys_allowed = list("invader4352")
-
-/datum/sprite_accessory/mam_tails/lunasune
- name = "lunasune"
- icon_state = "lunasune"
- extra = TRUE
- ckeys_allowed = list("invader4352")
diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm
index bd1fba44e2..71a12e9ff4 100644
--- a/code/modules/mob/living/blood.dm
+++ b/code/modules/mob/living/blood.dm
@@ -198,6 +198,11 @@
for(var/V in roundstart_quirks)
var/datum/quirk/T = V
blood_data["quirks"] += T.type
+ blood_data["changeling_loudness"] = 0
+ if(mind)
+ var/datum/antagonist/changeling/ling = mind.has_antag_datum(/datum/antagonist/changeling)
+ if(istype(ling))
+ blood_data["changeling_loudness"] = ling.loudfactor
return blood_data
//get the id of the substance this mob use as blood.
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index aee1daa449..2d4b64c4ad 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -317,9 +317,9 @@ GLOBAL_LIST_EMPTY(roundstart_races)
var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD)
if(!HD) //Decapitated
return
-
if(H.has_trait(TRAIT_HUSK))
return
+
var/datum/sprite_accessory/S
var/list/standing = list()
@@ -351,7 +351,6 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(H.facial_hair_style && (FACEHAIR in species_traits) && (!facialhair_hidden || dynamic_fhair_suffix))
S = GLOB.facial_hair_styles_list[H.facial_hair_style]
if(S)
-
//List of all valid dynamic_fhair_suffixes
var/static/list/fextensions
if(!fextensions)
@@ -410,7 +409,6 @@ GLOBAL_LIST_EMPTY(roundstart_races)
else if(H.hair_style && (HAIR in species_traits))
S = GLOB.hair_styles_list[H.hair_style]
if(S)
-
//List of all valid dynamic_hair_suffixes
var/static/list/extensions
if(!extensions)
@@ -612,6 +610,10 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(!H.dna.features["mam_ears"] || H.dna.features["mam_ears"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD || HD.status == BODYPART_ROBOTIC)
bodyparts_to_add -= "mam_ears"
+ if("mam_snouts" in mutant_bodyparts) //Take a closer look at that snout!
+ if((H.wear_mask && (H.wear_mask.flags_inv & HIDEFACE)) || (H.head && (H.head.flags_inv & HIDEFACE)) || !HD || HD.status == BODYPART_ROBOTIC)
+ bodyparts_to_add -= "mam_snouts"
+
if("taur" in mutant_bodyparts)
if(!H.dna.features["taur"] || H.dna.features["taur"] == "None" || (H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)))
bodyparts_to_add -= "taur"
@@ -696,13 +698,19 @@ GLOBAL_LIST_EMPTY(roundstart_races)
var/mutable_appearance/accessory_overlay = mutable_appearance(S.icon, layer = -layer)
+ accessory_overlay.color = null //just because. reee.
+
//A little rename so we don't have to use tail_lizard or tail_human when naming the sprites.
if(bodypart == "tail_lizard" || bodypart == "tail_human" || bodypart == "mam_tail" || bodypart == "xenotail")
bodypart = "tail"
- else if(bodypart == "waggingtail_lizard" || bodypart == "waggingtail_human" || bodypart == "mam_waggingtail")
+ else if(bodypart == "waggingtail_lizard" || bodypart == "waggingtail_human")
bodypart = "waggingtail"
+ if(bodypart == "mam_waggingtail")
+ bodypart = "tailwag"
if(bodypart == "mam_ears" || bodypart == "ears")
bodypart = "ears"
+ if(bodypart == "mam_snouts" || bodypart == "snout")
+ bodypart = "snout"
if(bodypart == "xenohead")
bodypart = "xhead"
@@ -714,6 +722,15 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(S.center)
accessory_overlay = center_image(accessory_overlay, S.dimension_x, S.dimension_y)
+ var/list/colorlist = list()
+ colorlist.Cut()
+ colorlist += ReadRGB(H.dna.features["mcolor"])
+ colorlist += ReadRGB(H.dna.features["mcolor2"])
+ colorlist += ReadRGB(H.dna.features["mcolor3"])
+ colorlist += list(0,0,0)
+ for(var/index=1, index<=colorlist.len, index++)
+ colorlist[index] = colorlist[index]/255
+
if(!(H.has_trait(TRAIT_HUSK)))
if(!forced_colour)
switch(S.color_src)
@@ -732,6 +749,10 @@ GLOBAL_LIST_EMPTY(roundstart_races)
accessory_overlay.color = "#[fixed_mut_color3]"
else
accessory_overlay.color = "#[H.dna.features["mcolor3"]]"
+
+ if(MATRIXED)
+ accessory_overlay.color = list(colorlist)
+
if(HAIR)
if(hair_color == "mutcolor")
accessory_overlay.color = "#[H.dna.features["mcolor"]]"
@@ -743,6 +764,21 @@ GLOBAL_LIST_EMPTY(roundstart_races)
accessory_overlay.color = "#[H.eye_color]"
else
accessory_overlay.color = forced_colour
+ else
+ if(bodypart == "ears")
+ accessory_overlay.icon_state = "m_ears_none_[layertext]"
+ if(bodypart == "tail")
+ accessory_overlay.icon_state = "m_tail_husk_[layertext]"
+ if(MATRIXED)
+ var/list/husklist = list()
+ husklist += ReadRGB("#a3a3a3")
+ husklist += ReadRGB("#a3a3a3")
+ husklist += ReadRGB("#a3a3a3")
+ husklist += list(0,0,0)
+ for(var/index=1, index<=husklist.len, index++)
+ husklist[index] = husklist[index]/255
+ accessory_overlay.color = husklist
+
standing += accessory_overlay
if(S.hasinner)
@@ -1221,6 +1257,9 @@ GLOBAL_LIST_EMPTY(roundstart_races)
. += speedmod
. += H.physiology.speed_mod
+ if (H.m_intent == MOVE_INTENT_WALK && H.has_trait(TRAIT_SPEEDY_STEP))
+ . -= 1
+
if(H.has_trait(TRAIT_IGNORESLOWDOWN))
ignoreslow = 1
@@ -1703,6 +1742,21 @@ GLOBAL_LIST_EMPTY(roundstart_races)
H.adjust_bodytemperature((thermal_protection+1)*natural + min(thermal_protection * (loc_temp - H.bodytemperature) / BODYTEMP_HEAT_DIVISOR, BODYTEMP_HEATING_MAX))
else //we're sweating, insulation hinders out ability to reduce heat - but will reduce the amount of heat we get from the environment
H.adjust_bodytemperature(natural*(1/(thermal_protection+1)) + min(thermal_protection * (loc_temp - H.bodytemperature) / BODYTEMP_HEAT_DIVISOR, BODYTEMP_HEATING_MAX))
+ switch((loc_temp - H.bodytemperature)*thermal_protection)
+ if(-INFINITY to -50)
+ H.throw_alert("temp", /obj/screen/alert/cold, 3)
+ if(-50 to -35)
+ H.throw_alert("temp", /obj/screen/alert/cold, 2)
+ if(-35 to -20)
+ H.throw_alert("temp", /obj/screen/alert/cold, 1)
+ if(-20 to 0) //This is the sweet spot where air is considered normal
+ H.clear_alert("temp")
+ if(0 to 15) //When the air around you matches your body's temperature, you'll start to feel warm.
+ H.throw_alert("temp", /obj/screen/alert/hot, 1)
+ if(15 to 30)
+ H.throw_alert("temp", /obj/screen/alert/hot, 2)
+ if(30 to INFINITY)
+ H.throw_alert("temp", /obj/screen/alert/hot, 3)
// +/- 50 degrees from 310K is the 'safe' zone, where no damage is dealt.
if(H.bodytemperature > BODYTEMP_HEAT_DAMAGE_LIMIT && !H.has_trait(TRAIT_RESISTHEAT))
@@ -1718,14 +1772,6 @@ GLOBAL_LIST_EMPTY(roundstart_races)
else
firemodifier = min(firemodifier, 0)
burn_damage = max(log(2-firemodifier,(H.bodytemperature-BODYTEMP_NORMAL))-5,0) // this can go below 5 at log 2.5
- if (burn_damage)
- switch(burn_damage)
- if(0 to 2)
- H.throw_alert("temp", /obj/screen/alert/hot, 1)
- if(2 to 4)
- H.throw_alert("temp", /obj/screen/alert/hot, 2)
- else
- H.throw_alert("temp", /obj/screen/alert/hot, 3)
burn_damage = burn_damage * heatmod * H.physiology.heat_mod
if (H.stat < UNCONSCIOUS && (prob(burn_damage) * 10) / 4) //40% for level 3 damage on humans
H.emote("scream")
@@ -1736,17 +1782,13 @@ GLOBAL_LIST_EMPTY(roundstart_races)
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "cold", /datum/mood_event/cold)
switch(H.bodytemperature)
if(200 to BODYTEMP_COLD_DAMAGE_LIMIT)
- H.throw_alert("temp", /obj/screen/alert/cold, 1)
H.apply_damage(COLD_DAMAGE_LEVEL_1*coldmod*H.physiology.cold_mod, BURN)
if(120 to 200)
- H.throw_alert("temp", /obj/screen/alert/cold, 2)
H.apply_damage(COLD_DAMAGE_LEVEL_2*coldmod*H.physiology.cold_mod, BURN)
else
- H.throw_alert("temp", /obj/screen/alert/cold, 3)
H.apply_damage(COLD_DAMAGE_LEVEL_3*coldmod*H.physiology.cold_mod, BURN)
else
- H.clear_alert("temp")
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "cold")
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "hot")
diff --git a/code/modules/mob/living/carbon/human/species_types/felinid.dm b/code/modules/mob/living/carbon/human/species_types/felinid.dm
index 7207a4f49d..1ee697d66c 100644
--- a/code/modules/mob/living/carbon/human/species_types/felinid.dm
+++ b/code/modules/mob/living/carbon/human/species_types/felinid.dm
@@ -4,8 +4,8 @@
id = "felinid"
limbs_id = "human"
- mutant_bodyparts = list("ears", "tail_human")
- default_features = list("mcolor" = "FFF", "tail_human" = "Cat", "ears" = "Cat", "wings" = "None")
+ mutant_bodyparts = list("mam_ears", "mam_tail")
+ default_features = list("mcolor" = "FFF", "mam_tail" = "Cat", "mam_ears" = "Cat", "wings" = "None")
mutantears = /obj/item/organ/ears/cat
mutanttail = /obj/item/organ/tail/cat
@@ -23,38 +23,39 @@
stop_wagging_tail(H)
. = ..()
+
/datum/species/human/felinid/can_wag_tail(mob/living/carbon/human/H)
- return ("tail_human" in mutant_bodyparts) || ("waggingtail_human" in mutant_bodyparts)
+ return ("mam_tail" in mutant_bodyparts) || ("mam_waggingtail" in mutant_bodyparts)
/datum/species/human/felinid/is_wagging_tail(mob/living/carbon/human/H)
- return ("waggingtail_human" in mutant_bodyparts)
+ return ("mam_waggingtail" in mutant_bodyparts)
/datum/species/human/felinid/start_wagging_tail(mob/living/carbon/human/H)
- if("tail_human" in mutant_bodyparts)
- mutant_bodyparts -= "tail_human"
- mutant_bodyparts |= "waggingtail_human"
+ if("mam_tail" in mutant_bodyparts)
+ mutant_bodyparts -= "mam_tail"
+ mutant_bodyparts |= "mam_waggingtail"
H.update_body()
/datum/species/human/felinid/stop_wagging_tail(mob/living/carbon/human/H)
- if("waggingtail_human" in mutant_bodyparts)
- mutant_bodyparts -= "waggingtail_human"
- mutant_bodyparts |= "tail_human"
+ if("mam_waggingtail" in mutant_bodyparts)
+ mutant_bodyparts -= "mam_waggingtail"
+ mutant_bodyparts |= "mam_tail"
H.update_body()
/datum/species/human/felinid/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load)
if(ishuman(C))
var/mob/living/carbon/human/H = C
if(!pref_load) //Hah! They got forcefully purrbation'd. Force default felinid parts on them if they have no mutant parts in those areas!
- if(H.dna.features["tail_human"] == "None")
- H.dna.features["tail_human"] = "Cat"
- if(H.dna.features["ears"] == "None")
- H.dna.features["ears"] = "Cat"
- if(H.dna.features["ears"] == "Cat")
+ if(H.dna.features["mam_tail"] == "None")
+ H.dna.features["mam_tail"] = "Cat"
+ if(H.dna.features["mam_ears"] == "None")
+ H.dna.features["mam_ears"] = "Cat"
+ if(H.dna.features["mam_ears"] == "Cat")
var/obj/item/organ/ears/cat/ears = new
ears.Insert(H, drop_if_replaced = FALSE)
else
mutantears = /obj/item/organ/ears
- if(H.dna.features["tail_human"] == "Cat")
+ if(H.dna.features["mam_tail"] == "Cat")
var/obj/item/organ/tail/cat/tail = new
tail.Insert(H, drop_if_replaced = FALSE)
else
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index 72052f0fa1..71717bfc16 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -359,7 +359,6 @@ There are several things that need to be remembered:
apply_overlay(BELT_LAYER)
-
/mob/living/carbon/human/update_inv_wear_suit()
remove_overlay(SUIT_LAYER)
@@ -391,8 +390,6 @@ There are several things that need to be remembered:
else if(S.taurmode == NOT_TAURIC && S.adjusted == NORMAL_STYLE)
S.alternate_worn_icon = null
-
-
overlays_standing[SUIT_LAYER] = S.build_worn_icon(state = wear_suit.icon_state, default_layer = SUIT_LAYER, default_icon_file = ((wear_suit.alternate_worn_icon) ? S.alternate_worn_icon : 'icons/mob/suit.dmi'))
var/mutable_appearance/suit_overlay = overlays_standing[SUIT_LAYER]
if(OFFSET_SUIT in dna.species.offset_features)
@@ -477,7 +474,6 @@ There are several things that need to be remembered:
out += overlays_standing[i]
return out
-
//human HUD updates for items in our inventory
//update whether our head item appears on our hud.
@@ -614,7 +610,7 @@ generate/load female uniform sprites matching all previously decided variables
else if(dna.species.fixed_mut_color)
. += "-coloured-[dna.species.fixed_mut_color]"
else if(dna.features["mcolor"])
- . += "-coloured-[dna.features["mcolor"]]"
+ . += "-coloured-[dna.features["mcolor"]]-[dna.features["mcolor2"]]-[dna.features["mcolor3"]]"
else
. += "-not_coloured"
@@ -644,6 +640,8 @@ generate/load female uniform sprites matching all previously decided variables
. += "-digitigrade[BP.use_digitigrade]"
if(BP.dmg_overlay_type)
. += "-[BP.dmg_overlay_type]"
+ if(BP.body_markings)
+ . += "-[BP.body_markings]"
if(has_trait(TRAIT_HUSK))
. += "-husk"
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index c32b6ace78..ef91c6843d 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -1067,10 +1067,12 @@
update_canmove() //if the mob was asleep inside a container and then got forceMoved out we need to make them fall.
/mob/living/proc/update_z(new_z) // 1+ to register, null to unregister
+ if(isnull(new_z) && audiovisual_redirect)
+ return
if (registered_z != new_z)
if (registered_z)
SSmobs.clients_by_zlevel[registered_z] -= src
- if (client)
+ if (client || audiovisual_redirect)
if (new_z)
SSmobs.clients_by_zlevel[new_z] += src
for (var/I in length(SSidlenpcpool.idle_mobs_by_zlevel[new_z]) to 1 step -1) //Backwards loop because we're removing (guarantees optimal rather than worst-case performance), it's fine to use .len here but doesn't compile on 511
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 3dbb454655..b4524a54e6 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -86,7 +86,7 @@
var/datum/action/innate/deploy_last_shell/redeploy_action = new
var/chnotify = 0
- var/multicam_allowed = FALSE
+
var/multicam_on = FALSE
var/obj/screen/movable/pic_in_pic/ai/master_multicam
var/list/multicam_screens = list()
diff --git a/code/modules/mob/living/silicon/ai/multicam.dm b/code/modules/mob/living/silicon/ai/multicam.dm
index 20b5f96242..fcc068b7fe 100644
--- a/code/modules/mob/living/silicon/ai/multicam.dm
+++ b/code/modules/mob/living/silicon/ai/multicam.dm
@@ -194,7 +194,7 @@ GLOBAL_DATUM(ai_camera_room_landmark, /obj/effect/landmark/ai_multicam_room)
//AI procs
/mob/living/silicon/ai/proc/drop_new_multicam(silent = FALSE)
- if(!multicam_allowed)
+ if(!CONFIG_GET(flag/allow_ai_multicam))
if(!silent)
to_chat(src, "This action is currently disabled. Contact an administrator to enable this feature.")
return
@@ -213,7 +213,7 @@ GLOBAL_DATUM(ai_camera_room_landmark, /obj/effect/landmark/ai_multicam_room)
return C
/mob/living/silicon/ai/proc/toggle_multicam()
- if(!multicam_allowed)
+ if(!CONFIG_GET(flag/allow_ai_multicam))
to_chat(src, "This action is currently disabled. Contact an administrator to enable this feature.")
return
if(multicam_on)
diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm
index be98d1bfab..43abe7c825 100644
--- a/code/modules/mob/living/status_procs.dm
+++ b/code/modules/mob/living/status_procs.dm
@@ -261,11 +261,13 @@
if(!has_trait(TRAIT_HUSK))
remove_trait(TRAIT_DISFIGURED, "husk")
update_body()
+ return TRUE
/mob/living/proc/become_husk(source)
if(!has_trait(TRAIT_HUSK))
add_trait(TRAIT_DISFIGURED, "husk")
update_body()
+ . = TRUE
add_trait(TRAIT_HUSK, source)
/mob/living/proc/cure_fakedeath(list/sources)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 79215ff5f5..30e58ebb44 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -76,6 +76,8 @@
return "a ... thing?"
/mob/proc/show_message(msg, type, alt_msg, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2)
+ if(audiovisual_redirect)
+ audiovisual_redirect.show_message(msg ? "[msg]" : null, type, alt_msg ? "[alt_msg]" : null, alt_type)
if(!client)
return
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index 298fee46cd..a0126f5fdd 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -110,3 +110,5 @@
var/datum/click_intercept
var/registered_z
+
+ var/mob/audiovisual_redirect //Mob to redirect messages, speech, and sounds to
diff --git a/code/modules/mob/status_procs.dm b/code/modules/mob/status_procs.dm
index 6841534b0e..a1a1bbe502 100644
--- a/code/modules/mob/status_procs.dm
+++ b/code/modules/mob/status_procs.dm
@@ -232,6 +232,8 @@
remove_eyeblur()
/mob/proc/add_eyeblur()
+ if(!client)
+ return
var/obj/screen/plane_master/game_world/GW = locate(/obj/screen/plane_master/game_world) in client.screen
var/obj/screen/plane_master/floor/F = locate(/obj/screen/plane_master/floor) in client.screen
GW.add_filter("blurry_eyes", 2, EYE_BLUR(CLAMP(eye_blurry*0.1,0.6,3)))
@@ -242,6 +244,8 @@
add_eyeblur()
/mob/proc/remove_eyeblur()
+ if(!client)
+ return
var/obj/screen/plane_master/game_world/GW = locate(/obj/screen/plane_master/game_world) in client.screen
var/obj/screen/plane_master/floor/F = locate(/obj/screen/plane_master/floor) in client.screen
GW.remove_filter("blurry_eyes")
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index 701e92527b..ae6e309507 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -477,8 +477,12 @@
/datum/action/toggle_scope_zoom/IsAvailable()
. = ..()
- if(!. && gun)
+ if(!gun)
+ return FALSE
+ if(!.)
gun.zoom(owner, FALSE)
+ if(!owner.get_held_index_of_item(gun))
+ return FALSE
/datum/action/toggle_scope_zoom/Remove(mob/living/L)
gun.zoom(L, FALSE)
diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm
index 9674485c45..252d0d0dc3 100644
--- a/code/modules/reagents/chemistry/holder.dm
+++ b/code/modules/reagents/chemistry/holder.dm
@@ -361,6 +361,8 @@
var/required_temp = C.required_temp
var/is_cold_recipe = C.is_cold_recipe
var/meets_temp_requirement = 0
+ var/has_special_react = C.special_react
+ var/can_special_react = 0
for(var/B in cached_required_reagents)
if(!has_reagent(B, cached_required_reagents[B]))
@@ -396,7 +398,10 @@
if(required_temp == 0 || (is_cold_recipe && chem_temp <= required_temp) || (!is_cold_recipe && chem_temp >= required_temp))
meets_temp_requirement = 1
- if(total_matching_reagents == total_required_reagents && total_matching_catalysts == total_required_catalysts && matching_container && matching_other && meets_temp_requirement)
+ if(!has_special_react || C.check_special_react(src))
+ can_special_react = 1
+
+ if(total_matching_reagents == total_required_reagents && total_matching_catalysts == total_required_catalysts && matching_container && matching_other && meets_temp_requirement && can_special_react)
possible_reactions += C
if(possible_reactions.len)
@@ -412,6 +417,7 @@
selected_reaction = competitor
var/list/cached_required_reagents = selected_reaction.required_reagents
var/list/cached_results = selected_reaction.results
+ var/special_react_result = selected_reaction.check_special_react(src)
var/list/multiplier = INFINITY
for(var/B in cached_required_reagents)
multiplier = min(multiplier, round(get_reagent_amount(B) / cached_required_reagents[B]))
@@ -443,7 +449,7 @@
ME2.name = "used slime extract"
ME2.desc = "This extract has been used up."
- selected_reaction.on_reaction(src, multiplier)
+ selected_reaction.on_reaction(src, multiplier, special_react_result)
reaction_occurred = 1
while(reaction_occurred)
diff --git a/code/modules/reagents/chemistry/recipes.dm b/code/modules/reagents/chemistry/recipes.dm
index e19d2c20d7..50006eef62 100644
--- a/code/modules/reagents/chemistry/recipes.dm
+++ b/code/modules/reagents/chemistry/recipes.dm
@@ -13,13 +13,17 @@
var/required_temp = 0
var/is_cold_recipe = 0 // Set to 1 if you want the recipe to only react when it's BELOW the required temp.
+ var/special_react = FALSE //Determines if the recipe has special conditions for it to react. Mainly used for ling blood tests
var/mix_message = "The solution begins to bubble." //The message shown to nearby people upon mixing, if applicable
var/mix_sound = 'sound/effects/bubbles.ogg' //The sound played upon mixing, if applicable
-/datum/chemical_reaction/proc/on_reaction(datum/reagents/holder, created_volume)
+/datum/chemical_reaction/proc/on_reaction(datum/reagents/holder, created_volume, specialreact)
return
//I recommend you set the result amount to the total volume of all components.
+/datum/chemical_reaction/proc/check_special_react(datum/reagents/holder)
+ return
+
/datum/chemical_reaction/proc/chemical_mob_spawn(datum/reagents/holder, amount_to_spawn, reaction_name, mob_class = HOSTILE_SPAWN, mob_faction = "chemicalsummon")
if(holder && holder.my_atom)
var/atom/A = holder.my_atom
diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm
index e1f4e3dd36..bcd08b1853 100644
--- a/code/modules/reagents/chemistry/recipes/others.dm
+++ b/code/modules/reagents/chemistry/recipes/others.dm
@@ -133,6 +133,18 @@
required_reagents = list("slime_toxin" = 1, "mutagen" = 1)
+/datum/chemical_reaction/fermis_plush
+ name = "Fermis plush"
+ id = "fermis_plush"
+ required_reagents = list("sugar" = 10, "blood" = 10, "stable_plasma" = 10)
+ mob_react = FALSE
+ required_temp = 400
+
+/datum/chemical_reaction/fermis_plush/on_reaction(datum/reagents/holder, created_volume)
+ var/location = get_turf(holder.my_atom)
+ for(var/i = 1, i <= created_volume, i+=10)
+ new /obj/item/toy/plush/catgirl/fermis(location)
+
////////////////////////////////// VIROLOGY //////////////////////////////////////////
/datum/chemical_reaction/virus_food
diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
index 471131ff00..587d6c8b38 100644
--- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
+++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
@@ -464,4 +464,30 @@
results = list("firefighting_foam" = 3)
required_reagents = list("stabilizing_agent" = 1,"fluorosurfactant" = 1,"carbon" = 1)
required_temp = 200
- is_cold_recipe = 1
\ No newline at end of file
+ is_cold_recipe = 1
+
+/datum/chemical_reaction/reagent_explosion/lingblood
+ name = "Changeling Blood Reaction"
+ id = "ling_blood_reaction"
+ results = list("ash" = 1)
+ required_reagents = list("blood" = 1)
+ strengthdiv = 4 //The explosion should be somewhat strong if a full 15u is heated within a syringe. !!fun!!
+ required_temp = 666
+ special_react = TRUE
+ mix_sound = 'sound/effects/lingbloodhiss.ogg'
+ mix_message = "The blood bubbles and sizzles violently!"
+
+/datum/chemical_reaction/reagent_explosion/lingblood/check_special_react(datum/reagents/holder)
+ if(!holder)
+ return FALSE
+ var/list/D = holder.get_data("blood")
+ if(D && D["changeling_loudness"])
+ return (D["changeling_loudness"] >= 4 ? D["changeling_loudness"] : FALSE)
+ else
+ return FALSE
+
+/datum/chemical_reaction/reagent_explosion/lingblood/on_reaction(datum/reagents/holder, created_volume, specialreact)
+ if(specialreact >= 10)
+ return ..()
+ else
+ return FALSE
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index e48e18c34c..5da091152f 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -849,10 +849,10 @@
var/obj/vehicle/V = C
var/datum/component/riding/R = V.GetComponent(/datum/component/riding)
if(R)
- if(R.vehicle_move_delay <= 0 )
+ if(R.vehicle_move_delay <= 1 )
to_chat(user, "The [C] can't be made any faster!")
return ..()
- R.vehicle_move_delay = 0
+ R.vehicle_move_delay = 1
to_chat(user, "You slather the red gunk over the [C], making it faster.")
C.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
diff --git a/code/modules/surgery/bodyparts/bodyparts.dm b/code/modules/surgery/bodyparts/bodyparts.dm
index 8d0547d2c5..5beb9e87d8 100644
--- a/code/modules/surgery/bodyparts/bodyparts.dm
+++ b/code/modules/surgery/bodyparts/bodyparts.dm
@@ -45,6 +45,10 @@
var/species_color = ""
var/mutation_color = ""
var/no_update = 0
+ var/list/body_markings = list() //for bodypart markings
+ var/list/markings_color = list()
+ var/auxmarking
+ var/list/auxmarking_color = list()
var/animal_origin = null //for nonhuman bodypart (e.g. monkey)
var/dismemberable = 1 //whether it can be dismembered with a weapon.
@@ -285,6 +289,7 @@
should_draw_gender = FALSE
should_draw_greyscale = FALSE
no_update = TRUE
+ body_markings = "husk" // reeee
if(no_update)
return
@@ -298,6 +303,16 @@
should_draw_citadel = S.should_draw_citadel // Citadel Addition
species_flags_list = H.dna.species.species_traits
+ //body marking memes
+ var/list/colorlist = list()
+ colorlist.Cut()
+ colorlist += ReadRGB(H.dna.features["mcolor"])
+ colorlist += ReadRGB(H.dna.features["mcolor2"])
+ colorlist += ReadRGB(H.dna.features["mcolor3"])
+ colorlist += list(0,0,0)
+ for(var/index=1, index<=colorlist.len, index++)
+ colorlist[index] = colorlist[index]/255
+
if(S.use_skintones)
skin_tone = H.skin_tone
should_draw_greyscale = TRUE
@@ -316,6 +331,17 @@
else
species_color = ""
+ if("mam_body_markings" in S.default_features)
+ if(H.dna.features.["mam_body_markings"] != "None")
+ body_markings = lowertext(H.dna.features.["mam_body_markings"])
+ if(MATRIXED)
+ markings_color = list(colorlist)
+ else
+ markings_color = (H.dna.features.["mcolor"])
+ else
+ body_markings = "None"
+ markings_color = ""
+
if(!dropping_limb && H.dna.check_mutation(HULK))
mutation_color = "00aa00"
else
@@ -346,6 +372,7 @@
//Gives you a proper icon appearance for the dismembered limb
/obj/item/bodypart/proc/get_limb_icon(dropped)
+ cut_overlays()
icon_state = "" //to erase the default sprite, we're building the visual aspects of the bodypart through overlays alone.
. = list()
@@ -358,9 +385,17 @@
. += image('icons/mob/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_[brutestate]0", -DAMAGE_LAYER, image_dir)
if(burnstate)
. += image('icons/mob/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_0[burnstate]", -DAMAGE_LAYER, image_dir)
+ if(body_markings)
+ if(use_digitigrade == NOT_DIGITIGRADE)
+ . += image('modular_citadel/icons/mob/mam_markings.dmi', "[body_markings]_[body_zone]", -MARKING_LAYER, image_dir)
+ else
+ . += image('modular_citadel/icons/mob/mam_markings.dmi', "[body_markings]_digitigrade_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir)
var/image/limb = image(layer = -BODYPARTS_LAYER, dir = image_dir)
var/image/aux
+ var/image/marking
+ var/image/auxmarking
+
. += limb
if(animal_origin)
@@ -403,11 +438,31 @@
limb.icon_state = "[species_id]_[body_zone]_[icon_gender]"
else
limb.icon_state = "[species_id]_[body_zone]"
+
+ // Body markings
+ if(body_markings)
+ if(species_id == "husk")
+ marking = image('modular_citadel/icons/mob/mam_markings.dmi', "husk_[body_zone]", -MARKING_LAYER, image_dir)
+ else if(species_id == "husk" && use_digitigrade)
+ marking = image('modular_citadel/icons/mob/mam_markings.dmi', "husk_digitigrade_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir)
+
+ else if(!use_digitigrade)
+ marking = image('modular_citadel/icons/mob/mam_markings.dmi', "[body_markings]_[body_zone]", -MARKING_LAYER, image_dir)
+ else
+ marking = image('modular_citadel/icons/mob/mam_markings.dmi', "[body_markings]_digitigrade_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir)
+ . += marking
+
// Citadel End
if(aux_zone)
aux = image(limb.icon, "[species_id]_[aux_zone]", -aux_layer, image_dir)
. += aux
+ if(body_markings)
+ if(species_id == "husk")
+ auxmarking = image('modular_citadel/icons/mob/mam_markings.dmi', "husk_[aux_zone]", -aux_layer, image_dir)
+ else
+ auxmarking = image('modular_citadel/icons/mob/mam_markings.dmi', "[body_markings]_[aux_zone]", -aux_layer, image_dir)
+ . += auxmarking
else
limb.icon = icon
@@ -416,17 +471,45 @@
else
limb.icon_state = "[body_zone]"
if(aux_zone)
- aux = image(limb.icon, "[aux_zone]", -aux_layer, image_dir)
+ aux = image(limb.icon, "[species_id]_[aux_zone]", -aux_layer, image_dir)
. += aux
+ if(body_markings)
+ if(species_id == "husk")
+ auxmarking = image('modular_citadel/icons/mob/mam_markings.dmi', "husk_[aux_zone]", -aux_layer, image_dir)
+ else
+ auxmarking = image('modular_citadel/icons/mob/mam_markings.dmi', "[body_markings]_[aux_zone]", -aux_layer, image_dir)
+ . += auxmarking
+
+ if(body_markings)
+ if(species_id == "husk")
+ marking = image('modular_citadel/icons/mob/mam_markings.dmi', "husk_[body_zone]", -MARKING_LAYER, image_dir)
+ else if(species_id == "husk" && use_digitigrade)
+ marking = image('modular_citadel/icons/mob/mam_markings.dmi', "husk_digitigrade_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir)
+
+ else if(!use_digitigrade)
+ marking = image('modular_citadel/icons/mob/mam_markings.dmi', "[body_markings]_[body_zone]", -MARKING_LAYER, image_dir)
+ else
+ marking = image('modular_citadel/icons/mob/mam_markings.dmi', "[body_markings]_digitigrade_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir)
+ . += marking
return
if(should_draw_greyscale)
+ marking.color = null
var/draw_color = mutation_color || species_color || (skin_tone && skintone2hex(skin_tone))
if(draw_color)
limb.color = "#[draw_color]"
if(aux_zone)
aux.color = "#[draw_color]"
+ if(body_markings)
+ auxmarking.color = list(markings_color)
+
+ if(body_markings)
+ if(species_id == "husk")
+ marking.color = "#141414"
+ else
+ marking.color = list(markings_color)
+
/obj/item/bodypart/deconstruct(disassembled = TRUE)
drop_organs()
diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm
index 9d9e26c6fa..9cc56a6ca8 100644
--- a/code/modules/surgery/bodyparts/helpers.dm
+++ b/code/modules/surgery/bodyparts/helpers.dm
@@ -288,6 +288,7 @@
O.drop_limb(1)
qdel(O)
N.attach_limb(src)
+
if(body_plan_changed && ishuman(src))
var/mob/living/carbon/human/H = src
if(H.w_uniform)
@@ -311,4 +312,4 @@
S.adjusted = NORMAL_STYLE
else
S.adjusted = ALT_STYLE
- H.update_inv_wear_suit()
\ No newline at end of file
+ H.update_inv_wear_suit()
diff --git a/html/changelogs/AutoChangeLog-pr-7987.yml b/html/changelogs/AutoChangeLog-pr-7987.yml
new file mode 100644
index 0000000000..e525b1668e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7987.yml
@@ -0,0 +1,10 @@
+author: "Poojawa"
+delete-after: True
+changes:
+ - rscadd: "All markings, tails, ears, and snouts for Citadel races are color matrixed!"
+ - imageadd: "all markings are on a per-limb basis, including Digitigrade legs!"
+ - imageadd: "a bunch of tails were blessed with tail wagging sprites, Fish, Sharks, Fennecs, Wahs, raccoons, and others."
+ - imageadd: "Tiger markings + tail added, skunk tails improved via sprites from Virgo"
+ - tweak: "tweaked some sprites to look better, but they absolutely could use a few extra passes for quality"
+ - rscadd: "HumanScissors in the Tools folder will permit anyone to contribute matrix'd markings to the sprite sheet, however Mam_markings is very, very full. Be careful."
+ - tweak: "Character preview was both optimized for taurs and bad-touched for better updating. I don't know if it'll be bad, but hey its better."
diff --git a/html/changelogs/AutoChangeLog-pr-7999.yml b/html/changelogs/AutoChangeLog-pr-7999.yml
new file mode 100644
index 0000000000..516f304f98
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7999.yml
@@ -0,0 +1,5 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - tweak: "The kindle status effect stun duration now properly proportional to the owner's remaining health."
+ - tweak: "Clockwork cult's kindle now affects silicons."
diff --git a/html/changelogs/AutoChangeLog-pr-8008.yml b/html/changelogs/AutoChangeLog-pr-8008.yml
new file mode 100644
index 0000000000..5845bd1b87
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8008.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - balance: "Slime speed potions can now only increase the speed of vehicles to be on par with sprinting speed. They can no longer make a scooter roll around ten times faster than a speeding blue hedgehog."
diff --git a/html/changelogs/AutoChangeLog-pr-8010.yml b/html/changelogs/AutoChangeLog-pr-8010.yml
new file mode 100644
index 0000000000..9694674b7c
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8010.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - rscdel: "Changelings will no longer recieve team objectives"
diff --git a/html/changelogs/AutoChangeLog-pr-8011.yml b/html/changelogs/AutoChangeLog-pr-8011.yml
new file mode 100644
index 0000000000..9d0db00db4
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8011.yml
@@ -0,0 +1,5 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - balance: "Changelings no longer start off with hivemind communication as an innate ability. Hivemind communication now requires 1 dna point, on par with syndicate encryption keys, which are 2 TC."
+ - code_imp: "Hivemind link now relies on hivemind communication just like the hivemind download/upload abilities."
diff --git a/html/changelogs/AutoChangeLog-pr-8012.yml b/html/changelogs/AutoChangeLog-pr-8012.yml
new file mode 100644
index 0000000000..212f252a7d
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8012.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - bugfix: "It's now only possible to zoom a gun if it's in one of your hands"
diff --git a/html/changelogs/AutoChangeLog-pr-8021.yml b/html/changelogs/AutoChangeLog-pr-8021.yml
new file mode 100644
index 0000000000..fca715cd3d
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8021.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - bugfix: "Mobs without clients no longer cause runtimes when their eyeblur updates"
diff --git a/html/changelogs/AutoChangeLog-pr-8023.yml b/html/changelogs/AutoChangeLog-pr-8023.yml
new file mode 100644
index 0000000000..1b30435bda
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8023.yml
@@ -0,0 +1,5 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - rscadd: "Blood tests have been added. If a changeling has a sufficient number of loud abilities, you will be able to test their blood by heating up a sample of it. However, if the changeling has a large amount of loud abilities, attempts to test their blood will have explosive results."
+ - rscadd: "Changelings now make a very obvious noise when readapting. This is to prevent the cheese strat of simply readapting when you get caught to avoid detection."
diff --git a/html/changelogs/AutoChangeLog-pr-8025.yml b/html/changelogs/AutoChangeLog-pr-8025.yml
new file mode 100644
index 0000000000..ee60aab630
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8025.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - tweak: "The temperature notification will now take into consideration both the ambient temperature and your body temperature, increasing the responsiveness of the temperature notification and making it much more realistic."
diff --git a/html/changelogs/AutoChangeLog-pr-8030.yml b/html/changelogs/AutoChangeLog-pr-8030.yml
new file mode 100644
index 0000000000..c82325b394
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8030.yml
@@ -0,0 +1,5 @@
+author: "Multicam Config"
+delete-after: True
+changes:
+ - config: "removed whether or not the stuff for multicam was checking the useless var and instead now checks the CONFIG_GET flag."
+ - admin: "Admins now have a verb in the Server tab to turn AI multicam on and off."
diff --git a/html/changelogs/AutoChangeLog-pr-8031.yml b/html/changelogs/AutoChangeLog-pr-8031.yml
new file mode 100644
index 0000000000..16ce735811
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8031.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - tweak: "Shuttle transit borders are now 10 tiles wide instead of 8 tiles, hopefully repairing the immersions that get shattered by the ability to see normal space where the transit areas end."
diff --git a/html/changelogs/AutoChangeLog-pr-8033.yml b/html/changelogs/AutoChangeLog-pr-8033.yml
new file mode 100644
index 0000000000..e4a77766f1
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8033.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - bugfix: "The sprint hotkey will no longer cause you to get permanently stuck sprinting if the server lags. Just tap shift again if you get stuck"
diff --git a/html/changelogs/AutoChangeLog-pr-8034.yml b/html/changelogs/AutoChangeLog-pr-8034.yml
new file mode 100644
index 0000000000..c9fabf1874
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8034.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - rscadd: "You can now hear sounds in the real world while inside of a VR sleeper."
diff --git a/icons/mob/human_parts_greyscale.dmi b/icons/mob/human_parts_greyscale.dmi
index f162d36633..47ef8e816f 100644
Binary files a/icons/mob/human_parts_greyscale.dmi and b/icons/mob/human_parts_greyscale.dmi differ
diff --git a/interface/skin.dmf b/interface/skin.dmf
index 99850c34ba..65f4a22664 100644
--- a/interface/skin.dmf
+++ b/interface/skin.dmf
@@ -268,3 +268,30 @@ window "statwindow"
is-default = true
saved-params = ""
+ window "preferences_window"
+ elem "preferences_window"
+ type = MAIN
+ pos = 372,0
+ size = 1120x1000
+ anchor1 = none
+ anchor2 = none
+ background-color = none
+ is-visible = false
+ saved-params = "pos;size;is-minimized;is-maximized"
+ statusbar = false
+ elem "preferences_browser"
+ type = BROWSER
+ pos = -8,-8
+ size = 896x1008
+ anchor1 = 0,0
+ anchor2 = 90,100
+ background-color = none
+ saved-params = ""
+ elem "character_preview_map"
+ type = MAP
+ pos = 887,0
+ size = 313x1000
+ anchor1 = 90,0
+ anchor2 = 100,100
+ right-click = true
+ saved-params = "zoom;letterbox;zoom-mode"
diff --git a/modular_citadel/code/init.dm b/modular_citadel/code/init.dm
index 6df5be02eb..2c2b5b811f 100644
--- a/modular_citadel/code/init.dm
+++ b/modular_citadel/code/init.dm
@@ -9,6 +9,7 @@
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails, GLOB.mam_tails_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_ears, GLOB.mam_ears_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails_animated, GLOB.mam_tails_animated_list)
+ init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_snouts, GLOB.mam_snouts_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/taur, GLOB.taur_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_head, GLOB.xeno_head_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_tail, GLOB.xeno_tail_list)
diff --git a/modular_citadel/code/modules/client/preferences.dm b/modular_citadel/code/modules/client/preferences.dm
index 927d324e23..358208c1d7 100644
--- a/modular_citadel/code/modules/client/preferences.dm
+++ b/modular_citadel/code/modules/client/preferences.dm
@@ -40,6 +40,7 @@
"mcolor3" = "FFF",
"mam_body_markings" = "None",
"mam_ears" = "None",
+ "mam_snouts" = "None",
"mam_tail" = "None",
"mam_tail_animated" = "None",
"xenodorsal" = "Standard",
diff --git a/modular_citadel/code/modules/client/preferences_savefile.dm b/modular_citadel/code/modules/client/preferences_savefile.dm
index 8f65e47d2b..209d46db61 100644
--- a/modular_citadel/code/modules/client/preferences_savefile.dm
+++ b/modular_citadel/code/modules/client/preferences_savefile.dm
@@ -40,6 +40,7 @@
WRITE_FILE(S["feature_mam_ears"], features["mam_ears"])
WRITE_FILE(S["feature_mam_tail_animated"], features["mam_tail_animated"])
WRITE_FILE(S["feature_taur"], features["taur"])
+ WRITE_FILE(S["feature_mam_snouts"], features["mam_snouts"])
//Xeno features
WRITE_FILE(S["feature_xeno_tail"], features["xenotail"])
WRITE_FILE(S["feature_xeno_dors"], features["xenodorsal"])
diff --git a/modular_citadel/code/modules/keybindings/bindings_human.dm b/modular_citadel/code/modules/keybindings/bindings_human.dm
index 963e71d709..ffe88bd4a9 100644
--- a/modular_citadel/code/modules/keybindings/bindings_human.dm
+++ b/modular_citadel/code/modules/keybindings/bindings_human.dm
@@ -1,13 +1,13 @@
/mob/living/carbon/human/key_down(_key, client/user)
switch(_key)
if("Shift")
- togglesprint()
+ sprint_hotkey(TRUE)
return
return ..()
/mob/living/carbon/human/key_up(_key, client/user)
switch(_key)
if("Shift")
- togglesprint()
+ sprint_hotkey(FALSE)
return
return ..()
diff --git a/modular_citadel/code/modules/keybindings/bindings_robot.dm b/modular_citadel/code/modules/keybindings/bindings_robot.dm
index 59151f2b40..d3b6248f7d 100644
--- a/modular_citadel/code/modules/keybindings/bindings_robot.dm
+++ b/modular_citadel/code/modules/keybindings/bindings_robot.dm
@@ -1,13 +1,13 @@
/mob/living/silicon/robot/key_down(_key, client/user)
switch(_key)
if("Shift")
- togglesprint()
+ sprint_hotkey(TRUE)
return
return ..()
/mob/living/silicon/robot/key_up(_key, client/user)
switch(_key)
if("Shift")
- togglesprint()
+ sprint_hotkey(FALSE)
return
return ..()
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 38343838e9..b22989024e 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
@@ -7,12 +7,6 @@
var/extra2_color_src = MUTCOLORS3
var/list/ckeys_allowed
-/* tbi eventually idk
-/datum/sprite_accessory/legs/digitigrade_mam
- name = "Anthro Digitigrade Legs"
- icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-*/
-
/datum/sprite_accessory/moth_wings/none
name = "None"
icon_state = "none"
@@ -29,14 +23,146 @@
name = "None"
icon_state = "None"
+
+/datum/sprite_accessory/tails/lizard/axolotl
+ name = "Axolotl"
+ icon_state = "axolotl"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/lizard/axolotl
+ name = "Axolotl"
+ icon_state = "axolotl"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/************* Lizard compatable snoots ************/
+/datum/sprite_accessory/snouts/bird
+ name = "Beak"
+ icon_state = "bird"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/bigbeak
+ name = "Big Beak"
+ icon_state = "bigbeak"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/bug
+ name = "Bug"
+ icon_state = "bug"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ extra2 = TRUE
+ extra2_color_src = MUTCOLORS3
+
+/datum/sprite_accessory/snouts/elephant
+ name = "Elephant"
+ icon_state = "elephant"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+ extra = TRUE
+ extra_color_src = MUTCOLORS3
+
+/datum/sprite_accessory/snouts/lcanid
+ name = "Mammal, Long"
+ icon_state = "lcanid"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/lcanidalt
+ name = "Mammal, Long ALT"
+ icon_state = "lcanidalt"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/scanid
+ name = "Mammal, Short"
+ icon_state = "scanid"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/scanidalt
+ name = "Mammal, Short ALT"
+ icon_state = "scanidalt"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/wolf
+ name = "Mammal, Thick"
+ icon_state = "wolf"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/wolfalt
+ name = "Mammal, Thick ALT"
+ icon_state = "wolfalt"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/redpanda
+ name = "WahCoon"
+ icon_state = "wah"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/rhino
+ name = "Horn"
+ icon_state = "rhino"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+ extra = TRUE
+ extra = MUTCOLORS3
+
+/datum/sprite_accessory/snouts/rodent
+ name = "Rodent"
+ icon_state = "rodent"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/husky
+ name = "Husky"
+ icon_state = "husky"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/otie
+ name = "Otie"
+ icon_state = "otie"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/pede
+ name = "Scolipede"
+ icon_state = "pede"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/sergal
+ name = "Sergal"
+ icon_state = "sergal"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/snouts/shark
+ name = "Shark"
+ icon_state = "shark"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+
+/datum/sprite_accessory/snouts/toucan
+ name = "Toucan"
+ icon_state = "toucan"
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
+ color_src = MATRIXED
+
/******************************************
************ Human Ears/Tails *************
*******************************************/
/datum/sprite_accessory/tails/human/ailurus
name = "Red Panda"
- icon_state = "ailurus"
- color_src = 0
+ icon_state = "wah"
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/ears/human/axolotl
@@ -49,7 +175,7 @@
icon_state = "axolotl"
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
-/datum/sprite_accessory/tails_animated/axolotl
+/datum/sprite_accessory/tails_animated/human/axolotl
name = "Axolotl"
icon_state = "axolotl"
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
@@ -58,6 +184,7 @@
name = "Bear"
icon_state = "bear"
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
/datum/sprite_accessory/tails/human/bear
name = "Bear"
@@ -83,7 +210,7 @@
name = "Cow"
icon_state = "cow"
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- gender_specific = 1
+ color_src = MATRIXED
/datum/sprite_accessory/tails/human/cow
name = "Cow"
@@ -105,6 +232,7 @@
name = "Eevee"
icon_state = "eevee"
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
/datum/sprite_accessory/tails/human/eevee
name = "Eevee"
@@ -120,12 +248,13 @@
name = "Elephant"
icon_state = "elephant"
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
/datum/sprite_accessory/ears/fennec
name = "Fennec"
icon_state = "fennec"
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- hasinner = 1
+ color_src = MATRIXED
/datum/sprite_accessory/tails/human/fennec
name = "Fennec"
@@ -141,39 +270,33 @@
name = "Fish"
icon_state = "fish"
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- color_src = MUTCOLORS3
+ color_src = MATRIXED
/datum/sprite_accessory/tails/human/fish
name = "Fish"
icon_state = "fish"
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- extra = TRUE
- extra_color_src = MUTCOLORS3
/datum/sprite_accessory/tails_animated/human/fish
name = "Fish"
icon_state = "fish"
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- extra = TRUE
- extra_color_src = MUTCOLORS3
/datum/sprite_accessory/ears/fox
name = "Fox"
icon_state = "fox"
- hasinner = 1
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
/datum/sprite_accessory/tails/human/fox
name = "Fox"
icon_state = "fox"
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- extra = TRUE
/datum/sprite_accessory/tails_animated/human/fox
name = "Fox"
icon_state = "fox"
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- extra = TRUE
/datum/sprite_accessory/tails/human/horse
name = "Horse"
@@ -191,15 +314,13 @@
name = "Husky"
icon_state = "husky"
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- extra = TRUE
/datum/sprite_accessory/tails_animated/human/husky
name = "Husky"
icon_state = "husky"
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- extra = TRUE
- /datum/sprite_accessory/tails/human/insect
+/datum/sprite_accessory/tails/human/insect
name = "Insect"
icon_state = "insect"
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
@@ -217,188 +338,199 @@
/datum/sprite_accessory/tails/human/kitsune
name = "Kitsune"
icon_state = "kitsune"
- extra = TRUE
- extra_color_src = MUTCOLORS2
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails_animated/human/kitsune
name = "Kitsune"
icon_state = "kitsune"
- extra = TRUE
- extra_color_src = MUTCOLORS2
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/ears/lab
name = "Dog, Floppy"
icon_state = "lab"
- hasinner = 0
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
/datum/sprite_accessory/ears/murid
name = "Murid"
icon_state = "murid"
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
/datum/sprite_accessory/tails/human/murid
name = "Murid"
icon_state = "murid"
- color_src = 0
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails_animated/human/murid
name = "Murid"
icon_state = "murid"
- color_src = 0
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/ears/human/otie
name = "Otusian"
icon_state = "otie"
- hasinner= 1
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
/datum/sprite_accessory/tails/human/otie
name = "Otusian"
icon_state = "otie"
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails_animated/human/otie
name = "Otusian"
icon_state = "otie"
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails/orca
name = "Orca"
icon_state = "orca"
- extra = TRUE
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails_animated/orca
name = "Orca"
icon_state = "orca"
- extra = TRUE
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/ears/human/pede
name = "Scolipede"
icon_state = "pede"
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- color_src = MUTCOLORS2
- extra_color_src = MUTCOLORS3
+ color_src = MATRIXED
/datum/sprite_accessory/tails/human/pede
name = "Scolipede"
icon_state = "pede"
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails_animated/human/pede
name = "Scolipede"
icon_state = "pede"
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/ears/human/rabbit
name = "Rabbit"
icon_state = "rabbit"
- hasinner= 1
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
/datum/sprite_accessory/tails/human/rabbit
name = "Rabbit"
icon_state = "rabbit"
- color_src = 0
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails_animated/human/rabbit
name = "Rabbit"
icon_state = "rabbit"
- color_src = 0
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/ears/human/sergal
name = "Sergal"
icon_state = "sergal"
- hasinner= 1
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
/datum/sprite_accessory/tails/human/sergal
name = "Sergal"
icon_state = "sergal"
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails_animated/human/sergal
name = "Sergal"
icon_state = "sergal"
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/ears/human/skunk
name = "skunk"
icon_state = "skunk"
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
/datum/sprite_accessory/tails/human/skunk
name = "skunk"
icon_state = "skunk"
- color_src = 0
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails_animated/human/skunk
name = "skunk"
icon_state = "skunk"
- color_src = 0
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails/human/shark
name = "Shark"
icon_state = "shark"
- color_src = MUTCOLORS
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails/human/shark/datashark
name = "datashark"
icon_state = "datashark"
- color_src = 0
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/ears/squirrel
name = "Squirrel"
icon_state = "squirrel"
- hasinner= 1
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
/datum/sprite_accessory/tails/human/squirrel
name = "Squirrel"
icon_state = "squirrel"
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails_animated/human/squirrel
name = "Squirrel"
icon_state = "squirrel"
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails/human/yentacle
name = "Tentacle"
icon_state = "tentacle"
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails_animated/human/tentacle
name = "Tentacle"
icon_state = "tentacle"
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/ears/wolf
name = "Wolf"
icon_state = "wolf"
- hasinner = 1
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
/datum/sprite_accessory/tails/human/wolf
name = "Wolf"
icon_state = "wolf"
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails_animated/human/wolf
name = "Wolf"
icon_state = "wolf"
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/******************************************
@@ -406,126 +538,253 @@
*******************************************/
/datum/sprite_accessory/mam_ears
- extra = TRUE
- extra2 = TRUE
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- extra_icon = 'modular_citadel/icons/mob/mam_ears.dmi'
- extra2_icon = 'modular_citadel/icons/mob/mam_ears.dmi'
+ color_src = MATRIXED
/datum/sprite_accessory/mam_ears/none
name = "None"
icon_state = "none"
/datum/sprite_accessory/mam_tails
- extra = TRUE
- extra2 = TRUE
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- extra_icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- extra2_icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/mam_tails/none
name = "None"
icon_state = "none"
/datum/sprite_accessory/mam_tails_animated
- extra = TRUE
- extra2 = TRUE
+ color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- extra_icon = 'modular_citadel/icons/mob/mam_tails.dmi'
- extra2_icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/mam_tails_animated/none
name = "None"
icon_state = "none"
+ color_src = MATRIXED
-/datum/sprite_accessory/snouts
+/datum/sprite_accessory/mam_snouts
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
-/datum/sprite_accessory/snouts/none
+/datum/sprite_accessory/mam_snouts/none
name = "None"
icon_state = "none"
- extra_icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- extra2_icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
/******************************************
**************** Snouts *******************
*******************************************/
-/datum/sprite_accessory/snouts/bird
+/datum/sprite_accessory/mam_snouts/bird
name = "Beak"
icon_state = "bird"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- color_src = MUTCOLORS3
-/datum/sprite_accessory/snouts/bigbeak
+/datum/sprite_accessory/mam_snouts/bigbeak
name = "Big Beak"
icon_state = "bigbeak"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- color_src = MUTCOLORS3
-/datum/sprite_accessory/snouts/elephant
+/datum/sprite_accessory/mam_snouts/bug
+ name = "Bug"
+ icon_state = "bug"
+ color_src = MUTCOLORS
+ extra2 = TRUE
+ extra2_color_src = MUTCOLORS3
+
+/datum/sprite_accessory/mam_snouts/elephant
name = "Elephant"
icon_state = "elephant"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
extra = TRUE
extra_color_src = MUTCOLORS3
-/datum/sprite_accessory/snouts/lcanid
- name = "Fox, Long"
+/datum/sprite_accessory/mam_snouts/lcanid
+ name = "Mammal, Long"
icon_state = "lcanid"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- extra = TRUE
-/datum/sprite_accessory/snouts/scanid
- name = "Fox, Short"
+/datum/sprite_accessory/mam_snouts/lcanidalt
+ name = "Mammal, Long ALT"
+ icon_state = "lcanidalt"
+
+/datum/sprite_accessory/mam_snouts/scanid
+ name = "Mammal, Short"
icon_state = "scanid"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- extra = TRUE
-/datum/sprite_accessory/snouts/wolf
- name = "Wolf"
+/datum/sprite_accessory/mam_snouts/scanidalt
+ name = "Mammal, Short ALT"
+ icon_state = "scanidalt"
+
+/datum/sprite_accessory/mam_snouts/wolf
+ name = "Mammal, Thick"
icon_state = "wolf"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- extra = TRUE
-/datum/sprite_accessory/snouts/rhino
+/datum/sprite_accessory/mam_snouts/wolfalt
+ name = "Mammal, Thick ALT"
+ icon_state = "wolfalt"
+
+/datum/sprite_accessory/mam_snouts/redpanda
+ name = "WahCoon"
+ icon_state = "wah"
+
+/datum/sprite_accessory/mam_snouts/rhino
name = "Horn"
icon_state = "rhino"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
extra = TRUE
extra = MUTCOLORS3
-/datum/sprite_accessory/snouts/husky
+/datum/sprite_accessory/mam_snouts/rodent
+ name = "Rodent"
+ icon_state = "rodent"
+
+/datum/sprite_accessory/mam_snouts/husky
name = "Husky"
icon_state = "husky"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- extra = TRUE
-/datum/sprite_accessory/snouts/otie
+/datum/sprite_accessory/mam_snouts/otie
name = "Otie"
icon_state = "otie"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- extra = TRUE
-/datum/sprite_accessory/snouts/pede
+/datum/sprite_accessory/mam_snouts/pede
name = "Scolipede"
icon_state = "pede"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- extra = TRUE
- color_src = MUTCOLORS
- extra_color_src = MUTCOLORS2
-/datum/sprite_accessory/snouts/sergal
+/datum/sprite_accessory/mam_snouts/sergal
name = "Sergal"
icon_state = "sergal"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- color_src = MUTCOLORS2
-/datum/sprite_accessory/snouts/toucan
+/datum/sprite_accessory/mam_snouts/shark
+ name = "Shark"
+ icon_state = "shark"
+
+/datum/sprite_accessory/mam_snouts/toucan
name = "Toucan"
icon_state = "toucan"
- icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
- color_src = MUTCOLORS3
+
+/datum/sprite_accessory/mam_snouts/sharp
+ name = "Sharp"
+ icon_state = "sharp"
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/mam_snouts/round
+ name = "Round"
+ icon_state = "round"
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/mam_snouts/sharplight
+ name = "Sharp + Light"
+ icon_state = "sharplight"
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/mam_snouts/roundlight
+ name = "Round + Light"
+ icon_state = "roundlight"
+ color_src = MUTCOLORS
+
+
+/******************************************
+**************** Snouts *******************
+*************but higher up*****************/
+
+/datum/sprite_accessory/mam_snouts/fbird
+ name = "Beak (Top)"
+ icon_state = "fbird"
+
+/datum/sprite_accessory/mam_snouts/fbigbeak
+ name = "Big Beak (Top)"
+ icon_state = "fbigbeak"
+
+/datum/sprite_accessory/mam_snouts/fbug
+ name = "Bug (Top)"
+ icon_state = "fbug"
+ color_src = MUTCOLORS
+ extra2 = TRUE
+ extra2_color_src = MUTCOLORS3
+
+/datum/sprite_accessory/mam_snouts/felephant
+ name = "Elephant (Top)"
+ icon_state = "felephant"
+ extra = TRUE
+ extra_color_src = MUTCOLORS3
+
+/datum/sprite_accessory/mam_snouts/flcanid
+ name = "Mammal, Long (Top)"
+ icon_state = "flcanid"
+
+/datum/sprite_accessory/mam_snouts/flcanidalt
+ name = "Mammal, Long ALT (Top)"
+ icon_state = "flcanidalt"
+
+/datum/sprite_accessory/mam_snouts/fscanid
+ name = "Mammal, Short (Top)"
+ icon_state = "fscanid"
+
+/datum/sprite_accessory/mam_snouts/fscanidalt
+ name = "Mammal, Short ALT (Top)"
+ icon_state = "fscanidalt"
+
+/datum/sprite_accessory/mam_snouts/fwolf
+ name = "Mammal, Thick (Top)"
+ icon_state = "fwolf"
+
+/datum/sprite_accessory/mam_snouts/fwolfalt
+ name = "Mammal, Thick ALT (Top)"
+ icon_state = "fwolfalt"
+
+/datum/sprite_accessory/mam_snouts/fredpanda
+ name = "WahCoon (Top)"
+ icon_state = "fwah"
+
+/datum/sprite_accessory/mam_snouts/frhino
+ name = "Horn (Top)"
+ icon_state = "frhino"
+ extra = TRUE
+ extra = MUTCOLORS3
+
+/datum/sprite_accessory/mam_snouts/frodent
+ name = "Rodent (Top)"
+ icon_state = "frodent"
+
+/datum/sprite_accessory/mam_snouts/fhusky
+ name = "Husky (Top)"
+ icon_state = "fhusky"
+
+/datum/sprite_accessory/mam_snouts/fotie
+ name = "Otie (Top)"
+ icon_state = "fotie"
+
+/datum/sprite_accessory/mam_snouts/fpede
+ name = "Scolipede (Top)"
+ icon_state = "fpede"
+
+/datum/sprite_accessory/mam_snouts/fsergal
+ name = "Sergal (Top)"
+ icon_state = "fsergal"
+
+/datum/sprite_accessory/mam_snouts/fshark
+ name = "Shark (Top)"
+ icon_state = "fshark"
+
+/datum/sprite_accessory/mam_snouts/ftoucan
+ name = "Toucan (Top)"
+ icon_state = "ftoucan"
+
+/datum/sprite_accessory/mam_snouts/fsharp
+ name = "Sharp (Top)"
+ icon_state = "fsharp"
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/mam_snouts/fround
+ name = "Round (Top)"
+ icon_state = "fround"
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/mam_snouts/fsharplight
+ name = "Sharp + Light (Top)"
+ icon_state = "fsharplight"
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/mam_snouts/froundlight
+ name = "Round + Light (Top)"
+ icon_state = "froundlight"
+ color_src = MUTCOLORS
/******************************************
***************** Ears ********************
@@ -539,18 +798,47 @@
name = "Bear"
icon_state = "bear"
+/datum/sprite_accessory/mam_ears/bigwolf
+ name = "Big Wolf"
+ icon_state = "bigwolf"
+
+/datum/sprite_accessory/mam_ears/bigwolfinner
+ name = "Big Wolf (ALT)"
+ icon_state = "bigwolfinner"
+ hasinner = 1
+
+/datum/sprite_accessory/mam_ears/bigwolfdark
+ name = "Dark Big Wolf"
+ icon_state = "bigwolfdark"
+
+/datum/sprite_accessory/mam_ears/bigwolfinnerdark
+ name = "Dark Big Wolf (ALT)"
+ icon_state = "bigwolfinnerdark"
+ hasinner = 1
+
+/datum/sprite_accessory/mam_ears/cat
+ name = "Cat"
+ icon_state = "cat"
+ hasinner = 1
+ color_src = HAIR
+
/datum/sprite_accessory/mam_ears/catbig
name = "Cat, Big"
icon_state = "catbig"
- hasinner = 1
/datum/sprite_accessory/mam_ears/cow
name = "Cow"
icon_state = "cow"
+/datum/sprite_accessory/mam_ears/curled
+ name = "Curled Horn"
+ icon_state = "horn1"
+ color_src = MUTCOLORS3
+
/datum/sprite_accessory/mam_ears/deer
name = "Deer"
icon_state = "deer"
+ color_src = MUTCOLORS3
/datum/sprite_accessory/mam_ears/eevee
name = "Eevee"
@@ -563,17 +851,14 @@
/datum/sprite_accessory/mam_ears/fennec
name = "Fennec"
icon_state = "fennec"
- hasinner = 1
/datum/sprite_accessory/mam_ears/fish
name = "Fish"
icon_state = "fish"
- color_src = MUTCOLORS3
/datum/sprite_accessory/mam_ears/fox
name = "Fox"
icon_state = "fox"
- hasinner = 1
/datum/sprite_accessory/mam_ears/husky
name = "Husky"
@@ -583,6 +868,11 @@
name = "kangaroo"
icon_state = "kangaroo"
+/datum/sprite_accessory/mam_ears/jellyfish
+ name = "Jellyfish"
+ icon_state = "jellyfish"
+ color_src = HAIR
+
/datum/sprite_accessory/mam_ears/lab
name = "Dog, Long"
icon_state = "lab"
@@ -591,37 +881,25 @@
name = "Murid"
icon_state = "murid"
-/datum/sprite_accessory/mam_ears/neko
- name = "Neko"
- icon_state = "cat"
- hasinner = 1
- color_src = HAIR
-
/datum/sprite_accessory/mam_ears/otie
name = "Otusian"
icon_state = "otie"
- hasinner= 1
/datum/sprite_accessory/mam_ears/squirrel
name = "Squirrel"
icon_state = "squirrel"
- hasinner= 1
/datum/sprite_accessory/mam_ears/pede
name = "Scolipede"
icon_state = "pede"
- color_src = MUTCOLORS2
- extra_color_src = MUTCOLORS3
/datum/sprite_accessory/mam_ears/rabbit
name = "Rabbit"
icon_state = "rabbit"
- hasinner= 1
/datum/sprite_accessory/mam_ears/sergal
name = "Sergal"
icon_state = "sergal"
- hasinner= 1
/datum/sprite_accessory/mam_ears/skunk
name = "skunk"
@@ -630,20 +908,19 @@
/datum/sprite_accessory/mam_ears/wolf
name = "Wolf"
icon_state = "wolf"
- hasinner = 1
/******************************************
*********** Tails and Things **************
*******************************************/
/datum/sprite_accessory/mam_tails/ailurus
- name = "Ailurus"
- icon_state = "ailurus"
+ name = "Red Panda"
+ icon_state = "wah"
extra = TRUE
/datum/sprite_accessory/mam_tails_animated/ailurus
- name = "Ailurus"
- icon_state = "ailurus"
+ name = "Red Panda"
+ icon_state = "wah"
extra = TRUE
/datum/sprite_accessory/mam_tails/axolotl
@@ -662,6 +939,16 @@
name = "Bear"
icon_state = "bear"
+/datum/sprite_accessory/mam_tails/cat
+ name = "Cat"
+ icon_state = "cat"
+ color_src = HAIR
+
+/datum/sprite_accessory/mam_tails_animated/cat
+ name = "Cat"
+ icon_state = "cat"
+ color_src = HAIR
+
/datum/sprite_accessory/mam_tails/catbig
name = "Cat, Big"
icon_state = "catbig"
@@ -670,6 +957,14 @@
name = "Cat, Big"
icon_state = "catbig"
+/datum/sprite_accessory/mam_tails/corvid
+ name = "Corvid"
+ icon_state = "crow"
+
+/datum/sprite_accessory/mam_tails_animated/corvid
+ name = "Corvid"
+ icon_state = "crow"
+
/datum/sprite_accessory/mam_tail/cow
name = "Cow"
icon_state = "cow"
@@ -678,19 +973,13 @@
name = "Cow"
icon_state = "cow"
-/datum/sprite_accessory/mam_ears/curled
- name = "Curled Horn"
- icon_state = "horn1"
-
/datum/sprite_accessory/mam_tails/eevee
name = "Eevee"
icon_state = "eevee"
- extra = TRUE
/datum/sprite_accessory/mam_tails_animated/eevee
name = "Eevee"
icon_state = "eevee"
- extra = TRUE
/datum/sprite_accessory/mam_tails/fennec
name = "Fennec"
@@ -703,24 +992,18 @@
/datum/sprite_accessory/mam_tails/human/fish
name = "Fish"
icon_state = "fish"
- extra = TRUE
- extra_color_src = MUTCOLORS3
/datum/sprite_accessory/mam_tails_animated/human/fish
name = "Fish"
icon_state = "fish"
- extra = TRUE
- extra_color_src = MUTCOLORS3
/datum/sprite_accessory/mam_tails/fox
name = "Fox"
icon_state = "fox"
- extra = TRUE
/datum/sprite_accessory/mam_tails_animated/fox
name = "Fox"
icon_state = "fox"
- extra = TRUE
/datum/sprite_accessory/mam_tails/hawk
name = "Hawk"
@@ -743,12 +1026,10 @@
/datum/sprite_accessory/mam_tails/husky
name = "Husky"
icon_state = "husky"
- extra = TRUE
/datum/sprite_accessory/mam_tails_animated/husky
name = "Husky"
icon_state = "husky"
- extra = TRUE
datum/sprite_accessory/mam_tails/insect
name = "Insect"
@@ -766,20 +1047,13 @@ datum/sprite_accessory/mam_tails/insect
name = "kangaroo"
icon_state = "kangaroo"
-/datum/sprite_accessory/mam_ears/jellyfish
- name = "Jellyfish"
- icon_state = "jellyfish"
- color_src = HAIR
-
/datum/sprite_accessory/mam_tails/kitsune
name = "Kitsune"
icon_state = "kitsune"
- extra = TRUE
/datum/sprite_accessory/mam_tails_animated/kitsune
name = "Kitsune"
icon_state = "kitsune"
- extra = TRUE
/datum/sprite_accessory/mam_tails/lab
name = "Lab"
@@ -792,22 +1066,10 @@ datum/sprite_accessory/mam_tails/insect
/datum/sprite_accessory/mam_tails/murid
name = "Murid"
icon_state = "murid"
- color_src = 0
/datum/sprite_accessory/mam_tails_animated/murid
name = "Murid"
icon_state = "murid"
- color_src = 0
-
-/datum/sprite_accessory/mam_tails/neko
- name = "Neko"
- icon_state = "cat"
- color_src = HAIR
-
-/datum/sprite_accessory/mam_tails_animated/neko
- name = "Neko"
- icon_state = "cat"
- color_src = HAIR
/datum/sprite_accessory/mam_tails/otie
name = "Otusian"
@@ -820,12 +1082,10 @@ datum/sprite_accessory/mam_tails/insect
/datum/sprite_accessory/mam_tails/orca
name = "Orca"
icon_state = "orca"
- extra = TRUE
/datum/sprite_accessory/mam_tails_animated/orca
name = "Orca"
icon_state = "orca"
- extra = TRUE
/datum/sprite_accessory/mam_tails/pede
name = "Scolipede"
@@ -852,38 +1112,36 @@ datum/sprite_accessory/mam_tails/insect
icon_state = "sergal"
/datum/sprite_accessory/mam_tails/skunk
- name = "skunk"
+ name = "Skunk"
icon_state = "skunk"
- color_src = 0
- extra = TRUE
/datum/sprite_accessory/mam_tails_animated/skunk
- name = "skunk"
+ name = "Skunk"
icon_state = "skunk"
- color_src = 0
- extra = TRUE
/datum/sprite_accessory/mam_tails/shark
name = "Shark"
icon_state = "shark"
- color_src = MUTCOLORS
/datum/sprite_accessory/mam_tails_animated/shark
name = "Shark"
icon_state = "shark"
- color_src = MUTCOLORS
/datum/sprite_accessory/mam_tails/shepherd
name = "Shepherd"
icon_state = "shepherd"
- extra = TRUE
- extra2 = TRUE
/datum/sprite_accessory/mam_tails_animated/shepherd
name = "Shepherd"
icon_state = "shepherd"
- extra = TRUE
- extra2 = TRUE
+
+/datum/sprite_accessory/mam_tails/straighttail
+ name = "Straight Tail"
+ icon_state = "straighttail"
+
+/datum/sprite_accessory/mam_tails_animated/straighttail
+ name = "Straight Tail"
+ icon_state = "straighttail"
/datum/sprite_accessory/mam_tails/squirrel
name = "Squirrel"
@@ -893,7 +1151,7 @@ datum/sprite_accessory/mam_tails/insect
name = "Squirrel"
icon_state = "squirrel"
-datum/sprite_accessory/mam_tails/tentacle
+/datum/sprite_accessory/mam_tails/tentacle
name = "Tentacle"
icon_state = "tentacle"
@@ -901,6 +1159,14 @@ datum/sprite_accessory/mam_tails/tentacle
name = "Tentacle"
icon_state = "tentacle"
+/datum/sprite_accessory/mam_tails/tiger
+ name = "Tiger"
+ icon_state = "tiger"
+
+/datum/sprite_accessory/mam_tails_animated/tiger
+ name = "Tiger"
+ icon_state = "tiger"
+
/datum/sprite_accessory/mam_tails/wolf
name = "Wolf"
icon_state = "wolf"
@@ -914,150 +1180,168 @@ datum/sprite_accessory/mam_tails/tentacle
*******************************************/
/datum/sprite_accessory/mam_body_markings
- extra = TRUE
- extra2 = TRUE
- icon = 'modular_citadel/icons/mob/mam_body_markings.dmi'
+ extra = FALSE
+ extra2 = FALSE
+ color_src = MATRIXED
+ gender_specific = 0
+ icon = 'modular_citadel/icons/mob/mam_markings.dmi'
/datum/sprite_accessory/mam_body_markings/none
name = "None"
icon_state = "none"
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/mam_body_markings/plain
+ name = "Plain"
+ icon_state = "plain"
/datum/sprite_accessory/mam_body_markings/ailurus
- name = "Red Panda"
- icon_state = "ailurus"
- gender_specific = 1
-
-/datum/sprite_accessory/mam_body_markings/belly
- name = "Bee"
- icon_state = "bee"
- color_src = MUTCOLORS3
- gender_specific = 1
+ name = "Redpanda"
+ icon_state = "wah"
/datum/sprite_accessory/mam_body_markings/bee
+ name = "Bee"
+ icon_state = "bee"
+
+/datum/sprite_accessory/mam_body_markings/belly
name = "Belly"
icon_state = "belly"
- gender_specific = 1
+
+/datum/sprite_accessory/mam_body_markings/bellyslim
+ name = "Bellyslim"
+ icon_state = "bellyslim"
/datum/sprite_accessory/mam_body_markings/corgi
name = "Corgi"
icon_state = "corgi"
- color_src = MUTCOLORS2
- extra_color_src = MUTCOLORS3
- gender_specific = 1
/datum/sprite_accessory/mam_body_markings/cow
- name = "Cow"
- icon_state = "cow"
- color_src = MUTCOLORS2
- extra_color_src = MUTCOLORS3
- gender_specific = 1
+ name = "Bovine"
+ icon_state = "bovine"
/datum/sprite_accessory/mam_body_markings/corvid
- name = "Crow"
+ name = "Corvid"
icon_state = "corvid"
- gender_specific = 1
+
+/datum/sprite_accessory/mam_body_markings/dalmation
+ name = "Dalmation"
+ icon_state = "dalmation"
/datum/sprite_accessory/mam_body_markings/deer
name = "Deer"
icon_state = "deer"
- color_src = MUTCOLORS2
- extra_color_src = MUTCOLORS3
- gender_specific = 1
/datum/sprite_accessory/mam_body_markings/eevee
name = "Eevee"
icon_state = "eevee"
- color_src = MUTCOLORS3
+
+/datum/sprite_accessory/mam_body_markings/hippo
+ name = "Hippo"
+ icon_state = "hippo"
/datum/sprite_accessory/mam_body_markings/fennec
name = "Fennec"
icon_state = "Fennec"
- gender_specific = 1
/datum/sprite_accessory/mam_body_markings/fox
name = "Fox"
icon_state = "fox"
- gender_specific = 1
/datum/sprite_accessory/mam_body_markings/frog
name = "Frog"
icon_state = "frog"
- gender_specific = 1
- color_src = MUTCOLORS2
+
+/datum/sprite_accessory/mam_body_markings/goat
+ name = "Goat"
+ icon_state = "goat"
+
+/datum/sprite_accessory/mam_body_markings/handsfeet
+ name = "Handsfeet"
+ icon_state = "handsfeet"
/datum/sprite_accessory/mam_body_markings/hawk
name = "Hawk"
icon_state = "hawk"
- gender_specific = 1
/datum/sprite_accessory/mam_body_markings/husky
name = "Husky"
icon_state = "husky"
- gender_specific = 1
+
+/datum/sprite_accessory/mam_body_markings/hyena
+ name = "Hyena"
+ icon_state = "hyena"
+
+/datum/sprite_accessory/mam_body_markings/lab
+ name = "Lab"
+ icon_state = "lab"
/datum/sprite_accessory/mam_body_markings/moth
name = "Moth"
icon_state = "moth"
- color_src = MUTCOLORS2
- extra_color_src = MUTCOLORS3
- gender_specific = 1
/datum/sprite_accessory/mam_body_markings/otie
name = "Otie"
icon_state = "otie"
- gender_specific = 1
+
+/datum/sprite_accessory/mam_body_markings/otter
+ name = "Otter"
+ icon_state = "otter"
/datum/sprite_accessory/mam_body_markings/orca
name = "Orca"
icon_state = "orca"
- color_src = MUTCOLORS2
- gender_specific = 1
+
+/datum/sprite_accessory/mam_body_markings/panther
+ name = "Panther"
+ icon_state = "panther"
+
+/datum/sprite_accessory/mam_body_markings/possum
+ name = "Possum"
+ icon_state = "possum"
+
+/datum/sprite_accessory/mam_body_markings/raccoon
+ name = "Raccoon"
+ icon_state = "raccoon"
/datum/sprite_accessory/mam_body_markings/pede
name = "Scolipede"
- icon_state = "pede"
- extra = TRUE
- extra_color_src = MUTCOLORS3
- color_src = MUTCOLORS2
- gender_specific = 1
+ icon_state = "scolipede"
/datum/sprite_accessory/mam_body_markings/shark
name = "Shark"
icon_state = "shark"
- color_src = MUTCOLORS2
- extra_color_src = MUTCOLORS3
- gender_specific = 1
+
+/datum/sprite_accessory/mam_body_markings/skunk
+ name = "Skunk"
+ icon_state = "skunk"
+
+/datum/sprite_accessory/mam_body_markings/sergal
+ name = "Sergal"
+ icon_state = "sergal"
/datum/sprite_accessory/mam_body_markings/shepherd
name = "Shepherd"
icon_state = "shepherd"
- gender_specific = 1
+
+/datum/sprite_accessory/mam_body_markings/tajaran
+ name = "Tajaran"
+ icon_state = "tajaran"
/datum/sprite_accessory/mam_body_markings/tiger
- name = "Tiger Stripes"
- color_src = MUTCOLORS3
+ name = "Tiger"
icon_state = "tiger"
/datum/sprite_accessory/mam_body_markings/turian
name = "Turian"
- extra = TRUE
- color_src = MUTCOLORS
- extra_color_src = MUTCOLORS2
icon_state = "turian"
- gender_specific = 1
/datum/sprite_accessory/mam_body_markings/wolf
name = "Wolf"
icon_state = "wolf"
- color_src = MUTCOLORS2
- gender_specific = 1
/datum/sprite_accessory/mam_body_markings/xeno
name = "Xeno"
icon_state = "xeno"
- color_src = MUTCOLORS2
- extra_color_src = MUTCOLORS3
- gender_specific = 1
/******************************************
@@ -1072,6 +1356,7 @@ datum/sprite_accessory/mam_tails/tentacle
center = TRUE
dimension_x = 64
var/taur_mode = NOT_TAURIC
+ color_src = MATRIXED
/datum/sprite_accessory/taur/none
name = "None"
@@ -1090,11 +1375,13 @@ datum/sprite_accessory/mam_tails/tentacle
/datum/sprite_accessory/taur/drider
name = "Drider"
icon_state = "drider"
+ color_src = MUTCOLORS
/datum/sprite_accessory/taur/eevee
name = "Eevee"
icon_state = "eevee"
taur_mode = PAW_TAURIC
+ color_src = MUTCOLORS
/datum/sprite_accessory/taur/fox
name = "Fox"
@@ -1130,6 +1417,7 @@ datum/sprite_accessory/mam_tails/tentacle
name = "Scolipede"
icon_state = "pede"
taur_mode = PAW_TAURIC
+ color_src = MUTCOLORS
/datum/sprite_accessory/taur/panther
name = "Panther"
@@ -1141,15 +1429,16 @@ datum/sprite_accessory/mam_tails/tentacle
icon_state = "shepherd"
taur_mode = PAW_TAURIC
-/datum/sprite_accessory/taur/tajaran
- name = "Tajaran"
- icon_state = "tajaran"
- taur_mode = PAW_TAURIC
-
/datum/sprite_accessory/taur/tentacle
name = "Tentacle"
icon_state = "tentacle"
taur_mode = SNEK_TAURIC
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/taur/tiger
+ name = "Tiger"
+ icon_state = "tiger"
+ taur_mode = PAW_TAURIC
/datum/sprite_accessory/taur/wolf
name = "Wolf"
@@ -1365,17 +1654,15 @@ datum/sprite_accessory/mam_tails/tentacle
/datum/sprite_accessory/body_markings/guilmon
name = "Guilmon"
icon_state = "guilmon"
- gender_specific = 1
+ color_src = MATRIXED
/datum/sprite_accessory/tails/lizard/guilmon
name = "Guilmon"
icon_state = "guilmon"
- extra = TRUE
/datum/sprite_accessory/tails_animated/lizard/guilmon
name = "Guilmon"
icon_state = "guilmon"
- extra = TRUE
/datum/sprite_accessory/horns/guilmon
name = "Guilmon"
@@ -1385,52 +1672,41 @@ datum/sprite_accessory/mam_tails/tentacle
/datum/sprite_accessory/snout/guilmon
name = "Guilmon"
icon_state = "guilmon"
+ color_src = MATRIXED
/datum/sprite_accessory/mam_tails/shark/datashark
name = "DataShark"
icon_state = "datashark"
- color_src = 0
ckeys_allowed = list("rubyflamewing")
/datum/sprite_accessory/mam_tails_animated/shark/datashark
name = "DataShark"
icon_state = "datashark"
- color_src = 0
/datum/sprite_accessory/mam_body_markings/shark/datashark
name = "DataShark"
icon_state = "datashark"
- color_src = MUTCOLORS2
ckeys_allowed = list("rubyflamewing")
-
//Sabresune
/datum/sprite_accessory/mam_ears/sabresune
name = "sabresune"
icon_state = "sabresune"
- hasinner = 1
- extra = TRUE
- extra_color_src = MUTCOLORS3
ckeys_allowed = list("poojawa")
/datum/sprite_accessory/mam_tails/sabresune
name = "sabresune"
icon_state = "sabresune"
- extra = TRUE
ckeys_allowed = list("poojawa")
/datum/sprite_accessory/mam_tails_animated/sabresune
name = "sabresune"
icon_state = "sabresune"
- extra = TRUE
/datum/sprite_accessory/mam_body_markings/sabresune
name = "Sabresune"
icon_state = "sabresune"
- color_src = MUTCOLORS2
- extra = FALSE
- extra2 = FALSE
ckeys_allowed = list("poojawa")
@@ -1438,21 +1714,16 @@ datum/sprite_accessory/mam_tails/tentacle
/datum/sprite_accessory/mam_ears/lunasune
name = "lunasune"
icon_state = "lunasune"
- hasinner = 1
- extra = TRUE
- extra_color_src = MUTCOLORS2
ckeys_allowed = list("invader4352")
/datum/sprite_accessory/mam_tails/lunasune
name = "lunasune"
icon_state = "lunasune"
- extra = TRUE
ckeys_allowed = list("invader4352")
/datum/sprite_accessory/mam_tails_animated/lunasune
name = "lunasune"
icon_state = "lunasune"
- extra = TRUE
/*************** VIRGO PORTED HAIRS ****************************/
#define VHAIR(_name, new_state) /datum/sprite_accessory/hair/##new_state/icon_state=#new_state;/datum/sprite_accessory/hair/##new_state/name = "Virgo - " + #_name
diff --git a/modular_citadel/code/modules/mob/living/carbon/human/human_movement.dm b/modular_citadel/code/modules/mob/living/carbon/human/human_movement.dm
index 0e59e2cd9f..c4449d33d7 100644
--- a/modular_citadel/code/modules/mob/living/carbon/human/human_movement.dm
+++ b/modular_citadel/code/modules/mob/living/carbon/human/human_movement.dm
@@ -31,3 +31,7 @@
for(var/obj/screen/sprintbutton/selector in hud_used.static_inventory)
selector.insert_witty_toggle_joke_here(src)
return TRUE
+
+/mob/living/carbon/human/proc/sprint_hotkey(targetstatus)
+ if(targetstatus ? !sprinting : sprinting)
+ togglesprint()
diff --git a/modular_citadel/code/modules/mob/living/carbon/human/species.dm b/modular_citadel/code/modules/mob/living/carbon/human/species.dm
index 1dd6276140..73a50dccf0 100644
--- a/modular_citadel/code/modules/mob/living/carbon/human/species.dm
+++ b/modular_citadel/code/modules/mob/living/carbon/human/species.dm
@@ -98,6 +98,8 @@
return GLOB.mam_body_markings_list[H.dna.features["mam_body_markings"]]
if("mam_ears")
return GLOB.mam_ears_list[H.dna.features["mam_ears"]]
+ if("mam_snouts")
+ return GLOB.mam_snouts_list[H.dna.features["mam_snouts"]]
if("taur")
return GLOB.taur_list[H.dna.features["taur"]]
if("xenodorsal")
diff --git a/modular_citadel/code/modules/mob/living/carbon/human/species_types/furrypeople.dm b/modular_citadel/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
index 16c5460174..edc36ae3af 100644
--- a/modular_citadel/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
+++ b/modular_citadel/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
@@ -5,8 +5,8 @@
should_draw_citadel = TRUE
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR)
inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID)
- mutant_bodyparts = list("mam_tail", "mam_ears", "mam_body_markings", "snout", "taur", "legs")
- default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "snout" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "mam_body_markings" = "Husky", "taur" = "None", "legs" = "Normal Legs")
+ mutant_bodyparts = list("mam_tail", "mam_ears", "mam_body_markings", "mam_snouts", "taur", "legs")
+ default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "mam_body_markings" = "Husky", "taur" = "None", "legs" = "Normal Legs")
attack_verb = "claw"
attack_sound = 'sound/weapons/slash.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
@@ -46,6 +46,7 @@
/datum/species/mammal/qualifies_for_rank(rank, list/features)
return TRUE
+
//AVIAN//
/datum/species/avian
name = "Avian"
@@ -55,8 +56,8 @@
should_draw_citadel = TRUE
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR)
inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID)
- mutant_bodyparts = list("snout", "wings", "taur", "mam_tail", "mam_body_markings", "taur")
- default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "snout" = "Beak", "wings" = "None", "taur" = "None", "mam_body_markings" = "Hawk", "mam_tail" = "Hawk")
+ mutant_bodyparts = list("mam_snouts", "wings", "taur", "mam_tail", "mam_body_markings", "taur")
+ default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_snouts" = "Beak", "mam_body_markings" = "Hawk", "wings" = "None", "taur" = "None", "mam_tail" = "Hawk")
attack_verb = "peck"
attack_sound = 'sound/weapons/slash.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
@@ -101,8 +102,8 @@
should_draw_citadel = TRUE
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR)
inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID)
- mutant_bodyparts = list("mam_tail", "mam_body_markings", "mam_ears", "taur", "legs")
- default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "Shark", "mam_body_markings" = "Shark", "mam_ears" = "None", "snout" = "Round", "taur" = "None", "legs" = "Normal Legs")
+ mutant_bodyparts = list("mam_tail", "mam_ears","mam_body_markings", "taur", "legs", "mam_snouts")
+ default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "Shark", "mam_ears" = "None", "mam_body_markings" = "Shark", "mam_snouts" = "Round", "taur" = "None", "legs" = "Normal Legs")
attack_verb = "bite"
attack_sound = 'sound/weapons/bite.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
@@ -148,8 +149,8 @@
should_draw_citadel = TRUE
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR)
inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID, MOB_BUG)
- mutant_bodyparts = list("mam_body_markings", "mam_ears", "mam_tail", "taur", "moth_wings")
- default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_body_markings" = "Moth", "mam_tail" = "None", "mam_ears" = "None", "moth_wings" = "Plain", "snout" = "None", "taur" = "None")
+ mutant_bodyparts = list("mam_ears", "mam_body_markings", "mam_tail", "taur", "moth_wings", "mam_snouts")
+ default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "None", "mam_ears" = "None", "moth_wings" = "Plain", "mam_snouts" = "Bug", "mam_body_markings" = "Moth", "taur" = "None")
attack_verb = "flutter" //wat?
attack_sound = 'sound/weapons/slash.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
@@ -196,8 +197,8 @@
should_draw_citadel = TRUE
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,DIGITIGRADE)
inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID)
- mutant_bodyparts = list("xenotail", "xenohead", "xenodorsal", "taur", "mam_body_markings")
- default_features = list("xenotail"="Xenomorph Tail","xenohead"="Standard","xenodorsal"="Standard","mcolor" = "0F0","mcolor2" = "0F0","mcolor3" = "0F0","taur" = "None","mam_body_markings" = "Xeno")
+ mutant_bodyparts = list("xenotail", "xenohead", "xenodorsal", "mam_body_markings", "taur")
+ default_features = list("xenotail"="Xenomorph Tail","xenohead"="Standard","xenodorsal"="Standard", "mam_body_markings" = "Xeno","mcolor" = "0F0","mcolor2" = "0F0","mcolor3" = "0F0","taur" = "None")
attack_verb = "slash"
attack_sound = 'sound/weapons/slash.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
diff --git a/modular_citadel/code/modules/mob/living/silicon/robot/robot_movement.dm b/modular_citadel/code/modules/mob/living/silicon/robot/robot_movement.dm
index 37dba85c40..598690590c 100644
--- a/modular_citadel/code/modules/mob/living/silicon/robot/robot_movement.dm
+++ b/modular_citadel/code/modules/mob/living/silicon/robot/robot_movement.dm
@@ -23,3 +23,7 @@
for(var/obj/screen/sprintbutton/selector in hud_used.static_inventory)
selector.insert_witty_toggle_joke_here(src)
return TRUE
+
+/mob/living/silicon/robot/proc/sprint_hotkey(targetstatus)
+ if(targetstatus ? !sprinting : sprinting)
+ togglesprint()
diff --git a/modular_citadel/icons/mob/citadel_refs/mam_body_markings Matrixed Ref.dmi b/modular_citadel/icons/mob/citadel_refs/mam_body_markings Matrixed Ref.dmi
new file mode 100644
index 0000000000..7cf2c599ee
Binary files /dev/null and b/modular_citadel/icons/mob/citadel_refs/mam_body_markings Matrixed Ref.dmi differ
diff --git a/modular_citadel/icons/mob/mam_body_markings.dmi b/modular_citadel/icons/mob/mam_body_markings.dmi
deleted file mode 100644
index 99f4d0624c..0000000000
Binary files a/modular_citadel/icons/mob/mam_body_markings.dmi and /dev/null differ
diff --git a/modular_citadel/icons/mob/mam_ears.dmi b/modular_citadel/icons/mob/mam_ears.dmi
index 51ffd28bbc..b3946b546c 100644
Binary files a/modular_citadel/icons/mob/mam_ears.dmi and b/modular_citadel/icons/mob/mam_ears.dmi differ
diff --git a/modular_citadel/icons/mob/mam_markings.dmi b/modular_citadel/icons/mob/mam_markings.dmi
new file mode 100644
index 0000000000..1d64bb857f
Binary files /dev/null and b/modular_citadel/icons/mob/mam_markings.dmi differ
diff --git a/modular_citadel/icons/mob/mam_snouts.dmi b/modular_citadel/icons/mob/mam_snouts.dmi
index 98b62f929d..0bcfab6905 100644
Binary files a/modular_citadel/icons/mob/mam_snouts.dmi and b/modular_citadel/icons/mob/mam_snouts.dmi differ
diff --git a/modular_citadel/icons/mob/mam_tails OLD.dmi b/modular_citadel/icons/mob/mam_tails OLD.dmi
new file mode 100644
index 0000000000..7627b71b35
Binary files /dev/null and b/modular_citadel/icons/mob/mam_tails OLD.dmi differ
diff --git a/modular_citadel/icons/mob/mam_tails.dmi b/modular_citadel/icons/mob/mam_tails.dmi
index 7627b71b35..8c97b869d6 100644
Binary files a/modular_citadel/icons/mob/mam_tails.dmi and b/modular_citadel/icons/mob/mam_tails.dmi differ
diff --git a/modular_citadel/icons/mob/mam_taur.dmi b/modular_citadel/icons/mob/mam_taur.dmi
index 5591636886..ebaa0123ae 100644
Binary files a/modular_citadel/icons/mob/mam_taur.dmi and b/modular_citadel/icons/mob/mam_taur.dmi differ
diff --git a/modular_citadel/icons/mob/markings_notmammals.dmi b/modular_citadel/icons/mob/markings_notmammals.dmi
new file mode 100644
index 0000000000..4161ea2cea
Binary files /dev/null and b/modular_citadel/icons/mob/markings_notmammals.dmi differ
diff --git a/modular_citadel/icons/mob/mutant_bodyparts.dmi b/modular_citadel/icons/mob/mutant_bodyparts.dmi
index 7dcff09747..f369f21afb 100644
Binary files a/modular_citadel/icons/mob/mutant_bodyparts.dmi and b/modular_citadel/icons/mob/mutant_bodyparts.dmi differ
diff --git a/modular_citadel/interface/skin.dmf b/modular_citadel/interface/skin.dmf
index eca2dda112..39626ef912 100644
--- a/modular_citadel/interface/skin.dmf
+++ b/modular_citadel/interface/skin.dmf
@@ -287,3 +287,30 @@ window "statwindow"
prefix-color = #ebebeb
suffix-color = #ebebeb
+window "preferences_window"
+ elem "preferences_window"
+ type = MAIN
+ pos = 372,0
+ size = 1120x1000
+ anchor1 = none
+ anchor2 = none
+ background-color = none
+ is-visible = false
+ saved-params = "pos;size;is-minimized;is-maximized"
+ statusbar = false
+ elem "preferences_browser"
+ type = BROWSER
+ pos = -8,-8
+ size = 896x1008
+ anchor1 = 0,0
+ anchor2 = 90,100
+ background-color = none
+ saved-params = ""
+ elem "character_preview_map"
+ type = MAP
+ pos = 887,0
+ size = 313x1000
+ anchor1 = 90,0
+ anchor2 = 100,100
+ right-click = true
+ saved-params = "zoom;letterbox;zoom-mode"
\ No newline at end of file
diff --git a/modular_citadel/sound/voice/merowr.ogg b/modular_citadel/sound/voice/merowr.ogg
new file mode 100644
index 0000000000..01fb993c61
Binary files /dev/null and b/modular_citadel/sound/voice/merowr.ogg differ
diff --git a/sound/effects/lingbloodhiss.ogg b/sound/effects/lingbloodhiss.ogg
new file mode 100644
index 0000000000..31ebcf06bc
Binary files /dev/null and b/sound/effects/lingbloodhiss.ogg differ
diff --git a/sound/effects/lingreadapt.ogg b/sound/effects/lingreadapt.ogg
new file mode 100644
index 0000000000..9ca98eb78c
Binary files /dev/null and b/sound/effects/lingreadapt.ogg differ
diff --git a/tools/HumanScissors/!README.txt b/tools/HumanScissors/!README.txt
new file mode 100644
index 0000000000..d8396c8b85
--- /dev/null
+++ b/tools/HumanScissors/!README.txt
@@ -0,0 +1,7 @@
+This small Byond program takes all the icons in SpritesToSnip.dmi,
+cuts them using all the icons in CookieCutter.dmi, and produces a file save
+dialog for you to download the resulting DMI.
+
+Useful for cutting up species sprites from full body ones. Or whatever else.
+
+--Arokha/Aronai
\ No newline at end of file
diff --git a/tools/HumanScissors/CookieCutter.dmi b/tools/HumanScissors/CookieCutter.dmi
new file mode 100644
index 0000000000..f0fcf87617
Binary files /dev/null and b/tools/HumanScissors/CookieCutter.dmi differ
diff --git a/tools/HumanScissors/HumanScissors.dm b/tools/HumanScissors/HumanScissors.dm
new file mode 100644
index 0000000000..28a9f804af
--- /dev/null
+++ b/tools/HumanScissors/HumanScissors.dm
@@ -0,0 +1,56 @@
+/*
+ These are simple defaults for your project.
+ */
+
+world
+ fps = 25 // 25 frames per second
+ icon_size = 32 // 32x32 icon size by default
+
+ view = 6 // show up to 6 tiles outward from center (13x13 view)
+
+
+// Make objects move 8 pixels per tick when walking
+//usr << ftp(usr.working,"[usr.outfile].dmi")
+mob
+ step_size = 8
+
+obj
+ step_size = 8
+
+
+
+client/verb/split_sprites()
+ set name = "Begin The Decimation"
+ set desc = "Loads SpritesToSnip.dmi and cuts them with CookieCutter.dmi"
+ set category = "Here"
+
+ var/icon/SpritesToSnip = icon('SpritesToSnip.dmi')
+ var/icon/CookieCutter = icon('CookieCutter.dmi')
+
+ var/icon/RunningOutput = new ()
+
+ //For each original project
+ for(var/OriginalState in icon_states(SpritesToSnip))
+ //For each piece we're going to cut
+ for(var/CutterState in icon_states(CookieCutter))
+
+ //The fully assembled icon to cut
+ var/icon/Original = icon(SpritesToSnip,OriginalState)
+
+ //Our cookie cutter sprite
+ var/icon/Cutter = icon(CookieCutter,CutterState)
+
+ //We have to make these all black to cut with
+ Cutter.Blend(rgb(0,0,0),ICON_MULTIPLY)
+
+ //Blend with AND to cut
+ Original.Blend(Cutter,ICON_AND) //AND, not ADD
+
+ //Make a useful name
+ var/good_name = "[OriginalState]_[CutterState]"
+
+ //Add to the output with the good name
+ RunningOutput.Insert(Original,good_name)
+
+ //Give the output
+ usr << ftp(RunningOutput,"CutUpPeople.dmi")
diff --git a/tools/HumanScissors/HumanScissors.dme b/tools/HumanScissors/HumanScissors.dme
new file mode 100644
index 0000000000..86377f1c57
--- /dev/null
+++ b/tools/HumanScissors/HumanScissors.dme
@@ -0,0 +1,18 @@
+// DM Environment file for HumanScissors.dme.
+// All manual changes should be made outside the BEGIN_ and END_ blocks.
+// New source code should be placed in .dm files: choose File/New --> Code File.
+
+// BEGIN_INTERNALS
+// END_INTERNALS
+
+// BEGIN_FILE_DIR
+#define FILE_DIR .
+// END_FILE_DIR
+
+// BEGIN_PREFERENCES
+// END_PREFERENCES
+
+// BEGIN_INCLUDE
+#include "HumanScissors.dm"
+// END_INCLUDE
+
diff --git a/tools/HumanScissors/SpritesToSnip.dmi b/tools/HumanScissors/SpritesToSnip.dmi
new file mode 100644
index 0000000000..f4dbfb6b81
Binary files /dev/null and b/tools/HumanScissors/SpritesToSnip.dmi differ
|