From 762a3e3c0201b419f0810e6bc476bac7470243e0 Mon Sep 17 00:00:00 2001 From: Poojawa Date: Sun, 16 Jun 2019 18:45:26 -0500 Subject: [PATCH 001/222] Ports revised job backend from TG --- code/__DEFINES/jobs.dm | 38 ++ code/__DEFINES/preferences.dm | 7 +- code/__HELPERS/cmp.dm | 3 + code/controllers/subsystem/job.dm | 174 ++++--- code/datums/outfit.dm | 8 + code/game/gamemodes/game_mode.dm | 2 +- code/modules/client/preferences.dm | 195 ++------ code/modules/client/preferences_savefile.dm | 90 ++-- code/modules/jobs/job_exp.dm | 2 + .../jobs/job_types/{job.dm => _job.dm} | 456 +++++++++--------- .../jobs/job_types/{silicon.dm => ai.dm} | 159 +++--- code/modules/jobs/job_types/assistant.dm | 2 +- .../jobs/job_types/atmospheric_technician.dm | 44 ++ code/modules/jobs/job_types/bartender.dm | 30 ++ code/modules/jobs/job_types/botanist.dm | 32 ++ code/modules/jobs/job_types/captain.dm | 60 +-- code/modules/jobs/job_types/cargo_service.dm | 290 ----------- .../jobs/job_types/cargo_technician.dm | 27 ++ .../{civilian_chaplain.dm => chaplain.dm} | 215 +++++---- code/modules/jobs/job_types/chemist.dm | 36 ++ code/modules/jobs/job_types/chief_engineer.dm | 63 +++ .../jobs/job_types/chief_medical_officer.dm | 58 +++ code/modules/jobs/job_types/civilian.dm | 202 -------- code/modules/jobs/job_types/clown.dm | 57 +++ code/modules/jobs/job_types/cook.dm | 52 ++ code/modules/jobs/job_types/curator.dm | 42 ++ code/modules/jobs/job_types/cyborg.dm | 27 ++ code/modules/jobs/job_types/detective.dm | 56 +++ code/modules/jobs/job_types/engineering.dm | 167 ------- code/modules/jobs/job_types/geneticist.dm | 35 ++ .../jobs/job_types/head_of_personnel.dm | 49 ++ .../jobs/job_types/head_of_security.dm | 67 +++ code/modules/jobs/job_types/janitor.dm | 27 ++ code/modules/jobs/job_types/lawyer.dm | 47 ++ code/modules/jobs/job_types/medical.dm | 204 -------- code/modules/jobs/job_types/medical_doctor.dm | 35 ++ code/modules/jobs/job_types/mime.dm | 49 ++ code/modules/jobs/job_types/quartermaster.dm | 32 ++ .../jobs/job_types/research_director.dm | 60 +++ code/modules/jobs/job_types/roboticist.dm | 34 ++ code/modules/jobs/job_types/science.dm | 131 ----- code/modules/jobs/job_types/scientist.dm | 33 ++ code/modules/jobs/job_types/security.dm | 334 ------------- .../jobs/job_types/security_officer.dm | 158 ++++++ code/modules/jobs/job_types/shaft_miner.dm | 70 +++ .../jobs/job_types/station_engineer.dm | 54 +++ code/modules/jobs/job_types/virologist.dm | 35 ++ code/modules/jobs/job_types/warden.dm | 55 +++ .../modules/mob/dead/new_player/new_player.dm | 137 +++--- .../mob/dead/new_player/preferences_setup.dm | 55 +-- tgstation.dme | 40 +- 51 files changed, 2201 insertions(+), 2134 deletions(-) rename code/modules/jobs/job_types/{job.dm => _job.dm} (85%) rename code/modules/jobs/job_types/{silicon.dm => ai.dm} (71%) create mode 100644 code/modules/jobs/job_types/atmospheric_technician.dm create mode 100644 code/modules/jobs/job_types/bartender.dm create mode 100644 code/modules/jobs/job_types/botanist.dm delete mode 100644 code/modules/jobs/job_types/cargo_service.dm create mode 100644 code/modules/jobs/job_types/cargo_technician.dm rename code/modules/jobs/job_types/{civilian_chaplain.dm => chaplain.dm} (67%) create mode 100644 code/modules/jobs/job_types/chemist.dm create mode 100644 code/modules/jobs/job_types/chief_engineer.dm create mode 100644 code/modules/jobs/job_types/chief_medical_officer.dm delete mode 100644 code/modules/jobs/job_types/civilian.dm create mode 100644 code/modules/jobs/job_types/clown.dm create mode 100644 code/modules/jobs/job_types/cook.dm create mode 100644 code/modules/jobs/job_types/curator.dm create mode 100644 code/modules/jobs/job_types/cyborg.dm create mode 100644 code/modules/jobs/job_types/detective.dm delete mode 100644 code/modules/jobs/job_types/engineering.dm create mode 100644 code/modules/jobs/job_types/geneticist.dm create mode 100644 code/modules/jobs/job_types/head_of_personnel.dm create mode 100644 code/modules/jobs/job_types/head_of_security.dm create mode 100644 code/modules/jobs/job_types/janitor.dm create mode 100644 code/modules/jobs/job_types/lawyer.dm delete mode 100644 code/modules/jobs/job_types/medical.dm create mode 100644 code/modules/jobs/job_types/medical_doctor.dm create mode 100644 code/modules/jobs/job_types/mime.dm create mode 100644 code/modules/jobs/job_types/quartermaster.dm create mode 100644 code/modules/jobs/job_types/research_director.dm create mode 100644 code/modules/jobs/job_types/roboticist.dm delete mode 100644 code/modules/jobs/job_types/science.dm create mode 100644 code/modules/jobs/job_types/scientist.dm delete mode 100644 code/modules/jobs/job_types/security.dm create mode 100644 code/modules/jobs/job_types/security_officer.dm create mode 100644 code/modules/jobs/job_types/shaft_miner.dm create mode 100644 code/modules/jobs/job_types/station_engineer.dm create mode 100644 code/modules/jobs/job_types/virologist.dm create mode 100644 code/modules/jobs/job_types/warden.dm diff --git a/code/__DEFINES/jobs.dm b/code/__DEFINES/jobs.dm index dc4080a789..e6b1d77f8a 100644 --- a/code/__DEFINES/jobs.dm +++ b/code/__DEFINES/jobs.dm @@ -48,3 +48,41 @@ #define JOB_UNAVAILABLE_PLAYTIME 3 #define JOB_UNAVAILABLE_ACCOUNTAGE 4 #define JOB_UNAVAILABLE_SLOTFULL 5 + +#define DEFAULT_RELIGION "Christianity" +#define DEFAULT_DEITY "Space Jesus" + +#define JOB_DISPLAY_ORDER_DEFAULT 0 + +#define JOB_DISPLAY_ORDER_ASSISTANT 1 +#define JOB_DISPLAY_ORDER_CAPTAIN 2 +#define JOB_DISPLAY_ORDER_HEAD_OF_PERSONNEL 3 +#define JOB_DISPLAY_ORDER_QUARTERMASTER 4 +#define JOB_DISPLAY_ORDER_CARGO_TECHNICIAN 5 +#define JOB_DISPLAY_ORDER_SHAFT_MINER 6 +#define JOB_DISPLAY_ORDER_BARTENDER 7 +#define JOB_DISPLAY_ORDER_COOK 8 +#define JOB_DISPLAY_ORDER_BOTANIST 9 +#define JOB_DISPLAY_ORDER_JANITOR 10 +#define JOB_DISPLAY_ORDER_CLOWN 11 +#define JOB_DISPLAY_ORDER_MIME 12 +#define JOB_DISPLAY_ORDER_CURATOR 13 +#define JOB_DISPLAY_ORDER_LAWYER 14 +#define JOB_DISPLAY_ORDER_CHAPLAIN 15 +#define JOB_DISPLAY_ORDER_CHIEF_ENGINEER 16 +#define JOB_DISPLAY_ORDER_STATION_ENGINEER 17 +#define JOB_DISPLAY_ORDER_ATMOSPHERIC_TECHNICIAN 18 +#define JOB_DISPLAY_ORDER_CHIEF_MEDICAL_OFFICER 19 +#define JOB_DISPLAY_ORDER_MEDICAL_DOCTOR 20 +#define JOB_DISPLAY_ORDER_CHEMIST 21 +#define JOB_DISPLAY_ORDER_GENETICIST 22 +#define JOB_DISPLAY_ORDER_VIROLOGIST 23 +#define JOB_DISPLAY_ORDER_RESEARCH_DIRECTOR 24 +#define JOB_DISPLAY_ORDER_SCIENTIST 25 +#define JOB_DISPLAY_ORDER_ROBOTICIST 26 +#define JOB_DISPLAY_ORDER_HEAD_OF_SECURITY 27 +#define JOB_DISPLAY_ORDER_WARDEN 28 +#define JOB_DISPLAY_ORDER_DETECTIVE 29 +#define JOB_DISPLAY_ORDER_SECURITY_OFFICER 30 +#define JOB_DISPLAY_ORDER_AI 31 +#define JOB_DISPLAY_ORDER_CYBORG 32 diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm index 02f151dcd9..0992b2e586 100644 --- a/code/__DEFINES/preferences.dm +++ b/code/__DEFINES/preferences.dm @@ -69,4 +69,9 @@ //Flags in the players table in the db #define DB_FLAG_EXEMPT 1 -#define DEFAULT_CYBORG_NAME "Default Cyborg Name" \ No newline at end of file +#define DEFAULT_CYBORG_NAME "Default Cyborg Name" + +//Job preferences levels +#define JP_LOW 1 +#define JP_MEDIUM 2 +#define JP_HIGH 3 diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm index e09ebcb10c..37f36a7e0d 100644 --- a/code/__HELPERS/cmp.dm +++ b/code/__HELPERS/cmp.dm @@ -81,3 +81,6 @@ GLOBAL_VAR_INIT(cmp_field, "name") /proc/cmp_advdisease_resistance_asc(datum/disease/advance/A, datum/disease/advance/B) return A.totalResistance() - B.totalResistance() + +/proc/cmp_job_display_asc(datum/job/A, datum/job/B) + return A.display_order - B.display_order diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm index 5e960e0f96..5983fa3ae5 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -116,7 +116,7 @@ SUBSYSTEM_DEF(job) if(player.mind && job.title in player.mind.restricted_roles) JobDebug("FOC incompatible with antagonist role, Player: [player]") continue - if(player.client.prefs.GetJobDepartment(job, level) & job.flag) + if(player.client.prefs.job_preferences[job.title] == level) JobDebug("FOC pass, Player: [player], Level:[level]") candidates += player return candidates @@ -228,7 +228,7 @@ SUBSYSTEM_DEF(job) * fills var "assigned_role" for all ready players. * This proc must not have any side effect besides of modifying "assigned_role". **/ -/datum/controller/subsystem/job/proc/DivideOccupations() +/datum/controller/subsystem/job/proc/DivideOccupations(list/required_jobs) //Setup new player list and get the jobs list JobDebug("Running DO") @@ -241,14 +241,14 @@ SUBSYSTEM_DEF(job) //Get the players who are ready for(var/mob/dead/new_player/player in GLOB.player_list) - if(player.ready == PLAYER_READY_TO_PLAY && player.mind && !player.mind.assigned_role) + if(player.ready == PLAYER_READY_TO_PLAY && player.check_preferences() && player.mind && !player.mind.assigned_role) unassigned += player initial_players_to_assign = unassigned.len JobDebug("DO, Len: [unassigned.len]") if(unassigned.len == 0) - return 0 + return validate_required_jobs(required_jobs) //Scale number of open security officer slots to population setup_officer_positions() @@ -269,7 +269,7 @@ SUBSYSTEM_DEF(job) //People who wants to be the overflow role, sure, go on. JobDebug("DO, Running Overflow Check 1") var/datum/job/overflow = GetJob(SSjob.overflow_role) - var/list/overflow_candidates = FindOccupationCandidates(overflow, 3) + var/list/overflow_candidates = FindOccupationCandidates(overflow, JP_LOW) JobDebug("AC1, Candidates: [overflow_candidates.len]") for(var/mob/dead/new_player/player in overflow_candidates) JobDebug("AC1 pass, Player: [player]") @@ -297,7 +297,8 @@ SUBSYSTEM_DEF(job) // Loop through all levels from high to low var/list/shuffledoccupations = shuffle(occupations) - for(var/level = 1 to 3) + var/list/levels = list(JP_HIGH,JP_MEDIUM,JP_LOW) + for(var/level in levels) //Check the head jobs first each level CheckHeadPositions(level) @@ -332,7 +333,7 @@ SUBSYSTEM_DEF(job) continue // If the player wants that job on this level, then try give it to him. - if(player.client.prefs.GetJobDepartment(job, level) & job.flag) + if(player.client.prefs.job_preferences[job.title] == level) // If the job isn't filled if((job.current_positions < job.spawn_positions) || job.spawn_positions == -1) JobDebug("DO pass, Player: [player], Level:[level], Job:[job.title]") @@ -351,9 +352,28 @@ SUBSYSTEM_DEF(job) //Mop up people who can't leave. for(var/mob/dead/new_player/player in unassigned) //Players that wanted to back out but couldn't because they're antags (can you feel the edge case?) if(!GiveRandomJob(player)) - AssignRole(player, SSjob.overflow_role) //If everything is already filled, make them an assistant + if(!AssignRole(player, SSjob.overflow_role)) //If everything is already filled, make them an assistant + return FALSE //Living on the edge, the forced antagonist couldn't be assigned to overflow role (bans, client age) - just reroll - return 1 + return validate_required_jobs(required_jobs) + +/datum/controller/subsystem/job/proc/validate_required_jobs(list/required_jobs) + if(!required_jobs.len) + return TRUE + for(var/required_group in required_jobs) + var/group_ok = TRUE + for(var/rank in required_group) + var/datum/job/J = GetJob(rank) + if(!J) + SSticker.mode.setup_error = "Invalid job [rank] in gamemode required jobs." + return FALSE + if(J.current_positions < required_group[rank]) + group_ok = FALSE + break + if(group_ok) + return TRUE + SSticker.mode.setup_error = "Required jobs not present." + return FALSE //We couldn't find a job from prefs for this guy. /datum/controller/subsystem/job/proc/HandleUnassigned(mob/dead/new_player/player) @@ -406,7 +426,7 @@ SUBSYSTEM_DEF(job) if(length(GLOB.jobspawn_overrides[rank])) S = pick(GLOB.jobspawn_overrides[rank]) if(S) - SendToAtom(H, S, buckle = FALSE) + S.JoinPlayerHere(H, FALSE) if(!S) //if there isn't a spawnpoint send them to latejoin, if there's no latejoin go yell at your mapper log_world("Couldn't find a round start spawn point for [rank]") SendToLateJoin(H) @@ -418,7 +438,7 @@ SUBSYSTEM_DEF(job) if(job) if(!job.dresscodecompliant)// CIT CHANGE - dress code compliance equip_loadout(N, H) // CIT CHANGE - allows players to spawn with loadout items - var/new_mob = job.equip(H, null, null, joined_late) + var/new_mob = job.equip(H, null, null, joined_late , null, M.client) if(ismob(new_mob)) H = new_mob if(!joined_late) @@ -428,16 +448,22 @@ SUBSYSTEM_DEF(job) SSpersistence.antag_rep_change[M.client.ckey] += job.GetAntagRep() +/* if(M.client.holder) + if(CONFIG_GET(flag/auto_deadmin_players) || (M.client.prefs?.toggles & DEADMIN_ALWAYS)) + M.client.holder.auto_deadmin() + else + handle_auto_deadmin_roles(M.client, rank) */ + to_chat(M, "You are the [rank].") if(job) to_chat(M, "As the [rank] you answer directly to [job.supervisors]. Special circumstances may change this.") - to_chat(M, "To speak on your departments radio, use the :h button. To see others, look closely at your headset.") + job.radio_help_message(M) if(job.req_admin_notify) - to_chat(M, "You are playing a job that is important for Game Progression. If you have to disconnect, please notify the admins via adminhelp.") + to_chat(M, "You are playing a job that is important for Game Progression. If you have to disconnect immediately, please notify the admins via adminhelp. Otherwise put your locker gear back into the locker and cryo out.") if(job.custom_spawn_text) to_chat(M, "[job.custom_spawn_text]") if(CONFIG_GET(number/minimal_access_threshold)) - to_chat(M, "As this station was initially staffed with a [CONFIG_GET(flag/jobs_have_minimal_access) ? "full crew, only your job's necessities" : "skeleton crew, additional access may"] have been added to your ID card.") + to_chat(M, "As this station was initially staffed with a [CONFIG_GET(flag/jobs_have_minimal_access) ? "full crew, only your job's necessities" : "skeleton crew, additional access may"] have been added to your ID card.") if(job && H) if(job.dresscodecompliant)// CIT CHANGE - dress code compliance @@ -446,12 +472,24 @@ SUBSYSTEM_DEF(job) equip_loadout(N, H, TRUE)//CIT CHANGE - makes players spawn with in-backpack loadout items properly. A little hacky but it works return H - +/* +/datum/controller/subsystem/job/proc/handle_auto_deadmin_roles(client/C, rank) + if(!C?.holder) + return TRUE + var/datum/job/job = GetJob(rank) + if(!job) + return + if((job.auto_deadmin_role_flags & DEADMIN_POSITION_HEAD) && (CONFIG_GET(flag/auto_deadmin_heads) || (C.prefs?.toggles & DEADMIN_POSITION_HEAD))) + return C.holder.auto_deadmin() + else if((job.auto_deadmin_role_flags & DEADMIN_POSITION_SECURITY) && (CONFIG_GET(flag/auto_deadmin_security) || (C.prefs?.toggles & DEADMIN_POSITION_SECURITY))) + return C.holder.auto_deadmin() + else if((job.auto_deadmin_role_flags & DEADMIN_POSITION_SILICON) && (CONFIG_GET(flag/auto_deadmin_silicons) || (C.prefs?.toggles & DEADMIN_POSITION_SILICON))) //in the event there's ever psuedo-silicon roles added, ie synths. + return C.holder.auto_deadmin()*/ /datum/controller/subsystem/job/proc/setup_officer_positions() var/datum/job/J = SSjob.GetJob("Security Officer") if(!J) - throw EXCEPTION("setup_officer_positions(): Security officer job is missing") + CRASH("setup_officer_positions(): Security officer job is missing") var/ssc = CONFIG_GET(number/security_scaling_coeff) if(ssc > 0) @@ -502,13 +540,15 @@ SUBSYSTEM_DEF(job) if(job.required_playtime_remaining(player.client)) young++ continue - if(player.client.prefs.GetJobDepartment(job, 1) & job.flag) - high++ - else if(player.client.prefs.GetJobDepartment(job, 2) & job.flag) - medium++ - else if(player.client.prefs.GetJobDepartment(job, 3) & job.flag) - low++ - else never++ //not selected + switch(player.client.prefs.job_preferences[job.title]) + if(JP_HIGH) + high++ + if(JP_MEDIUM) + medium++ + if(JP_LOW) + low++ + else + never++ SSblackbox.record_feedback("nested tally", "job_preferences", high, list("[job.title]", "high")) SSblackbox.record_feedback("nested tally", "job_preferences", medium, list("[job.title]", "medium")) SSblackbox.record_feedback("nested tally", "job_preferences", low, list("[job.title]", "low")) @@ -551,51 +591,61 @@ SUBSYSTEM_DEF(job) newjob.spawn_positions = J.spawn_positions newjob.current_positions = J.current_positions -/datum/controller/subsystem/job/proc/SendToAtom(mob/M, atom/A, buckle) - if(buckle && isliving(M) && istype(A, /obj/structure/chair)) - var/obj/structure/chair/C = A - if(C.buckle_mob(M, FALSE, FALSE)) - return - M.forceMove(get_turf(A)) +/atom/proc/JoinPlayerHere(mob/M, buckle) + // By default, just place the mob on the same turf as the marker or whatever. + M.forceMove(get_turf(src)) + +/obj/structure/chair/JoinPlayerHere(mob/M, buckle) + // Placing a mob in a chair will attempt to buckle it, or else fall back to default. + if (buckle && isliving(M) && buckle_mob(M, FALSE, FALSE)) + return + ..() /datum/controller/subsystem/job/proc/SendToLateJoin(mob/M, buckle = TRUE) + var/atom/destination if(M.mind && M.mind.assigned_role && length(GLOB.jobspawn_overrides[M.mind.assigned_role])) //We're doing something special today. - SendToAtom(M,pick(GLOB.jobspawn_overrides[M.mind.assigned_role]),FALSE) + destination = pick(GLOB.jobspawn_overrides[M.mind.assigned_role]) + destination.JoinPlayerHere(M, FALSE) return if(latejoin_trackers.len) - SendToAtom(M, pick(latejoin_trackers), buckle) - else - //bad mojo - var/area/shuttle/arrival/A = GLOB.areas_by_type[/area/shuttle/arrival] - if(A) - //first check if we can find a chair - var/obj/structure/chair/C = locate() in A - if(C) - SendToAtom(M, C, buckle) - return - else //last hurrah - var/list/avail = list() - for(var/turf/T in A) - if(!is_blocked_turf(T, TRUE)) - avail += T - if(avail.len) - SendToAtom(M, pick(avail), FALSE) - return + destination = pick(latejoin_trackers) + destination.JoinPlayerHere(M, buckle) + return - //pick an open spot on arrivals and dump em - var/list/arrivals_turfs = shuffle(get_area_turfs(/area/shuttle/arrival)) - if(arrivals_turfs.len) - for(var/turf/T in arrivals_turfs) - if(!is_blocked_turf(T, TRUE)) - SendToAtom(M, T, FALSE) - return - //last chance, pick ANY spot on arrivals and dump em - SendToAtom(M, arrivals_turfs[1], FALSE) - else - var/msg = "Unable to send mob [M] to late join!" - message_admins(msg) - CRASH(msg) + //bad mojo + var/area/shuttle/arrival/A = GLOB.areas_by_type[/area/shuttle/arrival] + if(A) + //first check if we can find a chair + var/obj/structure/chair/C = locate() in A + if(C) + C.JoinPlayerHere(M, buckle) + return + + //last hurrah + var/list/avail = list() + for(var/turf/T in A) + if(!is_blocked_turf(T, TRUE)) + avail += T + if(avail.len) + destination = pick(avail) + destination.JoinPlayerHere(M, FALSE) + return + + //pick an open spot on arrivals and dump em + var/list/arrivals_turfs = shuffle(get_area_turfs(/area/shuttle/arrival)) + if(arrivals_turfs.len) + for(var/turf/T in arrivals_turfs) + if(!is_blocked_turf(T, TRUE)) + T.JoinPlayerHere(M, FALSE) + return + //last chance, pick ANY spot on arrivals and dump em + destination = arrivals_turfs[1] + destination.JoinPlayerHere(M, FALSE) + else + var/msg = "Unable to send mob [M] to late join!" + message_admins(msg) + CRASH(msg) /////////////////////////////////// @@ -637,4 +687,4 @@ SUBSYSTEM_DEF(job) . |= player.mind /datum/controller/subsystem/job/proc/JobDebug(message) - log_job_debug(message) \ No newline at end of file + log_job_debug(message) diff --git a/code/datums/outfit.dm b/code/datums/outfit.dm index 1f5c28d3c2..68165af956 100755 --- a/code/datums/outfit.dm +++ b/code/datums/outfit.dm @@ -21,6 +21,7 @@ var/l_hand = null var/internals_slot = null //ID of slot containing a gas tank var/list/backpack_contents = null // In the list(path=count,otherpath=count) format + var/box // Internals box. Will be inserted at the start of backpack_contents var/list/implants = null var/accessory = null @@ -83,6 +84,13 @@ H.equip_to_slot_or_del(new l_pocket(H),SLOT_L_STORE) if(r_pocket) H.equip_to_slot_or_del(new r_pocket(H),SLOT_R_STORE) + + if(box) + if(!backpack_contents) + backpack_contents = list() + backpack_contents.Insert(1, box) + backpack_contents[box] = 1 + if(backpack_contents) for(var/path in backpack_contents) var/number = backpack_contents[path] diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index d16cbebb2a..28a0e21061 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -355,7 +355,7 @@ // Ultimate randomizing code right here for(var/mob/dead/new_player/player in GLOB.player_list) - if(player.client && player.ready == PLAYER_READY_TO_PLAY) + if(player.client && player.ready == PLAYER_READY_TO_PLAY && player.check_preferences()) players += player // Shuffling, the players list is now ping-independent!!! diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index a0eea344a3..0984523ace 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -165,18 +165,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/list/all_quirks = list() var/list/character_quirks = list() - //Jobs, uses bitflags - var/job_civilian_high = 0 - var/job_civilian_med = 0 - var/job_civilian_low = 0 - - var/job_medsci_high = 0 - var/job_medsci_med = 0 - var/job_medsci_low = 0 - - var/job_engsec_high = 0 - var/job_engsec_med = 0 - var/job_engsec_low = 0 + //Job preferences 2.0 - indexed by job title , no key or value implies never + var/list/job_preferences = list() // Want randomjob if preferences already filled - Donkie var/joblessrole = BERANDOMJOB //defaults to 1 for fewer assistants @@ -975,9 +965,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) //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 - var/datum/job/overflow = SSjob.GetJob(SSjob.overflow_role) - - for(var/datum/job/job in SSjob.occupations) + for(var/datum/job/job in sortList(SSjob.occupations, /proc/cmp_job_display_asc)) index += 1 if((index >= limit) || (job.title in splitJobs)) @@ -994,7 +982,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/rank = job.title lastJob = job if(jobban_isbanned(user, rank)) - HTML += "[rank] BANNED" + HTML += "[rank] BANNED" continue var/required_playtime_remaining = job.required_playtime_remaining(user.client) if(required_playtime_remaining) @@ -1004,7 +992,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/available_in_days = job.available_in_days(user.client) HTML += "[rank] \[IN [(available_in_days)] DAYS\]" continue - if((job_civilian_low & overflow.flag) && (rank != SSjob.overflow_role) && !jobban_isbanned(user, SSjob.overflow_role)) + if((job_preferences[SSjob.overflow_role] == JP_LOW) && (rank != SSjob.overflow_role) && !jobban_isbanned(user, SSjob.overflow_role)) HTML += "[rank]" continue if((rank in GLOB.command_positions) || (rank == "AI"))//Bold head jobs @@ -1019,32 +1007,32 @@ GLOBAL_LIST_EMPTY(preferences_datums) 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 - + switch(job_preferences[job.title]) + if(JP_HIGH) + prefLevelLabel = "High" + prefLevelColor = "slateblue" + prefUpperLevel = 4 + prefLowerLevel = 2 + if(JP_MEDIUM) + prefLevelLabel = "Medium" + prefLevelColor = "green" + prefUpperLevel = 1 + prefLowerLevel = 3 + if(JP_LOW) + prefLevelLabel = "Low" + prefLevelColor = "orange" + prefUpperLevel = 2 + prefLowerLevel = 4 + else + prefLevelLabel = "NEVER" + prefLevelColor = "red" + prefUpperLevel = 3 + prefLowerLevel = 1 HTML += "" if(rank == SSjob.overflow_role)//Overflow is special - if(job_civilian_low & overflow.flag) + if(job_preferences[SSjob.overflow_role] == JP_LOW) HTML += "Yes" else HTML += "No" @@ -1075,61 +1063,17 @@ GLOBAL_LIST_EMPTY(preferences_datums) /datum/preferences/proc/SetJobPreferenceLevel(datum/job/job, level) if (!job) - return 0 + return FALSE - if (level == 1) // to high - // remove any other job(s) set to high - job_civilian_med |= job_civilian_high - job_engsec_med |= job_engsec_high - job_medsci_med |= job_medsci_high - job_civilian_high = 0 - job_engsec_high = 0 - job_medsci_high = 0 + if (level == JP_HIGH) // to high + //Set all other high to medium + for(var/j in job_preferences) + if(job_preferences[j] == JP_HIGH) + job_preferences[j] = JP_MEDIUM + //technically break here - if (job.department_flag == CIVILIAN) - job_civilian_low &= ~job.flag - job_civilian_med &= ~job.flag - job_civilian_high &= ~job.flag - - switch(level) - if (1) - job_civilian_high |= job.flag - if (2) - job_civilian_med |= job.flag - if (3) - job_civilian_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 - - return 0 + job_preferences[job.title] = level + return TRUE /datum/preferences/proc/UpdateJobPreference(mob/user, role, desiredLvl) if(!SSjob || SSjob.occupations.len <= 0) @@ -1146,64 +1090,29 @@ GLOBAL_LIST_EMPTY(preferences_datums) ShowChoices(user) return - if(role == SSjob.overflow_role) - if(job_civilian_low & job.flag) - job_civilian_low &= ~job.flag - else - job_civilian_low |= job.flag - SetChoices(user) - return 1 + var/jpval = null + switch(desiredLvl) + if(3) + jpval = JP_LOW + if(2) + jpval = JP_MEDIUM + if(1) + jpval = JP_HIGH - SetJobPreferenceLevel(job, desiredLvl) + if(role == SSjob.overflow_role) + if(job_preferences[job.title] == JP_LOW) + jpval = null + else + jpval = JP_LOW + + SetJobPreferenceLevel(job, jpval) SetChoices(user) return 1 /datum/preferences/proc/ResetJobs() - - job_civilian_high = 0 - job_civilian_med = 0 - job_civilian_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 - - -/datum/preferences/proc/GetJobDepartment(datum/job/job, level) - if(!job || !level) - return 0 - switch(job.department_flag) - if(CIVILIAN) - switch(level) - if(1) - return job_civilian_high - if(2) - return job_civilian_med - if(3) - return job_civilian_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 - return 0 + job_preferences = list() /datum/preferences/proc/SetQuirks(mob/user) if(!SSquirks) diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 7401a54efc..d7ec8eaea6 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -5,7 +5,7 @@ // You do not need to raise this if you are adding new values that have sane defaults. // Only raise this value when changing the meaning/format/name/layout of an existing value // where you would want the updater procs below to run -#define SAVEFILE_VERSION_MAX 20 +#define SAVEFILE_VERSION_MAX 21 /* SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn @@ -49,6 +49,59 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car pda_style = "mono" if(current_version < 20) pda_color = "#808000" + if(current_version < 21) + job_preferences = list() //It loaded null from nonexistant savefile field. + var/job_civilian_high = 0 + var/job_civilian_med = 0 + var/job_civilian_low = 0 + + var/job_medsci_high = 0 + var/job_medsci_med = 0 + var/job_medsci_low = 0 + + var/job_engsec_high = 0 + var/job_engsec_med = 0 + var/job_engsec_low = 0 + + 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 + + //Can't use SSjob here since this happens right away on login + for(var/job in subtypesof(/datum/job)) + var/datum/job/J = job + var/new_value + var/fval = initial(J.flag) + switch(initial(J.department_flag)) + if(CIVILIAN) + if(job_civilian_high & fval) + new_value = JP_HIGH + else if(job_civilian_med & fval) + new_value = JP_MEDIUM + else if(job_civilian_low & fval) + new_value = JP_LOW + if(MEDSCI) + if(job_medsci_high & fval) + new_value = JP_HIGH + else if(job_medsci_med & fval) + new_value = JP_MEDIUM + else if(job_medsci_low & fval) + new_value = JP_LOW + if(ENGSEC) + if(job_engsec_high & fval) + new_value = JP_HIGH + else if(job_engsec_med & fval) + new_value = JP_MEDIUM + else if(job_engsec_low & fval) + new_value = JP_LOW + if(new_value) + job_preferences[initial(J.title)] = new_value /datum/preferences/proc/load_path(ckey,filename="preferences.sav") if(!ckey) @@ -289,15 +342,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car //Jobs S["joblessrole"] >> joblessrole - 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 + //Load prefs + S["job_preferences"] >> job_preferences //Quirks S["all_quirks"] >> all_quirks @@ -413,15 +459,10 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car features["moth_wings"] = sanitize_inlist(features["moth_wings"], GLOB.moth_wings_list) joblessrole = sanitize_integer(joblessrole, 1, 3, initial(joblessrole)) - 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)) + //Validate job prefs + for(var/j in job_preferences) + if(job_preferences[j] != JP_LOW && job_preferences[j] != JP_MEDIUM && job_preferences[j] != JP_LOW) + job_preferences -= j all_quirks = SANITIZE_LIST(all_quirks) positive_quirks = SANITIZE_LIST(positive_quirks) @@ -489,15 +530,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car //Jobs WRITE_FILE(S["joblessrole"] , joblessrole) - WRITE_FILE(S["job_civilian_high"] , job_civilian_high) - WRITE_FILE(S["job_civilian_med"] , job_civilian_med) - WRITE_FILE(S["job_civilian_low"] , job_civilian_low) - WRITE_FILE(S["job_medsci_high"] , job_medsci_high) - WRITE_FILE(S["job_medsci_med"] , job_medsci_med) - WRITE_FILE(S["job_medsci_low"] , job_medsci_low) - WRITE_FILE(S["job_engsec_high"] , job_engsec_high) - WRITE_FILE(S["job_engsec_med"] , job_engsec_med) - WRITE_FILE(S["job_engsec_low"] , job_engsec_low) + //Write prefs + WRITE_FILE(S["job_preferences"] , job_preferences) //Quirks WRITE_FILE(S["all_quirks"] , all_quirks) diff --git a/code/modules/jobs/job_exp.dm b/code/modules/jobs/job_exp.dm index 4b7b175240..f99bf65071 100644 --- a/code/modules/jobs/job_exp.dm +++ b/code/modules/jobs/job_exp.dm @@ -8,6 +8,8 @@ GLOBAL_PROTECT(exp_to_update) return 0 if(!CONFIG_GET(flag/use_exp_tracking)) return 0 + if(!SSdbcore.Connect()) + return 0 if(!exp_requirements || !exp_type) return 0 if(!job_is_xp_locked(src.title)) diff --git a/code/modules/jobs/job_types/job.dm b/code/modules/jobs/job_types/_job.dm similarity index 85% rename from code/modules/jobs/job_types/job.dm rename to code/modules/jobs/job_types/_job.dm index e441b3e889..59af18b76d 100644 --- a/code/modules/jobs/job_types/job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -1,223 +1,233 @@ -/datum/job - //The name of the job - var/title = "NOPE" - - //Job access. The use of minimal_access or access is determined by a config setting: config.jobs_have_minimal_access - var/list/minimal_access = list() //Useful for servers which prefer to only have access given to the places a job absolutely needs (Larger server population) - var/list/access = list() //Useful for servers which either have fewer players, so each person needs to fill more than one role, or servers which like to give more access, so players can't hide forever in their super secure departments (I'm looking at you, chemistry!) - - //Determines who can demote this position - var/department_head = list() - - //Tells the given channels that the given mob is the new department head. See communications.dm for valid channels. - var/list/head_announce = null - - //Bitflags for the job - var/flag = 0 - var/department_flag = 0 - - //Players will be allowed to spawn in as jobs that are set to "Station" - var/faction = "None" - - //How many players can be this job - var/total_positions = 0 - - //How many players can spawn in as this job - var/spawn_positions = 0 - - //How many players have this job - var/current_positions = 0 - - //Supervisors, who this person answers to directly - var/supervisors = "" - - //Sellection screen color - var/selection_color = "#ffffff" - - - //If this is set to 1, a text is printed to the player when jobs are assigned, telling him that he should let admins know that he has to disconnect. - var/req_admin_notify - - var/custom_spawn_text - - //If you have the use_age_restriction_for_jobs config option enabled and the database set up, this option will add a requirement for players to be at least minimal_player_age days old. (meaning they first signed in at least that many days before.) - var/minimal_player_age = 0 - - var/outfit = null - - var/exp_requirements = 0 - - var/exp_type = "" - var/exp_type_department = "" - - //The amount of good boy points playing this role will earn you towards a higher chance to roll antagonist next round - //can be overridden by antag_rep.txt config - var/antag_rep = 10 - -//Only override this proc -//H is usually a human unless an /equip override transformed it -/datum/job/proc/after_spawn(mob/living/H, mob/M, latejoin = FALSE) - //do actions on H but send messages to M as the key may not have been transferred_yet - -/datum/job/proc/announce(mob/living/carbon/human/H) - if(head_announce) - announce_head(H, head_announce) - -/datum/job/proc/override_latejoin_spawn(mob/living/carbon/human/H) //Return TRUE to force latejoining to not automatically place the person in latejoin shuttle/whatever. - return FALSE - -//Used for a special check of whether to allow a client to latejoin as this job. -/datum/job/proc/special_check_latejoin(client/C) - return TRUE - -/datum/job/proc/GetAntagRep() - . = CONFIG_GET(keyed_list/antag_rep)[lowertext(title)] - if(. == null) - return antag_rep - -//Don't override this unless the job transforms into a non-human (Silicons do this for example) -/datum/job/proc/equip(mob/living/carbon/human/H, visualsOnly = FALSE, announce = TRUE, latejoin = FALSE, datum/outfit/outfit_override = null) - if(!H) - return FALSE - - if(CONFIG_GET(flag/enforce_human_authority) && (title in GLOB.command_positions)) - if(H.dna.species.id != "human") - H.set_species(/datum/species/human) - H.apply_pref_name("human", H.client) - - //Equip the rest of the gear - H.dna.species.before_equip_job(src, H, visualsOnly) - - if(outfit_override || outfit) - H.equipOutfit(outfit_override ? outfit_override : outfit, visualsOnly) - - H.dna.species.after_equip_job(src, H, visualsOnly) - - if(!visualsOnly && announce) - announce(H) - -/datum/job/proc/get_access() - if(!config) //Needed for robots. - return src.minimal_access.Copy() - - . = list() - - if(CONFIG_GET(flag/jobs_have_minimal_access)) - . = src.minimal_access.Copy() - else - . = src.access.Copy() - - if(CONFIG_GET(flag/everyone_has_maint_access)) //Config has global maint access set - . |= list(ACCESS_MAINT_TUNNELS) - -/datum/job/proc/announce_head(var/mob/living/carbon/human/H, var/channels) //tells the given channel that the given mob is the new department head. See communications.dm for valid channels. - if(H && GLOB.announcement_systems.len) - //timer because these should come after the captain announcement - SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/addtimer, CALLBACK(pick(GLOB.announcement_systems), /obj/machinery/announcement_system/proc/announce, "NEWHEAD", H.real_name, H.job, channels), 1)) - -//If the configuration option is set to require players to be logged as old enough to play certain jobs, then this proc checks that they are, otherwise it just returns 1 -/datum/job/proc/player_old_enough(client/C) - if(available_in_days(C) == 0) - return TRUE //Available in 0 days = available right now = player is old enough to play. - return FALSE - - -/datum/job/proc/available_in_days(client/C) - if(!C) - return 0 - if(!CONFIG_GET(flag/use_age_restriction_for_jobs)) - return 0 - if(C.prefs.db_flags & DB_FLAG_EXEMPT) - return 0 - if(!isnum(C.player_age)) - return 0 //This is only a number if the db connection is established, otherwise it is text: "Requires database", meaning these restrictions cannot be enforced - if(!isnum(minimal_player_age)) - return 0 - - return max(0, minimal_player_age - C.player_age) - -/datum/job/proc/config_check() - return TRUE - -/datum/job/proc/map_check() - return TRUE - - -/datum/outfit/job - name = "Standard Gear" - - var/jobtype = null - - uniform = /obj/item/clothing/under/color/grey - id = /obj/item/card/id - ears = /obj/item/radio/headset - belt = /obj/item/pda - back = /obj/item/storage/backpack - shoes = /obj/item/clothing/shoes/sneakers/black - - var/backpack = /obj/item/storage/backpack - var/satchel = /obj/item/storage/backpack/satchel - var/duffelbag = /obj/item/storage/backpack/duffelbag - var/box = /obj/item/storage/box/survival - - var/pda_slot = SLOT_BELT - -/datum/outfit/job/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - switch(H.backbag) - if(GBACKPACK) - back = /obj/item/storage/backpack //Grey backpack - if(GSATCHEL) - back = /obj/item/storage/backpack/satchel //Grey satchel - if(GDUFFELBAG) - back = /obj/item/storage/backpack/duffelbag //Grey Duffel bag - if(LSATCHEL) - back = /obj/item/storage/backpack/satchel/leather //Leather Satchel - if(DSATCHEL) - back = satchel //Department satchel - if(DDUFFELBAG) - back = duffelbag //Department duffel bag - else - back = backpack //Department backpack - - if(box) - if(!backpack_contents) - backpack_contents = list() - backpack_contents.Insert(1, box) // Box always takes a first slot in backpack - backpack_contents[box] = 1 - -/datum/outfit/job/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - if(visualsOnly) - return - - var/datum/job/J = SSjob.GetJobType(jobtype) - if(!J) - J = SSjob.GetJob(H.job) - - if(H.nameless && J.dresscodecompliant) - if(J.title in GLOB.command_positions) - H.real_name = J.title - else - H.real_name = "[J.title] #[rand(10000, 99999)]" - - var/obj/item/card/id/C = H.wear_id - if(istype(C)) - C.access = J.get_access() - shuffle_inplace(C.access) // Shuffle access list to make NTNet passkeys less predictable - C.registered_name = H.real_name - C.assignment = J.title - C.update_label() - H.sec_hud_set_ID() - - var/obj/item/pda/PDA = H.get_item_by_slot(pda_slot) - if(istype(PDA)) - PDA.owner = H.real_name - PDA.ownjob = J.title - PDA.update_label() - -/datum/outfit/job/get_chameleon_disguise_info() - var/list/types = ..() - types -= /obj/item/storage/backpack //otherwise this will override the actual backpacks - types += backpack - types += satchel - types += duffelbag - return types +/datum/job + //The name of the job , used for preferences, bans and more. Make sure you know what you're doing before changing this. + var/title = "NOPE" + + //Job access. The use of minimal_access or access is determined by a config setting: config.jobs_have_minimal_access + var/list/minimal_access = list() //Useful for servers which prefer to only have access given to the places a job absolutely needs (Larger server population) + var/list/access = list() //Useful for servers which either have fewer players, so each person needs to fill more than one role, or servers which like to give more access, so players can't hide forever in their super secure departments (I'm looking at you, chemistry!) + + //Determines who can demote this position + var/department_head = list() + + //Tells the given channels that the given mob is the new department head. See communications.dm for valid channels. + var/list/head_announce = null + + //Bitflags for the job + var/flag = NONE //Deprecated + var/department_flag = NONE //Deprecated +// var/auto_deadmin_role_flags = NONE + + //Players will be allowed to spawn in as jobs that are set to "Station" + var/faction = "None" + + //How many players can be this job + var/total_positions = 0 + + //How many players can spawn in as this job + var/spawn_positions = 0 + + //How many players have this job + var/current_positions = 0 + + //Supervisors, who this person answers to directly + var/supervisors = "" + + //Sellection screen color + var/selection_color = "#ffffff" + + + //If this is set to 1, a text is printed to the player when jobs are assigned, telling him that he should let admins know that he has to disconnect. + var/req_admin_notify + + // This is for Citadel specific tweaks to job notices. + var/custom_spawn_text + + //If you have the use_age_restriction_for_jobs config option enabled and the database set up, this option will add a requirement for players to be at least minimal_player_age days old. (meaning they first signed in at least that many days before.) + var/minimal_player_age = 0 + + var/outfit = null + + var/exp_requirements = 0 + + var/exp_type = "" + var/exp_type_department = "" + + //The amount of good boy points playing this role will earn you towards a higher chance to roll antagonist next round + //can be overridden by antag_rep.txt config + var/antag_rep = 10 + + var/list/mind_traits // Traits added to the mind of the mob assigned this job + + var/display_order = JOB_DISPLAY_ORDER_DEFAULT + +//Only override this proc +//H is usually a human unless an /equip override transformed it +/datum/job/proc/after_spawn(mob/living/H, mob/M, latejoin = FALSE) + //do actions on H but send messages to M as the key may not have been transferred_yet +/* if(mind_traits) + for(var/t in mind_traits) + ADD_TRAIT(H.mind, t, JOB_TRAIT)*/ + +/datum/job/proc/announce(mob/living/carbon/human/H) + if(head_announce) + announce_head(H, head_announce) + +/datum/job/proc/override_latejoin_spawn(mob/living/carbon/human/H) //Return TRUE to force latejoining to not automatically place the person in latejoin shuttle/whatever. + return FALSE + +//Used for a special check of whether to allow a client to latejoin as this job. +/datum/job/proc/special_check_latejoin(client/C) + return TRUE + +/datum/job/proc/GetAntagRep() + . = CONFIG_GET(keyed_list/antag_rep)[lowertext(title)] + if(. == null) + return antag_rep + +//Don't override this unless the job transforms into a non-human (Silicons do this for example) +/datum/job/proc/equip(mob/living/carbon/human/H, visualsOnly = FALSE, announce = TRUE, latejoin = FALSE, datum/outfit/outfit_override = null, client/preference_source) + if(!H) + return FALSE + + if(CONFIG_GET(flag/enforce_human_authority) && (title in GLOB.command_positions)) + if(H.dna.species.id != "human") + H.set_species(/datum/species/human) + H.apply_pref_name("human", preference_source) + + //Equip the rest of the gear + H.dna.species.before_equip_job(src, H, visualsOnly) + + if(outfit_override || outfit) + H.equipOutfit(outfit_override ? outfit_override : outfit, visualsOnly) + + H.dna.species.after_equip_job(src, H, visualsOnly) + + if(!visualsOnly && announce) + announce(H) + +/datum/job/proc/get_access() + if(!config) //Needed for robots. + return src.minimal_access.Copy() + + . = list() + + if(CONFIG_GET(flag/jobs_have_minimal_access)) + . = src.minimal_access.Copy() + else + . = src.access.Copy() + + if(CONFIG_GET(flag/everyone_has_maint_access)) //Config has global maint access set + . |= list(ACCESS_MAINT_TUNNELS) + +/datum/job/proc/announce_head(var/mob/living/carbon/human/H, var/channels) //tells the given channel that the given mob is the new department head. See communications.dm for valid channels. + if(H && GLOB.announcement_systems.len) + //timer because these should come after the captain announcement + SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/addtimer, CALLBACK(pick(GLOB.announcement_systems), /obj/machinery/announcement_system/proc/announce, "NEWHEAD", H.real_name, H.job, channels), 1)) + +//If the configuration option is set to require players to be logged as old enough to play certain jobs, then this proc checks that they are, otherwise it just returns 1 +/datum/job/proc/player_old_enough(client/C) + if(available_in_days(C) == 0) + return TRUE //Available in 0 days = available right now = player is old enough to play. + return FALSE + + +/datum/job/proc/available_in_days(client/C) + if(!C) + return 0 + if(!CONFIG_GET(flag/use_age_restriction_for_jobs)) + return 0 + if(!SSdbcore.Connect()) + return 0 //Without a database connection we can't get a player's age so we'll assume they're old enough for all jobs + if(!isnum(minimal_player_age)) + return 0 + + return max(0, minimal_player_age - C.player_age) + +/datum/job/proc/config_check() + return TRUE + +/datum/job/proc/map_check() + return TRUE + +/datum/job/proc/radio_help_message(mob/M) + to_chat(M, "Prefix your message with :h to speak on your department's radio. To see other prefixes, look closely at your headset.") + +/datum/outfit/job + name = "Standard Gear" + + var/jobtype = null + + uniform = /obj/item/clothing/under/color/grey + id = /obj/item/card/id + ears = /obj/item/radio/headset + belt = /obj/item/pda + back = /obj/item/storage/backpack + shoes = /obj/item/clothing/shoes/sneakers/black + box = /obj/item/storage/box/survival + + var/backpack = /obj/item/storage/backpack + var/satchel = /obj/item/storage/backpack/satchel + var/duffelbag = /obj/item/storage/backpack/duffelbag + + var/pda_slot = SLOT_BELT + +/datum/outfit/job/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE) + switch(H.backbag) + if(GBACKPACK) + back = /obj/item/storage/backpack //Grey backpack + if(GSATCHEL) + back = /obj/item/storage/backpack/satchel //Grey satchel + if(GDUFFELBAG) + back = /obj/item/storage/backpack/duffelbag //Grey Duffel bag + if(LSATCHEL) + back = /obj/item/storage/backpack/satchel/leather //Leather Satchel + if(DSATCHEL) + back = satchel //Department satchel + if(DDUFFELBAG) + back = duffelbag //Department duffel bag + else + back = backpack //Department backpack + +/datum/outfit/job/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) + if(visualsOnly) + return + + var/datum/job/J = SSjob.GetJobType(jobtype) + if(!J) + J = SSjob.GetJob(H.job) + + if(H.nameless && J.dresscodecompliant) + if(J.title in GLOB.command_positions) + H.real_name = J.title + else + H.real_name = "[J.title] #[rand(10000, 99999)]" + + var/obj/item/card/id/C = H.wear_id + if(istype(C)) + C.access = J.get_access() + shuffle_inplace(C.access) // Shuffle access list to make NTNet passkeys less predictable + C.registered_name = H.real_name + C.assignment = J.title + C.update_label() + H.sec_hud_set_ID() + + var/obj/item/pda/PDA = H.get_item_by_slot(pda_slot) + if(istype(PDA)) + PDA.owner = H.real_name + PDA.ownjob = J.title + PDA.update_label() + +/datum/outfit/job/get_chameleon_disguise_info() + var/list/types = ..() + types -= /obj/item/storage/backpack //otherwise this will override the actual backpacks + types += backpack + types += satchel + types += duffelbag + return types + +//Warden and regular officers add this result to their get_access() +/datum/job/proc/check_config_for_sec_maint() + if(CONFIG_GET(flag/security_has_maint_access)) + return list(ACCESS_MAINT_TUNNELS) + return list() + diff --git a/code/modules/jobs/job_types/silicon.dm b/code/modules/jobs/job_types/ai.dm similarity index 71% rename from code/modules/jobs/job_types/silicon.dm rename to code/modules/jobs/job_types/ai.dm index ab963eb8f3..4bcfab5836 100644 --- a/code/modules/jobs/job_types/silicon.dm +++ b/code/modules/jobs/job_types/ai.dm @@ -1,90 +1,69 @@ -/* -AI -*/ -/datum/job/ai - title = "AI" - flag = AI_JF - department_flag = ENGSEC - faction = "Station" - total_positions = 1 - spawn_positions = 1 - selection_color = "#ccffcc" - supervisors = "your laws" - req_admin_notify = TRUE - minimal_player_age = 30 - exp_requirements = 180 - exp_type = EXP_TYPE_CREW - exp_type_department = EXP_TYPE_SILICON - var/do_special_check = TRUE - -/datum/job/ai/equip(mob/living/carbon/human/H, visualsOnly, announce, latejoin, outfit_override) - . = H.AIize(latejoin) - -/datum/job/ai/after_spawn(mob/H, mob/M, latejoin) - . = ..() - if(latejoin) - var/obj/structure/AIcore/latejoin_inactive/lateJoinCore - for(var/obj/structure/AIcore/latejoin_inactive/P in GLOB.latejoin_ai_cores) - if(P.is_available()) - lateJoinCore = P - GLOB.latejoin_ai_cores -= P - break - if(lateJoinCore) - lateJoinCore.available = FALSE - H.forceMove(lateJoinCore.loc) - qdel(lateJoinCore) - var/mob/living/silicon/ai/AI = H - AI.apply_pref_name("ai", M.client) //If this runtimes oh well jobcode is fucked. - AI.set_core_display_icon(null, M.client) - - //we may have been created after our borg - if(SSticker.current_state == GAME_STATE_SETTING_UP) - for(var/mob/living/silicon/robot/R in GLOB.silicon_mobs) - if(!R.connected_ai) - R.TryConnectToAI() - - if(latejoin) - announce(AI) - -/datum/job/ai/override_latejoin_spawn() - return TRUE - -/datum/job/ai/special_check_latejoin(client/C) - if(!do_special_check) - return TRUE - for(var/i in GLOB.latejoin_ai_cores) - var/obj/structure/AIcore/latejoin_inactive/LAI = i - if(istype(LAI)) - if(LAI.is_available()) - return TRUE - return FALSE - -/datum/job/ai/announce(mob/living/silicon/ai/AI) - . = ..() - SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "[AI] has been downloaded to an empty bluespace-networked AI core at [AREACOORD(AI)].")) - -/datum/job/ai/config_check() - return CONFIG_GET(flag/allow_ai) - -/* -Cyborg -*/ -/datum/job/cyborg - title = "Cyborg" - flag = CYBORG - department_flag = ENGSEC - faction = "Station" - total_positions = 0 - spawn_positions = 1 - supervisors = "your laws and the AI" //Nodrak - selection_color = "#ddffdd" - minimal_player_age = 21 - exp_requirements = 120 - exp_type = EXP_TYPE_CREW - -/datum/job/cyborg/equip(mob/living/carbon/human/H, visualsOnly = FALSE, announce = TRUE, latejoin = FALSE, outfit_override = null) - return H.Robotize(FALSE, latejoin) - -/datum/job/cyborg/after_spawn(mob/living/silicon/robot/R, mob/M) - R.updatename(M.client) - R.gender = NEUTER +/datum/job/ai + title = "AI" + flag = AI_JF +// auto_deadmin_role_flags = DEADMIN_POSITION_SILICON + department_flag = ENGSEC + faction = "Station" + total_positions = 1 + spawn_positions = 1 + selection_color = "#ccffcc" + supervisors = "your laws" + req_admin_notify = TRUE + minimal_player_age = 30 + exp_requirements = 180 + exp_type = EXP_TYPE_CREW + exp_type_department = EXP_TYPE_SILICON + display_order = JOB_DISPLAY_ORDER_AI + var/do_special_check = TRUE + +/datum/job/ai/equip(mob/living/carbon/human/H, visualsOnly, announce, latejoin, datum/outfit/outfit_override, client/preference_source = null) + if(visualsOnly) + CRASH("dynamic preview is unsupported") + . = H.AIize(latejoin,preference_source) + +/datum/job/ai/after_spawn(mob/H, mob/M, latejoin) + . = ..() + if(latejoin) + var/obj/structure/AIcore/latejoin_inactive/lateJoinCore + for(var/obj/structure/AIcore/latejoin_inactive/P in GLOB.latejoin_ai_cores) + if(P.is_available()) + lateJoinCore = P + GLOB.latejoin_ai_cores -= P + break + if(lateJoinCore) + lateJoinCore.available = FALSE + H.forceMove(lateJoinCore.loc) + qdel(lateJoinCore) + var/mob/living/silicon/ai/AI = H + AI.apply_pref_name("ai", M.client) //If this runtimes oh well jobcode is fucked. + AI.set_core_display_icon(null, M.client) + + //we may have been created after our borg + if(SSticker.current_state == GAME_STATE_SETTING_UP) + for(var/mob/living/silicon/robot/R in GLOB.silicon_mobs) + if(!R.connected_ai) + R.TryConnectToAI() + + if(latejoin) + announce(AI) + +/datum/job/ai/override_latejoin_spawn() + return TRUE + +/datum/job/ai/special_check_latejoin(client/C) + if(!do_special_check) + return TRUE + for(var/i in GLOB.latejoin_ai_cores) + var/obj/structure/AIcore/latejoin_inactive/LAI = i + if(istype(LAI)) + if(LAI.is_available()) + return TRUE + return FALSE + +/datum/job/ai/announce(mob/living/silicon/ai/AI) + . = ..() + SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "[AI] has been downloaded to an empty bluespace-networked AI core at [AREACOORD(AI)].")) + +/datum/job/ai/config_check() + return CONFIG_GET(flag/allow_ai) + diff --git a/code/modules/jobs/job_types/assistant.dm b/code/modules/jobs/job_types/assistant.dm index 65805f73fd..726d099ec6 100644 --- a/code/modules/jobs/job_types/assistant.dm +++ b/code/modules/jobs/job_types/assistant.dm @@ -14,7 +14,7 @@ Assistant minimal_access = list() //See /datum/job/assistant/get_access() outfit = /datum/outfit/job/assistant antag_rep = 7 - + display_order = JOB_DISPLAY_ORDER_ASSISTANT /datum/job/assistant/get_access() if(CONFIG_GET(flag/assistants_have_maint_access) || !CONFIG_GET(flag/jobs_have_minimal_access)) //Config has assistant maint access set diff --git a/code/modules/jobs/job_types/atmospheric_technician.dm b/code/modules/jobs/job_types/atmospheric_technician.dm new file mode 100644 index 0000000000..31d66eced2 --- /dev/null +++ b/code/modules/jobs/job_types/atmospheric_technician.dm @@ -0,0 +1,44 @@ +/datum/job/atmos + title = "Atmospheric Technician" + flag = ATMOSTECH + department_head = list("Chief Engineer") + department_flag = ENGSEC + faction = "Station" + total_positions = 3 + spawn_positions = 2 + supervisors = "the chief engineer" + selection_color = "#fff5cc" + exp_requirements = 60 + exp_type = EXP_TYPE_CREW + + outfit = /datum/outfit/job/atmos + + access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, + ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_ATMOSPHERICS, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_ATMOSPHERICS, ACCESS_MAINT_TUNNELS, ACCESS_CONSTRUCTION, ACCESS_MINERAL_STOREROOM) + display_order = JOB_DISPLAY_ORDER_ATMOSPHERIC_TECHNICIAN + +/datum/outfit/job/atmos + name = "Atmospheric Technician" + jobtype = /datum/job/atmos + + belt = /obj/item/storage/belt/utility/atmostech + l_pocket = /obj/item/pda/atmos + ears = /obj/item/radio/headset/headset_eng + uniform = /obj/item/clothing/under/rank/atmospheric_technician + r_pocket = /obj/item/analyzer + + backpack = /obj/item/storage/backpack/industrial + satchel = /obj/item/storage/backpack/satchel/eng + duffelbag = /obj/item/storage/backpack/duffelbag/engineering + box = /obj/item/storage/box/engineer + pda_slot = SLOT_L_STORE + backpack_contents = list(/obj/item/modular_computer/tablet/preset/advanced=1) + +/datum/outfit/job/atmos/rig + name = "Atmospheric Technician (Hardsuit)" + + mask = /obj/item/clothing/mask/gas + suit = /obj/item/clothing/suit/space/hardsuit/engine/atmos + suit_store = /obj/item/tank/internals/oxygen + internals_slot = SLOT_S_STORE diff --git a/code/modules/jobs/job_types/bartender.dm b/code/modules/jobs/job_types/bartender.dm new file mode 100644 index 0000000000..5d13720da2 --- /dev/null +++ b/code/modules/jobs/job_types/bartender.dm @@ -0,0 +1,30 @@ +/datum/job/bartender + title = "Bartender" + flag = BARTENDER + department_head = list("Head of Personnel") + department_flag = CIVILIAN + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the head of personnel" + selection_color = "#bbe291" + exp_type_department = EXP_TYPE_SERVICE // This is so the jobs menu can work properly + + outfit = /datum/outfit/job/bartender + + access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_BAR, ACCESS_MINERAL_STOREROOM) + display_order = JOB_DISPLAY_ORDER_BARTENDER + +/datum/outfit/job/bartender + name = "Bartender" + jobtype = /datum/job/bartender + + glasses = /obj/item/clothing/glasses/sunglasses/reagent + belt = /obj/item/pda/bar + ears = /obj/item/radio/headset/headset_srv + uniform = /obj/item/clothing/under/rank/bartender + suit = /obj/item/clothing/suit/armor/vest + backpack_contents = list(/obj/item/storage/box/beanbag=1) + shoes = /obj/item/clothing/shoes/laceup + diff --git a/code/modules/jobs/job_types/botanist.dm b/code/modules/jobs/job_types/botanist.dm new file mode 100644 index 0000000000..e6338d9b0a --- /dev/null +++ b/code/modules/jobs/job_types/botanist.dm @@ -0,0 +1,32 @@ +/datum/job/hydro + title = "Botanist" + flag = BOTANIST + department_head = list("Head of Personnel") + department_flag = CIVILIAN + faction = "Station" + total_positions = 3 + spawn_positions = 2 + supervisors = "the head of personnel" + selection_color = "#bbe291" + + outfit = /datum/outfit/job/botanist + + access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_HYDROPONICS, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM) + display_order = JOB_DISPLAY_ORDER_BOTANIST + +/datum/outfit/job/botanist + name = "Botanist" + jobtype = /datum/job/hydro + + belt = /obj/item/pda/botanist + ears = /obj/item/radio/headset/headset_srv + uniform = /obj/item/clothing/under/rank/hydroponics + suit = /obj/item/clothing/suit/apron + gloves =/obj/item/clothing/gloves/botanic_leather + suit_store = /obj/item/plant_analyzer + + backpack = /obj/item/storage/backpack/botany + satchel = /obj/item/storage/backpack/satchel/hyd + + diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm index cd9c914e7a..e80840f8aa 100755 --- a/code/modules/jobs/job_types/captain.dm +++ b/code/modules/jobs/job_types/captain.dm @@ -1,9 +1,7 @@ -/* -Captain -*/ /datum/job/captain title = "Captain" flag = CAPTAIN +// auto_deadmin_role_flags = DEADMIN_POSITION_HEAD|DEADMIN_POSITION_SECURITY //:eyes: department_head = list("CentCom") department_flag = ENGSEC faction = "Station" @@ -15,12 +13,17 @@ Captain minimal_player_age = 14 exp_requirements = 180 exp_type = EXP_TYPE_CREW + exp_type_department = EXP_TYPE_COMMAND outfit = /datum/outfit/job/captain access = list() //See get_access() minimal_access = list() //See get_access() +// mind_traits = list(TRAIT_DISK_VERIFIER) + + display_order = JOB_DISPLAY_ORDER_CAPTAIN + /datum/job/captain/get_access() return get_all_accesses() @@ -58,54 +61,3 @@ Captain mask = /obj/item/clothing/mask/gas/sechailer suit = /obj/item/clothing/suit/space/hardsuit/captain suit_store = /obj/item/tank/internals/oxygen - -/* -Head of Personnel -*/ -/datum/job/hop - title = "Head of Personnel" - flag = HOP - department_head = list("Captain") - department_flag = CIVILIAN - head_announce = list("Supply", "Service") - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the captain" - selection_color = "#ddddff" - req_admin_notify = 1 - minimal_player_age = 10 - exp_requirements = 180 - exp_type = EXP_TYPE_CREW - exp_type_department = EXP_TYPE_SUPPLY - - outfit = /datum/outfit/job/hop - - access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_COURT, ACCESS_WEAPONS, - ACCESS_MEDICAL, ACCESS_ENGINE, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_EVA, ACCESS_HEADS, - ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_MAINT_TUNNELS, ACCESS_BAR, ACCESS_JANITOR, ACCESS_CONSTRUCTION, ACCESS_MORGUE, - ACCESS_CREMATORIUM, ACCESS_KITCHEN, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_MAILSORTING, ACCESS_QM, ACCESS_HYDROPONICS, ACCESS_LAWYER, - ACCESS_THEATRE, ACCESS_CHAPEL_OFFICE, ACCESS_LIBRARY, ACCESS_RESEARCH, ACCESS_MINING, ACCESS_VAULT, ACCESS_MINING_STATION, - ACCESS_HOP, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_COURT, ACCESS_WEAPONS, - ACCESS_MEDICAL, ACCESS_ENGINE, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_EVA, ACCESS_HEADS, - ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_MAINT_TUNNELS, ACCESS_BAR, ACCESS_JANITOR, ACCESS_CONSTRUCTION, ACCESS_MORGUE, - ACCESS_CREMATORIUM, ACCESS_KITCHEN, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_MAILSORTING, ACCESS_QM, ACCESS_HYDROPONICS, ACCESS_LAWYER, - ACCESS_THEATRE, ACCESS_CHAPEL_OFFICE, ACCESS_LIBRARY, ACCESS_RESEARCH, ACCESS_MINING, ACCESS_VAULT, ACCESS_MINING_STATION, - ACCESS_HOP, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM) - - -/datum/outfit/job/hop - name = "Head of Personnel" - jobtype = /datum/job/hop - - id = /obj/item/card/id/silver - belt = /obj/item/pda/heads/hop - ears = /obj/item/radio/headset/heads/hop - uniform = /obj/item/clothing/under/rank/head_of_personnel - shoes = /obj/item/clothing/shoes/sneakers/brown - head = /obj/item/clothing/head/hopcap - backpack_contents = list(/obj/item/storage/box/ids=1,\ - /obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced = 1) - - chameleon_extras = list(/obj/item/gun/energy/e_gun, /obj/item/stamp/hop) diff --git a/code/modules/jobs/job_types/cargo_service.dm b/code/modules/jobs/job_types/cargo_service.dm deleted file mode 100644 index 22ef2a9211..0000000000 --- a/code/modules/jobs/job_types/cargo_service.dm +++ /dev/null @@ -1,290 +0,0 @@ -/* -Quartermaster -*/ -/datum/job/qm - title = "Quartermaster" - flag = QUARTERMASTER - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the head of personnel" - selection_color = "#d7b088" - - outfit = /datum/outfit/job/quartermaster - - access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM, ACCESS_VAULT) - minimal_access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM, ACCESS_VAULT) - -/datum/outfit/job/quartermaster - name = "Quartermaster" - jobtype = /datum/job/qm - - belt = /obj/item/pda/quartermaster - ears = /obj/item/radio/headset/headset_cargo - uniform = /obj/item/clothing/under/rank/cargo - shoes = /obj/item/clothing/shoes/sneakers/brown - glasses = /obj/item/clothing/glasses/sunglasses - l_hand = /obj/item/clipboard - - chameleon_extras = /obj/item/stamp/qm - -/* -Cargo Technician -*/ -/datum/job/cargo_tech - title = "Cargo Technician" - flag = CARGOTECH - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 3 - spawn_positions = 2 - supervisors = "the quartermaster and the head of personnel" - selection_color = "#dcba97" - - outfit = /datum/outfit/job/cargo_tech - - access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_MAINT_TUNNELS, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_MAILSORTING, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/cargo_tech - name = "Cargo Technician" - jobtype = /datum/job/cargo_tech - - belt = /obj/item/pda/cargo - ears = /obj/item/radio/headset/headset_cargo - uniform = /obj/item/clothing/under/rank/cargotech - l_hand = /obj/item/export_scanner - -/* -Shaft Miner -*/ -/datum/job/mining - title = "Shaft Miner" - flag = MINER - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 3 - spawn_positions = 3 - supervisors = "the quartermaster and the head of personnel" - selection_color = "#dcba97" - custom_spawn_text = "Remember, you are a miner, not a hunter. Hunting monsters is not a requirement of your job, the only requirement of your job is to provide materials for the station. Don't be afraid to run away if you're inexperienced with fighting the mining area's locals." - - outfit = /datum/outfit/job/miner - - access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MAILSORTING, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/miner - name = "Shaft Miner (Lavaland)" - jobtype = /datum/job/mining - - belt = /obj/item/pda/shaftminer - ears = /obj/item/radio/headset/headset_cargo/mining - shoes = /obj/item/clothing/shoes/workboots/mining - gloves = /obj/item/clothing/gloves/color/black - uniform = /obj/item/clothing/under/rank/miner/lavaland - l_pocket = /obj/item/reagent_containers/hypospray/medipen/survival - r_pocket = /obj/item/flashlight/seclite - backpack_contents = list( - /obj/item/storage/bag/ore=1,\ - /obj/item/kitchen/knife/combat/survival=1,\ - /obj/item/mining_voucher=1,\ - /obj/item/suit_voucher=1,\ - /obj/item/stack/marker_beacon/ten=1) - - backpack = /obj/item/storage/backpack/explorer - satchel = /obj/item/storage/backpack/satchel/explorer - duffelbag = /obj/item/storage/backpack/duffelbag - box = /obj/item/storage/box/survival_mining - - chameleon_extras = /obj/item/gun/energy/kinetic_accelerator - -/datum/outfit/job/miner/asteroid - name = "Shaft Miner (Asteroid)" - uniform = /obj/item/clothing/under/rank/miner - shoes = /obj/item/clothing/shoes/workboots - -/datum/outfit/job/miner/equipped - name = "Shaft Miner (Lavaland + Equipment)" - suit = /obj/item/clothing/suit/hooded/explorer/standard - mask = /obj/item/clothing/mask/gas/explorer - glasses = /obj/item/clothing/glasses/meson - suit_store = /obj/item/tank/internals/oxygen - internals_slot = SLOT_S_STORE - backpack_contents = list( - /obj/item/storage/bag/ore=1, - /obj/item/kitchen/knife/combat/survival=1, - /obj/item/mining_voucher=1, - /obj/item/t_scanner/adv_mining_scanner/lesser=1, - /obj/item/gun/energy/kinetic_accelerator=1,\ - /obj/item/stack/marker_beacon/ten=1) - -/datum/outfit/job/miner/equipped/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - ..() - if(visualsOnly) - return - if(istype(H.wear_suit, /obj/item/clothing/suit/hooded)) - var/obj/item/clothing/suit/hooded/S = H.wear_suit - S.ToggleHood() - -/datum/outfit/job/miner/equipped/hardsuit - name = "Shaft Miner (Equipment + Hardsuit)" - suit = /obj/item/clothing/suit/space/hardsuit/mining - mask = /obj/item/clothing/mask/breath - - -/* -Bartender -*/ -/datum/job/bartender - title = "Bartender" - flag = BARTENDER - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the head of personnel" - selection_color = "#bbe291" - - outfit = /datum/outfit/job/bartender - - access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_BAR, ACCESS_MINERAL_STOREROOM) - - -/datum/outfit/job/bartender - name = "Bartender" - jobtype = /datum/job/bartender - - glasses = /obj/item/clothing/glasses/sunglasses/reagent - belt = /obj/item/pda/bar - ears = /obj/item/radio/headset/headset_srv - uniform = /obj/item/clothing/under/rank/bartender - suit = /obj/item/clothing/suit/armor/vest - backpack_contents = list(/obj/item/storage/box/beanbag=1,/obj/item/book/granter/action/drink_fling=1) - shoes = /obj/item/clothing/shoes/laceup - -/* -Cook -*/ -/datum/job/cook - title = "Cook" - flag = COOK - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 2 - spawn_positions = 1 - supervisors = "the head of personnel" - selection_color = "#bbe291" - var/cooks = 0 //Counts cooks amount - - outfit = /datum/outfit/job/cook - - access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/cook - name = "Cook" - jobtype = /datum/job/cook - - belt = /obj/item/pda/cook - ears = /obj/item/radio/headset/headset_srv - uniform = /obj/item/clothing/under/rank/chef - suit = /obj/item/clothing/suit/toggle/chef - head = /obj/item/clothing/head/chefhat - mask = /obj/item/clothing/mask/fakemoustache/italian - backpack_contents = list(/obj/item/sharpener = 1) - -/datum/outfit/job/cook/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - ..() - var/datum/job/cook/J = SSjob.GetJobType(jobtype) - if(J) // Fix for runtime caused by invalid job being passed - if(J.cooks>0)//Cooks - suit = /obj/item/clothing/suit/apron/chef - head = /obj/item/clothing/head/soft/mime - if(!visualsOnly) - J.cooks++ - -/datum/outfit/job/cook/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - ..() - if(visualsOnly) - return - var/list/possible_boxes = subtypesof(/obj/item/storage/box/ingredients) - var/chosen_box = pick(possible_boxes) - var/obj/item/storage/box/I = new chosen_box(src) - H.equip_to_slot_or_del(I,SLOT_IN_BACKPACK) - var/datum/martial_art/cqc/under_siege/justacook = new - justacook.teach(H) - -/* -Botanist -*/ -/datum/job/hydro - title = "Botanist" - flag = BOTANIST - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 3 - spawn_positions = 2 - supervisors = "the head of personnel" - selection_color = "#bbe291" - - outfit = /datum/outfit/job/botanist - - access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_HYDROPONICS, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM) - // Removed tox and chem access because STOP PISSING OFF THE CHEMIST GUYS - // Removed medical access because WHAT THE FUCK YOU AREN'T A DOCTOR YOU GROW WHEAT - // Given Morgue access because they have a viable means of cloning. - - -/datum/outfit/job/botanist - name = "Botanist" - jobtype = /datum/job/hydro - - belt = /obj/item/pda/botanist - ears = /obj/item/radio/headset/headset_srv - uniform = /obj/item/clothing/under/rank/hydroponics - suit = /obj/item/clothing/suit/apron - gloves =/obj/item/clothing/gloves/botanic_leather - suit_store = /obj/item/plant_analyzer - - backpack = /obj/item/storage/backpack/botany - satchel = /obj/item/storage/backpack/satchel/hyd - - -/* -Janitor -*/ -/datum/job/janitor - title = "Janitor" - flag = JANITOR - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 2 - spawn_positions = 1 - supervisors = "the head of personnel" - selection_color = "#bbe291" - var/global/janitors = 0 - - outfit = /datum/outfit/job/janitor - - access = list(ACCESS_JANITOR, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_JANITOR, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/janitor - name = "Janitor" - jobtype = /datum/job/janitor - - belt = /obj/item/pda/janitor - ears = /obj/item/radio/headset/headset_srv - uniform = /obj/item/clothing/under/rank/janitor - backpack_contents = list(/obj/item/modular_computer/tablet/preset/advanced=1) diff --git a/code/modules/jobs/job_types/cargo_technician.dm b/code/modules/jobs/job_types/cargo_technician.dm new file mode 100644 index 0000000000..9699f12be5 --- /dev/null +++ b/code/modules/jobs/job_types/cargo_technician.dm @@ -0,0 +1,27 @@ +/datum/job/cargo_tech + title = "Cargo Technician" + flag = CARGOTECH + department_head = list("Quartermaster") + department_flag = CIVILIAN + faction = "Station" + total_positions = 3 + spawn_positions = 2 + supervisors = "the quartermaster" + selection_color = "#dcba97" + + outfit = /datum/outfit/job/cargo_tech + + access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_MAINT_TUNNELS, ACCESS_CARGO, ACCESS_MAILSORTING, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_CARGO_TECHNICIAN + +/datum/outfit/job/cargo_tech + name = "Cargo Technician" + jobtype = /datum/job/cargo_tech + + belt = /obj/item/pda/cargo + ears = /obj/item/radio/headset/headset_cargo + uniform = /obj/item/clothing/under/rank/cargotech + l_hand = /obj/item/export_scanner + diff --git a/code/modules/jobs/job_types/civilian_chaplain.dm b/code/modules/jobs/job_types/chaplain.dm similarity index 67% rename from code/modules/jobs/job_types/civilian_chaplain.dm rename to code/modules/jobs/job_types/chaplain.dm index e44347a208..f2ced729a9 100644 --- a/code/modules/jobs/job_types/civilian_chaplain.dm +++ b/code/modules/jobs/job_types/chaplain.dm @@ -1,94 +1,121 @@ -//Due to how large this one is it gets its own file -/* -Chaplain -*/ -/datum/job/chaplain - title = "Chaplain" - flag = CHAPLAIN - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the head of personnel" - selection_color = "#dddddd" - - outfit = /datum/outfit/job/chaplain - - access = list(ACCESS_MORGUE, ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_THEATRE) - minimal_access = list(ACCESS_MORGUE, ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_THEATRE) - -/datum/job/chaplain/after_spawn(mob/living/H, mob/M) - if(H.mind) - H.mind.isholy = TRUE - - var/obj/item/storage/book/bible/booze/B = new - - if(SSreligion.religion) - B.deity_name = SSreligion.deity - B.name = SSreligion.bible_name - B.icon_state = SSreligion.bible_icon_state - B.item_state = SSreligion.bible_item_state - to_chat(H, "There is already an established religion onboard the station. You are an acolyte of [SSreligion.deity]. Defer to the Chaplain.") - H.equip_to_slot_or_del(B, SLOT_IN_BACKPACK) - var/nrt = SSreligion.holy_weapon_type || /obj/item/nullrod - var/obj/item/nullrod/N = new nrt(H) - H.put_in_hands(N) - return - - var/new_religion = "Christianity" - if(M.client && M.client.prefs.custom_names["religion"]) - new_religion = M.client.prefs.custom_names["religion"] - - var/new_deity = "Space Jesus" - if(M.client && M.client.prefs.custom_names["deity"]) - new_deity = M.client.prefs.custom_names["deity"] - - B.deity_name = new_deity - - - switch(lowertext(new_religion)) - if("christianity") - B.name = pick("The Holy Bible","The Dead Sea Scrolls") - if("satanism") - B.name = "The Unholy Bible" - if("cthulhu") - B.name = "The Necronomicon" - if("islam") - B.name = "Quran" - if("scientology") - B.name = pick("The Biography of L. Ron Hubbard","Dianetics") - if("chaos") - B.name = "The Book of Lorgar" - if("imperium") - B.name = "Uplifting Primer" - if("toolboxia") - B.name = "Toolbox Manifesto" - if("homosexuality") - B.name = "Guys Gone Wild" - if("lol", "wtf", "gay", "penis", "ass", "poo", "badmin", "shitmin", "deadmin", "cock", "cocks", "meme", "memes") - B.name = pick("Woodys Got Wood: The Aftermath", "War of the Cocks", "Sweet Bro and Hella Jef: Expanded Edition") - H.adjustBrainLoss(100) // starts off retarded as fuck - if("science") - B.name = pick("Principle of Relativity", "Quantum Enigma: Physics Encounters Consciousness", "Programming the Universe", "Quantum Physics and Theology", "String Theory for Dummies", "How To: Build Your Own Warp Drive", "The Mysteries of Bluespace", "Playing God: Collector's Edition") - else - B.name = "The Holy Book of [new_religion]" - - SSreligion.religion = new_religion - SSreligion.bible_name = B.name - SSreligion.deity = B.deity_name - - H.equip_to_slot_or_del(B, SLOT_IN_BACKPACK) - - SSblackbox.record_feedback("text", "religion_name", 1, "[new_religion]", 1) - SSblackbox.record_feedback("text", "religion_deity", 1, "[new_deity]", 1) - -/datum/outfit/job/chaplain - name = "Chaplain" - jobtype = /datum/job/chaplain - - belt = /obj/item/pda/chaplain - uniform = /obj/item/clothing/under/rank/chaplain - backpack_contents = list(/obj/item/camera/spooky = 1) - backpack = /obj/item/storage/backpack/cultpack - satchel = /obj/item/storage/backpack/cultpack +/datum/job/chaplain + title = "Chaplain" + flag = CHAPLAIN + department_head = list("Head of Personnel") + department_flag = CIVILIAN + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the head of personnel" + selection_color = "#dddddd" + + outfit = /datum/outfit/job/chaplain + + access = list(ACCESS_MORGUE, ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_THEATRE) + minimal_access = list(ACCESS_MORGUE, ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_THEATRE) + + display_order = JOB_DISPLAY_ORDER_CHAPLAIN + + +/datum/job/chaplain/after_spawn(mob/living/H, mob/M) + . = ..() + if(H.mind) + H.mind.isholy = TRUE + + var/obj/item/storage/book/bible/booze/B = new + + if(SSreligion.religion) + B.deity_name = SSreligion.deity + B.name = SSreligion.bible_name + B.icon_state = SSreligion.bible_icon_state + B.item_state = SSreligion.bible_item_state + to_chat(H, "There is already an established religion onboard the station. You are an acolyte of [SSreligion.deity]. Defer to the Chaplain.") + H.equip_to_slot_or_del(B, SLOT_IN_BACKPACK) + var/nrt = SSreligion.holy_weapon_type || /obj/item/nullrod + var/obj/item/nullrod/N = new nrt(H) + H.put_in_hands(N) + return + + var/new_religion = DEFAULT_RELIGION + if(M.client && M.client.prefs.custom_names["religion"]) + new_religion = M.client.prefs.custom_names["religion"] + + var/new_deity = DEFAULT_DEITY + if(M.client && M.client.prefs.custom_names["deity"]) + new_deity = M.client.prefs.custom_names["deity"] + + B.deity_name = new_deity + + + switch(lowertext(new_religion)) + if("christianity") // DEFAULT_RELIGION + B.name = pick("The Holy Bible","The Dead Sea Scrolls") + if("buddhism") + B.name = "The Sutras" + if("clownism","honkmother","honk","honkism","comedy") + B.name = pick("The Holy Joke Book", "Just a Prank", "Hymns to the Honkmother") + if("chaos") + B.name = "The Book of Lorgar" + if("cthulhu") + B.name = "The Necronomicon" + if("hinduism") + B.name = "The Vedas" + if("homosexuality") + B.name = pick("Guys Gone Wild","Coming Out of The Closet") + if("imperium") + B.name = "Uplifting Primer" + if("islam") + B.name = "Quran" + if("judaism") + B.name = "The Torah" + if("lampism") + B.name = "Fluorescent Incandescence" + if("lol", "wtf", "gay", "penis", "ass", "poo", "badmin", "shitmin", "deadmin", "cock", "cocks", "meme", "memes") + B.name = pick("Woodys Got Wood: The Aftermath", "War of the Cocks", "Sweet Bro and Hella Jef: Expanded Edition","F.A.T.A.L. Rulebook") + H.adjustBrainLoss(100) // starts off retarded as fuck + if("monkeyism","apism","gorillism","primatism") + B.name = pick("Going Bananas", "Bananas Out For Harambe") + if("mormonism") + B.name = "The Book of Mormon" + if("pastafarianism") + B.name = "The Gospel of the Flying Spaghetti Monster" + if("rastafarianism","rasta") + B.name = "The Holy Piby" + if("satanism") + B.name = "The Unholy Bible" + if("science") + B.name = pick("Principle of Relativity", "Quantum Enigma: Physics Encounters Consciousness", "Programming the Universe", "Quantum Physics and Theology", "String Theory for Dummies", "How To: Build Your Own Warp Drive", "The Mysteries of Bluespace", "Playing God: Collector's Edition") + if("scientology") + B.name = pick("The Biography of L. Ron Hubbard","Dianetics") + if("servicianism", "partying") + B.name = "The Tenets of Servicia" + B.deity_name = pick("Servicia", "Space Bacchus", "Space Dionysus") + B.desc = "Happy, Full, Clean. Live it and give it." + if("subgenius") + B.name = "Book of the SubGenius" + if("toolboxia","greytide") + B.name = pick("Toolbox Manifesto","iGlove Assistants") + if("weeaboo","kawaii") + B.name = pick("Fanfiction Compendium","Japanese for Dummies","The Manganomicon","Establishing Your O.T.P") + else + B.name = "The Holy Book of [new_religion]" + + SSreligion.religion = new_religion + SSreligion.bible_name = B.name + SSreligion.deity = B.deity_name + + H.equip_to_slot_or_del(B, SLOT_IN_BACKPACK) + + SSblackbox.record_feedback("text", "religion_name", 1, "[new_religion]", 1) + SSblackbox.record_feedback("text", "religion_deity", 1, "[new_deity]", 1) + +/datum/outfit/job/chaplain + name = "Chaplain" + jobtype = /datum/job/chaplain + + belt = /obj/item/pda/chaplain + ears = /obj/item/radio/headset/headset_srv + uniform = /obj/item/clothing/under/rank/chaplain + backpack_contents = list(/obj/item/camera/spooky = 1) + backpack = /obj/item/storage/backpack/cultpack + satchel = /obj/item/storage/backpack/cultpack diff --git a/code/modules/jobs/job_types/chemist.dm b/code/modules/jobs/job_types/chemist.dm new file mode 100644 index 0000000000..908209ef69 --- /dev/null +++ b/code/modules/jobs/job_types/chemist.dm @@ -0,0 +1,36 @@ +/datum/job/chemist + title = "Chemist" + flag = CHEMIST + department_head = list("Chief Medical Officer") + department_flag = MEDSCI + faction = "Station" + total_positions = 2 + spawn_positions = 2 + supervisors = "the chief medical officer" + selection_color = "#ffeef0" + exp_type = EXP_TYPE_CREW + exp_requirements = 60 + + outfit = /datum/outfit/job/chemist + + access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_CHEMISTRY, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_CHEMIST + +/datum/outfit/job/chemist + name = "Chemist" + jobtype = /datum/job/chemist + + glasses = /obj/item/clothing/glasses/science + belt = /obj/item/pda/chemist + ears = /obj/item/radio/headset/headset_med + uniform = /obj/item/clothing/under/rank/chemist + shoes = /obj/item/clothing/shoes/sneakers/white + suit = /obj/item/clothing/suit/toggle/labcoat/chemist + backpack = /obj/item/storage/backpack/chemistry + satchel = /obj/item/storage/backpack/satchel/chem + duffelbag = /obj/item/storage/backpack/duffelbag/med + + chameleon_extras = /obj/item/gun/syringe + diff --git a/code/modules/jobs/job_types/chief_engineer.dm b/code/modules/jobs/job_types/chief_engineer.dm new file mode 100644 index 0000000000..dd89e925b5 --- /dev/null +++ b/code/modules/jobs/job_types/chief_engineer.dm @@ -0,0 +1,63 @@ +/datum/job/chief_engineer + title = "Chief Engineer" + flag = CHIEF +// auto_deadmin_role_flags = DEADMIN_POSITION_HEAD + department_head = list("Captain") + department_flag = ENGSEC + head_announce = list("Engineering") + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the captain" + selection_color = "#ffeeaa" + req_admin_notify = 1 + minimal_player_age = 7 + exp_requirements = 180 + exp_type = EXP_TYPE_CREW + exp_type_department = EXP_TYPE_ENGINEERING + + outfit = /datum/outfit/job/ce + + access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, + ACCESS_EXTERNAL_AIRLOCKS, ACCESS_ATMOSPHERICS, ACCESS_EVA, + ACCESS_HEADS, ACCESS_CONSTRUCTION, ACCESS_SEC_DOORS, ACCESS_MINISAT, + ACCESS_CE, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, + ACCESS_EXTERNAL_AIRLOCKS, ACCESS_ATMOSPHERICS, ACCESS_EVA, + ACCESS_HEADS, ACCESS_CONSTRUCTION, ACCESS_SEC_DOORS, ACCESS_MINISAT, + ACCESS_CE, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_CHIEF_ENGINEER + +/datum/outfit/job/ce + name = "Chief Engineer" + jobtype = /datum/job/chief_engineer + + id = /obj/item/card/id/silver + belt = /obj/item/storage/belt/utility/chief/full + l_pocket = /obj/item/pda/heads/ce + ears = /obj/item/radio/headset/heads/ce + uniform = /obj/item/clothing/under/rank/chief_engineer + shoes = /obj/item/clothing/shoes/sneakers/brown + head = /obj/item/clothing/head/hardhat/white + gloves = /obj/item/clothing/gloves/color/black/ce + backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced=1) + + backpack = /obj/item/storage/backpack/industrial + satchel = /obj/item/storage/backpack/satchel/eng + duffelbag = /obj/item/storage/backpack/duffelbag/engineering + box = /obj/item/storage/box/engineer + pda_slot = SLOT_L_STORE + chameleon_extras = /obj/item/stamp/ce + +/datum/outfit/job/ce/rig + name = "Chief Engineer (Hardsuit)" + + mask = /obj/item/clothing/mask/breath + suit = /obj/item/clothing/suit/space/hardsuit/engine/elite + shoes = /obj/item/clothing/shoes/magboots/advance + suit_store = /obj/item/tank/internals/oxygen + glasses = /obj/item/clothing/glasses/meson/engine + gloves = /obj/item/clothing/gloves/color/yellow + head = null + internals_slot = SLOT_S_STORE diff --git a/code/modules/jobs/job_types/chief_medical_officer.dm b/code/modules/jobs/job_types/chief_medical_officer.dm new file mode 100644 index 0000000000..54963b1bc1 --- /dev/null +++ b/code/modules/jobs/job_types/chief_medical_officer.dm @@ -0,0 +1,58 @@ +/datum/job/cmo + title = "Chief Medical Officer" + flag = CMO_JF + department_head = list("Captain") + department_flag = MEDSCI +// auto_deadmin_role_flags = DEADMIN_POSITION_HEAD + head_announce = list("Medical") + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the captain" + selection_color = "#ffddf0" + req_admin_notify = 1 + minimal_player_age = 7 + exp_requirements = 180 + exp_type = EXP_TYPE_CREW + exp_type_department = EXP_TYPE_MEDICAL + + outfit = /datum/outfit/job/cmo + + access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_HEADS, ACCESS_MINERAL_STOREROOM, + ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_CMO, ACCESS_SURGERY, ACCESS_RC_ANNOUNCE, + ACCESS_KEYCARD_AUTH, ACCESS_SEC_DOORS, ACCESS_MAINT_TUNNELS) + minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_HEADS, ACCESS_MINERAL_STOREROOM, + ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_CMO, ACCESS_SURGERY, ACCESS_RC_ANNOUNCE, + ACCESS_KEYCARD_AUTH, ACCESS_SEC_DOORS, ACCESS_MAINT_TUNNELS) + + display_order = JOB_DISPLAY_ORDER_CHIEF_MEDICAL_OFFICER + +/datum/outfit/job/cmo + name = "Chief Medical Officer" + jobtype = /datum/job/cmo + + id = /obj/item/card/id/silver + belt = /obj/item/pda/heads/cmo + l_pocket = /obj/item/pinpointer/crew + ears = /obj/item/radio/headset/heads/cmo + uniform = /obj/item/clothing/under/rank/chief_medical_officer + shoes = /obj/item/clothing/shoes/sneakers/brown + suit = /obj/item/clothing/suit/toggle/labcoat/cmo + l_hand = /obj/item/storage/firstaid/regular + suit_store = /obj/item/flashlight/pen + backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1) + + backpack = /obj/item/storage/backpack/medic + satchel = /obj/item/storage/backpack/satchel/med + duffelbag = /obj/item/storage/backpack/duffelbag/med + + chameleon_extras = list(/obj/item/gun/syringe, /obj/item/stamp/cmo) + +/datum/outfit/job/cmo/hardsuit + name = "Chief Medical Officer (Hardsuit)" + + mask = /obj/item/clothing/mask/breath + suit = /obj/item/clothing/suit/space/hardsuit/medical + suit_store = /obj/item/tank/internals/oxygen + r_pocket = /obj/item/flashlight/pen + diff --git a/code/modules/jobs/job_types/civilian.dm b/code/modules/jobs/job_types/civilian.dm deleted file mode 100644 index 944499470a..0000000000 --- a/code/modules/jobs/job_types/civilian.dm +++ /dev/null @@ -1,202 +0,0 @@ -/* -Clown -*/ -/datum/job/clown - title = "Clown" - flag = CLOWN - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the head of personnel" - selection_color = "#dddddd" - - outfit = /datum/outfit/job/clown - - access = list(ACCESS_THEATRE) - minimal_access = list(ACCESS_THEATRE) - -/datum/job/clown/after_spawn(mob/living/carbon/human/H, mob/M) - H.apply_pref_name("clown", M.client) - -/datum/outfit/job/clown - name = "Clown" - jobtype = /datum/job/clown - - belt = /obj/item/pda/clown - uniform = /obj/item/clothing/under/rank/clown - shoes = /obj/item/clothing/shoes/clown_shoes - mask = /obj/item/clothing/mask/gas/clown_hat - l_pocket = /obj/item/bikehorn - backpack_contents = list( - /obj/item/stamp/clown = 1, - /obj/item/reagent_containers/spray/waterflower = 1, - /obj/item/reagent_containers/food/snacks/grown/banana = 1, - /obj/item/instrument/bikehorn = 1, - ) - - implants = list(/obj/item/implant/sad_trombone) - - backpack = /obj/item/storage/backpack/clown - satchel = /obj/item/storage/backpack/clown - duffelbag = /obj/item/storage/backpack/duffelbag/clown //strangely has a duffel - - box = /obj/item/storage/box/hug/survival - - chameleon_extras = /obj/item/stamp/clown - - -/datum/outfit/job/clown/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - ..() - if(visualsOnly) - return - - H.fully_replace_character_name(H.real_name, pick(GLOB.clown_names)) - -/datum/outfit/job/clown/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - ..() - if(visualsOnly) - return - - H.dna.add_mutation(CLOWNMUT) - -/* -Mime -*/ -/datum/job/mime - title = "Mime" - flag = MIME - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the head of personnel" - selection_color = "#dddddd" - - outfit = /datum/outfit/job/mime - - access = list(ACCESS_THEATRE) - minimal_access = list(ACCESS_THEATRE) - -/datum/job/mime/after_spawn(mob/living/carbon/human/H, mob/M) - H.apply_pref_name("mime", M.client) - -/datum/outfit/job/mime - name = "Mime" - jobtype = /datum/job/mime - - belt = /obj/item/pda/mime - uniform = /obj/item/clothing/under/rank/mime - mask = /obj/item/clothing/mask/gas/mime - gloves = /obj/item/clothing/gloves/color/white - head = /obj/item/clothing/head/frenchberet - suit = /obj/item/clothing/suit/suspenders - backpack_contents = list(/obj/item/reagent_containers/food/drinks/bottle/bottleofnothing=1) - - accessory = /obj/item/clothing/accessory/pocketprotector/cosmetology - backpack = /obj/item/storage/backpack/mime - satchel = /obj/item/storage/backpack/mime - - -/datum/outfit/job/mime/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - ..() - - if(visualsOnly) - return - - if(H.mind) - H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/mime_wall(null)) - H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/mime/speak(null)) - H.mind.miming = 1 - -/* -Curator -*/ -/datum/job/curator - title = "Curator" - flag = CURATOR - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the head of personnel" - selection_color = "#dddddd" - - outfit = /datum/outfit/job/curator - - access = list(ACCESS_LIBRARY) - minimal_access = list(ACCESS_LIBRARY, ACCESS_CONSTRUCTION,ACCESS_MINING_STATION) - -/datum/outfit/job/curator - name = "Curator" - jobtype = /datum/job/curator - - belt = /obj/item/pda/curator - uniform = /obj/item/clothing/under/rank/curator - l_hand = /obj/item/storage/bag/books - r_pocket = /obj/item/key/displaycase - l_pocket = /obj/item/laser_pointer - accessory = /obj/item/clothing/accessory/pocketprotector/full - backpack_contents = list( - /obj/item/melee/curator_whip = 1, - /obj/item/soapstone = 1, - /obj/item/barcodescanner = 1 - ) - - -/datum/outfit/job/curator/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - ..() - - if(visualsOnly) - return - - H.grant_all_languages(omnitongue=TRUE) -/* -Lawyer -*/ -/datum/job/lawyer - title = "Lawyer" - flag = LAWYER - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 2 - spawn_positions = 2 - supervisors = "the head of personnel" - selection_color = "#dddddd" - var/lawyers = 0 //Counts lawyer amount - - outfit = /datum/outfit/job/lawyer - - access = list(ACCESS_LAWYER, ACCESS_COURT, ACCESS_SEC_DOORS) - minimal_access = list(ACCESS_LAWYER, ACCESS_COURT, ACCESS_SEC_DOORS) - -/datum/outfit/job/lawyer - name = "Lawyer" - jobtype = /datum/job/lawyer - - belt = /obj/item/pda/lawyer - ears = /obj/item/radio/headset/headset_sec - uniform = /obj/item/clothing/under/lawyer/bluesuit - suit = /obj/item/clothing/suit/toggle/lawyer - shoes = /obj/item/clothing/shoes/laceup - l_hand = /obj/item/storage/briefcase/lawyer - l_pocket = /obj/item/laser_pointer - r_pocket = /obj/item/clothing/accessory/lawyers_badge - - chameleon_extras = /obj/item/stamp/law - - -/datum/outfit/job/lawyer/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - ..() - if(visualsOnly) - return - - var/datum/job/lawyer/J = SSjob.GetJobType(jobtype) - J.lawyers++ - if(J.lawyers>1) - uniform = /obj/item/clothing/under/lawyer/purpsuit - suit = /obj/item/clothing/suit/toggle/lawyer/purple diff --git a/code/modules/jobs/job_types/clown.dm b/code/modules/jobs/job_types/clown.dm new file mode 100644 index 0000000000..d73937a604 --- /dev/null +++ b/code/modules/jobs/job_types/clown.dm @@ -0,0 +1,57 @@ +/datum/job/clown + title = "Clown" + flag = CLOWN + department_head = list("Head of Personnel") + department_flag = CIVILIAN + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the head of personnel" + selection_color = "#dddddd" + + outfit = /datum/outfit/job/clown + + access = list(ACCESS_THEATRE) + minimal_access = list(ACCESS_THEATRE) + + display_order = JOB_DISPLAY_ORDER_CLOWN + + +/datum/job/clown/after_spawn(mob/living/carbon/human/H, mob/M) + . = ..() + H.apply_pref_name("clown", M.client) + +/datum/outfit/job/clown + name = "Clown" + jobtype = /datum/job/clown + + belt = /obj/item/pda/clown + ears = /obj/item/radio/headset/headset_srv + uniform = /obj/item/clothing/under/rank/clown + shoes = /obj/item/clothing/shoes/clown_shoes + mask = /obj/item/clothing/mask/gas/clown_hat + l_pocket = /obj/item/bikehorn + backpack_contents = list( + /obj/item/stamp/clown = 1, + /obj/item/reagent_containers/spray/waterflower = 1, + /obj/item/reagent_containers/food/snacks/grown/banana = 1, + /obj/item/instrument/bikehorn = 1, + ) + + implants = list(/obj/item/implant/sad_trombone) + + backpack = /obj/item/storage/backpack/clown + satchel = /obj/item/storage/backpack/clown + duffelbag = /obj/item/storage/backpack/duffelbag/clown //strangely has a duffel + + box = /obj/item/storage/box/hug/survival + + chameleon_extras = /obj/item/stamp/clown + +/datum/outfit/job/clown/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) + ..() + if(visualsOnly) + return + + H.fully_replace_character_name(H.real_name, pick(GLOB.clown_names)) //rename the mob AFTER they're equipped so their ID gets updated properly. + H.dna.add_mutation(CLOWNMUT) diff --git a/code/modules/jobs/job_types/cook.dm b/code/modules/jobs/job_types/cook.dm new file mode 100644 index 0000000000..c213d4dffc --- /dev/null +++ b/code/modules/jobs/job_types/cook.dm @@ -0,0 +1,52 @@ +/datum/job/cook + title = "Cook" + flag = COOK + department_head = list("Head of Personnel") + department_flag = CIVILIAN + faction = "Station" + total_positions = 2 + spawn_positions = 1 + supervisors = "the head of personnel" + selection_color = "#bbe291" + var/cooks = 0 //Counts cooks amount + + outfit = /datum/outfit/job/cook + + access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_COOK + +/datum/outfit/job/cook + name = "Cook" + jobtype = /datum/job/cook + + belt = /obj/item/pda/cook + ears = /obj/item/radio/headset/headset_srv + uniform = /obj/item/clothing/under/rank/chef + suit = /obj/item/clothing/suit/toggle/chef + head = /obj/item/clothing/head/chefhat + mask = /obj/item/clothing/mask/fakemoustache/italian + backpack_contents = list(/obj/item/sharpener = 1) + +/datum/outfit/job/cook/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE) + ..() + var/datum/job/cook/J = SSjob.GetJobType(jobtype) + if(J) // Fix for runtime caused by invalid job being passed + if(J.cooks>0)//Cooks + suit = /obj/item/clothing/suit/apron/chef + head = /obj/item/clothing/head/soft/mime + if(!visualsOnly) + J.cooks++ + +/datum/outfit/job/cook/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) + ..() + if(visualsOnly) + return + var/list/possible_boxes = subtypesof(/obj/item/storage/box/ingredients) + var/chosen_box = pick(possible_boxes) + var/obj/item/storage/box/I = new chosen_box(src) + H.equip_to_slot_or_del(I,SLOT_IN_BACKPACK) + var/datum/martial_art/cqc/under_siege/justacook = new + justacook.teach(H) + diff --git a/code/modules/jobs/job_types/curator.dm b/code/modules/jobs/job_types/curator.dm new file mode 100644 index 0000000000..6199d812df --- /dev/null +++ b/code/modules/jobs/job_types/curator.dm @@ -0,0 +1,42 @@ +/datum/job/curator + title = "Curator" + flag = CURATOR + department_head = list("Head of Personnel") + department_flag = CIVILIAN + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the head of personnel" + selection_color = "#dddddd" + + outfit = /datum/outfit/job/curator + + access = list(ACCESS_LIBRARY, ACCESS_CONSTRUCTION, ACCESS_MINING_STATION) + minimal_access = list(ACCESS_LIBRARY, ACCESS_CONSTRUCTION, ACCESS_MINING_STATION) + + display_order = JOB_DISPLAY_ORDER_CURATOR + +/datum/outfit/job/curator + name = "Curator" + jobtype = /datum/job/curator + + shoes = /obj/item/clothing/shoes/laceup + belt = /obj/item/pda/curator + ears = /obj/item/radio/headset/headset_srv + uniform = /obj/item/clothing/under/rank/curator + l_hand = /obj/item/storage/bag/books + r_pocket = /obj/item/key/displaycase + l_pocket = /obj/item/laser_pointer + accessory = /obj/item/clothing/accessory/pocketprotector/full + backpack_contents = list( + /obj/item/soapstone = 1, + /obj/item/barcodescanner = 1 + ) + +/datum/outfit/job/curator/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) + ..() + + if(visualsOnly) + return + + H.grant_all_languages(omnitongue=TRUE) diff --git a/code/modules/jobs/job_types/cyborg.dm b/code/modules/jobs/job_types/cyborg.dm new file mode 100644 index 0000000000..29c4c3d833 --- /dev/null +++ b/code/modules/jobs/job_types/cyborg.dm @@ -0,0 +1,27 @@ +/datum/job/cyborg + title = "Cyborg" + flag = CYBORG +// auto_deadmin_role_flags = DEADMIN_POSITION_SILICON + department_flag = ENGSEC + faction = "Station" + total_positions = 0 + spawn_positions = 1 + supervisors = "your laws and the AI" //Nodrak + selection_color = "#ddffdd" + minimal_player_age = 21 + exp_requirements = 120 + exp_type = EXP_TYPE_CREW + + display_order = JOB_DISPLAY_ORDER_CYBORG + +/datum/job/cyborg/equip(mob/living/carbon/human/H, visualsOnly = FALSE, announce = TRUE, latejoin = FALSE, datum/outfit/outfit_override = null, client/preference_source = null) + if(visualsOnly) + CRASH("dynamic preview is unsupported") + return H.Robotize(FALSE, latejoin) + +/datum/job/cyborg/after_spawn(mob/living/silicon/robot/R, mob/M) + R.updatename(M.client) + R.gender = NEUTER + +/datum/job/cyborg/radio_help_message(mob/M) + to_chat(M, "Prefix your message with :b to speak with other cyborgs and AI.") diff --git a/code/modules/jobs/job_types/detective.dm b/code/modules/jobs/job_types/detective.dm new file mode 100644 index 0000000000..cfd9d5fdab --- /dev/null +++ b/code/modules/jobs/job_types/detective.dm @@ -0,0 +1,56 @@ +/datum/job/detective + title = "Detective" + flag = DETECTIVE +// auto_deadmin_role_flags = DEADMIN_POSITION_SECURITY + department_head = list("Head of Security") + department_flag = ENGSEC + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the head of security" + selection_color = "#ffeeee" + minimal_player_age = 7 + exp_requirements = 300 + exp_type = EXP_TYPE_CREW + + outfit = /datum/outfit/job/detective + + access = list(ACCESS_SEC_DOORS, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_COURT, ACCESS_BRIG, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_SEC_DOORS, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_COURT, ACCESS_BRIG, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) + +// mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) + + display_order = JOB_DISPLAY_ORDER_DETECTIVE + +/datum/outfit/job/detective + name = "Detective" + jobtype = /datum/job/detective + + belt = /obj/item/pda/detective + ears = /obj/item/radio/headset/headset_sec/alt + uniform = /obj/item/clothing/under/rank/det + neck = /obj/item/clothing/neck/tie/black + shoes = /obj/item/clothing/shoes/sneakers/brown + suit = /obj/item/clothing/suit/det_suit + gloves = /obj/item/clothing/gloves/color/black + head = /obj/item/clothing/head/fedora/det_hat + l_pocket = /obj/item/toy/crayon/white + r_pocket = /obj/item/lighter + backpack_contents = list(/obj/item/storage/box/evidence=1,\ + /obj/item/detective_scanner=1,\ + /obj/item/melee/classic_baton=1) + mask = /obj/item/clothing/mask/cigarette + + implants = list(/obj/item/implant/mindshield) + + chameleon_extras = list(/obj/item/gun/ballistic/revolver/detective, /obj/item/clothing/glasses/sunglasses) + +/datum/outfit/job/detective/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) + ..() + var/obj/item/clothing/mask/cigarette/cig = H.wear_mask + if(istype(cig)) //Some species specfic changes can mess this up (plasmamen) + cig.light("") + + if(visualsOnly) + return + diff --git a/code/modules/jobs/job_types/engineering.dm b/code/modules/jobs/job_types/engineering.dm deleted file mode 100644 index f28e5f1afc..0000000000 --- a/code/modules/jobs/job_types/engineering.dm +++ /dev/null @@ -1,167 +0,0 @@ -/* -Chief Engineer -*/ -/datum/job/chief_engineer - title = "Chief Engineer" - flag = CHIEF - department_head = list("Captain") - department_flag = ENGSEC - head_announce = list("Engineering") - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the captain" - selection_color = "#ffeeaa" - req_admin_notify = 1 - minimal_player_age = 7 - exp_requirements = 180 - exp_type = EXP_TYPE_CREW - exp_type_department = EXP_TYPE_ENGINEERING - - outfit = /datum/outfit/job/ce - - access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, - ACCESS_EXTERNAL_AIRLOCKS, ACCESS_ATMOSPHERICS, ACCESS_EMERGENCY_STORAGE, ACCESS_EVA, - ACCESS_HEADS, ACCESS_CONSTRUCTION, ACCESS_SEC_DOORS, ACCESS_MINISAT, - ACCESS_CE, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, - ACCESS_EXTERNAL_AIRLOCKS, ACCESS_ATMOSPHERICS, ACCESS_EMERGENCY_STORAGE, ACCESS_EVA, - ACCESS_HEADS, ACCESS_CONSTRUCTION, ACCESS_SEC_DOORS, ACCESS_MINISAT, - ACCESS_CE, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/ce - name = "Chief Engineer" - jobtype = /datum/job/chief_engineer - - id = /obj/item/card/id/silver - belt = /obj/item/storage/belt/utility/chief/full - l_pocket = /obj/item/pda/heads/ce - ears = /obj/item/radio/headset/heads/ce - uniform = /obj/item/clothing/under/rank/chief_engineer - shoes = /obj/item/clothing/shoes/sneakers/brown - head = /obj/item/clothing/head/hardhat/white - gloves = /obj/item/clothing/gloves/color/black/ce - backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced=1) - - backpack = /obj/item/storage/backpack/industrial - satchel = /obj/item/storage/backpack/satchel/eng - duffelbag = /obj/item/storage/backpack/duffelbag/engineering - box = /obj/item/storage/box/engineer - pda_slot = SLOT_L_STORE - chameleon_extras = /obj/item/stamp/ce - -/datum/outfit/job/ce/rig - name = "Chief Engineer (Hardsuit)" - - mask = /obj/item/clothing/mask/breath - suit = /obj/item/clothing/suit/space/hardsuit/engine/elite - shoes = /obj/item/clothing/shoes/magboots/advance - suit_store = /obj/item/tank/internals/oxygen - glasses = /obj/item/clothing/glasses/meson/engine - gloves = /obj/item/clothing/gloves/color/yellow - head = null - internals_slot = SLOT_S_STORE - - -/* -Station Engineer -*/ -/datum/job/engineer - title = "Station Engineer" - flag = ENGINEER - department_head = list("Chief Engineer") - department_flag = ENGSEC - faction = "Station" - total_positions = 5 - spawn_positions = 5 - supervisors = "the chief engineer" - selection_color = "#fff5cc" - exp_requirements = 60 - exp_type = EXP_TYPE_CREW - - outfit = /datum/outfit/job/engineer - - access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, - ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_ATMOSPHERICS, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, - ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/engineer - name = "Station Engineer" - jobtype = /datum/job/engineer - - belt = /obj/item/storage/belt/utility/full/engi - l_pocket = /obj/item/pda/engineering - ears = /obj/item/radio/headset/headset_eng - uniform = /obj/item/clothing/under/rank/engineer - shoes = /obj/item/clothing/shoes/workboots - head = /obj/item/clothing/head/hardhat - r_pocket = /obj/item/t_scanner - - backpack = /obj/item/storage/backpack/industrial - satchel = /obj/item/storage/backpack/satchel/eng - duffelbag = /obj/item/storage/backpack/duffelbag/engineering - box = /obj/item/storage/box/engineer - pda_slot = SLOT_L_STORE - backpack_contents = list(/obj/item/modular_computer/tablet/preset/advanced=1) - -/datum/outfit/job/engineer/gloved - name = "Station Engineer (Gloves)" - gloves = /obj/item/clothing/gloves/color/yellow - -/datum/outfit/job/engineer/gloved/rig - name = "Station Engineer (Hardsuit)" - - mask = /obj/item/clothing/mask/breath - suit = /obj/item/clothing/suit/space/hardsuit/engine - suit_store = /obj/item/tank/internals/oxygen - head = null - internals_slot = SLOT_S_STORE - - -/* -Atmospheric Technician -*/ -/datum/job/atmos - title = "Atmospheric Technician" - flag = ATMOSTECH - department_head = list("Chief Engineer") - department_flag = ENGSEC - faction = "Station" - total_positions = 3 - spawn_positions = 2 - supervisors = "the chief engineer" - selection_color = "#fff5cc" - exp_requirements = 60 - exp_type = EXP_TYPE_CREW - - outfit = /datum/outfit/job/atmos - - access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, - ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_ATMOSPHERICS, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_ATMOSPHERICS, ACCESS_MAINT_TUNNELS, ACCESS_EMERGENCY_STORAGE, ACCESS_CONSTRUCTION, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/atmos - name = "Atmospheric Technician" - jobtype = /datum/job/atmos - - belt = /obj/item/storage/belt/utility/atmostech - l_pocket = /obj/item/pda/atmos - ears = /obj/item/radio/headset/headset_eng - uniform = /obj/item/clothing/under/rank/atmospheric_technician - r_pocket = /obj/item/analyzer - - backpack = /obj/item/storage/backpack/industrial - satchel = /obj/item/storage/backpack/satchel/eng - duffelbag = /obj/item/storage/backpack/duffelbag/engineering - box = /obj/item/storage/box/engineer - pda_slot = SLOT_L_STORE - backpack_contents = list(/obj/item/modular_computer/tablet/preset/advanced=1) - -/datum/outfit/job/atmos/rig - name = "Atmospheric Technician (Hardsuit)" - - mask = /obj/item/clothing/mask/gas - suit = /obj/item/clothing/suit/space/hardsuit/engine/atmos - suit_store = /obj/item/tank/internals/oxygen - internals_slot = SLOT_S_STORE diff --git a/code/modules/jobs/job_types/geneticist.dm b/code/modules/jobs/job_types/geneticist.dm new file mode 100644 index 0000000000..6006ff1083 --- /dev/null +++ b/code/modules/jobs/job_types/geneticist.dm @@ -0,0 +1,35 @@ +/datum/job/geneticist + title = "Geneticist" + flag = GENETICIST + department_head = list("Chief Medical Officer", "Research Director") + department_flag = MEDSCI + faction = "Station" + total_positions = 2 + spawn_positions = 2 + supervisors = "the chief medical officer and research director" + selection_color = "#ffeef0" + exp_type = EXP_TYPE_CREW + exp_requirements = 60 + + outfit = /datum/outfit/job/geneticist + + access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_CHEMISTRY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_ROBOTICS, ACCESS_MINERAL_STOREROOM, ACCESS_TECH_STORAGE) + minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_GENETICIST + +/datum/outfit/job/geneticist + name = "Geneticist" + jobtype = /datum/job/geneticist + + belt = /obj/item/pda/geneticist + ears = /obj/item/radio/headset/headset_medsci + uniform = /obj/item/clothing/under/rank/geneticist + shoes = /obj/item/clothing/shoes/sneakers/white + suit = /obj/item/clothing/suit/toggle/labcoat/genetics + suit_store = /obj/item/flashlight/pen + + backpack = /obj/item/storage/backpack/genetics + satchel = /obj/item/storage/backpack/satchel/gen + duffelbag = /obj/item/storage/backpack/duffelbag/med + diff --git a/code/modules/jobs/job_types/head_of_personnel.dm b/code/modules/jobs/job_types/head_of_personnel.dm new file mode 100644 index 0000000000..a5d917e1c9 --- /dev/null +++ b/code/modules/jobs/job_types/head_of_personnel.dm @@ -0,0 +1,49 @@ +/datum/job/hop + title = "Head of Personnel" + flag = HOP +// auto_deadmin_role_flags = DEADMIN_POSITION_HEAD + department_head = list("Captain") + department_flag = CIVILIAN + head_announce = list("Supply", "Service") + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the captain" + selection_color = "#ddddff" + req_admin_notify = 1 + minimal_player_age = 10 + exp_requirements = 180 + exp_type = EXP_TYPE_CREW + exp_type_department = EXP_TYPE_SUPPLY + + outfit = /datum/outfit/job/hop + + access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_COURT, ACCESS_WEAPONS, + ACCESS_MEDICAL, ACCESS_ENGINE, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_EVA, ACCESS_HEADS, + ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_MAINT_TUNNELS, ACCESS_BAR, ACCESS_JANITOR, ACCESS_CONSTRUCTION, ACCESS_MORGUE, + ACCESS_CREMATORIUM, ACCESS_KITCHEN, ACCESS_CARGO, ACCESS_MAILSORTING, ACCESS_QM, ACCESS_HYDROPONICS, ACCESS_LAWYER, + ACCESS_THEATRE, ACCESS_CHAPEL_OFFICE, ACCESS_LIBRARY, ACCESS_RESEARCH, ACCESS_MINING, ACCESS_VAULT, ACCESS_MINING_STATION, + ACCESS_HOP, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_COURT, ACCESS_WEAPONS, + ACCESS_MEDICAL, ACCESS_ENGINE, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_EVA, ACCESS_HEADS, + ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_MAINT_TUNNELS, ACCESS_BAR, ACCESS_JANITOR, ACCESS_CONSTRUCTION, ACCESS_MORGUE, + ACCESS_CREMATORIUM, ACCESS_KITCHEN, ACCESS_CARGO, ACCESS_MAILSORTING, ACCESS_QM, ACCESS_HYDROPONICS, ACCESS_LAWYER, + ACCESS_THEATRE, ACCESS_CHAPEL_OFFICE, ACCESS_LIBRARY, ACCESS_RESEARCH, ACCESS_MINING, ACCESS_VAULT, ACCESS_MINING_STATION, + ACCESS_HOP, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_HEAD_OF_PERSONNEL + +/datum/outfit/job/hop + name = "Head of Personnel" + jobtype = /datum/job/hop + + id = /obj/item/card/id/silver + belt = /obj/item/pda/heads/hop + ears = /obj/item/radio/headset/heads/hop + uniform = /obj/item/clothing/under/rank/head_of_personnel + shoes = /obj/item/clothing/shoes/sneakers/brown + head = /obj/item/clothing/head/hopcap + backpack_contents = list(/obj/item/storage/box/ids=1,\ + /obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced = 1) + + chameleon_extras = list(/obj/item/gun/energy/e_gun, /obj/item/stamp/hop) diff --git a/code/modules/jobs/job_types/head_of_security.dm b/code/modules/jobs/job_types/head_of_security.dm new file mode 100644 index 0000000000..9df087c834 --- /dev/null +++ b/code/modules/jobs/job_types/head_of_security.dm @@ -0,0 +1,67 @@ +/datum/job/hos + title = "Head of Security" + flag = HOS +// auto_deadmin_role_flags = DEADMIN_POSITION_HEAD|DEADMIN_POSITION_SECURITY + department_head = list("Captain") + department_flag = ENGSEC + head_announce = list("Security") + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the captain" + selection_color = "#ffdddd" + req_admin_notify = 1 + minimal_player_age = 14 + exp_requirements = 300 + exp_type = EXP_TYPE_CREW + exp_type_department = EXP_TYPE_SECURITY + + outfit = /datum/outfit/job/hos +// mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) + + access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, + ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_ALL_PERSONAL_LOCKERS, + ACCESS_RESEARCH, ACCESS_ENGINE, ACCESS_MINING, ACCESS_MEDICAL, ACCESS_CONSTRUCTION, ACCESS_MAILSORTING, + ACCESS_HEADS, ACCESS_HOS, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, + ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_ALL_PERSONAL_LOCKERS, + ACCESS_RESEARCH, ACCESS_ENGINE, ACCESS_MINING, ACCESS_MEDICAL, ACCESS_CONSTRUCTION, ACCESS_MAILSORTING, + ACCESS_HEADS, ACCESS_HOS, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_HEAD_OF_SECURITY + +/datum/outfit/job/hos + name = "Head of Security" + jobtype = /datum/job/hos + + id = /obj/item/card/id/silver + belt = /obj/item/pda/heads/hos + ears = /obj/item/radio/headset/heads/hos/alt + uniform = /obj/item/clothing/under/rank/head_of_security + shoes = /obj/item/clothing/shoes/jackboots + suit = /obj/item/clothing/suit/armor/hos/trenchcoat + gloves = /obj/item/clothing/gloves/color/black/hos + head = /obj/item/clothing/head/HoS/beret + glasses = /obj/item/clothing/glasses/hud/security/sunglasses + suit_store = /obj/item/gun/energy/e_gun + r_pocket = /obj/item/assembly/flash/handheld + l_pocket = /obj/item/restraints/handcuffs + backpack_contents = list(/obj/item/melee/baton/loaded=1) + + backpack = /obj/item/storage/backpack/security + satchel = /obj/item/storage/backpack/satchel/sec + duffelbag = /obj/item/storage/backpack/duffelbag/sec + box = /obj/item/storage/box/security + + implants = list(/obj/item/implant/mindshield) + + chameleon_extras = list(/obj/item/gun/energy/e_gun/hos, /obj/item/stamp/hos) + +/datum/outfit/job/hos/hardsuit + name = "Head of Security (Hardsuit)" + + mask = /obj/item/clothing/mask/gas/sechailer + suit = /obj/item/clothing/suit/space/hardsuit/security/hos + suit_store = /obj/item/tank/internals/oxygen + backpack_contents = list(/obj/item/melee/baton/loaded=1, /obj/item/gun/energy/e_gun=1) + diff --git a/code/modules/jobs/job_types/janitor.dm b/code/modules/jobs/job_types/janitor.dm new file mode 100644 index 0000000000..d0a06ca0e0 --- /dev/null +++ b/code/modules/jobs/job_types/janitor.dm @@ -0,0 +1,27 @@ +/datum/job/janitor + title = "Janitor" + flag = JANITOR + department_head = list("Head of Personnel") + department_flag = CIVILIAN + faction = "Station" + total_positions = 2 + spawn_positions = 1 + supervisors = "the head of personnel" + selection_color = "#bbe291" + var/global/janitors = 0 + + outfit = /datum/outfit/job/janitor + + access = list(ACCESS_JANITOR, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_JANITOR, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_JANITOR + +/datum/outfit/job/janitor + name = "Janitor" + jobtype = /datum/job/janitor + + belt = /obj/item/pda/janitor + ears = /obj/item/radio/headset/headset_srv + uniform = /obj/item/clothing/under/rank/janitor + backpack_contents = list(/obj/item/modular_computer/tablet/preset/advanced=1) diff --git a/code/modules/jobs/job_types/lawyer.dm b/code/modules/jobs/job_types/lawyer.dm new file mode 100644 index 0000000000..a04f5b665c --- /dev/null +++ b/code/modules/jobs/job_types/lawyer.dm @@ -0,0 +1,47 @@ +/datum/job/lawyer + title = "Lawyer" + flag = LAWYER + department_head = list("Head of Personnel") + department_flag = CIVILIAN + faction = "Station" + total_positions = 2 + spawn_positions = 2 + supervisors = "the head of personnel" + selection_color = "#dddddd" + var/lawyers = 0 //Counts lawyer amount + + outfit = /datum/outfit/job/lawyer + + access = list(ACCESS_LAWYER, ACCESS_COURT, ACCESS_SEC_DOORS) + minimal_access = list(ACCESS_LAWYER, ACCESS_COURT, ACCESS_SEC_DOORS) + +// mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) + + display_order = JOB_DISPLAY_ORDER_LAWYER + +/datum/outfit/job/lawyer + name = "Lawyer" + jobtype = /datum/job/lawyer + + belt = /obj/item/pda/lawyer + ears = /obj/item/radio/headset/headset_sec + uniform = /obj/item/clothing/under/lawyer/bluesuit + suit = /obj/item/clothing/suit/toggle/lawyer + shoes = /obj/item/clothing/shoes/laceup + l_hand = /obj/item/storage/briefcase/lawyer + l_pocket = /obj/item/laser_pointer + r_pocket = /obj/item/clothing/accessory/lawyers_badge + + chameleon_extras = /obj/item/stamp/law + + +/datum/outfit/job/lawyer/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE) + ..() + if(visualsOnly) + return + + var/datum/job/lawyer/J = SSjob.GetJobType(jobtype) + J.lawyers++ + if(J.lawyers>1) + uniform = /obj/item/clothing/under/lawyer/purpsuit + suit = /obj/item/clothing/suit/toggle/lawyer/purple diff --git a/code/modules/jobs/job_types/medical.dm b/code/modules/jobs/job_types/medical.dm deleted file mode 100644 index 5a926f490a..0000000000 --- a/code/modules/jobs/job_types/medical.dm +++ /dev/null @@ -1,204 +0,0 @@ -/* -Chief Medical Officer -*/ -/datum/job/cmo - title = "Chief Medical Officer" - flag = CMO_JF - department_head = list("Captain") - department_flag = MEDSCI - head_announce = list("Medical") - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the captain" - selection_color = "#ffddf0" - req_admin_notify = 1 - minimal_player_age = 7 - exp_requirements = 180 - exp_type = EXP_TYPE_CREW - exp_type_department = EXP_TYPE_MEDICAL - - outfit = /datum/outfit/job/cmo - - access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_HEADS, ACCESS_MINERAL_STOREROOM, - ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_CMO, ACCESS_SURGERY, ACCESS_RC_ANNOUNCE, - ACCESS_KEYCARD_AUTH, ACCESS_SEC_DOORS, ACCESS_MAINT_TUNNELS) - minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_HEADS, ACCESS_MINERAL_STOREROOM, - ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_CMO, ACCESS_SURGERY, ACCESS_RC_ANNOUNCE, - ACCESS_KEYCARD_AUTH, ACCESS_SEC_DOORS, ACCESS_MAINT_TUNNELS) - -/datum/outfit/job/cmo - name = "Chief Medical Officer" - jobtype = /datum/job/cmo - - id = /obj/item/card/id/silver - belt = /obj/item/pda/heads/cmo - l_pocket = /obj/item/pinpointer/crew - ears = /obj/item/radio/headset/heads/cmo - uniform = /obj/item/clothing/under/rank/chief_medical_officer - shoes = /obj/item/clothing/shoes/sneakers/brown - suit = /obj/item/clothing/suit/toggle/labcoat/cmo - l_hand = /obj/item/storage/firstaid/regular - suit_store = /obj/item/flashlight/pen - backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1) - - backpack = /obj/item/storage/backpack/medic - satchel = /obj/item/storage/backpack/satchel/med - duffelbag = /obj/item/storage/backpack/duffelbag/med - - chameleon_extras = list(/obj/item/gun/syringe, /obj/item/stamp/cmo) - -/datum/outfit/job/cmo/hardsuit - name = "Chief Medical Officer (Hardsuit)" - - mask = /obj/item/clothing/mask/breath - suit = /obj/item/clothing/suit/space/hardsuit/medical - suit_store = /obj/item/tank/internals/oxygen - r_pocket = /obj/item/flashlight/pen - -/* -Medical Doctor -*/ -/datum/job/doctor - title = "Medical Doctor" - flag = DOCTOR - department_head = list("Chief Medical Officer") - department_flag = MEDSCI - faction = "Station" - total_positions = 5 - spawn_positions = 3 - supervisors = "the chief medical officer" - selection_color = "#ffeef0" - - outfit = /datum/outfit/job/doctor - - access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/doctor - name = "Medical Doctor" - jobtype = /datum/job/doctor - - belt = /obj/item/pda/medical - ears = /obj/item/radio/headset/headset_med - uniform = /obj/item/clothing/under/rank/medical - shoes = /obj/item/clothing/shoes/sneakers/white - suit = /obj/item/clothing/suit/toggle/labcoat - l_hand = /obj/item/storage/firstaid/regular - suit_store = /obj/item/flashlight/pen - - backpack = /obj/item/storage/backpack/medic - satchel = /obj/item/storage/backpack/satchel/med - duffelbag = /obj/item/storage/backpack/duffelbag/med - - chameleon_extras = /obj/item/gun/syringe - -/* -Chemist -*/ -/datum/job/chemist - title = "Chemist" - flag = CHEMIST - department_head = list("Chief Medical Officer") - department_flag = MEDSCI - faction = "Station" - total_positions = 2 - spawn_positions = 2 - supervisors = "the chief medical officer" - selection_color = "#ffeef0" - exp_type = EXP_TYPE_CREW - exp_requirements = 60 - - outfit = /datum/outfit/job/chemist - - access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_MEDICAL, ACCESS_CHEMISTRY, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/chemist - name = "Chemist" - jobtype = /datum/job/chemist - - glasses = /obj/item/clothing/glasses/science - belt = /obj/item/pda/chemist - ears = /obj/item/radio/headset/headset_med - uniform = /obj/item/clothing/under/rank/chemist - shoes = /obj/item/clothing/shoes/sneakers/white - suit = /obj/item/clothing/suit/toggle/labcoat/chemist - backpack = /obj/item/storage/backpack/chemistry - satchel = /obj/item/storage/backpack/satchel/chem - duffelbag = /obj/item/storage/backpack/duffelbag/med - - chameleon_extras = /obj/item/gun/syringe - -/* -Geneticist -*/ -/datum/job/geneticist - title = "Geneticist" - flag = GENETICIST - department_head = list("Chief Medical Officer", "Research Director") - department_flag = MEDSCI - faction = "Station" - total_positions = 2 - spawn_positions = 2 - supervisors = "the chief medical officer and research director" - selection_color = "#ffeef0" - exp_type = EXP_TYPE_CREW - exp_requirements = 60 - - outfit = /datum/outfit/job/geneticist - - access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_CHEMISTRY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_ROBOTICS, ACCESS_MINERAL_STOREROOM, ACCESS_TECH_STORAGE) - minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/geneticist - name = "Geneticist" - jobtype = /datum/job/geneticist - - belt = /obj/item/pda/geneticist - ears = /obj/item/radio/headset/headset_medsci - uniform = /obj/item/clothing/under/rank/geneticist - shoes = /obj/item/clothing/shoes/sneakers/white - suit = /obj/item/clothing/suit/toggle/labcoat/genetics - suit_store = /obj/item/flashlight/pen - - backpack = /obj/item/storage/backpack/genetics - satchel = /obj/item/storage/backpack/satchel/gen - duffelbag = /obj/item/storage/backpack/duffelbag/med - -/* -Virologist -*/ -/datum/job/virologist - title = "Virologist" - flag = VIROLOGIST - department_head = list("Chief Medical Officer") - department_flag = MEDSCI - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the chief medical officer" - selection_color = "#ffeef0" - exp_type = EXP_TYPE_CREW - exp_requirements = 60 - - outfit = /datum/outfit/job/virologist - - access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_MEDICAL, ACCESS_VIROLOGY, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/virologist - name = "Virologist" - jobtype = /datum/job/virologist - - belt = /obj/item/pda/viro - ears = /obj/item/radio/headset/headset_med - uniform = /obj/item/clothing/under/rank/virologist - mask = /obj/item/clothing/mask/surgical - shoes = /obj/item/clothing/shoes/sneakers/white - suit = /obj/item/clothing/suit/toggle/labcoat/virologist - suit_store = /obj/item/flashlight/pen - - backpack = /obj/item/storage/backpack/virology - satchel = /obj/item/storage/backpack/satchel/vir - duffelbag = /obj/item/storage/backpack/duffelbag/med diff --git a/code/modules/jobs/job_types/medical_doctor.dm b/code/modules/jobs/job_types/medical_doctor.dm new file mode 100644 index 0000000000..e3379e4be1 --- /dev/null +++ b/code/modules/jobs/job_types/medical_doctor.dm @@ -0,0 +1,35 @@ +/datum/job/doctor + title = "Medical Doctor" + flag = DOCTOR + department_head = list("Chief Medical Officer") + department_flag = MEDSCI + faction = "Station" + total_positions = 5 + spawn_positions = 3 + supervisors = "the chief medical officer" + selection_color = "#ffeef0" + + outfit = /datum/outfit/job/doctor + + access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_VIROLOGY, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_MEDICAL_DOCTOR + +/datum/outfit/job/doctor + name = "Medical Doctor" + jobtype = /datum/job/doctor + + belt = /obj/item/pda/medical + ears = /obj/item/radio/headset/headset_med + uniform = /obj/item/clothing/under/rank/medical + shoes = /obj/item/clothing/shoes/sneakers/white + suit = /obj/item/clothing/suit/toggle/labcoat + l_hand = /obj/item/storage/firstaid/regular + suit_store = /obj/item/flashlight/pen + + backpack = /obj/item/storage/backpack/medic + satchel = /obj/item/storage/backpack/satchel/med + duffelbag = /obj/item/storage/backpack/duffelbag/med + + chameleon_extras = /obj/item/gun/syringe diff --git a/code/modules/jobs/job_types/mime.dm b/code/modules/jobs/job_types/mime.dm new file mode 100644 index 0000000000..1347da7125 --- /dev/null +++ b/code/modules/jobs/job_types/mime.dm @@ -0,0 +1,49 @@ +/datum/job/mime + title = "Mime" + flag = MIME + department_head = list("Head of Personnel") + department_flag = CIVILIAN + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the head of personnel" + selection_color = "#dddddd" + + outfit = /datum/outfit/job/mime + + access = list(ACCESS_THEATRE) + minimal_access = list(ACCESS_THEATRE) + + display_order = JOB_DISPLAY_ORDER_MIME + +/datum/job/mime/after_spawn(mob/living/carbon/human/H, mob/M) + H.apply_pref_name("mime", M.client) + +/datum/outfit/job/mime + name = "Mime" + jobtype = /datum/job/mime + + belt = /obj/item/pda/mime + ears = /obj/item/radio/headset/headset_srv + uniform = /obj/item/clothing/under/rank/mime + mask = /obj/item/clothing/mask/gas/mime + gloves = /obj/item/clothing/gloves/color/white + head = /obj/item/clothing/head/frenchberet + suit = /obj/item/clothing/suit/suspenders + backpack_contents = list(/obj/item/reagent_containers/food/drinks/bottle/bottleofnothing=1) + + backpack = /obj/item/storage/backpack/mime + satchel = /obj/item/storage/backpack/mime + + +/datum/outfit/job/mime/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) + ..() + + if(visualsOnly) + return + + if(H.mind) + H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/mime_wall(null)) + H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/mime/speak(null)) + H.mind.miming = 1 + diff --git a/code/modules/jobs/job_types/quartermaster.dm b/code/modules/jobs/job_types/quartermaster.dm new file mode 100644 index 0000000000..3220dd9a09 --- /dev/null +++ b/code/modules/jobs/job_types/quartermaster.dm @@ -0,0 +1,32 @@ +/datum/job/qm + title = "Quartermaster" + flag = QUARTERMASTER + department_head = list("Captain") + department_flag = CIVILIAN +// auto_deadmin_role_flags = DEADMIN_POSITION_HEAD + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the captain" + selection_color = "#d7b088" + + outfit = /datum/outfit/job/quartermaster + + access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM, ACCESS_VAULT) + minimal_access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM, ACCESS_VAULT) + + display_order = JOB_DISPLAY_ORDER_QUARTERMASTER + +/datum/outfit/job/quartermaster + name = "Quartermaster" + jobtype = /datum/job/qm + + belt = /obj/item/pda/quartermaster + ears = /obj/item/radio/headset/headset_cargo + uniform = /obj/item/clothing/under/rank/cargo + shoes = /obj/item/clothing/shoes/sneakers/brown + glasses = /obj/item/clothing/glasses/sunglasses + l_hand = /obj/item/clipboard + + chameleon_extras = /obj/item/stamp/qm + diff --git a/code/modules/jobs/job_types/research_director.dm b/code/modules/jobs/job_types/research_director.dm new file mode 100644 index 0000000000..2df606bd20 --- /dev/null +++ b/code/modules/jobs/job_types/research_director.dm @@ -0,0 +1,60 @@ +/datum/job/rd + title = "Research Director" + flag = RD_JF +// auto_deadmin_role_flags = DEADMIN_POSITION_HEAD + department_head = list("Captain") + department_flag = MEDSCI + head_announce = list("Science") + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the captain" + selection_color = "#ffddff" + req_admin_notify = 1 + minimal_player_age = 7 + exp_type_department = EXP_TYPE_SCIENCE + exp_requirements = 180 + exp_type = EXP_TYPE_CREW + + outfit = /datum/outfit/job/rd + + access = list(ACCESS_RD, ACCESS_HEADS, ACCESS_TOX, ACCESS_GENETICS, ACCESS_MORGUE, + ACCESS_TOX_STORAGE, ACCESS_TELEPORTER, ACCESS_SEC_DOORS, + ACCESS_RESEARCH, ACCESS_ROBOTICS, ACCESS_XENOBIOLOGY, ACCESS_AI_UPLOAD, + ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM, + ACCESS_TECH_STORAGE, ACCESS_MINISAT, ACCESS_MAINT_TUNNELS, ACCESS_NETWORK) + minimal_access = list(ACCESS_RD, ACCESS_HEADS, ACCESS_TOX, ACCESS_GENETICS, ACCESS_MORGUE, + ACCESS_TOX_STORAGE, ACCESS_TELEPORTER, ACCESS_SEC_DOORS, + ACCESS_RESEARCH, ACCESS_ROBOTICS, ACCESS_XENOBIOLOGY, ACCESS_AI_UPLOAD, + ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM, + ACCESS_TECH_STORAGE, ACCESS_MINISAT, ACCESS_MAINT_TUNNELS, ACCESS_NETWORK) + + display_order = JOB_DISPLAY_ORDER_RESEARCH_DIRECTOR + +/datum/outfit/job/rd + name = "Research Director" + jobtype = /datum/job/rd + + id = /obj/item/card/id/silver + belt = /obj/item/pda/heads/rd + ears = /obj/item/radio/headset/heads/rd + uniform = /obj/item/clothing/under/rank/research_director + shoes = /obj/item/clothing/shoes/sneakers/brown + suit = /obj/item/clothing/suit/toggle/labcoat + l_hand = /obj/item/clipboard + l_pocket = /obj/item/laser_pointer + backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced=1) + + backpack = /obj/item/storage/backpack/science + satchel = /obj/item/storage/backpack/satchel/tox + + chameleon_extras = /obj/item/stamp/rd + +/datum/outfit/job/rd/rig + name = "Research Director (Hardsuit)" + + l_hand = null + mask = /obj/item/clothing/mask/breath + suit = /obj/item/clothing/suit/space/hardsuit/rd + suit_store = /obj/item/tank/internals/oxygen + internals_slot = SLOT_S_STORE diff --git a/code/modules/jobs/job_types/roboticist.dm b/code/modules/jobs/job_types/roboticist.dm new file mode 100644 index 0000000000..ef3c1277a1 --- /dev/null +++ b/code/modules/jobs/job_types/roboticist.dm @@ -0,0 +1,34 @@ +/datum/job/roboticist + title = "Roboticist" + flag = ROBOTICIST + department_head = list("Research Director") + department_flag = MEDSCI + faction = "Station" + total_positions = 2 + spawn_positions = 2 + supervisors = "the research director" + selection_color = "#ffeeff" + exp_requirements = 60 + exp_type = EXP_TYPE_CREW + + outfit = /datum/outfit/job/roboticist + + access = list(ACCESS_ROBOTICS, ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM, ACCESS_XENOBIOLOGY, ACCESS_GENETICS) + minimal_access = list(ACCESS_ROBOTICS, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_ROBOTICIST + +/datum/outfit/job/roboticist + name = "Roboticist" + jobtype = /datum/job/roboticist + + belt = /obj/item/storage/belt/utility/full + l_pocket = /obj/item/pda/roboticist + ears = /obj/item/radio/headset/headset_sci + uniform = /obj/item/clothing/under/rank/roboticist + suit = /obj/item/clothing/suit/toggle/labcoat + + backpack = /obj/item/storage/backpack/science + satchel = /obj/item/storage/backpack/satchel/tox + + pda_slot = SLOT_L_STORE diff --git a/code/modules/jobs/job_types/science.dm b/code/modules/jobs/job_types/science.dm deleted file mode 100644 index 6a14f204a3..0000000000 --- a/code/modules/jobs/job_types/science.dm +++ /dev/null @@ -1,131 +0,0 @@ -/* -Research Director -*/ -/datum/job/rd - title = "Research Director" - flag = RD_JF - department_head = list("Captain") - department_flag = MEDSCI - head_announce = list("Science") - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the captain" - selection_color = "#ffddff" - req_admin_notify = 1 - minimal_player_age = 7 - exp_type_department = EXP_TYPE_SCIENCE - exp_requirements = 180 - exp_type = EXP_TYPE_CREW - - outfit = /datum/outfit/job/rd - - access = list(ACCESS_RD, ACCESS_HEADS, ACCESS_TOX, ACCESS_GENETICS, ACCESS_MORGUE, - ACCESS_TOX_STORAGE, ACCESS_TELEPORTER, ACCESS_SEC_DOORS, - ACCESS_RESEARCH, ACCESS_ROBOTICS, ACCESS_XENOBIOLOGY, ACCESS_AI_UPLOAD, - ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM, - ACCESS_TECH_STORAGE, ACCESS_MINISAT, ACCESS_MAINT_TUNNELS, ACCESS_NETWORK) - minimal_access = list(ACCESS_RD, ACCESS_HEADS, ACCESS_TOX, ACCESS_GENETICS, ACCESS_MORGUE, - ACCESS_TOX_STORAGE, ACCESS_TELEPORTER, ACCESS_SEC_DOORS, - ACCESS_RESEARCH, ACCESS_ROBOTICS, ACCESS_XENOBIOLOGY, ACCESS_AI_UPLOAD, - ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM, - ACCESS_TECH_STORAGE, ACCESS_MINISAT, ACCESS_MAINT_TUNNELS, ACCESS_NETWORK) - -/datum/outfit/job/rd - name = "Research Director" - jobtype = /datum/job/rd - - id = /obj/item/card/id/silver - belt = /obj/item/pda/heads/rd - ears = /obj/item/radio/headset/heads/rd - uniform = /obj/item/clothing/under/rank/research_director - shoes = /obj/item/clothing/shoes/sneakers/brown - suit = /obj/item/clothing/suit/toggle/labcoat - l_hand = /obj/item/clipboard - l_pocket = /obj/item/laser_pointer - backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced=1) - - backpack = /obj/item/storage/backpack/science - satchel = /obj/item/storage/backpack/satchel/tox - - chameleon_extras = /obj/item/stamp/rd - -/datum/outfit/job/rd/rig - name = "Research Director (Hardsuit)" - - l_hand = null - mask = /obj/item/clothing/mask/breath - suit = /obj/item/clothing/suit/space/hardsuit/rd - suit_store = /obj/item/tank/internals/oxygen - internals_slot = SLOT_S_STORE - -/* -Scientist -*/ -/datum/job/scientist - title = "Scientist" - flag = SCIENTIST - department_head = list("Research Director") - department_flag = MEDSCI - faction = "Station" - total_positions = 5 - spawn_positions = 3 - supervisors = "the research director" - selection_color = "#ffeeff" - exp_requirements = 60 - exp_type = EXP_TYPE_CREW - - - outfit = /datum/outfit/job/scientist - - access = list(ACCESS_ROBOTICS, ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_MINERAL_STOREROOM, ACCESS_TECH_STORAGE, ACCESS_GENETICS) - minimal_access = list(ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/scientist - name = "Scientist" - jobtype = /datum/job/scientist - - belt = /obj/item/pda/toxins - ears = /obj/item/radio/headset/headset_sci - uniform = /obj/item/clothing/under/rank/scientist - shoes = /obj/item/clothing/shoes/sneakers/white - suit = /obj/item/clothing/suit/toggle/labcoat/science - - backpack = /obj/item/storage/backpack/science - satchel = /obj/item/storage/backpack/satchel/tox - -/* -Roboticist -*/ -/datum/job/roboticist - title = "Roboticist" - flag = ROBOTICIST - department_head = list("Research Director") - department_flag = MEDSCI - faction = "Station" - total_positions = 2 - spawn_positions = 2 - supervisors = "the research director" - selection_color = "#ffeeff" - exp_requirements = 60 - exp_type = EXP_TYPE_CREW - - outfit = /datum/outfit/job/roboticist - - access = list(ACCESS_ROBOTICS, ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM, ACCESS_XENOBIOLOGY, ACCESS_GENETICS) - minimal_access = list(ACCESS_ROBOTICS, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/roboticist - name = "Roboticist" - jobtype = /datum/job/roboticist - - belt = /obj/item/storage/belt/utility/full - l_pocket = /obj/item/pda/roboticist - ears = /obj/item/radio/headset/headset_sci - uniform = /obj/item/clothing/under/rank/roboticist - suit = /obj/item/clothing/suit/toggle/labcoat - - backpack = /obj/item/storage/backpack/science - satchel = /obj/item/storage/backpack/satchel/tox - - pda_slot = SLOT_L_STORE diff --git a/code/modules/jobs/job_types/scientist.dm b/code/modules/jobs/job_types/scientist.dm new file mode 100644 index 0000000000..e3f04f0b29 --- /dev/null +++ b/code/modules/jobs/job_types/scientist.dm @@ -0,0 +1,33 @@ +/datum/job/scientist + title = "Scientist" + flag = SCIENTIST + department_head = list("Research Director") + department_flag = MEDSCI + faction = "Station" + total_positions = 5 + spawn_positions = 3 + supervisors = "the research director" + selection_color = "#ffeeff" + exp_requirements = 60 + exp_type = EXP_TYPE_CREW + + outfit = /datum/outfit/job/scientist + + access = list(ACCESS_ROBOTICS, ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_MINERAL_STOREROOM, ACCESS_TECH_STORAGE, ACCESS_GENETICS) + minimal_access = list(ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_SCIENTIST + +/datum/outfit/job/scientist + name = "Scientist" + jobtype = /datum/job/scientist + + belt = /obj/item/pda/toxins + ears = /obj/item/radio/headset/headset_sci + uniform = /obj/item/clothing/under/rank/scientist + shoes = /obj/item/clothing/shoes/sneakers/white + suit = /obj/item/clothing/suit/toggle/labcoat/science + + backpack = /obj/item/storage/backpack/science + satchel = /obj/item/storage/backpack/satchel/tox + diff --git a/code/modules/jobs/job_types/security.dm b/code/modules/jobs/job_types/security.dm deleted file mode 100644 index e7e0922f62..0000000000 --- a/code/modules/jobs/job_types/security.dm +++ /dev/null @@ -1,334 +0,0 @@ -//Warden and regular officers add this result to their get_access() -/datum/job/proc/check_config_for_sec_maint() - if(CONFIG_GET(flag/security_has_maint_access)) - return list(ACCESS_MAINT_TUNNELS) - return list() - -/* -Head of Security -*/ -/datum/job/hos - title = "Head of Security" - flag = HOS - department_head = list("Captain") - department_flag = ENGSEC - head_announce = list("Security") - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the captain" - selection_color = "#ffdddd" - req_admin_notify = 1 - minimal_player_age = 14 - exp_requirements = 300 - exp_type = EXP_TYPE_CREW - exp_type_department = EXP_TYPE_SECURITY - - outfit = /datum/outfit/job/hos - - access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, - ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_ALL_PERSONAL_LOCKERS, - ACCESS_RESEARCH, ACCESS_ENGINE, ACCESS_MINING, ACCESS_MEDICAL, ACCESS_CONSTRUCTION, ACCESS_MAILSORTING, - ACCESS_HEADS, ACCESS_HOS, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, - ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_ALL_PERSONAL_LOCKERS, - ACCESS_RESEARCH, ACCESS_ENGINE, ACCESS_MINING, ACCESS_MEDICAL, ACCESS_CONSTRUCTION, ACCESS_MAILSORTING, - ACCESS_HEADS, ACCESS_HOS, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/hos - name = "Head of Security" - jobtype = /datum/job/hos - - id = /obj/item/card/id/silver - belt = /obj/item/pda/heads/hos - ears = /obj/item/radio/headset/heads/hos/alt - uniform = /obj/item/clothing/under/rank/head_of_security - shoes = /obj/item/clothing/shoes/jackboots - suit = /obj/item/clothing/suit/armor/hos/trenchcoat - gloves = /obj/item/clothing/gloves/color/black/hos - head = /obj/item/clothing/head/HoS/beret - glasses = /obj/item/clothing/glasses/hud/security/sunglasses - suit_store = /obj/item/gun/energy/e_gun - r_pocket = /obj/item/assembly/flash/handheld - l_pocket = /obj/item/restraints/handcuffs - backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1) - - backpack = /obj/item/storage/backpack/security - satchel = /obj/item/storage/backpack/satchel/sec - duffelbag = /obj/item/storage/backpack/duffelbag/sec - box = /obj/item/storage/box/security - - implants = list(/obj/item/implant/mindshield) - - chameleon_extras = list(/obj/item/gun/energy/e_gun/hos, /obj/item/stamp/hos) - -/datum/outfit/job/hos/hardsuit - name = "Head of Security (Hardsuit)" - - mask = /obj/item/clothing/mask/gas/sechailer - suit = /obj/item/clothing/suit/space/hardsuit/security/hos - suit_store = /obj/item/tank/internals/oxygen - backpack_contents = list(/obj/item/melee/baton/loaded=1, /obj/item/gun/energy/e_gun=1) - -/* -Warden -*/ -/datum/job/warden - title = "Warden" - flag = WARDEN - department_head = list("Head of Security") - department_flag = ENGSEC - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the head of security" - selection_color = "#ffeeee" - minimal_player_age = 7 - exp_requirements = 300 - exp_type = EXP_TYPE_CREW - - outfit = /datum/outfit/job/warden - - access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_FORENSICS_LOCKERS, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) //SEE /DATUM/JOB/WARDEN/GET_ACCESS() - -/datum/job/warden/get_access() - var/list/L = list() - L = ..() | check_config_for_sec_maint() - return L - -/datum/outfit/job/warden - name = "Warden" - jobtype = /datum/job/warden - - belt = /obj/item/pda/warden - ears = /obj/item/radio/headset/headset_sec/alt - uniform = /obj/item/clothing/under/rank/warden - shoes = /obj/item/clothing/shoes/jackboots - suit = /obj/item/clothing/suit/armor/vest/warden/alt - gloves = /obj/item/clothing/gloves/color/black - head = /obj/item/clothing/head/warden - glasses = /obj/item/clothing/glasses/hud/security/sunglasses - r_pocket = /obj/item/assembly/flash/handheld - l_pocket = /obj/item/restraints/handcuffs - suit_store = /obj/item/gun/energy/e_gun/advtaser - backpack_contents = list(/obj/item/melee/baton/loaded=1) - - backpack = /obj/item/storage/backpack/security - satchel = /obj/item/storage/backpack/satchel/sec - duffelbag = /obj/item/storage/backpack/duffelbag/sec - box = /obj/item/storage/box/security - - implants = list(/obj/item/implant/mindshield) - - chameleon_extras = /obj/item/gun/ballistic/shotgun/automatic/combat/compact - -/* -Detective -*/ -/datum/job/detective - title = "Detective" - flag = DETECTIVE - department_head = list("Head of Security") - department_flag = ENGSEC - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the head of security" - selection_color = "#ffeeee" - minimal_player_age = 7 - exp_requirements = 300 - exp_type = EXP_TYPE_CREW - - outfit = /datum/outfit/job/detective - - access = list(ACCESS_SEC_DOORS, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_COURT, ACCESS_BRIG, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_SEC_DOORS, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_COURT, ACCESS_BRIG, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) - -/datum/outfit/job/detective - name = "Detective" - jobtype = /datum/job/detective - - belt = /obj/item/pda/detective - ears = /obj/item/radio/headset/headset_sec/alt - uniform = /obj/item/clothing/under/rank/det - shoes = /obj/item/clothing/shoes/sneakers/brown - suit = /obj/item/clothing/suit/det_suit - gloves = /obj/item/clothing/gloves/color/black - head = /obj/item/clothing/head/fedora/det_hat - l_pocket = /obj/item/toy/crayon/white - r_pocket = /obj/item/lighter - backpack_contents = list(/obj/item/storage/box/evidence=1,\ - /obj/item/detective_scanner=1,\ - /obj/item/melee/classic_baton=1) - mask = /obj/item/clothing/mask/cigarette - - implants = list(/obj/item/implant/mindshield) - - chameleon_extras = list(/obj/item/gun/ballistic/revolver/detective, /obj/item/clothing/glasses/sunglasses) - -/datum/outfit/job/detective/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - ..() - var/obj/item/clothing/mask/cigarette/cig = H.wear_mask - if(istype(cig)) //Some species specfic changes can mess this up (plasmamen) - cig.light("") - - if(visualsOnly) - return - -/* -Security Officer -*/ -/datum/job/officer - title = "Security Officer" - flag = OFFICER - department_head = list("Head of Security") - department_flag = ENGSEC - faction = "Station" - total_positions = 5 //Handled in /datum/controller/occupations/proc/setup_officer_positions() - spawn_positions = 5 //Handled in /datum/controller/occupations/proc/setup_officer_positions() - supervisors = "the head of security, and the head of your assigned department (if applicable)" - selection_color = "#ffeeee" - minimal_player_age = 7 - exp_requirements = 300 - exp_type = EXP_TYPE_CREW - - outfit = /datum/outfit/job/security - - access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_FORENSICS_LOCKERS, ACCESS_MINERAL_STOREROOM) - minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) //BUT SEE /DATUM/JOB/WARDEN/GET_ACCESS() - - -/datum/job/officer/get_access() - var/list/L = list() - L |= ..() | check_config_for_sec_maint() - return L - -GLOBAL_LIST_INIT(available_depts, list(SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, SEC_DEPT_SCIENCE, SEC_DEPT_SUPPLY)) - -/datum/job/officer/after_spawn(mob/living/carbon/human/H, mob/M) - // Assign department security - var/department - if(M && M.client && M.client.prefs) - department = M.client.prefs.prefered_security_department - if(!LAZYLEN(GLOB.available_depts) || department == "None") - return - else if(department in GLOB.available_depts) - LAZYREMOVE(GLOB.available_depts, department) - else - department = pick_n_take(GLOB.available_depts) - var/ears = null - var/accessory = null - var/list/dep_access = null - var/destination = null - var/spawn_point = null - switch(department) - if(SEC_DEPT_SUPPLY) - ears = /obj/item/radio/headset/headset_sec/alt/department/supply - dep_access = list(ACCESS_MAILSORTING, ACCESS_MINING, ACCESS_MINING_STATION) - destination = /area/security/checkpoint/supply - spawn_point = locate(/obj/effect/landmark/start/depsec/supply) in GLOB.department_security_spawns - accessory = /obj/item/clothing/accessory/armband/cargo - if(SEC_DEPT_ENGINEERING) - ears = /obj/item/radio/headset/headset_sec/alt/department/engi - dep_access = list(ACCESS_CONSTRUCTION, ACCESS_ENGINE) - destination = /area/security/checkpoint/engineering - spawn_point = locate(/obj/effect/landmark/start/depsec/engineering) in GLOB.department_security_spawns - accessory = /obj/item/clothing/accessory/armband/engine - if(SEC_DEPT_MEDICAL) - ears = /obj/item/radio/headset/headset_sec/alt/department/med - dep_access = list(ACCESS_MEDICAL) - destination = /area/security/checkpoint/medical - spawn_point = locate(/obj/effect/landmark/start/depsec/medical) in GLOB.department_security_spawns - accessory = /obj/item/clothing/accessory/armband/medblue - if(SEC_DEPT_SCIENCE) - ears = /obj/item/radio/headset/headset_sec/alt/department/sci - dep_access = list(ACCESS_RESEARCH) - destination = /area/security/checkpoint/science - spawn_point = locate(/obj/effect/landmark/start/depsec/science) in GLOB.department_security_spawns - accessory = /obj/item/clothing/accessory/armband/science - - if(accessory) - var/obj/item/clothing/under/U = H.w_uniform - U.attach_accessory(new accessory) - if(ears) - if(H.ears) - qdel(H.ears) - H.equip_to_slot_or_del(new ears(H),SLOT_EARS) - - var/obj/item/card/id/W = H.wear_id - W.access |= dep_access - - var/teleport = 0 - if(!CONFIG_GET(flag/sec_start_brig)) - if(destination || spawn_point) - teleport = 1 - if(teleport) - var/turf/T - if(spawn_point) - T = get_turf(spawn_point) - H.Move(T) - else - var/safety = 0 - while(safety < 25) - T = safepick(get_area_turfs(destination)) - if(T && !H.Move(T)) - safety += 1 - continue - else - break - if(department) - to_chat(M, "You have been assigned to [department]!") - else - to_chat(M, "You have not been assigned to any department. Patrol the halls and help where needed.") - - - -/datum/outfit/job/security - name = "Security Officer" - jobtype = /datum/job/officer - - belt = /obj/item/pda/security - ears = /obj/item/radio/headset/headset_sec/alt - uniform = /obj/item/clothing/under/rank/security - gloves = /obj/item/clothing/gloves/color/black - head = /obj/item/clothing/head/helmet/sec - suit = /obj/item/clothing/suit/armor/vest/alt - shoes = /obj/item/clothing/shoes/jackboots - l_pocket = /obj/item/restraints/handcuffs - r_pocket = /obj/item/assembly/flash/handheld - suit_store = /obj/item/gun/energy/e_gun/advtaser - backpack_contents = list(/obj/item/melee/baton/loaded=1) - - backpack = /obj/item/storage/backpack/security - satchel = /obj/item/storage/backpack/satchel/sec - duffelbag = /obj/item/storage/backpack/duffelbag/sec - box = /obj/item/storage/box/security - - implants = list(/obj/item/implant/mindshield) - - chameleon_extras = list(/obj/item/gun/energy/e_gun/advtaser, /obj/item/clothing/glasses/hud/security/sunglasses, /obj/item/clothing/head/helmet) - //The helmet is necessary because /obj/item/clothing/head/helmet/sec is overwritten in the chameleon list by the standard helmet, which has the same name and icon state - - -/obj/item/radio/headset/headset_sec/alt/department/Initialize() - . = ..() - wires = new/datum/wires/radio(src) - secure_radio_connections = new - recalculateChannels() - -/obj/item/radio/headset/headset_sec/alt/department/engi - keyslot = new /obj/item/encryptionkey/headset_sec - keyslot2 = new /obj/item/encryptionkey/headset_eng - -/obj/item/radio/headset/headset_sec/alt/department/supply - keyslot = new /obj/item/encryptionkey/headset_sec - keyslot2 = new /obj/item/encryptionkey/headset_cargo - -/obj/item/radio/headset/headset_sec/alt/department/med - keyslot = new /obj/item/encryptionkey/headset_sec - keyslot2 = new /obj/item/encryptionkey/headset_med - -/obj/item/radio/headset/headset_sec/alt/department/sci - keyslot = new /obj/item/encryptionkey/headset_sec - keyslot2 = new /obj/item/encryptionkey/headset_sci diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm new file mode 100644 index 0000000000..98ec759db8 --- /dev/null +++ b/code/modules/jobs/job_types/security_officer.dm @@ -0,0 +1,158 @@ +/datum/job/officer + title = "Security Officer" + flag = OFFICER +// auto_deadmin_role_flags = DEADMIN_POSITION_SECURITY + department_head = list("Head of Security") + department_flag = ENGSEC + faction = "Station" + total_positions = 5 //Handled in /datum/controller/occupations/proc/setup_officer_positions() + spawn_positions = 5 //Handled in /datum/controller/occupations/proc/setup_officer_positions() + supervisors = "the head of security, and the head of your assigned department (if applicable)" + selection_color = "#ffeeee" + minimal_player_age = 7 + exp_requirements = 300 + exp_type = EXP_TYPE_CREW + + outfit = /datum/outfit/job/security + + access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_FORENSICS_LOCKERS, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) // See /datum/job/officer/get_access() + +// mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) + + display_order = JOB_DISPLAY_ORDER_SECURITY_OFFICER + +/datum/job/officer/get_access() + var/list/L = list() + L |= ..() | check_config_for_sec_maint() + return L + +GLOBAL_LIST_INIT(available_depts, list(SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, SEC_DEPT_SCIENCE, SEC_DEPT_SUPPLY)) + +/datum/job/officer/after_spawn(mob/living/carbon/human/H, mob/M) + . = ..() + // Assign department security + var/department + if(M && M.client && M.client.prefs) + department = M.client.prefs.prefered_security_department + if(!LAZYLEN(GLOB.available_depts) || department == "None") + return + else if(department in GLOB.available_depts) + LAZYREMOVE(GLOB.available_depts, department) + else + department = pick_n_take(GLOB.available_depts) + var/ears = null + var/accessory = null + var/list/dep_access = null + var/destination = null + var/spawn_point = null + switch(department) + if(SEC_DEPT_SUPPLY) + ears = /obj/item/radio/headset/headset_sec/alt/department/supply + dep_access = list(ACCESS_MAILSORTING, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_CARGO) + destination = /area/security/checkpoint/supply + spawn_point = locate(/obj/effect/landmark/start/depsec/supply) in GLOB.department_security_spawns + accessory = /obj/item/clothing/accessory/armband/cargo + if(SEC_DEPT_ENGINEERING) + ears = /obj/item/radio/headset/headset_sec/alt/department/engi + dep_access = list(ACCESS_CONSTRUCTION, ACCESS_ENGINE, ACCESS_ATMOSPHERICS) + destination = /area/security/checkpoint/engineering + spawn_point = locate(/obj/effect/landmark/start/depsec/engineering) in GLOB.department_security_spawns + accessory = /obj/item/clothing/accessory/armband/engine + if(SEC_DEPT_MEDICAL) + ears = /obj/item/radio/headset/headset_sec/alt/department/med + dep_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CLONING) + destination = /area/security/checkpoint/medical + spawn_point = locate(/obj/effect/landmark/start/depsec/medical) in GLOB.department_security_spawns + accessory = /obj/item/clothing/accessory/armband/medblue + if(SEC_DEPT_SCIENCE) + ears = /obj/item/radio/headset/headset_sec/alt/department/sci + dep_access = list(ACCESS_RESEARCH, ACCESS_TOX) + destination = /area/security/checkpoint/science + spawn_point = locate(/obj/effect/landmark/start/depsec/science) in GLOB.department_security_spawns + accessory = /obj/item/clothing/accessory/armband/science + + if(accessory) + var/obj/item/clothing/under/U = H.w_uniform + U.attach_accessory(new accessory) + if(ears) + if(H.ears) + qdel(H.ears) + H.equip_to_slot_or_del(new ears(H),SLOT_EARS) + + var/obj/item/card/id/W = H.wear_id + W.access |= dep_access + + var/teleport = 0 + if(!CONFIG_GET(flag/sec_start_brig)) + if(destination || spawn_point) + teleport = 1 + if(teleport) + var/turf/T + if(spawn_point) + T = get_turf(spawn_point) + H.Move(T) + else + var/safety = 0 + while(safety < 25) + T = safepick(get_area_turfs(destination)) + if(T && !H.Move(T)) + safety += 1 + continue + else + break + if(department) + to_chat(M, "You have been assigned to [department]!") + else + to_chat(M, "You have not been assigned to any department. Patrol the halls and help where needed.") + + + +/datum/outfit/job/security + name = "Security Officer" + jobtype = /datum/job/officer + + belt = /obj/item/pda/security + ears = /obj/item/radio/headset/headset_sec/alt + uniform = /obj/item/clothing/under/rank/security + gloves = /obj/item/clothing/gloves/color/black + head = /obj/item/clothing/head/helmet/sec + suit = /obj/item/clothing/suit/armor/vest/alt + shoes = /obj/item/clothing/shoes/jackboots + l_pocket = /obj/item/restraints/handcuffs + r_pocket = /obj/item/assembly/flash/handheld + suit_store = /obj/item/gun/energy/disabler + backpack_contents = list(/obj/item/melee/baton/loaded=1) + + backpack = /obj/item/storage/backpack/security + satchel = /obj/item/storage/backpack/satchel/sec + duffelbag = /obj/item/storage/backpack/duffelbag/sec + box = /obj/item/storage/box/security + + implants = list(/obj/item/implant/mindshield) + + chameleon_extras = list(/obj/item/gun/energy/disabler, /obj/item/clothing/glasses/hud/security/sunglasses, /obj/item/clothing/head/helmet) + //The helmet is necessary because /obj/item/clothing/head/helmet/sec is overwritten in the chameleon list by the standard helmet, which has the same name and icon state + + +/obj/item/radio/headset/headset_sec/alt/department/Initialize() + . = ..() + wires = new/datum/wires/radio(src) + secure_radio_connections = new + recalculateChannels() + +/obj/item/radio/headset/headset_sec/alt/department/engi + keyslot = new /obj/item/encryptionkey/headset_sec + keyslot2 = new /obj/item/encryptionkey/headset_eng + +/obj/item/radio/headset/headset_sec/alt/department/supply + keyslot = new /obj/item/encryptionkey/headset_sec + keyslot2 = new /obj/item/encryptionkey/headset_cargo + +/obj/item/radio/headset/headset_sec/alt/department/med + keyslot = new /obj/item/encryptionkey/headset_sec + keyslot2 = new /obj/item/encryptionkey/headset_med + +/obj/item/radio/headset/headset_sec/alt/department/sci + keyslot = new /obj/item/encryptionkey/headset_sec + keyslot2 = new /obj/item/encryptionkey/headset_sci diff --git a/code/modules/jobs/job_types/shaft_miner.dm b/code/modules/jobs/job_types/shaft_miner.dm new file mode 100644 index 0000000000..59d29954fd --- /dev/null +++ b/code/modules/jobs/job_types/shaft_miner.dm @@ -0,0 +1,70 @@ +/datum/job/mining + title = "Shaft Miner" + flag = MINER + department_head = list("Quartermaster") + department_flag = CIVILIAN + faction = "Station" + total_positions = 3 + spawn_positions = 3 + supervisors = "the quartermaster" + selection_color = "#dcba97" + + outfit = /datum/outfit/job/miner + + access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MAILSORTING, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_SHAFT_MINER + +/datum/outfit/job/miner + name = "Shaft Miner" + jobtype = /datum/job/mining + + belt = /obj/item/pda/shaftminer + ears = /obj/item/radio/headset/headset_cargo/mining + shoes = /obj/item/clothing/shoes/workboots/mining + gloves = /obj/item/clothing/gloves/color/black + uniform = /obj/item/clothing/under/rank/miner/lavaland + l_pocket = /obj/item/reagent_containers/hypospray/medipen/survival + r_pocket = /obj/item/storage/bag/ore //causes issues if spawned in backpack + backpack_contents = list( + /obj/item/flashlight/seclite=1,\ + /obj/item/kitchen/knife/combat/survival=1,\ + /obj/item/mining_voucher=1,\ + /obj/item/stack/marker_beacon/ten=1) + + backpack = /obj/item/storage/backpack/explorer + satchel = /obj/item/storage/backpack/satchel/explorer + duffelbag = /obj/item/storage/backpack/duffelbag + box = /obj/item/storage/box/survival_mining + + chameleon_extras = /obj/item/gun/energy/kinetic_accelerator + +/datum/outfit/job/miner/equipped + name = "Shaft Miner (Equipment)" + suit = /obj/item/clothing/suit/hooded/explorer + mask = /obj/item/clothing/mask/gas/explorer + glasses = /obj/item/clothing/glasses/meson + suit_store = /obj/item/tank/internals/oxygen + internals_slot = SLOT_S_STORE + backpack_contents = list( + /obj/item/flashlight/seclite=1,\ + /obj/item/kitchen/knife/combat/survival=1, + /obj/item/mining_voucher=1, + /obj/item/t_scanner/adv_mining_scanner/lesser=1, + /obj/item/gun/energy/kinetic_accelerator=1,\ + /obj/item/stack/marker_beacon/ten=1) + +/datum/outfit/job/miner/equipped/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) + ..() + if(visualsOnly) + return + if(istype(H.wear_suit, /obj/item/clothing/suit/hooded)) + var/obj/item/clothing/suit/hooded/S = H.wear_suit + S.ToggleHood() + +/datum/outfit/job/miner/equipped/hardsuit + name = "Shaft Miner (Equipment + Hardsuit)" + suit = /obj/item/clothing/suit/space/hardsuit/mining + mask = /obj/item/clothing/mask/breath + diff --git a/code/modules/jobs/job_types/station_engineer.dm b/code/modules/jobs/job_types/station_engineer.dm new file mode 100644 index 0000000000..4a2a2c7fd2 --- /dev/null +++ b/code/modules/jobs/job_types/station_engineer.dm @@ -0,0 +1,54 @@ +/datum/job/engineer + title = "Station Engineer" + flag = ENGINEER + department_head = list("Chief Engineer") + department_flag = ENGSEC + faction = "Station" + total_positions = 5 + spawn_positions = 5 + supervisors = "the chief engineer" + selection_color = "#fff5cc" + exp_requirements = 60 + exp_type = EXP_TYPE_CREW + + outfit = /datum/outfit/job/engineer + + access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, + ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_ATMOSPHERICS, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, + ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_STATION_ENGINEER + +/datum/outfit/job/engineer + name = "Station Engineer" + jobtype = /datum/job/engineer + + belt = /obj/item/storage/belt/utility/full/engi + l_pocket = /obj/item/pda/engineering + ears = /obj/item/radio/headset/headset_eng + uniform = /obj/item/clothing/under/rank/engineer + shoes = /obj/item/clothing/shoes/workboots + head = /obj/item/clothing/head/hardhat + r_pocket = /obj/item/t_scanner + + backpack = /obj/item/storage/backpack/industrial + satchel = /obj/item/storage/backpack/satchel/eng + duffelbag = /obj/item/storage/backpack/duffelbag/engineering + box = /obj/item/storage/box/engineer + pda_slot = SLOT_L_STORE + backpack_contents = list(/obj/item/modular_computer/tablet/preset/advanced=1) + +/datum/outfit/job/engineer/gloved + name = "Station Engineer (Gloves)" + gloves = /obj/item/clothing/gloves/color/yellow + +/datum/outfit/job/engineer/gloved/rig + name = "Station Engineer (Hardsuit)" + mask = /obj/item/clothing/mask/breath + suit = /obj/item/clothing/suit/space/hardsuit/engine + suit_store = /obj/item/tank/internals/oxygen + head = null + internals_slot = SLOT_S_STORE + + diff --git a/code/modules/jobs/job_types/virologist.dm b/code/modules/jobs/job_types/virologist.dm new file mode 100644 index 0000000000..26f38e594b --- /dev/null +++ b/code/modules/jobs/job_types/virologist.dm @@ -0,0 +1,35 @@ +/datum/job/virologist + title = "Virologist" + flag = VIROLOGIST + department_head = list("Chief Medical Officer") + department_flag = MEDSCI + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the chief medical officer" + selection_color = "#ffeef0" + exp_type = EXP_TYPE_CREW + exp_requirements = 60 + + outfit = /datum/outfit/job/virologist + + access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_MEDICAL, ACCESS_VIROLOGY, ACCESS_MINERAL_STOREROOM) + + display_order = JOB_DISPLAY_ORDER_VIROLOGIST + +/datum/outfit/job/virologist + name = "Virologist" + jobtype = /datum/job/virologist + + belt = /obj/item/pda/viro + ears = /obj/item/radio/headset/headset_med + uniform = /obj/item/clothing/under/rank/virologist + mask = /obj/item/clothing/mask/surgical + shoes = /obj/item/clothing/shoes/sneakers/white + suit = /obj/item/clothing/suit/toggle/labcoat/virologist + suit_store = /obj/item/flashlight/pen + + backpack = /obj/item/storage/backpack/virology + satchel = /obj/item/storage/backpack/satchel/vir + duffelbag = /obj/item/storage/backpack/duffelbag/med diff --git a/code/modules/jobs/job_types/warden.dm b/code/modules/jobs/job_types/warden.dm new file mode 100644 index 0000000000..b70281f099 --- /dev/null +++ b/code/modules/jobs/job_types/warden.dm @@ -0,0 +1,55 @@ +/datum/job/warden + title = "Warden" + flag = WARDEN +// auto_deadmin_role_flags = DEADMIN_POSITION_SECURITY + department_head = list("Head of Security") + department_flag = ENGSEC + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "the head of security" + selection_color = "#ffeeee" + minimal_player_age = 7 + exp_requirements = 300 + exp_type = EXP_TYPE_CREW + + outfit = /datum/outfit/job/warden + + access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_FORENSICS_LOCKERS, ACCESS_MINERAL_STOREROOM) + minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) // See /datum/job/warden/get_access() + +// mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) + + display_order = JOB_DISPLAY_ORDER_WARDEN + +/datum/job/warden/get_access() + var/list/L = list() + L = ..() | check_config_for_sec_maint() + return L + +/datum/outfit/job/warden + name = "Warden" + jobtype = /datum/job/warden + + belt = /obj/item/pda/warden + ears = /obj/item/radio/headset/headset_sec/alt + uniform = /obj/item/clothing/under/rank/warden + shoes = /obj/item/clothing/shoes/jackboots + suit = /obj/item/clothing/suit/armor/vest/warden/alt + gloves = /obj/item/clothing/gloves/color/black + head = /obj/item/clothing/head/warden + glasses = /obj/item/clothing/glasses/hud/security/sunglasses + r_pocket = /obj/item/assembly/flash/handheld + l_pocket = /obj/item/restraints/handcuffs + suit_store = /obj/item/gun/energy/disabler + backpack_contents = list(/obj/item/melee/baton/loaded=1) + + backpack = /obj/item/storage/backpack/security + satchel = /obj/item/storage/backpack/satchel/sec + duffelbag = /obj/item/storage/backpack/duffelbag/sec + box = /obj/item/storage/box/security + + implants = list(/obj/item/implant/mindshield) + + chameleon_extras = /obj/item/gun/ballistic/shotgun/automatic/combat/compact + diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index 84be6438c0..9bd37cf171 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -13,8 +13,12 @@ canmove = FALSE anchored = TRUE // don't get pushed around + var/mob/living/new_character //for instant transfer once the round is set up + //Used to make sure someone doesn't get spammed with messages if they're ineligible for roles + var/ineligible_for_roles = FALSE + /mob/dead/new_player/Initialize() if(client && SSticker.state == GAME_STATE_STARTUP) var/obj/screen/splash/S = new(client, TRUE, TRUE) @@ -33,8 +37,7 @@ return /mob/dead/new_player/proc/new_player_panel() - var/output = "

Welcome, [client ? client.prefs.real_name : "Unknown User"]

" - output += "

Setup Character

" + var/output = "

Setup Character

" if(SSticker.current_state <= GAME_STATE_PREGAME) switch(ready) @@ -75,7 +78,7 @@ var/datum/browser/popup = new(src, "playersetup", "
New Player Options
", 250, 265) popup.set_window_options("can_close=0") popup.set_content(output) - popup.open(0) + popup.open(FALSE) /mob/dead/new_player/Topic(href, href_list[]) if(src != usr) @@ -429,8 +432,7 @@ /mob/dead/new_player/proc/LateChoices() - var/dat = "
Round Duration: [DisplayTimeText(world.time - SSticker.round_start_time)]
" - + var/list/dat = list("
Round Duration: [DisplayTimeText(world.time - SSticker.round_start_time)]
") if(SSshuttle.emergency) switch(SSshuttle.emergency.mode) if(SHUTTLE_ESCAPE) @@ -438,57 +440,49 @@ if(SHUTTLE_CALL) if(!SSshuttle.canRecall()) dat += "
The station is currently undergoing evacuation procedures.

" + for(var/datum/job/prioritized_job in SSjob.prioritized_jobs) + if(prioritized_job.current_positions >= prioritized_job.total_positions) + SSjob.prioritized_jobs -= prioritized_job + dat += "
" + var/column_counter = 0 + for(var/list/category in list(GLOB.command_positions) + list(GLOB.engineering_positions) + list(GLOB.supply_positions) + list(GLOB.nonhuman_positions - "pAI") + list(GLOB.civilian_positions) + list(GLOB.medical_positions) + list(GLOB.science_positions) + list(GLOB.security_positions)) + var/cat_color = SSjob.name_occupations[category[1]].selection_color //use the color of the first job in the category (the department head) as the category color + dat += "
" + dat += "[SSjob.name_occupations[category[1]].exp_type_department]" + var/list/dept_dat = list() + for(var/job in category) + var/datum/job/job_datum = SSjob.name_occupations[job] + if(job_datum && IsJobUnavailable(job_datum.title, TRUE) == JOB_AVAILABLE) + var/command_bold = "" + if(job in GLOB.command_positions) + command_bold = " command" + if(job_datum in SSjob.prioritized_jobs) + dept_dat += "[job_datum.title] ([job_datum.current_positions])" + else + dept_dat += "[job_datum.title] ([job_datum.current_positions])" + if(!dept_dat.len) + dept_dat += "No positions open." + dat += jointext(dept_dat, "") + dat += "

" + column_counter++ + if(column_counter > 0 && (column_counter % 3 == 0)) + dat += "
" + dat += "
" + dat += "" - var/available_job_count = 0 - for(var/datum/job/job in SSjob.occupations) - if(job && IsJobUnavailable(job.title, TRUE) == JOB_AVAILABLE) - available_job_count++ + var/available_ghosts = 0 for(var/spawner in GLOB.mob_spawners) - available_job_count++ + available_ghosts++ break - if(!available_job_count) - dat += "
There are currently no open positions!
" - + if(!available_ghosts) + dat += "
There are currently no open ghost spawners.
" else - dat += "
Choose from the following open positions:

" - var/list/categorizedJobs = list( - "Command" = list(jobs = list(), titles = GLOB.command_positions, color = "#aac1ee"), - "Engineering" = list(jobs = list(), titles = GLOB.engineering_positions, color = "#ffd699"), - "Supply" = list(jobs = list(), titles = GLOB.supply_positions, color = "#ead4ae"), - "Miscellaneous" = list(jobs = list(), titles = list(), color = "#ffffff", colBreak = TRUE), - "Ghost Role" = list(jobs = list(), titles = GLOB.mob_spawners, color = "#ffffff"), - "Synthetic" = list(jobs = list(), titles = GLOB.nonhuman_positions, color = "#ccffcc"), - "Service" = list(jobs = list(), titles = GLOB.civilian_positions, color = "#cccccc"), - "Medical" = list(jobs = list(), titles = GLOB.medical_positions, color = "#99ffe6", colBreak = TRUE), - "Science" = list(jobs = list(), titles = GLOB.science_positions, color = "#e6b3e6"), - "Security" = list(jobs = list(), titles = GLOB.security_positions, color = "#ff9999"), - ) + dat += "
Currently open Ghost roles:

" + var/list/categorizedJobs = list("Ghost Role" = list(jobs = list(), titles = GLOB.mob_spawners, color = "#ffffff")) for(var/spawner in GLOB.mob_spawners) categorizedJobs["Ghost Role"]["jobs"] += spawner - for(var/datum/job/job in SSjob.occupations) - if(job && IsJobUnavailable(job.title, TRUE) == JOB_AVAILABLE) - var/categorized = FALSE - for(var/jobcat in categorizedJobs) - var/list/jobs = categorizedJobs[jobcat]["jobs"] - if(job.title in categorizedJobs[jobcat]["titles"]) - categorized = TRUE - if(jobcat == "Command") - - if(job.title == "Captain") // Put captain at top of command jobs - jobs.Insert(1, job) - else - jobs += job - else // Put heads at top of non-command jobs - if(job.title in GLOB.command_positions) - jobs.Insert(1, job) - else - jobs += job - if(!categorized) - categorizedJobs["Miscellaneous"]["jobs"] += job - - dat += "
" for(var/jobcat in categorizedJobs) if(categorizedJobs[jobcat]["colBreak"]) @@ -498,16 +492,6 @@ var/color = categorizedJobs[jobcat]["color"] dat += "
" dat += "[jobcat]" - for(var/datum/job/job in categorizedJobs[jobcat]["jobs"]) - var/position_class = "otherPosition" - if(job.title in GLOB.command_positions) - position_class = "commandPosition" - if(job in SSjob.prioritized_jobs) - dat += "[job.title] ([job.current_positions])" - else - dat += "[job.title] ([job.current_positions])" - categorizedJobs[jobcat]["jobs"] -= job - for(var/spawner in categorizedJobs[jobcat]["jobs"]) dat += "[spawner]" @@ -515,16 +499,11 @@ dat += "
" dat += "" - // Removing the old window method but leaving it here for reference - //src << browse(dat, "window=latechoices;size=300x640;can_close=1") - - // Added the new browser window method var/datum/browser/popup = new(src, "latechoices", "Choose Profession", 680, 580) popup.add_stylesheet("playeroptions", 'html/browser/playeroptions.css') - popup.set_content(dat) + popup.set_content(jointext(dat, "")) popup.open(FALSE) // FALSE is passed to open so that it doesn't use the onclose() proc - /mob/dead/new_player/proc/create_character(transfer_after) spawning = 1 close_spawn_windows() @@ -533,7 +512,7 @@ var/frn = CONFIG_GET(flag/force_random_names) if(!frn) - frn = jobban_isbanned(src, "appearance") + frn = jobban_isbanned(src, "Appearance") if(QDELETED(src)) return if(frn) @@ -580,3 +559,31 @@ src << browse(null, "window=preferences") //closes job selection src << browse(null, "window=mob_occupation") src << browse(null, "window=latechoices") //closes late job selection + +/* Used to make sure that a player has a valid job preference setup, used to knock players out of eligibility for anything if their prefs don't make sense. + A "valid job preference setup" in this situation means at least having one job set to low, or not having "return to lobby" enabled + Prevents "antag rolling" by setting antag prefs on, all jobs to never, and "return to lobby if preferences not availible" + Doing so would previously allow you to roll for antag, then send you back to lobby if you didn't get an antag role + This also does some admin notification and logging as well, as well as some extra logic to make sure things don't go wrong +*/ + +/mob/dead/new_player/proc/check_preferences() + if(!client) + return FALSE //Not sure how this would get run without the mob having a client, but let's just be safe. + if(client.prefs.joblessrole != RETURNTOLOBBY) + return TRUE + // If they have antags enabled, they're potentially doing this on purpose instead of by accident. Notify admins if so. + var/has_antags = FALSE + if(client.prefs.be_special.len > 0) + has_antags = TRUE + if(client.prefs.job_preferences.len == 0) + if(!ineligible_for_roles) + to_chat(src, "You have no jobs enabled, along with return to lobby if job is unavailable. This makes you ineligible for any round start role, please update your job preferences.") + ineligible_for_roles = TRUE + ready = PLAYER_NOT_READY + if(has_antags) + log_admin("[src.ckey] just got booted back to lobby with no jobs, but antags enabled.") + message_admins("[src.ckey] just got booted back to lobby with no jobs enabled, but antag rolling enabled. Likely antag rolling abuse.") + + return FALSE //This is the only case someone should actually be completely blocked from antag rolling as well + return TRUE \ No newline at end of file diff --git a/code/modules/mob/dead/new_player/preferences_setup.dm b/code/modules/mob/dead/new_player/preferences_setup.dm index 353df3aa66..e15ef482a4 100644 --- a/code/modules/mob/dead/new_player/preferences_setup.dm +++ b/code/modules/mob/dead/new_player/preferences_setup.dm @@ -21,50 +21,35 @@ age = rand(AGE_MIN,AGE_MAX) /datum/preferences/proc/update_preview_icon() - // Silicons only need a very basic preview since there is no customization for them. -// var/wide_icon = FALSE //CITDEL THINGS -// if(features["taur"] != "None") -// wide_icon = TRUE - if(job_engsec_high) - switch(job_engsec_high) - if(AI_JF) - parent.show_character_previews(image('icons/mob/ai.dmi', resolve_ai_icon(preferred_ai_core_display), dir = SOUTH)) - return - if(CYBORG) - parent.show_character_previews(image('icons/mob/robots.dmi', icon_state = "robot", dir = SOUTH)) - return + // Determine what job is marked as 'High' priority, and dress them up as such. + var/datum/job/previewJob + var/highest_pref = 0 + for(var/job in job_preferences) + if(job_preferences[job] > highest_pref) + previewJob = SSjob.GetJob(job) + highest_pref = job_preferences[job] + + if(previewJob) + // Silicons only need a very basic preview since there is no customization for them. + if(istype(previewJob,/datum/job/ai)) + parent.show_character_previews(image('icons/mob/ai.dmi', icon_state = resolve_ai_icon(preferred_ai_core_display), dir = SOUTH)) + return + if(istype(previewJob,/datum/job/cyborg)) + parent.show_character_previews(image('icons/mob/robots.dmi', icon_state = "robot", dir = SOUTH)) + return // Set up the dummy for its photoshoot var/mob/living/carbon/human/dummy/mannequin = generate_or_wait_for_human_dummy(DUMMY_HUMAN_SLOT_PREFERENCES) mannequin.cut_overlays() + // Apply the Dummy's preview background first so we properly layer everything else on top of it. mannequin.add_overlay(mutable_appearance('modular_citadel/icons/ui/backgrounds.dmi', bgstate, layer = SPACE_LAYER)) copy_to(mannequin) - // Determine what job is marked as 'High' priority, and dress them up as such. - var/datum/job/previewJob - var/highRankFlag = job_civilian_high | job_medsci_high | job_engsec_high - - if(job_civilian_low & ASSISTANT) - previewJob = SSjob.GetJob("Assistant") - else if(highRankFlag) - var/highDeptFlag - if(job_civilian_high) - highDeptFlag = CIVILIAN - else if(job_medsci_high) - highDeptFlag = MEDSCI - else if(job_engsec_high) - highDeptFlag = ENGSEC - - for(var/datum/job/job in SSjob.occupations) - if(job.flag == highRankFlag && job.department_flag == highDeptFlag) - previewJob = job - break - if(previewJob) - if(current_tab != 2) - mannequin.job = previewJob.title - previewJob.equip(mannequin, TRUE) + mannequin.job = previewJob.title + previewJob.equip(mannequin, TRUE, preference_source = parent) COMPILE_OVERLAYS(mannequin) parent.show_character_previews(new /mutable_appearance(mannequin)) unset_busy_human_dummy(DUMMY_HUMAN_SLOT_PREFERENCES) + diff --git a/tgstation.dme b/tgstation.dme index 0fbefaa7b8..341497cb5c 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -1767,17 +1767,39 @@ #include "code\modules\jobs\access.dm" #include "code\modules\jobs\job_exp.dm" #include "code\modules\jobs\jobs.dm" +#include "code\modules\jobs\job_types\_job.dm" +#include "code\modules\jobs\job_types\ai.dm" #include "code\modules\jobs\job_types\assistant.dm" +#include "code\modules\jobs\job_types\atmospheric_technician.dm" +#include "code\modules\jobs\job_types\bartender.dm" +#include "code\modules\jobs\job_types\botanist.dm" #include "code\modules\jobs\job_types\captain.dm" -#include "code\modules\jobs\job_types\cargo_service.dm" -#include "code\modules\jobs\job_types\civilian.dm" -#include "code\modules\jobs\job_types\civilian_chaplain.dm" -#include "code\modules\jobs\job_types\engineering.dm" -#include "code\modules\jobs\job_types\job.dm" -#include "code\modules\jobs\job_types\medical.dm" -#include "code\modules\jobs\job_types\science.dm" -#include "code\modules\jobs\job_types\security.dm" -#include "code\modules\jobs\job_types\silicon.dm" +#include "code\modules\jobs\job_types\cargo_technician.dm" +#include "code\modules\jobs\job_types\chaplain.dm" +#include "code\modules\jobs\job_types\chemist.dm" +#include "code\modules\jobs\job_types\chief_engineer.dm" +#include "code\modules\jobs\job_types\chief_medical_officer.dm" +#include "code\modules\jobs\job_types\clown.dm" +#include "code\modules\jobs\job_types\cook.dm" +#include "code\modules\jobs\job_types\curator.dm" +#include "code\modules\jobs\job_types\cyborg.dm" +#include "code\modules\jobs\job_types\detective.dm" +#include "code\modules\jobs\job_types\geneticist.dm" +#include "code\modules\jobs\job_types\head_of_personnel.dm" +#include "code\modules\jobs\job_types\head_of_security.dm" +#include "code\modules\jobs\job_types\janitor.dm" +#include "code\modules\jobs\job_types\lawyer.dm" +#include "code\modules\jobs\job_types\medical_doctor.dm" +#include "code\modules\jobs\job_types\mime.dm" +#include "code\modules\jobs\job_types\quartermaster.dm" +#include "code\modules\jobs\job_types\research_director.dm" +#include "code\modules\jobs\job_types\roboticist.dm" +#include "code\modules\jobs\job_types\scientist.dm" +#include "code\modules\jobs\job_types\security_officer.dm" +#include "code\modules\jobs\job_types\shaft_miner.dm" +#include "code\modules\jobs\job_types\station_engineer.dm" +#include "code\modules\jobs\job_types\virologist.dm" +#include "code\modules\jobs\job_types\warden.dm" #include "code\modules\jobs\map_changes\map_changes.dm" #include "code\modules\keybindings\bindings_admin.dm" #include "code\modules\keybindings\bindings_atom.dm" From f19a3541a33c09fee796bffa1e2f61b2496728ff Mon Sep 17 00:00:00 2001 From: Poojawa Date: Sun, 16 Jun 2019 19:30:14 -0500 Subject: [PATCH 002/222] cleans up runtimes --- code/controllers/subsystem/ticker.dm | 2 +- code/game/gamemodes/game_mode.dm | 1 + code/game/gamemodes/revolution/revolution.dm | 1 + code/modules/mob/dead/new_player/new_player.dm | 7 ++++++- 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 4a3143da79..f5222642c0 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -244,7 +244,7 @@ SUBSYSTEM_DEF(ticker) var/can_continue = 0 can_continue = src.mode.pre_setup() //Choose antagonists CHECK_TICK - SSjob.DivideOccupations() //Distribute jobs + can_continue = can_continue && SSjob.DivideOccupations(mode.required_jobs) //Distribute jobs CHECK_TICK if(!GLOB.Debug2) diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 28a0e21061..13f6db2422 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -24,6 +24,7 @@ var/list/datum/mind/antag_candidates = list() // List of possible starting antags goes here var/list/restricted_jobs = list() // Jobs it doesn't make sense to be. I.E chaplain or AI cultist var/list/protected_jobs = list() // Jobs that can't be traitors because + var/list/required_jobs = list() // alternative required job groups eg list(list(cap=1),list(hos=1,sec=2)) translates to one captain OR one hos and two secmans var/required_players = 0 var/maximum_players = -1 // -1 is no maximum, positive numbers limit the selection of a mode on overstaffed stations var/required_enemies = 0 diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm index 09047b05a9..38dd128505 100644 --- a/code/game/gamemodes/revolution/revolution.dm +++ b/code/game/gamemodes/revolution/revolution.dm @@ -13,6 +13,7 @@ antag_flag = ROLE_REV false_report_weight = 10 restricted_jobs = list("Security Officer", "Warden", "Detective", "AI", "Cyborg","Captain", "Head of Personnel", "Head of Security", "Chief Engineer", "Research Director", "Chief Medical Officer") + required_jobs = list(list("Captain"=1),list("Head of Personnel"=1),list("Head of Security"=1),list("Chief Engineer"=1),list("Research Director"=1),list("Chief Medical Officer"=1)) //Any head present required_players = 30 required_enemies = 2 recommended_enemies = 3 diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index 9bd37cf171..645b1b2203 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -446,7 +446,12 @@ dat += "" dat += "" dat += "" - dat += "" + dat += "" dat += "" dat += "" dat += "" @@ -141,7 +136,7 @@ dat += "" var/counter = 1 - while(src.active2.fields[text("com_[]", counter)]) + while(active2.fields[text("com_[]", counter)]) dat += "" counter++ dat += "" @@ -169,7 +164,7 @@ dat += "
Medical Robots:" var/bdat = null for(var/mob/living/simple_animal/bot/medbot/M in GLOB.alive_mob_list) - if(M.z != src.z) + if(M.z != z) continue //only find medibots on the same z-level as the computer var/turf/bl = get_turf(M) if(bl) //if it can't find a turf for the medibot, then it probably shouldn't be showing up @@ -189,7 +184,7 @@ dat += "{Log In}" var/datum/browser/popup = new(user, "med_rec", "Medical Records Console", 600, 400) popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) + popup.set_title_image(user.browse_rsc_icon(icon, icon_state)) popup.open() /obj/machinery/computer/med_data/Topic(href, href_list) @@ -197,29 +192,20 @@ if(.) return . if(!(active1 in GLOB.data_core.general)) - src.active1 = null + active1 = null if(!(active2 in GLOB.data_core.medical)) - src.active2 = null + active2 = null if(usr.contents.Find(src) || (in_range(src, usr) && isturf(loc)) || issilicon(usr) || IsAdminGhost(usr)) usr.set_machine(src) if(href_list["temp"]) - src.temp = null - if(href_list["scan"]) - if(src.scan) - usr.put_in_hands(scan) - scan = null - else - var/obj/item/I = usr.is_holding_item_of_type(/obj/item/card/id) - if(I) - if(!usr.transferItemToLoc(I, src)) - return - src.scan = I + temp = null else if(href_list["logout"]) - src.authenticated = null - src.screen = null - src.active1 = null - src.active2 = null + authenticated = null + screen = null + active1 = null + active2 = null + playsound(src, 'sound/machines/terminal_off.ogg', 50, FALSE) else if(href_list["choice"]) // SORTING! if(href_list["choice"] == "Sorting") @@ -234,34 +220,37 @@ sortBy = href_list["sort"] order = initial(order) else if(href_list["login"]) - if(issilicon(usr)) - src.active1 = null - src.active2 = null - src.authenticated = 1 - src.rank = "AI" - src.screen = 1 - else if(IsAdminGhost(usr)) - src.active1 = null - src.active2 = null - src.authenticated = 1 - src.rank = "Central Command" - src.screen = 1 - else if(istype(src.scan, /obj/item/card/id)) - src.active1 = null - src.active2 = null - if(src.check_access(src.scan)) - src.authenticated = src.scan.registered_name - src.rank = src.scan.assignment - src.screen = 1 - if(src.authenticated) - + var/mob/M = usr + var/obj/item/card/id/I = M.get_idcard(TRUE) + if(issilicon(M)) + active1 = null + active2 = null + authenticated = 1 + rank = "AI" + screen = 1 + else if(IsAdminGhost(M)) + active1 = null + active2 = null + authenticated = 1 + rank = "Central Command" + screen = 1 + else if(istype(I) && check_access(I)) + active1 = null + active2 = null + authenticated = I.registered_name + rank = I.assignment + screen = 1 + else + to_chat(usr, "Unauthorized access.") + playsound(src, 'sound/machines/terminal_on.ogg', 50, FALSE) + if(authenticated) if(href_list["screen"]) - src.screen = text2num(href_list["screen"]) - if(src.screen < 1) - src.screen = 1 + screen = text2num(href_list["screen"]) + if(screen < 1) + screen = 1 - src.active1 = null - src.active2 = null + active1 = null + active2 = null else if(href_list["vir"]) var/type = href_list["vir"] @@ -269,7 +258,7 @@ var/AfS = "" for(var/mob/M in Dis.viable_mobtypes) AfS += " [initial(M.name)];" - src.temp = {"Name: [Dis.name] + temp = {"Name: [Dis.name]
Number of stages: [Dis.max_stages]
Spread: [Dis.spread_text] Transmission
Possible Cure: [(Dis.cure_text||"none")] @@ -280,110 +269,112 @@
Severity: [Dis.severity]"} else if(href_list["del_all"]) - src.temp = "Are you sure you wish to delete all records?
\n\tYes
\n\tNo
" + temp = "Are you sure you wish to delete all records?
\n\tYes
\n\tNo
" else if(href_list["del_all2"]) investigate_log("[key_name(usr)] has deleted all medical records.", INVESTIGATE_RECORDS) GLOB.data_core.medical.Cut() - src.temp = "All records deleted." + temp = "All records deleted." else if(href_list["field"]) - var/a1 = src.active1 - var/a2 = src.active2 + var/a1 = active1 + var/a2 = active2 switch(href_list["field"]) if("fingerprint") if(active1) - var/t1 = stripped_input("Please input fingerprint hash:", "Med. records", src.active1.fields["fingerprint"], null) + var/t1 = stripped_input("Please input fingerprint hash:", "Med. records", active1.fields["fingerprint"], null) if(!canUseMedicalRecordsConsole(usr, t1, a1)) return - src.active1.fields["fingerprint"] = t1 - if("sex") + active1.fields["fingerprint"] = t1 + if("gender") if(active1) - if(src.active1.fields["sex"] == "Male") - src.active1.fields["sex"] = "Female" + if(active1.fields["gender"] == "Male") + active1.fields["gender"] = "Female" + else if(active1.fields["gender"] == "Female") + active1.fields["gender"] = "Other" else - src.active1.fields["sex"] = "Male" + active1.fields["gender"] = "Male" if("age") if(active1) - var/t1 = input("Please input age:", "Med. records", src.active1.fields["age"], null) as num + var/t1 = input("Please input age:", "Med. records", active1.fields["age"], null) as num if(!canUseMedicalRecordsConsole(usr, t1, a1)) return - src.active1.fields["age"] = t1 + active1.fields["age"] = t1 if("species") if(active1) - var/t1 = stripped_input("Please input species name", "Med. records", src.active1.fields["species"], null) + var/t1 = stripped_input("Please input species name", "Med. records", active1.fields["species"], null) if(!canUseMedicalRecordsConsole(usr, t1, a1)) return active1.fields["species"] = t1 if("mi_dis") if(active2) - var/t1 = stripped_input("Please input minor disabilities list:", "Med. records", src.active2.fields["mi_dis"], null) + var/t1 = stripped_input("Please input minor disabilities list:", "Med. records", active2.fields["mi_dis"], null) if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) return - src.active2.fields["mi_dis"] = t1 + active2.fields["mi_dis"] = t1 if("mi_dis_d") if(active2) - var/t1 = stripped_input("Please summarize minor dis.:", "Med. records", src.active2.fields["mi_dis_d"], null) + var/t1 = stripped_input("Please summarize minor dis.:", "Med. records", active2.fields["mi_dis_d"], null) if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) return - src.active2.fields["mi_dis_d"] = t1 + active2.fields["mi_dis_d"] = t1 if("ma_dis") if(active2) - var/t1 = stripped_input("Please input major disabilities list:", "Med. records", src.active2.fields["ma_dis"], null) + var/t1 = stripped_input("Please input major disabilities list:", "Med. records", active2.fields["ma_dis"], null) if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) return - src.active2.fields["ma_dis"] = t1 + active2.fields["ma_dis"] = t1 if("ma_dis_d") if(active2) - var/t1 = stripped_input("Please summarize major dis.:", "Med. records", src.active2.fields["ma_dis_d"], null) + var/t1 = stripped_input("Please summarize major dis.:", "Med. records", active2.fields["ma_dis_d"], null) if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) return - src.active2.fields["ma_dis_d"] = t1 + active2.fields["ma_dis_d"] = t1 if("alg") if(active2) - var/t1 = stripped_input("Please state allergies:", "Med. records", src.active2.fields["alg"], null) + var/t1 = stripped_input("Please state allergies:", "Med. records", active2.fields["alg"], null) if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) return - src.active2.fields["alg"] = t1 + active2.fields["alg"] = t1 if("alg_d") if(active2) - var/t1 = stripped_input("Please summarize allergies:", "Med. records", src.active2.fields["alg_d"], null) + var/t1 = stripped_input("Please summarize allergies:", "Med. records", active2.fields["alg_d"], null) if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) return - src.active2.fields["alg_d"] = t1 + active2.fields["alg_d"] = t1 if("cdi") if(active2) - var/t1 = stripped_input("Please state diseases:", "Med. records", src.active2.fields["cdi"], null) + var/t1 = stripped_input("Please state diseases:", "Med. records", active2.fields["cdi"], null) if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) return - src.active2.fields["cdi"] = t1 + active2.fields["cdi"] = t1 if("cdi_d") if(active2) - var/t1 = stripped_input("Please summarize diseases:", "Med. records", src.active2.fields["cdi_d"], null) + var/t1 = stripped_input("Please summarize diseases:", "Med. records", active2.fields["cdi_d"], null) if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) return - src.active2.fields["cdi_d"] = t1 + active2.fields["cdi_d"] = t1 if("notes") if(active2) - var/t1 = stripped_input("Please summarize notes:", "Med. records", src.active2.fields["notes"], null) + var/t1 = stripped_input("Please summarize notes:", "Med. records", active2.fields["notes"], null) if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) return - src.active2.fields["notes"] = t1 + active2.fields["notes"] = t1 if("p_stat") if(active1) - src.temp = "Physical Condition:
\n\t*Deceased*
\n\t*Unconscious*
\n\tActive
\n\tPhysically Unfit
" + temp = "Physical Condition:
\n\t*Deceased*
\n\t*Unconscious*
\n\tActive
\n\tPhysically Unfit
" if("m_stat") if(active1) - src.temp = "Mental Condition:
\n\t*Insane*
\n\t*Unstable*
\n\t*Watch*
\n\tStable
" + temp = "Mental Condition:
\n\t*Insane*
\n\t*Unstable*
\n\t*Watch*
\n\tStable
" if("blood_type") if(active2) - src.temp = "Blood Type:
\n\tA-A+
\n\tB-B+
\n\tAB-AB+
\n\tO-O+
" + temp = "Blood Type:
\n\tA-A+
\n\tB-B+
\n\tAB-AB+
\n\tO-O+
" if("b_dna") if(active2) - var/t1 = stripped_input("Please input DNA hash:", "Med. records", src.active2.fields["b_dna"], null) + var/t1 = stripped_input("Please input DNA hash:", "Med. records", active2.fields["b_dna"], null) if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) return - src.active2.fields["b_dna"] = t1 + active2.fields["b_dna"] = t1 if("show_photo_front") if(active1) if(active1.fields["photo_front"]) @@ -402,51 +393,51 @@ if(active1) switch(href_list["p_stat"]) if("deceased") - src.active1.fields["p_stat"] = "*Deceased*" + active1.fields["p_stat"] = "*Deceased*" if("unconscious") - src.active1.fields["p_stat"] = "*Unconscious*" + active1.fields["p_stat"] = "*Unconscious*" if("active") - src.active1.fields["p_stat"] = "Active" + active1.fields["p_stat"] = "Active" if("unfit") - src.active1.fields["p_stat"] = "Physically Unfit" + active1.fields["p_stat"] = "Physically Unfit" else if(href_list["m_stat"]) if(active1) switch(href_list["m_stat"]) if("insane") - src.active1.fields["m_stat"] = "*Insane*" + active1.fields["m_stat"] = "*Insane*" if("unstable") - src.active1.fields["m_stat"] = "*Unstable*" + active1.fields["m_stat"] = "*Unstable*" if("watch") - src.active1.fields["m_stat"] = "*Watch*" + active1.fields["m_stat"] = "*Watch*" if("stable") - src.active1.fields["m_stat"] = "Stable" + active1.fields["m_stat"] = "Stable" else if(href_list["blood_type"]) if(active2) switch(href_list["blood_type"]) if("an") - src.active2.fields["blood_type"] = "A-" + active2.fields["blood_type"] = "A-" if("bn") - src.active2.fields["blood_type"] = "B-" + active2.fields["blood_type"] = "B-" if("abn") - src.active2.fields["blood_type"] = "AB-" + active2.fields["blood_type"] = "AB-" if("on") - src.active2.fields["blood_type"] = "O-" + active2.fields["blood_type"] = "O-" if("ap") - src.active2.fields["blood_type"] = "A+" + active2.fields["blood_type"] = "A+" if("bp") - src.active2.fields["blood_type"] = "B+" + active2.fields["blood_type"] = "B+" if("abp") - src.active2.fields["blood_type"] = "AB+" + active2.fields["blood_type"] = "AB+" if("op") - src.active2.fields["blood_type"] = "O+" + active2.fields["blood_type"] = "O+" else if(href_list["del_r"]) if(active2) - src.temp = "Are you sure you wish to delete the record (Medical Portion Only)?
\n\tYes
\n\tNo
" + temp = "Are you sure you wish to delete the record (Medical Portion Only)?
\n\tYes
\n\tNo
" else if(href_list["del_r2"]) investigate_log("[key_name(usr)] has deleted the medical records for [active1.fields["name"]].", INVESTIGATE_RECORDS) @@ -463,10 +454,10 @@ screen = 4 else if(href_list["new"]) - if((istype(src.active1, /datum/data/record) && !( istype(src.active2, /datum/data/record) ))) + if((istype(active1, /datum/data/record) && !( istype(active2, /datum/data/record) ))) var/datum/data/record/R = new /datum/data/record( ) - R.fields["name"] = src.active1.fields["name"] - R.fields["id"] = src.active1.fields["id"] + R.fields["name"] = active1.fields["name"] + R.fields["id"] = active1.fields["id"] R.name = text("Medical Record #[]", R.fields["id"]) R.fields["blood_type"] = "Unknown" R.fields["b_dna"] = "Unknown" @@ -480,76 +471,77 @@ R.fields["cdi_d"] = "No diseases have been diagnosed at the moment." R.fields["notes"] = "No notes." GLOB.data_core.medical += R - src.active2 = R - src.screen = 4 + active2 = R + screen = 4 else if(href_list["add_c"]) if(!(active2 in GLOB.data_core.medical)) return - var/a2 = src.active2 + var/a2 = active2 var/t1 = stripped_multiline_input("Add Comment:", "Med. records", null, null) if(!canUseMedicalRecordsConsole(usr, t1, null, a2)) return var/counter = 1 - while(src.active2.fields[text("com_[]", counter)]) + while(active2.fields[text("com_[]", counter)]) counter++ - src.active2.fields[text("com_[]", counter)] = text("Made by [] ([]) on [] [], []
[]", src.authenticated, src.rank, STATION_TIME_TIMESTAMP("hh:mm:ss"), time2text(world.realtime, "MMM DD"), GLOB.year_integer+540, t1) + active2.fields[text("com_[]", counter)] = text("Made by [] ([]) on [] [], []
[]", authenticated, rank, STATION_TIME_TIMESTAMP("hh:mm:ss"), time2text(world.realtime, "MMM DD"), GLOB.year_integer+540, t1) else if(href_list["del_c"]) - if((istype(src.active2, /datum/data/record) && src.active2.fields[text("com_[]", href_list["del_c"])])) - src.active2.fields[text("com_[]", href_list["del_c"])] = "Deleted" + if((istype(active2, /datum/data/record) && active2.fields[text("com_[]", href_list["del_c"])])) + active2.fields[text("com_[]", href_list["del_c"])] = "Deleted" else if(href_list["search"]) var/t1 = stripped_input(usr, "Search String: (Name, DNA, or ID)", "Med. records") if(!canUseMedicalRecordsConsole(usr, t1)) return - src.active1 = null - src.active2 = null + active1 = null + active2 = null t1 = lowertext(t1) for(var/datum/data/record/R in GLOB.data_core.medical) if((lowertext(R.fields["name"]) == t1 || t1 == lowertext(R.fields["id"]) || t1 == lowertext(R.fields["b_dna"]))) - src.active2 = R + active2 = R else //Foreach continue //goto(3229) - if(!( src.active2 )) - src.temp = text("Could not locate record [].", sanitize(t1)) + if(!( active2 )) + temp = text("Could not locate record [].", sanitize(t1)) else for(var/datum/data/record/E in GLOB.data_core.general) - if((E.fields["name"] == src.active2.fields["name"] || E.fields["id"] == src.active2.fields["id"])) - src.active1 = E + if((E.fields["name"] == active2.fields["name"] || E.fields["id"] == active2.fields["id"])) + active1 = E else //Foreach continue //goto(3334) - src.screen = 4 + screen = 4 else if(href_list["print_p"]) - if(!( src.printing )) - src.printing = 1 + if(!( printing )) + printing = 1 GLOB.data_core.medicalPrintCount++ playsound(loc, 'sound/items/poster_being_created.ogg', 100, 1) sleep(30) - var/obj/item/paper/P = new /obj/item/paper( src.loc ) + var/obj/item/paper/P = new /obj/item/paper( loc ) P.info = "
Medical Record - (MR-[GLOB.data_core.medicalPrintCount])

" if(active1 in GLOB.data_core.general) - P.info += text("Name: [] ID: []
\nSex: []
\nAge: []
", src.active1.fields["name"], src.active1.fields["id"], src.active1.fields["sex"], src.active1.fields["age"]) + P.info += text("Name: [] ID: []
\nGender: []
\nAge: []
", active1.fields["name"], active1.fields["id"], active1.fields["gender"], active1.fields["age"]) P.info += "\nSpecies: [active1.fields["species"]]
" - P.info += text("\nFingerprint: []
\nPhysical Status: []
\nMental Status: []
", src.active1.fields["fingerprint"], src.active1.fields["p_stat"], src.active1.fields["m_stat"]) + P.info += text("\nFingerprint: []
\nPhysical Status: []
\nMental Status: []
", active1.fields["fingerprint"], active1.fields["p_stat"], active1.fields["m_stat"]) else P.info += "General Record Lost!
" if(active2 in GLOB.data_core.medical) - P.info += text("
\n
Medical Data

\nBlood Type: []
\nDNA: []
\n
\nMinor Disabilities: []
\nDetails: []
\n
\nMajor Disabilities: []
\nDetails: []
\n
\nAllergies: []
\nDetails: []
\n
\nCurrent Diseases: [] (per disease info placed in log/comment section)
\nDetails: []
\n
\nImportant Notes:
\n\t[]
\n
\n
Comments/Log

", src.active2.fields["blood_type"], src.active2.fields["b_dna"], src.active2.fields["mi_dis"], src.active2.fields["mi_dis_d"], src.active2.fields["ma_dis"], src.active2.fields["ma_dis_d"], src.active2.fields["alg"], src.active2.fields["alg_d"], src.active2.fields["cdi"], src.active2.fields["cdi_d"], src.active2.fields["notes"]) + P.info += text("
\n
Medical Data

\nBlood Type: []
\nDNA: []
\n
\nMinor Disabilities: []
\nDetails: []
\n
\nMajor Disabilities: []
\nDetails: []
\n
\nAllergies: []
\nDetails: []
\n
\nCurrent Diseases: [] (per disease info placed in log/comment section)
\nDetails: []
\n
\nImportant Notes:
\n\t[]
\n
\n
Comments/Log

", active2.fields["blood_type"], active2.fields["b_dna"], active2.fields["mi_dis"], active2.fields["mi_dis_d"], active2.fields["ma_dis"], active2.fields["ma_dis_d"], active2.fields["alg"], active2.fields["alg_d"], active2.fields["cdi"], active2.fields["cdi_d"], active2.fields["notes"]) var/counter = 1 - while(src.active2.fields[text("com_[]", counter)]) - P.info += text("[]
", src.active2.fields[text("com_[]", counter)]) + while(active2.fields[text("com_[]", counter)]) + P.info += text("[]
", active2.fields[text("com_[]", counter)]) counter++ - P.name = text("MR-[] '[]'", GLOB.data_core.medicalPrintCount, src.active1.fields["name"]) + P.name = text("MR-[] '[]'", GLOB.data_core.medicalPrintCount, active1.fields["name"]) else P.info += "Medical Record Lost!
" P.name = text("MR-[] '[]'", GLOB.data_core.medicalPrintCount, "Record Lost") P.info += "" - src.printing = null + P.update_icon() + printing = null - src.add_fingerprint(usr) - src.updateUsrDialog() + add_fingerprint(usr) + updateUsrDialog() return /obj/machinery/computer/med_data/emp_act(severity) @@ -560,11 +552,11 @@ switch(rand(1,6)) if(1) if(prob(10)) - R.fields["name"] = random_unique_lizard_name(R.fields["sex"],1) + R.fields["name"] = random_unique_lizard_name(R.fields["gender"],1) else - R.fields["name"] = random_unique_name(R.fields["sex"],1) + R.fields["name"] = random_unique_name(R.fields["gender"],1) if(2) - R.fields["sex"] = pick("Male", "Female") + R.fields["gender"] = pick("Male", "Female", "Other") if(3) R.fields["age"] = rand(AGE_MIN, AGE_MAX) if(4) @@ -583,7 +575,7 @@ if(user) if(message) if(authenticated) - if(user.canUseTopic(src)) + if(user.canUseTopic(src, BE_CLOSE)) if(!record1 || record1 == active1) if(!record2 || record2 == active2) return 1 diff --git a/code/game/machinery/computer/prisoner.dm b/code/game/machinery/computer/prisoner.dm index 798b0e4c65..a852612d9d 100644 --- a/code/game/machinery/computer/prisoner.dm +++ b/code/game/machinery/computer/prisoner.dm @@ -1,143 +1 @@ /obj/machinery/computer/prisoner - name = "prisoner management console" - desc = "Used to manage tracking implants placed inside criminals." - icon_screen = "explosive" - icon_keyboard = "security_key" - req_access = list(ACCESS_BRIG) - var/id = 0 - var/temp = null - var/status = 0 - var/timeleft = 60 - var/stop = 0 - var/screen = 0 // 0 - No Access Denied, 1 - Access allowed - var/obj/item/card/id/prisoner/inserted_id - circuit = /obj/item/circuitboard/computer/prisoner - - light_color = LIGHT_COLOR_RED - -/obj/machinery/computer/prisoner/ui_interact(mob/user) - . = ..() - var/dat = "" - if(screen == 0) - dat += "
Unlock Console" - else if(screen == 1) - dat += "

Prisoner ID Management

" - if(inserted_id) - dat += text("[inserted_id]
") - dat += text("Collected Points: [inserted_id.points]. Reset.
") - dat += text("Card goal: [inserted_id.goal]. Set
") - dat += text("Space Law recommends quotas of 100 points per minute they would normally serve in the brig.
") - else - dat += text("Insert Prisoner ID.
") - dat += "

Prisoner Implant Management

" - dat += "
Chemical Implants
" - var/turf/Tr = null - for(var/obj/item/implant/chem/C in GLOB.tracked_chem_implants) - Tr = get_turf(C) - if((Tr) && (Tr.z != src.z)) - continue//Out of range - if(!C.imp_in) - continue - dat += "ID: [C.imp_in.name] | Remaining Units: [C.reagents.total_volume]
" - dat += "| Inject: " - dat += "((1))" - dat += "((5))" - dat += "((10))
" - dat += "********************************
" - dat += "
Tracking Implants
" - for(var/obj/item/implant/tracking/T in GLOB.tracked_implants) - if(!isliving(T.imp_in)) - continue - Tr = get_turf(T) - if((Tr) && (Tr.z != src.z)) - continue//Out of range - - var/loc_display = "Unknown" - var/mob/living/M = T.imp_in - if(is_station_level(Tr.z) && !isspaceturf(M.loc)) - var/turf/mob_loc = get_turf(M) - loc_display = mob_loc.loc - - dat += "ID: [T.imp_in.name] | Location: [loc_display]
" - dat += "(Message Holder) |
" - dat += "********************************
" - dat += "
Lock Console" - var/datum/browser/popup = new(user, "computer", "Prisoner Management Console", 400, 500) - popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) - popup.open() - return - -/obj/machinery/computer/prisoner/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/card/id)) - return attack_hand(user) - else - return ..() - -/obj/machinery/computer/prisoner/process() - if(!..()) - src.updateDialog() - return - - -/obj/machinery/computer/prisoner/Topic(href, href_list) - if(..()) - return - if(usr.contents.Find(src) || (in_range(src, usr) && isturf(loc)) || issilicon(usr)) - usr.set_machine(src) - - if(href_list["id"]) - if(href_list["id"] =="insert" && !inserted_id) - var/obj/item/card/id/prisoner/I = usr.is_holding_item_of_type(/obj/item/card/id/prisoner) - if(I) - if(!usr.transferItemToLoc(I, src)) - return - inserted_id = I - else - to_chat(usr, "No valid ID.") - else if(inserted_id) - switch(href_list["id"]) - if("eject") - inserted_id.forceMove(drop_location()) - inserted_id.verb_pickup() - inserted_id = null - if("reset") - inserted_id.points = 0 - if("setgoal") - var/num = round(input(usr, "Choose prisoner's goal:", "Input an Integer", null) as num|null) - if(num >= 0) - num = min(num,1000) //Cap the quota to the equivilent of 10 minutes. - inserted_id.goal = num - else if(href_list["inject1"]) - var/obj/item/implant/I = locate(href_list["inject1"]) in GLOB.tracked_chem_implants - if(I && istype(I)) - I.activate(1) - else if(href_list["inject5"]) - var/obj/item/implant/I = locate(href_list["inject5"]) in GLOB.tracked_chem_implants - if(I && istype(I)) - I.activate(5) - - else if(href_list["inject10"]) - var/obj/item/implant/I = locate(href_list["inject10"]) in GLOB.tracked_chem_implants - if(I && istype(I)) - I.activate(10) - - else if(href_list["lock"]) - if(src.allowed(usr)) - screen = !screen - else - to_chat(usr, "Unauthorized Access.") - - else if(href_list["warn"]) - var/warning = copytext(sanitize(input(usr,"Message:","Enter your message here!","")),1,MAX_MESSAGE_LEN) - if(!warning) - return - var/obj/item/implant/I = locate(href_list["warn"]) in GLOB.tracked_implants - if(I && istype(I) && I.imp_in) - var/mob/living/R = I.imp_in - to_chat(R, "You hear a voice in your head saying: '[warning]'") - log_directed_talk(usr, R, warning, LOG_SAY, "implant message") - - src.add_fingerprint(usr) - src.updateUsrDialog() - return diff --git a/code/game/machinery/computer/prisoner/_prisoner.dm b/code/game/machinery/computer/prisoner/_prisoner.dm new file mode 100644 index 0000000000..d07c351a22 --- /dev/null +++ b/code/game/machinery/computer/prisoner/_prisoner.dm @@ -0,0 +1,52 @@ +/obj/machinery/computer/prisoner + var/obj/item/card/id/prisoner/contained_id + +/obj/machinery/computer/prisoner/Destroy() + if(contained_id) + contained_id.forceMove(get_turf(src)) + return ..() + + +/obj/machinery/computer/prisoner/examine(mob/user) + . = ..() + if(contained_id) + . += "Alt-click to eject the ID card." + + + +/obj/machinery/computer/prisoner/AltClick(mob/user) + id_eject(user) + return ..() + +/obj/machinery/computer/prisoner/proc/id_insert(mob/user, obj/item/card/id/prisoner/P) + if(istype(P)) + if(contained_id) + to_chat(user, "There's already an ID card in the console!") + return + if(!user.transferItemToLoc(P, src)) + return + contained_id = P + user.visible_message("[user] inserts an ID card into the console.", \ + "You insert the ID card into the console.") + playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + updateUsrDialog() + +/obj/machinery/computer/prisoner/proc/id_eject(mob/user) + if(!contained_id) + to_chat(user, "There's no ID card in the console!") + return + else + contained_id.forceMove(drop_location()) + if(!issilicon(user) && Adjacent(user)) + user.put_in_hands(contained_id) + contained_id = null + user.visible_message("[user] gets an ID card from the console.", \ + "You get the ID card from the console.") + playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + updateUsrDialog() + +/obj/machinery/computer/prisoner/attackby(obj/item/I, mob/user) + if(istype(I, /obj/item/card/id/prisoner)) + id_insert(user, I) + else + return ..() diff --git a/code/game/machinery/computer/prisoner/gulag_teleporter.dm b/code/game/machinery/computer/prisoner/gulag_teleporter.dm new file mode 100644 index 0000000000..f6e164efe9 --- /dev/null +++ b/code/game/machinery/computer/prisoner/gulag_teleporter.dm @@ -0,0 +1,142 @@ +//computer that handle the points and teleports the prisoner +/obj/machinery/computer/prisoner/gulag_teleporter_computer + name = "labor camp teleporter console" + desc = "Used to send criminals to the Labor Camp." + icon_screen = "explosive" + icon_keyboard = "security_key" + req_access = list(ACCESS_ARMORY) + circuit = /obj/item/circuitboard/computer/gulag_teleporter_console + var/default_goal = 200 + var/obj/machinery/gulag_teleporter/teleporter = null + var/obj/structure/gulag_beacon/beacon = null + var/mob/living/carbon/human/prisoner = null + var/datum/data/record/temporary_record = null + + light_color = LIGHT_COLOR_RED + +/obj/machinery/computer/prisoner/gulag_teleporter_computer/Initialize() + . = ..() + scan_machinery() + +/obj/machinery/computer/prisoner/gulag_teleporter_computer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "gulag_console", name, 455, 440, master_ui, state) + ui.open() + +/obj/machinery/computer/prisoner/gulag_teleporter_computer/ui_data(mob/user) + var/list/data = list() + + var/list/prisoner_list = list() + var/can_teleport = FALSE + + if(teleporter && (teleporter.occupant && ishuman(teleporter.occupant))) + prisoner = teleporter.occupant + prisoner_list["name"] = prisoner.real_name + if(contained_id) + can_teleport = TRUE + if(!isnull(GLOB.data_core.general)) + for(var/r in GLOB.data_core.security) + var/datum/data/record/R = r + if(R.fields["name"] == prisoner_list["name"]) + temporary_record = R + prisoner_list["crimstat"] = temporary_record.fields["criminal"] + + data["prisoner"] = prisoner_list + + if(teleporter) + data["teleporter"] = teleporter + data["teleporter_location"] = "([teleporter.x], [teleporter.y], [teleporter.z])" + data["teleporter_lock"] = teleporter.locked + data["teleporter_state_open"] = teleporter.state_open + if(beacon) + data["beacon"] = beacon + data["beacon_location"] = "([beacon.x], [beacon.y], [beacon.z])" + if(contained_id) + data["id"] = contained_id + data["id_name"] = contained_id.registered_name + data["goal"] = contained_id.goal + data["can_teleport"] = can_teleport + + return data + +/obj/machinery/computer/prisoner/gulag_teleporter_computer/ui_act(action, list/params) + if(isliving(usr)) + playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) + if(..()) + return + if(!allowed(usr)) + to_chat(usr, "Access denied.") + return + switch(action) + if("scan_teleporter") + teleporter = findteleporter() + if("scan_beacon") + beacon = findbeacon() + if("handle_id") + if(contained_id) + id_eject(usr) + else + id_insert(usr) + if("set_goal") + var/new_goal = input("Set the amount of points:", "Points", contained_id.goal) as num|null + if(!isnum(new_goal)) + return + if(!new_goal) + new_goal = default_goal + if (new_goal > 1000) + to_chat(usr, "The entered amount of points is too large. Points have instead been set to the maximum allowed amount.") + contained_id.goal = CLAMP(new_goal, 0, 1000) //maximum 1000 points + if("toggle_open") + if(teleporter.locked) + to_chat(usr, "The teleporter is locked") + return + teleporter.toggle_open() + if("teleporter_lock") + if(teleporter.state_open) + to_chat(usr, "Close the teleporter before locking!") + return + teleporter.locked = !teleporter.locked + if("teleport") + if(!teleporter || !beacon) + return + addtimer(CALLBACK(src, .proc/teleport, usr), 5) + +/obj/machinery/computer/prisoner/gulag_teleporter_computer/proc/scan_machinery() + teleporter = findteleporter() + beacon = findbeacon() + +/obj/machinery/computer/prisoner/gulag_teleporter_computer/proc/findteleporter() + var/obj/machinery/gulag_teleporter/teleporterf = null + + for(var/direction in GLOB.cardinals) + teleporterf = locate(/obj/machinery/gulag_teleporter, get_step(src, direction)) + if(teleporterf && teleporterf.is_operational()) + return teleporterf + +/obj/machinery/computer/prisoner/gulag_teleporter_computer/proc/findbeacon() + return locate(/obj/structure/gulag_beacon) + +/obj/machinery/computer/prisoner/gulag_teleporter_computer/proc/teleport(mob/user) + if(!contained_id) //incase the ID was removed after the transfer timer was set. + say("Warning: Unable to transfer prisoner without a valid Prisoner ID inserted!") + return + var/id_goal_not_set + if(!contained_id.goal) + id_goal_not_set = TRUE + contained_id.goal = default_goal + say("[contained_id]'s ID card goal defaulting to [contained_id.goal] points.") + log_game("[key_name(user)] teleported [key_name(prisoner)] to the Labor Camp [COORD(beacon)] for [id_goal_not_set ? "default goal of ":""][contained_id.goal] points.") + teleporter.handle_prisoner(contained_id, temporary_record) + playsound(src, 'sound/weapons/emitter.ogg', 50, 1) + prisoner.forceMove(get_turf(beacon)) + prisoner.Stun(40) // small travel dizziness + to_chat(prisoner, "The teleportation makes you a little dizzy.") + new /obj/effect/particle_effect/sparks(get_turf(prisoner)) + playsound(src, "sparks", 50, 1) + if(teleporter.locked) + teleporter.locked = FALSE + teleporter.toggle_open() + contained_id = null + temporary_record = null diff --git a/code/game/machinery/computer/prisoner/management.dm b/code/game/machinery/computer/prisoner/management.dm new file mode 100644 index 0000000000..e231a1748a --- /dev/null +++ b/code/game/machinery/computer/prisoner/management.dm @@ -0,0 +1,139 @@ + +/obj/machinery/computer/prisoner/management + name = "prisoner management console" + desc = "Used to manage tracking implants placed inside criminals." + icon_screen = "explosive" + icon_keyboard = "security_key" + req_access = list(ACCESS_BRIG) + var/id = 0 + var/temp = null + var/status = 0 + var/timeleft = 60 + var/stop = 0 + var/screen = 0 // 0 - No Access Denied, 1 - Access allowed + circuit = /obj/item/circuitboard/computer/prisoner + + light_color = LIGHT_COLOR_RED + +/obj/machinery/computer/prisoner/management/ui_interact(mob/user) + . = ..() + if(isliving(user)) + playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) + var/dat = "" + if(screen == 0) + dat += "
{Log In}" + else if(screen == 1) + dat += "

Prisoner ID Management

" + if(contained_id) + dat += text("[contained_id]
") + dat += text("Collected Points: [contained_id.points]. Reset.
") + dat += text("Card goal: [contained_id.goal]. Set
") + dat += text("Space Law recommends quotas of 100 points per minute they would normally serve in the brig.
") + else + dat += text("Insert Prisoner ID.
") + dat += "

Prisoner Implant Management

" + dat += "
Chemical Implants
" + var/turf/Tr = null + for(var/obj/item/implant/chem/C in GLOB.tracked_chem_implants) + Tr = get_turf(C) + if((Tr) && (Tr.z != src.z)) + continue//Out of range + if(!C.imp_in) + continue + dat += "ID: [C.imp_in.name] | Remaining Units: [C.reagents.total_volume]
" + dat += "| Inject: " + dat += "((1))" + dat += "((5))" + dat += "((10))
" + dat += "********************************
" + dat += "
Tracking Implants
" + for(var/obj/item/implant/tracking/T in GLOB.tracked_implants) + if(!isliving(T.imp_in)) + continue + Tr = get_turf(T) + if((Tr) && (Tr.z != src.z)) + continue//Out of range + + var/loc_display = "Unknown" + var/mob/living/M = T.imp_in + if(is_station_level(Tr.z) && !isspaceturf(M.loc)) + var/turf/mob_loc = get_turf(M) + loc_display = mob_loc.loc + + dat += "ID: [T.imp_in.name] | Location: [loc_display]
" + dat += "(Message Holder) |
" + dat += "********************************
" + dat += "
{Log Out}" + var/datum/browser/popup = new(user, "computer", "Prisoner Management Console", 400, 500) + popup.set_content(dat) + popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) + popup.open() + return + +/obj/machinery/computer/prisoner/management/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/card/id)) + if(screen) + id_insert(user) + else + to_chat(user, "Unauthorized access.") + else + return ..() + +/obj/machinery/computer/prisoner/management/process() + if(!..()) + src.updateDialog() + return + +/obj/machinery/computer/prisoner/management/Topic(href, href_list) + if(..()) + return + if(usr.contents.Find(src) || (in_range(src, usr) && isturf(loc)) || issilicon(usr)) + usr.set_machine(src) + + if(href_list["id"]) + if(href_list["id"] =="insert" && !contained_id) + id_insert(usr) + else if(contained_id) + switch(href_list["id"]) + if("eject") + id_eject(usr) + if("reset") + contained_id.points = 0 + if("setgoal") + var/num = round(input(usr, "Choose prisoner's goal:", "Input an Integer", null) as num|null) + if(num >= 0) + num = min(num,1000) //Cap the quota to the equivilent of 10 minutes. + contained_id.goal = num + else if(href_list["inject1"]) + var/obj/item/implant/I = locate(href_list["inject1"]) in GLOB.tracked_chem_implants + if(I && istype(I)) + I.activate(1) + else if(href_list["inject5"]) + var/obj/item/implant/I = locate(href_list["inject5"]) in GLOB.tracked_chem_implants + if(I && istype(I)) + I.activate(5) + else if(href_list["inject10"]) + var/obj/item/implant/I = locate(href_list["inject10"]) in GLOB.tracked_chem_implants + if(I && istype(I)) + I.activate(10) + + else if(href_list["lock"]) + if(allowed(usr)) + screen = !screen + playsound(src, 'sound/machines/terminal_on.ogg', 50, FALSE) + else + to_chat(usr, "Unauthorized access.") + + else if(href_list["warn"]) + var/warning = copytext(sanitize(input(usr,"Message:","Enter your message here!","")),1,MAX_MESSAGE_LEN) + if(!warning) + return + var/obj/item/implant/I = locate(href_list["warn"]) in GLOB.tracked_implants + if(I && istype(I) && I.imp_in) + var/mob/living/R = I.imp_in + to_chat(R, "You hear a voice in your head saying: '[warning]'") + log_directed_talk(usr, R, warning, LOG_SAY, "implant message") + + src.add_fingerprint(usr) + src.updateUsrDialog() + return diff --git a/code/game/machinery/computer/security.dm b/code/game/machinery/computer/security.dm index 607f8dbe78..1823e34100 100644 --- a/code/game/machinery/computer/security.dm +++ b/code/game/machinery/computer/security.dm @@ -5,13 +5,10 @@ icon_keyboard = "security_key" req_one_access = list(ACCESS_SECURITY, ACCESS_FORENSICS_LOCKERS) circuit = /obj/item/circuitboard/computer/secure_data - var/obj/item/card/id/scan = null - var/authenticated = null var/rank = null var/screen = null var/datum/data/record/active1 = null var/datum/data/record/active2 = null - var/a_id = null var/temp = null var/printing = null var/can_change_id = 0 @@ -23,11 +20,6 @@ light_color = LIGHT_COLOR_RED -/obj/machinery/computer/secure_data/examine(mob/user) - ..() - if(scan) - to_chat(user, "Alt-click to eject the ID card.") - /obj/machinery/computer/secure_data/syndie icon_keyboard = "syndie_key" @@ -40,32 +32,19 @@ clockwork = TRUE //it'd look weird pass_flags = PASSTABLE -/obj/machinery/computer/secure_data/attackby(obj/item/O, mob/user, params) - if(istype(O, /obj/item/card/id)) - if(!scan) - if(!user.transferItemToLoc(O, src)) - return - scan = O - to_chat(user, "You insert [O].") - playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0) - updateUsrDialog() - else - to_chat(user, "There's already an ID card in the console.") - else - return ..() - //Someone needs to break down the dat += into chunks instead of long ass lines. /obj/machinery/computer/secure_data/ui_interact(mob/user) . = ..() + playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) if(src.z > 6) to_chat(user, "Unable to establish a connection: \black You're too far away from the station!") return var/dat if(temp) - dat = text("[]

Clear Screen", temp) + dat = "[temp]

Clear Screen" else - dat = text("Confirm Identity: []
", (scan ? text("[]", scan.name) : "----------")) + dat = "" if(authenticated) switch(screen) if(1) @@ -190,7 +169,7 @@ dat += {"
" var/column_counter = 0 for(var/list/category in list(GLOB.command_positions) + list(GLOB.engineering_positions) + list(GLOB.supply_positions) + list(GLOB.nonhuman_positions - "pAI") + list(GLOB.civilian_positions) + list(GLOB.medical_positions) + list(GLOB.science_positions) + list(GLOB.security_positions)) - var/cat_color = SSjob.name_occupations[category[1]].selection_color //use the color of the first job in the category (the department head) as the category color + var/cat_color = "fff" //random default + if(SSjob.name_occupations && SSjob.name_occupations[category[1]]) + cat_color = SSjob.name_occupations[category[1]].selection_color //use the color of the first job in the category (the department head) as the category color + else + cat_color = SSjob.occupations[category[1]].selection_color + dat += "
" dat += "[SSjob.name_occupations[category[1]].exp_type_department]" var/list/dept_dat = list() From 43affcb83118d1a7e9def4b70b420e7fb1045d19 Mon Sep 17 00:00:00 2001 From: Poojawa Date: Thu, 4 Jul 2019 00:52:48 -0500 Subject: [PATCH 003/222] properly fixes Quartermaster headrole, mind traits --- code/modules/jobs/job_types/captain.dm | 1 + code/modules/jobs/job_types/detective.dm | 2 +- code/modules/jobs/job_types/head_of_personnel.dm | 4 ++-- code/modules/jobs/job_types/head_of_security.dm | 2 +- code/modules/jobs/job_types/lawyer.dm | 2 +- code/modules/jobs/job_types/quartermaster.dm | 12 ++++++++++-- code/modules/jobs/job_types/security_officer.dm | 2 +- code/modules/jobs/job_types/warden.dm | 2 +- 8 files changed, 18 insertions(+), 9 deletions(-) diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm index e80840f8aa..e6cf7d1c5c 100755 --- a/code/modules/jobs/job_types/captain.dm +++ b/code/modules/jobs/job_types/captain.dm @@ -20,6 +20,7 @@ access = list() //See get_access() minimal_access = list() //See get_access() + mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) // mind_traits = list(TRAIT_DISK_VERIFIER) display_order = JOB_DISPLAY_ORDER_CAPTAIN diff --git a/code/modules/jobs/job_types/detective.dm b/code/modules/jobs/job_types/detective.dm index cfd9d5fdab..6c12c1db09 100644 --- a/code/modules/jobs/job_types/detective.dm +++ b/code/modules/jobs/job_types/detective.dm @@ -18,7 +18,7 @@ access = list(ACCESS_SEC_DOORS, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_COURT, ACCESS_BRIG, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) minimal_access = list(ACCESS_SEC_DOORS, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_COURT, ACCESS_BRIG, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) -// mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) + mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) display_order = JOB_DISPLAY_ORDER_DETECTIVE diff --git a/code/modules/jobs/job_types/head_of_personnel.dm b/code/modules/jobs/job_types/head_of_personnel.dm index a5d917e1c9..d658a49380 100644 --- a/code/modules/jobs/job_types/head_of_personnel.dm +++ b/code/modules/jobs/job_types/head_of_personnel.dm @@ -4,7 +4,7 @@ // auto_deadmin_role_flags = DEADMIN_POSITION_HEAD department_head = list("Captain") department_flag = CIVILIAN - head_announce = list("Supply", "Service") + head_announce = list("Service") faction = "Station" total_positions = 1 spawn_positions = 1 @@ -14,7 +14,7 @@ minimal_player_age = 10 exp_requirements = 180 exp_type = EXP_TYPE_CREW - exp_type_department = EXP_TYPE_SUPPLY + exp_type_department = EXP_TYPE_SERVICE outfit = /datum/outfit/job/hop diff --git a/code/modules/jobs/job_types/head_of_security.dm b/code/modules/jobs/job_types/head_of_security.dm index 9df087c834..0ca0e393ac 100644 --- a/code/modules/jobs/job_types/head_of_security.dm +++ b/code/modules/jobs/job_types/head_of_security.dm @@ -17,7 +17,7 @@ exp_type_department = EXP_TYPE_SECURITY outfit = /datum/outfit/job/hos -// mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) + mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_ALL_PERSONAL_LOCKERS, diff --git a/code/modules/jobs/job_types/lawyer.dm b/code/modules/jobs/job_types/lawyer.dm index a04f5b665c..0b8be52116 100644 --- a/code/modules/jobs/job_types/lawyer.dm +++ b/code/modules/jobs/job_types/lawyer.dm @@ -15,7 +15,7 @@ access = list(ACCESS_LAWYER, ACCESS_COURT, ACCESS_SEC_DOORS) minimal_access = list(ACCESS_LAWYER, ACCESS_COURT, ACCESS_SEC_DOORS) -// mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) + mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) display_order = JOB_DISPLAY_ORDER_LAWYER diff --git a/code/modules/jobs/job_types/quartermaster.dm b/code/modules/jobs/job_types/quartermaster.dm index 3220dd9a09..b85a4ad404 100644 --- a/code/modules/jobs/job_types/quartermaster.dm +++ b/code/modules/jobs/job_types/quartermaster.dm @@ -3,17 +3,25 @@ flag = QUARTERMASTER department_head = list("Captain") department_flag = CIVILIAN + head_announce = list("Supply") // auto_deadmin_role_flags = DEADMIN_POSITION_HEAD faction = "Station" total_positions = 1 spawn_positions = 1 supervisors = "the captain" selection_color = "#d7b088" + req_admin_notify = 1 + minimal_player_age = 7 + exp_requirements = 180 + exp_type = EXP_TYPE_CREW + exp_type_department = EXP_TYPE_SUPPLY outfit = /datum/outfit/job/quartermaster - access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM, ACCESS_VAULT) - minimal_access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM, ACCESS_VAULT) + access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, + ACCESS_MINERAL_STOREROOM, ACCESS_VAULT) + minimal_access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_QM, ACCESS_MINING, + ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM, ACCESS_VAULT) display_order = JOB_DISPLAY_ORDER_QUARTERMASTER diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm index 98ec759db8..05ba91aa4a 100644 --- a/code/modules/jobs/job_types/security_officer.dm +++ b/code/modules/jobs/job_types/security_officer.dm @@ -18,7 +18,7 @@ access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_FORENSICS_LOCKERS, ACCESS_MINERAL_STOREROOM) minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) // See /datum/job/officer/get_access() -// mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) + mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) display_order = JOB_DISPLAY_ORDER_SECURITY_OFFICER diff --git a/code/modules/jobs/job_types/warden.dm b/code/modules/jobs/job_types/warden.dm index b70281f099..821ce352f7 100644 --- a/code/modules/jobs/job_types/warden.dm +++ b/code/modules/jobs/job_types/warden.dm @@ -18,7 +18,7 @@ access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_FORENSICS_LOCKERS, ACCESS_MINERAL_STOREROOM) minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) // See /datum/job/warden/get_access() -// mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) + mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) display_order = JOB_DISPLAY_ORDER_WARDEN From 899c5fed7e0e3b6ab61408354badbc3bb005bf2a Mon Sep 17 00:00:00 2001 From: Poojawa Date: Thu, 4 Jul 2019 00:56:17 -0500 Subject: [PATCH 004/222] Oh this should be uncommented too. --- code/modules/jobs/job_types/_job.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm index 59af18b76d..ebf417acdd 100644 --- a/code/modules/jobs/job_types/_job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -64,9 +64,9 @@ //H is usually a human unless an /equip override transformed it /datum/job/proc/after_spawn(mob/living/H, mob/M, latejoin = FALSE) //do actions on H but send messages to M as the key may not have been transferred_yet -/* if(mind_traits) + if(mind_traits) for(var/t in mind_traits) - ADD_TRAIT(H.mind, t, JOB_TRAIT)*/ + ADD_TRAIT(H.mind, t, JOB_TRAIT) /datum/job/proc/announce(mob/living/carbon/human/H) if(head_announce) From fe148a9f7b6dfa809412277f589e671758e3cf11 Mon Sep 17 00:00:00 2001 From: Poojawa Date: Fri, 26 Jul 2019 17:37:46 -0500 Subject: [PATCH 005/222] Delete civilian.dm --- code/modules/jobs/job_types/civilian.dm | 206 ------------------------ 1 file changed, 206 deletions(-) delete mode 100644 code/modules/jobs/job_types/civilian.dm diff --git a/code/modules/jobs/job_types/civilian.dm b/code/modules/jobs/job_types/civilian.dm deleted file mode 100644 index feca1a402d..0000000000 --- a/code/modules/jobs/job_types/civilian.dm +++ /dev/null @@ -1,206 +0,0 @@ -/* -Clown -*/ -/datum/job/clown - title = "Clown" - flag = CLOWN - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the head of personnel" - selection_color = "#dddddd" - - outfit = /datum/outfit/job/clown - - access = list(ACCESS_THEATRE) - minimal_access = list(ACCESS_THEATRE) - -/datum/job/clown/after_spawn(mob/living/carbon/human/H, mob/M) - . = ..() - H.apply_pref_name("clown", M.client) - -/datum/outfit/job/clown - name = "Clown" - jobtype = /datum/job/clown - - belt = /obj/item/pda/clown - uniform = /obj/item/clothing/under/rank/clown - shoes = /obj/item/clothing/shoes/clown_shoes - mask = /obj/item/clothing/mask/gas/clown_hat - l_pocket = /obj/item/bikehorn - backpack_contents = list( - /obj/item/stamp/clown = 1, - /obj/item/reagent_containers/spray/waterflower = 1, - /obj/item/reagent_containers/food/snacks/grown/banana = 1, - /obj/item/instrument/bikehorn = 1, - ) - - implants = list(/obj/item/implant/sad_trombone) - - backpack = /obj/item/storage/backpack/clown - satchel = /obj/item/storage/backpack/clown - duffelbag = /obj/item/storage/backpack/duffelbag/clown //strangely has a duffel - - box = /obj/item/storage/box/hug/survival - - chameleon_extras = /obj/item/stamp/clown - - -/datum/outfit/job/clown/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - ..() - if(visualsOnly) - return - - H.fully_replace_character_name(H.real_name, pick(GLOB.clown_names)) - -/datum/outfit/job/clown/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - ..() - if(visualsOnly) - return - - H.dna.add_mutation(CLOWNMUT) - H.dna.add_mutation(SMILE) - -/* -Mime -*/ -/datum/job/mime - title = "Mime" - flag = MIME - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the head of personnel" - selection_color = "#dddddd" - - outfit = /datum/outfit/job/mime - - access = list(ACCESS_THEATRE) - minimal_access = list(ACCESS_THEATRE) - -/datum/job/mime/after_spawn(mob/living/carbon/human/H, mob/M) - H.apply_pref_name("mime", M.client) - -/datum/outfit/job/mime - name = "Mime" - jobtype = /datum/job/mime - - belt = /obj/item/pda/mime - uniform = /obj/item/clothing/under/rank/mime - mask = /obj/item/clothing/mask/gas/mime - gloves = /obj/item/clothing/gloves/color/white - head = /obj/item/clothing/head/frenchberet - suit = /obj/item/clothing/suit/suspenders - backpack_contents = list(/obj/item/reagent_containers/food/drinks/bottle/bottleofnothing=1) - - accessory = /obj/item/clothing/accessory/pocketprotector/cosmetology - backpack = /obj/item/storage/backpack/mime - satchel = /obj/item/storage/backpack/mime - - -/datum/outfit/job/mime/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - ..() - - if(visualsOnly) - return - - if(H.mind) - H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/mime_wall(null)) - H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/mime/speak(null)) - H.mind.miming = 1 - -/* -Curator -*/ -/datum/job/curator - title = "Curator" - flag = CURATOR - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the head of personnel" - selection_color = "#dddddd" - - outfit = /datum/outfit/job/curator - - access = list(ACCESS_LIBRARY) - minimal_access = list(ACCESS_LIBRARY, ACCESS_CONSTRUCTION,ACCESS_MINING_STATION) - -/datum/outfit/job/curator - name = "Curator" - jobtype = /datum/job/curator - - belt = /obj/item/pda/curator - uniform = /obj/item/clothing/under/rank/curator - l_hand = /obj/item/storage/bag/books - r_pocket = /obj/item/key/displaycase - l_pocket = /obj/item/laser_pointer - accessory = /obj/item/clothing/accessory/pocketprotector/full - backpack_contents = list( - /obj/item/melee/curator_whip = 1, - /obj/item/soapstone = 1, - /obj/item/barcodescanner = 1 - ) - - -/datum/outfit/job/curator/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - ..() - - if(visualsOnly) - return - - H.grant_all_languages(omnitongue=TRUE) -/* -Lawyer -*/ -/datum/job/lawyer - title = "Lawyer" - flag = LAWYER - department_head = list("Head of Personnel") - department_flag = CIVILIAN - faction = "Station" - total_positions = 2 - spawn_positions = 2 - supervisors = "the head of personnel" - selection_color = "#dddddd" - var/lawyers = 0 //Counts lawyer amount - - outfit = /datum/outfit/job/lawyer - - access = list(ACCESS_LAWYER, ACCESS_COURT, ACCESS_SEC_DOORS) - minimal_access = list(ACCESS_LAWYER, ACCESS_COURT, ACCESS_SEC_DOORS) - - mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) - -/datum/outfit/job/lawyer - name = "Lawyer" - jobtype = /datum/job/lawyer - - belt = /obj/item/pda/lawyer - ears = /obj/item/radio/headset/headset_sec - uniform = /obj/item/clothing/under/lawyer/bluesuit - suit = /obj/item/clothing/suit/toggle/lawyer - shoes = /obj/item/clothing/shoes/laceup - l_hand = /obj/item/storage/briefcase/lawyer - l_pocket = /obj/item/laser_pointer - r_pocket = /obj/item/clothing/accessory/lawyers_badge - - chameleon_extras = /obj/item/stamp/law - - -/datum/outfit/job/lawyer/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - ..() - if(visualsOnly) - return - - var/datum/job/lawyer/J = SSjob.GetJobType(jobtype) - J.lawyers++ - if(J.lawyers>1) - uniform = /obj/item/clothing/under/lawyer/purpsuit - suit = /obj/item/clothing/suit/toggle/lawyer/purple From 58a27fa082b21ad64a08cb2c4fe72f49df0ddad2 Mon Sep 17 00:00:00 2001 From: Poojawa Date: Wed, 31 Jul 2019 19:37:53 -0500 Subject: [PATCH 006/222] tabby boi --- code/modules/mob/dead/new_player/new_player.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index a74e11ea46..58de99945b 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -477,7 +477,7 @@ var/available_ghosts = 0 for(var/spawner in GLOB.mob_spawners) - if(!LAZYLEN(spawner)) + if(!LAZYLEN(spawner)) continue var/obj/effect/mob_spawn/S = pick(GLOB.mob_spawners[spawner]) if(!istype(S) || !S.can_latejoin()) From 1893a8f31994caeb18e43237229cb1a30082ef37 Mon Sep 17 00:00:00 2001 From: Poojawa Date: Thu, 1 Aug 2019 11:14:50 -0500 Subject: [PATCH 007/222] correctly copy/pasta's the chaplain stuff --- code/game/gamemodes/revolution/revolution.dm | 4 +- code/modules/jobs/job_types/chaplain.dm | 67 ++++++++++++++------ 2 files changed, 49 insertions(+), 22 deletions(-) diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm index 38dd128505..1f2aa8ad30 100644 --- a/code/game/gamemodes/revolution/revolution.dm +++ b/code/game/gamemodes/revolution/revolution.dm @@ -12,8 +12,8 @@ config_tag = "revolution" antag_flag = ROLE_REV false_report_weight = 10 - restricted_jobs = list("Security Officer", "Warden", "Detective", "AI", "Cyborg","Captain", "Head of Personnel", "Head of Security", "Chief Engineer", "Research Director", "Chief Medical Officer") - required_jobs = list(list("Captain"=1),list("Head of Personnel"=1),list("Head of Security"=1),list("Chief Engineer"=1),list("Research Director"=1),list("Chief Medical Officer"=1)) //Any head present + restricted_jobs = list("Security Officer", "Warden", "Detective", "AI", "Cyborg","Captain", "Head of Personnel", "Head of Security", "Chief Engineer", "Research Director", "Chief Medical Officer", "Quartermaster") + required_jobs = list(list("Captain"=1),list("Head of Personnel"=1),list("Head of Security"=1),list("Chief Engineer"=1),list("Research Director"=1),list("Chief Medical Officer"=1),list("Quartermaster"=1)) //Any head present required_players = 30 required_enemies = 2 recommended_enemies = 3 diff --git a/code/modules/jobs/job_types/chaplain.dm b/code/modules/jobs/job_types/chaplain.dm index 8de228db2a..f6648fdf86 100644 --- a/code/modules/jobs/job_types/chaplain.dm +++ b/code/modules/jobs/job_types/chaplain.dm @@ -1,6 +1,3 @@ -/* -Chaplain -*/ /datum/job/chaplain title = "Chaplain" flag = CHAPLAIN @@ -17,6 +14,9 @@ Chaplain access = list(ACCESS_MORGUE, ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_THEATRE) minimal_access = list(ACCESS_MORGUE, ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_THEATRE) + display_order = JOB_DISPLAY_ORDER_CHAPLAIN + + /datum/job/chaplain/after_spawn(mob/living/H, mob/M) . = ..() if(H.mind) @@ -36,11 +36,11 @@ Chaplain H.put_in_hands(N) return - var/new_religion = "Christianity" + var/new_religion = DEFAULT_RELIGION if(M.client && M.client.prefs.custom_names["religion"]) new_religion = M.client.prefs.custom_names["religion"] - var/new_deity = "Space Jesus" + var/new_deity = DEFAULT_DEITY if(M.client && M.client.prefs.custom_names["deity"]) new_deity = M.client.prefs.custom_names["deity"] @@ -48,29 +48,55 @@ Chaplain switch(lowertext(new_religion)) - if("christianity") + if("christianity") // DEFAULT_RELIGION B.name = pick("The Holy Bible","The Dead Sea Scrolls") - if("satanism") - B.name = "The Unholy Bible" - if("cthulhu") - B.name = "The Necronomicon" - if("islam") - B.name = "Quran" - if("scientology") - B.name = pick("The Biography of L. Ron Hubbard","Dianetics") + if("buddhism") + B.name = "The Sutras" + if("clownism","honkmother","honk","honkism","comedy") + B.name = pick("The Holy Joke Book", "Just a Prank", "Hymns to the Honkmother") if("chaos") B.name = "The Book of Lorgar" + if("cthulhu") + B.name = "The Necronomicon" + if("hinduism") + B.name = "The Vedas" + if("homosexuality") + B.name = pick("Guys Gone Wild","Coming Out of The Closet") if("imperium") B.name = "Uplifting Primer" - if("toolboxia") - B.name = "Toolbox Manifesto" - if("homosexuality") - B.name = "Guys Gone Wild" + if("islam") + B.name = "Quran" + if("judaism") + B.name = "The Torah" + if("lampism") + B.name = "Fluorescent Incandescence" if("lol", "wtf", "gay", "penis", "ass", "poo", "badmin", "shitmin", "deadmin", "cock", "cocks", "meme", "memes") - B.name = pick("Woodys Got Wood: The Aftermath", "War of the Cocks", "Sweet Bro and Hella Jef: Expanded Edition") + B.name = pick("Woodys Got Wood: The Aftermath", "War of the Cocks", "Sweet Bro and Hella Jef: Expanded Edition","F.A.T.A.L. Rulebook") H.adjustBrainLoss(100) // starts off retarded as fuck + if("monkeyism","apism","gorillism","primatism") + B.name = pick("Going Bananas", "Bananas Out For Harambe") + if("mormonism") + B.name = "The Book of Mormon" + if("pastafarianism") + B.name = "The Gospel of the Flying Spaghetti Monster" + if("rastafarianism","rasta") + B.name = "The Holy Piby" + if("satanism") + B.name = "The Unholy Bible" if("science") B.name = pick("Principle of Relativity", "Quantum Enigma: Physics Encounters Consciousness", "Programming the Universe", "Quantum Physics and Theology", "String Theory for Dummies", "How To: Build Your Own Warp Drive", "The Mysteries of Bluespace", "Playing God: Collector's Edition") + if("scientology") + B.name = pick("The Biography of L. Ron Hubbard","Dianetics") + if("servicianism", "partying") + B.name = "The Tenets of Servicia" + B.deity_name = pick("Servicia", "Space Bacchus", "Space Dionysus") + B.desc = "Happy, Full, Clean. Live it and give it." + if("subgenius") + B.name = "Book of the SubGenius" + if("toolboxia","greytide") + B.name = pick("Toolbox Manifesto","iGlove Assistants") + if("weeaboo","kawaii") + B.name = pick("Fanfiction Compendium","Japanese for Dummies","The Manganomicon","Establishing Your O.T.P") else B.name = "The Holy Book of [new_religion]" @@ -88,7 +114,8 @@ Chaplain jobtype = /datum/job/chaplain belt = /obj/item/pda/chaplain + ears = /obj/item/radio/headset/headset_srv uniform = /obj/item/clothing/under/rank/chaplain backpack_contents = list(/obj/item/camera/spooky = 1) backpack = /obj/item/storage/backpack/cultpack - satchel = /obj/item/storage/backpack/cultpack + satchel = /obj/item/storage/backpack/cultpack \ No newline at end of file From f59b60e83a09c1cf65c4bc9f160999233fafcfab Mon Sep 17 00:00:00 2001 From: Sishen Date: Thu, 8 Aug 2019 01:11:20 -0400 Subject: [PATCH 008/222] QOL OOGA BOOGA --- _maps/map_files/BoxStation/BoxStation.dmm | 6 +- .../map_files/Deltastation/DeltaStation2.dmm | 14 +- _maps/map_files/MetaStation/MetaStation.dmm | 8 +- _maps/map_files/PubbyStation/PubbyStation.dmm | 6 +- _maps/map_files/debug/runtimestation.dmm | 2 +- _maps/map_files/generic/CentCom.dmm | 6 +- code/game/machinery/_machinery.dm | 116 ++++++- code/game/machinery/computer/apc_control.dm | 1 - code/game/machinery/computer/card.dm | 3 - .../game/machinery/computer/communications.dm | 1 - code/game/machinery/computer/medical.dm | 286 +++++++++--------- code/game/machinery/computer/prisoner.dm | 142 --------- .../machinery/computer/prisoner/_prisoner.dm | 52 ++++ .../computer/prisoner/gulag_teleporter.dm | 142 +++++++++ .../machinery/computer/prisoner/management.dm | 139 +++++++++ code/game/machinery/computer/security.dm | 115 +++---- code/game/machinery/gulag_item_reclaimer.dm | 41 +-- .../circuitboards/computer_circuitboards.dm | 7 +- code/modules/mining/laborcamp/laborstacker.dm | 70 ++--- code/modules/mining/machine_redemption.dm | 61 ++-- code/modules/mining/machine_vending.dm | 119 ++------ tgstation.dme | 3 + tgui/src/interfaces/gulag_item_reclaimer.ract | 5 +- tgui/src/interfaces/labor_claim_console.ract | 25 +- .../interfaces/ore_redemption_machine.ract | 18 +- 25 files changed, 726 insertions(+), 662 deletions(-) create mode 100644 code/game/machinery/computer/prisoner/_prisoner.dm create mode 100644 code/game/machinery/computer/prisoner/gulag_teleporter.dm create mode 100644 code/game/machinery/computer/prisoner/management.dm diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm index 980e23188a..7350b4f0c6 100644 --- a/_maps/map_files/BoxStation/BoxStation.dmm +++ b/_maps/map_files/BoxStation/BoxStation.dmm @@ -2924,7 +2924,7 @@ /turf/open/floor/plasteel/showroomfloor, /area/security/warden) "agp" = ( -/obj/machinery/computer/prisoner, +/obj/machinery/computer/prisoner/management, /turf/open/floor/plasteel/showroomfloor, /area/security/warden) "agq" = ( @@ -4489,7 +4489,7 @@ /turf/open/space, /area/solar/port/fore) "ajr" = ( -/obj/machinery/computer/gulag_teleporter_computer, +/obj/machinery/computer/prisoner/gulag_teleporter_computer, /turf/open/floor/plasteel, /area/security/processing) "ajs" = ( @@ -19371,7 +19371,7 @@ /turf/closed/wall, /area/bridge) "aTR" = ( -/obj/machinery/computer/prisoner, +/obj/machinery/computer/prisoner/management, /obj/effect/turf_decal/tile/red{ dir = 1 }, diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index fd7c0a3c00..88f3704091 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -4503,7 +4503,7 @@ /turf/open/floor/plasteel, /area/security/checkpoint) "anx" = ( -/obj/machinery/computer/prisoner{ +/obj/machinery/computer/prisoner/management{ dir = 8 }, /obj/machinery/status_display{ @@ -36400,7 +36400,7 @@ /turf/open/floor/plasteel/grimy, /area/crew_quarters/heads/hos) "boc" = ( -/obj/machinery/computer/prisoner{ +/obj/machinery/computer/prisoner/management{ dir = 8 }, /turf/open/floor/plasteel/grimy, @@ -38706,7 +38706,7 @@ /turf/open/floor/plasteel/grimy, /area/crew_quarters/heads/hos) "brE" = ( -/obj/machinery/computer/prisoner{ +/obj/machinery/computer/prisoner/management{ dir = 8 }, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ @@ -39610,7 +39610,7 @@ /turf/open/floor/plasteel/dark, /area/security/execution/transfer) "bth" = ( -/obj/machinery/computer/gulag_teleporter_computer{ +/obj/machinery/computer/prisoner/gulag_teleporter_computer{ dir = 1 }, /obj/structure/disposalpipe/segment{ @@ -42723,7 +42723,7 @@ /turf/open/floor/plasteel/dark, /area/bridge) "byk" = ( -/obj/machinery/computer/prisoner, +/obj/machinery/computer/prisoner/management, /obj/effect/turf_decal/tile/red{ dir = 1 }, @@ -56938,7 +56938,7 @@ /turf/open/floor/plasteel, /area/security/warden) "bTh" = ( -/obj/machinery/computer/prisoner{ +/obj/machinery/computer/prisoner/management{ dir = 8 }, /obj/structure/cable/white{ @@ -125921,7 +125921,7 @@ /turf/open/floor/plasteel, /area/security/checkpoint/escape) "egj" = ( -/obj/machinery/computer/prisoner{ +/obj/machinery/computer/prisoner/management{ dir = 1 }, /obj/structure/cable/white{ diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index 75d7466371..13f774d25d 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -2017,7 +2017,7 @@ /turf/open/floor/plasteel/dark, /area/crew_quarters/heads/hos) "aeu" = ( -/obj/machinery/computer/prisoner, +/obj/machinery/computer/prisoner/management, /turf/open/floor/plasteel/dark, /area/crew_quarters/heads/hos) "aev" = ( @@ -8416,7 +8416,7 @@ /turf/open/floor/plating, /area/security/warden) "apI" = ( -/obj/machinery/computer/prisoner{ +/obj/machinery/computer/prisoner/management{ dir = 4 }, /obj/structure/cable/yellow{ @@ -10514,7 +10514,7 @@ /turf/open/floor/plating, /area/maintenance/port/fore) "atK" = ( -/obj/machinery/computer/gulag_teleporter_computer{ +/obj/machinery/computer/prisoner/gulag_teleporter_computer{ dir = 1 }, /turf/open/floor/plasteel/dark, @@ -30781,7 +30781,7 @@ /obj/structure/cable/yellow{ icon_state = "2-4" }, -/obj/machinery/computer/prisoner, +/obj/machinery/computer/prisoner/management, /obj/effect/turf_decal/tile/red{ dir = 1 }, diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm index ee97af14fc..2e8887c75f 100644 --- a/_maps/map_files/PubbyStation/PubbyStation.dmm +++ b/_maps/map_files/PubbyStation/PubbyStation.dmm @@ -4897,7 +4897,7 @@ /turf/open/floor/plasteel/showroomfloor, /area/security/warden) "amT" = ( -/obj/machinery/computer/prisoner, +/obj/machinery/computer/prisoner/management, /obj/machinery/airalarm{ pixel_y = 22 }, @@ -6072,7 +6072,7 @@ /turf/open/floor/plating, /area/security/brig) "apF" = ( -/obj/machinery/computer/gulag_teleporter_computer{ +/obj/machinery/computer/prisoner/gulag_teleporter_computer{ dir = 1 }, /turf/open/floor/plasteel/dark, @@ -7048,7 +7048,7 @@ /turf/open/floor/plasteel/dark, /area/bridge) "arR" = ( -/obj/machinery/computer/prisoner, +/obj/machinery/computer/prisoner/management, /obj/effect/turf_decal/tile/red{ dir = 1 }, diff --git a/_maps/map_files/debug/runtimestation.dmm b/_maps/map_files/debug/runtimestation.dmm index 3bdf64ac27..feb8fc8cc0 100644 --- a/_maps/map_files/debug/runtimestation.dmm +++ b/_maps/map_files/debug/runtimestation.dmm @@ -523,7 +523,7 @@ /turf/open/floor/plasteel, /area/science) "bC" = ( -/obj/machinery/computer/gulag_teleporter_computer{ +/obj/machinery/computer/prisoner/gulag_teleporter_computer{ dir = 4 }, /turf/open/floor/plasteel, diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm index 115ad3d363..8d743b7f71 100644 --- a/_maps/map_files/generic/CentCom.dmm +++ b/_maps/map_files/generic/CentCom.dmm @@ -3864,7 +3864,7 @@ /turf/open/floor/plasteel, /area/centcom/control) "jS" = ( -/obj/machinery/computer/prisoner, +/obj/machinery/computer/prisoner/management, /obj/effect/turf_decal/stripes/line, /turf/open/floor/plasteel, /area/centcom/control) @@ -5857,7 +5857,7 @@ /turf/open/floor/plasteel, /area/centcom/control) "nY" = ( -/obj/machinery/computer/prisoner{ +/obj/machinery/computer/prisoner/management{ dir = 1 }, /obj/effect/turf_decal/stripes/line{ @@ -10495,7 +10495,7 @@ /turf/open/floor/plasteel/dark, /area/centcom/control) "yv" = ( -/obj/machinery/computer/prisoner{ +/obj/machinery/computer/prisoner/management{ dir = 1 }, /obj/machinery/light, diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index b0e4c699d7..e5fd73228a 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -113,6 +113,11 @@ Class Procs: var/atom/movable/occupant = null var/speed_process = FALSE // Process as fast as possible? var/obj/item/circuitboard/circuit // Circuit to be created and inserted when the machinery is created + var/obj/item/card/id/inserted_scan_id + var/obj/item/card/id/inserted_modify_id + var/list/region_access = null // For the identification console (card.dm) + var/list/head_subordinates = null // For the identification console (card.dm) + var/authenticated = 0 // For the identification console (card.dm) var/interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON | INTERACT_MACHINE_SET_MACHINE @@ -131,7 +136,7 @@ Class Procs: else START_PROCESSING(SSfastprocess, src) power_change() - AddComponent(/datum/component/redirect, list(COMSIG_ENTER_AREA = CALLBACK(src, .proc/power_change))) + RegisterSignal(src, COMSIG_ENTER_AREA, .proc/power_change) if (occupant_typecache) occupant_typecache = typecacheof(occupant_typecache) @@ -143,6 +148,10 @@ Class Procs: else STOP_PROCESSING(SSfastprocess, src) dropContents() + if(length(component_parts)) + for(var/atom/A in component_parts) + qdel(A) + component_parts.Cut() return ..() /obj/machinery/proc/locate_machinery() @@ -179,12 +188,15 @@ Class Procs: L.update_canmove() occupant = null +/obj/machinery/proc/can_be_occupant(atom/movable/am) + return occupant_typecache ? is_type_in_typecache(am, occupant_typecache) : isliving(am) + /obj/machinery/proc/close_machine(atom/movable/target = null) state_open = FALSE density = TRUE if(!target) for(var/am in loc) - if (!(occupant_typecache ? is_type_in_typecache(am, occupant_typecache) : isliving(am))) + if (!(can_be_occupant(am))) continue var/atom/movable/AM = am if(AM.has_buckled_mobs()) @@ -311,6 +323,7 @@ Class Procs: spawn_frame(disassembled) for(var/obj/item/I in component_parts) I.forceMove(loc) + component_parts.Cut() qdel(src) /obj/machinery/proc/spawn_frame(disassembled) @@ -348,8 +361,8 @@ Class Procs: panel_open = FALSE icon_state = icon_state_closed to_chat(user, "You close the maintenance hatch of [src].") - return 1 - return 0 + return TRUE + return FALSE /obj/machinery/proc/default_change_direction_wrench(mob/user, obj/item/I) if(panel_open && I.tool_behaviour == TOOL_WRENCH) @@ -401,7 +414,7 @@ Class Procs: var/obj/item/circuitboard/machine/CB = locate(/obj/item/circuitboard/machine) in component_parts var/P if(W.works_from_distance) - display_parts(user) + to_chat(user, display_parts(user)) for(var/obj/item/A in component_parts) for(var/D in CB.req_components) if(ispath(A.type, D)) @@ -429,34 +442,38 @@ Class Procs: break RefreshParts() else - display_parts(user) + to_chat(user, display_parts(user)) if(shouldplaysound) W.play_rped_sound() return TRUE return FALSE /obj/machinery/proc/display_parts(mob/user) - to_chat(user, "It contains the following parts:") + . = list() + . += "It contains the following parts:" for(var/obj/item/C in component_parts) - to_chat(user, "[icon2html(C, user)] \A [C].") + . += "[icon2html(C, user)] \A [C]." + . = jointext(., "") /obj/machinery/examine(mob/user) - ..() + . = ..() if(stat & BROKEN) - to_chat(user, "It looks broken and non-functional.") + . += "It looks broken and non-functional." if(!(resistance_flags & INDESTRUCTIBLE)) if(resistance_flags & ON_FIRE) - to_chat(user, "It's on fire!") + . += "It's on fire!" var/healthpercent = (obj_integrity/max_integrity) * 100 switch(healthpercent) if(50 to 99) - to_chat(user, "It looks slightly damaged.") + . += "It looks slightly damaged." if(25 to 50) - to_chat(user, "It appears heavily damaged.") + . += "It appears heavily damaged." if(0 to 25) - to_chat(user, "It's falling apart!") + . += "It's falling apart!" if(user.research_scanner && component_parts) - display_parts(user) + . += display_parts(user, TRUE) + if(inserted_scan_id || inserted_modify_id) + . += "Alt-click to eject the ID card." //called on machinery construction (i.e from frame to machinery) but not on initialization /obj/machinery/proc/on_construction() @@ -490,3 +507,72 @@ Class Procs: . = . % 9 AM.pixel_x = -8 + ((.%3)*8) AM.pixel_y = -8 + (round( . / 3)*8) + +/obj/machinery/proc/id_insert_scan(mob/user, obj/item/card/id/I) + I = user.get_active_held_item() + if(istype(I)) + if(inserted_scan_id) + to_chat(user, "There's already an ID card in the console!") + return + if(!user.transferItemToLoc(I, src)) + return + inserted_scan_id = I + user.visible_message("[user] inserts an ID card into the console.", \ + "You insert the ID card into the console.") + playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + updateUsrDialog() + +/obj/machinery/proc/id_eject_scan(mob/user) + if(!inserted_scan_id) + to_chat(user, "There's no ID card in the console!") + return + if(inserted_scan_id) + inserted_scan_id.forceMove(drop_location()) + if(!issilicon(user) && Adjacent(user)) + user.put_in_hands(inserted_scan_id) + inserted_scan_id = null + user.visible_message("[user] gets an ID card from the console.", \ + "You get the ID card from the console.") + playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + updateUsrDialog() + +/obj/machinery/proc/id_eject_modify(mob/user) + if(inserted_modify_id) + GLOB.data_core.manifest_modify(inserted_modify_id.registered_name, inserted_modify_id.assignment) + inserted_modify_id.update_label() + inserted_modify_id.forceMove(drop_location()) + if(!issilicon(user) && Adjacent(user)) + user.put_in_hands(inserted_modify_id) + user.visible_message("[user] gets an ID card from the console.", \ + "You get the ID card from the console.") + playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + inserted_modify_id = null + region_access = null + head_subordinates = null + updateUsrDialog() + +/obj/machinery/proc/id_insert_modify(mob/user) + var/obj/item/card/id/I = user.get_active_held_item() + if(istype(I)) + if(inserted_modify_id) + to_chat(user, "There's already an ID card in the console!") + return + if(!user.transferItemToLoc(I, src)) + return + inserted_modify_id = I + user.visible_message("[user] inserts an ID card into the console.", \ + "You insert the ID card into the console.") + playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + updateUsrDialog() + +/obj/machinery/AltClick(mob/user) + if(!user.canUseTopic(src, !issilicon(user)) || !is_operational()) + return + if(inserted_modify_id) + id_eject_modify(user) + authenticated = FALSE + return + if(inserted_scan_id) + id_eject_scan(user) + authenticated = FALSE + return diff --git a/code/game/machinery/computer/apc_control.dm b/code/game/machinery/computer/apc_control.dm index e51d623c2f..d433c55724 100644 --- a/code/game/machinery/computer/apc_control.dm +++ b/code/game/machinery/computer/apc_control.dm @@ -11,7 +11,6 @@ var/list/result_filters //For sorting the results var/checking_logs = 0 var/list/logs - var/authenticated = 0 var/auth_id = "\[NULL\]" /obj/machinery/computer/apc_control/Initialize() diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm index 09bf401e12..0cce853c49 100644 --- a/code/game/machinery/computer/card.dm +++ b/code/game/machinery/computer/card.dm @@ -13,11 +13,8 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0) circuit = /obj/item/circuitboard/computer/card var/obj/item/card/id/scan = null var/obj/item/card/id/modify = null - var/authenticated = 0 var/mode = 0 var/printing = null - var/list/region_access = null - var/list/head_subordinates = null var/target_dept = 0 //Which department this computer has access to. 0=all departments //Cooldown for closing positions in seconds diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 752765baa1..c79fb385b3 100755 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -6,7 +6,6 @@ icon_keyboard = "tech_key" req_access = list(ACCESS_HEADS) circuit = /obj/item/circuitboard/computer/communications - var/authenticated = 0 var/auth_id = "Unknown" //Who is currently logged in? var/list/datum/comm_message/messages = list() var/datum/comm_message/currmsg diff --git a/code/game/machinery/computer/medical.dm b/code/game/machinery/computer/medical.dm index 8af83ae08e..d4fe3e27a2 100644 --- a/code/game/machinery/computer/medical.dm +++ b/code/game/machinery/computer/medical.dm @@ -7,13 +7,10 @@ icon_keyboard = "med_key" req_one_access = list(ACCESS_MEDICAL, ACCESS_FORENSICS_LOCKERS) circuit = /obj/item/circuitboard/computer/med_data - var/obj/item/card/id/scan = null - var/authenticated = null var/rank = null var/screen = null var/datum/data/record/active1 var/datum/data/record/active2 - var/a_id = null var/temp = null var/printing = null //Sorting Variables @@ -25,24 +22,22 @@ /obj/machinery/computer/med_data/syndie icon_keyboard = "syndie_key" -/obj/machinery/computer/med_data/attackby(obj/item/O, mob/user, params) - if(istype(O, /obj/item/card/id) && !scan) - if(!user.transferItemToLoc(O, src)) - return - scan = O - to_chat(user, "You insert [O].") +/obj/machinery/computer/med_data/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/card/id)) + id_insert_scan(user) else return ..() /obj/machinery/computer/med_data/ui_interact(mob/user) . = ..() + if(isliving(user)) + playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) var/dat if(temp) dat = text("[temp]

Clear Screen") else - dat = text("Confirm Identity: []
", (src.scan ? text("[]", src.scan.name) : "----------")) - if(src.authenticated) - switch(src.screen) + if(authenticated) + switch(screen) if(1) dat += {" Search Records @@ -116,7 +111,7 @@ dat += "
ID:[active1.fields["id"]]
Sex: [active1.fields["sex"]] 
Gender: [active1.fields["gender"]] 
Age: [active1.fields["age"]] 
Species: [active1.fields["species"]] 
Fingerprint: [active1.fields["fingerprint"]] 

Comments/Log
[active2.fields[text("com_[]", counter)]]
Delete Entry
Add Entry
\s*$/g,rb={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"
- + "} dat += "" dat += {" @@ -309,36 +288,39 @@ What a mess.*/ active1 = null active2 = null - if("Confirm Identity") - eject_id(usr) - if("Log Out") authenticated = null screen = null active1 = null active2 = null + playsound(src, 'sound/machines/terminal_off.ogg', 50, FALSE) if("Log In") - if(issilicon(usr)) - var/mob/living/silicon/borg = usr + var/mob/M = usr + var/obj/item/card/id/I = M.get_idcard(TRUE) + if(issilicon(M)) + var/mob/living/silicon/borg = M active1 = null active2 = null authenticated = borg.name rank = "AI" screen = 1 - else if(IsAdminGhost(usr)) + else if(IsAdminGhost(M)) active1 = null active2 = null - authenticated = usr.client.holder.admin_signature + authenticated = M.client.holder.admin_signature rank = "Central Command" screen = 1 - else if(istype(scan, /obj/item/card/id)) + else if(I && check_access(I)) active1 = null active2 = null - if(check_access(scan)) - authenticated = scan.registered_name - rank = scan.assignment - screen = 1 + authenticated = I.registered_name + rank = I.assignment + screen = 1 + else + to_chat(usr, "Unauthorized Access.") + playsound(src, 'sound/machines/terminal_on.ogg', 50, FALSE) + //RECORD FUNCTIONS if("Record Maintenance") screen = 2 @@ -346,16 +328,14 @@ What a mess.*/ active2 = null if("Browse Record") - var/datum/data/record/R = locate(href_list["d_rec"]) - var/S = locate(href_list["d_rec"]) - if(!( GLOB.data_core.general.Find(R) )) + var/datum/data/record/R = locate(href_list["d_rec"]) in GLOB.data_core.general + if(!R) temp = "Record Not Found!" else + active1 = active2 = R for(var/datum/data/record/E in GLOB.data_core.security) if((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) - S = E - active1 = R - active2 = S + active2 = E screen = 3 @@ -368,7 +348,7 @@ What a mess.*/ var/obj/item/paper/P = new /obj/item/paper( loc ) P.info = "
Security Record - (SR-[GLOB.data_core.securityPrintCount])

" if((istype(active1, /datum/data/record) && GLOB.data_core.general.Find(active1))) - P.info += text("Name: [] ID: []
\nSex: []
\nAge: []
", active1.fields["name"], active1.fields["id"], active1.fields["sex"], active1.fields["age"]) + P.info += text("Name: [] ID: []
\nGender: []
\nAge: []
", active1.fields["name"], active1.fields["id"], active1.fields["gender"], active1.fields["age"]) P.info += "\nSpecies: [active1.fields["species"]]
" P.info += text("\nFingerprint: []
\nPhysical Status: []
\nMental Status: []
", active1.fields["fingerprint"], active1.fields["p_stat"], active1.fields["m_stat"]) else @@ -419,6 +399,7 @@ What a mess.*/ P.info += "Security Record Lost!
" P.name = text("SR-[] '[]'", GLOB.data_core.securityPrintCount, "Record Lost") P.info += "" + P.update_icon() printing = null if("Print Poster") if(!( printing )) @@ -512,7 +493,7 @@ What a mess.*/ G.fields["name"] = "New Record" G.fields["id"] = "[num2hex(rand(1, 1.6777215E7), 6)]" G.fields["rank"] = "Unassigned" - G.fields["sex"] = "Male" + G.fields["gender"] = "Male" G.fields["age"] = "Unknown" G.fields["species"] = "Human" G.fields["photo_front"] = new /icon() @@ -584,12 +565,14 @@ What a mess.*/ if(!canUseSecurityRecordsConsole(usr, t1, a1)) return active1.fields["fingerprint"] = t1 - if("sex") + if("gender") if(istype(active1, /datum/data/record)) - if(active1.fields["sex"] == "Male") - active1.fields["sex"] = "Female" + if(active1.fields["gender"] == "Male") + active1.fields["gender"] = "Female" + else if(active1.fields["gender"] == "Female") + active1.fields["gender"] = "Other" else - active1.fields["sex"] = "Male" + active1.fields["gender"] = "Male" if("age") if(istype(active1, /datum/data/record)) var/t1 = input("Please input age:", "Secure. records", active1.fields["age"], null) as num @@ -767,19 +750,14 @@ What a mess.*/ P = user.get_active_held_item() return P -/obj/machinery/computer/secure_data/proc/print_photo(icon/temp, name) +/obj/machinery/computer/secure_data/proc/print_photo(icon/temp, person_name) if (printing) return printing = TRUE sleep(20) var/obj/item/photo/P = new/obj/item/photo(drop_location()) - var/icon/small_img = icon(temp) - var/icon/ic = icon('icons/obj/items_and_weapons.dmi',"photo") - small_img.Scale(8, 8) - ic.Blend(small_img,ICON_OVERLAY, 13, 13) - P.icon = ic - P.picture.picture_image = temp - P.desc = "The photo on file for [name]." + var/datum/picture/toEmbed = new(name = person_name, desc = "The photo on file for [person_name].", image = temp) + P.set_picture(toEmbed, TRUE, TRUE) P.pixel_x = rand(-10, 10) P.pixel_y = rand(-10, 10) printing = FALSE @@ -799,7 +777,7 @@ What a mess.*/ else R.fields["name"] = "[pick(pick(GLOB.first_names_male), pick(GLOB.first_names_female))] [pick(GLOB.last_names)]" if(2) - R.fields["sex"] = pick("Male", "Female") + R.fields["gender"] = pick("Male", "Female", "Other") if(3) R.fields["age"] = rand(5, 85) if(4) @@ -823,7 +801,7 @@ What a mess.*/ /obj/machinery/computer/secure_data/proc/canUseSecurityRecordsConsole(mob/user, message1 = 0, record1, record2) if(user) if(authenticated) - if(user.canUseTopic(src)) + if(user.canUseTopic(src, BE_CLOSE)) if(!trim(message1)) return 0 if(!record1 || record1 == active1) @@ -831,22 +809,3 @@ What a mess.*/ return 1 return 0 -/obj/machinery/computer/secure_data/AltClick(mob/user) - if(user.canUseTopic(src)) - eject_id(user) - -/obj/machinery/computer/secure_data/proc/eject_id(mob/user) - if(scan) - scan.forceMove(drop_location()) - if(!issilicon(user) && Adjacent(user)) - user.put_in_hands(scan) - scan = null - playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0) - else //switching the ID with the one you're holding - if(issilicon(user) || !Adjacent(user)) - return - var/obj/item/card/id/held_id = user.is_holding_item_of_type(/obj/item/card/id) - if(QDELETED(held_id) || !user.transferItemToLoc(held_id, src)) - return - scan = held_id - playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0) diff --git a/code/game/machinery/gulag_item_reclaimer.dm b/code/game/machinery/gulag_item_reclaimer.dm index f6cb58bbbc..89ec0dec7a 100644 --- a/code/game/machinery/gulag_item_reclaimer.dm +++ b/code/game/machinery/gulag_item_reclaimer.dm @@ -9,7 +9,6 @@ idle_power_usage = 100 active_power_usage = 2500 var/list/stored_items = list() - var/obj/item/card/id/prisoner/inserted_id = null var/obj/machinery/gulag_teleporter/linked_teleporter = null /obj/machinery/gulag_item_reclaimer/Destroy() @@ -18,9 +17,6 @@ I.forceMove(get_turf(src)) if(linked_teleporter) linked_teleporter.linked_reclaimer = null - if(inserted_id) - inserted_id.forceMove(get_turf(src)) - inserted_id = null return ..() /obj/machinery/gulag_item_reclaimer/emag_act(mob/user) @@ -29,18 +25,6 @@ req_access = list() obj_flags |= EMAGGED -/obj/machinery/gulag_item_reclaimer/attackby(obj/item/I, mob/user) - if(istype(I, /obj/item/card/id)) - if(!inserted_id) - if(!user.transferItemToLoc(I, src)) - return - inserted_id = I - to_chat(user, "You insert [I].") - return - else - to_chat(user, "There's an ID inserted already.") - return ..() - /obj/machinery/gulag_item_reclaimer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) @@ -55,15 +39,19 @@ if(allowed(user)) can_reclaim = TRUE - if(inserted_id) - data["id"] = inserted_id - data["id_name"] = inserted_id.registered_name - if(inserted_id.points >= inserted_id.goal) + var/obj/item/card/id/I = user.get_idcard(TRUE) + if(istype(I, /obj/item/card/id/prisoner)) + var/obj/item/card/id/prisoner/P = I + if(P.points >= P.goal) can_reclaim = TRUE var/list/mobs = list() for(var/i in stored_items) var/mob/thismob = i + if(QDELETED(thismob)) + say("Alert! Unable to locate vital signals of a previously processed prisoner. Ejecting equipment!") + drop_items(thismob) + continue var/list/mob_info = list() mob_info["name"] = thismob.real_name mob_info["mob"] = "[REF(thismob)]" @@ -78,16 +66,6 @@ /obj/machinery/gulag_item_reclaimer/ui_act(action, list/params) switch(action) - if("handle_id") - if(inserted_id) - usr.put_in_hands(inserted_id) - inserted_id = null - else - var/obj/item/I = usr.is_holding_item_of_type(/obj/item/card/id) - if(I) - if(!usr.transferItemToLoc(I, src)) - return - inserted_id = I if("release_items") var/mob/M = locate(params["mobref"]) if(M == usr || allowed(usr)) @@ -98,8 +76,9 @@ /obj/machinery/gulag_item_reclaimer/proc/drop_items(mob/user) if(!stored_items[user]) return + var/drop_location = drop_location() for(var/i in stored_items[user]) var/obj/item/W = i stored_items[user] -= W - W.forceMove(get_turf(src)) + W.forceMove(drop_location) stored_items -= user diff --git a/code/game/objects/items/circuitboards/computer_circuitboards.dm b/code/game/objects/items/circuitboards/computer_circuitboards.dm index 7d2ffe0a02..9035c8d47c 100644 --- a/code/game/objects/items/circuitboards/computer_circuitboards.dm +++ b/code/game/objects/items/circuitboards/computer_circuitboards.dm @@ -162,10 +162,11 @@ /obj/item/circuitboard/computer/prisoner name = "Prisoner Management Console (Computer Board)" - build_path = /obj/machinery/computer/prisoner + build_path = /obj/machinery/computer/prisoner/management + /obj/item/circuitboard/computer/gulag_teleporter_console name = "Labor Camp teleporter console (Computer Board)" - build_path = /obj/machinery/computer/gulag_teleporter_computer + build_path = /obj/machinery/computer/prisoner/gulag_teleporter_computer /obj/item/circuitboard/computer/rdconsole/production name = "R&D Console Production Only (Computer Board)" @@ -366,4 +367,4 @@ /obj/item/circuitboard/computer/nanite_cloud_controller name = "Nanite Cloud Control (Computer Board)" - build_path = /obj/machinery/computer/nanite_cloud_controller \ No newline at end of file + build_path = /obj/machinery/computer/nanite_cloud_controller diff --git a/code/modules/mining/laborcamp/laborstacker.dm b/code/modules/mining/laborcamp/laborstacker.dm index 4a628c5f34..b8a536279d 100644 --- a/code/modules/mining/laborcamp/laborstacker.dm +++ b/code/modules/mining/laborcamp/laborstacker.dm @@ -10,12 +10,10 @@ GLOBAL_LIST(labor_sheet_values) density = FALSE var/obj/machinery/mineral/stacking_machine/laborstacker/stacking_machine = null var/machinedir = SOUTH - var/obj/item/card/id/prisoner/inserted_id var/obj/machinery/door/airlock/release_door var/door_tag = "prisonshuttle" var/obj/item/radio/Radio //needed to send messages to sec radio - /obj/machinery/mineral/labor_claim_console/Initialize() . = ..() Radio = new/obj/item/radio(src) @@ -34,18 +32,6 @@ GLOBAL_LIST(labor_sheet_values) /proc/cmp_sheet_list(list/a, list/b) return a["value"] - b["value"] -/obj/machinery/mineral/labor_claim_console/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/card/id/prisoner)) - if(!inserted_id) - if(!user.transferItemToLoc(I, src)) - return - inserted_id = I - to_chat(user, "You insert [I].") - return - else - to_chat(user, "There's an ID inserted already.") - return ..() - /obj/machinery/mineral/labor_claim_console/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) @@ -58,14 +44,20 @@ GLOBAL_LIST(labor_sheet_values) var/can_go_home = FALSE data["emagged"] = (obj_flags & EMAGGED) ? 1 : 0 - if(inserted_id) - data["id"] = inserted_id - data["id_name"] = inserted_id.registered_name - data["points"] = inserted_id.points - data["goal"] = inserted_id.goal - if(check_auth()) + if(obj_flags & EMAGGED) can_go_home = TRUE + data["status_info"] = "No Prisoner ID detected." + var/obj/item/card/id/I = user.get_idcard(TRUE) + if(istype(I, /obj/item/card/id/prisoner)) + var/obj/item/card/id/prisoner/P = I + data["id_points"] = P.points + if(P.points >= P.goal) + can_go_home = TRUE + data["status_info"] = "Goal met!" + else + data["status_info"] = "You are [(P.goal - P.points)] points away." + if(stacking_machine) data["unclaimed_points"] = stacking_machine.points @@ -78,29 +70,19 @@ GLOBAL_LIST(labor_sheet_values) if(..()) return switch(action) - if("handle_id") - if(inserted_id) - if(!usr.get_active_held_item()) - usr.put_in_hands(inserted_id) - inserted_id = null - else - inserted_id.forceMove(get_turf(src)) - inserted_id = null - else - var/obj/item/I = usr.get_active_held_item() - if(istype(I, /obj/item/card/id/prisoner)) - if(!usr.transferItemToLoc(I, src)) - return - inserted_id = I if("claim_points") - inserted_id.points += stacking_machine.points - stacking_machine.points = 0 - to_chat(usr, "Points transferred.") + var/mob/M = usr + var/obj/item/card/id/I = M.get_idcard(TRUE) + if(istype(I, /obj/item/card/id/prisoner)) + var/obj/item/card/id/prisoner/P = I + P.points += stacking_machine.points + stacking_machine.points = 0 + to_chat(usr, "Points transferred.") + else + to_chat(usr, "No valid id for point transfer detected.") if("move_shuttle") if(!alone_in_area(get_area(src), usr)) to_chat(usr, "Prisoners are only allowed to be released while alone.") - else if(!check_auth()) - to_chat(usr, "Prisoners are only allowed to be released when they reach their point goal.") else switch(SSshuttle.moveShuttle("laborcamp", "laborcamp_home", TRUE)) if(1) @@ -112,14 +94,9 @@ GLOBAL_LIST(labor_sheet_values) else if(!(obj_flags & EMAGGED)) Radio.set_frequency(FREQ_SECURITY) - Radio.talk_into(src, "[inserted_id.registered_name] has returned to the station. Minerals and Prisoner ID card ready for retrieval.", FREQ_SECURITY) + Radio.talk_into(src, "A prisoner has returned to the station. Minerals and Prisoner ID card ready for retrieval.", FREQ_SECURITY) to_chat(usr, "Shuttle received message and will be sent shortly.") -/obj/machinery/mineral/labor_claim_console/proc/check_auth() - if(obj_flags & EMAGGED) - return 1 //Shuttle is emagged, let any ol' person through - return (istype(inserted_id) && inserted_id.points >= inserted_id.goal) //Otherwise, only let them out if the prisoner's reached his quota. - /obj/machinery/mineral/labor_claim_console/proc/locate_stacking_machine() stacking_machine = locate(/obj/machinery/mineral/stacking_machine, get_step(src, machinedir)) if(stacking_machine) @@ -132,10 +109,8 @@ GLOBAL_LIST(labor_sheet_values) obj_flags |= EMAGGED to_chat(user, "PZZTTPFFFT") - /**********************Prisoner Collection Unit**************************/ - /obj/machinery/mineral/stacking_machine/laborstacker force_connect = TRUE var/points = 0 //The unclaimed value of ore stacked. @@ -151,6 +126,7 @@ GLOBAL_LIST(labor_sheet_values) return ..() /**********************Point Lookup Console**************************/ + /obj/machinery/mineral/labor_points_checker name = "points checking console" desc = "A console used by prisoners to check the progress on their quotas. Simply swipe a prisoner ID." diff --git a/code/modules/mining/machine_redemption.dm b/code/modules/mining/machine_redemption.dm index 4605f7d693..6c1a00b020 100644 --- a/code/modules/mining/machine_redemption.dm +++ b/code/modules/mining/machine_redemption.dm @@ -13,7 +13,6 @@ speed_process = TRUE circuit = /obj/item/circuitboard/machine/ore_redemption layer = BELOW_OBJ_LAYER - var/obj/item/card/id/inserted_id var/points = 0 var/ore_pickup_rate = 15 var/sheet_per_ore = 1 @@ -48,18 +47,23 @@ point_upgrade = point_upgrade_temp sheet_per_ore = sheet_per_ore_temp +/obj/machinery/mineral/ore_redemption/examine(mob/user) + . = ..() + if(in_range(user, src) || isobserver(user)) + . += "The status display reads: Smelting [sheet_per_ore] sheet(s) per piece of ore.
Ore pickup speed at [ore_pickup_rate].
" + /obj/machinery/mineral/ore_redemption/proc/smelt_ore(obj/item/stack/ore/O) var/datum/component/material_container/mat_container = materials.mat_container if (!mat_container) return - if(istype(O, /obj/item/stack/ore/bluespace_crystal/refined)) + if(O.refined_type == null) return ore_buffer -= O if(O && O.refined_type) - points += O.points * point_upgrade * O.amount + points += O.points * O.amount var/material_amount = mat_container.get_item_material_amount(O) @@ -72,11 +76,8 @@ else var/mats = O.materials & mat_container.materials var/amount = O.amount - var/id = inserted_id && inserted_id.registered_name - if (id) - id = " (ID: [id])" mat_container.insert_item(O, sheet_per_ore) //insert it - materials.silo_log(src, "smelted", amount, "ores[id]", mats) + materials.silo_log(src, "smelted", amount, "ores", mats) qdel(O) /obj/machinery/mineral/ore_redemption/proc/can_smelt_alloy(datum/design/D) @@ -168,15 +169,7 @@ return if(!powered()) - return - if(istype(W, /obj/item/card/id)) - var/obj/item/card/id/I = user.get_active_held_item() - if(istype(I) && !istype(inserted_id)) - if(!user.transferItemToLoc(I, src)) - return - inserted_id = I - interact(user) - return + return ..() if(istype(W, /obj/item/disk/design_disk)) if(user.transferItemToLoc(W, src)) @@ -205,9 +198,6 @@ /obj/machinery/mineral/ore_redemption/ui_data(mob/user) var/list/data = list() data["unclaimedPoints"] = points - if(inserted_id) - data["hasID"] = TRUE - data["claimedPoints"] = inserted_id.mining_points data["materials"] = list() var/datum/component/material_container/mat_container = materials.mat_container @@ -245,32 +235,24 @@ return var/datum/component/material_container/mat_container = materials.mat_container switch(action) - if("Eject") - if(!inserted_id) - return - usr.put_in_hands(inserted_id) - inserted_id = null - return TRUE - if("Insert") - var/obj/item/card/id/I = usr.get_active_held_item() - if(istype(I)) - if(!usr.transferItemToLoc(I,src)) - return - inserted_id = I - else - to_chat(usr, "Not a valid ID!") - return TRUE if("Claim") - if(inserted_id) - inserted_id.mining_points += points - points = 0 + var/mob/M = usr + var/obj/item/card/id/I = M.get_idcard(TRUE) + if(points) + if(I) + I.mining_points += points + points = 0 + else + to_chat(usr, "No ID detected.") + else + to_chat(usr, "No points to claim.") return TRUE if("Release") if(!mat_container) return if(materials.on_hold()) to_chat(usr, "Mineral access is on hold, please contact the quartermaster.") - else if(!check_access(inserted_id) && !allowed(usr)) //Check the ID inside, otherwise check the user + else if(!allowed(usr)) //Check the ID inside, otherwise check the user to_chat(usr, "Required access not found.") else var/mat_id = params["id"] @@ -293,6 +275,7 @@ var/list/mats = list() mats[mat_id] = MINERAL_MATERIAL_AMOUNT materials.silo_log(src, "released", -count, "sheets", mats) + //Logging deleted for quick coding return TRUE if("diskInsert") var/obj/item/disk/design_disk/disk = usr.get_active_held_item() @@ -321,7 +304,7 @@ return var/alloy_id = params["id"] var/datum/design/alloy = stored_research.isDesignResearchedID(alloy_id) - if((check_access(inserted_id) || allowed(usr)) && alloy) + if((check_access(inserted_scan_id) || allowed(usr)) && alloy) var/smelt_amount = can_smelt_alloy(alloy) var/desired = 0 if (params["sheets"]) diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm index aed90cebdf..e49f2e73ed 100644 --- a/code/modules/mining/machine_vending.dm +++ b/code/modules/mining/machine_vending.dm @@ -20,6 +20,7 @@ new /datum/data/mining_equipment("Soap", /obj/item/soap/nanotrasen, 200), new /datum/data/mining_equipment("Laser Pointer", /obj/item/laser_pointer, 300), new /datum/data/mining_equipment("Alien Toy", /obj/item/clothing/mask/facehugger/toy, 300), + new /datum/data/mining_equipment("Stabilizing Serum", /obj/item/hivelordstabilizer, 400), new /datum/data/mining_equipment("Fulton Beacon", /obj/item/fulton_core, 400), new /datum/data/mining_equipment("Shelter Capsule", /obj/item/survivalcapsule, 400), new /datum/data/mining_equipment("Survival Knife", /obj/item/kitchen/knife/combat/survival, 450), @@ -28,8 +29,6 @@ new /datum/data/mining_equipment("Larger Ore Bag", /obj/item/storage/bag/ore/large, 500), new /datum/data/mining_equipment("500 Point Transfer Card", /obj/item/card/mining_point_card/mp500, 500), new /datum/data/mining_equipment("Tracking Implant Kit", /obj/item/storage/box/minertracker, 600), - new /datum/data/mining_equipment("Survival Medipen", /obj/item/reagent_containers/hypospray/medipen/survival, 750), - new /datum/data/mining_equipment("Stabilizing Serum", /obj/item/hivelordstabilizer, 750), new /datum/data/mining_equipment("Jaunter", /obj/item/wormhole_jaunter, 750), new /datum/data/mining_equipment("Kinetic Crusher", /obj/item/twohanded/required/kinetic_crusher, 750), new /datum/data/mining_equipment("Kinetic Accelerator", /obj/item/gun/energy/kinetic_accelerator, 750), @@ -54,7 +53,6 @@ new /datum/data/mining_equipment("Super Resonator", /obj/item/resonator/upgraded, 2500), new /datum/data/mining_equipment("Jump Boots", /obj/item/clothing/shoes/bhop, 2500), new /datum/data/mining_equipment("Luxury Shelter Capsule", /obj/item/survivalcapsule/luxury, 3000), - new /datum/data/mining_equipment("Miner Full Replacement", /obj/item/storage/backpack/duffelbag/mining_cloned, 3000), new /datum/data/mining_equipment("Nanotrasen Minebot", /mob/living/simple_animal/hostile/mining_drone, 800), new /datum/data/mining_equipment("Minebot Melee Upgrade", /obj/item/mine_bot_upgrade, 400), new /datum/data/mining_equipment("Minebot Armor Upgrade", /obj/item/mine_bot_upgrade/health, 400), @@ -68,9 +66,7 @@ new /datum/data/mining_equipment("KA Range Increase", /obj/item/borg/upgrade/modkit/range, 1000), new /datum/data/mining_equipment("KA Damage Increase", /obj/item/borg/upgrade/modkit/damage, 1000), new /datum/data/mining_equipment("KA Cooldown Decrease", /obj/item/borg/upgrade/modkit/cooldown, 1000), - new /datum/data/mining_equipment("KA AoE Damage", /obj/item/borg/upgrade/modkit/aoe/mobs, 2000), - new /datum/data/mining_equipment("Premium Accelerator", /obj/item/gun/energy/kinetic_accelerator/premiumka, 8000) - + new /datum/data/mining_equipment("KA AoE Damage", /obj/item/borg/upgrade/modkit/aoe/mobs, 2000) ) /datum/data/mining_equipment @@ -95,60 +91,42 @@ /obj/machinery/mineral/equipment_vendor/ui_interact(mob/user) . = ..() - var/dat - dat +="
" - if(istype(inserted_id)) - dat += "You have [inserted_id.mining_points] mining points collected. Eject ID.
" - else - dat += "No ID inserted. Insert ID.
" - dat += "
" + var/list/dat = list() dat += "
Equipment point cost list:
Name: [active1.fields["name"]] 
ID: [active1.fields["id"]] 
Sex: [active1.fields["sex"]] 
Gender: [active1.fields["gender"]] 
Age: [active1.fields["age"]] 
Species: [active1.fields["species"]] 
Rank: [active1.fields["rank"]] 
" for(var/datum/data/mining_equipment/prize in prize_list) dat += "" dat += "
[prize.equipment_name][prize.cost]Purchase
" var/datum/browser/popup = new(user, "miningvendor", "Mining Equipment Vendor", 400, 350) - popup.set_content(dat) + popup.set_content(dat.Join()) popup.open() return /obj/machinery/mineral/equipment_vendor/Topic(href, href_list) if(..()) return - if(href_list["choice"]) - if(istype(inserted_id)) - if(href_list["choice"] == "eject") - to_chat(usr, "You eject the ID from [src]'s card slot.") - inserted_id.forceMove(loc) - inserted_id.verb_pickup() - inserted_id = null - else if(href_list["choice"] == "insert") - var/obj/item/card/id/I = usr.get_active_held_item() - if(istype(I)) - if(!usr.transferItemToLoc(I, src)) - return - inserted_id = I - to_chat(usr, "You insert the ID into [src]'s card slot.") - else - to_chat(usr, "Error: No valid ID!") - flick(icon_deny, src) if(href_list["purchase"]) - if(istype(inserted_id)) - var/datum/data/mining_equipment/prize = locate(href_list["purchase"]) + var/mob/M = usr + var/obj/item/card/id/I = M.get_idcard(TRUE) + if(istype(I)) + var/datum/data/mining_equipment/prize = locate(href_list["purchase"]) in prize_list if (!prize || !(prize in prize_list)) to_chat(usr, "Error: Invalid choice!") flick(icon_deny, src) return - if(prize.cost > inserted_id.mining_points) - to_chat(usr, "Error: Insufficient points for [prize.equipment_name]!") + if(prize.cost > I.mining_points) + to_chat(usr, "Error: Insufficient credits for [prize.equipment_name] on [I]!") flick(icon_deny, src) else - inserted_id.mining_points -= prize.cost - to_chat(usr, "[src] clanks to life briefly before vending [prize.equipment_name]!") - new prize.equipment_path(src.loc) - SSblackbox.record_feedback("nested tally", "mining_equipment_bought", 1, list("[type]", "[prize.equipment_path]")) + if (I.mining_points -= prize.cost) + to_chat(usr, "[src] clanks to life briefly before vending [prize.equipment_name]!") + new prize.equipment_path(src.loc) + SSblackbox.record_feedback("nested tally", "mining_equipment_bought", 1, list("[type]", "[prize.equipment_path]")) + else + to_chat(usr, "Error: Transaction failure, please try again later!") + flick(icon_deny, src) else - to_chat(usr, "Error: Please insert a valid ID!") + to_chat(usr, "Error: An ID with a registered account is required!") flick(icon_deny, src) updateUsrDialog() return @@ -157,18 +135,6 @@ if(istype(I, /obj/item/mining_voucher)) RedeemVoucher(I, user) return - if(istype(I, /obj/item/suit_voucher)) - RedeemSVoucher(I, user) - return - if(istype(I, /obj/item/card/id)) - var/obj/item/card/id/C = usr.get_active_held_item() - if(istype(C) && !istype(inserted_id)) - if(!usr.transferItemToLoc(C, src)) - return - inserted_id = C - to_chat(usr, "You insert the ID into [src]'s card slot.") - interact(user) - return if(default_deconstruction_screwdriver(user, "mining-open", "mining", I)) updateUsrDialog() return @@ -212,7 +178,6 @@ if(prob(50 / severity) && severity < 3) qdel(src) - /****************Golem Point Vendor**************************/ /obj/machinery/mineral/equipment_vendor/golem @@ -228,7 +193,6 @@ new /datum/data/mining_equipment("Monkey Cube", /obj/item/reagent_containers/food/snacks/monkeycube, 300), new /datum/data/mining_equipment("Toolbelt", /obj/item/storage/belt/utility, 350), new /datum/data/mining_equipment("Royal Cape of the Liberator", /obj/item/bedsheet/rd/royal_cape, 500), - new /datum/data/mining_equipment("Sulphuric Acid", /obj/item/reagent_containers/glass/beaker/sulphuric, 500), new /datum/data/mining_equipment("Grey Slime Extract", /obj/item/slime_extract/grey, 1000), new /datum/data/mining_equipment("Modification Kit", /obj/item/borg/upgrade/modkit/trigger_guard, 1700), new /datum/data/mining_equipment("The Liberator's Legacy", /obj/item/storage/box/rndboards, 2000) @@ -315,52 +279,13 @@ desc = "A kit containing everything a crewmember needs to support a shaft miner in the field." /obj/item/storage/backpack/duffelbag/mining_conscript/PopulateContents() - new /obj/item/pickaxe/mini(src) new /obj/item/clothing/glasses/meson(src) new /obj/item/t_scanner/adv_mining_scanner/lesser(src) new /obj/item/storage/bag/ore(src) - new /obj/item/clothing/suit/hooded/explorer/standard(src) - new /obj/item/encryptionkey/headset_cargo(src) + new /obj/item/clothing/suit/hooded/explorer(src) + new /obj/item/encryptionkey/headset_mining(src) new /obj/item/clothing/mask/gas/explorer(src) new /obj/item/card/mining_access_card(src) - -//CITADEL ADDITIONS BELOW - -/obj/item/storage/backpack/duffelbag/mining_cloned - name = "mining replacement kit" - desc = "A large bag that has advance tools and a spare jumpsuit, boots, and gloves for a newly cloned miner to get back in the field. Even as a new Id!" - -/obj/item/storage/backpack/duffelbag/mining_cloned/PopulateContents() - new /obj/item/pickaxe/mini(src) - new /obj/item/clothing/under/rank/miner/lavaland(src) - new /obj/item/clothing/shoes/workboots/mining(src) - new /obj/item/clothing/gloves/color/black(src) - new /obj/item/implanter/tracking/gps(src) + new /obj/item/gun/energy/kinetic_accelerator(src) new /obj/item/kitchen/knife/combat/survival(src) - new /obj/item/storage/firstaid/regular(src) - new /obj/item/reagent_containers/hypospray/medipen/survival(src) - new /obj/item/t_scanner/adv_mining_scanner(src) - new /obj/item/clothing/suit/hooded/explorer/standard(src) - new /obj/item/encryptionkey/headset_cargo(src) - new /obj/item/clothing/mask/gas/explorer(src) - new /obj/item/card/id/mining(src) - new /obj/item/storage/bag/ore(src) - new /obj/item/clothing/glasses/meson/prescription(src) - -/obj/machinery/mineral/equipment_vendor/proc/RedeemSVoucher(obj/item/suit_voucher/voucher, mob/redeemer) - var/items = list("Exo-suit", "SEVA suit") - - var/selection = input(redeemer, "Pick your suit.", "Suit Voucher Redemption") as null|anything in items - if(!selection || !Adjacent(redeemer) || QDELETED(voucher) || voucher.loc != redeemer) - return - var/drop_location = drop_location() - switch(selection) - if("Exo-suit") - new /obj/item/clothing/suit/hooded/explorer/exo(drop_location) - new /obj/item/clothing/mask/gas/exo(drop_location) - if("SEVA suit") - new /obj/item/clothing/suit/hooded/explorer/seva(drop_location) - new /obj/item/clothing/mask/gas/seva(drop_location) - - SSblackbox.record_feedback("tally", "suit_voucher_redeemed", 1, selection) - qdel(voucher) + new /obj/item/flashlight/seclite(src) diff --git a/tgstation.dme b/tgstation.dme index da990c169a..2238cb9145 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -646,6 +646,9 @@ #include "code\game\machinery\computer\arcade\minesweeper.dm" #include "code\game\machinery\computer\arcade\misc_arcade.dm" #include "code\game\machinery\computer\arcade\orion_trail.dm" +#include "code\game\machinery\computer\prisoner\_prisoner.dm" +#include "code\game\machinery\computer\prisoner\gulag_teleporter.dm" +#include "code\game\machinery\computer\prisoner\management.dm" #include "code\game\machinery\doors\airlock.dm" #include "code\game\machinery\doors\airlock_electronics.dm" #include "code\game\machinery\doors\airlock_types.dm" diff --git a/tgui/src/interfaces/gulag_item_reclaimer.ract b/tgui/src/interfaces/gulag_item_reclaimer.ract index 7c315d869c..ac6d5d5165 100644 --- a/tgui/src/interfaces/gulag_item_reclaimer.ract +++ b/tgui/src/interfaces/gulag_item_reclaimer.ract @@ -1,10 +1,7 @@ - -
{{data.id ? data.id_name : "-------------"}}
-
{{#each data.mobs}} Drop Items {{/each}} - \ No newline at end of file + diff --git a/tgui/src/interfaces/labor_claim_console.ract b/tgui/src/interfaces/labor_claim_console.ract index 16b3ae0491..21e69f9aa9 100644 --- a/tgui/src/interfaces/labor_claim_console.ract +++ b/tgui/src/interfaces/labor_claim_console.ract @@ -6,24 +6,15 @@ {{/each}} - - {{data.id ? data.id_name : "-------------"}} + + {{data.unclaimed_points}} + Claim points - {{#if data.id}} - - {{data.points}} - - - {{data.goal}} - - - {{data.unclaimed_points}} - Claim points - - {{/if}} -
+ Points: {{data.id_points}} + + {{data.status_info}} Move shuttle -
-
\ No newline at end of file + + diff --git a/tgui/src/interfaces/ore_redemption_machine.ract b/tgui/src/interfaces/ore_redemption_machine.ract index 596b624e98..650c5ddd5e 100644 --- a/tgui/src/interfaces/ore_redemption_machine.ract +++ b/tgui/src/interfaces/ore_redemption_machine.ract @@ -3,24 +3,10 @@ This machine only accepts ore. Gibtonite and Slag are not accepted. - Current unclaimed points: {{data.unclaimedPoints}} - {{#if data.unclaimedPoints}} + Current unclaimed credits: {{data.unclaimedPoints}} - Claim Points + Claim - {{/if}} - - - {{#if data.hasID}} - - Eject ID - - You have {{data.claimedPoints}} mining points collected. - {{else}} - - Insert ID - - {{/if}} From 4ba3d851ed3bed202097a2eaa022ff1bac5dd7f6 Mon Sep 17 00:00:00 2001 From: Sishen Date: Fri, 9 Aug 2019 00:46:14 -0400 Subject: [PATCH 009/222] IT JUST WORKS --- code/__DEFINES/maths.dm | 6 + code/__HELPERS/roundend.dm | 7 + code/__HELPERS/time.dm | 8 + code/game/gamemodes/dynamic/dynamic.dm | 750 ++++++++++++++++++ .../gamemodes/dynamic/dynamic_rulesets.dm | 211 +++++ .../dynamic/dynamic_rulesets_latejoin.dm | 110 +++ .../dynamic/dynamic_rulesets_midround.dm | 460 +++++++++++ .../dynamic/dynamic_rulesets_roundstart.dm | 729 +++++++++++++++++ code/game/gamemodes/dynamic/readme.md | 57 ++ code/game/gamemodes/game_mode.dm | 4 + code/modules/admin/admin.dm | 57 ++ code/modules/admin/topic.dm | 290 +++++++ tgstation.dme | 9 + 13 files changed, 2698 insertions(+) create mode 100644 code/game/gamemodes/dynamic/dynamic.dm create mode 100644 code/game/gamemodes/dynamic/dynamic_rulesets.dm create mode 100644 code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm create mode 100644 code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm create mode 100644 code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm create mode 100644 code/game/gamemodes/dynamic/readme.md diff --git a/code/__DEFINES/maths.dm b/code/__DEFINES/maths.dm index d344f7f010..5bce51293f 100644 --- a/code/__DEFINES/maths.dm +++ b/code/__DEFINES/maths.dm @@ -201,4 +201,10 @@ return list(region_x1 & region_x2, region_y1 & region_y2) +#define EXP_DISTRIBUTION(desired_mean) ( -(1/(1/desired_mean)) * log(rand(1, 1000) * 0.001) ) + +#define LORENTZ_DISTRIBUTION(x, s) ( s*TAN(TODEGREES(PI*(rand()-0.5))) + x ) +#define LORENTZ_CUMULATIVE_DISTRIBUTION(x, y, s) ( (1/PI)*TORADIANS(arctan((x-y)/s)) + 1/2 ) + +#define RULE_OF_THREE(a, b, x) ((a*x)/b) // ) diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm index 55d9e7a6cd..0e9413520b 100644 --- a/code/__HELPERS/roundend.dm +++ b/code/__HELPERS/roundend.dm @@ -308,6 +308,13 @@ //ignore this comment, it fixes the broken sytax parsing caused by the " above else parts += "[GLOB.TAB]Nobody died this shift!" + if(istype(SSticker.mode, /datum/game_mode/dynamic)) + var/datum/game_mode/dynamic/mode = SSticker.mode + parts += "[GLOB.TAB]Threat level: [mode.threat_level]" + parts += "[GLOB.TAB]Threat left: [mode.threat]" + parts += "[GLOB.TAB]Executed rules:" + for(var/datum/dynamic_ruleset/rule in mode.executed_rules) + parts += "[GLOB.TAB][GLOB.TAB][rule.ruletype] - [rule.name]: -[rule.cost] threat" return parts.Join("
") /client/proc/roundend_report_file() diff --git a/code/__HELPERS/time.dm b/code/__HELPERS/time.dm index b28e7b5807..f0d5a7b252 100644 --- a/code/__HELPERS/time.dm +++ b/code/__HELPERS/time.dm @@ -73,3 +73,11 @@ GLOBAL_VAR_INIT(rollovercheck_last_timeofday, 0) /proc/daysSince(realtimev) return round((world.realtime - realtimev) / (24 HOURS)) + +/proc/worldtime2text() + return gameTimestamp("hh:mm:ss", world.time) + +/proc/gameTimestamp(format = "hh:mm:ss", wtime=null) + if(!wtime) + wtime = world.time + return time2text(wtime - GLOB.timezoneOffset, format) diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm new file mode 100644 index 0000000000..ab4ac4d5c6 --- /dev/null +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -0,0 +1,750 @@ +#define CURRENT_LIVING_PLAYERS 1 +#define CURRENT_LIVING_ANTAGS 2 +#define CURRENT_DEAD_PLAYERS 3 +#define CURRENT_OBSERVERS 4 + +#define ONLY_RULESET 1 +#define HIGHLANDER_RULESET 2 +#define TRAITOR_RULESET 4 +#define MINOR_RULESET 8 + +#define RULESET_STOP_PROCESSING 1 + +// -- Injection delays +GLOBAL_VAR_INIT(dynamic_latejoin_delay_min, (5 MINUTES)) +GLOBAL_VAR_INIT(dynamic_latejoin_delay_max, (25 MINUTES)) + +GLOBAL_VAR_INIT(dynamic_midround_delay_min, (15 MINUTES)) +GLOBAL_VAR_INIT(dynamic_midround_delay_max, (35 MINUTES)) + +// Are HIGHLANDER_RULESETs allowed to stack? +GLOBAL_VAR_INIT(dynamic_no_stacking, TRUE) +// A number between -5 and +5. +// A negative value will give a more peaceful round and +// a positive value will give a round with higher threat. +GLOBAL_VAR_INIT(dynamic_curve_centre, 0) +// A number between 0.5 and 4. +// Higher value will favour extreme rounds and +// lower value rounds closer to the average. +GLOBAL_VAR_INIT(dynamic_curve_width, 1.8) +// If enabled only picks a single starting rule and executes only autotraitor midround ruleset. +GLOBAL_VAR_INIT(dynamic_classic_secret, FALSE) +// How many roundstart players required for high population override to take effect. +GLOBAL_VAR_INIT(dynamic_high_pop_limit, 55) +// If enabled does not accept or execute any rulesets. +GLOBAL_VAR_INIT(dynamic_forced_extended, FALSE) +// How high threat is required for HIGHLANDER_RULESETs stacking. +// This is independent of dynamic_no_stacking. +GLOBAL_VAR_INIT(dynamic_stacking_limit, 90) +// List of forced roundstart rulesets. +GLOBAL_LIST_EMPTY(dynamic_forced_roundstart_ruleset) +// Forced threat level, setting this to zero or higher forces the roundstart threat to the value. +GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) + +/datum/game_mode/dynamic + name = "dynamic mode" + config_tag = "dynamic" + + announce_span = "danger" + announce_text = "Dynamic mode!" // This needs to be changed maybe + + reroll_friendly = FALSE; + + // Threat logging vars + /// The "threat cap", threat shouldn't normally go above this and is used in ruleset calculations + var/threat_level = 0 + /// Set at the beginning of the round. Spent by the mode to "purchase" rules. + var/threat = 0 + /// Running information about the threat. Can store text or datum entries. + var/list/threat_log = list() + /// List of roundstart rules used for selecting the rules. + var/list/roundstart_rules = list() + /// List of latejoin rules used for selecting the rules. + var/list/latejoin_rules = list() + /// List of midround rules used for selecting the rules. + var/list/midround_rules = list() + /** # Pop range per requirement. + * If the value is five the range is: + * 0-4, 5-9, 10-14, 15-19, 20-24, 25-29, 30-34, 35-39, 40-54, 45+ + * If it is six the range is: + * 0-5, 6-11, 12-17, 18-23, 24-29, 30-35, 36-41, 42-47, 48-53, 54+ + * If it is seven the range is: + * 0-6, 7-13, 14-20, 21-27, 28-34, 35-41, 42-48, 49-55, 56-62, 63+ + */ + var/pop_per_requirement = 6 + /// The requirement used for checking if a second rule should be selected. + var/list/second_rule_req = list(100, 100, 80, 70, 60, 50, 30, 20, 10, 0) + /// The requirement used for checking if a third rule should be selected. + var/list/third_rule_req = list(100, 100, 100, 90, 80, 70, 60, 50, 40, 30) + /// Threat requirement for a second ruleset when high pop override is in effect. + var/high_pop_second_rule_req = 40 + /// Threat requirement for a third ruleset when high pop override is in effect. + var/high_pop_third_rule_req = 60 + /// Number of players who were ready on roundstart. + var/roundstart_pop_ready = 0 + /// List of candidates used on roundstart rulesets. + var/list/candidates = list() + /// Rules that are processed, rule_process is called on the rules in this list. + var/list/current_rules = list() + /// List of executed rulesets. + var/list/executed_rules = list() + /// Associative list of current players, in order: living players, living antagonists, dead players and observers. + var/list/list/current_players = list(CURRENT_LIVING_PLAYERS, CURRENT_LIVING_ANTAGS, CURRENT_DEAD_PLAYERS, CURRENT_OBSERVERS) + /// When world.time is over this number the mode tries to inject a latejoin ruleset. + var/latejoin_injection_cooldown = 0 + /// When world.time is over this number the mode tries to inject a midround ruleset. + var/midround_injection_cooldown = 0 + /// When TRUE GetInjectionChance returns 100. + var/forced_injection = FALSE + /// Forced ruleset to be executed for the next latejoin. + var/datum/dynamic_ruleset/latejoin/forced_latejoin_rule = null + /// When current_players was updated last time. + var/pop_last_updated = 0 + /// How many percent of the rounds are more peaceful. + var/peaceful_percentage = 50 + /// If a highlander executed. + var/highlander_executed = FALSE + /// If a only ruleset has been executed. + var/only_ruleset_executed = FALSE + +/datum/game_mode/dynamic/admin_panel() + var/list/dat = list("Game Mode Panel

Game Mode Panel

") + dat += "Dynamic Mode \[VV\]
" + dat += "Threat Level: [threat_level]
" + + dat += "Threat to Spend: [threat] \[Adjust\] \[View Log\]
" + dat += "
" + dat += "Parameters: centre = [GLOB.dynamic_curve_centre] ; width = [GLOB.dynamic_curve_width].
" + dat += "On average, [peaceful_percentage]% of the rounds are more peaceful.
" + dat += "Forced extended: [GLOB.dynamic_forced_extended ? "On" : "Off"]
" + dat += "Classic secret (only autotraitor): [GLOB.dynamic_classic_secret ? "On" : "Off"]
" + dat += "No stacking (only one round-ender): [GLOB.dynamic_no_stacking ? "On" : "Off"]
" + dat += "Stacking limit: [GLOB.dynamic_stacking_limit] \[Adjust\]" + dat += "
" + dat += "Executed rulesets: " + if (executed_rules.len > 0) + dat += "
" + for (var/datum/dynamic_ruleset/DR in executed_rules) + dat += "[DR.ruletype] - [DR.name]
" + else + dat += "none.
" + dat += "
Injection Timers: ([get_injection_chance(TRUE)]% chance)
" + dat += "Latejoin: [(latejoin_injection_cooldown-world.time)>60*10 ? "[round((latejoin_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(latejoin_injection_cooldown-world.time)] seconds"] \[Now!\]
" + dat += "Midround: [(midround_injection_cooldown-world.time)>60*10 ? "[round((midround_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(midround_injection_cooldown-world.time)] seconds"] \[Now!\]
" + usr << browse(dat.Join(), "window=gamemode_panel;size=500x500") + +/datum/game_mode/dynamic/Topic(href, href_list) + if (..()) // Sanity, maybe ? + return + if(!check_rights(R_ADMIN)) + message_admins("[usr.key] has attempted to override the game mode panel!") + log_admin("[key_name(usr)] tried to use the game mode panel without authorization.") + return + if (href_list["forced_extended"]) + GLOB.dynamic_forced_extended = !GLOB.dynamic_forced_extended + else if (href_list["no_stacking"]) + GLOB.dynamic_no_stacking = !GLOB.dynamic_no_stacking + else if (href_list["classic_secret"]) + GLOB.dynamic_classic_secret = !GLOB.dynamic_classic_secret + else if (href_list["adjustthreat"]) + var/threatadd = input("Specify how much threat to add (negative to subtract). This can inflate the threat level.", "Adjust Threat", 0) as null|num + if(!threatadd) + return + if(threatadd > 0) + create_threat(threatadd) + else + spend_threat(-threatadd) + else if (href_list["injectlate"]) + latejoin_injection_cooldown = 0 + forced_injection = TRUE + message_admins("[key_name(usr)] forced a latejoin injection.", 1) + else if (href_list["injectmid"]) + midround_injection_cooldown = 0 + forced_injection = TRUE + message_admins("[key_name(usr)] forced a midround injection.", 1) + else if (href_list["threatlog"]) + show_threatlog(usr) + else if (href_list["stacking_limit"]) + GLOB.dynamic_stacking_limit = input(usr,"Change the threat limit at which round-endings rulesets will start to stack.", "Change stacking limit", null) as num + + admin_panel() // Refreshes the window + +// Checks if there are HIGHLANDER_RULESETs and calls the rule's round_result() proc +/datum/game_mode/dynamic/set_round_result() + for(var/datum/dynamic_ruleset/rule in executed_rules) + if(rule.flags & HIGHLANDER_RULESET) + if(rule.check_finished()) // Only the rule that actually finished the round sets round result. + return rule.round_result() + // If it got to this part, just pick one highlander if it exists + for(var/datum/dynamic_ruleset/rule in executed_rules) + if(rule.flags & HIGHLANDER_RULESET) + return rule.round_result() + return ..() + +/datum/game_mode/dynamic/send_intercept() + . = "Central Command Status Summary
" + switch(round(threat_level)) + if(0 to 19) + update_playercounts() + if(!current_players[CURRENT_LIVING_ANTAGS].len) + . += "Peaceful Waypoint
" + . += "Your station orbits deep within controlled, core-sector systems and serves as a waypoint for routine traffic through Nanotrasen's trade empire. Due to the combination of high security, interstellar traffic, and low strategic value, it makes any direct threat of violence unlikely. Your primary enemies will be incompetence and bored crewmen: try to organize team-building events to keep staffers interested and productive." + else + . += "Core Territory
" + . += "Your station orbits within reliably mundane, secure space. Although Nanotrasen has a firm grip on security in your region, the valuable resources and strategic position aboard your station make it a potential target for infiltrations. Monitor crew for non-loyal behavior, but expect a relatively tame shift free of large-scale destruction. We expect great things from your station." + if(20 to 39) + . += "Anomalous Exogeology
" + . += "Although your station lies within what is generally considered Nanotrasen-controlled space, the course of its orbit has caused it to cross unusually close to exogeological features with anomalous readings. Although these features offer opportunities for our research department, it is known that these little understood readings are often correlated with increased activity from competing interstellar organizations and individuals, among them the Wizard Federation and Cult of the Geometer of Blood - all known competitors for Anomaly Type B sites. Exercise elevated caution." + if(40 to 65) + . += "Contested System
" + . += "Your station's orbit passes along the edge of Nanotrasen's sphere of influence. While subversive elements remain the most likely threat against your station, hostile organizations are bolder here, where our grip is weaker. Exercise increased caution against elite Syndicate strike forces, or Executives forbid, some kind of ill-conceived unionizing attempt." + if(66 to 79) + . += "Uncharted Space
" + . += "Congratulations and thank you for participating in the NT 'Frontier' space program! Your station is actively orbiting a high value system far from the nearest support stations. Little is known about your region of space, and the opportunity to encounter the unknown invites greater glory. You are encouraged to elevate security as necessary to protect Nanotrasen assets." + if(80 to 99) + . += "Black Orbit
" + . += "As part of a mandatory security protocol, we are required to inform you that as a result of your orbital pattern directly behind an astrological body (oriented from our nearest observatory), your station will be under decreased monitoring and support. It is anticipated that your extreme location and decreased surveillance could pose security risks. Avoid unnecessary risks and attempt to keep your station in one piece." + if(100) + . += "Impending Doom
" + . += "Your station is somehow in the middle of hostile territory, in clear view of any enemy of the corporation. Your likelihood to survive is low, and station destruction is expected and almost inevitable. Secure any sensitive material and neutralize any enemy you will come across. It is important that you at least try to maintain the station.
" + . += "Good luck." + + if(station_goals.len) + . += "
Special Orders for [station_name()]:" + for(var/datum/station_goal/G in station_goals) + G.on_report() + . += G.get_report() + + print_command_report(., "Central Command Status Summary", announce=FALSE) + priority_announce("A summary has been copied and printed to all communications consoles.", "Security level elevated.", 'sound/ai/intercept.ogg') + if(GLOB.security_level < SEC_LEVEL_BLUE) + set_security_level(SEC_LEVEL_BLUE) + +// Yes, this is copy pasted from game_mode +/datum/game_mode/dynamic/check_finished(force_ending) + if(!SSticker.setup_done || !gamemode_ready) + return FALSE + if(replacementmode && round_converted == 2) + return replacementmode.check_finished() + if(SSshuttle.emergency && (SSshuttle.emergency.mode == SHUTTLE_ENDGAME)) + return TRUE + if(station_was_nuked) + return TRUE + if(force_ending) + return TRUE + for(var/datum/dynamic_ruleset/rule in executed_rules) + if(rule.flags & HIGHLANDER_RULESET) + return rule.check_finished() + +/datum/game_mode/dynamic/proc/show_threatlog(mob/admin) + if(!SSticker.HasRoundStarted()) + alert("The round hasn't started yet!") + return + + if(!check_rights(R_ADMIN)) + return + + var/list/out = list("Threat LogThreat Log
Starting Threat: [threat_level]
") + + for(var/entry in threat_log) + if(istext(entry)) + out += "[entry]
" + + out += "Remaining threat/threat_level: [threat]/[threat_level]" + + usr << browse(out.Join(), "window=threatlog;size=700x500") + +/// Generates the threat level using lorentz distribution and assigns peaceful_percentage. +/datum/game_mode/dynamic/proc/generate_threat() + var/relative_threat = LORENTZ_DISTRIBUTION(GLOB.dynamic_curve_centre, GLOB.dynamic_curve_width) + threat_level = round(lorentz_to_threat(relative_threat), 0.1) + + peaceful_percentage = round(LORENTZ_CUMULATIVE_DISTRIBUTION(relative_threat, GLOB.dynamic_curve_centre, GLOB.dynamic_curve_width), 0.01)*100 + + threat = threat_level + +/datum/game_mode/dynamic/can_start() + /* Disabled for now, had some changes that need to be tested and this might interfere with that. + if(GLOB.dynamic_curve_centre == 0) + // 10 is when the centre starts to decrease + // 6 is just 1 + 5 (from the maximum value and the one decreased) + // 1 just makes the curve look better, I don't know. + // Limited between 1 and 5 then inverted and rounded + // With this you get a centre curve that stays at -5 until 10 then first rapidly decreases but slows down at the end + GLOB.dynamic_curve_centre = round(-CLAMP((10*6/GLOB.player_list.len)-1, 0, 5), 0.5) + */ + message_admins("Dynamic mode parameters for the round:") + message_admins("Centre is [GLOB.dynamic_curve_centre], Width is [GLOB.dynamic_curve_width], Forced extended is [GLOB.dynamic_forced_extended ? "Enabled" : "Disabled"], No stacking is [GLOB.dynamic_no_stacking ? "Enabled" : "Disabled"].") + message_admins("Stacking limit is [GLOB.dynamic_stacking_limit], Classic secret is [GLOB.dynamic_classic_secret ? "Enabled" : "Disabled"], High population limit is [GLOB.dynamic_high_pop_limit].") + log_game("DYNAMIC: Dynamic mode parameters for the round:") + log_game("DYNAMIC: Centre is [GLOB.dynamic_curve_centre], Width is [GLOB.dynamic_curve_width], Forced extended is [GLOB.dynamic_forced_extended ? "Enabled" : "Disabled"], No stacking is [GLOB.dynamic_no_stacking ? "Enabled" : "Disabled"].") + log_game("DYNAMIC: Stacking limit is [GLOB.dynamic_stacking_limit], Classic secret is [GLOB.dynamic_classic_secret ? "Enabled" : "Disabled"], High population limit is [GLOB.dynamic_high_pop_limit].") + if(GLOB.dynamic_forced_threat_level >= 0) + threat_level = round(GLOB.dynamic_forced_threat_level, 0.1) + threat = threat_level + else + generate_threat() + + var/latejoin_injection_cooldown_middle = 0.5*(GLOB.dynamic_latejoin_delay_max + GLOB.dynamic_latejoin_delay_min) + latejoin_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(latejoin_injection_cooldown_middle), GLOB.dynamic_latejoin_delay_min, GLOB.dynamic_latejoin_delay_max)) + world.time + + var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_midround_delay_max + GLOB.dynamic_midround_delay_min) + midround_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_midround_delay_min, GLOB.dynamic_midround_delay_max)) + world.time + message_admins("Dynamic Mode initialized with a Threat Level of... [threat_level]!") + log_game("DYNAMIC: Dynamic Mode initialized with a Threat Level of... [threat_level]!") + return TRUE + +/datum/game_mode/dynamic/pre_setup() + for (var/rule in subtypesof(/datum/dynamic_ruleset)) + var/datum/dynamic_ruleset/ruleset = new rule() + // Simple check if the ruleset should be added to the lists. + if(ruleset.name == "") + continue + switch(ruleset.ruletype) + if("Roundstart") + roundstart_rules += ruleset + if ("Latejoin") + latejoin_rules += ruleset + if ("Midround") + if (ruleset.weight) + midround_rules += ruleset + for(var/mob/dead/new_player/player in GLOB.player_list) + if(player.ready == PLAYER_READY_TO_PLAY && player.mind) + roundstart_pop_ready++ + candidates.Add(player) + log_game("DYNAMIC: Listing [roundstart_rules.len] round start rulesets, and [candidates.len] players ready.") + if (candidates.len <= 0) + return TRUE + if (roundstart_rules.len <= 0) + return TRUE + + if(GLOB.dynamic_forced_roundstart_ruleset.len > 0) + rigged_roundstart() + else + roundstart() + + var/starting_rulesets = "" + for (var/datum/dynamic_ruleset/roundstart/DR in executed_rules) + starting_rulesets += "[DR.name], " + candidates.Cut() + return TRUE + +/datum/game_mode/dynamic/post_setup(report) + update_playercounts() + + for(var/datum/dynamic_ruleset/roundstart/rule in executed_rules) + rule.candidates.Cut() // The rule should not use candidates at this point as they all are null. + if(!rule.execute()) + stack_trace("The starting rule \"[rule.name]\" failed to execute.") + ..() + +/// A simple roundstart proc used when dynamic_forced_roundstart_ruleset has rules in it. +/datum/game_mode/dynamic/proc/rigged_roundstart() + message_admins("[GLOB.dynamic_forced_roundstart_ruleset.len] rulesets being forced. Will now attempt to draft players for them.") + log_game("DYNAMIC: [GLOB.dynamic_forced_roundstart_ruleset.len] rulesets being forced. Will now attempt to draft players for them.") + for (var/datum/dynamic_ruleset/roundstart/rule in GLOB.dynamic_forced_roundstart_ruleset) + message_admins("Drafting players for forced ruleset [rule.name].") + log_game("DYNAMIC: Drafting players for forced ruleset [rule.name].") + rule.mode = src + rule.candidates = candidates.Copy() + rule.trim_candidates() + if (rule.ready(TRUE)) + picking_roundstart_rule(list(rule), forced = TRUE) + +/datum/game_mode/dynamic/proc/roundstart() + if (GLOB.dynamic_forced_extended) + log_game("DYNAMIC: Starting a round of forced extended.") + return TRUE + var/list/drafted_rules = list() + for (var/datum/dynamic_ruleset/roundstart/rule in roundstart_rules) + if (rule.acceptable(roundstart_pop_ready, threat_level) && threat >= rule.cost) // If we got the population and threat required + rule.candidates = candidates.Copy() + rule.trim_candidates() + if (rule.ready() && rule.candidates.len > 0) + drafted_rules[rule] = rule.weight + + var/indice_pop = min(10,round(roundstart_pop_ready/pop_per_requirement)+1) + var/extra_rulesets_amount = 0 + if (GLOB.dynamic_classic_secret) + extra_rulesets_amount = 0 + else + if (roundstart_pop_ready > GLOB.dynamic_high_pop_limit) + message_admins("High Population Override is in effect! Threat Level will have more impact on which roles will appear, and player population less.") + log_game("DYNAMIC: High Population Override is in effect! Threat Level will have more impact on which roles will appear, and player population less.") + if (threat_level > high_pop_second_rule_req) + extra_rulesets_amount++ + if (threat_level > high_pop_third_rule_req) + extra_rulesets_amount++ + else + if (threat_level >= second_rule_req[indice_pop]) + extra_rulesets_amount++ + if (threat_level >= third_rule_req[indice_pop]) + extra_rulesets_amount++ + + if (drafted_rules.len > 0 && picking_roundstart_rule(drafted_rules)) + if (extra_rulesets_amount > 0) // We've got enough population and threat for a second rulestart rule + for (var/datum/dynamic_ruleset/roundstart/rule in drafted_rules) + if (rule.cost > threat) + drafted_rules -= rule + if (drafted_rules.len > 0 && picking_roundstart_rule(drafted_rules)) + if (extra_rulesets_amount > 1) // We've got enough population and threat for a third rulestart rule + for (var/datum/dynamic_ruleset/roundstart/rule in drafted_rules) + if (rule.cost > threat) + drafted_rules -= rule + picking_roundstart_rule(drafted_rules) + else + return FALSE + return TRUE + +/// Picks a random roundstart rule from the list given as an argument and executes it. +/datum/game_mode/dynamic/proc/picking_roundstart_rule(list/drafted_rules = list(), forced = FALSE) + var/datum/dynamic_ruleset/roundstart/starting_rule = pickweight(drafted_rules) + if(!starting_rule) + return FALSE + + if(!forced) + if(only_ruleset_executed) + return FALSE + // Check if a blocking ruleset has been executed. + else if(check_blocking(starting_rule.blocking_rules, executed_rules)) + drafted_rules -= starting_rule + if(drafted_rules.len <= 0) + return FALSE + starting_rule = pickweight(drafted_rules) + // Check if the ruleset is highlander and if a highlander ruleset has been executed + else if(starting_rule.flags & HIGHLANDER_RULESET) + if(threat < GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking) + if(highlander_executed) + drafted_rules -= starting_rule + if(drafted_rules.len <= 0) + return FALSE + starting_rule = pickweight(drafted_rules) + + message_admins("Picking a [istype(starting_rule, /datum/dynamic_ruleset/roundstart/delayed/) ? " delayed " : ""] ruleset [starting_rule.name]") + log_game("DYNAMIC: Picking a [istype(starting_rule, /datum/dynamic_ruleset/roundstart/delayed/) ? " delayed " : ""] ruleset [starting_rule.name]") + + roundstart_rules -= starting_rule + drafted_rules -= starting_rule + + if (istype(starting_rule, /datum/dynamic_ruleset/roundstart/delayed/)) + var/datum/dynamic_ruleset/roundstart/delayed/rule = starting_rule + addtimer(CALLBACK(src, .proc/execute_delayed, rule), rule.delay) + + starting_rule.trim_candidates() + if (starting_rule.pre_execute()) + spend_threat(starting_rule.cost) + threat_log += "[worldtime2text()]: Roundstart [starting_rule.name] spent [starting_rule.cost]" + if(starting_rule.flags & HIGHLANDER_RULESET) + highlander_executed = TRUE + else if(starting_rule.flags & ONLY_RULESET) + only_ruleset_executed = TRUE + executed_rules += starting_rule + if (starting_rule.persistent) + current_rules += starting_rule + for(var/mob/M in starting_rule.assigned) + for (var/datum/dynamic_ruleset/roundstart/rule in roundstart_rules) + if (!rule.ready()) + drafted_rules -= rule // And removing rules that are no longer elligible + return TRUE + else + stack_trace("The starting rule \"[starting_rule.name]\" failed to pre_execute.") + return FALSE + +/// Executes delayed roundstart rules and has a hack in it. +/datum/game_mode/dynamic/proc/execute_delayed(datum/dynamic_ruleset/roundstart/delayed/rule) + update_playercounts() + rule.candidates = current_players[CURRENT_LIVING_PLAYERS].Copy() + rule.trim_candidates() + if(rule.execute()) + executed_rules += rule + if (rule.persistent) + current_rules += rule + return TRUE + else + stack_trace("The delayed roundstart rule \"[rule.name]\" failed to execute.") + return FALSE + +/// Picks a random midround OR latejoin rule from the list given as an argument and executes it. +/// Also this could be named better. +/datum/game_mode/dynamic/proc/picking_midround_latejoin_rule(list/drafted_rules = list(), forced = FALSE) + var/datum/dynamic_ruleset/rule = pickweight(drafted_rules) + if(!rule) + return FALSE + + if(!forced) + if(only_ruleset_executed) + return FALSE + // Check if a blocking ruleset has been executed. + else if(check_blocking(rule.blocking_rules, executed_rules)) + drafted_rules -= rule + if(drafted_rules.len <= 0) + return FALSE + rule = pickweight(drafted_rules) + // Check if the ruleset is highlander and if a highlander ruleset has been executed + else if(rule.flags & HIGHLANDER_RULESET) + if(threat < GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking) + if(highlander_executed) + drafted_rules -= rule + if(drafted_rules.len <= 0) + return FALSE + rule = pickweight(drafted_rules) + + if(!rule.repeatable) + if(rule.ruletype == "Latejoin") + latejoin_rules = remove_from_list(latejoin_rules, rule.type) + else if(rule.type == "Midround") + midround_rules = remove_from_list(midround_rules, rule.type) + + if (rule.execute()) + log_game("DYNAMIC: Injected a [rule.ruletype == "latejoin" ? "latejoin" : "midround"] ruleset [rule.name].") + spend_threat(rule.cost) + threat_log += "[worldtime2text()]: [rule.ruletype] [rule.name] spent [rule.cost]" + if(rule.flags & HIGHLANDER_RULESET) + highlander_executed = TRUE + else if(rule.flags & ONLY_RULESET) + only_ruleset_executed = TRUE + if(rule.ruletype == "Latejoin") + var/mob/M = pick(rule.candidates) + message_admins("[key_name(M)] joined the station, and was selected by the [rule.name] ruleset.") + log_game("DYNAMIC: [key_name(M)] joined the station, and was selected by the [rule.name] ruleset.") + executed_rules += rule + rule.candidates.Cut() + if (rule.persistent) + current_rules += rule + return TRUE + else + stack_trace("The [rule.ruletype] rule \"[rule.name]\" failed to execute.") + return FALSE + +/// An experimental proc to allow admins to call rules on the fly or have rules call other rules. +/datum/game_mode/dynamic/proc/picking_specific_rule(ruletype, forced = FALSE) + var/datum/dynamic_ruleset/midround/new_rule + if(ispath(ruletype)) + new_rule = new ruletype() // You should only use it to call midround rules though. + else if(istype(ruletype, /datum/dynamic_ruleset)) + new_rule = ruletype + else + return FALSE + + if(!new_rule) + return FALSE + + if(!forced) + if(only_ruleset_executed) + return FALSE + // Check if a blocking ruleset has been executed. + else if(check_blocking(new_rule.blocking_rules, executed_rules)) + return FALSE + // Check if the ruleset is highlander and if a highlander ruleset has been executed + else if(new_rule.flags & HIGHLANDER_RULESET) + if(threat < GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking) + if(highlander_executed) + return FALSE + + update_playercounts() + if ((forced || (new_rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && new_rule.cost <= threat))) + new_rule.candidates = current_players.Copy() + new_rule.trim_candidates() + if (new_rule.ready(forced)) + spend_threat(new_rule.cost) + threat_log += "[worldtime2text()]: Forced rule [new_rule.name] spent [new_rule.cost]" + if (new_rule.execute()) // This should never fail since ready() returned 1 + if(new_rule.flags & HIGHLANDER_RULESET) + highlander_executed = TRUE + else if(new_rule.flags & ONLY_RULESET) + only_ruleset_executed = TRUE + log_game("DYNAMIC: Making a call to a specific ruleset...[new_rule.name]!") + executed_rules += new_rule + if (new_rule.persistent) + current_rules += new_rule + return TRUE + else if (forced) + log_game("DYNAMIC: The ruleset [new_rule.name] couldn't be executed due to lack of elligible players.") + return FALSE + +/datum/game_mode/dynamic/process() + if (pop_last_updated < world.time - (60 SECONDS)) + pop_last_updated = world.time + update_playercounts() + + for (var/datum/dynamic_ruleset/rule in current_rules) + if(rule.rule_process() == RULESET_STOP_PROCESSING) // If rule_process() returns 1 (RULESET_STOP_PROCESSING), stop processing. + current_rules -= rule + + if (midround_injection_cooldown < world.time) + if (GLOB.dynamic_forced_extended) + return + + // Somehow it manages to trigger midround multiple times so this was moved here. + // There is no way this should be able to trigger an injection twice now. + var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_midround_delay_max + GLOB.dynamic_midround_delay_min) + midround_injection_cooldown = (round(CLAMP(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_midround_delay_min, GLOB.dynamic_midround_delay_max)) + world.time) + + // Time to inject some threat into the round + if(EMERGENCY_ESCAPED_OR_ENDGAMED) // Unless the shuttle is gone + return + + log_game("DYNAMIC: Checking state of the round.") + + update_playercounts() + + if (prob(get_injection_chance())) + var/list/drafted_rules = list() + for (var/datum/dynamic_ruleset/midround/rule in midround_rules) + if (rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && threat >= rule.cost) + // Classic secret : only autotraitor/minor roles + if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET))) + continue + rule.candidates = list() + rule.candidates = current_players.Copy() + rule.trim_candidates() + if (rule.ready() && rule.candidates.len > 0) + drafted_rules[rule] = rule.get_weight() + if (drafted_rules.len > 0) + picking_midround_latejoin_rule(drafted_rules) + +/// Updates current_players. +/datum/game_mode/dynamic/proc/update_playercounts() + current_players[CURRENT_LIVING_PLAYERS] = list() + current_players[CURRENT_LIVING_ANTAGS] = list() + current_players[CURRENT_DEAD_PLAYERS] = list() + current_players[CURRENT_OBSERVERS] = list() + for (var/mob/M in GLOB.player_list) + if (istype(M, /mob/dead/new_player)) + continue + if (M.stat != DEAD) + current_players[CURRENT_LIVING_PLAYERS].Add(M) + if (M.mind && (M.mind.special_role || M.mind.antag_datums?.len > 0)) + current_players[CURRENT_LIVING_ANTAGS].Add(M) + else + if (istype(M,/mob/dead/observer)) + var/mob/dead/observer/O = M + if (O.started_as_observer) // Observers + current_players[CURRENT_OBSERVERS].Add(M) + continue + current_players[CURRENT_DEAD_PLAYERS].Add(M) // Players who actually died (and admins who ghosted, would be nice to avoid counting them somehow) + +/// Gets the chance for latejoin and midround injection, the dry_run argument is only used for forced injection. +/datum/game_mode/dynamic/proc/get_injection_chance(dry_run = FALSE) + if(forced_injection) + forced_injection = !dry_run + return 100 + var/chance = 0 + // If the high pop override is in effect, we reduce the impact of population on the antag injection chance + var/high_pop_factor = (current_players[CURRENT_LIVING_PLAYERS].len >= GLOB.dynamic_high_pop_limit) + var/max_pop_per_antag = max(5,15 - round(threat_level/10) - round(current_players[CURRENT_LIVING_PLAYERS].len/(high_pop_factor ? 10 : 5))) + if (!current_players[CURRENT_LIVING_ANTAGS].len) + chance += 50 // No antags at all? let's boost those odds! + else + var/current_pop_per_antag = current_players[CURRENT_LIVING_PLAYERS].len / current_players[CURRENT_LIVING_ANTAGS].len + if (current_pop_per_antag > max_pop_per_antag) + chance += min(50, 25+10*(current_pop_per_antag-max_pop_per_antag)) + else + chance += 25-10*(max_pop_per_antag-current_pop_per_antag) + if (current_players[CURRENT_DEAD_PLAYERS].len > current_players[CURRENT_LIVING_PLAYERS].len) + chance -= 30 // More than half the crew died? ew, let's calm down on antags + if (threat > 70) + chance += 15 + if (threat < 30) + chance -= 15 + return round(max(0,chance)) + +/// Removes type from the list +/datum/game_mode/dynamic/proc/remove_from_list(list/type_list, type) + for(var/I in type_list) + if(istype(I, type)) + type_list -= I + return type_list + +/// Checks if a type in blocking_list is in rule_list. +/datum/game_mode/dynamic/proc/check_blocking(list/blocking_list, list/rule_list) + if(blocking_list.len > 0) + for(var/blocking in blocking_list) + for(var/datum/executed in rule_list) + if(blocking == executed.type) + return TRUE + return FALSE + +/// Checks if client age is age or older. +/datum/game_mode/dynamic/proc/check_age(client/C, age) + enemy_minimum_age = age + if(get_remaining_days(C) == 0) + enemy_minimum_age = initial(enemy_minimum_age) + return TRUE // Available in 0 days = available right now = player is old enough to play. + enemy_minimum_age = initial(enemy_minimum_age) + return FALSE + +/datum/game_mode/dynamic/make_antag_chance(mob/living/carbon/human/newPlayer) + if (GLOB.dynamic_forced_extended) + return + if(EMERGENCY_ESCAPED_OR_ENDGAMED) // No more rules after the shuttle has left + return + + update_playercounts() + + if (forced_latejoin_rule) + forced_latejoin_rule.candidates = list(newPlayer) + forced_latejoin_rule.trim_candidates() + log_game("DYNAMIC: Forcing ruleset [forced_latejoin_rule]") + if (forced_latejoin_rule.ready(TRUE)) + picking_midround_latejoin_rule(list(forced_latejoin_rule), forced = TRUE) + forced_latejoin_rule = null + + else if (latejoin_injection_cooldown < world.time && prob(get_injection_chance())) + var/list/drafted_rules = list() + for (var/datum/dynamic_ruleset/latejoin/rule in latejoin_rules) + if (rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && threat >= rule.cost) + // Classic secret : only autotraitor/minor roles + if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET))) + continue + // No stacking : only one round-enter, unless > stacking_limit threat. + if (threat < GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking) + if(rule.flags & HIGHLANDER_RULESET && highlander_executed) + continue + + rule.candidates = list(newPlayer) + rule.trim_candidates() + if (rule.ready()) + drafted_rules[rule] = rule.get_weight() + + if (drafted_rules.len > 0 && picking_midround_latejoin_rule(drafted_rules)) + var/latejoin_injection_cooldown_middle = 0.5*(GLOB.dynamic_latejoin_delay_max + GLOB.dynamic_latejoin_delay_min) + latejoin_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(latejoin_injection_cooldown_middle), GLOB.dynamic_latejoin_delay_min, GLOB.dynamic_latejoin_delay_max)) + world.time + +/// Refund threat, but no more than threat_level. +/datum/game_mode/dynamic/proc/refund_threat(regain) + threat = min(threat_level,threat+regain) + +/// Generate threat and increase the threat_level if it goes beyond, capped at 100 +/datum/game_mode/dynamic/proc/create_threat(gain) + threat = min(100, threat+gain) + if(threat > threat_level) + threat_level = threat + +/// Expend threat, can't fall under 0. +/datum/game_mode/dynamic/proc/spend_threat(cost) + threat = max(threat-cost,0) + +/// Turns the value generated by lorentz distribution to threat value between 0 and 100. +/datum/game_mode/dynamic/proc/lorentz_to_threat(x) + switch (x) + if (-INFINITY to -20) + return rand(0, 10) + if (-20 to -10) + return RULE_OF_THREE(-40, -20, x) + 50 + if (-10 to -5) + return RULE_OF_THREE(-30, -10, x) + 50 + if (-5 to -2.5) + return RULE_OF_THREE(-20, -5, x) + 50 + if (-2.5 to -0) + return RULE_OF_THREE(-10, -2.5, x) + 50 + if (0 to 2.5) + return RULE_OF_THREE(10, 2.5, x) + 50 + if (2.5 to 5) + return RULE_OF_THREE(20, 5, x) + 50 + if (5 to 10) + return RULE_OF_THREE(30, 10, x) + 50 + if (10 to 20) + return RULE_OF_THREE(40, 20, x) + 50 + if (20 to INFINITY) + return rand(90, 100) diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets.dm b/code/game/gamemodes/dynamic/dynamic_rulesets.dm new file mode 100644 index 0000000000..66afcbfb92 --- /dev/null +++ b/code/game/gamemodes/dynamic/dynamic_rulesets.dm @@ -0,0 +1,211 @@ +/datum/dynamic_ruleset + /// For admin logging and round end screen. + var/name = "" + /// For admin logging and round end screen, do not change this unless making a new rule type. + var/ruletype = "" + /// If set to TRUE, the rule won't be discarded after being executed, and dynamic will call rule_process() every time it ticks. + var/persistent = FALSE + /// If set to TRUE, dynamic mode will be able to draft this ruleset again later on. (doesn't apply for roundstart rules) + var/repeatable = FALSE + /// If set higher than 0 decreases weight by itself causing the ruleset to appear less often the more it is repeated. + var/repeatable_weight_decrease = 2 + /// List of players that are being drafted for this rule + var/list/mob/candidates = list() + /// List of players that were selected for this rule + var/list/datum/mind/assigned = list() + /// Preferences flag such as ROLE_WIZARD that need to be turned on for players to be antag + var/antag_flag = null + /// The antagonist datum that is assigned to the mobs mind on ruleset execution. + var/datum/antagonist/antag_datum = null + /// The required minimum account age for this ruleset. + var/minimum_required_age = 7 + /// If set, and config flag protect_roles_from_antagonist is false, then the rule will not pick players from these roles. + var/list/protected_roles = list() + /// If set, rule will deny candidates from those roles always. + var/list/restricted_roles = list() + /// If set, rule will only accept candidates from those roles, IMPORTANT: DOES NOT WORK ON ROUNDSTART RULESETS. + var/list/exclusive_roles = list() + /// If set, there needs to be a certain amount of players doing those roles (among the players who won't be drafted) for the rule to be drafted IMPORTANT: DOES NOT WORK ON ROUNDSTART RULESETS. + var/list/enemy_roles = list() + /// If enemy_roles was set, this is the amount of enemy job workers needed per threat_level range (0-10,10-20,etc) IMPORTANT: DOES NOT WORK ON ROUNDSTART RULESETS. + var/required_enemies = list(1,1,0,0,0,0,0,0,0,0) + /// The rule needs this many candidates (post-trimming) to be executed (example: Cult needs 4 players at round start) + var/required_candidates = 0 + /// 1 -> 9, probability for this rule to be picked against other rules + var/weight = 5 + /// Threat cost for this rule, this is decreased from the mode's threat when the rule is executed. + var/cost = 0 + /// A flag that determines how the ruleset is handled + /// HIGHLANDER_RULESET are rulesets can end the round. + /// TRAITOR_RULESET and MINOR_RULESET can't end the round and have no difference right now. + var/flags = 0 + /// Pop range per requirement. If zero defaults to mode's pop_per_requirement. + var/pop_per_requirement = 0 + /// Requirements are the threat level requirements per pop range. + /// With the default values, The rule will never get drafted below 10 threat level (aka: "peaceful extended"), and it requires a higher threat level at lower pops. + var/list/requirements = list(40,30,20,10,10,10,10,10,10,10) + /// An alternative, static requirement used instead when pop is over mode's high_pop_limit. + var/high_population_requirement = 10 + /// Reference to the mode, use this instead of SSticker.mode. + var/datum/game_mode/dynamic/mode = null + /// If a role is to be considered another for the purpose of banning. + var/antag_flag_override = null + /// If a ruleset type which is in this list has been executed, then the ruleset will not be executed. + var/list/blocking_rules = list() + /// The minimum amount of players required for the rule to be considered. + var/minimum_players = 0 + /// The maximum amount of players required for the rule to be considered. + /// Anything below zero or exactly zero is ignored. + var/maximum_players = 0 + + +/datum/dynamic_ruleset/New() + ..() + if(CONFIG_GET(flag/protect_roles_from_antagonist)) + restricted_roles += protected_roles + if(CONFIG_GET(flag/protect_assistant_from_antagonist)) + restricted_roles += "Assistant" + + if (istype(SSticker.mode, /datum/game_mode/dynamic)) + mode = SSticker.mode + else if (GLOB.master_mode != "dynamic") // This is here to make roundstart forced ruleset function. + qdel(src) + +/datum/dynamic_ruleset/roundstart // One or more of those drafted at roundstart + ruletype = "Roundstart" + +/datum/dynamic_ruleset/roundstart/delayed/ // Executed with a 30 seconds delay + var/delay = 30 SECONDS + var/required_type = /mob/living/carbon/human // No ghosts, new players or silicons allowed. + +// Can be drafted when a player joins the server +/datum/dynamic_ruleset/latejoin + ruletype = "Latejoin" + +/// By default, a rule is acceptable if it satisfies the threat level/population requirements. +/// If your rule has extra checks, such as counting security officers, do that in ready() instead +/datum/dynamic_ruleset/proc/acceptable(population = 0, threat_level = 0) + if(minimum_players > population) + return FALSE + if(maximum_players > 0 && population > maximum_players) + return FALSE + if (population >= GLOB.dynamic_high_pop_limit) + return (threat_level >= high_population_requirement) + else + pop_per_requirement = pop_per_requirement > 0 ? pop_per_requirement : mode.pop_per_requirement + var/indice_pop = min(10,round(population/pop_per_requirement)+1) + return (threat_level >= requirements[indice_pop]) + +/// This is called if persistent variable is true everytime SSTicker ticks. +/datum/dynamic_ruleset/proc/rule_process() + return + +/// Called on game mode pre_setup, used for non-delayed roundstart rulesets only. +/// Do everything you need to do before job is assigned here. +/// IMPORTANT: ASSIGN special_role HERE +/datum/dynamic_ruleset/proc/pre_execute() + return TRUE + +/// Called on post_setup on roundstart and when the rule executes on midround and latejoin. +/// Give your candidates or assignees equipment and antag datum here. +/datum/dynamic_ruleset/proc/execute() + for(var/datum/mind/M in assigned) + M.add_antag_datum(antag_datum) + return TRUE + +/// Called after delay set in ruleset. +/// Give your candidates or assignees equipment and antag datum here. +/datum/dynamic_ruleset/roundstart/delayed/execute() + if (SSticker && SSticker.current_state < GAME_STATE_PLAYING) + CRASH("The delayed ruleset [name] executed before the round started.") + +/// Here you can perform any additional checks you want. (such as checking the map etc) +/// Remember that on roundstart no one knows what their job is at this point. +/// IMPORTANT: If ready() returns TRUE, that means pre_execute() or execute() should never fail! +/datum/dynamic_ruleset/proc/ready(forced = 0) + if (required_candidates > candidates.len) + return FALSE + return TRUE + +/// Gets weight of the ruleset +/// Note that this decreases weight if repeatable is TRUE and repeatable_weight_decrease is higher than 0 +/// Note: If you don't want repeatable rulesets to decrease their weight use the weight variable directly +/datum/dynamic_ruleset/proc/get_weight() + if(repeatable && weight > 1 && repeatable_weight_decrease > 0) + for(var/datum/dynamic_ruleset/DR in mode.executed_rules) + if(istype(DR, type)) + weight = max(weight-repeatable_weight_decrease,1) + return weight + +/// Here you can remove candidates that do not meet your requirements. +/// This means if their job is not correct or they have disconnected you can remove them from candidates here. +/// Usually this does not need to be changed unless you need some specific requirements from your candidates. +/datum/dynamic_ruleset/proc/trim_candidates() + return + +/// Counts how many players are ready at roundstart. +/// Used only by non-delayed roundstart rulesets. +/datum/dynamic_ruleset/proc/num_players() + . = 0 + for(var/mob/dead/new_player/P in GLOB.player_list) + if(P.client && P.ready == PLAYER_READY_TO_PLAY) + . ++ + +/// Set mode result and news report here. +/// Only called if ruleset is flagged as HIGHLANDER_RULESET +/datum/dynamic_ruleset/proc/round_result() + +/// Checks if round is finished, return true to end the round. +/// Only called if ruleset is flagged as HIGHLANDER_RULESET +/datum/dynamic_ruleset/proc/check_finished() + return FALSE + +////////////////////////////////////////////// +// // +// ROUNDSTART RULESETS // +// // +////////////////////////////////////////////// + +/// Checks if candidates are connected and if they are banned or don't want to be the antagonist. +/datum/dynamic_ruleset/roundstart/trim_candidates() + for(var/mob/dead/new_player/P in candidates) + if (!P.client || !P.mind) // Are they connected? + candidates.Remove(P) + continue + if(!mode.check_age(P.client, minimum_required_age)) + candidates.Remove(P) + continue + if(P.mind.special_role) // We really don't want to give antag to an antag. + candidates.Remove(P) + continue + if (!(antag_flag in P.client.prefs.be_special) || jobban_isbanned(P.ckey, list(antag_flag, ROLE_SYNDICATE)) || (antag_flag_override && jobban_isbanned(P.ckey, list(antag_flag_override, ROLE_SYNDICATE))))//are they willing and not antag-banned? + candidates.Remove(P) + continue + +/// Checks if candidates are required mob type, connected, banned and if the job is exclusive to the role. +/datum/dynamic_ruleset/roundstart/delayed/trim_candidates() + . = ..() + for (var/mob/P in candidates) + if (!istype(P, required_type)) + candidates.Remove(P) // Can be a new_player, etc. + continue + if(!mode.check_age(P.client, minimum_required_age)) + candidates.Remove(P) + continue + if (!P.client || !P.mind || !P.mind.assigned_role) // Are they connected? + candidates.Remove(P) + continue + if(P.mind.special_role || P.mind.antag_datums?.len > 0) // Are they an antag already? + candidates.Remove(P) + continue + if (!(antag_flag in P.client.prefs.be_special) || jobban_isbanned(P.ckey, list(antag_flag, ROLE_SYNDICATE)) || (antag_flag_override && jobban_isbanned(P.ckey, list(antag_flag_override, ROLE_SYNDICATE))))//are they willing and not antag-banned? + candidates.Remove(P) + continue + if ((exclusive_roles.len > 0) && !(P.mind.assigned_role in exclusive_roles)) // Is the rule exclusive to their job? + candidates.Remove(P) + continue + +/// Do your checks if the ruleset is ready to be executed here. +/// Should ignore certain checks if forced is TRUE +/datum/dynamic_ruleset/roundstart/ready(forced = FALSE) + return ..() diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm new file mode 100644 index 0000000000..dbaeaf0163 --- /dev/null +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm @@ -0,0 +1,110 @@ +////////////////////////////////////////////// +// // +// LATEJOIN RULESETS // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/latejoin/trim_candidates() + for(var/mob/P in candidates) + if (!P.client || !P.mind || !P.mind.assigned_role) // Are they connected? + candidates.Remove(P) + continue + if(!mode.check_age(P.client, minimum_required_age)) + candidates.Remove(P) + continue + if (!(antag_flag in P.client.prefs.be_special) || jobban_isbanned(P.ckey, list(antag_flag, ROLE_SYNDICATE)) || (antag_flag_override && jobban_isbanned(P.ckey, list(antag_flag_override))))//are they willing and not antag-banned? + candidates.Remove(P) + continue + if (P.mind.assigned_role in restricted_roles) // Does their job allow for it? + candidates.Remove(P) + continue + if ((exclusive_roles.len > 0) && !(P.mind.assigned_role in exclusive_roles)) // Is the rule exclusive to their job? + candidates.Remove(P) + continue + +/datum/dynamic_ruleset/latejoin/ready(forced = 0) + if (!forced) + var/job_check = 0 + if (enemy_roles.len > 0) + for (var/mob/M in mode.current_players[CURRENT_LIVING_PLAYERS]) + if (M.stat == DEAD) + continue // Dead players cannot count as opponents + if (M.mind && M.mind.assigned_role && (M.mind.assigned_role in enemy_roles) && (!(M in candidates) || (M.mind.assigned_role in restricted_roles))) + job_check++ // Checking for "enemies" (such as sec officers). To be counters, they must either not be candidates to that rule, or have a job that restricts them from it + + var/threat = round(mode.threat_level/10) + if (job_check < required_enemies[threat]) + return FALSE + return ..() + +/datum/dynamic_ruleset/latejoin/execute() + var/mob/M = pick(candidates) + assigned += M.mind + M.mind.special_role = antag_flag + M.mind.add_antag_datum(antag_datum) + return TRUE + +////////////////////////////////////////////// +// // +// SYNDICATE TRAITORS // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/latejoin/infiltrator + name = "Syndicate Infiltrator" + antag_datum = /datum/antagonist/traitor + antag_flag = ROLE_TRAITOR + protected_roles = list("Security Officer", "Warden", "Head of Personnel", "Detective", "Head of Security", "Captain") + restricted_roles = list("AI","Cyborg") + required_candidates = 1 + weight = 7 + cost = 5 + requirements = list(40,30,20,10,10,10,10,10,10,10) + high_population_requirement = 10 + repeatable = TRUE + flags = TRAITOR_RULESET + +////////////////////////////////////////////// +// // +// REVOLUTIONARY PROVOCATEUR // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/latejoin/provocateur + name = "Provocateur" + antag_datum = /datum/antagonist/rev/head + antag_flag = ROLE_REV_HEAD + antag_flag_override = ROLE_REV + restricted_roles = list("AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director") + enemy_roles = list("AI", "Cyborg", "Security Officer","Detective","Head of Security", "Captain", "Warden") + required_enemies = list(2,2,1,1,1,1,1,0,0,0) + required_candidates = 1 + weight = 2 + cost = 20 + requirements = list(101,101,70,40,30,20,20,20,20,20) + high_population_requirement = 50 + flags = HIGHLANDER_RULESET + var/required_heads = 3 + +/datum/dynamic_ruleset/latejoin/provocateur/ready(forced=FALSE) + if (forced) + required_heads = 1 + if(!..()) + return FALSE + var/head_check = 0 + for(var/mob/player in mode.current_players[CURRENT_LIVING_PLAYERS]) + if (player.mind.assigned_role in GLOB.command_positions) + head_check++ + return (head_check >= required_heads) + +/datum/dynamic_ruleset/latejoin/provocateur/execute() + var/mob/M = pick(candidates) + assigned += M.mind + M.mind.special_role = antag_flag + var/datum/antagonist/rev/head/new_head = new() + new_head.give_flash = TRUE + new_head.give_hud = TRUE + new_head.remove_clumsy = TRUE + new_head = M.mind.add_antag_datum(new_head) + new_head.rev_team.max_headrevs = 1 // Only one revhead if it is latejoin. + return TRUE diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm new file mode 100644 index 0000000000..440765718b --- /dev/null +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -0,0 +1,460 @@ +////////////////////////////////////////////// +// // +// MIDROUND RULESETS // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/midround // Can be drafted once in a while during a round + ruletype = "Midround" + /// If the ruleset should be restricted from ghost roles. + var/restrict_ghost_roles = TRUE + /// What type the ruleset is restricted to. + var/required_type = /mob/living/carbon/human + var/list/living_players = list() + var/list/living_antags = list() + var/list/dead_players = list() + var/list/list_observers = list() + +/datum/dynamic_ruleset/midround/from_ghosts + weight = 0 + /// Whether the ruleset should call generate_ruleset_body or not. + var/makeBody = TRUE + +/datum/dynamic_ruleset/midround/trim_candidates() + // Unlike the previous two types, these rulesets are not meant for /mob/dead/new_player + // And since I want those rulesets to be as flexible as possible, I'm not gonna put much here, + // + // All you need to know is that here, the candidates list contains 4 lists itself, indexed with the following defines: + // Candidates = list(CURRENT_LIVING_PLAYERS, CURRENT_LIVING_ANTAGS, CURRENT_DEAD_PLAYERS, CURRENT_OBSERVERS) + // So for example you can get the list of all current dead players with var/list/dead_players = candidates[CURRENT_DEAD_PLAYERS] + // Make sure to properly typecheck the mobs in those lists, as the dead_players list could contain ghosts, or dead players still in their bodies. + // We're still gonna trim the obvious (mobs without clients, jobbanned players, etc) + living_players = trim_list(candidates[CURRENT_LIVING_PLAYERS]) + living_antags = trim_list(candidates[CURRENT_LIVING_ANTAGS]) + dead_players = trim_list(candidates[CURRENT_DEAD_PLAYERS]) + list_observers = trim_list(candidates[CURRENT_OBSERVERS]) + +/datum/dynamic_ruleset/midround/proc/trim_list(list/L = list()) + var/list/trimmed_list = L.Copy() + var/antag_name = initial(antag_flag) + for(var/mob/M in trimmed_list) + if (!istype(M, required_type)) + trimmed_list.Remove(M) + continue + if (!M.client) // Are they connected? + trimmed_list.Remove(M) + continue + if(!mode.check_age(M.client, minimum_required_age)) + trimmed_list.Remove(M) + continue + if (!(antag_name in M.client.prefs.be_special) || jobban_isbanned(M.ckey, list(antag_name, ROLE_SYNDICATE)))//are they willing and not antag-banned? + trimmed_list.Remove(M) + continue + if (M.mind) + if (restrict_ghost_roles && M.mind.assigned_role in GLOB.exp_specialmap[EXP_TYPE_SPECIAL]) // Are they playing a ghost role? + trimmed_list.Remove(M) + continue + if (M.mind.assigned_role in restricted_roles || HAS_TRAIT(M, TRAIT_MINDSHIELD)) // Does their job allow it or are they mindshielded? + trimmed_list.Remove(M) + continue + if ((exclusive_roles.len > 0) && !(M.mind.assigned_role in exclusive_roles)) // Is the rule exclusive to their job? + trimmed_list.Remove(M) + continue + return trimmed_list + +// You can then for example prompt dead players in execute() to join as strike teams or whatever +// Or autotator someone + +// IMPORTANT, since /datum/dynamic_ruleset/midround may accept candidates from both living, dead, and even antag players, you need to manually check whether there are enough candidates +// (see /datum/dynamic_ruleset/midround/autotraitor/ready(var/forced = FALSE) for example) +/datum/dynamic_ruleset/midround/ready(forced = FALSE) + if (!forced) + var/job_check = 0 + if (enemy_roles.len > 0) + for (var/mob/M in living_players) + if (M.stat == DEAD) + continue // Dead players cannot count as opponents + if (M.mind && M.mind.assigned_role && (M.mind.assigned_role in enemy_roles) && (!(M in candidates) || (M.mind.assigned_role in restricted_roles))) + job_check++ // Checking for "enemies" (such as sec officers). To be counters, they must either not be candidates to that rule, or have a job that restricts them from it + + var/threat = round(mode.threat_level/10) + if (job_check < required_enemies[threat]) + return FALSE + return TRUE + +/datum/dynamic_ruleset/midround/from_ghosts/execute() + var/list/possible_candidates = list() + possible_candidates.Add(dead_players) + possible_candidates.Add(list_observers) + send_applications(possible_candidates) + if(assigned.len > 0) + return TRUE + else + return FALSE + +/// This sends a poll to ghosts if they want to be a ghost spawn from a ruleset. +/datum/dynamic_ruleset/midround/from_ghosts/proc/send_applications(list/possible_volunteers = list()) + if (possible_volunteers.len <= 0) // This shouldn't happen, as ready() should return FALSE if there is not a single valid candidate + message_admins("Possible volunteers was 0. This shouldn't appear, because of ready(), unless you forced it!") + return + message_admins("Polling [possible_volunteers.len] players to apply for the [name] ruleset.") + log_game("DYNAMIC: Polling [possible_volunteers.len] players to apply for the [name] ruleset.") + + candidates = pollGhostCandidates("The mode is looking for volunteers to become [antag_flag] for [name]", antag_flag, SSticker.mode, antag_flag, poll_time = 300) + + if(!candidates || candidates.len <= 0) + message_admins("The ruleset [name] received no applications.") + log_game("DYNAMIC: The ruleset [name] received no applications.") + mode.refund_threat(cost) + mode.threat_log += "[worldtime2text()]: Rule [name] refunded [cost] (no applications)" + mode.executed_rules -= src + return + + message_admins("[candidates.len] players volunteered for the ruleset [name].") + log_game("DYNAMIC: [candidates.len] players volunteered for [name].") + review_applications() + +/// Here is where you can check if your ghost applicants are valid for the ruleset. +/// Called by send_applications(). +/datum/dynamic_ruleset/midround/from_ghosts/proc/review_applications() + for (var/i = 1, i <= required_candidates, i++) + if(candidates.len <= 0) + if(i == 1) + // We have found no candidates so far and we are out of applicants. + mode.refund_threat(cost) + mode.threat_log += "[worldtime2text()]: Rule [name] refunded [cost] (all applications invalid)" + mode.executed_rules -= src + break + var/mob/applicant = pick(candidates) + candidates -= applicant + if(!isobserver(applicant)) + if(applicant.stat == DEAD) // Not an observer? If they're dead, make them one. + applicant = applicant.ghostize(FALSE) + else // Not dead? Disregard them, pick a new applicant + i-- + continue + + if(!applicant) + i-- + continue + + var/mob/new_character = applicant + + if (makeBody) + new_character = generate_ruleset_body(applicant) + + finish_setup(new_character, i) + assigned += applicant + notify_ghosts("[new_character] has been picked for the ruleset [name]!", source = new_character, action = NOTIFY_ORBIT, header="Something Interesting!") + +/datum/dynamic_ruleset/midround/from_ghosts/proc/generate_ruleset_body(mob/applicant) + var/mob/living/carbon/human/new_character = makeBody(applicant) + new_character.dna.remove_all_mutations() + return new_character + +/datum/dynamic_ruleset/midround/from_ghosts/proc/finish_setup(mob/new_character, index) + var/datum/antagonist/new_role = new antag_datum() + setup_role(new_role) + new_character.mind.add_antag_datum(new_role) + new_character.mind.special_role = antag_flag + +/datum/dynamic_ruleset/midround/from_ghosts/proc/setup_role(datum/antagonist/new_role) + return + +////////////////////////////////////////////// +// // +// SYNDICATE TRAITORS // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/midround/autotraitor + name = "Syndicate Sleeper Agent" + antag_datum = /datum/antagonist/traitor + antag_flag = ROLE_TRAITOR + protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel") + restricted_roles = list("Cyborg", "AI", "Positronic Brain") + required_candidates = 1 + weight = 7 + cost = 10 + requirements = list(50,40,30,20,10,10,10,10,10,10) + repeatable = TRUE + high_population_requirement = 10 + flags = TRAITOR_RULESET + +/datum/dynamic_ruleset/midround/autotraitor/acceptable(population = 0, threat = 0) + var/player_count = mode.current_players[CURRENT_LIVING_PLAYERS].len + var/antag_count = mode.current_players[CURRENT_LIVING_ANTAGS].len + var/max_traitors = round(player_count / 10) + 1 + if ((antag_count < max_traitors) && prob(mode.threat_level))//adding traitors if the antag population is getting low + return ..() + else + return FALSE + +/datum/dynamic_ruleset/midround/autotraitor/trim_candidates() + ..() + for(var/mob/living/player in living_players) + if(issilicon(player)) // Your assigned role doesn't change when you are turned into a silicon. + living_players -= player + continue + if(is_centcom_level(player.z)) + living_players -= player // We don't autotator people in CentCom + continue + if(player.mind && (player.mind.special_role || player.mind.antag_datums?.len > 0)) + living_players -= player // We don't autotator people with roles already + +/datum/dynamic_ruleset/midround/autotraitor/ready(forced = FALSE) + if (required_candidates > living_players.len) + return FALSE + return ..() + +/datum/dynamic_ruleset/midround/autotraitor/execute() + var/mob/M = pick(living_players) + assigned += M + living_players -= M + var/datum/antagonist/traitor/newTraitor = new + M.mind.add_antag_datum(newTraitor) + return TRUE + + +////////////////////////////////////////////// +// // +// Malfunctioning AI // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/midround/malf + name = "Malfunctioning AI" + antag_datum = /datum/antagonist/traitor + antag_flag = ROLE_MALF + enemy_roles = list("Security Officer", "Warden","Detective","Head of Security", "Captain", "Scientist", "Chemist", "Research Director", "Chief Engineer") + exclusive_roles = list("AI") + required_enemies = list(4,4,4,4,4,4,2,2,2,0) + required_candidates = 1 + weight = 3 + cost = 35 + requirements = list(101,101,80,70,60,60,50,50,40,40) + high_population_requirement = 35 + required_type = /mob/living/silicon/ai + var/ion_announce = 33 + var/removeDontImproveChance = 10 + +/datum/dynamic_ruleset/midround/malf/trim_candidates() + ..() + candidates = candidates[CURRENT_LIVING_PLAYERS] + for(var/mob/living/player in candidates) + if(!isAI(player)) + candidates -= player + continue + if(is_centcom_level(player.z)) + candidates -= player + continue + if(player.mind && (player.mind.special_role || player.mind.antag_datums?.len > 0)) + candidates -= player + +/datum/dynamic_ruleset/midround/malf/execute() + if(!candidates || !candidates.len) + return FALSE + var/mob/living/silicon/ai/M = pick(candidates) + candidates -= M + assigned += M.mind + var/datum/antagonist/traitor/AI = new + M.mind.special_role = antag_flag + M.mind.add_antag_datum(AI) + if(prob(ion_announce)) + priority_announce("Ion storm detected near the station. Please check all AI-controlled equipment for errors.", "Anomaly Alert", 'sound/ai/ionstorm.ogg') + if(prob(removeDontImproveChance)) + M.replace_random_law(generate_ion_law(), list(LAW_INHERENT, LAW_SUPPLIED, LAW_ION)) + else + M.add_ion_law(generate_ion_law()) + return TRUE + +////////////////////////////////////////////// +// // +// WIZARD (GHOST) // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/midround/from_ghosts/wizard + name = "Wizard" + antag_datum = /datum/antagonist/wizard + antag_flag = ROLE_WIZARD + enemy_roles = list("Security Officer","Detective","Head of Security", "Captain") + required_enemies = list(2,2,1,1,1,1,1,0,0,0) + required_candidates = 1 + weight = 1 + cost = 20 + requirements = list(90,90,70,40,30,20,10,10,10,10) + high_population_requirement = 50 + repeatable = TRUE + +/datum/dynamic_ruleset/midround/from_ghosts/wizard/ready(forced = FALSE) + if (required_candidates > (dead_players.len + list_observers.len)) + return FALSE + if(GLOB.wizardstart.len == 0) + log_admin("Cannot accept Wizard ruleset. Couldn't find any wizard spawn points.") + message_admins("Cannot accept Wizard ruleset. Couldn't find any wizard spawn points.") + return FALSE + return ..() + +/datum/dynamic_ruleset/midround/from_ghosts/wizard/finish_setup(mob/new_character, index) + ..() + new_character.forceMove(pick(GLOB.wizardstart)) + +////////////////////////////////////////////// +// // +// NUCLEAR OPERATIVES (MIDROUND) // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/midround/from_ghosts/nuclear + name = "Nuclear Assault" + antag_flag = ROLE_OPERATIVE + antag_datum = /datum/antagonist/nukeop + enemy_roles = list("AI", "Cyborg", "Security Officer", "Warden","Detective","Head of Security", "Captain") + required_enemies = list(3,3,3,3,3,2,1,1,0,0) + required_candidates = 5 + weight = 5 + cost = 35 + requirements = list(90,90,90,80,60,40,30,20,10,10) + high_population_requirement = 10 + var/operative_cap = list(2,2,3,3,4,5,5,5,5,5) + var/datum/team/nuclear/nuke_team + flags = HIGHLANDER_RULESET + +/datum/dynamic_ruleset/midround/from_ghosts/nuclear/acceptable(population=0, threat=0) + if (locate(/datum/dynamic_ruleset/roundstart/nuclear) in mode.executed_rules) + return FALSE // Unavailable if nuke ops were already sent at roundstart + var/indice_pop = min(10,round(living_players.len/5)+1) + required_candidates = operative_cap[indice_pop] + return ..() + +/datum/dynamic_ruleset/midround/from_ghosts/nuclear/ready(forced = FALSE) + if (required_candidates > (dead_players.len + list_observers.len)) + return FALSE + return ..() + +/datum/dynamic_ruleset/midround/from_ghosts/nuclear/finish_setup(mob/new_character, index) + new_character.mind.special_role = "Nuclear Operative" + new_character.mind.assigned_role = "Nuclear Operative" + if (index == 1) // Our first guy is the leader + var/datum/antagonist/nukeop/leader/new_role = new + nuke_team = new_role.nuke_team + new_character.mind.add_antag_datum(new_role) + else + return ..() + +////////////////////////////////////////////// +// // +// BLOB (GHOST) // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/midround/from_ghosts/blob + name = "Blob" + antag_datum = /datum/antagonist/blob + antag_flag = ROLE_BLOB + enemy_roles = list("Security Officer", "Detective", "Head of Security", "Captain") + required_enemies = list(2,2,1,1,1,1,1,0,0,0) + required_candidates = 1 + weight = 4 + cost = 10 + requirements = list(101,101,101,80,60,50,30,20,10,10) + high_population_requirement = 50 + repeatable = TRUE + +/datum/dynamic_ruleset/midround/from_ghosts/blob/generate_ruleset_body(mob/applicant) + var/body = applicant.become_overmind() + return body + +////////////////////////////////////////////// +// // +// XENOMORPH (GHOST) // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/midround/from_ghosts/xenomorph + name = "Alien Infestation" + antag_datum = /datum/antagonist/xeno + antag_flag = ROLE_ALIEN + enemy_roles = list("Security Officer", "Detective", "Head of Security", "Captain") + required_enemies = list(2,2,1,1,1,1,1,0,0,0) + required_candidates = 1 + weight = 3 + cost = 10 + requirements = list(101,101,101,70,50,40,20,15,10,10) + high_population_requirement = 50 + repeatable = TRUE + var/list/vents = list() + +/datum/dynamic_ruleset/midround/from_ghosts/xenomorph/execute() + // 50% chance of being incremented by one + required_candidates += prob(50) + for(var/obj/machinery/atmospherics/components/unary/vent_pump/temp_vent in GLOB.machines) + if(QDELETED(temp_vent)) + continue + if(is_station_level(temp_vent.loc.z) && !temp_vent.welded) + var/datum/pipeline/temp_vent_parent = temp_vent.parents[1] + if(!temp_vent_parent) + continue // No parent vent + // Stops Aliens getting stuck in small networks. + // See: Security, Virology + if(temp_vent_parent.other_atmosmch.len > 20) + vents += temp_vent + if(!vents.len) + return FALSE + . = ..() + +/datum/dynamic_ruleset/midround/from_ghosts/xenomorph/generate_ruleset_body(mob/applicant) + var/obj/vent = pick_n_take(vents) + var/mob/living/carbon/alien/larva/new_xeno = new(vent.loc) + new_xeno.key = applicant.key + message_admins("[ADMIN_LOOKUPFLW(new_xeno)] has been made into an alien by the midround ruleset.") + log_game("DYNAMIC: [key_name(new_xeno)] was spawned as an alien by the midround ruleset.") + return new_xeno + +////////////////////////////////////////////// +// // +// NIGHTMARE (GHOST) // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/midround/from_ghosts/nightmare + name = "Nightmare" + antag_datum = /datum/antagonist/nightmare + antag_flag = "Nightmare" + antag_flag_override = ROLE_ALIEN + enemy_roles = list("Security Officer", "Detective", "Head of Security", "Captain") + required_enemies = list(2,2,1,1,1,1,1,0,0,0) + required_candidates = 1 + weight = 3 + cost = 10 + requirements = list(101,101,101,70,50,40,20,15,10,10) + high_population_requirement = 50 + repeatable = TRUE + var/list/spawn_locs = list() + +/datum/dynamic_ruleset/midround/from_ghosts/nightmare/execute() + for(var/X in GLOB.xeno_spawn) + var/turf/T = X + var/light_amount = T.get_lumcount() + if(light_amount < SHADOW_SPECIES_LIGHT_THRESHOLD) + spawn_locs += T + if(!spawn_locs.len) + return FALSE + . = ..() + +/datum/dynamic_ruleset/midround/from_ghosts/nightmare/generate_ruleset_body(mob/applicant) + var/datum/mind/player_mind = new /datum/mind(applicant.key) + player_mind.active = TRUE + + var/mob/living/carbon/human/S = new (pick(spawn_locs)) + player_mind.transfer_to(S) + player_mind.assigned_role = "Nightmare" + player_mind.special_role = "Nightmare" + player_mind.add_antag_datum(/datum/antagonist/nightmare) + S.set_species(/datum/species/shadow/nightmare) + + playsound(S, 'sound/magic/ethereal_exit.ogg', 50, 1, -1) + message_admins("[ADMIN_LOOKUPFLW(S)] has been made into a Nightmare by the midround ruleset.") + log_game("DYNAMIC: [key_name(S)] was spawned as a Nightmare by the midround ruleset.") + return S diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm new file mode 100644 index 0000000000..76b1952492 --- /dev/null +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm @@ -0,0 +1,729 @@ + +////////////////////////////////////////////// +// // +// SYNDICATE TRAITORS // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/roundstart/traitor + name = "Traitors" + persistent = TRUE + antag_flag = ROLE_TRAITOR + antag_datum = /datum/antagonist/traitor/ + minimum_required_age = 0 + protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain") + restricted_roles = list("Cyborg") + required_candidates = 1 + weight = 5 + cost = 10 + requirements = list(10,10,10,10,10,10,10,10,10,10) + high_population_requirement = 10 + var/autotraitor_cooldown = 450 // 15 minutes (ticks once per 2 sec) + +/datum/dynamic_ruleset/roundstart/traitor/pre_execute() + var/traitor_scaling_coeff = 10 - max(0,round(mode.threat_level/10)-5) // Above 50 threat level, coeff goes down by 1 for every 10 levels + var/num_traitors = min(round(mode.candidates.len / traitor_scaling_coeff) + 1, candidates.len) + for (var/i = 1 to num_traitors) + var/mob/M = pick(candidates) + candidates -= M + assigned += M.mind + M.mind.special_role = ROLE_TRAITOR + M.mind.restricted_roles = restricted_roles + return TRUE + +/datum/dynamic_ruleset/roundstart/traitor/rule_process() + if (autotraitor_cooldown > 0) + autotraitor_cooldown-- + else + autotraitor_cooldown = 450 // 15 minutes + message_admins("Checking if we can turn someone into a traitor.") + log_game("DYNAMIC: Checking if we can turn someone into a traitor.") + mode.picking_specific_rule(/datum/dynamic_ruleset/midround/autotraitor) + +////////////////////////////////////////// +// // +// BLOOD BROTHERS // +// // +////////////////////////////////////////// + +/datum/dynamic_ruleset/roundstart/traitorbro + name = "Blood Brothers" + antag_flag = ROLE_BROTHER + antag_datum = /datum/antagonist/brother/ + protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain") + restricted_roles = list("Cyborg", "AI") + required_candidates = 2 + weight = 4 + cost = 10 + requirements = list(40,30,30,20,20,15,15,15,10,10) + high_population_requirement = 15 + var/list/datum/team/brother_team/pre_brother_teams = list() + var/const/team_amount = 2 // Hard limit on brother teams if scaling is turned off + var/const/min_team_size = 2 + +/datum/dynamic_ruleset/roundstart/traitorbro/pre_execute() + var/num_teams = team_amount + var/bsc = CONFIG_GET(number/brother_scaling_coeff) + if(bsc) + num_teams = max(1, round(num_players() / bsc)) + + for(var/j = 1 to num_teams) + if(candidates.len < min_team_size || candidates.len < required_candidates) + break + var/datum/team/brother_team/team = new + var/team_size = prob(10) ? min(3, candidates.len) : 2 + for(var/k = 1 to team_size) + var/mob/bro = pick(candidates) + candidates -= bro + assigned += bro.mind + team.add_member(bro.mind) + bro.mind.special_role = "brother" + bro.mind.restricted_roles = restricted_roles + pre_brother_teams += team + return TRUE + +/datum/dynamic_ruleset/roundstart/traitorbro/execute() + for(var/datum/team/brother_team/team in pre_brother_teams) + team.pick_meeting_area() + team.forge_brother_objectives() + for(var/datum/mind/M in team.members) + M.add_antag_datum(/datum/antagonist/brother, team) + team.update_name() + mode.brother_teams += pre_brother_teams + return TRUE + +////////////////////////////////////////////// +// // +// CHANGELINGS // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/roundstart/changeling + name = "Changelings" + antag_flag = ROLE_CHANGELING + antag_datum = /datum/antagonist/changeling + protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain") + restricted_roles = list("AI", "Cyborg") + required_candidates = 1 + weight = 3 + cost = 30 + requirements = list(80,70,60,50,40,20,20,10,10,10) + high_population_requirement = 10 + var/team_mode_probability = 30 + +/datum/dynamic_ruleset/roundstart/changeling/pre_execute() + var/num_changelings = min(round(mode.candidates.len / 10) + 1, candidates.len) + for (var/i = 1 to num_changelings) + var/mob/M = pick(candidates) + candidates -= M + assigned += M.mind + M.mind.restricted_roles = restricted_roles + M.mind.special_role = ROLE_CHANGELING + return TRUE + +/datum/dynamic_ruleset/roundstart/changeling/execute() + var/team_mode = FALSE + if(prob(team_mode_probability)) + team_mode = TRUE + var/list/team_objectives = subtypesof(/datum/objective/changeling_team_objective) + var/list/possible_team_objectives = list() + for(var/T in team_objectives) + var/datum/objective/changeling_team_objective/CTO = T + if(assigned.len >= initial(CTO.min_lings)) + possible_team_objectives += T + + if(possible_team_objectives.len && prob(20*assigned.len)) + GLOB.changeling_team_objective_type = pick(possible_team_objectives) + for(var/datum/mind/changeling in assigned) + var/datum/antagonist/changeling/new_antag = new antag_datum() + new_antag.team_mode = team_mode + changeling.add_antag_datum(new_antag) + return TRUE + +////////////////////////////////////////////// +// // +// WIZARDS // +// // +////////////////////////////////////////////// + +// Dynamic is a wonderful thing that adds wizards to every round and then adds even more wizards during the round. +/datum/dynamic_ruleset/roundstart/wizard + name = "Wizard" + antag_flag = ROLE_WIZARD + antag_datum = /datum/antagonist/wizard + minimum_required_age = 14 + restricted_roles = list("Head of Security", "Captain") // Just to be sure that a wizard getting picked won't ever imply a Captain or HoS not getting drafted + required_candidates = 1 + weight = 2 + cost = 30 + requirements = list(90,90,70,40,30,20,10,10,10,10) + high_population_requirement = 10 + var/list/roundstart_wizards = list() + +/datum/dynamic_ruleset/roundstart/wizard/acceptable(population=0, threat=0) + if(GLOB.wizardstart.len == 0) + log_admin("Cannot accept Wizard ruleset. Couldn't find any wizard spawn points.") + message_admins("Cannot accept Wizard ruleset. Couldn't find any wizard spawn points.") + return FALSE + return ..() + +/datum/dynamic_ruleset/roundstart/wizard/pre_execute() + if(GLOB.wizardstart.len == 0) + return FALSE + + var/mob/M = pick(candidates) + if (M) + candidates -= M + assigned += M.mind + M.mind.assigned_role = ROLE_WIZARD + M.mind.special_role = ROLE_WIZARD + + return TRUE + +/datum/dynamic_ruleset/roundstart/wizard/execute() + for(var/datum/mind/M in assigned) + M.current.forceMove(pick(GLOB.wizardstart)) + M.add_antag_datum(new antag_datum()) + return TRUE + +////////////////////////////////////////////// +// // +// BLOOD CULT // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/roundstart/bloodcult + name = "Blood Cult" + antag_flag = ROLE_CULTIST + antag_datum = /datum/antagonist/cult + minimum_required_age = 14 + restricted_roles = list("AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Chaplain", "Head of Personnel") + required_candidates = 2 + weight = 3 + cost = 30 + requirements = list(100,90,80,60,40,30,10,10,10,10) + high_population_requirement = 10 + flags = HIGHLANDER_RULESET + var/cultist_cap = list(2,2,2,3,3,4,4,4,4,4) + var/datum/team/cult/main_cult + +/datum/dynamic_ruleset/roundstart/bloodcult/ready(forced = FALSE) + var/indice_pop = min(10,round(mode.roundstart_pop_ready/pop_per_requirement)+1) + required_candidates = cultist_cap[indice_pop] + . = ..() + +/datum/dynamic_ruleset/roundstart/bloodcult/pre_execute() + var/indice_pop = min(10,round(mode.roundstart_pop_ready/pop_per_requirement)+1) + var/cultists = cultist_cap[indice_pop] + for(var/cultists_number = 1 to cultists) + if(candidates.len <= 0) + break + var/mob/M = pick(candidates) + candidates -= M + assigned += M.mind + M.mind.special_role = ROLE_CULTIST + M.mind.restricted_roles = restricted_roles + return TRUE + +/datum/dynamic_ruleset/roundstart/bloodcult/execute() + main_cult = new + for(var/datum/mind/M in assigned) + var/datum/antagonist/cult/new_cultist = new antag_datum() + new_cultist.cult_team = main_cult + new_cultist.give_equipment = TRUE + M.add_antag_datum(new_cultist) + main_cult.setup_objectives() + return TRUE + +/datum/dynamic_ruleset/roundstart/bloodcult/round_result() + ..() + if(main_cult.check_cult_victory()) + SSticker.mode_result = "win - cult win" + SSticker.news_report = CULT_SUMMON + else + SSticker.mode_result = "loss - staff stopped the cult" + SSticker.news_report = CULT_FAILURE + +////////////////////////////////////////////// +// // +// NUCLEAR OPERATIVES // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/roundstart/nuclear + name = "Nuclear Emergency" + antag_flag = ROLE_OPERATIVE + antag_datum = /datum/antagonist/nukeop + var/datum/antagonist/antag_leader_datum = /datum/antagonist/nukeop/leader + minimum_required_age = 14 + restricted_roles = list("Head of Security", "Captain") // Just to be sure that a nukie getting picked won't ever imply a Captain or HoS not getting drafted + required_candidates = 5 + weight = 3 + cost = 40 + requirements = list(90,90,90,80,60,40,30,20,10,10) + high_population_requirement = 10 + flags = HIGHLANDER_RULESET + var/operative_cap = list(2,2,2,3,3,3,4,4,5,5) + var/datum/team/nuclear/nuke_team + +/datum/dynamic_ruleset/roundstart/nuclear/ready(forced = FALSE) + var/indice_pop = min(10,round(mode.roundstart_pop_ready/pop_per_requirement)+1) + required_candidates = operative_cap[indice_pop] + . = ..() + +/datum/dynamic_ruleset/roundstart/nuclear/pre_execute() + // If ready() did its job, candidates should have 5 or more members in it + + var/indice_pop = min(10,round(mode.roundstart_pop_ready/5)+1) + var/operatives = operative_cap[indice_pop] + for(var/operatives_number = 1 to operatives) + if(candidates.len <= 0) + break + var/mob/M = pick(candidates) + candidates -= M + assigned += M.mind + M.mind.assigned_role = "Nuclear Operative" + M.mind.special_role = "Nuclear Operative" + return TRUE + +/datum/dynamic_ruleset/roundstart/nuclear/execute() + var/leader = TRUE + for(var/datum/mind/M in assigned) + if (leader) + leader = FALSE + var/datum/antagonist/nukeop/leader/new_op = M.add_antag_datum(antag_leader_datum) + nuke_team = new_op.nuke_team + else + var/datum/antagonist/nukeop/new_op = new antag_datum() + M.add_antag_datum(new_op) + return TRUE + +/datum/dynamic_ruleset/roundstart/nuclear/round_result() + var result = nuke_team.get_result() + switch(result) + if(NUKE_RESULT_FLUKE) + SSticker.mode_result = "loss - syndicate nuked - disk secured" + SSticker.news_report = NUKE_SYNDICATE_BASE + if(NUKE_RESULT_NUKE_WIN) + SSticker.mode_result = "win - syndicate nuke" + SSticker.news_report = STATION_NUKED + if(NUKE_RESULT_NOSURVIVORS) + SSticker.mode_result = "halfwin - syndicate nuke - did not evacuate in time" + SSticker.news_report = STATION_NUKED + if(NUKE_RESULT_WRONG_STATION) + SSticker.mode_result = "halfwin - blew wrong station" + SSticker.news_report = NUKE_MISS + if(NUKE_RESULT_WRONG_STATION_DEAD) + SSticker.mode_result = "halfwin - blew wrong station - did not evacuate in time" + SSticker.news_report = NUKE_MISS + if(NUKE_RESULT_CREW_WIN_SYNDIES_DEAD) + SSticker.mode_result = "loss - evacuation - disk secured - syndi team dead" + SSticker.news_report = OPERATIVES_KILLED + if(NUKE_RESULT_CREW_WIN) + SSticker.mode_result = "loss - evacuation - disk secured" + SSticker.news_report = OPERATIVES_KILLED + if(NUKE_RESULT_DISK_LOST) + SSticker.mode_result = "halfwin - evacuation - disk not secured" + SSticker.news_report = OPERATIVE_SKIRMISH + if(NUKE_RESULT_DISK_STOLEN) + SSticker.mode_result = "halfwin - detonation averted" + SSticker.news_report = OPERATIVE_SKIRMISH + else + SSticker.mode_result = "halfwin - interrupted" + SSticker.news_report = OPERATIVE_SKIRMISH + +////////////////////////////////////////////// +// // +// REVS // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/roundstart/delayed/revs + name = "Revolution" + persistent = TRUE + antag_flag = ROLE_REV_HEAD + antag_flag_override = ROLE_REV + antag_datum = /datum/antagonist/rev/head + minimum_required_age = 14 + restricted_roles = list("AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director") + required_candidates = 3 + weight = 2 + cost = 35 + requirements = list(101,101,70,40,30,20,10,10,10,10) + high_population_requirement = 10 + delay = 5 MINUTES + flags = HIGHLANDER_RULESET + // I give up, just there should be enough heads with 35 players... + minimum_players = 35 + var/datum/team/revolution/revolution + var/finished = 0 + +/datum/dynamic_ruleset/roundstart/delayed/revs/execute() + var/max_canditates = 4 + revolution = new() + for(var/i = 1 to max_canditates) + if(candidates.len <= 0) + break + var/mob/M = pick(candidates) + candidates -= M + assigned += M.mind + M.mind.restricted_roles = restricted_roles + M.mind.special_role = antag_flag + var/datum/antagonist/rev/head/new_head = new antag_datum() + new_head.give_flash = TRUE + new_head.give_hud = TRUE + new_head.remove_clumsy = TRUE + M.mind.add_antag_datum(new_head,revolution) + + revolution.update_objectives() + revolution.update_heads() + SSshuttle.registerHostileEnvironment(src) + + return TRUE + +/datum/dynamic_ruleset/roundstart/delayed/revs/rule_process() + if(check_rev_victory()) + finished = 1 + else if(check_heads_victory()) + finished = 2 + return + +/datum/dynamic_ruleset/roundstart/delayed/revs/check_finished() + if(CONFIG_GET(keyed_list/continuous)["revolution"]) + if(finished) + SSshuttle.clearHostileEnvironment(src) + return ..() + if(finished != 0) + return TRUE + else + return ..() + +/datum/dynamic_ruleset/roundstart/delayed/revs/proc/check_rev_victory() + for(var/datum/objective/mutiny/objective in revolution.objectives) + if(!(objective.check_completion())) + return FALSE + return TRUE + +/datum/dynamic_ruleset/roundstart/delayed/revs/proc/check_heads_victory() + for(var/datum/mind/rev_mind in revolution.head_revolutionaries()) + var/turf/T = get_turf(rev_mind.current) + if(!considered_afk(rev_mind) && considered_alive(rev_mind) && is_station_level(T.z)) + if(ishuman(rev_mind.current) || ismonkey(rev_mind.current)) + return FALSE + return TRUE + +/datum/dynamic_ruleset/roundstart/delayed/revs/round_result() + if(finished == 1) + SSticker.mode_result = "win - heads killed" + SSticker.news_report = REVS_WIN + else if(finished == 2) + SSticker.mode_result = "loss - rev heads killed" + SSticker.news_report = REVS_LOSE + +// Admin only rulesets. The threat requirement is 101 so it is not possible to roll them. + +////////////////////////////////////////////// +// // +// EXTENDED // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/roundstart/extended + name = "Extended" + antag_flag = null + antag_datum = null + restricted_roles = list() + required_candidates = 0 + weight = 3 + cost = 0 + requirements = list(101,101,101,101,101,101,101,101,101,101) + high_population_requirement = 101 + +/datum/dynamic_ruleset/roundstart/extended/pre_execute() + message_admins("Starting a round of extended.") + log_game("Starting a round of extended.") + mode.spend_threat(mode.threat) + return TRUE + +////////////////////////////////////////////// +// // +// CLOCKCULT // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/roundstart/clockcult + name = "Clockcult" + antag_flag = ROLE_SERVANT_OF_RATVAR + antag_datum = /datum/antagonist/clockcult + restricted_roles = list("AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Chaplain", "Head of Personnel") + required_candidates = 4 + weight = 3 + cost = 0 + requirements = list(101,101,101,101,101,101,101,101,101,101) + high_population_requirement = 101 + flags = HIGHLANDER_RULESET + var/ark_time + +/datum/dynamic_ruleset/roundstart/clockcult/pre_execute() + var/list/errorList = list() + var/list/reebes = SSmapping.LoadGroup(errorList, "Reebe", "map_files/generic", "City_of_Cogs.dmm", default_traits = ZTRAITS_REEBE, silent = TRUE) + if(errorList.len) + message_admins("Reebe failed to load!") + log_game("Reebe failed to load!") + return FALSE + for(var/datum/parsed_map/PM in reebes) + PM.initTemplateBounds() + + var/starter_servants = 4 + var/number_players = num_players() + if(number_players > 30) + number_players -= 30 + starter_servants += round(number_players / 10) + starter_servants = min(starter_servants, 8) + for (var/i in 1 to starter_servants) + var/mob/servant = pick(candidates) + candidates -= servant + assigned += servant.mind + servant.mind.assigned_role = ROLE_SERVANT_OF_RATVAR + servant.mind.special_role = ROLE_SERVANT_OF_RATVAR + ark_time = 30 + round((number_players / 5)) + ark_time = min(ark_time, 35) + return TRUE + +/datum/dynamic_ruleset/roundstart/clockcult/execute() + var/list/spread_out_spawns = GLOB.servant_spawns.Copy() + for(var/datum/mind/servant in assigned) + var/mob/S = servant.current + if(!spread_out_spawns.len) + spread_out_spawns = GLOB.servant_spawns.Copy() + log_game("[key_name(servant)] was made an initial servant of Ratvar") + var/turf/T = pick_n_take(spread_out_spawns) + S.forceMove(T) + greet_servant(S) + equip_servant(S) + add_servant_of_ratvar(S, TRUE) + var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar //that's a mouthful + G.final_countdown(ark_time) + return TRUE + +/datum/dynamic_ruleset/roundstart/clockcult/proc/greet_servant(mob/M) //Description of their role + if(!M) + return 0 + to_chat(M, "You are a servant of Ratvar, the Clockwork Justiciar!") + to_chat(M, "You have approximately [ark_time] minutes until the Ark activates.") + to_chat(M, "Unlock Script scripture by converting a new servant.") + to_chat(M, "Application scripture will be unlocked halfway until the Ark's activation.") + M.playsound_local(get_turf(M), 'sound/ambience/antag/clockcultalr.ogg', 100, FALSE, pressure_affected = FALSE) + return 1 + +/datum/dynamic_ruleset/roundstart/clockcult/proc/equip_servant(mob/living/M) //Grants a clockwork slab to the mob, with one of each component + if(!M || !ishuman(M)) + return FALSE + var/mob/living/carbon/human/L = M + L.equipOutfit(/datum/outfit/servant_of_ratvar) + var/obj/item/clockwork/slab/S = new + var/slot = "At your feet" + var/list/slots = list("In your left pocket" = SLOT_L_STORE, "In your right pocket" = SLOT_R_STORE, "In your backpack" = SLOT_IN_BACKPACK, "On your belt" = SLOT_BELT) + if(ishuman(L)) + var/mob/living/carbon/human/H = L + slot = H.equip_in_one_of_slots(S, slots) + if(slot == "In your backpack") + slot = "In your [H.back.name]" + if(slot == "At your feet") + if(!S.forceMove(get_turf(L))) + qdel(S) + if(S && !QDELETED(S)) + to_chat(L, "There is a paper in your backpack! It'll tell you if anything's changed, as well as what to expect.") + to_chat(L, "[slot] is a clockwork slab, a multipurpose tool used to construct machines and invoke ancient words of power. If this is your first time \ + as a servant, you can find a concise tutorial in the Recollection category of its interface.") + to_chat(L, "If you want more information, you can read the wiki page to learn more.") + return TRUE + return FALSE + +/datum/dynamic_ruleset/roundstart/clockcult/round_result() + if(GLOB.clockwork_gateway_activated) + SSticker.news_report = CLOCK_SUMMON + SSticker.mode_result = "win - servants completed their objective (summon ratvar)" + else + SSticker.news_report = CULT_FAILURE + SSticker.mode_result = "loss - servants failed their objective (summon ratvar)" + +////////////////////////////////////////////// +// // +// CLOWN OPS // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/roundstart/nuclear/clown_ops + name = "Clown Ops" + antag_datum = /datum/antagonist/nukeop/clownop + antag_leader_datum = /datum/antagonist/nukeop/leader/clownop + requirements = list(101,101,101,101,101,101,101,101,101,101) + high_population_requirement = 101 + +/datum/dynamic_ruleset/roundstart/nuclear/clown_ops/pre_execute() + . = ..() + if(.) + for(var/obj/machinery/nuclearbomb/syndicate/S in GLOB.nuke_list) + var/turf/T = get_turf(S) + if(T) + qdel(S) + new /obj/machinery/nuclearbomb/syndicate/bananium(T) + for(var/datum/mind/V in assigned) + V.assigned_role = "Clown Operative" + V.special_role = "Clown Operative" + +////////////////////////////////////////////// +// // +// DEVIL // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/roundstart/devil + name = "Devil" + antag_flag = ROLE_DEVIL + antag_datum = /datum/antagonist/devil + restricted_roles = list("Lawyer", "Curator", "Chaplain", "Head of Security", "Captain", "AI") + required_candidates = 1 + weight = 3 + cost = 0 + requirements = list(101,101,101,101,101,101,101,101,101,101) + high_population_requirement = 101 + var/devil_limit = 4 // Hard limit on devils if scaling is turned off + +/datum/dynamic_ruleset/roundstart/devil/pre_execute() + var/tsc = CONFIG_GET(number/traitor_scaling_coeff) + var/num_devils = 1 + + if(tsc) + num_devils = max(required_candidates, min(round(num_players() / (tsc * 3)) + 2, round(num_players() / (tsc * 1.5)))) + else + num_devils = max(required_candidates, min(num_players(), devil_limit)) + + for(var/j = 0, j < num_devils, j++) + if (!candidates.len) + break + var/mob/devil = pick(candidates) + assigned += devil + candidates -= devil + devil.mind.special_role = ROLE_DEVIL + devil.mind.restricted_roles = restricted_roles + + log_game("[key_name(devil)] has been selected as a devil") + return TRUE + +/datum/dynamic_ruleset/roundstart/devil/execute() + for(var/datum/mind/devil in assigned) + add_devil(devil.current, ascendable = TRUE) + add_devil_objectives(devil,2) + return TRUE + +/datum/dynamic_ruleset/roundstart/devil/proc/add_devil_objectives(datum/mind/devil_mind, quantity) + var/list/validtypes = list(/datum/objective/devil/soulquantity, /datum/objective/devil/soulquality, /datum/objective/devil/sintouch, /datum/objective/devil/buy_target) + var/datum/antagonist/devil/D = devil_mind.has_antag_datum(/datum/antagonist/devil) + for(var/i = 1 to quantity) + var/type = pick(validtypes) + var/datum/objective/devil/objective = new type(null) + objective.owner = devil_mind + D.objectives += objective + if(!istype(objective, /datum/objective/devil/buy_target)) + validtypes -= type + else + objective.find_target() + +////////////////////////////////////////////// +// // +// MONKEY // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/roundstart/monkey + name = "Monkey" + antag_flag = ROLE_MONKEY + antag_datum = /datum/antagonist/monkey/leader + restricted_roles = list("Cyborg", "AI") + required_candidates = 1 + weight = 3 + cost = 0 + requirements = list(101,101,101,101,101,101,101,101,101,101) + high_population_requirement = 101 + var/players_per_carrier = 30 + var/monkeys_to_win = 1 + var/escaped_monkeys = 0 + var/datum/team/monkey/monkey_team + +/datum/dynamic_ruleset/roundstart/monkey/pre_execute() + var/carriers_to_make = max(round(num_players()/players_per_carrier, 1), 1) + + for(var/j = 0, j < carriers_to_make, j++) + if (!candidates.len) + break + var/mob/carrier = pick(candidates) + candidates -= carrier + assigned += carrier.mind + carrier.mind.special_role = "Monkey Leader" + carrier.mind.restricted_roles = restricted_roles + log_game("[key_name(carrier)] has been selected as a Jungle Fever carrier") + return TRUE + +/datum/dynamic_ruleset/roundstart/monkey/execute() + for(var/datum/mind/carrier in assigned) + var/datum/antagonist/monkey/M = add_monkey_leader(carrier) + if(M) + monkey_team = M.monkey_team + return TRUE + +/datum/dynamic_ruleset/roundstart/monkey/proc/check_monkey_victory() + if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME) + return FALSE + var/datum/disease/D = new /datum/disease/transformation/jungle_fever() + for(var/mob/living/carbon/monkey/M in GLOB.alive_mob_list) + if (M.HasDisease(D)) + if(M.onCentCom() || M.onSyndieBase()) + escaped_monkeys++ + if(escaped_monkeys >= monkeys_to_win) + return TRUE + else + return FALSE + +// This does not get called. Look into making it work. +/datum/dynamic_ruleset/roundstart/monkey/round_result() + if(check_monkey_victory()) + SSticker.mode_result = "win - monkey win" + else + SSticker.mode_result = "loss - staff stopped the monkeys" + +////////////////////////////////////////////// +// // +// METEOR // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/roundstart/meteor + name = "Meteor" + persistent = TRUE + required_candidates = 0 + weight = 3 + cost = 0 + requirements = list(101,101,101,101,101,101,101,101,101,101) + high_population_requirement = 101 + var/meteordelay = 2000 + var/nometeors = 0 + var/rampupdelta = 5 + +/datum/dynamic_ruleset/roundstart/meteor/rule_process() + if(nometeors || meteordelay > world.time - SSticker.round_start_time) + return + + var/list/wavetype = GLOB.meteors_normal + var/meteorminutes = (world.time - SSticker.round_start_time - meteordelay) / 10 / 60 + + if (prob(meteorminutes)) + wavetype = GLOB.meteors_threatening + + if (prob(meteorminutes/2)) + wavetype = GLOB.meteors_catastrophic + + var/ramp_up_final = CLAMP(round(meteorminutes/rampupdelta), 1, 10) + + spawn_meteors(ramp_up_final, wavetype) diff --git a/code/game/gamemodes/dynamic/readme.md b/code/game/gamemodes/dynamic/readme.md new file mode 100644 index 0000000000..6bd064cf7c --- /dev/null +++ b/code/game/gamemodes/dynamic/readme.md @@ -0,0 +1,57 @@ +# DYNAMIC + +## ROUNDSTART + +Dynamic rolls threat based on a special sauce formula: +"dynamic_curve_width \* tan((3.1416 \* (rand() - 0.5) \* 57.2957795)) + dynamic_curve_centre" + +Latejoin and midround injection cooldowns are set using exponential distribution between +5 minutes and 25 for latejoin +15 minutes and 35 for midround +this value is then added to world.time and assigned to the injection cooldown variables. + +rigged_roundstart() is called instead if there are forced rules (an admin set the mode) + +can_start() -> pre_setup() -> roundstart() OR rigged_roundstart() -> picking_roundstart_rule(drafted_rules) -> post_setup() + +## PROCESS + +Calls rule_process on every rule which is in the current_rules list. +Every sixty seconds, update_playercounts() +Midround injection time is checked against world.time to see if an injection should happen. +If midround injection time is lower than world.time, it updates playercounts again, then tries to inject and generates a new cooldown regardless of whether a rule is picked. + +## LATEJOIN + +make_antag_chance(newPlayer) -> [For each latespawn rule...] +-> acceptable(living players, threat_level) -> trim_candidates() -> ready(forced=FALSE) +**If true, add to drafted rules +**NOTE that acceptable uses threat_level not threat! +**NOTE Latejoin timer is ONLY reset if at least one rule was drafted. +**NOTE the new_player.dm AttemptLateSpawn() calls OnPostSetup for all roles (unless assigned role is MODE) +[After collecting all draftble rules...] +-> picking_latejoin_ruleset(drafted_rules) -> spend threat -> ruleset.execute() +## MIDROUND +process() -> [For each midround rule...] +-> acceptable(living players, threat_level) -> trim_candidates() -> ready(forced=FALSE) +[After collecting all draftble rules...] +-> picking_midround_ruleset(drafted_rules) -> spend threat -> ruleset.execute() +## FORCED +For latejoin, it simply sets forced_latejoin_rule +make_antag_chance(newPlayer) -> trim_candidates() -> ready(forced=TRUE) **NOTE no acceptable() call +For midround, calls the below proc with forced = TRUE +picking_specific_rule(ruletype,forced) -> forced OR acceptable(living_players, threat_level) -> trim_candidates() -> ready(forced) -> spend threat -> execute() +**NOTE specific rule can be called by RS traitor->MR autotraitor w/ forced=FALSE +**NOTE that due to short circuiting acceptable() need not be called if forced. +## RULESET +acceptable(population,threat) just checks if enough threat_level for population indice. +**NOTE that we currently only send threat_level as the second arg, not threat. +ready(forced) checks if enough candidates and calls the map's map_ruleset(dynamic_ruleset) at the parent level +trim_candidates() varies significantly according to the ruleset type +Roundstart: All candidates are new_player mobs. Check them for standard stuff: connected, desire role, not banned, etc. +**NOTE Roundstart deals with both candidates (trimmed list of valid players) and mode.candidates (everyone readied up). Don't confuse them! +Latejoin: Only one candidate, the latejoiner. Standard checks. +Midround: Instead of building a single list candidates, candidates contains four lists: living, dead, observing, and living antags. Standard checks in trim_list(list). +Midround - Rulesets have additional types +/from_ghosts: execute() -> send_applications() -> review_applications() -> finish_setup(mob/newcharacter, index) -> setup_role(role) +**NOTE: execute() here adds dead players and observers to candidates list diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index d16cbebb2a..cc992fefbc 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -558,3 +558,7 @@ SSticker.news_report = STATION_EVACUATED if(SSshuttle.emergency.is_hijacked()) SSticker.news_report = SHUTTLE_HIJACK + +/// Mode specific admin panel. +/datum/game_mode/proc/admin_panel() + return diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index b400f44b98..555c35980d 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -423,6 +423,25 @@ if(GLOB.master_mode == "secret") dat += "(Force Secret Mode)
" + if(GLOB.master_mode == "dynamic") + if(SSticker.current_state <= GAME_STATE_PREGAME) + dat += "(Force Roundstart Rulesets)
" + if (GLOB.dynamic_forced_roundstart_ruleset.len > 0) + for(var/datum/dynamic_ruleset/roundstart/rule in GLOB.dynamic_forced_roundstart_ruleset) + dat += {"-> [rule.name] <-
"} + dat += "(Clear Rulesets)
" + dat += "(Dynamic mode options)
" + else if (SSticker.IsRoundInProgress()) + dat += "(Force Next Latejoin Ruleset)
" + if (SSticker && SSticker.mode && istype(SSticker.mode,/datum/game_mode/dynamic)) + var/datum/game_mode/dynamic/mode = SSticker.mode + if (mode.forced_latejoin_rule) + dat += {"-> [mode.forced_latejoin_rule.name] <-
"} + dat += "(Execute Midround Ruleset!)
" + dat += "
" + if(SSticker.IsRoundInProgress()) + dat += "(Game Mode Panel)
" + dat += {"
Create Object
@@ -839,6 +858,44 @@ browser.set_content(dat.Join()) browser.open() +/datum/admins/proc/dynamic_mode_options(mob/user) + var/dat = {" +

Dynamic Mode Options


+
+

Common options

+ All these options can be changed midround.
+
+ Force extended: - Option is [GLOB.dynamic_forced_extended ? "ON" : "OFF"]. +
This will force the round to be extended. No rulesets will be drafted.
+
+ No stacking: - Option is [GLOB.dynamic_no_stacking ? "ON" : "OFF"]. +
Unless the threat goes above [GLOB.dynamic_stacking_limit], only one "round-ender" ruleset will be drafted.
+
+ Classic secret mode: - Option is [GLOB.dynamic_classic_secret ? "ON" : "OFF"]. +
Only one roundstart ruleset will be drafted. Only traitors and minor roles will latespawn.
+
+
+ Forced threat level: Current value : [GLOB.dynamic_forced_threat_level]. +
The value threat is set to if it is higher than -1.
+
+ High population limit: Current value : [GLOB.dynamic_high_pop_limit]. +
The threshold at which "high population override" will be in effect.
+
+ Stacking threeshold: Current value : [GLOB.dynamic_stacking_limit]. +
The threshold at which "round-ender" rulesets will stack. A value higher than 100 ensure this never happens.
+

Advanced parameters

+ Curve centre: -> [GLOB.dynamic_curve_centre] <-
+ Curve width: -> [GLOB.dynamic_curve_width] <-
+ Latejoin injection delay:
+ Minimum: -> [GLOB.dynamic_latejoin_delay_min / 60 / 10] <- Minutes
+ Maximum: -> [GLOB.dynamic_latejoin_delay_max / 60 / 10] <- Minutes
+ Midround injection delay:
+ Minimum: -> [GLOB.dynamic_midround_delay_min / 60 / 10] <- Minutes
+ Maximum: -> [GLOB.dynamic_midround_delay_max / 60 / 10] <- Minutes
+ "} + + user << browse(dat, "window=dyn_mode_options;size=900x650") + /datum/admins/proc/create_or_modify_area() set category = "Debug" set name = "Create or modify area" diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index d881044757..91df9ef85c 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -291,6 +291,11 @@ else if(href_list["editrights"]) edit_rights_topic(href_list) + else if(href_list["gamemode_panel"]) + if(!check_rights(R_ADMIN)) + return + SSticker.mode.admin_panel() + else if(href_list["call_shuttle"]) if(!check_rights(R_ADMIN)) return @@ -1342,6 +1347,291 @@ else if(href_list["f_secret"]) return HandleFSecret() + + else if(href_list["f_dynamic_roundstart"]) + if(!check_rights(R_ADMIN)) + return + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode.", null, null, null, null) + var/roundstart_rules = list() + for (var/rule in subtypesof(/datum/dynamic_ruleset/roundstart)) + var/datum/dynamic_ruleset/roundstart/newrule = new rule() + roundstart_rules[newrule.name] = newrule + var/added_rule = input(usr,"What ruleset do you want to force? This will bypass threat level and population restrictions.", "Rigging Roundstart", null) as null|anything in roundstart_rules + if (added_rule) + GLOB.dynamic_forced_roundstart_ruleset += roundstart_rules[added_rule] + log_admin("[key_name(usr)] set [added_rule] to be a forced roundstart ruleset.") + message_admins("[key_name(usr)] set [added_rule] to be a forced roundstart ruleset.", 1) + Game() + + else if(href_list["f_dynamic_roundstart_clear"]) + if(!check_rights(R_ADMIN)) + return + GLOB.dynamic_forced_roundstart_ruleset = list() + Game() + log_admin("[key_name(usr)] cleared the rigged roundstart rulesets. The mode will pick them as normal.") + message_admins("[key_name(usr)] cleared the rigged roundstart rulesets. The mode will pick them as normal.", 1) + + else if(href_list["f_dynamic_roundstart_remove"]) + if(!check_rights(R_ADMIN)) + return + var/datum/dynamic_ruleset/roundstart/rule = locate(href_list["f_dynamic_roundstart_remove"]) + GLOB.dynamic_forced_roundstart_ruleset -= rule + Game() + log_admin("[key_name(usr)] removed [rule] from the forced roundstart rulesets.") + message_admins("[key_name(usr)] removed [rule] from the forced roundstart rulesets.", 1) + + else if(href_list["f_dynamic_latejoin"]) + if(!check_rights(R_ADMIN)) + return + if(!SSticker || !SSticker.mode) + return alert(usr, "The game must start first.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + var/latejoin_rules = list() + for (var/rule in subtypesof(/datum/dynamic_ruleset/latejoin)) + var/datum/dynamic_ruleset/latejoin/newrule = new rule() + latejoin_rules[newrule.name] = newrule + var/added_rule = input(usr,"What ruleset do you want to force upon the next latejoiner? This will bypass threat level and population restrictions.", "Rigging Latejoin", null) as null|anything in latejoin_rules + if (added_rule) + var/datum/game_mode/dynamic/mode = SSticker.mode + mode.forced_latejoin_rule = latejoin_rules[added_rule] + log_admin("[key_name(usr)] set [added_rule] to proc on the next latejoin.") + message_admins("[key_name(usr)] set [added_rule] to proc on the next latejoin.", 1) + Game() + + else if(href_list["f_dynamic_latejoin_clear"]) + if(!check_rights(R_ADMIN)) + return + if (SSticker && SSticker.mode && istype(SSticker.mode,/datum/game_mode/dynamic)) + var/datum/game_mode/dynamic/mode = SSticker.mode + mode.forced_latejoin_rule = null + Game() + log_admin("[key_name(usr)] cleared the forced latejoin ruleset.") + message_admins("[key_name(usr)] cleared the forced latejoin ruleset.", 1) + + else if(href_list["f_dynamic_midround"]) + if(!check_rights(R_ADMIN)) + return + if(!SSticker || !SSticker.mode) + return alert(usr, "The game must start first.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + var/midround_rules = list() + for (var/rule in subtypesof(/datum/dynamic_ruleset/midround)) + var/datum/dynamic_ruleset/midround/newrule = new rule() + midround_rules[newrule.name] = rule + var/added_rule = input(usr,"What ruleset do you want to force right now? This will bypass threat level and population restrictions.", "Execute Ruleset", null) as null|anything in midround_rules + if (added_rule) + var/datum/game_mode/dynamic/mode = SSticker.mode + log_admin("[key_name(usr)] executed the [added_rule] ruleset.") + message_admins("[key_name(usr)] executed the [added_rule] ruleset.", 1) + mode.picking_specific_rule(midround_rules[added_rule],1) + + else if (href_list["f_dynamic_options"]) + if(!check_rights(R_ADMIN)) + return + + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_roundstart_centre"]) + if(!check_rights(R_ADMIN)) + return + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + var/new_centre = input(usr,"Change the centre of the dynamic mode threat curve. A negative value will give a more peaceful round ; a positive value, a round with higher threat. Any number between -5 and +5 is allowed.", "Change curve centre", null) as num + if (new_centre < -5 || new_centre > 5) + return alert(usr, "Only values between -5 and +5 are allowed.", null, null, null, null) + + log_admin("[key_name(usr)] changed the distribution curve center to [new_centre].") + message_admins("[key_name(usr)] changed the distribution curve center to [new_centre]", 1) + GLOB.dynamic_curve_centre = new_centre + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_roundstart_width"]) + if(!check_rights(R_ADMIN)) + return + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + var/new_width = input(usr,"Change the width of the dynamic mode threat curve. A higher value will favour extreme rounds ; a lower value, a round closer to the average. Any Number between 0.5 and 4 are allowed.", "Change curve width", null) as num + if (new_width < 0.5 || new_width > 4) + return alert(usr, "Only values between 0.5 and +2.5 are allowed.", null, null, null, null) + + log_admin("[key_name(usr)] changed the distribution curve width to [new_width].") + message_admins("[key_name(usr)] changed the distribution curve width to [new_width]", 1) + GLOB.dynamic_curve_width = new_width + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_roundstart_latejoin_min"]) + if(!check_rights(R_ADMIN)) + return + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + var/new_min = input(usr,"Change the minimum delay of latejoin injection in minutes.", "Change latejoin injection delay minimum", null) as num + if(new_min <= 0) + return alert(usr, "The minimum can't be zero or lower.", null, null, null, null) + if((new_min MINUTES) > GLOB.dynamic_latejoin_delay_max) + return alert(usr, "The minimum must be lower than the maximum.", null, null, null, null) + + log_admin("[key_name(usr)] changed the latejoin injection minimum delay to [new_min] minutes.") + message_admins("[key_name(usr)] changed the latejoin injection minimum delay to [new_min] minutes", 1) + GLOB.dynamic_latejoin_delay_min = (new_min MINUTES) + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_roundstart_latejoin_max"]) + if(!check_rights(R_ADMIN)) + return + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + var/new_max = input(usr,"Change the maximum delay of latejoin injection in minutes.", "Change latejoin injection delay maximum", null) as num + if(new_max <= 0) + return alert(usr, "The maximum can't be zero or lower.", null, null, null, null) + if((new_max MINUTES) < GLOB.dynamic_latejoin_delay_min) + return alert(usr, "The maximum must be higher than the minimum.", null, null, null, null) + + log_admin("[key_name(usr)] changed the latejoin injection maximum delay to [new_max] minutes.") + message_admins("[key_name(usr)] changed the latejoin injection maximum delay to [new_max] minutes", 1) + GLOB.dynamic_latejoin_delay_max = (new_max MINUTES) + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_roundstart_midround_min"]) + if(!check_rights(R_ADMIN)) + return + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + var/new_min = input(usr,"Change the minimum delay of midround injection in minutes.", "Change midround injection delay minimum", null) as num + if(new_min <= 0) + return alert(usr, "The minimum can't be zero or lower.", null, null, null, null) + if((new_min MINUTES) > GLOB.dynamic_midround_delay_max) + return alert(usr, "The minimum must be lower than the maximum.", null, null, null, null) + + log_admin("[key_name(usr)] changed the midround injection minimum delay to [new_min] minutes.") + message_admins("[key_name(usr)] changed the midround injection minimum delay to [new_min] minutes", 1) + GLOB.dynamic_midround_delay_min = (new_min MINUTES) + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_roundstart_midround_max"]) + if(!check_rights(R_ADMIN)) + return + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + var/new_max = input(usr,"Change the maximum delay of midround injection in minutes.", "Change midround injection delay maximum", null) as num + if(new_max <= 0) + return alert(usr, "The maximum can't be zero or lower.", null, null, null, null) + if((new_max MINUTES) > GLOB.dynamic_midround_delay_max) + return alert(usr, "The maximum must be higher than the minimum.", null, null, null, null) + + log_admin("[key_name(usr)] changed the midround injection maximum delay to [new_max] minutes.") + message_admins("[key_name(usr)] changed the midround injection maximum delay to [new_max] minutes", 1) + GLOB.dynamic_midround_delay_max = (new_max MINUTES) + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_force_extended"]) + if(!check_rights(R_ADMIN)) + return + + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + GLOB.dynamic_forced_extended = !GLOB.dynamic_forced_extended + log_admin("[key_name(usr)] set 'forced_extended' to [GLOB.dynamic_forced_extended].") + message_admins("[key_name(usr)] set 'forced_extended' to [GLOB.dynamic_forced_extended].") + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_no_stacking"]) + if(!check_rights(R_ADMIN)) + return + + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + GLOB.dynamic_no_stacking = !GLOB.dynamic_no_stacking + log_admin("[key_name(usr)] set 'no_stacking' to [GLOB.dynamic_no_stacking].") + message_admins("[key_name(usr)] set 'no_stacking' to [GLOB.dynamic_no_stacking].") + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_classic_secret"]) + if(!check_rights(R_ADMIN)) + return + + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + GLOB.dynamic_classic_secret = !GLOB.dynamic_classic_secret + log_admin("[key_name(usr)] set 'classic_secret' to [GLOB.dynamic_classic_secret].") + message_admins("[key_name(usr)] set 'classic_secret' to [GLOB.dynamic_classic_secret].") + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_stacking_limit"]) + if(!check_rights(R_ADMIN)) + return + + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + GLOB.dynamic_stacking_limit = input(usr,"Change the threat limit at which round-endings rulesets will start to stack.", "Change stacking limit", null) as num + log_admin("[key_name(usr)] set 'stacking_limit' to [GLOB.dynamic_stacking_limit].") + message_admins("[key_name(usr)] set 'stacking_limit' to [GLOB.dynamic_stacking_limit].") + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_high_pop_limit"]) + if(!check_rights(R_ADMIN)) + return + + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + var/new_value = input(usr, "Enter the high-pop override threshold for dynamic mode.", "High pop override") as num + if (new_value < 0) + return alert(usr, "Only positive values allowed!", null, null, null, null) + GLOB.dynamic_high_pop_limit = new_value + + log_admin("[key_name(usr)] set 'high_pop_limit' to [GLOB.dynamic_high_pop_limit].") + message_admins("[key_name(usr)] set 'high_pop_limit' to [GLOB.dynamic_high_pop_limit].") + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_forced_threat"]) + if(!check_rights(R_ADMIN)) + return + + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + var/new_value = input(usr, "Enter the forced threat level for dynamic mode.", "Forced threat level") as num + if (new_value > 100) + return alert(usr, "The value must be be under 100.", null, null, null, null) + GLOB.dynamic_forced_threat_level = new_value + + log_admin("[key_name(usr)] set 'forced_threat_level' to [GLOB.dynamic_forced_threat_level].") + message_admins("[key_name(usr)] set 'forced_threat_level' to [GLOB.dynamic_forced_threat_level].") + dynamic_mode_options(usr) else if(href_list["c_mode2"]) if(!check_rights(R_ADMIN|R_SERVER)) diff --git a/tgstation.dme b/tgstation.dme index da990c169a..7ea5546fca 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -544,6 +544,11 @@ #include "code\game\gamemodes\devil\game_mode.dm" #include "code\game\gamemodes\devil\objectives.dm" #include "code\game\gamemodes\devil\devil agent\devil_agent.dm" +#include "code\game\gamemodes\dynamic\dynamic.dm" +#include "code\game\gamemodes\dynamic\dynamic_rulesets.dm" +#include "code\game\gamemodes\dynamic\dynamic_rulesets_latejoin.dm" +#include "code\game\gamemodes\dynamic\dynamic_rulesets_midround.dm" +#include "code\game\gamemodes\dynamic\dynamic_rulesets_roundstart.dm" #include "code\game\gamemodes\extended\extended.dm" #include "code\game\gamemodes\meteor\meteor.dm" #include "code\game\gamemodes\meteor\meteors.dm" @@ -2926,6 +2931,7 @@ #include "modular_citadel\code\modules\arousal\toys\dildos.dm" #include "modular_citadel\code\modules\awaymissions\citadel_ghostrole_spawners.dm" #include "modular_citadel\code\modules\cargo\console.dm" +#include "modular_citadel\code\modules\cargo\packs.dm" #include "modular_citadel\code\modules\client\client_defines.dm" #include "modular_citadel\code\modules\client\client_procs.dm" #include "modular_citadel\code\modules\client\preferences.dm" @@ -2959,6 +2965,7 @@ #include "modular_citadel\code\modules\clothing\under\trek_under.dm" #include "modular_citadel\code\modules\clothing\under\turtlenecks.dm" #include "modular_citadel\code\modules\clothing\under\under.dm" +#include "modular_citadel\code\modules\crafting\recipes.dm" #include "modular_citadel\code\modules\custom_loadout\custom_items.dm" #include "modular_citadel\code\modules\custom_loadout\load_to_mob.dm" #include "modular_citadel\code\modules\custom_loadout\read_from_file.dm" @@ -2983,6 +2990,7 @@ #include "modular_citadel\code\modules\mentor\mentorhelp.dm" #include "modular_citadel\code\modules\mentor\mentorpm.dm" #include "modular_citadel\code\modules\mentor\mentorsay.dm" +#include "modular_citadel\code\modules\mining\mine_items.dm" #include "modular_citadel\code\modules\mining\mining_ruins.dm" #include "modular_citadel\code\modules\mob\cit_emotes.dm" #include "modular_citadel\code\modules\mob\mob.dm" @@ -3040,6 +3048,7 @@ #include "modular_citadel\code\modules\research\designs\xenobio_designs.dm" #include "modular_citadel\code\modules\research\designs\weapon_designs\weapon_designs.dm" #include "modular_citadel\code\modules\research\techweb\_techweb.dm" +#include "modular_citadel\code\modules\research\techweb\all_nodes.dm" #include "modular_citadel\code\modules\research\xenobiology\xenobio_camera.dm" #include "modular_citadel\code\modules\vehicles\secway.dm" #include "modular_citadel\code\modules\vore\hook-defs_vr.dm" From 921e12dd64b8c7dbcd22bee2bd0137a5f6827dfa Mon Sep 17 00:00:00 2001 From: Sishen Date: Fri, 9 Aug 2019 01:43:36 -0400 Subject: [PATCH 010/222] Update tgstation.dme --- tgstation.dme | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tgstation.dme b/tgstation.dme index 7ea5546fca..807c7f28a1 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -2931,7 +2931,6 @@ #include "modular_citadel\code\modules\arousal\toys\dildos.dm" #include "modular_citadel\code\modules\awaymissions\citadel_ghostrole_spawners.dm" #include "modular_citadel\code\modules\cargo\console.dm" -#include "modular_citadel\code\modules\cargo\packs.dm" #include "modular_citadel\code\modules\client\client_defines.dm" #include "modular_citadel\code\modules\client\client_procs.dm" #include "modular_citadel\code\modules\client\preferences.dm" @@ -2965,7 +2964,6 @@ #include "modular_citadel\code\modules\clothing\under\trek_under.dm" #include "modular_citadel\code\modules\clothing\under\turtlenecks.dm" #include "modular_citadel\code\modules\clothing\under\under.dm" -#include "modular_citadel\code\modules\crafting\recipes.dm" #include "modular_citadel\code\modules\custom_loadout\custom_items.dm" #include "modular_citadel\code\modules\custom_loadout\load_to_mob.dm" #include "modular_citadel\code\modules\custom_loadout\read_from_file.dm" @@ -2990,7 +2988,6 @@ #include "modular_citadel\code\modules\mentor\mentorhelp.dm" #include "modular_citadel\code\modules\mentor\mentorpm.dm" #include "modular_citadel\code\modules\mentor\mentorsay.dm" -#include "modular_citadel\code\modules\mining\mine_items.dm" #include "modular_citadel\code\modules\mining\mining_ruins.dm" #include "modular_citadel\code\modules\mob\cit_emotes.dm" #include "modular_citadel\code\modules\mob\mob.dm" @@ -3048,7 +3045,6 @@ #include "modular_citadel\code\modules\research\designs\xenobio_designs.dm" #include "modular_citadel\code\modules\research\designs\weapon_designs\weapon_designs.dm" #include "modular_citadel\code\modules\research\techweb\_techweb.dm" -#include "modular_citadel\code\modules\research\techweb\all_nodes.dm" #include "modular_citadel\code\modules\research\xenobiology\xenobio_camera.dm" #include "modular_citadel\code\modules\vehicles\secway.dm" #include "modular_citadel\code\modules\vore\hook-defs_vr.dm" From 251ac24e02de6d13973ecef5ac7818ecc69f8217 Mon Sep 17 00:00:00 2001 From: Fermi Date: Sun, 11 Aug 2019 00:35:36 +0100 Subject: [PATCH 011/222] [NEED TO TEST] {Preview} Fixes Neurotoxin and adjusts it's reaction. --- .../food_and_drinks/recipes/drinks_recipes.dm | 25 ++++++++++++++++++- .../chemistry/reagents/alcohol_reagents.dm | 18 +++++++++++++ .../reagents/chemistry/recipes/fermi.dm | 6 ++--- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/code/modules/food_and_drinks/recipes/drinks_recipes.dm b/code/modules/food_and_drinks/recipes/drinks_recipes.dm index 7c44857b1d..b97b919e1e 100644 --- a/code/modules/food_and_drinks/recipes/drinks_recipes.dm +++ b/code/modules/food_and_drinks/recipes/drinks_recipes.dm @@ -381,6 +381,29 @@ id = "neurotoxin" results = list("neurotoxin" = 2) required_reagents = list("gargleblaster" = 1, "morphine" = 1) + //FermiChem vars: Easy to make, but hard to make potent + OptimalTempMin = 200 // Lower area of bell curve for determining heat based rate reactions + OptimalTempMax = 950 // Upper end for above + ExplodeTemp = 999 //Temperature at which reaction explodes + OptimalpHMin = 2 // Lowest value of pH determining pH a 1 value for pH based rate reactions (Plateu phase) + OptimalpHMax = 2.8 // Higest value for above + ReactpHLim = 5 // How far out pH wil react, giving impurity place (Exponential phase) + CatalystFact = 0 // How much the catalyst affects the reaction (0 = no catalyst) + CurveSharpT = 2 // How sharp the temperature exponential curve is (to the power of value) + CurveSharppH = 4 // How sharp the pH exponential curve is (to the power of value) + ThermicConstant = 10 //Temperature change per 1u produced + HIonRelease = 0.02 //pH change per 1u reaction + RateUpLim = 5 //Optimal/max rate possible if all conditions are perfect + FermiChem = TRUE//If the chemical uses the Fermichem reaction mechanics + FermiExplode = FALSE //If the chemical explodes in a special way + PurityMin = 0 //The minimum purity something has to be above, otherwise it explodes. + +/datum/chemical_reaction/neurotoxin/FermiFinish(datum/reagents/holder, var/atom/my_atom) + var/datum/reagent/consumable/ethanol/neurotoxin/Nt = locate(/datum/reagent/consumable/ethanol/neurotoxin) in my_atom.reagents.reagent_list + var/cached_volume = Nt.volume + if(Nt.purity < 0.5) + holder.remove_reagent(src.id, cached_volume) + holder.add_reagent("neuroweak", cached_volume) /datum/chemical_reaction/snowwhite name = "Snow White" @@ -794,4 +817,4 @@ name = "Red Queen" id = "red_queen" results = list("red_queen" = 10) - required_reagents = list("tea" = 6, "mercury" = 2, "blackpepper" = 1, "growthserum" = 1) \ No newline at end of file + required_reagents = list("tea" = 6, "mercury" = 2, "blackpepper" = 1, "growthserum" = 1) diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm index 79b6f96781..0817d04cb8 100644 --- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm @@ -1373,6 +1373,7 @@ All effects don't start immediately, but rather get worse over time; the rate is /datum/reagent/consumable/ethanol/neurotoxin name = "Neurotoxin" + id = "neurotoxin" description = "A strong neurotoxin that puts the subject into a death-like state." color = "#2E2E61" // rgb: 46, 46, 97 boozepwr = 50 @@ -1382,6 +1383,9 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_icon_state = "neurotoxinglass" glass_name = "Neurotoxin" glass_desc = "A drink that is guaranteed to knock you silly." + ImpureChem = "neuroweak" + InverseChemVal = 0 //Clear conversion + InverseChem = "neuroweak" /datum/reagent/consumable/ethanol/neurotoxin/proc/pickt() return (pick(TRAIT_PARALYSIS_L_ARM,TRAIT_PARALYSIS_R_ARM,TRAIT_PARALYSIS_R_LEG,TRAIT_PARALYSIS_L_LEG)) @@ -1417,6 +1421,20 @@ All effects don't start immediately, but rather get worse over time; the rate is M.adjustStaminaLoss(10) ..() +/datum/reagent/consumable/ethanol/neuroweak + name = "Neuroalcohol" + id = "neuroweak" + description = "A mostly safe alcoholic drink for the true daredevils. Do not mix with Neurotoxin." + boozepwr = 60 + +/datum/reagent/consumable/ethanol/neuroweak/on_mob_life(mob/living/carbon/M) + if(holder.has_reagent("neurotoxin")) + M.adjustBrainLoss(0.5*REM, 150) + else + M.adjustBrainLoss(-0.5*REM, 150) + M.dizziness +=2 + ..() + /datum/reagent/consumable/ethanol/hippies_delight name = "Hippie's Delight" id = "hippiesdelight" diff --git a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm index 078e1c8a71..bd327809eb 100644 --- a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm +++ b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm @@ -2,15 +2,15 @@ mix_sound = 'sound/effects/bubbles.ogg' //Called for every reaction step -/datum/chemical_reaction/fermi/proc/FermiCreate(holder) +/datum/chemical_reaction/proc/FermiCreate(holder) return //Called when reaction STOP_PROCESSING -/datum/chemical_reaction/fermi/proc/FermiFinish(datum/reagents/holder) +/datum/chemical_reaction/proc/FermiFinish(datum/reagents/holder) return //Called when temperature is above a certain threshold, or if purity is too low. -/datum/chemical_reaction/fermi/proc/FermiExplode(datum/reagents, var/atom/my_atom, volume, temp, pH, Exploding = FALSE) +/datum/chemical_reaction/proc/FermiExplode(datum/reagents, var/atom/my_atom, volume, temp, pH, Exploding = FALSE) if (Exploding == TRUE) return From 57835e2f81369b2a2cc7a845b62d557cf2d04b92 Mon Sep 17 00:00:00 2001 From: Poojawa Date: Sat, 10 Aug 2019 19:20:05 -0500 Subject: [PATCH 012/222] head announce datums --- code/modules/jobs/job_types/chief_engineer.dm | 2 +- code/modules/jobs/job_types/chief_medical_officer.dm | 2 +- code/modules/jobs/job_types/head_of_personnel.dm | 2 +- code/modules/jobs/job_types/head_of_security.dm | 2 +- code/modules/jobs/job_types/quartermaster.dm | 2 +- code/modules/jobs/job_types/research_director.dm | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/code/modules/jobs/job_types/chief_engineer.dm b/code/modules/jobs/job_types/chief_engineer.dm index dd89e925b5..3a91a89992 100644 --- a/code/modules/jobs/job_types/chief_engineer.dm +++ b/code/modules/jobs/job_types/chief_engineer.dm @@ -4,7 +4,7 @@ // auto_deadmin_role_flags = DEADMIN_POSITION_HEAD department_head = list("Captain") department_flag = ENGSEC - head_announce = list("Engineering") + head_announce = list(RADIO_CHANNEL_ENGINEERING) faction = "Station" total_positions = 1 spawn_positions = 1 diff --git a/code/modules/jobs/job_types/chief_medical_officer.dm b/code/modules/jobs/job_types/chief_medical_officer.dm index 54963b1bc1..35af7b20ba 100644 --- a/code/modules/jobs/job_types/chief_medical_officer.dm +++ b/code/modules/jobs/job_types/chief_medical_officer.dm @@ -4,7 +4,7 @@ department_head = list("Captain") department_flag = MEDSCI // auto_deadmin_role_flags = DEADMIN_POSITION_HEAD - head_announce = list("Medical") + head_announce = list(RADIO_CHANNEL_MEDICAL) faction = "Station" total_positions = 1 spawn_positions = 1 diff --git a/code/modules/jobs/job_types/head_of_personnel.dm b/code/modules/jobs/job_types/head_of_personnel.dm index d658a49380..0d0b0e7e2f 100644 --- a/code/modules/jobs/job_types/head_of_personnel.dm +++ b/code/modules/jobs/job_types/head_of_personnel.dm @@ -4,7 +4,7 @@ // auto_deadmin_role_flags = DEADMIN_POSITION_HEAD department_head = list("Captain") department_flag = CIVILIAN - head_announce = list("Service") + head_announce = list(RADIO_CHANNEL_SERVICE) faction = "Station" total_positions = 1 spawn_positions = 1 diff --git a/code/modules/jobs/job_types/head_of_security.dm b/code/modules/jobs/job_types/head_of_security.dm index 0ca0e393ac..5c0d254769 100644 --- a/code/modules/jobs/job_types/head_of_security.dm +++ b/code/modules/jobs/job_types/head_of_security.dm @@ -4,7 +4,7 @@ // auto_deadmin_role_flags = DEADMIN_POSITION_HEAD|DEADMIN_POSITION_SECURITY department_head = list("Captain") department_flag = ENGSEC - head_announce = list("Security") + head_announce = list(RADIO_CHANNEL_SECURITY) faction = "Station" total_positions = 1 spawn_positions = 1 diff --git a/code/modules/jobs/job_types/quartermaster.dm b/code/modules/jobs/job_types/quartermaster.dm index b85a4ad404..3ba6ca9e36 100644 --- a/code/modules/jobs/job_types/quartermaster.dm +++ b/code/modules/jobs/job_types/quartermaster.dm @@ -3,7 +3,7 @@ flag = QUARTERMASTER department_head = list("Captain") department_flag = CIVILIAN - head_announce = list("Supply") + head_announce = list(RADIO_CHANNEL_SUPPLY) // auto_deadmin_role_flags = DEADMIN_POSITION_HEAD faction = "Station" total_positions = 1 diff --git a/code/modules/jobs/job_types/research_director.dm b/code/modules/jobs/job_types/research_director.dm index 2df606bd20..d1be81df38 100644 --- a/code/modules/jobs/job_types/research_director.dm +++ b/code/modules/jobs/job_types/research_director.dm @@ -4,7 +4,7 @@ // auto_deadmin_role_flags = DEADMIN_POSITION_HEAD department_head = list("Captain") department_flag = MEDSCI - head_announce = list("Science") + head_announce = list(RADIO_CHANNEL_SCIENCE) faction = "Station" total_positions = 1 spawn_positions = 1 From a3cd143131c83329a259d1883f3517767048591f Mon Sep 17 00:00:00 2001 From: Poojawa Date: Sat, 10 Aug 2019 19:28:47 -0500 Subject: [PATCH 013/222] whaccky github hijinks --- code/modules/jobs/job_types/captain.dm | 64 ++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 code/modules/jobs/job_types/captain.dm diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm new file mode 100644 index 0000000000..79a31b89eb --- /dev/null +++ b/code/modules/jobs/job_types/captain.dm @@ -0,0 +1,64 @@ +/datum/job/captain + title = "Captain" + flag = CAPTAIN +// auto_deadmin_role_flags = DEADMIN_POSITION_HEAD|DEADMIN_POSITION_SECURITY //:eyes: + department_head = list("CentCom") + department_flag = ENGSEC + faction = "Station" + total_positions = 1 + spawn_positions = 1 + supervisors = "Nanotrasen officials and Space law" + selection_color = "#ccccff" + req_admin_notify = 1 + minimal_player_age = 14 + exp_requirements = 180 + exp_type = EXP_TYPE_CREW + exp_type_department = EXP_TYPE_COMMAND + + outfit = /datum/outfit/job/captain + + access = list() //See get_access() + minimal_access = list() //See get_access() + + mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) +// mind_traits = list(TRAIT_DISK_VERIFIER) + + display_order = JOB_DISPLAY_ORDER_CAPTAIN + +/datum/job/captain/get_access() + return get_all_accesses() + +/datum/job/captain/announce(mob/living/carbon/human/H) + ..() + SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "Captain [H.nameless ? "" : "[H.real_name] "]on deck!")) + +/datum/outfit/job/captain + name = "Captain" + jobtype = /datum/job/captain + + id = /obj/item/card/id/gold + belt = /obj/item/pda/captain + glasses = /obj/item/clothing/glasses/sunglasses + ears = /obj/item/radio/headset/heads/captain/alt + gloves = /obj/item/clothing/gloves/color/captain + uniform = /obj/item/clothing/under/rank/captain + suit = /obj/item/clothing/suit/armor/vest/capcarapace + shoes = /obj/item/clothing/shoes/sneakers/brown + head = /obj/item/clothing/head/caphat + backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1, /obj/item/station_charter=1) + + backpack = /obj/item/storage/backpack/captain + satchel = /obj/item/storage/backpack/satchel/cap + duffelbag = /obj/item/storage/backpack/duffelbag/captain + + implants = list(/obj/item/implant/mindshield) + accessory = /obj/item/clothing/accessory/medal/gold/captain + + chameleon_extras = list(/obj/item/gun/energy/e_gun, /obj/item/stamp/captain) + +/datum/outfit/job/captain/hardsuit + name = "Captain (Hardsuit)" + + mask = /obj/item/clothing/mask/gas/sechailer + suit = /obj/item/clothing/suit/space/hardsuit/captain + suit_store = /obj/item/tank/internals/oxygen From 821463f59c80c45a4f742120d6f7d7bf72f6dfe6 Mon Sep 17 00:00:00 2001 From: TrilbySpaceClone Date: Sun, 11 Aug 2019 11:47:56 -0400 Subject: [PATCH 014/222] Nya --- .../food_and_drinks/recipes/drinks_recipes.dm | 8 +++++++- code/modules/hydroponics/grown/tea_coffee.dm | 19 +++++++++++++++++- .../chemistry/reagents/drink_reagents.dm | 17 ++++++++++++++++ .../chemistry/reagents/other_reagents.dm | 12 +++++++++++ icons/obj/hydroponics/growing_flowers.dmi | Bin 13230 -> 14070 bytes icons/obj/hydroponics/harvest.dmi | Bin 51063 -> 51397 bytes icons/obj/hydroponics/seeds.dmi | Bin 22003 -> 22135 bytes 7 files changed, 54 insertions(+), 2 deletions(-) diff --git a/code/modules/food_and_drinks/recipes/drinks_recipes.dm b/code/modules/food_and_drinks/recipes/drinks_recipes.dm index 7c44857b1d..364cf7ec65 100644 --- a/code/modules/food_and_drinks/recipes/drinks_recipes.dm +++ b/code/modules/food_and_drinks/recipes/drinks_recipes.dm @@ -794,4 +794,10 @@ name = "Red Queen" id = "red_queen" results = list("red_queen" = 10) - required_reagents = list("tea" = 6, "mercury" = 2, "blackpepper" = 1, "growthserum" = 1) \ No newline at end of file + required_reagents = list("tea" = 6, "mercury" = 2, "blackpepper" = 1, "growthserum" = 1) + +/datum/chemical_reaction/catnip_tea + name = "Catnip Tea" + id = "catnip_tea" + results = list("catnip_tea" = 3) + required_reagents = list("tea" = 5, "catnip" = 2) \ No newline at end of file diff --git a/code/modules/hydroponics/grown/tea_coffee.dm b/code/modules/hydroponics/grown/tea_coffee.dm index fc84617ed8..e7e3679a30 100644 --- a/code/modules/hydroponics/grown/tea_coffee.dm +++ b/code/modules/hydroponics/grown/tea_coffee.dm @@ -32,7 +32,7 @@ species = "teaastra" plantname = "Tea Astra Plant" product = /obj/item/reagent_containers/food/snacks/grown/tea/astra - mutatelist = list() + mutatelist = list(/obj/item/seeds/tea/catnip) reagents_add = list("synaptizine" = 0.1, "vitamin" = 0.04, "teapowder" = 0.1) rarity = 20 @@ -43,6 +43,23 @@ filling_color = "#4582B4" grind_results = list("teapowder" = 0, "salglu_solution" = 0) +// Kitty drugs +/obj/item/seeds/tea/catnip + name = "pack of catnip seeds" + icon_state = "seed-catnip" + desc = "Long stocks with flowering tips that has a chemical to make feline attracted to it." + species = "catnip" + plantname = "Catnip Plant" + product = /obj/item/reagent_containers/food/snacks/grown/tea/catnip + reagents_add = list("catnip" = 0.1, "vitamin" = 0.06, "teapowder" = 0.3) + rarity = 50 + +/obj/item/reagent_containers/food/snacks/grown/tea/catnip + seed = /obj/item/seeds/tea/catnip + name = "Catnip buds" + icon_state = "catnip_leaves" + filling_color = "#4582B4" + grind_results = list("catnp" = 2, "water" = 1) // Coffee /obj/item/seeds/coffee diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm index 8aa555944a..2f4714bf2f 100644 --- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm @@ -881,3 +881,20 @@ to_chat(M, "[pick("Diamond skies where white deer fly.","Sipping strawberry tea.","Silver raindrops drift through timeless, Neverending June.","Crystal ... pearls free, with love!","Beaming love into me.")]") ..() . = 1 + +/datum/reagent/consumable/catnip_tea + name = "Catnip Tea" + id = "catnip_tea" + description = "A sleepy and tasty catnip tea!" + color = "#101000" // rgb: 16, 16, 0 + nutriment_factor = 0 + taste_description = "sugar and catnip" + glass_icon_state = "teaglass" + glass_name = "glass of catnip tea" + glass_desc = "A purfect drink for a cat." + +/datum/reagent/consumable/catnip_tea/on_mob_life(mob/living/carbon/M) + M.emote("nya") + to_chat(M, "[pick("Headpats feel nice.", "Backrubs would be nice.", "Mew")]") + M.adjustArousalLoss(5) + M.adjustStaminaLoss(3) diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index db927411c0..5914183549 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -1962,3 +1962,15 @@ /datum/reagent/changeling_string/Destroy() qdel(original_dna) return ..() + +/datum/reagent/pax/catnip + name = "catnip" + id = "catnip" + taste_description = "grass" + description = "A colorless liquid that makes people more peaceful and felines more happy." + metabolization_rate = 1.75 * REAGENTS_METABOLISM + +/datum/reagent/pax/catnip/on_mob_life(mob/living/carbon/M) + M.emote("nya") + to_chat(M, "[pick("Headpats feel nice.", "The feeling of a hairball...", "Backrubs would be nice.", "Whats behind those doors?")]") + M.adjustArousalLoss(2) \ No newline at end of file diff --git a/icons/obj/hydroponics/growing_flowers.dmi b/icons/obj/hydroponics/growing_flowers.dmi index 2752ad8dc502f25ae1a5bcb088a1798f511fc91e..2f541dfc9b5ff6331a0978036de299e618adca58 100644 GIT binary patch literal 14070 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%0A(EyekoocH+ZSs+rW$ET8!%3GCBWk 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 delta 16532 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 Nt*EI`BWD@@e*m?)=vM#$ diff --git a/icons/obj/hydroponics/seeds.dmi b/icons/obj/hydroponics/seeds.dmi index 30be27486b0e35af955d8cb0575b3eb2471168a0..b65f395598697a0f832209bcf774799e4b5adc3a 100644 GIT binary patch literal 22135 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 literal 22003 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 Date: Sun, 11 Aug 2019 13:10:14 -0400 Subject: [PATCH 015/222] Update machine_vending.dm --- code/modules/mining/machine_vending.dm | 47 ++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm index e49f2e73ed..e6f57cb1f6 100644 --- a/code/modules/mining/machine_vending.dm +++ b/code/modules/mining/machine_vending.dm @@ -279,13 +279,56 @@ desc = "A kit containing everything a crewmember needs to support a shaft miner in the field." /obj/item/storage/backpack/duffelbag/mining_conscript/PopulateContents() + new /obj/item/pickaxe/mini(src) new /obj/item/clothing/glasses/meson(src) new /obj/item/t_scanner/adv_mining_scanner/lesser(src) new /obj/item/storage/bag/ore(src) - new /obj/item/clothing/suit/hooded/explorer(src) - new /obj/item/encryptionkey/headset_mining(src) + new /obj/item/clothing/suit/hooded/explorer/standard(src) + new /obj/item/encryptionkey/headset_cargo(src) new /obj/item/clothing/mask/gas/explorer(src) new /obj/item/card/mining_access_card(src) new /obj/item/gun/energy/kinetic_accelerator(src) new /obj/item/kitchen/knife/combat/survival(src) new /obj/item/flashlight/seclite(src) + + //CITADEL ADDITIONS BELOW + +/obj/item/storage/backpack/duffelbag/mining_cloned + name = "mining replacement kit" + desc = "A large bag that has advance tools and a spare jumpsuit, boots, and gloves for a newly cloned miner to get back in the field. Even as a new Id!" + +/obj/item/storage/backpack/duffelbag/mining_cloned/PopulateContents() + new /obj/item/pickaxe/mini(src) + new /obj/item/clothing/under/rank/miner/lavaland(src) + new /obj/item/clothing/shoes/workboots/mining(src) + new /obj/item/clothing/gloves/color/black(src) + new /obj/item/implanter/tracking/gps(src) + new /obj/item/gun/energy/kinetic_accelerator(src) + new /obj/item/kitchen/knife/combat/survival(src) + new /obj/item/storage/firstaid/regular(src) + new /obj/item/reagent_containers/hypospray/medipen/survival(src) + new /obj/item/t_scanner/adv_mining_scanner(src) + new /obj/item/clothing/suit/hooded/explorer/standard(src) + new /obj/item/encryptionkey/headset_cargo(src) + new /obj/item/clothing/mask/gas/explorer(src) + new /obj/item/card/id/mining(src) + new /obj/item/storage/bag/ore(src) + new /obj/item/clothing/glasses/meson/prescription(src) + +/obj/machinery/mineral/equipment_vendor/proc/RedeemSVoucher(obj/item/suit_voucher/voucher, mob/redeemer) + var/items = list("Exo-suit", "SEVA suit") + + var/selection = input(redeemer, "Pick your suit.", "Suit Voucher Redemption") as null|anything in items + if(!selection || !Adjacent(redeemer) || QDELETED(voucher) || voucher.loc != redeemer) + return + var/drop_location = drop_location() + switch(selection) + if("Exo-suit") + new /obj/item/clothing/suit/hooded/explorer/exo(drop_location) + new /obj/item/clothing/mask/gas/exo(drop_location) + if("SEVA suit") + new /obj/item/clothing/suit/hooded/explorer/seva(drop_location) + new /obj/item/clothing/mask/gas/seva(drop_location) + + SSblackbox.record_feedback("tally", "suit_voucher_redeemed", 1, selection) + qdel(voucher) From ffa574b1be73646583be67145cd7c8a0ed82da5e Mon Sep 17 00:00:00 2001 From: Sishen Date: Sun, 11 Aug 2019 13:17:55 -0400 Subject: [PATCH 016/222] Update machine_vending.dm --- code/modules/mining/machine_vending.dm | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm index e6f57cb1f6..38d2e3e100 100644 --- a/code/modules/mining/machine_vending.dm +++ b/code/modules/mining/machine_vending.dm @@ -32,6 +32,7 @@ new /datum/data/mining_equipment("Jaunter", /obj/item/wormhole_jaunter, 750), new /datum/data/mining_equipment("Kinetic Crusher", /obj/item/twohanded/required/kinetic_crusher, 750), new /datum/data/mining_equipment("Kinetic Accelerator", /obj/item/gun/energy/kinetic_accelerator, 750), + new /datum/data/mining_equipment("Survival Medipen", /obj/item/reagent_containers/hypospray/medipen/survival, 750), new /datum/data/mining_equipment("Brute First-Aid Kit", /obj/item/storage/firstaid/brute, 800), new /datum/data/mining_equipment("Burn First-Aid Kit", /obj/item/storage/firstaid/fire, 800), new /datum/data/mining_equipment("First-Aid Kit", /obj/item/storage/firstaid/regular, 800), @@ -66,7 +67,9 @@ new /datum/data/mining_equipment("KA Range Increase", /obj/item/borg/upgrade/modkit/range, 1000), new /datum/data/mining_equipment("KA Damage Increase", /obj/item/borg/upgrade/modkit/damage, 1000), new /datum/data/mining_equipment("KA Cooldown Decrease", /obj/item/borg/upgrade/modkit/cooldown, 1000), - new /datum/data/mining_equipment("KA AoE Damage", /obj/item/borg/upgrade/modkit/aoe/mobs, 2000) + new /datum/data/mining_equipment("KA AoE Damage", /obj/item/borg/upgrade/modkit/aoe/mobs, 2000), + new /datum/data/mining_equipment("Miner Full Replacement", /obj/item/storage/backpack/duffelbag/mining_cloned, 3000), + new /datum/data/mining_equipment("Premium Accelerator", /obj/item/gun/energy/kinetic_accelerator/premiumka, 8000) ) /datum/data/mining_equipment @@ -135,6 +138,9 @@ if(istype(I, /obj/item/mining_voucher)) RedeemVoucher(I, user) return + if(istype(I, /obj/item/suit_voucher)) + RedeemSVoucher(I, user) + return if(default_deconstruction_screwdriver(user, "mining-open", "mining", I)) updateUsrDialog() return From 0f4469e59fde4832090e784bfbf81c7c1dd15f63 Mon Sep 17 00:00:00 2001 From: Fermi Date: Mon, 12 Aug 2019 01:03:35 +0100 Subject: [PATCH 017/222] Re-enables fermiexplosions in grenades. --- code/modules/reagents/chemistry/holder.dm | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm index 300e73a6fd..e9eb00a180 100644 --- a/code/modules/reagents/chemistry/holder.dm +++ b/code/modules/reagents/chemistry/holder.dm @@ -495,7 +495,12 @@ //Standard reaction mechanics: else if (C.FermiChem == TRUE)//Just to make sure - return 0 + if (chem_temp > C.ExplodeTemp) //To allow fermigrenades + var/datum/chemical_reaction/fermi/Ferm = selected_reaction + fermiIsReacting = FALSE + SSblackbox.record_feedback("tally", "fermi_chem", 1, ("[Ferm] explosion")) + Ferm.FermiExplode(src, my_atom, volume = total_volume, temp = chem_temp, pH = pH) + return 0 for(var/B in cached_required_reagents) // multiplier = min(multiplier, round((get_reagent_amount(B) / cached_required_reagents[B]), 0.01)) @@ -693,7 +698,7 @@ //Make sure things are limited. pH = CLAMP(pH, 0, 14) - + //return said amount to compare for next step. return (reactedVol) From 10ca106f065d77e2552bfa10c810db5c34ad654a Mon Sep 17 00:00:00 2001 From: Fermi Date: Mon, 12 Aug 2019 01:36:21 +0100 Subject: [PATCH 018/222] [TO TEST] Adds nuance to hatmium and SDGF explosions. --- .../reagents/chemistry/recipes/fermi.dm | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm index 078e1c8a71..c6e3c801ea 100644 --- a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm +++ b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm @@ -137,12 +137,14 @@ /datum/chemical_reaction/fermi/SDGF/FermiExplode(datum/reagents, var/atom/my_atom, volume, temp, pH)//Spawns an angery teratoma! var/turf/T = get_turf(my_atom) - var/mob/living/simple_animal/slime/S = new(T,"green") - S.damage_coeff = list(BRUTE = 0.9 , BURN = 2, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) - S.name = "Living teratoma" - S.real_name = "Living teratoma" - S.rabid = 1//Make them an angery boi - S.color = "#810010" + var/amount_to_spawn = round((volume/30), 1) + for(var/i in 1 to amount_to_spawn) + var/mob/living/simple_animal/slime/S = new(T,"green") + S.damage_coeff = list(BRUTE = 0.9 , BURN = 2, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) + S.name = "Living teratoma" + S.real_name = "Living teratoma" + S.rabid = 1//Make them an angery boi + S.color = "#810010" my_atom.reagents.clear_reagents() var/list/seen = viewers(8, get_turf(my_atom)) for(var/mob/M in seen) @@ -353,11 +355,13 @@ PurityMin = 0.5 /datum/chemical_reaction/fermi/hatmium/FermiExplode(src, var/atom/my_atom, volume, temp, pH) - var/obj/item/clothing/head/hattip/hat = new /obj/item/clothing/head/hattip(get_turf(my_atom)) - hat.animate_atom_living() + var/amount_to_spawn = round((volume/30), 1) + for(var/i in 1 to amount_to_spawn) + var/obj/item/clothing/head/hattip/hat = new /obj/item/clothing/head/hattip(get_turf(my_atom)) + hat.animate_atom_living() var/list/seen = viewers(8, get_turf(my_atom)) for(var/mob/M in seen) - to_chat(M, "The makes an off sounding pop, as a hat suddenly climbs out of the beaker!") + to_chat(M, "The [src] makes an off sounding pop, as a hat suddenly climbs out of it!") my_atom.reagents.clear_reagents() /datum/chemical_reaction/fermi/furranium From 75440a48c50f9eb4a3e9b9cefa243d9c1ceab377 Mon Sep 17 00:00:00 2001 From: Fermi Date: Mon, 12 Aug 2019 01:36:46 +0100 Subject: [PATCH 019/222] 30 might be too much --- .../code/modules/reagents/chemistry/recipes/fermi.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm index c6e3c801ea..6625207a71 100644 --- a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm +++ b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm @@ -137,7 +137,7 @@ /datum/chemical_reaction/fermi/SDGF/FermiExplode(datum/reagents, var/atom/my_atom, volume, temp, pH)//Spawns an angery teratoma! var/turf/T = get_turf(my_atom) - var/amount_to_spawn = round((volume/30), 1) + var/amount_to_spawn = round((volume/50), 1) for(var/i in 1 to amount_to_spawn) var/mob/living/simple_animal/slime/S = new(T,"green") S.damage_coeff = list(BRUTE = 0.9 , BURN = 2, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) @@ -355,7 +355,7 @@ PurityMin = 0.5 /datum/chemical_reaction/fermi/hatmium/FermiExplode(src, var/atom/my_atom, volume, temp, pH) - var/amount_to_spawn = round((volume/30), 1) + var/amount_to_spawn = round((volume/50), 1) for(var/i in 1 to amount_to_spawn) var/obj/item/clothing/head/hattip/hat = new /obj/item/clothing/head/hattip(get_turf(my_atom)) hat.animate_atom_living() From 08bba425e41a2d8a09981fd0ee3693615f3c0ad5 Mon Sep 17 00:00:00 2001 From: Sishen Date: Mon, 12 Aug 2019 19:42:58 -0400 Subject: [PATCH 020/222] run in a straight line to win gamemode lol --- code/game/mecha/combat/gygax.dm | 3 +++ code/modules/mob/living/carbon/human/human_defense.dm | 9 +++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/code/game/mecha/combat/gygax.dm b/code/game/mecha/combat/gygax.dm index 95137938d0..98330fae88 100644 --- a/code/game/mecha/combat/gygax.dm +++ b/code/game/mecha/combat/gygax.dm @@ -6,6 +6,7 @@ dir_in = 1 //Facing North. max_integrity = 250 deflect_chance = 5 + force = 20 armor = list("melee" = 25, "bullet" = 20, "laser" = 30, "energy" = 15, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100) max_temperature = 25000 infra_luminosity = 6 @@ -13,6 +14,7 @@ internal_damage_threshold = 35 max_equip = 3 step_energy_drain = 3 + leg_overload_coeff = 300 /obj/mecha/combat/gygax/dark desc = "A lightweight exosuit, painted in a dark scheme. This model appears to have some modifications." @@ -20,6 +22,7 @@ icon_state = "darkgygax" max_integrity = 300 deflect_chance = 15 + force = 25 armor = list("melee" = 40, "bullet" = 40, "laser" = 50, "energy" = 35, "bomb" = 20, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100) max_temperature = 35000 leg_overload_coeff = 100 diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index ff4878aa13..5af295a5dd 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -348,10 +348,15 @@ if(temp) var/update = 0 var/dmg = rand(M.force/2, M.force) + var/atom/throw_target = get_edge_target_turf(src, M.dir) switch(M.damtype) if("brute") - if(M.force > 20) - Unconscious(20) + if(M.force > 35) // durand and other heavy mechas + Knockdown(50) + src.throw_at(throw_target, rand(1,5), 7) + else if(M.force >= 20 && !IsKnockdown()) // lightweight mechas like gygax + Knockdown(30) + src.throw_at(throw_target, rand(1,3), 7) update |= temp.receive_damage(dmg, 0) playsound(src, 'sound/weapons/punch4.ogg', 50, 1) if("fire") From 3224e6ca4aa8b64216c67b3681c8a64fed4e5e8d Mon Sep 17 00:00:00 2001 From: Trilbyspaceclone <30435998+Trilbyspaceclone@users.noreply.github.com> Date: Tue, 13 Aug 2019 11:46:52 -0400 Subject: [PATCH 021/222] ..() --- code/modules/reagents/chemistry/reagents/drink_reagents.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm index 2f4714bf2f..75e265d2fd 100644 --- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm @@ -898,3 +898,4 @@ to_chat(M, "[pick("Headpats feel nice.", "Backrubs would be nice.", "Mew")]") M.adjustArousalLoss(5) M.adjustStaminaLoss(3) + ..() From 0056e3eb61a22de7871bc315a14d055243a6e26c Mon Sep 17 00:00:00 2001 From: Trilbyspaceclone <30435998+Trilbyspaceclone@users.noreply.github.com> Date: Tue, 13 Aug 2019 11:49:00 -0400 Subject: [PATCH 022/222] Update other_reagents.dm --- code/modules/reagents/chemistry/reagents/other_reagents.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 5914183549..2e093a7459 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -1973,4 +1973,5 @@ /datum/reagent/pax/catnip/on_mob_life(mob/living/carbon/M) M.emote("nya") to_chat(M, "[pick("Headpats feel nice.", "The feeling of a hairball...", "Backrubs would be nice.", "Whats behind those doors?")]") - M.adjustArousalLoss(2) \ No newline at end of file + M.adjustArousalLoss(2) + ..() From 522566551696b252941263b8ffc503e3aceb6c47 Mon Sep 17 00:00:00 2001 From: Trilbyspaceclone <30435998+Trilbyspaceclone@users.noreply.github.com> Date: Fri, 16 Aug 2019 23:48:41 -0400 Subject: [PATCH 023/222] kev fix --- code/modules/reagents/chemistry/reagents/drink_reagents.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm index 75e265d2fd..7bc807aa14 100644 --- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm @@ -892,10 +892,11 @@ glass_icon_state = "teaglass" glass_name = "glass of catnip tea" glass_desc = "A purfect drink for a cat." + var/staminaloss = M.getStaminaLoss() /datum/reagent/consumable/catnip_tea/on_mob_life(mob/living/carbon/M) + M.getStaminaLoss(min(50 - staminaloss, 3)) M.emote("nya") to_chat(M, "[pick("Headpats feel nice.", "Backrubs would be nice.", "Mew")]") M.adjustArousalLoss(5) - M.adjustStaminaLoss(3) ..() From c81fd8fcd454ae56e22112b7fccac2fae6b078ac Mon Sep 17 00:00:00 2001 From: Trilbyspaceclone <30435998+Trilbyspaceclone@users.noreply.github.com> Date: Sat, 17 Aug 2019 00:02:22 -0400 Subject: [PATCH 024/222] Update drink_reagents.dm --- code/modules/reagents/chemistry/reagents/drink_reagents.dm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm index 7bc807aa14..fc408e0a91 100644 --- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm @@ -896,7 +896,9 @@ /datum/reagent/consumable/catnip_tea/on_mob_life(mob/living/carbon/M) M.getStaminaLoss(min(50 - staminaloss, 3)) - M.emote("nya") - to_chat(M, "[pick("Headpats feel nice.", "Backrubs would be nice.", "Mew")]") + if(prob(20)) + M.emote("nya") + if(prob(20)) + to_chat(M, "[pick("Headpats feel nice.", "Backrubs would be nice.", "Mew")]") M.adjustArousalLoss(5) ..() From 3851739533bb39de89c13a1a68cfa1359e670974 Mon Sep 17 00:00:00 2001 From: Trilbyspaceclone <30435998+Trilbyspaceclone@users.noreply.github.com> Date: Sat, 17 Aug 2019 00:06:58 -0400 Subject: [PATCH 025/222] Update other_reagents.dm --- code/modules/reagents/chemistry/reagents/other_reagents.dm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 2e093a7459..6680920442 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -1971,7 +1971,9 @@ metabolization_rate = 1.75 * REAGENTS_METABOLISM /datum/reagent/pax/catnip/on_mob_life(mob/living/carbon/M) - M.emote("nya") - to_chat(M, "[pick("Headpats feel nice.", "The feeling of a hairball...", "Backrubs would be nice.", "Whats behind those doors?")]") + if(prob(20)) + M.emote("nya") + if(prob(20)) + to_chat(M, "[pick("Headpats feel nice.", "The feeling of a hairball...", "Backrubs would be nice.", "Whats behind those doors?")]") M.adjustArousalLoss(2) ..() From bcf65dc90181508f5340f049241b7904f250b399 Mon Sep 17 00:00:00 2001 From: Trilbyspaceclone <30435998+Trilbyspaceclone@users.noreply.github.com> Date: Sat, 17 Aug 2019 00:58:02 -0400 Subject: [PATCH 026/222] Update drink_reagents.dm --- code/modules/reagents/chemistry/reagents/drink_reagents.dm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm index fc408e0a91..978fa54d0f 100644 --- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm @@ -892,10 +892,9 @@ glass_icon_state = "teaglass" glass_name = "glass of catnip tea" glass_desc = "A purfect drink for a cat." - var/staminaloss = M.getStaminaLoss() /datum/reagent/consumable/catnip_tea/on_mob_life(mob/living/carbon/M) - M.getStaminaLoss(min(50 - staminaloss, 3)) + M.getStaminaLoss(min(50 - M.getStaminaLoss(), 3)) if(prob(20)) M.emote("nya") if(prob(20)) From 4b6b2cf19524032efdf170d30f87a1ae644bfda8 Mon Sep 17 00:00:00 2001 From: Code-Cygnet <54194215+Code-Cygnet@users.noreply.github.com> Date: Sat, 17 Aug 2019 01:37:28 -0400 Subject: [PATCH 027/222] Adds new drink to drink recipes It's a drink for Captains --- code/modules/food_and_drinks/recipes/drinks_recipes.dm | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/code/modules/food_and_drinks/recipes/drinks_recipes.dm b/code/modules/food_and_drinks/recipes/drinks_recipes.dm index 7c44857b1d..d35955d2d3 100644 --- a/code/modules/food_and_drinks/recipes/drinks_recipes.dm +++ b/code/modules/food_and_drinks/recipes/drinks_recipes.dm @@ -794,4 +794,11 @@ name = "Red Queen" id = "red_queen" results = list("red_queen" = 10) - required_reagents = list("tea" = 6, "mercury" = 2, "blackpepper" = 1, "growthserum" = 1) \ No newline at end of file + required_reagents = list("tea" = 6, "mercury" = 2, "blackpepper" = 1, "growthserum" = 1) + +/datum/chemical_reaction/commander_and_chief + name = "Commander and Chief" + id = "commander_and_chief" + results = list("commander_and_chief" = 50) + required_reagents = list("allies_cocktail" = 50, "champagne" = 20, "doctors_delight" = 10, "quintiple_sec" = 10, "screwdriver" = 10) + mix_message = "When your powers combine, I am Captain Pl-..." From 372c53b3da679aef0f5a2a34a6b71587109d3a35 Mon Sep 17 00:00:00 2001 From: Code-Cygnet <54194215+Code-Cygnet@users.noreply.github.com> Date: Sat, 17 Aug 2019 01:47:25 -0400 Subject: [PATCH 028/222] Uploads new drinks.dmi Adds Commander and Chif --- icons/obj/drinks.dmi | Bin 85302 -> 85723 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/icons/obj/drinks.dmi b/icons/obj/drinks.dmi index 7822cdb8c236ea58fc03d4812f74561781b6b0b2..c255e0a104b992bda3df8d0882a0c808d87ea506 100644 GIT binary patch delta 8618 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 Date: Sat, 17 Aug 2019 11:10:09 -0400 Subject: [PATCH 029/222] some updates thanks to thechosenevilone --- code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm index 440765718b..064a325ca1 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -29,10 +29,10 @@ // So for example you can get the list of all current dead players with var/list/dead_players = candidates[CURRENT_DEAD_PLAYERS] // Make sure to properly typecheck the mobs in those lists, as the dead_players list could contain ghosts, or dead players still in their bodies. // We're still gonna trim the obvious (mobs without clients, jobbanned players, etc) - living_players = trim_list(candidates[CURRENT_LIVING_PLAYERS]) - living_antags = trim_list(candidates[CURRENT_LIVING_ANTAGS]) - dead_players = trim_list(candidates[CURRENT_DEAD_PLAYERS]) - list_observers = trim_list(candidates[CURRENT_OBSERVERS]) + living_players = trim_list(mode.current_players[CURRENT_LIVING_PLAYERS]) + living_antags = trim_list(mode.current_players[CURRENT_LIVING_ANTAGS]) + dead_players = trim_list(mode.current_players[CURRENT_DEAD_PLAYERS]) + list_observers = trim_list(mode.current_players[CURRENT_OBSERVERS]) /datum/dynamic_ruleset/midround/proc/trim_list(list/L = list()) var/list/trimmed_list = L.Copy() From 1d0cb91aafc6b6339fbab2d89248eb58b6f98663 Mon Sep 17 00:00:00 2001 From: Code-Cygnet <54194215+Code-Cygnet@users.noreply.github.com> Date: Sat, 17 Aug 2019 19:02:30 -0400 Subject: [PATCH 030/222] Update traits.dm Adds new mob trait at line 121 --- code/__DEFINES/traits.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index ed0007135d..a4bca2f2c8 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -118,6 +118,7 @@ #define TRAIT_LAW_ENFORCEMENT_METABOLISM "law-enforcement-metabolism" #define TRAIT_STRONG_GRABBER "strong_grabber" #define TRAIT_CALCIUM_HEALER "calcium_healer" +#define TRAIT_CAPTAIN_METABOLISM "captain-metabolism" //non-mob traits #define TRAIT_PARALYSIS "paralysis" //Used for limb-based paralysis, where replacing the limb will fix it @@ -203,4 +204,4 @@ #define FLIGHTSUIT_TRAIT "flightsuit" #define LOCKED_HELMET_TRAIT "locked-helmet" #define NINJA_SUIT_TRAIT "ninja-suit" -#define ANTI_DROP_IMPLANT_TRAIT "anti-drop-implant" \ No newline at end of file +#define ANTI_DROP_IMPLANT_TRAIT "anti-drop-implant" From d2760287e10335173865f1ca0348ca5407b4a49c Mon Sep 17 00:00:00 2001 From: Code-Cygnet <54194215+Code-Cygnet@users.noreply.github.com> Date: Sat, 17 Aug 2019 19:27:11 -0400 Subject: [PATCH 031/222] Update captain.dm Adds mind trait at line 24 --- code/modules/jobs/job_types/captain.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm index 80c78220e6..dd8cc5a887 100755 --- a/code/modules/jobs/job_types/captain.dm +++ b/code/modules/jobs/job_types/captain.dm @@ -21,6 +21,8 @@ Captain access = list() //See get_access() minimal_access = list() //See get_access() + mind_traits = list(TRAIT_CAPTAIN_METABOLISM) + /datum/job/captain/get_access() return get_all_accesses() From 975a33aad78f4d27b37be223970d53877283c924 Mon Sep 17 00:00:00 2001 From: Code-Cygnet <54194215+Code-Cygnet@users.noreply.github.com> Date: Sat, 17 Aug 2019 19:38:58 -0400 Subject: [PATCH 032/222] Update alcohol_reagents.dm Adds commander and chief, starting at line 2125 and ending at 2146.. hopefully. --- .../chemistry/reagents/alcohol_reagents.dm | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm index 79b6f96781..35efd651df 100644 --- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm @@ -2122,6 +2122,29 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_name = "Planet Cracker" glass_desc = "Although historians believe the drink was originally created to commemorate the end of an important conflict in man's past, its origins have largely been forgotten and it is today seen more as a general symbol of human supremacy." +/datum/reagent/consumable/ethanol/commander_and_chief + name = "Commander and Chief" + id = "commander_and_chief" + description = "A cocktail for the captain on the go." + color = "#ffffc9" + boozepwr = 50 + quality = DRINK_FANTASTIC + taste_description = "Tastes like...duty and responsibility?" + glass_icon_state = "commander_and_chief" + glass_name = "Commander and Chief" + glass_desc = "The gems of this majestic chalice represent the departments and their Heads." + +/datum/reagent/consumable/ethanol/commander_and_chief/on_mob_life(mob/living/carbon/M) + if(M.mind && HAS_TRAIT(M.mind, TRAIT_CAPTAIN_METABOLISM))) + M.heal_bodypart_damage(2,2,2) + M.adjustBruteLoss(-3.5,0) + M.adjustOxyLoss(-3.5,0) + M.adjustFireLoss(-3.5,0) + M.adjustToxLoss(-3.5,0) + M.radiation = max(M.raddiation - 25, 0) + . = 1 + return ..() + /datum/reagent/consumable/ethanol/fruit_wine name = "Fruit Wine" id = "fruit_wine" From b5842048b4d6e40230bc79617680779751af0932 Mon Sep 17 00:00:00 2001 From: Poojawa Date: Sat, 17 Aug 2019 23:42:01 -0500 Subject: [PATCH 033/222] blacklisting quirks --- code/modules/jobs/job_types/chief_engineer.dm | 1 + code/modules/jobs/job_types/chief_medical_officer.dm | 1 + code/modules/jobs/job_types/detective.dm | 1 + code/modules/jobs/job_types/head_of_personnel.dm | 2 ++ code/modules/jobs/job_types/head_of_security.dm | 1 + code/modules/jobs/job_types/quartermaster.dm | 1 + code/modules/jobs/job_types/research_director.dm | 1 + code/modules/jobs/job_types/security_officer.dm | 1 + code/modules/jobs/job_types/warden.dm | 1 + 9 files changed, 10 insertions(+) diff --git a/code/modules/jobs/job_types/chief_engineer.dm b/code/modules/jobs/job_types/chief_engineer.dm index 3a91a89992..7fca1c9faf 100644 --- a/code/modules/jobs/job_types/chief_engineer.dm +++ b/code/modules/jobs/job_types/chief_engineer.dm @@ -28,6 +28,7 @@ ACCESS_CE, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM) display_order = JOB_DISPLAY_ORDER_CHIEF_ENGINEER + blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/paraplegic, /datum/quirk/insanity) /datum/outfit/job/ce name = "Chief Engineer" diff --git a/code/modules/jobs/job_types/chief_medical_officer.dm b/code/modules/jobs/job_types/chief_medical_officer.dm index 35af7b20ba..b464141ae2 100644 --- a/code/modules/jobs/job_types/chief_medical_officer.dm +++ b/code/modules/jobs/job_types/chief_medical_officer.dm @@ -26,6 +26,7 @@ ACCESS_KEYCARD_AUTH, ACCESS_SEC_DOORS, ACCESS_MAINT_TUNNELS) display_order = JOB_DISPLAY_ORDER_CHIEF_MEDICAL_OFFICER + blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity) /datum/outfit/job/cmo name = "Chief Medical Officer" diff --git a/code/modules/jobs/job_types/detective.dm b/code/modules/jobs/job_types/detective.dm index 6c12c1db09..82745ae9fb 100644 --- a/code/modules/jobs/job_types/detective.dm +++ b/code/modules/jobs/job_types/detective.dm @@ -21,6 +21,7 @@ mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) display_order = JOB_DISPLAY_ORDER_DETECTIVE + blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/nonviolent, /datum/quirk/paraplegic) /datum/outfit/job/detective name = "Detective" diff --git a/code/modules/jobs/job_types/head_of_personnel.dm b/code/modules/jobs/job_types/head_of_personnel.dm index 0d0b0e7e2f..96a7932f46 100644 --- a/code/modules/jobs/job_types/head_of_personnel.dm +++ b/code/modules/jobs/job_types/head_of_personnel.dm @@ -33,6 +33,8 @@ display_order = JOB_DISPLAY_ORDER_HEAD_OF_PERSONNEL + blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/prosopagnosia, /datum/quirk/insanity) + /datum/outfit/job/hop name = "Head of Personnel" jobtype = /datum/job/hop diff --git a/code/modules/jobs/job_types/head_of_security.dm b/code/modules/jobs/job_types/head_of_security.dm index 5c0d254769..07dfa05774 100644 --- a/code/modules/jobs/job_types/head_of_security.dm +++ b/code/modules/jobs/job_types/head_of_security.dm @@ -29,6 +29,7 @@ ACCESS_HEADS, ACCESS_HOS, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM) display_order = JOB_DISPLAY_ORDER_HEAD_OF_SECURITY + blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/nonviolent, /datum/quirk/paraplegic, /datum/quirk/insanity) /datum/outfit/job/hos name = "Head of Security" diff --git a/code/modules/jobs/job_types/quartermaster.dm b/code/modules/jobs/job_types/quartermaster.dm index 3ba6ca9e36..2c68d005db 100644 --- a/code/modules/jobs/job_types/quartermaster.dm +++ b/code/modules/jobs/job_types/quartermaster.dm @@ -24,6 +24,7 @@ ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM, ACCESS_VAULT) display_order = JOB_DISPLAY_ORDER_QUARTERMASTER + blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity) /datum/outfit/job/quartermaster name = "Quartermaster" diff --git a/code/modules/jobs/job_types/research_director.dm b/code/modules/jobs/job_types/research_director.dm index d1be81df38..6f23f403dc 100644 --- a/code/modules/jobs/job_types/research_director.dm +++ b/code/modules/jobs/job_types/research_director.dm @@ -30,6 +30,7 @@ ACCESS_TECH_STORAGE, ACCESS_MINISAT, ACCESS_MAINT_TUNNELS, ACCESS_NETWORK) display_order = JOB_DISPLAY_ORDER_RESEARCH_DIRECTOR + blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity) /datum/outfit/job/rd name = "Research Director" diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm index 05ba91aa4a..24c2e3cde0 100644 --- a/code/modules/jobs/job_types/security_officer.dm +++ b/code/modules/jobs/job_types/security_officer.dm @@ -21,6 +21,7 @@ mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) display_order = JOB_DISPLAY_ORDER_SECURITY_OFFICER + blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/nonviolent, /datum/quirk/paraplegic) /datum/job/officer/get_access() var/list/L = list() diff --git a/code/modules/jobs/job_types/warden.dm b/code/modules/jobs/job_types/warden.dm index 821ce352f7..d7691cb488 100644 --- a/code/modules/jobs/job_types/warden.dm +++ b/code/modules/jobs/job_types/warden.dm @@ -21,6 +21,7 @@ mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM) display_order = JOB_DISPLAY_ORDER_WARDEN + blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/nonviolent, /datum/quirk/paraplegic) /datum/job/warden/get_access() var/list/L = list() From 933db4d05fa8ed01fe679048ce8fc82428f753b4 Mon Sep 17 00:00:00 2001 From: Poojawa Date: Sun, 18 Aug 2019 01:00:16 -0500 Subject: [PATCH 034/222] reverts the overly greyish colors back to vibrant ones --- code/modules/jobs/job_types/captain.dm | 2 +- code/modules/jobs/job_types/chief_engineer.dm | 2 +- code/modules/jobs/job_types/chief_medical_officer.dm | 2 +- code/modules/jobs/job_types/head_of_personnel.dm | 2 +- code/modules/jobs/job_types/head_of_security.dm | 2 +- code/modules/jobs/job_types/quartermaster.dm | 2 +- code/modules/jobs/job_types/research_director.dm | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm index 5abe3c021a..d334cff772 100644 --- a/code/modules/jobs/job_types/captain.dm +++ b/code/modules/jobs/job_types/captain.dm @@ -8,7 +8,7 @@ total_positions = 1 spawn_positions = 1 supervisors = "Nanotrasen officials and Space law" - selection_color = "#ccccff" + selection_color = "#aac1ee" req_admin_notify = 1 minimal_player_age = 14 exp_requirements = 180 diff --git a/code/modules/jobs/job_types/chief_engineer.dm b/code/modules/jobs/job_types/chief_engineer.dm index 7fca1c9faf..a4b197d479 100644 --- a/code/modules/jobs/job_types/chief_engineer.dm +++ b/code/modules/jobs/job_types/chief_engineer.dm @@ -9,7 +9,7 @@ total_positions = 1 spawn_positions = 1 supervisors = "the captain" - selection_color = "#ffeeaa" + selection_color = "#ffd699" req_admin_notify = 1 minimal_player_age = 7 exp_requirements = 180 diff --git a/code/modules/jobs/job_types/chief_medical_officer.dm b/code/modules/jobs/job_types/chief_medical_officer.dm index b464141ae2..f0f044e6b1 100644 --- a/code/modules/jobs/job_types/chief_medical_officer.dm +++ b/code/modules/jobs/job_types/chief_medical_officer.dm @@ -9,7 +9,7 @@ total_positions = 1 spawn_positions = 1 supervisors = "the captain" - selection_color = "#ffddf0" + selection_color = "#99ffe6" req_admin_notify = 1 minimal_player_age = 7 exp_requirements = 180 diff --git a/code/modules/jobs/job_types/head_of_personnel.dm b/code/modules/jobs/job_types/head_of_personnel.dm index 96a7932f46..d373b8c181 100644 --- a/code/modules/jobs/job_types/head_of_personnel.dm +++ b/code/modules/jobs/job_types/head_of_personnel.dm @@ -9,7 +9,7 @@ total_positions = 1 spawn_positions = 1 supervisors = "the captain" - selection_color = "#ddddff" + selection_color = "#cccccc" req_admin_notify = 1 minimal_player_age = 10 exp_requirements = 180 diff --git a/code/modules/jobs/job_types/head_of_security.dm b/code/modules/jobs/job_types/head_of_security.dm index 07dfa05774..961b9ea58f 100644 --- a/code/modules/jobs/job_types/head_of_security.dm +++ b/code/modules/jobs/job_types/head_of_security.dm @@ -9,7 +9,7 @@ total_positions = 1 spawn_positions = 1 supervisors = "the captain" - selection_color = "#ffdddd" + selection_color = "#ff9999" req_admin_notify = 1 minimal_player_age = 14 exp_requirements = 300 diff --git a/code/modules/jobs/job_types/quartermaster.dm b/code/modules/jobs/job_types/quartermaster.dm index 2c68d005db..a3830e389f 100644 --- a/code/modules/jobs/job_types/quartermaster.dm +++ b/code/modules/jobs/job_types/quartermaster.dm @@ -9,7 +9,7 @@ total_positions = 1 spawn_positions = 1 supervisors = "the captain" - selection_color = "#d7b088" + selection_color = "#ead4ae" req_admin_notify = 1 minimal_player_age = 7 exp_requirements = 180 diff --git a/code/modules/jobs/job_types/research_director.dm b/code/modules/jobs/job_types/research_director.dm index 6f23f403dc..5b239c44e0 100644 --- a/code/modules/jobs/job_types/research_director.dm +++ b/code/modules/jobs/job_types/research_director.dm @@ -9,7 +9,7 @@ total_positions = 1 spawn_positions = 1 supervisors = "the captain" - selection_color = "#ffddff" + selection_color = "#e6b3e6" req_admin_notify = 1 minimal_player_age = 7 exp_type_department = EXP_TYPE_SCIENCE From b5da43c1b7b7ce8ec05bc82111e69da97f9608c9 Mon Sep 17 00:00:00 2001 From: Poojawa Date: Sun, 18 Aug 2019 04:04:05 -0500 Subject: [PATCH 035/222] Gives Sec Officers back their stun combat weapons --- code/modules/jobs/job_types/security_officer.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm index 24c2e3cde0..bb54ed0a6c 100644 --- a/code/modules/jobs/job_types/security_officer.dm +++ b/code/modules/jobs/job_types/security_officer.dm @@ -122,7 +122,7 @@ GLOBAL_LIST_INIT(available_depts, list(SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, S shoes = /obj/item/clothing/shoes/jackboots l_pocket = /obj/item/restraints/handcuffs r_pocket = /obj/item/assembly/flash/handheld - suit_store = /obj/item/gun/energy/disabler + suit_store = /obj/item/gun/energy/e_gun/advtaser backpack_contents = list(/obj/item/melee/baton/loaded=1) backpack = /obj/item/storage/backpack/security From 5e03f5be3d794fce94c7d2bca8075211a890f63b Mon Sep 17 00:00:00 2001 From: Poojawa Date: Sun, 18 Aug 2019 04:24:48 -0500 Subject: [PATCH 036/222] Update shaft_miner.dm --- code/modules/jobs/job_types/shaft_miner.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/jobs/job_types/shaft_miner.dm b/code/modules/jobs/job_types/shaft_miner.dm index 59d29954fd..6b7f8ecb6f 100644 --- a/code/modules/jobs/job_types/shaft_miner.dm +++ b/code/modules/jobs/job_types/shaft_miner.dm @@ -31,6 +31,7 @@ /obj/item/flashlight/seclite=1,\ /obj/item/kitchen/knife/combat/survival=1,\ /obj/item/mining_voucher=1,\ + /obj/item/suit_voucher=1,\ /obj/item/stack/marker_beacon/ten=1) backpack = /obj/item/storage/backpack/explorer From c4198296d03ab2aaaa03a25080dbdfc8f4d2794e Mon Sep 17 00:00:00 2001 From: Poojawa Date: Sun, 18 Aug 2019 04:26:30 -0500 Subject: [PATCH 037/222] and this too --- code/modules/jobs/job_types/shaft_miner.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/jobs/job_types/shaft_miner.dm b/code/modules/jobs/job_types/shaft_miner.dm index 6b7f8ecb6f..1c662b8e8f 100644 --- a/code/modules/jobs/job_types/shaft_miner.dm +++ b/code/modules/jobs/job_types/shaft_miner.dm @@ -43,7 +43,7 @@ /datum/outfit/job/miner/equipped name = "Shaft Miner (Equipment)" - suit = /obj/item/clothing/suit/hooded/explorer + suit = /obj/item/clothing/suit/hooded/explorer/standard mask = /obj/item/clothing/mask/gas/explorer glasses = /obj/item/clothing/glasses/meson suit_store = /obj/item/tank/internals/oxygen From 867b11215887543f5f4eac186aabe27c52562023 Mon Sep 17 00:00:00 2001 From: Poojawa Date: Sun, 18 Aug 2019 07:44:46 -0500 Subject: [PATCH 038/222] HOW DID THIS NOT GET UPDATED???? --- code/controllers/subsystem/job.dm | 3 +- code/modules/client/preferences_savefile.dm | 68 ++++++++++++++++++--- 2 files changed, 60 insertions(+), 11 deletions(-) diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm index 4001c666ee..f70309b6b2 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -297,7 +297,8 @@ SUBSYSTEM_DEF(job) // Loop through all levels from high to low var/list/shuffledoccupations = shuffle(occupations) - for(var/level = 1 to 3) + var/list/levels = list(JP_HIGH,JP_MEDIUM,JP_LOW) + for(var/level in levels) //Check the head jobs first each level CheckHeadPositions(level) diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 7911d92495..d3eb94c253 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -5,7 +5,7 @@ // You do not need to raise this if you are adding new values that have sane defaults. // Only raise this value when changing the meaning/format/name/layout of an existing value // where you would want the updater procs below to run -#define SAVEFILE_VERSION_MAX 20 +#define SAVEFILE_VERSION_MAX 21 /* SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn @@ -49,6 +49,59 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car pda_style = "mono" if(current_version < 20) pda_color = "#808000" + if(current_version < 21) + job_preferences = list() //It loaded null from nonexistant savefile field. + var/job_civilian_high = 0 + var/job_civilian_med = 0 + var/job_civilian_low = 0 + + var/job_medsci_high = 0 + var/job_medsci_med = 0 + var/job_medsci_low = 0 + + var/job_engsec_high = 0 + var/job_engsec_med = 0 + var/job_engsec_low = 0 + + 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 + + //Can't use SSjob here since this happens right away on login + for(var/job in subtypesof(/datum/job)) + var/datum/job/J = job + var/new_value + var/fval = initial(J.flag) + switch(initial(J.department_flag)) + if(CIVILIAN) + if(job_civilian_high & fval) + new_value = JP_HIGH + else if(job_civilian_med & fval) + new_value = JP_MEDIUM + else if(job_civilian_low & fval) + new_value = JP_LOW + if(MEDSCI) + if(job_medsci_high & fval) + new_value = JP_HIGH + else if(job_medsci_med & fval) + new_value = JP_MEDIUM + else if(job_medsci_low & fval) + new_value = JP_LOW + if(ENGSEC) + if(job_engsec_high & fval) + new_value = JP_HIGH + else if(job_engsec_med & fval) + new_value = JP_MEDIUM + else if(job_engsec_low & fval) + new_value = JP_LOW + if(new_value) + job_preferences[initial(J.title)] = new_value /datum/preferences/proc/load_path(ckey,filename="preferences.sav") if(!ckey) @@ -425,15 +478,10 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car features["moth_wings"] = sanitize_inlist(features["moth_wings"], GLOB.moth_wings_list) joblessrole = sanitize_integer(joblessrole, 1, 3, initial(joblessrole)) - 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)) + //Validate job prefs + for(var/j in job_preferences) + if(job_preferences[j] != JP_LOW && job_preferences[j] != JP_MEDIUM && job_preferences[j] != JP_HIGH) + job_preferences -= j all_quirks = SANITIZE_LIST(all_quirks) positive_quirks = SANITIZE_LIST(positive_quirks) From 9cbd8af5b97d5712bc44d1ba70ae46569c17f3e8 Mon Sep 17 00:00:00 2001 From: Poojawa Date: Sun, 18 Aug 2019 14:38:10 -0500 Subject: [PATCH 039/222] Updates colors, fixes alignment issues. --- code/__DEFINES/jobs.dm | 24 +++++++------- .../jobs/job_types/atmospheric_technician.dm | 2 +- .../jobs/job_types/cargo_technician.dm | 2 +- code/modules/jobs/job_types/chemist.dm | 2 +- code/modules/jobs/job_types/chief_engineer.dm | 2 +- .../jobs/job_types/chief_medical_officer.dm | 2 +- code/modules/jobs/job_types/detective.dm | 2 +- code/modules/jobs/job_types/geneticist.dm | 2 +- .../jobs/job_types/head_of_personnel.dm | 2 +- .../jobs/job_types/head_of_security.dm | 2 +- code/modules/jobs/job_types/medical_doctor.dm | 2 +- code/modules/jobs/job_types/quartermaster.dm | 2 +- .../jobs/job_types/research_director.dm | 2 +- code/modules/jobs/job_types/roboticist.dm | 2 +- code/modules/jobs/job_types/scientist.dm | 2 +- .../jobs/job_types/security_officer.dm | 2 +- code/modules/jobs/job_types/shaft_miner.dm | 2 +- .../jobs/job_types/station_engineer.dm | 2 +- code/modules/jobs/job_types/virologist.dm | 2 +- code/modules/jobs/job_types/warden.dm | 2 +- .../modules/mob/dead/new_player/new_player.dm | 31 +++++++++++-------- 21 files changed, 49 insertions(+), 44 deletions(-) diff --git a/code/__DEFINES/jobs.dm b/code/__DEFINES/jobs.dm index e6b1d77f8a..e6eb9f313e 100644 --- a/code/__DEFINES/jobs.dm +++ b/code/__DEFINES/jobs.dm @@ -57,18 +57,18 @@ #define JOB_DISPLAY_ORDER_ASSISTANT 1 #define JOB_DISPLAY_ORDER_CAPTAIN 2 #define JOB_DISPLAY_ORDER_HEAD_OF_PERSONNEL 3 -#define JOB_DISPLAY_ORDER_QUARTERMASTER 4 -#define JOB_DISPLAY_ORDER_CARGO_TECHNICIAN 5 -#define JOB_DISPLAY_ORDER_SHAFT_MINER 6 -#define JOB_DISPLAY_ORDER_BARTENDER 7 -#define JOB_DISPLAY_ORDER_COOK 8 -#define JOB_DISPLAY_ORDER_BOTANIST 9 -#define JOB_DISPLAY_ORDER_JANITOR 10 -#define JOB_DISPLAY_ORDER_CLOWN 11 -#define JOB_DISPLAY_ORDER_MIME 12 -#define JOB_DISPLAY_ORDER_CURATOR 13 -#define JOB_DISPLAY_ORDER_LAWYER 14 -#define JOB_DISPLAY_ORDER_CHAPLAIN 15 +#define JOB_DISPLAY_ORDER_BARTENDER 4 +#define JOB_DISPLAY_ORDER_COOK 5 +#define JOB_DISPLAY_ORDER_BOTANIST 6 +#define JOB_DISPLAY_ORDER_JANITOR 7 +#define JOB_DISPLAY_ORDER_CLOWN 8 +#define JOB_DISPLAY_ORDER_MIME 9 +#define JOB_DISPLAY_ORDER_CURATOR 10 +#define JOB_DISPLAY_ORDER_LAWYER 11 +#define JOB_DISPLAY_ORDER_CHAPLAIN 12 +#define JOB_DISPLAY_ORDER_QUARTERMASTER 13 +#define JOB_DISPLAY_ORDER_CARGO_TECHNICIAN 14 +#define JOB_DISPLAY_ORDER_SHAFT_MINER 15 #define JOB_DISPLAY_ORDER_CHIEF_ENGINEER 16 #define JOB_DISPLAY_ORDER_STATION_ENGINEER 17 #define JOB_DISPLAY_ORDER_ATMOSPHERIC_TECHNICIAN 18 diff --git a/code/modules/jobs/job_types/atmospheric_technician.dm b/code/modules/jobs/job_types/atmospheric_technician.dm index 31d66eced2..93775beca9 100644 --- a/code/modules/jobs/job_types/atmospheric_technician.dm +++ b/code/modules/jobs/job_types/atmospheric_technician.dm @@ -7,7 +7,7 @@ total_positions = 3 spawn_positions = 2 supervisors = "the chief engineer" - selection_color = "#fff5cc" + selection_color = "#ff9b3d" exp_requirements = 60 exp_type = EXP_TYPE_CREW diff --git a/code/modules/jobs/job_types/cargo_technician.dm b/code/modules/jobs/job_types/cargo_technician.dm index 9699f12be5..3ceb29bae2 100644 --- a/code/modules/jobs/job_types/cargo_technician.dm +++ b/code/modules/jobs/job_types/cargo_technician.dm @@ -7,7 +7,7 @@ total_positions = 3 spawn_positions = 2 supervisors = "the quartermaster" - selection_color = "#dcba97" + selection_color = "#ca8f55" outfit = /datum/outfit/job/cargo_tech diff --git a/code/modules/jobs/job_types/chemist.dm b/code/modules/jobs/job_types/chemist.dm index 908209ef69..a915d261ed 100644 --- a/code/modules/jobs/job_types/chemist.dm +++ b/code/modules/jobs/job_types/chemist.dm @@ -7,7 +7,7 @@ total_positions = 2 spawn_positions = 2 supervisors = "the chief medical officer" - selection_color = "#ffeef0" + selection_color = "#74b5e0" exp_type = EXP_TYPE_CREW exp_requirements = 60 diff --git a/code/modules/jobs/job_types/chief_engineer.dm b/code/modules/jobs/job_types/chief_engineer.dm index a4b197d479..da3f281267 100644 --- a/code/modules/jobs/job_types/chief_engineer.dm +++ b/code/modules/jobs/job_types/chief_engineer.dm @@ -9,7 +9,7 @@ total_positions = 1 spawn_positions = 1 supervisors = "the captain" - selection_color = "#ffd699" + selection_color = "#ee7400" req_admin_notify = 1 minimal_player_age = 7 exp_requirements = 180 diff --git a/code/modules/jobs/job_types/chief_medical_officer.dm b/code/modules/jobs/job_types/chief_medical_officer.dm index f0f044e6b1..4c7249f048 100644 --- a/code/modules/jobs/job_types/chief_medical_officer.dm +++ b/code/modules/jobs/job_types/chief_medical_officer.dm @@ -9,7 +9,7 @@ total_positions = 1 spawn_positions = 1 supervisors = "the captain" - selection_color = "#99ffe6" + selection_color = "#509ed1" req_admin_notify = 1 minimal_player_age = 7 exp_requirements = 180 diff --git a/code/modules/jobs/job_types/detective.dm b/code/modules/jobs/job_types/detective.dm index 82745ae9fb..27a54fbd1f 100644 --- a/code/modules/jobs/job_types/detective.dm +++ b/code/modules/jobs/job_types/detective.dm @@ -8,7 +8,7 @@ total_positions = 1 spawn_positions = 1 supervisors = "the head of security" - selection_color = "#ffeeee" + selection_color = "#c02f2f" minimal_player_age = 7 exp_requirements = 300 exp_type = EXP_TYPE_CREW diff --git a/code/modules/jobs/job_types/geneticist.dm b/code/modules/jobs/job_types/geneticist.dm index 6006ff1083..d7f59ff883 100644 --- a/code/modules/jobs/job_types/geneticist.dm +++ b/code/modules/jobs/job_types/geneticist.dm @@ -7,7 +7,7 @@ total_positions = 2 spawn_positions = 2 supervisors = "the chief medical officer and research director" - selection_color = "#ffeef0" + selection_color = "#74b5e0" exp_type = EXP_TYPE_CREW exp_requirements = 60 diff --git a/code/modules/jobs/job_types/head_of_personnel.dm b/code/modules/jobs/job_types/head_of_personnel.dm index d373b8c181..e320ce20b4 100644 --- a/code/modules/jobs/job_types/head_of_personnel.dm +++ b/code/modules/jobs/job_types/head_of_personnel.dm @@ -9,7 +9,7 @@ total_positions = 1 spawn_positions = 1 supervisors = "the captain" - selection_color = "#cccccc" + selection_color = "#3a8529" req_admin_notify = 1 minimal_player_age = 10 exp_requirements = 180 diff --git a/code/modules/jobs/job_types/head_of_security.dm b/code/modules/jobs/job_types/head_of_security.dm index 961b9ea58f..3ccbcbfc15 100644 --- a/code/modules/jobs/job_types/head_of_security.dm +++ b/code/modules/jobs/job_types/head_of_security.dm @@ -9,7 +9,7 @@ total_positions = 1 spawn_positions = 1 supervisors = "the captain" - selection_color = "#ff9999" + selection_color = "#b90000" req_admin_notify = 1 minimal_player_age = 14 exp_requirements = 300 diff --git a/code/modules/jobs/job_types/medical_doctor.dm b/code/modules/jobs/job_types/medical_doctor.dm index e3379e4be1..19fa1c7158 100644 --- a/code/modules/jobs/job_types/medical_doctor.dm +++ b/code/modules/jobs/job_types/medical_doctor.dm @@ -7,7 +7,7 @@ total_positions = 5 spawn_positions = 3 supervisors = "the chief medical officer" - selection_color = "#ffeef0" + selection_color = "#74b5e0" outfit = /datum/outfit/job/doctor diff --git a/code/modules/jobs/job_types/quartermaster.dm b/code/modules/jobs/job_types/quartermaster.dm index a3830e389f..49a93026ba 100644 --- a/code/modules/jobs/job_types/quartermaster.dm +++ b/code/modules/jobs/job_types/quartermaster.dm @@ -9,7 +9,7 @@ total_positions = 1 spawn_positions = 1 supervisors = "the captain" - selection_color = "#ead4ae" + selection_color = "#a06121" req_admin_notify = 1 minimal_player_age = 7 exp_requirements = 180 diff --git a/code/modules/jobs/job_types/research_director.dm b/code/modules/jobs/job_types/research_director.dm index 5b239c44e0..5368ceee64 100644 --- a/code/modules/jobs/job_types/research_director.dm +++ b/code/modules/jobs/job_types/research_director.dm @@ -9,7 +9,7 @@ total_positions = 1 spawn_positions = 1 supervisors = "the captain" - selection_color = "#e6b3e6" + selection_color = "#7544cc" req_admin_notify = 1 minimal_player_age = 7 exp_type_department = EXP_TYPE_SCIENCE diff --git a/code/modules/jobs/job_types/roboticist.dm b/code/modules/jobs/job_types/roboticist.dm index ef3c1277a1..782b175ad4 100644 --- a/code/modules/jobs/job_types/roboticist.dm +++ b/code/modules/jobs/job_types/roboticist.dm @@ -7,7 +7,7 @@ total_positions = 2 spawn_positions = 2 supervisors = "the research director" - selection_color = "#ffeeff" + selection_color = "#9574cd" exp_requirements = 60 exp_type = EXP_TYPE_CREW diff --git a/code/modules/jobs/job_types/scientist.dm b/code/modules/jobs/job_types/scientist.dm index e3f04f0b29..f40a25d6ba 100644 --- a/code/modules/jobs/job_types/scientist.dm +++ b/code/modules/jobs/job_types/scientist.dm @@ -7,7 +7,7 @@ total_positions = 5 spawn_positions = 3 supervisors = "the research director" - selection_color = "#ffeeff" + selection_color = "#9574cd" exp_requirements = 60 exp_type = EXP_TYPE_CREW diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm index bb54ed0a6c..4f12d6a19c 100644 --- a/code/modules/jobs/job_types/security_officer.dm +++ b/code/modules/jobs/job_types/security_officer.dm @@ -8,7 +8,7 @@ total_positions = 5 //Handled in /datum/controller/occupations/proc/setup_officer_positions() spawn_positions = 5 //Handled in /datum/controller/occupations/proc/setup_officer_positions() supervisors = "the head of security, and the head of your assigned department (if applicable)" - selection_color = "#ffeeee" + selection_color = "#c02f2f" minimal_player_age = 7 exp_requirements = 300 exp_type = EXP_TYPE_CREW diff --git a/code/modules/jobs/job_types/shaft_miner.dm b/code/modules/jobs/job_types/shaft_miner.dm index 1c662b8e8f..c1b0c643c6 100644 --- a/code/modules/jobs/job_types/shaft_miner.dm +++ b/code/modules/jobs/job_types/shaft_miner.dm @@ -7,7 +7,7 @@ total_positions = 3 spawn_positions = 3 supervisors = "the quartermaster" - selection_color = "#dcba97" + selection_color = "#ca8f55" outfit = /datum/outfit/job/miner diff --git a/code/modules/jobs/job_types/station_engineer.dm b/code/modules/jobs/job_types/station_engineer.dm index 4a2a2c7fd2..55381549ba 100644 --- a/code/modules/jobs/job_types/station_engineer.dm +++ b/code/modules/jobs/job_types/station_engineer.dm @@ -7,7 +7,7 @@ total_positions = 5 spawn_positions = 5 supervisors = "the chief engineer" - selection_color = "#fff5cc" + selection_color = "#ff9b3d" exp_requirements = 60 exp_type = EXP_TYPE_CREW diff --git a/code/modules/jobs/job_types/virologist.dm b/code/modules/jobs/job_types/virologist.dm index 26f38e594b..dcc13af627 100644 --- a/code/modules/jobs/job_types/virologist.dm +++ b/code/modules/jobs/job_types/virologist.dm @@ -7,7 +7,7 @@ total_positions = 1 spawn_positions = 1 supervisors = "the chief medical officer" - selection_color = "#ffeef0" + selection_color = "#74b5e0" exp_type = EXP_TYPE_CREW exp_requirements = 60 diff --git a/code/modules/jobs/job_types/warden.dm b/code/modules/jobs/job_types/warden.dm index d7691cb488..eb0ce292c8 100644 --- a/code/modules/jobs/job_types/warden.dm +++ b/code/modules/jobs/job_types/warden.dm @@ -8,7 +8,7 @@ total_positions = 1 spawn_positions = 1 supervisors = "the head of security" - selection_color = "#ffeeee" + selection_color = "#c02f2f" minimal_player_age = 7 exp_requirements = 300 exp_type = EXP_TYPE_CREW diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index 5ea556304e..cd0d19f543 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -37,7 +37,8 @@ return /mob/dead/new_player/proc/new_player_panel() - var/output = "

Setup Character

" + var/output = "

Welcome, [client ? client.prefs.real_name : "Unknown User"]

" + output += "

Setup Character

" if(SSticker.current_state <= GAME_STATE_PREGAME) switch(ready) @@ -444,7 +445,7 @@ if(SEC_LEVEL_RED) level = "red" if(SEC_LEVEL_DELTA) - level = "delta" + level = "delta" var/dat = "
Round Duration: [DisplayTimeText(world.time - SSticker.round_start_time)]
Alert Level: [capitalize(level)]
" if(SSshuttle.emergency) @@ -457,17 +458,18 @@ for(var/datum/job/prioritized_job in SSjob.prioritized_jobs) if(prioritized_job.current_positions >= prioritized_job.total_positions) SSjob.prioritized_jobs -= prioritized_job - dat += "
" + dat += "
" var/column_counter = 0 - for(var/list/category in list(GLOB.command_positions) + list(GLOB.engineering_positions) + list(GLOB.supply_positions) + list(GLOB.nonhuman_positions - "pAI") + list(GLOB.civilian_positions) + list(GLOB.medical_positions) + list(GLOB.science_positions) + list(GLOB.security_positions)) + var/free_space = 0 + for(var/list/category in list(GLOB.command_positions) + list(GLOB.supply_positions) + list(GLOB.engineering_positions) + list(GLOB.nonhuman_positions - "pAI") + list(GLOB.civilian_positions) + list(GLOB.medical_positions) + list(GLOB.science_positions) + list(GLOB.security_positions)) var/cat_color = "fff" //random default if(SSjob.name_occupations && SSjob.name_occupations[category[1]]) cat_color = SSjob.name_occupations[category[1]].selection_color //use the color of the first job in the category (the department head) as the category color else cat_color = SSjob.occupations[category[1]].selection_color - dat += "
" dat += "[SSjob.name_occupations[category[1]].exp_type_department]" + var/list/dept_dat = list() for(var/job in category) var/datum/job/job_datum = SSjob.name_occupations[job] @@ -484,10 +486,16 @@ dat += jointext(dept_dat, "") dat += "

" column_counter++ - if(column_counter > 0 && (column_counter % 3 == 0)) + if(free_space <=4) + free_space++ + if(column_counter > 0 && (column_counter % 3 == 0)) + dat += "
" + if(free_space >= 5 && (free_space % 5 == 0) && (column_counter % 3 != 0)) + free_space = 0 + column_counter = 0 dat += "" - dat += "
" - dat += "" + + dat += "
" var/available_ghosts = 0 for(var/spawner in GLOB.mob_spawners) @@ -502,7 +510,6 @@ if(!available_ghosts) dat += "
There are currently no open ghost spawners.
" else - dat += "
Currently open Ghost roles:

" var/list/categorizedJobs = list("Ghost Role" = list(jobs = list(), titles = GLOB.mob_spawners, color = "#ffffff")) for(var/spawner in GLOB.mob_spawners) if(!LAZYLEN(spawner)) @@ -512,10 +519,8 @@ continue categorizedJobs["Ghost Role"]["jobs"] += spawner - dat += "\s*$/g,rb={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"
" + dat += "
" for(var/jobcat in categorizedJobs) - if(categorizedJobs[jobcat]["colBreak"]) - dat += "" if(!length(categorizedJobs[jobcat]["jobs"])) continue var/color = categorizedJobs[jobcat]["color"] @@ -528,7 +533,7 @@ dat += "
" dat += "" - var/datum/browser/popup = new(src, "latechoices", "Choose Profession", 680, 580) + var/datum/browser/popup = new(src, "latechoices", "Choose Profession", 720, 600) popup.add_stylesheet("playeroptions", 'html/browser/playeroptions.css') popup.set_content(jointext(dat, "")) popup.open(FALSE) // FALSE is passed to open so that it doesn't use the onclose() proc From 2ad94dccac95846cb236584e614d241110de662b Mon Sep 17 00:00:00 2001 From: Sishen Date: Sun, 18 Aug 2019 21:11:16 -0400 Subject: [PATCH 040/222] Update dynamic_rulesets_roundstart.dm --- code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm index 76b1952492..2d829e448a 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm @@ -203,6 +203,7 @@ cost = 30 requirements = list(100,90,80,60,40,30,10,10,10,10) high_population_requirement = 10 + pop_per_requirement = 5 flags = HIGHLANDER_RULESET var/cultist_cap = list(2,2,2,3,3,4,4,4,4,4) var/datum/team/cult/main_cult @@ -262,6 +263,7 @@ cost = 40 requirements = list(90,90,90,80,60,40,30,20,10,10) high_population_requirement = 10 + pop_per_requirement = 5 flags = HIGHLANDER_RULESET var/operative_cap = list(2,2,2,3,3,3,4,4,5,5) var/datum/team/nuclear/nuke_team From 8fdb1c59d5220870e4bf70b3cf60ffa69bfe593d Mon Sep 17 00:00:00 2001 From: Sishen Date: Sun, 18 Aug 2019 21:16:07 -0400 Subject: [PATCH 041/222] Update dynamic_rulesets_roundstart.dm --- code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm index 2d829e448a..ee5ad46fb7 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm @@ -154,7 +154,7 @@ minimum_required_age = 14 restricted_roles = list("Head of Security", "Captain") // Just to be sure that a wizard getting picked won't ever imply a Captain or HoS not getting drafted required_candidates = 1 - weight = 2 + weight = 1 cost = 30 requirements = list(90,90,70,40,30,20,10,10,10,10) high_population_requirement = 10 From a351d8f99574653405447c65d356c2627b38d85f Mon Sep 17 00:00:00 2001 From: Code-Cygnet <54194215+Code-Cygnet@users.noreply.github.com> Date: Sun, 18 Aug 2019 21:34:31 -0400 Subject: [PATCH 042/222] Update captain.dm Attempted error fix. --- code/modules/jobs/job_types/captain.dm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm index dd8cc5a887..1e64773607 100755 --- a/code/modules/jobs/job_types/captain.dm +++ b/code/modules/jobs/job_types/captain.dm @@ -21,8 +21,12 @@ Captain access = list() //See get_access() minimal_access = list() //See get_access() + mind_traits = list(TRAIT_CAPTAIN_METABOLISM) + blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/prosopagnosia, /datum/quirk/insanity) + + /datum/job/captain/get_access() return get_all_accesses() From 5840284e9ea12f6cdd52681e9c2588236f8a4b7d Mon Sep 17 00:00:00 2001 From: Code-Cygnet <54194215+Code-Cygnet@users.noreply.github.com> Date: Sun, 18 Aug 2019 22:14:41 -0400 Subject: [PATCH 043/222] Update alcohol_reagents.dm Edited a typo at line 2144. --- code/modules/reagents/chemistry/reagents/alcohol_reagents.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm index 35efd651df..8b787b5839 100644 --- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm @@ -2141,7 +2141,7 @@ All effects don't start immediately, but rather get worse over time; the rate is M.adjustOxyLoss(-3.5,0) M.adjustFireLoss(-3.5,0) M.adjustToxLoss(-3.5,0) - M.radiation = max(M.raddiation - 25, 0) + M.radiation = max(M.radiation - 25, 0) . = 1 return ..() From c8810be706cecde36d49a54a8a5970fb628e346e Mon Sep 17 00:00:00 2001 From: Code-Cygnet <54194215+Code-Cygnet@users.noreply.github.com> Date: Sun, 18 Aug 2019 22:15:52 -0400 Subject: [PATCH 044/222] Update captain.dm --- code/modules/jobs/job_types/captain.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm index 3d705ffef5..58943df4e4 100755 --- a/code/modules/jobs/job_types/captain.dm +++ b/code/modules/jobs/job_types/captain.dm @@ -21,7 +21,7 @@ Captain access = list() //See get_access() minimal_access = list() //See get_access() - mind_traits = list(TRAIT_CAPTAIN_METABOLISM) + mind_traits = list(TRAIT_CAPTAIN_METABOLISM) blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity) From 70e3964fd2561f7bfcdd790613196c8b68e57f68 Mon Sep 17 00:00:00 2001 From: Poojawa Date: Sun, 18 Aug 2019 21:22:10 -0500 Subject: [PATCH 045/222] Update head_of_security.dm --- code/modules/jobs/job_types/head_of_security.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/jobs/job_types/head_of_security.dm b/code/modules/jobs/job_types/head_of_security.dm index 961b9ea58f..249e426c96 100644 --- a/code/modules/jobs/job_types/head_of_security.dm +++ b/code/modules/jobs/job_types/head_of_security.dm @@ -47,7 +47,7 @@ suit_store = /obj/item/gun/energy/e_gun r_pocket = /obj/item/assembly/flash/handheld l_pocket = /obj/item/restraints/handcuffs - backpack_contents = list(/obj/item/melee/baton/loaded=1) + backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1) backpack = /obj/item/storage/backpack/security satchel = /obj/item/storage/backpack/satchel/sec From 43541b043d177e484f45d499143c10a608b8e993 Mon Sep 17 00:00:00 2001 From: Poojawa Date: Sun, 18 Aug 2019 21:27:00 -0500 Subject: [PATCH 046/222] Update warden.dm --- code/modules/jobs/job_types/warden.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/jobs/job_types/warden.dm b/code/modules/jobs/job_types/warden.dm index d7691cb488..23d964dad3 100644 --- a/code/modules/jobs/job_types/warden.dm +++ b/code/modules/jobs/job_types/warden.dm @@ -42,7 +42,7 @@ glasses = /obj/item/clothing/glasses/hud/security/sunglasses r_pocket = /obj/item/assembly/flash/handheld l_pocket = /obj/item/restraints/handcuffs - suit_store = /obj/item/gun/energy/disabler + suit_store = /obj/item/gun/energy/e_gun/advtaser backpack_contents = list(/obj/item/melee/baton/loaded=1) backpack = /obj/item/storage/backpack/security From 8ad705ec74ccf8237699f10ed827930361f2b072 Mon Sep 17 00:00:00 2001 From: Poojawa Date: Mon, 19 Aug 2019 02:16:30 -0500 Subject: [PATCH 047/222] Update curator.dm --- code/modules/jobs/job_types/curator.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/jobs/job_types/curator.dm b/code/modules/jobs/job_types/curator.dm index 6199d812df..7f02b6721f 100644 --- a/code/modules/jobs/job_types/curator.dm +++ b/code/modules/jobs/job_types/curator.dm @@ -30,7 +30,8 @@ accessory = /obj/item/clothing/accessory/pocketprotector/full backpack_contents = list( /obj/item/soapstone = 1, - /obj/item/barcodescanner = 1 + /obj/item/barcodescanner = 1, + /obj/item/melee/curator_whip = 1 ) /datum/outfit/job/curator/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) From cce33ec7e58be535aa982c2620a14d038a49b2ac Mon Sep 17 00:00:00 2001 From: Trilbyspaceclone <30435998+Trilbyspaceclone@users.noreply.github.com> Date: Mon, 19 Aug 2019 07:17:57 -0400 Subject: [PATCH 048/222] Update drink_reagents.dm --- code/modules/reagents/chemistry/reagents/drink_reagents.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm index 978fa54d0f..f80206c04a 100644 --- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm @@ -891,10 +891,10 @@ taste_description = "sugar and catnip" glass_icon_state = "teaglass" glass_name = "glass of catnip tea" - glass_desc = "A purfect drink for a cat." + glass_desc = "A purrfect drink for a cat." /datum/reagent/consumable/catnip_tea/on_mob_life(mob/living/carbon/M) - M.getStaminaLoss(min(50 - M.getStaminaLoss(), 3)) + M.adjustStaminaLoss(min(50 - M.getStaminaLoss(), 3)) if(prob(20)) M.emote("nya") if(prob(20)) From c10c78eb2737871428840604a7a78515a6107446 Mon Sep 17 00:00:00 2001 From: TrilbySpaceClone Date: Mon, 19 Aug 2019 07:56:20 -0400 Subject: [PATCH 049/222] readds cotten sprites --- icons/obj/hydroponics/harvest.dmi | Bin 51397 -> 51850 bytes icons/obj/hydroponics/seeds.dmi | Bin 22135 -> 22302 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/icons/obj/hydroponics/harvest.dmi b/icons/obj/hydroponics/harvest.dmi index ef84c20d5676413280a17f1d0b4c722a0dec8dd0..5f1a9b0515798506bddc2fdddd12d975a779c929 100644 GIT binary patch delta 17450 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 SZnGx?5O})!xvX1ns6oy6`q#Fh)X@OyYVdfv- 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 diff --git a/icons/obj/hydroponics/seeds.dmi b/icons/obj/hydroponics/seeds.dmi index b65f395598697a0f832209bcf774799e4b5adc3a..1cdb720dca490f167c133b8d48d09d57c0a90399 100644 GIT binary patch literal 22302 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 UH=Sp2+*^Q}iuS8|CELjV0xwgJ?*IS* literal 22135 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 From 167b18d045386e1444bef0400fad23dbb9f85655 Mon Sep 17 00:00:00 2001 From: Code-Cygnet <54194215+Code-Cygnet@users.noreply.github.com> Date: Mon, 19 Aug 2019 15:28:51 -0400 Subject: [PATCH 050/222] Update code/modules/reagents/chemistry/reagents/alcohol_reagents.dm Error spotted at 2138 and fixed by Sishen, aka Papa Pax! Co-Authored-By: Sishen1542 --- code/modules/reagents/chemistry/reagents/alcohol_reagents.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm index 8b787b5839..afd2be3f53 100644 --- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm @@ -2135,7 +2135,7 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_desc = "The gems of this majestic chalice represent the departments and their Heads." /datum/reagent/consumable/ethanol/commander_and_chief/on_mob_life(mob/living/carbon/M) - if(M.mind && HAS_TRAIT(M.mind, TRAIT_CAPTAIN_METABOLISM))) + if(M.mind && HAS_TRAIT(M.mind, TRAIT_CAPTAIN_METABOLISM)) M.heal_bodypart_damage(2,2,2) M.adjustBruteLoss(-3.5,0) M.adjustOxyLoss(-3.5,0) From e7d08d1fed42049545e41f6580519b11213b90fc Mon Sep 17 00:00:00 2001 From: Code-Cygnet <54194215+Code-Cygnet@users.noreply.github.com> Date: Mon, 19 Aug 2019 15:53:13 -0400 Subject: [PATCH 051/222] Update drinks_recipes.dm Fixed error at line 803, allies_cocktail to alliescocktail. Am bone-head :(. --- code/modules/food_and_drinks/recipes/drinks_recipes.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/food_and_drinks/recipes/drinks_recipes.dm b/code/modules/food_and_drinks/recipes/drinks_recipes.dm index d35955d2d3..3ba16dfa48 100644 --- a/code/modules/food_and_drinks/recipes/drinks_recipes.dm +++ b/code/modules/food_and_drinks/recipes/drinks_recipes.dm @@ -800,5 +800,5 @@ name = "Commander and Chief" id = "commander_and_chief" results = list("commander_and_chief" = 50) - required_reagents = list("allies_cocktail" = 50, "champagne" = 20, "doctors_delight" = 10, "quintiple_sec" = 10, "screwdriver" = 10) + required_reagents = list("alliescocktail" = 50, "champagne" = 20, "doctors_delight" = 10, "quintiple_sec" = 10, "screwdriver" = 10) mix_message = "When your powers combine, I am Captain Pl-..." From d6c9daa4eb17ea293d0a22b891d867ccbd9aaec4 Mon Sep 17 00:00:00 2001 From: Code-Cygnet <54194215+Code-Cygnet@users.noreply.github.com> Date: Mon, 19 Aug 2019 16:04:16 -0400 Subject: [PATCH 052/222] Update drinks_recipes.dm Fixed more errors, spelling and id errors to be exact with the help of Papa Pax :D. --- code/modules/food_and_drinks/recipes/drinks_recipes.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/food_and_drinks/recipes/drinks_recipes.dm b/code/modules/food_and_drinks/recipes/drinks_recipes.dm index 3ba16dfa48..82e80d7584 100644 --- a/code/modules/food_and_drinks/recipes/drinks_recipes.dm +++ b/code/modules/food_and_drinks/recipes/drinks_recipes.dm @@ -800,5 +800,5 @@ name = "Commander and Chief" id = "commander_and_chief" results = list("commander_and_chief" = 50) - required_reagents = list("alliescocktail" = 50, "champagne" = 20, "doctors_delight" = 10, "quintiple_sec" = 10, "screwdriver" = 10) + required_reagents = list("alliescocktail" = 50, "champagne" = 20, "doctorsdelight" = 10, "quintuple_sec" = 10, "screwdrivercocktail" = 10) mix_message = "When your powers combine, I am Captain Pl-..." From b01f135d3a91fa04fda32b2969198a587c0f1303 Mon Sep 17 00:00:00 2001 From: Poojawa Date: Sat, 24 Aug 2019 19:09:56 -0500 Subject: [PATCH 053/222] addresses a few concerns --- code/modules/jobs/job_types/_job.dm | 2 ++ code/modules/jobs/job_types/captain.dm | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm index cc18560cbb..2eeffa8b7a 100644 --- a/code/modules/jobs/job_types/_job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -139,6 +139,8 @@ return 0 if(!SSdbcore.Connect()) return 0 //Without a database connection we can't get a player's age so we'll assume they're old enough for all jobs + if(C.prefs.db_flags & DB_FLAG_EXEMPT) + return 0 if(!isnum(minimal_player_age)) return 0 diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm index d334cff772..00a710bdf4 100644 --- a/code/modules/jobs/job_types/captain.dm +++ b/code/modules/jobs/job_types/captain.dm @@ -25,7 +25,7 @@ display_order = JOB_DISPLAY_ORDER_CAPTAIN - blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/nonviolent, /datum/quirk/insanity) + blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity) /datum/job/captain/get_access() return get_all_accesses() From 1ba9d374fe5f5a8f6db95a0589117fc5b3083ecd Mon Sep 17 00:00:00 2001 From: Poojawa Date: Sun, 25 Aug 2019 01:19:16 -0500 Subject: [PATCH 054/222] whatever, I guess --- code/modules/mob/dead/new_player/new_player.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index cd0d19f543..1cd32d43ac 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -546,7 +546,7 @@ var/frn = CONFIG_GET(flag/force_random_names) if(!frn) - frn = jobban_isbanned(src, "Appearance") + frn = jobban_isbanned(src, "appearance") if(QDELETED(src)) return if(frn) From a4fd2be7f7fd97fb74fb4607362e677b35086a7d Mon Sep 17 00:00:00 2001 From: Tupinambis Date: Mon, 26 Aug 2019 14:45:12 -0500 Subject: [PATCH 055/222] Various Shotgun Nerfs. --- code/modules/projectiles/guns/ballistic/shotgun.dm | 2 ++ .../projectiles/projectile/bullets/shotgun.dm | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm index 856dfed78b..04f24794ef 100644 --- a/code/modules/projectiles/guns/ballistic/shotgun.dm +++ b/code/modules/projectiles/guns/ballistic/shotgun.dm @@ -5,6 +5,7 @@ item_state = "shotgun" w_class = WEIGHT_CLASS_BULKY force = 10 + fire_delay = 10 flags_1 = CONDUCT_1 slot_flags = ITEM_SLOT_BACK mag_type = /obj/item/ammo_box/magazine/internal/shot @@ -205,6 +206,7 @@ name = "combat shotgun" desc = "A semi automatic shotgun with tactical furniture and a six-shell capacity underneath." icon_state = "cshotgun" + fire_delay = 5 mag_type = /obj/item/ammo_box/magazine/internal/shot/com w_class = WEIGHT_CLASS_HUGE unique_reskin = list("Tatical" = "cshotgun", diff --git a/code/modules/projectiles/projectile/bullets/shotgun.dm b/code/modules/projectiles/projectile/bullets/shotgun.dm index f9aa47c6a3..3595df098a 100644 --- a/code/modules/projectiles/projectile/bullets/shotgun.dm +++ b/code/modules/projectiles/projectile/bullets/shotgun.dm @@ -1,11 +1,11 @@ /obj/item/projectile/bullet/shotgun_slug name = "12g shotgun slug" - damage = 60 + damage = 50 /obj/item/projectile/bullet/shotgun_beanbag name = "beanbag slug" damage = 5 - stamina = 80 + stamina = 70 /obj/item/projectile/bullet/incendiary/shotgun name = "incendiary slug" @@ -47,7 +47,7 @@ /obj/item/projectile/bullet/shotgun_frag12 name ="frag12 slug" - damage = 25 + damage = 20 knockdown = 50 /obj/item/projectile/bullet/shotgun_frag12/on_hit(atom/target, blocked = FALSE) @@ -61,12 +61,12 @@ /obj/item/projectile/bullet/pellet/shotgun_buckshot name = "buckshot pellet" - damage = 12.5 + damage = 10 /obj/item/projectile/bullet/pellet/shotgun_rubbershot name = "rubbershot pellet" - damage = 3 - stamina = 25 + damage = 2 + stamina = 12.5 /obj/item/projectile/bullet/pellet/Range() ..() From 13638ed5d67a2269c9181bce3dc36294038e48bf Mon Sep 17 00:00:00 2001 From: Tupinambis Date: Mon, 26 Aug 2019 15:08:36 -0500 Subject: [PATCH 056/222] Reverts some changes I deemed unneccesary. Undoes a fuckup --- code/modules/projectiles/guns/ballistic/shotgun.dm | 1 - code/modules/projectiles/projectile/bullets/shotgun.dm | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm index 04f24794ef..951d227a89 100644 --- a/code/modules/projectiles/guns/ballistic/shotgun.dm +++ b/code/modules/projectiles/guns/ballistic/shotgun.dm @@ -5,7 +5,6 @@ item_state = "shotgun" w_class = WEIGHT_CLASS_BULKY force = 10 - fire_delay = 10 flags_1 = CONDUCT_1 slot_flags = ITEM_SLOT_BACK mag_type = /obj/item/ammo_box/magazine/internal/shot diff --git a/code/modules/projectiles/projectile/bullets/shotgun.dm b/code/modules/projectiles/projectile/bullets/shotgun.dm index 3595df098a..3555cd3b75 100644 --- a/code/modules/projectiles/projectile/bullets/shotgun.dm +++ b/code/modules/projectiles/projectile/bullets/shotgun.dm @@ -1,6 +1,6 @@ /obj/item/projectile/bullet/shotgun_slug name = "12g shotgun slug" - damage = 50 + damage = 60 /obj/item/projectile/bullet/shotgun_beanbag name = "beanbag slug" @@ -47,7 +47,7 @@ /obj/item/projectile/bullet/shotgun_frag12 name ="frag12 slug" - damage = 20 + damage = 25 knockdown = 50 /obj/item/projectile/bullet/shotgun_frag12/on_hit(atom/target, blocked = FALSE) From d43b4599ef18cbea53cb2bae31380185a027e38e Mon Sep 17 00:00:00 2001 From: Tupinambis Date: Mon, 26 Aug 2019 15:53:44 -0500 Subject: [PATCH 057/222] I was bullied to reduce click delay. --- code/modules/projectiles/guns/ballistic/shotgun.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm index 951d227a89..9962bb3424 100644 --- a/code/modules/projectiles/guns/ballistic/shotgun.dm +++ b/code/modules/projectiles/guns/ballistic/shotgun.dm @@ -205,7 +205,7 @@ name = "combat shotgun" desc = "A semi automatic shotgun with tactical furniture and a six-shell capacity underneath." icon_state = "cshotgun" - fire_delay = 5 + fire_delay = 3 mag_type = /obj/item/ammo_box/magazine/internal/shot/com w_class = WEIGHT_CLASS_HUGE unique_reskin = list("Tatical" = "cshotgun", From 419ea7f58c04dceb8e75dcc19e294a009f563232 Mon Sep 17 00:00:00 2001 From: TrilbySpaceClone Date: Tue, 27 Aug 2019 12:41:47 -0400 Subject: [PATCH 058/222] Fancy_part1 --- code/game/objects/items/tools/crowbar.dm | 2 +- code/game/objects/items/tools/screwdriver.dm | 2 +- code/game/objects/items/tools/weldingtool.dm | 2 +- code/game/objects/items/tools/wirecutters.dm | 4 ++-- code/game/objects/items/tools/wrench.dm | 2 +- icons/obj/clothing/belt_overlays.dmi | Bin 4840 -> 5402 bytes icons/obj/tools.dmi | Bin 23306 -> 26057 bytes modular_citadel/icons/obj/tools.dmi | Bin 16853 -> 18597 bytes 8 files changed, 6 insertions(+), 6 deletions(-) diff --git a/code/game/objects/items/tools/crowbar.dm b/code/game/objects/items/tools/crowbar.dm index 70bfebb799..f891a48df6 100644 --- a/code/game/objects/items/tools/crowbar.dm +++ b/code/game/objects/items/tools/crowbar.dm @@ -31,7 +31,7 @@ name = "brass crowbar" desc = "A brass crowbar. It feels faintly warm to the touch." resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "crowbar_brass" + icon_state = "crowbar_clock" toolspeed = 0.5 /obj/item/crowbar/bronze diff --git a/code/game/objects/items/tools/screwdriver.dm b/code/game/objects/items/tools/screwdriver.dm index 68946f73cd..6cbede78a8 100644 --- a/code/game/objects/items/tools/screwdriver.dm +++ b/code/game/objects/items/tools/screwdriver.dm @@ -81,7 +81,7 @@ name = "brass screwdriver" desc = "A screwdriver made of brass. The handle feels freezing cold." resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "screwdriver_brass" + icon_state = "screwdriver_clock" item_state = "screwdriver_brass" toolspeed = 0.5 random_color = FALSE diff --git a/code/game/objects/items/tools/weldingtool.dm b/code/game/objects/items/tools/weldingtool.dm index 9b622a14c4..fb38e4335e 100644 --- a/code/game/objects/items/tools/weldingtool.dm +++ b/code/game/objects/items/tools/weldingtool.dm @@ -360,7 +360,7 @@ name = "brass welding tool" desc = "A brass welder that seems to constantly refuel itself. It is faintly warm to the touch." resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "brasswelder" + icon_state = "clockwelder" item_state = "brasswelder" /obj/item/weldingtool/bronze diff --git a/code/game/objects/items/tools/wirecutters.dm b/code/game/objects/items/tools/wirecutters.dm index 527891afdb..e40ae8bdc1 100644 --- a/code/game/objects/items/tools/wirecutters.dm +++ b/code/game/objects/items/tools/wirecutters.dm @@ -63,9 +63,9 @@ /obj/item/wirecutters/brass name = "brass wirecutters" - desc = "A pair of wirecutters made of brass. The handle feels freezing cold to the touch." + desc = "A pair of eloquent wirecutters made of brass. The handle feels freezing cold to the touch." resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "cutters_brass" + icon_state = "cutters_clock" random_color = FALSE toolspeed = 0.5 diff --git a/code/game/objects/items/tools/wrench.dm b/code/game/objects/items/tools/wrench.dm index 8ff960825a..462eb22aaa 100644 --- a/code/game/objects/items/tools/wrench.dm +++ b/code/game/objects/items/tools/wrench.dm @@ -32,7 +32,7 @@ name = "brass wrench" desc = "A brass wrench. It's faintly warm to the touch." resistance_flags = FIRE_PROOF | ACID_PROOF - icon_state = "wrench_brass" + icon_state = "wrench_clock" toolspeed = 0.5 /obj/item/wrench/bronze diff --git a/icons/obj/clothing/belt_overlays.dmi b/icons/obj/clothing/belt_overlays.dmi index 717937c0340ca2f25f7358e58b694d008c93838a..da8ff0a20bd6c93dbbb17545017ddf5de03911ab 100644 GIT binary patch literal 5402 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 f8@CtDDIg_{bR$R$NJxW(bVzsi-e>WB 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
[stamps]" + else if(istype(target.get_active_held_item(), /obj/item/pen) | istype(target.get_active_held_item(), /obj/item/toy/crayon)) + return "[name][info_links]
[stamps]" + else + return "[name][info]
[stamps]" + +/obj/item/paper/oui_canview(mob/target) + if(check_rights_for(target.client, R_FUN)) //Allows admins to view faxes + return TRUE + if(isAI(target)) + var/mob/living/silicon/ai/ai = target + return get_dist(src, ai.current) < 2 + if(iscyborg(target)) + return get_dist(src, target) < 2 + return ..() /obj/item/paper/update_icon() @@ -65,20 +90,13 @@ /obj/item/paper/examine(mob/user) ..() to_chat(user, "Alt-click to fold it.") - - var/datum/asset/assets = get_asset_datum(/datum/asset/spritesheet/simple/paper) - assets.send(user) - - if(in_range(user, src) || isobserver(user)) - if(user.is_literate()) - user << browse("[name][info]
[stamps]", "window=[name]") - onclose(user, "[name]") - else - user << browse("[name][stars(info)]
[stamps]", "window=[name]") - onclose(user, "[name]") + if(oui_canview(user)) + ui.render(user) else to_chat(user, "You're too far away to read it!") +/obj/item/paper/proc/show_content(mob/user) + user.examinate(src) /obj/item/paper/verb/rename() set name = "Rename paper" @@ -98,7 +116,7 @@ if((loc == usr && usr.stat == CONSCIOUS)) name = "paper[(n_name ? text("- '[n_name]'") : null)]" add_fingerprint(usr) - + ui.render_all() /obj/item/paper/suicide_act(mob/user) user.visible_message("[user] scratches a grid on [user.p_their()] wrist with the paper! It looks like [user.p_theyre()] trying to commit sudoku...") @@ -108,7 +126,7 @@ spam_flag = FALSE /obj/item/paper/attack_self(mob/user) - user.examinate(src) + show_content(user) if(rigged && (SSevents.holidays && SSevents.holidays[APRIL_FOOLS])) if(!spam_flag) spam_flag = TRUE @@ -123,11 +141,9 @@ else //cyborg or AI not seeing through a camera dist = get_dist(src, user) if(dist < 2) - usr << browse("[name][info]
[stamps]", "window=[name]") - onclose(usr, "[name]") + show_content(user) else - usr << browse("[name][stars(info)]
[stamps]", "window=[name]") - onclose(usr, "[name]") + to_chat(user, "You can't quite see it.") /obj/item/paper/proc/addtofield(id, text, links = 0) @@ -173,6 +189,7 @@ for(var/i in 1 to min(fields, 15)) addtofield(i, "
write", 1) info_links = info_links + "write" + ui.render_all() /obj/item/paper/proc/clearpaper() @@ -289,7 +306,7 @@ if(istype(P, /obj/item/pen) || istype(P, /obj/item/toy/crayon)) if(user.is_literate()) - user << browse("[name][info_links]
[stamps]", "window=[name]") + show_content(user) return else to_chat(user, "You don't know how to read or write.") @@ -312,6 +329,7 @@ add_overlay(stampoverlay) to_chat(user, "You stamp the paper with your rubber stamp.") + ui.render_all() if(P.is_hot()) if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(10)) diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm index 871fd32b16..082b1a7d11 100644 --- a/code/modules/recycling/disposal/bin.dm +++ b/code/modules/recycling/disposal/bin.dm @@ -264,6 +264,13 @@ name = "disposal unit" desc = "A pneumatic waste disposal unit." icon_state = "disposal" + var/datum/oracle_ui/themed/nano/ui + +/obj/machinery/disposal/bin/Initialize(mapload, obj/structure/disposalconstruct/make_from) + . = ..() + ui = new /datum/oracle_ui/themed/nano(src, 330, 190, "disposal_bin") + ui.auto_refresh = TRUE + ui.can_resize = FALSE // attack by item places it in to disposal /obj/machinery/disposal/bin/attackby(obj/item/I, mob/user, params) @@ -275,32 +282,43 @@ STR.remove_from_storage(O,src) T.update_icon() update_icon() + ui.soft_update_fields() else + ui.soft_update_fields() return ..() // handle machine interaction -/obj/machinery/disposal/bin/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ - datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state) +/obj/machinery/disposal/bin/ui_interact(mob/user, state) if(stat & BROKEN) return - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - ui = new(user, src, ui_key, "disposal_unit", name, 300, 200, master_ui, state) - ui.open() + if(user.loc == src) + to_chat(user, "You cannot reach the controls from inside!") + return + ui.render(user) -/obj/machinery/disposal/bin/ui_data(mob/user) +/obj/machinery/disposal/bin/oui_canview(mob/user) + if(user.loc == src) + return FALSE + if(stat & BROKEN) + return FALSE + if(Adjacent(user)) + return TRUE + return ..() + + +/obj/machinery/disposal/bin/oui_data(mob/user) var/list/data = list() - data["flush"] = flush - data["full_pressure"] = full_pressure - data["pressure_charging"] = pressure_charging - data["panel_open"] = panel_open - var/per = CLAMP(100* air_contents.return_pressure() / (SEND_PRESSURE), 0, 100) - data["per"] = round(per, 1) + data["flush"] = flush ? ui.act("Disengage", user, "handle-0", class="active") : ui.act("Engage", user, "handle-1") + data["full_pressure"] = full_pressure ? "Ready" : (pressure_charging ? "Pressurizing" : "Off") + data["pressure_charging"] = pressure_charging ? ui.act("Turn Off", user, "pump-0", class="active", disabled=full_pressure) : ui.act("Turn On", user, "pump-1", disabled=full_pressure) + var/per = full_pressure ? 100 : CLAMP(100* air_contents.return_pressure() / (SEND_PRESSURE), 0, 99) + data["per"] = "[round(per, 1)]%" + data["contents"] = ui.act("Eject Contents", user, "eject", disabled=contents.len < 1) data["isai"] = isAI(user) return data -/obj/machinery/disposal/bin/ui_act(action, params) +/obj/machinery/disposal/bin/oui_act(mob/user, action, list/params) if(..()) return @@ -327,6 +345,7 @@ if("eject") eject() . = TRUE + ui.soft_update_fields() /obj/machinery/disposal/bin/hitby(atom/movable/AM) @@ -346,6 +365,7 @@ full_pressure = FALSE pressure_charging = TRUE update_icon() + ui.soft_update_fields() /obj/machinery/disposal/bin/update_icon() cut_overlays() @@ -389,7 +409,7 @@ do_flush() flush_count = 0 - updateDialog() + ui.soft_update_fields() if(flush && air_contents.return_pressure() >= SEND_PRESSURE) // flush can happen even without power do_flush() diff --git a/modular_kepler/code/modules/oracle_ui/README.md b/modular_kepler/code/modules/oracle_ui/README.md new file mode 100644 index 0000000000..8aaf73f513 --- /dev/null +++ b/modular_kepler/code/modules/oracle_ui/README.md @@ -0,0 +1,233 @@ +# `/datum/oracle_ui` + +This datum is a replacement for tgui which does not use any Node.js dependencies, and works entirely through raw HTML, JS and CSS. It's designed to be reasonably easy to port something from tgui to oracle_ui. + +### How to create a UI + +For this example, we're going to port the disposals bin from tgui to oracle_ui. + +#### Step 1 + +In order to create a UI, you will first need to create an instance of `/datum/oracle_ui` or one of its subclasses, in this case `/datum/oracle_ui/themed/nano`. + +You need to pass in `src`, the width of the window, the height of the window, and the template to render from. You can optionally set some flags to disallow window resizing and whether to automatically refresh the UI. + +`code/modules/recycling/disposal-unit.dm` +```dm +/obj/machinery/disposal/bin/Initialize(mapload, obj/structure/disposalconstruct/make_from) + . = ..() + ui = new /datum/oracle_ui/themed/nano(src, 330, 190, "disposal_bin") + ui.auto_refresh = TRUE + ui.can_resize = FALSE +``` + +#### Step 2 + +You will now need to make a template in `modular_kepler/html/oracle_ui/content/{template_name}`. + +Values defined as `@{value}` will get replaced at runtime by oracle_ui. + +`modular_kepler/html/oracle_ui/content/disposal_bin/index.html` +```html +
+
+ State: +
@{full_pressure}
+
+
+ Pressure: +
+
+
+
@{per}
+
+
+
+
+ Handle: +
@{flush}
+
+
+ Eject: +
@{contents}
+
+
+ Compressor: +
@{pressure_charging}
+
+
+``` + +#### Step 3 + +Now you need to implement the methods that provide data to oracle_ui. `oui_data` can be adapted from the `ui_data` proc that tgui uses. + +The `act` proc generates a hyperlink that will result in `oui_act` getting called on your object when clicked. The `class` argument defines a css class to be added to the hyperlink, and disabled determines whether the hyperlink will be disabled or not. + +Calling `soft_update_fields` will result in the UI being updated on all clients, which is useful when the object changes state. + +`code/modules/recycling/disposal-unit.dm` +```dm +/obj/machinery/disposal/bin/oui_data(mob/user) + var/list/data = list() + data["flush"] = flush ? ui.act("Disengage", user, "handle-0", class="active") : ui.act("Engage", user, "handle-1") + data["full_pressure"] = full_pressure ? "Ready" : (pressure_charging ? "Pressurizing" : "Off") + data["pressure_charging"] = pressure_charging ? ui.act("Turn Off", user, "pump-0", class="active", disabled=full_pressure) : ui.act("Turn On", user, "pump-1", disabled=full_pressure) + var/per = full_pressure ? 100 : Clamp(100* air_contents.return_pressure() / (SEND_PRESSURE), 0, 99) + data["per"] = "[round(per, 1)]%" + data["contents"] = ui.act("Eject Contents", user, "eject", disabled=contents.len < 1) + data["isai"] = isAI(user) + return data +/obj/machinery/disposal/bin/oui_act(mob/user, action, list/params) + if(..()) + return + switch(action) + if("handle-0") + flush = FALSE + update_icon() + . = TRUE + if("handle-1") + if(!panel_open) + flush = TRUE + update_icon() + . = TRUE + if("pump-0") + if(pressure_charging) + pressure_charging = FALSE + update_icon() + . = TRUE + if("pump-1") + if(!pressure_charging) + pressure_charging = TRUE + update_icon() + . = TRUE + if("eject") + eject() + . = TRUE + ui.soft_update_fields() +``` + +#### Step 4 + +You now need to hook in and ensure oracle_ui is invoked upon clicking. `render` should be used to open the UI for a user, typically on click. + +`code/modules/recycling/disposal-unit.dm` +```dm +/obj/machinery/disposal/bin/ui_interact(mob/user, state) + if(stat & BROKEN) + return + if(user.loc == src) + to_chat(user, "You cannot reach the controls from inside!") + return + ui.render(user) +``` + +#### Done + +![gif](https://user-images.githubusercontent.com/202160/37561879-1bb9179e-2a52-11e8-902c-80e6e6df7204.gif) + +You should have a functional UI at this point. Some additional odds and ends can be discovered throughout `code/modules/recycling/disposal-unit.dm`. For a full diff of the changes made to it, refer to [the original pull request on GitHub](https://github.com/OracleStation/OracleStation/pull/702/files#diff-4b6c20ec7d37222630e7524d9577e230). + +### API Reference + +#### `/datum/oracle_ui` + +The main datum which handles the UI. + +##### `get_content(mob/target)` +Returns the HTML that should be displayed for a specified target mob. Calls `oui_getcontent` on the datasource to get the return value. *This proc is not used in the themed subclass.* + +##### `can_view(mob/target)` +Returns whether the specified target mob can view the UI. Calls `oui_canview` on the datasource to get the return value. + +##### `test_viewer(mob/target, updating)` +Tests whether the client is valid and can view the UI. If updating is TRUE, checks to see if they still have the UI window open. + +##### `render(mob/target, updating = FALSE)` +Opens the UI for a target mob, sending HTML. If updating is TRUE, will only do it to clients which still have the window open. + +##### `render_all()` +Does the above, but for all viewers and with updating set to TRUE. + +##### `close(mob/target)` +Closes the UI for the specified target mob. + +##### `close_all()` +Does the above, but for all viewers. + +##### `check_view(mob/target)` +Checks if the specified target mob can view the UI, and if they can't closes their UI + +##### `check_view_all()` +Does the above, but for all viewers. + +##### `call_js(mob/target, js_func, list/parameters = list())` +Invokes `js_func` in the UI of the specified target mob with the specified parameters. + +##### `call_js_all(js_func, list/parameters = list()))` +Does the above, but for all viewers. + +##### `steal_focus(mob/target)` +Causes the UI to steal focus for the specified target mob. + +##### `steal_focus_all()` +Does the above, but for all viewers. + +##### `flash(mob/target, times = -1)` +Causes the UI to flash for the specified target mob the specified number of times, the default keeps the element flashing until focused. + +##### `flash_all()` +Does the above, but for all viewers. + +##### `href(mob/user, action, list/parameters = list())` +Generates a href for the specified user which will invoke `oui_act` on the datasource with the specified action and parameters. + +#### `/datum/oracle_ui/themed` + +A subclass which supports templating and theming. + +##### `get_file(path)` +Loads a file from disk and returns the contents. Caches files loaded from disk for you. + +##### `get_content_file(filename)` +Loads a file from the current content folder and returns the contents. + +##### `get_themed_file(filename)` +Loads a file from the current theme folder and returns the contents. + +##### `process_template(template, variables)` +Processes a template and populates it with the provided variables. + +##### `get_inner_content(mob/target)` +Returns the templated content to be inserted into the main template for the specified target mob. + +##### `soft_update_fields()` +For all viewers, updates the fields in the template via the `updateFields` javaScript function. + +##### `soft_update_all()` +For all viewers, updates the content body in the template via the `replaceContent` javaScript function. + +##### `change_page(var/newpage)` +Changes the template to use to draw the page and forces an update to all viewers + +##### `act(label, mob/user, action, list/parameters = list(), class = "", disabled = FALSE` +Returns a fully formatted hyperlink for the specified user. `label` will be the hyperlink label, `action` and `parameters` are what will be passed to `oui_act`, `class` is any CSS classes to apply to the hyperlink and `disabled` will disable the hyperlink. + +#### `/datum` + +Functions built into all objects to support oracle_ui. There are default implementations for most major superclasses. + +##### `oui_canview(mob/user)` +Returns whether the specified user view the UI at this time. + +##### `oui_getcontent(mob/user)` +Returns the raw HTML to be sent to the specified user. *This proc is not used in the themed subclass of oracle_ui.* + +##### `oui_data(mob/user)` +Returns templating data for the specified user. *This proc is only used in the themed subclass of oracle_ui.* + +##### `oui_data_debug(mob/user)` +Returns the above, but JSON-encoded and escaped, for copy pasting into the web IDE. *This proc is only used for debugging purposes.* + +##### `oui_act(mob/user, action, list/params)` +Called when a hyperlink is clicked in the UI. diff --git a/modular_kepler/code/modules/oracle_ui/assets.dm b/modular_kepler/code/modules/oracle_ui/assets.dm new file mode 100644 index 0000000000..e68fce38a7 --- /dev/null +++ b/modular_kepler/code/modules/oracle_ui/assets.dm @@ -0,0 +1,9 @@ +/datum/asset/simple/oui_theme_nano + assets = list( + // JavaScript + "sui-nano-common.js" = 'modular_kepler/html/oracle_ui/themes/nano/sui-nano-common.js', + "sui-nano-jquery.min.js" = 'modular_kepler/html/oracle_ui/themes/nano/sui-nano-jquery.min.js', + // Stylesheets + "sui-nano-common.css" = 'modular_kepler/html/oracle_ui/themes/nano/sui-nano-common.css', + ) + \ No newline at end of file diff --git a/modular_kepler/code/modules/oracle_ui/hookup_procs.dm b/modular_kepler/code/modules/oracle_ui/hookup_procs.dm new file mode 100644 index 0000000000..e6038744c1 --- /dev/null +++ b/modular_kepler/code/modules/oracle_ui/hookup_procs.dm @@ -0,0 +1,44 @@ +/datum/proc/oui_canview(mob/user) + return TRUE + +/datum/proc/oui_getcontent(mob/user) + return "Default Implementation" + +/datum/proc/oui_canuse(mob/user) + if(isobserver(user) && !user.has_unlimited_silicon_privilege) + return FALSE + return oui_canview(user) + +/datum/proc/oui_data(mob/user) + return list() + +/datum/proc/oui_data_debug(mob/user) + return html_encode(json_encode(oui_data(user))) + +/datum/proc/oui_act(mob/user, action, list/params) + // No Implementation + +/atom/oui_canview(mob/user) + if(isobserver(user)) + return TRUE + if(user.incapacitated()) + return FALSE + if(isturf(src.loc) && Adjacent(user)) + return TRUE + return FALSE + +/obj/item/oui_canview(mob/user) + if(src.loc == user) + return src in user.held_items + return ..() + +/obj/machinery/oui_canview(mob/user) + if(user.has_unlimited_silicon_privilege) + return TRUE + if(!can_interact()) + return FALSE + if(iscyborg(user)) + return can_see(user, src, 7) + if(isAI(user)) + return GLOB.cameranet.checkTurfVis(get_turf_pixel(src)) + return ..() diff --git a/modular_kepler/code/modules/oracle_ui/oracle_ui.dm b/modular_kepler/code/modules/oracle_ui/oracle_ui.dm new file mode 100644 index 0000000000..5e8d6b9c7b --- /dev/null +++ b/modular_kepler/code/modules/oracle_ui/oracle_ui.dm @@ -0,0 +1,134 @@ +/datum/oracle_ui + var/width = 512 + var/height = 512 + var/can_close = TRUE + var/can_minimize = FALSE + var/can_resize = TRUE + var/titlebar = TRUE + var/window_id = null + var/viewers[0] + var/auto_check_view = TRUE + var/auto_refresh = FALSE + var/atom/datasource = null + var/datum/asset/assets = null + +/datum/oracle_ui/New(atom/n_datasource, n_width = 512, n_height = 512, n_assets = null) + datasource = n_datasource + window_id = REF(src) + width = n_width + height = n_height + +/datum/oracle_ui/Destroy() + close_all() + if(src.datum_flags & DF_ISPROCESSING) + STOP_PROCESSING(SSobj, src) + return ..() + +/datum/oracle_ui/process() + if(auto_check_view) + check_view_all() + if(auto_refresh) + render_all() + +/datum/oracle_ui/proc/get_content(mob/target) + return call(datasource, "oui_getcontent")(target) + +/datum/oracle_ui/proc/can_view(mob/target) + return call(datasource, "oui_canview")(target) + +/datum/oracle_ui/proc/test_viewer(mob/target, updating) + //If the target is null or does not have a client, remove from viewers and return + if(!target | !target.client | !can_view(target)) + viewers -= target + if(viewers.len < 1 && (src.datum_flags & DF_ISPROCESSING)) + STOP_PROCESSING(SSobj, src) //No more viewers, stop polling + close(target) + return FALSE + //If this is an update, and they have closed the window, remove from viewers and return + if(updating && winget(target, window_id, "is-visible") != "true") + viewers -= target + if(viewers.len < 1 && (src.datum_flags & DF_ISPROCESSING)) + STOP_PROCESSING(SSobj, src) //No more viewers, stop polling + return FALSE + return TRUE + +/datum/oracle_ui/proc/render(mob/target, updating = FALSE) + set waitfor = FALSE //Makes this an async call + if(!can_view(target)) + return + //Check to see if they have the window open still if updating + if(updating && !test_viewer(target, updating)) + return + //Send assets + if(!updating && assets) + assets.send(target) + //Add them to the viewers if they aren't there already + viewers |= target + if(!(src.datum_flags & DF_ISPROCESSING) && (auto_refresh | auto_check_view)) + START_PROCESSING(SSobj, src) //Start processing to poll for viewability + //Send the content + if(updating) + target << output(get_content(target), "[window_id].browser") + else + target << browse(get_content(target), "window=[window_id];size=[width]x[height];can_close=[can_close];can_minimize=[can_minimize];can_resize=[can_resize];titlebar=[titlebar];focus=false;") + steal_focus(target) + +/datum/oracle_ui/proc/render_all() + for(var/viewer in viewers) + render(viewer, TRUE) + +/datum/oracle_ui/proc/close(mob/target) + if(target && target.client) + target << browse(null, "window=[window_id]") + +/datum/oracle_ui/proc/close_all() + for(var/viewer in viewers) + close(viewer) + viewers = list() + +/datum/oracle_ui/proc/check_view_all() + for(var/viewer in viewers) + check_view(viewer) + +/datum/oracle_ui/proc/check_view(mob/target) + set waitfor = FALSE //Makes this an async call + if(!test_viewer(target, TRUE)) + close(target) + +/datum/oracle_ui/proc/call_js(mob/target, js_func, list/parameters = list()) + set waitfor = FALSE //Makes this an async call + if(!test_viewer(target, TRUE)) + return + target << output(list2params(parameters),"[window_id].browser:[js_func]") + +/datum/oracle_ui/proc/call_js_all(js_func, list/parameters = list()) + for(var/viewer in viewers) + call_js(viewer, js_func, parameters) + +/datum/oracle_ui/proc/steal_focus(mob/target) + set waitfor = FALSE //Makes this an async call + winset(target, "[window_id]","focus=true") + +/datum/oracle_ui/proc/steal_focus_all() + for(var/viewer in viewers) + steal_focus(viewer) + +/datum/oracle_ui/proc/flash(mob/target, times = -1) + set waitfor = FALSE //Makes this an async call + winset(target, "[window_id]","flash=[times]") + +/datum/oracle_ui/proc/flash_all(times = -1) + for(var/viewer in viewers) + flash(viewer, times) + +/datum/oracle_ui/proc/href(mob/user, action, list/parameters = list()) + var/params_string = replacetext(list2params(parameters),"&",";") + return "?src=[REF(src)];sui_action=[action];sui_user=[REF(user)];[params_string]" + +/datum/oracle_ui/Topic(href, parameters) + var/action = parameters["sui_action"] + var/mob/current_user = locate(parameters["sui_user"]) + if(!call(datasource, "oui_canuse")(current_user)) + return + if(datasource) + call(datasource, "oui_act")(current_user, action, parameters); diff --git a/modular_kepler/code/modules/oracle_ui/themed.dm b/modular_kepler/code/modules/oracle_ui/themed.dm new file mode 100644 index 0000000000..9bf31bd1da --- /dev/null +++ b/modular_kepler/code/modules/oracle_ui/themed.dm @@ -0,0 +1,82 @@ +/datum/oracle_ui/themed + var/theme = "" + var/content_root = "" + var/current_page = "index.html" + var/root_template = "" + +/datum/oracle_ui/themed/New(atom/n_datasource, n_width = 512, n_height = 512, n_content_root = "") + root_template = get_themed_file("index.html") + content_root = n_content_root + return ..(n_datasource, n_width, n_height, get_asset_datum(/datum/asset/simple/oui_theme_nano)) + +/datum/oracle_ui/themed/process() + if(auto_check_view) + check_view_all() + if(auto_refresh) + soft_update_fields() + +GLOBAL_LIST_EMPTY(oui_template_variables) +GLOBAL_LIST_EMPTY(oui_file_cache) + +/datum/oracle_ui/themed/proc/get_file(path) + if(GLOB.oui_file_cache[path]) + return GLOB.oui_file_cache[path] + else if(fexists(path)) + var/data = file2text(path) + GLOB.oui_file_cache[path] = data + return data + else + var/errormsg = "MISSING PATH '[path]'" +#ifndef UNIT_TESTS + log_world(errormsg) //Because Travis absolutely hates these procs +#endif + return errormsg + +/datum/oracle_ui/themed/proc/get_content_file(filename) + return get_file("./modular_kepler/html/oracle_ui/content/[content_root]/[filename]") + +/datum/oracle_ui/themed/proc/get_themed_file(filename) + return get_file("./modular_kepler/html/oracle_ui/themes/[theme]/[filename]") + +/datum/oracle_ui/themed/proc/process_template(template, variables) + var/regex/pattern = regex("\\@\\{(\\w+)\\}","gi") + GLOB.oui_template_variables = variables + var/replaced = pattern.Replace(template, /proc/oui_process_template_replace) + GLOB.oui_template_variables = null + return replaced + +/proc/oui_process_template_replace(match, group1) + var/value = GLOB.oui_template_variables[group1] + return "[value]" + +/datum/oracle_ui/themed/proc/get_inner_content(mob/target) + var/list/data = call(datasource, "oui_data")(target) + return process_template(get_content_file(current_page), data) + +/datum/oracle_ui/themed/get_content(mob/target) + var/list/template_data = list("title" = datasource.name, "body" = get_inner_content(target)) + return process_template(root_template, template_data) + +/datum/oracle_ui/themed/proc/soft_update_fields() + for(var/viewer in viewers) + var/json = json_encode(call(datasource, "oui_data")(viewer)) + call_js(viewer, "updateFields", list(json)) + +/datum/oracle_ui/themed/proc/soft_update_all() + for(var/viewer in viewers) + call_js(viewer, "replaceContent", list(get_inner_content(viewer))) + +/datum/oracle_ui/themed/proc/change_page(newpage) + if(newpage == current_page) + return + current_page = newpage + render_all() + +/datum/oracle_ui/themed/proc/act(label, mob/user, action, list/parameters = list(), class = "", disabled = FALSE) + if(disabled) + return "[label]" + else + return "[label]" + +/datum/oracle_ui/themed/nano + theme = "nano" diff --git a/modular_kepler/html/oracle_ui/content/disposal_bin/index.html b/modular_kepler/html/oracle_ui/content/disposal_bin/index.html new file mode 100644 index 0000000000..8f7713b53c --- /dev/null +++ b/modular_kepler/html/oracle_ui/content/disposal_bin/index.html @@ -0,0 +1,27 @@ +
+
+ State: +
@{full_pressure}
+
+
+ Pressure: +
+
+
+
@{per}
+
+
+
+
+ Handle: +
@{flush}
+
+
+ Eject: +
@{contents}
+
+
+ Compressor: +
@{pressure_charging}
+
+
\ No newline at end of file diff --git a/modular_kepler/html/oracle_ui/editor_tool.html b/modular_kepler/html/oracle_ui/editor_tool.html new file mode 100644 index 0000000000..e0ce75bb29 --- /dev/null +++ b/modular_kepler/html/oracle_ui/editor_tool.html @@ -0,0 +1,103 @@ + + + + + + OracleUI IDE + + + +
+

Content Template:

+ +
+
+

Data:

+ +
+
+

Output:

+ +
+ + + diff --git a/modular_kepler/html/oracle_ui/themes/nano/index.html b/modular_kepler/html/oracle_ui/themes/nano/index.html new file mode 100644 index 0000000000..388f6e4ce4 --- /dev/null +++ b/modular_kepler/html/oracle_ui/themes/nano/index.html @@ -0,0 +1,19 @@ + + + + + + @{title} + + + + + +
+
@{title}
+
+ @{body} +
+
+ + diff --git a/modular_kepler/html/oracle_ui/themes/nano/sui-nano-common.css b/modular_kepler/html/oracle_ui/themes/nano/sui-nano-common.css new file mode 100644 index 0000000000..481b81c3e3 --- /dev/null +++ b/modular_kepler/html/oracle_ui/themes/nano/sui-nano-common.css @@ -0,0 +1,353 @@ +body +{ + padding: 0; + margin: 0; + background-color: #272727; + font-size: 12px; + color: #ffffff; + line-height: 170%; + cursor: default; + -moz-user-select: none; + -ms-user-select: none; +} + +hr +{ + background-color: #40628a; + height: 1px; +} + +a, a:link, a:visited, a:active, .linkOn, .linkOff +{ + color: #ffffff; + text-decoration: none; + background: #40628a; + border: 1px solid #161616; + padding: 1px 4px 1px 4px; + margin: 0 2px 0 0; + cursor:default; +} + +a:hover +{ + color: #40628a; + background: #ffffff; +} + +a.white, a.white:link, a.white:visited, a.white:active +{ + color: #40628a; + text-decoration: none; + background: #ffffff; + border: 1px solid #161616; + padding: 1px 4px 1px 4px; + margin: 0 2px 0 0; + cursor:default; +} + +a.white:hover +{ + color: #ffffff; + background: #40628a; +} + +.active, a.active:link, a.active:visited, a.active:active, a.active:hover +{ + color: #ffffff; + background: #2f943c; + border-color: #24722e; +} + +.disabled, a.disabled:link, a.disabled:visited, a.disabled:active, a.disabled:hover +{ + color: #ffffff; + background: #999999; + border-color: #666666; +} + +a.icon, .linkOn.icon, .linkOff.icon +{ + position: relative; + padding: 1px 4px 2px 20px; +} + +a.icon img, .linkOn.icon img +{ + position: absolute; + top: 0; + left: 0; + width: 18px; + height: 18px; +} + +ul +{ + padding: 4px 0 0 10px; + margin: 0; + list-style-type: none; +} + +li +{ + padding: 0 0 2px 0; +} + +img, a img +{ + border-style:none; +} + +h1, h2, h3, h4, h5, h6 +{ + margin: 0; + padding: 16px 0 8px 0; + color: #517087; +} + +h1 +{ + font-size: 15px; +} + +h2 +{ + font-size: 14px; +} + +h3 +{ + font-size: 13px; +} + +h4 +{ + font-size: 12px; +} + +.uiWrapper +{ + + width: 100%; + height: 100%; +} + +.uiTitle +{ + clear: both; + padding: 6px 8px 6px 8px; + border-bottom: 2px solid #161616; + background: #383838; + color: #98B0C3; + font-size: 16px; +} + +.uiTitle.icon +{ + padding: 6px 8px 6px 42px; + background-position: 2px 50%; + background-repeat: no-repeat; +} + +.uiContent +{ + clear: both; + padding: 8px; + font-family: Verdana, Geneva, sans-serif; +} + +.good +{ + color: #00ff00; +} + +.average +{ + color: #d09000; +} + +.bad +{ + color: #ff0000; +} + +.highlight +{ + color: #8BA5C4; +} + +.dark +{ + color: #272727; +} + +.notice +{ + position: relative; + background: #E9C183; + color: #15345A; + font-size: 10px; + font-style: italic; + padding: 2px 4px 0 4px; + margin: 4px; +} + +.notice.icon +{ + padding: 2px 4px 0 20px; +} + +.notice img +{ + position: absolute; + top: 0; + left: 0; + width: 16px; + height: 16px; +} + +div.notice +{ + clear: both; +} + +.statusDisplay +{ + background: #000000; + color: #ffffff; + border: 1px solid #40628a; + padding: 4px; + margin: 3px 0; +} + +.statusLabel +{ + width: 138px; + float: left; + overflow: hidden; + color: #98B0C3; +} + +.statusValue +{ + float: left; +} + +.block +{ + padding: 8px; + margin: 10px 4px 4px 4px; + border: 1px solid #40628a; + background-color: #202020; +} + +.block h3 +{ + padding: 0; +} + +.progressBar +{ + position: relative; + width: 185px; + height: 14px; + border: 1px solid #666666; + float: left; + overflow: hidden; + padding: 1px; +} + +.progressLabel +{ + top: -2px; + height: 100%; + position: absolute; + right: 4px; + text-align: right; +} + +.progressFill +{ + width: 100%; + height: 100%; + background: #40628a; + overflow: hidden; + transition: width 2.2s linear; +} + +.progressFill.good +{ + color: #ffffff; + background: #00ff00; +} + +.progressFill.average +{ + color: #ffffff; + background: #d09000; +} + +.progressFill.bad +{ + color: #ffffff; + background: #ff0000; +} + +.progressFill.highlight +{ + color: #ffffff; + background: #8BA5C4; +} + +.clearBoth +{ + clear: both; +} + +.clearLeft +{ + clear: left; +} + +.clearRight +{ + clear: right; +} + +.line +{ + width: 100%; + clear: both; +} + +section .label, section .content +{ + display: table-cell; + margin: 0; + text-align: left; + vertical-align: middle; + padding: 3px 2px +} + +section .label +{ + width: 1%; + padding-right: 32px; + white-space: nowrap; + color: #8ba5c4; +} + +section +{ + display: table-row; + width: 100% +} + +.display { + width: calc(100% - 8px); + padding: 4px; + background-color: #000; + background-color: rgba(0, 0, 0, .33); + box-shadow: inset 0 0 5px rgba(0, 0, 0, .5); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr=#54000000,endColorStr=#54000000)"; + filter: progid: DXImageTransform.Microsoft.gradient(startColorStr=#54000000, endColorStr=#54000000); +} \ No newline at end of file diff --git a/modular_kepler/html/oracle_ui/themes/nano/sui-nano-common.js b/modular_kepler/html/oracle_ui/themes/nano/sui-nano-common.js new file mode 100644 index 0000000000..716891a53f --- /dev/null +++ b/modular_kepler/html/oracle_ui/themes/nano/sui-nano-common.js @@ -0,0 +1,47 @@ +function replaceContent(body) { + var maincontent = document.getElementById('maincontent'); + if(maincontent) { + maincontent.innerHTML = body; + } +} + +function updateProgressLabels() { + var progressBars = document.getElementsByClassName("progressBar"); + for(var i = 0; i < progressBars.length; i++) { + var progressBar = progressBars[i]; + if(!progressBar) + continue; + var progressFill = progressBar.getElementsByClassName("progressFill")[0]; + if(!progressFill) + continue; + var width = parseInt(getComputedStyle(progressFill).width); + var maxWidth = parseInt(getComputedStyle(progressBar).width); + var progressLabel = progressBar.getElementsByClassName("progressLabel")[0]; + if(progressLabel) + progressLabel.innerHTML = Math.round((width / maxWidth) * 100) + '%'; + } +} + +if(getComputedStyle) { setInterval(updateProgressLabels, 50); } //Fallback + +function updateFields(json) { + var fields = JSON.parse(json); + for (var key in fields) { + let value = fields[key]; + var element = document.getElementById(key); + if(element == null) { + continue; + } else if(element.classList.contains('progressBar')) { + var progressFill = element.getElementsByClassName("progressFill")[0]; + if(progressFill) + progressFill.style["width"] = value; + if(!getComputedStyle) { //Fallback + var progressLabel = element.getElementsByClassName("progressLabel")[0]; + if(progressLabel) + progressLabel.innerHTML = value; + } + } else { + element.innerHTML = value; + } + } +} \ No newline at end of file diff --git a/modular_kepler/html/oracle_ui/themes/nano/sui-nano-jquery.min.js b/modular_kepler/html/oracle_ui/themes/nano/sui-nano-jquery.min.js new file mode 100644 index 0000000000..645c5adc18 --- /dev/null +++ b/modular_kepler/html/oracle_ui/themes/nano/sui-nano-jquery.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.11.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.1",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="
",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h; + if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="
a",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/

x1^}5BkKl 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 C29T%# From 3b2be43bd870a55a545f97435efc849576ae8e03 Mon Sep 17 00:00:00 2001 From: Tupinambis Date: Tue, 27 Aug 2019 18:35:08 -0500 Subject: [PATCH 059/222] Slightly increased rubbershot damage from 12.5 to 15 per pellet. --- code/modules/projectiles/projectile/bullets/shotgun.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/projectiles/projectile/bullets/shotgun.dm b/code/modules/projectiles/projectile/bullets/shotgun.dm index 3555cd3b75..4a1c954b1b 100644 --- a/code/modules/projectiles/projectile/bullets/shotgun.dm +++ b/code/modules/projectiles/projectile/bullets/shotgun.dm @@ -66,7 +66,7 @@ /obj/item/projectile/bullet/pellet/shotgun_rubbershot name = "rubbershot pellet" damage = 2 - stamina = 12.5 + stamina = 15 /obj/item/projectile/bullet/pellet/Range() ..() From 124d8503dc9892acfe8223b21c5501c4f7f187f1 Mon Sep 17 00:00:00 2001 From: Fermi Date: Thu, 29 Aug 2019 00:12:16 +0100 Subject: [PATCH 060/222] Tests and fixes. --- .../food_and_drinks/recipes/drinks_recipes.dm | 8 ++- .../chemistry/machinery/chem_master.dm | 4 +- code/modules/reagents/chemistry/reagents.dm | 58 +++++++++++++++++-- .../chemistry/reagents/alcohol_reagents.dm | 11 +++- .../chemistry/reagents/drink_reagents.dm | 3 + .../chemistry/reagents/fermi_reagents.dm | 47 +-------------- .../reagents/chemistry/recipes/fermi.dm | 4 +- 7 files changed, 77 insertions(+), 58 deletions(-) diff --git a/code/modules/food_and_drinks/recipes/drinks_recipes.dm b/code/modules/food_and_drinks/recipes/drinks_recipes.dm index b97b919e1e..af1b5337a1 100644 --- a/code/modules/food_and_drinks/recipes/drinks_recipes.dm +++ b/code/modules/food_and_drinks/recipes/drinks_recipes.dm @@ -385,8 +385,8 @@ OptimalTempMin = 200 // Lower area of bell curve for determining heat based rate reactions OptimalTempMax = 950 // Upper end for above ExplodeTemp = 999 //Temperature at which reaction explodes - OptimalpHMin = 2 // Lowest value of pH determining pH a 1 value for pH based rate reactions (Plateu phase) - OptimalpHMax = 2.8 // Higest value for above + OptimalpHMin = 3 // Lowest value of pH determining pH a 1 value for pH based rate reactions (Plateu phase) + OptimalpHMax = 3.6 // Higest value for above ReactpHLim = 5 // How far out pH wil react, giving impurity place (Exponential phase) CatalystFact = 0 // How much the catalyst affects the reaction (0 = no catalyst) CurveSharpT = 2 // How sharp the temperature exponential curve is (to the power of value) @@ -405,6 +405,10 @@ holder.remove_reagent(src.id, cached_volume) holder.add_reagent("neuroweak", cached_volume) +/datum/chemical_reaction/neurotoxin/FermiExplode(datum/reagents, var/atom/my_atom, volume, temp, pH)//reduced size + volume = volume/10 + ..() + /datum/chemical_reaction/snowwhite name = "Snow White" id = "snowwhite" diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm index 002c54be94..0a4b3b8f53 100644 --- a/code/modules/reagents/chemistry/machinery/chem_master.dm +++ b/code/modules/reagents/chemistry/machinery/chem_master.dm @@ -391,9 +391,9 @@ state = "Gas" var/const/P = 3 //The number of seconds between life ticks var/T = initial(R.metabolization_rate) * (60 / P) - if(istype(R, /datum/reagent/fermi)) + var/datum/chemical_reaction/Rcr = get_chemical_reaction(R.id) + if(Rcr && Rcr.FermiChem) fermianalyze = TRUE - var/datum/chemical_reaction/Rcr = get_chemical_reaction(R.id) var/pHpeakCache = (Rcr.OptimalpHMin + Rcr.OptimalpHMax)/2 analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold), "purityF" = initial(R.purity), "inverseRatioF" = initial(R.InverseChemVal), "purityE" = initial(Rcr.PurityMin), "minTemp" = initial(Rcr.OptimalTempMin), "maxTemp" = initial(Rcr.OptimalTempMax), "eTemp" = initial(Rcr.ExplodeTemp), "pHpeak" = pHpeakCache) else diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm index c21629ce8f..4a51f3e760 100644 --- a/code/modules/reagents/chemistry/reagents.dm +++ b/code/modules/reagents/chemistry/reagents.dm @@ -33,18 +33,21 @@ var/addiction_stage4_end = 40 var/overdosed = 0 // You fucked up and this is now triggering its overdose effects, purge that shit quick. var/self_consuming = FALSE + var/metabolizing = FALSE + var/invisible = FALSE //Set to true if it doesn't appear on handheld health analyzers. //Fermichem vars: + var/FermiChem = FALSE //If it's a fermichem var/purity = 1 //How pure a chemical is from 0 - 1. var/addProc = FALSE //If the chemical should force an on_new() call - var/turf/loc = null //Should be the creation location! + var/turf/loc = null //Should be the creation location! var/pH = 7 //pH of the specific reagent, used for calculating the sum pH of a holder. + var/SplitChem = FALSE //If the chem splits on metabolism var/ImpureChem = "fermiTox"// What chemical is metabolised with an inpure reaction var/InverseChemVal = 0.25 // If the impurity is below 0.5, replace ALL of the chem with InverseChem upon metabolising var/InverseChem = "fermiTox"// What chem is metabolised when purity is below InverseChemVal, this shouldn't be made, but if it does, well, I guess I'll know about it. var/DoNotSplit = FALSE // If impurity is handled within the main chem itself var/OnMobMergeCheck = FALSE //Call on_mob_life proc when reagents are merging. - var/metabolizing = FALSE - var/invisible = FALSE //Set to true if it doesn't appear on handheld health analyzers. + /datum/reagent/Destroy() // This should only be called by the holder, so it's already handled clearing its references . = ..() @@ -74,7 +77,27 @@ return // Called when this reagent is first added to a mob -/datum/reagent/proc/on_mob_add(mob/living/L) +/datum/reagent/proc/on_mob_add(mob/living/L, amount) + if(SplitChem) + var/mob/living/carbon/M = L + if(!M) + return + if(purity < 0) + CRASH("Purity below 0 for chem: [id], Please let Fermis Know!") + if (purity == 1 || DoNotSplit == TRUE) + log_game("FERMICHEM: [M] ckey: [M.key] has ingested [volume]u of [id]") + return + else if (InverseChemVal > purity)//Turns all of a added reagent into the inverse chem + M.reagents.remove_reagent(id, amount, FALSE) + M.reagents.add_reagent(InverseChem, amount, FALSE, other_purity = 1) + log_game("FERMICHEM: [M] ckey: [M.key] has ingested [volume]u of [InverseChem]") + return + else + var/impureVol = amount * (1 - purity) //turns impure ratio into impure chem + M.reagents.remove_reagent(id, (impureVol), FALSE) + M.reagents.add_reagent(ImpureChem, impureVol, FALSE, other_purity = 1) + log_game("FERMICHEM: [M] ckey: [M.key] has ingested [volume - impureVol]u of [id]") + log_game("FERMICHEM: [M] ckey: [M.key] has ingested [volume]u of [ImpureChem]") return // Called when this reagent is removed while inside a mob @@ -97,7 +120,32 @@ return // Called when two reagents of the same are mixing. -/datum/reagent/proc/on_merge(data) +/datum/reagent/proc/on_merge(data, amount, mob/living/carbon/M, purity) + if(SplitChem) + if(!ishuman(M)) + return + if (purity < 0) + CRASH("Purity below 0 for chem: [id], Please let Fermis Know!") + if (purity == 1 || DoNotSplit == TRUE) + log_game("FERMICHEM: [M] ckey: [M.key] has merged [volume]u of [id] in themselves") + return + else if (InverseChemVal > purity) + M.reagents.remove_reagent(id, amount, FALSE) + M.reagents.add_reagent(InverseChem, amount, FALSE, other_purity = 1) + for(var/datum/reagent/fermi/R in M.reagents.reagent_list) + if(R.name == "") + R.name = name//Negative effects are hidden + log_game("FERMICHEM: [M] ckey: [M.key] has merged [volume]u of [InverseChem]") + return + else + var/impureVol = amount * (1 - purity) + M.reagents.remove_reagent(id, impureVol, FALSE) + M.reagents.add_reagent(ImpureChem, impureVol, FALSE, other_purity = 1) + for(var/datum/reagent/fermi/R in M.reagents.reagent_list) + if(R.name == "") + R.name = name//Negative effects are hidden + log_game("FERMICHEM: [M] ckey: [M.key] has merged [volume - impureVol]u of [id]") + log_game("FERMICHEM: [M] ckey: [M.key] has merged [volume]u of [ImpureChem]") return /datum/reagent/proc/on_update(atom/A) diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm index 0817d04cb8..97f94d596d 100644 --- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm @@ -1383,6 +1383,7 @@ All effects don't start immediately, but rather get worse over time; the rate is glass_icon_state = "neurotoxinglass" glass_name = "Neurotoxin" glass_desc = "A drink that is guaranteed to knock you silly." + SplitChem = TRUE ImpureChem = "neuroweak" InverseChemVal = 0 //Clear conversion InverseChem = "neuroweak" @@ -1422,14 +1423,18 @@ All effects don't start immediately, but rather get worse over time; the rate is ..() /datum/reagent/consumable/ethanol/neuroweak - name = "Neuroalcohol" + name = "Neuro-Smash" id = "neuroweak" - description = "A mostly safe alcoholic drink for the true daredevils. Do not mix with Neurotoxin." + description = "A mostly safe alcoholic drink for the true daredevils. Counteracts Neurotoxins." boozepwr = 60 /datum/reagent/consumable/ethanol/neuroweak/on_mob_life(mob/living/carbon/M) if(holder.has_reagent("neurotoxin")) - M.adjustBrainLoss(0.5*REM, 150) + M.adjustBrainLoss(-1*REM, 150) + M.reagents.remove_reagent("neurotoxin", 0.25, FALSE) + if(holder.has_reagent("fentanyl")) + M.adjustBrainLoss(-1*REM, 150) + M.reagents.remove_reagent("fentanyl", 0.25, FALSE) else M.adjustBrainLoss(-0.5*REM, 150) M.dizziness +=2 diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm index bfefc073f8..913a6b3ef7 100644 --- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm @@ -13,6 +13,7 @@ glass_icon_state = "glass_orange" glass_name = "glass of orange juice" glass_desc = "Vitamins! Yay!" + pH = 3.3 /datum/reagent/consumable/orangejuice/on_mob_life(mob/living/carbon/M) if(M.getOxyLoss() && prob(30)) @@ -45,6 +46,7 @@ glass_icon_state = "glass_green" glass_name = "glass of lime juice" glass_desc = "A glass of sweet-sour lime juice." + pH = 2.2 /datum/reagent/consumable/limejuice/on_mob_life(mob/living/carbon/M) if(M.getToxLoss() && prob(20)) @@ -125,6 +127,7 @@ glass_icon_state = "lemonglass" glass_name = "glass of lemon juice" glass_desc = "Sour..." + pH = 2 /datum/reagent/consumable/banana name = "Banana Juice" diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm index 275c244a83..d7122e85e3 100644 --- a/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm +++ b/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm @@ -6,58 +6,17 @@ id = "fermi" taste_description = "affection and love!" can_synth = FALSE + SplitChem = TRUE //This should process fermichems to find out how pure they are and what effect to do. /datum/reagent/fermi/on_mob_add(mob/living/carbon/M, amount) . = ..() - if(!M) - return - if(purity < 0) - CRASH("Purity below 0 for chem: [id], Please let Fermis Know!") - if (purity == 1 || DoNotSplit == TRUE) - log_game("FERMICHEM: [M] ckey: [M.key] has ingested [volume]u of [id]") - return - else if (InverseChemVal > purity)//Turns all of a added reagent into the inverse chem - M.reagents.remove_reagent(id, amount, FALSE) - M.reagents.add_reagent(InverseChem, amount, FALSE, other_purity = 1) - log_game("FERMICHEM: [M] ckey: [M.key] has ingested [volume]u of [InverseChem]") - return - else - var/impureVol = amount * (1 - purity) //turns impure ratio into impure chem - M.reagents.remove_reagent(id, (impureVol), FALSE) - M.reagents.add_reagent(ImpureChem, impureVol, FALSE, other_purity = 1) - log_game("FERMICHEM: [M] ckey: [M.key] has ingested [volume - impureVol]u of [id]") - log_game("FERMICHEM: [M] ckey: [M.key] has ingested [volume]u of [ImpureChem]") - return + //When merging two fermichems, see above /datum/reagent/fermi/on_merge(data, amount, mob/living/carbon/M, purity)//basically on_mob_add but for merging . = ..() - if(!ishuman(M)) - return - if (purity < 0) - CRASH("Purity below 0 for chem: [id], Please let Fermis Know!") - if (purity == 1 || DoNotSplit == TRUE) - log_game("FERMICHEM: [M] ckey: [M.key] has merged [volume]u of [id] in themselves") - return - else if (InverseChemVal > purity) - M.reagents.remove_reagent(id, amount, FALSE) - M.reagents.add_reagent(InverseChem, amount, FALSE, other_purity = 1) - for(var/datum/reagent/fermi/R in M.reagents.reagent_list) - if(R.name == "") - R.name = name//Negative effects are hidden - log_game("FERMICHEM: [M] ckey: [M.key] has merged [volume]u of [InverseChem]") - return - else - var/impureVol = amount * (1 - purity) - M.reagents.remove_reagent(id, impureVol, FALSE) - M.reagents.add_reagent(ImpureChem, impureVol, FALSE, other_purity = 1) - for(var/datum/reagent/fermi/R in M.reagents.reagent_list) - if(R.name == "") - R.name = name//Negative effects are hidden - log_game("FERMICHEM: [M] ckey: [M.key] has merged [volume - impureVol]u of [id]") - log_game("FERMICHEM: [M] ckey: [M.key] has merged [volume]u of [ImpureChem]") - return + //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm index bd327809eb..ef48ccb789 100644 --- a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm +++ b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm @@ -101,10 +101,10 @@ PurityMin = 0.4 //The minimum purity something has to be above, otherwise it explodes. /datum/chemical_reaction/fermi/eigenstate/FermiFinish(datum/reagents/holder, var/atom/my_atom)//Strange how this doesn't work but the other does. - if(!locate(/datum/reagent/fermi/eigenstate) in my_atom.reagents.reagent_list) + var/datum/reagent/fermi/eigenstate/E = locate(/datum/reagent/fermi/eigenstate) in my_atom.reagents.reagent_list + if(!E) return var/turf/open/location = get_turf(my_atom) - var/datum/reagent/fermi/eigenstate/E = locate(/datum/reagent/fermi/eigenstate) in my_atom.reagents.reagent_list if(location) E.location_created = location E.data.["location_created"] = location From 5b144ef1c6a8c610491bc6ff3028a79c06a864aa Mon Sep 17 00:00:00 2001 From: Fermi Date: Thu, 29 Aug 2019 00:13:24 +0100 Subject: [PATCH 061/222] Removed unused var --- code/modules/reagents/chemistry/reagents.dm | 1 - 1 file changed, 1 deletion(-) diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm index 4a51f3e760..520148848c 100644 --- a/code/modules/reagents/chemistry/reagents.dm +++ b/code/modules/reagents/chemistry/reagents.dm @@ -36,7 +36,6 @@ var/metabolizing = FALSE var/invisible = FALSE //Set to true if it doesn't appear on handheld health analyzers. //Fermichem vars: - var/FermiChem = FALSE //If it's a fermichem var/purity = 1 //How pure a chemical is from 0 - 1. var/addProc = FALSE //If the chemical should force an on_new() call var/turf/loc = null //Should be the creation location! From a5b8a56f9a92153413e95004c2a0ee49cfa8dda3 Mon Sep 17 00:00:00 2001 From: Fermi Date: Thu, 29 Aug 2019 00:32:05 +0100 Subject: [PATCH 062/222] Realised it was impossible. --- code/modules/food_and_drinks/recipes/drinks_recipes.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/food_and_drinks/recipes/drinks_recipes.dm b/code/modules/food_and_drinks/recipes/drinks_recipes.dm index af1b5337a1..c704c185a3 100644 --- a/code/modules/food_and_drinks/recipes/drinks_recipes.dm +++ b/code/modules/food_and_drinks/recipes/drinks_recipes.dm @@ -385,8 +385,8 @@ OptimalTempMin = 200 // Lower area of bell curve for determining heat based rate reactions OptimalTempMax = 950 // Upper end for above ExplodeTemp = 999 //Temperature at which reaction explodes - OptimalpHMin = 3 // Lowest value of pH determining pH a 1 value for pH based rate reactions (Plateu phase) - OptimalpHMax = 3.6 // Higest value for above + OptimalpHMin = 4.6 // Lowest value of pH determining pH a 1 value for pH based rate reactions (Plateu phase) + OptimalpHMax = 5.2 // Higest value for above ReactpHLim = 5 // How far out pH wil react, giving impurity place (Exponential phase) CatalystFact = 0 // How much the catalyst affects the reaction (0 = no catalyst) CurveSharpT = 2 // How sharp the temperature exponential curve is (to the power of value) From c1d9e3f03b456f3cbcaafbf11a382964bd9314bb Mon Sep 17 00:00:00 2001 From: Fermi Date: Thu, 29 Aug 2019 00:37:18 +0100 Subject: [PATCH 063/222] Failing is frustrating --- code/modules/reagents/chemistry/reagents/alcohol_reagents.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm index 97f94d596d..a58a328003 100644 --- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm @@ -1427,6 +1427,7 @@ All effects don't start immediately, but rather get worse over time; the rate is id = "neuroweak" description = "A mostly safe alcoholic drink for the true daredevils. Counteracts Neurotoxins." boozepwr = 60 + pH = 8 /datum/reagent/consumable/ethanol/neuroweak/on_mob_life(mob/living/carbon/M) if(holder.has_reagent("neurotoxin")) From 96aae12057109cbde4ce2ed81d086d89c15bac69 Mon Sep 17 00:00:00 2001 From: TrilbySpaceClone Date: Thu, 29 Aug 2019 21:19:16 -0400 Subject: [PATCH 064/222] readds --- icons/obj/hydroponics/seeds.dmi | Bin 22302 -> 22704 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/icons/obj/hydroponics/seeds.dmi b/icons/obj/hydroponics/seeds.dmi index 1cdb720dca490f167c133b8d48d09d57c0a90399..24363fccfe379b4cfa5cf19d5e825876509b84d2 100644 GIT binary patch delta 3138 zcmaKvc{J4R-^afUqcnrLZ6mw7Nh*YpJ%j9JUt(+_`ywCN=C!fSZu3~vA2)dnt0sw$> zFEj%H)~!Em93oKn!#%?ughV_D4g!E^VjiJANLU?~G_Ye0oAj^ot=FP=5v1Csl7I4Z zn&_K8mc9F?%xt=J7CRClI5lPyd}HnCH>08+bTGkk7u3@b2BwJN9v=yK8a)ury_W;e+$B2)zxfK2D2%>y{>F4~b z+Q^-^EVg-7CvWiV`4^(XJ9R zGR5>Q(Jt|ESZrt?7E%9r53cOFRV9a6IGY%3dr7aDR}*gWX0$af4F)NwX}^eDbrFKq zNu0Clq^fvP?X3xy^|SOcED(tl!H} zT?|p`R+^>6_Rr4@NNtQ!YIHi;Dq^=YM?)l_edh|jt}(EG_OjxE5oMt(ls8(k^Rt=C(HJM8&t8u0Jav1?!j@TT|-z3wR!V}A-_!J zBmJ_@DVmx47b8Q3sM2(gpI=XI@?DYZu#}@Q!cKUi8>Zvp$4?+!O0sV{etOK*2tv;5 zvht&Al=S^zV7%umHKtkuIC9N+qyTX7kTEyGo98~3OzR>i6r?-%rs0f7E)7}v67J|u zrIr};26h*jNDddlM^_DS5CZqD9Vgsz4 zn|E^PG;Zi2Qd|fVHO}3qB>f~4CW%~=X^p#v?uQM^3zB}768Ar~uEC*)J#YgBMVh{= zJE$!UjZKLrdB$7Zz_92D@VzAKIZO~^Eti+OcRKxCSkow}1}OQW1vj+3DogZD+oKiIf;oca;`nQ~y#Gl1j&1 z;Wr06ZE=8H8LMsa`goe$hJ4FxGSmlGH1hi9+eUB8C1gguHeH+p5|-qA?3$p-A)7Y_ zL;17vv~8r1&00Dq1Ymn}O@o=Feru~iM?#z+zM=H|*~t9@m1#*EG0ll{RN7#W`ZjuY z!z!F|{gsU>a?SImW+KiLVU{dYGzHM6HaG8j=N!GUan^a($c&0Dv2>;06W;4(`8j-;XZk zV|YZF+Q|#qzpKrFaa=3Qexs{Ufczlw5oNgg&+XucTu1$`u9%F9Asz>`KwJ|itf^7kLmeXqsiYE6MdX<&;Hskh)k{tJjHN4%)GQdi!zQ=Zwt-rKyY^WT`!E3j*#OL z)#Cj44gbzj0(1ol{~T+Jn1m>>;IIWP2HojK({t{LBapDg>1vsti;)QC5ZW1Kw zBVKIF@lHIgv|PTeNrr^s=_1AVcpV8^e~=oS-+j&aWl1+`-nJIn`9-F9eZdpK0Jr6g zhyy$^AV4K2bZ}8W@&0$qZ3qm#2+ z22dE2pw8O3u?3&waA%91c?8H^vHToZ@m4LN8>6a77v)H3j5O;SuCaLm)uZ>_lQ@E) zEqH`&XaAW+XYS*}N=)1YOhQ3F*|l*XM9RBXIJX&VZEAXV@(w2qpnk}EKs8pz&={(8zS$+N)iA*I&uvFdIeD47dB zWF`yPyvGb)i12xiWb0Ye8`$Tzivyzn_WI(fqX>Zj*{onO#2fHzrpUW$B^h_~#e24~ zKkmNk2>PsYJV3$bxF>ZWJb94{sff9AhbKvl06z8*`qG!)RcacNt(o5|u5%@=RM`Gq zUsqRVp$~W!C7UXcX}s$*Jd=O-uz3sy)b#&aW%SZ7!`36_OTIK0onGB56-LvUeZEI+ zlYwR6s&Ra7D4J3KWQ^nKR)lA$_FkI&0YAfXh%)$N)uy82EduYlPwA^ZIo95<*s<5w zI9|&1qM~;@pXX9f*5rf#CVgD0)5@ia$1LzqY^NPdGfmt~&WLkXulOwc`JM>vx6-vW zoi~gaq$EQWYEtRYi3f$sybM)9JkvvdLV+l#JHU$&ddy;m^5Xel^*I`Pc zMMCO2o6#rK|7ZT61cQ|XoG796^@lKlhJ18-lT)__|Dg>`s({Z6lu9Dchi%QP(Us67 zzIW%MH~w}M0d?wQ`gwlhk*KXQt4L`gajnh>+!Cmoedn)7 zZw|c>-_oe|uAc{?WpY~V_`~@mWl-)6Yk5V5`^kuW-LfEJNMD|D-xnhxA;NV*M+cpD zeCoY!!?9LX?*d5Rm>Kr$jghO=ax@CXtwjm{1d{R&s^)DagI=Yi{4n+B?5GRZ!4gt# z|88z!5XqPxP^G1$@O`h7NJ)Wp0Mb&|Q#OFe-5Qwhlt(+a}76#c7dSXJ7 zeWzt1ic5Tj&g*BT+}0pMPW@*fFH?FXU~W=UScL@qe?tC`DE!~*hR!gjQr5Il9N~0R O0E`VRP^4RKnEwJ+@b?J- delta 2733 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 nfCU19KqG_!3j_jzM*J7b Date: Fri, 30 Aug 2019 20:42:22 +0100 Subject: [PATCH 065/222] Heat plays a component now. --- .../code/modules/reagents/chemistry/recipes/fermi.dm | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm index 6625207a71..89ef2a329c 100644 --- a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm +++ b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm @@ -24,26 +24,32 @@ if (500 to 750) for(var/turf/turf in range(1,T)) new /obj/effect/hotspot(turf) + volume*=1.1 if (751 to 1100) for(var/turf/turf in range(2,T)) new /obj/effect/hotspot(turf) + volume*=1.2 if (1101 to 1500) //If you're crafty for(var/turf/turf in range(3,T)) new /obj/effect/hotspot(turf) + volume*=1.3 if (1501 to 2500) //requested for(var/turf/turf in range(4,T)) new /obj/effect/hotspot(turf) + volume*=1.4 if (2501 to 5000) for(var/turf/turf in range(5,T)) new /obj/effect/hotspot(turf) + volume*=1.5 if (5001 to INFINITY) for(var/turf/turf in range(6,T)) new /obj/effect/hotspot(turf) + volume*=1.6 message_admins("Fermi explosion at [T], with a temperature of [temp], pH of [pH], Impurity tot of [ImpureTot].") @@ -66,7 +72,7 @@ if (pH > 10) //if alkaline, small explosion. var/datum/effect_system/reagents_explosion/e = new() - e.set_up(round((volume/30)*(pH-9)), T, 0, 0) + e.set_up(round((volume/28)*(pH-9)), T, 0, 0) e.start() if(!ImpureTot == 0) //If impure, v.small emp (0.6 or less) From 85fc947dd78609ab641fbad1b47f55af9f6ee1ba Mon Sep 17 00:00:00 2001 From: Fermi Date: Fri, 30 Aug 2019 20:44:39 +0100 Subject: [PATCH 066/222] Allows furranium grown from organic sources. --- .../code/modules/reagents/chemistry/recipes/fermi.dm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm index 078e1c8a71..94bad98752 100644 --- a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm +++ b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm @@ -382,6 +382,9 @@ FermiChem = TRUE PurityMin = 0.3 +/datum/chemical_reaction/fermi/furranium/organic + required_reagents = list("aphro" = 0.1, "catnip" = 0.1, "silver" = 0.2, "salglu_solution" = 0.1) + //FOR INSTANT REACTIONS - DO NOT MULTIPLY LIMIT BY 10. //There's a weird rounding error or something ugh. From 58458a67409ee03f97904ce75f1c9f4e6fa86096 Mon Sep 17 00:00:00 2001 From: TrilbySpaceClone Date: Sat, 31 Aug 2019 21:12:27 -0400 Subject: [PATCH 067/222] the seeds --- icons/obj/hydroponics/harvest.dmi | Bin 51762 -> 52053 bytes icons/obj/hydroponics/seeds.dmi | Bin 22779 -> 22917 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/icons/obj/hydroponics/harvest.dmi b/icons/obj/hydroponics/harvest.dmi index fe126cadd8dfd2d06060e64c00e6c711249d5415..7796e1b1996c0c7fa23b7b38fadffcc42668b0f9 100644 GIT binary patch delta 18445 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 Date: Sat, 31 Aug 2019 21:16:14 -0400 Subject: [PATCH 068/222] huh --- code/modules/hydroponics/grown/tea_coffee.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/hydroponics/grown/tea_coffee.dm b/code/modules/hydroponics/grown/tea_coffee.dm index 8de7c9358f..06cbb1df0c 100644 --- a/code/modules/hydroponics/grown/tea_coffee.dm +++ b/code/modules/hydroponics/grown/tea_coffee.dm @@ -51,6 +51,7 @@ desc = "Long stocks with flowering tips that has a chemical to make feline attracted to it." species = "catnip" plantname = "Catnip Plant" + growthstages = 3 product = /obj/item/reagent_containers/food/snacks/grown/tea/catnip reagents_add = list("catnip" = 0.1, "vitamin" = 0.06, "teapowder" = 0.3) rarity = 50 From b474af1a66abeef7d43c019bf963bb32f1974749 Mon Sep 17 00:00:00 2001 From: EmeraldSundisk Date: Sun, 1 Sep 2019 09:58:22 -0700 Subject: [PATCH 069/222] Update DeltaStation2.dmm --- .../map_files/Deltastation/DeltaStation2.dmm | 32 ++++++------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index f02a4f4a31..cefc0eb1a5 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -114276,11 +114276,6 @@ /obj/structure/cable/white{ icon_state = "1-2" }, -/obj/machinery/door/airlock/maintenance_hatch{ - name = "Maintenance Hatch"; - req_access_txt = "12" - }, -/obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/simple/supply/hidden, /obj/effect/turf_decal/stripes/line{ dir = 2 @@ -114288,6 +114283,10 @@ /obj/effect/turf_decal/stripes/line{ dir = 1 }, +/obj/machinery/door/airlock/maintenance_hatch{ + name = "Chapel Maintenance"; + req_access_txt = "27" + }, /turf/open/floor/plasteel, /area/maintenance/port/aft) "dKE" = ( @@ -118987,7 +118986,6 @@ /obj/structure/cable/white{ icon_state = "1-2" }, -/obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/manifold4w/supply/hidden, /obj/effect/turf_decal/delivery, /turf/open/floor/plasteel, @@ -119332,7 +119330,6 @@ /turf/closed/wall, /area/chapel/office) "dTx" = ( -/obj/structure/bodycontainer/morgue, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -119343,6 +119340,7 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, +/obj/structure/closet/crate/coffin, /turf/open/floor/plasteel/dark, /area/chapel/office) "dTy" = ( @@ -121768,7 +121766,6 @@ /turf/open/floor/plating, /area/maintenance/port/aft) "dYv" = ( -/obj/structure/bodycontainer/morgue, /obj/structure/sign/poster/official/ian{ pixel_y = -32 }, @@ -121782,6 +121779,7 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, +/obj/structure/closet/crate/coffin, /turf/open/floor/plasteel/dark, /area/chapel/office) "dYw" = ( @@ -126476,6 +126474,7 @@ name = "Mass Driver" }, /obj/machinery/mass_driver{ + id = "chapelgun"; name = "Holy Driver" }, /turf/open/floor/plating, @@ -126706,7 +126705,7 @@ /area/science/mixing) "iyd" = ( /turf/open/space, -/area/space/nearstation) +/area/space) "iQh" = ( /obj/structure/bodycontainer/morgue{ dir = 1 @@ -126946,19 +126945,6 @@ }, /turf/open/floor/plasteel, /area/maintenance/port) -"kzR" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 2 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/obj/machinery/door/airlock/maintenance_hatch{ - name = "Chapel Maintenance"; - req_access_txt = "27" - }, -/turf/open/floor/plasteel, -/area/chapel/office) "kLu" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{ dir = 4 @@ -160100,7 +160086,7 @@ dYu dZg jhK jhK -kzR +dZN owr mXJ gJj From eee1ccbe2ca72dbdbe295f95ee2fad9afbdef4ae Mon Sep 17 00:00:00 2001 From: Alonefromhell Date: Tue, 27 Aug 2019 22:12:00 +0200 Subject: [PATCH 070/222] merge oracle ui from kepler --- code/controllers/subsystem/assets.dm | 12 +- code/modules/paperwork/paper.dm | 54 ++- code/modules/recycling/disposal/bin.dm | 50 ++- .../code/modules/oracle_ui/README.md | 233 ++++++++++++ .../code/modules/oracle_ui/assets.dm | 9 + .../code/modules/oracle_ui/hookup_procs.dm | 44 +++ .../code/modules/oracle_ui/oracle_ui.dm | 134 +++++++ .../code/modules/oracle_ui/themed.dm | 82 ++++ .../oracle_ui/content/disposal_bin/index.html | 27 ++ .../html/oracle_ui/editor_tool.html | 103 +++++ .../html/oracle_ui/themes/nano/index.html | 19 + .../oracle_ui/themes/nano/sui-nano-common.css | 353 ++++++++++++++++++ .../oracle_ui/themes/nano/sui-nano-common.js | 47 +++ .../themes/nano/sui-nano-jquery.min.js | 4 + tgstation.dme | 4 + 15 files changed, 1141 insertions(+), 34 deletions(-) create mode 100644 modular_kepler/code/modules/oracle_ui/README.md create mode 100644 modular_kepler/code/modules/oracle_ui/assets.dm create mode 100644 modular_kepler/code/modules/oracle_ui/hookup_procs.dm create mode 100644 modular_kepler/code/modules/oracle_ui/oracle_ui.dm create mode 100644 modular_kepler/code/modules/oracle_ui/themed.dm create mode 100644 modular_kepler/html/oracle_ui/content/disposal_bin/index.html create mode 100644 modular_kepler/html/oracle_ui/editor_tool.html create mode 100644 modular_kepler/html/oracle_ui/themes/nano/index.html create mode 100644 modular_kepler/html/oracle_ui/themes/nano/sui-nano-common.css create mode 100644 modular_kepler/html/oracle_ui/themes/nano/sui-nano-common.js create mode 100644 modular_kepler/html/oracle_ui/themes/nano/sui-nano-jquery.min.js diff --git a/code/controllers/subsystem/assets.dm b/code/controllers/subsystem/assets.dm index 7285298283..7b6554bd3f 100644 --- a/code/controllers/subsystem/assets.dm +++ b/code/controllers/subsystem/assets.dm @@ -6,7 +6,17 @@ SUBSYSTEM_DEF(assets) var/list/preload = list() /datum/controller/subsystem/assets/Initialize(timeofday) - for(var/type in typesof(/datum/asset)) + + var/list/priority_assets = list( + /datum/asset/simple/oui_theme_nano, + /datum/asset/simple/goonchat + ) + + for(var/type in priority_assets) + var/datum/asset/A = new type() + A.register() + + for(var/type in typesof(/datum/asset) - (priority_assets | list(/datum/asset, /datum/asset/simple))) var/datum/asset/A = type if (type != initial(A._abstract)) get_asset_datum(type) diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index 37877ffb09..a342b23c24 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -31,6 +31,7 @@ var/spam_flag = 0 var/contact_poison // Reagent ID to transfer on contact var/contact_poison_volume = 0 + var/datum/oracle_ui/ui = null /obj/item/paper/pickup(user) @@ -40,16 +41,40 @@ if(!istype(G) || G.transfer_prints) H.reagents.add_reagent(contact_poison,contact_poison_volume) contact_poison = null + ui.check_view_all() ..() +/obj/item/paper/dropped(mob/user) + ui.check_view(user) + return ..() + /obj/item/paper/Initialize() . = ..() pixel_y = rand(-8, 8) pixel_x = rand(-9, 9) + ui = new /datum/oracle_ui(src, 420, 600, get_asset_datum(/datum/asset/spritesheet/simple/paper)) + ui.can_resize = FALSE update_icon() updateinfolinks() +/obj/item/paper/oui_getcontent(mob/target) + if(!target.is_literate()) + return "[name][stars(info)]

","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:k.htmlSerialize?[0,"",""]:[1,"X
","
"]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?""!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m(" + + + + diff --git a/html/oracle_ui/themes/nano/index.html b/html/oracle_ui/themes/nano/index.html new file mode 100644 index 0000000000..388f6e4ce4 --- /dev/null +++ b/html/oracle_ui/themes/nano/index.html @@ -0,0 +1,19 @@ + + + + + + @{title} + + + + + +
+
@{title}
+
+ @{body} +
+
+ + diff --git a/html/oracle_ui/themes/nano/sui-nano-common.css b/html/oracle_ui/themes/nano/sui-nano-common.css new file mode 100644 index 0000000000..481b81c3e3 --- /dev/null +++ b/html/oracle_ui/themes/nano/sui-nano-common.css @@ -0,0 +1,353 @@ +body +{ + padding: 0; + margin: 0; + background-color: #272727; + font-size: 12px; + color: #ffffff; + line-height: 170%; + cursor: default; + -moz-user-select: none; + -ms-user-select: none; +} + +hr +{ + background-color: #40628a; + height: 1px; +} + +a, a:link, a:visited, a:active, .linkOn, .linkOff +{ + color: #ffffff; + text-decoration: none; + background: #40628a; + border: 1px solid #161616; + padding: 1px 4px 1px 4px; + margin: 0 2px 0 0; + cursor:default; +} + +a:hover +{ + color: #40628a; + background: #ffffff; +} + +a.white, a.white:link, a.white:visited, a.white:active +{ + color: #40628a; + text-decoration: none; + background: #ffffff; + border: 1px solid #161616; + padding: 1px 4px 1px 4px; + margin: 0 2px 0 0; + cursor:default; +} + +a.white:hover +{ + color: #ffffff; + background: #40628a; +} + +.active, a.active:link, a.active:visited, a.active:active, a.active:hover +{ + color: #ffffff; + background: #2f943c; + border-color: #24722e; +} + +.disabled, a.disabled:link, a.disabled:visited, a.disabled:active, a.disabled:hover +{ + color: #ffffff; + background: #999999; + border-color: #666666; +} + +a.icon, .linkOn.icon, .linkOff.icon +{ + position: relative; + padding: 1px 4px 2px 20px; +} + +a.icon img, .linkOn.icon img +{ + position: absolute; + top: 0; + left: 0; + width: 18px; + height: 18px; +} + +ul +{ + padding: 4px 0 0 10px; + margin: 0; + list-style-type: none; +} + +li +{ + padding: 0 0 2px 0; +} + +img, a img +{ + border-style:none; +} + +h1, h2, h3, h4, h5, h6 +{ + margin: 0; + padding: 16px 0 8px 0; + color: #517087; +} + +h1 +{ + font-size: 15px; +} + +h2 +{ + font-size: 14px; +} + +h3 +{ + font-size: 13px; +} + +h4 +{ + font-size: 12px; +} + +.uiWrapper +{ + + width: 100%; + height: 100%; +} + +.uiTitle +{ + clear: both; + padding: 6px 8px 6px 8px; + border-bottom: 2px solid #161616; + background: #383838; + color: #98B0C3; + font-size: 16px; +} + +.uiTitle.icon +{ + padding: 6px 8px 6px 42px; + background-position: 2px 50%; + background-repeat: no-repeat; +} + +.uiContent +{ + clear: both; + padding: 8px; + font-family: Verdana, Geneva, sans-serif; +} + +.good +{ + color: #00ff00; +} + +.average +{ + color: #d09000; +} + +.bad +{ + color: #ff0000; +} + +.highlight +{ + color: #8BA5C4; +} + +.dark +{ + color: #272727; +} + +.notice +{ + position: relative; + background: #E9C183; + color: #15345A; + font-size: 10px; + font-style: italic; + padding: 2px 4px 0 4px; + margin: 4px; +} + +.notice.icon +{ + padding: 2px 4px 0 20px; +} + +.notice img +{ + position: absolute; + top: 0; + left: 0; + width: 16px; + height: 16px; +} + +div.notice +{ + clear: both; +} + +.statusDisplay +{ + background: #000000; + color: #ffffff; + border: 1px solid #40628a; + padding: 4px; + margin: 3px 0; +} + +.statusLabel +{ + width: 138px; + float: left; + overflow: hidden; + color: #98B0C3; +} + +.statusValue +{ + float: left; +} + +.block +{ + padding: 8px; + margin: 10px 4px 4px 4px; + border: 1px solid #40628a; + background-color: #202020; +} + +.block h3 +{ + padding: 0; +} + +.progressBar +{ + position: relative; + width: 185px; + height: 14px; + border: 1px solid #666666; + float: left; + overflow: hidden; + padding: 1px; +} + +.progressLabel +{ + top: -2px; + height: 100%; + position: absolute; + right: 4px; + text-align: right; +} + +.progressFill +{ + width: 100%; + height: 100%; + background: #40628a; + overflow: hidden; + transition: width 2.2s linear; +} + +.progressFill.good +{ + color: #ffffff; + background: #00ff00; +} + +.progressFill.average +{ + color: #ffffff; + background: #d09000; +} + +.progressFill.bad +{ + color: #ffffff; + background: #ff0000; +} + +.progressFill.highlight +{ + color: #ffffff; + background: #8BA5C4; +} + +.clearBoth +{ + clear: both; +} + +.clearLeft +{ + clear: left; +} + +.clearRight +{ + clear: right; +} + +.line +{ + width: 100%; + clear: both; +} + +section .label, section .content +{ + display: table-cell; + margin: 0; + text-align: left; + vertical-align: middle; + padding: 3px 2px +} + +section .label +{ + width: 1%; + padding-right: 32px; + white-space: nowrap; + color: #8ba5c4; +} + +section +{ + display: table-row; + width: 100% +} + +.display { + width: calc(100% - 8px); + padding: 4px; + background-color: #000; + background-color: rgba(0, 0, 0, .33); + box-shadow: inset 0 0 5px rgba(0, 0, 0, .5); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr=#54000000,endColorStr=#54000000)"; + filter: progid: DXImageTransform.Microsoft.gradient(startColorStr=#54000000, endColorStr=#54000000); +} \ No newline at end of file diff --git a/html/oracle_ui/themes/nano/sui-nano-common.js b/html/oracle_ui/themes/nano/sui-nano-common.js new file mode 100644 index 0000000000..716891a53f --- /dev/null +++ b/html/oracle_ui/themes/nano/sui-nano-common.js @@ -0,0 +1,47 @@ +function replaceContent(body) { + var maincontent = document.getElementById('maincontent'); + if(maincontent) { + maincontent.innerHTML = body; + } +} + +function updateProgressLabels() { + var progressBars = document.getElementsByClassName("progressBar"); + for(var i = 0; i < progressBars.length; i++) { + var progressBar = progressBars[i]; + if(!progressBar) + continue; + var progressFill = progressBar.getElementsByClassName("progressFill")[0]; + if(!progressFill) + continue; + var width = parseInt(getComputedStyle(progressFill).width); + var maxWidth = parseInt(getComputedStyle(progressBar).width); + var progressLabel = progressBar.getElementsByClassName("progressLabel")[0]; + if(progressLabel) + progressLabel.innerHTML = Math.round((width / maxWidth) * 100) + '%'; + } +} + +if(getComputedStyle) { setInterval(updateProgressLabels, 50); } //Fallback + +function updateFields(json) { + var fields = JSON.parse(json); + for (var key in fields) { + let value = fields[key]; + var element = document.getElementById(key); + if(element == null) { + continue; + } else if(element.classList.contains('progressBar')) { + var progressFill = element.getElementsByClassName("progressFill")[0]; + if(progressFill) + progressFill.style["width"] = value; + if(!getComputedStyle) { //Fallback + var progressLabel = element.getElementsByClassName("progressLabel")[0]; + if(progressLabel) + progressLabel.innerHTML = value; + } + } else { + element.innerHTML = value; + } + } +} \ No newline at end of file diff --git a/html/oracle_ui/themes/nano/sui-nano-jquery.min.js b/html/oracle_ui/themes/nano/sui-nano-jquery.min.js new file mode 100644 index 0000000000..645c5adc18 --- /dev/null +++ b/html/oracle_ui/themes/nano/sui-nano-jquery.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.11.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.1",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="
",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h; + if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="
a",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/
","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:k.htmlSerialize?[0,"",""]:[1,"X
","
"]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?""!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m("