diff --git a/code/__DEFINES/_click.dm b/code/__DEFINES/_click.dm index 86396a730f0..07d044f8b89 100644 --- a/code/__DEFINES/_click.dm +++ b/code/__DEFINES/_click.dm @@ -14,3 +14,32 @@ #define CTRL_CLICK "ctrl" #define ALT_CLICK "alt" #define SHIFT_CLICK "shift" + +//Cells involved if using a Grid control +#define DRAG_CELL "drag-cell" +#define DROP_CELL "drop-cell" + +//The button used for dragging (only sent for unrelated mouse up/down messages during a drag) +#define DRAG "drag" + +//If the mouse is over a link in maptext, or this event is related to clicking such a link +#define LINK "link" + +//Pixel coordinates relative to the icon's position on screen +#define VIS_X "vis-x" +#define VIS_Y "vis-y" + +//Pixel coordinates within the icon, in the icon's coordinate space +#define ICON_X "icon-x" +#define ICON_Y "icon-y" + +//Pixel coordinates in screen_loc format ("[tile_x]:[pixel_x],[tile_y]:[pixel_y]") +#define SCREEN_LOC "screen-loc" + +//https://secure.byond.com/docs/ref/info.html#/atom/var/mouse_opacity +/// Objects will ignore being clicked on regardless of their transparency (used in parallax, lighting effects, holograms, lasers, etc.) +#define MOUSE_OPACITY_TRANSPARENT 0 +/// Objects will be clicked on if it is the topmost object and the pixel isn't transparent at the position of the mouse (default behavior for 99.99% of game objects) +#define MOUSE_OPACITY_ICON 1 +/// Objects will be always be clicked on regardless of pixel transparency or other objects at that location (used in space vines, megafauna, storage containers) +#define MOUSE_OPACITY_OPAQUE 2 diff --git a/code/__DEFINES/_math.dm b/code/__DEFINES/_math.dm index d7b0946c614..28c03149a60 100644 --- a/code/__DEFINES/_math.dm +++ b/code/__DEFINES/_math.dm @@ -28,6 +28,8 @@ // round() acts like floor(x, 1) by default but can't handle other values #define FLOOR(x, y) ( round((x) / (y)) * (y) ) +#define ROUND_UP(x) ( -round(-(x))) + // Similar to clamp but the bottom rolls around to the top and vice versa. min is inclusive, max is exclusive #define WRAP(val, min, max) clamp(( min == max ? min : (val) - (round(((val) - (min))/((max) - (min))) * ((max) - (min))) ),min,max) diff --git a/code/__DEFINES/action_button_defines.dm b/code/__DEFINES/action_button_defines.dm index 315c1b1af53..ac840dafb9a 100644 --- a/code/__DEFINES/action_button_defines.dm +++ b/code/__DEFINES/action_button_defines.dm @@ -5,3 +5,24 @@ #define AB_CHECK_TURF (1<<4) #define AB_CHECK_HANDS_BLOCKED (1<<5) #define AB_CHECK_IMMOBILE (1<<6) + +#define ACTION_BUTTON_DEFAULT_BACKGROUND "_use_ui_default_background" + + +//Upper left (action buttons) + +#define ui_action_palette "WEST+0:23,NORTH-1:3" +#define ui_action_palette_offset(north_offset) ("WEST+0:23,NORTH-[1+north_offset]:3") + +#define ui_palette_scroll "WEST+1:8,NORTH-6:28" +#define ui_palette_scroll_offset(north_offset) ("WEST+1:8,NORTH-[6+north_offset]:15") +// Defines relating to action button positions + +/// Whatever the base action datum thinks is best +#define SCRN_OBJ_DEFAULT "default" +/// Floating somewhere on the hud, not in any predefined place +#define SCRN_OBJ_FLOATING "floating" +/// In the list of buttons stored at the top of the screen +#define SCRN_OBJ_IN_LIST "list" +/// In the collapseable palette +#define SCRN_OBJ_IN_PALETTE "palette" diff --git a/code/__DEFINES/action_defines.dm b/code/__DEFINES/action_defines.dm new file mode 100644 index 00000000000..726148081d9 --- /dev/null +++ b/code/__DEFINES/action_defines.dm @@ -0,0 +1,6 @@ + +#define UPDATE_BUTTON_NAME (1<<0) +#define UPDATE_BUTTON_ICON (1<<1) +#define UPDATE_BUTTON_BACKGROUND (1<<2) +#define UPDATE_BUTTON_OVERLAY (1<<3) +#define UPDATE_BUTTON_STATUS (1<<4) diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 142b1be96b8..66b7ca87f19 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -219,6 +219,9 @@ ///////////////// +///from base of client/Click(): (atom/target, atom/location, control, params, mob/user) +#define COMSIG_CLIENT_CLICK "atom_client_click" + ///from base of area/Entered(): (/area) #define COMSIG_ENTER_AREA "enter_area" ///from base of area/Exited(): (/area) @@ -924,6 +927,10 @@ #define COMSIG_ACTION_TRIGGER "action_trigger" #define COMPONENT_ACTION_BLOCK_TRIGGER (1<<0) +// Note that this is only defined for actions because this could be a good bit expensive otherwise +/// From base of /atom/movable/screen/movable/action_button/MouseWheel(src, delta_x, delta_y, location, control, params) +#define COMSIG_ACTION_SCROLLED "action_scrolled" + //Xenobio hotkeys ///from slime CtrlClickOn(): (/mob) diff --git a/code/__DEFINES/hud.dm b/code/__DEFINES/hud.dm index e2b9380850c..8b1670845eb 100644 --- a/code/__DEFINES/hud.dm +++ b/code/__DEFINES/hud.dm @@ -70,3 +70,30 @@ #define EXAMINE_HUD_MEDICAL_READ "medical_read" #define EXAMINE_HUD_MEDICAL_WRITE "medical_write" #define EXAMINE_HUD_SKILLS "skills" + +/proc/ui_hand_position(i) + // values based on old hand ui positions (CENTER:-/+16,SOUTH:5) + var/x_off = i % 2 ? 0 : -1 + var/y_off = round((i-1) / 2) + return"CENTER+[x_off]:16,SOUTH+[y_off]:5" + +/proc/ui_equip_position(mob/M) + // values based on old equip ui position (CENTER: +/-16,SOUTH+1:5) + var/y_off = round(1 / 2) + return "CENTER:-16,SOUTH+[y_off+1]:5" + +/proc/ui_swaphand_position(mob/M, which = 1) + // values based on old swaphand ui positions (CENTER: +/-16,SOUTH+1:5) + var/x_off = which == 1 ? -1 : 0 + var/y_off = round(1 / 2) + return "CENTER+[x_off]:16,SOUTH+[y_off+1]:5" + + +/// Takes a string or num view, and converts it to pixel width/height in a list(pixel_width, pixel_height) +/proc/view_to_pixels(view) + if(!view) + return list(0, 0) + var/list/view_info = getviewsize(view) + view_info[1] *= world.icon_size + view_info[2] *= world.icon_size + return view_info diff --git a/code/__DEFINES/misc_defines.dm b/code/__DEFINES/misc_defines.dm index 2d0e6525127..db931f29746 100644 --- a/code/__DEFINES/misc_defines.dm +++ b/code/__DEFINES/misc_defines.dm @@ -412,11 +412,6 @@ #define AREASELECT_CORNERA "corner A" #define AREASELECT_CORNERB "corner B" -//https://secure.byond.com/docs/ref/info.html#/atom/var/mouse_opacity -#define MOUSE_OPACITY_TRANSPARENT 0 -#define MOUSE_OPACITY_ICON 1 -#define MOUSE_OPACITY_OPAQUE 2 - // Defib stats /// Past this much time the patient is unrecoverable (in deciseconds). #define BASE_DEFIB_TIME_LIMIT (300 SECONDS) diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm index 812f8369e23..f6dec8c1b78 100644 --- a/code/__HELPERS/lists.dm +++ b/code/__HELPERS/lists.dm @@ -676,6 +676,7 @@ #define UNSETEMPTY(L) if(L && !L.len) L = null #define LAZYREMOVE(L, I) if(L) { L -= I; if(!L.len) { L = null; } } #define LAZYADD(L, I) if(!L) { L = list(); } L += I; +#define LAZYOR(L, I) if(!L) { L = list(); } L |= I; /// Adds I to L, initializing L if necessary, if I is not already in L #define LAZYDISTINCTADD(L, I) if(!L) { L = list(); } L |= I; #define LAZYACCESS(L, I) (L ? (isnum(I) ? (I > 0 && I <= L.len ? L[I] : null) : L[I]) : null) diff --git a/code/__HELPERS/mob_helpers.dm b/code/__HELPERS/mob_helpers.dm index fef111d3f39..6abb34f3423 100644 --- a/code/__HELPERS/mob_helpers.dm +++ b/code/__HELPERS/mob_helpers.dm @@ -609,10 +609,17 @@ GLOBAL_LIST_EMPTY(do_after_once_tracker) var/totalviewrange = 1 + 2 * view viewX = totalviewrange viewY = totalviewrange - else + else if(istext(view)) var/list/viewrangelist = splittext(view, "x") viewX = text2num(viewrangelist[1]) viewY = text2num(viewrangelist[2]) + else if(islist(view) && length(view) == 2 && isnum(view[1]) && isnum(view[2])) + // better be a list of nums! + viewX = view[1] + viewY = view[2] + else + CRASH("Invalid view type parameter passed to getviewsize: [view]") + return list(viewX, viewY) //Used in chemical_mob_spawn. Generates a random mob based on a given gold_core_spawnable value. diff --git a/code/__HELPERS/screen_objs.dm b/code/__HELPERS/screen_objs.dm new file mode 100644 index 00000000000..aa86b6d5795 --- /dev/null +++ b/code/__HELPERS/screen_objs.dm @@ -0,0 +1,91 @@ +/// Takes a screen loc string in the format +/// "+-left-offset:+-pixel,+-bottom-offset:+-pixel" +/// Where the :pixel is optional, and returns +/// A list in the format (x_offset, y_offset) +/// We require context to get info out of screen locs that contain relative info, so NORTH, SOUTH, etc +/proc/screen_loc_to_offset(screen_loc, view) + if(!screen_loc) + return list(64, 64) + var/list/view_size = view_to_pixels(view) + var/x = 0 + var/y = 0 + // Time to parse for directional relative offsets + if(findtext(screen_loc, "EAST")) // If you're starting from the east, we start from the east too + x += view_size[1] + if(findtext(screen_loc, "WEST")) // HHHHHHHHHHHHHHHHHHHHHH WEST is technically a 1 tile offset from the start. Shoot me please + x += world.icon_size + if(findtext(screen_loc, "NORTH")) + y += view_size[2] + if(findtext(screen_loc, "SOUTH")) + y += world.icon_size + // Cut out everything we just parsed + screen_loc = cut_relative_direction(screen_loc) + + var/list/x_and_y = splittext(screen_loc, ",") + var/list/x_pack = splittext(x_and_y[1], ":") + var/list/y_pack = splittext(x_and_y[2], ":") + x += text2num(x_pack[1]) * world.icon_size + y += text2num(y_pack[1]) * world.icon_size + + if(length(x_pack) > 1) + x += text2num(x_pack[2]) + if(length(y_pack) > 1) + y += text2num(y_pack[2]) + return list(x, y) + +/// Takes a list in the form (x_offset, y_offset) +/// And converts it to a screen loc string +/// Accepts an optional view string/size to force the screen_loc around, so it can't go out of scope +/proc/offset_to_screen_loc(x_offset, y_offset, view = null) + if(view) + var/list/view_bounds = view_to_pixels(view) + x_offset = clamp(x_offset, world.icon_size, view_bounds[1]) + y_offset = clamp(y_offset, world.icon_size, view_bounds[2]) + + // Round with no argument is floor, so we get the non pixel offset here + var/x = round(x_offset / world.icon_size) + var/pixel_x = x_offset % world.icon_size + var/y = round(y_offset / world.icon_size) + var/pixel_y = y_offset % world.icon_size + + var/list/generated_loc = list() + generated_loc += "[x]" + if(pixel_x) + generated_loc += ":[pixel_x]" + generated_loc += ",[y]" + if(pixel_y) + generated_loc += ":[pixel_y]" + return jointext(generated_loc, "") + +/** + * Returns a valid location to place a screen object without overflowing the viewport + * + * * target: The target location as a purely number based screen_loc string "+-left-offset:+-pixel,+-bottom-offset:+-pixel" + * * target_offset: The amount we want to offset the target location by. We explictly don't care about direction here, we will try all 4 + * * view: The view variable of the client we're doing this for. We use this to get the size of the screen + * + * Returns a screen loc representing the valid location +**/ +/proc/get_valid_screen_location(target_loc, target_offset, view) + var/list/offsets = screen_loc_to_offset(target_loc) + var/base_x = offsets[1] + var/base_y = offsets[2] + + var/list/view_size = view_to_pixels(view) + + // Bias to the right, down, left, and then finally up + if(base_x + target_offset < view_size[1]) + return offset_to_screen_loc(base_x + target_offset, base_y, view) + if(base_y - target_offset > world.icon_size) + return offset_to_screen_loc(base_x, base_y - target_offset, view) + if(base_x - target_offset > world.icon_size) + return offset_to_screen_loc(base_x - target_offset, base_y, view) + if(base_y + target_offset < view_size[2]) + return offset_to_screen_loc(base_x, base_y + target_offset, view) + stack_trace("You passed in a scren location {[target_loc]} and offset {[target_offset]} that can't be fit in the viewport Width {[view_size[1]]}, Height {[view_size[2]]}. what did you do lad") + return null // The fuck did you do lad + +/// Takes a screen_loc string and cut out any directions like NORTH or SOUTH +/proc/cut_relative_direction(fragment) + var/static/regex/regex = regex(@"([A-Z])\w+", "g") + return regex.Replace(fragment, "") diff --git a/code/_onclick/hud/action_button.dm b/code/_onclick/hud/action_button.dm index e67eaf0dc82..b78612c0fbd 100644 --- a/code/_onclick/hud/action_button.dm +++ b/code/_onclick/hud/action_button.dm @@ -1,36 +1,104 @@ /atom/movable/screen/movable/action_button desc = "CTRL-Shift click on this button to bind it to a hotkey." - var/datum/action/linked_action - var/actiontooltipstyle = "" screen_loc = null - var/ordered = TRUE + /// The action triggered by this button. + var/datum/action/linked_action + /// The style of tool-tip. + var/actiontooltipstyle = "" + /// The keybind that will trigger this action button. var/datum/keybinding/mob/trigger_action_button/linked_keybind + /// The HUD this action button belongs to + var/datum/hud/our_hud + + /// Where we are currently placed on the hud. SCRN_OBJ_DEFAULT asks the linked action what it thinks + var/location = SCRN_OBJ_DEFAULT + /// A unique bitflag, combined with the name of our linked action this lets us persistently remember any user changes to our position + var/id + /// UID of the last thing we hovered over. Used for managing action button dragging. + var/last_hovered_ref + +/atom/movable/screen/movable/action_button/Destroy() + . = ..() + if(our_hud) + var/mob/viewer = our_hud.mymob + our_hud.hide_action(src) + viewer?.client?.screen -= src + linked_action.viewers -= our_hud + viewer.update_action_buttons() + our_hud = null + linked_action = null + return ..() + +/atom/movable/screen/movable/action_button/proc/can_use(mob/user) + if(!linked_action) + return TRUE + return !isnull(linked_action.viewers[user.hud_used]) + +// Entered and Exited won't fire while you're dragging something, because you're still "holding" it +// Very much byond logic, but I want nice behavior, so we fake it with drag +/atom/movable/screen/movable/action_button/MouseDrag(atom/over_object, src_location, over_location, src_control, over_control, params) + . = ..() + if(!can_use(usr)) + return + + + // We're basically holding a ref here to the last object we were over. + var/atom/last_hovered = locateUID(last_hovered_ref) + if(last_hovered == over_object) + return + else + if(!istype(last_hovered)) + // no current ref, assume it was us. This is our "first go" location + last_hovered = src + var/datum/hud/our_hud = usr.hud_used + our_hud?.generate_landings(src) + // close the tooltips on our button so we don't get stuck with them + + if(last_hovered) + last_hovered.MouseExited(over_location, over_control, params) + closeToolTip(usr) + last_hovered_ref = UID(over_object) + over_object.MouseEntered(over_location, over_control, params) /atom/movable/screen/movable/action_button/MouseDrop(over_object) - if(locked && could_be_click_lag()) // in case something bad happend and game realised we dragged our ability instead of pressing it - Click() - drag_start = 0 + last_hovered_ref = null + if(!can_use(usr)) return - drag_start = 0 - if(locked) - to_chat(usr, "Action button \"[name]\" is locked, unlock it first.") - closeToolTip(usr) + var/datum/hud/our_hud = usr.hud_used + if(over_object == src) + our_hud.hide_landings() return - if((istype(over_object, /atom/movable/screen/movable/action_button) && !istype(over_object, /atom/movable/screen/movable/action_button/hide_toggle))) - var/atom/movable/screen/movable/action_button/B = over_object - var/list/actions = usr.actions - actions.Swap(actions.Find(linked_action), actions.Find(B.linked_action)) - moved = FALSE - ordered = TRUE - B.moved = FALSE - B.ordered = TRUE - closeToolTip(usr) - usr.update_action_buttons() - else if(istype(over_object, /atom/movable/screen/movable/action_button/hide_toggle)) - closeToolTip(usr) - else - closeToolTip(usr) - return ..() + + if(istype(over_object, /atom/movable/screen/action_landing)) + var/atom/movable/screen/action_landing/reserve = over_object + reserve.hit_by(src) + our_hud.hide_landings() + return + + our_hud.hide_landings() + + if(istype(over_object, /atom/movable/screen/button_palette) || istype(over_object, /atom/movable/screen/palette_scroll)) + our_hud.position_action(src, SCRN_OBJ_IN_PALETTE) + return + if(istype(over_object, /atom/movable/screen/movable/action_button)) + var/atom/movable/screen/movable/action_button/button = over_object + our_hud.position_action_relative(src, button) + return + + . = ..() + + our_hud.position_action(src, screen_loc) + +/atom/movable/screen/movable/action_button/MouseWheel(delta_x, delta_y, location, control, params) + . = ..() + SEND_SIGNAL(src, COMSIG_ACTION_SCROLLED, delta_x, delta_y, location, control, params) + +/atom/movable/screen/movable/action_button/proc/load_position() + var/mob/user = our_hud.mymob + if(!user) + return + var/position_info = SCRN_OBJ_DEFAULT + user.hud_used.position_action(src, position_info) /atom/movable/screen/movable/action_button/Click(location, control, params) var/list/modifiers = params2list(params) @@ -41,15 +109,8 @@ return FALSE usr.changeNext_click(1) if(modifiers["shift"]) - if(locked) - to_chat(usr, "Action button \"[name]\" is locked, unlock it first.") - return TRUE - moved = FALSE - usr.update_action_buttons(TRUE) //redraw buttons that are no longer considered "moved" - return TRUE - if(modifiers["ctrl"]) - locked = !locked - to_chat(usr, "Action button \"[name]\" [locked ? "" : "un"]locked.") + var/datum/hud/our_hud = usr.hud_used + our_hud.position_action(src, SCRN_OBJ_DEFAULT) return TRUE if(modifiers["alt"]) AltClick(usr) @@ -57,12 +118,28 @@ if(modifiers["middle"]) linked_action.Trigger(left_click = FALSE) return TRUE + if(modifiers["ctrl"]) + CtrlClick(usr) + return TRUE linked_action.Trigger(TRUE) transform = transform.Scale(0.8, 0.8) alpha = 200 animate(src, transform = matrix(), time = 0.4 SECONDS, alpha = 255) return TRUE + +/** + * This is a silly proc used in hud code code to determine what icon and icon state we should be using + * for hud elements (such as action buttons) that don't have their own icon and icon state set. + * + * It returns a list, which is pretty much just a struct of info + */ +/datum/hud/proc/get_action_buttons_icons() + . = list() + .["bg_icon"] = ui_style2icon(mymob.client?.prefs.UI_style) + .["bg_state"] = "template" + .["bg_state_active"] = "template_active" + /atom/movable/screen/movable/action_button/proc/set_to_keybind(mob/user) var/keybind_to_set_to = uppertext(input(user, "What keybind do you want to set this action button to?") as text) if(keybind_to_set_to) @@ -82,82 +159,21 @@ return linked_action.AltTrigger() /atom/movable/screen/movable/action_button/proc/clean_up_keybinds(mob/owner) - if(linked_keybind) - owner.client.active_keybindings[linked_keybind.binded_to] -= (linked_keybind) - if(!length(owner.client.active_keybindings[linked_keybind.binded_to])) - owner.client.active_keybindings[linked_keybind.binded_to] = null - owner.client.active_keybindings -= linked_keybind.binded_to - QDEL_NULL(linked_keybind) - -//Hide/Show Action Buttons ... Button -/atom/movable/screen/movable/action_button/hide_toggle - name = "Hide Buttons" - desc = "Shift-click any button to reset its position, and Control-click it to lock/unlock its position. Alt-click this button to reset all buttons to their default positions." - icon = 'icons/mob/actions/actions.dmi' - icon_state = "bg_default" - var/hidden = FALSE - -/atom/movable/screen/movable/action_button/hide_toggle/MouseDrop(over_object) - if(istype(over_object, /atom/movable/screen/movable/action_button)) - closeToolTip(usr) - else - closeToolTip(usr) - return ..() - -/atom/movable/screen/movable/action_button/hide_toggle/Click(location, control, params) - var/list/modifiers = params2list(params) - - if(modifiers["alt"]) - AltClick(usr) - return TRUE - - usr.hud_used.action_buttons_hidden = !usr.hud_used.action_buttons_hidden - - hidden = usr.hud_used.action_buttons_hidden - if(hidden) - name = "Show Buttons" - else - name = "Hide Buttons" - update_icon(UPDATE_OVERLAYS) - usr.update_action_buttons() - -/atom/movable/screen/movable/action_button/hide_toggle/AltClick(mob/user) - for(var/V in user.actions) - var/datum/action/A = V - var/atom/movable/screen/movable/action_button/B = A.button - B.moved = FALSE - if(moved) - moved = FALSE - user.update_action_buttons(TRUE) - to_chat(user, "Action button positions have been reset.") - -/atom/movable/screen/movable/action_button/hide_toggle/proc/InitialiseIcon(mob/living/user) - if(isalien(user)) - icon = 'icons/mob/actions/actions.dmi' - icon_state = "bg_alien" - else - icon = initial(icon) - icon_state = "bg_default" - if(user.client) // Apply the client's UI style - icon = ui_style2icon(user.client.prefs.UI_style) - icon_state = "template" - if(user.client) - alpha = user.client.prefs.UI_style_alpha - color = user.client.prefs.UI_style_color - update_icon(UPDATE_OVERLAYS) - -/atom/movable/screen/movable/action_button/hide_toggle/update_overlays() - . = ..() - var/image/img = image(initial(icon), src, hidden ? "show" : "hide") - img.appearance_flags = RESET_COLOR | RESET_ALPHA - . += img + if(!linked_keybind || !owner.client) + return + owner.client.active_keybindings[linked_keybind.binded_to] -= (linked_keybind) + if(!length(owner.client.active_keybindings[linked_keybind.binded_to])) + owner.client.active_keybindings[linked_keybind.binded_to] = null + owner.client.active_keybindings -= linked_keybind.binded_to + QDEL_NULL(linked_keybind) /atom/movable/screen/movable/action_button/MouseEntered(location, control, params) . = ..() - if(!QDELETED(src)) + var/list/modifiers = params2list(params) + if(!QDELETED(src) && !LAZYACCESS(modifiers, DRAG) && !LAZYACCESS(modifiers, LEFT_CLICK)) // tooltips opening on drag prevents things from being dropped onto their actual objects) if(!linked_keybind) openToolTip(usr, src, params, title = name, content = desc, theme = actiontooltipstyle) - else + else if(linked_keybind) var/list/desc_information = list() desc_information += desc desc_information += "This action is currently bound to the [linked_keybind.binded_to] key." @@ -166,11 +182,12 @@ /atom/movable/screen/movable/action_button/MouseExited() closeToolTip(usr) + return ..() -/mob/proc/update_action_buttons_icon() +/mob/proc/update_action_buttons_icon(status_only = FALSE) for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons(status_only) //This is the proc used to update all the action buttons. /mob/proc/update_action_buttons(reload_screen) @@ -180,61 +197,368 @@ if(hud_used.hud_shown != HUD_STYLE_STANDARD) return - var/button_number = 0 + for(var/datum/action/action as anything in actions) + var/atom/movable/screen/movable/action_button/button = action.viewers[hud_used] + action.UpdateButtons() + if(reload_screen) + client.screen += button + client.update_active_keybindings() - if(hud_used.action_buttons_hidden) - for(var/datum/action/A in actions) - A.button.screen_loc = null - if(reload_screen) - client.screen += A.button - else - for(var/datum/action/A in actions) - A.override_location() // If the action has a location override, call it - A.UpdateButtonIcon() - - var/atom/movable/screen/movable/action_button/B = A.button - if(B.ordered) - button_number++ - if(!B.moved) - B.screen_loc = hud_used.ButtonNumberToScreenCoords(button_number) - else - B.screen_loc = B.moved - if(reload_screen) - client.screen += B - - if(!button_number) - hud_used.hide_actions_toggle.screen_loc = null - return - - if(!hud_used.hide_actions_toggle.moved) - hud_used.hide_actions_toggle.screen_loc = hud_used.ButtonNumberToScreenCoords(button_number+1) - else - hud_used.hide_actions_toggle.screen_loc = hud_used.hide_actions_toggle.moved if(reload_screen) - client.screen += hud_used.hide_actions_toggle + hud_used.update_our_owner() + + // This holds the logic for the palette buttons + hud_used.palette_actions.refresh_actions() #define AB_MAX_COLUMNS 10 -/datum/hud/proc/ButtonNumberToScreenCoords(number) // TODO : Make this zero-indexed for readabilty - var/row = round((number - 1)/AB_MAX_COLUMNS) - var/col = ((number - 1)%(AB_MAX_COLUMNS)) + 1 - var/coord_col = "+[col-1]" - var/coord_col_offset = 4 + 2 * col +/atom/movable/screen/button_palette + desc = "Drag buttons to move them.
Shift-click any button to reset it.
Alt-click this to reset all buttons.
Ctrl-click this to get a detailed explanation of how to use this." + icon = 'icons/hud/64x16_actions.dmi' + icon_state = "screen_gen_palette" + screen_loc = ui_action_palette + var/datum/hud/our_hud + var/expanded = FALSE + /// Id of any currently running timers that set our color matrix + var/color_timer_id - var/coord_row = "[row ? -row : "+0"]" +/atom/movable/screen/button_palette/Destroy() + if(our_hud) + our_hud.mymob?.client?.screen -= src + our_hud.toggle_palette = null + our_hud = null + return ..() - return "WEST[coord_col]:[coord_col_offset],NORTH[coord_row]:-6" +/atom/movable/screen/button_palette/Initialize(mapload) + . = ..() + update_appearance() -/datum/hud/proc/SetButtonCoords(atom/movable/screen/button,number) - var/row = round((number-1)/AB_MAX_COLUMNS) - var/col = ((number - 1)%(AB_MAX_COLUMNS)) + 1 - var/x_offset = 32*(col-1) + 4 + 2*col - var/y_offset = -32*(row+1) + 26 +/atom/movable/screen/button_palette/proc/set_hud(datum/hud/our_hud) + src.our_hud = our_hud + refresh_owner() - var/matrix/M = matrix() - M.Translate(x_offset,y_offset) - button.transform = M +/atom/movable/screen/button_palette/update_name(updates) + . = ..() + if(expanded) + name = "Hide Buttons" + else + name = "Show Buttons" + +/atom/movable/screen/button_palette/CtrlClick(mob/user) + if(!istype(user)) + return + + var/list/explanation = list() + + explanation.Insert( + "
The Action Palette [bicon(src)] and You
", + "The Action Palette [bicon(src)] is the new way to hide action buttons. You can hide only some buttons, and quickly bring them up when needed, instead of hiding all of them.", + "To use it, drag action buttons onto it, or onto other buttons already in the palette. You can then click the palette to hide or show it. If you click away from the palette, it will be hidden.", + "If you have more than 9 action buttons, you can use the scroll arrows to see all of the buttons present, and you can always drag buttons out of the palette whenever you want.", + "You can drag action buttons anywhere on the screen, onto other buttons, or onto the little squares that appear when you start dragging them.", + "If you drag a button onto another button, it'll snap onto that other button and form a little group.", + "", // empty space to force another br + "If you need more help, check the wiki or send a mentorhelp." + ) + + to_chat(user, chat_box_notice(explanation.Join("
"))) + + + +/atom/movable/screen/button_palette/proc/refresh_owner() + var/mob/viewer = our_hud.mymob + if(viewer.client) + viewer.client.screen |= src + + var/list/settings = our_hud.get_action_buttons_icons() + var/ui_icon = "[settings["bg_icon"]]" + var/list/ui_segments = splittext(ui_icon, ".") + var/list/ui_paths = splittext(ui_segments[1], "/") + var/ui_name = ui_paths[length(ui_paths)] + + icon_state = "[ui_name]_palette" + + +/atom/movable/screen/button_palette/MouseEntered(location, control, params) + . = ..() + if(QDELETED(src)) + return + var/list/modifiers = params2list(params) + // don't show the tooltip if we're dragging + if(!LAZYACCESS(modifiers, DRAG) && !LAZYACCESS(modifiers, LEFT_CLICK)) + show_tooltip(params) + +/atom/movable/screen/button_palette/MouseExited() + closeToolTip(usr) + return ..() + +/atom/movable/screen/button_palette/proc/show_tooltip(params) + openToolTip(usr, src, params, title = name, content = desc) + +GLOBAL_LIST_INIT(palette_added_matrix, list(0.4,0.5,0.2,0, 0,1.4,0,0, 0,0.4,0.6,0, 0,0,0,1, 0,0,0,0)) +GLOBAL_LIST_INIT(palette_removed_matrix, list(1.4,0,0,0, 0.7,0.4,0,0, 0.4,0,0.6,0, 0,0,0,1, 0,0,0,0)) + +/atom/movable/screen/button_palette/proc/play_item_added() + color_for_now(GLOB.palette_added_matrix) + +/atom/movable/screen/button_palette/proc/play_item_removed() + color_for_now(GLOB.palette_removed_matrix) + +/atom/movable/screen/button_palette/proc/color_for_now(list/color) + if(color_timer_id) + return + add_atom_colour(color, TEMPORARY_COLOUR_PRIORITY) //We unfortunately cannot animate matrix colors. Curse you lummy it would be ~~non~~trivial to interpolate between the two valuessssssssss + color_timer_id = addtimer(CALLBACK(src, PROC_REF(remove_color), color), 2 SECONDS) + +/atom/movable/screen/button_palette/proc/remove_color(list/to_remove) + color_timer_id = null + remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, to_remove) + +/atom/movable/screen/button_palette/proc/can_use(mob/user) + return TRUE + +/atom/movable/screen/button_palette/Click(location, control, params) + if(!can_use(usr)) + return + + var/list/modifiers = params2list(params) + + if(LAZYACCESS(modifiers, CTRL_CLICK)) + CtrlClick(usr) + return TRUE + + if(LAZYACCESS(modifiers, ALT_CLICK)) + for(var/datum/action/action as anything in usr.actions) // Reset action positions to default + for(var/datum/hud/hud as anything in action.viewers) + var/atom/movable/screen/movable/action_button/button = action.viewers[hud] + hud.position_action(button, SCRN_OBJ_DEFAULT) + to_chat(usr, "Action button positions have been reset.") + return TRUE + + set_expanded(!expanded) + +/atom/movable/screen/button_palette/proc/clicked_while_open(datum/source, atom/target, atom/location, control, params, mob/user) + if(istype(target, /atom/movable/screen/movable/action_button) || istype(target, /atom/movable/screen/palette_scroll) || target == src) // If you're clicking on an action button, or us, you can live + return + set_expanded(FALSE) + if(source) + UnregisterSignal(source, COMSIG_CLIENT_CLICK) + + +/atom/movable/screen/button_palette/proc/set_expanded(new_expanded) + var/datum/action_group/our_group = our_hud.palette_actions + if(!length(our_group.actions)) //Looks dumb, trust me lad + new_expanded = FALSE + if(expanded == new_expanded) + return + + expanded = new_expanded + our_group.refresh_actions() + update_appearance() + + if(!usr.client) + return + + if(expanded) + RegisterSignal(usr.client, COMSIG_CLIENT_CLICK, PROC_REF(clicked_while_open)) + else + UnregisterSignal(usr.client, COMSIG_CLIENT_CLICK) + + closeToolTip(usr) //Our tooltips are now invalid, can't seem to update them in one frame, so here, just close them + + +/atom/movable/screen/palette_scroll + icon = 'icons/mob/screen_gen.dmi' + screen_loc = ui_palette_scroll + /// How should we move the palette's actions? + /// Positive scrolls down the list, negative scrolls back + var/scroll_direction = 0 + var/datum/hud/our_hud + +/atom/movable/screen/palette_scroll/proc/can_use(mob/user) + return TRUE + + +/atom/movable/screen/palette_scroll/proc/set_hud(datum/hud/our_hud) + src.our_hud = our_hud + refresh_owner() + +/atom/movable/screen/palette_scroll/proc/refresh_owner() + var/mob/viewer = our_hud.mymob + if(viewer.client) + viewer.client.screen |= src + var/list/settings = our_hud.get_action_buttons_icons() + icon = settings["bg_icon"] + +/atom/movable/screen/palette_scroll/MouseEntered(location, control, params) + . = ..() + if(QDELETED(src)) + return + openToolTip(usr, src, params, title = name, content = desc) + +/atom/movable/screen/palette_scroll/Click(location, control, params) + if(!can_use(usr)) + return + our_hud.palette_actions.scroll(scroll_direction) + +/atom/movable/screen/palette_scroll/MouseExited() + closeToolTip(usr) + return ..() + +/atom/movable/screen/palette_scroll/down + name = "Scroll Down" + desc = "Click on this to scroll the actions above down" + icon_state = "scroll_down" + scroll_direction = 1 + +/atom/movable/screen/palette_scroll/down/Destroy() + if(our_hud) + our_hud.mymob?.client?.screen -= src + our_hud.palette_down = null + our_hud = null + return ..() + +/atom/movable/screen/palette_scroll/up + name = "Scroll Up" + desc = "Click on this to scroll the actions above up" + icon_state = "scroll_up" + scroll_direction = -1 + +/atom/movable/screen/palette_scroll/up/Destroy() + if(our_hud) + our_hud.mymob?.client?.screen -= src + our_hud.palette_up = null + our_hud = null + return ..() + +/// Exists so you have a place to put your buttons when you move them around +/atom/movable/screen/action_landing + name = "Button Space" + desc = "Drag and drop a button into this spot
to add it to the group" + icon = 'icons/mob/screen_gen.dmi' + icon_state = "reserved" + // We want our whole 32x32 space to be clickable, so dropping's forgiving + mouse_opacity = MOUSE_OPACITY_OPAQUE + var/datum/action_group/owner + +/atom/movable/screen/action_landing/Destroy() + if(owner) + owner.landing = null + owner?.owner?.mymob?.client?.screen -= src + owner.refresh_actions() + owner = null + return ..() + +/atom/movable/screen/action_landing/proc/set_owner(datum/action_group/owner) + src.owner = owner + refresh_owner() + +/atom/movable/screen/action_landing/proc/refresh_owner() + var/datum/hud/our_hud = owner.owner + var/mob/viewer = our_hud.mymob + if(viewer.client) + viewer.client.screen |= src + + var/list/settings = our_hud.get_action_buttons_icons() + icon = settings["bg_icon"] + +/// Reacts to having a button dropped on it +/atom/movable/screen/action_landing/proc/hit_by(atom/movable/screen/movable/action_button/button) + var/datum/hud/our_hud = owner.owner + our_hud.position_action(button, owner.location) + +/datum/hud/proc/position_action(atom/movable/screen/movable/action_button/button, position) + if(button.location != SCRN_OBJ_DEFAULT) + hide_action(button) + switch(position) + if(SCRN_OBJ_DEFAULT) // Reset to the default + position_action(button, button.linked_action.default_button_position) + return + if(SCRN_OBJ_IN_LIST) + listed_actions.insert_action(button) + if(SCRN_OBJ_IN_PALETTE) + palette_actions.insert_action(button) + else // If we don't have it as a define, this is a screen_loc, and we should be floating + floating_actions += button + button.screen_loc = position + position = SCRN_OBJ_FLOATING + + button.location = position + +/datum/hud/proc/position_action_relative(atom/movable/screen/movable/action_button/button, atom/movable/screen/movable/action_button/relative_to) + if(button.location != SCRN_OBJ_DEFAULT) + hide_action(button) + switch(relative_to.location) + if(SCRN_OBJ_IN_LIST) + listed_actions.insert_action(button, listed_actions.index_of(relative_to)) + if(SCRN_OBJ_IN_PALETTE) + palette_actions.insert_action(button, palette_actions.index_of(relative_to)) + if(SCRN_OBJ_FLOATING) // If we don't have it as a define, this is a screen_loc, and we should be floating + floating_actions += button + var/client/our_client = mymob.client + if(!our_client) + position_action(button, button.linked_action.default_button_position) + return + var/client_view_size = getviewsize(our_client.view) + button.screen_loc = get_valid_screen_location(relative_to.screen_loc, world.icon_size, client_view_size) // Asks for a location adjacent to our button that won't overflow the map + + button.location = relative_to.location + +/// Removes the passed in action from its current position on the screen +/datum/hud/proc/hide_action(atom/movable/screen/movable/action_button/button) + switch(button.location) + if(SCRN_OBJ_DEFAULT) // Invalid + CRASH("We just tried to hide an action buttion that somehow has the default position as its location, you done fucked up") + if(SCRN_OBJ_FLOATING) + floating_actions -= button + if(SCRN_OBJ_IN_LIST) + listed_actions.remove_action(button) + if(SCRN_OBJ_IN_PALETTE) + palette_actions.remove_action(button) + button.screen_loc = null + +/// Generates visual landings for all groups that the button is not a memeber of +/datum/hud/proc/generate_landings(atom/movable/screen/movable/action_button/button) + listed_actions.generate_landing() + palette_actions.generate_landing() + +/// Clears all currently visible landings +/datum/hud/proc/hide_landings() + listed_actions.clear_landing() + palette_actions.clear_landing() + +// Updates any existing "owned" visuals, ensures they continue to be visible +/datum/hud/proc/update_our_owner() + toggle_palette.refresh_owner() + palette_down.refresh_owner() + palette_up.refresh_owner() + listed_actions.update_landing() + palette_actions.update_landing() + +/// Ensures all of our buttons are properly within the bounds of our client's view, moves them if they're not +/datum/hud/proc/view_audit_buttons() + var/our_view = mymob?.client?.view + if(!our_view) + return + listed_actions.check_against_view() + palette_actions.check_against_view() + for(var/atom/movable/screen/movable/action_button/floating_button as anything in floating_actions) + var/list/current_offsets = screen_loc_to_offset(floating_button.screen_loc) + // We set the view arg here, so the output will be properly hemm'd in by our new view + floating_button.screen_loc = offset_to_screen_loc(current_offsets[1], current_offsets[2], view = our_view) + +/// Generates and fills new action groups with our mob's current actions +/datum/hud/proc/build_action_groups() + listed_actions = new(src) + palette_actions = new(src) + floating_actions = list() + for(var/datum/action/action as anything in mymob.actions) + var/atom/movable/screen/movable/action_button/button = action.viewers[src] + if(!button) + action.ShowTo(mymob) + button = action.viewers[src] + position_action(button, button.location) #undef AB_MAX_COLUMNS diff --git a/code/_onclick/hud/action_group.dm b/code/_onclick/hud/action_group.dm new file mode 100644 index 00000000000..480e4ba02ca --- /dev/null +++ b/code/_onclick/hud/action_group.dm @@ -0,0 +1,223 @@ +/datum/action_group + /// The hud we're owned by + var/datum/hud/owner + /// The action buttons we're managing + var/list/atom/movable/screen/movable/action_button/actions + /// The initial vertical offset of our action buttons + var/north_offset = 0 + /// The pixel vertical offset of our action buttons + var/pixel_north_offset = 0 + /// The pixel horizontal offset of our action buttons + var/pixel_horiz_offset = 0 + /// Max amount of buttons we can have per row + /// Indexes at 1 + var/column_max = 0 + /// How far "ahead" of the first row we start. Lets us "scroll" our rows + /// Indexes at 1 + var/row_offset = 0 + /// How many rows of actions we can have at max before we just stop hiding + /// Indexes at 1 + var/max_rows = INFINITY + /// The screen location we go by + var/location + /// Our landing screen object + var/atom/movable/screen/action_landing/landing + +/datum/action_group/New(datum/hud/owner) + ..() + actions = list() + src.owner = owner + +/datum/action_group/Destroy() + owner = null + QDEL_NULL(landing) + QDEL_LIST_CONTENTS(actions) + return ..() + +/datum/action_group/proc/insert_action(atom/movable/screen/action, index) + if(action in actions) + if(actions[index] == action) + return + actions -= action // Don't dupe, come on + if(!index) + index = length(actions) + 1 + index = min(length(actions) + 1, index) + actions.Insert(index, action) + refresh_actions() + +/datum/action_group/proc/remove_action(atom/movable/screen/action) + actions -= action + refresh_actions() + +/datum/action_group/proc/refresh_actions() + + // We don't use size() here because landings are not canon + var/total_rows = ROUND_UP(length(actions) / column_max) + total_rows -= max_rows // Lets get the amount of rows we're off from our max + row_offset = clamp(row_offset, 0, total_rows) // You're not allowed to offset so far that we have a row of blank space + + var/button_number = 0 + for(var/atom/movable/screen/button as anything in actions) + var/postion = ButtonNumberToScreenCoords(button_number) + button.screen_loc = postion + button_number++ + + if(landing) + var/postion = ButtonNumberToScreenCoords(button_number, landing = TRUE) // Need a good way to count buttons off screen, but allow this to display in the right place if it's being placed with no concern for dropdown + landing.screen_loc = postion + button_number++ + +/// Accepts a number represeting our position in the group, indexes at 0 to make the math nicer +/datum/action_group/proc/ButtonNumberToScreenCoords(number, landing = FALSE) + var/row = round(number / column_max) + row -= row_offset // If you're less then 0, you don't get to render, this lets us "scroll" rows ya feel? + if(row < 0) + return null + + // Could use >= here, but I think it's worth noting that the two start at different places, since row is based on number here + if(row > max_rows - 1) + if(!landing) // If you're not a landing, go away please. thx + return null + // We always want to render landings, even if their action button can't be displayed. + // So we set a row equal to the max amount of rows + 1. Willing to overrun that max slightly to properly display the landing spot + row = max_rows // Remembering that max_rows indexes at 1, and row indexes at 0 + + // We're going to need to set our column to match the first item in the last row, so let's set number properly now + number = row * column_max + + var/visual_row = row + north_offset + var/coord_row = visual_row ? "-[visual_row]" : "+0" + + var/visual_column = number % column_max + var/coord_col = "+[visual_column]" + var/coord_col_offset = 4 + 2 * (visual_column + 1) + var/coord_row_offset = pixel_north_offset + 2 * (1 * visual_row) + return "WEST[coord_col]:[coord_col_offset],NORTH[coord_row]:-[coord_row_offset]" + +/datum/action_group/proc/check_against_view() + var/owner_view = owner?.mymob?.client?.view + if(!owner_view) + return + // Unlikey as it is, we may have been changed. Want to start from our target position and fail down + column_max = initial(column_max) + // Convert our viewer's view var into a workable offset + var/list/view_size = view_to_pixels(owner_view) + + // We're primarially concerned about width here, if someone makes us 1x2000 I wish them a swift and watery death + var/furthest_screen_loc = ButtonNumberToScreenCoords(column_max - 1) + var/list/offsets = screen_loc_to_offset(furthest_screen_loc, owner_view) + if(offsets[1] > world.icon_size && offsets[1] < view_size[1] && offsets[2] > world.icon_size && offsets[2] < view_size[2]) // We're all good + return + + for(column_max in column_max - 1 to 1 step -1) // Yes I could do this by unwrapping ButtonNumberToScreenCoords, but I don't feel like it + var/tested_screen_loc = ButtonNumberToScreenCoords(column_max) + offsets = screen_loc_to_offset(tested_screen_loc, owner_view) + // We've found a valid max length, pack it in + if(offsets[1] > world.icon_size && offsets[1] < view_size[1] && offsets[2] > world.icon_size && offsets[2] < view_size[2]) + break + // Use our newly resized column max + refresh_actions() + +/// Returns the amount of objects we're storing at the moment +/datum/action_group/proc/size() + var/amount = length(actions) + if(landing) + amount += 1 + return amount + +/datum/action_group/proc/index_of(atom/movable/screen/get_location) + return actions.Find(get_location) + +/// Generates a landing object that can be dropped on to join this group +/datum/action_group/proc/generate_landing() + if(landing) + return + landing = new() + landing.set_owner(src) + refresh_actions() + +/// Clears any landing objects we may currently have +/datum/action_group/proc/clear_landing() + QDEL_NULL(landing) + +/datum/action_group/proc/update_landing() + if(!landing) + return + landing.refresh_owner() + +/datum/action_group/proc/scroll(amount) + row_offset += amount + refresh_actions() + +/datum/action_group/palette + north_offset = 2 + column_max = 3 + max_rows = 3 + location = SCRN_OBJ_IN_PALETTE + +/datum/action_group/palette/proc/on_scroll(atom/movable/screen/movable/action_button/button, delta_x, delta_y, location, control, params) + SIGNAL_HANDLER // COMSIG_ACTION_SCROLLED + if(delta_y > 0) + owner.palette_actions.scroll(1) + else if(delta_y < 0) + owner.palette_actions.scroll(-1) + + +/datum/action_group/palette/insert_action(atom/movable/screen/action, index) + . = ..() + var/atom/movable/screen/button_palette/palette = owner.toggle_palette + RegisterSignal(action, COMSIG_ACTION_SCROLLED, PROC_REF(on_scroll)) + palette.play_item_added() + +/datum/action_group/palette/remove_action(atom/movable/screen/action) + . = ..() + var/atom/movable/screen/button_palette/palette = owner.toggle_palette + UnregisterSignal(action, COMSIG_ACTION_SCROLLED) + palette.play_item_removed() + if(!length(actions)) + palette.set_expanded(FALSE) + +/datum/action_group/palette/refresh_actions() + var/atom/movable/screen/button_palette/palette = owner.toggle_palette + var/atom/movable/screen/palette_scroll/scroll_down = owner.palette_down + var/atom/movable/screen/palette_scroll/scroll_up = owner.palette_up + + var/actions_above = round((owner.listed_actions.size() - 1) / owner.listed_actions.column_max) + north_offset = initial(north_offset) + actions_above + + palette.screen_loc = ui_action_palette_offset(actions_above) + var/action_count = length(owner?.mymob?.actions) + var/our_row_count = round((length(actions) - 1) / column_max) + if(!action_count) + palette.screen_loc = null + + if(palette.expanded && action_count && our_row_count >= max_rows) + scroll_down.screen_loc = ui_palette_scroll_offset(actions_above) + scroll_up.screen_loc = ui_palette_scroll_offset(actions_above) + else + scroll_down.screen_loc = null + scroll_up.screen_loc = null + + return ..() + +/datum/action_group/palette/ButtonNumberToScreenCoords(number, landing) + var/atom/movable/screen/button_palette/palette = owner.toggle_palette + if(palette.expanded) + return ..() + + if(!landing) + return null + + // We only render the landing in this case, so we force it to be the second item displayed (Second rather then first since it looks nicer) + // Remember the number var indexes at 0 + return ..(1 + (row_offset * column_max), landing) + + +/datum/action_group/listed + pixel_north_offset = 6 + column_max = 10 + location = SCRN_OBJ_IN_LIST + +/datum/action_group/listed/refresh_actions() + . = ..() + owner?.palette_actions.refresh_actions() // We effect them, so we gotta refresh em diff --git a/code/_onclick/hud/ai_hud.dm b/code/_onclick/hud/ai_hud.dm index 918cfa8d432..d99b737cc1f 100644 --- a/code/_onclick/hud/ai_hud.dm +++ b/code/_onclick/hud/ai_hud.dm @@ -140,10 +140,6 @@ var/mob/living/silicon/robot/borg = usr borg.sensor_mode() -/mob/living/silicon/ai/create_mob_hud() - if(client && !hud_used) - hud_used = new /datum/hud/ai(src) - /datum/hud/ai/New(mob/owner) ..() diff --git a/code/_onclick/hud/alien_hud.dm b/code/_onclick/hud/alien_hud.dm index c0e4a3ee097..eff377796e0 100644 --- a/code/_onclick/hud/alien_hud.dm +++ b/code/_onclick/hud/alien_hud.dm @@ -38,11 +38,6 @@ name = "plasma stored" screen_loc = ui_alienplasmadisplay - -/mob/living/carbon/alien/humanoid/create_mob_hud() - if(client && !hud_used) - hud_used = new /datum/hud/alien(src) - /datum/hud/alien/New(mob/living/carbon/alien/humanoid/owner) ..() diff --git a/code/_onclick/hud/alien_larva.dm b/code/_onclick/hud/alien_larva.dm index e911c2bb396..83f304279f7 100644 --- a/code/_onclick/hud/alien_larva.dm +++ b/code/_onclick/hud/alien_larva.dm @@ -1,7 +1,3 @@ -/mob/living/carbon/alien/larva/create_mob_hud() - if(client && !hud_used) - hud_used = new /datum/hud/larva(src) - /datum/hud/larva/New(mob/owner) ..() diff --git a/code/_onclick/hud/blob_overmind.dm b/code/_onclick/hud/blob_overmind.dm index dfb74955d1b..13a2fa73efd 100644 --- a/code/_onclick/hud/blob_overmind.dm +++ b/code/_onclick/hud/blob_overmind.dm @@ -1,7 +1,3 @@ -/mob/camera/blob/create_mob_hud() - if(client && !hud_used) - hud_used = new /datum/hud/blob_overmind(src) - /atom/movable/screen/blob icon = 'icons/mob/blob.dmi' diff --git a/code/_onclick/hud/bot_hud.dm b/code/_onclick/hud/bot_hud.dm index 9a27937a5be..d854058a4c1 100644 --- a/code/_onclick/hud/bot_hud.dm +++ b/code/_onclick/hud/bot_hud.dm @@ -11,10 +11,6 @@ var/mob/living/simple_animal/bot/B = usr B.Radio.interact(usr) -/mob/living/simple_animal/bot/create_mob_hud() - if(client && !hud_used) - hud_used = new /datum/hud/bot(src) - /datum/hud/bot/New(mob/owner) ..() var/atom/movable/screen/using diff --git a/code/_onclick/hud/constructs_hud.dm b/code/_onclick/hud/constructs_hud.dm index e2dea642407..941f25fad0a 100644 --- a/code/_onclick/hud/constructs_hud.dm +++ b/code/_onclick/hud/constructs_hud.dm @@ -1,11 +1,3 @@ -/mob/living/simple_animal/hostile/construct/armoured/create_mob_hud() - if(client && !hud_used) - hud_used = new /datum/hud/construct/armoured(src) - -/mob/living/simple_animal/hostile/construct/behemoth/create_mob_hud() - if(client && !hud_used) - hud_used = new /datum/hud/construct/armoured(src) - /datum/hud/construct/armoured/New(mob/owner) ..() mymob.healths = new /atom/movable/screen() @@ -15,10 +7,6 @@ mymob.healths.screen_loc = ui_construct_health infodisplay += mymob.healths -/mob/living/simple_animal/hostile/construct/builder/create_mob_hud() - if(client && !hud_used) - hud_used = new /datum/hud/construct/builder(src) - /datum/hud/construct/builder/New(mob/owner) ..() mymob.healths = new /atom/movable/screen() @@ -28,10 +16,6 @@ mymob.healths.screen_loc = ui_construct_health infodisplay += mymob.healths -/mob/living/simple_animal/hostile/construct/wraith/create_mob_hud() - if(client && !hud_used) - hud_used = new /datum/hud/construct/wraith(src) - /datum/hud/construct/wraith/New(mob/owner) ..() mymob.healths = new /atom/movable/screen() @@ -41,9 +25,6 @@ mymob.healths.screen_loc = ui_construct_health infodisplay += mymob.healths -/mob/living/simple_animal/hostile/construct/harvester/create_mob_hud() - if(client && !hud_used) - hud_used = new /datum/hud/construct/harvester(src) /datum/hud/construct/harvester/New(mob/owner) ..() diff --git a/code/_onclick/hud/ghost_hud.dm b/code/_onclick/hud/ghost_hud.dm index 251800750a1..f7994d9aa45 100644 --- a/code/_onclick/hud/ghost_hud.dm +++ b/code/_onclick/hud/ghost_hud.dm @@ -1,8 +1,3 @@ -/mob/dead/observer/create_mob_hud() - if(client && !hud_used) - hud_used = new /datum/hud/ghost(src) - SEND_SIGNAL(src, COMSIG_MOB_HUD_CREATED) - /atom/movable/screen/ghost icon = 'icons/mob/screen_ghost.dmi' diff --git a/code/_onclick/hud/guardian_hud.dm b/code/_onclick/hud/guardian_hud.dm index 122b2408c5e..231020265a1 100644 --- a/code/_onclick/hud/guardian_hud.dm +++ b/code/_onclick/hud/guardian_hud.dm @@ -1,7 +1,3 @@ -/mob/living/simple_animal/hostile/guardian/create_mob_hud() - if(client && !hud_used) - hud_used = new /datum/hud/guardian(src) - /datum/hud/guardian/New(mob/owner) ..() var/atom/movable/screen/using diff --git a/code/_onclick/hud/hud_datum.dm b/code/_onclick/hud/hud_datum.dm index 6cfe661d3ac..6ac4cce04b8 100644 --- a/code/_onclick/hud/hud_datum.dm +++ b/code/_onclick/hud/hud_datum.dm @@ -7,10 +7,14 @@ /datum/hud var/mob/mymob - var/hud_shown = TRUE //Used for the HUD toggle (F12) - var/hud_version = 1 //Current displayed version of the HUD - var/inventory_shown = TRUE //the inventory - var/hotkey_ui_hidden = FALSE //This is to hide the buttons that can be used via hotkeys. (hotkeybuttons list of buttons) + /// Used for the HUD toggle (F12) + var/hud_shown = TRUE + /// Current displayed version of the HUD + var/hud_version = 1 + /// Whether or not their toggleable inventory + var/inventory_shown = TRUE + /// This is to hide the buttons that can be used via hotkeys. (hotkeybuttons list of buttons) + var/hotkey_ui_hidden = FALSE var/atom/movable/screen/lingchemdisplay var/atom/movable/screen/lingstingdisplay @@ -28,14 +32,28 @@ var/atom/movable/screen/module_store_icon var/atom/movable/screen/combo/combo_display - var/list/static_inventory = list() //the screen objects which are static - var/list/toggleable_inventory = list() //the screen objects which can be hidden - var/list/hotkeybuttons = list() //the buttons that can be used via hotkeys - var/list/infodisplay = list() //the screen objects that display mob info (health, alien plasma, etc...) - var/list/inv_slots[SLOT_HUD_AMOUNT] // /atom/movable/screen/inventory objects, ordered by their slot ID. + // Elements used for action buttons + // -- the main clickable buttons + var/atom/movable/screen/button_palette/toggle_palette + var/atom/movable/screen/palette_scroll/down/palette_down + var/atom/movable/screen/palette_scroll/up/palette_up + /// the groups of actions, such as palette (previously normal) actions + var/datum/action_group/palette/palette_actions + /// action group for expanded actions, the normal action set + var/datum/action_group/listed/listed_actions + /// A list of action buttons which aren't owned by any action group, and are just floating somewhere on the hud. + var/list/floating_actions - var/atom/movable/screen/movable/action_button/hide_toggle/hide_actions_toggle - var/action_buttons_hidden = FALSE + // the screen objects which are static + var/list/static_inventory = list() + /// the screen objects which can be hidden (your human items on the left) + var/list/toggleable_inventory = list() + /// the buttons that can be used via hotkeys + var/list/hotkeybuttons = list() + //the screen objects that display mob info (health, alien plasma, etc...) + var/list/infodisplay = list() + /// /atom/movable/screen/inventory objects, ordered by their slot ID. + var/list/inv_slots[SLOT_HUD_AMOUNT] var/list/atom/movable/screen/plane_master/plane_masters = list() // see "appearance_flags" in the ref, assoc list of "[plane]" = object ///Assoc list of controller groups, associated with key string group name with value of the plane master controller ref @@ -45,13 +63,31 @@ /mob/proc/create_mob_hud() if(client && !hud_used) - hud_used = new /datum/hud(src) + if(!ispath(hud_type)) + CRASH("Hud type must be a type, was instead [hud_type]!") + set_hud_used(new hud_type(src)) update_sight() + SEND_SIGNAL(src, COMSIG_MOB_HUD_CREATED) + +/mob/proc/set_hud_used(datum/hud/new_hud) + hud_used = new_hud + new_hud.build_action_groups() + +/datum/hud/proc/get_all_action_buttons() + var/list/all_action_buttons = list() + all_action_buttons += palette_actions.actions + all_action_buttons += listed_actions.actions + return all_action_buttons /datum/hud/New(mob/owner) mymob = owner - hide_actions_toggle = new - hide_actions_toggle.InitialiseIcon(mymob) + + toggle_palette = new() + toggle_palette.set_hud(src) + palette_down = new() + palette_down.set_hud(src) + palette_up = new() + palette_up.set_hud(src) for(var/mytype in subtypesof(/atom/movable/screen/plane_master)) var/atom/movable/screen/plane_master/instance = new mytype() @@ -69,10 +105,14 @@ if(mymob.hud_used == src) mymob.hud_used = null - QDEL_NULL(hide_actions_toggle) + QDEL_NULL(toggle_palette) + QDEL_NULL(palette_down) + QDEL_NULL(palette_up) + QDEL_NULL(palette_actions) + QDEL_NULL(listed_actions) + QDEL_LIST_CONTENTS(floating_actions) QDEL_NULL(module_store_icon) - QDEL_LIST_CONTENTS(static_inventory) inv_slots.Cut() @@ -125,29 +165,29 @@ switch(display_hud_version) if(HUD_STYLE_STANDARD) //Default HUD hud_shown = TRUE //Governs behavior of other procs - if(static_inventory.len) + if(length(static_inventory)) mymob.client.screen += static_inventory - if(toggleable_inventory.len && inventory_shown) + if(length(toggleable_inventory) && inventory_shown) mymob.client.screen += toggleable_inventory - if(hotkeybuttons.len && !hotkey_ui_hidden) + if(length(hotkeybuttons) && !hotkey_ui_hidden) mymob.client.screen += hotkeybuttons - if(infodisplay.len) + if(length(infodisplay)) mymob.client.screen += infodisplay - mymob.client.screen += hide_actions_toggle + mymob.client.screen += toggle_palette if(action_intent) action_intent.screen_loc = initial(action_intent.screen_loc) //Restore intent selection to the original position if(HUD_STYLE_REDUCED) //Reduced HUD hud_shown = FALSE //Governs behavior of other procs - if(static_inventory.len) + if(length(static_inventory)) mymob.client.screen -= static_inventory - if(toggleable_inventory.len) + if(length(toggleable_inventory)) mymob.client.screen -= toggleable_inventory - if(hotkeybuttons.len) + if(length(hotkeybuttons)) mymob.client.screen -= hotkeybuttons - if(infodisplay.len) + if(length(infodisplay)) mymob.client.screen += infodisplay //These ones are a part of 'static_inventory', 'toggleable_inventory' or 'hotkeybuttons' but we want them to stay @@ -161,13 +201,13 @@ if(HUD_STYLE_NOHUD) //No HUD hud_shown = FALSE //Governs behavior of other procs - if(static_inventory.len) + if(length(static_inventory)) mymob.client.screen -= static_inventory - if(toggleable_inventory.len) + if(length(toggleable_inventory)) mymob.client.screen -= toggleable_inventory - if(hotkeybuttons.len) + if(length(hotkeybuttons)) mymob.client.screen -= hotkeybuttons - if(infodisplay.len) + if(length(infodisplay)) mymob.client.screen -= infodisplay hud_version = display_hud_version @@ -206,9 +246,9 @@ /mob/proc/hide_hud() if(hud_used && client) hud_used.show_hud() //Shows the next hud preset - to_chat(src, "Switched HUD mode. Press the key you just pressed to toggle the HUD mode again.") + to_chat(src, "Switched HUD mode. Press the key you just pressed to toggle the HUD mode again.") else - to_chat(src, "This mob type does not use a HUD.") + to_chat(src, "This mob type does not use a HUD.") /datum/hud/proc/update_locked_slots() return diff --git a/code/_onclick/hud/human_hud.dm b/code/_onclick/hud/human_hud.dm index c69e78f6404..110b278f63a 100644 --- a/code/_onclick/hud/human_hud.dm +++ b/code/_onclick/hud/human_hud.dm @@ -51,7 +51,7 @@ /mob/living/carbon/human/create_mob_hud() if(client && !hud_used) - hud_used = new /datum/hud/human(src, ui_style2icon(client.prefs.UI_style), client.prefs.UI_style_color, client.prefs.UI_style_alpha) + set_hud_used(new /datum/hud/human(src, ui_style2icon(client.prefs.UI_style), client.prefs.UI_style_color, client.prefs.UI_style_alpha)) SEND_SIGNAL(src, COMSIG_HUMAN_CREATE_MOB_HUD) /datum/hud/human diff --git a/code/_onclick/hud/movable_screen_objects.dm b/code/_onclick/hud/movable_screen_objects.dm index f43effee417..65fd2f13c20 100644 --- a/code/_onclick/hud/movable_screen_objects.dm +++ b/code/_onclick/hud/movable_screen_objects.dm @@ -10,10 +10,11 @@ /atom/movable/screen/movable var/snap2grid = FALSE - var/moved = FALSE - var/locked = TRUE var/x_off = -16 var/y_off = -16 + // add a green overlay + mouse_drag_pointer = 'icons/mouse_icons/screen_drag.dmi' + //Snap Screen Object //Tied to the grid, snaps to the nearest turf @@ -22,33 +23,31 @@ snap2grid = TRUE /atom/movable/screen/movable/MouseDrop(over_object, src_location, over_location, src_control, over_control, params) - if(locked) //no! I am locked! begone! + var/position = mouse_params_to_position(params) + if(!position) return - var/list/PM = params2list(params) + screen_loc = position + +/// Takes mouse parmas as input, returns a string representing the appropriate mouse position +/atom/movable/screen/movable/proc/mouse_params_to_position(params) + + var/list/modifiers = params2list(params) //No screen-loc information? abort. - if(!PM || !PM["screen-loc"]) + if(!LAZYACCESS(modifiers, SCREEN_LOC)) return - //Split screen-loc up into X+Pixel_X and Y+Pixel_Y - var/list/screen_loc_params = splittext(PM["screen-loc"], ",") - - //Split X+Pixel_X up into list(X, Pixel_X) - var/list/screen_loc_X = splittext(screen_loc_params[1],":") - - //Split Y+Pixel_Y up into list(Y, Pixel_Y) - var/list/screen_loc_Y = splittext(screen_loc_params[2],":") + var/client/our_client = usr.client + var/list/offset = screen_loc_to_offset(LAZYACCESS(modifiers, SCREEN_LOC)) if(snap2grid) //Discard Pixel Values - screen_loc = "[screen_loc_X[1]],[screen_loc_Y[1]]" - + offset[1] = FLOOR(offset[1], world.icon_size) // drops any pixel offset + offset[2] = FLOOR(offset[2], world.icon_size) // drops any pixel offset else //Normalise Pixel Values (So the object drops at the center of the mouse, not 16 pixels off) - var/pix_X = text2num(screen_loc_X[2]) + x_off - var/pix_Y = text2num(screen_loc_Y[2]) + y_off - screen_loc = "[screen_loc_X[1]]:[pix_X],[screen_loc_Y[1]]:[pix_Y]" - - moved = screen_loc + offset[1] += x_off + offset[2] += y_off + return offset_to_screen_loc(offset[1], offset[2], our_client?.view) //Debug procs /client/proc/test_movable_UI() diff --git a/code/_onclick/hud/other_mobs_hud.dm b/code/_onclick/hud/other_mobs_hud.dm index 27fe7bf5524..39fe3a31552 100644 --- a/code/_onclick/hud/other_mobs_hud.dm +++ b/code/_onclick/hud/other_mobs_hud.dm @@ -1,6 +1,3 @@ -/mob/living/simple_animal/create_mob_hud() - hud_used = new /datum/hud/simple_animal(src) - /datum/hud/simple_animal/New(mob/user) ..() @@ -15,11 +12,6 @@ user.overlay_fullscreen("see_through_darkness", /atom/movable/screen/fullscreen/see_through_darkness) - -/mob/living/simple_animal/pet/create_mob_hud() - if(client && !hud_used) - hud_used = new /datum/hud/corgi(src) - /datum/hud/corgi/New(mob/user) ..() diff --git a/code/_onclick/hud/robot_hud.dm b/code/_onclick/hud/robot_hud.dm index c34807563c5..ae1e54f9fe2 100644 --- a/code/_onclick/hud/robot_hud.dm +++ b/code/_onclick/hud/robot_hud.dm @@ -85,11 +85,6 @@ /atom/movable/screen/robot/mov_intent/Click() usr.toggle_move_intent() - -/mob/living/silicon/robot/create_mob_hud() - if(client && !hud_used) - hud_used = new /datum/hud/robot(src) - /datum/hud/robot/New(mob/user) ..() diff --git a/code/_onclick/hud/screentip.dm b/code/_onclick/hud/screentip.dm index 542c96e626f..d70cbd72e32 100644 --- a/code/_onclick/hud/screentip.dm +++ b/code/_onclick/hud/screentip.dm @@ -13,6 +13,8 @@ update_view() /atom/movable/screen/screentip/proc/update_view(datum/source) - if(!hud) //Might not have been initialized by now + if(!hud?.mymob?.client) //Might not have been initialized by now return - maptext_width = getviewsize(hud.mymob.client.view)[1] * world.icon_size + var/list/view_size = getviewsize(hud.mymob.client.view) + var/view = "[view_size[1]]x[view_size[2]]" + maptext_width = view_to_pixels(view)[1] diff --git a/code/_onclick/hud/slime_hud.dm b/code/_onclick/hud/slime_hud.dm index 58a579e3599..d0337832a80 100644 --- a/code/_onclick/hud/slime_hud.dm +++ b/code/_onclick/hud/slime_hud.dm @@ -2,7 +2,3 @@ ..() mymob.healths = new /atom/movable/screen/healths/slime() infodisplay += mymob.healths - -/mob/living/simple_animal/slime/create_mob_hud() - if(client && !hud_used) - hud_used = new /datum/hud/slime(src) diff --git a/code/datums/action.dm b/code/datums/action.dm index 5ab9d6fa023..7e1c0752ec8 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -4,56 +4,73 @@ var/desc = null var/obj/target = null var/check_flags = 0 - var/atom/movable/screen/movable/action_button/button = null var/button_icon = 'icons/mob/actions/actions.dmi' - var/background_icon_state = "bg_default" + var/background_icon = 'icons/mob/actions/actions.dmi' + var/background_icon_state = ACTION_BUTTON_DEFAULT_BACKGROUND var/buttontooltipstyle = "" var/icon_icon = 'icons/mob/actions/actions.dmi' var/button_icon_state = "default" + var/transparent_when_unavailable = TRUE var/mob/owner + /// Where any buttons we create should be by default. Accepts screen_loc and location defines + var/default_button_position = SCRN_OBJ_IN_LIST + /// Map of huds viewing a button with our action -> their button + var/list/viewers = list() + /datum/action/New(Target) target = Target - button = new - button.linked_action = src - button.name = name - button.actiontooltipstyle = buttontooltipstyle - var/list/our_description = list() - our_description += desc - our_description += button.desc - button.desc = our_description.Join(" ") + +/datum/action/proc/clear_ref(datum/ref) + SIGNAL_HANDLER + if(ref == owner) + Remove(owner) + if(ref == target) + qdel(src) /datum/action/Destroy() if(owner) Remove(owner) if(target) target = null - QDEL_NULL(button) + QDEL_LIST_ASSOC_VAL(viewers) // Qdel the buttons in the viewers list **NOT THE HUDS** return ..() /datum/action/proc/Grant(mob/M) + if(!M) + Remove(owner) + return if(owner) if(owner == M) return Remove(owner) owner = M - M.actions += src - if(M.client) - M.client.screen += button - button.locked = TRUE - M.update_action_buttons() + RegisterSignal(owner, COMSIG_PARENT_QDELETING, PROC_REF(clear_ref), override = TRUE) + GiveAction(M) -/datum/action/proc/Remove(mob/M) - owner = null - if(!M) +/datum/action/proc/Remove(mob/remove_from) + for(var/datum/hud/hud in viewers) + if(!hud.mymob) + continue + HideFrom(hud.mymob) + + LAZYREMOVE(remove_from?.actions, src) // We aren't always properly inserted into the viewers list, gotta make sure that action's cleared + viewers = list() + // owner = null + + if(isnull(owner)) return - if(M.client) - M.client.screen -= button - button.clean_up_keybinds(M) - button.moved = FALSE //so the button appears in its normal position when given to another owner. - button.locked = FALSE - M.actions -= src - M.update_action_buttons() + + if(target == owner) + RegisterSignal(target, COMSIG_PARENT_QDELETING, PROC_REF(clear_ref), override = TRUE) + if(owner == remove_from) + UnregisterSignal(owner, COMSIG_PARENT_QDELETING) + owner = null + +/datum/action/proc/UpdateButtons(status_only, force) + for(var/datum/hud/hud in viewers) + var/atom/movable/screen/movable/button = viewers[hud] + UpdateButton(button, status_only, force) /datum/action/proc/Trigger(left_click = TRUE) if(!IsAvailable()) @@ -95,31 +112,105 @@ return FALSE return TRUE -/datum/action/proc/UpdateButtonIcon() +/datum/action/proc/UpdateButton(atom/movable/screen/movable/action_button/button, status_only = FALSE, force = FALSE) + if(!button) + return + if(!status_only) + button.name = name + button.desc = desc + if(owner?.hud_used && background_icon_state == ACTION_BUTTON_DEFAULT_BACKGROUND) + var/list/settings = owner.hud_used.get_action_buttons_icons() + if(button.icon != settings["bg_icon"]) + button.icon = settings["bg_icon"] + if(button.icon_state != settings["bg_state"]) + button.icon_state = settings["bg_state"] + else + if(button.icon != button_icon) + button.icon = button_icon + if(button.icon_state != background_icon_state) + button.icon_state = background_icon_state + + ApplyIcon(button, force) + + if(!IsAvailable()) + apply_unavailable_effect(button) + else + return TRUE + +//Give our action button to the player +/datum/action/proc/GiveAction(mob/viewer) + var/datum/hud/our_hud = viewer.hud_used + if(viewers[our_hud]) // Already have a copy of us? go away + return + LAZYOR(viewer.actions, src) // Move this in + ShowTo(viewer) + +//Adds our action button to the screen of a player +/datum/action/proc/ShowTo(mob/viewer) + var/datum/hud/our_hud = viewer.hud_used + if(!our_hud || viewers[our_hud]) // There's no point in this if you have no hud in the first place + return + + + var/atom/movable/screen/movable/action_button/button = CreateButton() + SetId(button, viewer) + + button.our_hud = our_hud + viewers[our_hud] = button + if(viewer.client) + viewer.client.screen += button + + button.load_position(viewer) + viewer.update_action_buttons() + + +//Removes our action button from the screen of a player +/datum/action/proc/HideFrom(mob/viewer) + var/datum/hud/our_hud = viewer.hud_used + var/atom/movable/screen/movable/action_button/button = viewers[our_hud] + LAZYREMOVE(viewer.actions, src) if(button) - if(owner && owner.client && background_icon_state == "bg_default") // If it's a default action background, apply the custom HUD style - button.alpha = owner.client.prefs.UI_style_alpha - button.color = owner.client.prefs.UI_style_color - button.icon = ui_style2icon(owner.client.prefs.UI_style) - button.icon_state = "template" - else - button.icon = button_icon - button.icon_state = background_icon_state + button.clean_up_keybinds(viewer) + qdel(button) - ApplyIcon(button) - var/obj/effect/proc_holder/spell/S = target - if(istype(S) && S.cooldown_handler.should_draw_cooldown() || !IsAvailable()) - apply_unavailable_effect() - else - return TRUE -/datum/action/proc/apply_unavailable_effect() +/datum/action/proc/CreateButton() + var/atom/movable/screen/movable/action_button/button = new() + button.linked_action = src + button.name = name + button.actiontooltipstyle = buttontooltipstyle + var/list/our_description = list() + our_description += desc + our_description += button.desc + button.desc = our_description.Join(" ") + return button + + +/datum/action/proc/SetId(atom/movable/screen/movable/action_button/our_button, mob/owner) + //button id generation + var/bitfield = 0 + for(var/datum/action/action in owner.actions) + if(action == src) // This could be us, which is dumb + continue + var/atom/movable/screen/movable/action_button/button = action.viewers[owner.hud_used] + if(action.name == name && button.id) + bitfield |= button.id + + bitfield = ~bitfield // Flip our possible ids, so we can check if we've found a unique one + for(var/i in 0 to 23) // We get 24 possible bitflags in dm + var/bitflag = 1 << i // Shift us over one + if(bitfield & bitflag) + our_button.id = bitflag + return + +/datum/action/proc/apply_unavailable_effect(atom/movable/screen/movable/action_button/B) var/image/img = image('icons/mob/screen_white.dmi', icon_state = "template") img.alpha = 200 img.appearance_flags = RESET_COLOR | RESET_ALPHA img.color = "#000000" img.plane = FLOAT_PLANE + 1 - button.add_overlay(img) + B.add_overlay(img) + /datum/action/proc/ApplyIcon(atom/movable/screen/movable/action_button/current_button) current_button.cut_overlays() @@ -143,10 +234,12 @@ use_itemicon = FALSE icon_icon = custom_icon button_icon_state = custom_icon_state + UpdateButtons() /datum/action/item_action/Destroy() var/obj/item/I = target - I.actions -= src + if(islist(I?.actions)) + I.actions -= src return ..() /datum/action/item_action/Trigger(left_click = TRUE, attack_self = TRUE) //Maybe we don't want to click the thing itself @@ -217,13 +310,14 @@ /datum/action/item_action/set_internals name = "Set Internals" -/datum/action/item_action/set_internals/UpdateButtonIcon() - if(..()) //button available - if(iscarbon(owner)) - var/mob/living/carbon/C = owner - if(target == C.internal) - button.icon = 'icons/mob/actions/actions.dmi' - button.icon_state = "bg_default_on" +/datum/action/item_action/set_internals/UpdateButton(atom/movable/screen/movable/action_button/button, status_only = FALSE, force) + if(!..()) // no button available + return + if(!iscarbon(owner)) + return + var/mob/living/carbon/C = owner + if(target == C.internal) + button.icon_state = "template_active" /datum/action/item_action/toggle_mister name = "Toggle Mister" @@ -255,19 +349,17 @@ /datum/action/item_action/toggle_unfriendly_fire/Trigger(left_click) if(..()) - UpdateButtonIcon() + UpdateButtons() -/datum/action/item_action/toggle_unfriendly_fire/UpdateButtonIcon() +/datum/action/item_action/toggle_unfriendly_fire/UpdateButtons() if(istype(target, /obj/item/hierophant_club)) var/obj/item/hierophant_club/H = target if(H.friendly_fire_check) button_icon_state = "vortex_ff_off" name = "Toggle Friendly Fire \[OFF\]" - button.name = name else button_icon_state = "vortex_ff_on" name = "Toggle Friendly Fire \[ON\]" - button.name = name ..() /datum/action/item_action/vortex_recall @@ -290,28 +382,24 @@ /datum/action/item_action/toggle/New(Target) ..() name = "Toggle [target.name]" - button.name = name /datum/action/item_action/openclose /datum/action/item_action/openclose/New(Target) ..() name = "Open/Close [target.name]" - button.name = name /datum/action/item_action/button /datum/action/item_action/button/New(Target) ..() name = "Button/Unbutton [target.name]" - button.name = name /datum/action/item_action/zipper /datum/action/item_action/zipper/New(Target) ..() name = "Zip/Unzip [target.name]" - button.name = name /datum/action/item_action/halt name = "HALT!" @@ -352,7 +440,6 @@ /datum/action/item_action/adjust/New(Target) ..() name = "Adjust [target.name]" - button.name = name /datum/action/item_action/pontificate name = "Pontificate Evilly" @@ -495,17 +582,14 @@ /datum/action/item_action/organ_action/toggle/New(Target) ..() name = "Toggle [target.name]" - button.name = name /datum/action/item_action/organ_action/use/New(Target) ..() name = "Use [target.name]" - button.name = name /datum/action/item_action/organ_action/use/eyesofgod/New(target) ..() name = "See with the Eyes of the Gods" - button.name = name /datum/action/item_action/voice_changer/toggle name = "Toggle Voice Changer" @@ -556,14 +640,12 @@ var/obj/effect/proc_holder/spell/S = target S.action = src name = S.name - var/list/our_description = list() - our_description += S.desc - our_description += button.desc - button.desc = our_description.Join(" ") + desc = S.desc button_icon = S.action_icon button_icon_state = S.action_icon_state background_icon_state = S.action_background_icon_state - button.name = name + UpdateButtons() + /datum/action/spell_action/Destroy() var/obj/effect/proc_holder/spell/S = target @@ -593,7 +675,7 @@ return spell.can_cast(owner) return FALSE -/datum/action/spell_action/apply_unavailable_effect() +/datum/action/spell_action/apply_unavailable_effect(atom/movable/screen/movable/action_button/button) var/obj/effect/proc_holder/spell/S = target if(!istype(S)) return ..() @@ -613,19 +695,6 @@ count_down_holder.maptext = "
[text]
" button.add_overlay(count_down_holder) -/* -/datum/action/spell_action/alien - -/datum/action/spell_action/alien/IsAvailable() - if(!target) - return 0 - var/obj/effect/proc_holder/alien/ab = target - - if(owner) - return ab.cost_check(ab.check_turf, owner, 1) - return 0 -*/ - //Preset for general and toggled actions /datum/action/innate check_flags = 0 diff --git a/code/datums/spell.dm b/code/datums/spell.dm index 3cd988a0624..e20a939e364 100644 --- a/code/datums/spell.dm +++ b/code/datums/spell.dm @@ -193,7 +193,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) custom_handler?.spend_spell_cost(user, src) if(action) - action.UpdateButtonIcon() + action.UpdateButtons() /obj/effect/proc_holder/spell/proc/invocation(mob/user) //spelling the spell out and setting it on recharge/reducing charges amount switch(invocation_type) @@ -362,7 +362,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) cast(targets, user = user) after_cast(targets, user) if(action) - action.UpdateButtonIcon() + action.UpdateButtons() /** * Will write additional logs if create_custom_logs is TRUE and the caster has a ckey. Override this @@ -435,11 +435,11 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) custom_handler?.revert_cast(user, src) if(action) - action.UpdateButtonIcon() + action.UpdateButtons() -/obj/effect/proc_holder/spell/proc/updateButtonIcon() +/obj/effect/proc_holder/spell/proc/UpdateButtons() if(action) - action.UpdateButtonIcon() + action.UpdateButtons() /obj/effect/proc_holder/spell/proc/adjust_var(mob/living/target = usr, type, amount) //handles the adjustment of the var when the spell is used. has some hardcoded types switch(type) diff --git a/code/datums/spell_cooldown/spell_charges.dm b/code/datums/spell_cooldown/spell_charges.dm index 165caeba027..bdbe9230405 100644 --- a/code/datums/spell_cooldown/spell_charges.dm +++ b/code/datums/spell_cooldown/spell_charges.dm @@ -28,7 +28,7 @@ if(recharge_time > world.time) return FALSE current_charges++ - spell_parent.action.UpdateButtonIcon() + spell_parent.action.UpdateButtons() if(current_charges < max_charges) // we have more recharges to go recharge_time = world.time + recharge_duration return FALSE diff --git a/code/datums/spell_cooldown/spell_cooldown.dm b/code/datums/spell_cooldown/spell_cooldown.dm index 3d320bdca8a..68f935e5f00 100644 --- a/code/datums/spell_cooldown/spell_cooldown.dm +++ b/code/datums/spell_cooldown/spell_cooldown.dm @@ -33,7 +33,7 @@ if(!spell_parent.action) stack_trace("[spell_parent.type] ended up with a null action") return PROCESS_KILL - spell_parent.action.UpdateButtonIcon() + spell_parent.action.UpdateButtons() if(should_end_cooldown()) return PROCESS_KILL @@ -58,7 +58,7 @@ else recharge_time = get_recharge_time() if(spell_parent.action) - spell_parent.action.UpdateButtonIcon() + spell_parent.action.UpdateButtons() START_PROCESSING(SSfastprocess, src) /datum/spell_cooldown/proc/revert_cast() diff --git a/code/datums/spells/alien_spells/basetype_alien_spell.dm b/code/datums/spells/alien_spells/basetype_alien_spell.dm index c4413e45d90..f192962592e 100644 --- a/code/datums/spells/alien_spells/basetype_alien_spell.dm +++ b/code/datums/spells/alien_spells/basetype_alien_spell.dm @@ -15,7 +15,7 @@ Updates the spell's actions on use as well, so they know when they can or can't vessel.stored_plasma = clamp(vessel.stored_plasma + amount, 0, vessel.max_plasma) update_plasma_display(src) for(var/datum/action/spell_action/action in actions) - action.UpdateButtonIcon() + action.UpdateButtons() /obj/effect/proc_holder/spell/alien_spell action_background_icon_state = "bg_alien" diff --git a/code/datums/spells/alien_spells/neurotoxin_spit.dm b/code/datums/spells/alien_spells/neurotoxin_spit.dm index ad4048f53a1..d3cabc594c0 100644 --- a/code/datums/spells/alien_spells/neurotoxin_spit.dm +++ b/code/datums/spells/alien_spells/neurotoxin_spit.dm @@ -16,7 +16,7 @@ if(!action) return action.button_icon_state = "alien_neurotoxin_[active]" - action.UpdateButtonIcon() + action.UpdateButtons() /obj/effect/proc_holder/spell/alien_spell/neurotoxin/cast(list/targets, mob/living/carbon/user) var/target = targets[1] diff --git a/code/datums/spells/lichdom.dm b/code/datums/spells/lichdom.dm index b882d6dec2c..ccdad7e9863 100644 --- a/code/datums/spells/lichdom.dm +++ b/code/datums/spells/lichdom.dm @@ -96,7 +96,7 @@ to_chat(lich, "Your bones clatter and shudder as they're pulled back into this world!") /obj/effect/proc_holder/spell/lichdom/proc/attempt_mark_item(mob/user) - var/obj/item/target = user.get_active_hand() + var/obj/item/target = user.get_active_hand() if(!target) to_chat(user, "You must hold an item you wish to make your phylactery!") return @@ -114,10 +114,10 @@ stat_allowed = UNCONSCIOUS cooldown_handler.recharge_duration = 3 MINUTES cooldown_handler.revert_cast() - - if(action && action.button) - action.name = action.button.name = name - action.desc = action.button.desc = desc + if(action) + action.name = name + action.desc = desc + UpdateButtons() target.name = "ensouled [target.name]" target.desc += "
A terrible aura surrounds this item, its very existence is offensive to life itself..." @@ -137,7 +137,7 @@ RegisterSignal(target, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_Z_CHANGED), PROC_REF(check_revivability_handler)) RegisterSignal(current_body, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_Z_CHANGED), PROC_REF(check_revivability_handler)) to_chat(user, "With a hideous feeling of emptiness you watch in horrified fascination as skin sloughs off bone! Blood boils, nerves disintegrate, eyes boil in their sockets! As your organs crumble to dust in your fleshless chest you come to terms with your choice. You're a lich!") - + existence_stops_round_end = TRUE GLOB.configuration.gamemode.disable_certain_round_early_end = TRUE diff --git a/code/datums/spells/wizard_spells.dm b/code/datums/spells/wizard_spells.dm index e68728e9c4f..c39d4742f34 100644 --- a/code/datums/spells/wizard_spells.dm +++ b/code/datums/spells/wizard_spells.dm @@ -367,7 +367,7 @@ if(!action) return action.button_icon_state = "fireball[active]" - action.UpdateButtonIcon() + action.UpdateButtons() /obj/effect/proc_holder/spell/fireball/cast(list/targets, mob/living/user = usr) var/target = targets[1] //There is only ever one target for fireball diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 57211a2fd69..cf70c3d27bb 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -632,7 +632,7 @@ . = ..() for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() /atom/proc/get_filter(name) if(filter_data && filter_data[name]) diff --git a/code/game/gamemodes/cult/blood_magic.dm b/code/game/gamemodes/cult/blood_magic.dm index 3b90a7c9add..47ca9460e58 100644 --- a/code/game/gamemodes/cult/blood_magic.dm +++ b/code/game/gamemodes/cult/blood_magic.dm @@ -5,27 +5,29 @@ desc = "Prepare blood magic by carving runes into your flesh. This is easier with an empowering rune." var/list/spells = list() var/channeling = FALSE + default_button_position = DEFAULT_BLOODSPELLS /datum/action/innate/cult/blood_magic/Remove() for(var/X in spells) qdel(X) ..() -/datum/action/innate/cult/blood_magic/override_location() - button.ordered = FALSE - button.screen_loc = DEFAULT_BLOODSPELLS - button.moved = DEFAULT_BLOODSPELLS - /datum/action/innate/cult/blood_magic/proc/Positioning() - var/list/screen_loc_split = splittext(button.screen_loc, ",") - var/list/screen_loc_X = splittext(screen_loc_split[1], ":") - var/list/screen_loc_Y = splittext(screen_loc_split[2], ":") - var/pix_X = text2num(screen_loc_X[2]) - for(var/datum/action/innate/cult/blood_spell/B in spells) - if(B.button.locked) - var/order = pix_X + spells.Find(B) * 31 - B.button.screen_loc = "[screen_loc_X[1]]:[order],[screen_loc_Y[1]]:[screen_loc_Y[2]]" - B.button.moved = B.button.screen_loc + for(var/datum/hud/hud as anything in viewers) + var/our_view = hud.mymob?.client?.view || "15x15" + var/atom/movable/screen/movable/action_button/button = viewers[hud] + var/position = screen_loc_to_offset(button.screen_loc) + var/spells_iterated = 0 + for(var/datum/action/innate/cult/blood_spell/blood_spell in spells) + spells_iterated += 1 + if(blood_spell.positioned) + continue + var/atom/movable/screen/movable/action_button/moving_button = blood_spell.viewers[hud] + if(!moving_button) + continue + var/our_x = position[1] + spells_iterated * world.icon_size // Offset any new buttons into our list + hud.position_action(moving_button, offset_to_screen_loc(our_x, position[2], our_view)) + blood_spell.positioned = TRUE /datum/action/innate/cult/blood_magic/Activate() var/rune = FALSE @@ -98,6 +100,9 @@ var/base_desc //To allow for updating tooltips var/invocation = "Hoi there something's wrong!" var/health_cost = 0 + /// Have we already been positioned into our starting location? + var/positioned = FALSE + /datum/action/innate/cult/blood_spell/proc/get_panel_text() if(initial(charges) == 1) @@ -105,7 +110,7 @@ var/available_charges = hand_magic ? "[hand_magic.uses]" : "[charges]" return "[available_charges]/[initial(charges)]" -/datum/action/innate/cult/blood_spell/UpdateButtonIcon() +/datum/action/innate/cult/blood_spell/UpdateButton(atom/movable/screen/movable/action_button/button, status_only, force) . = ..() var/text = get_panel_text() if(!text || !button) @@ -120,11 +125,12 @@ base_desc = desc desc += "
Has [charges] use\s remaining." all_magic = BM - button.ordered = FALSE + // todo blood magic guh + // button.ordered = FALSE ..() /datum/action/innate/cult/blood_spell/override_location() - button.locked = TRUE + // button.locked = TRUE all_magic.Positioning() /datum/action/innate/cult/blood_spell/Remove() @@ -311,10 +317,10 @@ var/mob/living/carbon/human/H = target H.Hallucinate(120 SECONDS) attached_action.charges-- - attached_action.UpdateButtonIcon() + attached_action.UpdateButtons() attached_action.desc = attached_action.base_desc attached_action.desc += "
Has [attached_action.charges] use\s remaining." - attached_action.UpdateButtonIcon() + attached_action.UpdateButtons() user.ranged_ability.remove_ranged_ability(user, "[H] has been cursed with living nightmares!") if(attached_action.charges <= 0) to_chat(ranged_ability_user, "You have exhausted the spell's power!") @@ -364,7 +370,7 @@ qdel(src) desc = "[revealing ? "Reveals" : "Conceals"] nearby cult structures, airlocks, and runes." desc += "
Has [charges] use\s remaining." - UpdateButtonIcon() + UpdateButtons() /datum/action/innate/cult/blood_spell/manipulation name = "Blood Rites" @@ -418,7 +424,7 @@ source.charges = uses source.desc = source.base_desc source.desc += "
Has [uses] use\s remaining." - source.UpdateButtonIcon() + source.UpdateButtons() return ..() /obj/item/melee/blood_magic/customised_abstract_text(mob/living/carbon/owner) @@ -446,7 +452,7 @@ else if(source) source.desc = source.base_desc source.desc += "
Has [uses] use\s remaining." - source.UpdateButtonIcon() + source.UpdateButtons() //The spell effects @@ -585,7 +591,7 @@ else user.visible_message("This victim doesn't have enough arms to complete the restraint!") return - source.UpdateButtonIcon() + source.UpdateButtons() ..() /obj/item/melee/blood_magic/shackles/proc/CuffAttack(mob/living/carbon/C, mob/living/user) @@ -879,12 +885,12 @@ target.clean_blood() else steal_blood(user, target) - source.UpdateButtonIcon() + source.UpdateButtons() return if(isconstruct(target)) heal_construct(user, target) - source.UpdateButtonIcon() + source.UpdateButtons() return if(istype(target, /obj/item/blood_orb)) @@ -894,10 +900,10 @@ to_chat(user, "You obtain [candidate.blood] blood from the orb of blood!") playsound(user, 'sound/misc/enter_blood.ogg', 50, extrarange = SOUND_RANGE_SET(7)) qdel(candidate) - source.UpdateButtonIcon() + source.UpdateButtons() return blood_draw(target, user) - source.UpdateButtonIcon() + source.UpdateButtons() /obj/item/melee/blood_magic/manipulator/proc/blood_draw(atom/target, mob/living/carbon/human/user) var/temp = 0 @@ -1001,4 +1007,4 @@ to_chat(user, "You need a free hand for this rite!") uses += BLOOD_BARRAGE_COST // Refund the charges qdel(rite) - source.UpdateButtonIcon() + source.UpdateButtons() diff --git a/code/game/gamemodes/cult/cult_actions.dm b/code/game/gamemodes/cult/cult_actions.dm index 1bafae2b646..e26efbad2d4 100644 --- a/code/game/gamemodes/cult/cult_actions.dm +++ b/code/game/gamemodes/cult/cult_actions.dm @@ -112,16 +112,12 @@ name = "Draw Blood Rune" desc = "Use the ritual dagger to create a powerful blood rune" button_icon_state = "blood_dagger" + default_button_position = "6:157,4:-2" /datum/action/innate/cult/use_dagger/Grant() button_icon_state = GET_CULT_DATA(dagger_icon, "blood_dagger") ..() -/datum/action/innate/cult/use_dagger/override_location() - button.ordered = FALSE - button.screen_loc = "6:157,4:-2" - button.moved = "6:157,4:-2" - /datum/action/innate/cult/use_dagger/Activate() var/obj/item/melee/cultblade/dagger/D = owner.find_item(/obj/item/melee/cultblade/dagger) if(D) diff --git a/code/game/gamemodes/cult/cult_items.dm b/code/game/gamemodes/cult/cult_items.dm index 0126e8f88a1..dbc810b059a 100644 --- a/code/game/gamemodes/cult/cult_items.dm +++ b/code/game/gamemodes/cult/cult_items.dm @@ -633,6 +633,7 @@ button_icon_state = "bloodspear" var/obj/item/cult_spear/spear var/cooldown = 0 + default_button_position = "6:157,4:-2" /datum/action/innate/cult/spear/Grant(mob/user, obj/blood_spear) . = ..() diff --git a/code/game/gamemodes/malfunction/Malf_Modules.dm b/code/game/gamemodes/malfunction/Malf_Modules.dm index 85dbc3cda17..114bc2a24e5 100644 --- a/code/game/gamemodes/malfunction/Malf_Modules.dm +++ b/code/game/gamemodes/malfunction/Malf_Modules.dm @@ -42,9 +42,10 @@ if(initial(uses) > 1) //no need to tell 'em if it was one-use anyway! to_chat(owner, "[name] has run out of uses!") qdel(src) - else - desc = "[initial(desc)] It has [uses] use\s remaining." - UpdateButtonIcon() + if(QDELETED(src) || uses) //Not sure if not having src here would cause a runtime, so it's here to be safe + return + desc = "[initial(desc)] It has [uses] use\s remaining." + UpdateButtons() //Framework for ranged abilities that can have different effects by left-clicking stuff. /datum/action/innate/ai/ranged @@ -190,7 +191,7 @@ else //Adding uses to an existing module action.uses += initial(action.uses) action.desc = "[initial(action.desc)] It has [action.uses] use\s remaining." - action.UpdateButtonIcon() + action.UpdateButtons() temp = "Additional use[action.uses > 1 ? "s" : ""] added to [action.name]!" processing_time -= AM.cost diff --git a/code/game/gamemodes/miniantags/abduction/abduction_gear.dm b/code/game/gamemodes/miniantags/abduction/abduction_gear.dm index cb0ea1b2811..6c98ab8b3f1 100644 --- a/code/game/gamemodes/miniantags/abduction/abduction_gear.dm +++ b/code/game/gamemodes/miniantags/abduction/abduction_gear.dm @@ -49,7 +49,7 @@ H.update_inv_wear_suit() for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() /obj/item/clothing/suit/armor/abductor/vest/item_action_slot_check(slot, mob/user) if(slot == SLOT_HUD_OUTER_SUIT) //we only give the mob the ability to activate the vest if he's actually wearing it. @@ -426,7 +426,7 @@ Congratulations! You are now trained for invasive xenobiology research!"} update_icon(UPDATE_ICON_STATE) for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() /obj/item/abductor_baton/update_icon_state() switch(mode) diff --git a/code/game/gamemodes/miniantags/guardian/guardian.dm b/code/game/gamemodes/miniantags/guardian/guardian.dm index e9a5c252d88..e56038057e2 100644 --- a/code/game/gamemodes/miniantags/guardian/guardian.dm +++ b/code/game/gamemodes/miniantags/guardian/guardian.dm @@ -30,6 +30,7 @@ melee_damage_upper = 15 AIStatus = AI_OFF butcher_results = list(/obj/item/food/snacks/ectoplasm = 1) + hud_type = /datum/hud/guardian var/summoned = FALSE var/cooldown = 0 var/damage_transfer = 1 //how much damage from each attack we transfer to the owner diff --git a/code/game/gamemodes/miniantags/guardian/host_actions.dm b/code/game/gamemodes/miniantags/guardian/host_actions.dm index 8a622789e34..75157f84991 100644 --- a/code/game/gamemodes/miniantags/guardian/host_actions.dm +++ b/code/game/gamemodes/miniantags/guardian/host_actions.dm @@ -82,7 +82,7 @@ // Do this immediately, so the user can't spam a bunch of polls. cooldown_timer = addtimer(CALLBACK(src, PROC_REF(reset_cooldown)), 5 MINUTES) - UpdateButtonIcon() + UpdateButtons() to_chat(owner, "Searching for a replacement ghost...") var/list/mob/dead/observer/candidates = SSghost_spawns.poll_candidates("Do you want to play as [guardian.real_name]?", ROLE_GUARDIAN, FALSE, 15 SECONDS, source = guardian) @@ -181,7 +181,7 @@ */ /datum/action/guardian/reset_guardian/proc/reset_cooldown() cooldown_timer = null - UpdateButtonIcon() + UpdateButtons() /** * Grants all existing `/datum/action/guardian` type actions to the src mob. diff --git a/code/game/gamemodes/miniantags/morph/morph.dm b/code/game/gamemodes/miniantags/morph/morph.dm index 7f1b0587de8..46a2f0af1d2 100644 --- a/code/game/gamemodes/miniantags/morph/morph.dm +++ b/code/game/gamemodes/miniantags/morph/morph.dm @@ -145,7 +145,7 @@ /mob/living/simple_animal/hostile/morph/proc/add_food(amount) gathered_food += amount for(var/datum/action/spell_action/action in actions) - action.UpdateButtonIcon() + action.UpdateButtons() /mob/living/simple_animal/hostile/morph/proc/assume() @@ -155,8 +155,8 @@ melee_damage_lower = 5 melee_damage_upper = 5 speed = MORPHED_SPEED - ambush_spell.updateButtonIcon() - pass_airlock_spell.updateButtonIcon() + ambush_spell.UpdateButtons() + pass_airlock_spell.UpdateButtons() move_resist = MOVE_FORCE_DEFAULT // They become more fragile and easier to move /mob/living/simple_animal/hostile/morph/proc/restore() @@ -171,7 +171,7 @@ if(ambush_prepared) to_chat(src, "The ambush potential has faded as you take your true form.") failed_ambush() - pass_airlock_spell.updateButtonIcon() + pass_airlock_spell.UpdateButtons() move_resist = MOVE_FORCE_STRONG // Return to their fatness @@ -183,7 +183,7 @@ /mob/living/simple_animal/hostile/morph/proc/failed_ambush() ambush_prepared = FALSE - ambush_spell.updateButtonIcon() + ambush_spell.UpdateButtons() mimic_spell.perfect_disguise = FALSE // Reset the perfect disguise remove_status_effect(/datum/status_effect/morph_ambush) UnregisterSignal(src, COMSIG_MOVABLE_MOVED) diff --git a/code/game/gamemodes/miniantags/pulsedemon/pulsedemon.dm b/code/game/gamemodes/miniantags/pulsedemon/pulsedemon.dm index fa0c590e6b0..664ffe97b59 100644 --- a/code/game/gamemodes/miniantags/pulsedemon/pulsedemon.dm +++ b/code/game/gamemodes/miniantags/pulsedemon/pulsedemon.dm @@ -322,7 +322,7 @@ if(!S.action || S.locked) continue if(S.requires_area) - S.action.UpdateButtonIcon() + S.action.UpdateButtons() // can enter an apc at all? /mob/living/simple_animal/demon/pulse_demon/proc/is_valid_apc(obj/machinery/power/apc/A) @@ -435,7 +435,7 @@ var/dist = S.cast_cost - orig // only update icon if the amount is actually enough to change a spell's availability if(dist == 0 || (dist > 0 && realdelta >= dist) || (dist < 0 && realdelta <= dist)) - S.action.UpdateButtonIcon() + S.action.UpdateButtons() return realdelta // logarithmic scale for glow strength, see table: diff --git a/code/game/gamemodes/miniantags/pulsedemon/pulsedemon_abilities.dm b/code/game/gamemodes/miniantags/pulsedemon/pulsedemon_abilities.dm index 86c22acaeb6..6901e46e7d7 100644 --- a/code/game/gamemodes/miniantags/pulsedemon/pulsedemon_abilities.dm +++ b/code/game/gamemodes/miniantags/pulsedemon/pulsedemon_abilities.dm @@ -32,9 +32,9 @@ else name = "[initial(name)][cast_cost == 0 ? "" : " ([format_si_suffix(cast_cost)]W)"]" desc = "[initial(desc)][spell_level == level_max ? "" : " It costs [format_si_suffix(upgrade_cost)]W to upgrade."]" - action.button.name = name + action.name = name action.desc = desc - action.UpdateButtonIcon() + action.UpdateButtons() /obj/effect/proc_holder/spell/pulse_demon/can_cast(mob/living/simple_animal/demon/pulse_demon/user, charge_check, show_message) if(!..()) @@ -257,7 +257,7 @@ /obj/effect/proc_holder/spell/pulse_demon/toggle/proc/do_toggle(varstate, mob/user) if(action) action.background_icon_state = varstate ? action_background_icon_state : "[action_background_icon_state]_disabled" - action.UpdateButtonIcon() + action.UpdateButtons() if(user) to_chat(user, "You will [varstate ? "now" : "no longer"] [base_message]") return varstate diff --git a/code/game/gamemodes/miniantags/revenant/revenant_abilities.dm b/code/game/gamemodes/miniantags/revenant/revenant_abilities.dm index 2ea56a6ccdf..bc3b622ad25 100644 --- a/code/game/gamemodes/miniantags/revenant/revenant_abilities.dm +++ b/code/game/gamemodes/miniantags/revenant/revenant_abilities.dm @@ -200,7 +200,7 @@ user.reveal(reveal) user.stun(stun) if(action) - action.UpdateButtonIcon() + action.UpdateButtons() return TRUE //Overload Light: Breaks a light that's online and sends out lightning bolts to all nearby people. diff --git a/code/game/jobs/job/support.dm b/code/game/jobs/job/support.dm index 306a441e26a..5d636d988f3 100644 --- a/code/game/jobs/job/support.dm +++ b/code/game/jobs/job/support.dm @@ -358,7 +358,7 @@ singlemutcheck(H, GLOB.clumsyblock, MUTCHK_FORCED) active = TRUE background_icon_state = "bg_spell" - UpdateButtonIcon() + UpdateButtons() to_chat(H, "You start acting clumsy to throw suspicions off. Focus again before using weapons.") /datum/action/innate/toggle_clumsy/Deactivate() @@ -367,7 +367,7 @@ singlemutcheck(H, GLOB.clumsyblock, MUTCHK_FORCED) active = FALSE background_icon_state = "bg_default" - UpdateButtonIcon() + UpdateButtons() to_chat(H, "You focus and can now use weapons regularly.") /datum/job/mime diff --git a/code/game/mecha/mecha_actions.dm b/code/game/mecha/mecha_actions.dm index d638bfe4123..dcafd77e1dc 100644 --- a/code/game/mecha/mecha_actions.dm +++ b/code/game/mecha/mecha_actions.dm @@ -66,7 +66,7 @@ button_icon_state = "mech_internals_[chassis.use_internal_tank ? "on" : "off"]" chassis.occupant_message("Now taking air from [chassis.use_internal_tank ? "internal airtank" : "environment"].") chassis.log_message("Now taking air from [chassis.use_internal_tank ? "internal airtank" : "environment"].") - UpdateButtonIcon() + UpdateButtons() /datum/action/innate/mecha/mech_toggle_lights name = "Toggle Lights" @@ -84,7 +84,7 @@ button_icon_state = "mech_lights_off" chassis.occupant_message("Toggled lights [chassis.lights ? "on" : "off"].") chassis.log_message("Toggled lights [chassis.lights ? "on" : "off"].") - UpdateButtonIcon() + UpdateButtons() /datum/action/innate/mecha/mech_view_stats name = "View Stats" @@ -114,7 +114,7 @@ chassis.deflect_chance = initial(chassis.deflect_chance) chassis.occupant_message("You disable [chassis] defence mode.") chassis.log_message("Toggled defence mode.") - UpdateButtonIcon() + UpdateButtons() /datum/action/innate/mecha/mech_overload_mode name = "Toggle leg actuators overload" @@ -144,7 +144,7 @@ chassis.step_in = initial(chassis.step_in) chassis.step_energy_drain = chassis.normal_step_energy_drain chassis.occupant_message("You disable leg actuators overload.") - UpdateButtonIcon() + UpdateButtons() /datum/action/innate/mecha/mech_toggle_thrusters name = "Toggle Thrusters" @@ -194,7 +194,7 @@ SEND_SOUND(owner, sound(chassis.zoomsound, volume = 50)) else owner.client.RemoveViewMod("mecha") - UpdateButtonIcon() + UpdateButtons() /datum/action/innate/mecha/mech_toggle_phasing name = "Toggle Phasing" @@ -206,7 +206,7 @@ chassis.phasing = !chassis.phasing button_icon_state = "mech_phasing_[chassis.phasing ? "on" : "off"]" chassis.occupant_message("En":"#f00\">Dis"]abled phasing.") - UpdateButtonIcon() + UpdateButtons() /datum/action/innate/mecha/mech_switch_damtype @@ -230,4 +230,4 @@ chassis.damtype = new_damtype button_icon_state = "mech_damtype_[new_damtype]" playsound(src, 'sound/mecha/mechmove01.ogg', 50, 1) - UpdateButtonIcon() + UpdateButtons() diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 222e4ebaa40..fffdab16013 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -179,7 +179,13 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons if(ismob(loc)) var/mob/m = loc m.unEquip(src, 1) - QDEL_LIST_CONTENTS(actions) + // actions clear themselves from the list on cut + if(islist(actions)) + for(var/datum/action/A as anything in actions) + qdel(A) + if(!isnull(actions)) + actions.Cut() + master = null return ..() diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index 909451a633d..5118c56e628 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -39,7 +39,7 @@ update_brightness() for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() return TRUE /obj/item/flashlight/attack(mob/living/M as mob, mob/living/user as mob) diff --git a/code/game/objects/items/devices/traitordevices.dm b/code/game/objects/items/devices/traitordevices.dm index 0282857720a..a8817a1b722 100644 --- a/code/game/objects/items/devices/traitordevices.dm +++ b/code/game/objects/items/devices/traitordevices.dm @@ -28,7 +28,7 @@ else GLOB.active_jammers -= src for(var/datum/action/item_action/toggle_radio_jammer/A in actions) - A.UpdateButtonIcon() + A.UpdateButtons() /obj/item/teleporter name = "syndicate teleporter" diff --git a/code/game/objects/items/devices/voice_changer.dm b/code/game/objects/items/devices/voice_changer.dm index 779409f16c6..1fd3e0bdeb0 100644 --- a/code/game/objects/items/devices/voice_changer.dm +++ b/code/game/objects/items/devices/voice_changer.dm @@ -31,7 +31,7 @@ for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() /obj/item/voice_changer/proc/set_voice(mob/user) var/chosen_voice = clean_input("What voice would you like to mimic? Leave this empty to use the voice on your ID card.", "Set Voice Changer", voice, user) diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 80d1c2da512..e5986a9833c 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -202,7 +202,7 @@ icon_state = "selfrepair_[on ? "on" : "off"]" for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() else icon_state = "cyborg_upgrade5" diff --git a/code/game/objects/items/weapons/bio_chips/bio_chip_stealth.dm b/code/game/objects/items/weapons/bio_chips/bio_chip_stealth.dm index 0dfdf4e864c..8003d7dfe0e 100644 --- a/code/game/objects/items/weapons/bio_chips/bio_chip_stealth.dm +++ b/code/game/objects/items/weapons/bio_chips/bio_chip_stealth.dm @@ -63,11 +63,11 @@ SIGNAL_HANDLER on_cooldown = TRUE addtimer(CALLBACK(src, PROC_REF(end_cooldown)), 10 SECONDS) - UpdateButtonIcon() + UpdateButtons() /datum/action/item_action/agent_box/proc/end_cooldown() on_cooldown = FALSE - UpdateButtonIcon() + UpdateButtons() /datum/action/item_action/agent_box/IsAvailable() if(..() && !on_cooldown) diff --git a/code/game/objects/items/weapons/defib.dm b/code/game/objects/items/weapons/defib.dm index 693084f5069..55b7a9b25a0 100644 --- a/code/game/objects/items/weapons/defib.dm +++ b/code/game/objects/items/weapons/defib.dm @@ -159,7 +159,7 @@ update_icon(UPDATE_OVERLAYS) for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() /obj/item/defibrillator/equipped(mob/user, slot) ..() diff --git a/code/game/objects/items/weapons/holy_weapons.dm b/code/game/objects/items/weapons/holy_weapons.dm index 28dbe865f5c..0cf30e2db5e 100644 --- a/code/game/objects/items/weapons/holy_weapons.dm +++ b/code/game/objects/items/weapons/holy_weapons.dm @@ -375,9 +375,6 @@ melee_attack_chain(attacking_shade, attacking_atom) force += 5 -/mob/living/simple_animal/shade/sword/create_mob_hud() - hud_used = new /datum/hud/sword(src) - /datum/hud/sword/New(mob/user) ..() diff --git a/code/game/objects/items/weapons/tanks/jetpack.dm b/code/game/objects/items/weapons/tanks/jetpack.dm index eace17ea30d..865861edeb0 100644 --- a/code/game/objects/items/weapons/tanks/jetpack.dm +++ b/code/game/objects/items/weapons/tanks/jetpack.dm @@ -52,7 +52,7 @@ to_chat(user, "You turn the jetpack off.") for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() /obj/item/tank/jetpack/proc/turn_on(mob/user) diff --git a/code/game/objects/items/weapons/twohanded.dm b/code/game/objects/items/weapons/twohanded.dm index 694768dd3b9..71a0768a94c 100644 --- a/code/game/objects/items/weapons/twohanded.dm +++ b/code/game/objects/items/weapons/twohanded.dm @@ -448,7 +448,7 @@ user.update_inv_r_hand() for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() /obj/item/chainsaw/attack_hand(mob/user) . = ..() diff --git a/code/modules/antagonists/vampire/vamp_datum.dm b/code/modules/antagonists/vampire/vamp_datum.dm index d5a096bcef5..65625b191a5 100644 --- a/code/modules/antagonists/vampire/vamp_datum.dm +++ b/code/modules/antagonists/vampire/vamp_datum.dm @@ -310,7 +310,7 @@ check_vampire_upgrade(TRUE) for(var/obj/effect/proc_holder/spell/S in powers) if(S.action) - S.action.UpdateButtonIcon() + S.action.UpdateButtons() /datum/antagonist/vampire/proc/vamp_burn(burn_chance) if(prob(burn_chance) && owner.current.health >= 50) diff --git a/code/modules/antagonists/vampire/vampire_powers/umbrae_powers.dm b/code/modules/antagonists/vampire/vampire_powers/umbrae_powers.dm index f00aa187994..5d75d682faf 100644 --- a/code/modules/antagonists/vampire/vampire_powers/umbrae_powers.dm +++ b/code/modules/antagonists/vampire/vampire_powers/umbrae_powers.dm @@ -17,7 +17,9 @@ var/datum/antagonist/vampire/V = user.mind.has_antag_datum(/datum/antagonist/vampire) if(!V) return - action.button.name = "[initial(name)] ([V.iscloaking ? "Deactivate" : "Activate"])" + + action.name = "[initial(name)] ([V.iscloaking ? "Deactivate" : "Activate"])" + UpdateButtons() /obj/effect/proc_holder/spell/vampire/self/cloak/cast(list/targets, mob/user = usr) var/datum/antagonist/vampire/V = user.mind.has_antag_datum(/datum/antagonist/vampire) diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 0aaea933918..113e3d1c4c8 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -1176,6 +1176,11 @@ var/list/screensize = getviewsize(view) return max(screensize[1], screensize[2]) +/client/Click(object, location, control, params) + . = ..() + // please yell at me if this is Too Much + SEND_SIGNAL(src, COMSIG_CLIENT_CLICK, object, location, control, params, usr) + /// Compiles a full list of verbs and sends it to the browser /client/proc/init_verbs() if(IsAdminAdvancedProcCall()) diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index 0387be33942..0bc12e7c74b 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -94,10 +94,14 @@ qdel(O) ..() -/datum/action/item_action/chameleon/change/proc/initialize_disguises() - if(button) +/datum/action/item_action/chameleon/change/UpdateButton(atom/movable/screen/movable/action_button/button, status_only, force) + . = ..() + if(.) button.name = "Change [chameleon_name] Appearance" + +/datum/action/item_action/chameleon/change/proc/initialize_disguises() + UpdateButtons() chameleon_blacklist |= typecacheof(target.type) for(var/V in typesof(chameleon_type)) if(ispath(V) && ispath(V, /obj/item)) @@ -141,7 +145,7 @@ update_item(picked_item) var/obj/item/thing = target thing.update_slot_icon() - UpdateButtonIcon() + UpdateButtons() /datum/action/item_action/chameleon/change/proc/update_item(obj/item/picked_item) target.name = initial(picked_item.name) diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 055bd13fa97..461afdbf469 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -62,7 +62,7 @@ C.head_update(src, forced = 1) for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() return TRUE /obj/item/clothing/proc/visor_toggling() //handles all the actual toggling of flags @@ -446,7 +446,7 @@ usr.update_inv_head() for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() // Changes the speech verb when wearing a mask if a value is returned /obj/item/clothing/mask/proc/change_speech_verb() @@ -646,7 +646,7 @@ to_chat(user, "You [flavour] \the [src].") for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() else var/flavour = "open" icon_state += "_open" @@ -656,7 +656,7 @@ to_chat(user, "You [flavour] \the [src].") for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() suit_adjusted = !suit_adjusted update_icon(UPDATE_ICON_STATE) diff --git a/code/modules/clothing/glasses/engine_goggles.dm b/code/modules/clothing/glasses/engine_goggles.dm index 03bde7c6b0e..e593c0eb03d 100644 --- a/code/modules/clothing/glasses/engine_goggles.dm +++ b/code/modules/clothing/glasses/engine_goggles.dm @@ -65,7 +65,7 @@ update_icon(UPDATE_ICON_STATE) for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() /obj/item/clothing/glasses/meson/engine/attack_self(mob/user) toggle_mode(user, TRUE) diff --git a/code/modules/clothing/head/hardhat.dm b/code/modules/clothing/head/hardhat.dm index 84752b623df..62dda694baf 100644 --- a/code/modules/clothing/head/hardhat.dm +++ b/code/modules/clothing/head/hardhat.dm @@ -36,7 +36,7 @@ H.update_inv_head() for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() /obj/item/clothing/head/hardhat/proc/turn_on(mob/user) set_light(brightness_on) diff --git a/code/modules/clothing/head/soft_caps.dm b/code/modules/clothing/head/soft_caps.dm index c8cdf01e64e..c61869c24b5 100644 --- a/code/modules/clothing/head/soft_caps.dm +++ b/code/modules/clothing/head/soft_caps.dm @@ -32,7 +32,7 @@ for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() /obj/item/clothing/head/soft/red name = "red cap" diff --git a/code/modules/clothing/shoes/magboots.dm b/code/modules/clothing/shoes/magboots.dm index fb1bce27ee5..797006d07ad 100644 --- a/code/modules/clothing/shoes/magboots.dm +++ b/code/modules/clothing/shoes/magboots.dm @@ -52,7 +52,7 @@ user.update_gravity(user.mob_has_gravity()) for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() check_mag_pulse(user) /obj/item/clothing/shoes/magboots/proc/check_mag_pulse(mob/user) diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm index 48520b2adaf..a430ed04f40 100644 --- a/code/modules/clothing/spacesuits/hardsuit.dm +++ b/code/modules/clothing/spacesuits/hardsuit.dm @@ -66,7 +66,7 @@ set_light(0) for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() /obj/item/clothing/head/helmet/space/hardsuit/extinguish_light(force = FALSE) if(on) @@ -310,7 +310,7 @@ C.head_update(src, forced = 1) for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() /obj/item/clothing/head/helmet/space/hardsuit/syndi/proc/toggle_hardsuit_mode(mob/user) //Helmet Toggles Suit Mode if(linkedsuit) diff --git a/code/modules/clothing/spacesuits/plasmamen.dm b/code/modules/clothing/spacesuits/plasmamen.dm index cfc22e69e6e..4519e320e1f 100644 --- a/code/modules/clothing/spacesuits/plasmamen.dm +++ b/code/modules/clothing/spacesuits/plasmamen.dm @@ -45,7 +45,7 @@ . = ..() for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() /obj/item/clothing/head/helmet/space/plasmaman/update_icon_state() if(!up) diff --git a/code/modules/clothing/suits/armor_suits.dm b/code/modules/clothing/suits/armor_suits.dm index a2853fbe952..9a5dda61757 100644 --- a/code/modules/clothing/suits/armor_suits.dm +++ b/code/modules/clothing/suits/armor_suits.dm @@ -434,7 +434,7 @@ user.update_inv_wear_suit() for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() /obj/item/clothing/suit/armor/reactive/emp_act(severity) var/emp_power = 5 + (severity-1 ? 0 : 5) diff --git a/code/modules/clothing/suits/hood.dm b/code/modules/clothing/suits/hood.dm index 723ffb80d1d..7df145f0fa6 100644 --- a/code/modules/clothing/suits/hood.dm +++ b/code/modules/clothing/suits/hood.dm @@ -45,7 +45,7 @@ hood.forceMove(src) for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() /obj/item/clothing/suit/hooded/dropped() ..() @@ -67,7 +67,7 @@ H.update_inv_wear_suit() for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() else if((hood?.flags & NODROP) && respects_nodrop) if(ishuman(loc)) diff --git a/code/modules/clothing/suits/misc_suits.dm b/code/modules/clothing/suits/misc_suits.dm index 648694fa4e2..301c4c86314 100644 --- a/code/modules/clothing/suits/misc_suits.dm +++ b/code/modules/clothing/suits/misc_suits.dm @@ -1085,7 +1085,7 @@ usr.update_inv_wear_suit() for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() /obj/item/clothing/suit/lordadmiral name = "lord admiral's coat" diff --git a/code/modules/customitems/item_defines.dm b/code/modules/customitems/item_defines.dm index 6d2a3cce5a1..aaee4575f7a 100644 --- a/code/modules/customitems/item_defines.dm +++ b/code/modules/customitems/item_defines.dm @@ -1003,7 +1003,7 @@ for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() to_chat(user, "You turn [src]'s lighting system [flavour].") user.update_inv_wear_suit() @@ -1331,7 +1331,7 @@ for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() /obj/item/toy/plushie/fluff/fox/ui_action_click(mob/user) change_color(user) @@ -1407,7 +1407,7 @@ usr.update_inv_head() for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() /// chronx100: Hughe O'Splash /obj/item/clothing/suit/chaplain_hoodie/fluff/chronx diff --git a/code/modules/events/blob/overmind.dm b/code/modules/events/blob/overmind.dm index c31363e81c7..a06f0c1ce15 100644 --- a/code/modules/events/blob/overmind.dm +++ b/code/modules/events/blob/overmind.dm @@ -12,6 +12,8 @@ pass_flags = PASSBLOB faction = list(ROLE_BLOB) + hud_type = /datum/hud/blob_overmind + var/obj/structure/blob/core/blob_core = null // The blob overmind's core var/blob_points = 0 var/max_blob_points = 100 diff --git a/code/modules/games/cards.dm b/code/modules/games/cards.dm index 0093de60001..3746b18a15b 100644 --- a/code/modules/games/cards.dm +++ b/code/modules/games/cards.dm @@ -496,7 +496,7 @@ if(length(cards) <= 2) for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() ..() /obj/item/cardhand/update_name() diff --git a/code/modules/input/keybindings_procs.dm b/code/modules/input/keybindings_procs.dm index 8ae07693672..b5e95307f01 100644 --- a/code/modules/input/keybindings_procs.dm +++ b/code/modules/input/keybindings_procs.dm @@ -14,9 +14,10 @@ active_keybindings[key] += list(KB) if(!mob) // Clients can join before world/new is setup, so we gotta mob check em return active_keybindings - for(var/datum/action/action as anything in mob.actions) - if(action.button?.linked_keybind?.binded_to) - var/datum/keybinding/mob/trigger_action_button/linked_bind = action.button.linked_keybind + for(var/atom/movable/screen/movable/action_button/button as anything in mob.hud_used.get_all_action_buttons()) + // TODO VERIFY THIS (AND KEYBINDS) WORK PROPERLY + if(button.linked_keybind?.binded_to) + var/datum/keybinding/mob/trigger_action_button/linked_bind = button.linked_keybind active_keybindings[linked_bind.binded_to] += list(linked_bind) return active_keybindings diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm index dc43a12ccca..c34741ccaaa 100644 --- a/code/modules/mining/equipment/kinetic_crusher.dm +++ b/code/modules/mining/equipment/kinetic_crusher.dm @@ -185,7 +185,7 @@ spawn(1) for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() //destablizing force /obj/item/projectile/destabilizer diff --git a/code/modules/mining/equipment/regenerative_core.dm b/code/modules/mining/equipment/regenerative_core.dm index 8eed8473919..2df3f2bd9fc 100644 --- a/code/modules/mining/equipment/regenerative_core.dm +++ b/code/modules/mining/equipment/regenerative_core.dm @@ -129,7 +129,7 @@ . += "legion_soul_crackle" for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() /obj/item/organ/internal/regenerative_core/legion/go_inert() ..() diff --git a/code/modules/mob/dead/observer/observer_base.dm b/code/modules/mob/dead/observer/observer_base.dm index 78185dc9e3e..2c5640f1915 100644 --- a/code/modules/mob/dead/observer/observer_base.dm +++ b/code/modules/mob/dead/observer/observer_base.dm @@ -39,6 +39,7 @@ GLOBAL_DATUM_INIT(ghost_crew_monitor, /datum/ui_module/crew_monitor/ghost, new) var/datum/orbit_menu/orbit_menu /// The "color" their runechat would have had var/alive_runechat_color = "#FFFFFF" + hud_type = /datum/hud/ghost /mob/dead/observer/New(mob/body=null, flags=1) set_invisibility(GLOB.observer_default_invisibility) diff --git a/code/modules/mob/inventory_procs.dm b/code/modules/mob/inventory_procs.dm index 171aeaf9c2f..fb4369f170e 100644 --- a/code/modules/mob/inventory_procs.dm +++ b/code/modules/mob/inventory_procs.dm @@ -114,7 +114,7 @@ W.forceMove(drop_location()) W.layer = initial(W.layer) W.plane = initial(W.plane) - W.dropped() + W.dropped(src) /mob/proc/drop_item_v() //this is dumb. if(stat == CONSCIOUS && isturf(loc)) diff --git a/code/modules/mob/living/brain/MMI.dm b/code/modules/mob/living/brain/MMI.dm index 5b0293c0bb2..7a0acac7751 100644 --- a/code/modules/mob/living/brain/MMI.dm +++ b/code/modules/mob/living/brain/MMI.dm @@ -81,7 +81,7 @@ alien = 0 if(radio_action) - radio_action.UpdateButtonIcon() + radio_action.UpdateButtons() SSblackbox.record_feedback("amount", "mmis_filled", 1) else to_chat(user, "You can't drop [B]!") @@ -180,7 +180,7 @@ /obj/item/mmi/proc/become_occupied(new_icon) icon_state = new_icon if(radio) - radio_action.UpdateButtonIcon() + radio_action.UpdateButtons() /obj/item/mmi/examine(mob/user) . = ..() diff --git a/code/modules/mob/living/carbon/alien/alien_base.dm b/code/modules/mob/living/carbon/alien/alien_base.dm index 9a6ae766c88..8392f8a09bf 100644 --- a/code/modules/mob/living/carbon/alien/alien_base.dm +++ b/code/modules/mob/living/carbon/alien/alien_base.dm @@ -213,7 +213,7 @@ Des: Removes all infected images from the alien. and carry the owner just to make sure*/ /mob/living/carbon/proc/update_plasma_display(mob/owner) for(var/datum/action/spell_action/action in actions) - action.UpdateButtonIcon() + action.UpdateButtons() if(!hud_used || !isalien(owner)) //clientless aliens or non aliens return hud_used.alien_plasma_display.maptext = "
[get_plasma()]
" diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm index 5b139d6652d..f952bfe2797 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm @@ -14,6 +14,7 @@ var/alien_movement_delay = 0 //This can be + or -, how fast an alien moves var/temperature_resistance = T0C+75 pass_flags = PASSTABLE + hud_type = /datum/hud/alien //This is fine right now, if we're adding organ specific damage this needs to be updated /mob/living/carbon/alien/humanoid/Initialize(mapload) @@ -32,9 +33,9 @@ return FALSE /mob/living/carbon/alien/humanoid/emp_act(severity) - if(r_store) + if(r_store) r_store.emp_act(severity) - if(l_store) + if(l_store) l_store.emp_act(severity) ..() diff --git a/code/modules/mob/living/carbon/alien/larva/larva.dm b/code/modules/mob/living/carbon/alien/larva/larva.dm index f6508a8286b..7f9bb302712 100644 --- a/code/modules/mob/living/carbon/alien/larva/larva.dm +++ b/code/modules/mob/living/carbon/alien/larva/larva.dm @@ -14,6 +14,7 @@ var/max_grown = 200 death_message = "lets out a waning high-pitched cry." death_sound = null + hud_type = /datum/hud/larva //This is fine right now, if we're adding organ specific damage this needs to be updated /mob/living/carbon/alien/larva/Initialize(mapload) diff --git a/code/modules/mob/living/carbon/human/species/golem.dm b/code/modules/mob/living/carbon/human/species/golem.dm index ac5c1a5f8e4..2c1426512ea 100644 --- a/code/modules/mob/living/carbon/human/species/golem.dm +++ b/code/modules/mob/living/carbon/human/species/golem.dm @@ -541,9 +541,9 @@ H.buckled.unbuckle_mob(H, force = TRUE) do_teleport(H, picked) last_teleport = world.time - UpdateButtonIcon() //action icon looks unavailable + UpdateButtons() //action icon looks unavailable sleep(cooldown + 5) - UpdateButtonIcon() //action icon looks available again + UpdateButtons() //action icon looks available again /datum/unarmed_attack/golem/bluespace attack_verb = "bluespace punch" diff --git a/code/modules/mob/living/silicon/ai/ai_mob.dm b/code/modules/mob/living/silicon/ai/ai_mob.dm index 9711290c71b..f660e415f72 100644 --- a/code/modules/mob/living/silicon/ai/ai_mob.dm +++ b/code/modules/mob/living/silicon/ai/ai_mob.dm @@ -47,6 +47,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list( see_invisible = SEE_INVISIBLE_LIVING_AI see_in_dark = 8 can_strip = FALSE + hud_type = /datum/hud/ai hat_offset_y = 3 is_centered = TRUE can_be_hatted = TRUE diff --git a/code/modules/mob/living/silicon/robot/robot_mob.dm b/code/modules/mob/living/silicon/robot/robot_mob.dm index 1bde5789c74..420db674ac7 100644 --- a/code/modules/mob/living/silicon/robot/robot_mob.dm +++ b/code/modules/mob/living/silicon/robot/robot_mob.dm @@ -13,6 +13,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( universal_understand = TRUE deathgasp_on_death = TRUE blocks_emissive = EMISSIVE_BLOCK_UNIQUE + hud_type = /datum/hud/robot var/sight_mode = 0 var/custom_name = "" diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index cf9c15ffaa6..c03dcb1b381 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -17,6 +17,7 @@ sentience_type = SENTIENCE_ARTIFICIAL status_flags = 0 // No default canpush can_strip = FALSE + hud_type = /datum/hud/bot speak_emote = list("states") friendly = "boops" @@ -139,6 +140,7 @@ /// Will be true if we lost target we were chasing var/lost_target = FALSE + /obj/item/radio/headset/bot requires_tcomms = FALSE canhear_range = 0 diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm index b02d0a309f7..1540c3aaf06 100644 --- a/code/modules/mob/living/simple_animal/constructs.dm +++ b/code/modules/mob/living/simple_animal/constructs.dm @@ -139,6 +139,7 @@ desc = "A possessed suit of armour driven by the will of the restless dead" icon_state = "behemoth" icon_living = "behemoth" + hud_type = /datum/hud/construct/armoured maxHealth = 250 health = 250 response_harm = "harmlessly punches" @@ -182,6 +183,7 @@ desc = "A wicked bladed shell contraption piloted by a bound spirit" icon_state = "floating" icon_living = "floating" + hud_type = /datum/hud/construct/wraith maxHealth = 75 health = 75 melee_damage_lower = 25 @@ -211,6 +213,7 @@ desc = "A bulbous construct dedicated to building and maintaining Cult armies." icon_state = "artificer" icon_living = "artificer" + hud_type = /datum/hud/construct/builder maxHealth = 50 health = 50 response_harm = "viciously beats" @@ -304,6 +307,7 @@ attack_sound = 'sound/weapons/punch4.ogg' force_threshold = 11 construct_type = "behemoth" + hud_type = /datum/hud/construct/armoured var/energy = 0 var/max_energy = 1000 @@ -321,6 +325,7 @@ desc = "A harbinger of enlightenment. It'll be all over soon." icon_state = "harvester" icon_living = "harvester" + hud_type = /datum/hud/construct/harvester maxHealth = 40 health = 40 melee_damage_lower = 20 diff --git a/code/modules/mob/living/simple_animal/friendly/dog.dm b/code/modules/mob/living/simple_animal/friendly/dog.dm index af1762e3bcc..6886ae40901 100644 --- a/code/modules/mob/living/simple_animal/friendly/dog.dm +++ b/code/modules/mob/living/simple_animal/friendly/dog.dm @@ -74,6 +74,7 @@ childtype = list(/mob/living/simple_animal/pet/dog/corgi/puppy = 95, /mob/living/simple_animal/pet/dog/corgi/puppy/void = 5) animal_species = /mob/living/simple_animal/pet/dog collar_type = "corgi" + hud_type = /datum/hud/corgi var/obj/item/inventory_head var/obj/item/inventory_back var/shaved = FALSE diff --git a/code/modules/mob/living/simple_animal/friendly/pet.dm b/code/modules/mob/living/simple_animal/friendly/pet.dm index c7735d55ccd..5c5003dcf21 100644 --- a/code/modules/mob/living/simple_animal/friendly/pet.dm +++ b/code/modules/mob/living/simple_animal/friendly/pet.dm @@ -5,6 +5,7 @@ blood_volume = BLOOD_VOLUME_NORMAL can_collar = TRUE speed = 0 // same speed as a person. + hud_type = /datum/hud/corgi /mob/living/simple_animal/pet/attackby(obj/item/O, mob/user, params) if(istype(O, /obj/item/newspaper)) diff --git a/code/modules/mob/living/simple_animal/hostile/mining/elites/elite.dm b/code/modules/mob/living/simple_animal/hostile/mining/elites/elite.dm index 1785a9682d8..5c6f883a02e 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining/elites/elite.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining/elites/elite.dm @@ -111,8 +111,8 @@ While using this makes the system rely on OnFire, it still gives options for tim ///The internal attack ID for the elite's OpenFire() proc to use var/chosen_attack_num = 0 -/datum/action/innate/elite_attack/New(Target) - . = ..() +/datum/action/innate/elite_attack/CreateButton() + var/atom/movable/screen/movable/action_button/button = ..() button.maptext = "" button.maptext_x = 8 button.maptext_y = 0 @@ -127,7 +127,7 @@ While using this makes the system rely on OnFire, it still gives options for tim return UpdateButton() -/datum/action/innate/elite_attack/proc/UpdateButton(status_only = FALSE) +/datum/action/innate/elite_attack/UpdateButton(atom/movable/screen/movable/action_button/button, status_only = FALSE, force = FALSE) if(status_only) return var/mob/living/simple_animal/hostile/asteroid/elite/elite_owner = owner diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/empress_terror.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/empress_terror.dm index 4c8524671b3..a17cdffafdb 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/empress_terror.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/empress_terror.dm @@ -46,7 +46,8 @@ /mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/NestMode() ..() - queeneggs_action.button.name = "Empress Eggs" + queeneggs_action.name = "Empress Eggs" + queeneggs_action.UpdateButtons() /mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/LayQueenEggs() var/eggtype = tgui_input_list(src, "What kind of eggs?", "Egg laying", list(TS_DESC_QUEEN, TS_DESC_MOTHER, TS_DESC_PRINCE, TS_DESC_PRINCESS, TS_DESC_RED, TS_DESC_GRAY, TS_DESC_GREEN, TS_DESC_BLACK, TS_DESC_PURPLE, TS_DESC_WHITE, TS_DESC_BROWN)) diff --git a/code/modules/mob/living/simple_animal/shade.dm b/code/modules/mob/living/simple_animal/shade.dm index ca63f9a1217..bd5b9b270d3 100644 --- a/code/modules/mob/living/simple_animal/shade.dm +++ b/code/modules/mob/living/simple_animal/shade.dm @@ -66,6 +66,7 @@ health = 100 maxHealth = 100 weather_immunities = list("ash") + hud_type = /datum/hud/sword /mob/living/simple_animal/shade/sword/Initialize(mapload) .=..() diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index d7e94514dc2..9df1fb62e00 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -4,6 +4,7 @@ health = 20 maxHealth = 20 gender = PLURAL //placeholder + hud_type = /datum/hud/simple_animal universal_understand = TRUE universal_speak = FALSE diff --git a/code/modules/mob/living/simple_animal/slime/slime_mob.dm b/code/modules/mob/living/simple_animal/slime/slime_mob.dm index 7ac51e83d0c..2e4fca91f6f 100644 --- a/code/modules/mob/living/simple_animal/slime/slime_mob.dm +++ b/code/modules/mob/living/simple_animal/slime/slime_mob.dm @@ -2,6 +2,7 @@ name = "grey baby slime (123)" icon = 'icons/mob/slimes.dmi' icon_state = "grey baby slime" + hud_type = /datum/hud/slime pass_flags = PASSTABLE | PASSGRILLE ventcrawler = VENTCRAWLER_ALWAYS gender = NEUTER diff --git a/code/modules/mob/living/stat_states.dm b/code/modules/mob/living/stat_states.dm index c55ba82fedd..e46e0aac96c 100644 --- a/code/modules/mob/living/stat_states.dm +++ b/code/modules/mob/living/stat_states.dm @@ -76,7 +76,7 @@ if(mind) for(var/S in mind.spell_list) var/obj/effect/proc_holder/spell/spell = S - spell.updateButtonIcon() + spell.UpdateButtons() return TRUE diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index c4388e17cf5..3a8a7459958 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -5,7 +5,8 @@ input_focus = null if(s_active) s_active.close(src) - QDEL_NULL(hud_used) + if(!QDELETED(hud_used)) + QDEL_NULL(hud_used) if(mind && mind.current == src) spellremove() mobspellremove() diff --git a/code/modules/mob/mob_vars.dm b/code/modules/mob/mob_vars.dm index cab03a2c440..2b3e4cc88e1 100644 --- a/code/modules/mob/mob_vars.dm +++ b/code/modules/mob/mob_vars.dm @@ -84,6 +84,7 @@ var/obj/item/storage/s_active = null //Carbon var/obj/item/clothing/mask/wear_mask = null //Carbon + /// The instantiated version of the mob's hud. var/datum/hud/hud_used = null hud_possible = list(SPECIALROLE_HUD) @@ -121,6 +122,9 @@ var/move_on_shuttle = TRUE // Can move on the shuttle. + /// The type of HUD that this mob uses. Not to + var/hud_type = /datum/hud + var/antagHUD = FALSE // Whether AntagHUD is active right now var/can_change_intents = TRUE //all mobs can change intents by default. ///Override for sound_environments. If this is set the user will always hear a specific type of reverb (Instead of the area defined reverb) diff --git a/code/modules/mod/mod_actions.dm b/code/modules/mod/mod_actions.dm index f2108b27782..3a8f5a9e694 100644 --- a/code/modules/mod/mod_actions.dm +++ b/code/modules/mod/mod_actions.dm @@ -49,7 +49,7 @@ if(!ready && left_click) ready = TRUE button_icon_state = "activate-ready" - UpdateButtonIcon() + UpdateButtons() addtimer(CALLBACK(src, PROC_REF(reset_ready)), 3 SECONDS) return var/obj/item/mod/control/mod = target @@ -60,7 +60,7 @@ /datum/action/item_action/mod/activate/proc/reset_ready() ready = FALSE button_icon_state = initial(button_icon_state) - UpdateButtonIcon() + UpdateButtons() /datum/action/item_action/mod/module name = "Toggle Module" diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index d4b5bbfdb41..ed3abfcfec5 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -388,7 +388,7 @@ for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() /obj/item/gun/proc/clear_bayonet() if(!bayonet) diff --git a/code/modules/projectiles/guns/projectile/automatic.dm b/code/modules/projectiles/guns/projectile/automatic.dm index c83645824c5..94e39bc7f68 100644 --- a/code/modules/projectiles/guns/projectile/automatic.dm +++ b/code/modules/projectiles/guns/projectile/automatic.dm @@ -63,7 +63,7 @@ update_icon() for(var/X in actions) var/datum/action/A = X - A.UpdateButtonIcon() + A.UpdateButtons() /obj/item/gun/projectile/automatic/can_shoot() return get_ammo() diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm index 4c0d3967f50..c2e847de6a9 100644 --- a/code/modules/surgery/organs/heart.dm +++ b/code/modules/surgery/organs/heart.dm @@ -180,7 +180,9 @@ /datum/action/item_action/organ_action/cursed_heart/proc/poll_keybinds() if(alert(owner, "You've been given a cursed heart! Do you want to bind its action to a keybind?", "Cursed Heart", "Yes", "No") == "Yes") - button.set_to_keybind(owner) + return + // button.set_to_keybind(owner) + // TODO GAHHH SORRY GDN /obj/item/organ/internal/heart/cybernetic name = "cybernetic heart" diff --git a/code/modules/surgery/organs/subtypes/skrell_organs.dm b/code/modules/surgery/organs/subtypes/skrell_organs.dm index de58d05a866..25506e7b210 100644 --- a/code/modules/surgery/organs/subtypes/skrell_organs.dm +++ b/code/modules/surgery/organs/subtypes/skrell_organs.dm @@ -22,7 +22,7 @@ /obj/item/organ/internal/headpocket/proc/update_button_state() for(var/datum/action/item_action/T in actions) T.button_icon_state = "skrell_headpocket[held_item ? "_out" : "_in"]" - T.UpdateButtonIcon() + T.UpdateButtons() /obj/item/organ/internal/headpocket/Destroy() empty_contents() diff --git a/icons/hud/64x16_actions.dmi b/icons/hud/64x16_actions.dmi new file mode 100644 index 00000000000..ae81ace4d55 Binary files /dev/null and b/icons/hud/64x16_actions.dmi differ diff --git a/icons/mob/screen_ai.dmi b/icons/mob/screen_ai.dmi index 78071da391f..df250d94beb 100644 Binary files a/icons/mob/screen_ai.dmi and b/icons/mob/screen_ai.dmi differ diff --git a/icons/mob/screen_alien.dmi b/icons/mob/screen_alien.dmi index 209ec839939..6275b65a437 100644 Binary files a/icons/mob/screen_alien.dmi and b/icons/mob/screen_alien.dmi differ diff --git a/icons/mob/screen_gen.dmi b/icons/mob/screen_gen.dmi index 6da1291ff4e..194bbec0303 100644 Binary files a/icons/mob/screen_gen.dmi and b/icons/mob/screen_gen.dmi differ diff --git a/icons/mob/screen_midnight.dmi b/icons/mob/screen_midnight.dmi index 8d1f1648cf5..9352fb36540 100644 Binary files a/icons/mob/screen_midnight.dmi and b/icons/mob/screen_midnight.dmi differ diff --git a/icons/mob/screen_operative.dmi b/icons/mob/screen_operative.dmi index 4abe226fa84..422f63089b4 100644 Binary files a/icons/mob/screen_operative.dmi and b/icons/mob/screen_operative.dmi differ diff --git a/icons/mob/screen_plasmafire.dmi b/icons/mob/screen_plasmafire.dmi index a9f2a25bd1a..fe5fd3a782c 100644 Binary files a/icons/mob/screen_plasmafire.dmi and b/icons/mob/screen_plasmafire.dmi differ diff --git a/icons/mob/screen_retro.dmi b/icons/mob/screen_retro.dmi index 0f2d9ed91e0..292fea07106 100644 Binary files a/icons/mob/screen_retro.dmi and b/icons/mob/screen_retro.dmi differ diff --git a/icons/mob/screen_robot.dmi b/icons/mob/screen_robot.dmi index 2fb11de46ab..264bfb66ff7 100644 Binary files a/icons/mob/screen_robot.dmi and b/icons/mob/screen_robot.dmi differ diff --git a/icons/mob/screen_slimecore.dmi b/icons/mob/screen_slimecore.dmi index 2cbc53e7ba1..44253c19608 100644 Binary files a/icons/mob/screen_slimecore.dmi and b/icons/mob/screen_slimecore.dmi differ diff --git a/icons/mouse_icons/screen_drag.dmi b/icons/mouse_icons/screen_drag.dmi new file mode 100644 index 00000000000..48e4fce85f7 Binary files /dev/null and b/icons/mouse_icons/screen_drag.dmi differ diff --git a/paradise.dme b/paradise.dme index 9109a7e1c8d..842679f672c 100644 --- a/paradise.dme +++ b/paradise.dme @@ -29,6 +29,7 @@ #include "code\__DEFINES\_versions.dm" #include "code\__DEFINES\access_defines.dm" #include "code\__DEFINES\action_button_defines.dm" +#include "code\__DEFINES\action_defines.dm" #include "code\__DEFINES\admin_defines.dm" #include "code\__DEFINES\announce_defines.dm" #include "code\__DEFINES\antag_defines.dm" @@ -159,6 +160,7 @@ #include "code\__HELPERS\qdel.dm" #include "code\__HELPERS\radiation_helpers.dm" #include "code\__HELPERS\sanitize_values.dm" +#include "code\__HELPERS\screen_objs.dm" #include "code\__HELPERS\stacktrace.dm" #include "code\__HELPERS\string_assoc_lists.dm" #include "code\__HELPERS\text.dm" @@ -205,6 +207,7 @@ #include "code\_onclick\overmind_onclick.dm" #include "code\_onclick\telekinesis.dm" #include "code\_onclick\hud\action_button.dm" +#include "code\_onclick\hud\action_group.dm" #include "code\_onclick\hud\ai_hud.dm" #include "code\_onclick\hud\alert.dm" #include "code\_onclick\hud\alien_hud.dm"