From 8407cfbab1e49a68f248e50f6fb6602484cfcb43 Mon Sep 17 00:00:00 2001 From: Sun-Soaked <45698967+Sun-Soaked@users.noreply.github.com> Date: Thu, 18 Apr 2024 23:48:08 -0400 Subject: [PATCH] Cogbar Port (#2899) ## About The Pull Request Do_afters have no visual feedback for nearby people, which is bad (and leads to a lot of unintentional interruptions) This adds a visual indicator in the form of a spinning cog that displays to nearby players while you do a Do_after() Ports [This Guy](https://github.com/tgstation/tgstation/pull/82416) and assorted. Thanks @jlsnow301 (plus some assorted stuff) Implements it on do_mob()'s(which tg rightfully decided to kill.) Some of our equip handling code makes me want to explode, but that's a problem for another day ## Why It's Good For The Game Action feedback 4 nearby players, less accidental tileswaps ## Changelog :cl: jlsnow301, sun-soaked add: do_afters and do_mob actions now show nearby players a spinning cog while in progress. fix: the progressbar.dmm file is no longer misspelled "progess"bar /:cl: --------- Co-authored-by: Sun-Soaked <45698967+MemedHams@users.noreply.github.com> --- code/__DEFINES/layers.dm | 3 + code/__HELPERS/mobs.dm | 15 ++- code/datums/cogbar.dm | 88 ++++++++++++++++++ code/datums/progressbar.dm | 2 +- .../structures/beds_chairs/alien_nest.dm | 2 +- code/game/objects/structures/kitchen_spike.dm | 2 +- .../nukeop/equipment/borgchameleon.dm | 2 +- .../nukeop/equipment/nuclearbomb.dm | 2 +- .../components/unary_devices/cryo.dm | 2 +- code/modules/clothing/shoes/_shoes.dm | 2 +- code/modules/mob/living/carbon/carbon.dm | 2 +- code/modules/mob/living/carbon/human/human.dm | 2 +- code/modules/ninja/suit/ninjaDrainAct.dm | 16 ++-- icons/effects/progessbar.dmi | Bin 1013 -> 0 bytes icons/effects/progressbar.dmi | Bin 0 -> 1246 bytes shiptest.dme | 1 + tgui/packages/tgui/interfaces/Cloner.js | 2 +- 17 files changed, 122 insertions(+), 21 deletions(-) create mode 100644 code/datums/cogbar.dm delete mode 100644 icons/effects/progessbar.dmi create mode 100644 icons/effects/progressbar.dmi diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm index fd61f4f1123b..6f76dae9769f 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers.dm @@ -130,6 +130,9 @@ #define CAMERA_STATIC_LAYER 19 #define CAMERA_STATIC_RENDER_TARGET "CAMERA_STATIC_PLANE" +///Wants to be part of the game plane, but also wants to draw above literally everything else +#define HIGH_GAME_PLANE 30 + //HUD layer defines #define FULLSCREEN_PLANE 31 diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index f307aa952804..81ba9ec06dd2 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -242,7 +242,7 @@ GLOBAL_LIST_EMPTY(species_list) return "unknown" ///Timed action involving two mobs, the user and the target. -/proc/do_mob(mob/user , mob/target, time = 3 SECONDS, uninterruptible = FALSE, progress = TRUE, datum/callback/extra_checks = null, ignore_loc_change = FALSE) +/proc/do_mob(mob/user , mob/target, time = 3 SECONDS, uninterruptible = FALSE, progress = TRUE, datum/callback/extra_checks = null, ignore_loc_change = FALSE, hidden = FALSE) if(!user || !target) return FALSE @@ -262,8 +262,11 @@ GLOBAL_LIST_EMPTY(species_list) LAZYADD(target.targeted_by, user) var/holding = user.get_active_held_item() var/datum/progressbar/progbar + var/datum/cogbar/cog if (progress) progbar = new(user, time, target) + if(!hidden && time >= 1 SECONDS) + cog = new(user) var/endtime = world.time+time var/starttime = world.time @@ -292,6 +295,8 @@ GLOBAL_LIST_EMPTY(species_list) break if(!QDELETED(progbar)) progbar.end_progress() + + cog?.remove() if(!QDELETED(target)) LAZYREMOVE(user.do_afters, target) LAZYREMOVE(target.targeted_by, user) @@ -311,7 +316,7 @@ GLOBAL_LIST_EMPTY(species_list) return ..() ///Timed action involving one mob user. Target is optional. -/proc/do_after(mob/user, delay, needhand = TRUE, atom/target = null, progress = TRUE, datum/callback/extra_checks = null) +/proc/do_after(mob/user, delay, needhand = TRUE, atom/target = null, progress = TRUE, datum/callback/extra_checks = null, hidden = FALSE) if(!user) return FALSE @@ -342,9 +347,11 @@ GLOBAL_LIST_EMPTY(species_list) delay *= user.do_after_coefficent() var/datum/progressbar/progbar + var/datum/cogbar/cog if(progress) progbar = new(user, delay, target || user) - + if(!hidden && delay >= 1 SECONDS) + cog = new(user) var/endtime = world.time + delay var/starttime = world.time . = TRUE @@ -389,6 +396,8 @@ GLOBAL_LIST_EMPTY(species_list) if(!QDELETED(progbar)) progbar.end_progress() + cog?.remove() + if(!QDELETED(target)) LAZYREMOVE(user.do_afters, target) LAZYREMOVE(target.targeted_by, user) diff --git a/code/datums/cogbar.dm b/code/datums/cogbar.dm new file mode 100644 index 000000000000..c03daa33a6ab --- /dev/null +++ b/code/datums/cogbar.dm @@ -0,0 +1,88 @@ +#define COGBAR_ANIMATION_TIME (0.5 SECONDS) + +/** + * ### Cogbar + * Represents that the user is busy doing something. + */ +/datum/cogbar + /// Who's doing the thing + var/mob/user + /// The user client + var/client/user_client + /// The visible element to other players + var/obj/effect/overlay/vis/cog + /// The blank image that overlaps the cog - hides it from the source user + var/image/blank + /// The offset of the icon + //var/offset_y + + +/datum/cogbar/New(mob/user) + src.user = user + src.user_client = user.client + +//Porting oversized icon offsets later, they have too many other unported dependencies. sorry zephyr + //var/list/icon_offsets = user.get_oversized_icon_offsets() + //offset_y = icon_offsets["y"] + + add_cog_to_user() + + RegisterSignal(user, COMSIG_PARENT_QDELETING, PROC_REF(on_user_delete)) + + +/datum/cogbar/Destroy() + if(user) + SSvis_overlays.remove_vis_overlay(user, user.managed_vis_overlays) + user_client?.images -= blank + + user = null + user_client = null + cog = null + QDEL_NULL(blank) + + return ..() + + +/// Adds the cog to the user, visible by other players +/datum/cogbar/proc/add_cog_to_user() + cog = SSvis_overlays.add_vis_overlay(user, + icon = 'icons/effects/progressbar.dmi', + iconstate = "cog", + plane = HIGH_GAME_PLANE, + add_appearance_flags = APPEARANCE_UI_IGNORE_ALPHA, + unique = TRUE, + alpha = 0, + ) + cog.pixel_y = world.icon_size// + offset_y + animate(cog, alpha = 255, time = COGBAR_ANIMATION_TIME) + + if(isnull(user_client)) + return + + blank = image('icons/blanks/32x32.dmi', cog, "nothing") + blank.plane = HIGH_GAME_PLANE + blank.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA + blank.override = TRUE + + user_client.images += blank + + +/// Removes the cog from the user +/datum/cogbar/proc/remove() + if(isnull(cog)) + qdel(src) + return + + animate(cog, alpha = 0, time = COGBAR_ANIMATION_TIME) + + QDEL_IN(src, COGBAR_ANIMATION_TIME) + + +/// When the user is deleted, remove the cog +/datum/cogbar/proc/on_user_delete(datum/source) + SIGNAL_HANDLER + + qdel(src) + + +#undef COGBAR_ANIMATION_TIME diff --git a/code/datums/progressbar.dm b/code/datums/progressbar.dm index 25621a613eeb..7134d2e8ecef 100644 --- a/code/datums/progressbar.dm +++ b/code/datums/progressbar.dm @@ -32,7 +32,7 @@ return goal = goal_number bar_loc = target - bar = image('icons/effects/progessbar.dmi', bar_loc, "prog_bar_0", HUD_LAYER) + bar = image('icons/effects/progressbar.dmi', bar_loc, "prog_bar_0", HUD_LAYER) bar.plane = ABOVE_HUD_PLANE bar.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA user = User diff --git a/code/game/objects/structures/beds_chairs/alien_nest.dm b/code/game/objects/structures/beds_chairs/alien_nest.dm index 532b4385f2cf..4f132b11af99 100644 --- a/code/game/objects/structures/beds_chairs/alien_nest.dm +++ b/code/game/objects/structures/beds_chairs/alien_nest.dm @@ -34,7 +34,7 @@ M.visible_message("[M.name] struggles to break free from the gelatinous resin!",\ "You struggle to break free from the gelatinous resin... (Stay still for two minutes.)",\ "You hear squelching...") - if(!do_after(M, 1200, target = src)) + if(!do_after(M, 1200, target = src, hidden = TRUE)) if(M && M.buckled) to_chat(M, "You fail to unbuckle yourself!") return diff --git a/code/game/objects/structures/kitchen_spike.dm b/code/game/objects/structures/kitchen_spike.dm index 65479f171334..d863b693604f 100644 --- a/code/game/objects/structures/kitchen_spike.dm +++ b/code/game/objects/structures/kitchen_spike.dm @@ -112,7 +112,7 @@ "You struggle to break free from [src], exacerbating your wounds! (Stay still for two minutes.)",\ "You hear a wet squishing noise..") M.adjustBruteLoss(30) - if(!do_after(M, 1200, target = src)) + if(!do_after(M, 1200, target = src, hidden = TRUE)) if(M && M.buckled) to_chat(M, "You fail to free yourself!") return diff --git a/code/modules/antagonists/nukeop/equipment/borgchameleon.dm b/code/modules/antagonists/nukeop/equipment/borgchameleon.dm index ddc895060b0c..17cd8fd99bff 100644 --- a/code/modules/antagonists/nukeop/equipment/borgchameleon.dm +++ b/code/modules/antagonists/nukeop/equipment/borgchameleon.dm @@ -65,7 +65,7 @@ to_chat(user, "You activate \the [src].") playsound(src, 'sound/effects/seedling_chargeup.ogg', 100, TRUE, -6) apply_wibbly_filters(user) - if (do_after(user, 50, target=user) && user.cell.use(activationCost)) + if (do_after(user, 50, target=user, hidden = TRUE) && user.cell.use(activationCost)) playsound(src, 'sound/effects/bamf.ogg', 100, TRUE, -6) to_chat(user, "You are now disguised as the Nanotrasen engineering borg \"[friendlyName]\".") activate(user) diff --git a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm index d0019eb19cc2..f3d6bb31abf4 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm @@ -126,7 +126,7 @@ if(istype(I, /obj/item/nuke_core_container)) var/obj/item/nuke_core_container/core_box = I to_chat(user, "You start loading the plutonium core into [core_box]...") - if(do_after(user,50,target=src)) + if(do_after(user,50,target=src, hidden = TRUE)) if(core_box.load(core, user)) to_chat(user, "You load the plutonium core into [core_box].") deconstruction_state = NUKESTATE_CORE_REMOVED diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm index 8f547335e9e0..3705cb361d82 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm @@ -273,7 +273,7 @@ user.visible_message("You see [user] kicking against the glass of [src]!", \ "You struggle inside [src], kicking the release with your foot... (this will take about [DisplayTimeText(breakout_time)].)", \ "You hear a thump from [src].") - if(do_after(user, breakout_time, target = src)) + if(do_after(user, breakout_time, target = src, hidden = TRUE)) if(!user || user.stat != CONSCIOUS || user.loc != src) return user.visible_message("[user] successfully broke out of [src]!", \ diff --git a/code/modules/clothing/shoes/_shoes.dm b/code/modules/clothing/shoes/_shoes.dm index 7b2ded27e269..1b5f0ae58fae 100644 --- a/code/modules/clothing/shoes/_shoes.dm +++ b/code/modules/clothing/shoes/_shoes.dm @@ -157,7 +157,7 @@ if(HAS_TRAIT(user, TRAIT_CLUMSY)) // based clowns trained their whole lives for this mod_time *= 0.75 - if(do_after(user, mod_time, needhand=TRUE, target=our_guy, extra_checks=CALLBACK(src, PROC_REF(still_shoed), our_guy))) + if(do_after(user, mod_time, needhand=TRUE, target=our_guy, extra_checks=CALLBACK(src, PROC_REF(still_shoed), our_guy), hidden = TRUE)) to_chat(user, "You [tied ? "untie" : "knot"] the laces on [loc]'s [src.name].") if(tied == SHOES_UNTIED) adjust_laces(SHOES_KNOTTED, user) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 5b316dad9cb6..36fd8e1e6704 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -255,7 +255,7 @@ buckle_cd = O.breakouttime visible_message("[src] attempts to unbuckle [p_them()]self!", \ "You attempt to unbuckle yourself... (This will take around [round(buckle_cd/600,1)] minute\s, and you need to stay still.)") - if(do_after(src, buckle_cd, 0, target = src)) + if(do_after(src, buckle_cd, 0, target = src, hidden = TRUE)) if(!buckled) return buckled.user_unbuckle_mob(src,src) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index ecad7982b83a..292047676575 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -247,7 +247,7 @@ else return - if(do_mob(usr, src, POCKET_STRIP_DELAY/delay_denominator)) //placing an item into the pocket is 4 times faster + if(do_mob(usr, src, POCKET_STRIP_DELAY/delay_denominator, hidden = TRUE)) //placing an item into the pocket is 4 times faster if(pocket_item) if(pocket_item == (pocket_id == ITEM_SLOT_RPOCKET ? r_store : l_store)) //item still in the pocket we search dropItemToGround(pocket_item) diff --git a/code/modules/ninja/suit/ninjaDrainAct.dm b/code/modules/ninja/suit/ninjaDrainAct.dm index 2e3dac4fddbe..4939686ee9fd 100644 --- a/code/modules/ninja/suit/ninjaDrainAct.dm +++ b/code/modules/ninja/suit/ninjaDrainAct.dm @@ -41,7 +41,7 @@ They *could* go in their appropriate files, but this is supposed to be modular drain = S.cell.maxcharge - S.cell.charge maxcapacity = 1//Reached maximum battery capacity. - if (do_after(H,10, target = src)) + if (do_after(H,10, target = src, hidden = TRUE)) spark_system.start() playsound(loc, "sparks", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) cell.use(drain) @@ -85,7 +85,7 @@ They *could* go in their appropriate files, but this is supposed to be modular drain = S.cell.maxcharge - S.cell.charge maxcapacity = 1 - if (do_after(H,10, target = src)) + if (do_after(H,10, target = src, hidden = TRUE)) spark_system.start() playsound(loc, "sparks", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) charge -= drain @@ -104,7 +104,7 @@ They *could* go in their appropriate files, but this is supposed to be modular . = 0 if(charge) - if(G.candrain && do_after(H,30, target = src)) + if(G.candrain && do_after(H,30, target = src, hidden = TRUE)) . = charge if(S.cell.charge + charge > S.cell.maxcharge) S.cell.charge = S.cell.maxcharge @@ -131,7 +131,7 @@ They *could* go in their appropriate files, but this is supposed to be modular if(stored_research) to_chat(H, "Copying files...") - if(do_after(H, S.s_delay, target = src) && G.candrain && src) + if(do_after(H, S.s_delay, target = src, hidden = TRUE) && G.candrain && src) stored_research.copy_research_to(S.stored_research) to_chat(H, "Data analyzed. Process finished.") @@ -148,7 +148,7 @@ They *could* go in their appropriate files, but this is supposed to be modular if(stored_research) to_chat(H, "Copying files...") - if(do_after(H, S.s_delay, target = src) && G.candrain && src) + if(do_after(H, S.s_delay, target = src, hidden = TRUE) && G.candrain && src) stored_research.copy_research_to(S.stored_research) to_chat(H, "Data analyzed. Process finished.") @@ -167,7 +167,7 @@ They *could* go in their appropriate files, but this is supposed to be modular while(G.candrain && !maxcapacity && src) drain = (round((rand(G.mindrain, G.maxdrain))/2)) var/drained = 0 - if(PN && do_after(H,10, target = src)) + if(PN && do_after(H,10, target = src, hidden = TRUE)) drained = min(drain, delayed_surplus()) add_delayedload(drained) if(drained < drain)//if no power on net, drain apcs @@ -207,7 +207,7 @@ They *could* go in their appropriate files, but this is supposed to be modular if(S.cell.charge + drain > S.cell.maxcharge) drain = S.cell.maxcharge - S.cell.charge maxcapacity = 1 - if (do_after(H,10, target = src)) + if (do_after(H,10, target = src, hidden = TRUE)) spark_system.start() playsound(loc, "sparks", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) cell.use(drain) @@ -235,7 +235,7 @@ They *could* go in their appropriate files, but this is supposed to be modular if(S.cell.charge+drain > S.cell.maxcharge) drain = S.cell.maxcharge - S.cell.charge maxcapacity = 1 - if (do_after(H,10)) + if (do_after(H,10, hidden = TRUE)) spark_system.start() playsound(loc, "sparks", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) cell.use(drain) diff --git a/icons/effects/progessbar.dmi b/icons/effects/progessbar.dmi deleted file mode 100644 index f055a07ba1492a36912ed6b9fdbf1b8e278e4864..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1013 zcmV{hG&VIm%m6bYAt(O;Gt6c)|CuuY%rgN0Gc#uYW|{wws`2W@R{!XX_Jw>-00001 zbW%=J06^y0W&i*H`+8JZbVOxyV{&P5bZKvH004NLt=78=!Y~vD;JJBzP}a&<)8%MEhWm?j3)Zra)=6xBl?EerTz7 z2YY{}C!ZDnI3odCOJc@_05D+)6(Cd$p#p@8A=H3SGlUutYKG7NLc!i*uz0b$M%=72C~2n#@1FoXplEEvKP5S9#K2?$Hhi~pB6mdowp z_0xF(AJ~Na{wENT0007PNklv0t6x9nR}0$u{oB{)U_tBr^7Wp8-tS=Ve1xxX z-y8q{0001B9=)5H{`uJ5-8Y;M*c?^b)l|-F?d&Gl;Cg;4=6BBDl=2j8a8{3Rk1G9o zF6Xs=ej99XJwF%oJLhjpc@8#MJOQU0F!(#_e897F000000DyV)Zf5%DV|RB0{QrPW zP`^g)YbxY-&)>v(3N~n&zdH%r;k*0yZ6VJ=0slz9|8;|Kevb3n{QXIMK4A7IVDNX; z`G9BV00000008so-OTjQ$L{XF;e0>}>emO`*IksSV1q~J?<(_C^Zc{^J+JNG_fejM z4IZ7puguTQ^F0B*-@)Gb2w&m8IRF3v006)|dN(uu^Rc_TZ#W;Y3+mTm`9QR@@89>8{ynek_dho%&(F>C-!4?<=d1Gpvp)fYzoX6vJUa&f00000 zm`Cqsrhh(mcQ?TA3tYCZhf4dJR<^qz8{C|q*3Lh){l36u|Nd6#-}B0T|6_xj^YhyI zZ*9LX@Y|n&!QWBm1D>4&000000L)|d=H>a_+u)-1H8r)b{{qWTx&hbydv5CA{|A25 j4Ve82nEe|t^Iw5?ZsBHuRElq(00000NkvXXu0mjf6jA0r diff --git a/icons/effects/progressbar.dmi b/icons/effects/progressbar.dmi new file mode 100644 index 0000000000000000000000000000000000000000..3eed14db704a76ab77d9ea02c39e290c85e428c1 GIT binary patch literal 1246 zcmZvadr(pd6vi(w$y%X1uCAmFW;==Y&=kuax@5vCYHI4HlNPsH35(1W^Mx0BnCosE zX>2PgQZ|*gDLrUd#}=uSMi!-aPOQ;GMM@q?hIoa$*iL`#o`1eG-<+btJbRl(&9iO0+7@U z5+Wo4Y7&5uNDPD_L|kLH?rQ1CLq>j4@!-z^zHU1D$ksFbY)ZGB&=v9^ks`A0i;~yxke+Y6 z(_1>GefvY4PZ%W=UYRVa{qYPKX7WK+Y&!Jt@-=5PoxHE@;O@#wwq(?esA#Tl*y_G$ ziGYR*q6)pibO8+$v`H8VJ{0r;L2<(QV1yuqIEG;(7r9 zL!nV(Gs~KcL&g)0E5EFMwY)@>+FM{ocKRp#t=^&h3VW!1q)Pf$jEMtr?d-H0+Swa@ zDwgUuW>Ps3FPk#hO~1oS#*`=#X`&NezvD=YUFl32JPSi8XrA2D^4+(k+%Q&Jq;60* z&!2sT_Z}Sy@k5>SnJ+_fqp+WOgD0N%Cp&H#O&!%X%yr`)713XCv&-%fU5zzxsu0<< zEw{UQqR%bQ0YS64b#$HBCk-ZC5y>px9gVY3^QlImYqr zYZPpGhBZoWzWKL1w(Rmf&)Nr)${5+S{YW9tz>$pZA0RV3eLe19Lo4UqpNdhzs3iSo zB%s~gC2SMRhK5#I5bSvM^!Iz{qWbO_ZkRr0&4#|2Hwmm7ok{1JXsSj#PeBNb>alMh zXt!Ugn}HNhvo^f31)H(UMgJc$rIk)*(fR47qZrOQgsCp=wTh=p$ucgP=E`F+%$y3> z`D%90c`V27)vt)IemDBxSnU=_vALE0js!i4|P90KFGWc=f+ zNBq+@u$vNa0QUEj+sxAFVJkR{==G-)wgn<6iE>WGu!;xbTHBGaa5p1H8QARz6oX { beakerContents={data.beakerContents} /> -
+