[MIRROR] Action button refactor/rework: Enhanced Dragging [MDB IGNORE] (#12423)

* Action button refactor/rework: Enhanced Dragging

* PHEW

Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
Co-authored-by: Gandalf <9026500+Gandalf2k15@users.noreply.github.com>
This commit is contained in:
SkyratBot
2022-04-01 02:38:57 +02:00
committed by GitHub
parent 2f25875974
commit cec72761ac
79 changed files with 1334 additions and 721 deletions

View File

@@ -1,8 +1,10 @@
// Atom mouse signals. Format: // mouse signals. Format:
// When the signal is called: (signal arguments) // When the signal is called: (signal arguments)
// All signals send the source datum of the signal as the first argument // All signals send the source datum of the signal as the first argument
///from base of atom/Click(): (location, control, params, mob/user) ///from base of client/Click(): (atom/target, atom/location, control, params, mob/user)
#define COMSIG_CLIENT_CLICK "atom_client_click"
///from base of atom/Click(): (atom/location, control, params, mob/user)
#define COMSIG_CLICK "atom_click" #define COMSIG_CLICK "atom_click"
///from base of atom/ShiftClick(): (/mob) ///from base of atom/ShiftClick(): (/mob)
#define COMSIG_CLICK_SHIFT "shift_click" #define COMSIG_CLICK_SHIFT "shift_click"

View File

@@ -14,3 +14,202 @@
#define APPEARANCE_UI_IGNORE_ALPHA (RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|RESET_ALPHA|PIXEL_SCALE) #define APPEARANCE_UI_IGNORE_ALPHA (RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|RESET_ALPHA|PIXEL_SCALE)
/// Used for HUD objects /// Used for HUD objects
#define APPEARANCE_UI (RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|PIXEL_SCALE) #define APPEARANCE_UI (RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|PIXEL_SCALE)
/*
These defines specificy screen locations. For more information, see the byond documentation on the screen_loc var.
The short version:
Everything is encoded as strings because apparently that's how Byond rolls.
"1,1" is the bottom left square of the user's screen. This aligns perfectly with the turf grid.
"1:2,3:4" is the square (1,3) with pixel offsets (+2, +4); slightly right and slightly above the turf grid.
Pixel offsets are used so you don't perfectly hide the turf under them, that would be crappy.
In addition, the keywords NORTH, SOUTH, EAST, WEST and CENTER can be used to represent their respective
screen borders. NORTH-1, for example, is the row just below the upper edge. Useful if you want your
UI to scale with screen size.
The size of the user's screen is defined by client.view (indirectly by world.view), in our case "15x15".
Therefore, the top right corner (except during admin shenanigans) is at "15,15"
*/
/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)
var/y_off = round((M.held_items.len-1) / 2) //values based on old equip ui position (CENTER: +/-16,SOUTH+1:5)
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((M.held_items.len-1) / 2)
return "CENTER+[x_off]:16,SOUTH+[y_off+1]:5"
//Lower left, persistent menu
#define ui_inventory "WEST:6,SOUTH:5"
//Middle left indicators
#define ui_lingchemdisplay "WEST,CENTER-1:15"
#define ui_lingstingdisplay "WEST:6,CENTER-3:11"
//Lower center, persistent menu
#define ui_sstore1 "CENTER-5:10,SOUTH:5"
#define ui_id "CENTER-4:12,SOUTH:5"
#define ui_belt "CENTER-3:14,SOUTH:5"
#define ui_back "CENTER-2:14,SOUTH:5"
#define ui_storage1 "CENTER+1:18,SOUTH:5"
#define ui_storage2 "CENTER+2:20,SOUTH:5"
#define ui_combo "CENTER+4:24,SOUTH+1:7" //combo meter for martial arts
//Lower right, persistent menu
#define ui_drop_throw "EAST-1:28,SOUTH+1:7"
#define ui_above_movement "EAST-2:26,SOUTH+1:7"
#define ui_above_intent "EAST-3:24, SOUTH+1:7"
#define ui_movi "EAST-2:26,SOUTH:5"
#define ui_acti "EAST-3:24,SOUTH:5"
#define ui_combat_toggle "EAST-3:24,SOUTH:5"
#define ui_zonesel "EAST-1:28,SOUTH:5"
#define ui_acti_alt "EAST-1:28,SOUTH:5" //alternative intent switcher for when the interface is hidden (F12)
#define ui_crafting "EAST-4:22,SOUTH:5"
#define ui_building "EAST-4:22,SOUTH:21"
#define ui_language_menu "EAST-4:6,SOUTH:21"
#define ui_skill_menu "EAST-4:22,SOUTH:5"
//Upper-middle right (alerts)
#define ui_alert1 "EAST-1:28,CENTER+5:27"
#define ui_alert2 "EAST-1:28,CENTER+4:25"
#define ui_alert3 "EAST-1:28,CENTER+3:23"
#define ui_alert4 "EAST-1:28,CENTER+2:21"
#define ui_alert5 "EAST-1:28,CENTER+1:19"
//Upper left (action buttons)
#define ui_action_palette "WEST+0:23,NORTH-1:5"
#define ui_action_palette_offset(north_offset) ("WEST+0:23,NORTH-[1+north_offset]:5")
#define ui_palette_scroll "WEST+1:8,NORTH-6:28"
#define ui_palette_scroll_offset(north_offset) ("WEST+1:8,NORTH-[6+north_offset]:28")
//Middle right (status indicators)
#define ui_healthdoll "EAST-1:28,CENTER-2:13"
#define ui_health "EAST-1:28,CENTER-1:15"
#define ui_internal "EAST-1:28,CENTER+1:17"
#define ui_mood "EAST-1:28,CENTER:17"
#define ui_spacesuit "EAST-1:28,CENTER-4:10"
#define ui_stamina "EAST-1:28,CENTER-3:10"
//Pop-up inventory
#define ui_shoes "WEST+1:8,SOUTH:5"
#define ui_iclothing "WEST:6,SOUTH+1:7"
#define ui_oclothing "WEST+1:8,SOUTH+1:7"
#define ui_gloves "WEST+2:10,SOUTH+1:7"
#define ui_glasses "WEST:6,SOUTH+3:11"
#define ui_mask "WEST+1:8,SOUTH+2:9"
#define ui_ears "WEST+2:10,SOUTH+2:9"
#define ui_neck "WEST:6,SOUTH+2:9"
#define ui_head "WEST+1:8,SOUTH+3:11"
//Generic living
#define ui_living_pull "EAST-1:28,CENTER-3:15"
#define ui_living_healthdoll "EAST-1:28,CENTER-1:15"
//Monkeys
#define ui_monkey_head "CENTER-5:13,SOUTH:5"
#define ui_monkey_mask "CENTER-4:14,SOUTH:5"
#define ui_monkey_neck "CENTER-3:15,SOUTH:5"
#define ui_monkey_back "CENTER-2:16,SOUTH:5"
//Drones
#define ui_drone_drop "CENTER+1:18,SOUTH:5"
#define ui_drone_pull "CENTER+2:2,SOUTH:5"
#define ui_drone_storage "CENTER-2:14,SOUTH:5"
#define ui_drone_head "CENTER-3:14,SOUTH:5"
//Cyborgs
#define ui_borg_health "EAST-1:28,CENTER-1:15"
#define ui_borg_pull "EAST-2:26,SOUTH+1:7"
#define ui_borg_radio "EAST-1:28,SOUTH+1:7"
#define ui_borg_intents "EAST-2:26,SOUTH:5"
#define ui_borg_lamp "CENTER-3:16, SOUTH:5"
#define ui_borg_tablet "CENTER-4:16, SOUTH:5"
#define ui_inv1 "CENTER-2:16,SOUTH:5"
#define ui_inv2 "CENTER-1 :16,SOUTH:5"
#define ui_inv3 "CENTER :16,SOUTH:5"
#define ui_borg_module "CENTER+1:16,SOUTH:5"
#define ui_borg_store "CENTER+2:16,SOUTH:5"
#define ui_borg_camera "CENTER+3:21,SOUTH:5"
#define ui_borg_alerts "CENTER+4:21,SOUTH:5"
#define ui_borg_language_menu "CENTER+4:19,SOUTH+1:6"
//Aliens
#define ui_alien_health "EAST,CENTER-1:15"
#define ui_alienplasmadisplay "EAST,CENTER-2:15"
#define ui_alien_queen_finder "EAST,CENTER-3:15"
#define ui_alien_storage_r "CENTER+1:18,SOUTH:5"
#define ui_alien_language_menu "EAST-4:20,SOUTH:5"
//AI
#define ui_ai_core "SOUTH:6,WEST"
#define ui_ai_camera_list "SOUTH:6,WEST+1"
#define ui_ai_track_with_camera "SOUTH:6,WEST+2"
#define ui_ai_camera_light "SOUTH:6,WEST+3"
#define ui_ai_crew_monitor "SOUTH:6,WEST+4"
#define ui_ai_crew_manifest "SOUTH:6,WEST+5"
#define ui_ai_alerts "SOUTH:6,WEST+6"
#define ui_ai_announcement "SOUTH:6,WEST+7"
#define ui_ai_shuttle "SOUTH:6,WEST+8"
#define ui_ai_state_laws "SOUTH:6,WEST+9"
#define ui_ai_pda_send "SOUTH:6,WEST+10"
#define ui_ai_pda_log "SOUTH:6,WEST+11"
#define ui_ai_take_picture "SOUTH:6,WEST+12"
#define ui_ai_view_images "SOUTH:6,WEST+13"
#define ui_ai_sensor "SOUTH:6,WEST+14"
#define ui_ai_multicam "SOUTH+1:6,WEST+13"
#define ui_ai_add_multicam "SOUTH+1:6,WEST+14"
#define ui_ai_language_menu "SOUTH+1:8,WEST+11:30"
//pAI
#define ui_pai_software "SOUTH:6,WEST"
#define ui_pai_shell "SOUTH:6,WEST+1"
#define ui_pai_chassis "SOUTH:6,WEST+2"
#define ui_pai_rest "SOUTH:6,WEST+3"
#define ui_pai_light "SOUTH:6,WEST+4"
#define ui_pai_newscaster "SOUTH:6,WEST+5"
#define ui_pai_host_monitor "SOUTH:6,WEST+6"
#define ui_pai_crew_manifest "SOUTH:6,WEST+7"
#define ui_pai_state_laws "SOUTH:6,WEST+8"
#define ui_pai_pda_send "SOUTH:6,WEST+9"
#define ui_pai_pda_log "SOUTH:6,WEST+10"
#define ui_pai_internal_gps "SOUTH:6,WEST+11"
#define ui_pai_take_picture "SOUTH:6,WEST+12"
#define ui_pai_view_images "SOUTH:6,WEST+13"
#define ui_pai_radio "SOUTH:6,WEST+14"
#define ui_pai_language_menu "SOUTH+1:8,WEST+13:31"
//Ghosts
#define ui_ghost_spawners_menu "SOUTH:6,CENTER-3:24"
#define ui_ghost_orbit "SOUTH:6,CENTER-2:24"
#define ui_ghost_reenter_corpse "SOUTH:6,CENTER-1:24"
#define ui_ghost_teleport "SOUTH:6,CENTER:24"
#define ui_ghost_pai "SOUTH: 6, CENTER+1:24"
#define ui_ghost_minigames "SOUTH: 6, CENTER+2:24"
#define ui_ghost_language_menu "SOUTH: 22, CENTER+3:8"
//Blobbernauts
#define ui_blobbernaut_overmind_health "EAST-1:28,CENTER+0:19"
//Families
#define ui_wanted_lvl "NORTH,11"
// 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"

View File

@@ -0,0 +1,18 @@
// ERP stuff
#define ui_vagina "WEST+1:8,SOUTH+4:14"
#define ui_vagina_down "WEST+1:8,SOUTH+1:8"
#define ui_anus "WEST+2:10,SOUTH+4:14"
#define ui_anus_down "WEST+2:10,SOUTH+1:8"
#define ui_nipples "WEST:6,SOUTH+5:17"
#define ui_nipples_down "WEST:6,SOUTH+2:11"
#define ui_penis "WEST+1:8,SOUTH+5:17"
#define ui_penis_down "WEST+1:8,SOUTH+2:11"
#define ui_erp_inventory "WEST:6,SOUTH+1:8"
#define ui_erp_inventory_up "WEST:6,SOUTH+4:14"
// Cyborg PDA
#define ui_borg_pda_send "CENTER+5:21,SOUTH:5" // To the right of the alert panel
#define ui_borg_pda_log "CENTER+6:21,SOUTH:5"
// Ammo counter
#define ui_ammocounter "EAST-1:28,CENTER-5:9"

View File

@@ -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, "")

View File

@@ -6,6 +6,15 @@
var/list/viewrangelist = splittext(view,"x") var/list/viewrangelist = splittext(view,"x")
return list(text2num(viewrangelist[1]), text2num(viewrangelist[2])) return list(text2num(viewrangelist[1]), text2num(viewrangelist[2]))
/// 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
/proc/in_view_range(mob/user, atom/A) /proc/in_view_range(mob/user, atom/A)
var/list/view_range = getviewsize(user.client.view) var/list/view_range = getviewsize(user.client.view)
var/turf/source = get_turf(user) var/turf/source = get_turf(user)

View File

@@ -92,26 +92,26 @@
if (LAZYACCESS(modifiers, MIDDLE_CLICK)) if (LAZYACCESS(modifiers, MIDDLE_CLICK))
if (src_object && src_location != over_location) if (src_object && src_location != over_location)
middragtime = world.time middragtime = world.time
middragatom = src_object middle_drag_atom_ref = WEAKREF(src_object)
else else
middragtime = 0 middragtime = 0
middragatom = null middle_drag_atom_ref = null
mouseParams = params mouseParams = params
mouseLocation = over_location mouse_location_ref = WEAKREF(over_location)
mouseObject = over_object mouse_object_ref = WEAKREF(over_object)
if(selected_target[1] && over_object?.IsAutoclickable()) if(selected_target[1] && over_object?.IsAutoclickable())
selected_target[1] = over_object selected_target[1] = over_object
selected_target[2] = params selected_target[2] = params
if(active_mousedown_item) if(active_mousedown_item)
active_mousedown_item.onMouseDrag(src_object, over_object, src_location, over_location, params, mob) active_mousedown_item.onMouseDrag(src_object, over_object, src_location, over_location, params, mob)
SEND_SIGNAL(src, COMSIG_CLIENT_MOUSEDRAG, src_object, over_object, src_location, over_location, src_control, over_control, params) SEND_SIGNAL(src, COMSIG_CLIENT_MOUSEDRAG, src_object, over_object, src_location, over_location, src_control, over_control, params)
return ..()
/obj/item/proc/onMouseDrag(src_object, over_object, src_location, over_location, params, mob) /obj/item/proc/onMouseDrag(src_object, over_object, src_location, over_location, params, mob)
return return
/client/MouseDrop(src_object, over_object, src_location, over_location, src_control, over_control, params) /client/MouseDrop(atom/src_object, atom/over_object, atom/src_location, atom/over_location, src_control, over_control, params)
if (middragatom == src_object) if (IS_WEAKREF_OF(src_object, middle_drag_atom_ref))
middragtime = 0 middragtime = 0
middragatom = null middle_drag_atom_ref = null
..() ..()

View File

