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