diff --git a/code/game/objects/effects/temporary_visuals/miscellaneous.dm b/code/game/objects/effects/temporary_visuals/miscellaneous.dm
index 8fd1c061c32..d349d0b1cd7 100644
--- a/code/game/objects/effects/temporary_visuals/miscellaneous.dm
+++ b/code/game/objects/effects/temporary_visuals/miscellaneous.dm
@@ -289,4 +289,33 @@
/obj/effect/temp_visual/dir_setting/firing_effect/magic
icon_state = "shieldsparkles"
- duration = 3
\ No newline at end of file
+ duration = 3
+
+/obj/effect/temp_visual/impact_effect
+ icon_state = "impact_bullet"
+ duration = 5
+
+/obj/effect/temp_visual/impact_effect/Initialize(mapload, x, y)
+ pixel_x = x
+ pixel_y = y
+ return ..()
+
+/obj/effect/temp_visual/impact_effect/red_laser
+ icon_state = "impact_laser"
+ duration = 4
+
+/obj/effect/temp_visual/impact_effect/blue_laser
+ icon_state = "impact_laser_blue"
+ duration = 4
+
+/obj/effect/temp_visual/impact_effect/green_laser
+ icon_state = "impact_laser_green"
+ duration = 4
+
+/obj/effect/temp_visual/impact_effect/purple_laser
+ icon_state = "impact_laser_purple"
+ duration = 4
+
+/obj/effect/temp_visual/impact_effect/ion
+ icon_state = "shieldsparkles"
+ duration = 6
\ No newline at end of file
diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm
index 5a8f842307e..26b79c9e9f4 100644
--- a/code/game/turfs/simulated/walls.dm
+++ b/code/game/turfs/simulated/walls.dm
@@ -1,3 +1,7 @@
+#define WALL_DENT_HIT 1
+#define WALL_DENT_SHOT 2
+#define MAX_DENT_DECALS 15
+
/turf/simulated/wall
name = "wall"
desc = "A huge chunk of metal used to seperate rooms."
@@ -25,7 +29,7 @@
var/slicing_duration = 100
var/engraving //engraving on the wall
var/engraving_quality
-
+ var/list/dent_decals
var/sheet_type = /obj/item/stack/sheet/metal
var/sheet_amount = 2
var/girder_type = /obj/structure/girder
@@ -167,6 +171,8 @@
/turf/simulated/wall/blob_act()
if(prob(50))
dismantle_wall()
+ else
+ add_dent(WALL_DENT_HIT)
/turf/simulated/wall/rpd_act(mob/user, obj/item/rpd/our_rpd)
if(our_rpd.mode == RPD_ATMOS_MODE)
@@ -191,6 +197,8 @@
M.occupant_message("You smash through the wall.")
visible_message("[src.name] smashes through the wall!")
playsound(src, 'sound/effects/meteorimpact.ogg', 100, 1)
+ else
+ add_dent(WALL_DENT_HIT)
// Wall-rot effect, a nasty fungus that destroys walls.
/turf/simulated/wall/proc/rot()
@@ -260,6 +268,7 @@
dismantle_wall(TRUE)
else
playsound(src, 'sound/effects/bang.ogg', 50, 1)
+ add_dent(WALL_DENT_HIT)
to_chat(user, text("You punch the wall."))
return TRUE
@@ -296,7 +305,6 @@
if(try_wallmount(I, user, params))
return
-
// The magnetic gripper does a separate attackby, so bail from this one
if(istype(I, /obj/item/gripper))
return
@@ -327,7 +335,7 @@
return TRUE // this means "don't continue trying to find alternative uses in attackby", not "decon succeeded"
var/response = "Dismantle"
- if(damage)
+ if(damage || LAZYLEN(dent_decals))
response = alert(user, "Would you like to repair or dismantle [src]?", "[src]", "Repair", "Dismantle")
switch(response)
@@ -336,6 +344,8 @@
playsound(src, WT.usesound, 100, 1)
if(do_after(user, max(5, damage / 5) * WT.toolspeed, target = src) && WT && WT.isOn())
to_chat(user, "You finish repairing the damage to [src].")
+ cut_overlay(dent_decals)
+ dent_decals.Cut()
take_damage(-damage)
else
to_chat(user, "You begin slicing through the outer plating.")
@@ -435,3 +445,27 @@
/turf/simulated/wall/narsie_act()
if(prob(20))
ChangeTurf(/turf/simulated/wall/cult)
+
+/turf/simulated/wall/proc/add_dent(denttype, x=rand(-8, 8), y=rand(-8, 8))
+ if(LAZYLEN(dent_decals) >= MAX_DENT_DECALS)
+ return
+
+ var/mutable_appearance/decal = mutable_appearance('icons/effects/effects.dmi', "", BULLET_HOLE_LAYER)
+ switch(denttype)
+ if(WALL_DENT_SHOT)
+ decal.icon_state = "bullet_hole"
+ if(WALL_DENT_HIT)
+ decal.icon_state = "impact[rand(1, 3)]"
+
+ decal.pixel_x = x
+ decal.pixel_y = y
+
+ if(LAZYLEN(dent_decals))
+ cut_overlay(dent_decals)
+ dent_decals += decal
+ else
+ dent_decals = list(decal)
+
+ add_overlay(dent_decals)
+
+#undef MAX_DENT_DECALS
\ No newline at end of file
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index a8d368d6aef..2c55ed48692 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -56,6 +56,7 @@
var/jitter = 0
var/forcedodge = 0 //to pass through everything
var/dismemberment = 0 //The higher the number, the greater the bonus to dismembering. 0 will not dismember at all.
+ var/impact_effect_type //what type of impact effect to show when hitting something
var/ricochets = 0
var/ricochets_max = 2
var/ricochet_chance = 0
@@ -82,9 +83,26 @@
/obj/item/projectile/proc/on_hit(atom/target, blocked = 0, hit_zone)
var/turf/target_loca = get_turf(target)
+ var/hitx
+ var/hity
+ if(target == original)
+ hitx = target.pixel_x + p_x - 16
+ hity = target.pixel_y + p_y - 16
+ else
+ hitx = target.pixel_x + rand(-8, 8)
+ hity = target.pixel_y + rand(-8, 8)
+ if(!nodamage && (damage_type == BRUTE || damage_type == BURN) && iswallturf(target_loca) && prob(75))
+ var/turf/simulated/wall/W = target_loca
+ if(impact_effect_type)
+ new impact_effect_type(target_loca, hitx, hity)
+
+ W.add_dent(WALL_DENT_SHOT, hitx, hity)
+ return 0
if(alwayslog)
add_attack_logs(firer, target, "Shot with a [type]")
if(!isliving(target))
+ if(impact_effect_type)
+ new impact_effect_type(target_loca, hitx, hity)
return 0
var/mob/living/L = target
var/mob/living/carbon/human/H
@@ -115,7 +133,8 @@
M.bloody_hands(H)
/* Uncomment when bloody_body stops randomly not transferring blood colour.
M.bloody_body(H) */
-
+ else if(impact_effect_type)
+ new impact_effect_type(target_loca, hitx, hity)
var/organ_hit_text = ""
if(L.has_limbs)
organ_hit_text = " in \the [parse_zone(def_zone)]"
diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm
index b34364c4c93..bad6b6db68b 100644
--- a/code/modules/projectiles/projectile/beams.dm
+++ b/code/modules/projectiles/projectile/beams.dm
@@ -8,6 +8,7 @@
hitsound_wall = 'sound/weapons/effects/searwall.ogg'
flag = "laser"
eyeblur = 2
+ impact_effect_type = /obj/effect/temp_visual/impact_effect/red_laser
is_reflectable = TRUE
light_range = 2
light_color = LIGHT_COLOR_RED
@@ -38,6 +39,7 @@
irradiate = 30
forcedodge = 1
range = 15
+ impact_effect_type = /obj/effect/temp_visual/impact_effect/green_laser
light_color = LIGHT_COLOR_GREEN
/obj/item/projectile/beam/disabler
@@ -48,12 +50,14 @@
flag = "energy"
hitsound = 'sound/weapons/tap.ogg'
eyeblur = 0
+ impact_effect_type = /obj/effect/temp_visual/impact_effect/blue_laser
light_color = LIGHT_COLOR_CYAN
/obj/item/projectile/beam/pulse
name = "pulse"
icon_state = "u_laser"
damage = 50
+ impact_effect_type = /obj/effect/temp_visual/impact_effect/blue_laser
light_color = LIGHT_COLOR_DARKBLUE
/obj/item/projectile/beam/pulse/on_hit(var/atom/target, var/blocked = 0)
@@ -70,6 +74,7 @@
damage = 30
legacy = 1
animate_movement = SLIDE_STEPS
+ impact_effect_type = /obj/effect/temp_visual/impact_effect/green_laser
light_color = LIGHT_COLOR_GREEN
/obj/item/projectile/beam/emitter/singularity_pull()
@@ -84,6 +89,7 @@
flag = "laser"
var/suit_types = list(/obj/item/clothing/suit/redtag, /obj/item/clothing/suit/bluetag)
log_override = TRUE
+ impact_effect_type = /obj/effect/temp_visual/impact_effect/blue_laser
light_color = LIGHT_COLOR_DARKBLUE
/obj/item/projectile/beam/lasertag/on_hit(atom/target, blocked = 0)
@@ -102,6 +108,7 @@
/obj/item/projectile/beam/lasertag/redtag
icon_state = "laser"
suit_types = list(/obj/item/clothing/suit/bluetag)
+ impact_effect_type = /obj/effect/temp_visual/impact_effect/red_laser
light_color = LIGHT_COLOR_RED
/obj/item/projectile/beam/lasertag/bluetag
@@ -115,6 +122,7 @@
stun = 5
weaken = 5
stutter = 5
+ impact_effect_type = /obj/effect/temp_visual/impact_effect/purple_laser
light_color = LIGHT_COLOR_PINK
/obj/item/projectile/beam/immolator
@@ -142,14 +150,17 @@
icon_state = "purple_laser"
damage = 200
damage_type = BURN
+ impact_effect_type = /obj/effect/temp_visual/impact_effect/purple_laser
light_color = LIGHT_COLOR_PURPLE
/obj/item/projectile/beam/instakill/blue
icon_state = "blue_laser"
+ impact_effect_type = /obj/effect/temp_visual/impact_effect/blue_laser
light_color = LIGHT_COLOR_DARKBLUE
/obj/item/projectile/beam/instakill/red
icon_state = "red_laser"
+ impact_effect_type = /obj/effect/temp_visual/impact_effect/red_laser
light_color = LIGHT_COLOR_RED
/obj/item/projectile/beam/instakill/on_hit(atom/target)
diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm
index 1cde9ef5017..a973ce1dd87 100644
--- a/code/modules/projectiles/projectile/bullets.dm
+++ b/code/modules/projectiles/projectile/bullets.dm
@@ -5,6 +5,7 @@
damage_type = BRUTE
flag = "bullet"
hitsound_wall = "ricochet"
+ impact_effect_type = /obj/effect/temp_visual/impact_effect
/obj/item/projectile/bullet/weakbullet //beanbag, heavy stamina damage
name = "beanbag slug"
diff --git a/code/modules/projectiles/projectile/energy.dm b/code/modules/projectiles/projectile/energy.dm
index 5da56d179bd..e1ca470c95a 100644
--- a/code/modules/projectiles/projectile/energy.dm
+++ b/code/modules/projectiles/projectile/energy.dm
@@ -41,6 +41,7 @@
damage = 20
damage_type = CLONE
irradiate = 10
+ impact_effect_type = /obj/effect/temp_visual/impact_effect/green_laser
/obj/item/projectile/energy/dart
name = "dart"
@@ -73,6 +74,7 @@
/obj/item/projectile/energy/shock_revolver
name = "shock bolt"
icon_state = "purple_laser"
+ impact_effect_type = /obj/effect/temp_visual/impact_effect/purple_laser
var/chain
/obj/item/ammo_casing/energy/shock_revolver/ready_proj(atom/target, mob/living/user, quiet, zone_override = "")
diff --git a/code/modules/projectiles/projectile/reusable.dm b/code/modules/projectiles/projectile/reusable.dm
index 1c23605f2b3..bd249037946 100644
--- a/code/modules/projectiles/projectile/reusable.dm
+++ b/code/modules/projectiles/projectile/reusable.dm
@@ -3,6 +3,7 @@
desc = "How do you even reuse a bullet?"
var/ammo_type = /obj/item/ammo_casing/caseless/
var/dropped = 0
+ impact_effect_type = null
/obj/item/projectile/bullet/reusable/on_hit(atom/target, blocked = 0)
. = ..()
diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm
index d313195a40e..e8099332a61 100644
--- a/code/modules/projectiles/projectile/special.dm
+++ b/code/modules/projectiles/projectile/special.dm
@@ -5,6 +5,7 @@
alwayslog = TRUE
damage_type = BURN
nodamage = 1
+ impact_effect_type = /obj/effect/temp_visual/impact_effect/ion
flag = "energy"
/obj/item/projectile/ion/on_hit(var/atom/target, var/blocked = 0)
@@ -129,6 +130,7 @@
damage = 0
damage_type = TOX
nodamage = 1
+ impact_effect_type = /obj/effect/temp_visual/impact_effect/green_laser
flag = "energy"
/obj/item/projectile/energy/floramut/on_hit(var/atom/target, var/blocked = 0)
@@ -244,6 +246,7 @@
damage = 5
range = 3
dismemberment = 20
+ impact_effect_type = /obj/effect/temp_visual/impact_effect/purple_laser
/obj/item/projectile/plasma/New()
var/turf/proj_turf = get_turf(src)
diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi
index 26526f68951..bea6f281f7a 100644
Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