From 8e899178d6ae2f7c9688e6f9b4a0ce3e35a3e9d7 Mon Sep 17 00:00:00 2001 From: Matt Atlas Date: Sun, 31 Mar 2024 20:32:25 +0200 Subject: [PATCH 01/16] Education and skills ground work --- aurorastation.dme | 12 ++++++- code/__DEFINES/skills.dm | 23 ++++++++++++++ code/controllers/subsystems/skills.dm | 3 ++ code/datums/skills/_skills.dm | 11 +++++++ code/datums/skills/combat/combat.dm | 17 ++++++++++ code/datums/skills/everyday/service.dm | 17 ++++++++++ .../datums/skills/occupational/engineering.dm | 23 ++++++++++++++ code/datums/skills/occupational/medical.dm | 26 ++++++++++++++++ .../background/education/_education.dm | 11 +++++++ code/modules/background/education/medical.dm | 16 ++++++++++ .../preference_setup/preference_setup.dm | 15 ++++++--- .../client/preference_setup/skills/skills.dm | 31 +++++++++++++++++++ 12 files changed, 199 insertions(+), 6 deletions(-) create mode 100644 code/__DEFINES/skills.dm create mode 100644 code/controllers/subsystems/skills.dm create mode 100644 code/datums/skills/_skills.dm create mode 100644 code/datums/skills/combat/combat.dm create mode 100644 code/datums/skills/everyday/service.dm create mode 100644 code/datums/skills/occupational/engineering.dm create mode 100644 code/datums/skills/occupational/medical.dm create mode 100644 code/modules/background/education/_education.dm create mode 100644 code/modules/background/education/medical.dm create mode 100644 code/modules/client/preference_setup/skills/skills.dm diff --git a/aurorastation.dme b/aurorastation.dme index 4c939bd13ea..abc6c79b283 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -111,6 +111,7 @@ #include "code\__DEFINES\ship_weapons.dm" #include "code\__DEFINES\shuttle.dm" #include "code\__DEFINES\singletons.dm" +#include "code\__DEFINES\skills.dm" #include "code\__DEFINES\smart_token_bucket.dm" #include "code\__DEFINES\solar.dm" #include "code\__DEFINES\sound.dm" @@ -334,6 +335,7 @@ #include "code\controllers\subsystems\records.dm" #include "code\controllers\subsystems\responseteam.dm" #include "code\controllers\subsystems\runechat.dm" +#include "code\controllers\subsystems\skills.dm" #include "code\controllers\subsystems\skybox.dm" #include "code\controllers\subsystems\sound_loops.dm" #include "code\controllers\subsystems\sounds.dm" @@ -494,6 +496,11 @@ #include "code\datums\repositories\singletons.dm" #include "code\datums\repositories\sound_channels.dm" #include "code\datums\repositories\unique.dm" +#include "code\datums\skills\_skills.dm" +#include "code\datums\skills\combat\combat.dm" +#include "code\datums\skills\everyday\service.dm" +#include "code\datums\skills\occupational\engineering.dm" +#include "code\datums\skills\occupational\medical.dm" #include "code\datums\state_machine\state.dm" #include "code\datums\state_machine\transition.dm" #include "code\datums\tips\tips.dm" @@ -1619,6 +1626,8 @@ #include "code\modules\background\citizenship\tajara.dm" #include "code\modules\background\citizenship\unathi.dm" #include "code\modules\background\citizenship\vaurca.dm" +#include "code\modules\background\education\_education.dm" +#include "code\modules\background\education\medical.dm" #include "code\modules\background\origins\_origins.dm" #include "code\modules\background\origins\origins\diona\biesel.dm" #include "code\modules\background\origins\origins\diona\coalition.dm" @@ -1785,6 +1794,7 @@ #include "code\modules\client\preference_setup\occupation\occupation.dm" #include "code\modules\client\preference_setup\origin\origin.dm" #include "code\modules\client\preference_setup\other\01_incidents.dm" +#include "code\modules\client\preference_setup\skills\skills.dm" #include "code\modules\client\verbs\ping.dm" #include "code\modules\clothing\chameleon.dm" #include "code\modules\clothing\clothing.dm" @@ -3653,12 +3663,12 @@ #include "code\ZAS\Zone.dm" #include "code\ze_genesis_call\genesis_call.dm" #include "interface\interface.dm" +#include "interface\skin.dmf" #include "interface\fonts\fonts_datum.dm" #include "interface\fonts\grand_9k.dm" #include "interface\fonts\pixellari.dm" #include "interface\fonts\spess_font.dm" #include "interface\fonts\tiny_unicode.dm" -#include "interface\skin.dmf" #include "maps\_common\areas\ai.dm" #include "maps\_common\areas\areas.dm" #include "maps\_common\areas\asteroid_areas.dm" diff --git a/code/__DEFINES/skills.dm b/code/__DEFINES/skills.dm new file mode 100644 index 00000000000..9eeb22880b8 --- /dev/null +++ b/code/__DEFINES/skills.dm @@ -0,0 +1,23 @@ +/// You don't know anything about this subject. +#define SKILL_LEVEL_UNFAMILIAR 1 +/// You're familiar with this subject, either by reading into it or by doing some courses. +#define SKILL_LEVEL_FAMILIAR 2 +/// You've been formally trained in this subject. Typically, this is the minimum level for a job. +#define SKILL_LEVEL_TRAINED 3 +/// You have some training and a good amount of experience in this subject. +#define SKILL_LEVEL_PROFESSIONAL 4 + +/// An everyday skill is a skill that can be picked up normally. Think like mixing a drink, growing a plant, cooking, and so on. +#define SKILL_CATEGORY_EVERYDAY "Everyday" + #define SKILL_SUBCATEGORY_SERVICE "Service" + #define SKILL_SUBCATEGORY_MUNDANE "Mundane" + +/// Occupational skills are the skills necessary for you to do your job to a minimum degree. +#define SKILL_CATEGORY_OCCUPATIONAL "Occupational" + #define SKILL_SUBCATEGORY_MEDICAL "Medical" + #define SKILL_SUBCATEGORY_ENGINEERING "Engineering" + +///A combat skill is a skill that has a direct effect in combat. These have an increased cost. +#define SKILL_CATEGORY_COMBAT "Combat" + #define SKILL_SUBCATEGORY_RANGED "Ranged" + #define SKILL_SUBCATEGORY_MELEE "Melee" diff --git a/code/controllers/subsystems/skills.dm b/code/controllers/subsystems/skills.dm new file mode 100644 index 00000000000..1103982d5cc --- /dev/null +++ b/code/controllers/subsystems/skills.dm @@ -0,0 +1,3 @@ +SUBSYSTEM_DEF(skills) + name = "Skills" + flags = SS_NO_FIRE diff --git a/code/datums/skills/_skills.dm b/code/datums/skills/_skills.dm new file mode 100644 index 00000000000..e5fb6046c01 --- /dev/null +++ b/code/datums/skills/_skills.dm @@ -0,0 +1,11 @@ +/singleton/skill + /// The displayed name of the skill. + var/name + /// A description of this skill's effects. + var/description + /// The maximum level this skill can reach. + var/maximum_level = SKILL_LEVEL_TRAINED + /// The category of this skill. Used for sorting, typically. + var/category + /// The sub-category of this skill. Used to better sort skills. + var/subcategory diff --git a/code/datums/skills/combat/combat.dm b/code/datums/skills/combat/combat.dm new file mode 100644 index 00000000000..5b828cee076 --- /dev/null +++ b/code/datums/skills/combat/combat.dm @@ -0,0 +1,17 @@ +/singleton/skill/unarmed_combat + name = "Unarmed Combat" + description = "punching things" + category = SKILL_CATEGORY_COMBAT + subcategory = SKILL_SUBCATEGORY_MELEE + +/singleton/skill/armed_combat + name = "Armed Combat" + description = "zomboid time" + category = SKILL_CATEGORY_COMBAT + subcategory = SKILL_SUBCATEGORY_MELEE + +/singleton/skill/firearms + name = "Firearms" + description = "using guns. split this into close arms/longarms/special arms?" + category = SKILL_CATEGORY_COMBAT + subcategory = SKILL_SUBCATEGORY_RANGED diff --git a/code/datums/skills/everyday/service.dm b/code/datums/skills/everyday/service.dm new file mode 100644 index 00000000000..4b3a49bcbb3 --- /dev/null +++ b/code/datums/skills/everyday/service.dm @@ -0,0 +1,17 @@ +/singleton/skill/mixing + name = "Mixing" + description = "valhalla skill" + category = SKILL_CATEGORY_OCCUPATIONAL + subcategory = SKILL_SUBCATEGORY_SERVICE + +/singleton/skill/cooking + name = "Cooking" + description = "Cooking Mama" + category = SKILL_CATEGORY_OCCUPATIONAL + subcategory = SKILL_SUBCATEGORY_SERVICE + +/singleton/skill/gardening + name = "Gardening" + description = "this is boring as shit" + category = SKILL_CATEGORY_OCCUPATIONAL + subcategory = SKILL_SUBCATEGORY_SERVICE diff --git a/code/datums/skills/occupational/engineering.dm b/code/datums/skills/occupational/engineering.dm new file mode 100644 index 00000000000..04157a77096 --- /dev/null +++ b/code/datums/skills/occupational/engineering.dm @@ -0,0 +1,23 @@ +/singleton/skill/electrical_engineering + name = "Electrical Engineering" + description = "wiring, anything power related" + category = SKILL_CATEGORY_OCCUPATIONAL + subcategory = SKILL_SUBCATEGORY_ENGINEERING + +/singleton/skill/mechanical_engineering + name = "Mechanical Engineering" + description = "building things" + category = SKILL_CATEGORY_OCCUPATIONAL + subcategory = SKILL_SUBCATEGORY_ENGINEERING + +/singleton/skill/atmospherics_systems + name = "Atmospherics Systems" + description = "atmospherics things" + category = SKILL_CATEGORY_OCCUPATIONAL + subcategory = SKILL_SUBCATEGORY_ENGINEERING + +/singleton/skill/reactor_systems + name = "Reactor Systems" + description = "reactor equipment" + category = SKILL_CATEGORY_OCCUPATIONAL + subcategory = SKILL_SUBCATEGORY_ENGINEERING diff --git a/code/datums/skills/occupational/medical.dm b/code/datums/skills/occupational/medical.dm new file mode 100644 index 00000000000..52687f5842d --- /dev/null +++ b/code/datums/skills/occupational/medical.dm @@ -0,0 +1,26 @@ +/singleton/skill/medicine + name = "Medicine" + desc = "how to use health analyzers, ATKs, syringes" + maximum_level = SKILL_LEVEL_PROFESSIONAL + category = SKILL_CATEGORY_MEDICAL + +/singleton/skill/surgery + name = "Surgery" + description = "the one everyone wants to do in medical to be the protag" + maximum_level = SKILL_LEVEL_PROFESSIONAL + category = SKILL_CATEGORY_MEDICAL + +/singleton/skill/pharmacology + name = "Pharmacology" + description = "why are you playing pharma LOL" + category = SKILL_CATEGORY_MEDICAL + +/singleton/skill/anatomy + name = "Anatomy" + description = "this one lets you know what's wrong with people" + category = SKILL_CATEGORY_MEDICAL + +/singleton/skill/forensics + name = "Forensics" + description = "forensics shit i guess" + category = SKILL_CATEGORY_MEDICAL diff --git a/code/modules/background/education/_education.dm b/code/modules/background/education/_education.dm new file mode 100644 index 00000000000..ba24115b347 --- /dev/null +++ b/code/modules/background/education/_education.dm @@ -0,0 +1,11 @@ +/singleton/education + /// The name of this education type. + var/name + /// The description of this education type. It should ideally match what's on the Aurora wiki, but from an IC point of view. + var/description + /// Age requirement for this education. Should match the job this is intended for. This doesn't need to be here per se, but it helps to filter results. + var/list/minimum_character_age + /// The jobs this education type allows you to access. + var/list/jobs + /// The given skills for this education type. Linked list of skill type to level. + var/list/skills diff --git a/code/modules/background/education/medical.dm b/code/modules/background/education/medical.dm new file mode 100644 index 00000000000..fbd4ea4c480 --- /dev/null +++ b/code/modules/background/education/medical.dm @@ -0,0 +1,16 @@ +/singleton/education/surgical_degree + name = "Surgery MD" + description = "You are 30 years of age or older, with applicable MD from accredited school and a completed 2 years of Residency at an \ + accredited hospital or clinic." + jobs = list("Surgeon") + minimum_character_age = list( + SPECIES_HUMAN = 30, + SPECIES_SKRELL = 60, + SPECIES_SKRELL_AXIORI = 60 + ) + skills = list( + /singleton/skill/surgery = SKILL_LEVEL_PROFESSIONAL, + /singleton/skill/medicine = SKILL_LEVEL_TRAINED, + /singleton/skill/anatomy = SKILL_LEVEL_TRAINED + ) + diff --git a/code/modules/client/preference_setup/preference_setup.dm b/code/modules/client/preference_setup/preference_setup.dm index 8be5a8721e2..f8c8e3c564c 100644 --- a/code/modules/client/preference_setup/preference_setup.dm +++ b/code/modules/client/preference_setup/preference_setup.dm @@ -28,30 +28,35 @@ sort_order = 2 category_item_type = /datum/category_item/player_setup_item/origin +/datum/category_group/player_setup_category/skill_preferences + name = "Skills" + sort_order = 3 + category_item_type = /datum/category_item/player_setup_item/skills + /datum/category_group/player_setup_category/occupation_preferences name = "Occupation" - sort_order = 3 + sort_order = 4 category_item_type = /datum/category_item/player_setup_item/occupation /datum/category_group/player_setup_category/appearance_preferences name = "Roles" - sort_order = 4 + sort_order = 5 category_item_type = /datum/category_item/player_setup_item/antagonism /datum/category_group/player_setup_category/loadout_preferences name = "Loadout" - sort_order = 5 + sort_order = 6 category_item_type = /datum/category_item/player_setup_item/loadout /datum/category_group/player_setup_category/global_preferences name = "Global" - sort_order = 6 + sort_order = 7 category_item_type = /datum/category_item/player_setup_item/player_global sql_role = SQL_PREFERENCES /datum/category_group/player_setup_category/other_preferences name = "Other" - sort_order = 7 + sort_order = 8 category_item_type = /datum/category_item/player_setup_item/other /**************************** diff --git a/code/modules/client/preference_setup/skills/skills.dm b/code/modules/client/preference_setup/skills/skills.dm new file mode 100644 index 00000000000..954dee10a81 --- /dev/null +++ b/code/modules/client/preference_setup/skills/skills.dm @@ -0,0 +1,31 @@ +/datum/category_item/player_setup_item/skills + name = "Skills" + sort_order = 1 + +/datum/category_item/player_setup_item/skills/load_character(var/savefile/S) + //todomatt + +/datum/category_item/player_setup_item/skills/save_character(var/savefile/S) + //todomatt + +/datum/category_item/player_setup_item/skills/gather_load_query() + //todomatt + +/datum/category_item/player_setup_item/skills/gather_load_parameters() + //todomatt + +/datum/category_item/player_setup_item/skills/gather_save_query() + //todomatt + +/datum/category_item/player_setup_item/skills/gather_save_parameters() + //todomatt + +/datum/category_item/player_setup_item/skills/sanitize_character(var/sql_load = 0) + //todomatt + +/datum/category_item/player_setup_item/skills/content(var/mob/user) + //todomatt + +/datum/category_item/player_setup_item/skills/OnTopic(href, href_list, user) + //todomatt + return ..() From 73746c400b29a70d012af100001041d58cfc5339 Mon Sep 17 00:00:00 2001 From: Matt Atlas Date: Mon, 1 Apr 2024 23:39:11 +0200 Subject: [PATCH 02/16] some more work on skills, SQL base work --- SQL/migrate-2023/V011__skills_education.sql | 7 ++++ aurorastation.dme | 1 + code/__DEFINES/skills.dm | 1 + code/datums/skills/occupational/medical.dm | 17 ++++++---- code/datums/skills/occupational/science.dm | 23 +++++++++++++ .../client/preference_setup/origin/origin.dm | 5 +++ .../client/preference_setup/skills/skills.dm | 33 +++++++++++++++---- 7 files changed, 75 insertions(+), 12 deletions(-) create mode 100644 SQL/migrate-2023/V011__skills_education.sql create mode 100644 code/datums/skills/occupational/science.dm diff --git a/SQL/migrate-2023/V011__skills_education.sql b/SQL/migrate-2023/V011__skills_education.sql new file mode 100644 index 00000000000..3528e569a1f --- /dev/null +++ b/SQL/migrate-2023/V011__skills_education.sql @@ -0,0 +1,7 @@ +-- +-- Implemented in PR #?????. +-- Add education and skills. +-- + +ALTER TABLE `ss13_characters` ADD COLUMN `education` VARCHAR(48) DEFAULT NULL AFTER `origin`; +ALTER TABLE `ss13_characters` ADD COLUMN `skills` VARCHAR(256) DEFAULT NULL AFTER `education`; diff --git a/aurorastation.dme b/aurorastation.dme index abc6c79b283..a3b95a25454 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -501,6 +501,7 @@ #include "code\datums\skills\everyday\service.dm" #include "code\datums\skills\occupational\engineering.dm" #include "code\datums\skills\occupational\medical.dm" +#include "code\datums\skills\occupational\science.dm" #include "code\datums\state_machine\state.dm" #include "code\datums\state_machine\transition.dm" #include "code\datums\tips\tips.dm" diff --git a/code/__DEFINES/skills.dm b/code/__DEFINES/skills.dm index 9eeb22880b8..19ec510482d 100644 --- a/code/__DEFINES/skills.dm +++ b/code/__DEFINES/skills.dm @@ -16,6 +16,7 @@ #define SKILL_CATEGORY_OCCUPATIONAL "Occupational" #define SKILL_SUBCATEGORY_MEDICAL "Medical" #define SKILL_SUBCATEGORY_ENGINEERING "Engineering" + #define SKILL_SUBCATEGORY_SCIENCE "Science" ///A combat skill is a skill that has a direct effect in combat. These have an increased cost. #define SKILL_CATEGORY_COMBAT "Combat" diff --git a/code/datums/skills/occupational/medical.dm b/code/datums/skills/occupational/medical.dm index 52687f5842d..e1501406ba7 100644 --- a/code/datums/skills/occupational/medical.dm +++ b/code/datums/skills/occupational/medical.dm @@ -1,26 +1,31 @@ /singleton/skill/medicine name = "Medicine" - desc = "how to use health analyzers, ATKs, syringes" + description = = "how to use health analyzers, ATKs, syringes" maximum_level = SKILL_LEVEL_PROFESSIONAL - category = SKILL_CATEGORY_MEDICAL + category = SKILL_CATEGORY_OCCUPATIONAL + subcategory = SKILL_SUBCATEGORY_MEDICAL /singleton/skill/surgery name = "Surgery" description = "the one everyone wants to do in medical to be the protag" maximum_level = SKILL_LEVEL_PROFESSIONAL - category = SKILL_CATEGORY_MEDICAL + category = SKILL_CATEGORY_OCCUPATIONAL + subcategory = SKILL_SUBCATEGORY_MEDICAL /singleton/skill/pharmacology name = "Pharmacology" description = "why are you playing pharma LOL" - category = SKILL_CATEGORY_MEDICAL + category = SKILL_CATEGORY_OCCUPATIONAL + subcategory = SKILL_SUBCATEGORY_MEDICAL /singleton/skill/anatomy name = "Anatomy" description = "this one lets you know what's wrong with people" - category = SKILL_CATEGORY_MEDICAL + category = SKILL_CATEGORY_OCCUPATIONAL + subcategory = SKILL_SUBCATEGORY_MEDICAL /singleton/skill/forensics name = "Forensics" description = "forensics shit i guess" - category = SKILL_CATEGORY_MEDICAL + category = SKILL_CATEGORY_OCCUPATIONAL + subcategory = SKILL_SUBCATEGORY_MEDICAL diff --git a/code/datums/skills/occupational/science.dm b/code/datums/skills/occupational/science.dm new file mode 100644 index 00000000000..42c9b1d644e --- /dev/null +++ b/code/datums/skills/occupational/science.dm @@ -0,0 +1,23 @@ +/singleton/skill/research + name = "Research" + desc = "it's generic research shit, using the protolathe, destructive analyzers, etc" + category = SKILL_CATEGORY_OCCUPATIONAL + subcategory = SKILL_SUBCATEGORY_SCIENCE + +/singleton/skill/robotics + name = "Robotics" + desc = "fixing cyborgs and IPCs" + category = SKILL_CATEGORY_OCCUPATIONAL + subcategory = SKILL_SUBCATEGORY_SCIENCE + +/singleton/skill/xenobotany + name = "Xenobotany" + desc = "gene editing plants" + category = SKILL_CATEGORY_OCCUPATIONAL + subcategory = SKILL_SUBCATEGORY_SCIENCE + +/singleton/skill/archaeology + name = "Archaeology" + desc = "finding archaeological stuff" + category = SKILL_CATEGORY_OCCUPATIONAL + subcategory = SKILL_SUBCATEGORY_SCIENCE diff --git a/code/modules/client/preference_setup/origin/origin.dm b/code/modules/client/preference_setup/origin/origin.dm index a4baf10ac52..82d0bd1415e 100644 --- a/code/modules/client/preference_setup/origin/origin.dm +++ b/code/modules/client/preference_setup/origin/origin.dm @@ -9,6 +9,7 @@ /datum/category_item/player_setup_item/origin/load_character(var/savefile/S) S["culture"] >> pref.culture S["origin"] >> pref.origin + S["education"] >> pref.education S["citizenship"] >> pref.citizenship S["religion"] >> pref.religion S["accent"] >> pref.accent @@ -17,6 +18,7 @@ /datum/category_item/player_setup_item/origin/save_character(var/savefile/S) S["culture"] << pref.culture S["origin"] << pref.origin + S["education"] << pref.education S["citizenship"] << pref.citizenship S["religion"] << pref.religion S["accent"] << pref.accent @@ -28,6 +30,7 @@ "vars" = list( "culture", "origin", + "education", "economic_status", "citizenship", "religion", @@ -45,6 +48,7 @@ "ss13_characters" = list( "culture", "origin", + "education", "economic_status", "citizenship", "religion", @@ -58,6 +62,7 @@ return list( "culture" = pref.culture, "origin" = pref.origin, + "education" = pref.education, "economic_status" = pref.economic_status, "citizenship" = pref.citizenship, "religion" = pref.religion, diff --git a/code/modules/client/preference_setup/skills/skills.dm b/code/modules/client/preference_setup/skills/skills.dm index 954dee10a81..e4f3d58c2b3 100644 --- a/code/modules/client/preference_setup/skills/skills.dm +++ b/code/modules/client/preference_setup/skills/skills.dm @@ -3,28 +3,49 @@ sort_order = 1 /datum/category_item/player_setup_item/skills/load_character(var/savefile/S) + S["culture"] >> pref.education //todomatt /datum/category_item/player_setup_item/skills/save_character(var/savefile/S) - //todomatt + S["culture"] << pref.skills /datum/category_item/player_setup_item/skills/gather_load_query() - //todomatt + return list( + "ss13_characters" = list( + "vars" = list( + "skills" + ), + "args" = list("id") + ) + ) /datum/category_item/player_setup_item/skills/gather_load_parameters() - //todomatt + return list("id" = pref.current_character) /datum/category_item/player_setup_item/skills/gather_save_query() - //todomatt + return list( + "ss13_characters" = list( + "skills", + "id" = 1, + "ckey" = 1 + ) + ) /datum/category_item/player_setup_item/skills/gather_save_parameters() - //todomatt + return list( + "skills" = pref.culture, + "id" = pref.current_character, + "ckey" = PREF_CLIENT_CKEY + ) + /datum/category_item/player_setup_item/skills/sanitize_character(var/sql_load = 0) //todomatt /datum/category_item/player_setup_item/skills/content(var/mob/user) - //todomatt + var/list/dat = list() + dat += "skills n shit" + . = dat.Join() /datum/category_item/player_setup_item/skills/OnTopic(href, href_list, user) //todomatt From 4c2a84c15cebc4dfa0766dbc780bfcdfe911dde0 Mon Sep 17 00:00:00 2001 From: Matt Atlas Date: Thu, 4 Apr 2024 22:04:40 +0200 Subject: [PATCH 03/16] skill caps, char setup beginning --- SQL/migrate-2023/V011__skills_education.sql | 1 + code/datums/skills/_skills.dm | 3 + .../datums/skills/occupational/engineering.dm | 4 + code/datums/skills/occupational/medical.dm | 7 +- code/datums/skills/occupational/science.dm | 12 ++- .../background/education/_education.dm | 7 ++ .../client/preference_setup/origin/origin.dm | 85 +++++++++++++++++-- .../client/preference_setup/skills/skills.dm | 5 +- code/modules/client/preferences.dm | 24 ++++-- 9 files changed, 126 insertions(+), 22 deletions(-) diff --git a/SQL/migrate-2023/V011__skills_education.sql b/SQL/migrate-2023/V011__skills_education.sql index 3528e569a1f..4ba8a8996f1 100644 --- a/SQL/migrate-2023/V011__skills_education.sql +++ b/SQL/migrate-2023/V011__skills_education.sql @@ -5,3 +5,4 @@ ALTER TABLE `ss13_characters` ADD COLUMN `education` VARCHAR(48) DEFAULT NULL AFTER `origin`; ALTER TABLE `ss13_characters` ADD COLUMN `skills` VARCHAR(256) DEFAULT NULL AFTER `education`; +ALTER TABLE `ss13_characters` DROP COLUMN `home_system`; diff --git a/code/datums/skills/_skills.dm b/code/datums/skills/_skills.dm index e5fb6046c01..d0d67306f49 100644 --- a/code/datums/skills/_skills.dm +++ b/code/datums/skills/_skills.dm @@ -3,6 +3,9 @@ var/name /// A description of this skill's effects. var/description + /// The maximum level someone with no education can reach in this skill. Typically, this should be FAMILIAR on occupational skills. + /// If null, then there is no cap. + var/uneducated_skill_cap /// The maximum level this skill can reach. var/maximum_level = SKILL_LEVEL_TRAINED /// The category of this skill. Used for sorting, typically. diff --git a/code/datums/skills/occupational/engineering.dm b/code/datums/skills/occupational/engineering.dm index 04157a77096..bd7d41f966c 100644 --- a/code/datums/skills/occupational/engineering.dm +++ b/code/datums/skills/occupational/engineering.dm @@ -1,23 +1,27 @@ /singleton/skill/electrical_engineering name = "Electrical Engineering" description = "wiring, anything power related" + uneducated_skill_cap = SKILL_LEVEL_FAMILIAR category = SKILL_CATEGORY_OCCUPATIONAL subcategory = SKILL_SUBCATEGORY_ENGINEERING /singleton/skill/mechanical_engineering name = "Mechanical Engineering" description = "building things" + uneducated_skill_cap = SKILL_LEVEL_FAMILIAR category = SKILL_CATEGORY_OCCUPATIONAL subcategory = SKILL_SUBCATEGORY_ENGINEERING /singleton/skill/atmospherics_systems name = "Atmospherics Systems" description = "atmospherics things" + uneducated_skill_cap = SKILL_LEVEL_UNFAMILIAR category = SKILL_CATEGORY_OCCUPATIONAL subcategory = SKILL_SUBCATEGORY_ENGINEERING /singleton/skill/reactor_systems name = "Reactor Systems" description = "reactor equipment" + uneducated_skill_cap = SKILL_LEVEL_UNFAMILIAR category = SKILL_CATEGORY_OCCUPATIONAL subcategory = SKILL_SUBCATEGORY_ENGINEERING diff --git a/code/datums/skills/occupational/medical.dm b/code/datums/skills/occupational/medical.dm index e1501406ba7..028b8e06028 100644 --- a/code/datums/skills/occupational/medical.dm +++ b/code/datums/skills/occupational/medical.dm @@ -1,6 +1,7 @@ /singleton/skill/medicine name = "Medicine" - description = = "how to use health analyzers, ATKs, syringes" + description ="how to use health analyzers, ATKs, syringes" + uneducated_skill_cap = SKILL_LEVEL_FAMILIAR maximum_level = SKILL_LEVEL_PROFESSIONAL category = SKILL_CATEGORY_OCCUPATIONAL subcategory = SKILL_SUBCATEGORY_MEDICAL @@ -8,6 +9,7 @@ /singleton/skill/surgery name = "Surgery" description = "the one everyone wants to do in medical to be the protag" + uneducated_skill_cap = SKILL_LEVEL_UNFAMILIAR maximum_level = SKILL_LEVEL_PROFESSIONAL category = SKILL_CATEGORY_OCCUPATIONAL subcategory = SKILL_SUBCATEGORY_MEDICAL @@ -15,17 +17,20 @@ /singleton/skill/pharmacology name = "Pharmacology" description = "why are you playing pharma LOL" + uneducated_skill_cap = SKILL_LEVEL_UNFAMILIAR category = SKILL_CATEGORY_OCCUPATIONAL subcategory = SKILL_SUBCATEGORY_MEDICAL /singleton/skill/anatomy name = "Anatomy" description = "this one lets you know what's wrong with people" + uneducated_skill_cap = SKILL_LEVEL_FAMILIAR category = SKILL_CATEGORY_OCCUPATIONAL subcategory = SKILL_SUBCATEGORY_MEDICAL /singleton/skill/forensics name = "Forensics" description = "forensics shit i guess" + uneducated_skill_cap = SKILL_LEVEL_UNFAMILIAR category = SKILL_CATEGORY_OCCUPATIONAL subcategory = SKILL_SUBCATEGORY_MEDICAL diff --git a/code/datums/skills/occupational/science.dm b/code/datums/skills/occupational/science.dm index 42c9b1d644e..277a475dda4 100644 --- a/code/datums/skills/occupational/science.dm +++ b/code/datums/skills/occupational/science.dm @@ -1,23 +1,27 @@ /singleton/skill/research name = "Research" - desc = "it's generic research shit, using the protolathe, destructive analyzers, etc" + description = "it's generic research shit, using the protolathe, destructive analyzers, etc" + uneducated_skill_cap = SKILL_LEVEL_UNFAMILIAR category = SKILL_CATEGORY_OCCUPATIONAL subcategory = SKILL_SUBCATEGORY_SCIENCE /singleton/skill/robotics name = "Robotics" - desc = "fixing cyborgs and IPCs" + description = "fixing cyborgs and IPCs" + uneducated_skill_cap = SKILL_LEVEL_FAMILIAR category = SKILL_CATEGORY_OCCUPATIONAL subcategory = SKILL_SUBCATEGORY_SCIENCE /singleton/skill/xenobotany name = "Xenobotany" - desc = "gene editing plants" + description = "gene editing plants" + uneducated_skill_cap = SKILL_LEVEL_UNFAMILIAR category = SKILL_CATEGORY_OCCUPATIONAL subcategory = SKILL_SUBCATEGORY_SCIENCE /singleton/skill/archaeology name = "Archaeology" - desc = "finding archaeological stuff" + description = "finding archaeological stuff" + uneducated_skill_cap = SKILL_LEVEL_UNFAMILIAR category = SKILL_CATEGORY_OCCUPATIONAL subcategory = SKILL_SUBCATEGORY_SCIENCE diff --git a/code/modules/background/education/_education.dm b/code/modules/background/education/_education.dm index ba24115b347..b4fadedcf6e 100644 --- a/code/modules/background/education/_education.dm +++ b/code/modules/background/education/_education.dm @@ -9,3 +9,10 @@ var/list/jobs /// The given skills for this education type. Linked list of skill type to level. var/list/skills + /// Species that CANNOT take this education, if necessary. This is a list of names, must match what's in the species pref variable. + /// Empty list means no restrictions. + var/list/species_restriction + +/singleton/education/high_school + name = "High School Diploma" + description = "Your character has a high school diploma." diff --git a/code/modules/client/preference_setup/origin/origin.dm b/code/modules/client/preference_setup/origin/origin.dm index 82d0bd1415e..7efb857002a 100644 --- a/code/modules/client/preference_setup/origin/origin.dm +++ b/code/modules/client/preference_setup/origin/origin.dm @@ -75,27 +75,50 @@ var/datum/species/S = GLOB.all_species[pref.species] if(!istext(pref.culture) || !ispath(text2path(pref.culture), /singleton/origin_item/culture)) var/singleton/origin_item/culture/CI = S.possible_cultures[1] - pref.culture = "[CI]" + pref.culture = "[CI.type]" + var/singleton/origin_item/culture/our_culture = GET_SINGLETON(text2path(pref.culture)) if(!istext(pref.origin) || !ispath(text2path(pref.origin), /singleton/origin_item/origin)) var/singleton/origin_item/origin/OI = pick(our_culture.possible_origins) - pref.origin = "[OI]" + pref.origin = "[OI.type]" else var/singleton/origin_item/origin/origin_check = text2path(pref.origin) if(!(origin_check in our_culture.possible_origins)) to_client_chat(SPAN_WARNING("Your origin has been reset due to it being incompatible with your culture!")) var/singleton/origin_item/origin/OI = pick(our_culture.possible_origins) - pref.origin = "[OI]" + pref.origin = "[OI.type]" + + if(!istext(pref.education) || !ispath(text2path(pref.education), /singleton/education)) + var/singleton/education/ED = find_suitable_education() + if(ED) + pref.education = "[ED.type]" + else + var/singleton/education/our_education = GET_SINGLETON(text2path(pref.education)) + if(length(our_education.species_restriction)) + if(pref.species in our_education.species_restriction) + var/singleton/education/ED = find_suitable_education() + if(ED) + pref.education = "[ED.type]" + if(length(our_education.minimum_character_age)) + if(pref.species in our_education.minimum_character_age) + if(pref.age < our_education.minimum_character_age[pref.species]) + var/singleton/education/ED = find_suitable_education() + if(ED) + pref.education = "[ED.type]" + var/singleton/origin_item/origin/our_origin = GET_SINGLETON(text2path(pref.origin)) if(!(pref.citizenship in our_origin.possible_citizenships)) to_client_chat(SPAN_WARNING("Your previous citizenship is invalid for this origin! Resetting.")) pref.citizenship = our_origin.possible_citizenships[1] + if(!(pref.religion in our_origin.possible_religions)) to_client_chat(SPAN_WARNING("Your previous religion is invalid for this origin! Resetting.")) pref.religion = our_origin.possible_religions[1] + if(!(pref.accent in our_origin.possible_accents)) to_client_chat(SPAN_WARNING("Your previous accent is invalid for this origin! Resetting.")) pref.accent = our_origin.possible_accents[1] + pref.economic_status = sanitize_inlist(pref.economic_status, ECONOMIC_POSITIONS, initial(pref.economic_status)) /datum/category_item/player_setup_item/origin/content(var/mob/user) @@ -119,6 +142,8 @@ if(OR.important_information) dat += "
- [OR.important_information]" dat += "
" + var/singleton/education/ED = GET_SINGLETON(text2path(pref.education)) + dat += "Education: [ED.name]
" dat += "Economic Status: [pref.economic_status]
" dat += "Citizenship: [pref.citizenship]
" dat += "Religion: [pref.religion]
" @@ -136,7 +161,7 @@ var/result = tgui_input_list(user, "Choose your character's culture.", "Culture", options) var/singleton/origin_item/culture/chosen_culture = options[result] if(chosen_culture) - show_window(chosen_culture, "set_culture_data", user) + show_origin_window(chosen_culture, "set_culture_data", user) return TOPIC_HANDLED if(href_list["open_origin_menu"]) @@ -149,9 +174,28 @@ var/result = tgui_input_list(user, "Choose your character's origin.", "Origins", options) var/singleton/origin_item/origin/chosen_origin = options[result] if(chosen_origin) - show_window(chosen_origin, "set_origin_data", user) + show_origin_window(chosen_origin, "set_origin_data", user) return TOPIC_HANDLED + if(href_list["open_education_menu"]) + var/list/options = list() + var/singleton/education/our_education = GET_SINGLETON(text2path(pref.education)) + var/list/singleton/education/education_list = GET_SINGLETON_SUBTYPE_MAP(/singleton/education) + for(var/singleton_type in education_list) + var/singleton/education/ED = education_list[singleton_type] + if(length(ED.species_restriction)) + if(pref.species in ED.species_restriction) + continue + if(length(ED.minimum_character_age)) + if(pref.species in ED.minimum_character_age) + if(pref.age < ED.minimum_character_age[pref.species]) + continue + options[ED.name] = ED + var/result = tgui_input_list(user, "Choose your character's education.", "Education", options) + var/singleton/education/chosen_education = options[result] + if(chosen_education) + show_education_window(chosen_education, "set_education_data", user) + if(href_list["set_culture_data"]) user << browse(null, "window=set_culture_data") pref.culture = html_decode(href_list["set_culture_data"]) @@ -164,6 +208,12 @@ sanitize_character() return TOPIC_REFRESH + if(href_list["set_education_data"]) + user << browse(null, "window=set_education_data") + pref.education = html_decode(href_list["set_education_data"]) + sanitize_character() + return TOPIC_REFRESH + if(href_list["economic_status"]) var/new_status = tgui_input_list(user, "Choose how wealthy your character is. Note that this applies a multiplier to a value that is also affected by your species and job.", "Character Preference", ECONOMIC_POSITIONS, pref.economic_status) if(new_status && CanUseTopic(user)) @@ -212,7 +262,7 @@ sanitize_character() return TOPIC_REFRESH -/datum/category_item/player_setup_item/origin/proc/show_window(var/singleton/origin_item/OI, var/topic_data, var/mob/user) +/datum/category_item/player_setup_item/origin/proc/show_origin_window(var/singleton/origin_item/OI, var/topic_data, var/mob/user) var/datum/browser/origin_win = new(user, topic_data, "Origins Selection") var/dat = "
[OI.name]
" dat += "
[OI.desc]
" @@ -223,6 +273,15 @@ origin_win.set_content(dat) origin_win.open() +/datum/category_item/player_setup_item/origin/proc/show_education_window(var/singleton/education/ED, var/topic_data, var/mob/user) + var/datum/browser/education_win = new(user, topic_data, "Education Selection") + var/dat = "
[ED.name]
" + dat += "
[ED.description]
" + dat += "
\[Select\]
" + dat += "" + education_win.set_content(dat) + education_win.open() + /datum/category_item/player_setup_item/origin/proc/show_citizenship_menu(mob/user, selected_citizenship) var/datum/citizenship/citizenship = SSrecords.citizenships[selected_citizenship] if(citizenship) @@ -256,3 +315,17 @@ dat += "" acc_win.set_content(dat) acc_win.open() + +/// This proc finds and returns the first suitable education for the pref datum. +/datum/category_item/player_setup_item/origin/proc/find_suitable_education() + var/list/singleton/education/education_list = GET_SINGLETON_SUBTYPE_MAP(/singleton/education) + for(var/singleton_type in education_list) + var/singleton/education/ED = education_list[singleton_type] + if(length(ED.species_restriction)) + if(pref.species in ED.species_restriction) + continue + if(length(ED.minimum_character_age)) + if(pref.species in ED.minimum_character_age) + if(pref.age < ED.minimum_character_age[pref.species]) + continue + return ED diff --git a/code/modules/client/preference_setup/skills/skills.dm b/code/modules/client/preference_setup/skills/skills.dm index e4f3d58c2b3..51c2c62760f 100644 --- a/code/modules/client/preference_setup/skills/skills.dm +++ b/code/modules/client/preference_setup/skills/skills.dm @@ -3,11 +3,10 @@ sort_order = 1 /datum/category_item/player_setup_item/skills/load_character(var/savefile/S) - S["culture"] >> pref.education - //todomatt + S["skills"] >> pref.skills /datum/category_item/player_setup_item/skills/save_character(var/savefile/S) - S["culture"] << pref.skills + S["skills"] << pref.skills /datum/category_item/player_setup_item/skills/gather_load_query() return list( diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index c82a2250156..946eb440622 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -93,15 +93,24 @@ var/list/preferences_datums = list() var/machine_serial_number var/machine_ownership_status = IPC_OWNERSHIP_COMPANY - //Some faction information. - var/home_system = "Unset" //System of birth. - var/citizenship = "None" //Current home system. - var/faction = "None" //Antag faction/general associated faction. - var/religion = "None" //Religious association. - var/accent = "None" //Character accent. - + /// Character citizenship. + var/citizenship = "None" + /// Antag faction/general associated faction. + var/faction = "None" + /// Religious association. + var/religion = "None" + /// Character accent. + var/accent = "None" + + /// The character's culture singleton. var/culture + /// The character's origin singleton. var/origin + /// The character's education singleton. + var/education + + /// The character's skills list. + var/list/skills = list() var/list/psionics = list() @@ -638,7 +647,6 @@ var/list/preferences_datums = list() b_eyes = 0 species = SPECIES_HUMAN - home_system = "Unset" citizenship = "None" faction = "None" religion = "None" From 4e1f497b99d3424528db61e6aa143608b6c17fe7 Mon Sep 17 00:00:00 2001 From: Matt Atlas Date: Fri, 2 Aug 2024 17:41:12 +0200 Subject: [PATCH 04/16] the fuck was I doing again? --- code/controllers/subsystems/skills.dm | 18 ++++++++++++++++++ .../client/preference_setup/origin/origin.dm | 1 - .../client/preference_setup/skills/skills.dm | 13 ++++++++++++- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/code/controllers/subsystems/skills.dm b/code/controllers/subsystems/skills.dm index 1103982d5cc..401631f36a9 100644 --- a/code/controllers/subsystems/skills.dm +++ b/code/controllers/subsystems/skills.dm @@ -1,3 +1,21 @@ SUBSYSTEM_DEF(skills) name = "Skills" flags = SS_NO_FIRE + + /// This is essentially the list we use to read skills in the character setup. + var/list/skill_tree = list() + /// A map of all the skill levels to their definition. + var/list/skill_level_map = list( + "Unfamiliar" = "You don't know anything about this subject.", + "Familiar" = "You're familiar with this subject, either by reading into it or by doing some courses.", + "Trained" = "You've been formally trained in this subject. Typically, this is the minimum level for a job.", + "Professional" = "You have a lot of training and a good amount of experience in this subject." + ) + +/datum/controller/subsystem/skills/Initialize() + . = ..() + for(var/singleton/skill/skill in GET_SINGLETON_SUBTYPE_LIST(/singleton/skill)) + skill_tree[skill.category] = skill.subcategory + if(!islist(skill_tree[skill.category][skill.subcategory])) + skill_tree[skill.category][skill.subcategory] = list() + skill_tree[skill.category][skill.subcategory] |= skill diff --git a/code/modules/client/preference_setup/origin/origin.dm b/code/modules/client/preference_setup/origin/origin.dm index 7efb857002a..af97c392f83 100644 --- a/code/modules/client/preference_setup/origin/origin.dm +++ b/code/modules/client/preference_setup/origin/origin.dm @@ -179,7 +179,6 @@ if(href_list["open_education_menu"]) var/list/options = list() - var/singleton/education/our_education = GET_SINGLETON(text2path(pref.education)) var/list/singleton/education/education_list = GET_SINGLETON_SUBTYPE_MAP(/singleton/education) for(var/singleton_type in education_list) var/singleton/education/ED = education_list[singleton_type] diff --git a/code/modules/client/preference_setup/skills/skills.dm b/code/modules/client/preference_setup/skills/skills.dm index 51c2c62760f..1ee3f8aad7e 100644 --- a/code/modules/client/preference_setup/skills/skills.dm +++ b/code/modules/client/preference_setup/skills/skills.dm @@ -43,7 +43,18 @@ /datum/category_item/player_setup_item/skills/content(var/mob/user) var/list/dat = list() - dat += "skills n shit" + for(var/category in SSskills.skill_tree) + var/subcategory = SSskills.skill_tree[category] + for(var/singleton/skill/skill in SSskills.skill_tree[category][subcategory]) + dat += "[category]" + dat += "" + dat += "" + dat += "[skill.name] ([subcategory])" + //TODOMATT: add education cap + for(var/skill_level in SKILL_LEVEL_UNFAMILIAR to skill.maximum_level) + dat += "\[SSskills.skill_level_map[skill_level]\]" + dat += "" + dat += "" . = dat.Join() /datum/category_item/player_setup_item/skills/OnTopic(href, href_list, user) From 93a7a7e8f827d8656415eeac8ee7fa5e3a06964d Mon Sep 17 00:00:00 2001 From: Matt Atlas Date: Fri, 4 Oct 2024 17:53:52 +0200 Subject: [PATCH 05/16] kono sekai --- aurorastation.dme | 1 + code/controllers/subsystems/skills.dm | 23 +++++++++++++++---- code/datums/skills/_skill_categories.dm | 18 +++++++++++++++ code/datums/skills/combat/combat.dm | 6 ++--- code/datums/skills/everyday/service.dm | 6 ++--- .../datums/skills/occupational/engineering.dm | 8 +++---- code/datums/skills/occupational/medical.dm | 10 ++++---- code/datums/skills/occupational/science.dm | 8 +++---- .../client/preference_setup/skills/skills.dm | 19 ++++++++------- 9 files changed, 65 insertions(+), 34 deletions(-) create mode 100644 code/datums/skills/_skill_categories.dm diff --git a/aurorastation.dme b/aurorastation.dme index 49fad7a68eb..40d0a5bf483 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -537,6 +537,7 @@ #include "code\datums\repositories\singletons.dm" #include "code\datums\repositories\sound_channels.dm" #include "code\datums\repositories\unique.dm" +#include "code\datums\skills\_skill_categories.dm" #include "code\datums\skills\_skills.dm" #include "code\datums\skills\combat\combat.dm" #include "code\datums\skills\everyday\service.dm" diff --git a/code/controllers/subsystems/skills.dm b/code/controllers/subsystems/skills.dm index 401631f36a9..b15d4e9936e 100644 --- a/code/controllers/subsystems/skills.dm +++ b/code/controllers/subsystems/skills.dm @@ -13,9 +13,22 @@ SUBSYSTEM_DEF(skills) ) /datum/controller/subsystem/skills/Initialize() - . = ..() + // Initialize the skill category lists first. + // This creates linked lists as follows: "Science" -> empty list + for(var/singleton/skill_category/skill_category in GET_SINGLETON_SUBTYPE_LIST(/singleton/skill_category)) + skill_tree[skill_category] = list() + + // Now, initialize all the skills. + // What actually goes on here: we want a tree that we can traverse programmatically. + // To do that, we first of all make empty lists above with all the categories (they're singletons so we can easily iterate over them). + // Next, we add the empty subcategory lists if they're not present. At this point, the tree would look like "Combat" -> "Melee" -> empty list + // After that's done, if our skill is not present, add it to the empty list of the subcategory. for(var/singleton/skill/skill in GET_SINGLETON_SUBTYPE_LIST(/singleton/skill)) - skill_tree[skill.category] = skill.subcategory - if(!islist(skill_tree[skill.category][skill.subcategory])) - skill_tree[skill.category][skill.subcategory] = list() - skill_tree[skill.category][skill.subcategory] |= skill + var/singleton/skill_category/skill_category = GET_SINGLETON(skill.category) + if(!(skill.subcategory in skill_tree[skill_category])) + skill_tree[skill_category] |= skill.subcategory + skill_tree[skill_category][skill.subcategory] = list() + + if(!(skill in skill_tree[skill_category][skill.subcategory])) + skill_tree[skill_category][skill.subcategory] |= skill + return SS_INIT_SUCCESS diff --git a/code/datums/skills/_skill_categories.dm b/code/datums/skills/_skill_categories.dm new file mode 100644 index 00000000000..a2e7b4da93b --- /dev/null +++ b/code/datums/skills/_skill_categories.dm @@ -0,0 +1,18 @@ +/singleton/skill_category + /// The name of the skill category. + var/name + /// The description and purpose of the skill category, displayed in the info tab. + var/desc + +/singleton/skill_category/everyday + name = SKILL_CATEGORY_EVERYDAY + desc = "An everyday skill is a skill that can be picked up normally. Think like mixing a drink, growing a plant, cooking, and so on." + +/singleton/skill_category/occupational + name = SKILL_CATEGORY_OCCUPATIONAL + desc = "Occupational skills are the skills necessary for you to do your job. They typically lock certain aspects of your department if you aren't proficient enough." + +/singleton/skill_category/combat + name = SKILL_CATEGORY_COMBAT + desc = "A combat skill is a skill that has a direct effect in combat. These have an increased cost." + diff --git a/code/datums/skills/combat/combat.dm b/code/datums/skills/combat/combat.dm index 5b828cee076..c552c793877 100644 --- a/code/datums/skills/combat/combat.dm +++ b/code/datums/skills/combat/combat.dm @@ -1,17 +1,17 @@ /singleton/skill/unarmed_combat name = "Unarmed Combat" description = "punching things" - category = SKILL_CATEGORY_COMBAT + category = /singleton/skill_category/combat subcategory = SKILL_SUBCATEGORY_MELEE /singleton/skill/armed_combat name = "Armed Combat" description = "zomboid time" - category = SKILL_CATEGORY_COMBAT + category = /singleton/skill_category/combat subcategory = SKILL_SUBCATEGORY_MELEE /singleton/skill/firearms name = "Firearms" description = "using guns. split this into close arms/longarms/special arms?" - category = SKILL_CATEGORY_COMBAT + category = /singleton/skill_category/combat subcategory = SKILL_SUBCATEGORY_RANGED diff --git a/code/datums/skills/everyday/service.dm b/code/datums/skills/everyday/service.dm index 4b3a49bcbb3..e1d7ab75fa3 100644 --- a/code/datums/skills/everyday/service.dm +++ b/code/datums/skills/everyday/service.dm @@ -1,17 +1,17 @@ /singleton/skill/mixing name = "Mixing" description = "valhalla skill" - category = SKILL_CATEGORY_OCCUPATIONAL + category = /singleton/skill_category/everyday subcategory = SKILL_SUBCATEGORY_SERVICE /singleton/skill/cooking name = "Cooking" description = "Cooking Mama" - category = SKILL_CATEGORY_OCCUPATIONAL + category = /singleton/skill_category/everyday subcategory = SKILL_SUBCATEGORY_SERVICE /singleton/skill/gardening name = "Gardening" description = "this is boring as shit" - category = SKILL_CATEGORY_OCCUPATIONAL + category = /singleton/skill_category/everyday subcategory = SKILL_SUBCATEGORY_SERVICE diff --git a/code/datums/skills/occupational/engineering.dm b/code/datums/skills/occupational/engineering.dm index bd7d41f966c..e8005c49972 100644 --- a/code/datums/skills/occupational/engineering.dm +++ b/code/datums/skills/occupational/engineering.dm @@ -2,26 +2,26 @@ name = "Electrical Engineering" description = "wiring, anything power related" uneducated_skill_cap = SKILL_LEVEL_FAMILIAR - category = SKILL_CATEGORY_OCCUPATIONAL + category = /singleton/skill_category/occupational subcategory = SKILL_SUBCATEGORY_ENGINEERING /singleton/skill/mechanical_engineering name = "Mechanical Engineering" description = "building things" uneducated_skill_cap = SKILL_LEVEL_FAMILIAR - category = SKILL_CATEGORY_OCCUPATIONAL + category = /singleton/skill_category/occupational subcategory = SKILL_SUBCATEGORY_ENGINEERING /singleton/skill/atmospherics_systems name = "Atmospherics Systems" description = "atmospherics things" uneducated_skill_cap = SKILL_LEVEL_UNFAMILIAR - category = SKILL_CATEGORY_OCCUPATIONAL + category = /singleton/skill_category/occupational subcategory = SKILL_SUBCATEGORY_ENGINEERING /singleton/skill/reactor_systems name = "Reactor Systems" description = "reactor equipment" uneducated_skill_cap = SKILL_LEVEL_UNFAMILIAR - category = SKILL_CATEGORY_OCCUPATIONAL + category = /singleton/skill_category/occupational subcategory = SKILL_SUBCATEGORY_ENGINEERING diff --git a/code/datums/skills/occupational/medical.dm b/code/datums/skills/occupational/medical.dm index 028b8e06028..9657b5e376f 100644 --- a/code/datums/skills/occupational/medical.dm +++ b/code/datums/skills/occupational/medical.dm @@ -3,7 +3,7 @@ description ="how to use health analyzers, ATKs, syringes" uneducated_skill_cap = SKILL_LEVEL_FAMILIAR maximum_level = SKILL_LEVEL_PROFESSIONAL - category = SKILL_CATEGORY_OCCUPATIONAL + category = /singleton/skill_category/occupational subcategory = SKILL_SUBCATEGORY_MEDICAL /singleton/skill/surgery @@ -11,26 +11,26 @@ description = "the one everyone wants to do in medical to be the protag" uneducated_skill_cap = SKILL_LEVEL_UNFAMILIAR maximum_level = SKILL_LEVEL_PROFESSIONAL - category = SKILL_CATEGORY_OCCUPATIONAL + category = /singleton/skill_category/occupational subcategory = SKILL_SUBCATEGORY_MEDICAL /singleton/skill/pharmacology name = "Pharmacology" description = "why are you playing pharma LOL" uneducated_skill_cap = SKILL_LEVEL_UNFAMILIAR - category = SKILL_CATEGORY_OCCUPATIONAL + category = /singleton/skill_category/occupational subcategory = SKILL_SUBCATEGORY_MEDICAL /singleton/skill/anatomy name = "Anatomy" description = "this one lets you know what's wrong with people" uneducated_skill_cap = SKILL_LEVEL_FAMILIAR - category = SKILL_CATEGORY_OCCUPATIONAL + category = /singleton/skill_category/occupational subcategory = SKILL_SUBCATEGORY_MEDICAL /singleton/skill/forensics name = "Forensics" description = "forensics shit i guess" uneducated_skill_cap = SKILL_LEVEL_UNFAMILIAR - category = SKILL_CATEGORY_OCCUPATIONAL + category = /singleton/skill_category/occupational subcategory = SKILL_SUBCATEGORY_MEDICAL diff --git a/code/datums/skills/occupational/science.dm b/code/datums/skills/occupational/science.dm index 277a475dda4..a426c949844 100644 --- a/code/datums/skills/occupational/science.dm +++ b/code/datums/skills/occupational/science.dm @@ -2,26 +2,26 @@ name = "Research" description = "it's generic research shit, using the protolathe, destructive analyzers, etc" uneducated_skill_cap = SKILL_LEVEL_UNFAMILIAR - category = SKILL_CATEGORY_OCCUPATIONAL + category = /singleton/skill_category/occupational subcategory = SKILL_SUBCATEGORY_SCIENCE /singleton/skill/robotics name = "Robotics" description = "fixing cyborgs and IPCs" uneducated_skill_cap = SKILL_LEVEL_FAMILIAR - category = SKILL_CATEGORY_OCCUPATIONAL + category = /singleton/skill_category/occupational subcategory = SKILL_SUBCATEGORY_SCIENCE /singleton/skill/xenobotany name = "Xenobotany" description = "gene editing plants" uneducated_skill_cap = SKILL_LEVEL_UNFAMILIAR - category = SKILL_CATEGORY_OCCUPATIONAL + category = /singleton/skill_category/occupational subcategory = SKILL_SUBCATEGORY_SCIENCE /singleton/skill/archaeology name = "Archaeology" description = "finding archaeological stuff" uneducated_skill_cap = SKILL_LEVEL_UNFAMILIAR - category = SKILL_CATEGORY_OCCUPATIONAL + category = /singleton/skill_category/occupational subcategory = SKILL_SUBCATEGORY_SCIENCE diff --git a/code/modules/client/preference_setup/skills/skills.dm b/code/modules/client/preference_setup/skills/skills.dm index 1ee3f8aad7e..8fcd9befae1 100644 --- a/code/modules/client/preference_setup/skills/skills.dm +++ b/code/modules/client/preference_setup/skills/skills.dm @@ -44,17 +44,16 @@ /datum/category_item/player_setup_item/skills/content(var/mob/user) var/list/dat = list() for(var/category in SSskills.skill_tree) - var/subcategory = SSskills.skill_tree[category] - for(var/singleton/skill/skill in SSskills.skill_tree[category][subcategory]) - dat += "[category]" - dat += "" + var/singleton/skill_category/skill_category = category + dat += "
[skill_category.name]" + for(var/subcategory in SSskills.skill_tree[skill_category]) + dat += "[subcategory]" dat += "" - dat += "" - //TODOMATT: add education cap - for(var/skill_level in SKILL_LEVEL_UNFAMILIAR to skill.maximum_level) - dat += "" - dat += "" - dat += "
[skill.name] ([subcategory])\[SSskills.skill_level_map[skill_level]\]
" + for(var/singleton/skill/skill in SSskills.skill_tree[skill_category][subcategory]) + dat += "[skill.name]" + for(var/skill_level in SKILL_LEVEL_UNFAMILIAR to skill.maximum_level) + dat += "[SSskills.skill_level_map[skill_level]]" + dat += "" . = dat.Join() /datum/category_item/player_setup_item/skills/OnTopic(href, href_list, user) From f99078b90e1466d271d76934727f378c51f43d70 Mon Sep 17 00:00:00 2001 From: Matt Atlas Date: Sun, 6 Oct 2024 17:43:36 +0200 Subject: [PATCH 06/16] sddsds --- .../modules/client/preference_setup/skills/skills.dm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/code/modules/client/preference_setup/skills/skills.dm b/code/modules/client/preference_setup/skills/skills.dm index 8fcd9befae1..57de9df4c1d 100644 --- a/code/modules/client/preference_setup/skills/skills.dm +++ b/code/modules/client/preference_setup/skills/skills.dm @@ -45,15 +45,15 @@ var/list/dat = list() for(var/category in SSskills.skill_tree) var/singleton/skill_category/skill_category = category - dat += "
[skill_category.name]" + dat += "[skill_category.name]
" for(var/subcategory in SSskills.skill_tree[skill_category]) - dat += "[subcategory]" - dat += "" + dat += "[subcategory]
" for(var/singleton/skill/skill in SSskills.skill_tree[skill_category][subcategory]) - dat += "" + dat += "[skill.name]" for(var/skill_level in SKILL_LEVEL_UNFAMILIAR to skill.maximum_level) - dat += "" - dat += "
[skill.name]
[SSskills.skill_level_map[skill_level]]
" + dat += "[SSskills.skill_level_map[skill_level]]" + dat += "" + dat += "
" . = dat.Join() /datum/category_item/player_setup_item/skills/OnTopic(href, href_list, user) From 0f4e5bd9e7495339e9372300f668388c567c5a5f Mon Sep 17 00:00:00 2001 From: Mattia Date: Mon, 7 Oct 2024 15:21:21 +0200 Subject: [PATCH 07/16] makes the ui work (the easy part) --- code/modules/client/preference_setup/skills/skills.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/modules/client/preference_setup/skills/skills.dm b/code/modules/client/preference_setup/skills/skills.dm index 57de9df4c1d..40d0ce38dbe 100644 --- a/code/modules/client/preference_setup/skills/skills.dm +++ b/code/modules/client/preference_setup/skills/skills.dm @@ -47,12 +47,12 @@ var/singleton/skill_category/skill_category = category dat += "[skill_category.name]
" for(var/subcategory in SSskills.skill_tree[skill_category]) - dat += "[subcategory]" + dat += "[subcategory]
" for(var/singleton/skill/skill in SSskills.skill_tree[skill_category][subcategory]) - dat += "[skill.name]" + dat += "[skill.name]: " for(var/skill_level in SKILL_LEVEL_UNFAMILIAR to skill.maximum_level) dat += "[SSskills.skill_level_map[skill_level]]" - dat += "" + dat += "
" dat += "

