From 4fc23e4051ce6154d50e33fc11c9b436596086b6 Mon Sep 17 00:00:00 2001 From: Anewbe Date: Tue, 21 Aug 2018 22:17:04 -0500 Subject: [PATCH] Adds a new subset of grenades that shoot projectiles --- .../items/weapons/grenades/explosive.dm | 67 +++-------- .../objects/items/weapons/grenades/grenade.dm | 2 +- .../items/weapons/grenades/projectile.dm | 75 +++++++++++++ .../game/objects/items/weapons/tanks/tanks.dm | 29 ----- .../modules/projectiles/projectile/bullets.dm | 60 ---------- .../modules/projectiles/projectile/pellets.dm | 106 ++++++++++++++++++ polaris.dme | 2 + 7 files changed, 200 insertions(+), 141 deletions(-) create mode 100644 code/game/objects/items/weapons/grenades/projectile.dm create mode 100644 code/modules/projectiles/projectile/pellets.dm diff --git a/code/game/objects/items/weapons/grenades/explosive.dm b/code/game/objects/items/weapons/grenades/explosive.dm index a45348e3b99..28cd8aea92b 100644 --- a/code/game/objects/items/weapons/grenades/explosive.dm +++ b/code/game/objects/items/weapons/grenades/explosive.dm @@ -1,36 +1,3 @@ -//obj/item/weapon/grenade/explosive - //desc = "A fragmentation grenade, optimized for harming personnel without causing massive structural damage." - //name = "frag grenade" - //icon = 'icons/obj/grenade.dmi' - //det_time = 50 - //icon_state = "frggrenade" - //origin_tech = list(TECH_MATERIAL = 2, TECH_COMBAT = 3) - -//obj/item/weapon/grenade/explosive/prime() -// ..() - //spawn(0) - //explosion(src.loc,-1,-1,2) //If you're within two tiles of the grenade, you get hit twice, which tends to do 50+ brute and cause fractures. - //explosion(src.loc,-1,-1,3) //This is preferable to increasing the severity, so we don't decap with frags. - //qdel(src) - //return - -//Explosive grenade projectile, borrowed from fragmentation grenade code. -/obj/item/projectile/bullet/pellet/fragment - damage = 10 - armor_penetration = 30 - range_step = 2 //projectiles lose a fragment each time they travel this distance. Can be a non-integer. - - base_spread = 0 //causes it to be treated as a shrapnel explosion instead of cone - spread_step = 20 - - silenced = 1 //embedding messages are still produced so it's kind of weird when enabled. - no_attack_log = 1 - muzzle_type = null - -/obj/item/projectile/bullet/pellet/fragment/strong - damage = 15 - armor_penetration = 20 - /obj/item/weapon/grenade/explosive name = "fragmentation grenade" desc = "A fragmentation grenade, optimized for harming personnel without causing massive structural damage." @@ -56,6 +23,21 @@ src.fragmentate(O, num_fragments, spread_range, fragment_types) qdel(src) +/obj/item/weapon/grenade/explosive/proc/on_explosion(var/turf/O) + if(explosion_size) + explosion(O, -1, -1, explosion_size, round(explosion_size/2), 0) + +// Waaaaay more pellets +/obj/item/weapon/grenade/explosive/frag + name = "fragmentation grenade" + desc = "A military fragmentation grenade, designed to explode in a deadly shower of fragments." + icon_state = "frag" + loadable = null + + fragment_types = list(/obj/item/projectile/bullet/pellet/fragment) + num_fragments = 200 //total number of fragments produced by the grenade + + /obj/proc/fragmentate(var/turf/T=get_turf(src), var/fragment_number = 30, var/spreading_range = 5, var/list/fragtypes=list(/obj/item/projectile/bullet/pellet/fragment/)) set waitfor = 0 @@ -80,21 +62,4 @@ else if(!M.lying && src.loc != get_turf(src)) //if it's not on the turf, it must be in the mob! P.attack_mob(M, 0, 25) //you're holding a grenade, dude! else - P.attack_mob(M, 0, 100) //otherwise, allow a decent amount of fragments to pass - - -/obj/item/weapon/grenade/explosive/proc/on_explosion(var/turf/O) - if(explosion_size) - explosion(O, -1, -1, explosion_size, round(explosion_size/2), 0) - - -/obj/item/weapon/grenade/explosive/frag - name = "fragmentation grenade" - desc = "A military fragmentation grenade, designed to explode in a deadly shower of fragments." - icon_state = "frag" - loadable = null - - fragment_types = list(/obj/item/projectile/bullet/pellet/fragment) - num_fragments = 200 //total number of fragments produced by the grenade - - //The radius of the circle used to launch projectiles. Lower values mean less projectiles are used but if set too low gaps may appear in the spread pattern + P.attack_mob(M, 0, 100) //otherwise, allow a decent amount of fragments to pass \ No newline at end of file diff --git a/code/game/objects/items/weapons/grenades/grenade.dm b/code/game/objects/items/weapons/grenades/grenade.dm index af4194a6b52..7b7e85cce32 100644 --- a/code/game/objects/items/weapons/grenades/grenade.dm +++ b/code/game/objects/items/weapons/grenades/grenade.dm @@ -12,7 +12,7 @@ var/active = 0 var/det_time = 50 - var/loadable = 1 + var/loadable = TRUE var/arm_sound = 'sound/weapons/armbomb.ogg' /obj/item/weapon/grenade/proc/clown_check(var/mob/living/user) diff --git a/code/game/objects/items/weapons/grenades/projectile.dm b/code/game/objects/items/weapons/grenades/projectile.dm new file mode 100644 index 00000000000..05153df4fe9 --- /dev/null +++ b/code/game/objects/items/weapons/grenades/projectile.dm @@ -0,0 +1,75 @@ +/obj/item/weapon/grenade/shooter + name = "projectile grenade" // I have no idea what else to call this, but the base type should never be used + icon_state = "frggrenade" + item_state = "grenade" + + var/list/projectile_types = list(/obj/item/projectile/bullet/pistol/rubber) // What sorts of projectiles might we make? + + //The radius of the circle used to launch projectiles. Lower values mean less projectiles are used but if set too low gaps may appear in the spread pattern + var/spread_range = 7 + + loadable = FALSE + +/obj/item/weapon/grenade/shooter/detonate() + ..() + + var/turf/O = get_turf(src) + if(!O) + return + + src.launch_many_projectiles(O, spread_range, projectile_types) + + qdel(src) + + + +/obj/item/weapon/grenade/shooter/rubber + name = "rubber pellet grenade" + desc = "An anti-riot grenade that fires a cloud of rubber projectiles upon detonation." + projectile_types = list(/obj/item/projectile/bullet/pistol/rubber) + +// Exists mostly so I don't have to copy+paste the sprite vars to a billion things +/obj/item/weapon/grenade/shooter/energy + icon_state = "flashbang" + item_state = "flashbang" + spread_range = 3 // Because dear god + +/obj/item/weapon/grenade/shooter/energy/laser + name = "laser grenade" + desc = "A horrifically dangerous rave in a can." + projectile_types = list(/obj/item/projectile/beam/midlaser) + +/obj/item/weapon/grenade/shooter/energy/flash + name = "flash grenade" + desc = "A grenade that creates a large number of flashes upon detonation." + projectile_types = list(/obj/item/projectile/energy/flash) + +/obj/item/weapon/grenade/shooter/energy/tesla + name = "tesla grenade" + projectile_types = list(/obj/item/projectile/beam/chain_lightning/lesser) + + +// This is just fragmentate, but less specific. Don't know how to make either of them less awful, at the moment +/obj/proc/launch_many_projectiles(var/turf/T=get_turf(src), var/spreading_range = 5, var/list/projectiletypes=list(/obj/item/projectile/bullet/pistol/rubber)) + set waitfor = 0 + var/list/target_turfs = getcircle(T, spreading_range) + + for(var/turf/O in target_turfs) + sleep(0) + var/shot_type = pick(projectiletypes) + + var/obj/item/projectile/P = new shot_type(T) + P.shot_from = src.name + + P.launch(O) + + //Make sure to hit any mobs in the source turf + for(var/mob/living/M in T) + //lying on a frag grenade while the grenade is on the ground causes you to absorb most of the shrapnel. + //you will most likely be dead, but others nearby will be spared the fragments that hit you instead. + if(M.lying && isturf(src.loc)) + P.attack_mob(M, 0, 5) + else if(!M.lying && src.loc != get_turf(src)) //if it's not on the turf, it must be in the mob! + P.attack_mob(M, 0, 25) //you're holding a grenade, dude! + else + P.attack_mob(M, 0, 100) //otherwise, allow a decent amount of fragments to pass \ No newline at end of file diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm index 07979777e79..8ad660eb6ab 100644 --- a/code/game/objects/items/weapons/tanks/tanks.dm +++ b/code/game/objects/items/weapons/tanks/tanks.dm @@ -674,32 +674,3 @@ var/list/global/tank_gauge_cache = list() /obj/item/device/tankassemblyproxy/HasProximity(atom/movable/AM as mob|obj) if(src.assembly) src.assembly.HasProximity(AM) - - -/obj/item/projectile/bullet/pellet/fragment/tank - name = "metal fragment" - damage = 9 //Big chunks flying off. - range_step = 2 //controls damage falloff with distance. projectiles lose a "pellet" each time they travel this distance. Can be a non-integer. - - base_spread = 0 //causes it to be treated as a shrapnel explosion instead of cone - spread_step = 20 - - armor_penetration = 20 - - silenced = 1 - no_attack_log = 1 - muzzle_type = null - pellets = 3 - -/obj/item/projectile/bullet/pellet/fragment/tank/small - name = "small metal fragment" - damage = 6 - armor_penetration = 5 - pellets = 5 - -/obj/item/projectile/bullet/pellet/fragment/tank/big - name = "large metal fragment" - damage = 17 - armor_penetration = 10 - range_step = 5 //controls damage falloff with distance. projectiles lose a "pellet" each time they travel this distance. Can be a non-integer. - pellets = 1 \ No newline at end of file diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm index 36a93a89b0c..b478186de79 100644 --- a/code/modules/projectiles/projectile/bullets.dm +++ b/code/modules/projectiles/projectile/bullets.dm @@ -62,66 +62,6 @@ return 0 -//For projectiles that actually represent clouds of projectiles -/obj/item/projectile/bullet/pellet - name = "shrapnel" //'shrapnel' sounds more dangerous (i.e. cooler) than 'pellet' - damage = 20 - //icon_state = "bullet" //TODO: would be nice to have it's own icon state - var/pellets = 4 //number of pellets - var/range_step = 2 //projectile will lose a fragment each time it travels this distance. Can be a non-integer. - var/base_spread = 90 //lower means the pellets spread more across body parts. If zero then this is considered a shrapnel explosion instead of a shrapnel cone - var/spread_step = 10 //higher means the pellets spread more across body parts with distance - -/obj/item/projectile/bullet/pellet/Bumped() - . = ..() - bumped = 0 //can hit all mobs in a tile. pellets is decremented inside attack_mob so this should be fine. - -/obj/item/projectile/bullet/pellet/proc/get_pellets(var/distance) - var/pellet_loss = round((distance - 1)/range_step) //pellets lost due to distance - return max(pellets - pellet_loss, 1) - -/obj/item/projectile/bullet/pellet/attack_mob(var/mob/living/target_mob, var/distance, var/miss_modifier) - if (pellets < 0) return 1 - - var/total_pellets = get_pellets(distance) - var/spread = max(base_spread - (spread_step*distance), 0) - - //shrapnel explosions miss prone mobs with a chance that increases with distance - var/prone_chance = 0 - if(!base_spread) - prone_chance = max(spread_step*(distance - 2), 0) - - var/hits = 0 - for (var/i in 1 to total_pellets) - if(target_mob.lying && target_mob != original && prob(prone_chance)) - continue - - //pellet hits spread out across different zones, but 'aim at' the targeted zone with higher probability - //whether the pellet actually hits the def_zone or a different zone should still be determined by the parent using get_zone_with_miss_chance(). - var/old_zone = def_zone - def_zone = ran_zone(def_zone, spread) - if (..()) hits++ - def_zone = old_zone //restore the original zone the projectile was aimed at - - pellets -= hits //each hit reduces the number of pellets left - if (hits >= total_pellets || pellets <= 0) - return 1 - return 0 - -/obj/item/projectile/bullet/pellet/get_structure_damage() - var/distance = get_dist(loc, starting) - return ..() * get_pellets(distance) - -/obj/item/projectile/bullet/pellet/Move() - . = ..() - - //If this is a shrapnel explosion, allow mobs that are prone to get hit, too - if(. && !base_spread && isturf(loc)) - for(var/mob/living/M in loc) - if(M.lying || !M.CanPass(src, loc)) //Bump if lying or if we would normally Bump. - if(Bump(M)) //Bump will make sure we don't hit a mob multiple times - return - /* short-casing projectiles, like the kind used in pistols or SMGs */ /obj/item/projectile/bullet/pistol diff --git a/code/modules/projectiles/projectile/pellets.dm b/code/modules/projectiles/projectile/pellets.dm new file mode 100644 index 00000000000..1c815f0bc2e --- /dev/null +++ b/code/modules/projectiles/projectile/pellets.dm @@ -0,0 +1,106 @@ + +//For projectiles that actually represent clouds of projectiles +/obj/item/projectile/bullet/pellet + name = "shrapnel" //'shrapnel' sounds more dangerous (i.e. cooler) than 'pellet' + damage = 20 + //icon_state = "bullet" //TODO: would be nice to have it's own icon state + var/pellets = 4 //number of pellets + var/range_step = 2 //projectile will lose a fragment each time it travels this distance. Can be a non-integer. + var/base_spread = 90 //lower means the pellets spread more across body parts. If zero then this is considered a shrapnel explosion instead of a shrapnel cone + var/spread_step = 10 //higher means the pellets spread more across body parts with distance + +/obj/item/projectile/bullet/pellet/Bumped() + . = ..() + bumped = 0 //can hit all mobs in a tile. pellets is decremented inside attack_mob so this should be fine. + +/obj/item/projectile/bullet/pellet/proc/get_pellets(var/distance) + var/pellet_loss = round((distance - 1)/range_step) //pellets lost due to distance + return max(pellets - pellet_loss, 1) + +/obj/item/projectile/bullet/pellet/attack_mob(var/mob/living/target_mob, var/distance, var/miss_modifier) + if (pellets < 0) return 1 + + var/total_pellets = get_pellets(distance) + var/spread = max(base_spread - (spread_step*distance), 0) + + //shrapnel explosions miss prone mobs with a chance that increases with distance + var/prone_chance = 0 + if(!base_spread) + prone_chance = max(spread_step*(distance - 2), 0) + + var/hits = 0 + for (var/i in 1 to total_pellets) + if(target_mob.lying && target_mob != original && prob(prone_chance)) + continue + + //pellet hits spread out across different zones, but 'aim at' the targeted zone with higher probability + //whether the pellet actually hits the def_zone or a different zone should still be determined by the parent using get_zone_with_miss_chance(). + var/old_zone = def_zone + def_zone = ran_zone(def_zone, spread) + if (..()) hits++ + def_zone = old_zone //restore the original zone the projectile was aimed at + + pellets -= hits //each hit reduces the number of pellets left + if (hits >= total_pellets || pellets <= 0) + return 1 + return 0 + +/obj/item/projectile/bullet/pellet/get_structure_damage() + var/distance = get_dist(loc, starting) + return ..() * get_pellets(distance) + +/obj/item/projectile/bullet/pellet/Move() + . = ..() + + //If this is a shrapnel explosion, allow mobs that are prone to get hit, too + if(. && !base_spread && isturf(loc)) + for(var/mob/living/M in loc) + if(M.lying || !M.CanPass(src, loc)) //Bump if lying or if we would normally Bump. + if(Bump(M)) //Bump will make sure we don't hit a mob multiple times + return + +//Explosive grenade projectile, borrowed from fragmentation grenade code. +/obj/item/projectile/bullet/pellet/fragment + damage = 10 + armor_penetration = 30 + range_step = 2 //projectiles lose a fragment each time they travel this distance. Can be a non-integer. + + base_spread = 0 //causes it to be treated as a shrapnel explosion instead of cone + spread_step = 20 + + silenced = 1 //embedding messages are still produced so it's kind of weird when enabled. + no_attack_log = 1 + muzzle_type = null + +/obj/item/projectile/bullet/pellet/fragment/strong + damage = 15 + armor_penetration = 20 + +// Tank rupture fragments +/obj/item/projectile/bullet/pellet/fragment/tank + name = "metal fragment" + damage = 9 //Big chunks flying off. + range_step = 2 //controls damage falloff with distance. projectiles lose a "pellet" each time they travel this distance. Can be a non-integer. + + base_spread = 0 //causes it to be treated as a shrapnel explosion instead of cone + spread_step = 20 + + armor_penetration = 20 + + silenced = 1 + no_attack_log = 1 + muzzle_type = null + pellets = 3 + +/obj/item/projectile/bullet/pellet/fragment/tank/small + name = "small metal fragment" + damage = 6 + armor_penetration = 5 + pellets = 5 + +/obj/item/projectile/bullet/pellet/fragment/tank/big + name = "large metal fragment" + damage = 17 + armor_penetration = 10 + range_step = 5 //controls damage falloff with distance. projectiles lose a "pellet" each time they travel this distance. Can be a non-integer. + pellets = 1 \ No newline at end of file diff --git a/polaris.dme b/polaris.dme index bbe642cdd1c..a223cb4ba1a 100644 --- a/polaris.dme +++ b/polaris.dme @@ -981,6 +981,7 @@ #include "code\game\objects\items\weapons\grenades\explosive.dm" #include "code\game\objects\items\weapons\grenades\flashbang.dm" #include "code\game\objects\items\weapons\grenades\grenade.dm" +#include "code\game\objects\items\weapons\grenades\projectile.dm" #include "code\game\objects\items\weapons\grenades\smokebomb.dm" #include "code\game\objects\items\weapons\grenades\spawnergrenade.dm" #include "code\game\objects\items\weapons\grenades\supermatter.dm" @@ -2166,6 +2167,7 @@ #include "code\modules\projectiles\projectile\energy.dm" #include "code\modules\projectiles\projectile\force.dm" #include "code\modules\projectiles\projectile\magnetic.dm" +#include "code\modules\projectiles\projectile\pellets.dm" #include "code\modules\projectiles\projectile\special.dm" #include "code\modules\projectiles\targeting\targeting_client.dm" #include "code\modules\projectiles\targeting\targeting_gun.dm"