From 4a450545ef7c840b89845f9b2e304a193bcee647 Mon Sep 17 00:00:00 2001 From: jack-fractal Date: Mon, 18 May 2015 19:24:41 -0400 Subject: [PATCH 1/8] Porting UI changes for AI's and Robots Gives AI's a set of icons for their more common tasks. Makes Cyborg inventories work like backpacks. --- aurora.dme | 2 + code/_onclick/hud/_defines.dm | 22 +++ code/_onclick/hud/ai.dm | 143 ++++++++++++++++++ code/_onclick/hud/other_mobs.dm | 3 - code/_onclick/hud/robot.dm | 101 +++++++++++-- code/_onclick/hud/screen_objects.dm | 91 ++++++++++- code/game/objects/items.dm | 8 + .../mob/living/carbon/human/examine.dm | 10 +- code/modules/mob/living/silicon/ai/ai.dm | 6 +- code/modules/mob/living/silicon/ai/life.dm | 6 + code/modules/mob/living/silicon/ai/nano.dm | 11 ++ .../mob/living/silicon/robot/inventory.dm | 116 +++++++------- code/modules/mob/living/silicon/robot/life.dm | 9 +- .../modules/mob/living/silicon/robot/robot.dm | 13 ++ code/modules/mob/living/silicon/silicon.dm | 19 ++- icons/mob/screen_ai.dmi | Bin 0 -> 2394 bytes 16 files changed, 480 insertions(+), 80 deletions(-) create mode 100644 code/_onclick/hud/ai.dm create mode 100644 code/modules/mob/living/silicon/ai/nano.dm create mode 100644 icons/mob/screen_ai.dmi diff --git a/aurora.dme b/aurora.dme index 3b5bcedb..c7d1c3fa 100644 --- a/aurora.dme +++ b/aurora.dme @@ -125,6 +125,7 @@ #include "code\_onclick\other_mobs.dm" #include "code\_onclick\telekinesis.dm" #include "code\_onclick\hud\_defines.dm" +#include "code\_onclick\hud\ai.dm" #include "code\_onclick\hud\alien.dm" #include "code\_onclick\hud\alien_larva.dm" #include "code\_onclick\hud\hud.dm" @@ -1155,6 +1156,7 @@ #include "code\modules\mob\living\silicon\ai\life.dm" #include "code\modules\mob\living\silicon\ai\login.dm" #include "code\modules\mob\living\silicon\ai\logout.dm" +#include "code\modules\mob\living\silicon\ai\nano.dm" #include "code\modules\mob\living\silicon\ai\say.dm" #include "code\modules\mob\living\silicon\ai\freelook\cameranet.dm" #include "code\modules\mob\living\silicon\ai\freelook\chunk.dm" diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm index fc822a38..57d2cac3 100644 --- a/code/_onclick/hud/_defines.dm +++ b/code/_onclick/hud/_defines.dm @@ -39,6 +39,7 @@ #define ui_alien_head "4:12,1:5" //aliens #define ui_alien_oclothing "5:14,1:5" //aliens +#define ui_borg_sensor "5:16,1:5" //borgs #define ui_inv1 "6:16,1:5" //borgs #define ui_inv2 "7:16,1:5" //borgs #define ui_inv3 "8:16,1:5" //borgs @@ -57,6 +58,8 @@ #define ui_acti_alt "14:28,1:5" //alternative intent switcher for when the interface is hidden (F12) #define ui_borg_pull "12:24,2:7" +#define ui_borg_radio "EAST-1:28,SOUTH+1:7" +#define ui_borg_intents "EAST-2:26,SOUTH:5" #define ui_borg_module "13:26,2:7" #define ui_borg_panel "14:28,2:7" @@ -117,3 +120,22 @@ #define ui_iarrowleft "SOUTH-1,11" #define ui_iarrowright "SOUTH-1,13" + +// AI + +#define ui_ai_camera_list "SOUTH:6+1,WEST+1:16" +#define ui_ai_track_with_camera "SOUTH:6+1,WEST+2:16" +#define ui_ai_camera_light "SOUTH:6+1,WEST+3:16" +#define ui_ai_sensor "SOUTH:6+1,WEST+4:16" + +#define ui_ai_core "SOUTH:6,WEST+1:16" +#define ui_ai_crew_monitor "SOUTH:6,WEST+2:16" +#define ui_ai_crew_manifest "SOUTH:6,WEST+3:16" +#define ui_ai_alerts "SOUTH:6,WEST+4:16" +#define ui_ai_announcement "SOUTH:6,WEST+5:16" +#define ui_ai_shuttle "SOUTH:6,WEST+6:16" +#define ui_ai_state_laws "SOUTH:6,WEST+7:16" +#define ui_ai_pda_send "SOUTH:6,WEST+8:16" +#define ui_ai_pda_log "SOUTH:6,WEST+9:16" +#define ui_ai_take_picture "SOUTH:6,WEST+10:16" +#define ui_ai_view_images "SOUTH:6,WEST+11:16" \ No newline at end of file diff --git a/code/_onclick/hud/ai.dm b/code/_onclick/hud/ai.dm new file mode 100644 index 00000000..b528832c --- /dev/null +++ b/code/_onclick/hud/ai.dm @@ -0,0 +1,143 @@ +/datum/hud/proc/ai_hud() + adding = list() + other = list() + + var/obj/screen/using + +//AI core + using = new /obj/screen() + using.name = "AI Core" + using.icon = 'icons/mob/screen_ai.dmi' + using.icon_state = "ai_core" + using.screen_loc = ui_ai_core + using.layer = 20 + adding += using + +//Camera list + using = new /obj/screen() + using.name = "Show Camera List" + using.icon = 'icons/mob/screen_ai.dmi' + using.icon_state = "camera" + using.screen_loc = ui_ai_camera_list + using.layer = 20 + adding += using + +//Track + using = new /obj/screen() + using.name = "Track With Camera" + using.icon = 'icons/mob/screen_ai.dmi' + using.icon_state = "track" + using.screen_loc = ui_ai_track_with_camera + using.layer = 20 + adding += using + +//Camera light + using = new /obj/screen() + using.name = "Toggle Camera Light" + using.icon = 'icons/mob/screen_ai.dmi' + using.icon_state = "camera_light" + using.screen_loc = ui_ai_camera_light + using.layer = 20 + adding += using + +//Crew Monitorting + using = new /obj/screen() + using.name = "Crew Monitoring" + using.icon = 'icons/mob/screen_ai.dmi' + using.icon_state = "crew_monitor" + using.screen_loc = ui_ai_crew_monitor + using.layer = 20 + adding += using + +//Crew Manifest + using = new /obj/screen() + using.name = "Show Crew Manifest" + using.icon = 'icons/mob/screen_ai.dmi' + using.icon_state = "manifest" + using.screen_loc = ui_ai_crew_manifest + using.layer = 20 + adding += using + +//Alerts + using = new /obj/screen() + using.name = "Show Alerts" + using.icon = 'icons/mob/screen_ai.dmi' + using.icon_state = "alerts" + using.screen_loc = ui_ai_alerts + using.layer = 20 + adding += using + +//Announcement + using = new /obj/screen() + using.name = "Announcement" + using.icon = 'icons/mob/screen_ai.dmi' + using.icon_state = "announcement" + using.screen_loc = ui_ai_announcement + using.layer = 20 + adding += using + +//Shuttle + using = new /obj/screen() + using.name = "Call Emergency Shuttle" + using.icon = 'icons/mob/screen_ai.dmi' + using.icon_state = "call_shuttle" + using.screen_loc = ui_ai_shuttle + using.layer = 20 + adding += using + +//Laws + using = new /obj/screen() + using.name = "State Laws" + using.icon = 'icons/mob/screen_ai.dmi' + using.icon_state = "state_laws" + using.screen_loc = ui_ai_state_laws + using.layer = 20 + adding += using + +//PDA message + using = new /obj/screen() + using.name = "PDA - Send Message" + using.icon = 'icons/mob/screen_ai.dmi' + using.icon_state = "pda_send" + using.screen_loc = ui_ai_pda_send + using.layer = 20 + adding += using + +//PDA log + using = new /obj/screen() + using.name = "PDA - Show Message Log" + using.icon = 'icons/mob/screen_ai.dmi' + using.icon_state = "pda_receive" + using.screen_loc = ui_ai_pda_log + using.layer = 20 + adding += using + +//Take image + using = new /obj/screen() + using.name = "Take Image" + using.icon = 'icons/mob/screen_ai.dmi' + using.icon_state = "take_picture" + using.screen_loc = ui_ai_take_picture + using.layer = 20 + adding += using + +//View images + using = new /obj/screen() + using.name = "View Images" + using.icon = 'icons/mob/screen_ai.dmi' + using.icon_state = "view_images" + using.screen_loc = ui_ai_view_images + using.layer = 20 + adding += using + +//Medical/Security sensors + using = new /obj/screen() + using.name = "Set Sensor Augmentation" + using.icon = 'icons/mob/screen_ai.dmi' + using.icon_state = "ai_sensor" + using.screen_loc = ui_ai_sensor + using.layer = 20 + adding += using + + mymob.client.screen += adding + other + return \ No newline at end of file diff --git a/code/_onclick/hud/other_mobs.dm b/code/_onclick/hud/other_mobs.dm index cd19e78d..10cf0d03 100644 --- a/code/_onclick/hud/other_mobs.dm +++ b/code/_onclick/hud/other_mobs.dm @@ -13,9 +13,6 @@ mymob.blind.screen_loc = "1,1" mymob.blind.layer = 0 -/datum/hud/proc/ai_hud() - return - /datum/hud/proc/blob_hud(ui_style = 'icons/mob/screen1_Midnight.dmi') blobpwrdisplay = new /obj/screen() diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm index 62cf2247..e91cfb50 100644 --- a/code/_onclick/hud/robot.dm +++ b/code/_onclick/hud/robot.dm @@ -12,7 +12,7 @@ using.dir = SOUTHWEST using.icon = 'icons/mob/screen1_robot.dmi' using.icon_state = "radio" - using.screen_loc = ui_movi + using.screen_loc = ui_borg_radio using.layer = 20 src.adding += using @@ -50,13 +50,22 @@ //End of module select +//Sec/Med HUDs + using = new /obj/screen() + using.name = "Toggle Sensor Augmentation" + using.icon = 'icons/mob/screen_ai.dmi' + using.icon_state = "ai_sensor" + using.screen_loc = ui_borg_sensor + using.layer = 20 + adding += using + //Intent using = new /obj/screen() using.name = "act_intent" using.dir = SOUTHWEST using.icon = 'icons/mob/screen1_robot.dmi' - using.icon_state = (mymob.a_intent == "hurt" ? "harm" : mymob.a_intent) - using.screen_loc = ui_acti + using.icon_state = (mymob.a_intent == "harm" ? "harm" : mymob.a_intent) + using.screen_loc = ui_borg_intents using.layer = 20 src.adding += using action_intent = using @@ -82,14 +91,6 @@ mymob.hands.name = "module" mymob.hands.screen_loc = ui_borg_module -//Module Panel - using = new /obj/screen() - using.name = "panel" - using.icon = 'icons/mob/screen1_robot.dmi' - using.icon_state = "panel" - using.screen_loc = ui_borg_panel - using.layer = 19 - src.adding += using //Store mymob.throw_icon = new /obj/screen() @@ -153,18 +154,90 @@ if (mymob.client.target_can_click) mymob.item_use_icon.dir = 1 src.adding += mymob.item_use_icon - mymob.gun_move_icon = new /obj/screen/gun/move(null) + /*mymob.gun_move_icon = new /obj/screen/gun/move(null) if (mymob.client.target_can_move) mymob.gun_move_icon.dir = 1 mymob.gun_run_icon = new /obj/screen/gun/run(null) if (mymob.client.target_can_run) mymob.gun_run_icon.dir = 1 src.adding += mymob.gun_run_icon - src.adding += mymob.gun_move_icon + src.adding += mymob.gun_move_icon*/ mymob.client.screen = null - mymob.client.screen += list( mymob.throw_icon, mymob.zone_sel, mymob.oxygen, mymob.fire, mymob.hands, mymob.healths, mymob:cells, mymob.pullin, mymob.blind, mymob.flash, mymob.gun_setting_icon) //, mymob.rest, mymob.sleep, mymob.mach ) + mymob.client.screen += list(mymob.zone_sel, mymob.oxygen, mymob.fire, mymob.hands, mymob.healths, mymob:cells, mymob.pullin, mymob.blind, mymob.flash, mymob.gun_setting_icon) //, mymob.rest, mymob.sleep, mymob.mach ) mymob.client.screen += src.adding + src.other return + + +/datum/hud/proc/toggle_show_robot_modules() + if(!isrobot(mymob)) return + + var/mob/living/silicon/robot/r = mymob + + r.shown_robot_modules = !r.shown_robot_modules + update_robot_modules_display() + +/datum/hud/proc/update_robot_modules_display() + if(!isrobot(mymob)) return + + var/mob/living/silicon/robot/r = mymob + + if(r.shown_robot_modules) + //Modules display is shown + r.client.screen += r.throw_icon //"store" icon + + if(!r.module) + usr << "\red No module selected" + return + + if(!r.module.modules) + usr << "\red Selected module has no modules to select" + return + + if(!r.robot_modules_background) + return + + var/display_rows = round((r.module.modules.len) / 8) +1 //+1 because round() returns floor of number + r.robot_modules_background.screen_loc = "CENTER-4:16,SOUTH+1:7 to CENTER+3:16,SOUTH+[display_rows]:7" + r.client.screen += r.robot_modules_background + + var/x = -4 //Start at CENTER-4,SOUTH+1 + var/y = 1 + + //Unfortunately adding the emag module to the list of modules has to be here. This is because a borg can + //be emagged before they actually select a module. - or some situation can cause them to get a new module + // - or some situation might cause them to get de-emagged or something. + if(r.emagged) + if(!(r.module.emag in r.module.modules)) + r.module.modules.Add(r.module.emag) + else + if(r.module.emag in r.module.modules) + r.module.modules.Remove(r.module.emag) + + for(var/atom/movable/A in r.module.modules) + if( (A != r.module_state_1) && (A != r.module_state_2) && (A != r.module_state_3) ) + //Module is not currently active + r.client.screen += A + if(x < 0) + A.screen_loc = "CENTER[x]:16,SOUTH+[y]:7" + else + A.screen_loc = "CENTER+[x]:16,SOUTH+[y]:7" + A.layer = 20 + + x++ + if(x == 4) + x = -4 + y++ + + else + //Modules display is hidden + r.client.screen -= r.throw_icon //"store" icon + + for(var/atom/A in r.module.modules) + if( (A != r.module_state_1) && (A != r.module_state_2) && (A != r.module_state_3) ) + //Module is not currently active + r.client.screen -= A + r.shown_robot_modules = 0 + r.client.screen -= r.robot_modules_background diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 02929525..69dcde47 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -370,10 +370,12 @@ usr.drop_item_v() if("module") - if(issilicon(usr)) - if(usr:module) + if(isrobot(usr)) + var/mob/living/silicon/robot/R = usr + if(R.module) + R.hud_used.toggle_show_robot_modules() return 1 - usr:pick_module() + R.pick_module() if("radio") if(issilicon(usr)) @@ -386,6 +388,11 @@ if(issilicon(usr)) usr:uneq_active() + if("Toggle Sensor Augmentation") + if(isrobot(usr)) + var/mob/living/silicon/robot/R = usr + R.sensor_mode() + if("module1") if(istype(usr, /mob/living/silicon/robot)) usr:toggle_module(1) @@ -455,7 +462,85 @@ if("Toggle Gun Mode") usr.client.ToggleGunMode() + + if("AI Core") + if(isAI(usr)) + var/mob/living/silicon/ai/AI = usr + AI.view_core() + + if("Show Camera List") + if(isAI(usr)) + var/mob/living/silicon/ai/AI = usr + var/camera = input(AI) in AI.get_camera_list() + AI.ai_camera_list(camera) + + if("Track With Camera") + if(isAI(usr)) + var/mob/living/silicon/ai/AI = usr + var/target_name = input(AI) in AI.trackable_mobs() + AI.ai_camera_track(target_name) + + if("Toggle Camera Light") + if(isAI(usr)) + var/mob/living/silicon/ai/AI = usr + AI.toggle_camera_light() + + if("Crew Monitoring") + if(isAI(usr)) + var/mob/living/silicon/ai/AI = usr + AI.nano_crew_monitor() + + if("Show Crew Manifest") + if(isAI(usr)) + var/mob/living/silicon/ai/AI = usr + AI.ai_roster() + + if("Show Alerts") + if(isAI(usr)) + var/mob/living/silicon/ai/AI = usr + AI.ai_alerts() + + if("Announcement") + if(isAI(usr)) + var/mob/living/silicon/ai/AI = usr + AI.ai_announcement() + + if("Call Emergency Shuttle") + if(isAI(usr)) + var/mob/living/silicon/ai/AI = usr + AI.ai_call_shuttle() + + if("State Laws") + if(isAI(usr)) + var/mob/living/silicon/ai/AI = usr + AI.checklaws() + + if("PDA - Send Message") + if(isAI(usr)) + var/mob/living/silicon/ai/AI = usr + AI.aiPDA.cmd_send_pdamesg(usr) + + if("PDA - Show Message Log") + if(isAI(usr)) + var/mob/living/silicon/ai/AI = usr + AI.aiPDA.cmd_show_message_log(usr) + + if("Take Image") + if(isAI(usr)) + var/mob/living/silicon/ai/AI = usr + AI.aiCamera.toggle_camera_mode() + + if("View Images") + if(isAI(usr)) + var/mob/living/silicon/ai/AI = usr + AI.aiCamera.viewpictures() + + if("Set Sensor Augmentation") + if(isAI(usr)) + var/mob/living/silicon/ai/AI = usr + AI.sensor_mode() + else return 0 return 1 diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 1b87ddc6..8570fb0b 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -180,6 +180,14 @@ user.put_in_active_hand(src) return +/obj/item/attack_ai(mob/user as mob) + if (istype(src.loc, /obj/item/weapon/robot_module)) + //If the item is part of a cyborg module, equip it + if(!isrobot(user)) return + var/mob/living/silicon/robot/R = user + R.activate_module(src) + R.hud_used.update_robot_modules_display() + // Due to storage type consolidation this should get used more now. // I have cleaned it up a little, but it could probably use more. -Sayu /obj/item/attackby(obj/item/weapon/W as obj, mob/user as mob) diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index c31aebbb..c0c6208e 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -502,13 +502,15 @@ return istype(H.glasses, /obj/item/clothing/glasses/hud/health) else return 0 - else if(istype(M, /mob/living/silicon/robot)) - var/mob/living/silicon/robot/R = M + else if(istype(M, /mob/living/silicon)) + var/mob/living/silicon/R = M switch(hudtype) if("security") - return istype(R.module_state_1, /obj/item/borg/sight/hud/sec) || istype(R.module_state_2, /obj/item/borg/sight/hud/sec) || istype(R.module_state_3, /obj/item/borg/sight/hud/sec) + if(R.sensor_mode == 1) + return 1 if("medical") - return istype(R.module_state_1, /obj/item/borg/sight/hud/med) || istype(R.module_state_2, /obj/item/borg/sight/hud/med) || istype(R.module_state_3, /obj/item/borg/sight/hud/med) + if(R.sensor_mode == 2) + return 1 else return 0 else diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index b4495d47..7ea6ca75 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -724,7 +724,11 @@ var/list/ai_verbs_default = list( else lightNearbyCamera() - +/mob/living/silicon/ai/proc/sensor_mode() + set name = "Set Sensor Augmentation" + set desc = "Augment visual feed with internal sensor overlays." + set category = "AI Commands" + toggle_sensor_mode() // Handled camera lighting, when toggled. // It will get the nearest camera from the eyeobj, lighting it. diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm index 5fe31ac3..11457dee 100644 --- a/code/modules/mob/living/silicon/ai/life.dm +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -172,6 +172,12 @@ src.show_laws() sleep(50) theAPC = null + regular_hud_updates() + switch(src.sensor_mode) + if (SEC_HUD) + process_sec_hud(src,1,src.eyeobj) + if (MED_HUD) + process_med_hud(src,1,src.eyeobj) /mob/living/silicon/ai/updatehealth() if(status_flags & GODMODE) diff --git a/code/modules/mob/living/silicon/ai/nano.dm b/code/modules/mob/living/silicon/ai/nano.dm new file mode 100644 index 00000000..9fab4365 --- /dev/null +++ b/code/modules/mob/living/silicon/ai/nano.dm @@ -0,0 +1,11 @@ +var/obj/nano_module/crew_monitor/crew_monitor + +/mob/living/silicon/ai/proc/init_subsystems() + crew_monitor = new(src) + +/mob/living/silicon/ai/proc/nano_crew_monitor() + set category = "AI Commands" + set name = "Crew Monitor" + if (!crew_monitor) + init_subsystems() + crew_monitor.ui_interact(usr) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/inventory.dm b/code/modules/mob/living/silicon/robot/inventory.dm index 35ce156b..1c310d63 100644 --- a/code/modules/mob/living/silicon/robot/inventory.dm +++ b/code/modules/mob/living/silicon/robot/inventory.dm @@ -5,67 +5,77 @@ /mob/living/silicon/robot/get_active_hand() return module_active + + /*-------TODOOOOOOOOOO--------*/ -/mob/living/silicon/robot/proc/uneq_active() - if(isnull(module_active)) - return - if(module_state_1 == module_active) - if(istype(module_state_1,/obj/item/borg/sight)) - sight_mode &= ~module_state_1:sight_mode - if (client) - client.screen -= module_state_1 - contents -= module_state_1 +/mob/living/silicon/robot/proc/uneq_module(obj/item/O) + if(!O) + return 0 + + if(istype(O,/obj/item/borg/sight)) + var/obj/item/borg/sight/S = O + sight_mode &= ~S.sight_mode + else if(istype(O, /obj/item/device/flashlight)) + var/obj/item/device/flashlight/F = O + if(F.on) + F.on = 0 + F.update_brightness(src) + if(client) + client.screen -= O + contents -= O + if(module) + O.loc = module //Return item to module so it appears in its contents, so it can be taken out again. + + if(module_active == O) module_active = null - module_state_1 = null + if(module_state_1 == O) inv1.icon_state = "inv1" - else if(module_state_2 == module_active) - if(istype(module_state_2,/obj/item/borg/sight)) - sight_mode &= ~module_state_2:sight_mode - if (client) - client.screen -= module_state_2 - contents -= module_state_2 - module_active = null - module_state_2 = null + module_state_1 = null + else if(module_state_2 == O) inv2.icon_state = "inv2" - else if(module_state_3 == module_active) - if(istype(module_state_3,/obj/item/borg/sight)) - sight_mode &= ~module_state_3:sight_mode - if (client) - client.screen -= module_state_3 - contents -= module_state_3 - module_active = null + module_state_2 = null + else if(module_state_3 == O) module_state_3 = null inv3.icon_state = "inv3" - updateicon() + return 1 + +/mob/living/silicon/robot/proc/activate_module(var/obj/item/O) + if(!(locate(O) in src.module.modules) && O != src.module.emag) + return + if(activated(O)) + src << "Already activated" + return + if(!module_state_1) + module_state_1 = O + O.layer = 20 + O.screen_loc = inv1.screen_loc + contents += O + if(istype(module_state_1,/obj/item/borg/sight)) + sight_mode |= module_state_1:sight_mode + else if(!module_state_2) + module_state_2 = O + O.layer = 20 + O.screen_loc = inv2.screen_loc + contents += O + if(istype(module_state_2,/obj/item/borg/sight)) + sight_mode |= module_state_2:sight_mode + else if(!module_state_3) + module_state_3 = O + O.layer = 20 + O.screen_loc = inv3.screen_loc + contents += O + if(istype(module_state_3,/obj/item/borg/sight)) + sight_mode |= module_state_3:sight_mode + else + src << "You need to disable a module first!" + +/mob/living/silicon/robot/proc/uneq_active() + uneq_module(module_active) /mob/living/silicon/robot/proc/uneq_all() - module_active = null - - if(module_state_1) - if(istype(module_state_1,/obj/item/borg/sight)) - sight_mode &= ~module_state_1:sight_mode - if (client) - client.screen -= module_state_1 - contents -= module_state_1 - module_state_1 = null - inv1.icon_state = "inv1" - if(module_state_2) - if(istype(module_state_2,/obj/item/borg/sight)) - sight_mode &= ~module_state_2:sight_mode - if (client) - client.screen -= module_state_2 - contents -= module_state_2 - module_state_2 = null - inv2.icon_state = "inv2" - if(module_state_3) - if(istype(module_state_3,/obj/item/borg/sight)) - sight_mode &= ~module_state_3:sight_mode - if (client) - client.screen -= module_state_3 - contents -= module_state_3 - module_state_3 = null - inv3.icon_state = "inv3" - updateicon() + uneq_module(module_state_1) + uneq_module(module_state_2) + uneq_module(module_state_3) /mob/living/silicon/robot/proc/activated(obj/item/O) if(module_state_1 == O) diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm index 3913577e..18d6294f 100644 --- a/code/modules/mob/living/silicon/robot/life.dm +++ b/code/modules/mob/living/silicon/robot/life.dm @@ -168,7 +168,14 @@ client.images.Remove(hud) var/obj/item/borg/sight/hud/hud = (locate(/obj/item/borg/sight/hud) in src) - if(hud && hud.hud) hud.hud.process_hud(src) + if(hud && hud.hud) + hud.hud.process_hud(src) + else + switch(src.sensor_mode) + if (SEC_HUD) + process_sec_hud(src,1) + if (MED_HUD) + process_med_hud(src,1) if (src.healths) if (src.stat != 2) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index bf1532c0..ffa9d2df 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -18,6 +18,9 @@ var/obj/screen/inv1 = null var/obj/screen/inv2 = null var/obj/screen/inv3 = null + + var/shown_robot_modules = 0 //Used to determine whether they have the module menu shown or not + var/obj/screen/robot_modules_background //3 Modules can be activated at any one time. var/obj/item/weapon/robot_module/module = null @@ -73,6 +76,10 @@ add_language("Robot Talk", 1) + robot_modules_background = new() + robot_modules_background.icon_state = "block" + robot_modules_background.layer = 19 //Objects that appear on screen are on layer 20, UI should be just below it. + ident = rand(1, 999) updatename("Default") updateicon() @@ -425,6 +432,12 @@ updatehealth() return 1 return 0 + +/mob/living/silicon/robot/proc/sensor_mode() + set name = "Set Sensor Augmentation" + set desc = "Augment visual feed with internal sensor overlays." + set category = "Robot Commands" + toggle_sensor_mode() // this function shows information about the malf_ai gameplay type in the status screen /mob/living/silicon/robot/show_malf_ai() diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index ca4fadba..dd7bb964 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -1,3 +1,6 @@ +#define SEC_HUD 1 //Security HUD mode +#define MED_HUD 2 //Medical HUD mode + /mob/living/silicon gender = NEUTER voice_name = "synthesized voice" @@ -11,6 +14,7 @@ var/speak_statement = "states" var/speak_exclamation = "declares" var/speak_query = "queries" + var/sensor_mode = 0 //Determines the current HUD. var/pose //Yes, now AIs can pose too. var/obj/item/device/camera/siliconcam/aiCamera = null //photography var/local_transmit //If set, can only speak to others of the same type within a short range. @@ -204,4 +208,17 @@ flavor_text = copytext(sanitize(input(usr, "Please enter your new flavour text.", "Flavour text", null) as text), 1) /mob/living/silicon/binarycheck() - return 1 \ No newline at end of file + return 1 + +/mob/living/silicon/proc/toggle_sensor_mode() + var/sensor_type = input("Please select sensor type.", "Sensor Integration", null) in list("Security", "Medical","Disable") + switch(sensor_type) + if ("Security") + sensor_mode = SEC_HUD + src << "Security records overlay enabled." + if ("Medical") + sensor_mode = MED_HUD + src << "Life signs monitor overlay enabled." + if ("Disable") + sensor_mode = 0 + src << "Sensor augmentations disabled." diff --git a/icons/mob/screen_ai.dmi b/icons/mob/screen_ai.dmi new file mode 100644 index 0000000000000000000000000000000000000000..ad813aad751431f9eac707d5979d4d4ded54cb4f GIT binary patch literal 2394 zcmV-g38nUlP)004jp0{{R3ySfe*jCC08*s@e+~dWdH_(M0BO?z3>g5Z5C9M%06>5Mb?N|e z3r7HGPylrRZrxV^e*iXS05VfFDZ*Bkpc$|%rO^(7a429RtDI(a9hGDjB5D2jtt`K=rLoM=y z9JjqbX)Dccc{jDf-7Aw67&Z|NOZ@d zrwIXB^yR-SJEIOh% zzZRC8Ke7D@4QvS(z1;dpBT(q=X@hy5psWcli_+0V&^o9kB?w@n7obbX@;Z_@MPdZY0UV5j-_>n&Ju>VP-Rave1mh zEI!ghx+d7nW}+J=sR{DJ=m7*bAEX2g&4bKzizQf3Xg)Nf25vq$YtKzs4_=du335~Z zW7i~S=r2NWPy356%%=V6H^_%K2zKUUEDQrda2bOUXg5|Z|6La?LXRKJ@Nlzyh}5T+7g)&4O}#UD|2 z=r`5xf)Gb72^usJ4}O6cYKc{SF)t=i;E|p`>sORgzo~xbg*qxnFfOlvw8v#pm@3=Z z{qji9U+dS$ir~C{=lM~@H9?diK@|w8#po4Uf~dEvC9T$4zo~u~0oIOM6SQ&C_dzt^ z$%|Sf8o=uD3Q@n-`c3t_Ot7T5CyGmgx=YYFf|?`f8TIOSZn4%l>YhAU5;Prx)<@)% z?_%nMIZoO7ou@(_bZnYfe71*|mlv)FGC|jc zEJ15uqwiIp@K_UU9hDM%etxzu|Gn@8fBgys4NoxnprHgCfG4~Zjv#T=hM@Do*VBw( zH;SJmqi+cshY*j{2dSerK4^pZwdaE=5n~r}1bcdppz%&v5^SbA9fGeNJ=igB^-_-% zNx!bFo+oH1!C91swy!;X9&4?P#$u}HeNYk~WThqO`2FVeI9W-Aa4ygg?CaSm#++M6 zF)KtbT!mPO-+ws$VTBMD1zQxCBEv#U=eibwicdsct(RojsSzeIoW zh54;Mc$1r)Etd|0x&F%2%%w+)&%M*stId4rNV2tlcS^T1Wk)}|pL{04S^X}qOk^Cd z8U5&v{1$>$`K%^5tKV5bc}qu!U}taFW`a=E)@Y4-Qol=^1Lc&UlpiGsp&>_bR=+#> z?L`|1+9DSv82aX~t>63|?0KlllayduI4?#o&ARp8Z!g+FFdA6ys|npM|Dnj_q_jPF z`p_YmN)L-f0~vzQCm7yvJ6;%qyn##w*R_Q%!BD(eG)vGi><~2W9qAC5)(7qTZ*oQu zB7Nu(Oyw`b5GWRdRVO6ZC&TG6aJUDkLbp6HtPsfgOT;eQrx0^FDa* zoLG1Z_eODEZ&d@Lk|}@pgR`x^}7uO<$Yyf zwY!ZO>d0M$+CY)-B5bVRjeXDq>=Nuqp-+s9=43uNtKW?YN_UgVkHrkZY5Qi2XG3su zg{Qb{vZI$d5@kZLXFk~O@7%v8F(ZQR4G1Y_Kf!^14?$xFdZh3t3%!>&KYvgEd8@L@ zz7MqT61?_>`xTTn#`>Gwbe9w`wI^+FaTM#duCIwl;C)O z;QoU4wVVo zZCkh)P20A@!uCLdu6P=K&#$QvVM#D(96*p#*~dH&Bxs-AjIO1GdnpN)LydNymWLV` z2nK*k_?I$@YjKaF9!n7Y3)VzXFk^8N>3O4tM-q%791yw~9?WLK;{Qm3I>xYLsML_) z1@d4;kekh17s1G>?}Ii*4vpf5pxYANBY3!h1;O|LvfEVNCFnnMXda9uIhh{fmi_00 z4>vH>H(@iu!+p>_U{NhcuFMBPg#UYDTNEEXo4NLd`_-2|ZgQ6V56_zIL~y}3;{X5v M07*qoM6N<$f~~w#2><{9 literal 0 HcmV?d00001 From 92226dff35e5a891cccab637de2ea9c5d39956b0 Mon Sep 17 00:00:00 2001 From: jack-fractal Date: Sat, 23 May 2015 00:18:57 -0400 Subject: [PATCH 2/8] Refresh problems and hotkeys Ooohkay, so I added a bit more to this while fixing the issue with the backpack module select screen not refreshing when you stored items. I did a pass over the hotkeys! Hurray! All right. Lets do this: Key X Previously, this hotkey wouldn't start cycling if your first inventory slot wasn't filled. So if you had slots 2 and 3 full, but 1 empty, clicking X would do nothing. Now it works how you'd expect. It cycles if you have something selected, and if you have nothing selected, it selects the first item. Key C This deselects everything, leaving you able to interact with computers and distant AI objects. Previously, to do this you had to click on an empty area of your selected module. It was very awkward. Key V This stores your currently selected item. Key Q Previously this would just tell you that you weren't allowed to drop items as a robot. Now it toggles your inventory open or closed. Key 1,2,3 Previously hitting 1 would activate Help intent, and 4 would activate Harm intent. Robots have only two intent types, making the toggle key F more useful. These now select the respective modules. I also revised how clicking on items in the backpack works. Now, clicking on an item in the module storage, with a tool selected, will hot-swap the item into your current module. Taken together, these changes reduce an enormous amount of unnecessary clicking. --- code/_onclick/cyborg.dm | 10 ++- code/_onclick/hud/screen_objects.dm | 5 +- code/game/objects/items.dm | 4 +- code/modules/mob/living/carbon/carbon.dm | 6 ++ .../mob/living/silicon/robot/inventory.dm | 74 +++++++++++++++---- code/modules/mob/mob_helpers.dm | 59 +++++++++++++++ interface/skin.dmf | 32 ++++++-- 7 files changed, 163 insertions(+), 27 deletions(-) diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm index 5f007bbe..e003b697 100644 --- a/code/_onclick/cyborg.dm +++ b/code/_onclick/cyborg.dm @@ -57,7 +57,10 @@ RestrainedClickOn(A) return */ - + // handle equipping modules + if (A.equip_robot(src)) + return + var/obj/item/W = get_active_hand() // Cyborgs have no range-checking unless there is item use @@ -126,6 +129,9 @@ /atom/proc/attack_robot(mob/user as mob) attack_ai(user) return + +/atom/proc/equip_robot(mob/user as mob) + return /mob/living/silicon/robot/MiddleClickOn(var/atom/A) cycle_modules() @@ -142,6 +148,6 @@ var/locked_door=A.AICtrlClick(src) if (!locked_door) ..(A) - + /mob/living/silicon/robot/AltClickOn(var/atom/A) A.AIAltClick(src) \ No newline at end of file diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 69dcde47..9109d339 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -385,8 +385,9 @@ usr:installed_modules() if("store") - if(issilicon(usr)) - usr:uneq_active() + if(isrobot(usr)) + var/mob/living/silicon/robot/R = usr + R.uneq_active() if("Toggle Sensor Augmentation") if(isrobot(usr)) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 8570fb0b..4821ac8d 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -180,13 +180,15 @@ user.put_in_active_hand(src) return -/obj/item/attack_ai(mob/user as mob) + +/obj/item/equip_robot(mob/user as mob) if (istype(src.loc, /obj/item/weapon/robot_module)) //If the item is part of a cyborg module, equip it if(!isrobot(user)) return var/mob/living/silicon/robot/R = user R.activate_module(src) R.hud_used.update_robot_modules_display() + return TRUE // Due to storage type consolidation this should get used more now. // I have cleaned it up a little, but it could probably use more. -Sayu diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 98964af5..d0fddc9a 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -282,6 +282,12 @@ if(src.throw_icon) src.throw_icon.icon_state = "act_throw_on" +/mob/living/carbon/key_pressed_q() + if(!get_active_hand()) + usr << "\red You have nothing to drop in your hand." + return + return drop_item() + /mob/proc/throw_item(atom/target) return diff --git a/code/modules/mob/living/silicon/robot/inventory.dm b/code/modules/mob/living/silicon/robot/inventory.dm index 1c310d63..afa2d685 100644 --- a/code/modules/mob/living/silicon/robot/inventory.dm +++ b/code/modules/mob/living/silicon/robot/inventory.dm @@ -37,14 +37,21 @@ else if(module_state_3 == O) module_state_3 = null inv3.icon_state = "inv3" + + hud_used.update_robot_modules_display() // update the display + return 1 - + + /mob/living/silicon/robot/proc/activate_module(var/obj/item/O) if(!(locate(O) in src.module.modules) && O != src.module.emag) return if(activated(O)) src << "Already activated" return + var/selected=get_selected_module() // this makes you swap your selected module if you've got one selected + if (selected) + uneq_active() if(!module_state_1) module_state_1 = O O.layer = 20 @@ -68,6 +75,8 @@ sight_mode |= module_state_3:sight_mode else src << "You need to disable a module first!" + if (selected) // replaces your selection if you're swapping + select_module(selected) /mob/living/silicon/robot/proc/uneq_active() uneq_module(module_active) @@ -174,6 +183,11 @@ return return + +/mob/living/silicon/robot/proc/deselect_current_module() //deselect current module + deselect_module(get_selected_module()) + + //toggle_module(module) - Toggles the selection of the module slot specified by "module". /mob/living/silicon/robot/proc/toggle_module(var/module) //Module is 1-3 if(module < 1 || module > 3) return @@ -187,23 +201,51 @@ deselect_module(get_selected_module()) //If we can't do select anything, at least deselect the current module. return +/mob/living/silicon/robot/proc/first_active_module() + for (var/slot=0,slot<=3,slot++) + if (module_active(slot)) + return slot + return 0 + +/mob/living/silicon/robot/proc/next_slot(var/slot) + if (slot >= 3) + return 1 + return slot+1 + //cycle_modules() - Cycles through the list of selected modules. /mob/living/silicon/robot/proc/cycle_modules() var/slot_start = get_selected_module() - if(slot_start) deselect_module(slot_start) //Only deselect if we have a selected slot. - - var/slot_num - if(slot_start == 0) - slot_num = 1 - slot_start = 2 + if(slot_start) + deselect_module(slot_start) //Only deselect if we have a selected slot. + if(!slot_start) // we did not find a module + select_module(first_active_module()) // try to select the first active module else - slot_num = slot_start + 1 - - while(slot_start != slot_num) //If we wrap around without finding any free slots, just give up. - if(module_active(slot_num)) - select_module(slot_num) - return - slot_num++ - if(slot_num > 3) slot_num = 1 //Wrap around. - + var/slot_num = next_slot(slot_start) + while(slot_start != slot_num) //If we wrap around without finding any free slots, just give up. + if(module_active(slot_num)) + select_module(slot_num) + return + slot_num=next_slot(slot_num) return + + +/mob/living/silicon/robot/key_pressed_v() + uneq_active() + +/mob/living/silicon/robot/key_pressed_c() + deselect_current_module() + +/mob/living/silicon/robot/key_pressed_q() + hud_used.toggle_show_robot_modules() + +/mob/living/silicon/robot/key_pressed_1() + return select_module(1) + +/mob/living/silicon/robot/key_pressed_2() + return select_module(2) + +/mob/living/silicon/robot/key_pressed_3() + return select_module(3) + +/mob/living/silicon/robot/key_pressed_4() + return \ No newline at end of file diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 5e183dcc..27ac10e4 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -394,6 +394,65 @@ var/list/intents = list("help","disarm","grab","hurt") if(2) return "grab" else return "hurt" +/mob/proc/key_pressed_c() + return +/mob/proc/key_pressed_q() + return +/mob/proc/key_pressed_v() + return + +/client/verb/key_pressed_c() + set hidden = 1 + set name = "key-pressed-c" + if (mob) + mob:key_pressed_c() + +/client/verb/key_pressed_q() + set hidden = 1 + set name = "key-pressed-q" + if (mob) + mob:key_pressed_q() + +/client/verb/key_pressed_v() + set hidden = 1 + set name = "key-pressed-v" + if (mob) + mob:key_pressed_v() + +/mob/proc/key_pressed_1() + return a_intent_change("help") +/mob/proc/key_pressed_2() + return a_intent_change("disarm") +/mob/proc/key_pressed_3() + return a_intent_change("grab") +/mob/proc/key_pressed_4() + return a_intent_change("hurt") + +/client/verb/key_pressed_1() + set hidden = 1 + set name = "key-pressed-1" + if (mob) + mob:key_pressed_1() + +/client/verb/key_pressed_2() + set hidden = 1 + set name = "key-pressed-2" + if (mob) + mob:key_pressed_2() + +/client/verb/key_pressed_3() + set hidden = 1 + set name = "key-pressed-3" + if (mob) + mob:key_pressed_3() + +/client/verb/key_pressed_4() + set hidden = 1 + set name = "key-pressed-4" + if (mob) + mob:key_pressed_4() + + //change a mob's act-intent. Input the intent as a string such as "help" or use "right"/"left /mob/verb/a_intent_change(input as text) set name = "a-intent" diff --git a/interface/skin.dmf b/interface/skin.dmf index d0a59f86..b71f4dc6 100644 --- a/interface/skin.dmf +++ b/interface/skin.dmf @@ -243,31 +243,43 @@ macro "hotkeymode" is-disabled = false elem name = "1" - command = "a-intent help" + command = "key-pressed-1" is-disabled = false elem name = "CTRL+1" command = "a-intent help" is-disabled = false + elem + name = "SHIFT+1" + command = "shift-1-key-pressed" + is-disabled = false elem name = "2" - command = "a-intent disarm" + command = "key-pressed-2" is-disabled = false elem name = "CTRL+2" command = "a-intent disarm" is-disabled = false + elem + name = "SHIFT+2" + command = "shift-2-key-pressed" + is-disabled = false elem name = "3" - command = "a-intent grab" + command = "key-pressed-3" is-disabled = false elem name = "CTRL+3" command = "a-intent grab" is-disabled = false + elem + name = "SHIFT+3" + command = "shift-3-key-pressed" + is-disabled = false elem name = "4" - command = "a-intent hurt" + command = "key-pressed-4" is-disabled = false elem name = "CTRL+4" @@ -281,6 +293,10 @@ macro "hotkeymode" name = "CTRL+A+REP" command = ".west" is-disabled = false + elem + name = "C" + command = "key-pressed-c" + is-disabled = false elem name = "D+REP" command = ".east" @@ -323,11 +339,11 @@ macro "hotkeymode" is-disabled = false elem name = "Q" - command = ".northwest" + command = "key-pressed-q" is-disabled = false elem name = "CTRL+Q" - command = ".northwest" + command = "key-pressed-q" is-disabled = false elem name = "R" @@ -349,6 +365,10 @@ macro "hotkeymode" name = "T" command = "say" is-disabled = false + elem "Toggle Module" + name = "V" + command = "key-pressed-v" + is-disabled = false elem "w_key" name = "W+REP" command = ".north" From 87e76d6204bcd20e7ae6beb90c11e65e1e286233 Mon Sep 17 00:00:00 2001 From: jack-fractal Date: Sat, 23 May 2015 16:41:19 -0400 Subject: [PATCH 3/8] Removing the now unused hud module objects The new code does not use the module hud objects to modify cyborg vision. --- code/modules/mob/living/silicon/robot/robot_modules.dm | 2 -- 1 file changed, 2 deletions(-) diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 9f4cdb23..bbd67ef5 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -128,7 +128,6 @@ New() src.modules += new /obj/item/device/flashlight(src) src.modules += new /obj/item/device/flash(src) - src.modules += new /obj/item/borg/sight/hud/med(src) src.modules += new /obj/item/device/healthanalyzer(src) src.modules += new /obj/item/device/reagent_scanner/adv(src) src.modules += new /obj/item/roller_holder(src) @@ -237,7 +236,6 @@ New() src.modules += new /obj/item/device/flashlight(src) src.modules += new /obj/item/device/flash(src) - src.modules += new /obj/item/borg/sight/hud/sec(src) src.modules += new /obj/item/weapon/handcuffs/cyborg(src) src.modules += new /obj/item/weapon/melee/baton/loaded(src) src.modules += new /obj/item/weapon/gun/energy/taser/cyborg(src) From 5b123a835b421b43184ec39b94f5273e64c8466e Mon Sep 17 00:00:00 2001 From: jack-fractal Date: Sat, 23 May 2015 18:37:14 -0400 Subject: [PATCH 4/8] Module Refactor (Cameras/Sprites/Sensors) This modifies where sprites, sensors, and camera networks are stored. Rather than being in a function, they are now part of the robot modules. This makes it way easier to extend and modify this junk. Seriously. Object Oriented Programming! This also limits sensor modifications to the correct modules, and makes them a basic part of that module. Picking a security module gives you sec-hud, picking a crisis or surgeon module gives you med-hud. Nobody else gets any huds. Removes the sensor control UI button. --- .gitignore | 3 +- code/_onclick/hud/robot.dm | 9 --- code/modules/mob/living/silicon/robot/life.dm | 14 ++-- .../modules/mob/living/silicon/robot/robot.dm | 79 +++---------------- .../mob/living/silicon/robot/robot_modules.dm | 78 +++++++++++++++--- 5 files changed, 81 insertions(+), 102 deletions(-) diff --git a/.gitignore b/.gitignore index 12d7d356..0e375e08 100644 --- a/.gitignore +++ b/.gitignore @@ -18,8 +18,7 @@ maps/tgstation2_medbayrework_final.dmm Outpost.dmm data/investigate/gravity.html data/investigate/gravity.html -config/admins.txt -config/admin_ranks.txt +config/*.* data/investigate/gravity.html data/investigate/gravity.html data/investigate/gravity.html diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm index e91cfb50..0d178023 100644 --- a/code/_onclick/hud/robot.dm +++ b/code/_onclick/hud/robot.dm @@ -50,15 +50,6 @@ //End of module select -//Sec/Med HUDs - using = new /obj/screen() - using.name = "Toggle Sensor Augmentation" - using.icon = 'icons/mob/screen_ai.dmi' - using.icon_state = "ai_sensor" - using.screen_loc = ui_borg_sensor - using.layer = 20 - adding += using - //Intent using = new /obj/screen() using.name = "act_intent" diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm index 18d6294f..2445aa9a 100644 --- a/code/modules/mob/living/silicon/robot/life.dm +++ b/code/modules/mob/living/silicon/robot/life.dm @@ -167,15 +167,11 @@ if(copytext(hud.icon_state,1,4) == "hud") //ugly, but icon comparison is worse, I believe client.images.Remove(hud) - var/obj/item/borg/sight/hud/hud = (locate(/obj/item/borg/sight/hud) in src) - if(hud && hud.hud) - hud.hud.process_hud(src) - else - switch(src.sensor_mode) - if (SEC_HUD) - process_sec_hud(src,1) - if (MED_HUD) - process_med_hud(src,1) + switch(src.sensor_mode) + if (SEC_HUD) + process_sec_hud(src,1) + if (MED_HUD) + process_med_hud(src,1) if (src.healths) if (src.stat != 2) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index ffa9d2df..5d70a9c8 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -175,103 +175,44 @@ modules+="Combat" modtype = input("Please, select a module!", "Robot", null, null) in modules - var/module_sprites[0] //Used to store the associations between sprite names and sprite index. - if(module) return switch(modtype) if("Standard") module = new /obj/item/weapon/robot_module/standard(src) - module_sprites["Basic"] = "robot_old" - module_sprites["Android"] = "droid" - module_sprites["Default"] = "robot" - if("Service") module = new /obj/item/weapon/robot_module/butler(src) - module_sprites["Waitress"] = "Service" - module_sprites["Kent"] = "toiletbot" - module_sprites["Bro"] = "Brobot" - module_sprites["Rich"] = "maximillion" - module_sprites["Default"] = "Service2" - if("Clerical") module = new /obj/item/weapon/robot_module/clerical(src) - module_sprites["Waitress"] = "Service" - module_sprites["Kent"] = "toiletbot" - module_sprites["Bro"] = "Brobot" - module_sprites["Rich"] = "maximillion" - module_sprites["Default"] = "Service2" - if("Miner") module = new /obj/item/weapon/robot_module/miner(src) - module.channels = list("Supply" = 1) - if(camera && "Robots" in camera.network) - camera.network.Add("MINE") - module_sprites["Basic"] = "Miner_old" - module_sprites["Advanced Droid"] = "droid-miner" - module_sprites["Treadhead"] = "Miner" - if("Crisis") module = new /obj/item/weapon/robot_module/crisis(src) - module.channels = list("Medical" = 1) - if(camera && "Robots" in camera.network) - camera.network.Add("Medical") - module_sprites["Basic"] = "Medbot" - module_sprites["Standard"] = "surgeon" - module_sprites["Advanced Droid"] = "droid-medical" - module_sprites["Needles"] = "medicalrobot" - if("Surgeon") module = new /obj/item/weapon/robot_module/surgeon(src) - module.channels = list("Medical" = 1) - if(camera && "Robots" in camera.network) - camera.network.Add("Medical") - - module_sprites["Basic"] = "Medbot" - module_sprites["Standard"] = "surgeon" - module_sprites["Advanced Droid"] = "droid-medical" - module_sprites["Needles"] = "medicalrobot" - if("Security") module = new /obj/item/weapon/robot_module/security(src) - module.channels = list("Security" = 1) - module_sprites["Basic"] = "secborg" - module_sprites["Red Knight"] = "Security" - module_sprites["Black Knight"] = "securityrobot" - module_sprites["Bloodhound"] = "bloodhound" - if("Engineering") module = new /obj/item/weapon/robot_module/engineering(src) - module.channels = list("Engineering" = 1) - if(camera && "Robots" in camera.network) - camera.network.Add("Engineering") - module_sprites["Basic"] = "Engineering" - module_sprites["Antique"] = "engineerrobot" - module_sprites["Landmate"] = "landmate" - if("Construction") module = new /obj/item/weapon/robot_module/construction(src) - module.channels = list("Engineering" = 1) - if(camera && "Robots" in camera.network) - camera.network.Add("Engineering") - module_sprites["Basic"] = "Engineering" - module_sprites["Antique"] = "engineerrobot" - module_sprites["Landmate"] = "landmate" - if("Janitor") module = new /obj/item/weapon/robot_module/janitor(src) - module_sprites["Basic"] = "JanBot2" - module_sprites["Mopbot"] = "janitorrobot" - module_sprites["Mop Gear Rex"] = "mopgearrex" - if("Combat") module = new /obj/item/weapon/robot_module/combat(src) - module_sprites["Combat Android"] = "droid-combat" - module.channels = list("Security" = 1) - //languages + // languages module.add_languages(src) + + // cameras + module.add_to_camera_network(src) + + // sensors + module.add_sensor_modification(src) + + // create sprite list + var/list/module_sprites = module.sprites.Copy() //Custom_sprite check and entry if (custom_sprite == 1) diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index bbd67ef5..e5e529ce 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -6,6 +6,9 @@ item_state = "electronic" flags = FPRINT|TABLEPASS | CONDUCT var/channels = list() + var/camera_network = null + var/sensor_mode = 0 + var/list/sprites = list("Basic"="robot_old") var/list/modules = list() var/obj/item/emag = null var/obj/item/borg/upgrade/jetpack = null @@ -26,11 +29,9 @@ src.modules += new /obj/item/device/flash(src) src.emag = new /obj/item/toy/sword(src) src.emag.name = "Placeholder Emag Item" -// src.jetpack = new /obj/item/toy/sword(src) -// src.jetpack.name = "Placeholder Upgrade Item" return - - + + /obj/item/weapon/robot_module/proc/respawn_consumable(var/mob/living/silicon/robot/R) if(!stacktypes || !stacktypes.len) return @@ -66,9 +67,19 @@ R.add_language("Rootspeak", 0) +/obj/item/weapon/robot_module/proc/add_to_camera_network(var/mob/living/silicon/robot/R) + if (camera_network) + if(R.camera && "Robots" in R.camera.network) + R.camera.network.Add(camera_network) + + +/obj/item/weapon/robot_module/proc/add_sensor_modification(var/mob/living/silicon/robot/R) + R.sensor_mode=sensor_mode + + /obj/item/weapon/robot_module/standard name = "standard robot module" - + sprites=list("Basic" = "robot_old","Android" = "droid", "Default" = "robot") New() src.modules += new /obj/item/device/flashlight(src) src.modules += new /obj/item/device/flash(src) @@ -82,6 +93,13 @@ /obj/item/weapon/robot_module/surgeon name = "surgeon robot module" + sensor_mode=MED_HUD + channels=list("Medical" = 1) + camera_network="Medical" + sprites=list( "Basic" = "Medbot", + "Standard "= "surgeon", + "Advanced Droid" = "droid-medical", + "Needles" = "medicalrobot") stacktypes = list( /obj/item/stack/medical/advanced/bruise_pack = 5, /obj/item/stack/nanopaste = 5 @@ -119,6 +137,13 @@ /obj/item/weapon/robot_module/crisis name = "crisis robot module" + sensor_mode=MED_HUD + channels=list("Medical" = 1) + camera_network="Medical" + sprites=list( "Basic" = "Medbot", + "Standard "= "surgeon", + "Advanced Droid" = "droid-medical", + "Needles" = "medicalrobot") stacktypes = list( /obj/item/stack/medical/ointment = 5, /obj/item/stack/medical/bruise_pack = 5, @@ -163,7 +188,11 @@ /obj/item/weapon/robot_module/construction name = "construction robot module" - + channels = list("Engineering" = 1) + camera_network="Engineering" + sprites=list( "Basic" = "Engineering", + "Antique" = "engineerrobot", + "Landmate" = "landmate") stacktypes = list( /obj/item/stack/sheet/metal = 50, /obj/item/stack/sheet/plasteel = 10, @@ -184,7 +213,11 @@ /obj/item/weapon/robot_module/engineering name = "engineering robot module" - + channels = list("Engineering" = 1) + camera_network="Engineering" + sprites=list( "Basic" = "Engineering", + "Antique" = "engineerrobot", + "Landmate" = "landmate") stacktypes = list( /obj/item/stack/sheet/metal = 50, /obj/item/stack/sheet/glass = 50, @@ -232,7 +265,12 @@ /obj/item/weapon/robot_module/security name = "security robot module" - + sensor_mode=SEC_HUD + channels=list("Security" = 1) + sprites = list( "Basic" = "secborg", + "Red Knight" = "Security", + "Black Knight" = "securityrobot", + "Bloodhound" = "bloodhound") New() src.modules += new /obj/item/device/flashlight(src) src.modules += new /obj/item/device/flash(src) @@ -260,7 +298,9 @@ /obj/item/weapon/robot_module/janitor name = "janitorial robot module" - + sprites=list( "Basic" = "JanBot2", + "Mopbot" = "janitorrobot", + "Mop Gear Rex" = "mopgearrex" ) New() src.modules += new /obj/item/device/flashlight(src) src.modules += new /obj/item/device/flash(src) @@ -283,7 +323,11 @@ /obj/item/weapon/robot_module/butler name = "service robot module" - + sprites = list( "Waitress" = "Service", + "Kent" = "toiletbot", + "Bro" = "Brobot", + "Rich" = "maximillion", + "Default" = "Service2") New() src.modules += new /obj/item/device/flashlight(src) src.modules += new /obj/item/device/flash(src) @@ -324,7 +368,11 @@ /obj/item/weapon/robot_module/clerical name = "clerical robot module" - + sprites = list( "Waitress" = "Service", + "Kent" = "toiletbot", + "Bro" = "Brobot", + "Rich" = "maximillion", + "Default" = "Service2") New() src.modules += new /obj/item/device/flashlight(src) src.modules += new /obj/item/device/flash(src) @@ -352,7 +400,10 @@ /obj/item/weapon/robot_module/miner name = "miner robot module" - + channels=list("Supply" = 1) + sprites = list( "Basic" = "Miner_old", + "Advanced Droid" = "droid-miner", + "Treadhead" = "Miner") New() src.modules += new /obj/item/device/flashlight(src) src.modules += new /obj/item/device/flash(src) @@ -378,7 +429,8 @@ /obj/item/weapon/robot_module/combat name = "combat robot module" - + channels=list("Security" = 1) + sprites = list("Combat Android" = "droid-combat") New() src.modules += new /obj/item/device/flashlight(src) src.modules += new /obj/item/device/flash(src) From b836e71e9c3dff51b808ed1eaa4992c2a87a215e Mon Sep 17 00:00:00 2001 From: jack-fractal Date: Sat, 23 May 2015 18:39:51 -0400 Subject: [PATCH 5/8] Reverting changes to gitignore Blergh. Didn't mean to change this. --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 0e375e08..12d7d356 100644 --- a/.gitignore +++ b/.gitignore @@ -18,7 +18,8 @@ maps/tgstation2_medbayrework_final.dmm Outpost.dmm data/investigate/gravity.html data/investigate/gravity.html -config/*.* +config/admins.txt +config/admin_ranks.txt data/investigate/gravity.html data/investigate/gravity.html data/investigate/gravity.html From 07973e77dd10d3944dfcd3307c1edb14be63c62d Mon Sep 17 00:00:00 2001 From: jack-fractal Date: Sat, 23 May 2015 22:30:33 -0400 Subject: [PATCH 6/8] Adding modules to Examine Adds modules to examine message for cyborgs. Adds feedback when switching modules for cyborg and close-by mobs. --- .../mob/living/silicon/robot/examine.dm | 4 + .../mob/living/silicon/robot/inventory.dm | 104 +++++++++++++----- 2 files changed, 80 insertions(+), 28 deletions(-) diff --git a/code/modules/mob/living/silicon/robot/examine.dm b/code/modules/mob/living/silicon/robot/examine.dm index 39851507..b9ca25b5 100644 --- a/code/modules/mob/living/silicon/robot/examine.dm +++ b/code/modules/mob/living/silicon/robot/examine.dm @@ -7,6 +7,10 @@ return var/msg = "*---------*\nThis is \icon[src] \a [src][custom_name ? ", [modtype] [braintype]" : ""]!\n" + + msg += "\n" + msg += describe_all_modules() // describe modules + msg += "\n" msg += "" if (src.getBruteLoss()) if (src.getBruteLoss() < 75) diff --git a/code/modules/mob/living/silicon/robot/inventory.dm b/code/modules/mob/living/silicon/robot/inventory.dm index afa2d685..d1b10ccd 100644 --- a/code/modules/mob/living/silicon/robot/inventory.dm +++ b/code/modules/mob/living/silicon/robot/inventory.dm @@ -8,7 +8,7 @@ /*-------TODOOOOOOOOOO--------*/ -/mob/living/silicon/robot/proc/uneq_module(obj/item/O) +/mob/living/silicon/robot/proc/uneq_module(obj/item/O,var/display_tool_transfer=TRUE) if(!O) return 0 @@ -25,7 +25,16 @@ contents -= O if(module) O.loc = module //Return item to module so it appears in its contents, so it can be taken out again. - + + if (!display_tool_transfer) + for(var/mob/M in viewers(src, null)) // show when cyborgs change their modules + if (M == src) + usr << "You retract \icon[O] [O] into your internal tool storage." + else if (M in range(1)) //If someone is standing close enough, they can tell what it is... + M.show_message("[src] retracts \icon[O] [O] into their internal tool storage.") + else //Otherwise they can only see that you've put something back. + M.show_message("[src] retracts a tool into their internal tool storage.") + if(module_active == O) module_active = null if(module_state_1 == O) @@ -42,6 +51,7 @@ return 1 + /mob/living/silicon/robot/proc/activate_module(var/obj/item/O) if(!(locate(O) in src.module.modules) && O != src.module.emag) @@ -51,35 +61,49 @@ return var/selected=get_selected_module() // this makes you swap your selected module if you've got one selected if (selected) - uneq_active() - if(!module_state_1) - module_state_1 = O - O.layer = 20 - O.screen_loc = inv1.screen_loc - contents += O - if(istype(module_state_1,/obj/item/borg/sight)) - sight_mode |= module_state_1:sight_mode - else if(!module_state_2) - module_state_2 = O - O.layer = 20 - O.screen_loc = inv2.screen_loc - contents += O - if(istype(module_state_2,/obj/item/borg/sight)) - sight_mode |= module_state_2:sight_mode - else if(!module_state_3) - module_state_3 = O - O.layer = 20 - O.screen_loc = inv3.screen_loc - contents += O - if(istype(module_state_3,/obj/item/borg/sight)) - sight_mode |= module_state_3:sight_mode - else + for(var/mob/M in viewers(src, null)) // show when cyborgs change their modules + if (M == src) + usr << "You swap \icon[module_active] [module_active] for \icon[O] [O]." + else if (M in range(1)) //If someone is standing close enough, they can tell what it is... + M.show_message("[src] swaps \icon[module_active] [module_active] for \icon[O] [O].") + else //Otherwise they can only see that you've swapped something. + M.show_message("[src] swaps some of their tools.") + uneq_active(TRUE) + + var/target=(selected) ? selected : first_free_module() // find where we're putting this + if (!target) // if there's nowhere to put it just warn them and kick out src << "You need to disable a module first!" + return + + switch (target) + if(1) + module_state_1=O + O.screen_loc = inv1.screen_loc + if(2) + module_state_2=O + O.screen_loc = inv2.screen_loc + if(3) + module_state_3=O + O.screen_loc = inv3.screen_loc + + O.layer = 20 // this bit moves the target object into the robot, and moves it's location on screen + contents += O + if(istype(O,/obj/item/borg/sight)) + sight_mode |= module_state_1:sight_mode + if (selected) // replaces your selection if you're swapping select_module(selected) + else // only do this if we activated a module but weren't swapping + for(var/mob/M in viewers(src, null)) // show when cyborgs change their modules + if (M == src) + usr << "You retrieve \icon[O] [O] from your internal tool storage." + else if (M in range(1)) //If someone is standing close enough, they can tell what it is... + M.show_message("[src] extends \icon[O] [O] from their internal tool storage.") + else //Otherwise they can only see that you've swapped something. + M.show_message("[src] extends a tool.") -/mob/living/silicon/robot/proc/uneq_active() - uneq_module(module_active) +/mob/living/silicon/robot/proc/uneq_active(var/display_tool_transfer=FALSE) + uneq_module(module_active,display_tool_transfer) /mob/living/silicon/robot/proc/uneq_all() uneq_module(module_state_1) @@ -206,6 +230,12 @@ if (module_active(slot)) return slot return 0 + +/mob/living/silicon/robot/proc/first_free_module() + for (var/slot=1,slot<=3,slot++) + if (!module_active(slot)) + return slot + return 0 /mob/living/silicon/robot/proc/next_slot(var/slot) if (slot >= 3) @@ -248,4 +278,22 @@ return select_module(3) /mob/living/silicon/robot/key_pressed_4() - return \ No newline at end of file + return + + +/mob/living/silicon/robot/proc/describe_module(var/slot) + var/list/index_module=list(module_state_1,module_state_2,module_state_3) + var/result = " Hardpoint [slot] holds " + result += (index_module[slot]) ? "\icon[index_module[slot]] [index_module[slot]]." : "nothing." + result += "\n" + return result + + +/mob/living/silicon/robot/proc/describe_all_modules() + var/result="It has three tool hardpoints.\n" + for (var/x = 1; x <=3; x++) + result+=describe_module(x) + var/selected=get_selected_module() + if (selected) + result+="\nThe activity light on hardpoint [selected] is on.\n" + return result From f1d2958af8bae9d0e56c96ada4a47d207da0863a Mon Sep 17 00:00:00 2001 From: jack-fractal Date: Sun, 24 May 2015 03:23:14 -0400 Subject: [PATCH 7/8] Bugfix - Logged off and out of power If you logged out with your backpack open, and then something forced you to remove or unequip a module (like running out of power) you'd get a runtime error when it tried to access the client's hud. --- code/_onclick/hud/robot.dm | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm index 0d178023..913440e7 100644 --- a/code/_onclick/hud/robot.dm +++ b/code/_onclick/hud/robot.dm @@ -171,10 +171,11 @@ update_robot_modules_display() /datum/hud/proc/update_robot_modules_display() - if(!isrobot(mymob)) return - + if(!isrobot(mymob)) + return var/mob/living/silicon/robot/r = mymob - + if (!r.client) // no client? No problem! + return if(r.shown_robot_modules) //Modules display is shown r.client.screen += r.throw_icon //"store" icon From c866ecfb8efac03e8c29b14e30b70950ef11348f Mon Sep 17 00:00:00 2001 From: jack-fractal Date: Tue, 26 May 2015 17:48:59 -0400 Subject: [PATCH 8/8] Adding SmileyDemons revised AI icons --- icons/mob/screen_ai.dmi | Bin 2394 -> 5404 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/icons/mob/screen_ai.dmi b/icons/mob/screen_ai.dmi index ad813aad751431f9eac707d5979d4d4ded54cb4f..ddc08ed4395bfdc4b3ee32183d2604f30649dc0b 100644 GIT binary patch literal 5404 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 M07*qoM6N<$f~~w#2><{9