" . = dat.Join() From 989ad9267768dca9cadbd9754fe8051e17a050b3 Mon Sep 17 00:00:00 2001 From: Mattia Date: Mon, 7 Oct 2024 16:34:24 +0200 Subject: [PATCH 08/16] all the places I've been, all the blood I've bled... --- .../client/preference_setup/skills/skills.dm | 36 +++++++++++++++++-- code/modules/client/preferences.dm | 3 +- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/code/modules/client/preference_setup/skills/skills.dm b/code/modules/client/preference_setup/skills/skills.dm index 40d0ce38dbe..49abe4173e1 100644 --- a/code/modules/client/preference_setup/skills/skills.dm +++ b/code/modules/client/preference_setup/skills/skills.dm @@ -37,6 +37,16 @@ "ckey" = PREF_CLIENT_CKEY ) +/datum/category_item/player_setup_item/skills/load_character_special(savefile/S) + if(!pref.skills) + pref.skills = "{}" + + var/before = pref.skills + try + pref.skills = json_decode(pref.skills) + catch (var/exception/e) + log_debug("SKILLS: Caught [e]. Initial value: [before]") + pref.skills = list() /datum/category_item/player_setup_item/skills/sanitize_character(var/sql_load = 0) //todomatt @@ -49,13 +59,33 @@ for(var/subcategory in SSskills.skill_tree[skill_category]) dat += "[subcategory]
" for(var/singleton/skill/skill in SSskills.skill_tree[skill_category][subcategory]) - dat += "[skill.name]: " + dat += "[skill.name]: " for(var/skill_level in SKILL_LEVEL_UNFAMILIAR to skill.maximum_level) - dat += "[SSskills.skill_level_map[skill_level]]" + dat += "[SSskills.skill_level_map[skill_level]]" dat += "
" dat += "

