[MIRROR] Completes the /datum/component/shadekin work (#11148)

Co-authored-by: Cameron Lennox <killer65311@gmail.com>
Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
This commit is contained in:
CHOMPStation2StaffMirrorBot
2025-07-09 00:01:08 -07:00
committed by GitHub
parent 52b6360a09
commit 3e095bf5db
81 changed files with 1870 additions and 2670 deletions

View File

@@ -838,8 +838,9 @@
#define COMSIG_GARGOYLE_CHECK_ENERGY "gargoyle_check_energy"
// Species Components
///from /datum/species/xenochimera/handle_environment_special()
///from /datum/species/proc/handle_species_components()
#define COMSIG_XENOCHIMERA_COMPONENT "xenochimera_component"
#define COMSIG_SHADEKIN_COMPONENT "shadekin_component"
// Hose Connector Component
#define COMSIG_HOSE_FORCEPUMP "hose_force_pump"

View File

@@ -1,13 +1,3 @@
#define NOT_WHILE_SHIFTED 1
#define ONLY_WHILE_SHIFTED 2
#define SHIFTED_OR_NOT 3
#define AB_PHASE_SHIFTED 0x1
#define AB_PHASE_SHIFTING 0x2
#define AB_SHADE_REGEN 0x4
#define AB_DARK_TUNNEL 0x40 //CHOMPEdit Add - Dark Tunneling
#define AB_DARK_RESPITE 0x80 //CHOMPEdit Add - Dark Respite
//Porting over the type system of the mobs
#define BLUE_EYES 1
#define RED_EYES 2

View File

@@ -11,8 +11,13 @@ GLOBAL_LIST_EMPTY(everyone_traits_neutral) // Neutral traits available to all sp
GLOBAL_LIST_EMPTY(everyone_traits_negative) // Neutral traits available to all species, indexed by path
GLOBAL_LIST_EMPTY(traits_costs) // Just path = cost list, saves time in char setup
GLOBAL_LIST_EMPTY(all_traits) // All of 'em at once (same instances)
GLOBAL_LIST_EMPTY(active_ghost_pods)
GLOBAL_LIST_EMPTY(active_ghost_pods) //NYI - Used downstream
GLOBAL_LIST_EMPTY(latejoin_gatewaystation) //NYI - Used downstream
GLOBAL_LIST_EMPTY(latejoin_plainspath) //NYI - Used downstream
GLOBAL_LIST_EMPTY(latejoin_fueldepot) //NYI - Used downstream
GLOBAL_LIST_EMPTY(latejoin_tyrvillage) //NYI - Used downstream
GLOBAL_LIST_EMPTY(latejoin_thedark) //NYI - Used downstream
//Global vars for making the overmap_renamer subsystem.
//Collects all instances by reference of visitable overmap objects of /obj/effect/overmap/visitable like the debris field.
GLOBAL_LIST_EMPTY(visitable_overmap_object_instances)

View File

@@ -20,6 +20,8 @@
return
if(!Adjacent(usr) || !over.Adjacent(usr))
return // should stop you from dragging through windows
if(is_incorporeal(usr))
return
INVOKE_ASYNC(over, TYPE_PROC_REF(/atom, MouseDrop_T), src, usr, src_location, over_location, src_control, over_control, params)

View File

@@ -56,7 +56,7 @@
showing = 0
overlays.len = 0
overlays.Add(closed_state)
else if(forced_state != 1) // We're opening it, show the icons.
else if(forced_state != 1) // We're opening it, show the icons. OR, if forced_state == 2, we're forcing it to open it.
open_ability_master()
update_abilities(1)
showing = 1
@@ -84,6 +84,7 @@
A.screen_loc = "[encode_screen_X(xpos)]:[x_pix],[encode_screen_Y(ypos)]:[y_pix]"
if(my_mob && my_mob.client)
my_mob.client.screen += A
my_mob.client.screen |= src
// A.handle_icon_updates = 1
/obj/screen/movable/ability_master/proc/update_abilities(forced = 0, mob/user)
@@ -177,12 +178,12 @@
/mob/Login()
..()
if(ability_master)
ability_master.toggle_open(1)
client.screen -= ability_master
ability_master.toggle_open(2) //Force it to open on login.
//client.screen -= ability_master
/mob/Initialize(mapload)
. = ..()
if(!ability_master) //VOREStation Edit: S H A D E K I N
if(!ability_master)
ability_master = new /obj/screen/movable/ability_master(src)
///////////ACTUAL ABILITIES////////////

View File

@@ -547,6 +547,31 @@ GLOBAL_LIST_INIT(global_huds, list(
/mob/new_player/add_click_catcher()
return
/mob/living/create_mob_hud(datum/hud/HUD, apply_to_client = TRUE)
..()
var/list/hud_elements = list()
shadekin_display = new /obj/screen/shadekin()
shadekin_display.screen_loc = ui_shadekin_display
shadekin_display.icon_state = "shadekin"
hud_elements |= shadekin_display
xenochimera_danger_display = new /obj/screen/xenochimera/danger_level()
xenochimera_danger_display.screen_loc = ui_xenochimera_danger_display
xenochimera_danger_display.icon_state = "danger00"
hud_elements |= xenochimera_danger_display
lleill_display = new /obj/screen/lleill()
lleill_display.screen_loc = ui_lleill_display
lleill_display.icon_state = "lleill"
hud_elements |= lleill_display
if(client)
client.screen = list()
client.screen += hud_elements
client.screen += client.void
/* TGMC Ammo HUD Port
* These procs call to screen_objects.dm's respective procs.
* All these do is manage the amount of huds on screen and set the HUD.

View File

@@ -321,22 +321,10 @@
using.alpha = HUD.ui_alpha
adding |= using
//VOREStation Addition begin
shadekin_display = new /obj/screen/shadekin()
shadekin_display.screen_loc = ui_shadekin_display
shadekin_display.icon_state = "shadekin"
//Component hud elements. Made in /mob/living/create_mob_hud
hud_elements |= shadekin_display
xenochimera_danger_display = new /obj/screen/xenochimera/danger_level()
xenochimera_danger_display.screen_loc = ui_xenochimera_danger_display
xenochimera_danger_display.icon_state = "danger00"
hud_elements |= xenochimera_danger_display
lleill_display = new /obj/screen/lleill()
lleill_display.screen_loc = ui_lleill_display
lleill_display.icon_state = "lleill"
hud_elements |= lleill_display
//VOREStation Addition end
ling_chem_display = new /obj/screen/ling/chems()
ling_chem_display.screen_loc = ui_ling_chemical_display

View File

@@ -623,7 +623,7 @@
var/mob/living/silicon/ai/AI = usr
AI.view_images()
else
return attempt_vr(src,"Click_vr",list(location,control,params)) //VOREStation Add - Additional things.
return attempt_vr(src,"Click_vr",list(location,control,params))
return 1
/obj/screen/inventory/Click()

View File

@@ -1,24 +1,16 @@
/obj/screen/proc/Click_vr(location, control, params)
if(!usr) return 1
switch(name)
//Shadekin
if("darkness")
var/turf/T = get_turf(usr)
var/darkness = round(1 - T.get_lumcount(),0.1)
to_chat(usr,span_notice(span_bold("Darkness:") + " [darkness]"))
if("energy")
var/mob/living/simple_mob/shadekin/SK = usr
if(istype(SK))
to_chat(usr,span_notice(span_bold("Energy:") + " [SK.comp.dark_energy] ([SK.dark_gains])"))
if("shadekin status")
var/turf/T = get_turf(usr)
if(T)
var/darkness = round(1 - T.get_lumcount(),0.1)
to_chat(usr,span_notice(span_bold("Darkness:") + " [darkness]"))
var/mob/living/carbon/human/H = usr
if(istype(H) && istype(H.species, /datum/species/shadekin))
to_chat(usr,span_notice(span_bold("Energy:") + " [H.shadekin_get_energy(H)]"))
var/mob/living/H = usr
if(ismob(H))
var/datum/component/shadekin/SK = H.get_shadekin_component()
if(SK)
to_chat(usr,span_notice(span_bold("Energy:") + " [SK.shadekin_get_energy()]"))
if("glamour")
var/mob/living/carbon/human/H = usr
if(istype(H))

View File

@@ -1,8 +0,0 @@
/datum/component/shadekin
var/dark_energy = 100
var/max_dark_energy = 100
var/dark_energy_infinite = FALSE
/datum/component/shadekin/Initialize()
if(!ishuman(parent) && !issimplekin(parent)) //Both humankin and simplekin can have this component
return COMPONENT_INCOMPATIBLE

View File

@@ -0,0 +1,213 @@
///Returns the shadekin component of the given mob
/mob/living/proc/get_shadekin_component()
var/datum/component/shadekin/SK = GetComponent(/datum/component/shadekin)
if(SK)
return SK
///Handles the shadekin's HUD updates.
/datum/component/shadekin/proc/update_shadekin_hud()
var/turf/T = get_turf(owner)
if(owner.shadekin_display)
var/l_icon = 0
var/e_icon = 0
owner.shadekin_display.invisibility = INVISIBILITY_NONE
if(T)
var/brightness = T.get_lumcount() //Brightness in 0.0 to 1.0
var/darkness = 1-brightness //Invert
switch(darkness)
if(0.80 to 1.00)
l_icon = 0
if(0.60 to 0.80)
l_icon = 1
if(0.40 to 0.60)
l_icon = 2
if(0.20 to 0.40)
l_icon = 3
if(0.00 to 0.20)
l_icon = 4
switch(shadekin_get_energy())
if(0 to 24)
e_icon = 0
if(25 to 49)
e_icon = 1
if(50 to 74)
e_icon = 2
if(75 to 99)
e_icon = 3
if(100 to INFINITY)
e_icon = 4
owner.shadekin_display.icon_state = "shadekin-[l_icon]-[e_icon]"
return
///For simplekin or those that have a pre-defined eye color
/datum/component/shadekin/proc/set_eye_energy()
if(!eye_color_influences_energy)
return
switch(eye_color)
//Blue has constant, steady (slow) regen and ignores darkness.
if(BLUE_EYES)
set_light_and_darkness(0.75,0.75)
nutrition_conversion_scaling = 0.5
if(RED_EYES)
set_light_and_darkness(-0.5,0.5)
nutrition_conversion_scaling = 2
if(PURPLE_EYES)
set_light_and_darkness(-0.5,1)
nutrition_conversion_scaling = 1
if(YELLOW_EYES)
set_light_and_darkness(-2,3)
nutrition_conversion_scaling = 0.5
if(GREEN_EYES)
set_light_and_darkness(0.125,2)
nutrition_conversion_scaling = 0.5
if(ORANGE_EYES)
set_light_and_darkness(-0.25,0.75)
nutrition_conversion_scaling = 1.5
///Sets our eye color.
/datum/component/shadekin/proc/set_shadekin_eyecolor()
if(!ishuman(owner))
return eye_color //revert to default if we're not a human
var/mob/living/carbon/human/H = owner
var/eyecolor_rgb = rgb(H.r_eyes, H.g_eyes, H.b_eyes)
var/list/hsv_color = rgb2num(eyecolor_rgb, COLORSPACE_HSV)
var/eyecolor_hue = hsv_color[1]
var/eyecolor_sat = hsv_color[2]
var/eyecolor_val = hsv_color[3]
//First, clamp the saturation/value to prevent black/grey/white eyes
if(eyecolor_sat < 10)
eyecolor_sat = 10
if(eyecolor_val < 40)
eyecolor_val = 40
eyecolor_rgb = rgb(eyecolor_hue, eyecolor_sat, eyecolor_val, space=COLORSPACE_HSV)
var/list/rgb_color = rgb2num(eyecolor_rgb)
H.r_eyes = rgb_color[1]
H.g_eyes = rgb_color[2]
H.b_eyes = rgb_color[3]
//Now determine what color we fall into.
switch(eyecolor_hue)
if(0 to 20)
eye_color = RED_EYES
if(21 to 50)
eye_color = ORANGE_EYES
if(51 to 70)
eye_color = YELLOW_EYES
if(71 to 160)
eye_color = GREEN_EYES
if(161 to 260)
eye_color = BLUE_EYES
if(261 to 340)
eye_color = PURPLE_EYES
if(341 to 360)
eye_color = RED_EYES
return eye_color
///Adds the shadekin abilities to the owner.
/datum/component/shadekin/proc/add_shadekin_abilities()
if(!owner.ability_master || !istype(owner.ability_master, /obj/screen/movable/ability_master/shadekin))
owner.ability_master = null
owner.ability_master = new /obj/screen/movable/ability_master/shadekin(owner)
for(var/datum/power/shadekin/P in shadekin_ability_datums)
if(!(P.verbpath in owner.verbs))
add_verb(owner, P.verbpath)
owner.ability_master.add_shadekin_ability(
object_given = owner,
verb_given = P.verbpath,
name_given = P.name,
ability_icon_given = P.ability_icon_state,
arguments = list()
)
//wait, it's all light?
///Allows setting the light and darkness gain.
///@Args: light_gain, dark_gain
/datum/component/shadekin/proc/set_light_and_darkness(light_gain, dark_gain)
if(light_gain)
energy_light = light_gain
if(dark_gain)
energy_dark = dark_gain
//ENERGY HELPERS
/// Returns the shadekin's current energy.
/// Returns max_energy if dark_energy_infinite is set to TRUE.
/datum/component/shadekin/proc/shadekin_get_energy()
if(dark_energy_infinite)
return max_dark_energy
return dark_energy
/// Returns the shadekin's maximum energy.
/datum/component/shadekin/proc/shadekin_get_max_energy()
return max_dark_energy
///Sets the shadekin's energy TO the given value.
/datum/component/shadekin/proc/shadekin_set_energy(var/new_energy)
if(!isnum(new_energy))
return
dark_energy = CLAMP(new_energy, 0, max_dark_energy)
///Sets the shadekin's maximum energy.
/datum/component/shadekin/proc/shadekin_set_max_energy(var/new_max_energy)
if(!isnum(new_max_energy))
return //No.
max_dark_energy = new_max_energy
///Adjusts the shadekin's energy by the given amount.
/datum/component/shadekin/proc/shadekin_adjust_energy(var/amount)
if(!isnum(amount))
return //No
shadekin_set_energy(dark_energy + amount)
/datum/component/shadekin/proc/handle_nutrition_conversion(dark_gains)
if(!nutrition_energy_conversion)
return
if(shadekin_get_energy() == 100 && dark_gains > 0)
owner.nutrition += dark_gains * 5 * nutrition_conversion_scaling
else if(shadekin_get_energy() < 50 && owner.nutrition > 500)
owner.nutrition -= nutrition_conversion_scaling * 50
dark_gains += nutrition_conversion_scaling
/datum/component/shadekin/proc/attack_dephase(var/turf/T = null, atom/dephaser)
// no assigned dephase-target, just use our own
if(!T)
T = get_turf(owner)
if(!in_phase || doing_phase)
return FALSE
// make sure it's possible to be dephased (and we're in phase)
if(!T || !T.CanPass(owner,T))
return FALSE
log_admin("[key_name_admin(owner)] was stunned out of phase at [T.x],[T.y],[T.z] by [dephaser.name], last touched by [dephaser.forensic_data?.get_lastprint()].")
message_admins("[key_name_admin(owner)] was stunned out of phase at [T.x],[T.y],[T.z] by [dephaser.name], last touched by [dephaser.forensic_data?.get_lastprint()]. (<A href='byond://?_src_=holder;[HrefToken()];adminplayerobservecoodjump=1;X=[T.x];Y=[T.y];Z=[T.z]'>JMP</a>)", 1)
// start the dephase
owner.phase_in(T, src)
shadekin_adjust_energy(-20) // loss of energy for the interception
// apply a little extra stun for good measure
owner.Weaken(3)
/mob/living/carbon/human/is_incorporeal()
var/datum/component/shadekin/SK = get_shadekin_component()
if(SK && SK.in_phase) //Shadekin
return TRUE
return ..()
///Proc that takes in special considerations, such as 'no abilities in VR' and the such
///Returns TRUE if we try to do something forbidden
/datum/component/shadekin/proc/special_considerations(allow_vr)
if(!allow_vr && istype(get_area(owner), /area/vr))
to_chat(owner, span_danger("The VR systems cannot comprehend this power! This is useless to you!"))
return TRUE
return FALSE

View File

@@ -0,0 +1,68 @@
//////////////////////
/// CREATE SHADE ///
//////////////////////
/datum/power/shadekin/create_shade
name = "Create Shade (25)"
desc = "Create a field of darkness that follows you."
verbpath = /mob/living/proc/create_shade
ability_icon_state = "create_shade"
/mob/living/proc/create_shade()
set name = "Create Shade (25)"
set desc = "Create a field of darkness that follows you."
set category = "Abilities.Shadekin"
var/ability_cost = 25
var/datum/component/shadekin/SK = get_shadekin_component()
if(!istype(SK))
to_chat(src, span_warning("Only a shadekin can use that!"))
return FALSE
else if(SK.special_considerations(TRUE))
return FALSE
else if(stat)
to_chat(src, span_warning("Can't use that ability in your state!"))
return FALSE
else if(SK.shadekin_get_energy() < ability_cost)
to_chat(src, span_warning("Not enough energy for that ability!"))
return FALSE
else if(SK.in_phase)
to_chat(src, span_warning("You can't use that while phase shifted!"))
return FALSE
playsound(src, 'sound/effects/bamf.ogg', 75, 1)
add_modifier(/datum/modifier/shadekin/create_shade,20 SECONDS)
SK.shadekin_adjust_energy(-ability_cost)
return TRUE
/datum/modifier/shadekin/create_shade
name = "Shadekin Shadegen"
desc = "Darkness envelops you."
mob_overlay_state = ""
on_created_text = span_notice("You drag part of The Dark into realspace, enveloping yourself.")
on_expired_text = span_warning("You lose your grasp on The Dark and realspace reasserts itself.")
stacks = MODIFIER_STACK_EXTEND
var/mob/living/simple_mob/shadekin/my_kin
/datum/modifier/shadekin/create_shade/tick()
var/datum/component/shadekin/SK = my_kin.get_shadekin_component()
if(SK && SK.in_phase)
expire()
/datum/modifier/shadekin/create_shade/on_applied()
my_kin = holder
holder.glow_toggle = TRUE
holder.glow_range = 8
holder.glow_intensity = -10
holder.glow_color = "#FFFFFF"
holder.set_light(8, -10, "#FFFFFF")
/datum/modifier/shadekin/create_shade/on_expire()
holder.glow_toggle = initial(holder.glow_toggle)
holder.glow_range = initial(holder.glow_range)
holder.glow_intensity = initial(holder.glow_intensity)
holder.glow_color = initial(holder.glow_color)
holder.set_light(0)
my_kin = null

View File

@@ -0,0 +1,207 @@
/datum/power/shadekin/dark_maw
name = "Dark Maw (20)"
desc = "Create a trap to capture others, or steal people from phase"
verbpath = /mob/living/proc/dark_maw
ability_icon_state = "dark_maw_ic"
/mob/living/proc/dark_maw()
set name = "Dark Maw (20)"
set desc = "Create a trap to capture others, or steal people from phase"
set category = "Abilities.Shadekin"
var/ability_cost = 20
var/datum/component/shadekin/SK = get_shadekin_component()
if(!SK)
return FALSE
if(SK.special_considerations())
return FALSE
if(stat)
to_chat(src, span_warning("Can't use that ability in your state!"))
return FALSE
if(SK.shadekin_get_energy() < ability_cost)
to_chat(src, span_warning("Not enough energy for that ability!"))
return FALSE
var/turf/T = get_turf(src)
if(!istype(T))
to_chat(src, span_warning("You don't seem to be able to set a trap here!"))
return FALSE
if(T.get_lumcount() >= 0.5)
to_chat(src, span_warning("There is too much light here for your trap to last!"))
return FALSE
if(do_after(src, 10))
if(SK.in_phase)
new /obj/effect/abstract/dark_maw(loc, src, TRUE)
else
new /obj/effect/abstract/dark_maw(loc, src)
SK.shadekin_adjust_energy(-ability_cost)
return TRUE
return FALSE
/mob/living/proc/clear_dark_maws()
set name = "Dispel dark maws"
set desc = "Dispel any active dark maws in place"
set category = "Abilities.Shadekin"
var/datum/component/shadekin/SK = get_shadekin_component()
if(!SK)
to_chat(src, span_warning("Only a shadekin can use that!"))
return FALSE
for(var/obj/effect/abstract/dark_maw/dm in SK.active_dark_maws)
dm.dispel()
/obj/effect/abstract/dark_maw
var/mob/living/owner = null
var/obj/belly/target = null
var/has_signal = FALSE
icon = 'icons/obj/Shadekin_powers.dmi'
icon_state = "dark_maw_waiting"
/obj/effect/abstract/dark_maw/Initialize(mapload, var/mob/user, var/trigger_now = FALSE)
. = ..()
if(!isturf(loc))
return INITIALIZE_HINT_QDEL
var/datum/component/shadekin/SK
if(user && isliving(user))
owner = user
if(owner.vore_selected)
target = owner.vore_selected
RegisterSignal(owner, COMSIG_PARENT_QDELETING, PROC_REF(drop_everything_and_delete))
has_signal = TRUE
SK = owner.get_shadekin_component()
var/turf/T = loc
if(T.get_lumcount() >= 0.5)
visible_message(span_notice("A set of shadowy lines flickers away in the light."))
icon_state = "dark_maw_used"
return INITIALIZE_HINT_QDEL
var/mob/living/target_user = null
for(var/mob/living/L in T)
if(L != owner && !L.is_incorporeal())
target_user = L
break
if(istype(target_user))
triggered_by(target_user, 1)
// to trigger rebuild
else if(trigger_now)
icon_state = "dark_maw_used"
flick("dark_maw_tr", src)
visible_message(span_warning("A set of crystals suddenly springs from the ground and shadowy tendrils wrap around nothing before vanishing."))
QDEL_IN(src, 3 SECONDS)
else
if(SK)
SK.active_dark_maws += src
flick("dark_maw", src)
START_PROCESSING(SSobj, src)
///Called when we get a signal that our owner is being qdel'd
/obj/effect/abstract/dark_maw/proc/drop_everything_and_delete()
SIGNAL_HANDLER
qdel(src)
/obj/effect/abstract/dark_maw/Destroy()
STOP_PROCESSING(SSobj, src)
if(owner)
if(has_signal)
UnregisterSignal(owner, COMSIG_PARENT_QDELETING)
var/datum/component/shadekin/SK = owner.get_shadekin_component()
if(SK)
SK.active_dark_maws -= src
owner = null
target = null
return ..()
/obj/effect/abstract/dark_maw/Crossed(O)
. = ..()
if(!isliving(O))
return
if(icon_state != "dark_maw_waiting")
return
var/mob/living/L = O
if(!L.is_incorporeal() && (!owner || L != owner))
triggered_by(L)
/obj/effect/abstract/dark_maw/process()
var/turf/T = get_turf(src)
if(!istype(T) || T.get_lumcount() >= 0.5)
dispel()
/obj/effect/abstract/dark_maw/proc/dispel()
if(icon_state == "dark_maw_waiting")
visible_message(span_notice("A set of shadowy lines flickers away in the light."))
else
visible_message(span_notice("The crystals and shadowy tendrils dissipate with the light shone on it."))
icon_state = "dark_maw_used"
qdel(src)
/obj/effect/abstract/dark_maw/proc/triggered_by(var/mob/living/L, var/triggered_instantly = 0)
STOP_PROCESSING(SSobj, src)
icon_state = "dark_maw_used"
flick("dark_maw_tr", src)
L.AdjustStunned(4)
visible_message(span_warning("A set of crystals spring out of the ground and shadowy tendrils start wrapping around [L]."))
if(owner && !triggered_instantly)
to_chat(owner, span_warning("A dark maw you deployed has triggered!"))
addtimer(CALLBACK(src, PROC_REF(do_trigger), L), 1 SECOND, TIMER_DELETE_ME)
/obj/effect/abstract/dark_maw/proc/do_trigger(var/mob/living/L)
var/will_vore = 1
if(!owner || !(target in owner) || !L.devourable || !L.can_be_drop_prey || !owner.can_be_drop_pred || !L.phase_vore)
will_vore = 0
if(!src || src.gc_destroyed)
//We got deleted probably, do nothing more
return
if(L.loc != get_turf(src))
visible_message(span_notice("The shadowy tendrils fail to catch anything and dissipate."))
qdel(src)
return
if(will_vore)
visible_message(span_warning("The shadowy tendrils grab around [L] and drag them into the floor, leaving nothing behind."))
L.forceMove(target)
qdel(src)
return
var/obj/effect/energy_net/dark/net = new /obj/effect/energy_net/dark(get_turf(src))
if(net.buckle_mob(L))
visible_message(span_warning("The shadowy tendrils wrap around [L] and traps them in a net of dark energy."))
else
visible_message(span_notice("The shadowy tendrils wrap around [L] and then dissipate, leaving them in place."))
qdel(src)
/obj/effect/energy_net/dark
name = "dark net"
desc = "It's a net made of dark energy."
icon = 'icons/obj/Shadekin_powers.dmi'
icon_state = "dark_net"
escape_time = 30 SECONDS
/obj/effect/energy_net/dark/user_unbuckle_mob(mob/living/buckled_mob, mob/user)
if(isliving(user))
var/mob/living/unbuckler = user
var/datum/component/shadekin/SK = unbuckler.get_shadekin_component()
if(SK)
visible_message(span_danger("[user] dissipates \the [src] with a touch!"))
unbuckle_mob(buckled_mob)
return
. = ..()
/obj/effect/energy_net/dark/process()
. = ..()
var/turf/T = get_turf(src)
if(!istype(T) || T.get_lumcount() >= 0.6)
visible_message(span_notice("The tangle of dark tendrils fades away in the light."))
qdel(src)

View File

@@ -0,0 +1,107 @@
//Non-Canon on Virgo. Used downstream.
/datum/power/shadekin/dark_respite
name = "Dark Respite (Only in Dark)"
desc = "Focus yourself on healing any injuries sustained."
verbpath = /mob/living/proc/dark_respite
ability_icon_state = "dark_respite"
/mob/living/proc/dark_respite()
set name = "Dark Respite (Only in Dark)"
set desc = "Focus yourself on healing any injuries sustained."
set category = "Abilities.Shadekin"
var/datum/component/shadekin/SK = get_shadekin_component()
if(!SK)
return FALSE
if(SK.special_considerations())
return FALSE
if(stat)
to_chat(src, span_warning("Can't use that ability in your state!"))
return FALSE
if(!istype(get_area(src), /area/shadekin))
to_chat(src, span_warning("Can only trigger Dark Respite in the Dark!"))
return FALSE
if(SK.in_dark_respite)
to_chat(src, span_warning("You can't use that so soon after an emergency warp!"))
return FALSE
if(has_modifier_of_type(/datum/modifier/dark_respite) && !SK.manual_respite)
to_chat(src, span_warning("You cannot manually end a Dark Respite triggered by an emergency warp!"))
if(SK.in_phase)
to_chat(src, span_warning("You can't use that while phase shifted!"))
return FALSE
if(has_modifier_of_type(/datum/modifier/dark_respite))
to_chat(src, span_notice("You stop focusing the Dark on healing yourself."))
SK.manual_respite = FALSE
remove_a_modifier_of_type(/datum/modifier/dark_respite)
return TRUE
to_chat(src, span_notice("You start focusing the Dark on healing yourself. (Leave the dark or trigger the ability again to end this.)"))
SK.manual_respite = TRUE
add_modifier(/datum/modifier/dark_respite)
return TRUE
/datum/modifier/dark_respite
name = "Dark Respite"
pain_immunity = 1
var/datum/component/shadekin/SK
// Override this for special effects when it gets added to the mob.
/datum/modifier/dark_respite/on_applied()
SK = holder.get_shadekin_component()
if(!SK)
expire()
return
/datum/modifier/dark_respite/tick()
if(!SK)
expire()
return
var/mob/living/carbon/human/H
if(istype(holder, /mob/living/carbon/human))
H = holder
if(H.nutrition)
H.add_chemical_effect(CE_BLOODRESTORE, 5)
if(istype(get_area(H), /area/shadekin))
pain_immunity = TRUE
//Very good healing, but only in the Dark.
holder.adjustFireLoss((-0.25))
holder.adjustBruteLoss((-0.25))
holder.adjustToxLoss((-0.25))
holder.heal_organ_damage(3, 0)
if(H)
H.add_chemical_effect(CE_ANTIBIOTIC, ANTIBIO_SUPER)
for(var/obj/item/organ/I in H.internal_organs)
if(I.robotic >= ORGAN_ROBOT)
continue
if(I.damage > 0)
I.damage = max(I.damage - 0.25, 0)
if(I.damage <= 5 && I.organ_tag == O_EYES)
H.sdisabilities &= ~BLIND
for(var/obj/item/organ/external/O in H.organs)
if(O.status & ORGAN_BROKEN)
O.mend_fracture() //Only works if the bone won't rebreak, as usual
for(var/datum/wound/W in O.wounds)
if(W.bleeding())
W.damage = max(W.damage - 3, 0)
if(W.damage <= 0)
O.wounds -= W
if(W.internal)
W.damage = max(W.damage - 3, 0)
if(W.damage <= 0)
O.wounds -= W
else
if(SK.manual_respite)
to_chat(holder, span_notice("As you leave the Dark, you stop focusing the Dark on healing yourself."))
SK.manual_respite = FALSE
expire()
if(pain_immunity)
pain_immunity = 0
/datum/modifier/dark_respite/on_expire()
SK = null

View File

@@ -1,11 +1,8 @@
// Kind of like a combination of all the teleporter stuff all in one package.
// And without the power requirements or accuracy loss,
// though it requires a shadekin to open the minion portals.
// Also yes this needs to be outside of modular chomp because there are variables that have to be map overriden.
GLOBAL_LIST_BOILERPLATE(all_darkportal_hubs, /obj/structure/dark_portal/hub)
GLOBAL_LIST_BOILERPLATE(all_darkportal_minions, /obj/structure/dark_portal/minion)
/obj/structure/dark_portal
name = "Dark portal"
icon = 'modular_chomp/icons/obj/shadekin_portal.dmi'
icon = 'icons/obj/shadekin_portal.dmi'
density = TRUE
anchored = TRUE
var/locked = null
@@ -16,51 +13,15 @@
/obj/structure/dark_portal/proc/close_portal()
return
/obj/structure/dark_portal/proc/is_shadekin(mob/shade_maybe)
if(istype(shade_maybe, /mob/living/simple_mob/shadekin))
return TRUE
else if(istype(shade_maybe, /mob/living/carbon/human))
var/mob/living/carbon/human/carbonkin_maybe = shade_maybe
if(carbonkin_maybe.get_species() == SPECIES_SHADEKIN)
return TRUE
return FALSE
/obj/structure/dark_portal/proc/get_ability_flags(mob/shade_maybe)
if(istype(shade_maybe, /mob/living/simple_mob/shadekin))
var/mob/living/simple_mob/shadekin/shadekin = shade_maybe
return shadekin.ability_flags
else if(istype(shade_maybe, /mob/living/carbon/human))
var/mob/living/carbon/human/carbonkin_maybe = shade_maybe
return carbonkin_maybe.ability_flags
return 0
/obj/structure/dark_portal/proc/get_shadekin_energy(mob/shade_maybe)
if(istype(shade_maybe, /mob/living/simple_mob/shadekin))
var/mob/living/simple_mob/shadekin/shadekin = shade_maybe
return shadekin.comp.dark_energy
else if(istype(shade_maybe, /mob/living/carbon/human))
var/mob/living/carbon/human/carbonkin_maybe = shade_maybe
return carbonkin_maybe.shadekin_get_energy()
return 0
/obj/structure/dark_portal/proc/adjust_shadekin_energy(mob/shade_maybe, amount)
if(istype(shade_maybe, /mob/living/simple_mob/shadekin))
var/mob/living/simple_mob/shadekin/shadekin = shade_maybe
shadekin.comp.dark_energy += amount
return
else if(istype(shade_maybe, /mob/living/carbon/human))
var/mob/living/carbon/human/carbonkin_maybe = shade_maybe
return carbonkin_maybe.shadekin_adjust_energy(amount)
return 0
/obj/structure/dark_portal/proc/teleport(atom/movable/M as mob|obj)
if(!locked)
return
if(is_shadekin(M))
if(get_ability_flags(M) & AB_DARK_RESPITE)
if(isliving(M))
var/mob/living/to_check = M
var/datum/component/shadekin/SK = to_check.GetComponent(/datum/component/shadekin)
if(SK && SK.in_dark_respite)
to_chat(M, span_warning("You can't go through this portal so soon after an emergency warp!"))
var/mob/living/user = M
user.Stun(10)
to_check.Stun(10)
return
do_teleport(M, locked, precision, local = FALSE, bohsafe = TRUE)
@@ -77,8 +38,6 @@
var/list/destination_station_areas // Override this in map files!
var/list/destination_wilderness_areas // Override this in map files!
GLOBAL_LIST_BOILERPLATE(all_darkportal_hubs, /obj/structure/dark_portal/hub)
/obj/structure/dark_portal/hub/Initialize(mapload)
. = ..()
locked = src
@@ -93,12 +52,15 @@ GLOBAL_LIST_BOILERPLATE(all_darkportal_hubs, /obj/structure/dark_portal/hub)
locked_name = src.name
precision = 1
/obj/structure/dark_portal/hub/attack_hand(mob/user)
if(is_shadekin(user))
if(get_ability_flags(user) & AB_DARK_RESPITE)
/obj/structure/dark_portal/hub/attack_hand(mob/living/user)
if(!isliving(user))
return
var/datum/component/shadekin/SK = user.GetComponent(/datum/component/shadekin)
if(SK)
if(SK.in_dark_respite)
to_chat(user, span_warning("You can't use this so soon after an emergency warp!"))
return
if(get_ability_flags(user) & AB_PHASE_SHIFTED)
if(SK.in_phase)
to_chat(user, span_warning("You can't use this while phase shifted!"))
return
if(locked != src)
@@ -172,20 +134,21 @@ GLOBAL_LIST_BOILERPLATE(all_darkportal_hubs, /obj/structure/dark_portal/hub)
/obj/structure/dark_portal/minion
icon_state = "minion0"
GLOBAL_LIST_BOILERPLATE(all_darkportal_minions, /obj/structure/dark_portal/minion)
/obj/structure/dark_portal/minion/close_portal()
locked = null
locked_name = ""
precision = 1
icon_state = "minion0"
/obj/structure/dark_portal/minion/attack_hand(mob/user)
if(is_shadekin(user))
if(get_ability_flags(user) & AB_DARK_RESPITE)
/obj/structure/dark_portal/minion/attack_hand(mob/living/user)
if(!isliving(user))
return
var/datum/component/shadekin/SK = user.GetComponent(/datum/component/shadekin)
if(SK)
if(SK.in_dark_respite)
to_chat(user, span_warning("You can't use this so soon after an emergency warp!"))
return FALSE
if(get_ability_flags(user) & AB_PHASE_SHIFTED)
if(SK.in_phase)
to_chat(user, span_warning("You can't use this while phase shifted!"))
return FALSE
if(icon_state == "minion1")
@@ -195,21 +158,19 @@ GLOBAL_LIST_BOILERPLATE(all_darkportal_minions, /obj/structure/dark_portal/minio
if(confirm == "Yes")
close_portal()
return
if(get_shadekin_energy(user) < 10)
if(SK.shadekin_get_energy() < 10)
to_chat(user, span_warning("Not enough energy to open up the portal! (10 required)"))
return
if(!LAZYLEN(GLOB.all_darkportal_hubs))
to_chat(user, span_warning("No hub portals exist!"))
return
if(LAZYLEN(GLOB.all_darkportal_hubs) == 1)
adjust_shadekin_energy(user, -10)
SK.shadekin_adjust_energy(user, -10)
var/obj/structure/dark_portal/target = GLOB.all_darkportal_hubs[1]
locked = target
locked_name = target.name
icon_state = "minion1"
spawn(3000)
if(locked == target)
close_portal()
addtimer(CALLBACK(src, PROC_REF(check_to_close),target), 5 MINUTES, TIMER_DELETE_ME)
return
var/list/L = list()
for(var/obj/structure/dark_portal/hub/H in GLOB.all_darkportal_hubs)
@@ -220,9 +181,8 @@ GLOBAL_LIST_BOILERPLATE(all_darkportal_minions, /obj/structure/dark_portal/minio
locked = L[desc]
locked_name = desc
icon_state = "minion1"
spawn(3000)
if(locked == L[desc])
close_portal()
addtimer(CALLBACK(src, PROC_REF(check_to_close_desc),locked), 5 MINUTES, TIMER_DELETE_ME)
return
else if(!istype(user, /mob/living))
return
else if(icon_state == "minion0")
@@ -230,6 +190,14 @@ GLOBAL_LIST_BOILERPLATE(all_darkportal_minions, /obj/structure/dark_portal/minio
else
to_chat(user, span_notice("You touch the portal, your hand able to pass through without harm."))
/obj/structure/dark_portal/proc/check_to_close(var/obj/structure/dark_portal/target)
if(locked == target)
close_portal()
/obj/structure/dark_portal/proc/check_to_close_desc(var/old_locked)
if(locked == old_locked)
close_portal()
/obj/structure/dark_portal/minion/Bumped(M as mob|obj)
spawn()
if(icon_state == "minion1")

View File

@@ -0,0 +1,93 @@
//Non-Canon on Virgo. Used downstream.
/datum/power/shadekin/dark_tunneling
name = "Dark Tunneling (100) (Once)"
desc = "Make a passage to the dark."
verbpath = /mob/living/proc/dark_tunneling
ability_icon_state = "minion0"
/mob/living/proc/dark_tunneling()
set name = "Dark Tunneling (100) (Once)"
set desc = "Make a passage to the dark."
set category = "Abilities.Shadekin"
var/template_id = "dark_portal"
var/datum/map_template/shelter/template
var/ability_cost = 100
var/tunnel_time = 60 SECONDS
var/datum/component/shadekin/SK = get_shadekin_component()
if(!SK)
return FALSE
if(SK.special_considerations())
return FALSE
if(stat)
to_chat(src, span_warning("Can't use that ability in your state!"))
return FALSE
if(SK.in_phase)
to_chat(src, span_warning("You can't use that while phase shifted!"))
return FALSE
if(SK.created_dark_tunnel)
to_chat(src, span_warning("You have already made a tunnel to the Dark!"))
return FALSE
if(!template)
template = SSmapping.shelter_templates[template_id]
if(!template)
throw EXCEPTION("Shelter template ([template_id]) not found!")
return FALSE
var/turf/deploy_location = get_turf(src)
var/status = template.check_deploy(deploy_location)
switch(status)
//Not allowed due to /area technical reasons
if(SHELTER_DEPLOY_BAD_AREA)
to_chat(src, span_warning("A tunnel to the Dark will not function in this area."))
//Anchored objects or no space
if(SHELTER_DEPLOY_BAD_TURFS, SHELTER_DEPLOY_ANCHORED_OBJECTS)
var/width = template.width
var/height = template.height
to_chat(src, span_warning("There is not enough open area for a tunnel to the Dark to form! You need to clear a [width]x[height] area!"))
if(status != SHELTER_DEPLOY_ALLOWED)
return FALSE
var/turf/T = deploy_location
var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread()
smoke.attach(T)
smoke.set_up(10, 0, T)
smoke.start()
src.visible_message(span_notice("[src] begins pulling dark energies around themselves."))
if(do_after(src, tunnel_time))
if(SK.created_dark_tunnel) //check again because the user may have queued this up multiple times.
to_chat(src, span_warning("You have already made a tunnel to the Dark!"))
return FALSE
playsound(src, 'sound/effects/phasein.ogg', 100, 1)
src.visible_message(span_notice("[src] finishes pulling dark energies around themselves, creating a portal."))
log_and_message_admins("[key_name_admin(src)] created a tunnel to the dark at [get_area(T)]!")
template.annihilate_plants(deploy_location)
template.load(deploy_location, centered = TRUE)
template.update_lighting(deploy_location)
SK.created_dark_tunnel = TRUE
SK.shadekin_adjust_energy(-(ability_cost - 10)) //Leaving enough energy to actually activate the portal
return TRUE
return FALSE
/datum/map_template/shelter/dark_portal
name = "Dark Portal"
shelter_id = "dark_portal"
description = "A portal to a section of the Dark"
mappath = "maps/submaps/shelters/dark_portal.dmm"
/datum/map_template/shelter/dark_portal/New()
. = ..()
blacklisted_turfs = typecacheof(list(/turf/unsimulated))
GLOB.blacklisted_areas = typecacheof(list(/area/centcom, /area/shadekin))

View File

@@ -27,6 +27,8 @@
var/datum/component/shadekin/SK = get_shadekin_component()
if(!SK)
return FALSE
if(SK.special_considerations())
return FALSE
if(stat)
to_chat(src, span_warning("Can't use that ability in your state!"))
return FALSE
@@ -50,10 +52,24 @@
darkness = 1-brightness //Invert
var/watcher = 0
for(var/mob/living/carbon/human/watchers in oview(7,src )) // If we can see them...
if(watchers in oviewers(7,src)) // And they can see us...
if(!(watchers.stat) && !isbelly(watchers.loc) && !istype(watchers.loc, /obj/item/holder)) // And they are alive and not being held by someone...
for(var/mob/living/thing in orange(7, src)) //Fun fact, doing two typed loops is faster than doing one untyped loop. Check it with Tracy!
if(istype(thing, /mob/living/carbon/human))
var/mob/living/carbon/human/watchers = thing
if(watchers in oviewers(7,src))
var/datum/component/shadekin/watcher_SK = watchers.get_shadekin_component()
if(!watcher_SK && !(watchers.stat) && !isbelly(watchers.loc) && !istype(watchers.loc, /obj/item/holder)) // And they are alive and not being held by someone...
watcher++ //They are watching us!
if(istype(thing, /mob/living/silicon/robot))
var/mob/living/silicon/robot/watchers = thing
var/datum/component/shadekin/watcher_SK = watchers.get_shadekin_component() //you never know, man.
if(watchers in oviewers(7,src))
if(!watcher_SK && !watchers.stat && !isbelly(watchers.loc))
watcher++ //The robot is watching us!
if(SK.camera_counts_as_watcher)
for(var/obj/machinery/camera/watchers in orange(7, src))
if(watchers.can_use())
if(src in watchers.can_see())
watcher++ //The camera is watching us!
ability_cost = CLAMP(ability_cost/(0.01+darkness*2),50, 80)//This allows for 1 watcher in full light
if(watcher>0)
@@ -163,6 +179,8 @@
held_lights.update_brightness()
SK.doing_phase = FALSE
if(SK.flicker_time < 5 || SK.flicker_distance < 5 || SK.flicker_break_chance < 5)
Stun(SK.calculate_stun())
if(!SK.flicker_time)
return //Early return. No time, no flickering.
//Affect nearby lights

View File

@@ -0,0 +1,68 @@
//////////////////////////
/// REGENERATE OTHER ///
//////////////////////////
/datum/power/shadekin/regenerate_other
name = "Regenerate Other (50)"
desc = "Spend energy to heal physical wounds in another creature."
verbpath = /mob/living/proc/regenerate_other
ability_icon_state = "shadekin_regen"
/mob/living/proc/regenerate_other()
set name = "Regenerate Other (50)"
set desc = "Spend energy to heal physical wounds in another creature."
set category = "Abilities.Shadekin"
var/ability_cost = 50
var/datum/component/shadekin/SK = get_shadekin_component()
if(!SK)
return FALSE
if(SK.special_considerations())
return FALSE
if(stat)
to_chat(src, span_warning("Can't use that ability in your state!"))
return FALSE
else if(SK.shadekin_get_energy() < ability_cost)
to_chat(src, span_warning("Not enough energy for that ability!"))
return FALSE
else if(SK.in_phase)
to_chat(src, span_warning("You can't use that while phase shifted!"))
return FALSE
var/list/viewed = oview(1)
var/list/targets = list()
for(var/mob/living/L in viewed)
targets += L
if(!targets.len)
to_chat(src,span_warning("Nobody nearby to mend!"))
return FALSE
var/mob/living/target = tgui_input_list(src,"Pick someone to mend:","Mend Other", targets)
if(!target)
return FALSE
target.add_modifier(/datum/modifier/shadekin/heal_boop,1 MINUTE)
playsound(src, 'sound/effects/EMPulse.ogg', 75, 1)
SK.shadekin_adjust_energy(-ability_cost)
visible_message(span_notice("\The [src] gently places a hand on \the [target]..."))
face_atom(target)
return TRUE
/datum/modifier/shadekin/heal_boop
name = "Shadekin Regen"
desc = "You feel serene and well rested."
mob_overlay_state = "green_sparkles"
on_created_text = span_notice("Sparkles begin to appear around you, and all your ills seem to fade away.")
on_expired_text = span_notice("The sparkles have faded, although you feel much healthier than before.")
stacks = MODIFIER_STACK_EXTEND
/datum/modifier/shadekin/heal_boop/tick()
if(!holder.getBruteLoss() && !holder.getFireLoss() && !holder.getToxLoss() && !holder.getOxyLoss() && !holder.getCloneLoss()) // No point existing if the spell can't heal.
expire()
return
holder.adjustBruteLoss(-2)
holder.adjustFireLoss(-2)
holder.adjustToxLoss(-2)
holder.adjustOxyLoss(-2)
holder.adjustCloneLoss(-2)

View File

@@ -0,0 +1,281 @@
//See comp_helpers.dm for helper procs.
/datum/component/shadekin
VAR_PRIVATE/mob/living/owner
dupe_mode = COMPONENT_DUPE_UNIQUE
//Energy Vars
///How much energy we have RIGHT NOW
var/dark_energy = 100
///How much energy we can have
var/max_dark_energy = 100
///Always be at our max_dark_energy
var/dark_energy_infinite = FALSE
///How much energy we generate in the dark
var/energy_dark = 0.75
///How much energy we generate in the light
var/energy_light = 0.25
///If we care about eye color when it comes to factoring in energy
var/eye_color_influences_energy = TRUE
///Energy gain from nutrition
var/nutrition_conversion_scaling = 0.5
///If we convert nutrition to energy
var/nutrition_energy_conversion = FALSE
//Phase Vars
///Are we currently in a phase transition?
var/doing_phase = FALSE
///Are we currently phased?
var/in_phase = FALSE
///Chance to break lights on phase-in
var/flicker_break_chance = 0
///Color that lights will flicker to on phase-in. Off by default.
var/flicker_color
///Time that lights will flicker on phase-in. Default is 10 times.
var/flicker_time = 10
///Range that we flicker lights. Default is 10.
var/flicker_distance = 10
///If we can get the 'phase debuff' applied to us. (No using guns, dropping things in hands, etc).
var/normal_phase = TRUE
///If we drop items on phase.
var/drop_items_on_phase = FALSE
///If cameras count as watchers for us
var/camera_counts_as_watcher = FALSE
//Dark Respite Vars (Unused on Virgo)
///If we are in dark respite or not
var/in_dark_respite = FALSE
var/manual_respite = FALSE
var/respite_activating = FALSE
//Dark Tunneling Vars (Unused on Virgo)
///If we have already made a dark tunnel
var/created_dark_tunnel = FALSE
//Dark Maw Vars (Unused on Virgo)
///Our current active dark maws
var/list/active_dark_maws = list()
//Ability Vars
///The innate abilities we start with
var/list/shadekin_abilities = list(/datum/power/shadekin/phase_shift,
/datum/power/shadekin/regenerate_other,
/datum/power/shadekin/create_shade)
///Datum holder. Largely ignore this.
var/list/shadekin_ability_datums = list()
//Misc Vars
///Eyecolor
var/eye_color = BLUE_EYES
///For downstream. Enables some extra verbs. Causes things to drop in hand when you phase.
var/extended_kin = FALSE
/datum/component/shadekin/phase_only
shadekin_abilities = list(/datum/power/shadekin/phase_shift)
/datum/component/shadekin/full
shadekin_abilities = list(/datum/power/shadekin/phase_shift,
/datum/power/shadekin/regenerate_other,
/datum/power/shadekin/create_shade,
/datum/power/shadekin/dark_maw,
/datum/power/shadekin/dark_respite,
/datum/power/shadekin/dark_tunneling)
extended_kin = TRUE
drop_items_on_phase = TRUE
camera_counts_as_watcher = TRUE
/datum/component/shadekin/full/rakshasa
flicker_time = 0 //Rakshasa don't flicker lights when they phase in.
dark_energy_infinite = TRUE
normal_phase = FALSE
/datum/component/shadekin/Initialize()
//normal component bs
if(!isliving(parent))
return COMPONENT_INCOMPATIBLE
owner = parent
add_shadekin_abilities(owner)
if(ishuman(owner))
RegisterSignal(owner, COMSIG_SHADEKIN_COMPONENT, PROC_REF(handle_comp)) //Happens every species tick.
else
RegisterSignal(owner, COMSIG_LIVING_LIFE, PROC_REF(handle_comp)) //Happens every life tick (mobs)
//generates powers and then adds them
for(var/power in shadekin_abilities)
var/datum/power/shadekin/SKP = new power(src)
shadekin_ability_datums.Add(SKP)
add_shadekin_abilities()
handle_comp() //First hit is free!
//decides what 'eye color' we are and how much energy we should get
set_shadekin_eyecolor() //Gets what eye color we are.
set_eye_energy() //Sets the energy values based on our eye color.
//Misc stuff we need to do
if(extended_kin)
add_verb(owner, /mob/living/proc/nutrition_conversion_toggle)
add_verb(owner, /mob/living/proc/flicker_adjustment)
/datum/component/shadekin/Destroy(force)
if(ishuman(owner))
UnregisterSignal(owner, COMSIG_SHADEKIN_COMPONENT)
else
UnregisterSignal(owner, COMSIG_LIVING_LIFE)
if(extended_kin)
remove_verb(owner, /mob/living/proc/nutrition_conversion_toggle)
remove_verb(owner, /mob/living/proc/flicker_adjustment)
for(var/datum/power in shadekin_ability_datums)
qdel(power)
for(var/obj/effect/abstract/dark_maw/dm as anything in active_dark_maws) //if the component gets destroyed so does your precious maws
if(!QDELETED(dm))
qdel(dm)
active_dark_maws.Cut()
shadekin_abilities.Cut()
shadekin_ability_datums.Cut()
owner = null
. = ..()
/datum/component/shadekin/proc/recalc_values()
set_shadekin_eyecolor() //Gets what eye color we are.
set_eye_energy() //Sets the energy values based on our eye color.
///Handles the component running.
/datum/component/shadekin/proc/handle_comp()
SIGNAL_HANDLER
if(QDELETED(parent))
return
if(owner.stat == DEAD) //dead, don't process.
return
handle_shade()
///Handles the shadekin's energy gain and loss.
/datum/component/shadekin/proc/handle_shade()
//Shifted kin don't gain/lose energy (and save time if we're at the cap)
var/darkness = 1
var/dark_gains = 0
var/turf/T = get_turf(owner)
if(!T)
dark_gains = 0
return
var/brightness = T.get_lumcount() //Brightness in 0.0 to 1.0
darkness = 1-brightness //Invert
var/is_dark = (darkness >= 0.5)
if(in_phase)
dark_gains = 0
else
//Heal (very) slowly in good darkness
if(is_dark)
//The below sends a DB query...This needs to be fixed before this can be enabled as we're now dealing with signal handlers.
//Reenable once that mess is taken care of.
owner.adjustFireLoss((-0.10)*darkness)
owner.adjustBruteLoss((-0.10)*darkness)
owner.adjustToxLoss((-0.10)*darkness)
//energy_dark and energy_light are set by the shadekin eye traits.
//These are balanced around their playstyles and 2 planned new aggressive abilities
dark_gains = energy_dark
else
dark_gains = energy_light
handle_nutrition_conversion(dark_gains)
shadekin_adjust_energy(dark_gains)
//Update huds
update_shadekin_hud()
/datum/component/shadekin/proc/calculate_stun()
var/stun_time = 3
if(flicker_time > 0)
stun_time -= min(flicker_time / 5, 1)
if(flicker_distance > 0)
stun_time -= min(flicker_distance / 5, 1)
if(flicker_break_chance > 0)
stun_time -= min(flicker_break_chance / 5, 1)
return stun_time
/datum/component/shadekin/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ShadekinConfig", "Shadekin Config")
ui.open()
/datum/component/shadekin/tgui_data(mob/user)
var/data = list(
"stun_time" = calculate_stun(),
"flicker_time" = flicker_time,
"flicker_color" = flicker_color,
"flicker_break_chance" = flicker_break_chance,
"flicker_distance" = flicker_distance,
)
return data
/datum/component/shadekin/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
return TRUE
switch(action)
if("adjust_time")
var/new_time = text2num(params["val"])
new_time = CLAMP(new_time, 2, 20)
if(!isnum(new_time))
return FALSE
flicker_time = new_time
ui.user.write_preference_directly(/datum/preference/numeric/living/flicker_time, new_time)
return TRUE
if("adjust_color")
var/set_new_color = tgui_color_picker(ui.user, "Select a color you wish the lights to flicker as (Default is #E0EFF0)", "Color Selector", flicker_color)
if(!set_new_color)
return FALSE
flicker_color = set_new_color
ui.user.write_preference_directly(/datum/preference/color/living/flicker_color, set_new_color)
return TRUE
if("adjust_break")
var/new_break_chance = text2num(params["val"])
new_break_chance = CLAMP(new_break_chance, 0, 25)
if(!isnum(new_break_chance))
return FALSE
flicker_break_chance = new_break_chance
ui.user.write_preference_directly(/datum/preference/numeric/living/flicker_break_chance, new_break_chance)
return TRUE
if("adjust_distance")
var/new_distance = text2num(params["val"])
new_distance = CLAMP(new_distance, 4, 10)
if(!isnum(new_distance))
return FALSE
flicker_distance = new_distance
ui.user.write_preference_directly(/datum/preference/numeric/living/flicker_distance, new_distance)
return TRUE
/mob/living/proc/nutrition_conversion_toggle()
set name = "Toggle Energy <-> Nutrition conversions"
set desc = "Toggle dark energy and nutrition being converted into each other when full"
set category = "Abilities.Shadekin"
var/datum/component/shadekin/SK = get_shadekin_component()
if(!SK)
to_chat(src, span_warning("Only a shadekin can use that!"))
return FALSE
if(SK.nutrition_energy_conversion)
to_chat(src, span_notice("Nutrition and dark energy conversions disabled."))
SK.nutrition_energy_conversion = 0
else
to_chat(src, span_notice("Nutrition and dark energy conversions enabled."))
SK.nutrition_energy_conversion = 1
/mob/living/proc/flicker_adjustment()
set name = "Adjust Light Flicker"
set desc = "Allows you to adjust the settings of the light flicker when you phase in!"
set category = "Abilities.Shadekin"
var/datum/component/shadekin/SK = get_shadekin_component()
if(!SK)
to_chat(src, span_warning("Only a shadekin can use that!"))
return FALSE
SK.tgui_interact(src)

View File

@@ -6,7 +6,7 @@ var/bluespace_item_types = newlist(/obj/item/storage/backpack/holding,
)
//wrapper
/proc/do_teleport(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null, local=TRUE, bohsafe=FALSE) //CHOMPStation Edit
/proc/do_teleport(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null, local=TRUE, bohsafe=FALSE)
new /datum/teleport/instant/science(arglist(args))
return
@@ -19,17 +19,17 @@ var/bluespace_item_types = newlist(/obj/item/storage/backpack/holding,
var/soundin //soundfile to play before teleportation
var/soundout //soundfile to play after teleportation
var/force_teleport = 1 //if false, teleport will use Move() proc (dense objects will prevent teleportation)
var/local = TRUE //VOREStation Add - If false, can teleport from/to any z-level
var/bohsafe = FALSE //CHOMP Add - if true, can teleport safely with a BoH
var/local = TRUE //If false, can teleport from/to any z-level
var/bohsafe = FALSE //If true, can teleport safely with a BoH
/datum/teleport/New(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null, local=TRUE, bohsafe=FALSE) //CHOMPStation Edit
/datum/teleport/New(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null, local=TRUE, bohsafe=FALSE)
..()
if(!initTeleport(arglist(args)))
return 0
return 1
/datum/teleport/proc/initTeleport(ateleatom,adestination,aprecision,afteleport,aeffectin,aeffectout,asoundin,asoundout,local,bohsafe) //CHOMPStation Edit
/datum/teleport/proc/initTeleport(ateleatom,adestination,aprecision,afteleport,aeffectin,aeffectout,asoundin,asoundout,local,bohsafe)
if(!setTeleatom(ateleatom))
return 0
if(!setDestination(adestination))
@@ -40,7 +40,7 @@ var/bluespace_item_types = newlist(/obj/item/storage/backpack/holding,
setEffects(aeffectin,aeffectout)
setForceTeleport(afteleport)
setSounds(asoundin,asoundout)
src.local = local // VOREStation Add
src.local = local
return 1
//must succeed
@@ -123,7 +123,7 @@ var/bluespace_item_types = newlist(/obj/item/storage/backpack/holding,
var/mob/living/L = teleatom
if(L.buckled)
C = L.buckled
if(attempt_vr(src,"try_televore",args)) return //VOREStation Edit - Telenoms.
if(attempt_vr(src,"try_televore",args)) return
if(force_teleport)
teleatom.forceMove(destturf)
playSpecials(destturf,effectout,soundout)
@@ -142,7 +142,7 @@ var/bluespace_item_types = newlist(/obj/item/storage/backpack/holding,
/datum/teleport/instant //teleports when datum is created
/datum/teleport/instant/New(ateleatom, adestination, aprecision=0, afteleport=1, bohsafe=0, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null) //CHOMP edit
/datum/teleport/instant/New(ateleatom, adestination, aprecision=0, afteleport=1, bohsafe=0, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null)
if(..())
teleport()
return
@@ -152,20 +152,18 @@ var/bluespace_item_types = newlist(/obj/item/storage/backpack/holding,
if(!aeffectin || !aeffectout)
var/datum/effect/effect/system/spark_spread/aeffect = new
aeffect.set_up(5, 1, teleatom)
//CHOMP add start
var/datum/effect/effect/system/spark_spread/aeffect2 = new
aeffect2.set_up(5, 1, teleatom) //This looks stupid, but it doesn't work unless I do
//CHOMP add end
aeffect2.set_up(5, 1, teleatom)
effectin = effectin || aeffect
effectout = effectout || aeffect2 //CHOMP edit
effectout = effectout || aeffect2
return 1
else
return ..()
/datum/teleport/instant/science/setPrecision(aprecision)
..()
if(bohsafe) //CHOMPedit
return 1 //CHOMPedit
if(bohsafe)
return 1
var/list/bluespace_things = newlist()
@@ -174,14 +172,12 @@ var/bluespace_item_types = newlist(/obj/item/storage/backpack/holding,
precision = rand(1, 100)
bluespace_things |= teleatom.search_contents_for(item)
//VOREStation Addition Start: Prevent taurriding abuse
if(isliving(teleatom))
var/mob/living/L = teleatom
if(LAZYLEN(L.buckled_mobs))
for(var/mob/rider in L.buckled_mobs)
for (var/item in bluespace_item_types)
bluespace_things |= rider.search_contents_for(item)
//VOREStation Addition End: Prevent taurriding abuse
if(bluespace_things.len)
precision = max(rand(1,100)*bluespace_things.len,100)
@@ -202,17 +198,6 @@ var/bluespace_item_types = newlist(/obj/item/storage/backpack/holding,
else
teleatom.visible_message(span_danger("\The [teleatom] bounces off of the portal!"))
return 0
/* VOREStation Removal
if(destination.z in using_map.admin_levels) //CentCom z-level
if(istype(teleatom, /obj/mecha))
var/obj/mecha/MM = teleatom
to_chat(MM.occupant, span_danger("\The [MM] would not survive the jump to a location so far away!"))
return 0
if(!isemptylist(teleatom.search_contents_for(/obj/item/storage/backpack/holding)))
teleatom.visible_message(span_danger("\The [teleatom] bounces off of the portal!"))
return 0
*/ //VOREStation Removal End
//VOREStation Edit Start
var/obstructed = 0
var/turf/dest_turf = get_turf(destination)
if(local && !(dest_turf.z in using_map.player_levels))
@@ -239,4 +224,3 @@ var/bluespace_item_types = newlist(/obj/item/storage/backpack/holding,
return 0
else
return 1
//VOREStation Edit End

View File

@@ -2693,6 +2693,12 @@ var/list/the_station_areas = list (
dynamic_lighting = 0
requires_power = 0
/area/shadekin
name = "\improper Shadekin Retreat"
icon_state = "blue"
requires_power = 0
ambience = AMBIENCE_OTHERWORLDLY
flags = RAD_SHIELDED | AREA_FLAG_IS_NOT_PERSISTENT | BLUE_SHIELDED | AREA_ALLOW_LARGE_SIZE | AREA_LIMIT_DARK_RESPITE | AREA_ALLOW_CLOCKOUT
//CHOMPSTATION AREAS
//Moved hangars to here from Southern cross areas.

View File

@@ -73,13 +73,6 @@
name = "\improper Particle Accelerator Lab"
icon_state = "toxlab"
/area/shadekin
name = "\improper Shadekin Retreat"
icon_state = "blue"
requires_power = 0
ambience = AMBIENCE_OTHERWORLDLY
flags = RAD_SHIELDED | AREA_FLAG_IS_NOT_PERSISTENT | BLUE_SHIELDED | AREA_ALLOW_LARGE_SIZE | AREA_LIMIT_DARK_RESPITE | AREA_ALLOW_CLOCKOUT
/area/security/nuke_storage
flags = PHASE_SHIELDED

View File

@@ -563,23 +563,16 @@ GLOBAL_DATUM(spoiler_obfuscation_image, /image)
return (flags & flag) == flag
return flags & flag
// RS Port #658 Start
/area/proc/check_phase_shift(var/mob/ourmob)
/area/proc/check_phase_shift(var/mob/living/ourmob)
if(!flag_check(AREA_BLOCK_PHASE_SHIFT) || !ourmob.is_incorporeal())
return
if(!isliving(ourmob))
return
if(check_rights_for(ourmob.client, R_HOLDER))
if(check_rights_for(ourmob.client, R_HOLDER)) //If we're an admin, we don't get affected by phase blockers.
return
if(issimplekin(ourmob))
var/mob/living/simple_mob/shadekin/SK = ourmob
if(SK.ability_flags & AB_PHASE_SHIFTED)
SK.phase_in(SK.loc)
if(ishuman(ourmob))
var/mob/living/carbon/human/SK = ourmob
if(SK.ability_flags & AB_PHASE_SHIFTED)
SK.phase_in(SK.loc)
// RS Port #658 End
var/datum/component/shadekin/SK = ourmob.get_shadekin_component()
if(SK && SK.in_phase)
SK.attack_dephase(ourmob.loc, src)
/area/proc/isAlwaysIndoors()
return FALSE

View File

@@ -1015,6 +1015,8 @@ About the new airlock wires panel:
/obj/machinery/door/airlock/CtrlClick(mob/user) //Hold door open
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if(user.is_incorporeal())
return
if(!Adjacent(user))
return
if(user.a_intent == I_HURT)

View File

@@ -25,9 +25,11 @@ GLOBAL_LIST_BOILERPLATE(all_portals, /obj/effect/portal)
if(AM.is_incorporeal())
if(!event)
return
if(iscarbon(AM))
var/mob/living/carbon/human/H = AM
H.attack_dephase(null, src)
if(isliving(AM))
var/mob/living/L = AM
var/datum/component/shadekin/SK = L.get_shadekin_component()
if(SK)
SK.attack_dephase(null, src)
if(ismob(AM) && !(isliving(AM)))
return //do not send ghosts, zshadows, ai eyes, etc
spawn(0)

View File

@@ -33,6 +33,7 @@
var/cell_type = /obj/item/cell/device
var/power_usage = 1
var/power_use = 1
var/flickering = FALSE
pickup_sound = 'sound/items/pickup/device.ogg'
drop_sound = 'sound/items/drop/device.ogg'
@@ -88,6 +89,9 @@
. += "It appears to have a high amount of power remaining."
/obj/item/flashlight/attack_self(mob/user)
if(flickering)
to_chat(user, "The light is currently malfunctioning and you're unable to adjust it!") //To prevent some lighting anomalities.
return
if(power_use)
if(!isturf(user.loc))
to_chat(user, "You cannot turn the light on while in this [user.loc].") //To prevent some lighting anomalities.
@@ -240,6 +244,48 @@
var/turf/T = get_turf(target)
OL.place_directional_light(T)
/obj/item/flashlight/proc/flicker(var/amount = rand(10, 20), var/flicker_color, var/forced)
if(flickering)
return
if(!flicker_color)
flicker_color = light_color //If we don't have a flicker color, use our current light color.
if((!power_use && !forced) || (!power_usage && !forced))
return //We don't use power / have no power, so we're probably a flare or dead.
flickering = TRUE
var/original_color = light_color
var/original_on = on
var/datum/component/overlay_lighting/OL = GetComponent(/datum/component/overlay_lighting) //BEWARE, ESOTERIC BULLSHIT HERE.
if(flicker_color && light_color != flicker_color)
set_light_color(flicker_color)
OL.directional_atom.color = flicker_color
do_flicker(amount, flicker_color, original_color, original_on, OL, 1)
/// Args:
/// amount is how many timer to flicker.
/// flicker_color is what to set the flashlight to when we flicker.
/// original_color is what our original color was prior to flickering
/// original_on is if we were originally on or not.
/// OL is our overlay for lighting.
/// ticker is how many times we have flickered so far.
/obj/item/flashlight/proc/do_flicker(var/amount = rand(10, 20), var/flicker_color, var/original_color, var/original_on, var/datum/component/overlay_lighting/OL, var/ticker)
if(ticker >= amount) //We have flickered enough times. Terminate the cycle.
finish_flicker(original_color, original_on, OL)
return
on = !on
update_brightness()
if(!on) // Only play when the light turns off.
playsound(src, 'sound/effects/light_flicker.ogg', 50, 1)
addtimer(CALLBACK(src, PROC_REF(do_flicker), amount, flicker_color, original_color, original_on, OL, ++ticker), rand(5,15), TIMER_DELETE_ME)
/obj/item/flashlight/proc/finish_flicker(var/original_color, var/original_on, var/datum/component/overlay_lighting/OL)
set_light_color(original_color)
OL.directional_atom.color = original_color
on = original_on
flickering = FALSE
update_brightness()
/obj/item/flashlight/pen
name = "penlight"
desc = "A pen-sized light, used by medical staff."

View File

@@ -0,0 +1,61 @@
/datum/preference/color/living/flicker_color
category = PREFERENCE_CATEGORY_MANUALLY_RENDERED
savefile_identifier = PREFERENCE_CHARACTER
savefile_key = "flicker_color"
can_randomize = FALSE
/datum/preference/color/living/flicker_color/create_default_value()
return "#E0EFF0"
/datum/preference/color/living/flicker_color/apply_to_living(mob/living/target, value)
var/datum/component/shadekin/our_SK = target.get_shadekin_component()
if(our_SK)
our_SK.flicker_color = value
/datum/preference/numeric/living/flicker_time
category = PREFERENCE_CATEGORY_MANUALLY_RENDERED
savefile_identifier = PREFERENCE_CHARACTER
savefile_key = "flicker_time"
can_randomize = FALSE
minimum = 2
maximum = 20
/datum/preference/numeric/living/flicker_time/create_default_value()
return 10
/datum/preference/numeric/living/flicker_time/apply_to_living(mob/living/target, value)
var/datum/component/shadekin/our_SK = target.get_shadekin_component()
if(our_SK)
our_SK.flicker_time = value
/datum/preference/numeric/living/flicker_break_chance
category = PREFERENCE_CATEGORY_MANUALLY_RENDERED
savefile_identifier = PREFERENCE_CHARACTER
savefile_key = "flicker_break_chance"
can_randomize = FALSE
minimum = 0
maximum = 25
/datum/preference/numeric/living/flicker_break_chance/create_default_value()
return 0
/datum/preference/numeric/living/flicker_break_chance/apply_to_living(mob/living/target, value)
var/datum/component/shadekin/our_SK = target.get_shadekin_component()
if(our_SK)
our_SK.flicker_break_chance = value
/datum/preference/numeric/living/flicker_distance
category = PREFERENCE_CATEGORY_MANUALLY_RENDERED
savefile_identifier = PREFERENCE_CHARACTER
savefile_key = "flicker_distance"
can_randomize = FALSE
minimum = 4
maximum = 10
/datum/preference/numeric/living/flicker_distance/create_default_value()
return 4
/datum/preference/numeric/living/flicker_distance/apply_to_living(mob/living/target, value)
var/datum/component/shadekin/our_SK = target.get_shadekin_component()
if(our_SK)
our_SK.flicker_distance = value

View File

@@ -287,3 +287,41 @@
emote_message_1p_target = "You prbt at TARGET."
emote_message_3p_target = "prbts at TARGET."
emote_sound = 'sound/voice/prbt.ogg'
//Some Spooky sounds.
/decl/emote/audible/evil_laugh
key = "evillaugh"
emote_message_3p = "laughs!"
emote_sound = 'sound/mob/spooky/laugh.ogg'
/decl/emote/audible/evil_no
key = "evilno"
emote_message_3p = "says no!"
emote_sound = 'sound/mob/spooky/no.ogg'
/decl/emote/audible/evil_breathing
key = "evilbreath"
emote_message_3p = "breaths heavily!"
emote_sound = 'sound/mob/spooky/breath1.ogg'
/decl/emote/audible/evil_breathing_2
key = "evilbreath2"
emote_message_3p = "breaths heavily!"
emote_sound = 'sound/mob/spooky/breath2.ogg'
/decl/emote/audible/goodripsound
key = "goodripsound"
emote_message_3p = "drips goo."
/decl/emote/audible/goodripsound/do_extra(var/mob/user)
..()
var/goo_sounds = list (
'sound/mob/spooky/decay1.ogg',
'sound/mob/spooky/decay2.ogg',
'sound/mob/spooky/decay3.ogg',
'sound/mob/spooky/corrosion1.ogg',
'sound/mob/spooky/corrosion2.ogg',
'sound/mob/spooky/corrosion3.ogg'
)
var/sound = pick(goo_sounds)
playsound(user.loc, sound, 100, 1)

View File

@@ -331,3 +331,18 @@
/decl/emote/visible/tilt
key = "tilt"
emote_message_3p = "tilts USER_THEIR head."
/decl/emote/visible/goodrip
key = "goodrip"
emote_message_3p = "drips goo."
/decl/emote/visible/goodrip/do_extra(var/mob/user)
..()
new /obj/effect/decal/cleanable/blood/oil(user)
var/goo_sounds = list (
'sound/mob/spooky/decay1.ogg',
'sound/mob/spooky/decay2.ogg',
'sound/mob/spooky/decay3.ogg'
)
var/sound = pick(goo_sounds)
playsound(user.loc, sound, 100, 1)

View File

@@ -27,15 +27,12 @@
if(world.time < next_emote)
to_chat(src, span_warning("You cannot use another emote yet."))
return
//VOREStation Addition Start
if(forced_psay)
pme(message)
return
if(autowhisper)
return me_verb_subtle(message)
//VOREStation Addition End
if(act == "help")
if(world.time >= next_emote_refresh)
var/list/usable_emotes = list()

View File

@@ -332,8 +332,9 @@
return if_no_id
//repurposed proc. Now it combines get_id_name() and get_face_name() to determine a mob's name variable. Made into a seperate proc as it'll be useful elsewhere
/mob/living/carbon/human/proc/get_visible_name()
if(ability_flags & AB_PHASE_SHIFTED)
/mob/living/carbon/human/get_visible_name()
var/datum/component/shadekin/SK = get_shadekin_component()
if(SK && SK.in_phase)
return "Something" // Something
if(wear_mask && (wear_mask.flags_inv&HIDEFACE)) //Wearing a mask which hides our face, use id-name if possible
return get_id_name("Unknown")

View File

@@ -14,43 +14,3 @@
tail_alt = TAIL_UPPER_LAYER // not a toggle for humans but a pointer for what layer the tail should be when facing North/East/West
var/list/body_writing // assoc list by BP_ key
/mob/living/carbon/human/proc/shadekin_get_energy()
var/datum/species/shadekin/SK = species
if(!istype(SK))
return 0
return SK.get_energy(src)
/mob/living/carbon/human/proc/shadekin_get_max_energy()
var/datum/species/shadekin/SK = species
if(!istype(SK))
return 0
return SK.get_max_energy(src)
/mob/living/carbon/human/proc/shadekin_set_energy(var/new_energy)
var/datum/species/shadekin/SK = species
if(!istype(SK))
return 0
SK.set_energy(src, new_energy)
/mob/living/carbon/human/proc/shadekin_set_max_energy(var/new_max_energy)
var/datum/species/shadekin/SK = species
if(!istype(SK))
return 0
SK.set_max_energy(src, new_max_energy)
/mob/living/carbon/human/proc/shadekin_adjust_energy(var/amount)
var/datum/species/shadekin/SK = species
if(!istype(SK))
return 0
SK.set_energy(src, SK.get_energy(src) + amount)

View File

@@ -1,5 +1,6 @@
/mob/living/carbon/human/GetAltName()
if(ability_flags & AB_PHASE_SHIFTED)
var/datum/component/shadekin/SK = get_shadekin_component()
if(SK && SK.in_phase)
return ""
if(name != GetVoice())
return " (as [get_id_name("Unknown")])"

View File

@@ -10,8 +10,7 @@
but next to no verifiable evidence to their existence. However, they have recently been more verifiably \
documented in the Virgo system, following a mining bombardment of Virgo 3. The crew of NSB Adephagia have \
taken to calling these creatures 'Shadekin', and the name has generally stuck and spread. " //TODO: Something that's not wiki copypaste
//CHOMPStation Removal TFF 12/24/19 - Wikilinks removed
// wikilink = "https://wiki.vore-station.net/Shadekin"
wikilink = "https://wiki.vore-station.net/Shadekin"
catalogue_data = list(/datum/category_item/catalogue/fauna/shadekin)
language = LANGUAGE_SHADEKIN
@@ -22,9 +21,6 @@
unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/claws/shadekin, /datum/unarmed_attack/bite/sharp/shadekin)
rarity_value = 15 //INTERDIMENSIONAL FLUFFERS
// male_scream_sound = null //CHOMPedit
// female_scream_sound = null //CHOMPedit
inherent_verbs = list(/mob/proc/adjust_hive_range)
siemens_coefficient = 1
@@ -62,7 +58,7 @@
// has_glowing_eyes = TRUE //Applicable through neutral taits.
//death_message = "phases to somewhere far away!" //CHOMPEdit Removed
death_message = "phases to somewhere far away!"
speech_bubble_appearance = "ghost"
genders = list(MALE, FEMALE, PLURAL, NEUTER)
@@ -72,7 +68,6 @@
breath_type = null
poison_type = null
water_breather = TRUE //They don't quite breathe
var/doing_phase = FALSE // Prevent bugs when spamming phase button
vision_flags = SEE_SELF|SEE_MOBS
appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_SKIN_COLOR | HAS_EYE_COLOR | HAS_UNDERWEAR
@@ -105,38 +100,25 @@
BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right)
)
//SHADEKIN-UNIQUE STUFF GOES HERE
var/list/shadekin_abilities = list(/datum/power/shadekin/phase_shift,
/datum/power/shadekin/regenerate_other,
/datum/power/shadekin/create_shade,
/datum/power/shadekin/dark_tunneling, //CHOMPEdit Add - Dark Tunneling
/datum/power/shadekin/dark_respite, //CHOMPEdit Add - Dark Respite
/datum/power/shadekin/dark_maw) //CHOMPEdit Add - Dark Maw
var/list/shadekin_ability_datums = list()
var/list/active_dark_maws = list() //CHOMPEdit - Add dark maws
var/kin_type
var/energy_light = 0.25
var/energy_dark = 0.75
var/nutrition_conversion_scaling = 0.5 //CHOMPEdit - Add nutrition <-> dark energy conversion
var/phase_gentle = TRUE //CHOMPEdit - Add gentle phasing, defaults to on.
var/manual_respite = FALSE //CHOMPEdit - Dark Respite
var/respite_activating = FALSE //CHOMPEdit - Dark Respite
var/nutrition_energy_conversion = TRUE //CHOMPEdit - Add toggle to nutrition and energy conversions
species_component = /datum/component/shadekin
species_component = /datum/component/shadekin/full //CHOMPEdit: Enabling full shadekin.
component_requires_late_recalc = TRUE
/datum/species/shadekin/New()
..()
for(var/power in shadekin_abilities)
var/datum/power/shadekin/SKP = new power(src)
shadekin_ability_datums.Add(SKP)
//CHOMPEdit Begin - Actually phase to the Dark on death
/datum/species/shadekin/handle_death(var/mob/living/carbon/human/H)
H.clear_dark_maws() //CHOMPEdit - clear dark maws on death or similar
if(respite_activating)
var/special_handling = TRUE //varswitch for downstream //CHOMPEdit - Enable.
H.clear_dark_maws() //clear dark maws on death or similar
if(!special_handling)
spawn(1)
for(var/obj/item/W in H)
H.drop_from_inventory(W)
qdel(H)
else
var/datum/component/shadekin/SK = H.get_shadekin_component()
if(!SK)
return
if(SK.respite_activating)
return TRUE
var/area/current_area = get_area(H)
if((H.ability_flags & AB_DARK_RESPITE) || H.has_modifier_of_type(/datum/modifier/dark_respite) || current_area.flag_check(AREA_LIMIT_DARK_RESPITE))
if((SK.in_dark_respite) || H.has_modifier_of_type(/datum/modifier/dark_respite) || current_area.flag_check(AREA_LIMIT_DARK_RESPITE))
return
if(!LAZYLEN(GLOB.latejoin_thedark))
log_and_message_admins("[H] died outside of the dark but there were no valid floors to warp to")
@@ -145,24 +127,31 @@
H.visible_message("<b>\The [H.name]</b> phases to somewhere far away!")
var/obj/effect/temp_visual/shadekin/phase_out/phaseanimout = new /obj/effect/temp_visual/shadekin/phase_out(H.loc)
phaseanimout.dir = H.dir
respite_activating = TRUE
SK.respite_activating = TRUE
H.drop_l_hand()
H.drop_r_hand()
H.shadekin_set_energy(0)
H.ability_flags |= AB_DARK_RESPITE
SK.shadekin_set_energy(0)
SK.in_dark_respite = TRUE
H.invisibility = INVISIBILITY_SHADEKIN
H.adjustFireLoss(-(H.getFireLoss() * 0.75))
H.adjustBruteLoss(-(H.getBruteLoss() * 0.75))
H.adjustToxLoss(-(H.getToxLoss() * 0.75))
H.adjustCloneLoss(-(H.getCloneLoss() * 0.75))
H.germ_level = 0 // CHOMPAdd - Take away the germs, or we'll die AGAIN
H.germ_level = 0 //Take away the germs, or we'll die AGAIN
H.vessel.add_reagent(REAGENT_ID_BLOOD,blood_volume-H.vessel.total_volume)
for(var/obj/item/organ/external/bp in H.organs)
bp.bandage()
bp.disinfect()
for(var/obj/item/organ/internal/I in H.internal_organs) //other wise their organs stay mush
I.damage = 0
I.status = 0
if(I.organ_tag == O_EYES)
H.sdisabilities &= ~BLIND
if(I.organ_tag == O_LUNGS)
H.SetLosebreath(0)
H.nutrition = 0
H.invisibility = INVISIBILITY_SHADEKIN
BITRESET(H.hud_updateflag, HEALTH_HUD)
@@ -175,14 +164,14 @@
add_attack_logs(belly.owner, H, "Digested in [lowertext(belly.name)]")
to_chat(belly.owner, span_notice("\The [H.name] suddenly vanishes within your [belly.name]"))
H.forceMove(pick(GLOB.latejoin_thedark))
if(H.ability_flags & AB_PHASE_SHIFTED)
if(SK.in_phase)
H.phase_shift()
else
var/obj/effect/temp_visual/shadekin/phase_in/phaseanim = new /obj/effect/temp_visual/shadekin/phase_in(H.loc)
phaseanim.dir = H.dir
H.invisibility = initial(H.invisibility)
respite_activating = FALSE
belly.owner.handle_belly_update() // CHOMPEdit
SK.respite_activating = FALSE
belly.owner.handle_belly_update()
H.clear_fullscreen("belly")
if(H.hud_used)
if(!H.hud_used.hud_shown)
@@ -193,76 +182,34 @@
H.forced_psay = FALSE
spawn(5 MINUTES)
H.ability_flags &= ~AB_DARK_RESPITE
to_chat(H, span_notice("You feel like you can leave the Dark again"))
addtimer(CALLBACK(H, TYPE_PROC_REF(/mob/living, can_leave_dark)), 5 MINUTES, TIMER_DELETE_ME)
else
H.add_modifier(/datum/modifier/dark_respite, 25 MINUTES)
spawn(1 SECOND)
H.forceMove(pick(GLOB.latejoin_thedark))
if(H.ability_flags & AB_PHASE_SHIFTED)
H.phase_shift()
else
var/obj/effect/temp_visual/shadekin/phase_in/phaseanim = new /obj/effect/temp_visual/shadekin/phase_in(H.loc)
phaseanim.dir = H.dir
H.invisibility = initial(H.invisibility)
respite_activating = FALSE
addtimer(CALLBACK(H, TYPE_PROC_REF(/mob/living, enter_the_dark)), 1 SECOND, TIMER_DELETE_ME)
spawn(15 MINUTES)
H.ability_flags &= ~AB_DARK_RESPITE
to_chat(H, span_notice("You feel like you can leave the Dark again"))
addtimer(CALLBACK(H, TYPE_PROC_REF(/mob/living, can_leave_dark)), 15 MINUTES, TIMER_DELETE_ME)
return TRUE
/datum/modifier/dark_respite
name = "Dark Respite"
pain_immunity = 1
/datum/modifier/dark_respite/tick()
if(istype(src.holder, /mob/living/carbon/human))
var/mob/living/carbon/human/H = src.holder
if(H.nutrition)
H.add_chemical_effect(CE_BLOODRESTORE, 5)
H.nutrition = max(H.nutrition - 5, 0)
/mob/living/proc/enter_the_dark()
var/datum/component/shadekin/SK = get_shadekin_component()
if(!SK)
return
SK.respite_activating = FALSE
SK.in_dark_respite = TRUE
if(istype(get_area(H), /area/shadekin))
if(!src.pain_immunity)
src.pain_immunity = 1
//Very good healing, but only in the Dark.
H.adjustFireLoss((-0.25))
H.adjustBruteLoss((-0.25))
H.adjustToxLoss((-0.25))
H.heal_organ_damage(3, 0)
H.add_chemical_effect(CE_ANTIBIOTIC, ANTIBIO_SUPER) //CHOMP Edit - increased ANTIBIO from Normal to Super
for(var/obj/item/organ/I in H.internal_organs)
if(I.robotic >= ORGAN_ROBOT)
continue
if(I.damage > 0)
I.damage = max(I.damage - 0.25, 0)
if(I.damage <= 5 && I.organ_tag == O_EYES)
H.sdisabilities &= ~BLIND
for(var/obj/item/organ/external/O in H.organs)
if(O.status & ORGAN_BROKEN)
O.mend_fracture() //Only works if the bone won't rebreak, as usual
for(var/datum/wound/W in O.wounds)
if(W.bleeding())
W.damage = max(W.damage - 3, 0)
if(W.damage <= 0)
O.wounds -= W
if(W.internal)
W.damage = max(W.damage - 3, 0)
if(W.damage <= 0)
O.wounds -= W
else
var/datum/species/shadekin/SK = H.species
if(SK.manual_respite)
to_chat(H, span_notice("As you leave the Dark, you stop focusing the Dark on healing yourself."))
SK.manual_respite = FALSE
src.expire()
if(src.pain_immunity)
src.pain_immunity = 0
//CHOMPEdit End
forceMove(pick(GLOB.latejoin_thedark))
invisibility = initial(invisibility)
SK.respite_activating = FALSE
/mob/living/proc/can_leave_dark()
var/datum/component/shadekin/SK = get_shadekin_component()
if(!SK)
return
SK.in_dark_respite = FALSE
to_chat(src, span_notice("You feel like you can leave the Dark again"))
/datum/species/shadekin/get_bodytype()
return SPECIES_SHADEKIN
@@ -270,241 +217,33 @@
/datum/species/shadekin/get_random_name()
return "shadekin"
/datum/species/shadekin/handle_environment_special(var/mob/living/carbon/human/H)
handle_shade(H)
..()
/datum/species/shadekin/add_inherent_verbs(var/mob/living/carbon/human/H)
..()
add_shadekin_abilities(H)
/datum/species/shadekin/proc/add_shadekin_abilities(var/mob/living/carbon/human/H)
if(!H.ability_master || !istype(H.ability_master, /obj/screen/movable/ability_master/shadekin))
H.ability_master = null
H.ability_master = new /obj/screen/movable/ability_master/shadekin(H)
for(var/datum/power/shadekin/P in shadekin_ability_datums)
if(!(P.verbpath in H.verbs))
add_verb(H, P.verbpath)
H.ability_master.add_shadekin_ability(
object_given = H,
verb_given = P.verbpath,
name_given = P.name,
ability_icon_given = P.ability_icon_state,
arguments = list()
)
add_verb(H,/mob/living/carbon/human/proc/phase_strength_toggle ) //CHOMPEdit - Add gentle phasing //CHOMPEdit
add_verb(H,/mob/living/carbon/human/proc/nutrition_conversion_toggle ) //CHOMPEdit - Add nutrition conversion toggle //CHOMPEdit
add_verb(H,/mob/living/carbon/human/proc/clear_dark_maws ) //CHOMPEdit - Add Dark maw clearing //CHOMPEdit
/datum/species/shadekin/proc/handle_shade(var/mob/living/carbon/human/H)
//CHOMPEdit begin - No energy during dark respite
if(H.has_modifier_of_type(/datum/modifier/dark_respite))
set_energy(H, 0)
update_shadekin_hud(H)
return
//CHOMPEdit End
//Shifted kin don't gain/lose energy (and save time if we're at the cap)
var/darkness = 1
var/dark_gains = 0
var/turf/T = get_turf(H)
if(!T)
dark_gains = 0
return
var/brightness = T.get_lumcount() //Brightness in 0.0 to 1.0
//CHOMPEdit begin - dark in bellies
if(isbelly(H.loc))
brightness = 0
//CHOMPEdit end
darkness = 1-brightness //Invert
var/is_dark = (darkness >= 0.5) || istype(get_area(H), /area/shadekin) //CHOMPEdit - Dark provides health
if(H.ability_flags & AB_PHASE_SHIFTED)
dark_gains = 0
else
//Heal (very) slowly in good darkness
if(is_dark)
H.adjustFireLoss((-0.10)*darkness)
H.adjustBruteLoss((-0.10)*darkness)
H.adjustToxLoss((-0.10)*darkness)
//energy_dark and energy_light are set by the shadekin eye traits.
//These are balanced around their playstyles and 2 planned new aggressive abilities
dark_gains = energy_dark
else
dark_gains = energy_light
//CHOMPEdit begin - Energy <-> nutrition conversion
if(nutrition_energy_conversion && get_energy(H) == 100 && dark_gains > 0)
H.nutrition += dark_gains * 5 * nutrition_conversion_scaling
else if(nutrition_energy_conversion && get_energy(H) < 50 && H.nutrition > 500)
H.nutrition -= nutrition_conversion_scaling * 50
dark_gains += nutrition_conversion_scaling
//CHOMPEdit end
set_energy(H, get_energy(H) + dark_gains)
//Update huds
update_shadekin_hud(H)
/datum/species/shadekin/proc/get_energy(var/mob/living/carbon/human/H)
var/datum/component/shadekin/comp = H.GetComponent(/datum/component/shadekin)
if(!comp)
return FALSE //No component, no energy to be had.
//CHOMPEdit - Dark Respite
if(H.ability_flags & AB_DARK_RESPITE || H.has_modifier_of_type(/datum/modifier/dark_respite))
return FALSE
//CHOMPEdit - Dark Respite
if(comp.dark_energy_infinite)
return comp.max_dark_energy
return comp.dark_energy
/datum/species/shadekin/proc/get_max_energy(var/mob/living/carbon/human/H)
var/datum/component/shadekin/comp = H.GetComponent(/datum/component/shadekin)
if(!comp)
return FALSE //No component, no energy to be had.
return comp.max_dark_energy
/datum/species/shadekin/proc/set_energy(var/mob/living/carbon/human/H, var/new_energy)
var/datum/component/shadekin/comp = H.GetComponent(/datum/component/shadekin)
if(!comp)
return FALSE //No component, no energy to be had.
comp.dark_energy = CLAMP(new_energy, 0, get_max_energy(H))
/datum/species/shadekin/proc/set_max_energy(var/mob/living/carbon/human/H, var/new_max_energy)
var/datum/component/shadekin/comp = H.GetComponent(/datum/component/shadekin)
if(!comp)
return FALSE //No component, no energy to be had.
comp.max_dark_energy = new_max_energy
/datum/species/shadekin/proc/update_shadekin_hud(var/mob/living/carbon/human/H)
var/turf/T = get_turf(H)
if(H.shadekin_display)
var/l_icon = 0
var/e_icon = 0
H.shadekin_display.invisibility = INVISIBILITY_NONE
if(T)
var/brightness = T.get_lumcount() //Brightness in 0.0 to 1.0
var/darkness = 1-brightness //Invert
switch(darkness)
if(0.80 to 1.00)
l_icon = 0
if(0.60 to 0.80)
l_icon = 1
if(0.40 to 0.60)
l_icon = 2
if(0.20 to 0.40)
l_icon = 3
if(0.00 to 0.20)
l_icon = 4
switch(get_energy(H))
if(0 to 24)
e_icon = 0
if(25 to 49)
e_icon = 1
if(50 to 74)
e_icon = 2
if(75 to 99)
e_icon = 3
if(100 to INFINITY)
e_icon = 4
H.shadekin_display.icon_state = "shadekin-[l_icon]-[e_icon]"
return
/datum/species/shadekin/proc/get_shadekin_eyecolor(var/mob/living/carbon/human/H)
var/eyecolor_rgb = rgb(H.r_eyes, H.g_eyes, H.b_eyes)
var/eyecolor_hue = rgb2num(eyecolor_rgb, COLORSPACE_HSV)[1]
var/eyecolor_sat = rgb2num(eyecolor_rgb, COLORSPACE_HSV)[2]
var/eyecolor_val = rgb2num(eyecolor_rgb, COLORSPACE_HSV)[3]
//First, clamp the saturation/value to prevent black/grey/white eyes
if(eyecolor_sat < 10)
eyecolor_sat = 10
if(eyecolor_val < 40)
eyecolor_val = 40
eyecolor_rgb = rgb(eyecolor_hue, eyecolor_sat, eyecolor_val, space=COLORSPACE_HSV)
H.r_eyes = rgb2num(eyecolor_rgb)[1]
H.g_eyes = rgb2num(eyecolor_rgb)[2]
H.b_eyes = rgb2num(eyecolor_rgb)[3]
//Now determine what color we fall into.
var/eyecolor_type = BLUE_EYES
switch(eyecolor_hue)
if(0 to 20)
eyecolor_type = RED_EYES
if(21 to 50)
eyecolor_type = ORANGE_EYES
if(51 to 70)
eyecolor_type = YELLOW_EYES
if(71 to 160)
eyecolor_type = GREEN_EYES
if(161 to 260)
eyecolor_type = BLUE_EYES
if(261 to 340)
eyecolor_type = PURPLE_EYES
if(341 to 360)
eyecolor_type = RED_EYES
return eyecolor_type
/datum/species/shadekin/post_spawn_special(var/mob/living/carbon/human/H)
.=..()
var/eyecolor_type = get_shadekin_eyecolor(H)
var/datum/component/shadekin/SK = H.get_shadekin_component()
if(!SK)
CRASH("A shadekin [H] somehow is missing their shadekin component post-spawn!")
switch(eyecolor_type)
switch(SK.eye_color)
if(BLUE_EYES)
total_health = 75 //ChompEDIT - balance tweaks
energy_light = 0.5
energy_dark = 0.5
nutrition_conversion_scaling = 0.5 //CHOMPEdit - Add nutrition <-> dark energy conversion
total_health = 75 //CHOMPEdit
if(RED_EYES)
total_health = 150 //ChompEDIT - balance tweaks
energy_light = -1
energy_dark = 0.5 //ChompEDIT
nutrition_conversion_scaling = 2 //CHOMPEdit - Add nutrition <-> dark energy conversion
total_health = 150 //CHOMPEdit
if(PURPLE_EYES)
total_health = 100 //ChompEDIT - balance tweaks
energy_light = -0.5
energy_dark = 1
nutrition_conversion_scaling = 1 //CHOMPEdit - Add nutrition <-> dark energy conversion
total_health = 150
if(YELLOW_EYES)
total_health = 50 //ChompEDIT - balance tweaks
energy_light = -2
energy_dark = 3
nutrition_conversion_scaling = 0.5 //CHOMPEdit - Add nutrition <-> dark energy conversion
total_health = 50 //CHOMPEdit
if(GREEN_EYES)
total_health = 100 //ChompEDIT - balance tweaks
energy_light = 0.125
energy_dark = 2
nutrition_conversion_scaling = 0.5 //CHOMPEdit - Add nutrition <-> dark energy conversion
total_health = 100
if(ORANGE_EYES)
total_health = 125 //ChompEDIT - balance tweaks
energy_light = -0.5
energy_dark = 0.5 //ChompEDIT
nutrition_conversion_scaling = 1.5 //CHOMPEdit - Add nutrition <-> dark energy conversion
total_health = 125 //CHOMPEdit
H.maxHealth = total_health
H.health = H.getMaxHealth()
/datum/species/shadekin/produceCopy(var/list/traits, var/mob/living/carbon/human/H, var/custom_base, var/reset_dna = TRUE) // Traitgenes reset_dna flag required, or genes get reset on resleeve
var/datum/species/shadekin/new_copy = ..()
new_copy.total_health = total_health
new_copy.energy_light = energy_light
new_copy.energy_dark = energy_dark
return new_copy

View File

@@ -1,473 +1,5 @@
/datum/power/shadekin
/mob/living/carbon/human/is_incorporeal()
if(ability_flags & AB_PHASE_SHIFTED) //Shadekin
var/datum/component/shadekin/SK = get_shadekin_component()
if(SK && SK.in_phase) //Shadekin
return TRUE
return ..()
/////////////////////
/// PHASE SHIFT ///
/////////////////////
//Visual effect for phase in/out
/obj/effect/temp_visual/shadekin
randomdir = FALSE
duration = 5
icon = 'icons/mob/vore_shadekin.dmi'
/obj/effect/temp_visual/shadekin/phase_in
icon_state = "tp_in"
/obj/effect/temp_visual/shadekin/phase_out
icon_state = "tp_out"
/datum/power/shadekin/phase_shift
name = "Phase Shift (100)"
desc = "Shift yourself out of alignment with realspace to travel quickly to different areas."
verbpath = /mob/living/carbon/human/proc/phase_shift
ability_icon_state = "tech_passwall"
/mob/living/carbon/human/proc/phase_shift()
set name = "Phase Shift (100)"
set desc = "Shift yourself out of alignment with realspace to travel quickly to different areas."
set category = "Abilities.Shadekin"
/* //CHOMPEdit - Moved below //RS Port #658 Start
var/area/A = get_area(src)
if(!client?.holder && A.flag_check(AREA_BLOCK_PHASE_SHIFT))
to_chat(src, span_warning("You can't do that here!"))
return
//RS Port #658 End
*/ //CHOMPEdit End
var/ability_cost = 100
var/darkness = 1
var/turf/T = get_turf(src)
if(!T)
to_chat(src,span_warning("You can't use that here!"))
return FALSE
if((get_area(src).flags & PHASE_SHIELDED)) //CHOMPEdit Start - Mapping tools to control phasing
to_chat(src,span_warning("This area is preventing you from phasing!"))
return FALSE
//RS Port #658 Start
var/area/A = get_area(src)
if(!client?.holder && A.flag_check(AREA_BLOCK_PHASE_SHIFT))
to_chat(src, span_warning("You can't do that here!"))
return FALSE
//RS Port #658 End //CHOMPEdit End
if(ability_flags & AB_PHASE_SHIFTING)
return FALSE
var/brightness = T.get_lumcount() //Brightness in 0.0 to 1.0
darkness = 1-brightness //Invert
var/watcher = 0
//CHOMPEdit Start - Nerf to phasing
for(var/thing in orange(7, src))
if(istype(thing, /mob/living/carbon/human))
var/mob/living/carbon/human/watchers = thing
if((watchers in oviewers(7,src)) && watchers.species != SPECIES_SHADEKIN) // And they can see us... (And aren't themselves a shadekin)
if(!(watchers.stat) && !isbelly(watchers.loc) && !istype(watchers.loc, /obj/item/holder)) // And they are alive and not being held by someone...
watcher++ // They are watching us!
else if(istype(thing, /mob/living/silicon/robot))
var/mob/living/silicon/robot/watchers = thing
if(watchers in oviewers(7,src))
if(!watchers.stat && !isbelly(watchers.loc))
watcher++ //The robot is watching us!
else if(istype(thing, /obj/machinery/camera))
var/obj/machinery/camera/watchers = thing
if(watchers.can_use())
if(src in watchers.can_see())
watcher++ //CHOMPEdit End - The camera is watching us!
ability_cost = CLAMP(ability_cost/(0.01+darkness*2),50, 80)//This allows for 1 watcher in full light
if(watcher>0)
ability_cost = ability_cost + ( 15 * watcher )
if(!(ability_flags & AB_PHASE_SHIFTED))
log_debug("[src] attempted to shift with [watcher] observers with a cost of [ability_cost] in a darkness level of [darkness]") //CHOMPEdit Start - More clear phase info.
// inform about the observers affecting phasing
if(darkness<=0.4 && watcher>=2)
to_chat(src, span_warning("You have a few observers in a well-lit area! This may prevent phasing. (Working cameras count towards observers)"))
else if(watcher>=3)
to_chat(src, span_warning("You have a large number of observers! This may prevent phasing. (Working cameras count towards observers)")) //CHOMPEdit End
var/datum/species/shadekin/SK = species
/* if(!istype(SK)) //CHOMPEdit Removal - Moved to shadekin_ability_check
to_chat(src, span_warning("Only a shadekin can use that!"))
return FALSE
else if(stat)
to_chat(src, span_warning("Can't use that ability in your state!")) */ //CHOMPEdit End
if(!shadekin_ability_check())
return FALSE
// Prevent bugs when spamming phase button
else if(SK.doing_phase)
to_chat(src, span_warning("You are already trying to phase!"))
return FALSE
else if(shadekin_get_energy() < ability_cost && !(ability_flags & AB_PHASE_SHIFTED))
to_chat(src, span_warning("Not enough energy for that ability!"))
return FALSE
if(!(ability_flags & AB_PHASE_SHIFTED))
shadekin_adjust_energy(-ability_cost)
playsound(src, 'sound/effects/stealthoff.ogg', 75, 1)
if(!T.CanPass(src,T) || loc != T)
to_chat(src,span_warning("You can't use that here!"))
return FALSE
SK.doing_phase = TRUE // Prevent bugs when spamming phase button
//Shifting in
if(ability_flags & AB_PHASE_SHIFTED)
phase_in(T)
//Shifting out
else
phase_out(T)
SK.doing_phase = FALSE // Prevent bugs when spamming phase button
/mob/living/carbon/human/proc/phase_in(var/turf/T)
if(ability_flags & AB_PHASE_SHIFTED)
// pre-change
forceMove(T)
var/original_canmove = canmove
SetStunned(0)
SetWeakened(0)
if(buckled)
buckled.unbuckle_mob()
if(pulledby)
pulledby.stop_pulling()
stop_pulling()
// change
canmove = FALSE
ability_flags &= ~AB_PHASE_SHIFTED
ability_flags |= AB_PHASE_SHIFTING
throwpass = FALSE
name = get_visible_name()
for(var/obj/belly/B as anything in vore_organs)
B.escapable = initial(B.escapable)
//cut_overlays()
invisibility = initial(invisibility)
see_invisible = initial(see_invisible)
see_invisible_default = initial(see_invisible_default) //CHOMPEdit Add - Allow seeing phased entities while phased. (Port upstream)
incorporeal_move = initial(incorporeal_move)
density = initial(density)
force_max_speed = initial(force_max_speed)
can_pull_size = initial(can_pull_size) //CHOMPEdit Start - Resetting pull ability after phasing back in (Port upstream)
can_pull_mobs = initial(can_pull_mobs)
hovering = initial(hovering) //CHOMPEdit End
update_icon()
//Cosmetics mostly
var/obj/effect/temp_visual/shadekin/phase_in/phaseanim = new /obj/effect/temp_visual/shadekin/phase_in(src.loc)
phaseanim.pixel_y = (src.size_multiplier - 1) * 16 // Pixel shift for the animation placement
phaseanim.adjust_scale(src.size_multiplier, src.size_multiplier)
phaseanim.dir = dir
alpha = 0
automatic_custom_emote(VISIBLE_MESSAGE,"phases in!")
addtimer(CALLBACK(src, PROC_REF(shadekin_complete_phase_in), original_canmove), 5, TIMER_DELETE_ME)
/mob/living/carbon/human/proc/shadekin_complete_phase_in(var/original_canmove)
var/datum/species/shadekin/SK = species //CHOMPEdit Add - Eye check. (Port upstream)
canmove = original_canmove
alpha = initial(alpha)
remove_modifiers_of_type(/datum/modifier/shadekin_phase_vision)
remove_modifiers_of_type(/datum/modifier/shadekin_phase) //CHOMPEdit Add - Shadekin probably shouldn't be hit while phasing (Port upstream)
//Potential phase-in vore
if(can_be_drop_pred || can_be_drop_prey) //Toggleable in vore panel //CHOMPEdit Start - Dropprey and phasevore checks. (Port upstream when possible)
var/list/potentials = living_mobs(0)
if(potentials.len)
var/mob/living/target = pick(potentials)
if(can_be_drop_pred && istype(target) && target.devourable && target.can_be_drop_prey && target.phase_vore && vore_selected && phase_vore)
target.forceMove(vore_selected)
to_chat(target, span_vwarning("\The [src] phases in around you, [vore_selected.vore_verb]ing you into their [vore_selected.name]!"))
to_chat(src, span_vwarning("You phase around [target], [vore_selected.vore_verb]ing them into your [vore_selected.name]!"))
else if(can_be_drop_prey && istype(target) && devourable && target.can_be_drop_pred && target.phase_vore && target.vore_selected && phase_vore)
forceMove(target.vore_selected)
to_chat(target, span_vwarning("\The [src] phases into you, [target.vore_selected.vore_verb]ing them into your [target.vore_selected.name]!"))
to_chat(src, span_vwarning("You phase into [target], having them [target.vore_selected.vore_verb] you into their [target.vore_selected.name]!")) //CHOMPEdit End - Dropprey and phasevore checks.
ability_flags &= ~AB_PHASE_SHIFTING
//Affect nearby lights
var/destroy_lights = 0
//CHOMPEdit Start - Add back light destruction & gentle phasing (Port upstream but replace with my variable toggle for full 100% control over chance, color, etc ~Diana)
if(SK.get_shadekin_eyecolor(src) == RED_EYES)
destroy_lights = 80
else if(SK.get_shadekin_eyecolor(src) == PURPLE_EYES)
destroy_lights = 25
// Add gentle phasing
if(SK.phase_gentle) // gentle case: No light destruction. Flicker in 4 tile radius once.
for(var/obj/machinery/light/L in GLOB.machines)
if(L.z != z || get_dist(src,L) > 4)
continue
L.flicker(1)
Stun(1)
else //CHOMPEdit End
for(var/obj/machinery/light/L in GLOB.machines)
if(L.z != z || get_dist(src,L) > 10)
continue
if(prob(destroy_lights))
addtimer(CALLBACK(L, TYPE_PROC_REF(/obj/machinery/light, broken)), rand(5,25), TIMER_DELETE_ME)
else
L.flicker(10)
/mob/living/carbon/human/proc/phase_out(var/turf/T)
if(!(ability_flags & AB_PHASE_SHIFTED))
// pre-change
forceMove(T)
var/original_canmove = canmove
SetStunned(0)
SetWeakened(0)
if(buckled)
buckled.unbuckle_mob()
if(pulledby)
pulledby.stop_pulling()
stop_pulling()
canmove = FALSE
var/list/allowed_implants = list( //CHOMPEdit Start - Implant dropping
/obj/item/implant/sizecontrol,
/obj/item/implant/compliance,
)
for(var/obj/item/organ/external/organ in organs)
for(var/obj/item/O in organ.implants)
if(is_type_in_list(O, allowed_implants))
continue
if(O == nif)
nif.unimplant(src)
O.forceMove(drop_location())
organ.implants -= O
if(!has_embedded_objects())
clear_alert("embeddedobject")
//CHOMPEdit End
// change
ability_flags |= AB_PHASE_SHIFTED
ability_flags |= AB_PHASE_SHIFTING
throwpass = TRUE
automatic_custom_emote(VISIBLE_MESSAGE,"phases out!")
name = get_visible_name()
//CHOMPEdit Start - Unequipping slots when phasing in, and preventing pulling stuff while phased.
if(l_hand)
unEquip(l_hand)
if(r_hand)
unEquip(r_hand)
if(back)
unEquip(back)
can_pull_size = 0
can_pull_mobs = MOB_PULL_NONE
hovering = TRUE
//CHOMPEdit End
for(var/obj/belly/B as anything in vore_organs)
B.escapable = FALSE
var/obj/effect/temp_visual/shadekin/phase_out/phaseanim = new /obj/effect/temp_visual/shadekin/phase_out(src.loc)
phaseanim.pixel_y = (src.size_multiplier - 1) * 16 // Pixel shift for the animation placement
phaseanim.adjust_scale(src.size_multiplier, src.size_multiplier)
phaseanim.dir = dir
alpha = 0
add_modifier(/datum/modifier/shadekin_phase_vision)
add_modifier(/datum/modifier/shadekin_phase) //CHOMPEdit Add - Shadekin probably shouldn't be hit while phasing
sleep(5)
invisibility = INVISIBILITY_SHADEKIN
see_invisible = INVISIBILITY_SHADEKIN
see_invisible_default = INVISIBILITY_SHADEKIN // Allow seeing phased entities while phased.
//cut_overlays()
update_icon()
alpha = 127
canmove = original_canmove
incorporeal_move = TRUE
density = FALSE
force_max_speed = TRUE
ability_flags &= ~AB_PHASE_SHIFTING
/datum/modifier/shadekin_phase_vision
name = "Shadekin Phase Vision"
vision_flags = SEE_THRU
//////////////////////////
/// REGENERATE OTHER ///
//////////////////////////
/datum/power/shadekin/regenerate_other
name = "Regenerate Other (50)"
desc = "Spend energy to heal physical wounds in another creature."
verbpath = /mob/living/carbon/human/proc/regenerate_other
ability_icon_state = "tech_biomedaura"
/mob/living/carbon/human/proc/regenerate_other()
set name = "Regenerate Other (50)"
set desc = "Spend energy to heal physical wounds in another creature."
set category = "Abilities.Shadekin"
var/ability_cost = 50
/* CHOMPEdit Start - general shadekin ability check
var/datum/species/shadekin/SK = species
if(!istype(SK))
to_chat(src, span_warning("Only a shadekin can use that!"))
return FALSE
else if(stat)
to_chat(src, span_warning("Can't use that ability in your state!"))
return FALSE
//CHOMPEdit Start - Dark Respite
else if((ability_flags & AB_DARK_RESPITE || has_modifier_of_type(/datum/modifier/dark_respite)) && !(ability_flags & AB_PHASE_SHIFTED))
to_chat(src, span_warning("You can't use that so soon after an emergency warp!"))
return FALSE
*/
if(!shadekin_ability_check())
return FALSE
//CHOMPEdit End
else if(shadekin_get_energy() < ability_cost)
to_chat(src, span_warning("Not enough energy for that ability!"))
return FALSE
else if(ability_flags & AB_PHASE_SHIFTED)
to_chat(src, span_warning("You can't use that while phase shifted!"))
return FALSE
var/list/viewed = oview(1)
var/list/targets = list()
for(var/mob/living/L in viewed)
targets += L
if(!targets.len)
to_chat(src,span_warning("Nobody nearby to mend!"))
return FALSE
var/mob/living/target = tgui_input_list(src,"Pick someone to mend:","Mend Other", targets)
if(!target)
return FALSE
target.add_modifier(/datum/modifier/shadekin/heal_boop,1 MINUTE)
playsound(src, 'sound/effects/EMPulse.ogg', 75, 1)
shadekin_adjust_energy(-ability_cost)
visible_message(span_notice("\The [src] gently places a hand on \the [target]..."))
face_atom(target)
return TRUE
/datum/modifier/shadekin/heal_boop
name = "Shadekin Regen"
desc = "You feel serene and well rested."
mob_overlay_state = "green_sparkles"
on_created_text = span_notice("Sparkles begin to appear around you, and all your ills seem to fade away.")
on_expired_text = span_notice("The sparkles have faded, although you feel much healthier than before.")
stacks = MODIFIER_STACK_EXTEND
/datum/modifier/shadekin/heal_boop/tick()
if(!holder.getBruteLoss() && !holder.getFireLoss() && !holder.getToxLoss() && !holder.getOxyLoss() && !holder.getCloneLoss()) // No point existing if the spell can't heal.
expire()
return
holder.adjustBruteLoss(-2)
holder.adjustFireLoss(-2)
holder.adjustToxLoss(-2)
holder.adjustOxyLoss(-2)
holder.adjustCloneLoss(-2)
//////////////////////
/// CREATE SHADE ///
//////////////////////
/datum/power/shadekin/create_shade
name = "Create Shade (25)"
desc = "Create a field of darkness that follows you."
verbpath = /mob/living/carbon/human/proc/create_shade
ability_icon_state = "tech_dispelold"
/mob/living/carbon/human/proc/create_shade()
set name = "Create Shade (25)"
set desc = "Create a field of darkness that follows you."
set category = "Abilities.Shadekin"
var/ability_cost = 25
/* CHOMPEdit Start - general shadekin ability check
var/datum/species/shadekin/SK = species
if(!istype(SK))
to_chat(src, span_warning("Only a shadekin can use that!"))
return FALSE
else if(stat)
to_chat(src, span_warning("Can't use that ability in your state!"))
return FALSE
//CHOMPEdit Start - Dark Respite
else if((ability_flags & AB_DARK_RESPITE || has_modifier_of_type(/datum/modifier/dark_respite)) && !(ability_flags & AB_PHASE_SHIFTED))
to_chat(src, span_warning("You can't use that so soon after an emergency warp!"))
return FALSE
*/
if(!shadekin_ability_check())
return FALSE
//CHOMPEdit End
else if(shadekin_get_energy() < ability_cost)
to_chat(src, span_warning("Not enough energy for that ability!"))
return FALSE
else if(ability_flags & AB_PHASE_SHIFTED)
to_chat(src, span_warning("You can't use that while phase shifted!"))
return FALSE
playsound(src, 'sound/effects/bamf.ogg', 75, 1)
add_modifier(/datum/modifier/shadekin/create_shade,20 SECONDS)
shadekin_adjust_energy(-ability_cost)
return TRUE
/datum/modifier/shadekin/create_shade
name = "Shadekin Shadegen"
desc = "Darkness envelops you."
mob_overlay_state = ""
on_created_text = span_notice("You drag part of The Dark into realspace, enveloping yourself.")
on_expired_text = span_warning("You lose your grasp on The Dark and realspace reasserts itself.")
stacks = MODIFIER_STACK_EXTEND
var/mob/living/simple_mob/shadekin/my_kin
/datum/modifier/shadekin/create_shade/tick()
if(my_kin.ability_flags & AB_PHASE_SHIFTED)
expire()
/datum/modifier/shadekin/create_shade/on_applied()
my_kin = holder
holder.glow_toggle = TRUE
holder.glow_range = 8
holder.glow_intensity = -10
holder.glow_color = "#FFFFFF"
holder.set_light(8, -10, "#FFFFFF")
/datum/modifier/shadekin/create_shade/on_expire()
holder.glow_toggle = initial(holder.glow_toggle)
holder.glow_range = initial(holder.glow_range)
holder.glow_intensity = initial(holder.glow_intensity)
holder.glow_color = initial(holder.glow_color)
holder.set_light(0)
my_kin = null
// force dephase proc, to be called by other procs to dephase the shadekin. T is the target to force dephase them to.
/mob/living/carbon/human/proc/attack_dephase(var/turf/T = null, atom/dephaser)
var/datum/species/shadekin/SK = species
// no assigned dephase-target, just use our own
if(!T)
T = get_turf(src)
// make sure it's possible to be dephased (and we're in phase)
if(!istype(SK) || SK.doing_phase || !T.CanPass(src,T) || loc != T || !(ability_flags & AB_PHASE_SHIFTED) )
return FALSE
log_admin("[key_name_admin(src)] was stunned out of phase at [T.x],[T.y],[T.z] by [dephaser.name], last touched by [dephaser.forensic_data?.get_lastprint()].")
message_admins("[key_name_admin(src)] was stunned out of phase at [T.x],[T.y],[T.z] by [dephaser.name], last touched by [dephaser.forensic_data?.get_lastprint()]. (<A href='byond://?_src_=holder;[HrefToken()];adminplayerobservecoodjump=1;X=[T.x];Y=[T.y];Z=[T.z]'>JMP</a>)", 1)
// start the dephase
phase_in(T)
shadekin_adjust_energy(-20) // loss of energy for the interception
// apply a little extra stun for good measure
src.Weaken(3)

View File

@@ -26,6 +26,7 @@
/obj/screen/ability/verb_based/shadekin
icon_state = "grey_spell_base"
background_base_state = "grey"
icon = 'icons/mob/shadekin_abilities.dmi'
/obj/screen/movable/ability_master/proc/add_shadekin_ability(var/object_given, var/verb_given, var/name_given, var/ability_icon_given, var/arguments)
if(!object_given)

View File

@@ -1,95 +0,0 @@
/datum/species/shadekin_yw
name = SPECIES_SHADEKIN_YW
name_plural = "Shadekin"
icobase = 'icons/mob/human_races/r_shadekin_vr.dmi'
deform = 'icons/mob/human_races/r_shadekin_vr.dmi'
tail = "tail"
icobase_tail = 1
blurb = "A shadekin, where their powers have been stripped down, their access to the bluespace warp, removed."
catalogue_data = list(/datum/category_item/catalogue/fauna/shadekin)
language = LANGUAGE_SHADEKIN
assisted_langs = list()
unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/claws/shadekin, /datum/unarmed_attack/bite/sharp/shadekin)
rarity_value = 10 //INTERDIMENSIONAL FLUFFERS
darksight = 10
slowdown = -0.5
brute_mod = 0.9 // Naturally sturdy.
burn_mod = 1.2 // Furry
warning_low_pressure = 50
hazard_low_pressure = -1
warning_high_pressure = 300
hazard_high_pressure = INFINITY
cold_level_1 = -1 //Immune to cold
cold_level_2 = -1
cold_level_3 = -1
flags = NO_SCAN
spawn_flags = SPECIES_CAN_JOIN
reagent_tag = IS_SHADEKIN // for shadekin-unqiue chem interactions
flesh_color = "#FFC896"
blood_color = "#A10808"
base_color = "#f0f0f0"
color_mult = 1
has_glowing_eyes = TRUE
male_cough_sounds = null
female_cough_sounds = null
//male_sneeze_sound = null //CHOMPStation Edit Disable
//female_sneeze_sound = null //CHOMPStation Edit Disable
speech_bubble_appearance = "ghost"
genders = list(PLURAL, NEUTER) //no sexual dymorphism
ambiguous_genders = TRUE //but just in case
breath_type = null
poison_type = null
vision_flags = SEE_SELF
appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_SKIN_COLOR | HAS_EYE_COLOR | HAS_UNDERWEAR
move_trail = /obj/effect/decal/cleanable/blood/tracks/paw
has_organ = list(
O_HEART = /obj/item/organ/internal/heart,
O_VOICE = /obj/item/organ/internal/voicebox,
O_LIVER = /obj/item/organ/internal/liver,
O_KIDNEYS = /obj/item/organ/internal/kidneys,
O_BRAIN = /obj/item/organ/internal/brain/shadekin,
O_EYES = /obj/item/organ/internal/eyes,
O_STOMACH = /obj/item/organ/internal/stomach,
O_INTESTINE = /obj/item/organ/internal/intestine
)
has_limbs = list(
BP_TORSO = list("path" = /obj/item/organ/external/chest),
BP_GROIN = list("path" = /obj/item/organ/external/groin),
BP_HEAD = list("path" = /obj/item/organ/external/head/vr/shadekin),
BP_L_ARM = list("path" = /obj/item/organ/external/arm),
BP_R_ARM = list("path" = /obj/item/organ/external/arm/right),
BP_L_LEG = list("path" = /obj/item/organ/external/leg),
BP_R_LEG = list("path" = /obj/item/organ/external/leg/right),
BP_L_HAND = list("path" = /obj/item/organ/external/hand),
BP_R_HAND = list("path" = /obj/item/organ/external/hand/right),
BP_L_FOOT = list("path" = /obj/item/organ/external/foot),
BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right)
)
/datum/species/shadekin_yw/get_bodytype()
return SPECIES_SHADEKIN
/datum/species/shadekin_yw/get_random_name()
return "shadekin"
/datum/species/shadekin_yw/can_breathe_water()
return TRUE //they dont quite breathe

