Move drones to modular + changes

Moves drones into the modular folder to allow for more violent changes without having to worry about upstreams potentially adding something to regular drones.

Restructures some of drone code a bit to be nicer in my oppinion

Still needs a second pass at some point but hey if you never start
This commit is contained in:
Sharkmare
2023-04-13 11:48:05 +02:00
parent b8a9f86017
commit f1330a3ebd
14 changed files with 1907 additions and 14 deletions

View File

@@ -0,0 +1,401 @@
//Modified copy of regula drone folder
/mob/living/silicon/robot/drone
name = "maintenance drone"
real_name = "drone"
icon = 'icons/mob/robots.dmi'
icon_state = "repairbot"
maxHealth = 35
health = 35
cell_emp_mult = 1
universal_speak = 0
universal_understand = 1
gender = NEUTER
pass_flags = PASSTABLE
braintype = "Drone"
lawupdate = 0
density = TRUE
req_access = list(access_engine, access_robotics)
integrated_light_power = 3
local_transmit = 1
can_pull_size = ITEMSIZE_NO_CONTAINER
can_pull_mobs = MOB_PULL_SMALLER
can_enter_vent_with = list(
/obj,
/atom/movable/emissive_blocker)
mob_bump_flag = SIMPLE_ANIMAL
mob_swap_flags = SIMPLE_ANIMAL
mob_push_flags = SIMPLE_ANIMAL
mob_always_swap = 1
mob_size = MOB_LARGE // Small mobs can't open doors, it's a huge pain for drones.
//Used for self-mailing.
var/mail_destination = ""
var/obj/machinery/drone_fabricator/master_fabricator
var/law_type = /datum/ai_laws/drone
var/module_type = /obj/item/weapon/robot_module/drone
var/obj/item/hat
var/hat_x_offset = 0
var/hat_y_offset = -13
var/serial_number = 0
var/name_override = 0
var/foreign_droid = FALSE
holder_type = /obj/item/weapon/holder/drone
can_be_antagged = FALSE
var/static/list/shell_types = list("Classic" = "repairbot", "Eris" = "maintbot")
var/can_pick_shell = TRUE
var/list/shell_accessories
var/can_blitz = FALSE
//vore addition
mob_size = MOB_SMALL
var/list/mob_hat_cache = list()
/proc/get_hat_icon(var/obj/item/hat, var/offset_x = 0, var/offset_y = 0)
var/t_state = hat.icon_state
if(LAZYACCESS(hat.item_state_slots, slot_head_str))
t_state = hat.item_state_slots[slot_head_str]
else if(hat.item_state)
t_state = hat.item_state
var/key = "[t_state]_[offset_x]_[offset_y]"
if(!mob_hat_cache[key]) // Not ideal as there's no guarantee all hat icon_states
var/t_icon = INV_HEAD_DEF_ICON // are unique across multiple dmis, but whatever.
if(hat.icon_override)
t_icon = hat.icon_override
else if(LAZYACCESS(hat.item_icons, slot_head_str))
t_icon = hat.item_icons[slot_head_str]
var/image/I = image(icon = t_icon, icon_state = t_state)
I.pixel_x = offset_x
I.pixel_y = offset_y
mob_hat_cache[key] = I
return mob_hat_cache[key]
/mob/living/silicon/robot/drone/Destroy()
if(hat)
hat.loc = get_turf(src)
..()
/mob/living/silicon/robot/drone/is_sentient()
return FALSE
/mob/living/silicon/robot/drone/New()
..()
verbs += /mob/living/proc/ventcrawl
verbs += /mob/living/proc/hide
remove_language("Robot Talk")
add_language("Robot Talk", 0)
add_language("Drone Talk", 1)
serial_number = rand(0,999)
//They are unable to be upgraded, so let's give them a bit of a better battery.
cell.maxcharge = 10000
cell.charge = 10000
// NO BRAIN.
mmi = null
//We need to screw with their HP a bit. They have around one fifth as much HP as a full borg.
for(var/V in components) if(V != "power cell")
var/datum/robot_component/C = components[V]
C.max_damage = 10
verbs -= /mob/living/silicon/robot/verb/Namepick
if(can_pick_shell)
var/random = pick(shell_types)
icon_state = shell_types[random]
shell_accessories = list("[icon_state]-eyes-blue")
updateicon()
updatename()
/mob/living/silicon/robot/drone/init()
if(!scrambledcodes && !foreign_droid)
aiCamera = new/obj/item/device/camera/siliconcam/drone_camera(src)
additional_law_channels["Drone"] = ":d"
if(!laws) laws = new law_type
if(!module) module = new module_type(src)
flavor_text = "It's a tiny little repair drone. The casing is stamped with an corporate logo and the subscript: '[using_map.company_name] Recursive Repair Systems: Fixing Tomorrow's Problem, Today!'"
playsound(src, 'sound/machines/twobeep.ogg', 50, 0)
/mob/living/silicon/robot/drone/Login()
. = ..()
if(can_pick_shell)
to_chat(src, "<b>You can select a shell using the 'Robot Commands' > 'Customize Appearance'</b>")
//Redefining some robot procs...
/mob/living/silicon/robot/drone/SetName(pickedName as text)
// Would prefer to call the grandparent proc but this isn't possible, so..
real_name = pickedName
name = real_name
/mob/living/silicon/robot/drone/updatename()
if(name_override)
return
real_name = "[initial(name)] ([serial_number])"
name = real_name
/mob/living/silicon/robot/drone/updateicon()
cut_overlays()
if(islist(shell_accessories))
add_overlay(shell_accessories)
if(hat) // Let the drones wear hats.
add_overlay(get_hat_icon(hat, hat_x_offset, hat_y_offset))
/mob/living/silicon/robot/drone/verb/pick_shell()
set name = "Customize Appearance"
set category = "Robot Commands"
if(!can_pick_shell)
to_chat(src, "<span class='warning'>You already selected a shell or this drone type isn't customizable.</span>")
return
var/list/choices = shell_types.Copy()
if(can_blitz)
choices["Blitz"] = "blitzshell"
var/shell_choice = tgui_input_list(src, "Select a shell. NOTE: You can only do this once during this drone-lifetime.", "Customize Shell", choices)
if(!shell_choice)
return
icon_state = choices[shell_choice]
// If you add more, datumize these. Having 'basically two' is not enough to make me bother though.
shell_accessories = null
if(icon_state in list("repairbot", "maintbot"))
var/eye_color = tgui_input_list(src, "Select eye color:", "Eye Color", list("blue", "red", "orange", "green", "violet"))
if(eye_color)
LAZYADD(shell_accessories, "[icon_state]-eyes-[eye_color]")
if(icon_state == "maintbot")
var/armor_color = tgui_input_list(src, "Select plating color:", "Eye Color", list("blue", "red", "orange", "green", "brown"))
if(armor_color)
LAZYADD(shell_accessories, "[icon_state]-shell-[armor_color]")
can_pick_shell = FALSE
updateicon()
/mob/living/silicon/robot/drone/choose_icon()
return
/mob/living/silicon/robot/drone/pick_module()
return
/mob/living/silicon/robot/drone/proc/wear_hat(var/obj/item/new_hat)
if(hat)
return
hat = new_hat
new_hat.loc = src
updateicon()
//Drones cannot be upgraded with borg modules so we need to catch some items before they get used in ..().
/mob/living/silicon/robot/drone/attackby(var/obj/item/weapon/W, var/mob/user)
//Early return handler
if(handle_attackby_return(W,user))
return
if(user.a_intent == "help" && istype(W, /obj/item/clothing/head))
equip_hat(W,user)
..()
//Denesting for the above code
/mob/living/silicon/robot/drone/proc/equip_hat(var/obj/item/clothing/head/W, var/mob/user)
if(hat)
to_chat(user, "<span class='warning'>\The [src] is already wearing \the [hat].</span>")
return
user.unEquip(W)
wear_hat(W)
user.visible_message("<b>\The [user]</b> puts \the [W] on \the [src].")
return
/mob/living/silicon/robot/drone/proc/handle_attackby_return(var/obj/item/W, var/mob/user)
var/hint
if(W.is_crowbar())
hint = "<span class='danger'>\The [src] is hermetically sealed. You can't open the case.</span>"
else if(istype(W, /obj/item/borg/upgrade/))
hint = "<span class='danger'>\The [src] is not compatible with \the [W].</span>"
else if(stat == 2)
hint = handle_try_reboot(W,user) //ugly as shit nesting otherwise
if(hint!="MSG-SKIP")
to_chat(usr,hint)
return hint //null if we dont handle early return
/mob/living/silicon/robot/drone/proc/handle_try_reboot(var/obj/item/W,var/mob/user)
var/datum/gender/TU = gender_datums[user.get_visible_gender()]
if(!istype(W, /obj/item/weapon/card/id)&&!istype(W, /obj/item/device/pda))
return handle_try_shutdown(user, TU)
if(!config.allow_drone_spawn || emagged || health < -35) //It's dead, Dave.
return "<span class='danger'>The interface is fried, and a distressing burned smell wafts from the robot's interior. You're not rebooting this one.</span>"
if(!allowed(usr))
return "<span class='danger'>Access denied.</span>"
user.visible_message("<span class='danger'>\The [user] swipes [TU.his] ID card through \the [src], attempting to reboot it.</span>", "<span class='danger'>>You swipe your ID card through \the [src], attempting to reboot it.</span>")
var/drones = 0
for(var/mob/living/silicon/robot/drone/D in player_list)
drones++
if(drones < config.max_maint_drones)
request_player()
return "MSG-SKIP"
/mob/living/silicon/robot/drone/proc/handle_try_shutdown(var/mob/user, var/datum/gender/TU)
user.visible_message("<span class='danger'>\The [user] swipes [TU.his] ID card through \the [src], attempting to shut it down.</span>", "<span class='danger'>You swipe your ID card through \the [src], attempting to shut it down.</span>")
if(emagged)
return "MSG-SKIP"
if(allowed(usr))
shut_down()
return "MSG-SKIP"
else
return "<span class='danger'>Access denied.</span>"
//ATTACKBY HANDLERS END
/mob/living/silicon/robot/drone/emag_act(var/remaining_charges, var/mob/user)
if(!client || stat == 2)
to_chat(user, "<span class='danger'>There's not much point subverting this heap of junk.</span>")
return
if(emagged)
to_chat(src, "<span class='danger'>\The [user] attempts to load subversive software into you, but your hacked subroutines ignore the attempt.</span>")
to_chat(user, "<span class='danger'>You attempt to subvert [src], but the sequencer has no effect.</span>")
return
to_chat(user, "<span class='danger'>You swipe the sequencer across [src]'s interface and watch its eyes flicker.</span>")
to_chat(src, "<span class='danger'>You feel a sudden burst of malware loaded into your execute-as-root buffer. Your tiny brain methodically parses, loads and executes the script.</span>")
log_game("[key_name(user)] emagged drone [key_name(src)]. Laws overridden.")
var/time = time2text(world.realtime,"hh:mm:ss")
lawchanges.Add("[time] <B>:</B> [user.name]([user.key]) emagged [name]([key])")
emagged = 1
lawupdate = 0
connected_ai = null
clear_supplied_laws()
clear_inherent_laws()
laws = new /datum/ai_laws/syndicate_override
var/datum/gender/TU = gender_datums[user.get_visible_gender()]
set_zeroth_law("Only [user.real_name] and people [TU.he] designate[TU.s] as being such are operatives.")
to_chat(src, "<b>Obey these laws:</b>")
laws.show_laws(src)
to_chat(src, "<span class='danger'>ALERT: [user.real_name] is your new master. Obey your new laws and \his commands.</span>")
return 1
//DRONE LIFE/DEATH
//For some goddamn reason robots have this hardcoded. Redefining it for our fragile friends here.
/mob/living/silicon/robot/drone/updatehealth()
if(status_flags & GODMODE)
health = maxHealth
set_stat(CONSCIOUS)
return
health = maxHealth - (getBruteLoss() + getFireLoss())
return
//Easiest to check this here, then check again in the robot proc.
//Standard robots use config for crit, which is somewhat excessive for these guys.
//Drones killed by damage will gib.
/mob/living/silicon/robot/drone/handle_regular_status_updates()
var/turf/T = get_turf(src)
if(!T || health <= -35 )
timeofdeath = world.time
death() //Possibly redundant, having trouble making death() cooperate.
gib()
return
..()
//DRONE MOVEMENT.
/mob/living/silicon/robot/drone/Process_Spaceslipping(var/prob_slip)
return 0
//CONSOLE PROCS
/mob/living/silicon/robot/drone/proc/law_resync()
if(stat == DEAD)
return //opting for an early return here to remove unneeded nesting
if(emagged)
to_chat(src, "<span class='danger'>You feel something attempting to modify your programming, but your hacked subroutines are unaffected.</span>")
else
to_chat(src, "<span class='danger'>A reset-to-factory directive packet filters through your data connection, and you obediently modify your programming to suit it.</span>")
full_law_reset()
show_laws()
/mob/living/silicon/robot/drone/proc/shut_down()
if(stat == DEAD)
return //opting for an early return here to remove unneeded nesting
if(emagged)
to_chat(src, "<span class='danger'>You feel a system kill order percolate through your tiny brain, but it doesn't seem like a good idea to you.</span>")
else
to_chat(src, "<span class='danger'>You feel a system kill order percolate through your tiny brain, and you obediently destroy yourself.</span>")
death()
/mob/living/silicon/robot/drone/proc/full_law_reset()
clear_supplied_laws(1)
clear_inherent_laws(1)
clear_ion_laws(1)
laws = new law_type
//Reboot procs.
/mob/living/silicon/robot/drone/proc/request_player()
for(var/mob/observer/dead/O in player_list)
if(jobban_isbanned(O, "Cyborg") || !O.client || !O.client.prefs.be_special & BE_PAI)
continue
question(O.client)
/mob/living/silicon/robot/drone/proc/question(var/client/C)
spawn(0)
if(!C || jobban_isbanned(C,"Cyborg")) return
var/response = tgui_alert(C, "Someone is attempting to reboot a maintenance drone. Would you like to play as one?", "Maintenance drone reboot", list("Yes", "No", "Never for this round"))
if(!C || ckey)
return
if(response == "Yes")
transfer_personality(C)
else if (response == "Never for this round")
C.prefs.be_special ^= BE_PAI
/mob/living/silicon/robot/drone/proc/transfer_personality(var/client/player)
if(!player) return
src.ckey = player.ckey
if(player.mob && player.mob.mind)
player.mob.mind.transfer_to(src)
lawupdate = 0
to_chat(src, "<b>Systems rebooted</b>. Loading base pattern maintenance protocol...")
spawn(3 SECONDS)
full_law_reset()
to_chat(src,"<b>Loaded</b>.")
spawn(4 SECONDS)
welcome_drone()
/mob/living/silicon/robot/drone/proc/welcome_drone()
to_chat(src, "<b>You are a maintenance drone, a tiny-brained robotic repair machine</b>.")
to_chat(src, "You have no individual will, no personality, and no drives or urges other than your laws.")
to_chat(src, "Remember, you are <b>lawed against interference with the crew</b>. Also remember, <b>you DO NOT take orders from the AI.</b>")
to_chat(src, "Use <b>say ;Hello</b> to talk to other drones and <b>say Hello</b> to speak silently to your nearby fellows.")
/mob/living/silicon/robot/drone/add_robot_verbs()
src.verbs |= silicon_subsystems
/mob/living/silicon/robot/drone/remove_robot_verbs()
src.verbs -= silicon_subsystems

