mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-26 06:22:26 +01:00
Security Fines (#4634)
Allows security to fine criminals with the sentencing console Prints a human readable copy of the charges and the applied sentence
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
--
|
||||
-- Adds a new table to load the regulations ("laws") from
|
||||
--
|
||||
CREATE TABLE `ss13_law` (
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`law_id` VARCHAR(4) NOT NULL,
|
||||
`name` VARCHAR(50) NOT NULL,
|
||||
`description` VARCHAR(500) NOT NULL,
|
||||
`min_fine` INT(10) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`max_fine` INT(10) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`min_brig_time` INT(10) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`max_brig_time` INT(10) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`severity` INT(10) UNSIGNED NULL DEFAULT '0',
|
||||
`felony` INT(10) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
`deleted_at` DATETIME NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE INDEX `UNIQUE LAW` (`law_id`)
|
||||
)
|
||||
ENGINE=InnoDB;
|
||||
@@ -278,8 +278,6 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s
|
||||
|
||||
// Law settings
|
||||
#define PERMABRIG_SENTENCE 90 // Measured in minutes
|
||||
//#define PERMAPRISON_SENTENCE 60 // Measured in IC days
|
||||
#define FELONY_LEVEL 2.0 // What is the minimum law severity that counts as a felony?
|
||||
|
||||
#define LAYER_TABLE 2.8
|
||||
#define LAYER_UNDER_TABLE 2.79
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
/proc/log_debug(text,level = SEVERITY_DEBUG)
|
||||
if (config.log_debug)
|
||||
game_log("DEBUG", text)
|
||||
|
||||
if (level == SEVERITY_ERROR) // Errors are always logged
|
||||
error(text)
|
||||
|
||||
for(var/client/C in admins)
|
||||
if(!C.prefs) //This is to avoid null.toggles runtime error while still initialyzing players preferences
|
||||
@@ -51,7 +54,7 @@
|
||||
if (config.log_game)
|
||||
game_log("GAME", text)
|
||||
send_gelf_log(
|
||||
short_message = text,
|
||||
short_message = text,
|
||||
long_message = "[time_stamp()]: [text]",
|
||||
level = level,
|
||||
category = "GAME",
|
||||
@@ -92,8 +95,8 @@
|
||||
if (config.log_attack)
|
||||
game_log("ATTACK", text)
|
||||
send_gelf_log(
|
||||
short_message = text,
|
||||
long_message = "[time_stamp()]: [text]",
|
||||
short_message = text,
|
||||
long_message = "[time_stamp()]: [text]",
|
||||
level = level,
|
||||
category="ATTACK",
|
||||
additional_data = list("_ckey" = html_encode(ckey), "_ckey_target" = html_encode(ckey_target))
|
||||
@@ -108,7 +111,7 @@
|
||||
if (config.log_pda)
|
||||
game_log("PDA", text)
|
||||
send_gelf_log(
|
||||
short_message = text,
|
||||
short_message = text,
|
||||
long_message = "[time_stamp()]: [text]",
|
||||
level = level,
|
||||
category="PDA",
|
||||
@@ -119,9 +122,9 @@
|
||||
if (config.log_pda)
|
||||
game_log("NTIRC", text)
|
||||
send_gelf_log(
|
||||
short_message = text,
|
||||
long_message="[time_stamp()]: [text]",
|
||||
level = level,
|
||||
short_message = text,
|
||||
long_message="[time_stamp()]: [text]",
|
||||
level = level,
|
||||
category = "NTIRC",
|
||||
additional_data = list("_ckey" = html_encode(ckey), "_ntirc_conversation" = html_encode(conversation))
|
||||
)
|
||||
@@ -187,7 +190,7 @@
|
||||
return english_list(comps, nothing_text="0", and_text="|", comma_text="|")
|
||||
|
||||
//more or less a logging utility
|
||||
/proc/key_name(var/whom, var/include_link = null, var/include_name = 1, var/highlight_special = 0, var/datum/ticket/ticket = null)
|
||||
/proc/key_name(var/whom, var/include_link = null, var/include_name = 1, var/highlight_special = 0, var/datum/ticket/ticket = null)
|
||||
var/mob/M
|
||||
var/client/C
|
||||
var/key
|
||||
@@ -217,7 +220,7 @@
|
||||
|
||||
if(key)
|
||||
if(include_link && C)
|
||||
. += "<a href='?priv_msg=\ref[C];ticket=\ref[ticket]'>"
|
||||
. += "<a href='?priv_msg=\ref[C];ticket=\ref[ticket]'>"
|
||||
|
||||
if(C && C.holder && C.holder.fakekey && !include_name)
|
||||
. += "Administrator"
|
||||
|
||||
@@ -13,6 +13,12 @@
|
||||
NEW_SS_GLOBAL(SSlaw)
|
||||
|
||||
/datum/controller/subsystem/law/Initialize(timeofday)
|
||||
if(config.sql_enabled)
|
||||
load_from_sql()
|
||||
else
|
||||
load_from_code()
|
||||
|
||||
/datum/controller/subsystem/law/proc/load_from_code()
|
||||
for (var/L in subtypesof(/datum/law/low_severity))
|
||||
low_severity += new L
|
||||
|
||||
@@ -23,3 +29,64 @@
|
||||
high_severity += new L
|
||||
|
||||
laws = low_severity + med_severity + high_severity
|
||||
|
||||
/datum/controller/subsystem/law/proc/load_from_sql()
|
||||
if(!establish_db_connection(dbcon))
|
||||
log_debug("SSlaw: SQL ERROR - Failed to connect.")
|
||||
return load_from_code()
|
||||
|
||||
var/DBQuery/law_query = dbcon.NewQuery("SELECT law_id, name, description, min_fine, max_fine, min_brig_time, max_brig_time, severity, felony FROM ss13_law WHERE deleted_at IS NULL ORDER BY law_id ASC")
|
||||
law_query.Execute()
|
||||
while(law_query.NextRow())
|
||||
CHECK_TICK
|
||||
try
|
||||
var/datum/law/L = new
|
||||
L.id = law_query.item[1]
|
||||
L.name = law_query.item[2]
|
||||
L.desc = law_query.item[3]
|
||||
L.min_fine = text2num(law_query.item[4])
|
||||
L.max_fine = text2num(law_query.item[5])
|
||||
L.min_brig_time = text2num(law_query.item[6])
|
||||
L.max_brig_time = text2num(law_query.item[7])
|
||||
L.severity = text2num(law_query.item[8])
|
||||
L.felony = text2num(law_query.item[9])
|
||||
|
||||
if(L.severity == 1)
|
||||
low_severity += L
|
||||
else if(L.severity == 2)
|
||||
med_severity += L
|
||||
else if(L.severity == 3)
|
||||
high_severity += L
|
||||
else
|
||||
throw("Law with id: [L.id] deleted due to invalid severity: [L.severity]")
|
||||
qdel(L)
|
||||
catch(var/exception/el)
|
||||
log_debug("SSlaw: Error when loading law: [el]")
|
||||
|
||||
laws = low_severity + med_severity + high_severity
|
||||
if(!laws.len)
|
||||
log_debug("SSlaw: No laws loaded. Loading from code and migrating to SQL")
|
||||
load_from_code()
|
||||
migrate_to_sql()
|
||||
|
||||
/datum/controller/subsystem/law/proc/migrate_to_sql()
|
||||
for(var/datum/law/L in laws)
|
||||
log_debug("SSlaw: Migrating law [L.id] to SQL")
|
||||
var/DBQuery/law_update_query = dbcon.NewQuery({"
|
||||
INSERT IGNORE INTO ss13_law
|
||||
(law_id, name, description, min_fine, max_fine, min_brig_time, max_brig_time, severity, felony)
|
||||
VALUES
|
||||
(:law_id:, :name:, :desc:, :min_fine:, :max_fine:, :min_brig_time:, :max_brig_time:, :severity:, :felony:)
|
||||
"})
|
||||
law_update_query.Execute(list(
|
||||
"law_id"=L.id,
|
||||
"name"=L.name,
|
||||
"desc"=L.desc,
|
||||
"min_fine"=L.min_fine,
|
||||
"max_fine"=L.max_fine,
|
||||
"min_brig_time"=L.min_brig_time,
|
||||
"max_brig_time"=L.max_brig_time,
|
||||
"severity"=L.severity,
|
||||
"felony"=L.felony
|
||||
))
|
||||
return
|
||||
@@ -128,7 +128,7 @@ DBQuery/proc/Execute(var/list/argument_list = null, var/pass_not_found = 0, sql_
|
||||
|
||||
var/error = ErrorMsg()
|
||||
if (error)
|
||||
error("SQL Error: '[error]'")
|
||||
log_debug("SQL Error: '[error]'",SEVERITY_ERROR)
|
||||
// This is hacky and should probably be changed
|
||||
if (error == "MySQL server has gone away")
|
||||
log_game("MySQL connection drop detected, attempting to reconnect.")
|
||||
|
||||
@@ -162,7 +162,7 @@
|
||||
. += "<br><hr>"
|
||||
. += "<center>"
|
||||
. += "<a href='?src=\ref[src];button=render_guilty'>Render Guilty</a>"
|
||||
// . += "<a href='?src=\ref[src];button=render_guilty_fine'>Render Guilty - Fine</a>"
|
||||
. += "<a href='?src=\ref[src];button=render_guilty_fine'>Render Guilty - Fine</a>"
|
||||
. += "</center>"
|
||||
|
||||
return .
|
||||
@@ -368,8 +368,8 @@
|
||||
. += "<tr>"
|
||||
. += "<td><b>[L.name]</b></td>"
|
||||
. += "<td><i>[L.desc]</i></td>"
|
||||
. += "<td>[L.min_brig_time] - [L.max_brig_time] minutes</td>"
|
||||
. += "<td>[L.min_fine]-[L.max_fine]cR</td>"
|
||||
. += "<td>[L.get_brig_time_string()]</td>"
|
||||
. += "<td>[L.get_fine_string()]</td>"
|
||||
. += "<td><a href='?src=\ref[src];button=add_charge;law=\ref[L]'>Charge</a></td>"
|
||||
. += "</tr>"
|
||||
|
||||
@@ -398,8 +398,8 @@
|
||||
. += "<tr>"
|
||||
. += "<td><b>[L.name]</b></td>"
|
||||
. += "<td><i>[L.desc]</i></td>"
|
||||
. += "<td>[L.min_brig_time] - [L.max_brig_time] minutes</td>"
|
||||
. += "<td>[L.min_fine]-[L.max_fine]cR</td>"
|
||||
. += "<td>[L.get_brig_time_string()]</td>"
|
||||
. += "<td>[L.get_fine_string()]</td>"
|
||||
. += "<td><a href='?src=\ref[src];button=add_charge;law=\ref[L]'>Charge</a></td>"
|
||||
. += "</tr>"
|
||||
|
||||
@@ -427,7 +427,7 @@
|
||||
. += "<tr>"
|
||||
. += "<td><b>[L.name]</b></td>"
|
||||
. += "<td><i>[L.desc]</i></td>"
|
||||
. += "<td>[L.min_brig_time] - [L.max_brig_time] minutes</td>"
|
||||
. += "<td>[L.get_brig_time_string()]</td>"
|
||||
. += "<td><a href='?src=\ref[src];button=add_charge;law=\ref[L]'>Charge</a></td>"
|
||||
. += "</tr>"
|
||||
|
||||
@@ -457,38 +457,66 @@
|
||||
user << "<span class='alert'>[error]</span>"
|
||||
return
|
||||
|
||||
incident.renderGuilty( user )
|
||||
print_incident_overview(incident.renderGuilty(user, 0))
|
||||
var/obj/item/weapon/card/id/card = incident.card.resolve()
|
||||
if( incident.brig_sentence < PERMABRIG_SENTENCE)
|
||||
ping( "\The [src] pings, \"[card] has been found guilty of their crimes!\"" )
|
||||
ping( "\The [src] pings, \"[card.registered_name] has been found guilty of their crimes!\"" )
|
||||
else
|
||||
pingx3( "\The [src] pings, \"[card] has been found guilty of their crimes and earned a HuT Sentence\"" )
|
||||
pingx3( "\The [src] pings, \"[card.registered_name] has been found guilty of their crimes and earned a HuT Sentence\"" )
|
||||
|
||||
incident = null
|
||||
menu_screen = "main_menu"
|
||||
|
||||
// /obj/machinery/computer/sentencing/proc/render_guilty_fine( var/mob/living/user, var/obj/item/weapon/card/id/C )
|
||||
// if( !incident )
|
||||
// user << "<span class='alert'>There is no active case!</span>"
|
||||
// return
|
||||
//
|
||||
// if( !istype( user ))
|
||||
// return
|
||||
//
|
||||
// var/error = print_incident_report()
|
||||
//
|
||||
// if( error )
|
||||
// user << "<span class='alert'>[error]</span>"
|
||||
// return
|
||||
//
|
||||
// //TODO: Try to charge the criminal if not return and print error message
|
||||
//
|
||||
// incident.renderGuilty( user )
|
||||
//
|
||||
// ping( "\The [src] pings, \"[incident.card] has been fined for their crimes!\"" )
|
||||
//
|
||||
// incident = null
|
||||
// menu_screen = "main_menu"
|
||||
/obj/machinery/computer/sentencing/proc/render_guilty_fine( var/mob/living/user )
|
||||
if(!incident)
|
||||
user << "<span class='alert'>There is no active case!</span>"
|
||||
return
|
||||
|
||||
if(!istype(user))
|
||||
return
|
||||
|
||||
if(incident.fine <= 0)
|
||||
buzz("\The [src] buzzes, \"No fine has been entered!\"")
|
||||
return
|
||||
|
||||
//Lets check if there is a felony amongst the crimes
|
||||
for(var/datum/law/L in incident.charges)
|
||||
if(L.felony)
|
||||
buzz("\The [src] buzzes, \"The crimes are too severe to apply a fine!\"")
|
||||
if(!L.can_fine())
|
||||
buzz("\The [src] buzzes, \"It is not possible to fine for [L.name]\"")
|
||||
return
|
||||
|
||||
//Try to resole the security account first
|
||||
var/datum/money_account/security_account = department_accounts["Security"]
|
||||
if(!security_account)
|
||||
buzz("\The [src] buzzes, \"Could not get security account!\"")
|
||||
return
|
||||
|
||||
var/obj/item/weapon/card/id/card = incident.card.resolve()
|
||||
//Let´s get the account of the suspect and verify they have enough money
|
||||
var/datum/money_account/suspect_account = get_account(card.associated_account_number)
|
||||
if(!suspect_account)
|
||||
buzz("\The [src] buzzes, \"Could not get suspect account!\"")
|
||||
return
|
||||
|
||||
if(suspect_account.money < incident.fine)
|
||||
buzz("\The [src] buzzes, \"There is not enough money in the account to pay the fine!\"")
|
||||
return
|
||||
|
||||
charge_to_account(suspect_account.account_number,security_account.owner_name,"Incident: [incident.UID]","Sentencing Console",-incident.fine)
|
||||
charge_to_account(security_account.account_number,suspect_account.owner_name,"Incident: [incident.UID]Fine","Sentencing Console",incident.fine)
|
||||
print_incident_overview(incident.renderGuilty(user,1))
|
||||
|
||||
ping("\The [src] pings, \"[card.registered_name] has been fined for their crimes!\"")
|
||||
|
||||
incident = null
|
||||
menu_screen = "main_menu"
|
||||
|
||||
/obj/machinery/computer/sentencing/proc/print_incident_overview(var/text)
|
||||
var/obj/item/weapon/paper/P = new /obj/item/weapon/paper
|
||||
P.set_content_unsafe("Incident Summary",text)
|
||||
print(P)
|
||||
|
||||
/obj/machinery/computer/sentencing/proc/print_incident_report( var/sentence = 1 )
|
||||
var/error = incident.missingSentenceReq()
|
||||
@@ -636,20 +664,13 @@
|
||||
if( alert("No incident notes were added. Adding a short description of the incident is highly recommended. Do you still want to continue with the print?",,"Yes","No") == "No" )
|
||||
return
|
||||
render_guilty( usr )
|
||||
// if( "render_guilty_fine")
|
||||
// //Check for the notes
|
||||
// if( !incident.notes )
|
||||
// if( alert("No incident notes were added. Adding a short description of the incident is highly recommended. Do you still want to continue with the print?",,"Yes","No") == "No" )
|
||||
// return
|
||||
// //Get the ID Card
|
||||
// var/obj/item/weapon/card/id/C = usr.get_active_hand()
|
||||
// if( istype( C ))
|
||||
// if( incident && C.mob )
|
||||
// render_guilty_fine( usr, C)
|
||||
// else
|
||||
// usr << "<span class='alert'>\The [src] buzzes, \"ID card not tied to a NanoTrasen Employee!\"</span>"
|
||||
// else
|
||||
// usr << "<span class='alert'>\The [src] buzzes, \"The suspects ID is required to fine them\"</span>"
|
||||
if( "render_guilty_fine" )
|
||||
//Check for the notes
|
||||
if( !incident.notes )
|
||||
if( alert("No incident notes were added. Adding a short description of the incident is highly recommended. Do you still want to continue with the print?",,"Yes","No") == "No" )
|
||||
return
|
||||
//Get the ID Card
|
||||
render_guilty_fine( usr )
|
||||
|
||||
add_fingerprint(usr)
|
||||
updateUsrDialog()
|
||||
|
||||
@@ -296,6 +296,13 @@ Class Procs:
|
||||
state(text, "blue")
|
||||
playsound(src.loc, 'sound/machines/pingx3.ogg', 50, 0)
|
||||
|
||||
/obj/machinery/proc/buzz(text=null)
|
||||
if (!text)
|
||||
text = "\The [src] buzzes."
|
||||
|
||||
state(text, "blue")
|
||||
playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0) //TODO: Check if that one is the correct sound
|
||||
|
||||
/obj/machinery/proc/shock(mob/user, prb)
|
||||
if(inoperable())
|
||||
return 0
|
||||
|
||||
@@ -134,14 +134,25 @@
|
||||
|
||||
return max
|
||||
|
||||
/datum/crime_incident/proc/renderGuilty( var/mob/living/user )
|
||||
//type: 0 - brig sentence, 1 - fine, 2 - prison sentence
|
||||
/datum/crime_incident/proc/renderGuilty( var/mob/living/user, var/type=0 )
|
||||
if( !criminal )
|
||||
return
|
||||
|
||||
created_by = "[user.ckey] - [user.real_name]"
|
||||
|
||||
if(type == 0)
|
||||
prison_sentence = 0
|
||||
fine = 0
|
||||
else if(type == 1)
|
||||
brig_sentence = 0
|
||||
prison_sentence = 0
|
||||
else if(type == 2)
|
||||
brig_sentence = 0
|
||||
fine = 0
|
||||
|
||||
saveCharInfraction()
|
||||
generateReport()
|
||||
return generateReport()
|
||||
|
||||
/datum/crime_incident/proc/generateReport()
|
||||
. = "<center>Security Incident Report</center><hr>"
|
||||
@@ -149,18 +160,18 @@
|
||||
. += "<br>"
|
||||
. += "<b>CRIMINAL</b>: <i>[criminal]</i><br><br>"
|
||||
|
||||
. += "[criminal] was found guilty of the following crimes on [time2text(world.realtime, "DD/MMM")]/[game_year]. "
|
||||
. += "[criminal] was found guilty of the following crimes on [game_year]-[time2text(world.realtime, "MMM-DD")].<br>"
|
||||
|
||||
if( !brig_sentence && !prison_sentence )
|
||||
. += "As decided by the arbiter(s), they will serve no time for their crimes."
|
||||
else
|
||||
if( brig_sentence != 0 )
|
||||
. += "As decided by the arbiter(s), they will serve the following sentence:<br>"
|
||||
if( brig_sentence )
|
||||
if( brig_sentence >= PERMABRIG_SENTENCE )
|
||||
. += "\t<b>BRIG</b>: <i>Holding until transfer</i><br>"
|
||||
else
|
||||
. += "\t<b>BRIG</b>: <i>[brig_sentence] minutes</i><br>"
|
||||
|
||||
if( brig_sentence >= PERMABRIG_SENTENCE )
|
||||
. += "\t<b>BRIG</b>: <i>Holding until transfer</i><br>"
|
||||
else
|
||||
. += "\t<b>BRIG</b>: <i>[brig_sentence] minutes</i><br>"
|
||||
else if ( fine != 0 )
|
||||
. += "As decided by the arbiter(s), they have been fined [fine] credits.<br>"
|
||||
else
|
||||
. += "As decided by the arbiter(s), they will serve no time for their crimes.<br>"
|
||||
. += "<br><table>"
|
||||
. += "<tr><th colspan='2'>CHARGES</th></tr>"
|
||||
for( var/datum/law/L in charges )
|
||||
|
||||
+19
-1
@@ -30,4 +30,22 @@ $PRISONER_NAME was found guilty of $CRIME on $DATE. Their sentence was $SENTENCE
|
||||
var/max_prison_time = 0 A sentence totalling 60 days or more is a life sentence*/
|
||||
|
||||
var/severity = 0 // 1 - Low, 2 - Medium, 3 - High
|
||||
var/felony = 0 // Does this law carry a felony conviction?
|
||||
var/felony = 0 // Does this law carry a felony conviction?
|
||||
|
||||
/datum/law/proc/can_fine()
|
||||
if(max_fine == 0)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/law/proc/get_fine_string()
|
||||
if(max_fine == 0)
|
||||
return "n.a."
|
||||
return "[min_fine] - [max_fine] cR"
|
||||
|
||||
/datum/law/proc/get_brig_time_string()
|
||||
if(min_brig_time >= PERMABRIG_SENTENCE)
|
||||
return "HuT"
|
||||
if(max_brig_time >= PERMABRIG_SENTENCE)
|
||||
return "[min_brig_time] minutes - HuT"
|
||||
else
|
||||
return "[min_brig_time] - [max_brig_time] minutes"
|
||||
@@ -0,0 +1,37 @@
|
||||
################################
|
||||
# Example Changelog File
|
||||
#
|
||||
# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
|
||||
#
|
||||
# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
|
||||
# When it is, any changes listed below will disappear.
|
||||
#
|
||||
# Valid Prefixes:
|
||||
# bugfix
|
||||
# wip (For works in progress)
|
||||
# tweak
|
||||
# soundadd
|
||||
# sounddel
|
||||
# rscadd (general adding of nice things)
|
||||
# rscdel (general deleting of nice things)
|
||||
# imageadd
|
||||
# imagedel
|
||||
# maptweak
|
||||
# spellcheck (typo fixes)
|
||||
# experiment
|
||||
# balance
|
||||
#################################
|
||||
|
||||
# Your name.
|
||||
author: Arrow768
|
||||
|
||||
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
|
||||
delete-after: True
|
||||
|
||||
# Any changes you've made. See valid prefix list above.
|
||||
# INDENT WITH TWO SPACES. NOT TABS. SPACES.
|
||||
# SCREW THIS UP AND IT WON'T WORK.
|
||||
# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
|
||||
# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
|
||||
changes:
|
||||
- rscadd: "The sentencing console has been upgraded with a integrated fining system."
|
||||
Reference in New Issue
Block a user