From e61df669d703c5b7c2b5ac30499d113d5583ac53 Mon Sep 17 00:00:00 2001 From: EgorDinamit <53223414+EgorDinamit@users.noreply.github.com> Date: Sun, 28 Jan 2024 17:28:35 +0300 Subject: [PATCH] Mind Engraver, Dominion Tech (#506) * Mind Engraver, Dominion Tech * Fixes! * Density updating * More tweaks & updates * Async on GoOut() * fix linking * Buff random skills nanochip * Minor tweaks * Fluff engraver memory nanochip --- baystation12.dme | 4 + code/__defines/research.dm | 23 +- .../computer/mind_engraver_control.dm | 106 ++++++ code/game/machinery/mind_engraver.dm | 310 ++++++++++++++++++ .../items/devices/mind_engraver_chip.dm | 293 +++++++++++++++++ .../circuitboards/computer/computer.dm | 10 + .../circuitboards/machinery/mind_engraver.dm | 13 + code/game/objects/objs.dm | 4 + code/game/objects/structures.dm | 4 - code/modules/mob/living/living.dm | 6 +- .../research/designs/designs_circuits.dm | 36 +- code/modules/research/part_replacer.dm | 4 +- code/modules/research/research.dm | 7 +- icons/obj/machines/mind_engraver.dmi | Bin 0 -> 6577 bytes 14 files changed, 793 insertions(+), 27 deletions(-) create mode 100644 code/game/machinery/computer/mind_engraver_control.dm create mode 100644 code/game/machinery/mind_engraver.dm create mode 100644 code/game/objects/items/devices/mind_engraver_chip.dm create mode 100644 code/game/objects/items/weapons/circuitboards/machinery/mind_engraver.dm create mode 100644 icons/obj/machines/mind_engraver.dmi diff --git a/baystation12.dme b/baystation12.dme index b3f1f1a927b..31026a8d5dc 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -736,6 +736,7 @@ #include "code\game\machinery\magnet.dm" #include "code\game\machinery\mass_driver.dm" #include "code\game\machinery\mech_recharger.dm" +#include "code\game\machinery\mind_engraver.dm" #include "code\game\machinery\navbeacon.dm" #include "code\game\machinery\newscaster.dm" #include "code\game\machinery\nuclear_bomb.dm" @@ -821,6 +822,7 @@ #include "code\game\machinery\computer\guestpass.dm" #include "code\game\machinery\computer\law.dm" #include "code\game\machinery\computer\message.dm" +#include "code\game\machinery\computer\mind_engraver_control.dm" #include "code\game\machinery\computer\Operating.dm" #include "code\game\machinery\computer\pandemic.dm" #include "code\game\machinery\computer\prisoner.dm" @@ -986,6 +988,7 @@ #include "code\game\objects\items\devices\lightreplacer.dm" #include "code\game\objects\items\devices\megaphone.dm" #include "code\game\objects\items\devices\microlaser_radioactive.dm" +#include "code\game\objects\items\devices\mind_engraver_chip.dm" #include "code\game\objects\items\devices\modkit.dm" #include "code\game\objects\items\devices\multitool.dm" #include "code\game\objects\items\devices\oxycandle.dm" @@ -1104,6 +1107,7 @@ #include "code\game\objects\items\weapons\circuitboards\machinery\household.dm" #include "code\game\objects\items\weapons\circuitboards\machinery\mech_recharger.dm" #include "code\game\objects\items\weapons\circuitboards\machinery\medical.dm" +#include "code\game\objects\items\weapons\circuitboards\machinery\mind_engraver.dm" #include "code\game\objects\items\weapons\circuitboards\machinery\mining.dm" #include "code\game\objects\items\weapons\circuitboards\machinery\mining_drill.dm" #include "code\game\objects\items\weapons\circuitboards\machinery\oxyregenerator.dm" diff --git a/code/__defines/research.dm b/code/__defines/research.dm index 722c17cff6b..a13d01887af 100644 --- a/code/__defines/research.dm +++ b/code/__defines/research.dm @@ -1,19 +1,20 @@ #define SHEET_MATERIAL_AMOUNT 2000 -#define TECH_MATERIAL "materials" -#define TECH_ENGINEERING "engineering" -#define TECH_PHORON "phorontech" -#define TECH_POWER "powerstorage" -#define TECH_BLUESPACE "bluespace" -#define TECH_BIO "biotech" -#define TECH_COMBAT "combat" -#define TECH_MAGNET "magnets" -#define TECH_DATA "programming" -#define TECH_ESOTERIC "esoteric" +#define TECH_MATERIAL "materials" +#define TECH_ENGINEERING "engineering" +#define TECH_PHORON "phorontech" +#define TECH_POWER "powerstorage" +#define TECH_BLUESPACE "bluespace" +#define TECH_BIO "biotech" +#define TECH_COMBAT "combat" +#define TECH_MAGNET "magnets" +#define TECH_DATA "programming" +#define TECH_ESOTERIC "esoteric" +#define TECH_DOMINION "dominion" #define IMPRINTER 0x1 //For circuits. Uses glass/chemicals. #define PROTOLATHE 0x2 //New stuff. Uses glass/metal/chemicals #define MECHFAB 0x4 //Mechfab #define CHASSIS 0x8 //For protolathe, but differently -#define T_BOARD(name) "circuit board (" + (name) + ")" \ No newline at end of file +#define T_BOARD(name) "circuit board (" + (name) + ")" diff --git a/code/game/machinery/computer/mind_engraver_control.dm b/code/game/machinery/computer/mind_engraver_control.dm new file mode 100644 index 00000000000..82ff9a5d5a1 --- /dev/null +++ b/code/game/machinery/computer/mind_engraver_control.dm @@ -0,0 +1,106 @@ +/obj/machinery/computer/mind_engraver_control + name = "mind engraver control console" + density = TRUE + anchored = TRUE + icon_keyboard = "generic_key" + icon_screen = "holocontrol" + machine_name = "mind engraver control console" + machine_desc = "A control console used to interface with the mind engraver." + + var/obj/machinery/mind_engraver/linked_engraver = null + var/model_name = "Mind Engraver v1.3" + var/model_producer = "Terran Dominion" + +/obj/machinery/computer/mind_engraver_control/Initialize() + . = ..() + for(var/obj/machinery/mind_engraver/ME in range(src, 1)) + LinkEngraver(ME) + break + +/obj/machinery/computer/mind_engraver_control/Destroy() + linked_engraver = null + return ..() + +/obj/machinery/computer/mind_engraver_control/attackby(obj/item/I, mob/user) + if(istype(I, /obj/item/mind_engraver_chip)) + to_chat(user, SPAN_WARNING("\The [I] must be inserted in the mind engraver, not the console!")) + return TRUE + if(istype(I, /obj/item/device/multitool)) + var/obj/item/device/multitool/M = I + var/obj/machinery/mind_engraver/buffer = M.get_buffer(/obj/machinery/mind_engraver) + if(!istype(buffer)) + return TRUE + linked_engraver = buffer + to_chat(user, SPAN_NOTICE("You link [src] with the machine in [I]'s buffer.")) + return ..() + +/obj/machinery/computer/mind_engraver_control/interface_interact(user) + interact(user) + return TRUE + +/obj/machinery/computer/mind_engraver_control/interact(mob/living/user) + //If the computer is being hacked or is emagged, display the reboot message. + if(!istype(linked_engraver)) + to_chat(user, SPAN_WARNING("\The [src] is not linked to any machine!")) + return + + var/list/dat = list() + dat += "

[model_name]


" + dat += "[model_producer], all rights reserved.

" + + dat += "Lock status: [linked_engraver.locked ? "Locked" : "Unlocked"]
" + + if(linked_engraver.occupant) + dat += "Occupant: [linked_engraver.occupant.name]
" + if(linked_engraver.currently_imprinting) + dat += "\The [linked_engraver] is currently operating!
" + dat += "Approximate time remaining: [round((linked_engraver.imprint_end - world.time) / 10)] seconds
" + else if(istype(linked_engraver.nanochip)) + dat += "Begin Imprinting Process
" + + if(!istype(linked_engraver.nanochip)) + dat += "Nanochip missing!
" + else if(!linked_engraver.nanochip.stored_data) + dat += "Nanochip data missing!
" + else + dat += "Currently installed nanochip:
" + dat += "Type: [linked_engraver.nanochip.stored_data.chip_type]
" + dat += "Function: [linked_engraver.nanochip.stored_data.PrintFunction()]
" + + var/datum/browser/popup = new(user, "mind_engraver", "Mind Engraver Control Console", 480, 600) + popup.set_content(JOINTEXT(dat)) + popup.open() + return + +/obj/machinery/computer/mind_engraver_control/Topic(href, href_list) + . = ..() + if(.) + return + + if(href_list["lock"]) + if(istype(linked_engraver)) + linked_engraver.ToggleLock() + + if(href_list["start"]) + if(istype(linked_engraver)) + if(linked_engraver.StartImprint()) + to_chat(usr, SPAN_NOTICE("\The [linked_engraver] has begun the imprinting process!")) + else + to_chat(usr, SPAN_WARNING("\The [linked_engraver] failed to start a new imprinting process!")) + + return interact(usr) + +/obj/machinery/computer/mind_engraver_control/proc/LinkEngraver(obj/machinery/mind_engraver/ME) + if(istype(linked_engraver)) + UnregisterSignal(linked_engraver, COMSIG_PARENT_QDELETING) + if(!istype(ME)) + return + + linked_engraver = ME + RegisterSignal(ME, COMSIG_PARENT_QDELETING, .proc/OnLinkDestroyed) + +/obj/machinery/computer/mind_engraver_control/proc/OnLinkDestroyed() + SIGNAL_HANDLER + + UnregisterSignal(linked_engraver, COMSIG_PARENT_QDELETING) + linked_engraver = null diff --git a/code/game/machinery/mind_engraver.dm b/code/game/machinery/mind_engraver.dm new file mode 100644 index 00000000000..89c63367ca5 --- /dev/null +++ b/code/game/machinery/mind_engraver.dm @@ -0,0 +1,310 @@ +/obj/machinery/mind_engraver + name = "mind engraver" + desc = "A complicated scanner connected to even more complicated machinery." + icon = 'icons/obj/machines/mind_engraver.dmi' + icon_state = "engraver_0" + density = FALSE + anchored = TRUE + construct_state = /decl/machine_construction/default/panel_closed + + machine_name = "mind engraver" + machine_desc = "Mind Engravers are an ultra-tech device that was used by Terran Dominion during its power peak. \ + Allows to imprint knowledge, skills or new memories into the mind of its occupant." + + var/obj/item/mind_engraver_chip/nanochip = null + var/mob/living/carbon/human/occupant = null + var/currently_imprinting = FALSE + /// How much time it takes to finish a single process + var/imprint_time = 80 SECONDS + /// World time when imprint process is finished + var/imprint_end = 0 + /// If TRUE - prevents the user from leaving, unless resisted out of + var/locked = FALSE + /// When the next breakout attempt can be done + var/breakout_cooldown = 0 + /// Base chance on every Process() tick to do random damage + var/mistake_chance = 4 + +/obj/machinery/mind_engraver/Destroy() + INVOKE_ASYNC(src, .proc/GoOut) + RemoveChip() + return ..() + +/obj/machinery/mind_engraver/Process() + if(stat & (NOPOWER|BROKEN)) + if(occupant) + GoOutPowerLoss() + return + + if(!currently_imprinting) + return + + if(!occupant || !nanochip) + StopImprint() + return + + if(world.time < imprint_end) + var/obj/item/organ/external/O_head = occupant.get_organ(BP_HEAD) + if(prob(mistake_chance) && istype(O_head)) + var/choice = pick(1, 2, 3) + switch(choice) + if(1) + O_head.take_external_damage(rand(5, 10), 0, DAM_SHARP|DAM_EDGE) + to_chat(occupant, SPAN_DANGER("\The [src] misplaces a surgical incision, damaging your skin!")) + if(2) + occupant.adjustBrainLoss(rand(5, 15)) + to_chat(occupant, SPAN_DANGER("\The [src]'s laser accidentaly passes over the exposed sections of your head, damaging your brain!")) + if(3) + occupant.custom_pain(SPAN_WARNING("You feel sudden sharp pain in your head!"), 20, affecting = O_head) + return + + FinishImprint() + + return + +/obj/machinery/mind_engraver/examine(mob/user, distance) + . = ..() + if(distance <= 1 && istype(nanochip)) + to_chat(user, SPAN_NOTICE("It has a [nanochip] installed in it.")) + +/obj/machinery/mind_engraver/attackby(obj/item/I, mob/user) + if(istype(I, /obj/item/mind_engraver_chip)) + add_fingerprint(user) + if(nanochip) + to_chat(user, SPAN_WARNING("\The [src] has a nanochip already installed.")) + return + if(!user.unEquip(I, src)) + return + user.visible_message( + SPAN_NOTICE("\The [user] inserts \a [I] into \the [src]."), + SPAN_NOTICE("You insert \a [I] into \the [src]."), + ) + nanochip = I + return TRUE + if(istype(I, /obj/item/device/multitool)) + var/obj/item/device/multitool/M = I + M.set_buffer(src) + to_chat(user, SPAN_NOTICE("You save the data in [M]'s buffer. It can now be used to link with the mind engraver console.")) + return TRUE + return ..() + +/obj/machinery/mind_engraver/AltClick(mob/user) + if(CanDefaultInteract(user)) + RemoveChip(user) + return + return ..() + +/obj/machinery/mind_engraver/relaymove(mob/user) + . = ..() + if(locked) + to_chat(user, SPAN_WARNING("\The [src] is currently locked and will not let you out!")) + return + INVOKE_ASYNC(src, .proc/GoOut) + +/obj/machinery/mind_engraver/mob_breakout(mob/living/escapee) + . = ..() + if(breakout_cooldown > world.time || escapee != occupant || !locked) + return FALSE + + . = TRUE + + to_chat(escapee, SPAN_WARNING("You lean on the back of \the [src] and start pushing the door open.")) + visible_message(SPAN_DANGER("\The [src] begins to shake violently!")) + + for(var/i = 1 to 3) + breakout_cooldown = world.time + 20 SECONDS + if(!do_after(escapee, (10 SECONDS), incapacitation_flags = INCAPACITATION_DEFAULT & ~INCAPACITATION_RESTRAINED)) + return FALSE + + if(!locked) + INVOKE_ASYNC(src, .proc/GoOut) + return FALSE + + playsound(src, 'sound/effects/glassbash.ogg', i * 30, 1) + shake_animation() + add_fingerprint(escapee) + + ToggleLock(FALSE) + INVOKE_ASYNC(src, .proc/GoOut) + to_chat(escapee, SPAN_NOTICE("You successfully break out!")) + visible_message(SPAN_DANGER("\The [escapee] successfully broke out of \the [src]!")) + return TRUE + +/obj/machinery/mind_engraver/emp_act(severity) + if(stat & (BROKEN|NOPOWER)) + return + + . = ..() + + if(prob(33)) + GoOutPowerLoss() + return + +/obj/machinery/mind_engraver/MouseDrop_T(mob/living/carbon/human/H, mob/user) + if(!CanMouseDrop(H, user)) + return + if(!istype(H)) + return + if(H.buckled) + to_chat(user, SPAN_WARNING("Unbuckle the subject before attempting to move them.")) + return + GoIn(H, user) + +/obj/machinery/mind_engraver/RefreshParts() + . = ..() + var/T = Clamp(total_component_rating_of_type(/obj/item/stock_parts/manipulator), 1, 12) + imprint_time = initial(imprint_time) / (T * 0.5) + + T = Clamp(total_component_rating_of_type(/obj/item/stock_parts/capacitor), 1, 12) + mistake_chance = max(0, 1 + initial(mistake_chance) - (T * 0.25)) + +/obj/machinery/mind_engraver/on_update_icon() + overlays.Cut() + + if(!occupant) + icon_state = "engraver_0" + density = FALSE + if(locked) + icon_state = "engraver_1" + density = TRUE + else + icon_state = "engraver_0" + density = FALSE + else + icon_state = "engraver_2" + density = TRUE + + if(locked) + overlays += image(icon, "locked_overlay") + +/obj/machinery/mind_engraver/proc/SetOccupant(mob/living/carbon/human/H) + occupant = H + update_icon() + if(!occupant) + update_use_power(POWER_USE_IDLE) + return + occupant.forceMove(src) + occupant.stop_pulling() + if(occupant.client) + occupant.client.perspective = EYE_PERSPECTIVE + occupant.client.eye = src + + update_use_power(POWER_USE_ACTIVE) + +/obj/machinery/mind_engraver/proc/GoIn(mob/living/carbon/human/H, mob/user) + if(!istype(H)) + return + if(stat & (BROKEN|NOPOWER)) + return + if(occupant) + to_chat(user, SPAN_WARNING("\The [src] is already occupied.")) + return + if(locked) + to_chat(user, SPAN_WARNING("\The [src] is locked.")) + return + + if(H == user) + visible_message(SPAN_NOTICE("\The [user] starts climbing into \the [src].")) + else + visible_message(SPAN_WARNING("\The [user] starts putting [H] into \the [src].")) + + if(do_after(user, 20, src)) + if(QDELETED(H)) + return + if(get_dist(H, user) > 1) + return + if(occupant) + to_chat(user, SPAN_WARNING("\The [src] is already occupied.")) + return + if(locked) + to_chat(user, SPAN_WARNING("\The [src] is locked.")) + return + if(H.buckled) + to_chat(user, SPAN_WARNING("Unbuckle the subject before attempting to move them.")) + return + SetOccupant(H) + +/obj/machinery/mind_engraver/proc/GoOut() + if(!occupant) + return + + if(locked) + return + + if(currently_imprinting) + StopImprint() + var/obj/item/organ/external/O_head = occupant.get_organ(BP_HEAD) + if(O_head) + to_chat(occupant, SPAN_DANGER("\The [src]'s tools quickly disengage away from your brain, leaving a terrible tear!")) + occupant.adjustBrainLoss(100) + occupant.custom_pain(SPAN_WARNING("It feels as if your head burst open!"), 50, affecting = O_head) + O_head.take_external_damage(35, 0, DAM_SHARP|DAM_EDGE) + if(!(stat & (NOPOWER|BROKEN))) + visible_message(SPAN_DANGER("\The [src] blares an alarm as its occupant leaves mid-procedure!")) + playsound(src, 'sound/machines/warning-buzzer.ogg', 50, TRUE, 7) + + if(occupant.client) + occupant.client.eye = occupant.client.mob + occupant.client.perspective = MOB_PERSPECTIVE + occupant.dropInto(loc) + SetOccupant(null) + +/obj/machinery/mind_engraver/proc/GoOutPowerLoss() + if(!occupant) + return + + visible_message(SPAN_DANGER("\The [src] blares an alarm as it loses power[locked ? "" : " and forcefuly ejects the occupant"]!")) + playsound(src, 'sound/machines/warning-buzzer.ogg', 50, TRUE, 7) + return INVOKE_ASYNC(src, .proc/GoOut) + +/obj/machinery/mind_engraver/proc/RemoveChip(mob/user) + if(!nanochip) + return + + if(currently_imprinting) + to_chat(user, SPAN_WARNING("\The [src] is currently imprinting the data from the nanochip!")) + return + + nanochip.dropInto(loc) + if(user) + user.put_in_any_hand_if_possible(nanochip) + nanochip = null + +/obj/machinery/mind_engraver/proc/StartImprint() + if(currently_imprinting) + return FALSE + + if(!nanochip || !occupant) + return FALSE + + currently_imprinting = TRUE + imprint_end = world.time + imprint_time + visible_message(SPAN_NOTICE("\The [src] chimes as it begins its operation!")) + playsound(src, 'sound/machines/synth_yes.ogg', 50, TRUE, 7) + return TRUE + +/obj/machinery/mind_engraver/proc/StopImprint() + currently_imprinting = FALSE + +/obj/machinery/mind_engraver/proc/FinishImprint() + StopImprint() + + if(!nanochip || !occupant) + return + + if(nanochip.stored_data) + nanochip.stored_data.ApplyEffect(occupant) + + ToggleLock(FALSE) + INVOKE_ASYNC(src, .proc/GoOut) + visible_message(SPAN_NOTICE("\The [src] produces a signal as it finishes its operation!")) + playsound(src, 'sound/machines/ping.ogg', 50, TRUE, 7) + +/obj/machinery/mind_engraver/proc/ToggleLock(force_set = null) + if(force_set != null) + locked = force_set + else + locked = !locked + var/sound_path = locked ? 'sound/machines/bolts_down.ogg' : 'sound/machines/bolts_up.ogg' + playsound(src, sound_path, 35, TRUE) + update_icon() diff --git a/code/game/objects/items/devices/mind_engraver_chip.dm b/code/game/objects/items/devices/mind_engraver_chip.dm new file mode 100644 index 00000000000..ad6e54ba510 --- /dev/null +++ b/code/game/objects/items/devices/mind_engraver_chip.dm @@ -0,0 +1,293 @@ +/obj/item/mind_engraver_chip + name = "mind engraver nanochip" + desc = "A tiny chip that stores data used by mind engravers to imprint certain knowledge." + icon = 'icons/obj/stock_parts.dmi' + icon_state = "rom2" + item_state = "electronic" + w_class = ITEM_SIZE_SMALL + + origin_tech = list(TECH_DATA = 8, TECH_DOMINION = 5) + + var/datum/engraver_data/stored_data = null + +/obj/item/mind_engraver_chip/Initialize() + . = ..() + if(ispath(stored_data)) + stored_data = new stored_data() + +/obj/item/mind_engraver_chip/Destroy() + QDEL_NULL(stored_data) + stored_data = null + return ..() + +/* Presets */ +/obj/item/mind_engraver_chip/human_languages + name = "mind engraver nanochip - \"Languages of the Humanity\"" + desc = "A relatively big chip with tiny label saying \"Languages of the Humanity\"." + icon_state = "romos2" + stored_data = /datum/engraver_data/language/humanity + +/obj/item/mind_engraver_chip/diplomatic_languages + name = "mind engraver nanochip - \"Dominion Diplomacy\"" + desc = "A bigger chip used by Terran Dominion to grant instant knowledge on all languages important to the Diplomatic \ + procedures in the universe." + icon_state = "romos2" + stored_data = /datum/engraver_data/language/diplomatic + +/* Randomized spawns */ +/obj/item/mind_engraver_chip/random_skills + stored_data = /datum/engraver_data/skill/random + +/obj/item/mind_engraver_chip/random_languages + stored_data = /datum/engraver_data/language/random + +/////////// +/* Datum */ +/////////// +/datum/engraver_data + var/chip_type = "UNKNOWN" + +/datum/engraver_data/proc/PrintFunction() + return "UNKNOWN" + +/datum/engraver_data/proc/ApplyEffect(mob/living/carbon/human/target) + if(!istype(target)) + return FALSE + return TRUE + +/* Skills */ +/datum/engraver_data/skill + chip_type = "Skill Imprint" + var/max_skills_count = 3 + var/list/skills = list() + +/datum/engraver_data/skill/PrintFunction() + if(!LAZYLEN(skills)) + return SPAN_DANGER("MISSING SKILL DATA") + var/func_text = "
" + for(var/decl/hierarchy/skill/S in GLOB.skills) + if(!(S.type in skills)) + continue + func_text += " - Improves knowledge in the field of [S.name] to the [S.levels[skills[S.type]]] level
" + return func_text + +/datum/engraver_data/skill/ApplyEffect(mob/living/carbon/human/target) + if(!..()) + return FALSE + + if(!target.skillset) + return FALSE + + for(var/decl/hierarchy/skill/S in GLOB.skills) + if(!(S.type in skills)) + continue + if(target.get_skill_value(S.type) >= skills[S.type]) + continue + target.skillset.skill_list[S.type] = skills[S.type] + to_chat(target, SPAN_NOTICE("You feel much more proficient in the field of [S.name]!")) + + target.skillset.on_levels_change() + return TRUE + +// Random +/datum/engraver_data/skill/random/New() + . = ..() + var/list/valid_skills = GLOB.skills.Copy() + for(var/i = 1 to rand(1, max_skills_count)) + if(!LAZYLEN(valid_skills)) + return + var/decl/hierarchy/skill/S = pick(valid_skills) + valid_skills -= S + skills[S.type] = rand(SKILL_BASIC, length(S.levels)) + +// Presets +/datum/engraver_data/skill/max_combat + skills = list( + SKILL_COMBAT = SKILL_MAX, + SKILL_WEAPONS = SKILL_MAX, + ) + +/datum/engraver_data/skill/max_command + skills = list( + SKILL_BUREAUCRACY = SKILL_MAX, + SKILL_FINANCE = SKILL_MAX, + SKILL_PILOT = SKILL_MAX, + ) + +/datum/engraver_data/skill/trained_medical + skills = list( + SKILL_MEDICAL = SKILL_TRAINED, + SKILL_ANATOMY = SKILL_TRAINED, + SKILL_CHEMISTRY = SKILL_TRAINED, + ) + +/* Languages */ +/datum/engraver_data/language + chip_type = "Language Imprint" + var/max_language_count = 3 + var/list/languages = list() + +/datum/engraver_data/language/PrintFunction() + if(!LAZYLEN(languages)) + return SPAN_DANGER("MISSING SKILL DATA") + var/func_text = "
" + for(var/lang in languages) + if(!all_languages[lang]) + continue + func_text += " - Imprints professional level knowledge on [lowertext(lang)] language
" + return func_text + +/datum/engraver_data/language/ApplyEffect(mob/living/carbon/human/target) + if(!..()) + return FALSE + + for(var/lang in languages) + if(!target.add_language(lang)) + continue + to_chat(target, SPAN_NOTICE("You gain professional understanding of [lowertext(lang)] language!")) + + return TRUE + +// Random +/datum/engraver_data/language/random/New() + . = ..() + var/list/valid_languages = all_languages.Copy() + for(var/i = 1 to rand(1, max_language_count)) + if(!LAZYLEN(valid_languages)) + return + var/lang = pick(valid_languages) + valid_languages -= lang + languages |= lang + +// Presets +/datum/engraver_data/language/humanity/New() + . = ..() + for(var/lang in subtypesof(/datum/language/human)) + var/datum/language/L = lang + languages |= initial(L.name) + +/datum/engraver_data/language/diplomatic + languages = list( + LANGUAGE_COMMON, + LANGUAGE_SPACER, + LANGUAGE_HUMAN_ENGLISH, + LANGUAGE_SKRELLIAN, + LANGUAGE_UNATHI_SINTA, + ) + +/datum/engraver_data/language/english + languages = list(LANGUAGE_HUMAN_ENGLISH) + +/datum/engraver_data/language/skrell + languages = list(LANGUAGE_SKRELLIAN) + +/datum/engraver_data/language/adherent + languages = list(LANGUAGE_ADHERENT) + +/* Fluff */ +/datum/engraver_data/memory + chip_type = "Memory Imprint" + var/function_text = "UNKNOWN" + +/datum/engraver_data/memory/PrintFunction() + if(!function_text) + return SPAN_DANGER("MISSING SKILL DATA") + return "[function_text]
" + +// Presets +/datum/engraver_data/memory/dominion_info_one + function_text = "Imprints basic information about Terran Dominion, as of year 244, III e." + // List of text that will be sent to the user some time after applying the nanochip + var/list/after_thoughts = list( + "Soldier" = list( + "You feel like it might be good idea to join the Terran Navy...", + "You think that Dominion's army could use a soldier like you...", + "There's definitely a need for people like you in the Terran military!", + "Why are you not in the Dominion's army...? You are missing out on so much...", + "You could be a Lieutenant by now, and then aristocratic status is just a step away...", + "The Terran Dominion needs you in its military... You are a great soldier!", + ), + "Governor" = list( + "You feel like Terran Dominion could use someone like you for their government apparatus...", + "You think it'd be really nice if you were governing some planet out there...", + "Maybe your skills would be incredibly useful if put to some use..?", + "You start to wonder how high planet governor's salary is...", + "The Terran Dominion definitely needs you as one of their governors... You are an excellent strategist and leader!", + ), + "Scientist" = list( + "You feel like you are a wonderful scientist...", + "You wonder if Dominion's Ministry of Scientific Progress is where you belong...", + "Terran Dominion rewards their scientist handsomely, doesn't it?", + "Your mind is full of useful knowldge and ideas, the Dominion would certainly need you...", + "Your place is with other great minds in the Terran Dominion... You are an absolute genius!", + ), + "Doctor" = list( + "You feel like you could save a lot more lives as a doctor in the Dominion's military...", + "Terran Dominion has better medical equipment than the ones you are used to...", + "How great would it be if you were a combat medic? Or a field surgeon for the Terran navy?", + "You are an absolute master with surgical tools and medical equipment, after all...", + "The Terran Dominion would not say \"no\" to a great doctor like you, you are the best one out there!", + ), + // Lmao, + "Useless" = list( + "You try to think of how useful you'd be for the Terran Dominion...", + "You feel like you are just not fit for society...", + "Maybe you could be a... something...?", + "Now you just feel like the most useless person in universe...", + "You think it's a great idea to donate your brain to the Ministry of Scientific Progress...", + "Maybe becoming a cyborg will make you more useful...", + ), + ) + +/datum/engraver_data/memory/dominion_info_one/ApplyEffect(mob/living/target) + if(!..()) + return FALSE + + var/list/dat = list() + + dat += "

