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