" . = dat.Join() /datum/category_item/player_setup_item/skills/OnTopic(href, href_list, user) - //todomatt + if(href_list["skillinfo"]) + var/singleton/skill/skill_to_show = GET_SINGLETON(text2path(href_list["skillinfo"])) + if(!skill_to_show) + log_debug("SKILLS: Invalid skill selected for [user]: [skill_to_show]") + return + var/datum/browser/skill_window = new(user, "skill_info", "Skill Information") + var/dat = "
[skill_to_show.name]
" + dat += "
[skill_to_show.description]
" + if(skill_to_show.uneducated_skill_cap) + dat += "Without the relevant education, you may only reach the [SSskills.skill_level_map[skill_to_show.uneducated_skill_cap]] level.
" + dat += "" + skill_window.set_content(dat) + skill_window.open() + else if(href_list["setskill"]) + var/singleton/skill/new_skill = GET_SINGLETON(text2path(href_list["setskill"])) + if(!new_skill) + log_debug("SKILLS: Invalid skill selected for [user]: [new_skill]") + return + // check if you can actually pick it... + pref.skills[new_skill.type] = text2num(href_list["newvalue"]) + return ..() diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 7bf9925ac49..fb19c80512e 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -109,9 +109,10 @@ var/list/preferences_datums = list() /// The character's education singleton. var/education - /// The character's skills list. + /// The character's skills list. JSON. var/list/skills = list() + /// The character's psionics. JSON. var/list/psionics = list() var/list/char_render_holders //Should only be a key-value list of north/south/east/west = obj/screen. From 0b9fbe5bd1db210750af892cfe13f6754daff098 Mon Sep 17 00:00:00 2001 From: Mattia Date: Fri, 11 Oct 2024 16:28:48 +0200 Subject: [PATCH 09/16] cold and isolated, sold out and violated --- code/datums/skills/_skills.dm | 15 ++++++++++ .../datums/skills/occupational/engineering.dm | 12 +++++--- code/datums/skills/occupational/science.dm | 17 ++++++++--- .../client/preference_setup/origin/origin.dm | 8 ++++- .../client/preference_setup/skills/skills.dm | 29 ++++++++++++++----- 5 files changed, 65 insertions(+), 16 deletions(-) diff --git a/code/datums/skills/_skills.dm b/code/datums/skills/_skills.dm index d0d67306f49..bef46c7a6ac 100644 --- a/code/datums/skills/_skills.dm +++ b/code/datums/skills/_skills.dm @@ -12,3 +12,18 @@ var/category /// The sub-category of this skill. Used to better sort skills. var/subcategory + +/singleton/skill/proc/get_maximum_level(var/singleton/education/education) + if(!istype(education)) + crash_with("SKILL: Invalid [education] fed to get_maximum_level!") + + // If there is no uneducated skill cap, it means we can always pick the maximum level. + if(!uneducated_skill_cap) + return maximum_level + + // Otherwise, we need to check the education... + if(type in education.skills) + return education.skills[type] + + + return uneducated_skill_cap diff --git a/code/datums/skills/occupational/engineering.dm b/code/datums/skills/occupational/engineering.dm index e8005c49972..94e0986ceda 100644 --- a/code/datums/skills/occupational/engineering.dm +++ b/code/datums/skills/occupational/engineering.dm @@ -1,27 +1,31 @@ /singleton/skill/electrical_engineering name = "Electrical Engineering" - description = "wiring, anything power related" + description = "Electrical engineering has to do with anything that involves wires and electricity. This includes things such as hacking doors, machines, but also \ + laying down wires, or repairing wiring damage in prosthetics." uneducated_skill_cap = SKILL_LEVEL_FAMILIAR category = /singleton/skill_category/occupational subcategory = SKILL_SUBCATEGORY_ENGINEERING /singleton/skill/mechanical_engineering name = "Mechanical Engineering" - description = "building things" + description = "Mechanical engineering has to do with general construction of objects, walls, windows, and so on. It is also necessary for the usage of heavy machinery \ + such as emitters." uneducated_skill_cap = SKILL_LEVEL_FAMILIAR category = /singleton/skill_category/occupational subcategory = SKILL_SUBCATEGORY_ENGINEERING /singleton/skill/atmospherics_systems name = "Atmospherics Systems" - description = "atmospherics things" + description = "Atmospherics systems involves the usage of atmospherics tooling and machinery, such as powered pumps, certain settings on air alarms, pipe wrenches, \ + pipe layers, and pipe construction." uneducated_skill_cap = SKILL_LEVEL_UNFAMILIAR category = /singleton/skill_category/occupational subcategory = SKILL_SUBCATEGORY_ENGINEERING /singleton/skill/reactor_systems name = "Reactor Systems" - description = "reactor equipment" + description = "Reactor systems envelops anything used for reactors, such as the computers and gyrotrons for the INDRA. It is also necessary to correctly interpret information \ + from reactor monitoring programs." uneducated_skill_cap = SKILL_LEVEL_UNFAMILIAR category = /singleton/skill_category/occupational subcategory = SKILL_SUBCATEGORY_ENGINEERING diff --git a/code/datums/skills/occupational/science.dm b/code/datums/skills/occupational/science.dm index a426c949844..c7eb824d7a3 100644 --- a/code/datums/skills/occupational/science.dm +++ b/code/datums/skills/occupational/science.dm @@ -7,21 +7,30 @@ /singleton/skill/robotics name = "Robotics" - description = "fixing cyborgs and IPCs" + description = "Robotics is well you know what the fuck it is man" uneducated_skill_cap = SKILL_LEVEL_FAMILIAR category = /singleton/skill_category/occupational subcategory = SKILL_SUBCATEGORY_SCIENCE /singleton/skill/xenobotany name = "Xenobotany" - description = "gene editing plants" + description = "Xenobotany is the creation and study of new or alien genomes of plants. It is necessary to be able to properly splice and process them." uneducated_skill_cap = SKILL_LEVEL_UNFAMILIAR category = /singleton/skill_category/occupational subcategory = SKILL_SUBCATEGORY_SCIENCE /singleton/skill/archaeology - name = "Archaeology" - description = "finding archaeological stuff" + name = "Xenoarchaeology" + description = "Xenoarchaeology is the study of alien civilizations, artifacts, architecture, and so on. It is necessary for the unearthing and cataloguing of \ + alien artifacts." + uneducated_skill_cap = SKILL_LEVEL_UNFAMILIAR + category = /singleton/skill_category/occupational + subcategory = SKILL_SUBCATEGORY_SCIENCE + +/singleton/skill/xenobiology + name = "Xenobiology" + description = "Xenobiology is the study of the research and cataloguing of alien lifeforms. It is necessary not only for the proper detailing of \ + alien creatures, but also for their processing, such as with slimes." uneducated_skill_cap = SKILL_LEVEL_UNFAMILIAR category = /singleton/skill_category/occupational subcategory = SKILL_SUBCATEGORY_SCIENCE diff --git a/code/modules/client/preference_setup/origin/origin.dm b/code/modules/client/preference_setup/origin/origin.dm index 35ae6362d23..65947b1fc8a 100644 --- a/code/modules/client/preference_setup/origin/origin.dm +++ b/code/modules/client/preference_setup/origin/origin.dm @@ -276,7 +276,13 @@ /datum/category_item/player_setup_item/origin/proc/show_education_window(var/singleton/education/ED, var/topic_data, var/mob/user) var/datum/browser/education_win = new(user, topic_data, "Education Selection") var/dat = "
[ED.name]
" - dat += "
[ED.description]
" + dat += "
[ED.description]
" + dat += "This education gives you the following skills:" + var/list/skills_to_show = list() + for(var/skill in ED.skills) + var/singleton/skill/S = GET_SINGLETON(skill) + skills_to_show += S.name + dat += "[english_list(skills_to_show)]
" dat += "
\[Select\]
" dat += "" education_win.set_content(dat) diff --git a/code/modules/client/preference_setup/skills/skills.dm b/code/modules/client/preference_setup/skills/skills.dm index 49abe4173e1..29d7cc43fe7 100644 --- a/code/modules/client/preference_setup/skills/skills.dm +++ b/code/modules/client/preference_setup/skills/skills.dm @@ -32,7 +32,7 @@ /datum/category_item/player_setup_item/skills/gather_save_parameters() return list( - "skills" = pref.culture, + "skills" = pref.skills, "id" = pref.current_character, "ckey" = PREF_CLIENT_CKEY ) @@ -53,16 +53,25 @@ /datum/category_item/player_setup_item/skills/content(var/mob/user) var/list/dat = list() + var/singleton/education/education = GET_SINGLETON(text2path(pref.education)) for(var/category in SSskills.skill_tree) var/singleton/skill_category/skill_category = category dat += "[skill_category.name]
" for(var/subcategory in SSskills.skill_tree[skill_category]) dat += "[subcategory]
" for(var/singleton/skill/skill in SSskills.skill_tree[skill_category][subcategory]) - dat += "[skill.name]: " - for(var/skill_level in SKILL_LEVEL_UNFAMILIAR to skill.maximum_level) - dat += "[SSskills.skill_level_map[skill_level]]" - dat += "
" + dat += "[skill.name]: " + var/current_skill_level = 0 + if(skill.type in pref.skills) + current_skill_level = pref.skills[skill.type] + for(var/skill_level in SKILL_LEVEL_UNFAMILIAR to skill.get_maximum_level(education)) + if(current_skill_level == skill_level) + dat += "\[[SSskills.skill_level_map[skill_level]]\]" + if(current_skill_level > skill_level) + dat += "[SSskills.skill_level_map[skill_level]]" + if(current_skill_level < skill_level) + dat += "[SSskills.skill_level_map[skill_level]]" + dat += "