View File

@@ -1,19 +0,0 @@
//This file is so i can make upates to shadekin and easily push to vorestation, just a main override file
/datum/species/shadekin/handle_environment_special(var/mob/living/carbon/human/H)
handle_shade(H)
handle_phased(H)
//Slippery fingers, if we ever make some update that makes all held items non useable for kins we can remove this.
/datum/species/shadekin/proc/handle_phased(var/mob/living/carbon/human/shadekin/H)
if(H.ability_flags & AB_PHASE_SHIFTED)
if(H.l_hand)
H.drop_l_hand()
if(H.r_hand)
H.drop_r_hand()
return 1 //we are phased and applied all handling
else
return 0 //we aren't phased ignore all

View File

@@ -359,6 +359,7 @@
var/food_preference_bonus = 0
var/datum/component/species_component = null // The component that this species uses. Example: Xenochimera use /datum/component/xenochimera
var/component_requires_late_recalc = FALSE // If TRUE, the component will do special recalculation stuff at the end of update_icons_body()
// For Lleill and Hanner
var/lleill_energy = 200
@@ -595,12 +596,11 @@
SEND_SIGNAL(H, COMSIG_XENOCHIMERA_COMPONENT)
//Shadekin Species Component.
/* //For when shadekin actually have their component control everything.
var/datum/component/shadekin/sk = H.get_xenochimera_component()
//For when shadekin actually have their component control everything.
var/datum/component/shadekin/sk = H.get_shadekin_component()
if(sk)
if(!H.stat || !(xc.revive_ready == REVIVING_NOW || xc.revive_ready == REVIVING_DONE))
if(!H.stat)
SEND_SIGNAL(H, COMSIG_SHADEKIN_COMPONENT)
*/
// Used to update alien icons for aliens.
/datum/species/proc/handle_login_special(var/mob/living/carbon/human/H)

