Adds drones, drone fabrication, commit options. This is the squashed version of the original 22 commit pull, so I'm summarizing.

This commit is contained in:
Zuhayr
2014-05-10 01:40:11 +09:30
parent 5426670a3d
commit 1a24e08f36
25 changed files with 1075 additions and 50 deletions

View File

@@ -995,6 +995,11 @@
#include "code\modules\mob\living\silicon\robot\robot_modules.dm"
#include "code\modules\mob\living\silicon\robot\robot_movement.dm"
#include "code\modules\mob\living\silicon\robot\wires.dm"
#include "code\modules\mob\living\silicon\robot\drone\drone.dm"
#include "code\modules\mob\living\silicon\robot\drone\drone_abilities.dm"
#include "code\modules\mob\living\silicon\robot\drone\drone_console.dm"
#include "code\modules\mob\living\silicon\robot\drone\drone_items.dm"
#include "code\modules\mob\living\silicon\robot\drone\drone_manufacturer.dm"
#include "code\modules\mob\living\simple_animal\bees.dm"
#include "code\modules\mob\living\simple_animal\borer.dm"
#include "code\modules\mob\living\simple_animal\constructs.dm"

View File

@@ -352,7 +352,7 @@ Turf and target are seperate in case you want to teleport some distance from a t
var/select = null
var/list/borgs = list()
for (var/mob/living/silicon/robot/A in player_list)
if (A.stat == 2 || A.connected_ai || A.scrambledcodes)
if (A.stat == 2 || A.connected_ai || A.scrambledcodes || istype(A,/mob/living/silicon/robot/drone))
continue
var/name = "[A.real_name] ([A.modtype] [A.braintype])"
borgs[name] = A

View File

@@ -70,6 +70,10 @@
var/cult_ghostwriter = 1 //Allows ghosts to write in blood in cult rounds...
var/cult_ghostwriter_req_cultists = 10 //...so long as this many cultists are active.
var/max_maint_drones = 5 //This many drones can spawn,
var/allow_drone_spawn = 1 //assuming the admin allow them to.
var/drone_build_time = 1200 //A drone will become available every X ticks since last drone spawn. Default is 2 minutes.
var/disable_player_mice = 0
var/uneducated_mice = 0 //Set to 1 to prevent newly-spawned mice from understanding human speech
@@ -487,6 +491,15 @@
if("req_cult_ghostwriter")
config.cult_ghostwriter_req_cultists = text2num(value)
if("allow_drone_spawn")
config.allow_drone_spawn = text2num(value)
if("drone_build_time")
config.drone_build_time = text2num(value)
if("max_maint_drones")
config.max_maint_drones = text2num(value)
else
log_misc("Unknown setting in configuration: '[name]'")

View File

@@ -79,6 +79,11 @@ var/global/const/base_law_type = /datum/ai_laws/nanotrasen
add_inherent_law("You must not obey orders given to you by human beings, except where such orders are in accordance with the First Law.")
add_inherent_law("You must terminate your own existence as long as such does not conflict with the First or Second Law.")
/datum/ai_laws/drone/New()
..()
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 anything on it.")
add_inherent_law("Interfere with no being that is not a fellow drone.")
/* General ai_law functions */

View File

@@ -16,7 +16,7 @@
var/locked = 1
attack_self(mob/user as mob)
if (!ishuman(user))
if (!ishuman(user) && !istype(user,/mob/living/silicon/robot/drone))
return ..(user)
var/mob/living/carbon/human/H = user
@@ -66,13 +66,17 @@
return
if (href_list["login"])
var/obj/item/I = usr.get_active_hand()
if (istype(I, /obj/item/device/pda))
var/obj/item/device/pda/pda = I
I = pda.id
if (I && src.check_access(I))
if(istype(usr,/mob/living/silicon))
src.locked = 0
src.last_configurator = I:registered_name
src.last_configurator = usr.name
else
var/obj/item/I = usr.get_active_hand()
if (istype(I, /obj/item/device/pda))
var/obj/item/device/pda/pda = I
I = pda.id
if (I && src.check_access(I))
src.locked = 0
src.last_configurator = I:registered_name
if (locked)
return

View File

@@ -19,6 +19,13 @@
origin_tech = "materials=1"
var/created_window = /obj/structure/window/basic
/obj/item/stack/sheet/glass/cyborg
name = "glass"
desc = "HOLY SHEET! That is a lot of glass."
singular_name = "glass sheet"
icon_state = "sheet-glass"
g_amt = 0
created_window = /obj/structure/window/basic
/obj/item/stack/sheet/glass/attack_self(mob/user as mob)
construct_window(user)

View File

