diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 892dd3f8107..614cee7d234 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1899,3 +1899,27 @@ var/mob/dview/dview_mob = new num_sample -= num result += (1 << num) return result + +/proc/pixel_shift_dir(var/dir, var/amount_x = 32, var/amount_y = 32) //Returns a list with pixel_shift values that will shift an object's icon one tile in the direction passed. + amount_x = min(max(0, amount_x), 32) //No less than 0, no greater than 32. + amount_y = min(max(0, amount_x), 32) + var/list/shift = list("x" = 0, "y" = 0) + switch(dir) + if(NORTH) + shift["y"] = amount_y + if(SOUTH) + shift["y"] = -amount_y + if(EAST) + shift["x"] = amount_x + if(WEST) + shift["x"] = -amount_x + if(NORTHEAST) + shift = list("x" = amount_x, "y" = amount_y) + if(NORTHWEST) + shift = list("x" = -amount_x, "y" = amount_y) + if(SOUTHEAST) + shift = list("x" = amount_x, "y" = -amount_y) + if(SOUTHWEST) + shift = list("x" = -amount_x, "y" = -amount_y) + + return shift diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 22cadfaa659..efc5e62827d 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -512,10 +512,11 @@ var/list/blood_splatter_icons = list() overlays += blood_overlay /atom/proc/clean_blood() - germ_level = 0 - if(islist(blood_DNA)) - blood_DNA = null - return 1 + if(!istype(src, /obj/effect/decal/cleanable/blood)) + germ_level = 0 + if(islist(blood_DNA)) + blood_DNA = null + return TRUE /obj/item/clean_blood() diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm index f17b5f6901a..02f89f6f0f6 100644 --- a/code/game/objects/effects/decals/Cleanable/humans.dm +++ b/code/game/objects/effects/decals/Cleanable/humans.dm @@ -22,6 +22,7 @@ var/global/list/image/splatter_cache=list() var/amount = 5 appearance_flags = NO_CLIENT_COLOR var/dry_timer = 0 + var/off_floor = FALSE /obj/effect/decal/cleanable/blood/New() ..() @@ -88,7 +89,7 @@ var/global/list/image/splatter_cache=list() //Add "bloodiness" of this blood's type, to the human's shoes /obj/effect/decal/cleanable/blood/Crossed(atom/movable/O) - if(ishuman(O)) + if(!off_floor && ishuman(O)) var/mob/living/carbon/human/H = O var/obj/item/organ/external/l_foot = H.get_organ("l_foot") var/obj/item/organ/external/r_foot = H.get_organ("r_foot") diff --git a/code/game/objects/effects/overlays.dm b/code/game/objects/effects/overlays.dm index 96f52929da6..10d78bd2ae1 100644 --- a/code/game/objects/effects/overlays.dm +++ b/code/game/objects/effects/overlays.dm @@ -205,6 +205,7 @@ animate(src, pixel_x = target_pixel_x, pixel_y = target_pixel_y, alpha = 0, time = duration) /obj/effect/overlay/temp/dir_setting/bloodsplatter/xenosplatter + color = null splatter_type = "xsplatter" /obj/effect/overlay/wall_rot diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 7141e41363a..9524e3a9327 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -1172,14 +1172,18 @@ var/list/robot_verbs_default = list( if(module.type == /obj/item/weapon/robot_module/janitor) var/turf/tile = loc if(isturf(tile)) - tile.clean_blood() + var/floor_only = TRUE if(istype(tile, /turf/simulated)) var/turf/simulated/S = tile S.dirt = 0 for(var/A in tile) if(istype(A, /obj/effect)) if(is_cleanable(A)) - qdel(A) + var/obj/effect/decal/cleanable/blood/B = A + if(istype(B) && B.off_floor) + floor_only = FALSE + else + qdel(A) else if(istype(A, /obj/item)) var/obj/item/cleaned_item = A cleaned_item.clean_blood() @@ -1200,6 +1204,8 @@ var/list/robot_verbs_default = list( cleaned_human.update_inv_shoes(0,0) cleaned_human.clean_blood() to_chat(cleaned_human, "[src] cleans your face!") + if(floor_only) + tile.clean_blood() return #undef BORG_CAMERA_BUFFER diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index f2beec3f6bc..71ac935153b 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -71,6 +71,7 @@ if(!isliving(target)) return 0 var/mob/living/L = target + var/mob/living/carbon/human/H if(blocked < 100) // not completely blocked if(damage && L.blood_volume && damage_type == BRUTE) var/splatter_dir = dir @@ -81,11 +82,23 @@ else var/blood_color = "#C80000" if(ishuman(target)) - var/mob/living/carbon/human/H = target + H = target blood_color = H.species.blood_color new /obj/effect/overlay/temp/dir_setting/bloodsplatter(target_loca, splatter_dir, blood_color) if(prob(33)) - L.add_splatter_floor(target_loca) + var/list/shift = list("x" = 0, "y" = 0) + var/turf/step_over = get_step(target_loca, splatter_dir) + + if(get_splatter_blockage(step_over, target, splatter_dir, target_loca)) //If you can't cross the tile or any of its relevant obstacles... + shift = pixel_shift_dir(splatter_dir) //Pixel shift the blood there instead (so you can't see wallsplatter through walls). + else + target_loca = step_over + L.add_splatter_floor(target_loca, shift_x = shift["x"], shift_y = shift["y"]) + if(istype(H)) + for(var/mob/living/carbon/human/M in step_over) //Bloody the mobs who're infront of the spray. + M.bloody_hands(H) + /* Uncomment when bloody_body stops randomly not transferring blood colour. + M.bloody_body(H) */ var/organ_hit_text = "" if(L.has_limbs) @@ -110,6 +123,15 @@ add_logs(firer, L, "shot", src, reagent_note) return L.apply_effects(stun, weaken, paralyze, irradiate, slur, stutter, eyeblur, drowsy, blocked, stamina, jitter) +/obj/item/projectile/proc/get_splatter_blockage(var/turf/step_over, var/atom/target, var/splatter_dir, var/target_loca) //Check whether the place we want to splatter blood is blocked (i.e. by windows). + var/turf/step_cardinal = !(splatter_dir in list(NORTH, SOUTH, EAST, WEST)) ? get_step(target_loca, get_cardinal_dir(target_loca, step_over)) : null + + if(step_over.density && !step_over.CanPass(target, step_over, 1)) //Preliminary simple check. + return TRUE + for(var/atom/movable/border_obstacle in step_over) //Check to see if we're blocked by a (non-full) window or some such. Do deeper investigation if we're splattering blood diagonally. + if(border_obstacle.flags&ON_BORDER && get_dir(step_cardinal ? step_cardinal : target_loca, step_over) == turn(border_obstacle.dir, 180)) + return TRUE + /obj/item/projectile/proc/vol_by_damage() if(damage) return Clamp((damage) * 0.67, 30, 100)// Multiply projectile damage by 0.67, then clamp the value between 30 and 100 diff --git a/code/modules/reagents/chemistry/reagents/water.dm b/code/modules/reagents/chemistry/reagents/water.dm index 5c7657e9407..4eb6a246f2b 100644 --- a/code/modules/reagents/chemistry/reagents/water.dm +++ b/code/modules/reagents/chemistry/reagents/water.dm @@ -132,18 +132,27 @@ taste_message = "floor cleaner" /datum/reagent/space_cleaner/reaction_obj(obj/O, volume) - if(istype(O, /obj/effect/decal/cleanable)) - qdel(O) + if(is_cleanable(O)) + var/obj/effect/decal/cleanable/blood/B = O + if(!(istype(B) && B.off_floor)) + qdel(O) else - O.color = initial(O.color) + if(!istype(O, /atom/movable/lighting_overlay)) + O.color = initial(O.color) O.clean_blood() /datum/reagent/space_cleaner/reaction_turf(turf/T, volume) if(volume >= 1) - T.color = initial(T.color) - T.clean_blood() + var/floor_only = TRUE for(var/obj/effect/decal/cleanable/C in src) - qdel(C) + var/obj/effect/decal/cleanable/blood/B = C + if(istype(B) && B.off_floor) + floor_only = FALSE + else + qdel(C) + T.color = initial(T.color) + if(floor_only) + T.clean_blood() for(var/mob/living/carbon/slime/M in T) M.adjustToxLoss(rand(5,10)) diff --git a/code/modules/surgery/organs/blood.dm b/code/modules/surgery/organs/blood.dm index 987b5cf53e4..bc19b6c6159 100644 --- a/code/modules/surgery/organs/blood.dm +++ b/code/modules/surgery/organs/blood.dm @@ -229,7 +229,7 @@ return list("O-", "O+") //to add a splatter of blood or other mob liquid. -/mob/living/proc/add_splatter_floor(turf/T, small_drip) +/mob/living/proc/add_splatter_floor(turf/T, small_drip, shift_x, shift_y) if(get_blood_id() != "blood")//is it blood or welding fuel? return if(!T) @@ -260,29 +260,50 @@ return // Find a blood decal or create a new one. - var/obj/effect/decal/cleanable/blood/B = locate() in T - if(!B) + var/obj/effect/decal/cleanable/blood/B + if(!(locate(B) in T) || pixel_x || pixel_y) B = new /obj/effect/decal/cleanable/blood/splatter(T) + else + B = locate() in T B.transfer_mob_blood_dna(src) //give blood info to the blood decal. if(temp_blood_DNA) B.blood_DNA |= temp_blood_DNA + B.pixel_x = (shift_x) + B.pixel_y = (shift_y) B.update_icon() + if(shift_x || shift_y) + B.off_floor = TRUE + B.layer = BELOW_MOB_LAYER //So the blood lands ontop of things like posters, windows, etc. -/mob/living/carbon/human/add_splatter_floor(turf/T, small_drip) +/mob/living/carbon/human/add_splatter_floor(turf/T, small_drip, shift_x, shift_y) if(!(NO_BLOOD in species.species_traits)) ..() -/mob/living/carbon/alien/add_splatter_floor(turf/T, small_drip) +/mob/living/carbon/alien/add_splatter_floor(turf/T, small_drip, shift_x, shift_y) if(!T) T = get_turf(src) - var/obj/effect/decal/cleanable/blood/xeno/B = locate() in T.contents - if(!B) + var/obj/effect/decal/cleanable/blood/xeno/B + if(!(locate(B) in T) || pixel_x || pixel_y) B = new(T) + else + B = locate() in T B.blood_DNA["UNKNOWN DNA"] = "X*" + B.pixel_x = (shift_x) + B.pixel_y = (shift_y) + if(shift_x || shift_y) + B.off_floor = TRUE + B.layer = BELOW_MOB_LAYER -/mob/living/silicon/robot/add_splatter_floor(turf/T, small_drip) +/mob/living/silicon/robot/add_splatter_floor(turf/T, small_drip, shift_x, shift_y) if(!T) T = get_turf(src) - var/obj/effect/decal/cleanable/blood/oil/B = locate() in T.contents - if(!B) - B = new(T) \ No newline at end of file + var/obj/effect/decal/cleanable/blood/oil/B + if(!(locate(B) in T) || pixel_x || pixel_y) + B = new(T) + else + B = locate() in T + B.pixel_x = (shift_x) + B.pixel_y = (shift_y) + if(shift_x || shift_y) + B.off_floor = TRUE + B.layer = BELOW_MOB_LAYER