diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index b1b359bbb74..79979534211 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -139,8 +139,7 @@ for(var/client/remove_from in hide_from) remove_from.images -= image_to_remove - -///Add an image to a list of clients and calls a proc to remove it after a duration +/// Add an image to a list of clients and calls a proc to remove it after a duration /proc/flick_overlay_global(image/image_to_show, list/show_to, duration) if(!show_to || !length(show_to) || !image_to_show) return @@ -148,7 +147,7 @@ add_to.images += image_to_show addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(remove_image_from_clients), image_to_show, show_to), duration, TIMER_CLIENT_TIME) -/// Flicks a certain overlay onto an atom, handling icon_state strings +///Flicks a certain overlay onto an atom, handling icon_state strings /atom/proc/flick_overlay(image_to_show, list/show_to, duration, layer) var/image/passed_image = \ istext(image_to_show) \ @@ -157,13 +156,37 @@ flick_overlay_global(passed_image, show_to, duration) -/// flicks an overlay to anyone who can view this atom -/atom/proc/flick_overlay_view(image_to_show, duration) - var/list/viewing = list() - for(var/mob/viewer as anything in viewers(src)) - if(viewer.client) - viewing += viewer.client - flick_overlay(image_to_show, viewing, duration) +/** + * Helper atom that copies an appearance and exists for a period +*/ +/atom/movable/flick_visual + +/// Takes the passed in MA/icon_state, mirrors it onto ourselves, and displays that in world for duration seconds +/// Returns the displayed object, you can animate it and all, but you don't own it, we'll delete it after the duration +/atom/proc/flick_overlay_view(mutable_appearance/display, duration) + if(!display) + return null + + var/mutable_appearance/passed_appearance = \ + istext(display) \ + ? mutable_appearance(icon, display, layer) \ + : display + + // If you don't give it a layer, we assume you want it to layer on top of this atom + // Because this is vis_contents, we need to set the layer manually (you can just set it as you want on return if this is a problem) + if(passed_appearance.layer == FLOAT_LAYER) + passed_appearance.layer = layer + 0.1 + // This is faster then pooling. I promise + var/atom/movable/flick_visual/visual = new() + visual.appearance = passed_appearance + // I hate /area + var/atom/movable/lies_to_children = src + lies_to_children.vis_contents += visual + QDEL_IN_CLIENT_TIME(visual, duration) + return visual + +/area/flick_overlay_view(mutable_appearance/display, duration) + return ///Get active players who are playing in the round /proc/get_active_player_count(alive_check = FALSE, afk_check = FALSE, human_check = FALSE) diff --git a/code/controllers/subsystem/wardrobe.dm b/code/controllers/subsystem/wardrobe.dm index 58f81f86ad4..ac435cc9a6d 100644 --- a/code/controllers/subsystem/wardrobe.dm +++ b/code/controllers/subsystem/wardrobe.dm @@ -310,7 +310,7 @@ SUBSYSTEM_DEF(wardrobe) initial_callbacks[/obj/item/organ] = play_with play_with = new /list(WARDROBE_CALLBACK_REMOVE) - play_with[WARDROBE_CALLBACK_REMOVE] = CALLBACK(null, TYPE_PROC_REF(/obj/item/storage/box/survival,wardrobe_removal)) + play_with[WARDROBE_CALLBACK_REMOVE] = CALLBACK(null, TYPE_PROC_REF(/obj/item/storage/box/survival, wardrobe_removal)) initial_callbacks[/obj/item/storage/box/survival] = play_with /datum/controller/subsystem/wardrobe/proc/load_outfits() diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 10b61d1051f..9379e45e5e5 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -60,7 +60,7 @@ ///overlays managed by [update_overlays][/atom/proc/update_overlays] to prevent removing overlays that weren't added by the same proc. Single items are stored on their own, not in a list. var/list/managed_overlays - /// Lazylist of all images (hopefully attached to us) to update when we change z levels + /// Lazylist of all images (or atoms, I'm sorry) (hopefully attached to us) to update when we change z levels /// You will need to manage adding/removing from this yourself, but I'll do the updating for you var/list/image/update_on_z diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 5b0f0b00e91..da14776f916 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -1166,7 +1166,7 @@ if(update_on_z) // I so much wish this could be somewhere else. alas, no. - for(var/image/update in update_on_z) + for(var/image/update as anything in update_on_z) SET_PLANE(update, PLANE_TO_TRUE(update.plane), new_turf) if(update_overlays_on_z) // This EVEN more so diff --git a/code/game/machinery/scan_gate.dm b/code/game/machinery/scan_gate.dm index 8fd41bcc9d9..49d5fab21f2 100644 --- a/code/game/machinery/scan_gate.dm +++ b/code/game/machinery/scan_gate.dm @@ -199,8 +199,8 @@ if(next_beep <= world.time) next_beep = world.time + (2 SECONDS) playsound(src, 'sound/machines/scanbuzz.ogg', 100, FALSE) - var/image/alarm_image = image(icon, src, "alarm_light", layer+1) - flick_overlay_view(alarm_image, 2 SECONDS) + var/mutable_appearance/alarm_display = mutable_appearance(icon, "alarm_light") + flick_overlay_view(alarm_display, 2 SECONDS) set_scanline("alarm", 2 SECONDS) /obj/machinery/scanner_gate/can_interact(mob/user) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index d594f3c538f..76dedcd323c 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -1348,7 +1348,7 @@ if(!istype(loc, /turf)) return source = loc - var/image/pickup_animation = image(icon = src, loc = source, layer = layer + 0.1) + var/image/pickup_animation = image(icon = src) SET_PLANE(pickup_animation, GAME_PLANE, source) pickup_animation.transform.Scale(0.75) pickup_animation.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA @@ -1369,13 +1369,13 @@ to_y += 10 pickup_animation.pixel_x += 6 * (prob(50) ? 1 : -1) //6 to the right or left, helps break up the straight upward move - flick_overlay_global(pickup_animation, GLOB.clients, 4) - var/matrix/animation_matrix = new(pickup_animation.transform) + var/atom/movable/flick_visual/pickup = source.flick_overlay_view(pickup_animation, 0.4 SECONDS) + var/matrix/animation_matrix = new(pickup.transform) animation_matrix.Turn(pick(-30, 30)) animation_matrix.Scale(0.65) - animate(pickup_animation, alpha = 175, pixel_x = to_x, pixel_y = to_y, time = 3, transform = animation_matrix, easing = CUBIC_EASING) - animate(alpha = 0, transform = matrix().Scale(0.7), time = 1) + animate(pickup, alpha = 175, pixel_x = to_x, pixel_y = to_y, time = 0.3 SECONDS, transform = animation_matrix, easing = CUBIC_EASING) + animate(alpha = 0, transform = matrix().Scale(0.7), time = 0.1 SECONDS) /obj/item/proc/do_drop_animation(atom/moving_from) if(!istype(loc, /turf)) @@ -1422,9 +1422,9 @@ /atom/movable/proc/do_item_attack_animation(atom/attacked_atom, visual_effect_icon, obj/item/used_item) var/image/attack_image if(visual_effect_icon) - attack_image = image('icons/effects/effects.dmi', attacked_atom, visual_effect_icon, attacked_atom.layer + 0.1) + attack_image = image(icon = 'icons/effects/effects.dmi', icon_state = visual_effect_icon) else if(used_item) - attack_image = image(icon = used_item, loc = attacked_atom, layer = attacked_atom.layer + 0.1) + attack_image = image(icon = used_item) attack_image.plane = attacked_atom.plane + 1 // Scale the icon. @@ -1451,12 +1451,12 @@ if(!attack_image) return - flick_overlay_global(attack_image, GLOB.clients, 10) + var/atom/movable/flick_visual/attack = attacked_atom.flick_overlay_view(attack_image, 1 SECONDS) var/matrix/copy_transform = new(transform) // And animate the attack! - animate(attack_image, alpha = 175, transform = copy_transform.Scale(0.75), pixel_x = 0, pixel_y = 0, pixel_z = 0, time = 3) - animate(time = 1) - animate(alpha = 0, time = 3, easing = CIRCULAR_EASING|EASE_OUT) + animate(attack, alpha = 175, transform = copy_transform.Scale(0.75), pixel_x = 0, pixel_y = 0, pixel_z = 0, time = 0.3 SECONDS) + animate(time = 0.1 SECONDS) + animate(alpha = 0, time = 0.3 SECONDS, easing = CIRCULAR_EASING|EASE_OUT) /// Common proc used by painting tools like spraycans and palettes that can access the entire 24 bits color space. /obj/item/proc/pick_painting_tool_color(mob/user, default_color) diff --git a/code/game/objects/items/devices/laserpointer.dm b/code/game/objects/items/devices/laserpointer.dm index 380a7c82b56..45000bf4353 100644 --- a/code/game/objects/items/devices/laserpointer.dm +++ b/code/game/objects/items/devices/laserpointer.dm @@ -165,16 +165,16 @@ //laser pointer image icon_state = "pointer_[pointer_icon_state]" - var/image/I = image('icons/obj/weapons/guns/projectiles.dmi',targloc,pointer_icon_state,10) + var/mutable_appearance/laser = mutable_appearance('icons/obj/weapons/guns/projectiles.dmi', pointer_icon_state, 10) var/list/modifiers = params2list(params) if(modifiers) if(LAZYACCESS(modifiers, ICON_X)) - I.pixel_x = (text2num(LAZYACCESS(modifiers, ICON_X)) - 16) + laser.pixel_x = (text2num(LAZYACCESS(modifiers, ICON_X)) - 16) if(LAZYACCESS(modifiers, ICON_Y)) - I.pixel_y = (text2num(LAZYACCESS(modifiers, ICON_Y)) - 16) + laser.pixel_y = (text2num(LAZYACCESS(modifiers, ICON_Y)) - 16) else - I.pixel_x = target.pixel_x + rand(-5,5) - I.pixel_y = target.pixel_y + rand(-5,5) + laser.pixel_x = target.pixel_x + rand(-5,5) + laser.pixel_y = target.pixel_y + rand(-5,5) if(outmsg) to_chat(user, outmsg) @@ -190,7 +190,7 @@ to_chat(user, span_warning("[src]'s battery is overused, it needs time to recharge!")) recharge_locked = TRUE - targloc.flick_overlay_view(I, 10) + targloc.flick_overlay_view(laser, 1 SECONDS) icon_state = "pointer" /obj/item/laser_pointer/process(seconds_per_tick) diff --git a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm index f504e89bee8..2771fe2bd76 100644 --- a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm +++ b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm @@ -81,18 +81,19 @@ /// Does the MGS ! animation /atom/proc/do_alert_animation() - var/image/alert_image = image('icons/obj/storage/closet.dmi', src, "cardboard_special", layer+1) - SET_PLANE_EXPLICIT(alert_image, ABOVE_LIGHTING_PLANE, src) - flick_overlay_view(alert_image, 0.8 SECONDS) - alert_image.alpha = 0 - animate(alert_image, pixel_z = 32, alpha = 255, time = 0.5 SECONDS, easing = ELASTIC_EASING) + var/mutable_appearance/alert = mutable_appearance('icons/obj/storage/closet.dmi', "cardboard_special") + SET_PLANE_EXPLICIT(alert, ABOVE_LIGHTING_PLANE, src) + var/atom/movable/flick_visual/exclamation = flick_overlay_view(alert, 1 SECONDS) + exclamation.alpha = 0 + animate(exclamation, pixel_z = 32, alpha = 255, time = 0.5 SECONDS, easing = ELASTIC_EASING) // We use this list to update plane values on parent z change, which is why we need the timer too // I'm sorry :( - LAZYADD(update_on_z, alert_image) - addtimer(CALLBACK(src, PROC_REF(forget_alert_image), alert_image), 0.8 SECONDS) + LAZYADD(update_on_z, exclamation) + // Intentionally less time then the flick so we don't get weird shit + addtimer(CALLBACK(src, PROC_REF(forget_alert), exclamation), 0.8 SECONDS, TIMER_CLIENT_TIME) -/atom/proc/forget_alert_image(image/alert_image) - LAZYREMOVE(update_on_z, alert_image) +/atom/proc/forget_alert(atom/movable/flick_visual/exclamation) + LAZYREMOVE(update_on_z, exclamation) /obj/structure/closet/cardboard/metal name = "large metal box" diff --git a/code/game/objects/structures/gym/weight_machine.dm b/code/game/objects/structures/gym/weight_machine.dm index ef156f1b645..3f6361a494d 100644 --- a/code/game/objects/structures/gym/weight_machine.dm +++ b/code/game/objects/structures/gym/weight_machine.dm @@ -105,9 +105,9 @@ if(!has_buckled_mobs()) end_workout() return FALSE - var/image/workout_icon = new(icon, src, "[base_icon_state]-o", ABOVE_MOB_LAYER) - workout_icon.plane = GAME_PLANE_UPPER - flick_overlay_view(workout_icon, 8) + var/mutable_appearance/workout = mutable_appearance(icon, "[base_icon_state]-o", ABOVE_MOB_LAYER) + SET_PLANE_EXPLICIT(workout, GAME_PLANE_UPPER, src) + flick_overlay_view(workout, 0.8 SECONDS) flick("[base_icon_state]-u", src) var/mob/living/user = buckled_mobs[1] animate(user, pixel_y = pixel_shift_y, time = 4) diff --git a/code/game/turfs/closed/minerals.dm b/code/game/turfs/closed/minerals.dm index 6be28e9c0b3..0b4561bf842 100644 --- a/code/game/turfs/closed/minerals.dm +++ b/code/game/turfs/closed/minerals.dm @@ -704,7 +704,7 @@ /turf/closed/mineral/gibtonite/proc/countdown(notify_admins = FALSE) set waitfor = FALSE while(istype(src, /turf/closed/mineral/gibtonite) && stage == GIBTONITE_ACTIVE && det_time > 0 && mineralAmt >= 1) - flick_overlay_view(image('icons/turf/smoothrocks.dmi', src, "rock_Gibtonite_active"), 5) //makes the animation pulse one time per tick + flick_overlay_view(mutable_appearance('icons/turf/smoothrocks.dmi', "rock_Gibtonite_active", ON_EDGED_TURF_LAYER + 0.1), 0.5 SECONDS) //makes the animation pulse one time per tick det_time-- sleep(0.5 SECONDS) if(istype(src, /turf/closed/mineral/gibtonite)) diff --git a/code/modules/antagonists/heretic/magic/fire_blast.dm b/code/modules/antagonists/heretic/magic/fire_blast.dm index 8900ea2350a..d3d3e0b2df0 100644 --- a/code/modules/antagonists/heretic/magic/fire_blast.dm +++ b/code/modules/antagonists/heretic/magic/fire_blast.dm @@ -129,10 +129,10 @@ /datum/status_effect/fire_blasted/on_apply() if(owner.on_fire && animate_duration > 0 SECONDS) - var/image/warning_sign = image(icon = 'icons/effects/effects.dmi', icon_state = "blessed", layer = BELOW_MOB_LAYER, loc = owner) - owner.flick_overlay_view(warning_sign, initial(duration)) - warning_sign.alpha = 50 - animate(warning_sign, alpha = 255, time = animate_duration) + var/mutable_appearance/warning_sign = mutable_appearance('icons/effects/effects.dmi', "blessed", BELOW_MOB_LAYER) + var/atom/movable/flick_visual/warning = owner.flick_overlay_view(warning_sign, initial(duration)) + warning.alpha = 50 + animate(warning, alpha = 255, time = animate_duration) return TRUE diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index f746a75bdfc..cee8b4e8cc9 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -861,9 +861,9 @@ // Beakers, bottles, buckets, etc. if(reagent_source.is_drainable()) playsound(loc, 'sound/effects/slosh.ogg', 25, TRUE) - var/image/splash_animation = image('icons/effects/effects.dmi', src, "splash_hydroponics") + var/mutable_appearance/splash_animation = mutable_appearance('icons/effects/effects.dmi', "splash_hydroponics") splash_animation.color = mix_color_from_reagents(reagent_source.reagents.reagent_list) - flick_overlay_global(splash_animation, GLOB.clients, 1.1 SECONDS) + flick_overlay_view(splash_animation, 1.1 SECONDS) if(visi_msg) visible_message(span_notice("[visi_msg].")) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 26538109f2a..d7b929fe30a 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -506,13 +506,13 @@ */ /mob/living/proc/do_slap_animation(atom/slapped) do_attack_animation(slapped, no_effect=TRUE) - var/image/gloveimg = image('icons/effects/effects.dmi', slapped, "slapglove", slapped.layer + 0.1) - gloveimg.pixel_y = 10 // should line up with head - gloveimg.pixel_x = 10 - flick_overlay_global(gloveimg, GLOB.clients, 10) + var/mutable_appearance/glove_appearance = mutable_appearance('icons/effects/effects.dmi', "slapglove") + glove_appearance.pixel_y = 10 // should line up with head + glove_appearance.pixel_x = 10 + var/atom/movable/flick_visual/glove = slapped.flick_overlay_view(glove_appearance, 1 SECONDS) // And animate the attack! - animate(gloveimg, alpha = 175, transform = matrix() * 0.75, pixel_x = 0, pixel_y = 10, pixel_z = 0, time = 3) + animate(glove, alpha = 175, transform = matrix() * 0.75, pixel_x = 0, pixel_y = 10, pixel_z = 0, time = 3) animate(time = 1) animate(alpha = 0, time = 3, easing = CIRCULAR_EASING|EASE_OUT) diff --git a/code/modules/mob/living/simple_animal/guardian/types/protector.dm b/code/modules/mob/living/simple_animal/guardian/types/protector.dm index 584041752a8..4809c3dc1c6 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/protector.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/protector.dm @@ -35,7 +35,7 @@ /mob/living/simple_animal/hostile/guardian/protector/adjustHealth(amount, updating_health = TRUE, forced = FALSE) . = ..() if(. > 0 && toggle) - var/image/flash_overlay = new('icons/effects/effects.dmi', src, "shield-flash", layer+0.01, dir = pick(GLOB.cardinals)) + var/image/flash_overlay = new('icons/effects/effects.dmi', src, "shield-flash", dir = pick(GLOB.cardinals)) flash_overlay.color = guardian_color flick_overlay_view(flash_overlay, 0.5 SECONDS) diff --git a/code/modules/mob/living/simple_animal/hostile/blobbernaut.dm b/code/modules/mob/living/simple_animal/hostile/blobbernaut.dm index 2162ff5d68b..dc1d038795f 100644 --- a/code/modules/mob/living/simple_animal/hostile/blobbernaut.dm +++ b/code/modules/mob/living/simple_animal/hostile/blobbernaut.dm @@ -71,13 +71,13 @@ return FALSE adjustHealth(maxHealth * BLOBMOB_BLOBBERNAUT_HEALTH_DECAY * damagesources * seconds_per_tick) //take 2.5% of max health as damage when not near the blob or if the naut has no factory, 5% if both - var/image/image = new('icons/mob/nonhuman-player/blob.dmi', src, "nautdamage", MOB_LAYER+0.01) - image.appearance_flags = RESET_COLOR + var/mutable_appearance/healing = mutable_appearance('icons/mob/nonhuman-player/blob.dmi', "nautdamage", MOB_LAYER+0.01) + healing.appearance_flags = RESET_COLOR if(overmind) - image.color = overmind.blobstrain.complementary_color + healing.color = overmind.blobstrain.complementary_color - flick_overlay_view(image, 8) + flick_overlay_view(healing, 0.8 SECONDS) /mob/living/simple_animal/hostile/blob/blobbernaut/AttackingTarget() . = ..() diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm index 38126f8feb1..ee90e9a6bbb 100644 --- a/code/modules/reagents/reagent_containers.dm +++ b/code/modules/reagents/reagent_containers.dm @@ -140,11 +140,11 @@ playsound(target, 'sound/effects/slosh.ogg', 25, TRUE) - var/image/splash_animation = image('icons/effects/effects.dmi', target, "splash") + var/mutable_appearance/splash_animation = mutable_appearance('icons/effects/effects.dmi', "splash") if(isturf(target)) - splash_animation = image('icons/effects/effects.dmi', target, "splash_floor") + splash_animation.icon_state = "splash_floor" splash_animation.color = mix_color_from_reagents(reagents.reagent_list) - flick_overlay_global(splash_animation, GLOB.clients, 1.0 SECONDS) + target.flick_overlay_view(splash_animation, 1 SECONDS) for(var/datum/reagent/reagent as anything in reagents.reagent_list) reagent_text += "[reagent] ([num2text(reagent.volume)])," @@ -239,11 +239,11 @@ playsound(target, 'sound/effects/slosh.ogg', 25, TRUE) - var/image/splash_animation = image('icons/effects/effects.dmi', target, "splash") + var/mutable_appearance/splash_animation = mutable_appearance('icons/effects/effects.dmi', "splash") if(isturf(target)) - splash_animation = image('icons/effects/effects.dmi', target, "splash_floor") + splash_animation.icon_state = "splash_floor" splash_animation.color = mix_color_from_reagents(reagents.reagent_list) - flick_overlay_global(splash_animation, GLOB.clients, 1.0 SECONDS) + target.flick_overlay_view(splash_animation, 1.0 SECONDS) reagents.clear_reagents() diff --git a/icons/turf/smoothrocks.dmi b/icons/turf/smoothrocks.dmi index 0948aaaaa3b..9a60937a219 100644 Binary files a/icons/turf/smoothrocks.dmi and b/icons/turf/smoothrocks.dmi differ