From 41ce944736ba3a3dc373433893f2552765b84d36 Mon Sep 17 00:00:00 2001 From: Cameron Lennox Date: Tue, 8 Jul 2025 22:11:11 -0400 Subject: [PATCH] Minor fixes (#17966) * Stops some abilities from being done in VR * yeh * Update comp_helpers.dm * anti exploit * i am speed * Update areas.dm * Update areas.dm * Update dark_tunneling.dm * get rid of these unused abilities incompatible with new system. * forgot the human handling whoops * byeeee * Update shadekin.dm * voucher qdel fix * nutriment * Update shadekin.dm * mooore * Update shadekin.dm * yea * Update comp_helpers.dm * more fixes * bunch of fixes * type and default * dynamic * store settings * . --------- Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com> --- code/__defines/shadekin.dm | 6 - .../species/shadekin/helpers/comp_helpers.dm | 70 +++++++- .../species/shadekin/powers/create_shade.dm | 2 + .../species/shadekin/powers/dark_maw.dm | 2 + .../species/shadekin/powers/dark_respite.dm | 2 + .../powers/dark_tunnel/dark_tunneling.dm | 5 + .../species/shadekin/powers/phase_shift.dm | 27 ++- .../shadekin/powers/regenerate_other.dm | 2 + .../components/species/shadekin/shadekin.dm | 102 ++++++++--- code/game/area/areas.dm | 12 +- code/game/machinery/doors/airlock.dm | 2 + code/game/objects/effects/portals.dm | 8 +- code/game/objects/structures/girders.dm | 5 +- .../types/character/general/06_special.dm | 61 +++++++ .../equipment_vendor.dm | 3 + .../carbon/human/species/shadekin/shadekin.dm | 111 +++++++++++- .../species/shadekin/shadekin_abilities.dm | 29 --- .../living/carbon/human/species/species.dm | 1 + .../mob/living/carbon/human/update_icons.dm | 4 + .../silicon/robot/robot_simple_items.dm | 27 ++- .../subtypes/vore/shadekin/ability_objects.dm | 168 ------------------ .../subtypes/vore/shadekin/shadekin.dm | 31 +--- .../tgui/interfaces/ShadekinConfig.tsx | 132 ++++++++++++++ vorestation.dme | 3 +- 24 files changed, 531 insertions(+), 284 deletions(-) create mode 100644 code/modules/client/preferences/types/character/general/06_special.dm delete mode 100644 code/modules/mob/living/carbon/human/species/shadekin/shadekin_abilities.dm delete mode 100644 code/modules/mob/living/simple_mob/subtypes/vore/shadekin/ability_objects.dm create mode 100644 tgui/packages/tgui/interfaces/ShadekinConfig.tsx diff --git a/code/__defines/shadekin.dm b/code/__defines/shadekin.dm index 1dd3db67e20..62833a785a0 100644 --- a/code/__defines/shadekin.dm +++ b/code/__defines/shadekin.dm @@ -1,9 +1,3 @@ -#define NOT_WHILE_SHIFTED 1 -#define ONLY_WHILE_SHIFTED 2 -#define SHIFTED_OR_NOT 3 - -#define AB_SHADE_REGEN 0x1 - //Porting over the type system of the mobs #define BLUE_EYES 1 #define RED_EYES 2 diff --git a/code/datums/components/species/shadekin/helpers/comp_helpers.dm b/code/datums/components/species/shadekin/helpers/comp_helpers.dm index 42475beff60..59ab4b8d808 100644 --- a/code/datums/components/species/shadekin/helpers/comp_helpers.dm +++ b/code/datums/components/species/shadekin/helpers/comp_helpers.dm @@ -50,28 +50,35 @@ //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(var/mob/living/carbon/human/H) +/datum/component/shadekin/proc/set_shadekin_eyecolor() if(!ishuman(owner)) return eye_color //revert to default if we're not a human - else - H = owner + + var/mob/living/carbon/human/H = owner 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] + 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) @@ -81,9 +88,10 @@ 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] + 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) @@ -159,3 +167,47 @@ 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()]. (JMP)", 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 diff --git a/code/datums/components/species/shadekin/powers/create_shade.dm b/code/datums/components/species/shadekin/powers/create_shade.dm index a9c1facd114..506d0f274cb 100644 --- a/code/datums/components/species/shadekin/powers/create_shade.dm +++ b/code/datums/components/species/shadekin/powers/create_shade.dm @@ -18,6 +18,8 @@ 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 diff --git a/code/datums/components/species/shadekin/powers/dark_maw.dm b/code/datums/components/species/shadekin/powers/dark_maw.dm index 0f66687affe..edf5cdda4a2 100644 --- a/code/datums/components/species/shadekin/powers/dark_maw.dm +++ b/code/datums/components/species/shadekin/powers/dark_maw.dm @@ -14,6 +14,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 diff --git a/code/datums/components/species/shadekin/powers/dark_respite.dm b/code/datums/components/species/shadekin/powers/dark_respite.dm index 4bb333d7e69..d71b42dab6c 100644 --- a/code/datums/components/species/shadekin/powers/dark_respite.dm +++ b/code/datums/components/species/shadekin/powers/dark_respite.dm @@ -14,6 +14,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 diff --git a/code/datums/components/species/shadekin/powers/dark_tunnel/dark_tunneling.dm b/code/datums/components/species/shadekin/powers/dark_tunnel/dark_tunneling.dm index 01cca9732c8..261bb61782a 100644 --- a/code/datums/components/species/shadekin/powers/dark_tunnel/dark_tunneling.dm +++ b/code/datums/components/species/shadekin/powers/dark_tunnel/dark_tunneling.dm @@ -20,6 +20,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 @@ -63,6 +65,9 @@ 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.")) diff --git a/code/datums/components/species/shadekin/powers/phase_shift.dm b/code/datums/components/species/shadekin/powers/phase_shift.dm index 4580277558b..a314c72d36a 100644 --- a/code/datums/components/species/shadekin/powers/phase_shift.dm +++ b/code/datums/components/species/shadekin/powers/phase_shift.dm @@ -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... - watcher++ // They are watching us! + 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) @@ -85,7 +101,6 @@ else phase_out(T, SK) - /mob/living/proc/phase_in(var/turf/T, var/datum/component/shadekin/SK) if(SK.in_phase) @@ -163,6 +178,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 diff --git a/code/datums/components/species/shadekin/powers/regenerate_other.dm b/code/datums/components/species/shadekin/powers/regenerate_other.dm index 375da05fa7e..96e895e20c2 100644 --- a/code/datums/components/species/shadekin/powers/regenerate_other.dm +++ b/code/datums/components/species/shadekin/powers/regenerate_other.dm @@ -17,6 +17,8 @@ var/datum/component/shadekin/SK = get_shadekin_component() if(!SK) return FALSE + if(SK.special_considerations(TRUE)) + return FALSE if(stat) to_chat(src, span_warning("Can't use that ability in your state!")) return FALSE diff --git a/code/datums/components/species/shadekin/shadekin.dm b/code/datums/components/species/shadekin/shadekin.dm index 17f2fcd0f2e..921705e14a3 100644 --- a/code/datums/components/species/shadekin/shadekin.dm +++ b/code/datums/components/species/shadekin/shadekin.dm @@ -38,6 +38,8 @@ 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 @@ -56,8 +58,8 @@ //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/power/shadekin/regenerate_other, + /datum/power/shadekin/create_shade) ///Datum holder. Largely ignore this. var/list/shadekin_ability_datums = list() @@ -72,13 +74,14 @@ /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) + /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. @@ -132,6 +135,10 @@ 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 @@ -172,11 +179,74 @@ 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"]) + 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_brack_chance = text2num(params["val"]) + if(!isnum(new_brack_chance)) + return FALSE + flicker_break_chance = new_brack_chance + ui.user.write_preference_directly(/datum/preference/numeric/living/flicker_break_chance, new_brack_chance) + return TRUE + if("adjust_distance") + var/new_distance = text2num(params["val"]) + 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" @@ -204,21 +274,5 @@ if(!SK) to_chat(src, span_warning("Only a shadekin can use that!")) return FALSE - var/flicker_timer = tgui_input_number(src, "Adjust how long lights flicker when you phase in! (Min 10 Max 20 times!)", "Set Flicker", SK.flicker_time, 20, 10) - if(flicker_timer > 20 || flicker_timer < 10) - to_chat(src,"You must choose a number between 10 and 20") - return - SK.flicker_time = flicker_timer - to_chat(src,"Flicker timer set to [SK.flicker_time] seconds!") - var/set_new_color = tgui_color_picker(src,"Select a color you wish the lights to flicker as (Default is #E0EFF0)","Color Selector", SK.flicker_color) - if(set_new_color) - SK.flicker_color = set_new_color - to_chat(src,"Flicker color set to [SK.flicker_color]!") - - var/break_chance = tgui_input_number(src, "Adjust the % chance for lights to break when you phase in! (Default 0. Min 0. Max 25)", "Set Break Chance", 0, 25, 0) - if(break_chance > 25 || break_chance < 0) - to_chat(src,"You must choose a number between 0 and 25") - return - SK.flicker_break_chance = break_chance - to_chat(src,"Break chance set to [SK.flicker_break_chance]%") + SK.tgui_interact(src) diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 74cd4a6a01c..bf053ef3d26 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -141,21 +141,17 @@ GLOBAL_LIST_EMPTY(areas_by_type) if(fire || party || atmosalm) firedoors_close() arfgs_activate() - // VOREStation Edit - Make the lights colored! if(fire) for(var/obj/machinery/light/L in src) L.set_alert_fire() else if(atmosalm) for(var/obj/machinery/light/L in src) L.set_alert_atmos() - // VOREStation Edit End else firedoors_open() arfgs_deactivate() - // VOREStation Edit - Put the lights back! for(var/obj/machinery/light/L in src) L.reset_alert() - // VOREStation Edit End // Close all firedoors in the area /area/proc/firedoors_close() @@ -396,7 +392,7 @@ var/list/mob/living/forced_ambiance_list = list() play_ambience(L, initial = TRUE) if(flag_check(AREA_NO_SPOILERS)) L.disable_spoiler_vision() - check_phase_shift(M) //RS Port #658 + check_phase_shift(M) // Update the area's color grading if(L.client && L.client.color != get_color_tint()) // Try to check if we should bother changing before doing blending @@ -452,7 +448,7 @@ var/list/mob/living/forced_ambiance_list = list() return // Being buckled to something solid keeps you in place. if(istype(H.shoes, /obj/item/clothing/shoes/magboots) && (H.shoes.item_flags & NOSLIP)) return - if(H.is_incorporeal()) // VOREstation edit - Phaseshifted beings should not be affected by gravity + if(H.is_incorporeal()) // Phaseshifted beings should not be affected by gravity return if(H.species.can_zero_g_move || H.species.can_space_freemove) return @@ -568,11 +564,11 @@ GLOBAL_DATUM(spoiler_obfuscation_image, /image) 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 var/datum/component/shadekin/SK = ourmob.get_shadekin_component() if(SK && SK.in_phase) - ourmob.phase_in(ourmob.loc, SK) + SK.attack_dephase(ourmob.loc, src) /area/proc/isAlwaysIndoors() return FALSE diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 89e7a816864..2fb6f5f4d21 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -1013,6 +1013,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) diff --git a/code/game/objects/effects/portals.dm b/code/game/objects/effects/portals.dm index 66ecb957602..0ea439716d3 100644 --- a/code/game/objects/effects/portals.dm +++ b/code/game/objects/effects/portals.dm @@ -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) diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index 65c3f38d9d2..db5d7b9ee0c 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -231,6 +231,9 @@ /obj/structure/girder/proc/construct_wall(obj/item/stack/material/S, mob/user) var/amount_to_use = reinf_material ? 1 : 2 + var/time_to_reinforce = 4 SECONDS + if(isrobot(user)) //Robots get a speed boost. + time_to_reinforce = 1.5 SECONDS if(S.get_amount() < amount_to_use) to_chat(user, span_notice("There isn't enough material here to construct a wall.")) return FALSE @@ -248,7 +251,7 @@ to_chat(user, span_notice("You begin adding the plating...")) - if(!do_after(user,40) || !S.use(amount_to_use)) + if(!do_after(user,time_to_reinforce) || !S.use(amount_to_use)) return TRUE //once we've gotten this far don't call parent attackby() if(anchored) diff --git a/code/modules/client/preferences/types/character/general/06_special.dm b/code/modules/client/preferences/types/character/general/06_special.dm new file mode 100644 index 00000000000..65c7f30329e --- /dev/null +++ b/code/modules/client/preferences/types/character/general/06_special.dm @@ -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 diff --git a/code/modules/mining/ore_redemption_machine/equipment_vendor.dm b/code/modules/mining/ore_redemption_machine/equipment_vendor.dm index 21d578e1af8..dafbe41d516 100644 --- a/code/modules/mining/ore_redemption_machine/equipment_vendor.dm +++ b/code/modules/mining/ore_redemption_machine/equipment_vendor.dm @@ -317,6 +317,9 @@ if(!selection) to_chat(redeemer, span_notice("You decide not to redeem anything for now.")) return + if(QDELETED(voucher)) + to_chat(redeemer, span_warning("The voucher has already been redeemed.")) + return switch(selection) if("Kinetic Accelerator + KA Addon") //1250-2100 points worth diff --git a/code/modules/mob/living/carbon/human/species/shadekin/shadekin.dm b/code/modules/mob/living/carbon/human/species/shadekin/shadekin.dm index 27f6c0d78fe..5f1a5d736ce 100644 --- a/code/modules/mob/living/carbon/human/species/shadekin/shadekin.dm +++ b/code/modules/mob/living/carbon/human/species/shadekin/shadekin.dm @@ -101,12 +101,115 @@ ) species_component = /datum/component/shadekin + component_requires_late_recalc = TRUE /datum/species/shadekin/handle_death(var/mob/living/carbon/human/H) - spawn(1) - for(var/obj/item/W in H) - H.drop_from_inventory(W) - qdel(H) + var/special_handling = FALSE //varswitch for downstream + 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((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") + return + + H.visible_message("\The [H.name] 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 + SK.respite_activating = TRUE + + H.drop_l_hand() + H.drop_r_hand() + + 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 //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) + BITRESET(H.hud_updateflag, STATUS_HUD) + BITRESET(H.hud_updateflag, LIFE_HUD) + + if(istype(H.loc, /obj/belly)) + //Yay digestion... presumably... + var/obj/belly/belly = H.loc + 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(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) + SK.respite_activating = FALSE + belly.owner.handle_belly_update() + H.clear_fullscreen("belly") + if(H.hud_used) + if(!H.hud_used.hud_shown) + H.toggle_hud_vis() + H.stop_sound_channel(CHANNEL_PREYLOOP) + H.add_modifier(/datum/modifier/dark_respite, 10 MINUTES) + H.muffled = FALSE + H.forced_psay = FALSE + + + 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) + + addtimer(CALLBACK(H, TYPE_PROC_REF(/mob/living, enter_the_dark)), 1 SECOND, TIMER_DELETE_ME) + + addtimer(CALLBACK(H, TYPE_PROC_REF(/mob/living, can_leave_dark)), 15 MINUTES, TIMER_DELETE_ME) + + return TRUE + + +/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 + + 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 diff --git a/code/modules/mob/living/carbon/human/species/shadekin/shadekin_abilities.dm b/code/modules/mob/living/carbon/human/species/shadekin/shadekin_abilities.dm deleted file mode 100644 index 527e8b9903b..00000000000 --- a/code/modules/mob/living/carbon/human/species/shadekin/shadekin_abilities.dm +++ /dev/null @@ -1,29 +0,0 @@ -/datum/power/shadekin - -/mob/living/carbon/human/is_incorporeal() - var/datum/component/shadekin/SK = get_shadekin_component() - if(SK && SK.in_phase) //Shadekin - return TRUE - return ..() - -// 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/component/shadekin/SK = get_shadekin_component() - if(!SK) - return FALSE - // 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(SK.doing_phase || !T.CanPass(src,T) || loc != T || !(SK.in_phase) ) - 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()]. (JMP)", 1) - // start the dephase - phase_in(T) - SK.shadekin_adjust_energy(-20) // loss of energy for the interception - // apply a little extra stun for good measure - src.Weaken(3) diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm index 7f45c9919f3..740e8919366 100644 --- a/code/modules/mob/living/carbon/human/species/species.dm +++ b/code/modules/mob/living/carbon/human/species/species.dm @@ -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 diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 3e348d7145f..e9802d12875 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -370,6 +370,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)) diff --git a/code/modules/mob/living/silicon/robot/robot_simple_items.dm b/code/modules/mob/living/silicon/robot/robot_simple_items.dm index 9ca16ceb48e..e9282ed2497 100644 --- a/code/modules/mob/living/silicon/robot/robot_simple_items.dm +++ b/code/modules/mob/living/silicon/robot/robot_simple_items.dm @@ -531,14 +531,22 @@ . += wrapped.examine(user) /obj/item/gripper/CtrlClick(mob/user) - if(wrapped) + if(wrapped && !is_in_use()) wrapped.attack_self(user) return /obj/item/gripper/AltClick(mob/user) - drop_item() + if(!is_in_use()) + drop_item() return +//This is used to check if the gripper is currently being used. +//If it is, we don't allow any other actions to be performed. +/obj/item/gripper/proc/is_in_use() + if(wrapped) + if(istype(wrapped.loc, /obj/item/storage/internal/gripper)) + return FALSE //We are in a gripper storage or another gripper, so we are not in use. + return TRUE //This is the code that updates our pockets and decides if they should have icons or not. //This should be called every time we use the gripper and our wrapped item is used up. @@ -565,6 +573,9 @@ photo_images["[pocket_to_check.name]" + "[pocket_content.name]"] = pocket_image /obj/item/gripper/attack_self(mob/user as mob) + if(is_in_use()) + to_chat(user, span_danger("You are currently using the gripper on something!")) + return generate_icons() var/list/options = list() @@ -588,6 +599,9 @@ return ..() /obj/item/gripper/attackby(var/obj/item/O, var/mob/user) + if(is_in_use()) + to_chat(user, span_danger("You are currently using the gripper on something!")) + return FALSE if(wrapped) wrapped.loc = src.loc //Place it in to the robot. var/resolved = wrapped.attackby(O, user) @@ -621,6 +635,9 @@ if(!wrapped) to_chat(src, span_warning("You have nothing to drop!")) return + if(is_in_use()) + to_chat(src, span_danger("You are currently using the gripper on something!")) + return if((wrapped == current_pocket && !istype(wrapped.loc, /obj/item/storage/internal/gripper))) //We have wrapped selected as our current_pocket AND wrapped is not in a gripper storage wrapped = null current_pocket = pick(pockets) @@ -643,6 +660,9 @@ wrapped = null /obj/item/gripper/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) + if(is_in_use()) + to_chat(user, span_danger("You are currently using the gripper on something!")) + return FALSE if(wrapped) //The force of the wrapped obj gets set to zero during the attack() and afterattack(). if(QDELETED(wrapped) || (wrapped.loc != src.loc && !istype(wrapped.loc,/obj/item/storage/internal/gripper))) //If our wrapper was deleted OR it's no longer in our internal gripper storage wrapped = null //we become null @@ -659,6 +679,9 @@ /obj/item/gripper/afterattack(var/atom/target, var/mob/living/user, proximity, params) if(!proximity) return // This will prevent them using guns at range but adminbuse can add them directly to modules, so eh. + if(is_in_use()) + to_chat(user, span_danger("You are currently using the gripper on something!")) + return var/current_pocket_full = FALSE //There's some weirdness with items being lost inside the arm. Trying to fix all cases. ~Z if(wrapped == current_pocket) diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/ability_objects.dm b/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/ability_objects.dm deleted file mode 100644 index b39871d4682..00000000000 --- a/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/ability_objects.dm +++ /dev/null @@ -1,168 +0,0 @@ -/obj/effect/shadekin_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/shadekin_ability/Initialize(mapload) - . = ..() - if(issimplekin(loc)) - my_kin = loc - loc = null - -/obj/effect/shadekin_ability/Destroy() - my_kin = null - return ..() - -/obj/effect/shadekin_ability/proc/atom_button_text() - var/shift_denial - if(shift_mode == NOT_WHILE_SHIFTED && my_kin.comp.in_phase) - shift_denial = "Physical Only" - else if(shift_mode == ONLY_WHILE_SHIFTED && !(my_kin.comp.in_phase)) - 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/shadekin_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(span_bold("[name]") + " (Cost: [cost]%) - [desc]")) - else - do_ability(my_kin) - -/obj/effect/shadekin_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.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.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) - 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/shadekin_ability/phase_shift - ability_name = "Phase Shift" - desc = "Shift yourself out of alignment with realspace to travel quickly between dark areas (or light areas, with a price)." - icon_state = "tech_passwall" - cost = 100 - shift_mode = SHIFTED_OR_NOT - ab_sound = 'sound/effects/stealthoff.ogg' -/obj/effect/shadekin_ability/phase_shift/do_ability() - if(!..()) - return - my_kin.phase_shift() - if(my_kin.comp.in_phase) - cost = 0 //Shifting back is free (but harmful in light) - else - cost = initial(cost) -///////////////////////////////////////////////////////////////// -/obj/effect/shadekin_ability/heal_boop - ability_name = "Regenerate Other" - desc = "Spend energy to heal physical wounds in another creature." - icon_state = "tech_biomedaura" - cost = 50 - shift_mode = NOT_WHILE_SHIFTED - ab_sound = 'sound/effects/EMPulse.ogg' -/obj/effect/shadekin_ability/heal_boop/do_ability() - if(!..()) - return - if(!my_kin.mend_other()) - my_kin.comp.dark_energy += cost //Refund due to abort -/* -/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) -*/ -///////////////////////////////////////////////////////////////// -/obj/effect/shadekin_ability/create_shade - ability_name = "Create Shade" - desc = "Create a field of darkness that follows you." - icon_state = "tech_dispelold" - cost = 25 - shift_mode = NOT_WHILE_SHIFTED - ab_sound = 'sound/effects/bamf.ogg' -/obj/effect/shadekin_ability/create_shade/do_ability() - if(!..()) - return - my_kin.add_modifier(/datum/modifier/shadekin/create_shade,20 SECONDS) -/* -/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.comp.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 -*/ -/* -///////////////////////////////////////////////////////////////// -/obj/effect/shadekin_ability/energy_feast - ability_name = "Devour Energy" - desc = "Devour the energy from another creature (potentially fatal)." - icon_state = "gen_eat" - cost = 25 - shift_mode = NOT_WHILE_SHIFTED -/obj/effect/shadekin_ability/energy_feast/do_ability() - if(!..()) - return -*/ diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/shadekin.dm b/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/shadekin.dm index 17a88ceef18..28ed6bc691b 100644 --- a/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/shadekin.dm +++ b/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/shadekin.dm @@ -124,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) @@ -229,22 +224,6 @@ 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!") var/special_handling = FALSE //varswitch for downstream @@ -315,7 +294,7 @@ 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/proc/enter_the_dark() +/mob/living/simple_mob/shadekin/enter_the_dark() comp.respite_activating = FALSE comp.in_dark_respite = TRUE @@ -325,7 +304,7 @@ invisibility = initial(invisibility) comp.respite_activating = FALSE -/mob/living/simple_mob/shadekin/proc/can_leave_dark() +/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")) @@ -352,16 +331,22 @@ //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(comp.in_phase) diff --git a/tgui/packages/tgui/interfaces/ShadekinConfig.tsx b/tgui/packages/tgui/interfaces/ShadekinConfig.tsx new file mode 100644 index 00000000000..a50931a6cfa --- /dev/null +++ b/tgui/packages/tgui/interfaces/ShadekinConfig.tsx @@ -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(); + + 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 ( + + + + {isSubtle && ( + + Subtle Phasing, causes {stun_time} s stun. + + )} + +
+ + + + + act('adjust_time', { val: value })} + unit="x" + /> + + + + ? + + + + + + + + + + + + + + + + + + + act('adjust_break', { val: value }) + } + unit="%" + /> + + + + ? + + + + + + + + + act('adjust_distance', { val: value }) + } + unit="tiles" + /> + + + + ? + + + + + +
+
+
+
+
+ ); +}; diff --git a/vorestation.dme b/vorestation.dme index 31ea7c18805..db3d8a2e75d 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -2227,6 +2227,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" @@ -3211,7 +3212,6 @@ #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\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" #include "code\modules\mob\living\carbon\human\species\station\alraune.dm" #include "code\modules\mob\living\carbon\human\species\station\custom.dm" @@ -3591,7 +3591,6 @@ #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\shadekin.dm" #include "code\modules\mob\living\simple_mob\subtypes\vore\shadekin\types.dm"