From 2710120acd7d190d421077fbdf00466d705fbbc2 Mon Sep 17 00:00:00 2001 From: NovaBot <154629622+NovaBot13@users.noreply.github.com> Date: Thu, 4 Apr 2024 09:26:26 -0400 Subject: [PATCH] [MIRROR] Adds a visual effect to breathing in cold environments (#1803) * Adds a visual effect to breathing in cold environments (#82336) ## About The Pull Request Humans (who breathe) (with lungs) now has a particle associated when breathing in cold air. The colder the air, the more likely the particle to occur per breath. https://github.com/tgstation/tgstation/assets/51863163/f375dd1b-87f6-4124-9329-4714fe988c16 Other changes: - Adjusts the probability of getting "your lungs feel cold/hot" when breathing cold/hot air depending on how cold/hot the air is. - Very cold air now has a chance of causing humans to shiver when they breathe it in. ## Why It's Good For The Game Some nice VFX to breathe some style into the game. ## Changelog :cl: Melbert qol: Breathing cold air now has a particle effect associated, careful not to let your glasses fog up. qol: Breathing cold air will now occasionally make your spaceman shiver. Brrr. /:cl: * Adds a visual effect to breathing in cold environments --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> --- code/game/objects/effects/particles/smoke.dm | 13 ++++ .../surgery/organs/internal/lungs/_lungs.dm | 70 ++++++++++++++++-- icons/effects/particles/smoke.dmi | Bin 480 -> 1274 bytes 3 files changed, 75 insertions(+), 8 deletions(-) diff --git a/code/game/objects/effects/particles/smoke.dm b/code/game/objects/effects/particles/smoke.dm index 4f31ffc0869..b41b4eb1d96 100644 --- a/code/game/objects/effects/particles/smoke.dm +++ b/code/game/objects/effects/particles/smoke.dm @@ -46,3 +46,16 @@ fadein = 0.7 SECONDS position = generator(GEN_VECTOR, list(-3, 5, 0), list(3, 6.5, 0), NORMAL_RAND) velocity = generator(GEN_VECTOR, list(-0.1, 0.4, 0), list(0.1, 0.5, 0), NORMAL_RAND) + +/particles/fog + icon = 'icons/effects/particles/smoke.dmi' + icon_state = list("chill_1" = 2, "chill_2" = 2, "chill_3" = 1) + +/particles/fog/breath + count = 1 + spawning = 1 + lifespan = 1 SECONDS + fade = 0.5 SECONDS + grow = 0.05 + spin = 2 + color = "#fcffff77" diff --git a/code/modules/surgery/organs/internal/lungs/_lungs.dm b/code/modules/surgery/organs/internal/lungs/_lungs.dm index 1db1963e8d6..8bba59d7987 100644 --- a/code/modules/surgery/organs/internal/lungs/_lungs.dm +++ b/code/modules/surgery/organs/internal/lungs/_lungs.dm @@ -754,31 +754,85 @@ if(!HAS_TRAIT(breather, TRAIT_RESISTCOLD)) // COLD DAMAGE var/cold_modifier = breather.dna.species.coldmod + var/breath_effect_prob = 0 if(breath_temperature < cold_level_3_threshold) - breather.apply_damage(cold_level_3_damage*cold_modifier, cold_damage_type, spread_damage = TRUE) + breather.apply_damage(cold_level_3_damage * cold_modifier, cold_damage_type, spread_damage = TRUE) + breath_effect_prob = 100 if(breath_temperature > cold_level_3_threshold && breath_temperature < cold_level_2_threshold) - breather.apply_damage(cold_level_2_damage*cold_modifier, cold_damage_type, spread_damage = TRUE) + breather.apply_damage(cold_level_2_damage * cold_modifier, cold_damage_type, spread_damage = TRUE) + breath_effect_prob = 50 if(breath_temperature > cold_level_2_threshold && breath_temperature < cold_level_1_threshold) - breather.apply_damage(cold_level_1_damage*cold_modifier, cold_damage_type, spread_damage = TRUE) + breather.apply_damage(cold_level_1_damage * cold_modifier, cold_damage_type, spread_damage = TRUE) + breath_effect_prob = 25 if(breath_temperature < cold_level_1_threshold) - if(prob(20)) + if(prob(sqrt(breath_effect_prob) * 4)) to_chat(breather, span_warning("You feel [cold_message] in your [name]!")) + if(prob(50)) + breather.emote("shiver") + if(prob(breath_effect_prob)) + // Breathing into your mask, no particle. We can add fogged up glasses later + if(breather.is_mouth_covered()) + return + // Even though breathing via internals TECHNICALLY exhales into the environment, we'll still block it + if(breather.internal || breather.external) + return + emit_breath_particle(breather, /particles/fog/breath) if(!HAS_TRAIT(breather, TRAIT_RESISTHEAT)) // HEAT DAMAGE var/heat_modifier = breather.dna.species.heatmod + var/heat_message_prob = 0 if(breath_temperature > heat_level_1_threshold && breath_temperature < heat_level_2_threshold) - breather.apply_damage(heat_level_1_damage*heat_modifier, heat_damage_type, spread_damage = TRUE) + breather.apply_damage(heat_level_1_damage * heat_modifier, heat_damage_type, spread_damage = TRUE) + heat_message_prob = 100 if(breath_temperature > heat_level_2_threshold && breath_temperature < heat_level_3_threshold) - breather.apply_damage(heat_level_2_damage*heat_modifier, heat_damage_type, spread_damage = TRUE) + breather.apply_damage(heat_level_2_damage * heat_modifier, heat_damage_type, spread_damage = TRUE) + heat_message_prob = 50 if(breath_temperature > heat_level_3_threshold) - breather.apply_damage(heat_level_3_damage*heat_modifier, heat_damage_type, spread_damage = TRUE) + breather.apply_damage(heat_level_3_damage * heat_modifier, heat_damage_type, spread_damage = TRUE) + heat_message_prob = 25 if(breath_temperature > heat_level_1_threshold) - if(prob(20)) + if(prob(sqrt(heat_message_prob) * 4)) to_chat(breather, span_warning("You feel [hot_message] in your [name]!")) // The air you breathe out should match your body temperature breath.temperature = breather.bodytemperature +/// Creates a particle effect off the mouth of the passed mob. +/obj/item/organ/internal/lungs/proc/emit_breath_particle(mob/living/carbon/human/breather, particle_type) + ASSERT(ispath(particle_type, /particles)) + + var/obj/effect/abstract/particle_holder/holder = new(breather, particle_type) + var/particles/breath_particle = holder.particles + var/breath_dir = breather.dir + + var/list/particle_grav = list(0, 0.1, 0) + var/list/particle_pos = list(0, breather.get_mob_height() + 2, 0) + if(breath_dir & NORTH) + particle_grav[2] = 0.2 + breath_particle.rotation = pick(-45, 45) + // Layer it behind the mob since we're facing away from the camera + holder.pixel_w -= 4 + holder.pixel_y += 4 + if(breath_dir & WEST) + particle_grav[1] = -0.2 + particle_pos[1] = -5 + breath_particle.rotation = -45 + if(breath_dir & EAST) + particle_grav[1] = 0.2 + particle_pos[1] = 5 + breath_particle.rotation = 45 + if(breath_dir & SOUTH) + particle_grav[2] = 0.2 + breath_particle.rotation = pick(-45, 45) + // Shouldn't be necessary but just for parity + holder.pixel_w += 4 + holder.pixel_y -= 4 + + breath_particle.gravity = particle_grav + breath_particle.position = particle_pos + + QDEL_IN(holder, breath_particle.lifespan) + /obj/item/organ/internal/lungs/on_life(seconds_per_tick, times_fired) . = ..() if(failed && !(organ_flags & ORGAN_FAILING)) diff --git a/icons/effects/particles/smoke.dmi b/icons/effects/particles/smoke.dmi index 4a3239499b965b8b35f854eb90d216983f5e78f2..99123beeb59a98ff228d7857a35e2cc07c803d11 100644 GIT binary patch literal 1274 zcmeAS@N?(olHy`uVBq!ia0vp^4M3d0!3HF+R#kZdsYO*G5hX6E#mPmP1tppJc?=8{ zb9&DjavgFIXnk1qUBvlPw`b1wi7Ypjb~f>(m56O-Gir{zpJeT5bhrA$;qb$iJC1Pv zGW=zpJL#G@i-m08z1mA_co=tGvtITkLDyYms)B=RW$mS{EBDO4tR}GF-onme|UzAjU`OBhgr(aQ0*Tp zpIYzRzUIOUSNl5~J!BOV-yDyXa+2DomL~k_!k)8BH+-2><@ceo?s9JX?|t9*>@R-z zbkg^dr1W(5rs>feg#`*HGCc8MC{kgt6l##+bm(JIaA%sJ%y^`FF&Ig4-K{ffV45kU0|%j>_%F+BM9X0NwV zPt#@wv)?%aZ;CnElK z1q@~%UjMdg!wl2OfmUfUmsEsu2A^X08!NV0k1Du6X4a0Czz;k+;Z7#?Tz zryY-Mh}m~x^RgqYKX*Q0-S8;7yM*~g>$!*ZH{=h#6ie9qlKXRU#lJTz!|QkX*JSsa zZ8|&YztnBz1)J&`&juNv`o|J~Uv$rR_kt+KvhUv}>Nc!p0XqEj%Q=}Q(cvl_uHQd! z*zd1D{BgcfTuEB<_T~B0W*rdwP_**@-N|o-mls#sGDk2n?3eo*c=FgL8N1qlLOT04 z?%Bju^5{)}!S-u%GW%bgv6_GU=X!?OrSt9TIiqS8+~?lEd%Jx{_R;dU6U!I=didAn z`v;9%_ZUuVuV!dCzW;p%=ZiaXcECWh{BixMfO4JBv90z^-`Ex0^_!qc21kexCH(lR zw8UoHCN&);s>oWrl5KV}4mhv1**w>PJ-E1Jx0ei!w8fwbzr*zKj6yZf4h zvm=&9z0RFB%OYNjnL%y)t!A;86MQFicXu~;ue<)*&p1J5qx13ePr0+NP34XGC;IV{ zPvH`qIpGbvx0(S}YuNv4{Jhji>$Uj0R~+6l-%`X3p;BwYEEfSz@ib z+>7(aB#v&c&PywwvcU32*JcCz=Tn=*t1Gs-+q!*BPIm23OfcK$&v#3{L1r(95^|=) d7F2&&-A|wC|9+xj5wI|0@O1TaS?83{1OOfFDZ*Bkpc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5fFwryM;w;ZhDainGjE%TB zGg33tGfE(w;*!LYR3KBSI5$5#HQrE(i!&v&s2C_>$i` ziMhns3sy&jy;XV9i(+p8ye)S3FWG`2A^e}a%iZ}C zf?>Xk)GJ0&qt?v^4P(HN4g<0=1s1lhno89aprv!9P-8$jGN6scf