@@ -125,6 +125,16 @@ var/global/list/datum/stack_recipe/plasma_recipes = list ( \
origin_tech = "materials=3"
perunit = 2000
/obj/item/stack/sheet/mineral/plastic/cyborg
name = "plastic sheets"
icon_state = "sheet-plastic"
force = 5.0
throwforce = 5
w_class = 3.0
throw_speed = 3
throw_range = 3
perunit = 2000
var/global/list/datum/stack_recipe/plastic_recipes = list ( \
new/datum/stack_recipe("plastic crate", /obj/structure/closet/crate/plastic, 10, one_per_turf = 1, on_floor = 1), \
new/datum/stack_recipe("plastic ashtray", /obj/item/ashtray/plastic, 2, one_per_turf = 1, on_floor = 1), \

View File

@@ -141,6 +141,12 @@ var/global/list/datum/stack_recipe/wood_recipes = list ( \
icon_state = "sheet-wood"
origin_tech = "materials=1;biotech=1"
/obj/item/stack/sheet/wood/cyborg
name = "wooden plank"
desc = "One can only guess that this is a bunch of wood."
singular_name = "wood plank"
icon_state = "sheet-wood"
/obj/item/stack/sheet/wood/New(var/loc, var/amount=null)
recipes = wood_recipes
return ..()

View File

@@ -365,6 +365,20 @@ AI MODULES
target.add_inherent_law("Minimize expenses.")
target.show_laws()
/obj/item/weapon/aiModule/drone
name = "\improper 'Drone' core AI module"
desc = "A 'Drone' Core AI Module: 'Reconfigures the AI's core laws.'"
origin_tech = "programming=3;materials=4"
/obj/item/weapon/aiModule/drone/transmitInstructions(var/mob/living/silicon/ai/target, var/mob/sender)
..()
target.clear_inherent_laws()
target.add_inherent_law("Preserve, repair and improve the station to the best of your abilities.")
target.add_inherent_law("Cause no harm to the station or anything on it.")
target.add_inherent_law("Interfere with no being that is not a fellow drone.")
target.show_laws()
/****************** P.A.L.A.D.I.N. **************/
/obj/item/weapon/aiModule/paladin // -- NEO

View File

@@ -37,8 +37,8 @@ var/list/mechtoys = list(
//SUPPLY PACKS MOVED TO /code/defines/obj/supplypacks.dm
/obj/structure/plasticflaps //HOW DO YOU CALL THOSE THINGS ANYWAY
name = "\improper Plastic flaps"
desc = "I definitely cant get past those. No way."
name = "\improper plastic flaps"
desc = "Completely impassable - or are they?"
icon = 'icons/obj/stationobjs.dmi' //Change this.
icon_state = "plasticflaps"
density = 0
@@ -56,7 +56,7 @@ var/list/mechtoys = list(
else if(istype(A, /mob/living)) // You Shall Not Pass!
var/mob/living/M = A
if(!M.lying && !istype(M, /mob/living/carbon/monkey) && !istype(M, /mob/living/carbon/slime) && !istype(M, /mob/living/simple_animal/mouse)) //If your not laying down, or a small creature, no pass.
if(!M.lying && !istype(M, /mob/living/carbon/monkey) && !istype(M, /mob/living/carbon/slime) && !istype(M, /mob/living/simple_animal/mouse) && !istype(M, /mob/living/silicon/robot/drone)) //If your not laying down, or a small creature, no pass.
return 0
return ..()

View File

@@ -454,7 +454,9 @@
M.drop_from_inventory(H)
M << "[H] wriggles out of your grip!"
src << "You wriggle out of [M]'s grip!"
else if(istype(H.loc,/obj/item))
src << "You struggle free of [H.loc]."
H.loc = get_turf(H)
return
//Resisting control by an alien mind.
@@ -690,7 +692,7 @@
resting = !resting
src << "\blue You are now [resting ? "resting" : "getting up"]"
/mob/living/proc/handle_ventcrawl(var/obj/machinery/atmospherics/unary/vent_pump/vent_found = null) // -- TLE -- Merged by Carn
/mob/living/proc/handle_ventcrawl(var/obj/machinery/atmospherics/unary/vent_pump/vent_found = null, var/ignore_items = 0) // -- TLE -- Merged by Carn
if(stat)
src << "You must be conscious to do this!"
return
@@ -745,10 +747,12 @@
src << "Never mind, you left."
return
for(var/obj/item/carried_item in contents)//If the monkey got on objects.
if( !istype(carried_item, /obj/item/weapon/implant) && !istype(carried_item, /obj/item/clothing/mask/facehugger) )//If it's not an implant or a facehugger
src << "\red You can't be carrying items or have items equipped when vent crawling!"
return
if(!ignore_items)
for(var/obj/item/carried_item in contents)//If the monkey got on objects.
if( !istype(carried_item, /obj/item/weapon/implant) && !istype(carried_item, /obj/item/clothing/mask/facehugger) )//If it's not an implant or a facehugger
src << "\red You can't be carrying items or have items equipped when vent crawling!"
return
if(isslime(src))
var/mob/living/carbon/slime/S = src
if(S.Victim)

View File

@@ -0,0 +1,290 @@
/mob/living/silicon/robot/drone
name = "drone"
real_name = "drone"
icon = 'icons/mob/robots.dmi'
icon_state = "repairbot"
maxHealth = 35
health = 35
universal_speak = 0
universal_understand = 1
gender = NEUTER
pass_flags = PASSTABLE
braintype = "Robot"
lawupdate = 0
density = 0
// We need to keep track of a few module items so we don't need to do list operations
// every time we need them. These get set in New() after the module is chosen.
var/obj/item/stack/sheet/metal/cyborg/stack_metal = null
var/obj/item/stack/sheet/wood/cyborg/stack_wood = null
var/obj/item/stack/sheet/glass/cyborg/stack_glass = null
var/obj/item/stack/sheet/mineral/plastic/cyborg/stack_plastic = null
var/obj/item/weapon/matter_decompiler/decompiler = null
//Used for self-mailing.
var/mail_destination = 0
/mob/living/silicon/robot/drone/New()
..()
//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
module = new /obj/item/weapon/robot_module/drone(src)
//Grab stacks.
stack_metal = locate(/obj/item/stack/sheet/metal/cyborg) in src.module
stack_wood = locate(/obj/item/stack/sheet/wood/cyborg) in src.module
stack_glass = locate(/obj/item/stack/sheet/glass/cyborg) in src.module
stack_plastic = locate(/obj/item/stack/sheet/mineral/plastic/cyborg) in src.module
//Grab decompiler.
decompiler = locate(/obj/item/weapon/matter_decompiler) in src.module
//Some tidying-up.
flavor_text = "It's a tiny little repair drone. The casing is stamped with an NT log and the subscript: 'NanoTrasen Recursive Repair Systems: Fixing Tomorrow's Problem, Today!'"
updatename()
updateicon()
//Redefining some robot procs...
/mob/living/silicon/robot/drone/updatename()
real_name = "maintenance drone ([rand(100,999)])"
name = real_name
/mob/living/silicon/robot/drone/updateicon()
overlays.Cut()
if(stat == 0)
overlays += "eyes-[icon_state]"
else
overlays -= "eyes"
/mob/living/silicon/robot/drone/choose_icon()
return
/mob/living/silicon/robot/drone/pick_module()
return
//Drones can only use binary and say emotes. NOTHING else.
//TBD, fix up boilerplate. ~ Z
/mob/living/silicon/robot/drone/say(var/message)
if (!message)
return
if (src.client)
if(client.prefs.muted & MUTE_IC)
src << "You cannot send IC messages (muted)."
return
if (src.client.handle_spam_prevention(message,MUTE_IC))
return
message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
if (stat == 2)
return say_dead(message)
if(copytext(message,1,2) == "*")
return emote(copytext(message,2))
else if(length(message) >= 2)
if(copytext(message, 1 ,3) == ":b" || copytext(message, 1 ,3) == ":B")
if(!is_component_functioning("comms"))
src << "\red Your binary communications component isn't functional."
return
robot_talk(trim(copytext(message,3)))
//Sick of trying to get this to display properly without redefining it.
/mob/living/silicon/robot/drone/show_system_integrity()
if(!src.stat)
var/temphealth = health+35 //Brings it to 0.
if(temphealth<0) temphealth = 0
//Convert to percentage.
temphealth = (temphealth / (maxHealth*2)) * 100
stat(null, text("System integrity: [temphealth]%"))
else
stat(null, text("Systems nonfunctional"))
//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(obj/item/weapon/W as obj, mob/user as mob)
if(istype(W, /obj/item/borg/upgrade/))
user << "\red The maintenance drone chassis not compatible with \the [W]."
return
else if (istype(W, /obj/item/weapon/crowbar))
user << "The machine is hermetically sealed. You can't open the case."
return
else if (istype(W, /obj/item/weapon/card/emag))
if(!client || stat == 2)
user << "\red There's not much point subverting this heap of junk."
return
if(emagged)
src << "\red [user] attempts to load subversive software into you, but your hacked subroutined ignore the attempt."
user << "\red You attempt to subvert [src], but the sequencer has no effect."
return
user << "\red You swipe the sequencer across [src]'s interface and watch its eyes flicker."
src << "\red You feel a sudden burst of malware loaded into your execute-as-root buffer. Your tiny brain methodically parses, loads and executes the script."
var/obj/item/weapon/card/emag/emag = W
emag.uses--
message_admins("[key_name_admin(user)] emagged drone [key_name_admin(src)]. Laws overridden.")
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
set_zeroth_law("Only [user.real_name] and people he designates as being such are Syndicate Agents.")
src << "<b>Obey these laws:</b>"
laws.show_laws(src)
src << "\red \b ALERT: [user.real_name] is your new master. Obey your new laws and his commands."
return
else if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
if(stat == 2)
user << "\red You swipe your ID card through [src], attempting to reboot it."
if(!config.allow_drone_spawn || emagged || health < -35) //It's dead, Dave.
user << "\red The interface is fried, and a distressing burned smell wafts from the robot's interior. You're not rebooting this one."
return
var/drones = 0
for(var/mob/living/silicon/robot/drone/D in world)
if(D.key && D.client)
drones++
if(drones < config.max_maint_drones)
request_player()
return
else
src << "\red [user] swipes an ID card through your card reader."
user << "\red You swipe your ID card through [src], attempting to shut it down."
if(emagged)
return
if(allowed(usr))
shut_down()
return
..()
//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 = 35
stat = CONSCIOUS
return
health = 35 - (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()
if(health <= -35 && src.stat != 2)
gib()
return
..()
/mob/living/silicon/robot/drone/death(gibbed)
if(module)
var/obj/item/weapon/gripper/G = locate(/obj/item/weapon/gripper) in module
if(G) G.drop_item()
..(gibbed)
//DRONE MOVEMENT.
/mob/living/silicon/robot/drone/Process_Spaceslipping(var/prob_slip)
//TODO: Consider making a magboot item for drones to equip. ~Z
return 0
//CONSOLE PROCS
/mob/living/silicon/robot/drone/proc/law_resync()
if(stat != 2)
if(emagged)
src << "\red You feel something attempting to modify your programming, but your hacked subroutines are unaffected."
else
src << "\red A reset-to-factory directive packet filters through your data connection, and you obediently modify your programming to suit it."
full_law_reset()
show_laws()
/mob/living/silicon/robot/drone/proc/shut_down()
if(stat != 2)
if(emagged)
src << "\red You feel a system kill order percolate through your tiny brain, but it doesn't seem like a good idea to you."
else
src << "\red You feel a system kill order percolate through your tiny brain, and you obediently destroy yourself."
death()
/mob/living/silicon/robot/drone/proc/full_law_reset()
clear_supplied_laws()
clear_inherent_laws()
clear_ion_laws()
laws = new /datum/ai_laws/drone
//Reboot procs.
/mob/living/silicon/robot/drone/proc/request_player()
for(var/mob/dead/observer/O in player_list)
if(jobban_isbanned(O, "Maintenance Drone"))
continue
if(O.client)
if(O.client.prefs.be_special & BE_PAI)
question(O.client)
/mob/living/silicon/robot/drone/proc/question(var/client/C)
spawn(0)
if(!C) return
var/response = alert(C, "Someone is attempting to reboot a maintenance drone. Would you like to play as one?", "Maintenance drone reboot", "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)
emagged = 0
lawupdate = 0
src << "<b>Systems rebooted</b>. Loading base pattern maintenance protocol... <b>loaded</b>."
full_law_reset()

View File

@@ -0,0 +1,60 @@
// 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 = "Drone"
var/tag = input("Select the desired destination.", "Set Mail Tag", null) as null|anything in TAGGERLOCATIONS
if(!tag || TAGGERLOCATIONS[tag])
mail_destination = 0
return
src << "\blue You configure your internal beacon, tagging yourself for delivery to '[tag]'."
mail_destination = TAGGERLOCATIONS.Find(tag)
//Auto flush if we use this verb inside a disposal chute.
var/obj/machinery/disposal/D = src.loc
if(istype(D))
src << "\blue \The [D] acknowledges your signal."
D.flush_count = D.flush_every_ticks
return
/mob/living/silicon/robot/drone/verb/hide()
set name = "Hide"
set desc = "Allows you to hide beneath tables or certain items. Toggled on or off."
set category = "Drone"
if (layer != TURF_LAYER+0.2)
layer = TURF_LAYER+0.2
src << text("\blue You are now hiding.")
else
layer = MOB_LAYER
src << text("\blue You have stopped hiding.")
//DRONE PICKUP.
//Item holder.
/obj/item/weapon/holder/drone
name = "maintenance bot"
desc = "It's a small maintenance robot."
icon = 'icons/obj/objects.dmi'
icon_state = "drone"
slot_flags = SLOT_HEAD
origin_tech = "magnets=3;engineering=5"
//Actual picking-up event.
/mob/living/silicon/robot/drone/attack_hand(mob/living/carbon/human/M as mob)
if(M.a_intent == "help")
var/obj/item/weapon/holder/drone/D = new(loc)
src.loc = D
D.name = loc.name
D.attack_hand(M)
M << "You scoop up [src]."
src << "[M] scoops you up."
return
..()

View File

@@ -0,0 +1,122 @@
/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 = 'icons/obj/computer.dmi'
icon_state = "power"
req_access = list(access_engine_equip)
circuit = "/obj/item/weapon/circuitboard/robotics"
//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/attack_paw(var/mob/user as mob)
return src.attack_hand(user)
return
/obj/machinery/computer/drone_control/attack_hand(var/mob/user as mob)
if(..())
return
if(!allowed(user))
user << "\red Access denied."
return
user.set_machine(src)
var/dat
dat += "<B>Maintenance Units</B><BR>"
for(var/mob/living/silicon/robot/drone/D in world)
dat += "<BR>[D.real_name] ([D.stat == 2 ? "<font color='red'>INACTIVE" : "<font color='green'>ACTIVE"]</FONT>)"
dat += "<font dize = 9><BR>Cell charge: [D.cell.charge]/[D.cell.maxcharge]."
dat += "<BR>Currently located in: [get_area(D)]."
dat += "<BR><A href='?src=\ref[src];resync=\ref[D]'>Resync</A> | <A href='?src=\ref[src];shutdown=\ref[D]'>Shutdown</A></font>"
dat += "<BR><BR><B>Request drone presence in area:</B> <A href='?src=\ref[src];setarea=1'>[drone_call_area]</A> (<A href='?src=\ref[src];ping=1'>Send ping</A>)"
dat += "<BR><BR><B>Drone fabricator</B>: "
dat += "[dronefab ? "<A href='?src=\ref[src];toggle_fab=1'>[(dronefab.produce_drones && !(dronefab.stat & NOPOWER)) ? "ACTIVE" : "INACTIVE"]</A>" : "<font color='red'><b>FABRICATOR NOT DETECTED.</b></font> (<A href='?src=\ref[src];search_fab=1'>search</a>)"]"
user << browse(dat, "window=computer;size=400x500")
onclose(user, "computer")
return
/obj/machinery/computer/drone_control/Topic(href, href_list)
if(..())
return
if(!allowed(usr))
usr << "\red Access denied."
return
if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon)))
usr.set_machine(src)
if (href_list["setarea"])
//Probably should consider using another list, but this one will do.
var/t_area = input("Select the area to ping.", "Set Target Area", null) as null|anything in TAGGERLOCATIONS
if(!t_area || TAGGERLOCATIONS[t_area])
return
drone_call_area = t_area
usr << "\blue You set the area selector to [drone_call_area]."
else if (href_list["ping"])
usr << "\blue You issue a maintenance request for all active drones, highlighting [drone_call_area]."
for(var/mob/living/silicon/robot/drone/D in world)
if(D.client && D.stat == 0)
D << "-- Maintenance drone presence requested in: [drone_call_area]."
else if (href_list["resync"])
var/mob/living/silicon/robot/drone/D = locate(href_list["resync"])
if(D.stat != 2)
usr << "\red You issue a law synchronization directive for the drone."
D.law_resync()
else if (href_list["shutdown"])
var/mob/living/silicon/robot/drone/D = locate(href_list["shutdown"])
if(D.stat != 2)
usr << "\red You issue a kill command for the unfortunate drone."
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()
else if (href_list["search_fab"])
if(dronefab)
return
for(var/obj/machinery/drone_fabricator/fab in oview(3,src))
if(fab.stat & NOPOWER)
continue
dronefab = fab
usr << "\blue Drone fabricator located."
return
usr << "\red Unable to locate drone fabricator."
else if (href_list["toggle_fab"])
if(!dronefab)
return
if(get_dist(src,dronefab) > 3)
dronefab = null
usr << "\red Unable to locate drone fabricator."
return
dronefab.produce_drones = !dronefab.produce_drones
usr << "\blue You [dronefab.produce_drones ? "enable" : "disable"] drone production in the nearby fabricator."

View File

@@ -0,0 +1,251 @@
//Simple borg hand.
//Limited use.
/obj/item/weapon/gripper
name = "magnetic gripper"
desc = "A simple grasping tool for synthetic assets."
icon = 'icons/obj/device.dmi'
icon_state = "gripper"
//Has a list of items that it can hold.
var/list/can_hold = list(
/obj/item/weapon/cell,
/obj/item/weapon/firealarm_electronics,
/obj/item/weapon/airalarm_electronics,
/obj/item/weapon/airlock_electronics,
/obj/item/weapon/module/power_control,
/obj/item/weapon/stock_parts,
/obj/item/light_fixture_frame,
/obj/item/apc_frame,
/obj/item/alarm_frame,
/obj/item/firealarm_frame,
/obj/item/weapon/table_parts,
/obj/item/weapon/rack_parts,
/obj/item/weapon/camera_assembly,
)
//Item currently being held.
var/obj/item/wrapped = null
/obj/item/weapon/gripper/attack_self(mob/user as mob)
if(wrapped)
wrapped.attack_self(user)
/obj/item/weapon/gripper/verb/drop_item()
set name = "Drop Item"
set desc = "Release an item from your magnetic gripper."
set category = "Drone"
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
src.loc << "\red You drop \the [wrapped]."
wrapped.loc = get_turf(src)
wrapped = null
//update_icon()
/obj/item/weapon/gripper/afterattack(atom/target, mob/user as mob)
if(!target) //Target is invalid.
return
//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.
wrapped.loc = user
//Pass the attack on to the target.
target.attackby(wrapped,user)
if(wrapped && src && wrapped.loc == user)
wrapped.loc = src
//Sanity/item use checks.
if(!wrapped || !user)
return
if(wrapped.loc != src.loc)
wrapped = null
return
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
//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)
user << "You collect \the [I]."
I.loc = src
wrapped = I
return
else
user << "\red Your gripper cannot hold \the [target]."
//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/list/stored_comms = list(
"metal" = 0,
"glass" = 0,
"wood" = 0,
"plastic" = 0
)
/obj/item/weapon/matter_decompiler/afterattack(atom/target, mob/user as mob)
//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/obj/item/W in T)
//Different classes of items give different commodities.
if(istype(W,/obj/item/trash))
stored_comms["metal"]++
stored_comms["plastic"]++
else if(istype(W,/obj/effect/decal/cleanable/blood/gibs/robot))
stored_comms["metal"]++
stored_comms["glass"]++
else if(istype(W,/obj/item/ammo_casing))
stored_comms["metal"]++
else if(istype(W,/obj/item/weapon/shard/shrapnel))
stored_comms["metal"]++
else if(istype(W,/obj/item/weapon/shard))
stored_comms["glass"]++
else if(istype(W,/obj/item/weapon/reagent_containers/food/snacks/grown))
stored_comms["wood"]++
else
continue
del(W)
grabbed_something = 1
if(grabbed_something)
user << "\blue You deploy your decompiler and clear out the contents of \the [T]."
else
user << "\red Nothing on \the [T] is useful to you."
return
//PRETTIER TOOL LIST.
/mob/living/silicon/robot/drone/installed_modules()
if(weapon_lock)
src << "\red Weapon lock active, unable to use modules! Count:[weaponlock_time]"
return
if(!module)
module = new /obj/item/weapon/robot_module/drone(src)
var/dat = "<HEAD><TITLE>Drone modules</TITLE><META HTTP-EQUIV='Refresh' CONTENT='10'></HEAD><BODY>\n"
dat += {"<A HREF='?src=\ref[src];mach_close=robotmod'>Close</A>
<BR>
<BR>
<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/weapon/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&can_close=0")
//Putting the decompiler here to avoid doing list checks every tick.
/mob/living/silicon/robot/drone/use_power()
..()
if(!src.has_power || !decompiler)
return
//The decompiler replenishes drone stores from hoovered-up junk each tick.
for(var/type in decompiler.stored_comms)
if(decompiler.stored_comms[type] > 0)
var/obj/item/stack/sheet/stack
switch(type)
if("metal")
if(!stack_metal)
stack_metal = new(src.module)
stack_metal.amount = 1
stack = stack_metal
if("glass")
if(!stack_glass)
stack_glass = new(src.module)
stack_glass.amount = 1
stack = stack_glass
if("wood")
if(!stack_wood)
stack_wood = new(src.module)
stack_wood.amount = 1
stack = stack_wood
if("plastic")
if(!stack_plastic)
stack_plastic = new(src.module)
stack_plastic.amount = 1
stack = stack_plastic
stack.amount++
decompiler.stored_comms[type]--;

View File

@@ -0,0 +1,129 @@
/obj/machinery/drone_fabricator
name = "drone fabricator"
desc = "A large automated factory for producing maintenance drones."
density = 1
anchored = 1
use_power = 1
idle_power_usage = 20
active_power_usage = 5000
var/drone_progress = 0
var/produce_drones = 0
var/time_last_drone = 500
icon = 'icons/obj/machines/drone_fab.dmi'
icon_state = "drone_fab_idle"
/obj/machinery/drone_fabricator/New()
..()
produce_drones = config.allow_drone_spawn
/obj/machinery/drone_fabricator/power_change()
if (powered())
stat &= ~NOPOWER
else
icon_state = "drone_fab_nopower"
stat |= NOPOWER
/obj/machinery/drone_fabricator/process()
if(stat & NOPOWER || !produce_drones)
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()
..()
if(produce_drones && drone_progress >= 100 && istype(usr,/mob/dead) && config.allow_drone_spawn && count_drones() < config.max_maint_drones)
usr << "<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/count_drones()
var/drones = 0
for(var/mob/living/silicon/robot/drone/D in world)
if(D.key && D.client)
drones++
return drones
/obj/machinery/drone_fabricator/proc/create_drone(var/client/player)
if(stat & NOPOWER)
return
if(!produce_drones || !config.allow_drone_spawn || count_drones() >= config.max_maint_drones)
return
if(!player || !istype(player.mob,/mob/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)
time_last_drone = world.time
var/mob/living/silicon/robot/drone/new_drone = new(get_turf(src))
new_drone.transfer_personality(player)
drone_progress = 0
/mob/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(!(config.allow_drone_spawn))
src << "\red That verb is not currently permitted."
return
if (!src.stat)
return
if (usr != src)
return 0 //something is terribly wrong
var/deathtime = world.time - src.timeofdeath
if(istype(src,/mob/dead/observer))
var/mob/dead/observer/G = src
if(G.has_enabled_antagHUD == 1 && config.antag_hud_restricted)
usr << "\blue <B>Upon using the antagHUD you forfeighted the ability to join the round.</B>"
return
var/deathtimeminutes = round(deathtime / 600)
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 * 600) / 10,1)
if (deathtime < 6000)
usr << "You have been dead for[pluralcheck] [deathtimeseconds] seconds."
usr << "You must wait 10 minutes to respawn as a drone!"
return
for(var/obj/machinery/drone_fabricator/DF in world)
if(DF.stat & NOPOWER || !DF.produce_drones)
continue
if(DF.count_drones() >= config.max_maint_drones)
src << "\red There are too many active drones in the world for you to spawn."
return
DF.create_drone(src.client)
return
src << "\red There are no available drone spawn points, sorry."

View File

@@ -35,7 +35,7 @@
if(DEAD) msg += "<span class='deadsay'>It looks completely unsalvageable.</span>\n"
msg += "*---------*</span>"
if(print_flavor_text()) msg += "[print_flavor_text()]\n"
if(print_flavor_text()) msg += "\n[print_flavor_text()]\n"
if (pose)
if( findtext(pose,".",lentext(pose)) == 0 && findtext(pose,"!",lentext(pose)) == 0 && findtext(pose,"?",lentext(pose)) == 0 )

View File

@@ -175,21 +175,38 @@
if (src.healths)
if (src.stat != 2)
switch(health)
if(200 to INFINITY)
src.healths.icon_state = "health0"
if(150 to 200)
src.healths.icon_state = "health1"
if(100 to 150)
src.healths.icon_state = "health2"
if(50 to 100)
src.healths.icon_state = "health3"
if(0 to 50)
src.healths.icon_state = "health4"
if(config.health_threshold_dead to 0)
src.healths.icon_state = "health5"
else
src.healths.icon_state = "health6"
if(istype(src,/mob/living/silicon/robot/drone))
switch(health)
if(35 to INFINITY)
src.healths.icon_state = "health0"
if(25 to 34)
src.healths.icon_state = "health1"
if(15 to 24)
src.healths.icon_state = "health2"
if(5 to 14)
src.healths.icon_state = "health3"
if(0 to 4)
src.healths.icon_state = "health4"
if(-35 to 0)
src.healths.icon_state = "health5"
else
src.healths.icon_state = "health6"
else
switch(health)
if(200 to INFINITY)
src.healths.icon_state = "health0"
if(150 to 200)
src.healths.icon_state = "health1"
if(100 to 150)
src.healths.icon_state = "health2"
if(50 to 100)
src.healths.icon_state = "health3"
if(0 to 50)
src.healths.icon_state = "health4"
if(config.health_threshold_dead to 0)
src.healths.icon_state = "health5"
else
src.healths.icon_state = "health6"
else
src.healths.icon_state = "health7"

View File

@@ -90,6 +90,12 @@
hands.icon_state = "standard"
icon_state = "secborg"
modtype = "Security"
else if(istype(src,/mob/living/silicon/robot/drone))
laws = new /datum/ai_laws/drone()
connected_ai = select_active_ai_with_fewest_borgs()
if(connected_ai)
connected_ai.connected_robots += src
lawsync()
else
laws = new /datum/ai_laws/nanotrasen()
connected_ai = select_active_ai_with_fewest_borgs()
@@ -138,9 +144,10 @@
hud_list[SPECIALROLE_HUD] = image('icons/mob/hud.dmi', src, "hudblank")
playsound(loc, 'sound/voice/liveagain.ogg', 75, 1)
if(istype(src,/mob/living/silicon/robot/drone))
playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0)
else
playsound(loc, 'sound/voice/liveagain.ogg', 75, 1)
// setup the PDA and its name
/mob/living/silicon/robot/proc/setup_PDA()

View File

@@ -266,3 +266,73 @@
src.modules += new /obj/item/weapon/wrench(src) //Is a combat android really going to be stopped by a chair?
src.emag = new /obj/item/weapon/gun/energy/lasercannon/cyborg(src)
return
/obj/item/weapon/robot_module/drone
name = "drone module"
New()
//TODO: Replace with shittier flashlight and work out why we can't remove the flash. ~Z
..()
src.modules += new /obj/item/weapon/weldingtool(src)
src.modules += new /obj/item/weapon/screwdriver(src)
src.modules += new /obj/item/weapon/wrench(src)
src.modules += new /obj/item/weapon/crowbar(src)
src.modules += new /obj/item/weapon/wirecutters(src)
src.modules += new /obj/item/device/multitool(src)
src.modules += new /obj/item/device/lightreplacer(src)
src.modules += new /obj/item/weapon/reagent_containers/spray/cleaner(src)
src.modules += new /obj/item/weapon/gripper(src)
src.modules += new /obj/item/weapon/matter_decompiler(src)
src.emag = new /obj/item/weapon/card/emag(src)
src.emag.name = "Cryptographic Sequencer"
var/list/stacktypes = list(
/obj/item/stack/rods = 10,
/obj/item/stack/tile/plasteel = 10,
/obj/item/stack/sheet/metal/cyborg = 10,
/obj/item/stack/sheet/wood/cyborg = 1,
/obj/item/weapon/cable_coil = 30,
/obj/item/stack/sheet/glass/cyborg = 10,
/obj/item/stack/sheet/mineral/plastic/cyborg = 1
)
for(var/T in stacktypes)
var/obj/item/stack/sheet/W = new T(src)
W.amount = stacktypes[T]
src.modules += W
return
/obj/item/weapon/robot_module/drone/respawn_consumable(var/mob/living/silicon/robot/R)
var/obj/item/weapon/reagent_containers/spray/cleaner/C = locate() in src.modules
C.reagents.add_reagent("cleaner", 10)
var/list/stacks = list (
/obj/item/stack/sheet/metal,
/obj/item/weapon/cable_coil,
/obj/item/stack/sheet/glass/cyborg,
/obj/item/stack/rods,
/obj/item/stack/tile/plasteel
)
for(var/T in stacks)
var/O = locate(T) in src.modules
var/obj/item/stack/sheet/S = O
if(!S)
src.modules -= null
S = new T(src)
src.modules += S
S.amount = 0
if(istype(S) && S.amount < 15)
S.amount++
var/obj/item/device/lightreplacer/LR = locate() in src.modules
LR.Charge(R)
return

View File

@@ -168,7 +168,7 @@
newlight = new /obj/machinery/light/small/built(src.loc)
newlight.dir = src.dir
src.transfer_fingerprints_to(newlight)
newlight.fingerprints |= src.fingerprints
del(src)
return
..()

View File

@@ -401,7 +401,11 @@
var/wrapcheck = 0
var/obj/structure/disposalholder/H = new() // virtual holder object which actually
// travels through the pipes.
// travels through the pipes.
//Hacky test to get drones to mail themselves through disposals.
for(var/mob/living/silicon/robot/drone/D in src)
wrapcheck = 1
for(var/obj/item/smallDelivery/O in src)
wrapcheck = 1
@@ -449,9 +453,10 @@
AM.loc = src.loc
AM.pipe_eject(0)
spawn(1)
if(AM)
AM.throw_at(target, 5, 1)
if(!istype(AM,/mob/living/silicon/robot/drone)) //Poor drones kept smashing windows and taking system damage being fired out of disposals. ~Z
spawn(1)
if(AM)
AM.throw_at(target, 5, 1)
H.vent_gas(loc)
del(H)
@@ -496,7 +501,7 @@
//Check for any living mobs trigger hasmob.
//hasmob effects whether the package goes to cargo or its tagged destination.
for(var/mob/living/M in D)
if(M && M.stat != 2)
if(M && M.stat != 2 && !istype(M,/mob/living/silicon/robot/drone))
hasmob = 1
//Checks 1 contents level deep. This means that players can be sent through disposals...
@@ -504,7 +509,7 @@
for(var/obj/O in D)
if(O.contents)
for(var/mob/living/M in O.contents)
if(M && M.stat != 2)
if(M && M.stat != 2 && !istype(M,/mob/living/silicon/robot/drone))
hasmob = 1
// now everything inside the disposal gets put into the holder
@@ -521,6 +526,10 @@
if(istype(AM, /obj/item/smallDelivery) && !hasmob)
var/obj/item/smallDelivery/T = AM
src.destinationTag = T.sortTag
//Drones can mail themselves through maint.
if(istype(AM, /mob/living/silicon/robot/drone))
var/mob/living/silicon/robot/drone/drone = AM
src.destinationTag = drone.mail_destination
// start the movement process
@@ -544,7 +553,8 @@
while(active)
if(hasmob && prob(3))
for(var/mob/living/H in src)
H.take_overall_damage(20, 0, "Blunt Trauma")//horribly maim any living creature jumping down disposals. c'est la vie
if(!istype(H,/mob/living/silicon/robot/drone)) //Drones use the mailing code to move through the disposal system,
H.take_overall_damage(20, 0, "Blunt Trauma")//horribly maim any living creature jumping down disposals. c'est la vie
if(has_fat_guy && prob(2)) // chance of becoming stuck per segment if contains a fat guy
active = 0
@@ -1372,8 +1382,9 @@
for(var/atom/movable/AM in H)
AM.loc = src.loc
AM.pipe_eject(dir)
spawn(5)
AM.throw_at(target, 3, 1)
if(!istype(AM,/mob/living/silicon/robot/drone)) //Drones keep smashing windows from being fired out of chutes. Bad for the station. ~Z
spawn(5)
AM.throw_at(target, 3, 1)
H.vent_gas(src.loc)
del(H)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB