diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm index 6f5a9d4e5c1..07e37e1fa9c 100644 --- a/code/__HELPERS/lists.dm +++ b/code/__HELPERS/lists.dm @@ -168,11 +168,9 @@ proc/listclearnulls(list/list) //Return a list with no duplicate entries /proc/uniquelist(var/list/L) - var/list/K = list() - for(var/item in L) - if(!(item in K)) - K += item - return K + . = list() + for(var/i in L) + . |= i //Mergesort: divides up the list into halves to begin the sort /proc/sortKey(var/list/client/L, var/order = 1) diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index e512fefc53a..a25c43cbbaf 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -62,6 +62,7 @@ var/automute_on = 0 //enables automuting/spam prevention var/jobs_have_minimal_access = 0 //determines whether jobs use minimal access or expanded access. + var/reactionary_explosions = 0 //If we use reactionary explosions, explosions that react to walls and doors var/assistantlimit = 0 //enables assistant limiting var/assistantratio = 2 //how many assistants to security members @@ -340,6 +341,9 @@ if("protect_roles_from_antagonist") config.protect_roles_from_antagonist = 1 + if("reactionary_explosions") + config.reactionary_explosions = 1 + if ("probability") var/prob_pos = findtext(value, " ") var/prob_name = null diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 108c4c8b2f6..d5317a1586d 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -22,6 +22,10 @@ var/global/list/ghdel_profiling = list() // replaced by OPENCONTAINER flags and atom/proc/is_open_container() ///Chemistry. + + //Value used to increment ex_act() if reactionary_explosions is on + var/explosion_block = 0 + //Detective Work, used for the duplicate data points kept in the scanners var/list/original_atom diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 64f9bc02add..ec8b45ef78b 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -49,6 +49,7 @@ var/hasShocked = 0 //Prevents multiple shocks from happening var/frozen = 0 //special condition for airlocks that are frozen shut, this will look weird on not normal airlocks because of a lack of special overlays. autoclose = 1 + explosion_block = 1 /obj/machinery/door/airlock/command name = "Airlock" @@ -283,6 +284,7 @@ name = "High Tech Security Airlock" icon = 'icons/obj/doors/hightechsecurity.dmi' assembly_type = /obj/structure/door_assembly/door_assembly_highsecurity + explosion_block = 2 /obj/machinery/door/airlock/highsecurity/red name = "Secure Armory Airlock" diff --git a/code/game/machinery/doors/poddoor.dm b/code/game/machinery/doors/poddoor.dm index 7348a57181c..36f62d6befd 100644 --- a/code/game/machinery/doors/poddoor.dm +++ b/code/game/machinery/doors/poddoor.dm @@ -4,6 +4,7 @@ icon = 'icons/obj/doors/rapid_pdoor.dmi' icon_state = "pdoor1" var/id = 1.0 + explosion_block = 3 /obj/machinery/door/poddoor/preopen icon_state = "pdoor0" @@ -24,6 +25,30 @@ else return 0 +//"BLAST" doors are obviously stronger than regular doors when it comes to BLASTS. +/obj/machinery/door/poddoor/ex_act(severity, target) + switch(severity) + if(1.0) + if(prob(80)) + qdel(src) + else + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(2, 1, src) + s.start() + if(2.0) + if(prob(20)) + qdel(src) + else + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(2, 1, src) + s.start() + + if(3.0) + if(prob(80)) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(2, 1, src) + s.start() + /obj/machinery/door/poddoor/attackby(obj/item/weapon/C as obj, mob/user as mob, params) src.add_fingerprint(user) if (!( istype(C, /obj/item/weapon/crowbar) || (istype(C, /obj/item/weapon/twohanded/fireaxe) && C:wielded == 1) )) diff --git a/code/game/machinery/doors/unpowered.dm b/code/game/machinery/doors/unpowered.dm index 8e03e874a71..90e71dc7b83 100644 --- a/code/game/machinery/doors/unpowered.dm +++ b/code/game/machinery/doors/unpowered.dm @@ -1,7 +1,7 @@ /obj/machinery/door/unpowered autoclose = 0 var/locked = 0 - + explosion_block = 1 Bumped(atom/AM) if(src.locked) diff --git a/code/game/objects/explosion.dm b/code/game/objects/explosion.dm index d8a5172888f..b88f63baab8 100644 --- a/code/game/objects/explosion.dm +++ b/code/game/objects/explosion.dm @@ -74,16 +74,43 @@ proc/explosion(turf/epicenter, devastation_range, heavy_impact_range, light_impa for(var/turf/T in trange(max_range, epicenter)) var/dist = cheap_pythag(T.x - x0,T.y - y0) + if(config.reactionary_explosions) + var/turf/Trajectory = T + while(Trajectory != epicenter) + Trajectory = get_step_towards(Trajectory, epicenter) + if(Trajectory.density && Trajectory.explosion_block) + dist += Trajectory.explosion_block + + for(var/obj/machinery/door/D in Trajectory) + if(D.density && D.explosion_block) + dist += D.explosion_block + + var/throw_dist = dist + if(dist < devastation_range) dist = 1 else if(dist < heavy_impact_range) dist = 2 else if(dist < light_impact_range) dist = 3 - else continue + else dist = 0 - T.ex_act(dist) if(T) for(var/atom_movable in T.contents) //bypass type checking since only atom/movable can be contained by turfs anyway var/atom/movable/AM = atom_movable if(AM) AM.ex_act(dist) +// if(flame_dist && prob(40) && !istype(T, /turf/space) && !T.density) +// PoolOrNew(/obj/effect/hotspot, T) //Mostly for ambience! + if(dist > 0) + T.ex_act(dist) + + //--- THROW ITEMS AROUND --- + + var/throw_dir = get_dir(epicenter,T) + for(var/obj/item/I in T) + spawn(0) //Simultaneously not one at a time + if(I) + var/throw_range = rand(throw_dist, max_range) + var/turf/throw_at = get_ranged_target_turf(I, throw_dir, throw_range) + I.throw_speed = 4 //Temporarily change their throw_speed for embedding purposes (Reset when it finishes throwing, regardless of hitting anything) + I.throw_at(throw_at, throw_range, 2)//Throw it at 2 speed, this is purely visual anyway. var/took = (world.timeofday-start)/10 //You need to press the DebugGame verb to see these now....they were getting annoying and we've collected a fair bit of data. Just -test- changes to explosion code using this please so we can compare @@ -109,3 +136,71 @@ proc/explosion(turf/epicenter, devastation_range, heavy_impact_range, light_impa proc/secondaryexplosion(turf/epicenter, range) for(var/turf/tile in trange(range, epicenter)) tile.ex_act(2) + +/client/proc/check_bomb_impacts() + set name = "Check Bomb Impact" + set category = "Debug" + + var/newmode = alert("Use reactionary explosions?","Check Bomb Impact", "Yes", "No") + + var/turf/epicenter = get_turf(src) + var/dev = 0 + var/heavy = 0 + var/light = 0 + var/list/choices = list("Small Bomb","Medium Bomb","Big Bomb","Custom Bomb") + var/choice = input("Bomb Size?") in choices + switch(choice) + if(null) + return 0 + if("Small Bomb") + dev = 1 + heavy = 2 + light = 3 + if("Medium Bomb") + dev = 2 + heavy = 3 + light = 4 + if("Big Bomb") + dev = 3 + heavy = 5 + light = 7 + if("Custom Bomb") + dev = input("Devestation range (Tiles):") as num + heavy = input("Heavy impact range (Tiles):") as num + light = input("Light impact range (Tiles):") as num + + var/max_range = max(dev, heavy, light) + var/x0 = epicenter.x + var/y0 = epicenter.y + var/list/wipe_colours = list() + for(var/turf/T in trange(max_range, epicenter)) + wipe_colours += T + var/dist = cheap_pythag(T.x - x0, T.y - y0) + + if(newmode == "Yes") + var/turf/TT = T + while(TT != epicenter) + TT = get_step_towards(TT,epicenter) + if(TT.density && TT.explosion_block) + dist += TT.explosion_block + + for(var/obj/machinery/door/D in TT) + if(D.density && D.explosion_block) + dist += D.explosion_block + + if(dist < dev) + T.color = "red" + T.maptext = "Dev" + else if (dist < heavy) + T.color = "yellow" + T.maptext = "Heavy" + else if (dist < light) + T.color = "blue" + T.maptext = "Light" + else + continue + + sleep(100) + for(var/turf/T in wipe_colours) + T.color = null + T.maptext = "" diff --git a/code/game/objects/items/random_items.dm b/code/game/objects/items/random_items.dm index 0bbd8ba35aa..1a6ab66a72e 100644 --- a/code/game/objects/items/random_items.dm +++ b/code/game/objects/items/random_items.dm @@ -61,7 +61,7 @@ // identify_probability = 0 New() ..() - var/global/list/chems_only = list("slimejelly","blood","water","lube","charcoal","toxin","cyanide","morphine","epinephrine","space_drugs","serotrotium","oxygen","copper","nitrogen","hydrogen","potassium","mercury","sulfur","carbon","chlorine","fluorine","sodium","phosphorus","lithium","sugar","sacid","facid","glycerol","radium","mutadone","thermite","mutagen","virusfood","iron","gold","silver","uranium","aluminum","silicon","fuel","cleaner","atrazine","plasma","teporone","lexorin","silver_sulfadiazine","salbutamol","perfluorodecalin","omnizine","synaptizine","haloperidol","potass_iodide","pen_acid","mannitol","oculine","styptic_powder","methamphetamine","cryoxadone","clonexadone","spaceacillin","carpotoxin","mindbreaker","fluorosurfactant","fluorosurfactant","ethanol","ammonia","diethylamine","antihol","pancuronium","lipolicide","condensedcapsaicin","frostoil","amanitin","psilocybin","enzyme","nothing","salglu_solution","antifreeze","neurotoxin") + var/global/list/chems_only = list("slimejelly","blood","water","lube","charcoal","toxin","cyanide","morphine","epinephrine","space_drugs","serotrotium","oxygen","copper","nitrogen","hydrogen","potassium","mercury","sulfur","carbon","chlorine","fluorine","sodium","phosphorus","lithium","sugar","sacid","facid","glycerol","radium","mutadone","thermite","mutagen","virusfood","iron","gold","silver","uranium","aluminum","silicon","fuel","cleaner","atrazine","plasma","teporone","lexorin","silver_sulfadiazine","salbutamol","perfluorodecalin","omnizine","synaptizine","haloperidol","potass_iodide","pen_acid","mannitol","oculine","styptic_powder","methamphetamine","cryoxadone","spaceacillin","carpotoxin","mindbreaker","fluorosurfactant","fluorosurfactant","ethanol","ammonia","diethylamine","antihol","pancuronium","lipolicide","condensedcapsaicin","frostoil","amanitin","psilocybin","enzyme","nothing","salglu_solution","antifreeze","neurotoxin") var/global/list/rare_chems = list("minttoxin","nanites","xenomicrobes","adminordrazine") var/datum/reagent/R = pick(chems_only + rare_chems) diff --git a/code/game/objects/items/weapons/grenades.dm b/code/game/objects/items/weapons/grenades.dm index 74d2038edb7..3d6c101a109 100644 --- a/code/game/objects/items/weapons/grenades.dm +++ b/code/game/objects/items/weapons/grenades.dm @@ -30,7 +30,7 @@ B1.reagents.add_reagent("blood",60) if(prob(5)) B1.reagents.add_reagent("blood",1) // Quality control problems, causes a mess - B2.reagents.add_reagent("clonexadone",30) + B2.reagents.add_reagent("cryoxadone",30) beakers += B1 beakers += B2 diff --git a/code/game/objects/items/weapons/storage/storage.dm b/code/game/objects/items/weapons/storage/storage.dm index b22b813d1c1..613fe2d844c 100644 --- a/code/game/objects/items/weapons/storage/storage.dm +++ b/code/game/objects/items/weapons/storage/storage.dm @@ -38,6 +38,26 @@ show_to(M) return + if ((istype(over_object, /obj/structure/table) || istype(over_object, /turf/simulated/floor)) \ + && contents.len && loc == usr && !usr.stat && !usr.restrained() && usr.canmove && over_object.Adjacent(usr) \ + && !istype(src, /obj/item/weapon/storage/lockbox)) + var/turf/T = get_turf(over_object) + if (istype(over_object, /turf/simulated/floor)) + if (get_turf(usr) != T) + return // Can only empty containers onto the floor under you + if("Yes" != alert(usr,"Empty \the [src] onto \the [T]?","Confirm","Yes","No")) + return + if(!(usr && over_object && contents.len && loc == usr && !usr.stat && !usr.restrained() && usr.canmove && get_turf(usr) == T)) + return // Something happened while the player was thinking + hide_from(usr) + usr.face_atom(over_object) + usr.visible_message("[usr] empties \the [src] onto \the [over_object].", + "You empty \the [src] onto \the [over_object].") + for(var/obj/item/I in contents) + remove_from_storage(I, T) + update_icon() // For content-sensitive icons + return + if (!( istype(over_object, /obj/screen) )) return ..() if (!(src.loc == usr) || (src.loc && src.loc.loc == usr)) diff --git a/code/game/turfs/simulated/floor_types.dm b/code/game/turfs/simulated/floor_types.dm index 91e4fd2a9b9..5ea347aa51e 100644 --- a/code/game/turfs/simulated/floor_types.dm +++ b/code/game/turfs/simulated/floor_types.dm @@ -66,6 +66,19 @@ F.make_plating() return +/turf/simulated/floor/engine/ex_act(severity,target) + switch(severity) + if(1.0) + if(prob(80)) + ReplaceWithLattice() + else if(prob(50)) + qdel(src) + else + make_plating(1) + if(2.0) + if(prob(50)) + make_plating(1) + /turf/simulated/floor/engine/cult name = "engraved floor" icon_state = "cult" diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index 7dbaa7b2492..e4c61e1c754 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -16,6 +16,7 @@ opacity = 1 density = 1 blocks_air = 1 + explosion_block = 1 thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT heat_capacity = 312500 //a little over 5 cm thick , 312500 for 1 m by 2.5 m by 0.25 m plasteel wall diff --git a/code/game/turfs/simulated/walls_mineral.dm b/code/game/turfs/simulated/walls_mineral.dm index 393ff4beb8e..6e5aa0c33a8 100644 --- a/code/game/turfs/simulated/walls_mineral.dm +++ b/code/game/turfs/simulated/walls_mineral.dm @@ -11,6 +11,7 @@ icon_state = "gold0" walltype = "gold" mineral = "gold" + explosion_block = 0 //gold is a soft metal you dingus. //var/electro = 1 //var/shocked = null @@ -29,6 +30,7 @@ icon_state = "diamond0" walltype = "diamond" mineral = "diamond" + explosion_block = 3 /turf/simulated/wall/mineral/clown name = "bananium wall" @@ -43,6 +45,7 @@ icon_state = "sandstone0" walltype = "sandstone" mineral = "sandstone" + explosion_block = 0 /turf/simulated/wall/mineral/uranium name = "uranium wall" @@ -50,6 +53,7 @@ icon_state = "uranium0" walltype = "uranium" mineral = "uranium" + explosion_block = 0 /turf/simulated/wall/mineral/uranium/proc/radiate() if(!active) diff --git a/code/game/turfs/simulated/walls_reinforced.dm b/code/game/turfs/simulated/walls_reinforced.dm index 2ef06abefae..bf79c84e7c0 100644 --- a/code/game/turfs/simulated/walls_reinforced.dm +++ b/code/game/turfs/simulated/walls_reinforced.dm @@ -4,7 +4,7 @@ icon_state = "r_wall" opacity = 1 density = 1 - + explosion_block = 2 damage_cap = 200 max_temperature = 6000 diff --git a/code/game/turfs/unsimulated/walls.dm b/code/game/turfs/unsimulated/walls.dm index ca422c46cd6..27b057e5fce 100644 --- a/code/game/turfs/unsimulated/walls.dm +++ b/code/game/turfs/unsimulated/walls.dm @@ -4,6 +4,7 @@ icon_state = "riveted" opacity = 1 density = 1 + explosion_block = 2 /turf/unsimulated/wall/fakeglass name = "window" diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 5b151c850c2..ae3f2c2a5d9 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -144,7 +144,8 @@ var/list/admin_verbs_debug = list( /client/proc/toggledebuglogs, /client/proc/qdel_toggle, // /vg/ /client/proc/gc_dump_hdl, - /client/proc/debugNatureMapGenerator + /client/proc/debugNatureMapGenerator, + /client/proc/check_bomb_impacts ) var/list/admin_verbs_possess = list( /proc/possess, diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index c2498a5a740..3da342387ea 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -488,6 +488,14 @@ emp_act ..() return + +/mob/living/carbon/human/experience_pressure_difference(pressure_difference, direction) + if(shoes) + if(istype(shoes,/obj/item/clothing/shoes/magboots)) //TODO: Make a not-shit shoe var system to negate airflow. + var/obj/item/clothing/shoes/magboots/MB = shoes + if(MB.magpulse) + return 0 + ..() /mob/living/carbon/human/water_act(volume, temperature, source) ..() diff --git a/code/modules/procedural mapping/mapGenerator.dm b/code/modules/procedural mapping/mapGenerator.dm index 887ddfc40a4..c0b89549f3e 100644 --- a/code/modules/procedural mapping/mapGenerator.dm +++ b/code/modules/procedural mapping/mapGenerator.dm @@ -49,30 +49,28 @@ if(!checkRegion(Start, End)) return 0 - var/centerX = abs(max(End.x-Start.x,1)) - var/centerY = abs(max(End.y-Start.y,1)) - + var/centerX = max(abs((End.x+Start.x)/2),1) + var/centerY = max(abs((End.y+Start.y)/2),1) var/lilZ = min(Start.z,End.z) var/bigZ = max(Start.z,End.z) - var/centerZ = max(abs(bigZ-(lilZ/2)),1) //Spherical maps! woo! + var/sphereMagic = max(abs(bigZ-(lilZ/2)),1) //Spherical maps! woo! var/radius = abs(max(centerX,centerY)) //take the biggest displacement as the radius if(replace) undefineRegion() - //Sphere mode engage - var/evenCheckZ = 0 - if(max(bigZ,lilZ) % 2 == 0) - evenCheckZ = centerZ+1 + //Even sphere correction engage + var/offByOneOffset = 1 + if(bigZ % 2 == 0) + offByOneOffset = 0 - for(var/i = lilZ, i <= bigZ, i++) + for(var/i = lilZ, i <= bigZ+offByOneOffset, i++) var/theRadius = radius - if(i != centerZ) - if(i != evenCheckZ) - theRadius = max(radius/max((2*abs(centerZ-i)),1),1) + if(i != sphereMagic) + theRadius = max(radius/max((2*abs(sphereMagic-i)),1),1) map |= circlerange(locate(centerX,centerY,i),theRadius) diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm index 136d589b75d..6b23a7dae2f 100644 --- a/code/modules/projectiles/ammunition.dm +++ b/code/modules/projectiles/ammunition.dm @@ -10,8 +10,9 @@ var/caliber = "" //Which kind of guns it can be loaded into var/projectile_type = ""//The bullet type to create when New() is called var/obj/item/projectile/BB = null //The loaded bullet - var/buck = 0 + var/pellets = 1 var/deviation = 0 + var/spread = 0 /obj/item/ammo_casing/New() @@ -50,6 +51,12 @@ else user << "\blue There is no bullet in the casing to inscribe anything into." +/obj/item/ammo_casing/proc/newshot() //For energy weapons, shotgun shells and wands (!). + if (!BB) + BB = new projectile_type(src) + return + + //Boxes of ammo /obj/item/ammo_box diff --git a/code/modules/projectiles/ammunition/ammo_casings.dm b/code/modules/projectiles/ammunition/ammo_casings.dm index b6313d6eae4..5ceb6aa386b 100644 --- a/code/modules/projectiles/ammunition/ammo_casings.dm +++ b/code/modules/projectiles/ammunition/ammo_casings.dm @@ -46,8 +46,8 @@ desc = "A 12 gauge buckshot shell." icon_state = "gshell" projectile_type = "/obj/item/projectile/bullet/pellet" - buck = 5 - deviation = 0.8 + pellets = 5 + deviation = 30 /obj/item/ammo_casing/shotgun/beanbag @@ -64,8 +64,8 @@ icon_state = "gshell" projectile_type = "/obj/item/projectile/bullet/pellet/weak" m_amt = 250 - buck = 5 - deviation = 0.8 + pellets = 5 + deviation = 30 /obj/item/ammo_casing/shotgun/improvised/overload name = "overloaded improvised shell" @@ -74,12 +74,12 @@ icon_state = "improvshell" projectile_type = /obj/item/projectile/bullet/pellet/random m_amt = 250 - buck = 5 - deviation = 1.0 + pellets = 5 + deviation = 30 /obj/item/ammo_casing/shotgun/improvised/overload/New() ..() - buck = rand(3, 8) + pellets = rand(3, 8) /obj/item/ammo_casing/shotgun/stunslug name = "taser slug" @@ -120,8 +120,8 @@ desc = "A shotgun shell which fires a spread of incendiary pellets." icon_state = "ishell2" projectile_type = "/obj/item/projectile/bullet/incendiary/shell/dragonsbreath" - buck = 4 - deviation = 0.9 + pellets = 4 + deviation = 30 /obj/item/ammo_casing/shotgun/ion name = "ion shell" @@ -129,8 +129,8 @@ The unique properties of the crystal splot the pulse into a spread of individually weaker bolts." icon_state = "ionshell" projectile_type = /obj/item/projectile/ion/weak - buck = 4 - deviation = 0.9 + pellets = 4 + deviation = 30 /obj/item/ammo_casing/shotgun/laserslug name = "laser slug" diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index a9ef5784dcc..4efee86bb44 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -35,13 +35,14 @@ var/automatic = 0 //Used to determine if you can target multiple people. var/tmp/mob/living/last_moved_mob //Used to fire faster at more than one person. var/tmp/told_cant_shoot = 0 //So that it doesn't spam them with the fact they cannot hit them. - var/firerate = 1 // 0 for one bullet after tarrget moves and aim is lowered, + var/firerate = 1 // 0 for one bullet after tarrget moves and aim is lowered, //1 for keep shooting until aim is lowered var/fire_delay = 0 var/last_fired = 0 var/obj/item/device/flashlight/F = null var/can_flashlight = 0 var/heavy_weapon = 0 + var/randomspread = 0 proc/ready_to_fire() if(world.time >= last_fired + fire_delay) @@ -73,8 +74,8 @@ return /obj/item/weapon/gun/afterattack(atom/A as mob|obj|turf|area, mob/living/user as mob|obj, flag, params) - if(flag) return //we're placing gun on a table or in backpack - if(istype(target, /obj/machinery/recharger) && istype(src, /obj/item/weapon/gun/energy)) return//Shouldnt flag take care of this? + if(flag) return //we're placing gun on a table or in backpack + if(istype(target, /obj/machinery/recharger) && istype(src, /obj/item/weapon/gun/energy)) return//Shouldnt flag take care of this? if(user && user.client && user.client.gun_mode && !(A in target)) PreFire(A,user,params) //They're using the new gun system, locate what they're aiming at. else @@ -113,11 +114,6 @@ add_fingerprint(user) - var/turf/curloc = get_turf(user) - var/turf/targloc = get_turf(target) - if (!istype(targloc) || !istype(curloc)) - return - if(!special_check(user)) return @@ -129,23 +125,40 @@ if(!process_chambered()) //CHECK return click_empty(user) - if(!in_chamber) - return - if(heavy_weapon) if(user.get_inactive_hand()) recoil = 4 //one-handed kick else recoil = initial(recoil) - in_chamber.firer = user - in_chamber.def_zone = user.zone_sel.selecting - if(targloc == curloc) - user.bullet_act(in_chamber) - qdel(in_chamber) - update_icon() + if (istype(in_chamber, /obj/item/projectile/bullet/blank)) // A hacky way of making blank shotgun shells work again. Honk. + in_chamber.delete() + in_chamber = null return + user.changeNext_move(CLICK_CD_RANGE) + + var/spread = 0 + var/turf/targloc = get_turf(target) + if(chambered) + for (var/i = max(1, chambered.pellets), i > 0, i--) //Previous way of doing it fucked up math for spreading. This way, even the first projectile is part of the spread code. + if(i != max(1, chambered.pellets)) //Have we fired the initial chambered bullet yet? + in_chamber = new chambered.projectile_type() + ready_projectile(target, user) + prepare_shot(in_chamber) + if(chambered.deviation) + if(randomspread) //Random spread + spread = (rand() - 0.5) * chambered.deviation + else //Smart spread + spread = (i / chambered.pellets - 0.5) * chambered.deviation + if(!process_projectile(targloc, user, params, spread)) + return 0 + else + ready_projectile(target, user) + prepare_shot(in_chamber) + if(!process_projectile(targloc, user, params, spread)) + return 0 + if(recoil) spawn() shake_camera(user, recoil + 1, recoil) @@ -164,76 +177,71 @@ user.visible_message("[src] flies out of [user]'s hands!", "[src] kicks out of your grip!") user.drop_item() - if (istype(in_chamber, /obj/item/projectile/bullet/blank)) // A hacky way of making blank shotgun shells work again. Honk. - in_chamber.delete() - in_chamber = null - return - + update_icon() + if(user.hand) + user.update_inv_l_hand() + else + user.update_inv_r_hand() +/obj/item/weapon/gun/proc/ready_projectile(atom/target as mob|obj|turf, mob/living/user) + in_chamber.firer = user + in_chamber.def_zone = user.zone_sel.selecting in_chamber.original = target + return + +/obj/item/weapon/gun/proc/process_projectile(var/turf/targloc, mob/living/user as mob|obj, params, spread) + var/turf/curloc = user.loc + if (!istype(targloc) || !istype(curloc) || !in_chamber) + return 0 + if(targloc == curloc) //Fire the projectile + user.bullet_act(in_chamber) + qdel(in_chamber) + update_icon() + return 1 + in_chamber.loc = get_turf(user) in_chamber.starting = get_turf(user) - in_chamber.shot_from = src - user.changeNext_move(CLICK_CD_RANGE) - in_chamber.silenced = silenced in_chamber.current = curloc in_chamber.yo = targloc.y - curloc.y in_chamber.xo = targloc.x - curloc.x - - if(istype(user, /mob/living/carbon)) - var/mob/living/carbon/mob = user - if(mob.shock_stage > 120) - in_chamber.yo += rand(-2,2) - in_chamber.xo += rand(-2,2) - else if(mob.shock_stage > 70) - in_chamber.yo += rand(-1,1) - in_chamber.xo += rand(-1,1) - - - if(chambered) // Beep boop buckshot - var/target_x = targloc.x - var/target_y = targloc.y - var/target_z = targloc.z - if(in_chamber) - in_chamber.process() - while(chambered.buck > 0) - var/dx = round(gaussian(0,chambered.deviation),1) - var/dy = round(gaussian(0,chambered.deviation),1) - targloc = locate(target_x+dx, target_y+dy, target_z) - if(!targloc || targloc == curloc) - break - in_chamber = new chambered.projectile_type() - prepare_shot(in_chamber) - in_chamber.original = target - in_chamber.loc = get_turf(user) - in_chamber.starting = get_turf(user) - in_chamber.current = curloc - in_chamber.yo = targloc.y - curloc.y - in_chamber.xo = targloc.x - curloc.x - if(in_chamber) - in_chamber.process() - chambered.buck-- - - if(params) var/list/mouse_control = params2list(params) if(mouse_control["icon-x"]) in_chamber.p_x = text2num(mouse_control["icon-x"]) if(mouse_control["icon-y"]) in_chamber.p_y = text2num(mouse_control["icon-y"]) + if(mouse_control["screen-loc"]) + //Split screen-loc up into X+Pixel_X and Y+Pixel_Y + var/list/screen_loc_params = text2list(mouse_control["screen-loc"], ",") - spawn() - if(in_chamber) - in_chamber.process() - sleep(1) + //Split X+Pixel_X up into list(X, Pixel_X) + var/list/screen_loc_X = text2list(screen_loc_params[1],":") + + //Split Y+Pixel_Y up into list(Y, Pixel_Y) + var/list/screen_loc_Y = text2list(screen_loc_params[2],":") + + var/x = text2num(screen_loc_X[1]) * 32 + text2num(screen_loc_X[2]) - 32 + var/y = text2num(screen_loc_Y[1]) * 32 + text2num(screen_loc_Y[2]) - 32 + var/ox = round(544/2) //"origin" x - Basically center of the screen. This is a bad way of doing it because if you are able to view MORE than 17 tiles at a time your aim will get fucked. + var/oy = round(544/2) //"origin" y - Basically center of the screen. + + var/angle = Atan2(y - oy, x - ox) + + in_chamber.Angle = angle + + if(istype(user, /mob/living/carbon)) //Increase spread based on shock + var/mob/living/carbon/mob = user + if(mob.shock_stage > 120) + spread += rand(-5,5) + else if(mob.shock_stage > 70) + spread += rand(-2,2) + + if(spread) + in_chamber.Angle += spread + if(in_chamber) + in_chamber.process() in_chamber = null - - update_icon() - - if(user.hand) - user.update_inv_l_hand() - else - user.update_inv_r_hand() + return 1 /obj/item/weapon/gun/proc/can_fire() return process_chambered() @@ -378,4 +386,5 @@ if(F) if(F.on) user.AddLuminosity(-F.brightness_on) - SetLuminosity(F.brightness_on) \ No newline at end of file + SetLuminosity(F.brightness_on) + diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 8424fb54b69..a4ce8cdeac2 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -19,6 +19,7 @@ pass_flags = PASSTABLE mouse_opacity = 0 hitsound = 'sound/weapons/pierce.ogg' + animate_movement = 0 var/bumped = 0 //Prevents it from hitting more than one guy at once var/def_zone = "" //Aiming at var/mob/firer = null//Who shot it @@ -60,6 +61,11 @@ var/chatlog_attacks = 1 + var/speed = 1 //Amount of deciseconds it takes for projectile to travel. Animation is adjusted accordingly. + var/Angle = 0 //For new projectiles + var/spread = 0 //Amount of degrees by which the projectiles will be spread DURING MOVEMENT. It exists for chaotic types of projectiles, like bees or something. + var/legacy = 0 //Use the legacy projectile system or new pixel movement? + proc/delete() // Garbage collect the projectiles loc = null @@ -174,43 +180,108 @@ return 1 - process() - spawn while(src) - if(kill_count < 1) - del(src) - return - kill_count-- - if((!( current ) || loc == current)) - current = locate(min(max(x + xo, 1), world.maxx), min(max(y + yo, 1), world.maxy), z) - if((x == 1 || x == world.maxx || y == 1 || y == world.maxy)) - del(src) - return - step_towards(src, current) - sleep(1) - if(!bumped && !isturf(original)) - if(loc == get_turf(original)) - if(!(original in permutated)) - Bump(original) - sleep(1) - Range() - return - proc/dumbfire(var/dir) // for spacepods, go snowflake go - if(!dir) - del(src) - if(kill_count < 1) - del(src) - kill_count-- - spawn while(src) - var/turf/T = get_step(src, dir) - step_towards(src, T) - sleep(1) - if(!bumped && !isturf(original)) - if(loc == get_turf(original)) - if(!(original in permutated)) - Bump(original) - sleep(1) - return + process(var/setAngle) + if(setAngle) Angle = setAngle + if(!legacy) + spawn() //New projectile system + while(loc) + if(kill_count < 1) + qdel(src) + return + kill_count-- + if((!( current ) || loc == current)) + current = locate(Clamp(x+xo,1,world.maxx),Clamp(y+yo,1,world.maxy),z) + if(!Angle) + Angle=round(Get_Angle(src,current)) + //world << "[Angle] angle" + //overlays.Cut() + //var/icon/I=new(initial(icon),icon_state) //using initial(icon) makes sure that the angle for that is reset as well + //I.Turn(Angle) + //I.DrawBox(rgb(255,0,0,50),1,1,32,32) + //icon = I + if(spread) //Chaotic spread + Angle += (rand() - 0.5) * spread + var/matrix/M = new//matrix(transform) + M.Turn(Angle) + transform = M + + var/Pixel_x=round(sin(Angle)+16*sin(Angle)*2) + var/Pixel_y=round(cos(Angle)+16*cos(Angle)*2) + var/pixel_x_offset = pixel_x + Pixel_x + var/pixel_y_offset = pixel_y + Pixel_y + var/new_x = x + var/new_y = y + //Not sure if using whiles for this is good + while(pixel_x_offset > 16) + //world << "Pre-adjust coords (x++): xy [pixel_x] xy offset [pixel_x_offset]" + pixel_x_offset -= 32 + pixel_x -= 32 + new_x++// x++ + while(pixel_x_offset < -16) + //world << "Pre-adjust coords (x--): xy [pixel_x] xy offset [pixel_x_offset]" + pixel_x_offset += 32 + pixel_x += 32 + new_x-- + + while(pixel_y_offset > 16) + //world << "Pre-adjust coords (y++): py [pixel_y] py offset [pixel_y_offset]" + pixel_y_offset -= 32 + pixel_y -= 32 + new_y++ + while(pixel_y_offset < -16) + //world << "Pre-adjust coords (y--): py [pixel_y] py offset [pixel_y_offset]" + pixel_y_offset += 32 + pixel_y += 32 + new_y-- + + speed = round(speed) //Just in case. + step_towards(src, locate(new_x, new_y, z)) //Original projectiles stepped towards 'current' + if(speed <= 1) //We should really only animate at speed 2 + pixel_x = pixel_x_offset + pixel_y = pixel_y_offset + else + animate(src, pixel_x = pixel_x_offset, pixel_y = pixel_y_offset, time = max(1, (speed <= 3 ? speed - 1 : speed))) + +/* + var/turf/T = get_turf(src) + if(T) + T.color = "#6666FF" + spawn(10) + T.color = initial(T.color) +*/ + + if(!bumped && ((original && original.layer>=2.75) || ismob(original))) + if(loc == get_turf(original)) + if(!(original in permutated)) + Bump(original) + Range() + sleep(max(1, speed)) + else + spawn() //Old projectile system + while(loc) + if(kill_count < 1) + qdel(src) + return + kill_count-- + if((!( current ) || loc == current)) + current = locate(Clamp(x+xo,1,world.maxx),Clamp(y+yo,1,world.maxy),z) + if(!Angle) + Angle=round(Get_Angle(src,current)) + var/matrix/M = new//matrix(transform) + M.Turn(Angle) + transform = M //So there's no need to give icons directions again + step_towards(src, current) + if(!bumped && ((original && original.layer>=2.75) || ismob(original))) + if(loc == get_turf(original)) + if(!(original in permutated)) + Bump(original) + Range() + sleep(1) + + 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. + process() /obj/item/projectile/test //Used to see if you can hit them. invisibility = 101 //Nope! Can't see me! diff --git a/code/modules/reagents/Chemistry-Reagents.dm b/code/modules/reagents/Chemistry-Reagents.dm index 6a7d90a5d32..f36b16e8f2a 100644 --- a/code/modules/reagents/Chemistry-Reagents.dm +++ b/code/modules/reagents/Chemistry-Reagents.dm @@ -1270,25 +1270,11 @@ datum on_mob_life(var/mob/living/M as mob) if(!M) M = holder.my_atom - if(M.bodytemperature < 170) - M.adjustCloneLoss(-1) + if(M.bodytemperature < 265) + M.adjustCloneLoss(-4) M.adjustOxyLoss(-10) M.heal_organ_damage(12,12) M.adjustToxLoss(-3) - ..() - return - - clonexadone - name = "Clonexadone" - id = "clonexadone" - description = "A liquid compound similar to that used in the cloning process. Can be used to 'finish' clones that get ejected early when used in conjunction with a cryo tube." - reagent_state = LIQUID - color = "#0000C8" // rgb: 200, 165, 220 - - on_mob_life(var/mob/living/M as mob) - if(!M) M = holder.my_atom - if(M.bodytemperature < 170) - M.adjustCloneLoss(-3) M.status_flags &= ~DISFIGURED ..() return diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm index 00f9a662b91..f4fc2e30b34 100644 --- a/code/modules/reagents/Chemistry-Recipes.dm +++ b/code/modules/reagents/Chemistry-Recipes.dm @@ -113,8 +113,8 @@ datum name = "mitocholide" id = "mitocholide" result = "mitocholide" - required_reagents = list("synthflesh" = 1, "clonexadone" = 1) - result_amount = 2 + required_reagents = list("synthflesh" = 1, "cryoxadone" = 1, "plasma" = 1) + result_amount = 3 holy_water name = "Holy Water" @@ -132,14 +132,6 @@ datum result_amount = 4 mix_message = "The solution bubbles softly." - clonexadone - name = "Clonexadone" - id = "clonexadone" - result = "clonexadone" - required_reagents = list("cryoxadone" = 1, "sodium" = 1) - required_catalysts = list("plasma" = 5) - result_amount = 2 - spaceacillin name = "Spaceacillin" id = "spaceacillin" @@ -983,7 +975,7 @@ datum name = "Syntiflesh" id = "syntiflesh" result = null - required_reagents = list("blood" = 5, "clonexadone" = 1) + required_reagents = list("blood" = 5, "cryoxadone" = 1) result_amount = 1 on_reaction(var/datum/reagents/holder, var/created_volume) var/location = get_turf(holder.my_atom) diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm index d1506aa8dbc..5bc8b20a6bb 100644 --- a/code/modules/recycling/disposal.dm +++ b/code/modules/recycling/disposal.dm @@ -93,22 +93,14 @@ user << "You can't place that item inside the disposal unit." return - if(istype(I, /obj/item/weapon/storage/bag/trash)) - var/obj/item/weapon/storage/bag/trash/T = I - if(T.contents.len) - user << "\blue You empty the bag." - for(var/obj/item/O in T.contents) - T.remove_from_storage(O,src) - T.update_icon() - update() - return - - if(istype(I, /obj/item/weapon/storage/part_replacer)) - var/obj/item/weapon/storage/part_replacer/P = I - if(P.contents.len) - user << "\blue You empty the RPED's contents." - for(var/obj/item/O in P.contents) - P.remove_from_storage(O,src) + if(istype(I, /obj/item/weapon/storage)) + var/obj/item/weapon/storage/S = I + if((S.allow_quick_empty || S.allow_quick_gather) && S.contents.len) + S.hide_from(user) + user.visible_message("[user] empties \the [S] into \the [src].", "You empty \the [S] into \the [src].") + for(var/obj/item/O in S.contents) + S.remove_from_storage(O, src) + S.update_icon() // For content-sensitive icons update() return diff --git a/code/setup.dm b/code/setup.dm index f629ab3b14f..c14124cb929 100644 --- a/code/setup.dm +++ b/code/setup.dm @@ -795,7 +795,7 @@ var/list/be_special_flags = list( #define PULSE_THREADY 5 //occurs during hypovolemic shock //feel free to add shit to lists below var/list/tachycardics = list("coffee", "methamphetamine", "nitroglycerin", "thirteenloko", "nicotine") //increase heart rate -var/list/bradycardics = list("neurotoxin", "cryoxadone", "clonexadone", "space_drugs") //decrease heart rate +var/list/bradycardics = list("neurotoxin", "cryoxadone", "space_drugs") //decrease heart rate var/list/heartstopper = list("capulettium", "capulettium_plus") //this stops the heart var/list/cheartstopper = list() //this stops the heart when overdose is met -- c = conditional diff --git a/icons/obj/projectiles.dmi b/icons/obj/projectiles.dmi index 57f75b0f54e..73177afd0bd 100644 Binary files a/icons/obj/projectiles.dmi and b/icons/obj/projectiles.dmi differ