mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 02:09:41 +00:00
[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:
committed by
GitHub
parent
52b6360a09
commit
3e095bf5db
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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////////////
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
213
code/datums/components/species/shadekin/helpers/comp_helpers.dm
Normal file
213
code/datums/components/species/shadekin/helpers/comp_helpers.dm
Normal 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
|
||||
@@ -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
|
||||
207
code/datums/components/species/shadekin/powers/dark_maw.dm
Normal file
207
code/datums/components/species/shadekin/powers/dark_maw.dm
Normal 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)
|
||||
107
code/datums/components/species/shadekin/powers/dark_respite.dm
Normal file
107
code/datums/components/species/shadekin/powers/dark_respite.dm
Normal 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
|
||||
@@ -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")
|
||||
@@ -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))
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
281
code/datums/components/species/shadekin/shadekin.dm
Normal file
281
code/datums/components/species/shadekin/shadekin.dm
Normal 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)
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")])"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
. = ..()
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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!"))
|
||||
|
||||
BIN
icons/mob/shadekin_abilities.dmi
Normal file
BIN
icons/mob/shadekin_abilities.dmi
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
BIN
icons/obj/Shadekin_powers.dmi
Normal file
BIN
icons/obj/Shadekin_powers.dmi
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
icons/obj/shadekin_portal.dmi
Normal file
BIN
icons/obj/shadekin_portal.dmi
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
47
maps/submaps/shelters/dark_portal.dmm
Normal file
47
maps/submaps/shelters/dark_portal.dmm
Normal 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
|
||||
"}
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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!"))
|
||||
|
||||
BIN
sound/mob/spooky/breath1.ogg
Normal file
BIN
sound/mob/spooky/breath1.ogg
Normal file
Binary file not shown.
BIN
sound/mob/spooky/breath2.ogg
Normal file
BIN
sound/mob/spooky/breath2.ogg
Normal file
Binary file not shown.
BIN
sound/mob/spooky/corrosion1.ogg
Normal file
BIN
sound/mob/spooky/corrosion1.ogg
Normal file
Binary file not shown.
BIN
sound/mob/spooky/corrosion2.ogg
Normal file
BIN
sound/mob/spooky/corrosion2.ogg
Normal file
Binary file not shown.
BIN
sound/mob/spooky/corrosion3.ogg
Normal file
BIN
sound/mob/spooky/corrosion3.ogg
Normal file
Binary file not shown.
BIN
sound/mob/spooky/decay1.ogg
Normal file
BIN
sound/mob/spooky/decay1.ogg
Normal file
Binary file not shown.
BIN
sound/mob/spooky/decay2.ogg
Normal file
BIN
sound/mob/spooky/decay2.ogg
Normal file
Binary file not shown.
BIN
sound/mob/spooky/decay3.ogg
Normal file
BIN
sound/mob/spooky/decay3.ogg
Normal file
Binary file not shown.
BIN
sound/mob/spooky/emerge.ogg
Normal file
BIN
sound/mob/spooky/emerge.ogg
Normal file
Binary file not shown.
BIN
sound/mob/spooky/laugh.ogg
Normal file
BIN
sound/mob/spooky/laugh.ogg
Normal file
Binary file not shown.
BIN
sound/mob/spooky/no.ogg
Normal file
BIN
sound/mob/spooky/no.ogg
Normal file
Binary file not shown.
132
tgui/packages/tgui/interfaces/ShadekinConfig.tsx
Normal file
132
tgui/packages/tgui/interfaces/ShadekinConfig.tsx
Normal 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>
|
||||
);
|
||||
};
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user