From 4133e98dfeb3327ae636889612422d7246c0aac8 Mon Sep 17 00:00:00 2001 From: Crazylemon Date: Fri, 25 Dec 2015 22:51:02 -0800 Subject: [PATCH 01/19] Port of RemieRichard's infinite antag system This is just the first chunk, of fixing around the be_special flag stuff It will probably break everything as-is --- code/__DEFINES/preferences.dm | 17 ---- code/__DEFINES/role_preferences.dm | 54 +++++++++++++ code/__HELPERS/game.dm | 8 +- code/_globalvars/configuration.dm | 19 ----- code/datums/mind.dm | 14 ++-- .../game/gamemodes/autotraitor/autotraitor.dm | 8 +- code/game/gamemodes/blob/blob.dm | 2 +- code/game/gamemodes/game_mode.dm | 55 +------------ .../game/gamemodes/malfunction/malfunction.dm | 2 +- code/game/jobs/job_controller.dm | 2 +- code/modules/admin/verbs/one_click_antag.dm | 34 ++++---- code/modules/admin/verbs/randomverbs.dm | 2 +- code/modules/hydroponics/seed_mobs.dm | 78 +------------------ .../modules/mob/living/silicon/pai/recruit.dm | 6 +- .../mob/living/silicon/robot/drone/drone.dm | 2 +- .../modules/mob/living/simple_animal/borer.dm | 2 +- paradise.dme | 1 + 17 files changed, 99 insertions(+), 207 deletions(-) create mode 100644 code/__DEFINES/role_preferences.dm diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm index 1f170276c8f..1753045cb8c 100644 --- a/code/__DEFINES/preferences.dm +++ b/code/__DEFINES/preferences.dm @@ -26,20 +26,3 @@ #define MEMBER_PUBLIC 8192 #define TOGGLES_DEFAULT (CHAT_OOC|CHAT_DEAD|CHAT_GHOSTEARS|CHAT_GHOSTSIGHT|CHAT_PRAYER|CHAT_RADIO|CHAT_ATTACKLOGS|CHAT_LOOC|MEMBER_PUBLIC) - -#define BE_TRAITOR 1 -#define BE_OPERATIVE 2 -#define BE_CHANGELING 4 -#define BE_WIZARD 8 -#define BE_MALF 16 -#define BE_REV 32 -#define BE_ALIEN 64 -#define BE_PAI 128 -#define BE_CULTIST 256 -#define BE_NINJA 512 -#define BE_RAIDER 1024 -#define BE_VAMPIRE 2048 -#define BE_MUTINEER 4096 -#define BE_BLOB 8192 -#define BE_SHADOWLING 16384 -#define BE_REVENANT 32768 \ No newline at end of file diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm new file mode 100644 index 00000000000..50c52f107bc --- /dev/null +++ b/code/__DEFINES/role_preferences.dm @@ -0,0 +1,54 @@ + + +//Values for antag preferences, event roles, etc. unified here + + + +//These are synced with the Database, if you change the values of the defines +//then you MUST update the database! +#define ROLE_TRAITOR "traitor" +#define ROLE_OPERATIVE "operative" +#define ROLE_CHANGELING "changeling" +#define ROLE_WIZARD "wizard" +#define ROLE_MALF "malf AI" +#define ROLE_REV "revolutionary" +#define ROLE_ALIEN "xenomorph" +#define ROLE_PAI "pAI" +#define ROLE_CULTIST "cultist" +#define ROLE_BLOB "blob" +#define ROLE_NINJA "space ninja" +#define ROLE_MONKEY "monkey" +#define ROLE_GANG "gangster" +#define ROLE_SHADOWLING "shadowling" +#define ROLE_ABDUCTOR "abductor" +#define ROLE_REVENANT "revenant" +#define ROLE_HOG_GOD "hand of god: god" // We're prolly gonna port this one day or another +#define ROLE_HOG_CULTIST "hand of god: cultist" +#define ROLE_RAIDER "vox raider" +#define ROLE_VAMPIRE "vampire" + + +//Missing assignment means it's not a gamemode specific role, IT'S NOT A BUG OR ERROR. +//The gamemode specific ones are just so the gamemodes can query whether a player is old enough +//(in game days played) to play that role +var/global/list/special_roles = list( + ROLE_TRAITOR = /datum/game_mode/traitor, + ROLE_OPERATIVE = /datum/game_mode/nuclear, + ROLE_CHANGELING = /datum/game_mode/changeling, + ROLE_WIZARD = /datum/game_mode/wizard, + ROLE_MALF = /datum/game_mode/malfunction, + ROLE_REV = /datum/game_mode/revolution, + ROLE_ALIEN, + ROLE_PAI, + ROLE_CULTIST = /datum/game_mode/cult, + ROLE_BLOB = /datum/game_mode/blob, + ROLE_NINJA, + ROLE_MONKEY = /datum/game_mode/monkey, + ROLE_GANG = /datum/game_mode/gang, + ROLE_SHADOWLING = /datum/game_mode/shadowling, + ROLE_ABDUCTOR = /datum/game_mode/abduction, + ROLE_HOG_GOD = /datum/game_mode/hand_of_god, + ROLE_HOG_CULTIST = /datum/game_mode/hand_of_god, + ROLE_RAIDER = /datum/game_mode/heist, + ROLE_VAMPIRE = /datum/game_mode/vampire, +) diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 0d51ed39ec1..f821b19e665 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -290,17 +290,17 @@ proc/isInSight(var/atom/A, var/atom/B) return M return null -/proc/get_candidates(be_special_flag=0, afk_bracket=3000, override_age=0, override_jobban=0) - var/roletext = get_roletext(be_special_flag) +/proc/get_candidates(be_special_type, afk_bracket=3000, override_age=0, override_jobban=0) + var/roletext = get_roletext(be_special_type) var/list/candidates = list() // Keep looping until we find a non-afk candidate within the time bracket (we limit the bracket to 10 minutes (6000)) while(!candidates.len && afk_bracket < 6000) for(var/mob/dead/observer/G in player_list) if(G.client != null) if(!(G.mind && G.mind.current && G.mind.current.stat != DEAD)) - if(!G.client.is_afk(afk_bracket) && (G.client.prefs.be_special & be_special_flag)) + if(!G.client.is_afk(afk_bracket) && (be_special_type in G.client.prefs.be_special)) if(!override_jobban || (!jobban_isbanned(G, roletext) && !jobban_isbanned(G,"Syndicate"))) - if(override_age || player_old_enough_antag(G.client,be_special_flag)) + if(override_age || player_old_enough_antag(G.client,be_special_type)) candidates += G.client afk_bracket += 600 // Add a minute to the bracket, for every attempt diff --git a/code/_globalvars/configuration.dm b/code/_globalvars/configuration.dm index 61bfd723241..4cfa038cd1e 100644 --- a/code/_globalvars/configuration.dm +++ b/code/_globalvars/configuration.dm @@ -31,25 +31,6 @@ var/MAX_EX_LIGHT_RANGE = 14 var/MAX_EX_FLASH_RANGE = 14 var/MAX_EX_FLAME_RANGE = 14 -var/list/be_special_flags = list( - "traitor" = BE_TRAITOR, - "operative" = BE_OPERATIVE, - "changeling" = BE_CHANGELING, - "wizard" = BE_WIZARD, - "malf AI" = BE_MALF, - "revolutionary" = BE_REV, - "alien" = BE_ALIEN, - "pAI" = BE_PAI, - "cultist" = BE_CULTIST, - "ninja" = BE_NINJA, - "raider" = BE_RAIDER, - "vampire" = BE_VAMPIRE, - "mutineer" = BE_MUTINEER, - "blob" = BE_BLOB, - "shadowling" = BE_SHADOWLING, - "revenant" = BE_REVENANT -) - //Random event stuff, apparently used var/eventchance = 10 //% per 5 mins var/event = 0 diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 712c1b41e1c..860ebdd01b9 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -180,7 +180,7 @@ else text += "EMPLOYEE|headrev|rev" - if(current && current.client && current.client.prefs.be_special & BE_REV) + if(current && current.client && (ROLE_REV in current.client.prefs.be_special)) text += "|Enabled in Prefs" else text += "|Disabled in Prefs" @@ -205,7 +205,7 @@ text += "EMPLOYEE|cultist" - if(current && current.client && current.client.prefs.be_special & BE_CULTIST) + if(current && current.client && (ROLE_CULTIST in current.client.prefs.be_special)) text += "|Enabled in Prefs" else text += "|Disabled in Prefs" @@ -225,7 +225,7 @@ else text += "yes|NO" - if(current && current.client && current.client.prefs.be_special & BE_WIZARD) + if(current && current.client && (ROLE_WIZARD in current.client.prefs.be_special)) text += "|Enabled in Prefs" else text += "|Disabled in Prefs" @@ -246,7 +246,7 @@ else text += "yes|NO" - if(current && current.client && current.client.prefs.be_special & BE_CHANGELING) + if(current && current.client && (ROLE_CHANGELING in current.client.prefs.be_special)) text += "|Enabled in Prefs" else text += "|Disabled in Prefs" @@ -294,7 +294,7 @@ else text += "operative|NANOTRASEN" - if(current && current.client && current.client.prefs.be_special & BE_OPERATIVE) + if(current && current.client && (ROLE_OPERATIVE in current.client.prefs.be_special)) text += "|Enabled in Prefs" else text += "|Disabled in Prefs" @@ -316,7 +316,7 @@ else text += "traitor|EMPLOYEE" - if(current && current.client && current.client.prefs.be_special & BE_TRAITOR) + if(current && current.client && (ROLE_TRAITOR in current.client.prefs.be_special)) text += "|Enabled in Prefs" else text += "|Disabled in Prefs" @@ -335,7 +335,7 @@ else text += "shadowling|thrall|HUMAN" - if(current && current.client && current.client.prefs.be_special & BE_SHADOWLING) + if(current && current.client && (ROLE_SHADOWLING in current.client.prefs.be_special)) text += "|Enabled in Prefs" else text += "|Disabled in Prefs" diff --git a/code/game/gamemodes/autotraitor/autotraitor.dm b/code/game/gamemodes/autotraitor/autotraitor.dm index 8a9e9cc54b2..551d1a8e9b9 100644 --- a/code/game/gamemodes/autotraitor/autotraitor.dm +++ b/code/game/gamemodes/autotraitor/autotraitor.dm @@ -76,13 +76,13 @@ var/traitorcount = 0 var/possible_traitors[0] for(var/mob/living/player in mob_list) - if (player.client && player.stat != 2) + if (player.client && player.stat != DEAD) playercount += 1 - if (player.client && player.mind && player.mind.special_role && player.stat != 2) + if (player.client && player.mind && player.mind.special_role && player.stat != DEAD) traitorcount += 1 - if (player.client && player.mind && !player.mind.special_role && player.stat != 2) + if (player.client && player.mind && !player.mind.special_role && player.stat != DEAD) if (ishuman(player) || isrobot(player) || isAI(player)) - if (player.client && player.client.prefs.be_special & BE_TRAITOR && !jobban_isbanned(player, "traitor") && !jobban_isbanned(player, "Syndicate")) + if (player.client && (ROLE_TRAITOR in player.client.prefs.be_special) && !jobban_isbanned(player, "traitor") && !jobban_isbanned(player, "Syndicate")) possible_traitors += player.mind for(var/datum/mind/player in possible_traitors) for(var/job in restricted_jobs) diff --git a/code/game/gamemodes/blob/blob.dm b/code/game/gamemodes/blob/blob.dm index 1cbd8dd7a1e..ed1f5a5ffbd 100644 --- a/code/game/gamemodes/blob/blob.dm +++ b/code/game/gamemodes/blob/blob.dm @@ -58,7 +58,7 @@ var/list/blob_nodes = list() /datum/game_mode/blob/proc/get_blob_candidates() var/list/candidates = list() for(var/mob/living/carbon/human/player in player_list) - if(!player.stat && player.mind && !player.mind.special_role && !jobban_isbanned(player, "Syndicate") && (player.client.prefs.be_special & BE_BLOB)) + if(!player.stat && player.mind && !player.mind.special_role && !jobban_isbanned(player, "Syndicate") && (ROLE_BLOB in player.client.prefs.be_special)) candidates += player return candidates diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 244ae984ac8..54591061d33 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -254,7 +254,7 @@ // Get a list of all the people who want to be the antagonist for this round, except those with incompatible species for(var/mob/new_player/player in players) - if(player.client.prefs.be_special & role && !(player.client.prefs.species in protected_species)) + if((role in player.client.prefs.be_special) && !(player.client.prefs.species in protected_species)) log_debug("[player.key] had [roletext] enabled, so we are drafting them.") candidates += player.mind players -= player @@ -276,57 +276,6 @@ if(player.assigned_role == job) candidates -= player - /*if(candidates.len < recommended_enemies) - for(var/mob/new_player/player in players) - if(player.client && player.ready) - if(!(player.client.prefs.be_special & role)) // We don't have enough people who want to be antagonist, make a seperate list of people who don't want to be one - if(!jobban_isbanned(player, "Syndicate") && !jobban_isbanned(player, roletext)) //Nodrak/Carn: Antag Job-bans - drafted += player.mind - - if(restricted_jobs) - for(var/datum/mind/player in drafted) // Remove people who can't be an antagonist - for(var/job in restricted_jobs) - if(player.assigned_role == job) - drafted -= player - - drafted = shuffle(drafted) // Will hopefully increase randomness, Donkie - - while(candidates.len < recommended_enemies) // Pick randomlly just the number of people we need and add them to our list of candidates - if(drafted.len > 0) - applicant = pick(drafted) - if(applicant) - candidates += applicant - log_debug("[applicant.key] was force-drafted as [roletext], because there aren't enough candidates.") - drafted.Remove(applicant) - - else // Not enough scrubs, ABORT ABORT ABORT - break - - if(candidates.len < recommended_enemies && override_jobbans) //If we still don't have enough people, we're going to start drafting banned people. - for(var/mob/new_player/player in players) - if (player.client && player.ready) - if(jobban_isbanned(player, "Syndicate") || jobban_isbanned(player, roletext)) //Nodrak/Carn: Antag Job-bans - drafted += player.mind - - if(restricted_jobs) - for(var/datum/mind/player in drafted) // Remove people who can't be an antagonist - for(var/job in restricted_jobs) - if(player.assigned_role == job) - drafted -= player - - drafted = shuffle(drafted) // Will hopefully increase randomness, Donkie - - while(candidates.len < recommended_enemies) // Pick randomlly just the number of people we need and add them to our list of candidates - if(drafted.len > 0) - applicant = pick(drafted) - if(applicant) - candidates += applicant - drafted.Remove(applicant) - log_debug("[applicant.key] was force-drafted as [roletext], because there aren't enough candidates.") - - else // Not enough scrubs, ABORT ABORT ABORT - break - */ return candidates // Returns: The number of people who had the antagonist role set to yes, regardless of recomended_enemies, if that number is greater than recommended_enemies // recommended_enemies if the number of people with that role set to yes is less than recomended_enemies, @@ -336,7 +285,7 @@ /datum/game_mode/proc/latespawn(var/mob) /* -/datum/game_mode/proc/check_player_role_pref(var/role, var/mob/new_player/player) +/datum/game_mode/proc/check_player_role_pref(var/role, var/mob/player) if(player.preferences.be_special & role) return 1 return 0 diff --git a/code/game/gamemodes/malfunction/malfunction.dm b/code/game/gamemodes/malfunction/malfunction.dm index f206fee3591..476c4585236 100644 --- a/code/game/gamemodes/malfunction/malfunction.dm +++ b/code/game/gamemodes/malfunction/malfunction.dm @@ -31,7 +31,7 @@ var/datum/job/ai/DummyAIjob = new for(var/mob/new_player/player in player_list) if(player.client && player.ready) - if(player.client.prefs.be_special & BE_MALF) + if(ROLE_MALF in player.client.prefs.be_special) if(!jobban_isbanned(player, "Syndicate") && !jobban_isbanned(player, "AI") && !jobban_isbanned(player, roletext) && DummyAIjob.player_old_enough(player.client)) if(player_old_enough_antag(player.client,role)) antag_candidates += player.mind diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm index 9a34e2e1524..f25fd419da8 100644 --- a/code/game/jobs/job_controller.dm +++ b/code/game/jobs/job_controller.dm @@ -94,7 +94,7 @@ var/global/datum/controller/occupations/job_master if(!job.player_old_enough(player.client)) Debug("FOC player not old enough, Player: [player]") continue - if(flag && (!player.client.prefs.be_special & flag)) + if(flag && (!(flag in player.client.prefs.be_special)) Debug("FOC flag failed, Player: [player], Flag: [flag], ") continue if(player.mind && job.title in player.mind.restricted_roles) diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm index ad25fab49ce..798dd02b85f 100644 --- a/code/modules/admin/verbs/one_click_antag.dm +++ b/code/modules/admin/verbs/one_click_antag.dm @@ -33,7 +33,7 @@ client/proc/one_click_antag() var/datum/mind/themind = null for(var/mob/living/silicon/ai/ai in player_list) - if(ai.client && ai.client.prefs.be_special & BE_MALF) + if(ai.client && (ROLE_MALF in ai.client.prefs.be_special)) AIs += ai if(AIs.len) @@ -57,8 +57,8 @@ client/proc/one_click_antag() var/mob/living/carbon/human/H = null for(var/mob/living/carbon/human/applicant in player_list) - if(applicant.client.prefs.be_special & BE_TRAITOR) - if(player_old_enough_antag(applicant.client,BE_TRAITOR)) + if(ROLE_TRAITOR in applicant.client.prefs.be_special) + if(player_old_enough_antag(applicant.client,ROLE_TRAITOR)) if(!applicant.stat) if(applicant.mind) if (!applicant.mind.special_role) @@ -91,8 +91,8 @@ client/proc/one_click_antag() var/mob/living/carbon/human/H = null for(var/mob/living/carbon/human/applicant in player_list) - if(applicant.client.prefs.be_special & BE_CHANGELING) - if(player_old_enough_antag(applicant.client,BE_CHANGELING)) + if(ROLE_CHANGELING in applicant.client.prefs.be_special) + if(player_old_enough_antag(applicant.client,ROLE_CHANGELING)) if(!applicant.stat) if(applicant.mind) if (!applicant.mind.special_role) @@ -123,8 +123,8 @@ client/proc/one_click_antag() var/mob/living/carbon/human/H = null for(var/mob/living/carbon/human/applicant in player_list) - if(applicant.client.prefs.be_special & BE_REV) - if(player_old_enough_antag(applicant.client,BE_REV)) + if(ROLE_REV in applicant.client.prefs.be_special) + if(player_old_enough_antag(applicant.client,ROLE_REV)) if(applicant.stat == CONSCIOUS) if(applicant.mind) if(!applicant.mind.special_role) @@ -150,9 +150,9 @@ client/proc/one_click_antag() var/time_passed = world.time for(var/mob/G in respawnable_list) - if(istype(G) && G.client && G.client.prefs.be_special & BE_WIZARD) + if(istype(G) && G.client && (ROLE_WIZARD in G.client.prefs.be_special)) if(!jobban_isbanned(G, "wizard") && !jobban_isbanned(G, "Syndicate")) - if(player_old_enough_antag(G.client,BE_WIZARD)) + if(player_old_enough_antag(G.client,ROLE_WIZARD)) spawn(0) switch(G.timed_alert("Do you wish to be considered for the position of Space Wizard Foundation 'diplomat'?","Please answer in 30 seconds!","No",300,"Yes","No"))//alert(G, "Do you wish to be considered for the position of Space Wizard Foundation 'diplomat'?","Please answer in 30 seconds!","Yes","No")) if("Yes") @@ -192,8 +192,8 @@ client/proc/one_click_antag() var/mob/living/carbon/human/H = null for(var/mob/living/carbon/human/applicant in player_list) - if(applicant.client.prefs.be_special & BE_CULTIST) - if(player_old_enough_antag(applicant.client,BE_CULTIST)) + if(ROLE_CULTIST in applicant.client.prefs.be_special) + if(player_old_enough_antag(applicant.client,ROLE_CULTIST)) if(applicant.stat == CONSCIOUS) if(applicant.mind) if(!applicant.mind.special_role) @@ -224,9 +224,9 @@ client/proc/one_click_antag() var/time_passed = world.time for(var/mob/G in respawnable_list) - if(istype(G) && G.client && G.client.prefs.be_special & BE_OPERATIVE) + if(istype(G) && G.client && (ROLE_OPERATIVE in G.client.prefs.be_special)) if(!jobban_isbanned(G, "operative") && !jobban_isbanned(G, "Syndicate")) - if(player_old_enough_antag(G.client,BE_OPERATIVE)) + if(player_old_enough_antag(G.client,ROLE_OPERATIVE)) spawn(0) switch(alert(G,"Do you wish to be considered for a nuke team being sent in?","Please answer in 30 seconds!","Yes","No")) if("Yes") @@ -442,8 +442,8 @@ client/proc/one_click_antag() //Generates a list of candidates from active ghosts. for(var/mob/G in respawnable_list) - if(istype(G) && G.client && G.client.prefs.be_special & BE_RAIDER) - if(player_old_enough_antag(G.client,BE_RAIDER)) + if(istype(G) && G.client && (ROLE_RAIDER in G.client.prefs.be_special)) + if(player_old_enough_antag(G.client,ROLE_RAIDER)) if(!jobban_isbanned(G, "raider") && !jobban_isbanned(G, "Syndicate")) spawn(0) switch(alert(G,"Do you wish to be considered for a vox raiding party arriving on the station?","Please answer in 30 seconds!","Yes","No")) @@ -543,8 +543,8 @@ client/proc/one_click_antag() var/mob/living/carbon/human/H = null for(var/mob/living/carbon/human/applicant in player_list) - if(applicant.client.prefs.be_special & BE_VAMPIRE) - if(player_old_enough_antag(applicant.client,BE_VAMPIRE)) + if(ROLE_VAMPIRE in applicant.client.prefs.be_special) + if(player_old_enough_antag(applicant.client,ROLE_VAMPIRE)) if(!applicant.stat) if(applicant.mind) if (!applicant.mind.special_role) diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 40d8bc80671..e428f25fc39 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -444,7 +444,7 @@ Traitors and the like can also be revived with the previous role mostly intact. var/list/candidates = list() for(var/mob/M in player_list) if(M.stat != DEAD) continue //we are not dead! - if(!M.client.prefs.be_special & BE_ALIEN) continue //we don't want to be an alium + if(!(ROLE_ALIEN in M.client.prefs.be_special)) continue //we don't want to be an alium if(jobban_isbanned(M, "alien") || jobban_isbanned(M, "Syndicate")) continue //we are jobbanned if(M.client.is_afk()) continue //we are afk if(M.mind && M.mind.current && M.mind.current.stat != DEAD) continue //we have a live body we are tied to diff --git a/code/modules/hydroponics/seed_mobs.dm b/code/modules/hydroponics/seed_mobs.dm index b7fd3b4fdfd..57579a3a797 100644 --- a/code/modules/hydroponics/seed_mobs.dm +++ b/code/modules/hydroponics/seed_mobs.dm @@ -2,80 +2,4 @@ var/list/currently_querying // Used to avoid asking the same ghost repeatedly. // The following procs are used to grab players for mobs produced by a seed (mostly for dionaea). -/datum/seed/proc/handle_living_product(var/mob/living/host) -/* - if(!host || !istype(host)) return - - spawn(0) - request_player(host) - if(istype(host,/mob/living/simple_animal)) - return - spawn(75) - if(!host.ckey && !host.client) - host.death() // This seems redundant, but a lot of mobs don't - host.stat = DEAD // handle death() properly. Better safe than etc. - host.visible_message("[host] is malformed and unable to survive. It expires pitifully, leaving behind some seeds.") - - var/total_yield = rand(1,3) - for(var/j = 0;j<=total_yield;j++) - var/obj/item/seeds/S = new(get_turf(host)) - S.seed_type = name - S.update_seed() - -/datum/seed/proc/request_player(var/mob/living/host) - if(!host) return - for(var/mob/dead/observer/O in player_list) - if(jobban_isbanned(O, "Dionaea")) - continue - if(O.client) - if(O.client.prefs.be_special & BE_PLANT && !(O.client in currently_querying)) - currently_querying |= O.client - question(O.client,host) - -/datum/seed/proc/question(var/client/C,var/mob/living/host) - spawn(0) - - if(!C || !host || !(C.mob && istype(C.mob,/mob/dead))) return // We don't want to spam them repeatedly if they're already in a mob. - - var/response = alert(C, "Someone is harvesting [display_name]. Would you like to play as one?", "Sentient plant harvest", "Yes", "No", "Never for this round.") - - if(!C || !host || !(C.mob && istype(C.mob,/mob/dead))) return // ...or accidentally accept an invalid argument for transfer. - - if(response == "Yes") - transfer_personality(C,host) - else if (response == "Never for this round") - C.prefs.be_special ^= BE_PLANT - - currently_querying -= C - -/datum/seed/proc/transfer_personality(var/client/player,var/mob/living/host) - - //Something is wrong, abort. - if(!player || !host) return - - //Host already has a controller, pike off slowpoke. - if(host.client && host.ckey) return - - //Transfer them over. - host.ckey = player.ckey - if(player.mob && player.mob.mind) - player.mob.mind.transfer_to(host) - - if(host.dna) host.dna.real_name = host.real_name - - // Update mode specific HUD icons. - callHook("harvest_podman", list(host)) - - host << "\green You awaken slowly, stirring into sluggish motion as the air caresses you." - - // This is a hack, replace with some kind of species blurb proc. - if(istype(host,/mob/living/simple_animal/diona)) - host << "You are [host], one of a race of drifting interstellar plantlike creatures that sometimes share their seeds with human traders." - host << "Too much darkness will send you into shock and starve you, but light will help you heal." - - var/newname = input(host,"Enter a name, or leave blank for the default name.", "Name change","") as text - newname = sanitize(newname) - if (newname != "") - host.real_name = newname - host.name = host.real_name -*/ \ No newline at end of file +/datum/seed/proc/handle_living_product(var/mob/living/host) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/pai/recruit.dm b/code/modules/mob/living/silicon/pai/recruit.dm index 768b46c2283..fe785adf929 100644 --- a/code/modules/mob/living/silicon/pai/recruit.dm +++ b/code/modules/mob/living/silicon/pai/recruit.dm @@ -348,15 +348,15 @@ var/datum/paiController/paiController // Global handler for pAI candidates proc/requestRecruits(var/obj/item/device/paicard/P) for(var/mob/dead/observer/O in player_list) - if(O.client && O.client.prefs.be_special & BE_PAI) - if(player_old_enough_antag(O.client,BE_PAI)) + if(O.client && (ROLE_PAI in O.client.prefs.be_special)) + if(player_old_enough_antag(O.client,ROLE_PAI)) if(check_recruit(O)) O << "\blue A pAI card is looking for personalities. (Teleport | Sign Up)" //question(O.client) proc/check_recruit(var/mob/dead/observer/O) if(jobban_isbanned(O, "pAI") || jobban_isbanned(O,"nonhumandept")) return 0 - if(!player_old_enough_antag(O.client,BE_PAI)) + if(!player_old_enough_antag(O.client,ROLE_PAI)) return 0 if(O.has_enabled_antagHUD == 1 && config.antag_hud_restricted) return 0 diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm index 4b38f79c2cc..005b1194821 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone.dm @@ -259,7 +259,7 @@ if(jobban_isbanned(O,"nonhumandept") || jobban_isbanned(O,"Drone")) continue if(O.client) - if(O.client.prefs.be_special & BE_PAI) + if(ROLE_PAI in O.client.prefs.be_special) question(O.client,O) /mob/living/silicon/robot/drone/proc/question(var/client/C,var/mob/M) diff --git a/code/modules/mob/living/simple_animal/borer.dm b/code/modules/mob/living/simple_animal/borer.dm index ab593967725..854969123e5 100644 --- a/code/modules/mob/living/simple_animal/borer.dm +++ b/code/modules/mob/living/simple_animal/borer.dm @@ -462,7 +462,7 @@ mob/living/simple_animal/borer/proc/request_player() if(jobban_isbanned(O, "Syndicate")) continue if(O.client) - if(O.client.prefs.be_special & BE_ALIEN && !jobban_isbanned(O, "alien")) + if((BE_ALIEN in O.client.prefs.be_special) && !jobban_isbanned(O, "alien")) question(O.client) mob/living/simple_animal/borer/proc/question(var/client/C) diff --git a/paradise.dme b/paradise.dme index c4f2edc5dee..6c56a7fdaee 100644 --- a/paradise.dme +++ b/paradise.dme @@ -35,6 +35,7 @@ #include "code\__DEFINES\preferences.dm" #include "code\__DEFINES\process_scheduler.dm" #include "code\__DEFINES\qdel.dm" +#include "code\__DEFINES\role_preferences.dm" #include "code\__DEFINES\sight.dm" #include "code\__DEFINES\stat.dm" #include "code\__HELPERS\_string_lists.dm" From 23e8b1277f46256896aeab8bcc6304a61fdd38c6 Mon Sep 17 00:00:00 2001 From: Crazylemon Date: Sun, 27 Dec 2015 06:32:25 -0800 Subject: [PATCH 02/19] Wave 2 of tweaks, probably needs a little more Ripped out the preferences_savefile.dm because it's obsolete and we don't use it --- SQL/paradise_schema.sql | 4 +- SQL/paradise_schema_prefixed.sql | 4 +- code/__DEFINES/role_preferences.dm | 6 +- code/game/gamemodes/antag_spawner.dm | 4 +- .../game/gamemodes/autotraitor/autotraitor.dm | 8 +- code/game/gamemodes/blob/blob.dm | 2 +- code/game/gamemodes/blob/blobs/core.dm | 2 +- code/game/gamemodes/borer/borer.dm | 2 +- code/game/gamemodes/changeling/changeling.dm | 2 +- .../game/gamemodes/changeling/traitor_chan.dm | 2 +- code/game/gamemodes/cult/cult.dm | 2 +- code/game/gamemodes/events.dm | 4 +- code/game/gamemodes/game_mode.dm | 17 +- code/game/gamemodes/heist/heist.dm | 2 +- .../game/gamemodes/malfunction/malfunction.dm | 4 +- code/game/gamemodes/mutiny/mutiny.dm | 2 +- code/game/gamemodes/nuclear/nuclear.dm | 2 +- code/game/gamemodes/revolution/revolution.dm | 2 +- .../gamemodes/revolution/rp_revolution.dm | 3 +- code/game/gamemodes/shadowling/shadowling.dm | 2 +- code/game/gamemodes/traitor/traitor.dm | 2 +- code/game/gamemodes/vampire/vampire.dm | 2 +- code/game/gamemodes/wizard/artefact.dm | 4 +- code/game/gamemodes/wizard/raginmages.dm | 10 +- code/game/gamemodes/wizard/wizard.dm | 8 +- code/game/gamemodes/xenos/xenos.dm | 2 +- code/game/objects/effects/spiders.dm | 2 +- code/modules/client/preferences.dm | 87 ++-- code/modules/client/preferences_mysql.dm | 9 +- code/modules/client/preferences_savefile.dm | 443 ------------------ 30 files changed, 86 insertions(+), 559 deletions(-) delete mode 100644 code/modules/client/preferences_savefile.dm diff --git a/SQL/paradise_schema.sql b/SQL/paradise_schema.sql index d3594d87fa6..f6e8ea640a3 100644 --- a/SQL/paradise_schema.sql +++ b/SQL/paradise_schema.sql @@ -66,7 +66,7 @@ CREATE TABLE `characters` ( `med_record` mediumtext NOT NULL, `sec_record` mediumtext NOT NULL, `gen_record` mediumtext NOT NULL, - `be_special` mediumint(8) NOT NULL, + `be_role` mediumtext NOT NULL, `disabilities` mediumint(8) NOT NULL, `player_alt_titles` mediumtext NOT NULL, `organ_data` mediumtext NOT NULL, @@ -233,7 +233,7 @@ CREATE TABLE `player` ( `UI_style` varchar(10) DEFAULT 'Midnight', `UI_style_color` varchar(7) DEFAULT '#ffffff', `UI_style_alpha` smallint(4) DEFAULT '255', - `be_special` mediumint(8) DEFAULT '0', + `be_role` mediumtext NOT NULL, `default_slot` smallint(4) DEFAULT '1', `toggles` mediumint(8) DEFAULT '383', `sound` mediumint(8) DEFAULT '31', diff --git a/SQL/paradise_schema_prefixed.sql b/SQL/paradise_schema_prefixed.sql index 4a61245cf83..6fa053e79c1 100644 --- a/SQL/paradise_schema_prefixed.sql +++ b/SQL/paradise_schema_prefixed.sql @@ -66,7 +66,7 @@ CREATE TABLE `SS13_characters` ( `med_record` mediumtext NOT NULL, `sec_record` mediumtext NOT NULL, `gen_record` mediumtext NOT NULL, - `be_special` mediumint(8) NOT NULL, + `be_role` mediumtext NOT NULL, `disabilities` mediumint(8) NOT NULL, `player_alt_titles` mediumtext NOT NULL, `organ_data` mediumtext NOT NULL, @@ -233,7 +233,7 @@ CREATE TABLE `SS13_player` ( `UI_style` varchar(10) DEFAULT 'Midnight', `UI_style_color` varchar(7) DEFAULT '#ffffff', `UI_style_alpha` smallint(4) DEFAULT '255', - `be_special` mediumint(8) DEFAULT '0', + `be_role` mediumtext NOT NULL, `default_slot` smallint(4) DEFAULT '1', `toggles` mediumint(8) DEFAULT '383', `sound` mediumint(8) DEFAULT '31', diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index 50c52f107bc..6d2cfe702ed 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -26,6 +26,7 @@ #define ROLE_HOG_CULTIST "hand of god: cultist" #define ROLE_RAIDER "vox raider" #define ROLE_VAMPIRE "vampire" +#define ROLE_MUTINEER "mutineer" //Missing assignment means it's not a gamemode specific role, IT'S NOT A BUG OR ERROR. @@ -47,8 +48,9 @@ var/global/list/special_roles = list( ROLE_GANG = /datum/game_mode/gang, ROLE_SHADOWLING = /datum/game_mode/shadowling, ROLE_ABDUCTOR = /datum/game_mode/abduction, - ROLE_HOG_GOD = /datum/game_mode/hand_of_god, - ROLE_HOG_CULTIST = /datum/game_mode/hand_of_god, +// ROLE_HOG_GOD = /datum/game_mode/hand_of_god, +// ROLE_HOG_CULTIST = /datum/game_mode/hand_of_god, ROLE_RAIDER = /datum/game_mode/heist, ROLE_VAMPIRE = /datum/game_mode/vampire, + ROLE_MUTINEER = /datum/game_mode/mutiny, ) diff --git a/code/game/gamemodes/antag_spawner.dm b/code/game/gamemodes/antag_spawner.dm index cd09b5d7a9a..011efa31c74 100644 --- a/code/game/gamemodes/antag_spawner.dm +++ b/code/game/gamemodes/antag_spawner.dm @@ -36,7 +36,7 @@ return checking = 1 user << "The device is now checking for possible borgs." - var/list/mob/dead/observer/borg_candidates = pollCandidates("Do you want to play as a Syndicate [borg_to_spawn] borg?", "operative", 1, BE_OPERATIVE, 300) + var/list/mob/dead/observer/borg_candidates = pollCandidates("Do you want to play as a Syndicate [borg_to_spawn] borg?", "operative", 1, ROLE_OPERATIVE, 300) if(borg_candidates.len > 0 && !used) checking = 0 used = 1 @@ -74,7 +74,7 @@ icon_state = "vial" /obj/item/weapon/antag_spawner/slaughter_demon/attack_self(mob/user as mob) - var/list/demon_candidates = get_candidates(BE_ALIEN) + var/list/demon_candidates = get_candidates(ROLE_ALIEN) if(user.z == ZLEVEL_CENTCOMM)//this is to make sure the wizard does NOT summon a demon from the Den.. user << "You should probably wait until you reach the station." return diff --git a/code/game/gamemodes/autotraitor/autotraitor.dm b/code/game/gamemodes/autotraitor/autotraitor.dm index 551d1a8e9b9..bc9f83d88e0 100644 --- a/code/game/gamemodes/autotraitor/autotraitor.dm +++ b/code/game/gamemodes/autotraitor/autotraitor.dm @@ -18,7 +18,7 @@ if(config.protect_roles_from_antagonist) restricted_jobs += protected_jobs - possible_traitors = get_players_for_role(BE_TRAITOR) + possible_traitors = get_players_for_role(ROLE_TRAITOR) for(var/mob/new_player/P in world) if(P.client && P.ready) @@ -160,15 +160,15 @@ if(shuttle_master.emergency.mode >= SHUTTLE_ESCAPE) return //message_admins("Late Join Check") - if((character.client && character.client.prefs.be_special & BE_TRAITOR) && !jobban_isbanned(character, "traitor") && !jobban_isbanned(character, "Syndicate")) + if((character.client && (ROLE_TRAITOR in character.client.prefs.be_special) && !jobban_isbanned(character, "traitor") && !jobban_isbanned(character, "Syndicate")) //message_admins("Late Joiner has Be Syndicate") //message_admins("Checking number of players") var/playercount = 0 var/traitorcount = 0 for(var/mob/living/player in mob_list) - if (player.client && player.stat != 2) + if (player.client && player.stat != DEAD) playercount += 1 - if (player.client && player.mind && player.mind.special_role && player.stat != 2) + if (player.client && player.mind && player.mind.special_role && player.stat != DEAD) traitorcount += 1 //message_admins("Live Players: [playercount]") //message_admins("Live Traitors: [traitorcount]") diff --git a/code/game/gamemodes/blob/blob.dm b/code/game/gamemodes/blob/blob.dm index ed1f5a5ffbd..4c8914b9131 100644 --- a/code/game/gamemodes/blob/blob.dm +++ b/code/game/gamemodes/blob/blob.dm @@ -29,7 +29,7 @@ var/list/blob_nodes = list() /datum/game_mode/blob/pre_setup() - var/list/possible_blobs = get_players_for_role(BE_BLOB) + var/list/possible_blobs = get_players_for_role(ROLE_BLOB) // stop setup if no possible traitors if(!possible_blobs.len) diff --git a/code/game/gamemodes/blob/blobs/core.dm b/code/game/gamemodes/blob/blobs/core.dm index 4ccaa08d7be..5954a5b1dba 100644 --- a/code/game/gamemodes/blob/blobs/core.dm +++ b/code/game/gamemodes/blob/blobs/core.dm @@ -101,7 +101,7 @@ var/list/candidates = list() if(!new_overmind) - candidates = get_candidates(BE_BLOB) + candidates = get_candidates(ROLE_BLOB) if(candidates.len) C = pick(candidates) else diff --git a/code/game/gamemodes/borer/borer.dm b/code/game/gamemodes/borer/borer.dm index 3a491c769df..c31216c8add 100644 --- a/code/game/gamemodes/borer/borer.dm +++ b/code/game/gamemodes/borer/borer.dm @@ -29,7 +29,7 @@ // also make sure that there's at least one borer and one host recommended_enemies = max(src.num_players() / 20 * 2, 2) - var/list/datum/mind/possible_borers = get_players_for_role(BE_ALIEN) + var/list/datum/mind/possible_borers = get_players_for_role(ROLE_ALIEN) if(possible_borers.len < 2) log_admin("MODE FAILURE: BORER. NOT ENOUGH BORER CANDIDATES.") diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm index d40402f0ae2..bc323d14c3c 100644 --- a/code/game/gamemodes/changeling/changeling.dm +++ b/code/game/gamemodes/changeling/changeling.dm @@ -46,7 +46,7 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon" if(config.protect_roles_from_antagonist) restricted_jobs += protected_jobs - var/list/datum/mind/possible_changelings = get_players_for_role(BE_CHANGELING) + var/list/datum/mind/possible_changelings = get_players_for_role(ROLE_CHANGELING) changeling_amount = 1 + round(num_players() / 10) diff --git a/code/game/gamemodes/changeling/traitor_chan.dm b/code/game/gamemodes/changeling/traitor_chan.dm index 48ea01b1a29..8cb86e6cc3c 100644 --- a/code/game/gamemodes/changeling/traitor_chan.dm +++ b/code/game/gamemodes/changeling/traitor_chan.dm @@ -18,7 +18,7 @@ if(config.protect_roles_from_antagonist) restricted_jobs += protected_jobs - var/list/datum/mind/possible_changelings = get_players_for_role(BE_CHANGELING) + var/list/datum/mind/possible_changelings = get_players_for_role(ROLE_CHANGELING) for(var/mob/new_player/player in player_list) if((player.mind in possible_changelings) && (player.client.prefs.species in protected_species_changeling)) diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm index 457a9d85995..0ec4d72b5de 100644 --- a/code/game/gamemodes/cult/cult.dm +++ b/code/game/gamemodes/cult/cult.dm @@ -71,7 +71,7 @@ if(config.protect_roles_from_antagonist) restricted_jobs += protected_jobs - var/list/cultists_possible = get_players_for_role(BE_CULTIST) + var/list/cultists_possible = get_players_for_role(ROLE_CULTIST) for(var/cultists_number = 1 to max_cultists_to_start) if(!cultists_possible.len) diff --git a/code/game/gamemodes/events.dm b/code/game/gamemodes/events.dm index 3f1cd777310..8c1d97fef07 100644 --- a/code/game/gamemodes/events.dm +++ b/code/game/gamemodes/events.dm @@ -6,7 +6,7 @@ if(temp_vent.parent.other_atmosmch.len > 50) // Stops Aliens getting stuck in small networks. See: Security, Virology vents += temp_vent - var/list/candidates = get_candidates(BE_ALIEN,ALIEN_AFK_BRACKET) + var/list/candidates = get_candidates(ROLE_ALIEN,ALIEN_AFK_BRACKET) if(prob(40)) spawncount++ //sometimes, have two larvae spawn instead of one while((spawncount >= 1) && vents.len && candidates.len) @@ -25,7 +25,7 @@ command_announcement.Announce("Unidentified lifesigns detected coming aboard [station_name()]. Secure any exterior access, including ducting and ventilation.", "Lifesign Alert", new_sound = 'sound/AI/aliens.ogg') for(var/mob/M in player_list) M << sound('sound/AI/aliens.ogg') - + /proc/lightsout(isEvent = 0, lightsoutAmount = 1,lightsoutRange = 25) //leave lightsoutAmount as 0 to break ALL lights if(isEvent) command_announcement.Announce("An Electrical storm has been detected in your area, please repair potential electronic overloads.","Electrical Storm Alert") diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 54591061d33..f2de8d413fd 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -438,22 +438,7 @@ proc/get_nt_opposed() obj_count++ /proc/get_roletext(var/role) - var/roletext - switch(role) - if(BE_CHANGELING) roletext="changeling" - if(BE_TRAITOR) roletext="traitor" - if(BE_OPERATIVE) roletext="operative" - if(BE_WIZARD) roletext="wizard" - if(BE_MALF) roletext="malf AI" - if(BE_REV) roletext="revolutionary" - if(BE_CULTIST) roletext="cultist" - if(BE_NINJA) roletext="ninja" - if(BE_RAIDER) roletext="raider" - if(BE_VAMPIRE) roletext="vampire" - if(BE_ALIEN) roletext="alien" - if(BE_MUTINEER) roletext="mutineer" - if(BE_BLOB) roletext="blob" - return roletext + return role /proc/get_nuke_code() var/nukecode = "ERROR" diff --git a/code/game/gamemodes/heist/heist.dm b/code/game/gamemodes/heist/heist.dm index e6d4914ad3a..229993ee50c 100644 --- a/code/game/gamemodes/heist/heist.dm +++ b/code/game/gamemodes/heist/heist.dm @@ -33,7 +33,7 @@ var/global/list/obj/cortical_stacks = list() //Stacks for 'leave nobody behind' if(!..()) return 0 - var/list/candidates = get_players_for_role(BE_RAIDER) + var/list/candidates = get_players_for_role(ROLE_RAIDER) var/raider_num = 0 //Check that we have enough vox. diff --git a/code/game/gamemodes/malfunction/malfunction.dm b/code/game/gamemodes/malfunction/malfunction.dm index 476c4585236..4d436e29ca9 100644 --- a/code/game/gamemodes/malfunction/malfunction.dm +++ b/code/game/gamemodes/malfunction/malfunction.dm @@ -25,7 +25,7 @@ The AI on the satellite has malfunctioned and must be destroyed.
The AI satellite is deep in space and can only be accessed with the use of a teleporter! You have [AI_win_timeleft/60] minutes to disable it."} -/datum/game_mode/malfunction/get_players_for_role(var/role = BE_MALF) +/datum/game_mode/malfunction/get_players_for_role(var/role = ROLE_MALF) var/roletext = get_roletext(role) var/datum/job/ai/DummyAIjob = new @@ -39,7 +39,7 @@ return antag_candidates /datum/game_mode/malfunction/pre_setup() - get_players_for_role(BE_MALF) + get_players_for_role(ROLE_MALF) var/datum/mind/chosen_ai if(!antag_candidates.len) diff --git a/code/game/gamemodes/mutiny/mutiny.dm b/code/game/gamemodes/mutiny/mutiny.dm index a198fb21eac..1d2faebe5ff 100644 --- a/code/game/gamemodes/mutiny/mutiny.dm +++ b/code/game/gamemodes/mutiny/mutiny.dm @@ -80,7 +80,7 @@ datum/game_mode/mutiny proc/get_head_mutineer_candidates() var/list/candidates[0] for(var/mob/mutineer in player_list) - if(mutineer.client.prefs.be_special & BE_MUTINEER) + if(ROLE_MUTINEER in mutineer.client.prefs.be_special) if(!jobban_isbanned(mutineer, "mutineer") && !jobban_isbanned(mutineer,"Syndicate")) for(var/job in command_positions - "Captain") if(mutineer.mind && mutineer.mind.assigned_role == job) diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index 007e1c1da04..bfcb53db43c 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -31,7 +31,7 @@ proc/issyndicate(mob/living/M as mob) if(!..()) return 0 - var/list/possible_syndicates = get_players_for_role(BE_OPERATIVE) + var/list/possible_syndicates = get_players_for_role(ROLE_OPERATIVE) var/agent_number = 0 if(possible_syndicates.len < 1) diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm index 714ad3d5870..345114a4088 100644 --- a/code/game/gamemodes/revolution/revolution.dm +++ b/code/game/gamemodes/revolution/revolution.dm @@ -45,7 +45,7 @@ if(config.protect_roles_from_antagonist) restricted_jobs += protected_jobs - var/list/datum/mind/possible_headrevs = get_players_for_role(BE_REV) + var/list/datum/mind/possible_headrevs = get_players_for_role(ROLE_REV) for (var/i=1 to max_headrevs) if(possible_headrevs.len==0) diff --git a/code/game/gamemodes/revolution/rp_revolution.dm b/code/game/gamemodes/revolution/rp_revolution.dm index 3e9c18bca12..ef2ec130047 100644 --- a/code/game/gamemodes/revolution/rp_revolution.dm +++ b/code/game/gamemodes/revolution/rp_revolution.dm @@ -1,4 +1,5 @@ // BS12's less violent revolution mode +// Isn't this basically mutiny but without any real reason /datum/game_mode/revolution/rp_revolution name = "rp-revolution" @@ -29,7 +30,7 @@ max_headrevs = max(num_players / 4, 3) recommended_enemies = max_headrevs - var/list/datum/mind/possible_headrevs = get_players_for_role(BE_REV) + var/list/datum/mind/possible_headrevs = get_players_for_role(ROLE_REV) var/head_check = 0 for(var/mob/new_player/player in player_list) diff --git a/code/game/gamemodes/shadowling/shadowling.dm b/code/game/gamemodes/shadowling/shadowling.dm index fd1ac61ef80..551fb869839 100644 --- a/code/game/gamemodes/shadowling/shadowling.dm +++ b/code/game/gamemodes/shadowling/shadowling.dm @@ -78,7 +78,7 @@ Made by Xhuis if(config.protect_roles_from_antagonist) restricted_jobs += protected_jobs - var/list/datum/mind/possible_shadowlings = get_players_for_role(BE_SHADOWLING) + var/list/datum/mind/possible_shadowlings = get_players_for_role(ROLE_SHADOWLING) if(!possible_shadowlings.len) return 0 diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm index a94cda0f3cf..df18240e7bf 100644 --- a/code/game/gamemodes/traitor/traitor.dm +++ b/code/game/gamemodes/traitor/traitor.dm @@ -34,7 +34,7 @@ if(config.protect_roles_from_antagonist) restricted_jobs += protected_jobs - var/list/possible_traitors = get_players_for_role(BE_TRAITOR) + var/list/possible_traitors = get_players_for_role(ROLE_TRAITOR) // stop setup if no possible traitors if(!possible_traitors.len) diff --git a/code/game/gamemodes/vampire/vampire.dm b/code/game/gamemodes/vampire/vampire.dm index 14266ef9f15..0931adfe4ef 100644 --- a/code/game/gamemodes/vampire/vampire.dm +++ b/code/game/gamemodes/vampire/vampire.dm @@ -47,7 +47,7 @@ if(config.protect_roles_from_antagonist) restricted_jobs += protected_jobs - var/list/datum/mind/possible_vampires = get_players_for_role(BE_VAMPIRE) + var/list/datum/mind/possible_vampires = get_players_for_role(ROLE_VAMPIRE) vampire_amount = 1 + round(num_players() / 10) diff --git a/code/game/gamemodes/wizard/artefact.dm b/code/game/gamemodes/wizard/artefact.dm index 17e60881cc5..587b9ad1af5 100644 --- a/code/game/gamemodes/wizard/artefact.dm +++ b/code/game/gamemodes/wizard/artefact.dm @@ -49,7 +49,7 @@ if (used) H << "You already used this contract!" return - var/list/candidates = get_candidates(BE_WIZARD) + var/list/candidates = get_candidates(ROLE_WIZARD) if(candidates.len) src.used = 1 var/client/C = pick(candidates) @@ -294,7 +294,7 @@ var/global/list/multiverse = list() usr.mind.special_role = "[usr.real_name] Prime" evil = FALSE else - var/list/candidates = get_candidates(BE_WIZARD) + var/list/candidates = get_candidates(ROLE_WIZARD) if(candidates.len) var/client/C = pick(candidates) spawn_copy(C, get_turf(user.loc), user) diff --git a/code/game/gamemodes/wizard/raginmages.dm b/code/game/gamemodes/wizard/raginmages.dm index 81684f83e37..30af14862cd 100644 --- a/code/game/gamemodes/wizard/raginmages.dm +++ b/code/game/gamemodes/wizard/raginmages.dm @@ -17,7 +17,7 @@ ..() if(!max_mages) for(var/mob/living/player in mob_list) - if (player.client && player.stat != 2) + if (player.client && player.stat != DEAD) playercount += 1 max_mages = round(playercount / 5) @@ -40,12 +40,12 @@ continue if(istype(wizard.current,/mob/living/carbon/brain)) continue - if(wizard.current.stat==2) + if(wizard.current.stat==DEAD) continue - if(wizard.current.stat==1) + if(wizard.current.stat==UNCONSCIOUS) if(wizard.current.health < 0) wizard.current << "\red The Space Wizard Federation is upset with your performance and have terminated your employment." - wizard.current.stat = 2 + wizard.current.death() continue wizards_alive++ @@ -73,7 +73,7 @@ var/mob/dead/observer/theghost = null spawn(rand(200, 600)) message_admins("SWF is still pissed, sending another wizard - [max_mages - mages_made] left.") - candidates = get_candidates(BE_WIZARD) + candidates = get_candidates(ROLE_WIZARD) if(!candidates.len) message_admins("No applicable ghosts for the next ragin' mage, asking ghosts instead.") var/time_passed = world.time diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm index 8b7267408b9..45beb619642 100644 --- a/code/game/gamemodes/wizard/wizard.dm +++ b/code/game/gamemodes/wizard/wizard.dm @@ -23,7 +23,7 @@ /datum/game_mode/wizard/can_start()//This could be better, will likely have to recode it later if(!..()) return 0 - var/list/datum/mind/possible_wizards = get_players_for_role(BE_WIZARD) + var/list/datum/mind/possible_wizards = get_players_for_role(ROLE_WIZARD) if(possible_wizards.len==0) return 0 var/datum/mind/wizard = pick(possible_wizards) @@ -211,7 +211,7 @@ for(var/datum/mind/wizard in wizards) if(!istype(wizard.current,/mob/living/carbon)) continue - if(wizard.current.stat==2) + if(wizard.current.stat==DEAD) continue wizards_alive++ @@ -219,7 +219,7 @@ for(var/datum/mind/traitor in traitors) if(!istype(traitor.current,/mob/living/carbon)) continue - if(traitor.current.stat==2) + if(traitor.current.stat==DEAD) continue traitors_alive++ @@ -269,7 +269,7 @@ wizardwin = 0 count++ - if(wizard.current && wizard.current.stat!=2 && wizardwin) + if(wizard.current && wizard.current.stat!=DEAD && wizardwin) text += "
The wizard was successful!" feedback_add_details("wizard_success","SUCCESS") else diff --git a/code/game/gamemodes/xenos/xenos.dm b/code/game/gamemodes/xenos/xenos.dm index f73b398c20d..f30debb7e98 100644 --- a/code/game/gamemodes/xenos/xenos.dm +++ b/code/game/gamemodes/xenos/xenos.dm @@ -25,7 +25,7 @@ if(!..()) return 0 - var/list/candidates = get_players_for_role(BE_ALIEN) + var/list/candidates = get_players_for_role(ROLE_ALIEN) var/playersready = 0 var/xenos_num for(var/mob/new_player/player in player_list) diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm index b8a90698e2a..eb0cb3abf63 100644 --- a/code/game/objects/effects/spiders.dm +++ b/code/game/objects/effects/spiders.dm @@ -198,7 +198,7 @@ S.faction = faction S.master_commander = master_commander if(player_spiders) - var/list/candidates = get_candidates(BE_ALIEN, ALIEN_AFK_BRACKET) + var/list/candidates = get_candidates(ROLE_ALIEN, ALIEN_AFK_BRACKET) var/client/C = null if(candidates.len) diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index e7987280d48..81669e556c6 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -2,42 +2,23 @@ var/list/preferences_datums = list() -var/global/list/special_roles = list( //keep synced with the defines BE_* in setup.dm. THE ORDER MATTERS -//some autodetection here. - "traitor" = IS_MODE_COMPILED("traitor"), // 1 / 1 - "operative" = IS_MODE_COMPILED("nuclear"), // 2 / 2 - "changeling" = IS_MODE_COMPILED("changeling"), // 4 / 3 - "wizard" = IS_MODE_COMPILED("wizard"), // 8 / 4 - "malf AI" = IS_MODE_COMPILED("malfunction"), // 16 / 5 - "revolutionary" = IS_MODE_COMPILED("revolution"), // 32 / 6 - "alien" = 1, // 62 / 7 - "pAI" = 1, // 128 / 8 - "cultist" = IS_MODE_COMPILED("cult"), // 256 / 9 - "ninja" = 1, // 512 / 10 - "raider" = IS_MODE_COMPILED("heist"), // 1024 / 11 - "vampire" = IS_MODE_COMPILED("vampire"), // 2048 / 12 - "mutineer" = IS_MODE_COMPILED("mutiny"), // 4096 / 13 - "blob" = IS_MODE_COMPILED("blob"), // 8192 / 14 - "shadowling" = IS_MODE_COMPILED("shadowling"), //16384 / 15 - "revenant" = 1 //32768 / 16 -) var/global/list/special_role_times = list( //minimum age (in days) for accounts to play these roles - num2text(BE_PAI) = 0, - num2text(BE_TRAITOR) = 7, - num2text(BE_CHANGELING) = 14, - num2text(BE_SHADOWLING) = 14, - num2text(BE_WIZARD) = 14, - num2text(BE_REV) = 14, - num2text(BE_VAMPIRE) = 14, - num2text(BE_BLOB) = 14, - num2text(BE_REVENANT) = 14, - num2text(BE_OPERATIVE) = 21, - num2text(BE_CULTIST) = 21, - num2text(BE_RAIDER) = 21, - num2text(BE_ALIEN) = 21, - num2text(BE_NINJA) = 21, - num2text(BE_MUTINEER) = 21, - num2text(BE_MALF) = 30, + num2text(ROLE_PAI) = 0, + num2text(ROLE_TRAITOR) = 7, + num2text(ROLE_CHANGELING) = 14, + num2text(ROLE_SHADOWLING) = 14, + num2text(ROLE_WIZARD) = 14, + num2text(ROLE_REV) = 14, + num2text(ROLE_VAMPIRE) = 14, + num2text(ROLE_BLOB) = 14, + num2text(ROLE_REVENANT) = 14, + num2text(ROLE_OPERATIVE) = 21, + num2text(ROLE_CULTIST) = 21, + num2text(ROLE_RAIDER) = 21, + num2text(ROLE_ALIEN) = 21, + num2text(ROLE_NINJA) = 21, + num2text(ROLE_MUTINEER) = 21, + num2text(ROLE_MALF) = 30, ) /proc/player_old_enough_antag(client/C, role) @@ -91,7 +72,8 @@ datum/preferences //game-preferences // var/lastchangelog = "" //Saved changlog filesize to detect if there was a change var/ooccolor = "#b82e00" - var/be_special = 0 //Special role selection + var/be_special = list() //Special role selection + var/old_be_special = 0 //For converting from the old format var/UI_style = "Midnight" var/toggles = TOGGLES_DEFAULT var/sound = SOUND_DEFAULT @@ -209,8 +191,9 @@ datum/preferences save_preferences(C) save_character(C) //let's save this new random character so it doesn't keep generating new ones. -/datum/preferences - proc/ShowChoices(mob/user) + +// Hello I am a proc full of snowflake species checks how are you +/datum/preferences/proc/ShowChoices(mob/user) if(!user || !user.client) return update_preview_icon() user << browse_rsc(preview_icon_front, "previewicon.png") @@ -409,20 +392,16 @@ datum/preferences // dat += "