" dat += "

" . = dat.Join() @@ -80,12 +89,18 @@ dat += "" skill_window.set_content(dat) skill_window.open() + else if(href_list["setskill"]) var/singleton/skill/new_skill = GET_SINGLETON(text2path(href_list["setskill"])) if(!new_skill) log_debug("SKILLS: Invalid skill selected for [user]: [new_skill]") return - // check if you can actually pick it... - pref.skills[new_skill.type] = text2num(href_list["newvalue"]) + + var/new_skill_value = text2num(href_list["newvalue"]) + if(new_skill_value == SKILL_LEVEL_UNFAMILIAR) + pref.skills -= new_skill.type + else + pref.skills[new_skill.type] = text2num(new_skill_value) + return TOPIC_REFRESH return ..() From 4828e78b172ceeb47836b590dd6c374df2c1edce Mon Sep 17 00:00:00 2001 From: Matt Atlas Date: Sun, 10 Nov 2024 22:14:53 +0100 Subject: [PATCH 10/16] Divine decree --- aurorastation.dme | 6 ++ .../background/education/engineering.dm | 86 +++++++++++++++++++ code/modules/background/education/medical.dm | 63 +++++++++++++- code/modules/background/education/misc.dm | 19 ++++ code/modules/background/education/science.dm | 81 +++++++++++++++++ code/modules/background/education/security.dm | 15 ++++ code/modules/background/education/service.dm | 67 +++++++++++++++ .../client/preference_setup/origin/origin.dm | 19 +++- .../client/preference_setup/skills/skills.dm | 80 +++++++++++++---- code/modules/client/preferences.dm | 3 +- code/modules/mob/mob.dm | 2 + code/modules/mob/mob_defines.dm | 2 + code/modules/mob/skills/skills.dm | 57 ++++++++++++ code/modules/power/singularity/emitter.dm | 3 + 14 files changed, 479 insertions(+), 24 deletions(-) create mode 100644 code/modules/background/education/engineering.dm create mode 100644 code/modules/background/education/misc.dm create mode 100644 code/modules/background/education/science.dm create mode 100644 code/modules/background/education/security.dm create mode 100644 code/modules/background/education/service.dm create mode 100644 code/modules/mob/skills/skills.dm diff --git a/aurorastation.dme b/aurorastation.dme index 83d7132b8be..8614dd5c5b5 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -1709,7 +1709,12 @@ #include "code\modules\background\citizenship\unathi.dm" #include "code\modules\background\citizenship\vaurca.dm" #include "code\modules\background\education\_education.dm" +#include "code\modules\background\education\engineering.dm" #include "code\modules\background\education\medical.dm" +#include "code\modules\background\education\misc.dm" +#include "code\modules\background\education\science.dm" +#include "code\modules\background\education\security.dm" +#include "code\modules\background\education\service.dm" #include "code\modules\background\origins\_origins.dm" #include "code\modules\background\origins\origins\diona\biesel.dm" #include "code\modules\background\origins\origins\diona\coalition.dm" @@ -2842,6 +2847,7 @@ #include "code\modules\mob\living\simple_animal\hostile\retaliate\retaliate.dm" #include "code\modules\mob\living\simple_animal\hostile\toy\mech.dm" #include "code\modules\mob\living\simple_animal\mechanical\mechanical.dm" +#include "code\modules\mob\skills\skills.dm" #include "code\modules\modular_computers\_description.dm" #include "code\modules\modular_computers\laptop_vendor.dm" #include "code\modules\modular_computers\computers\modular_computer\core.dm" diff --git a/code/modules/background/education/engineering.dm b/code/modules/background/education/engineering.dm new file mode 100644 index 00000000000..508d6355020 --- /dev/null +++ b/code/modules/background/education/engineering.dm @@ -0,0 +1,86 @@ +/singleton/education/mechanical_engineering_degree + name = "Mechanical Engineering Degree" + description = "You are at least 25 years of age, with a Bachelor's degree in Mechanical Engineering. You specialize in constructing structural systems, lathing, \ + and the more manual pleasures of engineering, such as welding and wrenching." + jobs = list("Engineer") + minimum_character_age = list( + SPECIES_HUMAN = 25, + SPECIES_SKRELL = 60, + SPECIES_SKRELL_AXIORI = 60 + ) + skills = list( + /singleton/skill/mechanical_engineering = SKILL_LEVEL_PROFESSIONAL, + /singleton/skill/electrical_engineering = SKILL_LEVEL_TRAINED, + /singleton/skill/atmospherics_systems = SKILL_LEVEL_TRAINED, + /singleton/skill/reactor_systems = SKILL_LEVEL_TRAINED + ) + +/singleton/education/electrical_engineering + name = "Electrical Engineering Degree" + description = "You are at least 25 years of age, with a Bachelor's degree in Electrical Engineering. You specialize in cutting wires, electronic circuits, and other \ + electrical systems." + jobs = list("Engineer") + minimum_character_age = list( + SPECIES_HUMAN = 25, + SPECIES_SKRELL = 60, + SPECIES_SKRELL_AXIORI = 60 + ) + skills = list( + /singleton/skill/mechanical_engineering = SKILL_LEVEL_TRAINED, + /singleton/skill/electrical_engineering = SKILL_LEVEL_PROFESSIONAL, + /singleton/skill/atmospherics_systems = SKILL_LEVEL_TRAINED, + /singleton/skill/reactor_systems = SKILL_LEVEL_TRAINED + ) + +/singleton/education/atmospherics_engineer + name = "Atmospherics Systems Degree" + description = "You are at least 25 years of age, with a Bachelor's degree in Atmospherics Systems. You specialize in everything to do with atmospherics systems, \ + whether that's the delivery of gases, usage of atmospherics machines, or simply how to use a pipe wrench." + jobs = list("Atmospherics Technician") + minimum_character_age = list( + SPECIES_HUMAN = 25, + SPECIES_SKRELL = 60, + SPECIES_SKRELL_AXIORI = 60 + ) + skills = list( + /singleton/skill/mechanical_engineering = SKILL_LEVEL_TRAINED, + /singleton/skill/electrical_engineering = SKILL_LEVEL_TRAINED, + /singleton/skill/atmospherics_systems = SKILL_LEVEL_PROFESSIONAL, + /singleton/skill/reactor_systems = SKILL_LEVEL_TRAINED + ) + + +/singleton/education/reactors_engineer + name = "Reactor Systems Degree" + description = "You are at least 25 years of age, with a Bachelor's degree in Reactor Systems. You specialize in everything to do with reactors systems, \ + whether you are looking at a Supermatter, an INDRA reactor, or a combustion chamber." + jobs = list("Engineer") + minimum_character_age = list( + SPECIES_HUMAN = 25, + SPECIES_SKRELL = 60, + SPECIES_SKRELL_AXIORI = 60 + ) + skills = list( + /singleton/skill/mechanical_engineering = SKILL_LEVEL_TRAINED, + /singleton/skill/electrical_engineering = SKILL_LEVEL_TRAINED, + /singleton/skill/atmospherics_systems = SKILL_LEVEL_TRAINED, + /singleton/skill/reactor_systems = SKILL_LEVEL_PROFESSIONAL + ) + +/singleton/education/experienced_engineer + name = "Engineering Certification" + description = "You are at least 25 years of age. You may not have an Engineering degree, but you had enough experience for the Conglomerate to validate it instead \ + of a degree. You do not have the same specialization as your fellow Engineers with a degree, making up for it by being a jack of all trades. \ + You could probably fix a car, whereas they might not be able to." + jobs = list("Engineer") + minimum_character_age = list( + SPECIES_HUMAN = 25, + SPECIES_SKRELL = 60, + SPECIES_SKRELL_AXIORI = 60 + ) + skills = list( + /singleton/skill/mechanical_engineering = SKILL_LEVEL_TRAINED, + /singleton/skill/electrical_engineering = SKILL_LEVEL_TRAINED, + /singleton/skill/atmospherics_systems = SKILL_LEVEL_TRAINED, + /singleton/skill/reactor_systems = SKILL_LEVEL_TRAINED + ) diff --git a/code/modules/background/education/medical.dm b/code/modules/background/education/medical.dm index fbd4ea4c480..58db4c6991d 100644 --- a/code/modules/background/education/medical.dm +++ b/code/modules/background/education/medical.dm @@ -1,6 +1,6 @@ /singleton/education/surgical_degree - name = "Surgery MD" - description = "You are 30 years of age or older, with applicable MD from accredited school and a completed 2 years of Residency at an \ + name = "MD, Surgery Track" + description = "You are 30 years of age or older, with an applicable MD from accredited school and you have completed 2 years of residency at an \ accredited hospital or clinic." jobs = list("Surgeon") minimum_character_age = list( @@ -14,3 +14,62 @@ /singleton/skill/anatomy = SKILL_LEVEL_TRAINED ) +/singleton/education/physician_degree + name = "MD, Physician Track" + description = "You are at least 30 years of age, with an applicable MD from an accredited school and you have completed 2 years of residency at an \ + accredited hospital or clinic." + jobs = list("Physician") + minimum_character_age = list( + SPECIES_HUMAN = 30, + SPECIES_SKRELL = 60, + SPECIES_SKRELL_AXIORI = 60 + ) + skills = list( + /singleton/skill/surgery = SKILL_LEVEL_TRAINED, + /singleton/skill/medicine = SKILL_LEVEL_PROFESSIONAL, + /singleton/skill/anatomy = SKILL_LEVEL_TRAINED + ) + +/singleton/education/pharmacist_degree + name = "Doctor of Pharmacy" + description = "You are at least 25 years of age, with an applicable Masters from an accredited school, along with 2 years of residency at an \ + accredited hospital or clinic." + jobs = list("Pharmacist") + minimum_character_age = list( + SPECIES_HUMAN = 30, + SPECIES_SKRELL = 60, + SPECIES_SKRELL_AXIORI = 60 + ) + skills = list( + /singleton/skill/medicine = SKILL_LEVEL_TRAINED, + /singleton/skill/anatomy = SKILL_LEVEL_TRAINED + ) + +/singleton/education/psychologist_degree + name = "Psychology PhD" + description = "You are at least 30 years of age, with a PhD from an accredited university in an applicable field." + jobs = list("Psychologist") + minimum_character_age = list( + SPECIES_HUMAN = 25, + SPECIES_SKRELL = 60, + SPECIES_SKRELL_AXIORI = 60 + ) + skills = list( + /singleton/skill/pharmacology = SKILL_LEVEL_PROFESSIONAL, + /singleton/skill/medicine = SKILL_LEVEL_TRAINED, + /singleton/skill/anatomy = SKILL_LEVEL_TRAINED + ) + +/singleton/education/paramedic + name = "Paramedic Certification" + description = "You are at least 18 years of age, with a Paramedic certification." + jobs = list("Paramedic") + minimum_character_age = list( + SPECIES_HUMAN = 18, + SPECIES_SKRELL = 55, + SPECIES_SKRELL_AXIORI = 55 + ) + skills = list( + /singleton/skill/medicine = SKILL_LEVEL_TRAINED, + /singleton/skill/anatomy = SKILL_LEVEL_TRAINED + ) diff --git a/code/modules/background/education/misc.dm b/code/modules/background/education/misc.dm new file mode 100644 index 00000000000..d2986659294 --- /dev/null +++ b/code/modules/background/education/misc.dm @@ -0,0 +1,19 @@ +/singleton/education/finance + name = "Finance Degree" + description = "You are at least 21 years of age. You graduated in a field related to finance, whether that is Business Management or something else. \ + You can count very well, and you have a statistician's eye - especially for credits." + minimum_character_age = list( + SPECIES_HUMAN = 21, + SPECIES_SKRELL = 55, + SPECIES_SKRELL_AXIORI = 55 + ) + +/singleton/education/arts + name = "Humanities Degree" + description = "You are at least 21 years of age. You graduated in a field related to the humanities, whether that is music, arts, linguistics, or a bachelor's in \ + psychology. You are likely very well-read on foreign cultures and on the human mind." + minimum_character_age = list( + SPECIES_HUMAN = 21, + SPECIES_SKRELL = 55, + SPECIES_SKRELL_AXIORI = 55 + ) diff --git a/code/modules/background/education/science.dm b/code/modules/background/education/science.dm new file mode 100644 index 00000000000..218ff30e23e --- /dev/null +++ b/code/modules/background/education/science.dm @@ -0,0 +1,81 @@ +/singleton/education/research_and_development + name = "Research & Development Degree" + description = "You are at least 30 years of age, with a PhD in an applicable field for Research and Development. This may range from a Firearms Engineering degree \ + to a Bluespace Engineering degree or even Aerospace Engineering. Space is the limit for your research." + jobs = list("Scientist") + minimum_character_age = list( + SPECIES_HUMAN = 30, + SPECIES_SKRELL = 60, + SPECIES_SKRELL_AXIORI = 60 + ) + skills = list( + /singleton/skill/research = SKILL_LEVEL_PROFESSIONAL + ) + +/singleton/education/robotics_masters + name = "Robotics Master's" + description = "You are at least 25 years of age, with a Master's in Robotics. Your specialization is in building and repairing IPCs and other smaller robots, though \ + you are also capable of building exoskeletons and mechs. You're also proficient with some more basic engineering skills, though you prefer the \ + theoretical aspect and robots in general." + jobs = list("Roboticist") + minimum_character_age = list( + SPECIES_HUMAN = 25, + SPECIES_SKRELL = 60, + SPECIES_SKRELL_AXIORI = 60 + ) + skills = list( + /singleton/skill/research = SKILL_LEVEL_FAMILIAR, + /singleton/skill/robotics = SKILL_LEVEL_PROFESSIONAL, + /singleton/skill/surgery = SKILL_LEVEL_FAMILIAR, + /singleton/skill/electrical_engineering = SKILL_LEVEL_FAMILIAR, + /singleton/skill/mechanical_engineering = SKILL_LEVEL_FAMILIAR, + ) + +/singleton/education/mechatronics_masters + name = "Mechatronics Master's" + description = "You are at least 25 years of age, with a Master's in Mechatronics. Your specialization is with building large human-sized exoskeletons and mechs, though \ + you've also learnt how to repair IPCs and simpler robots as well. You're more proficient with the mechanical aspects of engineering as well." + jobs = list("Roboticist") + minimum_character_age = list( + SPECIES_HUMAN = 25, + SPECIES_SKRELL = 60, + SPECIES_SKRELL_AXIORI = 60 + ) + skills = list( + /singleton/skill/research = SKILL_LEVEL_FAMILIAR, + /singleton/skill/robotics = SKILL_LEVEL_TRAINED, + /singleton/skill/surgery = SKILL_LEVEL_FAMILIAR, + /singleton/skill/electrical_engineering = SKILL_LEVEL_FAMILIAR, + /singleton/skill/mechanical_engineering = SKILL_LEVEL_PROFESSIONAL + ) + +/singleton/education/xenobotany_degree + name = "Xenobotany Degree" + description = "You are at least 30 years of age, with a PhD in Xenobotany. Your specialization is with discovering, sequencing, and creating alien flora... though \ + you can also grow some potatoes in your spare time." + jobs = list("Xenobotanist") + minimum_character_age = list( + SPECIES_HUMAN = 30, + SPECIES_SKRELL = 60, + SPECIES_SKRELL_AXIORI = 60 + ) + skills = list( + /singleton/skill/research = SKILL_LEVEL_FAMILIAR, + /singleton/skill/gardening = SKILL_LEVEL_PROFESSIONAL, + /singleton/skill/xenobotany = SKILL_LEVEL_PROFESSIONAL + ) + + +/singleton/education/xenobiology_degree + name = "Xenobiology Degree" + description = "You are at least 30 years of age, with a PhD in Xenobiology. Your specialization is with discovering and cataloguing alien animals." + jobs = list("Xenobiologist") + minimum_character_age = list( + SPECIES_HUMAN = 30, + SPECIES_SKRELL = 60, + SPECIES_SKRELL_AXIORI = 60 + ) + skills = list( + /singleton/skill/research = SKILL_LEVEL_FAMILIAR, + /singleton/skill/xenobiology = SKILL_LEVEL_PROFESSIONAL + ) diff --git a/code/modules/background/education/security.dm b/code/modules/background/education/security.dm new file mode 100644 index 00000000000..2a4a07d880c --- /dev/null +++ b/code/modules/background/education/security.dm @@ -0,0 +1,15 @@ +/singleton/education/forensics_degree + name = "Forensics Science Degree" + description = "You are 25 years of age or older, with a degree in Forensics Science. You specialize in the medical procedures required to understand why someone died." + jobs = list("Investigator") + minimum_character_age = list( + SPECIES_HUMAN = 25, + SPECIES_SKRELL = 60, + SPECIES_SKRELL_AXIORI = 60 + ) + skills = list( + /singleton/skill/surgery = SKILL_LEVEL_FAMILIAR, + /singleton/skill/medicine = SKILL_LEVEL_FAMILIAR, + /singleton/skill/anatomy = SKILL_LEVEL_FAMILIAR, + /singleton/skill/forensics = SKILL_LEVEL_PROFESSIONAL + ) diff --git a/code/modules/background/education/service.dm b/code/modules/background/education/service.dm new file mode 100644 index 00000000000..33c2327f559 --- /dev/null +++ b/code/modules/background/education/service.dm @@ -0,0 +1,67 @@ +/singleton/education/mixing + name = "Mixing License" + description = "You paid for and successfully attained an Idris mixing license, making you officially a specialist in mixing cocktails, mocktails, and whatever else. \ + Time to mix drinks and save lives." + jobs = list("Bartender") + minimum_character_age = list( + SPECIES_HUMAN = 18, + SPECIES_SKRELL = 50, + SPECIES_SKRELL_AXIORI = 50 + ) + skills = list( + /singleton/skill/mixing = SKILL_LEVEL_PROFESSIONAL, + ) + +/singleton/education/cooking_degree + name = "Culinary Arts Degree" + description = "You obtained a degree in Culinary Arts, making you an artist at cooking. Pancakes, steaks, and cultural food - you've learnt about how to cook it all." + jobs = list("Chef") + minimum_character_age = list( + SPECIES_HUMAN = 18, + SPECIES_SKRELL = 50, + SPECIES_SKRELL_AXIORI = 50 + ) + skills = list( + /singleton/skill/cooking = SKILL_LEVEL_PROFESSIONAL, + ) + +/singleton/education/cooking_certification + name = "Culinary Certification" + description = "You obtained an Idris certification to work as a cook. You won't be as good as a professional chef, but you can pour your soul out into a good breakfast." + jobs = list("Chef") + minimum_character_age = list( + SPECIES_HUMAN = 18, + SPECIES_SKRELL = 50, + SPECIES_SKRELL_AXIORI = 50 + ) + skills = list( + /singleton/skill/cooking = SKILL_LEVEL_TRAINED, + ) + +/singleton/education/hydroponics_degree + name = "Hydroponics Degree" + description = "You obtained a degree to work as a hydroponicist or gardener. Your degree covered both manual and hydroponics gardening of just about every plant known to your species, \ + alongside plants that are more typical to other cultures in the Spur." + jobs = list("Gardener") + minimum_character_age = list( + SPECIES_HUMAN = 18, + SPECIES_SKRELL = 50, + SPECIES_SKRELL_AXIORI = 50 + ) + skills = list( + /singleton/skill/gardening = SKILL_LEVEL_PROFESSIONAL, + ) + +/singleton/education/hydroponics_certification + name = "Hydroponics Certification" + description = "You obtained an Idris certification to work as a hydroponicist or gardener. Although you might not be as much of an expert as someone with a Hydroponics degree, \ + you can still plant just about everything if you give it your all." + jobs = list("Gardener") + minimum_character_age = list( + SPECIES_HUMAN = 18, + SPECIES_SKRELL = 50, + SPECIES_SKRELL_AXIORI = 50 + ) + skills = list( + /singleton/skill/gardening = SKILL_LEVEL_TRAINED, + ) diff --git a/code/modules/client/preference_setup/origin/origin.dm b/code/modules/client/preference_setup/origin/origin.dm index 65947b1fc8a..46bd20bbf7a 100644 --- a/code/modules/client/preference_setup/origin/origin.dm +++ b/code/modules/client/preference_setup/origin/origin.dm @@ -210,7 +210,18 @@ if(href_list["set_education_data"]) user << browse(null, "window=set_education_data") - pref.education = html_decode(href_list["set_education_data"]) + var/new_education = html_decode(href_list["set_education_data"]) + pref.education = new_education + + pref.skills = list() // reset skills because we have to give them new minimums + to_chat(user, SPAN_WARNING("Your skills have been reset as you changed your education.")) + var/singleton/education/education = GET_SINGLETON(text2path(new_education)) + if(istype(education)) + for(var/skill in education.skills) + var/singleton/skill/new_skill = GET_SINGLETON(skill) + pref.skills[new_skill.type] = education.skills[new_skill.type] + to_chat(user, SPAN_NOTICE("Added the [new_skill.name] skill at level [SSskills.skill_level_map[education.skills[new_skill.type]]].")) + sanitize_character() return TOPIC_REFRESH @@ -277,12 +288,12 @@ var/datum/browser/education_win = new(user, topic_data, "Education Selection") var/dat = "
[ED.name]
" dat += "
[ED.description]
" - dat += "This education gives you the following skills:" + dat += "This education gives you the following skills: " var/list/skills_to_show = list() for(var/skill in ED.skills) var/singleton/skill/S = GET_SINGLETON(skill) - skills_to_show += S.name - dat += "[english_list(skills_to_show)]
" + skills_to_show += "[S.name] ([SPAN_DANGER(SSskills.skill_level_map[ED.skills[S.type]])])" + dat += "[english_list(skills_to_show)].
" dat += "
\[Select\]
" dat += "" education_win.set_content(dat) diff --git a/code/modules/client/preference_setup/skills/skills.dm b/code/modules/client/preference_setup/skills/skills.dm index 29d7cc43fe7..fdca0d182e7 100644 --- a/code/modules/client/preference_setup/skills/skills.dm +++ b/code/modules/client/preference_setup/skills/skills.dm @@ -51,29 +51,75 @@ /datum/category_item/player_setup_item/skills/sanitize_character(var/sql_load = 0) //todomatt +// Skills HTML UI lifted from Baystation 12. Credit goes to Afterthought12. Thank you for saving me from HTML hell! /datum/category_item/player_setup_item/skills/content(var/mob/user) + if(!SSskills.initialized) + return "
Skills not initialized yet. Please wait a bit and reload this section.
" + var/list/dat = list() + + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + + dat += "" var/singleton/education/education = GET_SINGLETON(text2path(pref.education)) for(var/category in SSskills.skill_tree) var/singleton/skill_category/skill_category = category - dat += "[skill_category.name]
" + dat += "" for(var/subcategory in SSskills.skill_tree[skill_category]) - dat += "[subcategory]
[skill_category.name] (X points remaining)" + dat += "
" + dat += "" for(var/singleton/skill/skill in SSskills.skill_tree[skill_category][subcategory]) - dat += "[skill.name]: " - var/current_skill_level = 0 - if(skill.type in pref.skills) - current_skill_level = pref.skills[skill.type] - for(var/skill_level in SKILL_LEVEL_UNFAMILIAR to skill.get_maximum_level(education)) - if(current_skill_level == skill_level) - dat += "\[[SSskills.skill_level_map[skill_level]]\]" - if(current_skill_level > skill_level) - dat += "[SSskills.skill_level_map[skill_level]]" - if(current_skill_level < skill_level) - dat += "[SSskills.skill_level_map[skill_level]]" - dat += "

