diff --git a/code/modules/mob/living/carbon/human/human_powers.dm b/code/modules/mob/living/carbon/human/human_powers.dm
index 93203a05559..d058cdc0438 100644
--- a/code/modules/mob/living/carbon/human/human_powers.dm
+++ b/code/modules/mob/living/carbon/human/human_powers.dm
@@ -459,7 +459,6 @@
src << "Your spine still aches!"
return
-
if(stat || paralysis || stunned || weakened || lying || restrained() || buckled)
src << "You cannot launch a quill in your current state."
return
@@ -473,3 +472,91 @@
var/obj/item/weapon/arrow/quill/A = new /obj/item/weapon/arrow/quill(usr.loc)
A.throw_at(target, 10, 30, user)
msg_admin_attack("[key_name_admin(src)] launched a quill at [key_name_admin(target)] (JMP)",ckey=key_name(src),ckey_target=key_name(target))
+
+
+/mob/living/carbon/human/proc/shatter_light()
+ set category = "Abilities"
+ set name = "Shatter Lights"
+ set desc = "Shatter all lights around yourself."
+
+ if(last_special > world.time)
+ src << "You're still regaining your strength!"
+ return
+
+ last_special = world.time + 50
+
+ visible_message("\The [src] shrieks!")
+ playsound(src.loc, 'sound/species/shadow/grue_screech.ogg', 100, 1)
+
+ for(var/obj/machinery/light/L in range(7))
+ L.broken()
+
+/mob/living/carbon/human/proc/create_darkness()
+ set category = "Abilities"
+ set name = "Create Darkness"
+ set desc = "Create a field of darkness around yourself."
+
+ if(last_special > world.time)
+ src << "You're still regaining your strength!"
+ return
+
+ last_special = world.time + 100
+
+ playsound(src.loc, 'sound/species/shadow/grue_growl.ogg', 100, 1)
+
+ src.set_light(4,-20)
+
+ addtimer(CALLBACK(src, /atom/.proc/set_light, 0), 30 SECONDS)
+
+/mob/living/carbon/human/proc/darkness_eyes()
+ set category = "Abilities"
+ set name = "Toggle Shadow Vision"
+ set desc = "Toggle between seeing shadows or not."
+
+ if (!stop_sight_update)
+ src << "Your eyes shift around, allowing you to see in the dark."
+ src.stop_sight_update = 1
+ src.see_invisible = SEE_INVISIBLE_NOLIGHTING
+
+ else
+ src << "You return your vision to normal."
+ src.stop_sight_update = 0
+
+/mob/living/carbon/human/proc/shadow_step(var/turf/T in turfs)
+ set category = "Abilities"
+ set name = "Shadow Step"
+ set desc = "Travel from place to place using the shadows."
+
+ if(last_special > world.time)
+ src << "You're still regaining your strength!"
+ return
+
+ if (!T || T.density || T.contains_dense_objects())
+ src << "You cannot do that."
+ return
+
+ if(!isturf(loc))
+ to_chat(src, "You cannot teleport out of your current location.")
+ return
+
+ if (T.z != src.z || get_dist(T, get_turf(src)) > world.view)
+ src << "Your powers are not capable of taking you that far."
+ return
+
+ if (!T.dynamic_lighting || T.get_lumcount() > 0.1)
+ src << "The destination is too bright."
+ return
+
+ last_special = world.time + 200
+
+ visible_message("\The [src] vanishes into the shadows!")
+
+ anim(get_turf(loc), loc,'icons/mob/mob.dmi',,"shadow", null ,loc.dir)
+
+ forceMove(T)
+
+ for (var/obj/item/weapon/grab/G in contents)
+ if (G.affecting)
+ G.affecting.forceMove(locate(T.x + rand(-1,1), T.y + rand(-1,1), T.z))
+ else
+ qdel(G)
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 848f985e61c..fd28ae6b76e 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -920,6 +920,15 @@
if(status_flags & GODMODE) return 0 //godmode
+ if(species.light_dam)
+ var/light_amount = 0
+ if(isturf(loc))
+ var/turf/T = loc
+ light_amount = T.get_lumcount() * 10
+ if(light_amount > species.light_dam) //if there's enough light, start dying
+ take_overall_damage(5,5)
+ else //heal in the dark
+ heal_overall_damage(5,5)
// nutrition decrease
if (nutrition > 0 && stat != 2)
diff --git a/code/modules/mob/living/carbon/human/species/outsider/shadow.dm b/code/modules/mob/living/carbon/human/species/outsider/shadow.dm
index 59518009af0..2f6251dba27 100644
--- a/code/modules/mob/living/carbon/human/species/outsider/shadow.dm
+++ b/code/modules/mob/living/carbon/human/species/outsider/shadow.dm
@@ -1,13 +1,25 @@
+/mob/living/carbon/human/shadow/Initialize(mapload)
+ . = ..(mapload, "Shadow")
+
/datum/species/shadow
name = "Shadow"
name_plural = "shadows"
+ blurb = "Have you ever been alone at night \
+ thought you heard footsteps behind, \
+ and turned around and no one's there? \
+ And as you quicken up your pace \
+ you find it hard to look again, \
+ because you're sure there's someone there."
+
icobase = 'icons/mob/human_races/r_shadow.dmi'
deform = 'icons/mob/human_races/r_shadow.dmi'
- eyes = "blank_eyes"
+ eyes = "eyes_shadow"
+ has_floating_eyes = 1
- language = "Sol Common" //todo?
- unarmed_types = list(/datum/unarmed_attack/claws/strong, /datum/unarmed_attack/bite/sharp)
+ language = "Cult"
+
+ unarmed_types = list(/datum/unarmed_attack/bite/sharp, /datum/unarmed_attack/claws/strong)
light_dam = 2
darksight = 8
has_organ = list()
@@ -15,23 +27,78 @@
rarity_value = 10
virus_immune = 1
+ breakcuffs = list(MALE,FEMALE,NEUTER)
+
fall_mod = 0
+ ethanol_resistance = -1
+ taste_sensitivity = TASTE_NUMB
+
+ speech_sounds = list('sound/species/shadow/grue_growl.ogg')
+ speech_chance = 50
+
+ warning_low_pressure = 50 //immune to pressure, so they can into space/survive breaches without worries
+ hazard_low_pressure = 0
+
+ cold_level_1 = 80
+ cold_level_2 = 50
+ cold_level_3 = 0
+
+ brute_mod = 0.5
+ burn_mod = 1.2
+
+ breath_type = null
+ poison_type = null
+
blood_color = "#CCCCCC"
flesh_color = "#AAAAAA"
remains_type = /obj/effect/decal/cleanable/ash
death_message = "dissolves into ash..."
- flags = NO_BLOOD | NO_SCAN | NO_SLIP | NO_POISON | NO_MINOR_CUT
+ flags = NO_BLOOD | NO_SCAN | NO_SLIP | NO_POISON | NO_PAIN | NO_BREATHE | NO_MINOR_CUT
spawn_flags = IS_RESTRICTED
+ vision_flags = DEFAULT_SIGHT | SEE_MOBS
+
+ has_limbs = list(
+ "chest" = list("path" = /obj/item/organ/external/chest/unbreakable),
+ "groin" = list("path" = /obj/item/organ/external/groin/unbreakable),
+ "head" = list("path" = /obj/item/organ/external/head/unbreakable),
+ "l_arm" = list("path" = /obj/item/organ/external/arm/unbreakable),
+ "r_arm" = list("path" = /obj/item/organ/external/arm/right/unbreakable),
+ "l_leg" = list("path" = /obj/item/organ/external/leg/unbreakable),
+ "r_leg" = list("path" = /obj/item/organ/external/leg/right/unbreakable),
+ "l_hand" = list("path" = /obj/item/organ/external/hand/unbreakable),
+ "r_hand" = list("path" = /obj/item/organ/external/hand/right/unbreakable),
+ "l_foot" = list("path" = /obj/item/organ/external/foot/unbreakable),
+ "r_foot" = list("path" = /obj/item/organ/external/foot/right/unbreakable)
+ )
+
stamina = 500 //Tireless automatons
stamina_recovery = 1
sprint_speed_factor = 0.3
exhaust_threshold = 0 //No oxyloss, so zero threshold
+ inherent_verbs = list(
+ /mob/living/carbon/human/proc/shatter_light,
+ /mob/living/carbon/human/proc/create_darkness,
+ /mob/living/carbon/human/proc/darkness_eyes,
+ /mob/living/carbon/human/proc/shadow_step
+ )
+
/datum/species/shadow/handle_death(var/mob/living/carbon/human/H)
spawn(1)
new /obj/effect/decal/cleanable/ash(H.loc)
qdel(H)
+
+/datum/species/shadow/handle_post_spawn(var/mob/living/carbon/human/H)
+ if(H.mind)
+ H.mind.assigned_role = "Shadow"
+ H.mind.special_role = "Shadow"
+ H.real_name = "grue"
+ H.name = H.real_name
+ ..()
+
+/datum/species/shadow/get_random_name()
+ return "grue"
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index d0be291aed3..ebe84ee1513 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -379,7 +379,7 @@ There are several things that need to be remembered:
var/has_visible_hair = h_style && !(head && (head.flags_inv & BLOCKHEADHAIR))
var/icon/hair_icon = generate_hair_icon(has_visible_hair)
-
+
// Handle light emission.
if (species.light_range)
if (has_visible_hair)
@@ -398,7 +398,7 @@ There are several things that need to be remembered:
/mob/living/carbon/human/update_mutations(var/update_icons=1)
if (QDELING(src))
return
-
+
var/fat
if(FAT in mutations)
fat = "fat"
@@ -447,7 +447,7 @@ There are several things that need to be remembered:
/mob/living/carbon/human/regenerate_icons()
if (QDELING(src))
return
-
+
..()
if(transforming) return
@@ -484,7 +484,7 @@ There are several things that need to be remembered:
/mob/living/carbon/human/update_inv_w_uniform(var/update_icons=1)
if (QDELING(src))
return
-
+
overlays_raw[UNIFORM_LAYER] = null
if(check_draw_underclothing())
w_uniform.screen_loc = ui_iclothing
@@ -550,7 +550,7 @@ There are several things that need to be remembered:
/mob/living/carbon/human/update_inv_wear_id(var/update_icons=1)
if (QDELING(src))
return
-
+
overlays_raw[ID_LAYER] = null
if(wear_id)
@@ -571,8 +571,8 @@ There are several things that need to be remembered:
/mob/living/carbon/human/update_inv_gloves(var/update_icons=1)
if (QDELING(src))
return
-
-
+
+
if(check_draw_gloves())
var/t_state = gloves.item_state || gloves.icon_state
@@ -682,7 +682,7 @@ There are several things that need to be remembered:
/mob/living/carbon/human/update_inv_shoes(var/update_icons=1)
if (QDELING(src))
return
-
+
overlays_raw[SHOES_LAYER] = null
if(check_draw_shoes())
var/image/standing
@@ -721,7 +721,7 @@ There are several things that need to be remembered:
/mob/living/carbon/human/update_inv_s_store(var/update_icons=1)
if (QDELING(src))
return
-
+
if(s_store)
//s_store.auto_adapt_species(src)
overlays_raw[SUIT_STORE_LAYER] = image('icons/mob/belt_mirror.dmi', s_store.item_state || s_store.icon_state)
@@ -839,7 +839,7 @@ There are several things that need to be remembered:
/mob/living/carbon/human/update_inv_wear_suit(var/update_icons=1)
if (QDELING(src))
return
-
+
if (istype(wear_suit, /obj/item))
wear_suit.screen_loc = ui_oclothing
@@ -892,7 +892,7 @@ There are several things that need to be remembered:
/mob/living/carbon/human/update_inv_pockets(var/update_icons=1)
if (QDELING(src))
return
-
+
if(l_store)
l_store.screen_loc = ui_storage1 //TODO
if(r_store)
@@ -1002,7 +1002,7 @@ There are several things that need to be remembered:
/mob/living/carbon/human/update_inv_handcuffed(var/update_icons=1)
if (QDELING(src))
return
-
+
if(handcuffed)
drop_r_hand()
drop_l_hand()
@@ -1025,7 +1025,7 @@ There are several things that need to be remembered:
/mob/living/carbon/human/update_inv_legcuffed(var/update_icons=1)
if (QDELING(src))
return
-
+
if(legcuffed)
var/image/standing
if(legcuffed.icon_override)
@@ -1081,7 +1081,7 @@ There are several things that need to be remembered:
overlays_raw[R_HAND_LAYER] = image(t_icon, t_state)
- if(update_icons)
+ if(update_icons)
update_icons()
diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm
index 88bcbe64136..6b96c97bb6c 100644
--- a/code/modules/mob/living/life.dm
+++ b/code/modules/mob/living/life.dm
@@ -174,8 +174,9 @@
if (is_ventcrawling)
sight |= SEE_TURFS|BLIND
- see_in_dark = initial(see_in_dark)
- see_invisible = initial(see_invisible)
+ if (!stop_sight_update) //If true, it won't reset the mob vision flags to the initial ones
+ see_in_dark = initial(see_in_dark)
+ see_invisible = initial(see_invisible)
/mob/living/proc/update_dead_sight()
sight |= SEE_TURFS
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index ad3c55627c6..072bbe983ff 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -72,3 +72,5 @@
var/cloaked = 0//Set to 1 by cloaking devices, optimises update_icons
var/tesla_ignore = 0 // If true, mob is not affected by tesla bolts.
+
+ var/stop_sight_update = 0 //If true, it won't reset the mob vision flags
diff --git a/icons/mob/human_face.dmi b/icons/mob/human_face.dmi
index ebdd7b40bba..1822e2ad4c5 100644
Binary files a/icons/mob/human_face.dmi and b/icons/mob/human_face.dmi differ
diff --git a/sound/species/shadow/grue_ambience.ogg b/sound/species/shadow/grue_ambience.ogg
new file mode 100644
index 00000000000..2b84ea0f4bc
Binary files /dev/null and b/sound/species/shadow/grue_ambience.ogg differ
diff --git a/sound/species/shadow/grue_growl.ogg b/sound/species/shadow/grue_growl.ogg
new file mode 100644
index 00000000000..64cde513c13
Binary files /dev/null and b/sound/species/shadow/grue_growl.ogg differ
diff --git a/sound/species/shadow/grue_screech.ogg b/sound/species/shadow/grue_screech.ogg
new file mode 100644
index 00000000000..c79f26bb186
Binary files /dev/null and b/sound/species/shadow/grue_screech.ogg differ