View File

@@ -153,14 +153,18 @@
/datum/unarmed_attack/claws/shadekin/apply_effects(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage)
..()
if(!(target == user))
user.shadekin_adjust_energy(attack_damage)
var/datum/component/shadekin/SK = user.get_shadekin_component()
if(SK)
SK.shadekin_adjust_energy(attack_damage)
/datum/unarmed_attack/bite/sharp/shadekin
/datum/unarmed_attack/bite/sharp/shadekin/apply_effects(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage)
..()
if(!(target == user))
user.shadekin_adjust_energy(attack_damage)
var/datum/component/shadekin/SK = user.get_shadekin_component()
if(SK)
SK.shadekin_adjust_energy(attack_damage)
/datum/unarmed_attack/claws/chimera //special feral attack that gets stronger as they get angrier

View File

@@ -376,6 +376,10 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) //see UpdateDamageIcon()
update_wing_showing()
update_vore_belly_sprite()
update_vore_tail_sprite()
if(species && species.component_requires_late_recalc)
var/datum/component/shadekin/SK = GetComponent(/datum/component/shadekin)
if(SK)
SK.recalc_values()
/mob/living/carbon/human/proc/update_skin()
if(QDESTROYING(src))

View File

@@ -18,6 +18,15 @@
selected_image = image(icon = GLOB.buildmode_hud, loc = src, icon_state = "ai_sel")
/mob/living/proc/get_visible_name()
var/datum/component/shadekin/SK = get_shadekin_component()
if(SK && SK.in_phase)
return "Something"
if(real_name)
return real_name
else
return name
/mob/living/Destroy()
SSradiation.listeners -= src
remove_all_modifiers(TRUE)
@@ -1255,7 +1264,7 @@
swap_hand()
/mob/living/throw_item(atom/target)
if(incapacitated() || !target || istype(target, /obj/screen))
if(incapacitated() || !target || istype(target, /obj/screen) || is_incorporeal())
return FALSE
var/atom/movable/item = src.get_active_hand()

