diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm
index ae6943d553a..444077aacd7 100644
--- a/code/__DEFINES/flags.dm
+++ b/code/__DEFINES/flags.dm
@@ -134,4 +134,6 @@
//resistance_flags
#define INDESTRUCTIBLE 64 //doesn't take damage
+#define CHECK_RICOCHET_1 (1<<4)
+
GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768))
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 5ca34ceb57e..657afff2028 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -14,6 +14,7 @@
var/simulated = 1 //filter for actions - used by lighting overlays
var/atom_say_verb = "says"
var/dont_save = 0 // For atoms that are temporary by necessity - like lighting overlays
+ var/flags_1 = NONE
///Chemistry.
var/container_type = NONE
@@ -696,6 +697,9 @@ var/list/blood_splatter_icons = list()
/atom/proc/ratvar_act()
return
+/atom/proc/handle_ricochet(obj/item/projectile/P)
+ return
+
//This proc is called on the location of an atom when the atom is Destroy()'d
/atom/proc/handle_atom_del(atom/A)
return
diff --git a/code/game/gamemodes/blob/blobs/shield.dm b/code/game/gamemodes/blob/blobs/shield.dm
index dc381a449fa..97a73946393 100644
--- a/code/game/gamemodes/blob/blobs/shield.dm
+++ b/code/game/gamemodes/blob/blobs/shield.dm
@@ -27,9 +27,10 @@
brute_resist = 0
health = 50
maxHealth = 50
+ flags_1 = CHECK_RICOCHET_1
var/reflect_chance = 80 //80% chance to reflect
-
-/obj/structure/blob/shield/reflective/bullet_act(obj/item/projectile/P)
+
+/obj/structure/blob/shield/reflective/handle_ricochet(obj/item/projectile/P)
if(P.is_reflectable && prob(reflect_chance) && !istype(P, /obj/item/projectile/beam/pulse))
var/P_turf = get_turf(P)
var/face_direction = get_dir(src, P_turf)
@@ -44,3 +45,6 @@
return -1// complete projectile permutation
else
take_damage(P.damage, P.damage_type)
+
+/obj/structure/blob/shield/reflective/bullet_act()
+ return
diff --git a/code/game/gamemodes/blob/powers.dm b/code/game/gamemodes/blob/powers.dm
index da714ccfad5..8340de85ce2 100644
--- a/code/game/gamemodes/blob/powers.dm
+++ b/code/game/gamemodes/blob/powers.dm
@@ -33,60 +33,49 @@
/mob/camera/blob/verb/create_shield_power()
set category = "Blob"
- set name = "Create Shield Blob (10)"
- set desc = "Create a shield blob."
+ set name = "Create/Upgrade Shield Blob (15)"
+ set desc = "Create/Upgrade a shield blob. Using this on an existing shield blob turns it into a reflective blob, capable of reflecting most energy projectiles but making it much weaker than usual to brute attacks."
var/turf/T = get_turf(src)
create_shield(T)
/mob/camera/blob/proc/create_shield(var/turf/T)
- var/obj/structure/blob/B = (locate(/obj/structure/blob) in T)
-
- if(!B)//We are on a blob
- to_chat(src, "There is no blob here!")
- return
-
- if(!istype(B, /obj/structure/blob/normal))
- to_chat(src, "Unable to use this blob, find a normal one.")
- return
-
- if(!can_buy(10))
- return
-
- B.color = blob_reagent_datum.color
- B.change_to(/obj/structure/blob/shield)
-
- return
-
-/mob/camera/blob/verb/upgrade_shield()
- set category = "Blob"
- set name = "Upgrade Shield Blob (20)"
- set desc = "Using this on an existing shield blob turns it into a reflective blob, capable of reflecting most energy projectiles but making it much weaker than usual to brute attacks."
-
- var/turf/T = get_turf(src)
-
+ var/obj/structure/blob/B = locate(/obj/structure/blob) in T
var/obj/structure/blob/shield/S = locate(/obj/structure/blob/shield) in T
- if(S)
- if(!can_buy(20))
+ if(!S)
+ if(!B)//We are on a blob
+ to_chat(src, "There is no blob here!")
return
- if(S.health < S.maxHealth * 0.5)
- to_chat(src, "This shield blob is too damaged to be modified properly!")
+ else if(!istype(B, /obj/structure/blob/normal))
+ to_chat(src, "Unable to use this blob, find a normal one.")
return
-
+
+ else if(!can_buy(15))
+ return
+
+ B.color = blob_reagent_datum.color
+ B.change_to(/obj/structure/blob/shield)
+ else
+
if(istype(S, /obj/structure/blob/shield/reflective))
to_chat(src, "There's already a reflector blob here!")
return
-
+
+
+ else if(S.health < S.maxHealth * 0.5)
+ to_chat(src, "This shield blob is too damaged to be modified properly!")
+ return
+
+ else if (!can_buy(15))
+ return
+
to_chat(src, "You secrete a reflective ooze over the shield blob, allowing it to reflect energy projectiles at the cost of reduced intregrity.")
S.change_to(/obj/structure/blob/shield/reflective)
S.color = blob_reagent_datum.color
-
- else
- to_chat(src, "There is no shield blob here!")
return
/mob/camera/blob/verb/create_resource()
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index 39f25c5ef89..5e1a84d804d 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -30,7 +30,9 @@
var/spread = 0 //amount (in degrees) of projectile spread
var/legacy = FALSE //legacy projectile system
animate_movement = 0
-
+
+ var/ignore_source_check = FALSE
+
var/damage = 10
var/tile_dropoff = 0 //how much damage should be decremented as the bullet moves
var/tile_dropoff_s = 0 //same as above but for stamina
@@ -54,6 +56,9 @@
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/ricochets = 0
+ var/ricochets_max = 2
+ var/ricochet_chance = 0
var/log_override = FALSE //whether print to admin attack logs or just keep it in the diary
@@ -157,6 +162,14 @@
/obj/item/projectile/Bump(atom/A, yes)
if(!yes) //prevents double bumps.
return
+
+ if(check_ricochet(A) && check_ricochet_flag(A) && ricochets < ricochets_max)
+ ricochets++
+ if(A.handle_ricochet(src))
+ on_ricochet(A)
+ ignore_source_check = TRUE
+ range = initial(range)
+ return TRUE
if(firer)
if(A == firer || (A == firer.loc && istype(A, /obj/mecha))) //cannot shoot yourself or your mech
loc = A.loc
@@ -280,3 +293,17 @@ obj/item/projectile/Crossed(atom/movable/AM) //A mob moving on a tile with a pro
/obj/item/projectile/proc/dumbfire(var/dir)
current = get_ranged_target_turf(src, dir, world.maxx) //world.maxx is the range. Not sure how to handle this better.
fire()
+
+
+/obj/item/projectile/proc/on_ricochet(atom/A)
+ return
+
+/obj/item/projectile/proc/check_ricochet()
+ if(prob(ricochet_chance))
+ return TRUE
+ return FALSE
+
+/obj/item/projectile/proc/check_ricochet_flag(atom/A)
+ if(A.flags_1 & CHECK_RICOCHET_1)
+ return TRUE
+ return FALSE