From 6b9c3336360a739d4364b08657cafc5d453191f9 Mon Sep 17 00:00:00 2001 From: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com> Date: Sun, 17 May 2026 05:45:07 -0400 Subject: [PATCH] Adds Security Fines (#31857) * Adds Fines * Forgot one * Enhanced Clarity * Fixes issue with linked account * If no crime stated, states in the fine message * Updates fine scanner sprite * Updates fine scanner behavior * Adds comment to records * Apply suggestions from code review Co-authored-by: JimKil3 <47290811+JimKil3@users.noreply.github.com> Signed-off-by: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com> * Removes capitalization --------- Signed-off-by: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com> Co-authored-by: JimKil3 <47290811+JimKil3@users.noreply.github.com> --- .../objects/items/weapons/storage/belt.dm | 1 + .../closets/secure/security_lockers.dm | 4 + .../economy/economy_machinery/fines.dm | 109 ++++++++++++++++++ code/modules/martial_arts/judo.dm | 1 + .../supply/supply_packs/pack_security.dm | 1 + icons/obj/device.dmi | Bin 76434 -> 74153 bytes paradise.dme | 1 + 7 files changed, 117 insertions(+) create mode 100644 code/modules/economy/economy_machinery/fines.dm diff --git a/code/game/objects/items/weapons/storage/belt.dm b/code/game/objects/items/weapons/storage/belt.dm index 759e0b49860..7eb0105ce22 100644 --- a/code/game/objects/items/weapons/storage/belt.dm +++ b/code/game/objects/items/weapons/storage/belt.dm @@ -323,6 +323,7 @@ /obj/item/sample/print, /obj/item/forensics/swab, /obj/item/forensics/sample_kit, + /obj/item/fine_scanner, ) /obj/item/storage/belt/security/full/populate_contents() diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security_lockers.dm b/code/game/objects/structures/crates_lockers/closets/secure/security_lockers.dm index f89e99fd640..13f7ae53c64 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/security_lockers.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/security_lockers.dm @@ -67,6 +67,7 @@ new /obj/item/reagent_containers/drinks/flask/barflask(src) new /obj/item/clothing/mask/gas/sechailer(src) new /obj/item/autosurgeon/organ/one_use/sec_hud(src) + new /obj/item/fine_scanner(src) /obj/structure/closet/secure_closet/warden name = "warden's locker" @@ -89,6 +90,7 @@ new /obj/item/storage/box/holobadge(src) new /obj/item/clothing/gloves/color/black/krav_maga/sec(src) new /obj/item/clothing/mask/gas/sechailer(src) + new /obj/item/fine_scanner(src) /obj/structure/closet/secure_closet/security name = "security officer's locker" @@ -110,6 +112,7 @@ new /obj/item/flashlight/seclite(src) new /obj/item/clothing/head/helmet(src) new /obj/item/clothing/suit/armor/secjacket(src) + new /obj/item/fine_scanner(src) /obj/structure/closet/secure_closet/evidence name = "evidence locker" @@ -211,6 +214,7 @@ new /obj/item/storage/box/tapes(src) new /obj/item/taperecorder(src) new /obj/item/storage/briefcase/crimekit(src) + new /obj/item/fine_scanner(src) /obj/structure/closet/secure_closet/injection name = "lethal injections locker" diff --git a/code/modules/economy/economy_machinery/fines.dm b/code/modules/economy/economy_machinery/fines.dm new file mode 100644 index 00000000000..fb25b86c5ed --- /dev/null +++ b/code/modules/economy/economy_machinery/fines.dm @@ -0,0 +1,109 @@ +/obj/item/fine_scanner + name = "fine scanner" + desc = "Swipe an ID card to issue a fine." + icon = 'icons/obj/device.dmi' + icon_state = "fine_scanner" + w_class = WEIGHT_CLASS_SMALL + slot_flags = ITEM_SLOT_BELT + materials = list(MAT_METAL = 300, MAT_GLASS = 140) + new_attack_chain = TRUE + /// Built in radio used to message about crime + var/obj/item/radio/radio + /// The set fine amount + var/fine_amount = 250 + /// linked money account database to this scanner. Usually the station database + var/datum/money_account_database/main_station/account_database + /// The linked account. This will usually be security unless admins tinker + var/linked_account + /// The sound the machine makes on a success + var/fine_sound = 'sound/machines/chime.ogg' + /// The sound the machine makes on a fail + var/fail_sound = 'sound/machines/synth_no.ogg' + +/obj/item/fine_scanner/Initialize(mapload) + . = ..() + account_database = GLOB.station_money_database + linked_account = account_database.get_account_by_department(DEPARTMENT_SECURITY) + radio = new /obj/item/radio(src) + radio.listening = FALSE + radio.config(list("Security" = 0)) + radio.follow_target = src + +/obj/item/fine_scanner/Destroy() + linked_account = null + return ..() + +/obj/item/fine_scanner/activate_self(mob/user) + . = ..() + if(!Adjacent(user)) + return + var/minutes = tgui_input_number(user, "Select the number of minutes that would be served (1-10):", "Issue Fine", 5, 10, 1) + if(!minutes) + return + fine_amount = minutes * 50 + +/obj/item/fine_scanner/item_interaction(mob/living/user, obj/item/used, list/modifiers) + . = ..() + if(istype(used, /obj/item/card/id)) + var/crime_string = tgui_input_text(user, "Enter the crime a fine is being issued for.", "Issue Fine") + if(!Adjacent(user)) + return + if(!account_database) + account_database = GLOB.station_money_database + linked_account = account_database.get_account_by_department(DEPARTMENT_SECURITY) + // Needs to ensure it actually is connected, in case there is no database. + if(account_database) + linked_account = account_database.get_account_by_department(DEPARTMENT_SECURITY) + issue_fine(user, used, crime_string) + +/obj/item/fine_scanner/proc/issue_fine(mob/living/user, obj/item/card/id/C, crime_string) + if(!crime_string || crime_string == "") + crime_string = "(NO CRIME LISTED)" + visible_message(SPAN_NOTICE("[user] swipes a card through [src].")) + var/datum/money_account/D = GLOB.station_money_database.find_user_account(C.associated_account_number, include_departments = FALSE) + if(!D) + visible_message("[bicon(src)][SPAN_WARNING("[src] buzzes as its display flashes \"Invalid account link.\"")]", SPAN_NOTICE("You hear something buzz.")) + playsound(src, fail_sound, 50, TRUE) + return + if(!GLOB.station_money_database.charge_account(D, fine_amount, "Security Fine", user.name, FALSE, FALSE)) + visible_message("[bicon(src)][SPAN_WARNING("[src] buzzes as its display flashes \"Insufficient funds.\"")]", SPAN_NOTICE("You hear something buzz.")) + playsound(src, fail_sound, 50, TRUE) + return + GLOB.station_money_database.credit_account(linked_account, fine_amount, "Security Fine", user.name, FALSE) + playsound(src, fine_sound, 50, TRUE) + radio.autosay("[C.registered_name] has paid a fine of [fine_amount] credits for the crime of [crime_string]. Fine issued by [user.name].", "Automatic Fine System", "Security") + print_report(user, C, crime_string) + var/datum/data/record/R = find_security_record("name", C.registered_name) + if(istype(R)) + R.fields["criminal"] = SEC_RECORD_STATUS_RELEASED + R.fields["comments"] += "Fined [fine_amount] credits for the crime of [crime_string]. Fine issued by [user.name] at [station_time_timestamp()]." + update_all_mob_security_hud() + +/obj/item/fine_scanner/proc/print_report(mob/living/user, obj/item/card/id/card, crime_string) + for(var/obj/machinery/computer/prisoner/C in GLOB.prisoncomputer_list) + var/obj/item/paper/P = new /obj/item/paper(C.loc) + P.name = "Fine log - [card.registered_name] [station_time_timestamp()]" + P.info = "
Pd4UJty@d#
z+cp-Bp^`8t;v6UQ7RQi=fha{^ktl;<1JmT6R}9EYxQ>1+shxdmoUdm$UFZEhM>GD`
z7qc`OACjJ)o?oz)gCWj77&!Q9lCER2?BPS4CcxZ~sV=*#m}%f%J`K{Uo&hLx_;D%M
zy3zk#ETht4%ALb1)sVgS2kYB)xK@7mSt-krvdt8!J9rkP&fVd;?8&C+pnz=jqdfi0
zt@0tM;1jPOdc LlHWLFr04
zF+&0Ay1v5@Kxt7=DYf+Ij25#JSYk4ifJv7jvib?>;{cxr{;(2%PK$WHiFc9Jfj>JT
zbvtYGO@^J_Jx!MgXn)`%g}pJ3av2ejA3gWJ_$jui{=SEYHx8|8j9QN+rKd-KR*wn9
z8tXHU@WR2Isg^G5ca_^5IFw=|cL*#fz@zNLX^gOE#v%@WKD _`7%Ys+;2Q6trv+BbI8`Apo!$VQtazXjLuNS&d;td)jCKH}$3or@uPzTJF$
z^ rd V;|)P
znKLax?Y$|y9}U>MJI_YpAX&{Q>;JSba!cf&;qH=oID0w-V))_ezD~xMU%%zDKylu?
zMClNqDZmmWfAC;Pv-of3 ?ozrDkWxfSIBt3PGy=i6O{PtmK{Q>FD{{ft*^(^Akl>O6
zIxFzxFUBfph`#xf9khe;|87VE$@pU%ATtU?s~icSz<4&vU7I!U-nEOZ^E3JUX{Lm=
z=6B2bY1QVmwwqFcRy)m{y1a(@fySuQ%$JyR6uyzihohLY>klxF?EHXnH1Bpn6n0K9
zBeno47h`HT&c%0XE7@}_7jo|aG|l>v?S)(Vd`?}Toh-SEELxS5koYfkwKPrtHMa`R
ztB=Kln`C2$=#EAoobXl8Hl~Q;AMjh3a6<;mnrOzngrK{ka--ilQ8S=q#uxrfOmjad
zgeA>pqjj`+cL&F>{a3x`-MfQqJ0OaaL$;2c0a>hkK;|Ybg|+;_lz!JIBQABH#V-Br
zCUPOBOI_V^5%8OCwx}MxcHg%?lm_Q`G$IFnsb&LqW4rfP3*jHBH@~cjz$*n*F!0Ez
zHzkuk!O1!_TFPujnH>pUxqRUqt3*5U0i|TGvTM?AY&qZ82$)xE1k9Q-{}f4i9}p4*
z^IuDtAwjbE%LFp*X-UvY!8CfmcyxDJ1Etk7ux5$dk3M_Om3 rl<3
zF94snCh#xX6q;3Z*5oE0l6dUupKumAg
zY}zw~p6;;B75PB%iT48Rj`j=(DBe{D>!VZanQ40;_qH|$wuSM-b7P|aftw}(xmZPw
zm5jP4hfY}nc+z)JALaE#_`KWBpH#oq6k93Vw*M+hPvpXy+=tq}FOUd}bLqiDIKbl*
zXKfT*+#N3x1kD95l(Q**#F;SxSSF0q!xwW{cWl1P_P2s+kdb?yDJB(%ok1@(zu&m{
zw~qjWQSrr8enR3Rwl2JOu#?>=DBuzE)
k8;S+QtYz7_;Z8dM}Bl59t)S57B4&
ze?wI^#P$7K7PV4jkxf6DX~JAK43bV=ni~O{O8UN;@rW`6>AH)O2ia5pu&2mpNKL&^
zp{O^xRqeo$Ik(iebs+`OH%il~PsTGJEYC{jI)^nPsU_zwP^ATmSp{L}{Urp=CvVD!
zLIo|AG`=H^FmLh@*Y=Oinbakmv4}SbHfD~q+>6?&e)Zg7`3u+PFOhJDL_KQfzDH|(
zozL@J-zn?AgGIsO!G8ctjQ7Z-g^)omtv)S?3j%3PK+JC3YRH#vS!j1+I)HY%5}w|)
zz_h;n%vS$1`fpVa9^XubE{K|*SXv~eeOo@*wV(u~vfgI>X$$Uf0KbqaMU^brc+uhybm)ZT)k{Ljm
zlP_h(uESjTuLIibd@+(@QK<19>-cpi(=V`7$`}e~D2y8j6KzAcrvrdi_fLi;=YEG@
z;&_ZO0)f`E4dL7c#>hL@+sm|UY5JFQ<$k}vPz+n3I*U|Rq<93N^@T^__yPgG!S&dI
z=!<_b@64#o6<_c|`B)3uXLjK1J4TJQK^d(W-ghwq?6KTP#!nCUyr ~$QdfEA9Yzo*UAbX)>%ulyx#>;6w!x^;w{Rt^#>QSL}e
zDS3(n_22b>Ld<1OUmC_8)oK=^m{_RK)t>ay(