" if(jobban_isbanned(user, "Syndicate")) dat += "You are banned from special roles." - src.be_special = 0 + src.be_special = list() else - var/n = 0 for (var/i in special_roles) - if(special_roles[i]) //if mode is available on the server - var/special_role_flag = be_special_flags[i] - if(jobban_isbanned(user, i)) - dat += "Be [i]: \[BANNED]
" - else if(!player_old_enough_antag(user.client,special_role_flag)) - var/available_in_days_antag = available_in_days_antag(user.client,special_role_flag) - dat += "Be [i]: \[IN [(available_in_days_antag)] DAYS]
" - else - dat += "Be [i]: [src.be_special&(1<
" - n++ + if(jobban_isbanned(user, i)) + dat += "Be [capitalize(i)]: \[BANNED]
" + else if(!player_old_enough_antag(user.client,i)) + var/available_in_days_antag = available_in_days_antag(user.client,i) + dat += "Be [capitalize(i)]: \[IN [(available_in_days_antag)] DAYS]
" + else + dat += "Be [capitalize(i)]: [(i in src.be_special) ? "Yes" : "No"]
" dat += "
" if(!IsGuestKey(user.key)) @@ -1446,8 +1425,12 @@ datum/preferences UI_style_alpha = UI_style_alpha_new if("be_special") - var/num = text2num(href_list["num"]) - be_special ^= (1<Nice try." + else + be_special ^= r if("name") be_random_name = !be_random_name diff --git a/code/modules/client/preferences_mysql.dm b/code/modules/client/preferences_mysql.dm index 98c26df8ec8..be900d254b7 100644 --- a/code/modules/client/preferences_mysql.dm +++ b/code/modules/client/preferences_mysql.dm @@ -5,7 +5,7 @@ UI_style, UI_style_color, UI_style_alpha, - be_special, + be_role, default_slot, toggles, sound, @@ -28,7 +28,7 @@ UI_style = query.item[2] UI_style_color = query.item[3] UI_style_alpha = text2num(query.item[4]) - be_special = text2num(query.item[5]) + be_special = params2list(query.item[5]) default_slot = text2num(query.item[6]) toggles = text2num(query.item[7]) sound = text2num(query.item[8]) @@ -39,7 +39,6 @@ ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor)) // lastchangelog = sanitize_text(lastchangelog, initial(lastchangelog)) UI_style = sanitize_inlist(UI_style, list("White", "Midnight"), initial(UI_style)) - be_special = sanitize_integer(be_special, 0, 65535, initial(be_special)) default_slot = sanitize_integer(default_slot, 1, max_save_slots, initial(default_slot)) toggles = sanitize_integer(toggles, 0, 65535, initial(toggles)) sound = sanitize_integer(sound, 0, 65535, initial(sound)) @@ -57,7 +56,7 @@ UI_style='[UI_style]', UI_style_color='[UI_style_color]', UI_style_alpha='[UI_style_alpha]', - be_special='[be_special]', + be_role='[sql_sanitize_text(list2params(be_special))]', default_slot='[default_slot]', toggles='[toggles]', sound='[sound]', @@ -152,7 +151,7 @@ //socks socks = query.item[54] body_accessory = query.item[55] - + //Sanitize metadata = sanitize_text(metadata, initial(metadata)) real_name = reject_bad_name(real_name) diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm deleted file mode 100644 index f1dd7b307f3..00000000000 --- a/code/modules/client/preferences_savefile.dm +++ /dev/null @@ -1,443 +0,0 @@ -#define SAVEFILE_VERSION_MIN 8 -#define SAVEFILE_VERSION_MAX 12 - -//handles converting savefiles to new formats -//MAKE SURE YOU KEEP THIS UP TO DATE! -//If the sanity checks are capable of handling any issues. Only increase SAVEFILE_VERSION_MAX, -//this will mean that savefile_version will still be over SAVEFILE_VERSION_MIN, meaning -//this savefile update doesn't run everytime we load from the savefile. -//This is mainly for format changes, such as the bitflags in toggles changing order or something. -//if a file can't be updated, return 0 to delete it and start again -//if a file was updated, return 1 -/datum/preferences/proc/savefile_update() - if(savefile_version < 8) //lazily delete everything + additional files so they can be saved in the new format - for(var/ckey in preferences_datums) - var/datum/preferences/D = preferences_datums[ckey] - if(D == src) - var/delpath = "data/player_saves/[copytext(ckey,1,2)]/[ckey]/" - if(delpath && fexists(delpath)) - fdel(delpath) - break - return 0 - - if(savefile_version == SAVEFILE_VERSION_MAX) //update successful. - save_preferences() - save_character() - return 1 - return 0 - -/datum/preferences/proc/load_path(ckey,filename="preferences.sav") - if(!ckey) return - path = "data/player_saves/[copytext(ckey,1,2)]/[ckey]/[filename]" - savefile_version = SAVEFILE_VERSION_MAX - -/* -/datum/preferences/proc/load_preferences() - if(!path) return 0 - if(!fexists(path)) return 0 - var/savefile/S = new /savefile(path) - if(!S) return 0 - S.cd = "/" - - S["version"] >> savefile_version - //Conversion - if(!savefile_version || !isnum(savefile_version) || savefile_version < SAVEFILE_VERSION_MIN || savefile_version > SAVEFILE_VERSION_MAX) - if(!savefile_update()) //handles updates - savefile_version = SAVEFILE_VERSION_MAX - save_preferences() - save_character() - return 0 - - //general preferences - S["ooccolor"] >> ooccolor - S["lastchangelog"] >> lastchangelog - S["UI_style"] >> UI_style - S["be_special"] >> be_special - S["default_slot"] >> default_slot - S["toggles"] >> toggles - S["sound"] >> sound - S["UI_style_color"] >> UI_style_color - S["UI_style_alpha"] >> UI_style_alpha - S["randomslot"] >> randomslot - S["volume"] >> volume - //Sanitize - ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor)) - lastchangelog = sanitize_text(lastchangelog, initial(lastchangelog)) - UI_style = sanitize_inlist(UI_style, list("White", "Midnight"), initial(UI_style)) - be_special = sanitize_integer(be_special, 0, 65535, initial(be_special)) - default_slot = sanitize_integer(default_slot, 1, MAX_SAVE_SLOTS, initial(default_slot)) - toggles = sanitize_integer(toggles, 0, 65535, initial(toggles)) - sound = sanitize_integer(sound, 0, 65535, initial(toggles)) - UI_style_color = sanitize_hexcolor(UI_style_color, initial(UI_style_color)) - UI_style_alpha = sanitize_integer(UI_style_alpha, 0, 255, initial(UI_style_alpha)) - randomslot = sanitize_integer(randomslot, 0, 1, initial(randomslot)) - volume = sanitize_integer(volume, 0, 100, initial(volume)) - return 1 - -/datum/preferences/proc/save_preferences() - if(!path) return 0 - var/savefile/S = new /savefile(path) - if(!S) return 0 - S.cd = "/" - - S["version"] << savefile_version - - //general preferences - S["ooccolor"] << ooccolor - S["lastchangelog"] << lastchangelog - S["UI_style"] << UI_style - S["be_special"] << be_special - S["default_slot"] << default_slot - S["toggles"] << toggles - S["sound"] << sound - S["UI_style_color"] << UI_style_color - S["UI_style_alpha"] << UI_style_alpha - S["randomslot"] << randomslot - S["volume"] << volume - return 1 - - -//saving volume changes -/datum/preferences/proc/save_volume() - if(!path) return 0 - var/savefile/S = new /savefile(path) - if(!S) return 0 - S.cd = "/" - - S["volume"] << volume - return 1 -*/ - -/datum/preferences/proc/load_save(dir) - var/savefile/S = new /savefile(path) - if(!S) return 0 - S.cd = dir - - //Character - S["OOC_Notes"] >> metadata - S["real_name"] >> real_name - S["name_is_always_random"] >> be_random_name - S["gender"] >> gender - S["age"] >> age - S["species"] >> species - S["language"] >> language - S["spawnpoint"] >> spawnpoint - - //colors to be consolidated into hex strings (requires some work with dna code) - S["hair_red"] >> r_hair - S["hair_green"] >> g_hair - S["hair_blue"] >> b_hair - S["facial_red"] >> r_facial - S["facial_green"] >> g_facial - S["facial_blue"] >> b_facial - S["skin_tone"] >> s_tone - S["skin_red"] >> r_skin - S["skin_green"] >> g_skin - S["skin_blue"] >> b_skin - S["hair_style_name"] >> h_style - S["facial_style_name"] >> f_style - S["eyes_red"] >> r_eyes - S["eyes_green"] >> g_eyes - S["eyes_blue"] >> b_eyes - S["underwear"] >> underwear - S["undershirt"] >> undershirt - S["socks"] >> socks - S["backbag"] >> backbag - S["b_type"] >> b_type - S["accent"] >> accent - S["voice"] >> voice - S["pitch"] >> pitch - S["talkspeed"] >> talkspeed - - //Jobs - S["alternate_option"] >> alternate_option - S["job_civilian_high"] >> job_civilian_high - S["job_civilian_med"] >> job_civilian_med - S["job_civilian_low"] >> job_civilian_low - S["job_medsci_high"] >> job_medsci_high - S["job_medsci_med"] >> job_medsci_med - S["job_medsci_low"] >> job_medsci_low - S["job_engsec_high"] >> job_engsec_high - S["job_engsec_med"] >> job_engsec_med - S["job_engsec_low"] >> job_engsec_low - S["job_karma_high"] >> job_karma_high - S["job_karma_med"] >> job_karma_med - S["job_karma_low"] >> job_karma_low - - //Miscellaneous - S["flavor_text"] >> flavor_text - S["med_record"] >> med_record - S["sec_record"] >> sec_record - S["gen_record"] >> gen_record - S["be_special"] >> be_special - S["disabilities"] >> disabilities - S["player_alt_titles"] >> player_alt_titles - S["organ_data"] >> organ_data - - S["nanotrasen_relation"] >> nanotrasen_relation - //S["skin_style"] >> skin_style - - //Sanitize - metadata = sanitize_text(metadata, initial(metadata)) - real_name = reject_bad_name(real_name) - if(isnull(species)) species = "Human" - if(isnull(language)) language = "None" - if(isnull(nanotrasen_relation)) nanotrasen_relation = initial(nanotrasen_relation) - 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) - age = sanitize_integer(age, AGE_MIN, AGE_MAX, initial(age)) - r_hair = sanitize_integer(r_hair, 0, 255, initial(r_hair)) - g_hair = sanitize_integer(g_hair, 0, 255, initial(g_hair)) - b_hair = sanitize_integer(b_hair, 0, 255, initial(b_hair)) - r_facial = sanitize_integer(r_facial, 0, 255, initial(r_facial)) - g_facial = sanitize_integer(g_facial, 0, 255, initial(g_facial)) - b_facial = sanitize_integer(b_facial, 0, 255, initial(b_facial)) - s_tone = sanitize_integer(s_tone, -185, 34, initial(s_tone)) - r_skin = sanitize_integer(r_skin, 0, 255, initial(r_skin)) - g_skin = sanitize_integer(g_skin, 0, 255, initial(g_skin)) - b_skin = sanitize_integer(b_skin, 0, 255, initial(b_skin)) - h_style = sanitize_inlist(h_style, hair_styles_list, initial(h_style)) - f_style = sanitize_inlist(f_style, facial_hair_styles_list, initial(f_style)) - r_eyes = sanitize_integer(r_eyes, 0, 255, initial(r_eyes)) - g_eyes = sanitize_integer(g_eyes, 0, 255, initial(g_eyes)) - b_eyes = sanitize_integer(b_eyes, 0, 255, initial(b_eyes)) - underwear = sanitize_integer(underwear, 1, underwear_m.len, initial(underwear)) - undershirt = sanitize_integer(undershirt, 1, undershirt_t.len, initial(undershirt)) - socks = sanitize_integer(socks,1 socks_t.len, initial(socks)) - backbag = sanitize_integer(backbag, 1, backbaglist.len, initial(backbag)) - b_type = sanitize_text(b_type, initial(b_type)) - accent = sanitize_text(accent, initial(accent)) - voice = sanitize_text(voice, initial(voice)) - pitch = sanitize_text(pitch, initial(pitch)) - talkspeed = sanitize_text(talkspeed, initial(talkspeed)) - - alternate_option = sanitize_integer(alternate_option, 0, 2, initial(alternate_option)) - job_civilian_high = sanitize_integer(job_civilian_high, 0, 65535, initial(job_civilian_high)) - job_civilian_med = sanitize_integer(job_civilian_med, 0, 65535, initial(job_civilian_med)) - job_civilian_low = sanitize_integer(job_civilian_low, 0, 65535, initial(job_civilian_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)) - - if(isnull(disabilities)) disabilities = 0 - if(!player_alt_titles) player_alt_titles = new() - if(!organ_data) src.organ_data = list() - //if(!skin_style) skin_style = "Default" - -/datum/preferences/proc/random_character() - if(!path) return 0 - if(!fexists(path)) return 0 - var/savefile/S = new /savefile(path) - if(!S) return 0 - var/list/saves = list() - var/name - for(var/i=1, i<=MAX_SAVE_SLOTS, i++) - S.cd = "/character[i]" - S["real_name"] >> name - if(!name) continue - saves.Add(S.cd) - - if(!saves.len) - load_character() - return 0 - S.cd = pick(saves) - load_save(S.cd) - return 1 -/* -/datum/preferences/proc/load_character(slot) - if(!path) return 0 - if(!fexists(path)) return 0 - var/savefile/S = new /savefile(path) - if(!S) return 0 - S.cd = "/" - if(!slot) slot = default_slot - slot = sanitize_integer(slot, 1, MAX_SAVE_SLOTS, initial(default_slot)) - if(slot != default_slot) - default_slot = slot - S["default_slot"] << slot - S.cd = "/character[slot]" - load_save(S.cd) - Now loaded by proc load_save(S.cd) - //Character - S["OOC_Notes"] >> metadata - S["real_name"] >> real_name - S["name_is_always_random"] >> be_random_name - S["gender"] >> gender - S["age"] >> age - S["species"] >> species - S["language"] >> language - - //colors to be consolidated into hex strings (requires some work with dna code) - S["hair_red"] >> r_hair - S["hair_green"] >> g_hair - S["hair_blue"] >> b_hair - S["facial_red"] >> r_facial - S["facial_green"] >> g_facial - S["facial_blue"] >> b_facial - S["skin_tone"] >> s_tone - S["skin_red"] >> r_skin - S["skin_green"] >> g_skin - S["skin_blue"] >> b_skin - S["hair_style_name"] >> h_style - S["facial_style_name"] >> f_style - S["eyes_red"] >> r_eyes - S["eyes_green"] >> g_eyes - S["eyes_blue"] >> b_eyes - S["underwear"] >> underwear - S["undershirt"] >> undershirt - S["backbag"] >> backbag - S["b_type"] >> b_type - - //Jobs - S["alternate_option"] >> alternate_option - S["job_civilian_high"] >> job_civilian_high - S["job_civilian_med"] >> job_civilian_med - S["job_civilian_low"] >> job_civilian_low - S["job_medsci_high"] >> job_medsci_high - S["job_medsci_med"] >> job_medsci_med - S["job_medsci_low"] >> job_medsci_low - S["job_engsec_high"] >> job_engsec_high - S["job_engsec_med"] >> job_engsec_med - S["job_engsec_low"] >> job_engsec_low - - //Miscellaneous - S["flavor_text"] >> flavor_text - S["med_record"] >> med_record - S["sec_record"] >> sec_record - S["gen_record"] >> gen_record - S["be_special"] >> be_special - S["disabilities"] >> disabilities - S["player_alt_titles"] >> player_alt_titles - S["organ_data"] >> organ_data - - S["nanotrasen_relation"] >> nanotrasen_relation - //S["skin_style"] >> skin_style - - - //Sanitize - metadata = sanitize_text(metadata, initial(metadata)) - real_name = reject_bad_name(real_name) - if(isnull(species)) species = "Human" - if(isnull(language)) language = "None" - if(isnull(spawnpoint)) spawnpoint = "Arrivals Shuttle" - if(isnull(nanotrasen_relation)) nanotrasen_relation = initial(nanotrasen_relation) - if(!real_name) real_name = random_name(gender) - be_random_name = sanitize_integer(be_random_name, 0, 1, initial(be_random_name)) - gender = sanitize_gender(gender) - age = sanitize_integer(age, AGE_MIN, AGE_MAX, initial(age)) - r_hair = sanitize_integer(r_hair, 0, 255, initial(r_hair)) - g_hair = sanitize_integer(g_hair, 0, 255, initial(g_hair)) - b_hair = sanitize_integer(b_hair, 0, 255, initial(b_hair)) - r_facial = sanitize_integer(r_facial, 0, 255, initial(r_facial)) - g_facial = sanitize_integer(g_facial, 0, 255, initial(g_facial)) - b_facial = sanitize_integer(b_facial, 0, 255, initial(b_facial)) - s_tone = sanitize_integer(s_tone, -185, 34, initial(s_tone)) - r_skin = sanitize_integer(r_skin, 0, 255, initial(r_skin)) - g_skin = sanitize_integer(g_skin, 0, 255, initial(g_skin)) - b_skin = sanitize_integer(b_skin, 0, 255, initial(b_skin)) - h_style = sanitize_inlist(h_style, hair_styles_list, initial(h_style)) - f_style = sanitize_inlist(f_style, facial_hair_styles_list, initial(f_style)) - r_eyes = sanitize_integer(r_eyes, 0, 255, initial(r_eyes)) - g_eyes = sanitize_integer(g_eyes, 0, 255, initial(g_eyes)) - b_eyes = sanitize_integer(b_eyes, 0, 255, initial(b_eyes)) - underwear = sanitize_integer(underwear, 1, underwear_m.len, initial(underwear)) - undershirt = sanitize_integer(undershirt, 1, undershirt_t.len, initial(undershirt)) - backbag = sanitize_integer(backbag, 1, backbaglist.len, initial(backbag)) - b_type = sanitize_text(b_type, initial(b_type)) - - alternate_option = sanitize_integer(alternate_option, 0, 2, initial(alternate_option)) - job_civilian_high = sanitize_integer(job_civilian_high, 0, 65535, initial(job_civilian_high)) - job_civilian_med = sanitize_integer(job_civilian_med, 0, 65535, initial(job_civilian_med)) - job_civilian_low = sanitize_integer(job_civilian_low, 0, 65535, initial(job_civilian_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)) - - if(isnull(disabilities)) disabilities = 0 - if(!player_alt_titles) player_alt_titles = new() - if(!organ_data) src.organ_data = list() - //if(!skin_style) skin_style = "Default" - - return 1 - -/datum/preferences/proc/save_character() - if(!path) return 0 - var/savefile/S = new /savefile(path) - if(!S) return 0 - S.cd = "/character[default_slot]" - - //Character - S["OOC_Notes"] << metadata - S["real_name"] << real_name - S["name_is_always_random"] << be_random_name - S["gender"] << gender - S["age"] << age - S["species"] << species - S["language"] << language - S["hair_red"] << r_hair - S["hair_green"] << g_hair - S["hair_blue"] << b_hair - S["facial_red"] << r_facial - S["facial_green"] << g_facial - S["facial_blue"] << b_facial - S["skin_tone"] << s_tone - S["skin_red"] << r_skin - S["skin_green"] << g_skin - S["skin_blue"] << b_skin - S["hair_style_name"] << h_style - S["facial_style_name"] << f_style - S["eyes_red"] << r_eyes - S["eyes_green"] << g_eyes - S["eyes_blue"] << b_eyes - S["underwear"] << underwear - S["undershirt"] << undershirt - S["backbag"] << backbag - S["b_type"] << b_type - S["accent"] << accent - S["voice"] << voice - S["pitch"] << pitch - S["talkspeed"] << talkspeed - - //Jobs - S["alternate_option"] << alternate_option - S["job_civilian_high"] << job_civilian_high - S["job_civilian_med"] << job_civilian_med - S["job_civilian_low"] << job_civilian_low - S["job_medsci_high"] << job_medsci_high - S["job_medsci_med"] << job_medsci_med - S["job_medsci_low"] << job_medsci_low - S["job_engsec_high"] << job_engsec_high - S["job_engsec_med"] << job_engsec_med - S["job_engsec_low"] << job_engsec_low - S["job_karma_high"] << job_karma_high - S["job_karma_med"] << job_karma_med - S["job_karma_low"] << job_karma_low - - //Miscellaneous - S["flavor_text"] << flavor_text - S["med_record"] << med_record - S["sec_record"] << sec_record - S["gen_record"] << gen_record - S["player_alt_titles"] << player_alt_titles - S["be_special"] << be_special - S["disabilities"] << disabilities - S["organ_data"] << organ_data - - S["nanotrasen_relation"] << nanotrasen_relation - //S["skin_style"] << skin_style - - return 1 -*/ - -#undef SAVEFILE_VERSION_MAX -#undef SAVEFILE_VERSION_MIN From a7675c79c3c9c9aa02a31b91f555e731c58fa9bf Mon Sep 17 00:00:00 2001 From: Crazylemon Date: Sun, 27 Dec 2015 06:39:20 -0800 Subject: [PATCH 03/19] Now to fix the compiling errors, travis does this super fast --- code/game/gamemodes/autotraitor/autotraitor.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/gamemodes/autotraitor/autotraitor.dm b/code/game/gamemodes/autotraitor/autotraitor.dm index bc9f83d88e0..06b09867e6e 100644 --- a/code/game/gamemodes/autotraitor/autotraitor.dm +++ b/code/game/gamemodes/autotraitor/autotraitor.dm @@ -160,7 +160,7 @@ if(shuttle_master.emergency.mode >= SHUTTLE_ESCAPE) return //message_admins("Late Join Check") - if((character.client && (ROLE_TRAITOR in character.client.prefs.be_special) && !jobban_isbanned(character, "traitor") && !jobban_isbanned(character, "Syndicate")) + if(character.client && (ROLE_TRAITOR in character.client.prefs.be_special) && !jobban_isbanned(character, "traitor") && !jobban_isbanned(character, "Syndicate")) //message_admins("Late Joiner has Be Syndicate") //message_admins("Checking number of players") var/playercount = 0 From c227ae536c566fbe2757a9c3e90a7df48dfc7802 Mon Sep 17 00:00:00 2001 From: Crazylemon Date: Sun, 27 Dec 2015 07:58:21 -0800 Subject: [PATCH 04/19] Added a bunch of new antag tags because whee these are cheap Also it compiles now as for not turning the DB into mush... wait on that "feature" --- code/__DEFINES/role_preferences.dm | 16 +- code/game/jobs/job_controller.dm | 2 +- code/modules/client/preferences.dm | 2605 +++++++++-------- code/modules/client/preferences_mysql.dm | 6 +- code/modules/events/alien_infestation.dm | 4 +- code/modules/events/borers.dm | 4 +- code/modules/events/slaughterevent.dm | 3 +- .../carbon/alien/special/alien_embryo.dm | 2 +- .../mob/living/carbon/brain/posibrain.dm | 7 +- .../mob/living/carbon/metroid/metroid.dm | 2 +- .../modules/mob/living/simple_animal/borer.dm | 16 +- .../living/simple_animal/guardian/guardian.dm | 2 +- .../living/simple_animal/revenant/revenant.dm | 2 +- .../revenant/revenant_spawn_event.dm | 2 +- 14 files changed, 1341 insertions(+), 1332 deletions(-) diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index 6d2cfe702ed..817f3e7a76a 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -27,6 +27,12 @@ #define ROLE_RAIDER "vox raider" #define ROLE_VAMPIRE "vampire" #define ROLE_MUTINEER "mutineer" +// Role tags for EVERYONE! +#define ROLE_BORER "cortical borer" +#define ROLE_DEMON "slaughter demon" +#define ROLE_SENTIENT "sentient animal" +#define ROLE_POSIBRAIN "positronic brain" +#define ROLE_GUARDIAN "guardian" //Missing assignment means it's not a gamemode specific role, IT'S NOT A BUG OR ERROR. @@ -44,13 +50,17 @@ var/global/list/special_roles = list( ROLE_CULTIST = /datum/game_mode/cult, ROLE_BLOB = /datum/game_mode/blob, ROLE_NINJA, - ROLE_MONKEY = /datum/game_mode/monkey, - ROLE_GANG = /datum/game_mode/gang, +// ROLE_MONKEY = /datum/game_mode/monkey, Sooner or later these are going to get ported +// ROLE_GANG = /datum/game_mode/gang, ROLE_SHADOWLING = /datum/game_mode/shadowling, - ROLE_ABDUCTOR = /datum/game_mode/abduction, +// ROLE_ABDUCTOR = /datum/game_mode/abduction, // ROLE_HOG_GOD = /datum/game_mode/hand_of_god, // ROLE_HOG_CULTIST = /datum/game_mode/hand_of_god, ROLE_RAIDER = /datum/game_mode/heist, ROLE_VAMPIRE = /datum/game_mode/vampire, ROLE_MUTINEER = /datum/game_mode/mutiny, + ROLE_BORER, + ROLE_DEMON, + ROLE_SENTIENT, + ROLE_POSIBRAIN, ) diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm index f25fd419da8..f5dc80dcae7 100644 --- a/code/game/jobs/job_controller.dm +++ b/code/game/jobs/job_controller.dm @@ -94,7 +94,7 @@ var/global/datum/controller/occupations/job_master if(!job.player_old_enough(player.client)) Debug("FOC player not old enough, Player: [player]") continue - if(flag && (!(flag in player.client.prefs.be_special)) + if(flag && !(flag in player.client.prefs.be_special)) Debug("FOC flag failed, Player: [player], Flag: [flag], ") continue if(player.mind && job.title in player.mind.restricted_roles) diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 81669e556c6..792482643ef 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -194,1004 +194,881 @@ datum/preferences // Hello I am a proc full of snowflake species checks how are you /datum/preferences/proc/ShowChoices(mob/user) - if(!user || !user.client) return - update_preview_icon() - user << browse_rsc(preview_icon_front, "previewicon.png") - user << browse_rsc(preview_icon_side, "previewicon2.png") - var/dat = "
" + if(!user || !user.client) return + update_preview_icon() + user << browse_rsc(preview_icon_front, "previewicon.png") + user << browse_rsc(preview_icon_side, "previewicon2.png") + var/dat = "
" - dat += "Character Settings" - dat += "Game Preferences" - dat += "
" - dat += "
" + dat += "Character Settings" + dat += "Game Preferences" + dat += "
" + dat += "
" - switch(current_tab) - if (0) // Character Settings# - dat += "
" - dat += "Slot [slot_name] - " - dat += "Load slot - " - dat += "Save slot - " - dat += "Reload slot" - dat += "
" - dat += "

