diff --git a/code/__DEFINES/particle_defines.dm b/code/__DEFINES/particle_defines.dm new file mode 100644 index 00000000000..b261cd4f98d --- /dev/null +++ b/code/__DEFINES/particle_defines.dm @@ -0,0 +1,7 @@ +// These are used to convery what kind of debris should spawn from being hit by something +#define DEBRIS_SPARKS "spark" +#define DEBRIS_WOOD "wood" +#define DEBRIS_ROCK "rock" +#define DEBRIS_GLASS "glass" +#define DEBRIS_LEAF "leaf" +#define DEBRIS_SNOW "snow" diff --git a/code/datums/components/debris.dm b/code/datums/components/debris.dm new file mode 100644 index 00000000000..908c966a9e1 --- /dev/null +++ b/code/datums/components/debris.dm @@ -0,0 +1,93 @@ +/* + * In this file you can find the particle component for bullet hits + * Originally from https://github.com/tgstation/TerraGov-Marine-Corps/pull/12752 + */ + +/particles/debris + icon = 'icons/effects/particles/generic_particles.dmi' + width = 500 + height = 500 + count = 10 + spawning = 10 + lifespan = 0.5 SECONDS + fade = 0.3 SECONDS + drift = generator("circle", 0, 7) + scale = 0.3 + velocity = list(50, 0) + friction = generator("num", 0.1, 0.15) + spin = generator("num", -20, 20) + +/particles/impact_smoke + icon = 'icons/effects/effects.dmi' + icon_state = "smoke" + width = 500 + height = 500 + count = 20 + spawning = 20 + lifespan = 0.8 SECONDS + fade = 10 SECONDS + grow = 0.1 + scale = 0.2 + spin = generator("num", -20, 20) + velocity = list(50, 0) + friction = generator("num", 0.1, 0.5) + +/datum/component/debris + /// Icon state of debris when impacted by a projectile + var/debris + /// Velocity of debris particles + var/debris_velocity = -15 + /// Amount of debris particles + var/debris_amount = 8 + /// Scale of particle debris + var/debris_scale = 0.7 + +/datum/component/debris/Initialize(_debris_icon_state, _debris_velocity = -15, _debris_amount = 8, _debris_scale = 0.7) + . = ..() + debris = _debris_icon_state + debris_velocity = _debris_velocity + debris_amount = _debris_amount + debris_scale = _debris_scale + RegisterSignal(parent, COMSIG_ATOM_BULLET_ACT, PROC_REF(register_for_impact)) + +/datum/component/debris/Destroy(force) + . = ..() + if(parent) + UnregisterSignal(parent, COMSIG_ATOM_BULLET_ACT) + +/datum/component/debris/proc/register_for_impact(datum/source, obj/item/projectile/proj) + SIGNAL_HANDLER // COMSIG_ATOM_BULLET_ACT + INVOKE_ASYNC(src, PROC_REF(on_impact), proj) + +/datum/component/debris/proc/on_impact(obj/item/projectile/P) + var/angle = !isnull(P.Angle) ? P.Angle : round(get_angle(P.starting, parent), 1) + var/x_component = sin(angle) * debris_velocity + var/y_component = cos(angle) * debris_velocity + var/x_component_smoke = sin(angle) * -15 + var/y_component_smoke = cos(angle) * -15 + + var/obj/effect/abstract/particle_holder/debris_visuals + var/obj/effect/abstract/particle_holder/smoke_visuals + var/position_offset = rand(-6, 6) + + smoke_visuals = new(parent, /particles/impact_smoke) + smoke_visuals.particles.position = list(position_offset, position_offset) + smoke_visuals.particles.velocity = list(x_component_smoke, y_component_smoke) + + if(debris && !(P.damage_type == BURN)) + debris_visuals = new(parent, /particles/debris) + debris_visuals.particles.position = generator("circle", position_offset, position_offset) + debris_visuals.particles.velocity = list(x_component, y_component) + debris_visuals.layer = ABOVE_OBJ_LAYER + 0.02 + debris_visuals.particles.icon_state = debris + debris_visuals.particles.count = debris_amount + debris_visuals.particles.spawning = debris_amount + debris_visuals.particles.scale = debris_scale + smoke_visuals.layer = ABOVE_OBJ_LAYER + 0.01 + + addtimer(CALLBACK(src, PROC_REF(remove_ping), src, smoke_visuals, debris_visuals), 0.5 SECONDS) + +/datum/component/debris/proc/remove_ping(hit, obj/effect/abstract/particle_holder/smoke_visuals, obj/effect/abstract/particle_holder/debris_visuals) + QDEL_NULL(smoke_visuals) + if(debris_visuals) + QDEL_NULL(debris_visuals) diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm index 63b1325a260..040bd8b1359 100644 --- a/code/game/machinery/deployable.dm +++ b/code/game/machinery/deployable.dm @@ -27,6 +27,10 @@ //The list of directions to block a projectile from var/list/directional_list = list() +/obj/structure/barricade/Initialize(mapload) + . = ..() + AddComponent(/datum/component/debris, DEBRIS_WOOD, -20, 10) + /obj/structure/barricade/deconstruct(disassembled = TRUE) if(!(flags & NODECONSTRUCT)) make_debris() diff --git a/code/game/objects/effects/effects.dm b/code/game/objects/effects/effects.dm index 1d74ec9bb0d..2a7267b881d 100644 --- a/code/game/objects/effects/effects.dm +++ b/code/game/objects/effects/effects.dm @@ -148,3 +148,65 @@ /obj/effect/decal/proc/on_scoop() return + +/// These effects can be added to anything to hold particles, which is useful because Byond only allows a single particle per atom +/obj/effect/abstract/particle_holder + anchored = TRUE + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + layer = ABOVE_ALL_MOB_LAYER + vis_flags = VIS_INHERIT_PLANE + invisibility = FALSE + ///typepath of the last location we're in, if it's different when moved then we need to update vis contents + var/last_attached_location_type + /// The main item we're attached to at the moment, particle holders hold particles for something + var/atom/parent + /// The mob that is holding our item + var/mob/holding_parent + +/obj/effect/abstract/particle_holder/Initialize(mapload, particle_path = null) + . = ..() + if(!loc) + stack_trace("particle holder was created with no loc!") + return INITIALIZE_HINT_QDEL + parent = loc + + if(ismovable(parent)) + RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(on_move)) + RegisterSignal(parent, COMSIG_PARENT_QDELETING, PROC_REF(on_qdel)) + + particles = new particle_path + update_visual_contents(parent) + +/obj/effect/abstract/particle_holder/Destroy(force) + if(parent) + UnregisterSignal(parent, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING)) + QDEL_NULL(particles) + return ..() + +///signal called when parent is moved +/obj/effect/abstract/particle_holder/proc/on_move(atom/movable/attached, atom/oldloc, direction) + SIGNAL_HANDLER + if(parent.loc.type != last_attached_location_type) + update_visual_contents(attached) + +///signal called when parent is deleted +/obj/effect/abstract/particle_holder/proc/on_qdel(atom/movable/attached, force) + SIGNAL_HANDLER + qdel(src)//our parent is gone and we need to be as well + +///logic proc for particle holders, aka where they move. +///subtypes of particle holders can override this for particles that should always be turf level or do special things when repositioning. +///this base subtype has some logic for items, as the loc of items becomes mobs very often hiding the particles +/obj/effect/abstract/particle_holder/proc/update_visual_contents(atom/movable/attached_to) + // Remove old + if(holding_parent && !(QDELETED(holding_parent))) + holding_parent.vis_contents -= src + + // Add new + if(isitem(attached_to) && ismob(attached_to.loc)) //special case we want to also be emitting from the mob + var/mob/particle_mob = attached_to.loc + last_attached_location_type = attached_to.loc + particle_mob.vis_contents += src + + // Readd to ourselves + attached_to.vis_contents |= src diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index 1c0bc9cd224..1c3a997a220 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -14,6 +14,10 @@ var/metalUsed = 2 //used to determine amount returned in deconstruction var/metal_type = /obj/item/stack/sheet/metal +/obj/structure/girder/Initialize(mapload) + . = ..() + AddComponent(/datum/component/debris, DEBRIS_SPARKS, -20, 10) + /obj/structure/girder/examine(mob/user) . = ..() switch(state) diff --git a/code/game/objects/structures/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm index 788c451338a..ec197bb5c3d 100644 --- a/code/game/objects/structures/mineral_doors.dm +++ b/code/game/objects/structures/mineral_doors.dm @@ -27,6 +27,7 @@ . = ..() initial_state = icon_state air_update_turf(1) + AddComponent(/datum/component/debris, DEBRIS_SPARKS, -20, 10) /obj/structure/mineral_door/Destroy() density = FALSE @@ -211,3 +212,7 @@ resistance_flags = FLAMMABLE max_integrity = 200 rad_insulation = RAD_VERY_LIGHT_INSULATION + +/obj/structure/mineral_door/wood/Initialize() + . = ..() + AddComponent(/datum/component/debris, DEBRIS_WOOD, -20, 10) diff --git a/code/game/turfs/simulated/minerals.dm b/code/game/turfs/simulated/minerals.dm index 0cb28240dea..a090a32cbcf 100644 --- a/code/game/turfs/simulated/minerals.dm +++ b/code/game/turfs/simulated/minerals.dm @@ -42,6 +42,7 @@ var/turf/T = get_step(src, dir) if(istype(T, /turf/simulated/mineral/random)) Spread(T) + AddComponent(/datum/component/debris, DEBRIS_ROCK, -20, 10, 1) /turf/simulated/mineral/proc/Spread(turf/T) T.ChangeTurf(type) diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index d4c41a5fd55..680cd80c053 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -61,6 +61,7 @@ underlay_appearance.icon_state = fixed_underlay["icon_state"] fixed_underlay = string_assoc_list(fixed_underlay) underlays += underlay_appearance + AddComponent(/datum/component/debris, DEBRIS_SPARKS, -20, 10, 1) /turf/simulated/wall/BeforeChange() for(var/obj/effect/overlay/wall_rot/WR in src) diff --git a/code/game/turfs/simulated/walls_mineral.dm b/code/game/turfs/simulated/walls_mineral.dm index c5a0cad1ea5..e667cfb2314 100644 --- a/code/game/turfs/simulated/walls_mineral.dm +++ b/code/game/turfs/simulated/walls_mineral.dm @@ -2,10 +2,10 @@ name = "mineral wall" desc = "This shouldn't exist" icon_state = "" - var/last_event = 0 - var/active = FALSE smoothing_flags = SMOOTH_BITMASK canSmoothWith = null + var/last_event = 0 + var/active = FALSE /turf/simulated/wall/mineral/shuttleRotate(rotation) return //This override is needed to properly rotate the object when on a shuttle that is rotated. diff --git a/code/modules/hydroponics/fermenting_barrel.dm b/code/modules/hydroponics/fermenting_barrel.dm index 71c296d900b..cad77d337e2 100644 --- a/code/modules/hydroponics/fermenting_barrel.dm +++ b/code/modules/hydroponics/fermenting_barrel.dm @@ -13,6 +13,7 @@ /obj/structure/fermenting_barrel/Initialize() create_reagents(300) //Bluespace beakers, but without the portability or efficiency in circuits. + AddComponent(/datum/component/debris, DEBRIS_WOOD, -20, 10) . = ..() /obj/structure/fermenting_barrel/examine(mob/user) diff --git a/code/modules/mining/lavaland/ash_flora.dm b/code/modules/mining/lavaland/ash_flora.dm index 3a3419db0e2..46331272516 100644 --- a/code/modules/mining/lavaland/ash_flora.dm +++ b/code/modules/mining/lavaland/ash_flora.dm @@ -167,6 +167,10 @@ harvest_message_high = "You finish mining the rock." delete_on_harvest = TRUE +/obj/structure/flora/ash/rock/Initialize(mapload) + . = ..() + AddComponent(/datum/component/debris, DEBRIS_ROCK, -20, 10) + /obj/structure/flora/ash/rock/style_2 icon_state = "basalt2" diff --git a/code/modules/projectiles/guns/projectile/automatic.dm b/code/modules/projectiles/guns/projectile/automatic.dm index 94e39bc7f68..d9879a9f46e 100644 --- a/code/modules/projectiles/guns/projectile/automatic.dm +++ b/code/modules/projectiles/guns/projectile/automatic.dm @@ -112,7 +112,7 @@ //WT550// /obj/item/gun/projectile/automatic/wt550 - name = "WT-550 PDW" + name = "\improper WT-550 PDW" desc = "An outdated personal defense weapon utilized by law enforcement. Chambered in 4.6x30mm." icon_state = "wt550" item_state = "wt550" diff --git a/icons/effects/particles/generic_particles.dmi b/icons/effects/particles/generic_particles.dmi new file mode 100644 index 00000000000..e322afcebbe Binary files /dev/null and b/icons/effects/particles/generic_particles.dmi differ diff --git a/paradise.dme b/paradise.dme index b8bc61904dc..427bca5bcd2 100644 --- a/paradise.dme +++ b/paradise.dme @@ -92,6 +92,7 @@ #include "code\__DEFINES\muzzle_flash.dm" #include "code\__DEFINES\nanomob_defines.dm" #include "code\__DEFINES\newscaster_defines.dm" +#include "code\__DEFINES\particle_defines.dm" #include "code\__DEFINES\pda.dm" #include "code\__DEFINES\pipes.dm" #include "code\__DEFINES\power_defines.dm" @@ -402,6 +403,7 @@ #include "code\datums\components\corpse_description.dm" #include "code\datums\components\cult_held_body.dm" #include "code\datums\components\deadchat_control.dm" +#include "code\datums\components\debris.dm" #include "code\datums\components\decal.dm" #include "code\datums\components\defibrillator.dm" #include "code\datums\components\ducttape.dm"