diff --git a/SQL/migrate/V026__law_database.sql b/SQL/migrate/V026__law_database.sql
new file mode 100644
index 00000000000..b6c3a18faaa
--- /dev/null
+++ b/SQL/migrate/V026__law_database.sql
@@ -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;
\ No newline at end of file
diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm
index 84a43f42104..eec5b5c2140 100644
--- a/code/__defines/misc.dm
+++ b/code/__defines/misc.dm
@@ -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
diff --git a/code/_helpers/logging.dm b/code/_helpers/logging.dm
index fbd6411c4e7..8bea89a5a75 100644
--- a/code/_helpers/logging.dm
+++ b/code/_helpers/logging.dm
@@ -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)
- . += ""
+ . += ""
if(C && C.holder && C.holder.fakekey && !include_name)
. += "Administrator"
diff --git a/code/controllers/subsystems/law.dm b/code/controllers/subsystems/law.dm
index a54d67df741..9f1e0fec00d 100644
--- a/code/controllers/subsystems/law.dm
+++ b/code/controllers/subsystems/law.dm
@@ -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
\ No newline at end of file
diff --git a/code/defines/procs/dbcore.dm b/code/defines/procs/dbcore.dm
index 9c51134667a..541bf6aeae5 100644
--- a/code/defines/procs/dbcore.dm
+++ b/code/defines/procs/dbcore.dm
@@ -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.")
diff --git a/code/game/machinery/computer/sentencing.dm b/code/game/machinery/computer/sentencing.dm
index 72e9ff48529..c3845c05642 100644
--- a/code/game/machinery/computer/sentencing.dm
+++ b/code/game/machinery/computer/sentencing.dm
@@ -162,7 +162,7 @@
. += "
"
. += ""
. += " "
@@ -398,8 +398,8 @@
. += "[L.name] "
. += "[L.desc] "
- . += "[L.min_brig_time] - [L.max_brig_time] minutes "
- . += "[L.min_fine]-[L.max_fine]cR "
+ . += "[L.get_brig_time_string()] "
+ . += "[L.get_fine_string()] "
. += "Charge "
. += ""
. += " "
@@ -427,7 +427,7 @@
. += "[L.name] "
. += "[L.desc] "
- . += "[L.min_brig_time] - [L.max_brig_time] minutes "
- . += "[L.min_fine]-[L.max_fine]cR "
+ . += "[L.get_brig_time_string()] "
+ . += "[L.get_fine_string()] "
. += "Charge "
. += ""
. += " "
@@ -457,38 +457,66 @@
user << "[error]"
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 << "There is no active case!"
-// return
-//
-// if( !istype( user ))
-// return
-//
-// var/error = print_incident_report()
-//
-// if( error )
-// user << "[error]"
-// 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 << "There is no active case!"
+ 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 << "\The [src] buzzes, \"ID card not tied to a NanoTrasen Employee!\""
- // else
- // usr << "\The [src] buzzes, \"The suspects ID is required to fine them\""
+ 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()
diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm
index bd6941952ff..97f31919a7e 100644
--- a/code/game/machinery/machinery.dm
+++ b/code/game/machinery/machinery.dm
@@ -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
diff --git a/code/modules/law/incident.dm b/code/modules/law/incident.dm
index 3b02dbc1f11..c3e592dc09f 100644
--- a/code/modules/law/incident.dm
+++ b/code/modules/law/incident.dm
@@ -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()
. = "[L.name] "
. += "[L.desc] "
- . += "[L.min_brig_time] - [L.max_brig_time] minutes "
+ . += "[L.get_brig_time_string()] "
. += "Charge "
. += "
"
@@ -149,18 +160,18 @@
. += "
"
. += "CRIMINAL: [criminal]
"
- . += "[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")].
"
- 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:
"
- if( brig_sentence )
- if( brig_sentence >= PERMABRIG_SENTENCE )
- . += "\tBRIG: Holding until transfer
"
- else
- . += "\tBRIG: [brig_sentence] minutes
"
-
+ if( brig_sentence >= PERMABRIG_SENTENCE )
+ . += "\tBRIG: Holding until transfer
"
+ else
+ . += "\tBRIG: [brig_sentence] minutes
"
+ else if ( fine != 0 )
+ . += "As decided by the arbiter(s), they have been fined [fine] credits.
"
+ else
+ . += "As decided by the arbiter(s), they will serve no time for their crimes.
"
. += "
| CHARGES |
|---|