Occupation Choices

" - dat += "Set Occupation Preferences
" - dat += "

Identity

" - dat += "
" - if(appearance_isbanned(user)) - dat += "You are banned from using custom names and appearances. You can continue to adjust your characters, but you will be randomised once you join the game.
" - dat += "Name: " - dat += "[real_name]
" - dat += "(Random Name) " - dat += "(Always Random Name: [be_random_name ? "Yes" : "No"])" - dat += "
" - dat += "Gender: [gender == MALE ? "Male" : "Female"]
" - dat += "Age: [age]" - //dat += "Spawn Point: [spawnpoint]" - dat += "
Body " - dat += "(®)" - dat += "
" - dat += "Species: [species]
" - if(species == "Vox")//oldvox code, sucks I know - dat += "N2 Tank: [speciesprefs ? "Large N2 Tank" : "Specialized N2 Tank"]
" - dat += "Secondary Language:
[language]
" - dat += "Blood Type: [b_type]
" - if(species == "Human") - dat += "Skin Tone: [-s_tone + 35]/220
" + switch(current_tab) + if (0) // Character Settings# + dat += "
" + dat += "Slot [slot_name] - " + dat += "Load slot - " + dat += "Save slot - " + dat += "Reload slot" + dat += "
" + dat += "

Occupation Choices

" + dat += "Set Occupation Preferences
" + dat += "

Identity

" + dat += "
" + if(appearance_isbanned(user)) + dat += "You are banned from using custom names and appearances. You can continue to adjust your characters, but you will be randomised once you join the game.
" + dat += "Name: " + dat += "[real_name]
" + dat += "(Random Name) " + dat += "(Always Random Name: [be_random_name ? "Yes" : "No"])" + dat += "
" + dat += "Gender: [gender == MALE ? "Male" : "Female"]
" + dat += "Age: [age]" + //dat += "Spawn Point: [spawnpoint]" + dat += "
Body " + dat += "(®)" + dat += "
" + dat += "Species: [species]
" + if(species == "Vox")//oldvox code, sucks I know + dat += "N2 Tank: [speciesprefs ? "Large N2 Tank" : "Specialized N2 Tank"]
" + dat += "Secondary Language:
[language]
" + dat += "Blood Type: [b_type]
" + if(species == "Human") + dat += "Skin Tone: [-s_tone + 35]/220
" - // dat += "Skin pattern: Adjust
" - dat += "
Handicaps
" - dat += "\t\[Set Disabilities\]
" - dat += "Limbs: Adjust
" - if(species != "Slime People" && species != "Machine") - dat += "Internal Organs: Adjust
" + // dat += "Skin pattern: Adjust
" + dat += "
Handicaps
" + dat += "\t\[Set Disabilities\]
" + dat += "Limbs: Adjust
" + if(species != "Slime People" && species != "Machine") + dat += "Internal Organs: Adjust
" - //display limbs below - var/ind = 0 - for(var/name in organ_data) - //world << "[ind] \ [organ_data.len]" - var/status = organ_data[name] - var/organ_name = null - switch(name) - if("l_arm") - organ_name = "left arm" - if("r_arm") - organ_name = "right arm" - if("l_leg") - organ_name = "left leg" - if("r_leg") - organ_name = "right leg" - if("l_foot") - organ_name = "left foot" - if("r_foot") - organ_name = "right foot" - if("l_hand") - organ_name = "left hand" - if("r_hand") - organ_name = "right hand" - if("heart") - organ_name = "heart" - if("eyes") - organ_name = "eyes" + //display limbs below + var/ind = 0 + for(var/name in organ_data) + //world << "[ind] \ [organ_data.len]" + var/status = organ_data[name] + var/organ_name = null + switch(name) + if("l_arm") + organ_name = "left arm" + if("r_arm") + organ_name = "right arm" + if("l_leg") + organ_name = "left leg" + if("r_leg") + organ_name = "right leg" + if("l_foot") + organ_name = "left foot" + if("r_foot") + organ_name = "right foot" + if("l_hand") + organ_name = "left hand" + if("r_hand") + organ_name = "right hand" + if("heart") + organ_name = "heart" + if("eyes") + organ_name = "eyes" - if(status == "cyborg") - ++ind - if(ind > 1) - dat += ", " - var/datum/robolimb/R - if(rlimb_data[name] && all_robolimbs[rlimb_data[name]]) - R = all_robolimbs[rlimb_data[name]] - else - R = basic_robolimb - dat += "\t[R.company] [organ_name] prothesis" - - - else if(status == "amputated") - ++ind - if(ind > 1) - dat += ", " - dat += "\tAmputated [organ_name]" - - else if(status == "mechanical") - ++ind - if(ind > 1) - dat += ", " - dat += "\tMechanical [organ_name]" - - else if(status == "assisted") - ++ind - if(ind > 1) - dat += ", " - switch(organ_name) - if("heart") - dat += "\tPacemaker-assisted [organ_name]" - if("voicebox") //on adding voiceboxes for speaking skrell/similar replacements - dat += "\tSurgically altered [organ_name]" - if("eyes") - dat += "\tRetinal overlayed [organ_name]" - else - dat += "\tMechanically assisted [organ_name]" - if(!ind) - dat += "\[...\]

" - else - dat += "

" - dat += "Underwear:
[underwear]
" - dat += "Undershirt:
[undershirt]
" - dat += "Socks:
[socks]
" - dat += "Backpack Type:
[backbaglist[backbag]]
" - dat += "Nanotrasen Relation:
[nanotrasen_relation]
" - dat += "
Preview
" - dat += "
" - - if(jobban_isbanned(user, "Records")) - dat += "You are banned from using character records.
" - else - dat += "Character Records
" - dat += "Set Flavor Text
" - if(lentext(flavor_text) <= 40) - if(!lentext(flavor_text)) - dat += "\[...\]" + if(status == "cyborg") + ++ind + if(ind > 1) + dat += ", " + var/datum/robolimb/R + if(rlimb_data[name] && all_robolimbs[rlimb_data[name]]) + R = all_robolimbs[rlimb_data[name]] else - dat += "[flavor_text]" - else - dat += "[TextPreview(flavor_text)]...
" - dat += "
" + R = basic_robolimb + dat += "\t[R.company] [organ_name] prothesis" - var/hairname = "Hair" - if(species == "Machine") - hairname = "Frame Color" - dat += "
[hairname]
" - dat += "Change Color
__
" - dat += "
Style: [h_style]
" - dat += "
Facial
" - dat += "Change Color
__
" - dat += "
Style: [f_style]
" + else if(status == "amputated") + ++ind + if(ind > 1) + dat += ", " + dat += "\tAmputated [organ_name]" - dat += "
Eyes
" - dat += "Change Color
__

" + else if(status == "mechanical") + ++ind + if(ind > 1) + dat += ", " + dat += "\tMechanical [organ_name]" - if((species in list("Unathi", "Tajaran", "Skrell", "Slime People", "Vulpkanin", "Machine")) || body_accessory_by_species[species] || check_rights(R_ADMIN, 0, user)) //admins can always fuck with this, because they are admins - dat += "
Body Color
" - dat += "Change Color
__
" - - if(body_accessory_by_species[species] || check_rights(R_ADMIN, 0, user)) - dat += "
Body Accessory
" - dat += "Accessory: [body_accessory ? "[body_accessory]" : "None"]
" - - dat += "

" - - if (1) // General Preferences - dat += "
" - dat += "

General Settings

" - dat += "UI Style: [UI_style]
" - dat += "Custom UI settings:
" - dat += "Color: [UI_style_color]
__

" - dat += "Alpha (transparency): [UI_style_alpha]
" - dat += "Play admin midis: [(sound & SOUND_MIDI) ? "Yes" : "No"]
" - dat += "Play lobby music: [(sound & SOUND_LOBBY) ? "Yes" : "No"]
" - dat += "Randomized character slot: [randomslot ? "Yes" : "No"]
" - dat += "Ghost ears: [(toggles & CHAT_GHOSTEARS) ? "Nearest Creatures" : "All Speech"]
" - dat += "Ghost sight: [(toggles & CHAT_GHOSTSIGHT) ? "Nearest Creatures" : "All Emotes"]
" - dat += "Ghost radio: [(toggles & CHAT_GHOSTRADIO) ? "Nearest Speakers" : "All Chatter"]
" - if(config.allow_Metadata) - dat += "OOC notes: Edit
" - - if(user.client) - if(user.client.holder) - dat += "Adminhelp sound: " - dat += "[(sound & SOUND_ADMINHELP)?"On":"Off"]
" - - if(check_rights(R_ADMIN,0)) - dat += "OOC:     Change
" - - if(unlock_content) - dat += "BYOND Membership Publicity: [(toggles & MEMBER_PUBLIC) ? "Public" : "Hidden"]
" - - dat += "
" - dat += "

Special Role Settings

" -// dat += "

" - if(jobban_isbanned(user, "Syndicate")) - dat += "You are banned from special roles." - src.be_special = list() - else - for (var/i in special_roles) - if(jobban_isbanned(user, i)) - dat += "Be [capitalize(i)]: \[BANNED]
" - else if(!player_old_enough_antag(user.client,i)) - var/available_in_days_antag = available_in_days_antag(user.client,i) - dat += "Be [capitalize(i)]: \[IN [(available_in_days_antag)] DAYS]
" + else if(status == "assisted") + ++ind + if(ind > 1) + dat += ", " + switch(organ_name) + if("heart") + dat += "\tPacemaker-assisted [organ_name]" + if("voicebox") //on adding voiceboxes for speaking skrell/similar replacements + dat += "\tSurgically altered [organ_name]" + if("eyes") + dat += "\tRetinal overlayed [organ_name]" else - dat += "Be [capitalize(i)]: [(i in src.be_special) ? "Yes" : "No"]
" - dat += "

" + dat += "\tMechanically assisted [organ_name]" + if(!ind) + dat += "\[...\]

" + else + dat += "

" + dat += "Underwear:
[underwear]
" + dat += "Undershirt:
[undershirt]
" + dat += "Socks:
[socks]
" + dat += "Backpack Type:
[backbaglist[backbag]]
" + dat += "Nanotrasen Relation:
[nanotrasen_relation]
" + dat += "
Preview
" + dat += "
" - if(!IsGuestKey(user.key)) - dat += "Undo - " - dat += "Save Setup - " + if(jobban_isbanned(user, "Records")) + dat += "You are banned from using character records.
" + else + dat += "Character Records
" + dat += "Set Flavor Text
" + if(lentext(flavor_text) <= 40) + if(!lentext(flavor_text)) + dat += "\[...\]" + else + dat += "[flavor_text]" + else + dat += "[TextPreview(flavor_text)]...
" + dat += "
" - dat += "Reset Setup" - dat += "" + var/hairname = "Hair" + if(species == "Machine") + hairname = "Frame Color" + dat += "
[hairname]
" + dat += "Change Color
__
" + dat += "
Style: [h_style]
" + + dat += "
Facial
" + dat += "Change Color
__
" + dat += "
Style: [f_style]
" + + dat += "
Eyes
" + dat += "Change Color
__

" + + if((species in list("Unathi", "Tajaran", "Skrell", "Slime People", "Vulpkanin", "Machine")) || body_accessory_by_species[species] || check_rights(R_ADMIN, 0, user)) //admins can always fuck with this, because they are admins + dat += "
Body Color
" + dat += "Change Color
__
" + + if(body_accessory_by_species[species] || check_rights(R_ADMIN, 0, user)) + dat += "
Body Accessory
" + dat += "Accessory: [body_accessory ? "[body_accessory]" : "None"]
" + + dat += "

" + + if (1) // General Preferences + dat += "
" + dat += "

General Settings

" + dat += "UI Style: [UI_style]
" + dat += "Custom UI settings:
" + dat += "Color: [UI_style_color]
__

" + dat += "Alpha (transparency): [UI_style_alpha]
" + dat += "Play admin midis: [(sound & SOUND_MIDI) ? "Yes" : "No"]
" + dat += "Play lobby music: [(sound & SOUND_LOBBY) ? "Yes" : "No"]
" + dat += "Randomized character slot: [randomslot ? "Yes" : "No"]
" + dat += "Ghost ears: [(toggles & CHAT_GHOSTEARS) ? "Nearest Creatures" : "All Speech"]
" + dat += "Ghost sight: [(toggles & CHAT_GHOSTSIGHT) ? "Nearest Creatures" : "All Emotes"]
" + dat += "Ghost radio: [(toggles & CHAT_GHOSTRADIO) ? "Nearest Speakers" : "All Chatter"]
" + if(config.allow_Metadata) + dat += "OOC notes: Edit
" + + if(user.client) + if(user.client.holder) + dat += "Adminhelp sound: " + dat += "[(sound & SOUND_ADMINHELP)?"On":"Off"]
" + + if(check_rights(R_ADMIN,0)) + dat += "OOC:     Change
" + + if(unlock_content) + dat += "BYOND Membership Publicity: [(toggles & MEMBER_PUBLIC) ? "Public" : "Hidden"]
" + + dat += "
" + dat += "

