From 6aa1afc21319aa91c3cd764b4f59d39774c32190 Mon Sep 17 00:00:00 2001 From: brndd Date: Fri, 10 Jan 2025 10:37:43 +0200 Subject: [PATCH 1/6] Add the spiderbot fabricator The spiderbot fabricator is a device built by R&D that can be activated by ghosts to spawn there as a spiderbot. It is similar to the MoMMI fabricator, except it must be fed metal sheets to work and can actually be built by players. It can also be used by mice by clicking on it to become a mouse-spiderbot (which is apparently a thing). --- code/game/machinery/constructable_frame.dm | 11 + code/game/machinery/spiderbot_spawner.dm | 224 ++++++++++++++++++ .../designs/boards/machine_science.dm | 11 +- vgstation13.dme | 1 + 4 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 code/game/machinery/spiderbot_spawner.dm diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index f167da47aed1..65e5c3782247 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -494,6 +494,17 @@ to destroy them and players will be able to make replacements. /obj/item/weapon/stock_parts/micro_laser = 2, /obj/item/weapon/stock_parts/console_screen = 1) +/obj/item/weapon/circuitboard/spiderbot_fabricator + name = "Circuit board (Spiderbot Fabricator)" + desc = "A circuit board used to run a spiderbot fabricator." + build_path = /obj/machinery/spiderbot_fabricator + board_type = MACHINE + origin_tech = Tc_PROGRAMMING + "=4;" + Tc_ENGINEERING + "=4" + req_components = list( + /obj/item/weapon/stock_parts/matter_bin = 1, + /obj/item/weapon/stock_parts/manipulator = 2, + /obj/item/weapon/stock_parts/micro_laser = 1) + /obj/item/weapon/circuitboard/podfab name = "Circuit board (Spacepod Fabricator)" desc = "A circuit board used to run a spacepod fabricator." diff --git a/code/game/machinery/spiderbot_spawner.dm b/code/game/machinery/spiderbot_spawner.dm new file mode 100644 index 000000000000..045708671927 --- /dev/null +++ b/code/game/machinery/spiderbot_spawner.dm @@ -0,0 +1,224 @@ +/obj/machinery/spiderbot_fabricator + name = "\improper spiderbot fabricator" + desc = "A large pad sunk into the ground that brains with legs occasionally crawl out of." + icon = 'icons/obj/robotics.dmi' + icon_state = "mommispawner-idle" + density = TRUE + anchored = TRUE + machine_flags = SCREWTOGGLE | CROWDESTROY | WRENCHMOVE | FIXED2WORK + var/building = FALSE + var/metal = 0 + var/max_metal = 100 + var/const/metalPerSpiderbot = 10 + use_power = MACHINE_POWER_USE_IDLE + idle_power_usage = 20 + active_power_usage = 5000 + var/recharge_time = 120 SECONDS + var/recharge_time_reduction = 0 + var/last_built_time = -120 SECONDS + var/build_time = 20 SECONDS + var/build_time_reduction = 0 + +/obj/machinery/spiderbot_fabricator/proc/get_recharge_time() + return max(recharge_time - recharge_time_reduction, 0) + +/obj/machinery/spiderbot_fabricator/proc/get_build_time() + return max(build_time - build_time_reduction, 0) + +/obj/machinery/spiderbot_fabricator/New() + . = ..() + component_parts = newlist( + /obj/item/weapon/circuitboard/spiderbot_fabricator, + /obj/item/weapon/stock_parts/matter_bin, + /obj/item/weapon/stock_parts/manipulator, + /obj/item/weapon/stock_parts/manipulator, + /obj/item/weapon/stock_parts/micro_laser) + RefreshParts() + +//parent already calls spillContents for us +/obj/machinery/spiderbot_fabricator/crowbarDestroy(mob/user, obj/item/tool/crowbar/I) + if(building) + to_chat(user, "You cannot disassemble \the [src] while it is building something.") + return FALSE + return ..() + +/obj/machinery/spiderbot_fabricator/proc/eject_occupant() + for(var/atom/movable/I in src) + if(istype(I, /mob/living/simple_animal/mouse) || istype(I, /obj/item/device/mmi)) + I.forceMove(src.loc) + +/obj/machinery/spiderbot_fabricator/spillContents() + eject_occupant() + return ..() + +//Matter bin and half of manipulators reduce recharge time. Micro laser and half of manipulators reduce build time. +/obj/machinery/spiderbot_fabricator/RefreshParts() + recharge_time_reduction = 0 + build_time_reduction = 0 + for(var/obj/item/weapon/stock_parts/P in component_parts) + if(istype(P, /obj/item/weapon/stock_parts/matter_bin)) + recharge_time_reduction += (P.rating - 1) * (20 SECONDS) + else if(istype(P, /obj/item/weapon/stock_parts/manipulator)) + recharge_time_reduction += (P.rating - 1) * (10 SECONDS) + build_time_reduction += (P.rating - 1) * 15 //1.5 seconds + else if(istype(P, /obj/item/weapon/stock_parts/micro_laser)) + build_time_reduction += (P.rating - 1) * (3 SECONDS) + +/obj/machinery/spiderbot_fabricator/examine(mob/user) + ..() + to_chat(user, "The sheet storage is at [metal] out of [max_metal].") + +/obj/machinery/spiderbot_fabricator/process() + ..() + update_icon() + +/obj/machinery/spiderbot_fabricator/power_change() + if(powered()) + stat &= ~NOPOWER + else + stat |= NOPOWER + eject_occupant() + update_icon() + +/obj/machinery/spiderbot_fabricator/proc/isRecharging() + return (world.time - last_built_time) < get_recharge_time() + +/obj/machinery/spiderbot_fabricator/proc/canSpawn() + return !(stat & (FORCEDISABLE|NOPOWER)) && !building && !isRecharging() &&metal >= metalPerSpiderbot + +/obj/machinery/spiderbot_fabricator/proc/is_valid_user(var/mob/user) + if(!user) + return FALSE + + if(building) + to_chat(user, "\The [src] is busy building something already.") + return FALSE + + if(isRecharging()) + to_chat(user, "\The [src] is still recharging from its last activation.") + return FALSE + + if(metal < metalPerSpiderbot) + to_chat(user, "\The [name] doesn't have enough metal to complete this task.") + return FALSE + + if(istype(user, /mob/living/simple_animal/mouse)) + return TRUE + //Any checks below here should be specific to whether the user can spawn in as a posibrain-based spiderbot. + + if(jobban_isbanned(user, ROLE_POSIBRAIN)) + to_chat(user, "\The [name] lets out an annoyed buzz.") + return FALSE + + return TRUE + +/obj/machinery/spiderbot_fabricator/attack_ghost(var/mob/dead/observer/user) + if(is_valid_user(user)) + if(alert(user, "Do you wish to be turned into a spiderbot at this position?", "Confirm", "Yes", "No") != "Yes") + return + makeSpiderbot(user) + +/obj/machinery/spiderbot_fabricator/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(!..()) + if(istype(O,/obj/item/device/mmi)) + var/obj/item/device/mmi/mmi = O + if(!mmi.brainmob) + to_chat(user, "\The [mmi] appears to be devoid of any soul.") + return TRUE + + if(!mmi.brainmob.key) + if(!mind_can_reenter(mmi.brainmob.mind)) + to_chat(user, "\The [src] indicates that [O.name]'s mind is completely unresponsive; there's no point.") + return TRUE + + if(mmi.brainmob.stat == DEAD) + to_chat(user, "Yeah, good idea. Give something deader than the pizza in your fridge legs. Mom would be so proud.") + return TRUE + + if(!is_valid_user(mmi.brainmob)) + return TRUE + + if(user.drop_item(O, src)) + makeSpiderbot(mmi.brainmob, mmi) + return TRUE + else if(istype(O, /obj/item/stack/sheet/metal)) + var/obj/item/stack/sheet/metal/metal_sheet = O + var/amount = round(input("How many sheets do you want to add? (0 - [metal_sheet.amount])") as num)//No decimals + amount = min(amount, metal_sheet.amount) + if(!user.Adjacent(src) || !O || !O.loc || (O.loc != user && !isgripper(O.loc))) + return TRUE + if(amount <= 0) + return TRUE + amount = min(amount, max_metal - metal) + if(amount <= 0) + to_chat(user, "\The [src]'s sheet storage is already full.") + return TRUE + metal += amount + metal_sheet.use(amount) + to_chat(user, "You add [amount] metal sheets to \the [src].") + update_icon() + return TRUE + return FALSE + +/obj/machinery/spiderbot_fabricator/attack_animal(var/mob/user as mob) + if(istype(user, /mob/living/simple_animal/mouse) && is_valid_user(user)) + if(do_after(user, user, 2 SECONDS)) + user.visible_message("\The [user] scrambles into \the [src].", "You scramble into \the [src].") + makeSpiderbot(user) + return TRUE + + +/obj/machinery/spiderbot_fabricator/proc/makeSpiderbot(var/mob/user, var/obj/item/device/mmi/use_mmi) + if(!user || !istype(user) || !user.client) + return + + log_admin("([user.ckey]/[user]) became a spiderbot from \the [src] located in [get_area_name(src)] ([loc]).") + var/atom/movable/M = null + if(use_mmi) + M = use_mmi + else if(istype(user, /mob/living/simple_animal/mouse)) + M = user + M.forceMove(src) + else + var/obj/item/device/mmi/posibrain/mmi = new(src) + M = mmi + mmi.transfer_personality(user) + building = TRUE + update_icon() + visible_message("\The [src] buzzes and whirrs as it starts manufacturing a spiderbot.") + spawn(get_build_time()) + if(!building || M.loc != src) + //Whatever we were building escaped somehow + return + if(stat & (FORCEDISABLE|NOPOWER)) + //we got interrupted + eject_occupant() //just to make sure nothing is stuck inside + return + building = FALSE + update_icon() + var/mob/living/simple_animal/spiderbot/S = new(loc) + M.forceMove(S) + if(istype(M, /mob/living/simple_animal/mouse)) + user.mind.transfer_to(S) + S.name = "Spider-bot ([user.name])" + S.mouse = user + S.add_language(LANGUAGE_MOUSE) + else + S.mmi = M + S.transfer_personality(M) + to_chat(S, "You are now a spiderbot. Seek out the roboticist to be turned into something more useful.") + S.update_icon() + metal -= metalPerSpiderbot + last_built_time = world.time + +/obj/machinery/spiderbot_fabricator/update_icon() + if(stat & (FORCEDISABLE|NOPOWER)) + icon_state="mommispawner-nopower" + else if(building) + icon_state="mommispawner-building" + else if(isRecharging()) + icon_state="mommispawner-recharging" + else if(metal < metalPerSpiderbot) + icon_state="mommispawner-nopower" + else + icon_state="mommispawner-idle" diff --git a/code/modules/research/designs/boards/machine_science.dm b/code/modules/research/designs/boards/machine_science.dm index aafe061efd1e..5338dc9ee2d3 100644 --- a/code/modules/research/designs/boards/machine_science.dm +++ b/code/modules/research/designs/boards/machine_science.dm @@ -153,4 +153,13 @@ materials = list(MAT_GLASS = 2000, SACID = 15) category = "Machine Boards" build_path = /obj/item/weapon/circuitboard/suit_storage_unit - \ No newline at end of file + +/datum/design/spiderbotfabricator + name = "Circuit Design(Spiderbot Fabricator)" + desc = "The circuit board for a Spiderbot Fabricator." + id = "spiderbotfab" + req_tech = list(Tc_PROGRAMMING = 4, Tc_ENGINEERING = 4) + build_type = IMPRINTER + materials = list(MAT_GLASS = 2000, SACID = 20) + category = "Machine Boards" + build_path = /obj/item/weapon/circuitboard/spiderbot_fabricator diff --git a/vgstation13.dme b/vgstation13.dme index ac9bdb2ebf0b..f21907cadb17 100644 --- a/vgstation13.dme +++ b/vgstation13.dme @@ -778,6 +778,7 @@ #include "code\game\machinery\singularity_beacon.dm" #include "code\game\machinery\Sleeper.dm" #include "code\game\machinery\smartglass.dm" +#include "code\game\machinery\spiderbot_spawner.dm" #include "code\game\machinery\station_map.dm" #include "code\game\machinery\status_display.dm" #include "code\game\machinery\suit_dispenser.dm" From d1403bab9bddce07e395f32c0478ca54f9b73401 Mon Sep 17 00:00:00 2001 From: brndd Date: Fri, 10 Jan 2025 11:58:25 +0200 Subject: [PATCH 2/6] fix linter error --- code/game/machinery/spiderbot_spawner.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/machinery/spiderbot_spawner.dm b/code/game/machinery/spiderbot_spawner.dm index 045708671927..c5ee1b5888e4 100644 --- a/code/game/machinery/spiderbot_spawner.dm +++ b/code/game/machinery/spiderbot_spawner.dm @@ -47,7 +47,7 @@ if(istype(I, /mob/living/simple_animal/mouse) || istype(I, /obj/item/device/mmi)) I.forceMove(src.loc) -/obj/machinery/spiderbot_fabricator/spillContents() +/obj/machinery/spiderbot_fabricator/spillContents(destroy_chance = 0) eject_occupant() return ..() From 70b85cae8979a29e846cd39ac15116d9120f1b7d Mon Sep 17 00:00:00 2001 From: brndd Date: Thu, 23 Jan 2025 14:02:18 +0200 Subject: [PATCH 3/6] Load up with positronic brains instead of metal --- code/game/machinery/spiderbot_spawner.dm | 40 ++++++++---------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/code/game/machinery/spiderbot_spawner.dm b/code/game/machinery/spiderbot_spawner.dm index c5ee1b5888e4..7d000dd49648 100644 --- a/code/game/machinery/spiderbot_spawner.dm +++ b/code/game/machinery/spiderbot_spawner.dm @@ -7,9 +7,7 @@ anchored = TRUE machine_flags = SCREWTOGGLE | CROWDESTROY | WRENCHMOVE | FIXED2WORK var/building = FALSE - var/metal = 0 - var/max_metal = 100 - var/const/metalPerSpiderbot = 10 + var/brains = 0 use_power = MACHINE_POWER_USE_IDLE idle_power_usage = 20 active_power_usage = 5000 @@ -49,6 +47,9 @@ /obj/machinery/spiderbot_fabricator/spillContents(destroy_chance = 0) eject_occupant() + for(i=0, iThe sheet storage is at [metal] out of [max_metal].") + to_chat(user, "The machine is holding [brains] inactive positronic brains.") /obj/machinery/spiderbot_fabricator/process() ..() @@ -84,7 +85,7 @@ return (world.time - last_built_time) < get_recharge_time() /obj/machinery/spiderbot_fabricator/proc/canSpawn() - return !(stat & (FORCEDISABLE|NOPOWER)) && !building && !isRecharging() &&metal >= metalPerSpiderbot + return !(stat & (FORCEDISABLE|NOPOWER)) && !building && !isRecharging() && brains /obj/machinery/spiderbot_fabricator/proc/is_valid_user(var/mob/user) if(!user) @@ -98,8 +99,8 @@ to_chat(user, "\The [src] is still recharging from its last activation.") return FALSE - if(metal < metalPerSpiderbot) - to_chat(user, "\The [name] doesn't have enough metal to complete this task.") + if(brains <= 0) + to_chat(user, "\The [name] doesn't contain any positronic brains.") return FALSE if(istype(user, /mob/living/simple_animal/mouse)) @@ -123,7 +124,9 @@ if(istype(O,/obj/item/device/mmi)) var/obj/item/device/mmi/mmi = O if(!mmi.brainmob) - to_chat(user, "\The [mmi] appears to be devoid of any soul.") + brains += 1 + to_chat(user, "You insert \the [mmi] into \the [src]'s storage bay'.") + qdel(mmi) return TRUE if(!mmi.brainmob.key) @@ -141,23 +144,6 @@ if(user.drop_item(O, src)) makeSpiderbot(mmi.brainmob, mmi) return TRUE - else if(istype(O, /obj/item/stack/sheet/metal)) - var/obj/item/stack/sheet/metal/metal_sheet = O - var/amount = round(input("How many sheets do you want to add? (0 - [metal_sheet.amount])") as num)//No decimals - amount = min(amount, metal_sheet.amount) - if(!user.Adjacent(src) || !O || !O.loc || (O.loc != user && !isgripper(O.loc))) - return TRUE - if(amount <= 0) - return TRUE - amount = min(amount, max_metal - metal) - if(amount <= 0) - to_chat(user, "\The [src]'s sheet storage is already full.") - return TRUE - metal += amount - metal_sheet.use(amount) - to_chat(user, "You add [amount] metal sheets to \the [src].") - update_icon() - return TRUE return FALSE /obj/machinery/spiderbot_fabricator/attack_animal(var/mob/user as mob) @@ -181,6 +167,7 @@ M.forceMove(src) else var/obj/item/device/mmi/posibrain/mmi = new(src) + brains -= 1 M = mmi mmi.transfer_personality(user) building = TRUE @@ -208,7 +195,6 @@ S.transfer_personality(M) to_chat(S, "You are now a spiderbot. Seek out the roboticist to be turned into something more useful.") S.update_icon() - metal -= metalPerSpiderbot last_built_time = world.time /obj/machinery/spiderbot_fabricator/update_icon() @@ -218,7 +204,7 @@ icon_state="mommispawner-building" else if(isRecharging()) icon_state="mommispawner-recharging" - else if(metal < metalPerSpiderbot) + else if(!brains) icon_state="mommispawner-nopower" else icon_state="mommispawner-idle" From b0856649a01cc6dfd1a91c622e7cd06d607c834f Mon Sep 17 00:00:00 2001 From: brndd Date: Thu, 23 Jan 2025 14:06:46 +0200 Subject: [PATCH 4/6] var/i --- code/game/machinery/spiderbot_spawner.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/game/machinery/spiderbot_spawner.dm b/code/game/machinery/spiderbot_spawner.dm index 7d000dd49648..e14f8e4197fc 100644 --- a/code/game/machinery/spiderbot_spawner.dm +++ b/code/game/machinery/spiderbot_spawner.dm @@ -47,6 +47,7 @@ /obj/machinery/spiderbot_fabricator/spillContents(destroy_chance = 0) eject_occupant() + var/i for(i=0, i Date: Thu, 23 Jan 2025 14:10:41 +0200 Subject: [PATCH 5/6] shut up this warning too --- code/game/machinery/spiderbot_spawner.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/machinery/spiderbot_spawner.dm b/code/game/machinery/spiderbot_spawner.dm index e14f8e4197fc..eaa0f56560b0 100644 --- a/code/game/machinery/spiderbot_spawner.dm +++ b/code/game/machinery/spiderbot_spawner.dm @@ -50,7 +50,7 @@ var/i for(i=0, i Date: Thu, 23 Jan 2025 14:13:22 +0200 Subject: [PATCH 6/6] Improve this logic --- code/game/machinery/spiderbot_spawner.dm | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/code/game/machinery/spiderbot_spawner.dm b/code/game/machinery/spiderbot_spawner.dm index eaa0f56560b0..33383b49222c 100644 --- a/code/game/machinery/spiderbot_spawner.dm +++ b/code/game/machinery/spiderbot_spawner.dm @@ -124,17 +124,12 @@ if(!..()) if(istype(O,/obj/item/device/mmi)) var/obj/item/device/mmi/mmi = O - if(!mmi.brainmob) + if(!mmi.brainmob || (!mmi.brainmob.key && !mind_can_reenter(mmi.brainmob.mind))) brains += 1 to_chat(user, "You insert \the [mmi] into \the [src]'s storage bay'.") qdel(mmi) return TRUE - if(!mmi.brainmob.key) - if(!mind_can_reenter(mmi.brainmob.mind)) - to_chat(user, "\The [src] indicates that [O.name]'s mind is completely unresponsive; there's no point.") - return TRUE - if(mmi.brainmob.stat == DEAD) to_chat(user, "Yeah, good idea. Give something deader than the pizza in your fridge legs. Mom would be so proud.") return TRUE