Merge pull request #12416 from Ghommie/Ghommie-cit792

TGUI-next Check Skills menu.
This commit is contained in:
Putnam3145
2020-06-29 12:44:08 -07:00
committed by GitHub
18 changed files with 322 additions and 52 deletions
+7 -1
View File
@@ -100,4 +100,10 @@
///Ascending priority defines.
#define MODIFIER_SKILL_PRIORITY_LOW 100
#define MODIFIER_SKILL_PRIORITY_DEF 50
#define MODIFIER_SKILL_PRIORITY_MAX 1 //max priority, meant for job/antag modifiers so they don't null out other (de)buffs
#define MODIFIER_SKILL_PRIORITY_MAX 1 //max priority, meant for job/antag modifiers so they don't null out other (de)buffs
// UI Defines
///Categories of skills, these will be displayed alphabetically.
#define SKILL_UI_CAT_ENG "Engineering"
#define SKILL_UI_CAT_MED "Medical"
#define SKILL_UI_CAT_MISC "Misc"
+1 -1
View File
@@ -69,7 +69,7 @@
/proc/english_list(list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "" )
var/total = input.len
if (!total)
return "[nothing_text]"
return nothing_text
else if (total == 1)
return "[input[1]]"
else if (total == 2)
+5
View File
@@ -120,3 +120,8 @@ GLOBAL_VAR_INIT(cmp_field, "name")
/proc/cmp_item_block_priority_asc(obj/item/A, obj/item/B)
return A.block_priority - B.block_priority
/proc/cmp_skill_categories(datum/skill/A, datum/skill/B)
if(A.ui_category == B.ui_category)
return sorttext(A.name, B.name)
return sorttext(A.ui_category, B.ui_category)
+1 -1
View File
@@ -67,7 +67,7 @@
var/datum/skill_holder/skill_holder
/datum/mind/New(var/key)
skill_holder = new()
skill_holder = new(src)
src.key = key
soulOwner = src
martial_art = default_martial_art
+63 -3
View File
@@ -11,6 +11,66 @@
if(!mind.skill_holder)
to_chat(usr, "<span class='warning'>How do you check the skills of [(usr == src)? "yourself when you are" : "something"] without the capability for skills? (PROBABLY A BUG, PRESS F1.)</span>")
return
var/datum/browser/B = new(usr, "skilldisplay_[REF(src)]", "Skills of [src]")
B.set_content(mind.skill_html_readout())
B.open()
mind.skill_holder.ui_interact(src)
/datum/skill_holder/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "skillpanel", "[owner.name]'s Skills", 620, 580, master_ui, state)
ui.set_autoupdate(FALSE) // This UI is only ever opened by one person, and never is updated outside of user input.
ui.open()
else if(need_static_data_update)
update_static_data(user)
need_static_data_update = FALSE
/datum/skill_holder/ui_static_data(mob/user)
. = list()
.["skills"] = list()
for(var/path in GLOB.skill_datums)
var/datum/skill/S = GLOB.skill_datums[path]
var/list/dat = S.get_skill_data(src)
if(islist(dat["modifiers"]))
dat["modifiers"] = jointext(dat["modifiers"], ", ")
dat["percent_base"] = (dat["value_base"] / dat["max_value"])
dat["percent_mod"] = (dat["value_mod"] / dat["max_value"])
.["skills"] += list(dat)
/datum/skill_holder/ui_data(mob/user)
. = list()
.["playername"] = owner.name
.["see_skill_mods"] = see_skill_mods
.["admin"] = check_rights(R_DEBUG)
/datum/skill_holder/ui_act(action, params)
. = ..()
if(.)
return
switch(action)
if("toggle_mods")
see_skill_mods = !see_skill_mods
return TRUE
if ("adj_exp")
if(!check_rights(R_DEBUG))
return
var/skill = text2path(params["skill"])
var/number = input("Please insert the amount of experience/progress you'd like to add/subtract:") as num|null
if (number)
owner.set_skill_value(skill, owner.get_skill_value(skill, FALSE) + number)
return TRUE
if ("set_exp")
if(!check_rights(R_DEBUG))
return
var/skill = text2path(params["skill"])
var/number = input("Please insert the number you want to set the player's exp/progress to:") as num|null
if (!isnull(number))
owner.set_skill_value(skill, number)
return TRUE
if ("set_lvl")
if(!check_rights(R_DEBUG))
return
var/datum/skill/level/S = GLOB.skill_datums[text2path(params["skill"])]
var/number = input("Please insert a whole number between 0[S.associative ? " ([S.unskilled_tier])" : ""] and [S.max_levels][S.associative ? " ([S.levels[S.max_levels]])" : ""] corresponding to the level you'd like to set the player to.") as num|null
if (number >= 0 && number <= S.max_levels)
owner.set_skill_value(S.type, S.get_skill_level_value(number))
return TRUE
+85 -20
View File
@@ -8,6 +8,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
continue
S = new path
.[S.type] = S
. = sortTim(., /proc/cmp_skill_categories, TRUE)
/**
* Skill datums
@@ -34,6 +35,8 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
var/competency_multiplier = 1
/// A list of ways this skill can affect or be affected through actions and skill modifiers.
var/list/skill_traits = list(SKILL_SANITY, SKILL_INTELLIGENCE)
/// Index of this skill in the UI
var/ui_category = SKILL_UI_CAT_MISC
/**
* Ensures what someone's setting as a value for this skill is valid.
@@ -57,10 +60,28 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
return new_value > existing
/**
* Standard value "render"
* Get a list of data used in the skill panel menu.
*/
/datum/skill/proc/standard_render_value(value, level)
return value
/datum/skill/proc/get_skill_data(datum/skill_holder/H)
var/skill_value = H.owner.get_skill_value(type, FALSE)
. = list(
"name" = name,
"desc" = desc,
"path" = type,
"value_base" = skill_value,
"value_mod" = skill_value,
"modifiers" = "None",
"max_value" = 1 //To avoid division by zero later on.
)
var/list/mods = LAZYACCESS(H.skill_value_mods, type)
if(mods)
var/list/mod_names = list()
for(var/k in mods)
var/datum/skill_modifier/M = GLOB.skill_modifiers[k]
mod_names |= M.name
skill_value = M.apply_modifier(skill_value, type, H, MODIFIER_TARGET_VALUE)
.["value_mod"] = skill_value
.["modifiers"] = mod_names //Will be jointext()'d later.
// Just saying, the choice to use different sub-parent-types is to force coders to resolve issues as I won't be implementing custom procs to grab skill levels in a certain context.
// Aka: So people don't forget to change checks if they change a skill's progression type.
@@ -71,10 +92,12 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
competency_thresholds = list(THRESHOLD_COMPETENT = FALSE, THRESHOLD_EXPERT = TRUE, THRESHOLD_MASTER = TRUE)
/datum/skill/binary/sanitize_value(new_value)
return new_value? TRUE : FALSE
return new_value >= 1 ? TRUE : FALSE
/datum/skill/binary/standard_render_value(value, level)
return value? "Yes" : "No"
/datum/skill/binary/get_skill_data(datum/skill_holder/H)
. = ..()
.["base_readout"] = .["value_base"] ? "Learned: Yes" : "Learned: No"
.["mod_readout"] = .["value_mod"] ? "Learned: Yes" : "Learned: No"
/datum/skill/numerical
abstract_type = /datum/skill/numerical
@@ -84,14 +107,15 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
var/max_value = 100
/// Min value of this skill
var/min_value = 0
/// Display as a percent in standard_render_value?
var/display_as_percent = FALSE
/datum/skill/numerical/sanitize_value(new_value)
return clamp(new_value, min_value, max_value)
/datum/skill/numerical/standard_render_value(value, level)
return display_as_percent? "[round(value/max_value/100, 0.01)]%" : "[value] / [max_value]"
/datum/skill/numerical/get_skill_data(datum/skill_holder/H)
. = ..()
.["base_readout"] = "Skill Progress: \[[.["value_base"]] / [max_value]\]"
.["mod_readout"] = "Skill Progress: \[[.["value_mod"]] / [max_value]\]"
.["max_value"] = max_value
/datum/skill/enum
abstract_type = /datum/skill/enum
@@ -123,13 +147,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
var/max_assoc = ""
var/max_assoc_start = 1
for(var/lvl in 1 to max_levels)
var/value
switch(level_up_method)
if(STANDARD_LEVEL_UP)
value = XP_LEVEL(standard_xp_lvl_up, xp_lvl_multiplier, lvl)
if(DWARFY_LEVEL_UP)
value = DORF_XP_LEVEL(standard_xp_lvl_up, xp_lvl_multiplier, lvl)
value = round(value, 1)
var/value = round(get_skill_level_value(lvl), 1)
if(!associative)
levels += value
continue
@@ -167,8 +185,13 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
else if(. < 0)
to_chat(M.current, "<span class='warning'>I feel like I've become worse at [name]!</span>")
/datum/skill/level/standard_render_value(value, level)
var/current_lvl = associative ? (!level ? unskilled_tier : levels[level]) : level
/datum/skill/level/get_skill_data(datum/skill_holder/H)
. = ..()
var/skill_value_base = .["value_base"]
var/skill_value_mod = .["value_mod"]
.["level_based"] = TRUE
var/level = LAZYACCESS(H.skill_levels, type) || 0
var/current_lvl_xp_sum = 0
if(level)
current_lvl_xp_sum = associative ? levels[levels[level]] : levels[level]
@@ -176,8 +199,50 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
var/next_lvl_xp = associative ? levels[levels[next_index]] : levels[next_index]
if(next_lvl_xp > current_lvl_xp_sum)
next_lvl_xp -= current_lvl_xp_sum
.["lvl_base_num"] = .["lvl_mod_num"] = level
.["lvl_base"] = .["lvl_mod"] = associative ? (!level ? unskilled_tier : levels[level]) : level
.["base_style"] = .["mod_style"] = "font-weight:bold; color:hsl([(level+1)*(350/max_levels+1)], 50%, 50%)"
.["xp_next_lvl_base"] = .["xp_next_lvl_mod"] = "\[[skill_value_base - current_lvl_xp_sum]/[next_lvl_xp]\]"
return "[associative ? current_lvl : "Lvl. [current_lvl]"] ([value - current_lvl_xp_sum]/[next_lvl_xp])[level == max_levels ? " \[MAX!\]" : ""]"
.["max_lvl"] = max_levels
var/max_value = associative ? levels[levels[max_levels]] : levels[max_levels]
.["max_value"] = max_value
.["base_readout"] = "Overall Skill Progress: \[[skill_value_base]/[max_value]\]"
.["mod_readout"] = "Overall Skill Progress: \[[skill_value_mod]/[max_value]\]"
var/list/mods = LAZYACCESS(H.skill_level_mods, type)
if(mods) //I'm not proud of doing the same-ish process twice a row but here we go.
var/list/mod_names = .["modifiers"]
if(!mod_names)
.["modifiers"] = mod_names = list()
for(var/k in mods)
var/datum/skill_modifier/M = GLOB.skill_modifiers[k]
mod_names |= M.name
level = M.apply_modifier(level, type, H, MODIFIER_TARGET_LEVEL)
if(level)
current_lvl_xp_sum = associative ? levels[levels[level]] : levels[level]
else
current_lvl_xp_sum = 0
next_index = min(max_levels, level+1)
next_lvl_xp = associative ? levels[levels[next_index]] : levels[next_index]
if(next_lvl_xp > current_lvl_xp_sum)
next_lvl_xp -= current_lvl_xp_sum
.["lvl_mod_num"] = level
.["lvl_mod"] = associative ? (!level ? unskilled_tier : levels[level]) : level
.["mod_style"] = "font-weight:bold; color:hsl([(level+1)*(300/(max_levels+1))], 50%, 50%)"
.["xp_next_lvl_mod"] = "\[[skill_value_mod - current_lvl_xp_sum]/[next_lvl_xp]\]"
/**
* Gets the base value required to reach a level specified by the 'num' arg.
*/
/datum/skill/level/proc/get_skill_level_value(num)
switch(level_up_method)
if(STANDARD_LEVEL_UP)
. = XP_LEVEL(standard_xp_lvl_up, xp_lvl_multiplier, num)
if(DWARFY_LEVEL_UP)
. = DORF_XP_LEVEL(standard_xp_lvl_up, xp_lvl_multiplier, num)
/datum/skill/level/job
abstract_type = /datum/skill/level/job
+13 -15
View File
@@ -20,6 +20,18 @@
var/list/original_values
var/list/original_affinities
var/list/original_levels
/// The mind datum this skill is associated with, only used for the check_skills UI
var/datum/mind/owner
/// For UI updates.
var/need_static_data_update = TRUE
/// Whether modifiers and final skill values or only base values are displayed.
var/see_skill_mods = TRUE
/// The current selected skill category.
var/selected_category
/datum/skill_holder/New(owner)
..()
src.owner = owner
/**
* Grabs the value of a skill.
@@ -79,6 +91,7 @@
CRASH("Invalid set_skill_value call. Use skill typepaths.") //until a time when we somehow need text ids for dynamic skills, I'm enforcing this.
var/datum/skill/S = GLOB.skill_datums[skill]
value = S.sanitize_value(value)
skill_holder.need_static_data_update = TRUE
if(!isnull(value))
LAZYINITLIST(skill_holder.skills)
S.set_skill_value(skill_holder, value, src, silent)
@@ -183,18 +196,3 @@
divisor++
if(divisor)
. = modifier_is_multiplier ? value*(sum/divisor) : value/(sum/divisor)
/**
* Generates a HTML readout of our skills.
* Port to tgui-next when?
*/
/datum/mind/proc/skill_html_readout()
var/list/out = list("<center><h1>Skills</h1></center><hr>")
out += "<table style=\"width:100%\"><tr><th><b>Skill</b><th><b>Value</b></tr>"
for(var/path in GLOB.skill_datums)
var/datum/skill/S = GLOB.skill_datums[path]
var/skill_value = get_skill_value(path)
var/skill_level = get_skill_level(path, round = TRUE)
out += "<tr><td><font color='[S.name_color]'>[S.name]</font></td><td>[S.standard_render_value(skill_value, skill_level)]</td></tr>"
out += "</table>"
return out.Join("")
+5 -5
View File
@@ -7,6 +7,8 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
* and cause lots of edge cases. These are fairly simple overall... make a subtype though, don't use this one.
*/
/datum/skill_modifier
/// Name and description of the skill modifier, used in the UI
var/name = "???"
/// flags for this skill modifier.
var/modifier_flags = NONE
/// target skills, can be a specific skill typepath or a list of skill traits.
@@ -110,6 +112,7 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
if(M.modifier_flags & MODIFIER_SKILL_LEVEL)
ADD_MOD_STEP(skill_holder.skill_level_mods, path, skill_holder.original_levels, get_skill_level(path, FALSE))
LAZYSET(skill_holder.all_current_skill_modifiers, id, TRUE)
skill_holder.need_static_data_update = TRUE
if(M.modifier_flags & MODIFIER_SKILL_BODYBOUND)
M.RegisterSignal(src, COMSIG_MIND_TRANSFER, /datum/skill_modifier.proc/on_mind_transfer)
@@ -141,6 +144,7 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
if(M.modifier_flags & MODIFIER_SKILL_LEVEL && skill_holder.skill_level_mods)
REMOVE_MOD_STEP(skill_holder.skill_level_mods, path, skill_holder.original_levels)
LAZYREMOVE(skill_holder.all_current_skill_modifiers, id)
skill_holder.need_static_data_update = TRUE
if(!mind_transfer && M.modifier_flags & MODIFIER_SKILL_BODYBOUND)
M.UnregisterSignal(src, COMSIG_MIND_TRANSFER)
@@ -165,11 +169,7 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
var/datum/skill/S = GLOB.skill_datums[skillpath]
if(method == MODIFIER_TARGET_VALUE && S.progression_type == SKILL_PROGRESSION_LEVEL)
var/datum/skill/level/L = S
switch(L.level_up_method)
if(STANDARD_LEVEL_UP)
mod = XP_LEVEL(L.standard_xp_lvl_up, L.xp_lvl_multiplier, S.competency_thresholds[mod])
if(DWARFY_LEVEL_UP)
mod = DORF_XP_LEVEL(L.standard_xp_lvl_up, L.xp_lvl_multiplier, S.competency_thresholds[mod])
mod = L.get_skill_level_value(L.competency_thresholds[mod])
else
mod = S.competency_thresholds[mod]
+2 -1
View File
@@ -1,5 +1,6 @@
/datum/skill/level/job/wiring
name = "Wiring"
desc = "How proficient and knowledged you are at wiring beyond laying cables on the floor."
desc = "How proficient and knowledged you are at wiring beyond making post-futuristic wire art."
name_color = COLOR_PALE_ORANGE
skill_traits = list(SKILL_SANITY, SKILL_INTELLIGENCE, SKILL_USE_TOOL, SKILL_TRAINING_TOOL)
ui_category = SKILL_UI_CAT_ENG
+2 -1
View File
@@ -1,5 +1,6 @@
/datum/skill/numerical/surgery
name = "Surgery"
desc = "How proficient you are at doing surgery."
desc = "How proficient you are at performing surgical procedures."
name_color = COLOR_PALE_BLUE_GRAY
competency_multiplier = 1.5 // 60% surgery speed up at max value of 100, considering the base multiplier.
ui_category = SKILL_UI_CAT_MED
+2 -1
View File
@@ -1,6 +1,7 @@
/// Jobbie skill modifiers.
/datum/skill_modifier/job
name = "Job Training"
modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_VIRTUE|MODIFIER_SKILL_ORIGIN_DIFF
priority = MODIFIER_SKILL_PRIORITY_MAX
@@ -23,7 +24,7 @@
modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_VIRTUE|MODIFIER_SKILL_ORIGIN_DIFF
level_mod = JOB_SKILL_TRAINED
/datum/skill_modifier/job/level/New(id)
/datum/skill_modifier/job/level/New(id, register = FALSE)
if(level_mod)
value_mod = GET_STANDARD_LVL(level_mod)
..()
+2
View File
@@ -1,8 +1,10 @@
/datum/skill_modifier/bad_mood
name = "Mood (Dejected)"
modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_MULT|MODIFIER_SKILL_BODYBOUND
target_skills = list(SKILL_SANITY)
/datum/skill_modifier/great_mood
name = "Mood (Elated)"
modifier_flags = MODIFIER_SKILL_AFFINITY|MODIFIER_SKILL_MULT|MODIFIER_SKILL_BODYBOUND
target_skills = list(SKILL_SANITY)
affinity_mod = 1.2
+2
View File
@@ -1,4 +1,5 @@
/datum/skill_modifier/brain_damage
name = "Brain Damage"
target_skills = list(SKILL_INTELLIGENCE)
modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_AFFINITY|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_MULT|MODIFIER_SKILL_BODYBOUND
value_mod = 0.85
@@ -6,6 +7,7 @@
affinity_mod = 0.85
/datum/skill_modifier/heavy_brain_damage
name = "Brain Damage (Severe)"
target_skills = list(SKILL_INTELLIGENCE)
modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_AFFINITY|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_BODYBOUND|MODIFIER_SKILL_HANDICAP|MODIFIER_USE_THRESHOLDS
priority = MODIFIER_SKILL_PRIORITY_LOW
@@ -94,6 +94,9 @@ GLOBAL_LIST_EMPTY(antagonists)
if(skill_modifiers)
for(var/A in skill_modifiers)
ADD_SINGLETON_SKILL_MODIFIER(owner, A, type)
var/datum/skill_modifier/job/M = GLOB.skill_modifiers[GET_SKILL_MOD_ID(A, type)]
if(istype(M))
M.name = "[name] Training"
SEND_SIGNAL(owner.current, COMSIG_MOB_ANTAG_ON_GAIN, src)
/datum/antagonist/proc/is_banned(mob/M)
+1 -1
View File
@@ -415,7 +415,7 @@
"dna_discovered.gif" = 'html/dna_discovered.gif',
"dna_undiscovered.gif" = 'html/dna_undiscovered.gif',
"dna_extra.gif" = 'html/dna_extra.gif'
)
)
/datum/asset/simple/vv
assets = list(
@@ -0,0 +1,121 @@
import { Fragment } from 'inferno';
import { useBackend } from '../backend';
import { Box, Button, LabeledList, ProgressBar, Section } from '../components';
export const SkillPanel = props => {
const { act, data } = useBackend(props);
const skills = data.skills || [];
const see_mods = data.see_skill_mods;
const skillgreen = {
color: 'lightgreen',
fontWeight: 'bold',
};
const skillyellow = {
color: '#FFDB58',
fontWeight: 'bold',
};
return (
<Section
title={data.playername}
buttons={(
<Button
icon={see_mods ? 'Enabled' : 'Disabled'}
content={see_mods ? 'Modifiers Shown' : 'Modifiers Hidden'}
onClick={() => act('toggle_mods')} />
)}>
<LabeledList>
{skills.map(skill => (
<LabeledList.Item key={skill.name} label={skill.name}>
<span style={skillyellow}>
{skill.desc}
<br />
`Modifiers: ${skill.modifiers}`
</span>
<br />
{!!skill.level_based && (
<Box>
{see_mods ? (
<span>
Level: [
<span style={skill.mod_style}>
{skill.lvl_mod}
</span>]
</span>
) : (
<span>
Level: [
<span style={skill.base_style}>
{skill.lvl_base}
</span>]
</span>
)}
<br />
Total Experience:
{see_mods ? (
<span>[{skill.value_mod} XP]</span>
) : (
<span>[{skill.value_base} XP]</span>
)}
<br />
XP To Next Level:
{skill.max_lvl !== (see_mods
? skill.lvl_mod_num
: skill.lvl_base_num) ? (
<Box inline>
{see_mods ? (
<span>{skill.xp_next_lvl_mod}</span>
) : (
<span>{skill.xp_next_lvl_base}</span>
)}
</Box>
) : (
<span style={skillgreen}>
[MAXXED]
</span>
)}
</Box>
)}
{see_mods ? (
<span>{skill.mod_readout}</span>
) : (
<span>{skill.base_readout}</span>
)}
{see_mods ? (
<ProgressBar
value={skill.percent_mod}
color="good" />
) : (
<ProgressBar
value={skill.percent_base}
color="good" />
)}
<br />
{!!data.admin && (
<Fragment>
<Button
content="Adjust Exp"
onClick={() => act('adj_exp', {
skill: skill.path,
})} />
<Button
content="Set Exp"
onClick={() => act('set_exp', {
skill: skill.path,
})} />
{!!skill.level_based && (
<Button
content="Set Level"
onClick={() => act('set_lvl', {
skill: skill.path,
})} />
)}
</Fragment>
)}
<br />
<br />
</LabeledList.Item>
))}
</LabeledList>
</Section>
);
};
File diff suppressed because one or more lines are too long
+5
View File
@@ -81,6 +81,7 @@ import { RapidPipeDispenser } from './interfaces/RapidPipeDispenser';
import { SatelliteControl } from './interfaces/SatelliteControl';
import { ScannerGate } from './interfaces/ScannerGate';
import { ShuttleManipulator } from './interfaces/ShuttleManipulator';
import { SkillPanel } from './interfaces/SkillPanel';
import { Sleeper } from './interfaces/Sleeper';
import { SlimeBodySwapper } from './interfaces/SlimeBodySwapper';
import { Signaler } from './interfaces/Signaler';
@@ -472,6 +473,10 @@ const ROUTES = {
component: () => ShuttleManipulator,
scrollable: true,
},
skillpanel: {
component: () => SkillPanel,
scrollable: true,
},
sleeper: {
component: () => Sleeper,
scrollable: false,