Special Role Settings

" +// dat += "

" + if(jobban_isbanned(user, "Syndicate")) + dat += "You are banned from special roles." + src.be_special = list() + else + for (var/i in special_roles) + if(jobban_isbanned(user, i)) + dat += "Be [capitalize(i)]: \[BANNED]
" + else if(!player_old_enough_antag(user.client,i)) + var/available_in_days_antag = available_in_days_antag(user.client,i) + dat += "Be [capitalize(i)]: \[IN [(available_in_days_antag)] DAYS]
" + else + dat += "Be [capitalize(i)]: [(i in src.be_special) ? "Yes" : "No"]
" + dat += "

" + + if(!IsGuestKey(user.key)) + dat += "Undo - " + dat += "Save Setup - " + + dat += "Reset Setup" + dat += "
" // user << browse(dat, "window=preferences;size=560x580") - var/datum/browser/popup = new(user, "preferences", "
Character Setup
", 640, 810) - popup.set_content(dat) - popup.open(0) + var/datum/browser/popup = new(user, "preferences", "
Character Setup
", 640, 810) + popup.set_content(dat) + popup.open(0) - proc/SetChoices(mob/user, limit = 12, list/splitJobs = list("Civilian","Research Director","AI","Bartender"), width = 760, height = 790) - if(!job_master) - return +/datum/preferences/proc/SetChoices(mob/user, limit = 12, list/splitJobs = list("Civilian","Research Director","AI","Bartender"), width = 760, height = 790) + if(!job_master) + return - //limit - The amount of jobs allowed per column. Defaults to 17 to make it look nice. - //splitJobs - Allows you split the table by job. You can make different tables for each department by including their heads. Defaults to CE to make it look nice. - //width - Screen' width. Defaults to 550 to make it look nice. - //height - Screen's height. Defaults to 500 to make it look nice. + //limit - The amount of jobs allowed per column. Defaults to 17 to make it look nice. + //splitJobs - Allows you split the table by job. You can make different tables for each department by including their heads. Defaults to CE to make it look nice. + //width - Screen' width. Defaults to 550 to make it look nice. + //height - Screen's height. Defaults to 500 to make it look nice. - var/HTML = "" - HTML += "
" - HTML += "Choose occupation chances
Unavailable occupations are crossed out.

" - HTML += "
\[Done\]

" // Easier to press up here. - HTML += "
Left-click to raise an occupation preference, right-click to lower it.
" - HTML += "" - HTML += "" - switch(alternate_option) - if(GET_RANDOM_JOB) - HTML += "

Get random job if preferences unavailable

" - if(BE_CIVILIAN) - HTML += "

Be a civilian if preferences unavailable

" - if(RETURN_TO_LOBBY) - HTML += "

Return to lobby if preferences unavailable

" + for(var/i = 1, i < (limit - index), i += 1) // Finish the column so it is even + HTML += "" - HTML += "
\[Reset\]
" - HTML += "" + HTML += "
" // Table within a table for alignment, also allows you to easily add more colomns. - HTML += "" - var/index = -1 + var/HTML = "" + HTML += "
" + HTML += "Choose occupation chances
Unavailable occupations are crossed out.

" + HTML += "
\[Done\]

" // Easier to press up here. + HTML += "
Left-click to raise an occupation preference, right-click to lower it.
" + HTML += "" + HTML += "
" // Table within a table for alignment, also allows you to easily add more colomns. + HTML += "" + var/index = -1 - //The job before the current job. I only use this to get the previous jobs color when I'm filling in blank rows. - var/datum/job/lastJob - if (!job_master) return - for(var/datum/job/job in job_master.occupations) + //The job before the current job. I only use this to get the previous jobs color when I'm filling in blank rows. + var/datum/job/lastJob + if (!job_master) return + for(var/datum/job/job in job_master.occupations) - index += 1 - if((index >= limit) || (job.title in splitJobs)) - if((index < limit) && (lastJob != null)) - //If the cells were broken up by a job in the splitJob list then it will fill in the rest of the cells with - //the last job's selection color. Creating a rather nice effect. - for(var/i = 0, i < (limit - index), i += 1) - HTML += "" - HTML += "
  
" - index = 0 + index += 1 + if((index >= limit) || (job.title in splitJobs)) + if((index < limit) && (lastJob != null)) + //If the cells were broken up by a job in the splitJob list then it will fill in the rest of the cells with + //the last job's selection color. Creating a rather nice effect. + for(var/i = 0, i < (limit - index), i += 1) + HTML += "" + HTML += "
  
" + index = 0 - HTML += "" - continue - if(jobban_isbanned(user, rank)) - HTML += "[rank]" - continue - if(!job.player_old_enough(user.client)) - var/available_in_days = job.available_in_days(user.client) - HTML += "[rank]" - continue - if((job_support_low & CIVILIAN) && (rank != "Civilian")) - HTML += "[rank]" - continue - if((rank in command_positions) || (rank == "AI"))//Bold head jobs - HTML += "[rank]" - else - HTML += "[rank]" + HTML += "" + continue + if(jobban_isbanned(user, rank)) + HTML += "[rank]" + continue + if(!job.player_old_enough(user.client)) + var/available_in_days = job.available_in_days(user.client) + HTML += "[rank]" + continue + if((job_support_low & CIVILIAN) && (rank != "Civilian")) + HTML += "[rank]" + continue + if((rank in command_positions) || (rank == "AI"))//Bold head jobs + HTML += "[rank]" + else + HTML += "[rank]" - HTML += "" - HTML += "" - continue -/* - if(GetJobDepartment(job, 1) & job.flag) - HTML += " \[High]" - else if(GetJobDepartment(job, 2) & job.flag) - HTML += " \[Medium]" - else if(GetJobDepartment(job, 3) & job.flag) - HTML += " \[Low]" + if(rank == "Civilian")//Civilian is special + if(job_support_low & CIVILIAN) + HTML += " \[Yes]" else - HTML += " \[NEVER]" - */ - HTML += "[prefLevelLabel]" - + HTML += " \[No]" if(job.alt_titles) HTML += "
\[[GetPlayerAltTitle(job)]\]" - - HTML += "" + continue +/* + if(GetJobDepartment(job, 1) & job.flag) + HTML += " \[High]" + else if(GetJobDepartment(job, 2) & job.flag) + HTML += " \[Medium]" + else if(GetJobDepartment(job, 3) & job.flag) + HTML += " \[Low]" + else + HTML += " \[NEVER]" + */ + HTML += "[prefLevelLabel]" - for(var/i = 1, i < (limit - index), i += 1) // Finish the column so it is even - HTML += "" + if(job.alt_titles) + HTML += "
\[[GetPlayerAltTitle(job)]\]" - HTML += "
" - var/rank = job.title - lastJob = job - if(!is_job_whitelisted(user, rank)) - HTML += "[rank] \[KARMA]
\[BANNED]
\[IN [(available_in_days)] DAYS]
" + var/rank = job.title + lastJob = job + if(!is_job_whitelisted(user, rank)) + HTML += "[rank] \[KARMA]
\[BANNED]
\[IN [(available_in_days)] DAYS]
" + HTML += "" - var/prefLevelLabel = "ERROR" - var/prefLevelColor = "pink" - var/prefUpperLevel = -1 // level to assign on left click - var/prefLowerLevel = -1 // level to assign on right click + var/prefLevelLabel = "ERROR" + var/prefLevelColor = "pink" + var/prefUpperLevel = -1 // level to assign on left click + var/prefLowerLevel = -1 // level to assign on right click - if(GetJobDepartment(job, 1) & job.flag) - prefLevelLabel = "High" - prefLevelColor = "slateblue" - prefUpperLevel = 4 - prefLowerLevel = 2 - else if(GetJobDepartment(job, 2) & job.flag) - prefLevelLabel = "Medium" - prefLevelColor = "green" - prefUpperLevel = 1 - prefLowerLevel = 3 - else if(GetJobDepartment(job, 3) & job.flag) - prefLevelLabel = "Low" - prefLevelColor = "orange" - prefUpperLevel = 2 - prefLowerLevel = 4 - else - prefLevelLabel = "NEVER" - prefLevelColor = "red" - prefUpperLevel = 3 - prefLowerLevel = 1 + if(GetJobDepartment(job, 1) & job.flag) + prefLevelLabel = "High" + prefLevelColor = "slateblue" + prefUpperLevel = 4 + prefLowerLevel = 2 + else if(GetJobDepartment(job, 2) & job.flag) + prefLevelLabel = "Medium" + prefLevelColor = "green" + prefUpperLevel = 1 + prefLowerLevel = 3 + else if(GetJobDepartment(job, 3) & job.flag) + prefLevelLabel = "Low" + prefLevelColor = "orange" + prefUpperLevel = 2 + prefLowerLevel = 4 + else + prefLevelLabel = "NEVER" + prefLevelColor = "red" + prefUpperLevel = 3 + prefLowerLevel = 1 - HTML += "" + HTML += "" // HTML += "" - if(rank == "Civilian")//Civilian is special - if(job_support_low & CIVILIAN) - HTML += " \[Yes]" - else - HTML += " \[No]" - if(job.alt_titles) - HTML += "
\[[GetPlayerAltTitle(job)]\]
  
" - HTML += "
" + HTML += "
  
" - user << browse(null, "window=preferences") + HTML += "
" + + switch(alternate_option) + if(GET_RANDOM_JOB) + HTML += "

Get random job if preferences unavailable

" + if(BE_CIVILIAN) + HTML += "

Be a civilian if preferences unavailable

" + if(RETURN_TO_LOBBY) + HTML += "

Return to lobby if preferences unavailable

