diff --git a/code/__DEFINES/jobs.dm b/code/__DEFINES/jobs.dm index f0e668df7e..a58f813ef4 100644 --- a/code/__DEFINES/jobs.dm +++ b/code/__DEFINES/jobs.dm @@ -56,6 +56,7 @@ #define JOB_UNAVAILABLE_JOB_COOLDOWN 11 #define JOB_UNAVAILABLE_SLOTFULL 12 #define JOB_UNAVAILABLE_VIRTUESVICE 13 +#define JOB_UNAVAILABLE_AGEVET 14 #define DEFAULT_RELIGION "Christianity" #define DEFAULT_DEITY "Space Jesus" @@ -235,7 +236,7 @@ #define TUORO (1<<5) #define PAFANTO (1<<6) //heavy weapon technician - melee weapon and machine gun #define MULO (1<<7) // heavy weapon ammo bearer - stripped down soldato gear and ammo storage -#define SERVISTO (1<<8) //support role - can probably shit meds out the wazoo +#define SERVISTO (1<<8) //support role - can probably shit meds out the wazoo #define CURACISTO (1<<9) #define CAMPFOLLOWER (1<<10) #define CONSULO (1<<11) diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm index d8c1fa6988..ae84f6f853 100644 --- a/code/controllers/configuration/entries/general.dm +++ b/code/controllers/configuration/entries/general.dm @@ -440,6 +440,9 @@ /datum/config_entry/string/channel_announce_new_game_message default = null +/datum/config_entry/string/chat_announce_verify + config_entry_value = null + /datum/config_entry/flag/debug_admin_hrefs /datum/config_entry/number/mc_tick_rate/base_mc_tick_rate diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm index fb96d53166..d612e154ff 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -164,9 +164,14 @@ SUBSYSTEM_DEF(job) if(!job.special_job_check(player)) JobDebug("FOC player did not pass special check, Player: [player], Job:[job.title]") continue + if(job.agevet_req && !(player.client.ckey in GLOB.agevetted_list)) + JobDebug("FOC player is not agevetted, Player: [player], Job: [job.title]") + continue + if(CONFIG_GET(flag/usewhitelist)) if(job.whitelist_req && (!player.client.whitelisted())) continue + if(player.client.prefs.job_preferences[job.title] == level) JobDebug("FOC pass, Player: [player], Level:[level]") candidates += player @@ -252,6 +257,10 @@ SUBSYSTEM_DEF(job) JobDebug("GRJ player did not pass special check, Player: [player], Job:[job.title]") continue + if(job.agevet_req && !(player.client.ckey in GLOB.agevetted_list)) + JobDebug("GRJ player is not agevetted, Player: [player], Job: [job.title]") + continue + if(CONFIG_GET(flag/usewhitelist)) if(job.whitelist_req && (!player.client.whitelisted())) continue diff --git a/code/datums/sexcon/sexcon_helpers.dm b/code/datums/sexcon/sexcon_helpers.dm index d4fb09361a..e074e4c52a 100644 --- a/code/datums/sexcon/sexcon_helpers.dm +++ b/code/datums/sexcon/sexcon_helpers.dm @@ -61,6 +61,16 @@ if(!user?.client?.prefs.sexable) to_chat(user, "I don't want to touch [target]. (Your ERP preference, in the options)") return + if(!user.check_agevet()) + to_chat(user, "You're not age verified.") + log_combat(user, target, "tried ERP while non verified") + message_admins("[ADMIN_LOOKUPFLW(user)] has tried to use the ERP panel despite not being vetted.") + log_admin("[key_name(user)] has tried to use the ERP panel despite not being vetted.") + return + if(!target.check_agevet()) + to_chat(user, "[target] is not age verified.") + log_combat(user, target, "tried ERP against non verified") + return if(!target?.client?.prefs) to_chat(user, span_warning("[target] is simply not there. I can't do this.")) log_combat(user, target, "tried ERP menu against d/ced") @@ -180,7 +190,7 @@ if(my_demihuman || their_demihuman) return (my_demihuman && their_demihuman) return TRUE - + /mob/living/carbon/human/proc/try_impregnate(mob/living/carbon/human/wife) var/obj/item/organ/testicles/testes = getorganslot(ORGAN_SLOT_TESTICLES) if(!testes) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index dccf6e1704..ce1941a814 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -90,6 +90,16 @@ patron = initial(living.patron.name) body += "