View File

@@ -417,9 +417,10 @@
if(get_dist(get_turf(T), get_turf(src)) > leap_distance) return
if(ishuman(T))
var/mob/living/carbon/human/H = T
if(H.get_species() == SPECIES_SHADEKIN && (H.ability_flags & AB_PHASE_SHIFTED))
if(isliving(T))
var/mob/living/M = T
var/datum/component/shadekin/SK = M.get_shadekin_component()
if(SK && SK.in_phase)
power_cost *= 2
if(!use_direct_power(power_cost, minimum_power - power_cost))

View File

@@ -419,18 +419,18 @@
for(var/datum/matter_synth/our_synth in module.synths)
switch(our_synth.name)
if(METAL_SYNTH)
if(has_glass)
possible_synths[/obj/item/stack/material/cyborg/glass/reinforced] = list(our_synth, has_glass)
possible_synths += list(/obj/item/stack/material/cyborg/steel = list(our_synth))
possible_synths += list(/obj/item/stack/tile/floor/cyborg = list(our_synth))
possible_synths += list(/obj/item/stack/rods/cyborg = list(our_synth))
possible_synths += list(/obj/item/stack/tile/roofing/cyborg = list(our_synth))
if(has_glass)
possible_synths |= list(/obj/item/stack/material/cyborg/glass/reinforced = list(our_synth, has_glass))
if(PLASTEEL_SYNTH)
possible_synths += list(/obj/item/stack/material/cyborg/plasteel = list(our_synth))
if(GLASS_SYNTH)
possible_synths += list(/obj/item/stack/material/cyborg/glass = list(our_synth))
if(has_steel)
possible_synths |= list(/obj/item/stack/material/cyborg/glass/reinforced = list(our_synth, has_steel))
possible_synths[/obj/item/stack/material/cyborg/glass/reinforced] = list(our_synth, has_steel)
possible_synths += list(/obj/item/stack/material/cyborg/glass = list(our_synth))
if(WOOD_SYNTH)
possible_synths += list(/obj/item/stack/tile/wood/cyborg = list(our_synth))
possible_synths += list(/obj/item/stack/material/cyborg/wood = list(our_synth))