" - dat += "
[subcategory]

" - . = dat.Join() + dat += get_skill_row(skill, education) + dat += "" + + . = JOINTEXT(dat) + +/datum/category_item/player_setup_item/skills/proc/get_skill_row(singleton/skill/skill, singleton/education/education) + var/list/dat = list() + dat += "" + dat += "[skill.name]" + + var/current_level = pref.skills[skill.type] + var/maximum_skill_level = skill.get_maximum_level(education) + for(var/i = SKILL_LEVEL_UNFAMILIAR, i <= SKILL_LEVEL_PROFESSIONAL, i++) + dat += skill_to_button(skill, education, current_level, i, maximum_skill_level) + + return JOINTEXT(dat) + +/datum/category_item/player_setup_item/skills/proc/skill_to_button(singleton/skill/skill, singleton/education/education, current_level, selection_level, maximum_skill_level) + var/effective_level = selection_level + if(effective_level <= 0) + return "" + + var/level_name = SSskills.skill_level_map[effective_level] + var/cost = "N" //skill.get_cost(effective_level) + var/button_label = "[level_name] ([cost])" + var/given_skill = FALSE + + // Prevent removal of skills given by education. These are meant to be minimum skills for jobs, after all. + if(skill.type in education.skills) + given_skill = TRUE + + if((effective_level < current_level) && given_skill) + return "[span("Forced", "[button_label]")]" + else if((effective_level < current_level) && !given_skill) + return "[add_link(skill, education, button_label, "'Current'", effective_level)]" + else if(effective_level == current_level) + return "[span("Current", "[button_label]")]" + else if(effective_level <= maximum_skill_level) + return "[add_link(skill, education, button_label, "'Selectable'", effective_level)]" + else + return "[span("Toohigh", "[button_label]")]" + +/datum/category_item/player_setup_item/skills/proc/add_link(singleton/skill/skill, singleton/education/education, text, style, value) + if(skill.get_maximum_level(education) >= value) + return "[text]" + return text /datum/category_item/player_setup_item/skills/OnTopic(href, href_list, user) if(href_list["skillinfo"]) @@ -101,6 +147,6 @@ pref.skills -= new_skill.type else pref.skills[new_skill.type] = text2num(new_skill_value) - return TOPIC_REFRESH + return TOPIC_REFRESH return ..() diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 088db9e0602..81bf6a04539 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -483,7 +483,6 @@ var/list/preferences_datums = list() character.set_culture(GET_SINGLETON(text2path(culture))) character.set_origin(GET_SINGLETON(text2path(origin))) - // Destroy/cyborgize organs & setup body markings character.sync_organ_prefs_to_mob(src) @@ -524,6 +523,8 @@ var/list/preferences_datums = list() if(istype(P) && (P.ability_flags & PSI_FLAG_CANON)) P.apply(character) + character.skills.set_skills_from_pref(src) + if(icon_updates) character.force_update_limbs() character.update_mutations(0) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index a1bc4fc7a73..40a4f446d4f 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -104,6 +104,8 @@ become_hearing_sensitive() + skills = new skills(src) + /** * Generate the tag for this mob * diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 7c49b1fbf25..cf4f2c7e09b 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -274,3 +274,5 @@ /// A assoc lazylist of to_chat notifications, key = string message, value = world time integer var/list/message_notifications + /// The holder for mob skills. + var/datum/skills/skills = /datum/skills diff --git a/code/modules/mob/skills/skills.dm b/code/modules/mob/skills/skills.dm new file mode 100644 index 00000000000..09be0ec3352 --- /dev/null +++ b/code/modules/mob/skills/skills.dm @@ -0,0 +1,57 @@ +/datum/skills + /// The mob that owns this skill datum. + var/mob/owner + /// The skills that this skill datum holds. Assoc list of skill type to level. + var/list/skills = list() + /// The TGUI module for changing skills. + var/tgui_module + +/datum/skills/New(mob/M) + if(!istype(M)) + crash_with("Invalid mob [M] supplied to skill datum!") + owner = M + ..() + +/** + * Returns the proficiency with a certain skill. + */ +/datum/skills/proc/get_skill_level(skill_type) + if(skill_type in skills) + return skills[skill_type] + return SKILL_LEVEL_UNFAMILIAR + +/** + * Sets skills starting from a preferences datum. + */ +/datum/skills/proc/set_skills_from_pref(datum/preferences/pref) + for(var/S in pref.skills) + var/singleton/skill/skill = GET_SINGLETON(S) + var/skill_level = pref.skills[skill.type] + skills[skill.type] = skill_level + +/** + * Returns the mob's proficiency with a certain skill. + */ +/mob/proc/get_skill_level(skill_type) + return skills.get_skill_level(skill_type) + +/** + * Takes a skill type and the level of skill needed. + * Returns TRUE if the mob's skill level exceeds or equals the skill level needed. + * Returns FALSE otherwise. + */ +/mob/proc/skill_check(skill_type, skill_level_needed) + return get_skill_level(skill_type) >= skill_level_needed + +/** + * Returns a multiplier based on the mob's skill. Takes a skill type and a minimum skill floor at least. + * Bonus and malus are the modifiers added or removed for each skill level of difference from the required skill floor. + */ +/mob/proc/get_skill_multiplier(skill_type, skill_floor = SKILL_LEVEL_TRAINED, bonus = 0.2, malus = 0.2) + var/modifier = 1 + var/skill_level = get_skill_level(skill_type) + if(skill_level >= SKILL_LEVEL_TRAINED) + modifier -= bonus * max(1, skill_level - skill_floor) + else + modifier += malus * max(1, skill_floor - skill_level) + return modifier diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm index 4cdc8cce05a..7e88c4a88da 100644 --- a/code/modules/power/singularity/emitter.dm +++ b/code/modules/power/singularity/emitter.dm @@ -73,6 +73,9 @@ /obj/machinery/power/emitter/attack_hand(mob/user) add_fingerprint(user) + if(user.get_skill_level(/singleton/skill/reactor_systems) <= SKILL_LEVEL_FAMILIAR) + to_chat(user, SPAN_WARNING("You have no idea where the switch even is on this thing...")) + return activate(user) /obj/machinery/power/emitter/proc/activate(mob/user) From cecd34bb7a94953088f1d408633c2ff0d3a5d71c Mon Sep 17 00:00:00 2001 From: Matt Atlas Date: Sun, 10 Nov 2024 22:21:36 +0100 Subject: [PATCH 11/16] dasdas --- code/modules/client/preference_setup/skills/skills.dm | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/code/modules/client/preference_setup/skills/skills.dm b/code/modules/client/preference_setup/skills/skills.dm index fdca0d182e7..ce0e17b412f 100644 --- a/code/modules/client/preference_setup/skills/skills.dm +++ b/code/modules/client/preference_setup/skills/skills.dm @@ -31,8 +31,15 @@ ) /datum/category_item/player_setup_item/skills/gather_save_parameters() + var/list/sanitized_skills = list() + for(var/S in pref.skills) + var/singleton/skill/skill = GET_SINGLETON(text2path(S)) + if(!istype(skill)) + continue + sanitized_skills[skill.type] = pref.skills[S] + return list( - "skills" = pref.skills, + "skills" = json_encode(sanitized_skills), "id" = pref.current_character, "ckey" = PREF_CLIENT_CKEY ) From 900107e95823c4bc1b5b45e7dc7d80dd05aea535 Mon Sep 17 00:00:00 2001 From: Matt Atlas Date: Sun, 10 Nov 2024 22:42:26 +0100 Subject: [PATCH 12/16] pure furies --- .../client/preference_setup/origin/origin.dm | 89 ------------------ .../client/preference_setup/skills/skills.dm | 93 ++++++++++++++++++- 2 files changed, 91 insertions(+), 91 deletions(-) diff --git a/code/modules/client/preference_setup/origin/origin.dm b/code/modules/client/preference_setup/origin/origin.dm index 46bd20bbf7a..02ab8293337 100644 --- a/code/modules/client/preference_setup/origin/origin.dm +++ b/code/modules/client/preference_setup/origin/origin.dm @@ -9,7 +9,6 @@ /datum/category_item/player_setup_item/origin/load_character(var/savefile/S) S["culture"] >> pref.culture S["origin"] >> pref.origin - S["education"] >> pref.education S["citizenship"] >> pref.citizenship S["religion"] >> pref.religion S["accent"] >> pref.accent @@ -18,7 +17,6 @@ /datum/category_item/player_setup_item/origin/save_character(var/savefile/S) S["culture"] << pref.culture S["origin"] << pref.origin - S["education"] << pref.education S["citizenship"] << pref.citizenship S["religion"] << pref.religion S["accent"] << pref.accent @@ -30,7 +28,6 @@ "vars" = list( "culture", "origin", - "education", "economic_status", "citizenship", "religion", @@ -48,7 +45,6 @@ "ss13_characters" = list( "culture", "origin", - "education", "economic_status", "citizenship", "religion", @@ -62,7 +58,6 @@ return list( "culture" = pref.culture, "origin" = pref.origin, - "education" = pref.education, "economic_status" = pref.economic_status, "citizenship" = pref.citizenship, "religion" = pref.religion, @@ -88,24 +83,6 @@ var/singleton/origin_item/origin/OI = pick(our_culture.possible_origins) pref.origin = "[OI.type]" - if(!istext(pref.education) || !ispath(text2path(pref.education), /singleton/education)) - var/singleton/education/ED = find_suitable_education() - if(ED) - pref.education = "[ED.type]" - else - var/singleton/education/our_education = GET_SINGLETON(text2path(pref.education)) - if(length(our_education.species_restriction)) - if(pref.species in our_education.species_restriction) - var/singleton/education/ED = find_suitable_education() - if(ED) - pref.education = "[ED.type]" - if(length(our_education.minimum_character_age)) - if(pref.species in our_education.minimum_character_age) - if(pref.age < our_education.minimum_character_age[pref.species]) - var/singleton/education/ED = find_suitable_education() - if(ED) - pref.education = "[ED.type]" - var/singleton/origin_item/origin/our_origin = GET_SINGLETON(text2path(pref.origin)) if(!(pref.citizenship in our_origin.possible_citizenships)) to_client_chat(SPAN_WARNING("Your previous citizenship is invalid for this origin! Resetting.")) @@ -143,8 +120,6 @@ dat += "
- [OR.important_information]" dat += "
" - var/singleton/education/ED = GET_SINGLETON(text2path(pref.education)) - dat += "Education: [ED.name]
" dat += "Economic Status: [pref.economic_status]
" dat += "Citizenship: [pref.citizenship]
" dat += "Religion: [pref.religion]
" @@ -178,24 +153,6 @@ show_origin_window(chosen_origin, "set_origin_data", user) return TOPIC_HANDLED - if(href_list["open_education_menu"]) - var/list/options = list() - var/list/singleton/education/education_list = GET_SINGLETON_SUBTYPE_MAP(/singleton/education) - for(var/singleton_type in education_list) - var/singleton/education/ED = education_list[singleton_type] - if(length(ED.species_restriction)) - if(pref.species in ED.species_restriction) - continue - if(length(ED.minimum_character_age)) - if(pref.species in ED.minimum_character_age) - if(pref.age < ED.minimum_character_age[pref.species]) - continue - options[ED.name] = ED - var/result = tgui_input_list(user, "Choose your character's education.", "Education", options) - var/singleton/education/chosen_education = options[result] - if(chosen_education) - show_education_window(chosen_education, "set_education_data", user) - if(href_list["set_culture_data"]) user << browse(null, "window=set_culture_data") pref.culture = html_decode(href_list["set_culture_data"]) @@ -208,23 +165,6 @@ sanitize_character() return TOPIC_REFRESH - if(href_list["set_education_data"]) - user << browse(null, "window=set_education_data") - var/new_education = html_decode(href_list["set_education_data"]) - pref.education = new_education - - pref.skills = list() // reset skills because we have to give them new minimums - to_chat(user, SPAN_WARNING("Your skills have been reset as you changed your education.")) - var/singleton/education/education = GET_SINGLETON(text2path(new_education)) - if(istype(education)) - for(var/skill in education.skills) - var/singleton/skill/new_skill = GET_SINGLETON(skill) - pref.skills[new_skill.type] = education.skills[new_skill.type] - to_chat(user, SPAN_NOTICE("Added the [new_skill.name] skill at level [SSskills.skill_level_map[education.skills[new_skill.type]]].")) - - sanitize_character() - return TOPIC_REFRESH - if(href_list["economic_status"]) var/new_status = tgui_input_list(user, "Choose how wealthy your character is. Note that this applies a multiplier to a value that is also affected by your species and job.", "Character Preference", ECONOMIC_POSITIONS, pref.economic_status) if(new_status && CanUseTopic(user)) @@ -284,21 +224,6 @@ origin_win.set_content(dat) origin_win.open() -/datum/category_item/player_setup_item/origin/proc/show_education_window(var/singleton/education/ED, var/topic_data, var/mob/user) - var/datum/browser/education_win = new(user, topic_data, "Education Selection") - var/dat = "
[ED.name]
" - dat += "
[ED.description]
" - dat += "This education gives you the following skills: " - var/list/skills_to_show = list() - for(var/skill in ED.skills) - var/singleton/skill/S = GET_SINGLETON(skill) - skills_to_show += "[S.name] ([SPAN_DANGER(SSskills.skill_level_map[ED.skills[S.type]])])" - dat += "[english_list(skills_to_show)].
" - dat += "
\[Select\]
" - dat += "" - education_win.set_content(dat) - education_win.open() - /datum/category_item/player_setup_item/origin/proc/show_citizenship_menu(mob/user, selected_citizenship) var/datum/citizenship/citizenship = SSrecords.citizenships[selected_citizenship] if(citizenship) @@ -332,17 +257,3 @@ dat += "" acc_win.set_content(dat) acc_win.open() - -/// This proc finds and returns the first suitable education for the pref datum. -/datum/category_item/player_setup_item/origin/proc/find_suitable_education() - var/list/singleton/education/education_list = GET_SINGLETON_SUBTYPE_MAP(/singleton/education) - for(var/singleton_type in education_list) - var/singleton/education/ED = education_list[singleton_type] - if(length(ED.species_restriction)) - if(pref.species in ED.species_restriction) - continue - if(length(ED.minimum_character_age)) - if(pref.species in ED.minimum_character_age) - if(pref.age < ED.minimum_character_age[pref.species]) - continue - return ED diff --git a/code/modules/client/preference_setup/skills/skills.dm b/code/modules/client/preference_setup/skills/skills.dm index ce0e17b412f..1aeff76479f 100644 --- a/code/modules/client/preference_setup/skills/skills.dm +++ b/code/modules/client/preference_setup/skills/skills.dm @@ -4,14 +4,17 @@ /datum/category_item/player_setup_item/skills/load_character(var/savefile/S) S["skills"] >> pref.skills + S["education"] >> pref.education /datum/category_item/player_setup_item/skills/save_character(var/savefile/S) S["skills"] << pref.skills + S["education"] << pref.education /datum/category_item/player_setup_item/skills/gather_load_query() return list( "ss13_characters" = list( "vars" = list( + "education", "skills" ), "args" = list("id") @@ -24,6 +27,7 @@ /datum/category_item/player_setup_item/skills/gather_save_query() return list( "ss13_characters" = list( + "education", "skills", "id" = 1, "ckey" = 1 @@ -33,12 +37,13 @@ /datum/category_item/player_setup_item/skills/gather_save_parameters() var/list/sanitized_skills = list() for(var/S in pref.skills) - var/singleton/skill/skill = GET_SINGLETON(text2path(S)) + var/singleton/skill/skill = GET_SINGLETON(S) if(!istype(skill)) continue sanitized_skills[skill.type] = pref.skills[S] return list( + "education" = pref.education, "skills" = json_encode(sanitized_skills), "id" = pref.current_character, "ckey" = PREF_CLIENT_CKEY @@ -57,6 +62,23 @@ /datum/category_item/player_setup_item/skills/sanitize_character(var/sql_load = 0) //todomatt + if(!istext(pref.education) || !ispath(text2path(pref.education), /singleton/education)) + var/singleton/education/ED = find_suitable_education() + if(ED) + pref.education = "[ED.type]" + else + var/singleton/education/our_education = GET_SINGLETON(text2path(pref.education)) + if(length(our_education.species_restriction)) + if(pref.species in our_education.species_restriction) + var/singleton/education/ED = find_suitable_education() + if(ED) + pref.education = "[ED.type]" + if(length(our_education.minimum_character_age)) + if(pref.species in our_education.minimum_character_age) + if(pref.age < our_education.minimum_character_age[pref.species]) + var/singleton/education/ED = find_suitable_education() + if(ED) + pref.education = "[ED.type]" // Skills HTML UI lifted from Baystation 12. Credit goes to Afterthought12. Thank you for saving me from HTML hell! /datum/category_item/player_setup_item/skills/content(var/mob/user) @@ -71,7 +93,8 @@ dat += "" dat += "" dat += "" - + var/singleton/education/ED = GET_SINGLETON(text2path(pref.education)) + dat += "Education: [ED.name]

