From d04d6ae9ebb524a67cc6fb1dda1f276f2a0aba75 Mon Sep 17 00:00:00 2001
From: Ghommie <42542238+Ghommie@users.noreply.github.com>
Date: Mon, 25 May 2020 15:06:31 +0200
Subject: [PATCH 01/10] WIP
---
code/__DEFINES/skills/defines.dm | 8 ++-
code/__HELPERS/cmp.dm | 5 ++
code/datums/mind.dm | 2 +-
code/datums/skills/_check_skills.dm | 70 +++++++++++++++++++++++++--
code/datums/skills/_skill.dm | 3 ++
code/datums/skills/_skill_holder.dm | 10 ++++
code/datums/skills/_skill_modifier.dm | 7 +++
code/datums/skills/engineering.dm | 1 +
code/datums/skills/medical.dm | 1 +
code/modules/client/asset_cache.dm | 4 ++
10 files changed, 106 insertions(+), 5 deletions(-)
diff --git a/code/__DEFINES/skills/defines.dm b/code/__DEFINES/skills/defines.dm
index 659c0fe11b..60d2321927 100644
--- a/code/__DEFINES/skills/defines.dm
+++ b/code/__DEFINES/skills/defines.dm
@@ -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
\ No newline at end of file
+#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"
diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm
index 9b877e8fb0..963ed2a326 100644
--- a/code/__HELPERS/cmp.dm
+++ b/code/__HELPERS/cmp.dm
@@ -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)
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index b7eac62e83..a9438fa80b 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -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
diff --git a/code/datums/skills/_check_skills.dm b/code/datums/skills/_check_skills.dm
index a94c7c95ba..d2921c8756 100644
--- a/code/datums/skills/_check_skills.dm
+++ b/code/datums/skills/_check_skills.dm
@@ -11,6 +11,70 @@
if(!mind.skill_holder)
to_chat(usr, "How do you check the skills of [(usr == src)? "yourself when you are" : "something"] without the capability for skills? (PROBABLY A BUG, PRESS F1.)")
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)
+ if(need_static_data_update)
+ update_static_data(user)
+ 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, "check_skills", "[owner.name]'s Skills", 900, 480, 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)
+
+ .["skills"] = list()
+ var/list/current
+ var/category
+ for(var/path in GLOB.skill_datums)
+ var/datum/skill/S = GLOB.skill_datums[path]
+ if(!current || S.ui_category != category)
+ if(category)
+ .["skills"][category] = current
+ 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_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_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_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))
+
+ var/list/data = list(
+ name = S.name,
+ color = S.name_color,
+ skill_base = S.standard_render_value(skill_value, skill_level),
+ skill_mod = S.standard_render_value(mod_value, mod_level),
+ mod_ids = mod_ids
+ )
+ current += list(data)
+
+ if(category)
+ .["skills"][category] = current
+
+ 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)
+ )
+ .["modifiers"] = all_mods
diff --git a/code/datums/skills/_skill.dm b/code/datums/skills/_skill.dm
index 571a8274d8..9490c7c7d9 100644
--- a/code/datums/skills/_skill.dm
+++ b/code/datums/skills/_skill.dm
@@ -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.
diff --git a/code/datums/skills/_skill_holder.dm b/code/datums/skills/_skill_holder.dm
index 071db3306a..2b3c963c33 100644
--- a/code/datums/skills/_skill_holder.dm
+++ b/code/datums/skills/_skill_holder.dm
@@ -20,6 +20,15 @@
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 static UI update.
+ var/need_static_data_update = TRUE
+
+
+/datum/skill_holder/New(owner)
+ ..()
+ src.owner = owner
/**
* Grabs the value of a skill.
@@ -79,6 +88,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)
diff --git a/code/datums/skills/_skill_modifier.dm b/code/datums/skills/_skill_modifier.dm
index a28cf3aebd..5a81521b49 100644
--- a/code/datums/skills/_skill_modifier.dm
+++ b/code/datums/skills/_skill_modifier.dm
@@ -7,6 +7,9 @@ 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 = "???"
+ var/desc = ""
/// flags for this skill modifier.
var/modifier_flags = NONE
/// target skills, can be a specific skill typepath or a list of skill traits.
@@ -23,6 +26,8 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
var/level_mod = 1
/// Priority of this skill modifier compared to other ones.
var/priority = MODIFIER_SKILL_PRIORITY_DEF
+ /// Skill modifier icon, used in the UI
+ var/icon = "default"
/datum/skill_modifier/New(id, register = FALSE)
identifier = GET_SKILL_MOD_ID(type, id)
@@ -110,6 +115,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 +147,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)
diff --git a/code/datums/skills/engineering.dm b/code/datums/skills/engineering.dm
index db7b33450c..60e3fcc6a1 100644
--- a/code/datums/skills/engineering.dm
+++ b/code/datums/skills/engineering.dm
@@ -3,3 +3,4 @@
desc = "How proficient and knowledged you are at wiring beyond laying cables on the floor."
name_color = COLOR_PALE_ORANGE
skill_traits = list(SKILL_SANITY, SKILL_INTELLIGENCE, SKILL_USE_TOOL, SKILL_TRAINING_TOOL)
+ ui_category = SKILL_UI_CAT_ENG
diff --git a/code/datums/skills/medical.dm b/code/datums/skills/medical.dm
index 404c141157..3818a77db5 100644
--- a/code/datums/skills/medical.dm
+++ b/code/datums/skills/medical.dm
@@ -3,3 +3,4 @@
desc = "How proficient you are at doing surgery."
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
diff --git a/code/modules/client/asset_cache.dm b/code/modules/client/asset_cache.dm
index 6f62701590..73c857f78d 100644
--- a/code/modules/client/asset_cache.dm
+++ b/code/modules/client/asset_cache.dm
@@ -744,3 +744,7 @@ GLOBAL_LIST_EMPTY(asset_datums)
"dna_undiscovered.gif" = 'html/dna_undiscovered.gif',
"dna_extra.gif" = 'html/dna_extra.gif'
)
+
+/datum/asset/spritesheet/simple/skills
+ name = "skills"
+
From 745695e60d51412ee3c5793c5e7db276d9213e9d Mon Sep 17 00:00:00 2001
From: Ghommie <42542238+Ghommie@users.noreply.github.com>
Date: Sat, 30 May 2020 15:55:16 +0200
Subject: [PATCH 02/10] WIP, js tiring.
---
code/datums/skills/_check_skills.dm | 31 +++-
code/datums/skills/_skill_holder.dm | 12 +-
tgui-next/packages/tgui/interfaces/Skills.js | 146 +++++++++++++++++++
3 files changed, 183 insertions(+), 6 deletions(-)
create mode 100644 tgui-next/packages/tgui/interfaces/Skills.js
diff --git a/code/datums/skills/_check_skills.dm b/code/datums/skills/_check_skills.dm
index d2921c8756..30f105ab4b 100644
--- a/code/datums/skills/_check_skills.dm
+++ b/code/datums/skills/_check_skills.dm
@@ -20,21 +20,23 @@
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, "check_skills", "[owner.name]'s Skills", 900, 480, 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)
- .["skills"] = list()
+ .["categories"] = list()
var/list/current
var/category
for(var/path in GLOB.skill_datums)
var/datum/skill/S = GLOB.skill_datums[path]
if(!current || S.ui_category != category)
if(category)
- .["skills"][category] = current
+ var/list/cat = list("name" = category, "skills" = current)
+ .["categories"] += list(cat)
current = list()
category = S.ui_category
@@ -67,7 +69,9 @@
current += list(data)
if(category)
- .["skills"][category] = current
+ var/list/cat = list("name" = category, "skills" = current)
+ .["categories"] += list(cat)
+
var/all_mods = list()
for(var/id in all_current_skill_modifiers)
@@ -78,3 +82,22 @@
icon = assets.icon_class_name(M.icon)
)
.["modifiers"] = all_mods
+
+/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)
+ . = ..()
+ if(.)
+ return
+ switch(action)
+ if("toggle_mods")
+ see_skill_mods = !see_skill_mods
+ return TRUE
+ if("compact_toggle")
+ compact_mode = !compact_mode
+ if("select")
+ selected_category = params["category"]
diff --git a/code/datums/skills/_skill_holder.dm b/code/datums/skills/_skill_holder.dm
index 2b3c963c33..be97132b5c 100644
--- a/code/datums/skills/_skill_holder.dm
+++ b/code/datums/skills/_skill_holder.dm
@@ -22,13 +22,21 @@
var/list/original_levels
/// The mind datum this skill is associated with, only used for the check_skills UI
var/datum/mind/owner
- /// For static UI update.
+ /// 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
+ /// 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.
diff --git a/tgui-next/packages/tgui/interfaces/Skills.js b/tgui-next/packages/tgui/interfaces/Skills.js
new file mode 100644
index 0000000000..548d5ebee3
--- /dev/null
+++ b/tgui-next/packages/tgui/interfaces/Skills.js
@@ -0,0 +1,146 @@
+import { decodeHtmlEntities } from 'common/string';
+import { Component, Fragment } from 'inferno';
+import { act } from '../byond';
+import { Box, Button, Input, Section, Table, Tabs } from '../components';
+
+// It's a class because we need to store state in the form of
+// the current hovered item
+export class Uplink extends Component {
+ constructor() {
+ super();
+ this.state = {
+ hoveredItem: {},
+ };
+ }
+
+ setHoveredItem(hoveredItem) {
+ this.setState({
+ hoveredItem,
+ });
+ }
+
+ render() {
+ const { state } = this.props;
+ const { config, data } = state;
+ const { ref } = config;
+ const {
+ see_skill_mods,
+ compact_mode,
+ categories = [],
+ } = data;
+ return (
+
| Skill | Value |
|---|---|
| [S.name] | [S.standard_render_value(skill_value, skill_level)] |