diff --git a/SQL/feedback_schema.sql b/SQL/feedback_schema.sql
index 3fa0f7080d..ee8975263b 100644
--- a/SQL/feedback_schema.sql
+++ b/SQL/feedback_schema.sql
@@ -117,4 +117,11 @@ CREATE TABLE `erro_privacy` (
`ckey` varchar(32) NOT NULL,
`option` varchar(128) NOT NULL,
PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;
\ No newline at end of file
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;
+
+CREATE TABLE `vr_player_hours` (
+ `ckey` varchar(32) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL,
+ `department` varchar(64) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL,
+ `hours` double NOT NULL,
+ PRIMARY KEY (`ckey`,`department`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
\ No newline at end of file
diff --git a/code/controllers/configuration_vr.dm b/code/controllers/configuration_vr.dm
index f1298d4d61..6d6a922e9f 100644
--- a/code/controllers/configuration_vr.dm
+++ b/code/controllers/configuration_vr.dm
@@ -4,8 +4,9 @@
/datum/configuration
var/list/engine_map // Comma separated list of engines to choose from. Blank means fully random.
- var/assistants_ratio
- var/assistants_assured = 15 // Default 15, only used if the ratio is set though.
+ var/time_off = FALSE
+ var/limit_interns = -1 //Unlimited by default
+ var/limit_visitors = -1 //Unlimited by default
/hook/startup/proc/read_vs_config()
var/list/Lines = file2list("config/config.txt")
@@ -32,10 +33,6 @@
continue
switch (name)
- if ("assistants_ratio")
- config.assistants_ratio = text2num(value)
- if ("assistants_assured")
- config.assistants_assured = text2num(value)
if ("chat_webhook_url")
config.chat_webhook_url = value
if ("chat_webhook_key")
@@ -46,5 +43,11 @@
config.fax_export_dir = value
if ("items_survive_digestion")
config.items_survive_digestion = 1
+ if ("limit_interns")
+ config.limit_interns = text2num(value)
+ if ("limit_visitors")
+ config.limit_visitors = text2num(value)
+ if ("time_off")
+ config.time_off = TRUE
return 1
diff --git a/code/controllers/subsystems/persist_vr.dm b/code/controllers/subsystems/persist_vr.dm
new file mode 100644
index 0000000000..57375d5378
--- /dev/null
+++ b/code/controllers/subsystems/persist_vr.dm
@@ -0,0 +1,76 @@
+////////////////////////////////
+//// Paid Leave Subsystem
+//// For tracking how much department PTO time players have accured
+////////////////////////////////
+
+SUBSYSTEM_DEF(persist)
+ name = "Persist"
+ priority = 20
+ wait = 15 MINUTES
+ flags = SS_BACKGROUND|SS_NO_INIT|SS_KEEP_TIMING
+ runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME
+ var/list/currentrun = list()
+
+/datum/controller/subsystem/persist/fire(var/resumed = FALSE)
+ update_department_hours(resumed)
+
+// Do PTO Accruals
+/datum/controller/subsystem/persist/proc/update_department_hours(var/resumed = FALSE)
+ if(!config.time_off)
+ return
+
+ establish_db_connection()
+ if(!dbcon.IsConnected())
+ src.currentrun.Cut()
+ return
+ if(!resumed)
+ src.currentrun = human_mob_list.Copy()
+
+ //cache for sanic speed (lists are references anyways)
+ var/list/currentrun = src.currentrun
+ while (currentrun.len)
+ var/mob/M = currentrun[currentrun.len]
+ currentrun.len--
+ if (QDELETED(M) || !istype(M) || !M.mind || !M.client || TICKS2DS(M.client.inactivity) > wait)
+ continue
+
+ // Try and detect job and department of mob
+ var/datum/job/J = detect_job(M)
+ if(!istype(J) || !J.department || !J.timeoff_factor)
+ if (MC_TICK_CHECK)
+ return
+ continue
+
+ // Update client whatever
+ var/client/C = M.client
+ var/wait_in_hours = (wait / (1 HOUR)) * J.timeoff_factor
+ LAZYINITLIST(C.department_hours)
+ if(isnum(C.department_hours[J.department]))
+ C.department_hours[J.department] += wait_in_hours
+ else
+ C.department_hours[J.department] = wait_in_hours
+
+ // Okay we figured it out, lets update database!
+ var/sql_ckey = sql_sanitize_text(C.ckey)
+ var/sql_dpt = sql_sanitize_text(J.department)
+ var/sql_bal = text2num("[C.department_hours[J.department]]")
+ var/DBQuery/query = dbcon.NewQuery("INSERT INTO vr_player_hours (ckey, department, hours) VALUES ('[sql_ckey]', '[sql_dpt]', [sql_bal]) ON DUPLICATE KEY UPDATE hours = VALUES(hours)")
+ query.Execute()
+
+ if (MC_TICK_CHECK)
+ return
+
+// This proc tries to find the job datum of an arbitrary mob.
+/datum/controller/subsystem/persist/proc/detect_job(var/mob/M)
+ // Records are usually the most reliable way to get what job someone is.
+ var/datum/data/record/R = find_general_record("name", M.real_name)
+ if(R) // We found someone with a record.
+ var/recorded_rank = R.fields["real_rank"]
+ if(recorded_rank)
+ . = job_master.GetJob(recorded_rank)
+ if(.) return
+
+ // They have a custom title, aren't crew, or someone deleted their record, so we need a fallback method.
+ // Let's check the mind.
+ if(M.mind && M.mind.assigned_role)
+ . = job_master.GetJob(M.mind.assigned_role)
diff --git a/code/game/jobs/job/assistant.dm b/code/game/jobs/job/assistant.dm
index 50f22c6fef..8ac53caa85 100644
--- a/code/game/jobs/job/assistant.dm
+++ b/code/game/jobs/job/assistant.dm
@@ -1,23 +1,48 @@
+//VOREStation Edit - Basically this whole file
+/datum/job/intern
+ title = "Intern"
+ flag = INTERN
+ department = "Civilian"
+ department_flag = CIVILIAN
+ faction = "Station"
+ total_positions = -1
+ spawn_positions = -1
+ supervisors = "the staff from the departmen you're interning in"
+ selection_color = "#555555"
+ economic_modifier = 2
+ access = list() //See /datum/job/assistant/get_access()
+ minimal_access = list() //See /datum/job/assistant/get_access()
+ outfit_type = /decl/hierarchy/outfit/job/assistant
+ alt_titles = list("Apprentice Engineer","Medical Intern","Lab Assistant","Security Cadet","Jr. Cargo Tech") //VOREStation Edit
+//VOREStation Add
+/datum/job/intern/New()
+ ..()
+ total_positions = config.limit_interns
+ spawn_positions = config.limit_interns
+//VOREStation Add End
+
+// VOREStation Add
/datum/job/assistant
- title = "Assistant"
+ title = "Visitor"
flag = ASSISTANT
department = "Civilian"
department_flag = CIVILIAN
faction = "Station"
total_positions = -1
spawn_positions = -1
- supervisors = "absolutely everyone"
+ supervisors = "nobody! You don't work here"
selection_color = "#515151"
economic_modifier = 1
- access = list() //See /datum/job/assistant/get_access()
- minimal_access = list() //See /datum/job/assistant/get_access()
+ access = list()
+ minimal_access = list()
outfit_type = /decl/hierarchy/outfit/job/assistant
- alt_titles = list("Technical Assistant","Test Subject","Medical Intern","Research Assistant",
- "Visitor" = /decl/hierarchy/outfit/job/assistant/visitor,
- "Resident" = /decl/hierarchy/outfit/job/assistant/resident) //Test Subject is a VOREStation edit
-
+/datum/job/assistant/New()
+ ..()
+ total_positions = config.limit_visitors
+ spawn_positions = config.limit_visitors
/datum/job/assistant/get_access()
if(config.assistant_maint)
return list(access_maint_tunnels)
else
return list()
+//VOREStation Add End
diff --git a/code/game/jobs/job/job_vr.dm b/code/game/jobs/job/job_vr.dm
index d1bb79e7cc..71cb74a950 100644
--- a/code/game/jobs/job/job_vr.dm
+++ b/code/game/jobs/job/job_vr.dm
@@ -3,4 +3,11 @@
var/whitelist_only = 0
//Does not display this job on the occupation setup screen
- var/latejoin_only = 0
\ No newline at end of file
+ var/latejoin_only = 0
+
+ //Every hour playing this role gains this much time off. (Can be negative for off duty jobs!)
+ var/timeoff_factor = 3
+
+// Check client-specific availability rules.
+/datum/job/proc/player_has_enough_pto(client/C)
+ return timeoff_factor >= 0 || (C && LAZYACCESS(C.department_hours, department) > 0)
diff --git a/code/game/jobs/job/offduty_vr.dm b/code/game/jobs/job/offduty_vr.dm
new file mode 100644
index 0000000000..420943c562
--- /dev/null
+++ b/code/game/jobs/job/offduty_vr.dm
@@ -0,0 +1,81 @@
+//
+// "Off-duty" jobs are for people who want to do nothing and have earned it.
+//
+
+/datum/job/offduty_civilian
+ title = "Off-Duty Worker"
+ latejoin_only = TRUE
+ timeoff_factor = -1
+ total_positions = -1
+ faction = "Station"
+ department = "Civilian"
+ supervisors = "nobody! Enjoy your time off"
+ selection_color = "#9b633e"
+ access = list(access_maint_tunnels)
+ minimal_access = list(access_maint_tunnels)
+ outfit_type = /decl/hierarchy/outfit/job/assistant
+
+/datum/job/offduty_cargo
+ title = "Off-duty Cargo"
+ latejoin_only = TRUE
+ timeoff_factor = -1
+ total_positions = -1
+ faction = "Station"
+ department = "Cargo"
+ supervisors = "nobody! Enjoy your time off"
+ selection_color = "#9b633e"
+ access = list(access_maint_tunnels)
+ minimal_access = list(access_maint_tunnels)
+ outfit_type = /decl/hierarchy/outfit/job/assistant
+
+/datum/job/offduty_engineering
+ title = "Off-duty Engineer"
+ latejoin_only = TRUE
+ timeoff_factor = -1
+ total_positions = -1
+ faction = "Station"
+ department = "Engineering"
+ supervisors = "nobody! Enjoy your time off"
+ selection_color = "#5B4D20"
+ access = list(access_maint_tunnels, access_external_airlocks, access_construction)
+ minimal_access = list(access_maint_tunnels, access_external_airlocks)
+ outfit_type = /decl/hierarchy/outfit/job/assistant
+
+/datum/job/offduty_medical
+ title = "Off-duty Medic"
+ latejoin_only = TRUE
+ timeoff_factor = -1
+ total_positions = -1
+ faction = "Station"
+ department = "Medical"
+ supervisors = "nobody! Enjoy your time off"
+ selection_color = "#013D3B"
+ access = list(access_maint_tunnels, access_external_airlocks)
+ minimal_access = list(access_maint_tunnels, access_external_airlocks)
+ outfit_type = /decl/hierarchy/outfit/job/assistant
+
+/datum/job/offduty_science
+ title = "Off-duty Scientist"
+ latejoin_only = TRUE
+ timeoff_factor = -1
+ total_positions = -1
+ faction = "Station"
+ department = "Science"
+ supervisors = "nobody! Enjoy your time off"
+ selection_color = "#633D63"
+ access = list(access_maint_tunnels)
+ minimal_access = list(access_maint_tunnels)
+ outfit_type = /decl/hierarchy/outfit/job/assistant
+
+/datum/job/offduty_security
+ title = "Off-duty Officer"
+ latejoin_only = TRUE
+ timeoff_factor = -1
+ total_positions = -1
+ faction = "Station"
+ department = "Security"
+ supervisors = "nobody! Enjoy your time off"
+ selection_color = "#601C1C"
+ access = list(access_maint_tunnels)
+ minimal_access = list(access_maint_tunnels)
+ outfit_type = /decl/hierarchy/outfit/job/assistant
diff --git a/code/game/jobs/jobs.dm b/code/game/jobs/jobs.dm
index d2905c3a61..e5e9d240e2 100644
--- a/code/game/jobs/jobs.dm
+++ b/code/game/jobs/jobs.dm
@@ -44,6 +44,7 @@ var/const/ASSISTANT =(1<<11)
var/const/BRIDGE =(1<<12)
var/const/CLOWN =(1<<13) //VOREStation Add
var/const/MIME =(1<<14) //VOREStation Add
+var/const/INTERN =(1<<15) //VOREStation Add
var/list/assistant_occupations = list(
)
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index bed437ecc5..14462a93f6 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -103,7 +103,6 @@ var/list/admin_verbs_admin = list(
/datum/admins/proc/paralyze_mob,
/client/proc/fixatmos,
/datum/admins/proc/quick_nif, //VOREStation Add,
- /datum/admins/proc/assistant_ratio, //VOREStation Add,
/datum/admins/proc/sendFax
)
@@ -1050,7 +1049,7 @@ var/list/admin_verbs_event_manager = list(
set category = "Fun"
set name = "Man Up"
set desc = "Tells mob to man up and deal with it."
-
+
if(alert("Are you sure you want to tell them to man up?","Confirmation","Deal with it","No")=="No") return
T << "Man up and deal with it."
@@ -1063,7 +1062,7 @@ var/list/admin_verbs_event_manager = list(
set category = "Fun"
set name = "Man Up Global"
set desc = "Tells everyone to man up and deal with it."
-
+
if(alert("Are you sure you want to tell the whole server up?","Confirmation","Deal with it","No")=="No") return
for (var/mob/T as mob in mob_list)
diff --git a/code/modules/admin/verbs/debug_vr.dm b/code/modules/admin/verbs/debug_vr.dm
index 5484f37771..eb8cd37e01 100644
--- a/code/modules/admin/verbs/debug_vr.dm
+++ b/code/modules/admin/verbs/debug_vr.dm
@@ -30,18 +30,3 @@
log_and_message_admins("[key_name(src)] Quick NIF'd [H.real_name].")
feedback_add_details("admin_verb","QNIF") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-
-/datum/admins/proc/assistant_ratio()
- set category = "Admin"
- set name = "Toggle Asst. Ratio"
- set desc = "Toggles the assistant ratio enforcement on/off."
-
- if(!check_rights(R_ADMIN))
- return
-
- if(isnull(config.assistants_ratio))
- to_chat(usr,"Assistant ratio enforcement isn't even turned on...")
- return
-
- config.assistants_ratio *= -1
- to_chat(usr,"Assistant ratio enforcement now [config.assistants_ratio > 0 ? "enabled" : "disabled"].")
diff --git a/code/modules/client/client defines.dm b/code/modules/client/client defines.dm
index e4c5a10d35..3dc5642a81 100644
--- a/code/modules/client/client defines.dm
+++ b/code/modules/client/client defines.dm
@@ -48,8 +48,8 @@
var/player_age = "Requires database" //So admins know why it isn't working - Used to determine how old the account is - in days.
var/related_accounts_ip = "Requires database" //So admins know why it isn't working - Used to determine what other accounts previously logged in from this ip
var/related_accounts_cid = "Requires database" //So admins know why it isn't working - Used to determine what other accounts previously logged in from this computer id
+ var/list/department_hours // VOREStation Edit - Track hours of leave accured for each department.
preload_rsc = PRELOAD_RSC
var/global/obj/screen/click_catcher/void
-
diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm
index 012a74ef6c..76de070805 100644
--- a/code/modules/client/client procs.dm
+++ b/code/modules/client/client procs.dm
@@ -258,6 +258,15 @@
qdel(src)
return 0
+ // VOREStation Edit Start - Department Hours
+ if(config.time_off)
+ var/DBQuery/query_hours = dbcon.NewQuery("SELECT department, hours FROM vr_player_hours WHERE ckey = '[sql_ckey]'")
+ query_hours.Execute()
+ while(query_hours.NextRow())
+ LAZYINITLIST(department_hours)
+ department_hours[query_hours.item[1]] = text2num(query_hours.item[2])
+ // VOREStation Edit End - Department Hours
+
if(sql_id)
//Player already identified previously, we need to just update the 'lastseen', 'ip' and 'computer_id' variables
var/DBQuery/query_update = dbcon.NewQuery("UPDATE erro_player SET lastseen = Now(), ip = '[sql_ip]', computerid = '[sql_computerid]', lastadminrank = '[sql_admin_rank]' WHERE id = [sql_id]")
diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm
index 9b8a9aa457..1cdb98eaa7 100644
--- a/code/modules/mob/new_player/new_player.dm
+++ b/code/modules/mob/new_player/new_player.dm
@@ -318,6 +318,7 @@
if(jobban_isbanned(src,rank)) return 0
if(!job.player_old_enough(src.client)) return 0
if(!is_job_whitelisted(src,rank)) return 0 //VOREStation Code
+ if(!job.player_has_enough_pto(src.client)) return 0 //VOREStation Code
return 1
diff --git a/code/modules/mob/new_player/new_player_vr.dm b/code/modules/mob/new_player/new_player_vr.dm
index 0b5b2c26b6..d92df60859 100644
--- a/code/modules/mob/new_player/new_player_vr.dm
+++ b/code/modules/mob/new_player/new_player_vr.dm
@@ -47,22 +47,6 @@
pass = FALSE
to_chat(src,"Your custom species is not playable. Reconfigure your traits on the VORE tab.")
- //Assistant ratio enforcement
- if (config.assistants_ratio > 0) //Stored as a negative number when inactive by admin verb
-
- var/nonassistants = 0
- var/assistants = 0
- for(var/job in job_master.occupations)
- var/datum/job/J = job
- if(istype(J,/datum/job/assistant))
- assistants += J.current_positions
- else
- nonassistants += J.current_positions
-
- if(assistants != 0 && assistants >= config.assistants_assured && nonassistants/assistants < config.assistants_ratio)
- pass = FALSE
- to_chat(src,"There are currently [assistants] assistants, and [nonassistants] normal employees, while we enforce a specific ratio. Please join as a job instead of assistant.")
-
//Final popup notice
if (!pass)
alert(src,"There were problems with spawning your character. Check your message log for details.","Error","OK")
diff --git a/config/example/config.txt b/config/example/config.txt
index f459a49d79..f9ff877e89 100644
--- a/config/example/config.txt
+++ b/config/example/config.txt
@@ -399,3 +399,13 @@ STARLIGHT 0
## Default language prefix keys, separated with spaces. Only single character keys are supported. If unset, defaults to , # and -
# DEFAULT_LANGUAGE_PREFIXES , # -
+
+# Control which submaps are loaded for the Dynamic Engine system
+ENGINE_MAP Supermatter Engine,Edison's Bane
+
+# Controls if the 'time off' system is used for determining if players can play 'Off-Duty' jobs (requires SQL)
+# TIME_OFF
+
+# Applies a limit to the number of assistants and visitors respectively
+# LIMIT_INTERNS 6
+# LIMIT_VISITORS 6
\ No newline at end of file
diff --git a/vorestation.dme b/vorestation.dme
index ac98718777..6ea6cf7276 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -202,6 +202,7 @@
#include "code\controllers\subsystems\mapping_vr.dm"
#include "code\controllers\subsystems\mobs.dm"
#include "code\controllers\subsystems\orbits.dm"
+#include "code\controllers\subsystems\persist_vr.dm"
#include "code\controllers\subsystems\transcore_vr.dm"
#include "code\datums\ai_law_sets.dm"
#include "code\datums\ai_laws.dm"
@@ -612,6 +613,7 @@
#include "code\game\jobs\job\job.dm"
#include "code\game\jobs\job\job_vr.dm"
#include "code\game\jobs\job\medical.dm"
+#include "code\game\jobs\job\offduty_vr.dm"
#include "code\game\jobs\job\science.dm"
#include "code\game\jobs\job\security.dm"
#include "code\game\jobs\job\silicon.dm"