From dd187c900df152e3dfb4447e50c2b09c6fd03de6 Mon Sep 17 00:00:00 2001 From: Rykka Date: Sun, 10 May 2020 07:29:53 -0400 Subject: [PATCH] Port over Hover Inventory and Body Zone Hover Indicator The body zone selector now indicates which body part you are about to select when hovered over, and the hover inventory indicator basically shows where you are trying to put an item, and then shows an item ghost in red or green, giving visual feedback as to if that item will go in the slot or not. Gifs of this in action: ![https://i.imgur.com/MTi7Kpn.gif](https://i.imgur.com/MTi7Kpn.gif) Body Selection parts. ![https://i.imgur.com/KbLqWKy.gifv](https://i.imgur.com/KbLqWKy.gifv) Inventory Icon Overlays! Credit goes to @ShadowLarkens for original port to Paradise and assistance with port to Virgo. Sending to Polaris ASAP. - A note on `code/game/objects/items/weapons/storage/internal.dm`, VSCode automatically corrected the line endings, hence the massive filediff. The only practical changes are the addition of `disable_warning = 0` --- code/_onclick/hud/human.dm | 3 + code/_onclick/hud/screen_objects.dm | 135 +++++++++---- .../objects/items/weapons/storage/internal.dm | 180 +++++++++--------- code/modules/clothing/clothing.dm | 2 +- code/modules/clothing/gloves/arm_guards.dm | 2 +- code/modules/clothing/gloves/gauntlets.dm | 2 +- code/modules/clothing/masks/monitor.dm | 2 +- code/modules/clothing/shoes/magboots.dm | 2 +- code/modules/clothing/suits/armor.dm | 2 +- .../vore/fluffstuff/custom_clothes_vr.dm | 2 +- 10 files changed, 201 insertions(+), 131 deletions(-) diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index 1258e4ce94..adbee61eb8 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -28,6 +28,7 @@ inv_box.icon = ui_style inv_box.color = ui_color inv_box.alpha = ui_alpha + inv_box.hud = src var/list/slot_data = hud_data.gear[gear_slot] inv_box.name = gear_slot @@ -192,6 +193,7 @@ using.screen_loc = ui_swaphand1 using.color = ui_color using.alpha = ui_alpha + using.hud = src src.adding += using using = new /obj/screen/inventory() @@ -201,6 +203,7 @@ using.screen_loc = ui_swaphand2 using.color = ui_color using.alpha = ui_alpha + using.hud = src src.adding += using if(hud_data.has_resist) diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index e82d3ea5f6..bdf2ed6496 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -31,7 +31,36 @@ /obj/screen/inventory var/slot_id //The indentifier for the slot. It has nothing to do with ID cards. + var/list/object_overlays = list() // Required for inventory/screen overlays. +/obj/screen/inventory/MouseEntered() + ..() + add_overlays() + +/obj/screen/inventory/MouseExited() + ..() + cut_overlay(object_overlays) + object_overlays.Cut() + +/obj/screen/inventory/proc/add_overlays() + var/mob/user = hud.mymob + + if(hud && user && slot_id) + var/obj/item/holding = user.get_active_hand() + + if(!holding || user.get_equipped_item(slot_id)) + return + + var/image/item_overlay = image(holding) + item_overlay.alpha = 92 + + if(!holding.mob_can_equip(user, slot_id, disable_warning = TRUE)) + item_overlay.color = "#ff0000" + else + item_overlay.color = "#00ff00" + + object_overlays += item_overlay + add_overlay(object_overlays) /obj/screen/close name = "close" @@ -102,78 +131,116 @@ icon_state = "zone_sel" screen_loc = ui_zonesel var/selecting = BP_TORSO + var/static/list/hover_overlays_cache = list() + var/hovering_choice + var/mutable_appearance/selecting_appearance /obj/screen/zone_sel/Click(location, control,params) + if(isobserver(usr)) + return + var/list/PL = params2list(params) var/icon_x = text2num(PL["icon-x"]) var/icon_y = text2num(PL["icon-y"]) - var/old_selecting = selecting //We're only going to update_icon() if there's been a change + var/choice = get_zone_at(icon_x, icon_y) + if(!choice) + return 1 + return set_selected_zone(choice, usr) + +/obj/screen/zone_sel/MouseEntered(location, control, params) + MouseMove(location, control, params) + +/obj/screen/zone_sel/MouseMove(location, control, params) + if(isobserver(usr)) + return + + var/list/PL = params2list(params) + var/icon_x = text2num(PL["icon-x"]) + var/icon_y = text2num(PL["icon-y"]) + var/choice = get_zone_at(icon_x, icon_y) + + if(hovering_choice == choice) + return + vis_contents -= hover_overlays_cache[hovering_choice] + hovering_choice = choice + + var/obj/effect/overlay/zone_sel/overlay_object = hover_overlays_cache[choice] + if(!overlay_object) + overlay_object = new + overlay_object.icon_state = "[choice]" + hover_overlays_cache[choice] = overlay_object + vis_contents += overlay_object + + +/obj/effect/overlay/zone_sel + icon = 'icons/mob/zone_sel.dmi' + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + alpha = 128 + anchored = TRUE + layer = LAYER_HUD_ABOVE + plane = PLANE_PLAYER_HUD_ABOVE + +/obj/screen/zone_sel/MouseExited(location, control, params) + if(!isobserver(usr) && hovering_choice) + vis_contents -= hover_overlays_cache[hovering_choice] + hovering_choice = null + +/obj/screen/zone_sel/proc/get_zone_at(icon_x, icon_y) switch(icon_y) if(1 to 3) //Feet switch(icon_x) if(10 to 15) - selecting = BP_R_FOOT + return BP_R_FOOT if(17 to 22) - selecting = BP_L_FOOT - else - return 1 + return BP_L_FOOT if(4 to 9) //Legs switch(icon_x) if(10 to 15) - selecting = BP_R_LEG + return BP_R_LEG if(17 to 22) - selecting = BP_L_LEG - else - return 1 + return BP_L_LEG if(10 to 13) //Hands and groin switch(icon_x) if(8 to 11) - selecting = BP_R_HAND + return BP_R_HAND if(12 to 20) - selecting = BP_GROIN + return BP_GROIN if(21 to 24) - selecting = BP_L_HAND - else - return 1 + return BP_L_HAND if(14 to 22) //Chest and arms to shoulders switch(icon_x) if(8 to 11) - selecting = BP_R_ARM + return BP_R_ARM if(12 to 20) - selecting = BP_TORSO + return BP_TORSO if(21 to 24) - selecting = BP_L_ARM - else - return 1 + return BP_L_ARM if(23 to 30) //Head, but we need to check for eye or mouth if(icon_x in 12 to 20) - selecting = BP_HEAD switch(icon_y) if(23 to 24) if(icon_x in 15 to 17) - selecting = O_MOUTH + return O_MOUTH if(26) //Eyeline, eyes are on 15 and 17 if(icon_x in 14 to 18) - selecting = O_EYES + return O_EYES if(25 to 27) if(icon_x in 15 to 17) - selecting = O_EYES + return O_EYES + return BP_HEAD - if(old_selecting != selecting) - update_icon() - return 1 - -/obj/screen/zone_sel/proc/set_selected_zone(bodypart) - var/old_selecting = selecting - selecting = bodypart - if(old_selecting != selecting) +/obj/screen/zone_sel/proc/set_selected_zone(choice, mob/user) + if(isobserver(user)) + return + if(choice != selecting) + selecting = choice update_icon() /obj/screen/zone_sel/update_icon() - overlays.Cut() - overlays += image('icons/mob/zone_sel.dmi', "[selecting]") - + cut_overlay(selecting_appearance) + selecting_appearance = mutable_appearance('icons/mob/zone_sel.dmi', "[selecting]") + add_overlay(selecting_appearance) /obj/screen/Click(location, control, params) if(!usr) return 1 diff --git a/code/game/objects/items/weapons/storage/internal.dm b/code/game/objects/items/weapons/storage/internal.dm index 498f6aa5d3..00d6f79402 100644 --- a/code/game/objects/items/weapons/storage/internal.dm +++ b/code/game/objects/items/weapons/storage/internal.dm @@ -1,90 +1,90 @@ -//A storage item intended to be used by other items to provide storage functionality. -//Types that use this should consider overriding emp_act() and hear_talk(), unless they shield their contents somehow. -/obj/item/weapon/storage/internal - preserve_item = 1 - var/obj/item/master_item - -/obj/item/weapon/storage/internal/New(obj/item/MI) - master_item = MI - loc = master_item - //name = master_item.name //VOREStation Removal - verbs -= /obj/item/verb/verb_pickup //make sure this is never picked up. - ..() - -/obj/item/weapon/storage/internal/Destroy() - master_item = null - . = ..() - -/obj/item/weapon/storage/internal/attack_hand() - return //make sure this is never picked up - -/obj/item/weapon/storage/internal/mob_can_equip() - return 0 //make sure this is never picked up - -//Helper procs to cleanly implement internal storages - storage items that provide inventory slots for other items. -//These procs are completely optional, it is up to the master item to decide when it's storage get's opened by calling open() -//However they are helpful for allowing the master item to pretend it is a storage item itself. -//If you are using these you will probably want to override attackby() as well. -//See /obj/item/clothing/suit/storage for an example. - -//items that use internal storage have the option of calling this to emulate default storage MouseDrop behaviour. -//returns 1 if the master item's parent's MouseDrop() should be called, 0 otherwise. It's strange, but no other way of -//doing it without the ability to call another proc's parent, really. -/obj/item/weapon/storage/internal/proc/handle_mousedrop(mob/user as mob, obj/over_object as obj) - if (ishuman(user) || issmall(user)) //so monkeys can take off their backpacks -- Urist - - if (istype(user.loc,/obj/mecha)) // stops inventory actions in a mech - return 0 - - if(over_object == user && Adjacent(user)) // this must come before the screen objects only block - src.open(user) - return 0 - - if (!( istype(over_object, /obj/screen) )) - return 1 - - //makes sure master_item is equipped before putting it in hand, so that we can't drag it into our hand from miles away. - //there's got to be a better way of doing this... - if (!(master_item.loc == user) || (master_item.loc && master_item.loc.loc == user)) - return 0 - - if (!( user.restrained() ) && !( user.stat )) - switch(over_object.name) - if("r_hand") - user.unEquip(master_item) - user.put_in_r_hand(master_item) - if("l_hand") - user.unEquip(master_item) - user.put_in_l_hand(master_item) - master_item.add_fingerprint(user) - return 0 - return 0 - -//items that use internal storage have the option of calling this to emulate default storage attack_hand behaviour. -//returns 1 if the master item's parent's attack_hand() should be called, 0 otherwise. -//It's strange, but no other way of doing it without the ability to call another proc's parent, really. -/obj/item/weapon/storage/internal/proc/handle_attack_hand(mob/user as mob) - - if(ishuman(user)) - var/mob/living/carbon/human/H = user - if(H.l_store == master_item && !H.get_active_hand()) //Prevents opening if it's in a pocket. - H.put_in_hands(master_item) - H.l_store = null - return 0 - if(H.r_store == master_item && !H.get_active_hand()) - H.put_in_hands(master_item) - H.r_store = null - return 0 - - src.add_fingerprint(user) - if (master_item.loc == user) - src.open(user) - return 0 - - for(var/mob/M in range(1, master_item.loc)) - if (M.s_active == src) - src.close(M) - return 1 - -/obj/item/weapon/storage/internal/Adjacent(var/atom/neighbor) - return master_item.Adjacent(neighbor) +//A storage item intended to be used by other items to provide storage functionality. +//Types that use this should consider overriding emp_act() and hear_talk(), unless they shield their contents somehow. +/obj/item/weapon/storage/internal + preserve_item = 1 + var/obj/item/master_item + +/obj/item/weapon/storage/internal/New(obj/item/MI) + master_item = MI + loc = master_item + //name = master_item.name //VOREStation Removal + verbs -= /obj/item/verb/verb_pickup //make sure this is never picked up. + ..() + +/obj/item/weapon/storage/internal/Destroy() + master_item = null + . = ..() + +/obj/item/weapon/storage/internal/attack_hand() + return //make sure this is never picked up + +/obj/item/weapon/storage/internal/mob_can_equip(M as mob, slot, disable_warning = 0) + return 0 //make sure this is never picked up + +//Helper procs to cleanly implement internal storages - storage items that provide inventory slots for other items. +//These procs are completely optional, it is up to the master item to decide when it's storage get's opened by calling open() +//However they are helpful for allowing the master item to pretend it is a storage item itself. +//If you are using these you will probably want to override attackby() as well. +//See /obj/item/clothing/suit/storage for an example. + +//items that use internal storage have the option of calling this to emulate default storage MouseDrop behaviour. +//returns 1 if the master item's parent's MouseDrop() should be called, 0 otherwise. It's strange, but no other way of +//doing it without the ability to call another proc's parent, really. +/obj/item/weapon/storage/internal/proc/handle_mousedrop(mob/user as mob, obj/over_object as obj) + if (ishuman(user) || issmall(user)) //so monkeys can take off their backpacks -- Urist + + if (istype(user.loc,/obj/mecha)) // stops inventory actions in a mech + return 0 + + if(over_object == user && Adjacent(user)) // this must come before the screen objects only block + src.open(user) + return 0 + + if (!( istype(over_object, /obj/screen) )) + return 1 + + //makes sure master_item is equipped before putting it in hand, so that we can't drag it into our hand from miles away. + //there's got to be a better way of doing this... + if (!(master_item.loc == user) || (master_item.loc && master_item.loc.loc == user)) + return 0 + + if (!( user.restrained() ) && !( user.stat )) + switch(over_object.name) + if("r_hand") + user.unEquip(master_item) + user.put_in_r_hand(master_item) + if("l_hand") + user.unEquip(master_item) + user.put_in_l_hand(master_item) + master_item.add_fingerprint(user) + return 0 + return 0 + +//items that use internal storage have the option of calling this to emulate default storage attack_hand behaviour. +//returns 1 if the master item's parent's attack_hand() should be called, 0 otherwise. +//It's strange, but no other way of doing it without the ability to call another proc's parent, really. +/obj/item/weapon/storage/internal/proc/handle_attack_hand(mob/user as mob) + + if(ishuman(user)) + var/mob/living/carbon/human/H = user + if(H.l_store == master_item && !H.get_active_hand()) //Prevents opening if it's in a pocket. + H.put_in_hands(master_item) + H.l_store = null + return 0 + if(H.r_store == master_item && !H.get_active_hand()) + H.put_in_hands(master_item) + H.r_store = null + return 0 + + src.add_fingerprint(user) + if (master_item.loc == user) + src.open(user) + return 0 + + for(var/mob/M in range(1, master_item.loc)) + if (M.s_active == src) + src.close(M) + return 1 + +/obj/item/weapon/storage/internal/Adjacent(var/atom/neighbor) + return master_item.Adjacent(neighbor) diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index eff875ee8d..c6cc7d3db9 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -59,7 +59,7 @@ user.recalculate_vis() //BS12: Species-restricted clothing check. -/obj/item/clothing/mob_can_equip(M as mob, slot) +/obj/item/clothing/mob_can_equip(M as mob, slot, disable_warning = 0) //if we can't equip the item anyway, don't bother with species_restricted (cuts down on spam) if (!..()) diff --git a/code/modules/clothing/gloves/arm_guards.dm b/code/modules/clothing/gloves/arm_guards.dm index 558f855545..791bb0a10b 100644 --- a/code/modules/clothing/gloves/arm_guards.dm +++ b/code/modules/clothing/gloves/arm_guards.dm @@ -7,7 +7,7 @@ w_class = ITEMSIZE_NORMAL drop_sound = 'sound/items/drop/metalshield.ogg' -/obj/item/clothing/gloves/arm_guard/mob_can_equip(var/mob/living/carbon/human/H, slot) +/obj/item/clothing/gloves/arm_guard/mob_can_equip(var/mob/living/carbon/human/H, slot, disable_warning = 0) if(..()) //This will only run if no other problems occured when equiping. if(H.wear_suit) if(H.wear_suit.body_parts_covered & ARMS) diff --git a/code/modules/clothing/gloves/gauntlets.dm b/code/modules/clothing/gloves/gauntlets.dm index 8807fb93ad..eb5d05c909 100644 --- a/code/modules/clothing/gloves/gauntlets.dm +++ b/code/modules/clothing/gloves/gauntlets.dm @@ -14,7 +14,7 @@ punch_force = 5 var/obj/item/clothing/gloves/gloves = null //Undergloves -/obj/item/clothing/gloves/gauntlets/mob_can_equip(mob/user) +/obj/item/clothing/gloves/gauntlets/mob_can_equip(mob/user, slot, disable_warning = 0) var/mob/living/carbon/human/H = user if(H.gloves) gloves = H.gloves diff --git a/code/modules/clothing/masks/monitor.dm b/code/modules/clothing/masks/monitor.dm index 230f224d09..be337c9067 100644 --- a/code/modules/clothing/masks/monitor.dm +++ b/code/modules/clothing/masks/monitor.dm @@ -33,7 +33,7 @@ canremove = 1 return ..() -/obj/item/clothing/mask/monitor/mob_can_equip(var/mob/living/carbon/human/user, var/slot) +/obj/item/clothing/mask/monitor/mob_can_equip(var/mob/living/carbon/human/user, var/slot, disable_warning = FALSE) if (!..()) return 0 if(istype(user)) diff --git a/code/modules/clothing/shoes/magboots.dm b/code/modules/clothing/shoes/magboots.dm index 57b8a0911a..816c5052fc 100644 --- a/code/modules/clothing/shoes/magboots.dm +++ b/code/modules/clothing/shoes/magboots.dm @@ -42,7 +42,7 @@ user.update_inv_shoes() //so our mob-overlays update user.update_action_buttons() -/obj/item/clothing/shoes/magboots/mob_can_equip(mob/user, slot) +/obj/item/clothing/shoes/magboots/mob_can_equip(mob/user, slot, disable_warning = FALSE) var/mob/living/carbon/human/H = user if(H.shoes) diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index 691f53de5a..3920ddd636 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -520,7 +520,7 @@ |ACCESSORY_SLOT_ARMOR_M) blood_overlay_type = "armor" -/obj/item/clothing/suit/armor/pcarrier/mob_can_equip(var/mob/living/carbon/human/H, slot) +/obj/item/clothing/suit/armor/pcarrier/mob_can_equip(var/mob/living/carbon/human/H, slot, disable_warning = FALSE) if(..()) //This will only run if no other problems occured when equiping. if(H.gloves) if(H.gloves.body_parts_covered & ARMS) diff --git a/code/modules/vore/fluffstuff/custom_clothes_vr.dm b/code/modules/vore/fluffstuff/custom_clothes_vr.dm index a8e3f6f283..9dacba7f82 100644 --- a/code/modules/vore/fluffstuff/custom_clothes_vr.dm +++ b/code/modules/vore/fluffstuff/custom_clothes_vr.dm @@ -1885,7 +1885,7 @@ Departamental Swimsuits, for general use species_restricted = list("exclude", SPECIES_TESHARI) -/obj/item/clothing/under/fluff/slime_skeleton/mob_can_equip(M as mob, slot) +/obj/item/clothing/under/fluff/slime_skeleton/mob_can_equip(M as mob, slot, disable_warning = FALSE) if(!..()) return 0