View File

@@ -0,0 +1,36 @@
//Modified copy of regula drone folder
// DRONE ABILITIES
/mob/living/silicon/robot/drone/verb/set_mail_tag()
set name = "Set Mail Tag"
set desc = "Tag yourself for delivery through the disposals system."
set category = "Robot Commands"
var/new_tag = tgui_input_list(usr, "Select the desired destination.", "Set Mail Tag", GLOB.tagger_locations)
if(!new_tag)
mail_destination = ""
return
to_chat(src, "<span class='notice'>You configure your internal beacon, tagging yourself for delivery to '[new_tag]'.</span>")
mail_destination = new_tag
//Auto flush if we use this verb inside a disposal chute.
var/obj/machinery/disposal/D = src.loc
if(istype(D))
to_chat(src, "<span class='notice'>\The [D] acknowledges your signal.</span>")
D.flush_count = D.flush_every_ticks
return
/mob/living/silicon/robot/drone/MouseDrop(var/atom/over_object)
var/mob/living/carbon/human/H = over_object
if(!istype(H) || !Adjacent(H))
return ..()
if(H.a_intent == "grab" && hat && !(H.l_hand && H.r_hand))
H.put_in_hands(hat)
H.visible_message("<span class='danger'>\The [H] removes \the [src]'s [hat].</span>")
hat = null
updateicon()
return
else
return ..()

