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:
Werner
2018-04-29 20:34:49 +03:00
committed by Erki
parent ed504cbe20
commit cfd1900ee4
10 changed files with 253 additions and 70 deletions
+21
View File
@@ -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;
-2
View File
@@ -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
+12 -9
View File
@@ -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"
+67
View File
@@ -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
+1 -1
View File
@@ -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.")
+66 -45
View File
@@ -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()
+7
View File
@@ -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
+23 -12
View File
@@ -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
View File
@@ -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"
+37
View File
@@ -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."