diff --git a/code/__DEFINES/layers_planes.dm b/code/__DEFINES/layers_planes.dm index c7be89721e..cde08c3a60 100644 --- a/code/__DEFINES/layers_planes.dm +++ b/code/__DEFINES/layers_planes.dm @@ -153,6 +153,9 @@ #define CAMERA_STATIC_LAYER 19 #define CAMERA_STATIC_RENDER_TARGET "CAMERA_STATIC_PLANE" +/// Over lighting and every other crap, this is nearly as important as hud content and only visible to the user. +#define BALLOON_CHAT_PLANE 20 + //HUD layer defines #define FULLSCREEN_PLANE 20 diff --git a/code/__DEFINES/text.dm b/code/__DEFINES/text.dm new file mode 100644 index 0000000000..58c24747e0 --- /dev/null +++ b/code/__DEFINES/text.dm @@ -0,0 +1,5 @@ +/// Prepares a text to be used for maptext. Use this so it doesn't look hideous. +#define MAPTEXT(text) {"[##text]"} + +/// Macro from Lummox used to get height from a MeasureText proc +#define WXH_TO_HEIGHT(x) text2num(copytext(x, findtextEx(x, "x") + 1)) diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index e55faab1be..23dd63b4fd 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -402,6 +402,10 @@ O.screen_loc = screen_loc return O +/// Removes an image from a client's `.images`. Useful as a callback. +/proc/remove_image_from_client(image/image, client/remove_from) + remove_from?.images -= image + /proc/remove_images_from_clients(image/I, list/show_to) for(var/client/C in show_to) C.images -= I diff --git a/code/datums/chatmessage.dm b/code/datums/chatmessage.dm index eb49323464..fb95565d90 100644 --- a/code/datums/chatmessage.dm +++ b/code/datums/chatmessage.dm @@ -18,8 +18,6 @@ #define CHAT_LAYER_Z_STEP 0.0001 /// The number of z-layer 'slices' usable by the chat message layering #define CHAT_LAYER_MAX_Z (CHAT_LAYER_MAX - CHAT_LAYER) / CHAT_LAYER_Z_STEP -/// Macro from Lummox used to get height from a MeasureText proc -#define WXH_TO_HEIGHT(x) text2num(copytext(x, findtextEx(x, "x") + 1)) /** * # Chat Message Overlay diff --git a/code/modules/balloon_alert/balloon_alert.dm b/code/modules/balloon_alert/balloon_alert.dm new file mode 100644 index 0000000000..8a25206ed0 --- /dev/null +++ b/code/modules/balloon_alert/balloon_alert.dm @@ -0,0 +1,90 @@ +#define BALLOON_TEXT_WIDTH 200 +#define BALLOON_TEXT_SPAWN_TIME (0.2 SECONDS) +#define BALLOON_TEXT_FADE_TIME (0.1 SECONDS) +#define BALLOON_TEXT_FULLY_VISIBLE_TIME (0.7 SECONDS) +#define BALLOON_TEXT_TOTAL_LIFETIME(mult) (BALLOON_TEXT_SPAWN_TIME + BALLOON_TEXT_FULLY_VISIBLE_TIME*mult + BALLOON_TEXT_FADE_TIME) +/// The increase in duration per character in seconds +#define BALLOON_TEXT_CHAR_LIFETIME_INCREASE_MULT (0.05) +/// The amount of characters needed before this increase takes into effect +#define BALLOON_TEXT_CHAR_LIFETIME_INCREASE_MIN 10 + +/// Creates text that will float from the atom upwards to the viewer. +/atom/proc/balloon_alert(mob/viewer, text) + SHOULD_NOT_SLEEP(TRUE) + + INVOKE_ASYNC(src, .proc/balloon_alert_perform, viewer, text) + +/// Create balloon alerts (text that floats up) to everything within range. +/// Will only display to people who can see. +/atom/proc/balloon_alert_to_viewers(message, self_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs) + SHOULD_NOT_SLEEP(TRUE) + + var/list/hearers = get_hearers_in_view(vision_distance, src) + hearers -= ignored_mobs + + for (var/mob/hearer in hearers) + if (hearer.is_blind()) + continue + + balloon_alert(hearer, (hearer == src && self_message) || message) + +// Do not use. +// MeasureText blocks. I have no idea for how long. +// I would've made the maptext_height update on its own, but I don't know +// if this would look bad on laggy clients. +/atom/proc/balloon_alert_perform(mob/viewer, text) + var/client/viewer_client = viewer.client + if (isnull(viewer_client)) + return + + var/bound_width = world.icon_size + if (ismovable(src)) + var/atom/movable/movable_source = src + bound_width = movable_source.bound_width + + var/image/balloon_alert = image(loc = get_atom_on_turf(src), layer = ABOVE_MOB_LAYER) + balloon_alert.plane = BALLOON_CHAT_PLANE + balloon_alert.alpha = 0 + balloon_alert.appearance_flags = RESET_ALPHA|RESET_COLOR|RESET_TRANSFORM + balloon_alert.maptext = MAPTEXT("[text]") + balloon_alert.maptext_x = (BALLOON_TEXT_WIDTH - bound_width) * -0.5 + balloon_alert.maptext_height = WXH_TO_HEIGHT(viewer_client?.MeasureText(text, null, BALLOON_TEXT_WIDTH)) + balloon_alert.maptext_width = BALLOON_TEXT_WIDTH + + viewer_client?.images += balloon_alert + + var/duration_mult = 1 + var/duration_length = length(text) - BALLOON_TEXT_CHAR_LIFETIME_INCREASE_MIN + + if(duration_length > 0) + duration_mult += duration_length*BALLOON_TEXT_CHAR_LIFETIME_INCREASE_MULT + + animate( + balloon_alert, + pixel_y = world.icon_size * 1.2, + time = BALLOON_TEXT_TOTAL_LIFETIME(1), + easing = SINE_EASING | EASE_OUT, + ) + + animate( + alpha = 255, + time = BALLOON_TEXT_SPAWN_TIME, + easing = CUBIC_EASING | EASE_OUT, + flags = ANIMATION_PARALLEL, + ) + + animate( + alpha = 0, + time = BALLOON_TEXT_FULLY_VISIBLE_TIME*duration_mult, + easing = CUBIC_EASING | EASE_IN, + ) + + addtimer(CALLBACK(GLOBAL_PROC, .proc/remove_image_from_client, balloon_alert, viewer_client), BALLOON_TEXT_TOTAL_LIFETIME(duration_mult)) + +#undef BALLOON_TEXT_CHAR_LIFETIME_INCREASE_MIN +#undef BALLOON_TEXT_CHAR_LIFETIME_INCREASE_MULT +#undef BALLOON_TEXT_FADE_TIME +#undef BALLOON_TEXT_FULLY_VISIBLE_TIME +#undef BALLOON_TEXT_SPAWN_TIME +#undef BALLOON_TEXT_TOTAL_LIFETIME +#undef BALLOON_TEXT_WIDTH diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm index 8744af7b28..aa871723a3 100644 --- a/code/modules/reagents/reagent_containers.dm +++ b/code/modules/reagents/reagent_containers.dm @@ -66,7 +66,7 @@ amount_per_transfer_from_this = possible_transfer_amounts[i+1] else amount_per_transfer_from_this = possible_transfer_amounts[1] - to_chat(user, "[src]'s transfer amount is now [amount_per_transfer_from_this] units.") + balloon_alert(user, "Transferring [amount_per_transfer_from_this]u") return /obj/item/reagent_containers/attack(mob/living/M, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1) diff --git a/tgstation.dme b/tgstation.dme index 79aef22354..0d0171ce0e 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -119,6 +119,7 @@ #include "code\__DEFINES\status_effects.dm" #include "code\__DEFINES\strippable.dm" #include "code\__DEFINES\subsystems.dm" +#include "code\__DEFINES\text.dm" #include "code\__DEFINES\tgs.config.dm" #include "code\__DEFINES\tgs.dm" #include "code\__DEFINES\tgui.dm" @@ -1905,6 +1906,7 @@ #include "code\modules\awaymissions\mission_code\stationCollision.dm" #include "code\modules\awaymissions\mission_code\undergroundoutpost45.dm" #include "code\modules\awaymissions\mission_code\wildwest.dm" +#include "code\modules\balloon_alert\balloon_alert.dm" #include "code\modules\buildmode\bm_mode.dm" #include "code\modules\buildmode\buildmode.dm" #include "code\modules\buildmode\buttons.dm"