" dat += "" var/singleton/education/education = GET_SINGLETON(text2path(pref.education)) for(var/category in SSskills.skill_tree) @@ -156,4 +179,70 @@ pref.skills[new_skill.type] = text2num(new_skill_value) return TOPIC_REFRESH + else if(href_list["open_education_menu"]) + var/list/options = list() + var/list/singleton/education/education_list = GET_SINGLETON_SUBTYPE_MAP(/singleton/education) + for(var/singleton_type in education_list) + var/singleton/education/ED = education_list[singleton_type] + if(length(ED.species_restriction)) + if(pref.species in ED.species_restriction) + continue + if(length(ED.minimum_character_age)) + if(pref.species in ED.minimum_character_age) + if(pref.age < ED.minimum_character_age[pref.species]) + continue + options[ED.name] = ED + var/result = tgui_input_list(user, "Choose your character's education.", "Education", options) + var/singleton/education/chosen_education = options[result] + if(chosen_education) + show_education_window(chosen_education, "set_education_data", user) + + else if(href_list["set_education_data"]) + user << browse(null, "window=set_education_data") + var/new_education = html_decode(href_list["set_education_data"]) + pref.education = new_education + + pref.skills = list() // reset skills because we have to give them new minimums + to_chat(user, SPAN_WARNING("Your skills have been reset as you changed your education.")) + var/singleton/education/education = GET_SINGLETON(text2path(new_education)) + if(istype(education)) + for(var/skill in education.skills) + var/singleton/skill/new_skill = GET_SINGLETON(skill) + pref.skills[new_skill.type] = education.skills[new_skill.type] + to_chat(user, SPAN_NOTICE("Added the [new_skill.name] skill at level [SSskills.skill_level_map[education.skills[new_skill.type]]].")) + + sanitize_character() + return TOPIC_REFRESH + return ..() + +/datum/category_item/player_setup_item/skills/proc/show_education_window(var/singleton/education/ED, var/topic_data, var/mob/user) + var/datum/browser/education_win = new(user, topic_data, "Education Selection") + var/dat = "
[ED.name]
" + dat += "
[ED.description]
" + dat += "This education gives you the following skills: " + var/list/skills_to_show = list() + for(var/skill in ED.skills) + var/singleton/skill/S = GET_SINGLETON(skill) + skills_to_show += "[S.name] ([SPAN_DANGER(SSskills.skill_level_map[ED.skills[S.type]])])" + dat += "[english_list(skills_to_show)].
" + dat += "
\[Select\]
" + dat += "" + education_win.set_content(dat) + education_win.open() + +/** + * This proc finds and returns the first suitable education for the pref datum. + */ +/datum/category_item/player_setup_item/skills/proc/find_suitable_education() + var/list/singleton/education/education_list = GET_SINGLETON_SUBTYPE_MAP(/singleton/education) + for(var/singleton_type in education_list) + var/singleton/education/ED = education_list[singleton_type] + if(length(ED.species_restriction)) + if(pref.species in ED.species_restriction) + continue + if(length(ED.minimum_character_age)) + if(pref.species in ED.minimum_character_age) + if(pref.age < ED.minimum_character_age[pref.species]) + continue + return ED From 437c414016bf101262fea1fd43f755e3c9876002 Mon Sep 17 00:00:00 2001 From: Matt Atlas Date: Sun, 10 Nov 2024 23:02:09 +0100 Subject: [PATCH 13/16] makes sql saving work --- code/modules/client/preference_setup/skills/skills.dm | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/code/modules/client/preference_setup/skills/skills.dm b/code/modules/client/preference_setup/skills/skills.dm index 1aeff76479f..2f03b5ba026 100644 --- a/code/modules/client/preference_setup/skills/skills.dm +++ b/code/modules/client/preference_setup/skills/skills.dm @@ -54,12 +54,19 @@ pref.skills = "{}" var/before = pref.skills + var/loaded_skills try - pref.skills = json_decode(pref.skills) + loaded_skills = json_decode(pref.skills) catch (var/exception/e) log_debug("SKILLS: Caught [e]. Initial value: [before]") pref.skills = list() + pref.skills = list() + for(var/new_skill in loaded_skills) + var/singleton/skill/skill = GET_SINGLETON(text2path(new_skill)) + if(istype(skill)) + pref.skills[skill.type] = loaded_skills[new_skill] + /datum/category_item/player_setup_item/skills/sanitize_character(var/sql_load = 0) //todomatt if(!istext(pref.education) || !ispath(text2path(pref.education), /singleton/education)) From b662994a7223b729a311fdf2dd9e5fa76c08a9c9 Mon Sep 17 00:00:00 2001 From: Matt Atlas Date: Tue, 12 Nov 2024 22:01:12 +0100 Subject: [PATCH 14/16] asddasdsaads --- code/__DEFINES/skills.dm | 8 ++++++++ code/datums/skills/_skill_categories.dm | 11 ++++++++++ code/datums/skills/_skills.dm | 11 ++++++++++ .../client/preference_setup/skills/skills.dm | 20 ++++++++++++------- code/modules/client/preferences.dm | 2 ++ .../living/carbon/human/species/species.dm | 19 ++++++++++++++++++ 6 files changed, 64 insertions(+), 7 deletions(-) diff --git a/code/__DEFINES/skills.dm b/code/__DEFINES/skills.dm index 19ec510482d..7be22d22818 100644 --- a/code/__DEFINES/skills.dm +++ b/code/__DEFINES/skills.dm @@ -22,3 +22,11 @@ #define SKILL_CATEGORY_COMBAT "Combat" #define SKILL_SUBCATEGORY_RANGED "Ranged" #define SKILL_SUBCATEGORY_MELEE "Melee" + +#define BASE_SKILL_POINTS_COMBAT 4 +#define BASE_SKILL_POINTS_OCCUPATIONAL 8 +#define BASE_SKILL_POINTS_EVERYDAY 8 + +#define SKILL_MODIFIER_EASY 1 +#define SKILL_MODIFIER_MEDIUM 2 +#define SKILL_MODIFIER_HARD 4 diff --git a/code/datums/skills/_skill_categories.dm b/code/datums/skills/_skill_categories.dm index a2e7b4da93b..7c7903e2723 100644 --- a/code/datums/skills/_skill_categories.dm +++ b/code/datums/skills/_skill_categories.dm @@ -3,16 +3,27 @@ var/name /// The description and purpose of the skill category, displayed in the info tab. var/desc + /// The hex colour of the skill category. Shows as background on the skills tab. + var/color + /// The number of base points a character gets in this category. + var/base_skill_points + +/singleton/skill_category/proc/calculate_skill_points(datum/species/species, age, singleton/culture_item/culture, singleton/culture_item/origin) + var/species_modifier = species.modify_skill_points(src, age) + return base_skill_points * species_modifier /singleton/skill_category/everyday name = SKILL_CATEGORY_EVERYDAY desc = "An everyday skill is a skill that can be picked up normally. Think like mixing a drink, growing a plant, cooking, and so on." + base_skill_points = BASE_SKILL_POINTS_EVERYDAY /singleton/skill_category/occupational name = SKILL_CATEGORY_OCCUPATIONAL desc = "Occupational skills are the skills necessary for you to do your job. They typically lock certain aspects of your department if you aren't proficient enough." + base_skill_points = BASE_SKILL_POINTS_OCCUPATIONAL /singleton/skill_category/combat name = SKILL_CATEGORY_COMBAT desc = "A combat skill is a skill that has a direct effect in combat. These have an increased cost." + base_skill_points = BASE_SKILL_POINTS_COMBAT diff --git a/code/datums/skills/_skills.dm b/code/datums/skills/_skills.dm index bef46c7a6ac..a6b64f6313c 100644 --- a/code/datums/skills/_skills.dm +++ b/code/datums/skills/_skills.dm @@ -12,7 +12,12 @@ var/category /// The sub-category of this skill. Used to better sort skills. var/subcategory + /// The modifier for how difficult the skill is. Each level costs this much * the level. + var/skill_difficulty_modifier = SKILL_MODIFIER_MEDIUM +/** + * Returns the maximum level a character can have in this skill depending on education. + */ /singleton/skill/proc/get_maximum_level(var/singleton/education/education) if(!istype(education)) crash_with("SKILL: Invalid [education] fed to get_maximum_level!") @@ -27,3 +32,9 @@ return uneducated_skill_cap + +/** + * Returns the cost of this skill, modified by its difficulty modifier. + */ +/singleton/skill/proc/get_cost(level) + return skill_difficulty_modifier * level diff --git a/code/modules/client/preference_setup/skills/skills.dm b/code/modules/client/preference_setup/skills/skills.dm index 2f03b5ba026..1984fdc6e6b 100644 --- a/code/modules/client/preference_setup/skills/skills.dm +++ b/code/modules/client/preference_setup/skills/skills.dm @@ -87,7 +87,7 @@ if(ED) pref.education = "[ED.type]" -// Skills HTML UI lifted from Baystation 12. Credit goes to Afterthought12. Thank you for saving me from HTML hell! +// Skills HTML UI, along with a lot of other components here, lifted from Baystation 12. Credit goes to Afterthought12. Thank you for saving me from HTML hell! /datum/category_item/player_setup_item/skills/content(var/mob/user) if(!SSskills.initialized) return "
Skills not initialized yet. Please wait a bit and reload this section.
" @@ -101,12 +101,12 @@ dat += "" dat += "" var/singleton/education/ED = GET_SINGLETON(text2path(pref.education)) - dat += "Education: [ED.name]