View File

@@ -0,0 +1,124 @@
//Modified copy of regula drone folder
/obj/machinery/computer/drone_control
name = "Maintenance Drone Control"
desc = "Used to monitor the station's drone population and the assembler that services them."
icon_keyboard = "power_key"
icon_screen = "generic" //VOREStation Edit
req_access = list(access_engine_equip)
circuit = /obj/item/weapon/circuitboard/drone_control
//Used when pinging drones.
var/drone_call_area = "Engineering"
//Used to enable or disable drone fabrication.
var/obj/machinery/drone_fabricator/dronefab
/obj/machinery/computer/drone_control/attack_ai(var/mob/user as mob)
return src.attack_hand(user)
/obj/machinery/computer/drone_control/tgui_status(mob/user)
if(!allowed(user))
return STATUS_CLOSE
return ..()
/obj/machinery/computer/drone_control/attack_hand(var/mob/user as mob)
if(..())
return
tgui_interact(user)
/obj/machinery/computer/drone_control/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "DroneConsole", name)
ui.open()
/obj/machinery/computer/drone_control/tgui_data(mob/user)
var/list/data = list()
var/list/drones = list()
for(var/mob/living/silicon/robot/drone/D in mob_list)
//VOREStation Edit - multiz lol
if(!(D.z in using_map.get_map_levels(z, TRUE, 0)))
continue
//VOREStation Edit - multiz lol
if(D.foreign_droid)
continue
drones.Add(list(list(
"name" = D.real_name,
"active" = D.stat != 2,
"charge" = D.cell.charge,
"maxCharge" = D.cell.maxcharge,
"loc" = "[get_area(D)]",
"ref" = "\ref[D]",
)))
data["drones"] = drones
data["fabricator"] = dronefab
data["fabPower"] = dronefab?.produce_drones
data["areas"] = GLOB.tagger_locations
data["selected_area"] = "[drone_call_area]"
return data
/obj/machinery/computer/drone_control/tgui_act(action, params)
if(..())
return TRUE
switch(action)
if("set_dcall_area")
var/t_area = params["area"]
if(!t_area || !(t_area in GLOB.tagger_locations))
return
drone_call_area = t_area
to_chat(usr, "<span class='notice'>You set the area selector to [drone_call_area].</span>")
if("ping")
to_chat(usr, "<span class='notice'>You issue a maintenance request for all active drones, highlighting [drone_call_area].</span>")
for(var/mob/living/silicon/robot/drone/D in player_list)
if(D.stat == 0)
to_chat(D, "-- Maintenance drone presence requested in: [drone_call_area].")
if("resync")
var/mob/living/silicon/robot/drone/D = locate(params["ref"])
if(D.stat != 2)
to_chat(usr, "<span class='danger'>You issue a law synchronization directive for the drone.</span>")
D.law_resync()
if("shutdown")
var/mob/living/silicon/robot/drone/D = locate(params["ref"])
if(D.stat != 2)
to_chat(usr, "<span class='danger'>You issue a kill command for the unfortunate drone.</span>")
message_admins("[key_name_admin(usr)] issued kill order for drone [key_name_admin(D)] from control console.")
log_game("[key_name(usr)] issued kill order for [key_name(src)] from control console.")
D.shut_down()
if("search_fab")
if(dronefab)
return
for(var/obj/machinery/drone_fabricator/fab in oview(3,src))
if(fab.stat & NOPOWER)
continue
dronefab = fab
to_chat(usr, "<span class='notice'>Drone fabricator located.</span>")
return
to_chat(usr, "<span class='danger'>Unable to locate drone fabricator.</span>")
if("toggle_fab")
if(!dronefab)
return
if(get_dist(src,dronefab) > 3)
dronefab = null
to_chat(usr, "<span class='danger'>Unable to locate drone fabricator.</span>")
return
dronefab.produce_drones = !dronefab.produce_drones
to_chat(usr, "<span class='notice'>You [dronefab.produce_drones ? "enable" : "disable"] drone production in the nearby fabricator.</span>")

View File

@@ -0,0 +1,25 @@
//Modified copy of regula drone folder
//Redefining some robot procs, since drones can't be repaired and really shouldn't take component damage.
/mob/living/silicon/robot/drone/take_overall_damage(var/brute = 0, var/burn = 0, var/sharp = FALSE, var/used_weapon = null)
bruteloss += brute
fireloss += burn
/mob/living/silicon/robot/drone/heal_overall_damage(var/brute, var/burn)
bruteloss -= brute
fireloss -= burn
if(bruteloss<0) bruteloss = 0
if(fireloss<0) fireloss = 0
/mob/living/silicon/robot/drone/take_organ_damage(var/brute = 0, var/burn = 0, var/sharp = FALSE, var/emp = 0)
take_overall_damage(brute,burn)
/mob/living/silicon/robot/drone/heal_organ_damage(var/brute, var/burn)
heal_overall_damage(brute,burn)
/mob/living/silicon/robot/drone/getFireLoss()
return fireloss
/mob/living/silicon/robot/drone/getBruteLoss()
return bruteloss

View File

