Files
CHOMPStation2/code/game/machinery/computer/timeclock_vr.dm
CHOMPStation2StaffMirrorBot 4099a9435b [MIRROR] Machine var shim (#11878)
Co-authored-by: Will <7099514+Willburd@users.noreply.github.com>
Co-authored-by: C.L. <killer65311@gmail.com>
2025-10-27 02:35:27 -04:00

305 lines
10 KiB
Plaintext

/////////////////////////////////////////////
//Time Clock Terminal////////////////////////
/////////////////////////////////////////////
//
// Timeclock terminal machine itself
//
/obj/machinery/computer/timeclock
name = "timeclock terminal"
icon = 'icons/obj/machines/timeclock_vr.dmi'
icon_state = "timeclock"
icon_keyboard = null
light_color = "#0099ff"
light_power_on = 0.5
layer = ABOVE_WINDOW_LAYER
density = FALSE
circuit = /obj/item/circuitboard/timeclock
clicksound = null
var/channel = "Common" //Radio channel to announce on
var/obj/item/card/id/card // Inserted Id card
var/obj/item/radio/intercom/announce // Integreated announcer
/obj/machinery/computer/timeclock/Initialize(mapload)
. = ..()
announce = new /obj/item/radio/intercom(src)
/obj/machinery/computer/timeclock/Destroy()
if(card)
card.forceMove(get_turf(src))
card = null
. = ..()
/obj/machinery/computer/timeclock/update_icon()
if(inoperable())
icon_state = "[initial(icon_state)]_off"
else if(card)
icon_state = "[initial(icon_state)]_card"
else
icon_state = "[initial(icon_state)]"
/obj/machinery/computer/timeclock/power_change()
var/old_stat = stat
. = ..()
if(old_stat != stat)
update_icon()
if(stat & NOPOWER)
set_light(0)
else
set_light(light_range_on, light_power_on)
/obj/machinery/computer/timeclock/attackby(obj/I, mob/user)
if(istype(I, /obj/item/card/id))
if(!card && user.unEquip(I))
I.forceMove(src)
card = I
playsound(src, 'sound/effects/insert_id_card.ogg', 75, 0) // CHOMPEdit: Timeclock beepboop. TODO: Make clocks delay reading the card for ~3 seconds to line up with quiet boops
SStgui.update_uis(src)
update_icon()
else if(card)
to_chat(user, span_warning("There is already ID card inside."))
return
. = ..()
/obj/machinery/computer/timeclock/attack_hand(var/mob/user as mob)
if(..())
return
tgui_interact(user)
/obj/machinery/computer/timeclock/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "TimeClock", name)
ui.open()
/obj/machinery/computer/timeclock/tgui_data(mob/user)
var/list/data = ..()
// Okay, data for showing the user's OWN PTO stuff
if(user.client)
data["department_hours"] = SANITIZE_LIST(user.client.department_hours)
data["user_name"] = "[user]"
// Data about the card that we put into it.
data["card"] = null
data["assignment"] = null
data["job_datum"] = null
data["allow_change_job"] = null
data["job_choices"] = null
if(card)
data["card"] = "[card]"
data["assignment"] = card.assignment
data["card_cooldown"] = getCooldown()
var/datum/job/job = job_master.GetJob(card.rank)
if(job)
data["job_datum"] = list(
"title" = job.title,
"departments" = english_list(job.departments),
"selection_color" = job.selection_color,
"economic_modifier" = job.economic_modifier,
"timeoff_factor" = job.timeoff_factor,
"pto_department" = job.pto_type
)
if(CONFIG_GET(flag/time_off) && CONFIG_GET(flag/pto_job_change))
data["allow_change_job"] = TRUE
if(job && job.timeoff_factor < 0) // Currently are Off Duty, so gotta lookup what on-duty jobs are open
data["job_choices"] = getOpenOnDutyJobs(user, job.pto_type)
return data
/obj/machinery/computer/timeclock/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
return TRUE
add_fingerprint(ui.user)
switch(action)
if("id")
if(card)
ui.user.put_in_hands(card)
card = null
playsound(src, 'sound/effects/remove_id_card.ogg', 75, 0) // CHOMPEdit: Timeclock beepboop. TODO: Make clocks delay reading the card for ~3 seconds to line up with quiet boops
else
var/obj/item/I = ui.user.get_active_hand()
if (istype(I, /obj/item/card/id) && ui.user.unEquip(I))
I.forceMove(src)
card = I
playsound(src, 'sound/effects/insert_id_card.ogg', 75, 0) // CHOMPEdit: Timeclock beepboop. TODO: Make clocks delay reading the card for ~3 seconds to line up with quiet boops
update_icon()
return TRUE
if("switch-to-onduty-rank")
if(checkFace(ui.user))
if(checkCardCooldown(ui.user))
makeOnDuty(params["switch-to-onduty-rank"], params["switch-to-onduty-assignment"], ui.user)
ui.user.put_in_hands(card)
card = null
playsound(src, 'sound/effects/remove_id_card.ogg', 75, 0) // CHOMPEdit: Timeclock beepboop. TODO: Make clocks delay reading the card for ~3 seconds to line up with quiet boops
update_icon()
return TRUE
if("switch-to-offduty")
if(checkFace(ui.user))
if(checkCardCooldown(ui.user))
makeOffDuty(ui.user)
ui.user.put_in_hands(card)
card = null
playsound(src, 'sound/effects/remove_id_card.ogg', 75, 0) // CHOMPEdit: Timeclock beepboop. TODO: Make clocks delay reading the card for ~3 seconds to line up with quiet boops
update_icon()
return TRUE
/obj/machinery/computer/timeclock/proc/getOpenOnDutyJobs(var/mob/user, var/department)
var/list/available_jobs = list()
for(var/datum/job/job in job_master.occupations)
if(isOpenOnDutyJob(user, department, job))
available_jobs[job.title] = list(job.title)
if(job.alt_titles)
for(var/alt_job in job.alt_titles)
if(alt_job != job.title)
available_jobs[job.title] += alt_job
return available_jobs
/obj/machinery/computer/timeclock/proc/isOpenOnDutyJob(var/mob/user, var/department, var/datum/job/job)
return job \
&& job.is_position_available() \
&& !job.whitelist_only \
&& !jobban_isbanned(user,job.title) \
&& job.player_old_enough(user.client) \
&& job.player_has_enough_playtime(user.client) \
&& job.pto_type == department \
&& !job.disallow_jobhop \
&& job.timeoff_factor > 0
/obj/machinery/computer/timeclock/proc/makeOnDuty(var/newrank, var/newassignment, var/mob/user)
var/datum/job/oldjob = job_master.GetJob(card.rank)
var/datum/job/newjob = job_master.GetJob(newrank)
if(!oldjob || !isOpenOnDutyJob(user, oldjob.pto_type, newjob))
return
if(newassignment != newjob.title && !(newassignment in newjob.alt_titles))
return
//CHOMPadd START
if(newjob.camp_protection && round_duration_in_ds < CONFIG_GET(number/job_camp_time_limit))
if(SSjob.restricted_keys.len)
var/list/check = SSjob.restricted_keys[newjob.title]
if(user.client.ckey in check)
to_chat(user,span_danger("[newjob.title] is not presently selectable because you played as it last round. It will become available to you in [round((CONFIG_GET(number/job_camp_time_limit) - round_duration_in_ds) / 600)] minutes, if slots remain open."))
return
//CHOMPadd END
if(newjob)
newjob.register_shift_key(user.client.ckey)//CHOMPadd
card.access = newjob.get_access()
card.rank = newjob.title
card.assignment = newassignment
card.name = text("[card.registered_name]'s ID Card ([card.assignment])")
GLOB.data_core.manifest_modify(card.registered_name, card.assignment, card.rank)
card.last_job_switch = world.time
callHook("reassign_employee", list(card))
newjob.current_positions++
var/mob/living/carbon/human/H = user
H.mind.assigned_role = card.rank
H.mind.role_alt_title = card.assignment
announce.autosay("[card.registered_name] has moved On-Duty as [card.assignment].", "Employee Oversight", channel, zlevels = using_map.get_map_levels(get_z(src)))
return
/obj/machinery/computer/timeclock/proc/makeOffDuty(var/mob/user)
var/datum/job/foundjob = job_master.GetJob(card.rank)
if(!foundjob)
return
var/new_dept = foundjob.pto_type || PTO_CIVILIAN
var/datum/job/ptojob = null
for(var/datum/job/job in job_master.occupations)
if(job.pto_type == new_dept && job.timeoff_factor < 0)
ptojob = job
break
if(ptojob)
var/oldtitle = card.assignment
card.access = ptojob.get_access()
card.rank = ptojob.title
card.assignment = ptojob.title
card.name = text("[card.registered_name]'s ID Card ([card.assignment])")
GLOB.data_core.manifest_modify(card.registered_name, card.assignment, card.rank)
card.last_job_switch = world.time
callHook("reassign_employee", list(card))
var/mob/living/carbon/human/H = user
H.mind.assigned_role = ptojob.title
H.mind.role_alt_title = ptojob.title
foundjob.current_positions--
announce.autosay("[card.registered_name], [oldtitle], has moved Off-Duty.", "Employee Oversight", channel, zlevels = using_map.get_map_levels(get_z(src)))
return
/obj/machinery/computer/timeclock/proc/checkCardCooldown(var/mob/user)
if(!card)
return FALSE
var/time_left = getCooldown()
if(time_left > 0)
to_chat(user, "You need to wait another [round((time_left/10)/60, 1)] minute\s before you can switch.")
return FALSE
return TRUE
/obj/machinery/computer/timeclock/proc/getCooldown()
return 1 MINUTES - (world.time - card.last_job_switch) // CHOMPedit: 10 minute wait down to 1 minute.
/obj/machinery/computer/timeclock/proc/checkFace(var/mob/user)
var/turf/location = get_turf(src) // CHOMPedit: Needed for admin logs.
if(!card)
to_chat(user, span_notice("No ID is inserted."))
return FALSE
/* CHOMPedit start. Allows anyone to change people's IDs.
var/mob/living/carbon/human/H = user
if(!(istype(H)))
to_chat(user, span_warning("Invalid user detected. Access denied."))
return FALSE
else if((H.wear_mask && (H.wear_mask.flags_inv & HIDEFACE)) || (H.head && (H.head.flags_inv & HIDEFACE))) //Face hiding bad
to_chat(user, span_warning("Facial recognition scan failed due to physical obstructions. Access denied."))
return FALSE
else if(H.get_face_name() == "Unknown" || !(H.real_name == card.registered_name))
to_chat(user, span_warning("Facial recognition scan failed. Access denied."))
return FALSE
CHOMPedit end. */
else
message_admins("[key_name_admin(user)] has modified '[card.registered_name]' 's ID with a timeclock terminal. [ADMIN_JMP(location)]") // CHOMPedit: Logging
log_game("[key_name_admin(user)] has modified '[card.registered_name]' 's ID with a timeclock terminal.") // CHOMPedit: Logging
return TRUE
/obj/item/card/id
var/last_job_switch
/obj/item/card/id/Initialize(mapload)
. = ..()
last_job_switch = world.time
//
// Frame type for construction
//
/datum/frame/frame_types/timeclock_terminal
name = "Timeclock Terminal"
frame_class = FRAME_CLASS_DISPLAY
frame_size = 2
frame_style = FRAME_STYLE_WALL
x_offset = 30
y_offset = 30
icon_override = 'icons/obj/machines/timeclock_vr.dmi'
/datum/frame/frame_types/timeclock_terminal/get_icon_state(var/state)
return "timeclock_b[state]"
//
// Easy mapping
//
/obj/machinery/computer/timeclock/premade/north
dir = 2
pixel_y = 26
/obj/machinery/computer/timeclock/premade/south
dir = 1
pixel_y = -26
/obj/machinery/computer/timeclock/premade/east
dir = 8
pixel_x = 26
/obj/machinery/computer/timeclock/premade/west
dir = 4
pixel_x = -26