@@ -1,199 +0,0 @@
/*
These defines specificy screen locations. For more information, see the byond documentation on the screen_loc var.
The short version:
Everything is encoded as strings because apparently that's how Byond rolls.
"1,1" is the bottom left square of the user's screen. This aligns perfectly with the turf grid.
"1:2,3:4" is the square (1,3) with pixel offsets (+2, +4); slightly right and slightly above the turf grid.
Pixel offsets are used so you don't perfectly hide the turf under them, that would be crappy.
In addition, the keywords NORTH, SOUTH, EAST, WEST and CENTER can be used to represent their respective
screen borders. NORTH-1, for example, is the row just below the upper edge. Useful if you want your
UI to scale with screen size.
The size of the user's screen is defined by client.view (indirectly by world.view), in our case "15x15".
Therefore, the top right corner (except during admin shenanigans) is at "15,15"
*/
/proc/ui_hand_position(i) //values based on old hand ui positions (CENTER:-/+16,SOUTH:5)
var/x_off = -(!(i % 2))
var/y_off = round((i-1) / 2)
return"CENTER+[x_off]:16,SOUTH+[y_off]:5"
/proc/ui_equip_position(mob/M)
var/y_off = round((M.held_items.len-1) / 2) //values based on old equip ui position (CENTER: +/-16,SOUTH+1:5)
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((M.held_items.len-1) / 2)
return "CENTER+[x_off]:16,SOUTH+[y_off+1]:5"
//Lower left, persistent menu
#define ui_inventory "WEST:6,SOUTH:5"
//Middle left indicators
#define ui_lingchemdisplay "WEST,CENTER-1:15"
#define ui_lingstingdisplay "WEST:6,CENTER-3:11"
//Lower center, persistent menu
#define ui_sstore1 "CENTER-5:10,SOUTH:5"
#define ui_id "CENTER-4:12,SOUTH:5"
#define ui_belt "CENTER-3:14,SOUTH:5"
#define ui_back "CENTER-2:14,SOUTH:5"
#define ui_storage1 "CENTER+1:18,SOUTH:5"
#define ui_storage2 "CENTER+2:20,SOUTH:5"
#define ui_combo "CENTER+4:24,SOUTH+1:7" //combo meter for martial arts
//SKYRAT EDIT ADDITION BEGIN - ERP_SLOT_SYSTEM
#define ui_vagina "WEST+1:8,SOUTH+4:14"
#define ui_vagina_down "WEST+1:8,SOUTH+1:8"
#define ui_anus "WEST+2:10,SOUTH+4:14"
#define ui_anus_down "WEST+2:10,SOUTH+1:8"
#define ui_nipples "WEST:6,SOUTH+5:17"
#define ui_nipples_down "WEST:6,SOUTH+2:11"
#define ui_penis "WEST+1:8,SOUTH+5:17"
#define ui_penis_down "WEST+1:8,SOUTH+2:11"
#define ui_erp_inventory "WEST:6,SOUTH+1:8"
#define ui_erp_inventory_up "WEST:6,SOUTH+4:14"
//SKYRAT EDI ADDITION END
//Lower right, persistent menu
#define ui_drop_throw "EAST-1:28,SOUTH+1:7"
#define ui_above_movement "EAST-2:26,SOUTH+1:7"
#define ui_above_intent "EAST-3:24, SOUTH+1:7"
#define ui_movi "EAST-2:26,SOUTH:5"
#define ui_acti "EAST-3:24,SOUTH:5"
#define ui_combat_toggle "EAST-3:24,SOUTH:5"
#define ui_zonesel "EAST-1:28,SOUTH:5"
#define ui_acti_alt "EAST-1:28,SOUTH:5" //alternative intent switcher for when the interface is hidden (F12)
#define ui_crafting "EAST-4:22,SOUTH:5"
#define ui_building "EAST-4:22,SOUTH:21"
#define ui_language_menu "EAST-4:6,SOUTH:21"
#define ui_skill_menu "EAST-4:22,SOUTH:5"
//Upper-middle right (alerts)
#define ui_alert1 "EAST-1:28,CENTER+5:27"
#define ui_alert2 "EAST-1:28,CENTER+4:25"
#define ui_alert3 "EAST-1:28,CENTER+3:23"
#define ui_alert4 "EAST-1:28,CENTER+2:21"
#define ui_alert5 "EAST-1:28,CENTER+1:19"
//Middle right (status indicators)
#define ui_healthdoll "EAST-1:28,CENTER-2:13"
#define ui_health "EAST-1:28,CENTER-1:15"
#define ui_internal "EAST-1:28,CENTER+1:17"
#define ui_mood "EAST-1:28,CENTER:17"
#define ui_spacesuit "EAST-1:28,CENTER-4:10"
#define ui_stamina "EAST-1:28,CENTER-3:10"
//Pop-up inventory
#define ui_shoes "WEST+1:8,SOUTH:5"
#define ui_iclothing "WEST:6,SOUTH+1:7"
#define ui_oclothing "WEST+1:8,SOUTH+1:7"
#define ui_gloves "WEST+2:10,SOUTH+1:7"
#define ui_glasses "WEST:6,SOUTH+3:11"
#define ui_mask "WEST+1:8,SOUTH+2:9"
#define ui_ears "WEST+2:10,SOUTH+2:9"
#define ui_neck "WEST:6,SOUTH+2:9"
#define ui_head "WEST+1:8,SOUTH+3:11"
//Generic living
#define ui_living_pull "EAST-1:28,CENTER-3:15"
#define ui_living_healthdoll "EAST-1:28,CENTER-1:15"
//Monkeys
#define ui_monkey_head "CENTER-5:13,SOUTH:5"
#define ui_monkey_mask "CENTER-4:14,SOUTH:5"
#define ui_monkey_neck "CENTER-3:15,SOUTH:5"
#define ui_monkey_back "CENTER-2:16,SOUTH:5"
//Drones
#define ui_drone_drop "CENTER+1:18,SOUTH:5"
#define ui_drone_pull "CENTER+2:2,SOUTH:5"
#define ui_drone_storage "CENTER-2:14,SOUTH:5"
#define ui_drone_head "CENTER-3:14,SOUTH:5"
//Cyborgs
#define ui_borg_health "EAST-1:28,CENTER-1:15"
#define ui_borg_pull "EAST-2:26,SOUTH+1:7"
#define ui_borg_radio "EAST-1:28,SOUTH+1:7"
#define ui_borg_intents "EAST-2:26,SOUTH:5"
#define ui_borg_lamp "CENTER-3:16, SOUTH:5"
#define ui_borg_tablet "CENTER-4:16, SOUTH:5"
#define ui_inv1 "CENTER-2:16,SOUTH:5"
#define ui_inv2 "CENTER-1 :16,SOUTH:5"
#define ui_inv3 "CENTER :16,SOUTH:5"
#define ui_borg_module "CENTER+1:16,SOUTH:5"
#define ui_borg_store "CENTER+2:16,SOUTH:5"
#define ui_borg_camera "CENTER+3:21,SOUTH:5"
#define ui_borg_alerts "CENTER+4:21,SOUTH:5"
#define ui_borg_language_menu "CENTER+4:19,SOUTH+1:6"
// SKYRAT EDIT ADDITION BEGIN - Cyborg PDA
#define ui_borg_pda_send "CENTER+5:21,SOUTH:5" // To the right of the alert panel
#define ui_borg_pda_log "CENTER+6:21,SOUTH:5"
// SKYRAT EDIT ADDITION END
//Aliens
#define ui_alien_health "EAST,CENTER-1:15"
#define ui_alienplasmadisplay "EAST,CENTER-2:15"
#define ui_alien_queen_finder "EAST,CENTER-3:15"
#define ui_alien_storage_r "CENTER+1:18,SOUTH:5"
#define ui_alien_language_menu "EAST-4:20,SOUTH:5"
//AI
#define ui_ai_core "SOUTH:6,WEST"
#define ui_ai_camera_list "SOUTH:6,WEST+1"
#define ui_ai_track_with_camera "SOUTH:6,WEST+2"
#define ui_ai_camera_light "SOUTH:6,WEST+3"
#define ui_ai_crew_monitor "SOUTH:6,WEST+4"
#define ui_ai_crew_manifest "SOUTH:6,WEST+5"
#define ui_ai_alerts "SOUTH:6,WEST+6"
#define ui_ai_announcement "SOUTH:6,WEST+7"
#define ui_ai_shuttle "SOUTH:6,WEST+8"
#define ui_ai_state_laws "SOUTH:6,WEST+9"
#define ui_ai_pda_send "SOUTH:6,WEST+10"
#define ui_ai_pda_log "SOUTH:6,WEST+11"
#define ui_ai_take_picture "SOUTH:6,WEST+12"
#define ui_ai_view_images "SOUTH:6,WEST+13"
#define ui_ai_sensor "SOUTH:6,WEST+14"
#define ui_ai_multicam "SOUTH+1:6,WEST+13"
#define ui_ai_add_multicam "SOUTH+1:6,WEST+14"
#define ui_ai_language_menu "SOUTH+1:8,WEST+11:30"
//pAI
#define ui_pai_software "SOUTH:6,WEST"
#define ui_pai_shell "SOUTH:6,WEST+1"
#define ui_pai_chassis "SOUTH:6,WEST+2"
#define ui_pai_rest "SOUTH:6,WEST+3"
#define ui_pai_light "SOUTH:6,WEST+4"
#define ui_pai_newscaster "SOUTH:6,WEST+5"
#define ui_pai_host_monitor "SOUTH:6,WEST+6"
#define ui_pai_crew_manifest "SOUTH:6,WEST+7"
#define ui_pai_state_laws "SOUTH:6,WEST+8"
#define ui_pai_pda_send "SOUTH:6,WEST+9"
#define ui_pai_pda_log "SOUTH:6,WEST+10"
#define ui_pai_internal_gps "SOUTH:6,WEST+11"
#define ui_pai_take_picture "SOUTH:6,WEST+12"
#define ui_pai_view_images "SOUTH:6,WEST+13"
#define ui_pai_radio "SOUTH:6,WEST+14"
#define ui_pai_language_menu "SOUTH+1:8,WEST+13:31"
//Ghosts
#define ui_ghost_spawners_menu "SOUTH:6,CENTER-3:24"
#define ui_ghost_orbit "SOUTH:6,CENTER-2:24"
#define ui_ghost_reenter_corpse "SOUTH:6,CENTER-1:24"
#define ui_ghost_teleport "SOUTH:6,CENTER:24"
#define ui_ghost_pai "SOUTH: 6, CENTER+1:24"
#define ui_ghost_minigames "SOUTH: 6, CENTER+2:24"
#define ui_ghost_language_menu "SOUTH: 22, CENTER+3:8"
//Blobbernauts
#define ui_blobbernaut_overmind_health "EAST-1:28,CENTER+0:19"
//Families
#define ui_wanted_lvl "NORTH,11"
//SKYRAT HUD DEFINES BELOW
#define ui_ammocounter "EAST-1:28,CENTER-5:9"

View File

