diff --git a/SQL/paradise_schema.sql b/SQL/paradise_schema.sql index 9bfc6fa90b0..0b450df9848 100644 --- a/SQL/paradise_schema.sql +++ b/SQL/paradise_schema.sql @@ -274,6 +274,7 @@ CREATE TABLE `player` ( `nanoui_fancy` smallint(4) DEFAULT '1', `show_ghostitem_attack` smallint(4) DEFAULT '1', `lastchangelog` varchar(32) NOT NULL DEFAULT '0', + `exp` mediumtext, PRIMARY KEY (`id`), UNIQUE KEY `ckey` (`ckey`) ) ENGINE=InnoDB AUTO_INCREMENT=32446 DEFAULT CHARSET=latin1; diff --git a/SQL/paradise_schema_prefixed.sql b/SQL/paradise_schema_prefixed.sql index c0cc8c86d6b..2489e6cb325 100644 --- a/SQL/paradise_schema_prefixed.sql +++ b/SQL/paradise_schema_prefixed.sql @@ -273,6 +273,7 @@ CREATE TABLE `SS13_player` ( `nanoui_fancy` smallint(4) DEFAULT '1', `show_ghostitem_attack` smallint(4) DEFAULT '1', `lastchangelog` varchar(32) NOT NULL DEFAULT '0', + `exp` mediumtext, PRIMARY KEY (`id`), UNIQUE KEY `ckey` (`ckey`) ) ENGINE=InnoDB AUTO_INCREMENT=32446 DEFAULT CHARSET=latin1; diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm index d39cc600221..05200eea7dd 100644 --- a/code/__DEFINES/preferences.dm +++ b/code/__DEFINES/preferences.dm @@ -27,3 +27,10 @@ #define DONATOR_PUBLIC 32768 #define TOGGLES_DEFAULT (CHAT_OOC|CHAT_DEAD|CHAT_GHOSTEARS|CHAT_GHOSTSIGHT|CHAT_PRAYER|CHAT_RADIO|CHAT_ATTACKLOGS|CHAT_LOOC|MEMBER_PUBLIC|DONATOR_PUBLIC) + +// Playtime tracking system, see jobs_exp.dm +#define EXP_TYPE_LIVING "Living" +#define EXP_TYPE_CREW "Crew" +#define EXP_TYPE_SPECIAL "Special" +#define EXP_TYPE_GHOST "Ghost" +#define EXP_TYPE_EXEMPT "Exempt" \ No newline at end of file diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 9ac4a0eb4d6..2b5f80d7249 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -127,6 +127,10 @@ var/use_age_restriction_for_jobs = 0 //Do jobs use account age restrictions? --requires database var/use_age_restriction_for_antags = 0 //Do antags use account age restrictions? --requires database + var/use_exp_tracking = 0 + var/use_exp_restrictions = 0 + var/use_exp_restrictions_admin_bypass = 0 + var/simultaneous_pm_warning_timeout = 100 var/assistant_maint = 0 //Do assistants get maint access? @@ -240,6 +244,15 @@ if("use_age_restriction_for_antags") config.use_age_restriction_for_antags = 1 + if("use_exp_tracking") + config.use_exp_tracking = 1 + + if("use_exp_restrictions") + config.use_exp_restrictions = 1 + + if("use_exp_restrictions_admin_bypass") + config.use_exp_restrictions_admin_bypass = 1 + if("jobs_have_minimal_access") config.jobs_have_minimal_access = 1 diff --git a/code/game/jobs/job/engineering.dm b/code/game/jobs/job/engineering.dm index a8846f2134a..0384276a5e6 100644 --- a/code/game/jobs/job/engineering.dm +++ b/code/game/jobs/job/engineering.dm @@ -17,7 +17,8 @@ access_heads, access_construction, access_sec_doors, access_ce, access_RC_announce, access_keycard_auth, access_tcomsat, access_minisat, access_mechanic, access_mineral_storeroom) minimal_player_age = 21 - + exp_requirements = 600 + exp_type = EXP_TYPE_CREW equip(var/mob/living/carbon/human/H) if(!H) return 0 @@ -51,7 +52,6 @@ minimal_access = list(access_eva, access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_external_airlocks, access_construction, access_mineral_storeroom) alt_titles = list("Maintenance Technician","Engine Technician","Electrician") minimal_player_age = 7 - equip(var/mob/living/carbon/human/H) if(!H) return 0 H.equip_or_collect(new /obj/item/device/radio/headset/headset_eng(H), slot_l_ear) @@ -83,7 +83,6 @@ minimal_access = list(access_eva, access_atmospherics, access_maint_tunnels, access_external_airlocks, access_emergency_storage, access_construction, access_mineral_storeroom) alt_titles = list("Atmospheric Technician") minimal_player_age = 7 - equip(var/mob/living/carbon/human/H) if(!H) return 0 H.equip_or_collect(new /obj/item/device/radio/headset/headset_eng(H), slot_l_ear) diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm index 104ed27bc05..52a33e0f0fb 100644 --- a/code/game/jobs/job/job.dm +++ b/code/game/jobs/job/job.dm @@ -41,6 +41,9 @@ //If you have use_age_restriction_for_jobs config option enabled and the database set up, this option will add a requirement for players to be at least minimal_player_age days old. (meaning they first signed in at least that many days before.) var/minimal_player_age = 0 + var/exp_requirements = 0 + var/exp_type = "" + var/admin_only = 0 var/spawn_ert = 0 diff --git a/code/game/jobs/job/medical.dm b/code/game/jobs/job/medical.dm index 1baceb6a57e..64b34a4fa79 100644 --- a/code/game/jobs/job/medical.dm +++ b/code/game/jobs/job/medical.dm @@ -15,6 +15,8 @@ access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce, access_keycard_auth, access_sec_doors, access_psychiatrist, access_maint_tunnels, access_paramedic, access_mineral_storeroom) minimal_player_age = 21 + exp_requirements = 600 + exp_type = EXP_TYPE_CREW equip(var/mob/living/carbon/human/H) if(!H) return 0 @@ -109,7 +111,6 @@ alt_titles = list("Pharmacist","Pharmacologist") minimal_player_age = 7 - equip(var/mob/living/carbon/human/H) if(!H) return 0 switch(H.backbag) diff --git a/code/game/jobs/job/science.dm b/code/game/jobs/job/science.dm index f03f5b4c0a1..7ea2eb5464f 100644 --- a/code/game/jobs/job/science.dm +++ b/code/game/jobs/job/science.dm @@ -17,6 +17,8 @@ access_research, access_robotics, access_xenobiology, access_ai_upload, access_RC_announce, access_keycard_auth, access_tcomsat, access_gateway, access_xenoarch, access_minisat, access_maint_tunnels, access_mineral_storeroom) minimal_player_age = 21 + exp_requirements = 600 + exp_type = EXP_TYPE_CREW // All science-y guys get bonuses for maxing out their tech. required_objectives=list( diff --git a/code/game/jobs/job/security.dm b/code/game/jobs/job/security.dm index 47532f8d081..19539a83f4e 100644 --- a/code/game/jobs/job/security.dm +++ b/code/game/jobs/job/security.dm @@ -17,6 +17,8 @@ access_research, access_engine, access_mining, access_medical, access_construction, access_mailsorting, access_heads, access_hos, access_RC_announce, access_keycard_auth, access_gateway, access_pilot, access_weapons) minimal_player_age = 21 + exp_requirements = 600 + exp_type = EXP_TYPE_CREW equip(var/mob/living/carbon/human/H) if(!H) return 0 @@ -56,6 +58,8 @@ access = list(access_security, access_sec_doors, access_brig, access_armory, access_court, access_maint_tunnels, access_morgue, access_weapons) minimal_access = list(access_security, access_sec_doors, access_brig, access_armory, access_court, access_maint_tunnels, access_weapons) minimal_player_age = 21 + exp_requirements = 300 + exp_type = EXP_TYPE_CREW equip(var/mob/living/carbon/human/H) if(!H) return 0 @@ -98,6 +102,8 @@ minimal_access = list(access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels, access_court, access_weapons) alt_titles = list("Forensic Technician") minimal_player_age = 14 + exp_requirements = 300 + exp_type = EXP_TYPE_CREW equip(var/mob/living/carbon/human/H) if(!H) return 0 H.equip_or_collect(new /obj/item/device/radio/headset/headset_sec/alt(H), slot_l_ear) @@ -148,6 +154,8 @@ access = list(access_security, access_sec_doors, access_brig, access_court, access_maint_tunnels, access_morgue, access_weapons) minimal_access = list(access_security, access_sec_doors, access_brig, access_court, access_maint_tunnels, access_weapons) minimal_player_age = 14 + exp_requirements = 300 + exp_type = EXP_TYPE_CREW equip(var/mob/living/carbon/human/H) if(!H) return 0 H.equip_or_collect(new /obj/item/device/radio/headset/headset_sec/alt(H), slot_l_ear) diff --git a/code/game/jobs/job/silicon.dm b/code/game/jobs/job/silicon.dm index 7bb2b006f87..eedb50a8412 100644 --- a/code/game/jobs/job/silicon.dm +++ b/code/game/jobs/job/silicon.dm @@ -8,6 +8,8 @@ supervisors = "your laws" req_admin_notify = 1 minimal_player_age = 30 + exp_requirements = 600 + exp_type = EXP_TYPE_CREW equip(var/mob/living/carbon/human/H) if(!H) return 0 @@ -15,7 +17,7 @@ /datum/job/ai/is_position_available() return (empty_playable_ai_cores.len != 0) - + /datum/job/cyborg title = "Cyborg" @@ -26,6 +28,8 @@ supervisors = "your laws and the AI" //Nodrak selection_color = "#ddffdd" minimal_player_age = 21 + exp_requirements = 300 + exp_type = EXP_TYPE_CREW alt_titles = list("Android", "Robot") equip(var/mob/living/carbon/human/H) diff --git a/code/game/jobs/job/supervisor.dm b/code/game/jobs/job/supervisor.dm index 66f0ddb2c65..586fd27d639 100644 --- a/code/game/jobs/job/supervisor.dm +++ b/code/game/jobs/job/supervisor.dm @@ -12,6 +12,8 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1) access = list() //See get_access() minimal_access = list() //See get_access() minimal_player_age = 30 + exp_requirements = 600 + exp_type = EXP_TYPE_CREW equip(var/mob/living/carbon/human/H) if(!H) return 0 H.equip_or_collect(new /obj/item/device/radio/headset/heads/captain/alt(H), slot_l_ear) @@ -56,6 +58,8 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1) idtype = /obj/item/weapon/card/id/silver req_admin_notify = 1 minimal_player_age = 21 + exp_requirements = 600 + exp_type = EXP_TYPE_CREW access = list(access_security, access_sec_doors, access_brig, access_court, access_forensics_lockers, access_medical, access_engine, access_change_ids, access_ai_upload, access_eva, access_heads, access_all_personal_lockers, access_maint_tunnels, access_bar, access_janitor, access_construction, access_morgue, diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm index 9073f56ceb3..93d048ce96e 100644 --- a/code/game/jobs/job_controller.dm +++ b/code/game/jobs/job_controller.dm @@ -123,6 +123,9 @@ var/global/datum/controller/occupations/job_master if(job.admin_only) // No admin positions either. continue + if(job.available_in_playtime(player.client)) + continue + if(jobban_isbanned(player, job.title)) Debug("GRJ isbanned failed, Player: [player], Job: [job.title]") continue diff --git a/code/game/jobs/job_exp.dm b/code/game/jobs/job_exp.dm new file mode 100644 index 00000000000..520b1182e49 --- /dev/null +++ b/code/game/jobs/job_exp.dm @@ -0,0 +1,190 @@ +// Admin Verbs + +/client/proc/cmd_admin_check_player_exp() //Allows admins to determine who the newer players are. + set category = "Admin" + set name = "Check Player Playtime" + if(!check_rights(R_ADMIN)) + return + var/msg = "Playtime ReportPlaytime:
" + src << browse(msg, "window=Player_playtime_check") + + +/datum/admins/proc/cmd_show_exp_panel(var/client/C) + if(!C) + to_chat(usr, "ERROR: Client not found.") + return + if(!check_rights(R_ADMIN)) + return + var/body = "Playtime for [C.key]
Playtime:" + body += C.get_exp_report() + body += "" + usr << browse(body, "window=playerplaytime[C.ckey];size=550x615") + + +// Procs + + +/datum/job/proc/available_in_playtime(client/C) + if(!C) + return 0 + if(!exp_requirements || !exp_type) + return 0 + if(!config.use_exp_restrictions) + return 0 + if(config.use_exp_restrictions_admin_bypass && check_rights(R_ADMIN, 0, C.mob)) + return 0 + var/list/play_records = params2list(C.prefs.exp) + var/isexempt = text2num(play_records[EXP_TYPE_EXEMPT]) + if(isexempt) + return 0 + var/my_exp = text2num(play_records[get_exp_req_type()]) + var/job_requirement = text2num(get_exp_req_amount()) + if(my_exp >= job_requirement) + return 0 + else + return (job_requirement - my_exp) + +/datum/job/proc/get_exp_req_amount() + return exp_requirements + +/datum/job/proc/get_exp_req_type() + return exp_type + +/mob/proc/get_exp_report() + if(client) + return client.get_exp_report() + else + return "[src] has no client." + +/client/proc/get_exp_report() + if(!config.use_exp_tracking) + return "Tracking is disabled in the server configuration file." + var/list/play_records = params2list(prefs.exp) + if(!play_records.len) + return "[key] has no records." + var/return_text = "" + var/list/jobs_locked = list() + var/list/jobs_unlocked = list() + for(var/datum/job/job in job_master.occupations) + if(job.exp_requirements && job.exp_type) + if(!job.available_in_playtime(mob.client)) + jobs_unlocked += job.title + else + var/xp_req = job.get_exp_req_amount() + jobs_locked += "[job.title] [get_exp_format(text2num(play_records[job.get_exp_req_type()]))] / [get_exp_format(xp_req)] as [job.get_exp_req_type()])" + if(jobs_unlocked.len) + return_text += "

