WIP, let's just use TG's cause i'm dull
This commit is contained in:
@@ -20,83 +20,24 @@
|
||||
need_static_data_update = FALSE
|
||||
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 = new(user, src, ui_key, "skills", "[owner.name]'s Skills", 620, 580, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/datum/skill_holder/ui_static_data(mob/user)
|
||||
. = list()
|
||||
var/datum/asset/spritesheet/simple/assets = get_asset_datum(/datum/asset/spritesheet/simple/skills)
|
||||
|
||||
var/all_mods = list()
|
||||
for(var/id in all_current_skill_modifiers)
|
||||
var/datum/skill_modifier/M = GLOB.skill_modifiers[id]
|
||||
all_mods[id] = list(
|
||||
name = M.name,
|
||||
desc = M.desc,
|
||||
icon = assets.icon_class_name(M.icon_name)
|
||||
)
|
||||
|
||||
.["categories"] = list()
|
||||
var/list/current
|
||||
var/category
|
||||
.["skills"] = list()
|
||||
for(var/path in GLOB.skill_datums)
|
||||
var/datum/skill/S = GLOB.skill_datums[path]
|
||||
if(!current || S.ui_category != category)
|
||||
if(category)
|
||||
var/list/cat = list("name" = category, "skills" = current)
|
||||
.["categories"] += list(cat)
|
||||
current = list()
|
||||
category = S.ui_category
|
||||
|
||||
var/skill_value = owner.get_skill_value(path, FALSE)
|
||||
var/skill_level = owner.get_skill_level(path, FALSE)
|
||||
var/list/mod_list = list()
|
||||
var/list/modifiers
|
||||
var/list/mod_ids = list()
|
||||
|
||||
var/value_mods = LAZYACCESS(skill_value_mods, path)
|
||||
var/mod_value = skill_value
|
||||
for(var/k in value_mods)
|
||||
var/datum/skill_modifier/M = GLOB.skill_modifiers[k]
|
||||
mod_list |= M.name
|
||||
mod_ids |= M.identifier
|
||||
mod_value = M.apply_modifier(mod_value, path, src, MODIFIER_TARGET_VALUE)
|
||||
|
||||
var/lvl_mods = LAZYACCESS(skill_level_mods, path)
|
||||
var/mod_level = skill_level
|
||||
for(var/k in lvl_mods)
|
||||
var/datum/skill_modifier/M = GLOB.skill_modifiers[k]
|
||||
mod_list |= M.name
|
||||
mod_ids |= M.identifier
|
||||
mod_level = M.apply_modifier(mod_level, path, src, MODIFIER_TARGET_LEVEL)
|
||||
mod_level = SANITIZE_SKILL_LEVEL(S.type, round(mod_level, 1))
|
||||
|
||||
for(var/k in mod_ids)
|
||||
var/list/mod = all_current_skill_modifiers[k]
|
||||
if(mod)
|
||||
LAZYADD(modifiers, list(mod))
|
||||
|
||||
var/list/data = list(
|
||||
name = S.name,
|
||||
desc = S.desc,
|
||||
color = S.name_color,
|
||||
skill_base = S.standard_render_value(skill_value, skill_level),
|
||||
skill_mod = S.standard_render_value(mod_value, mod_level),
|
||||
mods_tooltip = english_list(mod_list, null),
|
||||
modifiers = modifiers
|
||||
)
|
||||
current += list(data)
|
||||
|
||||
if(category)
|
||||
var/list/cat = list("name" = category, "skills" = current)
|
||||
.["categories"] += list(cat)
|
||||
var/list/dat = S.get_skill_data(src)
|
||||
if(dat["modifiers"])
|
||||
dat["modifiers"] = jointext(dat["modifiers"], ", ")
|
||||
.["skills"] += list(dat)
|
||||
|
||||
/datum/skill_holder/ui_data(mob/user)
|
||||
. = list()
|
||||
.["see_skill_mods"] = see_skill_mods
|
||||
.["compact_mode"] = compact_mode
|
||||
.["selected_category"] = selected_category
|
||||
|
||||
/datum/skill_holder/ui_act(action, params)
|
||||
. = ..()
|
||||
@@ -108,5 +49,3 @@
|
||||
return TRUE
|
||||
if("compact_toggle")
|
||||
compact_mode = !compact_mode
|
||||
if("select")
|
||||
selected_category = params["category"]
|
||||
|
||||
@@ -60,10 +60,29 @@ 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,
|
||||
"name_color" = name_color,
|
||||
"level_based" = progression_type == SKILL_PROGRESSION_LEVEL,
|
||||
"value_base" = skill_value,
|
||||
"value_mod" = skill_value,
|
||||
"base_readout" = skill_value,
|
||||
"mod_readout" = skill_value
|
||||
)
|
||||
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)
|
||||
.["mod_readout"] = .["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.
|
||||
@@ -74,10 +93,13 @@ 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"
|
||||
.["max_value"] = 1
|
||||
|
||||
/datum/skill/numerical
|
||||
abstract_type = /datum/skill/numerical
|
||||
@@ -87,14 +109,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
|
||||
@@ -170,8 +193,12 @@ 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"]
|
||||
|
||||
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]
|
||||
@@ -179,8 +206,42 @@ 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"] = .["lvl_mod"] = associative ? (!level ? unskilled_tier : levels[level]) : level
|
||||
.["lvl_base_color"] = .["lvl_mod_color"] = (level+1)*(350/max_levels)
|
||||
.["xp_next_lvl_base"] = "XP To Next Level : \[[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_lvls"] = max_levels
|
||||
var/max_value
|
||||
switch(level_up_method)
|
||||
if(STANDARD_LEVEL_UP)
|
||||
max_value = .["max_value"] = XP_LEVEL(standard_xp_lvl_up, xp_lvl_multiplier, max_levels)
|
||||
if(DWARFY_LEVEL_UP)
|
||||
max_value = .["max_value"] = DORF_XP_LEVEL(standard_xp_lvl_up, xp_lvl_multiplier, max_levels)
|
||||
|
||||
.["base_readout"] = "Overall Skill Progress: \[[skill_value_base]/[max_value]\]"
|
||||
|
||||
var/list/mods = LAZYACCESS(H.skill_level_mods, type)
|
||||
if(mods) //I'm not proud of doing a similar 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"] = associative ? (!level ? unskilled_tier : levels[level]) : level
|
||||
.["lvl_mod_color"] = (level+1)*(350/max_levels)
|
||||
.["xp_next_lvl_mod"] = "XP To Next Level : \[[skill_value_mod - current_lvl_xp_sum]/[next_lvl_xp]\]"
|
||||
.["mod_readout"] = "Overall Skill Progress: \[[skill_value_mod]/[max_value]\]"
|
||||
|
||||
/datum/skill/level/job
|
||||
abstract_type = /datum/skill/level/job
|
||||
|
||||
@@ -28,15 +28,6 @@
|
||||
var/see_skill_mods = TRUE
|
||||
/// Whether skill descriptions are displayed or not.
|
||||
var/compact_mode = FALSE
|
||||
/// The current selected skill category.
|
||||
var/selected_category
|
||||
|
||||
/datum/skill_holder/New(owner)
|
||||
..()
|
||||
src.owner = owner
|
||||
var/datum/skill/S = locate() in GLOB.skill_datums
|
||||
if(S)
|
||||
selected_category = S.ui_category
|
||||
|
||||
/**
|
||||
* Grabs the value of a skill.
|
||||
@@ -201,18 +192,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("")
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
import { useBackend } from '../backend';
|
||||
import { Box, Button, LabeledList, ProgressBar, Section } from '../components';
|
||||
const skillgreen = {
|
||||
color: 'lightgreen',
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
const skillyellow = {
|
||||
color: '#FFDB58',
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
export const SkillPanel = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const skills = data.skills || [];
|
||||
return (
|
||||
<Section title={skills.playername}>
|
||||
<LabeledList>
|
||||
{skills.map(skill => (
|
||||
<LabeledList.Item key={skill.name} label={skill.name}>
|
||||
<span style={skillyellow}>
|
||||
{skill.desc}
|
||||
</span>
|
||||
<br />
|
||||
<Level skill_lvl_num={skill.lvlnum} skill_lvl={skill.lvl} />
|
||||
<br />
|
||||
Total Experience: [{skill.exp} XP]
|
||||
<br />
|
||||
XP To Next Level:
|
||||
{skill.exp_req !== 0 ? (
|
||||
<span>
|
||||
[{skill.exp_prog} / {skill.exp_req}]
|
||||
</span>
|
||||
) : (
|
||||
<span style={skillgreen}>
|
||||
[MAXXED]
|
||||
</span>
|
||||
)}
|
||||
<br />
|
||||
Overall Skill Progress: [{skill.exp} / {skill.max_exp}]
|
||||
<ProgressBar
|
||||
value={skill.exp_percent}
|
||||
color="good" />
|
||||
<br />
|
||||
<Button
|
||||
content="Adjust Exp"
|
||||
onClick={() => act('adj_exp', {
|
||||
skill: skill.path,
|
||||
})} />
|
||||
<Button
|
||||
content="Set Exp"
|
||||
onClick={() => act('set_exp', {
|
||||
skill: skill.path,
|
||||
})} />
|
||||
<Button
|
||||
content="Set Level"
|
||||
onClick={() => act('set_lvl', {
|
||||
skill: skill.path,
|
||||
})} />
|
||||
<br />
|
||||
<br />
|
||||
</LabeledList.Item>
|
||||
))}
|
||||
</LabeledList>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
const Level = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
skill_lvl_num,
|
||||
skill_lvl,
|
||||
} = props;
|
||||
let textstyle="font-weight:bold; color:hsl("+skill_lvl_num*50+", 50%, 50%)";
|
||||
return (
|
||||
<span>Level: [<span style={textstyle}>{skill_lvl}</span>]</span>
|
||||
);
|
||||
};
|
||||
const XPToNextLevel = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
xp_req,
|
||||
xp_prog,
|
||||
} = props;
|
||||
if (xp_req === 0) {
|
||||
return (
|
||||
<span style={skillgreen}>
|
||||
to next level: MAXXED
|
||||
</span>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<span>XP to next level: [{xp_prog} / {xp_req}]</span>
|
||||
);
|
||||
};
|
||||
@@ -1,150 +0,0 @@
|
||||
import { multiline, decodeHtmlEntities } from 'common/string';
|
||||
import { Fragment } from 'inferno';
|
||||
import { act } from '../byond';
|
||||
import { Box, Button, Section, LabeledList, Table, Tabs, Tooltip } from '../components';
|
||||
|
||||
export const Skills = props => {
|
||||
const { state } = props;
|
||||
const { config, data } = state;
|
||||
const { ref } = config;
|
||||
const {
|
||||
name,
|
||||
compact_mode,
|
||||
selected_category,
|
||||
see_skill_mods,
|
||||
categories = [],
|
||||
} = props;
|
||||
return (
|
||||
<Section
|
||||
buttons={(
|
||||
<Fragment>
|
||||
<Button
|
||||
icon={see_skill_mods ? 'check-square-o' : 'square-o'}
|
||||
content={'Show modifiers'}
|
||||
onClick={() => act(ref, 'toggle_mods')} />
|
||||
<Button
|
||||
icon={compact_mode ? 'list' : 'info'}
|
||||
content={compact_mode ? 'Compact' : 'Detailed'}
|
||||
onClick={() => act(ref, 'compact_toggle')} />
|
||||
</Fragment>
|
||||
)}>
|
||||
{(
|
||||
<Tabs vertical>
|
||||
{categories.map(category => {
|
||||
const { name, skills } = category;
|
||||
if (name !== selected_category) {
|
||||
return (
|
||||
<Tabs.Tab
|
||||
key={name}
|
||||
label={`${name} (${skills.length})`}>
|
||||
</Tabs.Tab>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Tabs.Tab
|
||||
key={name}
|
||||
label={`${name} (${skills.length})`}>
|
||||
{() => (
|
||||
<skillList
|
||||
compact={compact_mode}
|
||||
skills={skills}
|
||||
see_mods={see_skill_mods}
|
||||
/>
|
||||
)}
|
||||
</Tabs.Tab>
|
||||
);
|
||||
})}
|
||||
</Tabs>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const skillList = props => {
|
||||
const {
|
||||
compact,
|
||||
skills,
|
||||
see_mods,
|
||||
} = props;
|
||||
if (compact) {
|
||||
return (
|
||||
<Table>
|
||||
{skills.map(skill => {
|
||||
return (
|
||||
<Table.Row
|
||||
key={skill.name}
|
||||
className="candystripe">
|
||||
<Table.Cell bold>
|
||||
<Box color={skill.color}>
|
||||
{decodeHtmlEntities(skill.name)}
|
||||
</Box>
|
||||
</Table.Cell>
|
||||
<Table.Cell collapsing textAlign="right">
|
||||
<Box mr={1}>
|
||||
(see_mods
|
||||
? skill.skill_base
|
||||
: skill.skill_mod
|
||||
)
|
||||
{!!skill.mods_tooltip && (
|
||||
<Tooltip
|
||||
content={
|
||||
decodeHtmlEntities(
|
||||
`${skill.desc}
|
||||
\nModifiers:
|
||||
${skill.mods_tooltip}
|
||||
`)
|
||||
}
|
||||
position="left" />
|
||||
) || (
|
||||
<Tooltip
|
||||
content={
|
||||
decodeHtmlEntities(`${skill.desc}`)
|
||||
}
|
||||
position="left" />
|
||||
)}
|
||||
</Box>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
);
|
||||
})}
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
return skills.map(skill => {
|
||||
return (
|
||||
<Section
|
||||
key={skill.name}
|
||||
title={skill.name}
|
||||
level={2}
|
||||
buttons={(
|
||||
<Box mr={1}>
|
||||
content={
|
||||
see_mods
|
||||
? skill.skill_base
|
||||
: skill.skill_mod
|
||||
}
|
||||
</Box>
|
||||
)}>
|
||||
{decodeHtmlEntities(skill.desc)}
|
||||
{!!skill.modifiers && (
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Current Modifiers">
|
||||
{skill.modifiers.map(modifier => {
|
||||
<Box className={modifier.icon_class} mr={1}>
|
||||
<Tooltip
|
||||
content={
|
||||
decodeHtmlEntities(
|
||||
`<b>${modifier.name}</b>
|
||||
\n${modifier.desc}
|
||||
`)
|
||||
}
|
||||
position="relative" />
|
||||
</Box>;
|
||||
})}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
});
|
||||
};
|
||||
File diff suppressed because one or more lines are too long
@@ -81,7 +81,7 @@ import { RapidPipeDispenser } from './interfaces/RapidPipeDispenser';
|
||||
import { SatelliteControl } from './interfaces/SatelliteControl';
|
||||
import { ScannerGate } from './interfaces/ScannerGate';
|
||||
import { ShuttleManipulator } from './interfaces/ShuttleManipulator';
|
||||
import { Skills } from './interfaces/Skills';
|
||||
import { SkillPanel } from './interfaces/SkillPanel';
|
||||
import { Sleeper } from './interfaces/Sleeper';
|
||||
import { SlimeBodySwapper } from './interfaces/SlimeBodySwapper';
|
||||
import { Signaler } from './interfaces/Signaler';
|
||||
@@ -473,8 +473,8 @@ const ROUTES = {
|
||||
component: () => ShuttleManipulator,
|
||||
scrollable: true,
|
||||
},
|
||||
skills: {
|
||||
component: () => Skills,
|
||||
skillpanel: {
|
||||
component: () => SkillPanel,
|
||||
scrollable: true,
|
||||
},
|
||||
sleeper: {
|
||||
|
||||
Reference in New Issue
Block a user