From fe28096320bf9d4f966bfd78ddd2bd2c8c6017ba Mon Sep 17 00:00:00 2001 From: Joan Lung Date: Tue, 12 Jul 2016 19:25:00 -0400 Subject: [PATCH] Adds dextrous guardian (#19254) Added dextrous guardians to the code, able to hold and use items and store a single item within themselves. Dextrous guardians do low damage on punches, have medium damage resist, and recalling or leashing will force them to drop any items in their hands. --- code/__DEFINES/clothing.dm | 2 +- code/_onclick/hud/drones.dm | 71 +----------- code/_onclick/hud/generic_dextrous.dm | 14 +++ code/_onclick/hud/guardian.dm | 63 +++++++++- code/game/objects/items/toys.dm | 4 +- .../objects/items/weapons/storage/storage.dm | 2 +- .../objects/structures/beds_chairs/chair.dm | 6 +- code/modules/jobs/access.dm | 6 +- code/modules/mob/inventory.dm | 2 +- code/modules/mob/living/carbon/alien/alien.dm | 2 + code/modules/mob/living/carbon/human/human.dm | 3 + .../simple_animal/friendly/drone/_drone.dm | 22 +--- .../simple_animal/friendly/drone/inventory.dm | 53 +-------- .../living/simple_animal/guardian/guardian.dm | 103 ++++++++++++++++- .../simple_animal/guardian/types/dextrous.dm | 108 ++++++++++++++++++ .../living/simple_animal/hostile/hostile.dm | 2 +- .../mob/living/simple_animal/simple_animal.dm | 34 +++++- code/modules/mob/mob.dm | 5 +- code/modules/paperwork/photocopier.dm | 2 +- .../reagents/reagent_containers/glass.dm | 2 +- .../security_levels/keycard_authentication.dm | 9 +- code/modules/tgui/states/default.dm | 4 +- tgstation.dme | 1 + 23 files changed, 351 insertions(+), 169 deletions(-) create mode 100644 code/modules/mob/living/simple_animal/guardian/types/dextrous.dm diff --git a/code/__DEFINES/clothing.dm b/code/__DEFINES/clothing.dm index dd8ce2bdb96..f5efa04ea62 100644 --- a/code/__DEFINES/clothing.dm +++ b/code/__DEFINES/clothing.dm @@ -33,7 +33,7 @@ #define slot_s_store 17 #define slot_in_backpack 18 #define slot_legcuffed 19 -#define slot_drone_storage 20 +#define slot_generic_dextrous_storage 20 #define slots_amt 20 // Keep this up to date! diff --git a/code/_onclick/hud/drones.dm b/code/_onclick/hud/drones.dm index 631686b089b..4f621dcc72b 100644 --- a/code/_onclick/hud/drones.dm +++ b/code/_onclick/hud/drones.dm @@ -1,42 +1,14 @@ -/datum/hud/drone/New(mob/owner, ui_style = 'icons/mob/screen_midnight.dmi') +/datum/hud/dextrous/drone/New(mob/owner, ui_style = 'icons/mob/screen_midnight.dmi') ..() - var/obj/screen/using var/obj/screen/inventory/inv_box - using = new /obj/screen/drop() - using.icon = ui_style - using.screen_loc = ui_drone_drop - static_inventory += using - - pull_icon = new /obj/screen/pull() - pull_icon.icon = ui_style - pull_icon.update_icon(mymob) - pull_icon.screen_loc = ui_drone_pull - static_inventory += pull_icon - - inv_box = new /obj/screen/inventory/hand() - inv_box.name = "right hand" - inv_box.icon = ui_style - inv_box.icon_state = "hand_r" - inv_box.screen_loc = ui_rhand - inv_box.slot_id = slot_r_hand - static_inventory += inv_box - - inv_box = new /obj/screen/inventory/hand() - inv_box.name = "left hand" - inv_box.icon = ui_style - inv_box.icon_state = "hand_l" - inv_box.screen_loc = ui_lhand - inv_box.slot_id = slot_l_hand - static_inventory += inv_box - inv_box = new /obj/screen/inventory() inv_box.name = "internal storage" inv_box.icon = ui_style inv_box.icon_state = "suit_storage" // inv_box.icon_full = "template" inv_box.screen_loc = ui_drone_storage - inv_box.slot_id = slot_drone_storage + inv_box.slot_id = slot_generic_dextrous_storage static_inventory += inv_box inv_box = new /obj/screen/inventory() @@ -48,26 +20,6 @@ inv_box.slot_id = slot_head static_inventory += inv_box - using = new /obj/screen/swap_hand() - using.icon = ui_style - using.icon_state = "swap_1_m" - using.screen_loc = ui_swaphand1 - static_inventory += using - - using = new /obj/screen/swap_hand() - using.icon = ui_style - using.icon_state = "swap_2" - using.screen_loc = ui_swaphand2 - static_inventory += using - - zone_select = new /obj/screen/zone_sel() - zone_select.icon = ui_style - zone_select.update_icon(mymob) - - using = new /obj/screen/inventory/craft - using.icon = ui_style - static_inventory += using - for(var/obj/screen/inventory/inv in (static_inventory + toggleable_inventory)) if(inv.slot_id) inv.hud = src @@ -75,7 +27,7 @@ inv.update_icon() -/datum/hud/drone/persistant_inventory_update() +/datum/hud/dextrous/drone/persistant_inventory_update() if(!mymob) return var/mob/living/simple_animal/drone/D = mymob @@ -93,19 +45,4 @@ if(D.head) D.head.screen_loc = null - if(hud_version != HUD_STYLE_NOHUD) - if(D.r_hand) - D.r_hand.screen_loc = ui_rhand - D.client.screen += D.r_hand - if(D.l_hand) - D.l_hand.screen_loc = ui_lhand - D.client.screen += D.l_hand - else - if(D.r_hand) - D.r_hand.screen_loc = null - if(D.l_hand) - D.l_hand.screen_loc = null - -/mob/living/simple_animal/drone/create_mob_hud() - if(client && !hud_used) - hud_used = new /datum/hud/drone(src, ui_style2icon(client.prefs.UI_style)) + ..() diff --git a/code/_onclick/hud/generic_dextrous.dm b/code/_onclick/hud/generic_dextrous.dm index fe772d94ca1..2d9ae17bc0b 100644 --- a/code/_onclick/hud/generic_dextrous.dm +++ b/code/_onclick/hud/generic_dextrous.dm @@ -9,6 +9,12 @@ using.screen_loc = ui_drone_drop static_inventory += using + pull_icon = new /obj/screen/pull() + pull_icon.icon = ui_style + pull_icon.update_icon(mymob) + pull_icon.screen_loc = ui_drone_pull + static_inventory += pull_icon + inv_box = new /obj/screen/inventory/hand() inv_box.name = "right hand" inv_box.icon = ui_style @@ -37,6 +43,14 @@ using.screen_loc = ui_swaphand2 static_inventory += using + zone_select = new /obj/screen/zone_sel() + zone_select.icon = ui_style + zone_select.update_icon(mymob) + + using = new /obj/screen/inventory/craft + using.icon = ui_style + static_inventory += using + mymob.client.screen = list() for(var/obj/screen/inventory/inv in (static_inventory + toggleable_inventory)) diff --git a/code/_onclick/hud/guardian.dm b/code/_onclick/hud/guardian.dm index 0a9601385ff..d8b92fba713 100644 --- a/code/_onclick/hud/guardian.dm +++ b/code/_onclick/hud/guardian.dm @@ -29,8 +29,69 @@ /mob/living/simple_animal/hostile/guardian/create_mob_hud() if(client && !hud_used) - hud_used = new /datum/hud/guardian(src) + if(dextrous) + ..() + else + hud_used = new /datum/hud/guardian(src, ui_style2icon(client.prefs.UI_style)) +/datum/hud/dextrous/guardian/New(mob/living/simple_animal/hostile/guardian/owner, ui_style = 'icons/mob/screen_midnight.dmi') //for a dextrous guardian + ..() + var/obj/screen/using + if(istype(owner, /mob/living/simple_animal/hostile/guardian/dextrous)) + var/obj/screen/inventory/inv_box + + inv_box = new /obj/screen/inventory() + inv_box.name = "internal storage" + inv_box.icon = ui_style + inv_box.icon_state = "suit_storage" + inv_box.screen_loc = ui_id + inv_box.slot_id = slot_generic_dextrous_storage + static_inventory += inv_box + + using = new /obj/screen/guardian/Communicate() + using.screen_loc = ui_sstore1 + static_inventory += using + + else + + using = new /obj/screen/guardian/Communicate() + using.screen_loc = ui_id + static_inventory += using + + healths = new /obj/screen/healths/guardian() + infodisplay += healths + + using = new /obj/screen/guardian/Manifest() + using.screen_loc = ui_belt + static_inventory += using + + using = new /obj/screen/guardian/Recall() + using.screen_loc = ui_back + static_inventory += using + + using = new owner.toggle_button_type() + using.screen_loc = ui_storage2 + static_inventory += using + + using = new /obj/screen/guardian/ToggleLight() + using.screen_loc = ui_inventory + static_inventory += using + +/datum/hud/dextrous/guardian/persistant_inventory_update() + if(!mymob) + return + if(istype(mymob, /mob/living/simple_animal/hostile/guardian/dextrous)) + var/mob/living/simple_animal/hostile/guardian/dextrous/D = mymob + + if(hud_shown) + if(D.internal_storage) + D.internal_storage.screen_loc = ui_id + D.client.screen += D.internal_storage + else + if(D.internal_storage) + D.internal_storage.screen_loc = null + + ..() /obj/screen/guardian icon = 'icons/mob/guardian.dmi' diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 55a72521d75..c81e8596a99 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -172,8 +172,8 @@ /obj/item/toy/gun/afterattack(atom/target as mob|obj|turf|area, mob/user, flag) if (flag) return - if (!(istype(usr, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") - usr << "You don't have the dexterity to do this!" + if (!user.IsAdvancedToolUser()) + user << "You don't have the dexterity to do this!" return src.add_fingerprint(user) if (src.bullets < 1) diff --git a/code/game/objects/items/weapons/storage/storage.dm b/code/game/objects/items/weapons/storage/storage.dm index d9cd0e32560..8518b05a5dd 100644 --- a/code/game/objects/items/weapons/storage/storage.dm +++ b/code/game/objects/items/weapons/storage/storage.dm @@ -27,7 +27,7 @@ /obj/item/weapon/storage/MouseDrop(atom/over_object) - if(iscarbon(usr) || isdrone(usr)) //all the check for item manipulation are in other places, you can safely open any storages as anything and its not buggy, i checked + if(ismob(usr)) //all the check for item manipulation are in other places, you can safely open any storages as anything and its not buggy, i checked var/mob/M = usr if(!over_object) diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm index 0a4901985d6..395b9b05dae 100644 --- a/code/game/objects/structures/beds_chairs/chair.dm +++ b/code/game/objects/structures/beds_chairs/chair.dm @@ -32,15 +32,12 @@ switch(severity) if(1) qdel(src) - return if(2) if(prob(70)) deconstruct() - return if(3) if(prob(50)) deconstruct() - return /obj/structure/chair/narsie_act() if(prob(20)) @@ -71,7 +68,6 @@ ..() else rotate() - return /obj/structure/chair/proc/handle_rotation(direction) handle_layer() @@ -204,7 +200,7 @@ /obj/structure/chair/MouseDrop(over_object, src_location, over_location) . = ..() if(over_object == usr && Adjacent(usr)) - if(!item_chair || !ishuman(usr) || has_buckled_mobs() || src.flags & NODECONSTRUCT) + if(!item_chair || !usr.can_hold_items() || has_buckled_mobs() || src.flags & NODECONSTRUCT) return if(usr.incapacitated()) usr << "You can't do that right now!" diff --git a/code/modules/jobs/access.dm b/code/modules/jobs/access.dm index c65ff1d68b9..5e59e0da172 100644 --- a/code/modules/jobs/access.dm +++ b/code/modules/jobs/access.dm @@ -114,16 +114,16 @@ else if(istype(M, /mob/living/carbon/human)) var/mob/living/carbon/human/H = M //if they are holding or wearing a card that has access, that works - if(src.check_access(H.get_active_hand()) || src.check_access(H.wear_id)) + if(check_access(H.get_active_hand()) || src.check_access(H.wear_id)) return 1 else if(istype(M, /mob/living/carbon/monkey) || istype(M, /mob/living/carbon/alien/humanoid)) var/mob/living/carbon/george = M //they can only hold things :( - if(src.check_access(george.get_active_hand())) + if(check_access(george.get_active_hand())) return 1 else if(isanimal(M)) var/mob/living/simple_animal/A = M - if(check_access(A.access_card)) + if(check_access(A.get_active_hand()) || check_access(A.access_card)) return 1 return 0 diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index e3e179721fa..1268581a38b 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -247,7 +247,7 @@ S.handle_item_insertion(src) return 1 - S = M.get_item_by_slot(slot_drone_storage) //else we put in whatever is in drone storage + S = M.get_item_by_slot(slot_generic_dextrous_storage) //else we put in whatever is in drone storage if(istype(S) && S.can_be_inserted(src,1)) S.handle_item_insertion(src) diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm index 27fd4d679f6..4a9cddf7c14 100644 --- a/code/modules/mob/living/carbon/alien/alien.dm +++ b/code/modules/mob/living/carbon/alien/alien.dm @@ -228,3 +228,5 @@ Des: Removes all infected images from the alien. if(see_override) see_invisible = see_override +/mob/living/carbon/alien/can_hold_items() + return has_fine_manipulation diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index f11a76d0fc9..ab5600cfa12 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1077,6 +1077,9 @@ /mob/living/carbon/human/is_literate() return 1 +/mob/living/carbon/human/can_hold_items() + return TRUE + /mob/living/carbon/human/update_gravity(has_gravity,override = 0) override = dna.species.override_float ..() diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm index b503cdd2cbe..fac8d25c9db 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm @@ -47,6 +47,8 @@ hud_possible = list(DIAG_STAT_HUD, DIAG_HUD, ANTAG_HUD) unique_name = TRUE faction = list("silicon") + dextrous = TRUE + dextrous_hud_type = /datum/hud/dextrous/drone var/staticChoice = "static" var/list/staticChoices = list("static", "blank", "letter", "animal") var/picked = FALSE //Have we picked our visual appearence (+ colour if applicable) @@ -65,7 +67,6 @@ var/seeStatic = 1 //Whether we see static instead of mobs var/visualAppearence = MAINTDRONE //What we appear as var/hacked = 0 //If we have laws to destroy the station - var/datum/personal_crafting/handcrafting /mob/living/simple_animal/drone/New() . = ..() @@ -76,7 +77,7 @@ if(default_storage) var/obj/item/I = new default_storage(src) - equip_to_slot_or_del(I, slot_drone_storage) + equip_to_slot_or_del(I, slot_generic_dextrous_storage) if(default_hatmask) var/obj/item/I = new default_hatmask(src) equip_to_slot_or_del(I, slot_head) @@ -91,7 +92,6 @@ else verbs -= /mob/living/simple_animal/drone/verb/toggle_statics - handcrafting = new() var/datum/atom_hud/data/diagnostic/diag_hud = huds[DATA_HUD_DIAGNOSTIC] diag_hud.add_to_hud(src) @@ -109,9 +109,6 @@ else holder.icon_state = "hudstat" -/mob/living/simple_animal/drone/OpenCraftingMenu() - handcrafting.ui_interact(src) - /mob/living/simple_animal/drone/Destroy() qdel(access_card) //Otherwise it ends up on the floor! return ..() @@ -128,8 +125,6 @@ /mob/living/simple_animal/drone/death(gibbed) ..(gibbed) - drop_l_hand() - drop_r_hand() if(internal_storage) unEquip(internal_storage) if(head) @@ -197,17 +192,6 @@ msg += "*---------*" user << msg -/mob/living/simple_animal/drone/IsAdvancedToolUser() - return 1 - - -/mob/living/simple_animal/drone/canUseTopic(atom/movable/M, be_close = 0) - if(incapacitated()) - return 0 - if(be_close && !in_range(M, src)) - return 0 - return 1 - /mob/living/simple_animal/drone/assess_threat() //Secbots won't hunt maintenance drones. return -10 diff --git a/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm b/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm index 51bc2316b5b..2d5c1812c49 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm @@ -6,42 +6,6 @@ //Drone hands - - -/mob/living/simple_animal/drone/activate_hand(selhand) - - if(istext(selhand)) - selhand = lowertext(selhand) - - if(selhand == "right" || selhand == "r") - selhand = 0 - if(selhand == "left" || selhand == "l") - selhand = 1 - - if(selhand != src.hand) - swap_hand() - else - mode() - - -/mob/living/simple_animal/drone/swap_hand() - var/obj/item/held_item = get_active_hand() - if(held_item) - if(istype(held_item, /obj/item/weapon/twohanded)) - var/obj/item/weapon/twohanded/T = held_item - if(T.wielded == 1) - usr << "Your other hand is too busy holding the [T.name]." - return - - hand = !hand - if(hud_used && hud_used.inv_slots[slot_l_hand] && hud_used.inv_slots[slot_r_hand]) - var/obj/screen/inventory/hand/H - H = hud_used.inv_slots[slot_l_hand] - H.update_icon() - H = hud_used.inv_slots[slot_r_hand] - H.update_icon() - - /mob/living/simple_animal/drone/unEquip(obj/item/I, force) if(..(I,force)) update_inv_hands() @@ -63,7 +27,7 @@ if(!((I.slot_flags & SLOT_HEAD) || (I.slot_flags & SLOT_MASK))) return 0 return 1 - if(slot_drone_storage) + if(slot_generic_dextrous_storage) if(internal_storage) return 0 return 1 @@ -74,7 +38,7 @@ switch(slot_id) if(slot_head) return head - if(slot_drone_storage) + if(slot_generic_dextrous_storage) return internal_storage ..() @@ -103,7 +67,7 @@ if(slot_head) head = I update_inv_head() - if(slot_drone_storage) + if(slot_generic_dextrous_storage) internal_storage = I update_inv_internal_storage() else @@ -111,15 +75,8 @@ return -/mob/living/simple_animal/drone/stripPanelUnequip(obj/item/what, mob/who, where) - ..(what, who, where, 1) - - -/mob/living/simple_animal/drone/stripPanelEquip(obj/item/what, mob/who, where) - ..(what, who, where, 1) - /mob/living/simple_animal/drone/getBackSlot() - return slot_drone_storage + return slot_generic_dextrous_storage /mob/living/simple_animal/drone/getBeltSlot() - return slot_drone_storage + return slot_generic_dextrous_storage diff --git a/code/modules/mob/living/simple_animal/guardian/guardian.dm b/code/modules/mob/living/simple_animal/guardian/guardian.dm index a1d6748a28e..b907bd6942b 100644 --- a/code/modules/mob/living/simple_animal/guardian/guardian.dm +++ b/code/modules/mob/living/simple_animal/guardian/guardian.dm @@ -1,6 +1,9 @@ var/global/list/parasites = list() //all currently existing/living guardians +#define GUARDIAN_HANDS_LAYER 1 +#define GUARDIAN_TOTAL_LAYERS 1 + /mob/living/simple_animal/hostile/guardian name = "Guardian Spirit" real_name = "Guardian Spirit" @@ -31,6 +34,8 @@ var/global/list/parasites = list() //all currently existing/living guardians melee_damage_upper = 15 butcher_results = list(/obj/item/weapon/ectoplasm = 1) AIStatus = AI_OFF + dextrous_hud_type = /datum/hud/dextrous/guardian //if we're set to dextrous, account for it. + var/list/guardian_overlays[GUARDIAN_TOTAL_LAYERS] var/reset = 0 //if the summoner has reset the guardian already var/cooldown = 0 var/mob/living/summoner @@ -121,6 +126,7 @@ var/global/list/parasites = list() //all currently existing/living guardians med_hud_set_status() if(summoner) if(summoner.stat == DEAD) + forceMove(summoner.loc) src << "Your summoner has died!" visible_message("\The [src] dies along with its user!") summoner.visible_message("[summoner]'s body is completely consumed by the strain of sustaining [src]!") @@ -128,12 +134,12 @@ var/global/list/parasites = list() //all currently existing/living guardians if(!summoner.unEquip(W)) qdel(W) summoner.dust() - ghostize() + death(TRUE) qdel(src) else src << "Your summoner has died!" visible_message("The [src] dies along with its user!") - ghostize() + death(TRUE) qdel(src) snapback() @@ -177,9 +183,12 @@ var/global/list/parasites = list() //all currently existing/living guardians return 1 /mob/living/simple_animal/hostile/guardian/death() + drop_l_hand() + drop_r_hand() ..() - summoner << "Your [name] died somehow!" - summoner.death() + if(summoner) + summoner << "Your [name] died somehow!" + summoner.death() /mob/living/simple_animal/hostile/guardian/update_health_hud() if(summoner && hud_used && hud_used.healths) @@ -221,6 +230,84 @@ var/global/list/parasites = list() //all currently existing/living guardians ghostize() qdel(src) +//HAND HANDLING + +/mob/living/simple_animal/hostile/guardian/equip_to_slot(obj/item/I, slot) + if(!slot) + return FALSE + if(!istype(I)) + return FALSE + + . = TRUE + if(I == l_hand) + l_hand = null + else if(I == r_hand) + r_hand = null + update_inv_hands() + + if(I.pulledby) + I.pulledby.stop_pulling() + + I.screen_loc = null // will get moved if inventory is visible + I.loc = src + I.equipped(src, slot) + I.layer = ABOVE_HUD_LAYER + +/mob/living/simple_animal/hostile/guardian/proc/apply_overlay(cache_index) + var/image/I = guardian_overlays[cache_index] + if(I) + add_overlay(I) + +/mob/living/simple_animal/hostile/guardian/proc/remove_overlay(cache_index) + if(guardian_overlays[cache_index]) + overlays -= guardian_overlays[cache_index] + guardian_overlays[cache_index] = null + +/mob/living/simple_animal/hostile/guardian/proc/update_inv_hands() + remove_overlay(GUARDIAN_HANDS_LAYER) + var/list/hands_overlays = list() + + if(r_hand) + var/r_state = r_hand.item_state + if(!r_state) + r_state = r_hand.icon_state + + var/image/r_hand_image = r_hand.build_worn_icon(state = r_state, default_layer = GUARDIAN_HANDS_LAYER, default_icon_file = r_hand.righthand_file, isinhands = TRUE) + + hands_overlays += r_hand_image + + if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD) + r_hand.layer = ABOVE_HUD_LAYER + r_hand.screen_loc = ui_rhand + client.screen |= r_hand + + if(l_hand) + var/l_state = l_hand.item_state + if(!l_state) + l_state = l_hand.icon_state + + var/image/l_hand_image = l_hand.build_worn_icon(state = l_state, default_layer = GUARDIAN_HANDS_LAYER, default_icon_file = l_hand.lefthand_file, isinhands = TRUE) + + hands_overlays += l_hand_image + + if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD) + l_hand.layer = ABOVE_HUD_LAYER + l_hand.screen_loc = ui_lhand + client.screen |= l_hand + + if(hands_overlays.len) + guardian_overlays[GUARDIAN_HANDS_LAYER] = hands_overlays + apply_overlay(GUARDIAN_HANDS_LAYER) + +/mob/living/simple_animal/hostile/guardian/update_inv_l_hand() + update_inv_hands() + +/mob/living/simple_animal/hostile/guardian/update_inv_r_hand() + update_inv_hands() + +/mob/living/simple_animal/hostile/guardian/regenerate_icons() + update_inv_hands() + //MANIFEST, RECALL, TOGGLE MODE/LIGHT, SHOW TYPE /mob/living/simple_animal/hostile/guardian/proc/Manifest() @@ -380,7 +467,7 @@ var/global/list/parasites = list() //all currently existing/living guardians var/used_message = "All the cards seem to be blank now." var/failure_message = "..And draw a card! It's...blank? Maybe you should try again later." var/ling_failure = "The deck refuses to respond to a souless creature such as you." - var/list/possible_guardians = list("Chaos", "Standard", "Ranged", "Support", "Explosive", "Lightning", "Protector", "Charger", "Assassin") + var/list/possible_guardians = list("Assassin", "Chaos", "Charger", "Explosive", "Lightning", "Protector", "Ranged", "Standard", "Support") var/random = TRUE var/allowmultiple = 0 var/allowling = 1 @@ -449,6 +536,9 @@ var/global/list/parasites = list() //all currently existing/living guardians if("Assassin") pickedtype = /mob/living/simple_animal/hostile/guardian/assassin + if("Dextrous") + pickedtype = /mob/living/simple_animal/hostile/guardian/dextrous + var/list/guardians = user.hasparasites() if(guardians.len && !allowmultiple) user << "You already have a [mob_name]!" //nice try, bucko @@ -493,6 +583,9 @@ var/global/list/parasites = list() //all currently existing/living guardians /obj/item/weapon/guardiancreator/tech/choose random = FALSE +/obj/item/weapon/guardiancreator/tech/choose/dextrous + possible_guardians = list("Assassin", "Chaos", "Charger", "Dextrous", "Explosive", "Lightning", "Protector", "Ranged", "Standard", "Support") + /obj/item/weapon/paper/guardian name = "Holoparasite Guide" icon_state = "paper_words" diff --git a/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm b/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm new file mode 100644 index 00000000000..0d2387ef10b --- /dev/null +++ b/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm @@ -0,0 +1,108 @@ +//Dextrous +/mob/living/simple_animal/hostile/guardian/dextrous + melee_damage_lower = 10 + melee_damage_upper = 10 + damage_coeff = list(BRUTE = 0.75, BURN = 0.75, TOX = 0.75, CLONE = 0.75, STAMINA = 0, OXY = 0.75) + playstyle_string = "As a dextrous type you can hold items, store an item within yourself, and have medium damage resistance, but do low damage on attacks. Recalling and leashing will force you to drop unstored items!" + magic_fluff_string = "..And draw the Drone, a dextrous master of construction and repair." + tech_fluff_string = "Boot sequence complete. Dextrous combat modules loaded. Holoparasite swarm online." + carp_fluff_string = "CARP CARP CARP! You caught one! It can hold stuff in its fins, sort of." + dextrous = 1 + environment_target_typecache = list( + /obj/machinery/door/window, + /obj/structure/window, + /obj/structure/closet, + /obj/structure/table, + /obj/structure/grille, + /obj/structure/rack, + /obj/structure/barricade, + /obj/machinery/camera) //so we can also attack cameras + var/obj/item/internal_storage //what we're storing within ourself + +/mob/living/simple_animal/hostile/guardian/dextrous/death(gibbed) + ..() + if(internal_storage) + unEquip(internal_storage) + +/mob/living/simple_animal/hostile/guardian/dextrous/examine(mob/user) + if(dextrous) + var/msg = "*---------*\nThis is \icon[src] \a [src]!\n" + msg += "[desc]\n" + if(l_hand && !(l_hand.flags&ABSTRACT)) + if(l_hand.blood_DNA) + msg += "It is holding \icon[l_hand] [l_hand.gender==PLURAL?"some":"a"] blood-stained [l_hand.name] in its left hand!\n" + else + msg += "It is holding \icon[l_hand] \a [l_hand] in its left hand.\n" + + if(r_hand && !(r_hand.flags&ABSTRACT)) + if(r_hand.blood_DNA) + msg += "It is holding \icon[r_hand] [r_hand.gender==PLURAL?"some":"a"] blood-stained [r_hand.name] in its right hand!\n" + else + msg += "It is holding \icon[r_hand] \a [r_hand] in its right hand.\n" + + if(internal_storage && !(internal_storage.flags&ABSTRACT)) + if(internal_storage.blood_DNA) + msg += "It is holding \icon[internal_storage] [internal_storage.gender==PLURAL?"some":"a"] blood-stained [internal_storage.name] in its internal storage!\n" + else + msg += "It is holding \icon[internal_storage] \a [internal_storage] in its internal storage.\n" + msg += "*---------*" + user << msg + else + ..() + +/mob/living/simple_animal/hostile/guardian/dextrous/Recall() + if(loc == summoner || cooldown > world.time) + return 0 + drop_l_hand() + drop_r_hand() + return ..() //lose items, then return + +/mob/living/simple_animal/hostile/guardian/dextrous/snapback() + if(summoner && !(get_dist(get_turf(summoner),get_turf(src)) <= range)) + drop_l_hand() + drop_r_hand() + ..() //lose items, then return + +//SLOT HANDLING BULLSHIT FOR INTERNAL STORAGE +/mob/living/simple_animal/hostile/guardian/dextrous/unEquip(obj/item/I, force) + if(..(I,force)) + update_inv_hands() + if(I == internal_storage) + internal_storage = null + update_inv_internal_storage() + return 1 + return 0 + +/mob/living/simple_animal/hostile/guardian/dextrous/can_equip(obj/item/I, slot) + switch(slot) + if(slot_generic_dextrous_storage) + if(internal_storage) + return 0 + return 1 + ..() + +/mob/living/simple_animal/hostile/guardian/dextrous/equip_to_slot(obj/item/I, slot) + if(!..()) + return + + switch(slot) + if(slot_generic_dextrous_storage) + internal_storage = I + update_inv_internal_storage() + else + src << "You are trying to equip this item to an unsupported inventory slot. Report this to a coder!" + +/mob/living/simple_animal/hostile/guardian/dextrous/getBackSlot() + return slot_generic_dextrous_storage + +/mob/living/simple_animal/hostile/guardian/dextrous/getBeltSlot() + return slot_generic_dextrous_storage + +/mob/living/simple_animal/hostile/guardian/dextrous/proc/update_inv_internal_storage() + if(internal_storage && client && hud_used && hud_used.hud_shown) + internal_storage.screen_loc = ui_id + client.screen += internal_storage + +/mob/living/simple_animal/hostile/guardian/dextrous/regenerate_icons() + ..() + update_inv_internal_storage() \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index b0102f3d95f..07a52affb0f 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -234,7 +234,7 @@ /mob/living/simple_animal/hostile/UnarmedAttack(atom/A) target = A - if(dextrous) + if(dextrous && !is_type_in_typecache(A, environment_target_typecache) && !ismob(A)) ..() else AttackingTarget() diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 53187f4e7ec..a917c4551f5 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -78,10 +78,13 @@ var/attacked_sound = "punch" //Played when someone punches the creature var/dextrous = FALSE //If the creature has, and can use, hands + var/dextrous_hud_type = /datum/hud/dextrous + var/datum/personal_crafting/handcrafting /mob/living/simple_animal/New() ..() + handcrafting = new() verbs -= /mob/verb/observe if(!real_name) real_name = name @@ -509,16 +512,25 @@ return 1 return 0 -/mob/living/simple_animal/stripPanelUnequip(obj/item/what, mob/who, where, child_override) - if(!child_override) +/mob/living/simple_animal/canUseTopic(atom/movable/M, be_close = 0, no_dextery = 0) + if(incapacitated()) + return 0 + if(no_dextery || dextrous) + if(be_close && !in_range(M, src)) + return 0 + else src << "You don't have the dexterity to do this!" + return 0 + return 1 + +/mob/living/simple_animal/stripPanelUnequip(obj/item/what, mob/who, where) + if(!canUseTopic(who, TRUE)) return else ..() -/mob/living/simple_animal/stripPanelEquip(obj/item/what, mob/who, where, child_override) - if(!child_override) - src << "You don't have the dexterity to do this!" +/mob/living/simple_animal/stripPanelEquip(obj/item/what, mob/who, where) + if(!canUseTopic(who, TRUE)) return else ..() @@ -584,7 +596,17 @@ //Dextrous simple mobs can use hands! /mob/living/simple_animal/create_mob_hud() if(client && !hud_used && dextrous) - hud_used = new /datum/hud/dextrous(src, ui_style2icon(client.prefs.UI_style)) + hud_used = new dextrous_hud_type(src, ui_style2icon(client.prefs.UI_style)) + +/mob/living/simple_animal/OpenCraftingMenu() + if(dextrous) + handcrafting.ui_interact(src) + +/mob/living/simple_animal/can_hold_items() + return dextrous + +/mob/living/simple_animal/IsAdvancedToolUser() + return dextrous /mob/living/simple_animal/activate_hand(selhand) if(!dextrous) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 65595ed560c..6977e73153f 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -242,7 +242,7 @@ var/next_mob_id = 0 slot_ears, slot_glasses,\ slot_belt, slot_s_store,\ slot_l_store, slot_r_store,\ - slot_drone_storage\ + slot_generic_dextrous_storage\ ) for(var/slot in slot_priority) @@ -938,5 +938,8 @@ var/next_mob_id = 0 /mob/proc/is_literate() return 0 +/mob/proc/can_hold_items() + return FALSE + /mob/proc/get_idcard() return diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm index e924423a847..719cdf539cc 100644 --- a/code/modules/paperwork/photocopier.dm +++ b/code/modules/paperwork/photocopier.dm @@ -151,7 +151,7 @@ temp_img = icon("icons/ass/assfemale.png") else //In case anyone ever makes the generic ass. For now I'll be using male asses. temp_img = icon("icons/ass/assmale.png") - else if(isdrone (ass) || istype(ass,/mob/living/simple_animal/drone)) //Drones are hot + else if(isdrone(ass)) //Drones are hot temp_img = icon("icons/ass/assdrone.png") else break diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm index ed2793afb02..1676c8339e0 100644 --- a/code/modules/reagents/reagent_containers/glass.dm +++ b/code/modules/reagents/reagent_containers/glass.dm @@ -236,7 +236,7 @@ slot_ears, slot_glasses,\ slot_belt, slot_s_store,\ slot_l_store, slot_r_store,\ - slot_drone_storage + slot_generic_dextrous_storage ) /obj/item/weapon/reagent_containers/glass/bucket/attackby(obj/O, mob/user, params) diff --git a/code/modules/security_levels/keycard_authentication.dm b/code/modules/security_levels/keycard_authentication.dm index 46dc22254a0..34be79ef84d 100644 --- a/code/modules/security_levels/keycard_authentication.dm +++ b/code/modules/security_levels/keycard_authentication.dm @@ -43,10 +43,11 @@ var/datum/events/keycard_events = new() /obj/machinery/keycard_auth/ui_status(mob/user) if(isanimal(user)) - user << "You are too primitive to use this device!" - else - return ..() - return UI_CLOSE + var/mob/living/simple_animal/A = user + if(!A.dextrous) + user << "You are too primitive to use this device!" + return UI_CLOSE + return ..() /obj/machinery/keycard_auth/ui_act(action, params) if(..() || waiting || !allowed(usr)) diff --git a/code/modules/tgui/states/default.dm b/code/modules/tgui/states/default.dm index 74f2ad63c2f..38c3f4d196c 100644 --- a/code/modules/tgui/states/default.dm +++ b/code/modules/tgui/states/default.dm @@ -47,10 +47,10 @@ return UI_INTERACTIVE return UI_CLOSE -/mob/living/simple_animal/drone/default_can_use_topic(src_object) +/mob/living/simple_animal/default_can_use_topic(src_object) . = shared_ui_interaction(src_object) if(. > UI_CLOSE) - . = min(., shared_living_ui_distance(src_object)) // Drones can only use things they're near. + . = min(., shared_living_ui_distance(src_object)) //simple animals can only use things they're near. /mob/living/silicon/pai/default_can_use_topic(src_object) // pAIs can only use themselves and the owner's radio. diff --git a/tgstation.dme b/tgstation.dme index c391880b530..1befd361ada 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1452,6 +1452,7 @@ #include "code\modules\mob\living\simple_animal\guardian\guardiannaming.dm" #include "code\modules\mob\living\simple_animal\guardian\types\assassin.dm" #include "code\modules\mob\living\simple_animal\guardian\types\charger.dm" +#include "code\modules\mob\living\simple_animal\guardian\types\dextrous.dm" #include "code\modules\mob\living\simple_animal\guardian\types\explosive.dm" #include "code\modules\mob\living\simple_animal\guardian\types\fire.dm" #include "code\modules\mob\living\simple_animal\guardian\types\lightning.dm"