diff --git a/baystation12.dme b/baystation12.dme
index 97a7443639e..647e95ad1be 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -442,6 +442,7 @@
#include "code\game\machinery\rechargestation.dm"
#include "code\game\machinery\requests_console.dm"
#include "code\game\machinery\robot_fabricator.dm"
+#include "code\game\machinery\scanner.dm"
#include "code\game\machinery\seed_extractor.dm"
#include "code\game\machinery\shieldgen.dm"
#include "code\game\machinery\sink.dm"
diff --git a/code/game/machinery/scanner.dm b/code/game/machinery/scanner.dm
new file mode 100644
index 00000000000..857ed1dbbfc
--- /dev/null
+++ b/code/game/machinery/scanner.dm
@@ -0,0 +1,140 @@
+//not a computer
+obj/machinery/scanner
+ name = "Identity Analyser"
+ var/outputdir = 0
+ icon = 'stationobjs.dmi'
+ icon_state = "scanner_idle"
+ density = 1
+ anchored = 1
+ var/lastuser = null
+
+obj/machinery/scanner/New()
+ if(!outputdir)
+ switch(dir)
+ if(1)
+ outputdir = 2
+ if(2)
+ outputdir = 1
+ if(4)
+ outputdir = 8
+ if(8)
+ outputdir = 4
+ if(!outputdir)
+ outputdir = 8
+
+/obj/machinery/scanner/process()
+ if(stat & NOPOWER)
+ return
+ use_power(50)
+
+/obj/machinery/scanner/power_change()
+ if(!powered())
+ spawn(rand(0, 15))
+ icon_state = "scanner_off"
+ stat |= NOPOWER
+ else
+ icon_state = "scanner_idle"
+ stat &= ~NOPOWER
+
+obj/machinery/scanner/attack_hand(mob/living/carbon/human/user)
+ if(stat & NOPOWER)
+ return
+ if(!ishuman(user) || lastuser == user.real_name)
+ return
+ use_power(500)
+ flick("scanner_on",src)
+ lastuser = user.real_name
+ var/mname = user.real_name
+ var/dna = user.dna.unique_enzymes
+ var/bloodtype = user.b_type
+ var/fingerprint = md5(user.dna.uni_identity)
+ var/list/marks = list()
+ var/age = user.age
+ var/gender = user.gender
+ /* no dbstuff yet
+ var/DBQuery/cquery = dbcon.NewQuery("SELECT * from jobban WHERE ckey='[user.ckey]'")
+ if(!cquery.Execute()) return
+ else
+ while(cquery.NextRow())
+ var/list/row = cquery.GetRowData()
+ marks += row["rank"]
+ */
+ var/text = {"
+
Report
+ Name: [mname]
+ Age: [age]
+ Sex: [gender]
+ DNA: [dna]
+ Blood Type: [bloodtype]
+ Fingerprint: [fingerprint]
+
+ Black Marks:
"}
+ for(var/A in marks)
+ text += "\red[A]
"
+ user << "\blue You feel a sting as the scanner sucks all your information out of you and sticks it in it's database."
+ var/turf/T = get_step(src,outputdir)
+ var/obj/item/weapon/paper/print = new(T)
+ print.name = "[mname] Report"
+ print.info = text
+ print.stamped = 1
+
+ for(var/datum/data/record/test in data_core.general)
+ if (test.fields["name"] == mname)
+ return
+
+ var/datum/data/record/G = new()
+ var/datum/data/record/M = new()
+ var/datum/data/record/S = new()
+ var/datum/data/record/L = new()
+ G.fields["rank"] = "Unassigned"
+ G.fields["name"] = mname
+ G.fields["id"] = text("[]", add_zero(num2hex(rand(1, 1.6777215E7)), 6))
+ M.fields["name"] = G.fields["name"]
+ M.fields["id"] = G.fields["id"]
+ S.fields["name"] = G.fields["name"]
+ S.fields["id"] = G.fields["id"]
+ if(gender == FEMALE)
+ G.fields["sex"] = "Female"
+ else
+ G.fields["sex"] = "Male"
+ G.fields["age"] = text("[]", age)
+ G.fields["fingerprint"] = text("[]", fingerprint)
+ G.fields["p_stat"] = "Active"
+ G.fields["m_stat"] = "Stable"
+ M.fields["b_type"] = text("[]", bloodtype)
+ M.fields["b_dna"] = dna
+ M.fields["mi_dis"] = "None"
+ M.fields["mi_dis_d"] = "No minor disabilities have been declared."
+ M.fields["ma_dis"] = "None"
+ M.fields["ma_dis_d"] = "No major disabilities have been diagnosed."
+ M.fields["alg"] = "None"
+ M.fields["alg_d"] = "No allergies have been detected in this patient."
+ M.fields["cdi"] = "None"
+ M.fields["cdi_d"] = "No diseases have been diagnosed at the moment."
+ M.fields["notes"] = "No notes."
+ S.fields["criminal"] = "None"
+ S.fields["mi_crim"] = "None"
+ S.fields["mi_crim_d"] = "No minor crime convictions."
+ S.fields["ma_crim"] = "None"
+ S.fields["ma_crim_d"] = "No major crime convictions."
+ S.fields["notes"] = "No notes."
+
+ //Begin locked reporting
+ L.fields["name"] = mname
+ L.fields["sex"] = gender
+ L.fields["age"] = age
+ L.fields["id"] = md5("[mname][user.mind.assigned_role]")
+ L.fields["rank"] = "Unknown"
+ L.fields["b_type"] = bloodtype
+ L.fields["b_dna"] = dna
+ L.fields["enzymes"] = user.dna.struc_enzymes
+ L.fields["identity"] = user.dna.uni_identity
+ L.fields["image"] = getFlatIcon(user,0)//What the person looks like. Naked, in this case.
+ //End locked reporting
+
+ data_core.general += G
+ data_core.medical += M
+ data_core.security += S
+ data_core.locked += L
+
+
diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm
index 7a3395921b1..a1575253ed9 100644
--- a/code/modules/mob/new_player/new_player.dm
+++ b/code/modules/mob/new_player/new_player.dm
@@ -34,7 +34,7 @@
if(watch_locations.len>0)
loc = pick(watch_locations)
- if(!preferences.savefile_load(src, 0))
+ if(!preferences.savefile_load(src, 1))
preferences.ShowChoices(src)
if(!client.changes)
changes()
@@ -43,7 +43,7 @@
if(!client.changes && preferences.lastchangelog!=lastchangelog)
changes()
preferences.lastchangelog = lastchangelog
- preferences.savefile_save(src)
+ preferences.savefile_save(src, 1)
new_player_panel()
//PDA Resource Initialisation =======================================================>
@@ -117,11 +117,12 @@
else output += "You are ready (Cancel)
"
else
+ output += "View the Crew Manifest
"
output += "Join Game!
"
output += "
Observe
"
- src << browse(output,"window=playersetup;size=250x210;can_close=0")
+ src << browse(output,"window=playersetup;size=250x233;can_close=0")
return
Stat()
@@ -192,6 +193,9 @@
if(href_list["late_join"])
LateChoices()
+ if(href_list["manifest"])
+ ViewManifest()
+
if(href_list["SelectedJob"])
if(!client.authenticated)
src << "You are not authorized to enter the game."
@@ -339,6 +343,14 @@
return new_character
+ proc/ViewManifest()
+ var/dat = ""
+ dat += "Crew Manifest
"
+ for(var/datum/data/record/t in data_core.general)
+ dat += "[t.fields["name"]] - [t.fields["rank"]]
"
+ dat += "
"
+
+ src << browse(dat, "window=manifest;size=300x420;can_close=1")
Move()
return 0
diff --git a/code/modules/mob/new_player/preferences.dm b/code/modules/mob/new_player/preferences.dm
index 6c8b2c9a173..de97f31b6d4 100644
--- a/code/modules/mob/new_player/preferences.dm
+++ b/code/modules/mob/new_player/preferences.dm
@@ -102,6 +102,9 @@ datum/preferences
job_engsec_med = 0
job_engsec_low = 0
+ // slot stuff
+ var/slotname
+ var/curslot = 0
New()
hair_style = new/datum/sprite_accessory/hair/short
@@ -172,14 +175,32 @@ datum/preferences
src.be_special = 0
dat += "
"
- if(!IsGuestKey(user.key))
- dat += "Load Setup
"
- dat += "Save Setup
"
+ // slot options
+ if (!IsGuestKey(user.key))
+ if(!curslot)
+ dat += "Save Slot 1
"
+ else
+ dat += "Save Slot [curslot]
"
+ dat += "Load
"
+ dat += "Create New Slot
"
dat += "Reset Setup
"
dat += ""
user << browse(dat, "window=preferences;size=300x710")
+ proc/loadsave(mob/user)
+ var/dat = ""
+ dat += ""
+
+ var/list/slots = savefile_getslots(user)
+ for(var/slot=1, slot<=slots.len, slot++)
+ dat += "Load Slot [slot] ([slots[slot]]) (R)
"
+
+ dat += "Close
"
+ dat += ""
+ user << browse(dat, "window=saves;size=300x640")
+ proc/closesave(mob/user)
+ user << browse(null, "window=saves;size=300x640")
proc/SetChoices(mob/user, changedjob)
var/HTML = ""
@@ -536,13 +557,51 @@ datum/preferences
if(link_tags["b_random_name"])
be_random_name = !be_random_name
+ // slot links
if(!IsGuestKey(user.key))
- if(link_tags["save"])
- savefile_save(user)
+ if(link_tags["saveslot"])
+ var/slot = text2num(link_tags["saveslot"])
- else if(link_tags["load"])
- if(!savefile_load(user, 0))
+ savefile_save(user, slot)
+
+ else if(link_tags["loadslot"])
+ var/slot = text2num(link_tags["loadslot"])
+ if(slot == "CLOSE")
+ closesave(user)
+ return
+ if(!savefile_load(user, slot))
alert(user, "You do not have a savefile.")
+ else
+ curslot = slot
+ loadsave(user)
+ if(link_tags["removeslot"])
+ var/slot = text2num(link_tags["removeslot"])
+ if(!slot)
+ return
+
+ savefile_removeslot(user, slot)
+
+ usr << "Slot [slot] Deleted."
+ slot = 1
+ loadsave(usr)
+ if(link_tags["loadslot2"])
+ loadsave(user)
+ if(link_tags["createslot"])
+ var/list/slots = savefile_getslots(user)
+ var/count = slots.len
+ count++
+ if(count > 10)
+ usr << "You have reached the character limit."
+ return
+ var/slotname = input(usr,"Choose a name for your slot","Name","Default")
+
+ savefile_createslot(user, slotname)
+
+ if(!savefile_load(user, count))
+ alert(user, "You do not have a savefile.")
+ else
+ curslot = count
+ closesave(user)
if(link_tags["reset_all"])
gender = MALE
diff --git a/code/modules/mob/new_player/savefile.dm b/code/modules/mob/new_player/savefile.dm
index 5a206f2e0db..4f9678e09a2 100644
--- a/code/modules/mob/new_player/savefile.dm
+++ b/code/modules/mob/new_player/savefile.dm
@@ -4,16 +4,94 @@
datum/preferences/proc/savefile_path(mob/user)
return "data/player_saves/[copytext(user.ckey, 1, 2)]/[user.ckey]/preferences.sav"
-datum/preferences/proc/savefile_save(mob/user)
+datum/preferences/proc/savefile_getslots(mob/user)
+ if(IsGuestKey(user.key))
+ return new/list()
+
+ var/path = savefile_path(user)
+ if(!fexists(path))
+ return new/list()
+
+ var/list/slots = new()
+ var/savefile/F = new(path)
+
+ // slot 1
+ slots.Add(F["slotname"] ? F["slotname"] : "Default") // allow old prefs saves to be loaded as slot 1
+
+ // slots 2 - len
+ for(var/slot=2, slot<=F.dir.len, slot++)
+ var/dname = F.dir[slot]
+ if(copytext(dname, 1, 6) == "slot.")
+ slots.Add(copytext(dname, 6))
+
+ return slots
+
+datum/preferences/proc/savefile_createslot(mob/user, slotname)
+ if(IsGuestKey(user.key))
+ return
+
+ var/path = savefile_path(user)
+ if(!fexists(path))
+ return
+
+ var/savefile/F = new(path)
+
+ // 1st?
+ if(!F["real_name"])
+ F["slotname"] = "Default"
+ randomize_name()
+ else
+ F.dir.Add("slot." + slotname)
+
+ var/list/slots = savefile_getslots(user)
+ savefile_save(user, slots.len)
+
+datum/preferences/proc/savefile_removeslot(mob/user, slot)
+ if(IsGuestKey(user.key))
+ return
+
+ var/path = savefile_path(user)
+ if(!fexists(path))
+ return
+
+ var/list/slots = savefile_getslots(user)
+
+ if(slot > 1)
+ var/savefile/F = new(path)
+ F.dir.Remove("slot." + slots[slot])
+ else if(slots.len >= 2)
+ // otherwise, we're deleting slot 1, and must move slot 2 to slot 1
+ savefile_load(user, 2)
+ savefile_save(user, 1)
+
+ var/savefile/F = new(path)
+ F["slotname"] = slots[2] // slot 1's name <- slot 2's name
+ F.dir.Remove("slot." + slots[2])
+ else
+ // otherwise, we're wiping the last save (slot 1)
+ // actually no, that makes unintuitive, weird things happen
+ //F["slotname"] = null
+ //F["real_name"] = null
+ user << "You must have at least one slot!"
+
+datum/preferences/proc/savefile_save(mob/user, slot)
if (IsGuestKey(user.key))
return 0
- var/savefile/F = new /savefile(src.savefile_path(user))
-// var/version
-// F["version"] >> version
+ var/list/slots = savefile_getslots(user)
+ var/savefile/F = new(savefile_path(user))
+
+ // var/version
+ // F["version"] >> version
F["version"] << SAVEFILE_VERSION_MAX
+ // make this compatible with old single-slot system, making slot 1 be in root
+ if(slot != 1)
+ if(slots.len < slot)
+ return 0
+ F.cd = "slot." + slots[slot]
+
F["real_name"] << src.real_name
F["name_is_always_random"] << src.be_random_name
@@ -62,13 +140,15 @@ datum/preferences/proc/savefile_save(mob/user)
// returns 1 if loaded (or file was incompatible)
// returns 0 if savefile did not exist
-datum/preferences/proc/savefile_load(mob/user)
+datum/preferences/proc/savefile_load(mob/user, slot)
if(IsGuestKey(user.key)) return 0
var/path = savefile_path(user)
- if(!fexists(path)) return 0
+ if(!fexists(path))
+ // make it then!
+ savefile_save(user, slot)
- var/savefile/F = new /savefile(path)
+ var/savefile/F = new(path)
var/version = null
F["version"] >> version
@@ -78,6 +158,15 @@ datum/preferences/proc/savefile_load(mob/user)
alert(user, "Your savefile was incompatible with this version and was deleted.")
return 0
+ // make this compatible with old single-slot system, making slot 1 be in root
+ if(slot == 0)
+ return 0
+ if(slot != 1)
+ var/list/slots = savefile_getslots(user)
+ if(slots.len < slot)
+ return 0
+ F.cd = "slot." + slots[slot]
+
F["real_name"] >> src.real_name
F["gender"] >> src.gender
F["age"] >> src.age