Terran Dominion - Basic Information


" + dat += "This covers information about Terran Dominion as of year 244 of third era.
" + dat += "The following memories are all a part of the educational program initiated by the Ministry of Scientific Progress.
" + dat += "No other alterations will be present.

" + dat += "
" + dat += "Primary Language: English
" + dat += "Capital City: \[DATA EXPUNGED\] located on Earth, Sol system
" + dat += "Current Ruler: Emperor Jang Seo-joon" + dat += "
" + dat += "Terran Dominion is the official government of human species (homo-sapiens and its subtypes), \ + currently in control of over a hundred populated star systems and around 500 operational \ + space stations and motherships.
" + dat += "Terran Dominion is governed by the Emperor, which is appointed by the previous ruler as they see fit. \ + Members of aristocracy fill in the positions of authority, such as sector administrators, \ + ministers, advisors and military generals.
" + dat += "You, our dear citizen, is capable of joining the ranks of aristocracy by proving yourself to be a \ + valuable asset to the Dominion. Current data recommends that you seek employment in the following \ + fields if you are interested:
" + dat += "- Military;
" + dat += "- Planet Governor;
" + dat += "- Research & Development;
" + + var/datum/browser/popup = new(target, "mind_engraver_chip_[type]", "New Memory", 360, 500) + popup.set_content(JOINTEXT(dat)) + popup.open() + + to_chat(target, SPAN_WARNING("Your mind is flooded with batches of new information. You feel like you always knew it...")) + // SIDE EFFECTS! You now want to serve the Terran Dominion! Kinda... + var/chosen_type = "Useless" + // Trying to be as on-point as possible + if(target.get_skill_value(SKILL_HAULING) >= SKILL_EXPERIENCED || target.get_skill_value(SKILL_COMBAT) >= SKILL_TRAINED || target.get_skill_value(SKILL_WEAPONS) >= SKILL_TRAINED) + chosen_type = "Soldier" + else if(target.get_skill_value(SKILL_PILOT) >= SKILL_EXPERIENCED || target.get_skill_value(SKILL_BUREAUCRACY) >= SKILL_EXPERIENCED || target.get_skill_value(SKILL_FINANCE) >= SKILL_EXPERIENCED) + chosen_type = "Governor" + else if(target.get_skill_value(SKILL_SCIENCE) >= SKILL_EXPERIENCED || target.get_skill_value(SKILL_CHEMISTRY) >= SKILL_TRAINED || target.get_skill_value(SKILL_DEVICES) >= SKILL_EXPERIENCED) + chosen_type = "Scientist" + else if(target.get_skill_value(SKILL_MEDICAL) >= SKILL_TRAINED && target.get_skill_value(SKILL_ANATOMY) >= SKILL_TRAINED) + chosen_type = "Doctor" + + if(chosen_type in after_thoughts) + var/list/chosen_list = after_thoughts[chosen_type] + var/message_delay = rand(30 SECONDS, 80 SECONDS) + for(var/i = 1 to length(chosen_list)) + addtimer(CALLBACK(GLOBAL_PROC, /proc/to_chat, target, SPAN_SUBTLE(chosen_list[i])), (rand(90 SECONDS, 300 SECONDS) + (i * message_delay))) + + return TRUE diff --git a/code/game/objects/items/weapons/circuitboards/computer/computer.dm b/code/game/objects/items/weapons/circuitboards/computer/computer.dm index 4a40a7685d5..8e2274184ec 100644 --- a/code/game/objects/items/weapons/circuitboards/computer/computer.dm +++ b/code/game/objects/items/weapons/circuitboards/computer/computer.dm @@ -114,3 +114,13 @@ /obj/item/stock_parts/circuitboard/pandemic name = T_BOARD("PanD.E.M.I.C 2200 console") build_path = /obj/machinery/computer/pandemic + +/obj/item/stock_parts/circuitboard/aiupload + name = T_BOARD("AI upload console") + build_path = /obj/machinery/computer/upload/ai + origin_tech = list(TECH_DATA = 4) + +/obj/item/stock_parts/circuitboard/mind_engraver_console + name = T_BOARD("mind engraver console") + build_path = /obj/machinery/computer/mind_engraver_control + origin_tech = list(TECH_ENGINEERING = 7, TECH_DATA = 5, TECH_DOMINION = 2) diff --git a/code/game/objects/items/weapons/circuitboards/machinery/mind_engraver.dm b/code/game/objects/items/weapons/circuitboards/machinery/mind_engraver.dm new file mode 100644 index 00000000000..f0e3e7772cc --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/machinery/mind_engraver.dm @@ -0,0 +1,13 @@ +/obj/item/stock_parts/circuitboard/mind_engraver + name = T_BOARD("mind engraver") + build_path = /obj/machinery/mind_engraver + board_type = "machine" + origin_tech = list(TECH_ENGINEERING = 7, TECH_DATA = 5, TECH_DOMINION = 2) + req_components = list( + /obj/item/stock_parts/capacitor = 4, + /obj/item/stock_parts/scanning_module = 2, + /obj/item/stock_parts/manipulator = 2 + ) + additional_spawn_components = list( + /obj/item/stock_parts/power/apc/buildable = 1 + ) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index d6b75a553d3..f6139d7fca7 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -188,3 +188,7 @@ /obj/get_mass() return min(2**(w_class-1), 100) + +/obj/proc/mob_breakout(mob/living/escapee) + set waitfor = FALSE + return FALSE diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm index 5d2c42b1300..fd0762f8816 100644 --- a/code/game/objects/structures.dm +++ b/code/game/objects/structures.dm @@ -21,10 +21,6 @@ return TRUE return ..() -/obj/structure/proc/mob_breakout(mob/living/escapee) - set waitfor = FALSE - return FALSE - /obj/structure/Destroy() reset_mobs_offset() var/turf/T = get_turf(src) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 644401db125..e5a7de03883 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -667,9 +667,9 @@ default behaviour is: return TRUE //Breaking out of a structure? - if(istype(loc, /obj/structure)) - var/obj/structure/C = loc - if(C.mob_breakout(src)) + if(istype(loc, /obj)) + var/obj/O = loc + if(O.mob_breakout(src)) return TRUE /mob/living/proc/escape_inventory(obj/item/holder/H) diff --git a/code/modules/research/designs/designs_circuits.dm b/code/modules/research/designs/designs_circuits.dm index f5d8871a521..e5e1a05b957 100644 --- a/code/modules/research/designs/designs_circuits.dm +++ b/code/modules/research/designs/designs_circuits.dm @@ -667,6 +667,13 @@ build_path = /obj/item/stock_parts/circuitboard/disperser sort_string = "KCAAG" +/datum/design/circuit/shipmap + name = "ship holomap" + id = "shipmap" + req_tech = list(TECH_ENGINEERING = 1) + build_path = /obj/item/stock_parts/circuitboard/shipmap + sort_string = "LAAAA" + /datum/design/circuit/tcom req_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 4) @@ -904,9 +911,26 @@ build_path = /obj/item/stock_parts/circuitboard/radio_beacon sort_string = "XAAAI" -/datum/design/circuit/shipmap - name = "ship holomap" - id = "shipmap" - req_tech = list(TECH_ENGINEERING = 1) - build_path = /obj/item/stock_parts/circuitboard/shipmap - sort_string = "SAAAT" +/datum/design/circuit/dominion/AssembleDesignName() + if(build_path) + var/obj/item/stock_parts/circuitboard/C = build_path + if(initial(C.board_type) == "machine") + name = "\[Dominion Machine Circuit\] - [item_name]" + else if(initial(C.board_type) == "computer") + name = "\[Dominion Computer Circuit\] - [item_name]" + else + name = "\[Dominion Circuit\] - [item_name]" + +/datum/design/circuit/mind_engraver + name = "mind engraver" + id = "mind_engraver" + req_tech = list(TECH_ENGINEERING = 8, TECH_DATA = 6, TECH_DOMINION = 5) + build_path = /obj/item/stock_parts/circuitboard/mind_engraver + sort_string = "YAAAA" + +/datum/design/circuit/mind_engraver_console + name = "mind engraver console" + id = "mind_engraver_console" + req_tech = list(TECH_ENGINEERING = 8, TECH_DATA = 6, TECH_DOMINION = 5) + build_path = /obj/item/stock_parts/circuitboard/mind_engraver_console + sort_string = "YAAAB" diff --git a/code/modules/research/part_replacer.dm b/code/modules/research/part_replacer.dm index 6fc0242e44b..3ce85f9be8b 100644 --- a/code/modules/research/part_replacer.dm +++ b/code/modules/research/part_replacer.dm @@ -44,9 +44,9 @@ remote_interaction = TRUE remote_distance = 5 -/obj/item/research +/obj/item/research_debug name = "research debugging device" desc = "Instant research tool. For testing purposes only." icon = 'icons/obj/stock_parts.dmi' icon_state = "smes_coil" - origin_tech = list(TECH_MATERIAL = 19, TECH_ENGINEERING = 19, TECH_PHORON = 19, TECH_POWER = 19, TECH_BLUESPACE = 19, TECH_BIO = 19, TECH_COMBAT = 19, TECH_MAGNET = 19, TECH_DATA = 19, TECH_ESOTERIC = 19) \ No newline at end of file + origin_tech = list(TECH_MATERIAL = 19, TECH_ENGINEERING = 19, TECH_PHORON = 19, TECH_POWER = 19, TECH_BLUESPACE = 19, TECH_BIO = 19, TECH_COMBAT = 19, TECH_MAGNET = 19, TECH_DATA = 19, TECH_ESOTERIC = 19, TECH_DOMINION = 19) diff --git a/code/modules/research/research.dm b/code/modules/research/research.dm index f8ef4897f8a..c1c49e6e1de 100644 --- a/code/modules/research/research.dm +++ b/code/modules/research/research.dm @@ -197,6 +197,12 @@ research holder datum. id = TECH_ESOTERIC level = 0 +/datum/tech/dominion + name = "Dominion Technology" + desc = "Mostly forgotten and lost technology used during Terran Dominion's prime era, containing powerful designs and tools." + id = TECH_DOMINION + level = 0 + /obj/item/disk/tech_disk name = "fabricator data disk" desc = "A disk for storing fabricator learning data for backup." @@ -207,7 +213,6 @@ research holder datum. matter = list(MATERIAL_PLASTIC = 30, MATERIAL_STEEL = 30, MATERIAL_GLASS = 10) var/datum/tech/stored - /obj/item/disk/design_disk name = "component design disk" desc = "A disk for storing device design data for construction in lathes." diff --git a/icons/obj/machines/mind_engraver.dmi b/icons/obj/machines/mind_engraver.dmi new file mode 100644 index 0000000000000000000000000000000000000000..7e9788c45a9616536e5a238cc21ae5dcc22f55f4 GIT binary patch literal 6577 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 Ktz4sM9rZuU$rhym literal 0 HcmV?d00001