diff --git a/code/__DEFINES/atmospherics/atmos_core.dm b/code/__DEFINES/atmospherics/atmos_core.dm index 383e34f5c83..be8bae4cc11 100644 --- a/code/__DEFINES/atmospherics/atmos_core.dm +++ b/code/__DEFINES/atmospherics/atmos_core.dm @@ -131,8 +131,6 @@ #define FIRE_MINIMUM_TEMPERATURE_TO_SPREAD (150+T0C) ///Minimum temperature for fire to exist on a turf (100 °C or 373 K) #define FIRE_MINIMUM_TEMPERATURE_TO_EXIST (100+T0C) -///Minimum temperature for items on fire -#define BURNING_ITEM_MINIMUM_TEMPERATURE (150+T0C) ///Multiplier for the temperature shared to other turfs #define FIRE_SPREAD_RADIOSITY_SCALE 0.85 ///Helper for small fires to grow diff --git a/code/__DEFINES/atmospherics/atmos_mob_interaction.dm b/code/__DEFINES/atmospherics/atmos_mob_interaction.dm index 0472bc96bfd..084a8ba8654 100644 --- a/code/__DEFINES/atmospherics/atmos_mob_interaction.dm +++ b/code/__DEFINES/atmospherics/atmos_mob_interaction.dm @@ -144,3 +144,6 @@ #define SHOES_MIN_TEMP_PROTECT 2.0 /// For gloves #define SHOES_MAX_TEMP_PROTECT 1500 + +///Minimum temperature for items on fire +#define BURNING_ITEM_MINIMUM_TEMPERATURE (150+T0C) diff --git a/code/__DEFINES/sound.dm b/code/__DEFINES/sound.dm index f45c31f72dc..8a7a2708973 100644 --- a/code/__DEFINES/sound.dm +++ b/code/__DEFINES/sound.dm @@ -147,6 +147,7 @@ GLOBAL_LIST_INIT(announcer_keys, list( #define SFX_EXPLOSION_CREAKING "explosion_creaking" #define SFX_HISS "hiss" #define SFX_HONKBOT_E "honkbot_e" +#define SFX_GOOSE "goose" #define SFX_HULL_CREAKING "hull_creaking" #define SFX_HYPERTORUS_CALM "hypertorus_calm" #define SFX_HYPERTORUS_MELTING "hypertorus_melting" @@ -168,3 +169,4 @@ GLOBAL_LIST_INIT(announcer_keys, list( #define SFX_CRUNCHY_BUSH_WHACK "crunchy_bush_whack" #define SFX_TREE_CHOP "tree_chop" #define SFX_ROCK_TAP "rock_tap" +#define SFX_SEAR "sear" diff --git a/code/datums/components/acid.dm b/code/datums/components/acid.dm index 89430ff368e..61a72d93d18 100644 --- a/code/datums/components/acid.dm +++ b/code/datums/components/acid.dm @@ -15,43 +15,45 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e var/acid_volume /// The maximum volume of acid on the parent [/atom]. var/max_volume = INFINITY - /// Acid overlay appearance we apply - var/acid_overlay - /// The ambiant sound of acid eating away at the parent [/atom]. - var/datum/looping_sound/acid/sizzle /// Used exclusively for melting turfs. TODO: Move integrity to the atom level so that this can be dealt with there. var/parent_integrity = 30 /// How far the acid melting of turfs has progressed var/stage = 0 + /// Acid overlay appearance we apply + var/acid_overlay + /// The ambient sound of acid eating away at the parent [/atom]. + var/datum/looping_sound/acid/sizzle + /// Particle holder for acid particles (sick) + var/obj/effect/abstract/particle_holder/particle_effect /// The proc used to handle the parent [/atom] when processing. TODO: Unify damage and resistance flags so that this doesn't need to exist! var/datum/callback/process_effect -/datum/component/acid/Initialize(acid_power = ACID_POWER_MELT_TURF, acid_volume = 50, acid_overlay = GLOB.acid_overlay) +/datum/component/acid/Initialize(acid_power = ACID_POWER_MELT_TURF, acid_volume = 50, acid_overlay = GLOB.acid_overlay, acid_particles = /particles/acid) if(!isatom(parent)) return COMPONENT_INCOMPATIBLE - //not incompatible, but pointless + + // The parent object cannot have acid. Not incompatible, but should not really happen. var/atom/atom_parent = parent - if((acid_power) <= 0 || (acid_volume <= 0)) - stack_trace("Acid component added to an atom ([atom_parent.type]) with insufficient acid power ([acid_power]) or acid volume ([acid_volume]).") + if(atom_parent.resistance_flags & UNACIDABLE) qdel(src) return + //Not incompatible, but pointless + if((acid_power <= 0) || (acid_volume <= 0)) + qdel(src) + stack_trace("Tried to add /datum/component/acid to an atom ([atom_parent.type]) with insufficient acid power ([acid_power]) or acid volume ([acid_volume]).") + return if(isliving(parent)) - max_volume = MOB_ACID_VOLUME_MAX - process_effect = CALLBACK(src, PROC_REF(process_mob), parent) + src.max_volume = MOB_ACID_VOLUME_MAX + src.process_effect = CALLBACK(src, PROC_REF(process_mob), parent) else if(isturf(parent)) - max_volume = TURF_ACID_VOLUME_MAX - process_effect = CALLBACK(src, PROC_REF(process_turf), parent) + src.max_volume = TURF_ACID_VOLUME_MAX + src.process_effect = CALLBACK(src, PROC_REF(process_turf), parent) //if we failed all other checks, we must be an /atom/movable that uses integrity else if(atom_parent.uses_integrity) - // The parent object cannot have acid. Not incompatible, but should not really happen. - if(atom_parent.resistance_flags & UNACIDABLE) - qdel(src) - return - - max_volume = MOVABLE_ACID_VOLUME_MAX - process_effect = CALLBACK(src, PROC_REF(process_movable), parent) + src.max_volume = MOVABLE_ACID_VOLUME_MAX + src.process_effect = CALLBACK(src, PROC_REF(process_movable), parent) //or not... else stack_trace("Tried to add /datum/component/acid to an atom ([atom_parent.type]) which does not use atom_integrity!") @@ -61,23 +63,28 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e set_volume(acid_volume) src.acid_overlay = acid_overlay - sizzle = new(parent, TRUE) + sizzle = new(atom_parent, TRUE) + if(acid_particles) + // acid particles look pretty bad when they stack on mobs, so that behavior is not wanted for items + particle_effect = new(atom_parent, acid_particles, isitem(atom_parent) ? NONE : PARTICLE_ATTACH_MOB) START_PROCESSING(SSacid, src) /datum/component/acid/Destroy(force, silent) STOP_PROCESSING(SSacid, src) if(sizzle) QDEL_NULL(sizzle) + if(particle_effect) + QDEL_NULL(particle_effect) if(process_effect) QDEL_NULL(process_effect) return ..() /datum/component/acid/RegisterWithParent() + RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, PROC_REF(on_attack_hand)) RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) + RegisterSignal(parent, COMSIG_ATOM_EXPOSE_REAGENT, PROC_REF(on_expose_reagent)) RegisterSignal(parent, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(on_update_overlays)) RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, PROC_REF(on_clean)) - RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, PROC_REF(on_attack_hand)) - RegisterSignal(parent, COMSIG_ATOM_EXPOSE_REAGENT, PROC_REF(on_expose_reagent)) if(isturf(parent)) RegisterSignal(parent, COMSIG_ATOM_ENTERED, PROC_REF(on_entered)) var/atom/atom_parent = parent @@ -85,11 +92,12 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e /datum/component/acid/UnregisterFromParent() UnregisterSignal(parent, list( + COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_EXAMINE, + COMSIG_ATOM_EXPOSE_REAGENT, COMSIG_ATOM_UPDATE_OVERLAYS, COMSIG_COMPONENT_CLEAN_ACT, - COMSIG_ATOM_ATTACK_HAND, - COMSIG_ATOM_EXPOSE_REAGENT)) + )) if(isturf(parent)) UnregisterSignal(parent, COMSIG_ATOM_ENTERED) var/atom/atom_parent = parent @@ -98,6 +106,8 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e /// Averages corrosive power and sums volume. /datum/component/acid/InheritComponent(datum/component/new_comp, i_am_original, acid_power, acid_volume) + if(!i_am_original) + return acid_power = ((src.acid_power * src.acid_volume) + (acid_power * acid_volume)) / (src.acid_volume + acid_volume) set_volume(src.acid_volume + acid_volume) @@ -109,6 +119,11 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e /// Handles the slow corrosion of the parent [/atom]. /datum/component/acid/process(seconds_per_tick) + // If we somehow got unacidable, we need to bail out + var/atom/parent_atom = parent + if(parent_atom.resistance_flags & UNACIDABLE) + qdel(src) + return process_effect?.InvokeAsync(seconds_per_tick) if(QDELING(src)) //The process effect deals damage, and on turfs diminishes the acid volume, potentially destroying the component. Let's not destroy it twice. return @@ -122,6 +137,8 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e /// Handles processing on a [/mob/living]. /datum/component/acid/proc/process_mob(mob/living/target, seconds_per_tick) + if(target.resistance_flags & ACID_PROOF) + return target.acid_act(acid_power, acid_volume * seconds_per_tick) /// Handles processing on a [/turf]. @@ -135,7 +152,11 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e if(applied_targets) set_volume(acid_volume - (acid_used * applied_targets)) - // Snowflake code for handling acid melting walls. TODO: Move integrity handling to the atom level so this can be desnowflaked. + if(target_turf.resistance_flags & ACID_PROOF) + return + + // Snowflake code for handling acid melting walls. + // We really should consider making turfs use atom_integrity, but for now this is just for acids. if(acid_power < ACID_POWER_MELT_TURF) return @@ -189,25 +210,22 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e set_volume(acid_volume + reac_volume) return NONE -/// Handles searing the hand of anyone who tries to touch this without protection. -/datum/component/acid/proc/on_attack_hand(atom/parent_atom, mob/living/carbon/user) +/// Handles searing the hand of anyone who tries to touch parent without protection. +/datum/component/acid/proc/on_attack_hand(atom/source, mob/living/carbon/user) SIGNAL_HANDLER - if(!istype(user)) - return NONE - if((parent_atom == user) || (parent_atom.loc == user)) - return NONE // So people can take their own clothes off. - if((acid_power * acid_volume) < ACID_LEVEL_HANDBURN) - return NONE - if(user.gloves?.resistance_flags & (UNACIDABLE|ACID_PROOF)) + if(!iscarbon(user) || user.can_touch_acid(source, acid_power, acid_volume)) return NONE - var/obj/item/bodypart/affecting = user.get_bodypart("[(user.active_hand_index % 2 == 0) ? "r" : "l" ]_arm") - if(!affecting?.receive_damage(0, 5)) + var/obj/item/bodypart/affecting = user.get_active_hand() + //Should not happen! + if(!affecting) return NONE - to_chat(user, span_warning("The acid on \the [parent_atom] burns your hand!")) - playsound(parent_atom, 'sound/weapons/sear.ogg', 50, TRUE) + affecting.receive_damage(burn = 5) + to_chat(user, span_userdanger("The acid on \the [source] burns your hand!")) + INVOKE_ASYNC(user, TYPE_PROC_REF(/mob, emote), "scream") + playsound(source, SFX_SEAR, 50, TRUE) user.update_damage_overlays() return COMPONENT_CANCEL_ATTACK_CHAIN @@ -226,7 +244,8 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e return var/acid_used = min(acid_volume * 0.05, 20) - if(crosser.acid_act(acid_power, acid_used, FEET)) - playsound(crosser, 'sound/weapons/sear.ogg', 50, TRUE) - to_chat(crosser, span_userdanger("The acid on the [parent] burns you!")) - set_volume(max(acid_volume - acid_used, 10)) + if(!crosser.acid_act(acid_power, acid_used, FEET)) + return + playsound(crosser, SFX_SEAR, 50, TRUE) + to_chat(crosser, span_userdanger("The acid on the [parent] burns you!")) + set_volume(max(acid_volume - acid_used, 10)) diff --git a/code/datums/components/burning.dm b/code/datums/components/burning.dm index 347340e3e2c..dccb786f400 100644 --- a/code/datums/components/burning.dm +++ b/code/datums/components/burning.dm @@ -18,10 +18,12 @@ GLOBAL_DATUM_INIT(fire_overlay, /mutable_appearance, mutable_appearance('icons/e if(!atom_parent.uses_integrity) stack_trace("Tried to add /datum/component/burning to an atom ([atom_parent.type]) that does not use atom_integrity!") return COMPONENT_INCOMPATIBLE + // only flammable atoms should have this component, but it's not really an error if we try to apply this to a non flammable one if(!(atom_parent.resistance_flags & FLAMMABLE) || (atom_parent.resistance_flags & FIRE_PROOF)) qdel(src) return + src.fire_overlay = fire_overlay if(fire_particles) // burning particles look pretty bad when they stack on mobs, so that behavior is not wanted for items @@ -30,20 +32,27 @@ GLOBAL_DATUM_INIT(fire_overlay, /mutable_appearance, mutable_appearance('icons/e /datum/component/burning/Destroy(force, silent) STOP_PROCESSING(SSburning, src) + fire_overlay = null if(particle_effect) QDEL_NULL(particle_effect) return ..() /datum/component/burning/RegisterWithParent() - RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) + RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, PROC_REF(on_attack_hand)) RegisterSignal(parent, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(on_update_overlays)) + RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) RegisterSignal(parent, COMSIG_ATOM_EXTINGUISH, PROC_REF(on_extinguish)) var/atom/atom_parent = parent atom_parent.resistance_flags |= ON_FIRE atom_parent.update_appearance() /datum/component/burning/UnregisterFromParent() - UnregisterSignal(parent, list(COMSIG_ATOM_EXAMINE, COMSIG_ATOM_UPDATE_OVERLAYS, COMSIG_ATOM_EXTINGUISH)) + UnregisterSignal(parent, list( + COMSIG_ATOM_ATTACK_HAND, + COMSIG_ATOM_UPDATE_OVERLAYS, + COMSIG_ATOM_EXAMINE, + COMSIG_ATOM_EXTINGUISH, + )) var/atom/atom_parent = parent if(!QDELETED(atom_parent)) atom_parent.resistance_flags &= ~ON_FIRE @@ -51,7 +60,7 @@ GLOBAL_DATUM_INIT(fire_overlay, /mutable_appearance, mutable_appearance('icons/e /datum/component/burning/process(seconds_per_tick) var/atom/atom_parent = parent - // Check if the parent somehow became fireproof + // Check if the parent somehow became fireproof, remove component if so if(atom_parent.resistance_flags & FIRE_PROOF) atom_parent.extinguish() return @@ -63,6 +72,27 @@ GLOBAL_DATUM_INIT(fire_overlay, /mutable_appearance, mutable_appearance('icons/e examine_list += span_danger("[source.p_theyre(TRUE)] burning!") +/// Handles searing the hand of anyone who tries to touch parent without protection. +/datum/component/burning/proc/on_attack_hand(atom/source, mob/living/carbon/user) + SIGNAL_HANDLER + + if(!iscarbon(user) || user.can_touch_burning(source)) + to_chat(user, span_notice("You put out the fire on [source].")) + source.extinguish() + return COMPONENT_CANCEL_ATTACK_CHAIN + + var/obj/item/bodypart/affecting = user.get_active_hand() + //Should not happen! + if(!affecting) + return NONE + + affecting.receive_damage(burn = 5) + to_chat(user, span_userdanger("You burn your hand on [source]!")) + INVOKE_ASYNC(user, TYPE_PROC_REF(/mob, emote), "scream") + playsound(source, SFX_SEAR, 50, TRUE) + user.update_damage_overlays() + return COMPONENT_CANCEL_ATTACK_CHAIN + /// Maintains the burning overlay on the parent atom /datum/component/burning/proc/on_update_overlays(atom/source, list/overlays) SIGNAL_HANDLER diff --git a/code/datums/components/thermite.dm b/code/datums/components/thermite.dm index 913f2221163..85557482baf 100644 --- a/code/datums/components/thermite.dm +++ b/code/datums/components/thermite.dm @@ -6,6 +6,8 @@ var/burn_require /// The thermite overlay var/thermite_overlay + /// Default thermite overlay, do not touch + var/static/mutable_appearance/default_thermite_overlay = mutable_appearance('icons/effects/effects.dmi', "thermite") /// Callback related to burning, stored so the timer can be easily reset without losing the user var/datum/callback/burn_callback /// The timer for burning parent, calls burn_callback when done @@ -13,8 +15,6 @@ /// The thermite fire overlay var/obj/effect/overlay/thermite/fakefire - /// Default thermite overlay, do not touch - var/static/mutable_appearance/default_thermite_overlay = mutable_appearance('icons/effects/effects.dmi', "thermite") /// Blacklist of turfs that cannot have thermite on it var/static/list/blacklist = typecacheof(list( /turf/open/lava, @@ -54,32 +54,34 @@ /datum/component/thermite/Destroy() thermite_overlay = null - if(burn_callback) - QDEL_NULL(burn_callback) if(burn_timer) deltimer(burn_timer) burn_timer = null + if(burn_callback) + QDEL_NULL(burn_callback) if(fakefire) QDEL_NULL(fakefire) return ..() /datum/component/thermite/RegisterWithParent() + RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, PROC_REF(attackby_react)) + RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, PROC_REF(on_attack_hand)) + RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) RegisterSignal(parent, COMSIG_ATOM_FIRE_ACT, PROC_REF(on_fire_act)) RegisterSignal(parent, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(on_update_overlays)) RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, PROC_REF(clean_react)) - RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, PROC_REF(attackby_react)) - RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) RegisterSignal(parent, COMSIG_QDELETING, PROC_REF(parent_qdeleting)) //probably necessary because turfs are wack var/turf/turf_parent = parent turf_parent.update_appearance() /datum/component/thermite/UnregisterFromParent() UnregisterSignal(parent, list( + COMSIG_ATOM_ATTACKBY, + COMSIG_ATOM_ATTACK_HAND, + COMSIG_ATOM_EXAMINE, COMSIG_ATOM_FIRE_ACT, COMSIG_ATOM_UPDATE_OVERLAYS, COMSIG_COMPONENT_CLEAN_ACT, - COMSIG_ATOM_ATTACKBY, - COMSIG_ATOM_EXAMINE, COMSIG_QDELETING, )) var/turf/turf_parent = parent @@ -118,7 +120,7 @@ fakefire = new(parent_turf) burn_callback = CALLBACK(src, PROC_REF(burn_parent), user) burn_timer = addtimer(burn_callback, min(amount * 0.35 SECONDS, 20 SECONDS), TIMER_STOPPABLE) - //unregister everything mechanical, we are burning up + //unregister everything related to burning UnregisterSignal(parent, list(COMSIG_COMPONENT_CLEAN_ACT, COMSIG_ATOM_ATTACKBY, COMSIG_ATOM_FIRE_ACT)) /** @@ -145,7 +147,7 @@ /datum/component/thermite/proc/clean_react(datum/source, strength) SIGNAL_HANDLER - //Thermite is just some loose powder, you could probably clean it with your hands. << todo? + //Thermite is just some loose powder, you could probably clean it with your hands qdel(src) return COMPONENT_CLEANED @@ -166,6 +168,29 @@ if(exposed_temperature >= 1922) thermite_melt() +/// Handles searing the hand of anyone who tries to touch parent without protection, while burning +/datum/component/thermite/proc/on_attack_hand(atom/source, mob/living/carbon/user) + SIGNAL_HANDLER + + //not burning + if(!fakefire) + return NONE + + if(!iscarbon(user) || user.can_touch_burning(source)) + return NONE + + var/obj/item/bodypart/affecting = user.get_active_hand() + //Should not happen! + if(!affecting) + return NONE + + affecting.receive_damage(burn = 5) + to_chat(user, span_userdanger("The ignited thermite on \the [source] burns your hand!")) + INVOKE_ASYNC(user, TYPE_PROC_REF(/mob, emote), "scream") + playsound(source, SFX_SEAR, 50, TRUE) + user.update_damage_overlays() + return COMPONENT_CANCEL_ATTACK_CHAIN + /** * attackby reaction, ignites the thermite if its a flame creating object * diff --git a/code/datums/status_effects/debuffs/fire_stacks.dm b/code/datums/status_effects/debuffs/fire_stacks.dm index dee6471a62f..41fcaf0dcc8 100644 --- a/code/datums/status_effects/debuffs/fire_stacks.dm +++ b/code/datums/status_effects/debuffs/fire_stacks.dm @@ -272,11 +272,7 @@ cache_stacks() update_overlay() update_particles() - if(!iscarbon(owner)) - return - for(var/obj/item/equipped in owner.get_equipped_items()) - equipped.wash(CLEAN_TYPE_ACID) equipped.extinguish() /datum/status_effect/fire_handler/fire_stacks/on_remove() diff --git a/code/game/objects/effects/misc.dm b/code/game/objects/effects/misc.dm index 03664e280cb..4b801a61daf 100644 --- a/code/game/objects/effects/misc.dm +++ b/code/game/objects/effects/misc.dm @@ -47,17 +47,6 @@ var/list/container = list() -/obj/effect/overlay/thermite - name = "thermite" - desc = "Looks hot." - icon = 'icons/effects/fire.dmi' - icon_state = "2" //what? - anchored = TRUE - opacity = TRUE - density = TRUE - layer = FLY_LAYER - plane = ABOVE_GAME_PLANE - //Makes a tile fully lit no matter what /obj/effect/fullbright icon = 'icons/effects/alphacolors.dmi' diff --git a/code/game/objects/effects/overlays.dm b/code/game/objects/effects/overlays.dm index 318af5cf52e..24fae3f6139 100644 --- a/code/game/objects/effects/overlays.dm +++ b/code/game/objects/effects/overlays.dm @@ -8,9 +8,9 @@ return /obj/effect/overlay/beam//Not actually a projectile, just an effect. - name="beam" - icon='icons/effects/beam.dmi' - icon_state="b_beam" + name = "beam" + icon = 'icons/effects/beam.dmi' + icon_state = "b_beam" var/atom/BeamSource /obj/effect/overlay/beam/Initialize(mapload) @@ -24,6 +24,16 @@ icon_state = "shieldsparkles" anchored = TRUE +/obj/effect/overlay/thermite + name = "thermite" + desc = "Looks hot." + icon = 'icons/effects/fire.dmi' + icon_state = "2" //what? + anchored = TRUE + plane = ABOVE_GAME_PLANE + layer = FLY_LAYER + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + /obj/effect/overlay/vis mouse_opacity = MOUSE_OPACITY_TRANSPARENT anchored = TRUE diff --git a/code/game/objects/effects/particles/acid.dm b/code/game/objects/effects/particles/acid.dm new file mode 100644 index 00000000000..bcb7559ce9c --- /dev/null +++ b/code/game/objects/effects/particles/acid.dm @@ -0,0 +1,15 @@ +// Acid related particles. +/particles/acid + icon = 'icons/effects/particles/acid.dmi' + icon_state = list("goop_1" = 6, "goop_2" = 2, "goop_3" = 1) + width = 100 + height = 100 + count = 100 + spawning = 0.5 + color = "#FFFFFF80" //to get 96 alpha + lifespan = 1.5 SECONDS + fade = 1 SECONDS + grow = -0.025 + gravity = list(0, 0.15) + position = generator(GEN_SPHERE, 0, 16, NORMAL_RAND) + spin = generator(GEN_NUM, -15, 15, NORMAL_RAND) diff --git a/code/game/objects/effects/particles/fire.dm b/code/game/objects/effects/particles/fire.dm index 703fd6b06b5..9d90d0d29c2 100644 --- a/code/game/objects/effects/particles/fire.dm +++ b/code/game/objects/effects/particles/fire.dm @@ -1,21 +1,4 @@ // Fire related particles. -/particles/embers - icon = 'icons/effects/particles/generic.dmi' - icon_state = list("dot"=4,"cross"=1,"curl"=1) - width = 64 - height = 96 - count = 500 - spawning = 5 - lifespan = 3 SECONDS - fade = 1 SECONDS - color = 0 - color_change = 0.05 - gradient = list("#FBAF4D", "#FCE6B6", "#FD481C") - position = generator(GEN_BOX, list(-12,-16,0), list(12,16,0), NORMAL_RAND) - drift = generator(GEN_VECTOR, list(-0.1,0), list(0.1,0.025), UNIFORM_RAND) - spin = generator(GEN_NUM, list(-15,15), NORMAL_RAND) - scale = generator(GEN_VECTOR, list(0.5,0.5), list(2,2), NORMAL_RAND) - /particles/bonfire icon = 'icons/effects/particles/bonfire.dmi' icon_state = "bonfire" @@ -33,3 +16,20 @@ scale = generator(GEN_VECTOR, list(0.3, 0.3), list(1,1), NORMAL_RAND) rotation = 30 spin = generator(GEN_NUM, -20, 20) + +/particles/embers + icon = 'icons/effects/particles/generic.dmi' + icon_state = list("dot" = 4,"cross" = 1,"curl" = 1) + width = 64 + height = 96 + count = 500 + spawning = 5 + lifespan = 3 SECONDS + fade = 1 SECONDS + color = 0 + color_change = 0.05 + gradient = list("#FBAF4D", "#FCE6B6", "#FD481C") + position = generator(GEN_BOX, list(-12,-16,0), list(12,16,0), NORMAL_RAND) + drift = generator(GEN_VECTOR, list(-0.1,0), list(0.1,0.025), UNIFORM_RAND) + spin = generator(GEN_NUM, list(-15,15), NORMAL_RAND) + scale = generator(GEN_VECTOR, list(0.5,0.5), list(2,2), NORMAL_RAND) diff --git a/code/game/objects/effects/particles/misc.dm b/code/game/objects/effects/particles/misc.dm index 8fba3c7e1c4..18db20d6379 100644 --- a/code/game/objects/effects/particles/misc.dm +++ b/code/game/objects/effects/particles/misc.dm @@ -1,4 +1,4 @@ -//general or un-matched particles, make a new file if a few can be sorted together. +// General or un-matched particles, make a new file if a few can be sorted together. /particles/pollen icon = 'icons/effects/particles/pollen.dmi' icon_state = "pollen" diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index ad3f881b686..5d6f5273743 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -521,26 +521,6 @@ /obj/item/proc/attempt_pickup(mob/user) . = TRUE - if(resistance_flags & ON_FIRE) - var/mob/living/carbon/C = user - var/can_handle_hot = FALSE - if(!istype(C)) - can_handle_hot = TRUE - else if(C.gloves && (C.gloves.max_heat_protection_temperature > 360)) - can_handle_hot = TRUE - else if(HAS_TRAIT(C, TRAIT_RESISTHEAT) || HAS_TRAIT(C, TRAIT_RESISTHEATHANDS)) - can_handle_hot = TRUE - - if(can_handle_hot) - extinguish() - to_chat(user, span_notice("You put out the fire on [src].")) - else - to_chat(user, span_warning("You burn your hand on [src]!")) - var/obj/item/bodypart/affecting = C.get_bodypart("[(user.active_hand_index % 2 == 0) ? "r" : "l" ]_arm") - if(affecting?.receive_damage( 0, 5 )) // 5 burn damage - C.update_damage_overlays() - return - if(!(interaction_flags_item & INTERACT_ITEM_ATTACK_HAND_PICKUP)) //See if we're supposed to auto pickup. return @@ -878,7 +858,7 @@ /obj/item/proc/get_dismember_sound() if(damtype == BURN) - . = 'sound/weapons/sear.ogg' + . = SFX_SEAR else . = SFX_DESECRATION diff --git a/code/game/sound.dm b/code/game/sound.dm index c1dec90898a..d447e0866fe 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -184,35 +184,35 @@ /proc/get_sfx(soundin) if(istext(soundin)) switch(soundin) - if (SFX_SHATTER) + if(SFX_SHATTER) soundin = pick('sound/effects/glassbr1.ogg','sound/effects/glassbr2.ogg','sound/effects/glassbr3.ogg') - if (SFX_EXPLOSION) + if(SFX_EXPLOSION) soundin = pick('sound/effects/explosion1.ogg','sound/effects/explosion2.ogg') - if (SFX_EXPLOSION_CREAKING) + if(SFX_EXPLOSION_CREAKING) soundin = pick('sound/effects/explosioncreak1.ogg', 'sound/effects/explosioncreak2.ogg') - if (SFX_HULL_CREAKING) + if(SFX_HULL_CREAKING) soundin = pick('sound/effects/creak1.ogg', 'sound/effects/creak2.ogg', 'sound/effects/creak3.ogg') - if (SFX_SPARKS) + if(SFX_SPARKS) soundin = pick('sound/effects/sparks1.ogg','sound/effects/sparks2.ogg','sound/effects/sparks3.ogg','sound/effects/sparks4.ogg') - if (SFX_RUSTLE) + if(SFX_RUSTLE) soundin = pick('sound/effects/rustle1.ogg','sound/effects/rustle2.ogg','sound/effects/rustle3.ogg','sound/effects/rustle4.ogg','sound/effects/rustle5.ogg') - if (SFX_BODYFALL) + if(SFX_BODYFALL) soundin = pick('sound/effects/bodyfall1.ogg','sound/effects/bodyfall2.ogg','sound/effects/bodyfall3.ogg','sound/effects/bodyfall4.ogg') - if (SFX_PUNCH) + if(SFX_PUNCH) soundin = pick('sound/weapons/punch1.ogg','sound/weapons/punch2.ogg','sound/weapons/punch3.ogg','sound/weapons/punch4.ogg') - if (SFX_CLOWN_STEP) + if(SFX_CLOWN_STEP) soundin = pick('sound/effects/footstep/clownstep1.ogg','sound/effects/footstep/clownstep2.ogg') - if (SFX_SUIT_STEP) + if(SFX_SUIT_STEP) soundin = pick('sound/effects/suitstep1.ogg','sound/effects/suitstep2.ogg') - if (SFX_SWING_HIT) + if(SFX_SWING_HIT) soundin = pick('sound/weapons/genhit1.ogg', 'sound/weapons/genhit2.ogg', 'sound/weapons/genhit3.ogg') - if (SFX_HISS) + if(SFX_HISS) soundin = pick('sound/voice/hiss1.ogg','sound/voice/hiss2.ogg','sound/voice/hiss3.ogg','sound/voice/hiss4.ogg') - if (SFX_PAGE_TURN) + if(SFX_PAGE_TURN) soundin = pick('sound/effects/pageturn1.ogg', 'sound/effects/pageturn2.ogg','sound/effects/pageturn3.ogg') - if (SFX_RICOCHET) + if(SFX_RICOCHET) soundin = pick( 'sound/weapons/effects/ric1.ogg', 'sound/weapons/effects/ric2.ogg','sound/weapons/effects/ric3.ogg','sound/weapons/effects/ric4.ogg','sound/weapons/effects/ric5.ogg') - if (SFX_TERMINAL_TYPE) + if(SFX_TERMINAL_TYPE) soundin = pick(list( 'sound/machines/terminal_button01.ogg', 'sound/machines/terminal_button02.ogg', @@ -223,11 +223,11 @@ 'sound/machines/terminal_button07.ogg', 'sound/machines/terminal_button08.ogg', )) - if (SFX_DESECRATION) + if(SFX_DESECRATION) soundin = pick('sound/misc/desecration-01.ogg', 'sound/misc/desecration-02.ogg', 'sound/misc/desecration-03.ogg') - if (SFX_IM_HERE) + if(SFX_IM_HERE) soundin = pick('sound/hallucinations/im_here1.ogg', 'sound/hallucinations/im_here2.ogg') - if (SFX_CAN_OPEN) + if(SFX_CAN_OPEN) soundin = pick('sound/effects/can_open1.ogg', 'sound/effects/can_open2.ogg', 'sound/effects/can_open3.ogg') if(SFX_BULLET_MISS) soundin = pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg') @@ -260,7 +260,7 @@ 'sound/weapons/bladeslice.ogg', 'sound/weapons/flashbang.ogg', )) - if("goose") + if(SFX_GOOSE) soundin = pick('sound/creatures/goose1.ogg', 'sound/creatures/goose2.ogg', 'sound/creatures/goose3.ogg', 'sound/creatures/goose4.ogg') if(SFX_WARPSPEED) soundin = 'sound/runtime/hyperspace/hyperspace_begin.ogg' @@ -414,4 +414,6 @@ soundin = pick('sound/effects/treechop1.ogg', 'sound/effects/treechop2.ogg', 'sound/effects/treechop3.ogg') if(SFX_ROCK_TAP) soundin = pick('sound/effects/rocktap1.ogg', 'sound/effects/rocktap2.ogg', 'sound/effects/rocktap3.ogg') + if(SFX_SEAR) + soundin = 'sound/weapons/sear.ogg' return soundin diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 2d77af7e67c..6b733079d93 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -1364,6 +1364,32 @@ log_combat(shover, target, "shoved", addition = "into [name]") return COMSIG_CARBON_SHOVE_HANDLED +/** + * This proc is used to determine whether or not the mob can handle touching an acid affected object. + */ +/mob/living/carbon/proc/can_touch_acid(atom/acided_atom, acid_power, acid_volume) + // So people can take their own clothes off + if((acided_atom == src) || (acided_atom.loc == src)) + return TRUE + if((acid_power * acid_volume) < ACID_LEVEL_HANDBURN) + return TRUE + if(gloves?.resistance_flags & (UNACIDABLE | ACID_PROOF)) + return TRUE + return FALSE + +/** + * This proc is used to determine whether or not the mob can handle touching a burning object. + */ +/mob/living/carbon/proc/can_touch_burning(atom/burning_atom, acid_power, acid_volume) + // So people can take their own clothes off + if((burning_atom == src) || (burning_atom.loc == src)) + return TRUE + if(HAS_TRAIT(src, TRAIT_RESISTHEAT) || HAS_TRAIT(src, TRAIT_RESISTHEATHANDS)) + return TRUE + if(gloves?.max_heat_protection_temperature >= BURNING_ITEM_MINIMUM_TEMPERATURE) + return TRUE + return FALSE + /** * This proc is a helper for spraying blood for things like slashing/piercing wounds and dismemberment. * diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm index 4cc0e1ab1c6..18ebc4a96e3 100644 --- a/code/modules/surgery/bodyparts/helpers.dm +++ b/code/modules/surgery/bodyparts/helpers.dm @@ -43,7 +43,7 @@ /mob/living/carbon/get_active_hand() var/which_hand = BODY_ZONE_PRECISE_L_HAND - if(!(active_hand_index % 2)) + if(!(active_hand_index % RIGHT_HANDS)) which_hand = BODY_ZONE_PRECISE_R_HAND return get_bodypart(check_zone(which_hand)) @@ -54,7 +54,7 @@ /mob/living/carbon/has_left_hand(check_disabled = TRUE) for(var/obj/item/bodypart/hand_instance in hand_bodyparts) - if(!(hand_instance.held_index % 2) || (check_disabled && hand_instance.bodypart_disabled)) + if(!(hand_instance.held_index % RIGHT_HANDS) || (check_disabled && hand_instance.bodypart_disabled)) continue return TRUE return FALSE @@ -70,7 +70,7 @@ /mob/living/carbon/has_right_hand(check_disabled = TRUE) for(var/obj/item/bodypart/hand_instance in hand_bodyparts) - if(hand_instance.held_index % 2 || (check_disabled && hand_instance.bodypart_disabled)) + if(hand_instance.held_index % RIGHT_HANDS || (check_disabled && hand_instance.bodypart_disabled)) continue return TRUE return FALSE diff --git a/icons/effects/particles/acid.dmi b/icons/effects/particles/acid.dmi new file mode 100644 index 00000000000..74e347e9b97 Binary files /dev/null and b/icons/effects/particles/acid.dmi differ diff --git a/icons/effects/particles/echo.dmi b/icons/effects/particles/echo.dmi index a7a47e340d1..60a243a8a7b 100644 Binary files a/icons/effects/particles/echo.dmi and b/icons/effects/particles/echo.dmi differ diff --git a/icons/effects/particles/generic.dmi b/icons/effects/particles/generic.dmi index 0e6a84a34b3..41776efdbfd 100644 Binary files a/icons/effects/particles/generic.dmi and b/icons/effects/particles/generic.dmi differ diff --git a/tgstation.dme b/tgstation.dme index dba73c831de..fb2c94238ef 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1766,6 +1766,7 @@ #include "code\game\objects\effects\effect_system\fluid_spread\effects_foam.dm" #include "code\game\objects\effects\effect_system\fluid_spread\effects_smoke.dm" #include "code\game\objects\effects\landmarks\atmospherics_sanity_landmarks.dm" +#include "code\game\objects\effects\particles\acid.dm" #include "code\game\objects\effects\particles\fire.dm" #include "code\game\objects\effects\particles\misc.dm" #include "code\game\objects\effects\particles\note_particles.dm"