diff --git a/code/__DEFINES/~darkpack/jobs.dm b/code/__DEFINES/~darkpack/jobs.dm index dc0a0e29b8cb..774d10cb5542 100644 --- a/code/__DEFINES/~darkpack/jobs.dm +++ b/code/__DEFINES/~darkpack/jobs.dm @@ -269,7 +269,7 @@ DEFINE_BITFIELD(departments_bitflags, list( // Playtime tracking system, see jobs_exp.dm // weird one. -#define EXP_TYPE_KINDRED "Kindred" +#define EXP_TYPE_PLAYTIME "Playtime" #define EXP_TYPE_GAIA "Garou Nation" #define EXP_TYPE_SPIRAL "Pentex" #define EXP_TYPE_CAMARILLA "Camarilla Authorities" @@ -277,14 +277,16 @@ DEFINE_BITFIELD(departments_bitflags, list( #define EXP_TYPE_CHANTRY "Chantry" #define EXP_TYPE_ANARCH "Anarchs" #define EXP_TYPE_SABBAT "Sabbat" -#define EXP_TYPE_COUNCIL "Camarilla Primogen Council" #define EXP_TYPE_POLICE "Police Force" -#define EXP_TYPE_NATIONAL_SECURITY "National Security" #define EXP_TYPE_SERVICES "City Services" -// this prob should just say clinic genericly. -#define EXP_TYPE_CLINIC "St. John's Clinic" +#define EXP_TYPE_CLINIC "Clinic" #define EXP_TYPE_GIOVANNI "Giovanni Family" #define EXP_TYPE_MANOR "Voivodate" // APOC EDIT CHANGE - (Voivode) #define EXP_TYPE_CHURCH "Church" #define EXP_TYPE_CLUB "Strip Club" +#define EXP_TYPE_SOCIETY_OF_LEOPOLD "Society of Leopold" #define EXP_TYPE_OCEAN "Ocean 76" // APOC EDIT ADD - JOBS - Ocean 76 + +#define EXP_REQ_CRITICAL 720 +#define EXP_REQ_HEAD 360 +#define EXP_REQ_MINOR 180 diff --git a/code/__DEFINES/~darkpack/whitelist.dm b/code/__DEFINES/~darkpack/whitelist.dm new file mode 100644 index 000000000000..f6f9fdafc578 --- /dev/null +++ b/code/__DEFINES/~darkpack/whitelist.dm @@ -0,0 +1,2 @@ +#define WHITELIST_TRUSTED "trusted" +#define WHITELIST_TIMELIMITS "timelimits" diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 2a04edab3cd0..1b486aea6e03 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -226,7 +226,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) // DARKPACK EDIT ADD START - (patches alot of minor exploits from midround char sheet manipulation) if(!isnewplayer(usr) && ("[usr.client.prefs.default_slot]" in usr.persistent_client.joined_as_slots)) if(check_rights(R_ADMIN)) - to_chat(usr, span_warning("Swapping between character slots midround is unsupported and can lead to false writes to prefrences.")) + to_chat(usr, span_warning("Swapping between character slots midround is unsupported and can lead to false writes to preferences.")) else to_chat(usr, span_warning("You cannot be spawned in as this character to swap character slots. Return to the lobby to change characters.")) return FALSE diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 230da79e6db0..275e89daf94a 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -549,6 +549,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car stack_trace("remove_current_slot() being called when there are no slots to go to, the client should prevent this") return + discipline_levels = list() // TFN EDIT ADD - remove disciplines when removing a character slot savefile.remove_entry("character[default_slot]") tainted_character_profiles = TRUE switch_to_slot(closest_slot) diff --git a/code/modules/jobs/job_exp.dm b/code/modules/jobs/job_exp.dm index 2dfe36b6ed9a..7dd6d068ff2a 100644 --- a/code/modules/jobs/job_exp.dm +++ b/code/modules/jobs/job_exp.dm @@ -12,6 +12,10 @@ GLOBAL_PROTECT(exp_to_update) return 0 if(!IS_XP_LOCKED(src)) return 0 + // DARKPACK EDIT ADD START - (whitelist) + if(C.prefs?.has_whitelist(WHITELIST_TIMELIMITS)) + return 0 + // DARKPACK EDIT ADD END if(CONFIG_GET(flag/use_exp_restrictions_admin_bypass) && check_rights_for(C,R_ADMIN)) return 0 var/isexempt = C.prefs.db_flags & DB_FLAG_EXEMPT diff --git a/config/darkpack_config.txt b/config/darkpack_config.txt index e7839be05960..651d157f9361 100644 --- a/config/darkpack_config.txt +++ b/config/darkpack_config.txt @@ -51,6 +51,17 @@ ROUNDSTART_SPLATS splat_kinfolk ROUNDSTART_SPLATS splat_garou ROUNDSTART_SPLATS splat_corax +#WHITELISTED_SPLATS splat_garou +#WHITELISTED_SPLATS splat_corax + +#WHITELISTED_CLANS baali +#WHITELISTED_CLANS healer_salubri +#WHITELISTED_CLANS warrior_salubri +#WHITELISTED_CLANS true_brujah +#WHITELISTED_CLANS cappadocian +#WHITELISTED_CLANS harbinger + + ## If dead people and ghosts can LOOC to people who are alive. DISABLE_GHOST_LOOC diff --git a/modular_darkpack/master_files/code/modules/client/preferences_savefile.dm b/modular_darkpack/master_files/code/modules/client/preferences_savefile.dm index a1eb3d9fe5f2..69603ead4cdf 100644 --- a/modular_darkpack/master_files/code/modules/client/preferences_savefile.dm +++ b/modular_darkpack/master_files/code/modules/client/preferences_savefile.dm @@ -7,16 +7,49 @@ var/list/discipline_levels = list() // Alternative job titles stored in preferences. Assoc list, ie. alt_job_titles["Scientist"] = "Cytologist" var/list/alt_job_titles = list() - /// Whether this player is whitelisted to bypass discipline sheet validation limits + /// Whether this player is whitelisted to bypass discipline sheet validation limits /// LEGACY var/discipline_trusted = FALSE /datum/preferences/load_preferences() discipline_trusted = savefile.get_entry("discipline_trusted", FALSE) // deserialization and its consequences + + // WHITELIST + var/list/saved = savefile.get_entry("player_whitelists") + if(isnull(saved) || !islist(saved) || !length(saved)) + player_whitelists = get_default_player_whitelists().Copy() + else + player_whitelists = saved + + var/alist/defaults = get_default_player_whitelists() + for(var/key, bool in defaults) + if(!(key in player_whitelists)) + to_chat(parent, span_boldnotice("New whitelist key added to whitelists: [key] [bool ? "TRUE": "FALSE"].")) + player_whitelists[key] = bool + + for(var/key in saved) + if(!(key in defaults)) + to_chat(parent, span_boldnotice("Bad whitelist key has been removed from whitelists")) + player_whitelists[key] = null + + if(discipline_trusted && !player_whitelists[WHITELIST_TRUSTED]) // backwards compatibility + player_whitelists[WHITELIST_TRUSTED] = TRUE + if(!isnull(parent)) + to_chat(parent, span_boldnotice("Great news! Your existing trusted status was successfully migrated to the new splat whitelist system.")) + + discipline_trusted = player_whitelists[WHITELIST_TRUSTED] + // WHITELIST + . = ..() /datum/preferences/save_preferences() savefile.set_entry("discipline_trusted", discipline_trusted) // since existing load/save is per character, save and load it from a level above that + + // WHITELIST + if(!isnull(player_whitelists)) + savefile.set_entry("player_whitelists", player_whitelists) + // WHITELIST + . = ..() /datum/preferences/load_character(slot) diff --git a/modular_darkpack/modules/jobs/code/_departments.dm b/modular_darkpack/modules/jobs/code/_departments.dm index 55420e018485..58c63b743323 100644 --- a/modular_darkpack/modules/jobs/code/_departments.dm +++ b/modular_darkpack/modules/jobs/code/_departments.dm @@ -126,6 +126,7 @@ /datum/job_department/city_services department_name = DEPARTMENT_CITY_SERVICES department_bitflags = DEPARTMENT_BITFLAG_CITY_SERVICES + department_experience_type = EXP_TYPE_SERVICES display_order = 14 // give its own ui color? @@ -134,8 +135,7 @@ department_name = DEPARTMENT_SOCIETY_OF_LEOPOLD department_bitflags = DEPARTMENT_BITFLAG_SOCIETY_OF_LEOPOLD department_head = /datum/job/vampire/abbe - // why are you reusing the church xp. - department_experience_type = EXP_TYPE_CHURCH + department_experience_type = EXP_TYPE_SOCIETY_OF_LEOPOLD display_order = 15 ui_color = "#fff022" diff --git a/modular_darkpack/modules/jobs/code/_jobs.dm b/modular_darkpack/modules/jobs/code/_jobs.dm index f31c0912168a..9195476f531c 100644 --- a/modular_darkpack/modules/jobs/code/_jobs.dm +++ b/modular_darkpack/modules/jobs/code/_jobs.dm @@ -108,6 +108,11 @@ ((guestbook_flags & GUESTBOOK_DEPARTMENT) && length(common_departments))) spawned.mind.guestbook.add_guest(spawned, player_mob, player_mob.mind.name, player_mob.mind.name, silent = TRUE) +/datum/job/vampire + abstract_type = /datum/job/vampire + exp_required_type = EXP_TYPE_PLAYTIME + exp_granted_type = EXP_TYPE_PLAYTIME + /** * This type is used to indicate a lack of a job. * The mind variable assigned_role will point here by default. diff --git a/modular_darkpack/modules/jobs/code/anarchs/baron.dm b/modular_darkpack/modules/jobs/code/anarchs/baron.dm index ca815fab1478..19efda1c8d1b 100644 --- a/modular_darkpack/modules/jobs/code/anarchs/baron.dm +++ b/modular_darkpack/modules/jobs/code/anarchs/baron.dm @@ -13,6 +13,9 @@ /datum/job_department/anarch, ) + exp_requirements = EXP_REQ_HEAD + exp_required_type_department = EXP_TYPE_ANARCH + known_contacts = list("Bouncer", "Emissary", "Sweeper", "Prince", "Sheriff") allowed_clans = list(VAMPIRE_CLAN_DAUGHTERS_OF_CACOPHONY, VAMPIRE_CLAN_BAALI, VAMPIRE_CLAN_BANU_HAQIM, VAMPIRE_CLAN_CAITIFF, VAMPIRE_CLAN_TRUE_BRUJAH, VAMPIRE_CLAN_BRUJAH, VAMPIRE_CLAN_NOSFERATU, VAMPIRE_CLAN_GANGREL, VAMPIRE_CLAN_CITY_GANGREL, VAMPIRE_CLAN_TOREADOR, VAMPIRE_CLAN_MALKAVIAN, VAMPIRE_CLAN_VENTRUE, VAMPIRE_CLAN_LASOMBRA, VAMPIRE_CLAN_GARGOYLE, VAMPIRE_CLAN_SETITE, VAMPIRE_CLAN_SAMEDI, VAMPIRE_CLAN_NAGARAJA) allowed_splats = list(SPLAT_KINDRED) diff --git a/modular_darkpack/modules/jobs/code/camarilla/harpy.dm b/modular_darkpack/modules/jobs/code/camarilla/harpy.dm index dc9c5d7c338d..810fb480abd1 100644 --- a/modular_darkpack/modules/jobs/code/camarilla/harpy.dm +++ b/modular_darkpack/modules/jobs/code/camarilla/harpy.dm @@ -9,10 +9,10 @@ config_tag = "HARPY" req_admin_notify = 1 minimal_player_age = 10 - exp_requirements = 180 - exp_required_type = EXP_TYPE_CAMARILLA - exp_required_type_department = EXP_TYPE_CAMARILLA - exp_granted_type = EXP_TYPE_CAMARILLA + + // exp_requirements = EXP_REQ_MINOR + // exp_required_type_department = EXP_TYPE_CAMARILLA + job_flags = CITY_JOB_FLAGS outfit = /datum/outfit/job/vampire/harpy diff --git a/modular_darkpack/modules/jobs/code/camarilla/hound.dm b/modular_darkpack/modules/jobs/code/camarilla/hound.dm index 0f980d846e77..908827565bfb 100644 --- a/modular_darkpack/modules/jobs/code/camarilla/hound.dm +++ b/modular_darkpack/modules/jobs/code/camarilla/hound.dm @@ -7,10 +7,6 @@ spawn_positions = 7 supervisors = SUPERVISOR_SHERIFF minimal_player_age = 7 - exp_requirements = 20 - exp_required_type = EXP_TYPE_CAMARILLA - exp_required_type_department = EXP_TYPE_CAMARILLA - exp_granted_type = EXP_TYPE_CAMARILLA config_tag = "HOUND" job_flags = CITY_JOB_FLAGS outfit = /datum/outfit/job/vampire/hound diff --git a/modular_darkpack/modules/jobs/code/camarilla/primogens/banu_haqim.dm b/modular_darkpack/modules/jobs/code/camarilla/primogens/banu_haqim.dm index 4816a28c0b25..37ed807f4b7a 100644 --- a/modular_darkpack/modules/jobs/code/camarilla/primogens/banu_haqim.dm +++ b/modular_darkpack/modules/jobs/code/camarilla/primogens/banu_haqim.dm @@ -8,10 +8,8 @@ supervisors = SUPERVISOR_TRADITIONS req_admin_notify = 1 minimal_player_age = 14 - exp_requirements = 180 - exp_required_type = EXP_TYPE_CAMARILLA - exp_required_type_department = EXP_TYPE_CAMARILLA - exp_granted_type = EXP_TYPE_CAMARILLA + exp_requirements = EXP_REQ_HEAD + // exp_required_type_department = EXP_TYPE_CAMARILLA config_tag = "PRIMOGEN_BANU_HAQIM" job_flags = CITY_JOB_FLAGS outfit = /datum/outfit/job/vampire/banuprim diff --git a/modular_darkpack/modules/jobs/code/camarilla/primogens/lasombra.dm b/modular_darkpack/modules/jobs/code/camarilla/primogens/lasombra.dm index d5090b7b1ad3..c75d82cfcf27 100644 --- a/modular_darkpack/modules/jobs/code/camarilla/primogens/lasombra.dm +++ b/modular_darkpack/modules/jobs/code/camarilla/primogens/lasombra.dm @@ -8,10 +8,8 @@ supervisors = SUPERVISOR_TRADITIONS req_admin_notify = 1 minimal_player_age = 14 - exp_requirements = 180 - exp_required_type = EXP_TYPE_CAMARILLA - exp_required_type_department = EXP_TYPE_CAMARILLA - exp_granted_type = EXP_TYPE_CAMARILLA + exp_requirements = EXP_REQ_HEAD + // exp_required_type_department = EXP_TYPE_CAMARILLA config_tag = "PRIMOGEN_LASOMBRA" job_flags = CITY_JOB_FLAGS outfit = /datum/outfit/job/vampire/lasombraprim diff --git a/modular_darkpack/modules/jobs/code/camarilla/primogens/malkavian.dm b/modular_darkpack/modules/jobs/code/camarilla/primogens/malkavian.dm index 174c2c996329..9995de43036c 100644 --- a/modular_darkpack/modules/jobs/code/camarilla/primogens/malkavian.dm +++ b/modular_darkpack/modules/jobs/code/camarilla/primogens/malkavian.dm @@ -8,10 +8,8 @@ supervisors = SUPERVISOR_TRADITIONS req_admin_notify = 1 minimal_player_age = 14 - exp_requirements = 180 - exp_required_type = EXP_TYPE_CAMARILLA - exp_required_type_department = EXP_TYPE_CAMARILLA - exp_granted_type = EXP_TYPE_CAMARILLA + exp_requirements = EXP_REQ_HEAD + // exp_required_type_department = EXP_TYPE_CAMARILLA config_tag = "PRIMOGEN_MALKAVIAN" job_flags = CITY_JOB_FLAGS outfit = /datum/outfit/job/vampire/malkav diff --git a/modular_darkpack/modules/jobs/code/camarilla/primogens/nosferatu.dm b/modular_darkpack/modules/jobs/code/camarilla/primogens/nosferatu.dm index 9f5d30d84860..95bad802d7bd 100644 --- a/modular_darkpack/modules/jobs/code/camarilla/primogens/nosferatu.dm +++ b/modular_darkpack/modules/jobs/code/camarilla/primogens/nosferatu.dm @@ -8,10 +8,8 @@ supervisors = SUPERVISOR_TRADITIONS req_admin_notify = 1 minimal_player_age = 14 - exp_requirements = 180 - exp_required_type = EXP_TYPE_CAMARILLA - exp_required_type_department = EXP_TYPE_CAMARILLA - exp_granted_type = EXP_TYPE_CAMARILLA + exp_requirements = EXP_REQ_HEAD + // exp_required_type_department = EXP_TYPE_CAMARILLA config_tag = "PRIMOGEN_NOSFERATU" job_flags = CITY_JOB_FLAGS outfit = /datum/outfit/job/vampire/nosferatu diff --git a/modular_darkpack/modules/jobs/code/camarilla/primogens/toreador.dm b/modular_darkpack/modules/jobs/code/camarilla/primogens/toreador.dm index b9ccff0ea6e2..b8200a8c7ceb 100644 --- a/modular_darkpack/modules/jobs/code/camarilla/primogens/toreador.dm +++ b/modular_darkpack/modules/jobs/code/camarilla/primogens/toreador.dm @@ -8,10 +8,8 @@ supervisors = SUPERVISOR_TRADITIONS req_admin_notify = 1 minimal_player_age = 14 - exp_requirements = 180 - exp_required_type = EXP_TYPE_CAMARILLA - exp_required_type_department = EXP_TYPE_CAMARILLA - exp_granted_type = EXP_TYPE_CAMARILLA + exp_requirements = EXP_REQ_HEAD + // exp_required_type_department = EXP_TYPE_CAMARILLA config_tag = "PRIMOGEN_TOREADOR" job_flags = CITY_JOB_FLAGS outfit = /datum/outfit/job/vampire/toreador diff --git a/modular_darkpack/modules/jobs/code/camarilla/primogens/ventrue.dm b/modular_darkpack/modules/jobs/code/camarilla/primogens/ventrue.dm index 2a4ae75592e8..4f703adda681 100644 --- a/modular_darkpack/modules/jobs/code/camarilla/primogens/ventrue.dm +++ b/modular_darkpack/modules/jobs/code/camarilla/primogens/ventrue.dm @@ -8,10 +8,8 @@ supervisors = SUPERVISOR_TRADITIONS req_admin_notify = 1 minimal_player_age = 14 - exp_requirements = 180 - exp_required_type = EXP_TYPE_CAMARILLA - exp_required_type_department = EXP_TYPE_CAMARILLA - exp_granted_type = EXP_TYPE_CAMARILLA + exp_requirements = EXP_REQ_HEAD + // exp_required_type_department = EXP_TYPE_CAMARILLA config_tag = "PRIMOGEN_VENTRUE" job_flags = CITY_JOB_FLAGS outfit = /datum/outfit/job/vampire/ventrue diff --git a/modular_darkpack/modules/jobs/code/camarilla/prince.dm b/modular_darkpack/modules/jobs/code/camarilla/prince.dm index e86b3edde072..2ff3bd873014 100644 --- a/modular_darkpack/modules/jobs/code/camarilla/prince.dm +++ b/modular_darkpack/modules/jobs/code/camarilla/prince.dm @@ -8,10 +8,8 @@ supervisors = SUPERVISOR_TRADITIONS req_admin_notify = 1 minimal_player_age = 14 - exp_requirements = 180 - exp_required_type = EXP_TYPE_CAMARILLA + exp_requirements = EXP_REQ_CRITICAL exp_required_type_department = EXP_TYPE_CAMARILLA - exp_granted_type = EXP_TYPE_CAMARILLA config_tag = "PRINCE" job_flags = CITY_JOB_FLAGS outfit = /datum/outfit/job/vampire/prince diff --git a/modular_darkpack/modules/jobs/code/camarilla/seneschal.dm b/modular_darkpack/modules/jobs/code/camarilla/seneschal.dm index b4d93e481a52..c0b8f64352ee 100644 --- a/modular_darkpack/modules/jobs/code/camarilla/seneschal.dm +++ b/modular_darkpack/modules/jobs/code/camarilla/seneschal.dm @@ -8,10 +8,8 @@ supervisors = SUPERVISOR_PRINCE req_admin_notify = 1 minimal_player_age = 10 - exp_requirements = 180 - exp_required_type = EXP_TYPE_CAMARILLA - exp_required_type_department = EXP_TYPE_CAMARILLA - exp_granted_type = EXP_TYPE_CAMARILLA + exp_requirements = EXP_REQ_MINOR + // exp_required_type_department = EXP_TYPE_CAMARILLA config_tag = "SENESCHAL" job_flags = CITY_JOB_FLAGS outfit = /datum/outfit/job/vampire/clerk diff --git a/modular_darkpack/modules/jobs/code/camarilla/sheriff.dm b/modular_darkpack/modules/jobs/code/camarilla/sheriff.dm index ad4bd4741b58..a9da317b065e 100644 --- a/modular_darkpack/modules/jobs/code/camarilla/sheriff.dm +++ b/modular_darkpack/modules/jobs/code/camarilla/sheriff.dm @@ -8,10 +8,8 @@ supervisors = SUPERVISOR_PRINCE req_admin_notify = 1 minimal_player_age = 14 - exp_requirements = 120 - exp_required_type = EXP_TYPE_CAMARILLA - exp_required_type_department = EXP_TYPE_CAMARILLA - exp_granted_type = EXP_TYPE_CAMARILLA + exp_requirements = EXP_REQ_MINOR + // exp_required_type_department = EXP_TYPE_CAMARILLA config_tag = "SHERIFF" job_flags = CITY_JOB_FLAGS outfit = /datum/outfit/job/vampire/sheriff diff --git a/modular_darkpack/modules/jobs/code/camarilla/tower_employee.dm b/modular_darkpack/modules/jobs/code/camarilla/tower_employee.dm index 30112046d41e..11d03330c983 100644 --- a/modular_darkpack/modules/jobs/code/camarilla/tower_employee.dm +++ b/modular_darkpack/modules/jobs/code/camarilla/tower_employee.dm @@ -4,7 +4,6 @@ total_positions = 4 spawn_positions = 4 supervisors = SUPERVISOR_SENESCHAL_PUBLIC - exp_granted_type = EXP_TYPE_CAMARILLA config_tag = "TOWER_EMPLOYEE" outfit = /datum/outfit/job/vampire/towerwork job_flags = CITY_JOB_FLAGS diff --git a/modular_darkpack/modules/jobs/code/clinic/director.dm b/modular_darkpack/modules/jobs/code/clinic/director.dm index 4229413981c9..64b177dd80a9 100644 --- a/modular_darkpack/modules/jobs/code/clinic/director.dm +++ b/modular_darkpack/modules/jobs/code/clinic/director.dm @@ -4,10 +4,13 @@ total_positions = 1 spawn_positions = 1 supervisors = "the Hospital Administrator" - exp_required_type_department = EXP_TYPE_CLINIC config_tag = "CLINIC_DIRECTOR" outfit = /datum/outfit/job/vampire/clinic_director job_flags = CITY_JOB_FLAGS + + exp_required_type_department = EXP_TYPE_CLINIC + exp_requirements = EXP_REQ_HEAD + display_order = JOB_DISPLAY_ORDER_CLINICS_DIRECTOR departments_list = list( /datum/job_department/clinic, diff --git a/modular_darkpack/modules/jobs/code/clinic/doctor.dm b/modular_darkpack/modules/jobs/code/clinic/doctor.dm index 7f1c0e083e9c..a523074d1916 100644 --- a/modular_darkpack/modules/jobs/code/clinic/doctor.dm +++ b/modular_darkpack/modules/jobs/code/clinic/doctor.dm @@ -4,7 +4,7 @@ total_positions = 4 spawn_positions = 4 supervisors = "the Clinic Director" - exp_required_type_department = EXP_TYPE_CLINIC + // exp_required_type_department = EXP_TYPE_CLINIC config_tag = "DOCTOR" job_flags = CITY_JOB_FLAGS outfit = /datum/outfit/job/vampire/clinic_doctor diff --git a/modular_darkpack/modules/jobs/code/garou/councillor.dm b/modular_darkpack/modules/jobs/code/garou/councillor.dm index 9bfc9dea083f..8c62ceb181dc 100644 --- a/modular_darkpack/modules/jobs/code/garou/councillor.dm +++ b/modular_darkpack/modules/jobs/code/garou/councillor.dm @@ -8,10 +8,8 @@ supervisors = SUPERVISOR_LITANY req_admin_notify = 1 minimal_player_age = 25 - exp_requirements = 180 - exp_required_type = EXP_TYPE_GAIA + exp_requirements = EXP_REQ_HEAD exp_required_type_department = EXP_TYPE_GAIA - exp_granted_type = EXP_TYPE_GAIA config_tag = "COUNCILLOR" job_flags = CITY_JOB_FLAGS outfit = /datum/outfit/job/vampire/councillor diff --git a/modular_darkpack/modules/jobs/code/garou/guardian.dm b/modular_darkpack/modules/jobs/code/garou/guardian.dm index 23b2d8c18175..31ce42d50368 100644 --- a/modular_darkpack/modules/jobs/code/garou/guardian.dm +++ b/modular_darkpack/modules/jobs/code/garou/guardian.dm @@ -8,10 +8,7 @@ supervisors = /datum/job/vampire/warder req_admin_notify = 1 minimal_player_age = 25 - exp_requirements = 50 - exp_required_type = EXP_TYPE_GAIA exp_required_type_department = EXP_TYPE_GAIA - exp_granted_type = EXP_TYPE_GAIA config_tag = "GUARDIAN" job_flags = CITY_JOB_FLAGS outfit = /datum/outfit/job/vampire/guardian diff --git a/modular_darkpack/modules/jobs/code/garou/truthcatcher.dm b/modular_darkpack/modules/jobs/code/garou/truthcatcher.dm index c0f610d7e326..724c246309ce 100644 --- a/modular_darkpack/modules/jobs/code/garou/truthcatcher.dm +++ b/modular_darkpack/modules/jobs/code/garou/truthcatcher.dm @@ -8,10 +8,8 @@ supervisors = SUPERVISOR_LITANY req_admin_notify = 1 minimal_player_age = 25 - exp_requirements = 100 - exp_required_type = EXP_TYPE_GAIA + exp_requirements = EXP_REQ_MINOR exp_required_type_department = EXP_TYPE_GAIA - exp_granted_type = EXP_TYPE_GAIA config_tag = "TRUTHCATCHER" job_flags = CITY_JOB_FLAGS outfit = /datum/outfit/job/vampire/trutchcatcher diff --git a/modular_darkpack/modules/jobs/code/garou/warder.dm b/modular_darkpack/modules/jobs/code/garou/warder.dm index 5d991a16154f..68160f297695 100644 --- a/modular_darkpack/modules/jobs/code/garou/warder.dm +++ b/modular_darkpack/modules/jobs/code/garou/warder.dm @@ -8,10 +8,8 @@ supervisors = SUPERVISOR_LITANY req_admin_notify = 1 minimal_player_age = 25 - exp_requirements = 100 - exp_required_type = EXP_TYPE_GAIA + exp_requirements = EXP_REQ_MINOR exp_required_type_department = EXP_TYPE_GAIA - exp_granted_type = EXP_TYPE_GAIA config_tag = "WARDER" job_flags = CITY_JOB_FLAGS outfit = /datum/outfit/job/vampire/warder diff --git a/modular_darkpack/modules/jobs/code/garou/wyrmfoe.dm b/modular_darkpack/modules/jobs/code/garou/wyrmfoe.dm index 30091dc9cb7d..6f339bb2416e 100644 --- a/modular_darkpack/modules/jobs/code/garou/wyrmfoe.dm +++ b/modular_darkpack/modules/jobs/code/garou/wyrmfoe.dm @@ -8,10 +8,8 @@ supervisors = SUPERVISOR_LITANY req_admin_notify = 1 minimal_player_age = 25 - exp_requirements = 100 - exp_required_type = EXP_TYPE_GAIA + exp_requirements = EXP_REQ_MINOR exp_required_type_department = EXP_TYPE_GAIA - exp_granted_type = EXP_TYPE_GAIA config_tag = "WYRMFOE" job_flags = CITY_JOB_FLAGS outfit = /datum/outfit/job/vampire/wyrmfoe diff --git a/modular_darkpack/modules/jobs/code/giovanni/capo.dm b/modular_darkpack/modules/jobs/code/giovanni/capo.dm index 589e2881f17d..ada208f2e5b8 100644 --- a/modular_darkpack/modules/jobs/code/giovanni/capo.dm +++ b/modular_darkpack/modules/jobs/code/giovanni/capo.dm @@ -8,11 +8,13 @@ outfit = /datum/outfit/job/vampire/capo job_flags = CITY_JOB_FLAGS display_order = 1 - exp_required_type_department = EXP_TYPE_GIOVANNI departments_list = list( /datum/job_department/giovanni, ) + exp_required_type_department = EXP_TYPE_GIOVANNI + exp_requirements = EXP_REQ_HEAD + description = "Pure blood runs through your veins and, with it, old power. Throughout your long life you have learnt to hold onto two things and never let go: money, and family." minimum_masquerade = 0 allowed_splats = list(SPLAT_KINDRED) diff --git a/modular_darkpack/modules/jobs/code/hunters/abbe.dm b/modular_darkpack/modules/jobs/code/hunters/abbe.dm index f7c8c7a3d98d..4932d33307ee 100644 --- a/modular_darkpack/modules/jobs/code/hunters/abbe.dm +++ b/modular_darkpack/modules/jobs/code/hunters/abbe.dm @@ -11,6 +11,9 @@ job_flags = CITY_JOB_FLAGS outfit = /datum/outfit/job/vampire/abbe + exp_requirements = EXP_REQ_HEAD + exp_required_type_department = EXP_TYPE_SOCIETY_OF_LEOPOLD + display_order = JOB_DISPLAY_ORDER_ABBE departments_list = list( /datum/job_department/society_of_leopold, diff --git a/modular_darkpack/modules/jobs/code/miscelllaneous/citizen.dm b/modular_darkpack/modules/jobs/code/miscelllaneous/citizen.dm index 1eecac4916c9..b4a0832b0700 100644 --- a/modular_darkpack/modules/jobs/code/miscelllaneous/citizen.dm +++ b/modular_darkpack/modules/jobs/code/miscelllaneous/citizen.dm @@ -5,7 +5,6 @@ total_positions = -1 spawn_positions = -1 outfit = /datum/outfit/job/vampire/citizen - exp_granted_type = EXP_TYPE_KINDRED config_tag = "CITIZEN" display_order = JOB_DISPLAY_ORDER_CITIZEN departments_list = list( diff --git a/modular_darkpack/modules/jobs/code/miscelllaneous/red_news.dm b/modular_darkpack/modules/jobs/code/miscelllaneous/red_news.dm index 434bbe972bc3..5bc7c67718c4 100644 --- a/modular_darkpack/modules/jobs/code/miscelllaneous/red_news.dm +++ b/modular_darkpack/modules/jobs/code/miscelllaneous/red_news.dm @@ -5,7 +5,6 @@ total_positions = 2 spawn_positions = 2 outfit = /datum/outfit/job/vampire/red_news_reporter - exp_granted_type = EXP_TYPE_SPIRAL config_tag = "RED_NEWS_REPORTER" display_order = JOB_DISPLAY_ORDER_RED_NEWS_REPORTER departments_list = list( diff --git a/modular_darkpack/modules/jobs/code/pentex/affairs.dm b/modular_darkpack/modules/jobs/code/pentex/affairs.dm index eb7cbfb4dffc..853354471ac6 100644 --- a/modular_darkpack/modules/jobs/code/pentex/affairs.dm +++ b/modular_darkpack/modules/jobs/code/pentex/affairs.dm @@ -8,10 +8,8 @@ supervisors = "the Board and the Branch Lead" req_admin_notify = 1 minimal_player_age = 25 - exp_requirements = 150 - exp_required_type = EXP_TYPE_SPIRAL + exp_requirements = EXP_REQ_MINOR exp_required_type_department = EXP_TYPE_SPIRAL - exp_granted_type = EXP_TYPE_SPIRAL config_tag = "PENTEX_AFFAIRS" job_flags = CITY_JOB_FLAGS outfit = /datum/outfit/job/vampire/affairs diff --git a/modular_darkpack/modules/jobs/code/pentex/branch_lead.dm b/modular_darkpack/modules/jobs/code/pentex/branch_lead.dm index 7a56cc10c5c8..ed117ef12ceb 100644 --- a/modular_darkpack/modules/jobs/code/pentex/branch_lead.dm +++ b/modular_darkpack/modules/jobs/code/pentex/branch_lead.dm @@ -8,10 +8,8 @@ supervisors = "the Board" req_admin_notify = 1 minimal_player_age = 25 - exp_requirements = 180 - exp_required_type = EXP_TYPE_SPIRAL + exp_requirements = EXP_REQ_HEAD exp_required_type_department = EXP_TYPE_SPIRAL - exp_granted_type = EXP_TYPE_SPIRAL config_tag = "PENTEX_BRANCH_LEAD" job_flags = CITY_JOB_FLAGS outfit = /datum/outfit/job/vampire/branch_lead diff --git a/modular_darkpack/modules/jobs/code/pentex/employee.dm b/modular_darkpack/modules/jobs/code/pentex/employee.dm index c0cd69ff0cf8..9d6045c14447 100644 --- a/modular_darkpack/modules/jobs/code/pentex/employee.dm +++ b/modular_darkpack/modules/jobs/code/pentex/employee.dm @@ -8,10 +8,7 @@ supervisors = "the Board and the Branch Lead" req_admin_notify = 1 minimal_player_age = 25 - exp_requirements = 50 - exp_required_type = EXP_TYPE_SPIRAL exp_required_type_department = EXP_TYPE_SPIRAL - exp_granted_type = EXP_TYPE_SPIRAL config_tag = "PENTEX_EMPLOYEE" job_flags = CITY_JOB_FLAGS outfit = /datum/outfit/job/vampire/employee diff --git a/modular_darkpack/modules/jobs/code/pentex/executive.dm b/modular_darkpack/modules/jobs/code/pentex/executive.dm index 6f4cfc3bdca8..98c2578c3036 100644 --- a/modular_darkpack/modules/jobs/code/pentex/executive.dm +++ b/modular_darkpack/modules/jobs/code/pentex/executive.dm @@ -8,10 +8,8 @@ supervisors = "the Board and the Branch Lead" req_admin_notify = 1 minimal_player_age = 25 - exp_requirements = 150 - exp_required_type = EXP_TYPE_SPIRAL + exp_requirements = EXP_REQ_HEAD exp_required_type_department = EXP_TYPE_SPIRAL - exp_granted_type = EXP_TYPE_SPIRAL config_tag = "PENTEX_EXECUTIVE" job_flags = CITY_JOB_FLAGS outfit = /datum/outfit/job/vampire/executive diff --git a/modular_darkpack/modules/jobs/code/pentex/sec.dm b/modular_darkpack/modules/jobs/code/pentex/sec.dm index 75364f7805d0..461776fe51c4 100644 --- a/modular_darkpack/modules/jobs/code/pentex/sec.dm +++ b/modular_darkpack/modules/jobs/code/pentex/sec.dm @@ -8,10 +8,8 @@ supervisors = "the Board, Branch Lead, and Chief of Security" req_admin_notify = 1 minimal_player_age = 25 - exp_requirements = 100 - exp_required_type = EXP_TYPE_SPIRAL - exp_required_type_department = EXP_TYPE_SPIRAL - exp_granted_type = EXP_TYPE_SPIRAL + exp_requirements = EXP_REQ_MINOR + // exp_required_type_department = EXP_TYPE_SPIRAL config_tag = "PENTEX_SEC" job_flags = CITY_JOB_FLAGS outfit = /datum/outfit/job/vampire/pentex_sec diff --git a/modular_darkpack/modules/jobs/code/pentex/secchief.dm b/modular_darkpack/modules/jobs/code/pentex/secchief.dm index fa07dde36ab6..b587ac474f4c 100644 --- a/modular_darkpack/modules/jobs/code/pentex/secchief.dm +++ b/modular_darkpack/modules/jobs/code/pentex/secchief.dm @@ -8,10 +8,8 @@ supervisors = "the Board and the Branch Lead" req_admin_notify = 1 minimal_player_age = 25 - exp_requirements = 150 - exp_required_type = EXP_TYPE_SPIRAL + exp_requirements = EXP_REQ_MINOR exp_required_type_department = EXP_TYPE_SPIRAL - exp_granted_type = EXP_TYPE_SPIRAL config_tag = "PENTEX_SECCHIEF" job_flags = CITY_JOB_FLAGS outfit = /datum/outfit/job/vampire/secchief diff --git a/modular_darkpack/modules/jobs/code/police/captain.dm b/modular_darkpack/modules/jobs/code/police/captain.dm index f3a4db76409b..aaa3ba5793c8 100644 --- a/modular_darkpack/modules/jobs/code/police/captain.dm +++ b/modular_darkpack/modules/jobs/code/police/captain.dm @@ -13,6 +13,8 @@ /datum/job_department/police, ) + exp_requirements = EXP_REQ_HEAD + allowed_splats = list(SPLAT_NONE) description = "Underpaid, overworked, and understrength. Do your best to keep the order in " + CITY_NAME + ". Keep the officers in line." diff --git a/modular_darkpack/modules/jobs/code/police/fbi.dm b/modular_darkpack/modules/jobs/code/police/fbi.dm index 75b247a8b663..441954bab9ce 100644 --- a/modular_darkpack/modules/jobs/code/police/fbi.dm +++ b/modular_darkpack/modules/jobs/code/police/fbi.dm @@ -8,7 +8,6 @@ outfit = /datum/outfit/job/vampire/fbi job_flags = CITY_JOB_FLAGS display_order = JOB_DISPLAY_ORDER_FBI - exp_required_type_department = EXP_TYPE_NATIONAL_SECURITY departments_list = list( /datum/job_department/police, ) diff --git a/modular_darkpack/modules/jobs/code/police/police.dm b/modular_darkpack/modules/jobs/code/police/police.dm index 11e2fb127123..1961fca3a106 100644 --- a/modular_darkpack/modules/jobs/code/police/police.dm +++ b/modular_darkpack/modules/jobs/code/police/police.dm @@ -8,7 +8,7 @@ outfit = /datum/outfit/job/vampire/police_officer job_flags = CITY_JOB_FLAGS display_order = JOB_DISPLAY_ORDER_POLICE - exp_required_type_department = EXP_TYPE_POLICE + // exp_required_type_department = EXP_TYPE_POLICE departments_list = list( /datum/job_department/police, ) diff --git a/modular_darkpack/modules/jobs/code/police/sergeant.dm b/modular_darkpack/modules/jobs/code/police/sergeant.dm index f88bb12b754a..c61cddabcba8 100644 --- a/modular_darkpack/modules/jobs/code/police/sergeant.dm +++ b/modular_darkpack/modules/jobs/code/police/sergeant.dm @@ -8,7 +8,8 @@ outfit = /datum/outfit/job/vampire/police_sergeant job_flags = CITY_JOB_FLAGS display_order = JOB_DISPLAY_ORDER_POLICE_SERGEANT - exp_required_type_department = EXP_TYPE_POLICE + exp_requirements = EXP_REQ_MINOR + // exp_required_type_department = EXP_TYPE_POLICE departments_list = list( /datum/job_department/police, ) diff --git a/modular_darkpack/modules/jobs/code/sabbat/ductus.dm b/modular_darkpack/modules/jobs/code/sabbat/ductus.dm index 54320a1261a2..117af4dfc220 100644 --- a/modular_darkpack/modules/jobs/code/sabbat/ductus.dm +++ b/modular_darkpack/modules/jobs/code/sabbat/ductus.dm @@ -8,10 +8,13 @@ outfit = /datum/outfit/job/vampire/sabbatductus allowed_splats = list(SPLAT_KINDRED) job_flags = CITY_JOB_FLAGS - exp_required_type_department = EXP_TYPE_SABBAT departments_list = list( /datum/job_department/sabbat, ) + + exp_requirements = EXP_REQ_HEAD + exp_required_type_department = EXP_TYPE_SABBAT + description = "You are a Ductus and Pack Leader of your Sabbat pack. You are charged with rebellion against the Elders and the Camarilla, against the Jyhad, against the Masquerade and the Traditions, and the recognition of Caine as the true Dark Father of all Kindred kind. NOTE: BY PLAYING THIS ROLE YOU AGREE TO AND HAVE READ THE SERVER'S RULES ON ESCALATION FOR ANTAGS. KEEP THINGS INTERESTING AND ENGAGING FOR BOTH SIDES. KILLING PLAYERS JUST BECAUSE YOU CAN MAY RESULT IN A ROLEBAN." minimum_masquerade = 0 display_order = JOB_DISPLAY_ORDER_SABBATDUCTUS diff --git a/modular_darkpack/modules/jobs/code/sabbat/pack.dm b/modular_darkpack/modules/jobs/code/sabbat/pack.dm index de5db3a7fbf2..a08ab00c1690 100644 --- a/modular_darkpack/modules/jobs/code/sabbat/pack.dm +++ b/modular_darkpack/modules/jobs/code/sabbat/pack.dm @@ -8,7 +8,7 @@ outfit = /datum/outfit/job/vampire/sabbatpack job_flags = CITY_JOB_FLAGS allowed_splats = list(SPLAT_KINDRED) - exp_required_type_department = EXP_TYPE_SABBAT + // exp_required_type_department = EXP_TYPE_SABBAT departments_list = list( /datum/job_department/sabbat, ) diff --git a/modular_darkpack/modules/jobs/code/sabbat/priest.dm b/modular_darkpack/modules/jobs/code/sabbat/priest.dm index 208b076c0927..759594c08570 100644 --- a/modular_darkpack/modules/jobs/code/sabbat/priest.dm +++ b/modular_darkpack/modules/jobs/code/sabbat/priest.dm @@ -8,7 +8,7 @@ outfit = /datum/outfit/job/vampire/sabbatpriest allowed_splats = list(SPLAT_KINDRED) job_flags = CITY_JOB_FLAGS - exp_required_type_department = EXP_TYPE_SABBAT + departments_list = list( /datum/job_department/sabbat, ) @@ -18,6 +18,7 @@ display_order = JOB_DISPLAY_ORDER_SABBATPRIEST whitelisted = TRUE + /datum/outfit/job/vampire/sabbatpriest name = "Sabbat Priest" jobtype = /datum/job/vampire/sabbatpriest diff --git a/modular_darkpack/modules/jobs/code/supply/dealer.dm b/modular_darkpack/modules/jobs/code/supply/dealer.dm index 66bf314be100..49f80ac3cb7b 100644 --- a/modular_darkpack/modules/jobs/code/supply/dealer.dm +++ b/modular_darkpack/modules/jobs/code/supply/dealer.dm @@ -9,11 +9,13 @@ outfit = /datum/outfit/job/vampire/dealer display_order = JOB_DISPLAY_ORDER_DEALER - exp_required_type_department = EXP_TYPE_WAREHOUSE departments_list = list( /datum/job_department/supply, ) + exp_requirements = EXP_REQ_MINOR + exp_required_type_department = EXP_TYPE_WAREHOUSE + known_contacts = list("Prince", "Seneschal", "Sheriff", "Baron") allowed_splats = list(SPLAT_KINDRED, SPLAT_GHOUL, SPLAT_GAROU, SPLAT_NONE) splat_slots = list(SPLAT_NONE = 1) diff --git a/modular_darkpack/modules/jobs/code/supply/supply_tech.dm b/modular_darkpack/modules/jobs/code/supply/supply_tech.dm index 71f6f2d51712..d1f0bf6e4bb3 100644 --- a/modular_darkpack/modules/jobs/code/supply/supply_tech.dm +++ b/modular_darkpack/modules/jobs/code/supply/supply_tech.dm @@ -8,8 +8,8 @@ job_flags = CITY_JOB_FLAGS outfit = /datum/outfit/job/vampire/supply_tech + display_order = JOB_DISPLAY_ORDER_SUPPLY - exp_required_type_department = EXP_TYPE_WAREHOUSE departments_list = list( /datum/job_department/supply, ) diff --git a/modular_darkpack/modules/jobs/code/tremere/archivist.dm b/modular_darkpack/modules/jobs/code/tremere/archivist.dm index d82508c7000f..a6d2156337ed 100644 --- a/modular_darkpack/modules/jobs/code/tremere/archivist.dm +++ b/modular_darkpack/modules/jobs/code/tremere/archivist.dm @@ -7,7 +7,7 @@ config_tag = "CHANTRY_ARCHIVIST" outfit = /datum/outfit/job/vampire/archivist job_flags = CITY_JOB_FLAGS - exp_required_type_department = EXP_TYPE_CHANTRY + // exp_required_type_department = EXP_TYPE_CHANTRY departments_list = list( /datum/job_department/chantry, ) diff --git a/modular_darkpack/modules/jobs/code/tremere/gargoyle.dm b/modular_darkpack/modules/jobs/code/tremere/gargoyle.dm index ae4174802d7e..e2e10638ba38 100644 --- a/modular_darkpack/modules/jobs/code/tremere/gargoyle.dm +++ b/modular_darkpack/modules/jobs/code/tremere/gargoyle.dm @@ -7,7 +7,7 @@ config_tag = "CHANTRY_GARGOYLE" outfit = /datum/outfit/job/vampire/gargoyle job_flags = CITY_JOB_FLAGS - exp_required_type_department = EXP_TYPE_CHANTRY + // exp_required_type_department = EXP_TYPE_CHANTRY departments_list = list( /datum/job_department/chantry, ) diff --git a/modular_darkpack/modules/jobs/code/tremere/regent.dm b/modular_darkpack/modules/jobs/code/tremere/regent.dm index 199672b1d445..e7bd89bb2055 100644 --- a/modular_darkpack/modules/jobs/code/tremere/regent.dm +++ b/modular_darkpack/modules/jobs/code/tremere/regent.dm @@ -13,6 +13,8 @@ ) display_order = JOB_DISPLAY_ORDER_REGENT + exp_requirements = EXP_REQ_HEAD + description = "Lead the Chantry. You serve as both the Regent and Tremere Primogen. You report to the Tremere Lord of this region first, Prince second." minimum_masquerade = 4 allowed_splats = list(SPLAT_KINDRED) diff --git a/modular_darkpack/modules/jobs/code/tzimisce/voivode.dm b/modular_darkpack/modules/jobs/code/tzimisce/voivode.dm index 504648e4ce91..d223734ef5d6 100644 --- a/modular_darkpack/modules/jobs/code/tzimisce/voivode.dm +++ b/modular_darkpack/modules/jobs/code/tzimisce/voivode.dm @@ -7,12 +7,14 @@ config_tag = "VOIVODE" outfit = /datum/outfit/job/vampire/voivode job_flags = CITY_JOB_FLAGS - exp_required_type_department = EXP_TYPE_MANOR departments_list = list( /datum/job_department/manor, ) display_order = JOB_DISPLAY_ORDER_VOIVODE + exp_required_type_department = EXP_TYPE_MANOR + exp_requirements = EXP_REQ_HEAD + allowed_splats = list(SPLAT_KINDRED) allowed_clans = list(VAMPIRE_CLAN_TZIMISCE, VAMPIRE_CLAN_MALKAVIAN, VAMPIRE_CLAN_TOREADOR, VAMPIRE_CLAN_OLD_CLAN_TZIMISCE) // APOC EDIT CHANGE - JOBS - (Voivode) diff --git a/modular_darkpack/modules/matrix/code/matrix.dm b/modular_darkpack/modules/matrix/code/matrix.dm index 19296edd0e48..3cfd2402cefd 100644 --- a/modular_darkpack/modules/matrix/code/matrix.dm +++ b/modular_darkpack/modules/matrix/code/matrix.dm @@ -58,6 +58,7 @@ ADMIN_VERB_AND_CONTEXT_MENU(matrix_mob_verb, R_ADMIN, "Matrix Mob", "Matrix (des //handle_objectives() SSmasquerade.matrix_masquerade_breacher(despawning_mob, TRUE) + despawning_mob.client?.prefs?.save_character() // DARKPACK EDIT ADD despawning_mob.ghostize(FALSE) QDEL_NULL(despawning_mob) diff --git a/modular_darkpack/modules/powers/code/admin_discipline_editor.dm b/modular_darkpack/modules/powers/code/admin_preference_editor.dm similarity index 76% rename from modular_darkpack/modules/powers/code/admin_discipline_editor.dm rename to modular_darkpack/modules/powers/code/admin_preference_editor.dm index aa4acd106d75..978bb2f8822e 100644 --- a/modular_darkpack/modules/powers/code/admin_discipline_editor.dm +++ b/modular_darkpack/modules/powers/code/admin_preference_editor.dm @@ -1,32 +1,32 @@ -/datum/admin_discipline_editor +/datum/admin_preference_editor var/target_ckey = "" var/selected_slot = 0 var/datum/preferences/target_prefs = null var/loaded_offline = FALSE var/not_found = FALSE - var/list/discipline_cache = null + var/static/list/discipline_cache = null -/datum/admin_discipline_editor/Destroy() +/datum/admin_preference_editor/Destroy() if(loaded_offline) QDEL_NULL(target_prefs) target_prefs = null return ..() -/datum/admin_discipline_editor/ui_interact(mob/user, datum/tgui/ui) +/datum/admin_preference_editor/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, "AdminDisciplineEditor") + ui = new(user, src, "AdminPreferenceEditor") ui.open() -/datum/admin_discipline_editor/ui_state(mob/user) +/datum/admin_preference_editor/ui_state(mob/user) return ADMIN_STATE(R_ADMIN) -/datum/admin_discipline_editor/ui_data(mob/user) +/datum/admin_preference_editor/ui_data(mob/user) var/list/data = list() data["target_ckey"] = target_ckey data["selected_slot"] = selected_slot data["not_found"] = not_found - data["is_trusted"] = target_prefs?.discipline_trusted || FALSE + data["is_trusted"] = target_prefs?.has_whitelist(WHITELIST_TRUSTED) || FALSE data["character_slots"] = list() data["discipline_levels"] = list() data["clan_disciplines"] = list() @@ -49,7 +49,7 @@ if(!C || !C.mob) continue connected += ckey - if(C.prefs?.discipline_trusted) + if(C.prefs?.has_whitelist(WHITELIST_TRUSTED)) trusted_ckeys += ckey if(ishuman(C.mob)) var/list/validation = validate_mob_sheet(C.mob) @@ -95,11 +95,27 @@ data["clan_disciplines"] += disc_str clan_discs += disc_str - data["discipline_validation"] = validate_discipline_sheet(target_prefs.discipline_levels, clan_discs, target_prefs.discipline_trusted) + data["discipline_validation"] = validate_discipline_sheet(target_prefs.discipline_levels, clan_discs, target_prefs.has_whitelist(WHITELIST_TRUSTED)) + + var/splat_path = target_prefs?.read_preference(/datum/preference/choiced/splats) + if(!ispath(splat_path, /datum/splat/vampire)) + data["clan_name"] = null + data["clan_disciplines"] = list() + + var/client/target_client = GLOB.directory[target_ckey] + // if they have a value for screen_maps, they are in the character creator. + // an admin shouldnt be editing the same slot at the same time or it will risk wiping the slot + data["is_editing_character"] = target_client && length(target_client.screen_maps) > 0 + var/list/target_wl + if(target_prefs) + target_wl = target_prefs.get_all_whitelisted_entries() + + data["player_whitelists"] = target_wl || list() + data["whitelist_definitions"] = get_whitelist_definitions() return data -/datum/admin_discipline_editor/proc/build_discipline_cache() +/datum/admin_preference_editor/proc/build_discipline_cache() if(discipline_cache) return discipline_cache @@ -124,7 +140,7 @@ return discipline_cache -/datum/admin_discipline_editor/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) +/datum/admin_preference_editor/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() if(.) return @@ -200,15 +216,26 @@ log_admin("[key_name_admin(ui.user)] set [ADMIN_LOOKUPFLW(target_ckey)]'s character [character_name] to generation [new_gen]).") return TRUE - if("toggle_trusted") + if("set_whitelist") if(!target_prefs) return FALSE - target_prefs.discipline_trusted = !target_prefs.discipline_trusted + var/whitelist_id = params["id"] + if(!istext(whitelist_id) || !length(whitelist_id)) + return FALSE + var/should_grant = text2num(params["grant"]) + if(should_grant) + target_prefs.grant_whitelist(whitelist_id) + else + target_prefs.revoke_whitelist(whitelist_id) target_prefs.save_preferences() - message_admins("[ui.user] [target_prefs.discipline_trusted ? "granted" : "revoked"] trusted discipline whitelist for [ADMIN_LOOKUPFLW(target_ckey)].") + var/granted_revoked = should_grant ? "granted" : "revoked" + message_admins("[key_name_admin(ui.user)] [granted_revoked] whitelist '[whitelist_id]' for [ADMIN_LOOKUPFLW(target_ckey)].") + log_admin("[key_name_admin(ui.user)] [granted_revoked] whitelist '[whitelist_id]' for [ADMIN_LOOKUPFLW(target_ckey)].") + // SSoverwatch.record_action(null, "[key_name_admin(ui.user)] [granted_revoked] whitelist '[whitelist_id]' for [ADMIN_LOOKUPFLW(target_ckey)].") return TRUE -/datum/admin_discipline_editor/proc/load_target(search_ckey) + +/datum/admin_preference_editor/proc/load_target(search_ckey) if(loaded_offline && target_prefs) qdel(target_prefs) target_prefs = null @@ -237,7 +264,7 @@ selected_slot = 1 return TRUE -ADMIN_VERB(discipline_menu, R_ADMIN, "Discipline Menu", "Edit a player's disciplines.", ADMIN_CATEGORY_SECOND_CITY) - var/datum/admin_discipline_editor/editor = new +ADMIN_VERB(admin_preference_editor, R_ADMIN, "Discipline/Preference Editor", "Edit and view a player's disciplines and preferences.", ADMIN_CATEGORY_SECOND_CITY) + var/datum/admin_preference_editor/editor = new editor.ui_interact(user.mob) - BLACKBOX_LOG_ADMIN_VERB("Discipline Menu") + BLACKBOX_LOG_ADMIN_VERB("Discipline/Preference Editor") diff --git a/modular_darkpack/modules/powers/code/discipline_pref_middleware.dm b/modular_darkpack/modules/powers/code/discipline_pref_middleware.dm index 4017f4560f67..220769485273 100644 --- a/modular_darkpack/modules/powers/code/discipline_pref_middleware.dm +++ b/modular_darkpack/modules/powers/code/discipline_pref_middleware.dm @@ -7,9 +7,10 @@ GLOBAL_LIST_INIT(rare_discipline_types, list( /datum/discipline/obtenebration, /datum/discipline/thaumaturgy, /datum/discipline/necromancy, - /datum/discipline/daimoinon, /datum/discipline/valeren, - // melpominee not yet implemented but will go here + /datum/discipline/obeah, + /datum/discipline/daimoinon, + /datum/discipline/melpominee, )) // warns a player if they have no discipline dots assigned before joining @@ -118,6 +119,7 @@ GLOBAL_LIST_INIT(rare_discipline_types, list( data["clan_disciplines"] = list() data["clan_name"] = null var/clan_value = preferences.read_preference(/datum/preference/choiced/subsplat/vampire_clan) + /* // DARKPACK EDIT REMOVAL - dont automatically give them their clan disciplines in the UI actually. sometimes people want to be dominate malks or otherwise go homebrew if(clan_value) var/datum/subsplat/vampire_clan/clan_datum = get_vampire_clan(clan_value) if(clan_datum) @@ -125,6 +127,7 @@ GLOBAL_LIST_INIT(rare_discipline_types, list( for(var/disc_type in clan_datum.clan_disciplines) if(ispath(disc_type, /datum/discipline)) data["clan_disciplines"] += "[disc_type]" + */ var/discipline_count = 0 var/list/counted_discs = list() @@ -146,7 +149,7 @@ GLOBAL_LIST_INIT(rare_discipline_types, list( data["discipline_points_spent"] = points_spent data["discipline_tier"] = budget_info["tier"] data["discipline_tier_details"] = budget_info["details"] - data["is_trusted"] = preferences.discipline_trusted || FALSE + data["is_trusted"] = preferences?.has_whitelist(WHITELIST_TRUSTED) data["max_trusted_generation"] = MAX_TRUSTED_GENERATION data["max_public_generation"] = MAX_PUBLIC_GENERATION data["highest_generation_limit"] = HIGHEST_GENERATION_LIMIT @@ -257,8 +260,18 @@ GLOBAL_LIST_INIT(rare_discipline_types, list( if(!isnewplayer(user) && ("[user.client.prefs.default_slot]" in user.persistent_client.joined_as_slots)) to_chat(user, span_warning("You may not adjust discipline dots of characters that have played in the current round.")) return FALSE - - preferences.discipline_levels = list() + // preferences.discipline_levels = list() // DARKPACK EDIT REMOVAL + // DARKPACK EDIT START + var/clan_value = preferences.read_preference(/datum/preference/choiced/subsplat/vampire_clan) + if(!clan_value) + return FALSE + preferences.discipline_levels = list() // restore them to default + var/datum/subsplat/vampire_clan/clan_datum = get_vampire_clan(clan_value) // then give them their default clan discs. clear_discipline_levels fires from changing clans + if(clan_datum) + for(var/disc_type in clan_datum.clan_disciplines) + if(ispath(disc_type, /datum/discipline)) + preferences.discipline_levels += disc_type + // DARKPACK EDIT END preferences.save_character() return TRUE diff --git a/modular_darkpack/modules/splats/code/splat_configs.dm b/modular_darkpack/modules/splats/code/splat_configs.dm index 06f159a8a209..6f85b333b053 100644 --- a/modular_darkpack/modules/splats/code/splat_configs.dm +++ b/modular_darkpack/modules/splats/code/splat_configs.dm @@ -1,5 +1,7 @@ /// List of roundstart splats' their splat_id's GLOBAL_LIST_EMPTY(roundstart_splats) +GLOBAL_LIST_EMPTY(whitelisted_splats) +GLOBAL_LIST_EMPTY(default_player_whitelists) /datum/config_entry/keyed_list/roundstart_splats //splats you can play as from the get go. key_mode = KEY_MODE_TEXT @@ -9,9 +11,22 @@ GLOBAL_LIST_EMPTY(roundstart_splats) if(key_name in GLOB.splat_list) return TRUE - log_config("ERROR: [key_name] is not a valid race ID.") + log_config("ERROR: [key_name] is not a valid splat ID.") return FALSE + +/datum/config_entry/keyed_list/whitelisted_splats //splats you can play as from the get go. + key_mode = KEY_MODE_TEXT + value_mode = VALUE_MODE_FLAG + +/datum/config_entry/keyed_list/whitelisted_splats/ValidateListEntry(key_name, key_value) + if(key_name in GLOB.splat_list) + return TRUE + + log_config("ERROR: [key_name] is not a valid splat ID.") + return FALSE + + /** * Checks if a splat is eligible to be picked at roundstart. * @@ -23,6 +38,12 @@ GLOBAL_LIST_EMPTY(roundstart_splats) return TRUE return FALSE +/datum/splat/proc/requires_whitelist() + if(id in (CONFIG_GET(keyed_list/whitelisted_splats))) + return TRUE + return FALSE + + /** * Generates splat available to choose in character setup at roundstart * @@ -47,3 +68,33 @@ GLOBAL_LIST_EMPTY(roundstart_splats) GLOB.roundstart_splats = generate_selectable_splats() return GLOB.roundstart_splats + + +/proc/get_default_player_whitelists() + RETURN_TYPE(/alist) + + if (!GLOB.default_player_whitelists.len) + var/alist/defs = alist( + WHITELIST_TRUSTED = FALSE, + WHITELIST_TIMELIMITS = FALSE, + SPLAT_NONE = TRUE, + ) + + for(var/splat_id in get_selectable_splats()) + var/splat_type = GLOB.splat_list[splat_id] + var/datum/splat/splat = GLOB.splat_prototypes[splat_type] + + defs[splat_id] = !splat.requires_whitelist() + + for(var/clan_name in GLOB.vampire_clan_list) + var/datum/subsplat/vampire_clan/clan = get_vampire_clan(clan_name) + if(!clan) + continue + + if(clan.id in CONFIG_GET(keyed_list/whitelisted_clans)) + defs[clan.id] = FALSE + // defs[clan.id] = !(clan.id in CONFIG_GET(keyed_list/whitelisted_clans)) + + GLOB.default_player_whitelists = defs + + return GLOB.default_player_whitelists diff --git a/modular_darkpack/modules/splats/code/splat_management.dm b/modular_darkpack/modules/splats/code/splat_management.dm index 04b1e4b14c09..b17efd31b386 100644 --- a/modular_darkpack/modules/splats/code/splat_management.dm +++ b/modular_darkpack/modules/splats/code/splat_management.dm @@ -62,7 +62,7 @@ return TRUE -/// Returns the splat with the highest priority, with a prefrence for ones first assigned. +/// Returns the splat with the highest priority, with a preference for ones first assigned. /mob/living/proc/get_primary_splat(splat_type, count_splat = TRUE, count_halfsplat = TRUE) RETURN_TYPE(/datum/splat) diff --git a/modular_darkpack/modules/splats/code/subsplat/_subsplat.dm b/modular_darkpack/modules/splats/code/subsplat/_subsplat.dm index b83087902e52..8e07b650689e 100644 --- a/modular_darkpack/modules/splats/code/subsplat/_subsplat.dm +++ b/modular_darkpack/modules/splats/code/subsplat/_subsplat.dm @@ -16,7 +16,7 @@ var/name /// Description of what the splat is and what it does var/desc - /// If set, the roleplay level that is displayed in prefrences as a guide to players. + /// If set, the roleplay level that is displayed in preferences as a guide to players. var/roleplay_level /// ID for trait sources and whatnot var/id diff --git a/modular_darkpack/modules/vampire_the_masquerade/code/preferences/generation.dm b/modular_darkpack/modules/vampire_the_masquerade/code/preferences/generation.dm index 6eb52b1d0005..76532851ef69 100644 --- a/modular_darkpack/modules/vampire_the_masquerade/code/preferences/generation.dm +++ b/modular_darkpack/modules/vampire_the_masquerade/code/preferences/generation.dm @@ -8,13 +8,13 @@ maximum = HIGHEST_GENERATION_LIMIT /datum/preference/numeric/generation/is_valid(value, datum/preferences/preferences) - var/min = preferences?.discipline_trusted ? MAX_TRUSTED_GENERATION : MAX_PUBLIC_GENERATION + var/min = preferences?.has_whitelist(WHITELIST_TRUSTED) ? MAX_TRUSTED_GENERATION : MAX_PUBLIC_GENERATION return isnum(value) && value >= min && value <= HIGHEST_GENERATION_LIMIT /datum/preference/numeric/generation/deserialize(input, datum/preferences/preferences) if(istext(input)) input = text2num(input) - var/min = preferences?.discipline_trusted ? MAX_TRUSTED_GENERATION : MAX_PUBLIC_GENERATION + var/min = preferences?.has_whitelist(WHITELIST_TRUSTED) ? MAX_TRUSTED_GENERATION : MAX_PUBLIC_GENERATION return sanitize_float(input, min, HIGHEST_GENERATION_LIMIT, 1, rand(min, HIGHEST_GENERATION_LIMIT)) /datum/preference/numeric/generation/apply_to_human(mob/living/carbon/human/target, value) diff --git a/modular_darkpack/modules/vampire_the_masquerade/code/vampire_clan/trusted_whitelist.dm b/modular_darkpack/modules/vampire_the_masquerade/code/vampire_clan/trusted_whitelist.dm new file mode 100644 index 000000000000..08082f61d435 --- /dev/null +++ b/modular_darkpack/modules/vampire_the_masquerade/code/vampire_clan/trusted_whitelist.dm @@ -0,0 +1,76 @@ +/datum/config_entry/keyed_list/whitelisted_clans //splats you can play as from the get go. + key_mode = KEY_MODE_TEXT + value_mode = VALUE_MODE_FLAG + +/datum/config_entry/keyed_list/whitelisted_clans/ValidateListEntry(key_name, key_value) + for(var/clan_name in GLOB.vampire_clan_list) + var/datum/subsplat/vampire_clan/clan = get_vampire_clan(clan_name) + if(!clan) + continue + if(clan.id == key_name) + return TRUE + + log_config("ERROR: [key_name] is not a valid clan ID.") + return FALSE + + +// remember kids, you should always obtain enthusiastic informed values before proceeding +/datum/preference/choiced/subsplat/vampire_clan/create_informed_default_value(datum/preferences/preferences) + if(preferences && !preferences.has_whitelist(WHITELIST_TRUSTED)) + var/list/safe_choices = list() + for(var/choice in get_choices()) + var/datum/subsplat/vampire_clan/clan = get_vampire_clan(choice) + if(!clan || !(clan.id in CONFIG_GET(keyed_list/whitelisted_clans))) + safe_choices += choice + else if(preferences.has_whitelist(clan.id)) + safe_choices += choice + if(length(safe_choices)) + return pick(safe_choices) + return ..() + +/datum/preference/choiced/subsplat/vampire_clan/is_valid(value, datum/preferences/preferences) + if(preferences && !preferences.has_whitelist(WHITELIST_TRUSTED)) + var/datum/subsplat/vampire_clan/clan = get_vampire_clan(value) + if(clan?.id in CONFIG_GET(keyed_list/whitelisted_clans)) + if(!preferences.has_whitelist(clan.id)) + to_chat(preferences.parent, span_warning("The [clan.name] clan requires a special whitelisting process. Feel free to apply for it on Discord!")) + return FALSE + return ..() + +// helper procs to make absolutely sure unwhitelisted people cannot join with whitelisted splats +// useful in-case a regime member removes a trusted player from the whitelist +// so they cant continue to play on the trusted character with that clan selected +/proc/get_restricted_clan(mob/dead/new_player/new_player) + var/client/C = new_player.client + if(!C?.prefs) + return null + if(C.prefs.has_whitelist(WHITELIST_TRUSTED)) + return null + + var/datum/preference/preference_entry = GLOB.preference_entries[/datum/preference/choiced/subsplat/vampire_clan] + if(preference_entry.is_accessible(C.prefs)) + return null + + var/selected = C.prefs.read_preference(/datum/preference/choiced/subsplat/vampire_clan) + var/datum/subsplat/vampire_clan/clan = get_vampire_clan(selected) + if(clan?.id in CONFIG_GET(keyed_list/whitelisted_clans)) + if(!C.prefs.has_whitelist(clan.id)) + return clan + return null + +/atom/movable/screen/lobby/button/ready/Click(location, control, params) + var/mob/dead/new_player/new_player = hud.mymob + if(new_player.ready == PLAYER_NOT_READY) + var/datum/subsplat/vampire_clan/clan = get_restricted_clan(new_player) + if(clan) + to_chat(new_player, span_warning("[clan.name] requires a special whitelisting process. Feel free to apply for it on Discord!")) + return + return ..() + +/atom/movable/screen/lobby/button/join/Click(location, control, params) + var/mob/dead/new_player/new_player = hud.mymob + var/datum/subsplat/vampire_clan/clan = get_restricted_clan(new_player) + if(clan) + to_chat(new_player, span_warning("[clan.name] requires a special whitelisting process. Feel free to apply for it on Discord!")) + return + return ..() diff --git a/modular_darkpack/modules/whitelist/code/whitelist_enforcement.dm b/modular_darkpack/modules/whitelist/code/whitelist_enforcement.dm new file mode 100644 index 000000000000..e0318f6227ff --- /dev/null +++ b/modular_darkpack/modules/whitelist/code/whitelist_enforcement.dm @@ -0,0 +1,42 @@ +/mob/dead/new_player/proc/get_restricted_splat_name() + var/client/C = client + if(!C?.prefs) + return null + var/splat_path = C.prefs.read_preference(/datum/preference/choiced/splats) + if(!ispath(splat_path, /datum/splat)) + if(!C.prefs.has_whitelist(SPLAT_NONE)) + return "Human" + return null + var/datum/splat/splat = GLOB.splat_prototypes[splat_path] + if(!splat) + return null + if(!isnull(splat.id) && !C.prefs.has_whitelist(splat.id)) + return splat.name + return null + +/atom/movable/screen/lobby/button/ready/Click(location, control, params) + var/mob/dead/new_player/new_player = hud.mymob + if(new_player.ready == PLAYER_NOT_READY) + var/splat_name = new_player.get_restricted_splat_name() + if(splat_name) + to_chat(new_player, span_warning("[splat_name] requires a special whitelisting process. Feel free to apply for it on Discord!")) + return + return ..() + +/atom/movable/screen/lobby/button/join/Click(location, control, params) + var/mob/dead/new_player/new_player = hud.mymob + var/splat_name = new_player.get_restricted_splat_name() + if(splat_name) + to_chat(new_player, span_warning("[splat_name] requires a special whitelisting process. Feel free to apply for it on Discord!")) + return + return ..() + +/datum/preference/choiced/splats/is_valid(value, datum/preferences/preferences) + if(preferences) + var/splat_id = SPLAT_NONE + if(ispath(value, /datum/splat)) + var/datum/splat/splat = GLOB.splat_prototypes[value] + splat_id = splat?.id || SPLAT_NONE + if(!isnull(splat_id) && !preferences.has_whitelist(splat_id)) + return FALSE + return ..() diff --git a/modular_darkpack/modules/whitelist/code/whitelist_prefs.dm b/modular_darkpack/modules/whitelist/code/whitelist_prefs.dm new file mode 100644 index 000000000000..a45c4e756d09 --- /dev/null +++ b/modular_darkpack/modules/whitelist/code/whitelist_prefs.dm @@ -0,0 +1,98 @@ +/datum/preferences + var/list/player_whitelists + +/// Assoc list of id by whitelist state. +/datum/preferences/proc/get_player_whitelists() + RETURN_TYPE(/alist) + if(isnull(player_whitelists)) + player_whitelists = get_default_player_whitelists().Copy() + return player_whitelists + + +/// returns a flat list of true entires. +/datum/preferences/proc/get_all_whitelisted_entries() + RETURN_TYPE(/list) + var/list/flat_list = list() + var/list/alist/pref_whitelist = get_player_whitelists() + for(var/key, bool in pref_whitelist) + if(bool) + flat_list += key + return flat_list + +/datum/preferences/proc/has_whitelist(whitelist_id) + return get_player_whitelists()[whitelist_id] + +/datum/preferences/proc/grant_whitelist(whitelist_id) + var/list/wl = get_player_whitelists() + if(wl[whitelist_id]) + return + wl[whitelist_id] = TRUE + if(whitelist_id == WHITELIST_TRUSTED) + discipline_trusted = TRUE + +/datum/preferences/proc/revoke_whitelist(whitelist_id) + if(whitelist_id == SPLAT_NONE) // as funny as it would be, this should probably be protected + return + var/list/wl = get_player_whitelists() + if(!wl[whitelist_id]) + return + wl[whitelist_id] = FALSE + if(whitelist_id == WHITELIST_TRUSTED) + discipline_trusted = FALSE + +/datum/preference_middleware/disciplines/get_ui_data(mob/user) + var/list/data = ..() + var/datum/preferences/prefs = user?.client?.prefs + var/list/player_wl + if(prefs) + player_wl = prefs.get_all_whitelisted_entries() + data["player_whitelists"] = player_wl ? player_wl.Copy() : list() + return data + +/datum/admin_preference_editor/proc/get_whitelist_definitions() + var/alist/defaults = get_default_player_whitelists() + var/list/defs = list() + + defs[SPLAT_NONE] = list( + "name" = "Human", + "description" = "Access to play as a human.", + "category" = "splat", + "is_default" = defaults[SPLAT_NONE], + ) + for(var/splat_id in get_selectable_splats()) + var/splat_type = GLOB.splat_list[splat_id] + var/datum/splat/splat = GLOB.splat_prototypes[splat_type] + + defs[splat_id] = list( + "name" = splat.name, + "description" = "Access to play as a [splat.name].", + "category" = "splat", + "is_default" = defaults[splat_id], + ) + + defs[WHITELIST_TRUSTED] = list( + "name" = "Trusted", + "description" = "Bypasses discipline sheet limits, and allows them to be a lower generation kindred.", + "category" = "access", + "is_default" = defaults[WHITELIST_TRUSTED], + ) + defs[WHITELIST_TIMELIMITS] = list( + "name" = "Bypass Time Requirements", + "description" = "Bypasses time requierments for jobs.", + "category" = "access", + "is_default" = defaults[WHITELIST_TIMELIMITS], + ) + + + for(var/clan_name in GLOB.vampire_clan_list) + var/datum/subsplat/vampire_clan/clan = get_vampire_clan(clan_name) + if(!clan || !defaults[clan.id]) + continue + defs[clan.id] = list( + "name" = clan.name, + "description" = "Access to play [clan.name] without requiring trusted whitelist", + "category" = "clan", + "is_default" = defaults[clan.id] + ) + + return defs diff --git a/modular_zapoc/modules/jobs/code/ocean76/handler.dm b/modular_zapoc/modules/jobs/code/ocean76/handler.dm index 16ba3d667a56..2ca16049d0ce 100644 --- a/modular_zapoc/modules/jobs/code/ocean76/handler.dm +++ b/modular_zapoc/modules/jobs/code/ocean76/handler.dm @@ -9,7 +9,8 @@ outfit = /datum/outfit/job/vampire/ocean display_order = JOB_DISPLAY_ORDER_OCEAN_76_BOSS - exp_required_type_department = EXP_TYPE_OCEAN + // exp_required_type_department = EXP_TYPE_OCEAN + exp_requirements = EXP_REQ_HEAD department_for_prefs = /datum/job_department/ocean departments_list = list( /datum/job_department/ocean, diff --git a/modular_zapoc/modules/jobs/code/ocean76/operator.dm b/modular_zapoc/modules/jobs/code/ocean76/operator.dm index cadfebf6b78c..66efb844c6fe 100644 --- a/modular_zapoc/modules/jobs/code/ocean76/operator.dm +++ b/modular_zapoc/modules/jobs/code/ocean76/operator.dm @@ -9,7 +9,6 @@ outfit = /datum/outfit/job/vampire/ocean display_order = JOB_DISPLAY_ORDER_OCEAN_76_GANGER - exp_required_type_department = EXP_TYPE_OCEAN department_for_prefs = /datum/job_department/ocean departments_list = list( /datum/job_department/ocean, diff --git a/tgstation.dme b/tgstation.dme index c0bdda7d0859..955778479c20 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -478,6 +478,7 @@ #include "code\__DEFINES\~darkpack\subsystems.dm" #include "code\__DEFINES\~darkpack\vampire_clan.dm" #include "code\__DEFINES\~darkpack\walls.dm" +#include "code\__DEFINES\~darkpack\whitelist.dm" #include "code\__DEFINES\~darkpack\xp_and_freebie.dm" #include "code\__DEFINES\~darkpack\dcs\beastmaster_signals.dm" #include "code\__DEFINES\~darkpack\dcs\bouncer_signals.dm" @@ -7757,7 +7758,7 @@ #include "modular_darkpack\modules\pixel_shift\code\pixel_shift_component.dm" #include "modular_darkpack\modules\pixel_shift\code\pixel_shift_keybind.dm" #include "modular_darkpack\modules\postal\code\postal.dm" -#include "modular_darkpack\modules\powers\code\admin_discipline_editor.dm" +#include "modular_darkpack\modules\powers\code\admin_preference_editor.dm" #include "modular_darkpack\modules\powers\code\discipline_actions.dm" #include "modular_darkpack\modules\powers\code\discipline_configs.dm" #include "modular_darkpack\modules\powers\code\discipline_gain.dm" @@ -8001,6 +8002,7 @@ #include "modular_darkpack\modules\vampire_the_masquerade\code\vampire_clan\clan_mark.dm" #include "modular_darkpack\modules\vampire_the_masquerade\code\vampire_clan\clan_mark_pref.dm" #include "modular_darkpack\modules\vampire_the_masquerade\code\vampire_clan\clan_pref.dm" +#include "modular_darkpack\modules\vampire_the_masquerade\code\vampire_clan\trusted_whitelist.dm" #include "modular_darkpack\modules\vampire_the_masquerade\code\vampire_clan\clans\banu_haqim.dm" #include "modular_darkpack\modules\vampire_the_masquerade\code\vampire_clan\clans\brujah.dm" #include "modular_darkpack\modules\vampire_the_masquerade\code\vampire_clan\clans\caitiff.dm" @@ -8139,6 +8141,8 @@ #include "modular_darkpack\modules\werewolf_the_apocalypse\code\subsplats\tribes\garou.dm" #include "modular_darkpack\modules\werewolf_the_apocalypse\code\weapons\klaives.dm" #include "modular_darkpack\modules\westfield_mall\code\mall_areas.dm" +#include "modular_darkpack\modules\whitelist\code\whitelist_enforcement.dm" +#include "modular_darkpack\modules\whitelist\code\whitelist_prefs.dm" #include "modular_darkpack\modules\westfield_mall\code\modular_rooms.dm" #include "modular_darkpack\modules\z_travel\code\helpers.dm" #include "modular_darkpack\modules\z_travel\code\manhole.dm" diff --git a/tgui/packages/tgui/interfaces/AdminDisciplineEditor.tsx b/tgui/packages/tgui/interfaces/AdminDisciplineEditor.tsx deleted file mode 100644 index 92a24b3b7316..000000000000 --- a/tgui/packages/tgui/interfaces/AdminDisciplineEditor.tsx +++ /dev/null @@ -1,487 +0,0 @@ -import { useState } from 'react'; - -import { useBackend } from 'tgui/backend'; -import { Box, Button, DmIcon, Icon, Input, NumberInput, Section, Stack, Tooltip } from 'tgui-core/components'; -import { Window } from '../layouts'; - -type DisciplineInfo = { - name: string; - desc: string; - max_level: number; - rarity: 'rare' | 'common'; - icon?: string; - icon_state?: string; -}; - -type DisciplineValidation = { - total: number; - additional: number; - additional_rare: number; - valid: boolean; - violations: string[]; -}; - -type Data = { - target_ckey: string; - selected_slot: number; - not_found: boolean; - is_trusted: boolean; - character_slots: { slot: number; name: string }[]; - discipline_levels: Record; - clan_disciplines: string[]; - disciplines: Record; - discipline_validation: DisciplineValidation | null; - connected_ckeys: string[]; - invalid_ckeys: string[]; - trusted_ckeys: string[]; - character_name: string | null; - character_age: number | null; - immortal_age: number | null; - clan_name: string | null; - splat_name: string | null; - generation: number | null; - flavor_text: string | null; - headshot: string | null; -}; - -type DisciplineCardProps = { - path: string; - discipline: DisciplineInfo; - level: number; - isClanDiscipline: boolean; - clanName: string | null; - isAdditional: boolean; - onDotClick: (position: number) => void; -}; - -function DisciplineCard(props: DisciplineCardProps) { - const { discipline, level, isClanDiscipline, clanName, isAdditional, onDotClick } = props; - const isRare = discipline.rarity === 'rare'; - - return ( - -
- - {discipline.icon && discipline.icon_state && ( - - - - )} - - - {isClanDiscipline && clanName && ( - - ({clanName} Clan Discipline) - - )} - - {isRare ? 'Rare Discipline' : 'Common Discipline'} - - {discipline.desc} - - } - > - - {discipline.name} - {isClanDiscipline && ( - - - - )} - - - - - - {!isAdditional && ( - - Clan - - )} - - {isRare ? 'Rare' : 'Common'} - - - - - - {Array.from({ length: discipline.max_level }, (_, i) => { - const position = i + 1; - const filled = position <= level; - return ( - - onDotClick(position)} - style={{ cursor: 'pointer', fontSize: '13px', margin: '0 2px' }} - /> - - ); - })} - - - -
-
- ); -} - -export function AdminDisciplineEditor() { - const { act, data } = useBackend(); - const { - target_ckey, - selected_slot, - not_found, - is_trusted, - character_slots, - discipline_levels, - clan_disciplines, - disciplines, - discipline_validation, - connected_ckeys, - invalid_ckeys, - trusted_ckeys, - character_name, - character_age, - immortal_age, - clan_name, - splat_name, - generation, - flavor_text, - headshot, - } = data; - - const [ckeyInput, setCkeyInput] = useState(''); - const clanSet = new Set(clan_disciplines || []); - const allDisciplines = disciplines || {}; - const levels = discipline_levels || {}; - const connected = connected_ckeys || []; - const invalidSet = new Set(invalid_ckeys || []); - const trustedSet = new Set(trusted_ckeys || []); - - const handleDotClick = (path: string, position: number, currentLevel: number) => { - const newLevel = position <= currentLevel ? (position === 1 ? 0 : position) : position; - act('set_discipline_level', { discipline: path, level: newLevel }); - }; - - const disciplineEntries = Object.entries(allDisciplines); - - return ( - - - - -
- {connected.length === 0 && ( - - No players online. - - )} - {connected.map((ckey) => ( - - - - ))} -
-
- -
- - - setCkeyInput(value)} - onEnter={() => act('search_ckey', { ckey: ckeyInput })} - /> - - - - - - {!!not_found && ( - - No player found for ckey "{target_ckey}". - - )} -
- {target_ckey && !not_found && character_slots.length > 0 && ( -
- {target_ckey}'s character slots - - - - - - - } - > - - {character_slots.map(({ slot, name }) => ( - - - - ))} - -
- )} - {selected_slot > 0 && character_name && ( -
- - - - {character_name} - - - {character_age !== null && ( - - - Living Age: - - - {character_age} - - - )} - {immortal_age !== null && ( - - - Immortal Age: - - - {immortal_age} - - - )} - {character_age !== null && immortal_age !== null && ( - - - Chronological Age: - - - {character_age + immortal_age} - - - )} - {splat_name && ( - - - Splat: - - - {splat_name} - - - )} - {clan_name && ( - - - Clan: - - - {clan_name} - - - )} - {generation !== null && ( - - - Generation: - - - act('set_generation', { generation: value }) - } - /> - - )} - - {flavor_text && ( - - {flavor_text} - - )} - - - - {headshot && ( - - )} - - - -
- )} - {discipline_validation && ( -
- - - - Total disciplines: - - 5 ? 'red' : 'white'}> - {discipline_validation.total} / 5 - - - - - Non-Clan Rares in Use: - - = 2 ? 'red' : 'white'} - > - {discipline_validation.additional_rare} - - - - {is_trusted ? ( - - - Trusted - - ) : discipline_validation.valid ? ( - - - In compliance - - ) : ( - - - - Invalid! - - - )} - - -
- )} - - {selected_slot > 0 && splat_name === 'Human' && ( - - This character cannot be assigned disciplines or gifts. - - )} - {selected_slot > 0 && splat_name !== 'Human' && ( - - {disciplineEntries.map(([path, discipline]) => { - const level = levels[path] ?? 0; - return ( - handleDotClick(path, position, level)} - /> - ); - })} - - )} -
-
-
-
- ); -} diff --git a/tgui/packages/tgui/interfaces/AdminPreferenceEditor.tsx b/tgui/packages/tgui/interfaces/AdminPreferenceEditor.tsx new file mode 100644 index 000000000000..bd1e0494d582 --- /dev/null +++ b/tgui/packages/tgui/interfaces/AdminPreferenceEditor.tsx @@ -0,0 +1,519 @@ +import { useState } from 'react'; +import { useBackend } from 'tgui/backend'; +import { Box, Button, Divider, DmIcon, Icon, Input, NumberInput, Section, Stack, Tooltip } from 'tgui-core/components'; +import { Window } from '../layouts'; + +type DisciplineInfo = { + name: string; + desc: string; + max_level: number; + rarity: 'rare' | 'common'; + icon?: string; + icon_state?: string; +}; + +type DisciplineValidation = { + total: number; + additional: number; + additional_rare: number; + valid: boolean; + violations: string[]; +}; + +type WhitelistDefinition = { + name: string; + description: string; + category: 'splat' | 'access' | 'clan'; + is_default: boolean; +}; + +type Data = { + target_ckey: string; + selected_slot: number; + not_found: boolean; + is_trusted: boolean; + character_slots: { slot: number; name: string }[]; + discipline_levels: Record; + clan_disciplines: string[]; + disciplines: Record; + discipline_validation: DisciplineValidation | null; + connected_ckeys: string[]; + invalid_ckeys: string[]; + trusted_ckeys: string[]; + is_editing_character: boolean; + character_name: string | null; + character_age: number | null; + immortal_age: number | null; + clan_name: string | null; + generation: number | null; + splat_name: string | null; + flavor_text: string | null; + headshot: string | null; + player_whitelists: string[]; + whitelist_definitions: Record; +}; + +type DisciplineCardProps = { + path: string; + discipline: DisciplineInfo; + level: number; + isOwned: boolean; + isClanDiscipline: boolean; + clanName: string | null; + isAdditional: boolean; + onDotClick: (position: number) => void; + onRemove: (path: string) => void; +}; + +function DisciplineCard(props: DisciplineCardProps) { + const { discipline, level, isOwned, isClanDiscipline, clanName, path, isAdditional, onDotClick, onRemove } = props; + const isRare = discipline.rarity === 'rare'; + + return ( + + +
+ {isOwned && ( + onRemove(path)} + /> + )} + + + {discipline.icon && discipline.icon_state && ( + + + + )} + + + {isClanDiscipline && clanName && ( + + ({clanName} Clan Discipline) + + )} + + {isRare ? 'Rare Discipline' : 'Common Discipline'} + + {discipline.desc} + + } + > + + {discipline.name} + {isClanDiscipline && ( + + + + )} + + + + + + {!isAdditional && ( + + Clan + + )} + + {isRare ? 'Rare' : 'Common'} + + + + + + {Array.from({ length: discipline.max_level }, (_, i) => { + const position = i + 1; + const filled = position <= level; + return ( + + onDotClick(position)} + style={{ cursor: 'pointer', fontSize: '11px', margin: '0 1px' }} + /> + + ); + })} + + + +
+
+ ); +} + +const WHITELIST_CATEGORY_LABELS: Record = { + splat: 'Splat Access', + access: 'Access Level', + clan: 'Clan Access', +}; + +function WhitelistSection(props: { + playerWhitelists: string[]; + whitelistDefinitions: Record; + onToggle: (id: string, currentlyHas: boolean) => void; +}) { + const { playerWhitelists, whitelistDefinitions, onToggle } = props; + const whitelistSet = new Set(playerWhitelists); + const categories = ['splat', 'access', 'clan'] as const; + + return ( +
+ + {categories.map((category) => { + const entries = Object.entries(whitelistDefinitions).filter( + ([, wl]) => wl.category === category, + ); + if (!entries.length) return null; + return ( + + + {WHITELIST_CATEGORY_LABELS[category]} + + + {entries.map(([id, wl]) => { + const has = whitelistSet.has(id); + return ( + + + + + + ); + })} + + + ); + })} + +
+ ); +} + +export function AdminPreferenceEditor() { + const { act, data } = useBackend(); + const { + target_ckey, + selected_slot, + not_found, + is_trusted, + character_slots, + discipline_levels, + clan_disciplines, + disciplines, + discipline_validation, + connected_ckeys, + invalid_ckeys, + trusted_ckeys, + is_editing_character, + character_name, + character_age, + immortal_age, + clan_name, + splat_name, + generation, + flavor_text, + headshot, + player_whitelists, + whitelist_definitions, + } = data; + + const [ckeyInput, setCkeyInput] = useState(''); + const clanSet = new Set(clan_disciplines || []); + const allDisciplines = disciplines || {}; + const levels = discipline_levels || {}; + const connected = connected_ckeys || []; + const invalidSet = new Set(invalid_ckeys || []); + const trustedSet = new Set(trusted_ckeys || []); + + const handleDotClick = (path: string, position: number, currentLevel: number) => { + const newLevel = position <= currentLevel ? (position === 1 ? 0 : position) : position; + act('set_discipline_level', { discipline: path, level: newLevel }); + }; + + const handleRemove = (path: string) => { + act('set_discipline_level', { discipline: path, level: 0 }); + }; + + const handleWhitelistToggle = (id: string, currentlyHas: boolean) => { + act('set_whitelist', { id, grant: currentlyHas ? 0 : 1 }); + }; + + const disciplineEntries = Object.entries(allDisciplines); + + return ( + + + + +
+ {connected.length === 0 && No players online.} + {connected.map((ckey) => ( + + + + ))} +
+
+ +
+ + + setCkeyInput(value)} + onEnter={() => act('search_ckey', { ckey: ckeyInput })} + /> + + + + + + {!!not_found && ( + + No player found for ckey "{target_ckey}". + + )} +
+ + {target_ckey && !not_found && ( + + )} + + {target_ckey && !not_found && character_slots.length > 0 && ( +
+ + {character_slots.map(({ slot, name }) => ( + + + + ))} + +
+ )} + {selected_slot > 0 && character_name && ( + <> +
+ + + {character_name} + + + Living Age: + {character_age} + + + Immortal Age: + {immortal_age} + + + Clan: + {clan_name} + + + Splat: + {splat_name} + + {generation !== null && ( + + + Generation: + + + act('set_generation', { generation: value }) + } + /> + + )} + + {flavor_text && ( + + {flavor_text} + + )} + + + + {headshot && } + + + +
+ + {is_editing_character ? ( +
+ + + + + + + CHARACTER IS BEING EDITED + + + + +
For safety, you cannot make changes to {target_ckey}'s sheet while they have the character setup menu open.
+ You should probably ask {target_ckey} to spawn in, just to be safe.
+
+
+
+
+ ) : ( + <> + {discipline_validation && ( +
+ + + Total disciplines: + 5 ? 'red' : 'white'}> + {discipline_validation.total} / 5 + + + + Non-Clan Rares: + = 2 ? 'red' : 'white'}> + {discipline_validation.additional_rare} + + + + {is_trusted ? ( + + Trusted + + ) : ( + <> + + Untrusted + + + {discipline_validation.valid ? ( + In compliance + ) : ( + + + Invalid Configuration + + + )} + + + )} + + +
+ )} + {splat_name === 'Human' ? ( + + This character cannot be assigned disciplines or gifts. + + ) : ( + + {disciplineEntries.map(([path, discipline]) => { + const level = levels[path] ?? 0; + const isOwned = path in levels; + return ( + handleDotClick(path, position, level)} + onRemove={handleRemove} + /> + ); + })} + + )} + + )} + + )} +
+
+
+
+ ); +} diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/MainPage.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/MainPage.tsx index df6248910953..cd9a3ecb6c9c 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/MainPage.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/MainPage.tsx @@ -12,11 +12,13 @@ import { NumberInput, // DARKPACK EDIT Section, Stack, + Icon, // DARKPACK EDIT ADD } from 'tgui-core/components'; import { exhaustiveCheck } from 'tgui-core/exhaustive'; // DARKPACK EDIT ADD import { classes } from 'tgui-core/react'; import { createSearch } from 'tgui-core/string'; import { CharacterPreview } from '../../common/CharacterPreview'; +import { ConfirmModal } from '../components/ConfirmModal'; // DARKPACK EDIT ADD import { PageButton } from '../components/PageButton'; // DARKPACK EDIT ADD import { RandomizationButton } from '../components/RandomizationButton'; import { features } from '../preferences/features'; @@ -36,6 +38,7 @@ import { useServerPrefs } from '../useServerPrefs'; import { DeleteCharacterPopup } from './DeleteCharacterPopup'; import { MultiNameInput, NameInput } from './names'; import { VocalsInput, VoiceInput } from './darkpack_vocals'; // DARKPACK EDIT ADDITION +import { TRUSTED_CLAN_WHITELIST_IDS } from '../preferences/features/character_preferences/darkpack_trusted_whitelist'; // DARKPACK EDIT ADD const CLOTHING_CELL_SIZE = 48; const CLOTHING_SIDEBAR_ROWS = 12; // DARKPACK EDIT CHANGE - ORIGINAL: 9; @@ -105,10 +108,11 @@ type ChoicedSelectionProps = { supplementalFeature?: string; supplementalValue?: unknown; onSelect: (value: string) => void; + isLocked?: (choice: string) => boolean; // DARKPACK EDIT ADD }; function ChoicedSelection(props: ChoicedSelectionProps) { - const { catalog, supplementalFeature, supplementalValue } = props; + const { catalog, supplementalFeature, supplementalValue, isLocked } = props; // DARKPACK EDIT CHANGE - ORIGINAL: const { catalog, supplementalFeature, supplementalValue } = props; const [searchText, setSearchText] = useState(''); if (!catalog.icons) { @@ -154,6 +158,7 @@ function ChoicedSelection(props: ChoicedSelectionProps) { {searchInCatalog(searchText, catalog.icons).map( ([name, image], index) => { + const locked = isLocked?.(name) ?? false; // DARKPACK EDIT ADD return ( ); }, @@ -257,6 +280,7 @@ type MainFeatureProps = { handleSelect: (newClothing: string) => void; randomization?: RandomSetting; setRandomization: (newSetting: RandomSetting) => void; + isLocked?: (choice: string) => boolean; // DARKPACK EDIT ADD }; function MainFeature(props: MainFeatureProps) { @@ -267,6 +291,7 @@ function MainFeature(props: MainFeatureProps) { handleSelect, randomization, setRandomization, + isLocked, // DARKPACK EDIT ADD } = props; const supplementalFeature = catalog.supplemental_feature; @@ -288,6 +313,7 @@ function MainFeature(props: MainFeatureProps) { ] } onSelect={handleSelect} + isLocked={isLocked} // DARKPACK EDIT ADD /> } > @@ -464,6 +490,10 @@ export function MainPage(props: MainPageProps) { const [vocalsInputOpen, setVocalsInputOpen] = useState(false); // DARKPACK EDIT ADDITION const [randomToggleEnabled] = useRandomToggleState(); const [pendingConfirm, setPendingConfirm] = useState<(() => void) | null>(null); // DARKPACK EDIT ADD - for popups + // DARKPACK EDIT START + const whitelistSet = new Set(data.player_whitelists || []); + const isTrusted = whitelistSet.has('trusted'); + // DARKPACK EDIT END const serverData = useServerPrefs(); @@ -597,60 +627,13 @@ export function MainPage(props: MainPageProps) { )} {/* DARKPACK EDIT START - popup for clan, age, etc. changes */} {pendingConfirm !== null && ( - { + pendingConfirm?.(); + setPendingConfirm(null); }} - > - - - Change Character Details? - - - Changing significant character details (Clan, age, etc.) will wipe ALL of your existing disciplines. - This cannot be undone. Are you sure? - - - - - - - - - - - + onCancel={() => setPendingConfirm(null)} + /> )} {/* DARKPACK EDIT END*/} @@ -732,7 +715,14 @@ export function MainPage(props: MainPageProps) { } : baseSelect; // DARKPACK EDIT END - + // DARKPACK EDIT START - lock icons for whitelisted clans + const isChoiceLocked = clothingKey === 'vampire_clan' + ? (choice: string) => { + const whitelistId = TRUSTED_CLAN_WHITELIST_IDS[choice]; + return !!whitelistId && !isTrusted && !whitelistSet.has(whitelistId); + } + : undefined; + // DARKPACK EDIT END return ( {!catalog ? ( @@ -745,6 +735,7 @@ export function MainPage(props: MainPageProps) { handleSelect={handleSelect} randomization={randomizationOfMainFeatures[clothingKey]} setRandomization={createSetRandomization(clothingKey)} + isLocked={isChoiceLocked} // DARKPACK EDIT ADD /> )} diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/SplatsPage.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/SplatsPage.tsx index aa6cca155333..dad505685942 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/SplatsPage.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/SplatsPage.tsx @@ -1,6 +1,8 @@ // THIS IS A DARKPACK UI FILE +import { useState } from 'react'; // DARKPACK EDIT ADD import { useBackend } from 'tgui/backend'; +import { ConfirmModal } from '../components/ConfirmModal'; // DARKPACK EDIT ADD import { BlockQuote, Box, @@ -112,6 +114,10 @@ type SplatsPageInnerProps = { function SplatsPageInner(props: SplatsPageInnerProps) { const { act, data } = useBackend(); const setSplats = createSetPreference(act, 'splats'); + // DARKPACK EDIT START + const [pendingConfirm, setPendingConfirm] = useState<(() => void) | null>(null,); + const whitelistSet = new Set(data.player_whitelists || []); + // DARKPACK EDIT END const splats: [string, Splats][] = Object.entries(props.splats).map( ([splats, data]) => { @@ -142,24 +148,51 @@ function SplatsPageInner(props: SplatsPageInnerProps) { {splats.map(([splatsKey, splats]) => { + const isLocked = !!splatsKey && !whitelistSet.has(splatsKey); return ( ); })} @@ -214,6 +247,17 @@ function SplatsPageInner(props: SplatsPageInnerProps) { + {/* DARKPACK EDIT START - confirm dialog for splat changes */} + {pendingConfirm !== null && ( + { + pendingConfirm?.(); + setPendingConfirm(null); + }} + onCancel={() => setPendingConfirm(null)} + /> + )} + {/* DARKPACK EDIT END */} ); } diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/components/ConfirmModal.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/components/ConfirmModal.tsx new file mode 100644 index 000000000000..56b5726e027d --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/components/ConfirmModal.tsx @@ -0,0 +1,62 @@ +// THIS IS A DARKPACK UI FILE + +import { Box, Button, Stack } from 'tgui-core/components'; + +const DEFAULT_BODY = "Changing significant character details (Clan, age, etc.) will wipe ALL of your existing disciplines. This cannot be undone. Are you sure?"; + +type Props = { + title?: string; + body?: string; + onConfirm: () => void; + onCancel: () => void; +}; + +export function ConfirmModal(props: Props) { + const { title = 'Change Character Details?', body = DEFAULT_BODY, onConfirm, onCancel } = props; + + return ( + + + + {title} + + + {body} + + + + + + + + + + + + ); +} diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/darkpack_height.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/darkpack_height.tsx index def14e845419..9666f8bcce2e 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/darkpack_height.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/darkpack_height.tsx @@ -1,23 +1,62 @@ // THIS IS A DARKPACK UI FILE -import { type FeatureNumeric, type FeatureValueProps, type FeatureNumericData, FeatureNumberInput } from '../base'; -import { Stack, Box } from 'tgui-core/components'; - +// DARKPACK EDIT START +import { useState } from 'react'; +import { Button, Slider, Stack } from 'tgui-core/components'; +import { type FeatureNumeric, type FeatureValueProps, type FeatureNumericData } from '../base'; +// DARKPACK EDIT END type HeightServerData = FeatureNumericData & { height_labels: Record; }; +// DARKPACK EDIT START - height slider v2 +// on the back end, the height value 6 is around 4'10, which is 58 inches according to google so thats our baseline +const minimum_height = 58; // // DARKPACK EDIT - heights are integers on the back end, which sucks, but we cope by doing math on the front end i guess function HeightInput(props: FeatureValueProps) { + const { serverData, handleSetValue, value } = props; + const min = serverData?.minimum ?? 6; + const max = serverData?.maximum ?? 18; + const serverStep = serverData?.step ?? 2; // increments of 2. theres only 7 'real' heights, or height values that change the sprite + const inchSpan = serverData ? (max - min) * serverStep : 24; // all possible front end values, where only half are actual back end values. its written like this in-case some stinker goes and changes one of the height values, it doesnt brick saves + const [displayInch, setDisplayInch] = useState((value - min) * serverStep); + + // setting the (invisible, remove format() if you need this to make sense) slider value to 4 is floor(4/4)*2+6 and turns into a back end value of 8, or 5'2" on the front end. i think that's math:tm:. please dont judge me if im doing this wrong + // setting it to 8 is floor(8/4)*2+6, or 10 on the back end (which is a defined height value!!), front end is 5'6". bc theres a back end value on the new number, we update the sprite! yippee! + const snapToBackend = (inch: number) => min + Math.floor(inch / (serverStep * serverStep)) * serverStep; + const inches = minimum_height + displayInch; + const label = `${Math.floor(inches / 12)}'${inches % 12}"`; + const adjust = (delta: number) => { + const next = Math.max(0, Math.min(inchSpan, displayInch + delta)); + setDisplayInch(next); + handleSetValue(snapToBackend(next)); + }; return ( - - - - - - {props.serverData?.height_labels[props.value]} - - + <> + + +