diff --git a/_maps/RandomRuins/IceRuins/icemoon_underground_syndielab.dmm b/_maps/RandomRuins/IceRuins/icemoon_underground_syndielab.dmm
index 15a51d2858a..8a3b8d7a004 100644
--- a/_maps/RandomRuins/IceRuins/icemoon_underground_syndielab.dmm
+++ b/_maps/RandomRuins/IceRuins/icemoon_underground_syndielab.dmm
@@ -246,7 +246,6 @@
/turf/open/floor/mineral/plastitanium/red,
/area/ruin/syndielab)
"oA" = (
-/obj/structure/syndicate_uplink_beacon,
/turf/open/floor/iron/dark/textured,
/area/ruin/syndielab)
"oY" = (
@@ -267,10 +266,6 @@
pixel_x = -5;
pixel_y = 8
},
-/obj/item/traitor_bug{
- pixel_y = 6;
- pixel_x = 6
- },
/turf/open/floor/mineral/plastitanium/red,
/area/ruin/syndielab)
"qy" = (
diff --git a/_maps/RandomRuins/SpaceRuins/garbagetruck2.dmm b/_maps/RandomRuins/SpaceRuins/garbagetruck2.dmm
index f1c41c3bf17..16aa17b98f3 100644
--- a/_maps/RandomRuins/SpaceRuins/garbagetruck2.dmm
+++ b/_maps/RandomRuins/SpaceRuins/garbagetruck2.dmm
@@ -102,7 +102,6 @@
"kp" = (
/obj/structure/safe,
/obj/item/stamp/syndicate,
-/obj/item/traitor_bug,
/obj/item/eyesnatcher,
/obj/item/stack/spacecash/c1000,
/turf/open/floor/plating,
diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm
index c9b39755c63..c994dbcd2ce 100644
--- a/_maps/map_files/Birdshot/birdshot.dmm
+++ b/_maps/map_files/Birdshot/birdshot.dmm
@@ -39176,7 +39176,6 @@
"ncb" = (
/obj/effect/decal/cleanable/dirt,
/obj/structure/table/wood,
-/obj/item/paper/calling_card,
/obj/structure/alien/resin/membrane,
/obj/structure/alien/weeds,
/obj/structure/alien/weeds,
diff --git a/_maps/shuttles/hunter_mi13_foodtruck.dmm b/_maps/shuttles/hunter_mi13_foodtruck.dmm
index 4dca72eaae8..155aacf820a 100644
--- a/_maps/shuttles/hunter_mi13_foodtruck.dmm
+++ b/_maps/shuttles/hunter_mi13_foodtruck.dmm
@@ -104,14 +104,6 @@
/obj/item/binoculars{
pixel_y = 10
},
-/obj/item/traitor_bug{
- pixel_y = 6;
- pixel_x = 6
- },
-/obj/item/traitor_bug{
- pixel_y = 3;
- pixel_x = -5
- },
/obj/item/storage/box/zipties{
pixel_y = -4;
pixel_x = 4
diff --git a/code/__DEFINES/dcs/signals/signals_traitor.dm b/code/__DEFINES/dcs/signals/signals_traitor.dm
index 2752ab2363e..0a221dbd068 100644
--- a/code/__DEFINES/dcs/signals/signals_traitor.dm
+++ b/code/__DEFINES/dcs/signals/signals_traitor.dm
@@ -1,30 +1,5 @@
-/// Called when the hack_comm_console objective is completed.
-#define COMSIG_GLOB_TRAITOR_OBJECTIVE_COMPLETED "!traitor_objective_completed"
-
/// Called whenever the uplink handler receives any sort of update. Used by uplinks to update their UI. No arguments passed
#define COMSIG_UPLINK_HANDLER_ON_UPDATE "uplink_handler_on_update"
-/// Sent from the uplink handler when the traitor uses the syndicate uplink beacon to order a replacement uplink.
-#define COMSIG_UPLINK_HANDLER_REPLACEMENT_ORDERED "uplink_handler_replacement_ordered"
-
-/// Called before the traitor objective is generated
-#define COMSIG_TRAITOR_OBJECTIVE_PRE_GENERATE "traitor_objective_pre_generate"
- #define COMPONENT_TRAITOR_OBJECTIVE_ABORT_GENERATION (1<<0)
-/// Called whenever the traitor objective is completed
-#define COMSIG_TRAITOR_OBJECTIVE_COMPLETED "traitor_objective_completed"
-/// Called whenever the traitor objective is failed
-#define COMSIG_TRAITOR_OBJECTIVE_FAILED "traitor_objective_failed"
-
-/// Called when a traitor bug is planted in an area
-#define COMSIG_TRAITOR_BUG_PLANTED_GROUND "traitor_bug_planted_area"
-/// Called when a traitor bug is planted
-#define COMSIG_TRAITOR_BUG_PLANTED_OBJECT "traitor_bug_planted_object"
-/// Called before a traitor bug is planted, where it can still be overrided
-#define COMSIG_TRAITOR_BUG_PRE_PLANTED_OBJECT "traitor_bug_planted_pre_object"
- #define COMPONENT_FORCE_PLACEMENT (1<<0)
- #define COMPONENT_FORCE_FAIL_PLACEMENT (1<<1)
-
-/// Called when a machine a traitor has booby trapped triggers its payload
-#define COMSIG_TRAITOR_MACHINE_TRAP_TRIGGERED "traitor_machine_trap_triggered"
/// Called when a device a traitor has planted effects someone's mood. Pass the mind of the viewer.
#define COMSIG_DEMORALISING_EVENT "traitor_demoralise_event"
diff --git a/code/__DEFINES/uplink.dm b/code/__DEFINES/uplink.dm
index 929b558dfec..3b3621f24c5 100644
--- a/code/__DEFINES/uplink.dm
+++ b/code/__DEFINES/uplink.dm
@@ -9,13 +9,10 @@
/// This item is purchasable to clown ops
#define UPLINK_CLOWN_OPS (1 << 2)
-/// This item is purchasable to infiltrators (midround traitors)
-#define UPLINK_INFILTRATORS (1 << 3)
-
/// Can be randomly given to spies for their bounties
-#define UPLINK_SPY (1 << 4)
+#define UPLINK_SPY (1 << 3)
-#define UPLINK_LONE_OP (1 << 5)
+#define UPLINK_LONE_OP (1 << 4)
/// A blanket define for an item being purchasable by all types of nukie
#define UPLINK_ALL_SYNDIE_OPS (UPLINK_NUKE_OPS | UPLINK_LONE_OP | UPLINK_CLOWN_OPS)
diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm
index fd121537846..a81bc480f97 100644
--- a/code/controllers/configuration/entries/game_options.dm
+++ b/code/controllers/configuration/entries/game_options.dm
@@ -73,11 +73,6 @@
integer = FALSE
min_val = 0.01
-/// Determines how many potential objectives a traitor can have.
-/datum/config_entry/number/maximum_potential_objectives
- default = 6
- min_val = 1
-
/datum/config_entry/number/changeling_scaling_coeff //how much does the amount of players get divided by to determine changelings
default = 6
integer = FALSE
diff --git a/code/controllers/subsystem/dynamic/dynamic_rulesets_latejoin.dm b/code/controllers/subsystem/dynamic/dynamic_rulesets_latejoin.dm
index cefc1dffc0d..b71a1c1e85d 100644
--- a/code/controllers/subsystem/dynamic/dynamic_rulesets_latejoin.dm
+++ b/code/controllers/subsystem/dynamic/dynamic_rulesets_latejoin.dm
@@ -60,7 +60,7 @@
/datum/dynamic_ruleset/latejoin/infiltrator
name = "Syndicate Infiltrator"
- antag_datum = /datum/antagonist/traitor/infiltrator
+ antag_datum = /datum/antagonist/traitor
antag_flag = ROLE_SYNDICATE_INFILTRATOR
antag_flag_override = ROLE_TRAITOR
protected_roles = list(
diff --git a/code/controllers/subsystem/dynamic/dynamic_rulesets_midround.dm b/code/controllers/subsystem/dynamic/dynamic_rulesets_midround.dm
index 4801c00f9de..246490f5b86 100644
--- a/code/controllers/subsystem/dynamic/dynamic_rulesets_midround.dm
+++ b/code/controllers/subsystem/dynamic/dynamic_rulesets_midround.dm
@@ -238,7 +238,7 @@
/datum/dynamic_ruleset/midround/from_living/autotraitor
name = "Syndicate Sleeper Agent"
midround_ruleset_style = MIDROUND_RULESET_STYLE_LIGHT
- antag_datum = /datum/antagonist/traitor/infiltrator/sleeper_agent
+ antag_datum = /datum/antagonist/traitor
antag_flag = ROLE_SLEEPER_AGENT
antag_flag_override = ROLE_TRAITOR
protected_roles = list(
@@ -276,7 +276,7 @@
var/mob/M = pick(candidates)
assigned += M
candidates -= M
- var/datum/antagonist/traitor/infiltrator/sleeper_agent/newTraitor = new
+ var/datum/antagonist/traitor/newTraitor = new
M.mind.add_antag_datum(newTraitor)
message_admins("[ADMIN_LOOKUPFLW(M)] was selected by the [name] ruleset and has been made into a midround traitor.")
log_dynamic("[key_name(M)] was selected by the [name] ruleset and has been made into a midround traitor.")
diff --git a/code/controllers/subsystem/traitor.dm b/code/controllers/subsystem/traitor.dm
index 6ad6fca0893..53cf90ecbd0 100644
--- a/code/controllers/subsystem/traitor.dm
+++ b/code/controllers/subsystem/traitor.dm
@@ -9,15 +9,6 @@ SUBSYSTEM_DEF(traitor)
/// A list of all uplink items
var/list/uplink_items = list()
- /// File to load configurations from.
- var/configuration_path = "config/traitor_objective.json"
- /// Global configuration data that gets applied to each objective when it is created.
- /// Basic objective format
- /// '/datum/traitor_objective/path/to/objective': {
- /// "global_progression_influence_intensity": 0
- /// }
- var/configuration_data = list()
-
/// The coefficient multiplied by the current_global_progression for new joining traitors to calculate their progression
var/newjoin_progression_coeff = 1
/// The current progression that all traitors should be at in the round
@@ -29,31 +20,10 @@ SUBSYSTEM_DEF(traitor)
var/list/datum/uplink_handler/uplink_handlers = list()
/// The current scaling per minute of progression. Has a maximum value of 1 MINUTES.
var/current_progression_scaling = 1 MINUTES
- /// Used to handle the probability of getting an objective.
- var/datum/traitor_category_handler/category_handler
- /// The current debug handler for objectives. Used for debugging objectives
- var/datum/traitor_objective_debug/traitor_debug_panel
- /// Used by the debug menu, decides whether newly created objectives should generate progression and telecrystals. Do not modify for non-debug purposes.
- var/generate_objectives = TRUE
- /// Objectives that have been completed by type. Used for limiting objectives.
- var/list/taken_objectives_by_type = list()
- /// A list of all existing objectives by type
- var/list/all_objectives_by_type = list()
/datum/controller/subsystem/traitor/Initialize()
- category_handler = new()
- traitor_debug_panel = new(category_handler)
-
for(var/theft_item in subtypesof(/datum/objective_item/steal))
new theft_item
-
- if(fexists(configuration_path))
- var/list/data = json_decode(file2text(file(configuration_path)))
- for(var/typepath in data)
- var/actual_typepath = text2path(typepath)
- if(!actual_typepath)
- log_world("[configuration_path] has an invalid type ([typepath]) that doesn't exist in the codebase! Please correct or remove [typepath]")
- configuration_data[actual_typepath] = data[typepath]
return SS_INIT_SUCCESS
/datum/controller/subsystem/traitor/fire(resumed)
@@ -83,7 +53,6 @@ SUBSYSTEM_DEF(traitor)
var/amount_to_give = progression_scaling_delta + (progression_scaling_delta * deviance)
amount_to_give = clamp(amount_to_give, 0, progression_scaling_delta * 2)
handler.progression_points += amount_to_give
- handler.update_objectives()
handler.on_update()
/datum/controller/subsystem/traitor/proc/register_uplink_handler(datum/uplink_handler/uplink_handler)
@@ -97,22 +66,3 @@ SUBSYSTEM_DEF(traitor)
/datum/controller/subsystem/traitor/proc/uplink_handler_deleted(datum/uplink_handler/uplink_handler)
SIGNAL_HANDLER
uplink_handlers -= uplink_handler
-
-/datum/controller/subsystem/traitor/proc/on_objective_taken(datum/traitor_objective/objective)
- if(!istype(objective))
- return
-
- add_objective_to_list(objective, taken_objectives_by_type)
-
-/datum/controller/subsystem/traitor/proc/get_taken_count(datum/traitor_objective/objective_type)
- return length(taken_objectives_by_type[objective_type])
-
-
-/datum/controller/subsystem/traitor/proc/add_objective_to_list(datum/traitor_objective/objective, list/objective_list)
- var/datum/traitor_objective/current_type = objective.type
- while(current_type != /datum/traitor_objective)
- if(!objective_list[current_type])
- objective_list[current_type] = list(objective)
- else
- objective_list[current_type] += objective
- current_type = type2parent(current_type)
diff --git a/code/datums/components/crafting/structures.dm b/code/datums/components/crafting/structures.dm
index 10fe81efe96..7af26c0c89d 100644
--- a/code/datums/components/crafting/structures.dm
+++ b/code/datums/components/crafting/structures.dm
@@ -61,20 +61,6 @@
)
category = CAT_STRUCTURE
-/datum/crafting_recipe/syndicate_uplink_beacon
- name = "Syndicate Uplink Beacon"
- result = /obj/structure/syndicate_uplink_beacon
- tool_behaviors = list(TOOL_SCREWDRIVER)
- time = 6 SECONDS
- reqs = list(
- /obj/item/stack/sheet/iron = 5,
- /obj/item/stack/cable_coil = 5,
- /obj/item/beacon = 1,
- /obj/item/stack/ore/bluespace_crystal = 1,
- )
- category = CAT_STRUCTURE
- crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
-
/datum/crafting_recipe/manucrate
name = "Manufacturing Storage Unit"
result = /obj/machinery/power/manufacturing/storagebox
diff --git a/code/datums/components/uplink.dm b/code/datums/components/uplink.dm
index 82b12d555ac..98faa95b667 100644
--- a/code/datums/components/uplink.dm
+++ b/code/datums/components/uplink.dm
@@ -66,8 +66,6 @@
RegisterSignal(parent, COMSIG_RADIO_NEW_MESSAGE, PROC_REF(new_message))
else if(istype(parent, /obj/item/pen))
RegisterSignal(parent, COMSIG_PEN_ROTATED, PROC_REF(pen_rotation))
- else if(istype(parent, /obj/item/uplink/replacement))
- RegisterSignal(parent, COMSIG_MOVABLE_HEAR, PROC_REF(on_heard))
if(owner)
src.owner = owner
@@ -81,7 +79,6 @@
src.active = enabled
if(!uplink_handler_override)
uplink_handler = new()
- uplink_handler.has_objectives = FALSE
uplink_handler.uplink_flag = uplink_flag
uplink_handler.telecrystals = starting_tc
uplink_handler.has_progression = has_progression
@@ -89,7 +86,6 @@
else
uplink_handler = uplink_handler_override
RegisterSignal(uplink_handler, COMSIG_UPLINK_HANDLER_ON_UPDATE, PROC_REF(handle_uplink_handler_update))
- RegisterSignal(uplink_handler, COMSIG_UPLINK_HANDLER_REPLACEMENT_ORDERED, PROC_REF(handle_uplink_replaced))
if(!lockable)
active = TRUE
locked = FALSE
@@ -100,19 +96,6 @@
SIGNAL_HANDLER
SStgui.update_uis(src)
-/// When a new uplink is made via the syndicate beacon it locks all lockable uplinks and destroys replacement uplinks
-/datum/component/uplink/proc/handle_uplink_replaced()
- SIGNAL_HANDLER
- if(lockable)
- lock_uplink()
- if(!istype(parent, /obj/item/uplink/replacement))
- return
- var/obj/item/uplink_item = parent
- do_sparks(number = 3, cardinal_only = FALSE, source = uplink_item)
- uplink_item.visible_message(span_warning("The [uplink_item] suddenly combusts!"), vision_distance = COMBAT_MESSAGE_RANGE)
- new /obj/effect/decal/cleanable/ash(get_turf(uplink_item))
- qdel(uplink_item)
-
/datum/component/uplink/InheritComponent(datum/component/uplink/uplink)
lockable |= uplink.lockable
active |= uplink.active
@@ -186,12 +169,9 @@
data["telecrystals"] = uplink_handler.telecrystals
data["progression_points"] = uplink_handler.progression_points
data["current_expected_progression"] = SStraitor.current_global_progression
- data["maximum_active_objectives"] = uplink_handler.maximum_active_objectives
data["progression_scaling_deviance"] = SStraitor.progression_scaling_deviance
data["current_progression_scaling"] = SStraitor.current_progression_scaling
- data["maximum_potential_objectives"] = uplink_handler.maximum_potential_objectives
-
if(uplink_handler.primary_objectives)
var/list/primary_objectives = list()
for(var/datum/objective/task as anything in uplink_handler.primary_objectives)
@@ -204,25 +184,6 @@
primary_objectives += list(task_data)
data["primary_objectives"] = primary_objectives
- if(uplink_handler.has_objectives)
- var/list/potential_objectives = list()
- for(var/index in 1 to uplink_handler.potential_objectives.len)
- var/datum/traitor_objective/objective = uplink_handler.potential_objectives[index]
- var/list/objective_data = objective.uplink_ui_data(user)
- objective_data["id"] = index
- potential_objectives += list(objective_data)
-
- var/list/active_objectives = list()
- for(var/index in 1 to uplink_handler.active_objectives.len)
- var/datum/traitor_objective/objective = uplink_handler.active_objectives[index]
- var/list/objective_data = objective.uplink_ui_data(user)
- objective_data["id"] = index
- active_objectives += list(objective_data)
-
-
- data["potential_objectives"] = potential_objectives
- data["active_objectives"] = active_objectives
- data["completed_final_objective"] = uplink_handler.final_objective
var/list/stock_list = uplink_handler.item_stock.Copy()
var/list/extra_purchasable_stock = list()
@@ -263,7 +224,6 @@
var/list/data = list()
data["uplink_flag"] = uplink_handler.uplink_flag
data["has_progression"] = uplink_handler.has_progression
- data["has_objectives"] = uplink_handler.has_objectives
data["lockable"] = lockable
data["assigned_role"] = uplink_handler.assigned_role
data["assigned_species"] = uplink_handler.assigned_species
@@ -308,47 +268,9 @@
if("renegotiate_objectives")
uplink_handler.replace_objectives?.Invoke()
SStgui.update_uis(src)
-
- if(!uplink_handler.has_objectives)
- return TRUE
-
- if(uplink_handler.owner?.current != ui.user || !uplink_handler.can_take_objectives)
- return TRUE
-
- switch(action)
- if("regenerate_objectives")
- uplink_handler.generate_objectives()
- return TRUE
-
- var/list/objectives
- switch(action)
- if("start_objective")
- objectives = uplink_handler.potential_objectives
- if("objective_act", "finish_objective", "objective_abort")
- objectives = uplink_handler.active_objectives
-
- if(!objectives)
- return
-
- var/objective_index = round(text2num(params["index"]))
- if(objective_index < 1 || objective_index > length(objectives))
- return TRUE
- var/datum/traitor_objective/objective = objectives[objective_index]
-
- // Objective actions
- switch(action)
- if("start_objective")
- uplink_handler.take_objective(ui.user, objective)
- if("objective_act")
- uplink_handler.ui_objective_act(ui.user, objective, params["objective_action"])
- if("finish_objective")
- if(!objective.finish_objective(ui.user))
- return
- uplink_handler.complete_objective(objective)
- if("objective_abort")
- uplink_handler.abort_objective(objective)
return TRUE
+
/// Proc that locks uplinks
/datum/component/uplink/proc/lock_uplink()
active = FALSE
@@ -494,17 +416,6 @@
return returnable_code
-/// Proc that unlocks a locked replacement uplink when it hears the unlock code from their datum
-/datum/component/uplink/proc/on_heard(datum/source, list/hearing_args)
- SIGNAL_HANDLER
- if(!locked)
- return
- if(!findtext(hearing_args[HEARING_RAW_MESSAGE], unlock_code))
- return
- var/atom/replacement_uplink = parent
- locked = FALSE
- replacement_uplink.balloon_alert_to_viewers("beep", vision_distance = COMBAT_MESSAGE_RANGE)
-
/datum/component/uplink/proc/failsafe(atom/source)
if(!parent)
return
diff --git a/code/datums/mind/_mind.dm b/code/datums/mind/_mind.dm
index a4c75747e80..a059e139da5 100644
--- a/code/datums/mind/_mind.dm
+++ b/code/datums/mind/_mind.dm
@@ -408,41 +408,6 @@
message_admins("[key_name_admin(usr)] has unemag'ed [ai]'s Cyborgs.")
log_admin("[key_name(usr)] has unemag'ed [ai]'s Cyborgs.")
- else if(href_list["edit_obj_tc"])
- var/datum/traitor_objective/objective = locate(href_list["edit_obj_tc"])
- if(!istype(objective))
- return
- var/telecrystal = input("Set new telecrystal reward for [objective.name]","Syndicate uplink", objective.telecrystal_reward) as null | num
- if(isnull(telecrystal))
- return
- objective.telecrystal_reward = telecrystal
- message_admins("[key_name_admin(usr)] changed [objective]'s telecrystal reward count to [telecrystal].")
- log_admin("[key_name(usr)] changed [objective]'s telecrystal reward count to [telecrystal].")
- else if(href_list["edit_obj_pr"])
- var/datum/traitor_objective/objective = locate(href_list["edit_obj_pr"])
- if(!istype(objective))
- return
- var/progression = input("Set new progression reward for [objective.name]","Syndicate uplink", objective.progression_reward) as null | num
- if(isnull(progression))
- return
- objective.progression_reward = progression
- message_admins("[key_name_admin(usr)] changed [objective]'s progression reward count to [progression].")
- log_admin("[key_name(usr)] changed [objective]'s progression reward count to [progression].")
- else if(href_list["fail_objective"])
- var/datum/traitor_objective/objective = locate(href_list["fail_objective"])
- if(!istype(objective))
- return
- var/performed = objective.objective_state == OBJECTIVE_STATE_INACTIVE? "skipped" : "failed"
- message_admins("[key_name_admin(usr)] forcefully [performed] [objective].")
- log_admin("[key_name(usr)] forcefully [performed] [objective].")
- objective.fail_objective()
- else if(href_list["succeed_objective"])
- var/datum/traitor_objective/objective = locate(href_list["succeed_objective"])
- if(!istype(objective))
- return
- message_admins("[key_name_admin(usr)] forcefully succeeded [objective].")
- log_admin("[key_name(usr)] forcefully succeeded [objective].")
- objective.succeed_objective()
else if (href_list["common"])
switch(href_list["common"])
if("undress")
@@ -478,26 +443,6 @@
uplink.uplink_handler.progression_points = progression
message_admins("[key_name_admin(usr)] changed [current]'s progression point count to [progression].")
log_admin("[key_name(usr)] changed [current]'s progression point count to [progression].")
- uplink.uplink_handler.update_objectives()
- uplink.uplink_handler.generate_objectives()
- if("give_objective")
- if(!check_rights(R_FUN))
- return
- var/datum/component/uplink/uplink = find_syndicate_uplink()
- if(!uplink || !uplink.uplink_handler)
- return
- var/list/all_objectives = subtypesof(/datum/traitor_objective)
- var/objective_typepath = tgui_input_list(usr, "Select objective", "Select objective", all_objectives)
- if(!objective_typepath)
- return
- var/datum/traitor_objective/objective = uplink.uplink_handler.try_add_objective(objective_typepath, force = TRUE)
- if(objective)
- message_admins("[key_name_admin(usr)] gave [current] a traitor objective ([objective_typepath]).")
- log_admin("[key_name(usr)] gave [current] a traitor objective ([objective_typepath]).")
- else
- to_chat(usr, span_warning("Failed to generate the objective!"))
- message_admins("[key_name_admin(usr)] failed to give [current] a traitor objective ([objective_typepath]).")
- log_admin("[key_name(usr)] failed to give [current] a traitor objective ([objective_typepath]).")
if("uplink")
var/datum/antagonist/traitor/traitor_datum = has_antag_datum(/datum/antagonist/traitor)
if(!give_uplink(antag_datum = traitor_datum || null))
diff --git a/code/game/gamemodes/objective_items.dm b/code/game/gamemodes/objective_items.dm
index ac381ae4055..388457d5103 100644
--- a/code/game/gamemodes/objective_items.dm
+++ b/code/game/gamemodes/objective_items.dm
@@ -1,7 +1,55 @@
+GLOBAL_DATUM_INIT(steal_item_handler, /datum/objective_item_handler, new())
+
/proc/add_item_to_steal(source, type)
GLOB.steal_item_handler.objectives_by_path[type] += source
return type
+/// Holds references to information about all of the items you might need to steal for objectives
+/datum/objective_item_handler
+ var/list/list/objectives_by_path
+ var/generated_items = FALSE
+
+/datum/objective_item_handler/New()
+ . = ..()
+ objectives_by_path = list()
+ for(var/datum/objective_item/item as anything in subtypesof(/datum/objective_item))
+ objectives_by_path[initial(item.targetitem)] = list()
+ RegisterSignal(SSatoms, COMSIG_SUBSYSTEM_POST_INITIALIZE, PROC_REF(save_items))
+ RegisterSignal(SSdcs, COMSIG_GLOB_NEW_ITEM, PROC_REF(new_item_created))
+
+/datum/objective_item_handler/proc/new_item_created(datum/source, obj/item/item)
+ SIGNAL_HANDLER
+ if(HAS_TRAIT(item, TRAIT_ITEM_OBJECTIVE_BLOCKED))
+ return
+ if(!generated_items)
+ item.add_stealing_item_objective()
+ return
+ var/typepath = item.add_stealing_item_objective()
+ if(typepath != null)
+ register_item(item, typepath)
+
+/// Registers all items that are potentially stealable and removes ones that aren't.
+/// We still need to do things this way because on mapload, items may not be on the station until everything has finished loading.
+/datum/objective_item_handler/proc/save_items()
+ SIGNAL_HANDLER
+ for(var/obj/item/typepath as anything in objectives_by_path)
+ var/list/obj_by_path_cache = objectives_by_path[typepath].Copy()
+ for(var/obj/item/object as anything in obj_by_path_cache)
+ register_item(object, typepath)
+ generated_items = TRUE
+
+/datum/objective_item_handler/proc/register_item(atom/object, typepath)
+ var/turf/place = get_turf(object)
+ if(!place || !is_station_level(place.z))
+ objectives_by_path[typepath] -= object
+ return
+ RegisterSignal(object, COMSIG_QDELETING, PROC_REF(remove_item))
+
+/datum/objective_item_handler/proc/remove_item(atom/source)
+ SIGNAL_HANDLER
+ for(var/typepath in objectives_by_path)
+ objectives_by_path[typepath] -= source
+
//Contains the target item datums for Steal objectives.
/datum/objective_item
/// How the item is described in the objective
diff --git a/code/game/objects/structures/syndicate_uplink_beacon.dm b/code/game/objects/structures/syndicate_uplink_beacon.dm
deleted file mode 100644
index 33e260e8d20..00000000000
--- a/code/game/objects/structures/syndicate_uplink_beacon.dm
+++ /dev/null
@@ -1,114 +0,0 @@
-/// Device that traitors can craft in order to be sent a new, undisguised uplink
-/obj/structure/syndicate_uplink_beacon
- name = "suspicious beacon"
- icon = 'icons/obj/machines/telecomms.dmi'
- icon_state = "relay_traitor"
- desc = "This ramshackle device seems capable of receiving and sending signals for some nefarious purpose."
- density = TRUE
- anchored = TRUE
- /// Traitor's code that they speak into the radio
- var/uplink_code = ""
- /// weakref to person who is going to use the beacon to get a replacement uplink
- var/datum/weakref/owner
- /// while constructed the teleport beacon is still active
- var/obj/item/beacon/teleport_beacon
- /// Radio that the device needs to listen to the codeword from the traitor
- var/obj/item/radio/listening_radio
- /// prevents traitor from activating teleport_beacon proc too much in a small period of time
- COOLDOWN_DECLARE(beacon_cooldown)
-
-/obj/structure/syndicate_uplink_beacon/Initialize(mapload)
- . = ..()
- register_context()
-
- var/static/list/tool_behaviors = list(
- TOOL_SCREWDRIVER = list(
- SCREENTIP_CONTEXT_RMB = "Deconstruct",
- ),
- )
- AddElement(/datum/element/contextual_screentip_tools, tool_behaviors)
- listening_radio = new(src)
- listening_radio.canhear_range = 0
- teleport_beacon = new(src)
-
-/obj/structure/syndicate_uplink_beacon/attack_hand(mob/living/user, list/modifiers)
- if(!IS_TRAITOR(user))
- balloon_alert(user, "don't know how to use!")
- return
- if(IS_WEAKREF_OF(owner, user))
- balloon_alert(user, "already synchronized to you!")
- return
- if(owner != null)
- balloon_alert(user, "already claimed!")
- return
- var/datum/looping_sound/typing/typing_sounds = new(src, start_immediately = TRUE)
- balloon_alert(user, "synchronizing...")
- if(!do_after(user = user, delay = 3 SECONDS, target = src, interaction_key = REF(src), hidden = TRUE))
- typing_sounds.stop()
- return
- typing_sounds.stop()
- probe_traitor(user)
-
-/obj/structure/syndicate_uplink_beacon/screwdriver_act_secondary(mob/living/user, obj/item/tool)
- tool.play_tool_sound(src)
- balloon_alert(user, "deconstructing...")
- if (!do_after(user, 5 SECONDS, target = src, hidden = TRUE))
- return FALSE
- var/turf/beacon_tile = get_turf(src)
- new /obj/item/stack/sheet/iron/five(beacon_tile)
- new /obj/item/stack/cable_coil/five(beacon_tile)
- teleport_beacon.forceMove(beacon_tile)
- teleport_beacon = null
- qdel(src)
- return TRUE
-
-/obj/structure/syndicate_uplink_beacon/Destroy()
- QDEL_NULL(listening_radio)
- if(teleport_beacon)
- QDEL_NULL(teleport_beacon)
- return ..()
-
-/// Proc reads the user, sets radio to the correct frequency and starts to listen for the replacement uplink code
-/obj/structure/syndicate_uplink_beacon/proc/probe_traitor(mob/living/user)
- owner = WEAKREF(user)
- var/datum/antagonist/traitor/traitor_datum = user.mind.has_antag_datum(/datum/antagonist/traitor)
-
- uplink_code = traitor_datum.replacement_uplink_code
- listening_radio.set_frequency(traitor_datum.replacement_uplink_frequency)
- become_hearing_sensitive()
-
-/obj/structure/syndicate_uplink_beacon/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods, message_range)
- if(ismob(speaker) || radio_freq != listening_radio.get_frequency())
- return
- if(!findtext(message, uplink_code))
- return
- teleport_uplink()
-
-/// Proc uses owners uplink handler to create replacement uplink and then lock or destroy their other uplinks
-/obj/structure/syndicate_uplink_beacon/proc/teleport_uplink()
- if(!COOLDOWN_FINISHED(src, beacon_cooldown))
- return
- COOLDOWN_START(src, beacon_cooldown, 10 MINUTES)
-
- var/mob/living/resolved_owner = owner.resolve()
- if(isnull(resolved_owner))
- return
-
- var/datum/antagonist/traitor/traitor_datum = resolved_owner.mind.has_antag_datum(/datum/antagonist/traitor)
- if(isnull(traitor_datum))
- return
-
- var/datum/uplink_handler/uplink_handler = traitor_datum.uplink_handler
-
- SEND_SIGNAL(uplink_handler, COMSIG_UPLINK_HANDLER_REPLACEMENT_ORDERED)
- new /obj/item/uplink/replacement(get_turf(src), /*owner = */resolved_owner, /*tc_amount = */0, /*uplink_handler_override = */uplink_handler)
- flick("relay_traitor_activate", src)
- do_sparks(number = 5, cardinal_only = FALSE, source = src)
- log_traitor("[key_name(resolved_owner)] acquired a replacement uplink via the syndicate uplink beacon.")
-
-// Adds screentips
-/obj/structure/syndicate_uplink_beacon/add_context(atom/source, list/context, obj/item/held_item, mob/user)
- if(held_item || !IS_TRAITOR(user))
- return NONE
- context[SCREENTIP_CONTEXT_LMB] = "Synchronize with beacon"
- return CONTEXTUAL_SCREENTIP_SET
diff --git a/code/modules/admin/antag_panel.dm b/code/modules/admin/antag_panel.dm
index 7e7aa262de5..453113f885e 100644
--- a/code/modules/admin/antag_panel.dm
+++ b/code/modules/admin/antag_panel.dm
@@ -199,14 +199,10 @@ GLOBAL_VAR(antag_prototypes)
var/uplink_info = "Uplink:"
var/datum/component/uplink/U = find_syndicate_uplink()
if(U)
- if(!U.uplink_handler.has_objectives)
- uplink_info += "take"
if (check_rights(R_FUN, 0))
uplink_info += ", [U.uplink_handler.telecrystals] TC"
if(U.uplink_handler.has_progression)
uplink_info += ", [U.uplink_handler.progression_points] PR"
- if(U.uplink_handler.has_objectives)
- uplink_info += ", Force Give Objective"
else
uplink_info += ", [U.uplink_handler.telecrystals] TC"
if(U.uplink_handler.has_progression)
diff --git a/code/modules/admin/verbs/secrets.dm b/code/modules/admin/verbs/secrets.dm
index 8deec6bd6b4..b10ef0002d9 100644
--- a/code/modules/admin/verbs/secrets.dm
+++ b/code/modules/admin/verbs/secrets.dm
@@ -765,7 +765,6 @@ ADMIN_VERB(secrets, R_NONE, "Secrets", "Abuse harder than you ever have before w
assign_admin_objective_and_antag(player, antag_datum)
var/datum/uplink_handler/uplink = antag_datum.uplink_handler
uplink.has_progression = FALSE
- uplink.has_objectives = FALSE
if(ROLE_CHANGELING)
var/datum/antagonist/changeling/antag_datum = new
antag_datum.give_objectives = keep_generic_objecives
diff --git a/code/modules/antagonists/traitor/README.md b/code/modules/antagonists/traitor/README.md
deleted file mode 100644
index 360d1bd54eb..00000000000
--- a/code/modules/antagonists/traitor/README.md
+++ /dev/null
@@ -1,58 +0,0 @@
-# Progression Traitor Balance Guide
-
-This guide will explain how the values for progression traitor works, how to balance progression traitors and what you should NOT do when balancing.
-This guide will only explain progression values.
-
-## Definitions
-
-- Progression points OR Progression - A currency that controls what uplink items a player can purchase and what objectives they have accessible to them. Gained passively or by completing objectives and has diminishing returns as it strays from the expected progression
-- Expected Progression - A global value that increments by a value of 1 minute every minute, representing the 'time' that a player should be at if they had not completed any objectives.
-- Objectives - An activity or job that a player can take for rewards such as TC and progression points.
-- Player - The user(s) that are playing as the antagonist in this new system.
-- Expected deviance - The amount of deviance that can be expected from the minimum and maximum progressions. Usually calculated by `progression_scaling_deviance` + `progression_scaling_deviance` * `global_progression_deviance_required` (explained further down)
-
-## How it works
-
-This section will explain how the entire balance system works. This is an overview of the entire system.
-
-### Progression
-
-Progression points is passively given to a player, and are represented as minutes (or time values) in code. The round has its own 'expected progression', which is the progression value that you'd normally have if you hadn't completed any objectives whatsoever. This is the baseline progression that all players will be at unless they're a latejoiner, and it acts as the basis for determining how much progression points a player should get over time and the cost of objectives for a specific player, if they deviate too much from this value. The idea is that they will slowly drift back towards the expected progression if they do nothing and it becomes harder for them to progress as they deviate further from the expected progression. The amount that is passively given can also vary depending on how many players there are, so that at lower populations, expected progression rises more slowly.
-
-### Objectives
-
-Objectives are worth a certain amount of progression points, determined by the code. However, this can be scaled to be less if the player taking them is ahead of the expected progression. This scales exponentially, so that as a player deviates further from the expected progression, the reward diminishes exponentially, up to a reduced value of 90%. The similar thing happens in the opposite direction, with people who are lower than the expected progression getting more progression than usual for completing objectives.
-
-## How to balance
-
-### The traitor subsystem
-- `newjoin_progression_coeff` - The coefficient multiplied by the expected progression for new joining traitors to calculate their starting progression, so that they don't start from scratch
-- `progression_scaling_deviance` - The value that the entire system revolves around. This determines how your disadvantages are calculated, if you stray from the expected progression. Having a progression value that is `progression_scaling_deviance` minutes off of the expected progression means that you won't get any progression at all, and if objectives were configured to suit this, you'd have the highest reduction you can possibly get. From the expected progression to this value, it scales linearly and it also works in the opposite direction.
-- `current_progression_scaling` - Defined at compile time, this determines how fast expected progression scales. So if you have it set to 0.5 MINUTES, it'll take twice as long to unlock uplink items and new objectives.
-- `CONFIG:TRAITOR_IDEAL_PLAYER_COUNT` - The ideal player count before expected progression stops increasing. If the living player list gets below this value, the current progression scaling will be multiplied by player_count/traitor_ideal_player_count. In essence, this makes it so that progression scales more slowly when there isn't a lot of people alive.
-
-If you want to balance how fast the system progresses, you should look at modifying `current_progression_scaling`. If you want to balance how far someone should be allowed to deviate, you should look at modifying `progression-scaling-deviance`
-
-### Objectives
-- `progression_minimum` - The minimum number of progression points required before this objective can show up as a potential objective
-- `progression_maximum` - The maximum number of progression points before this objective stops showing up as a potential objective, used to prevent roundstart objectives from showing up during the late game.
-- `progression_reward` - The progression reward you get from completing an objective. This is the base value, and can also be a two element list of numbers if you want it to be random. This value is then scaled depending on whether a player is ahead or behind the expected progression
-- `global_progression_influence_intensity` - Determines how influential expected progression will affect the progression reward of this objective. Set to 0 to disable.
-- `global_progression_deviance_required` - Determines how much deviance is required before the scaling kicks in, to give objectives more leeway so that at the `progression_scaling_deviance`, it doesn't scale to 90% immediately.
-- `progression_cost_coeff_deviance` - This determines the randomness of the progression reward, to prevent all of the scaling from looking the same. Becomes a lot less significant as the scaling variable gets closer to 1.
-
-If you want to balance the expected timeframe an objective should be available, you should look at changing the `progression_minimum` or `progression_maximum`. If you want to balance how much objectives reward, you may want to look at modifying `progression_reward`. If you want to look at balancing the cost of an objective depending on the expected progression, you may want to look at `global_progression_influence_intensity`. If you want to look at decreasing or increasing the deviance allowed before objectives become worthless progression-wise, you may want to look at modifying `global_progression_deviance_required`
-
-### Uplink Items
-- `progression_minimum` - The minimum number of progression points required to purchase this uplink item.
-
-## What NOT to do when balancing
-
-### Overcompensate
-
-You do not want to overcompensate variables such as `progression_minimum` and `progression_maximum`. Such values need to be an accurate representation of roughly around the time a player should unlock the objective or uplink item. progression_scaling_deviance is supposed to represents the limit that a casual player can be at before it becomes significantly harder for them to progress throughout. You should expect people to be within `progression_scaling_deviance` + `progression_scaling_deviance` * `global_progression_deviance_required`. (Assuming `progression_scaling_deviance` is 20 minutes and `progression_scaling_deviance_required` is 0.5, 20 + 0.5 * 20 = 30; this gives us a value of 30 minutes). This is the expected deviance.
-
-### Reward large amounts of progression points
-
-Progression points are passively gained, so rewarding large amounts of progression points will let people bypass the scaling as they'll immediately jump to an absurd value. A good rule of thumb is to always keep the reward within or below the expected deviance.
-
diff --git a/code/modules/antagonists/traitor/balance_helper.dm b/code/modules/antagonists/traitor/balance_helper.dm
deleted file mode 100644
index b2a9661bfeb..00000000000
--- a/code/modules/antagonists/traitor/balance_helper.dm
+++ /dev/null
@@ -1,109 +0,0 @@
-ADMIN_VERB(debug_traitor_objectives, R_DEBUG, "Debug Traitor Objectives", "Verify functionality of traitor goals.", ADMIN_CATEGORY_DEBUG)
- SStraitor.traitor_debug_panel?.ui_interact(user.mob)
-
-/datum/traitor_objective_debug
- var/list/all_objectives
-
-/datum/traitor_objective_debug/New(datum/traitor_category_handler/category_handler)
- . = ..()
- all_objectives = list()
- for(var/datum/traitor_objective_category/category as anything in category_handler.all_categories)
- var/list/generated_list = list()
- var/list/current_list = category.objectives
- for(var/value in category.objectives)
- if(islist(value))
- generated_list += list(list(
- "objectives" = recursive_list_generate(value),
- "weight" = current_list[value]
- ))
- else
- generated_list += list(generate_objective_data(value, current_list[value]))
- all_objectives += list(list(
- "name" = category.name,
- "objectives" = generated_list,
- "weight" = category.weight,
- ))
-
-/datum/traitor_objective_debug/proc/recursive_list_generate(list/to_check)
- var/list/generated_list = list()
- for(var/value in to_check)
- if(islist(value))
- generated_list += list(list(
- "objectives" = recursive_list_generate(value),
- "weight" = to_check[value]
- ))
- else
- generated_list += list(generate_objective_data(value, to_check[value]))
- return generated_list
-
-/datum/traitor_objective_debug/proc/generate_objective_data(datum/traitor_objective/objective_type, weight)
- // Need to set this to false before we create the new objective to prevent init from fucking it up
- SStraitor.generate_objectives = FALSE
- var/datum/traitor_objective/objective = new objective_type()
- var/list/return_data = list(
- "name" = objective.name,
- "description" = objective.description,
- "progression_minimum" = objective.progression_minimum,
- "progression_maximum" = objective.progression_maximum,
- "global_progression" = objective.global_progression_deviance_required,
- "global_progression_limit_coeff" = objective.global_progression_limit_coeff,
- "global_progression_influence_intensity" = objective.global_progression_influence_intensity,
- "progression_reward" = objective.progression_reward,
- "telecrystal_reward" = objective.telecrystal_reward,
- "telecrystal_penalty" = objective.telecrystal_penalty,
- "weight" = weight,
- "type" = objective.type,
- )
- qdel(objective)
- SStraitor.generate_objectives = TRUE
- return return_data
-
-/datum/traitor_objective_debug/ui_interact(mob/user, datum/tgui/ui)
- ui = SStgui.try_update_ui(user, src, ui)
- if(!ui)
- ui = new(user, src, "TraitorObjectiveDebug")
- ui.open()
-
-/datum/traitor_objective_debug/ui_data(mob/user)
- var/list/data = list()
- data["current_progression"] = SStraitor.current_global_progression
- var/list/handlers = SStraitor.uplink_handlers
- var/list/handler_data = list()
- for(var/datum/uplink_handler/handler as anything in handlers)
- var/total_progression_from_objectives = 0
- for(var/datum/traitor_objective/objective as anything in handler.completed_objectives)
- if(objective.objective_state != OBJECTIVE_STATE_COMPLETED)
- continue
- total_progression_from_objectives += objective.progression_reward
- handler_data += list(list(
- "player" = handler.owner?.key,
- "progression_points" = handler.progression_points,
- "total_progression_from_objectives" = total_progression_from_objectives
- ))
- data["player_data"] = handler_data
- return data
-
-/datum/traitor_objective_debug/ui_static_data(mob/user)
- var/list/data = list()
- data["objective_data"] = all_objectives
- data["progression_scaling_deviance"] = SStraitor.progression_scaling_deviance
- return data
-
-/datum/traitor_objective_debug/ui_state(mob/user)
- return GLOB.admin_state
-
-/datum/traitor_objective_debug/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
- . = ..()
- if(.)
- return
-
- switch(action)
- if("set_current_expected_progression")
- SStraitor.current_global_progression = text2num(params["new_expected_progression"])
- return TRUE
- if("generate_json")
- var/temp_file = file("data/TraitorObjectiveDownloadTempFile")
- fdel(temp_file)
- WRITE_FILE(temp_file, all_objectives)
- DIRECT_OUTPUT(ui.user, ftp(temp_file, "TraitorObjectiveData.json"))
- return TRUE
diff --git a/code/modules/antagonists/traitor/components/traitor_objective_helpers.dm b/code/modules/antagonists/traitor/components/traitor_objective_helpers.dm
deleted file mode 100644
index 6bf5ce5d117..00000000000
--- a/code/modules/antagonists/traitor/components/traitor_objective_helpers.dm
+++ /dev/null
@@ -1,54 +0,0 @@
-/// Helper component that registers signals on an object
-/// This is not necessary to use and gives little control over the conditions
-/datum/component/traitor_objective_register
- dupe_mode = COMPONENT_DUPE_ALLOWED
-
- /// The target to apply the succeed/fail signals onto
- var/datum/target
- /// Signals to listen out for to automatically succeed the objective
- var/succeed_signals
- /// Signals to listen out for to automatically fail the objective.
- var/fail_signals
- /// Whether failing has a penalty
- var/penalty = 0
-
-/datum/component/traitor_objective_register/Initialize(datum/target, succeed_signals, fail_signals, penalty)
- . = ..()
- if(!istype(parent, /datum/traitor_objective))
- return COMPONENT_INCOMPATIBLE
- src.target = target
- src.succeed_signals = succeed_signals
- src.fail_signals = fail_signals
- src.penalty = penalty
-
-/datum/component/traitor_objective_register/RegisterWithParent()
- if(succeed_signals)
- RegisterSignals(target, succeed_signals, PROC_REF(on_success))
- if(fail_signals)
- RegisterSignals(target, fail_signals, PROC_REF(on_fail))
- RegisterSignals(parent, list(COMSIG_TRAITOR_OBJECTIVE_COMPLETED, COMSIG_TRAITOR_OBJECTIVE_FAILED), PROC_REF(delete_self))
-
-/datum/component/traitor_objective_register/UnregisterFromParent()
- if(target)
- if(succeed_signals)
- UnregisterSignal(target, succeed_signals)
- if(fail_signals)
- UnregisterSignal(target, fail_signals)
- UnregisterSignal(parent, list(
- COMSIG_TRAITOR_OBJECTIVE_COMPLETED,
- COMSIG_TRAITOR_OBJECTIVE_FAILED
- ))
-
-/datum/component/traitor_objective_register/proc/on_fail(datum/traitor_objective/source)
- SIGNAL_HANDLER
- var/datum/traitor_objective/objective = parent
- objective.fail_objective(penalty)
-
-/datum/component/traitor_objective_register/proc/on_success()
- SIGNAL_HANDLER
- var/datum/traitor_objective/objective = parent
- objective.succeed_objective()
-
-/datum/component/traitor_objective_register/proc/delete_self()
- SIGNAL_HANDLER
- qdel(src)
diff --git a/code/modules/antagonists/traitor/components/traitor_objective_limit_per_time.dm b/code/modules/antagonists/traitor/components/traitor_objective_limit_per_time.dm
deleted file mode 100644
index ce72e1227de..00000000000
--- a/code/modules/antagonists/traitor/components/traitor_objective_limit_per_time.dm
+++ /dev/null
@@ -1,41 +0,0 @@
-/// Helper component to track events on
-/datum/component/traitor_objective_limit_per_time
- dupe_mode = COMPONENT_DUPE_HIGHLANDER
-
- /// The maximum time that an objective will be considered for. Set to -1 to accept any time.
- var/time_period = 0
- /// The maximum amount of objectives that can be active or recently active at one time
- var/maximum_objectives = 0
- /// The typepath which we check for
- var/typepath
-
-/datum/component/traitor_objective_limit_per_time/Initialize(typepath, time_period, maximum_objectives)
- . = ..()
- if(!istype(parent, /datum/traitor_objective))
- return COMPONENT_INCOMPATIBLE
- src.time_period = time_period
- src.maximum_objectives = maximum_objectives
- src.typepath = typepath
- if(!typepath)
- src.typepath = parent.type
-
-/datum/component/traitor_objective_limit_per_time/RegisterWithParent()
- RegisterSignal(parent, COMSIG_TRAITOR_OBJECTIVE_PRE_GENERATE, PROC_REF(handle_generate))
-
-/datum/component/traitor_objective_limit_per_time/UnregisterFromParent()
- UnregisterSignal(parent, COMSIG_TRAITOR_OBJECTIVE_PRE_GENERATE)
-
-
-/datum/component/traitor_objective_limit_per_time/proc/handle_generate(datum/traitor_objective/source, datum/mind/owner, list/potential_duplicates)
- SIGNAL_HANDLER
- var/datum/uplink_handler/handler = source.handler
- if(!handler)
- return
- var/count = 0
- for(var/datum/traitor_objective/objective as anything in handler.potential_duplicate_objectives[typepath])
- if(time_period != -1 && objective.objective_state != OBJECTIVE_STATE_INACTIVE && (world.time - objective.time_of_completion) > time_period)
- continue
- count++
-
- if(count >= maximum_objectives)
- return COMPONENT_TRAITOR_OBJECTIVE_ABORT_GENERATION
diff --git a/code/modules/antagonists/traitor/components/traitor_objective_mind_tracker.dm b/code/modules/antagonists/traitor/components/traitor_objective_mind_tracker.dm
deleted file mode 100644
index 01d1febb9ac..00000000000
--- a/code/modules/antagonists/traitor/components/traitor_objective_mind_tracker.dm
+++ /dev/null
@@ -1,40 +0,0 @@
-/// Helper component to track events on
-/datum/component/traitor_objective_mind_tracker
- dupe_mode = COMPONENT_DUPE_ALLOWED
-
- /// The target to track
- var/datum/mind/target
- /// Signals to listen out for mapped to procs to call
- var/list/signals
- /// Current registered target
- var/mob/current_registered_target
-
-/datum/component/traitor_objective_mind_tracker/Initialize(datum/target, signals)
- . = ..()
- if(!istype(parent, /datum/traitor_objective))
- return COMPONENT_INCOMPATIBLE
- src.target = target
- src.signals = signals
-
-/datum/component/traitor_objective_mind_tracker/RegisterWithParent()
- RegisterSignal(target, COMSIG_MIND_TRANSFERRED, PROC_REF(handle_mind_transferred))
- RegisterSignal(target, COMSIG_QDELETING, PROC_REF(delete_self))
- RegisterSignals(parent, list(COMSIG_TRAITOR_OBJECTIVE_COMPLETED, COMSIG_TRAITOR_OBJECTIVE_FAILED), PROC_REF(delete_self))
- handle_mind_transferred(target)
-
-/datum/component/traitor_objective_mind_tracker/UnregisterFromParent()
- UnregisterSignal(target, COMSIG_MIND_TRANSFERRED)
- if(target.current)
- parent.UnregisterSignal(target.current, signals)
-
-/datum/component/traitor_objective_mind_tracker/proc/handle_mind_transferred(datum/source, mob/previous_body)
- SIGNAL_HANDLER
- if(current_registered_target)
- parent.UnregisterSignal(current_registered_target, signals)
-
- for(var/signal in signals)
- parent.RegisterSignal(target.current, signal, signals[signal])
-
-/datum/component/traitor_objective_mind_tracker/proc/delete_self()
- SIGNAL_HANDLER
- qdel(src)
diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm
index 2917a8202ef..920443bf0b5 100644
--- a/code/modules/antagonists/traitor/datum_traitor.dm
+++ b/code/modules/antagonists/traitor/datum_traitor.dm
@@ -23,15 +23,9 @@
var/uplink_flag_given = UPLINK_TRAITORS
var/give_objectives = TRUE
- /// Whether to give secondary objectives to the traitor, which aren't necessary but can be completed for a progression and TC boost.
- var/give_secondary_objectives = TRUE
var/should_give_codewords = TRUE
///give this traitor an uplink?
var/give_uplink = TRUE
- /// Code that allows traitor to get a replacement uplink
- var/replacement_uplink_code = ""
- /// Radio frequency that traitor must speak on to get a replacement uplink
- var/replacement_uplink_frequency = ""
///if TRUE, this traitor will always get hijacking as their final objective
var/is_hijacker = FALSE
@@ -53,17 +47,6 @@
///the final objective the traitor has to accomplish, be it escaping, hijacking, or just martyrdom.
var/datum/objective/ending_objective
-/datum/antagonist/traitor/infiltrator
- // Used to denote traitors who have joined midround and therefore have no access to secondary objectives.
- // Progression elements are best left to the roundstart antagonists
- // There will still be a timelock on uplink items
- name = "\improper Infiltrator"
- give_secondary_objectives = FALSE
- uplink_flag_given = UPLINK_INFILTRATORS
-
-/datum/antagonist/traitor/infiltrator/sleeper_agent
- name = "\improper Syndicate Sleeper Agent"
-
/datum/antagonist/traitor/New(give_objectives = TRUE)
. = ..()
src.give_objectives = give_objectives
@@ -73,7 +56,6 @@
if(give_uplink)
owner.give_uplink(silent = TRUE, antag_datum = src)
- generate_replacement_codes()
var/datum/component/uplink/uplink = owner.find_syndicate_uplink()
uplink_ref = WEAKREF(uplink)
@@ -87,10 +69,6 @@
uplink_handler.has_progression = TRUE
SStraitor.register_uplink_handler(uplink_handler)
- if(give_secondary_objectives)
- uplink_handler.has_objectives = TRUE
- uplink_handler.generate_objectives()
-
uplink_handler.can_replace_objectives = CALLBACK(src, PROC_REF(can_change_objectives))
uplink_handler.replace_objectives = CALLBACK(src, PROC_REF(submit_player_objective))
@@ -114,77 +92,20 @@
pick_employer()
- owner.teach_crafting_recipe(/datum/crafting_recipe/syndicate_uplink_beacon)
-
return ..()
/datum/antagonist/traitor/on_removal()
if(!isnull(uplink_handler))
- uplink_handler.has_objectives = FALSE
uplink_handler.can_replace_objectives = null
uplink_handler.replace_objectives = null
owner.take_uplink()
owner.special_role = null
- owner.forget_crafting_recipe(/datum/crafting_recipe/syndicate_uplink_beacon)
return ..()
-/datum/antagonist/traitor/proc/traitor_objective_to_html(datum/traitor_objective/to_display)
- var/string = "[to_display.name]"
- if(to_display.objective_state == OBJECTIVE_STATE_ACTIVE || to_display.objective_state == OBJECTIVE_STATE_INACTIVE)
- string += " [to_display.telecrystal_reward] TC"
- string += " [to_display.progression_reward] PR"
- else
- string += ", [to_display.telecrystal_reward] TC"
- string += ", [to_display.progression_reward] PR"
- if(to_display.objective_state == OBJECTIVE_STATE_ACTIVE && !istype(to_display, /datum/traitor_objective/ultimate))
- string += " Fail this objective"
- string += " Succeed this objective"
- if(to_display.objective_state == OBJECTIVE_STATE_INACTIVE)
- string += " Dispose of this objective"
-
- if(to_display.skipped)
- string += " - Skipped"
- else if(to_display.objective_state == OBJECTIVE_STATE_FAILED)
- string += " - Failed"
- else if(to_display.objective_state == OBJECTIVE_STATE_INVALID)
- string += " - Invalidated"
- else if(to_display.objective_state == OBJECTIVE_STATE_COMPLETED)
- string += " - Succeeded"
-
- return string
-
-/datum/antagonist/traitor/antag_panel_objectives()
- var/result = ..()
- if(!uplink_handler)
- return result
- result += "Traitor specific objectives "
- result += "Concluded Objectives: "
- for(var/datum/traitor_objective/objective as anything in uplink_handler.completed_objectives)
- result += "[traitor_objective_to_html(objective)] "
- if(!length(uplink_handler.completed_objectives))
- result += "EMPTY "
- result += "Ongoing Objectives: "
- for(var/datum/traitor_objective/objective as anything in uplink_handler.active_objectives)
- result += "[traitor_objective_to_html(objective)] "
- if(!length(uplink_handler.active_objectives))
- result += "EMPTY "
- result += "Potential Objectives: "
- for(var/datum/traitor_objective/objective as anything in uplink_handler.potential_objectives)
- result += "[traitor_objective_to_html(objective)] "
- if(!length(uplink_handler.potential_objectives))
- result += "EMPTY "
- result += "Force add objective "
- return result
-
/// Returns true if we're allowed to assign ourselves a new objective
/datum/antagonist/traitor/proc/can_change_objectives()
return can_assign_self_objectives
-/// proc that generates the traitors replacement uplink code and radio frequency
-/datum/antagonist/traitor/proc/generate_replacement_codes()
- replacement_uplink_code = "[pick(GLOB.phonetic_alphabet)] [rand(10,99)]"
- replacement_uplink_frequency = sanitize_frequency(rand(MIN_UNUSED_FREQ, MAX_FREQ), free = FALSE, syndie = FALSE)
-
/datum/antagonist/traitor/proc/pick_employer()
if(!employer)
var/faction = prob(75) ? FLAVOR_FACTION_SYNDICATE : FLAVOR_FACTION_NANOTRASEN
@@ -300,8 +221,6 @@
data["theme"] = traitor_flavor["ui_theme"]
data["code"] = uplink?.unlock_code
data["failsafe_code"] = uplink?.failsafe_code
- data["replacement_code"] = replacement_uplink_code
- data["replacement_frequency"] = format_frequency(replacement_uplink_frequency)
data["intro"] = traitor_flavor["introduction"]
data["allies"] = traitor_flavor["allies"]
data["goal"] = traitor_flavor["goal"]
@@ -340,9 +259,6 @@
traitor_won = FALSE
objectives_text += " Objective #[count]: [objective.explanation_text] [objective.get_roundend_success_suffix()]"
count++
- if(uplink_handler.final_objective)
- objectives_text += " [span_greentext("[traitor_won ? "Additionally" : "However"], the final objective \"[uplink_handler.final_objective]\" was completed!")]"
- traitor_won = TRUE
result += " [owner.name] [traitor_flavor["roundend_report"]]"
diff --git a/code/modules/antagonists/traitor/objective_category.dm b/code/modules/antagonists/traitor/objective_category.dm
deleted file mode 100644
index 5484d293798..00000000000
--- a/code/modules/antagonists/traitor/objective_category.dm
+++ /dev/null
@@ -1,68 +0,0 @@
-/// The traitor category handler. This is where the probability of all objectives are managed.
-/datum/traitor_category_handler
- var/list/datum/traitor_objective_category/all_categories = list()
-
-/datum/traitor_category_handler/New()
- . = ..()
- for(var/type in subtypesof(/datum/traitor_objective_category))
- var/datum/traitor_objective_category/category = new type()
- if(length(category.objectives))
- all_categories += category
- else
- // Category should just get autoGC'd here if they don't have any length, this may not be necessary
- qdel(category)
-
-/datum/traitor_category_handler/proc/objective_valid(datum/traitor_objective/objective_path, progression_points)
- if(initial(objective_path.abstract_type) == objective_path)
- return FALSE
- if(progression_points < initial(objective_path.progression_minimum))
- return FALSE
- if(progression_points > initial(objective_path.progression_maximum))
- return FALSE
- return TRUE
-
-/datum/traitor_category_handler/proc/get_possible_objectives(progression_points)
- var/list/valid_objectives = list()
- for(var/datum/traitor_objective_category/category as anything in all_categories)
- var/list/category_list = list()
- for(var/value in category.objectives)
- if(islist(value))
- var/list/objective_category = filter_invalid_objective_list(value, progression_points)
- if(!length(objective_category))
- continue
- category_list[objective_category] = category.objectives[value]
- else
- if(!objective_valid(value, progression_points))
- continue
- category_list[value] = category.objectives[value]
- if(!length(category_list))
- continue
- valid_objectives[category_list] = category.weight
-
- return valid_objectives
-
-/datum/traitor_category_handler/proc/filter_invalid_objective_list(list/objectives, progression_points)
- var/list/filtered_objectives = list()
- for(var/value in objectives)
- if(islist(value))
- var/list/result = filter_invalid_objective_list(value, progression_points)
- if(!length(result))
- continue
- filtered_objectives[result] = objectives[value]
- else
- if(!objective_valid(value, progression_points))
- continue
- filtered_objectives[value] = objectives[value]
- return filtered_objectives
-
-/// The objective category.
-/// Used to group up entire objectives into 1 weight objects to prevent having a
-/// higher chance of getting an objective due to an increased number of different objective subtypes.
-/// These are nothing but informational holders and will have no other purpose.
-/datum/traitor_objective_category
- /// Name of the category, unused but may help in the future
- var/name = "generic category"
- /// Assoc list of objectives by type mapped to their weight. Can also contain lists of objectives mapped to weight
- var/list/objectives = list()
- /// The weight of the category. How likely this category is to be chosen.
- var/weight = OBJECTIVE_WEIGHT_DEFAULT
diff --git a/code/modules/antagonists/traitor/objectives/abstract/target_player.dm b/code/modules/antagonists/traitor/objectives/abstract/target_player.dm
deleted file mode 100644
index c08f8cd46ee..00000000000
--- a/code/modules/antagonists/traitor/objectives/abstract/target_player.dm
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * The point of this datum is to act as a means to group target player objectives
- * Not all 'target player' objectives have to be under this subtype, it's only used if you don't want duplicates among the current
- * children types under this type.
- */
-/datum/traitor_objective/target_player
- abstract_type = /datum/traitor_objective/target_player
-
- progression_minimum = 30 MINUTES
-
- // The code below is for limiting how often you can get this objective. You will get this objective at a maximum of maximum_objectives_in_period every objective_period
- /// The objective period at which we consider if it is an 'objective'. Set to 0 to accept all objectives.
- var/objective_period = 15 MINUTES
- /// The maximum number of objectives we can get within this period.
- var/maximum_objectives_in_period = 4
-
- /// The target that we need to target.
- var/mob/living/target
-
-/datum/traitor_objective/target_player/Destroy(force)
- set_target(null)
- return ..()
-
-/datum/traitor_objective/target_player/proc/set_target(mob/living/new_target)
- if(target)
- UnregisterSignal(target, COMSIG_QDELETING)
- target = new_target
- if(target)
- RegisterSignal(target, COMSIG_QDELETING, PROC_REF(target_deleted))
-
-/datum/traitor_objective/target_player/proc/target_deleted(datum/source)
- SIGNAL_HANDLER
- set_target(null)
diff --git a/code/modules/antagonists/traitor/objectives/assassination.dm b/code/modules/antagonists/traitor/objectives/assassination.dm
deleted file mode 100644
index 5d5cdbd1981..00000000000
--- a/code/modules/antagonists/traitor/objectives/assassination.dm
+++ /dev/null
@@ -1,205 +0,0 @@
-/datum/traitor_objective_category/assassinate_kidnap
- name = "Assassination/Kidnap"
- objectives = list(
- list(
- /datum/traitor_objective/target_player/assassinate/calling_card = 1,
- /datum/traitor_objective/target_player/assassinate/calling_card/heads_of_staff = 1,
- ) = 1,
- list(
- list(
- /datum/traitor_objective/target_player/kidnapping/common = 20,
- /datum/traitor_objective/target_player/kidnapping/common/assistant = 1,
- ) = 4,
- /datum/traitor_objective/target_player/kidnapping/uncommon = 3,
- /datum/traitor_objective/target_player/kidnapping/rare = 2,
- /datum/traitor_objective/target_player/kidnapping/captain = 1
- ) = 1,
- )
-
-/datum/traitor_objective/target_player/assassinate
- name = "Assassinate %TARGET% the %JOB TITLE%"
- description = "Simply kill your target to accomplish this objective."
-
- abstract_type = /datum/traitor_objective/target_player/assassinate
-
- progression_minimum = 30 MINUTES
-
- /**
- * Makes the objective only set heads as targets when true, and block them from being targets when false.
- * This also blocks the objective from generating UNTIL the un-heads_of_staff version (WHICH SHOULD BE A DIRECT PARENT) is completed.
- * example: calling card objective, you kill someone, you unlock the chance to roll a head of staff target version of calling card.
- */
- var/heads_of_staff = FALSE
-
- duplicate_type = /datum/traitor_objective/target_player
-
-/datum/traitor_objective/target_player/assassinate/supported_configuration_changes()
- . = ..()
- . += NAMEOF(src, objective_period)
- . += NAMEOF(src, maximum_objectives_in_period)
-
-/datum/traitor_objective/target_player/assassinate/calling_card
- name = "Assassinate %TARGET% the %JOB TITLE%, and plant a calling card"
- description = "Kill your target and plant a calling card in the pockets of your victim. If your calling card gets destroyed before you are able to plant it, this objective will fail."
- progression_reward = 2 MINUTES
- telecrystal_reward = list(1, 2)
-
- var/obj/item/paper/calling_card/card
-
-/datum/traitor_objective/target_player/assassinate/calling_card/heads_of_staff
- progression_reward = 4 MINUTES
- telecrystal_reward = list(2, 3)
-
- heads_of_staff = TRUE
-
-/datum/traitor_objective/target_player/assassinate/calling_card/generate_ui_buttons(mob/user)
- var/list/buttons = list()
- if(!card)
- buttons += add_ui_button("", "Pressing this will materialize a calling card, which you must plant to succeed.", "paper-plane", "summon_card")
- return buttons
-
-/datum/traitor_objective/target_player/assassinate/calling_card/ui_perform_action(mob/living/user, action)
- . = ..()
- switch(action)
- if("summon_card")
- if(card)
- return
- card = new(user.drop_location())
- user.put_in_hands(card)
- card.balloon_alert(user, "the card materializes in your hand")
- RegisterSignal(card, COMSIG_ITEM_EQUIPPED, PROC_REF(on_card_planted))
- AddComponent(/datum/component/traitor_objective_register, card, \
- succeed_signals = null, \
- fail_signals = list(COMSIG_QDELETING), \
- penalty = TRUE)
-
-/datum/traitor_objective/target_player/assassinate/calling_card/proc/on_card_planted(datum/source, mob/living/equipper, slot)
- SIGNAL_HANDLER
- if(equipper != target)
- return //your target please
- if(equipper.stat != DEAD)
- return //kill them please
- if(!(slot & (ITEM_SLOT_LPOCKET|ITEM_SLOT_RPOCKET)))
- return //in their pockets please
- succeed_objective()
-
-/datum/traitor_objective/target_player/assassinate/calling_card/ungenerate_objective()
- . = ..() //unsets kill target
- if(card)
- UnregisterSignal(card, COMSIG_ITEM_EQUIPPED)
- card = null
-
-/datum/traitor_objective/target_player/assassinate/calling_card/target_deleted()
- //you cannot plant anything on someone who is gone gone, so even if this happens after you're still liable to fail
- fail_objective(penalty_cost = telecrystal_penalty)
-
-/datum/traitor_objective/target_player/assassinate/New(datum/uplink_handler/handler)
- . = ..()
- AddComponent(/datum/component/traitor_objective_limit_per_time, \
- /datum/traitor_objective/target_player, \
- time_period = objective_period, \
- maximum_objectives = maximum_objectives_in_period \
- )
-
-/datum/traitor_objective/target_player/assassinate/generate_objective(datum/mind/generating_for, list/possible_duplicates)
-
- var/list/already_targeting = list() //List of minds we're already targeting. The possible_duplicates is a list of objectives, so let's not mix things
- for(var/datum/objective/task as anything in handler.primary_objectives)
- if(!istype(task.target, /datum/mind))
- continue
- already_targeting += task.target //Removing primary objective kill targets from the list
-
- var/parent_type = type2parent(type)
- //don't roll head of staff types if you haven't completed the normal version
- if(heads_of_staff && !handler.get_completion_count(parent_type))
- // Locked if they don't have any of the risky bug room objective completed
- return FALSE
-
- var/list/possible_targets = list()
- var/try_target_late_joiners = FALSE
- if(generating_for.late_joiner)
- try_target_late_joiners = TRUE
- for(var/datum/mind/possible_target as anything in get_crewmember_minds())
- if(possible_target in already_targeting)
- continue
- var/target_area = get_area(possible_target.current)
- if(possible_target == generating_for)
- continue
- if(!ishuman(possible_target.current))
- continue
- if(possible_target.current.stat == DEAD)
- continue
- var/datum/antagonist/traitor/traitor = possible_target.has_antag_datum(/datum/antagonist/traitor)
- if(traitor && traitor.uplink_handler.telecrystals >= 0)
- continue
- if(!HAS_TRAIT(SSstation, STATION_TRAIT_LATE_ARRIVALS) && istype(target_area, /area/shuttle/arrival))
- continue
- //removes heads of staff from being targets from non heads of staff assassinations, and vice versa
- if(heads_of_staff)
- if(!(possible_target.assigned_role.job_flags & JOB_HEAD_OF_STAFF))
- continue
- else
- if((possible_target.assigned_role.job_flags & JOB_HEAD_OF_STAFF))
- continue
- possible_targets += possible_target
- for(var/datum/traitor_objective/target_player/objective as anything in possible_duplicates)
- possible_targets -= objective.target
- if(try_target_late_joiners)
- var/list/all_possible_targets = possible_targets.Copy()
- for(var/datum/mind/possible_target as anything in all_possible_targets)
- if(!possible_target.late_joiner)
- possible_targets -= possible_target
- if(!possible_targets.len)
- possible_targets = all_possible_targets
- special_target_filter(possible_targets)
- if(!possible_targets.len)
- return FALSE //MISSION FAILED, WE'LL GET EM NEXT TIME
-
- var/datum/mind/target_mind = pick(possible_targets)
- set_target(target_mind.current)
- replace_in_name("%TARGET%", target.real_name)
- replace_in_name("%JOB TITLE%", target_mind.assigned_role.title)
- RegisterSignal(target, COMSIG_LIVING_DEATH, PROC_REF(on_target_death))
- return TRUE
-
-/datum/traitor_objective/target_player/assassinate/ungenerate_objective()
- UnregisterSignal(target, COMSIG_LIVING_DEATH)
- set_target(null)
-
-///proc for checking for special states that invalidate a target
-/datum/traitor_objective/target_player/assassinate/proc/special_target_filter(list/possible_targets)
- return
-
-/datum/traitor_objective/target_player/assassinate/target_deleted()
- if(objective_state == OBJECTIVE_STATE_INACTIVE)
- //don't take an objective target of someone who is already obliterated
- fail_objective()
- return ..()
-
-/datum/traitor_objective/target_player/assassinate/proc/on_target_death()
- SIGNAL_HANDLER
- if(objective_state == OBJECTIVE_STATE_INACTIVE)
- //don't take an objective target of someone who is already dead
- fail_objective()
-
-/obj/item/paper/calling_card
- name = "calling card"
- icon_state = "syndicate_calling_card"
- color = "#ff5050"
- show_written_words = FALSE
- default_raw_text = {"
- **Death to Nanotrasen.**
-
- Only through the inviolable cooperation of corporations known as The Syndicate, can Nanotrasen and its autocratic tyrants be silenced.
- The outcries of Nanotrasen's employees are squelched by the suffocating iron grip of their leaders. If you read this, and understand
- why we fight, then you need only to look where Nanotrasen doesn't want you to find us to join our cause. Any number of our companies
- may be fighting with your interests in mind.
-
- SELF: They fight for the protection and freedom of silicon life all across the galaxy.
-
- Tiger Cooperative: They fight for religious freedom and their righteous concoctions.
-
- Waffle Corporation: They fight for the return of healthy corporate competition, snuffed out by Nanotrasen's monopoly.
-
- Animal Rights Consortium: They fight for nature and the right for all biological life to exist.
- "}
diff --git a/code/modules/antagonists/traitor/objectives/demoralise_assault.dm b/code/modules/antagonists/traitor/objectives/demoralise_assault.dm
deleted file mode 100644
index fe26864e4fc..00000000000
--- a/code/modules/antagonists/traitor/objectives/demoralise_assault.dm
+++ /dev/null
@@ -1,129 +0,0 @@
-/datum/traitor_objective_category/demoralise
- name = "Demoralise Crew"
- objectives = list(
- /datum/traitor_objective/target_player/assault = 1,
- /datum/traitor_objective/destroy_item/demoralise = 1,
- )
- weight = OBJECTIVE_WEIGHT_UNLIKELY
-
-/datum/traitor_objective/target_player/assault
- name = "Assault %TARGET% the %JOB TITLE%"
- description = "%TARGET% has been identified as a potential future agent. \
- Pick a fight and give them a good beating. \
- %COUNT% hits should reduce their morale and have them questioning their loyalties. \
- Try not to kill them just yet, we may want to recruit them in the future."
-
- abstract_type = /datum/traitor_objective/target_player
- duplicate_type = /datum/traitor_objective/target_player
-
- progression_minimum = 0 MINUTES
- progression_maximum = 30 MINUTES
- progression_reward = list(4 MINUTES, 8 MINUTES)
- telecrystal_reward = list(0, 1)
-
- /// Min attacks required to pass the objective. Picked at random between this and max.
- var/min_attacks_required = 2
- /// Max attacks required to pass the objective. Picked at random between this and min.
- var/max_attacks_required = 5
- /// The random number picked for the number of required attacks to pass this objective.
- var/attacks_required = 0
- /// Total number of successful attacks recorded.
- var/attacks_inflicted = 0
-
-/datum/traitor_objective/target_player/assault/on_objective_taken(mob/user)
- . = ..()
-
- target.AddElement(/datum/element/relay_attackers)
- RegisterSignal(target, COMSIG_ATOM_WAS_ATTACKED, PROC_REF(on_attacked))
-
-/datum/traitor_objective/target_player/assault/proc/on_attacked(mob/source, mob/living/attacker, attack_flags)
- SIGNAL_HANDLER
-
- // Only care about attacks from the objective's owner.
- if(attacker != handler.owner.current)
- return
-
- // We want some sort of damaging attack to trigger this, rather than shoves and non-lethals.
- if(!(attack_flags & ATTACKER_DAMAGING_ATTACK))
- return
-
- attacks_inflicted++
-
- if(attacks_inflicted == attacks_required)
- succeed_objective()
-
-/datum/traitor_objective/target_player/assault/ungenerate_objective()
- UnregisterSignal(target, COMSIG_ATOM_WAS_ATTACKED)
- UnregisterSignal(target, COMSIG_LIVING_DEATH)
- set_target(null)
-
-/datum/traitor_objective/target_player/assault/generate_objective(datum/mind/generating_for, list/possible_duplicates)
- var/list/already_targeting = list() //List of minds we're already targeting. The possible_duplicates is a list of objectives, so let's not mix things
- for(var/datum/objective/task as anything in handler.primary_objectives)
- if(!istype(task.target, /datum/mind))
- continue
- already_targeting += task.target //Removing primary objective kill targets from the list
-
- var/list/possible_targets = list()
-
- for(var/datum/mind/possible_target as anything in get_crewmember_minds())
- if(possible_target in already_targeting)
- continue
-
- if(possible_target == generating_for)
- continue
-
- if(!ishuman(possible_target.current))
- continue
-
- if(possible_target.current.stat == DEAD)
- continue
-
- if(possible_target.has_antag_datum(/datum/antagonist/traitor))
- continue
-
- possible_targets += possible_target
-
- for(var/datum/traitor_objective/target_player/objective as anything in possible_duplicates)
- possible_targets -= objective.target?.mind
-
- if(generating_for.late_joiner)
- var/list/all_possible_targets = possible_targets.Copy()
- for(var/datum/mind/possible_target as anything in all_possible_targets)
- if(!possible_target.late_joiner)
- possible_targets -= possible_target
- if(!possible_targets.len)
- possible_targets = all_possible_targets
-
- if(!possible_targets.len)
- return FALSE
-
- var/datum/mind/target_mind = pick(possible_targets)
-
- set_target(target_mind.current)
- replace_in_name("%TARGET%", target.real_name)
- replace_in_name("%JOB TITLE%", target_mind.assigned_role.title)
-
- attacks_required = rand(min_attacks_required, max_attacks_required)
- replace_in_name("%COUNT%", attacks_required)
-
- RegisterSignal(target, COMSIG_LIVING_DEATH, PROC_REF(on_target_death))
-
- return TRUE
-
-/datum/traitor_objective/target_player/assault/generate_ui_buttons(mob/user)
- var/list/buttons = list()
- if(attacks_required > attacks_inflicted)
- buttons += add_ui_button("[attacks_required - attacks_inflicted]", "This tells you how many more times you have to attack the target player to succeed.", "hand-rock-o", "none")
- return buttons
-
-/datum/traitor_objective/target_player/assault/target_deleted()
- //don't take an objective target of someone who is already obliterated
- fail_objective()
- return ..()
-
-/datum/traitor_objective/target_player/assault/proc/on_target_death()
- SIGNAL_HANDLER
-
- //don't take an objective target of someone who is already dead
- fail_objective()
diff --git a/code/modules/antagonists/traitor/objectives/destroy_heirloom.dm b/code/modules/antagonists/traitor/objectives/destroy_heirloom.dm
deleted file mode 100644
index 9182f23a649..00000000000
--- a/code/modules/antagonists/traitor/objectives/destroy_heirloom.dm
+++ /dev/null
@@ -1,153 +0,0 @@
-/datum/traitor_objective_category/destroy_heirloom
- name = "Destroy Heirloom"
- objectives = list(
- list(
- // There's about 16 jobs in common, so assistant has a 1/21 chance of getting chosen.
- /datum/traitor_objective/destroy_heirloom/common = 20,
- /datum/traitor_objective/destroy_heirloom/common/assistant = 1,
- ) = 4,
- /datum/traitor_objective/destroy_heirloom/uncommon = 3,
- /datum/traitor_objective/destroy_heirloom/rare = 2,
- /datum/traitor_objective/destroy_heirloom/captain = 1
- )
-
-/datum/traitor_objective/destroy_heirloom
- name = "Destroy %ITEM%, the family heirloom that belongs to %TARGET% the %JOB TITLE%"
- description = "%TARGET% has been on our shitlist for a while and we want to show them we mean business. Find their %ITEM% and destroy it."
-
- abstract_type = /datum/traitor_objective/destroy_heirloom
-
- /// The jobs that this objective is targeting.
- var/list/target_jobs
- /// the item we need to destroy
- var/obj/item/target_item
- /// the owner of the item we need to destroy
- var/datum/mind/target_mind
-
- // The code below is for limiting how often you can get this objective. You will get this objective at a maximum of maximum_objectives_in_period every objective_period
- /// The objective period at which we consider if it is an 'objective'. Set to 0 to accept all objectives.
- var/objective_period = 10 MINUTES
- /// The maximum number of objectives that can be taken in this period.
- var/maximum_objectives_in_period = 2
-
- duplicate_type = /datum/traitor_objective/destroy_heirloom
-
-/datum/traitor_objective/destroy_heirloom/common
- /// 30 minutes in, syndicate won't care about common heirlooms anymore
- progression_minimum = 0 MINUTES
- progression_maximum = 30 MINUTES
- progression_reward = list(8 MINUTES, 12 MINUTES)
- telecrystal_reward = list(1, 2)
- target_jobs = list(
- // Medical
- /datum/job/doctor,
- /datum/job/paramedic,
- /datum/job/psychologist,
- /datum/job/chemist,
- /datum/job/coroner,
- // Service
- /datum/job/clown,
- /datum/job/botanist,
- /datum/job/janitor,
- /datum/job/mime,
- /datum/job/lawyer,
- // Cargo
- /datum/job/cargo_technician,
- // Science
- /datum/job/geneticist,
- /datum/job/scientist,
- /datum/job/roboticist,
- // Engineering
- /datum/job/station_engineer,
- /datum/job/atmospheric_technician,
- )
-
-/// This is only for assistants, because the syndies are a lot less likely to give a shit about what an assistant does, so they're a lot less likely to appear
-/datum/traitor_objective/destroy_heirloom/common/assistant
- target_jobs = list(
- /datum/job/assistant
- )
-
-/datum/traitor_objective/destroy_heirloom/uncommon
- /// 45 minutes in, syndicate won't care about uncommon heirlooms anymore
- progression_minimum = 0 MINUTES
- progression_maximum = 45 MINUTES
- progression_reward = list(8 MINUTES, 12 MINUTES)
- telecrystal_reward = list(1, 2)
- target_jobs = list(
- // Cargo
- /datum/job/bitrunner,
- /datum/job/shaft_miner,
- // Service
- /datum/job/chaplain,
- /datum/job/bartender,
- /datum/job/cook,
- /datum/job/curator,
- )
-
-/datum/traitor_objective/destroy_heirloom/rare
- progression_minimum = 15 MINUTES
- /// 60 minutes in, syndicate won't care about rare heirlooms anymore
- progression_maximum = 60 MINUTES
- progression_reward = list(10 MINUTES, 14 MINUTES)
- telecrystal_reward = list(2, 3)
- target_jobs = list(
- // Security
- /datum/job/security_officer,
- /datum/job/warden,
- /datum/job/detective,
- // Heads of staff
- /datum/job/head_of_personnel,
- /datum/job/chief_medical_officer,
- /datum/job/research_director,
- /datum/job/quartermaster,
- /datum/job/chief_engineer,
- )
-
-/datum/traitor_objective/destroy_heirloom/captain
- progression_minimum = 30 MINUTES
- progression_reward = list(10 MINUTES, 14 MINUTES)
- telecrystal_reward = 4
- target_jobs = list(
- /datum/job/head_of_security,
- /datum/job/captain
- )
-
-/datum/traitor_objective/destroy_heirloom/New(datum/uplink_handler/handler)
- . = ..()
- AddComponent(/datum/component/traitor_objective_limit_per_time, \
- /datum/traitor_objective/destroy_heirloom, \
- time_period = objective_period, \
- maximum_objectives = maximum_objectives_in_period \
- )
-
-/datum/traitor_objective/destroy_heirloom/generate_objective(datum/mind/generating_for, list/possible_duplicates)
- var/list/possible_targets = list()
- for(var/datum/mind/possible_target as anything in get_crewmember_minds())
- if(possible_target == generating_for)
- continue
- if(!ishuman(possible_target.current))
- continue
- var/datum/quirk/item_quirk/family_heirloom/quirk = locate() in possible_target.current.quirks
- if(!quirk || !quirk.heirloom.resolve())
- continue
- if(!(possible_target.assigned_role.type in target_jobs))
- continue
- possible_targets += possible_target
- for(var/datum/traitor_objective/destroy_heirloom/objective as anything in possible_duplicates)
- possible_targets -= objective.target_mind
- if(!length(possible_targets))
- return FALSE
- target_mind = pick(possible_targets)
- AddComponent(/datum/component/traitor_objective_register, target_mind.current, fail_signals = list(COMSIG_QDELETING))
- var/datum/quirk/item_quirk/family_heirloom/quirk = locate() in target_mind.current.quirks
- target_item = quirk.heirloom.resolve()
- AddComponent(/datum/component/traitor_objective_register, target_item, succeed_signals = list(COMSIG_QDELETING))
- replace_in_name("%TARGET%", target_mind.name)
- replace_in_name("%JOB TITLE%", target_mind.assigned_role.title)
- replace_in_name("%ITEM%", target_item.name)
- return TRUE
-
-/datum/traitor_objective/destroy_heirloom/ungenerate_objective()
- target_item = null
- target_mind = null
diff --git a/code/modules/antagonists/traitor/objectives/destroy_item.dm b/code/modules/antagonists/traitor/objectives/destroy_item.dm
deleted file mode 100644
index 2c53f3d6b8c..00000000000
--- a/code/modules/antagonists/traitor/objectives/destroy_item.dm
+++ /dev/null
@@ -1,112 +0,0 @@
-/datum/traitor_objective/destroy_item
- name = "Steal %ITEM% and destroy it"
- description = "Find %ITEM% and destroy it using any means necessary. We can't allow the crew to have %ITEM% as it conflicts with our interests. %METHOD%"
-
- var/list/possible_items = list()
- /// The current target item that we are stealing.
- var/datum/objective_item/steal/target_item
- /// Any special equipment that may be needed
- var/list/special_equipment
- /// Items that are currently tracked and will succeed this objective when destroyed.
- var/list/tracked_items = list()
-
- abstract_type = /datum/traitor_objective/destroy_item
-
-/datum/traitor_objective/destroy_item/low_risk
- progression_minimum = 10 MINUTES
- progression_maximum = 35 MINUTES
- progression_reward = list(5 MINUTES, 10 MINUTES)
- telecrystal_reward = 1
-
- possible_items = list(
- /datum/objective_item/steal/traitor/bartender_shotgun,
- /datum/objective_item/steal/traitor/fireaxe,
- /datum/objective_item/steal/traitor/nullrod,
- /datum/objective_item/steal/traitor/big_crowbar,
- )
-
-/datum/traitor_objective/destroy_item/very_risky
- progression_minimum = 40 MINUTES
- progression_reward = 15 MINUTES
- telecrystal_reward = list(6, 9)
- possible_items = list(
- /datum/objective_item/steal/blackbox,
- )
-
-/// Super early-game destroy objective intended to be items easily tided that the crew tends to value.
-/datum/traitor_objective/destroy_item/demoralise
- description = "Find %ITEM% and destroy it using any means necessary. \
- We believe this luxury item is important for crew morale. \
- Destruction of this item will help our recruitment efforts."
-
- progression_minimum = 0 MINUTES
- progression_maximum = 10 MINUTES
- progression_reward = list(4 MINUTES, 8 MINUTES)
- telecrystal_reward = list(0, 1)
-
- possible_items = list(
- /datum/objective_item/steal/traitor/rpd,
- /datum/objective_item/steal/traitor/space_law,
- /datum/objective_item/steal/traitor/granted_stamp,
- /datum/objective_item/steal/traitor/denied_stamp,
- /datum/objective_item/steal/traitor/lizard_plush,
- /datum/objective_item/steal/traitor/moth_plush,
- /datum/objective_item/steal/traitor/insuls,
- )
-
-/datum/traitor_objective/destroy_item/generate_objective(datum/mind/generating_for, list/possible_duplicates)
- for(var/datum/traitor_objective/destroy_item/objective as anything in possible_duplicates)
- possible_items -= objective.target_item.type
- while(length(possible_items))
- var/datum/objective_item/steal/target = pick_n_take(possible_items)
- target = new target()
- if(!target.valid_objective_for(list(generating_for), require_owner = TRUE))
- qdel(target)
- continue
- target_item = target
- break
- if(!target_item)
- return FALSE
- if(target_item.exists_on_map)
- var/list/items = GLOB.steal_item_handler.objectives_by_path[target_item.targetitem]
- for(var/obj/item/item as anything in items)
- AddComponent(/datum/component/traitor_objective_register, item, succeed_signals = list(COMSIG_QDELETING))
- tracked_items += item
- if(length(target_item.special_equipment))
- special_equipment = target_item.special_equipment
- replace_in_name("%ITEM%", target_item.name)
- if(target_item.destruction_method != null)
- replace_in_name("%METHOD%", target_item.destruction_method)
- else
- replace_in_name("%METHOD%", "This item can be destroyed normally, such as by using a recycler, found in disposals.")
- AddComponent(/datum/component/traitor_objective_mind_tracker, generating_for, \
- signals = list(COMSIG_MOB_EQUIPPED_ITEM = PROC_REF(on_item_pickup)))
- return TRUE
-
-/datum/traitor_objective/destroy_item/generate_ui_buttons(mob/user)
- var/list/buttons = list()
- if(special_equipment)
- buttons += add_ui_button("", "Pressing this will summon any extra special equipment you may need for the mission.", "tools", "summon_gear")
- return buttons
-
-/datum/traitor_objective/destroy_item/ui_perform_action(mob/living/user, action)
- . = ..()
- switch(action)
- if("summon_gear")
- if(!special_equipment)
- return
- for(var/item in special_equipment)
- var/obj/item/new_item = new item(user.drop_location())
- user.put_in_hands(new_item)
- user.balloon_alert(user, "the equipment materializes in your hand")
- special_equipment = null
-
-/datum/traitor_objective/destroy_item/proc/on_item_pickup(datum/source, obj/item/item, slot)
- SIGNAL_HANDLER
- if(istype(item, target_item.targetitem) && !(item in tracked_items))
- AddComponent(/datum/component/traitor_objective_register, item, succeed_signals = list(COMSIG_QDELETING))
- tracked_items += item
-
-/datum/traitor_objective/destroy_item/ungenerate_objective()
- tracked_items.Cut()
- return ..()
diff --git a/code/modules/antagonists/traitor/objectives/eyesnatching.dm b/code/modules/antagonists/traitor/objectives/eyesnatching.dm
deleted file mode 100644
index 2ddad4913f0..00000000000
--- a/code/modules/antagonists/traitor/objectives/eyesnatching.dm
+++ /dev/null
@@ -1,240 +0,0 @@
-/datum/traitor_objective_category/eyesnatching
- name = "Eyesnatching"
- objectives = list(
- /datum/traitor_objective/target_player/eyesnatching = 1,
- /datum/traitor_objective/target_player/eyesnatching/heads = 1,
- )
- weight = OBJECTIVE_WEIGHT_UNLIKELY
-
-/datum/traitor_objective/target_player/eyesnatching
- name = "Steal the eyes of %TARGET% the %JOB TITLE%"
- description = "%TARGET% messed with the wrong people. Steal their eyes to teach them a lesson. You will be provided an experimental eyesnatcher device to aid you in your mission."
-
- progression_minimum = 10 MINUTES
-
- progression_reward = list(4 MINUTES, 8 MINUTES)
- telecrystal_reward = list(1, 2)
-
- /// If we're targeting heads of staff or not
- var/heads_of_staff = FALSE
- /// Have we already spawned an eyesnatcher
- var/spawned_eyesnatcher = FALSE
-
- duplicate_type = /datum/traitor_objective/target_player
-
-/datum/traitor_objective/target_player/eyesnatching/supported_configuration_changes()
- . = ..()
- . += NAMEOF(src, objective_period)
- . += NAMEOF(src, maximum_objectives_in_period)
-
-/datum/traitor_objective/target_player/eyesnatching/New(datum/uplink_handler/handler)
- . = ..()
- AddComponent(/datum/component/traitor_objective_limit_per_time, \
- /datum/traitor_objective/target_player, \
- time_period = objective_period, \
- maximum_objectives = maximum_objectives_in_period \
- )
-
-/datum/traitor_objective/target_player/eyesnatching/heads
- progression_reward = list(6 MINUTES, 12 MINUTES)
- telecrystal_reward = list(2, 3)
-
- heads_of_staff = TRUE
-
-/datum/traitor_objective/target_player/eyesnatching/generate_objective(datum/mind/generating_for, list/possible_duplicates)
-
- var/list/already_targeting = list() //List of minds we're already targeting. The possible_duplicates is a list of objectives, so let's not mix things
- for(var/datum/objective/task as anything in handler.primary_objectives)
- if(!istype(task.target, /datum/mind))
- continue
- already_targeting += task.target //Removing primary objective kill targets from the list
-
- var/list/possible_targets = list()
- var/try_target_late_joiners = FALSE
- if(generating_for.late_joiner)
- try_target_late_joiners = TRUE
-
- for(var/datum/mind/possible_target as anything in get_crewmember_minds())
- if(possible_target == generating_for)
- continue
-
- if(possible_target in already_targeting)
- continue
-
- if(!ishuman(possible_target.current))
- continue
-
- if(possible_target.current.stat == DEAD)
- continue
-
- if(possible_target.has_antag_datum(/datum/antagonist/traitor))
- continue
-
- if(!possible_target.assigned_role)
- continue
-
- if(heads_of_staff)
- if(!(possible_target.assigned_role.job_flags & JOB_HEAD_OF_STAFF))
- continue
- else
- if(possible_target.assigned_role.job_flags & JOB_HEAD_OF_STAFF)
- continue
-
- var/mob/living/carbon/human/targets_current = possible_target.current
- if(!targets_current.get_organ_by_type(/obj/item/organ/eyes))
- continue
-
- possible_targets += possible_target
-
- for(var/datum/traitor_objective/target_player/objective as anything in possible_duplicates)
- possible_targets -= objective.target?.mind
-
- if(try_target_late_joiners)
- var/list/all_possible_targets = possible_targets.Copy()
- for(var/datum/mind/possible_target as anything in all_possible_targets)
- if(!possible_target.late_joiner)
- possible_targets -= possible_target
-
- if(!possible_targets.len)
- possible_targets = all_possible_targets
-
- if(!possible_targets.len)
- return FALSE //MISSION FAILED, WE'LL GET EM NEXT TIME
-
- var/datum/mind/target_mind = pick(possible_targets)
- set_target(target_mind.current)
-
- replace_in_name("%TARGET%", target_mind.name)
- replace_in_name("%JOB TITLE%", target_mind.assigned_role.title)
- RegisterSignal(target, COMSIG_CARBON_LOSE_ORGAN, PROC_REF(check_eye_removal))
- AddComponent(/datum/component/traitor_objective_register, target, fail_signals = list(COMSIG_QDELETING))
- return TRUE
-
-/datum/traitor_objective/target_player/eyesnatching/proc/check_eye_removal(datum/source, obj/item/organ/eyes/removed)
- SIGNAL_HANDLER
-
- if(!istype(removed))
- return
-
- succeed_objective()
-
-/datum/traitor_objective/target_player/eyesnatching/generate_ui_buttons(mob/user)
- var/list/buttons = list()
- if(!spawned_eyesnatcher)
- buttons += add_ui_button("", "Pressing this will materialize an eyesnatcher, which can be used on incapacitaded or restrained targets to forcefully remove their eyes.", "syringe", "eyesnatcher")
- return buttons
-
-/datum/traitor_objective/target_player/eyesnatching/ui_perform_action(mob/living/user, action)
- . = ..()
- switch(action)
- if("eyesnatcher")
- if(spawned_eyesnatcher)
- return
- spawned_eyesnatcher = TRUE
- var/obj/item/eyesnatcher/eyesnatcher = new(user.drop_location())
- user.put_in_hands(eyesnatcher)
- eyesnatcher.balloon_alert(user, "the snatcher materializes in your hand")
-
-/obj/item/eyesnatcher
- name = "portable eyeball extractor"
- desc = "An overly complicated device that can pierce target's skull and extract their eyeballs if enough brute force is applied."
- icon = 'icons/obj/medical/surgery_tools.dmi'
- icon_state = "eyesnatcher"
- base_icon_state = "eyesnatcher"
- inhand_icon_state = "hypo"
- lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
- throwforce = 0
- w_class = WEIGHT_CLASS_SMALL
- throw_speed = 3
- throw_range = 5
- ///Whether it's been used to steal a pair of eyes already.
- var/used = FALSE
-
-/obj/item/eyesnatcher/update_icon_state()
- . = ..()
- icon_state = "[base_icon_state][used ? "-used" : ""]"
-
-/obj/item/eyesnatcher/attack(mob/living/carbon/human/target, mob/living/user, params)
- if(used || !istype(target) || !target.Adjacent(user)) //Works only once, no TK use
- return ..()
-
- var/obj/item/organ/eyes/eyeballies = target.get_organ_slot(ORGAN_SLOT_EYES)
- var/obj/item/bodypart/head/head = target.get_bodypart(BODY_ZONE_HEAD)
-
- if(!head || !eyeballies || target.is_eyes_covered())
- return ..()
- var/eye_snatch_enthusiasm = 5 SECONDS
- if(HAS_MIND_TRAIT(user, TRAIT_MORBID))
- eye_snatch_enthusiasm *= 0.7
- user.do_attack_animation(target, used_item = src)
- target.visible_message(
- span_warning("[user] presses [src] against [target]'s skull!"),
- span_userdanger("[user] presses [src] against your skull!"))
- if(!do_after(user, eye_snatch_enthusiasm, target = target, extra_checks = CALLBACK(src, PROC_REF(eyeballs_exist), eyeballies, head, target)))
- return
-
- to_chat(target, span_userdanger("You feel something forcing its way into your skull!"))
- balloon_alert(user, "applying pressure...")
- if(!do_after(user, eye_snatch_enthusiasm, target = target, extra_checks = CALLBACK(src, PROC_REF(eyeballs_exist), eyeballies, head, target)))
- return
-
- var/min_wound = head.get_wound_threshold_of_wound_type(WOUND_BLUNT, WOUND_SEVERITY_SEVERE, return_value_if_no_wound = 30, wound_source = src)
- var/max_wound = head.get_wound_threshold_of_wound_type(WOUND_BLUNT, WOUND_SEVERITY_CRITICAL, return_value_if_no_wound = 50, wound_source = src)
-
- target.apply_damage(20, BRUTE, BODY_ZONE_HEAD, wound_bonus = rand(min_wound, max_wound + 10), attacking_item = src)
- target.visible_message(
- span_danger("[src] pierces through [target]'s skull, horribly mutilating their eyes!"),
- span_userdanger("Something penetrates your skull, horribly mutilating your eyes! Holy fuck!"),
- span_hear("You hear a sickening sound of metal piercing flesh!")
- )
- eyeballies.apply_organ_damage(eyeballies.maxHealth)
- target.emote("scream")
- playsound(target, 'sound/effects/wounds/crackandbleed.ogg', 100)
- log_combat(user, target, "cracked the skull of (eye snatching)", src)
-
- if(!do_after(user, eye_snatch_enthusiasm, target = target, extra_checks = CALLBACK(src, PROC_REF(eyeballs_exist), eyeballies, head, target)))
- return
-
- if(!target.is_blind())
- to_chat(target, span_userdanger("You suddenly go blind!"))
- if(prob(1))
- to_chat(target, span_notice("At least you got a new pirate-y look out of it..."))
- var/obj/item/clothing/glasses/eyepatch/new_patch = new(target.loc)
- target.equip_to_slot_if_possible(new_patch, ITEM_SLOT_EYES, disable_warning = TRUE)
-
- to_chat(user, span_notice("You successfully extract [target]'s eyeballs."))
- playsound(target, 'sound/items/handling/surgery/retractor2.ogg', 100, TRUE)
- playsound(target, 'sound/effects/pop.ogg', 100, TRAIT_MUTE)
- eyeballies.Remove(target)
- eyeballies.forceMove(get_turf(target))
- notify_ghosts(
- "[target] has just had their eyes snatched!",
- source = target,
- header = "Ouch!",
- )
- target.emote("scream")
- if(prob(20))
- target.emote("cry")
- used = TRUE
- update_appearance(UPDATE_ICON)
-
-/obj/item/eyesnatcher/examine(mob/user)
- . = ..()
- if(used)
- . += span_notice("It has been used up.")
-
-/obj/item/eyesnatcher/proc/eyeballs_exist(obj/item/organ/eyes/eyeballies, obj/item/bodypart/head/head, mob/living/carbon/human/target)
- if(!eyeballies || QDELETED(eyeballies))
- return FALSE
- if(!head || QDELETED(head))
- return FALSE
-
- if(eyeballies.owner != target)
- return FALSE
- var/obj/item/organ/eyes/eyes = target.get_organ_slot(ORGAN_SLOT_EYES)
- //got different eyes or doesn't own the head... somehow
- if(head.owner != target || eyes != eyeballies)
- return FALSE
-
- return TRUE
diff --git a/code/modules/antagonists/traitor/objectives/final_objective/battle_royale.dm b/code/modules/antagonists/traitor/objectives/final_objective/battle_royale.dm
deleted file mode 100644
index e5208ff8331..00000000000
--- a/code/modules/antagonists/traitor/objectives/final_objective/battle_royale.dm
+++ /dev/null
@@ -1,43 +0,0 @@
-/datum/traitor_objective/ultimate/battle_royale
- name = "Implant crewmembers with a subtle implant, then make them fight to the death on pay-per-view TV."
- description = "Go to %AREA%, and receive the Royale Broadcast Kit. \
- Use the contained implant on station personnel to subtly implant them with a micro-explosive. \
- Once you have at least six contestants, use the contained remote to start a timer and begin broadcasting live. \
- If more than one contestant remains alive after ten minutes, all of the implants will detonate."
-
- ///Area type the objective owner must be in to receive the tools.
- var/area/kit_spawn_area
- ///Whether the kit was sent already.
- var/equipped = FALSE
-
-/datum/traitor_objective/ultimate/battle_royale/generate_objective(datum/mind/generating_for, list/possible_duplicates)
- var/list/possible_areas = GLOB.the_station_areas.Copy()
- for(var/area/possible_area as anything in possible_areas)
- if(ispath(possible_area, /area/station/hallway) || ispath(possible_area, /area/station/security))
- possible_areas -= possible_area
- if(length(possible_areas) == 0)
- return FALSE
- kit_spawn_area = pick(possible_areas)
- replace_in_name("%AREA%", initial(kit_spawn_area.name))
- return TRUE
-
-/datum/traitor_objective/ultimate/battle_royale/generate_ui_buttons(mob/user)
- var/list/buttons = list()
- if(!equipped)
- buttons += add_ui_button("", "Pressing this will call down a pod with the Royale Broadcast kit.", "biohazard", "deliver_kit")
- return buttons
-
-/datum/traitor_objective/ultimate/battle_royale/ui_perform_action(mob/living/user, action)
- . = ..()
- if(action != "deliver_kit" || equipped)
- return
- var/area/delivery_area = get_area(user)
- if(delivery_area.type != kit_spawn_area)
- to_chat(user, span_warning("You must be in [initial(kit_spawn_area.name)] to receive the Royale Broadcast kit."))
- return
- equipped = TRUE
- podspawn(list(
- "target" = get_turf(user),
- "style" = /datum/pod_style/syndicate,
- "spawn" = /obj/item/storage/box/syndie_kit/battle_royale,
- ))
diff --git a/code/modules/antagonists/traitor/objectives/final_objective/battlecruiser.dm b/code/modules/antagonists/traitor/objectives/final_objective/battlecruiser.dm
deleted file mode 100644
index 7da84f60026..00000000000
--- a/code/modules/antagonists/traitor/objectives/final_objective/battlecruiser.dm
+++ /dev/null
@@ -1,49 +0,0 @@
-/datum/traitor_objective/ultimate/battlecruiser
- name = "Reveal Station Coordinates to nearby Syndicate Battlecruiser"
- description = "Use a special upload card on a communications console to send the coordinates \
- of the station to a nearby Battlecruiser. You may want to make your syndicate status known to \
- the battlecruiser crew when they arrive - their goal will be to destroy the station."
-
- /// Checks whether we have sent the card to the traitor yet.
- var/sent_accesscard = FALSE
- /// Battlecruiser team that we get assigned to
- var/datum/team/battlecruiser/team
-
-/datum/traitor_objective/ultimate/battlecruiser/generate_objective(datum/mind/generating_for, list/possible_duplicates)
- // There's no empty space to load a battlecruiser in...
- if(SSmapping.is_planetary())
- return FALSE
-
- return TRUE
-
-/datum/traitor_objective/ultimate/battlecruiser/on_objective_taken(mob/user)
- . = ..()
- team = new()
- var/obj/machinery/nuclearbomb/selfdestruct/nuke = locate() in SSmachines.get_machines_by_type(/obj/machinery/nuclearbomb/selfdestruct)
- if(nuke.r_code == NUKE_CODE_UNSET)
- nuke.r_code = random_nukecode()
- team.nuke = nuke
- team.update_objectives()
- handler.owner.add_antag_datum(/datum/antagonist/battlecruiser/ally, team)
-
-
-/datum/traitor_objective/ultimate/battlecruiser/generate_ui_buttons(mob/user)
- var/list/buttons = list()
- if(!sent_accesscard)
- buttons += add_ui_button("", "Pressing this will materialize an upload card, which you can use on a communication console to contact the fleet.", "phone", "card")
- return buttons
-
-/datum/traitor_objective/ultimate/battlecruiser/ui_perform_action(mob/living/user, action)
- . = ..()
- switch(action)
- if("card")
- if(sent_accesscard)
- return
- sent_accesscard = TRUE
- var/obj/item/card/emag/battlecruiser/emag_card = new()
- emag_card.team = team
- podspawn(list(
- "target" = get_turf(user),
- "style" = /datum/pod_style/syndicate,
- "spawn" = emag_card,
- ))
diff --git a/code/modules/antagonists/traitor/objectives/final_objective/final_objective.dm b/code/modules/antagonists/traitor/objectives/final_objective/final_objective.dm
deleted file mode 100644
index 33675402397..00000000000
--- a/code/modules/antagonists/traitor/objectives/final_objective/final_objective.dm
+++ /dev/null
@@ -1,43 +0,0 @@
-/datum/traitor_objective_category/final_objective
- name = "Final Objective"
- objectives = list(
- /datum/traitor_objective/ultimate/battlecruiser = 1,
- /datum/traitor_objective/ultimate/battle_royale = 1,
- /datum/traitor_objective/ultimate/dark_matteor = 1,
- /datum/traitor_objective/ultimate/infect_ai = 1,
- /datum/traitor_objective/ultimate/romerol = 1,
- /datum/traitor_objective/ultimate/supermatter_cascade = 1,
- /datum/traitor_objective/ultimate/no_escape = 1,
- )
- weight = 100
-
-/datum/traitor_objective/ultimate
- abstract_type = /datum/traitor_objective/ultimate
- progression_minimum = 140 MINUTES
- needs_reward = FALSE
-
- var/progression_points_in_objectives = 20 MINUTES
-
-/// Determines if this final objective can be taken. Should be put into every final objective's generate function.
-/datum/traitor_objective/ultimate/can_generate_objective(generating_for, list/possible_duplicates)
- if(handler.get_completion_progression(/datum/traitor_objective) < progression_points_in_objectives)
- return FALSE
- if(SStraitor.get_taken_count(type) > 0) // Prevents multiple people from ever getting the same final objective.
- return FALSE
- if(length(possible_duplicates) > 0)
- return FALSE
- return TRUE
-
-/datum/traitor_objective/ultimate/on_objective_taken(mob/user)
- . = ..()
- handler.maximum_potential_objectives = 0
- for(var/datum/traitor_objective/objective as anything in handler.potential_objectives)
- if(objective == src)
- continue
- objective.fail_objective()
- user.playsound_local(get_turf(user), 'sound/music/antag/traitor/final_objective.ogg', vol = 100, vary = FALSE, channel = CHANNEL_TRAITOR)
- handler.final_objective = name
-
-/datum/traitor_objective/ultimate/uplink_ui_data(mob/user)
- . = ..()
- .["final_objective"] = TRUE
diff --git a/code/modules/antagonists/traitor/objectives/final_objective/infect_ai.dm b/code/modules/antagonists/traitor/objectives/final_objective/infect_ai.dm
deleted file mode 100644
index d47a2c6aabc..00000000000
--- a/code/modules/antagonists/traitor/objectives/final_objective/infect_ai.dm
+++ /dev/null
@@ -1,56 +0,0 @@
-/datum/traitor_objective/ultimate/infect_ai
- name = "Infect the station AI with an experimental virus."
- description = "Infect the station AI with an experimental virus. Go to %AREA% to receive an infected law upload board \
- and use it on the AI core or a law upload console."
-
- ///area type the objective owner must be in to receive the law upload module
- var/area/board_area_pickup
- ///checker on whether we have sent the law upload module
- var/sent_board = FALSE
-
-/datum/traitor_objective/ultimate/infect_ai/can_generate_objective(generating_for, list/possible_duplicates)
- . = ..()
- if(!.)
- return FALSE
-
- for(var/mob/living/silicon/ai/ai in GLOB.ai_list)
- if(ai.stat == DEAD || ai.mind?.has_antag_datum(/datum/antagonist/malf_ai) || !is_station_level(ai.z))
- continue
- return TRUE
-
- return FALSE
-
-/datum/traitor_objective/ultimate/infect_ai/generate_objective(datum/mind/generating_for, list/possible_duplicates)
- var/list/possible_areas = GLOB.the_station_areas.Copy()
- for(var/area/possible_area as anything in possible_areas)
- //remove areas too close to the destination, too obvious for our poor shmuck, or just unfair
- if(istype(possible_area, /area/station/hallway) || istype(possible_area, /area/station/security))
- possible_areas -= possible_area
- if(!length(possible_areas))
- return FALSE
- board_area_pickup = pick(possible_areas)
- replace_in_name("%AREA%", initial(board_area_pickup.name))
- return TRUE
-
-/datum/traitor_objective/ultimate/infect_ai/generate_ui_buttons(mob/user)
- var/list/buttons = list()
- if(!sent_board)
- buttons += add_ui_button("", "Pressing this will call down a pod with an infected law upload board.", "wifi", "upload_board")
- return buttons
-
-/datum/traitor_objective/ultimate/infect_ai/ui_perform_action(mob/living/user, action)
- . = ..()
- switch(action)
- if("upload_board")
- if(sent_board)
- return
- var/area/delivery_area = get_area(user)
- if(delivery_area.type != board_area_pickup)
- to_chat(user, span_warning("You must be in [initial(board_area_pickup.name)] to receive the infected law upload board."))
- return
- sent_board = TRUE
- podspawn(list(
- "target" = get_turf(user),
- "style" = /datum/pod_style/syndicate,
- "spawn" = /obj/item/ai_module/malf,
- ))
diff --git a/code/modules/antagonists/traitor/objectives/final_objective/no_escape.dm b/code/modules/antagonists/traitor/objectives/final_objective/no_escape.dm
deleted file mode 100644
index 12cbdcf2d01..00000000000
--- a/code/modules/antagonists/traitor/objectives/final_objective/no_escape.dm
+++ /dev/null
@@ -1,48 +0,0 @@
-/datum/traitor_objective/ultimate/no_escape
- name = "Attach a beacon to the escape shuttle that will attract a singularity to consume everything."
- description = "Go to %AREA%, and receive the smuggled beacon. Set up the beacon anywhere on the shuttle, \
- and charge it using an inducer then, IT COMES. Warning: The singularity will consume all in it's path, you included."
-
- ///area type the objective owner must be in to receive the satellites
- var/area/beacon_spawn_area_type
- ///checker on whether we have sent the beacon yet
- var/sent_beacon = FALSE
-
-/datum/traitor_objective/ultimate/no_escape/generate_objective(datum/mind/generating_for, list/possible_duplicates)
- var/list/possible_areas = GLOB.the_station_areas.Copy()
- for(var/area/possible_area as anything in possible_areas)
- if(!ispath(possible_area, /area/station/maintenance/solars) && !ispath(possible_area, /area/station/solars))
- possible_areas -= possible_area
- if(length(possible_areas) == 0)
- return FALSE
- beacon_spawn_area_type = pick(possible_areas)
- replace_in_name("%AREA%", initial(beacon_spawn_area_type.name))
- return TRUE
-
-/datum/traitor_objective/ultimate/no_escape/generate_ui_buttons(mob/user)
- var/list/buttons = list()
- if(!sent_beacon)
- buttons += add_ui_button("", "Pressing this will call down a pod with the smuggled beacon.", "beacon", "beacon")
- return buttons
-
-/datum/traitor_objective/ultimate/no_escape/ui_perform_action(mob/living/user, action)
- . = ..()
- switch(action)
- if("beacon")
- if(sent_beacon)
- return
- var/area/delivery_area = get_area(user)
- if(delivery_area.type != beacon_spawn_area_type)
- to_chat(user, span_warning("You must be in [initial(beacon_spawn_area_type.name)] to receive the smuggled beacon."))
- return
- sent_beacon = TRUE
- podspawn(list(
- "target" = get_turf(user),
- "style" = /datum/pod_style/syndicate,
- "spawn" = list(
- /obj/item/sbeacondrop/no_escape,
- /obj/item/inducer/syndicate,
- /obj/item/wrench
- )
- ))
-
diff --git a/code/modules/antagonists/traitor/objectives/final_objective/objective_dark_matteor.dm b/code/modules/antagonists/traitor/objectives/final_objective/objective_dark_matteor.dm
deleted file mode 100644
index b90fdba73d0..00000000000
--- a/code/modules/antagonists/traitor/objectives/final_objective/objective_dark_matteor.dm
+++ /dev/null
@@ -1,83 +0,0 @@
-/datum/traitor_objective/ultimate/dark_matteor
- name = "Summon a dark matter singularity to consume the station."
- description = "Go to %AREA%, and receive the smuggled satellites + emag. Set up and emag the satellites, \
- after enough have been recalibrated by the emag, IT COMES. Warning: The dark matter singularity will hunt all creatures, you included."
-
- //this is a prototype so this progression is for all basic level kill objectives
-
- ///area type the objective owner must be in to receive the satellites
- var/area/satellites_spawnarea_type
- ///checker on whether we have sent the satellites yet.
- var/sent_satellites = FALSE
-
-/datum/traitor_objective/ultimate/dark_matteor/can_generate_objective(generating_for, list/possible_duplicates)
- . = ..()
- if(!.)
- return FALSE
- if(SSmapping.is_planetary())
- return FALSE //meteors can't spawn on planets
- return TRUE
-
-/datum/traitor_objective/ultimate/dark_matteor/generate_objective(datum/mind/generating_for, list/possible_duplicates)
- var/list/possible_areas = GLOB.the_station_areas.Copy()
- for(var/area/possible_area as anything in possible_areas)
- if(!ispath(possible_area, /area/station/maintenance/solars) && !ispath(possible_area, /area/station/solars))
- possible_areas -= possible_area
- if(length(possible_areas) == 0)
- return FALSE
- satellites_spawnarea_type = pick(possible_areas)
- replace_in_name("%AREA%", initial(satellites_spawnarea_type.name))
- return TRUE
-
-/datum/traitor_objective/ultimate/dark_matteor/generate_ui_buttons(mob/user)
- var/list/buttons = list()
- if(!sent_satellites)
- buttons += add_ui_button("", "Pressing this will call down a pod with the smuggled satellites.", "satellite", "satellite")
- return buttons
-
-/datum/traitor_objective/ultimate/dark_matteor/ui_perform_action(mob/living/user, action)
- . = ..()
- switch(action)
- if("satellite")
- if(sent_satellites)
- return
- var/area/delivery_area = get_area(user)
- if(delivery_area.type != satellites_spawnarea_type)
- to_chat(user, span_warning("You must be in [initial(satellites_spawnarea_type.name)] to receive the smuggled satellites."))
- return
- sent_satellites = TRUE
- podspawn(list(
- "target" = get_turf(user),
- "style" = /datum/pod_style/syndicate,
- "spawn" = /obj/structure/closet/crate/engineering/smuggled_meteor_shields,
- ))
-
-/obj/structure/closet/crate/engineering/smuggled_meteor_shields
-
-/obj/structure/closet/crate/engineering/smuggled_meteor_shields/PopulateContents()
- ..()
- for(var/i in 1 to 11)
- new /obj/machinery/satellite/meteor_shield(src)
- new /obj/item/card/emag/meteor_shield_recalibrator(src)
- new /obj/item/paper/dark_matteor_summoning(src)
-
-/obj/item/paper/dark_matteor_summoning
- name = "notes - dark matter meteor summoning"
- default_raw_text = {"
- Summoning a dark matter meteor.
-
-
- Operative, this crate contains 10+1 spare meteor shield satellites stolen from NT’s supply lines. Your mission is to
- deploy them in space near the station and recalibrate them with the provided emag. Be careful: you need a 30 second
- cooldown between each hack, and NT will detect your interference after seven recalibrations. That means you
- have at least 5 minutes of work and 1 minute of resistance.
-
- This is a high-risk operation. You’ll need backup, fortification, and determination. The reward?
- A spectacular dark matter singularity that will wipe out the station.
-
- **Death to Nanotrasen.**
-"}
-
-/obj/item/card/emag/meteor_shield_recalibrator
- name = "cryptographic satellite recalibrator"
- desc = "It's a cryptographic sequencer that has been tuned to recalibrate meteor shields quicker and with less risk of frying them."
diff --git a/code/modules/antagonists/traitor/objectives/final_objective/romerol.dm b/code/modules/antagonists/traitor/objectives/final_objective/romerol.dm
deleted file mode 100644
index 09edc4b0c73..00000000000
--- a/code/modules/antagonists/traitor/objectives/final_objective/romerol.dm
+++ /dev/null
@@ -1,46 +0,0 @@
-/datum/traitor_objective/ultimate/romerol
- name = "Spread the experimental bioterror agent Romerol by calling a droppod down at %AREA%"
- description = "Go to %AREA%, and receive the bioterror agent. Spread it to the crew, \
- and watch then raise from the dead as mindless killing machines. Warning: The undead will attack you too."
-
- //this is a prototype so this progression is for all basic level kill objectives
-
- ///area type the objective owner must be in to receive the romerol
- var/area/romerol_spawnarea_type
- ///checker on whether we have sent the romerol yet.
- var/sent_romerol = FALSE
-
-/datum/traitor_objective/ultimate/romerol/generate_objective(datum/mind/generating_for, list/possible_duplicates)
- var/list/possible_areas = GLOB.the_station_areas.Copy()
- for(var/area/possible_area as anything in possible_areas)
- //remove areas too close to the destination, too obvious for our poor shmuck, or just unfair
- if(ispath(possible_area, /area/station/hallway) || ispath(possible_area, /area/station/security))
- possible_areas -= possible_area
- if(length(possible_areas) == 0)
- return FALSE
- romerol_spawnarea_type = pick(possible_areas)
- replace_in_name("%AREA%", initial(romerol_spawnarea_type.name))
- return TRUE
-
-/datum/traitor_objective/ultimate/romerol/generate_ui_buttons(mob/user)
- var/list/buttons = list()
- if(!sent_romerol)
- buttons += add_ui_button("", "Pressing this will call down a pod with the biohazard kit.", "biohazard", "romerol")
- return buttons
-
-/datum/traitor_objective/ultimate/romerol/ui_perform_action(mob/living/user, action)
- . = ..()
- switch(action)
- if("romerol")
- if(sent_romerol)
- return
- var/area/delivery_area = get_area(user)
- if(delivery_area.type != romerol_spawnarea_type)
- to_chat(user, span_warning("You must be in [initial(romerol_spawnarea_type.name)] to receive the bioterror agent."))
- return
- sent_romerol = TRUE
- podspawn(list(
- "target" = get_turf(user),
- "style" = /datum/pod_style/syndicate,
- "spawn" = /obj/item/storage/box/syndie_kit/romerol,
- ))
diff --git a/code/modules/antagonists/traitor/objectives/final_objective/supermatter_cascade.dm b/code/modules/antagonists/traitor/objectives/final_objective/supermatter_cascade.dm
deleted file mode 100644
index 2e9396c90b0..00000000000
--- a/code/modules/antagonists/traitor/objectives/final_objective/supermatter_cascade.dm
+++ /dev/null
@@ -1,57 +0,0 @@
-/datum/traitor_objective/ultimate/supermatter_cascade
- name = "Destroy the station by causing a crystallizing resonance cascade"
- description = "Destroy the station by causing a supermatter cascade. Go to %AREA% to retrieve the destabilizing crystal \
- and use it on the supermatter."
-
- ///area type the objective owner must be in to receive the destabilizing crystal
- var/area/dest_crystal_area_pickup
- ///checker on whether we have sent the crystal yet.
- var/sent_crystal = FALSE
-
-/datum/traitor_objective/ultimate/supermatter_cascade/can_generate_objective(generating_for, list/possible_duplicates)
- . = ..()
- if(!.)
- return FALSE
-
- if(isnull(GLOB.main_supermatter_engine))
- return FALSE
- var/obj/machinery/power/supermatter_crystal/engine/crystal = locate() in GLOB.main_supermatter_engine
- if(!is_station_level(crystal.z) && !is_mining_level(crystal.z))
- return FALSE
-
- return TRUE
-
-/datum/traitor_objective/ultimate/supermatter_cascade/generate_objective(datum/mind/generating_for, list/possible_duplicates)
- var/list/possible_areas = GLOB.the_station_areas.Copy()
- for(var/area/possible_area as anything in possible_areas)
- //remove areas too close to the destination, too obvious for our poor shmuck, or just unfair
- if(ispath(possible_area, /area/station/hallway) || ispath(possible_area, /area/station/security))
- possible_areas -= possible_area
- if(length(possible_areas) == 0)
- return FALSE
- dest_crystal_area_pickup = pick(possible_areas)
- replace_in_name("%AREA%", initial(dest_crystal_area_pickup.name))
- return TRUE
-
-/datum/traitor_objective/ultimate/supermatter_cascade/generate_ui_buttons(mob/user)
- var/list/buttons = list()
- if(!sent_crystal)
- buttons += add_ui_button("", "Pressing this will call down a pod with the supermatter cascade kit.", "biohazard", "destabilizing_crystal")
- return buttons
-
-/datum/traitor_objective/ultimate/supermatter_cascade/ui_perform_action(mob/living/user, action)
- . = ..()
- switch(action)
- if("destabilizing_crystal")
- if(sent_crystal)
- return
- var/area/delivery_area = get_area(user)
- if(delivery_area.type != dest_crystal_area_pickup)
- to_chat(user, span_warning("You must be in [initial(dest_crystal_area_pickup.name)] to receive the supermatter cascade kit."))
- return
- sent_crystal = TRUE
- podspawn(list(
- "target" = get_turf(user),
- "style" = /datum/pod_style/syndicate,
- "spawn" = /obj/item/destabilizing_crystal,
- ))
diff --git a/code/modules/antagonists/traitor/objectives/hack_comm_console.dm b/code/modules/antagonists/traitor/objectives/hack_comm_console.dm
deleted file mode 100644
index 1874b79d8a1..00000000000
--- a/code/modules/antagonists/traitor/objectives/hack_comm_console.dm
+++ /dev/null
@@ -1,55 +0,0 @@
-/datum/traitor_objective_category/hack_comm_console
- name = "Hack Communication Console"
- objectives = list(
- /datum/traitor_objective/hack_comm_console = 1,
- )
-
-/datum/traitor_objective/hack_comm_console
- name = "Hack a communication console to summon an unknown threat to the station"
- description = "Right click on a communication console to begin the hacking process. Once started, the AI will know that you are hacking a communication console, so be ready to run or have yourself disguised to prevent being caught. This objective will invalidate itself if another traitor completes it first."
-
- progression_minimum = 60 MINUTES
- progression_reward = list(30 MINUTES, 40 MINUTES)
- telecrystal_reward = list(7, 12)
-
- var/progression_objectives_minimum = 20 MINUTES
-
-/datum/traitor_objective/hack_comm_console/can_generate_objective(datum/mind/generating_for, list/possible_duplicates)
- if(length(possible_duplicates) > 0)
- return FALSE
- if(SStraitor.get_taken_count(/datum/traitor_objective/hack_comm_console) > 0)
- return FALSE
- if(handler.get_completion_progression(/datum/traitor_objective) < progression_objectives_minimum)
- return FALSE
- return TRUE
-
-/datum/traitor_objective/hack_comm_console/generate_objective(datum/mind/generating_for, list/possible_duplicates)
- AddComponent(/datum/component/traitor_objective_mind_tracker, generating_for, \
- signals = list(COMSIG_LIVING_UNARMED_ATTACK = PROC_REF(on_unarmed_attack)))
- RegisterSignal(SSdcs, COMSIG_GLOB_TRAITOR_OBJECTIVE_COMPLETED, PROC_REF(on_global_obj_completed))
- return TRUE
-
-/datum/traitor_objective/hack_comm_console/ungenerate_objective()
- UnregisterSignal(SSdcs, COMSIG_GLOB_TRAITOR_OBJECTIVE_COMPLETED)
-
-/datum/traitor_objective/hack_comm_console/proc/on_global_obj_completed(datum/source, datum/traitor_objective/objective)
- SIGNAL_HANDLER
- if(istype(objective, /datum/traitor_objective/hack_comm_console))
- fail_objective()
-
-/datum/traitor_objective/hack_comm_console/proc/on_unarmed_attack(mob/user, obj/machinery/computer/communications/target, proximity_flag, modifiers)
- SIGNAL_HANDLER
- if(!proximity_flag)
- return
- if(!modifiers[RIGHT_CLICK])
- return
- if(!istype(target))
- return
- INVOKE_ASYNC(src, PROC_REF(begin_hack), user, target)
- return COMPONENT_CANCEL_ATTACK_CHAIN
-
-/datum/traitor_objective/hack_comm_console/proc/begin_hack(mob/user, obj/machinery/computer/communications/target)
- if(!target.try_hack_console(user))
- return
-
- succeed_objective()
diff --git a/code/modules/antagonists/traitor/objectives/infect.dm b/code/modules/antagonists/traitor/objectives/infect.dm
deleted file mode 100644
index 459e8f54a0d..00000000000
--- a/code/modules/antagonists/traitor/objectives/infect.dm
+++ /dev/null
@@ -1,176 +0,0 @@
-/datum/traitor_objective_category/infect
- name = "Infect with Disease"
- objectives = list(
- /datum/traitor_objective/target_player/infect = 1,
- )
-
-/datum/traitor_objective/target_player/infect
- name = "Infect %TARGET% the %JOB TITLE%"
- description = "Infect your target with the experimental Hereditary Manifold Sickness."
-
- progression_minimum = 30 MINUTES
-
- progression_reward = list(8 MINUTES, 14 MINUTES)
- telecrystal_reward = 1
-
- duplicate_type = /datum/traitor_objective/target_player/infect
-
- /// if TRUE, can only target heads of staff
- /// if FALSE, CANNOT target heads of staff
- var/heads_of_staff = FALSE
- /// if TRUE, the injector item has been bestowed upon the player
- var/injector_given = FALSE
-
-/datum/traitor_objective/target_player/infect/supported_configuration_changes()
- . = ..()
- . += NAMEOF(src, objective_period)
- . += NAMEOF(src, maximum_objectives_in_period)
-
-/datum/traitor_objective/target_player/infect/can_generate_objective(generating_for, list/possible_duplicates)
- if(length(possible_duplicates) > 0)
- return FALSE
- return ..()
-
-/datum/traitor_objective/target_player/infect/generate_ui_buttons(mob/user)
- var/list/buttons = list()
- if(!injector_given)
- buttons += add_ui_button("", "Pressing this will materialize a EHMS autoinjector into your hand, which you must inject into the target to succeed.", "syringe", "summon_pen")
- return buttons
-
-/datum/traitor_objective/target_player/infect/ui_perform_action(mob/living/user, action)
- . = ..()
- switch(action)
- if("summon_pen")
- if(injector_given)
- return
- injector_given = TRUE
- var/obj/item/reagent_containers/hypospray/medipen/manifoldinjector/ehms = new(user.drop_location())
- user.put_in_hands(ehms)
- ehms.balloon_alert(user, "the injector materializes in your hand")
- RegisterSignal(ehms, COMSIG_EHMS_INJECTOR_INJECTED, PROC_REF(on_injected))
- AddComponent(/datum/component/traitor_objective_register, ehms, \
- succeed_signals = null, \
- fail_signals = list(COMSIG_QDELETING), \
- penalty = TRUE)
-
-/datum/traitor_objective/target_player/infect/proc/on_injected(datum/source, mob/living/user, mob/living/injected)
- SIGNAL_HANDLER
- if(injected != target)
- fail_objective()
- return
- if(injected == target)
- succeed_objective()
- return
-
-/datum/traitor_objective/target_player/infect/generate_objective(datum/mind/generating_for, list/possible_duplicates)
-
- var/list/already_targeting = list() //List of minds we're already targeting. The possible_duplicates is a list of objectives, so let's not mix things
- for(var/datum/objective/task as anything in handler.primary_objectives)
- if(!istype(task.target, /datum/mind))
- continue
- already_targeting += task.target //Removing primary objective kill targets from the list
-
- var/parent_type = type2parent(type)
- //don't roll head of staff types if you haven't completed the normal version
- if(heads_of_staff && !handler.get_completion_count(parent_type))
- // Locked if they don't have any of the risky bug room objective completed
- return FALSE
-
- var/list/possible_targets = list()
- var/try_target_late_joiners = FALSE
- if(generating_for.late_joiner)
- try_target_late_joiners = TRUE
- for(var/datum/mind/possible_target as anything in get_crewmember_minds())
- if(possible_target in already_targeting)
- continue
- var/target_area = get_area(possible_target.current)
- if(possible_target == generating_for)
- continue
- if(!ishuman(possible_target.current))
- continue
- if(possible_target.current.stat == DEAD)
- continue
- var/datum/antagonist/traitor/traitor = possible_target.has_antag_datum(/datum/antagonist/traitor)
- if(traitor && traitor.uplink_handler.telecrystals >= 0)
- continue
- var/mob/living/carbon/human/targets_current = possible_target.current
- var/datum/disease/chronic_illness/illness = locate() in targets_current.diseases
- if(illness)
- continue
- if(!HAS_TRAIT(SSstation, STATION_TRAIT_LATE_ARRIVALS) && istype(target_area, /area/shuttle/arrival))
- continue
- //removes heads of staff from being targets from non heads of staff assassinations, and vice versa
- if(heads_of_staff)
- if(!(possible_target.assigned_role.job_flags & JOB_HEAD_OF_STAFF))
- continue
- else
- if((possible_target.assigned_role.job_flags & JOB_HEAD_OF_STAFF))
- continue
- possible_targets += possible_target
- for(var/datum/traitor_objective/target_player/objective as anything in possible_duplicates)
- possible_targets -= objective.target
- if(try_target_late_joiners)
- var/list/all_possible_targets = possible_targets.Copy()
- for(var/datum/mind/possible_target as anything in all_possible_targets)
- if(!possible_target.late_joiner)
- possible_targets -= possible_target
- if(!possible_targets.len)
- possible_targets = all_possible_targets
- special_target_filter(possible_targets)
- if(!possible_targets.len)
- return FALSE //MISSION FAILED, WE'LL GET EM NEXT TIME
-
- var/datum/mind/target_mind = pick(possible_targets)
- set_target(target_mind.current)
- replace_in_name("%TARGET%", target.real_name)
- replace_in_name("%JOB TITLE%", target_mind.assigned_role.title)
- RegisterSignal(target, COMSIG_LIVING_DEATH, PROC_REF(on_target_death))
- return TRUE
-
-/datum/traitor_objective/target_player/infect/ungenerate_objective()
- UnregisterSignal(target, COMSIG_LIVING_DEATH)
- set_target(null)
-
-///proc for checking for special states that invalidate a target
-/datum/traitor_objective/target_player/infect/proc/special_target_filter(list/possible_targets)
- return
-
-/datum/traitor_objective/target_player/infect/target_deleted()
- if(objective_state == OBJECTIVE_STATE_INACTIVE)
- //don't take an objective target of someone who is already obliterated
- fail_objective()
- return ..()
-
-/datum/traitor_objective/target_player/infect/proc/on_target_death()
- SIGNAL_HANDLER
- if(objective_state == OBJECTIVE_STATE_INACTIVE)
- //don't take an objective target of someone who is already dead
- fail_objective()
-
-/obj/item/reagent_containers/hypospray/medipen/manifoldinjector
- name = "EHMS autoinjector"
- desc = "Experimental Hereditary Manifold Sickness autoinjector."
- icon_state = "tbpen"
- inhand_icon_state = "tbpen"
- base_icon_state = "tbpen"
- volume = 30
- amount_per_transfer_from_this = 30
- list_reagents = list(/datum/reagent/medicine/sansufentanyl = 20)
- stealthy = TRUE
- //Was the injector used on someone yet?
- var/used = FALSE
-
-/obj/item/reagent_containers/hypospray/medipen/manifoldinjector/attack(mob/living/affected_mob, mob/living/carbon/human/user)
- if(used)
- return ..()
- to_chat(affected_mob, span_warning("You feel someone try to inject you with something."))
- balloon_alert(user, "injecting...")
- log_combat(user, affected_mob, "attempted to inject", src)
- if(!do_after(user, 1.5 SECONDS, hidden = TRUE))
- balloon_alert(user, "interrupted!")
- return
- var/datum/disease/chronic_illness/hms = new /datum/disease/chronic_illness()
- affected_mob.ForceContractDisease(hms)
- used = TRUE
- inject(affected_mob, user)
- SEND_SIGNAL(src, COMSIG_EHMS_INJECTOR_INJECTED, user, affected_mob)
diff --git a/code/modules/antagonists/traitor/objectives/kidnapping.dm b/code/modules/antagonists/traitor/objectives/kidnapping.dm
deleted file mode 100644
index 0d4ff5cfd99..00000000000
--- a/code/modules/antagonists/traitor/objectives/kidnapping.dm
+++ /dev/null
@@ -1,300 +0,0 @@
-/datum/traitor_objective/target_player/kidnapping
- name = "Kidnap %TARGET% the %JOB TITLE% and deliver them to %AREA%"
- description = "%TARGET% holds extremely important information regarding secret NT projects - and you'll need to kidnap and deliver them to %AREA%, where our transport pod will be waiting. \
- If %TARGET% is delivered alive, you will be rewarded with an additional %TC% telecrystals."
-
- abstract_type = /datum/traitor_objective/target_player/kidnapping
-
- /// The jobs that this objective is targeting.
- var/list/target_jobs
- /// Area that the target needs to be delivered to
- var/area/dropoff_area
- /// Have we called the pod yet?
- var/pod_called = FALSE
- /// How much TC do we get from sending the target alive
- var/alive_bonus = 0
- /// All stripped targets belongings (weakrefs)
- var/list/target_belongings = list()
- /// The ID of the stoppable timer for returning the captured crew
- var/list/victim_timerid
-
- duplicate_type = /datum/traitor_objective/target_player
-
-/datum/traitor_objective/target_player/kidnapping/supported_configuration_changes()
- . = ..()
- . += NAMEOF(src, objective_period)
- . += NAMEOF(src, maximum_objectives_in_period)
-
-/datum/traitor_objective/target_player/kidnapping/New(datum/uplink_handler/handler)
- . = ..()
- AddComponent(/datum/component/traitor_objective_limit_per_time, \
- /datum/traitor_objective/target_player, \
- time_period = objective_period, \
- maximum_objectives = maximum_objectives_in_period \
- )
-
-/datum/traitor_objective/target_player/kidnapping/common
- progression_minimum = 0 MINUTES
- progression_maximum = 30 MINUTES
- progression_reward = list(2 MINUTES, 4 MINUTES)
- telecrystal_reward = list(1, 2)
- target_jobs = list(
- // Cargo
- /datum/job/cargo_technician,
- // Engineering
- /datum/job/atmospheric_technician,
- /datum/job/station_engineer,
- // Medical
- /datum/job/chemist,
- /datum/job/doctor,
- /datum/job/psychologist,
- /datum/job/coroner,
- // Science
- /datum/job/geneticist,
- /datum/job/roboticist,
- /datum/job/scientist,
- // Service
- /datum/job/bartender,
- /datum/job/botanist,
- /datum/job/chaplain,
- /datum/job/clown,
- /datum/job/curator,
- /datum/job/janitor,
- /datum/job/lawyer,
- /datum/job/mime,
- )
- alive_bonus = 2
-
-/datum/traitor_objective/target_player/kidnapping/common/assistant
- progression_minimum = 0 MINUTES
- progression_maximum = 15 MINUTES
- target_jobs = list(
- /datum/job/assistant
- )
-
-/datum/traitor_objective/target_player/kidnapping/uncommon //Hard to fish out targets
- progression_minimum = 0 MINUTES
- progression_maximum = 45 MINUTES
- progression_reward = list(4 MINUTES, 8 MINUTES)
- telecrystal_reward = list(1, 2)
-
- target_jobs = list(
- // Cargo
- /datum/job/bitrunner,
- /datum/job/shaft_miner,
- // Medical
- /datum/job/paramedic,
- // Service
- /datum/job/cook,
- )
- alive_bonus = 3
-
-/datum/traitor_objective/target_player/kidnapping/rare
- progression_minimum = 15 MINUTES
- progression_maximum = 60 MINUTES
- progression_reward = list(8 MINUTES, 12 MINUTES)
- telecrystal_reward = list(2, 3)
- target_jobs = list(
- // Heads of staff
- /datum/job/chief_engineer,
- /datum/job/chief_medical_officer,
- /datum/job/head_of_personnel,
- /datum/job/research_director,
- /datum/job/quartermaster,
- // Security
- /datum/job/detective,
- /datum/job/security_officer,
- /datum/job/warden,
- )
- alive_bonus = 4
-
-/datum/traitor_objective/target_player/kidnapping/captain
- progression_minimum = 30 MINUTES
- progression_reward = list(12 MINUTES, 16 MINUTES)
- telecrystal_reward = list(2, 3)
- target_jobs = list(
- /datum/job/captain,
- /datum/job/head_of_security,
- )
- alive_bonus = 5
-
-/datum/traitor_objective/target_player/kidnapping/generate_objective(datum/mind/generating_for, list/possible_duplicates)
-
- var/list/already_targeting = list() //List of minds we're already targeting. The possible_duplicates is a list of objectives, so let's not mix things
- for(var/datum/objective/task as anything in handler.primary_objectives)
- if(!istype(task.target, /datum/mind))
- continue
- already_targeting += task.target //Removing primary objective kill targets from the list
-
- var/list/possible_targets = list()
- for(var/datum/mind/possible_target as anything in get_crewmember_minds())
- if(possible_target == generating_for)
- continue
-
- if(possible_target in already_targeting)
- continue
-
- if(!ishuman(possible_target.current))
- continue
-
- if(possible_target.current.stat == DEAD)
- continue
-
- if(HAS_TRAIT(possible_target, TRAIT_HAS_BEEN_KIDNAPPED))
- continue
-
- if(possible_target.has_antag_datum(/datum/antagonist/traitor))
- continue
-
- if(!(possible_target.assigned_role.type in target_jobs))
- continue
-
- possible_targets += possible_target
-
- for(var/datum/traitor_objective/target_player/objective as anything in possible_duplicates)
- if(!objective.target) //the old objective was already completed.
- continue
- possible_targets -= objective.target.mind
-
- if(!length(possible_targets))
- return FALSE
-
- var/datum/mind/target_mind = pick(possible_targets)
- set_target(target_mind.current)
- AddComponent(/datum/component/traitor_objective_register, target, fail_signals = list(COMSIG_QDELETING))
- var/list/possible_areas = GLOB.the_station_areas.Copy()
- for(var/area/possible_area as anything in possible_areas)
- if(ispath(possible_area, /area/station/hallway) || ispath(possible_area, /area/station/security) || initial(possible_area.outdoors))
- possible_areas -= possible_area
-
- dropoff_area = pick(possible_areas)
- replace_in_name("%TARGET%", target_mind.name)
- replace_in_name("%JOB TITLE%", target_mind.assigned_role.title)
- replace_in_name("%AREA%", initial(dropoff_area.name))
- replace_in_name("%TC%", alive_bonus)
- return TRUE
-
-/datum/traitor_objective/target_player/kidnapping/ungenerate_objective()
- set_target(null)
- dropoff_area = null
-
-/datum/traitor_objective/target_player/kidnapping/on_objective_taken(mob/user)
- . = ..()
- INVOKE_ASYNC(src, PROC_REF(generate_holding_area))
-
-/datum/traitor_objective/target_player/kidnapping/proc/generate_holding_area()
- // Let's load in the holding facility ahead of time
- // even if they fail the objective it's better to get done now rather than later
- SSmapping.lazy_load_template(LAZY_TEMPLATE_KEY_NINJA_HOLDING_FACILITY)
-
-/datum/traitor_objective/target_player/kidnapping/generate_ui_buttons(mob/user)
- var/list/buttons = list()
- if(!pod_called)
- buttons += add_ui_button("Call Extraction Pod", "Pressing this will call down an extraction pod.", "rocket", "call_pod")
- return buttons
-
-/datum/traitor_objective/target_player/kidnapping/ui_perform_action(mob/living/user, action)
- . = ..()
- switch(action)
- if("call_pod")
- if(pod_called)
- return
- var/area/user_area = get_area(user)
- var/area/target_area = get_area(target)
-
- if(user_area.type != dropoff_area)
- to_chat(user, span_warning("You must be in [initial(dropoff_area.name)] to call the extraction pod."))
- return
-
- if(target_area.type != dropoff_area)
- to_chat(user, span_warning("[target.real_name] must be in [initial(dropoff_area.name)] for you to call the extraction pod."))
- return
-
- call_pod(user)
-
-/datum/traitor_objective/target_player/kidnapping/proc/call_pod(mob/living/user)
- pod_called = TRUE
- var/obj/structure/closet/supplypod/extractionpod/new_pod = new()
- RegisterSignal(new_pod, COMSIG_ATOM_ENTERED, PROC_REF(enter_check))
- new /obj/effect/pod_landingzone(get_turf(user), new_pod)
-
-/datum/traitor_objective/target_player/kidnapping/proc/enter_check(obj/structure/closet/supplypod/extractionpod/source, entered_atom)
- SIGNAL_HANDLER
- if(!istype(source))
- CRASH("Kidnapping objective's enter_check called with source being not an extraction pod: [source ? source.type : "N/A"]")
-
- if(!ishuman(entered_atom))
- return
-
- var/mob/living/carbon/human/sent_mob = entered_atom
-
- for(var/obj/item/belonging in sent_mob.gather_belongings(FALSE, FALSE))
- if(belonging == sent_mob.get_item_by_slot(ITEM_SLOT_ICLOTHING) || belonging == sent_mob.get_item_by_slot(ITEM_SLOT_FEET))
- continue
-
- var/unequipped = sent_mob.temporarilyRemoveItemFromInventory(belonging)
- if (!unequipped)
- continue
- belonging.moveToNullspace()
- target_belongings.Add(WEAKREF(belonging))
-
- var/datum/market_item/hostage/market_item = sent_mob.process_capture(rand(1000, 3000))
- RegisterSignal(market_item, COMSIG_MARKET_ITEM_SPAWNED, PROC_REF(on_victim_shipped))
-
- addtimer(CALLBACK(src, PROC_REF(handle_target), sent_mob), 1.5 SECONDS)
-
- if(sent_mob != target)
- fail_objective(penalty_cost = telecrystal_penalty)
- source.startExitSequence(source)
- return
-
- if(sent_mob.stat != DEAD)
- telecrystal_reward += alive_bonus
-
- succeed_objective()
- source.startExitSequence(source)
-
-/datum/traitor_objective/target_player/kidnapping/proc/handle_target(mob/living/carbon/human/sent_mob)
- victim_timerid = addtimer(CALLBACK(src, PROC_REF(return_target), sent_mob), COME_BACK_FROM_CAPTURE_TIME, TIMER_STOPPABLE)
- if(sent_mob.stat == DEAD)
- return
-
- sent_mob.flash_act()
- sent_mob.adjust_confusion(10 SECONDS)
- sent_mob.adjust_dizzy(10 SECONDS)
- sent_mob.set_eye_blur_if_lower(100 SECONDS)
- sent_mob.dna.species.give_important_for_life(sent_mob) // so plasmamen do not get left for dead
- to_chat(sent_mob, span_hypnophrase("A million voices echo in your head... \"Your mind held many valuable secrets - \
- we thank you for providing them. Your value is expended, and you will be ransomed back to your station. We always get paid, \
- so it's only a matter of time before we ship you back...\""))
-
-/datum/traitor_objective/target_player/kidnapping/proc/return_target(mob/living/carbon/human/sent_mob)
- if(!sent_mob || QDELETED(sent_mob)) //suicided and qdeleted themselves
- return
-
- var/obj/structure/closet/supplypod/back_to_station/return_pod = new()
- return_pod.return_from_capture(sent_mob)
- returnal_side_effects(return_pod, sent_mob)
-
-/datum/traitor_objective/target_player/kidnapping/proc/on_victim_shipped(datum/market_item/source, obj/item/market_uplink/uplink, shipping_method, turf/shipping_loc)
- SIGNAL_HANDLER
- deltimer(victim_timerid)
- returnal_side_effects(shipping_loc, source.item)
-
-/datum/traitor_objective/target_player/kidnapping/proc/returnal_side_effects(atom/dropoff_location, mob/living/carbon/human/sent_mob)
- for(var/obj/item/belonging in sent_mob.gather_belongings())
- if(belonging == sent_mob.get_item_by_slot(ITEM_SLOT_ICLOTHING) || belonging == sent_mob.get_item_by_slot(ITEM_SLOT_FEET))
- continue
- sent_mob.dropItemToGround(belonging) // No souvenirs, except shoes and t-shirts
-
- for(var/datum/weakref/belonging_ref in target_belongings)
- var/obj/item/belonging = belonging_ref.resolve()
- if(!belonging)
- continue
- belonging.forceMove(dropoff_location)
-
- sent_mob.flash_act()
- sent_mob.adjust_confusion(10 SECONDS)
- sent_mob.adjust_dizzy(10 SECONDS)
- sent_mob.set_eye_blur_if_lower(100 SECONDS)
- sent_mob.dna.species.give_important_for_life(sent_mob) // so plasmamen do not get left for dead
diff --git a/code/modules/antagonists/traitor/objectives/kill_pet.dm b/code/modules/antagonists/traitor/objectives/kill_pet.dm
deleted file mode 100644
index ddaf6ee47ce..00000000000
--- a/code/modules/antagonists/traitor/objectives/kill_pet.dm
+++ /dev/null
@@ -1,97 +0,0 @@
-/datum/traitor_objective_category/kill_pet
- name = "Kill Pet"
- objectives = list(
- /datum/traitor_objective/kill_pet/high_risk = 1,
- list(
- /datum/traitor_objective/kill_pet = 2,
- /datum/traitor_objective/kill_pet/medium_risk = 1,
- ) = 4,
- )
-
-/datum/traitor_objective/kill_pet
- name = "Kill the %DEPARTMENT HEAD%'s beloved %PET%"
- description = "The %DEPARTMENT HEAD% has particularly annoyed us by sending us spam emails and we want their %PET% dead to show them what happens when they cross us. "
-
- progression_minimum = 0 MINUTES
- telecrystal_reward = list(1, 2)
- progression_reward = list(3 MINUTES, 6 MINUTES)
-
- /// Possible heads mapped to their pet type. Can be a list of possible pets
- var/list/possible_heads = list(
- JOB_HEAD_OF_PERSONNEL = list(
- /mob/living/basic/pet/dog/corgi/ian,
- /mob/living/basic/pet/dog/corgi/puppy/ian
- ),
- JOB_CAPTAIN = /mob/living/basic/pet/fox/renault,
- JOB_CHIEF_MEDICAL_OFFICER = /mob/living/basic/pet/cat/runtime,
- JOB_CHIEF_ENGINEER = /mob/living/basic/parrot/poly,
- JOB_QUARTERMASTER = list(
- /mob/living/basic/gorilla/cargorilla,
- /mob/living/basic/sloth/citrus,
- /mob/living/basic/sloth/paperwork,
- )
- )
- /// The head that we are targeting
- var/datum/job/target
- /// Whether or not we only take from the traitor's own department head or not.
- var/limited_to_department_head = TRUE
- /// The actual pet that needs to be killed
- var/mob/living/target_pet
-
- duplicate_type = /datum/traitor_objective/kill_pet
-
-/datum/traitor_objective/kill_pet/medium_risk
- progression_minimum = 10 MINUTES
- progression_reward = list(5 MINUTES, 8 MINUTES)
- limited_to_department_head = FALSE
-
-/datum/traitor_objective/kill_pet/high_risk
- progression_minimum = 25 MINUTES
- progression_reward = list(14 MINUTES, 18 MINUTES)
- telecrystal_reward = list(2, 3)
-
- limited_to_department_head = FALSE
- possible_heads = list(
- JOB_HEAD_OF_SECURITY = list(
- /mob/living/basic/carp/pet/lia,
- /mob/living/basic/spider/giant/sgt_araneus,
- /mob/living/basic/bear/snow/misha,
- ),
- JOB_WARDEN = list(
- /mob/living/basic/pet/dog/pug/mcgriff
- )
- )
-
-/datum/traitor_objective/kill_pet/generate_objective(datum/mind/generating_for, list/possible_duplicates)
- var/datum/job/role = generating_for.assigned_role
- for(var/datum/traitor_objective/kill_pet/objective as anything in possible_duplicates)
- possible_heads -= objective.target.title
- if(limited_to_department_head)
- possible_heads = possible_heads & role.department_head
- possible_heads -= role.title
-
- if(!length(possible_heads))
- return FALSE
- target = SSjob.name_occupations[pick(possible_heads)]
- var/pet_type = possible_heads[target.title]
- if(islist(pet_type))
- for(var/type in pet_type)
- target_pet = locate(type) in GLOB.mob_living_list
- if(target_pet)
- break
- else
- target_pet = locate(pet_type) in GLOB.mob_living_list
- if(!target_pet)
- return FALSE
- if(target_pet.stat == DEAD)
- return FALSE
- AddComponent(/datum/component/traitor_objective_register, target_pet, \
- succeed_signals = list(COMSIG_QDELETING, COMSIG_LIVING_DEATH))
- replace_in_name("%DEPARTMENT HEAD%", target.title)
- replace_in_name("%PET%", target_pet.name)
- return TRUE
-
-/datum/traitor_objective/kill_pet/ungenerate_objective()
- if(target_pet)
- UnregisterSignal(target_pet, list(COMSIG_QDELETING, COMSIG_LIVING_DEATH))
- target_pet = null
diff --git a/code/modules/antagonists/traitor/objectives/locate_weakpoint.dm b/code/modules/antagonists/traitor/objectives/locate_weakpoint.dm
deleted file mode 100644
index 5492f04a0f8..00000000000
--- a/code/modules/antagonists/traitor/objectives/locate_weakpoint.dm
+++ /dev/null
@@ -1,282 +0,0 @@
-/datum/traitor_objective_category/locate_weakpoint
- name = "Locate And Destroy Weakpoint"
- objectives = list(
- /datum/traitor_objective/locate_weakpoint = 1,
- )
- weight = OBJECTIVE_WEIGHT_UNLIKELY
-
-/datum/traitor_objective/locate_weakpoint
- name = "Triangulate station's structural weakpoint and detonate an explosive charge nearby."
- description = "You will be given a handheld device that you'll need to use in %AREA1% and %AREA2% in order to triangulate the station's structural weakpoint and detonate an explosive charge there. Warning: Once you start scanning either one of the areas, station's AI will be alerted."
-
- progression_minimum = 45 MINUTES
- progression_reward = list(15 MINUTES, 20 MINUTES)
- telecrystal_reward = list(3, 5)
-
- var/progression_objectives_minimum = 20 MINUTES
-
- /// Have we sent a weakpoint locator yet?
- var/locator_sent = FALSE
- /// Have we sent a bomb yet?
- var/bomb_sent = FALSE
- /// Have we located the weakpoint yet?
- var/weakpoint_found = FALSE
- /// Areas that need to be scanned
- var/list/area/scan_areas
- /// Weakpoint where the bomb should be planted
- var/area/weakpoint_area
-
-/datum/traitor_objective/locate_weakpoint/can_generate_objective(datum/mind/generating_for, list/possible_duplicates)
- if(length(possible_duplicates) > 0)
- return FALSE
- if(handler.get_completion_progression(/datum/traitor_objective) < progression_objectives_minimum)
- return FALSE
- if(SStraitor.get_taken_count(/datum/traitor_objective/locate_weakpoint) > 0)
- return FALSE
- return TRUE
-
-/datum/traitor_objective/locate_weakpoint/generate_objective(datum/mind/generating_for, list/possible_duplicates)
- scan_areas = list()
- /// List of high-security areas that we pick required ones from
- var/list/allowed_areas = typecacheof(list(/area/station/command,
- /area/station/comms,
- /area/station/engineering,
- /area/station/science,
- /area/station/security,
- ))
-
- var/list/blacklisted_areas = typecacheof(list(/area/station/engineering/hallway,
- /area/station/engineering/lobby,
- /area/station/engineering/storage,
- /area/station/science/lobby,
- /area/station/science/ordnance/bomb,
- /area/station/security/prison,
- ))
-
- var/list/possible_areas = GLOB.the_station_areas.Copy()
- for(var/area/possible_area as anything in possible_areas)
- if(!is_type_in_typecache(possible_area, allowed_areas) || initial(possible_area.outdoors) || is_type_in_typecache(possible_area, blacklisted_areas))
- possible_areas -= possible_area
-
- for(var/i in 1 to 2)
- scan_areas[pick_n_take(possible_areas)] = TRUE
- weakpoint_area = pick_n_take(possible_areas)
-
- var/area/scan_area1 = scan_areas[1]
- var/area/scan_area2 = scan_areas[2]
- replace_in_name("%AREA1%", initial(scan_area1.name))
- replace_in_name("%AREA2%", initial(scan_area2.name))
- RegisterSignal(SSdcs, COMSIG_GLOB_TRAITOR_OBJECTIVE_COMPLETED, PROC_REF(on_global_obj_completed))
- return TRUE
-
-/datum/traitor_objective/locate_weakpoint/ungenerate_objective()
- UnregisterSignal(SSdcs, COMSIG_GLOB_TRAITOR_OBJECTIVE_COMPLETED)
-
-/datum/traitor_objective/locate_weakpoint/on_objective_taken(mob/user)
- . = ..()
-
- // We don't want multiple people being able to take weakpoint objectives if they get one available at the same time
- for(var/datum/traitor_objective/locate_weakpoint/other_objective as anything in SStraitor.all_objectives_by_type[/datum/traitor_objective/locate_weakpoint])
- if(other_objective != src)
- other_objective.fail_objective()
-
-
-/datum/traitor_objective/locate_weakpoint/proc/on_global_obj_completed(datum/source, datum/traitor_objective/objective)
- SIGNAL_HANDLER
- if(istype(objective, /datum/traitor_objective/locate_weakpoint))
- fail_objective()
-
-/datum/traitor_objective/locate_weakpoint/generate_ui_buttons(mob/user)
- var/list/buttons = list()
- if(!locator_sent)
- buttons += add_ui_button("", "Pressing this will materialize a weakpoint locator in your hand.", "globe", "locator")
- if(weakpoint_found && !bomb_sent)
- buttons += add_ui_button("", "Pressing this will materialize an ES8 explosive charge in your hand.", "bomb", "shatter_charge")
- return buttons
-
-/datum/traitor_objective/locate_weakpoint/ui_perform_action(mob/living/user, action)
- . = ..()
- switch(action)
- if("locator")
- if(locator_sent)
- return
- locator_sent = TRUE
- var/obj/item/weakpoint_locator/locator = new(user.drop_location(), src)
- user.put_in_hands(locator)
- locator.balloon_alert(user, "the weakpoint locator materializes in your hand")
-
- if("shatter_charge")
- if(bomb_sent)
- return
- bomb_sent = TRUE
- var/obj/item/grenade/c4/es8/bomb = new(user.drop_location(), src)
- user.put_in_hands(bomb)
- bomb.balloon_alert(user, "the ES8 charge materializes in your hand")
-
-/datum/traitor_objective/locate_weakpoint/proc/weakpoint_located()
- description = "Structural weakpoint has been located in %AREA%. Detonate an ES8 explosive charge there to create a shockwave that will severely damage the station."
- replace_in_name("%AREA%", initial(weakpoint_area.name))
- weakpoint_found = TRUE
-
-/datum/traitor_objective/locate_weakpoint/proc/create_shockwave(center_x, center_y, center_z)
- var/turf/epicenter = locate(center_x, center_y, center_z)
- var/lowpop = (length(GLOB.clients) <= CONFIG_GET(number/minimal_access_threshold))
- if(lowpop)
- explosion(epicenter, devastation_range = 2, heavy_impact_range = 4, light_impact_range = 6, explosion_cause = src)
- else
- explosion(epicenter, devastation_range = 3, heavy_impact_range = 6, light_impact_range = 9, explosion_cause = src)
- priority_announce(
- "Attention crew, it appears that a high-power explosive charge has been detonated in your station's weakpoint, causing severe structural damage.",
- "[command_name()] High-Priority Update"
- )
-
- succeed_objective()
-
-/obj/item/weakpoint_locator
- name = "structural weakpoint locator"
- desc = "A device that can triangulate station's structural weakpoint. It has to be used in %AREA1% and %AREA2% in order to triangulate the weakpoint. Warning: station's AI will be notified as soon as the process starts!"
- icon = 'icons/obj/antags/syndicate_tools.dmi'
- icon_state = "weakpoint_locator"
- inhand_icon_state = "weakpoint_locator"
- lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi'
- throwforce = 0
- w_class = WEIGHT_CLASS_SMALL
- throw_speed = 3
- throw_range = 5
- var/datum/weakref/objective_weakref
-
-/obj/item/weakpoint_locator/Initialize(mapload, datum/traitor_objective/locate_weakpoint/objective)
- . = ..()
- objective_weakref = WEAKREF(objective)
- if(!objective)
- return
- var/area/area1 = objective.scan_areas[1]
- var/area/area2 = objective.scan_areas[2]
- desc = replacetext(desc, "%AREA1%", initial(area1.name))
- desc = replacetext(desc, "%AREA2%", initial(area2.name))
-
-/obj/item/weakpoint_locator/Destroy(force)
- objective_weakref = null
- return ..()
-
-/obj/item/weakpoint_locator/attack_self(mob/living/user, modifiers)
- . = ..()
- if(!istype(user) || loc != user || !user.mind) //No TK cheese
- return
-
- var/datum/traitor_objective/locate_weakpoint/objective = objective_weakref.resolve()
-
- if(!objective || objective.objective_state == OBJECTIVE_STATE_INACTIVE)
- to_chat(user, span_warning("Your time to use [src] has not come yet."))
- return
-
- if(objective.handler.owner != user.mind)
- to_chat(user, span_warning("You have zero clue how to use [src]."))
- return
-
- var/area/user_area = get_area(user)
- if(!(user_area.type in objective.scan_areas))
- balloon_alert(user, "invalid area!")
- playsound(user, 'sound/machines/buzz/buzz-sigh.ogg', 30, TRUE)
- return
-
- if(!objective.scan_areas[user_area.type])
- balloon_alert(user, "already scanned here!")
- playsound(user, 'sound/machines/buzz/buzz-sigh.ogg', 30, TRUE)
- return
-
- user.visible_message(span_danger("[user] presses a few buttons on [src] and it starts ominously beeping!"), span_notice("You activate [src] and start scanning the area. Do not exit [get_area_name(user, TRUE)] until the scan finishes!"))
- playsound(user, 'sound/machines/beep/triple_beep.ogg', 30, TRUE)
- var/alertstr = span_userdanger("Network Alert: Station network probing attempt detected[user_area?" in [get_area_name(user, TRUE)]":". Unable to pinpoint location"].")
- for(var/mob/living/silicon/ai/ai_player in GLOB.player_list)
- to_chat(ai_player, alertstr)
-
- if(!do_after(user, 30 SECONDS, src, IGNORE_USER_LOC_CHANGE | IGNORE_TARGET_LOC_CHANGE | IGNORE_HELD_ITEM | IGNORE_INCAPACITATED | IGNORE_SLOWDOWNS, extra_checks = CALLBACK(src, PROC_REF(scan_checks), user, user_area, objective), hidden = TRUE))
- playsound(user, 'sound/machines/buzz/buzz-sigh.ogg', 30, TRUE)
- return
-
- playsound(user, 'sound/machines/ding.ogg', 100, TRUE)
- objective.scan_areas[user_area.type] = FALSE
- for(var/area/scan_area as anything in objective.scan_areas)
- if(objective.scan_areas[scan_area])
- say("Next scanning location is [initial(scan_area.name)]")
- return
-
- to_chat(user, span_notice("Scan finished. Structural weakpoint located in [initial(objective.weakpoint_area.name)]."))
- objective.weakpoint_located()
-
-/obj/item/weakpoint_locator/proc/scan_checks(mob/living/user, area/user_area, datum/traitor_objective/locate_weakpoint/parent_objective)
- if(get_area(user) != user_area)
- return FALSE
-
- if(parent_objective.objective_state != OBJECTIVE_STATE_ACTIVE)
- return FALSE
-
- var/atom/current_loc = loc
- while(!isturf(current_loc) && !ismob(current_loc))
- current_loc = current_loc.loc
-
- if(current_loc != user)
- return FALSE
-
- return TRUE
-
-/obj/item/grenade/c4/es8
- name = "ES8 explosive charge"
- desc = "A high-power explosive charge designed to create a shockwave in a structural weakpoint of the station."
-
- icon_state = "plasticx40"
- inhand_icon_state = "plasticx4"
- worn_icon_state = "x4"
-
- boom_sizes = list(3, 6, 9)
-
- /// Weakref to user's objective
- var/datum/weakref/objective_weakref
-
-/obj/item/grenade/c4/es8/Initialize(mapload, objective)
- . = ..()
- objective_weakref = WEAKREF(objective)
-
-/obj/item/grenade/c4/es8/Destroy()
- objective_weakref = null
- return ..()
-
-/obj/item/grenade/c4/es8/plant_c4(atom/bomb_target, mob/living/user)
- if(!IS_TRAITOR(user))
- to_chat(user, span_warning("You can't seem to find a way to detonate the charge."))
- return FALSE
-
- var/datum/traitor_objective/locate_weakpoint/objective = objective_weakref.resolve()
- if(!objective || objective.objective_state == OBJECTIVE_STATE_INACTIVE || objective.handler.owner != user.mind)
- to_chat(user, span_warning("You don't think it would be wise to use [src]."))
- return FALSE
-
- var/area/target_area = get_area(bomb_target)
- if (target_area.type != objective.weakpoint_area)
- to_chat(user, span_warning("[src] can only be detonated in [initial(objective.weakpoint_area.name)]."))
- return FALSE
-
- if(!isfloorturf(bomb_target) && !iswallturf(bomb_target))
- to_chat(user, span_warning("[src] can only be planted on a wall or the floor!"))
- return FALSE
-
- return ..()
-
-/obj/item/grenade/c4/es8/detonate(mob/living/lanced_by)
- var/area/target_area = get_area(target)
- var/datum/traitor_objective/locate_weakpoint/objective = objective_weakref.resolve()
-
- if(!objective)
- return
-
- if (target_area.type != objective.weakpoint_area)
- var/obj/item/grenade/c4/es8/new_bomb = new(target.drop_location())
- new_bomb.balloon_alert_to_viewers("invalid location!")
- target.cut_overlay(plastic_overlay, TRUE)
- qdel(src)
- return
-
- objective.create_shockwave(target.x, target.y, target.z)
- return ..()
diff --git a/code/modules/antagonists/traitor/objectives/sabotage_machinery.dm b/code/modules/antagonists/traitor/objectives/sabotage_machinery.dm
deleted file mode 100644
index 5f3e2387a35..00000000000
--- a/code/modules/antagonists/traitor/objectives/sabotage_machinery.dm
+++ /dev/null
@@ -1,239 +0,0 @@
-/// Datum which manages references to things we are instructed to destroy
-GLOBAL_DATUM_INIT(objective_machine_handler, /datum/objective_target_machine_handler, new())
-
-/// Marks a machine as a possible traitor sabotage target
-/proc/add_sabotage_machine(source, typepath)
- LAZYADD(GLOB.objective_machine_handler.machine_instances_by_path[typepath], source)
- return typepath
-
-/// Traitor objective to destroy a machine the crew cares about
-/datum/traitor_objective_category/sabotage_machinery
- name = "Sabotage Worksite"
- objectives = list(
- /datum/traitor_objective/sabotage_machinery/trap = 1,
- /datum/traitor_objective/sabotage_machinery/destroy = 1,
- )
-
-/datum/traitor_objective/sabotage_machinery
- name = "Sabotage the %MACHINE%"
- description = "Abstract objective holder which shouldn't appear in your uplink."
- abstract_type = /datum/traitor_objective/sabotage_machinery
-
- /// The maximum amount of this type of objective a traitor can have, set to 0 for no limit.
- var/maximum_allowed = 0
- /// The possible target machinery and the jobs tied to each one.
- var/list/applicable_jobs = list()
- /// The chosen job. Used to check for duplicates
- var/chosen_job
-
-/datum/traitor_objective/sabotage_machinery/can_generate_objective(datum/mind/generating_for, list/possible_duplicates)
- if(!maximum_allowed)
- return TRUE
- if(length(possible_duplicates) >= maximum_allowed)
- return FALSE
- return TRUE
-
-/datum/traitor_objective/sabotage_machinery/generate_objective(datum/mind/generating_for, list/possible_duplicates)
- var/list/possible_jobs = applicable_jobs.Copy()
- for(var/datum/traitor_objective/sabotage_machinery/objective as anything in possible_duplicates)
- possible_jobs -= objective.chosen_job
- for(var/available_job in possible_jobs)
- var/job_machine_path = possible_jobs[available_job]
- if (!length(GLOB.objective_machine_handler.machine_instances_by_path[job_machine_path]))
- possible_jobs -= available_job
- if(!length(possible_jobs))
- return FALSE
-
- chosen_job = pick(possible_jobs)
- var/list/obj/machinery/possible_machines = GLOB.objective_machine_handler.machine_instances_by_path[possible_jobs[chosen_job]]
- for(var/obj/machinery/machine as anything in possible_machines)
- prepare_machine(machine)
-
- replace_in_name("%JOB%", LOWER_TEXT(chosen_job))
- replace_in_name("%MACHINE%", possible_machines[1].name)
- return TRUE
-
-/// Marks a given machine as our target
-/datum/traitor_objective/sabotage_machinery/proc/prepare_machine(obj/machinery/machine)
- AddComponent(/datum/component/traitor_objective_register, machine, succeed_signals = list(COMSIG_QDELETING))
-
-// Destroy machines which are in annoying locations, are annoying when destroyed, and aren't directly interacted with
-/datum/traitor_objective/sabotage_machinery/destroy
- name = "Destroy the %MACHINE%"
- description = "Destroy the %MACHINE% to cause disarray and disrupt the operations of the %JOB%'s department."
-
- progression_reward = list(5 MINUTES, 10 MINUTES)
- telecrystal_reward = list(3, 4)
-
- progression_minimum = 15 MINUTES
-
- applicable_jobs = list(
- JOB_STATION_ENGINEER = /obj/machinery/telecomms/hub,
- JOB_SCIENTIST = /obj/machinery/rnd/server,
- )
-
-// Rig machines which are in public locations to explode when interacted with
-/datum/traitor_objective/sabotage_machinery/trap
- name = "Sabotage the %MACHINE%"
- description = "Destroy the %MACHINE% to cause disarray and disrupt the operations of the %JOB%'s department. If you can get another crew member to destroy the machine using the provided booby trap, you will be rewarded with an additional %PROGRESSION% reputation and %TC% telecrystals."
-
- progression_reward = list(2 MINUTES, 4 MINUTES)
- telecrystal_reward = 0 // Only from completing the bonus objective
-
- progression_minimum = 0 MINUTES
- progression_maximum = 10 MINUTES
-
- maximum_allowed = 2
- applicable_jobs = list(
- JOB_CHIEF_ENGINEER = /obj/machinery/rnd/production/protolathe/department/engineering,
- JOB_CHIEF_MEDICAL_OFFICER = /obj/machinery/rnd/production/techfab/department/medical,
- JOB_HEAD_OF_PERSONNEL = /obj/machinery/rnd/production/techfab/department/service,
- JOB_QUARTERMASTER = /obj/machinery/rnd/production/techfab/department/cargo,
- JOB_RESEARCH_DIRECTOR = /obj/machinery/rnd/production/protolathe/department/science,
- JOB_SHAFT_MINER = /obj/machinery/mineral/ore_redemption,
- )
-
- /// Bonus reward to grant if you booby trap successfully
- var/bonus_tc = 2
- /// Bonus progression to grant if you booby trap successfully
- var/bonus_progression = 5 MINUTES
- /// Have we given out a traitor trap item?
- var/traitor_trapper_given = FALSE
-
-/datum/traitor_objective/sabotage_machinery/trap/generate_objective(datum/mind/generating_for, list/possible_duplicates)
- . = ..()
- if (!.)
- return FALSE
-
- replace_in_name("%TC%", bonus_tc)
- replace_in_name("%PROGRESSION%", DISPLAY_PROGRESSION(bonus_progression))
- return TRUE
-
-/datum/traitor_objective/sabotage_machinery/trap/prepare_machine(obj/machinery/machine)
- RegisterSignal(machine, COMSIG_TRAITOR_MACHINE_TRAP_TRIGGERED, PROC_REF(sabotage_success))
- return ..()
-
-/// Called when you successfully proc the booby trap, gives a bonus reward
-/datum/traitor_objective/sabotage_machinery/trap/proc/sabotage_success(obj/machinery/machine)
- progression_reward += bonus_progression
- telecrystal_reward += bonus_tc
- succeed_objective()
-
-/datum/traitor_objective/sabotage_machinery/trap/generate_ui_buttons(mob/user)
- var/list/buttons = list()
- if(!traitor_trapper_given)
- buttons += add_ui_button("", "Pressing this will materialize an explosive trap in your hand, which you can conceal within the target machine", "wifi", "summon_gear")
- return buttons
-
-/datum/traitor_objective/sabotage_machinery/trap/ui_perform_action(mob/living/user, action)
- . = ..()
- switch(action)
- if("summon_gear")
- if(traitor_trapper_given)
- return
- traitor_trapper_given = TRUE
- var/obj/item/traitor_machine_trapper/tool = new(user.drop_location())
- user.put_in_hands(tool)
- tool.balloon_alert(user, "a booby trap materializes in your hand")
- tool.target_machine_path = applicable_jobs[chosen_job]
-
-/// Item which you use on a machine to cause it to explode next time someone interacts with it
-/obj/item/traitor_machine_trapper
- name = "suspicious device"
- desc = "It looks dangerous."
- icon = 'icons/obj/weapons/grenade.dmi'
- icon_state = "boobytrap"
-
- /// Light explosion range, to hurt the person using the machine
- var/explosion_range = 3
- /// The type of object on which this can be planted on.
- var/obj/machinery/target_machine_path
- /// The time it takes to deploy the bomb.
- var/deploy_time = 10 SECONDS
-
-/obj/item/traitor_machine_trapper/examine(mob/user)
- . = ..()
- if(!IS_TRAITOR(user))
- return
- if(target_machine_path)
- . += span_notice("This device must be placed by clicking on a [initial(target_machine_path.name)] with it. It can be removed with a screwdriver.")
- . += span_notice("Remember, you may leave behind fingerprints on the device. Wear gloves when handling it to be safe!")
-
-/obj/item/traitor_machine_trapper/pre_attack(atom/target, mob/living/user, params)
- . = ..()
- if (. || !istype(target, target_machine_path))
- return
- balloon_alert(user, "planting device...")
- if(!do_after(user, delay = deploy_time, target = src, interaction_key = DOAFTER_SOURCE_PLANTING_DEVICE, hidden = TRUE))
- return TRUE
- target.AddComponent(\
- /datum/component/interaction_booby_trap,\
- additional_triggers = list(COMSIG_ORM_COLLECTED_ORE),\
- on_triggered_callback = CALLBACK(src, PROC_REF(on_triggered)),\
- on_defused_callback = CALLBACK(src, PROC_REF(on_defused)),\
- )
- RegisterSignal(target, COMSIG_QDELETING, GLOBAL_PROC_REF(qdel), src)
- moveToNullspace()
- return TRUE
-
-/// Called when applied trap is triggered, mark success
-/obj/item/traitor_machine_trapper/proc/on_triggered(atom/machine)
- SEND_SIGNAL(machine, COMSIG_TRAITOR_MACHINE_TRAP_TRIGGERED)
- qdel(src)
-
-/// Called when applied trap has been defused, retrieve this item from nullspace
-/obj/item/traitor_machine_trapper/proc/on_defused(atom/machine, mob/defuser, obj/item/tool)
- UnregisterSignal(machine, COMSIG_QDELETING)
- playsound(machine, 'sound/effects/structure_stress/pop3.ogg', 100, vary = TRUE)
- forceMove(get_turf(machine))
- visible_message(span_warning("A [src] falls out from the [machine]!"))
-
-/// Datum which manages references to things we are instructed to destroy
-/datum/objective_target_machine_handler
- /// Existing instances of machines organised by typepath
- var/list/machine_instances_by_path = list()
-
-/datum/objective_target_machine_handler/New()
- . = ..()
- RegisterSignal(SSdcs, COMSIG_GLOB_NEW_MACHINE, PROC_REF(on_machine_created))
- RegisterSignal(SSatoms, COMSIG_SUBSYSTEM_POST_INITIALIZE, PROC_REF(finalise_valid_targets))
-
-/// Adds a newly created machine to our list of machines, if we need it
-/datum/objective_target_machine_handler/proc/on_machine_created(datum/source, obj/machinery/new_machine)
- SIGNAL_HANDLER
- new_machine.add_as_sabotage_target()
-
-/// Confirm that everything added to the list is a valid target, then prevent new targets from being added
-/datum/objective_target_machine_handler/proc/finalise_valid_targets()
- SIGNAL_HANDLER
- for (var/machine_type in machine_instances_by_path)
- for (var/obj/machinery/machine as anything in machine_instances_by_path[machine_type])
- var/turf/place = get_turf(machine)
- if(!place || !is_station_level(place.z))
- machine_instances_by_path[machine_type] -= machine
- continue
- RegisterSignal(machine, COMSIG_QDELETING, PROC_REF(machine_destroyed))
- UnregisterSignal(SSdcs, COMSIG_GLOB_NEW_MACHINE)
-
-/datum/objective_target_machine_handler/proc/machine_destroyed(atom/machine)
- SIGNAL_HANDLER
- // Sadly can't do a direct typepath association because of some map helper subtypes
- for (var/machine_type in machine_instances_by_path)
- machine_instances_by_path[machine_type] -= machine
-
-// Mark valid machines as targets, add a new entry here if you add a new potential target
-
-/obj/machinery/telecomms/hub/add_as_sabotage_target()
- return add_sabotage_machine(src, /obj/machinery/telecomms/hub) // Not always our specific type because of map helper subtypes
-
-/obj/machinery/rnd/server/add_as_sabotage_target()
- return add_sabotage_machine(src, type)
-
-/obj/machinery/rnd/production/protolathe/department/add_as_sabotage_target()
- return add_sabotage_machine(src, type)
-
-/obj/machinery/rnd/production/techfab/department/add_as_sabotage_target()
- return add_sabotage_machine(src, type)
-
-/obj/machinery/mineral/ore_redemption/add_as_sabotage_target()
- return add_sabotage_machine(src, type)
diff --git a/code/modules/antagonists/traitor/objectives/steal.dm b/code/modules/antagonists/traitor/objectives/steal.dm
deleted file mode 100644
index 77e7d17510b..00000000000
--- a/code/modules/antagonists/traitor/objectives/steal.dm
+++ /dev/null
@@ -1,322 +0,0 @@
-/datum/traitor_objective_category/steal_item
- name = "Steal Item"
- objectives = list(
- list(
- /datum/traitor_objective/steal_item/low_risk = 1,
- /datum/traitor_objective/destroy_item/low_risk = 1,
- ) = 1,
- /datum/traitor_objective/steal_item/somewhat_risky = 1,
- list(
- /datum/traitor_objective/destroy_item/very_risky = 1,
- /datum/traitor_objective/steal_item/very_risky = 1,
- ) = 1,
- /datum/traitor_objective/steal_item/most_risky = 1
- )
-
-GLOBAL_DATUM_INIT(steal_item_handler, /datum/objective_item_handler, new())
-
-/datum/objective_item_handler
- var/list/list/objectives_by_path
- var/generated_items = FALSE
-
-/datum/objective_item_handler/New()
- . = ..()
- objectives_by_path = list()
- for(var/datum/objective_item/item as anything in subtypesof(/datum/objective_item))
- objectives_by_path[initial(item.targetitem)] = list()
- RegisterSignal(SSatoms, COMSIG_SUBSYSTEM_POST_INITIALIZE, PROC_REF(save_items))
- RegisterSignal(SSdcs, COMSIG_GLOB_NEW_ITEM, PROC_REF(new_item_created))
-
-/datum/objective_item_handler/proc/new_item_created(datum/source, obj/item/item)
- SIGNAL_HANDLER
- if(HAS_TRAIT(item, TRAIT_ITEM_OBJECTIVE_BLOCKED))
- return
- if(!generated_items)
- item.add_stealing_item_objective()
- return
- var/typepath = item.add_stealing_item_objective()
- if(typepath != null)
- register_item(item, typepath)
-
-/// Registers all items that are potentially stealable and removes ones that aren't.
-/// We still need to do things this way because on mapload, items may not be on the station until everything has finished loading.
-/datum/objective_item_handler/proc/save_items()
- SIGNAL_HANDLER
- for(var/obj/item/typepath as anything in objectives_by_path)
- var/list/obj_by_path_cache = objectives_by_path[typepath].Copy()
- for(var/obj/item/object as anything in obj_by_path_cache)
- register_item(object, typepath)
- generated_items = TRUE
-
-/datum/objective_item_handler/proc/register_item(atom/object, typepath)
- var/turf/place = get_turf(object)
- if(!place || !is_station_level(place.z))
- objectives_by_path[typepath] -= object
- return
- RegisterSignal(object, COMSIG_QDELETING, PROC_REF(remove_item))
-
-/datum/objective_item_handler/proc/remove_item(atom/source)
- SIGNAL_HANDLER
- for(var/typepath in objectives_by_path)
- objectives_by_path[typepath] -= source
-
-/datum/traitor_objective/steal_item
- name = "Steal %ITEM% and place a schematics scanner on it."
- description = "Use the button below to materialize the schematic scanner within your hand, where you'll then be able to place it on the item. Additionally, you can keep it near you and let it scan for %TIME% minutes, and you will be rewarded with %PROGRESSION% reputation and %TC% telecrystals."
-
- progression_minimum = 20 MINUTES
-
- var/list/possible_items = list()
- /// The current target item that we are stealing.
- var/datum/objective_item/steal/target_item
- /// A list of 2 elements, which contain the range that the time will be in. Represented in minutes.
- var/hold_time_required = list(5, 15)
- /// The current time fulfilled around the item
- var/time_fulfilled = 0
- /// The maximum distance between the bug and the objective taker for time to count as fulfilled
- var/max_distance = 4
- /// The bug that will be put onto the item
- var/obj/item/traitor_bug/bug
- /// Any special equipment that may be needed
- var/list/special_equipment
- /// Telecrystal reward increase per unit of time.
- var/minutes_per_telecrystal = 3
-
- /// Extra TC given for holding the item for the required duration of time.
- var/extra_tc = 0
- /// Extra progression given for holding the item for the required duration of time.
- var/extra_progression = 0
-
- abstract_type = /datum/traitor_objective/steal_item
-
-/datum/traitor_objective/steal_item/low_risk
- progression_minimum = 10 MINUTES
- progression_maximum = 35 MINUTES
- progression_reward = list(5 MINUTES, 10 MINUTES)
- telecrystal_reward = 0
- minutes_per_telecrystal = 6
-
- possible_items = list(
- /datum/objective_item/steal/traitor/cargo_budget,
- /datum/objective_item/steal/traitor/clown_shoes,
- /datum/objective_item/steal/traitor/lawyers_badge,
- /datum/objective_item/steal/traitor/chef_moustache,
- /datum/objective_item/steal/traitor/pka,
- )
-
-/datum/traitor_objective/steal_item/somewhat_risky
- progression_minimum = 20 MINUTES
- progression_maximum = 50 MINUTES
- progression_reward = 10 MINUTES
- telecrystal_reward = 2
-
- possible_items = list(
- /datum/objective_item/steal/traitor/chief_engineer_belt
- )
-
-/datum/traitor_objective/steal_item/very_risky
- progression_minimum = 30 MINUTES
- progression_reward = 15 MINUTES
- telecrystal_reward = 3
-
- possible_items = list(
- /datum/objective_item/steal/traitor/det_revolver,
- )
-
-/datum/traitor_objective/steal_item/most_risky
- progression_minimum = 50 MINUTES
- progression_reward = 20 MINUTES
- telecrystal_reward = 5
-
- possible_items = list(
- /datum/objective_item/steal/traitor/captain_modsuit,
- /datum/objective_item/steal/traitor/captain_spare,
- )
-
-/datum/traitor_objective/steal_item/most_risky/generate_objective(datum/mind/generating_for, list/possible_duplicates)
- if(!handler.get_completion_count(/datum/traitor_objective/steal_item/very_risky))
- return FALSE
- return ..()
-
-/datum/traitor_objective/steal_item/generate_objective(datum/mind/generating_for, list/possible_duplicates)
- for(var/datum/traitor_objective/steal_item/objective as anything in possible_duplicates)
- possible_items -= objective.target_item.type
- while(length(possible_items))
- var/datum/objective_item/steal/target = pick_n_take(possible_items)
- target = new target()
- if(!target.valid_objective_for(list(generating_for), require_owner = TRUE))
- qdel(target)
- continue
- target_item = target
- break
- if(!target_item)
- return FALSE
- if(length(target_item.special_equipment))
- special_equipment = target_item.special_equipment
- hold_time_required = rand(hold_time_required[1], hold_time_required[2])
- extra_progression += hold_time_required * (1 MINUTES)
- extra_tc += round(hold_time_required / max(minutes_per_telecrystal, 0.1))
- replace_in_name("%ITEM%", target_item.name)
- replace_in_name("%TIME%", hold_time_required)
- replace_in_name("%TC%", extra_tc)
- replace_in_name("%PROGRESSION%", DISPLAY_PROGRESSION(extra_progression))
- return TRUE
-
-/datum/traitor_objective/steal_item/ungenerate_objective()
- STOP_PROCESSING(SSprocessing, src)
- if(bug)
- UnregisterSignal(bug, list(COMSIG_TRAITOR_BUG_PLANTED_OBJECT, COMSIG_TRAITOR_BUG_PRE_PLANTED_OBJECT))
- bug = null
-
-/datum/traitor_objective/steal_item/generate_ui_buttons(mob/user)
- var/list/buttons = list()
- if(special_equipment)
- buttons += add_ui_button("", "Pressing this will summon any extra special equipment you may need for the mission.", "tools", "summon_gear")
- if(!bug)
- buttons += add_ui_button("", "Pressing this will materialize a scanner in your hand, which you can place on the target item", "wifi", "summon_bug")
- else if(bug.planted_on)
- buttons += add_ui_button("[DisplayTimeText(time_fulfilled)]", "This tells you how much time you have spent around the target item after the scanner has been planted.", "clock", "none")
- buttons += add_ui_button("Skip Time", "Pressing this will succeed the mission. You will not get the extra TC and progression.", "forward", "cash_out")
- return buttons
-
-/datum/traitor_objective/steal_item/ui_perform_action(mob/living/user, action)
- . = ..()
- switch(action)
- if("summon_bug")
- if(bug)
- return
- bug = new(user.drop_location())
- user.put_in_hands(bug)
- bug.balloon_alert(user, "the scanner materializes in your hand")
- bug.target_object_type = target_item.targetitem
- AddComponent(/datum/component/traitor_objective_register, bug, \
- fail_signals = list(COMSIG_QDELETING), \
- penalty = telecrystal_penalty)
- RegisterSignal(bug, COMSIG_TRAITOR_BUG_PLANTED_OBJECT, PROC_REF(on_bug_planted))
- RegisterSignal(bug, COMSIG_TRAITOR_BUG_PRE_PLANTED_OBJECT, PROC_REF(handle_special_case))
- if("summon_gear")
- if(!special_equipment)
- return
- for(var/item in special_equipment)
- var/obj/item/new_item = new item(user.drop_location())
- user.put_in_hands(new_item)
- user.balloon_alert(user, "the equipment materializes in your hand")
- special_equipment = null
- if("cash_out")
- if(!bug.planted_on)
- return
- succeed_objective()
-
-/datum/traitor_objective/steal_item/process(seconds_per_tick)
- var/mob/owner = handler.owner?.current
- if(objective_state != OBJECTIVE_STATE_ACTIVE || !bug.planted_on)
- return PROCESS_KILL
- if(!owner)
- fail_objective()
- return PROCESS_KILL
- if(get_dist(get_turf(owner), get_turf(bug)) > max_distance)
- return
- time_fulfilled += seconds_per_tick * (1 SECONDS)
- if(time_fulfilled >= hold_time_required * (1 MINUTES))
- progression_reward += extra_progression
- telecrystal_reward += extra_tc
- succeed_objective()
- return PROCESS_KILL
- handler.on_update()
-
-/datum/traitor_objective/steal_item/proc/handle_special_case(obj/item/source, obj/item/target)
- SIGNAL_HANDLER
- if(HAS_TRAIT(target, TRAIT_ITEM_OBJECTIVE_BLOCKED))
- return COMPONENT_FORCE_FAIL_PLACEMENT
- if(istype(target, target_item.targetitem))
- if(!target_item.check_special_completion(target))
- return COMPONENT_FORCE_FAIL_PLACEMENT
- return
-
- var/found = FALSE
- for(var/typepath in target_item.valid_containers)
- if(istype(target, typepath))
- found = TRUE
- break
-
- if(!found)
- return
-
- var/found_item = locate(target_item.targetitem) in target
- if(!found_item || !target_item.check_special_completion(found_item))
- return COMPONENT_FORCE_FAIL_PLACEMENT
- return COMPONENT_FORCE_PLACEMENT
-
-/datum/traitor_objective/steal_item/proc/on_bug_planted(obj/item/source, obj/item/location)
- SIGNAL_HANDLER
- if(objective_state == OBJECTIVE_STATE_ACTIVE)
- START_PROCESSING(SSprocessing, src)
-
-/obj/item/traitor_bug
- name = "suspicious device"
- desc = "It looks dangerous."
- item_flags = NOBLUDGEON
-
- icon = 'icons/obj/antags/syndicate_tools.dmi'
- icon_state = "bug"
-
- /// The object on which this bug can be planted on. Has to be a type.
- var/obj/target_object_type
- /// The object this bug is currently planted on.
- var/obj/planted_on
- /// The time it takes to place this bug.
- var/deploy_time = 10 SECONDS
-
-/obj/item/traitor_bug/Initialize(mapload)
- . = ..()
- ADD_TRAIT(src, TRAIT_EXAMINE_SKIP, INNATE_TRAIT)
-
-/obj/item/traitor_bug/examine(mob/user)
- . = ..()
- if(planted_on)
- return
-
- if(IS_TRAITOR(user))
- if(target_object_type)
- . += span_notice("This device must be placed by clicking on the [initial(target_object_type.name)] with it.")
- . += span_notice("Remember, you may leave behind fingerprints or fibers on the device. Use soap or similar to scrub it clean to be safe!")
-
-/obj/item/traitor_bug/interact_with_atom(atom/movable/target, mob/living/user, list/modifiers)
- if(!target_object_type || !ismovable(target))
- return NONE
- if(SHOULD_SKIP_INTERACTION(target, src, user))
- return NONE
- var/result = SEND_SIGNAL(src, COMSIG_TRAITOR_BUG_PRE_PLANTED_OBJECT, target)
- if(!(result & COMPONENT_FORCE_PLACEMENT))
- if(result & COMPONENT_FORCE_FAIL_PLACEMENT || !istype(target, target_object_type))
- balloon_alert(user, "you can't attach this onto here!")
- return ITEM_INTERACT_BLOCKING
- if(!do_after(user, deploy_time, src, hidden = TRUE))
- return ITEM_INTERACT_BLOCKING
- if(planted_on)
- return ITEM_INTERACT_BLOCKING
- forceMove(target)
- target.vis_contents += src
- vis_flags |= VIS_INHERIT_PLANE
- planted_on = target
- RegisterSignal(planted_on, COMSIG_QDELETING, PROC_REF(handle_planted_on_deletion))
- SEND_SIGNAL(src, COMSIG_TRAITOR_BUG_PLANTED_OBJECT, target)
- return ITEM_INTERACT_SUCCESS
-
-/obj/item/traitor_bug/proc/handle_planted_on_deletion()
- planted_on = null
-
-/obj/item/traitor_bug/Destroy()
- if(planted_on)
- vis_flags &= ~VIS_INHERIT_PLANE
- planted_on.vis_contents -= src
- return ..()
-
-/obj/item/traitor_bug/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE)
- . = ..()
- if(planted_on)
- vis_flags &= ~VIS_INHERIT_PLANE
- planted_on.vis_contents -= src
- anchored = FALSE
- UnregisterSignal(planted_on, COMSIG_QDELETING)
- planted_on = null
diff --git a/code/modules/antagonists/traitor/traitor_objective.dm b/code/modules/antagonists/traitor/traitor_objective.dm
deleted file mode 100644
index ecfebaddead..00000000000
--- a/code/modules/antagonists/traitor/traitor_objective.dm
+++ /dev/null
@@ -1,264 +0,0 @@
-/// A traitor objective. Traitor objectives should not be deleted after they have been created and established, only failed.
-/// If a traitor objective needs to be removed from the failed/completed objective list of their handler, then you are doing something wrong
-/// and you should reconsider. When an objective is failed/completed, that is final and the only way you can change that is by refactoring the code.
-/datum/traitor_objective
- /// The name of the traitor objective
- var/name = "traitor objective"
- /// The description of the traitor objective
- var/description = "this is a traitor objective"
- /// The uplink handler holder to give the progression and telecrystals to.
- var/datum/uplink_handler/handler
- /// The minimum required progression points for this objective
- var/progression_minimum = null
- /// The maximum progression before this objective cannot appear anymore
- var/progression_maximum = INFINITY
- /// The progression that is rewarded from completing this traitor objective. Can either be a list of list(min, max) or a direct value
- var/progression_reward = 0 MINUTES
- /// The telecrystals that are rewarded from completing this traitor objective. Can either be a list of list(min,max) or a direct value
- var/telecrystal_reward = 0
- /// TC penalty for failing an objective or cancelling it
- var/telecrystal_penalty = 1
- /// The time at which this objective was first created
- var/time_of_creation = 0
- /// The time at which this objective was completed
- var/time_of_completion = 0
- /// The current state of this objective
- var/objective_state = OBJECTIVE_STATE_INACTIVE
- /// Whether this objective was forced upon by an admin. Won't get autocleared by the traitor subsystem if progression surpasses an amount
- var/forced = FALSE
- /// Whether this objective was skipped by going from an inactive state to a failed state.
- var/skipped = FALSE
-
- /// Determines how influential global progression will affect this objective. Set to 0 to disable.
- var/global_progression_influence_intensity = 0.1
- /// Determines how great the deviance has to be before progression starts to get reduced.
- var/global_progression_deviance_required = 1
- /// Determines the minimum and maximum progression this objective can be worth as a result of being influenced by global progression
- /// Should only be smaller than or equal to 1
- var/global_progression_limit_coeff = 0.6
- /// The deviance coefficient used to determine the randomness of the progression rewards.
- var/progression_cost_coeff_deviance = 0.05
- /// This gets added onto the coeff when calculating the updated progression cost. Used for variability and a slight bit of randomness
- var/progression_cost_coeff = 0
- /// The percentage that this objective has been increased or decreased by as a result of progression. Used by the UI
- var/original_progression = 0
- /// Abstract type that won't be included as a possible objective
- var/abstract_type = /datum/traitor_objective
- /// The duplicate type that will be used to check for duplicates.
- /// If undefined, this will either take from the abstract type or the type of the objective itself
- var/duplicate_type = null
- /// Used only in unit testing. Can be used to explicitly skip the progression_reward and telecrystal_reward check for non-abstract objectives.
- /// Useful for final objectives as they don't need a reward.
- var/needs_reward = TRUE
-
-/// Returns a list of variables that can be changed by config, allows for balance through configuration.
-/// It is not recommended to finetweak any values of objectives on your server.
-/datum/traitor_objective/proc/supported_configuration_changes()
- return list(
- NAMEOF(src, global_progression_influence_intensity),
- NAMEOF(src, global_progression_deviance_required),
- NAMEOF(src, global_progression_limit_coeff)
- )
-
-/// Replaces a word in the name of the proc. Also does it for the description
-/datum/traitor_objective/proc/replace_in_name(replace, word)
- name = replacetext(name, replace, word)
- description = replacetext(description, replace, word)
-
-/datum/traitor_objective/New(datum/uplink_handler/handler)
- . = ..()
- src.handler = handler
- src.time_of_creation = world.time
- apply_configuration()
- if(SStraitor.generate_objectives)
- if(islist(telecrystal_reward))
- telecrystal_reward = rand(telecrystal_reward[1], telecrystal_reward[2])
- if(islist(progression_reward))
- progression_reward = rand(progression_reward[1], progression_reward[2])
- else
- if(!islist(telecrystal_reward))
- telecrystal_reward = list(telecrystal_reward, telecrystal_reward)
- if(!islist(progression_reward))
- progression_reward = list(progression_reward, progression_reward)
- progression_cost_coeff = (rand()*2 - 1) * progression_cost_coeff_deviance
-
-/datum/traitor_objective/proc/apply_configuration()
- if(!length(SStraitor.configuration_data))
- return
- var/datum/traitor_objective/current_type = type
- var/list/types = list()
- while(current_type != /datum/traitor_objective)
- types += current_type
- current_type = type2parent(current_type)
- types += /datum/traitor_objective
- // Reverse the list direction
- reverse_range(types)
- var/list/supported_configurations = supported_configuration_changes()
- for(var/typepath in types)
- if(!(typepath in SStraitor.configuration_data))
- continue
- var/list/changes = SStraitor.configuration_data[typepath]
- for(var/variable in changes)
- if(!(variable in supported_configurations))
- continue
- vars[variable] = changes[variable]
-
-
-/// Updates the progression reward, scaling it depending on their current progression compared against the global progression
-/datum/traitor_objective/proc/update_progression_reward()
- if(!SStraitor.generate_objectives)
- return
- progression_reward = original_progression
- if(global_progression_influence_intensity <= 0)
- return
- var/minimum_progression = progression_reward * global_progression_limit_coeff
- var/maximum_progression = progression_reward * (2-global_progression_limit_coeff)
- var/deviance = (SStraitor.current_global_progression - handler.progression_points) / SStraitor.progression_scaling_deviance
- if(abs(deviance) < global_progression_deviance_required)
- return
- if(abs(deviance) == deviance) // If it is positive
- deviance = deviance - global_progression_deviance_required
- else
- deviance = deviance + global_progression_deviance_required
- var/coeff = NUM_E ** (global_progression_influence_intensity * abs(deviance)) - 1
- if(abs(deviance) != deviance)
- coeff *= -1
-
- // This has less of an effect as the coeff gets nearer to -1. Is linear
- coeff += progression_cost_coeff * min(max(1 - abs(coeff), 1), 0)
-
-
- progression_reward = clamp(
- progression_reward + progression_reward * coeff,
- minimum_progression,
- maximum_progression
- )
-
-/datum/traitor_objective/Destroy(force)
- handler = null
- return ..()
-
-/// Called whenever the objective is about to be generated. Bypassed by forcefully adding objectives.
-/// Returning false or true will do the same as the generate_objective proc.
-/datum/traitor_objective/proc/can_generate_objective(datum/mind/generating_for, list/possible_duplicates)
- return TRUE
-
-/// Called when the objective should be generated. Should return if the objective has been successfully generated.
-/// If false is returned, the objective will be removed as a potential objective for the traitor it is being generated for.
-/// This is only temporary, it will run the proc again when objectives are generated for the traitor again.
-/datum/traitor_objective/proc/generate_objective(datum/mind/generating_for, list/possible_duplicates)
- return FALSE
-
-/// Used to clean up signals and stop listening to states.
-/datum/traitor_objective/proc/ungenerate_objective()
- return
-
-/datum/traitor_objective/proc/get_log_data()
- return list(
- "type" = type,
- "owner" = handler.owner.key,
- "name" = name,
- "description" = description,
- "telecrystal_reward" = telecrystal_reward,
- "progression_reward" = progression_reward,
- "original_progression" = original_progression,
- "objective_state" = objective_state,
- "forced" = forced,
- "time_of_creation" = time_of_creation,
- )
-
-/// Converts the type into a useful debug string to be used for logging and debug display.
-/datum/traitor_objective/proc/to_debug_string()
- return "[type] (Name: [name], TC: [telecrystal_reward], Progression: [progression_reward], Time of creation: [time_of_creation])"
-
-/datum/traitor_objective/proc/save_objective()
- SSblackbox.record_feedback("associative", "traitor_objective", 1, get_log_data())
-
-/// Used to handle cleaning up the objective.
-/datum/traitor_objective/proc/handle_cleanup()
- time_of_completion = world.time
- ungenerate_objective()
- if(objective_state == OBJECTIVE_STATE_INACTIVE)
- skipped = TRUE
- handler.complete_objective(src) // Remove this objective immediately, no reason to keep it around. It isn't even active
-
-/// Used to fail objectives. Players can clear completed objectives in the UI
-/datum/traitor_objective/proc/fail_objective(penalty_cost = 0, trigger_update = TRUE)
- // Don't let players succeed already succeeded/failed objectives
- if(objective_state != OBJECTIVE_STATE_INACTIVE && objective_state != OBJECTIVE_STATE_ACTIVE)
- return
- SEND_SIGNAL(src, COMSIG_TRAITOR_OBJECTIVE_FAILED)
- handle_cleanup()
- log_traitor("[key_name(handler.owner)] [objective_state == OBJECTIVE_STATE_INACTIVE? "missed" : "failed"] [to_debug_string()]")
- if(penalty_cost)
- handler.add_telecrystals(-penalty_cost)
- objective_state = OBJECTIVE_STATE_FAILED
- else
- objective_state = OBJECTIVE_STATE_INVALID
- save_objective()
- if(trigger_update)
- handler.on_update() // Trigger an update to the UI
-
-/// Used to succeed objectives. Allows the player to cash it out in the UI.
-/datum/traitor_objective/proc/succeed_objective()
- // Don't let players succeed already succeeded/failed objectives
- if(objective_state != OBJECTIVE_STATE_INACTIVE && objective_state != OBJECTIVE_STATE_ACTIVE)
- return
- SEND_SIGNAL(src, COMSIG_TRAITOR_OBJECTIVE_COMPLETED)
- SEND_GLOBAL_SIGNAL(COMSIG_GLOB_TRAITOR_OBJECTIVE_COMPLETED, src)
- handle_cleanup()
- log_traitor("[key_name(handler.owner)] [objective_state == OBJECTIVE_STATE_INACTIVE? "missed" : "completed"] [to_debug_string()]")
- objective_state = OBJECTIVE_STATE_COMPLETED
- save_objective()
- handler.on_update() // Trigger an update to the UI
-
-/// Called by player input, do not call directly. Validates whether the objective is finished and pays out the handler if it is.
-/datum/traitor_objective/proc/finish_objective(mob/user)
- switch(objective_state)
- if(OBJECTIVE_STATE_FAILED, OBJECTIVE_STATE_INVALID)
- user.playsound_local(get_turf(user), 'sound/music/antag/traitor/objective_failed.ogg', vol = 100, vary = FALSE, channel = CHANNEL_TRAITOR)
- return TRUE
- if(OBJECTIVE_STATE_COMPLETED)
- user.playsound_local(get_turf(user), 'sound/music/antag/traitor/objective_success.ogg', vol = 100, vary = FALSE, channel = CHANNEL_TRAITOR)
- completion_payout()
- return TRUE
- return FALSE
-
-/// Called when rewards should be given to the user.
-/datum/traitor_objective/proc/completion_payout()
- handler.progression_points += progression_reward
- handler.add_telecrystals(telecrystal_reward)
-
-/// Used for sending data to the uplink UI
-/datum/traitor_objective/proc/uplink_ui_data(mob/user)
- return list(
- "name" = name,
- "description" = description,
- "progression_minimum" = progression_minimum,
- "progression_reward" = progression_reward,
- "telecrystal_reward" = telecrystal_reward,
- "ui_buttons" = generate_ui_buttons(user),
- "objective_state" = objective_state,
- "original_progression" = original_progression,
- "telecrystal_penalty" = telecrystal_penalty,
- )
-
-/datum/traitor_objective/proc/on_objective_taken(mob/user)
- SStraitor.on_objective_taken(src)
- log_traitor("[key_name(handler.owner)] has taken an objective: [to_debug_string()]")
-
-/// Used for generating the UI buttons for the UI. Use ui_perform_action to respond to clicks.
-/datum/traitor_objective/proc/generate_ui_buttons(mob/user)
- return
-
-/datum/traitor_objective/proc/add_ui_button(name, tooltip, icon, action)
- return list(list(
- "name" = name,
- "tooltip" = tooltip,
- "icon" = icon,
- "action" = action,
- ))
-
-/// Return TRUE to trigger a UI update
-/datum/traitor_objective/proc/ui_perform_action(mob/user, action)
- return TRUE
diff --git a/code/modules/antagonists/traitor/uplink_handler.dm b/code/modules/antagonists/traitor/uplink_handler.dm
index 83899300614..2801ef29aad 100644
--- a/code/modules/antagonists/traitor/uplink_handler.dm
+++ b/code/modules/antagonists/traitor/uplink_handler.dm
@@ -20,24 +20,6 @@
var/list/item_stock = list(UPLINK_SHARED_STOCK_KITS = 1 , UPLINK_SHARED_STOCK_SURPLUS = 1)
/// Extra stuff that can be purchased by an uplink, regardless of flag.
var/list/extra_purchasable = list()
- /// Whether this uplink handler has objectives.
- var/has_objectives = TRUE
- /// Whether this uplink handler can TAKE objectives.
- var/can_take_objectives = TRUE
- /// The maximum number of objectives that can be taken
- var/maximum_active_objectives = 2
- /// The maximum number of potential objectives that can exist.
- var/maximum_potential_objectives = 6
- /// Current objectives taken
- var/list/active_objectives = list()
- /// Potential objectives that can be taken
- var/list/potential_objectives = list()
- /// Objectives that have been completed.
- var/list/completed_objectives = list()
- /// All objectives assigned by type to handle any duplicates
- var/list/potential_duplicate_objectives = list()
- /// Text of the final objective, once assigned. Used for uplink data and traitor greentext. Empty string means not yet reached.
- var/final_objective = ""
/// Objectives that must be completed for traitor greentext. Set by the traitor datum.
var/list/primary_objectives
/// The role that this uplink handler is associated to.
@@ -55,10 +37,6 @@
///Reference to a contractor hub that the infiltrator can run, if they purchase it.
var/datum/contractor_hub/contractor_hub
-/datum/uplink_handler/New()
- . = ..()
- maximum_potential_objectives = CONFIG_GET(number/maximum_potential_objectives)
-
/datum/uplink_handler/Destroy(force)
can_replace_objectives = null
replace_objectives = null
@@ -140,136 +118,6 @@
on_update()
return TRUE
-
-/// Generates objectives for this uplink handler
-/datum/uplink_handler/proc/generate_objectives()
- var/potential_objectives_left = maximum_potential_objectives - (length(potential_objectives) + length(active_objectives))
- var/list/objectives = SStraitor.category_handler.get_possible_objectives(progression_points)
- if(!length(objectives))
- return
- while(length(objectives) && potential_objectives_left > 0)
- var/objective_typepath = pick_weight(objectives)
- var/list/target_list = objectives
- while(islist(objective_typepath))
- if(!length(objective_typepath))
- // Need to wrap this in a list or else it list unrolls and the list doesn't actually get removed.
- // Thank you byond, very cool!
- target_list -= list(objective_typepath)
- break
- target_list = objective_typepath
- objective_typepath = pick_weight(objective_typepath)
- if(islist(objective_typepath) || !objective_typepath)
- continue
- if(!try_add_objective(objective_typepath))
- target_list -= objective_typepath
- continue
- potential_objectives_left--
- on_update()
-
-/datum/uplink_handler/proc/try_add_objective(datum/traitor_objective/objective_typepath, force = FALSE)
- var/datum/traitor_objective/objective = new objective_typepath(src)
- var/duplicate_typepath = objective.duplicate_type
- if(!duplicate_typepath)
- if(objective.abstract_type != /datum/traitor_objective)
- duplicate_typepath = objective.abstract_type
- else
- duplicate_typepath = objective_typepath
-
- if(!force && !objective.can_generate_objective(owner, potential_duplicate_objectives[duplicate_typepath]))
- qdel(objective)
- return
-
- var/should_abort = SEND_SIGNAL(objective, COMSIG_TRAITOR_OBJECTIVE_PRE_GENERATE, owner, potential_duplicate_objectives[duplicate_typepath]) & COMPONENT_TRAITOR_OBJECTIVE_ABORT_GENERATION
- if(should_abort || !objective.generate_objective(owner, potential_duplicate_objectives[duplicate_typepath]))
- qdel(objective)
- return
- if(!handle_duplicate(objective))
- qdel(objective)
- return
- objective.forced = force
- log_traitor("[key_name(owner)] has received a potential objective: [objective.to_debug_string()] | Forced: [force]")
- objective.original_progression = objective.progression_reward
- objective.update_progression_reward()
- potential_objectives += objective
- SStraitor.add_objective_to_list(objective, SStraitor.all_objectives_by_type)
- return objective
-
-/datum/uplink_handler/proc/handle_duplicate(datum/traitor_objective/potential_duplicate)
- if(!istype(potential_duplicate))
- return FALSE
-
- var/datum/traitor_objective/current_type = potential_duplicate.type
- var/list/added_types = list()
- while(current_type != /datum/traitor_objective)
- if(!potential_duplicate_objectives[current_type])
- potential_duplicate_objectives[current_type] = list(potential_duplicate)
- else
- potential_duplicate_objectives[current_type] += potential_duplicate
-
- added_types += current_type
- current_type = type2parent(current_type)
- return TRUE
-
-/datum/uplink_handler/proc/get_completion_count(datum/traitor_objective/type)
- var/amount_completed = 0
- for(var/datum/traitor_objective/objective as anything in potential_duplicate_objectives[type])
- if(objective.objective_state == OBJECTIVE_STATE_COMPLETED)
- amount_completed += 1
- return amount_completed
-
-/datum/uplink_handler/proc/get_completion_progression(datum/traitor_objective/type)
- var/total_progression = 0
- for(var/datum/traitor_objective/objective as anything in completed_objectives)
- if(objective.objective_state == OBJECTIVE_STATE_COMPLETED)
- total_progression += objective.progression_reward
- return total_progression
-
-/// Used to complete objectives, failed or successful.
-/datum/uplink_handler/proc/complete_objective(datum/traitor_objective/to_remove)
- if(to_remove in completed_objectives)
- return
-
- potential_objectives -= to_remove
- active_objectives -= to_remove
- completed_objectives += to_remove
- update_objectives()
- generate_objectives()
-
-/// Updates the objectives on the uplink and deletes
-/datum/uplink_handler/proc/update_objectives()
- var/list/objectives_copy = potential_objectives + active_objectives
- for(var/datum/traitor_objective/objective as anything in objectives_copy)
- if(progression_points > objective.progression_maximum && !objective.forced && objective.objective_state != OBJECTIVE_STATE_ACTIVE)
- objective.fail_objective(trigger_update = FALSE)
- continue
- objective.update_progression_reward()
-
-/datum/uplink_handler/proc/abort_objective(datum/traitor_objective/to_abort)
- if(istype(to_abort, /datum/traitor_objective/ultimate))
- return
- if(to_abort.objective_state != OBJECTIVE_STATE_ACTIVE)
- return
- to_abort.fail_objective(penalty_cost = to_abort.telecrystal_penalty)
-
-/datum/uplink_handler/proc/take_objective(mob/user, datum/traitor_objective/to_take)
- if(!(to_take in potential_objectives))
- return
-
- user.playsound_local(get_turf(user), 'sound/music/antag/traitor/objective_taken.ogg', vol = 100, vary = FALSE, channel = CHANNEL_TRAITOR)
- to_take.on_objective_taken(user)
- to_take.objective_state = OBJECTIVE_STATE_ACTIVE
- potential_objectives -= to_take
- active_objectives += to_take
- on_update()
-
-/datum/uplink_handler/proc/ui_objective_act(mob/user, datum/traitor_objective/to_act_on, action)
- if(!(to_act_on in active_objectives))
- return
- if(to_act_on.objective_state != OBJECTIVE_STATE_ACTIVE)
- return
-
- to_act_on.ui_perform_action(user, action)
-
///Helper to add telecrystals to the uplink handler, calling set_telecrystals.
/datum/uplink_handler/proc/add_telecrystals(amount)
set_telecrystals(telecrystals + amount)
diff --git a/code/modules/events/stray_cargo.dm b/code/modules/events/stray_cargo.dm
index 0514af5764e..6f752a48825 100644
--- a/code/modules/events/stray_cargo.dm
+++ b/code/modules/events/stray_cargo.dm
@@ -166,7 +166,6 @@
"Nuke Op" = UPLINK_NUKE_OPS,
"Clown Op" = UPLINK_CLOWN_OPS,
"Lone Op" = UPLINK_LONE_OP,
- "Infiltrator" = UPLINK_INFILTRATORS,
"Spy" = UPLINK_SPY
)
var/uplink_type = tgui_input_list(usr, "Choose uplink to draw items from.", "Choose uplink type.", possible_uplinks)
diff --git a/code/modules/mapfluff/ruins/spaceruin_code/garbagetruck.dm b/code/modules/mapfluff/ruins/spaceruin_code/garbagetruck.dm
new file mode 100644
index 00000000000..e48bcfd0ceb
--- /dev/null
+++ b/code/modules/mapfluff/ruins/spaceruin_code/garbagetruck.dm
@@ -0,0 +1,103 @@
+/obj/item/eyesnatcher
+ name = "portable eyeball extractor"
+ desc = "An overly complicated device that can pierce target's skull and extract their eyeballs if enough brute force is applied."
+ icon = 'icons/obj/medical/surgery_tools.dmi'
+ icon_state = "eyesnatcher"
+ base_icon_state = "eyesnatcher"
+ inhand_icon_state = "hypo"
+ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
+ throwforce = 0
+ w_class = WEIGHT_CLASS_SMALL
+ throw_speed = 3
+ throw_range = 5
+ ///Whether it's been used to steal a pair of eyes already.
+ var/used = FALSE
+
+/obj/item/eyesnatcher/update_icon_state()
+ . = ..()
+ icon_state = "[base_icon_state][used ? "-used" : ""]"
+
+/obj/item/eyesnatcher/attack(mob/living/carbon/human/target, mob/living/user, params)
+ if(used || !istype(target) || !target.Adjacent(user)) //Works only once, no TK use
+ return ..()
+
+ var/obj/item/organ/eyes/eyeballies = target.get_organ_slot(ORGAN_SLOT_EYES)
+ var/obj/item/bodypart/head/head = target.get_bodypart(BODY_ZONE_HEAD)
+
+ if(!head || !eyeballies || target.is_eyes_covered())
+ return ..()
+ var/eye_snatch_enthusiasm = 5 SECONDS
+ if(HAS_MIND_TRAIT(user, TRAIT_MORBID))
+ eye_snatch_enthusiasm *= 0.7
+ user.do_attack_animation(target, used_item = src)
+ target.visible_message(
+ span_warning("[user] presses [src] against [target]'s skull!"),
+ span_userdanger("[user] presses [src] against your skull!"))
+ if(!do_after(user, eye_snatch_enthusiasm, target = target, extra_checks = CALLBACK(src, PROC_REF(eyeballs_exist), eyeballies, head, target)))
+ return
+
+ to_chat(target, span_userdanger("You feel something forcing its way into your skull!"))
+ balloon_alert(user, "applying pressure...")
+ if(!do_after(user, eye_snatch_enthusiasm, target = target, extra_checks = CALLBACK(src, PROC_REF(eyeballs_exist), eyeballies, head, target)))
+ return
+
+ var/min_wound = head.get_wound_threshold_of_wound_type(WOUND_BLUNT, WOUND_SEVERITY_SEVERE, return_value_if_no_wound = 30, wound_source = src)
+ var/max_wound = head.get_wound_threshold_of_wound_type(WOUND_BLUNT, WOUND_SEVERITY_CRITICAL, return_value_if_no_wound = 50, wound_source = src)
+
+ target.apply_damage(20, BRUTE, BODY_ZONE_HEAD, wound_bonus = rand(min_wound, max_wound + 10), attacking_item = src)
+ target.visible_message(
+ span_danger("[src] pierces through [target]'s skull, horribly mutilating their eyes!"),
+ span_userdanger("Something penetrates your skull, horribly mutilating your eyes! Holy fuck!"),
+ span_hear("You hear a sickening sound of metal piercing flesh!")
+ )
+ eyeballies.apply_organ_damage(eyeballies.maxHealth)
+ target.emote("scream")
+ playsound(target, 'sound/effects/wounds/crackandbleed.ogg', 100)
+ log_combat(user, target, "cracked the skull of (eye snatching)", src)
+
+ if(!do_after(user, eye_snatch_enthusiasm, target = target, extra_checks = CALLBACK(src, PROC_REF(eyeballs_exist), eyeballies, head, target)))
+ return
+
+ if(!target.is_blind())
+ to_chat(target, span_userdanger("You suddenly go blind!"))
+ if(prob(1))
+ to_chat(target, span_notice("At least you got a new pirate-y look out of it..."))
+ var/obj/item/clothing/glasses/eyepatch/new_patch = new(target.loc)
+ target.equip_to_slot_if_possible(new_patch, ITEM_SLOT_EYES, disable_warning = TRUE)
+
+ to_chat(user, span_notice("You successfully extract [target]'s eyeballs."))
+ playsound(target, 'sound/items/handling/surgery/retractor2.ogg', 100, TRUE)
+ playsound(target, 'sound/effects/pop.ogg', 100, TRAIT_MUTE)
+ eyeballies.Remove(target)
+ eyeballies.forceMove(get_turf(target))
+ notify_ghosts(
+ "[target] has just had their eyes snatched!",
+ source = target,
+ header = "Ouch!",
+ )
+ target.emote("scream")
+ if(prob(20))
+ target.emote("cry")
+ used = TRUE
+ update_appearance(UPDATE_ICON)
+
+/obj/item/eyesnatcher/examine(mob/user)
+ . = ..()
+ if(used)
+ . += span_notice("It has been used up.")
+
+/obj/item/eyesnatcher/proc/eyeballs_exist(obj/item/organ/eyes/eyeballies, obj/item/bodypart/head/head, mob/living/carbon/human/target)
+ if(!eyeballies || QDELETED(eyeballies))
+ return FALSE
+ if(!head || QDELETED(head))
+ return FALSE
+
+ if(eyeballies.owner != target)
+ return FALSE
+ var/obj/item/organ/eyes/eyes = target.get_organ_slot(ORGAN_SLOT_EYES)
+ //got different eyes or doesn't own the head... somehow
+ if(head.owner != target || eyes != eyeballies)
+ return FALSE
+
+ return TRUE
diff --git a/code/modules/modular_computers/computers/item/disks/virus_disk.dm b/code/modules/modular_computers/computers/item/disks/virus_disk.dm
index 3f646b22d8a..28ceb2da54a 100644
--- a/code/modules/modular_computers/computers/item/disks/virus_disk.dm
+++ b/code/modules/modular_computers/computers/item/disks/virus_disk.dm
@@ -147,11 +147,8 @@
target_mind = pick(backup_players)
hidden_uplink = target.AddComponent(/datum/component/uplink, target_mind, enabled = TRUE, starting_tc = telecrystals, has_progression = TRUE)
hidden_uplink.unlock_code = unlock_code
- hidden_uplink.uplink_handler.has_objectives = TRUE
hidden_uplink.uplink_handler.owner = target_mind
- hidden_uplink.uplink_handler.can_take_objectives = FALSE
hidden_uplink.uplink_handler.progression_points = min(SStraitor.current_global_progression, current_progression)
- hidden_uplink.uplink_handler.generate_objectives()
SStraitor.register_uplink_handler(hidden_uplink.uplink_handler)
else
hidden_uplink.uplink_handler.add_telecrystals(telecrystals)
diff --git a/code/modules/paperwork/paper_cutter.dm b/code/modules/paperwork/paper_cutter.dm
index 10aad59001a..f155123c13f 100644
--- a/code/modules/paperwork/paper_cutter.dm
+++ b/code/modules/paperwork/paper_cutter.dm
@@ -113,9 +113,12 @@
/obj/item/papercutter/attackby(obj/item/inserted_item, mob/user, params)
if(istype(inserted_item, /obj/item/paper))
if(is_type_in_list(inserted_item, list(
- /obj/item/paper/paperslip, /obj/item/paper/report, /obj/item/paper/fake_report,
- /obj/item/paper/calling_card, /obj/item/paper/pamphlet, /obj/item/paper/holy_writ)
- ))
+ /obj/item/paper/fake_report,
+ /obj/item/paper/holy_writ,
+ /obj/item/paper/pamphlet,
+ /obj/item/paper/paperslip,
+ /obj/item/paper/report,
+ )))
balloon_alert(user, "won't fit!")
return
if(stored_paper)
diff --git a/code/modules/station_goals/meteor_shield.dm b/code/modules/station_goals/meteor_shield.dm
index e4b76f600ca..8d5e2dbf409 100644
--- a/code/modules/station_goals/meteor_shield.dm
+++ b/code/modules/station_goals/meteor_shield.dm
@@ -145,8 +145,6 @@
to_chat(user, span_warning("The last satellite emagged needs [DisplayTimeText(COOLDOWN_TIMELEFT(src, shared_emag_cooldown))] to recalibrate first. Emagging another so soon could damage the satellite network."))
return FALSE
var/cooldown_applied = METEOR_SHIELD_EMAG_COOLDOWN
- if(istype(emag_card, /obj/item/card/emag/meteor_shield_recalibrator))
- cooldown_applied /= 3
COOLDOWN_START(src, shared_emag_cooldown, cooldown_applied)
obj_flags |= EMAGGED
to_chat(user, span_notice("You access the satellite's debug mode and it begins emitting a strange signal, increasing the chance of meteor strikes."))
diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm
index 9447368ddae..cf6003f3ca0 100644
--- a/code/modules/unit_tests/_unit_tests.dm
+++ b/code/modules/unit_tests/_unit_tests.dm
@@ -225,7 +225,6 @@
#include "mutant_organs.dm"
#include "novaflower_burn.dm"
#include "nuke_cinematic.dm"
-#include "objectives.dm"
#include "omnitools.dm"
#include "operating_table.dm"
#include "orderable_items.dm"
diff --git a/code/modules/unit_tests/objectives.dm b/code/modules/unit_tests/objectives.dm
deleted file mode 100644
index 30263c0f078..00000000000
--- a/code/modules/unit_tests/objectives.dm
+++ /dev/null
@@ -1,49 +0,0 @@
-/datum/unit_test/objectives_category/Run()
- var/datum/traitor_category_handler/category_handler = allocate(/datum/traitor_category_handler)
- var/list/objectives_that_exist = list()
- for(var/datum/traitor_objective_category/category as anything in category_handler.all_categories)
- for(var/value in category.objectives)
- TEST_ASSERT(isnum(category.objectives[value]), "[category.type] does not have a valid format for its objectives as an objective category! ([value] requires a weight to be assigned to it)")
- if(islist(value))
- recursive_check_list(category.type, value, objectives_that_exist)
- else
- objectives_that_exist += value
-
- SStraitor.generate_objectives = FALSE
- for(var/datum/traitor_objective/objective_typepath as anything in subtypesof(/datum/traitor_objective))
- var/datum/traitor_objective/objective = allocate(objective_typepath)
- if(objective.abstract_type == objective_typepath)
- // In this case, we don't want abstract types to define values that should be defined on non-abstract types
- // Nor do we want abstract types to appear in the pool of traitor objectives.
- if(objective_typepath in objectives_that_exist)
- TEST_FAIL("[objective_typepath] is in a traitor category and is an abstract type! Please remove it from the [/datum/traitor_objective_category].")
- // Since we didn't generate the objective, the rewards are going to be in list form: (min, max)
- if(!reward_is_zero(objective.progression_reward))
- TEST_FAIL("[objective_typepath] has set a progression reward as an abstract type! Please define progression rewards on non-abstract types rather than abstract types.")
- // Since we didn't generate the objective, the rewards are going to be in list form: (min, max)
- if(!reward_is_zero(objective.telecrystal_reward))
- TEST_FAIL("[objective_typepath] has set a telecrystal reward as an abstract type! Please define telecrystal rewards on non-abstract types rather than abstract types.")
- continue
- if(!(objective_typepath in objectives_that_exist))
- TEST_FAIL("[objective_typepath] is not in a traitor category and isn't an abstract type! Place it into a [/datum/traitor_objective_category] or remove it from code.")
- if(objective.progression_minimum == null)
- TEST_FAIL("[objective_typepath] has not defined a minimum progression level and isn't an abstract type! Please define the progression minimum variable on the datum")
- if(objective.needs_reward && reward_is_zero(objective.progression_reward) && reward_is_zero(objective.telecrystal_reward))
- TEST_FAIL("[objective_typepath] has not set either a progression reward or a telecrystal reward! Please set either a telecrystal or progression reward for this objective.")
-
-/// Returns whether the reward specified (in format (min, max)) is zero or not.
-/datum/unit_test/objectives_category/proc/reward_is_zero(list/reward)
- return (reward[1] == 0 && reward[2] == 0)
-
-/datum/unit_test/objectives_category/Destroy()
- SStraitor.generate_objectives = TRUE
- return ..()
-
-
-/datum/unit_test/objectives_category/proc/recursive_check_list(base_type, list/to_check, list/to_add_to)
- for(var/value in to_check)
- TEST_ASSERT(isnum(to_check[value]), "[base_type] does not have a valid format for its objectives as an objective category! ([value] requires a weight to be assigned to it)")
- if(islist(value))
- recursive_check_list(base_type, value, to_add_to)
- else
- to_add_to += value
diff --git a/code/modules/unit_tests/traitor.dm b/code/modules/unit_tests/traitor.dm
index 974888b3a0d..6b95d501804 100644
--- a/code/modules/unit_tests/traitor.dm
+++ b/code/modules/unit_tests/traitor.dm
@@ -22,11 +22,3 @@
var/datum/antagonist/traitor/traitor = mind.add_antag_datum(/datum/antagonist/traitor)
if(!traitor.uplink_handler)
TEST_FAIL("[job_name] when made traitor does not have a proper uplink created when spawned in!")
- for(var/datum/traitor_objective/objective_typepath as anything in subtypesof(/datum/traitor_objective))
- if(initial(objective_typepath.abstract_type) == objective_typepath)
- continue
- var/datum/traitor_objective/objective = allocate(objective_typepath, traitor.uplink_handler)
- try
- objective.generate_objective(mind, list())
- catch(var/exception/exception)
- TEST_FAIL("[objective_typepath] failed to generate their objective. Reason: [exception.name] [exception.file]:[exception.line]\n[exception.desc]")
diff --git a/code/modules/uplink/uplink_devices.dm b/code/modules/uplink/uplink_devices.dm
index 01246168798..01fbc133920 100644
--- a/code/modules/uplink/uplink_devices.dm
+++ b/code/modules/uplink/uplink_devices.dm
@@ -84,34 +84,6 @@
var/datum/component/uplink/hidden_uplink = GetComponent(/datum/component/uplink)
hidden_uplink.name = "dusty radio"
-// Uplink subtype used as replacement uplink
-/obj/item/uplink/replacement
- lockable_uplink = TRUE
-
-/obj/item/uplink/replacement/Initialize(mapload, owner, tc_amount = 10, datum/uplink_handler/uplink_handler_override = null)
- . = ..()
- var/datum/component/uplink/hidden_uplink = GetComponent(/datum/component/uplink)
- var/mob/living/replacement_needer = owner
- if(!istype(replacement_needer))
- return
- var/datum/antagonist/traitor/traitor_datum = replacement_needer?.mind.has_antag_datum(/datum/antagonist/traitor)
- hidden_uplink.unlock_code = traitor_datum?.replacement_uplink_code
- become_hearing_sensitive()
-
-/obj/item/uplink/replacement/screwdriver_act_secondary(mob/living/user, obj/item/tool)
- tool.play_tool_sound(src)
- balloon_alert(user, "deconstructing...")
- if (!do_after(user, 3 SECONDS, target = src))
- return FALSE
- qdel(src)
- return TRUE
-
-/obj/item/uplink/replacement/examine(mob/user)
- . = ..()
- if(!IS_TRAITOR(user))
- return
- . += span_notice("You can destroy this device with a screwdriver.")
-
// Multitool uplink
////obj/item/multitool/uplink/Initialize(mapload, owner, tc_amount = 20, datum/uplink_handler/uplink_handler_override = null) //ORIGINAL
/obj/item/multitool/uplink/Initialize(mapload, owner, tc_amount = 35, datum/uplink_handler/uplink_handler_override = null) //SKYRAT EDIT CHANGE. Original tc_amount = 20
diff --git a/code/modules/uplink/uplink_items/contractor.dm b/code/modules/uplink/uplink_items/contractor.dm
index 9283addc181..a970c42d6ac 100644
--- a/code/modules/uplink/uplink_items/contractor.dm
+++ b/code/modules/uplink/uplink_items/contractor.dm
@@ -13,7 +13,7 @@
item = /obj/item/storage/box/syndicate/contract_kit
category = /datum/uplink_category/contractor
cost = 20
- purchasable_from = UPLINK_INFILTRATORS
+ purchasable_from = UPLINK_TRAITORS
/datum/uplink_item/bundles_tc/contract_kit/purchase(mob/user, datum/uplink_handler/uplink_handler, atom/movable/source)
. = ..()
diff --git a/code/modules/uplink/uplink_items/nukeops.dm b/code/modules/uplink/uplink_items/nukeops.dm
index 17de7c15c4d..c7f0bc82a72 100644
--- a/code/modules/uplink/uplink_items/nukeops.dm
+++ b/code/modules/uplink/uplink_items/nukeops.dm
@@ -604,7 +604,8 @@
along with slurred speech, aggression, and the ability to infect others with this agent."
item = /obj/item/storage/box/syndie_kit/romerol
cost = 25
- purchasable_from = UPLINK_ALL_SYNDIE_OPS
+ progression_minimum = 30 MINUTES
+ purchasable_from = UPLINK_ALL_SYNDIE_OPS | UPLINK_TRAITORS // Don't give this to spies
cant_discount = TRUE
// Modsuits
diff --git a/tgstation.dme b/tgstation.dme
index 61b0d0442ff..6bfaa17c29d 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -2923,7 +2923,6 @@
#include "code\game\objects\structures\spawner.dm"
#include "code\game\objects\structures\spirit_board.dm"
#include "code\game\objects\structures\stairs.dm"
-#include "code\game\objects\structures\syndicate_uplink_beacon.dm"
#include "code\game\objects\structures\table_frames.dm"
#include "code\game\objects\structures\tables_racks.dm"
#include "code\game\objects\structures\tank_dispenser.dm"
@@ -3494,40 +3493,13 @@
#include "code\modules\antagonists\spy\spy_uplink.dm"
#include "code\modules\antagonists\survivalist\survivalist.dm"
#include "code\modules\antagonists\syndicate_monkey\syndicate_monkey.dm"
-#include "code\modules\antagonists\traitor\balance_helper.dm"
#include "code\modules\antagonists\traitor\datum_traitor.dm"
-#include "code\modules\antagonists\traitor\objective_category.dm"
-#include "code\modules\antagonists\traitor\traitor_objective.dm"
#include "code\modules\antagonists\traitor\uplink_handler.dm"
#include "code\modules\antagonists\traitor\components\demoraliser.dm"
-#include "code\modules\antagonists\traitor\components\traitor_objective_helpers.dm"
-#include "code\modules\antagonists\traitor\components\traitor_objective_limit_per_time.dm"
-#include "code\modules\antagonists\traitor\components\traitor_objective_mind_tracker.dm"
#include "code\modules\antagonists\traitor\contractor\contract_teammate.dm"
#include "code\modules\antagonists\traitor\contractor\contractor_hub.dm"
#include "code\modules\antagonists\traitor\contractor\contractor_items.dm"
#include "code\modules\antagonists\traitor\contractor\syndicate_contract.dm"
-#include "code\modules\antagonists\traitor\objectives\assassination.dm"
-#include "code\modules\antagonists\traitor\objectives\demoralise_assault.dm"
-#include "code\modules\antagonists\traitor\objectives\destroy_heirloom.dm"
-#include "code\modules\antagonists\traitor\objectives\destroy_item.dm"
-#include "code\modules\antagonists\traitor\objectives\eyesnatching.dm"
-#include "code\modules\antagonists\traitor\objectives\hack_comm_console.dm"
-#include "code\modules\antagonists\traitor\objectives\infect.dm"
-#include "code\modules\antagonists\traitor\objectives\kidnapping.dm"
-#include "code\modules\antagonists\traitor\objectives\kill_pet.dm"
-#include "code\modules\antagonists\traitor\objectives\locate_weakpoint.dm"
-#include "code\modules\antagonists\traitor\objectives\sabotage_machinery.dm"
-#include "code\modules\antagonists\traitor\objectives\steal.dm"
-#include "code\modules\antagonists\traitor\objectives\abstract\target_player.dm"
-#include "code\modules\antagonists\traitor\objectives\final_objective\battle_royale.dm"
-#include "code\modules\antagonists\traitor\objectives\final_objective\battlecruiser.dm"
-#include "code\modules\antagonists\traitor\objectives\final_objective\final_objective.dm"
-#include "code\modules\antagonists\traitor\objectives\final_objective\infect_ai.dm"
-#include "code\modules\antagonists\traitor\objectives\final_objective\no_escape.dm"
-#include "code\modules\antagonists\traitor\objectives\final_objective\objective_dark_matteor.dm"
-#include "code\modules\antagonists\traitor\objectives\final_objective\romerol.dm"
-#include "code\modules\antagonists\traitor\objectives\final_objective\supermatter_cascade.dm"
#include "code\modules\antagonists\valentines\heartbreaker.dm"
#include "code\modules\antagonists\valentines\valentine.dm"
#include "code\modules\antagonists\venus_human_trap\venus_human_trap.dm"
@@ -4854,6 +4826,7 @@
#include "code\modules\mapfluff\ruins\spaceruin_code\derelict_sulaco.dm"
#include "code\modules\mapfluff\ruins\spaceruin_code\DJstation.dm"
#include "code\modules\mapfluff\ruins\spaceruin_code\forgottenship.dm"
+#include "code\modules\mapfluff\ruins\spaceruin_code\garbagetruck.dm"
#include "code\modules\mapfluff\ruins\spaceruin_code\hauntedtradingpost.dm"
#include "code\modules\mapfluff\ruins\spaceruin_code\hellfactory.dm"
#include "code\modules\mapfluff\ruins\spaceruin_code\hilbertshotel.dm"
diff --git a/tgui/packages/tgui/interfaces/AntagInfoTraitor.tsx b/tgui/packages/tgui/interfaces/AntagInfoTraitor.tsx
index 520538afea8..4026e0cd9a9 100644
--- a/tgui/packages/tgui/interfaces/AntagInfoTraitor.tsx
+++ b/tgui/packages/tgui/interfaces/AntagInfoTraitor.tsx
@@ -1,10 +1,4 @@
-import {
- BlockQuote,
- Button,
- Dimmer,
- Section,
- Stack,
-} from 'tgui-core/components';
+import { BlockQuote, Button, Section, Stack } from 'tgui-core/components';
import { BooleanLike } from 'tgui-core/react';
import { useBackend } from '../backend';
@@ -37,8 +31,6 @@ type Info = {
intro: string;
code: string;
failsafe_code: string;
- replacement_code: string;
- replacement_frequency: string;
has_uplink: BooleanLike;
uplink_intro: string;
uplink_unlock_info: string;
@@ -117,37 +109,12 @@ const EmployerSection = (props) => {
const UplinkSection = (props) => {
const { data } = useBackend();
- const {
- has_uplink,
- uplink_intro,
- uplink_unlock_info,
- code,
- failsafe_code,
- replacement_code,
- replacement_frequency,
- } = data;
+ const { has_uplink, uplink_intro, uplink_unlock_info, code, failsafe_code } =
+ data;
return (
- {(!has_uplink && (
-
-
-
- Your uplink is missing or destroyed.
- Craft a Syndicate Uplink Beacon and then speak
-
-
- {replacement_code}
- {' '}
- on frequency{' '}
-
- {replacement_frequency}
- {' '}
- after synchronizing with the beacon.
-
-
-
- )) || (
+ {
<>
{uplink_intro}
@@ -163,29 +130,16 @@ const UplinkSection = (props) => {
{uplink_unlock_info}
>
- )}
+ }
- {(has_uplink && (
-
- If you lose your uplink, you can craft a Syndicate Uplink Beacon and
- then speak{' '}
-
- {replacement_code}
- {' '}
- on radio frequency{' '}
-
- {replacement_frequency}
- {' '}
- after synchronizing with the beacon.
-
- )) || (
+ {
{' '}