[MIRROR] 3(or 4) new traitor objectives [MDB IGNORE] (#13972)

* 3(or 4) new traitor objectives (#67287)

This PR introduces 3 new kind of traitor objectives:
Eyesnatcher objective, you'll need to remove your victim's eyes by any means. You will be given a device that you can use to pull out someone's eyes after 3 5 second delays. This would be quite loud and painful to the victim, so make sure you got them restrained or knocked out.

"Public" Sleeper protocol - this is a high progression(30+ minutes) objective. It's basically Sleeper Protocol, but availible for everyone instead of only med personnel.

Locate Structural Weakpoint - a high progression(45+ minutes) objectives that can be only completed once. You will recieve a device that you'll need to use in 2 different (somewhat secure) areas in order to triangulate the structural weakpoint of the station, you'll need to stay in the area for 30 seconds and station AI will be alerted about your attempt. After triangulating it, you will be given a location-locked explosive which will also create from 5 to 8 minor explosions in a 17-25 tile area.

Kidnap personnel - Basically old contractor kidnap. Down someone, get them to the extraction location, call in a pod, stuff them into it and send it back. Additional TCs if you bring them alive.

* 3(or 4) new traitor objectives

Co-authored-by: SmArtKar <44720187+SmArtKar@users.noreply.github.com>
This commit is contained in:
SkyratBot
2022-05-28 13:53:37 +01:00
committed by GitHub
co-authored by SmArtKar
parent 29a9e3f499
commit 82d1654df2
15 changed files with 870 additions and 45 deletions
+42 -42
View File
@@ -167,7 +167,7 @@
/obj/machinery/door/airlock/wood{
name = "Kitchen"
},
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"aG" = (
/obj/structure/railing/corner,
@@ -584,7 +584,7 @@
/obj/item/kirbyplants{
icon_state = "plant-10"
},
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"bO" = (
/obj/effect/landmark/holding_facility,
@@ -1103,7 +1103,7 @@
/obj/structure/mineral_door/paperframe{
name = "Dining Hall"
},
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"dk" = (
/obj/effect/turf_decal/siding/wood{
@@ -1115,7 +1115,7 @@
/obj/structure/mineral_door/paperframe{
name = "Botanical Garden"
},
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"dl" = (
/obj/effect/turf_decal/siding/wood,
@@ -1125,7 +1125,7 @@
/obj/structure/mineral_door/paperframe{
name = "Guest Suite *B"
},
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"dm" = (
/obj/machinery/seed_extractor,
@@ -1162,7 +1162,7 @@
/area/centcom/central_command_areas/holding)
"dt" = (
/obj/structure/closet/crate/freezer/blood,
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"du" = (
/obj/effect/turf_decal/tile/bar,
@@ -1456,7 +1456,7 @@
/obj/structure/mineral_door/paperframe{
name = "Guest Suite *A"
},
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"el" = (
/obj/structure/filingcabinet/medical,
@@ -1711,7 +1711,7 @@
/obj/machinery/door/airlock/wood{
name = "Washroom"
},
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"eU" = (
/obj/machinery/hydroponics/constructable,
@@ -2121,7 +2121,7 @@
"ge" = (
/obj/machinery/defibrillator_mount/directional/south,
/obj/machinery/stasis,
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"gf" = (
/obj/structure/flora/tree/pine/style_random,
@@ -2403,7 +2403,7 @@
name = "Momo";
radio_key = null
},
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"gX" = (
/obj/structure/table/reinforced,
@@ -2418,7 +2418,7 @@
/turf/open/floor/grass,
/area/centcom/central_command_areas/holding)
"hb" = (
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"hc" = (
/obj/structure/table/reinforced,
@@ -2617,7 +2617,7 @@
/obj/structure/mineral_door/paperframe{
name = "East Wing"
},
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"hz" = (
/obj/effect/turf_decal/tile/neutral/fourcorners,
@@ -2720,7 +2720,7 @@
},
/obj/machinery/washing_machine,
/obj/machinery/light/directional/east,
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"hL" = (
/obj/effect/turf_decal/tile/yellow/half,
@@ -6305,7 +6305,7 @@
dir = 1
},
/obj/effect/turf_decal/siding/wood,
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"sq" = (
/obj/machinery/computer/shuttle/white_ship{
@@ -6398,7 +6398,7 @@
"sF" = (
/obj/effect/turf_decal/tile/dark/fourcorners,
/obj/effect/turf_decal/siding/wood,
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"sG" = (
/obj/docking_port/stationary{
@@ -6942,7 +6942,7 @@
pixel_y = 3
},
/obj/item/clothing/suit/hawaiian,
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"ur" = (
/obj/machinery/pdapainter,
@@ -9104,7 +9104,7 @@
/obj/effect/turf_decal/siding/wood{
dir = 8
},
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"AH" = (
/turf/open/floor/iron,
@@ -10054,7 +10054,7 @@
name = "Bar"
},
/obj/machinery/duct,
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"Do" = (
/obj/structure/railing/corner{
@@ -10129,7 +10129,7 @@
/obj/structure/mineral_door/paperframe{
name = "Dojo"
},
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"Dx" = (
/obj/structure/chair/bronze{
@@ -10990,7 +10990,7 @@
/obj/structure/mineral_door/paperframe{
name = "Blue"
},
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"FV" = (
/obj/structure/chair/pew/left{
@@ -13115,7 +13115,7 @@
/obj/structure/mineral_door/paperframe{
name = "Performance Room"
},
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"MI" = (
/obj/machinery/light/directional/north,
@@ -13740,7 +13740,7 @@
/obj/structure/mineral_door/paperframe{
name = "Shrine"
},
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"Ov" = (
/obj/structure/table/reinforced/rglass,
@@ -14018,7 +14018,7 @@
/obj/structure/sign/painting/library{
pixel_y = 32
},
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"Pg" = (
/obj/machinery/computer/auxiliary_base/directional/north,
@@ -14431,7 +14431,7 @@
/obj/structure/mineral_door/paperframe{
name = "Electrical Room"
},
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"Qn" = (
/obj/effect/turf_decal/siding/purple{
@@ -14476,7 +14476,7 @@
/obj/effect/turf_decal/siding/wood{
dir = 1
},
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"Qv" = (
/obj/effect/turf_decal/tile/red{
@@ -14608,7 +14608,7 @@
/obj/machinery/door/airlock/wood{
name = "Toilet"
},
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"QR" = (
/obj/structure/chair/office/light{
@@ -14787,7 +14787,7 @@
"Rk" = (
/obj/machinery/defibrillator_mount/directional/north,
/obj/machinery/stasis,
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"Rl" = (
/obj/structure/chair/comfy/brown{
@@ -14803,7 +14803,7 @@
/obj/structure/table/reinforced/plastitaniumglass,
/obj/item/storage/basket,
/obj/machinery/light/directional/west,
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"Rn" = (
/obj/structure/chair/sofa/bench/right{
@@ -14923,7 +14923,7 @@
/obj/structure/sign/painting/library{
pixel_y = 32
},
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"RE" = (
/obj/effect/turf_decal/siding/wood,
@@ -14933,7 +14933,7 @@
/obj/structure/mineral_door/paperframe{
name = "Guest Suite *D"
},
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"RF" = (
/obj/structure/table/reinforced,
@@ -15051,7 +15051,7 @@
/obj/structure/mineral_door/paperframe{
name = "Red"
},
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"RZ" = (
/obj/effect/turf_decal/trimline/red,
@@ -15064,7 +15064,7 @@
name = "Hattori";
radio_key = null
},
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"Sb" = (
/obj/structure/table/wood,
@@ -15237,7 +15237,7 @@
/area/centcom/central_command_areas/holding)
"SF" = (
/obj/effect/turf_decal/siding/wood,
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"SG" = (
/obj/machinery/light/directional/south,
@@ -15306,7 +15306,7 @@
/obj/structure/mineral_door/paperframe{
name = "Guest Suite *C"
},
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"SQ" = (
/obj/structure/filingcabinet/medical,
@@ -15932,7 +15932,7 @@
/obj/structure/mineral_door/paperframe{
name = "Spectator's Lounge"
},
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"Uq" = (
/obj/structure/flora/grass/both/style_random,
@@ -16285,7 +16285,7 @@
icon_state = "plant-10"
},
/obj/machinery/light/small/directional/south,
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"Vk" = (
/obj/effect/turf_decal/tile/brown,
@@ -16415,7 +16415,7 @@
/obj/effect/turf_decal/siding/wood{
dir = 1
},
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"VH" = (
/obj/effect/turf_decal/tile/bar,
@@ -16497,7 +16497,7 @@
dir = 1
},
/obj/effect/turf_decal/siding/wood,
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"VT" = (
/obj/structure/rack,
@@ -16786,7 +16786,7 @@
/obj/effect/turf_decal/tile/dark/fourcorners,
/obj/effect/turf_decal/siding/wood,
/obj/machinery/washing_machine,
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"WA" = (
/obj/item/kirbyplants{
@@ -17186,7 +17186,7 @@
/area/centcom/tdome/administration)
"Xx" = (
/obj/machinery/vending/dinnerware,
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"Xy" = (
/obj/machinery/door/airlock/external/ruin{
@@ -17292,7 +17292,7 @@
/obj/item/organ/heart/cybernetic/tier2,
/obj/item/organ/heart/cybernetic/tier2,
/obj/item/defibrillator,
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"XJ" = (
/obj/structure/flora/bush/lavendergrass/style_random,
@@ -17935,7 +17935,7 @@
/obj/structure/window/paperframe{
can_atmos_pass = 0
},
/turf/open/floor/sepia,
/turf/open/floor/iron/sepia,
/area/centcom/central_command_areas/holding)
"ZC" = (
/obj/effect/turf_decal/stripes/line{
+7
View File
@@ -249,3 +249,10 @@ GLOBAL_LIST_INIT(ai_employers, list(
#define OBJECTIVE_STATE_FAILED 4
/// If the objective is no longer valid
#define OBJECTIVE_STATE_INVALID 5
/// Weights for traitor objective categories
#define OBJECTIVE_WEIGHT_TINY 5
#define OBJECTIVE_WEIGHT_SMALL 7
#define OBJECTIVE_WEIGHT_DEFAULT 10
#define OBJECTIVE_WEIGHT_BIG 15
#define OBJECTIVE_WEIGHT_HUGE 20
+2
View File
@@ -535,6 +535,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_ALLOW_HERETIC_CASTING "allow_heretic_casting"
/// Designates a heart as a living heart for a heretic.
#define TRAIT_LIVING_HEART "living_heart"
/// Prevents the same person from being chosen multiple times for kidnapping objective
#define TRAIT_HAS_BEEN_KIDNAPPED "has_been_kidnapped"
//quirk traits
#define TRAIT_ALCOHOL_TOLERANCE "alcohol_tolerance"
+27
View File
@@ -37,6 +37,8 @@ SUBSYSTEM_DEF(traitor)
var/generate_objectives = TRUE
/// Objectives that have been completed by type. Used for limiting objectives.
var/list/taken_objectives_by_type = list()
/// Contains 3 areas: 2 areas to scan in order to triangulate the third one which is the structural weakpoint itself
var/list/station_weakpoints = list()
/datum/controller/subsystem/traitor/Initialize(start_timeofday)
. = ..()
@@ -51,6 +53,31 @@ SUBSYSTEM_DEF(traitor)
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]
/// List of high-security areas that we pick required ones from
var/list/allowed_areas = typecacheof(list(/area/station/command,
/area/station/cargo/qm,
/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/test_area,
/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 3)
station_weakpoints += pick_n_take(possible_areas)
/datum/controller/subsystem/traitor/fire(resumed)
var/player_count = length(GLOB.alive_player_list)
// Has a maximum of 1 minute, however the value can be lower if there are lower players than the ideal
@@ -65,4 +65,4 @@
/// 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 = 1
var/weight = OBJECTIVE_WEIGHT_DEFAULT
@@ -0,0 +1,219 @@
/datum/traitor_objective_category/eyesnatching
name = "Eyesnatching"
objectives = list(
/datum/traitor_objective/eyesnatching = 1,
/datum/traitor_objective/eyesnatching/heads = 1,
)
weight = OBJECTIVE_WEIGHT_TINY
/datum/traitor_objective/eyesnatching
name = "Steal %TARGET%'s (%JOB TITLE%) eyes"
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_reward = list(4 MINUTES, 8 MINUTES)
telecrystal_reward = list(1, 2)
// 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 = 3
/// Who we're stealing eyes from
var/mob/living/victim
/// If we're targeting heads of staff or not
var/heads_of_staff = FALSE
/// Have we already spawned an eyesnatcher
var/spawned_eyesnatcher = FALSE
/datum/traitor_objective/eyesnatching/supported_configuration_changes()
. = ..()
. += NAMEOF(src, objective_period)
. += NAMEOF(src, maximum_objectives_in_period)
/datum/traitor_objective/eyesnatching/New(datum/uplink_handler/handler)
. = ..()
AddComponent(/datum/component/traitor_objective_limit_per_time, \
/datum/traitor_objective/eyesnatching, \
time_period = objective_period, \
maximum_objectives = maximum_objectives_in_period \
)
/datum/traitor_objective/eyesnatching/heads
progression_reward = list(6 MINUTES, 12 MINUTES)
telecrystal_reward = list(2, 3)
heads_of_staff = TRUE
/datum/traitor_objective/eyesnatching/generate_objective(datum/mind/generating_for, list/possible_duplicates)
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(!ishuman(possible_target.current))
continue
if(possible_target.current.stat == DEAD)
continue
if(possible_target.has_antag_datum(/datum/antagonist/traitor))
continue
if(heads_of_staff)
if(!(possible_target.assigned_role.departments_bitflags & DEPARTMENT_BITFLAG_COMMAND))
continue
else
if(possible_target.assigned_role.departments_bitflags & DEPARTMENT_BITFLAG_COMMAND)
continue
var/mob/living/carbon/human/targets_current = possible_target.current
if(!targets_current.getorgan(/obj/item/organ/eyes))
continue
possible_targets += targets_current
for(var/datum/traitor_objective/eyesnatching/objective as anything in possible_duplicates)
possible_targets -= objective.victim
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
victim = pick(possible_targets)
var/datum/mind/victim_mind = victim.mind
replace_in_name("%TARGET%", victim_mind.name)
replace_in_name("%JOB TITLE%", victim_mind.assigned_role.title)
RegisterSignal(victim, COMSIG_CARBON_LOSE_ORGAN, .proc/check_eye_removal)
AddComponent(/datum/component/traitor_objective_register, victim, fail_signals = COMSIG_PARENT_QDELETING)
/datum/traitor_objective/eyesnatching/proc/check_eye_removal(datum/source, obj/item/organ/eyes/removed)
SIGNAL_HANDLER
if(!istype(removed))
return
succeed_objective()
/datum/traitor_objective/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/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 eyesnatcher 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/surgery.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
var/used = FALSE
/obj/item/eyesnatcher/update_icon_state()
. = ..()
icon_state = "[base_icon_state][used ? "-used" : ""]"
/obj/item/eyesnatcher/attack(mob/living/carbon/human/victim, mob/living/user, params)
if(!istype(victim) || !victim.Adjacent(user)) //No TK use
return ..()
var/obj/item/organ/eyes/eyeballies = victim.getorganslot(ORGAN_SLOT_EYES)
var/obj/item/bodypart/head/head = victim.get_bodypart(BODY_ZONE_HEAD)
if(!eyeballies || victim.is_eyes_covered())
return ..()
if((head && head.eyes != eyeballies) || eyeballies.zone != BODY_ZONE_HEAD)
to_chat(user, span_warning("You don't know how to apply [src] to the abomination that [victim] is!"))
return ..()
if(!head || !istype(head))
return ..()
user.do_attack_animation(victim, used_item = src)
victim.visible_message(span_warning("[user] presses [src] against [victim]'s skull!"), span_userdanger("[user] presses [src] against your skull!"))
if(!do_after(user, 5 SECONDS, target = victim, extra_checks = CALLBACK(src, .proc/eyeballs_exist, eyeballies, head, victim)))
return
to_chat(victim, span_userdanger("You feel [src] pushing at your skull!"))
to_chat(user, span_notice("You apply more pressure to [src]."))
if(!do_after(user, 5 SECONDS, target = victim, extra_checks = CALLBACK(src, .proc/eyeballs_exist, eyeballies, head, victim)))
return
var/datum/wound/blunt/severe/severe_wound_type = /datum/wound/blunt/severe
var/datum/wound/blunt/critical/critical_wound_type = /datum/wound/blunt/critical
victim.apply_damage(20, BRUTE, BODY_ZONE_HEAD, wound_bonus = rand(initial(severe_wound_type.threshold_minimum), initial(critical_wound_type.threshold_minimum) + 10))
victim.visible_message(
span_danger("[src] pierces through [victim]'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.applyOrganDamage(eyeballies.maxHealth)
victim.emote("scream")
playsound(victim, "sound/effects/wounds/crackandbleed.ogg", 100)
log_combat(user, victim, "pierced skull of", src)
if(!do_after(user, 5 SECONDS, target = victim, extra_checks = CALLBACK(src, .proc/eyeballs_exist, eyeballies, head, victim)))
return
if(!HAS_TRAIT(victim, TRAIT_BLIND))
to_chat(victim, span_userdanger("You suddenly go blind!"))
to_chat(user, span_notice("You successfully extract [victim]'s eyeballs using [src]."))
victim.emote("scream")
playsound(victim, 'sound/surgery/retractor2.ogg', 100, TRUE)
playsound(victim, 'sound/effects/pop.ogg', 100, TRAIT_MUTE)
eyeballies.Remove(victim)
eyeballies.forceMove(get_turf(victim))
used = TRUE
desc += " It has been used up."
update_icon()
/obj/item/eyesnatcher/proc/eyeballs_exist(obj/item/organ/eyes/eyeballies, obj/item/bodypart/head, mob/living/carbon/human/victim)
if(!eyeballies || QDELETED(eyeballies))
return FALSE
if(!head || QDELETED(head))
return FALSE
if(!victim || QDELETED(victim))
return FALSE
if(eyeballies.owner != victim)
return FALSE
if(head.owner != victim || head.eyes != eyes)
return FALSE
return TRUE
@@ -0,0 +1,293 @@
/datum/traitor_objective_category/kidnapping
name = "Kidnap Personnel"
objectives = list( //Similar weights to destroy heirloom objectives
list(
/datum/traitor_objective/kidnapping/common = 20,
/datum/traitor_objective/kidnapping/less_common = 1,
) = 4,
/datum/traitor_objective/kidnapping/uncommon = 3,
/datum/traitor_objective/kidnapping/rare = 2,
/datum/traitor_objective/kidnapping/captain = 1
)
/datum/traitor_objective/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. \
You'll get additional reward if %TARGET% is delivered alive."
abstract_type = /datum/traitor_objective/kidnapping
//this is a prototype so this progression is for all basic level kill objectives
progression_reward = list(2 MINUTES, 4 MINUTES)
telecrystal_reward = list(1, 2)
/// The jobs that this objective is targetting.
var/list/target_jobs
/// The person we need to kidnap
var/mob/living/victim
/// Area that the victim 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 victims belongings
var/list/victim_belogings = list()
/datum/traitor_objective/kidnapping/common
progression_maximum = 30 MINUTES
target_jobs = list(
// Medical
/datum/job/doctor,
/datum/job/paramedic,
/datum/job/psychologist,
/datum/job/chemist,
// Service
/datum/job/clown,
/datum/job/botanist,
/datum/job/janitor,
/datum/job/mime,
/datum/job/lawyer,
/datum/job/chaplain,
/datum/job/bartender,
/datum/job/curator,
// Cargo
/datum/job/cargo_technician,
// Science
/datum/job/geneticist,
/datum/job/roboticist,
// Engineering
/datum/job/station_engineer,
/datum/job/atmospheric_technician,
)
/datum/traitor_objective/kidnapping/less_common
progression_maximum = 15 MINUTES
target_jobs = list(
/datum/job/assistant
)
/datum/traitor_objective/kidnapping/uncommon //Hard to fish out victims
progression_maximum = 45 MINUTES
target_jobs = list(
// Medical
/datum/job/virologist,
// Cargo
/datum/job/quartermaster,
/datum/job/shaft_miner,
// Service
/datum/job/cook,
// Science
/datum/job/scientist,
)
progression_reward = list(4 MINUTES, 8 MINUTES)
telecrystal_reward = list(1, 2)
alive_bonus = 1
/datum/traitor_objective/kidnapping/rare
progression_minimum = 15 MINUTES
progression_maximum = 60 MINUTES
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,
)
progression_reward = list(8 MINUTES, 12 MINUTES)
telecrystal_reward = list(1, 2)
alive_bonus = 2
/datum/traitor_objective/kidnapping/captain
progression_minimum = 30 MINUTES
target_jobs = list(
/datum/job/head_of_security,
/datum/job/captain
)
progression_reward = list(12 MINUTES, 16 MINUTES)
telecrystal_reward = list(2, 3)
alive_bonus = 2
/datum/traitor_objective/kidnapping/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
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/kidnapping/objective as anything in possible_duplicates)
possible_targets -= objective.victim.mind
if(!length(possible_targets))
return FALSE
var/datum/mind/target_mind = pick(possible_targets)
victim = target_mind.current
AddComponent(/datum/component/traitor_objective_register, victim, fail_signals = COMSIG_PARENT_QDELETING)
var/list/possible_areas = GLOB.the_station_areas.Copy()
for(var/area/possible_area as anything in possible_areas)
if(istype(possible_area, /area/station/hallway) || istype(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))
return TRUE
/datum/traitor_objective/kidnapping/ungenerate_objective()
victim = null
dropoff_area = null
/datum/traitor_objective/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/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/victim_area = get_area(victim)
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(victim_area.type != dropoff_area)
to_chat(user, span_warning("[victim.real_name] must be in [initial(dropoff_area.name)] for you to call the extraction pod."))
return
call_pod(user)
/datum/traitor_objective/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/enter_check)
new /obj/effect/pod_landingzone(get_turf(user), new_pod)
/datum/traitor_objective/kidnapping/proc/enter_check(obj/structure/closet/supplypod/extractionpod/source, entered_atom)
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
if(sent_mob.mind)
ADD_TRAIT(sent_mob.mind, TRAIT_HAS_BEEN_KIDNAPPED, TRAIT_GENERIC)
for(var/obj/item/belonging in sent_mob)
if(belonging == sent_mob.get_item_by_slot(ITEM_SLOT_ICLOTHING) || belonging == sent_mob.get_item_by_slot(ITEM_SLOT_FEET))
continue
sent_mob.transferItemToLoc(belonging)
victim_belogings.Add(belonging)
var/datum/bank_account/cargo_account = SSeconomy.get_dep_account(ACCOUNT_CAR)
if(cargo_account) //Just in case
cargo_account.adjust_money(-min(rand(1000, 3000), cargo_account.account_balance)) //Not so much, especially for competent cargo. Plus this can't be mass-triggered like it has been done with contractors
priority_announce("One of your crew was captured by a rival organisation - we've needed to pay their ransom to bring them back. As is policy we've taken a portion of the station's funds to offset the overall cost.", "Nanotrasen Asset Protection", has_important_message = TRUE)
addtimer(CALLBACK(src, .proc/handle_victim, sent_mob), 1.5 SECONDS)
if(sent_mob != victim)
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/kidnapping/proc/handle_victim(mob/living/carbon/human/sent_mob)
addtimer(CALLBACK(src, .proc/return_victim, sent_mob), 3 MINUTES)
if(sent_mob.stat == DEAD)
return
sent_mob.flash_act()
sent_mob.adjust_timed_status_effect(10 SECONDS, /datum/status_effect/confusion)
sent_mob.adjust_timed_status_effect(10 SECONDS, /datum/status_effect/dizziness)
sent_mob.blur_eyes(5 SECONDS)
to_chat(sent_mob, span_hypnophrase(span_reallybig("A million voices echo in your head... <i>\"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...\"</i>")))
/datum/traitor_objective/kidnapping/proc/return_victim(mob/living/carbon/human/sent_mob)
if(!sent_mob || QDELETED(sent_mob)) //suicided and qdeleted themselves
return
var/list/possible_turfs = list()
for(var/turf/open/open_turf in dropoff_area)
if(open_turf.is_blocked_turf() || isspaceturf(open_turf))
continue
possible_turfs += open_turf
if(!LAZYLEN(possible_turfs))
var/turf/new_turf = get_safe_random_station_turf()
if(!new_turf) //SOMEHOW
to_chat(sent_mob, span_hypnophrase(span_reallybig("A million voices echo in your head... <i>\"Seems where you got sent here from won't \
be able to handle our pod... You will die here instead.\"</i></span>")))
if (sent_mob.can_heartattack())
sent_mob.set_heartattack(TRUE)
return
possible_turfs += new_turf
var/obj/structure/closet/supplypod/return_pod = new()
return_pod.bluespace = TRUE
return_pod.explosionSize = list(0,0,0,0)
return_pod.style = STYLE_SYNDICATE
do_sparks(8, FALSE, sent_mob)
sent_mob.visible_message(span_notice("[sent_mob] vanishes!"))
for(var/obj/item/belonging in sent_mob)
if(belonging == sent_mob.get_item_by_slot(ITEM_SLOT_ICLOTHING) || belonging == sent_mob.get_item_by_slot(ITEM_SLOT_FEET))
continue
sent_mob.transferItemToLoc(belonging)
for(var/obj/item/belonging in victim_belogings)
belonging.forceMove(return_pod)
sent_mob.forceMove(return_pod)
sent_mob.flash_act()
sent_mob.adjust_timed_status_effect(10 SECONDS, /datum/status_effect/confusion)
sent_mob.adjust_timed_status_effect(10 SECONDS, /datum/status_effect/dizziness)
sent_mob.blur_eyes(5 SECONDS)
new /obj/effect/pod_landingzone(pick(possible_turfs), return_pod)
@@ -0,0 +1,257 @@
/datum/traitor_objective_category/locate_weakpoint
name = "Locate And Destroy Weakpoint"
objectives = list(
/datum/traitor_objective/locate_weakpoint = 1,
)
/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
/// Reference to the weakpoint locator(if we sent one)
var/obj/item/weakpoint_locator/locator
/// Reference to the ES8 explosive (if we sent one)
var/obj/item/grenade/c4/es8/shatter_charge
/// Locations we have to use the locator in
var/list/triangulation_locations
/// Have we located the weakpoint yet?
var/weakpoint_found = FALSE
/datum/traitor_objective/locate_weakpoint/generate_objective(datum/mind/generating_for, list/possible_duplicates)
////if(handler.get_completion_progression(/datum/traitor_objective) < progression_objectives_minimum)
//// return FALSE
if(!SStraitor.station_weakpoints || !LAZYLEN(SStraitor.station_weakpoints)) //This means that the weakpoint has already been hit
return FALSE
var/area/weakpoint_area1 = SStraitor.station_weakpoints[1]
var/area/weakpoint_area2 = SStraitor.station_weakpoints[2]
replace_in_name("%AREA1%", initial(weakpoint_area1.name))
replace_in_name("%AREA2%", initial(weakpoint_area2.name))
triangulation_locations = list(SStraitor.station_weakpoints[1] = TRUE, SStraitor.station_weakpoints[2] = TRUE)
RegisterSignal(generating_for, COMSIG_GLOB_TRAITOR_OBJECTIVE_COMPLETED, .proc/on_global_obj_completed)
return TRUE
/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)
buttons += add_ui_button("", "Pressing this will materialize a weakpoint locator in your hand.", "globe", "locator")
if(weakpoint_found && !shatter_charge)
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)
return
locator = new(user.drop_location())
user.put_in_hands(locator)
locator.balloon_alert(user, "the weakpoint locator materializes in your hand")
if("shatter_charge")
if(shatter_charge)
return
shatter_charge = new(user.drop_location())
user.put_in_hands(shatter_charge)
shatter_charge.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."
var/area/weakpoint_area = SStraitor.station_weakpoints[3]
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/severity = list(EXPLODE_LIGHT, EXPLODE_LIGHT, EXPLODE_LIGHT, EXPLODE_LIGHT, EXPLODE_HEAVY, EXPLODE_HEAVY, EXPLODE_DEVASTATE) //Can't use pick_weight because explode defines are numbers
var/wave_amount = rand(5, 8)
var/list/bombed_turfs = list()
for(var/i in 1 to wave_amount)
var/wave_angle = rand(-10, 10) + 360 / wave_amount * i
var/wave_distance = rand(17, 25)
var/turf/tentacle_ending = locate(clamp(center_x + round(cos(wave_angle) * wave_distance), 1, world.maxx), clamp(center_y + round(sin(wave_angle) * wave_distance), 1, world.maxy), center_z)
if(!tentacle_ending) //WUT
continue
var/turf/epicenter = locate(center_x, center_y, center_z)
for(var/turf/line_turf in get_line(epicenter, tentacle_ending))
for(var/turf/bomb_turf in range(1, line_turf))
if((bomb_turf in bombed_turfs) || bomb_turf == epicenter)
continue
bombed_turfs += bomb_turf
var/turf_severity = pick(severity)
EX_ACT(line_turf, turf_severity)
for(var/atom/victim in line_turf)
EX_ACT(victim, turf_severity - 1)
explosion(tentacle_ending, devastation_range = 1, heavy_impact_range = 3, light_impact_range = 5, 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"
)
SStraitor.station_weakpoints = null //Gone
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/device.dmi'
icon_state = "weakpoint_locator"
inhand_icon_state = "weakpoint_locator"
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
throwforce = 0
w_class = WEIGHT_CLASS_SMALL
throw_speed = 3
throw_range = 5
/obj/item/weakpoint_locator/Initialize(mapload)
. = ..()
var/area/weakpoint_area1 = SStraitor.station_weakpoints[1]
var/area/weakpoint_area2 = SStraitor.station_weakpoints[2]
desc = replacetext(desc, "%AREA1%", initial(weakpoint_area1.name))
desc = replacetext(desc, "%AREA2%", initial(weakpoint_area2.name))
/obj/item/weakpoint_locator/attack_self(mob/living/user, modifiers)
. = ..()
if(!istype(user) || loc != user || !user.mind) //No TK cheese
return
if(!user.mind.has_antag_datum(/datum/antagonist/traitor))
to_chat(user, span_warning("You have zero clue how to use [src]."))
return
var/datum/traitor_objective/locate_weakpoint/objective = get_weakpoint_objective(user)
if(!objective || objective.objective_state == OBJECTIVE_STATE_INACTIVE)
to_chat(user, span_warning("Your time to use [src] has not come yet."))
return
var/area/user_area = get_area(user)
if(!(user_area.type in objective.triangulation_locations))
balloon_alert(user, "invalid area!")
playsound(user, 'sound/machines/buzz-sigh.ogg', 30, TRUE)
return
if(!objective.triangulation_locations[user_area.type])
balloon_alert(user, "already scanned here!")
playsound(user, 'sound/machines/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/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, 3 SECONDS, src, IGNORE_USER_LOC_CHANGE | IGNORE_TARGET_LOC_CHANGE | IGNORE_HELD_ITEM | IGNORE_INCAPACITATED | IGNORE_SLOWDOWNS, extra_checks = CALLBACK(src, .proc/scan_checks, user, user_area, objective)))
playsound(user, 'sound/machines/buzz-sigh.ogg', 30, TRUE)
return
playsound(user, 'sound/machines/ding.ogg', 100, TRUE)
objective.triangulation_locations[user_area.type] = FALSE
for(var/area/scan_area in objective.triangulation_locations)
if(objective.triangulation_locations[scan_area])
say("Next scanning location is [initial(scan_area.name)]")
return
var/area/weakpoint_location = SStraitor.station_weakpoints[3]
to_chat(user, span_notice("Scan finished. Structural weakpoint located in [initial(weakpoint_location.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_FAILED || parent_objective.objective_state == OBJECTIVE_STATE_INVALID)
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/weakpoint_locator/proc/get_weakpoint_objective(mob/living/user)
if(!user.mind)
return
for(var/datum/traitor_objective/locate_weakpoint/weakpoint_objecitve in SStraitor.taken_objectives_by_type[/datum/traitor_objective/locate_weakpoint])
var/datum/uplink_handler/handler = weakpoint_objecitve.handler
if(handler.owner != user.mind)
continue
return weakpoint_objecitve
/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)
/// Reference to user's objective
var/datum/traitor_objective/locate_weakpoint/objective
/obj/item/grenade/c4/es8/Destroy()
objective = null
return ..()
/obj/item/grenade/c4/es8/afterattack(atom/movable/target, mob/user, flag)
if(!user.mind)
return
if(!user.mind.has_antag_datum(/datum/antagonist/traitor))
to_chat(user, span_warning("You can't seem to find a way to detonate the charge."))
return
for(var/datum/traitor_objective/locate_weakpoint/weakpoint_objecitve in SStraitor.taken_objectives_by_type[/datum/traitor_objective/locate_weakpoint])
var/datum/uplink_handler/handler = weakpoint_objecitve.handler
if(handler.owner != user.mind)
continue
objective = weakpoint_objecitve
if(!objective || objective.objective_state == OBJECTIVE_STATE_INACTIVE)
to_chat(user, span_warning("You don't think it would be wise to use [src]."))
return
var/area/target_area = get_area(target)
if (target_area.type != SStraitor.station_weakpoints[3])
var/area/weakpoint_area = SStraitor.station_weakpoints[3]
to_chat(user, span_warning("[src] can only be detonated in [initial(weakpoint_area.name)]."))
return
return ..()
/obj/item/grenade/c4/es8/detonate(mob/living/lanced_by)
var/area/target_area = get_area(target)
if (target_area.type != SStraitor.station_weakpoints[3])
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
if(!objective)
return
objective.create_shockwave(target.x, target.y, target.z)
return ..()
@@ -2,6 +2,7 @@
name = "Sleeper Protocol"
objectives = list(
/datum/traitor_objective/sleeper_protocol = 1,
/datum/traitor_objective/sleeper_protocol/everybody = 1,
)
@@ -17,12 +18,15 @@
JOB_MEDICAL_DOCTOR,
JOB_PARAMEDIC,
JOB_VIROLOGIST,
JOB_ROBOTICIST,
)
var/obj/item/disk/surgery/sleeper_protocol/disk
var/mob/living/current_registered_mob
var/inverted_limitation = FALSE
/datum/traitor_objective/sleeper_protocol/generate_ui_buttons(mob/user)
var/list/buttons = list()
if(!disk)
@@ -46,7 +50,9 @@
/datum/traitor_objective/sleeper_protocol/generate_objective(datum/mind/generating_for, list/possible_duplicates)
var/datum/job/job = generating_for.assigned_role
if(!(job.title in limited_to))
if(!(job.title in limited_to) && !inverted_limitation)
return FALSE
if((job.title in limited_to) && inverted_limitation)
return FALSE
AddComponent(/datum/component/traitor_objective_mind_tracker, generating_for, \
signals = list(COMSIG_MOB_SURGERY_STEP_SUCCESS = .proc/on_surgery_success))
@@ -87,7 +93,7 @@
/datum/surgery_step/brainwash/sleeper_agent
time = 25 SECONDS
var/list/possible_objectives = list(
var/static/list/possible_objectives = list(
"You love the Syndicate",
"Do not trust Nanotrasen",
"The Captain is a lizardperson",
@@ -111,3 +117,11 @@
if(!.)
return
target.gain_trauma(new /datum/brain_trauma/mild/phobia/conspiracies(), TRAUMA_RESILIENCE_LOBOTOMY)
/datum/traitor_objective/sleeper_protocol/everybody //Much harder for non-med and non-robo
progression_minimum = 30 MINUTES
progression_reward = list(15 MINUTES, 20 MINUTES)
telecrystal_reward = list(2, 3)
inverted_limitation = TRUE
+4
View File
@@ -78,6 +78,10 @@
bluespace = TRUE
explosionSize = list(0,0,1,2)
delays = list(POD_TRANSIT = 25, POD_FALLING = 4, POD_OPENING = 30, POD_LEAVING = 30)
reversing = TRUE
stay_after_drop = TRUE
leavingSound = 'sound/effects/podwoosh.ogg'
reverse_option_list = list("Mobs"=TRUE,"Objects"=FALSE,"Anchored"=FALSE,"Underfloor"=FALSE,"Wallmounted"=FALSE,"Floors"=FALSE,"Walls"=FALSE, "Mecha"=FALSE)
/obj/structure/closet/supplypod/centcompod
style = STYLE_CENTCOM
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

+2
View File
@@ -2319,7 +2319,9 @@
#include "code\modules\antagonists\traitor\objectives\destroy_item.dm"
#include "code\modules\antagonists\traitor\objectives\destroy_machinery.dm"
#include "code\modules\antagonists\traitor\objectives\hack_comm_console.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\sleeper_protocol.dm"
#include "code\modules\antagonists\traitor\objectives\steal.dm"
#include "code\modules\antagonists\traitor\objectives\final_objective\battlecruiser.dm"