diff --git a/code/game/objects/effects/spawners/bombspawner.dm b/code/game/objects/effects/spawners/bombspawner.dm index fb4716043f..7f2f509d01 100644 --- a/code/game/objects/effects/spawners/bombspawner.dm +++ b/code/game/objects/effects/spawners/bombspawner.dm @@ -111,15 +111,15 @@ set name = "Instant TTV" if(!check_rights(R_SPAWN)) return - + var/obj/effect/spawner/newbomb/proto = /obj/effect/spawner/newbomb/radio/custom - + var/p = input("Enter phoron amount (mol):","Phoron", initial(proto.phoron_amt)) as num|null if(p == null) return - + var/o = input("Enter oxygen amount (mol):","Oxygen", initial(proto.oxygen_amt)) as num|null if(o == null) return - + var/c = input("Enter carbon dioxide amount (mol):","Carbon Dioxide", initial(proto.carbon_amt)) as num|null if(c == null) return @@ -129,13 +129,13 @@ name = "TTV bomb" icon = 'icons/mob/screen1.dmi' icon_state = "x" - + var/assembly_type = /obj/item/device/assembly/signaler - + //Note that the maximum amount of gas you can put in a 70L air tank at 1013.25 kPa and 519K is 16.44 mol. - var/phoron_amt = 10.96 - var/oxygen_amt = 16.44 - var/carbon_amt = 0.0 + var/phoron_amt = 12 + var/oxygen_amt = 18 + var/carbon_amt = 0 /obj/effect/spawner/newbomb/timer name = "TTV bomb - timer" @@ -144,8 +144,8 @@ /obj/effect/spawner/newbomb/timer/syndicate name = "TTV bomb - merc" //High yield bombs. Yes, it is possible to make these with toxins - phoron_amt = 15.66 - oxygen_amt = 24.66 + phoron_amt = 18.5 + oxygen_amt = 28.5 /obj/effect/spawner/newbomb/proximity name = "TTV bomb - proximity" @@ -170,15 +170,20 @@ PT.master = V OT.master = V - PT.air_contents.temperature = PHORON_FLASHPOINT + PT.valve_welded = 1 PT.air_contents.gas["phoron"] = phoron_amt PT.air_contents.gas["carbon_dioxide"] = carbon_amt + PT.air_contents.total_moles = phoron_amt + carbon_amt + PT.air_contents.temperature = PHORON_MINIMUM_BURN_TEMPERATURE+1 PT.air_contents.update_values() - OT.air_contents.temperature = PHORON_FLASHPOINT + OT.valve_welded = 1 OT.air_contents.gas["oxygen"] = oxygen_amt + OT.air_contents.total_moles = oxygen_amt + OT.air_contents.temperature = PHORON_MINIMUM_BURN_TEMPERATURE+1 OT.air_contents.update_values() + var/obj/item/device/assembly/S = new assembly_type(V) @@ -190,3 +195,62 @@ V.update_icon() qdel(src) + + + +/////////////////////// +//One Tank Bombs, WOOOOOOO! -Luke +/////////////////////// + +/obj/effect/spawner/onetankbomb + name = "Single-tank bomb" + icon = 'icons/mob/screen1.dmi' + icon_state = "x" + +// var/assembly_type = /obj/item/device/assembly/signaler + + //Note that the maximum amount of gas you can put in a 70L air tank at 1013.25 kPa and 519K is 16.44 mol. + var/phoron_amt = 0 + var/oxygen_amt = 0 + +/obj/effect/spawner/onetankbomb/New(newloc) //just needs an assembly. + ..(newloc) + + var/type = pick(/obj/item/weapon/tank/phoron/onetankbomb, /obj/item/weapon/tank/oxygen/onetankbomb) + new type(src.loc) + + qdel(src) + +/obj/effect/spawner/onetankbomb/full + name = "Single-tank bomb" + icon = 'icons/mob/screen1.dmi' + icon_state = "x" + +// var/assembly_type = /obj/item/device/assembly/signaler + + //Note that the maximum amount of gas you can put in a 70L air tank at 1013.25 kPa and 519K is 16.44 mol. +/obj/effect/spawner/onetankbomb/full/New(newloc) //just needs an assembly. + ..(newloc) + + var/type = pick(/obj/item/weapon/tank/phoron/onetankbomb/full, /obj/item/weapon/tank/oxygen/onetankbomb/full) + new type(src.loc) + + qdel(src) + +/obj/effect/spawner/onetankbomb/frag + name = "Single-tank bomb" + icon = 'icons/mob/screen1.dmi' + icon_state = "x" + +// var/assembly_type = /obj/item/device/assembly/signaler + + //Note that the maximum amount of gas you can put in a 70L air tank at 1013.25 kPa and 519K is 16.44 mol. +/obj/effect/spawner/onetankbomb/full/New(newloc) //just needs an assembly. + ..(newloc) + + var/type = pick(/obj/item/weapon/tank/phoron/onetankbomb/full, /obj/item/weapon/tank/oxygen/onetankbomb/full) + new type(src.loc) + + qdel(src) + + diff --git a/code/game/objects/items/weapons/grenades/explosive.dm b/code/game/objects/items/weapons/grenades/explosive.dm index 62d13c3a2b..ccf8b89ee2 100644 --- a/code/game/objects/items/weapons/grenades/explosive.dm +++ b/code/game/objects/items/weapons/grenades/explosive.dm @@ -27,13 +27,17 @@ 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." icon_state = "frggrenade" item_state = "grenade" - var/fragment_type = /obj/item/projectile/bullet/pellet/fragment + var/fragment_types = list(/obj/item/projectile/bullet/pellet/fragment, /obj/item/projectile/bullet/pellet/fragment, /obj/item/projectile/bullet/pellet/fragment, /obj/item/projectile/bullet/pellet/fragment/strong) var/num_fragments = 63 //total number of fragments produced by the grenade var/explosion_size = 2 //size of the center explosion @@ -48,29 +52,49 @@ if(!O) return if(explosion_size) - explosion(O, -1, -1, 2, round(explosion_size/2), 0) + on_explosion(O) + src.fragmentate(O, num_fragments, spread_range, fragment_types) + qdel(src) - var/list/target_turfs = getcircle(O, spread_range) - var/fragments_per_projectile = round(num_fragments/target_turfs.len) - for(var/turf/T in target_turfs) - var/obj/item/projectile/bullet/pellet/fragment/P = new (O) +/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 + var/list/target_turfs = getcircle(T, spreading_range) + var/fragments_per_projectile = round(fragment_number/target_turfs.len) + for(var/turf/O in target_turfs) + sleep(0) + var/fragment_type = pickweight(fragtypes) + var/obj/item/projectile/bullet/pellet/fragment/P = new fragment_type(T) P.pellets = fragments_per_projectile P.shot_from = src.name - P.launch(T) - - //var/cone = new /obj/item/weapon/caution/cone (T) - //spawn(100) qdel(cone) + P.launch(O) //Make sure to hit any mobs in the source turf - for(var/mob/living/M in O) + 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, 0) + 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 - 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) + + +/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 diff --git a/code/game/objects/items/weapons/grenades/fragmentation.dm b/code/game/objects/items/weapons/grenades/fragmentation.dm deleted file mode 100644 index 9f10e9b4d4..0000000000 --- a/code/game/objects/items/weapons/grenades/fragmentation.dm +++ /dev/null @@ -1,61 +0,0 @@ -//Fragmentation grenade projectile -/obj/item/projectile/bullet/pellet/fragment - damage = 15 - range_step = 2 - - 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/weapon/grenade/frag - name = "fragmentation grenade" - desc = "A military fragmentation grenade, designed to explode in a deadly shower of fragments." - icon_state = "frag" - loadable = null - - var/num_fragments = 200 //total number of fragments produced by the grenade - var/fragment_damage = 15 - var/damage_step = 2 //projectiles lose a fragment each time they travel this distance. Can be a non-integer. - var/explosion_size = 2 //size of the center explosion - - //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 - -/obj/item/weapon/grenade/frag/prime() - ..() - - var/turf/O = get_turf(src) - if(!O) return - - if(explosion_size) - explosion(O, -1, round(explosion_size/2), explosion_size, round(explosion_size/2), 0) - - var/list/target_turfs = getcircle(O, spread_range) - var/fragments_per_projectile = round(num_fragments/target_turfs.len) - - for(var/turf/T in target_turfs) - var/obj/item/projectile/bullet/pellet/fragment/P = new (O) - - P.damage = fragment_damage - P.pellets = fragments_per_projectile - P.range_step = damage_step - P.shot_from = src.name - - P.launch(T) - - //var/cone = new /obj/item/weapon/caution/cone (T) - //spawn(100) qdel(cone) - - //Make sure to hit any mobs in the source turf - for(var/mob/living/M in O) - //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, 0) - else - P.attack_mob(M, 0, 100) //otherwise, allow a decent amount of fragments to pass - - qdel(src) diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm index b8daa05d7f..0787b2c873 100644 --- a/code/game/objects/items/weapons/tanks/tanks.dm +++ b/code/game/objects/items/weapons/tanks/tanks.dm @@ -16,26 +16,49 @@ var/list/global/tank_gauge_cache = list() slot_flags = SLOT_BACK w_class = ITEMSIZE_NORMAL - pressure_resistance = ONE_ATMOSPHERE*5 - force = 5.0 throwforce = 10.0 throw_speed = 1 throw_range = 4 - sprite_sheets = list( - "Teshari" = 'icons/mob/species/seromi/back.dmi' - ) - var/datum/gas_mixture/air_contents = null var/distribute_pressure = ONE_ATMOSPHERE - var/integrity = 3 + var/integrity = 20 + var/maxintegrity = 20 + var/valve_welded = 0 + var/obj/item/device/tankassemblyproxy/proxyassembly + var/volume = 70 var/manipulated_by = null //Used by _onclick/hud/screen_objects.dm internals to determine if someone has messed with our tank or not. //If they have and we haven't scanned it with the PDA or gas analyzer then we might just breath whatever they put in it. + + var/failure_temp = 173 //173 deg C Borate seal (yes it should be 153 F, but that's annoying) + var/leaking = 0 + var/wired = 0 + + description_info = "These tanks are utilised to store any of the various types of gaseous substances. \ + They can be attached to various portable atmospheric devices to be filled or emptied.
\ +
\ + Each tank is fitted with an emergency relief valve. This relief valve will open if the tank is pressurised to over ~3000kPa or heated to over 173ºC. \ + The valve itself will close after expending most or all of the contents into the air.
\ +
\ + Filling a tank such that experiences ~4000kPa of pressure will cause the tank to rupture, spilling out its contents and destroying the tank. \ + Tanks filled over ~5000kPa will rupture rather violently, exploding with significant force." + + description_antag = "Each tank may be incited to burn by attaching wires and an igniter assembly, though the igniter can only be used once and the mixture only burn if the igniter pushes a flammable gas mixture above the minimum burn temperature (126ºC). \ + Wired and assembled tanks may be disarmed with a set of wirecutters. Any exploding or rupturing tank will generate shrapnel, assuming their relief valves have been welded beforehand. Even if not, they can be incited to expel hot gas on ignition if pushed above 173ºC. \ + Relatively easy to make, the single tank bomb requries no tank transfer valve, and is still a fairly formidable weapon that can be manufactured from any tank." + +/obj/item/weapon/tank/proc/init_proxy() + var/obj/item/device/tankassemblyproxy/proxy = new /obj/item/device/tankassemblyproxy(src) + proxy.tank = src + src.proxyassembly = proxy + + /obj/item/weapon/tank/New() ..() + src.init_proxy() src.air_contents = new /datum/gas_mixture() src.air_contents.volume = volume //liters src.air_contents.temperature = T20C @@ -44,15 +67,17 @@ var/list/global/tank_gauge_cache = list() return /obj/item/weapon/tank/Destroy() - qdel_null(air_contents) + qdel(air_contents) processing_objects.Remove(src) + qdel(src.proxyassembly) if(istype(loc, /obj/item/device/transfer_valve)) var/obj/item/device/transfer_valve/TTV = loc TTV.remove_tank(src) + qdel(TTV) - return ..() + . = ..() /obj/item/weapon/tank/examine(mob/user) . = ..(user, 0) @@ -70,9 +95,17 @@ var/list/global/tank_gauge_cache = list() descriptive = "lukewarm" if(20 to 40) descriptive = "room temperature" - else + if(-20 to 20) descriptive = "cold" - user << "\The [src] feels [descriptive]." + else + descriptive = "bitterly cold" + to_chat(user, "\The [src] feels [descriptive].") + + if(src.proxyassembly.assembly || wired) + to_chat(user, "It seems to have [wired? "some wires ": ""][wired && src.proxyassembly.assembly? "and ":""][src.proxyassembly.assembly ? "some sort of assembly ":""]attached to it.") + if(src.valve_welded) + to_chat(user, "\The [src] emergency relief valve has been welded shut!") + /obj/item/weapon/tank/attackby(obj/item/weapon/W as obj, mob/user as mob) ..() @@ -87,15 +120,103 @@ var/list/global/tank_gauge_cache = list() LB.blow(src) src.add_fingerprint(user) + if(istype(W, /obj/item/stack/cable_coil)) + var/obj/item/stack/cable_coil/C = W + if(C.use(1)) + wired = 1 + to_chat(user, "You attach the wires to the tank.") + src.add_bomb_overlay() + + if(istype(W, /obj/item/weapon/wirecutters)) + if(wired && src.proxyassembly.assembly) + + to_chat(user, "You carefully begin clipping the wires that attach to the tank.") + if(do_after(user, 100,src)) + wired = 0 + src.overlays -= "bomb_assembly" + to_chat(user, "You cut the wire and remove the device.") + + var/obj/item/device/assembly_holder/assy = src.proxyassembly.assembly + if(assy.a_left && assy.a_right) + assy.dropInto(usr.loc) + assy.master = null + src.proxyassembly.assembly = null + else + if(!src.proxyassembly.assembly.a_left) + assy.a_right.dropInto(usr.loc) + assy.a_right.holder = null + assy.a_right = null + src.proxyassembly.assembly = null + qdel(assy) + src.overlays.Cut() + last_gauge_pressure = 0 + update_gauge() + + else + to_chat(user, "You slip and bump the igniter!") + if(prob(85)) + src.proxyassembly.receive_signal() + + else if(wired) + if(do_after(user, 10, src)) + to_chat(user, "You quickly clip the wire from the tank.") + wired = 0 + src.overlays -= "bomb_assembly" + + else + to_chat(user, "There are no wires to cut!") + + + if(istype(W, /obj/item/device/assembly_holder)) - bomb_assemble(W,user) + if(wired) + to_chat(user, "You begin attaching the assembly to \the [src].") + if(do_after(user, 50, src)) + to_chat(user, "You finish attaching the assembly to \the [src].") + bombers += "[key_name(user)] attached an assembly to a wired [src]. Temp: [src.air_contents.temperature-T0C]" + message_admins("[key_name_admin(user)] attached an assembly to a wired [src]. Temp: [src.air_contents.temperature-T0C]") + assemble_bomb(W,user) + else + to_chat(user, "You stop attaching the assembly.") + else + to_chat(user, "You need to wire the device up first.") + + + if(istype(W, /obj/item/weapon/weldingtool/)) + var/obj/item/weapon/weldingtool/WT = W + if(WT.remove_fuel(1,user)) + if(!valve_welded) + to_chat(user, "You begin welding the \the [src] emergency pressure relief valve.") + if(do_after(user, 40,src)) + to_chat(user, "You carefully weld \the [src] emergency pressure relief valve shut. \The [src] may now rupture under pressure!") + src.valve_welded = 1 + src.leaking = 0 + else + bombers += "[key_name(user)] attempted to weld a [src]. [src.air_contents.temperature-T0C]" + message_admins("[key_name_admin(user)] attempted to weld a [src]. [src.air_contents.temperature-T0C]") + if(WT.welding) + to_chat(user, "You accidentally rake \the [W] across \the [src]!") + maxintegrity -= rand(2,6) + integrity = min(integrity,maxintegrity) + src.air_contents.add_thermal_energy(rand(2000,50000)) + WT.eyecheck(user) + else + to_chat(user, "The emergency pressure relief valve has already been welded.") + add_fingerprint(user) + + /obj/item/weapon/tank/attack_self(mob/user as mob) + add_fingerprint(user) if (!(src.air_contents)) return - ui_interact(user) +// There's GOT to be a better way to do this + if (src.proxyassembly.assembly) + src.proxyassembly.assembly.attack_self(user) + + /obj/item/weapon/tank/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) var/mob/living/carbon/location = null @@ -117,7 +238,6 @@ var/list/global/tank_gauge_cache = list() data["defaultReleasePressure"] = round(TANK_DEFAULT_RELEASE_PRESSURE) data["maxReleasePressure"] = round(TANK_MAX_RELEASE_PRESSURE) data["valveOpen"] = using_internal ? 1 : 0 - data["maskConnected"] = 0 if(istype(location)) @@ -170,35 +290,38 @@ var/list/global/tank_gauge_cache = list() src.distribute_pressure += cp src.distribute_pressure = min(max(round(src.distribute_pressure), 0), TANK_MAX_RELEASE_PRESSURE) if (href_list["stat"]) - if(istype(loc,/mob/living/carbon)) - var/mob/living/carbon/location = loc - if(location.internal == src) - location.internal = null - location.internals.icon_state = "internal0" - usr << "You close the tank release valve." - if (location.internals) - location.internals.icon_state = "internal0" - else - - var/can_open_valve - if(location.wear_mask && (location.wear_mask.item_flags & AIRTIGHT)) - can_open_valve = 1 - else if(istype(location,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = location - if(H.head && (H.head.item_flags & AIRTIGHT)) - can_open_valve = 1 - - if(can_open_valve) - location.internal = src - usr << "You open \the [src] valve." - if (location.internals) - location.internals.icon_state = "internal1" - else - usr << "You need something to connect to \the [src]." + toggle_valve(usr) src.add_fingerprint(usr) return 1 +/obj/item/weapon/tank/proc/toggle_valve(var/mob/user) + if(istype(loc,/mob/living/carbon)) + var/mob/living/carbon/location = loc + if(location.internal == src) + location.internal = null + location.internals.icon_state = "internal0" + to_chat(user, "You close the tank release valve.") + if (location.internals) + location.internals.icon_state = "internal0" + else + var/can_open_valve + if(location.wear_mask && (location.wear_mask.item_flags & AIRTIGHT)) + can_open_valve = 1 + else if(istype(location,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = location + if(H.head && (H.head.item_flags & AIRTIGHT)) + can_open_valve = 1 + + if(can_open_valve) + location.internal = src + to_chat(user, "You open \the [src] valve.") + if (location.internals) + location.internals.icon_state = "internal1" + else + to_chat(user, "You need something to connect to \the [src].") + + /obj/item/weapon/tank/remove_air(amount) return air_contents.remove(amount) @@ -231,6 +354,17 @@ var/list/global/tank_gauge_cache = list() update_gauge() check_status() + +/obj/item/weapon/tank/proc/add_bomb_overlay() + if(src.wired) + src.overlays += "bomb_assembly" + if(src.proxyassembly.assembly) + var/icon/test = getFlatIcon(src.proxyassembly.assembly) + test.Shift(SOUTH,1) + test.Shift(WEST,3) + overlays += test + + /obj/item/weapon/tank/proc/update_gauge() var/gauge_pressure = 0 if(air_contents) @@ -245,11 +379,17 @@ var/list/global/tank_gauge_cache = list() last_gauge_pressure = gauge_pressure overlays.Cut() + add_bomb_overlay() var/indicator = "[gauge_icon][(gauge_pressure == -1) ? "overload" : gauge_pressure]" if(!tank_gauge_cache[indicator]) tank_gauge_cache[indicator] = image(icon, indicator) overlays += tank_gauge_cache[indicator] + + + + + /obj/item/weapon/tank/proc/check_status() //Handle exploding, leaking, and rupturing of the tank @@ -257,31 +397,61 @@ var/list/global/tank_gauge_cache = list() return 0 var/pressure = air_contents.return_pressure() + + if(pressure > TANK_FRAGMENT_PRESSURE) - if(!istype(src.loc,/obj/item/device/transfer_valve)) - message_admins("Explosive tank rupture! last key to touch the tank was [src.fingerprintslast].") - log_game("Explosive tank rupture! last key to touch the tank was [src.fingerprintslast].") + if(integrity <= 7) + if(!istype(src.loc,/obj/item/device/transfer_valve)) + message_admins("Explosive tank rupture! last key to touch the tank was [src.fingerprintslast].") + log_game("Explosive tank rupture! last key to touch the tank was [src.fingerprintslast].") - //Give the gas a chance to build up more pressure through reacting - air_contents.react() - air_contents.react() - air_contents.react() + //Give the gas a chance to build up more pressure through reacting + air_contents.react() + air_contents.react() + air_contents.react() - pressure = air_contents.return_pressure() - var/range = (pressure-TANK_FRAGMENT_PRESSURE)/TANK_FRAGMENT_SCALE + pressure = air_contents.return_pressure() + var/strength = ((pressure-TANK_FRAGMENT_PRESSURE)/TANK_FRAGMENT_SCALE) + + var/mult = ((src.air_contents.volume/140)**(1/2)) * (air_contents.total_moles**2/3)/((29*0.64) **2/3) //tanks appear to be experiencing a reduction on scale of about 0.64 total moles + //tanks appear to be experiencing a reduction on scale of about 0.64 total moles + + + + var/turf/simulated/T = get_turf(src) + T.hotspot_expose(src.air_contents.temperature, 70, 1) + if(!T) + return + + T.assume_air(air_contents) + explosion( + get_turf(loc), + round(min(BOMBCAP_DVSTN_RADIUS, ((mult)*strength)*0.15)), + round(min(BOMBCAP_HEAVY_RADIUS, ((mult)*strength)*0.35)), + round(min(BOMBCAP_LIGHT_RADIUS, ((mult)*strength)*0.80)), + round(min(BOMBCAP_FLASH_RADIUS, ((mult)*strength)*1.20)), + ) + + + var/num_fragments = round(rand(8,10) * sqrt(strength * mult)) + src.fragmentate(T, num_fragments, rand(5) + 7, list(/obj/item/projectile/bullet/pellet/fragment/tank/small = 7,/obj/item/projectile/bullet/pellet/fragment/tank = 2,/obj/item/projectile/bullet/pellet/fragment/strong = 1)) + + if(istype(loc, /obj/item/device/transfer_valve)) + var/obj/item/device/transfer_valve/TTV = loc + TTV.remove_tank(src) + qdel(TTV) + + + if(src) + qdel(src) + + else + integrity -=7 - explosion( - get_turf(loc), - round(min(BOMBCAP_DVSTN_RADIUS, range*0.25)), - round(min(BOMBCAP_HEAVY_RADIUS, range*0.50)), - round(min(BOMBCAP_LIGHT_RADIUS, range*1.00)), - round(min(BOMBCAP_FLASH_RADIUS, range*1.50)), - ) - qdel(src) else if(pressure > TANK_RUPTURE_PRESSURE) #ifdef FIREDBG - log_debug("\blue[x],[y] tank is rupturing: [pressure] kPa, integrity [integrity]") + log_debug("[x],[y] tank is rupturing: [pressure] kPa, integrity [integrity]") #endif if(integrity <= 0) @@ -289,24 +459,231 @@ var/list/global/tank_gauge_cache = list() if(!T) return T.assume_air(air_contents) - playsound(src.loc, 'sound/effects/spray.ogg', 10, 1, -3) + playsound(get_turf(src), 'sound/weapons/shotgun.ogg', 20, 1) + visible_message("\icon[src] \The [src] flies apart!", "You hear a bang!") + T.hotspot_expose(air_contents.temperature, 70, 1) + + + var/strength = 1+((pressure-TANK_LEAK_PRESSURE)/TANK_FRAGMENT_SCALE) + + var/mult = (air_contents.total_moles**2/3)/((29*0.64) **2/3) //tanks appear to be experiencing a reduction on scale of about 0.64 total moles + + var/num_fragments = round(rand(6,8) * sqrt(strength * mult)) //Less chunks, but bigger + src.fragmentate(T, num_fragments, 7, list(/obj/item/projectile/bullet/pellet/fragment/tank/small = 1,/obj/item/projectile/bullet/pellet/fragment/tank = 5,/obj/item/projectile/bullet/pellet/fragment/strong = 4)) + + if(istype(loc, /obj/item/device/transfer_valve)) + var/obj/item/device/transfer_valve/TTV = loc + TTV.remove_tank(src) + + qdel(src) + else - integrity-- + integrity-= 5 - else if(pressure > TANK_LEAK_PRESSURE) - #ifdef FIREDBG - log_debug("\blue[x],[y] tank is leaking: [pressure] kPa, integrity [integrity]") - #endif - if(integrity <= 0) + else if(pressure > TANK_LEAK_PRESSURE || air_contents.temperature - T0C > failure_temp) + + if((integrity <= 19 || src.leaking) && !valve_welded) var/turf/simulated/T = get_turf(src) if(!T) return - var/datum/gas_mixture/leaked_gas = air_contents.remove_ratio(0.25) - T.assume_air(leaked_gas) - else - integrity-- + var/datum/gas_mixture/environment = loc.return_air() + var/env_pressure = environment.return_pressure() + var/tank_pressure = src.air_contents.return_pressure() - else if(integrity < 3) - integrity++ + var/release_ratio = Clamp(0.002, sqrt(max(tank_pressure-env_pressure,0)/tank_pressure),1) + var/datum/gas_mixture/leaked_gas = air_contents.remove_ratio(release_ratio) + //dynamic air release based on ambient pressure + + T.assume_air(leaked_gas) + if(!leaking) + visible_message("\icon[src] \The [src] relief valve flips open with a hiss!", "You hear hissing.") + playsound(src.loc, 'sound/effects/spray.ogg', 10, 1, -3) + leaking = 1 + #ifdef FIREDBG + log_debug("[x],[y] tank is leaking: [pressure] kPa, integrity [integrity]") + #endif + + + else + integrity-= 2 + + + else + if(integrity < maxintegrity) + integrity++ + if(leaking) + integrity++ + if(integrity == maxintegrity) + leaking = 0 + +///////////////////////////////// +///Prewelded tanks +///////////////////////////////// + +/obj/item/weapon/tank/phoron/welded + valve_welded = 1 +/obj/item/weapon/tank/oxygen/welded + valve_welded = 1 + + +///////////////////////////////// +///Onetankbombs (added as actual items) +///////////////////////////////// + +/obj/item/weapon/tank/proc/onetankbomb(var/fill = 1) + var/phoron_amt = 4 + rand(4) + var/oxygen_amt = 6 + rand(8) + + if(fill == 2) + phoron_amt = 10 + oxygen_amt = 15 + else if (!fill) + phoron_amt = 3 + oxygen_amt = 4.5 + + + src.air_contents.gas["phoron"] = phoron_amt + src.air_contents.gas["oxygen"] = oxygen_amt + src.air_contents.update_values() + src.valve_welded = 1 + src.air_contents.temperature = PHORON_MINIMUM_BURN_TEMPERATURE-1 + + src.wired = 1 + + var/obj/item/device/assembly_holder/H = new(src) + src.proxyassembly.assembly = H + H.master = src.proxyassembly + + H.update_icon() + + src.overlays += "bomb_assembly" + + +/obj/item/weapon/tank/phoron/onetankbomb/New() + ..() + src.onetankbomb() + +/obj/item/weapon/tank/oxygen/onetankbomb/New() + ..() + src.onetankbomb() + + +/obj/item/weapon/tank/phoron/onetankbomb/full/New() + ..() + src.onetankbomb(2) + +/obj/item/weapon/tank/oxygen/onetankbomb/full/New() + ..() + src.onetankbomb(2) + +/obj/item/weapon/tank/phoron/onetankbomb/small/New() + ..() + src.onetankbomb(0) + +/obj/item/weapon/tank/oxygen/onetankbomb/small/New() + ..() + src.onetankbomb(1) + +///////////////////////////////// +///Pulled from rewritten bomb.dm +///////////////////////////////// + +/obj/item/device/tankassemblyproxy + name = "Tank assembly proxy" + desc = "Used as a stand in to trigger single tank assemblies... but you shouldn't see this." + var/obj/item/weapon/tank/tank = null + var/obj/item/device/assembly_holder/assembly = null + + +/obj/item/device/tankassemblyproxy/receive_signal() //This is mainly called by the sensor through sense() to the holder, and from the holder to here. + tank.ignite() //boom (or not boom if you made shijwtty mix) + + +/obj/item/weapon/tank/proc/assemble_bomb(W,user) //Bomb assembly proc. This turns assembly+tank into a bomb + var/obj/item/device/assembly_holder/S = W + var/mob/M = user + if(!S.secured) //Check if the assembly is secured + return + if(isigniter(S.a_left) == isigniter(S.a_right)) //Check if either part of the assembly has an igniter, but if both parts are igniters, then fuck it + return + + + M.drop_item() //Remove the assembly from your hands + M.remove_from_mob(src) //Remove the tank from your character,in case you were holding it + M.put_in_hands(src) //Equips the bomb if possible, or puts it on the floor. + + src.proxyassembly.assembly = S //Tell the bomb about its assembly part + S.master = src.proxyassembly //Tell the assembly about its new owner + S.forceMove(src) //Move the assembly + + src.update_icon() + + + src.add_bomb_overlay() + + return + + +/obj/item/weapon/tank/proc/ignite() //This happens when a bomb is told to explode + + var/obj/item/device/assembly_holder/assy = src.proxyassembly.assembly + var/ign = assy.a_right + var/obj/item/other = assy.a_left + + if (isigniter(assy.a_left)) + ign = assy.a_left + other = assy.a_right + + other.dropInto(get_turf(src)) + qdel(ign) + assy.master = null + src.proxyassembly.assembly = null + qdel(assy) + src.update_icon() + src.update_gauge() + + air_contents.add_thermal_energy(15000) + + +/obj/item/device/tankassemblyproxy/update_icon() + if(assembly) + tank.update_icon() + tank.overlays += "bomb_assembly" + else + tank.update_icon() + tank.overlays -= "bomb_assembly" + +/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/assembly/bomb.dm b/code/modules/assembly/bomb.dm deleted file mode 100644 index e41576020e..0000000000 --- a/code/modules/assembly/bomb.dm +++ /dev/null @@ -1,155 +0,0 @@ -/obj/item/device/onetankbomb - name = "bomb" - icon = 'icons/obj/tank.dmi' - item_state = "assembly" - throwforce = 5 - w_class = ITEMSIZE_NORMAL - throw_speed = 2 - throw_range = 4 - flags = CONDUCT | PROXMOVE - var/status = 0 //0 - not readied //1 - bomb finished with welder - var/obj/item/device/assembly_holder/bombassembly = null //The first part of the bomb is an assembly holder, holding an igniter+some device - var/obj/item/weapon/tank/bombtank = null //the second part of the bomb is a phoron tank - -/obj/item/device/onetankbomb/examine(mob/user) - ..(user) - user.examinate(bombtank) - -/obj/item/device/onetankbomb/update_icon() - if(bombtank) - icon_state = bombtank.icon_state - if(bombassembly) - overlays += bombassembly.icon_state - overlays += bombassembly.overlays - overlays += "bomb_assembly" - -/obj/item/device/onetankbomb/attackby(obj/item/weapon/W as obj, mob/user as mob) - if(istype(W, /obj/item/device/analyzer)) - bombtank.attackby(W, user) - return - if(istype(W, /obj/item/weapon/wrench) && !status) //This is basically bomb assembly code inverted. apparently it works. - - user << "You disassemble [src]." - - bombassembly.loc = user.loc - bombassembly.master = null - bombassembly = null - - bombtank.loc = user.loc - bombtank.master = null - bombtank = null - - qdel(src) - return - if((istype(W, /obj/item/weapon/weldingtool) && W:welding)) - if(!status) - status = 1 - bombers += "[key_name(user)] welded a single tank bomb. Temp: [bombtank.air_contents.temperature-T0C]" - message_admins("[key_name_admin(user)] welded a single tank bomb. Temp: [bombtank.air_contents.temperature-T0C]") - user << "A pressure hole has been bored to [bombtank] valve. \The [bombtank] can now be ignited." - else - status = 0 - bombers += "[key_name(user)] unwelded a single tank bomb. Temp: [bombtank.air_contents.temperature-T0C]" - user << "The hole has been closed." - add_fingerprint(user) - ..() - -/obj/item/device/onetankbomb/attack_self(mob/user as mob) //pressing the bomb accesses its assembly - bombassembly.attack_self(user, 1) - add_fingerprint(user) - return - -/obj/item/device/onetankbomb/receive_signal() //This is mainly called by the sensor through sense() to the holder, and from the holder to here. - visible_message("\icon[src] *beep* *beep*", "*beep* *beep*") - sleep(10) - if(!src) - return - if(status) - bombtank.ignite() //if its not a dud, boom (or not boom if you made shitty mix) the ignite proc is below, in this file - else - bombtank.release() - -/obj/item/device/onetankbomb/HasProximity(atom/movable/AM as mob|obj) - if(bombassembly) - bombassembly.HasProximity(AM) - -// ---------- Procs below are for tanks that are used exclusively in 1-tank bombs ---------- - -/obj/item/weapon/tank/proc/bomb_assemble(W,user) //Bomb assembly proc. This turns assembly+tank into a bomb - var/obj/item/device/assembly_holder/S = W - var/mob/M = user - if(!S.secured) //Check if the assembly is secured - return - if(isigniter(S.a_left) == isigniter(S.a_right)) //Check if either part of the assembly has an igniter, but if both parts are igniters, then fuck it - return - - var/obj/item/device/onetankbomb/R = new /obj/item/device/onetankbomb(loc) - - M.drop_item() //Remove the assembly from your hands - M.remove_from_mob(src) //Remove the tank from your character,in case you were holding it - M.put_in_hands(R) //Equips the bomb if possible, or puts it on the floor. - - R.bombassembly = S //Tell the bomb about its assembly part - S.master = R //Tell the assembly about its new owner - S.loc = R //Move the assembly out of the fucking way - - R.bombtank = src //Same for tank - master = R - loc = R - R.update_icon() - return - -/obj/item/weapon/tank/proc/ignite() //This happens when a bomb is told to explode - var/fuel_moles = air_contents.gas["phoron"] + air_contents.gas["oxygen"] / 6 - var/strength = 1 - - var/turf/ground_zero = get_turf(loc) - loc = null - - if(air_contents.temperature > (T0C + 400)) - strength = (fuel_moles/15) - - if(strength >=1) - explosion(ground_zero, round(strength,1), round(strength*2,1), round(strength*3,1), round(strength*4,1)) - else if(strength >=0.5) - explosion(ground_zero, 0, 1, 2, 4) - else if(strength >=0.2) - explosion(ground_zero, -1, 0, 1, 2) - else - ground_zero.assume_air(air_contents) - ground_zero.hotspot_expose(1000, 125) - - else if(air_contents.temperature > (T0C + 250)) - strength = (fuel_moles/20) - - if(strength >=1) - explosion(ground_zero, 0, round(strength,1), round(strength*2,1), round(strength*3,1)) - else if (strength >=0.5) - explosion(ground_zero, -1, 0, 1, 2) - else - ground_zero.assume_air(air_contents) - ground_zero.hotspot_expose(1000, 125) - - else if(air_contents.temperature > (T0C + 100)) - strength = (fuel_moles/25) - - if (strength >=1) - explosion(ground_zero, -1, 0, round(strength,1), round(strength*3,1)) - else - ground_zero.assume_air(air_contents) - ground_zero.hotspot_expose(1000, 125) - - else - ground_zero.assume_air(air_contents) - ground_zero.hotspot_expose(1000, 125) - - if(master) - qdel(master) - qdel(src) - -/obj/item/weapon/tank/proc/release() //This happens when the bomb is not welded. Tank contents are just spat out. - var/datum/gas_mixture/removed = air_contents.remove(air_contents.total_moles) - var/turf/simulated/T = get_turf(src) - if(!T) - return - T.assume_air(removed) \ No newline at end of file diff --git a/code/modules/random_map/drop/drop_types.dm b/code/modules/random_map/drop/drop_types.dm index 8fb02007b4..722aeec09e 100644 --- a/code/modules/random_map/drop/drop_types.dm +++ b/code/modules/random_map/drop/drop_types.dm @@ -86,8 +86,8 @@ var/global/list/datum/supply_drop_loot/supply_drop /obj/item/ammo_magazine/m762/ap, /obj/item/ammo_magazine/m762, /obj/item/weapon/shield/energy, - /obj/item/weapon/grenade/frag, - /obj/item/weapon/grenade/frag, + /obj/item/weapon/grenade/explosive/frag, + /obj/item/weapon/grenade/explosive/frag, /obj/item/weapon/grenade/smokebomb, /obj/item/weapon/grenade/smokebomb, /obj/item/weapon/grenade/flashbang, diff --git a/polaris.dme b/polaris.dme index 462504dd79..475aa322ec 100644 --- a/polaris.dme +++ b/polaris.dme @@ -902,7 +902,6 @@ #include "code\game\objects\items\weapons\grenades\emgrenade.dm" #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\fragmentation.dm" #include "code\game\objects\items\weapons\grenades\grenade.dm" #include "code\game\objects\items\weapons\grenades\smokebomb.dm" #include "code\game\objects\items\weapons\grenades\spawnergrenade.dm" @@ -1156,7 +1155,6 @@ #include "code\modules\alarm\motion_alarm.dm" #include "code\modules\alarm\power_alarm.dm" #include "code\modules\assembly\assembly.dm" -#include "code\modules\assembly\bomb.dm" #include "code\modules\assembly\helpers.dm" #include "code\modules\assembly\holder.dm" #include "code\modules\assembly\igniter.dm"