View File

@@ -105,6 +105,8 @@
if(in_stasis)
return 1 // return early to skip atmos checks
if(is_incorporeal())
return 1
var/atom/A = src.loc

View File

@@ -203,6 +203,11 @@
zone_sel.update_icon()
hud_elements |= zone_sel
//Component hud elements. Made in /mob/living/create_mob_hud
hud_elements |= shadekin_display
hud_elements |= xenochimera_danger_display
hud_elements |= lleill_display
//Hand things
if(has_hands)
//Drop button

View File

@@ -109,7 +109,7 @@
density = FALSE
force_max_speed = TRUE
/mob/living/simple_mob/vore/demon/verb/phase_shift()
/mob/living/simple_mob/vore/demon/verb/demonic_phase_shift()
set name = "Phase Shift"
set desc = "Shift out of reality temporarily"
set category = "Abilities.Demon"

View File

@@ -4,4 +4,4 @@
/mob/living/simple_mob/clowns/big/c_shift/Initialize(mapload)
. = ..()
add_verb(src, /mob/living/simple_mob/clowns/big/c_shift/proc/phase_shift)
comp = LoadComponent(comp)

View File

@@ -1,92 +1,20 @@
/mob/living/simple_mob/clowns/big/c_shift
var/ability_flags = 0 //Flags for active abilities
// Phase shifting procs (and related procs)
/mob/living/simple_mob/clowns/big/c_shift/proc/phase_shift()
var/turf/T = get_turf(src)
if(!T.CanPass(src,T) || loc != T)
to_chat(src,span_warning("You can't use that here!"))
return FALSE
forceMove(T)
var/original_canmove = canmove
SetStunned(0)
SetWeakened(0)
if(buckled)
buckled.unbuckle_mob()
if(pulledby)
pulledby.stop_pulling()
stop_pulling()
canmove = FALSE
//Shifting in
if(ability_flags & AB_PHASE_SHIFTED)
ability_flags &= ~AB_PHASE_SHIFTED
mouse_opacity = 2
name = real_name
cut_overlays()
alpha = initial(alpha)
invisibility = initial(invisibility)
see_invisible = initial(see_invisible)
incorporeal_move = initial(incorporeal_move)
density = initial(density)
force_max_speed = initial(force_max_speed)
//Cosmetics mostly
flick("tp_in",src)
automatic_custom_emote(VISIBLE_MESSAGE,"phases in!")
sleep(5) //The duration of the TP animation
canmove = original_canmove
// Do this after the potential vore, so we get the belly
update_icon()
//Affect nearby lights
for(var/obj/machinery/light/L in GLOB.machines)
if(L.z != z || get_dist(src,L) > 10)
continue
L.flicker(10)
//Shifting out
else
ability_flags |= AB_PHASE_SHIFTED
mouse_opacity = 0
automatic_custom_emote(VISIBLE_MESSAGE,"phases out!")
real_name = name
name = "Something"
cut_overlays()
flick("tp_out",src)
sleep(5)
invisibility = INVISIBILITY_LEVEL_TWO
see_invisible = INVISIBILITY_LEVEL_TWO
update_icon()
alpha = 127
canmove = original_canmove
incorporeal_move = TRUE
density = FALSE
force_max_speed = TRUE
var/datum/component/shadekin/comp = /datum/component/shadekin/phase_only //Component that holds all the shadekin vars.
/mob/living/simple_mob/clowns/big/c_shift/UnarmedAttack()
if(ability_flags & AB_PHASE_SHIFTED)
if(comp.in_phase)
return FALSE //Nope.
. = ..()
/mob/living/simple_mob/clowns/big/c_shift/can_fall()
if(ability_flags & AB_PHASE_SHIFTED)
if(comp.in_phase)
return FALSE //Nope!
return ..()
/mob/living/simple_mob/clowns/big/c_shift/zMove(direction)
if(ability_flags & AB_PHASE_SHIFTED)
if(comp.in_phase)
var/turf/destination = (direction == UP) ? GetAbove(src) : GetBelow(src)
if(destination)
forceMove(destination)

