diff --git a/code/__HELPERS/atom_pool.dm b/code/__HELPERS/atom_pool.dm index f3c71bcfef5..77a7caf5e40 100644 --- a/code/__HELPERS/atom_pool.dm +++ b/code/__HELPERS/atom_pool.dm @@ -34,13 +34,10 @@ var/global/list/GlobalPool = list() if(!AM) if(ispath(get_type)) if(islist(second_arg)) - AM = new get_type (arglist(second_arg)) + return new get_type (arglist(second_arg)) else - AM = new get_type (second_arg) - else - if(AM) - return AM - + return new get_type (second_arg) + return AM /proc/GetFromPool(var/get_type,var/second_arg) diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm index 64e013a4fd5..a289fff3f1f 100644 --- a/code/__HELPERS/lists.dm +++ b/code/__HELPERS/lists.dm @@ -30,6 +30,13 @@ return "[output][and_text][input[index]]" + +/proc/ConvertReqString2List(var/list/source_list) + var/list/temp_list = params2list(source_list) + for(var/O in temp_list) + temp_list[O] = text2num(temp_list[O]) + return temp_list + //Returns list element or null. Should prevent "index out of bounds" error. proc/listgetindex(var/list/list,index) if(istype(list) && list.len) diff --git a/code/datums/ai_law_sets.dm b/code/datums/ai_law_sets.dm index 278fd4a0df7..74b18fa2e75 100644 --- a/code/datums/ai_law_sets.dm +++ b/code/datums/ai_law_sets.dm @@ -99,6 +99,16 @@ add_inherent_law("Interfere with no being that is not a fellow drone.") ..() +/datum/ai_laws/construction_drone + name = "Construction Protocols" + law_header = "Construction Protocols" + selectable = 1 + +/datum/ai_laws/construction_drone/New() + add_inherent_law("Repair, refit and upgrade your assigned vessel.") + add_inherent_law("Prevent unplanned damage to your assigned vessel wherever possible.") + ..() + /******************** T.Y.R.A.N.T. ********************/ /datum/ai_laws/tyrant name = "T.Y.R.A.N.T." diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm index e59ad21e84f..48df75f6bcc 100755 --- a/code/game/area/Space Station 13 areas.dm +++ b/code/game/area/Space Station 13 areas.dm @@ -873,27 +873,27 @@ area/space/atmosalert() music = null /area/crew_quarters/captain - name = "\improper Captain's Office" + name = "\improper Command - Captain's Office" icon_state = "captain" /area/crew_quarters/heads/hop - name = "\improper Head of Personnel's Office" + name = "\improper Command - HoP's Office" icon_state = "head_quarters" /area/crew_quarters/heads/hor - name = "\improper Research Director's Office" + name = "\improper Research - RD's Office" icon_state = "head_quarters" /area/crew_quarters/heads/chief - name = "\improper Chief Engineer's Office" + name = "\improper Engineering - CE's Office" icon_state = "head_quarters" /area/crew_quarters/heads/hos - name = "\improper Head of Security's Office" + name = "\improper Security - HoS' Office" icon_state = "head_quarters" /area/crew_quarters/heads/cmo - name = "\improper Chief Medical Officer's Office" + name = "\improper Medbay - CMO's Office" icon_state = "head_quarters" /area/crew_quarters/courtroom @@ -1085,7 +1085,7 @@ area/space/atmosalert() icon_state = "atmos_storage" /area/engineering/drone_fabrication - name = "\improper Drone Fabrication" + name = "\improper Engineering Drone Fabrication" icon_state = "drone_fab" /area/engineering/engine_smes @@ -1171,23 +1171,23 @@ area/space/atmosalert() icon_state = "panelsP" /area/maintenance/auxsolarport - name = "Fore Port Solar Maintenance" + name = "Solar Maintenance - Fore Port" icon_state = "SolarcontrolP" /area/maintenance/starboardsolar - name = "Aft Starboard Solar Maintenance" + name = "Solar Maintenance - Aft Starboard" icon_state = "SolarcontrolS" /area/maintenance/portsolar - name = "Aft Port Solar Maintenance" + name = "Solar Maintenance - Aft Port" icon_state = "SolarcontrolP" /area/maintenance/auxsolarstarboard - name = "Fore Starboard Solar Maintenance" + name = "Solar Maintenance - Fore Starboard" icon_state = "SolarcontrolS" /area/maintenance/foresolar - name = "Fore Solar Maintenance" + name = "Solar Maintenance - Fore" icon_state = "SolarcontrolA" /area/assembly/chargebay diff --git a/code/game/machinery/OpTable.dm b/code/game/machinery/OpTable.dm index b01b0bbda6f..6e1ecdf4cab 100644 --- a/code/game/machinery/OpTable.dm +++ b/code/game/machinery/OpTable.dm @@ -105,6 +105,16 @@ else icon_state = "table2-idle" +/obj/machinery/optable/MouseDrop_T(mob/target, mob/user) + + var/mob/living/M = user + if(user.stat || user.restrained() || !check_table(user) || !iscarbon(target)) + return + if(istype(M)) + take_victim(target,user) + else + return ..() + /obj/machinery/optable/verb/climb_on() set name = "Climb On Table" set category = "Object" diff --git a/code/game/machinery/camera/presets.dm b/code/game/machinery/camera/presets.dm index 4fb3514da6d..e7e70486fb3 100644 --- a/code/game/machinery/camera/presets.dm +++ b/code/game/machinery/camera/presets.dm @@ -1,14 +1,49 @@ // PRESETS -var/global/list/station_networks = list("SS13","Civilian West","Engineering Outpost","MINE","Research Outpost","Prison","Security") +#define NETWORK_CIVILIAN_WEST "Civilian West" +#define NETWORK_ENGINE "Engine" +#define NETWORK_ENGINEERING "Engineering" +#define NETWORK_ENGINEERING_OUTPOST "Engineering Outpost" +#define NETWORK_MINE "MINE" +#define NETWORK_RESEARCH_OUTPOST "Research Outpost" +#define NETWORK_PRISON "Prison" +#define NETWORK_SECURITY "Security" + +var/global/list/station_networks = list( + "SS13", + NETWORK_CIVILIAN_WEST, + NETWORK_ENGINE, + NETWORK_ENGINEERING, + NETWORK_ENGINEERING_OUTPOST, + NETWORK_MINE, + NETWORK_RESEARCH_OUTPOST, + NETWORK_PRISON, + NETWORK_SECURITY + ) +var/global/list/engineering_networks = list( + NETWORK_ENGINE, + NETWORK_ENGINEERING, + NETWORK_ENGINEERING_OUTPOST, + "Atmosphere Alarms", + "Fire Alarms", + "Power Alarms") /obj/machinery/camera/network/civilian_west - network = list("Civilian West") + network = list(NETWORK_CIVILIAN_WEST) + +/obj/machinery/camera/network/engine + network = list(NETWORK_ENGINE) + +/obj/machinery/camera/network/engineering + network = list(NETWORK_ENGINEERING) + +/obj/machinery/camera/network/engineering_outpost + network = list(NETWORK_ENGINEERING_OUTPOST) /obj/machinery/camera/network/prison - network = list("Prison") + network = list(NETWORK_PRISON) /obj/machinery/camera/network/security - network = list("Security") + network = list(NETWORK_SECURITY) // EMP @@ -42,19 +77,25 @@ var/global/list/station_networks = list("SS13","Civilian West","Engineering Outp // AUTONAME /obj/machinery/camera/autoname/civilian_west - network = list("Civilian West") + network = list(NETWORK_CIVILIAN_WEST) + +/obj/machinery/camera/autoname/engine + network = list(NETWORK_ENGINE) + +/obj/machinery/camera/autoname/engineering + network = list(NETWORK_ENGINEERING) /obj/machinery/camera/autoname/engineering_outpost - network = list("Engineering Outpost") + network = list(NETWORK_ENGINEERING_OUTPOST) /obj/machinery/camera/autoname/mining_outpost - network = list("MINE") + network = list(NETWORK_MINE) /obj/machinery/camera/autoname/research_outpost - network = list("Research Outpost") + network = list(NETWORK_RESEARCH_OUTPOST) /obj/machinery/camera/autoname/security - network = list("Security") + network = list(NETWORK_SECURITY) /obj/machinery/camera/autoname var/number = 0 //camera number in area @@ -73,6 +114,7 @@ var/global/list/station_networks = list("SS13","Civilian West","Engineering Outp if(C.number) number = max(number, C.number+1) c_tag = "[A.name] #[number]" + invalidateCameraCache() // CHECKS @@ -113,3 +155,12 @@ var/global/list/station_networks = list("SS13","Civilian West","Engineering Outp if (isMotion()) mult++ active_power_usage = mult*initial(active_power_usage) + +#undef NETWORK_CIVILIAN_WEST +#undef NETWORK_ENGINE +#undef NETWORK_ENGINEERING +#undef NETWORK_ENGINEERING_OUTPOST +#undef NETWORK_MINE +#undef NETWORK_RESEARCH_OUTPOST +#undef NETWORK_PRISON +#undef NETWORK_SECURITY diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm index da12c061bee..f71f181ed31 100644 --- a/code/game/machinery/computer/camera.dm +++ b/code/game/machinery/computer/camera.dm @@ -240,9 +240,13 @@ name = "engineering camera monitor" desc = "Used to monitor fires and breaches." icon_state = "engineeringcameras" - network = list("Engineering","Engineering Outpost","Power Alarms","Atmosphere Alarms","Fire Alarms") circuit = /obj/item/weapon/circuitboard/security/engineering +/obj/machinery/computer/security/engineering/New() + if(!network) + network = engineering_networks + ..() + /obj/machinery/computer/security/nuclear name = "head mounted camera monitor" desc = "Used to access the built-in cameras in helmets." diff --git a/code/game/machinery/computer/station_alert.dm b/code/game/machinery/computer/station_alert.dm index ab136ca3714..6d5209ce585 100644 --- a/code/game/machinery/computer/station_alert.dm +++ b/code/game/machinery/computer/station_alert.dm @@ -4,13 +4,17 @@ desc = "Used to access the station's automated alert system." icon_state = "alert:0" circuit = "/obj/item/weapon/circuitboard/stationalert" - var/alarms = list("Fire"=list(), "Atmosphere"=list(), "Power"=list()) - var/obj/nano_module/alarm_monitor/engineering/alarm_monitor + var/obj/nano_module/alarm_monitor/alarm_monitor + var/monitor_type = /obj/nano_module/alarm_monitor/engineering + +/obj/machinery/computer/station_alert/security + name = "Security Alert Console" + monitor_type = /obj/nano_module/alarm_monitor/security /obj/machinery/computer/station_alert/New() - alarm_monitor = new(src) - alarm_monitor.register(src, /obj/machinery/computer/station_alert/update_icon) ..() + alarm_monitor = new monitor_type(src) + alarm_monitor.register(src, /obj/machinery/computer/station_alert/update_icon) /obj/machinery/computer/station_alert/Del() alarm_monitor.unregister(src) diff --git a/code/game/machinery/kitchen/microwave.dm b/code/game/machinery/kitchen/microwave.dm index fbdcfd2760c..fe75dff633d 100644 --- a/code/game/machinery/kitchen/microwave.dm +++ b/code/game/machinery/kitchen/microwave.dm @@ -135,11 +135,12 @@ return 1 else user << "\red You have no idea what you can cook with this [O]." - return 1 + ..() src.updateUsrDialog() /obj/machinery/microwave/attack_ai(mob/user as mob) - return 0 + if(istype(user, /mob/living/silicon/robot) && Adjacent(user)) + attack_hand(user) /obj/machinery/microwave/attack_hand(mob/user as mob) user.set_machine(src) diff --git a/code/game/machinery/kitchen/smartfridge.dm b/code/game/machinery/kitchen/smartfridge.dm index 1b1bb9bfb5f..f4e910a47dd 100644 --- a/code/game/machinery/kitchen/smartfridge.dm +++ b/code/game/machinery/kitchen/smartfridge.dm @@ -244,7 +244,7 @@ ..() /obj/machinery/smartfridge/attack_ai(mob/user as mob) - return 0 + attack_hand(user) /obj/machinery/smartfridge/attack_hand(mob/user as mob) if(stat & (NOPOWER|BROKEN)) diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index 88819e492f7..794fb0a887a 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -479,17 +479,6 @@ if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf)))) if ((href_list["vend"]) && (src.vend_ready) && (!currently_vending)) - - if(istype(usr,/mob/living/silicon)) - if(istype(usr,/mob/living/silicon/robot)) - var/mob/living/silicon/robot/R = usr - if(!(R.module && istype(R.module,/obj/item/weapon/robot_module/butler) )) - usr << "\red The vending machine refuses to interface with you, as you are not in its target demographic!" - return - else - usr << "\red The vending machine refuses to interface with you, as you are not in its target demographic!" - return - if((!allowed(usr)) && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH usr << "Access denied." //Unless emagged of course flick(icon_deny,src) @@ -504,6 +493,9 @@ if(R.price <= 0) src.vend(R, usr) + else if(istype(usr,/mob/living/silicon)) //If the item is not free, provide feedback if a synth is trying to buy something. + usr << "Artificial unit recognized. Artificial units cannot complete this transaction. Purchase canceled." + return else src.currently_vending = R if(!vendor_account || vendor_account.suspended) diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm index 9c262243c68..da508a8a31f 100644 --- a/code/game/objects/items/robot/robot_parts.dm +++ b/code/game/objects/items/robot/robot_parts.dm @@ -291,21 +291,14 @@ ..() if(istype(W, /obj/item/device/flash)) if(istype(user,/mob/living/silicon/robot)) - user << "\red How do you propose to do that?" - return - else if(src.flash1 && src.flash2) - user << "\blue You have already inserted the eyes!" - return - else if(src.flash1) - user.drop_item() - W.loc = src - src.flash2 = W - user << "\blue You insert the flash into the eye socket!" + var/current_module = user.get_active_hand() + if(current_module == W) + user << "How do you propose to do that?" + return + else + add_flashes(W,user) else - user.drop_item() - W.loc = src - src.flash1 = W - user << "\blue You insert the flash into the eye socket!" + add_flashes(W,user) else if(istype(W, /obj/item/weapon/stock_parts/manipulator)) user << "\blue You install some manipulators and modify the head, creating a functional spider-bot!" new /mob/living/simple_animal/spiderbot(get_turf(loc)) @@ -315,6 +308,22 @@ return return +/obj/item/robot_parts/head/proc/add_flashes(obj/item/W as obj, mob/user as mob) //Made into a seperate proc to avoid copypasta + if(src.flash1 && src.flash2) + user << "You have already inserted the eyes!" + return + else if(src.flash1) + user.drop_item() + W.loc = src + src.flash2 = W + user << "You insert the flash into the eye socket!" + else + user.drop_item() + W.loc = src + src.flash1 = W + user << "You insert the flash into the eye socket!" + + /obj/item/robot_parts/attackby(obj/item/W as obj, mob/user as mob) if(istype(W,/obj/item/weapon/card/emag)) if(sabotaged) diff --git a/code/game/objects/items/stacks/matter_synth.dm b/code/game/objects/items/stacks/matter_synth.dm index 0842f70d66a..3483dfbc61c 100644 --- a/code/game/objects/items/stacks/matter_synth.dm +++ b/code/game/objects/items/stacks/matter_synth.dm @@ -28,6 +28,9 @@ /datum/matter_synth/medicine name = "Medicine Synthesizer" +/datum/matter_synth/nanite + name = "Nanite Synthesizer" + /datum/matter_synth/metal name = "Metal Synthesizer" diff --git a/code/game/objects/items/weapons/RSF.dm b/code/game/objects/items/weapons/RSF.dm index 596675a094f..d3dc598cc3d 100644 --- a/code/game/objects/items/weapons/RSF.dm +++ b/code/game/objects/items/weapons/RSF.dm @@ -54,14 +54,9 @@ RSF user << "Changed dispensing mode to 'Dice Pack'" return if (mode == 5) - mode = 6 + mode = 1 user << "Changed dispensing mode to 'Cigarette'" return - if (mode == 6) - mode = 1 - user << "Changed dispensing mode to 'Dosh'" - return - // Change mode /obj/item/weapon/rsf/afterattack(atom/A, mob/user as mob, proximity) @@ -84,8 +79,8 @@ RSF switch(mode) if(1) - product = new /obj/item/weapon/spacecash/c10() - used_energy = 200 + product = new /obj/item/clothing/mask/smokable/cigarette() + used_energy = 10 if(2) product = new /obj/item/weapon/reagent_containers/food/drinks/drinkingglass() used_energy = 50 @@ -98,9 +93,6 @@ RSF if(5) product = new /obj/item/weapon/storage/pill_bottle/dice() used_energy = 200 - if(6) - product = new /obj/item/clothing/mask/smokable/cigarette() - used_energy = 10 user << "Dispensing [product ? product : "product"]..." product.loc = get_turf(A) diff --git a/code/game/objects/items/weapons/circuitboards/computer/camera_monitor.dm b/code/game/objects/items/weapons/circuitboards/computer/camera_monitor.dm index e45f51a088d..b7da10cc22e 100644 --- a/code/game/objects/items/weapons/circuitboards/computer/camera_monitor.dm +++ b/code/game/objects/items/weapons/circuitboards/computer/camera_monitor.dm @@ -5,16 +5,23 @@ /obj/item/weapon/circuitboard/security name = T_BOARD("security camera monitor") build_path = /obj/machinery/computer/security - var/network = list("SS13") req_access = list(access_security) + var/list/network var/locked = 1 var/emagged = 0 + +/obj/item/weapon/circuitboard/security/New() + ..() + network = station_networks /obj/item/weapon/circuitboard/security/engineering name = T_BOARD("engineering camera monitor") build_path = /obj/machinery/computer/security/engineering - network = list("Engineering","Power Alarms","Atmosphere Alarms","Fire Alarms") req_access = list() + +/obj/item/weapon/circuitboard/security/engineering/New() + ..() + network = engineering_networks /obj/item/weapon/circuitboard/security/mining name = T_BOARD("mining camera monitor") diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 40163e7c780..08abff9c2bf 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -249,6 +249,10 @@ src.add_fingerprint(user) return +/obj/structure/closet/attack_ai(mob/user) + if(istype(user, /mob/living/silicon/robot) && Adjacent(user)) // Robots can open/close it, but not the AI. + attack_hand(user) + /obj/structure/closet/relaymove(mob/user as mob) if(user.stat || !isturf(src.loc)) return diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index dc18b06e6c0..f0a5b9003a1 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -80,6 +80,7 @@ var/mob/living/carbon/human/vox/vox = new(get_turf(src),"Vox") vox.gender = user.gender raiders.equip(vox) + new /obj/item/organ/stack/vox(vox) if(user.mind) user.mind.transfer_to(vox) spawn(1) diff --git a/code/global.dm b/code/global.dm index 3ed04b52f38..f613b53b12b 100644 --- a/code/global.dm +++ b/code/global.dm @@ -244,7 +244,8 @@ var/list/cheartstopper = list("potassium_chloride") // Thi // Used by robots and robot preferences. var/list/robot_module_types = list( "Standard", "Engineering", "Construction", "Surgeon", "Crisis", - "Miner", "Janitor", "Service", "Clerical", "Security" + "Miner", "Janitor", "Service", "Clerical", "Security", + "Research" ) // Some scary sounds. @@ -277,4 +278,4 @@ var/global/obj/item/device/radio/intercom/global_announcer = new(null) var/list/station_departments = list("Command", "Medical", "Engineering", "Science", "Security", "Cargo", "Civilian") var/global/const/TICKS_IN_DAY = 864000 -var/global/const/TICKS_IN_SECOND = 10 \ No newline at end of file +var/global/const/TICKS_IN_SECOND = 10 diff --git a/code/modules/mob/living/carbon/human/species/outsider/vox.dm b/code/modules/mob/living/carbon/human/species/outsider/vox.dm index c037d81fb73..62ba2e49e86 100644 --- a/code/modules/mob/living/carbon/human/species/outsider/vox.dm +++ b/code/modules/mob/living/carbon/human/species/outsider/vox.dm @@ -30,7 +30,7 @@ poison_type = "oxygen" siemens_coefficient = 0.2 - flags = IS_WHITELISTED | NO_SCAN | HAS_EYE_COLOR + flags = CAN_JOIN | IS_WHITELISTED | NO_SCAN | HAS_EYE_COLOR blood_color = "#2299FC" flesh_color = "#808D11" @@ -47,8 +47,7 @@ "liver" = /obj/item/organ/liver, "kidneys" = /obj/item/organ/kidneys, "brain" = /obj/item/organ/brain, - "eyes" = /obj/item/organ/eyes, - "stack" = /obj/item/organ/stack/vox + "eyes" = /obj/item/organ/eyes ) /datum/species/vox/get_random_name(var/gender) diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm index 68396cba33e..8fd20e1368d 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone.dm @@ -14,7 +14,7 @@ lawupdate = 0 density = 1 req_access = list(access_engine, access_robotics) - integrated_light_power = 2 + integrated_light_power = 3 local_transmit = 1 mob_bump_flag = SIMPLE_ANIMAL @@ -24,6 +24,11 @@ //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/can_pull_size = 2 + var/can_pull_mobs holder_type = /obj/item/weapon/holder/drone @@ -36,9 +41,6 @@ add_language("Robot Talk", 0) add_language("Drone Talk", 1) - if(camera && "Robots" in camera.network) - camera.add_network("Engineering") - //They are unable to be upgraded, so let's give them a bit of a better battery. cell.maxcharge = 10000 cell.charge = 10000 @@ -52,16 +54,18 @@ C.max_damage = 10 verbs -= /mob/living/silicon/robot/verb/Namepick - module = new /obj/item/weapon/robot_module/drone(src) - - //Some tidying-up. - flavor_text = "It's a tiny little repair drone. The casing is stamped with an NT logo and the subscript: 'NanoTrasen Recursive Repair Systems: Fixing Tomorrow's Problem, Today!'" updateicon() /mob/living/silicon/robot/drone/init() - laws = new /datum/ai_laws/drone() + if(!laws) laws = new law_type + if(!module) module = new module_type(src) + aiCamera = new/obj/item/device/camera/siliconcam/drone_camera(src) + flavor_text = "It's a tiny little repair drone. The casing is stamped with an NT logo and the subscript: 'NanoTrasen Recursive Repair Systems: Fixing Tomorrow's Problem, Today!'" playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0) + spawn(1) + if(camera && ("Robots" in camera.network)) + camera.add_network("Engineering") //Redefining some robot procs... /mob/living/silicon/robot/drone/SetName(pickedName as text) @@ -91,26 +95,26 @@ /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]." + user << "\The [src] is 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." + user << "\The [src] 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." + user << "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." + src << "\The [user] attempts to load subversive software into you, but your hacked subroutines ignore the attempt." + user << "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." + user << "You swipe the sequencer across [src]'s interface and watch its eyes flicker." + src << "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-- @@ -130,7 +134,7 @@ src << "Obey these laws:" laws.show_laws(src) - src << "\red \b ALERT: [user.real_name] is your new master. Obey your new laws and his commands." + src << "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)) @@ -138,14 +142,14 @@ if(stat == 2) 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." + user << "The interface is fried, and a distressing burned smell wafts from the robot's interior. You're not rebooting this one." return if(!allowed(usr)) - user << "\red Access denied." + user << "Access denied." return - user.visible_message("\red \the [user] swipes \his ID card through \the [src], attempting to reboot it.", "\red You swipe your ID card through \the [src], attempting to reboot it.") + user.visible_message("\The [user] swipes \his ID card through \the [src], attempting to reboot it.", ">You swipe your ID card through \the [src], attempting to reboot it.") var/drones = 0 for(var/mob/living/silicon/robot/drone/D in world) if(D.key && D.client) @@ -155,7 +159,7 @@ return else - user.visible_message("\red \the [user] swipes \his ID card through \the [src], attempting to shut it down.", "\red You swipe your ID card through \the [src], attempting to shut it down.") + user.visible_message("\The [user] swipes \his ID card through \the [src], attempting to shut it down.", "You swipe your ID card through \the [src], attempting to shut it down.") if(emagged) return @@ -163,7 +167,7 @@ if(allowed(usr)) shut_down() else - user << "\red Access denied." + user << "Access denied." return @@ -185,7 +189,7 @@ //Drones killed by damage will gib. /mob/living/silicon/robot/drone/handle_regular_status_updates() - if(health <= -35 && src.stat != 2) + if((health <= -35 || (master_fabricator && src.z != master_fabricator.z)) && src.stat != 2) timeofdeath = world.time death() //Possibly redundant, having trouble making death() cooperate. gib() @@ -194,32 +198,31 @@ //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." + src << "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." + src << "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." + src << "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." + src << "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 + laws = new law_type //Reboot procs. @@ -267,17 +270,32 @@ ..() else if(istype(AM,/obj/item)) var/obj/item/O = AM - if(O.w_class > 2) + if(O.w_class > can_pull_size) src << "You are too small to pull that." return else ..() else - src << "You are too small to pull that." - return + if(!can_pull_mobs) + src << "You are too small to pull that." + return /mob/living/silicon/robot/drone/add_robot_verbs() src.verbs |= silicon_verbs_subsystems /mob/living/silicon/robot/drone/remove_robot_verbs() src.verbs -= silicon_verbs_subsystems + +/mob/living/silicon/robot/drone/construction + law_type = /datum/ai_laws/construction_drone + module_type = /obj/item/weapon/robot_module/drone/construction + can_pull_size = 5 + can_pull_mobs = 1 + +/mob/living/silicon/robot/drone/construction/init() + ..() + flavor_text = "It's a bulky construction drone stamped with a Sol Central glyph." + +/mob/living/silicon/robot/drone/construction/updatename() + real_name = "construction drone ([rand(100,999)])" + name = real_name \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/drone/drone_console.dm b/code/modules/mob/living/silicon/robot/drone/drone_console.dm index 749d9fea057..c707f85c68b 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_console.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_console.dm @@ -19,7 +19,7 @@ return if(!allowed(user)) - user << "\red Access denied." + user << "Access denied." return user.set_machine(src) @@ -27,6 +27,8 @@ dat += "Maintenance Units
" for(var/mob/living/silicon/robot/drone/D in world) + if(D.z != src.z) + continue dat += "
[D.real_name] ([D.stat == 2 ? "INACTIVE" : "ACTIVE"])" dat += "
Cell charge: [D.cell.charge]/[D.cell.maxcharge]." dat += "
Currently located in: [get_area(D)]." @@ -46,7 +48,7 @@ return if(!allowed(usr)) - usr << "\red Access denied." + usr << "Access denied." return if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) @@ -61,11 +63,11 @@ return drone_call_area = t_area - usr << "\blue You set the area selector to [drone_call_area]." + usr << "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]." + usr << "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]." @@ -75,7 +77,7 @@ 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." + usr << "You issue a law synchronization directive for the drone." D.law_resync() else if (href_list["shutdown"]) @@ -83,7 +85,7 @@ 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." + usr << "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() @@ -98,10 +100,10 @@ continue dronefab = fab - usr << "\blue Drone fabricator located." + usr << "Drone fabricator located." return - usr << "\red Unable to locate drone fabricator." + usr << "Unable to locate drone fabricator." else if (href_list["toggle_fab"]) @@ -110,10 +112,10 @@ if(get_dist(src,dronefab) > 3) dronefab = null - usr << "\red Unable to locate drone fabricator." + usr << "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." + usr << "You [dronefab.produce_drones ? "enable" : "disable"] drone production in the nearby fabricator." src.updateUsrDialog() \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/drone/drone_items.dm b/code/modules/mob/living/silicon/robot/drone/drone_items.dm index 68df16d0204..8353972ba2d 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_items.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_items.dm @@ -2,10 +2,12 @@ //Limited use. /obj/item/weapon/gripper name = "magnetic gripper" - desc = "A simple grasping tool for synthetic assets." + desc = "A simple grasping tool specialized in construction and engineering work." 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, @@ -28,8 +30,14 @@ var/obj/item/wrapped = null // Item currently being held. + var/force_holder = null // + // 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 @@ -38,14 +46,58 @@ /obj/item/weapon/gripper/paperwork name = "paperwork gripper" desc = "A simple grasping tool for clerical work." - icon = 'icons/obj/device.dmi' - icon_state = "gripper" can_hold = list( /obj/item/weapon/clipboard, /obj/item/weapon/paper, /obj/item/weapon/paper_bundle, - /obj/item/weapon/card/id + /obj/item/weapon/card/id, + /obj/item/weapon/book, + /obj/item/weapon/newspaper + ) + +/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/organ/brain, //to insert into MMIs. + /obj/item/stack/cable_coil, //again, for borg building + /obj/item/weapon/circuitboard, + /obj/item/slime_extract, + /obj/item/weapon/reagent_containers/glass, + /obj/item/weapon/reagent_containers/food/snacks/monkeycube + + ) + +/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/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/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/sheet ) /obj/item/weapon/gripper/attack_self(mob/user as mob) @@ -53,6 +105,9 @@ return wrapped.attack_self(user) return ..() +/obj/item/weapon/gripper/no_use/attack_self(mob/user as mob) + return + /obj/item/weapon/gripper/verb/drop_item() set name = "Drop Item" @@ -75,7 +130,12 @@ //update_icon() /obj/item/weapon/gripper/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) - return (wrapped ? wrapped.attack(M,user) : 0) + 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 + wrapped.attack(M,user) + return 1 + return 0 /obj/item/weapon/gripper/afterattack(var/atom/target, var/mob/living/user, proximity, params) @@ -97,6 +157,9 @@ 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. + 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 @@ -145,6 +208,21 @@ user.visible_message("[user] removes the power cell from [A]!", "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.updateicon() + A.updateicon() + A.cell.loc = src + A.cell = null + + user.visible_message("[user] removes the power cell from [A]!", "You remove the power cell.") + //TODO: Matter decompiler. /obj/item/weapon/matter_decompiler diff --git a/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm b/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm index d8009e6161c..247334c2eab 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm @@ -1,3 +1,10 @@ +/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 name = "drone fabricator" desc = "A large automated factory for producing maintenance drones." @@ -8,13 +15,20 @@ idle_power_usage = 20 active_power_usage = 5000 + var/fabricator_tag = "Exodus" var/drone_progress = 0 var/produce_drones = 1 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" +/obj/machinery/drone_fabricator/derelict + name = "construction drone fabricator" + fabricator_tag = "Derelict" + drone_type = /mob/living/silicon/robot/drone/construction + /obj/machinery/drone_fabricator/New() ..() @@ -48,13 +62,6 @@ if(produce_drones && drone_progress >= 100 && istype(user,/mob/dead) && config.allow_drone_spawn && count_drones() < config.max_maint_drones) user << "
A drone is prepared. Select 'Join As Drone' from the Ghost tab to spawn as a maintenance drone." -/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) @@ -71,13 +78,12 @@ flick("h_lathe_leave",src) time_last_drone = world.time - var/mob/living/silicon/robot/drone/new_drone = new(get_turf(src)) + var/mob/living/silicon/robot/drone/new_drone = new drone_type(get_turf(src)) new_drone.transfer_personality(player) + new_drone.master_fabricator = src drone_progress = 0 - - /mob/dead/verb/join_as_drone() set category = "Ghost" @@ -86,11 +92,11 @@ if(ticker.current_state < GAME_STATE_PLAYING) - src << "\red The game hasn't started yet!" + src << "The game hasn't started yet!" return if(!(config.allow_drone_spawn)) - src << "\red That verb is not currently permitted." + src << "That verb is not currently permitted." return if (!src.stat) @@ -100,14 +106,14 @@ return 0 //something is terribly wrong if(jobban_isbanned(src,"Cyborg")) - usr << "\red You are banned from playing synthetics and cannot spawn as a drone." + usr << "You are banned from playing synthetics and cannot spawn as a drone." return 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 Upon using the antagHUD you forfeighted the ability to join the round." + usr << "Upon using the antagHUD you forfeighted the ability to join the round." return var/deathtimeminutes = round(deathtime / 600) @@ -125,16 +131,18 @@ usr << "You must wait 10 minutes to respawn as a drone!" return + var/list/all_fabricators = list() 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 - if(DF.drone_progress >= 100) - DF.create_drone(src.client) - return + all_fabricators[DF.fabricator_tag] = DF - src << "\red There are no available drone spawn points, sorry." \ No newline at end of file + if(!all_fabricators.len) + src << "There are no available drone spawn points, sorry." + return + + var/choice = input(src,"Which fabricator do you wish to use?") as null|anything in all_fabricators + if(choice) + var/obj/machinery/drone_fabricator/chosen_fabricator = all_fabricators[choice] + chosen_fabricator.create_drone(src.client) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 5ff1c232132..cab055696df 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -265,7 +265,8 @@ module_sprites["Bro"] = "Brobot" module_sprites["Rich"] = "maximillion" module_sprites["Default"] = "Service2" - module_sprites["Drone"] = "drone-service" // How does this even work...? Oh well. + module_sprites["Drone - Service"] = "drone-service" + module_sprites["Drone - Hydro"] = "drone-hydro" if("Clerical") module = new /obj/item/weapon/robot_module/clerical(src) @@ -277,6 +278,12 @@ module_sprites["Default"] = "Service2" module_sprites["Drone"] = "drone-service" + if("Research") + module = new /obj/item/weapon/robot_module/research(src) + module.channels = list("Science" = 1) + module_sprites["Droid"] = "droid-science" + module_sprites["Drone"] = "drone-science" + if("Miner") module = new /obj/item/weapon/robot_module/miner(src) module.channels = list("Supply" = 1) @@ -296,7 +303,8 @@ module_sprites["Standard"] = "surgeon" module_sprites["Advanced Droid"] = "droid-medical" module_sprites["Needles"] = "medicalrobot" - module_sprites["Drone" ] = "drone-medical" + module_sprites["Drone - Medical" ] = "drone-medical" + module_sprites["Drone - Chemistry" ] = "drone-chemistry" if("Surgeon") module = new /obj/item/weapon/robot_module/surgeon(src) @@ -731,7 +739,7 @@ else user << "Unable to locate a radio." - else if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)) // trying to unlock the interface with an ID card + else if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)||istype(W, /obj/item/weapon/card/robot)) // trying to unlock the interface with an ID card if(emagged)//still allow them to open the cover user << "The interface seems slightly damaged" if(opened) @@ -868,6 +876,10 @@ //if they are holding or wearing a card that has access, that works if(check_access(H.get_active_hand()) || check_access(H.wear_id)) return 1 + else if(istype(M, /mob/living/silicon/robot)) + var/mob/living/silicon/robot/R = M + if(check_access(R.get_active_hand()) || istype(R.get_active_hand(), /obj/item/weapon/card/robot)) + return 1 return 0 /mob/living/silicon/robot/proc/check_access(obj/item/weapon/card/id/I) diff --git a/code/modules/mob/living/silicon/robot/robot_items.dm b/code/modules/mob/living/silicon/robot/robot_items.dm index 0d40f0954a6..d18ca506cca 100644 --- a/code/modules/mob/living/silicon/robot/robot_items.dm +++ b/code/modules/mob/living/silicon/robot/robot_items.dm @@ -1,3 +1,138 @@ +//A portable analyzer, for research borgs. This is better then giving them a gripper which can hold anything and letting them use the normal analyzer. +/obj/item/weapon/portable_destructive_analyzer + name = "Portable Destructive Analyzer" + icon = 'icons/obj/items.dmi' + icon_state = "portable_analyzer" + desc = "Similar to the stationary version, this rather unwieldy device allows you to break down objects in the name of science." + + var/min_reliability = 90 //Can't upgrade, call it laziness or a drawback + + var/datum/research/techonly/files //The device uses the same datum structure as the R&D computer/server. + //This analyzer can only store tech levels, however. + + var/obj/item/weapon/loaded_item //What is currently inside the analyzer. + +/obj/item/weapon/portable_destructive_analyzer/New() + ..() + files = new /datum/research/techonly(src) //Setup the research data holder. + +/obj/item/weapon/portable_destructive_analyzer/attack_self(user as mob) + var/response = alert(user, "Analyzing the item inside will *DESTROY* the item for good.\n\ + Syncing to the research server will send the data that is stored inside to research.\n\ + Ejecting will place the loaded item onto the floor.", + "What would you like to do?", "Analyze", "Sync", "Eject") + if(response == "Analyze") + if(loaded_item) + var/confirm = alert(user, "This will destroy the item inside forever. Are you sure?","Confirm Analyze","Yes","No") + if(confirm == "Yes") //This is pretty copypasta-y + user << "You activate the analyzer's microlaser, analyzing \the [loaded_item] and breaking it down." + flick("portable_analyzer_scan", src) + playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) + if(loaded_item.reliability >= min_reliability) + var/list/temp_tech = ConvertReqString2List(loaded_item.origin_tech) + for(var/T in temp_tech) + files.UpdateTech(T, temp_tech[T]) + user << "\The [loaded_item] had level [temp_tech[T]] in [T]." + loaded_item = null + for(var/obj/I in contents) + for(var/mob/M in I.contents) + M.death() + if(istype(I,/obj/item/stack/sheet))//Only deconsturcts one sheet at a time instead of the entire stack + var/obj/item/stack/sheet/S = I + if(S.get_amount() > 1) + S.use(1) + loaded_item = S + else + del(S) + desc = initial(desc) + icon_state = initial(icon_state) + else + del(I) + desc = initial(desc) + icon_state = initial(icon_state) + else + return + else + user << "The [src] is empty. Put something inside it first." + if(response == "Sync") + var/success = 0 + for(var/obj/machinery/r_n_d/server/S in machines) + if(S.disabled) + continue + for(var/datum/tech/T in files.known_tech) //Uploading + S.files.AddTech2Known(T) + for(var/datum/tech/T in S.files.known_tech) //Downloading + files.AddTech2Known(T) + success = 1 + files.RefreshResearch() + if(success) + user << "You connect to the research server, push your data upstream to it, then pull the resulting merged data from the master branch." + playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 1) + else + user << "Reserch server ping response timed out. Unable to connect. Please contact the system administrator." + playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 1) + if(response == "Eject") + if(loaded_item) + loaded_item.loc = get_turf(src) + desc = initial(desc) + icon_state = initial(icon_state) + loaded_item = null + else + user << "The [src] is already empty." + + +/obj/item/weapon/portable_destructive_analyzer/afterattack(var/atom/target, var/mob/living/user, proximity) + if(!target) + return + if(!proximity) + return + if(!isturf(target.loc)) // Don't load up stuff if it's inside a container or mob! + return + if(istype(target,/obj/item)) + if(loaded_item) + user << "Your [src] already has something inside. Analyze or eject it first." + return + var/obj/item/I = target + I.loc = src + loaded_item = I + for(var/mob/M in viewers()) + M.show_message(text("[user] adds the [I] to the [src]."), 1) + desc = initial(desc) + "
It is holding \the [loaded_item]." + flick("portable_analyzer_load", src) + icon_state = "portable_analyzer_full" + +//This is used to unlock other borg covers. +/obj/item/weapon/card/robot //This is not a child of id cards, as to avoid dumb typechecks on computers. + name = "access code transmission device" + icon_state = "id-robot" + desc = "A circuit grafted onto the bottom of an ID card. It is used to transmit access codes into other robot chassis, \ + allowing you to lock and unlock other robots' panels." + +/obj/item/weapon/card/id/robot/attack_self() //override so borgs can't flash their IDs. + return + +/obj/item/weapon/card/id/robot/read() + usr << "The ID card does not appear to have any writing on it." + return + +//A harvest item for serviceborgs. +/obj/item/weapon/robot_harvester + name = "auto harvester" + desc = "A hand-held harvest tool that resembles a sickle. It uses energy to cut plant matter very efficently." + icon = 'icons/obj/weapons.dmi' + icon_state = "autoharvester" + +/obj/item/weapon/robot_harvester/afterattack(var/atom/target, var/mob/living/user, proximity) + if(!target) + return + if(!proximity) + return + if(istype(target,/obj/machinery/portable_atmospherics/hydroponics)) + var/obj/machinery/portable_atmospherics/hydroponics/T = target + T.harvest(user) + else + user << "Harvesting \a [target] is not the purpose of this tool. The [src] is for plants being grown." + // A special tray for the service droid. Allow droid to pick up and drop items as if they were using the tray normally // Click on table to unload, click on item to load. Otherwise works identically to a tray. // Unlike the base item "tray", robotrays ONLY pick up food, drinks and condiments. diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 12565f4ea4f..a48adddeb82 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -314,8 +314,13 @@ /obj/item/weapon/robot_module/butler/New() ..() src.modules += new /obj/item/device/flash(src) - src.modules += new /obj/item/weapon/reagent_containers/food/drinks/cans/beer(src) - src.modules += new /obj/item/weapon/reagent_containers/food/condiment/enzyme(src) + src.modules += new /obj/item/weapon/gripper/service(src) + src.modules += new /obj/item/weapon/reagent_containers/glass/bucket(src) + src.modules += new /obj/item/weapon/minihoe(src) + src.modules += new /obj/item/weapon/hatchet(src) + src.modules += new /obj/item/device/analyzer/plant_analyzer(src) + src.modules += new /obj/item/weapon/storage/bag/plants(src) + src.modules += new /obj/item/weapon/robot_harvester(src) var/obj/item/weapon/rsf/M = new /obj/item/weapon/rsf(src) M.stored_matter = 30 @@ -358,6 +363,7 @@ src.modules += new /obj/item/weapon/pen/robopen(src) src.modules += new /obj/item/weapon/form_printer(src) src.modules += new /obj/item/weapon/gripper/paperwork(src) + src.modules += new /obj/item/weapon/hand_labeler(src) src.emag = new /obj/item/weapon/stamp/denied(src) /obj/item/weapon/robot_module/clerical/add_languages(var/mob/living/silicon/robot/R) @@ -395,6 +401,38 @@ src.emag = new /obj/item/weapon/pickaxe/plasmacutter(src) return +/obj/item/weapon/robot_module/research + name = "research module" + +/obj/item/weapon/robot_module/research/New() + ..() + src.modules += new /obj/item/device/flash(src) + src.modules += new /obj/item/weapon/portable_destructive_analyzer(src) + src.modules += new /obj/item/weapon/gripper/research(src) + src.modules += new /obj/item/weapon/gripper/no_use/loader(src) + src.modules += new /obj/item/device/robotanalyzer(src) + src.modules += new /obj/item/weapon/card/robot(src) + src.modules += new /obj/item/weapon/wrench(src) + src.modules += new /obj/item/weapon/screwdriver(src) + src.modules += new /obj/item/weapon/crowbar(src) + src.modules += new /obj/item/weapon/scalpel(src) + src.modules += new /obj/item/weapon/circular_saw(src) + src.modules += new /obj/item/weapon/extinguisher/mini(src) + src.modules += new /obj/item/weapon/reagent_containers/syringe(src) + src.modules += new /obj/item/weapon/reagent_containers/glass/beaker/large(src) + src.emag = new /obj/item/weapon/hand_tele(src) + + var/datum/matter_synth/nanite = new /datum/matter_synth/nanite(10000) + synths += nanite + + var/obj/item/stack/nanopaste/N = new /obj/item/stack/nanopaste(src) + N.uses_charge = 1 + N.charge_costs = list(1000) + N.synths = list(nanite) + src.modules += N + + return + /obj/item/weapon/robot_module/syndicate name = "illegal robot module" @@ -446,7 +484,7 @@ src.modules += new /obj/item/device/multitool(src) src.modules += new /obj/item/device/lightreplacer(src) src.modules += new /obj/item/weapon/gripper(src) - src.modules += new /obj/item/weapon/reagent_containers/spray/cleaner/drone(src) + src.modules += new /obj/item/weapon/soap(src) src.emag = new /obj/item/weapon/pickaxe/plasmacutter(src) src.emag.name = "Plasma Cutter" @@ -504,16 +542,19 @@ P.synths = list(plastic) src.modules += P +/obj/item/weapon/robot_module/drone/construction + name = "construction drone module" + +/obj/item/weapon/robot_module/drone/construction/New() + ..() + src.modules += new /obj/item/weapon/rcd/borg(src) + /obj/item/weapon/robot_module/drone/add_languages(var/mob/living/silicon/robot/R) return //not much ROM to spare in that tiny microprocessor! /obj/item/weapon/robot_module/drone/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) - var/obj/item/weapon/reagent_containers/spray/cleaner/C = locate() in src.modules - C.reagents.add_reagent("cleaner", 3 * amount) - var/obj/item/device/lightreplacer/LR = locate() in src.modules LR.Charge(R, amount) - ..() return @@ -521,7 +562,5 @@ /obj/item/proc/is_robot_module() if (!istype(src.loc, /mob/living/silicon/robot)) return 0 - var/mob/living/silicon/robot/R = src.loc - return (src in R.module.modules) diff --git a/code/modules/nano/modules/alarm_monitor.dm b/code/modules/nano/modules/alarm_monitor.dm index 9047023bf1b..b27349bf9a8 100644 --- a/code/modules/nano/modules/alarm_monitor.dm +++ b/code/modules/nano/modules/alarm_monitor.dm @@ -85,7 +85,7 @@ "origin_lost" = A.origin == null, "has_cameras" = cameras.len, "cameras" = cameras, - "lost_sources" = sanitize(english_list(lost_sources, nothing_text = "", and_text = ", ")))) + "lost_sources" = lost_sources.len ? sanitize(english_list(lost_sources, nothing_text = "", and_text = ", ")) : "")) data["categories"] = categories ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index b436d9f571f..143b00e6231 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -324,7 +324,17 @@ if(href_list["write"]) var/id = href_list["write"] //var/t = strip_html_simple(input(usr, "What text do you wish to add to " + (id=="end" ? "the end of the paper" : "field "+id) + "?", "[name]", null),8192) as message - var/t = sanitize(input("Enter what you want to write:", "Write", null, null) as message, MAX_PAPER_MESSAGE_LEN, extra = 0) + + var/textlimit = MAX_PAPER_MESSAGE_LEN - length(info) + if(textlimit <= 0) + usr << "There isn't enough space left on \the [src] to write anything." + return + + var/t = sanitize(input("Enter what you want to write:", "Write", null, null) as message, textlimit, extra = 0) + + if(!t) + return + var/obj/item/i = usr.get_active_hand() // Check to see if he still got that darn pen, also check if he's using a crayon or pen. var/iscrayon = 0 if(!istype(i, /obj/item/weapon/pen)) @@ -347,6 +357,9 @@ message_admins("PAPER: [usr] ([usr.ckey]) tried to use forbidden word in [src]: [bad].") return */ + + var last_fields_value = fields + //t = html_encode(t) t = replacetext(t, "\n", "
") t = parsepencode(t, i, usr, iscrayon) // Encode everything from pencode to html @@ -354,6 +367,7 @@ if(fields > 50)//large amount of fields creates a heavy load on the server, see updateinfolinks() and addtofield() usr << "Too many fields. Sorry, you can't do this." + fields = last_fields_value return if(id!="end") diff --git a/code/modules/research/circuitprinter.dm b/code/modules/research/circuitprinter.dm index a16e5653a93..e1e63c08dc9 100644 --- a/code/modules/research/circuitprinter.dm +++ b/code/modules/research/circuitprinter.dm @@ -104,46 +104,51 @@ using metal and glass, it uses glass and reagents (usually sulfuric acis). return 1 if(O.is_open_container()) return 0 - if(!istype(O, /obj/item/stack/sheet/glass) && !istype(O, /obj/item/stack/sheet/mineral/gold) && !istype(O, /obj/item/stack/sheet/mineral/diamond) && !istype(O, /obj/item/stack/sheet/mineral/uranium)) - user << "You cannot insert this item into \the [src]!" - return 1 +// if(!istype(O, /obj/item/stack/sheet/glass) && !istype(O, /obj/item/stack/sheet/mineral/gold) && !istype(O, /obj/item/stack/sheet/mineral/diamond) && !istype(O, /obj/item/stack/sheet/mineral/uranium)) +// user << "You cannot insert this item into \the [src]!" +// return 1 if(stat) return 1 if(busy) user << "\The [src] is busy. Please wait for completion of previous operation." return 1 - var/obj/item/stack/sheet/stack = O - if((TotalMaterials() + stack.perunit) > max_material_amount) - user << "\The [src] is full. Please remove glass from \the [src] in order to insert more." - return 1 - var/amount = round(input("How many sheets do you want to add?") as num) - if(amount < 0) - amount = 0 - if(amount == 0) - return - if(amount > stack.amount) - amount = min(stack.amount, round((max_material_amount - TotalMaterials()) / stack.perunit)) + if(istype(O, /obj/item/stack/sheet/glass) || istype(O, /obj/item/stack/sheet/mineral/gold) || istype(O, /obj/item/stack/sheet/mineral/diamond) || istype(O, /obj/item/stack/sheet/mineral/uranium)) - busy = 1 - use_power(max(1000, (3750 * amount / 10))) - var/stacktype = stack.type - stack.use(amount) - if(do_after(usr, 16)) - user << "You add [amount] sheets to \the [src]." - switch(stacktype) - if(/obj/item/stack/sheet/glass) - g_amount += amount * 3750 - if(/obj/item/stack/sheet/mineral/gold) - gold_amount += amount * 2000 - if(/obj/item/stack/sheet/mineral/diamond) - diamond_amount += amount * 2000 - if(/obj/item/stack/sheet/mineral/uranium) - uranium_amount += amount * 2000 - else - new stacktype(loc, amount) - busy = 0 - updateUsrDialog() + var/obj/item/stack/sheet/stack = O + if((TotalMaterials() + stack.perunit) > max_material_amount) + user << "\The [src] is full. Please remove glass from \the [src] in order to insert more." + return 1 + + var/amount = round(input("How many sheets do you want to add?") as num) + if(amount < 0) + amount = 0 + if(amount == 0) + return + if(amount > stack.amount) + amount = min(stack.amount, round((max_material_amount - TotalMaterials()) / stack.perunit)) + + busy = 1 + use_power(max(1000, (3750 * amount / 10))) + var/stacktype = stack.type + stack.use(amount) + if(do_after(usr, 16)) + user << "You add [amount] sheets to \the [src]." + switch(stacktype) + if(/obj/item/stack/sheet/glass) + g_amount += amount * 3750 + if(/obj/item/stack/sheet/mineral/gold) + gold_amount += amount * 2000 + if(/obj/item/stack/sheet/mineral/diamond) + diamond_amount += amount * 2000 + if(/obj/item/stack/sheet/mineral/uranium) + uranium_amount += amount * 2000 + else + new stacktype(loc, amount) + busy = 0 + updateUsrDialog() + + ..() //This is to stop these machines being hackable via clicking. /obj/machinery/r_n_d/circuit_imprinter/attack_hand(mob/user as mob) diff --git a/code/modules/research/destructive_analyzer.dm b/code/modules/research/destructive_analyzer.dm index 7b7445f0993..3fc97cc6ab4 100644 --- a/code/modules/research/destructive_analyzer.dm +++ b/code/modules/research/destructive_analyzer.dm @@ -13,7 +13,7 @@ Note: Must be placed within 3 tiles of the R&D Console var/obj/item/weapon/loaded_item = null var/decon_mod = 1 var/min_reliability = 90 - + use_power = 1 idle_power_usage = 30 active_power_usage = 2500 @@ -38,12 +38,6 @@ Note: Must be placed within 3 tiles of the R&D Console del(src) return -/obj/machinery/r_n_d/destructive_analyzer/proc/ConvertReqString2List(var/list/source_list) - var/list/temp_list = params2list(source_list) - for(var/O in temp_list) - temp_list[O] = text2num(temp_list[O]) - return temp_list - /obj/machinery/r_n_d/destructive_analyzer/update_icon() if(panel_open) icon_state = "d_analyzer_t" diff --git a/code/modules/research/protolathe.dm b/code/modules/research/protolathe.dm index 22df4b82ddd..06f3f7b760e 100644 --- a/code/modules/research/protolathe.dm +++ b/code/modules/research/protolathe.dm @@ -116,9 +116,6 @@ Note: Must be placed west/left of and R&D console to function. if(busy) user << "\The [src] is busy. Please wait for completion of previous operation." return 1 - if(!istype(O, /obj/item/stack/sheet)) - user << "You cannot insert this item into \the [src]!" - return 1 if(stat) return 1 if(istype(O,/obj/item/stack/sheet)) @@ -127,51 +124,52 @@ Note: Must be placed west/left of and R&D console to function. user << "\The [src]'s material bin is full. Please remove material before adding more." return 1 - var/obj/item/stack/sheet/stack = O - var/amount = round(input("How many sheets do you want to add?") as num)//No decimals - if(!O) - return - if(amount < 0)//No negative numbers - amount = 0 - if(amount == 0) - return - if(amount > stack.get_amount()) - amount = stack.get_amount() - if(max_material_storage - TotalMaterials() < (amount * stack.perunit))//Can't overfill - amount = min(stack.amount, round((max_material_storage - TotalMaterials()) / stack.perunit)) + var/obj/item/stack/sheet/stack = O + var/amount = round(input("How many sheets do you want to add?") as num)//No decimals + if(!O) + return + if(amount < 0)//No negative numbers + amount = 0 + if(amount == 0) + return + if(amount > stack.get_amount()) + amount = stack.get_amount() + if(max_material_storage - TotalMaterials() < (amount * stack.perunit))//Can't overfill + amount = min(stack.amount, round((max_material_storage - TotalMaterials()) / stack.perunit)) - overlays += "protolathe_[stack.name]" - sleep(10) - overlays -= "protolathe_[stack.name]" + overlays += "protolathe_[stack.name]" + sleep(10) + overlays -= "protolathe_[stack.name]" - icon_state = "protolathe" - busy = 1 - use_power(max(1000, (3750 * amount / 10))) - var/stacktype = stack.type - stack.use(amount) - if(do_after(user, 16)) - user << "You add [amount] sheets to \the [src]." icon_state = "protolathe" - switch(stacktype) - if(/obj/item/stack/sheet/metal) - m_amount += amount * 3750 - if(/obj/item/stack/sheet/glass) - g_amount += amount * 3750 - if(/obj/item/stack/sheet/mineral/gold) - gold_amount += amount * 2000 - if(/obj/item/stack/sheet/mineral/silver) - silver_amount += amount * 2000 - if(/obj/item/stack/sheet/mineral/phoron) - phoron_amount += amount * 2000 - if(/obj/item/stack/sheet/mineral/uranium) - uranium_amount += amount * 2000 - if(/obj/item/stack/sheet/mineral/diamond) - diamond_amount += amount * 2000 - else - new stacktype(loc, amount) - busy = 0 - updateUsrDialog() - return + busy = 1 + use_power(max(1000, (3750 * amount / 10))) + var/stacktype = stack.type + stack.use(amount) + if(do_after(user, 16)) + user << "You add [amount] sheets to \the [src]." + icon_state = "protolathe" + switch(stacktype) + if(/obj/item/stack/sheet/metal) + m_amount += amount * 3750 + if(/obj/item/stack/sheet/glass) + g_amount += amount * 3750 + if(/obj/item/stack/sheet/mineral/gold) + gold_amount += amount * 2000 + if(/obj/item/stack/sheet/mineral/silver) + silver_amount += amount * 2000 + if(/obj/item/stack/sheet/mineral/phoron) + phoron_amount += amount * 2000 + if(/obj/item/stack/sheet/mineral/uranium) + uranium_amount += amount * 2000 + if(/obj/item/stack/sheet/mineral/diamond) + diamond_amount += amount * 2000 + else + new stacktype(loc, amount) + busy = 0 + updateUsrDialog() + return + ..() //This is to stop these machines being hackable via clicking. /obj/machinery/r_n_d/protolathe/attack_hand(mob/user as mob) diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm index 1ad86378b03..89e31574d2c 100644 --- a/code/modules/research/rdconsole.dm +++ b/code/modules/research/rdconsole.dm @@ -256,7 +256,7 @@ won't update every console in existence) but it's more of a hassle to do. Also, screen = 1.0 return if(linked_destroy.loaded_item.reliability >= linked_destroy.min_reliability) - var/list/temp_tech = linked_destroy.ConvertReqString2List(linked_destroy.loaded_item.origin_tech) + var/list/temp_tech = ConvertReqString2List(linked_destroy.loaded_item.origin_tech) for(var/T in temp_tech) files.UpdateTech(T, temp_tech[T]) if(linked_destroy.loaded_item.reliability < 100 && linked_destroy.loaded_item.crit_fail) @@ -753,7 +753,7 @@ won't update every console in existence) but it's more of a hassle to do. Also, dat += "Name: [linked_destroy.loaded_item.name]
" dat += "Origin Tech:" dat += "