diff --git a/code/__HELPERS/screen_objs.dm b/code/__HELPERS/screen_objs.dm index 7debecf816f..cb8520225ab 100644 --- a/code/__HELPERS/screen_objs.dm +++ b/code/__HELPERS/screen_objs.dm @@ -101,3 +101,15 @@ /proc/cut_relative_direction(fragment) var/static/regex/regex = regex(@"([A-Z])\w+", "g") return regex.Replace(fragment, "") + +/// Returns a screen_loc format for a tiling screen objects from start and end positions. Start should be bottom left corner, and end top right corner. +/proc/spanning_screen_loc(start_px, start_py, end_px, end_py) + var/starting_tile_x = round(start_px / 32) + start_px -= starting_tile_x * 32 + var/starting_tile_y = round(start_py/ 32) + start_py -= starting_tile_y * 32 + var/ending_tile_x = round(end_px / 32) + end_px -= ending_tile_x * 32 + var/ending_tile_y = round(end_py / 32) + end_py -= ending_tile_y * 32 + return "[starting_tile_x]:[start_px],[starting_tile_y]:[start_py] to [ending_tile_x]:[end_px],[ending_tile_y]:[end_py]" diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 2fc1fe644ee..8cc29740870 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -294,7 +294,8 @@ /atom/movable/screen/close name = "close" plane = ABOVE_HUD_PLANE - icon_state = "backpack_close" + icon = 'icons/hud/screen_midnight.dmi' + icon_state = "storage_close" /atom/movable/screen/close/Initialize(mapload, datum/hud/hud_owner, new_master) . = ..() @@ -439,8 +440,8 @@ /atom/movable/screen/storage name = "storage" - icon_state = "block" - screen_loc = "7,7 to 10,8" + icon = 'icons/hud/screen_midnight.dmi' + icon_state = "storage_cell" plane = HUD_PLANE /atom/movable/screen/storage/Initialize(mapload, datum/hud/hud_owner, new_master) @@ -465,6 +466,27 @@ return TRUE +/atom/movable/screen/storage/corner + name = "storage" + icon_state = "storage_corner_topleft" + +/atom/movable/screen/storage/corner/top_right + icon_state = "storage_corner_topright" + +/atom/movable/screen/storage/corner/bottom_left + icon_state = "storage_corner_bottomleft" + +/atom/movable/screen/storage/corner/bottom_right + icon_state = "storage_corner_bottomright" + +/atom/movable/screen/storage/rowjoin + name = "storage" + icon_state = "storage_rowjoin_left" + alpha = 0 + +/atom/movable/screen/storage/rowjoin/right + icon_state = "storage_rowjoin_right" + /atom/movable/screen/throw_catch name = "throw/catch" icon = 'icons/hud/screen_midnight.dmi' diff --git a/code/datums/storage/storage.dm b/code/datums/storage/storage.dm index ecdb7aeb4d9..e04092481b2 100644 --- a/code/datums/storage/storage.dm +++ b/code/datums/storage/storage.dm @@ -4,6 +4,7 @@ * The parent and real_location variables are both weakrefs, so they must be resolved before they can be used. * If you're looking to create custom storage type behaviors, check ../subtypes */ + /datum/storage /** * A reference to the atom linked to this storage object @@ -22,10 +23,8 @@ /// List of all the mobs currently viewing the contents of this storage. VAR_PRIVATE/list/mob/is_using = list() - /// The storage display screen object. - VAR_PRIVATE/atom/movable/screen/storage/boxes - /// The 'close button' screen object. - VAR_PRIVATE/atom/movable/screen/close/closer + /// Associated list that keeps track of all storage UI datums per person. + VAR_PRIVATE/list/datum/storage_interface/storage_interfaces = null /// Typecache of items that can be inserted into this storage. /// By default, all item types can be inserted (assuming other conditions are met). @@ -131,9 +130,6 @@ qdel(src) return - boxes = new(null, null, src) - closer = new(null, null, src) - set_parent(parent) set_real_location(parent) @@ -141,22 +137,15 @@ src.max_specific_storage = max_specific_storage src.max_total_storage = max_total_storage - orient_to_hud() - /datum/storage/Destroy() parent = null real_location = null for(var/mob/person in is_using) - if(person.active_storage == src) - person.active_storage = null - person.client?.screen -= boxes - person.client?.screen -= closer - - QDEL_NULL(boxes) - QDEL_NULL(closer) + hide_contents(person) is_using.Cut() + QDEL_LAZYLIST(storage_interfaces) return ..() @@ -863,69 +852,6 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) return toreturn -/// Updates the storage UI to fit all objects inside storage. -/datum/storage/proc/orient_to_hud() - var/adjusted_contents = real_location.contents.len - - //Numbered contents display - var/list/datum/numbered_display/numbered_contents - if(numerical_stacking) - numbered_contents = process_numerical_display() - adjusted_contents = numbered_contents.len - //if the ammount of contents reaches some multiplier of the final column (and its not the last slot), let the player view an additional row - var/additional_row = (!(adjusted_contents % screen_max_columns) && adjusted_contents < max_slots) - - var/columns = clamp(max_slots, 1, screen_max_columns) - var/rows = clamp(CEILING(adjusted_contents / columns, 1) + additional_row, 1, screen_max_rows) - - orient_item_boxes(rows, columns, numbered_contents) - -/// Generates the actual UI objects, their location, and alignments whenever we open storage up. -/datum/storage/proc/orient_item_boxes(rows, cols, list/obj/item/numerical_display_contents) - boxes.screen_loc = "[screen_start_x]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y] to [screen_start_x+cols-1]:[screen_pixel_x],[screen_start_y+rows-1]:[screen_pixel_y]" - var/current_x = screen_start_x - var/current_y = screen_start_y - var/turf/our_turf = get_turf(real_location) - - if(islist(numerical_display_contents)) - for(var/type in numerical_display_contents) - var/datum/numbered_display/numberdisplay = numerical_display_contents[type] - - var/obj/item/display_sample = numberdisplay.sample_object - display_sample.mouse_opacity = MOUSE_OPACITY_OPAQUE - display_sample.screen_loc = "[current_x]:[screen_pixel_x],[current_y]:[screen_pixel_y]" - display_sample.maptext = MAPTEXT("[(numberdisplay.number > 1)? "[numberdisplay.number]" : ""]") - SET_PLANE(display_sample, ABOVE_HUD_PLANE, our_turf) - - current_x++ - - if(current_x - screen_start_x >= cols) - current_x = screen_start_x - current_y++ - - if(current_y - screen_start_y >= rows) - break - - else - for(var/obj/item in real_location) - item.mouse_opacity = MOUSE_OPACITY_OPAQUE - item.screen_loc = "[current_x]:[screen_pixel_x],[current_y]:[screen_pixel_y]" - item.maptext = "" - item.plane = ABOVE_HUD_PLANE - SET_PLANE(item, ABOVE_HUD_PLANE, our_turf) - - current_x++ - - if(current_x - screen_start_x >= cols) - current_x = screen_start_x - current_y++ - - if(current_y - screen_start_y >= rows) - break - - closer.screen_loc = "[screen_start_x + cols]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y]" - - /// Signal handler for when we get attacked with secondary click by an item. /datum/storage/proc/on_item_interact_secondary(datum/source, mob/user, atom/weapon) SIGNAL_HANDLER @@ -999,10 +925,10 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) /// Async version of putting something into a mobs hand. -/datum/storage/proc/put_in_hands_async(mob/toshow, obj/item/toremove) - if(!toshow.put_in_hands(toremove)) +/datum/storage/proc/put_in_hands_async(mob/to_show, obj/item/toremove) + if(!to_show.put_in_hands(toremove)) if(!silent) - toremove.balloon_alert(toshow, "fumbled!") + toremove.balloon_alert(to_show, "fumbled!") return TRUE /// Signal handler for whenever a mob walks away with us, close if they can't reach us. @@ -1037,48 +963,55 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) * Show our storage to a mob. * * Arguments - * * mob/toshow - the mob to show the storage to + * * mob/to_show - the mob to show the storage to * * Returns * * FALSE if the show failed * * TRUE otherwise */ -/datum/storage/proc/show_contents(mob/toshow) - if(!toshow.client) +/datum/storage/proc/show_contents(mob/to_show) + if(!to_show.client) return FALSE // You can only inspect hidden contents if you're an observer - if(!isobserver(toshow) && !display_contents) + if(!isobserver(to_show) && !display_contents) return FALSE - if(toshow.active_storage != src && (toshow.stat == CONSCIOUS)) + if(to_show.active_storage != src && (to_show.stat == CONSCIOUS)) for(var/obj/item/thing in real_location) - if(thing.on_found(toshow)) - toshow.active_storage.hide_contents(toshow) + if(thing.on_found(to_show)) + to_show.active_storage.hide_contents(to_show) - if(toshow.active_storage) - toshow.active_storage.hide_contents(toshow) + if(to_show.active_storage) + to_show.active_storage.hide_contents(to_show) - toshow.active_storage = src + to_show.active_storage = src if(ismovable(real_location)) var/atom/movable/movable_loc = real_location movable_loc.become_active_storage(src) - orient_to_hud() + LAZYINITLIST(storage_interfaces) - is_using |= toshow + var/ui_style = ui_style2icon(to_show.client?.prefs?.read_preference(/datum/preference/choiced/ui_style)) + + if (isnull(storage_interfaces[to_show])) + storage_interfaces[to_show] = new /datum/storage_interface(ui_style, src) + + orient_storage() + + is_using |= to_show + + to_show.client.screen |= storage_interfaces[to_show].list_ui_elements() + to_show.client.screen |= real_location.contents - toshow.client.screen |= boxes - toshow.client.screen |= closer - toshow.client.screen |= real_location.contents return TRUE /** * Hide our storage from a mob. * * Arguments - * * mob/toshow - the mob to hide the storage from + * * mob/to_hide - the mob to hide the storage from */ /datum/storage/proc/hide_contents(mob/to_hide) if(!to_hide.client) @@ -1090,13 +1023,18 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) var/atom/movable/movable_loc = real_location movable_loc.lose_active_storage(src) + if (isnull(storage_interfaces[to_hide])) + return TRUE + is_using -= to_hide - to_hide.client.screen -= boxes - to_hide.client.screen -= closer + to_hide.client.screen -= storage_interfaces[to_hide].list_ui_elements() to_hide.client.screen -= real_location.contents + QDEL_NULL(storage_interfaces[to_hide]) + return TRUE + /datum/storage/proc/action_trigger(datum/source, datum/action/triggered) SIGNAL_HANDLER @@ -1107,10 +1045,54 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) modeswitch_action = null +/// Updates views of all objects in storage and stretches UI to appropriate size +/datum/storage/proc/orient_storage() + var/adjusted_contents = length(real_location.contents) + var/list/datum/numbered_display/numbered_contents + if(numerical_stacking) + numbered_contents = process_numerical_display() + adjusted_contents = length(numbered_contents) + + //if the ammount of contents reaches some multiplier of the final column (and its not the last slot), let the player view an additional row + var/additional_row = (!(adjusted_contents % screen_max_columns) && adjusted_contents < max_slots) + + var/columns = clamp(max_slots, 1, screen_max_columns) + var/rows = clamp(CEILING(adjusted_contents / columns, 1) + additional_row, 1, screen_max_rows) + + for (var/ui_user in storage_interfaces) + storage_interfaces[ui_user].update_position(screen_start_x, screen_pixel_x, screen_start_y, screen_pixel_y, columns, rows) + + var/current_x = screen_start_x + var/current_y = screen_start_y + var/turf/our_turf = get_turf(real_location) + + var/list/obj/storage_contents = list() + if (islist(numbered_contents)) + for(var/content_type in numbered_contents) + var/datum/numbered_display/numberdisplay = numbered_contents[content_type] + storage_contents[numberdisplay.sample_object] = MAPTEXT("[(numberdisplay.number > 1)? "[numberdisplay.number]" : ""]") + else + for(var/obj/item as anything in real_location) + storage_contents[item] = "" + + for(var/obj/item as anything in storage_contents) + item.mouse_opacity = MOUSE_OPACITY_OPAQUE + item.screen_loc = "[current_x]:[screen_pixel_x],[current_y]:[screen_pixel_y]" + item.maptext = storage_contents[item] + SET_PLANE(item, ABOVE_HUD_PLANE, our_turf) + current_x++ + if(current_x - screen_start_x < columns) + continue + current_x = screen_start_x + + current_y++ + if(current_y - screen_start_y >= rows) + break + /** * Toggles the collectmode of our storage. * - * @param mob/toshow the mob toggling us + * @param mob/to_show the mob toggling us */ /datum/storage/proc/toggle_collection_mode(mob/user) collection_mode = (collection_mode + 1) % 3 diff --git a/code/datums/storage/storage_interface.dm b/code/datums/storage/storage_interface.dm new file mode 100644 index 00000000000..df6bdc9f2d1 --- /dev/null +++ b/code/datums/storage/storage_interface.dm @@ -0,0 +1,67 @@ +/// Datum tracker for storage UI +/datum/storage_interface + /// UI elements for this theme + var/atom/movable/screen/close/closer + var/atom/movable/screen/storage/cells + var/atom/movable/screen/storage/corner/corner_top_left + var/atom/movable/screen/storage/corner/top_right/corner_top_right + var/atom/movable/screen/storage/corner/bottom_left/corner_bottom_left + var/atom/movable/screen/storage/corner/bottom_right/corner_bottom_right + var/atom/movable/screen/storage/rowjoin/rowjoin_left + var/atom/movable/screen/storage/rowjoin/right/rowjoin_right + + /// Storage that owns us + var/datum/storage/parent_storage + +/datum/storage_interface/New(ui_style, parent_storage) + ..() + src.parent_storage = parent_storage + closer = new(null, null, parent_storage) + cells = new(null, null, parent_storage) + corner_top_left = new(null, null, parent_storage) + corner_top_right = new(null, null, parent_storage) + corner_bottom_left = new(null, null, parent_storage) + corner_bottom_right = new(null, null, parent_storage) + rowjoin_left = new(null, null, parent_storage) + rowjoin_right = new(null, null, parent_storage) + for (var/atom/movable/screen/ui_elem as anything in list_ui_elements()) + ui_elem.icon = ui_style + +/// Returns all UI elements under this theme +/datum/storage_interface/proc/list_ui_elements() + return list(cells, corner_top_left, corner_top_right, corner_bottom_left, corner_bottom_right, rowjoin_left, rowjoin_right, closer) + +/datum/storage_interface/Destroy(force) + QDEL_NULL(cells) + QDEL_NULL(corner_top_left) + QDEL_NULL(corner_top_right) + QDEL_NULL(corner_bottom_left) + QDEL_NULL(corner_bottom_right) + QDEL_NULL(rowjoin_left) + QDEL_NULL(rowjoin_right) + parent_storage = null + return ..() + +/// Updates position of all UI elements +/datum/storage_interface/proc/update_position(screen_start_x, screen_pixel_x, screen_start_y, screen_pixel_y, columns, rows) + var/start_pixel_x = screen_start_x * 32 + screen_pixel_x + var/start_pixel_y = screen_start_y * 32 + screen_pixel_y + var/end_pixel_x = start_pixel_x + (columns - 1) * 32 + var/end_pixel_y = start_pixel_y + (rows - 1) * 32 + + cells.screen_loc = spanning_screen_loc(start_pixel_x, start_pixel_y, end_pixel_x, end_pixel_y) + var/left_edge_loc = spanning_screen_loc(start_pixel_x + 32, start_pixel_y, end_pixel_x, end_pixel_y) + var/right_edge_loc = spanning_screen_loc(start_pixel_x, start_pixel_y, end_pixel_x + max(0, (columns - 2)) * 32, end_pixel_y) + corner_top_left.screen_loc = left_edge_loc + corner_top_right.screen_loc = right_edge_loc + corner_bottom_left.screen_loc = left_edge_loc + corner_bottom_right.screen_loc = right_edge_loc + + var/row_loc = spanning_screen_loc(start_pixel_x, start_pixel_y + 27, end_pixel_x, end_pixel_y + 27 + max(0, rows - 2) * 32) + rowjoin_left.screen_loc = row_loc + rowjoin_left.alpha = (rows > 1) * 255 + + rowjoin_right.screen_loc = row_loc + rowjoin_right.alpha = (rows > 1) * 255 + + closer.screen_loc = "[screen_start_x + columns]:[screen_pixel_x - 5],[screen_start_y]:[screen_pixel_y]" diff --git a/icons/hud/screen_clockwork.dmi b/icons/hud/screen_clockwork.dmi index 0923e42e7e4..17e0c92972e 100644 Binary files a/icons/hud/screen_clockwork.dmi and b/icons/hud/screen_clockwork.dmi differ diff --git a/icons/hud/screen_detective.dmi b/icons/hud/screen_detective.dmi index aed6e0d6572..9704ca96f4c 100644 Binary files a/icons/hud/screen_detective.dmi and b/icons/hud/screen_detective.dmi differ diff --git a/icons/hud/screen_glass.dmi b/icons/hud/screen_glass.dmi index 63ad3293921..6b6d9d515c5 100644 Binary files a/icons/hud/screen_glass.dmi and b/icons/hud/screen_glass.dmi differ diff --git a/icons/hud/screen_midnight.dmi b/icons/hud/screen_midnight.dmi index 5483ddf4564..8a6f2e1e8e0 100644 Binary files a/icons/hud/screen_midnight.dmi and b/icons/hud/screen_midnight.dmi differ diff --git a/icons/hud/screen_operative.dmi b/icons/hud/screen_operative.dmi index f2d60d394ac..73afee5b3ca 100644 Binary files a/icons/hud/screen_operative.dmi and b/icons/hud/screen_operative.dmi differ diff --git a/icons/hud/screen_plasmafire.dmi b/icons/hud/screen_plasmafire.dmi index 5423d3855b2..b0b2c7999c9 100644 Binary files a/icons/hud/screen_plasmafire.dmi and b/icons/hud/screen_plasmafire.dmi differ diff --git a/icons/hud/screen_retro.dmi b/icons/hud/screen_retro.dmi index b4252109d68..a0d5abf3be5 100644 Binary files a/icons/hud/screen_retro.dmi and b/icons/hud/screen_retro.dmi differ diff --git a/icons/hud/screen_slimecore.dmi b/icons/hud/screen_slimecore.dmi index a75fe55c378..84a7abec2be 100644 Binary files a/icons/hud/screen_slimecore.dmi and b/icons/hud/screen_slimecore.dmi differ diff --git a/icons/hud/screen_trasenknox.dmi b/icons/hud/screen_trasenknox.dmi index 2569d2a635e..00ad01258a3 100644 Binary files a/icons/hud/screen_trasenknox.dmi and b/icons/hud/screen_trasenknox.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 94849010765..b84349811ad 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1857,6 +1857,7 @@ #include "code\datums\status_effects\debuffs\slime\slime_leech.dm" #include "code\datums\status_effects\debuffs\slime\slimed.dm" #include "code\datums\storage\storage.dm" +#include "code\datums\storage\storage_interface.dm" #include "code\datums\storage\subtypes\backpack.dm" #include "code\datums\storage\subtypes\bag_of_holding.dm" #include "code\datums\storage\subtypes\cards.dm"