@@ -2,22 +2,36 @@
/atom/movable/screen/movable/action_button /atom/movable/screen/movable/action_button
var/datum/action/linked_action var/datum/action/linked_action
var/datum/hud/our_hud
var/actiontooltipstyle = "" var/actiontooltipstyle = ""
screen_loc = null screen_loc = null
var/button_icon_state var/button_icon_state
var/appearance_cache var/appearance_cache
/// 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 var/id
var/ordered = TRUE //If the button gets placed into the default bar /// A weakref of the last thing we hovered over
/// God I hate how dragging works
var/datum/weakref/last_hovored_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) /atom/movable/screen/movable/action_button/proc/can_use(mob/user)
if(linked_action) if(linked_action)
if(linked_action.owner == user) if(linked_action.viewers[user.hud_used])
return TRUE return TRUE
for(var/datum/weakref/reference as anything in linked_action.sharers)
if(IS_WEAKREF_OF(user, reference))
return TRUE
return FALSE return FALSE
else if (isobserver(user)) else if (isobserver(user))
var/mob/dead/observer/O = user var/mob/dead/observer/O = user
@@ -25,41 +39,14 @@
else else
return TRUE return TRUE
/atom/movable/screen/movable/action_button/MouseDrop(over_object)
if(!can_use(usr))
return
if((istype(over_object, /atom/movable/screen/movable/action_button) && !istype(over_object, /atom/movable/screen/movable/action_button/hide_toggle)))
if(locked)
to_chat(usr, span_warning("Action button \"[name]\" is locked, unlock it first."))
return
var/atom/movable/screen/movable/action_button/B = over_object
var/list/actions = usr.actions
actions.Swap(actions.Find(src.linked_action), actions.Find(B.linked_action))
moved = FALSE
ordered = TRUE
B.moved = FALSE
B.ordered = TRUE
usr.update_action_buttons()
else
return ..()
/atom/movable/screen/movable/action_button/Click(location,control,params) /atom/movable/screen/movable/action_button/Click(location,control,params)
if (!can_use(usr)) if (!can_use(usr))
return FALSE return FALSE
var/list/modifiers = params2list(params) var/list/modifiers = params2list(params)
if(LAZYACCESS(modifiers, SHIFT_CLICK)) if(LAZYACCESS(modifiers, SHIFT_CLICK))
if(locked) var/datum/hud/our_hud = usr.hud_used
to_chat(usr, span_warning("Action button \"[name]\" is locked, unlock it first.")) our_hud.position_action(src, SCRN_OBJ_DEFAULT)
return TRUE
moved = 0
usr.update_action_buttons() //redraw buttons that are no longer considered "moved"
return TRUE
if(LAZYACCESS(modifiers, CTRL_CLICK))
locked = !locked
to_chat(usr, span_notice("Action button \"[name]\" [locked ? "" : "un"]locked."))
if(id && usr.client) //try to (un)remember position
usr.client.prefs.action_buttons_screen_locs["[name]_[id]"] = locked ? moved : null
return TRUE return TRUE
if(usr.next_click > world.time) if(usr.next_click > world.time)
return return
@@ -70,127 +57,105 @@
linked_action.Trigger(trigger_flags = trigger_flags) linked_action.Trigger(trigger_flags = trigger_flags)
return TRUE return TRUE
//Hide/Show Action Buttons ... Button // Entered and Exited won't fire while you're dragging something, because you're still "holding" it
/atom/movable/screen/movable/action_button/hide_toggle // Very much byond logic, but I want nice behavior, so we fake it with drag
name = "Hide Buttons" /atom/movable/screen/movable/action_button/MouseDrag(atom/over_object, src_location, over_location, src_control, over_control, params)
desc = "Shift-click any button to reset its position, and Control-click it to lock it in place. Alt-click this button to reset all buttons to their default positions."
icon = 'icons/hud/actions.dmi'
icon_state = "bg_default"
var/hidden = FALSE
var/hide_icon = 'icons/hud/actions.dmi'
var/hide_state = "hide"
var/show_state = "show"
var/mutable_appearance/hide_appearance
var/mutable_appearance/show_appearance
/atom/movable/screen/movable/action_button/hide_toggle/Initialize(mapload)
. = ..() . = ..()
var/static/list/icon_cache = list() if(!can_use(usr))
var/cache_key = "[hide_icon][hide_state]"
hide_appearance = icon_cache[cache_key]
if(!hide_appearance)
hide_appearance = icon_cache[cache_key] = mutable_appearance(hide_icon, hide_state)
cache_key = "[hide_icon][show_state]"
show_appearance = icon_cache[cache_key]
if(!show_appearance)
show_appearance = icon_cache[cache_key] = mutable_appearance(hide_icon, show_state)
/atom/movable/screen/movable/action_button/hide_toggle/Click(location,control,params)
if (!can_use(usr))
return return
if(IS_WEAKREF_OF(over_object, last_hovored_ref))
return
var/atom/old_object
if(last_hovored_ref)
old_object = last_hovored_ref?.resolve()
else // If there's no current ref, we assume it was us. We also treat this as our "first go" location
old_object = src
var/datum/hud/our_hud = usr.hud_used
our_hud?.generate_landings(src)
var/list/modifiers = params2list(params) if(old_object)
if(LAZYACCESS(modifiers, SHIFT_CLICK)) old_object.MouseExited(over_location, over_control, params)
if(locked)
to_chat(usr, span_warning("Action button \"[name]\" is locked, unlock it first."))
return TRUE
moved = FALSE
usr.update_action_buttons(TRUE)
return TRUE
if(LAZYACCESS(modifiers, CTRL_CLICK))
locked = !locked
to_chat(usr, span_notice("Action button \"[name]\" [locked ? "" : "un"]locked."))
if(id && usr.client) //try to (un)remember position
usr.client.prefs.action_buttons_screen_locs["[name]_[id]"] = locked ? moved : null
return TRUE
if(LAZYACCESS(modifiers, ALT_CLICK))
var/buttons_locked = usr.client.prefs.read_preference(/datum/preference/toggle/buttons_locked)
for(var/V in usr.actions)
var/datum/action/A = V
var/atom/movable/screen/movable/action_button/B = A.button
B.moved = FALSE
if(B.id && usr.client)
usr.client.prefs.action_buttons_screen_locs["[B.name]_[B.id]"] = null
B.locked = buttons_locked
locked = buttons_locked
moved = FALSE
if(id && usr.client)
usr.client.prefs.action_buttons_screen_locs["[name]_[id]"] = null
usr.update_action_buttons(TRUE)
to_chat(usr, span_notice("Action button positions have been reset."))
return TRUE
usr.hud_used.action_buttons_hidden = !usr.hud_used.action_buttons_hidden
hidden = usr.hud_used.action_buttons_hidden last_hovored_ref = WEAKREF(over_object)
if(hidden) over_object.MouseEntered(over_location, over_control, params)
name = "Show Buttons"
else
name = "Hide Buttons"
update_appearance()
usr.update_action_buttons()
/atom/movable/screen/movable/action_button/hide_toggle/AltClick(mob/user) /atom/movable/screen/movable/action_button/MouseEntered(location, control, params)
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, span_notice("Action button positions have been reset."))
/atom/movable/screen/movable/action_button/hide_toggle/proc/InitialiseIcon(datum/hud/owner_hud)
var/settings = owner_hud.get_action_buttons_icons()
icon = settings["bg_icon"]
icon_state = settings["bg_state"]
hide_icon = settings["toggle_icon"]
hide_state = settings["toggle_hide"]
show_state = settings["toggle_show"]
update_appearance()
/atom/movable/screen/movable/action_button/hide_toggle/update_overlays()
. = ..()
. += hidden ? show_appearance : hide_appearance
/atom/movable/screen/movable/action_button/MouseEntered(location,control,params)
. = ..() . = ..()
if(!QDELETED(src)) if(!QDELETED(src))
openToolTip(usr,src,params,title = name,content = desc,theme = actiontooltipstyle) openToolTip(usr, src, params, title = name, content = desc, theme = actiontooltipstyle)
/atom/movable/screen/movable/action_button/MouseExited(location, control, params)
/atom/movable/screen/movable/action_button/MouseExited()
closeToolTip(usr) closeToolTip(usr)
return ..()
/atom/movable/screen/movable/action_button/MouseDrop(over_object)
last_hovored_ref = null
if(!can_use(usr))
return
var/datum/hud/our_hud = usr.hud_used
if(over_object == src)
our_hud.hide_landings()
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()
save_position()
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)
save_position()
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)
save_position()
return
. = ..()
our_hud.position_action(src, screen_loc)
save_position()
/atom/movable/screen/movable/action_button/proc/save_position()
var/mob/user = our_hud.mymob
if(!user?.client)
return
var/position_info = ""
switch(location)
if(SCRN_OBJ_FLOATING)
position_info = screen_loc
if(SCRN_OBJ_IN_LIST)
position_info = SCRN_OBJ_IN_LIST
if(SCRN_OBJ_IN_PALETTE)
position_info = SCRN_OBJ_IN_PALETTE
user.client.prefs.action_buttons_screen_locs["[name]_[id]"] = position_info
/atom/movable/screen/movable/action_button/proc/load_position()
var/mob/user = our_hud.mymob
if(!user)
return
var/position_info = user.client?.prefs?.action_buttons_screen_locs["[name]_[id]"] || SCRN_OBJ_DEFAULT
user.hud_used.position_action(src, position_info)
/atom/movable/screen/movable/action_button/proc/dump_save()
var/mob/user = our_hud.mymob
if(!user?.client)
return
user.client.prefs.action_buttons_screen_locs -= "[name]_[id]"
/datum/hud/proc/get_action_buttons_icons() /datum/hud/proc/get_action_buttons_icons()
. = list() . = list()
.["bg_icon"] = ui_style .["bg_icon"] = ui_style
.["bg_state"] = "template" .["bg_state"] = "template"
//TODO : Make these fit theme
.["toggle_icon"] = 'icons/hud/actions.dmi'
.["toggle_hide"] = "hide"
.["toggle_show"] = "show"
//see human and alien hud for specific implementations. //see human and alien hud for specific implementations.
/mob/proc/update_action_buttons_icon(status_only = FALSE) /mob/proc/update_action_buttons_icon(status_only = FALSE)
for(var/X in actions) for(var/X in actions)
var/datum/action/A = X var/datum/action/A = X
A.UpdateButtonIcon(status_only) A.UpdateButtons(status_only)
//This is the proc used to update all the action buttons. //This is the proc used to update all the action buttons.
/mob/proc/update_action_buttons(reload_screen) /mob/proc/update_action_buttons(reload_screen)
@@ -200,58 +165,243 @@
if(hud_used.hud_shown != HUD_STYLE_STANDARD) if(hud_used.hud_shown != HUD_STYLE_STANDARD)
return 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
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.UpdateButtonIcon()
var/atom/movable/screen/movable/action_button/B = A.button
if(B.ordered)
button_number++
if(B.moved)
B.screen_loc = B.moved
else
B.screen_loc = hud_used.ButtonNumberToScreenCoords(button_number)
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) 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()
/atom/movable/screen/button_palette
desc = "<b>Drag</b> buttons to move them<br><b>Shift-click</b> any button to reset it<br><b>Alt-click</b> this to reset all buttons"
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
/atom/movable/screen/button_palette/Destroy()
if(our_hud)
our_hud.mymob?.client?.screen -= src
our_hud.toggle_palette = null
our_hud = null
return ..()
#define AB_MAX_COLUMNS 10 /atom/movable/screen/button_palette/Initialize(mapload)
. = ..()
update_appearance()
/datum/hud/proc/ButtonNumberToScreenCoords(number) // TODO : Make this zero-indexed for readabilty /atom/movable/screen/button_palette/proc/set_hud(datum/hud/our_hud)
var/row = round((number - 1)/AB_MAX_COLUMNS) src.our_hud = our_hud
var/col = ((number - 1)%(AB_MAX_COLUMNS)) + 1 refresh_owner()
var/coord_col = "+[col-1]" /atom/movable/screen/button_palette/update_name(updates)
var/coord_col_offset = 4 + 2 * col . = ..()
if(expanded)
name = "Hide Buttons"
else
name = "Show Buttons"
var/coord_row = "[row ? -row : "+0"]" /atom/movable/screen/button_palette/proc/refresh_owner()
var/mob/viewer = our_hud.mymob
if(viewer.client)
viewer.client.screen |= src
return "WEST[coord_col]:[coord_col_offset],NORTH[coord_row]:-6" 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)]
/datum/hud/proc/SetButtonCoords(atom/movable/screen/button,number) icon_state = "[ui_name]_palette"
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
var/matrix/M = matrix() /atom/movable/screen/button_palette/MouseEntered(location, control, params)
M.Translate(x_offset,y_offset) . = ..()
button.transform = M if(QDELETED(src))
return
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/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)
if (isobserver(user))
var/mob/dead/observer/O = user
return !O.observetarget
return TRUE
/atom/movable/screen/button_palette/Click(location, control, params)
if(!can_use(usr))
return
var/list/modifiers = params2list(params)
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, span_notice("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/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/hud/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)
if (isobserver(user))
var/mob/dead/observer/O = user
return !O.observetarget
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/Click(location, control, params)
if(!can_use(usr))
return
our_hud.palette_actions.scroll(scroll_direction)
/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/MouseExited()
closeToolTip(usr)
return ..()
/atom/movable/screen/palette_scroll/down
name = "Scroll Down"
desc = "<b>Click</b> 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 = "<b>Click</b> 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 = "<b>Drag and drop</b> a button into this spot<br>to add it to the group"
icon = 'icons/hud/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)

View File

@@ -93,8 +93,13 @@ GLOBAL_LIST_INIT(available_erp_ui_styles, list(
/// game (MouseEntered). /// game (MouseEntered).
var/screentip_color var/screentip_color
var/atom/movable/screen/movable/action_button/hide_toggle/hide_actions_toggle var/atom/movable/screen/button_palette/toggle_palette
var/action_buttons_hidden = FALSE var/atom/movable/screen/palette_scroll/down/palette_down
var/atom/movable/screen/palette_scroll/up/palette_up
var/datum/action_group/palette/palette_actions
var/datum/action_group/listed/listed_actions
var/list/floating_actions
var/atom/movable/screen/healths var/atom/movable/screen/healths
var/atom/movable/screen/stamina var/atom/movable/screen/stamina
@@ -114,10 +119,12 @@ GLOBAL_LIST_INIT(available_erp_ui_styles, list(
ui_style = ui_style2icon(owner.client?.prefs?.read_preference(/datum/preference/choiced/ui_style)) ui_style = ui_style2icon(owner.client?.prefs?.read_preference(/datum/preference/choiced/ui_style))
erp_ui_style = erp_ui_style2icon(owner.client?.prefs?.read_preference(/datum/preference/choiced/ui_style)) //SKYRAT EDIT - ADDITION - ERP ICONS FIX erp_ui_style = erp_ui_style2icon(owner.client?.prefs?.read_preference(/datum/preference/choiced/ui_style)) //SKYRAT EDIT - ADDITION - ERP ICONS FIX
hide_actions_toggle = new toggle_palette = new()
hide_actions_toggle.InitialiseIcon(src) toggle_palette.set_hud(src)
if(mymob.client?.prefs) palette_down = new()
hide_actions_toggle.locked = mymob.client.prefs.read_preference(/datum/preference/toggle/buttons_locked) palette_down.set_hud(src)
palette_up = new()
palette_up.set_hud(src)
hand_slots = list() hand_slots = list()
@@ -142,7 +149,13 @@ GLOBAL_LIST_INIT(available_erp_ui_styles, list(
if(mymob.hud_used == src) if(mymob.hud_used == src)
mymob.hud_used = null 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(floating_actions)
QDEL_NULL(module_store_icon) QDEL_NULL(module_store_icon)
QDEL_LIST(static_inventory) QDEL_LIST(static_inventory)
@@ -184,10 +197,14 @@ GLOBAL_LIST_INIT(available_erp_ui_styles, list(
/mob/proc/create_mob_hud() /mob/proc/create_mob_hud()
if(!client || hud_used) if(!client || hud_used)
return return
hud_used = new hud_type(src) set_hud_used(new hud_type(src))
update_sight() update_sight()
SEND_SIGNAL(src, COMSIG_MOB_HUD_CREATED) 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()
//Version denotes which style should be displayed. blank or 0 means "next version" //Version denotes which style should be displayed. blank or 0 means "next version"
/datum/hud/proc/show_hud(version = 0, mob/viewmob) /datum/hud/proc/show_hud(version = 0, mob/viewmob)
if(!ismob(mymob)) if(!ismob(mymob))
@@ -196,6 +213,8 @@ GLOBAL_LIST_INIT(available_erp_ui_styles, list(
if(!screenmob.client) if(!screenmob.client)
return FALSE return FALSE
// This code is the absolute fucking worst, I want it to go die in a fire
// Seriously, why
screenmob.client.screen = list() screenmob.client.screen = list()
screenmob.client.apply_clickcatcher() screenmob.client.apply_clickcatcher()
@@ -221,7 +240,7 @@ GLOBAL_LIST_INIT(available_erp_ui_styles, list(
if(infodisplay.len) if(infodisplay.len)
screenmob.client.screen += infodisplay screenmob.client.screen += infodisplay
screenmob.client.screen += hide_actions_toggle screenmob.client.screen += toggle_palette
if(action_intent) if(action_intent)
action_intent.screen_loc = initial(action_intent.screen_loc) //Restore intent selection to the original position action_intent.screen_loc = initial(action_intent.screen_loc) //Restore intent selection to the original position
@@ -320,7 +339,6 @@ GLOBAL_LIST_INIT(available_erp_ui_styles, list(
ui_style = new_ui_style ui_style = new_ui_style
build_hand_slots() build_hand_slots()
hide_actions_toggle.InitialiseIcon(src)
//SKYRAT EDIT - ADDITION - ERP ICONS FIX //SKYRAT EDIT - ADDITION - ERP ICONS FIX
@@ -334,7 +352,6 @@ GLOBAL_LIST_INIT(available_erp_ui_styles, list(
item.icon = new_erp_ui_style item.icon = new_erp_ui_style
erp_ui_style = new_erp_ui_style erp_ui_style = new_erp_ui_style
hide_actions_toggle.InitialiseIcon(src)
//SKYRAT EDIT - ADDITION - ERP ICONS FIX - END //SKYRAT EDIT - ADDITION - ERP ICONS FIX - END
@@ -384,3 +401,306 @@ GLOBAL_LIST_INIT(available_erp_ui_styles, list(
/datum/hud/proc/update_locked_slots() /datum/hud/proc/update_locked_slots()
return return
/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
button.dump_save() // Nuke any existing saves
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
button.screen_loc = get_valid_screen_location(relative_to.screen_loc, world.icon_size, our_client.view_size.getView()) // 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)
/datum/action_group
/// The hud we're owned by
var/datum/hud/owner
/// The actions 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
/// 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(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)
return "WEST[coord_col]:[coord_col_offset],NORTH[coord_row]:-[pixel_north_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/insert_action(atom/movable/screen/action, index)
. = ..()
var/atom/movable/screen/button_palette/palette = owner.toggle_palette
palette.play_item_added()
/datum/action_group/palette/remove_action(atom/movable/screen/action)
. = ..()
var/atom/movable/screen/button_palette/palette = owner.toggle_palette
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

View File

@@ -9,9 +9,8 @@
//Not tied to the grid, places it's center where the cursor is //Not tied to the grid, places it's center where the cursor is
/atom/movable/screen/movable /atom/movable/screen/movable
mouse_drag_pointer = 'icons/effects/mouse_pointers/screen_drag.dmi'
var/snap2grid = FALSE var/snap2grid = FALSE
var/moved = FALSE
var/locked = FALSE
var/x_off = -16 var/x_off = -16
var/y_off = -16 var/y_off = -16
@@ -21,35 +20,29 @@
/atom/movable/screen/movable/snap /atom/movable/screen/movable/snap
snap2grid = TRUE snap2grid = TRUE
/atom/movable/screen/movable/MouseDrop(over_object, src_location, over_location, src_control, over_control, params) /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 return
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) var/list/modifiers = params2list(params)
//No screen-loc information? abort. //No screen-loc information? abort.
if(!LAZYACCESS(modifiers, SCREEN_LOC)) if(!LAZYACCESS(modifiers, SCREEN_LOC))
return return
var/client/our_client = usr.client
//Split screen-loc up into X+Pixel_X and Y+Pixel_Y var/list/offset = screen_loc_to_offset(LAZYACCESS(modifiers, SCREEN_LOC))
var/list/screen_loc_params = splittext(LAZYACCESS(modifiers, 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],":")
if(snap2grid) //Discard Pixel Values 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) 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 offset[1] += x_off
var/pix_Y = text2num(screen_loc_Y[2]) + y_off offset[2] += y_off
screen_loc = "[screen_loc_X[1]]:[pix_X],[screen_loc_Y[1]]:[pix_Y]" return offset_to_screen_loc(offset[1], offset[2], our_client?.view)
moved = screen_loc
//Debug procs //Debug procs
/client/proc/test_movable_UI() /client/proc/test_movable_UI()

View File

@@ -16,6 +16,6 @@
SIGNAL_HANDLER SIGNAL_HANDLER
if(!hud || !hud.mymob.client.view_size) //Might not have been initialized by now if(!hud || !hud.mymob.client.view_size) //Might not have been initialized by now
return return
maptext_width = getviewsize(hud.mymob.client.view_size.getView())[1] * world.icon_size maptext_width = view_to_pixels(hud.mymob.client.view_size.getView())[1]

View File

@@ -72,15 +72,15 @@ SUBSYSTEM_DEF(augury)
SSaugury.watchers += owner SSaugury.watchers += owner
to_chat(owner, span_notice("You are now auto-following debris.")) to_chat(owner, span_notice("You are now auto-following debris."))
active = TRUE active = TRUE
UpdateButtonIcon() UpdateButtons()
/datum/action/innate/augury/Deactivate() /datum/action/innate/augury/Deactivate()
SSaugury.watchers -= owner SSaugury.watchers -= owner
to_chat(owner, span_notice("You are no longer auto-following debris.")) to_chat(owner, span_notice("You are no longer auto-following debris."))
active = FALSE active = FALSE
UpdateButtonIcon() UpdateButtons()
/datum/action/innate/augury/UpdateButtonIcon(status_only = FALSE, force) /datum/action/innate/augury/UpdateButton(atom/movable/screen/movable/action_button/button, status_only = FALSE, force)
..() ..()
if(active) if(active)
button.icon_state = "template_active" button.icon_state = "template_active"

View File

@@ -4,9 +4,10 @@
var/datum/target var/datum/target
var/check_flags = NONE var/check_flags = NONE
var/processing = FALSE var/processing = FALSE
var/atom/movable/screen/movable/action_button/button = null
var/buttontooltipstyle = "" var/buttontooltipstyle = ""
var/transparent_when_unavailable = TRUE var/transparent_when_unavailable = TRUE
/// Where any buttons we create should be by default. Accepts screen_loc and location defines
var/default_button_position = SCRN_OBJ_IN_LIST
var/button_icon = 'icons/mob/actions/backgrounds.dmi' //This is the file for the BACKGROUND icon var/button_icon = 'icons/mob/actions/backgrounds.dmi' //This is the file for the BACKGROUND icon
var/background_icon_state = ACTION_BUTTON_DEFAULT_BACKGROUND //And this is the state for the background icon var/background_icon_state = ACTION_BUTTON_DEFAULT_BACKGROUND //And this is the state for the background icon
@@ -14,17 +15,11 @@
var/icon_icon = 'icons/hud/actions.dmi' //This is the file for the ACTION icon var/icon_icon = 'icons/hud/actions.dmi' //This is the file for the ACTION icon
var/button_icon_state = "default" //And this is the state for the action icon var/button_icon_state = "default" //And this is the state for the action icon
var/mob/owner var/mob/owner
///All mobs that are sharing our action button. ///List of all mobs that are viewing our action button -> A unique movable for them to view.
var/list/sharers = list() var/list/viewers = list()
/datum/action/New(Target) /datum/action/New(Target)
link_to(Target) link_to(Target)
button = new
button.linked_action = src
button.name = name
button.actiontooltipstyle = buttontooltipstyle
if(desc)
button.desc = desc
/datum/action/proc/link_to(Target) /datum/action/proc/link_to(Target)
target = Target target = Target
@@ -35,41 +30,21 @@
if(owner) if(owner)
Remove(owner) Remove(owner)
target = null target = null
QDEL_NULL(button) QDEL_LIST_ASSOC_VAL(viewers) // Qdel the buttons in the viewers list **NOT THE HUDS**
return ..() return ..()
/datum/action/proc/Grant(mob/M) /datum/action/proc/Grant(mob/M)
if(M) if(!M)
if(owner)
if(owner == M)
return
Remove(owner)
owner = M
RegisterSignal(owner, COMSIG_PARENT_QDELETING, .proc/clear_ref, override = TRUE)
//button id generation
var/counter = 0
var/bitfield = 0
for(var/datum/action/A in M.actions)
if(A.name == name && A.button.id)
counter += 1
bitfield |= A.button.id
bitfield = ~bitfield
var/bitflag = 1
for(var/i in 1 to (counter + 1))
if(bitfield & bitflag)
button.id = bitflag
break
bitflag *= 2
LAZYADD(M.actions, src)
if(M.client)
M.client.screen += button
button.locked = M.client.prefs.read_preference(/datum/preference/toggle/buttons_locked) || button.id ? M.client.prefs.action_buttons_screen_locs["[name]_[button.id]"] : FALSE //even if it's not defaultly locked we should remember we locked it before
button.moved = button.id ? M.client.prefs.action_buttons_screen_locs["[name]_[button.id]"] : FALSE
M.update_action_buttons()
else
Remove(owner) Remove(owner)
return
if(owner)
if(owner == M)
return
Remove(owner)
owner = M
RegisterSignal(owner, COMSIG_PARENT_QDELETING, .proc/clear_ref, override = TRUE)
GiveAction(M)
/datum/action/proc/clear_ref(datum/ref) /datum/action/proc/clear_ref(datum/ref)
SIGNAL_HANDLER SIGNAL_HANDLER
@@ -79,26 +54,18 @@
qdel(src) qdel(src)
/datum/action/proc/Remove(mob/M) /datum/action/proc/Remove(mob/M)
for(var/datum/weakref/reference as anything in sharers) for(var/datum/hud/hud in viewers)
var/mob/freeloader = reference.resolve() if(!hud.mymob)
if(!freeloader)
continue continue
Unshare(freeloader) HideFrom(hud.mymob)
sharers = null LAZYREMOVE(M.actions, src) // We aren't always properly inserted into the viewers list, gotta make sure that action's cleared
if(M) viewers = list()
if(M.client)
M.client.screen -= button
LAZYREMOVE(M.actions, src)
M.update_action_buttons()
if(owner) if(owner)
UnregisterSignal(owner, COMSIG_PARENT_QDELETING) UnregisterSignal(owner, COMSIG_PARENT_QDELETING)
if(target == owner) if(target == owner)
RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/clear_ref) RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/clear_ref)
owner = null owner = null
if(button)
button.moved = FALSE //so the button appears in its normal position when given to another owner.
button.locked = FALSE
button.id = null
/datum/action/proc/Trigger(trigger_flags) /datum/action/proc/Trigger(trigger_flags)
if(!IsAvailable()) if(!IsAvailable())
@@ -123,31 +90,36 @@
return FALSE return FALSE
return TRUE return TRUE
/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/UpdateButtonIcon(status_only = FALSE, force = FALSE) /datum/action/proc/UpdateButton(atom/movable/screen/movable/action_button/button, status_only = FALSE, force = FALSE)
if(button) if(!button)
if(!status_only) return
button.name = name if(!status_only)
button.desc = desc button.name = name
if(owner?.hud_used && background_icon_state == ACTION_BUTTON_DEFAULT_BACKGROUND) button.desc = desc
var/list/settings = owner.hud_used.get_action_buttons_icons() if(owner?.hud_used && background_icon_state == ACTION_BUTTON_DEFAULT_BACKGROUND)
if(button.icon != settings["bg_icon"]) var/list/settings = owner.hud_used.get_action_buttons_icons()
button.icon = settings["bg_icon"] if(button.icon != settings["bg_icon"])
if(button.icon_state != settings["bg_state"]) button.icon = settings["bg_icon"]
button.icon_state = settings["bg_state"] if(button.icon_state != settings["bg_state"])
else button.icon_state = settings["bg_state"]
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())
button.color = transparent_when_unavailable ? rgb(128,0,0,128) : rgb(128,0,0)
else else
button.color = rgb(255,255,255,255) if(button.icon != button_icon)
return TRUE button.icon = button_icon
if(button.icon_state != background_icon_state)
button.icon_state = background_icon_state
ApplyIcon(button, force)
if(!IsAvailable())
button.color = transparent_when_unavailable ? rgb(128,0,0,128) : rgb(128,0,0)
else
button.color = rgb(255,255,255,255)
return TRUE
/datum/action/proc/ApplyIcon(atom/movable/screen/movable/action_button/current_button, force = FALSE) /datum/action/proc/ApplyIcon(atom/movable/screen/movable/action_button/current_button, force = FALSE)
if(icon_icon && button_icon_state && ((current_button.button_icon_state != button_icon_state) || force)) if(icon_icon && button_icon_state && ((current_button.button_icon_state != button_icon_state) || force))
@@ -157,28 +129,67 @@
/datum/action/proc/OnUpdatedIcon() /datum/action/proc/OnUpdatedIcon()
SIGNAL_HANDLER SIGNAL_HANDLER
UpdateButtonIcon() UpdateButtons()
//Adds our action button to the screen of another player //Give our action button to the player
/datum/action/proc/Share(mob/freeloader) /datum/action/proc/GiveAction(mob/viewer)
if(!freeloader.client) var/datum/hud/our_hud = viewer.hud_used
if(viewers[our_hud]) // Already have a copy of us? go away
return return
sharers += WEAKREF(freeloader)
freeloader.client.screen += button
freeloader.actions += src
freeloader.update_action_buttons()
//Removes our action button from the screen of another player LAZYOR(viewer.actions, src) // Move this in
/datum/action/proc/Unshare(mob/freeloader) ShowTo(viewer)
if(!freeloader.client)
//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 return
for(var/freeloader_reference in sharers)
if(IS_WEAKREF_OF(freeloader, freeloader_reference)) var/atom/movable/screen/movable/action_button/button = CreateButton()
sharers -= freeloader_reference SetId(button, viewer)
break
freeloader.client.screen -= button button.our_hud = our_hud
freeloader.actions -= src viewers[our_hud] = button
freeloader.update_action_buttons() 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)
qdel(button)
/datum/action/proc/CreateButton()
var/atom/movable/screen/movable/action_button/button = new()
button.linked_action = src
button.name = name
button.actiontooltipstyle = buttontooltipstyle
if(desc)
button.desc = desc
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
//Presets for item actions //Presets for item actions
/datum/action/item_action /datum/action/item_action
@@ -274,12 +285,14 @@
/datum/action/item_action/set_internals /datum/action/item_action/set_internals
name = "Set Internals" name = "Set Internals"
/datum/action/item_action/set_internals/UpdateButtonIcon(status_only = FALSE, force) /datum/action/item_action/set_internals/UpdateButton(atom/movable/screen/movable/action_button/button, status_only = FALSE, force)
if(..()) //button available if(!..()) // no button available
if(iscarbon(owner)) return
var/mob/living/carbon/C = owner if(!iscarbon(owner))
if(target == C.internal) return
button.icon_state = "template_active" var/mob/living/carbon/C = owner
if(target == C.internal)
button.icon_state = "template_active"
/datum/action/item_action/pick_color /datum/action/item_action/pick_color
name = "Choose A Color" name = "Choose A Color"
@@ -333,7 +346,7 @@
SIGNAL_HANDLER SIGNAL_HANDLER
button_icon_state = "thermal_[suit.thermal_on ? "on" : "off"]" button_icon_state = "thermal_[suit.thermal_on ? "on" : "off"]"
UpdateButtonIcon() UpdateButtons()
/datum/action/item_action/vortex_recall /datum/action/item_action/vortex_recall
name = "Vortex Recall" name = "Vortex Recall"
@@ -387,7 +400,6 @@
..() ..()
var/obj/item/item_target = target var/obj/item/item_target = target
name = "Toggle [item_target.name]" name = "Toggle [item_target.name]"
button.name = name
/datum/action/item_action/halt /datum/action/item_action/halt
name = "HALT!" name = "HALT!"
@@ -413,7 +425,6 @@
..() ..()
var/obj/item/item_target = target var/obj/item/item_target = target
name = "Adjust [item_target.name]" name = "Adjust [item_target.name]"
button.name = name
/datum/action/item_action/switch_hud /datum/action/item_action/switch_hud
name = "Switch HUD" name = "Switch HUD"
@@ -499,13 +510,11 @@
..() ..()
var/obj/item/organ/organ_target = target var/obj/item/organ/organ_target = target
name = "Toggle [organ_target.name]" name = "Toggle [organ_target.name]"
button.name = name
/datum/action/item_action/organ_action/use/New(Target) /datum/action/item_action/organ_action/use/New(Target)
..() ..()
var/obj/item/organ/organ_target = target var/obj/item/organ/organ_target = target
name = "Use [organ_target.name]" name = "Use [organ_target.name]"
button.name = name
/datum/action/item_action/cult_dagger /datum/action/item_action/cult_dagger
name = "Draw Blood Rune" name = "Draw Blood Rune"
@@ -514,15 +523,13 @@
button_icon_state = "draw" button_icon_state = "draw"
buttontooltipstyle = "cult" buttontooltipstyle = "cult"
background_icon_state = "bg_demon" background_icon_state = "bg_demon"
default_button_position = "6:157,4:-2"
/datum/action/item_action/cult_dagger/Grant(mob/M) /datum/action/item_action/cult_dagger/Grant(mob/M)
if(!IS_CULTIST(M)) if(!IS_CULTIST(M))
Remove(owner) Remove(owner)
return return
return ..()
. = ..()
button.screen_loc = "6:157,4:-2"
button.moved = "6:157,4:-2"
/datum/action/item_action/cult_dagger/Trigger(trigger_flags) /datum/action/item_action/cult_dagger/Trigger(trigger_flags)
for(var/obj/item/held_item as anything in owner.held_items) // In case we were already holding a dagger for(var/obj/item/held_item as anything in owner.held_items) // In case we were already holding a dagger
@@ -617,7 +624,6 @@
icon_icon = S.action_icon icon_icon = S.action_icon
button_icon_state = S.action_icon_state button_icon_state = S.action_icon_state
background_icon_state = S.action_background_icon_state background_icon_state = S.action_background_icon_state
button.name = name
/datum/action/spell_action/Destroy() /datum/action/spell_action/Destroy()
var/obj/effect/proc_holder/S = target var/obj/effect/proc_holder/S = target
@@ -695,13 +701,14 @@
// Shares cooldowns with other cooldown abilities of the same value, not active if null // Shares cooldowns with other cooldown abilities of the same value, not active if null
var/shared_cooldown var/shared_cooldown
/datum/action/cooldown/New(Target) /datum/action/cooldown/CreateButton()
..() var/atom/movable/screen/movable/action_button/button = ..()
button.maptext = "" button.maptext = ""
button.maptext_x = 8 button.maptext_x = 8
button.maptext_y = 0 button.maptext_y = 0
button.maptext_width = 24 button.maptext_width = 24
button.maptext_height = 12 button.maptext_height = 12
return button
/datum/action/cooldown/IsAvailable() /datum/action/cooldown/IsAvailable()
return ..() && (next_use_time <= world.time) return ..() && (next_use_time <= world.time)
@@ -723,7 +730,7 @@
next_use_time = world.time + override_cooldown_time next_use_time = world.time + override_cooldown_time
else else
next_use_time = world.time + cooldown_time next_use_time = world.time + cooldown_time
UpdateButtonIcon() UpdateButtons()
START_PROCESSING(SSfastprocess, src) START_PROCESSING(SSfastprocess, src)
/datum/action/cooldown/Trigger(trigger_flags, atom/target) /datum/action/cooldown/Trigger(trigger_flags, atom/target)
@@ -741,7 +748,7 @@
else else
owner.click_intercept = src owner.click_intercept = src
for(var/datum/action/cooldown/ability in owner.actions) for(var/datum/action/cooldown/ability in owner.actions)
ability.UpdateButtonIcon() ability.UpdateButtons()
return TRUE return TRUE
return PreActivate(owner) return PreActivate(owner)
@@ -766,12 +773,13 @@
/datum/action/cooldown/proc/Activate(atom/target) /datum/action/cooldown/proc/Activate(atom/target)
return return
/datum/action/cooldown/UpdateButtonIcon(status_only = FALSE, force = FALSE) /datum/action/cooldown/UpdateButton(atom/movable/screen/movable/action_button/button, status_only = FALSE, force = FALSE)
. = ..() . = ..()
if(!button)
return
var/time_left = max(next_use_time - world.time, 0) var/time_left = max(next_use_time - world.time, 0)
if(button) if(text_cooldown)
if(text_cooldown) button.maptext = MAPTEXT("<b>[round(time_left/10, 0.1)]</b>")
button.maptext = MAPTEXT("<b>[round(time_left/10, 0.1)]</b>")
if(!owner || time_left == 0) if(!owner || time_left == 0)
button.maptext = "" button.maptext = ""
if(IsAvailable() && owner.click_intercept == src) if(IsAvailable() && owner.click_intercept == src)
@@ -781,28 +789,28 @@
var/time_left = max(next_use_time - world.time, 0) var/time_left = max(next_use_time - world.time, 0)
if(!owner || time_left == 0) if(!owner || time_left == 0)
STOP_PROCESSING(SSfastprocess, src) STOP_PROCESSING(SSfastprocess, src)
UpdateButtonIcon() UpdateButtons()
/datum/action/cooldown/Grant(mob/M) /datum/action/cooldown/Grant(mob/M)
..() ..()
if(owner) if(!owner)
UpdateButtonIcon() return
if(next_use_time > world.time) UpdateButtons()
START_PROCESSING(SSfastprocess, src) if(next_use_time > world.time)
START_PROCESSING(SSfastprocess, src)
///Like a cooldown action, but with an associated proc holder. ///Like a cooldown action, but with an associated proc holder.
/datum/action/cooldown/spell_like /datum/action/cooldown/spell_like
/datum/action/cooldown/spell_like/New(Target) /datum/action/cooldown/spell_like/New(Target)
..() ..()
var/obj/effect/proc_holder/our_proc_holder = target var/obj/effect/proc_holder/our_proc_holder = Target
our_proc_holder.action = src our_proc_holder.action = src
name = our_proc_holder.name name = our_proc_holder.name
desc = our_proc_holder.desc desc = our_proc_holder.desc
icon_icon = our_proc_holder.action_icon icon_icon = our_proc_holder.action_icon
button_icon_state = our_proc_holder.action_icon_state button_icon_state = our_proc_holder.action_icon_state
background_icon_state = our_proc_holder.action_background_icon_state background_icon_state = our_proc_holder.action_background_icon_state
button.name = name
/datum/action/cooldown/spell_like/Activate(atom/activate_target) /datum/action/cooldown/spell_like/Activate(atom/activate_target)
if(!target) if(!target)

View File

@@ -275,7 +275,7 @@
name = "Hide" name = "Hide"
desc = "Hide yourself from your owner's sight." desc = "Hide yourself from your owner's sight."
button_icon_state = "hide" button_icon_state = "hide"
UpdateButtonIcon() UpdateButtons()
/datum/action/innate/imaginary_hide/Activate() /datum/action/innate/imaginary_hide/Activate()
var/mob/camera/imaginary_friend/I = owner var/mob/camera/imaginary_friend/I = owner

View File

@@ -49,7 +49,7 @@
admin_popup = new admin_popup = new
var/client/parent_client = parent var/client/parent_client = parent
admin_popup.maptext_width = getviewsize(parent_client.view_size.getView())[1] * world.icon_size admin_popup.maptext_width = view_to_pixels(parent_client.view_size.getView())[1]
parent_client.screen += admin_popup parent_client.screen += admin_popup
/datum/component/admin_popup/proc/delete_self() /datum/component/admin_popup/proc/delete_self()

View File

@@ -141,7 +141,7 @@
var/obj/effect/proc_holder/proc_holder = ability var/obj/effect/proc_holder/proc_holder = ability
if(!proc_holder.action) if(!proc_holder.action)
return return
proc_holder.action.Share(rider) proc_holder.action.GiveAction(rider)
/// Takes away the riding parent's abilities from the rider /// Takes away the riding parent's abilities from the rider
/datum/component/riding/creature/proc/remove_abilities(mob/living/rider) /datum/component/riding/creature/proc/remove_abilities(mob/living/rider)
@@ -156,7 +156,7 @@
return return
if(rider == proc_holder.ranged_ability_user) if(rider == proc_holder.ranged_ability_user)
proc_holder.remove_ranged_ability() proc_holder.remove_ranged_ability()
proc_holder.action.Unshare(rider) proc_holder.action.HideFrom(rider)
/datum/component/riding/creature/riding_can_z_move(atom/movable/movable_parent, direction, turf/start, turf/destination, z_move_flags, mob/living/rider) /datum/component/riding/creature/riding_can_z_move(atom/movable/movable_parent, direction, turf/start, turf/destination, z_move_flags, mob/living/rider)
if(!(z_move_flags & ZMOVE_CAN_FLY_CHECKS)) if(!(z_move_flags & ZMOVE_CAN_FLY_CHECKS))

View File

@@ -841,7 +841,7 @@
if(istype(S, type)) if(istype(S, type))
continue continue
S.charge_counter = delay S.charge_counter = delay
S.updateButtonIcon() S.updateButtons()
INVOKE_ASYNC(S, /obj/effect/proc_holder/spell.proc/start_recharge) INVOKE_ASYNC(S, /obj/effect/proc_holder/spell.proc/start_recharge)
/datum/mind/proc/get_ghost(even_if_they_cant_reenter, ghosts_with_clients) /datum/mind/proc/get_ghost(even_if_they_cant_reenter, ghosts_with_clients)

View File

@@ -33,11 +33,13 @@
default = string default = string
apply() apply()
/datum/view_data/proc/safeApplyFormat() /datum/view_data/proc/afterViewChange()
if(isZooming()) if(isZooming())
assertFormat() assertFormat()
return else
resetFormat() resetFormat()
var/datum/hud/our_hud = chief?.mob?.hud_used
our_hud.view_audit_buttons() // Make sure our hud's buttons are in our new size
/datum/view_data/proc/assertFormat()//T-Pose /datum/view_data/proc/assertFormat()//T-Pose
winset(chief, "mapwindow.map", "zoom=0") winset(chief, "mapwindow.map", "zoom=0")
@@ -99,7 +101,7 @@
/datum/view_data/proc/apply() /datum/view_data/proc/apply()
chief?.change_view(getView()) chief?.change_view(getView())
safeApplyFormat() afterViewChange()
/datum/view_data/proc/supress() /datum/view_data/proc/supress()
is_suppressed = TRUE is_suppressed = TRUE

View File

@@ -1285,7 +1285,7 @@ GLOBAL_DATUM_INIT(fire_overlay, /mutable_appearance, mutable_appearance('icons/e
*/ */
/obj/item/proc/update_action_buttons(status_only = FALSE, force = FALSE) /obj/item/proc/update_action_buttons(status_only = FALSE, force = FALSE)
for(var/datum/action/current_action as anything in actions) for(var/datum/action/current_action as anything in actions)
current_action.UpdateButtonIcon(status_only, force) current_action.UpdateButtons(status_only, force)
// Update icons if this is being carried by a mob // Update icons if this is being carried by a mob
/obj/item/wash(clean_types) /obj/item/wash(clean_types)

View File

@@ -105,13 +105,13 @@
to_chat(owner, span_notice("You will now fold origami planes.")) to_chat(owner, span_notice("You will now fold origami planes."))
button_icon_state = "origami_on" button_icon_state = "origami_on"
active = TRUE active = TRUE
UpdateButtonIcon() UpdateButtons()
/datum/action/innate/origami/Deactivate() /datum/action/innate/origami/Deactivate()
to_chat(owner, span_notice("You will no longer fold origami planes.")) to_chat(owner, span_notice("You will no longer fold origami planes."))
button_icon_state = "origami_off" button_icon_state = "origami_off"
active = FALSE active = FALSE
UpdateButtonIcon() UpdateButtons()
///SPELLS/// ///SPELLS///

View File

@@ -114,7 +114,7 @@
var/client/controlling_client = controller.client var/client/controlling_client = controller.client
if(controlling_client) if(controlling_client)
var/modifiers = params2list(controlling_client.mouseParams) var/modifiers = params2list(controlling_client.mouseParams)
var/atom/target_atom = controlling_client.mouseObject var/atom/target_atom = controlling_client.mouse_object_ref?.resolve()
var/turf/target_turf = get_turf(target_atom) var/turf/target_turf = get_turf(target_atom)
if(istype(target_turf)) //They're hovering over something in the map. if(istype(target_turf)) //They're hovering over something in the map.
direction_track(controller, target_turf) direction_track(controller, target_turf)

View File

@@ -404,7 +404,7 @@ GLOBAL_LIST_INIT_TYPED(sdql_spells, /obj/effect/proc_holder/spell, list())
if("confirm") if("confirm")
if(target_spell) if(target_spell)
reassign_vars(target_spell) reassign_vars(target_spell)
target_spell.action.UpdateButtonIcon() target_spell.action.UpdateButtons()
log_admin("[key_name(user)] edited the SDQL spell \"[target_spell]\" owned by [key_name(target_mob)].") log_admin("[key_name(user)] edited the SDQL spell \"[target_spell]\" owned by [key_name(target_mob)].")
else else
var/new_spell = give_spell() var/new_spell = give_spell()
@@ -895,7 +895,7 @@ GLOBAL_LIST_INIT_TYPED(sdql_spells, /obj/effect/proc_holder/spell, list())
var/obj/effect/proc_holder/spell/new_spell = new path(null, target_mob, user.ckey) var/obj/effect/proc_holder/spell/new_spell = new path(null, target_mob, user.ckey)
GLOB.sdql_spells += new_spell GLOB.sdql_spells += new_spell
reassign_vars(new_spell) reassign_vars(new_spell)
new_spell.action.UpdateButtonIcon() new_spell.action.UpdateButtons()
if(target_mob.mind) if(target_mob.mind)
target_mob.mind.AddSpell(new_spell) target_mob.mind.AddSpell(new_spell)
else else

View File

@@ -95,7 +95,6 @@
/datum/action/innate/cellular_emporium/New(our_target) /datum/action/innate/cellular_emporium/New(our_target)
. = ..() . = ..()
button.name = name
if(istype(our_target, /datum/cellular_emporium)) if(istype(our_target, /datum/cellular_emporium))
cellular_emporium = our_target cellular_emporium = our_target
else else

View File

@@ -18,7 +18,7 @@
name = "Reviving Stasis" name = "Reviving Stasis"
desc = "We fall into a stasis, allowing us to regenerate and trick our enemies." desc = "We fall into a stasis, allowing us to regenerate and trick our enemies."
button_icon_state = "fake_death" button_icon_state = "fake_death"
UpdateButtonIcon() UpdateButtons()
chemical_cost = 15 chemical_cost = 15
to_chat(user, span_notice("We have revived ourselves.")) to_chat(user, span_notice("We have revived ourselves."))
else else
@@ -58,7 +58,7 @@
name = "Revive" name = "Revive"
desc = "We arise once more." desc = "We arise once more."
button_icon_state = "revive" button_icon_state = "revive"
UpdateButtonIcon() UpdateButtons()
chemical_cost = 0 chemical_cost = 0
revive_ready = TRUE revive_ready = TRUE

View File

@@ -2,15 +2,10 @@
name = "Prepare Blood Magic" name = "Prepare Blood Magic"
button_icon_state = "carve" button_icon_state = "carve"
desc = "Prepare blood magic by carving runes into your flesh. This is easier with an <b>empowering rune</b>." desc = "Prepare blood magic by carving runes into your flesh. This is easier with an <b>empowering rune</b>."
default_button_position = DEFAULT_BLOODSPELLS
var/list/spells = list() var/list/spells = list()
var/channeling = FALSE var/channeling = FALSE
/datum/action/innate/cult/blood_magic/Grant()
..()
button.screen_loc = DEFAULT_BLOODSPELLS
button.moved = DEFAULT_BLOODSPELLS
button.ordered = FALSE
/datum/action/innate/cult/blood_magic/Remove() /datum/action/innate/cult/blood_magic/Remove()
for(var/X in spells) for(var/X in spells)
qdel(X) qdel(X)
@@ -22,15 +17,21 @@
return ..() return ..()
/datum/action/innate/cult/blood_magic/proc/Positioning() /datum/action/innate/cult/blood_magic/proc/Positioning()
var/list/screen_loc_split = splittext(button.screen_loc,",") for(var/datum/hud/hud as anything in viewers)
var/list/screen_loc_X = splittext(screen_loc_split[1],":") var/our_view = hud.mymob?.client?.view || "15x15"
var/list/screen_loc_Y = splittext(screen_loc_split[2],":") var/atom/movable/screen/movable/action_button/button = viewers[hud]
var/pix_X = text2num(screen_loc_X[2]) var/position = screen_loc_to_offset(button.screen_loc)
for(var/datum/action/innate/cult/blood_spell/B in spells) var/spells_iterated = 0
if(B.button.locked) for(var/datum/action/innate/cult/blood_spell/blood_spell in spells)
var/order = pix_X+spells.Find(B)*31 spells_iterated += 1
B.button.screen_loc = "[screen_loc_X[1]]:[order],[screen_loc_Y[1]]:[screen_loc_Y[2]]" if(blood_spell.positioned)
B.button.moved = B.button.screen_loc 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() /datum/action/innate/cult/blood_magic/Activate()
var/rune = FALSE var/rune = FALSE
@@ -97,6 +98,8 @@
var/base_desc //To allow for updating tooltips var/base_desc //To allow for updating tooltips
var/invocation var/invocation
var/health_cost = 0 var/health_cost = 0
/// Have we already been positioned into our starting location?
var/positioned = FALSE
/datum/action/innate/cult/blood_spell/Grant(mob/living/owner, datum/action/innate/cult/blood_magic/BM) /datum/action/innate/cult/blood_spell/Grant(mob/living/owner, datum/action/innate/cult/blood_magic/BM)
if(health_cost) if(health_cost)
@@ -104,9 +107,7 @@
base_desc = desc base_desc = desc
desc += "<br><b><u>Has [charges] use\s remaining</u></b>." desc += "<br><b><u>Has [charges] use\s remaining</u></b>."
all_magic = BM all_magic = BM
..() return ..()
button.locked = TRUE
button.ordered = FALSE
/datum/action/innate/cult/blood_spell/Remove() /datum/action/innate/cult/blood_spell/Remove()
if(all_magic) if(all_magic)
@@ -275,7 +276,7 @@
attached_action.charges-- attached_action.charges--
attached_action.desc = attached_action.base_desc attached_action.desc = attached_action.base_desc
attached_action.desc += "<br><b><u>Has [attached_action.charges] use\s remaining</u></b>." attached_action.desc += "<br><b><u>Has [attached_action.charges] use\s remaining</u></b>."
attached_action.UpdateButtonIcon() attached_action.UpdateButtons()
if(attached_action.charges <= 0) if(attached_action.charges <= 0)
remove_ranged_ability(span_cult("You have exhausted the spell's power!")) remove_ranged_ability(span_cult("You have exhausted the spell's power!"))
qdel(src) qdel(src)
@@ -331,7 +332,7 @@
qdel(src) qdel(src)
desc = base_desc desc = base_desc
desc += "<br><b><u>Has [charges] use\s remaining</u></b>." desc += "<br><b><u>Has [charges] use\s remaining</u></b>."
UpdateButtonIcon() UpdateButtons()
/datum/action/innate/cult/blood_spell/manipulation /datum/action/innate/cult/blood_spell/manipulation
name = "Blood Rites" name = "Blood Rites"
@@ -380,7 +381,7 @@
source.charges = uses source.charges = uses
source.desc = source.base_desc source.desc = source.base_desc
source.desc += "<br><b><u>Has [uses] use\s remaining</u></b>." source.desc += "<br><b><u>Has [uses] use\s remaining</u></b>."
source.UpdateButtonIcon() source.UpdateButtons()
return ..() return ..()
/obj/item/melee/blood_magic/attack_self(mob/living/user) /obj/item/melee/blood_magic/attack_self(mob/living/user)
@@ -409,7 +410,7 @@
else if(source) else if(source)
source.desc = source.base_desc source.desc = source.base_desc
source.desc += "<br><b><u>Has [uses] use\s remaining</u></b>." source.desc += "<br><b><u>Has [uses] use\s remaining</u></b>."
source.UpdateButtonIcon() source.UpdateButtons()
//Stun //Stun
/obj/item/melee/blood_magic/stun /obj/item/melee/blood_magic/stun

View File

@@ -805,14 +805,13 @@ Striking a noncultist, however, will tear their flesh."}
desc = "Call the bloody halberd back to your hand!" desc = "Call the bloody halberd back to your hand!"
background_icon_state = "bg_demon" background_icon_state = "bg_demon"
button_icon_state = "bloodspear" button_icon_state = "bloodspear"
default_button_position = "6:157,4:-2"
var/obj/item/melee/cultblade/halberd/halberd var/obj/item/melee/cultblade/halberd/halberd
var/cooldown = 0 var/cooldown = 0
/datum/action/innate/cult/halberd/Grant(mob/user, obj/blood_halberd) /datum/action/innate/cult/halberd/Grant(mob/user, obj/blood_halberd)
. = ..() . = ..()
halberd = blood_halberd halberd = blood_halberd
button.screen_loc = "6:157,4:-2"
button.moved = "6:157,4:-2"
/datum/action/innate/cult/halberd/Activate() /datum/action/innate/cult/halberd/Activate()
if(owner == halberd.loc || cooldown > world.time) if(owner == halberd.loc || cooldown > world.time)

View File

@@ -43,7 +43,7 @@
organ_parent.icon = 'icons/obj/eldritch.dmi' organ_parent.icon = 'icons/obj/eldritch.dmi'
organ_parent.icon_state = "living_heart" organ_parent.icon_state = "living_heart"
action.UpdateButtonIcon() action.UpdateButtons()
/datum/component/living_heart/Destroy(force, silent) /datum/component/living_heart/Destroy(force, silent)
QDEL_NULL(action) QDEL_NULL(action)

View File

@@ -189,7 +189,7 @@
user.reveal(reveal) user.reveal(reveal)
user.stun(stun) user.stun(stun)
if(action) if(action)
action.UpdateButtonIcon() action.UpdateButtons()
return TRUE return TRUE
//Overload Light: Breaks a light that's online and sends out lightning bolts to all nearby people. //Overload Light: Breaks a light that's online and sends out lightning bolts to all nearby people.

View File

@@ -430,7 +430,6 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
/datum/action/innate/ai/ranged/override_machine/New() /datum/action/innate/ai/ranged/override_machine/New()
..() ..()
desc = "[desc] It has [uses] use\s remaining." desc = "[desc] It has [uses] use\s remaining."
button.desc = desc
/datum/action/innate/ai/ranged/override_machine/proc/animate_machine(obj/machinery/M) /datum/action/innate/ai/ranged/override_machine/proc/animate_machine(obj/machinery/M)
if(M && !QDELETED(M)) if(M && !QDELETED(M))
@@ -458,7 +457,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
attached_action.adjust_uses(-1) attached_action.adjust_uses(-1)
if(attached_action?.uses) if(attached_action?.uses)
attached_action.desc = "[initial(attached_action.desc)] It has [attached_action.uses] use\s remaining." attached_action.desc = "[initial(attached_action.desc)] It has [attached_action.uses] use\s remaining."
attached_action.UpdateButtonIcon() attached_action.UpdateButtons()
target.audible_message(span_userdanger("You hear a loud electrical buzzing sound coming from [target]!")) target.audible_message(span_userdanger("You hear a loud electrical buzzing sound coming from [target]!"))
addtimer(CALLBACK(attached_action, /datum/action/innate/ai/ranged/override_machine.proc/animate_machine, target), 50) //kabeep! addtimer(CALLBACK(attached_action, /datum/action/innate/ai/ranged/override_machine.proc/animate_machine, target), 50) //kabeep!
remove_ranged_ability(span_danger("Sending override signal...")) remove_ranged_ability(span_danger("Sending override signal..."))
@@ -508,7 +507,6 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
/datum/action/innate/ai/ranged/overload_machine/New() /datum/action/innate/ai/ranged/overload_machine/New()
..() ..()
desc = "[desc] It has [uses] use\s remaining." desc = "[desc] It has [uses] use\s remaining."
button.desc = desc
/datum/action/innate/ai/ranged/overload_machine/proc/detonate_machine(obj/machinery/M) /datum/action/innate/ai/ranged/overload_machine/proc/detonate_machine(obj/machinery/M)
if(M && !QDELETED(M)) if(M && !QDELETED(M))
@@ -541,7 +539,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
attached_action.adjust_uses(-1) attached_action.adjust_uses(-1)
if(attached_action?.uses) if(attached_action?.uses)
attached_action.desc = "[initial(attached_action.desc)] It has [attached_action.uses] use\s remaining." attached_action.desc = "[initial(attached_action.desc)] It has [attached_action.uses] use\s remaining."
attached_action.UpdateButtonIcon() attached_action.UpdateButtons()
target.audible_message(span_userdanger("You hear a loud electrical buzzing sound coming from [target]!")) target.audible_message(span_userdanger("You hear a loud electrical buzzing sound coming from [target]!"))
addtimer(CALLBACK(attached_action, /datum/action/innate/ai/ranged/overload_machine.proc/detonate_machine, target), 50) //kaboom! addtimer(CALLBACK(attached_action, /datum/action/innate/ai/ranged/overload_machine.proc/detonate_machine, target), 50) //kaboom!
remove_ranged_ability(span_danger("Overcharging machine...")) remove_ranged_ability(span_danger("Overcharging machine..."))
@@ -566,7 +564,6 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
/datum/action/innate/ai/blackout/New() /datum/action/innate/ai/blackout/New()
..() ..()
desc = "[desc] It has [uses] use\s remaining." desc = "[desc] It has [uses] use\s remaining."
button.desc = desc
/datum/action/innate/ai/blackout/Activate() /datum/action/innate/ai/blackout/Activate()
for(var/obj/machinery/power/apc/apc in GLOB.apcs_list) for(var/obj/machinery/power/apc/apc in GLOB.apcs_list)
@@ -577,9 +574,10 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
to_chat(owner, span_notice("Overcurrent applied to the powernet.")) to_chat(owner, span_notice("Overcurrent applied to the powernet."))
owner.playsound_local(owner, SFX_SPARKS, 50, 0) owner.playsound_local(owner, SFX_SPARKS, 50, 0)
adjust_uses(-1) adjust_uses(-1)
if(src && uses) //Not sure if not having src here would cause a runtime, so it's here to be safe if(QDELETED(src) || uses) //Not sure if not having src here would cause a runtime, so it's here to be safe
desc = "[initial(desc)] It has [uses] use\s remaining." return
UpdateButtonIcon() desc = "[initial(desc)] It has [uses] use\s remaining."
UpdateButtons()
/// HIGH IMPACT HONKING /// HIGH IMPACT HONKING
/datum/ai_module/destructive/megahonk /datum/ai_module/destructive/megahonk
@@ -785,7 +783,6 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
/datum/action/innate/ai/reactivate_cameras/New() /datum/action/innate/ai/reactivate_cameras/New()
..() ..()
desc = "[desc] It has [uses] use\s remaining." desc = "[desc] It has [uses] use\s remaining."
button.desc = desc
/datum/action/innate/ai/reactivate_cameras/Activate() /datum/action/innate/ai/reactivate_cameras/Activate()
var/fixed_cameras = 0 var/fixed_cameras = 0
@@ -801,9 +798,10 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
to_chat(owner, span_notice("Diagnostic complete! Cameras reactivated: <b>[fixed_cameras]</b>. Reactivations remaining: <b>[uses]</b>.")) to_chat(owner, span_notice("Diagnostic complete! Cameras reactivated: <b>[fixed_cameras]</b>. Reactivations remaining: <b>[uses]</b>."))
owner.playsound_local(owner, 'sound/items/wirecutter.ogg', 50, 0) owner.playsound_local(owner, 'sound/items/wirecutter.ogg', 50, 0)
adjust_uses(0, TRUE) //Checks the uses remaining adjust_uses(0, TRUE) //Checks the uses remaining
if(src && uses) //Not sure if not having src here would cause a runtime, so it's here to be safe if(QDELETED(src) || !uses) //Not sure if not having src here would cause a runtime, so it's here to be safe
desc = "[initial(desc)] It has [uses] use\s remaining." return
UpdateButtonIcon() desc = "[initial(desc)] It has [uses] use\s remaining."
UpdateButtons()
/// Upgrade Camera Network: EMP-proofs all cameras, in addition to giving them X-ray vision. /// Upgrade Camera Network: EMP-proofs all cameras, in addition to giving them X-ray vision.
/datum/ai_module/upgrade/upgrade_cameras /datum/ai_module/upgrade/upgrade_cameras

View File

@@ -120,6 +120,6 @@
else //Adding uses to an existing module else //Adding uses to an existing module
action.uses += initial(action.uses) action.uses += initial(action.uses)
action.desc = "[initial(action.desc)] It has [action.uses] use\s remaining." action.desc = "[initial(action.desc)] It has [action.uses] use\s remaining."
action.UpdateButtonIcon() action.UpdateButtons()
processing_time -= AM.cost processing_time -= AM.cost
SSblackbox.record_feedback("nested tally", "malfunction_modules_bought", 1, list("[initial(AM.name)]", "[AM.cost]")) SSblackbox.record_feedback("nested tally", "malfunction_modules_bought", 1, list("[initial(AM.name)]", "[AM.cost]"))

View File

@@ -166,14 +166,15 @@
var/obj/item/active_mousedown_item = null var/obj/item/active_mousedown_item = null
///Used in MouseDrag to preserve the original mouse click parameters ///Used in MouseDrag to preserve the original mouse click parameters
var/mouseParams = "" var/mouseParams = ""
///Used in MouseDrag to preserve the last mouse-entered location. ///Used in MouseDrag to preserve the last mouse-entered location. Weakref
var/mouseLocation = null var/datum/weakref/mouse_location_ref = null
///Used in MouseDrag to preserve the last mouse-entered object. ///Used in MouseDrag to preserve the last mouse-entered object. Weakref
var/mouseObject = null var/datum/weakref/mouse_object_ref
//Middle-mouse-button click dragtime control for aimbot exploit detection. //Middle-mouse-button click dragtime control for aimbot exploit detection.
var/middragtime = 0 var/middragtime = 0
//Middle-mouse-button clicked object control for aimbot exploit detection. //Middle-mouse-button clicked object control for aimbot exploit detection. Weakref
var/atom/middragatom var/datum/weakref/middle_drag_atom_ref
/// Messages currently seen by this client /// Messages currently seen by this client
var/list/seen_messages var/list/seen_messages

View File

@@ -911,7 +911,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
if(dragged && !LAZYACCESS(modifiers, dragged)) //I don't know what's going on here, but I don't trust it if(dragged && !LAZYACCESS(modifiers, dragged)) //I don't know what's going on here, but I don't trust it
return return
if (object && object == middragatom && LAZYACCESS(modifiers, LEFT_CLICK)) if (object && IS_WEAKREF_OF(object, middle_drag_atom_ref) && LAZYACCESS(modifiers, LEFT_CLICK))
ab = max(0, 5 SECONDS-(world.time-middragtime)*0.1) ab = max(0, 5 SECONDS-(world.time-middragtime)*0.1)
var/mcl = CONFIG_GET(number/minute_click_limit) var/mcl = CONFIG_GET(number/minute_click_limit)
@@ -960,6 +960,8 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
else else
winset(src, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED]") winset(src, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED]")
SEND_SIGNAL(src, COMSIG_CLIENT_CLICK, object, location, control, params, usr)
..() ..()
/client/proc/add_verbs_from_config() /client/proc/add_verbs_from_config()

View File

@@ -1,5 +0,0 @@
/datum/preference/toggle/buttons_locked
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "buttons_locked"
savefile_identifier = PREFERENCE_PLAYER
default_value = FALSE

View File

@@ -164,8 +164,8 @@
..() ..()
/datum/action/item_action/chameleon/change/proc/initialize_disguises() /datum/action/item_action/chameleon/change/proc/initialize_disguises()
if(button) name = "Change [chameleon_name] Appearance"
button.name = "Change [chameleon_name] Appearance" UpdateButtons()
chameleon_blacklist |= typecacheof(target.type) chameleon_blacklist |= typecacheof(target.type)
for(var/V in typesof(chameleon_type)) for(var/V in typesof(chameleon_type))
@@ -210,7 +210,7 @@
update_item(picked_item) update_item(picked_item)
var/obj/item/thing = target var/obj/item/thing = target
thing.update_slot_icon() thing.update_slot_icon()
UpdateButtonIcon() UpdateButtons()
/datum/action/item_action/chameleon/change/proc/update_item(obj/item/picked_item) /datum/action/item_action/chameleon/change/proc/update_item(obj/item/picked_item)
var/atom/atom_target = target var/atom/atom_target = target
@@ -326,8 +326,8 @@
agent_card.update_icon() agent_card.update_icon()
/datum/action/item_action/chameleon/change/id_trim/initialize_disguises() /datum/action/item_action/chameleon/change/id_trim/initialize_disguises()
if(button) name = "Change [chameleon_name] Appearance"
button.name = "Change [chameleon_name] Appearance" UpdateButtons()
chameleon_blacklist |= typecacheof(target.type) chameleon_blacklist |= typecacheof(target.type)
for(var/trim_path in typesof(chameleon_type)) for(var/trim_path in typesof(chameleon_type))
@@ -535,9 +535,9 @@
ADD_TRAIT(src, TRAIT_NODROP, ABSTRACT_ITEM_TRAIT) ADD_TRAIT(src, TRAIT_NODROP, ABSTRACT_ITEM_TRAIT)
chameleon_action.random_look() chameleon_action.random_look()
var/datum/action/item_action/chameleon/drone/togglehatmask/togglehatmask_action = new(src) var/datum/action/item_action/chameleon/drone/togglehatmask/togglehatmask_action = new(src)
togglehatmask_action.UpdateButtonIcon() togglehatmask_action.UpdateButtons()
var/datum/action/item_action/chameleon/drone/randomise/randomise_action = new(src) var/datum/action/item_action/chameleon/drone/randomise/randomise_action = new(src)
randomise_action.UpdateButtonIcon() randomise_action.UpdateButtons()
/obj/item/clothing/mask/chameleon /obj/item/clothing/mask/chameleon
name = "gas mask" name = "gas mask"
@@ -592,9 +592,9 @@
ADD_TRAIT(src, TRAIT_NODROP, ABSTRACT_ITEM_TRAIT) ADD_TRAIT(src, TRAIT_NODROP, ABSTRACT_ITEM_TRAIT)
chameleon_action.random_look() chameleon_action.random_look()
var/datum/action/item_action/chameleon/drone/togglehatmask/togglehatmask_action = new(src) var/datum/action/item_action/chameleon/drone/togglehatmask/togglehatmask_action = new(src)
togglehatmask_action.UpdateButtonIcon() togglehatmask_action.UpdateButtons()
var/datum/action/item_action/chameleon/drone/randomise/randomise_action = new(src) var/datum/action/item_action/chameleon/drone/randomise/randomise_action = new(src)
randomise_action.UpdateButtonIcon() randomise_action.UpdateButtons()
/obj/item/clothing/mask/chameleon/drone/attack_self(mob/user) /obj/item/clothing/mask/chameleon/drone/attack_self(mob/user)
to_chat(user, span_notice("[src] does not have a voice changer.")) to_chat(user, span_notice("[src] does not have a voice changer."))

View File

@@ -210,7 +210,7 @@ Doesn't work on other aliens/AI.*/
/obj/effect/proc_holder/alien/neurotoxin/update_icon() /obj/effect/proc_holder/alien/neurotoxin/update_icon()
action.button_icon_state = "alien_neurotoxin_[active]" action.button_icon_state = "alien_neurotoxin_[active]"
action.UpdateButtonIcon() action.UpdateButtons()
return ..() return ..()
/obj/effect/proc_holder/alien/neurotoxin/InterceptClickOn(mob/living/caller, params, atom/target) /obj/effect/proc_holder/alien/neurotoxin/InterceptClickOn(mob/living/caller, params, atom/target)
@@ -332,7 +332,7 @@ Doesn't work on other aliens/AI.*/
for(var/X in abilities) for(var/X in abilities)
var/obj/effect/proc_holder/alien/APH = X var/obj/effect/proc_holder/alien/APH = X
if(APH.has_action) if(APH.has_action)
APH.action.UpdateButtonIcon() APH.action.UpdateButtons()
return TRUE return TRUE
/mob/living/carbon/alien/adjustPlasma(amount) /mob/living/carbon/alien/adjustPlasma(amount)

View File

@@ -569,9 +569,9 @@
spark_system.start() spark_system.start()
do_teleport(H, get_turf(H), 12, asoundin = 'sound/weapons/emitter2.ogg', channel = TELEPORT_CHANNEL_BLUESPACE) do_teleport(H, get_turf(H), 12, asoundin = 'sound/weapons/emitter2.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
last_teleport = world.time last_teleport = world.time
UpdateButtonIcon() //action icon looks unavailable UpdateButtons() //action icon looks unavailable
//action icon looks available again //action icon looks available again
addtimer(CALLBACK(src, .proc/UpdateButtonIcon), cooldown + 5) addtimer(CALLBACK(src, .proc/UpdateButtons), cooldown + 5)
//honk //honk

View File

@@ -69,7 +69,7 @@
Cannibalize_Body(H) Cannibalize_Body(H)
if(regenerate_limbs) if(regenerate_limbs)
regenerate_limbs.UpdateButtonIcon() regenerate_limbs.UpdateButtons()
/datum/species/jelly/proc/Cannibalize_Body(mob/living/carbon/human/H) /datum/species/jelly/proc/Cannibalize_Body(mob/living/carbon/human/H)
var/list/limbs_to_consume = list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) - H.get_missing_limbs() var/list/limbs_to_consume = list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) - H.get_missing_limbs()
@@ -475,9 +475,9 @@
/datum/species/jelly/luminescent/proc/update_slime_actions() /datum/species/jelly/luminescent/proc/update_slime_actions()
integrate_extract.update_name() integrate_extract.update_name()
integrate_extract.UpdateButtonIcon() integrate_extract.UpdateButtons()
extract_minor.UpdateButtonIcon() extract_minor.UpdateButtons()
extract_major.UpdateButtonIcon() extract_major.UpdateButtons()
/datum/species/jelly/luminescent/proc/update_glow(mob/living/carbon/C, intensity) /datum/species/jelly/luminescent/proc/update_glow(mob/living/carbon/C, intensity)
if(intensity) if(intensity)
@@ -516,7 +516,7 @@
name = "Eject Extract" name = "Eject Extract"
desc = "Eject your current slime extract." desc = "Eject your current slime extract."
/datum/action/innate/integrate_extract/UpdateButtonIcon(status_only, force) /datum/action/innate/integrate_extract/UpdateButtons(status_only, force)
var/datum/species/jelly/luminescent/species = target var/datum/species/jelly/luminescent/species = target
if(!species || !species.current_extract) if(!species || !species.current_extract)
button_icon_state = "slimeconsume" button_icon_state = "slimeconsume"

View File

@@ -797,7 +797,7 @@
if(mind) if(mind)
for(var/S in mind.spell_list) for(var/S in mind.spell_list)
var/obj/effect/proc_holder/spell/spell = S var/obj/effect/proc_holder/spell/spell = S
spell.updateButtonIcon() spell.updateButtons()
if(excess_healing) if(excess_healing)
INVOKE_ASYNC(src, .proc/emote, "gasp") INVOKE_ASYNC(src, .proc/emote, "gasp")
log_combat(src, src, "revived") log_combat(src, src, "revived")

View File

@@ -500,7 +500,7 @@
if(!wash_audio.is_active()) if(!wash_audio.is_active())
wash_audio.start() wash_audio.start()
clean() clean()
UpdateButtonIcon() UpdateButtons()
/// Start the process of disabling the buffer. Plays some effects, waits a bit, then finishes /// Start the process of disabling the buffer. Plays some effects, waits a bit, then finishes
/datum/action/toggle_buffer/proc/deactivate_wash() /datum/action/toggle_buffer/proc/deactivate_wash()
@@ -530,7 +530,7 @@
var/mob/living/silicon/robot/robot_owner = owner var/mob/living/silicon/robot/robot_owner = owner
buffer_on = FALSE buffer_on = FALSE
robot_owner.remove_movespeed_modifier(/datum/movespeed_modifier/auto_wash) robot_owner.remove_movespeed_modifier(/datum/movespeed_modifier/auto_wash)
UpdateButtonIcon() UpdateButtons()
/// Should we keep trying to activate our buffer, or did you fuck it up somehow /// Should we keep trying to activate our buffer, or did you fuck it up somehow
/datum/action/toggle_buffer/proc/allow_buffer_activate() /datum/action/toggle_buffer/proc/allow_buffer_activate()
@@ -567,7 +567,7 @@
// We use more water doing this then mopping // We use more water doing this then mopping
reagents.remove_any(2) //reaction() doesn't use up the reagents reagents.remove_any(2) //reaction() doesn't use up the reagents
/datum/action/toggle_buffer/UpdateButtonIcon(status_only = FALSE, force = FALSE) /datum/action/toggle_buffer/UpdateButtons(status_only = FALSE, force = FALSE)
if(buffer_on) if(buffer_on)
name = "De-Activate Auto-Wash" name = "De-Activate Auto-Wash"
button_icon_state = "deactivate_wash" button_icon_state = "deactivate_wash"

View File

@@ -54,21 +54,18 @@
ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT) ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT)
var/spellnum = 1 var/spellnum = 1
for(var/spell in construct_spells) for(var/spell in construct_spells)
var/the_spell = new spell(null)
AddSpell(the_spell)
var/obj/effect/proc_holder/spell/S = mob_spell_list[spellnum]
var/pos = 2+spellnum*31 var/pos = 2+spellnum*31
if(construct_spells.len >= 4) if(construct_spells.len >= 4)
pos -= 31*(construct_spells.len - 4) pos -= 31*(construct_spells.len - 4)
S.action.button.screen_loc = "6:[pos],4:-2" var/obj/effect/proc_holder/spell/the_spell = new spell(null)
S.action.button.moved = "6:[pos],4:-2" the_spell?.action.default_button_position ="6:[pos],4:-2"
AddSpell(the_spell)
spellnum++ spellnum++
if(runetype) if(runetype)
our_rune = new runetype(src)
our_rune.Grant(src)
var/pos = 2+spellnum*31 var/pos = 2+spellnum*31
our_rune.button.screen_loc = "6:[pos],4:-2" our_rune = new runetype(src)
our_rune.button.moved = "6:[pos],4:-2" our_rune.default_button_position = "6:[pos],4:-2" // Set the default position to this random position
our_rune.Grant(src)
if(icon_state) if(icon_state)
add_overlay("glow_[icon_state]_[theme]") add_overlay("glow_[icon_state]_[theme]")

View File

@@ -337,7 +337,7 @@
if(ishuman(living_target) && (living_target.stat != DEAD || !consumed_mobs[living_target.tag])) //if they're not dead, you can consume them anyway if(ishuman(living_target) && (living_target.stat != DEAD || !consumed_mobs[living_target.tag])) //if they're not dead, you can consume them anyway
consumed_mobs[living_target.tag] = TRUE consumed_mobs[living_target.tag] = TRUE
fed++ fed++
lay_eggs_enriched.UpdateButtonIcon(TRUE) lay_eggs_enriched.UpdateButtons(TRUE)
visible_message(span_danger("[src] sticks a proboscis into [living_target] and sucks a viscous substance out."),span_notice("You suck the nutriment out of [living_target], feeding you enough to lay a cluster of eggs.")) visible_message(span_danger("[src] sticks a proboscis into [living_target] and sucks a viscous substance out."),span_notice("You suck the nutriment out of [living_target], feeding you enough to lay a cluster of eggs."))
living_target.death() //you just ate them, they're dead. living_target.death() //you just ate them, they're dead.
else else
@@ -403,7 +403,7 @@
/obj/effect/proc_holder/wrap/update_icon() /obj/effect/proc_holder/wrap/update_icon()
action.button_icon_state = "wrap_[active]" action.button_icon_state = "wrap_[active]"
action.UpdateButtonIcon() action.UpdateButtons()
return ..() return ..()
/obj/effect/proc_holder/wrap/Click() /obj/effect/proc_holder/wrap/Click()
@@ -486,7 +486,7 @@
new_eggs.faction = spider.faction new_eggs.faction = spider.faction
if(enriched) if(enriched)
spider.fed-- spider.fed--
UpdateButtonIcon(TRUE) UpdateButtons(TRUE)
spider.is_busy = FALSE spider.is_busy = FALSE
spider.stop_automated_movement = FALSE spider.stop_automated_movement = FALSE

View File

@@ -77,24 +77,32 @@ 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 ///The internal attack ID for the elite's OpenFire() proc to use
var/chosen_attack_num = 0 var/chosen_attack_num = 0
/datum/action/innate/elite_attack/New() /datum/action/innate/elite_attack/CreateButton()
..() var/atom/movable/screen/movable/action_button/button = ..()
button.maptext = "" button.maptext = ""
button.maptext_x = 8 button.maptext_x = 8
button.maptext_y = 0 button.maptext_y = 0
button.maptext_width = 24 button.maptext_width = 24
button.maptext_height = 12 button.maptext_height = 12
return button
/datum/action/innate/elite_attack/process() /datum/action/innate/elite_attack/process()
if(owner == null) if(owner == null)
STOP_PROCESSING(SSfastprocess, src) STOP_PROCESSING(SSfastprocess, src)
qdel(src) qdel(src)
return return
UpdateButtons()
/datum/action/innate/elite_attack/UpdateButton(atom/movable/screen/movable/action_button/button, status_only = FALSE, force = FALSE)
. = ..()
if(!.)
return
if(status_only)
return
var/mob/living/simple_animal/hostile/asteroid/elite/elite_owner = owner var/mob/living/simple_animal/hostile/asteroid/elite/elite_owner = owner
var/timeleft = max(elite_owner.ranged_cooldown - world.time, 0) var/timeleft = max(elite_owner.ranged_cooldown - world.time, 0)
if(timeleft == 0) if(timeleft == 0)
button.maptext = "" button.maptext = ""
UpdateButtonIcon()
else else
button.maptext = "<b class='maptext'>[round(timeleft/10, 0.1)]</b>" button.maptext = "<b class='maptext'>[round(timeleft/10, 0.1)]</b>"

View File

@@ -72,7 +72,7 @@
button_icon_state = "activate-ready" button_icon_state = "activate-ready"
if(!ai_action) if(!ai_action)
background_icon_state = "bg_tech" background_icon_state = "bg_tech"
UpdateButtonIcon() UpdateButtons()
addtimer(CALLBACK(src, .proc/reset_ready), 3 SECONDS) addtimer(CALLBACK(src, .proc/reset_ready), 3 SECONDS)
return return
var/obj/item/mod/control/mod = target var/obj/item/mod/control/mod = target
@@ -85,7 +85,7 @@
button_icon_state = initial(button_icon_state) button_icon_state = initial(button_icon_state)
if(!ai_action) if(!ai_action)
background_icon_state = initial(background_icon_state) background_icon_state = initial(background_icon_state)
UpdateButtonIcon() UpdateButtons()
/datum/action/item_action/mod/activate/ai /datum/action/item_action/mod/activate/ai
ai_action = TRUE ai_action = TRUE
@@ -180,14 +180,14 @@
/datum/action/item_action/mod/pinned_module/proc/on_module_activate(datum/source) /datum/action/item_action/mod/pinned_module/proc/on_module_activate(datum/source)
SIGNAL_HANDLER SIGNAL_HANDLER
UpdateButtonIcon() UpdateButtons()
/datum/action/item_action/mod/pinned_module/proc/on_module_deactivate(datum/source) /datum/action/item_action/mod/pinned_module/proc/on_module_deactivate(datum/source)
SIGNAL_HANDLER SIGNAL_HANDLER
UpdateButtonIcon() UpdateButtons()
/datum/action/item_action/mod/pinned_module/proc/on_module_use(datum/source) /datum/action/item_action/mod/pinned_module/proc/on_module_use(datum/source)
SIGNAL_HANDLER SIGNAL_HANDLER
UpdateButtonIcon() UpdateButtons()

View File

@@ -460,7 +460,7 @@
for(var/obj/item/item in buckled_mob.held_items) for(var/obj/item/item in buckled_mob.held_items)
if(istype(item, /obj/item/turret_control)) if(istype(item, /obj/item/turret_control))
qdel(item) qdel(item)
UpdateButtonIcon() UpdateButtons()
return return
playsound(proto_emitter,'sound/mecha/mechmove01.ogg', 50, TRUE) playsound(proto_emitter,'sound/mecha/mechmove01.ogg', 50, TRUE)
name = "Switch to Automatic Firing" name = "Switch to Automatic Firing"
@@ -477,7 +477,7 @@
else //Entries in the list should only ever be items or null, so if it's not an item, we can assume it's an empty hand else //Entries in the list should only ever be items or null, so if it's not an item, we can assume it's an empty hand
var/obj/item/turret_control/turret_control = new /obj/item/turret_control() var/obj/item/turret_control/turret_control = new /obj/item/turret_control()
buckled_mob.put_in_hands(turret_control) buckled_mob.put_in_hands(turret_control)
UpdateButtonIcon() UpdateButtons()
/obj/item/turret_control /obj/item/turret_control

View File

@@ -196,7 +196,9 @@
else else
P.color = rgb(0, 255, 0) P.color = rgb(0, 255, 0)
var/turf/curloc = get_turf(src) var/turf/curloc = get_turf(src)
var/turf/targloc = get_turf(current_user.client.mouseObject)
var/atom/target_atom = current_user.client.mouse_object_ref?.resolve()
var/turf/targloc = get_turf(target_atom)
if(!istype(targloc)) if(!istype(targloc))
if(!istype(curloc)) if(!istype(curloc))
return return
@@ -293,7 +295,9 @@
process_aim() process_aim()
if(aiming_time_left <= aiming_time_fire_threshold && check_user()) if(aiming_time_left <= aiming_time_fire_threshold && check_user())
sync_ammo() sync_ammo()
afterattack(M.client.mouseObject, M, FALSE, M.client.mouseParams, passthrough = TRUE) var/atom/target = M.client.mouse_object_ref?.resolve()
if(target)
afterattack(target, M, FALSE, M.client.mouseParams, passthrough = TRUE)
stop_aiming() stop_aiming()
QDEL_LIST(current_tracers) QDEL_LIST(current_tracers)
return ..() return ..()

View File

@@ -949,12 +949,10 @@
var/ty = (text2num(screen_loc_Y[1]) - 1) * world.icon_size + text2num(screen_loc_Y[2]) var/ty = (text2num(screen_loc_Y[1]) - 1) * world.icon_size + text2num(screen_loc_Y[2])
//Calculate the "resolution" of screen based on client's view and world's icon size. This will work if the user can view more tiles than average. //Calculate the "resolution" of screen based on client's view and world's icon size. This will work if the user can view more tiles than average.
var/list/screenview = getviewsize(user.client.view) var/list/screenview = view_to_pixels(user.client.view)
var/screenviewX = screenview[1] * world.icon_size
var/screenviewY = screenview[2] * world.icon_size
var/ox = round(screenviewX/2) - user.client.pixel_x //"origin" x var/ox = round(screenview[1] / 2) - user.client.pixel_x //"origin" x
var/oy = round(screenviewY/2) - user.client.pixel_y //"origin" y var/oy = round(screenview[2] / 2) - user.client.pixel_y //"origin" y
angle = ATAN2(tx - oy, ty - ox) angle = ATAN2(tx - oy, ty - ox)
return list(angle, p_x, p_y) return list(angle, p_x, p_y)

View File

@@ -231,7 +231,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
if("holdervar") if("holdervar")
adjust_var(user, holder_var_type, holder_var_amount) adjust_var(user, holder_var_type, holder_var_amount)
if(action) if(action)
action.UpdateButtonIcon() action.UpdateButtons()
return TRUE return TRUE
/obj/effect/proc_holder/spell/proc/charge_check(mob/user, silent = FALSE) /obj/effect/proc_holder/spell/proc/charge_check(mob/user, silent = FALSE)
@@ -304,7 +304,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
if(recharging && charge_type == "recharge" && (charge_counter < charge_max)) if(recharging && charge_type == "recharge" && (charge_counter < charge_max))
charge_counter += delta_time * 10 charge_counter += delta_time * 10
if(charge_counter >= charge_max) if(charge_counter >= charge_max)
action.UpdateButtonIcon() action.UpdateButtons()
charge_counter = charge_max charge_counter = charge_max
recharging = FALSE recharging = FALSE
@@ -321,7 +321,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
cast(targets,user=user) cast(targets,user=user)
after_cast(targets) after_cast(targets)
if(action) if(action)
action.UpdateButtonIcon() action.UpdateButtons()
/obj/effect/proc_holder/spell/proc/before_cast(list/targets) /obj/effect/proc_holder/spell/proc/before_cast(list/targets)
if(overlay) if(overlay)
@@ -382,7 +382,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
if("holdervar") if("holdervar")
adjust_var(user, holder_var_type, -holder_var_amount) adjust_var(user, holder_var_type, -holder_var_amount)
if(action) 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 /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
if (!istype(target)) if (!istype(target))
@@ -507,8 +507,8 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
perform(targets,user=user) perform(targets,user=user)
/obj/effect/proc_holder/spell/proc/updateButtonIcon(status_only, force) /obj/effect/proc_holder/spell/proc/updateButtons(status_only, force)
action.UpdateButtonIcon(status_only, force) action.UpdateButtons(status_only, force)
/obj/effect/proc_holder/spell/proc/can_be_cast_by(mob/caster) /obj/effect/proc_holder/spell/proc/can_be_cast_by(mob/caster)
if((human_req || clothes_req) && !ishuman(caster)) if((human_req || clothes_req) && !ishuman(caster))

View File

@@ -46,7 +46,7 @@
. = ..() . = ..()
action.button_icon_state = "[base_icon_state][active]" action.button_icon_state = "[base_icon_state][active]"
action.UpdateButtonIcon() action.UpdateButtons()
/obj/effect/proc_holder/spell/aimed/InterceptClickOn(mob/living/caller, params, atom/target) /obj/effect/proc_holder/spell/aimed/InterceptClickOn(mob/living/caller, params, atom/target)
if(..()) if(..())

View File

@@ -62,7 +62,7 @@
. = ..() . = ..()
action.button_icon_state = "[action_icon_state][active ? 1 : null]" action.button_icon_state = "[action_icon_state][active ? 1 : null]"
action.UpdateButtonIcon() action.UpdateButtons()
/obj/effect/proc_holder/spell/pointed/InterceptClickOn(mob/living/caller, params, atom/target) /obj/effect/proc_holder/spell/pointed/InterceptClickOn(mob/living/caller, params, atom/target)
if(..()) if(..())

View File

@@ -25,7 +25,7 @@
//Start recharging. //Start recharging.
attached_hand = null attached_hand = null
recharging = TRUE recharging = TRUE
action.UpdateButtonIcon() action.UpdateButtons()
/obj/effect/proc_holder/spell/targeted/touch/cast(list/targets,mob/user = usr) /obj/effect/proc_holder/spell/targeted/touch/cast(list/targets,mob/user = usr)
if(!QDELETED(attached_hand)) if(!QDELETED(attached_hand))

View File

@@ -23,7 +23,8 @@
user.transferItemToLoc(tool, target, TRUE) user.transferItemToLoc(tool, target, TRUE)
var/datum/action/item_action/hands_free/activate_pill/pill_action = new(tool) var/datum/action/item_action/hands_free/activate_pill/pill_action = new(tool)
pill_action.button.name = "Activate [tool.name]" pill_action.name = "Activate [tool.name]"
pill_action.UpdateButtons()
pill_action.target = tool pill_action.target = tool
pill_action.Grant(target) //The pill never actually goes in an inventory slot, so the owner doesn't inherit actions from it pill_action.Grant(target) //The pill never actually goes in an inventory slot, so the owner doesn't inherit actions from it

View File

@@ -87,13 +87,13 @@ Notes:
/datum/tooltip/proc/hide() /datum/tooltip/proc/hide()
queueHide = showing ? TRUE : FALSE
if (queueHide) if (queueHide)
addtimer(CALLBACK(src, .proc/do_hide), 1) addtimer(CALLBACK(src, .proc/do_hide), 1)
else else
do_hide() do_hide()
queueHide = showing ? TRUE : FALSE
return TRUE return TRUE
/datum/tooltip/proc/do_hide() /datum/tooltip/proc/do_hide()

View File

@@ -130,21 +130,29 @@
//alert(realIconSize + ' | ' +tooltip.tileSize + ' | ' + resizeRatio); //DEBUG //alert(realIconSize + ' | ' +tooltip.tileSize + ' | ' + resizeRatio); //DEBUG
//Parse out the tile and cursor locations from params (e.g. "icon-x=32;icon-y=29;screen-loc=3:10,15:29") const parameters = new Object();
//Parse out the contents of params (e.g. "icon-x=32;icon-y=29;screen-loc=3:10,15:29")
//It is worth noting that params is not always ordered in the same way. We therefore need to write the code
//To load their values in independantly of their order
var paramsA = tooltip.params.cursor.split(';'); var paramsA = tooltip.params.cursor.split(';');
if (paramsA.length < 3) {return false;} //Sometimes screen-loc is never sent ahaha fuck you byond for (var i = 0; i < paramsA.length; i++) {
var entry = paramsA[i];
var nameAndValue = entry.split("=");
parameters[nameAndValue[0]] = nameAndValue[1];
}
//Sometimes screen-loc is never sent ahaha fuck you byond
if (!parameters["icon-x"] || !parameters["icon-y"] || !parameters["screen-loc"]) {
return false;
}
//icon-x //icon-x
var iconX = paramsA[0]; var iconX = parseInt(parameters["icon-x"]);
iconX = iconX.split('=');
iconX = parseInt(iconX[1]);
//icon-y //icon-y
var iconY = paramsA[1]; var iconY = parseInt(parameters["icon-y"]);
iconY = iconY.split('=');
iconY = parseInt(iconY[1]);
//screen-loc //screen-loc
var screenLoc = paramsA[2]; var screenLoc = parameters["screen-loc"];
screenLoc = screenLoc.split('='); screenLoc = screenLoc.split(',');
screenLoc = screenLoc[1].split(',');
if (screenLoc.length < 2) {return false;} if (screenLoc.length < 2) {return false;}
var left = screenLoc[0]; var left = screenLoc[0];
var top = screenLoc[1]; var top = screenLoc[1];

View File

@@ -212,7 +212,7 @@ own integrity back to max. Shield is automatically dropped if we run out of powe
for(var/occupant in chassis.occupants) for(var/occupant in chassis.occupants)
var/datum/action/button = chassis.occupant_actions[occupant][/datum/action/vehicle/sealed/mecha/mech_defense_mode] var/datum/action/button = chassis.occupant_actions[occupant][/datum/action/vehicle/sealed/mecha/mech_defense_mode]
button.button_icon_state = "mech_defense_mode_[chassis.defense_mode ? "on" : "off"]" button.button_icon_state = "mech_defense_mode_[chassis.defense_mode ? "on" : "off"]"
button.UpdateButtonIcon() button.UpdateButtons()
set_light_on(chassis.defense_mode) set_light_on(chassis.defense_mode)

View File

@@ -44,7 +44,7 @@
chassis.movedelay = initial(chassis.movedelay) chassis.movedelay = initial(chassis.movedelay)
chassis.step_energy_drain = chassis.normal_step_energy_drain chassis.step_energy_drain = chassis.normal_step_energy_drain
chassis.balloon_alert(owner, "you disable the overload") chassis.balloon_alert(owner, "you disable the overload")
UpdateButtonIcon() UpdateButtons()
/obj/vehicle/sealed/mecha/combat/gygax/dark /obj/vehicle/sealed/mecha/combat/gygax/dark
desc = "A lightweight exosuit, painted in a dark scheme. This model appears to have some modifications." desc = "A lightweight exosuit, painted in a dark scheme. This model appears to have some modifications."

View File

@@ -69,7 +69,7 @@
SEND_SOUND(owner, sound('sound/mecha/imag_enh.ogg', volume=50)) SEND_SOUND(owner, sound('sound/mecha/imag_enh.ogg', volume=50))
else else
owner.client.view_size.resetToDefault() owner.client.view_size.resetToDefault()
UpdateButtonIcon() UpdateButtons()
/obj/vehicle/sealed/mecha/combat/marauder/seraph /obj/vehicle/sealed/mecha/combat/marauder/seraph
desc = "Heavy-duty, command-type exosuit. This is a custom model, utilized only by high-ranking military personnel." desc = "Heavy-duty, command-type exosuit. This is a custom model, utilized only by high-ranking military personnel."

View File

@@ -44,7 +44,7 @@
chassis.damtype = new_damtype chassis.damtype = new_damtype
button_icon_state = "mech_damtype_[new_damtype]" button_icon_state = "mech_damtype_[new_damtype]"
playsound(chassis, 'sound/mecha/mechmove01.ogg', 50, TRUE) playsound(chassis, 'sound/mecha/mechmove01.ogg', 50, TRUE)
UpdateButtonIcon() UpdateButtons()
/datum/action/vehicle/sealed/mecha/mech_toggle_phasing /datum/action/vehicle/sealed/mecha/mech_toggle_phasing
name = "Toggle Phasing" name = "Toggle Phasing"
@@ -56,4 +56,4 @@
chassis.phasing = chassis.phasing ? "" : "phasing" chassis.phasing = chassis.phasing ? "" : "phasing"
button_icon_state = "mech_phasing_[chassis.phasing ? "on" : "off"]" button_icon_state = "mech_phasing_[chassis.phasing ? "on" : "off"]"
chassis.balloon_alert(owner, "[chassis.phasing ? "enabled" : "disabled"] phasing") chassis.balloon_alert(owner, "[chassis.phasing ? "enabled" : "disabled"] phasing")
UpdateButtonIcon() UpdateButtons()

View File

@@ -117,8 +117,8 @@
return return
S_TIMER_COOLDOWN_START(chassis, COOLDOWN_MECHA_SKYFALL, skyfall_cooldown_time) S_TIMER_COOLDOWN_START(chassis, COOLDOWN_MECHA_SKYFALL, skyfall_cooldown_time)
button_icon_state = "mech_savannah_cooldown" button_icon_state = "mech_savannah_cooldown"
UpdateButtonIcon() UpdateButtons()
addtimer(CALLBACK(src, /datum/action/vehicle/sealed/mecha/skyfall.proc/reset_button_icon), skyfall_cooldown_time) addtimer(CALLBACK(src, .proc/reset_button_icon), skyfall_cooldown_time)
for(var/mob/living/shaken in range(7, chassis)) for(var/mob/living/shaken in range(7, chassis))
shake_camera(shaken, 3, 3) shake_camera(shaken, 3, 3)
@@ -219,7 +219,7 @@
*/ */
/datum/action/vehicle/sealed/mecha/skyfall/proc/reset_button_icon() /datum/action/vehicle/sealed/mecha/skyfall/proc/reset_button_icon()
button_icon_state = "mech_savannah" button_icon_state = "mech_savannah"
UpdateButtonIcon() UpdateButtons()
/datum/action/vehicle/sealed/mecha/ivanov_strike /datum/action/vehicle/sealed/mecha/ivanov_strike
name = "Ivanov Strike" name = "Ivanov Strike"
@@ -254,7 +254,7 @@
*/ */
/datum/action/vehicle/sealed/mecha/ivanov_strike/proc/reset_button_icon() /datum/action/vehicle/sealed/mecha/ivanov_strike/proc/reset_button_icon()
button_icon_state = "mech_ivanov" button_icon_state = "mech_ivanov"
UpdateButtonIcon() UpdateButtons()
/** /**
* ## start_missile_targeting * ## start_missile_targeting
@@ -322,7 +322,7 @@
"explosionSize" = list(0,0,1,2) "explosionSize" = list(0,0,1,2)
)) ))
button_icon_state = "mech_ivanov_cooldown" button_icon_state = "mech_ivanov_cooldown"
UpdateButtonIcon() UpdateButtons()
addtimer(CALLBACK(src, /datum/action/vehicle/sealed/mecha/ivanov_strike.proc/reset_button_icon), strike_cooldown_time) addtimer(CALLBACK(src, /datum/action/vehicle/sealed/mecha/ivanov_strike.proc/reset_button_icon), strike_cooldown_time)
//misc effects //misc effects

View File

@@ -38,7 +38,7 @@
button_icon_state = "mech_internals_[chassis.use_internal_tank ? "on" : "off"]" button_icon_state = "mech_internals_[chassis.use_internal_tank ? "on" : "off"]"
chassis.balloon_alert(owner, "taking air from [chassis.use_internal_tank ? "internal airtank" : "environment"]") chassis.balloon_alert(owner, "taking air from [chassis.use_internal_tank ? "internal airtank" : "environment"]")
chassis.log_message("Now taking air from [chassis.use_internal_tank?"internal airtank":"environment"].", LOG_MECHA) chassis.log_message("Now taking air from [chassis.use_internal_tank?"internal airtank":"environment"].", LOG_MECHA)
UpdateButtonIcon() UpdateButtons()
/datum/action/vehicle/sealed/mecha/mech_toggle_lights /datum/action/vehicle/sealed/mecha/mech_toggle_lights
name = "Toggle Lights" name = "Toggle Lights"
@@ -60,7 +60,7 @@
chassis.balloon_alert(owner, "toggled lights [chassis.mecha_flags & LIGHTS_ON ? "on":"off"]") chassis.balloon_alert(owner, "toggled lights [chassis.mecha_flags & LIGHTS_ON ? "on":"off"]")
playsound(chassis,'sound/machines/clockcult/brass_skewer.ogg', 40, TRUE) playsound(chassis,'sound/machines/clockcult/brass_skewer.ogg', 40, TRUE)
chassis.log_message("Toggled lights [(chassis.mecha_flags & LIGHTS_ON)?"on":"off"].", LOG_MECHA) chassis.log_message("Toggled lights [(chassis.mecha_flags & LIGHTS_ON)?"on":"off"].", LOG_MECHA)
UpdateButtonIcon() UpdateButtons()
/datum/action/vehicle/sealed/mecha/mech_view_stats /datum/action/vehicle/sealed/mecha/mech_view_stats
name = "View Stats" name = "View Stats"
@@ -104,7 +104,7 @@
for(var/occupant in occupants) for(var/occupant in occupants)
var/datum/action/action = LAZYACCESSASSOC(occupant_actions, occupant, /datum/action/vehicle/sealed/mecha/strafe) var/datum/action/action = LAZYACCESSASSOC(occupant_actions, occupant, /datum/action/vehicle/sealed/mecha/strafe)
action?.UpdateButtonIcon() action?.UpdateButtons()
///swap seats, for two person mecha ///swap seats, for two person mecha
/datum/action/vehicle/sealed/mecha/swap_seat /datum/action/vehicle/sealed/mecha/swap_seat

View File

@@ -86,10 +86,10 @@
return return
var/mob/living/living_owner = owner var/mob/living/living_owner = owner
button_icon_state = "mech_search_ruins_cooldown" button_icon_state = "mech_search_ruins_cooldown"
UpdateButtonIcon() UpdateButtons()
COOLDOWN_START(src, search_cooldown, SEARCH_COOLDOWN) COOLDOWN_START(src, search_cooldown, SEARCH_COOLDOWN)
addtimer(VARSET_CALLBACK(src, button_icon_state, "mech_search_ruins"), SEARCH_COOLDOWN) addtimer(VARSET_CALLBACK(src, button_icon_state, "mech_search_ruins"), SEARCH_COOLDOWN)
addtimer(CALLBACK(src, .proc/UpdateButtonIcon), SEARCH_COOLDOWN) addtimer(CALLBACK(src, .proc/UpdateButtons), SEARCH_COOLDOWN)
var/obj/pinpointed_ruin var/obj/pinpointed_ruin
for(var/obj/effect/landmark/ruin/ruin_landmark as anything in GLOB.ruin_landmarks) for(var/obj/effect/landmark/ruin/ruin_landmark as anything in GLOB.ruin_landmarks)
if(ruin_landmark.z != chassis.z) if(ruin_landmark.z != chassis.z)

View File

@@ -226,12 +226,16 @@
src.circuit_component = circuit_component src.circuit_component = circuit_component
button.maptext_x = 2 UpdateButtons()
button.maptext_y = 0
update_maptext()
START_PROCESSING(SSobj, src) START_PROCESSING(SSobj, src)
/datum/action/innate/bci_charge_action/CreateButton()
var/atom/movable/screen/movable/action_button/button = ..()
button.maptext_x = 2
button.maptext_y = 0
return button
/datum/action/innate/bci_charge_action/Destroy() /datum/action/innate/bci_charge_action/Destroy()
circuit_component.charge_action = null circuit_component.charge_action = null
circuit_component = null circuit_component = null
@@ -250,9 +254,14 @@
to_chat(owner, span_info("You can recharge it by using a cyborg recharging station.")) to_chat(owner, span_info("You can recharge it by using a cyborg recharging station."))
/datum/action/innate/bci_charge_action/process(delta_time) /datum/action/innate/bci_charge_action/process(delta_time)
update_maptext() UpdateButtons()
/datum/action/innate/bci_charge_action/proc/update_maptext() /datum/action/innate/bci_charge_action/UpdateButton(atom/movable/screen/movable/action_button/button, status_only = FALSE, force = FALSE)
. = ..()
if(!.)
return
if(status_only)
return
var/obj/item/stock_parts/cell/cell = circuit_component.parent.cell var/obj/item/stock_parts/cell/cell = circuit_component.parent.cell
button.maptext = cell ? MAPTEXT("[cell.percent()]%") : "" button.maptext = cell ? MAPTEXT("[cell.percent()]%") : ""

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 B

BIN
icons/hud/64x16_actions.dmi Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -135,7 +135,7 @@
if(fire_select_modes.len > 1) if(fire_select_modes.len > 1)
firemode_action = new(src) firemode_action = new(src)
firemode_action.button_icon_state = "fireselect_[fire_select]" firemode_action.button_icon_state = "fireselect_[fire_select]"
firemode_action.UpdateButtonIcon() firemode_action.UpdateButtons()
/obj/item/gun/ComponentInitialize() /obj/item/gun/ComponentInitialize()
. = ..() . = ..()
@@ -244,7 +244,7 @@
playsound(user, 'sound/weapons/empty.ogg', 100, TRUE) playsound(user, 'sound/weapons/empty.ogg', 100, TRUE)
update_appearance() update_appearance()
firemode_action.button_icon_state = "fireselect_[fire_select]" firemode_action.button_icon_state = "fireselect_[fire_select]"
firemode_action.UpdateButtonIcon() firemode_action.UpdateButtons()
SEND_SIGNAL(src, COMSIG_UPDATE_AMMO_HUD) SEND_SIGNAL(src, COMSIG_UPDATE_AMMO_HUD)
return TRUE return TRUE
@@ -397,7 +397,7 @@
else else
safety = !safety safety = !safety
tsafety.button_icon_state = "safety_[safety ? "on" : "off"]" tsafety.button_icon_state = "safety_[safety ? "on" : "off"]"
tsafety.UpdateButtonIcon() tsafety.UpdateButtons()
playsound(src, 'sound/weapons/empty.ogg', 100, TRUE) playsound(src, 'sound/weapons/empty.ogg', 100, TRUE)
user.visible_message(span_notice("[user] toggles [src]'s safety [safety ? "<font color='#00ff15'>ON</font>" : "<font color='#ff0000'>OFF</font>"]."), user.visible_message(span_notice("[user] toggles [src]'s safety [safety ? "<font color='#00ff15'>ON</font>" : "<font color='#ff0000'>OFF</font>"]."),
span_notice("You toggle [src]'s safety [safety ? "<font color='#00ff15'>ON</font>" : "<font color='#ff0000'>OFF</font>"].")) span_notice("You toggle [src]'s safety [safety ? "<font color='#00ff15'>ON</font>" : "<font color='#ff0000'>OFF</font>"]."))

View File

@@ -231,7 +231,7 @@
playsound(my_suit, 'modular_skyrat/master_files/sound/blackmesa/hev/blip.ogg', 50) playsound(my_suit, 'modular_skyrat/master_files/sound/blackmesa/hev/blip.ogg', 50)
UpdateButtonIcon() UpdateButtons()
/datum/action/item_action/hev_toggle/Trigger(trigger_flags) /datum/action/item_action/hev_toggle/Trigger(trigger_flags)
var/obj/item/clothing/suit/space/hev_suit/my_suit = target var/obj/item/clothing/suit/space/hev_suit/my_suit = target
@@ -249,7 +249,7 @@
playsound(my_suit, 'modular_skyrat/master_files/sound/blackmesa/hev/blip.ogg', 50) playsound(my_suit, 'modular_skyrat/master_files/sound/blackmesa/hev/blip.ogg', 50)
UpdateButtonIcon() UpdateButtons()
/obj/item/clothing/suit/space/hev_suit/proc/send_message(message, color = HEV_COLOR_ORANGE) /obj/item/clothing/suit/space/hev_suit/proc/send_message(message, color = HEV_COLOR_ORANGE)
if(send_notifications != HEV_NOTIFICATION_TEXT_AND_VOICE && send_notifications != HEV_NOTIFICATION_TEXT) if(send_notifications != HEV_NOTIFICATION_TEXT_AND_VOICE && send_notifications != HEV_NOTIFICATION_TEXT)

View File

@@ -282,6 +282,7 @@
#include "code\__DEFINES\~skyrat_defines\flavor_defines.dm" #include "code\__DEFINES\~skyrat_defines\flavor_defines.dm"
#include "code\__DEFINES\~skyrat_defines\game_options.dm" #include "code\__DEFINES\~skyrat_defines\game_options.dm"
#include "code\__DEFINES\~skyrat_defines\gun.dm" #include "code\__DEFINES\~skyrat_defines\gun.dm"
#include "code\__DEFINES\~skyrat_defines\hud.dm"
#include "code\__DEFINES\~skyrat_defines\integrated_electronics.dm" #include "code\__DEFINES\~skyrat_defines\integrated_electronics.dm"
#include "code\__DEFINES\~skyrat_defines\interactions.dm" #include "code\__DEFINES\~skyrat_defines\interactions.dm"
#include "code\__DEFINES\~skyrat_defines\inventory.dm" #include "code\__DEFINES\~skyrat_defines\inventory.dm"
@@ -367,6 +368,7 @@
#include "code\__HELPERS\ref.dm" #include "code\__HELPERS\ref.dm"
#include "code\__HELPERS\roundend.dm" #include "code\__HELPERS\roundend.dm"
#include "code\__HELPERS\sanitize_values.dm" #include "code\__HELPERS\sanitize_values.dm"
#include "code\__HELPERS\screen_objs.dm"
#include "code\__HELPERS\shell.dm" #include "code\__HELPERS\shell.dm"
#include "code\__HELPERS\spatial_info.dm" #include "code\__HELPERS\spatial_info.dm"
#include "code\__HELPERS\spawns.dm" #include "code\__HELPERS\spawns.dm"
@@ -435,7 +437,6 @@
#include "code\_onclick\overmind.dm" #include "code\_onclick\overmind.dm"
#include "code\_onclick\pai.dm" #include "code\_onclick\pai.dm"
#include "code\_onclick\telekinesis.dm" #include "code\_onclick\telekinesis.dm"
#include "code\_onclick\hud\_defines.dm"
#include "code\_onclick\hud\action_button.dm" #include "code\_onclick\hud\action_button.dm"
#include "code\_onclick\hud\ai.dm" #include "code\_onclick\hud\ai.dm"
#include "code\_onclick\hud\alert.dm" #include "code\_onclick\hud\alert.dm"
@@ -2490,7 +2491,6 @@
#include "code\modules\client\preferences\auto_fit_viewport.dm" #include "code\modules\client\preferences\auto_fit_viewport.dm"
#include "code\modules\client\preferences\body_type.dm" #include "code\modules\client\preferences\body_type.dm"
#include "code\modules\client\preferences\broadcast_login_logout.dm" #include "code\modules\client\preferences\broadcast_login_logout.dm"
#include "code\modules\client\preferences\buttons_locked.dm"
#include "code\modules\client\preferences\clothing.dm" #include "code\modules\client\preferences\clothing.dm"
#include "code\modules\client\preferences\darkened_flash.dm" #include "code\modules\client\preferences\darkened_flash.dm"
#include "code\modules\client\preferences\fov_darkness.dm" #include "code\modules\client\preferences\fov_darkness.dm"