|
3 | 3 | var/desc = null |
4 | 4 | var/obj/target = null |
5 | 5 | var/check_flags = 0 |
6 | | - /// Icon that our button screen object overlay and background |
7 | | - var/button_overlay_icon = 'icons/mob/actions/actions.dmi' |
8 | | - /// Icon state of screen object overlay |
9 | | - var/button_overlay_icon_state = ACTION_BUTTON_DEFAULT_OVERLAY |
10 | | - /// Icon that our button screen object background will have |
11 | | - var/button_background_icon = 'icons/mob/actions/actions.dmi' |
| 6 | + |
| 7 | + /// This is the icon state state for the BACKGROUND underlay icon of the button |
| 8 | + /// (If set to ACTION_BUTTON_DEFAULT_BACKGROUND, uses the hud's default background) |
| 9 | + var/background_icon = 'icons/mob/actions/actions.dmi' |
12 | 10 | /// Icon state of screen object background |
13 | | - var/button_background_icon_state = ACTION_BUTTON_DEFAULT_BACKGROUND |
| 11 | + var/background_icon_state = ACTION_BUTTON_DEFAULT_BACKGROUND |
| 12 | + |
| 13 | + /// This is the file for the icon that appears on the button |
| 14 | + var/button_icon = 'icons/mob/actions/actions.dmi' |
| 15 | + /// This is the icon state for the icon that appears on the button |
| 16 | + var/button_icon_state = ACTION_BUTTON_DEFAULT_OVERLAY |
| 17 | + |
| 18 | + /// This is the file for any FOREGROUND overlay icons on the button (such as borders) |
| 19 | + var/overlay_icon = 'icons/mob/actions/actions.dmi' |
| 20 | + /// This is the icon state for any FOREGROUND overlay icons on the button (such as borders) |
| 21 | + var/overlay_icon_state |
14 | 22 | var/buttontooltipstyle = "" |
15 | 23 | var/transparent_when_unavailable = TRUE |
16 | 24 | var/mob/owner |
|
20 | 28 | var/list/viewers = list() |
21 | 29 | /// Whether or not this will be shown to observers |
22 | 30 | var/show_to_observers = TRUE |
| 31 | + /// Toggles whether this action is usable or not |
| 32 | + var/action_disabled = FALSE |
| 33 | + /// The appearance used as an overlay for when the action is unavailable |
| 34 | + var/mutable_appearance/unavailable_effect |
23 | 35 |
|
| 36 | +/datum/action/New(target) |
| 37 | + link_to(target) |
24 | 38 |
|
25 | | -/datum/action/New(Target) |
26 | | - target = Target |
| 39 | +/// Links the passed target to our action, registering any relevant signals |
| 40 | +/datum/action/proc/link_to(target_) |
| 41 | + target = target_ |
| 42 | + RegisterSignal(target, COMSIG_PARENT_QDELETING, PROC_REF(clear_ref), override = TRUE) |
| 43 | + |
| 44 | + if(isatom(target)) |
| 45 | + RegisterSignal(target, COMSIG_ATOM_UPDATED_ICON, PROC_REF(on_target_icon_update)) |
27 | 46 |
|
28 | 47 | /datum/action/proc/should_draw_cooldown() |
29 | 48 | return !IsAvailable() |
|
79 | 98 | UnregisterSignal(owner, COMSIG_PARENT_QDELETING) |
80 | 99 | owner = null |
81 | 100 |
|
82 | | -/datum/action/proc/UpdateButtons(status_only, force) |
83 | | - for(var/datum/hud/hud in viewers) |
84 | | - var/atom/movable/screen/movable/button = viewers[hud] |
85 | | - UpdateButton(button, status_only, force) |
| 101 | +/// Builds / updates all buttons we have shared or given out |
| 102 | +/datum/action/proc/build_all_button_icons(update_flags = ALL, force) |
| 103 | + for(var/datum/hud/hud as anything in viewers) |
| 104 | + build_button_icon(viewers[hud], update_flags, force) |
86 | 105 |
|
87 | 106 | /datum/action/proc/Trigger(left_click = TRUE) |
88 | 107 | if(!IsAvailable()) |
|
123 | 142 | return FALSE |
124 | 143 | return TRUE |
125 | 144 |
|
126 | | -/datum/action/proc/UpdateButton(atom/movable/screen/movable/action_button/button, status_only = FALSE, force = FALSE) |
| 145 | +/** |
| 146 | + * Builds the icon of the button. |
| 147 | + * |
| 148 | + * Concept: |
| 149 | + * - Underlay (Background icon) |
| 150 | + * - Icon (button icon) |
| 151 | + * - Maptext |
| 152 | + * - Overlay (Background border) |
| 153 | + * |
| 154 | + * button - which button we are modifying the icon of |
| 155 | + * force - whether we're forcing a full update |
| 156 | + */ |
| 157 | +/datum/action/proc/build_button_icon(atom/movable/screen/movable/action_button/button, update_flags = ALL, force = FALSE) |
127 | 158 | if(!button) |
128 | 159 | return |
129 | | - if(!status_only) |
130 | | - button.name = name |
131 | | - if(desc) |
132 | | - button.desc = "[desc] [initial(button.desc)]" |
133 | | - if(owner?.hud_used && button_background_icon_state == ACTION_BUTTON_DEFAULT_BACKGROUND) |
134 | | - var/list/settings = owner.hud_used.get_action_buttons_icons() |
135 | | - if(button.icon != settings["bg_icon"]) |
136 | | - button.icon = settings["bg_icon"] |
137 | | - if(button.icon_state != settings["bg_state"]) |
138 | | - button.icon_state = settings["bg_state"] |
139 | | - else |
140 | | - if(button.icon != button_background_icon) |
141 | | - button.icon = button_background_icon |
142 | | - if(button.icon_state != button_background_icon_state) |
143 | | - button.icon_state = button_background_icon_state |
144 | 160 |
|
| 161 | + if(update_flags & UPDATE_BUTTON_NAME) |
| 162 | + update_button_name(button, force) |
| 163 | + |
| 164 | + if(update_flags & UPDATE_BUTTON_BACKGROUND) |
| 165 | + apply_button_background(button, force) |
| 166 | + |
| 167 | + if(update_flags & UPDATE_BUTTON_ICON) |
| 168 | + apply_button_icon(button, force) |
| 169 | + |
| 170 | + if(update_flags & UPDATE_BUTTON_OVERLAY) |
145 | 171 | apply_button_overlay(button, force) |
146 | 172 |
|
| 173 | + if(update_flags & UPDATE_BUTTON_STATUS) |
| 174 | + update_button_status(button, force) |
| 175 | + |
| 176 | +/** |
| 177 | + * Updates the name and description of the button to match our action name and discription. |
| 178 | + * |
| 179 | + * button - what button are we editing? |
| 180 | + * force - whether an update is forced regardless of existing status |
| 181 | + */ |
| 182 | +/datum/action/proc/update_button_name(atom/movable/screen/movable/action_button/button, force = FALSE) |
| 183 | + button.name = name |
| 184 | + if(desc) |
| 185 | + button.desc = desc |
| 186 | + |
| 187 | +/** |
| 188 | + * Any other miscellaneous "status" updates within the action button is handled here, |
| 189 | + * such as redding out when unavailable or modifying maptext. |
| 190 | + * |
| 191 | + * button - what button are we editing? |
| 192 | + * force - whether an update is forced regardless of existing status |
| 193 | + */ |
| 194 | +/datum/action/proc/update_button_status(atom/movable/screen/movable/action_button/button, force = FALSE) |
| 195 | + button.overlays -= unavailable_effect |
| 196 | + button.maptext = "" |
147 | 197 | if(should_draw_cooldown()) |
148 | 198 | apply_unavailable_effect(button) |
149 | | - else |
150 | | - return TRUE |
151 | 199 |
|
152 | 200 | //Give our action button to the player |
153 | 201 | /datum/action/proc/GiveAction(mob/viewer) |
|
164 | 212 | return |
165 | 213 |
|
166 | 214 |
|
167 | | - var/atom/movable/screen/movable/action_button/button = CreateButton() |
| 215 | + var/atom/movable/screen/movable/action_button/button = create_button() |
168 | 216 | SetId(button, viewer) |
169 | 217 |
|
170 | 218 | button.our_hud = our_hud |
|
186 | 234 | qdel(button) |
187 | 235 |
|
188 | 236 |
|
189 | | -/datum/action/proc/CreateButton() |
| 237 | +/datum/action/proc/create_button() |
190 | 238 | var/atom/movable/screen/movable/action_button/button = new() |
191 | 239 | button.linked_action = src |
192 | | - button.name = name |
| 240 | + build_button_icon(button, ALL, force = TRUE) |
| 241 | + // TODO: Pull all of this into the build button structure somehow later |
193 | 242 | button.actiontooltipstyle = buttontooltipstyle |
194 | 243 | var/list/our_description = list() |
195 | 244 | our_description += desc |
196 | 245 | our_description += button.desc |
197 | 246 | button.desc = our_description.Join(" ") |
198 | 247 | return button |
199 | 248 |
|
200 | | - |
201 | 249 | /datum/action/proc/SetId(atom/movable/screen/movable/action_button/our_button, mob/owner) |
202 | 250 | //button id generation |
203 | 251 | var/bitfield = 0 |
|
215 | 263 | our_button.id = bitflag |
216 | 264 | return |
217 | 265 |
|
218 | | -/datum/action/proc/apply_unavailable_effect(atom/movable/screen/movable/action_button/B) |
219 | | - var/image/img = image('icons/mob/screen_white.dmi', icon_state = "template") |
220 | | - img.alpha = 200 |
221 | | - img.appearance_flags = RESET_COLOR | RESET_ALPHA |
222 | | - img.color = "#000000" |
223 | | - img.plane = FLOAT_PLANE + 1 |
224 | | - B.add_overlay(img) |
225 | | - |
226 | | - |
227 | | -/datum/action/proc/apply_button_overlay(atom/movable/screen/movable/action_button/current_button) |
228 | | - current_button.cut_overlays() |
229 | | - if(button_overlay_icon && button_overlay_icon_state) |
230 | | - var/image/img = image(button_overlay_icon, current_button, button_overlay_icon_state) |
231 | | - img.appearance_flags = RESET_COLOR | RESET_ALPHA |
232 | | - img.pixel_x = 0 |
233 | | - img.pixel_y = 0 |
234 | | - current_button.add_overlay(img) |
| 266 | +/datum/action/proc/apply_unavailable_effect(atom/movable/screen/movable/action_button/button) |
| 267 | + if(isnull(unavailable_effect)) |
| 268 | + unavailable_effect = mutable_appearance('icons/mob/screen_white.dmi', icon_state = "template") |
| 269 | + unavailable_effect.alpha = 200 |
| 270 | + unavailable_effect.appearance_flags = RESET_COLOR | RESET_ALPHA |
| 271 | + unavailable_effect.color = "#000000" |
| 272 | + unavailable_effect.plane = FLOAT_PLANE + 1 |
| 273 | + button.overlays |= unavailable_effect |
| 274 | + |
| 275 | +/** |
| 276 | + * Applies any overlays to our button |
| 277 | + * |
| 278 | + * button - what button are we editing? |
| 279 | + * force - whether an update is forced regardless of existing status |
| 280 | + */ |
| 281 | +/datum/action/proc/apply_button_overlay(atom/movable/screen/movable/action_button/button, force = FALSE) |
| 282 | + SEND_SIGNAL(src, COMSIG_ACTION_OVERLAY_APPLY, button, force) |
| 283 | + |
| 284 | + if(!overlay_icon || !overlay_icon_state || (button.active_overlay_icon_state == overlay_icon_state && !force)) |
| 285 | + return |
| 286 | + |
| 287 | + button.cut_overlay(button.button_overlay) |
| 288 | + button.button_overlay = mutable_appearance(icon = overlay_icon, icon_state = overlay_icon_state, appearance_flags = (RESET_COLOR|RESET_ALPHA)) |
| 289 | + button.add_overlay(button.button_overlay) |
| 290 | + button.active_overlay_icon_state = overlay_icon_state |
| 291 | + |
| 292 | +/// Checks if our action is actively selected. Used for selecting icons primarily. |
| 293 | +/datum/action/proc/is_action_active(atom/movable/screen/movable/action_button/button) |
| 294 | + return FALSE |
| 295 | + |
| 296 | +/** |
| 297 | + * Creates the background underlay for the button |
| 298 | + * |
| 299 | + * button - what button are we editing? |
| 300 | + * force - whether an update is forced regardless of existing status |
| 301 | + */ |
| 302 | +/datum/action/proc/apply_button_background(atom/movable/screen/movable/action_button/button, force = FALSE) |
| 303 | + if(!background_icon || !background_icon_state || (button.active_underlay_icon_state == background_icon_state && !force)) |
| 304 | + return |
| 305 | + |
| 306 | + // What icons we use for our background |
| 307 | + var/list/icon_settings = list( |
| 308 | + // The icon file |
| 309 | + "bg_icon" = background_icon, |
| 310 | + // The icon state, if is_action_active() returns FALSE |
| 311 | + "bg_state" = background_icon_state, |
| 312 | + // The icon state, if is_action_active() returns TRUE |
| 313 | + "bg_state_active" = background_icon_state, |
| 314 | + ) |
| 315 | + |
| 316 | + // If background_icon_state is ACTION_BUTTON_DEFAULT_BACKGROUND instead use our hud's action button scheme |
| 317 | + if(background_icon_state == ACTION_BUTTON_DEFAULT_BACKGROUND && owner?.hud_used) |
| 318 | + icon_settings = owner.hud_used.get_action_buttons_icons() |
| 319 | + |
| 320 | + // Determine which icon to use |
| 321 | + var/used_icon_key = is_action_active(button) ? "bg_state_active" : "bg_state" |
| 322 | + |
| 323 | + // Make the underlay |
| 324 | + button.underlays.Cut() |
| 325 | + var/image/underlay = image(icon = icon_settings["bg_icon"], icon_state = icon_settings[used_icon_key]) |
| 326 | + button.underlays += underlay |
| 327 | + button.active_underlay_icon_state = icon_settings[used_icon_key] |
| 328 | + |
| 329 | +/** |
| 330 | + * Applies our button icon and icon state to the button |
| 331 | + * |
| 332 | + * button - what button are we editing? |
| 333 | + * force - whether an update is forced regardless of existing status |
| 334 | + */ |
| 335 | +/datum/action/proc/apply_button_icon(atom/movable/screen/movable/action_button/button, force = FALSE) |
| 336 | + if(!button_icon || !button_icon_state || (button.icon_state == button_icon_state && !force)) |
| 337 | + return |
| 338 | + |
| 339 | + button.icon = button_icon |
| 340 | + button.icon_state = button_icon_state |
| 341 | + |
| 342 | +/// Updates our buttons if our target's icon was updated |
| 343 | +/datum/action/proc/on_target_icon_update(datum/source, updates, updated) |
| 344 | + SIGNAL_HANDLER // COMSIG_ATOM_UPDATED_ICON |
| 345 | + |
| 346 | + var/update_flag = NONE |
| 347 | + var/forced = FALSE |
| 348 | + if(updates & UPDATE_ICON_STATE) |
| 349 | + update_flag |= UPDATE_BUTTON_ICON |
| 350 | + forced = TRUE |
| 351 | + if(updates & UPDATE_OVERLAYS) |
| 352 | + update_flag |= UPDATE_BUTTON_OVERLAY |
| 353 | + forced = TRUE |
| 354 | + if(updates & (UPDATE_NAME|UPDATE_DESC)) |
| 355 | + update_flag |= UPDATE_BUTTON_NAME |
| 356 | + // Status is not relevant, and background is not relevant. Neither will change |
| 357 | + |
| 358 | + // Force the update if an icon state or overlay change was done |
| 359 | + build_all_button_icons(update_flag, forced) |
0 commit comments