mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-17 18:13:34 +01:00
Adds drones, drone fabrication, commit options. This is the squashed version of the original 22 commit pull, so I'm summarizing.
Conflicts: baystation12.dme code/controllers/configuration.dm code/game/objects/items/weapons/AI_modules.dm code/modules/mob/living/living.dm code/modules/mob/living/silicon/robot/examine.dm code/modules/mob/living/silicon/robot/life.dm code/modules/mob/living/silicon/robot/robot.dm code/modules/mob/living/silicon/robot/robot_modules.dm code/modules/recycling/disposal.dm icons/mob/robots.dmi icons/obj/device.dmi
This commit is contained in:
@@ -458,7 +458,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.
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
..()
|
||||
@@ -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."
|
||||
@@ -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/robot_debris))
|
||||
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/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&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]--;
|
||||
@@ -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."
|
||||
@@ -32,6 +32,9 @@
|
||||
else
|
||||
msg += "Its cover is closed.\n"
|
||||
|
||||
if(!has_power)
|
||||
msg += "<span class='warning'>It appears to be running on backup power.</span>\n"
|
||||
|
||||
switch(src.stat)
|
||||
if(CONSCIOUS)
|
||||
if(!src.client) msg += "It appears to be in stand-by mode.\n" //afk
|
||||
@@ -39,7 +42,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 )
|
||||
|
||||
@@ -125,6 +125,10 @@
|
||||
src.druggy--
|
||||
src.druggy = max(0, src.druggy)
|
||||
|
||||
//update the state of modules and components here
|
||||
if (src.stat != 0)
|
||||
uneq_all()
|
||||
|
||||
if(!is_component_functioning("radio"))
|
||||
radio.on = 0
|
||||
else
|
||||
@@ -135,6 +139,9 @@
|
||||
else
|
||||
src.blinded = 1
|
||||
|
||||
if(!is_component_functioning("actuator"))
|
||||
src.Paralyse(3)
|
||||
|
||||
|
||||
return 1
|
||||
|
||||
@@ -175,21 +182,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"
|
||||
|
||||
@@ -326,4 +350,4 @@
|
||||
if(!on_fire) //Silicons don't gain stacks from hotspots, but hotspots can ignite them
|
||||
IgniteMob()
|
||||
|
||||
//Robots on fire
|
||||
//Robots on fire
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
var/datum/effect/effect/system/ion_trail_follow/ion_trail = null
|
||||
var/datum/effect/effect/system/spark_spread/spark_system//So they can initialize sparks whenever/N
|
||||
var/jeton = 0
|
||||
|
||||
var/has_power = 1
|
||||
var/killswitch = 0
|
||||
var/killswitch_time = 60
|
||||
var/weapon_lock = 0
|
||||
@@ -100,6 +100,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
|
||||
if(mmi.alien || alien)
|
||||
laws = new /datum/ai_laws/alienmov()
|
||||
@@ -152,22 +158,10 @@
|
||||
hud_list[IMPTRACK_HUD] = image('icons/mob/hud.dmi', src, "hudblank")
|
||||
hud_list[SPECIALROLE_HUD] = image('icons/mob/hud.dmi', src, "hudblank")
|
||||
|
||||
|
||||
|
||||
|
||||
hud_list[HEALTH_HUD] = image('icons/mob/hud.dmi', src, "hudblank")
|
||||
hud_list[STATUS_HUD] = image('icons/mob/hud.dmi', src, "hudhealth100")
|
||||
hud_list[ID_HUD] = image('icons/mob/hud.dmi', src, "hudblank")
|
||||
hud_list[WANTED_HUD] = image('icons/mob/hud.dmi', src, "hudblank")
|
||||
hud_list[IMPLOYAL_HUD] = image('icons/mob/hud.dmi', src, "hudblank")
|
||||
hud_list[IMPCHEM_HUD] = image('icons/mob/hud.dmi', src, "hudblank")
|
||||
hud_list[IMPTRACK_HUD] = image('icons/mob/hud.dmi', src, "hudblank")
|
||||
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()
|
||||
|
||||
@@ -249,3 +249,72 @@
|
||||
src.emag = new /obj/item/weapon/reagent_containers/spray/alien/acid(src)
|
||||
src.emag.reagents.add_reagent("pacid", 125)
|
||||
src.emag.reagents.add_reagent("sacid", 125)
|
||||
|
||||
/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/stack/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/stack/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
|
||||
|
||||
Reference in New Issue
Block a user