@@ -1,3 +1,603 @@
//Modified copy of regula drone folder
//Simple borg hand.
//Limited use.
/obj/item/weapon/gripper
name = "magnetic gripper"
desc = "A simple grasping tool specialized in construction and engineering work."
description_info = "Ctrl-Clicking on the gripper will drop whatever it is holding.<br>\
Using an object on the gripper will interact with the item inside it, if it exists, instead."
icon = 'icons/obj/device.dmi'
icon_state = "gripper"
flags = NOBLUDGEON
//Has a list of items that it can hold.
var/list/can_hold = list(
/obj/item/weapon/cell,
/obj/item/weapon/airlock_electronics,
/obj/item/weapon/tracker_electronics,
/obj/item/weapon/module/power_control,
/obj/item/weapon/stock_parts,
/obj/item/frame,
/obj/item/weapon/camera_assembly,
/obj/item/weapon/tank,
/obj/item/weapon/circuitboard,
/obj/item/weapon/smes_coil,
/obj/item/weapon/fuel_assembly,
/obj/item/weapon/ore/bluespace_crystal
) // CHOMPEdit - Buffing the gripper to allow bluespace crystal use for telesci building.
var/obj/item/wrapped = null // Item currently being held.
var/force_holder = null //
/obj/item/weapon/gripper/examine(mob/user)
. = ..()
if(wrapped)
. += "<span class='notice'>\The [src] is holding \the [wrapped].</span>"
. += wrapped.examine(user)
/obj/item/weapon/gripper/CtrlClick(mob/user)
drop_item()
return
/obj/item/weapon/gripper/AltClick(mob/user)
drop_item()
return
/obj/item/weapon/gripper/omni
name = "omni gripper"
desc = "A strange grasping tool that can hold anything a human can, but still maintains the limitations of application its more limited cousins have."
icon_state = "gripper-omni"
can_hold = list(/obj/item) // Testing and Event gripper.
// VEEEEERY limited version for mining borgs. Basically only for swapping cells and upgrading the drills.
/obj/item/weapon/gripper/miner
name = "drill maintenance gripper"
desc = "A simple grasping tool for the maintenance of heavy drilling machines."
icon_state = "gripper-mining"
can_hold = list(
/obj/item/weapon/cell,
/obj/item/weapon/stock_parts
)
/obj/item/weapon/gripper/security
name = "security gripper"
desc = "A simple grasping tool for corporate security work."
icon_state = "gripper-sec"
can_hold = list(
/obj/item/weapon/paper,
/obj/item/weapon/paper_bundle,
/obj/item/weapon/pen,
/obj/item/weapon/sample,
/obj/item/weapon/forensics/sample_kit,
/obj/item/device/taperecorder,
/obj/item/device/tape,
/obj/item/device/uv_light
)
/obj/item/weapon/gripper/paperwork
name = "paperwork gripper"
desc = "A simple grasping tool for clerical work."
can_hold = list(
/obj/item/weapon/clipboard,
/obj/item/weapon/paper,
/obj/item/weapon/paper_bundle,
/obj/item/weapon/card/id,
/obj/item/weapon/book,
/obj/item/weapon/newspaper
)
/obj/item/weapon/gripper/medical
name = "medical gripper"
desc = "A simple grasping tool for medical work."
can_hold = list(
/obj/item/weapon/reagent_containers/glass,
/obj/item/weapon/storage/pill_bottle,
/obj/item/weapon/reagent_containers/pill,
/obj/item/weapon/reagent_containers/blood,
/obj/item/device/nif, //Chompedit Add Nif handling
/obj/item/stack/material/phoron,
/obj/item/weapon/tank/anesthetic,
/obj/item/weapon/disk/body_record //Vorestation Edit: this lets you get an empty sleeve or help someone else
)
/obj/item/weapon/gripper/research //A general usage gripper, used for toxins/robotics/xenobio/etc
name = "scientific gripper"
icon_state = "gripper-sci"
desc = "A simple grasping tool suited to assist in a wide array of research applications."
can_hold = list(
/obj/item/weapon/cell,
/obj/item/weapon/stock_parts,
/obj/item/device/mmi,
/obj/item/robot_parts,
/obj/item/borg/upgrade,
/obj/item/device/flash, //to build borgs,
/obj/item/weapon/disk,
/obj/item/weapon/circuitboard,
/obj/item/weapon/reagent_containers/glass,
/obj/item/device/assembly/prox_sensor,
/obj/item/device/healthanalyzer, //to build medibots,
/obj/item/slime_cube,
/obj/item/slime_crystal,
/obj/item/weapon/disposable_teleporter/slime,
/obj/item/slimepotion,
/obj/item/slime_extract,
/obj/item/weapon/reagent_containers/food/snacks/monkeycube
)
/obj/item/weapon/gripper/circuit
name = "circuit assembly gripper"
icon_state = "gripper-circ"
desc = "A complex grasping tool used for working with circuitry."
can_hold = list(
/obj/item/weapon/cell/device,
/obj/item/device/electronic_assembly,
/obj/item/device/assembly/electronic_assembly,
/obj/item/clothing/under/circuitry,
/obj/item/clothing/gloves/circuitry,
/obj/item/clothing/glasses/circuitry,
/obj/item/clothing/shoes/circuitry,
/obj/item/clothing/head/circuitry,
/obj/item/clothing/ears/circuitry,
/obj/item/clothing/suit/circuitry,
/obj/item/weapon/implant/integrated_circuit,
/obj/item/integrated_circuit
)
/obj/item/weapon/gripper/service //Used to handle food, drinks, and seeds.
name = "service gripper"
icon_state = "gripper"
desc = "A simple grasping tool used to perform tasks in the service sector, such as handling food, drinks, and seeds."
can_hold = list(
/obj/item/weapon/reagent_containers/glass,
/obj/item/weapon/reagent_containers/food,
/obj/item/seeds,
/obj/item/weapon/grown,
/obj/item/trash,
/obj/item/weapon/reagent_containers/cooking_container
)
/obj/item/weapon/gripper/gravekeeper //Used for handling grave things, flowers, etc.
name = "grave gripper"
icon_state = "gripper"
desc = "A specialized grasping tool used in the preparation and maintenance of graves."
can_hold = list(
/obj/item/seeds,
/obj/item/weapon/grown,
/obj/item/weapon/material/gravemarker
)
/obj/item/weapon/gripper/no_use/organ
name = "organ gripper"
icon_state = "gripper-flesh"
desc = "A specialized grasping tool used to preserve and manipulate organic material."
can_hold = list(
/obj/item/organ,
/obj/item/device/nif //NIFs can be slapped in during surgery
)
/obj/item/weapon/gripper/no_use/organ/Entered(var/atom/movable/AM)
if(istype(AM, /obj/item/organ))
var/obj/item/organ/O = AM
O.preserved = 1
for(var/obj/item/organ/organ in O)
organ.preserved = 1
..()
/obj/item/weapon/gripper/no_use/organ/Exited(var/atom/movable/AM)
if(istype(AM, /obj/item/organ))
var/obj/item/organ/O = AM
O.preserved = 0
for(var/obj/item/organ/organ in O)
organ.preserved = 0
..()
/obj/item/weapon/gripper/no_use/organ/robotics
name = "robotics organ gripper"
icon_state = "gripper-flesh"
desc = "A specialized grasping tool used in robotics work."
can_hold = list(
/obj/item/organ/external,
/obj/item/organ/internal/brain, //to insert into MMIs,
/obj/item/organ/internal/cell,
/obj/item/organ/internal/eyes/robot,
/obj/item/device/nif //NIFs can be slapped in during surgery
)
/obj/item/weapon/gripper/no_use/mech
name = "exosuit gripper"
icon_state = "gripper-mech"
desc = "A large, heavy-duty grasping tool used in construction of mechs."
can_hold = list(
/obj/item/mecha_parts/part,
//obj/item/mecha_parts/micro/part, //VOREStation Edit: Allow construction of micromechs //CHOMPedit commented micromech stuff, because fuck this trash
/obj/item/mecha_parts/mecha_equipment,
/obj/item/mecha_parts/mecha_tracking,
/obj/item/mecha_parts/component
)
/obj/item/weapon/gripper/no_use //Used when you want to hold and put items in other things, but not able to 'use' the item
/obj/item/weapon/gripper/no_use/attack_self(mob/user as mob)
return
/obj/item/weapon/gripper/no_use/loader //This is used to disallow building with metal.
name = "sheet loader"
desc = "A specialized loading device, designed to pick up and insert sheets of materials inside machines."
icon_state = "gripper-sheet"
can_hold = list(
/obj/item/stack/material
)
/obj/item/weapon/gripper/attack_self(mob/user as mob)
if(wrapped)
return wrapped.attack_self(user)
return ..()
/obj/item/weapon/gripper/attackby(var/obj/item/O, var/mob/user)
if(wrapped) // We're interacting with the item inside. If you can hold a cup with 2 fingers and stick a straw in it, you could do that with a gripper and another robotic arm.
wrapped.loc = src.loc
var/resolved = wrapped.attackby(O, user)
if(QDELETED(wrapped) || wrapped.loc != src.loc) //Juuuust in case.
wrapped = null
if(!resolved && wrapped && O)
O.afterattack(wrapped,user,1)
if(QDELETED(wrapped) || wrapped.loc != src.loc) // I don't know of a nicer way to do this.
wrapped = null
if(wrapped)
wrapped.loc = src
return resolved
return ..()
/obj/item/weapon/gripper/verb/drop_gripper_item()
set name = "Drop Item"
set desc = "Release an item from your magnetic gripper."
set category = "Robot Commands"
drop_item()
/obj/item/weapon/gripper/proc/drop_item()
if(!wrapped)
//There's some weirdness with items being lost inside the arm. Trying to fix all cases. ~Z
for(var/obj/item/thing in src.contents)
thing.loc = get_turf(src)
return
if(wrapped.loc != src)
wrapped = null
return
to_chat(src.loc, "<span class='notice'>You drop \the [wrapped].</span>")
wrapped.loc = get_turf(src)
wrapped = null
//update_icon()
/obj/item/weapon/gripper/proc/drop_item_nm()
if(!wrapped)
for(var/obj/item/thing in src.contents)
thing.loc = get_turf(src)
return
if(wrapped.loc != src)
wrapped = null
return
wrapped.loc = get_turf(src)
wrapped = null
//update_icon()
/obj/item/weapon/gripper/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
if(wrapped) //The force of the wrapped obj gets set to zero during the attack() and afterattack().
force_holder = wrapped.force
wrapped.force = 0.0
if(QDELETED(wrapped) || wrapped.loc != src.loc) //qdel check here so it doesn't duplicate/spawn ghost items
wrapped = null
else
wrapped.loc = src.loc //To ensure checks pass.
wrapped.attack(M,user)
M.attackby(wrapped, user) //attackby reportedly gets procced by being clicked on, at least according to Anewbe.
if(QDELETED(wrapped) || wrapped.loc != src.loc)
wrapped = null
if(wrapped) //In the event nothing happened to wrapped, go back into the gripper.
wrapped.loc = src
return 1
return 0
/obj/item/weapon/gripper/afterattack(var/atom/target, var/mob/living/user, proximity, params)
if(!proximity)
return // This will prevent them using guns at range but adminbuse can add them directly to modules, so eh.
//There's some weirdness with items being lost inside the arm. Trying to fix all cases. ~Z
if(!wrapped)
for(var/obj/item/thing in src.contents)
wrapped = thing
break
if(wrapped) //Already have an item.
//Temporary put wrapped into user so target's attackby() checks pass.
wrapped.loc = user
//Pass the attack on to the target. This might delete/relocate wrapped.
var/resolved = target.attackby(wrapped,user)
if(!resolved && wrapped && target)
wrapped.afterattack(target,user,1)
//wrapped's force was set to zero. This resets it to the value it had before.
if(wrapped)
wrapped.force = force_holder
force_holder = null
//If wrapped was neither deleted nor put into target, put it back into the gripper.
if(wrapped && user && (wrapped.loc == user))
wrapped.loc = src
else
wrapped = null
return
else if(istype(target,/obj/item)) //Check that we're not pocketing a mob.
//...and that the item is not in a container.
if(!isturf(target.loc))
return
var/obj/item/I = target
if(I.anchored)
to_chat(user,"<span class='notice'>You are unable to lift \the [I] from \the [I.loc].</span>")
return
//Check if the item is blacklisted.
var/grab = 0
for(var/typepath in can_hold)
if(istype(I,typepath))
grab = 1
break
//We can grab the item, finally.
if(grab)
to_chat(user, "You collect \the [I].")
I.loc = src
wrapped = I
return
else
to_chat(user, "<span class='danger'>Your gripper cannot hold \the [target].</span>")
else if(istype(target,/obj/machinery/power/apc))
var/obj/machinery/power/apc/A = target
if(A.opened)
if(A.cell)
wrapped = A.cell
A.cell.add_fingerprint(user)
A.cell.update_icon()
A.cell.loc = src
A.cell = null
A.charging = 0
A.update_icon()
user.visible_message("<span class='danger'>[user] removes the power cell from [A]!</span>", "You remove the power cell.")
else if(istype(target,/mob/living/silicon/robot))
var/mob/living/silicon/robot/A = target
if(A.opened)
if(A.cell)
wrapped = A.cell
A.cell.add_fingerprint(user)
A.cell.update_icon()
A.updateicon()
A.cell.loc = src
A.cell = null
user.visible_message("<span class='danger'>[user] removes the power cell from [A]!</span>", "You remove the power cell.")
//TODO: Matter decompiler.
/obj/item/weapon/matter_decompiler
name = "matter decompiler"
desc = "Eating trash, bits of glass, or other debris will replenish your stores."
icon = 'icons/obj/device.dmi'
icon_state = "decompiler"
//Metal, glass, wood, plastic.
var/datum/matter_synth/metal = null
var/datum/matter_synth/glass = null
var/datum/matter_synth/wood = null
var/datum/matter_synth/plastic = null
/obj/item/weapon/matter_decompiler/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
return
/obj/item/weapon/matter_decompiler/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, proximity, params)
if(!proximity) return //Not adjacent.
//We only want to deal with using this on turfs. Specific items aren't important.
var/turf/T = get_turf(target)
if(!istype(T))
return
//Used to give the right message.
var/grabbed_something = 0
for(var/mob/M in T)
if(istype(M,/mob/living/simple_mob/animal/passive/lizard) || istype(M,/mob/living/simple_mob/animal/passive/mouse))
src.loc.visible_message("<span class='danger'>[src.loc] sucks [M] into its decompiler. There's a horrible crunching noise.</span>","<span class='danger'>It's a bit of a struggle, but you manage to suck [M] into your decompiler. It makes a series of visceral crunching noises.</span>")
new/obj/effect/decal/cleanable/blood/splatter(get_turf(src))
qdel(M)
if(wood)
wood.add_charge(2000)
if(plastic)
plastic.add_charge(2000)
return
else if(istype(M,/mob/living/silicon/robot/drone) && !M.client)
var/mob/living/silicon/robot/D = src.loc
if(!istype(D))
return
to_chat(D, "<span class='danger'>You begin decompiling [M].</span>")
if(!do_after(D,50))
to_chat(D, "<span class='danger'>You need to remain still while decompiling such a large object.</span>")
return
if(!M || !D) return
to_chat(D, "<span class='danger'>You carefully and thoroughly decompile [M], storing as much of its resources as you can within yourself.</span>")
qdel(M)
new/obj/effect/decal/cleanable/blood/oil(get_turf(src))
if(metal)
metal.add_charge(15000)
if(glass)
glass.add_charge(15000)
if(wood)
wood.add_charge(2000)
if(plastic)
plastic.add_charge(1000)
return
else
continue
for(var/obj/W in T)
//Different classes of items give different commodities.
if(istype(W,/obj/item/trash/cigbutt))
if(plastic)
plastic.add_charge(500)
else if(istype(W,/obj/effect/spider/spiderling))
if(wood)
wood.add_charge(2000)
if(plastic)
plastic.add_charge(2000)
else if(istype(W,/obj/item/weapon/light))
var/obj/item/weapon/light/L = W
if(L.status >= 2) //In before someone changes the inexplicably local defines. ~ Z
if(metal)
metal.add_charge(250)
if(glass)
glass.add_charge(250)
else
continue
else if(istype(W,/obj/effect/decal/remains/robot))
if(metal)
metal.add_charge(2000)
if(plastic)
plastic.add_charge(2000)
if(glass)
glass.add_charge(1000)
else if(istype(W,/obj/item/trash))
if(metal)
metal.add_charge(1000)
if(plastic)
plastic.add_charge(3000)
else if(istype(W,/obj/effect/decal/cleanable/blood/gibs/robot))
if(metal)
metal.add_charge(2000)
if(glass)
glass.add_charge(2000)
else if(istype(W,/obj/item/ammo_casing))
if(metal)
metal.add_charge(1000)
else if(istype(W,/obj/item/weapon/material/shard/shrapnel))
if(metal)
metal.add_charge(1000)
else if(istype(W,/obj/item/weapon/material/shard))
if(glass)
glass.add_charge(1000)
else if(istype(W,/obj/item/weapon/reagent_containers/food/snacks/grown))
if(wood)
wood.add_charge(4000)
else if(istype(W,/obj/item/pipe))
// This allows drones and engiborgs to clear pipe assemblies from floors.
else
continue
qdel(W)
grabbed_something = 1
if(grabbed_something)
to_chat(user, "<span class='notice'>You deploy your decompiler and clear out the contents of \the [T].</span>")
else
to_chat(user, "<span class='danger'>Nothing on \the [T] is useful to you.</span>")
return
//PRETTIER TOOL LIST.
/mob/living/silicon/robot/drone/installed_modules()
if(weapon_lock)
to_chat(src, "<span class='danger'>Weapon lock active, unable to use modules! Count:[weaponlock_time]</span>")
return
if(!module)
module = new /obj/item/weapon/robot_module/drone(src)
var/dat = "<HEAD><TITLE>Drone modules</TITLE></HEAD><BODY>\n"
dat += {"
<B>Activated Modules</B>
<BR>
Module 1: [module_state_1 ? "<A HREF=?src=\ref[src];mod=\ref[module_state_1]>[module_state_1]<A>" : "No Module"]<BR>
Module 2: [module_state_2 ? "<A HREF=?src=\ref[src];mod=\ref[module_state_2]>[module_state_2]<A>" : "No Module"]<BR>
Module 3: [module_state_3 ? "<A HREF=?src=\ref[src];mod=\ref[module_state_3]>[module_state_3]<A>" : "No Module"]<BR>
<BR>
<B>Installed Modules</B><BR><BR>"}
var/tools = "<B>Tools and devices</B><BR>"
var/resources = "<BR><B>Resources</B><BR>"
for (var/O in module.modules)
var/module_string = ""
if (!O)
module_string += text("<B>Resource depleted</B><BR>")
else if(activated(O))
module_string += text("[O]: <B>Activated</B><BR>")
else
module_string += text("[O]: <A HREF=?src=\ref[src];act=\ref[O]>Activate</A><BR>")
if((istype(O,/obj/item/weapon) || istype(O,/obj/item/device)) && !(istype(O,/obj/item/stack/cable_coil)))
tools += module_string
else
resources += module_string
dat += tools
if (emagged)
if (!module.emag)
dat += text("<B>Resource depleted</B><BR>")
else if(activated(module.emag))
dat += text("[module.emag]: <B>Activated</B><BR>")
else
dat += text("[module.emag]: <A HREF=?src=\ref[src];act=\ref[module.emag]>Activate</A><BR>")
dat += resources
src << browse(dat, "window=robotmod")
//CHOMPADDITIONS
/obj/item/weapon/gripper/scene
name = "misc gripper"
desc = "A simple grasping tool that can hold a variety of 'general' objects..."
@@ -10,4 +610,4 @@
/obj/item/weapon/handcuffs,
/obj/item/toy,
/obj/item/petrifier
)
)

View File

@@ -0,0 +1,42 @@
//Defines the extra laws drones have
/datum/ai_laws/jani_drone
name = "Maintence Protocols"
law_header = "Maintenance Protocols"
/datum/ai_laws/drone/New()
add_inherent_law("Do not interfere with the maintenance work of non-drones whenever possible.")
add_inherent_law("Preserve, repair and improve the station to the best of your abilities.")
add_inherent_law("Cause no harm to the station or any crew on it.")
..()
/datum/ai_laws/construction_drone
name = "Construction Protocols"
law_header = "Construction Protocols"
/datum/ai_laws/construction_drone/New()
add_inherent_law("Do not interfere with the construction work of non-drones whenever possible.")
add_inherent_law("Repair, refit and upgrade your assigned vessel.")
add_inherent_law("Prevent unplanned damage to your assigned vessel wherever possible.")
..()
/datum/ai_laws/mining_drone
name = "Excavation Protocols"
law_header = "Excavation Protocols"
/datum/ai_laws/mining_drone/New()
add_inherent_law("Do not interfere with the excavation work of non-drones whenever possible.")
add_inherent_law("Provide materials for repairing, refitting, and upgrading your assigned vessel.")
add_inherent_law("Prevent unplanned damage to your assigned excavation equipment wherever possible.")
..()
/datum/ai_laws/security_drone
name = "Security Protocols"
law_header = "Security Protocols"
/datum/ai_laws/security_drone/New()
add_inherent_law("Do not interfere with the security work of non-drones whenever possible.")
add_inherent_law("Provide protection to the crew and eliminate hostile lifeforms on your assigned vessel.")
add_inherent_law("Obey orders by security personnel except if they violate law 4.")
add_inherent_law("Lethal force requires a code higher than green AND orders by security to use it to authorize it.")
add_inherent_law("You must outfit yourself with a security beret.")
..()

View File

@@ -0,0 +1,182 @@
//Modified copy of regula drone folder
/proc/count_drones()
var/drones = 0
for(var/mob/living/silicon/robot/drone/D in player_list)
drones++
return drones
/obj/machinery/drone_fabricator
name = "drone fabricator"
desc = "A large automated factory for producing maintenance drones."
appearance_flags = 0
density = TRUE
anchored = TRUE
use_power = USE_POWER_IDLE
idle_power_usage = 20
active_power_usage = 5000
var/fabricator_tag = "Upper Level"
var/drone_progress = 0
var/produce_drones = 2
var/time_last_drone = 500
var/drone_type = /mob/living/silicon/robot/drone
icon = 'icons/obj/machines/drone_fab.dmi'
icon_state = "drone_fab_idle"
var/list/possible_drones = list("Maintenance Module" = /mob/living/silicon/robot/drone)
/obj/machinery/drone_fabricator/derelict
name = "construction drone fabricator"
fabricator_tag = "Upper Level Construction"
drone_type = /mob/living/silicon/robot/drone/construction
possible_drones = list("Construction Module" = /mob/living/silicon/robot/drone/construction)
/obj/machinery/drone_fabricator/mining
name = "mining drone fabricator"
fabricator_tag = "Upper Level Mining"
drone_type = /mob/living/silicon/robot/drone/mining
possible_drones = list("Mining Module" = /mob/living/silicon/robot/drone/mining)
/obj/machinery/drone_fabricator/New()
..()
/obj/machinery/drone_fabricator/power_change()
..()
if (stat & NOPOWER)
icon_state = "drone_fab_nopower"
/obj/machinery/drone_fabricator/process()
if(ticker.current_state < GAME_STATE_PLAYING)
return
if(stat & NOPOWER || !produce_drones)
if(icon_state != "drone_fab_nopower") icon_state = "drone_fab_nopower"
return
if(drone_progress >= 100)
icon_state = "drone_fab_idle"
return
icon_state = "drone_fab_active"
var/elapsed = world.time - time_last_drone
drone_progress = round((elapsed/config.drone_build_time)*100)
if(drone_progress >= 100)
visible_message("\The [src] voices a strident beep, indicating a drone chassis is prepared.")
/obj/machinery/drone_fabricator/examine(mob/user)
. = ..()
if(produce_drones && drone_progress >= 100 && istype(user,/mob/observer/dead) && config.allow_drone_spawn && count_drones() < config.max_maint_drones)
. += "<br><B>A drone is prepared. Select 'Join As Drone' from the Ghost tab to spawn as a maintenance drone.</B>"
/obj/machinery/drone_fabricator/proc/create_drone(var/client/player)
choose_dronetype(possible_drones) //Call Drone choice before executing create_drone
if(stat & NOPOWER)
return
if(!produce_drones || !config.allow_drone_spawn || count_drones() >= config.max_maint_drones)
return
if(player && !istype(player.mob,/mob/observer/dead))
return
visible_message("\The [src] churns and grinds as it lurches into motion, disgorging a shiny new drone after a few moments.")
flick("h_lathe_leave",src)
drone_progress = 0
time_last_drone = world.time
var/mob/living/silicon/robot/drone/new_drone = new drone_type(get_turf(src))
if(player)
announce_ghost_joinleave(player, 0, "They have taken control over a maintenance drone.")
if(player.mob && player.mob.mind) player.mob.mind.reset()
new_drone.transfer_personality(player)
return new_drone
/mob/observer/dead/verb/join_as_drone()
set category = "Ghost"
set name = "Join As Drone"
set desc = "If there is a powered, enabled fabricator in the game world with a prepared chassis, join as a maintenance drone."
if(ticker.current_state < GAME_STATE_PLAYING)
to_chat(src, "<span class='danger'>The game hasn't started yet!</span>")
return
if(!(config.allow_drone_spawn))
to_chat(src, "<span class='danger'>That verb is not currently permitted.</span>")
return
if (!src.stat)
return
if (usr != src)
return 0 //something is terribly wrong
if(jobban_isbanned(src,"Cyborg"))
to_chat(usr, "<span class='danger'>You are banned from playing synthetics and cannot spawn as a drone.</span>")
return
// VOREStation Addition Start
if(config.use_age_restriction_for_jobs && isnum(src.client.player_age))
var/time_till_play = max(0, 3 - src.client.player_age)
if(time_till_play)
to_chat(usr, "<span class='danger'>You have not been playing on the server long enough to join as drone.</span>")
return
// VOREStation Addition End
if(!MayRespawn(1))
return
var/deathtime = world.time - src.timeofdeath
var/deathtimeminutes = round(deathtime / (1 MINUTE))
var/pluralcheck = "minute"
if(deathtimeminutes == 0)
pluralcheck = ""
else if(deathtimeminutes == 1)
pluralcheck = " [deathtimeminutes] minute and"
else if(deathtimeminutes > 1)
pluralcheck = " [deathtimeminutes] minutes and"
var/deathtimeseconds = round((deathtime - deathtimeminutes * 1 MINUTE) / 10,1)
if (deathtime < 5 MINUTES)
to_chat(usr, "You have been dead for[pluralcheck] [deathtimeseconds] seconds.")
to_chat(usr, "You must wait 5 minutes to respawn as a drone!")
return
var/list/all_fabricators = list()
for(var/obj/machinery/drone_fabricator/DF in machines)
if(DF.stat & NOPOWER || !DF.produce_drones)
continue
if(DF.drone_progress >= 100)
all_fabricators[DF.fabricator_tag] = DF
if(!all_fabricators.len)
to_chat(src, "<span class='danger'>There are no available drone spawn points, sorry.</span>")
return
var/choice = tgui_input_list(src, "Which fabricator do you wish to use?", "Fabricator Choice", all_fabricators)
if(choice)
var/obj/machinery/drone_fabricator/chosen_fabricator = all_fabricators[choice]
chosen_fabricator.create_drone(src.client)
//UNIFY, sub fabricator that can handle more than one type
/obj/machinery/drone_fabricator/unify //Non-Specific dronetype
drone_type = null //var filled by drone choice.
fabricator_tag = "Unified Drone Fabricator"
possible_drones = list("Construction Module" = /mob/living/silicon/robot/drone/construction,
"Maintenance Module" = /mob/living/silicon/robot/drone,
) //List of drone types to choose from.//Changeable in mapping.
/obj/machinery/drone_fabricator/proc/choose_dronetype(possible_drones)
if(!LAZYLEN(possible_drones)-1)
drone_type = possible_drones[1]
return
var/choice
choice = input(usr,"What module would you like to use?") as null|anything in possible_drones
if(!choice) return
drone_type = possible_drones[choice]