Current Patron: [patron]" + var/idstatus = "
ID Status: " + if(!M.ckey) + idstatus += "No key!" + else if(!M.check_agevet()) + idstatus += "Unverified" + else + var/vetadmin = LAZYACCESS(GLOB.agevetted_list, M.ckey) + idstatus += "Age Verified by [vetadmin]" + body += idstatus + //Azure port. Incompatibility. /*var/curse_string = "" if(ishuman(M)) @@ -328,7 +338,7 @@ if(!check_rights()) return - + if(!M.ckey) to_chat(src, span_warning("There is no ckey attached to this mob.")) return diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index bfab60f4e4..5e207aaa04 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -38,6 +38,7 @@ GLOBAL_PROTECT(admin_verbs_default) /client/proc/admin_spread_effect, /client/proc/open_bounty_menu, /client/proc/remove_bounty, + /client/proc/agevet_player, // RATWOOD MODULAR START /client/proc/bunker_bypass, // RATWOOD MODULAR END @@ -887,7 +888,7 @@ GLOBAL_PROTECT(admin_verbs_hideable) scom_announce("An unknown force has erased the bounty on [target_name]. The gods are displeased.") message_admins("[ADMIN_LOOKUPFLW(src)] has removed the bounty on [ADMIN_LOOKUPFLW(target_name)]") return - to_chat(src, "Error. Bounty no longer active.") + to_chat(src, "Error. Bounty no longer active.") /client/proc/enable_browser_debug() set category = "Debug" diff --git a/code/modules/admin/agevetting.dm b/code/modules/admin/agevetting.dm new file mode 100644 index 0000000000..4e041b6c30 --- /dev/null +++ b/code/modules/admin/agevetting.dm @@ -0,0 +1,83 @@ +// This is almost entirely a copy paste of the Ratwood bunker system repurposed for adding in Age vetted people. +// Agevets matter more than simple whitelist access, so the approach is a bit different. +// We currently store age vets in an assoc list locally. +// The keys: player ckeys, values: the admin who added them. + +GLOBAL_LIST_INIT(agevetted_list, load_agevets_from_file()) +GLOBAL_PROTECT(agevetted_list) + +/client/proc/check_agevet() + if(LAZYACCESS(GLOB.agevetted_list, ckey) || holder) + return TRUE + return FALSE + +/mob/proc/check_agevet() + if(client) + return client.check_agevet() + if(LAZYACCESS(GLOB.agevetted_list, ckey) || copytext(key,1,2)=="@") //aghosted people stay verified + return TRUE + return FALSE + +/client/proc/agevet_player() + set category = "-Server-" + set name = "BC - Add Age Vetted" + + if(!check_rights()) + return + + var/selection = input("Who would you like to verify?", "CKEY", "") as text|null + if(selection) + if(alert(src, "Confirm: [selection] as being ID verified?", "Age Vetting", "Yes!", "No") == "Yes!") + add_agevet(selection, ckey, src) // keep the client ref to save us a duplicate list call + +/proc/add_agevet(target_ckey, admin_ckey = "SYSTEM", clientref) + if(!target_ckey || (target_ckey in GLOB.agevetted_list)) + return + + if(IsAdminAdvancedProcCall()) + return + + if(LAZYACCESS(GLOB.agevetted_list, target_ckey)) + to_chat(clientref, span_warning("The ckey \"[target_ckey]\" has already been ID vetted.")) + return + + target_ckey = ckey(target_ckey) + GLOB.agevetted_list[target_ckey] = admin_ckey + message_admins("ID VETTING: Added [target_ckey] to the agevetted list[admin_ckey? " by [admin_ckey]":""]") + log_admin("ID VETTING: Added [target_ckey] to the agevetted list[admin_ckey? " by [admin_ckey]":""]") + save_agevets_to_file() + log_agevet_to_csv(target_ckey, admin_ckey) + if(CONFIG_GET(string/chat_announce_verify)) + send2chat(new /datum/tgs_message_content("ID VETTING: Added [target_ckey] to the agevetted list[admin_ckey? " by [admin_ckey]":""]"), CONFIG_GET(string/chat_announce_verify)) + + // if they're online, notify + var/recipient = LAZYACCESS(GLOB.directory, target_ckey) + if(recipient) + to_chat(recipient, span_notice("Good news! You are now ID verified.")) + +// Read/write the assoc list. Player ckey maps to vetting admin ckey. +/proc/load_agevets_from_file() + var/json_file = file("data/agevets.json") + if(fexists(json_file)) + var/list/json = json_decode(file2text(json_file)) + return json + else + return list() + +/proc/save_agevets_to_file() + var/json_file = file("data/agevets.json") + var/list/file_data = list() + file_data = GLOB.agevetted_list + fdel(json_file) + WRITE_FILE(json_file,json_encode(file_data)) + +// for more convenient host oversight and perhaps an eventual database import. +/proc/log_agevet_to_csv(target_ckey, admin_ckey = "SYSTEM") + if(IsAdminAdvancedProcCall()) // sorry for using this twice + return + var/csv_file = file("data/agevets_log.csv") + var/current_date = time2text(world.timeofday, "YYYY-MM-DD") + if(!fexists(csv_file)) + var/csv_columns = "player_ckey,admin_ckey,datestamp,rogue_round_id" + WRITE_FILE(csv_file,csv_columns) + csv_file << "[target_ckey],[admin_ckey],[current_date],[GLOB.rogue_round_id]" diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm index 0c63179cd0..1f09425f12 100644 --- a/code/modules/admin/player_panel.dm +++ b/code/modules/admin/player_panel.dm @@ -246,7 +246,9 @@ M_job = "Observer" else M_job = "Ghost" - + var/M_vetstatus = "Unverified" + if(M.check_agevet()) + M_vetstatus = "Verified" var/M_name = html_encode(M.name) var/M_rname = html_encode(M.real_name) var/M_key = html_encode(M.key) @@ -266,7 +268,7 @@ - [M_name] - [M_rname] - [M_key] ([M_job]) + [M_name] - [M_rname] - [M_key] ([M_job]) - [M_vetstatus]
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 7e8a0d188a..af4ca41b9e 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -313,6 +313,13 @@ GLOBAL_LIST_EMPTY(chosen_names) dat += "" + var/agevetted = user.check_agevet() + dat += "" + dat += "VERIFIED: [agevetted ? "YAE!" : "NAE?"]" + dat += "" + + dat += "" + if(CONFIG_GET(flag/roundstart_traits)) dat += "

