Merge branch 'master' of https://github.com/ParadiseSS13/Paradise into HonkCrystalNuking

This commit is contained in:
Sirryan2002
2021-09-22 01:20:09 -04:00
122 changed files with 5159 additions and 4247 deletions
+1 -1
View File
@@ -130,7 +130,7 @@ GLOBAL_VAR_INIT(nologevent, 0)
if(GLOB.configuration.url.forum_playerinfo_url)
body += "<A href='?_src_=holder;webtools=[M.ckey]'>WebInfo</A> | "
if(M.client)
if(check_watchlist(M.client.ckey))
if(M.client.watchlisted)
body += "<A href='?_src_=holder;watchremove=[M.ckey]'>Remove from Watchlist</A> | "
body += "<A href='?_src_=holder;watchedit=[M.ckey]'>Edit Watchlist Reason</A> "
else
+18
View File
@@ -95,6 +95,24 @@ you will have to do something like if(client.holder.rights & R_ADMIN) yourself.
to_chat(user, "<font color='red'>Error: You are not an admin.</font>")
return 0
// Basically the above proc but checks at a /client level
/proc/check_rights_client(rights_required, show_msg = TRUE, client/C)
if(C)
if(rights_required)
if(C.holder)
if(rights_required & C.holder.rights)
return TRUE
else
if(show_msg)
to_chat(C, "<font color='red'>Error: You do not have sufficient rights to do that. You require one of the following flags:[rights2text(rights_required," ")].</font>")
else
if(C.holder)
return TRUE
else
if(show_msg)
to_chat(C, "<font color='red'>Error: You are not an admin.</font>")
return FALSE
//probably a bit iffy - will hopefully figure out a better solution
/proc/check_if_greater_rights_than(client/other)
if(usr && usr.client)
+6 -6
View File
@@ -1361,7 +1361,7 @@
to_chat(usr, "<span class='warning'>[M] doesn't seem to have an active client.</span>")
return
if(M.flavor_text == "" && M.client.prefs.flavor_text == "")
if(M.flavor_text == "" && M.client.prefs.active_character.flavor_text == "")
to_chat(usr, "<span class='warning'>[M] has no flavor text set.</span>")
return
@@ -1375,8 +1375,8 @@
M.flavor_text = ""
// Clear and save the DB character's flavor text
M.client.prefs.flavor_text = ""
M.client.prefs.save_character(M.client)
M.client.prefs.active_character.flavor_text = ""
M.client.prefs.active_character.save(M.client)
else if(href_list["userandomname"])
if(!check_rights(R_ADMIN))
@@ -1399,12 +1399,12 @@
message_admins("[key_name_admin(usr)] has forced [key_name_admin(M)] to use a random name.")
// Update the mob's name with a random one straight away
var/random_name = random_name(M.client.prefs.gender, M.client.prefs.species)
var/random_name = random_name(M.client.prefs.active_character.gender, M.client.prefs.active_character.species)
M.rename_character(M.real_name, random_name)
// Save that random name for next rounds
M.client.prefs.real_name = random_name
M.client.prefs.save_character(M.client)
M.client.prefs.active_character.real_name = random_name
M.client.prefs.active_character.save(M.client)
else if(href_list["asays"])
if(!check_rights(R_ADMIN))
+4 -3
View File
@@ -63,9 +63,10 @@
for(var/mob/thisplayer in players_to_spawn)
var/mob/living/carbon/human/H = new /mob/living/carbon/human(T)
H.name = random_name(pick(MALE,FEMALE))
var/datum/preferences/A = new() //Randomize appearance
A.real_name = H.name
A.copy_to(H)
var/datum/character_save/S = new //Randomize appearance
S.randomise()
S.real_name = H.name
S.copy_to(H)
H.dna.ready_dna(H)
H.mind_initialize()
@@ -124,9 +124,10 @@ GLOBAL_VAR_INIT(sent_syndicate_infiltration_team, 0)
var/syndicate_infiltrator_name = random_name(pick(MALE,FEMALE))
var/datum/preferences/A = new() //Randomize appearance
A.real_name = syndicate_infiltrator_name
A.copy_to(new_syndicate_infiltrator)
var/datum/character_save/S = new //Randomize appearance
S.randomise()
S.real_name = syndicate_infiltrator_name
S.copy_to(new_syndicate_infiltrator)
new_syndicate_infiltrator.dna.ready_dna(new_syndicate_infiltrator)
//Creates mind stuff.
+13 -11
View File
@@ -32,7 +32,7 @@
if(M.stat || !M.mind || M.mind.special_role || M.mind.offstation_role)
return FALSE
if(temp)
if((M.mind.assigned_role in temp.restricted_jobs) || (M.client.prefs.species in temp.protected_species))
if((M.mind.assigned_role in temp.restricted_jobs) || (M.client.prefs.active_character.species in temp.protected_species))
return FALSE
if(role) // Don't even bother evaluating if there's no role
if(player_old_enough_antag(M.client,role) && (role in M.client.prefs.be_special) && !M.client.skip_antag && (!jobban_isbanned(M, role)))
@@ -374,8 +374,8 @@
//First we spawn a dude.
var/mob/living/carbon/human/new_character = new(pick(GLOB.latejoin))//The mob being spawned.
var/datum/preferences/A = new(G_found.client)
A.copy_to(new_character)
// Then clone stuff over
G_found.client.prefs.active_character.copy_to(new_character)
new_character.dna.ready_dna(new_character)
new_character.key = G_found.key
@@ -388,13 +388,14 @@
var/syndicate_commando_rank = pick("Corporal", "Sergeant", "Staff Sergeant", "Sergeant 1st Class", "Master Sergeant", "Sergeant Major")
var/syndicate_commando_name = pick(GLOB.last_names)
var/datum/preferences/A = new()//Randomize appearance for the commando.
var/datum/character_save/S = new //Randomize appearance for the commando.
S.randomise()
if(syndicate_leader_selected)
A.real_name = "[syndicate_commando_leader_rank] [syndicate_commando_name]"
A.age = rand(35,45)
S.real_name = "[syndicate_commando_leader_rank] [syndicate_commando_name]"
S.age = rand(35, 45)
else
A.real_name = "[syndicate_commando_rank] [syndicate_commando_name]"
A.copy_to(new_syndicate_commando)
S.real_name = "[syndicate_commando_rank] [syndicate_commando_name]"
S.copy_to(new_syndicate_commando)
new_syndicate_commando.dna.ready_dna(new_syndicate_commando)//Creates DNA.
@@ -576,7 +577,8 @@
if(candidates.len)
var/teamOneMembers = 5
var/teamTwoMembers = 5
var/datum/preferences/A = new()
var/datum/character_save/S = new
S.randomise()
for(var/thing in GLOB.landmarks_list)
var/obj/effect/landmark/L = thing
if(L.name == "tdome1")
@@ -585,7 +587,7 @@
var/mob/living/carbon/human/newMember = new(L.loc)
A.copy_to(newMember)
S.copy_to(newMember)
newMember.dna.ready_dna(newMember)
@@ -607,7 +609,7 @@
var/mob/living/carbon/human/newMember = new(L.loc)
A.copy_to(newMember)
S.copy_to(newMember)
newMember.dna.ready_dna(newMember)
+3 -2
View File
@@ -11,8 +11,9 @@
continue
if(is_type_in_list(H.dna.species, incompatible_species))
H.set_species(/datum/species/human)
var/datum/preferences/A = new() // Randomize appearance
A.copy_to(H)
var/datum/character_save/S = new // Randomize appearance
S.randomise()
S.copy_to(H)
SSticker.mode.traitors += H.mind
H.mind.special_role = SPECIAL_ROLE_TRAITOR
+3 -2
View File
@@ -12,8 +12,9 @@
continue
if(is_type_in_list(H.dna.species, incompatible_species))
H.set_species(/datum/species/human)
var/datum/preferences/A = new() // Randomize appearance
A.copy_to(H)
var/datum/character_save/S = new // Randomize appearance
S.randomise()
S.copy_to(H)
for(var/obj/item/I in H)
if(istype(I, /obj/item/implant))
+5 -3
View File
@@ -396,10 +396,12 @@ Traitors and the like can also be revived with the previous role mostly intact.
new_character.age = record_found.fields["age"]
new_character.dna.blood_type = record_found.fields["blood_type"]
else
// We make a random character
new_character.change_gender(pick(MALE,FEMALE))
var/datum/preferences/A = new()
A.real_name = G_found.real_name
A.copy_to(new_character)
var/datum/character_save/S = new
S.randomise()
S.real_name = G_found.real_name
S.copy_to(new_character)
if(!new_character.real_name)
new_character.real_name = random_name(new_character.gender)
+6 -5
View File
@@ -138,13 +138,14 @@ GLOBAL_VAR_INIT(sent_strike_team, 0)
var/commando_leader_rank = pick("Lieutenant", "Captain", "Major")
var/commando_name = pick(GLOB.commando_names)
var/datum/preferences/A = new()//Randomize appearance for the commando.
var/datum/character_save/S = new //Randomize appearance for the commando.
S.randomise()
if(is_leader)
A.age = rand(35,45)
A.real_name = "[commando_leader_rank] [commando_name]"
S.age = rand(35, 45)
S.real_name = "[commando_leader_rank] [commando_name]"
else
A.real_name = "[commando_name]"
A.copy_to(new_commando)
S.real_name = "[commando_name]"
S.copy_to(new_commando)
new_commando.dna.ready_dna(new_commando)//Creates DNA.
@@ -104,13 +104,14 @@ GLOBAL_VAR_INIT(sent_syndicate_strike_team, 0)
var/syndicate_commando_rank = pick("Corporal", "Sergeant", "Staff Sergeant", "Sergeant 1st Class", "Master Sergeant", "Sergeant Major")
var/syndicate_commando_name = pick(GLOB.last_names)
var/datum/preferences/A = new()//Randomize appearance for the commando.
var/datum/character_save/S = new //Randomize appearance for the commando.
S.randomise()
if(is_leader)
A.age = rand(35,45)
A.real_name = "[syndicate_commando_leader_rank] [syndicate_commando_name]"
S.age = rand(35, 45)
S.real_name = "[syndicate_commando_leader_rank] [syndicate_commando_name]"
else
A.real_name = "[syndicate_commando_rank] [syndicate_commando_name]"
A.copy_to(new_syndicate_commando)
S.real_name = "[syndicate_commando_rank] [syndicate_commando_name]"
S.copy_to(new_syndicate_commando)
new_syndicate_commando.dna.ready_dna(new_syndicate_commando)//Creates DNA.
+14 -16
View File
@@ -16,8 +16,21 @@
qdel(query_watchfind)
return
else
qdel(query_watchfind)
target_ckey = new_ckey
if(check_watchlist(target_ckey))
var/already_watched = FALSE
var/datum/db_query/query_watch = SSdbcore.NewQuery("SELECT reason FROM watch WHERE ckey=:target_ckey", list(
"target_ckey" = target_ckey
))
if(!query_watch.warn_execute())
qdel(query_watch)
return
if(query_watch.NextRow())
already_watched = TRUE
qdel(query_watch)
if(already_watched)
to_chat(usr, "<span class='redtext'>[target_ckey] is already on the watchlist.</span>")
return
var/reason = input(usr,"Please state the reason","Reason") as message|null
@@ -132,18 +145,3 @@
output += "<br>[reason]<hr style='background:#000000; border:0; height:1px'>"
usr << browse(output, "window=watchwin;size=900x500")
qdel(query_watchlist)
/proc/check_watchlist(target_ckey)
var/datum/db_query/query_watch = SSdbcore.NewQuery("SELECT reason FROM watch WHERE ckey=:target_ckey", list(
"target_ckey" = target_ckey
))
if(!query_watch.warn_execute())
qdel(query_watch)
return
if(query_watch.NextRow())
var/entry = query_watch.item[1]
qdel(query_watch)
return entry
else
qdel(query_watch)
return 0
+6
View File
@@ -251,6 +251,12 @@ GLOBAL_DATUM_INIT(global_prizes, /datum/prizes, new())
typepath = /obj/item/toy/foamblade
cost = 100
/datum/prize_item/wind_up_toolbox
name = "Wind Up Toolbox"
desc = "A replica toolbox that rumbles when you turn the key."
typepath = /obj/item/toy/windup_toolbox
cost = 100
/datum/prize_item/redbutton
name = "Shiny Red Button"
desc = "PRESS IT!"
+48 -209
View File
@@ -268,8 +268,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 +278,53 @@
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
// 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 has to go here to avoid issues
// If you sleep past this point, you will get SSinput errors as well as goonchat errors
@@ -320,7 +348,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 +359,6 @@
if(SSinput.initialized)
set_macros()
donator_check()
check_ip_intel()
send_resources()
@@ -383,8 +409,6 @@
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.")
@@ -420,52 +444,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())
@@ -480,67 +470,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='#EB4E00'>[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,
@@ -550,6 +502,7 @@
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
@@ -565,7 +518,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
@@ -1051,7 +1004,7 @@
qdel(query_date)
// They have a date, lets bail
// They have a date already, lets bail
if(byondacc_date)
return
@@ -1092,120 +1045,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,102 @@
/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
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,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
@@ -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,550 +98,23 @@
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)
if(!C) // If the client disconnected during the query, try again later.
qdel(src)
return TRUE
// 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
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])
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))
// 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
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,
"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.
+4
View File
@@ -428,6 +428,10 @@ BLIND // can't see anything
var/datum/action/A = X
A.UpdateButtonIcon()
// Changes the speech verb when wearing a mask if a value is returned
/obj/item/clothing/mask/proc/change_speech_verb()
return
//Shoes
/obj/item/clothing/shoes
name = "shoes"
+5 -1
View File
@@ -313,7 +313,7 @@
flags = BLOCKHAIR
flags_inv = HIDEFACE
w_class = WEIGHT_CLASS_SMALL
var/voicechange = 0
var/voicechange = FALSE
var/temporaryname = " the Horse"
var/originalname = ""
@@ -347,6 +347,10 @@
if(user.real_name == "[originalname][temporaryname]" || user.real_name == "A Horse With No Name") //if it's somehow changed while the mask is on it doesn't revert
user.real_name = originalname
/obj/item/clothing/mask/horsehead/change_speech_verb()
if(voicechange)
return pick("whinnies", "neighs", "says")
/obj/item/clothing/mask/face
flags_inv = HIDEFACE
flags_cover = MASKCOVERSMOUTH
@@ -0,0 +1,44 @@
/obj/item/clothing/mask/gas/voice_modulator
name = "modified gas mask"
desc = "A gas mask modified with a sound modulator that disguises the user's voice when active"
icon_state = "voice_modulator"
item_state = "voice_modulator"
var/obj/item/voice_changer/voice_modulator/voice_modulator
/obj/item/clothing/mask/gas/voice_modulator/Initialize(mapload)
. = ..()
voice_modulator = new(src)
/obj/item/clothing/mask/gas/voice_modulator/Destroy()
QDEL_NULL(voice_modulator)
return ..()
/obj/item/clothing/mask/gas/voice_modulator/chameleon
name = "chameleon voice modulator mask"
desc = "A tactical mask equipped with chameleon technology and a sound modulator that disguises the user's voice when active"
icon_state = "swat"
item_state = "swat"
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/clothing/mask/gas/voice_modulator/chameleon/Initialize(mapload)
. = ..()
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/clothing/mask
chameleon_action.chameleon_name = "Mask"
chameleon_action.chameleon_blacklist = list()
chameleon_action.initialize_disguises()
/obj/item/clothing/mask/gas/voice_modulator/chameleon/Destroy()
QDEL_NULL(chameleon_action)
return ..()
/obj/item/clothing/mask/gas/voice_modulator/chameleon/emp_act(severity)
. = ..()
chameleon_action.emp_randomise()
/obj/item/clothing/mask/gas/voice_modulator/change_speech_verb()
if(voice_modulator.active)
return pick("modulates", "drones", "hums", "buzzes")
+10
View File
@@ -162,3 +162,13 @@
tools = list(TOOL_WIRECUTTER)
pathtools = list(/obj/item/kitchen/knife)
category = CAT_CLOTHING
/datum/crafting_recipe/voice_modulator
name = "Voice Modulator Mask"
result = list(/obj/item/clothing/mask/gas/voice_modulator)
time = 45
tools = list(TOOL_SCREWDRIVER, TOOL_MULTITOOL)
reqs = list(/obj/item/clothing/mask/gas = 1,
/obj/item/assembly/voice = 1,
/obj/item/stack/cable_coil = 5)
category = CAT_CLOTHING
@@ -323,7 +323,7 @@
/obj/item/lava_staff,
/obj/item/katana/energy,
/obj/item/hierophant_club,
/obj/item/storage/toolbox/green/memetic,
/obj/item/his_grace,
/obj/item/gun/projectile/automatic/l6_saw,
/obj/item/gun/magic/staff/chaos,
/obj/item/gun/magic/staff/spellblade,
+1 -1
View File
@@ -743,7 +743,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
return
var/mob/living/carbon/human/new_char = new(get_turf(src))
client.prefs.copy_to(new_char)
client.prefs.active_character.copy_to(new_char)
if(mind)
mind.active = TRUE
mind.transfer_to(new_char)
+6 -6
View File
@@ -2,17 +2,17 @@
return message // no autohiss at this level
/mob/living/carbon/human/handle_autohiss(message, datum/language/L)
if(!client || client.prefs.autohiss_mode == AUTOHISS_OFF) // no need to process if there's no client or they have autohiss off
if(!client || client.prefs.active_character.autohiss_mode == AUTOHISS_OFF) // no need to process if there's no client or they have autohiss off
return message
return dna.species.handle_autohiss(message, L, client.prefs.autohiss_mode)
return dna.species.handle_autohiss(message, L, client.prefs.active_character.autohiss_mode)
/client/verb/toggle_autohiss()
set name = "Toggle Auto-Accent"
set desc = "Toggle automatic accents for your species"
set category = "OOC"
prefs.autohiss_mode = (prefs.autohiss_mode + 1) % AUTOHISS_NUM
switch(prefs.autohiss_mode)
prefs.active_character.autohiss_mode = (prefs.active_character.autohiss_mode + 1) % AUTOHISS_NUM
switch(prefs.active_character.autohiss_mode)
if(AUTOHISS_OFF)
to_chat(src, "Auto-hiss is now OFF.")
if(AUTOHISS_BASIC)
@@ -20,7 +20,7 @@
if(AUTOHISS_FULL)
to_chat(src, "Auto-hiss is now FULL.")
else
prefs.autohiss_mode = AUTOHISS_OFF
prefs.active_character.autohiss_mode = AUTOHISS_OFF
to_chat(src, "Auto-hiss is now OFF.")
/datum/species
@@ -61,7 +61,7 @@
/datum/species/drask
autohiss_basic_map = list(
"o" = list ("oo", "ooo"),
"u" = list ("uu", "uuu")
"u" = list ("uu", "uuu")
)
autohiss_extra_map = list(
"m" = list ("mm", "mmm")
@@ -1955,7 +1955,7 @@ Eyes need to have significantly high darksight to shine unless the mob has the X
if(GLOB.configuration.general.allow_character_metadata)
if(client)
to_chat(usr, "[src]'s Metainfo:<br>[sanitize(client.prefs.metadata)]")
to_chat(usr, "[src]'s Metainfo:<br>[sanitize(client.prefs.active_character.metadata)]")
else
to_chat(usr, "[src] does not have any stored infomation!")
else
+6 -1
View File
@@ -149,7 +149,6 @@
var/obj/item/clothing/mask/horsehead/hoers = wear_mask
if(hoers.voicechange)
S.message = pick("NEEIIGGGHHHH!", "NEEEIIIIGHH!", "NEIIIGGHH!", "HAAWWWWW!", "HAAAWWW!")
verb = pick("whinnies", "neighs", "says")
if(dna)
for(var/mutation_type in active_mutations)
@@ -167,6 +166,12 @@
if(span)
S.message = "<span class='[span]'>[S.message]</span>"
if(wear_mask)
var/speech_verb_when_masked = wear_mask.change_speech_verb()
if(speech_verb_when_masked)
verb = speech_verb_when_masked
return list("verb" = verb)
/mob/living/carbon/human/handle_message_mode(message_mode, list/message_pieces, verb, used_radios)
@@ -67,7 +67,7 @@
to_chat(H, "<span class='warning'>The water stings[volume < 10 ? " you, but isn't concentrated enough to harm you" : null]!</span>")
/datum/species/grey/after_equip_job(datum/job/J, mob/living/carbon/human/H)
var/translator_pref = H.client.prefs.speciesprefs
var/translator_pref = H.client.prefs.active_character.speciesprefs
if(translator_pref || ((ismindshielded(H) || J.is_command || J.supervisors == "the captain") && HAS_TRAIT(H, TRAIT_WINGDINGS)))
if(J.title == "Mime")
return
@@ -81,7 +81,7 @@
H.unEquip(H.wear_mask)
H.equip_or_collect(new /obj/item/clothing/mask/breath/vox(H), slot_wear_mask)
var/tank_pref = H.client && H.client.prefs ? H.client.prefs.speciesprefs : null
var/tank_pref = H.client && H.client.prefs ? H.client.prefs.active_character.speciesprefs : null
var/obj/item/tank/internal_tank
if(tank_pref)//Diseasel, here you go
internal_tank = new /obj/item/tank/internals/nitrogen(H)
+2 -21
View File
@@ -300,7 +300,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
/mob/living/silicon/robot/proc/pick_module()
if(module)
return
var/list/modules = list("Generalist", "Engineering", "Medical", "Miner", "Janitor", "Service", "Security")
var/list/modules = list("Engineering", "Medical", "Miner", "Janitor", "Service")
if(islist(force_modules) && force_modules.len)
modules = force_modules.Copy()
if(mmi != null && mmi.alien)
@@ -315,14 +315,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
return
switch(modtype)
if("Generalist")
module = new /obj/item/robot_module/standard(src)
module.channels = list("Engineering" = 1, "Medical" = 1, "Security" = 1, "Service" = 1, "Supply" = 1)
module_sprites["Basic"] = "robot_old"
module_sprites["Android"] = "droid"
module_sprites["Default"] = "Standard"
module_sprites["Noble-STD"] = "Noble-STD"
if("Service")
module = new /obj/item/robot_module/butler(src)
module.channels = list("Service" = 1)
@@ -365,17 +357,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
see_reagents = TRUE
if("Security")
if(!weapons_unlock)
var/count_secborgs = 0
for(var/mob/living/silicon/robot/R in GLOB.alive_mob_list)
if(R && R.stat != DEAD && R.module && istype(R.module, /obj/item/robot_module/security))
count_secborgs++
var/max_secborgs = 2
if(GLOB.security_level == SEC_LEVEL_GREEN)
max_secborgs = 1
if(count_secborgs >= max_secborgs)
to_chat(src, "<span class='warning'>There are too many Security cyborgs active. Please choose another module.</span>")
return
module = new /obj/item/robot_module/security(src)
module.channels = list("Security" = 1)
module_sprites["Basic"] = "secborg"
@@ -1349,7 +1330,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
scrambledcodes = 1
req_one_access = list(ACCESS_CENT_SPECOPS)
ionpulse = 1
force_modules = list("Engineering", "Medical", "Security")
force_modules = list("Engineering", "Medical")
static_radio_channels = 1
allow_rename = FALSE
weapons_unlock = TRUE
@@ -265,47 +265,6 @@
/obj/item/robot_module/proc/handle_death(mob/living/silicon/robot/R, gibbed)
return
// Standard cyborg module.
/obj/item/robot_module/standard
// if station is fine, assist with constructing station goal room, cleaning, and repairing cables chewed by rats
// if medical crisis, assist by providing basic healthcare, retrieving corpses, and monitoring crew lifesigns
// if eng crisis, assist by helping repair hull breaches
// if sec crisis, assist by opening doors for sec and providing backup zipties on patrols
name = "generalist robot module"
module_type = "Standard"
subsystems = list(/mob/living/silicon/proc/subsystem_power_monitor, /mob/living/silicon/proc/subsystem_crew_monitor)
basic_modules = list(
// sec
/obj/item/flash/cyborg,
/obj/item/restraints/handcuffs/cable/zipties/cyborg,
// janitorial
/obj/item/soap/nanotrasen,
/obj/item/lightreplacer/cyborg,
// eng
/obj/item/crowbar/cyborg,
/obj/item/wrench/cyborg,
/obj/item/extinguisher, // for firefighting, and propulsion in space
/obj/item/weldingtool/largetank/cyborg,
// mining
/obj/item/pickaxe,
/obj/item/t_scanner/adv_mining_scanner,
/obj/item/storage/bag/ore/cyborg,
// med
/obj/item/healthanalyzer,
/obj/item/reagent_containers/borghypo/basic,
/obj/item/roller_holder, // for taking the injured to medbay without worsening their injuries or leaving a blood trail the whole way
/obj/item/stack/sheet/metal/cyborg,
/obj/item/stack/cable_coil/cyborg,
/obj/item/stack/rods/cyborg,
/obj/item/stack/tile/plasteel/cyborg
)
emag_modules = list(/obj/item/melee/energy/sword/cyborg)
special_rechargables = list(
/obj/item/extinguisher,
/obj/item/weldingtool/largetank/cyborg,
/obj/item/lightreplacer/cyborg
)
// Medical cyborg module.
/obj/item/robot_module/medical
name = "medical robot module"
@@ -319,6 +278,7 @@
/obj/item/borg_defib,
/obj/item/handheld_defibrillator,
/obj/item/roller_holder,
/obj/item/borg/cyborghug,
/obj/item/reagent_containers/borghypo,
/obj/item/scalpel/laser/laser1,
/obj/item/hemostat,
@@ -214,7 +214,7 @@
var/list/allowed_toolbox = list(/obj/item/storage/toolbox/emergency, //which toolboxes can be made into floorbots
/obj/item/storage/toolbox/electrical,
/obj/item/storage/toolbox/mechanical,
/obj/item/storage/toolbox/green,
/obj/item/storage/toolbox/artistic,
/obj/item/storage/toolbox/syndicate,
/obj/item/storage/toolbox/fakesyndi)
@@ -223,8 +223,6 @@
return
if(!is_type_in_list(src, allowed_toolbox))
return
if(type == /obj/item/storage/toolbox/green/memetic)
return
if(contents.len >= 1)
to_chat(user, "<span class='warning'>They won't fit in, as there is already stuff inside.</span>")
return
@@ -242,7 +240,7 @@
B.toolbox_color = "or"
if(/obj/item/storage/toolbox/electrical)
B.toolbox_color = "y"
if(/obj/item/storage/toolbox/green)
if(/obj/item/storage/toolbox/artistic)
B.toolbox_color = "g"
if(/obj/item/storage/toolbox/syndicate)
B.toolbox_color = "s"
@@ -69,7 +69,7 @@ Difficulty: Medium
ranged_cooldown = world.time + ranged_cooldown_time
else
visible_message("<span class='warning'><b>[src] charges!</b></span>")
SpinAnimation(speed = 20, loops = 5)
SpinAnimation(speed = 20, loops = 5, parallel = FALSE)
ranged = 0
retreat_distance = 0
minimum_distance = 0
+4 -6
View File
@@ -365,9 +365,6 @@
// STUN
/mob/living/Stun(amount, updating = 1, force = 0)
if(status_flags & CANSTUN || force)
if(absorb_stun(amount, force))
return FALSE
return SetStunned(max(stunned, amount), updating, force)
/mob/living/SetStunned(amount, updating = 1, force = 0) //if you REALLY need to set stun to a set amount without the whole "can't go below current stunned"
@@ -377,6 +374,8 @@
. = STATUS_UPDATE_NONE
if(status_flags & CANSTUN || force)
if(absorb_stun(amount, force))
return STATUS_UPDATE_NONE
stunned = max(amount, 0)
if(updating)
update_canmove()
@@ -405,9 +404,6 @@
// WEAKEN
/mob/living/Weaken(amount, updating = 1, force = 0)
if(status_flags & CANWEAKEN || force)
if(absorb_stun(amount, force))
return FALSE
return SetWeakened(max(weakened, amount), updating, force)
/mob/living/SetWeakened(amount, updating = 1, force = 0)
@@ -416,6 +412,8 @@
updating = FALSE
. = STATUS_UPDATE_NONE
if(status_flags & CANWEAKEN || force)
if(absorb_stun(amount, force))
return STATUS_UPDATE_NONE
weakened = max(amount, 0)
if(updating)
update_canmove() //updates lying, canmove and icons
+2 -2
View File
@@ -684,13 +684,13 @@ GLOBAL_LIST_INIT(intents, list(INTENT_HELP,INTENT_DISARM,INTENT_GRAB,INTENT_HARM
/mob/proc/has_valid_preferences()
if(!client)
return FALSE //Not sure how this would get run without the mob having a client, but let's just be safe.
if(client.prefs.alternate_option != RETURN_TO_LOBBY)
if(client.prefs.active_character.alternate_option != RETURN_TO_LOBBY)
return TRUE
// If they have antags enabled, they're potentially doing this on purpose instead of by accident. Notify admins if so.
var/has_antags = FALSE
if(client.prefs.be_special.len > 0)
has_antags = TRUE
if(!client.prefs.check_any_job())
if(!client.prefs.active_character.check_any_job())
to_chat(src, "<span class='danger'>You have no jobs enabled, along with return to lobby if job is unavailable. This makes you ineligible for any round start role, please update your job preferences.</span>")
if(has_antags)
log_admin("[src.ckey] just got booted back to lobby with no jobs, but antags enabled.")
+26 -26
View File
@@ -42,7 +42,7 @@
/mob/new_player/proc/new_player_panel_proc()
var/real_name = client.prefs.real_name
var/real_name = client.prefs.active_character.real_name
if(client.prefs.toggles2 & PREFTOGGLE_2_RANDOMSLOT)
real_name = "Random Character Slot"
var/output = "<center><p><a href='byond://?src=[UID()];show_preferences=1'>Setup Character</A><br /><i>[real_name]</i></p>"
@@ -184,13 +184,13 @@
to_chat(src, "<span class='notice'>Now teleporting.</span>")
observer.forceMove(O.loc)
observer.timeofdeath = world.time // Set the time of death so that the respawn timer works correctly.
client.prefs.update_preview_icon(1)
observer.icon = client.prefs.preview_icon
client.prefs.active_character.update_preview_icon(1)
observer.icon = client.prefs.active_character.preview_icon
observer.alpha = 127
if(client.prefs.be_random_name)
client.prefs.real_name = random_name(client.prefs.gender,client.prefs.species)
observer.real_name = client.prefs.real_name
if(client.prefs.active_character.be_random_name)
client.prefs.active_character.real_name = random_name(client.prefs.active_character.gender,client.prefs.active_character.species)
observer.real_name = client.prefs.active_character.real_name
observer.name = observer.real_name
observer.key = key
QDEL_NULL(mind)
@@ -212,10 +212,10 @@
if(!SSticker || SSticker.current_state != GAME_STATE_PLAYING)
to_chat(usr, "<span class='warning'>The round is either not ready, or has already finished...</span>")
return
if(client.prefs.species in GLOB.whitelisted_species)
if(client.prefs.active_character.species in GLOB.whitelisted_species)
if(!is_alien_whitelisted(src, client.prefs.species))
to_chat(src, alert("You are currently not whitelisted to play [client.prefs.species]."))
if(!is_alien_whitelisted(src, client.prefs.active_character.species))
to_chat(src, alert("You are currently not whitelisted to play [client.prefs.active_character.species]."))
return FALSE
LateChoices()
@@ -232,12 +232,12 @@
if(client.prefs.toggles2 & PREFTOGGLE_2_RANDOMSLOT)
client.prefs.load_random_character_slot(client)
if(client.prefs.species in GLOB.whitelisted_species)
if(!is_alien_whitelisted(src, client.prefs.species))
to_chat(src, alert("You are currently not whitelisted to play [client.prefs.species]."))
if(client.prefs.active_character.species in GLOB.whitelisted_species)
if(!is_alien_whitelisted(src, client.prefs.active_character.species))
to_chat(src, alert("You are currently not whitelisted to play [client.prefs.active_character.species]."))
return FALSE
AttemptLateSpawn(href_list["SelectedJob"],client.prefs.spawnpoint)
AttemptLateSpawn(href_list["SelectedJob"],client.prefs.active_character.spawnpoint)
return
if(!ready && href_list["preference"])
@@ -543,9 +543,9 @@
new_character.lastarea = get_area(loc)
if(SSticker.random_players || appearance_isbanned(new_character))
client.prefs.random_character()
client.prefs.real_name = random_name(client.prefs.gender)
client.prefs.copy_to(new_character)
client.prefs.active_character.randomise()
client.prefs.active_character.real_name = random_name(client.prefs.active_character.gender)
client.prefs.active_character.copy_to(new_character)
stop_sound_channel(CHANNEL_LOBBYMUSIC)
@@ -569,19 +569,19 @@
// This is to check that the player only has preferences set that they're supposed to
/mob/new_player/proc/check_prefs_are_sane()
var/datum/species/chosen_species
if(client.prefs.species)
chosen_species = GLOB.all_species[client.prefs.species]
if(client.prefs.active_character.species)
chosen_species = GLOB.all_species[client.prefs.active_character.species]
if(!(chosen_species && (is_species_whitelisted(chosen_species) || has_admin_rights())))
// Have to recheck admin due to no usr at roundstart. Latejoins are fine though.
log_runtime(EXCEPTION("[src] had species [client.prefs.species], though they weren't supposed to. Setting to Human."), src)
client.prefs.species = "Human"
log_runtime(EXCEPTION("[src] had species [client.prefs.active_character.species], though they weren't supposed to. Setting to Human."), src)
client.prefs.active_character.species = "Human"
var/datum/language/chosen_language
if(client.prefs.language)
chosen_language = GLOB.all_languages[client.prefs.language]
if((chosen_language == null && client.prefs.language != "None") || (chosen_language && chosen_language.flags & RESTRICTED))
log_runtime(EXCEPTION("[src] had language [client.prefs.language], though they weren't supposed to. Setting to None."), src)
client.prefs.language = "None"
if(client.prefs.active_character.language)
chosen_language = GLOB.all_languages[client.prefs.active_character.language]
if((chosen_language == null && client.prefs.active_character.language != "None") || (chosen_language && chosen_language.flags & RESTRICTED))
log_runtime(EXCEPTION("[src] had language [client.prefs.active_character.language], though they weren't supposed to. Setting to None."), src)
client.prefs.active_character.language = "None"
/mob/new_player/proc/ViewManifest()
GLOB.generic_crew_manifest.ui_interact(usr, state = GLOB.always_state)
@@ -607,7 +607,7 @@
/mob/new_player/get_gender()
if(!client || !client.prefs) ..()
return client.prefs.gender
return client.prefs.active_character.gender
/mob/new_player/is_ready()
return ready && ..()
Regular → Executable
View File
@@ -110,7 +110,7 @@
/obj/item/ammo_box/magazine/internal/shot/com
name = "combat shotgun internal magazine"
ammo_type = /obj/item/ammo_casing/shotgun/buckshot
ammo_type = /obj/item/ammo_casing/shotgun/beanbag
max_ammo = 6
/obj/item/ammo_box/magazine/internal/shot/dual
@@ -133,9 +133,6 @@
/obj/item/ammo_box/magazine/internal/shot/riot/short
max_ammo = 3
/obj/item/ammo_box/magazine/internal/shot/riot/buckshot
ammo_type = /obj/item/ammo_casing/shotgun/buckshot
/obj/item/ammo_box/magazine/internal/grenadelauncher
name = "grenade launcher internal magazine"
ammo_type = /obj/item/ammo_casing/a40mm
+1 -1
View File
@@ -403,7 +403,7 @@
return TRUE
/obj/item/gun/extinguish_light()
if(gun_light.on)
if(gun_light?.on)
toggle_gunlight()
visible_message("<span class='danger'>[src]'s light fades and turns off.</span>")
@@ -175,7 +175,7 @@
/obj/item/gun/projectile/automatic/m90/attackby(obj/item/A, mob/user, params)
if(istype(A, /obj/item/ammo_casing))
if(istype(A, underbarrel.magazine.ammo_type))
underbarrel.attack_self()
underbarrel.attack_self(user)
underbarrel.attackby(A, user, params)
else
return ..()
@@ -204,10 +204,6 @@
..()
post_sawoff()
/obj/item/gun/projectile/shotgun/riot/buckshot //comes pre-loaded with buckshot rather than rubber
mag_type = /obj/item/ammo_box/magazine/internal/shot/riot/buckshot
///////////////////////
// BOLT ACTION RIFLE //
///////////////////////
+4 -3
View File
@@ -267,9 +267,10 @@
if("human")
new_mob = new /mob/living/carbon/human(M.loc)
var/mob/living/carbon/human/H = new_mob
var/datum/preferences/A = new() //Randomize appearance for the human
A.species = get_random_species(TRUE)
A.copy_to(new_mob)
var/datum/character_save/S = new //Randomize appearance for the human
S.species = get_random_species(TRUE)
S.randomise()
S.copy_to(new_mob)
randomize = H.dna.species.name
else
return
@@ -1,5 +1,5 @@
/datum/reagent/spider_eggs
name = "spider eggs"
name = "Spider eggs"
id = "spidereggs"
description = "A fine dust containing spider eggs. Oh gosh."
reagent_state = SOLID
@@ -124,7 +124,7 @@
return ..()
/datum/reagent/bacon_grease
name = "pure bacon grease"
name = "Pure bacon grease"
id = "bacon_grease"
description = "Hook me up to an IV of that sweet, sweet stuff!"
reagent_state = LIQUID
@@ -185,30 +185,30 @@
taste_description = "watery milk"
/datum/reagent/mutagen/mutagenvirusfood
name = "mutagenic agar"
name = "Mutagenic agar"
id = "mutagenvirusfood"
description = "mutates blood"
color = "#A3C00F" // rgb: 163,192,15
/datum/reagent/mutagen/mutagenvirusfood/sugar
name = "sucrose agar"
name = "Sucrose agar"
id = "sugarvirusfood"
color = "#41B0C0" // rgb: 65,176,192
taste_mult = 1.5
/datum/reagent/medicine/diphenhydramine/diphenhydraminevirusfood
name = "virus rations"
name = "Virus rations"
id = "diphenhydraminevirusfood"
description = "mutates blood"
color = "#D18AA5" // rgb: 209,138,165
/datum/reagent/plasma_dust/plasmavirusfood
name = "virus plasma"
name = "Virus plasma"
id = "plasmavirusfood"
description = "mutates blood"
color = "#A69DA9" // rgb: 166,157,169
/datum/reagent/plasma_dust/plasmavirusfood/weak
name = "weakened virus plasma"
name = "Weakened virus plasma"
id = "weakplasmavirusfood"
color = "#CEC3C6" // rgb: 206,195,198
@@ -447,7 +447,7 @@
return ..()
/datum/reagent/consumable/flour
name = "flour"
name = "Flour"
id = "flour"
description = "This is what you rub all over yourself to pretend to be a ghost."
reagent_state = SOLID
@@ -852,7 +852,7 @@
return ..() | update_flags
/datum/reagent/cholesterol
name = "cholesterol"
name = "Cholesterol"
id = "cholesterol"
description = "Pure cholesterol. Probably not very good for you."
reagent_state = LIQUID
@@ -500,7 +500,7 @@
M.RemoveElement(/datum/element/waddling)
/datum/reagent/royal_bee_jelly
name = "royal bee jelly"
name = "Royal bee jelly"
id = "royal_bee_jelly"
description = "Royal Bee Jelly, if injected into a Queen Space Bee said bee will split into two bees."
color = "#00ff80"
@@ -1,5 +1,5 @@
/datum/reagent/phlogiston
name = "phlogiston"
name = "Phlogiston"
id = "phlogiston"
description = "It appears to be liquid fire."
reagent_state = LIQUID
@@ -36,7 +36,7 @@
return ..()
/datum/reagent/phlogiston/firedust
name = "phlogiston dust"
name = "Phlogiston dust"
id = "phlogiston_dust"
description = "And this is solid fire. However that works."
temp_fire = 1500
@@ -45,7 +45,7 @@
mob_burning = 3 // 15
/datum/reagent/napalm
name = "napalm"
name = "Napalm"
id = "napalm"
description = "A highly flammable jellied fuel."
reagent_state = LIQUID
@@ -199,7 +199,7 @@
/datum/reagent/stable_mutagen
name = "Stable mutagen"
id = "stable_mutagen"
description = "Just the regular, boring sort of mutagenic compound. Works in a completely predictable manner."
description = "Just the regular, boring sort of mutagenic compound. Works in a completely predictable manner."
reagent_state = LIQUID
color = "#7DFF00"
taste_description = "slime"
@@ -233,7 +233,7 @@
data = B.data.Copy()
/datum/reagent/uranium
name ="Uranium"
name = "Uranium"
id = "uranium"
description = "A silvery-white metallic chemical element in the actinide series, weakly radioactive."
reagent_state = SOLID
@@ -367,7 +367,7 @@
to_chat(H, "<span class='warning'>The blueish acidic substance stings[volume < 5 ? " you, but isn't concentrated enough to harm you" : null]!</span>")
/datum/reagent/acetic_acid
name = "acetic acid"
name = "Acetic acid"
id = "acetic_acid"
description = "A weak acid that is the main component of vinegar and bad hangovers."
color = "#0080ff"
@@ -703,22 +703,6 @@
build_path = /obj/item/weaponcrafting/receiver
category = list("hacked", "Security")
/datum/design/shotgun_slug
name = "Shotgun Slug"
id = "shotgun_slug"
build_type = AUTOLATHE
materials = list(MAT_METAL = 4000)
build_path = /obj/item/ammo_casing/shotgun
category = list("hacked", "Security")
/datum/design/buckshot_shell
name = "Buckshot shell"
id = "buckshot_shell"
build_type = AUTOLATHE
materials = list(MAT_METAL = 4000)
build_path = /obj/item/ammo_casing/shotgun/buckshot
category = list("hacked", "Security")
/datum/design/shotgun_dart
name = "Shotgun Dart"
id = "shotgun_dart"