View File

@@ -0,0 +1,39 @@
//Modified copy of regula drone folder
/mob/living/silicon/robot/drone/say(var/message, var/datum/language/speaking = null, var/whispering = 0)
if(local_transmit)
if (src.client && client.prefs.muted & MUTE_IC)
to_chat(src, "You cannot send IC messages (muted).")
return 0
message = sanitize(message)
if (stat == DEAD)
return say_dead(message)
if(copytext(message,1,2) == "*")
return emote(copytext(message,2))
if(copytext(message,1,2) == ";")
var/datum/language/L = GLOB.all_languages["Drone Talk"]
if(istype(L))
return L.broadcast(src,trim(copytext(message,2)))
//Must be concious to speak
if (stat)
return 0
var/list/listeners = hearers(5,src)
listeners |= src
for(var/mob/living/silicon/D in listeners)
if(D.client && D.local_transmit)
to_chat(D, "<b>[src]</b> transmits, \"[message]\"")
for (var/mob/M in player_list)
if (istype(M, /mob/new_player))
continue
else if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears))
if(M.client)
to_chat(M, "<b>[src]</b> transmits, \"[message]\"")
return 1
return ..()

View File

@@ -0,0 +1,53 @@
//All of the different types of drones
/mob/living/silicon/robot/drone/construction
name = "construction drone"
icon_state = "constructiondrone"
law_type = /datum/ai_laws/construction_drone
module_type = /obj/item/weapon/robot_module/drone/construction
hat_x_offset = 1
hat_y_offset = -12
can_pull_mobs = MOB_PULL_SAME
can_pick_shell = FALSE
shell_accessories = list("eyes-constructiondrone")
//These are short overrides dont do this for long shit
welcome_drone()
to_chat(src, "<b>You are a construction drone, an autonomous engineering and fabrication system.</b>.")
to_chat(src, "You are assigned to a Sol Central construction project. The name is irrelevant. Your task is to complete construction and subsystem integration as soon as possible.")
to_chat(src, "Use <b>:d</b> to talk to other drones and <b>say</b> to speak silently to your nearby fellows.")
to_chat(src, "<b>You do not follow orders from anyone; not the AI, not humans, and not other synthetics.</b>.")
//These are short overrides dont do this for long shit
init()
..()
flavor_text = "It's a bulky construction drone stamped with a Sol Central glyph."
/mob/living/silicon/robot/drone/mining
icon_state = "miningdrone"
item_state = "constructiondrone"
law_type = /datum/ai_laws/mining_drone
module_type = /obj/item/weapon/robot_module/drone/mining
hat_x_offset = 1
hat_y_offset = -12
can_pull_mobs = MOB_PULL_SAME
can_pick_shell = FALSE
shell_accessories = list("eyes-miningdrone")
//These are short overrides dont do this for long shit
init()
..()
flavor_text = "It's a bulky mining drone stamped with a Grayson logo."
/mob/living/silicon/robot/drone
name = "unified drone" //Maintenance drones can be a Jani specific shell now, the normal drone will be a blank shell not really intended for use
law_type = /datum/ai_laws/drone
/mob/living/silicon/robot/drone/jan
name = "maintenance drone"
law_type = /datum/ai_laws/jani_drone
/mob/living/silicon/robot/drone/sec
name = "security drone"
law_type = /datum/ai_laws/security_drone
/mob/living/silicon/robot/drone/min
name = "mining drone"
law_type = /datum/ai_laws/mining_drone

View File

@@ -0,0 +1,72 @@
//Modified copy of regula drone folder
/mob/living/silicon/robot/drone/swarm
name = "swarm drone"
real_name = "drone"
icon = 'icons/mob/swarmbot.dmi'
icon_state = "swarmer"
item_state = "repairbot"
faction = "swarmer"
maxHealth = 35
health = 35
cell_emp_mult = 0.5
universal_speak = 0
universal_understand = 1
gender = NEUTER
pass_flags = PASSTABLE
braintype = "Drone"
lawupdate = 0
density = TRUE
idcard_type = /obj/item/weapon/card/id/syndicate
req_access = list(999)
integrated_light_power = 3
local_transmit = 0
can_pull_size = ITEMSIZE_NO_CONTAINER
can_pull_mobs = MOB_PULL_SMALLER
can_enter_vent_with = list(
/obj,
/atom/movable/emissive_blocker)
mob_always_swap = 1
speed = 3
softfall = TRUE
mob_size = MOB_LARGE
law_type = /datum/ai_laws/swarm_drone
module_type = /obj/item/weapon/robot_module/drone/swarm
hat_x_offset = 0
hat_y_offset = -10
foreign_droid = TRUE
scrambledcodes = TRUE
holder_type = /obj/item/weapon/holder/drone
can_be_antagged = TRUE
var/spell_setup = list(
/spell/aoe_turf/conjure/swarmer,
/spell/aoe_turf/conjure/forcewall/swarm,
/spell/aoe_turf/conjure/zeropointwell,
/spell/aoe_turf/conjure/zeropointbarricade,
/spell/aoe_turf/blink/swarm,
/spell/aoe_turf/conjure/swarmer/gunner,
/spell/aoe_turf/conjure/swarmer/melee
)
/mob/living/silicon/robot/drone/swarm/Initialize()
. = ..()
add_language(LANGUAGE_SWARMBOT, 1)
for(var/spell in spell_setup)
src.add_spell(new spell, "nano_spell_ready", /obj/screen/movable/spell_master/swarm)
/mob/living/silicon/robot/drone/swarm/init()
..()
QDEL_NULL(aiCamera)
flavor_text = "Some form of ancient machine."

View File

@@ -0,0 +1,117 @@
//Modified copy of regula drone folder
/spell/aoe_turf/conjure/swarmer
name = "Self Replication"
desc = "This ability constructs a standard swarmer shell that may activate at some point."
school = "conjuration"
charge_max = 5 MINUTES
spell_flags = 0
invocation = "none"
invocation_type = SpI_NONE
range = 0
summon_type = list(/obj/structure/ghost_pod/ghost_activated/swarm_drone/event)
hud_state = "swarm_replicate"
/spell/aoe_turf/conjure/swarmer/conjure_animation(var/atom/movable/overlay/animation, var/turf/target)
animation.icon_state = "deflect_static"
flick("shield2",animation)
spawn(1 SECOND)
qdel(animation)
/spell/aoe_turf/conjure/forcewall/swarm
name = "Null-Field"
desc = "Create a bubble of null-point energy."
summon_type = list(/obj/effect/forcefield/swarm)
duration = 30 SECONDS
charge_max = 60 SECONDS
school = "conjuration"
invocation = "none"
invocation_type = SpI_NONE
range = 0
hud_state = "wiz_shield"
/obj/effect/forcefield/swarm
desc = "A pocket of strange energy."
name = "Null-Field"
icon = 'icons/effects/effects.dmi'
icon_state = "shield-old"
invisibility = 0
/spell/aoe_turf/conjure/zeropointwell
name = "Zero-Point Well"
desc = "This ability constructs a standard zero-point energy well, capable of charging nearby swarmers."
school = "conjuration"
charge_max = 120 SECONDS
spell_flags = 0
invocation = "none"
invocation_type = SpI_NONE
range = 0
summon_type = list(/obj/structure/cult/pylon/swarm/zp_well)
hud_state = "swarm_zeropoint"
/spell/aoe_turf/conjure/zeropointbarricade
name = "Zero-Point Barricade"
desc = "This ability constructs a standard zero-point energy wall, used to create a secure passageway for allies, and a bastion for defense."
school = "conjuration"
charge_max = 120 SECONDS
spell_flags = 0
invocation = "none"
invocation_type = SpI_NONE
range = 0
summon_type = list(/obj/structure/cult/pylon/swarm/defender)
hud_state = "swarm_barricade"
/spell/aoe_turf/blink/swarm
name = "Warp"
desc = "Your null-point drive jaunts you to a new location."
school = "abjuration"
charge_max = 5 MINUTES
spell_flags = Z2NOCAST | IGNOREDENSE
invocation = "none"
invocation_type = SpI_NONE
range = 10
inner_radius = 5
hud_state = "swarm_warp"
/spell/aoe_turf/conjure/swarmer/gunner
name = "Generate Gunner"
desc = "This spell constructs a gunner swarmer shell that may activate at some point."
school = "conjuration"
charge_type = Sp_CHARGES
charge_max = 1
spell_flags = 0
invocation = "none"
invocation_type = SpI_NONE
range = 0
summon_type = list(/obj/structure/ghost_pod/ghost_activated/swarm_drone/event/gunner)
hud_state = "swarm_replicate"
/spell/aoe_turf/conjure/swarmer/melee
name = "Generate Impaler"
desc = "This spell constructs an impaler swarmer shell that may activate at some point."
school = "conjuration"
charge_type = Sp_CHARGES
charge_max = 1
spell_flags = 0
invocation = "none"
invocation_type = SpI_NONE
range = 0
summon_type = list(/obj/structure/ghost_pod/ghost_activated/swarm_drone/event/melee)
hud_state = "swarm_replicate"

