diff --git a/code/__DEFINES/_planes+layers.dm b/code/__DEFINES/_planes+layers.dm index 885fa0a270e..b897a46c5f4 100644 --- a/code/__DEFINES/_planes+layers.dm +++ b/code/__DEFINES/_planes+layers.dm @@ -346,6 +346,9 @@ */ #define OBSERVER_PLANE 30 +/// Just above ghosts +#define POINT_PLANE 31 + /** *! -- Augmented Plane *? Augmented-reality stuff. diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 011efc5bf1c..eed1884f234 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1190,12 +1190,12 @@ var/list/WALLITEMS = list( /// Returns an x and y value require to reverse the transformations made to center an oversized icon /atom/proc/get_oversized_icon_offsets() - if (pixel_x == 0 && pixel_y == 0) + if (!base_pixel_x && !base_pixel_y && !base_pixel_w && !base_pixel_z) return list("x" = 0, "y" = 0) var/list/icon_dimensions = get_icon_dimensions(icon) var/icon_width = icon_dimensions["width"] var/icon_height = icon_dimensions["height"] return list( - "x" = icon_width > 32 && pixel_x != 0 ? (icon_width - 32) * 0.5 : 0, - "y" = icon_height > 32 && pixel_y != 0 ? (icon_height - 32) * 0.5 : 0, + "x" = icon_width > world.icon_size && (base_pixel_x || base_pixel_w) ? (icon_width - world.icon_size) * 0.5 : 0, + "y" = icon_height > world.icon_size && (base_pixel_y || base_pixel_z) ? (icon_height - world.icon_size) * 0.5 : 0, ) diff --git a/code/datums/progressbar.dm b/code/datums/progressbar.dm index 8b0e81746ef..7a017f7e074 100644 --- a/code/datums/progressbar.dm +++ b/code/datums/progressbar.dm @@ -79,9 +79,9 @@ continue progress_bar.listindex-- - progress_bar.bar.pixel_y = 32 + offset_y + (PROGRESSBAR_HEIGHT * (progress_bar.listindex - 1)) - var/dist_to_travel = 32 + offset_y + (PROGRESSBAR_HEIGHT * (progress_bar.listindex - 1)) - PROGRESSBAR_HEIGHT - animate(progress_bar.bar, pixel_y = dist_to_travel, time = PROGRESSBAR_ANIMATION_TIME, easing = SINE_EASING) + progress_bar.bar.pixel_z = world.icon_size + offset_y + (PROGRESSBAR_HEIGHT * (progress_bar.listindex - 1)) + var/dist_to_travel = world.icon_size + offset_y + (PROGRESSBAR_HEIGHT * (progress_bar.listindex - 1)) - PROGRESSBAR_HEIGHT + animate(progress_bar.bar, pixel_z = dist_to_travel, time = PROGRESSBAR_ANIMATION_TIME, easing = SINE_EASING) LAZYREMOVEASSOC(user.progressbars, bar_loc, src) user = null @@ -126,10 +126,10 @@ ///Adds a smoothly-appearing progress bar image to the player's screen. /datum/progressbar/proc/add_prog_bar_image_to_client() - bar.pixel_y = 0 + bar.pixel_z = 0 bar.alpha = 0 user_client.images += bar - animate(bar, pixel_y = 32 + offset_y + (PROGRESSBAR_HEIGHT * (listindex - 1)), alpha = 255, time = PROGRESSBAR_ANIMATION_TIME, easing = SINE_EASING) + animate(bar, pixel_z = world.icon_size + offset_y + (PROGRESSBAR_HEIGHT * (listindex - 1)), alpha = 255, time = PROGRESSBAR_ANIMATION_TIME, easing = SINE_EASING) ///Updates the progress bar image visually. /datum/progressbar/proc/update(progress) diff --git a/code/game/atoms/_atom.dm b/code/game/atoms/_atom.dm index 43b14bfafde..df6c62c88c3 100644 --- a/code/game/atoms/_atom.dm +++ b/code/game/atoms/_atom.dm @@ -193,7 +193,12 @@ /// and permanent adjustment. /// * Do **not** use this when calculating auto-centering; if we are a wall-mount it doesn't make sense to do so, as an example. var/base_pixel_y = 0 - /// expected icon width + ///Default pixel w shifting for the atom's icon. + var/base_pixel_w = 0 + ///Default pixel z shifting for the atom's icon. + var/base_pixel_z = 0 + + /// expected icon width; centering offsets will be calculated from this and our base pixel x. /// * this **should**, but often is not necessarily, always set to the icon's actual file dimensions. /// if an admin edits an icon this is often not set and we can't really assume alignment either way, so. /// * this is not necessarily able to be used for centering unless we are actually centered in the icon. diff --git a/code/game/objects/effects/temporary_visuals/point.dm b/code/game/objects/effects/temporary_visuals/point.dm index 1b16a3a5da8..a819fb60371 100644 --- a/code/game/objects/effects/temporary_visuals/point.dm +++ b/code/game/objects/effects/temporary_visuals/point.dm @@ -1,9 +1,16 @@ /obj/effect/temp_visual/point - name = "arrow" - desc = "It's an arrow hanging in mid-air. There may be a wizard about." + name = "pointer" icon = 'icons/mob/screen1.dmi' icon_state = "arrow" - plane = ABOVE_PLANE - anchored = 1 + plane = POINT_PLANE + duration = (2.5 SECONDS) + anchored = TRUE mouse_opacity = 0 - duration = 2 SECONDS + +/obj/effect/temp_visual/point/Initialize(mapload, set_invis = 0) + . = ..() + var/atom/old_loc = loc + abstract_move(get_turf(src)) + pixel_x = old_loc.pixel_x + pixel_y = old_loc.pixel_y + set_invisibility(set_invis) diff --git a/code/modules/mining/tools/fulton.dm b/code/modules/mining/tools/fulton.dm index b2c3a787de1..8acfa3de0d4 100644 --- a/code/modules/mining/tools/fulton.dm +++ b/code/modules/mining/tools/fulton.dm @@ -1,4 +1,4 @@ -var/global/list/total_extraction_beacons = list() +GLOBAL_LIST_EMPTY(total_extraction_beacons) // todo: this should be included in the air-support module being added later, not just a mining exclusive @@ -8,12 +8,19 @@ var/global/list/total_extraction_beacons = list() icon = 'icons/obj/fulton.dmi' icon_state = "extraction_pack" w_class = WEIGHT_CLASS_NORMAL - var/obj/structure/extraction_point/beacon + /// Beacon weakref + var/datum/weakref/beacon_ref + /// List of networks var/list/beacon_networks = list("station") + /// Number of uses left var/uses_left = 3 - var/can_use_indoors = FALSE - var/safe_for_living_creatures = 1 + /// Can be used indoors + var/can_use_indoors + /// Can be used on living creatures + var/safe_for_living_creatures = TRUE var/stuntime = 15 + /// Maximum force that can be used to extract + var/max_force_fulton = MOVE_FORCE_STRONG /obj/item/extraction_pack/wormhole name = "wormhole fulton extraction pack" @@ -27,143 +34,171 @@ var/global/list/total_extraction_beacons = list() icon = 'icons/obj/storage.dmi' icon_state = "phoroncrate" -/obj/item/extraction_pack/examine(mob/user, dist) +/obj/item/extraction_pack/examine() . = ..() - . +="It has [uses_left] use\s remaining." + . += SPAN_INFOPLAIN("It has [uses_left] use\s remaining.") + + var/obj/structure/extraction_point/beacon = beacon_ref?.resolve() + + if(isnull(beacon)) + beacon_ref = null + . += SPAN_INFOPLAIN("It is not linked to a beacon.") + return + + . += SPAN_INFOPLAIN("It is linked to [beacon.name].") /obj/item/extraction_pack/attack_self(mob/user, datum/event_args/actor/actor) . = ..() if(.) return var/list/possible_beacons = list() - for(var/B in global.total_extraction_beacons) - var/obj/structure/extraction_point/EP = B - if(EP.beacon_network in beacon_networks) - possible_beacons += EP + for(var/datum/weakref/point_ref as anything in GLOB.total_extraction_beacons) + var/obj/structure/extraction_point/extraction_point = point_ref.resolve() + if(isnull(extraction_point)) + GLOB.total_extraction_beacons.Remove(point_ref) + continue + if(extraction_point.beacon_network in beacon_networks) + possible_beacons += extraction_point - if(!possible_beacons.len) - to_chat(user, "There are no extraction beacons in existence!") + if(!length(possible_beacons)) + balloon_alert(user, "no beacons") return - else - var/A - - A = input("Select a beacon to connect to", "Balloon Extraction Pack", A) as null|anything in possible_beacons - - if(!A) - return - beacon = A - to_chat(user, "You link the extraction pack to the beacon system.") - -/obj/item/extraction_pack/afterattack(atom/movable/target, mob/user, clickchain_flags, list/params) - if(!beacon) - to_chat(user, "[src] is not linked to a beacon, and cannot be used.") + var/chosen_beacon = tgui_input_list(user, "Beacon to connect to", "Balloon Extraction Pack", sortNames(possible_beacons)) + if(isnull(chosen_beacon)) return - if(!can_use_indoors) - var/turf/T = get_turf(target) - if(T && !T.outdoors) - to_chat(user, "[src] can only be used on things that are outdoors!") - return + + beacon_ref = WEAKREF(chosen_beacon) + balloon_alert(user, "linked!") + +/obj/item/extraction_pack/afterattack(atom/interacting_with, mob/user, clickchain_flags, list/params) if(!(clickchain_flags & CLICKCHAIN_HAS_PROXIMITY)) return - if(!istype(target)) + if(!ismovable(interacting_with)) + return + if(!isturf(interacting_with.loc)) // no extracting stuff inside other stuff + return + var/atom/movable/thing = interacting_with + if(thing.anchored) return - else - if(!safe_for_living_creatures && check_for_living_mobs(target)) - to_chat(user, "[src] is not safe for use with living creatures, they wouldn't survive the trip back!") - return - if(!isturf(target.loc)) // no extracting stuff inside other stuff - return - if(target.anchored) - return - to_chat(user, "You start attaching the pack to [target]...") - if(do_after(user,50,target=target)) - to_chat(user, "You attach the pack to [target] and activate it.") - /* No components, sorry. No convienence for you! - if(loc == user && istype(user.back, /obj/item/storage/backpack)) - var/obj/item/storage/backpack/B = user.back - B.SendSignal(COMSIG_TRY_STORAGE_INSERT, src, user, FALSE, FALSE) - */ - uses_left-- - if(uses_left <= 0) - user.temporarily_remove_from_inventory(src, INV_OP_FORCE | INV_OP_SHOULD_NOT_INTERCEPT | INV_OP_SILENT) - var/mutable_appearance/balloon - var/mutable_appearance/balloon2 - var/mutable_appearance/balloon3 - if(isliving(target)) - var/mob/living/M = target - M.adjust_stunned(20 * 10) // Keep them from moving during the duration of the extraction - if(M.buckled) - M.buckled.unbuckle_mob(M) - else - target.anchored = TRUE - target.density = FALSE - var/obj/effect/extraction_holder/holder_obj = new(target.loc) - holder_obj.appearance = /obj/item/extraction_holdercrate - target.forceMove(holder_obj) - balloon2 = mutable_appearance('icons/obj/fulton_balloon.dmi', "fulton_expand") - balloon2.pixel_y = 18 - balloon2.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM - holder_obj.add_overlay(balloon2) - sleep(4) - balloon = mutable_appearance('icons/obj/fulton_balloon.dmi', "fulton_balloon") - balloon.pixel_y = 18 - balloon.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM - holder_obj.cut_overlay(balloon2) - holder_obj.add_overlay(balloon) - playsound(holder_obj.loc, 'sound/items/fulext_deploy.wav', 50, 1, -3) - animate(holder_obj, pixel_z = 10, time = 20) - sleep(20) - animate(holder_obj, pixel_z = 15, time = 10) - sleep(10) - animate(holder_obj, pixel_z = 10, time = 10) - sleep(10) - animate(holder_obj, pixel_z = 15, time = 10) - sleep(10) - animate(holder_obj, pixel_z = 10, time = 10) - sleep(10) - playsound(holder_obj.loc, 'sound/items/fultext_launch.wav', 50, 1, -3) - animate(holder_obj, pixel_z = 1000, time = 30) - if(ishuman(target)) - var/mob/living/carbon/L = target - L.adjust_stunned(20 * stuntime) - L.drowsyness = 0 - sleep(30) - var/list/flooring_near_beacon = list() - for(var/turf/T in range(1, beacon)) - if(T.density) - continue - flooring_near_beacon += T - if(!length(flooring_near_beacon)) - holder_obj.forceMove(get_turf(beacon)) - else - holder_obj.forceMove(pick(flooring_near_beacon)) - animate(holder_obj, pixel_z = 10, time = 50) - sleep(50) - animate(holder_obj, pixel_z = 15, time = 10) - sleep(10) - animate(holder_obj, pixel_z = 10, time = 10) - sleep(10) - balloon3 = mutable_appearance('icons/obj/fulton_balloon.dmi', "fulton_retract") - balloon3.pixel_y = 10 - balloon3.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM - holder_obj.cut_overlay(balloon) - holder_obj.add_overlay(balloon3) - sleep(4) - holder_obj.cut_overlay(balloon3) - target.anchored = FALSE // An item has to be unanchored to be extracted in the first place. - target.density = initial(target.density) - animate(holder_obj, pixel_z = 0, time = 5) - sleep(5) - target.forceMove(holder_obj.loc) - qdel(holder_obj) - if(uses_left <= 0) - qdel(src) + var/obj/structure/extraction_point/beacon = beacon_ref?.resolve() + if(isnull(beacon)) + balloon_alert(user, "not linked!") + beacon_ref = null + return + var/turf/turf = get_turf(thing) + if(!can_use_indoors) + if(!turf?.outdoors) + balloon_alert(user, "not outdoors!") + return + if(!safe_for_living_creatures && check_for_living_mobs(thing)) + to_chat(user, SPAN_WARNING("[src] is not safe for use with living creatures, they wouldn't survive the trip back!")) + balloon_alert(user, "not safe!") + return + if(thing.move_resist > max_force_fulton) + balloon_alert(user, "too heavy!") + return + + balloon_alert_to_viewers("attaching...") + playsound(thing, 'sound/items/zip.ogg', vol = 50, vary = TRUE) + if(isliving(thing)) + var/mob/living/creature = thing + if(creature.mind) + to_chat(thing, SPAN_USERDANGER("You are being extracted! Stand still to proceed.")) + + if(!do_after(user, 5 SECONDS, target = thing)) + return + + balloon_alert_to_viewers("extracting!") + // if(loc == user && ishuman(user)) + // var/mob/living/carbon/human/human_user = user + // human_user.back?.atom_storage?.attempt_insert(src, user, force = STORAGE_SOFT_LOCKED) + uses_left-- + + if(uses_left <= 0) + user.transfer_item_to_loc(src, thing, INV_OP_FORCE | INV_OP_SHOULD_NOT_INTERCEPT | INV_OP_SILENT) + + if(isliving(thing)) + var/mob/living/creature = thing + creature.set_paralyzed(32 SECONDS) // Keep them from moving during the duration of the extraction + if(creature.buckled) + creature.buckled.unbuckle_mob(creature, TRUE) // Unbuckle them to prevent anchoring problems + else + thing.set_anchored(TRUE) + thing.set_density(FALSE) + + var/obj/effect/extraction_holder/holder_obj = new(get_turf(thing)) + holder_obj.appearance = thing.appearance + thing.forceMove(holder_obj) + var/mutable_appearance/balloon2 = mutable_appearance('icons/obj/fulton_balloon.dmi', "fulton_expand", layer = ABOVE_MOB_LAYER+0.1, appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM | KEEP_APART) + balloon2.pixel_z = 10 + holder_obj.add_overlay(balloon2) + addtimer(CALLBACK(src, PROC_REF(create_balloon), thing, user, holder_obj, balloon2), 0.4 SECONDS) + +/obj/item/extraction_pack/proc/create_balloon(atom/movable/thing, mob/living/user, obj/effect/extraction_holder/holder_obj, mutable_appearance/balloon2) + var/mutable_appearance/balloon = mutable_appearance('icons/obj/fulton_balloon.dmi', "fulton_balloon", layer = ABOVE_MOB_LAYER+0.1, appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM | KEEP_APART) + balloon.pixel_z = 10 + holder_obj.cut_overlay(balloon2) + holder_obj.add_overlay(balloon) + playsound(holder_obj.loc, 'sound/items/fultext_deploy.ogg', vol = 50, vary = TRUE, extrarange = -3) + + animate(holder_obj, pixel_z = 10, time = 2 SECONDS, flags = ANIMATION_RELATIVE) + animate(pixel_z = 5, time = 1 SECONDS, flags = ANIMATION_RELATIVE) + animate(pixel_z = -5, time = 1 SECONDS, flags = ANIMATION_RELATIVE) + animate(pixel_z = 5, time = 1 SECONDS, flags = ANIMATION_RELATIVE) + animate(pixel_z = -5, time = 1 SECONDS, flags = ANIMATION_RELATIVE) + + sleep(6 SECONDS) + + playsound(holder_obj.loc, 'sound/items/fultext_launch.ogg', vol = 50, vary = TRUE, extrarange = -3) + animate(holder_obj, pixel_z = 1000, time = 3 SECONDS, flags = ANIMATION_RELATIVE) + + if(ishuman(thing)) + var/mob/living/carbon/human/creature = thing + creature.set_unconscious(0) + creature.drowsyness = 0 + creature.set_sleeping(0) + + sleep(3 SECONDS) + + var/turf/flooring_near_beacon = list() + var/turf/beacon_turf = get_turf(beacon_ref.resolve()) + for(var/turf/floor as anything in RANGE_TURFS(1, beacon_turf)) + if(!is_blocked_turf(floor)) + flooring_near_beacon += floor + + if(!length(flooring_near_beacon)) + flooring_near_beacon += beacon_turf + + holder_obj.forceMove(pick(flooring_near_beacon)) + + animate(holder_obj, pixel_z = -990, time = 5 SECONDS, flags = ANIMATION_RELATIVE) + animate(pixel_z = 5, time = 1 SECONDS, flags = ANIMATION_RELATIVE) + animate(pixel_z = -5, time = 1 SECONDS, flags = ANIMATION_RELATIVE) + + sleep(7 SECONDS) + + var/mutable_appearance/balloon3 = mutable_appearance('icons/obj/fulton_balloon.dmi', "fulton_retract", layer = ABOVE_MOB_LAYER+0.1, appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM | KEEP_APART) + balloon3.pixel_z = 10 + holder_obj.cut_overlay(balloon) + holder_obj.add_overlay(balloon3) + + sleep(0.4 SECONDS) + + holder_obj.cut_overlay(balloon3) + thing.set_anchored(FALSE) // An item has to be unanchored to be extracted in the first place. + thing.set_density(initial(thing.density)) + animate(holder_obj, pixel_z = -10, time = 0.5 SECONDS, flags = ANIMATION_RELATIVE) + sleep(0.5 SECONDS) + thing.forceMove(holder_obj.loc) + qdel(holder_obj) + if(uses_left <= 0) + qdel(src) /obj/item/fulton_core - name = "extraction beacon signaller" - desc = "Emits a signal which fulton recovery devices can lock onto. Activate in hand to create a beacon." + name = "extraction beacon assembly kit" + desc = "When built, emits a signal which fulton recovery devices can lock onto. Activate in hand to unfold into a beacon." icon = 'icons/obj/stock_parts.dmi' icon_state = "subspace_amplifier" @@ -171,9 +206,12 @@ var/global/list/total_extraction_beacons = list() . = ..() if(.) return - if(do_after(user,15,target = user) && !QDELETED(src)) - new /obj/structure/extraction_point(get_turf(user)) - qdel(src) + if(!do_after(user, 1.5 SECONDS, target = user) || QDELETED(src)) + return + + new /obj/structure/extraction_point(get_turf(user)) + playsound(src, 'sound/items/Deconstruct.ogg', vol = 50, vary = TRUE, extrarange = -5) + qdel(src) /obj/structure/extraction_point name = "fulton recovery beacon" @@ -187,11 +225,16 @@ var/global/list/total_extraction_beacons = list() /obj/structure/extraction_point/Initialize(mapload) . = ..() name += " ([rand(100,999)]) ([get_area_name(src, TRUE)])" - global.total_extraction_beacons += src + GLOB.total_extraction_beacons.Add(WEAKREF(src)) -/obj/structure/extraction_point/Destroy() - global.total_extraction_beacons -= src - ..() +/obj/structure/extraction_point/attack_hand(mob/living/user, datum/event_args/actor/clickchain/e_args) + . = ..() + balloon_alert_to_viewers("undeploying...") + if(!do_after(user, 1.5 SECONDS, src)) + return + new /obj/item/fulton_core(drop_location()) + playsound(src, 'sound/items/Deconstruct.ogg', vol = 50, vary = TRUE, extrarange = -5) + qdel(src) /obj/effect/extraction_holder name = "extraction holder" @@ -202,17 +245,16 @@ var/global/list/total_extraction_beacons = list() if(isliving(A)) var/mob/living/L = A if(L.stat != DEAD) - return 1 + return TRUE for(var/thing in A.get_all_contents()) if(isliving(A)) var/mob/living/L = A - update_icon() if(L.stat != DEAD) - return 1 - return 0 + return TRUE + return FALSE -/obj/effect/extraction_holder/singularity_pull() +/obj/effect/extraction_holder/singularity_act() return -/obj/effect/extraction_holder/singularity_pull() +/obj/effect/extraction_holder/singularity_pull(atom/singularity, current_size) return diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 7657ecaf396..888eea065cb 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -97,16 +97,19 @@ TYPE_REGISTER_SPATIAL_GRID(/mob/living, SSspatial_grids.living) start_pulling(AM) //mob verbs are faster than object verbs. See above. -/mob/living/pointed(atom/A as mob|obj|turf in view()) +/mob/living/pointed(atom/A as mob|obj|turf in view(client.view, src)) if(src.stat || src.restrained()) - return 0 + return FALSE if(src.status_flags & STATUS_FAKEDEATH) - return 0 - if(!..()) - return 0 + return FALSE - usr.visible_message("[src] points to [A]") - return 1 + return ..() + +/mob/living/_pointed(atom/pointing_at) + if(!..()) + return FALSE + log_emote("POINTED --> at [pointing_at] ([COORD(pointing_at)]).", src) + visible_message(SPAN_INFOPLAIN("[SPAN_NAME("[src]")] points at [pointing_at]."), SPAN_NOTICE("You point at [pointing_at].")) /*one proc, four uses swapping: if it's 1, the mobs are trying to switch, if 0, non-passive is pushing passive diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 516c880133a..2e856460455 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -391,6 +391,8 @@ to_chat(src, "
[result.Join("\n")]") SEND_SIGNAL(src, COMSIG_MOB_EXAMINATE, A) +#define POINT_TIME (2.5 SECONDS) + /** * Point at an atom * @@ -408,27 +410,100 @@ set name = "Point To" set category = VERB_CATEGORY_OBJECT - if(!src || !isturf(src.loc) || !(A in view(14, src))) - return 0 - if(istype(A, /obj/effect/temp_visual/point)) - return 0 + return FALSE - var/tile = get_turf(A) - if (!tile) - return 0 + // i am queued sometimes + _pointed(A) - var/obj/P = new /obj/effect/temp_visual/point(tile) - P.invisibility = invisibility - P.plane = ABOVE_PLANE - P.layer = FLY_LAYER - P.pixel_x = A.pixel_x + world.icon_size * (x - A.x) - P.pixel_y = A.pixel_y + world.icon_size * (y - A.y) - animate(P, pixel_x = A.pixel_x, pixel_y = A.pixel_y, time = 0.5 SECONDS, easing = QUAD_EASING) - face_atom(A) - log_emote("POINTED --> at [A] ([COORD(A)]).", src) +/mob/proc/_pointed(atom/pointing_at) + if(client) //Clientless mobs can just go ahead and point + if(!(pointing_at in view(client.view, src))) + return FALSE + // since we dont have the datum emote for pointing, too lazy to implement! (it sets the cooldown) + // if(iscarbon(src)) // special interactions for carbons + // var/mob/living/carbon/our_carbon = src + // if(our_carbon.get_usable_hand_count() <= 0 || our_carbon.handcuffed /* || HAS_TRAIT(src, TRAIT_HANDS_BLOCKED)*/) + // if(!TIMER_COOLDOWN_CHECK(src, "point_verb_emote_cooldown")) + // //cooldown handled in the emote. + // our_carbon.emote("point [pointing_at]") + // else + // to_chat(src, SPAN_WARNING("You need to wait before pointing again!")) + // return FALSE + + point_at(pointing_at, TRUE) return 1 +/** + * Point at an atom + * + * Intended to enable and standardise the pointing animation for all atoms + * + * Not intended as a replacement for the mob verb + */ +/atom/movable/proc/point_at(atom/pointed_atom, intentional = FALSE) + if(!isturf(loc)) + return FALSE + + if (pointed_atom in src) + create_point_bubble(pointed_atom) + return FALSE + + var/turf/tile = get_turf(pointed_atom) + if (!tile) + return FALSE + + var/turf/our_tile = get_turf(src) + var/obj/visual = new /obj/effect/temp_visual/point(our_tile, invisibility) + + // SEND_SIGNAL(src, COMSIG_MOVABLE_POINTED, pointed_atom, visual, intentional) + + animate(visual, pixel_x = (tile.x - our_tile.x) * world.icon_size + pointed_atom.pixel_x, pixel_y = (tile.y - our_tile.y) * world.icon_size + pointed_atom.pixel_y, time = 1.7, easing = EASE_OUT) + return TRUE + +/mob/point_at(atom/pointed_atom, intentional = FALSE) + . = ..() + if(.) + face_atom(pointed_atom) + +/atom/movable/proc/create_point_bubble(atom/pointed_atom) + var/mutable_appearance/thought_bubble = mutable_appearance( + 'icons/effects/effects.dmi', + "thought_bubble", + plane = POINT_PLANE, + appearance_flags = KEEP_APART, + ) + + var/mutable_appearance/pointed_atom_appearance = new(pointed_atom.appearance) + pointed_atom_appearance.blend_mode = BLEND_INSET_OVERLAY + pointed_atom_appearance.plane = FLOAT_PLANE + pointed_atom_appearance.layer = FLOAT_LAYER + pointed_atom_appearance.pixel_x = 0 + pointed_atom_appearance.pixel_y = 0 + thought_bubble.overlays += pointed_atom_appearance + // pointed_atom_appearance.remove_filter(HOVER_OUTLINE_FILTER) + + thought_bubble.pixel_w = 16 + thought_bubble.pixel_z = 32 + thought_bubble.alpha = 200 + + var/mutable_appearance/point_visual = mutable_appearance( + 'icons/mob/screen1.dmi', + "arrow" + ) + + thought_bubble.overlays += point_visual + + add_overlay(thought_bubble) + // LAZYADD(update_overlays_on_z, thought_bubble) + addtimer(CALLBACK(src, PROC_REF(clear_point_bubble), thought_bubble), POINT_TIME) + +/atom/movable/proc/clear_point_bubble(mutable_appearance/thought_bubble) + // LAZYREMOVE(update_overlays_on_z, thought_bubble) + cut_overlay(thought_bubble) + +#undef POINT_TIME + /mob/verb/set_self_relative_layer() set name = "Set relative layer" set desc = "Set your relative layer to other mobs on the same layer as yourself" diff --git a/code/modules/mob/observer/dead/dead.dm b/code/modules/mob/observer/dead/dead.dm index a25340b1e72..8361a8584fd 100644 --- a/code/modules/mob/observer/dead/dead.dm +++ b/code/modules/mob/observer/dead/dead.dm @@ -595,11 +595,11 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp W.add_hiddenprint(src) W.visible_message("Invisible fingers crudely paint something in blood on [T]...") -/mob/observer/dead/pointed(atom/A as mob|obj|turf in view()) +/mob/observer/dead/_pointed(atom/pointed_at) if(!..()) - return 0 - usr.visible_message("[src] points to [A]") - return 1 + return FALSE + + visible_message(SPAN_DEADSAY("[src] points to [pointed_at].")) /mob/observer/dead/proc/manifest(mob/user) is_manifest = TRUE diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index 6a7bac7c733..af888b6092d 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/sound/items/fulext_deploy.wav b/sound/items/fulext_deploy.wav deleted file mode 100644 index 9fbcb7e3f85..00000000000 Binary files a/sound/items/fulext_deploy.wav and /dev/null differ diff --git a/sound/items/fultext_launch.wav b/sound/items/fultext_launch.wav deleted file mode 100644 index a623a89ada4..00000000000 Binary files a/sound/items/fultext_launch.wav and /dev/null differ