Quirk Setup

" dat += "Configure Quirks
" @@ -1267,6 +1274,12 @@ Slots: [job.spawn_positions] [job.round_contrib_points ? "RCP: +[job.round_contr else if(href_list["preference"] == "playerquality") check_pq_menu(user.ckey) + else if(href_list["preference"] == "agevet") + if(!user.check_agevet()) + to_chat(usr, span_info("- You are currently not AGE-VERIFIED limiting your access to the server. To get access to more features, age-verify through the discord.")) + else + to_chat(usr, span_love("- You have been successfully AGE-VERIFIED!")) + else if(href_list["preference"] == "markings") ShowMarkings(user) return @@ -1892,7 +1905,7 @@ Slots: [job.spawn_positions] [job.round_contrib_points ? "RCP: +[job.round_contr charflaw = C if(charflaw.desc) to_chat(user, "[charflaw.desc]") - else + else var/result = input(user, "Select a flaw", "Roguetown") as null|anything in elf_flaw if(result) result = elf_flaw[result] diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm index 62e0dc1b7b..7e0b034772 100644 --- a/code/modules/jobs/job_types/_job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -87,6 +87,7 @@ var/tutorial = null var/whitelist_req = FALSE + var/agevet_req = TRUE var/bypass_jobban = FALSE var/bypass_lastclass = TRUE diff --git a/code/modules/jobs/job_types/roguetown/perserdunian/armsman.dm b/code/modules/jobs/job_types/roguetown/perserdunian/armsman.dm index 4234bac3fd..13c2aba295 100644 --- a/code/modules/jobs/job_types/roguetown/perserdunian/armsman.dm +++ b/code/modules/jobs/job_types/roguetown/perserdunian/armsman.dm @@ -5,13 +5,14 @@ faction = "Station" total_positions = 16 spawn_positions = 16 + agevet_req = FALSE allowed_races = RACES_CONSCRIPT allowed_sexes = list(MALE, FEMALE) allowed_ages = list(AGE_ADULT, AGE_MIDDLEAGED) tutorial = "You are the rank and file soldier of the Great Empire of Perserdun. \ Your main purpose is to bundle together with other Armsmen and to kill the enemies of the Empire. \ - Typically, Armsmen are filled with a great love for their nation and volunteer. Others are conscripted, or are convicts." + Typically, Armsmen are filled with a great love for their nation and volunteer. Others are conscripted, or are convicts." outfit = /datum/outfit/job/roguetown/armsman display_order = JDO_ARMSMAN diff --git a/code/modules/jobs/job_types/roguetown/risvonian/soldato.dm b/code/modules/jobs/job_types/roguetown/risvonian/soldato.dm index 69d63ebb70..b0edf797b7 100644 --- a/code/modules/jobs/job_types/roguetown/risvonian/soldato.dm +++ b/code/modules/jobs/job_types/roguetown/risvonian/soldato.dm @@ -5,6 +5,7 @@ faction = "Station" total_positions = 16 spawn_positions = 16 + agevet_req = FALSE allowed_races = RACES_CONSCRIPT allowed_sexes = list(MALE, FEMALE) allowed_ages = list(AGE_ADULT, AGE_MIDDLEAGED) diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index 8f938c5080..a531314c5b 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -329,6 +329,8 @@ GLOBAL_LIST_INIT(roleplay_readme, world.file2list("strings/rt/rp_prompt.txt")) switch(retval) if(JOB_AVAILABLE) return "[jobtitle] is available." + if(JOB_UNAVAILABLE_AGEVET) + return "[jobtitle] is restricted to agevetted players." if(JOB_UNAVAILABLE_GENERIC) return "[jobtitle] is unavailable." if(JOB_UNAVAILABLE_BANNED) @@ -394,6 +396,8 @@ GLOBAL_LIST_INIT(roleplay_readme, world.file2list("strings/rt/rp_prompt.txt")) if(CONFIG_GET(flag/usewhitelist)) if(job.whitelist_req && !client.whitelisted()) return JOB_UNAVAILABLE_GENERIC + if(job.agevet_req && !(ckey in GLOB.agevetted_list)) + return JOB_UNAVAILABLE_AGEVET if(!job.bypass_jobban) if(is_banned_from(ckey, rank)) return JOB_UNAVAILABLE_BANNED diff --git a/code/modules/mob/living/carbon/human/human_topic.dm b/code/modules/mob/living/carbon/human/human_topic.dm index a2542d1806..0b2b561977 100644 --- a/code/modules/mob/living/carbon/human/human_topic.dm +++ b/code/modules/mob/living/carbon/human/human_topic.dm @@ -35,6 +35,10 @@ GLOBAL_VAR_INIT(year_integer, text2num(year)) // = 2013??? dat += "
This is a LEGACY Profile from naive days of Psydon.
" if(valid_headshot_link(null, headshot_link, TRUE)) dat += ("
") + if(LAZYACCESS(GLOB.agevetted_list, ckey) || holder) + dat += ("
AGE VERIFIED
") + else + dat += ("
NON VERIFIED
") if(flavortext) dat += "
[flavortext_display]
" if(ooc_notes) @@ -171,14 +175,14 @@ GLOBAL_VAR_INIT(year_integer, text2num(year)) // = 2013??? if(!ishuman(src)) return var/success = FALSE - var/obscured_name = FALSE + var/obscured_name = FALSE var/static/list/unknown_names = list( "Unknown", "Unknown Man", "Unknown Woman", ) - + var/mob/living/carbon/human/H = src var/mob/living/carbon/human/user = usr var/intellectual = HAS_TRAIT(user, TRAIT_INTELLECTUAL) @@ -192,7 +196,7 @@ GLOBAL_VAR_INIT(year_integer, text2num(year)) // = 2013??? to_chat(user, span_info("They've moved too far away!")) return user.visible_message("[user] begins assessing [src].") - + if(do_mob(user, src, ((intellectual ? 20 : 40)) - (user.STAINT - 10) - (user.STAPER - 10) - user.get_skill_level(/datum/skill/misc/reading), uninterruptible = intellectual, double_progress = (intellectual ? FALSE : TRUE))) var/is_guarded = HAS_TRAIT(src, TRAIT_DECEIVING_MEEKNESS) //Will scramble Stats and prevent skills from being shown var/is_smart = FALSE //Maximum info (all skills, gear and stats) either Intellectual virtue or having high enough PER / INT / Reading @@ -200,7 +204,7 @@ GLOBAL_VAR_INIT(year_integer, text2num(year)) // = 2013??? var/is_normal = FALSE //High amount of info -- most gear slots, combat skills. No stats. //If you don't get any of these, you'll still get to see 3 gear slots and shown weapon skills in Assess. if(intellectual || ((user.STAINT - 10) + (user.STAPER - 10) + user.get_skill_level(/datum/skill/misc/reading)) >= 10) - is_smart = TRUE + is_smart = TRUE if(user.STAINT < 10 && !is_smart) is_stupid = TRUE if(!is_smart && !is_stupid && ((user.STAINT - 10) + (user.STAPER - 10) + user?.get_skill_level(/datum/skill/misc/reading)) >= 5) @@ -239,7 +243,7 @@ GLOBAL_VAR_INIT(year_integer, text2num(year)) // = 2013??? var/list/coverage_exposed = list(READABLE_ZONE_HEAD, READABLE_ZONE_CHEST, READABLE_ZONE_ARMS, READABLE_ZONE_L_ARM, READABLE_ZONE_R_ARM, READABLE_ZONE_LEGS, READABLE_ZONE_L_LEG, READABLE_ZONE_R_LEG, READABLE_ZONE_NOSE, READABLE_ZONE_MOUTH, READABLE_ZONE_EYES, READABLE_ZONE_NECK, READABLE_ZONE_VITALS, READABLE_ZONE_GROIN, READABLE_ZONE_HANDS, READABLE_ZONE_L_HAND, READABLE_ZONE_R_HAND, READABLE_ZONE_FEET, READABLE_ZONE_L_FOOT, READABLE_ZONE_R_FOOT) var/list/coverage = list() //All of the covered areas var/list/blunt_max = list() //Highest armor prot values - var/list/slash_max = list() + var/list/slash_max = list() var/list/stab_max = list() var/list/piercing_max = list() var/list/crit_weakness = list() //The critical damage type the zone will be weak to @@ -263,7 +267,7 @@ GLOBAL_VAR_INIT(year_integer, text2num(year)) // = 2013??? continue if(C.body_parts_covered_dynamic) readable_coverage = body_parts_covered2organ_names(C.body_parts_covered_dynamic, verbose = TRUE) - + if(length(C.prevent_crits) && (is_normal || is_smart)) for(var/critzone in C.prevent_crits) for(var/crit in critclasses) @@ -297,7 +301,7 @@ GLOBAL_VAR_INIT(year_integer, text2num(year)) // = 2013??? coverage_exposed.Remove(READABLE_ZONE_ARMS, READABLE_ZONE_R_ARM) //Since individual limbs can be exposed, this is needed for the accuracy / granularity of the printout. if(READABLE_ZONE_L_LEG) coverage_exposed.Remove(READABLE_ZONE_LEGS, READABLE_ZONE_L_LEG) //However it do be ugly. - if(READABLE_ZONE_R_LEG) + if(READABLE_ZONE_R_LEG) coverage_exposed.Remove(READABLE_ZONE_LEGS, READABLE_ZONE_R_LEG) if(READABLE_ZONE_L_HAND) coverage_exposed.Remove(READABLE_ZONE_HANDS, READABLE_ZONE_L_HAND) @@ -342,7 +346,7 @@ GLOBAL_VAR_INIT(year_integer, text2num(year)) // = 2013??? else coverage.Remove(READABLE_ZONE_FEET) else - coverage.Remove(READABLE_ZONE_FEET) + coverage.Remove(READABLE_ZONE_FEET) for(var/exposedzone in coverage_exposed) //We also filter out redundancies from the exposed remainder. Mostly L / Rs if there's a combined flag that slipped through. switch(exposedzone) if(READABLE_ZONE_HANDS) @@ -422,7 +426,7 @@ GLOBAL_VAR_INIT(year_integer, text2num(year)) // = 2013??? dat += "-----------------------
" else continue - + dat += "" dat += "" var/datum/browser/popup = new(user, "assess", ntitle = "[src] Assesment", nwidth = 1000, nheight = 600) @@ -528,7 +532,7 @@ GLOBAL_VAR_INIT(year_integer, text2num(year)) // = 2013??? str += crits str += "
---------------------------
" - + return str*/ /proc/skilldiff_report(var/input) diff --git a/config/config.txt b/config/config.txt index 0f6d2d0e30..f0e41f3701 100644 --- a/config/config.txt +++ b/config/config.txt @@ -471,6 +471,9 @@ MINUTE_CLICK_LIMIT 400 #CHANNEL_ANNOUNCE_NEW_GAME_MESSAGE A new round is beggining!! +## Send a message to the chat when a ckey is removed or added to verified +#CHAT_ANNOUNCE_VERIFY verify + ## Allow admin hrefs that don't use the new token system, will eventually be removed DEBUG_ADMIN_HREFS diff --git a/roguetown.dme b/roguetown.dme index c41795c905..316cc2cff6 100644 --- a/roguetown.dme +++ b/roguetown.dme @@ -1111,6 +1111,7 @@ #include "code\modules\admin\admin_ranks.dm" #include "code\modules\admin\admin_verbs.dm" #include "code\modules\admin\adminmenu.dm" +#include "code\modules\admin\agevetting.dm" #include "code\modules\admin\antag_panel.dm" #include "code\modules\admin\blacklist.dm" #include "code\modules\admin\chat_commands.dm"