diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm index d79d51ec91e..c47c4570b30 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers.dm @@ -177,6 +177,8 @@ #define RADIAL_BASE_LAYER 6 #define RADIAL_CONTENT_LAYER 7 +#define BALLOON_CHAT_PLANE 9 + /// This plane masks out lighting, to create an "emissive" effect for e.g glowing screens in otherwise dark areas. #define EMISSIVE_PLANE 10 #define EMISSIVE_TARGET "*emissive" diff --git a/code/_onclick/hud/rendering/_renderer.dm b/code/_onclick/hud/rendering/_renderer.dm index bfb7e768bc5..a5a7bde03c7 100644 --- a/code/_onclick/hud/rendering/_renderer.dm +++ b/code/_onclick/hud/rendering/_renderer.dm @@ -286,6 +286,13 @@ INITIALIZE_IMMEDIATE(/atom/movable/renderer) plane = HUD_PLANE renderer_flags = RENDERER_FLAG_AUTO +/// Draws balloon alert elements. NOT RUNECHAT +/atom/movable/renderer/balloon_alert + name = "Balloon Chat" + group = RENDER_GROUP_SCREEN + plane = BALLOON_CHAT_PLANE + renderer_flags = RENDERER_FLAG_AUTO + /* * * Group renderers diff --git a/code/game/machinery/howitzer.dm b/code/game/machinery/howitzer.dm index fd7bad1ecee..fdd48f0de83 100644 --- a/code/game/machinery/howitzer.dm +++ b/code/game/machinery/howitzer.dm @@ -169,7 +169,7 @@ ABSTRACT_TYPE(/obj/machinery/howitzer) return if(rotation_timerid) - balloon_alert_to_viewers("The howitzer is already doing an alignment!") + balloon_alert_to_viewers("already doing an alignment!") return //Not the same angle we are at, we have to rotate @@ -191,7 +191,7 @@ ABSTRACT_TYPE(/obj/machinery/howitzer) if(degrees_to_rotate > 180) degrees_to_rotate = 360 - degrees_to_rotate - balloon_alert_to_viewers("The howitzer starts to rotate!") + balloon_alert_to_viewers("rotating...") //Start the rotation looping sound rotation_looping_sound = new rotation_looping_sound_type(src) @@ -210,7 +210,7 @@ ABSTRACT_TYPE(/obj/machinery/howitzer) horizontal_angle = angle set_dir(wanted_dir) - balloon_alert_to_viewers("The howitzer stops rotating!") + balloon_alert_to_viewers("finished rotating") rotation_looping_sound.stop() QDEL_NULL(rotation_looping_sound) @@ -227,7 +227,7 @@ ABSTRACT_TYPE(/obj/machinery/howitzer) return if(rotation_timerid) - balloon_alert_to_viewers("The howitzer is already doing an alignment!") + balloon_alert_to_viewers("already doing an alignment!") return if(vertical_angle != angle) @@ -238,7 +238,7 @@ ABSTRACT_TYPE(/obj/machinery/howitzer) if(degrees_to_change > 180) //Yes this shouldn't happen, copy paste anyways degrees_to_change = 360 - degrees_to_change - balloon_alert_to_viewers("The howitzer starts to change the elevation!") + balloon_alert_to_viewers("changing elevation...") rotation_looping_sound = new rotation_looping_sound_type(src) rotation_looping_sound.start() @@ -253,7 +253,7 @@ ABSTRACT_TYPE(/obj/machinery/howitzer) vertical_angle = angle - balloon_alert_to_viewers("The howitzer steadies the barrel at the requested elevation!") + balloon_alert_to_viewers("finished changing elevation") rotation_looping_sound.stop() QDEL_NULL(rotation_looping_sound) @@ -266,7 +266,7 @@ ABSTRACT_TYPE(/obj/machinery/howitzer) */ /obj/machinery/howitzer/proc/fire(mob/user) if(!anchored) - balloon_alert_to_viewers("The howitzer is not anchored down!") + balloon_alert_to_viewers("not anchored down!") to_chat(user, SPAN_WARNING("The howitzer is not anchored down!")) return @@ -274,12 +274,12 @@ ABSTRACT_TYPE(/obj/machinery/howitzer) return if(!ready_to_fire) - balloon_alert_to_viewers("The howitzer is not ready to fire, it's adjusting the aim!") + balloon_alert_to_viewers("not ready to fire!") to_chat(user, SPAN_WARNING("The howitzer is not ready to fire, it's adjusting the aim!")) return if(!loaded_shot) - balloon_alert_to_viewers("The barrel is empty!") + balloon_alert_to_viewers("barrel is empty!") to_chat(user, SPAN_WARNING("The barrel is empty!")) return diff --git a/code/game/objects/items/devices/tvcamera.dm b/code/game/objects/items/devices/tvcamera.dm index cb8050bb505..604a6e4dd79 100644 --- a/code/game/objects/items/devices/tvcamera.dm +++ b/code/game/objects/items/devices/tvcamera.dm @@ -55,19 +55,23 @@ if(href_list["video"]) camera.set_status(!camera.status) if(camera.status) - balloon_alert(usr, SPAN_NOTICE("Video streaming: Activated. Broadcasting on channel: [channel]")) + balloon_alert(usr, "streaming video") + to_chat(usr, SPAN_NOTICE("Video streaming: Activated. Broadcasting on channel: [channel]")) playsound(src.loc, 'sound/machines/ping.ogg', 50, 1) else - balloon_alert(usr, SPAN_NOTICE("Video streaming: Deactivated.")) + balloon_alert(usr, "stopped streaming video") + to_chat(usr, SPAN_NOTICE("Video streaming: Deactivated.")) playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 1) update_icon() if(href_list["sound"]) radio.set_broadcasting(!radio.get_broadcasting()) if(radio.get_broadcasting()) - balloon_alert(usr, SPAN_NOTICE("Audio streaming: Activated. Broadcasting on frequency: [format_frequency(radio.get_frequency())].")) + balloon_alert(usr, "streaming audio") + to_chat(usr, SPAN_NOTICE("Audio streaming: Activated. Broadcasting on frequency: [format_frequency(radio.get_frequency())].")) playsound(src.loc, 'sound/machines/ping.ogg', 50, 1) else - balloon_alert(usr, SPAN_NOTICE("Audio streaming: Deactivated.")) + balloon_alert(usr, "stopped streaming audio") + to_chat(usr, SPAN_NOTICE("Audio streaming: Deactivated.")) playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 1) if(!href_list["close"]) attack_self(usr) diff --git a/code/game/objects/structures/weapons_rack.dm b/code/game/objects/structures/weapons_rack.dm index a1a8d29321e..dd5900ed94e 100644 --- a/code/game/objects/structures/weapons_rack.dm +++ b/code/game/objects/structures/weapons_rack.dm @@ -77,27 +77,29 @@ else if(istype(attacking_item, /obj/item/card/id)) var/obj/item/card/id/identification_card = attacking_item if(!forced_open && has_access(req_one_access = src.req_one_access, accesses = identification_card.access)) - balloon_alert_to_viewers("[user] [locked ? "unlocks" : "locks"] \the [src]!") + balloon_alert_to_viewers("[locked ? "unlocked" : "locked"]") playsound(src, 'sound/items/metal_shutter.ogg', 50, TRUE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) toggle_lock(user) else + balloon_alert(user, "it won't budge!") to_chat(user, SPAN_WARNING("You lack the required access to operate this rack's lock, or the lock mechanism is broken.")) else if(locked && attacking_item.iswelder()) var/obj/item/weldingtool/WT = attacking_item - balloon_alert_to_viewers("[user] starts to cut through the lock on \the [src]!") + balloon_alert_to_viewers("cutting through the lock...") if(WT.use_tool(src, user, 20 SECONDS, extra_checks = CALLBACK(src, PROC_REF(can_be_opened)))) //Last check because use_tool() is shitcoded if(forced_open || !can_be_opened()) return toggle_lock(user) + balloon_alert_to_viewers("lock cut") forced_open = TRUE else - balloon_alert_to_viewers("[src] was unlocked while you was working on it!") + to_chat(user, SPAN_NOTICE("\The [src] was unlocked while you were working on it!")) /obj/structure/weapons_rack/attack_hand(mob/living/user) diff --git a/code/modules/balloon_alert/balloon_alert.dm b/code/modules/balloon_alert/balloon_alert.dm index 8098aa3bb4c..101959489db 100644 --- a/code/modules/balloon_alert/balloon_alert.dm +++ b/code/modules/balloon_alert/balloon_alert.dm @@ -2,7 +2,11 @@ #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 (BALLOON_TEXT_SPAWN_TIME + BALLOON_TEXT_FULLY_VISIBLE_TIME + BALLOON_TEXT_FADE_TIME) +#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) @@ -23,10 +27,8 @@ for(var/mob/hearer in hearers - src) if(hearer.is_blind()) continue - balloon_alert(hearer, message) - if(self_message) - balloon_alert(src, self_message) + balloon_alert(hearer, (hearer == src && self_message) || message) // Do not use. // MeasureText blocks. I have no idea for how long. @@ -37,12 +39,13 @@ if (isnull(viewer_client)) return - var/bound_width = world.icon_size + var/bound_width = ICON_SIZE_X if (ismovable(src)) var/atom/movable/movable_source = src bound_width = movable_source.bound_width var/image/balloon_alert = image(loc = isturf(src) ? src : get_atom_on_turf(src), layer = ABOVE_HUMAN_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]") @@ -52,10 +55,12 @@ viewer_client?.images += balloon_alert + var/length_mult = 1 + max(0, length(strip_html_full(text)) - BALLOON_TEXT_CHAR_LIFETIME_INCREASE_MIN) * BALLOON_TEXT_CHAR_LIFETIME_INCREASE_MULT + animate( balloon_alert, - pixel_y = world.icon_size * 1.2, - time = BALLOON_TEXT_TOTAL_LIFETIME, + pixel_y = ICON_SIZE_Y * 1.2, + time = BALLOON_TEXT_TOTAL_LIFETIME(length_mult), easing = SINE_EASING | EASE_OUT, ) @@ -68,12 +73,14 @@ animate( alpha = 0, - time = BALLOON_TEXT_FULLY_VISIBLE_TIME, + time = BALLOON_TEXT_FULLY_VISIBLE_TIME * length_mult, easing = CUBIC_EASING | EASE_IN, ) - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(remove_image_from_client), balloon_alert, viewer_client), BALLOON_TEXT_TOTAL_LIFETIME) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(remove_image_from_client), balloon_alert, viewer_client), BALLOON_TEXT_TOTAL_LIFETIME(length_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 diff --git a/code/modules/games/cards.dm b/code/modules/games/cards.dm index 30cb16fa4f9..7542c7ad8e2 100644 --- a/code/modules/games/cards.dm +++ b/code/modules/games/cards.dm @@ -107,7 +107,7 @@ H.cards += P cards -= P H.update_icon() - balloon_alert_to_viewers("\The [user] draws a card.") + balloon_alert_to_viewers("draws a card") if(!length(cards)) qdel(src) @@ -151,7 +151,7 @@ H.cards += P cards -= P H.update_icon() - balloon_alert_to_viewers("\The [user] picks out a card.") + balloon_alert_to_viewers("picks out a card") if(!length(cards)) qdel(src) @@ -201,7 +201,7 @@ H.concealed = TRUE H.update_icon() user.do_attack_animation(src, null) - balloon_alert_to_viewers("\The [user] deals a card.") + balloon_alert_to_viewers("deals a card") H.throw_at(get_step(target,target.dir), 10, 1, user, FALSE) if(!length(cards)) qdel(src) @@ -245,7 +245,7 @@ cards -= P cards = newcards playsound(src.loc, 'sound/items/cards/cardshuffle.ogg', 100, 1, -4) - balloon_alert_to_viewers("\The [user] shuffles [src].") + balloon_alert_to_viewers("shuffling") /obj/item/pack name = "card pack" @@ -321,7 +321,7 @@ H.update_icon() src.update_icon() playsound(src, 'sound/items/cards/cardflip.ogg', 50, TRUE) - balloon_alert_to_viewers("\The [user] picks out a card.") + balloon_alert_to_viewers("picks out a card") if(deploy_in_front) H.forceMove(get_step(usr, usr.dir)) else @@ -352,7 +352,7 @@ else update_icon() playsound(src, 'sound/items/cards/cardflip.ogg', 50, TRUE) - balloon_alert_to_viewers("\The [user] [concealed ? "conceals" : "reveals"] their hand.") + balloon_alert_to_viewers("[concealed ? "conceals" : "reveals"] their hand.") /obj/item/hand/get_examine_text(mob/user, distance, is_adjacent, infix, suffix) . = ..() @@ -452,6 +452,6 @@ return D.cards = cards - balloon_alert_to_viewers("\The [user] turns his hand into a deck.") + user.visible_message(SPAN_NOTICE("\The [user] turns his hand into a deck."), SPAN_NOTICE("You turn your hand into a deck.")) qdel(src) user.put_in_hands(D) diff --git a/code/modules/games/tarot.dm b/code/modules/games/tarot.dm index b3bba9894b4..36a2c1eb441 100644 --- a/code/modules/games/tarot.dm +++ b/code/modules/games/tarot.dm @@ -26,7 +26,7 @@ P.back_icon = "card_back_tarot" cards += P -/obj/item/deck/tarot/AltClick(var/mob/user as mob) +/obj/item/deck/tarot/AltClick(mob/user) var/list/newcards = list() while(cards.len) var/datum/playingcard/P = pick(cards) @@ -37,7 +37,7 @@ cards -= P cards = newcards playsound(src.loc, 'sound/items/cards/cardshuffle.ogg', 100, 1, -4) - user.visible_message("\The [user] shuffles \the [src].") + balloon_alert_to_viewers("shuffling") /obj/item/deck/tarot/adhomai diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index a46a77c228d..6809333f45a 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -285,7 +285,7 @@ else if(needspin) to_chat(user, SPAN_WARNING("\The [src]'s trigger is locked. This weapon doesn't have a firing pin installed!")) - balloon_alert(user, "Trigger locked, firing pin needed!") + balloon_alert(user, "trigger locked, firing pin needed!") return FALSE else return TRUE @@ -705,7 +705,7 @@ safety_state = !safety_state update_icon() if(user) - balloon_alert(user, "Safety [safety_state ? "on" : "off"].") + balloon_alert(user, "safety [safety_state ? "on" : "off"].") if(!safety_state) playsound(src, safetyon_sound, 30, 1) else @@ -933,15 +933,15 @@ /obj/item/gun/attackby(obj/item/attacking_item, mob/user) if(istype(attacking_item, /obj/item/material/knife/bayonet)) if(!can_bayonet) - balloon_alert(user, "\the [attacking_item.name] doesn't fit") + balloon_alert(user, "doesn't fit!") return ..() if(bayonet) - balloon_alert(user, "\the [src] already has a bayonet") + balloon_alert(user, "already has a bayonet!") return TRUE if(user.l_hand != attacking_item && user.r_hand != attacking_item) - balloon_alert(user, "not in hand") + balloon_alert(user, "not in hand!") return user.drop_from_inventory(attacking_item,src) @@ -956,19 +956,19 @@ if(istype(attacking_item, /obj/item/ammo_display)) if(!can_ammo_display) - balloon_alert(user, "\the [attacking_item.name] doesn't fit") + balloon_alert(user, "doesn't fit!") return TRUE if(ammo_display) - balloon_alert(user, "\the [src] already has an ammo display") + balloon_alert(user, "already has an ammo display!") return TRUE if(user.l_hand != attacking_item && user.r_hand != attacking_item) - balloon_alert(user, "not in hand") + balloon_alert(user, "not in hand!") return if(displays_maptext) - balloon_alert(user, "\the [src] is already displaying its ammo count") + balloon_alert(user, "already displaying its ammo count!") return TRUE user.drop_from_inventory(attacking_item, src) diff --git a/code/modules/projectiles/guns/projectile.dm b/code/modules/projectiles/guns/projectile.dm index b8ab4791d77..10e2b62b80e 100644 --- a/code/modules/projectiles/guns/projectile.dm +++ b/code/modules/projectiles/guns/projectile.dm @@ -235,15 +235,15 @@ if(istype(attacking_item, /obj/item/suppressor)) var/obj/item/suppressor/S = attacking_item if(!can_suppress) - balloon_alert(user, "\the [S.name] doesn't fit") + balloon_alert(user, "doesn't fit!") return if(suppressed) - balloon_alert(user, "already has a suppressor") + balloon_alert(user, "already has a suppressor!") return if(user.l_hand != S && user.r_hand != S) - balloon_alert(user, "not in hand") + balloon_alert(user, "not in hand!") return user.drop_from_inventory(suppressor, src) diff --git a/code/modules/reagents/reagent_containers/food/drinks/bottle.dm b/code/modules/reagents/reagent_containers/food/drinks/bottle.dm index d2b0d3bc87a..fc15b2c7ee0 100644 --- a/code/modules/reagents/reagent_containers/food/drinks/bottle.dm +++ b/code/modules/reagents/reagent_containers/food/drinks/bottle.dm @@ -379,7 +379,7 @@ return if(is_open_container()) - balloon_alert(user, "the bottle was already open, you spill some on the floor...") + balloon_alert(user, "already open! you spill some on the floor!") if(reagents.total_volume) src.reagents.remove_any(reagents.total_volume / 5) return diff --git a/html/changelogs/GeneralCamo - Balloon Alert.yml b/html/changelogs/GeneralCamo - Balloon Alert.yml new file mode 100644 index 00000000000..e6e77d71643 --- /dev/null +++ b/html/changelogs/GeneralCamo - Balloon Alert.yml @@ -0,0 +1,60 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# - (fixes bugs) +# wip +# - (work in progress) +# qol +# - (quality of life) +# soundadd +# - (adds a sound) +# sounddel +# - (removes a sound) +# rscadd +# - (adds a feature) +# rscdel +# - (removes a feature) +# imageadd +# - (adds an image or sprite) +# imagedel +# - (removes an image or sprite) +# spellcheck +# - (fixes spelling or grammar) +# experiment +# - (experimental change) +# balance +# - (balance changes) +# code_imp +# - (misc internal code change) +# refactor +# - (refactors code) +# config +# - (makes a change to the config files) +# admin +# - (makes changes to administrator tools) +# server +# - (miscellaneous changes to server) +################################# + +# Your name. +author: GeneralCamo + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit. +# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog. +changes: + - rscadd: "Balloon alerts now change their duration on-screen depending on the length of them." + - qol: "Balloon alerts use a seperate plane that ignores lighting." + - qol: "Balloon alerts now use the standard established by tgstation, reducing their length and improving their readability."