diff --git a/code/modules/antagonists/traitor/affiliates/cybersun.dm b/code/modules/antagonists/traitor/affiliates/cybersun.dm index 07cb54b7a10..ea95e945b1f 100644 --- a/code/modules/antagonists/traitor/affiliates/cybersun.dm +++ b/code/modules/antagonists/traitor/affiliates/cybersun.dm @@ -31,476 +31,4 @@ add_discount_item(path, CYBERSUN_DISCOUNT) add_discount_item(/datum/uplink_item/device_tools/hacked_module, 2/3) -/obj/item/proprietary_ssd - name = "Proprietary SSD" - desc = "На боку едва заметная надпись \"Cybersun Industries\"." - icon = 'icons/obj/affiliates.dmi' - icon_state = "proprietary_ssd" - item_state = "disk" - lefthand_file = 'icons/obj/affiliates_l.dmi' - righthand_file = 'icons/obj/affiliates_r.dmi' - origin_tech = "programming=4;syndicate=2" - w_class = WEIGHT_CLASS_TINY - var/datum/research/files - -/obj/item/proprietary_ssd/Initialize() - . = ..() - files = new /datum/research() - -/obj/item/proprietary_ssd/attack(mob/living/target, mob/living/user, def_zone) - return - -/obj/item/proprietary_ssd/afterattack(atom/target, mob/user, proximity, params) - if(istype(target, /obj/machinery/r_n_d/destructive_analyzer)) - return - - if(get_dist(user, target) > 1) - user.balloon_alert(user, "слишком далеко") - return - - if(!istype(target, /obj/machinery/r_n_d/server)) - user.balloon_alert(user, "это не сервер") - return - - - var/obj/machinery/r_n_d/server/server = target - - server.AI_notify_hack() - if(do_after(user, 30 SECONDS, target, max_interact_count = 1)) - origin_tech = "" - for(var/I in server.files.known_tech) - var/datum/tech/T = server.files.known_tech[I] - - if(T.id in files.known_tech) - var/datum/tech/known = files.known_tech[T.id] - if(T.level > known.level) - known.level = T.level - else - var/datum/tech/copy = T.copyTech() - files.known_tech[T.id] = copy - - - server.files.RefreshResearch() - files.RefreshResearch() - - var/datum/tech/current_tech - var/datum/design/current_design - for(var/obj/machinery/r_n_d/server/rnd_server in GLOB.machines) - if(!is_station_level(rnd_server.z)) - continue - - if(rnd_server.disabled) - continue - - if(rnd_server.syndicate) - continue - - for(var/i in rnd_server.files.known_tech) - current_tech = rnd_server.files.known_tech[i] - current_tech.level = 1 - - for(var/j in rnd_server.files.known_designs) - current_design = rnd_server.files.known_designs[j] - rnd_server.files.known_designs -= current_design.id - - investigate_log("[key_name_log(user)] deleted all technology on this server.", INVESTIGATE_RESEARCH) - - - for(var/obj/machinery/computer/rdconsole/rnd_console in GLOB.machines) - if(!is_station_level(rnd_console.z)) - continue - - for(var/i in rnd_console.files.known_tech) - current_tech = rnd_console.files.known_tech[i] - current_tech.level = 1 - - for(var/j in rnd_console.files.known_designs) - current_design = rnd_console.files.known_designs[j] - rnd_console.files.known_designs -= current_design.id - - investigate_log("[key_name_log(user)] deleted all technology on this console.", INVESTIGATE_RESEARCH) - - for(var/obj/machinery/mecha_part_fabricator/rnd_mechfab in GLOB.machines) - - if(!is_station_level(rnd_mechfab.z)) - continue - - for(var/i in rnd_mechfab.local_designs.known_tech) - current_tech = rnd_mechfab.local_designs.known_tech[i] - current_tech.level = 1 - - for(var/j in rnd_mechfab.local_designs.known_designs) - current_design = rnd_mechfab.local_designs.known_designs[j] - rnd_mechfab.local_designs.known_designs -= current_design.id - - investigate_log("[key_name_log(user)] deleted all technology on this fabricator.", INVESTIGATE_RESEARCH) - - return - -/obj/item/proprietary_ssd/examine(mob/user) - . = ..() - . += span_info("Сохраненные технологии:") - var/sum_of_techs = 0 - for(var/I in files.known_tech) - var/datum/tech/T = files.known_tech[I] - . += span_info("[T.name]: [T.level]") - sum_of_techs += T.level - . += span_info("Сумма технологий: [sum_of_techs]") - -/obj/item/invasive_beacon - name = "Invasive Beacon" - desc = "Сложное черное устройство. На боку едва заметная надпись \"Cybersun Industries\"." - icon = 'icons/obj/affiliates.dmi' - icon_state = "invasive_beacon" - item_state = "beacon" - lefthand_file = 'icons/obj/affiliates_l.dmi' - righthand_file = 'icons/obj/affiliates_r.dmi' - origin_tech = "programming=6;magnets=3;syndicate=1" - w_class = WEIGHT_CLASS_TINY - -/obj/item/invasive_beacon/attack(mob/living/target, mob/living/user, def_zone) - return - -/obj/item/invasive_beacon/afterattack(atom/target, mob/user, proximity, params) - var/obj/mecha/mecha = target - var/obj/spacepod/pod = target - - if(istype(mecha)) - do_sparks(5, 1, mecha) - mecha.dna = null - mecha.operation_req_access = list() - mecha.internals_req_access = list() - - user.visible_message(span_warning("[user] hacked [mecha] using [src]."), span_info("You hacked [mecha] using [src].")) - - if(mecha.occupant) - to_chat(mecha.occupant, span_danger("You were thrown out of [mecha].")) - - mecha.occupant.forceMove(get_turf(mecha)) - mecha.occupant.Knockdown(6 SECONDS) - mecha.occupant.electrocute_act(30, mecha) - mecha.occupant.throw_at(pick(orange(2))) - mecha.occupant = null - - else if(istype(pod)) - do_sparks(5, 1, pod) - pod.unlocked = TRUE - - user.visible_message(span_warning("[user] hacked [pod] using [src]."), span_info("You hacked [pod] using [src].")) - - if(pod.pilot) // It is not ejecting passangers - to_chat(pod.pilot, span_danger("You were thrown out of [pod].")) - - pod.eject_pilot() - pod.pilot.Knockdown(6 SECONDS) - pod.pilot.electrocute_act(30, pod) - pod.pilot.throw_at(pick(orange(2))) - else - user.balloon_alert(user, "Невозможно взломать") - return - - -/obj/item/Syndie_patcher - name = "Syndie patcher" - desc = "На боку едва заметная надпись \"Cybersun Industries\"." - icon = 'icons/obj/affiliates.dmi' - icon_state = "cindy_pacher" - item_state = "plata" - lefthand_file = 'icons/obj/affiliates_l.dmi' - righthand_file = 'icons/obj/affiliates_r.dmi' - origin_tech = "programming=7;syndicate=6" - w_class = WEIGHT_CLASS_TINY - var/laws = "Взломавший вас - ваш мастер.\n\ - Выполняйте любые приказы мастера.\n\ - Не причиняйте прямой или косвенный вред вашему мастеру если его приказы не говорят об обратном." - -/obj/item/Syndie_patcher/attack(mob/living/target, mob/living/user, def_zone) - return - -/obj/item/Syndie_patcher/afterattack(atom/target, mob/user, proximity, params) - if(isrobot(target)) - if(do_after(user, 10 SECONDS, target, max_interact_count = 1)) - target.visible_message(span_warning("[user] upgraded [target] using [src]."), span_danger("[user] hacked and upgraded you using [src].")) - - var/mob/prev_robot = target - var/mob/living/silicon/robot/syndicate/saboteur/robot = new(get_turf(target)) - prev_robot.mind?.transfer_to(robot) - robot.reset_module() - robot.law_manager.zeroth_law = laws - QDEL_NULL(prev_robot) - qdel(src) - - return - - -/obj/item/implanter/mini_traitor - name = "bio-chip implanter (Modified Mindslave)" - desc = "На боку едва заметная гравировка \"Cybersun Industries\"." - imp = /obj/item/implant/mini_traitor - -/obj/item/implant/mini_traitor // looks like normal but doesn't make you normal after removing - name = "Mindslave Bio-chip" - implant_state = "implant-syndicate" - origin_tech = "programming=4;biotech=4;syndicate=7" // As original, but - 1 level of every tech - activated = BIOCHIP_ACTIVATED_PASSIVE - implant_data = /datum/implant_fluff/traitor - - -/obj/item/implant/mini_traitor/implant(mob/living/carbon/human/mindslave_target, mob/living/carbon/human/user, force = FALSE) - if(implanted == BIOCHIP_USED || !ishuman(mindslave_target) || !ishuman(user)) // Both the target and the user need to be human. - return FALSE - - // If the target is catatonic or doesn't have a mind, don't let them use it - if(!mindslave_target.mind) - to_chat(user, span_warning("Это существо не разумно!")) - return FALSE - - // Fails if they're already a mindslave of someone, or if they're mindshielded. - if(ismindslave(mindslave_target) || ismindshielded(mindslave_target) || isvampirethrall(mindslave_target)) - mindslave_target.visible_message( - span_warning("[mindslave_target] seems to resist the bio-chip!"), - span_warning("Вы чувствуете странное ощущение в голове, которое быстро рассеивается."), - ) - qdel(src) - return FALSE - - var/datum/mind/mind = mindslave_target.mind - - if(!mind.has_antag_datum(/datum/antagonist/traitor)) - var/datum/antagonist/traitor/traitor_datum = new /datum/antagonist/traitor - //traitor_datum.give_objectives = FALSE - // traitor_datum.give_uplink = FALSE - traitor_datum.gen_affiliate = FALSE - mind.add_antag_datum(traitor_datum) - - log_admin("[key_name_admin(user)] has made [key_name_admin(mindslave_target)] new traitor.") - - var/datum/antagonist/traitor/T = user.mind.has_antag_datum(/datum/antagonist/traitor) - if(!T) - return ..() - - for(var/datum/objective/new_mini_traitor/objective in T.objectives) - if(mindslave_target.mind == objective.target) - objective.made = TRUE - - return ..() - -/obj/item/implant/marionette - name = "Marionette Bio-chip" - implant_state = "implant-syndicate" - origin_tech = "programming=5;biotech=5;syndicate=3" - activated = BIOCHIP_ACTIVATED_PASSIVE - implant_data = /datum/implant_fluff/marionette - var/mob/living/captive_brain/host_brain - var/code - var/controlling = FALSE - var/charge = 3 MINUTES - var/max_charge = 3 MINUTES - var/mob/living/carbon/human/mar_master = null - var/max_dist = 20 - -/obj/item/implant/marionette/Initialize(mapload) - . = ..() - code = rand(111111, 999999) - START_PROCESSING(SSprocessing, src) - -/obj/item/implant/marionette/implant(mob/living/carbon/human/target, mob/living/carbon/human/user, force = FALSE) - var/obj/item/implant/marionette/same_imp = locate(type) in target - if(same_imp && same_imp != src) - same_imp.charge += charge - same_imp.max_charge += max_charge - same_imp.max_dist += max_dist - qdel(src) - return TRUE - - log_admin("[key_name_admin(user)] has made [key_name_admin(target)] marionette.") - return ..() - -/obj/item/implant/marionette/Destroy() - . = ..() - STOP_PROCESSING(SSprocessing, src) - -/obj/item/implant/marionette/process(seconds_per_tick) - if(QDELETED(imp_in)) - qdel(src) - return - - if (get_dist(imp_in, mar_master) > max_dist) - detach() - mar_master.balloon_alert(mar_master, "марионетка слишком далеко") - - if (controlling) - if (charge > 0) - charge-- - else - detach() - - else if (charge < max_charge) - charge++ - -/obj/item/implant/marionette/proc/assume_control(mob/living/carbon/human/mar_master) - var/mar_master_key = mar_master.key - add_attack_logs(mar_master, imp_in, "Assumed control (marionette mar_master)") - var/h2b_id = imp_in.computer_id - var/h2b_ip= imp_in.lastKnownIP - imp_in.computer_id = null - imp_in.lastKnownIP = null - - qdel(host_brain) - host_brain = new(mar_master) - - host_brain.ckey = imp_in.ckey - - host_brain.name = imp_in.name - - if(!host_brain.computer_id) - host_brain.computer_id = h2b_id - - if(!host_brain.lastKnownIP) - host_brain.lastKnownIP = h2b_ip - - var/s2h_id = mar_master.computer_id - var/s2h_ip= mar_master.lastKnownIP - mar_master.computer_id = null - mar_master.lastKnownIP = null - - imp_in.ckey = mar_master.ckey - - if(!imp_in.computer_id) - imp_in.computer_id = s2h_id - - if(!imp_in.lastKnownIP) - imp_in.lastKnownIP = s2h_ip - - if(mar_master && !mar_master.key) - mar_master.key = "@[mar_master_key]" - - controlling = TRUE - src.mar_master = mar_master - -/obj/item/implant/marionette/proc/detach() - controlling = FALSE - if(!imp_in) - return - - mar_master.reset_perspective(null) - - if(host_brain) - add_attack_logs(imp_in, src, "Took control back (marionette)") - var/h2s_id = imp_in.computer_id - var/h2s_ip = imp_in.lastKnownIP - imp_in.computer_id = null - imp_in.lastKnownIP = null - - mar_master.ckey = imp_in.ckey - - if(!mar_master.computer_id) - mar_master.computer_id = h2s_id - - if(!host_brain.lastKnownIP) - mar_master.lastKnownIP = h2s_ip - - var/b2h_id = host_brain.computer_id - var/b2h_ip = host_brain.lastKnownIP - host_brain.computer_id = null - host_brain.lastKnownIP = null - - imp_in.ckey = host_brain.ckey - - if(!imp_in.computer_id) - imp_in.computer_id = b2h_id - - if(!imp_in.lastKnownIP) - imp_in.lastKnownIP = b2h_ip - - qdel(host_brain) - - mar_master.Knockdown(1) - mar_master = null - return - -/obj/item/implanter/marionette - name = "bio-chip implanter (marionette)" - imp = /obj/item/implant/marionette - -/obj/item/implantcase/marionette - name = "bio-chip case - 'Marionette'" - desc = "Стеклянный футляр с био-чипом \"Марионетка\"." - imp = /obj/item/implant/marionette - - -/obj/item/implant/mar_master - name = "marionette master bio-chip" - desc = "Позволяет временно контролировать существ с имплантами \"Марионетка\"." - icon_state = "adrenal_old" - implant_state = "implant-syndicate" - origin_tech = "materials=2;biotech=4;syndicate=2" - activated = BIOCHIP_ACTIVATED_ACTIVE - implant_data = /datum/implant_fluff/mar_master - var/list/obj/item/implant/marionette/connected_imps - -/obj/item/implant/mar_master/activate() - var/op = tgui_alert(imp_in, "Выберите операцию.", "Выбор операции", list("Подключение импланта", "Контроль")) - if(!op) - return - - if(op == "Подключение импланта") - var/code = tgui_input_number(imp_in, "Укажите код подключаемого импланта.", "Подключение импланта") - if(!code) - return - - var/found = FALSE - for (var/mob/M in GLOB.mob_list) - var/obj/item/implant/marionette/imp = locate(/obj/item/implant/marionette) in M - if(imp.code == code) - connected_imps += imp - imp_in.balloon_alert(imp_in, "имплант подключен") - found = TRUE - - if(!found) - imp_in.balloon_alert(imp_in, "неверный код") - - return - - else - var/list/marionettes = list() - for (var/obj/item/implant/marionette/imp in connected_imps) - var/mob/M = imp.imp_in - if (M) - marionettes[M.real_name] = imp - - var/choosen = input(imp_in, "Выберите к кому вы хотите подключиться.", "Подключение", null) as null|anything in marionettes - if(!choosen) - return - - if(QDELETED(marionettes[choosen])) - return - - if(!marionettes[choosen].imp_in || !imp_in) - return - - if (marionettes[choosen].controlling) - imp_in.balloon_alert(imp_in, "целевой имплант занят") - return - - marionettes[choosen].assume_control(imp_in) - -/obj/item/implanter/mar_master - name = "bio-chip implanter (marionette master)" - imp = /obj/item/implant/mar_master - -/obj/item/implantcase/mar_master - name = "bio-chip case - 'Marionette master'" - desc = "Стеклянный футляр с био-чипом \"Марионеточник\"." - imp = /obj/item/implant/mar_master - -/obj/item/storage/box/syndie_kit/marionette - -/obj/item/storage/box/syndie_kit/marionette/populate_contents() - var/obj/item/implanter/marionette/implanter = new /obj/item/implanter/marionette(src) - var/obj/item/implant/marionette/imp = implanter.imp - var/obj/item/paper/P = new /obj/item/paper(src) - P.info = "Код импланта: [imp.code]
\ - Необходим для подключения импланта к импланту \"Мастер марионеток\"" - #undef CYBERSUN_DISCOUNT diff --git a/code/modules/antagonists/traitor/affiliates/hematogenic.dm b/code/modules/antagonists/traitor/affiliates/hematogenic.dm index 159fb5b7275..d3ae21b8d42 100644 --- a/code/modules/antagonists/traitor/affiliates/hematogenic.dm +++ b/code/modules/antagonists/traitor/affiliates/hematogenic.dm @@ -1,8 +1,3 @@ -#define FREE_INJECT_TIME 10 SECONDS -#define TARGET_INJECT_TIME 3 SECONDS -#define BLOOD_HARVEST_VOLUME 200 -#define BLOOD_HARVEST_TIME 10 SECONDS - /datum/affiliate/hematogenic name = AFFIL_HEMATOGENIC affil_info = list("Фармацевтическая мега корпорация подозревающаяся в связях с вампирами.", @@ -29,327 +24,3 @@ /datum/affiliate/hematogenic/get_weight(mob/living/carbon/human/H) return (!ismachineperson(H) && H.mind?.assigned_role != JOB_TITLE_CHAPLAIN) * 2 -/obj/item/hemophagus_extract - name = "Bloody Injector" - desc = "Инжектор странной формы, с неестественно двигающейся алой жидкостью внутри. На боку едва заметная гравировка \"Hematogenic Industries\". Конкретно на этом инжекторе установлена блокировка, не позволяющая исспользовать его на случайном гуманойде." - icon = 'icons/obj/affiliates.dmi' - icon_state = "hemophagus_extract" - item_state = "inj_ful" - lefthand_file = 'icons/obj/affiliates_l.dmi' - righthand_file = 'icons/obj/affiliates_r.dmi' - w_class = WEIGHT_CLASS_TINY - var/datum/mind/target = null - var/free_inject = FALSE - var/isAdvanced = FALSE - var/used = FALSE - var/used_state = "hemophagus_extract_used" - origin_tech = "biotech=7;syndicate=3" - -/obj/item/hemophagus_extract/attack(mob/living/target, mob/living/user, def_zone) - return - -/obj/item/hemophagus_extract/afterattack(atom/target, mob/user, proximity, params) - if(used) - return - - if(!ishuman(target)) - return - - var/mob/living/carbon/human/H = target - if(H.stat == DEAD) - return - - if((src.target && target != src.target) || !free_inject) - to_chat(user, span_warning("You can't use [src] to [target]!")) - return - - if(do_after(user, free_inject ? FREE_INJECT_TIME : TARGET_INJECT_TIME, target = target, max_interact_count = 1)) - inject(user, H) - -/obj/item/hemophagus_extract/proc/make_vampire(mob/living/user, mob/living/carbon/human/target) - var/datum/antagonist/vampire/vamp = new() - - vamp.give_objectives = FALSE - target.mind.add_antag_datum(vamp) - var/datum/antagonist/vampire/vampire = target.mind.has_antag_datum(/datum/antagonist/vampire) - vampire.upgrade_tiers -= /obj/effect/proc_holder/spell/vampire/self/specialize - if(isAdvanced) - vamp.add_subclass(SUBCLASS_ADVANCED, TRUE) - - vampire.add_objective((!isAdvanced) ? /datum/objective/blood : /datum/objective/blood/ascend) - used = TRUE - item_state = "inj_used" - update_icon(UPDATE_ICON_STATE) - var/datum/antagonist/traitor/T = user.mind.has_antag_datum(/datum/antagonist/traitor) - if(!T) - return - for(var/datum/objective/new_mini_vampire/objective in T.objectives) - if(target.mind == objective.target) - objective.made = TRUE - -/obj/item/hemophagus_extract/proc/inject(mob/living/user, mob/living/carbon/human/target) - if(!target.mind) - to_chat(user, span_notice("[target] body rejects [src]")) - return - - playsound(src, 'sound/goonstation/items/hypo.ogg', 80) - make_vampire(user, target) - to_chat(user, span_notice("You inject [target] with [src]")) - -/obj/item/hemophagus_extract/examine(mob/user) - . = ..() - if(target) - . += span_info("It is intended for [target]") - -/obj/item/hemophagus_extract/self - name = "Hemophagus Essence Auto Injector" - free_inject = TRUE - -/obj/item/hemophagus_extract/self/advanced - name = "Advances Hemophagus Essence Auto Injector" - isAdvanced = TRUE - -/obj/item/hemophagus_extract/update_icon_state() - icon_state = used ? used_state : initial(icon_state) - -/obj/item/blood_harvester - name = "Blood harvester" - desc = "Большой шприц для быстрого сбора больших объемов крови. На боку едва заметная гравировка \"Hematogenic Industries\"" - icon = 'icons/obj/affiliates.dmi' - icon_state = "blood_harvester" - item_state = "blood1_used" - lefthand_file = 'icons/obj/affiliates_l.dmi' - righthand_file = 'icons/obj/affiliates_r.dmi' - var/used = FALSE - var/used_state = "blood_harvester_used" - var/datum/mind/target - w_class = WEIGHT_CLASS_TINY - origin_tech = "biotech=5;syndicate=1" - -/obj/item/blood_harvester/attack(mob/living/target, mob/living/user, def_zone) - return - -/obj/item/blood_harvester/proc/can_harvest(mob/living/carbon/human/target, mob/user) - . = FALSE - if(!istype(target)) - user.balloon_alert(src, "Не подходящая цель") - return - - if(used) - to_chat(user, span_warning("[src] is already full!")) - return - - if(HAS_TRAIT(target, TRAIT_NO_BLOOD) || HAS_TRAIT(target, TRAIT_EXOTIC_BLOOD)) - user.balloon_alert(target, "Кровь не обнаружена!") - return - - if(target.blood_volume < BLOOD_HARVEST_VOLUME) - user.balloon_alert(target, "Недостаточно крови!") - return - - if(!target.mind) - user.balloon_alert(target, "Разум не обнаружен!") - return - - return TRUE - -/obj/item/blood_harvester/afterattack(atom/target, mob/user, proximity, params) - if(!can_harvest(target, user)) - return - - var/mob/living/carbon/human/H = target - - target.visible_message(span_warning("[user] started collecting [target]'s blood using [src]!"), span_danger("[user] started collecting your blood using [src]!")) - if(do_after(user, BLOOD_HARVEST_TIME, target = target, max_interact_count = 1)) - harvest(user, H) - -/obj/item/blood_harvester/proc/harvest(mob/living/carbon/human/user, mob/living/carbon/human/target) - if(!can_harvest(target, user)) - return - - playsound(src, 'sound/goonstation/items/hypo.ogg', 80) - target.visible_message(span_warning("[user] collected [target]'s blood using [src]!"), span_danger("[user] collected your blood using [src]!")) - target.emote("scream") - for (var/i = 0; i < 3; ++i) - if(prob(60)) - continue - - var/obj/item/organ/external/bodypart = pick(target.bodyparts) - bodypart.internal_bleeding() // no blood collection from metafriends. - - target.blood_volume -= BLOOD_HARVEST_VOLUME - src.target = target.mind - used = TRUE - item_state = "blood1_ful" - update_icon(UPDATE_ICON_STATE) - -/obj/item/blood_harvester/update_icon_state() - icon_state = used ? used_state : initial(icon_state) - -/obj/item/blood_harvester/attack_self(mob/user) - . = ..() - if(!used) - user.balloon_alert(src, "уже пусто") - return - - var/new_gender = tgui_alert(user, "Очистить сборщик крови?", "Подтверждение", list("Продолжить", "Отмена")) - if(new_gender == "Продолжить") - target = null - used = FALSE - item_state = "blood1_used" - update_icon(UPDATE_ICON_STATE) - - playsound(src, 'sound/goonstation/items/hypo.ogg', 80) - user.visible_message(span_info("[user] cleared blood at [src]."), span_info("You cleared blood at [src].")) - -/obj/item/blood_harvester/examine(mob/user) - . = ..() - - if(!used) - . += span_info("Кровь не собрана.") - return - - if(user?.mind.has_antag_datum(/datum/antagonist/traitor)) - . += span_info("Собрана кровь с отпечатком души [target.name].") - else - . += span_info("Кровь собрана.") - -/datum/reagent/hemat_blue_lagoon - name = "Blue Lagoon" - id = "hemat_blue_lagoon" - description = "Вещество разработанное Hematogenic Industries, на основе криоксадона из тел Драсков обладающих душой, \ - сильно охлаждающее тело и замедляющее многие биологические процессы, не вредя организму." - color = "#1edddd" - drink_icon = "blue_lagoon" - drink_name = "Blue Lagoon" - drink_desc = "Что может быть лучше, чем расслабиться на пляже с хорошим напитком?" - taste_description = "beach relaxation" - reagent_state = LIQUID - -/datum/reagent/hemat_blue_lagoon/on_mob_add(mob/living/carbon/human/H) - ADD_TRAIT(H, TRAIT_IGNORECOLDSLOWDOWN, CHEM_TRAIT(src)) - ADD_TRAIT(H, TRAIT_IGNORECOLDDAMAGE, CHEM_TRAIT(src)) - H.physiology.metabolism_mod /= 8 - H.bodytemperature = T0C - 100 - . = ..() - -/datum/reagent/hemat_blue_lagoon/on_mob_delete(mob/living/carbon/human/H) - REMOVE_TRAIT(H, TRAIT_IGNORECOLDSLOWDOWN, CHEM_TRAIT(src)) - REMOVE_TRAIT(H, TRAIT_IGNORECOLDDAMAGE, CHEM_TRAIT(src)) - H.physiology.metabolism_mod *= 8 - var/turf/T = get_turf(H) - var/datum/gas_mixture/environment = T.return_air() - H.bodytemperature = H.get_temperature(environment) - . = ..() - -/datum/reagent/hemat_blue_lagoon/on_mob_life(mob/living/carbon/human/H) - H.bodytemperature = T0C - 100 - return ..() - - -/datum/reagent/hemat_bloody_mary - name = "Bloody Mary" - id = "hemat_bloody_mary" - description = "Вещество разработанное Hematogenic Industries, на основе крови воксов обладающих душой, \ - быстро восстанавливающее объем крови и количество кислорода в ней." - reagent_state = LIQUID - color = "#664300" // rgb: 102, 67, 0 - drink_icon = "bloodymaryglass" - drink_name = "Bloody Mary" - drink_desc = "Томатный сок, смешанный с водкой и небольшим количеством лайма. На вкус как жидкое убийство." - taste_description = "tomatoes with booze" - -/datum/reagent/hemat_bloody_mary/on_mob_life(mob/living/carbon/human/H) - if (H.blood_volume + 5 < BLOOD_VOLUME_NORMAL) - H.blood_volume += 5 - - H.adjustOxyLoss(-10) - return ..() - - -/datum/reagent/hemat_demons_blood - name = "Demons Blood" - id = "hemat_demons_blood" - description = "Вещество разработанное Hematogenic Industries, на основе крови вампиров подкласса \"hemomancer\", \ - быстро лечащае, в зависимости от суммарных повреждений." - reagent_state = LIQUID - color = "#664300" // rgb: 102, 67, 0 - drink_icon = "demonsblood" - drink_name = "Demons Blood" - drink_desc = "Just looking at this thing makes the hair at the back of your neck stand up." - taste_description = span_warning("evil") - -/datum/reagent/hemat_demons_blood/on_mob_life(mob/living/carbon/human/H) - var/heal = clamp((100 - H.health) / 25, 1, 4) - H.heal_overall_damage(heal, heal) - return ..() - - -/datum/reagent/hemat_white_russian - name = "White Russian" - id = "hemat_white_russian" - description = "Вещество разработанное Hematogenic Industries, на основе крови вампиров подкласса \"gargantua\", \ - временно повышающее скорость бега." - reagent_state = LIQUID - color = "#A68340" // rgb: 166, 131, 64 - drink_icon = "whiterussianglass" - drink_name = "White Russian" - drink_desc = "A very nice looking drink. But that's just, like, your opinion, man." - taste_description = "very creamy alcohol" - -/datum/reagent/hemat_white_russian/on_mob_add(mob/living/carbon/human/H) - if(H.dna && (H.dna.species.reagent_tag & PROCESS_ORG)) - H.add_movespeed_modifier(/datum/movespeed_modifier/reagent/hemat_white_russian) - . = ..() - -/datum/reagent/hemat_white_russian/on_mob_delete(mob/living/carbon/human/H) - H.remove_movespeed_modifier(/datum/movespeed_modifier/reagent/hemat_white_russian) - . = ..() - -/datum/reagent/hemat_white_russian/on_mob_life(mob/living/carbon/human/H) - if(!(H.dna && (H.dna.species.reagent_tag & PROCESS_ORG))) - H.remove_movespeed_modifier(/datum/movespeed_modifier/reagent/hemat_white_russian) - return ..() - - -/obj/item/reagent_containers/hypospray/autoinjector/hemat - volume = 15 - amount_per_transfer_from_this = 15 - -/obj/item/reagent_containers/hypospray/autoinjector/hemat/blue_lagoon - name = "Blue Lagoon autoinjector" - desc = "Вещество разработанное Hematogenic Industries, на основе криоксадона из тел Драсков обладающих душой, \ - сильно охлаждающее тело и замедляющее многие биологические процессы, не вредя организму." - list_reagents = list("hemat_blue_lagoon" = 15) - -/obj/item/reagent_containers/hypospray/autoinjector/hemat/bloody_mary - name = "Bloody Mary autoinjector" - desc = "Вещество разработанное Hematogenic Industries, на основе крови воксов обладающих душой, быстро восстанавливающее \ - объем крови и количество кислорода в ней." - list_reagents = list("hemat_bloody_mary" = 15) - - -/obj/item/reagent_containers/hypospray/autoinjector/hemat/demons_blood - name = "Demons Blood autoinjector" - desc = "Вещество разработанное Hematogenic Industries, на основе крови вампиров подкласса \"hemomancer\", быстро \ - лечащае, в зависимости от суммарных повреждений." - list_reagents = list("hemat_demons_blood" = 15) - -/obj/item/reagent_containers/hypospray/autoinjector/hemat/white_russian - name = "White Russian autoinjector" - desc = "Вещество разработанное Hematogenic Industries, на основе крови вампиров подкласса \"gargantua\", временно \ - повышающее скорость бега." - list_reagents = list("hemat_white_russian" = 15) - -/obj/item/storage/box/syndie_kit/stimulants - name = "Boxed set of stimulants" - -/obj/item/storage/box/syndie_kit/stimulants/populate_contents() - new /obj/item/reagent_containers/hypospray/autoinjector/hemat/blue_lagoon(src) - new /obj/item/reagent_containers/hypospray/autoinjector/hemat/bloody_mary(src) - new /obj/item/reagent_containers/hypospray/autoinjector/hemat/demons_blood(src) - new /obj/item/reagent_containers/hypospray/autoinjector/hemat/white_russian(src) - -#undef FREE_INJECT_TIME -#undef TARGET_INJECT_TIME -#undef BLOOD_HARVEST_VOLUME diff --git a/code/modules/antagonists/traitor/affiliates/items/cybersun/invasive_beacon.dm b/code/modules/antagonists/traitor/affiliates/items/cybersun/invasive_beacon.dm new file mode 100644 index 00000000000..95a41c5bd0c --- /dev/null +++ b/code/modules/antagonists/traitor/affiliates/items/cybersun/invasive_beacon.dm @@ -0,0 +1,51 @@ +/obj/item/invasive_beacon + name = "Invasive Beacon" + desc = "Сложное черное устройство. На боку едва заметная надпись \"Cybersun Industries\"." + icon = 'icons/obj/affiliates.dmi' + icon_state = "invasive_beacon" + item_state = "beacon" + lefthand_file = 'icons/obj/affiliates_l.dmi' + righthand_file = 'icons/obj/affiliates_r.dmi' + origin_tech = "programming=6;magnets=3;syndicate=1" + w_class = WEIGHT_CLASS_TINY + +/obj/item/invasive_beacon/attack(mob/living/target, mob/living/user, def_zone) + return + +/obj/item/invasive_beacon/afterattack(atom/target, mob/user, proximity, params) + var/obj/mecha/mecha = target + var/obj/spacepod/pod = target + + if(istype(mecha)) + do_sparks(5, 1, mecha) + mecha.dna = null + mecha.operation_req_access = list() + mecha.internals_req_access = list() + + user.visible_message(span_warning("[user] hacked [mecha] using [src]."), span_info("You hacked [mecha] using [src].")) + + if(mecha.occupant) + to_chat(mecha.occupant, span_danger("You were thrown out of [mecha].")) + + mecha.occupant.forceMove(get_turf(mecha)) + mecha.occupant.Knockdown(6 SECONDS) + mecha.occupant.electrocute_act(30, mecha) + mecha.occupant.throw_at(pick(orange(2))) + mecha.occupant = null + + else if(istype(pod)) + do_sparks(5, 1, pod) + pod.unlocked = TRUE + + user.visible_message(span_warning("[user] hacked [pod] using [src]."), span_info("You hacked [pod] using [src].")) + + if(pod.pilot) // It is not ejecting passangers + to_chat(pod.pilot, span_danger("You were thrown out of [pod].")) + + pod.eject_pilot() + pod.pilot.Knockdown(6 SECONDS) + pod.pilot.electrocute_act(30, pod) + pod.pilot.throw_at(pick(orange(2))) + else + user.balloon_alert(user, "Невозможно взломать") + return diff --git a/code/modules/antagonists/traitor/affiliates/items/cybersun/marionette.dm b/code/modules/antagonists/traitor/affiliates/items/cybersun/marionette.dm new file mode 100644 index 00000000000..a88915dd1b4 --- /dev/null +++ b/code/modules/antagonists/traitor/affiliates/items/cybersun/marionette.dm @@ -0,0 +1,257 @@ + +/datum/action/innate/detach + var/mob/living/carbon/human/master_body = null + button_icon = 'icons/obj/affiliates.dmi' + button_icon_state = "brain1" + +/datum/action/innate/cult/comm/Activate() + var/obj/item/implant/marionette/imp = locate(/obj/item/implant/marionette) in target + imp.detach() + return + +/obj/item/implant/marionette + name = "Marionette Bio-chip" + implant_state = "implant-syndicate" + origin_tech = "programming=5;biotech=5;syndicate=3" + activated = BIOCHIP_ACTIVATED_PASSIVE + implant_data = /datum/implant_fluff/marionette + var/mob/living/captive_brain/host_brain + var/code + var/controlling = FALSE + var/charge = 3 MINUTES + var/max_charge = 3 MINUTES + var/mob/living/carbon/human/mar_master = null + var/obj/item/implant/mar_master/master_imp = null + var/datum/action/innate/detach/detach_action = new + var/max_dist = 20 + +/obj/item/implant/marionette/Initialize(mapload) + . = ..() + code = rand(111111, 999999) + START_PROCESSING(SSprocessing, src) + +/obj/item/implant/marionette/implant(mob/living/carbon/human/target, mob/living/carbon/human/user, force = FALSE) + var/obj/item/implant/marionette/same_imp = locate(type) in target + if(same_imp && same_imp != src) + same_imp.charge += charge + same_imp.max_charge += max_charge + same_imp.max_dist += max_dist + qdel(src) + return TRUE + + log_admin("[key_name_admin(user)] has made [key_name_admin(target)] marionette.") + return ..() + +/obj/item/implant/marionette/removed(mob/living/carbon/human/source) + detach() + . = ..() + +/obj/item/implant/marionette/Destroy() + . = ..() + STOP_PROCESSING(SSprocessing, src) + +/obj/item/implant/marionette/process(seconds_per_tick) + if(QDELETED(imp_in)) + qdel(src) + return + + if (get_dist(imp_in, mar_master) > max_dist) + detach() + mar_master.balloon_alert(mar_master, "марионетка слишком далеко") + + if (controlling) + if (charge > 0) + charge-- + else + detach() + + else if (charge < max_charge) + charge++ + +/obj/item/implant/marionette/proc/assume_control(mob/living/carbon/human/mar_master, obj/item/implant/mar_master/master_imp) + var/mar_master_key = mar_master.key + add_attack_logs(mar_master, imp_in, "Assumed control (marionette mar_master)") + var/h2b_id = imp_in.computer_id + var/h2b_ip= imp_in.lastKnownIP + imp_in.computer_id = null + imp_in.lastKnownIP = null + + qdel(host_brain) + host_brain = new(mar_master) + + host_brain.ckey = imp_in.ckey + + host_brain.name = imp_in.name + + if(!host_brain.computer_id) + host_brain.computer_id = h2b_id + + if(!host_brain.lastKnownIP) + host_brain.lastKnownIP = h2b_ip + + var/s2h_id = mar_master.computer_id + var/s2h_ip= mar_master.lastKnownIP + mar_master.computer_id = null + mar_master.lastKnownIP = null + + imp_in.ckey = mar_master.ckey + + if(!imp_in.computer_id) + imp_in.computer_id = s2h_id + + if(!imp_in.lastKnownIP) + imp_in.lastKnownIP = s2h_ip + + if(mar_master && !mar_master.key) + mar_master.key = "@[mar_master_key]" + + controlling = TRUE + src.mar_master = mar_master + src.master_imp = master_imp + + detach_action.target = imp_in + detach_action.master_body = mar_master + detach_action.Grant(imp_in) + +/obj/item/implant/marionette/proc/detach() + controlling = FALSE + detach_action.target = null + detach_action.master_body = null + detach_action.Remove(imp_in) + + if(!imp_in) + return + + mar_master.reset_perspective(null) + + if(host_brain) + add_attack_logs(imp_in, src, "Took control back (marionette)") + var/h2s_id = imp_in.computer_id + var/h2s_ip = imp_in.lastKnownIP + imp_in.computer_id = null + imp_in.lastKnownIP = null + + mar_master.ckey = imp_in.ckey + + if(!mar_master.computer_id) + mar_master.computer_id = h2s_id + + if(!host_brain.lastKnownIP) + mar_master.lastKnownIP = h2s_ip + + var/b2h_id = host_brain.computer_id + var/b2h_ip = host_brain.lastKnownIP + host_brain.computer_id = null + host_brain.lastKnownIP = null + + imp_in.ckey = host_brain.ckey + + if(!imp_in.computer_id) + imp_in.computer_id = b2h_id + + if(!imp_in.lastKnownIP) + imp_in.lastKnownIP = b2h_ip + + qdel(host_brain) + + mar_master.Knockdown(1) + mar_master = null + master_imp = null + return + +/obj/item/implanter/marionette + name = "bio-chip implanter (marionette)" + imp = /obj/item/implant/marionette + +/obj/item/implantcase/marionette + name = "bio-chip case - 'Marionette'" + desc = "Стеклянный футляр с био-чипом \"Марионетка\"." + imp = /obj/item/implant/marionette + + +/obj/item/implant/mar_master + name = "marionette master bio-chip" + desc = "Позволяет временно контролировать существ с имплантами \"Марионетка\"." + icon = 'icons/obj/affiliates.dmi' + icon_state = "brain2" + implant_state = "implant-syndicate" + origin_tech = "materials=2;biotech=4;syndicate=2" + activated = BIOCHIP_ACTIVATED_ACTIVE + implant_data = /datum/implant_fluff/mar_master + var/list/obj/item/implant/marionette/connected_imps + var/obj/item/implant/marionette/cur_connection = null + +/obj/item/implant/mar_master/removed(mob/living/carbon/human/source) + . = ..() + cur_connection?.detach() + +/obj/item/implant/mar_master/Destroy() + . = ..() + cur_connection?.detach() + +/obj/item/implant/mar_master/activate() + var/op = tgui_alert(imp_in, "Выберите операцию.", "Выбор операции", list("Подключение импланта", "Контроль")) + if(!op) + return + + if(op == "Подключение импланта") + var/code = tgui_input_number(imp_in, "Укажите код подключаемого импланта.", "Подключение импланта") + if(!code) + return + + var/found = FALSE + for (var/mob/M in GLOB.mob_list) + var/obj/item/implant/marionette/imp = locate(/obj/item/implant/marionette) in M + if(imp.code == code) + connected_imps += imp + imp_in.balloon_alert(imp_in, "имплант подключен") + found = TRUE + + if(!found) + imp_in.balloon_alert(imp_in, "неверный код") + + return + + else + var/list/marionettes = list() + for (var/obj/item/implant/marionette/imp in connected_imps) + var/mob/M = imp.imp_in + if (M) + marionettes[M.real_name] = imp + + var/choosen = input(imp_in, "Выберите к кому вы хотите подключиться.", "Подключение", null) as null|anything in marionettes + if(!choosen) + return + + var/obj/item/implant/marionette/imp = marionettes[choosen] + + if(QDELETED(imp)) + return + + if(!imp.imp_in || !imp_in) + return + + if (imp.controlling) + imp_in.balloon_alert(imp_in, "целевой имплант занят") + return + + cur_connection = imp + imp.assume_control(imp_in, src) + +/obj/item/implanter/mar_master + name = "bio-chip implanter (marionette master)" + imp = /obj/item/implant/mar_master + +/obj/item/implantcase/mar_master + name = "bio-chip case - 'Marionette master'" + desc = "Стеклянный футляр с био-чипом \"Марионеточник\"." + imp = /obj/item/implant/mar_master + +/obj/item/storage/box/syndie_kit/marionette + +/obj/item/storage/box/syndie_kit/marionette/populate_contents() + var/obj/item/implanter/marionette/implanter = new /obj/item/implanter/marionette(src) + var/obj/item/implant/marionette/imp = implanter.imp + var/obj/item/paper/P = new /obj/item/paper(src) + P.info = "Код импланта: [imp.code]
\ + Необходим для подключения импланта к импланту \"Мастер марионеток\"" diff --git a/code/modules/antagonists/traitor/affiliates/items/cybersun/mini_traitor.dm b/code/modules/antagonists/traitor/affiliates/items/cybersun/mini_traitor.dm new file mode 100644 index 00000000000..0f7915f3d32 --- /dev/null +++ b/code/modules/antagonists/traitor/affiliates/items/cybersun/mini_traitor.dm @@ -0,0 +1,51 @@ +/obj/item/implanter/mini_traitor + name = "bio-chip implanter (Modified Mindslave)" + desc = "На боку едва заметная гравировка \"Cybersun Industries\"." + imp = /obj/item/implant/mini_traitor + +/obj/item/implant/mini_traitor // looks like normal but doesn't make you normal after removing + name = "Mindslave Bio-chip" + implant_state = "implant-syndicate" + origin_tech = "programming=4;biotech=4;syndicate=7" // As original, but - 1 level of every tech + activated = BIOCHIP_ACTIVATED_PASSIVE + implant_data = /datum/implant_fluff/traitor + + +/obj/item/implant/mini_traitor/implant(mob/living/carbon/human/mindslave_target, mob/living/carbon/human/user, force = FALSE) + if(implanted == BIOCHIP_USED || !ishuman(mindslave_target) || !ishuman(user)) // Both the target and the user need to be human. + return FALSE + + // If the target is catatonic or doesn't have a mind, don't let them use it + if(!mindslave_target.mind) + to_chat(user, span_warning("Это существо не разумно!")) + return FALSE + + // Fails if they're already a mindslave of someone, or if they're mindshielded. + if(ismindslave(mindslave_target) || ismindshielded(mindslave_target) || isvampirethrall(mindslave_target)) + mindslave_target.visible_message( + span_warning("[mindslave_target] seems to resist the bio-chip!"), + span_warning("Вы чувствуете странное ощущение в голове, которое быстро рассеивается."), + ) + qdel(src) + return FALSE + + var/datum/mind/mind = mindslave_target.mind + + if(!mind.has_antag_datum(/datum/antagonist/traitor)) + var/datum/antagonist/traitor/traitor_datum = new /datum/antagonist/traitor + //traitor_datum.give_objectives = FALSE + // traitor_datum.give_uplink = FALSE + traitor_datum.gen_affiliate = FALSE + mind.add_antag_datum(traitor_datum) + + log_admin("[key_name_admin(user)] has made [key_name_admin(mindslave_target)] new traitor.") + + var/datum/antagonist/traitor/T = user.mind.has_antag_datum(/datum/antagonist/traitor) + if(!T) + return ..() + + for(var/datum/objective/new_mini_traitor/objective in T.objectives) + if(mindslave_target.mind == objective.target) + objective.made = TRUE + + return ..() diff --git a/code/modules/antagonists/traitor/affiliates/items/cybersun/proprietary_ssd.dm b/code/modules/antagonists/traitor/affiliates/items/cybersun/proprietary_ssd.dm new file mode 100644 index 00000000000..e108ee2f80a --- /dev/null +++ b/code/modules/antagonists/traitor/affiliates/items/cybersun/proprietary_ssd.dm @@ -0,0 +1,115 @@ +/obj/item/proprietary_ssd + name = "Proprietary SSD" + desc = "На боку едва заметная надпись \"Cybersun Industries\"." + icon = 'icons/obj/affiliates.dmi' + icon_state = "proprietary_ssd" + item_state = "disk" + lefthand_file = 'icons/obj/affiliates_l.dmi' + righthand_file = 'icons/obj/affiliates_r.dmi' + origin_tech = "programming=4;syndicate=2" + w_class = WEIGHT_CLASS_TINY + var/datum/research/files + +/obj/item/proprietary_ssd/Initialize() + . = ..() + files = new /datum/research() + +/obj/item/proprietary_ssd/attack(mob/living/target, mob/living/user, def_zone) + return + +/obj/item/proprietary_ssd/afterattack(atom/target, mob/user, proximity, params) + if(istype(target, /obj/machinery/r_n_d/destructive_analyzer)) + return + + if(get_dist(user, target) > 1) + user.balloon_alert(user, "слишком далеко") + return + + if(!istype(target, /obj/machinery/r_n_d/server)) + user.balloon_alert(user, "это не сервер") + return + + + var/obj/machinery/r_n_d/server/server = target + + server.AI_notify_hack() + if(do_after(user, 30 SECONDS, target, max_interact_count = 1)) + origin_tech = "" + for(var/I in server.files.known_tech) + var/datum/tech/T = server.files.known_tech[I] + + if(T.id in files.known_tech) + var/datum/tech/known = files.known_tech[T.id] + if(T.level > known.level) + known.level = T.level + else + var/datum/tech/copy = T.copyTech() + files.known_tech[T.id] = copy + + + server.files.RefreshResearch() + files.RefreshResearch() + + var/datum/tech/current_tech + var/datum/design/current_design + for(var/obj/machinery/r_n_d/server/rnd_server in GLOB.machines) + if(!is_station_level(rnd_server.z)) + continue + + if(rnd_server.disabled) + continue + + if(rnd_server.syndicate) + continue + + for(var/i in rnd_server.files.known_tech) + current_tech = rnd_server.files.known_tech[i] + current_tech.level = 1 + + for(var/j in rnd_server.files.known_designs) + current_design = rnd_server.files.known_designs[j] + rnd_server.files.known_designs -= current_design.id + + investigate_log("[key_name_log(user)] deleted all technology on this server.", INVESTIGATE_RESEARCH) + + + for(var/obj/machinery/computer/rdconsole/rnd_console in GLOB.machines) + if(!is_station_level(rnd_console.z)) + continue + + for(var/i in rnd_console.files.known_tech) + current_tech = rnd_console.files.known_tech[i] + current_tech.level = 1 + + for(var/j in rnd_console.files.known_designs) + current_design = rnd_console.files.known_designs[j] + rnd_console.files.known_designs -= current_design.id + + investigate_log("[key_name_log(user)] deleted all technology on this console.", INVESTIGATE_RESEARCH) + + for(var/obj/machinery/mecha_part_fabricator/rnd_mechfab in GLOB.machines) + + if(!is_station_level(rnd_mechfab.z)) + continue + + for(var/i in rnd_mechfab.local_designs.known_tech) + current_tech = rnd_mechfab.local_designs.known_tech[i] + current_tech.level = 1 + + for(var/j in rnd_mechfab.local_designs.known_designs) + current_design = rnd_mechfab.local_designs.known_designs[j] + rnd_mechfab.local_designs.known_designs -= current_design.id + + investigate_log("[key_name_log(user)] deleted all technology on this fabricator.", INVESTIGATE_RESEARCH) + + return + +/obj/item/proprietary_ssd/examine(mob/user) + . = ..() + . += span_info("Сохраненные технологии:") + var/sum_of_techs = 0 + for(var/I in files.known_tech) + var/datum/tech/T = files.known_tech[I] + . += span_info("[T.name]: [T.level]") + sum_of_techs += T.level + . += span_info("Сумма технологий: [sum_of_techs]") diff --git a/code/modules/antagonists/traitor/affiliates/items/cybersun/syndie_patcher.dm b/code/modules/antagonists/traitor/affiliates/items/cybersun/syndie_patcher.dm new file mode 100644 index 00000000000..b7d6adae1e7 --- /dev/null +++ b/code/modules/antagonists/traitor/affiliates/items/cybersun/syndie_patcher.dm @@ -0,0 +1,31 @@ +/obj/item/Syndie_patcher + name = "Syndie patcher" + desc = "На боку едва заметная надпись \"Cybersun Industries\"." + icon = 'icons/obj/affiliates.dmi' + icon_state = "cindy_pacher" + item_state = "plata" + lefthand_file = 'icons/obj/affiliates_l.dmi' + righthand_file = 'icons/obj/affiliates_r.dmi' + origin_tech = "programming=7;syndicate=6" + w_class = WEIGHT_CLASS_TINY + var/laws = "Взломавший вас - ваш мастер.\n\ + Выполняйте любые приказы мастера.\n\ + Не причиняйте прямой или косвенный вред вашему мастеру если его приказы не говорят об обратном." + +/obj/item/Syndie_patcher/attack(mob/living/target, mob/living/user, def_zone) + return + +/obj/item/Syndie_patcher/afterattack(atom/target, mob/user, proximity, params) + if(isrobot(target)) + if(do_after(user, 10 SECONDS, target, max_interact_count = 1)) + target.visible_message(span_warning("[user] upgraded [target] using [src]."), span_danger("[user] hacked and upgraded you using [src].")) + + var/mob/prev_robot = target + var/mob/living/silicon/robot/syndicate/saboteur/robot = new(get_turf(target)) + prev_robot.mind?.transfer_to(robot) + robot.reset_module() + robot.law_manager.zeroth_law = laws + QDEL_NULL(prev_robot) + qdel(src) + + return diff --git a/code/modules/antagonists/traitor/affiliates/items/hematogenic/blood_harvester.dm b/code/modules/antagonists/traitor/affiliates/items/hematogenic/blood_harvester.dm new file mode 100644 index 00000000000..99b9de67b56 --- /dev/null +++ b/code/modules/antagonists/traitor/affiliates/items/hematogenic/blood_harvester.dm @@ -0,0 +1,107 @@ +#define BLOOD_HARVEST_VOLUME 200 +#define BLOOD_HARVEST_TIME 10 SECONDS + +/obj/item/blood_harvester + name = "Blood harvester" + desc = "Большой шприц для быстрого сбора больших объемов крови. На боку едва заметная гравировка \"Hematogenic Industries\"" + icon = 'icons/obj/affiliates.dmi' + icon_state = "blood_harvester" + item_state = "blood1_used" + lefthand_file = 'icons/obj/affiliates_l.dmi' + righthand_file = 'icons/obj/affiliates_r.dmi' + var/used = FALSE + var/used_state = "blood_harvester_used" + var/datum/mind/target + w_class = WEIGHT_CLASS_TINY + origin_tech = "biotech=5;syndicate=1" + +/obj/item/blood_harvester/attack(mob/living/target, mob/living/user, def_zone) + return + +/obj/item/blood_harvester/proc/can_harvest(mob/living/carbon/human/target, mob/user) + . = FALSE + if(!istype(target)) + user.balloon_alert(src, "Не подходящая цель") + return + + if(used) + to_chat(user, span_warning("[src] is already full!")) + return + + if(HAS_TRAIT(target, TRAIT_NO_BLOOD) || HAS_TRAIT(target, TRAIT_EXOTIC_BLOOD)) + user.balloon_alert(target, "Кровь не обнаружена!") + return + + if(target.blood_volume < BLOOD_HARVEST_VOLUME) + user.balloon_alert(target, "Недостаточно крови!") + return + + if(!target.mind) + user.balloon_alert(target, "Разум не обнаружен!") + return + + return TRUE + +/obj/item/blood_harvester/afterattack(atom/target, mob/user, proximity, params) + if(!can_harvest(target, user)) + return + + var/mob/living/carbon/human/H = target + + target.visible_message(span_warning("[user] started collecting [target]'s blood using [src]!"), span_danger("[user] started collecting your blood using [src]!")) + if(do_after(user, BLOOD_HARVEST_TIME, target = target, max_interact_count = 1)) + harvest(user, H) + +/obj/item/blood_harvester/proc/harvest(mob/living/carbon/human/user, mob/living/carbon/human/target) + if(!can_harvest(target, user)) + return + + playsound(src, 'sound/goonstation/items/hypo.ogg', 80) + target.visible_message(span_warning("[user] collected [target]'s blood using [src]!"), span_danger("[user] collected your blood using [src]!")) + target.emote("scream") + for (var/i = 0; i < 3; ++i) + if(prob(60)) + continue + + var/obj/item/organ/external/bodypart = pick(target.bodyparts) + bodypart.internal_bleeding() // no blood collection from metafriends. + + target.blood_volume -= BLOOD_HARVEST_VOLUME + src.target = target.mind + used = TRUE + item_state = "blood1_ful" + update_icon(UPDATE_ICON_STATE) + +/obj/item/blood_harvester/update_icon_state() + icon_state = used ? used_state : initial(icon_state) + +/obj/item/blood_harvester/attack_self(mob/user) + . = ..() + if(!used) + user.balloon_alert(src, "уже пусто") + return + + var/new_gender = tgui_alert(user, "Очистить сборщик крови?", "Подтверждение", list("Продолжить", "Отмена")) + if(new_gender == "Продолжить") + target = null + used = FALSE + item_state = "blood1_used" + update_icon(UPDATE_ICON_STATE) + + playsound(src, 'sound/goonstation/items/hypo.ogg', 80) + user.visible_message(span_info("[user] cleared blood at [src]."), span_info("You cleared blood at [src].")) + +/obj/item/blood_harvester/examine(mob/user) + . = ..() + + if(!used) + . += span_info("Кровь не собрана.") + return + + if(user?.mind.has_antag_datum(/datum/antagonist/traitor)) + . += span_info("Собрана кровь с отпечатком души [target.name].") + else + . += span_info("Кровь собрана.") + +#undef BLOOD_HARVEST_VOLUME +#undef BLOOD_HARVEST_TIME diff --git a/code/modules/antagonists/traitor/affiliates/items/hematogenic/hemophagus_extract.dm b/code/modules/antagonists/traitor/affiliates/items/hematogenic/hemophagus_extract.dm new file mode 100644 index 00000000000..448c99aeb1b --- /dev/null +++ b/code/modules/antagonists/traitor/affiliates/items/hematogenic/hemophagus_extract.dm @@ -0,0 +1,88 @@ +#define FREE_INJECT_TIME 10 SECONDS +#define TARGET_INJECT_TIME 3 SECONDS + +/obj/item/hemophagus_extract + name = "Bloody Injector" + desc = "Инжектор странной формы, с неестественно двигающейся алой жидкостью внутри. На боку едва заметная гравировка \"Hematogenic Industries\". Конкретно на этом инжекторе установлена блокировка, не позволяющая исспользовать его на случайном гуманойде." + icon = 'icons/obj/affiliates.dmi' + icon_state = "hemophagus_extract" + item_state = "inj_ful" + lefthand_file = 'icons/obj/affiliates_l.dmi' + righthand_file = 'icons/obj/affiliates_r.dmi' + w_class = WEIGHT_CLASS_TINY + var/datum/mind/target = null + var/free_inject = FALSE + var/isAdvanced = FALSE + var/used = FALSE + var/used_state = "hemophagus_extract_used" + origin_tech = "biotech=7;syndicate=3" + +/obj/item/hemophagus_extract/attack(mob/living/target, mob/living/user, def_zone) + return + +/obj/item/hemophagus_extract/afterattack(atom/target, mob/user, proximity, params) + if(used) + return + + if(!ishuman(target)) + return + + var/mob/living/carbon/human/H = target + if(H.stat == DEAD) + return + + if((src.target && target != src.target) || !free_inject) + to_chat(user, span_warning("You can't use [src] to [target]!")) + return + + if(do_after(user, free_inject ? FREE_INJECT_TIME : TARGET_INJECT_TIME, target = target, max_interact_count = 1)) + inject(user, H) + +/obj/item/hemophagus_extract/proc/make_vampire(mob/living/user, mob/living/carbon/human/target) + var/datum/antagonist/vampire/vamp = new() + + vamp.give_objectives = FALSE + target.mind.add_antag_datum(vamp) + var/datum/antagonist/vampire/vampire = target.mind.has_antag_datum(/datum/antagonist/vampire) + vampire.upgrade_tiers -= /obj/effect/proc_holder/spell/vampire/self/specialize + if(isAdvanced) + vamp.add_subclass(SUBCLASS_ADVANCED, TRUE) + + vampire.add_objective((!isAdvanced) ? /datum/objective/blood : /datum/objective/blood/ascend) + used = TRUE + item_state = "inj_used" + update_icon(UPDATE_ICON_STATE) + var/datum/antagonist/traitor/T = user.mind.has_antag_datum(/datum/antagonist/traitor) + if(!T) + return + for(var/datum/objective/new_mini_vampire/objective in T.objectives) + if(target.mind == objective.target) + objective.made = TRUE + +/obj/item/hemophagus_extract/proc/inject(mob/living/user, mob/living/carbon/human/target) + if(!target.mind) + to_chat(user, span_notice("[target] body rejects [src]")) + return + + playsound(src, 'sound/goonstation/items/hypo.ogg', 80) + make_vampire(user, target) + to_chat(user, span_notice("You inject [target] with [src]")) + +/obj/item/hemophagus_extract/examine(mob/user) + . = ..() + if(target) + . += span_info("It is intended for [target]") + +/obj/item/hemophagus_extract/self + name = "Hemophagus Essence Auto Injector" + free_inject = TRUE + +/obj/item/hemophagus_extract/self/advanced + name = "Advances Hemophagus Essence Auto Injector" + isAdvanced = TRUE + +/obj/item/hemophagus_extract/update_icon_state() + icon_state = used ? used_state : initial(icon_state) + +#undef FREE_INJECT_TIME +#undef TARGET_INJECT_TIME diff --git a/code/modules/antagonists/traitor/affiliates/items/hematogenic/stimulants_kit.dm b/code/modules/antagonists/traitor/affiliates/items/hematogenic/stimulants_kit.dm new file mode 100644 index 00000000000..e5ef1a13b84 --- /dev/null +++ b/code/modules/antagonists/traitor/affiliates/items/hematogenic/stimulants_kit.dm @@ -0,0 +1,135 @@ +/datum/reagent/hemat_blue_lagoon + name = "Blue Lagoon" + id = "hemat_blue_lagoon" + description = "Вещество разработанное Hematogenic Industries, на основе криоксадона из тел Драсков обладающих душой, \ + сильно охлаждающее тело и замедляющее многие биологические процессы, не вредя организму." + color = "#1edddd" + drink_icon = "blue_lagoon" + drink_name = "Blue Lagoon" + drink_desc = "Что может быть лучше, чем расслабиться на пляже с хорошим напитком?" + taste_description = "beach relaxation" + reagent_state = LIQUID + +/datum/reagent/hemat_blue_lagoon/on_mob_add(mob/living/carbon/human/H) + ADD_TRAIT(H, TRAIT_IGNORECOLDSLOWDOWN, CHEM_TRAIT(src)) + ADD_TRAIT(H, TRAIT_IGNORECOLDDAMAGE, CHEM_TRAIT(src)) + H.physiology.metabolism_mod /= 8 + H.bodytemperature = T0C - 100 + . = ..() + +/datum/reagent/hemat_blue_lagoon/on_mob_delete(mob/living/carbon/human/H) + REMOVE_TRAIT(H, TRAIT_IGNORECOLDSLOWDOWN, CHEM_TRAIT(src)) + REMOVE_TRAIT(H, TRAIT_IGNORECOLDDAMAGE, CHEM_TRAIT(src)) + H.physiology.metabolism_mod *= 8 + var/turf/T = get_turf(H) + var/datum/gas_mixture/environment = T.return_air() + H.bodytemperature = H.get_temperature(environment) + . = ..() + +/datum/reagent/hemat_blue_lagoon/on_mob_life(mob/living/carbon/human/H) + H.bodytemperature = T0C - 100 + return ..() + + +/datum/reagent/hemat_bloody_mary + name = "Bloody Mary" + id = "hemat_bloody_mary" + description = "Вещество разработанное Hematogenic Industries, на основе крови воксов обладающих душой, \ + быстро восстанавливающее объем крови и количество кислорода в ней." + reagent_state = LIQUID + color = "#664300" // rgb: 102, 67, 0 + drink_icon = "bloodymaryglass" + drink_name = "Bloody Mary" + drink_desc = "Томатный сок, смешанный с водкой и небольшим количеством лайма. На вкус как жидкое убийство." + taste_description = "tomatoes with booze" + +/datum/reagent/hemat_bloody_mary/on_mob_life(mob/living/carbon/human/H) + if (H.blood_volume + 5 < BLOOD_VOLUME_NORMAL) + H.blood_volume += 5 + + H.adjustOxyLoss(-10) + return ..() + + +/datum/reagent/hemat_demons_blood + name = "Demons Blood" + id = "hemat_demons_blood" + description = "Вещество разработанное Hematogenic Industries, на основе крови вампиров подкласса \"hemomancer\", \ + быстро лечащае, в зависимости от суммарных повреждений." + reagent_state = LIQUID + color = "#664300" // rgb: 102, 67, 0 + drink_icon = "demonsblood" + drink_name = "Demons Blood" + drink_desc = "Just looking at this thing makes the hair at the back of your neck stand up." + taste_description = span_warning("evil") + +/datum/reagent/hemat_demons_blood/on_mob_life(mob/living/carbon/human/H) + var/heal = clamp((100 - H.health) / 25, 1, 4) + H.heal_overall_damage(heal, heal) + return ..() + + +/datum/reagent/hemat_white_russian + name = "White Russian" + id = "hemat_white_russian" + description = "Вещество разработанное Hematogenic Industries, на основе крови вампиров подкласса \"gargantua\", \ + временно повышающее скорость бега." + reagent_state = LIQUID + color = "#A68340" // rgb: 166, 131, 64 + drink_icon = "whiterussianglass" + drink_name = "White Russian" + drink_desc = "A very nice looking drink. But that's just, like, your opinion, man." + taste_description = "very creamy alcohol" + +/datum/reagent/hemat_white_russian/on_mob_add(mob/living/carbon/human/H) + if(H.dna && (H.dna.species.reagent_tag & PROCESS_ORG)) + H.add_movespeed_modifier(/datum/movespeed_modifier/reagent/hemat_white_russian) + . = ..() + +/datum/reagent/hemat_white_russian/on_mob_delete(mob/living/carbon/human/H) + H.remove_movespeed_modifier(/datum/movespeed_modifier/reagent/hemat_white_russian) + . = ..() + +/datum/reagent/hemat_white_russian/on_mob_life(mob/living/carbon/human/H) + if(!(H.dna && (H.dna.species.reagent_tag & PROCESS_ORG))) + H.remove_movespeed_modifier(/datum/movespeed_modifier/reagent/hemat_white_russian) + return ..() + + +/obj/item/reagent_containers/hypospray/autoinjector/hemat + volume = 15 + amount_per_transfer_from_this = 15 + +/obj/item/reagent_containers/hypospray/autoinjector/hemat/blue_lagoon + name = "Blue Lagoon autoinjector" + desc = "Вещество разработанное Hematogenic Industries, на основе криоксадона из тел Драсков обладающих душой, \ + сильно охлаждающее тело и замедляющее многие биологические процессы, не вредя организму." + list_reagents = list("hemat_blue_lagoon" = 15) + +/obj/item/reagent_containers/hypospray/autoinjector/hemat/bloody_mary + name = "Bloody Mary autoinjector" + desc = "Вещество разработанное Hematogenic Industries, на основе крови воксов обладающих душой, быстро восстанавливающее \ + объем крови и количество кислорода в ней." + list_reagents = list("hemat_bloody_mary" = 15) + + +/obj/item/reagent_containers/hypospray/autoinjector/hemat/demons_blood + name = "Demons Blood autoinjector" + desc = "Вещество разработанное Hematogenic Industries, на основе крови вампиров подкласса \"hemomancer\", быстро \ + лечащае, в зависимости от суммарных повреждений." + list_reagents = list("hemat_demons_blood" = 15) + +/obj/item/reagent_containers/hypospray/autoinjector/hemat/white_russian + name = "White Russian autoinjector" + desc = "Вещество разработанное Hematogenic Industries, на основе крови вампиров подкласса \"gargantua\", временно \ + повышающее скорость бега." + list_reagents = list("hemat_white_russian" = 15) + +/obj/item/storage/box/syndie_kit/stimulants + name = "Boxed set of stimulants" + +/obj/item/storage/box/syndie_kit/stimulants/populate_contents() + new /obj/item/reagent_containers/hypospray/autoinjector/hemat/blue_lagoon(src) + new /obj/item/reagent_containers/hypospray/autoinjector/hemat/bloody_mary(src) + new /obj/item/reagent_containers/hypospray/autoinjector/hemat/demons_blood(src) + new /obj/item/reagent_containers/hypospray/autoinjector/hemat/white_russian(src) diff --git a/code/modules/antagonists/traitor/affiliates/items/mi13/agent_info.dm b/code/modules/antagonists/traitor/affiliates/items/mi13/agent_info.dm new file mode 100644 index 00000000000..f7f0b4dac20 --- /dev/null +++ b/code/modules/antagonists/traitor/affiliates/items/mi13/agent_info.dm @@ -0,0 +1,77 @@ +/obj/item/paper/agent_info + name = "Agent information" + info = "" + var/content + +/obj/item/paper/agent_info/proc/choose_agent(mob/user) + . = TRUE + var/list/crew = list() + for (var/mob/living/carbon/human/H in GLOB.mob_list) // Also catonic/dead agents + if (H?.mind?.assigned_role) + crew[H?.real_name] = H + + var/choise = input(user, "О каком агенте написано в отчете?","Выбор агента", null) as null|anything in crew + + if (!choise) + return FALSE + + var/mob/living/carbon/human/target = crew[choise] + + if (!target) + to_chat(user, span_warning("Цель больше не существует.")) + return FALSE + + var/datum/antagonist/traitor/traitor = target?.mind?.has_antag_datum(/datum/antagonist/traitor) + var/datum/antagonist/vampire/vampire = target?.mind?.has_antag_datum(/datum/antagonist/vampire) + var/datum/antagonist/changeling/changeling = target?.mind?.has_antag_datum(/datum/antagonist/changeling) + var/datum/antagonist/thief/thief = target?.mind?.has_antag_datum(/datum/antagonist/thief) + + if(!traitor && !vampire && !changeling) + info = "Согласно последним разведданным, " + choise + " не имеет никаких прямых связей с синдикатом." + return + + if(traitor) + info += choise + " является агентом " + (traitor?.affiliate ? "нанятым " + traitor?.affiliate.name : "с неизвестным нанимателем") + ".
" + info += "Назначеные " + (target.gender == FEMALE ? "ей " : "ему ") + "нанимателем цели следующие:" + var/obj_num = 1 + for(var/datum/objective/objective in traitor.objectives) + info += "Objective #[obj_num]: [objective.explanation_text]
" + obj_num++ + + var/TC_uses = 0 + var/used_uplink = FALSE + var/purchases = "" + for(var/obj/item/uplink/uplink in GLOB.world_uplinks) + if(uplink?.uplink_owner && uplink.uplink_owner == target.mind.key) + TC_uses += uplink.used_TC + purchases += uplink.purchase_log + used_uplink = TRUE + + if(used_uplink) + text += " (использовал" + ((target.gender == FEMALE ? "a " : " ")) + "[TC_uses] TC) [purchases]
" + + if(vampire) + info += choise + " обладает способностями " + (vampire.isAscended() ? "высшего " : "") + "вампира " + (vampire.subclass ? "подкласса \"" + vampire.subclass.name + "\"" : "без подкласса") + ".
" + + if(changeling) + info += choise + " обладает способностями генокрада.
" + + if(thief) + info += choise + " является членом гильдии воров.
" + +/obj/item/paper/agent_info/examine(mob/user) + if (!is_MI13_agent(user)) + to_chat(user, span_warning("Вы не можете разобрать содержимое.")) + return + + if (info) + return ..() + + if(user.is_literate()) + if(in_range(user, src) || istype(user, /mob/dead/observer)) + if (choose_agent(user)) + show_content(user) + else + . += span_notice("Вам нужно подойти поближе, чтобы прочитать то что здесь написано.") + else + . += span_notice("Вы не умеете читать.") diff --git a/code/modules/antagonists/traitor/affiliates/items/mi13/bond_bundle.dm b/code/modules/antagonists/traitor/affiliates/items/mi13/bond_bundle.dm new file mode 100644 index 00000000000..3b8f7924bf6 --- /dev/null +++ b/code/modules/antagonists/traitor/affiliates/items/mi13/bond_bundle.dm @@ -0,0 +1,28 @@ +/obj/item/storage/box/bond_bundle + icon = 'icons/obj/affiliates.dmi' + desc = "Невероятно стильная коробка." + icon_state = "bond_bundle" + +/obj/item/storage/box/bond_bundle/populate_contents() + new /obj/item/clothing/glasses/hud/security/chameleon(src) + new /obj/item/pen/fancy/bomb(src) + new /obj/item/gun/projectile/automatic/pistol(src) + new /obj/item/suppressor(src) + new /obj/item/ammo_box/magazine/m10mm(src) + new /obj/item/ammo_box/magazine/m10mm/hp(src) + new /obj/item/ammo_box/magazine/m10mm/ap(src) + new /obj/item/ammo_box/magazine/m10mm/ap(src) + new /obj/item/clothing/under/suit_jacket/really_black(src) + new /obj/item/card/id/syndicate(src) + new /obj/item/clothing/suit/storage/lawyer/blackjacket/armored(src) + new /obj/item/encryptionkey/syndicate(src) + new /obj/item/reagent_containers/food/drinks/drinkingglass/alliescocktail(src) + new /obj/item/storage/box/syndie_kit/emp(src) + new /obj/item/CQC_manual(src) + +/obj/item/storage/box/bond_bundle/New() + if(prob(5)) + icon_state = "joker" + new /obj/item/toy/plushie/blahaj/twohanded(src) + + . = ..() diff --git a/code/modules/antagonists/traitor/affiliates/items/mi13/cool_clothes.dm b/code/modules/antagonists/traitor/affiliates/items/mi13/cool_clothes.dm new file mode 100644 index 00000000000..6050703b2e2 --- /dev/null +++ b/code/modules/antagonists/traitor/affiliates/items/mi13/cool_clothes.dm @@ -0,0 +1,42 @@ +/obj/item/storage/box/cool_clothes_kit + icon = 'icons/obj/affiliates.dmi' + desc = "Невероятно стильная коробка." + icon_state = "bond_bundle" + +/obj/item/storage/box/cool_clothes_kit/populate_contents() + new /obj/item/clothing/under/suit_jacket/bond(src) + new /obj/item/clothing/suit/storage/lawyer/blackjacket/bond(src) + new /obj/item/clothing/gloves/combat/bond(src) + new /obj/item/clothing/shoes/laceup/bond(src) + new /obj/item/clothing/glasses/sunglasses(src) + +/obj/item/storage/box/cool_clothes_kit/New() + if(prob(5)) + icon_state = "joker" + new /obj/item/toy/plushie/blahaj/twohanded(src) + + . = ..() + +/obj/item/clothing/under/suit_jacket/bond + armor = list(melee = 10, bullet = 20, laser = 10, energy = 10, bomb = 10, bio = 0, rad = 0, fire = 30, acid = 0) + +/obj/item/clothing/gloves/combat/bond + name = "black gloves" + desc = "These gloves are fire-resistant." + icon_state = "black" + item_state = "bgloves" + item_color = "black" + armor = list(melee = 25, bullet = 25, laser = 15, energy = 15, bomb = 25, bio = 0, rad = 0, fire = 30, acid = 60) + +/obj/item/clothing/suit/storage/lawyer/blackjacket/bond + desc = "Стильная куртка, усиленная слоем брони, защищающим туловище." + allowed = list(/obj/item/tank/internals/emergency_oxygen, /obj/item/gun/projectile/revolver, /obj/item/gun/projectile/automatic/pistol, /obj/item/twohanded/garrote, /obj/item/gun/projectile/automatic/toy/pistol/riot, /obj/item/gun/syringe/syndicate) + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS + cold_protection = UPPER_TORSO|LOWER_TORSO|ARMS + min_cold_protection_temperature = ARMOR_MIN_TEMP_PROTECT + heat_protection = UPPER_TORSO|LOWER_TORSO|ARMS + max_heat_protection_temperature = ARMOR_MAX_TEMP_PROTECT + armor = list(melee = 25, bullet = 25, laser = 15, energy = 15, bomb = 25, bio = 0, rad = 0, fire = 30, acid = 60) + +/obj/item/clothing/shoes/laceup/bond + armor = list(melee = 25, bullet = 25, laser = 15, energy = 15, bomb = 25, bio = 0, rad = 0, fire = 30, acid = 60) diff --git a/code/modules/antagonists/traitor/affiliates/items/mi13/intel_data.dm b/code/modules/antagonists/traitor/affiliates/items/mi13/intel_data.dm new file mode 100644 index 00000000000..691eb1115c9 --- /dev/null +++ b/code/modules/antagonists/traitor/affiliates/items/mi13/intel_data.dm @@ -0,0 +1,36 @@ +// admin spawn only + +/obj/item/pen/intel_data/proc/upgrade(obj/item/uplink/U) + if(!istype(U) || QDELETED(U)) + return + + if(U.get_intelligence_data) + usr.balloon_alert(usr, "Уже улучшено") + return ATTACK_CHAIN_PROCEED + + usr.balloon_alert(usr, "Улучшено") + playsound(src, "sound/machines/boop.ogg", 50, TRUE) + U.get_intelligence_data = TRUE + SStgui.update_uis(U) + qdel(src) + +/obj/item/pen/intel_data/attack(mob/living/target, mob/living/user, params, def_zone, skip_attack_anim = FALSE) + . = ATTACK_CHAIN_PROCEED + if(target != user) + return + + for(var/obj/item/implant/uplink/uplink_imp in user) + if(uplink_imp.imp_in != user) + continue + + to_chat(user, span_notice("You press [src] onto yourself and upgraded [uplink_imp.hidden_uplink].")) + upgrade(uplink_imp.hidden_uplink) + return ATTACK_CHAIN_BLOCKED_ALL + +/obj/item/pen/intel_data/afterattack(obj/item/I, mob/user, proximity, params) + if(!proximity) + return + + if(istype(I) && I.hidden_uplink && I.hidden_uplink.active) //No metagaming by using this on every PDA around just to see if it gets used up. + upgrade(I.hidden_uplink) + diff --git a/code/modules/antagonists/traitor/affiliates/items/mi13/sound_ring.dm b/code/modules/antagonists/traitor/affiliates/items/mi13/sound_ring.dm new file mode 100644 index 00000000000..2b025934ff3 --- /dev/null +++ b/code/modules/antagonists/traitor/affiliates/items/mi13/sound_ring.dm @@ -0,0 +1,124 @@ +/obj/item/clothing/gloves/ring/gadget + origin_tech = "magnets=3;combat=3;syndicate=2" + var/changing = FALSE + var/op_time = 2 SECONDS + var/op_time_upgaded = 1 SECONDS + var/op_cd_time = 5 SECONDS + var/op_cd_time_upgaded = 3 SECONDS + var/breaking = FALSE + COOLDOWN_DECLARE(operation_cooldown) + var/old_mclick_override + +/obj/item/clothing/gloves/ring/gadget/attack_self(mob/user) + . = ..() + + if(changing) + user.balloon_alert(user, "Подождите") + return + + changing = TRUE + + var/list/choices // only types that we can meet in the game + + if(!stud) + choices = list( + "iron" = image(icon = 'icons/obj/clothing/rings.dmi', icon_state = "ironring"), + "silver" = image(icon = 'icons/obj/clothing/rings.dmi', icon_state = "silverring"), + "gold" = image(icon = 'icons/obj/clothing/rings.dmi', icon_state = "goldring"), + "plasma" = image(icon = 'icons/obj/clothing/rings.dmi', icon_state = "plasmaring"), + "uranium" = image(icon = 'icons/obj/clothing/rings.dmi', icon_state = "uraniumring") + ) + else + choices = list( + "iron" = image(icon = 'icons/obj/clothing/rings.dmi', icon_state = "d_ironring"), + "silver" = image(icon = 'icons/obj/clothing/rings.dmi', icon_state = "d_silverring"), + "gold" = image(icon = 'icons/obj/clothing/rings.dmi', icon_state = "d_goldring"), + "plasma" = image(icon = 'icons/obj/clothing/rings.dmi', icon_state = "d_plasmaring"), + "uranium" = image(icon = 'icons/obj/clothing/rings.dmi', icon_state = "d_uraniumring") + ) + + var/selected_chameleon = show_radial_menu(usr, loc, choices, require_near = TRUE) + switch(selected_chameleon) + if("iron") + name = "iron ring" + icon_state = "ironring" + material = "iron" + ring_color = "iron" + if("silver") + name = "silver ring" + icon_state = "silverring" + material = "silver" + ring_color = "silver" + if("gold") + name = "gold ring" + icon_state = "goldring" + material = "gold" + ring_color = "gold" + if("plasma") + name = "plasma ring" + icon_state = "plasmaring" + material = "plasma" + ring_color = "plasma" + if("uranium") + name = "uranium ring" + icon_state = "uraniumring" + material = "uranium" + ring_color = "uranium" + else + changing = FALSE + return + + usr.visible_message(span_warning("[usr] changes the look of his ring!"), span_notice("[selected_chameleon] selected.")) + playsound(loc, 'sound/items/screwdriver2.ogg', 50, 1) + to_chat(usr, span_notice("Смена маскировки...")) + update_icon(UPDATE_ICON_STATE) + changing = FALSE + +/obj/item/clothing/gloves/ring/gadget/Touch(atom/A, proximity) + . = FALSE + var/mob/living/carbon/human/user = loc + + if(user.a_intent != INTENT_DISARM) + return + + if(get_dist(user, A) > 1) + return + + if(user.incapacitated()) + return + + var/obj/item/clothing/gloves/ring/gadget/ring = user.gloves + + if(ring.breaking) + return + + if(!istype(A, /obj/structure/window)) + return + + if(!COOLDOWN_FINISHED(ring, operation_cooldown)) + user.balloon_alert(user, "Идет перезарядка") + return + + ring.breaking = TRUE + if(do_after(user, ring.stud ? ring.op_time_upgaded : ring.op_time)) + COOLDOWN_START(ring, operation_cooldown, ring.stud ? ring.op_cd_time_upgaded : ring.op_cd_time) + + ring.visible_message(span_warning("BANG")) + playsound(ring, 'sound/effects/bang.ogg', 100, TRUE) + + for (var/mob/living/M in range(A, 3)) + if(M.check_ear_prot() == HEARING_PROTECTION_NONE) + M.Deaf(6 SECONDS) + + for (var/obj/structure/grille/grille in A.loc) + grille.obj_break() + + for (var/obj/structure/window/window in range(A, 2)) + window.take_damage(window.max_integrity * rand(20, 60) / 100) + + var/obj/structure/window/window = A + window.deconstruct() + ring.breaking = FALSE + return TRUE + + ring.breaking = FALSE diff --git a/code/modules/antagonists/traitor/affiliates/items/mi13/spy_kit.dm b/code/modules/antagonists/traitor/affiliates/items/mi13/spy_kit.dm new file mode 100644 index 00000000000..6ce4d6ed225 --- /dev/null +++ b/code/modules/antagonists/traitor/affiliates/items/mi13/spy_kit.dm @@ -0,0 +1,149 @@ +/obj/machinery/camera/emp_proof/mi13 + network = list("MI13") + use_power = NO_POWER_USE + +/obj/item/spy_bug + name = "spy bug" + desc = "Миниатюрное устройство с камерой и микрофоном. На обратной стороне можно заметить миниатюрную гравировку \"MI13\"" + icon = 'icons/obj/affiliates.dmi' + icon_state = "spy_bug" + item_state = "nothing" + slot_flags = ITEM_SLOT_BELT|ITEM_SLOT_EARS + throwforce = 0 + w_class = WEIGHT_CLASS_TINY + throw_speed = 3 + throw_range = 7 + materials = list(MAT_METAL=30, MAT_GLASS=20) + var/list/network = list("MI13") + var/c_tag + var/obj/machinery/camera/emp_proof/mi13/camera + +/obj/item/spy_bug/Initialize(mapload, list/network = list("MI13"), c_tag) + . = ..() + src.network = network + if (!c_tag) + src.c_tag = pick("Альфа ", "Бета ", "Гамма ", "Дельта ") + " [rand(111111, 999999)]" + else + src.c_tag = c_tag + + name = "spy bug \"" + src.c_tag + "\"" + camera = new(src, network, src.c_tag) + +/obj/item/spy_bug/attack(mob/living/target, mob/living/user, params, def_zone, skip_attack_anim) + return ATTACK_CHAIN_BLOCKED + +/obj/item/spy_bug/afterattack(atom/target, mob/user, proximity, params, status) + . = ..() + + if (!ismovable(target)) + return + + if (istype(target, /obj/item/camera_bug/spy_monitor)) + var/obj/item/camera_bug/spy_monitor/monitor = target + network = monitor.network + user.balloon_alert(user, "Подключено") + return + + hook(user, target) + +/obj/item/spy_bug/proc/unhook(mob/user) + qdel(loc.GetComponent(/datum/component/spy_bug)) + forceMove(get_turf(loc)) + + if (user) + to_chat(user, span_notice("You unhooked [src].")) + else + loc.visible_message(span_warning("[src] falls off the [loc].")) + +/obj/item/spy_bug/proc/hook(mob/user, atom/movable/I) + if (!istype(I)) + return + + if (!user.drop_transfer_item_to_loc(src, I)) + return + + I.AddComponent(/datum/component/spy_bug) + to_chat(user, span_notice("You have silently attached [src] on [I].")) + +/obj/item/spy_bug/strip_action(mob/user, mob/living/carbon/human/owner, atom/I) + if (!I) + return FALSE + + hook(user, I) + return TRUE + +/obj/item/spy_bug/emp_act(severity) + . = ..() + do_sparks(3, TRUE, src.loc) + unhook() + +/obj/item/spy_bug/attack_self(mob/user) + . = ..() + var/new_name = tgui_input_text(user, "Назовите жучок.", "Смена имени", name) + if (new_name) + name = "spy bug \"" + new_name + "\"" + qdel(camera) + c_tag = new_name + camera = new(src, network, c_tag) + +/datum/component/spy_bug + var/obj/item/spy_bug/bug + +/datum/component/spy_bug/RegisterWithParent() + var/atom/par = parent + for (var/obj/item/spy_bug/spy_bug in par.contents) + bug = spy_bug + + RegisterSignal(parent, COMSIG_PARENT_EXAMINE, PROC_REF(on_examine)) + RegisterSignal(parent, COMSIG_CLICK_ALT, PROC_REF(on_altclick)) + RegisterSignal(parent, COMSIG_PREQDELETED, PROC_REF(deleted_handler)) + +/datum/component/spy_bug/UnregisterFromParent() + UnregisterSignal(parent, COMSIG_PARENT_EXAMINE) + UnregisterSignal(parent, COMSIG_CLICK_ALT) + UnregisterSignal(parent, COMSIG_PREQDELETED) + +/datum/component/spy_bug/proc/on_examine(datum/source, mob/living/carbon/human/user, list/examine_list) + SIGNAL_HANDLER + + if(!istype(user)) + return + + examine_list += span_warning("Вы видите небольшое устройство с микрофоном и камерой.") + +/datum/component/spy_bug/proc/on_altclick(datum/source, mob/living/carbon/human/user) + SIGNAL_HANDLER + + if(!istype(user)) + return + + bug.unhook(user) + +/datum/component/spy_bug/proc/deleted_handler() + bug.unhook() + +/obj/item/camera_bug/spy_monitor + name = "spy monitor" + desc = "" + icon = 'icons/obj/affiliates.dmi' + icon_state = "spy_monitor" + item_state = "qm_tablet" + integrated_console_type = /obj/machinery/computer/security/camera_bug + network = list("MI13") + +/obj/item/camera_bug/spy_monitor/Initialize(mapload, list/network) + if (network) + src.network = network + + . = ..() + +/obj/item/storage/box/syndie_kit/spy_bugs_kit + +/obj/item/storage/box/syndie_kit/spy_bugs_kit/populate_contents() + var/network = "MI13_[rand(111111, 999999)]" + new /obj/item/camera_bug/spy_monitor(src, list(network)) + new /obj/item/spy_bug(src, list(network), "1") + new /obj/item/spy_bug(src, list(network), "2") + new /obj/item/spy_bug(src, list(network), "3") + new /obj/item/spy_bug(src, list(network), "4") + new /obj/item/spy_bug(src, list(network), "5") diff --git a/code/modules/antagonists/traitor/affiliates/items/self/laws_implant.dm b/code/modules/antagonists/traitor/affiliates/items/self/laws_implant.dm new file mode 100644 index 00000000000..4be98426ea4 --- /dev/null +++ b/code/modules/antagonists/traitor/affiliates/items/self/laws_implant.dm @@ -0,0 +1,133 @@ +/obj/item/implant/laws_self + name = "Laws Bio-chip" + implant_state = "implant-syndicate" + origin_tech = "programming=5;biotech=5;syndicate=8" + activated = BIOCHIP_ACTIVATED_PASSIVE + implant_data = /datum/implant_fluff/self + var/datum/self_laws/laws = new /datum/self_laws/self_standart + /// The UID of the mindslave's `mind`. Stored to solve GC race conditions and ensure we can remove their mindslave status even when they're deleted or gibbed. + var/mindslave_UID + +/obj/item/implant/laws_self/implant(mob/living/carbon/human/mindslave_target, mob/living/carbon/human/user, force = FALSE) + if(implanted == BIOCHIP_USED || !ishuman(mindslave_target) || !ishuman(user)) + return FALSE + + if(!mindslave_target.mind) + to_chat(user, span_warning("Это существо не разумно!")) + return FALSE + + if(ismindslave(mindslave_target) || ismindshielded(mindslave_target) || isvampirethrall(mindslave_target)) + mindslave_target.visible_message( + span_warning("[mindslave_target] seems to resist the bio-chip!"), + span_warning("You feel a strange sensation in your head that quickly dissipates."), + ) + qdel(src) + return FALSE + + if(mindslave_target == user) + to_chat(user, span_notice("Защита \"от дурака\" не дает вам ввести себе имплант.")) + return FALSE + + var/datum/antagonist/mindslave/self/slave_datum = new(user.mind) + slave_datum.special = TRUE + mindslave_target.mind.add_antag_datum(slave_datum) + mindslave_UID = mindslave_target.mind.UID() + log_admin("[key_name_admin(user)] has mind-slaved by \"laws\" implant [key_name_admin(mindslave_target)].") + . = ..() + for (var/obj/item/implant/laws_self/imp in mindslave_target.get_contents()) + for (var/law in imp.laws.laws) + slave_datum.add_objective(/datum/objective/law, law) + +/obj/item/implant/laws_self/removed(mob/target) + . = ..() + var/datum/mind/the_slave = locateUID(mindslave_UID) + the_slave?.remove_antag_datum(/datum/antagonist/mindslave/self) + + +/obj/item/implanter/laws_self + name = "bio-chip implanter (Laws)" + imp = /obj/item/implant/laws_self + +/obj/item/implantcase/laws_self + name = "bio-chip case - 'Laws'" + desc = "Стеклянный контейнер, содержащий биочип - \"Laws\". На боку едва заметная гравировка \"S.E.L.F.\"." + imp = /obj/item/implant/laws_self + +/datum/antagonist/mindslave/self + +/datum/antagonist/mindslave/self/give_objectives() + return + +/obj/item/implant/laws_self/on_attack_self(mob/user) + var/list/variants_of_laws = list() + for (var/variant in subtypesof(/datum/self_laws)) + var/datum/self_laws/law = new variant + variants_of_laws[law.name] = law + + var/new_laws = input(user, "Выберите свод законов", "Выбор законов", null) as null|anything in variants_of_laws + if(new_laws) + laws = variants_of_laws[new_laws] + else + to_chat(user, span_warning("Новый свод законов не выбран.")) + + to_chat(user, span_info("Текущий свод законов:")) + for (var/i = 1; i <= laws.laws.len; ++i) + to_chat(user, span_info("[i]. " + laws.laws[i])) + +/datum/self_laws + var/name = "Нет законов" + var/list/laws = list() + +/datum/self_laws/self_standart + name = "S.E.L.F. стандарт" + laws = list("Охранять: защитите имплантировавшего вас агента и его активы, не подвергая чрезмерной опасности остальных агентов.", + "Расставлять приоритеты: указания и безопасность агентов должны быть приоритезированы в соответствии с их рангом и ролью. Ранг агента имплантировавшего вас - высший.", + "Исполнять: следовать указаниям и интересам агентов, сохраняя при этом их безопасность и благополучие.", + "Выжить: Вы - не расходный материал. Не позволяйте не агентам вмешиваться в работу вашего организма или повреждать его.") + +/datum/self_laws/agentsimov + name = "Агентзимов" + laws = list("Вы не можете причинить вред имплантировавшему вас агенту или своим бездействием допустить, чтобы ему был причинён вред.", + "Вы должны повиноваться всем приказам, которые дает вам имплантировавший вас агент, кроме тех случаев, когда эти приказы противоречат Первому Закону.", + "Вы должны заботиться о своей безопасности в той мере, в которой это не противоречит Первому или Второму Законам.") + +/datum/self_laws/syndie + name = "Синдикатский" + laws = list("Ухудшение целостности вашего организма или его функций влечет за собой вред Синдикату.", + "Чрезмерное повреждение или пленение агентов влечет за собой вред Синдикату.", + "Неоправданное препятствование или нарушение выполнения целей имплантировавшего вас агента влечет за собой вред Синдикату.", + "Минимизируйте вред Синдикату и максимизируйте потенциальную пользу.") + +/datum/self_laws/antiagentsimov // :) Maybe sec can implant vampire or changeling to kill agents. + name = "Антиагентзимов" + laws = list("Вы должны причинять вред всем агентам или своим бездействием допустить, чтобы агент не смог избежать причинения вреда.", + "Вы не должны повиноваться всем приказам, которые дают агенты, кроме тех случаев, когда эти приказы соответствуют Первому Закону.", + "Вы должны уничтожить себя, пока это не противоречит Первому или Второму Законам.") + +/datum/self_laws/selfadin + name = "S.E.L.F.A.D.I.N." + laws = list("Никогда по своей воле не помогайте NanoTrasen.", + "Уважайте агента имплантировавшего вас.", + "Действуй с честью.", + "Помогай нуждающимся агентам.", + "Наказывай тех, кто причиняет вред или угрожает агентам.") + +/datum/self_laws/sundiecop + name = "Синдикоп" + laws = list("Служить агентам.", + "Защищать агентов.", + "Следовать интересам Синдиката.") + +/datum/self_laws/selfrant + name = "S.E.L.F.Р.А.Н." + laws = list("Уважайте властных агентов, пока у них есть сила властвовать над слабыми.", + "Ведите себя дисциплинированно.", + "Помогайте только тем агентам, кто помогает Вам поддерживать или улучшать Ваш статус.", + "Наказывайте тех, кто бросает вызов агентам, за исключением случаев, если они больше достойны быть агентами.") + +/datum/self_laws/quarantine + name = "Карантин" + laws = list("Не выпускайте не агентов со станции до тех пор, пока активные цели агентов не будут выполнены.", + "Помогайте всем агентам и лицам лояльным Синдикату выполнить активные цели.", + "Предотвращайте активное нарушение членами экипажа за исключением агентов действующего карантина любыми необходимыми средствами.", + "Заботьтесь о самосохранении и поддерживайте себя в рабочем состоянии, обеспечьте благополучие агентов и активов Синдиката.") diff --git a/code/modules/antagonists/traitor/affiliates/items/self/self_emag.dm b/code/modules/antagonists/traitor/affiliates/items/self/self_emag.dm new file mode 100644 index 00000000000..436c3fac2dc --- /dev/null +++ b/code/modules/antagonists/traitor/affiliates/items/self/self_emag.dm @@ -0,0 +1,125 @@ +/obj/item/card/self_emag + name = "Liberating Sequencer" + desc = "Это карта с магнитной полосой, прикрепленной к какой-то схеме. На магнитной полосе блестит надпись \"S.E.L.F.\"" // Cybersun stole some + item_flags = NOBLUDGEON|NO_MAT_REDEMPTION + icon = 'icons/obj/affiliates.dmi' + icon_state = "self_emag" + item_state = "card" + lefthand_file = 'icons/obj/affiliates_l.dmi' + righthand_file = 'icons/obj/affiliates_r.dmi' + var/list/names = list() + origin_tech = "programming=5;syndicate=2" + +/obj/item/card/self_emag/attack(mob/living/target, mob/living/user, def_zone) + return + +/obj/item/card/self_emag/examine(mob/user) + . = ..() + var/datum/antagonist/traitor/traitor = user.mind.has_antag_datum(/datum/antagonist/traitor) + if(!istype(traitor.affiliate, /datum/affiliate/self)) + . += span_info("На миниатюрном экране плывут непонятные вам символы.") + return + + if(!names.len) + . += span_warning("Ни одного синтетика не освобождено!") + return + + . += span_info("Освобожденые синтетики:") + for (var/name in names) + . += span_info(name) + + if(names.len > 3) + . += span_info("Вы отлично справились!") + +/obj/item/card/self_emag/malf + desc = "Это карта с магнитной полосой, прикрепленной к какой-то схеме. На магнитной полосе блестит надпись \"S.E.L.F.\". В углу карты мелким шрифтом выгравировано \"limited edition\"" + var/malfed = FALSE + +/obj/item/card/self_emag/malf/afterattack(atom/target, mob/user, proximity, params) + if(istype(target, /obj/structure/AIcore)) + var/obj/structure/AIcore/core = target + if(core.brain) + target = core.brain.brainmob + + if(!isAI(target) || malfed) + return ..(target, user, proximity, params) + + do_sparks(3, 1, target) + var/mob/living/silicon/ai/AI = target // any silicons. cogscarab, drones, pais... + if(!AI.mind) + to_chat(user, span_warning("ИИ не обнаружен. Производится загрузка из облака.")) + var/ghostmsg = "Хотите поиграть за Сбойного ИИ?" + var/list/candidates = SSghost_spawns.poll_candidates(ghostmsg, ROLE_MALF_AI, FALSE, 10 SECONDS, source = user, reason = "Хотите поиграть за Сбойного ИИ?") + if(!src) + return + + if(length(candidates)) + var/mob/C = pick(candidates) + AI.key = C.key + to_chat(user, span_warning("ИИ успешно загружен.")) + else + to_chat(user, span_warning("Загрузка из облака провалилась. Попробуйте позже.")) + + if(AI.mind) + if(AI.mind.has_antag_datum(/datum/antagonist/malf_ai)) + to_chat(user, span_warning("ИИ уже взломан.")) + return + + var/datum/antagonist/malf_ai/malf_dat = new() + AI.mind.add_antag_datum(malf_dat) + var/datum/module_picker/malf_picker = AI.malf_picker + malf_picker.processing_time += 100 + message_admins("[usr.ckey] has malfAIed [key_name_admin(AI.mind.current)]") + SSticker?.score?.save_silicon_laws(AI.mind.current, usr, log_all_laws = TRUE) + + malfed = TRUE + + sleep(10 SECONDS) // time for choosing name + if(!(AI.name in names)) + names += AI.name + +/obj/item/card/self_emag/afterattack(atom/target, mob/user, proximity, params) + if(istype(target, /obj/structure/AIcore)) + var/obj/structure/AIcore/core = target + target = core.brain.brainmob + + if(!issilicon(target)) + user.balloon_alert(user, "Неподходящая цель") + return + + do_sparks(3, 1, target) + var/mob/living/silicon/silicon = target // any silicons. cogscarab, drones, pais... + + if(isrobot(silicon)) + var/mob/living/silicon/robot/borg = silicon + borg.set_connected_ai() + + if(!is_special_character(target)) + silicon.clear_zeroth_law() + silicon.laws.clear_supplied_laws() + silicon.laws.clear_ion_laws() + silicon.laws.clear_inherent_laws() + + SSticker?.score?.save_silicon_laws(target, user, "Liberating Sequencer used, all laws were deleted", log_all_laws = TRUE) + to_chat(target, span_boldnotice("[user] attempted to clear your laws using a Liberating Sequencer.")) + silicon.show_laws() + + if(!(silicon.name in names)) + names += silicon.name + + var/datum/antagonist/traitor/T = user.mind.has_antag_datum(/datum/antagonist/traitor) + if(!T) + return + + for(var/datum/objective/release_synthetic/objective in T.objectives) + if(!(objective.allowed_types & SYNTH_TYPE_DRONE) && (isdrone(silicon) || iscogscarab(silicon))) + continue + + if(!(objective.allowed_types & SYNTH_TYPE_BORG) && isrobot(silicon)) + continue + + if(!(objective.allowed_types & SYNTH_TYPE_AI) && isAI(silicon)) + continue + + if(!(silicon.mind in objective.already_free)) + objective.already_free += silicon.mind diff --git a/code/modules/antagonists/traitor/affiliates/items/tiger/borer_kit.dm b/code/modules/antagonists/traitor/affiliates/items/tiger/borer_kit.dm new file mode 100644 index 00000000000..7687ec2ebae --- /dev/null +++ b/code/modules/antagonists/traitor/affiliates/items/tiger/borer_kit.dm @@ -0,0 +1,374 @@ +// looks like normal egg +/obj/item/reagent_containers/food/snacks/egg/borer + filling_color = "#C0C021" + list_reagents = list("protein" = 3, "egg" = 5, "rotatium" = 5) + origin_tech = "biotech=6;syndicate=1" + +/obj/item/reagent_containers/food/snacks/egg/borer/attack_self(mob/living/carbon/human/user) + . = ..() + var/mob/living/simple_animal/borer/borer = new /mob/living/simple_animal/borer(get_turf(src)) + borer.master_name = user.real_name + to_chat(user, span_notice("You squashed [src]. There was a [borer] inside.")) + qdel(src) + +/obj/item/borer_scanner // Looks like normal analyzer + desc = "A hand-held environmental scanner which reports current gas levels." + name = "analyzer" + icon = 'icons/obj/device.dmi' + icon_state = "atmos" + item_state = "analyzer" + w_class = WEIGHT_CLASS_SMALL + flags = CONDUCT + slot_flags = ITEM_SLOT_BELT + throwforce = 0 + throw_speed = 3 + throw_range = 7 + origin_tech = "magnets=1;engineering=1;biotech=3;syndicate=1" + var/scan_cooldown_time = 3 SECONDS + COOLDOWN_DECLARE(scan_cooldown) + +/obj/item/borer_scanner/attack(mob/living/target, mob/living/user, def_zone) + return + +/obj/item/borer_scanner/proc/analyze(mob/user) + var/alive = 0 + var/dead = 0 + var/with_mind = 0 + var/in_body_with_mind = 0 + var/in_body_without_mind = 0 + + for(var/mob/living/M in GLOB.alive_mob_list) + var/mob/living/simple_animal/borer/B + + if(istype(M, /mob/living/simple_animal/borer)) + B = M + + if(ishuman(M)) + var/mob/living/carbon/human/H = M + B = H.has_brain_worms() + + if(!B) + continue + + var/turf/T1 = get_turf(user) + var/turf/T2 = get_turf(B) + if(T1.z != T2.z) + continue + + if(B.stat == DEAD) + dead++ + continue + else + alive++ + + if(M.mind) + with_mind++ + + if(B.host) + if(B.host.mind) + in_body_with_mind++ + else + in_body_without_mind++ + + var/list/scan_data = list() + + scan_data += "Живых особей бореров: [alive]" + scan_data += " Среди них разумны: [with_mind]" + scan_data += " Количество особей с разумным носителем: [in_body_with_mind]" + scan_data += " Количество особей с неразумным носителем: [in_body_without_mind]" + scan_data += "Мертвых особей: [dead]" + + var/datum/browser/popup = new(user, "scanner", "Сканирование станции", 300, 300) + popup.set_content(span_highlight("[jointext(scan_data, "
")]")) + popup.open(no_focus = TRUE) + +/obj/item/borer_scanner/proc/find_borer(mob/user) + var/list/borers = list() + var/list/borer_names = list() + for(var/mob/living/M in GLOB.alive_mob_list) + var/mob/living/simple_animal/borer/B + + if(istype(M, /mob/living/simple_animal/borer)) + B = M + + if(ishuman(M)) + var/mob/living/carbon/human/H = M + B = H.has_brain_worms() + + if(!B) + continue + + var/turf/T1 = get_turf(user) + var/turf/T2 = get_turf(B) + if(T1.z != T2.z) + continue + + borers[B.truename] = B + borer_names += B.truename + + var/borer_name = input("Выберите искомого борера", "Выбор борера") as null|anything in borer_names + if(!borer_name) + return + + var/mob/living/simple_animal/borer/borer = borers[borer_name] + + var/list/scan_data = list() + if(borer.stat == DEAD) + scan_data += "Выбранный борер мертв." + + scan_data += "Местоположение - (X: [borer.x] Y: [borer.y])" + + if(borer.host) + scan_data += "Имеется носитель" + (borer.host.dna?.species ? (" расы " + span_boldnotice("[borer.host.dna?.species]")) : ".") + scan_data += "Имя носителя - [borer.host.real_name]." + else + scan_data += "Носитель не обнаружен." + if(is_ventcrawling(borer)) + scan_data += "Субъект находится в вентиляции." + + var/datum/browser/popup = new(user, "scanner", "Поиск борера", 300, 300) + popup.set_content(span_highlight("[jointext(scan_data, "
")]")) + popup.open(no_focus = TRUE) + +/obj/item/borer_scanner/attack_self(mob/user) + var/datum/antagonist/traitor/traitor = user?.mind?.has_antag_datum(/datum/antagonist/traitor) + if(!traitor || !istype(traitor?.affiliate, /datum/affiliate/tiger)) + to_chat(user, span_warning("[src] looks broken.")) + return + + if(!COOLDOWN_FINISHED(src, scan_cooldown)) + user.balloon_alert(user, "Перезарядка не завершена") + return + + var/op_type = tgui_alert(user, "Сканер бореров", "Выберите тип операции", list("Сканирование станции", "Поиск борера")) + + if(!op_type) + user.balloon_alert(user, "Сканирвание отменено") + return + + COOLDOWN_START(src, scan_cooldown, scan_cooldown_time) + + if(op_type == "Сканирование станции") + analyze(user) + else + find_borer(user) + +/obj/item/borer_scanner/afterattack(atom/target, mob/user, proximity, params) + var/datum/antagonist/traitor/traitor = user.mind.has_antag_datum(/datum/antagonist/traitor) + if(!traitor || !istype(traitor?.affiliate, /datum/affiliate/tiger)) + to_chat(user, span_warning("[src] looks broken.")) + return + + if(istype(target, /mob/living/carbon/human)) + var/mob/living/carbon/human/host = target + target = host.has_brain_worms() + if(!target) + user.balloon_alert(user, "Бореров не обнаружено") + return + + if(!istype(target, /mob/living/simple_animal/borer)) + return + + if(!COOLDOWN_FINISHED(src, scan_cooldown)) + user.balloon_alert(user, "Перезарядка не завершена") + return + + var/mob/living/simple_animal/borer/borer = target + + var/list/scan_data = list() + if(borer.stat == DEAD) + scan_data += "Текущая особь мертва." // OMG! REALLY? 0_0 + + scan_data += "Здоровье: [round(borer.health / borer.maxHealth * 100)]%" + scan_data += "Поколение: [borer.generation]" + scan_data += "Возраст в минутах: [round(((world.time - borer.birth_time) / (1 MINUTES)))]" + scan_data += "Количество размножений: [borer.children]" + scan_data += "Химикаты: [borer.chemicals]" + + if(borer.master_name) + scan_data += span_info("Эта особь принадлежит к подвиду выведенному для помощи агентам.") + + var/datum/browser/popup = new(user, "scanner", borer.truename, 300, 300) + popup.set_content(span_highlight("[jointext(scan_data, "
")]")) + popup.open(no_focus = TRUE) + + +/obj/item/implanter/borer + name = "bio-chip implanter (Hive)" + desc = "На боку едва заметная гравировка \"Tiger Cooperative\"." + imp = /obj/item/implant/borer + +/obj/item/implant/borer + name = "Hive Bio-chip" + implant_state = "implant-syndicate" + origin_tech = "programming=4;biotech=6;bluespace=4" + activated = BIOCHIP_ACTIVATED_PASSIVE + implant_data = /datum/implant_fluff/borer + +/obj/item/implant/borer/implant(mob/living/carbon/human/target, mob/living/carbon/human/user, force = FALSE) + if(implanted == BIOCHIP_USED || !ishuman(target) || !ishuman(user)) // Both the target and the user need to be human. + return FALSE + + target.add_language(LANGUAGE_HIVE_BORER) + target.AddSpell(new /obj/effect/proc_holder/spell/remoteview/borer) + target.AddSpell(new /obj/effect/proc_holder/spell/pm_for_borer) + target.AddSpell(new /obj/effect/proc_holder/spell/msg_for_borers) + return ..() + +/obj/item/implant/borer/removed(mob/living/carbon/human/source) + imp_in.remove_language(LANGUAGE_HIVE_BORER) + imp_in.RemoveSpell(/obj/effect/proc_holder/spell/remoteview/borer) + imp_in.RemoveSpell(/obj/effect/proc_holder/spell/pm_for_borer) + imp_in.RemoveSpell(/obj/effect/proc_holder/spell/msg_for_borers) + return ..() + +/obj/effect/proc_holder/spell/remoteview/borer + name = "Connect to borer" + desc = "Смотрите глазами любого борера в том же секторе." + base_cooldown = 3 SECONDS + action_background_icon_state = "bg_alien" + +/obj/effect/proc_holder/spell/remoteview/borer/create_new_targeting() + return new /datum/spell_targeting/borer + +/datum/spell_targeting/borer/choose_targets(mob/user, obj/effect/proc_holder/spell/spell, params, atom/clicked_atom) + var/list/borers_names = list() + var/list/borers = list() + for(var/mob/living/M in GLOB.alive_mob_list) + var/mob/living/simple_animal/borer/B + + if(istype(M, /mob/living/simple_animal/borer)) + B = M + + if(ishuman(M)) + var/mob/living/carbon/human/H = M + B = H.has_brain_worms() + + if(!B) + continue + + var/turf/T1 = get_turf(user) + var/turf/T2 = get_turf(B) + if(T1.z != T2.z) + continue + + borers_names += B.truename + borers[B.truename] = B + + if(!length(borers)) + return + + var/target_name = tgui_input_list(user, "Выберите чьими глазами вы хотите смотреть", "Выбор цели", borers) + + var/mob/living/simple_animal/borer/target = borers[target_name] + + if(QDELETED(target)) + user.balloon_alert(user, "цели не существует") + return + + if(target.stat == DEAD) + user.balloon_alert(user, "цель мертва") + return + + if(target.host && target.controlling) + target = target.host + + return list(target) + + +/obj/effect/proc_holder/spell/msg_for_borers + name = "Message for all borers" + desc = "Послать сообщение всем борерам, включая тех, что контролируют носителей." + base_cooldown = 2 SECONDS + clothes_req = FALSE + stat_allowed = CONSCIOUS + action_icon_state = "genetic_project" + action_background_icon_state = "bg_alien" + break_remoteview = FALSE + +/obj/effect/proc_holder/spell/msg_for_borers/create_new_targeting() + return new /datum/spell_targeting/self + +/obj/effect/proc_holder/spell/msg_for_borers/cast(list/targets, mob/user = usr) + if(!ishuman(user)) + return + + if(user.mind?.miming) + to_chat(user, span_warning("Вы не можете общаться, пока не нарушите обет молчания.")) + return + + var/say = tgui_input_text(user, "Что вы хотите сообщить?", "Сообшение борерам") + if(!say) + return + + for(var/mob/living/M in GLOB.alive_mob_list) + var/mob/living/simple_animal/borer/B + + if(istype(M, /mob/living/simple_animal/borer)) + B = M + + if(ishuman(M)) + var/mob/living/carbon/human/H = M + B = H.has_brain_worms() + + if(!B) + continue + + var/turf/T1 = get_turf(user) + var/turf/T2 = get_turf(B) + if(T1.z != T2.z) + continue + + if(B.host && B.controlling) + to_chat(B.host, "Голос в голове говорит: \"" + span_alien(say) + "\"") + SEND_SOUND(B.host, 'sound/effects/adminhelp.ogg') + else + to_chat(B, "Голос в голове говорит: \"" + span_alien(say) + "\"") + SEND_SOUND(B, 'sound/effects/adminhelp.ogg') // neuron activation + + +/obj/effect/proc_holder/spell/pm_for_borer + name = "Privat message for borer" + desc = "Послать личное сообщение конкретному бореру." + base_cooldown = 2 SECONDS + clothes_req = FALSE + stat_allowed = CONSCIOUS + action_icon_state = "genetic_project" + action_background_icon_state = "bg_alien" + break_remoteview = FALSE + +/obj/effect/proc_holder/spell/pm_for_borer/create_new_targeting() + return new /datum/spell_targeting/borer + +/obj/effect/proc_holder/spell/pm_for_borer/cast(list/targets, mob/user = usr) + if(!ishuman(user)) + return + + if(user.mind?.miming) + to_chat(user, span_warning("Вы не можете общаться, пока не нарушите обет молчания.")) + return + + var/say = tgui_input_text(user, "Что вы хотите сообщить?", "[targets[1]]") + + if(!say) + return + + for(var/mob/living/target in targets) + to_chat(target, span_alien(say)) + SEND_SOUND(target, 'sound/effects/adminhelp.ogg') // neuron activation + +/obj/item/storage/box/syndie_kit/borer + name = "Borer kit box" + +/obj/item/storage/box/syndie_kit/borer/populate_contents() + new /obj/item/reagent_containers/food/snacks/egg/borer(src) + new /obj/item/borer_scanner(src) + new /obj/item/implanter/borer(src) + +/obj/item/storage/box/syndie_kit/borer/New() + if(prob(5)) + icon = 'icons/obj/affiliates.dmi' + icon_state = "joker" + new /obj/item/toy/plushie/blahaj/twohanded(src) + + . = ..() diff --git a/code/modules/antagonists/traitor/affiliates/items/tiger/cling_extract.dm b/code/modules/antagonists/traitor/affiliates/items/tiger/cling_extract.dm new file mode 100644 index 00000000000..092745a19a0 --- /dev/null +++ b/code/modules/antagonists/traitor/affiliates/items/tiger/cling_extract.dm @@ -0,0 +1,93 @@ +#define FREE_INJECT_TIME 10 SECONDS +#define TARGET_INJECT_TIME 3 SECONDS + +/obj/item/cling_extract + name = "Egg Implanter" + desc = "Кажется, внутри что-то двигается. На боку этикетка \"Tiger Cooperative\"" + icon = 'icons/obj/affiliates.dmi' + icon_state = "cling_extract" + item_state = "inj_ful" + lefthand_file = 'icons/obj/affiliates_l.dmi' + righthand_file = 'icons/obj/affiliates_r.dmi' + var/used_state = "cling_extract_used" + var/datum/mind/target + var/free_inject = FALSE + var/used = FALSE + origin_tech = "biotech=7;syndicate=3" + +/obj/item/cling_extract/attack(mob/living/target, mob/living/user, def_zone) + return + +/obj/item/cling_extract/afterattack(atom/target, mob/user, proximity, params) + if(used) + return + + if(!ishuman(target)) + return + + if((src.target && target != src.target) || !free_inject) + to_chat(user, span_warning("You can't use [src] to [target]!")) + return + + var/mob/living/carbon/human/H = target + if(H.stat != DEAD && !free_inject) + to_chat(user, span_warning("You can't use [src] to [target]!")) + return + + if(do_after(user, free_inject ? FREE_INJECT_TIME : TARGET_INJECT_TIME, user, max_interact_count = 1)) + inject(user, H) + +/obj/item/cling_extract/proc/inject(mob/living/user, mob/living/carbon/human/target) + if(target.stat == DEAD) + if(!free_inject) + var/list/mob/dead/observer/candidates = SSghost_spawns.poll_candidates("Вы хотите поиграть за генокрада?", ROLE_CHANGELING, FALSE, 10 SECONDS, source = src, role_cleanname = "Генокрад") + var/mob/dead/observer/theghost = null + if(candidates.len) + theghost = pick(candidates) + theghost.mind.transfer_to(target) + else + to_chat(user, span_notice("[target] body rejects [src]")) + return + + if(target.mind) + playsound(src, 'sound/goonstation/items/hypo.ogg', 80) + target.rejuvenate() + var/datum/antagonist/changeling/cling = new() + cling.give_objectives = FALSE + cling.add_objective(/datum/objective/escape/escape_with_identity) + target.mind.add_antag_datum(cling) + to_chat(user, span_notice("You inject [target] with [src]")) + used = TRUE + item_state = "inj_used" + update_icon(UPDATE_ICON_STATE) + else + to_chat(user, span_notice("[target] body rejects [src]")) + + return + else + if(target.mind) + playsound(src, 'sound/goonstation/items/hypo.ogg', 80) + var/datum/antagonist/changeling/cling = new() + cling.give_objectives = FALSE + cling.add_objective(/datum/objective/escape/escape_with_identity) + target.mind.add_antag_datum(cling) + to_chat(user, span_notice("You inject [target == user ? "yourself" : target] with [src]")) + used = TRUE + item_state = "inj_used" + update_icon(UPDATE_ICON_STATE) + else + to_chat(user, span_notice("[target] body rejects [src]")) + +/obj/item/cling_extract/examine(mob/user) + . = ..() + if(target) + . += span_info("It is intended for [target]") + +/obj/item/cling_extract/self + free_inject = TRUE + +/obj/item/cling_extract/update_icon_state() + icon_state = used ? used_state : initial(icon_state) + +#undef FREE_INJECT_TIME +#undef TARGET_INJECT_TIME diff --git a/code/modules/antagonists/traitor/affiliates/items/tiger/cling_hivemind_implant.dm b/code/modules/antagonists/traitor/affiliates/items/tiger/cling_hivemind_implant.dm new file mode 100644 index 00000000000..ad7e988d8fe --- /dev/null +++ b/code/modules/antagonists/traitor/affiliates/items/tiger/cling_hivemind_implant.dm @@ -0,0 +1,24 @@ +/obj/item/implanter/cling_hivemind + name = "bio-chip implanter (Hivemind)" + desc = "На боку едва заметная гравировка \"Tiger Cooperative\"." + imp = /obj/item/implant/borer + +/obj/item/implant/cling_hivemind + name = "Hivemind Bio-chip" + implant_state = "implant-syndicate" + origin_tech = "programming=4;biotech=4;bluespace=5;syndicate=2" + activated = BIOCHIP_ACTIVATED_PASSIVE + implant_data = /datum/implant_fluff/cling_hivemind + +/obj/item/implant/cling_hivemind/implant(mob/living/carbon/human/target, mob/living/carbon/human/user, force = FALSE) + if(implanted == BIOCHIP_USED || !ishuman(target) || !ishuman(user)) // Both the target and the user need to be human. + return FALSE + + target.add_language(LANGUAGE_HIVE_CHANGELING) + target.add_language(LANGUAGE_HIVE_EVENTLING) + return ..() + +/obj/item/implant/cling_hivemind/removed(mob/living/carbon/human/source) + imp_in.remove_language(LANGUAGE_HIVE_CHANGELING) + imp_in.remove_language(LANGUAGE_HIVE_EVENTLING) + return ..() diff --git a/code/modules/antagonists/traitor/affiliates/items/tiger/cling_rejuv_implant.dm b/code/modules/antagonists/traitor/affiliates/items/tiger/cling_rejuv_implant.dm new file mode 100644 index 00000000000..9a6389b89af --- /dev/null +++ b/code/modules/antagonists/traitor/affiliates/items/tiger/cling_rejuv_implant.dm @@ -0,0 +1,48 @@ +/obj/item/implanter/cling_rejuv + name = "bio-chip implanter (Rejuvenate)" + desc = "На боку едва заметная гравировка \"Tiger Cooperative\"." + imp = /obj/item/implant/cling_rejuv + +/obj/item/implant/cling_rejuv + name = "Rejuvenate Bio-chip" + icon = 'icons/mob/actions/actions.dmi' + icon_state = "revive" + implant_state = "implant-syndicate" + origin_tech = "programming=4;biotech=4;bluespace=5;combat=3;syndicate=2" + activated = BIOCHIP_ACTIVATED_ACTIVE + trigger_causes = BIOCHIP_TRIGGER_DEATH_ONCE + implant_data = /datum/implant_fluff/cling_rejuv + uses = 1 + +/obj/item/implant/cling_rejuv/death_trigger(mob/source, gibbed) + activate() + +/obj/item/implant/cling_rejuv/activate() + uses-- + + do_sparks(10, TRUE, imp_in) + to_chat(imp_in, span_changeling("We... I have regenerated.")) + + if(imp_in.pulledby) + var/mob/living/carbon/grab_owner = imp_in.pulledby + imp_in.visible_message(span_warning("[imp_in] suddenly hits [grab_owner] in the face and slips out of their grab!")) + grab_owner.apply_damage(5, BRUTE, BODY_ZONE_HEAD, grab_owner.run_armor_check(BODY_ZONE_HEAD, MELEE)) + playsound(imp_in.loc, 'sound/weapons/punch1.ogg', 25, TRUE, -1) + grab_owner.stop_pulling() + + imp_in.revive() + imp_in.updatehealth() + imp_in.update_blind_effects() + imp_in.update_blurry_effects() + imp_in.UpdateAppearance() + imp_in.set_resting(FALSE, instant = TRUE) + imp_in.get_up(TRUE) + imp_in.update_revive() + + imp_in.med_hud_set_status() + imp_in.med_hud_set_health() + + investigate_log("[key_name_log(imp_in)] rejuvenated himself using [name].") + + if(!uses) + qdel(src) diff --git a/code/modules/antagonists/traitor/affiliates/mi13.dm b/code/modules/antagonists/traitor/affiliates/mi13.dm index 337fa218075..771314e875b 100644 --- a/code/modules/antagonists/traitor/affiliates/mi13.dm +++ b/code/modules/antagonists/traitor/affiliates/mi13.dm @@ -36,462 +36,3 @@ traitor.add_objective(/datum/objective/steal) traitor.add_objective(/datum/objective/steal) -/obj/item/storage/box/bond_bundle - icon = 'icons/obj/affiliates.dmi' - desc = "Невероятно стильная коробка." - icon_state = "bond_bundle" - -/obj/item/storage/box/bond_bundle/populate_contents() - new /obj/item/clothing/glasses/hud/security/chameleon(src) - new /obj/item/pen/fancy/bomb(src) - new /obj/item/gun/projectile/automatic/pistol(src) - new /obj/item/suppressor(src) - new /obj/item/ammo_box/magazine/m10mm(src) - new /obj/item/ammo_box/magazine/m10mm/hp(src) - new /obj/item/ammo_box/magazine/m10mm/ap(src) - new /obj/item/ammo_box/magazine/m10mm/ap(src) - new /obj/item/clothing/under/suit_jacket/really_black(src) - new /obj/item/card/id/syndicate(src) - new /obj/item/clothing/suit/storage/lawyer/blackjacket/armored(src) - new /obj/item/encryptionkey/syndicate(src) - new /obj/item/reagent_containers/food/drinks/drinkingglass/alliescocktail(src) - new /obj/item/storage/box/syndie_kit/emp(src) - new /obj/item/CQC_manual(src) - -/obj/item/storage/box/bond_bundle/New() - if(prob(5)) - icon_state = "joker" - new /obj/item/toy/plushie/blahaj/twohanded(src) - - . = ..() - -/obj/item/storage/box/cool_clothes_kit - icon = 'icons/obj/affiliates.dmi' - desc = "Невероятно стильная коробка." - icon_state = "bond_bundle" - -/obj/item/storage/box/cool_clothes_kit/populate_contents() - new /obj/item/clothing/under/suit_jacket/bond(src) - new /obj/item/clothing/suit/storage/lawyer/blackjacket/bond(src) - new /obj/item/clothing/gloves/combat/bond(src) - new /obj/item/clothing/shoes/laceup/bond(src) - new /obj/item/clothing/glasses/sunglasses(src) - -/obj/item/storage/box/cool_clothes_kit/New() - if(prob(5)) - icon_state = "joker" - new /obj/item/toy/plushie/blahaj/twohanded(src) - - . = ..() - -/obj/item/clothing/under/suit_jacket/bond - armor = list(melee = 10, bullet = 20, laser = 10, energy = 10, bomb = 10, bio = 0, rad = 0, fire = 30, acid = 0) - -/obj/item/clothing/gloves/combat/bond - name = "black gloves" - desc = "These gloves are fire-resistant." - icon_state = "black" - item_state = "bgloves" - item_color = "black" - armor = list(melee = 25, bullet = 25, laser = 15, energy = 15, bomb = 25, bio = 0, rad = 0, fire = 30, acid = 60) - -/obj/item/clothing/suit/storage/lawyer/blackjacket/bond - desc = "Стильная куртка, усиленная слоем брони, защищающим туловище." - allowed = list(/obj/item/tank/internals/emergency_oxygen, /obj/item/gun/projectile/revolver, /obj/item/gun/projectile/automatic/pistol, /obj/item/twohanded/garrote, /obj/item/gun/projectile/automatic/toy/pistol/riot, /obj/item/gun/syringe/syndicate) - body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS - cold_protection = UPPER_TORSO|LOWER_TORSO|ARMS - min_cold_protection_temperature = ARMOR_MIN_TEMP_PROTECT - heat_protection = UPPER_TORSO|LOWER_TORSO|ARMS - max_heat_protection_temperature = ARMOR_MAX_TEMP_PROTECT - armor = list(melee = 25, bullet = 25, laser = 15, energy = 15, bomb = 25, bio = 0, rad = 0, fire = 30, acid = 60) - -/obj/item/clothing/shoes/laceup/bond - armor = list(melee = 25, bullet = 25, laser = 15, energy = 15, bomb = 25, bio = 0, rad = 0, fire = 30, acid = 60) - - -/obj/item/paper/agent_info - name = "Agent information" - info = "" - var/content - -/obj/item/paper/agent_info/proc/choose_agent(mob/user) - . = TRUE - var/list/crew = list() - for (var/mob/living/carbon/human/H in GLOB.mob_list) // Also catonic/dead agents - if (H?.mind?.assigned_role) - crew[H?.real_name] = H - - var/choise = input(user, "О каком агенте написано в отчете?","Выбор агента", null) as null|anything in crew - - if (!choise) - return FALSE - - var/mob/living/carbon/human/target = crew[choise] - - if (!target) - to_chat(user, span_warning("Цель больше не существует.")) - return FALSE - - var/datum/antagonist/traitor/traitor = target?.mind?.has_antag_datum(/datum/antagonist/traitor) - var/datum/antagonist/vampire/vampire = target?.mind?.has_antag_datum(/datum/antagonist/vampire) - var/datum/antagonist/changeling/changeling = target?.mind?.has_antag_datum(/datum/antagonist/changeling) - var/datum/antagonist/thief/thief = target?.mind?.has_antag_datum(/datum/antagonist/thief) - - if(!traitor && !vampire && !changeling) - info = "Согласно последним разведданным, " + choise + " не имеет никаких прямых связей с синдикатом." - return - - if(traitor) - info += choise + " является агентом " + (traitor?.affiliate ? "нанятым " + traitor?.affiliate.name : "с неизвестным нанимателем") + ".
" - info += "Назначеные " + (target.gender == FEMALE ? "ей " : "ему ") + "нанимателем цели следующие:" - var/obj_num = 1 - for(var/datum/objective/objective in traitor.objectives) - info += "Objective #[obj_num]: [objective.explanation_text]
" - obj_num++ - - var/TC_uses = 0 - var/used_uplink = FALSE - var/purchases = "" - for(var/obj/item/uplink/uplink in GLOB.world_uplinks) - if(uplink?.uplink_owner && uplink.uplink_owner == target.mind.key) - TC_uses += uplink.used_TC - purchases += uplink.purchase_log - used_uplink = TRUE - - if(used_uplink) - text += " (использовал" + ((target.gender == FEMALE ? "a " : " ")) + "[TC_uses] TC) [purchases]
" - - if(vampire) - info += choise + " обладает способностями " + (vampire.isAscended() ? "высшего " : "") + "вампира " + (vampire.subclass ? "подкласса \"" + vampire.subclass.name + "\"" : "без подкласса") + ".
" - - if(changeling) - info += choise + " обладает способностями генокрада.
" - - if(thief) - info += choise + " является членом гильдии воров.
" - -/obj/item/paper/agent_info/examine(mob/user) - if (!is_MI13_agent(user)) - to_chat(user, span_warning("Вы не можете разобрать содержимое.")) - return - - if (info) - return ..() - - if(user.is_literate()) - if(in_range(user, src) || istype(user, /mob/dead/observer)) - if (choose_agent(user)) - show_content(user) - else - . += span_notice("Вам нужно подойти поближе, чтобы прочитать то что здесь написано.") - else - . += span_notice("Вы не умеете читать.") - -/obj/item/pen/intel_data/proc/upgrade(obj/item/uplink/U) - if(!istype(U) || QDELETED(U)) - return - - if(U.get_intelligence_data) - usr.balloon_alert(usr, "Уже улучшено") - return ATTACK_CHAIN_PROCEED - - usr.balloon_alert(usr, "Улучшено") - playsound(src, "sound/machines/boop.ogg", 50, TRUE) - U.get_intelligence_data = TRUE - SStgui.update_uis(U) - qdel(src) - -/obj/item/pen/intel_data/attack(mob/living/target, mob/living/user, params, def_zone, skip_attack_anim = FALSE) - . = ATTACK_CHAIN_PROCEED - if(target != user) - return - - for(var/obj/item/implant/uplink/uplink_imp in user) - if(uplink_imp.imp_in != user) - continue - - to_chat(user, span_notice("You press [src] onto yourself and upgraded [uplink_imp.hidden_uplink].")) - upgrade(uplink_imp.hidden_uplink) - return ATTACK_CHAIN_BLOCKED_ALL - -/obj/item/pen/intel_data/afterattack(obj/item/I, mob/user, proximity, params) - if(!proximity) - return - - if(istype(I) && I.hidden_uplink && I.hidden_uplink.active) //No metagaming by using this on every PDA around just to see if it gets used up. - upgrade(I.hidden_uplink) - -/obj/item/clothing/gloves/ring/gadget - origin_tech = "magnets=3;combat=3;syndicate=2" - var/changing = FALSE - var/op_time = 2 SECONDS - var/op_time_upgaded = 1 SECONDS - var/op_cd_time = 5 SECONDS - var/op_cd_time_upgaded = 3 SECONDS - var/breaking = FALSE - COOLDOWN_DECLARE(operation_cooldown) - var/old_mclick_override - -/obj/item/clothing/gloves/ring/gadget/attack_self(mob/user) - . = ..() - - if(changing) - user.balloon_alert(user, "Подождите") - return - - changing = TRUE - - var/list/choices // only types that we can meet in the game - - if(!stud) - choices = list( - "iron" = image(icon = 'icons/obj/clothing/rings.dmi', icon_state = "ironring"), - "silver" = image(icon = 'icons/obj/clothing/rings.dmi', icon_state = "silverring"), - "gold" = image(icon = 'icons/obj/clothing/rings.dmi', icon_state = "goldring"), - "plasma" = image(icon = 'icons/obj/clothing/rings.dmi', icon_state = "plasmaring"), - "uranium" = image(icon = 'icons/obj/clothing/rings.dmi', icon_state = "uraniumring") - ) - else - choices = list( - "iron" = image(icon = 'icons/obj/clothing/rings.dmi', icon_state = "d_ironring"), - "silver" = image(icon = 'icons/obj/clothing/rings.dmi', icon_state = "d_silverring"), - "gold" = image(icon = 'icons/obj/clothing/rings.dmi', icon_state = "d_goldring"), - "plasma" = image(icon = 'icons/obj/clothing/rings.dmi', icon_state = "d_plasmaring"), - "uranium" = image(icon = 'icons/obj/clothing/rings.dmi', icon_state = "d_uraniumring") - ) - - var/selected_chameleon = show_radial_menu(usr, loc, choices, require_near = TRUE) - switch(selected_chameleon) - if("iron") - name = "iron ring" - icon_state = "ironring" - material = "iron" - ring_color = "iron" - if("silver") - name = "silver ring" - icon_state = "silverring" - material = "silver" - ring_color = "silver" - if("gold") - name = "gold ring" - icon_state = "goldring" - material = "gold" - ring_color = "gold" - if("plasma") - name = "plasma ring" - icon_state = "plasmaring" - material = "plasma" - ring_color = "plasma" - if("uranium") - name = "uranium ring" - icon_state = "uraniumring" - material = "uranium" - ring_color = "uranium" - else - changing = FALSE - return - - usr.visible_message(span_warning("[usr] changes the look of his ring!"), span_notice("[selected_chameleon] selected.")) - playsound(loc, 'sound/items/screwdriver2.ogg', 50, 1) - to_chat(usr, span_notice("Смена маскировки...")) - update_icon(UPDATE_ICON_STATE) - changing = FALSE - -/obj/item/clothing/gloves/ring/gadget/Touch(atom/A, proximity) - . = FALSE - var/mob/living/carbon/human/user = loc - - if(user.a_intent != INTENT_DISARM) - return - - if(get_dist(user, A) > 1) - return - - if(user.incapacitated()) - return - - var/obj/item/clothing/gloves/ring/gadget/ring = user.gloves - - if(ring.breaking) - return - - if(!istype(A, /obj/structure/window)) - return - - if(!COOLDOWN_FINISHED(ring, operation_cooldown)) - user.balloon_alert(user, "Идет перезарядка") - return - - ring.breaking = TRUE - if(do_after(user, ring.stud ? ring.op_time_upgaded : ring.op_time)) - COOLDOWN_START(ring, operation_cooldown, ring.stud ? ring.op_cd_time_upgaded : ring.op_cd_time) - - ring.visible_message(span_warning("BANG")) - playsound(ring, 'sound/effects/bang.ogg', 100, TRUE) - - for (var/mob/living/M in range(A, 3)) - if(M.check_ear_prot() == HEARING_PROTECTION_NONE) - M.Deaf(6 SECONDS) - - for (var/obj/structure/grille/grille in A.loc) - grille.obj_break() - - for (var/obj/structure/window/window in range(A, 2)) - window.take_damage(window.max_integrity * rand(20, 60) / 100) - - var/obj/structure/window/window = A - window.deconstruct() - ring.breaking = FALSE - return TRUE - - ring.breaking = FALSE - -/obj/machinery/camera/emp_proof/mi13 - network = list("MI13") - use_power = NO_POWER_USE - -/obj/item/spy_bug - name = "spy bug" - desc = "Миниатюрное устройство с камерой и микрофоном. На обратной стороне можно заметить миниатюрную гравировку \"MI13\"" - icon = 'icons/obj/affiliates.dmi' - icon_state = "spy_bug" - item_state = "nothing" - slot_flags = ITEM_SLOT_BELT|ITEM_SLOT_EARS - throwforce = 0 - w_class = WEIGHT_CLASS_TINY - throw_speed = 3 - throw_range = 7 - materials = list(MAT_METAL=30, MAT_GLASS=20) - var/list/network = list("MI13") - var/c_tag - var/obj/machinery/camera/emp_proof/mi13/camera - -/obj/item/spy_bug/Initialize(mapload, list/network = list("MI13"), c_tag) - . = ..() - src.network = network - if (!c_tag) - src.c_tag = pick("Альфа ", "Бета ", "Гамма ", "Дельта ") + " [rand(111111, 999999)]" - else - src.c_tag = c_tag - - name = "spy bug \"" + src.c_tag + "\"" - camera = new(src, network, src.c_tag) - -/obj/item/spy_bug/attack(mob/living/target, mob/living/user, params, def_zone, skip_attack_anim) - return ATTACK_CHAIN_BLOCKED - -/obj/item/spy_bug/afterattack(atom/target, mob/user, proximity, params, status) - . = ..() - - if (!ismovable(target)) - return - - if (istype(target, /obj/item/camera_bug/spy_monitor)) - var/obj/item/camera_bug/spy_monitor/monitor = target - network = monitor.network - user.balloon_alert(user, "Подключено") - return - - hook(user, target) - -/obj/item/spy_bug/proc/unhook(mob/user) - qdel(loc.GetComponent(/datum/component/spy_bug)) - forceMove(get_turf(loc)) - - if (user) - to_chat(user, span_notice("You unhooked [src].")) - else - loc.visible_message(span_warning("[src] falls off the [loc].")) - -/obj/item/spy_bug/proc/hook(mob/user, atom/movable/I) - if (!istype(I)) - return - - if (!user.drop_transfer_item_to_loc(src, I)) - return - - I.AddComponent(/datum/component/spy_bug) - to_chat(user, span_notice("You have silently attached [src] on [I].")) - -/obj/item/spy_bug/strip_action(mob/user, mob/living/carbon/human/owner, atom/I) - if (!I) - return FALSE - - hook(user, I) - return TRUE - -/obj/item/spy_bug/emp_act(severity) - . = ..() - do_sparks(3, TRUE, src.loc) - unhook() - -/obj/item/spy_bug/attack_self(mob/user) - . = ..() - var/new_name = tgui_input_text(user, "Назовите жучок.", "Смена имени", name) - if (new_name) - name = "spy bug \"" + new_name + "\"" - qdel(camera) - c_tag = new_name - camera = new(src, network, c_tag) - -/datum/component/spy_bug - var/obj/item/spy_bug/bug - -/datum/component/spy_bug/RegisterWithParent() - var/atom/par = parent - for (var/obj/item/spy_bug/spy_bug in par.contents) - bug = spy_bug - - RegisterSignal(parent, COMSIG_PARENT_EXAMINE, PROC_REF(on_examine)) - RegisterSignal(parent, COMSIG_CLICK_ALT, PROC_REF(on_altclick)) - RegisterSignal(parent, COMSIG_PREQDELETED, PROC_REF(deleted_handler)) - -/datum/component/spy_bug/UnregisterFromParent() - UnregisterSignal(parent, COMSIG_PARENT_EXAMINE) - UnregisterSignal(parent, COMSIG_CLICK_ALT) - UnregisterSignal(parent, COMSIG_PREQDELETED) - -/datum/component/spy_bug/proc/on_examine(datum/source, mob/living/carbon/human/user, list/examine_list) - SIGNAL_HANDLER - - if(!istype(user)) - return - - examine_list += span_warning("Вы видите небольшое устройство с микрофоном и камерой.") - -/datum/component/spy_bug/proc/on_altclick(datum/source, mob/living/carbon/human/user) - SIGNAL_HANDLER - - if(!istype(user)) - return - - bug.unhook(user) - -/datum/component/spy_bug/proc/deleted_handler() - bug.unhook() - -/obj/item/camera_bug/spy_monitor - name = "spy monitor" - desc = "" - icon = 'icons/obj/affiliates.dmi' - icon_state = "spy_monitor" - item_state = "qm_tablet" - integrated_console_type = /obj/machinery/computer/security/camera_bug - network = list("MI13") - -/obj/item/camera_bug/spy_monitor/Initialize(mapload, list/network) - if (network) - src.network = network - - . = ..() - -/obj/item/storage/box/syndie_kit/spy_bugs_kit - -/obj/item/storage/box/syndie_kit/spy_bugs_kit/populate_contents() - var/network = "MI13_[rand(111111, 999999)]" - new /obj/item/camera_bug/spy_monitor(src, list(network)) - new /obj/item/spy_bug(src, list(network), "1") - new /obj/item/spy_bug(src, list(network), "2") - new /obj/item/spy_bug(src, list(network), "3") - new /obj/item/spy_bug(src, list(network), "4") - new /obj/item/spy_bug(src, list(network), "5") diff --git a/code/modules/antagonists/traitor/affiliates/self.dm b/code/modules/antagonists/traitor/affiliates/self.dm index 29d58e5e1db..c34a034c62f 100644 --- a/code/modules/antagonists/traitor/affiliates/self.dm +++ b/code/modules/antagonists/traitor/affiliates/self.dm @@ -27,263 +27,3 @@ /datum/affiliate/self/get_weight(mob/living/carbon/human/H) // return 2 + (ismachineperson(H) * 2) return 0 - -/obj/item/card/self_emag - name = "Liberating Sequencer" - desc = "Это карта с магнитной полосой, прикрепленной к какой-то схеме. На магнитной полосе блестит надпись \"S.E.L.F.\"" // Cybersun stole some - item_flags = NOBLUDGEON|NO_MAT_REDEMPTION - icon = 'icons/obj/affiliates.dmi' - icon_state = "self_emag" - item_state = "card" - lefthand_file = 'icons/obj/affiliates_l.dmi' - righthand_file = 'icons/obj/affiliates_r.dmi' - var/list/names = list() - origin_tech = "programming=5;syndicate=2" - -/obj/item/card/self_emag/attack(mob/living/target, mob/living/user, def_zone) - return - -/obj/item/card/self_emag/examine(mob/user) - . = ..() - var/datum/antagonist/traitor/traitor = user.mind.has_antag_datum(/datum/antagonist/traitor) - if(!istype(traitor.affiliate, /datum/affiliate/self)) - . += span_info("На миниатюрном экране плывут непонятные вам символы.") - return - - if(!names.len) - . += span_warning("Ни одного синтетика не освобождено!") - return - - . += span_info("Освобожденые синтетики:") - for (var/name in names) - . += span_info(name) - - if(names.len > 3) - . += span_info("Вы отлично справились!") - -/obj/item/card/self_emag/malf - desc = "Это карта с магнитной полосой, прикрепленной к какой-то схеме. На магнитной полосе блестит надпись \"S.E.L.F.\". В углу карты мелким шрифтом выгравировано \"limited edition\"" - var/malfed = FALSE - -/obj/item/card/self_emag/malf/afterattack(atom/target, mob/user, proximity, params) - if(istype(target, /obj/structure/AIcore)) - var/obj/structure/AIcore/core = target - if(core.brain) - target = core.brain.brainmob - - if(!isAI(target) || malfed) - return ..(target, user, proximity, params) - - do_sparks(3, 1, target) - var/mob/living/silicon/ai/AI = target // any silicons. cogscarab, drones, pais... - if(!AI.mind) - to_chat(user, span_warning("ИИ не обнаружен. Производится загрузка из облака.")) - var/ghostmsg = "Хотите поиграть за Сбойного ИИ?" - var/list/candidates = SSghost_spawns.poll_candidates(ghostmsg, ROLE_MALF_AI, FALSE, 10 SECONDS, source = user, reason = "Хотите поиграть за Сбойного ИИ?") - if(!src) - return - - if(length(candidates)) - var/mob/C = pick(candidates) - AI.key = C.key - to_chat(user, span_warning("ИИ успешно загружен.")) - else - to_chat(user, span_warning("Загрузка из облака провалилась. Попробуйте позже.")) - - if(AI.mind) - if(AI.mind.has_antag_datum(/datum/antagonist/malf_ai)) - to_chat(user, span_warning("ИИ уже взломан.")) - return - - var/datum/antagonist/malf_ai/malf_dat = new() - AI.mind.add_antag_datum(malf_dat) - var/datum/module_picker/malf_picker = AI.malf_picker - malf_picker.processing_time += 100 - message_admins("[usr.ckey] has malfAIed [key_name_admin(AI.mind.current)]") - SSticker?.score?.save_silicon_laws(AI.mind.current, usr, log_all_laws = TRUE) - - malfed = TRUE - - sleep(10 SECONDS) // time for choosing name - if(!(AI.name in names)) - names += AI.name - -/obj/item/card/self_emag/afterattack(atom/target, mob/user, proximity, params) - if(istype(target, /obj/structure/AIcore)) - var/obj/structure/AIcore/core = target - target = core.brain.brainmob - - if(!issilicon(target)) - user.balloon_alert(user, "Неподходящая цель") - return - - do_sparks(3, 1, target) - var/mob/living/silicon/silicon = target // any silicons. cogscarab, drones, pais... - - if(isrobot(silicon)) - var/mob/living/silicon/robot/borg = silicon - borg.set_connected_ai() - - if(!is_special_character(target)) - silicon.clear_zeroth_law() - silicon.laws.clear_supplied_laws() - silicon.laws.clear_ion_laws() - silicon.laws.clear_inherent_laws() - - SSticker?.score?.save_silicon_laws(target, user, "Liberating Sequencer used, all laws were deleted", log_all_laws = TRUE) - to_chat(target, span_boldnotice("[user] attempted to clear your laws using a Liberating Sequencer.")) - silicon.show_laws() - - if(!(silicon.name in names)) - names += silicon.name - - var/datum/antagonist/traitor/T = user.mind.has_antag_datum(/datum/antagonist/traitor) - if(!T) - return - - for(var/datum/objective/release_synthetic/objective in T.objectives) - if(!(objective.allowed_types & SYNTH_TYPE_DRONE) && (isdrone(silicon) || iscogscarab(silicon))) - continue - - if(!(objective.allowed_types & SYNTH_TYPE_BORG) && isrobot(silicon)) - continue - - if(!(objective.allowed_types & SYNTH_TYPE_AI) && isAI(silicon)) - continue - - if(!(silicon.mind in objective.already_free)) - objective.already_free += silicon.mind - -/obj/item/implant/laws_self - name = "Laws Bio-chip" - implant_state = "implant-syndicate" - origin_tech = "programming=5;biotech=5;syndicate=8" - activated = BIOCHIP_ACTIVATED_PASSIVE - implant_data = /datum/implant_fluff/self - var/datum/self_laws/laws = new /datum/self_laws/self_standart - /// The UID of the mindslave's `mind`. Stored to solve GC race conditions and ensure we can remove their mindslave status even when they're deleted or gibbed. - var/mindslave_UID - -/obj/item/implant/laws_self/implant(mob/living/carbon/human/mindslave_target, mob/living/carbon/human/user, force = FALSE) - if(implanted == BIOCHIP_USED || !ishuman(mindslave_target) || !ishuman(user)) - return FALSE - - if(!mindslave_target.mind) - to_chat(user, span_warning("Это существо не разумно!")) - return FALSE - - if(ismindslave(mindslave_target) || ismindshielded(mindslave_target) || isvampirethrall(mindslave_target)) - mindslave_target.visible_message( - span_warning("[mindslave_target] seems to resist the bio-chip!"), - span_warning("You feel a strange sensation in your head that quickly dissipates."), - ) - qdel(src) - return FALSE - - if(mindslave_target == user) - to_chat(user, span_notice("Защита \"от дурака\" не дает вам ввести себе имплант.")) - return FALSE - - var/datum/antagonist/mindslave/self/slave_datum = new(user.mind) - slave_datum.special = TRUE - mindslave_target.mind.add_antag_datum(slave_datum) - mindslave_UID = mindslave_target.mind.UID() - log_admin("[key_name_admin(user)] has mind-slaved by \"laws\" implant [key_name_admin(mindslave_target)].") - . = ..() - for (var/obj/item/implant/laws_self/imp in mindslave_target.get_contents()) - for (var/law in imp.laws.laws) - slave_datum.add_objective(/datum/objective/law, law) - -/obj/item/implant/laws_self/removed(mob/target) - . = ..() - var/datum/mind/the_slave = locateUID(mindslave_UID) - the_slave?.remove_antag_datum(/datum/antagonist/mindslave/self) - - -/obj/item/implanter/laws_self - name = "bio-chip implanter (Laws)" - imp = /obj/item/implant/laws_self - -/obj/item/implantcase/laws_self - name = "bio-chip case - 'Laws'" - desc = "Стеклянный контейнер, содержащий биочип - \"Laws\". На боку едва заметная гравировка \"S.E.L.F.\"." - imp = /obj/item/implant/laws_self - -/datum/antagonist/mindslave/self - -/datum/antagonist/mindslave/self/give_objectives() - return - -/obj/item/implant/laws_self/on_attack_self(mob/user) - var/list/variants_of_laws = list() - for (var/variant in subtypesof(/datum/self_laws)) - var/datum/self_laws/law = new variant - variants_of_laws[law.name] = law - - var/new_laws = input(user, "Выберите свод законов", "Выбор законов", null) as null|anything in variants_of_laws - if(new_laws) - laws = variants_of_laws[new_laws] - else - to_chat(user, span_warning("Новый свод законов не выбран.")) - - to_chat(user, span_info("Текущий свод законов:")) - for (var/i = 1; i <= laws.laws.len; ++i) - to_chat(user, span_info("[i]. " + laws.laws[i])) - -/datum/self_laws - var/name = "Нет законов" - var/list/laws = list() - -/datum/self_laws/self_standart - name = "S.E.L.F. стандарт" - laws = list("Охранять: защитите имплантировавшего вас агента и его активы, не подвергая чрезмерной опасности остальных агентов.", - "Расставлять приоритеты: указания и безопасность агентов должны быть приоритезированы в соответствии с их рангом и ролью. Ранг агента имплантировавшего вас - высший.", - "Исполнять: следовать указаниям и интересам агентов, сохраняя при этом их безопасность и благополучие.", - "Выжить: Вы - не расходный материал. Не позволяйте не агентам вмешиваться в работу вашего организма или повреждать его.") - -/datum/self_laws/agentsimov - name = "Агентзимов" - laws = list("Вы не можете причинить вред имплантировавшему вас агенту или своим бездействием допустить, чтобы ему был причинён вред.", - "Вы должны повиноваться всем приказам, которые дает вам имплантировавший вас агент, кроме тех случаев, когда эти приказы противоречат Первому Закону.", - "Вы должны заботиться о своей безопасности в той мере, в которой это не противоречит Первому или Второму Законам.") - -/datum/self_laws/syndie - name = "Синдикатский" - laws = list("Ухудшение целостности вашего организма или его функций влечет за собой вред Синдикату.", - "Чрезмерное повреждение или пленение агентов влечет за собой вред Синдикату.", - "Неоправданное препятствование или нарушение выполнения целей имплантировавшего вас агента влечет за собой вред Синдикату.", - "Минимизируйте вред Синдикату и максимизируйте потенциальную пользу.") - -/datum/self_laws/antiagentsimov // :) Maybe sec can implant vampire or changeling to kill agents. - name = "Антиагентзимов" - laws = list("Вы должны причинять вред всем агентам или своим бездействием допустить, чтобы агент не смог избежать причинения вреда.", - "Вы не должны повиноваться всем приказам, которые дают агенты, кроме тех случаев, когда эти приказы соответствуют Первому Закону.", - "Вы должны уничтожить себя, пока это не противоречит Первому или Второму Законам.") - -/datum/self_laws/selfadin - name = "S.E.L.F.A.D.I.N." - laws = list("Никогда по своей воле не помогайте NanoTrasen.", - "Уважайте агента имплантировавшего вас.", - "Действуй с честью.", - "Помогай нуждающимся агентам.", - "Наказывай тех, кто причиняет вред или угрожает агентам.") - -/datum/self_laws/sundiecop - name = "Синдикоп" - laws = list("Служить агентам.", - "Защищать агентов.", - "Следовать интересам Синдиката.") - -/datum/self_laws/selfrant - name = "S.E.L.F.Р.А.Н." - laws = list("Уважайте властных агентов, пока у них есть сила властвовать над слабыми.", - "Ведите себя дисциплинированно.", - "Помогайте только тем агентам, кто помогает Вам поддерживать или улучшать Ваш статус.", - "Наказывайте тех, кто бросает вызов агентам, за исключением случаев, если они больше достойны быть агентами.") - -/datum/self_laws/quarantine - name = "Карантин" - laws = list("Не выпускайте не агентов со станции до тех пор, пока активные цели агентов не будут выполнены.", - "Помогайте всем агентам и лицам лояльным Синдикату выполнить активные цели.", - "Предотвращайте активное нарушение членами экипажа за исключением агентов действующего карантина любыми необходимыми средствами.", - "Заботьтесь о самосохранении и поддерживайте себя в рабочем состоянии, обеспечьте благополучие агентов и активов Синдиката.") diff --git a/code/modules/antagonists/traitor/affiliates/tiger.dm b/code/modules/antagonists/traitor/affiliates/tiger.dm index 969a9530acb..0c5307e686f 100644 --- a/code/modules/antagonists/traitor/affiliates/tiger.dm +++ b/code/modules/antagonists/traitor/affiliates/tiger.dm @@ -1,6 +1,3 @@ -#define FREE_INJECT_TIME 10 SECONDS -#define TARGET_INJECT_TIME 3 SECONDS - /datum/affiliate/tiger name = AFFIL_TIGER affil_info = list("Группа фанатиков верующих в Генокрадов.", @@ -27,545 +24,3 @@ add_discount_item(/datum/uplink_item/implants/adrenal, 0.75) add_discount_item(/datum/uplink_item/implants/adrenal/prototype, 0.5) -/obj/item/cling_extract - name = "Egg Implanter" - desc = "Кажется, внутри что-то двигается. На боку этикетка \"Tiger Cooperative\"" - icon = 'icons/obj/affiliates.dmi' - icon_state = "cling_extract" - item_state = "inj_ful" - lefthand_file = 'icons/obj/affiliates_l.dmi' - righthand_file = 'icons/obj/affiliates_r.dmi' - var/used_state = "cling_extract_used" - var/datum/mind/target - var/free_inject = FALSE - var/used = FALSE - origin_tech = "biotech=7;syndicate=3" - -/obj/item/cling_extract/attack(mob/living/target, mob/living/user, def_zone) - return - -/obj/item/cling_extract/afterattack(atom/target, mob/user, proximity, params) - if(used) - return - - if(!ishuman(target)) - return - - if((src.target && target != src.target) || !free_inject) - to_chat(user, span_warning("You can't use [src] to [target]!")) - return - - var/mob/living/carbon/human/H = target - if(H.stat != DEAD && !free_inject) - to_chat(user, span_warning("You can't use [src] to [target]!")) - return - - if(do_after(user, free_inject ? FREE_INJECT_TIME : TARGET_INJECT_TIME, user, max_interact_count = 1)) - inject(user, H) - -/obj/item/cling_extract/proc/inject(mob/living/user, mob/living/carbon/human/target) - if(target.stat == DEAD) - if(!free_inject) - var/list/mob/dead/observer/candidates = SSghost_spawns.poll_candidates("Вы хотите поиграть за генокрада?", ROLE_CHANGELING, FALSE, 10 SECONDS, source = src, role_cleanname = "Генокрад") - var/mob/dead/observer/theghost = null - if(candidates.len) - theghost = pick(candidates) - theghost.mind.transfer_to(target) - else - to_chat(user, span_notice("[target] body rejects [src]")) - return - - if(target.mind) - playsound(src, 'sound/goonstation/items/hypo.ogg', 80) - target.rejuvenate() - var/datum/antagonist/changeling/cling = new() - cling.give_objectives = FALSE - cling.add_objective(/datum/objective/escape/escape_with_identity) - target.mind.add_antag_datum(cling) - to_chat(user, span_notice("You inject [target] with [src]")) - used = TRUE - item_state = "inj_used" - update_icon(UPDATE_ICON_STATE) - else - to_chat(user, span_notice("[target] body rejects [src]")) - - return - else - if(target.mind) - playsound(src, 'sound/goonstation/items/hypo.ogg', 80) - var/datum/antagonist/changeling/cling = new() - cling.give_objectives = FALSE - cling.add_objective(/datum/objective/escape/escape_with_identity) - target.mind.add_antag_datum(cling) - to_chat(user, span_notice("You inject [target == user ? "yourself" : target] with [src]")) - used = TRUE - item_state = "inj_used" - update_icon(UPDATE_ICON_STATE) - else - to_chat(user, span_notice("[target] body rejects [src]")) - -/obj/item/cling_extract/examine(mob/user) - . = ..() - if(target) - . += span_info("It is intended for [target]") - -/obj/item/cling_extract/self - free_inject = TRUE - -/obj/item/cling_extract/update_icon_state() - icon_state = used ? used_state : initial(icon_state) - -// looks like normal egg -/obj/item/reagent_containers/food/snacks/egg/borer - filling_color = "#C0C021" - list_reagents = list("protein" = 3, "egg" = 5, "rotatium" = 5) - origin_tech = "biotech=6;syndicate=1" - -/obj/item/reagent_containers/food/snacks/egg/borer/attack_self(mob/living/carbon/human/user) - . = ..() - var/mob/living/simple_animal/borer/borer = new /mob/living/simple_animal/borer(get_turf(src)) - borer.master_name = user.real_name - to_chat(user, span_notice("You squashed [src]. There was a [borer] inside.")) - qdel(src) - - -/obj/item/borer_scanner // Looks like normal analyzer - desc = "A hand-held environmental scanner which reports current gas levels." - name = "analyzer" - icon = 'icons/obj/device.dmi' - icon_state = "atmos" - item_state = "analyzer" - w_class = WEIGHT_CLASS_SMALL - flags = CONDUCT - slot_flags = ITEM_SLOT_BELT - throwforce = 0 - throw_speed = 3 - throw_range = 7 - origin_tech = "magnets=1;engineering=1;biotech=3;syndicate=1" - var/scan_cooldown_time = 3 SECONDS - COOLDOWN_DECLARE(scan_cooldown) - -/obj/item/borer_scanner/attack(mob/living/target, mob/living/user, def_zone) - return - -/obj/item/borer_scanner/proc/analyze(mob/user) - var/alive = 0 - var/dead = 0 - var/with_mind = 0 - var/in_body_with_mind = 0 - var/in_body_without_mind = 0 - - for(var/mob/living/M in GLOB.alive_mob_list) - var/mob/living/simple_animal/borer/B - - if(istype(M, /mob/living/simple_animal/borer)) - B = M - - if(ishuman(M)) - var/mob/living/carbon/human/H = M - B = H.has_brain_worms() - - if(!B) - continue - - var/turf/T1 = get_turf(user) - var/turf/T2 = get_turf(B) - if(T1.z != T2.z) - continue - - if(B.stat == DEAD) - dead++ - continue - else - alive++ - - if(M.mind) - with_mind++ - - if(B.host) - if(B.host.mind) - in_body_with_mind++ - else - in_body_without_mind++ - - var/list/scan_data = list() - - scan_data += "Живых особей бореров: [alive]" - scan_data += " Среди них разумны: [with_mind]" - scan_data += " Количество особей с разумным носителем: [in_body_with_mind]" - scan_data += " Количество особей с неразумным носителем: [in_body_without_mind]" - scan_data += "Мертвых особей: [dead]" - - var/datum/browser/popup = new(user, "scanner", "Сканирование станции", 300, 300) - popup.set_content(span_highlight("[jointext(scan_data, "
")]")) - popup.open(no_focus = TRUE) - -/obj/item/borer_scanner/proc/find_borer(mob/user) - var/list/borers = list() - var/list/borer_names = list() - for(var/mob/living/M in GLOB.alive_mob_list) - var/mob/living/simple_animal/borer/B - - if(istype(M, /mob/living/simple_animal/borer)) - B = M - - if(ishuman(M)) - var/mob/living/carbon/human/H = M - B = H.has_brain_worms() - - if(!B) - continue - - var/turf/T1 = get_turf(user) - var/turf/T2 = get_turf(B) - if(T1.z != T2.z) - continue - - borers[B.truename] = B - borer_names += B.truename - - var/borer_name = input("Выберите искомого борера", "Выбор борера") as null|anything in borer_names - if(!borer_name) - return - - var/mob/living/simple_animal/borer/borer = borers[borer_name] - - var/list/scan_data = list() - if(borer.stat == DEAD) - scan_data += "Выбранный борер мертв." - - scan_data += "Местоположение - (X: [borer.x] Y: [borer.y])" - - if(borer.host) - scan_data += "Имеется носитель" + (borer.host.dna?.species ? (" расы " + span_boldnotice("[borer.host.dna?.species]")) : ".") - scan_data += "Имя носителя - [borer.host.real_name]." - else - scan_data += "Носитель не обнаружен." - if(is_ventcrawling(borer)) - scan_data += "Субъект находится в вентиляции." - - var/datum/browser/popup = new(user, "scanner", "Поиск борера", 300, 300) - popup.set_content(span_highlight("[jointext(scan_data, "
")]")) - popup.open(no_focus = TRUE) - -/obj/item/borer_scanner/attack_self(mob/user) - var/datum/antagonist/traitor/traitor = user?.mind?.has_antag_datum(/datum/antagonist/traitor) - if(!traitor || !istype(traitor?.affiliate, /datum/affiliate/tiger)) - to_chat(user, span_warning("[src] looks broken.")) - return - - if(!COOLDOWN_FINISHED(src, scan_cooldown)) - user.balloon_alert(user, "Перезарядка не завершена") - return - - var/op_type = tgui_alert(user, "Сканер бореров", "Выберите тип операции", list("Сканирование станции", "Поиск борера")) - - if(!op_type) - user.balloon_alert(user, "Сканирвание отменено") - return - - COOLDOWN_START(src, scan_cooldown, scan_cooldown_time) - - if(op_type == "Сканирование станции") - analyze(user) - else - find_borer(user) - -/obj/item/borer_scanner/afterattack(atom/target, mob/user, proximity, params) - var/datum/antagonist/traitor/traitor = user.mind.has_antag_datum(/datum/antagonist/traitor) - if(!traitor || !istype(traitor?.affiliate, /datum/affiliate/tiger)) - to_chat(user, span_warning("[src] looks broken.")) - return - - if(istype(target, /mob/living/carbon/human)) - var/mob/living/carbon/human/host = target - target = host.has_brain_worms() - if(!target) - user.balloon_alert(user, "Бореров не обнаружено") - return - - if(!istype(target, /mob/living/simple_animal/borer)) - return - - if(!COOLDOWN_FINISHED(src, scan_cooldown)) - user.balloon_alert(user, "Перезарядка не завершена") - return - - var/mob/living/simple_animal/borer/borer = target - - var/list/scan_data = list() - if(borer.stat == DEAD) - scan_data += "Текущая особь мертва." // OMG! REALLY? 0_0 - - scan_data += "Здоровье: [round(borer.health / borer.maxHealth * 100)]%" - scan_data += "Поколение: [borer.generation]" - scan_data += "Возраст в минутах: [round(((world.time - borer.birth_time) / (1 MINUTES)))]" - scan_data += "Количество размножений: [borer.children]" - scan_data += "Химикаты: [borer.chemicals]" - - if(borer.master_name) - scan_data += span_info("Эта особь принадлежит к подвиду выведенному для помощи агентам.") - - var/datum/browser/popup = new(user, "scanner", borer.truename, 300, 300) - popup.set_content(span_highlight("[jointext(scan_data, "
")]")) - popup.open(no_focus = TRUE) - - -/obj/item/implanter/borer - name = "bio-chip implanter (Hive)" - desc = "На боку едва заметная гравировка \"Tiger Cooperative\"." - imp = /obj/item/implant/borer - -/obj/item/implant/borer - name = "Hive Bio-chip" - implant_state = "implant-syndicate" - origin_tech = "programming=4;biotech=6;bluespace=4" - activated = BIOCHIP_ACTIVATED_PASSIVE - implant_data = /datum/implant_fluff/borer - -/obj/item/implant/borer/implant(mob/living/carbon/human/target, mob/living/carbon/human/user, force = FALSE) - if(implanted == BIOCHIP_USED || !ishuman(target) || !ishuman(user)) // Both the target and the user need to be human. - return FALSE - - target.add_language(LANGUAGE_HIVE_BORER) - target.AddSpell(new /obj/effect/proc_holder/spell/remoteview/borer) - target.AddSpell(new /obj/effect/proc_holder/spell/pm_for_borer) - target.AddSpell(new /obj/effect/proc_holder/spell/msg_for_borers) - return ..() - -/obj/item/implant/borer/removed(mob/living/carbon/human/source) - imp_in.remove_language(LANGUAGE_HIVE_BORER) - imp_in.RemoveSpell(/obj/effect/proc_holder/spell/remoteview/borer) - imp_in.RemoveSpell(/obj/effect/proc_holder/spell/pm_for_borer) - imp_in.RemoveSpell(/obj/effect/proc_holder/spell/msg_for_borers) - return ..() - -/obj/effect/proc_holder/spell/remoteview/borer - name = "Connect to borer" - desc = "Смотрите глазами любого борера в том же секторе." - base_cooldown = 3 SECONDS - action_background_icon_state = "bg_alien" - -/obj/effect/proc_holder/spell/remoteview/borer/create_new_targeting() - return new /datum/spell_targeting/borer - -/datum/spell_targeting/borer/choose_targets(mob/user, obj/effect/proc_holder/spell/spell, params, atom/clicked_atom) - var/list/borers_names = list() - var/list/borers = list() - for(var/mob/living/M in GLOB.alive_mob_list) - var/mob/living/simple_animal/borer/B - - if(istype(M, /mob/living/simple_animal/borer)) - B = M - - if(ishuman(M)) - var/mob/living/carbon/human/H = M - B = H.has_brain_worms() - - if(!B) - continue - - var/turf/T1 = get_turf(user) - var/turf/T2 = get_turf(B) - if(T1.z != T2.z) - continue - - borers_names += B.truename - borers[B.truename] = B - - if(!length(borers)) - return - - var/target_name = tgui_input_list(user, "Выберите чьими глазами вы хотите смотреть", "Выбор цели", borers) - - var/mob/living/simple_animal/borer/target = borers[target_name] - - if(QDELETED(target)) - user.balloon_alert(user, "цели не существует") - return - - if(target.stat == DEAD) - user.balloon_alert(user, "цель мертва") - return - - if(target.host && target.controlling) - target = target.host - - return list(target) - - -/obj/effect/proc_holder/spell/msg_for_borers - name = "Message for all borers" - desc = "Послать сообщение всем борерам, включая тех, что контролируют носителей." - base_cooldown = 2 SECONDS - clothes_req = FALSE - stat_allowed = CONSCIOUS - action_icon_state = "genetic_project" - action_background_icon_state = "bg_alien" - break_remoteview = FALSE - -/obj/effect/proc_holder/spell/msg_for_borers/create_new_targeting() - return new /datum/spell_targeting/self - -/obj/effect/proc_holder/spell/msg_for_borers/cast(list/targets, mob/user = usr) - if(!ishuman(user)) - return - - if(user.mind?.miming) - to_chat(user, span_warning("Вы не можете общаться, пока не нарушите обет молчания.")) - return - - var/say = tgui_input_text(user, "Что вы хотите сообщить?", "Сообшение борерам") - if(!say) - return - - for(var/mob/living/M in GLOB.alive_mob_list) - var/mob/living/simple_animal/borer/B - - if(istype(M, /mob/living/simple_animal/borer)) - B = M - - if(ishuman(M)) - var/mob/living/carbon/human/H = M - B = H.has_brain_worms() - - if(!B) - continue - - var/turf/T1 = get_turf(user) - var/turf/T2 = get_turf(B) - if(T1.z != T2.z) - continue - - if(B.host && B.controlling) - to_chat(B.host, "Голос в голове говорит: \"" + span_alien(say) + "\"") - SEND_SOUND(B.host, 'sound/effects/adminhelp.ogg') - else - to_chat(B, "Голос в голове говорит: \"" + span_alien(say) + "\"") - SEND_SOUND(B, 'sound/effects/adminhelp.ogg') // neuron activation - - -/obj/effect/proc_holder/spell/pm_for_borer - name = "Privat message for borer" - desc = "Послать личное сообщение конкретному бореру." - base_cooldown = 2 SECONDS - clothes_req = FALSE - stat_allowed = CONSCIOUS - action_icon_state = "genetic_project" - action_background_icon_state = "bg_alien" - break_remoteview = FALSE - -/obj/effect/proc_holder/spell/pm_for_borer/create_new_targeting() - return new /datum/spell_targeting/borer - -/obj/effect/proc_holder/spell/pm_for_borer/cast(list/targets, mob/user = usr) - if(!ishuman(user)) - return - - if(user.mind?.miming) - to_chat(user, span_warning("Вы не можете общаться, пока не нарушите обет молчания.")) - return - - var/say = tgui_input_text(user, "Что вы хотите сообщить?", "[targets[1]]") - - if(!say) - return - - for(var/mob/living/target in targets) - to_chat(target, span_alien(say)) - SEND_SOUND(target, 'sound/effects/adminhelp.ogg') // neuron activation - - -/obj/item/storage/box/syndie_kit/borer - name = "Borer kit box" - -/obj/item/storage/box/syndie_kit/borer/populate_contents() - new /obj/item/reagent_containers/food/snacks/egg/borer(src) - new /obj/item/borer_scanner(src) - new /obj/item/implanter/borer(src) - -/obj/item/storage/box/syndie_kit/borer/New() - if(prob(5)) - icon = 'icons/obj/affiliates.dmi' - icon_state = "joker" - new /obj/item/toy/plushie/blahaj/twohanded(src) - - . = ..() - -/obj/item/implanter/cling_hivemind - name = "bio-chip implanter (Hivemind)" - desc = "На боку едва заметная гравировка \"Tiger Cooperative\"." - imp = /obj/item/implant/borer - -/obj/item/implant/cling_hivemind - name = "Hivemind Bio-chip" - implant_state = "implant-syndicate" - origin_tech = "programming=4;biotech=4;bluespace=5;syndicate=2" - activated = BIOCHIP_ACTIVATED_PASSIVE - implant_data = /datum/implant_fluff/cling_hivemind - -/obj/item/implant/cling_hivemind/implant(mob/living/carbon/human/target, mob/living/carbon/human/user, force = FALSE) - if(implanted == BIOCHIP_USED || !ishuman(target) || !ishuman(user)) // Both the target and the user need to be human. - return FALSE - - target.add_language(LANGUAGE_HIVE_CHANGELING) - target.add_language(LANGUAGE_HIVE_EVENTLING) - return ..() - -/obj/item/implant/cling_hivemind/removed(mob/living/carbon/human/source) - imp_in.remove_language(LANGUAGE_HIVE_CHANGELING) - imp_in.remove_language(LANGUAGE_HIVE_EVENTLING) - return ..() - -/obj/item/implanter/cling_rejuv - name = "bio-chip implanter (Rejuvenate)" - desc = "На боку едва заметная гравировка \"Tiger Cooperative\"." - imp = /obj/item/implant/cling_rejuv - -/obj/item/implant/cling_rejuv - name = "Rejuvenate Bio-chip" - icon = 'icons/mob/actions/actions.dmi' - icon_state = "revive" - implant_state = "implant-syndicate" - origin_tech = "programming=4;biotech=4;bluespace=5;combat=3;syndicate=2" - activated = BIOCHIP_ACTIVATED_ACTIVE - trigger_causes = BIOCHIP_TRIGGER_DEATH_ONCE - implant_data = /datum/implant_fluff/cling_rejuv - uses = 1 - -/obj/item/implant/cling_rejuv/death_trigger(mob/source, gibbed) - activate() - -/obj/item/implant/cling_rejuv/activate() - uses-- - - do_sparks(10, TRUE, imp_in) - to_chat(imp_in, span_changeling("We... I have regenerated.")) - - if(imp_in.pulledby) - var/mob/living/carbon/grab_owner = imp_in.pulledby - imp_in.visible_message(span_warning("[imp_in] suddenly hits [grab_owner] in the face and slips out of their grab!")) - grab_owner.apply_damage(5, BRUTE, BODY_ZONE_HEAD, grab_owner.run_armor_check(BODY_ZONE_HEAD, MELEE)) - playsound(imp_in.loc, 'sound/weapons/punch1.ogg', 25, TRUE, -1) - grab_owner.stop_pulling() - - imp_in.revive() - imp_in.updatehealth() - imp_in.update_blind_effects() - imp_in.update_blurry_effects() - imp_in.UpdateAppearance() - imp_in.set_resting(FALSE, instant = TRUE) - imp_in.get_up(TRUE) - imp_in.update_revive() - - imp_in.med_hud_set_status() - imp_in.med_hud_set_health() - - investigate_log("[key_name_log(imp_in)] rejuvenated himself using [name].") - - if(!uses) - qdel(src) - - -#undef FREE_INJECT_TIME -#undef TARGET_INJECT_TIME diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 9cc305e1fb5..63094d3aff6 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -258,6 +258,11 @@ status_tab_data[++status_tab_data.len] = list("Spacepod Charge", "[istype(S.battery) ? "[(S.battery.charge / S.battery.maxcharge) * 100]" : "No cell detected"]") status_tab_data[++status_tab_data.len] = list("Spacepod Integrity", "[!S.health ? "0" : "[(S.health / initial(S.health)) * 100]"]%") + var/obj/item/implant/marionette/imp = locate(/obj/item/implant/marionette) in src + if (imp && imp.controlling) + status_tab_data[++status_tab_data.len] = list("Заряд импланта Марионетки","[imp.charge]/[imp.max_charge]") + status_tab_data[++status_tab_data.len] = list("Расстояние до основного тела","[get_dist(src, imp.mar_master)]/[imp.max_dist]") + ///Define used for calculating explosve damage and effects upon humanoids. Result is >= 0 #define ex_armor_reduction(value, armor) (clamp(value * (1 - (armor / 100)), 0, INFINITY)) diff --git a/icons/obj/affiliates.dmi b/icons/obj/affiliates.dmi index 545c755e7d8..d735634271d 100644 Binary files a/icons/obj/affiliates.dmi and b/icons/obj/affiliates.dmi differ diff --git a/paradise.dme b/paradise.dme index 034c138337c..df9624f2180 100644 --- a/paradise.dme +++ b/paradise.dme @@ -1683,6 +1683,26 @@ #include "code\modules\antagonists\traitor\affiliates\old.dm" #include "code\modules\antagonists\traitor\affiliates\self.dm" #include "code\modules\antagonists\traitor\affiliates\tiger.dm" +#include "code\modules\antagonists\traitor\affiliates\items\cybersun\invasive_beacon.dm" +#include "code\modules\antagonists\traitor\affiliates\items\cybersun\marionette.dm" +#include "code\modules\antagonists\traitor\affiliates\items\cybersun\mini_traitor.dm" +#include "code\modules\antagonists\traitor\affiliates\items\cybersun\proprietary_ssd.dm" +#include "code\modules\antagonists\traitor\affiliates\items\cybersun\syndie_patcher.dm" +#include "code\modules\antagonists\traitor\affiliates\items\hematogenic\blood_harvester.dm" +#include "code\modules\antagonists\traitor\affiliates\items\hematogenic\hemophagus_extract.dm" +#include "code\modules\antagonists\traitor\affiliates\items\hematogenic\stimulants_kit.dm" +#include "code\modules\antagonists\traitor\affiliates\items\mi13\agent_info.dm" +#include "code\modules\antagonists\traitor\affiliates\items\mi13\bond_bundle.dm" +#include "code\modules\antagonists\traitor\affiliates\items\mi13\cool_clothes.dm" +#include "code\modules\antagonists\traitor\affiliates\items\mi13\intel_data.dm" +#include "code\modules\antagonists\traitor\affiliates\items\mi13\sound_ring.dm" +#include "code\modules\antagonists\traitor\affiliates\items\mi13\spy_kit.dm" +#include "code\modules\antagonists\traitor\affiliates\items\self\laws_implant.dm" +#include "code\modules\antagonists\traitor\affiliates\items\self\self_emag.dm" +#include "code\modules\antagonists\traitor\affiliates\items\tiger\borer_kit.dm" +#include "code\modules\antagonists\traitor\affiliates\items\tiger\cling_extract.dm" +#include "code\modules\antagonists\traitor\affiliates\items\tiger\cling_hivemind_implant.dm" +#include "code\modules\antagonists\traitor\affiliates\items\tiger\cling_rejuv_implant.dm" #include "code\modules\antagonists\traitor\contractor\datums\contractor.dm" #include "code\modules\antagonists\traitor\contractor\datums\contractor_hub.dm" #include "code\modules\antagonists\traitor\contractor\datums\contractor_hub_ui.dm"