diff --git a/baystation12.dme b/baystation12.dme index 828007b0de8..e3488cda375 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -1099,6 +1099,7 @@ #include "code\modules\projectiles\guns\energy\temperature.dm" #include "code\modules\projectiles\guns\projectile\automatic.dm" #include "code\modules\projectiles\guns\projectile\pistol.dm" +#include "code\modules\projectiles\guns\projectile\pneumatic.dm" #include "code\modules\projectiles\guns\projectile\revolver.dm" #include "code\modules\projectiles\guns\projectile\shotgun.dm" #include "code\modules\projectiles\projectile\animate.dm" diff --git a/code/defines/obj/weapon.dm b/code/defines/obj/weapon.dm index 13249887f87..e144c194e02 100644 --- a/code/defines/obj/weapon.dm +++ b/code/defines/obj/weapon.dm @@ -313,7 +313,7 @@ desc = "Could probably be used as ... a throwing weapon?" w_class = 1.0 force = 5.0 - throwforce = 15.0 + throwforce = 8.0 item_state = "shard-glass" g_amt = 3750 attack_verb = list("stabbed", "slashed", "sliced", "cut") diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 1d7d4bce3a6..59db6464fe0 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -21,10 +21,10 @@ //Detective Work, used for the duplicate data points kept in the scanners var/list/original_atom -/atom/proc/throw_impact(atom/hit_atom) +/atom/proc/throw_impact(atom/hit_atom, var/speed) if(istype(hit_atom,/mob/living)) var/mob/living/M = hit_atom - M.hitby(src) + M.hitby(src,speed) log_attack("[hit_atom] ([M.ckey]) was hit by [src] thrown by ([src.fingerprintslast])") @@ -32,7 +32,7 @@ var/obj/O = hit_atom if(!O.anchored) step(O, src.dir) - O.hitby(src) + O.hitby(src,speed) else if(isturf(hit_atom)) var/turf/T = hit_atom diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 087d6fa6795..8f4e6dba669 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -44,18 +44,18 @@ return 1 return 0 -/atom/movable/proc/hit_check() +/atom/movable/proc/hit_check(var/speed) if(src.throwing) for(var/atom/A in get_turf(src)) if(A == src) continue if(istype(A,/mob/living)) if(A:lying) continue - src.throw_impact(A) + src.throw_impact(A,speed) if(src.throwing == 1) src.throwing = 0 if(isobj(A)) if(A.density && !A.throwpass) // **TODO: Better behaviour for windows which are dense, but shouldn't always stop movement - src.throw_impact(A) + src.throw_impact(A,speed) src.throwing = 0 /atom/movable/proc/throw_at(atom/target, range, speed) @@ -97,7 +97,7 @@ if(!step) // going off the edge of the map makes get_step return null, don't let things go off the edge break src.Move(step) - hit_check() + hit_check(speed) error += dist_x dist_travelled++ dist_since_sleep++ @@ -109,7 +109,7 @@ if(!step) // going off the edge of the map makes get_step return null, don't let things go off the edge break src.Move(step) - hit_check() + hit_check(speed) error -= dist_y dist_travelled++ dist_since_sleep++ @@ -126,7 +126,7 @@ if(!step) // going off the edge of the map makes get_step return null, don't let things go off the edge break src.Move(step) - hit_check() + hit_check(speed) error += dist_y dist_travelled++ dist_since_sleep++ @@ -138,7 +138,7 @@ if(!step) // going off the edge of the map makes get_step return null, don't let things go off the edge break src.Move(step) - hit_check() + hit_check(speed) error -= dist_x dist_travelled++ dist_since_sleep++ @@ -150,7 +150,7 @@ //done throwing, either because it hit something or it finished moving src.throwing = 0 - if(isobj(src)) src:throw_impact(get_turf(src)) + if(isobj(src)) src:throw_impact(get_turf(src),speed) //Overlays diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm index 62ed84d34f6..da6f8f90c89 100644 --- a/code/game/machinery/iv_drip.dm +++ b/code/game/machinery/iv_drip.dm @@ -84,7 +84,7 @@ if(istype(src.beaker, /obj/item/weapon/reagent_containers/blood)) // speed up transfer on blood packs transfer_amount = 4 - attached.inject_blood(beaker,transfer_amount) + src.beaker.reagents.trans_to(src.attached, transfer_amount) update_icon() // Take blood diff --git a/code/game/objects/structures/stool_bed_chair_nest/stools.dm b/code/game/objects/structures/stool_bed_chair_nest/stools.dm index a2f18e8d813..ab7a55e1da8 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/stools.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/stools.dm @@ -37,11 +37,12 @@ /obj/structure/stool/MouseDrop(atom/over_object) if (istype(over_object, /mob/living/carbon/human)) var/mob/living/carbon/human/H = over_object - var/obj/item/weapon/stool/S = new/obj/item/weapon/stool() - S.origin = src - src.loc = S - H.put_in_hands(S) - H.visible_message("\red [H] grabs [src] from the floor!", "\red You grab [src] from the floor!") + if (!H.restrained() && !H.stat && in_range(src, over_object)) + var/obj/item/weapon/stool/S = new/obj/item/weapon/stool() + S.origin = src + src.loc = S + H.put_in_hands(S) + H.visible_message("\red [H] grabs [src] from the floor!", "\red You grab [src] from the floor!") /obj/item/weapon/stool name = "stool" diff --git a/code/modules/clothing/spacesuits/alien.dm b/code/modules/clothing/spacesuits/alien.dm index 7a74d855162..3a8824e644e 100644 --- a/code/modules/clothing/spacesuits/alien.dm +++ b/code/modules/clothing/spacesuits/alien.dm @@ -56,6 +56,8 @@ allowed = list(/obj/item/weapon/gun,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/melee/energy/sword,/obj/item/weapon/handcuffs,/obj/item/weapon/tank) slowdown = 2 armor = list(melee = 60, bullet = 50, laser = 30,energy = 15, bomb = 30, bio = 30, rad = 30) + heat_protection = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS + max_heat_protection_temperature = SPACE_SUIT_MAX_HEAT_PROTECITON_TEMPERATURE /obj/item/clothing/head/helmet/space/vox/carapace name = "alien visor" @@ -63,6 +65,7 @@ item_state = "vox-carapace" desc = "A glowing visor, perhaps stolen from a depressed Cylon." armor = list(melee = 60, bullet = 50, laser = 30, energy = 15, bomb = 30, bio = 30, rad = 30) + flags = HEADCOVERSEYES|STOPSPRESSUREDMAGE /obj/item/clothing/suit/space/vox/carapace name = "alien carapace armour" diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index d0f61484c66..86d251cdf45 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -61,7 +61,7 @@ P.on_hit(src, absorb) return absorb -/mob/living/hitby(atom/movable/AM as mob|obj)//Standardization and logging -Sieve +/mob/living/hitby(atom/movable/AM as mob|obj,var/speed)//Standardization and logging -Sieve if(istype(AM,/obj/)) var/obj/O = AM var/zone = ran_zone("chest",75)//Hits a random part of the body, geared towards the chest @@ -72,7 +72,7 @@ src.visible_message("\red [src] has been hit by [O].") var/armor = run_armor_check(zone, "melee", "Your armor has protected your [zone].", "Your armor has softened hit to your [zone].") if(armor < 2) - apply_damage(O.throwforce, dtype, zone, armor, O) + apply_damage(O.throwforce*(speed/5), dtype, zone, armor, O) if(!O.fingerprintslast) return var/client/assailant = directory[ckey(O.fingerprintslast)] diff --git a/code/modules/projectiles/guns/projectile/pneumatic.dm b/code/modules/projectiles/guns/projectile/pneumatic.dm new file mode 100644 index 00000000000..7d2f0c3b498 --- /dev/null +++ b/code/modules/projectiles/guns/projectile/pneumatic.dm @@ -0,0 +1,140 @@ +/obj/item/weapon/storage/pneumatic + name = "pneumatic cannon" + desc = "A large gas-powered cannon." + icon = 'icons/obj/gun.dmi' + icon_state = "pneumatic" + item_state = "pneumatic" + w_class = 4.0 + flags = FPRINT | TABLEPASS | CONDUCT | USEDELAY + slot_flags = SLOT_BELT + max_w_class = 3 + max_combined_w_class = 20 + + var/obj/item/weapon/tank/tank = null // Tank of gas for use in firing the cannon. + var/obj/item/weapon/storage/tank_container = new() // Something to hold the tank item so we don't accidentally fire it. + var/pressure_setting = 10 // Percentage of the gas in the tank used to fire the projectile. + var/possible_pressure_amounts = list(5,10,20,25,50) // Possible pressure settings. + var/minimum_tank_pressure = 10 // Minimum pressure to fire the gun. + var/cooldown = 0 // Whether or not we're cooling down. + var/cooldown_time = 50 // Time between shots. + var/force_divisor = 400 // Force equates to speed. Speed/5 equates to a damage multiplier for whoever you hit. + // For reference, a fully pressurized oxy tank at 50% gas release firing a health + // analyzer with a force_divisor of 10 hit with a damage multiplier of 3000+. + +/obj/item/weapon/storage/pneumatic/verb/set_pressure() //set amount of tank pressure. + + set name = "Set valve pressure" + set category = "Object" + set src in range(0) + var/N = input("Percentage of tank used per shot:","[src]") as null|anything in possible_pressure_amounts + if (N) + pressure_setting = N + usr << "You dial the pressure valve to [pressure_setting]%." + +/obj/item/weapon/storage/pneumatic/verb/eject_tank() //Remove the tank. + + set name = "Eject tank" + set category = "Object" + set src in range(0) + + if(tank) + usr << "You twist the valve and pop the tank out of [src]." + tank.loc = usr.loc + tank = null + icon_state = "pneumatic" + item_state = "pneumatic" + usr.update_icons() + else + usr << "There's no tank in [src]." + +/obj/item/weapon/storage/pneumatic/attackby(obj/item/W as obj, mob/user as mob) + if(!tank && istype(W,/obj/item/weapon/tank)) + user.drop_item() + tank = W + tank.loc = src.tank_container + user.visible_message("[user] jams [W] into [src]'s valve and twists it closed.","You jam [W] into [src]'s valve and twist it closed.") + icon_state = "pneumatic-tank" + item_state = "pneumatic-tank" + user.update_icons() + else + ..() + +/obj/item/weapon/storage/pneumatic/examine() + set src in view() + ..() + if (!(usr in view(2)) && usr!=src.loc) return + usr << "The valve is dialed to [pressure_setting]%." + if(tank) + usr << "The tank dial reads [tank.air_contents.return_pressure()] kPa." + else + usr << "Nothing is attached to the tank valve!" + +/obj/item/weapon/storage/pneumatic/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag, params) + if (istype(target, /obj/item/weapon/storage/backpack )) + return + + else if (target.loc == user.loc) + return + + else if (locate (/obj/structure/table, src.loc)) + return + + else if(target == user) + return + + if (length(contents) == 0) + user << "There's nothing in [src] to fire!" + return 0 + else + spawn(0) Fire(target,user,params) + +/obj/item/weapon/storage/pneumatic/attack(mob/living/M as mob, mob/living/user as mob, def_zone) + if (length(contents) > 0) + if(user.a_intent == "hurt") + user.visible_message("\red \The [user] fires \the [src] point blank at [M]!") + Fire(M,user) + return + else + Fire(M,user) + return + +/obj/item/weapon/storage/pneumatic/proc/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0) + + if (!tank) + user << "There is no gas tank in [src]!" + return 0 + + if (cooldown) + user << "The chamber hasn't built up enough pressure yet!" + return 0 + + add_fingerprint(user) + + var/turf/curloc = get_turf(user) + var/turf/targloc = get_turf(target) + if (!istype(targloc) || !istype(curloc)) + return + + var/fire_pressure = (tank.air_contents.return_pressure()/100)*pressure_setting + + if (fire_pressure < minimum_tank_pressure) + user << "There isn't enough gas in the tank to fire [src]." + return 0 + + var/obj/item/object = contents[1] + var/speed = ((fire_pressure*tank.volume)/object.w_class)/force_divisor //projectile speed. + if(speed>80) speed = 80 //damage cap. + + user.visible_message("[user] fires [src] and launches [object] at [target]!","You fire [src] and launch [object] at [target]!") + + src.remove_from_storage(object,user.loc) + object.throw_at(target,10,speed) + + var/lost_gas_amount = tank.air_contents.total_moles*(pressure_setting/100) + var/datum/gas_mixture/removed = tank.air_contents.remove(lost_gas_amount) + user.loc.assume_air(removed) + + cooldown = 1 + spawn(cooldown_time) + cooldown = 0 + user << "[src]'s gauge informs you it's ready to be fired again." diff --git a/code/modules/projectiles/projectile/force.dm b/code/modules/projectiles/projectile/force.dm index 68bf6456a03..364ad53370b 100644 --- a/code/modules/projectiles/projectile/force.dm +++ b/code/modules/projectiles/projectile/force.dm @@ -12,7 +12,7 @@ var/obj/T = target var/throwdir = get_dir(firer,target) - T.throw_at(get_edge_target_turf(target, throwdir),10,1) + T.throw_at(get_edge_target_turf(target, throwdir),10,10) return 1 /* diff --git a/code/modules/reagents/Chemistry-Holder.dm b/code/modules/reagents/Chemistry-Holder.dm index 68cb8c4e2ab..2fb6d0c27fb 100644 --- a/code/modules/reagents/Chemistry-Holder.dm +++ b/code/modules/reagents/Chemistry-Holder.dm @@ -104,6 +104,10 @@ datum for (var/datum/reagent/current_reagent in src.reagent_list) if (!current_reagent) continue + if (current_reagent.id == "blood" && ishuman(target)) + var/mob/living/carbon/human/H = target + H.inject_blood(my_atom, amount) + continue var/current_reagent_transfer = current_reagent.volume * part if(preserve_data) trans_data = current_reagent.data diff --git a/icons/mob/human.dmi b/icons/mob/human.dmi index dc9ca30eadc..9b4acf4d0d9 100644 Binary files a/icons/mob/human.dmi and b/icons/mob/human.dmi differ diff --git a/icons/mob/items_lefthand.dmi b/icons/mob/items_lefthand.dmi index c0e1013f9d3..c9ab6654416 100644 Binary files a/icons/mob/items_lefthand.dmi and b/icons/mob/items_lefthand.dmi differ diff --git a/icons/mob/items_righthand.dmi b/icons/mob/items_righthand.dmi index 1911107430d..b8ac94ee3a5 100644 Binary files a/icons/mob/items_righthand.dmi and b/icons/mob/items_righthand.dmi differ diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi index e65fc8825dd..41e428f3c21 100644 Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ diff --git a/icons/obj/gun.dmi b/icons/obj/gun.dmi index e9d1940dd33..5a0eab2d2a6 100644 Binary files a/icons/obj/gun.dmi and b/icons/obj/gun.dmi differ