Jobs Unlocked:" + if(jobs_locked.len) + return_text += "

Jobs Not Unlocked:" + return return_text + + +/client/proc/get_exp_living() + var/list/play_records = params2list(prefs.exp) + var/exp_living = text2num(play_records[EXP_TYPE_LIVING]) + return get_exp_format(exp_living) + +/proc/get_exp_format(var/expnum) + if(expnum > 60) + return num2text(round(expnum / 60)) + "h" + else if(expnum > 0) + return num2text(expnum) + "m" + else + return "0h" + +/proc/update_exp(var/mins, var/ann = 0) + if(!establish_db_connection()) + return -1 + spawn(0) + for(var/client/L in clients) + if(L.inactivity >= (10 MINUTES)) + continue + spawn(0) + L.update_exp_client(mins, ann) + sleep(10) + +/client/proc/update_exp_client(var/minutes, var/announce_changes = 0) + if(!src ||!ckey) + return + var/DBQuery/exp_read = dbcon.NewQuery("SELECT exp FROM [format_table_name("player")] WHERE ckey='[ckey]'") + if(!exp_read.Execute()) + var/err = exp_read.ErrorMsg() + log_game("SQL ERROR during exp_update_client read. Error : \[[err]\]\n") + message_admins("SQL ERROR during exp_update_client read. Error : \[[err]\]\n") + return + var/list/read_records = list() + var/hasread = 0 + while(exp_read.NextRow()) + read_records = params2list(exp_read.item[1]) + hasread = 1 + if(!hasread) + return + var/list/play_records = list() + for(var/rtype in exp_jobsmap) + if(text2num(read_records[rtype])) + play_records[rtype] = text2num(read_records[rtype]) + else + play_records[rtype] = 0 + if(mob.stat == CONSCIOUS && mob.mind.assigned_role) + play_records[EXP_TYPE_LIVING] += minutes + if(announce_changes) + to_chat(mob,"You got: [minutes] Living EXP!") + for(var/category in exp_jobsmap) + if(exp_jobsmap[category]["titles"]) + if(mob.mind.assigned_role in exp_jobsmap[category]["titles"]) + play_records[category] += minutes + if(announce_changes) + to_chat(mob,"You got: [minutes] [category] EXP!") + if(mob.mind.special_role) + play_records[EXP_TYPE_SPECIAL] += minutes + if(announce_changes) + to_chat(mob,"You got: [minutes] Special EXP!") + else if(isobserver(mob)) + play_records[EXP_TYPE_GHOST] += minutes + if(announce_changes) + to_chat(mob,"You got: [minutes] Ghost EXP!") + else + return + var/new_exp = list2params(play_records) + prefs.exp = new_exp + new_exp = sanitizeSQL(new_exp) + var/DBQuery/update_query = dbcon.NewQuery("UPDATE [format_table_name("player")] SET exp = '[new_exp]' WHERE ckey='[ckey]'") + if(!update_query.Execute()) + var/err = update_query.ErrorMsg() + log_game("SQL ERROR during exp_update_client write. Error : \[[err]\]\n") + message_admins("SQL ERROR during exp_update_client write. Error : \[[err]\]\n") + return + +/hook/roundstart/proc/exptimer() + if(!config.sql_enabled || !config.use_exp_tracking) + return 1 + spawn(0) + while(TRUE) + sleep(5 MINUTES) + update_exp(5,0) + return 1 diff --git a/code/game/jobs/jobs.dm b/code/game/jobs/jobs.dm index 6af69ebed9d..73f5cc2e5b0 100644 --- a/code/game/jobs/jobs.dm +++ b/code/game/jobs/jobs.dm @@ -183,3 +183,10 @@ var/list/whitelisted_positions = list( return titles +var/global/list/exp_jobsmap = list( + EXP_TYPE_LIVING = list(), // all living mobs + EXP_TYPE_CREW = list(titles = command_positions | engineering_positions | medical_positions | science_positions | support_positions | supply_positions | security_positions | civilian_positions | list("AI","Cyborg") | whitelisted_positions), // crew positions + EXP_TYPE_SPECIAL = list(), // antags, ERT, etc + EXP_TYPE_GHOST = list(), // dead people, observers + EXP_TYPE_EXEMPT = list() // special grandfather setting +) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 72de785456e..88a0c7708f0 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -41,7 +41,8 @@ var/global/nologevent = 0 body += "Options panel for [M]" if(M.client) body += " played by [M.client] " - body += "\[[M.client.holder ? M.client.holder.rank : "Player"]\]" + body += "\[[M.client.holder ? M.client.holder.rank : "Player"]\] " + body += "\[" + M.client.get_exp_living() + "\]" if(istype(M, /mob/new_player)) body += " Hasn't Entered Game " diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index ba46a995ffd..f3cf5c920db 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -75,6 +75,7 @@ var/list/admin_verbs_admin = list( /client/proc/debug_variables, /client/proc/show_snpc_verbs, /client/proc/reset_all_tcs, /*resets all telecomms scripts*/ + /client/proc/cmd_admin_check_player_exp, /* shows players by playtime */ /client/proc/toggle_mentor_chat ) var/list/admin_verbs_ban = list( diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 3b8e33d04f8..aeb00df710a 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -2009,6 +2009,15 @@ fax_panel(usr) + else if(href_list["getplaytimewindow"]) + if(!check_rights(R_ADMIN)) + return + var/mob/M = locateUID(href_list["getplaytimewindow"]) + if(!M) + to_chat(usr, "ERROR: Mob not found.") + return + cmd_show_exp_panel(M.client) + else if(href_list["jumpto"]) if(!check_rights(R_ADMIN)) return diff --git a/code/modules/client/preference/preferences.dm b/code/modules/client/preference/preferences.dm index c049852e3be..8f82ab7274f 100644 --- a/code/modules/client/preference/preferences.dm +++ b/code/modules/client/preference/preferences.dm @@ -82,6 +82,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts //game-preferences var/lastchangelog = "" //Saved changlog filesize to detect if there was a change + var/exp var/ooccolor = "#b82e00" var/be_special = list() //Special role selection var/UI_style = "Midnight" @@ -593,6 +594,10 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts if(jobban_isbanned(user, rank)) HTML += "[rank] \[BANNED]" continue + var/available_in_playtime = job.available_in_playtime(user.client) + if(available_in_playtime) + HTML += "[rank] \[ " + get_exp_format(available_in_playtime) + " as " + job.get_exp_req_type() + "" + continue if(!job.player_old_enough(user.client)) var/available_in_days = job.available_in_days(user.client) HTML += "[rank] \[IN [(available_in_days)] DAYS]" diff --git a/code/modules/client/preference/preferences_mysql.dm b/code/modules/client/preference/preferences_mysql.dm index 1425f714183..581daf222d3 100644 --- a/code/modules/client/preference/preferences_mysql.dm +++ b/code/modules/client/preference/preferences_mysql.dm @@ -13,7 +13,8 @@ volume, nanoui_fancy, show_ghostitem_attack, - lastchangelog + lastchangelog, + exp FROM [format_table_name("player")] WHERE ckey='[C.ckey]'"} ) @@ -40,6 +41,7 @@ nanoui_fancy = text2num(query.item[11]) show_ghostitem_attack = text2num(query.item[12]) lastchangelog = query.item[13] + exp = query.item[14] //Sanitize ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor)) @@ -54,6 +56,7 @@ nanoui_fancy = sanitize_integer(nanoui_fancy, 0, 1, initial(nanoui_fancy)) show_ghostitem_attack = sanitize_integer(show_ghostitem_attack, 0, 1, initial(show_ghostitem_attack)) lastchangelog = sanitize_text(lastchangelog, initial(lastchangelog)) + exp = sanitize_text(exp, initial(exp)) return 1 /datum/preferences/proc/save_preferences(client/C) diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm index 0e354b4c4a6..fdc1ace289c 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone.dm @@ -285,6 +285,7 @@ if(player.mob && player.mob.mind) player.mob.mind.transfer_to(src) + player.mob.mind.assigned_role = "Drone" lawupdate = 0 to_chat(src, "Systems rebooted. Loading base pattern maintenance protocol... loaded.") diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index f8a73364264..3c5e3ac0130 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -244,8 +244,10 @@ if(!job.is_position_available()) return 0 if(jobban_isbanned(src,rank)) return 0 if(!is_job_whitelisted(src, rank)) return 0 - if(!job.player_old_enough(src.client)) return 0 + if(!job.player_old_enough(client)) return 0 if(job.admin_only && !(check_rights(R_EVENT, 0))) return 0 + if(job.available_in_playtime(client)) + return 0 if(config.assistantlimit) if(job.title == "Civilian") diff --git a/config/example/config.txt b/config/example/config.txt index 31bde9c5e4f..7c1b8d6051b 100644 --- a/config/example/config.txt +++ b/config/example/config.txt @@ -17,6 +17,13 @@ JOBS_HAVE_MINIMAL_ACCESS ## you have noone older than 0 days, since noone has been logged yet. Only turn this on once you have had the database up for 30 days. #USE_AGE_RESTRICTION_FOR_JOBS +##Unhash this to track player playtime in the database. Requires database to be enabled. +#USE_EXP_TRACKING +##Unhash this to enable playtime requirements for jobs that have them defined. +#USE_EXP_RESTRICTIONS +##Allows admins to bypass job playtime requirements. +USE_EXP_RESTRICTIONS_ADMIN_BYPASS + ## Unhash this entry to have certain antagonist roles require your account to be at least a certain number of days old to select. You can configure the exact age requirement for different antag roles by editing special_role_times in /code/modules/client/preferences.dm. ## See USE_AGE_RESTRICTION_FOR_JOBS for more information #USE_AGE_RESTRICTION_FOR_ANTAGS diff --git a/paradise.dme b/paradise.dme index 1f9b3430ba4..d27aa499fa0 100644 --- a/paradise.dme +++ b/paradise.dme @@ -465,6 +465,7 @@ #include "code\game\gamemodes\wizard\wizard.dm" #include "code\game\jobs\access.dm" #include "code\game\jobs\job_controller.dm" +#include "code\game\jobs\job_exp.dm" #include "code\game\jobs\job_objective.dm" #include "code\game\jobs\jobs.dm" #include "code\game\jobs\whitelist.dm"