Merge branch 'master' into hair-gradients

This commit is contained in:
mochi
2021-10-27 13:33:12 +02:00
1117 changed files with 53392 additions and 61705 deletions
+9 -1
View File
@@ -56,7 +56,6 @@
var/global/obj/screen/click_catcher/void
var/karma = 0
var/karma_spent = 0
var/karma_tab = 0
@@ -115,10 +114,19 @@
/// Is the client watchlisted
var/watchlisted = FALSE
/// Client's pAI save
var/datum/pai_save/pai_save
/// List of the clients CUIs
var/list/datum/custom_user_item/cui_entries = list()
/client/vv_edit_var(var_name, var_value)
switch(var_name)
// I know we will never be in a world where admins are editing client vars to let people bypass TOS
// But guess what, if I have the ability to overengineer something, I am going to do it
if("tos_consent")
return FALSE
// Dont fuck with this
if("cui_entries")
return FALSE
return ..()
+91 -245
View File
@@ -8,8 +8,8 @@
#define UPLOAD_LIMIT 10485760 //Restricts client uploads to the server to 10MB //Boosted this thing. What's the worst that can happen?
#define MIN_CLIENT_VERSION 513 // Minimum byond major version required to play.
//I would just like the code ready should it ever need to be used.
#define SUGGESTED_CLIENT_VERSION 513 // only integers (e.g: 513, 514) are useful here. This is the part BEFORE the ".", IE 513 out of 513.1542
#define SUGGESTED_CLIENT_BUILD 1542 // only integers (e.g: 1542, 1543) are useful here. This is the part AFTER the ".", IE 1542 out of 513.1542
#define SUGGESTED_CLIENT_VERSION 514 // only integers (e.g: 513, 514) are useful here. This is the part BEFORE the ".", IE 513 out of 513.1542
#define SUGGESTED_CLIENT_BUILD 1566 // only integers (e.g: 1542, 1543) are useful here. This is the part AFTER the ".", IE 1542 out of 513.1542
#define SSD_WARNING_TIMER 30 // cycles, not seconds, so 30=60s
@@ -113,7 +113,7 @@
if(!holder && received_discord_pm < world.time - 6000) // Worse they can do is spam discord for 10 minutes
to_chat(usr, "<span class='warning'>You are no longer able to use this, it's been more then 10 minutes since an admin on Discord has responded to you</span>")
return
if(prefs.muted & MUTE_ADMINHELP)
if(check_mute(ckey, MUTE_ADMINHELP))
to_chat(usr, "<span class='warning'>You cannot use this as your client has been muted from sending messages to the admins on Discord</span>")
return
cmd_admin_discord_pm()
@@ -147,14 +147,8 @@
karma_purchase(karma,5,"job","Brig Physician")
if("3")
karma_purchase(karma,30,"job","Nanotrasen Representative")
if("5")
if("4")
karma_purchase(karma,30,"job","Blueshield")
if("6")
karma_purchase(karma,30,"job","Mechanic")
if("7")
karma_purchase(karma,45,"job","Magistrate")
if("9")
karma_purchase(karma,30,"job","Security Pod Pilot")
return
if(href_list["KarmaBuy2"])
var/karma=verify_karma()
@@ -202,6 +196,11 @@
..() //redirect to hsrc.Topic()
/client/proc/get_display_key()
var/fakekey = src?.holder?.fakekey
return fakekey ? fakekey : key
/client/proc/is_content_unlocked()
if(!prefs.unlock_content)
to_chat(src, "Become a BYOND member to access member-perks and features, as well as support the engine that makes this game possible. <a href='http://www.byond.com/membership'>Click here to find out more</a>.")
@@ -268,8 +267,8 @@
show_update_prompt = TRUE
else if(byond_version == SUGGESTED_CLIENT_VERSION && byond_build < SUGGESTED_CLIENT_BUILD)
show_update_prompt = TRUE
// Actually sent to client much later, so it appears after MOTD.
// Actually sent to client much later, so it appears after MOTD.
to_chat(src, "<span class='warning'>If the title screen is black, resources are still downloading. Please be patient until the title screen appears.</span>")
GLOB.directory[ckey] = src
@@ -278,25 +277,58 @@
if(GLOB.configuration.admin.enable_localhost_autoadmin)
if(is_connecting_from_localhost())
new /datum/admins("!LOCALHOST!", R_HOST, ckey) // Makes localhost rank
holder = GLOB.admin_datums[ckey]
if(holder)
GLOB.admins += src
holder.owner = src
//preferences datum - also holds some persistant data for the client (because we may as well keep these datums to a minimum)
prefs = GLOB.preferences_datums[ckey]
if(!prefs)
prefs = new /datum/preferences(src)
GLOB.preferences_datums[ckey] = prefs
log_client_to_db(tdata) // Make sure our client exists in the DB
pai_save = new(src)
// This is where we load all of the clients stuff from the DB
if(SSdbcore.IsConnected())
// Load in all our client data from the DB
var/list/datum/db_query/login_queries = list() // List of queries to run for login processing
for(var/datum/client_login_processor/CLP as anything in GLOB.client_login_processors)
login_queries[CLP.type] = CLP.get_query(src)
SSdbcore.MassExecute(login_queries, TRUE, FALSE, TRUE, FALSE) // Warn, no qdel, assoc, no log
// Now do fancy things with the results
for(var/datum/client_login_processor/CLP as anything in GLOB.client_login_processors)
CLP.process_result(login_queries[CLP.type], src)
QDEL_LIST_ASSOC_VAL(login_queries) // Clear out the used queries
else
prefs.parent = src
// Set vars here that need to be set if the DB is offline
// Give blank prefs
prefs = new /datum/preferences(src)
prefs.character_saves = list()
// Random character
prefs.character_saves += new /datum/character_save
prefs.active_character = prefs.character_saves[1]
// ToS accepted
tos_consent = TRUE
prefs.last_ip = address //these are gonna be used for banning
prefs.last_id = computer_id //these are gonna be used for banning
if(world.byond_version >= 511 && byond_version >= 511 && prefs.clientfps)
fps = prefs.clientfps
fps = prefs.clientfps
// Check if the client has or has not accepted TOS
check_tos_consent()
// Log alts
if(length(related_accounts_ip))
log_admin("[key_name(src)] Alts by IP: [jointext(related_accounts_ip, " ")]")
if(length(related_accounts_cid))
log_admin("[key_name(src)] Alts by CID: [jointext(related_accounts_cid, " ")]")
// This sleeps so it has to go here. Dont fucking move it.
SSinstancing.update_playercache(ckey)
// This has to go here to avoid issues
// If you sleep past this point, you will get SSinput errors as well as goonchat errors
@@ -304,14 +336,25 @@
// YOU WILL BREAK STUFF. SERIOUSLY. -aa07
GLOB.clients += src
spawn() // Goonchat does some non-instant checks in start()
chatOutput.start()
var/_2fa_alert = FALSE // This is so we can display the message where it will be seen
if(holder)
on_holder_add()
add_admin_verbs()
// Must be async because any sleeps (happen in sql queries) will break connectings clients
INVOKE_ASYNC(src, .proc/admin_memo_output, "Show", FALSE, TRUE)
if(GLOB.configuration.system.is_production && (holder.rights & R_ADMIN) && prefs._2fa_status == _2FA_DISABLED) // If they are an admin and their 2FA is disabled
// No, check_rights() does not work in the above proc, because we dont have a mob yet
_2fa_alert = TRUE
// This also has to be manually done since no mob to use check_rights() on
deadmin()
verbs += /client/proc/readmin
GLOB.deadmins += ckey
else
on_holder_add()
add_admin_verbs()
// Must be async because any sleeps (happen in sql queries) will break connectings clients
INVOKE_ASYNC(src, .proc/admin_memo_output, "Show", FALSE, TRUE)
// Forcibly enable hardware-accelerated graphics, as we need them for the lighting overlays.
// (but turn them off first, since sometimes BYOND doesn't turn them on properly otherwise)
@@ -320,7 +363,6 @@
winset(src, null, "command=\".configure graphics-hwmode off\"")
winset(src, null, "command=\".configure graphics-hwmode on\"")
log_client_to_db(tdata)
. = ..() //calls mob.Login()
@@ -332,7 +374,6 @@
if(SSinput.initialized)
set_macros()
donator_check()
check_ip_intel()
send_resources()
@@ -379,22 +420,15 @@
if(M.client)
playercount += 1
// Update the state of the panic bunker based on current playercount
var/threshold = GLOB.configuration.general.panic_bunker_threshold
if((playercount > threshold) && (GLOB.panic_bunker_enabled == FALSE))
GLOB.panic_bunker_enabled = TRUE
message_admins("Panic bunker has been automatically enabled due to playercount rising above [threshold]")
if((playercount < threshold) && (GLOB.panic_bunker_enabled == TRUE))
GLOB.panic_bunker_enabled = FALSE
message_admins("Panic bunker has been automatically disabled due to playercount dropping below [threshold]")
// Tell clients about active testmerges
if(world.TgsAvailable() && length(GLOB.revision_info.testmerges))
to_chat(src, GLOB.revision_info.get_testmerge_chatmessage(TRUE))
INVOKE_ASYNC(src, .proc/cid_count_check)
if(check_rights(R_ADMIN, FALSE, mob)) // Mob is required. Dont even try without it.
to_chat(src, "The queue server is currently [SSqueue.queue_enabled ? "<font color='green'>enabled</font>" : "<font color='disabled'>disabled</font>"], with a threshold of <b>[SSqueue.queue_threshold]</b>. This <b>[SSqueue.persist_queue ? "will" : "will not"]</b> persist through rounds.")
if(_2fa_alert)
to_chat(src,"<span class='boldannounce'><big>You do not have 2FA enabled. Admin verbs will be unavailable until you have enabled 2FA.</big></span>") // Very fucking obvious
/client/proc/is_connecting_from_localhost()
@@ -418,7 +452,9 @@
GLOB.admins -= src
GLOB.directory -= ckey
GLOB.clients -= src
SSinstancing.update_playercache() // Clear us out
QDEL_NULL(chatOutput)
QDEL_NULL(pai_save)
if(movingmob)
movingmob.client_mobs_in_contents -= mob
UNSETEMPTY(movingmob.client_mobs_in_contents)
@@ -428,52 +464,18 @@
return QDEL_HINT_HARDDEL_NOW
/client/proc/donator_check()
set waitfor = FALSE // This needs to run async because any sleep() inside /client/New() breaks stuff badly
if(IsGuestKey(key))
return
if(!SSdbcore.IsConnected())
return
if(check_rights(R_ADMIN, 0, mob)) // Yes, the mob is required, regardless of other examples in this file, it won't work otherwise
donator_level = DONATOR_LEVEL_MAX
donor_loadout_points()
return
//Donator stuff.
var/datum/db_query/query_donor_select = SSdbcore.NewQuery("SELECT ckey, tier, active FROM donators WHERE ckey=:ckey", list(
"ckey" = ckey
))
if(!query_donor_select.warn_execute())
qdel(query_donor_select)
return
while(query_donor_select.NextRow())
if(!text2num(query_donor_select.item[3]))
// Inactive donator.
donator_level = 0
qdel(query_donor_select)
return
donator_level = text2num(query_donor_select.item[2])
donor_loadout_points()
break
qdel(query_donor_select)
/client/proc/donor_loadout_points()
if(donator_level > 0 && prefs)
prefs.max_gear_slots = GLOB.configuration.general.base_loadout_points + 5
/client/proc/log_client_to_db(connectiontopic)
set waitfor = FALSE // This needs to run async because any sleep() inside /client/New() breaks stuff badly
if(IsGuestKey(key))
return
if(!SSdbcore.IsConnected())
return
var/datum/db_query/query = SSdbcore.NewQuery("SELECT id, datediff(Now(),firstseen) as age FROM player WHERE ckey=:ckey", list(
var/datum/db_query/query = SSdbcore.NewQuery("SELECT id, datediff(Now(), firstseen) as age FROM player WHERE ckey=:ckey", list(
"ckey" = ckey
))
if(!query.warn_execute())
@@ -488,67 +490,29 @@
break
qdel(query)
var/datum/db_query/query_ip = SSdbcore.NewQuery("SELECT ckey FROM player WHERE ip=:address", list(
"address" = address
))
if(!query_ip.warn_execute())
qdel(query_ip)
return
related_accounts_ip = list()
while(query_ip.NextRow())
if(ckey != query_ip.item[1])
related_accounts_ip.Add("[query_ip.item[1]]")
qdel(query_ip)
var/datum/db_query/query_cid = SSdbcore.NewQuery("SELECT ckey FROM player WHERE computerid=:cid", list(
"cid" = computer_id
))
if(!query_cid.warn_execute())
qdel(query_cid)
return
related_accounts_cid = list()
while(query_cid.NextRow())
if(ckey != query_cid.item[1])
related_accounts_cid.Add("[query_cid.item[1]]")
qdel(query_cid)
var/admin_rank = "Player"
// Admins don't get slammed by this, I guess
if(holder)
admin_rank = holder.rank
// Admins don't get slammed by this, I guess
else
if(check_randomizer(connectiontopic))
return
//Log all the alts
if(related_accounts_cid.len)
log_admin("[key_name(src)] alts:[jointext(related_accounts_cid, " - ")]")
var/watchreason = check_watchlist(ckey)
if(watchreason)
message_admins("<font color='red'><B>Notice: </B></font><font color='blue'>[key_name_admin(src)] is on the watchlist and has just connected - Reason: [watchreason]</font>")
SSdiscord.send2discord_simple_noadmins("**\[Watchlist]** [key_name(src)] is on the watchlist and has just connected - Reason: [watchreason]")
watchlisted = TRUE
//Just the standard check to see if it's actually a number
if(sql_id)
//Just the standard check to see if it's actually a number
if(istext(sql_id))
sql_id = text2num(sql_id)
if(!isnum(sql_id))
return
return // Return here because if we somehow didnt pull a number from an INT column, EVERYTHING is breaking
if(sql_id)
var/client_address = address
if(!client_address) // Localhost can sometimes have no address set
client_address = "127.0.0.1"
//Player already identified previously, we need to just update the 'lastseen', 'ip' and 'computer_id' variables
var/datum/db_query/query_update = SSdbcore.NewQuery("UPDATE player SET lastseen = Now(), ip=:sql_ip, computerid=:sql_cid, lastadminrank=:sql_ar WHERE id=:sql_id", list(
var/datum/db_query/query_update = SSdbcore.NewQuery("UPDATE player SET lastseen=NOW(), ip=:sql_ip, computerid=:sql_cid, lastadminrank=:sql_ar WHERE id=:sql_id", list(
"sql_ip" = client_address,
"sql_cid" = computer_id,
"sql_ar" = admin_rank,
@@ -558,20 +522,12 @@
if(!query_update.warn_execute())
qdel(query_update)
return
qdel(query_update)
// After the regular update
INVOKE_ASYNC(src, /client/.proc/get_byond_account_date, FALSE) // Async to avoid other procs in the client chain being delayed by a web request
else
//New player!! Need to insert all the stuff
// Check new peeps for panic bunker
// AA TODO: Move this to world.IsBanned()
if(GLOB.panic_bunker_enabled)
var/threshold = GLOB.configuration.general.panic_bunker_threshold
src << "Server is not accepting connections from never-before-seen players until player count is less than [threshold]. Please try again later."
qdel(src)
return // Dont insert or they can just go in again
var/datum/db_query/query_insert = SSdbcore.NewQuery("INSERT INTO player (id, ckey, firstseen, lastseen, ip, computerid, lastadminrank) VALUES (null, :ckey, Now(), Now(), :ip, :cid, :rank)", list(
"ckey" = ckey,
"ip" = address,
@@ -582,7 +538,7 @@
qdel(query_insert)
return
qdel(query_insert)
// This is their first connection instance, so TRUE here to nofiy admins
// This is their first connection instance, so TRUE here to notify admins
// This needs to happen here to ensure they actually have a row to update
INVOKE_ASYNC(src, /client/.proc/get_byond_account_date, TRUE) // Async to avoid other procs in the client chain being delayed by a web request
@@ -601,11 +557,11 @@
log_debug("check_ip_intel: skip check for player [key_name_admin(src)] connecting from localhost.")
return
if(vpn_whitelist_check(ckey))
if(SSipintel.vpn_whitelist_check(ckey))
log_debug("check_ip_intel: skip check for player [key_name_admin(src)] [address] on whitelist.")
return
var/datum/ipintel/res = get_ip_intel(address)
var/datum/ipintel/res = SSipintel.get_ip_intel(address)
ip_intel = res.intel
verify_ip_intel()
@@ -613,7 +569,9 @@
if(ip_intel >= GLOB.configuration.ipintel.bad_rating)
var/detailsurl = GLOB.configuration.ipintel.details_url ? "(<a href='[GLOB.configuration.ipintel.details_url][address]'>IP Info</a>)" : ""
if(GLOB.configuration.ipintel.whitelist_mode)
// AA TODO: move this check to world.IsBanned()
// Do not move this to isBanned(). This may sound weird, but:
// This needs to happen after their account is put into the DB
// This way, admins can then note people
spawn(40) // This is necessary because without it, they won't see the message, and addtimer cannot be used because the timer system may not have initialized yet
message_admins("<span class='adminnotice'>IPIntel: [key_name_admin(src)] on IP [address] was rejected. [detailsurl]</span>")
var/blockmsg = "<B>Error: proxy/VPN detected. Proxy/VPN use is not allowed here. Deactivate it before you reconnect.</B>"
@@ -883,6 +841,7 @@
winset(src, "rpane.forumb", "background-color=#40628a;text-color=#FFFFFF")
winset(src, "rpane.rulesb", "background-color=#40628a;text-color=#FFFFFF")
winset(src, "rpane.githubb", "background-color=#40628a;text-color=#FFFFFF")
winset(src, "rpane.webmap", "background-color=#40628a;text-color=#FFFFFF")
/* Mainwindow */
winset(src, "mainwindow.saybutton", "background-color=#40628a;text-color=#FFFFFF")
winset(src, "mainwindow.mebutton", "background-color=#40628a;text-color=#FFFFFF")
@@ -915,6 +874,7 @@
winset(src, "rpane.forumb", "background-color=none;text-color=#000000")
winset(src, "rpane.rulesb", "background-color=none;text-color=#000000")
winset(src, "rpane.githubb", "background-color=none;text-color=#000000")
winset(src, "rpane.webmap", "background-color=none;text-color=#000000")
/* Mainwindow */
winset(src, "mainwindow.saybutton", "background-color=none;text-color=#000000")
winset(src, "mainwindow.mebutton", "background-color=none;text-color=#000000")
@@ -1066,7 +1026,7 @@
qdel(query_date)
// They have a date, lets bail
// They have a date already, lets bail
if(byondacc_date)
return
@@ -1107,120 +1067,6 @@
/client/proc/show_update_notice()
to_chat(src, "<span class='userdanger'>Your BYOND client (v: [byond_version].[byond_build]) is out of date. This can cause glitches. We highly suggest you download the latest client from <a href='https://www.byond.com/download/'>byond.com</a> before playing. You can also update via the BYOND launcher application.</span>")
/**
* Checks if the client has accepted TOS
*
* Runs some checks against vars and the DB to see if the client has accepted TOS.
* Returns TRUE or FALSE if they have or have not
*/
/client/proc/check_tos_consent()
// If there is no TOS, auto accept
if(!GLOB.join_tos)
tos_consent = TRUE
return TRUE
// If theres no DB, assume yes
if(!SSdbcore.IsConnected())
tos_consent = TRUE
return TRUE
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey FROM privacy WHERE ckey=:ckey AND consent=1", list(
"ckey" = ckey
))
if(!query.warn_execute())
qdel(query)
// If our query failed, just assume yes
tos_consent = TRUE
return TRUE
// If we returned a row, they accepted
while(query.NextRow())
qdel(query)
tos_consent = TRUE
return TRUE
qdel(query)
// If we are here, they have not accepted, and need to read it
return FALSE
/**
* Checks if the client has more than a configured amount of CIDs tied to them in the past
*/
/client/proc/cid_count_check()
// If the config is 0, disable this
if(GLOB.configuration.general.max_client_cid_history == 0)
return
// If we have no DB, dont even bother
if(!SSdbcore.IsConnected())
return
// Now query how many cids they have
var/datum/db_query/query_cidcheck = SSdbcore.NewQuery("SELECT COUNT(DISTINCT computerID) FROM connection_log WHERE ckey=:ckey", list(
"ckey" = ckey
))
if(!query_cidcheck.warn_execute())
qdel(query_cidcheck)
return
var/cidcount = 0
if(query_cidcheck.NextRow())
cidcount = query_cidcheck.item[1]
qdel(query_cidcheck)
if(cidcount > GLOB.configuration.general.max_client_cid_history)
// Check their notes for CID tracking in the past
var/has_note = FALSE
var/note_text = ""
var/datum/db_query/query_find_track_note = SSdbcore.NewQuery("SELECT notetext FROM notes WHERE ckey=:ckey AND adminckey=:ackey", list(
"ckey" = ckey,
"ackey" = CIDTRACKING_PSUEDO_CKEY
))
if(!query_find_track_note.warn_execute())
qdel(query_find_track_note)
return
if(query_find_track_note.NextRow())
note_text = query_find_track_note.item[1] // Grab existing note text
has_note = TRUE
qdel(query_find_track_note)
if(has_note) // They have a note. Update it.
var/new_text = "Connected on the date of this note with unique CID #[cidcount]"
// Only update the note if the text is different. Otherwise it bumps the timestamp when it shouldnt
if(note_text != new_text)
var/datum/db_query/query_update_track_note = SSdbcore.NewQuery("UPDATE notes SET notetext=:notetext, timestamp=NOW(), round_id=:rid WHERE ckey=:ckey AND adminckey=:ackey", list(
"notetext" = new_text,
"ckey" = ckey,
"ackey" = CIDTRACKING_PSUEDO_CKEY,
"rid" = GLOB.round_id
))
if(!query_update_track_note.warn_execute())
qdel(query_update_track_note)
return
qdel(query_update_track_note)
else // They dont have a note. Make one.
// NOT logged because its automatic and will spam logs otherwise
// Also right checking must be disabled because its a psuedockey, not a real one
add_note(ckey, "Connected on the date of this note with unique CID #[cidcount]", adminckey = CIDTRACKING_PSUEDO_CKEY, logged = FALSE, checkrights = FALSE, automated = TRUE)
var/show_warning = TRUE
// Check if they have a note that matches the warning suppressor
var/datum/db_query/query_find_note = SSdbcore.NewQuery("SELECT id FROM notes WHERE ckey=:ckey AND notetext=:notetext", list(
"ckey" = ckey,
"notetext" = CIDWARNING_SUPPRESSED_NOTETEXT
))
if(!query_find_note.warn_execute())
qdel(query_find_note)
return
if(query_find_note.NextRow())
show_warning = FALSE
qdel(query_find_note)
if(show_warning)
message_admins("<font color='red'>[ckey] has just connected and has a history of [cidcount] different CIDs.</font> (<a href='?_src_=holder;webtools=[ckey]'>WebInfo</a>) (<a href='?_src_=holder;suppresscidwarning=[ckey]'>Suppress Warning</a>)")
/client/proc/update_ambience_pref()
if(prefs.sound & SOUND_AMBIENCE)
if(SSambience.ambience_listening_clients[src] > world.time)
@@ -0,0 +1,31 @@
/datum/client_login_processor/load_preferences
priority = 10
/datum/client_login_processor/load_preferences/get_query(client/C)
var/datum/db_query/query = SSdbcore.NewQuery({"SELECT
ooccolor,
UI_style,
UI_style_color,
UI_style_alpha,
be_role,
default_slot,
toggles,
toggles_2,
sound,
volume_mixer,
lastchangelog,
exp,
clientfps,
atklog,
fuid,
parallax,
2fa_status
FROM player
WHERE ckey=:ckey"}, list(
"ckey" = C.ckey
))
return query
/datum/client_login_processor/load_preferences/process_result(datum/db_query/Q, client/C)
C.prefs = new /datum/preferences(C, Q)
@@ -0,0 +1,106 @@
/datum/client_login_processor/load_characters
priority = 20
/datum/client_login_processor/load_characters/get_query(client/C)
// Get all their characters
var/datum/db_query/query = SSdbcore.NewQuery({"SELECT
OOC_Notes,
real_name,
name_is_always_random,
gender,
age,
species,
language,
hair_colour,
secondary_hair_colour,
facial_hair_colour,
secondary_facial_hair_colour,
skin_tone,
skin_colour,
marking_colours,
head_accessory_colour,
hair_style_name,
facial_style_name,
marking_styles,
head_accessory_style_name,
alt_head_name,
eye_colour,
underwear,
undershirt,
backbag,
b_type,
alternate_option,
job_support_high,
job_support_med,
job_support_low,
job_medsci_high,
job_medsci_med,
job_medsci_low,
job_engsec_high,
job_engsec_med,
job_engsec_low,
job_karma_high,
job_karma_med,
job_karma_low,
flavor_text,
med_record,
sec_record,
gen_record,
disabilities,
player_alt_titles,
organ_data,
rlimb_data,
nanotrasen_relation,
speciesprefs,
socks,
body_accessory,
gear,
autohiss,
slot,
hair_gradient,
hair_gradient_offset,
hair_gradient_colour,
hair_gradient_alpha
FROM characters WHERE ckey=:ckey"}, list(
"ckey" = C.ckey
))
return query
/datum/client_login_processor/load_characters/process_result(datum/db_query/Q, client/C)
// If we already loaded their characters, dont do it all again
if(C.prefs.characters_loaded)
return
// Step one, initialize their list of characters
C.prefs.character_saves = list()
C.prefs.character_saves.len = C.prefs.max_save_slots // Fill the list with empty indexes
// Fill it with blank characters first
for(var/i in 1 to C.prefs.max_save_slots)
var/datum/character_save/CS = new
CS.slot_number = i
C.prefs.character_saves[i] = CS
// Did we load at all
var/character_loaded = FALSE
while(Q.NextRow())
character_loaded = TRUE
var/datum/character_save/CS = C.prefs.character_saves[Q.item[53]] // Get the slot referenced by this query
CS.load(Q) // Let the save handle the query processing
CS.valid_save = TRUE
if(character_loaded)
// They have a character, set their active as their default slot
C.prefs.active_character = C.prefs.character_saves[C.prefs.default_slot]
else
// If we are here, they dont have a character. Lets make them a random one
var/datum/character_save/CS = C.prefs.character_saves[1] // Get slot 1
CS.randomise()
CS.real_name = random_name(CS.gender) // Pick a name
CS.valid_save = TRUE
CS.save(C)
C.prefs.active_character = C.prefs.character_saves[1] // Set slot 1 as their active
C.prefs.default_slot = 1
C.prefs.save_preferences(C)
C.prefs.characters_loaded = TRUE // Avoid this happening again
@@ -0,0 +1,24 @@
/datum/client_login_processor/tos_consent
priority = 30
/datum/client_login_processor/tos_consent/get_query(client/C)
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey FROM privacy WHERE ckey=:ckey AND consent=1", list(
"ckey" = C.ckey
))
return query
/datum/client_login_processor/tos_consent/process_result(datum/db_query/Q, client/C)
// If there is no TOS, auto accept
if(!GLOB.join_tos)
C.tos_consent = TRUE
return
// If our query failed, just assume yes
if(Q.last_error)
C.tos_consent = TRUE
return
// If we returned a row, they accepted
while(Q.NextRow())
C.tos_consent = TRUE
@@ -0,0 +1,27 @@
/datum/client_login_processor/donator_check
priority = 35
/datum/client_login_processor/donator_check/get_query(client/C)
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey, tier, active FROM donators WHERE ckey=:ckey", list(
"ckey" = C.ckey
))
return query
/datum/client_login_processor/donator_check/process_result(datum/db_query/Q, client/C)
if(IsGuestKey(C.key))
return
// Admins get all donor perks
if(check_rights_client(R_ADMIN, FALSE, C))
C.donator_level = DONATOR_LEVEL_MAX
C.donor_loadout_points()
return
while(Q.NextRow())
if(!text2num(Q.item[3]))
// Inactive donator.
C.donator_level = 0
return
C.donator_level = text2num(Q.item[2])
C.donor_loadout_points()
@@ -0,0 +1,15 @@
/datum/client_login_processor/watchlist
priority = 36
/datum/client_login_processor/watchlist/get_query(client/C)
var/datum/db_query/query = SSdbcore.NewQuery("SELECT reason FROM watch WHERE ckey=:ckey", list(
"ckey" = C.ckey
))
return query
/datum/client_login_processor/watchlist/process_result(datum/db_query/Q, client/C)
if(Q.NextRow())
var/watchreason = Q.item[1]
message_admins("<font color='red'><B>Notice: </B></font><font color='#EB4E00'>[key_name_admin(C)] is on the watchlist and has just connected - Reason: [watchreason]</font>")
SSdiscord.send2discord_simple_noadmins("**\[Watchlist]** [key_name(C)] is on the watchlist and has just connected - Reason: [watchreason]")
C.watchlisted = TRUE
@@ -0,0 +1,14 @@
/datum/client_login_processor/alts_ip
priority = 37
/datum/client_login_processor/alts_ip/get_query(client/C)
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey FROM player WHERE ip=:address", list(
"address" = C.address
))
return query
/datum/client_login_processor/alts_ip/process_result(datum/db_query/Q, client/C)
while(Q.NextRow())
if("[Q.item[1]]" == C.ckey)
continue
C.related_accounts_ip += "[Q.item[1]]"
@@ -0,0 +1,14 @@
/datum/client_login_processor/alts_cid
priority = 38
/datum/client_login_processor/alts_cid/get_query(client/C)
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey FROM player WHERE computerid=:cid", list(
"cid" = C.computer_id
))
return query
/datum/client_login_processor/alts_cid/process_result(datum/db_query/Q, client/C)
while(Q.NextRow())
if("[Q.item[1]]" == C.ckey)
continue
C.related_accounts_cid += "[Q.item[1]]"
@@ -0,0 +1,71 @@
/datum/client_login_processor/cid_count
priority = 39
/datum/client_login_processor/cid_count/get_query(client/C)
var/datum/db_query/query = SSdbcore.NewQuery("SELECT COUNT(DISTINCT computerID) FROM connection_log WHERE ckey=:ckey", list(
"ckey" = C.ckey
))
return query
/datum/client_login_processor/cid_count/process_result(datum/db_query/Q, client/C)
// If the config is 0, disable this
if(GLOB.configuration.general.max_client_cid_history == 0)
return
// Now query how many cids they have
var/cidcount = 0
if(Q.NextRow())
cidcount = Q.item[1]
if(cidcount > GLOB.configuration.general.max_client_cid_history)
// Check their notes for CID tracking in the past
var/has_note = FALSE
var/note_text = ""
var/datum/db_query/query_find_track_note = SSdbcore.NewQuery("SELECT notetext FROM notes WHERE ckey=:ckey AND adminckey=:ackey", list(
"ckey" = C.ckey,
"ackey" = CIDTRACKING_PSUEDO_CKEY
))
if(!query_find_track_note.warn_execute())
qdel(query_find_track_note)
return
if(query_find_track_note.NextRow())
note_text = query_find_track_note.item[1] // Grab existing note text
has_note = TRUE
qdel(query_find_track_note)
if(has_note) // They have a note. Update it.
var/new_text = "Connected on the date of this note with unique CID #[cidcount]"
// Only update the note if the text is different. Otherwise it bumps the timestamp when it shouldnt
if(note_text != new_text)
var/datum/db_query/query_update_track_note = SSdbcore.NewQuery("UPDATE notes SET notetext=:notetext, timestamp=NOW(), round_id=:rid WHERE ckey=:ckey AND adminckey=:ackey", list(
"notetext" = new_text,
"ckey" = C.ckey,
"ackey" = CIDTRACKING_PSUEDO_CKEY,
"rid" = GLOB.round_id
))
if(!query_update_track_note.warn_execute())
qdel(query_update_track_note)
return
qdel(query_update_track_note)
else // They dont have a note. Make one.
// NOT logged because its automatic and will spam logs otherwise
// Also right checking must be disabled because its a psuedockey, not a real one
add_note(C.ckey, "Connected on the date of this note with unique CID #[cidcount]", adminckey = CIDTRACKING_PSUEDO_CKEY, logged = FALSE, checkrights = FALSE, automated = TRUE)
var/show_warning = TRUE
// Check if they have a note that matches the warning suppressor
var/datum/db_query/query_find_note = SSdbcore.NewQuery("SELECT id FROM notes WHERE ckey=:ckey AND notetext=:notetext", list(
"ckey" = C.ckey,
"notetext" = CIDWARNING_SUPPRESSED_NOTETEXT
))
if(!query_find_note.warn_execute())
qdel(query_find_note)
return
if(query_find_note.NextRow())
show_warning = FALSE
qdel(query_find_note)
if(show_warning)
message_admins("<font color='red'>[C.ckey] has just connected and has a history of [cidcount] different CIDs.</font> (<a href='?_src_=holder;webtools=[C.ckey]'>WebInfo</a>) (<a href='?_src_=holder;suppresscidwarning=[C.ckey]'>Suppress Warning</a>)")
@@ -0,0 +1,8 @@
/datum/client_login_processor/pai_save
priority = 40
/datum/client_login_processor/pai_save/get_query(client/C)
return C.pai_save.get_query()
/datum/client_login_processor/pai_save/process_result(datum/db_query/Q, client/C)
C.pai_save.load_data(Q)
@@ -0,0 +1,20 @@
/datum/client_login_processor/cuis
priority = 45
/datum/client_login_processor/cuis/get_query(client/C)
var/datum/db_query/query = SSdbcore.NewQuery("SELECT cuiRealName, cuiPath, cuiItemName, cuiDescription, cuiJobMask FROM customuseritems WHERE cuiCKey=:ckey", list(
"ckey" = C.ckey
))
return query
/datum/client_login_processor/cuis/process_result(datum/db_query/Q, client/C)
while(Q.NextRow())
var/datum/custom_user_item/cui = new()
cui.characer_name = Q.item[1]
cui.object_typepath = text2path(Q.item[2])
cui.item_name_override = Q.item[3]
cui.item_desc_override = Q.item[4]
cui.raw_job_mask = Q.item[5]
if(cui.parse_info(C.ckey))
C.cui_entries += cui
@@ -0,0 +1,51 @@
/**
* # Client Login Processor Framework
*
* The holder class for all client data processing
*
* This framework is designed for loading in client data from the database.
* Login processors have their own queries, which will be put into one async batch and
* executed at the same time, to reduce the time it takes for a client to login.
* Login processors can also be given priorities to have things fire in specific orders
* EG: Load their preferences before their job bans, etc etc
*
* When creating these, please name the files with the priority at the start, and the typepath after
* EG: 10-load_preferences.dm
* This makes it easier to track stuff down -AA07
*
* Also if you have used other languages before with "interface" types (Java, C# (Microsoft Java), etc),
* treat this class as one of those. [get_query(client/C)] and [process_result(datum/db_query/Q, client/C)] MUST be overriden
*/
/datum/client_login_processor
/// The login priority. A lower priority will fire first
var/priority = 0
/**
* Query Getter
*
* Gets the DB query for this login processor
*
* Takes the client as an arg instead of just the ckey incase we need more data (IP, CID, etc).
* Returns a DB query datum.
*
* Arguments:
* * C - The client to use to generate the query
*/
/datum/client_login_processor/proc/get_query(client/C)
RETURN_TYPE(/datum/db_query)
CRASH("get_query() not overriden for [type]!")
/**
* Result Processor
*
* Takes the (now executed) query and the client and parses the required data out
* Note: This can be a no-op if you want to just update the DB, just return on the override
*
* Arguments:
* * Q - The DB query to process data from
* * C - The client to store stuff on
*/
/datum/client_login_processor/proc/process_result(datum/db_query/Q, client/C)
CRASH("process_result() not overriden for [type]!")
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -10,17 +10,27 @@ GLOBAL_LIST_EMPTY(gear_datums)
..()
/datum/gear
var/display_name //Name/index. Must be unique.
var/description //Description of this gear. If left blank will default to the description of the pathed item.
var/path //Path to item.
var/cost = 1 //Number of points used. Items in general cost 1 point, storage/armor/gloves/special use costs 2 points.
var/slot //Slot to equip to.
var/list/allowed_roles //Roles that can spawn with this item.
var/whitelisted //Term to check the whitelist for..
/// Displayed name of the item listing.
var/display_name
/// Description of the item listing. If left blank will default to the description of the pathed item.
var/description
/// Typepath of the item.
var/path
/// Loadout points cost to select the item listing.
var/cost = 1
/// Slot to equip the item to.
var/slot
/// List of job roles which can spawn with the item.
var/list/allowed_roles
/// Loadout category of the item listing.
var/sort_category = "General"
var/list/gear_tweaks = list() //List of datums which will alter the item after it has been spawned.
var/subtype_path = /datum/gear //for skipping organizational subtypes (optional)
var/subtype_cost_overlap = TRUE //if subtypes can take points at the same time
/// List of datums which will alter the item after it has been spawned. (NYI)
var/list/gear_tweaks = list()
/// Set on empty category datums to skip them being added to the list. (/datum/gear/accessory, /datum/gear/suit/coat/job, etc.)
var/main_typepath = /datum/gear
/// Does selecting a second item with the same `main_typepath` cost loadout points.
var/subtype_selection_cost = TRUE
/// Patreon donator tier needed to select this item listing.
var/donator_tier = 0
/datum/gear/New()
@@ -1,203 +1,215 @@
/*
######################################################################################
## ##
## IMPORTANT README ##
## ##
## Changing any /datum/gear typepaths --WILL-- break people's loadouts. ##
## The typepaths are stored directly in the `characters.gear` column of the DB. ##
## Please inform the server host if you wish to modify any of these. ##
## ##
######################################################################################
*/
/datum/gear/accessory
subtype_path = /datum/gear/accessory
main_typepath = /datum/gear/accessory
slot = slot_tie
sort_category = "Accessories"
/datum/gear/accessory/scarf
display_name = "scarf"
display_name = "Scarf"
path = /obj/item/clothing/accessory/scarf
/datum/gear/accessory/scarf/red
display_name = "scarf, red"
display_name = "Scarf, red"
path = /obj/item/clothing/accessory/scarf/red
/datum/gear/accessory/scarf/green
display_name = "scarf, green"
display_name = "Scarf, green"
path = /obj/item/clothing/accessory/scarf/green
/datum/gear/accessory/scarf/darkblue
display_name = "scarf, dark blue"
display_name = "Scarf, dark blue"
path = /obj/item/clothing/accessory/scarf/darkblue
/datum/gear/accessory/scarf/purple
display_name = "scarf, purple"
display_name = "Scarf, purple"
path = /obj/item/clothing/accessory/scarf/purple
/datum/gear/accessory/scarf/yellow
display_name = "scarf, yellow"
display_name = "Scarf, yellow"
path = /obj/item/clothing/accessory/scarf/yellow
/datum/gear/accessory/scarf/orange
display_name = "scarf, orange"
display_name = "Scarf, orange"
path = /obj/item/clothing/accessory/scarf/orange
/datum/gear/accessory/scarf/lightblue
display_name = "scarf, light blue"
display_name = "Scarf, light blue"
path = /obj/item/clothing/accessory/scarf/lightblue
/datum/gear/accessory/scarf/white
display_name = "scarf, white"
display_name = "Scarf, white"
path = /obj/item/clothing/accessory/scarf/white
/datum/gear/accessory/scarf/black
display_name = "scarf, black"
display_name = "Scarf, black"
path = /obj/item/clothing/accessory/scarf/black
/datum/gear/accessory/scarf/zebra
display_name = "scarf, zebra"
display_name = "Scarf, zebra"
path = /obj/item/clothing/accessory/scarf/zebra
/datum/gear/accessory/scarf/christmas
display_name = "scarf, christmas"
display_name = "Scarf, christmas"
path = /obj/item/clothing/accessory/scarf/christmas
/datum/gear/accessory/scarf/stripedred
display_name = "scarf, striped red"
display_name = "Scarf, striped red"
path = /obj/item/clothing/accessory/stripedredscarf
/datum/gear/accessory/scarf/stripedgreen
display_name = "scarf, striped green"
display_name = "Scarf, striped green"
path = /obj/item/clothing/accessory/stripedgreenscarf
/datum/gear/accessory/scarf/stripedblue
display_name = "scarf, striped blue"
display_name = "Scarf, striped blue"
path = /obj/item/clothing/accessory/stripedbluescarf
/datum/gear/accessory/holobadge
display_name = "holobadge, pin"
display_name = "Holobadge, pin"
path = /obj/item/clothing/accessory/holobadge
allowed_roles = list("Head of Security", "Warden", "Detective", "Security Officer", "Security Pod Pilot")
allowed_roles = list("Head of Security", "Warden", "Detective", "Security Officer")
/datum/gear/accessory/holobadge_n
display_name = "holobadge, cord"
display_name = "Holobadge, cord"
path = /obj/item/clothing/accessory/holobadge/cord
allowed_roles = list("Head of Security", "Warden", "Detective", "Security Officer", "Security Pod Pilot")
allowed_roles = list("Head of Security", "Warden", "Detective", "Security Officer")
/datum/gear/accessory/tieblue
display_name = "tie, blue"
display_name = "Tie, blue"
path = /obj/item/clothing/accessory/blue
/datum/gear/accessory/tiered
display_name = "tie, red"
display_name = "Tie, red"
path = /obj/item/clothing/accessory/red
/datum/gear/accessory/tieblack
display_name = "tie, black"
display_name = "Tie, black"
path = /obj/item/clothing/accessory/black
/datum/gear/accessory/tiehorrible
display_name = "tie, vomit green"
display_name = "Tie, vomit green"
path = /obj/item/clothing/accessory/horrible
/datum/gear/accessory/stethoscope
display_name = "stethoscope"
display_name = "Stethoscope"
path = /obj/item/clothing/accessory/stethoscope
allowed_roles = list("Chief Medical Officer", "Medical Doctor", "Paramedic", "Brig Physician")
/datum/gear/accessory/cowboyshirt
display_name = "cowboy shirt, black"
display_name = "Cowboy shirt, black"
path = /obj/item/clothing/accessory/cowboyshirt
/datum/gear/accessory/cowboyshirt/short_sleeved
display_name = "cowboy shirt, short sleeved black"
display_name = "Cowboy shirt, short sleeved black"
path = /obj/item/clothing/accessory/cowboyshirt/short_sleeved
/datum/gear/accessory/cowboyshirt/white
display_name = "cowboy shirt, white"
display_name = "Cowboy shirt, white"
path = /obj/item/clothing/accessory/cowboyshirt/white
/datum/gear/accessory/cowboyshirt/white/short_sleeved
display_name = "cowboy shirt, short sleeved white"
display_name = "Cowboy shirt, short sleeved white"
path = /obj/item/clothing/accessory/cowboyshirt/white/short_sleeved
/datum/gear/accessory/cowboyshirt/pink
display_name = "cowboy shirt, pink"
display_name = "Cowboy shirt, pink"
path = /obj/item/clothing/accessory/cowboyshirt/pink
/datum/gear/accessory/cowboyshirt/pink/short_sleeved
display_name = "cowboy shirt, short sleeved pink"
display_name = "Cowboy shirt, short sleeved pink"
path = /obj/item/clothing/accessory/cowboyshirt/pink/short_sleeved
/datum/gear/accessory/cowboyshirt/red
display_name = "cowboy shirt, red"
display_name = "Cowboy shirt, red"
path = /obj/item/clothing/accessory/cowboyshirt/red
/datum/gear/accessory/cowboyshirt/red/short_sleeved
display_name = "cowboy shirt, short sleeved red"
display_name = "Cowboy shirt, short sleeved red"
path = /obj/item/clothing/accessory/cowboyshirt/red/short_sleeved
/datum/gear/accessory/cowboyshirt/navy
display_name = "cowboy shirt, navy"
display_name = "Cowboy shirt, navy"
path = /obj/item/clothing/accessory/cowboyshirt/navy
/datum/gear/accessory/cowboyshirt/navy/short_sleeved
display_name = "cowboy shirt, short sleeved navy"
display_name = "Cowboy shirt, short sleeved navy"
path = /obj/item/clothing/accessory/cowboyshirt/navy/short_sleeved
/datum/gear/accessory/locket
display_name = "gold locket"
display_name = "Gold locket"
path = /obj/item/clothing/accessory/necklace/locket
/datum/gear/accessory/necklace
display_name = "simple necklace"
display_name = "Simple necklace"
path = /obj/item/clothing/accessory/necklace
/datum/gear/accessory/corset
display_name = "corset, black"
display_name = "Corset, black"
path = /obj/item/clothing/accessory/corset
/datum/gear/accessory/corsetred
display_name = "corset, red"
display_name = "Corset, red"
path = /obj/item/clothing/accessory/corset/red
/datum/gear/accessory/corsetblue
display_name = "corset, blue"
display_name = "Corset, blue"
path = /obj/item/clothing/accessory/corset/blue
/datum/gear/accessory/armband_red
display_name = "armband"
display_name = "Armband"
path = /obj/item/clothing/accessory/armband
/datum/gear/accessory/armband_civ
display_name = "armband, blue-yellow"
display_name = "Armband, blue-yellow"
path = /obj/item/clothing/accessory/armband/yb
/datum/gear/accessory/armband_job
subtype_path = /datum/gear/accessory/armband_job
subtype_cost_overlap = FALSE
main_typepath = /datum/gear/accessory/armband_job
subtype_selection_cost = FALSE
/datum/gear/accessory/armband_job/sec
display_name = " armband, security"
display_name = "Armband, security"
path = /obj/item/clothing/accessory/armband/sec
allowed_roles = list("Head of Security", "Warden", "Detective", "Security Officer", "Brig Physician", "Security Pod Pilot")
allowed_roles = list("Head of Security", "Warden", "Detective", "Security Officer", "Brig Physician")
/datum/gear/accessory/armband_job/cargo
display_name = "cargo armband"
display_name = "Armband, cargo"
path = /obj/item/clothing/accessory/armband/cargo
allowed_roles = list("Quartermaster","Cargo Technician", "Shaft Miner")
/datum/gear/accessory/armband_job/medical
display_name = "armband, medical"
display_name = "Armband, medical"
path = /obj/item/clothing/accessory/armband/med
allowed_roles = list("Chief Medical Officer", "Medical Doctor", "Coroner", "Paramedic", "Brig Physician")
/datum/gear/accessory/armband_job/emt
display_name = "armband, EMT"
display_name = "Armband, EMT"
path = /obj/item/clothing/accessory/armband/medgreen
allowed_roles = list("Paramedic", "Brig Physician")
/datum/gear/accessory/armband_job/engineering
display_name = "armband, engineering"
display_name = "Armband, engineering"
path = /obj/item/clothing/accessory/armband/engine
allowed_roles = list("Chief Engineer","Station Engineer", "Life Support Specialist")
/datum/gear/accessory/armband_job/hydro
display_name = "armband, hydroponics"
display_name = "Armband, hydroponics"
path = /obj/item/clothing/accessory/armband/hydro
allowed_roles = list("Botanist")
/datum/gear/accessory/armband_job/sci
display_name = "armband, science"
display_name = "Armband, science"
path = /obj/item/clothing/accessory/armband/science
allowed_roles = list("Research Director","Scientist", "Roboticist")
@@ -1,24 +1,37 @@
/*
######################################################################################
## ##
## IMPORTANT README ##
## ##
## Changing any /datum/gear typepaths --WILL-- break people's loadouts. ##
## The typepaths are stored directly in the `characters.gear` column of the DB. ##
## Please inform the server host if you wish to modify any of these. ##
## ##
######################################################################################
*/
/datum/gear/lipstick
display_name = "lipstick, red"
display_name = "Lipstick, red"
path = /obj/item/lipstick
sort_category = "Cosmetics"
/datum/gear/lipstick/black
display_name = "lipstick, black"
display_name = "Lipstick, black"
path = /obj/item/lipstick/black
/datum/gear/lipstick/jade
display_name = "lipstick, jade"
display_name = "Lipstick, jade"
path = /obj/item/lipstick/jade
/datum/gear/lipstick/purple
display_name = "lipstick, purple"
display_name = "Lipstick, purple"
path = /obj/item/lipstick/purple
/datum/gear/lipstick/blue
display_name = "lipstick, blue"
display_name = "Lipstick, blue"
path = /obj/item/lipstick/blue
/datum/gear/lipstick/lime
display_name = "lipstick, lime"
display_name = "Lipstick, lime"
path = /obj/item/lipstick/lime
@@ -1,7 +1,20 @@
/*
######################################################################################
## ##
## IMPORTANT README ##
## ##
## Changing any /datum/gear typepaths --WILL-- break people's loadouts. ##
## The typepaths are stored directly in the `characters.gear` column of the DB. ##
## Please inform the server host if you wish to modify any of these. ##
## ##
######################################################################################
*/
/datum/gear/donor
donator_tier = 2
sort_category = "Donor"
subtype_path = /datum/gear/donor
main_typepath = /datum/gear/donor
/datum/gear/donor/furgloves
display_name = "Fur Gloves"
@@ -1,136 +1,149 @@
/*
######################################################################################
## ##
## IMPORTANT README ##
## ##
## Changing any /datum/gear typepaths --WILL-- break people's loadouts. ##
## The typepaths are stored directly in the `characters.gear` column of the DB. ##
## Please inform the server host if you wish to modify any of these. ##
## ##
######################################################################################
*/
/datum/gear/dice
display_name = "a d20"
display_name = "D20"
path = /obj/item/dice/d20
/datum/gear/uplift
display_name = "a pack of Uplifts"
display_name = "Pack of Uplifts"
path = /obj/item/storage/fancy/cigarettes/cigpack_uplift
/datum/gear/robust
display_name = "a pack of Robusts"
display_name = "Pack of Robusts"
path = /obj/item/storage/fancy/cigarettes/cigpack_robust
/datum/gear/carp
display_name = "a pack of Carps"
display_name = "Pack of Carps"
path = /obj/item/storage/fancy/cigarettes/cigpack_carp
/datum/gear/midori
display_name = "a pack of Midoris"
display_name = "Pack of Midoris"
path = /obj/item/storage/fancy/cigarettes/cigpack_midori
/datum/gear/smokingpipe
display_name = "smoking pipe"
display_name = "Smoking pipe"
path = /obj/item/clothing/mask/cigarette/pipe
cost = 2
/datum/gear/lighter
display_name = "a cheap lighter"
display_name = "Cheap lighter"
path = /obj/item/lighter
/datum/gear/matches
display_name = "a box of matches"
display_name = "Box of matches"
path = /obj/item/storage/box/matches
/datum/gear/candlebox
display_name = "a box candles"
display_name = "Box of candles"
description = "For setting the mood or for occult rituals."
path = /obj/item/storage/fancy/candle_box/full
/datum/gear/rock
display_name = "a pet rock"
display_name = "Pet rock"
path = /obj/item/toy/pet_rock
/datum/gear/camera
display_name = "a camera"
display_name = "Camera"
path = /obj/item/camera
/datum/gear/redfoxplushie
display_name = "a red fox plushie"
display_name = "Red fox plushie"
path = /obj/item/toy/plushie/red_fox
/datum/gear/blackcatplushie
display_name = "a black cat plushie"
display_name = "Black cat plushie"
path = /obj/item/toy/plushie/black_cat
/datum/gear/voxplushie
display_name = "a vox plushie"
display_name = "Vox plushie"
path = /obj/item/toy/plushie/voxplushie
/datum/gear/lizardplushie
display_name = "a lizard plushie"
display_name = "Lizard plushie"
path = /obj/item/toy/plushie/lizardplushie
/datum/gear/deerplushie
display_name = "a deer plushie"
display_name = "Deer plushie"
path = /obj/item/toy/plushie/deer
/datum/gear/carpplushie
display_name = "a carp plushie"
display_name = "Carp plushie"
path = /obj/item/toy/carpplushie
/datum/gear/sechud
display_name = "a classic security HUD"
display_name = "Classic security HUD"
path = /obj/item/clothing/glasses/hud/security
allowed_roles = list("Head of Security", "Warden", "Security Officer", "Security Pod Pilot", "Internal Affairs Agent","Magistrate")
allowed_roles = list("Head of Security", "Warden", "Security Officer", "Internal Affairs Agent","Magistrate")
/datum/gear/cryaonbox
display_name = "a box of crayons"
display_name = "Box of crayons"
path = /obj/item/storage/fancy/crayons
/datum/gear/cane
display_name = "a walking cane"
display_name = "Walking cane"
path = /obj/item/cane
/datum/gear/cards
display_name = "a deck of standard cards"
display_name = "Deck of standard cards"
path = /obj/item/deck/cards
/datum/gear/doublecards
display_name = "a double deck of standard cards"
display_name = "Double deck of standard cards"
path = /obj/item/deck/doublecards
/datum/gear/tarot
display_name = "a deck of tarot cards"
display_name = "Deck of tarot cards"
path = /obj/item/deck/tarot
/datum/gear/headphones
display_name = "a pair of headphones"
display_name = "Headphones"
path = /obj/item/clothing/ears/headphones
/datum/gear/fannypack
display_name = "a fannypack"
display_name = "Fannypack"
path = /obj/item/storage/belt/fannypack
/datum/gear/blackbandana
display_name = "bandana, black"
display_name = "Bandana, black"
path = /obj/item/clothing/mask/bandana/black
/datum/gear/purplebandana
display_name = "bandana, purple"
display_name = "Bandana, purple"
path = /obj/item/clothing/mask/bandana/purple
/datum/gear/orangebandana
display_name = "bandana, orange"
display_name = "Bandana, orange"
path = /obj/item/clothing/mask/bandana/orange
/datum/gear/greenbandana
display_name = "bandana, green"
display_name = "Bandana, green"
path = /obj/item/clothing/mask/bandana/green
/datum/gear/bluebandana
display_name = "bandana, blue"
display_name = "Bandana, blue"
path = /obj/item/clothing/mask/bandana/blue
/datum/gear/redbandana
display_name = "bandana, red"
display_name = "Bandana, red"
path = /obj/item/clothing/mask/bandana/red
/datum/gear/goldbandana
display_name = "bandana, gold"
display_name = "Bandana, gold"
path = /obj/item/clothing/mask/bandana/gold
/datum/gear/skullbandana
display_name = "bandana, skull"
display_name = "Bandana, skull"
path = /obj/item/clothing/mask/bandana/skull
/datum/gear/mob_hunt_game
@@ -143,54 +156,54 @@
//////////////////////
/datum/gear/mug
display_name = "random coffee mug"
display_name = "Coffee mug, random"
description = "A randomly colored coffee mug. You'll need to supply your own beverage though."
path = /obj/item/reagent_containers/food/drinks/mug
sort_category = "Mugs"
/datum/gear/novelty_mug
display_name = "novelty coffee mug"
display_name = "Coffee mug, novelty"
description = "A random novelty coffee mug. You'll need to supply your own beverage though."
path = /obj/item/reagent_containers/food/drinks/mug/novelty
cost = 2
sort_category = "Mugs"
/datum/gear/mug/flask
display_name = "flask"
display_name = "Flask"
description = "A flask for drink transportation. You'll need to supply your own beverage though."
path = /obj/item/reagent_containers/food/drinks/flask/barflask
/datum/gear/mug/department
subtype_path = /datum/gear/mug/department
main_typepath = /datum/gear/mug/department
sort_category = "Mugs"
subtype_cost_overlap = FALSE
subtype_selection_cost = FALSE
/datum/gear/mug/department/eng
display_name = "engineer coffee mug"
display_name = "Coffee mug, engineering"
description = "An engineer's coffee mug, emblazoned in the colors of the Engineering department."
allowed_roles = list("Chief Engineer", "Station Engineer", "Mechanic", "Life Support Specialist")
allowed_roles = list("Chief Engineer", "Station Engineer", "Life Support Specialist")
path = /obj/item/reagent_containers/food/drinks/mug/eng
/datum/gear/mug/department/med
display_name = "doctor coffee mug"
display_name = "Coffee mug, medical"
description = "A doctor's coffee mug, emblazoned in the colors of the Medical department."
allowed_roles = list("Chief Medical Officer", "Medical Doctor", "Chemist", "Psychiatrist", "Paramedic", "Virologist", "Coroner")
path = /obj/item/reagent_containers/food/drinks/mug/med
/datum/gear/mug/department/sci
display_name = "scientist coffee mug"
display_name = "Coffee mug, science"
description = "A scientist's coffee mug, emblazoned in the colors of the Science department."
allowed_roles = list("Research Director", "Scientist", "Roboticist")
path = /obj/item/reagent_containers/food/drinks/mug/sci
/datum/gear/mug/department/sec
display_name = "officer coffee mug"
display_name = "Coffee mug, security"
description = "An officer's coffee mug, emblazoned in the colors of the Security department."
allowed_roles = list("Head of Security", "Warden", "Detective", "Security Officer", "Security Pod Pilot", "Brig Physician", "Internal Affairs Agent")
allowed_roles = list("Head of Security", "Warden", "Detective", "Security Officer", "Brig Physician", "Internal Affairs Agent")
path = /obj/item/reagent_containers/food/drinks/mug/sec
/datum/gear/mug/department/serv
display_name = "crewmember coffee mug"
display_name = "Coffee mug, service"
description = "A crewmember's coffee mug, emblazoned in the colors of the Service department."
path = /obj/item/reagent_containers/food/drinks/mug/serv
@@ -1,10 +1,23 @@
/*
######################################################################################
## ##
## IMPORTANT README ##
## ##
## Changing any /datum/gear typepaths --WILL-- break people's loadouts. ##
## The typepaths are stored directly in the `characters.gear` column of the DB. ##
## Please inform the server host if you wish to modify any of these. ##
## ##
######################################################################################
*/
/datum/gear/glasses
subtype_path = /datum/gear/glasses
main_typepath = /datum/gear/glasses
slot = slot_glasses
sort_category = "Glasses"
/datum/gear/glasses/sunglasses
display_name = "cheap sunglasses"
display_name = "Cheap sunglasses"
path = /obj/item/clothing/glasses/sunglasses_fake
/datum/gear/glasses/eyepatch
@@ -1,5 +1,18 @@
/*
######################################################################################
## ##
## IMPORTANT README ##
## ##
## Changing any /datum/gear typepaths --WILL-- break people's loadouts. ##
## The typepaths are stored directly in the `characters.gear` column of the DB. ##
## Please inform the server host if you wish to modify any of these. ##
## ##
######################################################################################
*/
/datum/gear/gloves
subtype_path = /datum/gear/gloves
main_typepath = /datum/gear/gloves
slot = slot_gloves
sort_category = "Gloves"
@@ -1,184 +1,197 @@
/*
######################################################################################
## ##
## IMPORTANT README ##
## ##
## Changing any /datum/gear typepaths --WILL-- break people's loadouts. ##
## The typepaths are stored directly in the `characters.gear` column of the DB. ##
## Please inform the server host if you wish to modify any of these. ##
## ##
######################################################################################
*/
/datum/gear/hat
subtype_path = /datum/gear/hat
main_typepath = /datum/gear/hat
slot = slot_head
sort_category = "Headwear"
/datum/gear/hat/hhat_yellow
display_name = "hardhat, yellow"
display_name = "Hardhat, yellow"
path = /obj/item/clothing/head/hardhat
allowed_roles = list("Chief Engineer", "Station Engineer", "Mechanic", "Life Support Specialist")
allowed_roles = list("Chief Engineer", "Station Engineer", "Life Support Specialist")
/datum/gear/hat/hhat_orange
display_name = "hardhat, orange"
display_name = "Hardhat, orange"
path = /obj/item/clothing/head/hardhat/orange
allowed_roles = list("Chief Engineer", "Station Engineer", "Mechanic", "Life Support Specialist")
allowed_roles = list("Chief Engineer", "Station Engineer", "Life Support Specialist")
/datum/gear/hat/hhat_blue
display_name = "hardhat, blue"
display_name = "Hardhat, blue"
path = /obj/item/clothing/head/hardhat/dblue
allowed_roles = list("Chief Engineer", "Station Engineer", "Mechanic", "Life Support Specialist")
allowed_roles = list("Chief Engineer", "Station Engineer", "Life Support Specialist")
/datum/gear/hat/that
display_name = "top hat"
display_name = "Top hat"
path = /obj/item/clothing/head/that
/datum/gear/hat/flatcap
display_name = "flat cap"
display_name = "Flat cap"
path = /obj/item/clothing/head/flatcap
/datum/gear/hat/witch
display_name = "witch hat"
display_name = "Witch hat"
path = /obj/item/clothing/head/wizard/marisa/fake
/datum/gear/hat/piratecaphat
display_name = "pirate captian hat"
display_name = "Pirate captian hat"
path = /obj/item/clothing/head/pirate
/datum/gear/hat/fez
display_name = "fez"
display_name = "Fez"
path = /obj/item/clothing/head/fez
/datum/gear/hat/rasta
display_name = "rasta hat"
display_name = "Rasta hat"
path = /obj/item/clothing/head/beanie/rasta
/datum/gear/hat/bfedora
display_name = "fedora, black"
display_name = "Fedora, black"
path = /obj/item/clothing/head/fedora
/datum/gear/hat/wfedora
display_name = "fedora, white"
display_name = "Fedora, white"
path = /obj/item/clothing/head/fedora/whitefedora
/datum/gear/hat/brfedora
display_name = "fedora, brown"
display_name = "Fedora, brown"
path = /obj/item/clothing/head/fedora/brownfedora
/datum/gear/hat/capcsec
display_name = "security corporate cap"
display_name = "Security cap, corporate"
path = /obj/item/clothing/head/soft/sec/corp
allowed_roles = list("Head of Security", "Warden", "Security Officer", "Security Pod Pilot")
allowed_roles = list("Head of Security", "Warden", "Security Officer")
/datum/gear/hat/capsec
display_name = "security cap"
display_name = "Security cap"
path = /obj/item/clothing/head/soft/sec
allowed_roles = list("Head of Security", "Warden", "Security Officer", "Security Pod Pilot")
allowed_roles = list("Head of Security", "Warden", "Security Officer")
/datum/gear/hat/capred
display_name = "cap, red"
display_name = "Cap, red"
path = /obj/item/clothing/head/soft/red
/datum/gear/hat/capblue
display_name = "cap, blue"
display_name = "Cap, blue"
path = /obj/item/clothing/head/soft/blue
/datum/gear/hat/capgreen
display_name = "cap, green"
display_name = "Cap, green"
path = /obj/item/clothing/head/soft/green
/datum/gear/hat/capblack
display_name = "cap, black"
display_name = "Cap, black"
path = /obj/item/clothing/head/soft/black
/datum/gear/hat/cappurple
display_name = "cap, purple"
display_name = "Cap, purple"
path = /obj/item/clothing/head/soft/purple
/datum/gear/hat/capwhite
display_name = "cap, white"
display_name = "Cap, white"
path = /obj/item/clothing/head/soft/mime
/datum/gear/hat/caporange
display_name = "cap, orange"
display_name = "Cap, orange"
path = /obj/item/clothing/head/soft/orange
/datum/gear/hat/capgrey
display_name = "cap, grey"
display_name = "Cap, grey"
path = /obj/item/clothing/head/soft/grey
/datum/gear/hat/capyellow
display_name = "cap, yellow"
display_name = "Cap, yellow"
path = /obj/item/clothing/head/soft/yellow
/datum/gear/hat/cowboyhat
display_name = "cowboy hat, brown"
display_name = "Cowboy hat, brown"
path = /obj/item/clothing/head/cowboyhat
/datum/gear/hat/cowboyhat/tan
display_name = "cowboy hat, tan"
display_name = "Cowboy hat, tan"
path = /obj/item/clothing/head/cowboyhat/tan
/datum/gear/hat/cowboyhat/black
display_name = "cowboy hat, black"
display_name = "Cowboy hat, black"
path = /obj/item/clothing/head/cowboyhat/black
/datum/gear/hat/cowboyhat/white
display_name = "cowboy hat, white"
display_name = "Cowboy hat, white"
path = /obj/item/clothing/head/cowboyhat/white
/datum/gear/hat/cowboyhat/pink
display_name = "cowboy hat, pink"
display_name = "Cowboy hat, pink"
path = /obj/item/clothing/head/cowboyhat/pink
/datum/gear/hat/beret_purple
display_name = "beret, purple"
display_name = "Beret, purple"
path = /obj/item/clothing/head/beret/purple_normal
/datum/gear/hat/beret_black
display_name = "beret, black"
display_name = "Beret, black"
path = /obj/item/clothing/head/beret/black
/datum/gear/hat/beret_blue
display_name = "beret, blue"
display_name = "Beret, blue"
path = /obj/item/clothing/head/beret/blue
/datum/gear/hat/beret_red
display_name = "beret, red"
display_name = "Beret, red"
path = /obj/item/clothing/head/beret
/datum/gear/hat/beret_job
subtype_path = /datum/gear/hat/beret_job
subtype_cost_overlap = FALSE
main_typepath = /datum/gear/hat/beret_job
subtype_selection_cost = FALSE
/datum/gear/hat/beret_job/sec
display_name = "security beret"
display_name = "Beret, security"
path = /obj/item/clothing/head/beret/sec
allowed_roles = list("Head of Security", "Warden", "Security Officer", "Security Pod Pilot")
allowed_roles = list("Head of Security", "Warden", "Security Officer")
/datum/gear/hat/beret_job/sci
display_name = "science beret"
display_name = "Beret, science"
path = /obj/item/clothing/head/beret/sci
allowed_roles = list("Research Director", "Scientist")
/datum/gear/hat/beret_job/med
display_name = "medical beret"
display_name = "Beret, medical"
path = /obj/item/clothing/head/beret/med
allowed_roles = list("Chief Medical Officer", "Medical Doctor" , "Virologist", "Brig Physician" , "Coroner")
/datum/gear/hat/beret_job/eng
display_name = "engineering beret"
display_name = "Beret, engineering"
path = /obj/item/clothing/head/beret/eng
allowed_roles = list("Chief Engineer", "Station Engineer")
/datum/gear/hat/beret_job/atmos
display_name = "atmospherics beret"
display_name = "Beret, atmospherics"
path = /obj/item/clothing/head/beret/atmos
allowed_roles = list("Chief Engineer", "Life Support Specialist")
/datum/gear/hat/surgicalcap_purple
display_name = "surgical cap, purple"
display_name = "Surgical cap, purple"
path = /obj/item/clothing/head/surgery/purple
allowed_roles = list("Chief Medical Officer", "Medical Doctor")
/datum/gear/hat/surgicalcap_green
display_name = "surgical cap, green"
display_name = "Surgical cap, green"
path = /obj/item/clothing/head/surgery/green
allowed_roles = list("Chief Medical Officer", "Medical Doctor")
/datum/gear/hat/flowerpin
display_name = "hair flower"
display_name = "Hair flower"
path = /obj/item/clothing/head/hairflower
/datum/gear/hat/capsolgov
display_name = "cap, Sol Gov"
display_name = "Cap, Sol Gov"
path = /obj/item/clothing/head/soft/solgov
@@ -1,47 +1,60 @@
/*
######################################################################################
## ##
## IMPORTANT README ##
## ##
## Changing any /datum/gear typepaths --WILL-- break people's loadouts. ##
## The typepaths are stored directly in the `characters.gear` column of the DB. ##
## Please inform the server host if you wish to modify any of these. ##
## ##
######################################################################################
*/
/datum/gear/racial
sort_category = "Racial"
subtype_path = /datum/gear/racial
main_typepath = /datum/gear/racial
cost = 1
/datum/gear/racial/taj
display_name = "embroidered veil"
display_name = "Embroidered veil"
description = "A common traditional nano-fiber veil worn by many Tajaran, It is rare and offensive to see it on other races."
path = /obj/item/clothing/glasses/tajblind
slot = slot_glasses
/datum/gear/racial/taj/sec
display_name = "sleek veil"
display_name = "Sleek veil"
description = "A common traditional nano-fiber veil worn by many Tajaran, It is rare and offensive to see it on other races. This one has an in-built security HUD."
path = /obj/item/clothing/glasses/hud/security/tajblind
allowed_roles = list("Head of Security", "Warden", "Security Officer", "Security Pod Pilot", "Internal Affairs Agent", "Magistrate")
allowed_roles = list("Head of Security", "Warden", "Security Officer", "Internal Affairs Agent", "Magistrate")
cost = 2
/datum/gear/racial/taj/med
display_name = "lightweight veil"
display_name = "Lightweight veil"
description = "A common traditional nano-fiber veil worn by many Tajaran, It is rare and offensive to see it on other races. This one has an in-built medical HUD."
path = /obj/item/clothing/glasses/hud/health/tajblind
allowed_roles = list("Chief Medical Officer", "Medical Doctor", "Chemist", "Psychiatrist", "Paramedic", "Virologist", "Brig Physician" , "Coroner")
cost = 2
/datum/gear/racial/taj/sci
display_name = "hi-tech veil"
display_name = "Hi-tech veil"
description = "A common traditional nano-fiber veil worn by many Tajaran, It is rare and offensive to see it on other races."
path = /obj/item/clothing/glasses/tajblind/sci
cost = 2
/datum/gear/racial/taj/eng
display_name = "industrial veil"
display_name = "Industrial veil"
description = "A common traditional nano-fiber veil worn by many Tajaran, It is rare and offensive to see it on other races."
path = /obj/item/clothing/glasses/tajblind/eng
cost = 2
/datum/gear/racial/taj/cargo
display_name = "khaki veil"
display_name = "Khaki veil"
description = "A common traditional nano-fiber veil worn by many Tajaran, It is rare and offensive to see it on other races. It is light and comfy!"
path = /obj/item/clothing/glasses/tajblind/cargo
cost = 2
/datum/gear/racial/footwraps
display_name = "cloth footwraps"
display_name = "Cloth footwraps"
path = /obj/item/clothing/shoes/footwraps
slot = slot_shoes
@@ -1,54 +1,67 @@
/*
######################################################################################
## ##
## IMPORTANT README ##
## ##
## Changing any /datum/gear typepaths --WILL-- break people's loadouts. ##
## The typepaths are stored directly in the `characters.gear` column of the DB. ##
## Please inform the server host if you wish to modify any of these. ##
## ##
######################################################################################
*/
/datum/gear/shoes
subtype_path = /datum/gear/shoes
main_typepath = /datum/gear/shoes
slot = slot_shoes
sort_category = "Shoes"
/datum/gear/shoes/sandals
display_name = "sandals, wooden"
display_name = "Sandals, wooden"
path = /obj/item/clothing/shoes/sandal
/datum/gear/shoes/winterboots
display_name = "winter boots"
display_name = "Winter boots"
path = /obj/item/clothing/shoes/winterboots
/datum/gear/shoes/workboots
display_name = "work boots"
display_name = "Work boots"
path = /obj/item/clothing/shoes/workboots
/datum/gear/shoes/fancysandals
display_name = "sandals, fancy"
display_name = "Sandals, fancy"
path = /obj/item/clothing/shoes/sandal/fancy
/datum/gear/shoes/dressshoes
display_name = "dress shoes"
display_name = "Dress shoes"
path = /obj/item/clothing/shoes/centcom
/datum/gear/shoes/cowboyboots
display_name = "cowboy boots, brown"
display_name = "Cowboy boots, brown"
path = /obj/item/clothing/shoes/cowboy
/datum/gear/shoes/cowboyboots_black
display_name = "cowboy boots, black"
display_name = "Cowboy boots, black"
path = /obj/item/clothing/shoes/cowboy/black
/datum/gear/shoes/cowboyboots/white
display_name = "cowboy boots, white"
display_name = "Cowboy boots, white"
path = /obj/item/clothing/shoes/cowboy/white
/datum/gear/shoes/cowboyboots/pink
display_name = "cowboy boots, pink"
display_name = "Cowboy boots, pink"
path = /obj/item/clothing/shoes/cowboy/pink
/datum/gear/shoes/jackboots
display_name = "jackboots"
display_name = "Jackboots"
path = /obj/item/clothing/shoes/jackboots
/datum/gear/shoes/jacksandals
display_name = "jacksandals"
display_name = "Jacksandals"
path = /obj/item/clothing/shoes/jackboots/jacksandals
/datum/gear/shoes/laceup
display_name = "laceup shoes"
display_name = "Laceup shoes"
path = /obj/item/clothing/shoes/laceup
/datum/gear/shoes/blackshoes
@@ -1,227 +1,238 @@
/*
######################################################################################
## ##
## IMPORTANT README ##
## ##
## Changing any /datum/gear typepaths --WILL-- break people's loadouts. ##
## The typepaths are stored directly in the `characters.gear` column of the DB. ##
## Please inform the server host if you wish to modify any of these. ##
## ##
######################################################################################
*/
/datum/gear/suit
subtype_path = /datum/gear/suit
main_typepath = /datum/gear/suit
slot = slot_wear_suit
sort_category = "External Wear"
//WINTER COATS
/datum/gear/suit/coat
subtype_path = /datum/gear/suit/coat
main_typepath = /datum/gear/suit/coat
/datum/gear/suit/coat/grey
display_name = "winter coat"
display_name = "Winter coat"
path = /obj/item/clothing/suit/hooded/wintercoat
/datum/gear/suit/coat/job
subtype_path = /datum/gear/suit/coat/job
subtype_cost_overlap = FALSE
main_typepath = /datum/gear/suit/coat/job
subtype_selection_cost = FALSE
/datum/gear/suit/coat/job/sec
display_name = "winter coat, security"
display_name = "Winter coat, security"
path = /obj/item/clothing/suit/hooded/wintercoat/security
allowed_roles = list("Head of Security", "Warden", "Detective", "Security Officer", "Security Pod Pilot")
allowed_roles = list("Head of Security", "Warden", "Detective", "Security Officer")
/datum/gear/suit/coat/job/captain
display_name = "winter coat, captain"
display_name = "Winter coat, captain"
path = /obj/item/clothing/suit/hooded/wintercoat/captain
allowed_roles = list("Captain")
/datum/gear/suit/coat/job/med
display_name = "winter coat, medical"
display_name = "Winter coat, medical"
path = /obj/item/clothing/suit/hooded/wintercoat/medical
allowed_roles = list("Chief Medical Officer", "Medical Doctor", "Chemist", "Psychiatrist", "Paramedic", "Virologist", "Brig Physician" , "Coroner")
/datum/gear/suit/coat/job/sci
display_name = "winter coat, science"
display_name = "Winter coat, science"
path = /obj/item/clothing/suit/hooded/wintercoat/science
allowed_roles = list("Scientist", "Research Director")
/datum/gear/suit/coat/job/engi
display_name = "winter coat, engineering"
display_name = "Winter coat, engineering"
path = /obj/item/clothing/suit/hooded/wintercoat/engineering
allowed_roles = list("Chief Engineer", "Station Engineer", "Mechanic")
allowed_roles = list("Chief Engineer", "Station Engineer")
/datum/gear/suit/coat/job/atmos
display_name = "winter coat, atmospherics"
display_name = "Winter coat, atmospherics"
path = /obj/item/clothing/suit/hooded/wintercoat/engineering/atmos
allowed_roles = list("Chief Engineer", "Life Support Specialist")
/datum/gear/suit/coat/job/hydro
display_name = "winter coat, hydroponics"
display_name = "Winter coat, hydroponics"
path = /obj/item/clothing/suit/hooded/wintercoat/hydro
allowed_roles = list("Botanist")
/datum/gear/suit/coat/job/cargo
display_name = "winter coat, cargo"
display_name = "Winter coat, cargo"
path = /obj/item/clothing/suit/hooded/wintercoat/cargo
allowed_roles = list("Quartermaster", "Cargo Technician")
/datum/gear/suit/coat/job/miner
display_name = "winter coat, miner"
display_name = "Winter coat, mining"
path = /obj/item/clothing/suit/hooded/wintercoat/miner
allowed_roles = list("Shaft Miner")
//LABCOATS
/datum/gear/suit/labcoat_emt
display_name = "labcoat, paramedic"
display_name = "Labcoat, paramedic"
path = /obj/item/clothing/suit/storage/labcoat/emt
allowed_roles = list("Chief Medical Officer", "Paramedic")
//JACKETS
/datum/gear/suit/leather_jacket
display_name = "leather jacket"
display_name = "Leather jacket"
path = /obj/item/clothing/suit/jacket/leather
/datum/gear/suit/motojacket
display_name = "leather motorcycle jacket"
display_name = "Leather motorcycle jacket"
path = /obj/item/clothing/suit/jacket/motojacket
/datum/gear/suit/br_tcoat
display_name = "trenchcoat, brown"
display_name = "Trenchcoat, brown"
path = /obj/item/clothing/suit/browntrenchcoat
/datum/gear/suit/bl_tcoat
display_name = "trenchcoat, black"
display_name = "Trenchcoat, black"
path = /obj/item/clothing/suit/blacktrenchcoat
/datum/gear/suit/bomber_jacket
display_name = "bomber jacket"
display_name = "Bomber jacket"
path = /obj/item/clothing/suit/jacket
/datum/gear/suit/ol_miljacket
display_name = "military jacket, olive"
display_name = "Military jacket, olive"
path = /obj/item/clothing/suit/jacket/miljacket
/datum/gear/suit/nv_miljacket
display_name = "military jacket, navy"
display_name = "Military jacket, navy"
path = /obj/item/clothing/suit/jacket/miljacket/navy
/datum/gear/suit/ds_miljacket
display_name = "military jacket, desert"
display_name = "Military jacket, desert"
path = /obj/item/clothing/suit/jacket/miljacket/desert
/datum/gear/suit/wh_miljacket
display_name = "military jacket, white"
display_name = "Military jacket, white"
path = /obj/item/clothing/suit/jacket/miljacket/white
/datum/gear/suit/secjacket
display_name = "security jacket"
display_name = "Security jacket"
path = /obj/item/clothing/suit/armor/secjacket
allowed_roles = list("Head of Security", "Warden", "Detective", "Security Officer", "Security Pod Pilot")
allowed_roles = list("Head of Security", "Warden", "Detective", "Security Officer")
/datum/gear/suit/secbomberjacket
display_name = "security bomber jacket"
path = /obj/item/clothing/suit/jacket/pilot
allowed_roles = list("Head of Security", "Warden", "Detective", "Security Officer", "Security Pod Pilot")
display_name = "Security bomber jacket"
path = /obj/item/clothing/suit/jacket/secbomber
allowed_roles = list("Head of Security", "Warden", "Detective", "Security Officer")
/datum/gear/suit/ianshirt
display_name = "Ian Shirt"
path = /obj/item/clothing/suit/ianshirt
/datum/gear/suit/poncho
display_name = "poncho, classic"
display_name = "Poncho, classic"
path = /obj/item/clothing/suit/poncho
/datum/gear/suit/grponcho
display_name = "poncho, green"
display_name = "Poncho, green"
path = /obj/item/clothing/suit/poncho/green
/datum/gear/suit/rdponcho
display_name = "poncho, red"
display_name = "Poncho, red"
path = /obj/item/clothing/suit/poncho/red
/datum/gear/suit/tphoodie
display_name = "hoodie, Tharsis Polytech"
display_name = "Hoodie, Tharsis Polytech"
path = /obj/item/clothing/suit/hooded/hoodie/tp
/datum/gear/suit/nthoodie
display_name = "hoodie, Nanotrasen"
display_name = "Hoodie, Nanotrasen"
path = /obj/item/clothing/suit/hooded/hoodie/nt
/datum/gear/suit/lamhoodie
display_name = "hoodie, Lunar Academy of Medicine"
display_name = "Hoodie, Lunar Academy of Medicine"
path = /obj/item/clothing/suit/hooded/hoodie/lam
/datum/gear/suit/cuthoodie
display_name = "hoodie, Canaan University of Technology"
display_name = "Hoodie, Canaan University of Technology"
path = /obj/item/clothing/suit/hooded/hoodie/cut
/datum/gear/suit/mithoodie
display_name = "hoodie, Martian Institute of Technology"
display_name = "Hoodie, Martian Institute of Technology"
path = /obj/item/clothing/suit/hooded/hoodie/mit
/datum/gear/suit/bluehoodie
display_name = "hoodie, blue"
display_name = "Hoodie, blue"
path = /obj/item/clothing/suit/hooded/hoodie/blue
/datum/gear/suit/blackhoodie
display_name = "hoodie, black"
display_name = "Hoodie, black"
path = /obj/item/clothing/suit/hooded/hoodie
//SUITS!
/datum/gear/suit/blacksuit
display_name = "suit jacket, black"
display_name = "Suit jacket, black"
path = /obj/item/clothing/suit/storage/lawyer/blackjacket
/datum/gear/suit/bluesuit
display_name = "suit jacket, blue"
display_name = "Suit jacket, blue"
path = /obj/item/clothing/suit/storage/lawyer/bluejacket
/datum/gear/suit/purplesuit
display_name = "suit jacket, purple"
display_name = "Suit jacket, purple"
path = /obj/item/clothing/suit/storage/lawyer/purpjacket
//Mantles!
/datum/gear/suit/mantle
display_name = "mantle"
display_name = "Mantle"
path = /obj/item/clothing/suit/mantle
/datum/gear/suit/old_scarf
display_name = "old scarf"
display_name = "Old scarf"
path = /obj/item/clothing/suit/mantle/old
/datum/gear/suit/regal_shawl
display_name = "regal shawl"
display_name = "Regal shawl"
path = /obj/item/clothing/suit/mantle/regal
/datum/gear/suit/mantle/job
subtype_path = /datum/gear/suit/mantle/job
subtype_cost_overlap = FALSE
main_typepath = /datum/gear/suit/mantle/job
subtype_selection_cost = FALSE
/datum/gear/suit/mantle/job/captain
display_name = "mantle, captain"
display_name = "Mantle, captain"
path = /obj/item/clothing/suit/mantle/armor/captain
allowed_roles = list("Captain")
/datum/gear/suit/mantle/job/ce
display_name = "mantle, chief engineer"
display_name = "Mantle, chief engineer"
path = /obj/item/clothing/suit/mantle/chief_engineer
allowed_roles = list("Chief Engineer")
/datum/gear/suit/mantle/job/cmo
display_name = "mantle, chief medical officer"
display_name = "Mantle, chief medical officer"
path = /obj/item/clothing/suit/mantle/labcoat/chief_medical_officer
allowed_roles = list("Chief Medical Officer")
/datum/gear/suit/mantle/job/hos
display_name = "mantle, head of security"
display_name = "Mantle, head of security"
path = /obj/item/clothing/suit/mantle/armor
allowed_roles = list("Head of Security")
/datum/gear/suit/mantle/job/hop
display_name = "mantle, head of personnel"
display_name = "Mantle, head of personnel"
path = /obj/item/clothing/suit/mantle/armor/head_of_personnel
allowed_roles = list("Head of Personnel")
/datum/gear/suit/mantle/job/rd
display_name = "mantle, research director"
display_name = "Mantle, research director"
path = /obj/item/clothing/suit/mantle/labcoat
allowed_roles = list("Research Director")
//Robes!
/datum/gear/suit/witch
display_name = "witch robes"
display_name = "Witch robes"
path = /obj/item/clothing/suit/wizrobe/marisa/fake
@@ -1,96 +1,105 @@
/*
######################################################################################
## ##
## IMPORTANT README ##
## ##
## Changing any /datum/gear typepaths --WILL-- break people's loadouts. ##
## The typepaths are stored directly in the `characters.gear` column of the DB. ##
## Please inform the server host if you wish to modify any of these. ##
## ##
######################################################################################
*/
// Uniform slot
/datum/gear/uniform
subtype_path = /datum/gear/uniform
main_typepath = /datum/gear/uniform
slot = slot_w_uniform
sort_category = "Uniforms and Casual Dress"
/datum/gear/uniform/suit
subtype_path = /datum/gear/uniform/suit
main_typepath = /datum/gear/uniform/suit
//there's a lot more colors than I thought there were @_@
/datum/gear/uniform/suit/jumpsuitblack
display_name = "jumpsuit, black"
display_name = "Jumpsuit, black"
path = /obj/item/clothing/under/color/black
/datum/gear/uniform/suit/jumpsuitblue
display_name = "jumpsuit, blue"
display_name = "Jumpsuit, blue"
path = /obj/item/clothing/under/color/blue
/datum/gear/uniform/suit/jumpsuitgreen
display_name = "jumpsuit, green"
display_name = "Jumpsuit, green"
path = /obj/item/clothing/under/color/green
/datum/gear/uniform/suit/jumpsuitgrey
display_name = "jumpsuit, grey"
display_name = "Jumpsuit, grey"
path = /obj/item/clothing/under/color/grey
/datum/gear/uniform/suit/jumpsuitorange
display_name = "jumpsuit, orange"
display_name = "Jumpsuit, orange"
path = /obj/item/clothing/under/color/orange
/datum/gear/uniform/suit/jumpsuitpink
display_name = "jumpsuit, pink"
display_name = "Jumpsuit, pink"
path = /obj/item/clothing/under/color/pink
/datum/gear/uniform/suit/jumpsuitred
display_name = "jumpsuit, red"
display_name = "Jumpsuit, red"
path = /obj/item/clothing/under/color/red
/datum/gear/uniform/suit/jumpsuitwhite
display_name = "jumpsuit, white"
display_name = "Jumpsuit, white"
path = /obj/item/clothing/under/color/white
/datum/gear/uniform/suit/jumpsuityellow
display_name = "jumpsuit, yellow"
display_name = "Jumpsuit, yellow"
path = /obj/item/clothing/under/color/yellow
/datum/gear/uniform/suit/jumpsuitlightblue
display_name = "jumpsuit, lightblue"
display_name = "Jumpsuit, lightblue"
path = /obj/item/clothing/under/color/lightblue
/datum/gear/uniform/suit/jumpsuitaqua
display_name = "jumpsuit, aqua"
display_name = "Jumpsuit, aqua"
path = /obj/item/clothing/under/color/aqua
/datum/gear/uniform/suit/jumpsuitpurple
display_name = "jumpsuit, purple"
display_name = "Jumpsuit, purple"
path = /obj/item/clothing/under/color/purple
/datum/gear/uniform/suit/jumpsuitlightpurple
display_name = "jumpsuit, lightpurple"
display_name = "Jumpsuit, lightpurple"
path = /obj/item/clothing/under/color/lightpurple
/datum/gear/uniform/suit/jumpsuitlightgreen
display_name = "jumpsuit, lightgreen"
display_name = "Jumpsuit, lightgreen"
path = /obj/item/clothing/under/color/lightgreen
/datum/gear/uniform/suit/jumpsuitlightblue
display_name = "jumpsuit, lightblue"
path = /obj/item/clothing/under/color/lightblue
/datum/gear/uniform/suit/jumpsuitlightbrown
display_name = "jumpsuit, lightbrown"
display_name = "Jumpsuit, lightbrown"
path = /obj/item/clothing/under/color/lightbrown
/datum/gear/uniform/suit/jumpsuitbrown
display_name = "jumpsuit, brown"
display_name = "Jumpsuit, brown"
path = /obj/item/clothing/under/color/brown
/datum/gear/uniform/suit/jumpsuityellowgreen
display_name = "jumpsuit, yellowgreen"
display_name = "Jumpsuit, yellowgreen"
path = /obj/item/clothing/under/color/yellowgreen
/datum/gear/uniform/suit/jumpsuitdarkblue
display_name = "jumpsuit, darkblue"
display_name = "Jumpsuit, darkblue"
path = /obj/item/clothing/under/color/darkblue
/datum/gear/uniform/suit/jumpsuitlightred
display_name = "jumpsuit, lightred"
display_name = "Jumpsuit, lightred"
path = /obj/item/clothing/under/color/lightred
/datum/gear/uniform/suit/jumpsuitdarkred
display_name = "jumpsuit, darkred"
display_name = "Jumpsuit, darkred"
path = /obj/item/clothing/under/color/darkred
/datum/gear/uniform/suit/soviet
@@ -98,229 +107,229 @@
path = /obj/item/clothing/under/soviet
/datum/gear/uniform/suit/kilt
display_name = "a kilt"
display_name = "Kilt"
path = /obj/item/clothing/under/kilt
/datum/gear/uniform/skirt
subtype_path = /datum/gear/uniform/skirt
main_typepath = /datum/gear/uniform/skirt
/datum/gear/uniform/skirt/blue
display_name = "plaid skirt, blue"
display_name = "Plaid skirt, blue"
path = /obj/item/clothing/under/dress/plaid_blue
/datum/gear/uniform/skirt/purple
display_name = "plaid skirt, purple"
display_name = "Plaid skirt, purple"
path = /obj/item/clothing/under/dress/plaid_purple
/datum/gear/uniform/skirt/red
display_name = "plaid skirt, red"
display_name = "Plaid skirt, red"
path = /obj/item/clothing/under/dress/plaid_red
/datum/gear/uniform/skirt/black
display_name = "skirt, black"
display_name = "Skirt, black"
path = /obj/item/clothing/under/blackskirt
/datum/gear/uniform/skirt/job
subtype_path = /datum/gear/uniform/skirt/job
subtype_cost_overlap = FALSE
main_typepath = /datum/gear/uniform/skirt/job
subtype_selection_cost = FALSE
/datum/gear/uniform/skirt/job/ce
display_name = "skirt, ce"
display_name = "Skirt, ce"
path = /obj/item/clothing/under/rank/chief_engineer/skirt
allowed_roles = list("Chief Engineer")
/datum/gear/uniform/skirt/job/atmos
display_name = "skirt, atmos"
display_name = "Skirt, atmos"
path = /obj/item/clothing/under/rank/atmospheric_technician/skirt
allowed_roles = list("Chief Engineer","Life Support Specialist")
/datum/gear/uniform/skirt/job/eng
display_name = "skirt, engineer"
display_name = "Skirt, engineer"
path = /obj/item/clothing/under/rank/engineer/skirt
allowed_roles = list("Chief Engineer","Station Engineer")
/datum/gear/uniform/skirt/job/roboticist
display_name = "skirt, roboticist"
display_name = "Skirt, roboticist"
path = /obj/item/clothing/under/rank/roboticist/skirt
allowed_roles = list("Research Director","Roboticist")
/datum/gear/uniform/skirt/job/cmo
display_name = "skirt, cmo"
display_name = "Skirt, cmo"
path = /obj/item/clothing/under/rank/chief_medical_officer/skirt
allowed_roles = list("Chief Medical Officer")
/datum/gear/uniform/skirt/job/chem
display_name = "skirt, chemist"
display_name = "Skirt, chemist"
path = /obj/item/clothing/under/rank/chemist/skirt
allowed_roles = list("Chief Medical Officer","Chemist")
/datum/gear/uniform/skirt/job/viro
display_name = "skirt, virologist"
display_name = "Skirt, virologist"
path = /obj/item/clothing/under/rank/virologist/skirt
allowed_roles = list("Virologist")
/datum/gear/uniform/skirt/job/med
display_name = "skirt, medical"
display_name = "Skirt, medical"
path = /obj/item/clothing/under/rank/medical/skirt
allowed_roles = list("Chief Medical Officer","Medical Doctor","Psychiatrist","Paramedic","Coroner")
/datum/gear/uniform/skirt/job/phys
display_name = "skirt, physician"
display_name = "Skirt, physician"
path = /obj/item/clothing/under/rank/security/brigphys/skirt
allowed_roles = list("Brig Physician")
/datum/gear/uniform/skirt/job/sci
display_name = "skirt, scientist"
display_name = "Skirt, scientist"
path = /obj/item/clothing/under/rank/scientist/skirt
allowed_roles = list("Research Director","Scientist")
/datum/gear/uniform/skirt/job/cargo
display_name = "skirt, cargo"
display_name = "Skirt, cargo"
path = /obj/item/clothing/under/rank/cargotech/skirt
allowed_roles = list("Quartermaster","Cargo Technician")
/datum/gear/uniform/skirt/job/qm
display_name = "skirt, QM"
display_name = "Skirt, QM"
path = /obj/item/clothing/under/rank/cargo/skirt
allowed_roles = list("Quartermaster")
/datum/gear/uniform/skirt/job/warden
display_name = "skirt, warden"
display_name = "Skirt, warden"
path = /obj/item/clothing/under/rank/warden/skirt
allowed_roles = list("Head of Security", "Warden")
/datum/gear/uniform/skirt/job/security
display_name = "skirt, security"
display_name = "Skirt, security"
path = /obj/item/clothing/under/rank/security/skirt
allowed_roles = list("Head of Security", "Warden", "Detective", "Security Officer")
/datum/gear/uniform/skirt/job/head_of_security
display_name = "skirt, hos"
display_name = "Skirt, hos"
path = /obj/item/clothing/under/rank/head_of_security/skirt
allowed_roles = list("Head of Security")
/datum/gear/uniform/skirt/job/ntrep
display_name = "skirt, nt rep"
display_name = "Skirt, nt rep"
path = /obj/item/clothing/under/rank/ntrep/skirt
allowed_roles = list("Nanotrasen Representative")
/datum/gear/uniform/skirt/job/blueshield
display_name = "skirt, blueshield"
display_name = "Skirt, blueshield"
path = /obj/item/clothing/under/rank/blueshield/skirt
allowed_roles = list("Blueshield")
/datum/gear/uniform/medical
subtype_path = /datum/gear/uniform/medical
main_typepath = /datum/gear/uniform/medical
/datum/gear/uniform/medical/pscrubs
display_name = "medical scrubs, purple"
display_name = "Medical scrubs, purple"
path = /obj/item/clothing/under/rank/medical/purple
allowed_roles = list("Chief Medical Officer", "Medical Doctor")
/datum/gear/uniform/medical/gscrubs
display_name = "medical scrubs, green"
display_name = "Medical scrubs, green"
path = /obj/item/clothing/under/rank/medical/green
allowed_roles = list("Chief Medical Officer", "Medical Doctor")
/datum/gear/uniform/sec
subtype_path = /datum/gear/uniform/sec
main_typepath = /datum/gear/uniform/sec
/datum/gear/uniform/sec/formal
display_name = "security uniform, formal"
display_name = "Security uniform, formal"
path = /obj/item/clothing/under/rank/security/formal
allowed_roles = list("Head of Security", "Warden", "Detective", "Security Officer", "Security Pod Pilot")
allowed_roles = list("Head of Security", "Warden", "Detective", "Security Officer")
/datum/gear/uniform/sec/secorporate
display_name = "security uniform, corporate"
display_name = "Security uniform, corporate"
path = /obj/item/clothing/under/rank/security/corp
allowed_roles = list("Head of Security", "Warden", "Security Officer", "Security Pod Pilot")
allowed_roles = list("Head of Security", "Warden", "Security Officer")
/datum/gear/uniform/sec/dispatch
display_name = "security uniform, dispatch"
display_name = "Security uniform, dispatch"
path = /obj/item/clothing/under/rank/dispatch
allowed_roles = list("Head of Security", "Warden", "Security Officer", "Security Pod Pilot")
allowed_roles = list("Head of Security", "Warden", "Security Officer")
/datum/gear/uniform/sec/casual
display_name = "security uniform, casual"
display_name = "Security uniform, casual"
path = /obj/item/clothing/under/rank/security2
allowed_roles = list("Head of Security", "Warden", "Security Officer", "Detective", "Security Pod Pilot")
allowed_roles = list("Head of Security", "Warden", "Security Officer", "Detective")
/datum/gear/uniform/shorts
subtype_path = /datum/gear/uniform/shorts
main_typepath = /datum/gear/uniform/shorts
/datum/gear/uniform/shorts/red
display_name = "shorts, red"
display_name = "Shorts, red"
path = /obj/item/clothing/under/shorts/red
/datum/gear/uniform/shorts/green
display_name = "shorts, green"
display_name = "Shorts, green"
path = /obj/item/clothing/under/shorts/green
/datum/gear/uniform/shorts/blue
display_name = "shorts, blue"
display_name = "Shorts, blue"
path = /obj/item/clothing/under/shorts/blue
/datum/gear/uniform/shorts/black
display_name = "shorts, black"
display_name = "Shorts, black"
path = /obj/item/clothing/under/shorts/black
/datum/gear/uniform/shorts/grey
display_name = "shorts, grey"
display_name = "Shorts, grey"
path = /obj/item/clothing/under/shorts/grey
/datum/gear/uniform/pants
subtype_path = /datum/gear/uniform/pants
main_typepath = /datum/gear/uniform/pants
/datum/gear/uniform/pants/jeans
display_name = "jeans, classic"
display_name = "Jeans, classic"
path = /obj/item/clothing/under/pants/classicjeans
/datum/gear/uniform/pants/mjeans
display_name = "jeans, mustang"
display_name = "Jeans, mustang"
path = /obj/item/clothing/under/pants/mustangjeans
/datum/gear/uniform/pants/bljeans
display_name = "jeans, black"
display_name = "Jeans, black"
path = /obj/item/clothing/under/pants/blackjeans
/datum/gear/uniform/pants/yfjeans
display_name = "jeans, Young Folks"
display_name = "Jeans, Young Folks"
path = /obj/item/clothing/under/pants/youngfolksjeans
/datum/gear/uniform/pants/whitepants
display_name = "pants, white"
display_name = "Pants, white"
path = /obj/item/clothing/under/pants/white
/datum/gear/uniform/pants/redpants
display_name = "pants, red"
display_name = "Pants, red"
path = /obj/item/clothing/under/pants/red
/datum/gear/uniform/pants/blackpants
display_name = "pants, black"
display_name = "Pants, black"
path = /obj/item/clothing/under/pants/black
/datum/gear/uniform/pants/tanpants
display_name = "pants, tan"
display_name = "Pants, tan"
path = /obj/item/clothing/under/pants/tan
/datum/gear/uniform/pants/bluepants
display_name = "pants, blue"
display_name = "Pants, blue"
path = /obj/item/clothing/under/pants/blue
/datum/gear/uniform/pants/trackpants
display_name = "trackpants"
display_name = "Trackpants"
path = /obj/item/clothing/under/pants/track
/datum/gear/uniform/pants/khakipants
display_name = "pants, khaki"
display_name = "Pants, khaki"
path = /obj/item/clothing/under/pants/khaki
/datum/gear/uniform/pants/caopants
display_name = "pants, camo"
display_name = "Pants, camo"
path = /obj/item/clothing/under/pants/camo
/datum/gear/uniform/suit/tacticool
display_name = "tacticool turtleneck"
display_name = "Tacticool turtleneck"
description = "A sleek black turtleneck paired with some khakis (WARNING DOES NOT HAVE SUIT SENSORS)"
path = /obj/item/clothing/under/syndicate/tacticool
File diff suppressed because it is too large Load Diff
@@ -1,32 +1,6 @@
/datum/preferences/proc/load_preferences(client/C)
var/datum/db_query/query = SSdbcore.NewQuery({"SELECT
ooccolor,
UI_style,
UI_style_color,
UI_style_alpha,
be_role,
default_slot,
toggles,
toggles_2,
sound,
volume_mixer,
lastchangelog,
exp,
clientfps,
atklog,
fuid,
parallax,
2fa_status
FROM player
WHERE ckey=:ckey"}, list(
"ckey" = C.ckey
))
if(!query.warn_execute())
qdel(query)
return
/datum/preferences/proc/load_preferences(datum/db_query/query)
// Looking for the query?
// Check ../login_processing/10-load_preferences.dm
//general preferences
while(query.NextRow())
@@ -48,8 +22,6 @@
parallax = text2num(query.item[16])
_2fa_status = query.item[17]
qdel(query)
//Sanitize
ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor))
UI_style = sanitize_inlist(UI_style, list("White", "Midnight", "Plasmafire", "Retro", "Slimecore", "Operative"), initial(UI_style))
@@ -65,7 +37,7 @@
atklog = sanitize_integer(atklog, 0, 100, initial(atklog))
fuid = sanitize_integer(fuid, 0, 10000000, initial(fuid))
parallax = sanitize_integer(parallax, 0, 16, initial(parallax))
return 1
return TRUE
/datum/preferences/proc/save_preferences(client/C)
@@ -126,570 +98,22 @@
qdel(query)
return 1
/datum/preferences/proc/load_character(client/C,slot)
saved = FALSE
if(!slot) slot = default_slot
slot = sanitize_integer(slot, 1, max_save_slots, initial(default_slot))
if(slot != default_slot)
default_slot = slot
var/datum/db_query/firstquery = SSdbcore.NewQuery("UPDATE player SET default_slot=:slot WHERE ckey=:ckey", list(
"slot" = slot,
"ckey" = C.ckey
))
if(!firstquery.warn_execute(async = FALSE)) // Dont make this async. It makes roundstart slow.
qdel(firstquery)
return
qdel(firstquery)
// Let's not have this explode if you sneeze on the DB
var/datum/db_query/query = SSdbcore.NewQuery({"SELECT
OOC_Notes,
real_name,
name_is_always_random,
gender,
age,
species,
language,
hair_colour,
secondary_hair_colour,
facial_hair_colour,
secondary_facial_hair_colour,
skin_tone,
skin_colour,
marking_colours,
head_accessory_colour,
hair_style_name,
facial_style_name,
marking_styles,
head_accessory_style_name,
alt_head_name,
eye_colour,
underwear,
undershirt,
backbag,
b_type,
alternate_option,
job_support_high,
job_support_med,
job_support_low,
job_medsci_high,
job_medsci_med,
job_medsci_low,
job_engsec_high,
job_engsec_med,
job_engsec_low,
job_karma_high,
job_karma_med,
job_karma_low,
flavor_text,
med_record,
sec_record,
gen_record,
disabilities,
player_alt_titles,
organ_data,
rlimb_data,
nanotrasen_relation,
speciesprefs,
socks,
body_accessory,
gear,
autohiss,
hair_gradient,
hair_gradient_offset,
hair_gradient_colour,
hair_gradient_alpha
FROM characters WHERE ckey=:ckey AND slot=:slot"}, list(
"ckey" = C.ckey,
"slot" = slot
))
if(!query.warn_execute(async = FALSE)) // Dont make this async. It makes roundstart slow.
qdel(query)
return
while(query.NextRow())
//Character
metadata = query.item[1]
real_name = query.item[2]
be_random_name = text2num(query.item[3])
gender = query.item[4]
age = text2num(query.item[5])
species = query.item[6]
language = query.item[7]
h_colour = query.item[8]
h_sec_colour = query.item[9]
f_colour = query.item[10]
f_sec_colour = query.item[11]
s_tone = text2num(query.item[12])
s_colour = query.item[13]
m_colours = params2list(query.item[14])
hacc_colour = query.item[15]
h_style = query.item[16]
f_style = query.item[17]
m_styles = params2list(query.item[18])
ha_style = query.item[19]
alt_head = query.item[20]
e_colour = query.item[21]
underwear = query.item[22]
undershirt = query.item[23]
backbag = query.item[24]
b_type = query.item[25]
//Jobs
alternate_option = text2num(query.item[26])
job_support_high = text2num(query.item[27])
job_support_med = text2num(query.item[28])
job_support_low = text2num(query.item[29])
job_medsci_high = text2num(query.item[30])
job_medsci_med = text2num(query.item[31])
job_medsci_low = text2num(query.item[32])
job_engsec_high = text2num(query.item[33])
job_engsec_med = text2num(query.item[34])
job_engsec_low = text2num(query.item[35])
job_karma_high = text2num(query.item[36])
job_karma_med = text2num(query.item[37])
job_karma_low = text2num(query.item[38])
//Miscellaneous
flavor_text = query.item[39]
med_record = query.item[40]
sec_record = query.item[41]
gen_record = query.item[42]
// Apparently, the preceding vars weren't always encoded properly...
if(findtext(flavor_text, "<")) // ... so let's clumsily check for tags!
flavor_text = html_encode(flavor_text)
if(findtext(med_record, "<"))
med_record = html_encode(med_record)
if(findtext(sec_record, "<"))
sec_record = html_encode(sec_record)
if(findtext(gen_record, "<"))
gen_record = html_encode(gen_record)
disabilities = text2num(query.item[43])
player_alt_titles = params2list(query.item[44])
organ_data = params2list(query.item[45])
rlimb_data = params2list(query.item[46])
nanotrasen_relation = query.item[47]
speciesprefs = text2num(query.item[48])
//socks
socks = query.item[49]
body_accessory = query.item[50]
loadout_gear = params2list(query.item[51])
autohiss_mode = text2num(query.item[52])
h_grad_style = query.item[53]
h_grad_offset_x = query.item[54] // parsed down below
h_grad_colour = query.item[55]
h_grad_alpha = query.item[56]
saved = TRUE
qdel(query)
//Sanitize
var/datum/species/SP = GLOB.all_species[species]
metadata = sanitize_text(metadata, initial(metadata))
real_name = reject_bad_name(real_name, 1)
if(isnull(species)) species = "Human"
if(isnull(language)) language = "None"
if(isnull(nanotrasen_relation)) nanotrasen_relation = initial(nanotrasen_relation)
if(isnull(speciesprefs)) speciesprefs = initial(speciesprefs)
if(!real_name) real_name = random_name(gender,species)
be_random_name = sanitize_integer(be_random_name, 0, 1, initial(be_random_name))
gender = sanitize_gender(gender, FALSE, !SP.has_gender)
age = sanitize_integer(age, AGE_MIN, AGE_MAX, initial(age))
h_colour = sanitize_hexcolor(h_colour)
h_sec_colour = sanitize_hexcolor(h_sec_colour)
f_colour = sanitize_hexcolor(f_colour)
f_sec_colour = sanitize_hexcolor(f_sec_colour)
s_tone = sanitize_integer(s_tone, -185, 34, initial(s_tone))
s_colour = sanitize_hexcolor(s_colour)
for(var/marking_location in m_colours)
m_colours[marking_location] = sanitize_hexcolor(m_colours[marking_location], DEFAULT_MARKING_COLOURS[marking_location])
hacc_colour = sanitize_hexcolor(hacc_colour)
h_style = sanitize_inlist(h_style, GLOB.hair_styles_public_list, initial(h_style))
f_style = sanitize_inlist(f_style, GLOB.facial_hair_styles_list, initial(f_style))
for(var/marking_location in m_styles)
m_styles[marking_location] = sanitize_inlist(m_styles[marking_location], GLOB.marking_styles_list, DEFAULT_MARKING_STYLES[marking_location])
ha_style = sanitize_inlist(ha_style, GLOB.head_accessory_styles_list, initial(ha_style))
alt_head = sanitize_inlist(alt_head, GLOB.alt_heads_list, initial(alt_head))
e_colour = sanitize_hexcolor(e_colour)
underwear = sanitize_text(underwear, initial(underwear))
undershirt = sanitize_text(undershirt, initial(undershirt))
backbag = sanitize_text(backbag, initial(backbag))
b_type = sanitize_text(b_type, initial(b_type))
autohiss_mode = sanitize_integer(autohiss_mode, 0, 2, initial(autohiss_mode))
alternate_option = sanitize_integer(alternate_option, 0, 2, initial(alternate_option))
job_support_high = sanitize_integer(job_support_high, 0, 65535, initial(job_support_high))
job_support_med = sanitize_integer(job_support_med, 0, 65535, initial(job_support_med))
job_support_low = sanitize_integer(job_support_low, 0, 65535, initial(job_support_low))
job_medsci_high = sanitize_integer(job_medsci_high, 0, 65535, initial(job_medsci_high))
job_medsci_med = sanitize_integer(job_medsci_med, 0, 65535, initial(job_medsci_med))
job_medsci_low = sanitize_integer(job_medsci_low, 0, 65535, initial(job_medsci_low))
job_engsec_high = sanitize_integer(job_engsec_high, 0, 65535, initial(job_engsec_high))
job_engsec_med = sanitize_integer(job_engsec_med, 0, 65535, initial(job_engsec_med))
job_engsec_low = sanitize_integer(job_engsec_low, 0, 65535, initial(job_engsec_low))
job_karma_high = sanitize_integer(job_karma_high, 0, 65535, initial(job_karma_high))
job_karma_med = sanitize_integer(job_karma_med, 0, 65535, initial(job_karma_med))
job_karma_low = sanitize_integer(job_karma_low, 0, 65535, initial(job_karma_low))
disabilities = sanitize_integer(disabilities, 0, 65535, initial(disabilities))
socks = sanitize_text(socks, initial(socks))
body_accessory = sanitize_text(body_accessory, initial(body_accessory))
// h_grad_style =
var/list/expl = splittext(h_grad_offset_x, ",")
if(length(expl) == 2)
h_grad_offset_x = text2num(expl[1]) || 0
h_grad_offset_y = text2num(expl[2]) || 0
h_grad_colour = sanitize_hexcolor(h_grad_colour)
h_grad_alpha = sanitize_integer(h_grad_alpha, 0, 255, initial(h_grad_alpha))
// if(isnull(disabilities)) disabilities = 0
if(!player_alt_titles) player_alt_titles = new()
if(!organ_data) src.organ_data = list()
if(!rlimb_data) src.rlimb_data = list()
if(!loadout_gear) loadout_gear = list()
// Check if the current body accessory exists
if(!GLOB.body_accessory_by_name[body_accessory])
body_accessory = null
return 1
/datum/preferences/proc/save_character(client/C)
var/organlist
var/rlimblist
var/playertitlelist
var/gearlist
var/markingcolourslist = list2params(m_colours)
var/markingstyleslist = list2params(m_styles)
if(!isemptylist(organ_data))
organlist = list2params(organ_data)
if(!isemptylist(rlimb_data))
rlimblist = list2params(rlimb_data)
if(!isemptylist(player_alt_titles))
playertitlelist = list2params(player_alt_titles)
if(!isemptylist(loadout_gear))
gearlist = list2params(loadout_gear)
var/datum/db_query/firstquery = SSdbcore.NewQuery("SELECT slot FROM characters WHERE ckey=:ckey ORDER BY slot", list(
"ckey" = C.ckey
))
if(!firstquery.warn_execute())
qdel(firstquery)
return
while(firstquery.NextRow())
if(text2num(firstquery.item[1]) == default_slot)
var/datum/db_query/query = SSdbcore.NewQuery({"UPDATE characters
SET
OOC_Notes=:metadata,
real_name=:real_name,
name_is_always_random=:be_random_name,
gender=:gender,
age=:age,
species=:species,
language=:language,
hair_colour=:h_colour,
secondary_hair_colour=:h_sec_colour,
facial_hair_colour=:f_colour,
secondary_facial_hair_colour=:f_sec_colour,
skin_tone=:s_tone,
skin_colour=:s_colour,
marking_colours=:markingcolourslist,
head_accessory_colour=:hacc_colour,
hair_style_name=:h_style,
facial_style_name=:f_style,
marking_styles=:markingstyleslist,
head_accessory_style_name=:ha_style,
alt_head_name=:alt_head,
eye_colour=:e_colour,
underwear=:underwear,
undershirt=:undershirt,
backbag=:backbag,
b_type=:b_type,
alternate_option=:alternate_option,
job_support_high=:job_support_high,
job_support_med=:job_support_med,
job_support_low=:job_support_low,
job_medsci_high=:job_medsci_high,
job_medsci_med=:job_medsci_med,
job_medsci_low=:job_medsci_low,
job_engsec_high=:job_engsec_high,
job_engsec_med=:job_engsec_med,
job_engsec_low=:job_engsec_low,
job_karma_high=:job_karma_high,
job_karma_med=:job_karma_med,
job_karma_low=:job_karma_low,
flavor_text=:flavor_text,
med_record=:med_record,
sec_record=:sec_record,
gen_record=:gen_record,
player_alt_titles=:playertitlelist,
disabilities=:disabilities,
organ_data=:organlist,
rlimb_data=:rlimblist,
nanotrasen_relation=:nanotrasen_relation,
speciesprefs=:speciesprefs,
socks=:socks,
body_accessory=:body_accessory,
gear=:gearlist,
autohiss=:autohiss_mode,
hair_gradient=:h_grad_style,
hair_gradient_offset=:h_grad_offset,
hair_gradient_colour=:h_grad_colour,
hair_gradient_alpha=:h_grad_alpha
WHERE ckey=:ckey
AND slot=:slot"}, list(
// OH GOD SO MANY PARAMETERS
"metadata" = metadata,
"real_name" = real_name,
"be_random_name" = be_random_name,
"gender" = gender,
"age" = age,
"species" = species,
"language" = language,
"h_colour" = h_colour,
"h_sec_colour" = h_sec_colour,
"f_colour" = f_colour,
"f_sec_colour" = f_sec_colour,
"s_tone" = s_tone,
"s_colour" = s_colour,
"markingcolourslist" = markingcolourslist,
"hacc_colour" = hacc_colour,
"h_style" = h_style,
"f_style" = f_style,
"markingstyleslist" = markingstyleslist,
"ha_style" = ha_style,
"alt_head" = (alt_head ? alt_head : ""), // This it intentional. It wont work without it!
"e_colour" = e_colour,
"underwear" = underwear,
"undershirt" = undershirt,
"backbag" = backbag,
"b_type" = b_type,
"alternate_option" = alternate_option,
"job_support_high" = job_support_high,
"job_support_med" = job_support_med,
"job_support_low" = job_support_low,
"job_medsci_high" = job_medsci_high,
"job_medsci_med" = job_medsci_med,
"job_medsci_low" = job_medsci_low,
"job_engsec_high" = job_engsec_high,
"job_engsec_med" = job_engsec_med,
"job_engsec_low" = job_engsec_low,
"job_karma_high" = job_karma_high,
"job_karma_med" = job_karma_med,
"job_karma_low" = job_karma_low,
"flavor_text" = flavor_text,
"med_record" = med_record,
"sec_record" = sec_record,
"gen_record" = gen_record,
"playertitlelist" = (playertitlelist ? playertitlelist : ""), // This it intentnional. It wont work without it!
"disabilities" = disabilities,
"organlist" = (organlist ? organlist : ""),
"rlimblist" = (rlimblist ? rlimblist : ""),
"nanotrasen_relation" = nanotrasen_relation,
"speciesprefs" = speciesprefs,
"socks" = socks,
"body_accessory" = (body_accessory ? body_accessory : ""),
"gearlist" = (gearlist ? gearlist : ""),
"autohiss_mode" = autohiss_mode,
"h_grad_style" = h_grad_style,
"h_grad_offset" = "[h_grad_offset_x],[h_grad_offset_y]",
"h_grad_colour" = h_grad_colour,
"h_grad_alpha" = h_grad_alpha,
"ckey" = C.ckey,
"slot" = default_slot
)
)
if(!query.warn_execute())
qdel(firstquery)
qdel(query)
return
qdel(firstquery)
qdel(query)
return 1
qdel(firstquery)
var/datum/db_query/query = SSdbcore.NewQuery({"
INSERT INTO characters (ckey, slot, OOC_Notes, real_name, name_is_always_random, gender,
age, species, language,
hair_colour, secondary_hair_colour,
facial_hair_colour, secondary_facial_hair_colour,
skin_tone, skin_colour,
marking_colours,
head_accessory_colour,
hair_style_name,
facial_style_name,
marking_styles,
head_accessory_style_name,
alt_head_name,
eye_colour,
underwear, undershirt,
backbag, b_type, alternate_option,
job_support_high, job_support_med, job_support_low,
job_medsci_high, job_medsci_med, job_medsci_low,
job_engsec_high, job_engsec_med, job_engsec_low,
job_karma_high, job_karma_med, job_karma_low,
flavor_text,
med_record,
sec_record,
gen_record,
player_alt_titles,
disabilities, organ_data, rlimb_data, nanotrasen_relation, speciesprefs,
socks, body_accessory, gear, autohiss)
VALUES
(:ckey, :slot, :metadata, :name, :be_random_name, :gender,
:age, :species, :language,
:h_colour, :h_sec_colour,
:f_colour, :f_sec_colour,
:s_tone, :s_colour,
:markingcolourslist,
:hacc_colour,
:h_style,
:f_style,
:markingstyleslist,
:ha_style,
:alt_head,
:e_colour,
:underwear, :undershirt,
:backbag, :b_type, :alternate_option,
:job_support_high, :job_support_med, :job_support_low,
:job_medsci_high, :job_medsci_med, :job_medsci_low,
:job_engsec_high, :job_engsec_med, :job_engsec_low,
:job_karma_high, :job_karma_med, :job_karma_low,
:flavor_text,
:med_record,
:sec_record,
:gen_record,
:playertitlelist,
:disabilities, :organlist, :rlimblist, :nanotrasen_relation, :speciesprefs,
:socks, :body_accessory, :gearlist, :autohiss_mode)
"}, list(
// This has too many params for anyone to look at this without going insae
"ckey" = C.ckey,
"slot" = default_slot,
"metadata" = metadata,
"name" = real_name,
"be_random_name" = be_random_name,
"gender" = gender,
"age" = age,
"species" = species,
"language" = language,
"h_colour" = h_colour,
"h_sec_colour" = h_sec_colour,
"f_colour" = f_colour,
"f_sec_colour" = f_sec_colour,
"s_tone" = s_tone,
"s_colour" = s_colour,
"markingcolourslist" = markingcolourslist,
"hacc_colour" = hacc_colour,
"h_style" = h_style,
"f_style" = f_style,
"markingstyleslist" = markingstyleslist,
"ha_style" = ha_style,
"alt_head" = alt_head,
"e_colour" = e_colour,
"underwear" = underwear,
"undershirt" = undershirt,
"backbag" = backbag,
"b_type" = b_type,
"alternate_option" = alternate_option,
"job_support_high" = job_support_high,
"job_support_med" = job_support_med,
"job_support_low" = job_support_low,
"job_medsci_high" = job_medsci_high,
"job_medsci_med" = job_medsci_med,
"job_medsci_low" = job_medsci_low,
"job_engsec_high" = job_engsec_high,
"job_engsec_med" = job_engsec_med,
"job_engsec_low" = job_engsec_low,
"job_karma_high" = job_karma_high,
"job_karma_med" = job_karma_med,
"job_karma_low" = job_karma_low,
"flavor_text" = flavor_text,
"med_record" = med_record,
"sec_record" = sec_record,
"gen_record" = gen_record,
"playertitlelist" = (playertitlelist ? playertitlelist : ""), // This it intentnional. It wont work without it!
"disabilities" = disabilities,
"organlist" = (organlist ? organlist : ""),
"rlimblist" = (rlimblist ? rlimblist : ""),
"nanotrasen_relation" = nanotrasen_relation,
"speciesprefs" = speciesprefs,
"socks" = socks,
"body_accessory" = (body_accessory ? body_accessory : ""),
"gearlist" = (gearlist ? gearlist : ""),
"autohiss_mode" = autohiss_mode
))
if(!query.warn_execute())
qdel(query)
return
qdel(query)
saved = TRUE
return 1
/datum/preferences/proc/load_random_character_slot(client/C)
var/datum/db_query/query = SSdbcore.NewQuery("SELECT slot FROM characters WHERE ckey=:ckey ORDER BY slot", list(
"ckey" = C.ckey
))
var/list/saves = list()
var/list/datum/character_save/valid_slots = list()
for(var/datum/character_save/CS in character_saves)
if(CS.valid_save)
valid_slots += CS
if(!query.warn_execute(async = FALSE)) // Dont async this. Youll make roundstart slow.
qdel(query)
if(!length(valid_slots))
// They have no valid saves. Lets just randomise #1
var/datum/character_save/CS = C.prefs.character_saves[1] // Get slot 1
CS.randomise()
CS.real_name = random_name(CS.gender) // Pick a name
C.prefs.active_character = C.prefs.character_saves[1] // Set slot 1 as their active
return
while(query.NextRow())
saves += text2num(query.item[1])
qdel(query)
if(!saves.len)
load_character(C)
return 0
load_character(C,pick(saves))
return 1
/datum/preferences/proc/clear_character_slot(client/C)
. = FALSE
// Is there a character in that slot?
var/datum/db_query/query = SSdbcore.NewQuery("SELECT slot FROM characters WHERE ckey=:ckey AND slot=:slot", list(
"ckey" = C.ckey,
"slot" = default_slot
))
if(!query.warn_execute())
qdel(query)
return
if(!query.NextRow())
qdel(query)
return
qdel(query)
var/datum/db_query/delete_query = SSdbcore.NewQuery("DELETE FROM characters WHERE ckey=:ckey AND slot=:slot", list(
"ckey" = C.ckey,
"slot" = default_slot
))
if(!delete_query.warn_execute())
qdel(delete_query)
return
qdel(delete_query)
saved = FALSE
return TRUE
var/datum/character_save/CS = pick(valid_slots)
C.prefs.active_character = CS
/**
* Saves [/datum/preferences/proc/volume_mixer] for the current client.
@@ -347,7 +347,7 @@
set desc = "Toggles forcing your runechat colour to white"
prefs.toggles2 ^= PREFTOGGLE_2_FORCE_WHITE_RUNECHAT
prefs.save_preferences(src)
to_chat(src, "Your runechats will [(prefs.toggles2 & PREFTOGGLE_2_FORCE_WHITE_RUNECHAT) ? "no longer" : "now"] be forced to be white.")
to_chat(src, "Your runechats will [(prefs.toggles2 & PREFTOGGLE_2_FORCE_WHITE_RUNECHAT) ? "now" : "no longer"] be forced to be white.")
/client/verb/toggle_simple_stat_panel()
set name = "Toggle Simple Status Panel"
@@ -356,3 +356,11 @@
prefs.toggles2 ^= PREFTOGGLE_2_SIMPLE_STAT_PANEL
prefs.save_preferences(src)
to_chat(src, "You will [(prefs.toggles2 & PREFTOGGLE_2_SIMPLE_STAT_PANEL) ? "no longer" : "now"] get detailed information on the status panel.")
/client/verb/toggle_item_outlines()
set name = "Toggle Item Outlines"
set category = "Preferences"
set desc = "Toggles seeing item outlines on hover."
prefs.toggles2 ^= PREFTOGGLE_2_SEE_ITEM_OUTLINES
prefs.save_preferences(src)
to_chat(usr, "You will [(prefs.toggles2 & PREFTOGGLE_2_SEE_ITEM_OUTLINES) ? "now" : "no longer"] see item outlines on hover.")