" + dat += "
Education: [ED.name]


" dat += "
" var/singleton/education/education = GET_SINGLETON(text2path(pref.education)) for(var/category in SSskills.skill_tree) var/singleton/skill_category/skill_category = category - dat += "" for(var/subcategory in SSskills.skill_tree[skill_category]) dat += "" @@ -119,7 +119,7 @@ /datum/category_item/player_setup_item/skills/proc/get_skill_row(singleton/skill/skill, singleton/education/education) var/list/dat = list() dat += "" - dat += "" + dat += "" var/current_level = pref.skills[skill.type] var/maximum_skill_level = skill.get_maximum_level(education) @@ -134,7 +134,7 @@ return "" var/level_name = SSskills.skill_level_map[effective_level] - var/cost = "N" //skill.get_cost(effective_level) + var/cost = skill.get_cost(effective_level) var/button_label = "[level_name] ([cost])" var/given_skill = FALSE @@ -155,9 +155,15 @@ /datum/category_item/player_setup_item/skills/proc/add_link(singleton/skill/skill, singleton/education/education, text, style, value) if(skill.get_maximum_level(education) >= value) - return "[text]" + return "[text]" return text +/datum/category_item/player_setup_item/skills/proc/calculate_remaining_skill_points(singleton/skill_category/skill_category) + if(!istype(skill_category)) + crash_with("Invalid skill category fed to calculate_remaining_skill_points!") + + var/total_points_available = skill_category.calculate_remaining_skill_points(GLOB.all_species[pref.species], pref.age) + /datum/category_item/player_setup_item/skills/OnTopic(href, href_list, user) if(href_list["skillinfo"]) var/singleton/skill/skill_to_show = GET_SINGLETON(text2path(href_list["skillinfo"])) @@ -233,7 +239,7 @@ var/singleton/skill/S = GET_SINGLETON(skill) skills_to_show += "[S.name] ([SPAN_DANGER(SSskills.skill_level_map[ED.skills[S.type]])])" dat += "[english_list(skills_to_show)].
" - dat += "
\[Select\]
" + dat += "
\[Select\]
" dat += "" education_win.set_content(dat) education_win.open() diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 81bf6a04539..f0b9f4214ab 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -111,6 +111,8 @@ var/list/preferences_datums = list() /// The character's skills list. JSON. var/list/skills = list() + /// The character's current spent skill points. Assoc list of SKILL_CATEGORY define to number of remaining skill points. + var/list/skill_points_remaining /// The character's psionics. JSON. var/list/psionics = list() diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm index 3c36b009ebb..ef821c6f054 100644 --- a/code/modules/mob/living/carbon/human/species/species.dm +++ b/code/modules/mob/living/carbon/human/species/species.dm @@ -346,6 +346,13 @@ ///Which species-unique robolimb types can this species take? var/list/valid_prosthetics + /// Modifiers for the available skill points for this species. Assoc list of SKILL_CATEGORY to number. + var/list/skill_points_modifiers = list( + SKILL_CATEGORY_EVERYDAY = 1, + SKILL_CATEGORY_OCCUPATIONAL = 1, + SKILL_CATEGORY_COMBAT = 1 + ) + //Sleeping stuff /** * Does this species sleep standing up? @@ -950,3 +957,15 @@ */ /datum/species/proc/sleep_examine_msg(var/mob/M) return SPAN_NOTICE("[M.get_pronoun("He")] appears to be fast asleep.\n") + +/** + * Gets a modifier for a skill category based on the character age or other species things. + * Must return a list with all three skill categories to a modifier (example: list(SKILL_CATEGORY_EVERYDAY = 1.5) ) + */ +/datum/species/proc/modify_skill_points(singleton/skill_category/skill_category, age) + var/list/skill_age_modifiers = list( + SKILL_CATEGORY_EVERYDAY = 1, + SKILL_CATEGORY_OCCUPATIONAL = 1, + SKILL_CATEGORY_COMBAT = 1 + ) + return skill_age_modifiers From afe2d2e42687f568e24cd28c6d089535eb35d287 Mon Sep 17 00:00:00 2001 From: Matt Atlas Date: Wed, 13 Nov 2024 12:49:01 +0100 Subject: [PATCH 15/16] seeking purpose --- code/datums/skills/_skill_categories.dm | 6 +- code/modules/background/origins/_origins.dm | 6 +- .../client/preference_setup/skills/skills.dm | 64 +++++++++++++++++-- 3 files changed, 67 insertions(+), 9 deletions(-) diff --git a/code/datums/skills/_skill_categories.dm b/code/datums/skills/_skill_categories.dm index 7c7903e2723..683a62477b1 100644 --- a/code/datums/skills/_skill_categories.dm +++ b/code/datums/skills/_skill_categories.dm @@ -8,9 +8,9 @@ /// The number of base points a character gets in this category. var/base_skill_points -/singleton/skill_category/proc/calculate_skill_points(datum/species/species, age, singleton/culture_item/culture, singleton/culture_item/origin) - var/species_modifier = species.modify_skill_points(src, age) - return base_skill_points * species_modifier +/singleton/skill_category/proc/calculate_skill_points(datum/species/species, age, singleton/origin_item/culture, singleton/origin_item/origin) + var/list/species_modifiers = species.modify_skill_points(src, age) + return base_skill_points * species_modifiers[name] /singleton/skill_category/everyday name = SKILL_CATEGORY_EVERYDAY diff --git a/code/modules/background/origins/_origins.dm b/code/modules/background/origins/_origins.dm index 4004d45da5a..d54a029677a 100644 --- a/code/modules/background/origins/_origins.dm +++ b/code/modules/background/origins/_origins.dm @@ -1,11 +1,15 @@ /singleton/origin_item var/name = "generic origin item" var/desc = DESC_PARENT - var/important_information //Big red text. Should only be used if not following it would incur a bwoink. + /// Big red text. Should only be used if not following it would incur a bwoink. + var/important_information + /// A list of the origin traits given by this culture item. var/list/origin_traits = list() /// Format for the following list: "Characters from this origin: [list entry], [list entry]." /// One list item per trait. var/list/origin_traits_descriptions = list() + /// A list of skills given by this origin. Assoc list of skill singleton type to level. + var/list/given_skills = list() /singleton/origin_item/culture name = "generic culture" diff --git a/code/modules/client/preference_setup/skills/skills.dm b/code/modules/client/preference_setup/skills/skills.dm index 1984fdc6e6b..8d938800c31 100644 --- a/code/modules/client/preference_setup/skills/skills.dm +++ b/code/modules/client/preference_setup/skills/skills.dm @@ -106,7 +106,7 @@ var/singleton/education/education = GET_SINGLETON(text2path(pref.education)) for(var/category in SSskills.skill_tree) var/singleton/skill_category/skill_category = category - dat += "" for(var/subcategory in SSskills.skill_tree[skill_category]) dat += "" @@ -116,18 +116,39 @@ . = JOINTEXT(dat) +/** + * Returns an HTML skill row. + */ /datum/category_item/player_setup_item/skills/proc/get_skill_row(singleton/skill/skill, singleton/education/education) var/list/dat = list() dat += "" dat += "" var/current_level = pref.skills[skill.type] - var/maximum_skill_level = skill.get_maximum_level(education) + var/maximum_skill_level = get_maximum_skill_level(skill, education) + for(var/i = SKILL_LEVEL_UNFAMILIAR, i <= SKILL_LEVEL_PROFESSIONAL, i++) dat += skill_to_button(skill, education, current_level, i, maximum_skill_level) return JOINTEXT(dat) +/datum/category_item/player_setup_item/skills/proc/get_maximum_skill_level(singleton/skill/skill, singleton/education/education) + var/base_maximum_level = skill.get_maximum_level(education) + var/remaining_skill_points = calculate_remaining_skill_points(GET_SINGLETON(skill.category)) + + for(var/skill_level = SKILL_LEVEL_UNFAMILIAR to base_maximum_level) + . = skill_level + + var/skill_cost = skill.get_cost(skill_level) + if(skill_cost > remaining_skill_points) + break + + skill_level++ + remaining_skill_points -= skill_cost + +/** + * Turns a skill into a dynamic button. + */ /datum/category_item/player_setup_item/skills/proc/skill_to_button(singleton/skill/skill, singleton/education/education, current_level, selection_level, maximum_skill_level) var/effective_level = selection_level if(effective_level <= 0) @@ -153,16 +174,46 @@ else return "" +/** + * Returns a button to set a skill in the skill UI. + */ /datum/category_item/player_setup_item/skills/proc/add_link(singleton/skill/skill, singleton/education/education, text, style, value) if(skill.get_maximum_level(education) >= value) return "[text]" return text +/** + * Returns the currently remaining skill points in a given category. + */ /datum/category_item/player_setup_item/skills/proc/calculate_remaining_skill_points(singleton/skill_category/skill_category) if(!istype(skill_category)) - crash_with("Invalid skill category fed to calculate_remaining_skill_points!") + crash_with("Invalid skill category [skill_category] fed to calculate_remaining_skill_points!") + + var/skill_points_remaining = skill_category.calculate_skill_points(GLOB.all_species[pref.species], pref.age, GET_SINGLETON(text2path(pref.culture)), GET_SINGLETON(text2path(pref.origin))) + var/current_points_used = get_used_skill_points_per_category(skill_category, GET_SINGLETON(text2path(pref.education))) + return skill_points_remaining - current_points_used + +/** + * Returns the amount of used skill points in a certain skill category, ignoring skills given by education. + */ +/datum/category_item/player_setup_item/skills/proc/get_used_skill_points_per_category(singleton/skill_category/skill_category, singleton/education/education) + if(!istype(skill_category)) + crash_with("Invalid skill category [skill_category] fed to get_used_skill_points_per_category!") + + if(!istype(education)) + crash_with("Invalid education [education] fed to get_used_skill_points_per_category!") + + . = 0 + for(var/skill_type in pref.skills) + var/singleton/skill/skill = GET_SINGLETON(skill_type) + if(skill.category != skill_category.type) + continue + + if(skill.type in education.skills) + continue + + . += skill.get_cost(pref.skills[skill.type]) - var/total_points_available = skill_category.calculate_remaining_skill_points(GLOB.all_species[pref.species], pref.age) /datum/category_item/player_setup_item/skills/OnTopic(href, href_list, user) if(href_list["skillinfo"]) @@ -229,6 +280,9 @@ return ..() +/** + * Opens a window showing details of an education. + */ /datum/category_item/player_setup_item/skills/proc/show_education_window(var/singleton/education/ED, var/topic_data, var/mob/user) var/datum/browser/education_win = new(user, topic_data, "Education Selection") var/dat = "
[ED.name]
" @@ -245,7 +299,7 @@ education_win.open() /** - * This proc finds and returns the first suitable education for the pref datum. + * Finds and returns the first suitable education for the pref datum. */ /datum/category_item/player_setup_item/skills/proc/find_suitable_education() var/list/singleton/education/education_list = GET_SINGLETON_SUBTYPE_MAP(/singleton/education) From 1b91fba6ad55e660359cefd99864ee747edb2aae Mon Sep 17 00:00:00 2001 From: Matt Atlas Date: Thu, 14 Nov 2024 23:05:01 +0100 Subject: [PATCH 16/16] sdsds --- code/modules/mob/mob.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 40a4f446d4f..adab58db08b 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -54,6 +54,8 @@ click_handlers.QdelClear() QDEL_NULL(click_handlers) + QDEL_NULL(skills) + return ..() /mob/New()
[skill_category.name] (X points remaining)" + dat += "
[skill_category.name] ([calculate_remaining_skill_points(skill_category)])" dat += "
[subcategory]
[skill.name][skill.name]
[skill_category.name] ([calculate_remaining_skill_points(skill_category)])" + dat += "
[skill_category.name] ([calculate_remaining_skill_points(skill_category)] points remaining)" dat += "
[subcategory]
[skill.name][span("Toohigh", "[button_label]")]