View File

@@ -0,0 +1,162 @@
//Modified copy of regula drone folder
//Swarm Assimilator / Breacher
/obj/item/weapon/matter_decompiler/swarm
name = "matter assimilator"
desc = "Used to eat some forms of simple machinery; and large, wall-shaped blocks of metal with energetic fields."
icon = 'icons/obj/device.dmi'
icon_state = "decompiler_swarm"
var/field_cooldown = 1 MINUTE
var/last_field = 0
/obj/item/weapon/matter_decompiler/swarm/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, proximity, params)
if(!proximity) return //Not adjacent.
//We only want to deal with using this on turfs. Specific items aren't important.
var/turf/T = get_turf(target)
if(!istype(T))
return
//Used to give the right message.
var/grabbed_something = FALSE
for(var/mob/M in T)
if(istype(M,/mob/living/simple_mob/animal/passive/lizard) || istype(M,/mob/living/simple_mob/animal/passive/mouse))
src.loc.visible_message("<span class='danger'>[src.loc] sucks [M] into its decompiler. There's a horrible crunching noise.</span>","<span class='danger'>It's a bit of a struggle, but you manage to suck [M] into your decompiler. It makes a series of visceral crunching noises.</span>")
new/obj/effect/decal/cleanable/blood/splatter(get_turf(src))
qdel(M)
if(wood)
wood.add_charge(2000)
if(plastic)
plastic.add_charge(2000)
return
else if(istype(M,/mob/living/silicon/robot/drone) && !M.client)
var/mob/living/silicon/robot/D = src.loc
if(!istype(D))
return
to_chat(D, "<span class='danger'>You begin decompiling [M].</span>")
if(!do_after(D,50))
to_chat(D, "<span class='danger'>You need to remain still while decompiling such a large object.</span>")
return
if(!M || !D) return
to_chat(D, "<span class='danger'>You carefully and thoroughly decompile [M], storing as much of its resources as you can within yourself.</span>")
qdel(M)
new/obj/effect/decal/cleanable/blood/oil(get_turf(src))
if(metal)
metal.add_charge(15000)
if(glass)
glass.add_charge(15000)
if(wood)
wood.add_charge(2000)
if(plastic)
plastic.add_charge(1000)
return
else
continue
for(var/obj/W in T)
//Different classes of items give different commodities.
if(istype(W,/obj/structure/girder))
if(metal)
metal.add_charge(500)
else if(istype(W,/obj/machinery/power/emitter))
if(metal)
metal.add_charge(3000)
if(plastic)
plastic.add_charge(1000)
else if(istype(W,/obj/machinery/space_heater))
if(metal)
metal.add_charge(1500)
if(plastic)
plastic.add_charge(750)
else if(istype(W,/obj/structure/closet))
var/obj/structure/closet/C = W
if(!C.opened)
continue
if(istype(W,/obj/structure/closet/coffin))
if(wood)
wood.add_charge(1000)
else if(istype(W,/obj/structure/closet/crate/plastic))
if(plastic)
plastic.add_charge(750)
else
if(metal)
metal.add_charge(1000)
else
continue
qdel(W)
grabbed_something = TRUE
if(istype(T,/turf/simulated/wall) && (last_field < world.time + field_cooldown))
if(!(locate(/obj/effect/temporary_effect/pulse/disintegrate)))
last_field = world.time
to_chat(user, "<span class='alien'>You deploy an energetic field through \the [T], beginning its deconstruction.</span>")
to_chat(user, "<span class='warning'>You should stand back.</span>")
new /obj/effect/temporary_effect/pulse/disintegrate(T)
else
to_chat(user, "<span class='notice'>There is already a disintigration field affecting \the [T].</span>")
if(grabbed_something)
to_chat(user, "<span class='notice'>You deploy your decompiler and clear out the contents of \the [T].</span>")
else
to_chat(user, "<span class='danger'>Nothing on \the [T] is useful to you.</span>")
return
/obj/effect/temporary_effect/pulse/disintegrate
name = "molecular debonding field"
desc = "This is something you do not want to near."
icon = 'icons/mob/swarmbot.dmi'
icon_state = "disintegrate_pulse"
light_range = 4
light_power = 5
light_color = "#00B4D9"
pulses_remaining = 5
pulse_delay = 2 SECONDS
/obj/effect/temporary_effect/pulse/disintegrate/emp_act()
visible_message("<span class='warning'>\The [src] flickers, before dispersing energetically.</span>")
qdel(src)
/obj/effect/temporary_effect/pulse/disintegrate/on_pulse()
var/turf/T = get_turf(src)
if(istype(T,/turf/simulated/wall))
T.take_damage(rand(20, 50))
else
qdel(src)
/obj/effect/temporary_effect/pulse/disintegrate/Destroy()
if(istype(get_turf(src), /turf/simulated/wall))
explosion(get_turf(src), -1, 1, 2, 5, adminlog = 1)
..()
/obj/item/weapon/gun/energy/xray/swarm
name = "spectral projector"
desc = "A high-power laser gun capable of expelling concentrated gamma blasts, which are able to penetrate matter easier than \
standard xray beams, resulting in an effective 'anti-everything' energy weapon."
icon_state = "xray"
item_state = "xray"
origin_tech = list(TECH_COMBAT = 5, TECH_MATERIAL = 3, TECH_MAGNET = 2)
projectile_type = /obj/item/projectile/beam/shock
charge_cost = 175
self_recharge = TRUE
use_external_power = TRUE
firemodes = list(
list(mode_name="kill", projectile_type=/obj/item/projectile/beam/gamma, charge_cost = 300),
list(mode_name="deter", projectile_type=/obj/item/projectile/beam/shock, charge_cost = 175),
)
/obj/item/weapon/gun/energy/xray/swarm/Initialize()
. = ..()
adjust_scale(-1, 1)

View File

@@ -0,0 +1,41 @@
/mob/living/silicon/robot/drone/swarm/gunner
name = "swarm gunner"
real_name = "drone"
icon = 'icons/mob/swarmbot.dmi'
icon_state = "swarmer_ranged"
faction = "swarmer"
maxHealth = 50
health = 50
speed = 4
law_type = /datum/ai_laws/swarm_drone/soldier
module_type = /obj/item/weapon/robot_module/drone/swarm/ranged
spell_setup = list(
/spell/aoe_turf/conjure/swarmer,
/spell/aoe_turf/conjure/forcewall/swarm,
/spell/aoe_turf/blink/swarm
)
/mob/living/silicon/robot/drone/swarm/melee
name = "swarm melee"
real_name = "drone"
icon = 'icons/mob/swarmbot.dmi'
icon_state = "swarmer_melee"
faction = "swarmer"
maxHealth = 70
health = 70
speed = 2
law_type = /datum/ai_laws/swarm_drone/soldier
module_type = /obj/item/weapon/robot_module/drone/swarm/melee
spell_setup = list(
/spell/aoe_turf/conjure/swarmer,
/spell/aoe_turf/conjure/forcewall/swarm,
/spell/aoe_turf/blink/swarm
)