diff --git a/baystation12.dme b/baystation12.dme index 6bded644ac..24052903c4 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -231,6 +231,20 @@ #include "code\game\gamemodes\malfunction\malfunction.dm" #include "code\game\gamemodes\meteor\meteor.dm" #include "code\game\gamemodes\meteor\meteors.dm" +#include "code\game\gamemodes\mutiny\auth_key.dm" +#include "code\game\gamemodes\mutiny\directive.dm" +#include "code\game\gamemodes\mutiny\emergency_authentication_device.dm" +#include "code\game\gamemodes\mutiny\key_pinpointer.dm" +#include "code\game\gamemodes\mutiny\mutiny.dm" +#include "code\game\gamemodes\mutiny\mutiny_fluff.dm" +#include "code\game\gamemodes\mutiny\mutiny_hooks.dm" +#include "code\game\gamemodes\mutiny\directives\alien_fraud_directive.dm" +#include "code\game\gamemodes\mutiny\directives\bluespace_contagion_directive.dm" +#include "code\game\gamemodes\mutiny\directives\financial_crisis_directive.dm" +#include "code\game\gamemodes\mutiny\directives\ipc_virus_directive.dm" +#include "code\game\gamemodes\mutiny\directives\research_to_ripleys_directive.dm" +#include "code\game\gamemodes\mutiny\directives\tau_ceti_needs_women_directive.dm" +#include "code\game\gamemodes\mutiny\directives\terminations_directive.dm" #include "code\game\gamemodes\ninja\ninja.dm" #include "code\game\gamemodes\nuclear\nuclear.dm" #include "code\game\gamemodes\nuclear\nuclearbomb.dm" diff --git a/code/__HELPERS/time.dm b/code/__HELPERS/time.dm index 51f56d9d12..bcd52b9e88 100644 --- a/code/__HELPERS/time.dm +++ b/code/__HELPERS/time.dm @@ -1,3 +1,9 @@ +#define SECOND *10 +#define SECONDS *10 + +#define MINUTE *600 +#define MINUTES *600 + //Returns the world time in english proc/worldtime2text(time = world.time) return "[round(time / 36000)+12]:[(time / 600 % 60) < 10 ? add_zero(time / 600 % 60, 1) : time / 600 % 60]" diff --git a/code/controllers/hooks-defs.dm b/code/controllers/hooks-defs.dm index cb51229c9f..1cd7c4aad8 100644 --- a/code/controllers/hooks-defs.dm +++ b/code/controllers/hooks-defs.dm @@ -15,3 +15,73 @@ * Called in gameticker.dm when a round ends. */ /hook/roundend + +/** + * Death hook. + * Called in death.dm when someone dies. + * Parameters: var/mob/living/carbon/human, var/gibbed + */ +/hook/death + +/** + * Cloning hook. + * Called in cloning.dm when someone is brought back by the wonders of modern science. + * Parameters: var/mob/living/carbon/human + */ +/hook/clone + +/** + * Debrained hook. + * Called in brain_item.dm when someone gets debrained. + * Parameters: var/obj/item/brain + */ +/hook/debrain + +/** + * Borged hook. + * Called in robot_parts.dm when someone gets turned into a cyborg. + * Parameters: var/mob/living/silicon/robot + */ +/hook/borgify + +/** + * Podman hook. + * Called in podmen.dm when someone is brought back as a Diona. + * Parameters: var/mob/living/carbon/monkey/diona + */ +/hook/harvest_podman + +/** + * Payroll revoked hook. + * Called in Accounts_DB.dm when someone's payroll is stolen at the Accounts terminal. + * Parameters: var/datum/money_account + */ +/hook/revoke_payroll + +/** + * Account suspension hook. + * Called in Accounts_DB.dm when someone's account is suspended or unsuspended at the Accounts terminal. + * Parameters: var/datum/money_account + */ +/hook/change_account_status + +/** + * Employee reassignment hook. + * Called in card.dm when someone's card is reassigned at the HoP's desk. + * Parameters: var/obj/item/weapon/card/id + */ +/hook/reassign_employee + +/** + * Employee terminated hook. + * Called in card.dm when someone's card is terminated at the HoP's desk. + * Parameters: var/obj/item/weapon/card/id + */ +/hook/terminate_employee + +/** + * Crate sold hook. + * Called in supplyshuttle.dm when a crate is sold on the shuttle. + * Parameters: var/obj/structure/closet/crate/sold, var/area/shuttle + */ +/hook/sell_crate diff --git a/code/controllers/hooks.dm b/code/controllers/hooks.dm index 5045da7592..48f1199ef7 100644 --- a/code/controllers/hooks.dm +++ b/code/controllers/hooks.dm @@ -23,7 +23,7 @@ * @param hook Identifier of the hook to call. * @returns 1 if all hooked code runs successfully, 0 otherwise. */ -/proc/callHook(hook) +/proc/callHook(hook, list/args=null) var/hook_path = text2path("/hook/[hook]") if(!hook_path) error("Invalid hook '/hook/[hook]' called.") @@ -32,7 +32,7 @@ var/caller = new hook_path var/status = 1 for(var/P in typesof("[hook_path]/proc")) - if(!call(caller, P)()) + if(!call(caller, P)(arglist(args))) error("Hook '[P]' failed or runtimed.") status = 0 diff --git a/code/controllers/shuttle_controller.dm b/code/controllers/shuttle_controller.dm index f92d8b1c7b..ac804dc4f2 100644 --- a/code/controllers/shuttle_controller.dm +++ b/code/controllers/shuttle_controller.dm @@ -36,7 +36,7 @@ datum/shuttle_controller if(direction == -1) setdirection(1) else - settimeleft(SHUTTLEARRIVETIME*coeff) + settimeleft(get_shuttle_arrive_time()*coeff) online = 1 if(always_fake_recall) fake_recall = rand(300,500) //turning on the red lights in hallways @@ -45,10 +45,16 @@ datum/shuttle_controller if(istype(A, /area/hallway)) A.readyalert() + proc/get_shuttle_arrive_time() + // During mutiny rounds, the shuttle takes twice as long. + if(ticker && istype(ticker.mode,/datum/game_mode/mutiny)) + return SHUTTLEARRIVETIME * 2 + + return SHUTTLEARRIVETIME + datum/shuttle_controller/proc/shuttlealert(var/X) alert = X - datum/shuttle_controller/proc/recall() if(direction == 1) var/timeleft = timeleft() @@ -78,9 +84,9 @@ datum/shuttle_controller/proc/timeleft() if(direction == 1 || direction == 2) return timeleft else - return SHUTTLEARRIVETIME-timeleft + return get_shuttle_arrive_time()-timeleft else - return SHUTTLEARRIVETIME + return get_shuttle_arrive_time() // sets the time left to a given delay (in seconds) datum/shuttle_controller/proc/settimeleft(var/delay) @@ -95,7 +101,7 @@ datum/shuttle_controller/proc/setdirection(var/dirn) direction = dirn // if changing direction, flip the timeleft by SHUTTLEARRIVETIME var/ticksleft = endtime - world.timeofday - endtime = world.timeofday + (SHUTTLEARRIVETIME*10 - ticksleft) + endtime = world.timeofday + (get_shuttle_arrive_time()*10 - ticksleft) return datum/shuttle_controller/proc/process() diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index fe252c3ab3..e97c915c0b 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -28,6 +28,7 @@ var/required_enemies = 0 var/recommended_enemies = 0 var/newscaster_announcements = null + var/ert_disabled = 0 var/uplink_welcome = "Syndicate Uplink Console:" var/uplink_uses = 10 var/uplink_items = {"Highly Visible and Dangerous Weapons; @@ -407,6 +408,9 @@ Implants; heads += player.mind return heads +/datum/game_mode/proc/check_antagonists_topic(href, href_list[]) + return 0 + /datum/game_mode/New() newscaster_announcements = pick(newscaster_standard_feeds) diff --git a/code/game/gamemodes/mutiny/auth_key.dm b/code/game/gamemodes/mutiny/auth_key.dm new file mode 100644 index 0000000000..f053d7c3a3 --- /dev/null +++ b/code/game/gamemodes/mutiny/auth_key.dm @@ -0,0 +1,39 @@ +/obj/item/weapon/mutiny/auth_key + name = "authentication key" + desc = "Better keep this safe." + icon = 'icons/obj/items.dmi' + icon_state = "nucleardisk" + item_state = "card-id" + w_class = 1 + + var/time_entered_space + var/obj/item/device/radio/radio + + New() + radio = new(src) + spawn(20 SECONDS) + keep_alive() + ..() + + proc/keep_alive() + var/in_space = istype(loc, /turf/space) + if (!in_space && time_entered_space) + // Recovered before the key was lost + time_entered_space = null + else if (in_space && !time_entered_space) + // The key has left the station + time_entered_space = world.time + else if (in_space && time_entered_space + (10 SECONDS) < world.time) + // Time is up + radio.autosay("This device has left the station's perimeter. Triggering emergency activation failsafe.", name) + del(src) + return + + spawn(10 SECONDS) + keep_alive() + +/obj/item/weapon/mutiny/auth_key/captain + name = "Captain's Authentication Key" + +/obj/item/weapon/mutiny/auth_key/secondary + name = "Emergency Secondary Authentication Key" diff --git a/code/game/gamemodes/mutiny/directive.dm b/code/game/gamemodes/mutiny/directive.dm new file mode 100644 index 0000000000..823645beef --- /dev/null +++ b/code/game/gamemodes/mutiny/directive.dm @@ -0,0 +1,29 @@ +datum/directive + var/datum/game_mode/mutiny/mode + var/list/special_orders + + New(var/datum/game_mode/mutiny/M) + mode = M + + proc/get_description() + return {" +
+ NanoTrasen's reasons for the following directives are classified. +
+ "} + + proc/meets_prerequisites() + return 0 + + proc/directives_complete() + return 1 + + proc/initialize() + return 1 + +/proc/get_directive(type) + var/datum/game_mode/mutiny/mode = get_mutiny_mode() + if(!mode || !mode.current_directive || !istype(mode.current_directive, text2path("/datum/directive/[type]"))) + return null + + return mode.current_directive diff --git a/code/game/gamemodes/mutiny/directives/alien_fraud_directive.dm b/code/game/gamemodes/mutiny/directives/alien_fraud_directive.dm new file mode 100644 index 0000000000..5c76326ad3 --- /dev/null +++ b/code/game/gamemodes/mutiny/directives/alien_fraud_directive.dm @@ -0,0 +1,36 @@ +datum/directive/terminations/alien_fraud + special_orders = list( + "Suspend financial accounts of all Tajaran and Unathi personnel.", + "Transfer their payrolls to the station account.", + "Terminate their employment.") + +datum/directive/terminations/alien_fraud/get_crew_to_terminate() + var/list/aliens[0] + for(var/mob/living/carbon/human/H in player_list) + if (H.species.name == "Tajaran" || H.species.name == "Unathi") + aliens.Add(H) + return aliens + +datum/directive/terminations/alien_fraud/get_description() + return {" ++ An extensive conspiracy network aimed at defrauding NanoTrasen of large amounts of funds has been uncovered + operating within Tau Ceti. Human personnel are not suspected to be involved. Further information is classified. +
+ "} + +datum/directive/terminations/alien_fraud/meets_prerequisites() + // There must be at least one Tajaran and at least one Unathi, but the total + // of the Tajarans and Unathi combined can't be more than 1/3rd of the crew. + var/tajarans = 0 + var/unathi = 0 + for(var/mob/living/carbon/human/H in player_list) + if (H.species.name == "Tajaran") + tajarans++ + if (H.species.name == "Unathi") + unathi++ + + if (!tajarans || !unathi) + return 0 + + return (tajarans + unathi) <= (player_list.len / 3) diff --git a/code/game/gamemodes/mutiny/directives/bluespace_contagion_directive.dm b/code/game/gamemodes/mutiny/directives/bluespace_contagion_directive.dm new file mode 100644 index 0000000000..65058e8015 --- /dev/null +++ b/code/game/gamemodes/mutiny/directives/bluespace_contagion_directive.dm @@ -0,0 +1,45 @@ +#define INFECTION_COUNT 5 + +datum/directive/bluespace_contagion + var/infection_count = 5 + var/list/infected = list() + +datum/directive/bluespace_contagion/get_description() + return {" ++ A manufactured and near-undetectable virus is spreading on NanoTrasen stations. + The pathogen travels by bluespace after maturing for one day. + No treatment has yet been discovered. Personnel onboard [station_name()] have been infected. Further information is classified. +
+ "} + +datum/directive/bluespace_contagion/initialize() + var/list/candidates = player_list.Copy() + var/list/infected_names = list() + for(var/i=0, i < INFECTION_COUNT, i++) + if(!candidates.len) + break + + var/mob/living/carbon/human/candidate = pick(candidates) + candidates.Remove(candidate) + infected.Add(candidate) + infected_names.Add("[candidate.mind.assigned_role] [candidate.mind.name]") + + special_orders = list( + "Quarantine these personnel: [list2text(infected_names, ", ")].", + "Allow one hour for a cure to be manufactured.", + "If no cure arrives after that time, execute the infected.") + +datum/directive/bluespace_contagion/meets_prerequisites() + return player_list.len >= 7 + +datum/directive/bluespace_contagion/directives_complete() + return infected.len == 0 + +/hook/death/proc/infected_killed(mob/living/carbon/human/deceased, gibbed) + var/datum/directive/bluespace_contagion/D = get_directive("bluespace_contagion") + if(!D) return 1 + + if(deceased in D.infected) + D.infected.Remove(deceased) + return 1 diff --git a/code/game/gamemodes/mutiny/directives/financial_crisis_directive.dm b/code/game/gamemodes/mutiny/directives/financial_crisis_directive.dm new file mode 100644 index 0000000000..a6c4ce2896 --- /dev/null +++ b/code/game/gamemodes/mutiny/directives/financial_crisis_directive.dm @@ -0,0 +1,26 @@ +datum/directive/terminations/financial_crisis + special_orders = list( + "Suspend financial accounts of all civilian personnel, excluding the Head of Personnel.", + "Transfer their payrolls to the station account.", + "Terminate their employment.") + +datum/directive/terminations/financial_crisis/get_crew_to_terminate() + var/list/civilians[0] + var/list/candidates = civilian_positions - "Head of Personnel" + for(var/mob/living/carbon/human/H in player_list) + if (candidates.Find(H.mind.assigned_role)) + civilians.Add(H) + return civilians + +datum/directive/terminations/financial_crisis/get_description() + return {" ++ Tau Ceti system banks in financial crisis. Local emergency situation ongoing. + NT Funds redistributed, impact upon civilian department expected. + Further information is classified. +
+ "} + +datum/directive/terminations/financial_crisis/meets_prerequisites() + var/list/civilians = get_crew_to_terminate() + return civilians.len >= 5 diff --git a/code/game/gamemodes/mutiny/directives/ipc_virus_directive.dm b/code/game/gamemodes/mutiny/directives/ipc_virus_directive.dm new file mode 100644 index 0000000000..0889012829 --- /dev/null +++ b/code/game/gamemodes/mutiny/directives/ipc_virus_directive.dm @@ -0,0 +1,83 @@ +datum/directive/ipc_virus + special_orders = list( + "Terminate employment of all IPC personnel.", + "Extract the Positronic Brains from IPC units.", + "Mount the Positronic Brains into Cyborgs.") + + var/list/roboticist_roles = list( + "Research Director", + "Roboticist" + ) + + var/list/brains_to_enslave = list() + var/list/cyborgs_to_make = list() + var/list/ids_to_terminate = list() + + proc/get_ipcs() + var/list/machines[0] + for(var/mob/living/carbon/human/H in player_list) + if (H.species.name == "Machine") + machines.Add(H) + return machines + + proc/get_roboticists() + var/list/roboticists[0] + for(var/mob/living/carbon/human/H in player_list) + if (roboticist_roles.Find(H.mind.assigned_role)) + roboticists.Add(H) + return roboticists + +datum/directive/ipc_virus/initialize() + for(var/mob/living/carbon/human/H in get_ipcs()) + brains_to_enslave.Add(H.mind) + cyborgs_to_make.Add(H.mind) + ids_to_terminate.Add(H.wear_id) + +datum/directive/ipc_virus/get_description() + return {" ++ IPC units have been found to be infected with a violent and undesired virus in Virgus Ferrorus system. + Risk to NSS Exodus IPC units has not been assessed. Further information is classified. +
+ "} + +datum/directive/ipc_virus/meets_prerequisites() + var/list/ipcs = get_ipcs() + var/list/roboticists = get_roboticists() + return ipcs.len > 2 && roboticists.len > 1 + +datum/directive/ipc_virus/directives_complete() + return brains_to_enslave.len == 0 && cyborgs_to_make.len == 0 && ids_to_terminate.len == 0 + +/hook/debrain/proc/debrain_directive(obj/item/brain/B) + var/datum/directive/ipc_virus/D = get_directive("ipc_virus") + if (!D) return 1 + + if(D.brains_to_enslave.Find(B.brainmob.mind)) + D.brains_to_enslave.Remove(B.brainmob.mind) + + return 1 + +/hook/borgify/proc/borgify_directive(mob/living/silicon/robot/cyborg) + var/datum/directive/ipc_virus/D = get_directive("ipc_virus") + if (!D) return 1 + + if(D.cyborgs_to_make.Find(cyborg.mind)) + D.cyborgs_to_make.Remove(cyborg.mind) + + // In case something glitchy happened and the victim got + // borged without us tracking the brain removal, go ahead + // and update that list too. + if(D.brains_to_enslave.Find(cyborg.mind)) + D.brains_to_enslave.Remove(cyborg.mind) + + return 1 + +/hook/terminate_employee/proc/ipc_termination(obj/item/weapon/card/id) + var/datum/directive/ipc_virus/D = get_directive("ipc_virus") + if (!D) return 1 + + if(D.ids_to_terminate && D.ids_to_terminate.Find(id)) + D.ids_to_terminate.Remove(id) + + return 1 diff --git a/code/game/gamemodes/mutiny/directives/research_to_ripleys_directive.dm b/code/game/gamemodes/mutiny/directives/research_to_ripleys_directive.dm new file mode 100644 index 0000000000..a6305a2a56 --- /dev/null +++ b/code/game/gamemodes/mutiny/directives/research_to_ripleys_directive.dm @@ -0,0 +1,65 @@ +#define MATERIALS_REQUIRED 200 + +datum/directive/research_to_ripleys + var/list/ids_to_reassign = list() + var/materials_shipped = 0 + + proc/get_researchers() + var/list/researchers[0] + for(var/mob/living/carbon/human/H in player_list) + if (H.mind.assigned_role in science_positions - "Research Director") + researchers.Add(H) + return researchers + + proc/count_researchers_reassigned() + var/researchers_reassigned = 0 + for(var/obj/item/weapon/card/id in ids_to_reassign) + if (ids_to_reassign[id]) + researchers_reassigned++ + + return researchers_reassigned + +datum/directive/research_to_ripleys/get_description() + return {" ++ The NanoTrasen Tau Ceti Manufactory faces an ore deficit. Financial crisis imminent. [station_name()] has been reassigned as a mining platform. + The Research Director is to assist the Head of Personnel in coordinating assets. + Weapons department reports solid sales. Further information is classified. +
+ "} + +datum/directive/research_to_ripleys/meets_prerequisites() + var/list/researchers = get_researchers() + return researchers.len > 3 + +datum/directive/research_to_ripleys/initialize() + for(var/mob/living/carbon/human/R in get_researchers()) + ids_to_reassign[R.wear_id] = 0 + + special_orders = list( + "Reassign all research personnel, excluding the Research Director, to Shaft Miner.", + "Deliver [MATERIALS_REQUIRED] sheets of metal or minerals via the supply shuttle to CentCom.") + +datum/directive/research_to_ripleys/directives_complete() + if (materials_shipped < MATERIALS_REQUIRED) return 0 + return count_researchers_reassigned() == ids_to_reassign.len + +/hook/reassign_employee/proc/research_reassignments(obj/item/weapon/card/id/id_card) + var/datum/directive/research_to_ripleys/D = get_directive("research_to_ripleys") + if(!D) return 1 + + if(D.ids_to_reassign && D.ids_to_reassign.Find(id_card)) + D.ids_to_reassign[id_card] = id_card.assignment == "Shaft Miner" ? 1 : 0 + + return 1 + +/hook/sell_crate/proc/deliver_materials(obj/structure/closet/crate/sold, area/shuttle) + var/datum/directive/research_to_ripleys/D = get_directive("research_to_ripleys") + if(!D) return 1 + + for(var/atom/A in sold) + if(istype(A, /obj/item/stack/sheet/mineral) || istype(A, /obj/item/stack/sheet/metal)) + var/obj/item/stack/S = A + D.materials_shipped += S.amount + + return 1 diff --git a/code/game/gamemodes/mutiny/directives/tau_ceti_needs_women_directive.dm b/code/game/gamemodes/mutiny/directives/tau_ceti_needs_women_directive.dm new file mode 100644 index 0000000000..c9b86ecdf1 --- /dev/null +++ b/code/game/gamemodes/mutiny/directives/tau_ceti_needs_women_directive.dm @@ -0,0 +1,83 @@ +datum/directive/tau_ceti_needs_women + var/list/command_targets = list() + var/list/alien_targets = list() + + proc/get_target_gender() + if(!mode.head_loyalist) return FEMALE + return mode.head_loyalist.current.gender == FEMALE ? MALE : FEMALE + + proc/get_crew_of_target_gender() + var/list/targets[0] + for(var/mob/living/carbon/human/H in player_list) + if(H.species.name != "Machine" && H.gender == get_target_gender()) + targets.Add(H) + return targets + + proc/get_target_heads() + var/list/heads[0] + for(var/mob/living/carbon/human/H in get_crew_of_target_gender()) + if(command_positions.Find(H.mind.assigned_role)) + heads.Add(H) + return heads + + proc/get_target_aliens() + var/list/aliens[0] + for(var/mob/living/carbon/human/H in get_crew_of_target_gender()) + if (H.species.name == "Tajaran" || H.species.name == "Unathi" || H.species.name == "Skrell") + aliens.Add(H) + return aliens + + proc/count_heads_reassigned() + var/heads_reassigned = 0 + for(var/obj/item/weapon/card/id in command_targets) + if (command_targets[id]) + heads_reassigned++ + + return heads_reassigned + +datum/directive/tau_ceti_needs_women/get_description() + return {" ++ Recent evidence suggests [get_target_gender()] aptitudes may be effected by radiation from Tau Ceti. + Effects were measured under laboratory and station conditions. Humans remain more trusted than Xeno. Further information is classified. +
+ "} + +datum/directive/tau_ceti_needs_women/initialize() + for(var/mob/living/carbon/human/H in get_target_heads()) + command_targets[H.wear_id] = 0 + + for(var/mob/living/carbon/human/H in get_target_aliens()) + alien_targets.Add(H.wear_id) + + special_orders = list( + "Remove [get_target_gender()] personnel from Command positions.", + "Terminate employment of all [get_target_gender()] Skrell, Tajara, and Unathi.") + +datum/directive/tau_ceti_needs_women/meets_prerequisites() + var/list/targets = get_crew_of_target_gender() + return targets.len >= 3 + +datum/directive/tau_ceti_needs_women/directives_complete() + return command_targets.len == count_heads_reassigned() && alien_targets.len == 0 + +/hook/reassign_employee/proc/command_reassignments(obj/item/weapon/card/id/id_card) + var/datum/directive/tau_ceti_needs_women/D = get_directive("tau_ceti_needs_women") + if(!D) return 1 + + if(D.command_targets && D.command_targets.Find(id_card)) + D.command_targets[id_card] = command_positions.Find(id_card.assignment) ? 0 : 1 + + return 1 + +/hook/terminate_employee/proc/gender_target_termination_directive(obj/item/weapon/card/id) + var/datum/directive/tau_ceti_needs_women/D = get_directive("tau_ceti_needs_women") + if (!D) return 1 + + if(D.alien_targets && D.alien_targets.Find(id)) + D.alien_targets.Remove(id) + + if(D.command_targets && D.command_targets.Find(id)) + D.command_targets[id] = 1 + + return 1 diff --git a/code/game/gamemodes/mutiny/directives/terminations_directive.dm b/code/game/gamemodes/mutiny/directives/terminations_directive.dm new file mode 100644 index 0000000000..bc9f808d90 --- /dev/null +++ b/code/game/gamemodes/mutiny/directives/terminations_directive.dm @@ -0,0 +1,56 @@ +// This is a parent directive meant to be derived by directives that fit +// the "fire X type of employee" pattern of directives. Simply apply your +// flavor text and override get_crew_to_terminate in your child datum. +// See alien_fraud_directive.dm for an example. +datum/directive/terminations + var/list/accounts_to_revoke = list() + var/list/accounts_to_suspend = list() + var/list/ids_to_terminate = list() + + proc/get_crew_to_terminate() + return list() + +datum/directive/terminations/directives_complete() + for(var/account_number in accounts_to_suspend) + if (!accounts_to_suspend[account_number]) + return 0 + + for(var/account_number in accounts_to_revoke) + if (!accounts_to_revoke[account_number]) + return 0 + + return ids_to_terminate.len == 0 + +datum/directive/terminations/initialize() + for(var/mob/living/carbon/human/A in get_crew_to_terminate()) + var/datum/money_account/account = A.mind.initial_account + accounts_to_revoke["[account.account_number]"] = 0 + accounts_to_suspend["[account.account_number]"] = account.suspended + ids_to_terminate.Add(A.wear_id) + +/hook/revoke_payroll/proc/payroll_directive(datum/money_account/account) + var/datum/directive/terminations/D = get_directive("terminations") + if (!D) return 1 + + if(D.accounts_to_revoke && D.accounts_to_revoke.Find("[account.account_number]")) + D.accounts_to_revoke["[account.account_number]"] = 1 + + return 1 + +/hook/change_account_status/proc/suspension_directive(datum/money_account/account) + var/datum/directive/terminations/D = get_directive("terminations") + if (!D) return 1 + + if(D.accounts_to_suspend && D.accounts_to_suspend.Find("[account.account_number]")) + D.accounts_to_suspend["[account.account_number]"] = account.suspended + + return 1 + +/hook/terminate_employee/proc/termination_directive(obj/item/weapon/card/id) + var/datum/directive/terminations/D = get_directive("terminations") + if (!D) return 1 + + if(D.ids_to_terminate && D.ids_to_terminate.Find(id)) + D.ids_to_terminate.Remove(id) + + return 1 diff --git a/code/game/gamemodes/mutiny/directives/test_directive.dm b/code/game/gamemodes/mutiny/directives/test_directive.dm new file mode 100644 index 0000000000..74e990f41c --- /dev/null +++ b/code/game/gamemodes/mutiny/directives/test_directive.dm @@ -0,0 +1,23 @@ +// For testing +datum/directive/terminations/test + special_orders = list( + "Suspend financial accounts of all ugly personnel.", + "Transfer their payrolls to the station account.", + "Terminate their employment.") + +datum/directive/terminations/test/get_crew_to_terminate() + var/list/uglies[0] + for(var/mob/living/carbon/human/H in player_list) + uglies.Add(H) + return uglies + +datum/directive/terminations/test/get_description() + return {" ++ Wow. Much ugly. So painful. + Many terminations. Very classified. +
+ "} + +datum/directive/terminations/test/meets_prerequisites() + return 1 diff --git a/code/game/gamemodes/mutiny/emergency_authentication_device.dm b/code/game/gamemodes/mutiny/emergency_authentication_device.dm new file mode 100644 index 0000000000..8aee11e11f --- /dev/null +++ b/code/game/gamemodes/mutiny/emergency_authentication_device.dm @@ -0,0 +1,105 @@ +/obj/machinery/emergency_authentication_device + var/datum/game_mode/mutiny/mode + + name = "\improper Emergency Authentication Device" + icon = 'icons/obj/stationobjs.dmi' + icon_state = "blackbox" + density = 1 + anchored = 1 + + var/captains_key + var/secondary_key + var/activated = 0 + + flags = FPRINT + use_power = 0 + + New(loc, mode) + src.mode = mode + ..(loc) + + proc/check_key_existence() + if(!mode.captains_key) + captains_key = 1 + + if(!mode.secondary_key) + secondary_key = 1 + + proc/get_status() + if(activated) + return "Activated" + if(captains_key && secondary_key) + return "Both Keys Authenticated" + if(captains_key) + return "Captain's Key Authenticated" + if(secondary_key) + return "Secondary Key Authenticated" + else + return "Inactive" + +/obj/machinery/emergency_authentication_device/attack_hand(mob/user) + if(activated) + user << "\blue \The [src] is already active!" + return + + if(!mode.current_directive.directives_complete()) + state("Command aborted. Communication with CentComm is prohibited until Directive X has been completed.") + return + + check_key_existence() + if(captains_key && secondary_key) + activated = 1 + user << "\blue You activate \the [src]!" + state("Command acknowledged. Initiating quantum entanglement relay to NanoTrasen High Command.") + return + + if(!captains_key && !secondary_key) + state("Command aborted. Please present the authentication keys before proceeding.") + return + + if(!captains_key) + state("Command aborted. Please present the Captain's Authentication Key.") + return + + if(!secondary_key) + state("Command aborted. Please present the Emergency Secondary Authentication Key.") + return + + // Impossible! + state("Command aborted. This unit is defective.") + +/obj/machinery/emergency_authentication_device/attackby(obj/item/weapon/O, mob/user) + if(activated) + user << "\blue \The [src] is already active!" + return + + if(!mode.current_directive.directives_complete()) + state({"Command aborted. Communication with CentCom is prohibited until Directive X has been completed."}) + return + + check_key_existence() + if(istype(O, /obj/item/weapon/mutiny/auth_key/captain) && !captains_key) + captains_key = O + user.drop_item() + O.loc = src + + state("Key received. Thank you, Captain [mode.head_loyalist].") + spawn(5) + state(secondary_key ? "Your keys have been authenticated. Communication with CentCom is now authorized." : "Please insert the Emergency Secondary Authentication Key now.") + return + + if(istype(O, /obj/item/weapon/mutiny/auth_key/secondary) && !secondary_key) + secondary_key = O + user.drop_item() + O.loc = src + + state("Key received. Thank you, Secondary Authenticator [mode.head_mutineer].") + spawn(5) + state(captains_key ? "Your keys have been authenticated. Communication with CentCom is now authorized." : "Please insert the Captain's Authentication Key now.") + return + ..() + +/obj/machinery/emergency_authentication_device/examine() + usr << {" +This is a specialized communications device that is able to instantly send a message to NanoTrasen High Command via quantum entanglement with a sister device at CentCom. +The EAD's status is [get_status()]."} diff --git a/code/game/gamemodes/mutiny/key_pinpointer.dm b/code/game/gamemodes/mutiny/key_pinpointer.dm new file mode 100644 index 0000000000..d847f8b70b --- /dev/null +++ b/code/game/gamemodes/mutiny/key_pinpointer.dm @@ -0,0 +1,49 @@ +/obj/item/weapon/pinpointer/advpinpointer/auth_key + name = "\improper Authentication Key Pinpointer" + desc = "Tracks the positions of the emergency authentication keys." + var/datum/game_mode/mutiny/mutiny + + New() + mutiny = ticker.mode + ..() + +/obj/item/weapon/pinpointer/advpinpointer/auth_key/attack_self() + switch(mode) + if (0) + mode = 1 + active = 1 + target = mutiny.captains_key + workobj() + usr << "\blue You calibrate \the [src] to locate the Captain's Authentication Key." + if (1) + mode = 2 + target = mutiny.secondary_key + usr << "\blue You calibrate \the [src] to locate the Emergency Secondary Authentication Key." + else + mode = 0 + active = 0 + icon_state = "pinoff" + usr << "\blue You switch \the [src] off." + +/obj/item/weapon/pinpointer/advpinpointer/auth_key/examine() + switch(mode) + if (0) + usr << "Is is calibrated for the Captain's Authentication Key." + if (1) + usr << "It is calibrated for the Emergency Secondary Authentication Key." + else + usr << "It is switched off." + +/datum/supply_packs/key_pinpointer + name = "Authentication Key Pinpointer crate" + contains = list(/obj/item/weapon/pinpointer/advpinpointer/auth_key) + cost = 250 + containertype = /obj/structure/closet/crate + containername = "Authentication Key Pinpointer crate" + access = access_heads + group = "Operations" + + New() + // This crate is only accessible during mutiny rounds + if (istype(ticker.mode,/datum/game_mode/mutiny)) + ..() diff --git a/code/game/gamemodes/mutiny/mutiny.dm b/code/game/gamemodes/mutiny/mutiny.dm new file mode 100644 index 0000000000..acef3b1d08 --- /dev/null +++ b/code/game/gamemodes/mutiny/mutiny.dm @@ -0,0 +1,350 @@ +datum/game_mode/mutiny + var/datum/mutiny_fluff/fluff + var/datum/directive/current_directive + var/obj/item/weapon/mutiny/auth_key/captain/captains_key + var/obj/item/weapon/mutiny/auth_key/secondary/secondary_key + var/obj/machinery/emergency_authentication_device/ead + var/datum/mind/head_loyalist + var/datum/mind/head_mutineer + var/list/loyalists = list() + var/list/mutineers = list() + var/list/body_count = list() + + name = "mutiny" + config_tag = "mutiny" + required_players = 7 + ert_disabled = 1 + + uplink_welcome = "Mutineers Uplink Console:" + uplink_uses = 0 + + New() + fluff = new(src) + + proc/reveal_directives() + spawn(rand(1 MINUTE, 3 MINUTES)) + fluff.announce_incoming_fax() + spawn(rand(3 MINUTES, 5 MINUTES)) + send_pda_message() + spawn(rand(3 MINUTES, 5 MINUTES)) + fluff.announce_directives() + spawn(rand(2 MINUTES, 3 MINUTE)) + fluff.announce_ert_unavailable() + + // Returns an array in case we want to expand on this later. + proc/get_head_loyalist_candidates() + var/list/candidates[0] + for(var/mob/loyalist in player_list) + if(loyalist.mind.assigned_role == "Captain") + candidates.Add(loyalist.mind) + return candidates + + proc/get_head_mutineer_candidates() + var/list/candidates[0] + for(var/mob/mutineer in player_list) + if(mutineer.client.prefs.be_special & BE_MUTINEER) + for(var/job in command_positions - "Captain") + if(mutineer.mind.assigned_role == job) + candidates.Add(mutineer.mind) + return candidates + + proc/get_directive_candidates() + var/list/candidates[0] + for(var/T in typesof(/datum/directive) - /datum/directive) + var/datum/directive/D = new T(src) + if (D.meets_prerequisites()) + candidates.Add(D) + return candidates + + proc/send_pda_message() + var/obj/item/device/pda/pda = null + for(var/obj/item/device/pda/P in head_mutineer.current) + pda = P + break + + if (!pda) + return 0 + + if (!pda.silent) + playsound(pda.loc, 'sound/machines/twobeep.ogg', 50, 1) + for (var/mob/O in hearers(3, pda.loc)) + O.show_message(text("\icon[pda] *[pda.ttone]*")) + + head_mutineer.current << fluff.get_pda_body() + return 1 + + proc/get_equipment_slots() + return list( + "left pocket" = slot_l_store, + "right pocket" = slot_r_store, + "backpack" = slot_in_backpack, + "left hand" = slot_l_hand, + "right hand" = slot_r_hand) + + proc/equip_head_loyalist() + var/mob/living/carbon/human/H = head_loyalist.current + captains_key = new(H) + H.equip_in_one_of_slots(captains_key, get_equipment_slots()) + H.update_icons() + H.verbs += /mob/living/carbon/human/proc/recruit_loyalist + + proc/equip_head_mutineer() + var/mob/living/carbon/human/H = head_mutineer.current + secondary_key = new(H) + H.equip_in_one_of_slots(secondary_key, get_equipment_slots()) + H.update_icons() + H.verbs += /mob/living/carbon/human/proc/recruit_mutineer + + proc/add_loyalist(datum/mind/M) + loyalists.Add(M) + if (M in mutineers) + mutineers.Remove(M) + + M.current << fluff.loyalist_tag("You have joined the loyalists!") + head_loyalist.current << fluff.loyalist_tag("[M] has joined the loyalists!") + update_icon(M) + + proc/add_mutineer(datum/mind/M) + mutineers.Add(M) + if (M in loyalists) + loyalists.Remove(M) + + M.current << fluff.mutineer_tag("You have joined the mutineers!") + head_mutineer.current << fluff.mutineer_tag("[M] has joined the mutineers!") + update_icon(M) + + proc/was_bloodbath() + var/list/remaining_loyalists = loyalists - body_count + if (!remaining_loyalists.len) + return 1 + + var/list/remaining_mutineers = mutineers - body_count + if (!remaining_mutineers.len) + return 1 + + return 0 + + proc/replace_nuke_with_ead() + for(var/obj/machinery/nuclearbomb/N in world) + ead = new(N.loc, src) + del(N) + + proc/unbolt_vault_door() + var/obj/machinery/door/airlock/vault = locate(/obj/machinery/door/airlock/vault) + vault.locked = 0 + + proc/round_outcome() + world << "+ [current_directive.get_description()] +
+
+ TO: Captain [mode.head_loyalist], Commanding Officer, [station_name()]
+ FROM: NanoTrasen Emergency Messaging Relay
+ DATE: [time2text(world.realtime, "MM/DD")]/[game_year]
+ SUBJECT: Directive X
+
+ A member of your Command Staff is this shift's designated Emergency Secondary Authenticator.
+ This Emergency Secondary Authenticator is uniquely aware of their role and possesses the Emergency Secondary Authentication Key.
+ As Captain, you possess the Captain's Authentication Key.
+ The Emergency Authentication Device is located in the vault of your station, and requires simultaneous activation of the Authentication Keys.
+ An Authentication Key Pinpointer can be delivered via Cargo Bay to assist recovery of the Authentication Keys should they be lost aboard the station.
+ A key's destruction or removal from the station's perimeter will automatically and irreversibly activate the Emergency Authentication Device.
+
+ Captain [mode.head_loyalist], you are to immediately initiate the following procedure; codenamed Directive X: +
+\"You must read this! NanoTrasen Chain of Command COMPROMISED. Command Encryptions BROKEN. [station_name()] Captain [mode.head_loyalist] will receive orders that must NOT BE BROUGHT TO FRUITION! + +They don't care about us they only care about WEALTH and POWER... Share this message with people you trust. + +Be safe, friend.\" (Unable to Reply)
"} + + + proc/announce_ert_unavailable() + // I might have gotten a little carried away. + centcom_announce({" +The presence of [pick( + "political instability", + "quantum fluctuations", + "hostile raiders", + "derelict station debris", + "REDACTED", + "ancient alien artillery", + "solar magnetic storms", + "sentient time-travelling killbots", + "gravitational anomalies", + "wormholes to another dimension", + "a telescience mishap", + "radiation flares", + "supermatter dust", + "leaks into a negative reality", + "antiparticle clouds", + "residual bluespace energy", + "suspected syndicate operatives", + "malfunctioning von Neumann probe swarms", + "shadowy interlopers", + "a stranded Vox arkship", + "haywire IPC constructs", + "rogue Unathi exiles", + "artifacts of eldritch horror", + "a brain slug infestation", + "killer bugs that lay eggs in the husks of the living", + "a deserted transport carrying xenomorph specimens", + "an emissary for the gestalt requesting a security detail", + "a Tajaran slave rebellion", + "radical Skrellian transevolutionaries", + "classified security operations", + "science-defying raw elemental chaos")] +in the region is tying up all available local emergency resources; +emergency response teams can not be called at this time.
+ "}) + + proc/announce() + world << "The current game mode is - Mutiny!" + world << {" +The crew will be divided by their sense of ethics when a morally turbulent emergency directive arrives with an incomplete command validation code.
+The [loyalist_tag("Head Loyalist")] is the Captain, who carries the [loyalist_tag("Captain's Authentication Key")] at all times.
+The [mutineer_tag("Head Mutineer")] is a random Head of Staff who carries the [mutineer_tag("Emergency Secondary Authentication Key")].
+Loyalists - Follow the Head Loyalist in carrying out [loyalist_tag("NanoTrasen's directives")] then activate the EAD.
+Mutineers - Prevent the completion of the [mutineer_tag("improperly validated directives")] and the activation of the EAD.
+
NanoTrasen's image will forever be haunted by the fact that a mutiny took place on one of its own stations.
+ "} + + proc/loyalist_minor_victory() + return {" +NanoTrasen has praised the efforts of Captain [mode.head_loyalist] and loyal members of [their(mode.head_loyalist)] crew, who recently managed to put down a mutiny--amid a local interstellar crisis--aboard the [station_name()], a research station in Tau Ceti. +The mutiny was spurred by a top secret directive sent to the station, presumably in response to the crisis within the system. +Despite the mutiny, the crew was successful in implementing the directive. Unfortunately, they failed to notify Central Command of their successes due to a breach in the chain of command. +[mode.mutineers.len] members of the station's personnel were charged with sedition against the Company and if found guilty will be sentenced to life incarceration. +NanoTrasen will be awarding [mode.loyalists.len] members of the crew with the [loyalist_tag("Star of Loyalty")], following their mostly successful efforts, at a ceremony this coming Thursday. +[mode.body_count.len] are believed to have died during the coup. +NanoTrasen's image will forever be haunted by the fact that a mutiny took place on one of its own stations.
+ "} + + proc/no_victory() + return {" +NanoTrasen has been thrust into turmoil following an apparent mutiny by key personnel aboard the [station_name()], a research station in Tau Ceti. +The mutiny was spurred by a top secret directive sent to the station, presumably in response to the crisis within the system. +No further information has yet emerged from the station or its crew, who are presumed to be in holding with NanoTrasen investigators. +NanoTrasen officials refuse to comment. +Sources indicate that [mode.mutineers.len] members of the station's personnel are currently under investigation for mutiny, and [mode.loyalists.len] crew are currently providing evidence to investigators, believed to be the 'loyal' station personnel. +[mode.body_count.len] are believed to have died during the coup. +NanoTrasen's image will forever be haunted by the fact that a mutiny took place on one of its own stations.
+ "} + + proc/mutineer_minor_victory() + return {" +Reports have emerged that an impromptu mutiny has taken place, amid a local interstellar crisis, aboard the [station_name()], a research station in Tau Ceti. +The mutiny was spurred by a top secret directive sent to the station, presumably in response to the crisis within the system. +Information at present indicates that the top-secret directive--which has since been retracted--was invalid due to a broken authentication code. Members of the crew, including an unidentified Head of Staff, prevented the directive from being accomplished. +[mode.mutineers.len] members of the station's personnel were released from interrogations today, following a mutiny investigation. +NanoTrasen has reprimanded [mode.loyalists.len] members of the crew for failing to follow command validation procedures. +[mode.body_count.len] are believed to have died during the coup. +Even though the directive was not successfully implemented, NanoTrasen's image will forever be haunted by the fact that its authentication protocol was breached with such magnitude and that a mutiny was the result.
+ "} + + proc/mutineer_major_victory() + return {" +NanoTrasen has praised the efforts of [mode.head_mutineer.assigned_role] [mode.head_mutineer] and several other members of the crew, who recently seized control of a research station in Tau Ceti--[station_name()]--amid a local interstellar crisis. +What appears to have been a "legitimate" mutiny was spurred by a top secret directive sent to the station, presumably in response to the crisis within the system. +It has been revealed that the directive was invalid and fraudulent. Company officials have not released a statement about the source of the directive. +Thanks to the efforts of the resistant members of the crew, the directive was not carried out. +[mode.mutineers.len] members of the station's personnel were congratulated and awarded with the [mutineer_tag("Star of Bravery")], for their efforts in preventing the illegal directive's completion. +NanoTrasen has [mode.loyalists.len] members of the crew in holding, while it investigates the circumstances that led to the acceptance and initiation of an invalid directive. +[mode.body_count.len] are believed to have died during the coup. +Even though the directive was not successfully implemented, NanoTrasen's image will forever be haunted by the fact that its authentication protocol was breached with such magnitude and that a mutiny was the result.
+ "} diff --git a/code/game/gamemodes/mutiny/mutiny_hooks.dm b/code/game/gamemodes/mutiny/mutiny_hooks.dm new file mode 100644 index 0000000000..4edb763ac0 --- /dev/null +++ b/code/game/gamemodes/mutiny/mutiny_hooks.dm @@ -0,0 +1,27 @@ +/hook/death/proc/track_kills(mob/living/carbon/human/deceased, gibbed) + var/datum/game_mode/mutiny/mode = get_mutiny_mode() + if (!mode) return 1 + + mode.body_count.Add(deceased.mind) + return 1 + +/hook/clone/proc/update_icon(mob/living/carbon/human/H) + var/datum/game_mode/mutiny/mode = get_mutiny_mode() + if (!mode) return 1 + + mode.update_icon(H.mind) + return 1 + +/hook/harvest_podman/proc/update_icon(mob/living/carbon/monkey/diona/D) + var/datum/game_mode/mutiny/mode = get_mutiny_mode() + if (!mode) return 1 + + mode.update_icon(D.mind) + return 1 + +/hook/roundend/proc/report_mutiny_news() + var/datum/game_mode/mutiny/mode = get_mutiny_mode() + if (!mode) return 1 + + mode.round_outcome() + return 1 diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index 4361460980..853481b144 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -183,6 +183,7 @@ H << "Consciousness slowly creeps over you as your body regenerates.| Command | " - - jobs_all += "|||||||||||||
| Special | "//Captain in special because he is head of heads ~Intercross21 - jobs_all += "Captain | " - jobs_all += "Custom | " - - counter = 0 - jobs_all += "|||||||||||
| Engineering | "//Orange - for(var/job in engineering_positions) - counter++ - if(counter >= 6) - jobs_all += "|||||||||||||
| " - counter = 0 - jobs_all += " | [replacetext(job, " ", " ")] | " - - counter = 0 - jobs_all += "||||||||||||
| Medical | "//Green - for(var/job in medical_positions) - counter++ - if(counter >= 6) - jobs_all += "|||||||||||||
| " - counter = 0 - jobs_all += " | [replacetext(job, " ", " ")] | " - - counter = 0 - jobs_all += "||||||||||||
| Science | "//Purple - for(var/job in science_positions) - counter++ - if(counter >= 6) - jobs_all += "|||||||||||||
| " - counter = 0 - jobs_all += " | [replacetext(job, " ", " ")] | " - - counter = 0 - jobs_all += "||||||||||||
| Civilian | "//Grey - for(var/job in civilian_positions) - counter++ - if(counter >= 6) - jobs_all += "|||||||||||||
| " - counter = 0 - jobs_all += " | [replacetext(job, " ", " ")] | " - - if(istype(src,/obj/machinery/computer/card/centcom)) - counter = 0 - jobs_all += "||||||||||||
| CentComm | "//Brown - for(var/job in get_all_centcom_jobs()) - if(counter >= 6) - jobs_all += "|||||||||||||
| " - counter = 0 - jobs_all += " | [replacetext(job, " ", " ")] | " - - var/body - if (authenticated && modify) - var/carddesc = {""} - carddesc += "" - - carddesc += "" - - carddesc += "Assignment: " - var/jobs = "[target_rank]" //CHECK THIS - var/accesses = "" - if(istype(src,/obj/machinery/computer/card/centcom)) - accesses += "
| [get_region_accesses_name(i)]: | " - accesses += "
| "
- for(var/A in get_region_accesses(i))
- if(A in modify.access)
- accesses += "[replacetext(get_access_desc(A), " ", " ")] "
- else
- accesses += "[replacetext(get_access_desc(A), " ", " ")] "
- accesses += " " - accesses += " | "
- accesses += "
|
- Player panel - Hover over a line to see more information - Check antagonists - - |
-
| - Search: - | -
|
-
-
- [M_name] - [M_rname] - [M_key] ([M_job])
-
- - |
-
"+search.innerText+"
"+filter+"
"+search.innerText.indexOf(filter))
+ if ( search.innerText.toLowerCase().indexOf(filter) == -1 )
+ {
+ //document.write("a");
+ //ltr.removeChild(tr);
+ td.innerHTML = "";
+ i--;
+ }
+ }catch(err) { }
+ }
+ }
+
+ var count = 0;
+ var index = -1;
+ var debug = document.getElementById("debug");
+
+ locked_tabs = new Array();
+
+ }
+
+ function expand(id,job,name,real_name,image,key,ip,antagonist,ref){
+
+ clearAll();
+
+ var span = document.getElementById(id);
+
+ body = "
| "; + + body += " | ";
+
+ body += ""+job+" "+name+" Real name "+real_name+" Played by "+key+" ("+ip+")" + + body += " | ";
+
+ body += "PP - "
+ body += "N - "
+ body += "VV - "
+ body += "TP - "
+ body += "PM - "
+ body += "SM - "
+ body += "JMP " + if(antagonist > 0) + body += "Antagonist"; + + body += " |
|
+ Player panel + Hover over a line to see more information - Check antagonists + + |
+
| + Search: + | +
|
+
+
+ [M_name] - [M_rname] - [M_key] ([M_job])
+
+ + |
+