Merge pull request #5224 from Kyep/jobs_unlock_system

Playtime Tracking
This commit is contained in:
Crazy Lemon
2017-01-03 18:06:28 -08:00
committed by GitHub
23 changed files with 281 additions and 8 deletions
+1
View File
@@ -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;
+1
View File
@@ -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;
+7
View File
@@ -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"
+13
View File
@@ -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
+2 -3
View File
@@ -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)
+3
View File
@@ -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
+2 -1
View File
@@ -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)
+2
View File
@@ -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(
+8
View File
@@ -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)
+5 -1
View File
@@ -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)
+4
View File
@@ -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,
+3
View File
@@ -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
+190
View File
@@ -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 = "<html><head><title>Playtime Report</title></head><body>Playtime:<BR><UL>"
for(var/client/C in clients)
msg += "<LI> - [key_name_admin(C)]: <A href='?_src_=holder;getplaytimewindow=[C.mob.UID()]'>" + C.get_exp_living() + "</a></LI>"
msg += "</UL></BODY></HTML>"
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 = "<html><head><title>Playtime for [C.key]</title></head><BODY><BR>Playtime:"
body += C.get_exp_report()
body += "</BODY></HTML>"
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 = "<UL>"
var/list/exp_data = list()
for(var/category in exp_jobsmap)
if(text2num(play_records[category]))
exp_data[category] = text2num(play_records[category])
else
exp_data[category] = 0
for(var/dep in exp_data)
if(exp_data[dep] > 0)
if(dep == EXP_TYPE_EXEMPT)
return_text += "<LI>Exempt (all jobs auto-unlocked)</LI>"
else if(exp_data[EXP_TYPE_LIVING] > 0)
var/my_pc = num2text(round(exp_data[dep]/exp_data[EXP_TYPE_LIVING]*100))
return_text += "<LI>[dep] [get_exp_format(exp_data[dep])] ([my_pc]%)</LI>"
else
return_text += "<LI>[dep] [get_exp_format(exp_data[dep])] </LI>"
if(config.use_exp_restrictions_admin_bypass && check_rights(R_ADMIN, 0, mob))
return_text += "<LI>Admin (all jobs auto-unlocked)</LI>"
return_text += "</UL>"
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 += "<BR><BR>Jobs Unlocked:<UL><LI>"
return_text += jobs_unlocked.Join("</LI><LI>")
return_text += "</LI></UL>"
if(jobs_locked.len)
return_text += "<BR><BR>Jobs Not Unlocked:<UL><LI>"
return_text += jobs_locked.Join("</LI><LI>")
return_text += "</LI></UL>"
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,"<span class='notice'>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,"<span class='notice'>You got: [minutes] [category] EXP!")
if(mob.mind.special_role)
play_records[EXP_TYPE_SPECIAL] += minutes
if(announce_changes)
to_chat(mob,"<span class='notice'>You got: [minutes] Special EXP!")
else if(isobserver(mob))
play_records[EXP_TYPE_GHOST] += minutes
if(announce_changes)
to_chat(mob,"<span class='notice'>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
+7
View File
@@ -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
)
+2 -1
View File
@@ -41,7 +41,8 @@ var/global/nologevent = 0
body += "<body>Options panel for <b>[M]</b>"
if(M.client)
body += " played by <b>[M.client]</b> "
body += "\[<A href='?_src_=holder;editrights=rank;ckey=[M.ckey]'>[M.client.holder ? M.client.holder.rank : "Player"]</A>\]"
body += "\[<A href='?_src_=holder;editrights=rank;ckey=[M.ckey]'>[M.client.holder ? M.client.holder.rank : "Player"]</A>\] "
body += "\[<A href='?_src_=holder;getplaytimewindow=[M.UID()]'>" + M.client.get_exp_living() + "</a>\]"
if(istype(M, /mob/new_player))
body += " <B>Hasn't Entered Game</B> "
+1
View File
@@ -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(
+9
View File
@@ -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
@@ -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 += "<del>[rank]</del></td><td><b> \[BANNED]</b></td></tr>"
continue
var/available_in_playtime = job.available_in_playtime(user.client)
if(available_in_playtime)
HTML += "<del>[rank]</del></td><td> \[ " + get_exp_format(available_in_playtime) + " as " + job.get_exp_req_type() + "</td></tr>"
continue
if(!job.player_old_enough(user.client))
var/available_in_days = job.available_in_days(user.client)
HTML += "<del>[rank]</del></td><td> \[IN [(available_in_days)] DAYS]</td></tr>"
@@ -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)
@@ -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, "<b>Systems rebooted</b>. Loading base pattern maintenance protocol... <b>loaded</b>.")
+3 -1
View File
@@ -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")
+7
View File
@@ -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
+1
View File
@@ -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"