View File

@@ -20,10 +20,9 @@
/obj/effect/shadekin_ability/proc/atom_button_text()
var/shift_denial
if(shift_mode == NOT_WHILE_SHIFTED && (my_kin.ability_flags & AB_PHASE_SHIFTED))
if(shift_mode == NOT_WHILE_SHIFTED && my_kin.comp.in_phase)
shift_denial = "Physical Only"
else if(shift_mode == ONLY_WHILE_SHIFTED && !(my_kin.ability_flags & AB_PHASE_SHIFTED))
else if(shift_mode == ONLY_WHILE_SHIFTED && !(my_kin.comp.in_phase))
shift_denial = "Shifted Only"
if(shift_denial)
@@ -47,15 +46,10 @@
if(my_kin.stat)
to_chat(my_kin,span_warning("Can't use that ability in your state!"))
return FALSE
//CHOMPEdit Begin - Dark Respite
if(my_kin.ability_flags & AB_DARK_RESPITE)
to_chat(src, span_warning("You can't use that so soon after an emergency warp!"))
return FALSE
//CHOMPEdit End
if(shift_mode == NOT_WHILE_SHIFTED && (my_kin.ability_flags & AB_PHASE_SHIFTED))
if(shift_mode == NOT_WHILE_SHIFTED && (my_kin.comp.in_phase))
to_chat(my_kin,span_warning("Can't use that ability while phase shifted!"))
return FALSE
else if(shift_mode == ONLY_WHILE_SHIFTED && !(my_kin.ability_flags & AB_PHASE_SHIFTED))
else if(shift_mode == ONLY_WHILE_SHIFTED && !(my_kin.comp.in_phase))
to_chat(my_kin,span_warning("Can only use that ability while phase shifted!"))
return FALSE
else if(my_kin.comp.dark_energy < cost)
@@ -80,7 +74,7 @@
if(!..())
return
my_kin.phase_shift()
if(my_kin.ability_flags & AB_PHASE_SHIFTED)
if(my_kin.comp.in_phase)
cost = 0 //Shifting back is free (but harmful in light)
else
cost = initial(cost)
@@ -141,7 +135,7 @@
var/mob/living/simple_mob/shadekin/my_kin
/datum/modifier/shadekin/create_shade/tick()
if(my_kin.ability_flags & AB_PHASE_SHIFTED)
if(my_kin.comp.in_phase)
expire()
/datum/modifier/shadekin/create_shade/on_applied()
@@ -172,38 +166,3 @@
if(!..())
return
*/
//CHOMPEdit start - Add dark tunneling ability
/obj/effect/shadekin_ability/dark_tunneling
ability_name = "Dark Tunneling"
desc = "Make a passage to the dark. (Once)"
icon_state = "minion0"
cost = 100
shift_mode = NOT_WHILE_SHIFTED
ab_sound = 'sound/effects/stealthoff.ogg'
/obj/effect/shadekin_ability/dark_tunneling/do_ability()
if(my_kin.ability_flags & AB_DARK_TUNNEL)
to_chat(src, span_warning("You have already made a tunnel to the Dark!"))
return FALSE
if(!..())
return
if(!my_kin.dark_tunneling())
my_kin.comp.dark_energy += cost //Refund due to abort
else
my_kin.comp.dark_energy += 10 //Refund enough to open the dark portal
//CHOMPEdit End
//CHOMPEdit start - Add Dark Maw ability
/obj/effect/shadekin_ability/dark_maw
ability_name = "Dark Maw"
desc = "Create a trap to capture others, or steal people from phase"
icon_state = "ling_absorb_dna"
cost = 20
shift_mode = SHIFTED_OR_NOT
ab_sound = 'sound/effects/stealthoff.ogg'
/obj/effect/shadekin_ability/dark_maw/do_ability()
if(!..())
return
if(!my_kin.dark_maw())
my_kin.comp.dark_energy += cost //Refund due to abort
//CHOMPEdit End

View File

@@ -1,20 +1,13 @@
// Phase shifting procs (and related procs)
/mob/living/simple_mob/shadekin/proc/phase_shift()
/mob/living/simple_mob/shadekin/phase_shift()
var/turf/T = get_turf(src)
var/area/A = T.loc //RS Port #658
var/area/A = T.loc
if(!T.CanPass(src,T) || loc != T)
to_chat(src,span_warning("You can't use that here!"))
return FALSE
//CHOMPAdd Start
if((get_area(src).flags & PHASE_SHIELDED))
to_chat(src,span_warning("This area is preventing you from phasing!"))
return FALSE
//CHOMPAdd End
//RS Port #658 Start
if(!check_rights_for(client, R_HOLDER) && A.flag_check(AREA_BLOCK_PHASE_SHIFT))
to_chat(src,span_warning("You can't use that here!"))
return FALSE
//RS Port #658 End
else if(doing_phase)
to_chat(src, span_warning("You are already trying to phase!"))
@@ -22,136 +15,27 @@
doing_phase = TRUE
//Shifting in
if(ability_flags & AB_PHASE_SHIFTED)
if(comp.in_phase)
phase_in(T)
//Shifting out
else
phase_out(T)
doing_phase = FALSE
/mob/living/simple_mob/shadekin/proc/phase_in(var/turf/T)
if(ability_flags & AB_PHASE_SHIFTED)
// pre-change
forceMove(T)
var/original_canmove = canmove
SetStunned(0)
SetWeakened(0)
if(buckled)
buckled.unbuckle_mob()
if(pulledby)
pulledby.stop_pulling()
stop_pulling()
canmove = FALSE
// change
ability_flags &= ~AB_PHASE_SHIFTED
throwpass = FALSE
name = real_name
for(var/obj/belly/B as anything in vore_organs)
B.escapable = initial(B.escapable)
cut_overlays()
alpha = initial(alpha)
invisibility = initial(invisibility)
see_invisible = initial(see_invisible)
incorporeal_move = initial(incorporeal_move)
density = initial(density)
force_max_speed = initial(force_max_speed)
//Cosmetics mostly
flick("tp_in",src)
automatic_custom_emote(VISIBLE_MESSAGE,"phases in!")
addtimer(CALLBACK(src, PROC_REF(shadekin_complete_phase_in), original_canmove), 5, TIMER_DELETE_ME)
/mob/living/simple_mob/shadekin/proc/shadekin_complete_phase_in(var/original_canmove)
canmove = original_canmove
//Potential phase-in vore
if(can_be_drop_pred) //Toggleable in vore panel
var/list/potentials = living_mobs(0)
if(potentials.len)
var/mob/living/target = pick(potentials)
if(istype(target) && target.devourable && target.can_be_drop_prey && vore_selected)
target.forceMove(vore_selected)
to_chat(target,span_vwarning("\The [src] phases in around you, [vore_selected.vore_verb]ing you into their [vore_selected.name]!"))
// Do this after the potential vore, so we get the belly
update_icon()
/* CHOMPRemove Start
//Affect nearby lights
var/destroy_lights = 0
if(eye_state == RED_EYES)
destroy_lights = 80
if(eye_state == PURPLE_EYES)
destroy_lights = 25
for(var/obj/machinery/light/L in GLOB.machines)
if(L.z != z || get_dist(src,L) > 10)
continue
if(prob(destroy_lights))
addtimer(CALLBACK(L, TYPE_PROC_REF(/obj/machinery/light, broken)), rand(5,25), TIMER_DELETE_ME)
else
L.flicker(10)
*/// CHOMPRemove End
handle_phasein_flicker() // CHOMPEdit, special handle for phase-in light flicker
/mob/living/simple_mob/shadekin/proc/phase_out(var/turf/T)
if(!(ability_flags & AB_PHASE_SHIFTED))
// pre-change
forceMove(T)
var/original_canmove = canmove
SetStunned(0)
SetWeakened(0)
if(buckled)
buckled.unbuckle_mob()
if(pulledby)
pulledby.stop_pulling()
stop_pulling()
canmove = FALSE
// change
ability_flags |= AB_PHASE_SHIFTED
throwpass = TRUE
automatic_custom_emote(VISIBLE_MESSAGE,"phases out!")
real_name = name
name = "Something"
for(var/obj/belly/B as anything in vore_organs)
B.escapable = FALSE
cut_overlays()
flick("tp_out",src)
sleep(5)
invisibility = INVISIBILITY_LEVEL_TWO
see_invisible = INVISIBILITY_LEVEL_TWO
update_icon()
alpha = 127
canmove = original_canmove
incorporeal_move = TRUE
density = FALSE
force_max_speed = TRUE
/mob/living/simple_mob/shadekin/UnarmedAttack()
if(ability_flags & AB_PHASE_SHIFTED)
if(comp.in_phase)
return FALSE //Nope.
. = ..()
/mob/living/simple_mob/shadekin/can_fall()
if(ability_flags & AB_PHASE_SHIFTED)
if(comp.in_phase)
return FALSE //Nope!
return ..()
/mob/living/simple_mob/shadekin/zMove(direction)
if(ability_flags & AB_PHASE_SHIFTED)
if(comp.in_phase)
var/turf/destination = (direction == UP) ? GetAbove(src) : GetBelow(src)
if(destination)
forceMove(destination)

View File

@@ -1,454 +0,0 @@
/mob/living/simple_mob/shadekin/Initialize(mapload)
var/list/ability_types = subtypesof(/obj/effect/shadekin_ability)
if(name == "Rakshasa")
ability_types += subtypesof(/obj/effect/rakshasa_ability)
shadekin_abilities = list()
for(var/type in ability_types)
shadekin_abilities += new type(src)
update_icon()
return ..()
/obj/effect/rakshasa_ability
name = ""
desc = ""
icon = 'icons/mob/screen_spells.dmi'
var/ability_name = "FIX ME"
var/cost = 50
var/mob/living/simple_mob/shadekin/my_kin
var/shift_mode = NOT_WHILE_SHIFTED
var/ab_sound
/obj/effect/rakshasa_ability/Initialize(mapload)
. = ..()
my_kin = loc
if(!istype(my_kin))
return INITIALIZE_HINT_QDEL
loc = null
/obj/effect/rakshasa_ability/Destroy()
my_kin = null
return ..()
/obj/effect/rakshasa_ability/proc/atom_button_text()
var/shift_denial
if(shift_mode == NOT_WHILE_SHIFTED && (my_kin.ability_flags & AB_PHASE_SHIFTED))
shift_denial = "Physical Only"
else if(shift_mode == ONLY_WHILE_SHIFTED && !(my_kin.ability_flags & AB_PHASE_SHIFTED))
shift_denial = "Shifted Only"
if(shift_denial)
name = shift_denial
else
name = my_kin.comp.dark_energy >= cost ? "Activate" : "No Energy"
return src
/obj/effect/rakshasa_ability/Click(var/location, var/control, var/params)
if(my_kin.stat) return
var/list/clickprops = params2list(params)
var/opts = clickprops["shift"]
if(opts)
to_chat(my_kin,span_notice("<b>[name]</b> (Cost: [cost]%) - [desc]"))
else
do_ability(my_kin)
/obj/effect/rakshasa_ability/proc/do_ability()
if(my_kin.stat)
to_chat(my_kin,span_warning("Can't use that ability in your state!"))
return FALSE
if(shift_mode == NOT_WHILE_SHIFTED && (my_kin.ability_flags & AB_PHASE_SHIFTED))
to_chat(my_kin,span_warning("Can't use that ability while phase shifted!"))
return FALSE
else if(shift_mode == ONLY_WHILE_SHIFTED && !(my_kin.ability_flags & AB_PHASE_SHIFTED))
to_chat(my_kin,span_warning("Can only use that ability while phase shifted!"))
return FALSE
else if(my_kin.comp.dark_energy < cost)
to_chat(my_kin,span_warning("Not enough energy for that ability!"))
return FALSE
my_kin.comp.dark_energy -= cost
if(ab_sound)
playsound(src,ab_sound,75,1)
return TRUE
/obj/effect/rakshasa_ability/phase_shift2
ability_name = "Goo Shift"
desc = "Shift yourself with goopy effects."
icon_state = "tech_passwall"
cost = 100
shift_mode = SHIFTED_OR_NOT
ab_sound = 'sound/effects/stealthoff.ogg'
/obj/effect/rakshasa_ability/phase_shift2/do_ability()
if(!..())
return
new /obj/effect/decal/cleanable/blood/oil(loc, src)
playsound(src, 'sound/rakshasa/Corrosion1.ogg', 100, 1)
my_kin.rakshasa_shift()
if(my_kin.ability_flags & AB_PHASE_SHIFTED)
cost = 0 //Shifting back is free (but harmful in light)
new /obj/effect/decal/cleanable/blood/oil(my_kin.loc)
var/goo_sounds = list (
'sound/rakshasa/Decay1.ogg',
'sound/rakshasa/Decay2.ogg',
'sound/rakshasa/Decay3.ogg'
)
var/sound = pick(goo_sounds)
playsound(my_kin.loc, sound, 100, 1)
else
cost = initial(cost)
new /obj/effect/decal/cleanable/blood/oil(my_kin.loc)
playsound(my_kin.loc, 'sound/rakshasa/Emerge0.ogg', 100, 1)
/////////////////////////////////////////////////////////////////
/obj/effect/rakshasa_ability/phase_shift3
ability_name = "Goo Shift No Emerge"
desc = "Shift yourself with goopy effects."
icon_state = "tech_passwall"
cost = 100
shift_mode = SHIFTED_OR_NOT
ab_sound = 'sound/effects/stealthoff.ogg'
/obj/effect/rakshasa_ability/phase_shift3/do_ability()
if(!..())
return
new /obj/effect/decal/cleanable/blood/oil(loc, src)
playsound(src, 'sound/rakshasa/Corrosion1.ogg', 100, 1)
my_kin.rakshasa_shift()
if(my_kin.ability_flags & AB_PHASE_SHIFTED)
cost = 0 //Shifting back is free (but harmful in light)
new /obj/effect/decal/cleanable/blood/oil(my_kin.loc)
var/goo_sounds = list (
'sound/rakshasa/Decay1.ogg',
'sound/rakshasa/Decay2.ogg',
'sound/rakshasa/Decay3.ogg'
)
var/sound = pick(goo_sounds)
playsound(my_kin.loc, sound, 100, 1)
else
cost = initial(cost)
new /obj/effect/decal/cleanable/blood/oil(my_kin.loc)
var/goo_sounds = list (
'sound/rakshasa/Decay1.ogg',
'sound/rakshasa/Decay2.ogg',
'sound/rakshasa/Decay3.ogg'
)
var/sound = pick(goo_sounds)
playsound(my_kin.loc, sound, 100, 1)
/////////////////////////////////////////////////////////////////
/obj/effect/rakshasa_ability/phase_shift4
ability_name = "Stealth Shift"
desc = "Stealthy. No light effects, no goo."
icon_state = "tech_passwall"
cost = 100
shift_mode = SHIFTED_OR_NOT
ab_sound = 'sound/effects/stealthoff.ogg'
/obj/effect/rakshasa_ability/phase_shift4/do_ability()
if(!..())
return
my_kin.stealth_shift()
if(my_kin.ability_flags & AB_PHASE_SHIFTED)
cost = 0 //Shifting back is free (but harmful in light)
else
cost = initial(cost)
/////////////////////////////////////////////////////////////////
/obj/effect/rakshasa_ability/drip_oil
ability_name = "Goo Drip"
desc = "Drip some goo."
icon_state = ""
cost = 0
shift_mode = SHIFTED_OR_NOT
ab_sound = 'sound/effects/stealthoff.ogg'
/obj/effect/rakshasa_ability/drip_oil/do_ability()
if(!..())
return
new /obj/effect/decal/cleanable/blood/oil(my_kin.loc)
var/goo_sounds = list (
'sound/rakshasa/Decay1.ogg',
'sound/rakshasa/Decay2.ogg',
'sound/rakshasa/Decay3.ogg'
)
var/sound = pick(goo_sounds)
playsound(my_kin.loc, sound, 100, 1)
/////////////////////////////////////////////////////////////////
/obj/effect/rakshasa_ability/laugh
ability_name = "Laugh"
desc = "Laugh."
icon_state = ""
cost = 0
shift_mode = SHIFTED_OR_NOT
ab_sound = 'sound/effects/stealthoff.ogg'
/obj/effect/rakshasa_ability/laugh/do_ability()
if(!..())
return
playsound(my_kin.loc, 'sound/rakshasa/Laugh.ogg', 100, 1)
/////////////////////////////////////////////////////////////////
/obj/effect/rakshasa_ability/no
ability_name = "Say No"
desc = "Say no!"
icon_state = ""
cost = 0
shift_mode = SHIFTED_OR_NOT
ab_sound = 'sound/effects/stealthoff.ogg'
/obj/effect/rakshasa_ability/no/do_ability()
if(!..())
return
playsound(my_kin.loc, 'sound/rakshasa/No.ogg', 100, 1)
/////////////////////////////////////////////////////////////////
/obj/effect/rakshasa_ability/emergesound
ability_name = "Heavy Breathing"
desc = "Heavy Breathing."
icon_state = ""
cost = 0
shift_mode = SHIFTED_OR_NOT
ab_sound = 'sound/effects/stealthoff.ogg'
/obj/effect/rakshasa_ability/emergesound/do_ability()
if(!..())
return
playsound(my_kin.loc, 'sound/rakshasa/Breath1.ogg', 100, 1)
/////////////////////////////////////////////////////////////////
/obj/effect/rakshasa_ability/trapsound
ability_name = "Raspy Breathing"
desc = "Raspy Breathing."
icon_state = ""
cost = 0
shift_mode = SHIFTED_OR_NOT
ab_sound = 'sound/effects/stealthoff.ogg'
/obj/effect/rakshasa_ability/trapsound/do_ability()
if(!..())
return
var/goo_sounds = list (
'sound/rakshasa/Breath2.ogg'
)
var/sound = pick(goo_sounds)
playsound(my_kin.loc, sound, 100, 1)
/////////////////////////////////////////////////////////////////
/obj/effect/rakshasa_ability/dripsound
ability_name = "Goop Drip Sound"
desc = "Do the drip sound without actually dripping."
icon_state = ""
cost = 0
shift_mode = SHIFTED_OR_NOT
ab_sound = 'sound/effects/stealthoff.ogg'
/obj/effect/rakshasa_ability/dripsound/do_ability()
if(!..())
return
var/goo_sounds = list (
'sound/rakshasa/Decay1.ogg',
'sound/rakshasa/Decay2.ogg',
'sound/rakshasa/Decay3.ogg',
'sound/rakshasa/Corrosion1.ogg',
'sound/rakshasa/Corrosion2.ogg',
'sound/rakshasa/Corrosion3.ogg'
)
var/sound = pick(goo_sounds)
playsound(my_kin.loc, sound, 100, 1)
/////////////////////////////////////////////////////////////////
/obj/effect/rakshasa_ability/trap
ability_name = "Lay Trap"
desc = "Lay a trap that will notify you when someone steps in it."
icon_state = ""
cost = 0
shift_mode = SHIFTED_OR_NOT
ab_sound = 'sound/effects/stealthoff.ogg'
/obj/effect/rakshasa_ability/trap/do_ability()
if(!..())
return
var/goo_sounds = list (
'sound/rakshasa/Corrosion1.ogg',
'sound/rakshasa/Corrosion2.ogg',
'sound/rakshasa/Corrosion3.ogg'
)
var/sound = pick(goo_sounds)
playsound(my_kin.loc, sound, 100, 1)
new /obj/structure/gootrap (my_kin.loc)
/////////////////////////////////////////////////////////////////
/obj/effect/rakshasa_ability/flicker
ability_name = "Flicker Lights"
desc = "Flicker the lights."
icon_state = ""
cost = 0
shift_mode = SHIFTED_OR_NOT
ab_sound = 'sound/effects/stealthoff.ogg'
/obj/effect/rakshasa_ability/flicker/do_ability()
if(!..())
return
my_kin.rakshasa_flicker()
////////////////////////////////////////////////////////////////
//PROCS
//PHASE SHIFTING
////////////////////////////////////////////////////////////////
//Rakshasa's phase shifts are now more stealthy. No announcement on them phasing in or out. Also, an extra phaseshift with no lights flickering. For flavor. There's probably a better way of doing this, butt fuck it.
/mob/living/simple_mob/shadekin/proc/rakshasa_shift()
var/turf/T = get_turf(src)
if(!T.CanPass(src,T) || loc != T)
to_chat(src,span_warning("You can't use that here!"))
return FALSE
forceMove(T)
var/original_canmove = canmove
SetStunned(0)
SetWeakened(0)
if(buckled)
buckled.unbuckle_mob()
if(pulledby)
pulledby.stop_pulling()
stop_pulling()
canmove = FALSE
//Shifting in
if(ability_flags & AB_PHASE_SHIFTED)
ability_flags &= ~AB_PHASE_SHIFTED
name = real_name
for(var/belly in vore_organs)
var/obj/belly/B = belly
B.escapable = initial(B.escapable)
overlays.Cut()
alpha = initial(alpha)
invisibility = initial(invisibility)
see_invisible = initial(see_invisible)
incorporeal_move = initial(incorporeal_move)
density = initial(density)
force_max_speed = initial(force_max_speed)
//Cosmetics mostly
flick("tp_in",src)
sleep(5) //The duration of the TP animation
canmove = original_canmove
//Potential phase-in vore
if(can_be_drop_pred) //Toggleable in vore panel
var/list/potentials = living_mobs(0)
if(potentials.len)
var/mob/living/target = pick(potentials)
if(istype(target) && target.devourable && target.can_be_drop_prey && vore_selected)
target.forceMove(vore_selected)
to_chat(target,span_warning("\The [src] phases in around you, [vore_selected.vore_verb]ing you into their [vore_selected.name]!"))
// Do this after the potential vore, so we get the belly
update_icon()
//Affect nearby lights
for(var/obj/machinery/light/L in GLOB.machines)
if(L.z != z || get_dist(src,L) > 10)
continue
L.flicker(10)
//Shifting out
else
ability_flags |= AB_PHASE_SHIFTED
real_name = name
name = "Something"
for(var/belly in vore_organs)
var/obj/belly/B = belly
B.escapable = FALSE
overlays.Cut()
flick("tp_out",src)
sleep(5)
invisibility = INVISIBILITY_LEVEL_TWO
see_invisible = INVISIBILITY_LEVEL_TWO
update_icon()
alpha = 127
canmove = original_canmove
incorporeal_move = TRUE
density = FALSE
force_max_speed = TRUE
////////////////////////////////////////////////////////////////
/mob/living/simple_mob/shadekin/proc/stealth_shift()
var/turf/T = get_turf(src)
if(!T.CanPass(src,T) || loc != T)
to_chat(src,span_warning("You can't use that here!"))
return FALSE
forceMove(T)
var/original_canmove = canmove
SetStunned(0)
SetWeakened(0)
if(buckled)
buckled.unbuckle_mob()
if(pulledby)
pulledby.stop_pulling()
stop_pulling()
canmove = FALSE
//Shifting in
if(ability_flags & AB_PHASE_SHIFTED)
ability_flags &= ~AB_PHASE_SHIFTED
name = real_name
for(var/belly in vore_organs)
var/obj/belly/B = belly
B.escapable = initial(B.escapable)
overlays.Cut()
alpha = initial(alpha)
invisibility = initial(invisibility)
see_invisible = initial(see_invisible)
incorporeal_move = initial(incorporeal_move)
density = initial(density)
force_max_speed = initial(force_max_speed)
//Cosmetics mostly
flick("tp_in",src)
sleep(5) //The duration of the TP animation
canmove = original_canmove
//Potential phase-in vore
if(can_be_drop_pred) //Toggleable in vore panel
var/list/potentials = living_mobs(0)
if(potentials.len)
var/mob/living/target = pick(potentials)
if(istype(target) && target.devourable && target.can_be_drop_prey && vore_selected)
target.forceMove(vore_selected)
to_chat(target,span_warning("\The [src] phases in around you, [vore_selected.vore_verb]ing you into their [vore_selected.name]!"))
// Do this after the potential vore, so we get the belly
update_icon()
//Shifting out
else
ability_flags |= AB_PHASE_SHIFTED
real_name = name
name = "Something"
for(var/belly in vore_organs)
var/obj/belly/B = belly
B.escapable = FALSE
overlays.Cut()
flick("tp_out",src)
sleep(5)
invisibility = INVISIBILITY_LEVEL_TWO
see_invisible = INVISIBILITY_LEVEL_TWO
update_icon()
alpha = 127
canmove = original_canmove
incorporeal_move = TRUE
density = FALSE
force_max_speed = TRUE
//LIGHT FLICKERING
////////////////////////////////////////////////////////////////
//A flicker proc. Because apparently putting this straight into the ability button doesn't work.
/mob/living/simple_mob/shadekin/proc/rakshasa_flicker()
for(var/obj/machinery/light/L in GLOB.machines)
if(L.z != z || get_dist(src,L) > 10)
continue
L.flicker(10)