" + + HTML += "
\[Reset\]
" + HTML += "
" + + user << browse(null, "window=preferences") // user << browse(HTML, "window=mob_occupation;size=[width]x[height]") - var/datum/browser/popup = new(user, "mob_occupation", "
Occupation Preferences
", width, height) - popup.set_window_options("can_close=0") - popup.set_content(HTML) - popup.open(0) + var/datum/browser/popup = new(user, "mob_occupation", "
Occupation Preferences
", width, height) + popup.set_window_options("can_close=0") + popup.set_content(HTML) + popup.open(0) + return + +/datum/preferences/proc/SetJobPreferenceLevel(var/datum/job/job, var/level) + if (!job) + return 0 + + if (level == 1) // to high + // remove any other job(s) set to high + job_support_med |= job_support_high + job_engsec_med |= job_engsec_high + job_medsci_med |= job_medsci_high + job_karma_med |= job_karma_high + job_support_high = 0 + job_engsec_high = 0 + job_medsci_high = 0 + job_karma_high = 0 + + if (job.department_flag == SUPPORT) + job_support_low &= ~job.flag + job_support_med &= ~job.flag + job_support_high &= ~job.flag + + switch(level) + if (1) + job_support_high |= job.flag + if (2) + job_support_med |= job.flag + if (3) + job_support_low |= job.flag + + return 1 + else if (job.department_flag == ENGSEC) + job_engsec_low &= ~job.flag + job_engsec_med &= ~job.flag + job_engsec_high &= ~job.flag + + switch(level) + if (1) + job_engsec_high |= job.flag + if (2) + job_engsec_med |= job.flag + if (3) + job_engsec_low |= job.flag + + return 1 + else if (job.department_flag == MEDSCI) + job_medsci_low &= ~job.flag + job_medsci_med &= ~job.flag + job_medsci_high &= ~job.flag + + switch(level) + if (1) + job_medsci_high |= job.flag + if (2) + job_medsci_med |= job.flag + if (3) + job_medsci_low |= job.flag + + return 1 + else if (job.department_flag == KARMA) + job_karma_low &= ~job.flag + job_karma_med &= ~job.flag + job_karma_high &= ~job.flag + + switch(level) + if (1) + job_karma_high |= job.flag + if (2) + job_karma_med |= job.flag + if (3) + job_karma_low |= job.flag + + return 1 + + return 0 + +/datum/preferences/proc/UpdateJobPreference(mob/user, role, desiredLvl) + var/datum/job/job = job_master.GetJob(role) + + if(!job) + user << browse(null, "window=mob_occupation") + ShowChoices(user) return - proc/SetJobPreferenceLevel(var/datum/job/job, var/level) - if (!job) - return 0 + if (!isnum(desiredLvl)) + user << "\red UpdateJobPreference - desired level was not a number. Please notify coders!" + ShowChoices(user) + return - if (level == 1) // to high - // remove any other job(s) set to high + if(role == "Civilian") + if(job_support_low & job.flag) + job_support_low &= ~job.flag + else + job_support_low |= job.flag + SetChoices(user) + return 1 + + SetJobPreferenceLevel(job, desiredLvl) + SetChoices(user) + + return 1 + +/datum/preferences/proc/ShowDisabilityState(mob/user,flag,label) + if(flag==DISABILITY_FLAG_FAT && species!=("Human" || "Tajaran" || "Grey")) + return "
  • [species] cannot be fat.
  • " + return "
  • [label]: [disabilities & flag ? "Yes" : "No"]
  • " + +/datum/preferences/proc/SetDisabilities(mob/user) + var/HTML = "" + + // AUTOFIXED BY fix_string_idiocy.py + // C:\Users\Rob\Documents\Projects\vgstation13\code\modules\client\preferences.dm:474: HTML += "
    " + HTML += {"
    + Choose disabilities
      "} + // END AUTOFIX + HTML += ShowDisabilityState(user,DISABILITY_FLAG_NEARSIGHTED,"Needs Glasses") + HTML += ShowDisabilityState(user,DISABILITY_FLAG_FAT,"Obese") + HTML += ShowDisabilityState(user,DISABILITY_FLAG_EPILEPTIC,"Seizures") + HTML += ShowDisabilityState(user,DISABILITY_FLAG_DEAF,"Deaf") + HTML += ShowDisabilityState(user,DISABILITY_FLAG_BLIND,"Blind") + HTML += ShowDisabilityState(user,DISABILITY_FLAG_MUTE,"Mute") + + + // AUTOFIXED BY fix_string_idiocy.py + // C:\Users\Rob\Documents\Projects\vgstation13\code\modules\client\preferences.dm:481: HTML += "
    " + HTML += {" + \[Done\] + \[Reset\] +
    "} + // END AUTOFIX + user << browse(null, "window=preferences") + user << browse(HTML, "window=disabil;size=350x300") + return + +/datum/preferences/proc/SetRecords(mob/user) + var/HTML = "" + HTML += "
    " + HTML += "Set Character Records
    " + + HTML += "Medical Records
    " + + if(lentext(med_record) <= 40) + HTML += "[med_record]" + else + HTML += "[copytext(med_record, 1, 37)]..." + + HTML += "

    Employment Records
    " + + if(lentext(gen_record) <= 40) + HTML += "[gen_record]" + else + HTML += "[copytext(gen_record, 1, 37)]..." + + HTML += "

    Security Records
    " + + if(lentext(sec_record) <= 40) + HTML += "[sec_record]
    " + else + HTML += "[copytext(sec_record, 1, 37)]...
    " + + HTML += "
    " + HTML += "\[Done\]" + HTML += "
    " + + user << browse(null, "window=preferences") + user << browse(HTML, "window=records;size=350x300") + return + +/datum/preferences/proc/GetPlayerAltTitle(datum/job/job) + return player_alt_titles.Find(job.title) > 0 \ + ? player_alt_titles[job.title] \ + : job.title + +/datum/preferences/proc/SetPlayerAltTitle(datum/job/job, new_title) + // remove existing entry + if(player_alt_titles.Find(job.title)) + player_alt_titles -= job.title + // add one if it's not default + if(job.title != new_title) + player_alt_titles[job.title] = new_title + +/datum/preferences/proc/SetJob(mob/user, role) + var/datum/job/job = job_master.GetJob(role) + if(!job) + user << browse(null, "window=mob_occupation") + ShowChoices(user) + return + + if(role == "Civilian") + if(job_support_low & job.flag) + job_support_low &= ~job.flag + else + job_support_low |= job.flag + SetChoices(user) + return 1 + + if(GetJobDepartment(job, 1) & job.flag) + SetJobDepartment(job, 1) + else if(GetJobDepartment(job, 2) & job.flag) + SetJobDepartment(job, 2) + else if(GetJobDepartment(job, 3) & job.flag) + SetJobDepartment(job, 3) + else//job = Never + SetJobDepartment(job, 4) + + SetChoices(user) + return 1 + +/datum/preferences/proc/ResetJobs() + job_support_high = 0 + job_support_med = 0 + job_support_low = 0 + + job_medsci_high = 0 + job_medsci_med = 0 + job_medsci_low = 0 + + job_engsec_high = 0 + job_engsec_med = 0 + job_engsec_low = 0 + + job_karma_high = 0 + job_karma_med = 0 + job_karma_low = 0 + + +/datum/preferences/proc/GetJobDepartment(var/datum/job/job, var/level) + if(!job || !level) return 0 + switch(job.department_flag) + if(SUPPORT) + switch(level) + if(1) + return job_support_high + if(2) + return job_support_med + if(3) + return job_support_low + if(MEDSCI) + switch(level) + if(1) + return job_medsci_high + if(2) + return job_medsci_med + if(3) + return job_medsci_low + if(ENGSEC) + switch(level) + if(1) + return job_engsec_high + if(2) + return job_engsec_med + if(3) + return job_engsec_low + if(KARMA) + switch(level) + if(1) + return job_karma_high + if(2) + return job_karma_med + if(3) + return job_karma_low + return 0 + +/datum/preferences/proc/SetJobDepartment(var/datum/job/job, var/level) + if(!job || !level) return 0 + switch(level) + if(1)//Only one of these should ever be active at once so clear them all here + job_support_high = 0 + job_medsci_high = 0 + job_engsec_high = 0 + job_karma_high = 0 + return 1 + if(2)//Set current highs to med, then reset them job_support_med |= job_support_high - job_engsec_med |= job_engsec_high job_medsci_med |= job_medsci_high + job_engsec_med |= job_engsec_high job_karma_med |= job_karma_high job_support_high = 0 - job_engsec_high = 0 job_medsci_high = 0 + job_engsec_high = 0 job_karma_high = 0 - if (job.department_flag == SUPPORT) - job_support_low &= ~job.flag - job_support_med &= ~job.flag - job_support_high &= ~job.flag - + switch(job.department_flag) + if(SUPPORT) switch(level) - if (1) - job_support_high |= job.flag - if (2) + if(2) + job_support_high = job.flag + job_support_med &= ~job.flag + if(3) job_support_med |= job.flag - if (3) + job_support_low &= ~job.flag + else job_support_low |= job.flag - - return 1 - else if (job.department_flag == ENGSEC) - job_engsec_low &= ~job.flag - job_engsec_med &= ~job.flag - job_engsec_high &= ~job.flag - + if(MEDSCI) switch(level) - if (1) - job_engsec_high |= job.flag - if (2) - job_engsec_med |= job.flag - if (3) - job_engsec_low |= job.flag - - return 1 - else if (job.department_flag == MEDSCI) - job_medsci_low &= ~job.flag - job_medsci_med &= ~job.flag - job_medsci_high &= ~job.flag - - switch(level) - if (1) - job_medsci_high |= job.flag - if (2) + if(2) + job_medsci_high = job.flag + job_medsci_med &= ~job.flag + if(3) job_medsci_med |= job.flag - if (3) + job_medsci_low &= ~job.flag + else job_medsci_low |= job.flag - - return 1 - else if (job.department_flag == KARMA) - job_karma_low &= ~job.flag - job_karma_med &= ~job.flag - job_karma_high &= ~job.flag - + if(ENGSEC) switch(level) - if (1) - job_karma_high |= job.flag - if (2) + if(2) + job_engsec_high = job.flag + job_engsec_med &= ~job.flag + if(3) + job_engsec_med |= job.flag + job_engsec_low &= ~job.flag + else + job_engsec_low |= job.flag + if(KARMA) + switch(level) + if(2) + job_karma_high = job.flag + job_karma_med &= ~job.flag + if(3) job_karma_med |= job.flag - if (3) + job_karma_low &= ~job.flag + else job_karma_low |= job.flag + return 1 - return 1 +/datum/preferences/proc/process_link(mob/user, list/href_list) + if(!user) return - return 0 - - proc/UpdateJobPreference(mob/user, role, desiredLvl) - var/datum/job/job = job_master.GetJob(role) - - if(!job) - user << browse(null, "window=mob_occupation") - ShowChoices(user) - return - - if (!isnum(desiredLvl)) - user << "\red UpdateJobPreference - desired level was not a number. Please notify coders!" - ShowChoices(user) - return - - if(role == "Civilian") - if(job_support_low & job.flag) - job_support_low &= ~job.flag - else - job_support_low |= job.flag - SetChoices(user) - return 1 - - SetJobPreferenceLevel(job, desiredLvl) - SetChoices(user) - - return 1 - - proc/ShowDisabilityState(mob/user,flag,label) - if(flag==DISABILITY_FLAG_FAT && species!=("Human" || "Tajaran" || "Grey")) - return "
  • [species] cannot be fat.
  • " - return "
  • [label]: [disabilities & flag ? "Yes" : "No"]
  • " - - proc/SetDisabilities(mob/user) - var/HTML = "" - - // AUTOFIXED BY fix_string_idiocy.py - // C:\Users\Rob\Documents\Projects\vgstation13\code\modules\client\preferences.dm:474: HTML += "
    " - HTML += {"
    - Choose disabilities
      "} - // END AUTOFIX - HTML += ShowDisabilityState(user,DISABILITY_FLAG_NEARSIGHTED,"Needs Glasses") - HTML += ShowDisabilityState(user,DISABILITY_FLAG_FAT,"Obese") - HTML += ShowDisabilityState(user,DISABILITY_FLAG_EPILEPTIC,"Seizures") - HTML += ShowDisabilityState(user,DISABILITY_FLAG_DEAF,"Deaf") - HTML += ShowDisabilityState(user,DISABILITY_FLAG_BLIND,"Blind") - HTML += ShowDisabilityState(user,DISABILITY_FLAG_MUTE,"Mute") - - - // AUTOFIXED BY fix_string_idiocy.py - // C:\Users\Rob\Documents\Projects\vgstation13\code\modules\client\preferences.dm:481: HTML += "
    " - HTML += {" - \[Done\] - \[Reset\] -
    "} - // END AUTOFIX - user << browse(null, "window=preferences") - user << browse(HTML, "window=disabil;size=350x300") - return - - proc/SetRecords(mob/user) - var/HTML = "" - HTML += "
    " - HTML += "Set Character Records
    " - - HTML += "Medical Records
    " - - if(lentext(med_record) <= 40) - HTML += "[med_record]" - else - HTML += "[copytext(med_record, 1, 37)]..." - - HTML += "

    Employment Records
    " - - if(lentext(gen_record) <= 40) - HTML += "[gen_record]" - else - HTML += "[copytext(gen_record, 1, 37)]..." - - HTML += "

    Security Records
    " - - if(lentext(sec_record) <= 40) - HTML += "[sec_record]
    " - else - HTML += "[copytext(sec_record, 1, 37)]...
    " - - HTML += "
    " - HTML += "\[Done\]" - HTML += "
    " - - user << browse(null, "window=preferences") - user << browse(HTML, "window=records;size=350x300") - return - - proc/GetPlayerAltTitle(datum/job/job) - return player_alt_titles.Find(job.title) > 0 \ - ? player_alt_titles[job.title] \ - : job.title - - proc/SetPlayerAltTitle(datum/job/job, new_title) - // remove existing entry - if(player_alt_titles.Find(job.title)) - player_alt_titles -= job.title - // add one if it's not default - if(job.title != new_title) - player_alt_titles[job.title] = new_title - - proc/SetJob(mob/user, role) - var/datum/job/job = job_master.GetJob(role) - if(!job) - user << browse(null, "window=mob_occupation") - ShowChoices(user) - return - - if(role == "Civilian") - if(job_support_low & job.flag) - job_support_low &= ~job.flag - else - job_support_low |= job.flag - SetChoices(user) - return 1 - - if(GetJobDepartment(job, 1) & job.flag) - SetJobDepartment(job, 1) - else if(GetJobDepartment(job, 2) & job.flag) - SetJobDepartment(job, 2) - else if(GetJobDepartment(job, 3) & job.flag) - SetJobDepartment(job, 3) - else//job = Never - SetJobDepartment(job, 4) - - SetChoices(user) - return 1 - - proc/ResetJobs() - job_support_high = 0 - job_support_med = 0 - job_support_low = 0 - - job_medsci_high = 0 - job_medsci_med = 0 - job_medsci_low = 0 - - job_engsec_high = 0 - job_engsec_med = 0 - job_engsec_low = 0 - - job_karma_high = 0 - job_karma_med = 0 - job_karma_low = 0 - - - proc/GetJobDepartment(var/datum/job/job, var/level) - if(!job || !level) return 0 - switch(job.department_flag) - if(SUPPORT) - switch(level) - if(1) - return job_support_high - if(2) - return job_support_med - if(3) - return job_support_low - if(MEDSCI) - switch(level) - if(1) - return job_medsci_high - if(2) - return job_medsci_med - if(3) - return job_medsci_low - if(ENGSEC) - switch(level) - if(1) - return job_engsec_high - if(2) - return job_engsec_med - if(3) - return job_engsec_low - if(KARMA) - switch(level) - if(1) - return job_karma_high - if(2) - return job_karma_med - if(3) - return job_karma_low - return 0 - - proc/SetJobDepartment(var/datum/job/job, var/level) - if(!job || !level) return 0 - switch(level) - if(1)//Only one of these should ever be active at once so clear them all here - job_support_high = 0 - job_medsci_high = 0 - job_engsec_high = 0 - job_karma_high = 0 - return 1 - if(2)//Set current highs to med, then reset them - job_support_med |= job_support_high - job_medsci_med |= job_medsci_high - job_engsec_med |= job_engsec_high - job_karma_med |= job_karma_high - job_support_high = 0 - job_medsci_high = 0 - job_engsec_high = 0 - job_karma_high = 0 - - switch(job.department_flag) - if(SUPPORT) - switch(level) - if(2) - job_support_high = job.flag - job_support_med &= ~job.flag - if(3) - job_support_med |= job.flag - job_support_low &= ~job.flag - else - job_support_low |= job.flag - if(MEDSCI) - switch(level) - if(2) - job_medsci_high = job.flag - job_medsci_med &= ~job.flag - if(3) - job_medsci_med |= job.flag - job_medsci_low &= ~job.flag - else - job_medsci_low |= job.flag - if(ENGSEC) - switch(level) - if(2) - job_engsec_high = job.flag - job_engsec_med &= ~job.flag - if(3) - job_engsec_med |= job.flag - job_engsec_low &= ~job.flag - else - job_engsec_low |= job.flag - if(KARMA) - switch(level) - if(2) - job_karma_high = job.flag - job_karma_med &= ~job.flag - if(3) - job_karma_med |= job.flag - job_karma_low &= ~job.flag - else - job_karma_low |= job.flag - return 1 - - proc/process_link(mob/user, list/href_list) - if(!user) return - - if(href_list["preference"] == "job") - switch(href_list["task"]) - if("close") - user << browse(null, "window=mob_occupation") - ShowChoices(user) - if("reset") - ResetJobs() - SetChoices(user) - if("random") - if(alternate_option == GET_RANDOM_JOB || alternate_option == BE_CIVILIAN) - alternate_option += 1 - else if(alternate_option == RETURN_TO_LOBBY) - alternate_option = 0 - else - return 0 - SetChoices(user) - if ("alt_title") - var/datum/job/job = locate(href_list["job"]) - if (job) - var/choices = list(job.title) + job.alt_titles - var/choice = input("Pick a title for [job.title].", "Character Generation", GetPlayerAltTitle(job)) as anything in choices | null - if(choice) - SetPlayerAltTitle(job, choice) - SetChoices(user) - if("input") - SetJob(user, href_list["text"]) - if("setJobLevel") - UpdateJobPreference(user, href_list["text"], text2num(href_list["level"])) + if(href_list["preference"] == "job") + switch(href_list["task"]) + if("close") + user << browse(null, "window=mob_occupation") + ShowChoices(user) + if("reset") + ResetJobs() + SetChoices(user) + if("random") + if(alternate_option == GET_RANDOM_JOB || alternate_option == BE_CIVILIAN) + alternate_option += 1 + else if(alternate_option == RETURN_TO_LOBBY) + alternate_option = 0 else - SetChoices(user) - return 1 - else if(href_list["preference"] == "disabilities") - - switch(href_list["task"]) - if("close") - user << browse(null, "window=disabil") - ShowChoices(user) - if("reset") - disabilities=0 - SetDisabilities(user) - if("input") - var/dflag=text2num(href_list["disability"]) - if(dflag >= 0) - if(!(dflag==DISABILITY_FLAG_FAT && species!=("Human" || "Tajaran" || "Grey"))) - disabilities ^= text2num(href_list["disability"]) //MAGIC - SetDisabilities(user) - else - SetDisabilities(user) - return 1 - - else if(href_list["preference"] == "records") - if(text2num(href_list["record"]) >= 1) - SetRecords(user) - return + return 0 + SetChoices(user) + if ("alt_title") + var/datum/job/job = locate(href_list["job"]) + if (job) + var/choices = list(job.title) + job.alt_titles + var/choice = input("Pick a title for [job.title].", "Character Generation", GetPlayerAltTitle(job)) as anything in choices | null + if(choice) + SetPlayerAltTitle(job, choice) + SetChoices(user) + if("input") + SetJob(user, href_list["text"]) + if("setJobLevel") + UpdateJobPreference(user, href_list["text"], text2num(href_list["level"])) else - user << browse(null, "window=records") - if(href_list["task"] == "med_record") - var/medmsg = input(usr,"Set your medical notes here.","Medical Records",html_decode(med_record)) as message - - if(medmsg != null) - medmsg = copytext(medmsg, 1, MAX_PAPER_MESSAGE_LEN) - medmsg = html_encode(medmsg) - - med_record = medmsg - SetRecords(user) - - if(href_list["task"] == "sec_record") - var/secmsg = input(usr,"Set your security notes here.","Security Records",html_decode(sec_record)) as message - - if(secmsg != null) - secmsg = copytext(secmsg, 1, MAX_PAPER_MESSAGE_LEN) - secmsg = html_encode(secmsg) - - sec_record = secmsg - SetRecords(user) - if(href_list["task"] == "gen_record") - var/genmsg = input(usr,"Set your employment notes here.","Employment Records",html_decode(gen_record)) as message - - if(genmsg != null) - genmsg = copytext(genmsg, 1, MAX_PAPER_MESSAGE_LEN) - genmsg = html_encode(genmsg) - - gen_record = genmsg - SetRecords(user) + SetChoices(user) + return 1 + else if(href_list["preference"] == "disabilities") switch(href_list["task"]) - if("random") - switch(href_list["preference"]) - if("name") - real_name = random_name(gender,species) - if("age") - age = rand(AGE_MIN, AGE_MAX) - if("hair") - if(species == "Human" || species == "Unathi" || species == "Tajaran" || species == "Skrell" || species == "Machine" || species == "Wryn" || species == "Vulpkanin") - r_hair = rand(0,255) - g_hair = rand(0,255) - b_hair = rand(0,255) - if("h_style") - h_style = random_hair_style(gender, species) - if("facial") - r_facial = rand(0,255) - g_facial = rand(0,255) - b_facial = rand(0,255) - if("f_style") - f_style = random_facial_hair_style(gender, species) - if("underwear") - underwear = random_underwear(gender) - ShowChoices(user) - if("undershirt") - undershirt = random_undershirt(gender) - ShowChoices(user) - if("socks") - socks = random_socks(gender) - ShowChoices(user) - if("eyes") - r_eyes = rand(0,255) - g_eyes = rand(0,255) - b_eyes = rand(0,255) - if("s_tone") - if(species == "Human") - s_tone = random_skin_tone() - if("s_color") - if(species in list("Unathi", "Tajaran", "Skrell", "Slime People", "Wyrn", "Vulpkanin", "Machine")) - r_skin = rand(0,255) - g_skin = rand(0,255) - b_skin = rand(0,255) - if("bag") - backbag = rand(1,4) - /*if("skin_style") - h_style = random_skin_style(gender)*/ - if("all") - random_character() + if("close") + user << browse(null, "window=disabil") + ShowChoices(user) + if("reset") + disabilities=0 + SetDisabilities(user) if("input") - switch(href_list["preference"]) - if("name") - var/raw_name = input(user, "Choose your character's name:", "Character Preference") as text|null - if (!isnull(raw_name)) // Check to ensure that the user entered text (rather than cancel.) - var/new_name = reject_bad_name(raw_name) - if(new_name) - real_name = new_name - else - user << "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and ." + var/dflag=text2num(href_list["disability"]) + if(dflag >= 0) + if(!(dflag==DISABILITY_FLAG_FAT && species!=("Human" || "Tajaran" || "Grey"))) + disabilities ^= text2num(href_list["disability"]) //MAGIC + SetDisabilities(user) + else + SetDisabilities(user) + return 1 - if("age") - var/new_age = input(user, "Choose your character's age:\n([AGE_MIN]-[AGE_MAX])", "Character Preference") as num|null - if(new_age) - age = max(min( round(text2num(new_age)), AGE_MAX),AGE_MIN) - if("species") + else if(href_list["preference"] == "records") + if(text2num(href_list["record"]) >= 1) + SetRecords(user) + return + else + user << browse(null, "window=records") + if(href_list["task"] == "med_record") + var/medmsg = input(usr,"Set your medical notes here.","Medical Records",html_decode(med_record)) as message - var/list/new_species = list("Human","Tajaran","Skrell","Unathi","Diona", "Vulpkanin") - var/prev_species = species + if(medmsg != null) + medmsg = copytext(medmsg, 1, MAX_PAPER_MESSAGE_LEN) + medmsg = html_encode(medmsg) + + med_record = medmsg + SetRecords(user) + + if(href_list["task"] == "sec_record") + var/secmsg = input(usr,"Set your security notes here.","Security Records",html_decode(sec_record)) as message + + if(secmsg != null) + secmsg = copytext(secmsg, 1, MAX_PAPER_MESSAGE_LEN) + secmsg = html_encode(secmsg) + + sec_record = secmsg + SetRecords(user) + if(href_list["task"] == "gen_record") + var/genmsg = input(usr,"Set your employment notes here.","Employment Records",html_decode(gen_record)) as message + + if(genmsg != null) + genmsg = copytext(genmsg, 1, MAX_PAPER_MESSAGE_LEN) + genmsg = html_encode(genmsg) + + gen_record = genmsg + SetRecords(user) + + switch(href_list["task"]) + if("random") + switch(href_list["preference"]) + if("name") + real_name = random_name(gender,species) + if("age") + age = rand(AGE_MIN, AGE_MAX) + if("hair") + if(species == "Human" || species == "Unathi" || species == "Tajaran" || species == "Skrell" || species == "Machine" || species == "Wryn" || species == "Vulpkanin") + r_hair = rand(0,255) + g_hair = rand(0,255) + b_hair = rand(0,255) + if("h_style") + h_style = random_hair_style(gender, species) + if("facial") + r_facial = rand(0,255) + g_facial = rand(0,255) + b_facial = rand(0,255) + if("f_style") + f_style = random_facial_hair_style(gender, species) + if("underwear") + underwear = random_underwear(gender) + ShowChoices(user) + if("undershirt") + undershirt = random_undershirt(gender) + ShowChoices(user) + if("socks") + socks = random_socks(gender) + ShowChoices(user) + if("eyes") + r_eyes = rand(0,255) + g_eyes = rand(0,255) + b_eyes = rand(0,255) + if("s_tone") + if(species == "Human") + s_tone = random_skin_tone() + if("s_color") + if(species in list("Unathi", "Tajaran", "Skrell", "Slime People", "Wyrn", "Vulpkanin", "Machine")) + r_skin = rand(0,255) + g_skin = rand(0,255) + b_skin = rand(0,255) + if("bag") + backbag = rand(1,4) + /*if("skin_style") + h_style = random_skin_style(gender)*/ + if("all") + random_character() + if("input") + switch(href_list["preference"]) + if("name") + var/raw_name = input(user, "Choose your character's name:", "Character Preference") as text|null + if (!isnull(raw_name)) // Check to ensure that the user entered text (rather than cancel.) + var/new_name = reject_bad_name(raw_name) + if(new_name) + real_name = new_name + else + user << "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and ." + + if("age") + var/new_age = input(user, "Choose your character's age:\n([AGE_MIN]-[AGE_MAX])", "Character Preference") as num|null + if(new_age) + age = max(min( round(text2num(new_age)), AGE_MAX),AGE_MIN) + if("species") + + var/list/new_species = list("Human","Tajaran","Skrell","Unathi","Diona", "Vulpkanin") + var/prev_species = species // var/whitelisted = 0 - if(config.usealienwhitelist) //If we're using the whitelist, make sure to check it! - for(var/S in whitelisted_species) - if(is_alien_whitelisted(user,S)) - new_species += S + if(config.usealienwhitelist) //If we're using the whitelist, make sure to check it! + for(var/S in whitelisted_species) + if(is_alien_whitelisted(user,S)) + new_species += S // whitelisted = 1 // if(!whitelisted) // alert(user, "You cannot change your species as you need to be whitelisted. If you wish to be whitelisted contact an admin in-game, on the forums, or on IRC.") - else //Not using the whitelist? Aliens for everyone! - new_species += whitelisted_species + else //Not using the whitelist? Aliens for everyone! + new_species += whitelisted_species - species = input("Please select a species", "Character Generation", null) in new_species + species = input("Please select a species", "Character Generation", null) in new_species - if(prev_species != species) - //grab one of the valid hair styles for the newly chosen species - var/list/valid_hairstyles = list() - for(var/hairstyle in hair_styles_list) - var/datum/sprite_accessory/S = hair_styles_list[hairstyle] - if(gender == MALE && S.gender == FEMALE) - continue - if(gender == FEMALE && S.gender == MALE) - continue - if( !(species in S.species_allowed)) - continue - valid_hairstyles[hairstyle] = hair_styles_list[hairstyle] - - if(valid_hairstyles.len) - h_style = pick(valid_hairstyles) - else - //this shouldn't happen - h_style = hair_styles_list["Bald"] - - //grab one of the valid facial hair styles for the newly chosen species - var/list/valid_facialhairstyles = list() - for(var/facialhairstyle in facial_hair_styles_list) - var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle] - if(gender == MALE && S.gender == FEMALE) - continue - if(gender == FEMALE && S.gender == MALE) - continue - if( !(species in S.species_allowed)) - continue - - valid_facialhairstyles[facialhairstyle] = facial_hair_styles_list[facialhairstyle] - - if(valid_facialhairstyles.len) - f_style = pick(valid_facialhairstyles) - else - //this shouldn't happen - f_style = facial_hair_styles_list["Shaved"] - - // Don't wear another species' underwear! - var/datum/sprite_accessory/S = underwear_list[underwear] - if(!(species in S.species_allowed)) - underwear = random_underwear(gender, species) - - S = undershirt_list[undershirt] - if(!(species in S.species_allowed)) - undershirt = random_undershirt(gender, species) - - S = socks_list[socks] - if(!(species in S.species_allowed)) - socks = random_socks(gender, species) - - //reset hair colour and skin colour - r_hair = 0//hex2num(copytext(new_hair, 2, 4)) - g_hair = 0//hex2num(copytext(new_hair, 4, 6)) - b_hair = 0//hex2num(copytext(new_hair, 6, 8)) - - s_tone = 0 - - body_accessory = null //no vulpatail on humans damnit - if("speciesprefs")//oldvox code - speciesprefs = !speciesprefs - - if("language") -// var/languages_available - var/list/new_languages = list("None") -/* - if(config.usealienwhitelist) - for(var/L in all_languages) - var/datum/language/lang = all_languages[L] - if((!(lang.flags & RESTRICTED)) && (is_alien_whitelisted(user, L)||(!( lang.flags & WHITELISTED )))) - new_languages += lang - languages_available = 1 - - if(!(languages_available)) - alert(user, "There are not currently any available secondary languages.") - else -*/ - for(var/L in all_languages) - var/datum/language/lang = all_languages[L] - if(!(lang.flags & RESTRICTED)) - new_languages += lang.name - - language = input("Please select a secondary language", "Character Generation", null) in new_languages - - if("metadata") - var/new_metadata = input(user, "Enter any information you'd like others to see, such as Roleplay-preferences:", "Game Preference" , metadata) as message|null - if(new_metadata) - metadata = sanitize(copytext(new_metadata,1,MAX_MESSAGE_LEN)) - - if("b_type") - var/new_b_type = input(user, "Choose your character's blood-type:", "Character Preference") as null|anything in list( "A+", "A-", "B+", "B-", "AB+", "AB-", "O+", "O-" ) - if(new_b_type) - b_type = new_b_type - - if("hair") - if(species == "Human" || species == "Unathi" || species == "Tajaran" || species == "Skrell" || species == "Machine" || species == "Vulpkanin") - var/input = "Choose your character's hair colour:" - if(species == "Machine") - input = "Choose your character's frame colour:" - var/new_hair = input(user, input, "Character Preference", rgb(r_hair, g_hair, b_hair)) as color|null - if(new_hair) - r_hair = hex2num(copytext(new_hair, 2, 4)) - g_hair = hex2num(copytext(new_hair, 4, 6)) - b_hair = hex2num(copytext(new_hair, 6, 8)) - - if("h_style") + if(prev_species != species) + //grab one of the valid hair styles for the newly chosen species var/list/valid_hairstyles = list() for(var/hairstyle in hair_styles_list) var/datum/sprite_accessory/S = hair_styles_list[hairstyle] + if(gender == MALE && S.gender == FEMALE) + continue + if(gender == FEMALE && S.gender == MALE) + continue if( !(species in S.species_allowed)) continue - valid_hairstyles[hairstyle] = hair_styles_list[hairstyle] - var/new_h_style = input(user, "Choose your character's hair style:", "Character Preference") as null|anything in valid_hairstyles - if(new_h_style) - h_style = new_h_style - - if("body_accessory") - var/list/possible_body_accessories = list() - if(check_rights(R_ADMIN, 1, user)) - possible_body_accessories = body_accessory_by_name.Copy() + if(valid_hairstyles.len) + h_style = pick(valid_hairstyles) else - for(var/B in body_accessory_by_name) - var/datum/body_accessory/accessory = body_accessory_by_name[B] - if(!istype(accessory)) - possible_body_accessories += "None" //the only null entry should be the "None" option - continue - if(species in accessory.allowed_species) - possible_body_accessories += B + //this shouldn't happen + h_style = hair_styles_list["Bald"] - var/new_body_accessory = input(user, "Choose your body accessory:", "Character Preference") as null|anything in possible_body_accessories - if(new_body_accessory) - body_accessory = (new_body_accessory == "None") ? null : new_body_accessory - - if("facial") - var/new_facial = input(user, "Choose your character's facial-hair colour:", "Character Preference", rgb(r_facial, g_facial, b_facial)) as color|null - if(new_facial) - r_facial = hex2num(copytext(new_facial, 2, 4)) - g_facial = hex2num(copytext(new_facial, 4, 6)) - b_facial = hex2num(copytext(new_facial, 6, 8)) - - if("f_style") + //grab one of the valid facial hair styles for the newly chosen species var/list/valid_facialhairstyles = list() for(var/facialhairstyle in facial_hair_styles_list) var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle] @@ -1204,435 +1081,559 @@ datum/preferences valid_facialhairstyles[facialhairstyle] = facial_hair_styles_list[facialhairstyle] - var/new_f_style = input(user, "Choose your character's facial-hair style:", "Character Preference") as null|anything in valid_facialhairstyles - if(new_f_style) - f_style = new_f_style - - if("underwear") - var/list/underwear_options - if(gender == MALE) - underwear_options = underwear_m + if(valid_facialhairstyles.len) + f_style = pick(valid_facialhairstyles) else - underwear_options = underwear_f + //this shouldn't happen + f_style = facial_hair_styles_list["Shaved"] - var/new_underwear = input(user, "Choose your character's underwear:", "Character Preference") as null|anything in underwear_options - if(new_underwear) - underwear = new_underwear - ShowChoices(user) + // Don't wear another species' underwear! + var/datum/sprite_accessory/S = underwear_list[underwear] + if(!(species in S.species_allowed)) + underwear = random_underwear(gender, species) - if("undershirt") - var/new_undershirt - if(gender == MALE) - new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in undershirt_m - else - new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in undershirt_f - if(new_undershirt) - undershirt = new_undershirt - ShowChoices(user) + S = undershirt_list[undershirt] + if(!(species in S.species_allowed)) + undershirt = random_undershirt(gender, species) - if("socks") - var/list/valid_sockstyles = list() - for(var/sockstyle in socks_list) - var/datum/sprite_accessory/S = socks_list[sockstyle] - if(gender == MALE && S.gender == FEMALE) + S = socks_list[socks] + if(!(species in S.species_allowed)) + socks = random_socks(gender, species) + + //reset hair colour and skin colour + r_hair = 0//hex2num(copytext(new_hair, 2, 4)) + g_hair = 0//hex2num(copytext(new_hair, 4, 6)) + b_hair = 0//hex2num(copytext(new_hair, 6, 8)) + + s_tone = 0 + + body_accessory = null //no vulpatail on humans damnit + if("speciesprefs")//oldvox code + speciesprefs = !speciesprefs + + if("language") +// var/languages_available + var/list/new_languages = list("None") +/* + if(config.usealienwhitelist) + for(var/L in all_languages) + var/datum/language/lang = all_languages[L] + if((!(lang.flags & RESTRICTED)) && (is_alien_whitelisted(user, L)||(!( lang.flags & WHITELISTED )))) + new_languages += lang + languages_available = 1 + + if(!(languages_available)) + alert(user, "There are not currently any available secondary languages.") + else +*/ + for(var/L in all_languages) + var/datum/language/lang = all_languages[L] + if(!(lang.flags & RESTRICTED)) + new_languages += lang.name + + language = input("Please select a secondary language", "Character Generation", null) in new_languages + + if("metadata") + var/new_metadata = input(user, "Enter any information you'd like others to see, such as Roleplay-preferences:", "Game Preference" , metadata) as message|null + if(new_metadata) + metadata = sanitize(copytext(new_metadata,1,MAX_MESSAGE_LEN)) + + if("b_type") + var/new_b_type = input(user, "Choose your character's blood-type:", "Character Preference") as null|anything in list( "A+", "A-", "B+", "B-", "AB+", "AB-", "O+", "O-" ) + if(new_b_type) + b_type = new_b_type + + if("hair") + if(species == "Human" || species == "Unathi" || species == "Tajaran" || species == "Skrell" || species == "Machine" || species == "Vulpkanin") + var/input = "Choose your character's hair colour:" + if(species == "Machine") + input = "Choose your character's frame colour:" + var/new_hair = input(user, input, "Character Preference", rgb(r_hair, g_hair, b_hair)) as color|null + if(new_hair) + r_hair = hex2num(copytext(new_hair, 2, 4)) + g_hair = hex2num(copytext(new_hair, 4, 6)) + b_hair = hex2num(copytext(new_hair, 6, 8)) + + if("h_style") + var/list/valid_hairstyles = list() + for(var/hairstyle in hair_styles_list) + var/datum/sprite_accessory/S = hair_styles_list[hairstyle] + if( !(species in S.species_allowed)) + continue + + valid_hairstyles[hairstyle] = hair_styles_list[hairstyle] + + var/new_h_style = input(user, "Choose your character's hair style:", "Character Preference") as null|anything in valid_hairstyles + if(new_h_style) + h_style = new_h_style + + if("body_accessory") + var/list/possible_body_accessories = list() + if(check_rights(R_ADMIN, 1, user)) + possible_body_accessories = body_accessory_by_name.Copy() + else + for(var/B in body_accessory_by_name) + var/datum/body_accessory/accessory = body_accessory_by_name[B] + if(!istype(accessory)) + possible_body_accessories += "None" //the only null entry should be the "None" option continue - if(gender == FEMALE && S.gender == MALE) - continue - if(!(species in S.species_allowed)) - continue - valid_sockstyles[sockstyle] = socks_list[sockstyle] - var/new_socks = input(user, "Choose your character's socks:", "Character Preference") as null|anything in valid_sockstyles - ShowChoices(user) - if(new_socks) - socks = new_socks + if(species in accessory.allowed_species) + possible_body_accessories += B - if("eyes") - var/new_eyes = input(user, "Choose your character's eye colour:", "Character Preference", rgb(r_eyes, g_eyes, b_eyes)) as color|null - if(new_eyes) - r_eyes = hex2num(copytext(new_eyes, 2, 4)) - g_eyes = hex2num(copytext(new_eyes, 4, 6)) - b_eyes = hex2num(copytext(new_eyes, 6, 8)) + var/new_body_accessory = input(user, "Choose your body accessory:", "Character Preference") as null|anything in possible_body_accessories + if(new_body_accessory) + body_accessory = (new_body_accessory == "None") ? null : new_body_accessory - if("s_tone") - if(species != "Human") - return - var/new_s_tone = input(user, "Choose your character's skin-tone:\n(Light 1 - 220 Dark)", "Character Preference") as num|null - if(new_s_tone) - s_tone = 35 - max(min( round(new_s_tone), 220),1) + if("facial") + var/new_facial = input(user, "Choose your character's facial-hair colour:", "Character Preference", rgb(r_facial, g_facial, b_facial)) as color|null + if(new_facial) + r_facial = hex2num(copytext(new_facial, 2, 4)) + g_facial = hex2num(copytext(new_facial, 4, 6)) + b_facial = hex2num(copytext(new_facial, 6, 8)) - if("skin") - if((species in list("Unathi", "Tajaran", "Skrell", "Slime People", "Vulpkanin", "Machine")) || body_accessory_by_species[species] || check_rights(R_ADMIN, 0, user)) - var/new_skin = input(user, "Choose your character's skin colour: ", "Character Preference", rgb(r_skin, g_skin, b_skin)) as color|null - if(new_skin) - r_skin = hex2num(copytext(new_skin, 2, 4)) - g_skin = hex2num(copytext(new_skin, 4, 6)) - b_skin = hex2num(copytext(new_skin, 6, 8)) + if("f_style") + var/list/valid_facialhairstyles = list() + for(var/facialhairstyle in facial_hair_styles_list) + var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle] + if(gender == MALE && S.gender == FEMALE) + continue + if(gender == FEMALE && S.gender == MALE) + continue + if( !(species in S.species_allowed)) + continue + + valid_facialhairstyles[facialhairstyle] = facial_hair_styles_list[facialhairstyle] + + var/new_f_style = input(user, "Choose your character's facial-hair style:", "Character Preference") as null|anything in valid_facialhairstyles + if(new_f_style) + f_style = new_f_style + + if("underwear") + var/list/underwear_options + if(gender == MALE) + underwear_options = underwear_m + else + underwear_options = underwear_f + + var/new_underwear = input(user, "Choose your character's underwear:", "Character Preference") as null|anything in underwear_options + if(new_underwear) + underwear = new_underwear + ShowChoices(user) + + if("undershirt") + var/new_undershirt + if(gender == MALE) + new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in undershirt_m + else + new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in undershirt_f + if(new_undershirt) + undershirt = new_undershirt + ShowChoices(user) + + if("socks") + var/list/valid_sockstyles = list() + for(var/sockstyle in socks_list) + var/datum/sprite_accessory/S = socks_list[sockstyle] + if(gender == MALE && S.gender == FEMALE) + continue + if(gender == FEMALE && S.gender == MALE) + continue + if(!(species in S.species_allowed)) + continue + valid_sockstyles[sockstyle] = socks_list[sockstyle] + var/new_socks = input(user, "Choose your character's socks:", "Character Preference") as null|anything in valid_sockstyles + ShowChoices(user) + if(new_socks) + socks = new_socks + + if("eyes") + var/new_eyes = input(user, "Choose your character's eye colour:", "Character Preference", rgb(r_eyes, g_eyes, b_eyes)) as color|null + if(new_eyes) + r_eyes = hex2num(copytext(new_eyes, 2, 4)) + g_eyes = hex2num(copytext(new_eyes, 4, 6)) + b_eyes = hex2num(copytext(new_eyes, 6, 8)) + + if("s_tone") + if(species != "Human") + return + var/new_s_tone = input(user, "Choose your character's skin-tone:\n(Light 1 - 220 Dark)", "Character Preference") as num|null + if(new_s_tone) + s_tone = 35 - max(min( round(new_s_tone), 220),1) + + if("skin") + if((species in list("Unathi", "Tajaran", "Skrell", "Slime People", "Vulpkanin", "Machine")) || body_accessory_by_species[species] || check_rights(R_ADMIN, 0, user)) + var/new_skin = input(user, "Choose your character's skin colour: ", "Character Preference", rgb(r_skin, g_skin, b_skin)) as color|null + if(new_skin) + r_skin = hex2num(copytext(new_skin, 2, 4)) + g_skin = hex2num(copytext(new_skin, 4, 6)) + b_skin = hex2num(copytext(new_skin, 6, 8)) - if("ooccolor") - var/new_ooccolor = input(user, "Choose your OOC colour:", "Game Preference", ooccolor) as color|null - if(new_ooccolor) - ooccolor = new_ooccolor + if("ooccolor") + var/new_ooccolor = input(user, "Choose your OOC colour:", "Game Preference", ooccolor) as color|null + if(new_ooccolor) + ooccolor = new_ooccolor - if("bag") - var/new_backbag = input(user, "Choose your character's style of bag:", "Character Preference") as null|anything in backbaglist - if(new_backbag) - backbag = backbaglist.Find(new_backbag) + if("bag") + var/new_backbag = input(user, "Choose your character's style of bag:", "Character Preference") as null|anything in backbaglist + if(new_backbag) + backbag = backbaglist.Find(new_backbag) - if("nt_relation") - var/new_relation = input(user, "Choose your relation to NT. Note that this represents what others can find out about your character by researching your background, not what your character actually thinks.", "Character Preference") as null|anything in list("Loyal", "Supportive", "Neutral", "Skeptical", "Opposed") - if(new_relation) - nanotrasen_relation = new_relation + if("nt_relation") + var/new_relation = input(user, "Choose your relation to NT. Note that this represents what others can find out about your character by researching your background, not what your character actually thinks.", "Character Preference") as null|anything in list("Loyal", "Supportive", "Neutral", "Skeptical", "Opposed") + if(new_relation) + nanotrasen_relation = new_relation - if("flavor_text") - var/msg = input(usr,"Set the flavor text in your 'examine' verb. This can also be used for OOC notes and preferences!","Flavor Text",html_decode(flavor_text)) as message + if("flavor_text") + var/msg = input(usr,"Set the flavor text in your 'examine' verb. This can also be used for OOC notes and preferences!","Flavor Text",html_decode(flavor_text)) as message - if(msg != null) - msg = copytext(msg, 1, MAX_MESSAGE_LEN) - msg = html_encode(msg) + if(msg != null) + msg = copytext(msg, 1, MAX_MESSAGE_LEN) + msg = html_encode(msg) - flavor_text = msg + flavor_text = msg - if("limbs") - var/limb_name = input(user, "Which limb do you want to change?") as null|anything in list("Left Leg","Right Leg","Left Arm","Right Arm","Left Foot","Right Foot","Left Hand","Right Hand") - if(!limb_name) return + if("limbs") + var/limb_name = input(user, "Which limb do you want to change?") as null|anything in list("Left Leg","Right Leg","Left Arm","Right Arm","Left Foot","Right Foot","Left Hand","Right Hand") + if(!limb_name) return - var/limb = null - var/second_limb = null // if you try to change the arm, the hand should also change - var/third_limb = null // if you try to unchange the hand, the arm should also change - var/valid_limb_states=list("Normal","Amputated","Prothesis") - switch(limb_name) - if("Left Leg") - limb = "l_leg" - second_limb = "l_foot" - if("Right Leg") - limb = "r_leg" - second_limb = "r_foot" - if("Left Arm") - limb = "l_arm" - second_limb = "l_hand" - if("Right Arm") - limb = "r_arm" - second_limb = "r_hand" - if("Left Foot") - limb = "l_foot" - third_limb = "l_leg" - if("Right Foot") - limb = "r_foot" - third_limb = "r_leg" - if("Left Hand") - limb = "l_hand" - third_limb = "l_arm" - if("Right Hand") - limb = "r_hand" - third_limb = "r_arm" + var/limb = null + var/second_limb = null // if you try to change the arm, the hand should also change + var/third_limb = null // if you try to unchange the hand, the arm should also change + var/valid_limb_states=list("Normal","Amputated","Prothesis") + switch(limb_name) + if("Left Leg") + limb = "l_leg" + second_limb = "l_foot" + if("Right Leg") + limb = "r_leg" + second_limb = "r_foot" + if("Left Arm") + limb = "l_arm" + second_limb = "l_hand" + if("Right Arm") + limb = "r_arm" + second_limb = "r_hand" + if("Left Foot") + limb = "l_foot" + third_limb = "l_leg" + if("Right Foot") + limb = "r_foot" + third_limb = "r_leg" + if("Left Hand") + limb = "l_hand" + third_limb = "l_arm" + if("Right Hand") + limb = "r_hand" + third_limb = "r_arm" - var/new_state = input(user, "What state do you wish the limb to be in?") as null|anything in valid_limb_states - if(!new_state) return + var/new_state = input(user, "What state do you wish the limb to be in?") as null|anything in valid_limb_states + if(!new_state) return - switch(new_state) - if("Normal") - organ_data[limb] = null - rlimb_data[limb] = null - if(third_limb) - organ_data[third_limb] = null - rlimb_data[third_limb] = null - if("Amputated") - organ_data[limb] = "amputated" - rlimb_data[limb] = null - if(second_limb) - organ_data[second_limb] = "amputated" - rlimb_data[second_limb] = null - if("Prothesis") - var/choice = input(user, "Which manufacturer do you wish to use for this limb?") as null|anything in chargen_robolimbs - if(!choice) - return - rlimb_data[limb] = choice - organ_data[limb] = "cyborg" - if(second_limb) - rlimb_data[second_limb] = choice - organ_data[second_limb] = "cyborg" + switch(new_state) + if("Normal") + organ_data[limb] = null + rlimb_data[limb] = null + if(third_limb) + organ_data[third_limb] = null + rlimb_data[third_limb] = null + if("Amputated") + organ_data[limb] = "amputated" + rlimb_data[limb] = null + if(second_limb) + organ_data[second_limb] = "amputated" + rlimb_data[second_limb] = null + if("Prothesis") + var/choice = input(user, "Which manufacturer do you wish to use for this limb?") as null|anything in chargen_robolimbs + if(!choice) + return + rlimb_data[limb] = choice + organ_data[limb] = "cyborg" + if(second_limb) + rlimb_data[second_limb] = choice + organ_data[second_limb] = "cyborg" - if("organs") - var/organ_name = input(user, "Which internal function do you want to change?") as null|anything in list("Heart", "Eyes") - if(!organ_name) return + if("organs") + var/organ_name = input(user, "Which internal function do you want to change?") as null|anything in list("Heart", "Eyes") + if(!organ_name) return - var/organ = null - switch(organ_name) - if("Heart") - organ = "heart" - if("Eyes") - organ = "eyes" + var/organ = null + switch(organ_name) + if("Heart") + organ = "heart" + if("Eyes") + organ = "eyes" - var/new_state = input(user, "What state do you wish the organ to be in?") as null|anything in list("Normal","Assisted","Mechanical") - if(!new_state) return + var/new_state = input(user, "What state do you wish the organ to be in?") as null|anything in list("Normal","Assisted","Mechanical") + if(!new_state) return - switch(new_state) - if("Normal") - organ_data[organ] = null - if("Assisted") - organ_data[organ] = "assisted" - if("Mechanical") - organ_data[organ] = "mechanical" + switch(new_state) + if("Normal") + organ_data[organ] = null + if("Assisted") + organ_data[organ] = "assisted" + if("Mechanical") + organ_data[organ] = "mechanical" /* - if("skin_style") - var/skin_style_name = input(user, "Select a new skin style") as null|anything in list("default1", "default2", "default3") - if(!skin_style_name) return + if("skin_style") + var/skin_style_name = input(user, "Select a new skin style") as null|anything in list("default1", "default2", "default3") + if(!skin_style_name) return */ /* if("spawnpoint") - var/list/spawnkeys = list() - for(var/S in spawntypes) - spawnkeys += S - var/choice = input(user, "Where would you like to spawn when latejoining?") as null|anything in spawnkeys - if(!choice || !spawntypes[choice]) - spawnpoint = "Arrivals Shuttle" - return - spawnpoint = choice */ + var/list/spawnkeys = list() + for(var/S in spawntypes) + spawnkeys += S + var/choice = input(user, "Where would you like to spawn when latejoining?") as null|anything in spawnkeys + if(!choice || !spawntypes[choice]) + spawnpoint = "Arrivals Shuttle" + return + spawnpoint = choice */ - else - switch(href_list["preference"]) - if("publicity") - if(unlock_content) - toggles ^= MEMBER_PUBLIC + else + switch(href_list["preference"]) + if("publicity") + if(unlock_content) + toggles ^= MEMBER_PUBLIC - if("gender") - if(gender == MALE) - gender = FEMALE - else - gender = MALE - underwear = random_underwear(gender) - - if("hear_adminhelps") - sound ^= SOUND_ADMINHELP - - if("ui") - switch(UI_style) - if("Midnight") - UI_style = "White" - else - UI_style = "Midnight" - - if("UIcolor") - var/UI_style_color_new = input(user, "Choose your UI color, dark colors are not recommended!", UI_style_color) as color|null - if(!UI_style_color_new) return - UI_style_color = UI_style_color_new - - if("UIalpha") - var/UI_style_alpha_new = input(user, "Select a new alpha(transparence) parametr for UI, between 50 and 255") as num - if(!UI_style_alpha_new | !(UI_style_alpha_new <= 255 && UI_style_alpha_new >= 50)) return - UI_style_alpha = UI_style_alpha_new - - if("be_special") - var/r = href_list["role"] - if(!(r in special_roles)) - message_admins("[user] attempted an href exploit! (This could have possibly lead to a \"Bobby Tables\" exploit, so they're probably up to no good). String: [r] ID: [last_id] IP: [last_ip]") - user << "Nice try." - else - be_special ^= r - - if("name") - be_random_name = !be_random_name - - if("randomslot") - randomslot = !randomslot - - if("hear_midis") - sound ^= SOUND_MIDI - - if("lobby_music") - sound ^= SOUND_LOBBY - if(sound & SOUND_LOBBY) - user << sound(ticker.login_music, repeat = 0, wait = 0, volume = 85, channel = 1) - else - user << sound(null, repeat = 0, wait = 0, volume = 85, channel = 1) - - if("ghost_ears") - toggles ^= CHAT_GHOSTEARS - - if("ghost_sight") - toggles ^= CHAT_GHOSTSIGHT - - if("ghost_radio") - toggles ^= CHAT_GHOSTRADIO - - if("ghost_radio") - toggles ^= CHAT_GHOSTRADIO - - if("save") - save_preferences(user) - save_character(user) - - if("reload") - load_preferences(user) - load_character(user) - - if("open_load_dialog") - if(!IsGuestKey(user.key)) - open_load_dialog(user) - - if("close_load_dialog") - close_load_dialog(user) - - if("changeslot") - if(!load_character(user,text2num(href_list["num"]))) - random_character() - real_name = random_name(gender) - save_character(user) - close_load_dialog(user) - - if("tab") - if (href_list["tab"]) - current_tab = text2num(href_list["tab"]) - - ShowChoices(user) - return 1 - - proc/copy_to(mob/living/carbon/human/character) - if(be_random_name) - real_name = random_name(gender,species) - - if(config.humans_need_surnames) - var/firstspace = findtext(real_name, " ") - var/name_length = length(real_name) - if(!firstspace) //we need a surname - real_name += " [pick(last_names)]" - else if(firstspace == name_length) - real_name += "[pick(last_names)]" - - character.real_name = real_name - character.name = character.real_name - if(character.dna) - character.dna.real_name = character.real_name - - character.flavor_text = flavor_text - character.med_record = med_record - character.sec_record = sec_record - character.gen_record = gen_record - - character.gender = gender - character.age = age - character.b_type = b_type - - character.r_eyes = r_eyes - character.g_eyes = g_eyes - character.b_eyes = b_eyes - - character.r_hair = r_hair - character.g_hair = g_hair - character.b_hair = b_hair - - character.r_facial = r_facial - character.g_facial = g_facial - character.b_facial = b_facial - - character.r_skin = r_skin - character.g_skin = g_skin - character.b_skin = b_skin - - character.s_tone = s_tone - - character.h_style = h_style - character.f_style = f_style - - - // Destroy/cyborgize organs - - for(var/name in organ_data) - - var/status = organ_data[name] - var/obj/item/organ/external/O = character.organs_by_name[name] - if(O) - if(status == "amputated") - character.organs_by_name[O.limb_name] = null - character.organs -= O - if(O.children) // This might need to become recursive. - for(var/obj/item/organ/external/child in O.children) - character.organs_by_name[child.limb_name] = null - character.organs -= child - - else if(status == "cyborg") - if(rlimb_data[name]) - O.robotize(rlimb_data[name]) + if("gender") + if(gender == MALE) + gender = FEMALE else - O.robotize() - else - var/obj/item/organ/I = character.internal_organs_by_name[name] - if(I) - if(status == "assisted") - I.mechassist() - else if(status == "mechanical") - I.robotize() + gender = MALE + underwear = random_underwear(gender) - if(disabilities & DISABILITY_FLAG_FAT && character.species.flags & CAN_BE_FAT)//character.species.flags & CAN_BE_FAT) - character.mutations += FAT - character.mutations += OBESITY - if(disabilities & DISABILITY_FLAG_NEARSIGHTED) - character.disabilities|=NEARSIGHTED - if(disabilities & DISABILITY_FLAG_EPILEPTIC) - character.disabilities|=EPILEPSY - if(disabilities & DISABILITY_FLAG_DEAF) - character.sdisabilities|=DEAF + if("hear_adminhelps") + sound ^= SOUND_ADMINHELP - // Wheelchair necessary? - var/obj/item/organ/external/l_foot = character.get_organ("l_foot") - var/obj/item/organ/external/r_foot = character.get_organ("r_foot") - if((!l_foot || l_foot.status & ORGAN_DESTROYED) && (!r_foot || r_foot.status & ORGAN_DESTROYED)) - var/obj/structure/stool/bed/chair/wheelchair/W = new /obj/structure/stool/bed/chair/wheelchair (character.loc) - character.buckled = W - character.update_canmove() - W.dir = character.dir - W.buckled_mob = character - W.add_fingerprint(character) + if("ui") + switch(UI_style) + if("Midnight") + UI_style = "White" + else + UI_style = "Midnight" - character.underwear = underwear - character.undershirt = undershirt - character.socks = socks + if("UIcolor") + var/UI_style_color_new = input(user, "Choose your UI color, dark colors are not recommended!", UI_style_color) as color|null + if(!UI_style_color_new) return + UI_style_color = UI_style_color_new - if(body_accessory) - character.body_accessory = body_accessory_by_name["[body_accessory]"] + if("UIalpha") + var/UI_style_alpha_new = input(user, "Select a new alpha(transparence) parametr for UI, between 50 and 255") as num + if(!UI_style_alpha_new | !(UI_style_alpha_new <= 255 && UI_style_alpha_new >= 50)) return + UI_style_alpha = UI_style_alpha_new - if(backbag > 4 || backbag < 1) - backbag = 1 //Same as above - character.backbag = backbag + if("be_special") + var/r = href_list["role"] + if(!(r in special_roles)) + message_admins("[user] attempted an href exploit! (This could have possibly lead to a \"Bobby Tables\" exploit, so they're probably up to no good). String: [r] ID: [last_id] IP: [last_ip]") + user << "Nice try." + else + be_special ^= r - //Debugging report to track down a bug, which randomly assigned the plural gender to people. - if(character.gender in list(PLURAL, NEUTER)) - if(isliving(src)) //Ghosts get neuter by default - message_admins("[key_name_admin(character)] has spawned with their gender as plural or neuter. Please notify coders.") - character.gender = MALE + if("name") + be_random_name = !be_random_name - proc/open_load_dialog(mob/user) + if("randomslot") + randomslot = !randomslot - var/DBQuery/query = dbcon.NewQuery("SELECT slot,real_name FROM [format_table_name("characters")] WHERE ckey='[user.ckey]' ORDER BY slot") + if("hear_midis") + sound ^= SOUND_MIDI - var/dat = "" - dat += "
    " - dat += "Select a character slot to load
    " - var/name + if("lobby_music") + sound ^= SOUND_LOBBY + if(sound & SOUND_LOBBY) + user << sound(ticker.login_music, repeat = 0, wait = 0, volume = 85, channel = 1) + else + user << sound(null, repeat = 0, wait = 0, volume = 85, channel = 1) - for(var/i=1, i<=max_save_slots, i++) - if(!query.Execute()) - var/err = query.ErrorMsg() - log_game("SQL ERROR during character slot loading. Error : \[[err]\]\n") - message_admins("SQL ERROR during character slot loading. Error : \[[err]\]\n") - return - while(query.NextRow()) - if(i==text2num(query.item[1])) - name = query.item[2] - if(!name) name = "Character[i]" - if(i==default_slot) - name = "[name]" - dat += "[name]
    " - name = null + if("ghost_ears") + toggles ^= CHAT_GHOSTEARS - dat += "
    " - dat += "Close
    " - dat += "
    " + if("ghost_sight") + toggles ^= CHAT_GHOSTSIGHT + + if("ghost_radio") + toggles ^= CHAT_GHOSTRADIO + + if("ghost_radio") + toggles ^= CHAT_GHOSTRADIO + + if("save") + save_preferences(user) + save_character(user) + + if("reload") + load_preferences(user) + load_character(user) + + if("open_load_dialog") + if(!IsGuestKey(user.key)) + open_load_dialog(user) + + if("close_load_dialog") + close_load_dialog(user) + + if("changeslot") + if(!load_character(user,text2num(href_list["num"]))) + random_character() + real_name = random_name(gender) + save_character(user) + close_load_dialog(user) + + if("tab") + if (href_list["tab"]) + current_tab = text2num(href_list["tab"]) + + ShowChoices(user) + return 1 + +/datum/preferences/proc/copy_to(mob/living/carbon/human/character) + if(be_random_name) + real_name = random_name(gender,species) + + if(config.humans_need_surnames) + var/firstspace = findtext(real_name, " ") + var/name_length = length(real_name) + if(!firstspace) //we need a surname + real_name += " [pick(last_names)]" + else if(firstspace == name_length) + real_name += "[pick(last_names)]" + + character.real_name = real_name + character.name = character.real_name + if(character.dna) + character.dna.real_name = character.real_name + + character.flavor_text = flavor_text + character.med_record = med_record + character.sec_record = sec_record + character.gen_record = gen_record + + character.gender = gender + character.age = age + character.b_type = b_type + + character.r_eyes = r_eyes + character.g_eyes = g_eyes + character.b_eyes = b_eyes + + character.r_hair = r_hair + character.g_hair = g_hair + character.b_hair = b_hair + + character.r_facial = r_facial + character.g_facial = g_facial + character.b_facial = b_facial + + character.r_skin = r_skin + character.g_skin = g_skin + character.b_skin = b_skin + + character.s_tone = s_tone + + character.h_style = h_style + character.f_style = f_style + + + // Destroy/cyborgize organs + + for(var/name in organ_data) + + var/status = organ_data[name] + var/obj/item/organ/external/O = character.organs_by_name[name] + if(O) + if(status == "amputated") + character.organs_by_name[O.limb_name] = null + character.organs -= O + if(O.children) // This might need to become recursive. + for(var/obj/item/organ/external/child in O.children) + character.organs_by_name[child.limb_name] = null + character.organs -= child + + else if(status == "cyborg") + if(rlimb_data[name]) + O.robotize(rlimb_data[name]) + else + O.robotize() + else + var/obj/item/organ/I = character.internal_organs_by_name[name] + if(I) + if(status == "assisted") + I.mechassist() + else if(status == "mechanical") + I.robotize() + + if(disabilities & DISABILITY_FLAG_FAT && character.species.flags & CAN_BE_FAT)//character.species.flags & CAN_BE_FAT) + character.mutations += FAT + character.mutations += OBESITY + if(disabilities & DISABILITY_FLAG_NEARSIGHTED) + character.disabilities|=NEARSIGHTED + if(disabilities & DISABILITY_FLAG_EPILEPTIC) + character.disabilities|=EPILEPSY + if(disabilities & DISABILITY_FLAG_DEAF) + character.sdisabilities|=DEAF + + // Wheelchair necessary? + var/obj/item/organ/external/l_foot = character.get_organ("l_foot") + var/obj/item/organ/external/r_foot = character.get_organ("r_foot") + if((!l_foot || l_foot.status & ORGAN_DESTROYED) && (!r_foot || r_foot.status & ORGAN_DESTROYED)) + var/obj/structure/stool/bed/chair/wheelchair/W = new /obj/structure/stool/bed/chair/wheelchair (character.loc) + character.buckled = W + character.update_canmove() + W.dir = character.dir + W.buckled_mob = character + W.add_fingerprint(character) + + character.underwear = underwear + character.undershirt = undershirt + character.socks = socks + + if(body_accessory) + character.body_accessory = body_accessory_by_name["[body_accessory]"] + + if(backbag > 4 || backbag < 1) + backbag = 1 //Same as above + character.backbag = backbag + + //Debugging report to track down a bug, which randomly assigned the plural gender to people. + if(character.gender in list(PLURAL, NEUTER)) + if(isliving(src)) //Ghosts get neuter by default + message_admins("[key_name_admin(character)] has spawned with their gender as plural or neuter. Please notify coders.") + character.gender = MALE + +/datum/preferences/proc/open_load_dialog(mob/user) + + var/DBQuery/query = dbcon.NewQuery("SELECT slot,real_name FROM [format_table_name("characters")] WHERE ckey='[user.ckey]' ORDER BY slot") + + var/dat = "" + dat += "
    " + dat += "Select a character slot to load
    " + var/name + + for(var/i=1, i<=max_save_slots, i++) + if(!query.Execute()) + var/err = query.ErrorMsg() + log_game("SQL ERROR during character slot loading. Error : \[[err]\]\n") + message_admins("SQL ERROR during character slot loading. Error : \[[err]\]\n") + return + while(query.NextRow()) + if(i==text2num(query.item[1])) + name = query.item[2] + if(!name) name = "Character[i]" + if(i==default_slot) + name = "[name]" + dat += "[name]
    " + name = null + + dat += "
    " + dat += "Close
    " + dat += "
    " // user << browse(dat, "window=saves;size=300x390") - var/datum/browser/popup = new(user, "saves", "
    Character Saves
    ", 300, 390) - popup.set_content(dat) - popup.open(0) - proc/close_load_dialog(mob/user) - user << browse(null, "window=saves") + var/datum/browser/popup = new(user, "saves", "
    Character Saves
    ", 300, 390) + popup.set_content(dat) + popup.open(0) + +/datum/preferences/proc/close_load_dialog(mob/user) + user << browse(null, "window=saves") diff --git a/code/modules/client/preferences_mysql.dm b/code/modules/client/preferences_mysql.dm index be900d254b7..016b3a7a46a 100644 --- a/code/modules/client/preferences_mysql.dm +++ b/code/modules/client/preferences_mysql.dm @@ -197,7 +197,6 @@ 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)) - be_special = sanitize_integer(be_special, 0, 65535, initial(be_special)) socks = sanitize_text(socks, initial(socks)) body_accessory = sanitize_text(body_accessory, initial(body_accessory)) @@ -268,7 +267,6 @@ sec_record='[sql_sanitize_text(html_decode(sec_record))]', gen_record='[sql_sanitize_text(html_decode(gen_record))]', player_alt_titles='[playertitlelist]', - be_special='[be_special]', disabilities='[disabilities]', organ_data='[organlist]', rlimb_data='[rlimblist]', @@ -302,7 +300,7 @@ 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, be_special, + player_alt_titles, disabilities, organ_data, rlimb_data, nanotrasen_relation, speciesprefs, socks, body_accessory) @@ -321,7 +319,7 @@ '[job_engsec_high]', '[job_engsec_med]', '[job_engsec_low]', '[job_karma_high]', '[job_karma_med]', '[job_karma_low]', '[sql_sanitize_text(html_encode(flavor_text))]', '[sql_sanitize_text(html_encode(med_record))]', '[sql_sanitize_text(html_encode(sec_record))]', '[sql_sanitize_text(html_encode(gen_record))]', - '[playertitlelist]', '[be_special]', + '[playertitlelist]', '[disabilities]', '[organlist]', '[rlimblist]', '[nanotrasen_relation]', '[speciesprefs]', '[socks]', '[body_accessory]') diff --git a/code/modules/events/alien_infestation.dm b/code/modules/events/alien_infestation.dm index a59f4eeac42..ccc0ef94191 100644 --- a/code/modules/events/alien_infestation.dm +++ b/code/modules/events/alien_infestation.dm @@ -21,7 +21,7 @@ if(temp_vent.parent.other_atmosmch.len > 50) //Stops Aliens getting stuck in small networks. See: Security, Virology vents += temp_vent - var/list/candidates = get_candidates(BE_ALIEN,ALIEN_AFK_BRACKET) + var/list/candidates = get_candidates(ROLE_ALIEN,ALIEN_AFK_BRACKET) while(spawncount > 0 && vents.len && candidates.len) var/obj/vent = pick_n_take(vents) @@ -33,4 +33,4 @@ spawncount-- successSpawn = 1 - + diff --git a/code/modules/events/borers.dm b/code/modules/events/borers.dm index d1620e45be7..d716b1df6c5 100644 --- a/code/modules/events/borers.dm +++ b/code/modules/events/borers.dm @@ -22,7 +22,7 @@ if(temp_vent.parent.other_atmosmch.len > 50) vents += temp_vent - var/list/candidates = get_candidates(BE_ALIEN,ALIEN_AFK_BRACKET) + var/list/candidates = get_candidates(ROLE_BORER,ALIEN_AFK_BRACKET) while(spawncount > 0 && vents.len && candidates.len) var/obj/vent = pick_n_take(vents) var/client/C = pick_n_take(candidates) @@ -32,4 +32,4 @@ spawncount-- successSpawn = 1 - + diff --git a/code/modules/events/slaughterevent.dm b/code/modules/events/slaughterevent.dm index c0f1ae75184..0889f8d8136 100644 --- a/code/modules/events/slaughterevent.dm +++ b/code/modules/events/slaughterevent.dm @@ -4,7 +4,7 @@ /datum/event/spawn_slaughter/proc/get_slaughter(var/end_if_fail = 0) key_of_slaughter = null if(!key_of_slaughter) - var/list/candidates = get_candidates(BE_ALIEN) + var/list/candidates = get_candidates(ROLE_DEMON) if(!candidates.len) if(end_if_fail) return 0 @@ -55,4 +55,3 @@ return 0 message_admins("Unfortunately, no candidates were available for becoming a Slaugter Demon. Shutting down.") kill() - \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm index 5494b199a87..5ffe45a8123 100644 --- a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm +++ b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm @@ -83,7 +83,7 @@ var/const/ALIEN_AFK_BRACKET = 450 // 45 seconds AttemptGrow() /obj/item/alien_embryo/proc/AttemptGrow(var/gib_on_success = 1) - var/list/candidates = get_candidates(BE_ALIEN,ALIEN_AFK_BRACKET,1) + var/list/candidates = get_candidates(ROLE_ALIEN,ALIEN_AFK_BRACKET,1) var/client/C = null // To stop clientless larva, we will check that our host has a client diff --git a/code/modules/mob/living/carbon/brain/posibrain.dm b/code/modules/mob/living/carbon/brain/posibrain.dm index 67caeb2788c..d76b7dea569 100644 --- a/code/modules/mob/living/carbon/brain/posibrain.dm +++ b/code/modules/mob/living/carbon/brain/posibrain.dm @@ -32,8 +32,9 @@ /obj/item/device/mmi/posibrain/proc/request_player() for(var/mob/dead/observer/O in player_list) if(check_observer(O)) - O << "\blue \A [src] has been activated. (Teleport | Sign Up)" - //question(O.client) + O << "\A [src] has been activated. (Teleport | Sign Up)" +// if(ROLE_POSIBRAIN in O.client.prefs.be_special) The Guardian implementation looks cleaner +// question(O.client) /obj/item/device/mmi/posibrain/proc/check_observer(var/mob/dead/observer/O) if(O.has_enabled_antagHUD == 1 && config.antag_hud_restricted) @@ -52,7 +53,7 @@ if(response == "Yes") transfer_personality(C.mob) else if (response == "Never for this round") - C.prefs.be_special ^= BE_PAI + C.prefs.be_special -= ROLE_POSIBRAIN // This should not ever happen, but let's be safe /obj/item/device/mmi/posibrain/dropbrain(var/turf/dropspot) diff --git a/code/modules/mob/living/carbon/metroid/metroid.dm b/code/modules/mob/living/carbon/metroid/metroid.dm index 4abae727c73..96680de98b8 100644 --- a/code/modules/mob/living/carbon/metroid/metroid.dm +++ b/code/modules/mob/living/carbon/metroid/metroid.dm @@ -789,7 +789,7 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75 user << "You offer the sentience potion to [M]..." being_used = 1 - var/list/candidates = get_candidates(BE_ALIEN, ALIEN_AFK_BRACKET) + var/list/candidates = get_candidates(ROLE_SENTIENT, ALIEN_AFK_BRACKET) shuffle(candidates) diff --git a/code/modules/mob/living/simple_animal/borer.dm b/code/modules/mob/living/simple_animal/borer.dm index 854969123e5..34ec44a4245 100644 --- a/code/modules/mob/living/simple_animal/borer.dm +++ b/code/modules/mob/living/simple_animal/borer.dm @@ -16,7 +16,7 @@ if (!message) return log_say("[key_name(src)] : [message]") - if (stat == 2) + if (stat == DEAD) return say_dead(message) var/mob/living/simple_animal/borer/B = src.loc src << "You whisper silently, \"[message]\"" @@ -302,7 +302,7 @@ detatch() leave_host() -mob/living/simple_animal/borer/proc/detatch() +/mob/living/simple_animal/borer/proc/detatch() if(!host) return @@ -416,7 +416,7 @@ mob/living/simple_animal/borer/proc/detatch() src << "You cannot infest a target in your current state." return - if(M.stat == 2) + if(M.stat == DEAD) src << "That is not an appropriate target." return @@ -457,15 +457,15 @@ mob/living/simple_animal/borer/proc/detatch() return //Procs for grabbing players. -mob/living/simple_animal/borer/proc/request_player() +/mob/living/simple_animal/borer/proc/request_player() for(var/mob/O in respawnable_list) if(jobban_isbanned(O, "Syndicate")) continue if(O.client) - if((BE_ALIEN in O.client.prefs.be_special) && !jobban_isbanned(O, "alien")) + if((ROLE_BORER in O.client.prefs.be_special) && !jobban_isbanned(O, "alien")) question(O.client) -mob/living/simple_animal/borer/proc/question(var/client/C) +/mob/living/simple_animal/borer/proc/question(var/client/C) spawn(0) if(!C) return var/response = alert(C, "A cortical borer needs a player. Are you interested?", "Cortical borer request", "Yes", "No", "Never for this round") @@ -474,9 +474,9 @@ mob/living/simple_animal/borer/proc/question(var/client/C) if(response == "Yes") transfer_personality(C) else if (response == "Never for this round") - C.prefs.be_special ^= BE_ALIEN + C.prefs.be_special -= ROLE_BORER -mob/living/simple_animal/borer/proc/transfer_personality(var/client/candidate) +/mob/living/simple_animal/borer/proc/transfer_personality(var/client/candidate) if(!candidate) return diff --git a/code/modules/mob/living/simple_animal/guardian/guardian.dm b/code/modules/mob/living/simple_animal/guardian/guardian.dm index fefd94092b0..b202fd9bf81 100644 --- a/code/modules/mob/living/simple_animal/guardian/guardian.dm +++ b/code/modules/mob/living/simple_animal/guardian/guardian.dm @@ -641,7 +641,7 @@ return used = TRUE user << "[use_message]" - var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as the [mob_name] of [user.real_name]?",BE_PAI, null, FALSE, 100) + var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as the [mob_name] of [user.real_name]?",ROLE_GUARDIAN, null, FALSE, 100) var/mob/dead/observer/theghost = null if(candidates.len) diff --git a/code/modules/mob/living/simple_animal/revenant/revenant.dm b/code/modules/mob/living/simple_animal/revenant/revenant.dm index 70edbc27dd3..dfe8d1838e0 100644 --- a/code/modules/mob/living/simple_animal/revenant/revenant.dm +++ b/code/modules/mob/living/simple_animal/revenant/revenant.dm @@ -442,7 +442,7 @@ if(!key_of_revenant) message_admins("The new revenant's old client either could not be found or is in a new, living mob - grabbing a random candidate instead...") - var/list/candidates = get_candidates(BE_REVENANT) + var/list/candidates = get_candidates(ROLE_REVENANT) if(!candidates.len) qdel(R) message_admins("No candidates were found for the new revenant. Oh well!") diff --git a/code/modules/mob/living/simple_animal/revenant/revenant_spawn_event.dm b/code/modules/mob/living/simple_animal/revenant/revenant_spawn_event.dm index 0f1b3545391..57ebb983e72 100644 --- a/code/modules/mob/living/simple_animal/revenant/revenant_spawn_event.dm +++ b/code/modules/mob/living/simple_animal/revenant/revenant_spawn_event.dm @@ -13,7 +13,7 @@ return key_of_revenant = null if(!key_of_revenant) - var/list/candidates = get_candidates(BE_REVENANT) + var/list/candidates = get_candidates(ROLE_REVENANT) if(!candidates.len) if(end_if_fail) return 0 From dc29161339457ac3c48ac15169c5cb6664144e79 Mon Sep 17 00:00:00 2001 From: Crazylemon64 Date: Sun, 27 Dec 2015 13:43:50 -0800 Subject: [PATCH 05/19] Adds an SQL list sanitization proc, and stores our tags in the DB --- SQL/paradise_schema.sql | 1 - SQL/paradise_schema_prefixed.sql | 1 - code/__HELPERS/sanitize_values.dm | 18 ++- code/modules/client/preferences_mysql.dm | 160 +++++++++++++++-------- code/modules/research/message_server.dm | 6 - 5 files changed, 122 insertions(+), 64 deletions(-) diff --git a/SQL/paradise_schema.sql b/SQL/paradise_schema.sql index f6e8ea640a3..b0e03f68efa 100644 --- a/SQL/paradise_schema.sql +++ b/SQL/paradise_schema.sql @@ -66,7 +66,6 @@ CREATE TABLE `characters` ( `med_record` mediumtext NOT NULL, `sec_record` mediumtext NOT NULL, `gen_record` mediumtext NOT NULL, - `be_role` mediumtext NOT NULL, `disabilities` mediumint(8) NOT NULL, `player_alt_titles` mediumtext NOT NULL, `organ_data` mediumtext NOT NULL, diff --git a/SQL/paradise_schema_prefixed.sql b/SQL/paradise_schema_prefixed.sql index 6fa053e79c1..567da99c300 100644 --- a/SQL/paradise_schema_prefixed.sql +++ b/SQL/paradise_schema_prefixed.sql @@ -66,7 +66,6 @@ CREATE TABLE `SS13_characters` ( `med_record` mediumtext NOT NULL, `sec_record` mediumtext NOT NULL, `gen_record` mediumtext NOT NULL, - `be_role` mediumtext NOT NULL, `disabilities` mediumint(8) NOT NULL, `player_alt_titles` mediumtext NOT NULL, `organ_data` mediumtext NOT NULL, diff --git a/code/__HELPERS/sanitize_values.dm b/code/__HELPERS/sanitize_values.dm index 70c63dfc789..f490f71df43 100644 --- a/code/__HELPERS/sanitize_values.dm +++ b/code/__HELPERS/sanitize_values.dm @@ -44,10 +44,24 @@ if(65 to 70) . += ascii2text(ascii+32) //letters A to F - translates to lowercase else return default return . - + /proc/sanitize_ooccolor(color) var/list/HSL = rgb2hsl(hex2num(copytext(color,2,4)),hex2num(copytext(color,4,6)),hex2num(copytext(color,6,8))) HSL[3] = min(HSL[3],0.4) var/list/RGB = hsl2rgb(arglist(HSL)) return "#[num2hex(RGB[1],2)][num2hex(RGB[2],2)][num2hex(RGB[3],2)]" - + + +// Sanitize inputs to avoid SQL injection attacks +/proc/sql_sanitize_text(var/text) + text = replacetext(text, "'", "''") + text = replacetext(text, ";", "") + text = replacetext(text, "&", "") + return text + +// Calls the above proc on each entry of a list to ensure its entries are clean +/proc/sql_sanitize_text_list(var/list/l) + var/list/new_list = l.Copy() + for (var/text in new_list) + sql_sanitize_text(text) + return new_list \ No newline at end of file diff --git a/code/modules/client/preferences_mysql.dm b/code/modules/client/preferences_mysql.dm index 016b3a7a46a..a8816db68ce 100644 --- a/code/modules/client/preferences_mysql.dm +++ b/code/modules/client/preferences_mysql.dm @@ -56,7 +56,7 @@ UI_style='[UI_style]', UI_style_color='[UI_style_color]', UI_style_alpha='[UI_style_alpha]', - be_role='[sql_sanitize_text(list2params(be_special))]', + be_role='[list2params(sql_sanitize_text_list(be_special))]', default_slot='[default_slot]', toggles='[toggles]', sound='[sound]', @@ -81,7 +81,60 @@ var/DBQuery/firstquery = dbcon.NewQuery("UPDATE [format_table_name("player")] SET default_slot=[slot] WHERE ckey='[C.ckey]'") firstquery.Execute() - var/DBQuery/query = dbcon.NewQuery("SELECT * FROM [format_table_name("characters")] WHERE ckey='[C.ckey]' AND slot='[slot]'") + // Let's not have this explode if you sneeze on the DB + var/DBQuery/query = dbcon.NewQuery({"SELECT + OOC_Notes, + real_name, + name_is_always_random, + gender, + age, + species, + language, + hair_red, + hair_green, + hair_blue, + facial_red, + facial_green, + facial_blue, + skin_tone, + skin_red, + skin_green, + skin_blue, + hair_style_name, + facial_style_name, + eyes_red, + eyes_green, + eyes_blue, + 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 + FROM [format_table_name("characters")] WHERE ckey='[C.ckey]' AND slot='[slot]'"}) if(!query.Execute()) var/err = query.ErrorMsg() log_game("SQL ERROR during character slot loading. Error : \[[err]\]\n") @@ -90,67 +143,66 @@ while(query.NextRow()) //Character - metadata = query.item[4] - real_name = query.item[5] - be_random_name = text2num(query.item[6]) - gender = query.item[7] - age = text2num(query.item[8]) - species = query.item[9] - language = query.item[10] + 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] //colors to be consolidated into hex strings (requires some work with dna code) - r_hair = text2num(query.item[11]) - g_hair = text2num(query.item[12]) - b_hair = text2num(query.item[13]) - r_facial = text2num(query.item[14]) - g_facial = text2num(query.item[15]) - b_facial = text2num(query.item[16]) - s_tone = text2num(query.item[17]) - r_skin = text2num(query.item[18]) - g_skin = text2num(query.item[19]) - b_skin = text2num(query.item[20]) - h_style = query.item[21] - f_style = query.item[22] - r_eyes = text2num(query.item[23]) - g_eyes = text2num(query.item[24]) - b_eyes = text2num(query.item[25]) - underwear = query.item[26] - undershirt = query.item[27] - backbag = text2num(query.item[28]) - b_type = query.item[29] + r_hair = text2num(query.item[8]) + g_hair = text2num(query.item[9]) + b_hair = text2num(query.item[10]) + r_facial = text2num(query.item[11]) + g_facial = text2num(query.item[12]) + b_facial = text2num(query.item[13]) + s_tone = text2num(query.item[14]) + r_skin = text2num(query.item[15]) + g_skin = text2num(query.item[16]) + b_skin = text2num(query.item[17]) + h_style = query.item[18] + f_style = query.item[19] + r_eyes = text2num(query.item[20]) + g_eyes = text2num(query.item[21]) + b_eyes = text2num(query.item[22]) + underwear = query.item[23] + undershirt = query.item[24] + backbag = text2num(query.item[25]) + b_type = query.item[26] //Jobs - alternate_option = text2num(query.item[30]) - job_support_high = text2num(query.item[31]) - job_support_med = text2num(query.item[32]) - job_support_low = text2num(query.item[33]) - job_medsci_high = text2num(query.item[34]) - job_medsci_med = text2num(query.item[35]) - job_medsci_low = text2num(query.item[36]) - job_engsec_high = text2num(query.item[37]) - job_engsec_med = text2num(query.item[38]) - job_engsec_low = text2num(query.item[39]) - job_karma_high = text2num(query.item[40]) - job_karma_med = text2num(query.item[41]) - job_karma_low = text2num(query.item[42]) + alternate_option = text2num(query.item[27]) + job_support_high = text2num(query.item[28]) + job_support_med = text2num(query.item[29]) + job_support_low = text2num(query.item[30]) + job_medsci_high = text2num(query.item[31]) + job_medsci_med = text2num(query.item[32]) + job_medsci_low = text2num(query.item[33]) + job_engsec_high = text2num(query.item[34]) + job_engsec_med = text2num(query.item[35]) + job_engsec_low = text2num(query.item[36]) + job_karma_high = text2num(query.item[37]) + job_karma_med = text2num(query.item[38]) + job_karma_low = text2num(query.item[39]) //Miscellaneous - flavor_text = query.item[43] - med_record = query.item[44] - sec_record = query.item[45] - gen_record = query.item[46] - be_special = text2num(query.item[47]) - disabilities = text2num(query.item[48]) - player_alt_titles = params2list(query.item[49]) - organ_data = params2list(query.item[50]) - rlimb_data = params2list(query.item[51]) - nanotrasen_relation = query.item[52] - speciesprefs = text2num(query.item[53]) + flavor_text = query.item[40] + med_record = query.item[41] + sec_record = query.item[42] + gen_record = query.item[43] + disabilities = text2num(query.item[44]) + player_alt_titles = params2list(query.item[45]) + organ_data = params2list(query.item[46]) + rlimb_data = params2list(query.item[47]) + nanotrasen_relation = query.item[48] + speciesprefs = text2num(query.item[49]) //socks - socks = query.item[54] - body_accessory = query.item[55] + socks = query.item[50] + body_accessory = query.item[51] //Sanitize metadata = sanitize_text(metadata, initial(metadata)) diff --git a/code/modules/research/message_server.dm b/code/modules/research/message_server.dm index 34a10b97f1d..7159f83ab0d 100644 --- a/code/modules/research/message_server.dm +++ b/code/modules/research/message_server.dm @@ -309,12 +309,6 @@ var/obj/machinery/blackbox_recorder/blackbox var/DBQuery/query_insert = dbcon.NewQuery(sql) query_insert.Execute() -// Sanitize inputs to avoid SQL injection attacks -proc/sql_sanitize_text(var/text) - text = replacetext(text, "'", "''") - text = replacetext(text, ";", "") - text = replacetext(text, "&", "") - return text proc/feedback_set(var/variable,var/value) if(!blackbox) return From 45e49de3f849e04e3f45b9a765f344c0764e272e Mon Sep 17 00:00:00 2001 From: Crazylemon64 Date: Sun, 27 Dec 2015 14:33:14 -0800 Subject: [PATCH 06/19] Adds an update proc for the sql DB, run as the DB is loaded There's probably a cooler and more automated, at-once solution to this though --- code/modules/client/preferences.dm | 9 +-- code/modules/client/preferences_mysql.dm | 84 ++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 4 deletions(-) diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 792482643ef..fcb840a894d 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -56,7 +56,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts #define MAX_SAVE_SLOTS 10 // Save slots for regular players #define MAX_SAVE_SLOTS_MEMBER 10 // Save slots for BYOND members -datum/preferences +/datum/preferences //doohickeys for savefiles // var/path var/default_slot = 1 //Holder so it doesn't default to slot 1, rather the last one used @@ -73,7 +73,6 @@ datum/preferences // var/lastchangelog = "" //Saved changlog filesize to detect if there was a change var/ooccolor = "#b82e00" var/be_special = list() //Special role selection - var/old_be_special = 0 //For converting from the old format var/UI_style = "Midnight" var/toggles = TOGGLES_DEFAULT var/sound = SOUND_DEFAULT @@ -1427,8 +1426,10 @@ datum/preferences if("be_special") var/r = href_list["role"] if(!(r in special_roles)) - message_admins("[user] attempted an href exploit! (This could have possibly lead to a \"Bobby Tables\" exploit, so they're probably up to no good). String: [r] ID: [last_id] IP: [last_ip]") - user << "Nice try." + var/cleaned_r = sql_sanitize_text(r) + if(r != cleaned_r) // hold it right there criminal scum + message_admins("[user] attempted an href exploit! (This could have possibly lead to a \"Bobby Tables\" exploit, so they're probably up to no good). String: [r] ID: [last_id] IP: [last_ip]") + user << "Hold it right there, criminal scum" else be_special ^= r diff --git a/code/modules/client/preferences_mysql.dm b/code/modules/client/preferences_mysql.dm index a8816db68ce..e10c5fb30d4 100644 --- a/code/modules/client/preferences_mysql.dm +++ b/code/modules/client/preferences_mysql.dm @@ -35,6 +35,8 @@ randomslot = text2num(query.item[9]) volume = text2num(query.item[10]) + old_roles_to_new(C) + //Sanitize ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor)) // lastchangelog = sanitize_text(lastchangelog, initial(lastchangelog)) @@ -50,6 +52,11 @@ /datum/preferences/proc/save_preferences(client/C) + // Might as well scrub out any malformed be_special list entries while we're here + for (var/role in be_special) + if(!(role in special_roles)) + be_special -= role + var/DBQuery/query = dbcon.NewQuery({"UPDATE [format_table_name("player")] SET ooccolor='[ooccolor]', @@ -384,6 +391,83 @@ message_admins("SQL ERROR during character slot saving. Error : \[[err]\]\n") return return 1 + +// If you see this proc lying around and don't know why it's there, expunge it, as this is for a short-term DB update +// 0 on failed update, 1 on success +/datum/preferences/proc/old_roles_to_new(var/client/C) + var/DBQuery/query = dbcon.NewQuery({" + SELECT be_special + FROM [format_table_name("players")] + WHERE ckey='[C.ckey]'"}) + if(!query.Execute()) + var/err = query.ErrorMsg() + log_game("SQL NOTICE: be_special has been purged from the database, bug the coders. Error : \[[err]\]\n") + message_admins("SQL NOTICE: be_special has been purged from the database, bug the coders. Error : \[[err]\]\n") + return 0 + var/old_be_special = query.item[1] + var/B_traitor = 1 + var/B_operative = 2 + var/B_changeling = 4 + var/B_wizard = 8 + var/B_malf = 16 + var/B_rev = 32 + var/B_alien = 64 + var/B_pai = 128 + var/B_cultist = 256 + var/B_ninja = 512 + var/B_raider = 1024 + var/B_vampire = 2048 + var/B_mutineer = 4096 + var/B_blob = 8192 + var/B_shadowling = 16384 + var/B_revenant = 32768 + + var/list/archived = list(B_traitor,B_operative,B_changeling,B_wizard,B_malf,B_rev,B_alien,B_pai,B_cultist,B_ninja,B_raider,B_vampire,B_mutineer,B_blob,B_revenant) + + // meow meow I am the copy cat + for(var/flag in archived) + if(old_be_special & flag) + switch(flag) + // hello i am byond i think constant variables r dumm + if(1) + be_special |= ROLE_TRAITOR + if(2) + be_special |= ROLE_OPERATIVE + if(4) + be_special |= ROLE_CHANGELING + if(8) + be_special |= ROLE_WIZARD + if(16) + be_special |= ROLE_MALF + if(32) + be_special |= ROLE_REV + if(64) + be_special |= ROLE_ALIEN + be_special |= ROLE_SENTIENT + be_special |= ROLE_DEMON + if(128) + be_special |= ROLE_PAI + be_special |= ROLE_POSIBRAIN + be_special |= ROLE_GUARDIAN + if(256) + be_special |= ROLE_CULTIST + if(512) + be_special |= ROLE_NINJA +// be_special |= ROLE_GANG since they will occupy the same ID and all + if(1024) + be_special |= ROLE_RAIDER + if(2048) + be_special |= ROLE_VAMPIRE + if(4096) + be_special |= ROLE_MUTINEER + if(8192) + be_special |= ROLE_BLOB + if(16384) + be_special |= ROLE_SHADOWLING + if(32768) + be_special |= ROLE_REVENANT + return 1 + /* /datum/preferences/proc/random_character(client/C) var/DBQuery/query = dbcon.NewQuery("SELECT slot FROM [format_table_name("characters")] WHERE ckey='[C.ckey]' ORDER BY slot") From 6f631b94c39fdcc3284df90111d1418ed555a92a Mon Sep 17 00:00:00 2001 From: Crazylemon64 Date: Sun, 27 Dec 2015 14:46:11 -0800 Subject: [PATCH 07/19] Reduces the amount of memes in the codebase --- code/modules/client/preferences.dm | 4 ++-- code/modules/client/preferences_mysql.dm | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index fcb840a894d..f343319d88a 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -1427,9 +1427,9 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts var/r = href_list["role"] if(!(r in special_roles)) var/cleaned_r = sql_sanitize_text(r) - if(r != cleaned_r) // hold it right there criminal scum + if(r != cleaned_r) // up to no good message_admins("[user] attempted an href exploit! (This could have possibly lead to a \"Bobby Tables\" exploit, so they're probably up to no good). String: [r] ID: [last_id] IP: [last_ip]") - user << "Hold it right there, criminal scum" + user << "Please don't break the server." else be_special ^= r diff --git a/code/modules/client/preferences_mysql.dm b/code/modules/client/preferences_mysql.dm index e10c5fb30d4..e7a4ef93b33 100644 --- a/code/modules/client/preferences_mysql.dm +++ b/code/modules/client/preferences_mysql.dm @@ -422,7 +422,7 @@ var/B_shadowling = 16384 var/B_revenant = 32768 - var/list/archived = list(B_traitor,B_operative,B_changeling,B_wizard,B_malf,B_rev,B_alien,B_pai,B_cultist,B_ninja,B_raider,B_vampire,B_mutineer,B_blob,B_revenant) + var/list/archived = list(B_traitor,B_operative,B_changeling,B_wizard,B_malf,B_rev,B_alien,B_pai,B_cultist,B_ninja,B_raider,B_vampire,B_mutineer,B_blob,B_shadowling,B_revenant) // meow meow I am the copy cat for(var/flag in archived) From c4cb53bf0aaa36097baaa6e01f4dc4d2f2a5bbb4 Mon Sep 17 00:00:00 2001 From: Crazylemon64 Date: Mon, 28 Dec 2015 01:12:13 -0800 Subject: [PATCH 08/19] To heck with it here we go looks good enough Also - Increases the number of memes in the codebase --- code/__DEFINES/role_preferences.dm | 2 ++ code/game/gamemodes/antag_spawner.dm | 2 +- code/modules/client/preferences.dm | 40 ++++++++++++++---------- code/modules/client/preferences_mysql.dm | 19 ++++++----- 4 files changed, 38 insertions(+), 25 deletions(-) diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index 817f3e7a76a..0c5a2d820c2 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -6,6 +6,8 @@ //These are synced with the Database, if you change the values of the defines //then you MUST update the database! +// If you're adding a new role, remember to update modules/admin/topic.dm, so admins can dish out +// justice if someone's abusing your role #define ROLE_TRAITOR "traitor" #define ROLE_OPERATIVE "operative" #define ROLE_CHANGELING "changeling" diff --git a/code/game/gamemodes/antag_spawner.dm b/code/game/gamemodes/antag_spawner.dm index 011efa31c74..608d0d4061d 100644 --- a/code/game/gamemodes/antag_spawner.dm +++ b/code/game/gamemodes/antag_spawner.dm @@ -74,7 +74,7 @@ icon_state = "vial" /obj/item/weapon/antag_spawner/slaughter_demon/attack_self(mob/user as mob) - var/list/demon_candidates = get_candidates(ROLE_ALIEN) + var/list/demon_candidates = get_candidates(ROLE_DEMON) if(user.z == ZLEVEL_CENTCOMM)//this is to make sure the wizard does NOT summon a demon from the Den.. user << "You should probably wait until you reach the station." return diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index f343319d88a..bc28c88ee2f 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -3,22 +3,28 @@ var/list/preferences_datums = list() var/global/list/special_role_times = list( //minimum age (in days) for accounts to play these roles - num2text(ROLE_PAI) = 0, - num2text(ROLE_TRAITOR) = 7, - num2text(ROLE_CHANGELING) = 14, - num2text(ROLE_SHADOWLING) = 14, - num2text(ROLE_WIZARD) = 14, - num2text(ROLE_REV) = 14, - num2text(ROLE_VAMPIRE) = 14, - num2text(ROLE_BLOB) = 14, - num2text(ROLE_REVENANT) = 14, - num2text(ROLE_OPERATIVE) = 21, - num2text(ROLE_CULTIST) = 21, - num2text(ROLE_RAIDER) = 21, - num2text(ROLE_ALIEN) = 21, - num2text(ROLE_NINJA) = 21, - num2text(ROLE_MUTINEER) = 21, - num2text(ROLE_MALF) = 30, + ROLE_PAI = 0, + ROLE_POSIBRAIN = 0, + ROLE_GUARDIAN = 0, + ROLE_TRAITOR = 7, + ROLE_CHANGELING = 14, + ROLE_SHADOWLING = 14, + ROLE_WIZARD = 14, + ROLE_REV = 14, + ROLE_VAMPIRE = 14, + ROLE_BLOB = 14, + ROLE_REVENANT = 14, + ROLE_OPERATIVE = 21, + ROLE_CULTIST = 21, + ROLE_RAIDER = 21, + ROLE_ALIEN = 21, + ROLE_DEMON = 21, + ROLE_SENTIENT = 21, +// ROLE_GANG = 21, + ROLE_BORER = 21, + ROLE_NINJA = 21, + ROLE_MUTINEER = 21, + ROLE_MALF = 30, ) /proc/player_old_enough_antag(client/C, role) @@ -1429,7 +1435,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts var/cleaned_r = sql_sanitize_text(r) if(r != cleaned_r) // up to no good message_admins("[user] attempted an href exploit! (This could have possibly lead to a \"Bobby Tables\" exploit, so they're probably up to no good). String: [r] ID: [last_id] IP: [last_ip]") - user << "Please don't break the server." + user << "Stop right there, criminal scum" else be_special ^= r diff --git a/code/modules/client/preferences_mysql.dm b/code/modules/client/preferences_mysql.dm index e7a4ef93b33..656ddb2a4e7 100644 --- a/code/modules/client/preferences_mysql.dm +++ b/code/modules/client/preferences_mysql.dm @@ -55,6 +55,7 @@ // Might as well scrub out any malformed be_special list entries while we're here for (var/role in be_special) if(!(role in special_roles)) + log_to_dd("[C.key] had a malformed role entry: '[role]'. Removing!") be_special -= role var/DBQuery/query = dbcon.NewQuery({"UPDATE [format_table_name("player")] @@ -392,19 +393,23 @@ return return 1 -// If you see this proc lying around and don't know why it's there, expunge it, as this is for a short-term DB update +// If you see this proc lying around and don't know why it's there, expunge it, as this is for a short-term DB update, starting 27/12/2015 // 0 on failed update, 1 on success /datum/preferences/proc/old_roles_to_new(var/client/C) var/DBQuery/query = dbcon.NewQuery({" SELECT be_special - FROM [format_table_name("players")] + FROM [format_table_name("player")] WHERE ckey='[C.ckey]'"}) if(!query.Execute()) - var/err = query.ErrorMsg() - log_game("SQL NOTICE: be_special has been purged from the database, bug the coders. Error : \[[err]\]\n") - message_admins("SQL NOTICE: be_special has been purged from the database, bug the coders. Error : \[[err]\]\n") return 0 - var/old_be_special = query.item[1] + var/old_be_special + while(query.NextRow()) + old_be_special = text2num(query.item[1]) + if(isnull(old_be_special)) + message_admins("SQL NOTICE: be_special has been purged from the database, bug the coders.\n") + return 0 + + old_be_special = sanitize_integer(old_be_special, 0, 65535) var/B_traitor = 1 var/B_operative = 2 var/B_changeling = 4 @@ -445,6 +450,7 @@ be_special |= ROLE_ALIEN be_special |= ROLE_SENTIENT be_special |= ROLE_DEMON + be_special |= ROLE_BORER if(128) be_special |= ROLE_PAI be_special |= ROLE_POSIBRAIN @@ -453,7 +459,6 @@ be_special |= ROLE_CULTIST if(512) be_special |= ROLE_NINJA -// be_special |= ROLE_GANG since they will occupy the same ID and all if(1024) be_special |= ROLE_RAIDER if(2048) From e5bcd0d39f2846c71924b460ea2c98c11da28ce9 Mon Sep 17 00:00:00 2001 From: Crazylemon64 Date: Mon, 28 Dec 2015 01:15:22 -0800 Subject: [PATCH 09/19] Format update now also autosaves the new antag prefs --- code/modules/client/preferences_mysql.dm | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/code/modules/client/preferences_mysql.dm b/code/modules/client/preferences_mysql.dm index 656ddb2a4e7..920a087ceac 100644 --- a/code/modules/client/preferences_mysql.dm +++ b/code/modules/client/preferences_mysql.dm @@ -471,6 +471,18 @@ be_special |= ROLE_SHADOWLING if(32768) be_special |= ROLE_REVENANT + + var/DBQuery/query2 = dbcon.NewQuery({"UPDATE [format_table_name("player")] + SET + be_role='[list2params(sql_sanitize_text_list(be_special))]' + WHERE ckey='[C.ckey]'"} + ) + + if(!query2.Execute()) + var/err = query2.ErrorMsg() + log_game("SQL ERROR during saving player preferences. Error : \[[err]\]\n") + message_admins("SQL ERROR during saving player preferences. Error : \[[err]\]\n") + return return 1 /* From 0f03947d5534c4d0cd9f8d194ac04bec020ee6b2 Mon Sep 17 00:00:00 2001 From: Fox-McCloud Date: Mon, 28 Dec 2015 08:37:27 -0500 Subject: [PATCH 10/19] Ports Elite Syndicate Hardsuit and Uplink Refactor --- code/datums/uplink_item.dm | 83 ++++++++++-------- .../items/weapons/storage/uplink_kits.dm | 11 +++ code/modules/clothing/spacesuits/rig.dm | 21 +++++ icons/mob/head.dmi | Bin 247960 -> 249331 bytes icons/mob/suit.dmi | Bin 444924 -> 446714 bytes icons/obj/clothing/hats.dmi | Bin 114682 -> 115952 bytes icons/obj/clothing/suits.dmi | Bin 149382 -> 150021 bytes 7 files changed, 79 insertions(+), 36 deletions(-) diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm index ea7f5e2abbd..c8729b833b3 100644 --- a/code/datums/uplink_item.dm +++ b/code/datums/uplink_item.dm @@ -13,9 +13,9 @@ var/list/uplink_items = list() var/datum/uplink_item/I = new item() if(!I.item) continue - if(I.gamemodes.len && ticker && !(ticker.mode.name in I.gamemodes)) + if(I.gamemodes.len && ticker && !(ticker.mode.type in I.gamemodes)) continue - if(I.excludefrom.len && ticker && (ticker.mode.name in I.excludefrom)) + if(I.excludefrom.len && ticker && (ticker.mode.type in I.excludefrom)) continue if(I.last) last += I @@ -285,7 +285,7 @@ var/list/uplink_items = list() desc = "A fully-loaded Scarborough Arms bullpup submachine gun that fires .45 rounds with a 20-round magazine and is compatible with suppressors." item = /obj/item/weapon/gun/projectile/automatic/c20r cost = 14 - gamemodes = list("nuclear emergency") + gamemodes = list(/datum/game_mode/nuclear) surplus = 40 /datum/uplink_item/dangerous/carbine @@ -294,7 +294,7 @@ var/list/uplink_items = list() reference = "AR" item = /obj/item/weapon/gun/projectile/automatic/m90 cost = 18 - gamemodes = list("nuclear emergency") + gamemodes = list(/datum/game_mode/nuclear) surplus = 50 /datum/uplink_item/dangerous/machinegun @@ -303,7 +303,7 @@ var/list/uplink_items = list() reference = "LMG" item = /obj/item/weapon/gun/projectile/automatic/l6_saw cost = 40 - gamemodes = list("nuclear emergency") + gamemodes = list(/datum/game_mode/nuclear) surplus = 0 /datum/uplink_item/dangerous/crossbow @@ -312,7 +312,7 @@ var/list/uplink_items = list() reference = "EC" item = /obj/item/weapon/gun/energy/kinetic_accelerator/crossbow cost = 12 - excludefrom = list("nuclear emergency") + excludefrom = list(/datum/game_mode/nuclear) surplus = 50 /datum/uplink_item/dangerous/flamethrower @@ -321,7 +321,7 @@ var/list/uplink_items = list() reference = "FT" item = /obj/item/weapon/flamethrower/full/tank cost = 11 - gamemodes = list("nuclear emergency") + gamemodes = list(/datum/game_mode/nuclear) surplus = 40 /datum/uplink_item/dangerous/sword @@ -344,7 +344,7 @@ var/list/uplink_items = list() reference = "VDG" item = /obj/item/weapon/grenade/spawnergrenade/manhacks cost = 8 - gamemodes = list("nuclear emergency") + gamemodes = list(/datum/game_mode/nuclear) surplus = 35 /datum/uplink_item/ammo/bioterror @@ -353,7 +353,7 @@ var/list/uplink_items = list() reference = "BTS" item = /obj/item/weapon/storage/box/syndie_kit/bioterror cost = 6 - gamemodes = list("nuclear emergency") + gamemodes = list(/datum/game_mode/nuclear) /datum/uplink_item/dangerous/tabungrenades name = "Tabun Gas Grenades" @@ -361,7 +361,7 @@ var/list/uplink_items = list() reference = "TGG" item = /obj/item/weapon/storage/box/syndie_kit/tabun cost = 15 - gamemodes = list("nuclear emergency") + gamemodes = list(/datum/game_mode/nuclear) surplus = 0 /datum/uplink_item/dangerous/emp @@ -385,7 +385,7 @@ var/list/uplink_items = list() reference = "GE" item = /obj/mecha/combat/gygax/dark/loaded cost = 90 - gamemodes = list("nuclear emergency") + gamemodes = list(/datum/game_mode/nuclear) surplus = 0 /datum/uplink_item/dangerous/mauler @@ -394,7 +394,7 @@ var/list/uplink_items = list() reference = "ME" item = /obj/mecha/combat/marauder/mauler/loaded cost = 140 - gamemodes = list("nuclear emergency") + gamemodes = list(/datum/game_mode/nuclear) surplus = 0 /datum/uplink_item/dangerous/syndieborg @@ -403,7 +403,7 @@ var/list/uplink_items = list() reference = "SC" item = /obj/item/weapon/antag_spawner/borg_tele cost = 50 - gamemodes = list("nuclear emergency") + gamemodes = list(/datum/game_mode/nuclear) surplus = 0 //for refunding the syndieborg teleporter @@ -416,7 +416,7 @@ var/list/uplink_items = list() name = "Holoparasites" desc = "Though capable of near sorcerous feats via use of hardlight holograms and nanomachines, they require an organic host as a home base and source of fuel." item = /obj/item/weapon/storage/box/syndie_kit/guardian - excludefrom = list("nuclear emergency") + excludefrom = list(/datum/game_mode/nuclear) cost = 12 // Ammunition @@ -445,7 +445,7 @@ var/list/uplink_items = list() reference = "45" item = /obj/item/ammo_box/magazine/smgm45 cost = 2 - gamemodes = list("nuclear emergency") + gamemodes = list(/datum/game_mode/nuclear) /datum/uplink_item/ammo/ammobag name = "Ammo Duffelbag - Shotgun Ammo Grab Bag" @@ -453,7 +453,7 @@ var/list/uplink_items = list() reference = "SAGL" item = /obj/item/weapon/storage/backpack/duffel/syndie/ammo/loaded cost = 10 //bulk buyer's discount. Very useful if you're buying a mech and dont have TC left to buy people non-shotgun guns - gamemodes = list("nuclear emergency") + gamemodes = list(/datum/game_mode/nuclear) /datum/uplink_item/ammo/bullslug name = "Drum Magazine - 12g Slugs" @@ -461,7 +461,7 @@ var/list/uplink_items = list() reference = "12BSG" item = /obj/item/ammo_box/magazine/m12g cost = 2 - gamemodes = list("nuclear emergency") + gamemodes = list(/datum/game_mode/nuclear) /datum/uplink_item/ammo/bullbuck name = "Drum Magazine - 12g buckshot" @@ -469,7 +469,7 @@ var/list/uplink_items = list() reference = "12BS" item = /obj/item/ammo_box/magazine/m12g/buckshot cost = 2 - gamemodes = list("nuclear emergency") + gamemodes = list(/datum/game_mode/nuclear) /datum/uplink_item/ammo/bullstun name = "Drum Magazine - 12g Stun Slug" @@ -477,7 +477,7 @@ var/list/uplink_items = list() reference = "12SS" item = /obj/item/ammo_box/magazine/m12g/stun cost = 3 - gamemodes = list("nuclear emergency") + gamemodes = list(/datum/game_mode/nuclear) /datum/uplink_item/ammo/bulldragon name = "Drum Magazine - 12g Dragon's Breath" @@ -485,7 +485,7 @@ var/list/uplink_items = list() reference = "12DB" item = /obj/item/ammo_box/magazine/m12g/dragon cost = 2 - gamemodes = list("nuclear emergency") + gamemodes = list(/datum/game_mode/nuclear) /datum/uplink_item/ammo/carbine name = "Toploader Magazine - 5.56" @@ -493,7 +493,7 @@ var/list/uplink_items = list() reference = "556" item = /obj/item/ammo_box/magazine/m556 cost = 2 - gamemodes = list("nuclear emergency") + gamemodes = list(/datum/game_mode/nuclear) /datum/uplink_item/ammo/a40mm name = "Ammo Box - 40mm grenades" @@ -501,7 +501,7 @@ var/list/uplink_items = list() reference = "40MM" item = /obj/item/ammo_box/a40mm cost = 4 - gamemodes = list("nuclear emergency") + gamemodes = list(/datum/game_mode/nuclear) /datum/uplink_item/ammo/machinegun name = "Box Magazine - 7.62x51mm" @@ -509,7 +509,7 @@ var/list/uplink_items = list() reference = "762" item = /obj/item/ammo_box/magazine/m762 cost = 12 - gamemodes = list("nuclear emergency") + gamemodes = list(/datum/game_mode/nuclear) surplus = 0 // STEALTHY WEAPONS @@ -530,7 +530,7 @@ var/list/uplink_items = list() reference = "SP" item = /obj/item/weapon/pen/sleepy cost = 8 - excludefrom = list("nuclear emergency") + excludefrom = list(/datum/game_mode/nuclear) /datum/uplink_item/stealthy_weapons/soap name = "Syndicate Soap" @@ -605,14 +605,14 @@ var/list/uplink_items = list() reference = "NSSS" item = /obj/item/clothing/shoes/syndigaloshes cost = 2 - excludefrom = list("nuclear emergency") + excludefrom = list(/datum/game_mode/nuclear) /datum/uplink_item/stealthy_tools/syndigaloshes/nuke name = "Tactical No-Slip Brown Shoes" desc = "These allow you to run on wet floors. They do not work on lubricated surfaces, and the maker swears they're better than normal ones, somehow." reference = "NNSSS" cost = 4 //but they aren't - gamemodes = list("nuclear emergency") + gamemodes = list(/datum/game_mode/nuclear) /datum/uplink_item/stealthy_tools/agent_card name = "Agent ID Card" @@ -691,7 +691,7 @@ var/list/uplink_items = list() reference = "SBM" item = /obj/item/weapon/storage/belt/military cost = 3 - excludefrom = list("nuclear emergency") + excludefrom = list(/datum/game_mode/nuclear) /datum/uplink_item/device_tools/medkit name = "Syndicate Combat Medic Kit" @@ -700,7 +700,7 @@ var/list/uplink_items = list() reference = "SCMK" item = /obj/item/weapon/storage/firstaid/tactical cost = 9 - gamemodes = list("nuclear emergency") + gamemodes = list(/datum/game_mode/nuclear) /datum/uplink_item/device_tools/space_suit name = "Space Suit" @@ -718,6 +718,17 @@ var/list/uplink_items = list() item = /obj/item/weapon/storage/box/syndie_kit/hardsuit cost = 8 +/datum/uplink_item/device_tools/elite_hardsuit + name = "Elite Syndicate Hardsuit" + desc = "The elite Syndicate hardsuit is worn by only the best nuclear agents. Features much better armoring and complete fireproofing, as well as a built in jetpack. \ + When the built in helmet is deployed your identity will be protected, even in death, as the suit cannot be removed by outside forces. Toggling the suit into combat mode \ + will allow you all the mobility of a loose fitting uniform without sacrificing armoring. Additionally the suit is collapsible, small enough to fit within a backpack. \ + Nanotrasen crewmembers are trained to report red space suit sightings; these suits in particular are known to drive employees into a panic." + reference = "ESHS" + item = /obj/item/weapon/storage/box/syndie_kit/elite_hardsuit + cost = 8 + gamemodes = list(/datum/game_mode/nuclear) + /datum/uplink_item/device_tools/thermal name = "Thermal Imaging Glasses" desc = "These glasses are thermals disguised as engineers' optical meson scanners. They allow you to see organisms through walls by capturing the upper portion of the infra-red light spectrum, emitted as heat and light by objects. Hotter objects, such as warm bodies, cybernetic organisms and artificial intelligence cores emit more of this light than cooler objects like walls and airlocks." @@ -755,7 +766,7 @@ var/list/uplink_items = list() reference = "BRMB" item = /obj/item/clothing/shoes/magboots/syndie cost = 3 - gamemodes = list("nuclear emergency") + gamemodes = list(/datum/game_mode/nuclear) /datum/uplink_item/device_tools/plastic_explosives name = "Composition C-4" @@ -793,7 +804,7 @@ var/list/uplink_items = list() reference = "SD" item = /obj/item/device/syndicatedetonator cost = 3 - gamemodes = list("nuclear emergency") + gamemodes = list(/datum/game_mode/nuclear) /datum/uplink_item/device_tools/advpinpointer name = "Advanced Pinpointer" @@ -815,7 +826,7 @@ var/list/uplink_items = list() item = /obj/item/weapon/circuitboard/teleporter reference = "TP" cost = 40 - gamemodes = list("nuclear emergency") + gamemodes = list(/datum/game_mode/nuclear) surplus = 0 /datum/uplink_item/device_tools/shield @@ -824,7 +835,7 @@ var/list/uplink_items = list() item = /obj/item/weapon/shield/energy reference = "ESD" cost = 16 - gamemodes = list("nuclear emergency") + gamemodes = list(/datum/game_mode/nuclear) surplus = 20 /datum/uplink_item/device_tools/medgun @@ -833,7 +844,7 @@ var/list/uplink_items = list() item = /obj/item/weapon/gun/medbeam reference = "MBG" cost = 15 - gamemodes = list("nuclear emergency") + gamemodes = list(/datum/game_mode/nuclear) // IMPLANTS @@ -903,7 +914,7 @@ var/list/uplink_items = list() reference = "SYB" item = /obj/item/weapon/storage/box/syndicate cost = 20 - excludefrom = list("nuclear emergency") + excludefrom = list(/datum/game_mode/nuclear) /datum/uplink_item/badass/syndiecards name = "Syndicate Playing Cards" @@ -912,7 +923,7 @@ var/list/uplink_items = list() reference = "SPC" item = /obj/item/toy/cards/deck/syndicate cost = 1 - excludefrom = list("nuclear emergency") + excludefrom = list(/datum/game_mode/nuclear) surplus = 40 /datum/uplink_item/badass/syndiecash @@ -962,7 +973,7 @@ var/list/uplink_items = list() reference = "SYSC" cost = 20 item = /obj/item/weapon/storage/box/syndicate - excludefrom = list("nuclear emergency") + excludefrom = list(/datum/game_mode/nuclear) /datum/uplink_item/badass/surplus_crate/spawn_item(turf/loc, obj/item/device/uplink/U) var/obj/structure/closet/crate/C = new(loc) diff --git a/code/game/objects/items/weapons/storage/uplink_kits.dm b/code/game/objects/items/weapons/storage/uplink_kits.dm index 50fb3e60ad8..7a0c29b3bfa 100644 --- a/code/game/objects/items/weapons/storage/uplink_kits.dm +++ b/code/game/objects/items/weapons/storage/uplink_kits.dm @@ -150,6 +150,17 @@ new /obj/item/clothing/head/helmet/space/rig/syndi(src) return +/obj/item/weapon/storage/box/syndie_kit/elite_hardsuit + name = "Boxed Elite Syndicate Hardsuit and Helmet" + can_hold = list("/obj/item/clothing/suit/space/rig/syndi/elite", "/obj/item/clothing/head/helmet/space/rig/syndi/elite") + max_w_class = 3 + +/obj/item/weapon/storage/box/syndie_kit/elite_hardsuit/New() + ..() + new /obj/item/clothing/suit/space/rig/syndi/elite(src) + new /obj/item/clothing/head/helmet/space/rig/syndi/elite(src) + return + /obj/item/weapon/storage/box/syndie_kit/conversion name = "box (CK)" diff --git a/code/modules/clothing/spacesuits/rig.dm b/code/modules/clothing/spacesuits/rig.dm index c96702b54b7..bc6d6f995cf 100644 --- a/code/modules/clothing/spacesuits/rig.dm +++ b/code/modules/clothing/spacesuits/rig.dm @@ -364,6 +364,27 @@ user.update_inv_wear_suit() user.update_inv_w_uniform() +//Elite Syndie suit +/obj/item/clothing/head/helmet/space/rig/syndi/elite + name = "elite syndicate hardsuit helmet" + desc = "An elite version of the syndicate helmet, with improved armour and fire shielding. It is in travel mode. Property of Gorlex Marauders." + icon_state = "hardsuit0-syndielite" + item_color = "syndielite" + armor = list(melee = 80, bullet = 70, laser = 50, energy = 25, bomb = 55, bio = 100, rad = 70) + heat_protection = HEAD + max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT + sprite_sheets = null + +/obj/item/clothing/suit/space/rig/syndi/elite + name = "elite syndicate hardsuit" + desc = "An elite version of the syndicate hardsuit, with improved armour and fire shielding. It is in travel mode." + icon_state = "hardsuit0-syndielite" + item_color = "syndielite" + armor = list(melee = 80, bullet = 70, laser = 50, energy = 25, bomb = 55, bio = 100, rad = 70) + heat_protection = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT + sprite_sheets = null + //Wizard Rig /obj/item/clothing/head/helmet/space/rig/wizard name = "gem-encrusted hardsuit helmet" diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi index 33e1e3dcaa4af173aad898e71fa383c92276985f..240314dbb85697530389c947aaec1aa97b459565 100644 GIT binary patch delta 21628 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 diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi index 9735f614804171b119c671e4b0bf6fcd031be2a2..4086b3259860e018422875c21ba4b3abd7ea45d2 100644 GIT binary patch delta 13943 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 Sr*#JeEH4#bE0n!34gNpCEkR5G diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi index 492d22ce3df40eb7b3da72cbc0de52e64539491a..e16c5188681f9a42ca0ff8b13fb154590af1259e 100644 GIT binary patch delta 5277 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 DS6DKP From 24aa63c8125ecba71732a492de72f7062acdff6a Mon Sep 17 00:00:00 2001 From: SamCroswell Date: Mon, 28 Dec 2015 09:55:13 -0500 Subject: [PATCH 11/19] Adds darkness_view to helmets --- code/modules/clothing/clothing.dm | 1 + code/modules/mob/living/carbon/human/species/species.dm | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 362d60e8dd9..f462bce2ee2 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -264,6 +264,7 @@ BLIND // can't see anything var/flash_protect = 0 var/tint = 0 var/HUDType = null + var/darkness_view = 0 var/vision_flags = 0 var/see_darkness = 1 diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm index bf0702f5f9e..6cff7f5f7a0 100644 --- a/code/modules/mob/living/carbon/human/species/species.dm +++ b/code/modules/mob/living/carbon/human/species/species.dm @@ -413,6 +413,7 @@ if(H.client) H.client.screen += global_hud.darkMask + var/minimum_darkness_view = INFINITY if(H.glasses) if(istype(H.glasses, /obj/item/clothing/glasses)) var/obj/item/clothing/glasses/G = H.glasses @@ -420,6 +421,7 @@ if(G.darkness_view) H.see_in_dark = G.darkness_view + minimum_darkness_view = G.darkness_view if(!G.see_darkness) H.see_invisible = SEE_INVISIBLE_MINIMUM @@ -437,6 +439,9 @@ var/obj/item/clothing/head/hat = H.head H.sight |= hat.vision_flags + if(hat.darkness_view && hat.darkness_view < minimum_darkness_view) // Pick the lowest of the two darkness_views between the glasses and helmet. + H.see_in_dark = hat.darkness_view + if(!hat.see_darkness) H.see_invisible = SEE_INVISIBLE_MINIMUM From b7848e3ed3b943067f7083dc513f526f4786636f Mon Sep 17 00:00:00 2001 From: FalseIncarnate Date: Mon, 28 Dec 2015 11:23:21 -0500 Subject: [PATCH 12/19] Heater / Freezer QOL Tweak Atmospherics Heaters and Freezers now let the player select the direction for the connector from a list of the cardinal directions. - Previously randomly picked a direction, leading to a lot of wasted time if RNG was angry with you. --- code/game/machinery/Freezer.dm | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/code/game/machinery/Freezer.dm b/code/game/machinery/Freezer.dm index 3725a3e929d..49c1fb8d325 100644 --- a/code/game/machinery/Freezer.dm +++ b/code/game/machinery/Freezer.dm @@ -43,7 +43,7 @@ T += M.rating min_temperature = max(0,T0C - (170 + (T*15))) current_heat_capacity = 1000 * ((H - 1) ** 2) - + /obj/machinery/atmospherics/unary/cold_sink/freezer/construction() ..(dir,dir) @@ -62,8 +62,10 @@ if(!panel_open) user << "Open the maintenance panel first." return + var/list/choices = list("West" = WEST, "East" = EAST, "South" = SOUTH, "North" = NORTH) + var/selected = input(user,"Select a direction for the connector.", "Connector Direction") in choices + dir = choices[selected] playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - dir = pick(WEST,EAST,SOUTH,NORTH) var/node_connect = dir initialize_directions = dir for(var/obj/machinery/atmospherics/target in get_step(src,node_connect)) @@ -84,7 +86,7 @@ /obj/machinery/atmospherics/unary/cold_sink/freezer/attack_ai(mob/user as mob) attack_hand(user) - + /obj/machinery/atmospherics/unary/cold_sink/freezer/attack_ghost(mob/user as mob) attack_hand(user) @@ -92,7 +94,7 @@ if(panel_open) user << "Close the maintenance panel first." return - + src.ui_interact(user) /obj/machinery/atmospherics/unary/cold_sink/freezer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) @@ -193,8 +195,8 @@ RefreshParts() /obj/machinery/atmospherics/unary/heat_reservoir/heater/construction() - ..(dir,dir) - + ..(dir,dir) + /obj/machinery/atmospherics/unary/heat_reservoir/heater/RefreshParts() var/H var/T @@ -220,8 +222,10 @@ if(!panel_open) user << "Open the maintenance panel first." return + var/list/choices = list("West" = WEST, "East" = EAST, "South" = SOUTH, "North" = NORTH) + var/selected = input(user,"Select a direction for the connector.", "Connector Direction") in choices + dir = choices[selected] playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - dir = pick(WEST,EAST,SOUTH,NORTH) var/node_connect = dir initialize_directions = dir for(var/obj/machinery/atmospherics/target in get_step(src,node_connect)) @@ -242,9 +246,9 @@ /obj/machinery/atmospherics/unary/heat_reservoir/heater/attack_ai(mob/user as mob) attack_hand(user) - + /obj/machinery/atmospherics/unary/heat_reservoir/heater/attack_ghost(mob/user as mob) - src.attack_hand(user) + src.attack_hand(user) /obj/machinery/atmospherics/unary/heat_reservoir/heater/attack_hand(mob/user as mob) if(panel_open) From 4908b327270ef8d7f1c0f96c326cecd28c47b43c Mon Sep 17 00:00:00 2001 From: Fox-McCloud Date: Tue, 29 Dec 2015 00:56:08 -0500 Subject: [PATCH 13/19] A few Overdose Reagent Tweaks --- code/modules/reagents/newchem/drugs.dm | 4 +--- code/modules/reagents/newchem/newchem_procs.dm | 1 - .../oldchem/reagents/drink/reagents_alcohol.dm | 18 ++++++++++++------ 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/code/modules/reagents/newchem/drugs.dm b/code/modules/reagents/newchem/drugs.dm index c27bef559ae..8216425da6a 100644 --- a/code/modules/reagents/newchem/drugs.dm +++ b/code/modules/reagents/newchem/drugs.dm @@ -15,7 +15,7 @@ /datum/reagent/nicotine/on_mob_life(var/mob/living/M as mob) if(!M) M = holder.my_atom - var/smoke_message = pick("You can just feel your lungs dying!", "You feel relaxed.", "You feel calmed.", "You feel the lung cancer forming.", "You feel the money you wasted.", "You feel like a space cowboy.", "You feel rugged.") + var/smoke_message = pick("You feel relaxed.", "You feel calmed.", "You feel like a space cowboy.", "You feel rugged.") if(prob(5)) M << "[smoke_message]" if(prob(50)) @@ -27,8 +27,6 @@ return /datum/reagent/nicotine/overdose_process(var/mob/living/M as mob) - if(prob(20)) - M << "You feel like you smoked too much." M.adjustToxLoss(1*REM) M.adjustOxyLoss(1*REM) ..() diff --git a/code/modules/reagents/newchem/newchem_procs.dm b/code/modules/reagents/newchem/newchem_procs.dm index a3dc47f26a4..92aa05c0280 100644 --- a/code/modules/reagents/newchem/newchem_procs.dm +++ b/code/modules/reagents/newchem/newchem_procs.dm @@ -45,7 +45,6 @@ datum/reagents/proc/metabolize(var/mob/M) if(M && R) if(R.volume >= R.overdose_threshold && !R.overdosed && R.overdose_threshold > 0) R.overdosed = 1 - M << "You feel like you took too much [R.name]!" R.overdose_start(M) if(R.volume < R.overdose_threshold && R.overdosed) R.overdosed = 0 diff --git a/code/modules/reagents/oldchem/reagents/drink/reagents_alcohol.dm b/code/modules/reagents/oldchem/reagents/drink/reagents_alcohol.dm index 0dd38567ccc..81ed8f644ac 100644 --- a/code/modules/reagents/oldchem/reagents/drink/reagents_alcohol.dm +++ b/code/modules/reagents/oldchem/reagents/drink/reagents_alcohol.dm @@ -144,13 +144,16 @@ confused_start = 100 //copy paste from LSD... shoot me -/datum/reagent/ethanol/absinthe/on_mob_life(var/mob/M) +/datum/reagent/ethanol/absinthe/on_mob_life(var/mob/living/M) if(!M) M = holder.my_atom if(!data) data = 1 data++ - M:hallucination += 5 - if(volume > overdose_threshold) - M:adjustToxLoss(1) + M.hallucination += 5 + ..() + return + +/datum/reagent/ethanol/absinthe/overdose_process(mob/living/M) + M.adjustToxLoss(1) ..() return @@ -164,8 +167,11 @@ /datum/reagent/ethanol/rum/on_mob_life(var/mob/living/M as mob) ..() M.dizziness +=5 - if(volume > overdose_threshold) - M:adjustToxLoss(1) + return + +/datum/reagent/ethanol/rum/overdose_process(mob/living/M) + M.adjustToxLoss(1) + ..() return /datum/reagent/ethanol/mojito From 3a6e7123d4179b9e2c2073bae5c690cad5d46098 Mon Sep 17 00:00:00 2001 From: Fox-McCloud Date: Tue, 29 Dec 2015 10:23:44 -0500 Subject: [PATCH 14/19] Adds in Pajama Closets --- _maps/map_files/cyberiad/cyberiad.dmm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/_maps/map_files/cyberiad/cyberiad.dmm b/_maps/map_files/cyberiad/cyberiad.dmm index b3d2b1e0fc8..e1a492d2ab1 100644 --- a/_maps/map_files/cyberiad/cyberiad.dmm +++ b/_maps/map_files/cyberiad/cyberiad.dmm @@ -1930,7 +1930,7 @@ "aLf" = (/obj/machinery/newscaster{pixel_y = -28},/obj/structure/closet/athletic_mixed,/turf/simulated/floor{icon_state = "neutral"},/area/crew_quarters/fitness) "aLg" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"; tag = ""},/obj/machinery/light,/obj/structure/closet/boxinggloves,/turf/simulated/floor{icon_state = "neutral"},/area/crew_quarters/fitness) "aLh" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/structure/disposalpipe/segment{dir = 1; icon_state = "pipe-c"},/obj/structure/closet/masks,/turf/simulated/floor{icon_state = "neutral"},/area/crew_quarters/fitness) -"aLi" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/light_switch{pixel_y = -25},/turf/simulated/floor{icon_state = "neutral"},/area/crew_quarters/fitness) +"aLi" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/light_switch{pixel_y = -25},/obj/structure/closet/wardrobe/pjs,/turf/simulated/floor{icon_state = "neutral"},/area/crew_quarters/fitness) "aLj" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/poolcontroller{pixel_y = -25; srange = 7},/turf/simulated/floor{icon_state = "neutral"},/area/crew_quarters/fitness) "aLk" = (/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"; tag = ""},/obj/structure/disposalpipe/segment{dir = 2; icon_state = "pipe-c"},/turf/simulated/floor,/area/crew_quarters/fitness) "aLl" = (/obj/structure/reagent_dispensers/water_cooler,/turf/simulated/floor,/area/crew_quarters/fitness) @@ -3376,7 +3376,7 @@ "bmV" = (/obj/machinery/door/airlock{name = "Unit 1"},/turf/simulated/floor{icon_state = "freezerfloor"},/area/crew_quarters/locker/locker_toilet) "bmW" = (/obj/machinery/light_switch{pixel_y = 28},/obj/machinery/atmospherics/unary/vent_scrubber{dir = 4; on = 1},/turf/simulated/floor{icon_state = "freezerfloor"},/area/crew_quarters/locker/locker_toilet) "bmX" = (/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor{icon_state = "freezerfloor"},/area/crew_quarters/locker/locker_toilet) -"bmY" = (/obj/structure/table,/obj/structure/window/reinforced{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor{dir = 8; icon_state = "barber"},/area/crew_quarters/locker) +"bmY" = (/obj/structure/window/reinforced{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/closet/wardrobe/pjs,/turf/simulated/floor{dir = 8; icon_state = "barber"},/area/crew_quarters/locker) "bmZ" = (/turf/simulated/floor{dir = 8; icon_state = "barber"},/area/crew_quarters/locker) "bna" = (/obj/structure/window/reinforced{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/dresser,/turf/simulated/floor{dir = 8; icon_state = "barber"},/area/crew_quarters/locker) "bnb" = (/obj/machinery/portable_atmospherics/pump,/turf/simulated/floor{icon_state = "delivery"},/area/crew_quarters/locker) @@ -6280,7 +6280,7 @@ "cqN" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor{icon_state = "white"},/area/medical/surgery) "cqO" = (/obj/structure/table,/obj/item/weapon/reagent_containers/blood/AMinus,/obj/item/weapon/reagent_containers/blood/APlus,/obj/item/weapon/reagent_containers/blood/BMinus,/obj/item/weapon/reagent_containers/blood/BPlus,/obj/item/weapon/reagent_containers/blood/OPlus,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/alarm{pixel_y = 23},/obj/item/weapon/reagent_containers/blood/OMinus,/obj/machinery/camera{c_tag = "Medbay Surgery 2 North"; network = list("SS13")},/turf/simulated/floor{icon_state = "white"},/area/medical/surgery) "cqP" = (/obj/structure/table,/obj/item/weapon/storage/box/gloves,/obj/item/weapon/storage/box/masks,/obj/item/weapon/reagent_containers/spray/cleaner{desc = "Someone has crossed out the Space from Space Cleaner and written in Surgery. 'Do not remove under punishment of death!!!' is scrawled on the back."; name = "Surgery Cleaner"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/light_switch{pixel_x = 5; pixel_y = 27},/obj/machinery/holosign_switch{id = "surgery2"; pixel_x = -5; pixel_y = 27},/turf/simulated/floor{icon_state = "white"},/area/medical/surgery) -"cqQ" = (/obj/machinery/light{dir = 8},/turf/simulated/floor{dir = 8; icon_state = "whitered"},/area/medical/medbay2) +"cqQ" = (/obj/machinery/light{dir = 8},/obj/structure/closet/wardrobe/pjs,/turf/simulated/floor{dir = 8; icon_state = "whitered"},/area/medical/medbay2) "cqR" = (/obj/machinery/door/airlock/maintenance{req_access_txt = "12"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4; level = 1},/turf/simulated/floor/plating,/area/maintenance/asmaint2) "cqS" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = ""},/obj/machinery/atmospherics/pipe/simple/visible/universal,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4; level = 1},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating,/area/maintenance/asmaint2) "cqT" = (/obj/effect/landmark{name = "xeno_spawn"; pixel_x = -1},/turf/simulated/floor/plating,/area/maintenance/asmaint) From e576b3a7774c6f817e67fecd866e2be8e482a203 Mon Sep 17 00:00:00 2001 From: Crazylemon Date: Tue, 29 Dec 2015 10:18:56 -0800 Subject: [PATCH 15/19] Fixes Fox's points --- code/game/gamemodes/borer/borer.dm | 2 +- code/modules/client/preferences_mysql.dm | 104 +++++++++++------------ 2 files changed, 53 insertions(+), 53 deletions(-) diff --git a/code/game/gamemodes/borer/borer.dm b/code/game/gamemodes/borer/borer.dm index c31216c8add..bf381ef763d 100644 --- a/code/game/gamemodes/borer/borer.dm +++ b/code/game/gamemodes/borer/borer.dm @@ -29,7 +29,7 @@ // also make sure that there's at least one borer and one host recommended_enemies = max(src.num_players() / 20 * 2, 2) - var/list/datum/mind/possible_borers = get_players_for_role(ROLE_ALIEN) + var/list/datum/mind/possible_borers = get_players_for_role(ROLE_BORER) if(possible_borers.len < 2) log_admin("MODE FAILURE: BORER. NOT ENOUGH BORER CANDIDATES.") diff --git a/code/modules/client/preferences_mysql.dm b/code/modules/client/preferences_mysql.dm index 920a087ceac..84d36fa9ea2 100644 --- a/code/modules/client/preferences_mysql.dm +++ b/code/modules/client/preferences_mysql.dm @@ -91,58 +91,58 @@ // Let's not have this explode if you sneeze on the DB var/DBQuery/query = dbcon.NewQuery({"SELECT - OOC_Notes, - real_name, - name_is_always_random, - gender, - age, - species, - language, - hair_red, - hair_green, - hair_blue, - facial_red, - facial_green, - facial_blue, - skin_tone, - skin_red, - skin_green, - skin_blue, - hair_style_name, - facial_style_name, - eyes_red, - eyes_green, - eyes_blue, - 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 - FROM [format_table_name("characters")] WHERE ckey='[C.ckey]' AND slot='[slot]'"}) + OOC_Notes, + real_name, + name_is_always_random, + gender, + age, + species, + language, + hair_red, + hair_green, + hair_blue, + facial_red, + facial_green, + facial_blue, + skin_tone, + skin_red, + skin_green, + skin_blue, + hair_style_name, + facial_style_name, + eyes_red, + eyes_green, + eyes_blue, + 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 + FROM [format_table_name("characters")] WHERE ckey='[C.ckey]' AND slot='[slot]'"}) if(!query.Execute()) var/err = query.ErrorMsg() log_game("SQL ERROR during character slot loading. Error : \[[err]\]\n") From 9045a4f011937b85e17cac7314e6b80b6b76b519 Mon Sep 17 00:00:00 2001 From: Fox-McCloud Date: Tue, 29 Dec 2015 22:43:18 -0500 Subject: [PATCH 16/19] flavortext tweaks --- code/modules/reagents/newchem/drugs.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/reagents/newchem/drugs.dm b/code/modules/reagents/newchem/drugs.dm index 8216425da6a..69679560ef8 100644 --- a/code/modules/reagents/newchem/drugs.dm +++ b/code/modules/reagents/newchem/drugs.dm @@ -15,7 +15,7 @@ /datum/reagent/nicotine/on_mob_life(var/mob/living/M as mob) if(!M) M = holder.my_atom - var/smoke_message = pick("You feel relaxed.", "You feel calmed.", "You feel like a space cowboy.", "You feel rugged.") + var/smoke_message = pick("You feel relaxed.", "You feel calmed.", "You feel less stressed.", "You feel more placid.", "You feel more undivided.") if(prob(5)) M << "[smoke_message]" if(prob(50)) From d14aac6f7b5598a9a7318de4bbaca2b55feda338 Mon Sep 17 00:00:00 2001 From: Fox-McCloud Date: Wed, 30 Dec 2015 00:07:37 -0500 Subject: [PATCH 17/19] nicotine patches --- code/game/machinery/vending.dm | 4 ++-- code/modules/reagents/newchem/patch.dm | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index f05ab015c49..0a87b6c61fd 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -865,10 +865,10 @@ product_ads = "Probably not bad for you!;Don't believe the scientists!;It's good for you!;Don't quit, buy more!;Smoke!;Nicotine heaven.;Best cigarettes since 2150.;Award-winning cigs." vend_delay = 34 icon_state = "cigs" - products = list(/obj/item/weapon/storage/fancy/cigarettes = 5,/obj/item/weapon/storage/fancy/cigarettes/cigpack_uplift = 3,/obj/item/weapon/storage/fancy/cigarettes/cigpack_robust = 2,/obj/item/weapon/storage/fancy/cigarettes/cigpack_carp = 3,/obj/item/weapon/storage/fancy/cigarettes/cigpack_midori = 1,/obj/item/weapon/storage/fancy/cigarettes/cigpack_random = 2,/obj/item/weapon/storage/box/matches = 10,/obj/item/weapon/lighter/random = 4,/obj/item/weapon/rollingpaperpack = 5) + products = list(/obj/item/weapon/storage/fancy/cigarettes = 5,/obj/item/weapon/storage/fancy/cigarettes/cigpack_uplift = 3,/obj/item/weapon/storage/fancy/cigarettes/cigpack_robust = 2,/obj/item/weapon/storage/fancy/cigarettes/cigpack_carp = 3,/obj/item/weapon/storage/fancy/cigarettes/cigpack_midori = 1,/obj/item/weapon/storage/fancy/cigarettes/cigpack_random = 2, /obj/item/weapon/reagent_containers/pill/patch/nicotine = 10, /obj/item/weapon/storage/box/matches = 10,/obj/item/weapon/lighter/random = 4,/obj/item/weapon/rollingpaperpack = 5) contraband = list(/obj/item/weapon/lighter/zippo = 4) premium = list(/obj/item/clothing/mask/cigarette/cigar/havana = 2,/obj/item/weapon/storage/fancy/cigarettes/cigpack_robustgold = 1) - prices = list(/obj/item/weapon/storage/fancy/cigarettes = 60,/obj/item/weapon/storage/fancy/cigarettes/cigpack_uplift = 60,/obj/item/weapon/storage/fancy/cigarettes/cigpack_robust = 60,/obj/item/weapon/storage/fancy/cigarettes/cigpack_carp = 60,/obj/item/weapon/storage/fancy/cigarettes/cigpack_midori = 60,/obj/item/weapon/storage/fancy/cigarettes/cigpack_random = 150,/obj/item/weapon/storage/box/matches = 10,/obj/item/weapon/lighter/random = 60, /obj/item/weapon/rollingpaperpack = 20) + prices = list(/obj/item/weapon/storage/fancy/cigarettes = 60,/obj/item/weapon/storage/fancy/cigarettes/cigpack_uplift = 60,/obj/item/weapon/storage/fancy/cigarettes/cigpack_robust = 60,/obj/item/weapon/storage/fancy/cigarettes/cigpack_carp = 60,/obj/item/weapon/storage/fancy/cigarettes/cigpack_midori = 60,/obj/item/weapon/storage/fancy/cigarettes/cigpack_random = 150, /obj/item/weapon/reagent_containers/pill/patch/nicotine = 15, /obj/item/weapon/storage/box/matches = 10,/obj/item/weapon/lighter/random = 60, /obj/item/weapon/rollingpaperpack = 20) refill_canister = /obj/item/weapon/vending_refill/cigarette /obj/machinery/vending/cigarette/New() diff --git a/code/modules/reagents/newchem/patch.dm b/code/modules/reagents/newchem/patch.dm index 1e71a84d304..7901c97cbc0 100644 --- a/code/modules/reagents/newchem/patch.dm +++ b/code/modules/reagents/newchem/patch.dm @@ -36,4 +36,11 @@ desc = "Helps with burn injuries." New() ..() - reagents.add_reagent("synthflesh", 20) \ No newline at end of file + reagents.add_reagent("synthflesh", 20) + +/obj/item/weapon/reagent_containers/pill/patch/nicotine + name = "nicotine patch" + desc = "Helps temporarily curb the cravings of nicotine dependency." + New() + ..() + reagents.add_reagent("nicotine", 20) \ No newline at end of file From a6725230b46eee3a525a959aefe37615ea0666b7 Mon Sep 17 00:00:00 2001 From: Fox-McCloud Date: Wed, 30 Dec 2015 02:00:28 -0500 Subject: [PATCH 18/19] sheets --- _maps/map_files/cyberiad/cyberiad.dmm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/_maps/map_files/cyberiad/cyberiad.dmm b/_maps/map_files/cyberiad/cyberiad.dmm index e1a492d2ab1..d951ce24e56 100644 --- a/_maps/map_files/cyberiad/cyberiad.dmm +++ b/_maps/map_files/cyberiad/cyberiad.dmm @@ -8712,6 +8712,7 @@ "dlB" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = ""},/turf/simulated/floor/plating/airless,/area/space) "dlC" = (/obj/structure/grille,/obj/structure/window/full/shuttle,/turf/space,/area/shuttle/constructionsite) "dlD" = (/obj/docking_port/mobile/pod{dir = 4; id = "pod4"; name = "escape pod 4"},/obj/machinery/door/airlock/shuttle{id_tag = "s_docking_airlock"; name = "Escape Pod Hatch"},/turf/simulated/shuttle/floor,/area/shuttle/pod_4) +"dlE" = (/obj/structure/table,/obj/structure/bedsheetbin{pixel_x = -1; pixel_y = 2},/turf/simulated/floor{dir = 8; icon_state = "barber"},/area/crew_quarters/locker) (1,1,1) = {" bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik @@ -8839,7 +8840,7 @@ bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbi bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbqYbqXbqXbqXbqXbqXbqXbqXbqXbqXbqXbqZbraaGdbraaJrbfqbgNblwbimblxblxblxblybimblzbgNblAblBbjWblCblCblCblCblDblCblEbecblFblGblHblHblIblJbcoblKblLblMblNblOblPblQblRblSblRblTblTblTblTblTblUberbeublVblWblXblYblZbmabmbbmcbmdbkBbmebmfbmgbmgbmgbmgbmhbmgbmibmjbmkbmlbmebmmbmnbcEbmobmpbmqbkNbmsbmtaYiaYibjfbcSbnCbcSbcSbcSaRebcSbcSbmvbmvbmwbmwbmxbeMbeMbmybmzbeMbeMbeMbmAbmBbmCaVbbgxbhNbeXbeXbeXbeXbhPbmDaVbbmEbmFbmFbmGbmFbmHbbPbbPbbPbbPbmIbbPbbPbbPbmJblobfgbfgbfgbfgbfgbfgbfgblnbloblpbgHbatbfjbfjbfkbfjbatddEbaAbmLbmMbmNbaAbBQbtmbmKbutbBQbtmbmKbutbBQbtmbmKbutbBQbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbrcbrbbrebrdbrfbrfbrgbrfbrfbrfbrgbluaInaInaKzbrVbcjbmQbimbmRblxblxblxblybmRbimbgNbmSbmTbjWblCbmUbmVbmWbmXblCbmYbmZbnabcobnbbncbndbnebcobejbnfbngbngbnhbngbngbngbngbnibnjbnjbnjbnkbnjbnlbnmbnnbnobnpbnqbnqbnqbnqbnqbnqbnrbnsbnrbmgbmgbntbnubnvbnwbnxbnybntbnzbmgbnAbnBbnAbnAbnAbnAbnAbnAbnAbmtaYiaYiaMebnEbnDbcSbnGbcSbnFbcSbnIbnHbnJbmwbpjaUTbnKbnLaUTaUTczObnNddybnNaUTaUTaVbbnObnPbnQbnQbnQbnQbnPbnRaVbbnSbmFbmFbmGbnTaRDbnUbnVbnWbnXbnYbnZboabobbocaQbbodaRSboebfgbfgboeaRSbofaQbbogbgHbatbgIbgIbgJbgIbatddDbgKblrblrblrbaAbGVbtmbmKbutbGVbtmbmKbutbGVbtmbmKbutbGVbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbrcbltbltblubltbltbltblvbltbltbtnaabaInboibdFbokbgNbjObjObjObimbolbombonboobgNbopboqbjWblCborblCbosbotblCboubovbowbcobnbbncbndbiCbcobejbnfbngboxboybozboAboBbngboCboDboEboFbnmbnmbnmbnmboGboHboIbnqboJboKboLboMboNboOboPboQbmgboRbnvboSboTboUboTboSbnvboVbmgboWboXboYboZbpabpbbpcbpdbnAbpebpfbpfbpgaMeaMeaMeaMebphbjfbphbpiaMeaURaMeaMeaUTaUTaUTaUTbplbpkbpkbpkbpkbpmbpJaVbbakbpnbakbpobpobakbpnbakaVbbnSbmFbmFbppbnTaRDaRDaRDaRDaRDbjvaRDaRDaRDaRDaQbbpqaQcaQcaQcaQcaQcaQcaQbaQbbprbpsbatbatbatbavbatbatddAbaAbaAbaAbaAbgKbqUddFbmKbmKbmKbmKbmKbmKbmKbmKbmKddGbqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaLyaCuaKzaKzaKzaDEaDEaDEaDEaDEaDEbtobpubgNbgNbgNbgNbgNbgNbpvbgNbgNbgNbejbejbpxblCbpybpzbosbpAblCbpBbpCbpBbcobnbbncbndbecbcobejbnfbngbpDbpEbpFboAbpFbngboCbpGbpHbpIbqtbpKbpLbnmbpMbpNboIbpObpPbpQbpRbpSbpSbpRbpTbpUbmgbpVbnvbnvbpWbpXboTboSbnvbpYbmkbpZbqabqbbqcbqdbqebqbbqfbnAbqgbqhbqibqjbqkbqlbqmbqnbqnbqnbqnbqnbqnbqobqpbqqbqrbqnbqsbqnbqnbqnbqnbqnbqnbqnbqndcZbqubqvbqvbqvbqvbqvbqvbqwbqlbqxbqybqybqzbqAbqBbqAbqCbqAbqDbqEbqFbqAbqGbqHbqIbqJbqKbqKbqKbqKbqKbqKbqKbqLbqMbqNbqNbqNbqNbqObqNbqPbKnddHbPfddIbiibPfdlbbmKbmKbmKbmKddKbmKddKbmKbmKbmKddGbdBbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaLyaCuaKzaKzaKzaDEaDEaDEaDEaDEaDEbtobpubgNbgNbgNbgNbgNbgNbpvbgNbgNbgNbejbejbpxblCbpybpzbosbpAblCdlEbpCbpBbcobnbbncbndbecbcobejbnfbngbpDbpEbpFboAbpFbngboCbpGbpHbpIbqtbpKbpLbnmbpMbpNboIbpObpPbpQbpRbpSbpSbpRbpTbpUbmgbpVbnvbnvbpWbpXboTboSbnvbpYbmkbpZbqabqbbqcbqdbqebqbbqfbnAbqgbqhbqibqjbqkbqlbqmbqnbqnbqnbqnbqnbqnbqobqpbqqbqrbqnbqsbqnbqnbqnbqnbqnbqnbqnbqndcZbqubqvbqvbqvbqvbqvbqvbqwbqlbqxbqybqybqzbqAbqBbqAbqCbqAbqDbqEbqFbqAbqGbqHbqIbqJbqKbqKbqKbqKbqKbqKbqKbqLbqMbqNbqNbqNbqNbqObqNbqPbKnddHbPfddIbiibPfdlbbmKbmKbmKbmKddKbmKddKbmKbmKbmKddGbdBbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbtpbtqbtqbtqbtqbwpbwpbtqbtqbxZbikaabaInaLAaJtbzPbzObzRbzQbzQbzQbzQbzSbzUbzTbcsbdVbBFbrhblCblCblCbribotblCbcobcobcobcobnbbrjbrkbrlbcobrmbrnbngbrobrpboAbpFbrqbngboCbrrbpHbpIbpIbrsbrtbnmbrubpNboIbpObrvbrwbrxbrybrzbrAbpTbrBbmgbrCbpWbnvbrDbrEbrDbnvbpWbrFbnzbrGbqbbqbbqcbrHbqebqbbrIbnAbrJbqibqibqjbqkbqlbqnbqnbqnbqnbqnbqnbqnbrKbqnbqnbqnbqnbqnbqnbrLbrMbrMbrMbrMbrMbrMbrMbrMbrMbrMbrMbrMbrMbrMbrNbrObrPbqKbqKbrQbmFbmFbmFbmFbmFbmGbmFbmFbmFbmFbmFbmFbmFbmFbmFbmFbmFbmFbrRbmFbrSbrTbatbatbatbatbatbatbatddLbaAbgKbaAbaAbaAbqUddMddOddNbdBddPbdBddPbdBddQddMddObqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbBGbDCbBHdjhbDDdjidjidjkdjjbtqbxZbjNaInaInaKBbrWbrXbrYbrXbrXbrXbrXbrZbsabsbbcsbcsbscbsdblCbmUbsebsfbpAblCbsgbshbsgbcobcobcobcobsibcobsjbskbngbslbsmbpFbsnbsobngboCbnmbspbpIbpIbpIbsqbnmbsrbpNboIbpObssbrwbrxbstbsubrAbpTbsvbmgbswbsxbnvbsybszbsAboSbsBbsCbsDbsEbsFbsGbsHbsIbsJbqbbsKbnAbsLbsMbqibqjbqkbqlbqnbsNbqnbqnbqnbqnbsObsPbsPbsPbsPbsQbqnbqnbqnbqnbsRbqnbsNbsSbqnbsTbsUbsVbqnbsWbsXbsXbsYbsZbtabtbbmFbmFbmFbmFbmFbmFbmFbtcbtdbmFbmFbmFbmFbmFbmFbmFbmFbmFbmFbmFbtebtfbtfbtgddSddRddUddTddTddTddTddVddWbaAaabbikbikaabbqUddXddZddYdeabqUbikbqUdecdebdecdecbqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbBGbDCdjldjidjidjidjidjidjidjideHdjnaGddjnaJrbtrbrXbtsbttbtubtvbtwbrZbtxbtybtzbtzbtAbtBblCblCblCbosbtCborbcsbcsbcsbcsbtDbejbejbskbejbsjbskbngbtEbtFbtGbtHboAbngbtIbnmbtJbpIbpIbpIbtKbtLbtMbpNbtNbnqbtObtPbpRbpRbpRbpRbpTbtQbmgbtRbtSbmgbmgbmgbmgbmgbmgbmgbnzbnAbtTbtUbtVbtWbtXbtYbtZbnAbvubuabuabucbucbucbucbucbucbucbudbudbuebufbugbugbufbuebudbudbuhbuhbuhbuhbuhbuhbuibuibujbuibuibuibuibuibukbulbumbunbmFbmFbuobuobupbupbupbupbupbuqbtfbtfbtebtfbmFbtfbtfbtfbtfburbusbusbusbusdedbuubuubuubuubuubuubuubuubuubikbikbikbikbdBddYddYddYdeebqUbikbqUdefdebdebdegbqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik From 7ea739fd824abdadba943a8e07ccfea4a754d5e7 Mon Sep 17 00:00:00 2001 From: Fox-McCloud Date: Wed, 30 Dec 2015 14:12:18 -0500 Subject: [PATCH 19/19] Fixes Guardians not being a selectable role --- code/__DEFINES/role_preferences.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index 0c5a2d820c2..86495432d0e 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -65,4 +65,5 @@ var/global/list/special_roles = list( ROLE_DEMON, ROLE_SENTIENT, ROLE_POSIBRAIN, + ROLE_GUARDIAN, )