View File

@@ -71,17 +71,12 @@
var/datum/component/shadekin/comp = /datum/component/shadekin //Component that holds all the shadekin vars.
var/dark_gains = 0 //Last tick's change in energy
var/ability_flags = 0 //Flags for active abilities
var/obj/screen/darkhud //Holder to update this icon
var/obj/screen/energyhud //Holder to update this icon
var/list/shadekin_abilities
var/check_for_observer = FALSE
var/check_timer = 0
var/doing_phase = FALSE // Prevent bugs when spamming phase button
var/respite_activating = FALSE //CHOMPEdit - Dark Respite
var/list/active_dark_maws = list()
/mob/living/simple_mob/shadekin/Initialize(mapload)
//You spawned the prototype, and want a totally random one.
if(type == /mob/living/simple_mob/shadekin)
@@ -100,6 +95,7 @@
flags |= ATOM_INITIALIZED
return INITIALIZE_HINT_QDEL
comp = LoadComponent(comp)
set_eye_energy()
if(icon_state == "map_example")
icon_state = pick("white","dark","brown")
@@ -128,11 +124,6 @@
if(eye_desc)
desc += " This one has [eye_desc]!"
var/list/ability_types = subtypesof(/obj/effect/shadekin_ability)
shadekin_abilities = list()
for(var/type in ability_types)
shadekin_abilities += new type(src)
update_icon()
add_verb(src, /mob/proc/adjust_hive_range)
@@ -204,11 +195,11 @@
/mob/living/simple_mob/shadekin/Life()
. = ..()
if(ability_flags & AB_PHASE_SHIFTED)
if(comp.in_phase)
density = FALSE
//Convert spare nutrition into energy at a certain ratio
if(. && nutrition > initial(nutrition) && comp.dark_energy < 100 && !(ability_flags | AB_DARK_RESPITE)) //CHOMPEdit - Dark Respite
if(. && nutrition > initial(nutrition) && comp.dark_energy < 100)
nutrition = max(0, nutrition-5)
comp.dark_energy = min(100,comp.dark_energy+1)
if(!client && check_for_observer && check_timer++ > 5)
@@ -218,9 +209,9 @@
if(!issimplekin(M))
non_kin_count ++
// Technically can be combined with ||, they call the same function, but readability is poor
if(!non_kin_count && (ability_flags & AB_PHASE_SHIFTED))
if(!non_kin_count && (comp.in_phase))
phase_shift() // shifting back in, nobody present
else if (non_kin_count && !(ability_flags & AB_PHASE_SHIFTED))
else if (non_kin_count && !(comp.in_phase))
phase_shift() // shifting out, scaredy
/mob/living/simple_mob/shadekin/update_icon()
@@ -233,34 +224,23 @@
add_overlay(tailimage)
add_overlay(eye_icon_state)
/mob/living/simple_mob/shadekin/update_misc_tabs()
..()
var/list/L = list()
for(var/obj/effect/shadekin_ability/A as anything in shadekin_abilities)
var/client/C = client
var/img
if(C && istype(C)) //sanity checks
if(A.ability_name in C.misc_cache)
img = C.misc_cache[A.ability_name]
else
img = icon2html(A,C,sourceonly=TRUE)
C.misc_cache[A.ability_name] = img
L[++L.len] = list("[A.ability_name]", A.ability_name, img, A.atom_button_text(), REF(A))
misc_tabs["Shadekin"] = L
//They phase back to the dark when killed
/mob/living/simple_mob/shadekin/death(gibbed, deathmessage = "phases to somewhere far away!")
//CHOMPEdit Begin - Dark Respite
if(respite_activating)
var/special_handling = TRUE //varswitch for downstream
if(!special_handling)
cut_overlays()
icon_state = ""
flick("tp_out",src)
QDEL_IN(src, 1 SECOND)
. = ..(FALSE, deathmessage)
else
if(comp.respite_activating)
return
//CHOMPEdit End
cut_overlays()
flick("tp_out",src)
//CHOMPEdit Begin - Actually phase to the dark on death
var/area/current_area = get_area(src)
if((ability_flags & AB_DARK_RESPITE) || current_area.flag_check(AREA_LIMIT_DARK_RESPITE))
if((comp.in_dark_respite) || current_area.flag_check(AREA_LIMIT_DARK_RESPITE))
icon_state = ""
spawn(1 SECOND)
qdel(src) //Back from whence you came!
@@ -276,14 +256,14 @@
return ..(FALSE, deathmessage)
src.visible_message("<b>\The [src.name]</b> [deathmessage]")
respite_activating = TRUE
visible_message("<b>\The [src.name]</b> [deathmessage]")
comp.respite_activating = TRUE
drop_l_hand()
drop_r_hand()
comp.dark_energy = 0
ability_flags |= AB_DARK_RESPITE
comp.in_dark_respite = TRUE
invisibility = INVISIBILITY_LEVEL_TWO
adjustFireLoss(-(getFireLoss() / 2))
@@ -300,33 +280,35 @@
to_chat(belly.owner, span_notice("\The [src.name] suddenly vanishes within your [belly.name]"))
forceMove(pick(GLOB.latejoin_thedark))
flick("tp_in",src)
respite_activating = FALSE
belly.owner.handle_belly_update() // CHOMPEdit
comp.respite_activating = FALSE
comp.in_dark_respite = TRUE
belly.owner.handle_belly_update()
clear_fullscreen("belly")
if(hud_used)
if(!hud_used.hud_shown)
toggle_hud_vis()
stop_sound_channel(CHANNEL_PREYLOOP)
spawn(10 MINUTES)
ability_flags &= ~AB_DARK_RESPITE
movement_cooldown = initial(movement_cooldown)
to_chat(src, span_notice("You feel like you can leave the Dark again"))
addtimer(CALLBACK(src, PROC_REF(can_leave_dark)), 10 MINUTES, TIMER_DELETE_ME)
else
spawn(1 SECOND)
respite_activating = FALSE
addtimer(CALLBACK(src, PROC_REF(enter_the_dark)), 1 SECOND, TIMER_DELETE_ME)
addtimer(CALLBACK(src, PROC_REF(can_leave_dark)), 15 MINUTES, TIMER_DELETE_ME)
/mob/living/simple_mob/shadekin/enter_the_dark()
comp.respite_activating = FALSE
comp.in_dark_respite = TRUE
forceMove(pick(GLOB.latejoin_thedark))
update_icon()
flick("tp_in",src)
invisibility = initial(invisibility)
respite_activating = FALSE
comp.respite_activating = FALSE
spawn(15 MINUTES)
ability_flags &= ~AB_DARK_RESPITE
/mob/living/simple_mob/shadekin/can_leave_dark()
comp.in_dark_respite = FALSE
movement_cooldown = initial(movement_cooldown)
to_chat(src, span_notice("You feel like you can leave the Dark again"))
//CHOMPEdit End
/* //VOREStation AI Temporary Removal
//Blue-eyes want to nom people to heal them
@@ -342,101 +324,40 @@
//They reach nutritional equilibrium (important for blue-eyes healbelly)
/mob/living/simple_mob/shadekin/Life()
if((. = ..()))
handle_shade()
comp.handle_comp()
/mob/living/simple_mob/shadekin/proc/set_eye_energy()
switch(eye_state)
//Blue has constant, steady (slow) regen and ignores darkness.
if(BLUE_EYES)
comp.set_light_and_darkness(0.75,0.75)
comp.nutrition_conversion_scaling = 0.5
if(RED_EYES)
comp.set_light_and_darkness(-0.5,0.5)
comp.nutrition_conversion_scaling = 2
if(PURPLE_EYES)
comp.set_light_and_darkness(-0.5,1)
comp.nutrition_conversion_scaling = 1
if(YELLOW_EYES)
comp.set_light_and_darkness(-2,3)
comp.nutrition_conversion_scaling = 0.5
if(GREEN_EYES)
comp.set_light_and_darkness(0.125,2)
comp.nutrition_conversion_scaling = 0.5
if(ORANGE_EYES)
comp.set_light_and_darkness(-0.25,0.75)
comp.nutrition_conversion_scaling = 1.5
/mob/living/simple_mob/shadekin/is_incorporeal()
if(ability_flags & AB_PHASE_SHIFTED)
if(comp.in_phase)
return TRUE
return FALSE
/mob/living/simple_mob/shadekin/handle_atmos()
if(ability_flags & AB_PHASE_SHIFTED)
if(comp.in_phase)
return
else
return .=..()
/mob/living/simple_mob/shadekin/proc/handle_shade()
//Shifted kin don't gain/lose energy (and save time if we're at the cap)
var/darkness = 1
var/turf/T = get_turf(src)
if(!T)
dark_gains = 0
return
var/brightness = T.get_lumcount() //Brightness in 0.0 to 1.0
darkness = 1-brightness //Invert
if(ability_flags & AB_PHASE_SHIFTED)
dark_gains = 0
else
//Heal (very) slowly in good darkness
if(darkness >= 0.75)
adjustFireLoss(-0.05)
adjustBruteLoss(-0.05)
adjustToxLoss(-0.05)
switch(eye_state)
//Blue has constant, steady (slow) regen and ignores darkness.
if(BLUE_EYES)
dark_gains = 0.5
//Red has extremely tiny energy buildup in dark, none in light, and hunts for energy.
if(RED_EYES)
if(darkness >= 0.75)
dark_gains = 0.25
//Purple eyes have moderate gains in darkness and loss in light.
if(PURPLE_EYES)
dark_gains = round((darkness - 0.5) * 2, 0.1)
//Yellow has extreme gains in darkness and loss in light.
if(YELLOW_EYES)
dark_gains = round((darkness - 0.5) * 4, 0.1)
//Similar to blues, but passive is less, and affected by dark
if(GREEN_EYES)
dark_gains = 0.25
dark_gains += round((darkness - 0.5), 0.1)
//More able to get energy out of the dark, worse attack gains tho
if(ORANGE_EYES)
if(darkness >= 0.65)
dark_gains = 0.30
comp.dark_energy = max(0,min(initial(comp.dark_energy),comp.dark_energy + dark_gains))
//CHOMPEdit Begin - Dark Respite
if(ability_flags & AB_DARK_RESPITE)
comp.dark_energy = 0
//CHOMPEdit End
if(comp.dark_energy_infinite)
comp.dark_energy = 100
//Update turf darkness hud
if(darkhud)
switch(darkness)
if(0.80 to 1.00)
darkhud.icon_state = "dark2"
if(0.60 to 0.80)
darkhud.icon_state = "dark1"
if(0.40 to 0.60)
darkhud.icon_state = "dark"
if(0.20 to 0.40)
darkhud.icon_state = "dark-1"
if(0.00 to 0.20)
darkhud.icon_state = "dark-2"
//Update energy storage hud
if(energyhud)
switch(comp.dark_energy)
if(80 to INFINITY)
energyhud.icon_state = "energy0"
if(60 to 80)
energyhud.icon_state = "energy1"
if(40 to 60)
energyhud.icon_state = "energy2"
if(20 to 40)
energyhud.icon_state = "energy3"
if(0 to 20)
energyhud.icon_state = "energy4"
/* //VOREStation AI Removal
//Friendly ones wander towards people, maybe shy-ly if they are set to shy
/mob/living/simple_mob/shadekin/handle_wander_movement()
@@ -519,26 +440,6 @@
comp.dark_energy += gains
//Special hud elements for darkness and energy gains
/mob/living/simple_mob/shadekin/extra_huds(var/datum/hud/hud,var/icon/ui_style,var/list/hud_elements)
//Darkness hud
darkhud = new /obj/screen()
darkhud.icon = ui_style
darkhud.icon_state = "dark"
darkhud.name = "darkness"
darkhud.screen_loc = "CENTER-2:16,SOUTH:5" //Left of the left hand
darkhud.alpha = 150
hud_elements |= darkhud
//Energy hud
energyhud = new /obj/screen()
energyhud.icon = ui_style
energyhud.icon_state = "energy0"
energyhud.name = "energy"
energyhud.screen_loc = "CENTER+1:16,SOUTH:5" //Right of the right hand
energyhud.alpha = 150
hud_elements |= energyhud
// When someone clicks us with an empty hand
/mob/living/simple_mob/shadekin/attack_hand(mob/living/carbon/human/M as mob)
. = ..()

View File

@@ -56,17 +56,26 @@
The hot goop you float in makes it hard to breathe; all consuming of space and light. \
Your body feels hot, growing weaker, more tired. Draining. Darkness coming. \
You struggle to stay awake while floating helplessly in the goo."
player_msg = "You are Rakshasa. You are not to directly harm crew, only consume. You never speak a language."
player_msg = "You are Rakshasa. You are not to directly harm crew, only consume. You never speak a language. You have special emotes: 'evillaugh', 'evilno', 'evilbreath', 'evilbreath2', and 'goodripsound'"
maxHealth = 1000000000000
health = 1000000000000
eye_state = "BLUE EYES"
eye_icon_state = "e_rakshasa"
comp = /datum/component/shadekin/full/rakshasa
/mob/living/simple_mob/shadekin/red/rakshasa/Initialize(mapload)
. = ..()
if(comp)
comp.dark_energy_infinite = TRUE
/mob/living/simple_mob/shadekin/red/rakshasa/get_available_emotes()
. = global._simple_mob_default_emotes.Copy()
. += /decl/emote/audible/evil_laugh
. += /decl/emote/audible/evil_no
. += /decl/emote/audible/evil_breathing
. += /decl/emote/audible/evil_breathing_2
. += /decl/emote/audible/goodripsound
/mob/living/simple_mob/shadekin/blue/luna
name = "Luna"
desc = "She appears to be a fuzzy critter of some sort. Her eyes shimmer a dark blue, glancing around curiously."

View File

@@ -409,6 +409,7 @@ var/global/list/light_type_cache = list()
else
base_state = "flamp"
..()
/obj/machinery/light/proc/set_alert_atmos()
if(!shows_alerts)
return
@@ -736,27 +737,35 @@ var/global/list/light_type_cache = list()
set_light(brightness_range * bulb_emergency_brightness_mul, max(bulb_emergency_pow_min, bulb_emergency_pow_mul * (cell.charge / cell.maxcharge)), bulb_emergency_colour)
return TRUE
/obj/machinery/light/proc/flicker(var/amount = rand(10, 20))
/obj/machinery/light/proc/flicker(var/amount = rand(10, 20), var/flicker_color)
if(flickering) return
if(on && status == LIGHT_OK)
flickering = 1
do_flicker(amount)
do_flicker(amount, flicker_color, brightness_color, brightness_color_ns)
/obj/machinery/light/proc/do_flicker(remaining_flicks)
/obj/machinery/light/proc/do_flicker(remaining_flicks, flicker_color, original_color, original_color_ns)
SHOULD_NOT_OVERRIDE(TRUE)
PRIVATE_PROC(TRUE)
if(status != LIGHT_OK)
flickering = 0
return
on = !on
if(flicker_color && brightness_color != flicker_color)
brightness_color = flicker_color
brightness_color_ns = flicker_color
update(0) //Yes. This is done here and then immediately followed up with another update(0). Why does it need that? I have no clue. But a single update(0) does not work.
update(0)
if(!on) // Only play when the light turns off.
playsound(src, 'sound/effects/light_flicker.ogg', 50, 1)
if(remaining_flicks > 0)
remaining_flicks--
addtimer(CALLBACK(src, PROC_REF(do_flicker), remaining_flicks), rand(5, 15), TIMER_DELETE_ME)
addtimer(CALLBACK(src, PROC_REF(do_flicker), remaining_flicks, flicker_color, original_color, original_color_ns), rand(5, 15), TIMER_DELETE_ME)
return
//All this happens after our final flicker.
on = (status == LIGHT_OK)
brightness_color = original_color
brightness_color_ns = original_color_ns
update(0)
update(0)
flickering = 0

View File

@@ -174,46 +174,46 @@
/obj/item/gun/proc/special_check(var/mob/user)
if(!isliving(user))
return 0
return FALSE
if(!user.IsAdvancedToolUser())
return 0
return FALSE
if(isanimal(user))
var/mob/living/simple_mob/S = user
if(!S.IsHumanoidToolUser(src))
return 0
return FALSE
var/mob/living/M = user
if(istype(M))
if(M.has_modifier_of_type(/datum/modifier/underwater_stealth))
to_chat(user, span_warning("You cannot use guns whilst hiding underwater!"))
return 0
return FALSE
else if(M.has_modifier_of_type(/datum/modifier/phased_out))
to_chat(user, span_warning("You cannot use guns whilst incorporeal!"))
return FALSE
else if(M.has_modifier_of_type(/datum/modifier/rednet))
to_chat(user, span_warning("Your gun refuses to fire!"))
return 0
return FALSE
else if(M.has_modifier_of_type(/datum/modifier/trait/thickdigits))
to_chat(user, span_warning("Your hands can't pull the trigger!!"))
return 0
return FALSE
else if(M.has_modifier_of_type(/datum/modifier/shield_projection/melee_focus))
to_chat(user, span_warning("The shield projection around you prevents you from using anything but melee!!"))
return 0
return FALSE
if(dna_lock && attached_lock.stored_dna)
if(!authorized_user(user))
if(attached_lock.safety_level == 0)
to_chat(M, span_danger("\The [src] buzzes in dissapointment and displays an invalid DNA symbol."))
return 0
return FALSE
if(!attached_lock.exploding)
if(attached_lock.safety_level == 1)
to_chat(M, span_danger("\The [src] hisses in dissapointment."))
visible_message(span_game(span_say(span_name("\The [src]") + " announces, \"Self-destruct occurring in ten seconds.\"")), span_game(span_say(span_name("\The [src]") + " announces, \"Self-destruct occurring in ten seconds.\"")))
attached_lock.exploding = 1
spawn(100)
explosion(src, 0, 0, 3, 4)
sleep(1)
qdel(src)
return 0
addtimer(CALLBACK(src, PROC_REF(lock_explosion)), 10 SECONDS, TIMER_DELETE_ME)
return FALSE
if(HULK in M.mutations)
to_chat(M, span_danger("Your fingers are much too large for the trigger guard!"))
return 0
return FALSE
if((CLUMSY in M.mutations) && prob(40)) //Clumsy handling
var/obj/P = consume_next_projectile()
if(P)
@@ -227,8 +227,12 @@
M.drop_item()
else
handle_click_empty(user)
return 0
return 1
return FALSE
return TRUE
/obj/item/gun/proc/lock_explosion()
explosion(src, 0, 0, 3, 4)
QDEL_IN(src, 1)
/obj/item/gun/emp_act(severity)
for(var/obj/O in contents)

View File

@@ -53,9 +53,11 @@
return 1
/obj/structure/table/MouseDrop_T(obj/O, mob/user, src_location, over_location, src_control, over_control, params)
if(user.is_incorporeal())
if(user.stat)
return
if(ismob(O.loc)) //If placing an item
if(can_reinforce && isliving(user) && istype(O, /obj/item/stack/material) && user.get_active_hand() == O && Adjacent(user))
reinforce_table(O, user)
else if(ismob(O.loc)) //If placing an item
if(!isitem(O) || user.get_active_hand() != O)
return ..()
if(isrobot(user))

View File

@@ -193,12 +193,6 @@ var/list/table_icon_cache = list()
visible_message(span_infoplain(span_bold("\The [user]") + " scratches at \the [src]!"))
return ..()
/obj/structure/table/MouseDrop_T(obj/item/stack/material/what, mob/user)
if(can_reinforce && isliving(user) && (!user.stat) && istype(what) && user.get_active_hand() == what && Adjacent(user))
reinforce_table(what, user)
else
return ..()
/obj/structure/table/proc/reinforce_table(obj/item/stack/material/S, mob/user)
if(reinforced)
to_chat(user, span_warning("\The [src] is already reinforced!"))

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,47 @@
//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
"a" = (
/turf/template_noop,
/area/template_noop)
"B" = (
/turf/simulated/floor/weird_things/dark,
/area/template_noop)
"O" = (
/obj/structure/dark_portal/minion,
/turf/template_noop,
/area/template_noop)
(1,1,1) = {"
a
B
B
a
a
"}
(2,1,1) = {"
B
a
B
B
B
"}
(3,1,1) = {"
B
B
O
B
a
"}
(4,1,1) = {"
B
B
B
B
a
"}
(5,1,1) = {"
B
a
B
B
a
"}

View File

@@ -57,13 +57,11 @@
last_pulse = world.time
use_power(1500)
for (var/mob/O in viewers(src, null))
if(get_dist(src, O) > range)
for(var/mob/living/O in range(range, src))
var/datum/component/shadekin/SK = O.get_shadekin_component()
if(!SK)
continue
if(ishuman(O))
var/mob/living/carbon/human/H = O
if(H.get_species() == SPECIES_SHADEKIN && (H.ability_flags & AB_PHASE_SHIFTED))
H.attack_dephase(null, src)
SK.attack_dephase(null, src) //Won't dephase them if they're not in phase. It has built in checks.
/obj/machinery/bluespace_denier/emp_act(severity)
if(stat & (BROKEN|NOPOWER))

View File

@@ -2,8 +2,3 @@
GLOBAL_LIST_INIT(shell_module_blacklist, list(
"Sci-borg", "Research"
))
GLOBAL_LIST_EMPTY(latejoin_gatewaystation)
GLOBAL_LIST_EMPTY(latejoin_plainspath)
GLOBAL_LIST_EMPTY(latejoin_fueldepot)
GLOBAL_LIST_EMPTY(latejoin_tyrvillage)
GLOBAL_LIST_EMPTY(latejoin_thedark)

View File

@@ -1,386 +0,0 @@
/mob/living/carbon/human/proc/shadekin_ability_check()
var/datum/species/shadekin/SK = species
if(!istype(SK))
to_chat(src, span_warning("Only a shadekin can use that!"))
return FALSE
if(stat)
to_chat(src, span_warning("Can't use that ability in your state!"))
return FALSE
if((ability_flags & AB_DARK_RESPITE || has_modifier_of_type(/datum/modifier/dark_respite)) && !(ability_flags & AB_PHASE_SHIFTED))
to_chat(src, span_warning("You can't use that so soon after an emergency warp!"))
return FALSE
return TRUE
//toggle proc for toggling gentle/normal phasing
/mob/living/carbon/human/proc/phase_strength_toggle()
set name = "Toggle Phase Strength"
set desc = "Toggle strength of phase. Gentle but slower, or faster but destructive to lights."
set category = "Abilities.Shadekin"
var/datum/species/shadekin/SK = species
if(!istype(SK))
to_chat(src, span_warning("Only a shadekin can use that!"))
return FALSE
if(SK.phase_gentle)
to_chat(src, span_notice("Phasing toggled to Normal. You may damage lights."))
SK.phase_gentle = 0
else
to_chat(src, span_notice("Phasing toggled to Gentle. You won't damage lights, but concentrating on that incurs a short stun."))
SK.phase_gentle = 1
/datum/power/shadekin/dark_tunneling
name = "Dark Tunneling (100) (Once)"
desc = "Make a passage to the dark."
verbpath = /mob/living/carbon/human/proc/dark_tunneling
ability_icon_state = "minion0"
/mob/living/carbon/human/proc/dark_tunneling()
set name = "Dark Tunneling (100) (Once)"
set desc = "Make a passage to the dark."
set category = "Abilities.Shadekin"
var/template_id = "dark_portal"
var/datum/map_template/shelter/template
var/ability_cost = 100
var/tunnel_time = 60 SECONDS
if(!shadekin_ability_check())
return FALSE
if(ability_flags & AB_PHASE_SHIFTED)
to_chat(src, span_warning("You can't use that while phase shifted!"))
return FALSE
if(ability_flags & AB_DARK_TUNNEL)
to_chat(src, span_warning("You have already made a tunnel to the Dark!"))
return FALSE
if(!template)
template = SSmapping.shelter_templates[template_id]
if(!template)
throw EXCEPTION("Shelter template ([template_id]) not found!")
return FALSE
var/turf/deploy_location = get_turf(src)
var/status = template.check_deploy(deploy_location)
switch(status)
//Not allowed due to /area technical reasons
if(SHELTER_DEPLOY_BAD_AREA)
to_chat(src, span_warning("A tunnel to the Dark will not function in this area."))
//Anchored objects or no space
if(SHELTER_DEPLOY_BAD_TURFS, SHELTER_DEPLOY_ANCHORED_OBJECTS)
var/width = template.width
var/height = template.height
to_chat(src, span_warning("There is not enough open area for a tunnel to the Dark to form! You need to clear a [width]x[height] area!"))
if(status != SHELTER_DEPLOY_ALLOWED)
return FALSE
var/turf/T = deploy_location
var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread()
smoke.attach(T)
smoke.set_up(10, 0, T)
smoke.start()
src.visible_message(span_notice("[src] begins pulling dark energies around themselves."))
if(do_after(src, tunnel_time))
playsound(src, 'sound/effects/phasein.ogg', 100, 1)
src.visible_message(span_notice("[src] finishes pulling dark energies around themselves, creating a portal."))
log_and_message_admins("[key_name_admin(src)] created a tunnel to the dark at [get_area(T)]!")
template.annihilate_plants(deploy_location)
template.load(deploy_location, centered = TRUE)
template.update_lighting(deploy_location)
ability_flags |= AB_DARK_TUNNEL
shadekin_adjust_energy(-(ability_cost - 10)) //Leaving enough energy to actually activate the portal
return TRUE
return FALSE
/datum/power/shadekin/dark_respite
name = "Dark Respite (Only in Dark)"
desc = "Focus yourself on healing any injuries sustained."
verbpath = /mob/living/carbon/human/proc/dark_respite
ability_icon_state = "ling_anatomic_panacea"
/mob/living/carbon/human/proc/dark_respite()
set name = "Dark Respite (Only in Dark)"
set desc = "Focus yourself on healing any injuries sustained."
set category = "Abilities.Shadekin"
var/datum/species/shadekin/SK = species
if(!istype(SK))
to_chat(src, span_warning("Only a shadekin can use that!"))
return FALSE
if(!istype(get_area(src), /area/shadekin))
to_chat(src, span_warning("Can only trigger Dark Respite in the Dark!"))
return FALSE
if(stat)
to_chat(src, span_warning("Can't use that ability in your state!"))
return FALSE
if(ability_flags & AB_DARK_RESPITE)
to_chat(src, span_warning("You can't use that so soon after an emergency warp!"))
return FALSE
if(has_modifier_of_type(/datum/modifier/dark_respite) && !SK.manual_respite)
to_chat(src, span_warning("You cannot manually end a Dark Respite triggered by an emergency warp!"))
if(ability_flags & AB_PHASE_SHIFTED)
to_chat(src, span_warning("You can't use that while phase shifted!"))
return FALSE
if(has_modifier_of_type(/datum/modifier/dark_respite))
to_chat(src, span_notice("You stop focusing the Dark on healing yourself."))
SK.manual_respite = FALSE
remove_a_modifier_of_type(/datum/modifier/dark_respite)
return TRUE
to_chat(src, span_notice("You start focusing the Dark on healing yourself. (Leave the dark or trigger the ability again to end this.)"))
SK.manual_respite = TRUE
add_modifier(/datum/modifier/dark_respite)
return TRUE
/datum/map_template/shelter/dark_portal
name = "Dark Portal"
shelter_id = "dark_portal"
description = "A portal to a section of the Dark"
mappath = "modular_chomp/maps/submaps/shelters/dark_portal.dmm"
/datum/map_template/shelter/dark_portal/New()
. = ..()
blacklisted_turfs = typecacheof(list(/turf/unsimulated))
GLOB.blacklisted_areas = typecacheof(list(/area/centcom, /area/shadekin))
/obj/effect/abstract/dark_maw
var/mob/living/owner = null
var/obj/belly/target = null
icon = 'modular_chomp/icons/obj/Shadekin_powers_2.dmi'
icon_state = "dark_maw_waiting"
/obj/effect/abstract/dark_maw/Initialize(mapload, var/mob/living/user, var/trigger_now = 0)
. = ..()
if(!isturf(loc))
return INITIALIZE_HINT_QDEL
var/turf/T = loc
if(T.get_lumcount() >= 0.5)
visible_message(span_notice("A set of shadowy lines flickers away in the light."))
icon_state = "dark_maw_used"
return INITIALIZE_HINT_QDEL
if(istype(user))
owner = user
target = owner.vore_selected
var/mob/living/target_user = null
for(var/mob/living/L in T)
if(L != owner && !L.incorporeal_move)
target_user = L
break
if(istype(target_user))
triggered_by(target_user, 1)
// to trigger rebuild
else if(trigger_now)
icon_state = "dark_maw_used"
flick("dark_maw_tr", src)
visible_message(span_warning("A set of crystals suddenly springs from the ground and shadowy tendrils wrap around nothing before vanishing."))
QDEL_IN(src, 3 SECONDS)
else
var/mob/living/carbon/human/carbon_owner = owner
var/mob/living/simple_mob/shadekin/sm_owner = owner
if(istype(carbon_owner))
var/datum/species/shadekin/SK = carbon_owner.species
if(istype(SK))
SK.active_dark_maws += src
else if(istype(sm_owner))
sm_owner.active_dark_maws += src
flick("dark_maw", src)
START_PROCESSING(SSobj, src)
/obj/effect/abstract/dark_maw/Destroy()
STOP_PROCESSING(SSobj, src)
if(istype(owner))
var/mob/living/carbon/human/carbon_owner = owner
var/mob/living/simple_mob/shadekin/sm_owner = owner
if(istype(carbon_owner))
var/datum/species/shadekin/SK = carbon_owner.species
if(istype(SK))
SK.active_dark_maws -= src
else if(istype(sm_owner))
sm_owner.active_dark_maws -= src
target = null
owner = null
return ..()
/obj/effect/abstract/dark_maw/Crossed(O)
. = ..()
if(!isliving(O))
return
if(icon_state != "dark_maw_waiting")
return
var/mob/living/L = O
if(!L.incorporeal_move && (!owner || L != owner))
triggered_by(L)
/obj/effect/abstract/dark_maw/process()
var/turf/T = get_turf(src)
if(!istype(T) || T.get_lumcount() >= 0.5)
dispel()
/obj/effect/abstract/dark_maw/proc/dispel()
if(icon_state == "dark_maw_waiting")
visible_message(span_notice("A set of shadowy lines flickers away in the light."))
else
visible_message(span_notice("The crystals and shadowy tendrils dissipate with the light shone on it."))
icon_state = "dark_maw_used"
qdel(src)
/obj/effect/abstract/dark_maw/proc/triggered_by(var/mob/living/L, var/triggered_instantly = 0)
STOP_PROCESSING(SSobj, src)
icon_state = "dark_maw_used"
flick("dark_maw_tr", src)
L.AdjustStunned(4)
visible_message(span_warning("A set of crystals spring out of the ground and shadowy tendrils start wrapping around [L]."))
if(owner && !triggered_instantly)
to_chat(owner, span_warning("A dark maw you deployed has triggered!"))
addtimer(CALLBACK(src, PROC_REF(do_trigger), L), 1 SECOND, TIMER_DELETE_ME)
/obj/effect/abstract/dark_maw/proc/do_trigger(var/mob/living/L)
var/will_vore = 1
if(!owner || !(target in owner) || !L.devourable || !L.can_be_drop_prey || !owner.can_be_drop_pred || !L.phase_vore)
will_vore = 0
if(!src || src.gc_destroyed)
//We got deleted probably, do nothing more
return
if(L.loc != get_turf(src))
visible_message(span_notice("The shadowy tendrils fail to catch anything and dissipate."))
qdel(src)
return
if(will_vore)
visible_message(span_warning("The shadowy tendrils grab around [L] and drag them into the floor, leaving nothing behind."))
L.forceMove(target)
qdel(src)
return
var/obj/effect/energy_net/dark/net = new /obj/effect/energy_net/dark(get_turf(src))
if(net.buckle_mob(L))
visible_message(span_warning("The shadowy tendrils wrap around [L] and traps them in a net of dark energy."))
else
visible_message(span_notice("The shadowy tendrils wrap around [L] and then dissipate, leaving them in place."))
qdel(src)
/obj/effect/energy_net/dark
name = "dark net"
desc = "It's a net made of dark energy."
icon = 'modular_chomp/icons/obj/Shadekin_powers_2.dmi'
icon_state = "dark_net"
escape_time = 30 SECONDS
/obj/effect/energy_net/dark/user_unbuckle_mob(mob/living/buckled_mob, mob/user)
if(istype(user,/mob/living/simple_mob/shadekin))
visible_message(span_danger("[user] dissipates \the [src] with a touch!"))
unbuckle_mob(buckled_mob)
return
if(istype(user,/mob/living/carbon/human))
var/mob/living/carbon/human/H = user
var/datum/species/shadekin/SK = H.species
if(istype(SK))
visible_message(span_danger("[user] dissipates \the [src] with a touch!"))
unbuckle_mob(buckled_mob)
return
. = ..()
/obj/effect/energy_net/dark/process()
. = ..()
var/turf/T = get_turf(src)
if(!istype(T) || T.get_lumcount() >= 0.6)
visible_message(span_notice("The tangle of dark tendrils fades away in the light."))
qdel(src)
/datum/power/shadekin/dark_maw
name = "Dark Maw (20)"
desc = "Create a trap to capture others, or steal people from phase"
verbpath = /mob/living/carbon/human/proc/dark_maw
ability_icon_state = "dark_maw_ic"
/mob/living/carbon/human/proc/dark_maw()
set name = "Dark Maw (20)"
set desc = "Create a trap to capture others, or steal people from phase"
set category = "Abilities.Shadekin"
var/ability_cost = 20
if(!shadekin_ability_check())
return FALSE
if(shadekin_get_energy() < ability_cost)
to_chat(src, span_warning("Not enough energy for that ability!"))
return FALSE
var/turf/T = get_turf(src)
if(!istype(T))
to_chat(src, span_warning("You don't seem to be able to set a trap here!"))
return FALSE
if(T.get_lumcount() >= 0.5)
to_chat(src, span_warning("There is too much light here for your trap to last!"))
return FALSE
if(do_after(src, 10))
if(ability_flags & AB_PHASE_SHIFTED)
new /obj/effect/abstract/dark_maw(loc, src, 1)
else
new /obj/effect/abstract/dark_maw(loc, src)
shadekin_adjust_energy(-ability_cost)
return TRUE
return FALSE
/mob/living/carbon/human/proc/clear_dark_maws()
set name = "Dispel dark maws"
set desc = "Dispel any active dark maws in place"
set category = "Abilities.Shadekin"
var/datum/species/shadekin/SK = species
if(!istype(SK))
to_chat(src, span_warning("Only a shadekin can use that!"))
return FALSE
for(var/obj/effect/abstract/dark_maw/dm in SK.active_dark_maws)
dm.dispel()
/mob/living/carbon/human/proc/nutrition_conversion_toggle()
set name = "Toggle Energy <-> Nutrition conversions"
set desc = "Toggle dark energy and nutrition being converted into each other when full"
set category = "Abilities.Shadekin"
var/datum/species/shadekin/SK = species
if(!istype(SK))
to_chat(src, span_warning("Only a shadekin can use that!"))
return FALSE
if(SK.nutrition_energy_conversion)
to_chat(src, span_notice("Nutrition and dark energy conversions disabled."))
SK.nutrition_energy_conversion = 0
else
to_chat(src, span_notice("Nutrition and dark energy conversions enabled."))
SK.nutrition_energy_conversion = 1
/datum/modifier/shadekin_phase
name = "Shadekin Phasing"
evasion = 100

View File

@@ -1,113 +0,0 @@
/mob/living/simple_mob/shadekin
var/phase_gentle = 0
/mob/living/simple_mob/shadekin/Login()
. = ..()
add_verb(src,/mob/living/simple_mob/shadekin/proc/phase_strength_toggle)
/mob/living/simple_mob/shadekin/proc/dark_tunneling()
var/template_id = "dark_portal"
var/datum/map_template/shelter/template
if(!template)
template = SSmapping.shelter_templates[template_id]
if(!template)
throw EXCEPTION("Shelter template ([template_id]) not found!")
return FALSE
var/turf/deploy_location = get_turf(src)
var/status = template.check_deploy(deploy_location)
switch(status)
//Not allowed due to /area technical reasons
if(SHELTER_DEPLOY_BAD_AREA)
to_chat(src, span_warning("A tunnel to the Dark will not function in this area."))
//Anchored objects or no space
if(SHELTER_DEPLOY_BAD_TURFS, SHELTER_DEPLOY_ANCHORED_OBJECTS)
var/width = template.width
var/height = template.height
to_chat(src, span_warning("There is not enough open area for a tunnel to the Dark to form! You need to clear a [width]x[height] area!"))
if(status != SHELTER_DEPLOY_ALLOWED)
return FALSE
var/turf/T = deploy_location
var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread()
smoke.attach(T)
smoke.set_up(10, 0, T)
smoke.start()
src.visible_message(span_notice("[src] begins pulling dark energies around themselves."))
if(do_after(src, 600)) //60 seconds
playsound(src, 'sound/effects/phasein.ogg', 100, 1)
src.visible_message(span_notice("[src] finishes pulling dark energies around themselves, creating a portal."))
log_and_message_admins("[key_name_admin(src)] created a tunnel to the dark at [get_area(T)]!")
template.annihilate_plants(deploy_location)
template.load(deploy_location, centered = TRUE)
template.update_lighting(deploy_location)
ability_flags &= AB_DARK_TUNNEL
return TRUE
else
return FALSE
/mob/living/simple_mob/shadekin/proc/dark_maw()
var/turf/T = get_turf(src)
if(!istype(T))
to_chat(src, span_warning("You don't seem to be able to set a trap here!"))
return FALSE
else if(T.get_lumcount() >= 0.5)
to_chat(src, span_warning("There is too much light here for your trap to last!"))
return FALSE
if(do_after(src, 10))
if(ability_flags & AB_PHASE_SHIFTED)
new /obj/effect/abstract/dark_maw(loc, src, 1)
else
new /obj/effect/abstract/dark_maw(loc, src)
return TRUE
else
return FALSE
// Allow horizontal resting
/mob/living/simple_mob/shadekin/update_transform()
update_transform_horizontal()
//custom light flicker proc
/mob/living/simple_mob/shadekin/proc/handle_phasein_flicker()
if(phase_gentle) // gentle case: No light destruction. Flicker in 4 tile radius for 3s. Weaken for 3sec after
for(var/obj/machinery/light/L in GLOB.machines)
if(L.z != z || get_dist(src,L) > 4)
continue
L.flicker(3)
src.Stun(3)
else //normal case. Flicker in 10 tile radius for 10s. chance to destroy light based on eye type.
var/destroy_lights = 0
if(eye_state == RED_EYES)
destroy_lights = 80
if(eye_state == PURPLE_EYES)
destroy_lights = 25
for(var/obj/machinery/light/L in GLOB.machines)
if(L.z != z || get_dist(src,L) > 10)
continue
if(prob(destroy_lights))
addtimer(CALLBACK(L, TYPE_PROC_REF(/obj/machinery/light, broken)), rand(5,25), TIMER_DELETE_ME)
else
L.flicker(10)
//toggle proc for toggling gentle/normal phasing
/mob/living/simple_mob/shadekin/proc/phase_strength_toggle()
set name = "Toggle Phase Strength"
set desc = "Toggle strength of phase. Gentle but slower, or faster but destructive to lights."
set category = "Abilities.Shadekin"
if(phase_gentle)
to_chat(src, span_notice("Phasing toggled to Normal. You may damage lights."))
phase_gentle = 0
else
to_chat(src, span_notice("Phasing toggled to Gentle. You won't damage lights, but concentrating on that incurs a short stun."))
phase_gentle = 1

View File

@@ -1,24 +1,24 @@
// This proc turns the BSC or arti-BSC into a phased-creature mine.
/obj/item/bluespace_crystal/Crossed(atom/movable/M)
. = ..()
if(istype(M, /mob/living/carbon/human))
var/mob/living/carbon/human/H = M
if(H.get_species() == SPECIES_SHADEKIN && (H.ability_flags & AB_PHASE_SHIFTED))
if(istype(M, /mob/living))
var/mob/living/L = M
var/datum/component/shadekin/SK = L.get_shadekin_component()
if(SK && SK.in_phase)
var/turf/T = get_turf(src)
visible_message(span_notice("[src] fizzles and disappears as something interacts with it!"))
playsound(src, pick('sound/effects/Glassbr1.ogg', 'sound/effects/Glassbr2.ogg', 'sound/effects/Glassbr3.ogg'), 50, 1)
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread()
s.set_up(5, 1, T)
s.start()
H.attack_dephase(T, src)
SK.attack_dephase(T, src)
qdel(src)
// This proc is the 'Dephase grenade' check. range is changeable. 0=self, 1=3x3, 2=5x5, 3=7x7...
/obj/item/bluespace_crystal/proc/dephase_shadekin()
var/turf/T = get_turf(src)
for(var/thing in range(3, T))
if(istype(thing, /mob/living/carbon/human))
var/mob/living/carbon/human/H = thing
if(H.get_species() == SPECIES_SHADEKIN && (H.ability_flags & AB_PHASE_SHIFTED))
H.attack_dephase(null, src)
for(var/mob/living/living in range(3, T))
var/datum/component/shadekin/SK = living.get_shadekin_component()
if(SK && SK.in_phase)
SK.attack_dephase(null, src)

View File

@@ -17,20 +17,6 @@
. = ..()
GLOB.blacklisted_areas = typecacheof(list(/area/centcom, /area/shadekin, /area/vr))
/mob/living/carbon/human/shadekin_ability_check()
. = ..()
if(. && istype(get_area(src), /area/vr))
to_chat(src, span_danger("The VR systems cannot comprehend this power! This is useless to you!"))
. = FALSE
/obj/effect/shadekin_ability/dark_tunneling/do_ability()
if(istype(get_area(my_kin), /area/vr))
to_chat(my_kin, span_danger("The VR systems cannot comprehend this power! This is useless to you!"))
return FALSE
else
..()
/obj/item/disposable_teleporter/attack_self(mob/user as mob)//Prevents people from using technomancer gear to escape to station from the VR pods.
if(istype(get_area(user), /area/vr))
to_chat(user, span_danger("\The [src] does not appear to work in VR! This is useless to you!"))

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
sound/mob/spooky/decay1.ogg Normal file

Binary file not shown.

BIN
sound/mob/spooky/decay2.ogg Normal file

Binary file not shown.

BIN
sound/mob/spooky/decay3.ogg Normal file

Binary file not shown.

BIN
sound/mob/spooky/emerge.ogg Normal file

Binary file not shown.

BIN
sound/mob/spooky/laugh.ogg Normal file

Binary file not shown.

BIN
sound/mob/spooky/no.ogg Normal file

Binary file not shown.

View File

@@ -0,0 +1,132 @@
import { useBackend } from 'tgui/backend';
import { Window } from 'tgui/layouts';
import {
Box,
Button,
ColorBox,
LabeledList,
NoticeBox,
NumberInput,
Section,
Stack,
Tooltip,
} from 'tgui-core/components';
type Data = {
stun_time: number;
flicker_time: number;
flicker_color: string | null;
flicker_break_chance: number;
flicker_distance: number;
};
export const ShadekinConfig = (props) => {
const { act, data } = useBackend<Data>();
const {
stun_time,
flicker_time,
flicker_color,
flicker_break_chance,
flicker_distance,
} = data;
const isSubtle =
flicker_time < 5 || flicker_break_chance < 5 || flicker_distance < 5;
return (
<Window width={300} height={isSubtle ? 220 : 190} theme="abductor">
<Window.Content>
<Stack fill vertical g={0}>
{isSubtle && (
<Stack.Item>
<NoticeBox>Subtle Phasing, causes {stun_time} s stun.</NoticeBox>
</Stack.Item>
)}
<Stack.Item>
<Section fill title="Shadekin Settings">
<LabeledList>
<LabeledList.Item label="Flicker Count">
<Stack>
<Stack.Item>
<NumberInput
step={1}
minValue={2}
maxValue={20}
value={flicker_time}
onChange={(value) => act('adjust_time', { val: value })}
unit="x"
/>
</Stack.Item>
<Stack.Item>
<Tooltip content="Adjust how long lights flicker when you phase in! (Min 10 Max 20 times!)">
<Box className="VorePanel__floatingButton">?</Box>
</Tooltip>
</Stack.Item>
</Stack>
</LabeledList.Item>
<LabeledList.Item label="Flicker Color">
<Stack align="center">
<Stack.Item>
<Button
onClick={() => act('adjust_color')}
tooltip="Select a color you wish the lights to flicker as (Default is #E0EFF0)"
>
Set Color
</Button>
</Stack.Item>
<Stack.Item>
<ColorBox color={flicker_color || '#E0EFF0'} />
</Stack.Item>
</Stack>
</LabeledList.Item>
<LabeledList.Item label="Flicker Light Break Chance">
<Stack>
<Stack.Item>
<NumberInput
step={1}
minValue={0}
maxValue={25}
value={flicker_break_chance}
onChange={(value) =>
act('adjust_break', { val: value })
}
unit="%"
/>
</Stack.Item>
<Stack.Item>
<Tooltip content="Adjust the % chance for lights to break when you phase in! (Default 0. Min 0. Max 25)">
<Box className="VorePanel__floatingButton">?</Box>
</Tooltip>
</Stack.Item>
</Stack>
</LabeledList.Item>
<LabeledList.Item label="Flicker Distance">
<Stack>
<Stack.Item>
<NumberInput
step={1}
minValue={4}
maxValue={10}
value={flicker_distance}
onChange={(value) =>
act('adjust_distance', { val: value })
}
unit="tiles"
/>
</Stack.Item>
<Stack.Item>
<Tooltip content="Adjust the range in which lights flicker when you phase in! (Default 4. Min 4. Max 10)">
<Box className="VorePanel__floatingButton">?</Box>
</Tooltip>
</Stack.Item>
</Stack>
</LabeledList.Item>
</LabeledList>
</Section>
</Stack.Item>
</Stack>
</Window.Content>
</Window>
);
};

View File

@@ -611,8 +611,16 @@
#include "code\datums\components\reagent_hose\datum.dm"
#include "code\datums\components\reagent_hose\inflation.dm"
#include "code\datums\components\reagent_hose\item.dm"
#include "code\datums\components\species\shadekin.dm"
#include "code\datums\components\species\xenochimera.dm"
#include "code\datums\components\species\shadekin\shadekin.dm"
#include "code\datums\components\species\shadekin\helpers\comp_helpers.dm"
#include "code\datums\components\species\shadekin\powers\create_shade.dm"
#include "code\datums\components\species\shadekin\powers\dark_maw.dm"
#include "code\datums\components\species\shadekin\powers\dark_respite.dm"
#include "code\datums\components\species\shadekin\powers\phase_shift.dm"
#include "code\datums\components\species\shadekin\powers\regenerate_other.dm"
#include "code\datums\components\species\shadekin\powers\dark_tunnel\dark_tunnel_structures.dm"
#include "code\datums\components\species\shadekin\powers\dark_tunnel\dark_tunneling.dm"
#include "code\datums\components\traits\burninlight.dm"
#include "code\datums\components\traits\drippy.dm"
#include "code\datums\components\traits\gargoyle.dm"
@@ -2333,6 +2341,7 @@
#include "code\modules\client\preferences\types\character\antagonism\01_basic.dm"
#include "code\modules\client\preferences\types\character\general\01_basic.dm"
#include "code\modules\client\preferences\types\character\general\03_body.dm"
#include "code\modules\client\preferences\types\character\general\06_special.dm"
#include "code\modules\client\preferences\types\game\admin.dm"
#include "code\modules\client\preferences\types\game\adult.dm"
#include "code\modules\client\preferences\types\game\auto_fit_viewport.dm"
@@ -3357,7 +3366,6 @@
#include "code\modules\mob\living\carbon\human\species\outsider\shadow.dm"
#include "code\modules\mob\living\carbon\human\species\outsider\skeleton.dm"
#include "code\modules\mob\living\carbon\human\species\outsider\vox.dm"
#include "code\modules\mob\living\carbon\human\species\shadekin\dark_portal_ch.dm"
#include "code\modules\mob\living\carbon\human\species\shadekin\shadekin.dm"
#include "code\modules\mob\living\carbon\human\species\shadekin\shadekin_abilities.dm"
#include "code\modules\mob\living\carbon\human\species\shadekin\shadekin_hud.dm"
@@ -3783,9 +3791,7 @@
#include "code\modules\mob\living\simple_mob\subtypes\vore\mobs_monsters\clowns\honkelemental.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\mobs_monsters\clowns\regularclowns.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\morph\morph.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\shadekin\ability_objects.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\shadekin\ability_procs.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\shadekin\rakshasa_abilities.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\shadekin\rakshasa_trap.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\shadekin\shadekin.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\shadekin\types.dm"
@@ -5044,7 +5050,6 @@
#include "modular_chomp\code\modules\mob\living\carbon\human\species\species.dm"
#include "modular_chomp\code\modules\mob\living\carbon\human\species\species_shapeshift_ch.dm"
#include "modular_chomp\code\modules\mob\living\carbon\human\species\outsider\vox.dm"
#include "modular_chomp\code\modules\mob\living\carbon\human\species\shadekin\shadekin_abilities.dm"
#include "modular_chomp\code\modules\mob\living\carbon\human\species\station\prommie_blob.dm"
#include "modular_chomp\code\modules\mob\living\carbon\human\species\station\species_attack.dm"
#include "modular_chomp\code\modules\mob\living\carbon\human\species\station\station.dm"
@@ -5143,7 +5148,6 @@
#include "modular_chomp\code\modules\mob\living\simple_mob\subtypes\vore\xeyakin.dm"
#include "modular_chomp\code\modules\mob\living\simple_mob\subtypes\vore\gateway\candy.dm"
#include "modular_chomp\code\modules\mob\living\simple_mob\subtypes\vore\plants\pitcher.dm"
#include "modular_chomp\code\modules\mob\living\simple_mob\subtypes\vore\shadekin\shadekin.dm"
#include "modular_chomp\code\modules\mob\new_player\sprite_accessories.dm"
#include "modular_chomp\code\modules\mob\new_player\sprite_accessories_ear.dm"
#include "modular_chomp\code\modules\mob\new_player\sprite_accessories_extra.dm"