diff --git a/baystation12.dme b/baystation12.dme
index 3140c5c97a..06ddf79d43 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -875,7 +875,6 @@
#include "code\modules\clothing\spacesuits\rig\modules\computer.dm"
#include "code\modules\clothing\spacesuits\rig\modules\modules.dm"
#include "code\modules\clothing\spacesuits\rig\modules\ninja.dm"
-#include "code\modules\clothing\spacesuits\rig\modules\rig_weapons.dm"
#include "code\modules\clothing\spacesuits\rig\modules\utility.dm"
#include "code\modules\clothing\spacesuits\rig\modules\vision.dm"
#include "code\modules\clothing\spacesuits\rig\suits\alien.dm"
@@ -1321,6 +1320,7 @@
#include "code\modules\projectiles\ammunition\bullets.dm"
#include "code\modules\projectiles\guns\alien.dm"
#include "code\modules\projectiles\guns\energy.dm"
+#include "code\modules\projectiles\guns\launcher.dm"
#include "code\modules\projectiles\guns\projectile.dm"
#include "code\modules\projectiles\guns\energy\laser.dm"
#include "code\modules\projectiles\guns\energy\nuclear.dm"
@@ -1328,14 +1328,17 @@
#include "code\modules\projectiles\guns\energy\special.dm"
#include "code\modules\projectiles\guns\energy\stun.dm"
#include "code\modules\projectiles\guns\energy\temperature.dm"
+#include "code\modules\projectiles\guns\launcher\crossbow.dm"
+#include "code\modules\projectiles\guns\launcher\grenade_launcher.dm"
+#include "code\modules\projectiles\guns\launcher\pneumatic.dm"
+#include "code\modules\projectiles\guns\launcher\rocket.dm"
+#include "code\modules\projectiles\guns\launcher\syringe_gun.dm"
#include "code\modules\projectiles\guns\projectile\automatic.dm"
-#include "code\modules\projectiles\guns\projectile\crossbow.dm"
-#include "code\modules\projectiles\guns\projectile\launcher.dm"
+#include "code\modules\projectiles\guns\projectile\dartgun.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\rocket.dm"
#include "code\modules\projectiles\guns\projectile\shotgun.dm"
+#include "code\modules\projectiles\guns\projectile\sniper.dm"
#include "code\modules\projectiles\projectile\animate.dm"
#include "code\modules\projectiles\projectile\beams.dm"
#include "code\modules\projectiles\projectile\bullets.dm"
@@ -1352,11 +1355,8 @@
#include "code\modules\reagents\Chemistry-Reagents-Antidepressants.dm"
#include "code\modules\reagents\Chemistry-Reagents.dm"
#include "code\modules\reagents\Chemistry-Recipes.dm"
-#include "code\modules\reagents\dartgun.dm"
-#include "code\modules\reagents\grenade_launcher.dm"
#include "code\modules\reagents\reagent_containers.dm"
#include "code\modules\reagents\reagent_dispenser.dm"
-#include "code\modules\reagents\syringe_gun.dm"
#include "code\modules\reagents\reagent_containers\blood_pack.dm"
#include "code\modules\reagents\reagent_containers\borghydro.dm"
#include "code\modules\reagents\reagent_containers\dropper.dm"
diff --git a/code/_onclick/hud/monkey.dm b/code/_onclick/hud/monkey.dm
index 65924284b5..0081fbe6b5 100644
--- a/code/_onclick/hud/monkey.dm
+++ b/code/_onclick/hud/monkey.dm
@@ -226,7 +226,7 @@
if (mymob.client.gun_mode) // If in aim mode, correct the sprite
mymob.gun_setting_icon.set_dir(2)
for(var/obj/item/weapon/gun/G in mymob) // If targeting someone, display other buttons
- if (G.target)
+ if (G.aim_targets)
mymob.item_use_icon = new /obj/screen/gun/item(null)
if (mymob.client.target_can_click)
mymob.item_use_icon.set_dir(1)
diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm
index 644b811376..2738cf3a7d 100644
--- a/code/_onclick/hud/robot.dm
+++ b/code/_onclick/hud/robot.dm
@@ -157,7 +157,7 @@ var/obj/screen/robot_inventory
if (mymob.client.gun_mode) // If in aim mode, correct the sprite
mymob.gun_setting_icon.set_dir(2)
for(var/obj/item/weapon/gun/G in mymob) // If targeting someone, display other buttons
- if (G.target)
+ if (G.aim_targets)
mymob.item_use_icon = new /obj/screen/gun/item(null)
if (mymob.client.target_can_click)
mymob.item_use_icon.set_dir(1)
diff --git a/code/defines/obj/weapon.dm b/code/defines/obj/weapon.dm
index 4f424e0315..e513a7db37 100644
--- a/code/defines/obj/weapon.dm
+++ b/code/defines/obj/weapon.dm
@@ -67,7 +67,7 @@
icon_state = "bike_horn"
item_state = "bike_horn"
throwforce = 3
- w_class = 1.0
+ w_class = 2
throw_speed = 3
throw_range = 15
attack_verb = list("HONKED")
diff --git a/code/game/gamemodes/factions.dm b/code/game/gamemodes/factions.dm
index 1aaa70e2a5..47c8586f6e 100644
--- a/code/game/gamemodes/factions.dm
+++ b/code/game/gamemodes/factions.dm
@@ -119,7 +119,7 @@
operative_notes = "We'd like to remind our operatives to keep it professional. You are not here to have a good time, you are here to accomplish your objectives. These vile communists must be stopped at all costs. You may collaborate with any friends of the Syndicate coalition, but keep an eye on any of those Tiger punks if they do show up. You are completely free to accomplish your objectives any way you see fit."
uplink_contents = {"Highly Visible and Dangerous Weapons;
-/obj/item/weapon/gun/projectile:6:Revolver;
+/obj/item/weapon/gun/projectile/revolver:6:Revolver;
/obj/item/ammo_magazine/a357:2:Ammo-357;
/obj/item/weapon/gun/energy/crossbow:5:Energy Crossbow;
/obj/item/weapon/melee/energy/sword:4:Energy Sword;
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index 3f0f8cdd64..8ad2d72288 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -40,7 +40,7 @@
new/datum/uplink_item(/obj/item/weapon/gun/energy/crossbow, 5, "Energy Crossbow", "XB"),
new/datum/uplink_item(/obj/item/weapon/storage/box/syndie_kit/g9mm, 5, "Silenced 9mm", "S9"),
new/datum/uplink_item(/obj/item/mecha_parts/mecha_equipment/weapon/energy/riggedlaser, 6, "Exosuit Rigged Laser", "RL"),
- new/datum/uplink_item(/obj/item/weapon/gun/projectile, 6, "Revolver", "RE"),
+ new/datum/uplink_item(/obj/item/weapon/gun/projectile/revolver, 6, "Revolver", "RE"),
new/datum/uplink_item(/obj/item/weapon/storage/box/syndicate, 10, "Mercenary Bundle", "BU")
),
"Stealthy and Inconspicuous Weapons" = list(
diff --git a/code/game/gamemodes/wizard/rightandwrong.dm b/code/game/gamemodes/wizard/rightandwrong.dm
index ccce7f9bff..1e16da590b 100644
--- a/code/game/gamemodes/wizard/rightandwrong.dm
+++ b/code/game/gamemodes/wizard/rightandwrong.dm
@@ -26,7 +26,7 @@
if("revolver")
new /obj/item/weapon/gun/projectile(get_turf(H))
if("detective")
- new /obj/item/weapon/gun/projectile/detective(get_turf(H))
+ new /obj/item/weapon/gun/projectile/revolver/detective(get_turf(H))
if("smg")
new /obj/item/weapon/gun/projectile/automatic/c20r(get_turf(H))
if("nuclear")
@@ -49,7 +49,7 @@
if("combatshotgun")
new /obj/item/weapon/gun/projectile/shotgun/pump/combat(get_turf(H))
if("mateba")
- new /obj/item/weapon/gun/projectile/mateba(get_turf(H))
+ new /obj/item/weapon/gun/projectile/revolver/mateba(get_turf(H))
if("smg")
new /obj/item/weapon/gun/projectile/automatic(get_turf(H))
if("uzi")
diff --git a/code/game/machinery/autolathe_datums.dm b/code/game/machinery/autolathe_datums.dm
index f13c3dc634..38989d2905 100644
--- a/code/game/machinery/autolathe_datums.dm
+++ b/code/game/machinery/autolathe_datums.dm
@@ -201,6 +201,11 @@
path = /obj/item/weapon/reagent_containers/syringe
category = "Medical"
+/datum/autolathe/recipe/syringegun_ammo
+ name = "syringe"
+ path = /obj/item/weapon/syringe_cartridge
+ category = "Arms and Ammunition"
+
/datum/autolathe/recipe/shotgun_blanks
name = "ammunition (shotgun, blank)"
path = /obj/item/ammo_casing/shotgun/blank
@@ -217,13 +222,13 @@
category = "Arms and Ammunition"
/datum/autolathe/recipe/magazine_rubber
- name = "ammunition (rubber)"
- path = /obj/item/ammo_magazine/c45r
+ name = "ammunition (.45, rubber)"
+ path = /obj/item/ammo_magazine/c45m/rubber
category = "Arms and Ammunition"
/datum/autolathe/recipe/magazine_flash
- name = "ammunition (flash)"
- path = /obj/item/ammo_magazine/c45f
+ name = "ammunition (.45, flash)"
+ path = /obj/item/ammo_magazine/c45m/flash
category = "Arms and Ammunition"
/datum/autolathe/recipe/consolescreen
@@ -294,6 +299,24 @@
hidden = 1
category = "Arms and Ammunition"
+/datum/autolathe/recipe/magazine_stetchkin
+ name = "ammunition (9mm)"
+ path = /obj/item/ammo_magazine/mc9mm
+ hidden = 1
+ category = "Arms and Ammunition"
+
+/datum/autolathe/recipe/magazine_stetchkin_flash
+ name = "ammunition (9mm, flash)"
+ path = /obj/item/ammo_magazine/mc9mm/flash
+ hidden = 1
+ category = "Arms and Ammunition"
+
+/datum/autolathe/recipe/magazine_c20r
+ name = "ammunition (12mm)"
+ path = /obj/item/ammo_magazine/a12mm
+ hidden = 1
+ category = "Arms and Ammunition"
+
/datum/autolathe/recipe/shotgun
name = "ammunition (slug, shotgun)"
path = /obj/item/ammo_casing/shotgun
@@ -306,6 +329,12 @@
hidden = 1
category = "Arms and Ammunition"
+/datum/autolathe/recipe/stunshell
+ name = "ammunition (stun cartridge, shotgun)"
+ path = /obj/item/ammo_casing/shotgun/stunshell
+ hidden = 1
+ category = "Arms and Ammunition"
+
/datum/autolathe/recipe/rcd
name = "rapid construction device"
path = /obj/item/weapon/rcd
diff --git a/code/game/machinery/bots/ed209bot.dm b/code/game/machinery/bots/ed209bot.dm
index 24e29e2839..639da55bf5 100644
--- a/code/game/machinery/bots/ed209bot.dm
+++ b/code/game/machinery/bots/ed209bot.dm
@@ -34,10 +34,10 @@
var/obj/item/weapon/gun/energy/taser/G = new /obj/item/weapon/gun/energy/taser(Tsec)
G.power_supply.charge = 0
else if(lasercolor == "b")
- var/obj/item/weapon/gun/energy/laser/bluetag/G = new /obj/item/weapon/gun/energy/laser/bluetag(Tsec)
+ var/obj/item/weapon/gun/energy/lasertag/blue/G = new (Tsec)
G.power_supply.charge = 0
else if(lasercolor == "r")
- var/obj/item/weapon/gun/energy/laser/redtag/G = new /obj/item/weapon/gun/energy/laser/redtag(Tsec)
+ var/obj/item/weapon/gun/energy/lasertag/red/G = new (Tsec)
G.power_supply.charge = 0
if (prob(50))
new /obj/item/robot_parts/l_leg(Tsec)
@@ -137,11 +137,11 @@
if(7)
switch(lasercolor)
if("b")
- if( !istype(W, /obj/item/weapon/gun/energy/laser/bluetag) )
+ if( !istype(W, /obj/item/weapon/gun/energy/lasertag/blue) )
return
name = "bluetag ED-209 assembly"
if("r")
- if( !istype(W, /obj/item/weapon/gun/energy/laser/redtag) )
+ if( !istype(W, /obj/item/weapon/gun/energy/lasertag/red) )
return
name = "redtag ED-209 assembly"
if("")
diff --git a/code/game/machinery/bots/medbot.dm b/code/game/machinery/bots/medbot.dm
index 65a40289d0..a83f59d03f 100644
--- a/code/game/machinery/bots/medbot.dm
+++ b/code/game/machinery/bots/medbot.dm
@@ -455,7 +455,7 @@
return
/obj/machinery/bot/medbot/bullet_act(var/obj/item/projectile/Proj)
- if(Proj.flag == "taser")
+ if(Proj.taser_effect)
src.stunned = min(stunned+10,20)
..()
diff --git a/code/game/machinery/bots/secbot.dm b/code/game/machinery/bots/secbot.dm
index 1dcc02fbb9..6aa43c1b39 100644
--- a/code/game/machinery/bots/secbot.dm
+++ b/code/game/machinery/bots/secbot.dm
@@ -702,10 +702,10 @@ Auto Patrol: []"},
switch(lasercolor)
if("b")
target_suit = /obj/item/clothing/suit/redtag
- target_weapon = /obj/item/weapon/gun/energy/laser/redtag
+ target_weapon = /obj/item/weapon/gun/energy/lasertag/red
if("r")
target_suit = /obj/item/clothing/suit/bluetag
- target_weapon = /obj/item/weapon/gun/energy/laser/bluetag
+ target_weapon = /obj/item/weapon/gun/energy/lasertag/blue
if((istype(perp.r_hand, target_weapon)) || (istype(perp.l_hand, target_weapon)))
threat += 4
diff --git a/code/game/machinery/portable_tag_turret.dm b/code/game/machinery/portable_tag_turret.dm
index 13f7032aa3..c9c2331e6d 100644
--- a/code/game/machinery/portable_tag_turret.dm
+++ b/code/game/machinery/portable_tag_turret.dm
@@ -5,13 +5,13 @@
/obj/machinery/porta_turret/tag
// Reasonable defaults, in case someone manually spawns us
var/lasercolor = "r" //Something to do with lasertag turrets, blame Sieve for not adding a comment.
- installation = /obj/item/weapon/gun/energy/laser/redtag
+ installation = /obj/item/weapon/gun/energy/lasertag/red
/obj/machinery/porta_turret/tag/red
/obj/machinery/porta_turret/tag/blue
lasercolor = "b"
- installation = /obj/item/weapon/gun/energy/laser/bluetag
+ installation = /obj/item/weapon/gun/energy/lasertag/blue
/obj/machinery/porta_turret/tag/New()
..()
@@ -19,8 +19,8 @@
/obj/machinery/porta_turret/tag/weapon_setup(var/obj/item/weapon/gun/energy/E)
switch(E.type)
- if(/obj/item/weapon/gun/energy/laser/bluetag)
- eprojectile = /obj/item/weapon/gun/energy/laser/bluetag
+ if(/obj/item/weapon/gun/energy/lasertag/blue)
+ eprojectile = /obj/item/weapon/gun/energy/lasertag/blue
lasercolor = "b"
req_access = list(access_maint_tunnels, access_theatre)
check_arrest = 0
@@ -30,8 +30,8 @@
check_anomalies = 0
shot_delay = 30
- if(/obj/item/weapon/gun/energy/laser/redtag)
- eprojectile = /obj/item/weapon/gun/energy/laser/redtag
+ if(/obj/item/weapon/gun/energy/lasertag/red)
+ eprojectile = /obj/item/weapon/gun/energy/lasertag/red
lasercolor = "r"
req_access = list(access_maint_tunnels, access_theatre)
check_arrest = 0
@@ -86,13 +86,13 @@
..()
if(lasercolor == "b" && disabled == 0)
- if(istype(Proj, /obj/item/weapon/gun/energy/laser/redtag))
+ if(istype(Proj, /obj/item/weapon/gun/energy/lasertag/red))
disabled = 1
del(Proj) // qdel
sleep(100)
disabled = 0
if(lasercolor == "r" && disabled == 0)
- if(istype(Proj, /obj/item/weapon/gun/energy/laser/bluetag))
+ if(istype(Proj, /obj/item/weapon/gun/energy/lasertag/blue))
disabled = 1
del(Proj) // qdel
sleep(100)
@@ -110,10 +110,10 @@
switch(lasercolor)
if("b")
target_suit = /obj/item/clothing/suit/redtag
- target_weapon = /obj/item/weapon/gun/energy/laser/redtag
+ target_weapon = /obj/item/weapon/gun/energy/lasertag/red
if("r")
target_suit = /obj/item/clothing/suit/bluetag
- target_weapon = /obj/item/weapon/gun/energy/laser/bluetag
+ target_weapon = /obj/item/weapon/gun/energy/lasertag/blue
if(target_suit)//Lasertag turrets target the opposing team, how great is that? -Sieve
diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm
index c531e53f96..a2dda1e400 100644
--- a/code/game/machinery/portable_turret.dm
+++ b/code/game/machinery/portable_turret.dm
@@ -733,7 +733,7 @@
gun_charge = E.power_supply.charge //the gun's charge is stored in gun_charge
user << "You add [I] to the turret."
- if(istype(installation, /obj/item/weapon/gun/energy/laser/bluetag) || istype(installation, /obj/item/weapon/gun/energy/laser/redtag))
+ if(istype(installation, /obj/item/weapon/gun/energy/lasertag/blue) || istype(installation, /obj/item/weapon/gun/energy/lasertag/red))
target_type = /obj/machinery/porta_turret/tag
else
target_type = /obj/machinery/porta_turret
diff --git a/code/game/mecha/combat/marauder.dm b/code/game/mecha/combat/marauder.dm
index cdb3645c62..d7e64c1ece 100644
--- a/code/game/mecha/combat/marauder.dm
+++ b/code/game/mecha/combat/marauder.dm
@@ -151,6 +151,7 @@
smoke_ready = 1
return
+//TODO replace this with zoom code that doesn't increase peripherial vision
/obj/mecha/combat/marauder/verb/zoom()
set category = "Exosuit Interface"
set name = "Zoom"
diff --git a/code/game/mecha/equipment/tools/tools.dm b/code/game/mecha/equipment/tools/tools.dm
index 5b71a34ec6..8338e2caa7 100644
--- a/code/game/mecha/equipment/tools/tools.dm
+++ b/code/game/mecha/equipment/tools/tools.dm
@@ -585,7 +585,7 @@
chassis.visible_message("The [chassis.name] armor deflects the projectile")
chassis.log_append_to_last("Armor saved.")
else
- chassis.take_damage(round(Proj.damage*src.damage_coeff),Proj.flag)
+ chassis.take_damage(round(Proj.damage*src.damage_coeff),Proj.check_armour)
chassis.check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST))
Proj.on_hit(chassis)
set_ready_state(0)
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index 4790550700..f57e2e046d 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -487,7 +487,7 @@
/obj/mecha/bullet_act(var/obj/item/projectile/Proj) //wrapper
- src.log_message("Hit by projectile. Type: [Proj.name]([Proj.flag]).",1)
+ src.log_message("Hit by projectile. Type: [Proj.name]([Proj.check_armour]).",1)
call((proc_res["dynbulletdamage"]||src), "dynbulletdamage")(Proj) //calls equipment
..()
return
@@ -506,10 +506,10 @@
var/ignore_threshold
if(istype(Proj, /obj/item/projectile/beam/pulse))
ignore_threshold = 1
- src.take_damage(Proj.damage, Proj.flag)
+ src.take_damage(Proj.damage, Proj.check_armour)
if(prob(25)) spark_system.start()
src.check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT),ignore_threshold)
-
+
//AP projectiles have a chance to cause additional damage
if(Proj.penetrating)
var/distance = get_dist(Proj.starting, get_turf(loc))
@@ -520,9 +520,9 @@
hit_occupant = 0
else
src.check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT), 1)
-
+
Proj.penetrating--
-
+
if(prob(15))
break //give a chance to exit early
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 1e3cb7547a..f622c28e7c 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -638,8 +638,8 @@ For zooming with scope or binoculars. This is called from
modules/mob/mob_movement.dm if you move you will be zoomed out
modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out.
*/
-
-/obj/item/proc/zoom(var/tileoffset = 11,var/viewsize = 12) //tileoffset is client view offset in the direction the user is facing. viewsize is how far out this thing zooms. 7 is normal view
+//Looking through a scope or binoculars should /not/ improve your periphereal vision. Still, increase viewsize a tiny bit so that sniping isn't as restricted to NSEW
+/obj/item/proc/zoom(var/tileoffset = 14,var/viewsize = 9) //tileoffset is client view offset in the direction the user is facing. viewsize is how far out this thing zooms. 7 is normal view
var/devicename
@@ -686,14 +686,6 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out.
usr.visible_message("[usr] peers through the [zoomdevicename ? "[zoomdevicename] of the [src.name]" : "[src.name]"].")
- /*
- if(istype(usr,/mob/living/carbon/human/))
- var/mob/living/carbon/human/H = usr
- usr.visible_message("[usr] holds [devicename] up to [H.get_visible_gender() == MALE ? "his" : H.get_visible_gender() == FEMALE ? "her" : "their"] eyes.")
- else
- usr.visible_message("[usr] holds [devicename] up to its eyes.")
- */
-
else
usr.client.view = world.view
if(!usr.hud_used.hud_shown)
diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm
index f9d3e356ce..9bc40c779d 100644
--- a/code/game/objects/items/robot/robot_upgrades.dm
+++ b/code/game/objects/items/robot/robot_upgrades.dm
@@ -121,7 +121,7 @@
usr << "There's no mounting point for the module!"
return 0
- var/obj/item/weapon/gun/energy/taser/cyborg/T = locate() in R.module
+ var/obj/item/weapon/gun/energy/taser/mounted/cyborg/T = locate() in R.module
if(!T)
T = locate() in R.module.contents
if(!T)
diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm
index 8a974df69a..e9b7a54562 100644
--- a/code/game/objects/items/toys.dm
+++ b/code/game/objects/items/toys.dm
@@ -140,7 +140,7 @@
icon_state = "revolver"
item_state = "gun"
flags = CONDUCT
- slot_flags = SLOT_BELT
+ slot_flags = SLOT_BELT|SLOT_HOLSTER
w_class = 3.0
matter = list("glass" = 10,"metal" = 10)
diff --git a/code/game/objects/items/weapons/grenades/flashbang.dm b/code/game/objects/items/weapons/grenades/flashbang.dm
index a332f6fa92..bda28f83b1 100644
--- a/code/game/objects/items/weapons/grenades/flashbang.dm
+++ b/code/game/objects/items/weapons/grenades/flashbang.dm
@@ -21,6 +21,7 @@
B.health -= damage
B.update_icon()
+ new/obj/effect/effect/sparks(src.loc)
new/obj/effect/effect/smoke/illumination(src.loc, brightness=15)
del(src)
return
diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm
index aaa77bf663..3376d3a4f8 100644
--- a/code/game/objects/items/weapons/storage/boxes.dm
+++ b/code/game/objects/items/weapons/storage/boxes.dm
@@ -79,7 +79,6 @@
/obj/item/weapon/storage/box/syringes
name = "box of syringes"
desc = "A box full of syringes."
- desc = "A biohazard alert warning is printed on the box"
icon_state = "syringe"
New()
@@ -92,6 +91,22 @@
new /obj/item/weapon/reagent_containers/syringe( src )
new /obj/item/weapon/reagent_containers/syringe( src )
+/obj/item/weapon/storage/box/syringegun
+ name = "box of syringe gun cartridges"
+ desc = "A box full of compressed gas cartridges."
+ icon_state = "syringe"
+
+ New()
+ ..()
+ new /obj/item/weapon/syringe_cartridge( src )
+ new /obj/item/weapon/syringe_cartridge( src )
+ new /obj/item/weapon/syringe_cartridge( src )
+ new /obj/item/weapon/syringe_cartridge( src )
+ new /obj/item/weapon/syringe_cartridge( src )
+ new /obj/item/weapon/syringe_cartridge( src )
+ new /obj/item/weapon/syringe_cartridge( src )
+
+
/obj/item/weapon/storage/box/beakers
name = "box of beakers"
icon_state = "beaker"
@@ -176,6 +191,48 @@
new /obj/item/ammo_casing/shotgun/pellet(src)
new /obj/item/ammo_casing/shotgun/pellet(src)
+/obj/item/weapon/storage/box/flashshells
+ name = "box of illumination shells"
+ desc = "It has a picture of a gun and several warning symbols on the front.
WARNING: Live ammunition. Misuse may result in serious injury or death."
+
+ New()
+ ..()
+ new /obj/item/ammo_casing/shotgun/flash(src)
+ new /obj/item/ammo_casing/shotgun/flash(src)
+ new /obj/item/ammo_casing/shotgun/flash(src)
+ new /obj/item/ammo_casing/shotgun/flash(src)
+ new /obj/item/ammo_casing/shotgun/flash(src)
+ new /obj/item/ammo_casing/shotgun/flash(src)
+ new /obj/item/ammo_casing/shotgun/flash(src)
+
+/obj/item/weapon/storage/box/stunshells
+ name = "box of stun shells"
+ desc = "It has a picture of a gun and several warning symbols on the front.
WARNING: Live ammunition. Misuse may result in serious injury or death."
+
+ New()
+ ..()
+ new /obj/item/ammo_casing/shotgun/stunshell(src)
+ new /obj/item/ammo_casing/shotgun/stunshell(src)
+ new /obj/item/ammo_casing/shotgun/stunshell(src)
+ new /obj/item/ammo_casing/shotgun/stunshell(src)
+ new /obj/item/ammo_casing/shotgun/stunshell(src)
+ new /obj/item/ammo_casing/shotgun/stunshell(src)
+ new /obj/item/ammo_casing/shotgun/stunshell(src)
+
+/obj/item/weapon/storage/box/heavysniperammo
+ name = "box of 14.5mm AP shells"
+ desc = "It has a picture of a gun and several warning symbols on the front.
WARNING: Live ammunition. Misuse may result in serious injury or death."
+
+ New()
+ ..()
+ new /obj/item/ammo_casing/a145(src)
+ new /obj/item/ammo_casing/a145(src)
+ new /obj/item/ammo_casing/a145(src)
+ new /obj/item/ammo_casing/a145(src)
+ new /obj/item/ammo_casing/a145(src)
+ new /obj/item/ammo_casing/a145(src)
+ new /obj/item/ammo_casing/a145(src)
+
/obj/item/weapon/storage/box/flashbangs
name = "box of flashbangs (WARNING)"
desc = "WARNING: These devices are extremely dangerous and can cause blindness or deafness in repeated use."
diff --git a/code/game/objects/items/weapons/storage/uplink_kits.dm b/code/game/objects/items/weapons/storage/uplink_kits.dm
index aa66b26f12..9d0a5d8296 100644
--- a/code/game/objects/items/weapons/storage/uplink_kits.dm
+++ b/code/game/objects/items/weapons/storage/uplink_kits.dm
@@ -26,7 +26,7 @@
return
if("guns")
- new /obj/item/weapon/gun/projectile(src)
+ new /obj/item/weapon/gun/projectile/revolver(src)
new /obj/item/ammo_magazine/a357(src)
new /obj/item/weapon/card/emag(src)
new /obj/item/weapon/plastique(src)
diff --git a/code/game/objects/structures/crates_lockers/closets/fitness.dm b/code/game/objects/structures/crates_lockers/closets/fitness.dm
index 05e7968a93..b42fe3f950 100644
--- a/code/game/objects/structures/crates_lockers/closets/fitness.dm
+++ b/code/game/objects/structures/crates_lockers/closets/fitness.dm
@@ -54,8 +54,8 @@
/obj/structure/closet/lasertag/red/New()
..()
- new /obj/item/weapon/gun/energy/laser/redtag(src)
- new /obj/item/weapon/gun/energy/laser/redtag(src)
+ new /obj/item/weapon/gun/energy/lasertag/red(src)
+ new /obj/item/weapon/gun/energy/lasertag/red(src)
new /obj/item/clothing/suit/redtag(src)
new /obj/item/clothing/suit/redtag(src)
@@ -68,7 +68,7 @@
/obj/structure/closet/lasertag/blue/New()
..()
- new /obj/item/weapon/gun/energy/laser/bluetag(src)
- new /obj/item/weapon/gun/energy/laser/bluetag(src)
+ new /obj/item/weapon/gun/energy/lasertag/blue(src)
+ new /obj/item/weapon/gun/energy/lasertag/blue(src)
new /obj/item/clothing/suit/bluetag(src)
new /obj/item/clothing/suit/bluetag(src)
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
index 6ee564d76b..672978400c 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
@@ -54,6 +54,7 @@
new /obj/item/weapon/storage/box/ids(src)
new /obj/item/weapon/storage/box/ids( src )
new /obj/item/weapon/gun/energy/gun(src)
+ new /obj/item/weapon/gun/projectile/colt/flash(src)
new /obj/item/device/flash(src)
return
@@ -258,10 +259,10 @@
new /obj/item/device/radio/headset/headset_sec(src)
new /obj/item/device/detective_scanner(src)
new /obj/item/clothing/suit/armor/det_suit(src)
- new /obj/item/ammo_magazine/c45r(src)
- new /obj/item/ammo_magazine/c45r(src)
+ new /obj/item/ammo_magazine/c45m/rubber(src)
+ new /obj/item/ammo_magazine/c45m/rubber(src)
new /obj/item/taperoll/police(src)
- new /obj/item/weapon/gun/projectile/detective/semiauto(src)
+ new /obj/item/weapon/gun/projectile/colt/detective(src)
new /obj/item/clothing/accessory/holster/armpit(src)
return
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index db7f0ec78b..769615af0f 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -595,7 +595,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
M.equip_to_slot_or_del(new /obj/item/weapon/cloaking_device(M), slot_r_store)
- M.equip_to_slot_or_del(new /obj/item/weapon/gun/projectile(M), slot_r_hand)
+ M.equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/revolver(M), slot_r_hand)
M.equip_to_slot_or_del(new /obj/item/ammo_magazine/a357(M), slot_l_store)
if ("tournament chef") //Steven Seagal FTW
@@ -710,7 +710,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
for(var/i=3, i>0, i--)
sec_briefcase.contents += new /obj/item/weapon/spacecash/c1000
sec_briefcase.contents += new /obj/item/weapon/gun/energy/crossbow
- sec_briefcase.contents += new /obj/item/weapon/gun/projectile/mateba
+ sec_briefcase.contents += new /obj/item/weapon/gun/projectile/revolver/mateba
sec_briefcase.contents += new /obj/item/ammo_magazine/a357
sec_briefcase.contents += new /obj/item/weapon/plastique
M.equip_to_slot_or_del(sec_briefcase, slot_l_hand)
@@ -892,7 +892,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
M.equip_to_slot_or_del(new /obj/item/clothing/glasses/thermal/eyepatch(M), slot_glasses)
M.equip_to_slot_or_del(new /obj/item/clothing/suit/hgpirate(M), slot_wear_suit)
M.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(M), slot_back)
- M.equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/mateba(M), slot_belt)
+ M.equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/revolver/mateba(M), slot_belt)
M.equip_to_slot_or_del(new /obj/item/clothing/under/soviet(M), slot_w_uniform)
var/obj/item/weapon/card/id/W = new(M)
W.name = "[M.real_name]'s ID Card"
diff --git a/code/modules/admin/verbs/striketeam.dm b/code/modules/admin/verbs/striketeam.dm
index 36199c0305..9f42da94d9 100644
--- a/code/modules/admin/verbs/striketeam.dm
+++ b/code/modules/admin/verbs/striketeam.dm
@@ -153,7 +153,7 @@ var/global/sent_strike_team = 0
equip_to_slot_or_del(new /obj/item/weapon/melee/energy/sword(src), slot_l_store)
equip_to_slot_or_del(new /obj/item/weapon/grenade/flashbang(src), slot_r_store)
equip_to_slot_or_del(new /obj/item/weapon/tank/emergency_oxygen(src), slot_s_store)
- equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/mateba(src), slot_belt)
+ equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/revolver/mateba(src), slot_belt)
equip_to_slot_or_del(new /obj/item/weapon/gun/energy/pulse_rifle(src), slot_r_hand)
diff --git a/code/modules/admin/verbs/vox_raiders.dm b/code/modules/admin/verbs/vox_raiders.dm
index 6676acec32..6c34bb92c6 100644
--- a/code/modules/admin/verbs/vox_raiders.dm
+++ b/code/modules/admin/verbs/vox_raiders.dm
@@ -37,7 +37,7 @@ var/global/vox_tick = 1
equip_to_slot_or_del(new /obj/item/weapon/storage/belt/utility/full(src), slot_belt)
equip_to_slot_or_del(new /obj/item/clothing/glasses/thermal/monocle(src), slot_glasses) // REPLACE WITH CODED VOX ALTERNATIVE.
equip_to_slot_or_del(new /obj/item/weapon/card/emag(src), slot_l_store)
- equip_to_slot_or_del(new /obj/item/weapon/gun/dartgun/vox/raider(src), slot_r_hand)
+ equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/dartgun/vox/raider(src), slot_r_hand)
equip_to_slot_or_del(new /obj/item/device/multitool(src), slot_l_hand)
if(4) // Vox medic!
@@ -46,7 +46,7 @@ var/global/vox_tick = 1
equip_to_slot_or_del(new /obj/item/weapon/storage/belt/utility/full(src), slot_belt) // Who needs actual surgical tools?
equip_to_slot_or_del(new /obj/item/clothing/glasses/hud/health(src), slot_glasses) // REPLACE WITH CODED VOX ALTERNATIVE.
equip_to_slot_or_del(new /obj/item/weapon/circular_saw(src), slot_l_store)
- equip_to_slot_or_del(new /obj/item/weapon/gun/dartgun/vox/medical, slot_r_hand)
+ equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/dartgun/vox/medical, slot_r_hand)
equip_to_slot_or_del(new /obj/item/clothing/mask/breath(src), slot_wear_mask)
equip_to_slot_or_del(new /obj/item/weapon/tank/nitrogen(src), slot_back)
diff --git a/code/modules/clothing/spacesuits/rig/modules/rig_weapons.dm b/code/modules/clothing/spacesuits/rig/modules/rig_weapons.dm
deleted file mode 100644
index 792a6ed0d0..0000000000
--- a/code/modules/clothing/spacesuits/rig/modules/rig_weapons.dm
+++ /dev/null
@@ -1,51 +0,0 @@
-//Weapon types intended to be used with rig modules
-
-/obj/item/weapon/gun/energy/lasercannon/mounted/load_into_chamber()
- if(in_chamber)
- return 1
- var/obj/item/rig_module/module = loc
- if(!istype(module))
- return 0
- if(module.holder && module.holder.wearer)
- var/mob/living/carbon/human/H = module.holder.wearer
- if(istype(H) && H.back)
- var/obj/item/weapon/rig/suit = H.back
- if(istype(suit) && suit.cell && suit.cell.charge >= 250)
- suit.cell.use(250)
- in_chamber = new /obj/item/projectile/beam/heavylaser(src)
- return 1
- return 0
-
-/obj/item/weapon/gun/energy/gun/mounted/load_into_chamber()
- if(in_chamber)
- return 1
- var/obj/item/rig_module/module = loc
- if(!istype(module))
- return 0
- if(module.holder && module.holder.wearer)
- var/mob/living/carbon/human/H = module.holder.wearer
- if(istype(H) && H.back)
- var/obj/item/weapon/rig/suit = H.back
- if(istype(suit) && suit.cell && suit.cell.charge >= 250)
- suit.cell.use(250)
- var/prog_path = projectile_type
- in_chamber = new prog_path(src)
- return 1
- return 0
-
-/obj/item/weapon/gun/energy/taser/mounted/load_into_chamber()
- if(in_chamber)
- return 1
- var/obj/item/rig_module/module = loc
- if(!istype(module))
- return 0
- if(module.holder && module.holder.wearer)
- var/mob/living/carbon/human/H = module.holder.wearer
- if(istype(H) && H.back)
- var/obj/item/weapon/rig/suit = H.back
- if(istype(suit) && suit.cell && suit.cell.charge >= 250)
- suit.cell.use(250)
- var/prog_path = projectile_type
- in_chamber = new prog_path(src)
- return 1
- return 0
\ No newline at end of file
diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm
index 6a5dd04cb6..acc8443f90 100644
--- a/code/modules/clothing/suits/armor.dm
+++ b/code/modules/clothing/suits/armor.dm
@@ -196,38 +196,31 @@
slowdown = 1
armor = list(melee = 60, bullet = 60, laser = 60, energy = 40, bomb = 20, bio = 0, rad = 0)
siemens_coefficient = 0.7
+ var/obj/item/clothing/accessory/holster/holster
+
+/obj/item/clothing/suit/armor/tactical/New()
+ ..()
+ holster = new(src)
- /obj/item/clothing/suit/armor/tactical/verb/holster()
- set name = "Holster"
- set category = "Object"
- set src in usr
- if(!istype(usr, /mob/living)) return
- if(usr.stat) return
+/obj/item/clothing/suit/armor/tactical/attackby(obj/item/W as obj, mob/user as mob)
+ ..()
+ holster.attackby(W, user)
- if(!holstered)
- if(!istype(usr.get_active_hand(), /obj/item/weapon/gun))
- usr << "\blue You need your gun equiped to holster it."
- return
- var/obj/item/weapon/gun/W = usr.get_active_hand()
- if (!W.isHandgun())
- usr << "\red This gun won't fit in \the belt!"
- return
- holstered = usr.get_active_hand()
- usr.drop_item()
- holstered.loc = src
- usr.visible_message("\blue \The [usr] holsters \the [holstered].", "You holster \the [holstered].")
- else
- if(istype(usr.get_active_hand(),/obj) && istype(usr.get_inactive_hand(),/obj))
- usr << "\red You need an empty hand to draw the gun!"
- else
- if(usr.a_intent == "hurt")
- usr.visible_message("\red \The [usr] draws \the [holstered], ready to shoot!", \
- "\red You draw \the [holstered], ready to shoot!")
- else
- usr.visible_message("\blue \The [usr] draws \the [holstered], pointing it at the ground.", \
- "\blue You draw \the [holstered], pointing it at the ground.")
- usr.put_in_hands(holstered)
- holstered = null
+/obj/item/clothing/suit/armor/tactical/verb/holster()
+ set name = "Holster"
+ set category = "Object"
+ set src in usr
+ if(!istype(usr, /mob/living)) return
+ if(usr.stat) return
+
+ if(!holster.holstered)
+ var/obj/item/W = usr.get_active_hand()
+ if(!istype(W, /obj/item))
+ usr << "You need your gun equiped to holster it."
+ return
+ holster.holster(W, usr)
+ else
+ holster.unholster(usr)
//Non-hardsuit ERT armor.
/obj/item/clothing/suit/armor/vest/ert
diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm
index 09e67ea871..bcca81141c 100644
--- a/code/modules/clothing/suits/miscellaneous.dm
+++ b/code/modules/clothing/suits/miscellaneous.dm
@@ -15,7 +15,7 @@
item_state = "bluetag"
blood_overlay_type = "armor"
body_parts_covered = UPPER_TORSO
- allowed = list (/obj/item/weapon/gun/energy/laser/bluetag)
+ allowed = list (/obj/item/weapon/gun/energy/lasertag/blue)
siemens_coefficient = 3.0
/obj/item/clothing/suit/redtag
@@ -25,7 +25,7 @@
item_state = "redtag"
blood_overlay_type = "armor"
body_parts_covered = UPPER_TORSO
- allowed = list (/obj/item/weapon/gun/energy/laser/redtag)
+ allowed = list (/obj/item/weapon/gun/energy/lasertag/red)
siemens_coefficient = 3.0
/*
diff --git a/code/modules/clothing/under/accessories/holster.dm b/code/modules/clothing/under/accessories/holster.dm
index af2743e43f..1a18604b6f 100644
--- a/code/modules/clothing/under/accessories/holster.dm
+++ b/code/modules/clothing/under/accessories/holster.dm
@@ -4,45 +4,40 @@
icon_state = "holster"
item_color = "holster"
slot = "utility"
- var/obj/item/weapon/gun/holstered = null
-
-//subtypes can override this to specify what can be holstered
-/obj/item/clothing/accessory/holster/proc/can_holster(obj/item/weapon/gun/W)
- return W.isHandgun()
+ var/obj/item/holstered = null
/obj/item/clothing/accessory/holster/proc/holster(obj/item/I, mob/user as mob)
if(holstered)
- user << "There is already a [holstered] holstered here!"
+ user << "There is already \a [holstered] holstered here!"
return
- if (!istype(I, /obj/item/weapon/gun))
- user << "Only guns can be holstered!"
+ if (!(I.slot_flags & SLOT_HOLSTER))
+ user << "[I] won't fit in [src]!"
return
- var/obj/item/weapon/gun/W = I
- if (!can_holster(W))
- user << "This [W] won't fit in the [src]!"
- return
-
- holstered = W
+ holstered = I
user.drop_from_inventory(holstered)
holstered.loc = src
holstered.add_fingerprint(user)
- user.visible_message("[user] holsters the [holstered].", "You holster the [holstered].")
+ user.visible_message("[user] holsters \the [holstered].", "You holster \the [holstered].")
/obj/item/clothing/accessory/holster/proc/unholster(mob/user as mob)
if(!holstered)
return
if(istype(user.get_active_hand(),/obj) && istype(user.get_inactive_hand(),/obj))
- user << "You need an empty hand to draw the [holstered]!"
+ user << "You need an empty hand to draw \the [holstered]!"
else
if(user.a_intent == "hurt")
- usr.visible_message("\red [user] draws the [holstered], ready to shoot!", \
- "You draw the [holstered], ready to shoot!")
+ usr.visible_message(
+ "\red [user] draws \the [holstered], ready to shoot!",
+ "You draw \the [holstered], ready to shoot!"
+ )
else
- user.visible_message("[user] draws the [holstered], pointing it at the ground.", \
- "You draw the [holstered], pointing it at the ground.")
+ user.visible_message(
+ "[user] draws \the [holstered], pointing it at the ground.",
+ "You draw \the [holstered], pointing it at the ground."
+ )
user.put_in_hands(holstered)
holstered.add_fingerprint(user)
holstered = null
@@ -86,6 +81,7 @@
if(!istype(usr, /mob/living)) return
if(usr.stat) return
+ //can't we just use src here?
var/obj/item/clothing/accessory/holster/H = null
if (istype(src, /obj/item/clothing/accessory/holster))
H = src
@@ -98,10 +94,10 @@
usr << "Something is very wrong."
if(!H.holstered)
- if(!istype(usr.get_active_hand(), /obj/item/weapon/gun))
+ var/obj/item/W = usr.get_active_hand()
+ if(!istype(W, /obj/item))
usr << "You need your gun equiped to holster it."
return
- var/obj/item/weapon/gun/W = usr.get_active_hand()
H.holster(W, usr)
else
H.unholster(usr)
diff --git a/code/modules/customitems/item_defines.dm b/code/modules/customitems/item_defines.dm
index 11a3fa03d4..95593385a0 100644
--- a/code/modules/customitems/item_defines.dm
+++ b/code/modules/customitems/item_defines.dm
@@ -1340,22 +1340,21 @@
desc = "A stun baton used for incapacitating targets; there seems to be a bunch of tally marks set into the handle."
///// Deckard .44 - Callum Leamas - Roaper
-/obj/item/weapon/gun/projectile/detective/fluff/callum_leamas
+/obj/item/weapon/gun/projectile/revolver/detective/fluff/callum_leamas
name = "Deckard .44"
desc = "A custom built revolver, based off the semi-popular Detective Special model."
icon = 'icons/obj/custom_items.dmi'
icon_state = "leamas-empty"
+ ammo_type = /obj/item/ammo_magazine/c38/rubber
-/obj/item/weapon/gun/projectile/detective/fluff/callum_leamas/update_icon()
-
+/obj/item/weapon/gun/projectile/revolver/detective/fluff/callum_leamas/update_icon()
..()
if(loaded.len)
icon_state = "leamas-loaded"
else
icon_state = "leamas-empty"
-/obj/item/weapon/gun/projectile/attackby(var/obj/item/A as obj, mob/user as mob)
-
+/obj/item/weapon/gun/projectile/revolver/detective/fluff/callum_leamas/load_ammo(var/obj/item/A, mob/user)
if(istype(A, /obj/item/ammo_magazine))
flick("leamas-reloading",src)
..()
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index dd5bfe7d59..38ffc73f4e 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -1220,10 +1220,11 @@
/mob/living/carbon/human/can_inject(var/mob/user, var/error_msg, var/target_zone)
. = 1
- if(!user)
- target_zone = pick("chest","chest","chest","left leg","right leg","left arm", "right arm", "head")
- else if(!target_zone)
- target_zone = user.zone_sel.selecting
+ if(!target_zone)
+ if(!user)
+ target_zone = pick("chest","chest","chest","left leg","right leg","left arm", "right arm", "head")
+ else
+ target_zone = user.zone_sel.selecting
switch(target_zone)
if("head")
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index a45a11f453..399eabcf04 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -304,10 +304,7 @@ emp_act
throw_mode_off()
return
- var/dtype = BRUTE
- if(istype(O,/obj/item/weapon))
- var/obj/item/weapon/W = O
- dtype = W.damtype
+ var/dtype = O.damtype
var/throw_damage = O.throwforce*(speed/THROWFORCE_SPEED_DIVISOR)
var/zone
@@ -318,11 +315,11 @@ emp_act
zone = ran_zone("chest",75) //Hits a random part of the body, geared towards the chest
//check if we hit
+ var/miss_chance = 15
if (O.throw_source)
var/distance = get_dist(O.throw_source, loc)
- zone = get_zone_with_miss_chance(zone, src, min(15*(distance-2), 0))
- else
- zone = get_zone_with_miss_chance(zone, src, 15)
+ miss_chance = max(15*(distance-2), 0)
+ zone = get_zone_with_miss_chance(zone, src, miss_chance)
if(!zone)
visible_message("\blue \The [O] misses [src] narrowly!")
@@ -370,17 +367,21 @@ emp_act
affecting.embed(I)
// Begin BS12 momentum-transfer code.
- if(O.throw_source && speed >= THROWNOBJ_KNOCKBACK_SPEED)
- var/obj/item/weapon/W = O
- var/momentum = speed/THROWNOBJ_KNOCKBACK_DIVISOR
+ var/mass = 1.5
+ if(istype(O, /obj/item))
+ var/obj/item/I = O
+ mass = I.w_class/THROWNOBJ_KNOCKBACK_DIVISOR
+ var/momentum = speed*mass
+
+ if(O.throw_source && momentum >= THROWNOBJ_KNOCKBACK_SPEED)
var/dir = get_dir(O.throw_source, src)
visible_message("\red [src] staggers under the impact!","\red You stagger under the impact!")
src.throw_at(get_edge_target_turf(src,dir),1,momentum)
+
+ if(!O || !src) return
- if(!W || !src) return
-
- if(W.loc == src && W.sharp) //Projectile is embedded and suitable for pinning.
+ if(O.loc == src && O.sharp) //Projectile is embedded and suitable for pinning.
var/turf/T = near_wall(dir,2)
if(T)
@@ -389,6 +390,13 @@ emp_act
src.anchored = 1
src.pinned += O
+/mob/living/carbon/human/embed(var/obj/O, var/def_zone=null)
+ if(!def_zone) ..()
+
+ var/datum/organ/external/affecting = get_organ(def_zone)
+ if(affecting)
+ affecting.embed(O)
+
/mob/living/carbon/human/proc/bloody_hands(var/mob/living/source, var/amount = 2)
if (gloves)
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index b33c182b28..eb0c9ce859 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -63,10 +63,10 @@
return
//Armor
- var/absorb = run_armor_check(def_zone, P.flag)
+ var/absorb = run_armor_check(def_zone, P.check_armour)
var/proj_sharp = is_sharp(P)
var/proj_edge = has_edge(P)
- if ((proj_sharp || proj_edge) && prob(getarmor(def_zone, P.flag)))
+ if ((proj_sharp || proj_edge) && prob(getarmor(def_zone, P.check_armour)))
proj_sharp = 0
proj_edge = 0
@@ -103,16 +103,13 @@
/mob/living/hitby(atom/movable/AM as mob|obj,var/speed = THROWFORCE_SPEED_DIVISOR)//Standardization and logging -Sieve
if(istype(AM,/obj/))
var/obj/O = AM
- var/dtype = BRUTE
- if(istype(O,/obj/item/weapon))
- var/obj/item/weapon/W = O
- dtype = W.damtype
+ var/dtype = O.damtype
var/throw_damage = O.throwforce*(speed/THROWFORCE_SPEED_DIVISOR)
var/miss_chance = 15
if (O.throw_source)
var/distance = get_dist(O.throw_source, loc)
- miss_chance = min(15*(distance-2), 0)
+ miss_chance = max(15*(distance-2), 0)
if (prob(miss_chance))
visible_message("\blue \The [O] misses [src] narrowly!")
@@ -136,20 +133,23 @@
msg_admin_attack("[src.name] ([src.ckey]) was hit by a [O], thrown by [M.name] ([assailant.ckey]) (JMP)")
// Begin BS12 momentum-transfer code.
- if(O.throw_source && speed >= THROWNOBJ_KNOCKBACK_SPEED)
- var/obj/item/weapon/W = O
- var/momentum = speed/THROWNOBJ_KNOCKBACK_DIVISOR
+ var/mass = 1.5
+ if(istype(O, /obj/item))
+ var/obj/item/I = O
+ mass = I.w_class/THROWNOBJ_KNOCKBACK_DIVISOR
+ var/momentum = speed*mass
+
+ if(O.throw_source && momentum >= THROWNOBJ_KNOCKBACK_SPEED)
var/dir = get_dir(O.throw_source, src)
visible_message("\red [src] staggers under the impact!","\red You stagger under the impact!")
src.throw_at(get_edge_target_turf(src,dir),1,momentum)
- if(!W || !src) return
+ if(!O || !src) return
- if(W.sharp) //Projectile is suitable for pinning.
+ if(O.sharp) //Projectile is suitable for pinning.
//Handles embedding for non-humans and simple_animals.
- O.loc = src
- src.embedded += O
+ embed(O)
var/turf/T = near_wall(dir,2)
@@ -158,7 +158,11 @@
visible_message("[src] is pinned to the wall by [O]!","You are pinned to the wall by [O]!")
src.anchored = 1
src.pinned += O
- src.verbs += /mob/proc/yank_out_object
+
+/mob/living/proc/embed(var/obj/O, var/def_zone=null)
+ O.loc = src
+ src.embedded += O
+ src.verbs += /mob/proc/yank_out_object
//This is called when the mob is thrown into a dense turf
/mob/living/proc/turf_collision(var/turf/T, var/speed)
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index 3458a5bb47..9f213ad7e5 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -223,9 +223,9 @@
src.modules += new /obj/item/borg/sight/hud/sec(src)
src.modules += new /obj/item/weapon/handcuffs/cyborg(src)
src.modules += new /obj/item/weapon/melee/baton/robot(src)
- src.modules += new /obj/item/weapon/gun/energy/taser/cyborg(src)
+ src.modules += new /obj/item/weapon/gun/energy/taser/mounted/cyborg(src)
src.modules += new /obj/item/taperoll/police(src)
- src.emag = new /obj/item/weapon/gun/energy/laser/cyborg(src)
+ src.emag = new /obj/item/weapon/gun/energy/laser/mounted(src)
return
/obj/item/weapon/robot_module/security/respawn_consumable(var/mob/living/silicon/robot/R)
@@ -236,7 +236,7 @@
F.icon_state = "flash"
else if(F.times_used)
F.times_used--
- var/obj/item/weapon/gun/energy/taser/cyborg/T = locate() in src.modules
+ var/obj/item/weapon/gun/energy/taser/mounted/cyborg/T = locate() in src.modules
if(T.power_supply.charge < T.power_supply.maxcharge)
T.power_supply.give(T.charge_cost)
T.update_icon()
@@ -383,11 +383,11 @@
..()
src.modules += new /obj/item/device/flash(src)
src.modules += new /obj/item/borg/sight/thermal(src)
- src.modules += new /obj/item/weapon/gun/energy/laser/cyborg(src)
+ src.modules += new /obj/item/weapon/gun/energy/laser/mounted(src)
src.modules += new /obj/item/weapon/pickaxe/plasmacutter(src)
src.modules += new /obj/item/borg/combat/shield(src)
src.modules += new /obj/item/borg/combat/mobility(src)
- src.emag = new /obj/item/weapon/gun/energy/lasercannon/cyborg(src)
+ src.emag = new /obj/item/weapon/gun/energy/lasercannon/mounted(src)
return
/obj/item/weapon/robot_module/drone
diff --git a/code/modules/mob/living/silicon/robot/robot_upgrades.dm b/code/modules/mob/living/silicon/robot/robot_upgrades.dm
index 71f22a3029..a6d08bd534 100644
--- a/code/modules/mob/living/silicon/robot/robot_upgrades.dm
+++ b/code/modules/mob/living/silicon/robot/robot_upgrades.dm
@@ -108,7 +108,7 @@
usr << "There's no mounting point for the module!"
return 0
- var/obj/item/weapon/gun/energy/taser/cyborg/T = locate() in R.module
+ var/obj/item/weapon/gun/energy/taser/mounted/cyborg/T = locate() in R.module
if(!T)
T = locate() in R.module.contents
if(!T)
diff --git a/code/modules/mob/living/simple_animal/hostile/russian.dm b/code/modules/mob/living/simple_animal/hostile/russian.dm
index b09a6ec548..b96a615170 100644
--- a/code/modules/mob/living/simple_animal/hostile/russian.dm
+++ b/code/modules/mob/living/simple_animal/hostile/russian.dm
@@ -38,7 +38,7 @@
icon_state = "russianranged"
icon_living = "russianranged"
corpse = /obj/effect/landmark/mobcorpse/russian/ranged
- weapon1 = /obj/item/weapon/gun/projectile/mateba
+ weapon1 = /obj/item/weapon/gun/projectile/revolver/mateba
ranged = 1
projectiletype = /obj/item/projectile/bullet
projectilesound = 'sound/weapons/Gunshot.ogg'
diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm
index b45d0aafa7..25e12ebfbf 100644
--- a/code/modules/organs/organ_external.dm
+++ b/code/modules/organs/organ_external.dm
@@ -159,7 +159,7 @@
//If limb took enough damage, try to cut or tear it off
if(body_part != UPPER_TORSO && body_part != LOWER_TORSO) //as hilarious as it is, getting hit on the chest too much shouldn't effectively gib you.
if(config.limbs_can_break && brute_dam >= max_damage * config.organ_health_multiplier)
- if( (edge && prob(5 * brute)) || (brute > 20 && prob(2 * brute)) )
+ if( (edge && prob(5 * brute)) || (brute > 20 && prob(brute)) )
droplimb(1)
return
diff --git a/code/modules/power/antimatter/control.dm b/code/modules/power/antimatter/control.dm
index b6eb7915d2..23c5e0243a 100644
--- a/code/modules/power/antimatter/control.dm
+++ b/code/modules/power/antimatter/control.dm
@@ -127,7 +127,7 @@
/obj/machinery/power/am_control_unit/bullet_act(var/obj/item/projectile/Proj)
- if(Proj.flag != "bullet")
+ if(Proj.check_armour != "bullet")
stability -= Proj.force
return 0
diff --git a/code/modules/power/antimatter/shielding.dm b/code/modules/power/antimatter/shielding.dm
index bdaeb0c659..5085fb6c85 100644
--- a/code/modules/power/antimatter/shielding.dm
+++ b/code/modules/power/antimatter/shielding.dm
@@ -117,7 +117,7 @@ proc/cardinalrange(var/center)
/obj/machinery/am_shielding/bullet_act(var/obj/item/projectile/Proj)
- if(Proj.flag != "bullet")
+ if(Proj.check_armour != "bullet")
stability -= Proj.force/2
return 0
diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm
index 36ab1047a3..69f0b92a48 100644
--- a/code/modules/power/cell.dm
+++ b/code/modules/power/cell.dm
@@ -128,7 +128,7 @@
rigged = 1 //broken batterys are dangerous
/obj/item/weapon/cell/emp_act(severity)
- charge -= 1000 / severity
+ charge -= maxcharge / severity
if (charge < 0)
charge = 0
if(reliability != 100 && prob(50/severity))
diff --git a/code/modules/power/rust/virtual_particle_catcher.dm b/code/modules/power/rust/virtual_particle_catcher.dm
index 2d32a9a785..350d9f66fc 100644
--- a/code/modules/power/rust/virtual_particle_catcher.dm
+++ b/code/modules/power/rust/virtual_particle_catcher.dm
@@ -42,7 +42,7 @@
name = "collector [mysize] OFF"
/obj/effect/rust_particle_catcher/bullet_act(var/obj/item/projectile/Proj)
- if(Proj.flag != "bullet" && parent)
+ if(Proj.check_armour != "bullet" && parent)
parent.AddEnergy(Proj.damage * 20, 0, 1)
update_icon()
return 0
diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm
index b4b213972f..d31ba64814 100644
--- a/code/modules/projectiles/ammunition.dm
+++ b/code/modules/projectiles/ammunition.dm
@@ -6,73 +6,159 @@
flags = CONDUCT
slot_flags = SLOT_BELT
throwforce = 1
- w_class = 1.0
+ w_class = 1
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/obj/item/projectile/BB = null //The loaded bullet - make it so that the projectiles are created only when needed?
+ var/spent_icon = null
+/obj/item/ammo_casing/New()
+ ..()
+ if(ispath(projectile_type))
+ BB = new projectile_type(src)
+ pixel_x = rand(-10, 10)
+ pixel_y = rand(-10, 10)
- New()
- ..()
- if(ispath(projectile_type))
- BB = new projectile_type(src)
- pixel_x = rand(-10.0, 10)
- pixel_y = rand(-10.0, 10)
- set_dir(pick(cardinal))
-
+//removes the projectile from the ammo casing
+/obj/item/ammo_casing/proc/expend()
+ . = BB
+ BB = null
+ set_dir(pick(cardinal)) //spin spent casings
+ update_icon()
/obj/item/ammo_casing/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(istype(W, /obj/item/weapon/screwdriver))
- if(BB)
- if(initial(BB.name) == "bullet")
- var/tmp_label = ""
- var/label_text = sanitize(copytext(input(user, "Inscribe some text into \the [initial(BB.name)]","Inscription",tmp_label), 1, MAX_NAME_LEN))
- if(length(label_text) > 20)
- user << "\red The inscription can be at most 20 characters long."
- else
- if(label_text == "")
- user << "\blue You scratch the inscription off of [initial(BB)]."
- BB.name = initial(BB.name)
- else
- user << "\blue You inscribe \"[label_text]\" into \the [initial(BB.name)]."
- BB.name = "[initial(BB.name)] \"[label_text]\""
- else
- user << "\blue You can only inscribe a metal bullet." //because inscribing beanbags is silly
- else
+ if(!BB)
user << "\blue There is no bullet in the casing to inscribe anything into."
+ return
+
+ var/tmp_label = ""
+ var/label_text = sanitize(copytext(input(user, "Inscribe some text into \the [initial(BB.name)]","Inscription",tmp_label), 1, MAX_NAME_LEN))
+ if(length(label_text) > 20)
+ user << "\red The inscription can be at most 20 characters long."
+ else if(!label_text)
+ user << "\blue You scratch the inscription off of [initial(BB)]."
+ BB.name = initial(BB.name)
+ else
+ user << "\blue You inscribe \"[label_text]\" into \the [initial(BB.name)]."
+ BB.name = "[initial(BB.name)] (\"[label_text]\")"
+
+/obj/item/ammo_casing/update_icon()
+ if(spent_icon && !BB)
+ icon_state = spent_icon
/obj/item/ammo_casing/examine(mob/user)
..()
if (!BB)
user << "This one is spent."
-//Boxes of ammo
+//Gun loading types
+#define SINGLE_CASING 1 //The gun only accepts ammo_casings. ammo_magazines should never have this as their mag_type.
+#define SPEEDLOADER 2 //Transfers casings from the mag to the gun when used.
+#define MAGAZINE 4 //The magazine item itself goes inside the gun
+
+//An item that holds casings and can be used to put them inside guns
/obj/item/ammo_magazine
- name = "ammo box (.357)"
- desc = "A box of ammo"
+ name = "magazine"
+ desc = "A magazine for some kind of gun."
icon_state = "357"
icon = 'icons/obj/ammo.dmi'
flags = CONDUCT
slot_flags = SLOT_BELT
item_state = "syringe_kit"
- matter = list("metal" = 50000)
- throwforce = 2
- w_class = 2.0
+ matter = list("metal" = 500)
+ throwforce = 5
+ w_class = 2
throw_speed = 4
throw_range = 10
+
var/list/stored_ammo = list()
- var/ammo_type = "/obj/item/ammo_casing"
+ var/mag_type = SPEEDLOADER //ammo_magazines can only be used with compatible guns. This is not a bitflag, the load_method var on guns is.
+ var/caliber = "357"
var/max_ammo = 7
+
+ var/ammo_type = /obj/item/ammo_casing //ammo type that is initially loaded
+ var/initial_ammo = null
+
var/multiple_sprites = 0
+ //because BYOND doesn't support numbers as keys in associative lists
+ var/list/icon_keys = list() //keys
+ var/list/ammo_states = list() //values
+/obj/item/ammo_magazine/New()
+ if(multiple_sprites)
+ initialize_magazine_icondata(src)
- New()
- for(var/i = 1, i <= max_ammo, i++)
+ if(isnull(initial_ammo))
+ initial_ammo = max_ammo
+
+ if(initial_ammo)
+ for(var/i in 1 to initial_ammo)
stored_ammo += new ammo_type(src)
+ update_icon()
+
+/obj/item/ammo_magazine/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ if(istype(W, /obj/item/ammo_casing))
+ var/obj/item/ammo_casing/C = W
+ if(C.caliber != caliber)
+ user << "[C] does not fit into [src]."
+ return
+ if(stored_ammo.len >= max_ammo)
+ user << "[src] is full!"
+ return
+ user.remove_from_mob(C)
+ C.loc = src
+ stored_ammo.Insert(1, C) //add to the head of the list
update_icon()
-
+/obj/item/ammo_magazine/attack_self(mob/user)
+ if(!stored_ammo.len)
+ user << "[src] is already empty!"
+ return
+ user << "You empty [src]."
+ for(var/obj/item/ammo_casing/C in stored_ammo)
+ C.loc = user.loc
+ C.set_dir(pick(cardinal))
+ stored_ammo.Cut()
update_icon()
- if(multiple_sprites)
- icon_state = "[initial(icon_state)]-[stored_ammo.len]"
- desc = "There are [stored_ammo.len] shell\s left!"
+
+/obj/item/ammo_magazine/update_icon()
+ if(multiple_sprites)
+ //find the lowest key greater than or equal to stored_ammo.len
+ var/new_state = null
+ for(var/idx in 1 to icon_keys.len)
+ var/ammo_count = icon_keys[idx]
+ if (ammo_count >= stored_ammo.len)
+ new_state = ammo_states[idx]
+ break
+ icon_state = (new_state)? new_state : initial(icon_state)
+
+/obj/item/ammo_magazine/examine(mob/user)
+ ..()
+ user << "There [(stored_ammo.len > 1)? "are" : "is"] [stored_ammo.len] round\s left!"
+
+//magazine icon state caching
+/var/global/list/magazine_icondata_keys = list()
+/var/global/list/magazine_icondata_states = list()
+
+/proc/initialize_magazine_icondata(var/obj/item/ammo_magazine/M)
+ var/typestr = "[M.type]"
+ if(!(typestr in magazine_icondata_keys) || !(typestr in magazine_icondata_states))
+ magazine_icondata_cache_add(M)
+
+ M.icon_keys = magazine_icondata_keys[typestr]
+ M.ammo_states = magazine_icondata_states[typestr]
+
+/proc/magazine_icondata_cache_add(var/obj/item/ammo_magazine/M)
+ var/list/icon_keys = list()
+ var/list/ammo_states = list()
+ var/list/states = icon_states(M.icon)
+ for(var/i = 0, i <= M.max_ammo, i++)
+ var/ammo_state = "[M.icon_state]-[i]"
+ if(ammo_state in states)
+ icon_keys += i
+ ammo_states += ammo_state
+
+ magazine_icondata_keys["[M.type]"] = icon_keys
+ magazine_icondata_states["[M.type]"] = ammo_states
+
diff --git a/code/modules/projectiles/ammunition/boxes.dm b/code/modules/projectiles/ammunition/boxes.dm
index ed33bbfe48..3466f40b48 100644
--- a/code/modules/projectiles/ammunition/boxes.dm
+++ b/code/modules/projectiles/ammunition/boxes.dm
@@ -1,45 +1,159 @@
/obj/item/ammo_magazine/a357
- name = "ammo box (.357)"
- desc = "A box of .357 ammo"
- icon_state = "357"
- ammo_type = "/obj/item/ammo_casing/a357"
+ //name = "ammo box (.357)"
+ //desc = "A box of .357 ammo"
+ //icon_state = "357"
+ name = "speed loader (.357)"
+ icon_state = "T38"
+ caliber = "357"
+ ammo_type = /obj/item/ammo_casing/a357
max_ammo = 7
multiple_sprites = 1
/obj/item/ammo_magazine/c38
name = "speed loader (.38)"
icon_state = "38"
- ammo_type = "/obj/item/ammo_casing/c38"
+ caliber = "38"
+ ammo_type = /obj/item/ammo_casing/c38
max_ammo = 6
multiple_sprites = 1
+/obj/item/ammo_magazine/c38/rubber
+ name = "speed loader (.38 rubber)"
+ ammo_type = /obj/item/ammo_casing/c38r
/obj/item/ammo_magazine/c45m
name = "magazine (.45)"
icon_state = "45"
- ammo_type = "/obj/item/ammo_casing/c45"
+ mag_type = MAGAZINE
+ ammo_type = /obj/item/ammo_casing/c45
+ caliber = ".45"
max_ammo = 7
multiple_sprites = 1
-/obj/item/ammo_magazine/c45/empty
- max_ammo = 0
+/obj/item/ammo_magazine/c45m/empty
+ initial_ammo = 0
-/obj/item/ammo_magazine/c45r
+/obj/item/ammo_magazine/c45m/rubber
name = "magazine (.45 rubber)"
- icon_state = "45"
- ammo_type = "/obj/item/ammo_casing/c45r"
- max_ammo = 7
- multiple_sprites = 1
+ ammo_type = /obj/item/ammo_casing/c45r
-/obj/item/ammo_magazine/c45f
+/obj/item/ammo_magazine/c45m/flash
name = "magazine (.45 flash)"
- icon_state = "45"
ammo_type = "/obj/item/ammo_casing/c45f"
+
+/obj/item/ammo_magazine/mc9mm
+ name = "magazine (9mm)"
+ icon_state = "9x19p"
+ origin_tech = "combat=2"
+ mag_type = MAGAZINE
+ caliber = "9mm"
+ ammo_type = /obj/item/ammo_casing/c9mm
+ max_ammo = 10
+ multiple_sprites = 1
+
+/obj/item/ammo_magazine/mc9mm/empty
+ initial_ammo = 0
+
+/obj/item/ammo_magazine/mc9mm/flash
+ ammo_type = /obj/item/ammo_casing/c9mmf
+
+/obj/item/ammo_magazine/c9mm
+ name = "ammunition Box (9mm)"
+ icon_state = "9mm"
+ origin_tech = "combat=2"
+ caliber = "9mm"
+ ammo_type = /obj/item/ammo_casing/c9mm
+ max_ammo = 30
+
+/obj/item/ammo_magazine/c9mm/empty
+ initial_ammo = 0
+
+/obj/item/ammo_magazine/c45
+ name = "ammunition Box (.45)"
+ icon_state = "9mm"
+ origin_tech = "combat=2"
+ caliber = ".45"
+ ammo_type = /obj/item/ammo_casing/c45
+ max_ammo = 30
+
+/obj/item/ammo_magazine/c9mm/empty
+ initial_ammo = 0
+
+/obj/item/ammo_magazine/a12mm
+ name = "magazine (12mm)"
+ icon_state = "12mm"
+ origin_tech = "combat=2"
+ mag_type = MAGAZINE
+ caliber = "12mm"
+ ammo_type = "/obj/item/ammo_casing/a12mm"
+ max_ammo = 20
+ multiple_sprites = 1
+
+/obj/item/ammo_magazine/a12mm/empty
+ initial_ammo = 0
+
+/obj/item/ammo_magazine/a50
+ name = "magazine (.50)"
+ icon_state = "50ae"
+ origin_tech = "combat=2"
+ mag_type = MAGAZINE
+ caliber = ".50"
+ ammo_type = /obj/item/ammo_casing/a50
max_ammo = 7
multiple_sprites = 1
-/obj/item/ammo_magazine/c45r/empty
- max_ammo = 0
+/obj/item/ammo_magazine/a50/empty
+ initial_ammo = 0
+
+/obj/item/ammo_magazine/a75
+ name = "ammo magazine (20mm)"
+ icon_state = "75"
+ mag_type = MAGAZINE
+ caliber = "75"
+ ammo_type = /obj/item/ammo_casing/a75
+ multiple_sprites = 1
+ max_ammo = 4
+
+/obj/item/ammo_magazine/a75/empty
+ initial_ammo = 0
+
+/obj/item/ammo_magazine/a762
+ name = "magazine box (7.62mm)"
+ icon_state = "a762"
+ origin_tech = "combat=2"
+ mag_type = MAGAZINE
+ caliber = "a762"
+ ammo_type = /obj/item/ammo_casing/a762
+ max_ammo = 50
+ multiple_sprites = 1
+
+/obj/item/ammo_magazine/a762/empty
+ initial_ammo = 0
+
+/obj/item/ammo_magazine/c762
+ name = "magazine (7.62mm)"
+ icon_state = "c762"
+ mag_type = MAGAZINE
+ caliber = "a762"
+ ammo_type = /obj/item/ammo_casing/a762
+ max_ammo = 20
+ multiple_sprites = 1
+
+/obj/item/ammo_magazine/chameleon
+ name = "magazine (.45)"
+ icon_state = "45"
+ mag_type = MAGAZINE
+ caliber = ".45"
+ ammo_type = /obj/item/ammo_casing/chameleon
+ max_ammo = 7
+ multiple_sprites = 1
+ matter = list()
+
+/obj/item/ammo_magazine/chameleon/empty
+ initial_ammo = 0
+
+/*
+//unused garbage
/obj/item/ammo_magazine/a418
name = "ammo box (.418)"
@@ -48,116 +162,10 @@
max_ammo = 7
multiple_sprites = 1
-
-
/obj/item/ammo_magazine/a666
name = "ammo box (.666)"
icon_state = "666"
ammo_type = "/obj/item/ammo_casing/a666"
max_ammo = 4
multiple_sprites = 1
-
-
-/obj/item/ammo_magazine/mc9mm
- name = "magazine (9mm)"
- icon_state = "9x19p"
- origin_tech = "combat=2"
- ammo_type = "/obj/item/ammo_casing/c9mm"
- max_ammo = 10
- multiple_sprites = 1
-
-/obj/item/ammo_magazine/mc9mm/empty/New()
- ..()
- stored_ammo = list()
- update_icon()
-
-/obj/item/ammo_magazine/c9mm
- name = "Ammunition Box (9mm)"
- icon_state = "9mm"
- origin_tech = "combat=2"
- ammo_type = "/obj/item/ammo_casing/c9mm"
- max_ammo = 30
-
-
-
-/obj/item/ammo_magazine/c45
- name = "Ammunition Box (.45)"
- icon_state = "9mm"
- origin_tech = "combat=2"
- ammo_type = "/obj/item/ammo_casing/c45"
- max_ammo = 30
-
-
-
-/obj/item/ammo_magazine/a12mm
- name = "magazine (12mm)"
- icon_state = "12mm"
- origin_tech = "combat=2"
- ammo_type = "/obj/item/ammo_casing/a12mm"
- max_ammo = 20
- multiple_sprites = 1
-
-
-/obj/item/ammo_magazine/a12mm/empty
- name = "magazine (12mm)"
- icon_state = "12mm"
- ammo_type = "/obj/item/ammo_casing/12mm"
- max_ammo = 0
-
-/obj/item/ammo_magazine/a50
- name = "magazine (.50)"
- icon_state = "50ae"
- origin_tech = "combat=2"
- ammo_type = "/obj/item/ammo_casing/a50"
- max_ammo = 7
- multiple_sprites = 1
-
-/obj/item/ammo_magazine/a50/empty
- name = "magazine (.50)"
- icon_state = "50ae"
- ammo_type = "/obj/item/ammo_casing/a50"
- max_ammo = 0
-
-/obj/item/ammo_magazine/a75
- name = "ammo magazine (.75)"
- icon_state = "75"
- ammo_type = "/obj/item/ammo_casing/a75"
- multiple_sprites = 1
- max_ammo = 8
-
-/obj/item/ammo_magazine/a75/empty
- name = "ammo magazine (.75)"
- icon_state = "75"
- ammo_type = "/obj/item/ammo_casing/a75"
- max_ammo = 0
-
-/obj/item/ammo_magazine/a762
- name = "magazine (a762)"
- icon_state = "a762"
- origin_tech = "combat=2"
- ammo_type = "/obj/item/ammo_casing/a762"
- max_ammo = 50
- multiple_sprites = 1
-
-/obj/item/ammo_magazine/a762/empty
- name = "magazine (a762)"
- icon_state = "a762"
- ammo_type = "/obj/item/ammo_casing/a762"
- max_ammo = 0
- multiple_sprites = 1
-
-/obj/item/ammo_magazine/chameleon
- name = "magazine (.45)"
- icon_state = "45"
- ammo_type = "/obj/item/ammo_casing/chameleon"
- max_ammo = 7
- multiple_sprites = 1
- matter = list()
-
-/obj/item/ammo_magazine/chameleon/empty
- name = "magazine (.45)"
- icon_state = "45"
- ammo_type = "/obj/item/ammo_casing/chameleon"
- max_ammo = 0
- multiple_sprites = 1
- matter = list()
+*/
diff --git a/code/modules/projectiles/ammunition/bullets.dm b/code/modules/projectiles/ammunition/bullets.dm
index d0cb2915dc..67308c50f7 100644
--- a/code/modules/projectiles/ammunition/bullets.dm
+++ b/code/modules/projectiles/ammunition/bullets.dm
@@ -16,6 +16,11 @@
/obj/item/ammo_casing/c38
desc = "A .38 bullet casing."
caliber = "38"
+ projectile_type = /obj/item/projectile/bullet/pistol
+
+/obj/item/ammo_casing/c38r
+ desc = "A .38 rubber bullet casing."
+ caliber = "38"
projectile_type = /obj/item/projectile/bullet/pistol/rubber
/obj/item/ammo_casing/c9mm
@@ -23,6 +28,12 @@
caliber = "9mm"
projectile_type = /obj/item/projectile/bullet/pistol
+/obj/item/ammo_casing/c9mmf
+ desc = "A 9mm flash shell casing."
+ caliber = "9mm"
+ projectile_type = /obj/item/projectile/energy/flash
+
+
/obj/item/ammo_casing/c45
desc = "A .45 bullet casing."
caliber = ".45"
@@ -73,36 +84,39 @@
projectile_type = /obj/item/projectile/bullet/shotgun/beanbag
matter = list("metal" = 500)
+//Can stun in one hit if aimed at the head, but
+//is blocked by clothing that stops tasers and is vulnerable to EMP
/obj/item/ammo_casing/shotgun/stunshell
name = "stun shell"
desc = "A 12 gauge taser cartridge."
icon_state = "stunshell"
+ spent_icon = "stunshell-spent"
projectile_type = /obj/item/projectile/energy/electrode/stunshot
matter = list("metal" = 1250, "glass" = 1250)
+/obj/item/ammo_casing/shotgun/stunshell/emp_act(severity)
+ if(prob(100/severity)) BB = null
+ update_icon()
+
+//Does not stun, only blinds, but has area of effect.
/obj/item/ammo_casing/shotgun/flash
name = "flash shell"
- desc = "A flash shell used to provide illumination."
+ desc = "A chemical shell used to signal distress or provide illumination."
icon_state = "fshell"
projectile_type = /obj/item/projectile/energy/flash/flare
matter = list("metal" = 250, "glass" = 250)
-/obj/item/ammo_casing/shotgun/dart
- name = "shotgun dart"
- desc = "A dart for use in shotguns."
- icon_state = "dart"
- projectile_type = /obj/item/projectile/energy/dart
- matter = list("metal" = 12500)
-
/obj/item/ammo_casing/a762
desc = "A 7.62mm bullet casing."
caliber = "a762"
projectile_type = /obj/item/projectile/bullet/rifle/a762
/obj/item/ammo_casing/a145
- name = "\improper AP shell casing"
+ name = "shell casing"
desc = "A 14.5mm AP shell."
- icon_state = "slshell"
+ icon_state = "lcasing"
+ spent_icon = "lcasing-spent"
+ caliber = "14.5mm"
projectile_type = /obj/item/projectile/bullet/rifle/a145
/obj/item/ammo_casing/rocket
@@ -118,6 +132,7 @@
projectile_type = /obj/item/projectile/bullet/chameleon
caliber = ".45"
+/*
/obj/item/ammo_casing/a418
desc = "A .418 bullet casing."
caliber = "357"
@@ -126,4 +141,5 @@
/obj/item/ammo_casing/a666
desc = "A .666 bullet casing."
caliber = "357"
- projectile_type = /obj/item/projectile/bullet/cyanideround
\ No newline at end of file
+ projectile_type = /obj/item/projectile/bullet/cyanideround
+*/
\ No newline at end of file
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index f4bc1175d5..c2d6266473 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -1,3 +1,4 @@
+//Parent gun type. Guns are weapons that can be aimed at mobs and act over a distance
/obj/item/weapon/gun
name = "gun"
desc = "Its a gun. It's pretty terrible, though."
@@ -5,59 +6,88 @@
icon_state = "detective"
item_state = "gun"
flags = CONDUCT
- slot_flags = SLOT_BELT
+ slot_flags = SLOT_BELT|SLOT_HOLSTER
matter = list("metal" = 2000)
- w_class = 3.0
+ w_class = 3
throwforce = 5
throw_speed = 4
throw_range = 5
- force = 5.0
+ force = 5
origin_tech = "combat=1"
attack_verb = list("struck", "hit", "bashed")
+ zoomdevicename = "scope"
+ var/fire_delay = 6
var/fire_sound = 'sound/weapons/Gunshot.ogg'
- var/obj/item/projectile/in_chamber = null
- var/caliber = ""
+ var/fire_sound_text = "gunshot"
+ var/recoil = 0 //screen shake
var/silenced = 0
- var/recoil = 0
- var/ejectshell = 1
- var/clumsy_check = 1
- var/tmp/list/mob/living/target //List of who yer targeting.
- var/tmp/lock_time = -100
- var/tmp/mouthshoot = 0 ///To stop people from suiciding twice... >.>
- var/automatic = 0 //Used to determine if you can target multiple people.
+ var/accuracy = 0 //accuracy is measured in tiles. +1 accuracy means that everything is effectively one tile closer for the purpose of miss chance, -1 means the opposite. launchers are not supported, at the moment.
+ var/scoped_accuracy = null
+
+ var/last_fired = 0
+
+ //aiming system stuff
+ var/keep_aim = 1 //1 for keep shooting until aim is lowered
+ //0 for one bullet after tarrget moves and aim is lowered
+ var/multi_aim = 0 //Used to determine if you can target multiple people.
+ var/tmp/list/mob/living/aim_targets //List of who yer targeting.
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 = 0 //0 for keep shooting until aim is lowered
- // 1 for one bullet after tarrget moves and aim is lowered
- var/fire_delay = 6
- var/last_fired = 0
+ var/tmp/lock_time = -100
- proc/ready_to_fire()
- if(world.time >= last_fired + fire_delay)
- last_fired = world.time
- return 1
- else
- return 0
+/obj/item/weapon/gun/New()
+ ..()
+ if(isnull(scoped_accuracy))
+ scoped_accuracy = accuracy
- proc/load_into_chamber()
+//Returns 1 if the gun is able to be fired
+/obj/item/weapon/gun/proc/ready_to_fire()
+ if(world.time >= last_fired + fire_delay)
+ last_fired = world.time
+ return 1
+ else
return 0
- proc/special_check(var/mob/M) //Placeholder for any special checks, like detective's revolver.
- return 1
+//Checks whether a given mob can use the gun
+//Any checks that shouldn't result in handle_click_empty() being called if they fail should go here.
+//Otherwise, if you want handle_click_empty() to be called, check in consume_next_projectile() and return null there.
+/obj/item/weapon/gun/proc/special_check(var/mob/user)
+ if(!istype(user, /mob/living))
+ return 0
+ if(!user.IsAdvancedToolUser())
+ return 0
+
+ var/mob/living/M = user
+
+ if(HULK in M.mutations)
+ M << "Your fingers are much too large for the trigger guard!"
+ return 0
+ if((CLUMSY in M.mutations) && prob(40)) //Clumsy handling
+ var/obj/P = consume_next_projectile()
+ if(P)
+ if(process_projectile(P, user, user, pick("l_foot", "r_foot")))
+ handle_post_fire(user, user)
+ user.visible_message(
+ "[user] shoots \himself in the foot with \the [src]!",
+ "You shoot yourself in the foot with \the [src]!"
+ )
+ M.drop_item()
+ else
+ handle_click_empty(user)
+ return 0
+ return 1
- emp_act(severity)
- for(var/obj/O in contents)
- O.emp_act(severity)
-
-/obj/item/weapon/gun/afterattack(atom/A as mob|obj|turf|area, mob/living/user as mob|obj, flag, params)
- if(flag) return //It's adjacent, is the user, or is on the user's person
- if(istype(target, /obj/machinery/recharger) && istype(src, /obj/item/weapon/gun/energy)) return//Shouldnt flag take care of this?
+/obj/item/weapon/gun/emp_act(severity)
+ for(var/obj/O in contents)
+ O.emp_act(severity)
+/obj/item/weapon/gun/afterattack(atom/A, mob/living/user, adjacent, params)
+ if(adjacent) return //A is adjacent, is the user, or is on the user's person
//decide whether to aim or shoot normally
var/aiming = 0
- if(user && user.client && !(A in target))
+ if(user && user.client && !(A in aim_targets))
var/client/C = user.client
//If help intent is on and we have clicked on an eligible target, switch to aim mode automatically
if(user.a_intent == "help" && isliving(A) && !C.gun_mode)
@@ -72,30 +102,16 @@
else
Fire(A,user,params) //Otherwise, fire normally.
-/obj/item/weapon/gun/proc/isHandgun()
- return 1
+/obj/item/weapon/gun/attack(atom/A, mob/living/user, def_zone)
+ if (A == user && user.zone_sel.selecting == "mouth" && !mouthshoot)
+ handle_suicide(user)
+ else if(user.a_intent == "hurt") //point blank shooting
+ Fire(A, user, pointblank=1)
+ else
+ return ..() //Pistolwhippin'
-/obj/item/weapon/gun/proc/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0)//TODO: go over this
- //Exclude lasertag guns from the CLUMSY check.
- if(!user) return
-
- if(clumsy_check)
- if(istype(user, /mob/living))
- var/mob/living/M = user
- if ((CLUMSY in M.mutations) && prob(50))
- M << "[src] blows up in your face."
- M.take_organ_damage(0,20)
- M.drop_item()
- del(src)
- return
-
- if (!user.IsAdvancedToolUser())
- return
- if(istype(user, /mob/living))
- var/mob/living/M = user
- if (HULK in M.mutations)
- M << "Your fingers are much too large for the trigger guard!"
- return
+/obj/item/weapon/gun/proc/Fire(atom/target, mob/living/user, params, pointblank=0, reflex=0)
+ if(!user || !target) return
add_fingerprint(user)
@@ -107,22 +123,68 @@
user << "[src] is not ready to fire again!"
return
- if(!load_into_chamber()) //CHECK
- return click_empty(user)
-
- if(!in_chamber)
+ var/obj/projectile = consume_next_projectile(user)
+ if(!projectile)
+ handle_click_empty(user)
return
+ user.next_move = world.time + 4
+
+ if(process_projectile(projectile, user, target, user.zone_sel.selecting, params, pointblank, reflex))
+ handle_post_fire(user, target, pointblank, reflex)
+
+ update_icon()
+ if(user.hand)
+ user.update_inv_l_hand()
+ else
+ user.update_inv_r_hand()
+
+
+//obtains the next projectile to fire
+/obj/item/weapon/gun/proc/consume_next_projectile()
+ return null
+
+//used by aiming code
+/obj/item/weapon/gun/proc/can_hit(atom/target as mob, var/mob/living/user as mob)
+ if(!special_check(user))
+ return 2
+ //just assume we can shoot through glass and stuff. No big deal, the player can just choose to not target someone
+ //on the other side of a window if it makes a difference. Or if they run behind a window, too bad.
+ return check_trajectory(target, user)
+
+//called if there was no projectile to shoot
+/obj/item/weapon/gun/proc/handle_click_empty(mob/user)
+ if (user)
+ user.visible_message("*click click*", "*click*")
+ else
+ src.visible_message("*click click*")
+ playsound(src.loc, 'sound/weapons/empty.ogg', 100, 1)
+
+//called after successfully firing
+/obj/item/weapon/gun/proc/handle_post_fire(mob/user, atom/target, var/pointblank=0, var/reflex=0)
if(silenced)
playsound(user, fire_sound, 10, 1)
else
playsound(user, fire_sound, 50, 1)
- user.visible_message("[user] fires [src][reflex ? " by reflex":""]!", \
- "You fire [src][reflex ? "by reflex":""]!", \
- "You hear a [istype(in_chamber, /obj/item/projectile/beam) ? "laser blast" : "gunshot"]!")
-
- user.next_move = world.time + 4
+ user.visible_message(
+ "[user] fires [src][pointblank ? " point blank at [target]":""][reflex ? " by reflex":""]!",
+ "You fire [src][reflex ? "by reflex":""]!",
+ "You hear a [fire_sound_text]!"
+ )
+ if(recoil)
+ spawn()
+ shake_camera(user, recoil+1, recoil)
+ update_icon()
+
+//does the actual shooting
+/obj/item/weapon/gun/proc/process_projectile(obj/projectile, mob/user, atom/target, var/target_zone, var/params=null, var/pointblank=0, var/reflex=0)
+ if(!istype(projectile, /obj/item/projectile))
+ return 0 //default behaviour only applies to true projectiles
+
+ var/obj/item/projectile/P = projectile
+
+ //shooting while in shock
var/x_offset = 0
var/y_offset = 0
if(istype(user, /mob/living/carbon))
@@ -134,101 +196,68 @@
y_offset = rand(-1,1)
x_offset = rand(-1,1)
- var/p_x
- var/p_y
+ //Point blank bonus
+ if(pointblank) P.damage *= 1.3
+
+ //TODO: accuracy modifiers
+
if(params)
- var/list/mouse_control = params2list(params)
- if(mouse_control["icon-x"])
- p_x = text2num(mouse_control["icon-x"])
- if(mouse_control["icon-y"])
- p_y = text2num(mouse_control["icon-y"])
+ P.set_clickpoint(params)
+
+ return !P.launch(target, user, src, target_zone, x_offset, y_offset)
+
+//Suicide handling.
+/obj/item/weapon/gun/var/mouthshoot = 0 //To stop people from suiciding twice... >.>
+/obj/item/weapon/gun/proc/handle_suicide(mob/living/user)
+ if(!ishuman(user))
+ return
+ var/mob/living/carbon/human/M = user
- if(in_chamber)
- var/fail = in_chamber.launch(
- target = target,
- user = user,
- launcher = src,
- target_zone = user.zone_sel.selecting,
- x_offset = x_offset,
- y_offset = y_offset,
- px = p_x,
- py = p_y
- )
-
- if(fail) return
-
- if(recoil)
- spawn()
- shake_camera(user, recoil + 1, recoil)
-
- sleep(1)
- in_chamber = null
-
- update_icon()
-
- if(user.hand)
- user.update_inv_l_hand()
- else
- user.update_inv_r_hand()
-
-/obj/item/weapon/gun/proc/can_fire()
- return load_into_chamber()
-
-/obj/item/weapon/gun/proc/can_hit(var/mob/living/target as mob, var/mob/living/user as mob)
- return in_chamber.check_fire(target,user)
-
-/obj/item/weapon/gun/proc/click_empty(mob/user = null)
- if (user)
- user.visible_message("*click click*", "\red *click*")
- playsound(user, 'sound/weapons/empty.ogg', 100, 1)
- else
- src.visible_message("*click click*")
- playsound(src.loc, 'sound/weapons/empty.ogg', 100, 1)
-
-/obj/item/weapon/gun/attack(mob/living/M as mob, mob/living/user as mob, def_zone)
- //Suicide handling.
- if (M == user && user.zone_sel.selecting == "mouth" && !mouthshoot)
- mouthshoot = 1
- M.visible_message("\red [user] sticks their gun in their mouth, ready to pull the trigger...")
- if(!do_after(user, 40))
- M.visible_message("\blue [user] decided life was worth living")
- mouthshoot = 0
- return
- if (load_into_chamber())
- user.visible_message("[user] pulls the trigger.")
- if(silenced)
- playsound(user, fire_sound, 10, 1)
- else
- playsound(user, fire_sound, 50, 1)
- if(istype(in_chamber, /obj/item/projectile/beam/lastertag))
- user.show_message("You feel rather silly, trying to commit suicide with a toy.")
- mouthshoot = 0
- return
-
- in_chamber.on_hit(M)
- if (in_chamber.damage_type != HALLOSS)
- user.apply_damage(in_chamber.damage*2.5, in_chamber.damage_type, "head", used_weapon = "Point blank shot in the mouth with \a [in_chamber]", sharp=1)
- user.death()
- else
- user << "Ow..."
- user.apply_effect(110,AGONY,0)
- del(in_chamber)
- mouthshoot = 0
- return
+ mouthshoot = 1
+ M.visible_message("\red [user] sticks their gun in their mouth, ready to pull the trigger...")
+ if(!do_after(user, 40))
+ M.visible_message("\blue [user] decided life was worth living")
+ mouthshoot = 0
+ return
+ var/obj/item/projectile/in_chamber = consume_next_projectile()
+ if (istype(in_chamber))
+ user.visible_message("[user] pulls the trigger.")
+ if(silenced)
+ playsound(user, fire_sound, 10, 1)
else
- click_empty(user)
+ playsound(user, fire_sound, 50, 1)
+ if(istype(in_chamber, /obj/item/projectile/beam/lastertag))
+ user.show_message("You feel rather silly, trying to commit suicide with a toy.")
mouthshoot = 0
return
- if (load_into_chamber())
- //Point blank shooting if on harm intent or target we were targeting.
- if(user.a_intent == "hurt")
- user.visible_message("\red \The [user] fires \the [src] point blank at [M]!")
- if(istype(in_chamber)) in_chamber.damage *= 1.3
- Fire(M,user)
- return
- else if(target && M in target)
- Fire(M,user) ///Otherwise, shoot!
- return
+ in_chamber.on_hit(M)
+ if (in_chamber.damage_type != HALLOSS)
+ user.apply_damage(in_chamber.damage*2.5, in_chamber.damage_type, "head", used_weapon = "Point blank shot in the mouth with \a [in_chamber]", sharp=1)
+ user.death()
+ else
+ user << "Ow..."
+ user.apply_effect(110,AGONY,0)
+ del(in_chamber)
+ mouthshoot = 0
+ return
else
- return ..() //Pistolwhippin'
+ handle_click_empty(user)
+ mouthshoot = 0
+ return
+
+/obj/item/weapon/gun/proc/toggle_scope(var/zoom_amount=2.0)
+ //looking through a scope limits your periphereal vision
+ //still, increase the view size by a tiny amount so that sniping isn't too restricted to NSEW
+ var/zoom_offset = round(world.view * zoom_amount)
+ var/view_size = round(world.view + zoom_amount)
+ var/scoped_accuracy_mod = zoom_offset
+
+ zoom(zoom_offset, view_size)
+ if(zoom)
+ accuracy = scoped_accuracy + scoped_accuracy_mod
+ if(recoil)
+ recoil = round(recoil*zoom_amount+1) //recoil is worse when looking through a scope
+ else
+ accuracy = (accuracy)
+ recoil = initial(recoil)
diff --git a/code/modules/projectiles/guns/alien.dm b/code/modules/projectiles/guns/alien.dm
index f9af71acc8..797d0b07c2 100644
--- a/code/modules/projectiles/guns/alien.dm
+++ b/code/modules/projectiles/guns/alien.dm
@@ -1,6 +1,6 @@
//Vox pinning weapon.
/obj/item/weapon/gun/launcher/spikethrower
- name = "Vox spike thrower"
+ name = "vox spike thrower"
desc = "A vicious alien projectile weapon. Parts of it quiver gelatinously, as though the thing is insectile and alive."
var/last_regen = 0
@@ -24,7 +24,6 @@
..()
/obj/item/weapon/gun/launcher/spikethrower/process()
-
if(spikes < max_spikes && world.time > last_regen + spike_gen_time)
spikes++
last_regen = world.time
@@ -32,35 +31,26 @@
/obj/item/weapon/gun/launcher/spikethrower/examine(mob/user)
..(user)
- user << "It has [spikes] [spikes == 1 ? "spike" : "spikes"] remaining."
+ user << "It has [spikes] spike\s remaining."
/obj/item/weapon/gun/launcher/spikethrower/update_icon()
icon_state = "spikethrower[spikes]"
-/obj/item/weapon/gun/launcher/spikethrower/emp_act(severity)
- return
-
/obj/item/weapon/gun/launcher/spikethrower/special_check(user)
if(istype(user,/mob/living/carbon/human))
var/mob/living/carbon/human/H = user
if(H.species && H.species.name != "Vox" && H.species.name != "Vox Armalis")
- user << "\red \The [src] does not respond to you!"
+ user << "\The [src] does not respond to you!"
return 0
- return 1
+ return ..()
/obj/item/weapon/gun/launcher/spikethrower/update_release_force()
return
-/obj/item/weapon/gun/launcher/spikethrower/load_into_chamber()
- if(in_chamber) return 1
- if(spikes < 1) return 0
-
+/obj/item/weapon/gun/launcher/spikethrower/consume_next_projectile()
+ if(spikes < 1) return null
spikes--
- in_chamber = new /obj/item/weapon/spike(src)
- return 1
-
-/obj/item/weapon/gun/launcher/spikethrower/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0)
- if(..()) update_icon()
+ return new /obj/item/weapon/spike(src)
//This gun only functions for armalis. The on-sprite is too huge to render properly on other sprites.
/obj/item/weapon/gun/energy/noisecannon
@@ -74,7 +64,7 @@
force = 10
projectile_type = /obj/item/projectile/energy/sonic
- cell_type = "/obj/item/weapon/cell/super"
+ cell_type = /obj/item/weapon/cell/super
fire_delay = 40
fire_sound = 'sound/effects/basscannon.ogg'
@@ -91,13 +81,9 @@
if(H.species.name == "Vox Armalis")
..()
return
- user << "\red \The [src] is far too large for you to pick up."
+ user << "\The [src] is far too large for you to pick up."
return
-/obj/item/weapon/gun/energy/noisecannon/load_into_chamber() //Does not have ammo.
- in_chamber = new projectile_type(src)
- return 1
-
/obj/item/weapon/gun/energy/noisecannon/update_icon()
return
@@ -108,7 +94,7 @@
icon_state = "particle"
damage = 60
damage_type = BRUTE
- flag = "bullet"
+ check_armour = "bullet"
pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
embed = 0
diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm
index 0ed82e9f4a..3cd90347f9 100644
--- a/code/modules/projectiles/guns/energy.dm
+++ b/code/modules/projectiles/guns/energy.dm
@@ -3,39 +3,78 @@
desc = "A basic energy-based gun."
icon_state = "energy"
fire_sound = 'sound/weapons/Taser.ogg'
+ fire_sound_text = "laser blast"
var/obj/item/weapon/cell/power_supply //What type of power cell this uses
var/charge_cost = 100 //How much energy is needed to fire.
- var/cell_type = "/obj/item/weapon/cell"
+ var/cell_type = /obj/item/weapon/cell
var/projectile_type = /obj/item/projectile/beam/practice
var/modifystate
+ var/charge_meter = 1 //if set, the icon state will be chosen based on the current charge
+
+ //self-recharging
+ var/self_recharge = 0 //if set, the weapon will recharge itself
+ var/use_external_power = 0 //if set, the weapon will look for an external power source to draw from, otherwise it recharges magically
+ var/recharge_time = 4
+ var/charge_tick = 0
- emp_act(severity)
- power_supply.use(round(power_supply.maxcharge / severity))
- update_icon()
- ..()
-
-
- New()
- ..()
- if(cell_type)
- power_supply = new cell_type(src)
- else
- power_supply = new(src)
- power_supply.give(power_supply.maxcharge)
- return
-
-
- load_into_chamber()
- if(in_chamber) return 1
- if(!power_supply) return 0
- if(!power_supply.use(charge_cost)) return 0
- if(!ispath(projectile_type)) return 0
- in_chamber = new projectile_type(src)
- return 1
-
-
+/obj/item/weapon/gun/energy/emp_act(severity)
+ ..()
update_icon()
+
+/obj/item/weapon/gun/energy/New()
+ ..()
+ if(cell_type)
+ power_supply = new cell_type(src)
+ power_supply.give(power_supply.maxcharge)
+ if(self_recharge)
+ processing_objects.Add(src)
+
+/obj/item/weapon/gun/energy/Del()
+ if(self_recharge)
+ processing_objects.Remove(src)
+ ..()
+
+/obj/item/weapon/gun/energy/process()
+ if(self_recharge) //Every [recharge_time] ticks, recharge a shot for the cyborg
+ charge_tick++
+ if(charge_tick < recharge_time) return 0
+ charge_tick = 0
+
+ if(!power_supply || power_supply.charge >= power_supply.maxcharge)
+ return 0 // check if we actually need to recharge
+
+ if(use_external_power)
+ var/obj/item/weapon/cell/external = get_external_power_supply()
+ if(!external || !external.use(charge_cost)) //Take power from the borg...
+ return 0
+
+ power_supply.give(charge_cost) //... to recharge the shot
+ update_icon()
+ return 1
+
+/obj/item/weapon/gun/energy/consume_next_projectile()
+ if(!power_supply) return null
+ if(!ispath(projectile_type)) return null
+ if(!power_supply.use(charge_cost)) return null
+ return new projectile_type(src)
+
+/obj/item/weapon/gun/energy/proc/get_external_power_supply()
+ if(isrobot(src.loc))
+ var/mob/living/silicon/robot/R = src.loc
+ return R.cell
+ if(istype(src.loc, /obj/item/rig_module))
+ var/obj/item/rig_module/module = src.loc
+ if(module.holder && module.holder.wearer)
+ var/mob/living/carbon/human/H = module.holder.wearer
+ if(istype(H) && H.back)
+ var/obj/item/weapon/rig/suit = H.back
+ if(istype(suit))
+ return suit.cell
+ return null
+
+/obj/item/weapon/gun/energy/update_icon()
+ if(charge_meter)
var/ratio = power_supply.charge / power_supply.maxcharge
ratio = round(ratio, 0.25) * 100
if(modifystate)
diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm
index 40a4b06689..2dc1cb65e2 100644
--- a/code/modules/projectiles/guns/energy/laser.dm
+++ b/code/modules/projectiles/guns/energy/laser.dm
@@ -4,89 +4,53 @@
icon_state = "laser"
item_state = "laser"
fire_sound = 'sound/weapons/Laser.ogg'
- w_class = 3.0
+ slot_flags = SLOT_BELT|SLOT_BACK
+ w_class = 3
+ force = 10 //it has a stock, might as well give some kind of perk over the egun
matter = list("metal" = 2000)
origin_tech = "combat=3;magnets=2"
projectile_type = /obj/item/projectile/beam
+/obj/item/weapon/gun/energy/laser/mounted
+ self_recharge = 1
+ use_external_power = 1
+
/obj/item/weapon/gun/energy/laser/practice
name = "practice laser gun"
desc = "A modified version of the basic laser gun, this one fires less concentrated energy bolts designed for target practice."
projectile_type = /obj/item/projectile/beam/practice
- clumsy_check = 0
obj/item/weapon/gun/energy/laser/retro
name = "retro laser"
icon_state = "retro"
desc = "An older model of the basic lasergun, no longer used by Nanotrasen's security or military forces. Nevertheless, it is still quite deadly and easy to maintain, making it a favorite amongst pirates and other outlaws."
-
-/obj/item/weapon/gun/energy/laser/captain
+/obj/item/weapon/gun/energy/captain
name = "antique laser gun"
icon_state = "caplaser"
desc = "This is an antique laser gun. All craftsmanship is of the highest quality. It is decorated with assistant leather and chrome. The object menaces with spikes of energy. On the item is an image of Space Station 13. The station is exploding."
- force = 10
+ force = 5
+ slot_flags = SLOT_BELT
origin_tech = null
- var/charge_tick = 0
-
-
- New()
- ..()
- processing_objects.Add(src)
-
-
- Del()
- processing_objects.Remove(src)
- ..()
-
-
- process()
- charge_tick++
- if(charge_tick < 4) return 0
- charge_tick = 0
- if(!power_supply) return 0
- power_supply.give(100)
- update_icon()
- return 1
-
-
-
-/obj/item/weapon/gun/energy/laser/cyborg/load_into_chamber()
- if(in_chamber)
- return 1
- if(isrobot(src.loc))
- var/mob/living/silicon/robot/R = src.loc
- if(R && R.cell)
- R.cell.use(100)
- in_chamber = new/obj/item/projectile/beam(src)
- return 1
- return 0
-
+ self_recharge = 1
/obj/item/weapon/gun/energy/lasercannon
name = "laser cannon"
- desc = "With the L.A.S.E.R. cannon, the lasing medium is enclosed in a tube lined with uranium-235 and subjected to high neutron flux in a nuclear reactor core. This incredible technology may help YOU achieve high excitation rates with small laser volumes!"
+ desc = "With the laser cannon, the lasing medium is enclosed in a tube lined with uranium-235 and subjected to high neutron flux in a nuclear reactor core. This incredible technology may help YOU achieve high excitation rates with small laser volumes!"
icon_state = "lasercannon"
+ item_state = "laser"
fire_sound = 'sound/weapons/lasercannonfire.ogg'
origin_tech = "combat=4;materials=3;powerstorage=3"
- projectile_type = "/obj/item/projectile/beam/heavylaser"
-
+ slot_flags = SLOT_BELT|SLOT_BACK
+ projectile_type = /obj/item/projectile/beam/heavylaser
+ charge_cost = 250
fire_delay = 20
- isHandgun()
- return 0
-
-/obj/item/weapon/gun/energy/lasercannon/cyborg/load_into_chamber()
- if(in_chamber)
- return 1
- if(isrobot(src.loc))
- var/mob/living/silicon/robot/R = src.loc
- if(R && R.cell)
- R.cell.use(250)
- in_chamber = new/obj/item/projectile/beam/heavylaser(src)
- return 1
- return 0
+/obj/item/weapon/gun/energy/lasercannon/mounted
+ self_recharge = 1
+ use_external_power = 1
+ recharge_time = 25
/obj/item/weapon/gun/energy/xray
name = "xray laser gun"
@@ -94,80 +58,58 @@ obj/item/weapon/gun/energy/laser/retro
icon_state = "xray"
fire_sound = 'sound/weapons/laser3.ogg'
origin_tech = "combat=5;materials=3;magnets=2;syndicate=2"
- projectile_type = "/obj/item/projectile/beam/xray"
+ projectile_type = /obj/item/projectile/beam/xray
charge_cost = 50
+/obj/item/weapon/gun/energy/sniperrifle
+ name = "\improper L.W.A.P. sniper rifle"
+ desc = "A high-power laser rifle fitted with a SMART aiming-system scope."
+ icon_state = "sniper"
+ item_state = "laser"
+ fire_sound = 'sound/weapons/marauder.ogg'
+ origin_tech = "combat=6;materials=5;powerstorage=4"
+ projectile_type = /obj/item/projectile/beam/sniper
+ slot_flags = SLOT_BACK
+ charge_cost = 250
+ fire_delay = 35
+ force = 10
+ w_class = 4
+ accuracy = -3 //shooting at the hip
+ scoped_accuracy = 0
+
+/obj/item/weapon/gun/energy/sniperrifle/verb/scope()
+ set category = "Object"
+ set name = "Use Scope"
+ set popup_menu = 1
+
+ toggle_scope(2.0)
////////Laser Tag////////////////////
-/obj/item/weapon/gun/energy/laser/bluetag
+/obj/item/weapon/gun/energy/lasertag
name = "laser tag gun"
+ item_state = "laser"
+ desc = "Standard issue weapon of the Imperial Guard"
+ origin_tech = "combat=1;magnets=2"
+ self_recharge = 1
+ matter = list("metal" = 2000)
+ fire_sound = 'sound/weapons/Laser.ogg'
+ projectile_type = /obj/item/projectile/beam/lastertag/blue
+ var/required_vest
+
+/obj/item/weapon/gun/energy/lasertag/special_check(var/mob/living/carbon/human/M)
+ if(ishuman(M))
+ if(!istype(M.wear_suit, required_vest))
+ M << "You need to be wearing your laser tag vest!"
+ return 0
+ return ..()
+
+/obj/item/weapon/gun/energy/lasertag/blue
icon_state = "bluetag"
- desc = "Standard issue weapon of the Imperial Guard"
- projectile_type = "/obj/item/projectile/beam/lastertag/blue"
- origin_tech = "combat=1;magnets=2"
- clumsy_check = 0
- var/charge_tick = 0
+ projectile_type = /obj/item/projectile/beam/lastertag/blue
+ required_vest = /obj/item/clothing/suit/bluetag
- special_check(var/mob/living/carbon/human/M)
- if(ishuman(M))
- if(istype(M.wear_suit, /obj/item/clothing/suit/bluetag))
- return 1
- M << "\red You need to be wearing your laser tag vest!"
- return 0
-
- New()
- ..()
- processing_objects.Add(src)
-
-
- Del()
- processing_objects.Remove(src)
- ..()
-
-
- process()
- charge_tick++
- if(charge_tick < 4) return 0
- charge_tick = 0
- if(!power_supply) return 0
- power_supply.give(100)
- update_icon()
- return 1
-
-
-
-/obj/item/weapon/gun/energy/laser/redtag
- name = "laser tag gun"
+/obj/item/weapon/gun/energy/lasertag/red
icon_state = "redtag"
- desc = "Standard issue weapon of the Imperial Guard"
- projectile_type = "/obj/item/projectile/beam/lastertag/red"
- origin_tech = "combat=1;magnets=2"
- clumsy_check = 0
- var/charge_tick = 0
-
- special_check(var/mob/living/carbon/human/M)
- if(ishuman(M))
- if(istype(M.wear_suit, /obj/item/clothing/suit/redtag))
- return 1
- M << "\red You need to be wearing your laser tag vest!"
- return 0
-
- New()
- ..()
- processing_objects.Add(src)
-
-
- Del()
- processing_objects.Remove(src)
- ..()
-
-
- process()
- charge_tick++
- if(charge_tick < 4) return 0
- charge_tick = 0
- if(!power_supply) return 0
- power_supply.give(100)
- update_icon()
- return 1
+ projectile_type = /obj/item/projectile/beam/lastertag/red
+ required_vest = /obj/item/clothing/suit/redtag
diff --git a/code/modules/projectiles/guns/energy/nuclear.dm b/code/modules/projectiles/guns/energy/nuclear.dm
index abfd7510a4..e2b97672c7 100644
--- a/code/modules/projectiles/guns/energy/nuclear.dm
+++ b/code/modules/projectiles/guns/energy/nuclear.dm
@@ -1,6 +1,6 @@
/obj/item/weapon/gun/energy/gun
name = "energy gun"
- desc = "A basic energy-based gun with two settings: Stun and kill."
+ desc = "An energy-based gun with two settings: Stun and kill."
icon_state = "energystun100"
item_state = null //so the human update icon uses the icon_state instead.
fire_sound = 'sound/weapons/Taser.ogg'
@@ -12,118 +12,108 @@
var/mode = 0 //0 = stun, 1 = kill
+/obj/item/weapon/gun/energy/gun/attack_self(mob/living/user as mob)
+ switch(mode)
+ if(0)
+ mode = 1
+ charge_cost = 100
+ fire_sound = 'sound/weapons/Laser.ogg'
+ user << "[src.name] is now set to kill."
+ projectile_type = /obj/item/projectile/beam
+ modifystate = "energykill"
+ if(1)
+ mode = 0
+ charge_cost = 100
+ fire_sound = 'sound/weapons/Taser.ogg'
+ user << "[src.name] is now set to stun."
+ projectile_type = /obj/item/projectile/beam/stun
+ modifystate = "energystun"
+ update_icon()
+ if(user.l_hand == src)
+ user.update_inv_l_hand()
+ else
+ user.update_inv_r_hand()
- attack_self(mob/living/user as mob)
- switch(mode)
- if(0)
- mode = 1
- charge_cost = 100
- fire_sound = 'sound/weapons/Laser.ogg'
- user << "\red [src.name] is now set to kill."
- projectile_type = /obj/item/projectile/beam
- modifystate = "energykill"
- if(1)
- mode = 0
- charge_cost = 100
- fire_sound = 'sound/weapons/Taser.ogg'
- user << "\red [src.name] is now set to stun."
- projectile_type = /obj/item/projectile/beam/stun
- modifystate = "energystun"
- update_icon()
- if(user.l_hand == src)
- user.update_inv_l_hand()
- else
- user.update_inv_r_hand()
+/obj/item/weapon/gun/energy/gun/mounted
+ self_recharge = 1
+ use_external_power = 1
/obj/item/weapon/gun/energy/gun/nuclear
name = "advanced energy gun"
desc = "An energy gun with an experimental miniaturized reactor."
icon_state = "nucgun"
- origin_tech = "combat=3;materials=5;powerstorage=3"
+ origin_tech = "combat=3;materials=5;powerstorage=3"
+ slot_flags = SLOT_BELT
+ force = 8 //looks heavier than a pistol
+ self_recharge = 1
var/lightfail = 0
- var/charge_tick = 0
- New()
- ..()
- processing_objects.Add(src)
+//override for failcheck behaviour
+/obj/item/weapon/gun/energy/gun/nuclear/process()
+ charge_tick++
+ if(charge_tick < 4) return 0
+ charge_tick = 0
+ if(!power_supply) return 0
+ if((power_supply.charge / power_supply.maxcharge) != 1)
+ if(!failcheck()) return 0
+ power_supply.give(charge_cost)
+ update_icon()
+ return 1
-
- Del()
+/obj/item/weapon/gun/energy/gun/nuclear/proc/failcheck()
+ lightfail = 0
+ if (prob(src.reliability)) return 1 //No failure
+ if (prob(src.reliability))
+ for (var/mob/living/M in range(0,src)) //Only a minor failure, enjoy your radiation if you're in the same tile or carrying it
+ if (src in M.contents)
+ M << "Your gun feels pleasantly warm for a moment."
+ else
+ M << "You feel a warm sensation."
+ M.apply_effect(rand(3,120), IRRADIATE)
+ lightfail = 1
+ else
+ for (var/mob/living/M in range(rand(1,4),src)) //Big failure, TIME FOR RADIATION BITCHES
+ if (src in M.contents)
+ M << "Your gun's reactor overloads!"
+ M << "You feel a wave of heat wash over you."
+ M.apply_effect(300, IRRADIATE)
+ crit_fail = 1 //break the gun so it stops recharging
processing_objects.Remove(src)
- ..()
+ update_icon()
+ return 0
- process()
- charge_tick++
- if(charge_tick < 4) return 0
- charge_tick = 0
- if(!power_supply) return 0
- if((power_supply.charge / power_supply.maxcharge) != 1)
- if(!failcheck()) return 0
- power_supply.give(100)
- update_icon()
- return 1
+/obj/item/weapon/gun/energy/gun/nuclear/proc/update_charge()
+ if (crit_fail)
+ overlays += "nucgun-whee"
+ return
+ var/ratio = power_supply.charge / power_supply.maxcharge
+ ratio = round(ratio, 0.25) * 100
+ overlays += "nucgun-[ratio]"
+/obj/item/weapon/gun/energy/gun/nuclear/proc/update_reactor()
+ if(crit_fail)
+ overlays += "nucgun-crit"
+ return
+ if(lightfail)
+ overlays += "nucgun-medium"
+ else if ((power_supply.charge/power_supply.maxcharge) <= 0.5)
+ overlays += "nucgun-light"
+ else
+ overlays += "nucgun-clean"
- proc
- failcheck()
- lightfail = 0
- if (prob(src.reliability)) return 1 //No failure
- if (prob(src.reliability))
- for (var/mob/living/M in range(0,src)) //Only a minor failure, enjoy your radiation if you're in the same tile or carrying it
- if (src in M.contents)
- M << "\red Your gun feels pleasantly warm for a moment."
- else
- M << "\red You feel a warm sensation."
- M.apply_effect(rand(3,120), IRRADIATE)
- lightfail = 1
- else
- for (var/mob/living/M in range(rand(1,4),src)) //Big failure, TIME FOR RADIATION BITCHES
- if (src in M.contents)
- M << "\red Your gun's reactor overloads!"
- M << "\red You feel a wave of heat wash over you."
- M.apply_effect(300, IRRADIATE)
- crit_fail = 1 //break the gun so it stops recharging
- processing_objects.Remove(src)
- update_icon()
- return 0
+/obj/item/weapon/gun/energy/gun/nuclear/proc/update_mode()
+ if (mode == 0)
+ overlays += "nucgun-stun"
+ else if (mode == 1)
+ overlays += "nucgun-kill"
+/obj/item/weapon/gun/energy/gun/nuclear/emp_act(severity)
+ ..()
+ reliability -= round(15/severity)
- update_charge()
- if (crit_fail)
- overlays += "nucgun-whee"
- return
- var/ratio = power_supply.charge / power_supply.maxcharge
- ratio = round(ratio, 0.25) * 100
- overlays += "nucgun-[ratio]"
-
-
- update_reactor()
- if(crit_fail)
- overlays += "nucgun-crit"
- return
- if(lightfail)
- overlays += "nucgun-medium"
- else if ((power_supply.charge/power_supply.maxcharge) <= 0.5)
- overlays += "nucgun-light"
- else
- overlays += "nucgun-clean"
-
-
- update_mode()
- if (mode == 0)
- overlays += "nucgun-stun"
- else if (mode == 1)
- overlays += "nucgun-kill"
-
-
- emp_act(severity)
- ..()
- reliability -= round(15/severity)
-
-
- update_icon()
- overlays.Cut()
- update_charge()
- update_reactor()
- update_mode()
+/obj/item/weapon/gun/energy/gun/nuclear/update_icon()
+ overlays.Cut()
+ update_charge()
+ update_reactor()
+ update_mode()
diff --git a/code/modules/projectiles/guns/energy/pulse.dm b/code/modules/projectiles/guns/energy/pulse.dm
index f9644779fc..82ab47438b 100644
--- a/code/modules/projectiles/guns/energy/pulse.dm
+++ b/code/modules/projectiles/guns/energy/pulse.dm
@@ -1,70 +1,57 @@
/obj/item/weapon/gun/energy/pulse_rifle
name = "pulse rifle"
- desc = "A heavy-duty, pulse-based energy weapon, preferred by front-line combat personnel."
+ desc = "A weapon that uses advanced pulse-based beam generation technology to emit powerful laser blasts. Because of its complexity and cost, it is rarely seen in use except by specialists."
icon_state = "pulse"
item_state = null //so the human update icon uses the icon_state instead.
+ slot_flags = SLOT_BELT|SLOT_BACK
force = 10
fire_sound = 'sound/weapons/pulse.ogg'
charge_cost = 200
projectile_type = /obj/item/projectile/beam/pulse
- cell_type = "/obj/item/weapon/cell/super"
+ cell_type = /obj/item/weapon/cell/super
var/mode = 2
fire_delay = 25
- attack_self(mob/living/user as mob)
- switch(mode)
- if(2)
- mode = 0
- charge_cost = 100
- fire_sound = 'sound/weapons/Taser.ogg'
- user << "\red \The [src] is now set to stun."
- projectile_type = /obj/item/projectile/beam/stun
- if(0)
- mode = 1
- charge_cost = 100
- fire_sound = 'sound/weapons/Laser.ogg'
- user << "\red \The [src] is now set to kill."
- projectile_type = /obj/item/projectile/beam
- if(1)
- mode = 2
- charge_cost = 200
- fire_sound = 'sound/weapons/pulse.ogg'
- user << "\red \The [name] is now set to DESTROY."
- projectile_type = /obj/item/projectile/beam/pulse
- return
-
- isHandgun()
- return 0
-
-/obj/item/weapon/gun/energy/pulse_rifle/cyborg/load_into_chamber()
- if(in_chamber)
- return 1
- if(isrobot(src.loc))
- var/mob/living/silicon/robot/R = src.loc
- if(R && R.cell)
- R.cell.use(charge_cost)
- in_chamber = new/obj/item/projectile/beam(src)
- return 1
- return 0
+/obj/item/weapon/gun/energy/pulse_rifle/attack_self(mob/living/user as mob)
+ switch(mode)
+ if(2)
+ mode = 0
+ charge_cost = 100
+ fire_sound = 'sound/weapons/Taser.ogg'
+ user << "[src.name] is now set to stun."
+ projectile_type = /obj/item/projectile/beam/stun
+ if(0)
+ mode = 1
+ charge_cost = 100
+ fire_sound = 'sound/weapons/Laser.ogg'
+ user << "[src.name] is now set to kill."
+ projectile_type = /obj/item/projectile/beam
+ if(1)
+ mode = 2
+ charge_cost = 200
+ fire_sound = 'sound/weapons/pulse.ogg'
+ user << "[src.name] is now set to DESTROY."
+ projectile_type = /obj/item/projectile/beam/pulse
+/obj/item/weapon/gun/energy/pulse_rifle/mounted
+ self_recharge = 1
+ use_external_power = 1
/obj/item/weapon/gun/energy/pulse_rifle/destroyer
name = "pulse destroyer"
- desc = "A heavy-duty, pulse-based energy weapon."
- cell_type = "/obj/item/weapon/cell/infinite"
+ desc = "A heavy-duty, pulse-based energy weapon. Because of its complexity and cost, it is rarely seen in use except by specialists."
+ cell_type = /obj/item/weapon/cell/infinite
fire_delay = 10
- attack_self(mob/living/user as mob)
- user << "\red \The [src] has three settings, and they are all DESTROY."
-
+/obj/item/weapon/gun/energy/pulse_rifle/destroyer/attack_self(mob/living/user as mob)
+ user << "[src.name] has three settings, and they are all DESTROY."
+//WHY?
/obj/item/weapon/gun/energy/pulse_rifle/M1911
name = "\improper M1911-P"
desc = "It's not the size of the gun, it's the size of the hole it puts through people."
+ slot_flags = SLOT_BELT|SLOT_HOLSTER
icon_state = "m1911-p"
- cell_type = "/obj/item/weapon/cell/infinite"
+ cell_type = /obj/item/weapon/cell/infinite
fire_delay = 10
-
- isHandgun()
- return 1
diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm
index d1e11d7942..112a33e387 100644
--- a/code/modules/projectiles/guns/energy/special.dm
+++ b/code/modules/projectiles/guns/energy/special.dm
@@ -5,17 +5,16 @@
fire_sound = 'sound/weapons/Laser.ogg'
origin_tech = "combat=2;magnets=4"
w_class = 4.0
+ force = 10
flags = CONDUCT
slot_flags = SLOT_BACK
charge_cost = 100
- projectile_type = "/obj/item/projectile/ion"
+ projectile_type = /obj/item/projectile/ion
/obj/item/weapon/gun/energy/ionrifle/emp_act(severity)
- if(severity <= 2)
- power_supply.use(round(power_supply.maxcharge / severity))
- update_icon()
- else
- return
+ if(severity > 2)
+ return //so it doesn't EMP itself, I guess
+ ..()
/obj/item/weapon/gun/energy/decloner
name = "biological demolecularisor"
@@ -24,9 +23,89 @@
fire_sound = 'sound/weapons/pulse3.ogg'
origin_tech = "combat=5;materials=4;powerstorage=3"
charge_cost = 100
- projectile_type = "/obj/item/projectile/energy/declone"
+ projectile_type = /obj/item/projectile/energy/declone
-obj/item/weapon/gun/energy/staff
+/obj/item/weapon/gun/energy/floragun
+ name = "floral somatoray"
+ desc = "A tool that discharges controlled radiation which induces mutation in plant cells."
+ icon_state = "floramut100"
+ item_state = "obj/item/gun.dmi"
+ fire_sound = 'sound/effects/stealthoff.ogg'
+ charge_cost = 100
+ projectile_type = /obj/item/projectile/energy/floramut
+ origin_tech = "materials=2;biotech=3;powerstorage=3"
+ modifystate = "floramut"
+ self_recharge = 1
+ var/mode = 0 //0 = mutate, 1 = yield boost
+
+/obj/item/weapon/gun/energy/floragun/attack_self(mob/living/user as mob)
+ switch(mode)
+ if(0)
+ mode = 1
+ charge_cost = 100
+ user << "The [src.name] is now set to increase yield."
+ projectile_type = /obj/item/projectile/energy/florayield
+ modifystate = "florayield"
+ if(1)
+ mode = 0
+ charge_cost = 100
+ user << "The [src.name] is now set to induce mutations."
+ projectile_type = /obj/item/projectile/energy/floramut
+ modifystate = "floramut"
+ update_icon()
+ return
+
+/obj/item/weapon/gun/energy/floragun/afterattack(obj/target, mob/user, adjacent_flag)
+ //allow shooting into adjacent hydrotrays regardless of intent
+ if(adjacent_flag && istype(target,/obj/machinery/portable_atmospherics/hydroponics))
+ user.visible_message("\The [user] fires \the [src] into \the [target]!")
+ Fire(target,user)
+ return
+ ..()
+
+/obj/item/weapon/gun/energy/meteorgun
+ name = "meteor gun"
+ desc = "For the love of god, make sure you're aiming this the right way!"
+ icon_state = "riotgun"
+ item_state = "c20r"
+ slot_flags = SLOT_BELT|SLOT_BACK
+ w_class = 4
+ projectile_type = /obj/item/projectile/meteor
+ charge_cost = 100
+ cell_type = /obj/item/weapon/cell/potato
+ self_recharge = 1
+ recharge_time = 5 //Time it takes for shots to recharge (in ticks)
+ charge_meter = 0
+
+/obj/item/weapon/gun/energy/meteorgun/pen
+ name = "meteor pen"
+ desc = "The pen is mightier than the sword."
+ icon = 'icons/obj/bureaucracy.dmi'
+ icon_state = "pen"
+ item_state = "pen"
+ w_class = 1
+ slot_flags = SLOT_BELT
+
+
+/obj/item/weapon/gun/energy/mindflayer
+ name = "mind flayer"
+ desc = "A prototype weapon recovered from the ruins of Research-Station Epsilon."
+ icon_state = "xray"
+ projectile_type = /obj/item/projectile/beam/mindflayer
+ fire_sound = 'sound/weapons/Laser.ogg'
+
+/obj/item/weapon/gun/energy/toxgun
+ name = "phoron pistol"
+ desc = "A specialized firearm designed to fire lethal bolts of phoron."
+ icon_state = "toxgun"
+ fire_sound = 'sound/effects/stealthoff.ogg'
+ w_class = 3.0
+ origin_tech = "combat=5;phorontech=4"
+ projectile_type = /obj/item/projectile/energy/phoron
+
+/* Staves */
+
+/obj/item/weapon/gun/energy/staff
name = "staff of change"
desc = "An artefact that spits bolts of coruscating energy which cause the target's very form to reshape itself"
icon = 'icons/obj/gun.dmi'
@@ -37,209 +116,51 @@ obj/item/weapon/gun/energy/staff
slot_flags = SLOT_BACK
w_class = 4.0
charge_cost = 200
- projectile_type = "/obj/item/projectile/change"
+ projectile_type = /obj/item/projectile/change
origin_tech = null
- clumsy_check = 0
- var/charge_tick = 0
+ self_recharge = 1
+ charge_meter = 0
-
- New()
- ..()
- processing_objects.Add(src)
-
-
- Del()
- processing_objects.Remove(src)
- ..()
-
-
- process()
- charge_tick++
- if(charge_tick < 4) return 0
- charge_tick = 0
- if(!power_supply) return 0
- power_supply.give(200)
- return 1
-
- update_icon()
- return
-
-
- click_empty(mob/user = null)
- if (user)
- user.visible_message("*fizzle*", "\red *fizzle*")
- else
- src.visible_message("*fizzle*")
- playsound(src.loc, 'sound/effects/sparks1.ogg', 100, 1)
+/obj/item/weapon/gun/energy/staff/handle_click_empty(mob/user = null)
+ if (user)
+ user.visible_message("*fizzle*", "*fizzle*")
+ else
+ src.visible_message("*fizzle*")
+ playsound(src.loc, 'sound/effects/sparks1.ogg', 100, 1)
/obj/item/weapon/gun/energy/staff/animate
name = "staff of animation"
desc = "An artefact that spits bolts of life-force which causes objects which are hit by it to animate and come to life! This magic doesn't affect machines."
- projectile_type = "/obj/item/projectile/animate"
+ projectile_type = /obj/item/projectile/animate
charge_cost = 100
-/obj/item/weapon/gun/energy/floragun
- name = "floral somatoray"
- desc = "A tool that discharges controlled radiation which induces mutation in plant cells."
- icon_state = "floramut100"
- item_state = "obj/item/gun.dmi"
- fire_sound = 'sound/effects/stealthoff.ogg'
- charge_cost = 100
- projectile_type = "/obj/item/projectile/energy/floramut"
- origin_tech = "materials=2;biotech=3;powerstorage=3"
- modifystate = "floramut"
- var/charge_tick = 0
- var/mode = 0 //0 = mutate, 1 = yield boost
-
-/obj/item/weapon/gun/energy/floragun/New()
- ..()
- processing_objects.Add(src)
-
-/obj/item/weapon/gun/energy/floragun/Del()
- processing_objects.Remove(src)
- ..()
-
-/obj/item/weapon/gun/energy/floragun/process()
- charge_tick++
- if(charge_tick < 4) return 0
- charge_tick = 0
- if(!power_supply) return 0
- power_supply.give(100)
- update_icon()
- return 1
-
-/obj/item/weapon/gun/energy/floragun/attack_self(mob/living/user as mob)
- switch(mode)
- if(0)
- mode = 1
- charge_cost = 100
- user << "\red The [src.name] is now set to increase yield."
- projectile_type = "/obj/item/projectile/energy/florayield"
- modifystate = "florayield"
- if(1)
- mode = 0
- charge_cost = 100
- user << "\red The [src.name] is now set to induce mutations."
- projectile_type = "/obj/item/projectile/energy/floramut"
- modifystate = "floramut"
- update_icon()
- return
-
-/obj/item/weapon/gun/energy/floragun/afterattack(obj/target, mob/user, flag)
-
- if(flag && istype(target,/obj/machinery/portable_atmospherics/hydroponics))
- var/obj/machinery/portable_atmospherics/hydroponics/tray = target
- if(load_into_chamber())
- user.visible_message("\red \The [user] fires \the [src] into \the [tray]!")
- Fire(target,user)
- return
-
- ..()
-
-/obj/item/weapon/gun/energy/meteorgun
- name = "meteor gun"
- desc = "For the love of god, make sure you're aiming this the right way!"
- icon_state = "riotgun"
- item_state = "c20r"
- w_class = 4
- projectile_type = "/obj/item/projectile/meteor"
- charge_cost = 100
- cell_type = "/obj/item/weapon/cell/potato"
- clumsy_check = 0 //Admin spawn only, might as well let clowns use it.
- var/charge_tick = 0
- var/recharge_time = 5 //Time it takes for shots to recharge (in ticks)
-
- New()
- ..()
- processing_objects.Add(src)
-
-
- Del()
- processing_objects.Remove(src)
- ..()
-
- process()
- charge_tick++
- if(charge_tick < recharge_time) return 0
- charge_tick = 0
- if(!power_supply) return 0
- power_supply.give(100)
-
- update_icon()
- return
-
-
-/obj/item/weapon/gun/energy/meteorgun/pen
- name = "meteor pen"
- desc = "The pen is mightier than the sword."
- icon = 'icons/obj/bureaucracy.dmi'
- icon_state = "pen"
- item_state = "pen"
- w_class = 1
-
-
-/obj/item/weapon/gun/energy/mindflayer
- name = "mind flayer"
- desc = "A prototype weapon recovered from the ruins of Research-Station Epsilon."
- icon_state = "xray"
- projectile_type = "/obj/item/projectile/beam/mindflayer"
- fire_sound = 'sound/weapons/Laser.ogg'
-
obj/item/weapon/gun/energy/staff/focus
name = "mental focus"
desc = "An artefact that channels the will of the user into destructive bolts of force. If you aren't careful with it, you might poke someone's brain out."
icon = 'icons/obj/wizard.dmi'
icon_state = "focus"
item_state = "focus"
- projectile_type = "/obj/item/projectile/forcebolt"
+ slot_flags = SLOT_BACK
+ projectile_type = /obj/item/projectile/forcebolt
/*
attack_self(mob/living/user as mob)
if(projectile_type == "/obj/item/projectile/forcebolt")
charge_cost = 200
- user << "\red The [src.name] will now strike a small area."
+ user << "The [src.name] will now strike a small area."
projectile_type = "/obj/item/projectile/forcebolt/strong"
else
charge_cost = 100
- user << "\red The [src.name] will now strike only a single person."
+ user << "The [src.name] will now strike only a single person."
projectile_type = "/obj/item/projectile/forcebolt"
*/
-/obj/item/weapon/gun/energy/toxgun
- name = "phoron pistol"
- desc = "A specialized firearm designed to fire lethal bolts of phoron."
- icon_state = "toxgun"
- fire_sound = 'sound/effects/stealthoff.ogg'
- w_class = 3.0
- origin_tech = "combat=5;phorontech=4"
- projectile_type = "/obj/item/projectile/energy/phoron"
-
-/obj/item/weapon/gun/energy/sniperrifle
- name = "\improper L.W.A.P. sniper rifle"
- desc = "A rifle constructed of lightweight materials, fitted with a SMART aiming-system scope."
- icon = 'icons/obj/gun.dmi'
- icon_state = "sniper"
- fire_sound = 'sound/weapons/marauder.ogg'
- origin_tech = "combat=6;materials=5;powerstorage=4"
- projectile_type = "/obj/item/projectile/beam/sniper"
- slot_flags = SLOT_BACK
- charge_cost = 250
- fire_delay = 35
- w_class = 4.0
- zoomdevicename = "scope"
-
-/obj/item/weapon/gun/energy/sniperrifle/verb/scope()
- set category = "Object"
- set name = "Use Scope"
- set popup_menu = 1
-
- zoom()
-
+/* Adminbus guns */
// Serves as a target spotter for the Icarus.
/obj/item/weapon/gun/energy/icarus
name = "rubber ducky"
desc = "It's a cute rubber duck. With an evil gleam in it's eye."
- projectile_type = "/obj/item/projectile/icarus/pointdefense"
+ projectile_type = /obj/item/projectile/icarus/pointdefense
icon = 'icons/obj/watercloset.dmi'
icon_state = "rubberducky"
item_state = "rubberducky"
@@ -247,11 +168,11 @@ obj/item/weapon/gun/energy/staff/focus
silenced = 1
/obj/item/weapon/gun/energy/icarus/attack_self(mob/living/user as mob)
- if(projectile_type == "/obj/item/projectile/icarus/pointdefense")
- projectile_type = "/obj/item/projectile/icarus/guns"
+ if(projectile_type == /obj/item/projectile/icarus/pointdefense)
+ projectile_type = /obj/item/projectile/icarus/guns
user << "You inform the Icarus to switch to the main guns."
else
- projectile_type = "/obj/item/projectile/icarus/pointdefense"
+ projectile_type = /obj/item/projectile/icarus/pointdefense
user << "You inform the Icarus to switch to the point-defense lasers."
. = ..()
@@ -281,5 +202,5 @@ obj/item/weapon/gun/energy/staff/focus
var/type = input(user,"What projectile type?","Projectile", null) as null|anything in typesof(/obj/item/projectile)
if(!type)
return ..()
-
+ projectile_type = type
. = ..()
diff --git a/code/modules/projectiles/guns/energy/stun.dm b/code/modules/projectiles/guns/energy/stun.dm
index c3d6529dcb..6bbc2aed3e 100644
--- a/code/modules/projectiles/guns/energy/stun.dm
+++ b/code/modules/projectiles/guns/energy/stun.dm
@@ -6,38 +6,15 @@
fire_sound = 'sound/weapons/Taser.ogg'
charge_cost = 100
projectile_type = /obj/item/projectile/beam/stun
- cell_type = "/obj/item/weapon/cell/crap"
+ cell_type = /obj/item/weapon/cell/crap
-/obj/item/weapon/gun/energy/taser/cyborg
- cell_type = "/obj/item/weapon/cell/secborg"
- var/charge_tick = 0
- var/recharge_time = 10 //Time it takes for shots to recharge (in ticks)
+/obj/item/weapon/gun/energy/taser/mounted
+ self_recharge = 1
+ use_external_power = 1
- New()
- ..()
- processing_objects.Add(src)
-
-
- Del()
- processing_objects.Remove(src)
- ..()
-
- process() //Every [recharge_time] ticks, recharge a shot for the cyborg
- charge_tick++
- if(charge_tick < recharge_time) return 0
- charge_tick = 0
-
- if(!power_supply) return 0 //sanity
- if(power_supply.charge >= power_supply.maxcharge) return 0 // check if we actually need to recharge
-
- if(isrobot(src.loc))
- var/mob/living/silicon/robot/R = src.loc
- if(R && R.cell)
- R.cell.use(charge_cost) //Take power from the borg...
- power_supply.give(charge_cost) //... to recharge the shot
-
- update_icon()
- return 1
+/obj/item/weapon/gun/energy/taser/mounted/cyborg
+ cell_type = /obj/item/weapon/cell/secborg
+ recharge_time = 10 //Time it takes for shots to recharge (in ticks)
/obj/item/weapon/gun/energy/stunrevolver
@@ -48,8 +25,7 @@
origin_tech = "combat=3;materials=3;powerstorage=2"
charge_cost = 125
projectile_type = /obj/item/projectile/beam/stun
- cell_type = "/obj/item/weapon/cell"
-
+ cell_type = /obj/item/weapon/cell
/obj/item/weapon/gun/energy/crossbow
@@ -60,43 +36,22 @@
item_state = "crossbow"
matter = list("metal" = 2000)
origin_tech = "combat=2;magnets=2;syndicate=5"
+ slot_flags = SLOT_BELT
silenced = 1
fire_sound = 'sound/weapons/Genhit.ogg'
projectile_type = /obj/item/projectile/energy/bolt
- cell_type = "/obj/item/weapon/cell/crap"
- var/charge_tick = 0
-
-
- New()
- ..()
- processing_objects.Add(src)
-
-
- Del()
- processing_objects.Remove(src)
- ..()
-
-
- process()
- charge_tick++
- if(charge_tick < 4) return 0
- charge_tick = 0
- if(!power_supply) return 0
- power_supply.give(100)
- return 1
-
-
- update_icon()
- return
+ cell_type = /obj/item/weapon/cell/crap
+ self_recharge = 1
+ charge_meter = 0
/obj/item/weapon/gun/energy/crossbow/ninja
name = "energy dart thrower"
projectile_type = /obj/item/projectile/energy/dart
/obj/item/weapon/gun/energy/crossbow/largecrossbow
- name = "Energy Crossbow"
+ name = "energy crossbow"
desc = "A weapon favored by mercenary infiltration teams."
- w_class = 4.0
+ w_class = 4
force = 10
matter = list("metal" = 200000)
projectile_type = /obj/item/projectile/energy/bolt/large
diff --git a/code/modules/projectiles/guns/energy/temperature.dm b/code/modules/projectiles/guns/energy/temperature.dm
index 1e61590f21..ad4db3d5ca 100644
--- a/code/modules/projectiles/guns/energy/temperature.dm
+++ b/code/modules/projectiles/guns/energy/temperature.dm
@@ -7,74 +7,73 @@
var/current_temperature = T20C
charge_cost = 100
origin_tech = "combat=3;materials=4;powerstorage=3;magnets=2"
+ slot_flags = SLOT_BELT|SLOT_BACK
- projectile_type = "/obj/item/projectile/temp"
- cell_type = "/obj/item/weapon/cell/crap"
+ projectile_type = /obj/item/projectile/temp
+ cell_type = /obj/item/weapon/cell/crap
- New()
- ..()
- processing_objects.Add(src)
+/obj/item/weapon/gun/energy/temperature/New()
+ ..()
+ processing_objects.Add(src)
- Del()
- processing_objects.Remove(src)
- ..()
+/obj/item/weapon/gun/energy/temperature/Del()
+ processing_objects.Remove(src)
+ ..()
- attack_self(mob/living/user as mob)
- user.set_machine(src)
- var/temp_text = ""
- if(temperature > (T0C - 50))
- temp_text = "[temperature] ([round(temperature-T0C)]°C) ([round(temperature*1.8-459.67)]°F)"
+/obj/item/weapon/gun/energy/temperature/attack_self(mob/living/user as mob)
+ user.set_machine(src)
+ var/temp_text = ""
+ if(temperature > (T0C - 50))
+ temp_text = "[temperature] ([round(temperature-T0C)]°C) ([round(temperature*1.8-459.67)]°F)"
+ else
+ temp_text = "[temperature] ([round(temperature-T0C)]°C) ([round(temperature*1.8-459.67)]°F)"
+
+ var/dat = {"Freeze Gun Configuration:
+ Current output temperature: [temp_text]
+ Target output temperature: - - - [current_temperature] + + +
+ "}
+
+ user << browse(dat, "window=freezegun;size=450x300;can_resize=1;can_close=1;can_minimize=1")
+ onclose(user, "window=freezegun", src)
+
+
+/obj/item/weapon/gun/energy/temperature/Topic(href, href_list)
+ if (..())
+ return
+ usr.set_machine(src)
+ src.add_fingerprint(usr)
+
+
+
+ if(href_list["temp"])
+ var/amount = text2num(href_list["temp"])
+ if(amount > 0)
+ src.current_temperature = min(500, src.current_temperature+amount)
else
- temp_text = "[temperature] ([round(temperature-T0C)]°C) ([round(temperature*1.8-459.67)]°F)"
-
- var/dat = {"Freeze Gun Configuration:
- Current output temperature: [temp_text]
- Target output temperature: - - - [current_temperature] + + +
- "}
+ src.current_temperature = max(0, src.current_temperature+amount)
+ if (istype(src.loc, /mob))
+ attack_self(src.loc)
+ src.add_fingerprint(usr)
+ return
- user << browse(dat, "window=freezegun;size=450x300;can_resize=1;can_close=1;can_minimize=1")
- onclose(user, "window=freezegun", src)
+/obj/item/weapon/gun/energy/temperature/process()
+ switch(temperature)
+ if(0 to 100) charge_cost = 1000
+ if(100 to 250) charge_cost = 500
+ if(251 to 300) charge_cost = 100
+ if(301 to 400) charge_cost = 500
+ if(401 to 500) charge_cost = 1000
-
- Topic(href, href_list)
- if (..())
- return
- usr.set_machine(src)
- src.add_fingerprint(usr)
-
-
-
- if(href_list["temp"])
- var/amount = text2num(href_list["temp"])
- if(amount > 0)
- src.current_temperature = min(500, src.current_temperature+amount)
+ if(current_temperature != temperature)
+ var/difference = abs(current_temperature - temperature)
+ if(difference >= 10)
+ if(current_temperature < temperature)
+ temperature -= 10
else
- src.current_temperature = max(0, src.current_temperature+amount)
- if (istype(src.loc, /mob))
- attack_self(src.loc)
- src.add_fingerprint(usr)
- return
-
-
- process()
- switch(temperature)
- if(0 to 100) charge_cost = 1000
- if(100 to 250) charge_cost = 500
- if(251 to 300) charge_cost = 100
- if(301 to 400) charge_cost = 500
- if(401 to 500) charge_cost = 1000
-
- if(current_temperature != temperature)
- var/difference = abs(current_temperature - temperature)
- if(difference >= 10)
- if(current_temperature < temperature)
- temperature -= 10
- else
- temperature += 10
- else
- temperature = current_temperature
- return
+ temperature += 10
+ else
+ temperature = current_temperature
diff --git a/code/modules/projectiles/guns/launcher.dm b/code/modules/projectiles/guns/launcher.dm
new file mode 100644
index 0000000000..ea86814afa
--- /dev/null
+++ b/code/modules/projectiles/guns/launcher.dm
@@ -0,0 +1,32 @@
+/obj/item/weapon/gun/launcher
+ name = "launcher"
+ desc = "A device that launches things."
+ icon = 'icons/obj/weapons.dmi'
+ w_class = 5.0
+ flags = CONDUCT
+ slot_flags = SLOT_BACK
+
+ var/release_force = 0
+ var/throw_distance = 10
+ fire_sound_text = "a launcher firing"
+
+//This normally uses a proc on projectiles and our ammo is not strictly speaking a projectile.
+/obj/item/weapon/gun/launcher/can_hit(var/mob/living/target as mob, var/mob/living/user as mob)
+ return 1
+
+//Override this to avoid a runtime with suicide handling.
+/obj/item/weapon/gun/launcher/handle_suicide(mob/living/user)
+ user << "\red Shooting yourself with \a [src] is pretty tricky. You can't seem to manage it."
+ return
+
+/obj/item/weapon/gun/launcher/proc/update_release_force(obj/item/projectile)
+ return 0
+
+/obj/item/weapon/gun/launcher/process_projectile(obj/item/projectile, mob/user, atom/target, var/target_zone, var/params=null, var/pointblank=0, var/reflex=0)
+ update_release_force(projectile)
+ projectile.loc = get_turf(user)
+ projectile.throw_at(target, throw_distance, release_force, user)
+ return 1
+
+/obj/item/weapon/gun/launcher/attack_self(mob/living/user as mob)
+ return
diff --git a/code/modules/projectiles/guns/projectile/crossbow.dm b/code/modules/projectiles/guns/launcher/crossbow.dm
similarity index 76%
rename from code/modules/projectiles/guns/projectile/crossbow.dm
rename to code/modules/projectiles/guns/launcher/crossbow.dm
index faa3f8509f..3d3e2f6d86 100644
--- a/code/modules/projectiles/guns/projectile/crossbow.dm
+++ b/code/modules/projectiles/guns/launcher/crossbow.dm
@@ -51,43 +51,39 @@
icon_state = "crossbow"
item_state = "crossbow-solid"
fire_sound = 'sound/weapons/punchmiss.ogg' // TODO: Decent THWOK noise.
- ejectshell = 0 // No spent shells.
- mouthshoot = 1 // No suiciding with this weapon, causes runtimes.
fire_sound_text = "a solid thunk"
fire_delay = 25
+ slot_flags = SLOT_BACK
+ var/obj/item/bolt
var/tension = 0 // Current draw on the bow.
var/max_tension = 5 // Highest possible tension.
var/release_speed = 5 // Speed per unit of tension.
var/obj/item/weapon/cell/cell = null // Used for firing superheated rods.
var/current_user // Used to check if the crossbow has changed hands since being drawn.
-/obj/item/weapon/gun/launcher/crossbow/emp_act(severity)
- if(cell && severity)
- cell.use(100*severity)
-
-/obj/item/weapon/gun/launcher/crossbow/special_check(user)
- if(tension <= 0)
- user << "\red \The [src] is not drawn back!"
- return 0
- return 1
-
/obj/item/weapon/gun/launcher/crossbow/update_release_force()
release_force = tension*release_speed
-/obj/item/weapon/gun/launcher/crossbow/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0)
+/obj/item/weapon/gun/launcher/crossbow/consume_next_projectile(mob/user=null)
+ if(tension <= 0)
+ user << "\red \The [src] is not drawn back!"
+ return null
+ return bolt
- if(!..()) return //Only do this on a successful shot.
+/obj/item/weapon/gun/launcher/crossbow/handle_post_fire(mob/user, atom/target)
+ bolt = null
icon_state = "crossbow"
tension = 0
+ ..()
/obj/item/weapon/gun/launcher/crossbow/attack_self(mob/living/user as mob)
if(tension)
- if(in_chamber && in_chamber.loc == src) //Just in case they click it the tick after firing.
- user.visible_message("[user] relaxes the tension on [src]'s string and removes [in_chamber].","You relax the tension on [src]'s string and remove [in_chamber].")
- in_chamber.loc = get_turf(src)
- var/obj/item/weapon/arrow/A = in_chamber
- in_chamber = null
+ if(bolt)
+ user.visible_message("[user] relaxes the tension on [src]'s string and removes [bolt].","You relax the tension on [src]'s string and remove [bolt].")
+ bolt.loc = get_turf(src)
+ var/obj/item/weapon/arrow/A = bolt
+ bolt = null
A.removed(user)
else
user.visible_message("[user] relaxes the tension on [src]'s string.","You relax the tension on [src]'s string.")
@@ -98,7 +94,7 @@
/obj/item/weapon/gun/launcher/crossbow/proc/draw(var/mob/user as mob)
- if(!in_chamber)
+ if(!bolt)
user << "You don't have anything nocked to [src]."
return
@@ -106,50 +102,57 @@
return
current_user = user
- user.visible_message("[user] begins to draw back the string of [src].","You begin to draw back the string of [src].")
+ user.visible_message("[user] begins to draw back the string of [src].","You begin to draw back the string of [src].")
tension = 1
- spawn(25) increase_tension(user) //TODO: This needs to be changed to something less shit.
+
+ while(bolt && tension && current_user == user)
+ if(!do_after(user, 25)) //crossbow strings don't just magically pull back on their own.
+ user.visible_message("[usr] stops drawing and relaxes the string of [src].","You stop drawing back and relax the string of [src].")
+ tension = 0
+ icon_state = "crossbow"
+ return
+
+ tension++
+ icon_state = "crossbow-drawn"
+
+ if(tension >= max_tension)
+ tension = max_tension
+ usr << "[src] clunks as you draw the string to its maximum tension!"
+ return
+
+ user.visible_message("[usr] draws back the string of [src]!","You continue drawing back the string of [src]!")
/obj/item/weapon/gun/launcher/crossbow/proc/increase_tension(var/mob/user as mob)
- if(!in_chamber || !tension || current_user != user) //Arrow has been fired, bow has been relaxed or user has changed.
+ if(!bolt || !tension || current_user != user) //Arrow has been fired, bow has been relaxed or user has changed.
return
- tension++
- icon_state = "crossbow-drawn"
-
- if(tension>=max_tension)
- tension = max_tension
- usr << "[src] clunks as you draw the string to its maximum tension!"
- else
- user.visible_message("[usr] draws back the string of [src]!","You continue drawing back the string of [src]!")
- spawn(25) increase_tension(user)
/obj/item/weapon/gun/launcher/crossbow/attackby(obj/item/W as obj, mob/user as mob)
- if(!in_chamber)
+ if(!bolt)
if (istype(W,/obj/item/weapon/arrow))
user.drop_item()
- in_chamber = W
- in_chamber.loc = src
- user.visible_message("[user] slides [in_chamber] into [src].","You slide [in_chamber] into [src].")
+ bolt = W
+ bolt.loc = src
+ user.visible_message("[user] slides [bolt] into [src].","You slide [bolt] into [src].")
icon_state = "crossbow-nocked"
return
else if(istype(W,/obj/item/stack/rods))
var/obj/item/stack/rods/R = W
if (R.use(1))
- in_chamber = new /obj/item/weapon/arrow/rod(src)
- in_chamber.fingerprintslast = src.fingerprintslast
- in_chamber.loc = src
+ bolt = new /obj/item/weapon/arrow/rod(src)
+ bolt.fingerprintslast = src.fingerprintslast
+ bolt.loc = src
icon_state = "crossbow-nocked"
- user.visible_message("[user] jams [in_chamber] into [src].","You jam [in_chamber] into [src].")
+ user.visible_message("[user] jams [bolt] into [src].","You jam [bolt] into [src].")
superheat_rod(user)
return
if(istype(W, /obj/item/weapon/cell))
if(!cell)
user.drop_item()
- W.loc = src
cell = W
+ cell.loc = src
user << "You jam [cell] into [src] and wire it to the firing coil."
superheat_rod(user)
else
@@ -168,14 +171,14 @@
..()
/obj/item/weapon/gun/launcher/crossbow/proc/superheat_rod(var/mob/user)
- if(!user || !cell || !in_chamber) return
+ if(!user || !cell || !bolt) return
if(cell.charge < 500) return
- if(in_chamber.throwforce >= 15) return
- if(!istype(in_chamber,/obj/item/weapon/arrow/rod)) return
+ if(bolt.throwforce >= 15) return
+ if(!istype(bolt,/obj/item/weapon/arrow/rod)) return
- user << "[in_chamber] plinks and crackles as it begins to glow red-hot."
- in_chamber.throwforce = 15
- in_chamber.icon_state = "metal-rod-superheated"
+ user << "[bolt] plinks and crackles as it begins to glow red-hot."
+ bolt.throwforce = 15
+ bolt.icon_state = "metal-rod-superheated"
cell.use(500)
diff --git a/code/modules/projectiles/guns/launcher/grenade_launcher.dm b/code/modules/projectiles/guns/launcher/grenade_launcher.dm
new file mode 100644
index 0000000000..14e1c2e785
--- /dev/null
+++ b/code/modules/projectiles/guns/launcher/grenade_launcher.dm
@@ -0,0 +1,82 @@
+/obj/item/weapon/gun/launcher/grenade
+ name = "grenade launcher"
+ desc = "A bulky pump-action grenade launcher. Holds up to 5 grenades in a revolving magazine."
+ icon = 'icons/obj/gun.dmi'
+ icon_state = "riotgun"
+ item_state = "riotgun"
+ w_class = 4
+ force = 10
+
+ fire_sound = 'sound/weapons/empty.ogg'
+ fire_sound_text = "a metallic thunk"
+ recoil = 0
+ throw_distance = 7
+ release_force = 5
+
+ var/obj/item/weapon/grenade/chambered
+ var/list/grenades = new/list()
+ var/max_grenades = 4 //holds this + one in the chamber
+ matter = list("metal" = 2000)
+
+//revolves the magazine, allowing players to choose between multiple grenade types
+/obj/item/weapon/gun/launcher/grenade/proc/pump(mob/M as mob)
+ playsound(M, 'sound/weapons/shotgunpump.ogg', 60, 1)
+
+ var/obj/item/weapon/grenade/next
+ if(grenades.len)
+ next = grenades[1] //get this first, so that the chambered grenade can still be removed if the grenades list is empty
+ if(chambered)
+ grenades += chambered //rotate the revolving magazine
+ chambered = null
+ if(next)
+ grenades -= next //Remove grenade from loaded list.
+ chambered = next
+ M << "You pump [src], loading \a [next] into the chamber."
+ else
+ M << "You pump [src], but the magazine is empty."
+ update_icon()
+
+/obj/item/weapon/gun/launcher/grenade/examine(mob/user)
+ if(..(user, 2))
+ var/grenade_count = grenades.len + (chambered? 1 : 0)
+ user << "Has [grenade_count] grenade\s remaining."
+ if(chambered)
+ user << "\A [chambered] is chambered."
+
+/obj/item/weapon/gun/launcher/grenade/attack_self(mob/user)
+ pump(user)
+
+/obj/item/weapon/gun/launcher/grenade/attackby(obj/item/I, mob/user)
+ if((istype(I, /obj/item/weapon/grenade)))
+ if(grenades.len >= max_grenades)
+ user << "[src] is full."
+ return
+ user.remove_from_mob(I)
+ I.loc = src
+ grenades.Insert(1, I) //add to the head of the list, so that it is loaded on the next pump
+ user.visible_message("[user] inserts \a [I] into [src].", "You insert \a [I] into [src].")
+ else
+ ..()
+
+/obj/item/weapon/gun/launcher/grenade/attack_hand(mob/user)
+ if(user.get_inactive_hand() == src)
+ if(grenades.len)
+ var/obj/item/weapon/grenade/G = grenades[grenades.len]
+ grenades.len--
+ user.put_in_hands(G)
+ user.visible_message("[user] removes \a [G] from [src].", "You remove \a [G] from [src].")
+ else
+ user << "[src] is empty."
+ else
+ ..()
+
+/obj/item/weapon/gun/launcher/grenade/consume_next_projectile()
+ if(chambered)
+ chambered.det_time = 10
+ chambered.activate(null)
+ return chambered
+
+/obj/item/weapon/gun/launcher/grenade/handle_post_fire(mob/user)
+ message_admins("[key_name_admin(user)] fired a grenade ([chambered.name]) from a grenade launcher ([src.name]).")
+ log_game("[key_name_admin(user)] used a grenade ([chambered.name]).")
+ chambered = null
diff --git a/code/modules/projectiles/guns/projectile/pneumatic.dm b/code/modules/projectiles/guns/launcher/pneumatic.dm
similarity index 85%
rename from code/modules/projectiles/guns/projectile/pneumatic.dm
rename to code/modules/projectiles/guns/launcher/pneumatic.dm
index 43a5bc8e9a..712e74e150 100644
--- a/code/modules/projectiles/guns/projectile/pneumatic.dm
+++ b/code/modules/projectiles/guns/launcher/pneumatic.dm
@@ -4,6 +4,7 @@
icon = 'icons/obj/gun.dmi'
icon_state = "pneumatic"
item_state = "pneumatic"
+ slot_flags = SLOT_BELT
w_class = 5.0
flags = CONDUCT
fire_sound_text = "a loud whoosh of moving air"
@@ -61,8 +62,7 @@
icon_state = "pneumatic-tank"
item_state = "pneumatic-tank"
user.update_icons()
- else if(W.w_class <= max_w_class)
-
+ else if(istype(W) && W.w_class <= max_w_class)
var/total_stored = 0
for(var/obj/item/O in src.contents)
total_stored += O.w_class
@@ -79,9 +79,6 @@
/obj/item/weapon/gun/launcher/pneumatic/attack_self(mob/user as mob)
if(contents.len > 0)
var/obj/item/removing = contents[contents.len]
- if(removing == in_chamber)
- in_chamber = null
-
removing.loc = get_turf(src)
user.put_in_hands(removing)
user << "You remove [removing] from the hopper."
@@ -89,12 +86,19 @@
user << "There is nothing to remove in \the [src]."
return
-/obj/item/weapon/gun/launcher/pneumatic/load_into_chamber()
+/obj/item/weapon/gun/launcher/pneumatic/consume_next_projectile(mob/user=null)
if(!contents.len)
- return 0
+ return null
+ if (!tank)
+ user << "There is no gas tank in [src]!"
+ return null
- in_chamber = contents[1]
- return !isnull(in_chamber)
+ 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 null
+
+ return contents[1]
/obj/item/weapon/gun/launcher/pneumatic/examine(mob/user)
if(!..(user, 2))
@@ -105,31 +109,21 @@
else
user << "Nothing is attached to the tank valve!"
-/obj/item/weapon/gun/launcher/pneumatic/special_check(user)
+/obj/item/weapon/gun/launcher/pneumatic/update_release_force(obj/item/projectile)
+ if(tank)
+ release_force = ((fire_pressure*tank.volume)/projectile.w_class)/force_divisor //projectile speed.
+ if(release_force > 80) release_force = 80 //damage cap.
+ else
+ release_force = 0
- if (!tank)
- user << "There is no gas tank in [src]!"
- return 0
-
- 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
-
- return 1
-
-/obj/item/weapon/gun/launcher/pneumatic/update_release_force()
- if(!in_chamber) return
- release_force = ((fire_pressure*tank.volume)/in_chamber.w_class)/force_divisor //projectile speed.
- if(release_force >80) release_force = 80 //damage cap.
-
-/obj/item/weapon/gun/launcher/pneumatic/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0)
-
- if(!tank || !..()) return //Only do this on a successful shot.
-
- 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)
+/obj/item/weapon/gun/launcher/pneumatic/handle_post_fire()
+ if(tank)
+ var/lost_gas_amount = tank.air_contents.total_moles*(pressure_setting/100)
+ var/datum/gas_mixture/removed = tank.air_contents.remove(lost_gas_amount)
+
+ var/turf/T = get_turf(src.loc)
+ if(T) T.assume_air(removed)
+ ..()
//Constructable pneumatic cannon.
diff --git a/code/modules/projectiles/guns/launcher/rocket.dm b/code/modules/projectiles/guns/launcher/rocket.dm
new file mode 100644
index 0000000000..fd86302fb8
--- /dev/null
+++ b/code/modules/projectiles/guns/launcher/rocket.dm
@@ -0,0 +1,48 @@
+/obj/item/weapon/gun/launcher/rocket
+ name = "rocket launcher"
+ desc = "MAGGOT."
+ icon_state = "rocket"
+ item_state = "rocket"
+ w_class = 4.0
+ throw_speed = 2
+ throw_range = 10
+ force = 5.0
+ flags = CONDUCT | USEDELAY
+ slot_flags = 0
+ origin_tech = "combat=8;materials=5"
+ fire_sound = 'sound/effects/bang.ogg'
+
+ release_force = 15
+ throw_distance = 30
+ var/max_rockets = 1
+ var/list/rockets = new/list()
+
+/obj/item/weapon/gun/launcher/rocket/examine(mob/user)
+ if(!..(user, 2))
+ return
+ user << "\blue [rockets.len] / [max_rockets] rockets."
+
+/obj/item/weapon/gun/launcher/rocket/attackby(obj/item/I as obj, mob/user as mob)
+ if(istype(I, /obj/item/ammo_casing/rocket))
+ if(rockets.len < max_rockets)
+ user.drop_item()
+ I.loc = src
+ rockets += I
+ user << "\blue You put the rocket in [src]."
+ user << "\blue [rockets.len] / [max_rockets] rockets."
+ else
+ usr << "\red [src] cannot hold more rockets."
+
+/obj/item/weapon/gun/launcher/rocket/consume_next_projectile()
+ if(rockets.len)
+ var/obj/item/ammo_casing/rocket/I = rockets[1]
+ var/obj/item/missile/M = new (src)
+ M.primed = 1
+ rockets -= I
+ return M
+ return null
+
+/obj/item/weapon/gun/launcher/rocket/handle_post_fire(mob/user, atom/target)
+ message_admins("[key_name_admin(user)] fired a rocket from a rocket launcher ([src.name]) at [target].")
+ log_game("[key_name_admin(user)] used a rocket launcher ([src.name]) at [target].")
+ ..()
diff --git a/code/modules/projectiles/guns/launcher/syringe_gun.dm b/code/modules/projectiles/guns/launcher/syringe_gun.dm
new file mode 100644
index 0000000000..d4d66ac1cd
--- /dev/null
+++ b/code/modules/projectiles/guns/launcher/syringe_gun.dm
@@ -0,0 +1,135 @@
+/obj/item/weapon/syringe_cartridge
+ name = "syringe gun cartridge"
+ desc = "An impact-triggered compressed gas cartridge that can fitted to a syringe for rapid injection."
+ icon = 'icons/obj/ammo.dmi'
+ icon_state = "syringe-cartridge"
+ var/icon_flight = "syringe-cartridge-flight" //so it doesn't look so weird when shot
+ matter = list("metal" = 125, "glass" = 375)
+ flags = CONDUCT
+ slot_flags = SLOT_BELT
+ throwforce = 3
+ force = 3
+ w_class = 1
+ var/obj/item/weapon/reagent_containers/syringe/syringe
+
+/obj/item/weapon/syringe_cartridge/update_icon()
+ underlays.Cut()
+ if(syringe)
+ underlays += image(syringe.icon, src, syringe.icon_state)
+ underlays += syringe.filling
+
+/obj/item/weapon/syringe_cartridge/attackby(obj/item/I, mob/user)
+ if(istype(I, /obj/item/weapon/reagent_containers/syringe))
+ syringe = I
+ user << "You carefully insert [syringe] into [src]."
+ user.remove_from_mob(syringe)
+ syringe.loc = src
+ sharp = 1
+ update_icon()
+
+/obj/item/weapon/syringe_cartridge/attack_self(mob/user)
+ if(syringe)
+ user << "You remove [syringe] from [src]."
+ user.put_in_hands(syringe)
+ syringe = null
+ sharp = initial(sharp)
+ update_icon()
+
+/obj/item/weapon/syringe_cartridge/proc/prime()
+ //the icon state will revert back when update_icon() is called from throw_impact()
+ icon_state = icon_flight
+ underlays.Cut()
+
+/obj/item/weapon/syringe_cartridge/throw_impact(atom/hit_atom, var/speed)
+ ..() //handles embedding for us. Should have a decent chance if thrown fast enough
+ if(syringe)
+ //check speed to see if we hit hard enough to trigger the rapid injection
+ //incidentally, this means syringe_cartridges can be used with the pneumatic launcher
+ if(speed >= 10 && isliving(hit_atom))
+ var/mob/living/L = hit_atom
+ //unfortuately we don't know where the dart will actually hit, since that's done by the parent.
+ if(L.can_inject())
+ if(syringe.reagents)
+ syringe.reagents.trans_to(L, 15)
+
+ syringe.break_syringe(iscarbon(hit_atom)? hit_atom : null)
+ syringe.update_icon()
+
+ icon_state = initial(icon_state) //reset icon state
+ update_icon()
+
+/obj/item/weapon/gun/launcher/syringe
+ name = "syringe gun"
+ desc = "A spring loaded rifle designed to fit syringes, designed to incapacitate unruly patients from a distance."
+ icon = 'icons/obj/gun.dmi'
+ icon_state = "syringegun"
+ item_state = "syringegun"
+ w_class = 3
+ force = 7
+ matter = list("metal" = 2000)
+ slot_flags = SLOT_BELT
+
+ fire_sound = 'sound/weapons/empty.ogg'
+ fire_sound_text = "a metallic thunk"
+ recoil = 0
+ release_force = 10
+ throw_distance = 10
+
+ var/list/darts = list()
+ var/max_darts = 1
+ var/obj/item/weapon/syringe_cartridge/next
+
+/obj/item/weapon/gun/launcher/syringe/consume_next_projectile()
+ if(next)
+ next.prime()
+ return next
+ return null
+
+/obj/item/weapon/gun/launcher/syringe/handle_post_fire()
+ ..()
+ darts -= next
+ next = null
+
+/obj/item/weapon/gun/launcher/syringe/attack_self(mob/living/user as mob)
+ if(next)
+ user.visible_message("[user] unlatches and carefully relaxes the bolt on [src].", "You unlatch and carefully relax the bolt on [src], unloading the spring.")
+ next = null
+ else if(darts.len)
+ playsound(src.loc, 'sound/weapons/flipblade.ogg', 50, 1)
+ user.visible_message("[user] draws back the bolt on [src], clicking it into place.", "You draw back the bolt on the [src], loading the spring!")
+ next = darts[1]
+ add_fingerprint(user)
+
+/obj/item/weapon/gun/launcher/syringe/attack_hand(mob/living/user as mob)
+ if(user.get_inactive_hand() == src)
+ if(!darts.len)
+ user << "[src] is empty."
+ return
+ if(next)
+ user << "[src]'s cover is locked shut."
+ return
+ var/obj/item/weapon/syringe_cartridge/C = darts[1]
+ darts -= C
+ user.put_in_hands(C)
+ user.visible_message("[user] removes \a [C] from [src].", "You remove \a [C] from [src].")
+ else
+ ..()
+
+/obj/item/weapon/gun/launcher/syringe/attackby(var/obj/item/A as obj, mob/user as mob)
+ if(istype(A, /obj/item/weapon/syringe_cartridge))
+ var/obj/item/weapon/syringe_cartridge/C = A
+ if(darts.len >= max_darts)
+ user << "[src] is full!"
+ return
+ user.remove_from_mob(C)
+ C.loc = src
+ darts += C //add to the end
+ user.visible_message("[user] inserts \a [C] into [src].", "You insert \a [C] into [src].")
+ else
+ ..()
+
+/obj/item/weapon/gun/launcher/syringe/rapid
+ name = "syringe gun revolver"
+ desc = "A modification of the syringe gun design, using a rotating cylinder to store up to five syringes. The spring still needs to be drawn between shots."
+ icon_state = "rapidsyringegun"
+ max_darts = 5
diff --git a/code/modules/projectiles/guns/projectile.dm b/code/modules/projectiles/guns/projectile.dm
index bea28e9c37..5f197d56e6 100644
--- a/code/modules/projectiles/guns/projectile.dm
+++ b/code/modules/projectiles/guns/projectile.dm
@@ -1,121 +1,191 @@
-#define SPEEDLOADER 0
-#define FROM_BOX 1
-#define MAGAZINE 2
+#define HOLD_CASINGS 0 //do not do anything after firing. Manual action, like pump shotguns, or guns that want to define custom behaviour
+#define EJECT_CASINGS 1 //drop spent casings on the ground after firing
+#define CYCLE_CASINGS 2 //experimental: cycle casings, like a revolver. Also works for multibarrelled guns
/obj/item/weapon/gun/projectile
- name = "revolver"
- desc = "A classic revolver. Uses .357 ammo"
+ name = "gun"
+ desc = "A gun that fires bullets."
icon_state = "revolver"
- caliber = "357"
origin_tech = "combat=2;materials=2"
- w_class = 3.0
+ w_class = 3
matter = list("metal" = 1000)
recoil = 1
- var/ammo_type = "/obj/item/ammo_casing/a357"
- var/list/loaded = list()
- var/max_shells = 7
- var/load_method = SPEEDLOADER //0 = Single shells or quick loader, 1 = box, 2 = magazine
- var/obj/item/ammo_magazine/empty_mag = null
- var/mag_type = null
+
+ var/caliber = "357" //determines which casings will fit
+ var/handle_casings = EJECT_CASINGS //determines how spent casings should be handled
+ var/load_method = SINGLE_CASING|SPEEDLOADER //1 = Single shells, 2 = box or quick loader, 3 = magazine
+ var/obj/item/ammo_casing/chambered = null
+
+ //For SINGLE_CASING or SPEEDLOADER guns
+ var/max_shells = 0 //the number of casings that will fit inside
+ var/ammo_type = null //the type of ammo that the gun comes preloaded with
+ var/list/loaded = list() //stored ammo
+
+ //For MAGAZINE guns
+ var/magazine_type = null //the type of magazine that the gun comes preloaded with
+ var/obj/item/ammo_magazine/ammo_magazine = null //stored magazine
+ var/auto_eject = 0 //if the magazine should automatically eject itself when empty.
+ var/auto_eject_sound = null
/obj/item/weapon/gun/projectile/New()
..()
- for(var/i = 1, i <= max_shells, i++)
- loaded += new ammo_type(src)
- if(load_method == MAGAZINE)
- empty_mag = new mag_type(src)
+ if(ispath(ammo_type) && (load_method & (SINGLE_CASING|SPEEDLOADER)))
+ for(var/i in 1 to max_shells)
+ loaded += new ammo_type(src)
+ if(ispath(magazine_type) && (load_method & MAGAZINE))
+ ammo_magazine = new magazine_type(src)
+ update_icon()
+
+/obj/item/weapon/gun/projectile/consume_next_projectile()
+ //store the next ammo_casing in a var so that handle_post_fire() knows which one to eject
+ //also we might as well remove chambered here, so that we don't have to figure out where it came from later
+ if(loaded.len)
+ chambered = loaded[1] //load next casing.
+ if(handle_casings != HOLD_CASINGS)
+ loaded -= chambered
+ else if(ammo_magazine && ammo_magazine.stored_ammo.len)
+ chambered = ammo_magazine.stored_ammo[1]
+ if(handle_casings != HOLD_CASINGS)
+ ammo_magazine.stored_ammo -= chambered
+ return chambered.BB
+
+/obj/item/weapon/gun/projectile/handle_post_fire()
+ ..()
+ if(chambered)
+ chambered.expend()
+
+ //check chambered again in case it deleted itself
+ if(chambered && handle_casings != HOLD_CASINGS)
+ switch(handle_casings)
+ if(EJECT_CASINGS) //eject casing onto ground.
+ chambered.loc = get_turf(src)
+ if(CYCLE_CASINGS) //cycle the casing back to the end.
+ if(ammo_magazine)
+ ammo_magazine.stored_ammo += chambered
+ else
+ loaded += chambered
+ chambered = null
+
+
+//Attempts to load A into src, depending on the type of thing being loaded and the load_method
+//Maybe this should be broken up into separate procs for each load method?
+/obj/item/weapon/gun/projectile/proc/load_ammo(var/obj/item/A, mob/user)
+ if(istype(A, /obj/item/ammo_magazine))
+ var/obj/item/ammo_magazine/AM = A
+ if(!(load_method & AM.mag_type) || caliber != AM.caliber)
+ return //incompatible
+
+ switch(AM.mag_type)
+ if(MAGAZINE)
+ if(ammo_magazine)
+ user << "[src] already has a magazine loaded." //already a magazine here
+ return
+ user.remove_from_mob(AM)
+ AM.loc = src
+ ammo_magazine = AM
+ user.visible_message("[user] inserts [AM] into [src].", "You insert [AM] into [src].")
+ playsound(src.loc, 'sound/weapons/flipblade.ogg', 50, 1)
+ if(SPEEDLOADER)
+ if(loaded.len >= max_shells)
+ user << "[src] is full!"
+ return
+ var/count = 0
+ for(var/obj/item/ammo_casing/C in AM.stored_ammo)
+ if(loaded.len >= max_shells)
+ break
+ if(C.caliber == caliber)
+ C.loc = src
+ loaded += C
+ AM.stored_ammo -= C //should probably go inside an ammo_magazine proc, but I guess less proc calls this way...
+ count++
+ if(count)
+ user.visible_message("[user] reloads [src].", "You load [count] round\s into [src].")
+ playsound(src.loc, 'sound/weapons/empty.ogg', 50, 1)
+ AM.update_icon()
+ else if(istype(A, /obj/item/ammo_casing))
+ var/obj/item/ammo_casing/C = A
+ if(!(load_method & SINGLE_CASING) || caliber != C.caliber)
+ return //incompatible
+ if(loaded.len >= max_shells)
+ user << "[src] is full."
+ return
+
+ user.remove_from_mob(C)
+ C.loc = src
+ loaded.Insert(1, C) //add to the head of the list
+ user.visible_message("[user] inserts \a [C] into [src].", "You insert \a [C] into [src].")
+ playsound(src.loc, 'sound/weapons/empty.ogg', 50, 1)
+
update_icon()
- return
-/obj/item/weapon/gun/projectile/load_into_chamber()
- if(in_chamber)
- return 1 //{R}
-
- if(!loaded.len)
- return 0
- var/obj/item/ammo_casing/AC = loaded[1] //load next casing.
- loaded -= AC //Remove casing from loaded list.
- if(isnull(AC) || !istype(AC))
- return 0
- AC.loc = get_turf(src) //Eject casing onto ground.
- if(AC.BB)
- in_chamber = AC.BB //Load projectile into chamber.
- AC.BB.loc = src //Set projectile loc to gun.
- return 1
- return 0
-
+//attempts to unload src. If allow_dump is set to 0, the speedloader unloading method will be disabled
+/obj/item/weapon/gun/projectile/proc/unload_ammo(mob/user, var/allow_dump=1)
+ if(ammo_magazine)
+ user.put_in_hands(ammo_magazine)
+ user.visible_message("[user] removes [ammo_magazine] from [src].", "You remove [ammo_magazine] from [src].")
+ playsound(src.loc, 'sound/weapons/empty.ogg', 50, 1)
+ ammo_magazine.update_icon()
+ ammo_magazine = null
+ else if(loaded.len)
+ //presumably, if it can be speed-loaded, it can be speed-unloaded.
+ if(allow_dump && (load_method & SPEEDLOADER))
+ var/count = 0
+ var/turf/T = get_turf(user)
+ if(T)
+ for(var/obj/item/ammo_casing/C in loaded)
+ C.loc = T
+ count++
+ loaded.Cut()
+ if(count)
+ user.visible_message("[user] unloads [src].", "You unload [count] round\s from [src].")
+ else if(load_method & SINGLE_CASING)
+ var/obj/item/ammo_casing/C = loaded[loaded.len]
+ loaded.len--
+ user.put_in_hands(C)
+ user.visible_message("[user] removes \a [C] from [src].", "You remove \a [C] from [src].")
+ else
+ user << "[src] is empty."
+ update_icon()
/obj/item/weapon/gun/projectile/attackby(var/obj/item/A as obj, mob/user as mob)
-
- var/num_loaded = 0
- if(istype(A, /obj/item/ammo_magazine))
- if((load_method == MAGAZINE) && loaded.len) return
- var/obj/item/ammo_magazine/AM = A
- if(AM.stored_ammo.len <= 0)
- user << "The magazine is empty!"
- return
- for(var/obj/item/ammo_casing/AC in AM.stored_ammo)
- if(loaded.len >= max_shells)
- break
- if(AC.caliber == caliber && loaded.len < max_shells)
- AC.loc = src
- AM.stored_ammo -= AC
- loaded += AC
- num_loaded++
- if(load_method == MAGAZINE)
- user.remove_from_mob(AM)
- empty_mag = AM
- empty_mag.loc = src
- if(istype(A, /obj/item/ammo_casing) && load_method == SPEEDLOADER)
- var/obj/item/ammo_casing/AC = A
- if(AC.caliber == caliber && loaded.len < max_shells)
- user.drop_item()
- AC.loc = src
- loaded += AC
- num_loaded++
- if(num_loaded)
- user << "\blue You load [num_loaded] shell\s into the gun!"
- A.update_icon()
- update_icon()
- return
+ load_ammo(A, user)
/obj/item/weapon/gun/projectile/attack_self(mob/user as mob)
- if (target)
- return ..()
- if (loaded.len)
- if (load_method == SPEEDLOADER)
- var/obj/item/ammo_casing/AC = loaded[1]
- loaded -= AC
- AC.loc = get_turf(src) //Eject casing onto ground.
- user << "\blue You unload shell from \the [src]!"
- if (load_method == MAGAZINE)
- var/obj/item/ammo_magazine/AM = empty_mag
- for (var/obj/item/ammo_casing/AC in loaded)
- AM.stored_ammo += AC
- loaded -= AC
- AM.loc = get_turf(src)
- empty_mag = null
- update_icon()
- AM.update_icon()
- user << "\blue You unload magazine from \the [src]!"
+ unload_ammo(user)
+
+/obj/item/weapon/gun/projectile/attack_hand(mob/user as mob)
+ if(user.get_inactive_hand() == src)
+ unload_ammo(user, allow_dump=0)
else
- user << "\red Nothing loaded in \the [src]!"
-
+ return ..()
+/obj/item/weapon/gun/projectile/afterattack(atom/A, mob/living/user)
+ ..()
+ if(auto_eject && ammo_magazine && ammo_magazine.stored_ammo && !ammo_magazine.stored_ammo.len)
+ ammo_magazine.loc = get_turf(src.loc)
+ user.visible_message(
+ "[ammo_magazine] falls out and clatters on the floor!",
+ "[ammo_magazine] falls out and clatters on the floor!"
+ )
+ if(auto_eject_sound)
+ playsound(user, auto_eject_sound, 40, 1)
+ ammo_magazine = null
+ update_icon()
/obj/item/weapon/gun/projectile/examine(mob/user)
..(user)
user << "Has [getAmmo()] round\s remaining."
-// if(in_chamber && !loaded.len)
-// user << "However, it has a chambered round."
-// if(in_chamber && loaded.len)
-// user << "It also has a chambered round." {R}
+ if(ammo_magazine)
+ user << "It has \a [ammo_magazine] loaded."
return
/obj/item/weapon/gun/projectile/proc/getAmmo()
var/bullets = 0
- for(var/obj/item/ammo_casing/AC in loaded)
- if(istype(AC))
- bullets += 1
+ if(loaded)
+ bullets += loaded.len
+ if(ammo_magazine && ammo_magazine.stored_ammo)
+ bullets += ammo_magazine.stored_ammo.len
+ if(chambered)
+ bullets += 1
return bullets
diff --git a/code/modules/projectiles/guns/projectile/automatic.dm b/code/modules/projectiles/guns/projectile/automatic.dm
index 0e5f0d68cd..c518a11a57 100644
--- a/code/modules/projectiles/guns/projectile/automatic.dm
+++ b/code/modules/projectiles/guns/projectile/automatic.dm
@@ -2,67 +2,67 @@
name = "submachine gun"
desc = "A lightweight, fast firing gun. Uses 9mm rounds."
icon_state = "saber" //ugly
- w_class = 3.0
+ w_class = 3
+ load_method = SPEEDLOADER //yup. until someone sprites a magazine for it.
max_shells = 22
caliber = "9mm"
- origin_tech = "combat=4;materials=2"
- ammo_type = "/obj/item/ammo_casing/c9mm"
- automatic = 1
-
+ origin_tech = "combat=4;materials=2"
+ slot_flags = SLOT_BELT
+ ammo_type = /obj/item/ammo_casing/c9mm
+ multi_aim = 1
fire_delay = 0
-
- isHandgun()
- return 0
-
-/obj/item/weapon/gun/projectile/automatic/test
- name = "test gun"
- ammo_type = "/obj/item/ammo_casing/a145"
-
+
/obj/item/weapon/gun/projectile/automatic/mini_uzi
name = "\improper Uzi"
desc = "A lightweight, fast firing gun, for when you want someone dead. Uses .45 rounds."
icon_state = "mini-uzi"
- w_class = 3.0
- max_shells = 16
+ w_class = 3
+ load_method = SPEEDLOADER //yup. until someone sprites a magazine for it.
+ max_shells = 15
caliber = ".45"
origin_tech = "combat=5;materials=2;syndicate=8"
- ammo_type = "/obj/item/ammo_casing/c45"
-
- isHandgun()
- return 1
-
+ ammo_type = /obj/item/ammo_casing/c45
/obj/item/weapon/gun/projectile/automatic/c20r
name = "\improper C-20r SMG"
- desc = "A lightweight, fast firing gun, for when you REALLY need someone dead. Uses 12mm rounds. Has a 'Scarborough Arms - Per falcis, per pravitas' buttstamp"
+ desc = "A lightweight, fast firing gun, for when you REALLY need someone dead. Uses 12mm pistol rounds. Has a 'Scarborough Arms - Per falcis, per pravitas' buttstamp"
icon_state = "c20r"
item_state = "c20r"
- w_class = 3.0
- max_shells = 20
+ w_class = 3
+ force = 10
caliber = "12mm"
origin_tech = "combat=5;materials=2;syndicate=8"
- ammo_type = "/obj/item/ammo_casing/a12mm"
+ slot_flags = SLOT_BELT|SLOT_BACK
fire_sound = 'sound/weapons/Gunshot_smg.ogg'
load_method = MAGAZINE
- mag_type = /obj/item/ammo_magazine/a12mm/empty
+ magazine_type = /obj/item/ammo_magazine/a12mm
+ auto_eject = 1
+ auto_eject_sound = 'sound/weapons/smg_empty_alarm.ogg'
- afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag)
- ..()
- if(!loaded.len && empty_mag)
- empty_mag.loc = get_turf(src.loc)
- empty_mag = null
- playsound(user, 'sound/weapons/smg_empty_alarm.ogg', 40, 1)
- update_icon()
- return
+/obj/item/weapon/gun/projectile/automatic/c20r/update_icon()
+ ..()
+ if(ammo_magazine)
+ icon_state = "c20r-[round(loaded.len,4)]"
+ else
+ icon_state = "c20r"
+ return
+/obj/item/weapon/gun/projectile/automatic/sts35
+ name = "\improper STS-35 Automatic Rifle"
+ desc = "A durable, rugged looking automatic weapon of make popular on the frontier, despite it's bulk. Uses 7.62mm rounds. It is unmarked."
+ icon_state = "assltrifle"
+ item_state = "shotgun"
+ w_class = 4
+ force = 10
+ caliber = "a762"
+ origin_tech = "combat=5;materials=1;syndicate=8"
+ slot_flags = SLOT_BACK
+ load_method = MAGAZINE
+ magazine_type = /obj/item/ammo_magazine/c762
- update_icon()
- ..()
- if(empty_mag)
- icon_state = "c20r-[round(loaded.len,4)]"
- else
- icon_state = "c20r"
- return
+/obj/item/weapon/gun/projectile/automatic/sts35/update_icon()
+ ..()
+ icon_state = (ammo_magazine)? "assltrifle" : "assltrifle-noclip"
/obj/item/weapon/gun/projectile/automatic/l6_saw
name = "\improper L6 SAW"
@@ -70,74 +70,39 @@
icon_state = "l6closed100"
item_state = "l6closedmag"
w_class = 4
+ force = 10
slot_flags = 0
max_shells = 50
caliber = "a762"
origin_tech = "combat=5;materials=1;syndicate=2"
+ slot_flags = SLOT_BACK
ammo_type = "/obj/item/ammo_casing/a762"
fire_sound = 'sound/weapons/Gunshot_smg.ogg'
load_method = MAGAZINE
+ magazine_type = /obj/item/ammo_magazine/a762
var/cover_open = 0
- var/mag_inserted = 1
-
/obj/item/weapon/gun/projectile/automatic/l6_saw/attack_self(mob/user as mob)
cover_open = !cover_open
user << "You [cover_open ? "open" : "close"] [src]'s cover."
update_icon()
-
/obj/item/weapon/gun/projectile/automatic/l6_saw/update_icon()
- icon_state = "l6[cover_open ? "open" : "closed"][mag_inserted ? round(loaded.len, 25) : "-empty"]"
+ icon_state = "l6[cover_open ? "open" : "closed"][ammo_magazine ? round(loaded.len, 25) : "-empty"]"
-
-/obj/item/weapon/gun/projectile/automatic/l6_saw/afterattack(atom/target as mob|obj|turf, mob/living/user as mob|obj, flag, params) //what I tried to do here is just add a check to see if the cover is open or not and add an icon_state change because I can't figure out how c-20rs do it with overlays
+/obj/item/weapon/gun/projectile/automatic/l6_saw/special_check(mob/user)
if(cover_open)
- user << "[src]'s cover is open! Close it before firing!"
- else
- ..()
- update_icon()
+ user << "[src]'s cover is open! Close it before firing!"
+ return 0
+ return ..()
-
-/obj/item/weapon/gun/projectile/automatic/l6_saw/attack_hand(mob/user as mob)
- if(loc != user)
- ..()
- return //let them pick it up
- if(!cover_open || (cover_open && !mag_inserted))
- ..()
- else if(cover_open && mag_inserted)
- //drop the mag
- empty_mag = new /obj/item/ammo_magazine/a762(src)
- empty_mag.stored_ammo = loaded
- empty_mag.icon_state = "a762-[round(loaded.len, 10)]"
- empty_mag.desc = "There are [loaded.len] shells left!"
- empty_mag.loc = get_turf(src.loc)
- user.put_in_hands(empty_mag)
- empty_mag = null
- mag_inserted = 0
- loaded = list()
- update_icon()
- user << "You remove the magazine from [src]."
-
-
-/obj/item/weapon/gun/projectile/automatic/l6_saw/attackby(var/obj/item/A as obj, mob/user as mob)
+/obj/item/weapon/gun/projectile/automatic/l6_saw/load_ammo(var/obj/item/A, mob/user)
if(!cover_open)
- user << "[src]'s cover is closed! You can't insert a new mag!"
+ user << "You need to open the cover to load [src]."
return
- else if(cover_open && mag_inserted)
- user << "[src] already has a magazine inserted!"
- return
- else if(cover_open && !mag_inserted)
- mag_inserted = 1
- user << "You insert the magazine!"
- update_icon()
..()
-
-/* The thing I found with guns in ss13 is that they don't seem to simulate the rounds in the magazine in the gun.
- Afaik, since projectile.dm features a revolver, this would make sense since the magazine is part of the gun.
- However, it looks like subsequent guns that use removable magazines don't take that into account and just get
- around simulating a removable magazine by adding the casings into the loaded list and spawning an empty magazine
- when the gun is out of rounds. Which means you can't eject magazines with rounds in them. The below is a very
- rough and poor attempt at making that happen. -Ausops */
-
\ No newline at end of file
+/obj/item/weapon/gun/projectile/automatic/l6_saw/unload_ammo(mob/user)
+ if(!cover_open)
+ return
+ ..()
\ No newline at end of file
diff --git a/code/modules/projectiles/guns/projectile/dartgun.dm b/code/modules/projectiles/guns/projectile/dartgun.dm
new file mode 100644
index 0000000000..4d90a0fef3
--- /dev/null
+++ b/code/modules/projectiles/guns/projectile/dartgun.dm
@@ -0,0 +1,202 @@
+/obj/item/projectile/bullet/chemdart
+ name = "dart"
+ icon_state = "dart"
+ damage = 5
+ sharp = 1
+ embed = 1 //the dart is shot fast enough to pierce space suits, so I guess splintering inside the target can be a thing. Should be rare due to low damage.
+ var/reagent_amount = 15
+ kill_count = 15 //shorter range
+
+/obj/item/projectile/bullet/chemdart/New()
+ reagents = new/datum/reagents(reagent_amount)
+ reagents.my_atom = src
+
+/obj/item/projectile/bullet/chemdart/on_hit(var/atom/target, var/blocked = 0, var/def_zone = null)
+ if(blocked < 2 && isliving(target))
+ var/mob/living/L = target
+ if(L.can_inject(target_zone=def_zone))
+ reagents.trans_to(L, reagent_amount)
+
+/obj/item/ammo_casing/chemdart
+ name = "chemical dart"
+ desc = "A small hardened, hollow dart."
+ icon_state = "dart"
+ caliber = "dart"
+ projectile_type = /obj/item/projectile/bullet/chemdart
+
+/obj/item/ammo_casing/chemdart/expend()
+ del(src)
+
+/obj/item/ammo_magazine/chemdart
+ name = "dart cartridge"
+ desc = "A rack of hollow darts."
+ icon_state = "darts"
+ item_state = "rcdammo"
+ origin_tech = "materials=2"
+ mag_type = MAGAZINE
+ caliber = "dart"
+ ammo_type = /obj/item/ammo_casing/chemdart
+ max_ammo = 5
+ multiple_sprites = 1
+
+/obj/item/weapon/gun/projectile/dartgun
+ name = "dart gun"
+ desc = "A small gas-powered dartgun, capable of delivering chemical cocktails swiftly across short distances."
+ icon_state = "dartgun-empty"
+
+ caliber = "dart"
+ fire_sound = 'sound/weapons/empty.ogg'
+ fire_sound_text = "a metallic click"
+ recoil = 0
+ silenced = 1
+ load_method = MAGAZINE
+ magazine_type = /obj/item/ammo_magazine/chemdart
+ auto_eject = 0
+
+ var/list/beakers = list() //All containers inside the gun.
+ var/list/mixing = list() //Containers being used for mixing.
+ var/max_beakers = 3
+ var/dart_reagent_amount = 15
+ var/container_type = /obj/item/weapon/reagent_containers/glass/beaker
+ var/list/starting_chems = null
+
+/obj/item/weapon/gun/projectile/dartgun/dartgun/New()
+ ..()
+ if(starting_chems)
+ for(var/chem in starting_chems)
+ var/obj/B = new container_type(src)
+ B.reagents.add_reagent(chem, 60)
+ beakers += B
+ update_icon()
+
+/obj/item/weapon/gun/projectile/dartgun/update_icon()
+ if(!ammo_magazine)
+ icon_state = "dartgun-empty"
+ return 1
+
+ if(!ammo_magazine.stored_ammo || ammo_magazine.stored_ammo.len)
+ icon_state = "dartgun-0"
+ else if(ammo_magazine.stored_ammo.len > 5)
+ icon_state = "dartgun-5"
+ else
+ icon_state = "dartgun-[ammo_magazine.stored_ammo.len]"
+ return 1
+
+/obj/item/weapon/gun/projectile/dartgun/consume_next_projectile()
+ . = ..()
+ var/obj/item/projectile/bullet/chemdart/dart = .
+ if(istype(dart))
+ fill_dart(dart)
+
+/obj/item/weapon/gun/projectile/dartgun/examine(mob/user)
+ //update_icon()
+ //if (!..(user, 2))
+ // return
+ ..()
+ if (beakers.len)
+ user << "\blue [src] contains:"
+ for(var/obj/item/weapon/reagent_containers/glass/beaker/B in beakers)
+ if(B.reagents && B.reagents.reagent_list.len)
+ for(var/datum/reagent/R in B.reagents.reagent_list)
+ user << "\blue [R.volume] units of [R.name]"
+
+/obj/item/weapon/gun/projectile/dartgun/attackby(obj/item/I as obj, mob/user as mob)
+ if(istype(I, /obj/item/weapon/reagent_containers/glass))
+ if(!istype(I, container_type))
+ user << "\blue [I] doesn't seem to fit into [src]."
+ return
+ if(beakers.len >= max_beakers)
+ user << "\blue [src] already has [max_beakers] beakers in it - another one isn't going to fit!"
+ return
+ var/obj/item/weapon/reagent_containers/glass/beaker/B = I
+ user.drop_item()
+ B.loc = src
+ beakers += B
+ user << "\blue You slot [B] into [src]."
+ src.updateUsrDialog()
+ return 1
+ ..()
+
+//fills the given dart with reagents
+/obj/item/weapon/gun/projectile/dartgun/proc/fill_dart(var/obj/item/projectile/bullet/chemdart/dart)
+ if(mixing.len)
+ var/mix_amount = dart.reagent_amount/mixing.len
+ for(var/obj/item/weapon/reagent_containers/glass/beaker/B in mixing)
+ B.reagents.trans_to(dart, mix_amount)
+
+/obj/item/weapon/gun/projectile/dartgun/attack_self(mob/user)
+ user.set_machine(src)
+ var/dat = "[src] mixing control:
"
+
+ if (beakers.len)
+ var/i = 1
+ for(var/obj/item/weapon/reagent_containers/glass/beaker/B in beakers)
+ dat += "Beaker [i] contains: "
+ if(B.reagents && B.reagents.reagent_list.len)
+ for(var/datum/reagent/R in B.reagents.reagent_list)
+ dat += "
[R.volume] units of [R.name], "
+ if (check_beaker_mixing(B))
+ dat += text("Mixing ")
+ else
+ dat += text("Not mixing ")
+ else
+ dat += "nothing."
+ dat += " \[Eject\]
"
+ i++
+ else
+ dat += "There are no beakers inserted!
"
+
+ if(ammo_magazine)
+ if(ammo_magazine.stored_ammo && ammo_magazine.stored_ammo.len)
+ dat += "The dart cartridge has [ammo_magazine.stored_ammo.len] shots remaining."
+ else
+ dat += "The dart cartridge is empty!"
+ dat += " \[Eject\]"
+
+ user << browse(dat, "window=dartgun")
+ onclose(user, "dartgun", src)
+
+/obj/item/weapon/gun/projectile/dartgun/proc/check_beaker_mixing(var/obj/item/B)
+ if(!mixing || !beakers)
+ return 0
+ for(var/obj/item/M in mixing)
+ if(M == B)
+ return 1
+ return 0
+
+/obj/item/weapon/gun/projectile/dartgun/Topic(href, href_list)
+ src.add_fingerprint(usr)
+ if(href_list["stop_mix"])
+ var/index = text2num(href_list["stop_mix"])
+ if(index <= beakers.len)
+ for(var/obj/item/M in mixing)
+ if(M == beakers[index])
+ mixing -= M
+ break
+ else if (href_list["mix"])
+ var/index = text2num(href_list["mix"])
+ if(index <= beakers.len)
+ mixing += beakers[index]
+ else if (href_list["eject"])
+ var/index = text2num(href_list["eject"])
+ if(index <= beakers.len)
+ if(beakers[index])
+ var/obj/item/weapon/reagent_containers/glass/beaker/B = beakers[index]
+ usr << "You remove [B] from [src]."
+ mixing -= B
+ beakers -= B
+ B.loc = get_turf(src)
+ else if (href_list["eject_cart"])
+ unload_ammo(usr)
+ src.updateUsrDialog()
+ return
+
+/obj/item/weapon/gun/projectile/dartgun/vox
+ name = "alien dart gun"
+ desc = "A small gas-powered dartgun, fitted for nonhuman hands."
+
+/obj/item/weapon/gun/projectile/dartgun/vox/medical
+ starting_chems = list("kelotane","bicaridine","anti_toxin")
+
+/obj/item/weapon/gun/projectile/dartgun/vox/raider
+ starting_chems = list("space_drugs","stoxin","impedrezene")
\ No newline at end of file
diff --git a/code/modules/projectiles/guns/projectile/launcher.dm b/code/modules/projectiles/guns/projectile/launcher.dm
deleted file mode 100644
index 6626d809cd..0000000000
--- a/code/modules/projectiles/guns/projectile/launcher.dm
+++ /dev/null
@@ -1,89 +0,0 @@
-/obj/item/weapon/gun/launcher
- name = "launcher"
- desc = "A device that launches things."
- icon = 'icons/obj/weapons.dmi'
- w_class = 5.0
- flags = CONDUCT
- slot_flags = SLOT_BACK
-
- var/release_force = 0
- var/fire_sound_text = "a launcher firing"
-
-//Check if we're drawing and if the bow is loaded.
-/obj/item/weapon/gun/launcher/load_into_chamber()
- return (!isnull(in_chamber))
-
-//This should not fit in a combat belt or holster.
-/obj/item/weapon/gun/launcher/isHandgun()
- return 0
-
-//Launchers are mechanical, no other impact.
-/obj/item/weapon/gun/launcher/emp_act(severity)
- return
-
-//This normally uses a proc on projectiles and our ammo is not strictly speaking a projectile.
-/obj/item/weapon/gun/launcher/can_hit(var/mob/living/target as mob, var/mob/living/user as mob)
- return
-
-//Override this to avoid a runtime with suicide handling.
-/obj/item/weapon/gun/launcher/attack(mob/living/M as mob, mob/living/user as mob, def_zone)
- if (M == user && user.zone_sel.selecting == "mouth")
- user << "\red Shooting yourself with \a [src] is pretty tricky. You can't seem to manage it."
- return
- ..()
-
-/obj/item/weapon/gun/launcher/proc/update_release_force()
- return 0
-
-/obj/item/weapon/gun/launcher/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0)
-
- if (!user.IsAdvancedToolUser())
- return 0
-
- add_fingerprint(user)
-
- //Make sure target turfs both exist.
- var/turf/curloc = get_turf(user)
- var/turf/targloc = get_turf(target)
- if (!istype(targloc) || !istype(curloc))
- return 0
-
- if(!special_check(user))
- return 0
-
- if (!ready_to_fire())
- if (world.time % 3) //to prevent spam
- user << "[src] is not ready to fire again!"
- return 0
-
- if(!load_into_chamber()) //CHECK
- return click_empty(user)
-
- if(!in_chamber)
- return 0
-
- update_release_force()
-
- playsound(user, fire_sound, 50, 1)
- user.visible_message("[user] fires [src][reflex ? " by reflex":""]!", \
- "You fire [src][reflex ? "by reflex":""]!", \
- "You hear [fire_sound_text]!")
-
- in_chamber.loc = get_turf(user)
- in_chamber.throw_at(target,10,release_force)
-
- sleep(1)
-
- 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/launcher/attack_self(mob/living/user as mob)
- return
diff --git a/code/modules/projectiles/guns/projectile/pistol.dm b/code/modules/projectiles/guns/projectile/pistol.dm
index a0c6b0e5cb..1d6df6f859 100644
--- a/code/modules/projectiles/guns/projectile/pistol.dm
+++ b/code/modules/projectiles/guns/projectile/pistol.dm
@@ -1,47 +1,70 @@
+/obj/item/weapon/gun/projectile/colt
+ name = "\improper Colt M1911"
+ desc = "A cheap Martian knock-off of a Colt M1911."
+ magazine_type = /obj/item/ammo_magazine/c45m
+ icon_state = "colt"
+ caliber = ".45"
+ origin_tech = "combat=2;materials=2"
+ load_method = MAGAZINE
+
+/obj/item/weapon/gun/projectile/colt/flash
+ name = "\improper Colt M1911 signal pistol"
+ desc = "A cheap Martian knock-off of a Colt M1911. Uses .45 signal flash rounds."
+ magazine_type = /obj/item/ammo_magazine/c45m/flash
+
+/obj/item/weapon/gun/projectile/colt/detective
+ desc = "A cheap Martian knock-off of a Colt M1911. Uses less-than-lethal .45 rounds."
+ magazine_type = /obj/item/ammo_magazine/c45m/rubber
+
+/obj/item/weapon/gun/projectile/colt/detective/verb/rename_gun()
+ set name = "Name Gun"
+ set category = "Object"
+ set desc = "Rename your gun. If you're the detective."
+
+ var/mob/M = usr
+ if(!M.mind) return 0
+ if(!M.mind.assigned_role == "Detective")
+ M << "You don't feel cool enough to name this gun, chump."
+ return 0
+
+ var/input = stripped_input(usr,"What do you want to name the gun?", ,"", MAX_NAME_LEN)
+
+ if(src && input && !M.stat && in_range(M,src))
+ name = input
+ M << "You name the gun [input]. Say hello to your new friend."
+ return 1
+
/obj/item/weapon/gun/projectile/silenced
name = "silenced pistol"
desc = "A small, quiet, easily concealable gun. Uses .45 rounds."
icon_state = "silenced_pistol"
- w_class = 3.0
- max_shells = 12
+ w_class = 3
caliber = ".45"
silenced = 1
origin_tech = "combat=2;materials=2;syndicate=8"
- ammo_type = "/obj/item/ammo_casing/c45"
-
-
+ load_method = MAGAZINE
+ magazine_type = /obj/item/ammo_magazine/c45m
/obj/item/weapon/gun/projectile/deagle
name = "desert eagle"
desc = "A robust handgun that uses .50 AE ammo"
icon_state = "deagle"
force = 14.0
- max_shells = 7
caliber = ".50"
- ammo_type ="/obj/item/ammo_casing/a50"
load_method = MAGAZINE
- mag_type = /obj/item/ammo_magazine/a50/empty
-
- afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag)
- ..()
- if(!loaded.len && empty_mag)
- empty_mag.loc = get_turf(src.loc)
- empty_mag = null
- playsound(user, 'sound/weapons/smg_empty_alarm.ogg', 40, 1)
- update_icon()
- return
+ magazine_type = /obj/item/ammo_magazine/a50
+ auto_eject = 1
/obj/item/weapon/gun/projectile/deagle/gold
desc = "A gold plated gun folded over a million times by superior martian gunsmiths. Uses .50 AE ammo."
icon_state = "deagleg"
item_state = "deagleg"
-
-
/obj/item/weapon/gun/projectile/deagle/camo
desc = "A Deagle brand Deagle for operators operating operationally. Uses .50 AE ammo."
icon_state = "deaglecamo"
item_state = "deagleg"
+ auto_eject_sound = 'sound/weapons/smg_empty_alarm.ogg'
@@ -55,47 +78,35 @@
origin_tech = "combat=3"
ammo_type = "/obj/item/ammo_casing/a75"
load_method = MAGAZINE
- mag_type = /obj/item/ammo_magazine/a75/empty
+ magazine_type = /obj/item/ammo_magazine/a75
+ auto_eject = 1
+ auto_eject_sound = 'sound/weapons/smg_empty_alarm.ogg'
- afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag)
- ..()
- if(!loaded.len && empty_mag)
- empty_mag.loc = get_turf(src.loc)
- empty_mag = null
- playsound(user, 'sound/weapons/smg_empty_alarm.ogg', 40, 1)
- update_icon()
- return
-
- update_icon()
- ..()
- if(empty_mag)
- icon_state = "gyropistolloaded"
- else
- icon_state = "gyropistol"
- return
+/obj/item/weapon/gun/projectile/gyropistol/update_icon()
+ ..()
+ if(ammo_magazine)
+ icon_state = "gyropistolloaded"
+ else
+ icon_state = "gyropistol"
/obj/item/weapon/gun/projectile/pistol
name = "\improper Stechtkin pistol"
desc = "A small, easily concealable gun. Uses 9mm rounds."
icon_state = "pistol"
w_class = 2
- max_shells = 10
caliber = "9mm"
silenced = 0
origin_tech = "combat=2;materials=2;syndicate=2"
- ammo_type = "/obj/item/ammo_casing/c9mm"
load_method = MAGAZINE
- mag_type = /obj/item/ammo_magazine/mc9mm
+ magazine_type = /obj/item/ammo_magazine/mc9mm
-/obj/item/weapon/gun/projectile/pistol/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag)
- ..()
- if(!loaded.len && empty_mag)
- empty_mag.loc = get_turf(src.loc)
- empty_mag = null
- return
+/obj/item/weapon/gun/projectile/pistol/flash
+ name = "\improper Stechtkin signal pistol"
+ desc = "A small, easily concealable gun. Uses 9mm signal flash rounds."
+ magazine_type = /obj/item/ammo_magazine/mc9mm/flash
/obj/item/weapon/gun/projectile/pistol/attack_hand(mob/user as mob)
- if(loc == user)
+ if(user.get_inactive_hand() == src)
if(silenced)
if(user.l_hand != src && user.r_hand != src)
..()
@@ -108,7 +119,6 @@
return
..()
-
/obj/item/weapon/gun/projectile/pistol/attackby(obj/item/I as obj, mob/user as mob)
if(istype(I, /obj/item/weapon/silencer))
if(user.l_hand != src && user.r_hand != src) //if we're not in his hands
diff --git a/code/modules/projectiles/guns/projectile/revolver.dm b/code/modules/projectiles/guns/projectile/revolver.dm
index 226e6467aa..9bef0c40d3 100644
--- a/code/modules/projectiles/guns/projectile/revolver.dm
+++ b/code/modules/projectiles/guns/projectile/revolver.dm
@@ -1,186 +1,42 @@
-/obj/item/weapon/gun/projectile/detective
+/obj/item/weapon/gun/projectile/revolver
+ name = "revolver"
+ desc = "A classic revolver. Uses .357 ammo"
+ icon_state = "revolver"
+ caliber = "357"
+ origin_tech = "combat=2;materials=2"
+ handle_casings = CYCLE_CASINGS
+ max_shells = 7
+ ammo_type = /obj/item/ammo_casing/a357
+
+/obj/item/weapon/gun/projectile/revolver/mateba
+ name = "mateba"
+ desc = "When you absolutely, positively need a 10mm hole in the other guy. Uses .357 ammo." //>10mm hole >.357
+ icon_state = "mateba"
+ origin_tech = "combat=2;materials=2"
+
+/obj/item/weapon/gun/projectile/revolver/detective
name = "revolver"
desc = "A cheap Martian knock-off of a Smith & Wesson Model 10. Uses .38-Special rounds."
icon_state = "detective"
max_shells = 6
caliber = "38"
origin_tech = "combat=2;materials=2"
- ammo_type = "/obj/item/ammo_casing/c38"
+ ammo_type = /obj/item/ammo_casing/c38
- special_check(var/mob/living/carbon/human/M)
- if(caliber == initial(caliber))
- return 1
- if(prob(70 - (loaded.len * 10))) //minimum probability of 10, maximum of 60
- M << "[src] blows up in your face."
- M.take_organ_damage(0,20)
- M.drop_item()
- del(src)
- return 0
+/obj/item/weapon/gun/projectile/revolver/detective/verb/rename_gun()
+ set name = "Name Gun"
+ set category = "Object"
+ set desc = "Click to rename your gun. If you're the detective."
+
+ var/mob/M = usr
+ if(!M.mind) return 0
+ if(!M.mind.assigned_role == "Detective")
+ M << "You don't feel cool enough to name this gun, chump."
+ return 0
+
+ var/input = stripped_input(usr,"What do you want to name the gun?", ,"", MAX_NAME_LEN)
+
+ if(src && input && !M.stat && in_range(M,src))
+ name = input
+ M << "You name the gun [input]. Say hello to your new friend."
return 1
-
- verb/rename_gun()
- set name = "Name Gun"
- set category = "Object"
- set desc = "Click to rename your gun. If you're the detective."
-
- var/mob/M = usr
- if(!M.mind) return 0
- if(!M.mind.assigned_role == "Detective")
- M << "You don't feel cool enough to name this gun, chump."
- return 0
-
- var/input = stripped_input(usr,"What do you want to name the gun?", ,"", MAX_NAME_LEN)
-
- if(src && input && !M.stat && in_range(M,src))
- name = input
- M << "You name the gun [input]. Say hello to your new friend."
- return 1
-
- attackby(var/obj/item/A as obj, mob/user as mob)
- ..()
- if(istype(A, /obj/item/weapon/screwdriver))
- if(caliber == "38")
- user << "You begin to reinforce the barrel of [src]."
- if(loaded.len)
- afterattack(user, user) //you know the drill
- playsound(user, fire_sound, 50, 1)
- user.visible_message("[src] goes off!", "[src] goes off in your face!")
- return
- if(do_after(user, 30))
- if(loaded.len)
- user << "You can't modify it!"
- return
- caliber = "357"
- desc = "The barrel and chamber assembly seems to have been modified."
- user << "You reinforce the barrel of [src]! Now it will fire .357 rounds."
- else if (caliber == "357")
- user << "You begin to revert the modifications to [src]."
- if(loaded.len)
- afterattack(user, user) //and again
- playsound(user, fire_sound, 50, 1)
- user.visible_message("[src] goes off!", "[src] goes off in your face!")
- return
- if(do_after(user, 30))
- if(loaded.len)
- user << "You can't modify it!"
- return
- caliber = "38"
- desc = initial(desc)
- user << "You remove the modifications on [src]! Now it will fire .38 rounds."
-
-
-/obj/item/weapon/gun/projectile/detective/semiauto
- name = "\improper Colt M1911"
- desc = "A cheap Martian knock-off of a Colt M1911. Uses less-than-lethal .45 rounds."
- icon_state = "colt"
- max_shells = 7
- caliber = ".45"
- ammo_type = "/obj/item/ammo_casing/c45r"
- load_method = MAGAZINE
- mag_type = /obj/item/ammo_magazine/c45r/empty
-
-/obj/item/weapon/gun/projectile/detective/semiauto/flash
- ammo_type = "/obj/item/ammo_casing/c45f"
-
-/obj/item/weapon/gun/projectile/detective/semiauto/colt
- desc = "A cheap Martian knock-off of a Colt M1911."
- ammo_type = "/obj/item/ammo_casing/c45"
-
-/obj/item/weapon/gun/projectile/detective/semiauto/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag)
- ..()
- if(!loaded.len && empty_mag)
- empty_mag.loc = get_turf(src.loc)
- empty_mag = null
- user << "The Magazine falls out and clatters on the floor!"
- return
-
-
-/obj/item/weapon/gun/projectile/mateba
- name = "mateba"
- desc = "When you absolutely, positively need a 10mm hole in the other guy. Uses .357 ammo." //>10mm hole >.357
- icon_state = "mateba"
- origin_tech = "combat=2;materials=2"
-
-// A gun to play Russian Roulette!
-// You can spin the chamber to randomize the position of the bullet.
-
-/obj/item/weapon/gun/projectile/russian
- name = "\improper Russian revolver"
- desc = "A Russian made revolver. Uses .357 ammo. It has a single slot in it's chamber for a bullet."
- max_shells = 6
- origin_tech = "combat=2;materials=2"
-
-/obj/item/weapon/gun/projectile/russian/New()
- Spin()
- update_icon()
-
-/obj/item/weapon/gun/projectile/russian/proc/Spin()
- for(var/obj/item/ammo_casing/AC in loaded)
- del(AC)
- loaded = list()
- var/random = rand(1, max_shells)
- for(var/i = 1; i <= max_shells; i++)
- if(i != random)
- loaded += i // Basically null
- else
- loaded += new ammo_type(src)
-
-
-/obj/item/weapon/gun/projectile/russian/attackby(var/obj/item/A as obj, mob/user as mob)
- if(!A) return
-
- var/num_loaded = 0
- if(istype(A, /obj/item/ammo_magazine))
-
- if((load_method == MAGAZINE) && loaded.len) return
- var/obj/item/ammo_magazine/AM = A
- for(var/obj/item/ammo_casing/AC in AM.stored_ammo)
- if(getAmmo() > 0 || loaded.len >= max_shells)
- break
- if(AC.caliber == caliber && loaded.len < max_shells)
- AC.loc = src
- AM.stored_ammo -= AC
- loaded += AC
- num_loaded++
- break
- A.update_icon()
-
- if(num_loaded)
- user.visible_message("[user] loads a single bullet into the revolver and spins the chamber.", "You load a single bullet into the chamber and spin it.")
- else
- user.visible_message("[user] spins the chamber of the revolver.", "You spin the revolver's chamber.")
- if(getAmmo() > 0)
- Spin()
- update_icon()
- return
-
-/obj/item/weapon/gun/projectile/russian/attack_self(mob/user as mob)
- user.visible_message("[user] spins the chamber of the revolver.", "You spin the revolver's chamber.")
- if(getAmmo() > 0)
- Spin()
-
-/obj/item/weapon/gun/projectile/russian/attack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj)
- if(!loaded.len)
- user.visible_message("\red *click*", "\red *click*")
- playsound(user, 'sound/weapons/empty.ogg', 100, 1)
- return
-
- if(isliving(target) && isliving(user))
- if(target == user)
- var/datum/organ/external/affecting = user.zone_sel.selecting
- if(affecting == "head")
-
- var/obj/item/ammo_casing/AC = loaded[1]
- if(!load_into_chamber())
- user.visible_message("\red *click*", "\red *click*")
- playsound(user, 'sound/weapons/empty.ogg', 100, 1)
- return
- if(!in_chamber)
- return
- var/obj/item/projectile/P = new AC.projectile_type
- playsound(user, fire_sound, 50, 1)
- user.visible_message("[user.name] fires [src] at \his head!", "You fire [src] at your head!", "You hear a [istype(in_chamber, /obj/item/projectile/beam) ? "laser blast" : "gunshot"]!")
- if(!P.nodamage)
- user.apply_damage(300, BRUTE, affecting, sharp=1) // You are dead, dead, dead.
- return
- ..()
diff --git a/code/modules/projectiles/guns/projectile/rocket.dm b/code/modules/projectiles/guns/projectile/rocket.dm
deleted file mode 100644
index 27fb15d571..0000000000
--- a/code/modules/projectiles/guns/projectile/rocket.dm
+++ /dev/null
@@ -1,51 +0,0 @@
-/obj/item/weapon/gun/rocketlauncher
- name = "rocket launcher"
- desc = "MAGGOT."
- icon_state = "rocket"
- item_state = "rocket"
- w_class = 4.0
- throw_speed = 2
- throw_range = 10
- force = 5.0
- flags = CONDUCT | USEDELAY
- slot_flags = 0
- origin_tech = "combat=8;materials=5"
- var/projectile = /obj/item/missile
- var/missile_speed = 2
- var/missile_range = 30
- var/max_rockets = 1
- var/list/rockets = new/list()
-
-/obj/item/weapon/gun/rocketlauncher/examine(mob/user)
- if(!..(user, 2))
- return
- user << "\blue [rockets.len] / [max_rockets] rockets."
-
-/obj/item/weapon/gun/rocketlauncher/attackby(obj/item/I as obj, mob/user as mob)
- if(istype(I, /obj/item/ammo_casing/rocket))
- if(rockets.len < max_rockets)
- user.drop_item()
- I.loc = src
- rockets += I
- user << "\blue You put the rocket in [src]."
- user << "\blue [rockets.len] / [max_rockets] rockets."
- else
- usr << "\red [src] cannot hold more rockets."
-
-/obj/item/weapon/gun/rocketlauncher/can_fire()
- return rockets.len
-
-/obj/item/weapon/gun/rocketlauncher/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0)
- if(rockets.len)
- var/obj/item/ammo_casing/rocket/I = rockets[1]
- var/obj/item/missile/M = new projectile(user.loc)
- playsound(user.loc, 'sound/effects/bang.ogg', 50, 1)
- M.primed = 1
- M.throw_at(target, missile_range, missile_speed,user)
- message_admins("[key_name_admin(user)] fired a rocket from a rocket launcher ([src.name]).")
- log_game("[key_name_admin(user)] used a rocket launcher ([src.name]).")
- rockets -= I
- del(I)
- return
- else
- usr << "\red [src] is empty."
diff --git a/code/modules/projectiles/guns/projectile/shotgun.dm b/code/modules/projectiles/guns/projectile/shotgun.dm
index e96c7637e3..77a9867e93 100644
--- a/code/modules/projectiles/guns/projectile/shotgun.dm
+++ b/code/modules/projectiles/guns/projectile/shotgun.dm
@@ -10,127 +10,79 @@
slot_flags = SLOT_BACK
caliber = "shotgun"
origin_tech = "combat=4;materials=2"
- ammo_type = "/obj/item/ammo_casing/shotgun/pellet"
+ load_method = SINGLE_CASING
+ ammo_type = /obj/item/ammo_casing/shotgun/pellet
+ handle_casings = HOLD_CASINGS
var/recentpump = 0 // to prevent spammage
- var/pumped = 0
- var/obj/item/ammo_casing/current_shell = null
- isHandgun()
- return 0
+/obj/item/weapon/gun/projectile/shotgun/pump/consume_next_projectile()
+ if(chambered)
+ return chambered.BB
+ return null
- load_into_chamber()
- if(in_chamber)
- return 1
- return 0
+/obj/item/weapon/gun/projectile/shotgun/pump/attack_self(mob/living/user as mob)
+ if(world.time >= recentpump + 10)
+ pump(user)
+ recentpump = world.time
-
- attack_self(mob/living/user as mob)
- if(recentpump) return
- pump(user)
- recentpump = 1
- spawn(10)
- recentpump = 0
- return
-
-
- proc/pump(mob/M as mob)
- playsound(M, 'sound/weapons/shotgunpump.ogg', 60, 1)
- pumped = 0
- if(current_shell)//We have a shell in the chamber
- current_shell.loc = get_turf(src)//Eject casing
- current_shell = null
- if(in_chamber)
- in_chamber = null
- if(!loaded.len) return 0
+/obj/item/weapon/gun/projectile/shotgun/pump/proc/pump(mob/M as mob)
+ playsound(M, 'sound/weapons/shotgunpump.ogg', 60, 1)
+
+ if(chambered)//We have a shell in the chamber
+ chambered.loc = get_turf(src)//Eject casing
+ chambered = null
+
+ if(loaded.len)
var/obj/item/ammo_casing/AC = loaded[1] //load next casing.
loaded -= AC //Remove casing from loaded list.
- current_shell = AC
- if(AC.BB)
- in_chamber = AC.BB //Load projectile into chamber.
- update_icon() //I.E. fix the desc
- return 1
+ chambered = AC
+
+ update_icon()
/obj/item/weapon/gun/projectile/shotgun/pump/combat
name = "combat shotgun"
icon_state = "cshotgun"
- max_shells = 8
origin_tech = "combat=5;materials=2"
- ammo_type = "/obj/item/ammo_casing/shotgun"
+ max_shells = 8
+ ammo_type = /obj/item/ammo_casing/shotgun
+
-//this is largely hacky and bad :( -Pete
/obj/item/weapon/gun/projectile/shotgun/doublebarrel
name = "double-barreled shotgun"
desc = "A true classic."
icon_state = "dshotgun"
item_state = "shotgun"
+ //SPEEDLOADER because rapid unloading.
+ //In principle someone could make a speedloader for it, so it makes sense.
+ load_method = SINGLE_CASING|SPEEDLOADER
+ handle_casings = CYCLE_CASINGS
max_shells = 2
- w_class = 4.0
+ w_class = 4
force = 10
flags = CONDUCT
slot_flags = SLOT_BACK
caliber = "shotgun"
- origin_tech = "combat=3;materials=1"
- ammo_type = "/obj/item/ammo_casing/shotgun/beanbag"
+ origin_tech = "combat=3;materials=1"
+ ammo_type = /obj/item/ammo_casing/shotgun/beanbag
- New()
- for(var/i = 1, i <= max_shells, i++)
- loaded += new ammo_type(src)
-
- update_icon()
- return
-
- load_into_chamber()
-// if(in_chamber)
-// return 1 {R}
- if(!loaded.len)
- return 0
-
- var/obj/item/ammo_casing/AC = loaded[1] //load next casing.
- loaded -= AC //Remove casing from loaded list.
- AC.desc += " This one is spent."
-
- if(AC.BB)
- in_chamber = AC.BB //Load projectile into chamber.
- return 1
- return 0
-
- attack_self(mob/living/user as mob)
- if(!(locate(/obj/item/ammo_casing/shotgun) in src) && !loaded.len)
- user << "\The [src] is empty."
- return
-
- for(var/obj/item/ammo_casing/shotgun/shell in src) //This feels like a hack. //don't code at 3:30am kids!!
- if(shell in loaded)
- loaded -= shell
- shell.loc = get_turf(src.loc)
-
- user << "You break \the [src]."
- update_icon()
-
- attackby(var/obj/item/A as obj, mob/user as mob)
- if(istype(A, /obj/item/ammo_casing) && !load_method)
- var/obj/item/ammo_casing/AC = A
- if(AC.caliber == caliber && (loaded.len < max_shells) && (contents.len < max_shells)) //forgive me father, for i have sinned
- user.drop_item()
- AC.loc = src
- loaded += AC
- user << "You load a shell into \the [src]!"
- A.update_icon()
- update_icon()
- if(istype(A, /obj/item/weapon/circular_saw) || istype(A, /obj/item/weapon/melee/energy) || istype(A, /obj/item/weapon/pickaxe/plasmacutter))
- user << "You begin to shorten the barrel of \the [src]."
- if(loaded.len)
- afterattack(user, user) //will this work?
- afterattack(user, user) //it will. we call it twice, for twice the FUN
+//this is largely hacky and bad :( -Pete
+/obj/item/weapon/gun/projectile/shotgun/doublebarrel/attackby(var/obj/item/A as obj, mob/user as mob)
+ if(istype(A, /obj/item/weapon/circular_saw) || istype(A, /obj/item/weapon/melee/energy) || istype(A, /obj/item/weapon/pickaxe/plasmacutter))
+ user << "You begin to shorten the barrel of \the [src]."
+ if(loaded.len)
+ for(var/i in 1 to max_shells)
+ afterattack(user, user) //will this work? //it will. we call it twice, for twice the FUN
playsound(user, fire_sound, 50, 1)
- user.visible_message("The shotgun goes off!", "The shotgun goes off in your face!")
- return
- if(do_after(user, 30)) //SHIT IS STEALTHY EYYYYY
- icon_state = "sawnshotgun"
- w_class = 3.0
- item_state = "gun"
- slot_flags &= ~SLOT_BACK //you can't sling it on your back
- slot_flags |= SLOT_BELT //but you can wear it on your belt (poorly concealed under a trenchcoat, ideally)
- name = "sawn-off shotgun"
- desc = "Omar's coming!"
- user << "You shorten the barrel of \the [src]!"
+ user.visible_message("The shotgun goes off!", "The shotgun goes off in your face!")
+ return
+ if(do_after(user, 30)) //SHIT IS STEALTHY EYYYYY
+ icon_state = "sawnshotgun"
+ w_class = 3
+ item_state = "gun"
+ slot_flags &= ~SLOT_BACK //you can't sling it on your back
+ slot_flags |= (SLOT_BELT|SLOT_HOLSTER) //but you can wear it on your belt (poorly concealed under a trenchcoat, ideally) - or in a holster, why not.
+ name = "sawn-off shotgun"
+ desc = "Omar's coming!"
+ user << "You shorten the barrel of \the [src]!"
+ else
+ ..()
\ No newline at end of file
diff --git a/code/modules/projectiles/guns/projectile/sniper.dm b/code/modules/projectiles/guns/projectile/sniper.dm
new file mode 100644
index 0000000000..4bab0678b7
--- /dev/null
+++ b/code/modules/projectiles/guns/projectile/sniper.dm
@@ -0,0 +1,67 @@
+/obj/item/weapon/gun/projectile/heavysniper
+ name = "\improper PTRS-7 rifle"
+ desc = "A portable anti-armour rifle fitted with a scope. Originally designed to used against lightly armoured exosuits, it is capable of punching through non-reinforced walls with ease. Fires 14.5mm AP shells."
+ icon_state = "heavysniper"
+ item_state = "sniper0"
+ w_class = 4
+ force = 10
+ slot_flags = SLOT_BACK
+ origin_tech = "combat=8;materials=2;syndicate=8"
+ caliber = "14.5mm"
+ recoil = 2 //extra kickback
+ //fire_sound = 'sound/weapons/sniper.ogg'
+ handle_casings = HOLD_CASINGS
+ load_method = SINGLE_CASING
+ max_shells = 1
+ ammo_type = /obj/item/ammo_casing/a145
+ //+2 accuracy over the LWAP because only one shot
+ accuracy = -1
+ scoped_accuracy = 2
+ var/bolt_open = 0
+
+/obj/item/weapon/gun/projectile/heavysniper/update_icon()
+ if(bolt_open)
+ icon_state = "heavysniper-open"
+ else
+ icon_state = "heavysniper"
+
+/obj/item/weapon/gun/projectile/heavysniper/attack_self(mob/user as mob)
+ playsound(src.loc, 'sound/weapons/flipblade.ogg', 50, 1)
+ bolt_open = !bolt_open
+ if(bolt_open)
+ if(chambered)
+ user << "You work the bolt open, ejecting [chambered]!"
+ chambered.loc = get_turf(src)
+ loaded -= chambered
+ chambered = null
+ else
+ user << "You work the bolt open."
+ else
+ user << "You work the bolt closed."
+ bolt_open = 0
+ add_fingerprint(user)
+ update_icon()
+
+/obj/item/weapon/gun/projectile/heavysniper/special_check(mob/user)
+ if(bolt_open)
+ user << "You can't fire [src] while the bolt is open!"
+ return 0
+ return ..()
+
+/obj/item/weapon/gun/projectile/heavysniper/load_ammo(var/obj/item/A, mob/user)
+ if(!bolt_open)
+ return
+ ..()
+
+/obj/item/weapon/gun/projectile/heavysniper/unload_ammo(mob/user, var/allow_dump=1)
+ if(!bolt_open)
+ return
+ ..()
+
+/obj/item/weapon/gun/projectile/heavysniper/verb/scope()
+ set category = "Object"
+ set name = "Use Scope"
+ set popup_menu = 1
+
+ toggle_scope(2.0)
+
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index 0ca1ab93fc..6176a48569 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -37,7 +37,7 @@
var/damage_type = BRUTE //BRUTE, BURN, TOX, OXY, CLONE are the only things that should be in here
var/nodamage = 0 //Determines if the projectile will skip any damage inflictions
var/taser_effect = 0 //If set then the projectile will apply it's agony damage using stun_effect_act() to mobs it hits, and other damage will be ignored
- var/flag = "bullet" //Defines what armor to use when it hits things. Must be set to bullet, laser, energy,or bomb //Cael - bio and rad are also valid
+ var/check_armour = "bullet" //Defines what armor to use when it hits things. Must be set to bullet, laser, energy,or bomb //Cael - bio and rad are also valid
var/projectile_type = /obj/item/projectile
var/penetrating = 0 //If greater than zero, the projectile will pass through dense objects as specified by on_penetrate()
var/kill_count = 50 //This will de-increment every process(). When 0, it will delete the projectile.
@@ -69,20 +69,19 @@
/obj/item/projectile/proc/on_penetrate(var/atom/A)
return 1
-/obj/item/projectile/proc/check_fire(var/mob/living/target as mob, var/mob/living/user as mob) //Checks if you can hit them or not.
- if(!istype(target) || !istype(user))
- return 0
- var/obj/item/projectile/test/in_chamber = new /obj/item/projectile/test(get_step_to(user,target)) //Making the test....
- in_chamber.target = target
- in_chamber.flags = flags //Set the flags...
- in_chamber.pass_flags = pass_flags //And the pass flags to that of the real projectile...
- in_chamber.firer = user
- var/output = in_chamber.process() //Test it!
- del(in_chamber) //No need for it anymore
- return output //Send it back to the gun!
+/obj/item/projectile/proc/check_fire(atom/target as mob, var/mob/living/user as mob) //Checks if you can hit them or not.
+ check_trajectory(target, user, pass_flags, flags)
+
+//sets the click point of the projectile using mouse input params
+/obj/item/projectile/proc/set_clickpoint(var/params)
+ var/list/mouse_control = params2list(params)
+ if(mouse_control["icon-x"])
+ p_x = text2num(mouse_control["icon-x"])
+ if(mouse_control["icon-y"])
+ p_y = text2num(mouse_control["icon-y"])
//called to launch a projectile from a gun
-/obj/item/projectile/proc/launch(atom/target, mob/user, obj/item/weapon/gun/launcher, var/target_zone, var/x_offset=0, var/y_offset=0, var/px=null, var/py=null)
+/obj/item/projectile/proc/launch(atom/target, mob/user, obj/item/weapon/gun/launcher, var/target_zone, var/x_offset=0, var/y_offset=0)
var/turf/curloc = get_turf(user)
var/turf/targloc = get_turf(target)
if (!istype(targloc) || !istype(curloc))
@@ -93,10 +92,12 @@
if(user == target) //Shooting yourself
user.bullet_act(src, target_zone)
+ on_impact(user)
del(src)
return 0
- if(targloc == curloc) //Shooting the ground
- targloc.bullet_act(src, target_zone)
+ if(targloc == curloc) //Shooting something in the same turf
+ target.bullet_act(src, target_zone)
+ on_impact(target)
del(src)
return 0
@@ -106,8 +107,6 @@
current = curloc
yo = targloc.y - curloc.y + y_offset
xo = targloc.x - curloc.x + x_offset
- if(!isnull(py)) p_y = py
- if(!isnull(px)) p_x = px
shot_from = launcher
silenced = launcher.silenced
@@ -129,15 +128,16 @@
xo = new_x - starting_loc.x
//Called when the projectile intercepts a mob. Returns 1 if the projectile hit the mob, 0 if it missed and should keep flying.
-/obj/item/projectile/proc/attack_mob(var/mob/living/target_mob, var/distance, var/miss_modifier = -30)
+/obj/item/projectile/proc/attack_mob(var/mob/living/target_mob, var/distance, var/miss_modifier)
//accuracy bonus from aiming
if (istype(shot_from, /obj/item/weapon/gun)) //If you aim at someone beforehead, it'll hit more often.
var/obj/item/weapon/gun/daddy = shot_from //Kinda balanced by fact you need like 2 seconds to aim
- if (daddy.target && original in daddy.target) //As opposed to no-delay pew pew
+ miss_modifier -= round(15*daddy.accuracy)
+ if (daddy.aim_targets && original in daddy.aim_targets) //As opposed to no-delay pew pew
miss_modifier += -30
//roll to-hit
- var/hit_zone = get_zone_with_miss_chance(def_zone, target_mob, max(miss_modifier + 15*distance, 0))
+ var/hit_zone = get_zone_with_miss_chance(def_zone, target_mob, max(miss_modifier + 15*(distance-2), 0))
if(!hit_zone)
visible_message("\The [src] misses [target_mob] narrowly!")
return 0
@@ -228,10 +228,10 @@
return 1
/obj/item/projectile/process()
- if(kill_count < 1)
- del(src)
- kill_count--
spawn while(src)
+ if(kill_count-- < 1)
+ on_impact(src.loc) //for any final impact behaviours
+ del(src)
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))
@@ -244,7 +244,8 @@
if(!(original in permutated))
Bump(original)
sleep(1)
-
+
+//"Tracing" projectile
/obj/item/projectile/test //Used to see if you can hit them.
invisibility = 101 //Nope! Can't see me!
yo = null
@@ -285,3 +286,16 @@
M = locate() in get_step(src,target)
if(istype(M))
return 1
+
+/proc/check_trajectory(atom/target as mob, var/mob/living/user as mob, var/pass_flags=PASSTABLE|PASSGLASS|PASSGRILLE, flags=null) //Checks if you can hit them or not.
+ if(!istype(target) || !istype(user))
+ return 0
+ var/obj/item/projectile/test/trace = new /obj/item/projectile/test(get_step_to(user,target)) //Making the test....
+ trace.target = target
+ if(!isnull(flags))
+ trace.flags = flags //Set the flags...
+ trace.pass_flags = pass_flags //And the pass flags to that of the real projectile...
+ trace.firer = user
+ var/output = trace.process() //Test it!
+ del(trace) //No need for it anymore
+ return output //Send it back to the gun!
\ No newline at end of file
diff --git a/code/modules/projectiles/projectile/animate.dm b/code/modules/projectiles/projectile/animate.dm
index 490227d233..0f92729ad4 100644
--- a/code/modules/projectiles/projectile/animate.dm
+++ b/code/modules/projectiles/projectile/animate.dm
@@ -4,7 +4,7 @@
damage = 0
damage_type = BURN
nodamage = 1
- flag = "energy"
+ check_armour = "energy"
/obj/item/projectile/animate/Bump(var/atom/change)
if((istype(change, /obj/item) || istype(change, /obj/structure)) && !is_type_in_list(change, protected_objects))
diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm
index 23ee20e132..b5ce31b168 100644
--- a/code/modules/projectiles/projectile/beams.dm
+++ b/code/modules/projectiles/projectile/beams.dm
@@ -14,7 +14,7 @@ var/list/beam_master = list()
pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
damage = 40
damage_type = BURN
- flag = "laser"
+ check_armour = "laser"
eyeblur = 4
var/frequency = 1
@@ -87,7 +87,7 @@ var/list/beam_master = list()
pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
damage = 0
damage_type = BURN
- flag = "laser"
+ check_armour = "laser"
eyeblur = 2
/obj/item/projectile/beam/heavylaser
@@ -121,7 +121,7 @@ var/list/beam_master = list()
pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
damage = 0
damage_type = BURN
- flag = "laser"
+ check_armour = "laser"
/obj/item/projectile/beam/lastertag/blue/on_hit(var/atom/target, var/blocked = 0)
if(istype(target, /mob/living/carbon/human))
@@ -136,7 +136,7 @@ var/list/beam_master = list()
pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
damage = 0
damage_type = BURN
- flag = "laser"
+ check_armour = "laser"
/obj/item/projectile/beam/lastertag/red/on_hit(var/atom/target, var/blocked = 0)
if(istype(target, /mob/living/carbon/human))
@@ -151,7 +151,7 @@ var/list/beam_master = list()
pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
damage = 0
damage_type = BURN
- flag = "laser"
+ check_armour = "laser"
/obj/item/projectile/beam/lastertag/omni/on_hit(var/atom/target, var/blocked = 0)
if(istype(target, /mob/living/carbon/human))
@@ -164,9 +164,9 @@ var/list/beam_master = list()
name = "sniper beam"
icon_state = "xray"
damage = 60
- stun = 5
- weaken = 5
- stutter = 5
+ stun = 3
+ weaken = 3
+ stutter = 3
/obj/item/projectile/beam/stun
name = "stun beam"
diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm
index 5da27e9ef0..e473a11405 100644
--- a/code/modules/projectiles/projectile/bullets.dm
+++ b/code/modules/projectiles/projectile/bullets.dm
@@ -4,7 +4,7 @@
damage = 60
damage_type = BRUTE
nodamage = 0
- flag = "bullet"
+ check_armour = "bullet"
embed = 1
sharp = 1
@@ -21,27 +21,27 @@
if(ismob(A))
if(iscarbon(A))
- //squishy mobs absorb KE
- if (damage <= 20) return 0
- damage *= 0.7
+ if (damage <= 20 && !prob(damage)) return 0
+ damage *= 0.7 //squishy mobs absorb KE
return 1
- if(istype(A, /obj/machinery) || istype(A, /obj/structure))
- var/chance = 15
- if(istype(A, /turf/simulated/wall))
- var/turf/simulated/wall/W = A
- chance = round(damage/W.damage_cap*100)
- else if(istype(A, /obj/machinery/door))
- var/obj/machinery/door/D = A
- chance = round(damage/D.maxhealth*100)
- else if(istype(A, /obj/structure/girder) || istype(A, /obj/structure/cultgirder))
- chance = 100
-
- if(prob(chance))
- if(A.opacity)
- //display a message so that people on the other side aren't so confused
- A.visible_message("\The [src] pierces through \the [A]!")
- return 1
+ var/chance = 0
+ if(istype(A, /turf/simulated/wall))
+ var/turf/simulated/wall/W = A
+ chance = round(damage/W.damage_cap*180)
+ else if(istype(A, /obj/machinery/door))
+ var/obj/machinery/door/D = A
+ chance = round(damage/D.maxhealth*100)
+ else if(istype(A, /obj/structure/girder) || istype(A, /obj/structure/cultgirder))
+ chance = 100
+ else if(istype(A, /obj/machinery) || istype(A, /obj/structure))
+ chance = 15
+
+ if(prob(chance))
+ if(A.opacity)
+ //display a message so that people on the other side aren't so confused
+ A.visible_message("\The [src] pierces through \the [A]!")
+ return 1
return 0
@@ -122,10 +122,13 @@
/* "Rifle" rounds */
/obj/item/projectile/bullet/rifle/a762
- damage = 25
+ damage = 30
+ penetrating = 1
/obj/item/projectile/bullet/rifle/a145
- damage = 90
+ damage = 80
+ stun = 3
+ weaken = 3
penetrating = 5
/* Miscellaneous */
diff --git a/code/modules/projectiles/projectile/change.dm b/code/modules/projectiles/projectile/change.dm
index 215c117342..24e2d4b6ef 100644
--- a/code/modules/projectiles/projectile/change.dm
+++ b/code/modules/projectiles/projectile/change.dm
@@ -4,7 +4,7 @@
damage = 0
damage_type = BURN
nodamage = 1
- flag = "energy"
+ check_armour = "energy"
on_hit(var/atom/change)
wabbajack(change)
diff --git a/code/modules/projectiles/projectile/energy.dm b/code/modules/projectiles/projectile/energy.dm
index 851f691b41..2a114e9067 100644
--- a/code/modules/projectiles/projectile/energy.dm
+++ b/code/modules/projectiles/projectile/energy.dm
@@ -3,37 +3,42 @@
icon_state = "spark"
damage = 0
damage_type = BURN
- flag = "energy"
+ check_armour = "energy"
-//releases a very short burst of light on impact, mainly used to blind people
+//releases a burst of light on impact or after travelling a distance
/obj/item/projectile/energy/flash
- name = "shell" //a chemical filled shell or something
+ name = "chemical shell"
icon_state = "bullet"
damage = 5
- var/flash_range = 1
- var/brightness = 5
- var/light_duration = 10
-
-/obj/item/projectile/energy/flash/on_impact()
- var/turf/T = get_turf(src)
+ kill_count = 15 //if the shell hasn't hit anything after travelling this far it just explodes.
+ var/flash_range = 0
+ var/brightness = 7
+ var/light_duration = 5
+/obj/item/projectile/energy/flash/on_impact(var/atom/A)
+ var/turf/T = flash_range? src.loc : get_turf(A)
if(!istype(T)) return
- src.visible_message("\The [src] explodes in a bright flash!")
+ //blind adjacent people
for (var/mob/living/carbon/M in viewers(T, flash_range))
if(M.eyecheck() < 1)
flick("e_flash", M.flash)
+ //snap pop
playsound(src, 'sound/effects/snap.ogg', 50, 1)
- new/obj/effect/effect/smoke/illumination(src.loc, brightness=max(flash_range*2, brightness), lifetime=light_duration)
+ src.visible_message("\The [src] explodes in a bright flash!")
+
+ new /obj/effect/decal/cleanable/ash(src.loc) //always use src.loc so that ash doesn't end up inside windows
+ new /obj/effect/effect/sparks(T)
+ new /obj/effect/effect/smoke/illumination(T, brightness=max(flash_range*2, brightness), lifetime=light_duration)
//blinds people like the flash round, but can also be used for temporary illumination
/obj/item/projectile/energy/flash/flare
damage = 10
flash_range = 1
- brightness = 7 //similar to a flare
- light_duration = 150
+ brightness = 9 //similar to a flare
+ light_duration = 200
/obj/item/projectile/energy/electrode
name = "electrode"
diff --git a/code/modules/projectiles/projectile/force.dm b/code/modules/projectiles/projectile/force.dm
index 4dffe4ce89..71b7d34d04 100644
--- a/code/modules/projectiles/projectile/force.dm
+++ b/code/modules/projectiles/projectile/force.dm
@@ -3,7 +3,7 @@
icon = 'icons/obj/projectiles.dmi'
icon_state = "ice_1"
damage = 20
- flag = "energy"
+ check_armour = "energy"
/obj/item/projectile/forcebolt/strong
name = "force bolt"
diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm
index c7c2c05c4a..fc69f6ec94 100644
--- a/code/modules/projectiles/projectile/special.dm
+++ b/code/modules/projectiles/projectile/special.dm
@@ -4,7 +4,7 @@
damage = 0
damage_type = BURN
nodamage = 1
- flag = "energy"
+ check_armour = "energy"
on_hit(var/atom/target, var/blocked = 0)
@@ -16,7 +16,7 @@
name ="explosive bolt"
icon_state= "bolter"
damage = 50
- flag = "bullet"
+ check_armour = "bullet"
sharp = 1
edge = 1
@@ -30,7 +30,7 @@
damage = 0
damage_type = BURN
nodamage = 1
- flag = "energy"
+ check_armour = "energy"
var/temperature = 300
@@ -47,7 +47,7 @@
damage = 0
damage_type = BRUTE
nodamage = 1
- flag = "bullet"
+ check_armour = "bullet"
Bump(atom/A as mob|obj|turf|area)
if(A == firer)
@@ -76,7 +76,7 @@
damage = 0
damage_type = TOX
nodamage = 1
- flag = "energy"
+ check_armour = "energy"
on_hit(var/atom/target, var/blocked = 0)
var/mob/living/M = target
@@ -115,7 +115,7 @@
damage = 0
damage_type = TOX
nodamage = 1
- flag = "energy"
+ check_armour = "energy"
on_hit(var/atom/target, var/blocked = 0)
var/mob/M = target
diff --git a/code/modules/projectiles/targeting.dm b/code/modules/projectiles/targeting.dm
index 496455f24e..c3988ff2ff 100644
--- a/code/modules/projectiles/targeting.dm
+++ b/code/modules/projectiles/targeting.dm
@@ -1,10 +1,10 @@
/obj/item/weapon/gun/verb/toggle_firerate()
- set name = "Toggle Firerate"
+ set name = "Toggle Continue Aiming"
set category = "Object"
- firerate = !firerate
+ keep_aim = !keep_aim
- if (firerate)
+ if (keep_aim)
loc << "You will now continue firing when your target moves."
else
loc << "You will now only fire once, then lower your aim, when your target moves."
@@ -12,7 +12,7 @@
/obj/item/weapon/gun/verb/lower_aim()
set name = "Lower Aim"
set category = "Object"
- if(target)
+ if(aim_targets)
stop_aim()
usr.visible_message("\blue \The [usr] lowers \the [src]...")
@@ -34,13 +34,13 @@
user.client.remove_gun_icons()
return ..()
-//Removes lock fro mall targets
+//Removes lock from all targets
/obj/item/weapon/gun/proc/stop_aim()
- if(target)
- for(var/mob/living/M in target)
+ if(aim_targets)
+ for(var/mob/living/M in aim_targets)
if(M)
M.NotTargeted(src) //Untargeting people.
- del(target)
+ del(aim_targets)
//Compute how to fire.....
//Return 1 if a target was found, 0 otherwise.
@@ -49,13 +49,13 @@
if(lock_time > world.time - 2) return
user.set_dir(get_cardinal_dir(src, A))
- if(isliving(A) && !(A in target))
+ if(isliving(A) && !(A in aim_targets))
Aim(A) //Clicked a mob, aim at them
return 1
//Didn't click someone, check if there is anyone along that guntrace
var/mob/living/M = GunTrace(usr.x,usr.y,A.x,A.y,usr.z,usr) //Find dat mob.
- if(isliving(M) && (M in view(user)) && !(M in target))
+ if(isliving(M) && (M in view(user)) && !(M in aim_targets))
Aim(M) //Aha! Aim at them!
return 1
@@ -63,13 +63,13 @@
//Aiming at the target mob.
/obj/item/weapon/gun/proc/Aim(var/mob/living/M)
- if(!target || !(M in target))
+ if(!aim_targets || !(M in aim_targets))
lock_time = world.time
- if(target && !automatic) //If they're targeting someone and they have a non automatic weapon.
- for(var/mob/living/L in target)
+ if(aim_targets && !multi_aim) //If they're targeting someone and they have a non multi_aim weapon.
+ for(var/mob/living/L in aim_targets)
if(L)
L.NotTargeted(src)
- del(target)
+ del(aim_targets)
usr.visible_message("\red [usr] turns \the [src] on [M]!")
else
usr.visible_message("\red [usr] aims \a [src] at [M]!")
@@ -90,29 +90,26 @@
return
M.last_move_intent = world.time
- if(can_fire())
- var/firing_check = can_hit(T,usr) //0 if it cannot hit them, 1 if it is capable of hitting, and 2 if a special check is preventing it from firing.
- if(firing_check > 0)
- if(firing_check == 1)
- Fire(T,usr, reflex = 1)
- else if(!told_cant_shoot)
- M << "\red They can't be hit from here!"
- told_cant_shoot = 1
- spawn(30)
- told_cant_shoot = 0
- else
- click_empty(M)
+ var/firing_check = can_hit(T,usr) //0 if it cannot hit them, 1 if it is capable of hitting, and 2 if a special check is preventing it from firing.
+ if(firing_check > 0)
+ if(firing_check == 1)
+ Fire(T,usr, reflex = 1)
+ else if(!told_cant_shoot)
+ M << "\red They can't be hit from here!"
+ told_cant_shoot = 1
+ spawn(30)
+ told_cant_shoot = 0
usr.set_dir(get_cardinal_dir(src, T))
- if (!firerate) // If firerate is set to lower aim after one shot, untarget the target
+ if (!keep_aim) // If keep_aim is set to lower aim after one shot, untarget the target
T.NotTargeted(src)
//Yay, math!
#define SIGN(X) ((X<0)?-1:1)
-proc/GunTrace(X1,Y1,X2,Y2,Z=1,exc_obj,PX1=16,PY1=16,PX2=16,PY2=16)
+/proc/GunTrace(X1,Y1,X2,Y2,Z=1,exc_obj,PX1=16,PY1=16,PX2=16,PY2=16)
//bluh << "Tracin' [X1],[Y1] to [X2],[Y2] on floor [Z]."
var/turf/T
var/mob/living/M
@@ -150,19 +147,19 @@ proc/GunTrace(X1,Y1,X2,Y2,Z=1,exc_obj,PX1=16,PY1=16,PX2=16,PY2=16)
//Targeting management procs
-mob/var
+/mob/var
list/targeted_by
target_time = -100
last_move_intent = -100
last_target_click = -5
target_locked = null
-mob/living/proc/Targeted(var/obj/item/weapon/gun/I) //Self explanitory.
- if(!I.target)
- I.target = list(src)
- else if(I.automatic && I.target.len < 5) //Automatic weapon, they can hold down a room.
- I.target += src
- else if(I.target.len >= 5)
+/mob/living/proc/Targeted(var/obj/item/weapon/gun/I) //Self explanitory.
+ if(!I.aim_targets)
+ I.aim_targets = list(src)
+ else if(I.multi_aim && I.aim_targets.len < 5) //multi_aim weapon, they can hold down a room.
+ I.aim_targets += src
+ else if(I.aim_targets.len >= 5)
if(ismob(I.loc))
I.loc << "You can only target 5 people at once!"
return
@@ -223,43 +220,43 @@ mob/living/proc/Targeted(var/obj/item/weapon/gun/I) //Self explanitory.
I.last_moved_mob = src
sleep(1)
-mob/living/proc/NotTargeted(var/obj/item/weapon/gun/I)
+/mob/living/proc/NotTargeted(var/obj/item/weapon/gun/I)
if(!I.silenced)
for(var/mob/living/M in viewers(src))
M << 'sound/weapons/TargetOff.ogg'
targeted_by -= I
- I.target.Remove(src) //De-target them
- if(!I.target.len)
- del(I.target)
+ I.aim_targets.Remove(src) //De-target them
+ if(!I.aim_targets.len)
+ del(I.aim_targets)
var/mob/living/T = I.loc //Remove the targeting icons
- if(T && ismob(T) && !I.target)
+ if(T && ismob(T) && !I.aim_targets)
T.client.remove_gun_icons()
if(!targeted_by.len)
del target_locked //Remove the overlay
del targeted_by
spawn(1) update_targeted()
-mob/living/Move()
+/mob/living/Move()
. = ..()
for(var/obj/item/weapon/gun/G in targeted_by) //Handle moving out of the gunner's view.
var/mob/living/M = G.loc
if(!(M in view(src)))
NotTargeted(G)
for(var/obj/item/weapon/gun/G in src) //Handle the gunner loosing sight of their target/s
- if(G.target)
- for(var/mob/living/M in G.target)
+ if(G.aim_targets)
+ for(var/mob/living/M in G.aim_targets)
if(M && !(M in view(src)))
M.NotTargeted(G)
//If you move out of range, it isn't going to still stay locked on you any more.
-client/var
+/client/var
target_can_move = 0
target_can_run = 0
target_can_click = 0
gun_mode = 0
//These are called by the on-screen buttons, adjusting what the victim can and cannot do.
-client/proc/add_gun_icons()
+/client/proc/add_gun_icons()
screen += usr.item_use_icon
screen += usr.gun_move_icon
if (target_can_move)
@@ -267,14 +264,15 @@ client/proc/add_gun_icons()
-client/proc/remove_gun_icons()
+/client/proc/remove_gun_icons()
if(!usr) return 1 // Runtime prevention on N00k agents spawning with SMG
screen -= usr.item_use_icon
screen -= usr.gun_move_icon
if (target_can_move)
screen -= usr.gun_run_icon
-client/verb/ToggleGunMode()
+/client/verb/ToggleGunMode()
+ set name = "Toggle Gun Mode"
set hidden = 1
gun_mode = !gun_mode
if(gun_mode)
@@ -288,7 +286,7 @@ client/verb/ToggleGunMode()
usr.gun_setting_icon.icon_state = "gun[gun_mode]"
-client/verb/AllowTargetMove()
+/client/verb/AllowTargetMove()
set hidden=1
//Changing client's permissions
@@ -310,8 +308,8 @@ client/verb/AllowTargetMove()
//Handling change for all the guns on client
for(var/obj/item/weapon/gun/G in usr)
G.lock_time = world.time + 5
- if(G.target)
- for(var/mob/living/M in G.target)
+ if(G.aim_targets)
+ for(var/mob/living/M in G.aim_targets)
if(target_can_move)
M << "Your character may now walk at the discretion of their targeter."
if(!target_can_run)
@@ -320,7 +318,7 @@ client/verb/AllowTargetMove()
else
M << "\red Your character will now be shot if they move."
-mob/living/proc/set_m_intent(var/intent)
+/mob/living/proc/set_m_intent(var/intent)
if (intent != "walk" && intent != "run")
return 0
m_intent = intent
@@ -346,14 +344,14 @@ client/verb/AllowTargetRun()
//Handling change for all the guns on client
for(var/obj/item/weapon/gun/G in src)
G.lock_time = world.time + 5
- if(G.target)
- for(var/mob/living/M in G.target)
+ if(G.aim_targets)
+ for(var/mob/living/M in G.aim_targets)
if(target_can_run)
M << "Your character may now run at the discretion of their targeter."
else
M << "\red Your character will now be shot if they run."
-client/verb/AllowTargetClick()
+/client/verb/AllowTargetClick()
set hidden=1
//Changing client's permissions
@@ -370,8 +368,8 @@ client/verb/AllowTargetClick()
//Handling change for all the guns on client
for(var/obj/item/weapon/gun/G in src)
G.lock_time = world.time + 5
- if(G.target)
- for(var/mob/living/M in G.target)
+ if(G.aim_targets)
+ for(var/mob/living/M in G.aim_targets)
if(target_can_click)
M << "Your character may now use items at the discretion of their targeter."
else
diff --git a/code/modules/reagents/dartgun.dm b/code/modules/reagents/dartgun.dm
deleted file mode 100644
index d256f4f5f3..0000000000
--- a/code/modules/reagents/dartgun.dm
+++ /dev/null
@@ -1,293 +0,0 @@
-/obj/item/weapon/dart_cartridge
- name = "dart cartridge"
- desc = "A rack of hollow darts."
- icon = 'icons/obj/ammo.dmi'
- icon_state = "darts-5"
- item_state = "rcdammo"
- opacity = 0
- density = 0
- anchored = 0.0
- origin_tech = "materials=2"
- var/darts = 5
-
-/obj/item/weapon/dart_cartridge/update_icon()
- if(!darts)
- icon_state = "darts-0"
- else if(darts > 5)
- icon_state = "darts-5"
- else
- icon_state = "darts-[darts]"
- return 1
-
-/obj/item/weapon/gun/dartgun
- name = "dart gun"
- desc = "A small gas-powered dartgun, capable of delivering chemical cocktails swiftly across short distances."
- icon_state = "dartgun-empty"
-
- var/list/beakers = list() //All containers inside the gun.
- var/list/mixing = list() //Containers being used for mixing.
- var/obj/item/weapon/dart_cartridge/cartridge = null //Container of darts.
- var/max_beakers = 3
- var/dart_reagent_amount = 15
- var/container_type = /obj/item/weapon/reagent_containers/glass/beaker
- var/list/starting_chems = null
-
-/obj/item/weapon/gun/dartgun/update_icon()
-
- if(!cartridge)
- icon_state = "dartgun-empty"
- return 1
-
- if(!cartridge.darts)
- icon_state = "dartgun-0"
- else if(cartridge.darts > 5)
- icon_state = "dartgun-5"
- else
- icon_state = "dartgun-[cartridge.darts]"
- return 1
-
-/obj/item/weapon/gun/dartgun/New()
-
- ..()
- if(starting_chems)
- for(var/chem in starting_chems)
- var/obj/B = new container_type(src)
- B.reagents.add_reagent(chem, 50)
- beakers += B
- cartridge = new /obj/item/weapon/dart_cartridge(src)
- update_icon()
-
-/obj/item/weapon/gun/dartgun/examine(mob/user)
- update_icon()
- if (!..(user, 2))
- return
- if (beakers.len)
- user << "\blue [src] contains:"
- for(var/obj/item/weapon/reagent_containers/glass/beaker/B in beakers)
- if(B.reagents && B.reagents.reagent_list.len)
- for(var/datum/reagent/R in B.reagents.reagent_list)
- user << "\blue [R.volume] units of [R.name]"
-
-/obj/item/weapon/gun/dartgun/attackby(obj/item/I as obj, mob/user as mob)
- if(istype(I, /obj/item/weapon/dart_cartridge))
-
- var/obj/item/weapon/dart_cartridge/D = I
-
- if(!D.darts)
- user << "\blue [D] is empty."
- return 0
-
- if(cartridge)
- if(cartridge.darts <= 0)
- src.remove_cartridge()
- else
- user << "\blue There's already a cartridge in [src]."
- return 0
-
- user.drop_item()
- cartridge = D
- D.loc = src
- user << "\blue You slot [D] into [src]."
- update_icon()
- return
- if(istype(I, /obj/item/weapon/reagent_containers/glass))
- if(!istype(I, container_type))
- user << "\blue [I] doesn't seem to fit into [src]."
- return
- if(beakers.len >= max_beakers)
- user << "\blue [src] already has [max_beakers] beakers in it - another one isn't going to fit!"
- return
- var/obj/item/weapon/reagent_containers/glass/beaker/B = I
- user.drop_item()
- B.loc = src
- beakers += B
- user << "\blue You slot [B] into [src]."
- src.updateUsrDialog()
-
-/obj/item/weapon/gun/dartgun/can_fire()
- if(!cartridge)
- return 0
- else
- return cartridge.darts
-
-/obj/item/weapon/gun/dartgun/proc/has_selected_beaker_reagents()
- return 0
-
-/obj/item/weapon/gun/dartgun/proc/remove_cartridge()
- if(cartridge)
- usr << "\blue You pop the cartridge out of [src]."
- var/obj/item/weapon/dart_cartridge/C = cartridge
- C.loc = get_turf(src)
- C.update_icon()
- cartridge = null
- src.update_icon()
-
-/obj/item/weapon/gun/dartgun/proc/get_mixed_syringe()
- if (!cartridge)
- return 0
- if(!cartridge.darts)
- return 0
-
- var/obj/item/weapon/reagent_containers/syringe/dart = new(src)
-
- if(mixing.len)
- var/mix_amount = dart_reagent_amount/mixing.len
- for(var/obj/item/weapon/reagent_containers/glass/beaker/B in mixing)
- B.reagents.trans_to(dart,mix_amount)
-
- return dart
-
-/obj/item/weapon/gun/dartgun/proc/fire_dart(atom/target, mob/user)
- if (locate (/obj/structure/table, src.loc))
- return
- else
- var/turf/trg = get_turf(target)
- var/obj/effect/syringe_gun_dummy/D = new/obj/effect/syringe_gun_dummy(get_turf(src))
- var/obj/item/weapon/reagent_containers/syringe/S = get_mixed_syringe()
- if(!S)
- user << "\red There are no darts in [src]!"
- return
- if(!S.reagents)
- user << "\red There are no reagents available!"
- return
- cartridge.darts--
- src.update_icon()
- S.reagents.trans_to(D, S.reagents.total_volume)
- del(S)
- D.icon_state = "syringeproj"
- D.name = "syringe"
- D.flags |= NOREACT
- playsound(user.loc, 'sound/items/syringeproj.ogg', 50, 1)
-
- for(var/i=0, i<6, i++)
- if(!D) break
- if(D.loc == trg) break
- step_towards(D,trg)
-
- if(D)
- for(var/mob/living/carbon/M in D.loc)
- if(!istype(M,/mob/living/carbon)) continue
- if(M == user) continue
- //Syringe gun attack logging by Yvarov
- var/R
- if(D.reagents)
- for(var/datum/reagent/A in D.reagents.reagent_list)
- R += A.id + " ("
- R += num2text(A.volume) + "),"
- if (istype(M, /mob))
- M.attack_log += "\[[time_stamp()]\] [user]/[user.ckey] shot [M]/[M.ckey] with a dartgun ([R])"
- user.attack_log += "\[[time_stamp()]\] [user]/[user.ckey] shot [M]/[M.ckey] with a dartgun ([R])"
- msg_admin_attack("[user] ([user.ckey]) shot [M] ([M.ckey]) with a dartgun ([R]) (JMP)")
-
- else
- M.attack_log += "\[[time_stamp()]\] UNKNOWN SUBJECT (No longer exists) shot [M]/[M.ckey] with a dartgun ([R])"
- msg_admin_attack("UNKNOWN shot [M] ([M.ckey]) with a dartgun ([R]) (JMP)")
-
- if(D.reagents)
- D.reagents.trans_to(M, 15)
- M << "You feel a slight prick."
-
- del(D)
- break
- if(D)
- for(var/atom/A in D.loc)
- if(A == user) continue
- if(A.density) del(D)
-
- sleep(1)
-
- if (D) spawn(10) del(D)
-
- return
-
-/obj/item/weapon/gun/dartgun/afterattack(obj/target, mob/user , flag)
- if(!isturf(target.loc) || target == user) return
- ..()
-
-/obj/item/weapon/gun/dartgun/can_hit(var/mob/living/target as mob, var/mob/living/user as mob)
- return 1
-
-/obj/item/weapon/gun/dartgun/attack_self(mob/user)
-
- user.set_machine(src)
- var/dat = "[src] mixing control:
"
-
- if (beakers.len)
- var/i = 1
- for(var/obj/item/weapon/reagent_containers/glass/beaker/B in beakers)
- dat += "Beaker [i] contains: "
- if(B.reagents && B.reagents.reagent_list.len)
- for(var/datum/reagent/R in B.reagents.reagent_list)
- dat += "
[R.volume] units of [R.name], "
- if (check_beaker_mixing(B))
- dat += text("Mixing ")
- else
- dat += text("Not mixing ")
- else
- dat += "nothing."
- dat += " \[Eject\]
"
- i++
- else
- dat += "There are no beakers inserted!
"
-
- if(cartridge)
- if(cartridge.darts)
- dat += "The dart cartridge has [cartridge.darts] shots remaining."
- else
- dat += "The dart cartridge is empty!"
- dat += " \[Eject\]"
-
- user << browse(dat, "window=dartgun")
- onclose(user, "dartgun", src)
-
-/obj/item/weapon/gun/dartgun/proc/check_beaker_mixing(var/obj/item/B)
- if(!mixing || !beakers)
- return 0
- for(var/obj/item/M in mixing)
- if(M == B)
- return 1
- return 0
-
-/obj/item/weapon/gun/dartgun/Topic(href, href_list)
- src.add_fingerprint(usr)
- if(href_list["stop_mix"])
- var/index = text2num(href_list["stop_mix"])
- if(index <= beakers.len)
- for(var/obj/item/M in mixing)
- if(M == beakers[index])
- mixing -= M
- break
- else if (href_list["mix"])
- var/index = text2num(href_list["mix"])
- if(index <= beakers.len)
- mixing += beakers[index]
- else if (href_list["eject"])
- var/index = text2num(href_list["eject"])
- if(index <= beakers.len)
- if(beakers[index])
- var/obj/item/weapon/reagent_containers/glass/beaker/B = beakers[index]
- usr << "You remove [B] from [src]."
- mixing -= B
- beakers -= B
- B.loc = get_turf(src)
- else if (href_list["eject_cart"])
- remove_cartridge()
- src.updateUsrDialog()
- return
-
-/obj/item/weapon/gun/dartgun/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0)
- if(cartridge)
- spawn(0) fire_dart(target,user)
- else
- usr << "\red [src] is empty."
-
-
-/obj/item/weapon/gun/dartgun/vox
- name = "alien dart gun"
- desc = "A small gas-powered dartgun, fitted for nonhuman hands."
-
-/obj/item/weapon/gun/dartgun/vox/medical
- starting_chems = list("kelotane","bicaridine","anti_toxin")
-
-/obj/item/weapon/gun/dartgun/vox/raider
- starting_chems = list("space_drugs","stoxin","impedrezene")
\ No newline at end of file
diff --git a/code/modules/reagents/grenade_launcher.dm b/code/modules/reagents/grenade_launcher.dm
deleted file mode 100644
index b96455a178..0000000000
--- a/code/modules/reagents/grenade_launcher.dm
+++ /dev/null
@@ -1,63 +0,0 @@
-
-
-/obj/item/weapon/gun/grenadelauncher
- name = "grenade launcher"
- icon = 'icons/obj/gun.dmi'
- icon_state = "riotgun"
- item_state = "riotgun"
- w_class = 4.0
- throw_speed = 2
- throw_range = 10
- force = 5.0
- var/list/grenades = new/list()
- var/max_grenades = 3
- matter = list("metal" = 2000)
-
- examine(mob/user)
- if(..(user, 2))
- user << "\blue [grenades] / [max_grenades] Grenades."
-
- attackby(obj/item/I as obj, mob/user as mob)
-
- if((istype(I, /obj/item/weapon/grenade)))
- if(grenades.len < max_grenades)
- user.drop_item()
- I.loc = src
- grenades += I
- user << "\blue You put the grenade in the grenade launcher."
- user << "\blue [grenades.len] / [max_grenades] Grenades."
- else
- usr << "\red The grenade launcher cannot hold more grenades."
-
- afterattack(obj/target, mob/user , flag)
-
- if (istype(target, /obj/item/weapon/storage/backpack ))
- return
-
- else if (locate (/obj/structure/table, src.loc))
- return
-
- else if(target == user)
- return
-
- if(grenades.len)
- spawn(0) fire_grenade(target,user)
- else
- usr << "\red The grenade launcher is empty."
-
- proc
- fire_grenade(atom/target, mob/user)
- for(var/mob/O in viewers(world.view, user))
- O.show_message(text("\red [] fired a grenade!", user), 1)
- user << "\red You fire the grenade launcher!"
- var/obj/item/weapon/grenade/chem_grenade/F = grenades[1] //Now with less copypasta!
- grenades -= F
- F.loc = user.loc
- F.throw_at(target, 30, 2, user)
- message_admins("[key_name_admin(user)] fired a grenade ([F.name]) from a grenade launcher ([src.name]).")
- log_game("[key_name_admin(user)] used a grenade ([src.name]).")
- F.active = 1
- F.icon_state = initial(icon_state) + "_active"
- playsound(user.loc, 'sound/weapons/armbomb.ogg', 75, 1, -3)
- spawn(15)
- F.prime()
\ No newline at end of file
diff --git a/code/modules/reagents/reagent_containers/food/snacks/grown.dm b/code/modules/reagents/reagent_containers/food/snacks/grown.dm
index b57a4d5562..c59a5f9f7c 100644
--- a/code/modules/reagents/reagent_containers/food/snacks/grown.dm
+++ b/code/modules/reagents/reagent_containers/food/snacks/grown.dm
@@ -337,6 +337,7 @@
icon = 'icons/obj/items.dmi'
icon_state = "banana"
item_state = "banana"
+ slot_flags = SLOT_HOLSTER
filling_color = "#FCF695"
trash = /obj/item/weapon/bananapeel
plantname = "banana"
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index c1d9b0fdec..8aa34a7dca 100644
--- a/code/modules/reagents/reagent_containers/syringes.dm
+++ b/code/modules/reagents/reagent_containers/syringes.dm
@@ -18,6 +18,7 @@
w_class = 1
sharp = 1
var/mode = SYRINGE_DRAW
+ var/image/filling //holds a reference to the current filling overlay
on_reagent_change()
update_icon()
@@ -217,7 +218,7 @@
item_state = "syringe_[rounded_vol]"
if(reagents.total_volume)
- var/image/filling = image('icons/obj/reagentfillings.dmi', src, "syringe10")
+ filling = image('icons/obj/reagentfillings.dmi', src, "syringe10")
filling.icon_state = "syringe[rounded_vol]"
@@ -225,7 +226,7 @@
overlays += filling
- /obj/item/weapon/reagent_containers/syringe/proc/syringestab(mob/living/carbon/target as mob, mob/living/carbon/user as mob)
+ proc/syringestab(mob/living/carbon/target as mob, mob/living/carbon/user as mob)
user.attack_log += "\[[time_stamp()]\] Attacked [target.name] ([target.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])"
target.attack_log += "\[[time_stamp()]\] Attacked by [user.name] ([user.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])"
@@ -268,13 +269,19 @@
src.reagents.reaction(target, INGEST)
var/syringestab_amount_transferred = rand(0, (reagents.total_volume - 5)) //nerfed by popular demand
src.reagents.trans_to(target, syringestab_amount_transferred)
+ src.break_syringe(target, user)
+
+ proc/break_syringe(mob/living/carbon/target, mob/living/carbon/user)
src.desc += " It is broken."
src.mode = SYRINGE_BROKEN
- src.add_blood(target)
- src.add_fingerprint(usr)
+ if(target)
+ src.add_blood(target)
+ if(user)
+ src.add_fingerprint(user)
src.update_icon()
+
/obj/item/weapon/reagent_containers/ld50_syringe
name = "Lethal Injection Syringe"
desc = "A syringe used for lethal injections."
diff --git a/code/modules/reagents/syringe_gun.dm b/code/modules/reagents/syringe_gun.dm
deleted file mode 100644
index faecb79868..0000000000
--- a/code/modules/reagents/syringe_gun.dm
+++ /dev/null
@@ -1,137 +0,0 @@
-
-
-
-/obj/item/weapon/gun/syringe
- name = "syringe gun"
- desc = "A spring loaded rifle designed to fit syringes, designed to incapacitate unruly patients from a distance."
- icon = 'icons/obj/gun.dmi'
- icon_state = "syringegun"
- item_state = "syringegun"
- w_class = 3.0
- throw_speed = 2
- throw_range = 10
- force = 4.0
- var/list/syringes = new/list()
- var/max_syringes = 1
- matter = list("metal" = 2000)
-
-/obj/item/weapon/gun/syringe/examine(mob/user)
- if(..(user, 2))
- user << "\blue [syringes.len] / [max_syringes] syringes."
-
-/obj/item/weapon/gun/syringe/attackby(obj/item/I as obj, mob/user as mob)
- if(istype(I, /obj/item/weapon/reagent_containers/syringe))
- var/obj/item/weapon/reagent_containers/syringe/S = I
- if(S.mode != 2)//SYRINGE_BROKEN in syringes.dm
- if(syringes.len < max_syringes)
- user.drop_item()
- I.loc = src
- syringes += I
- user << "\blue You put the syringe in [src]."
- user << "\blue [syringes.len] / [max_syringes] syringes."
- else
- usr << "\red [src] cannot hold more syringes."
- else
- usr << "\red This syringe is broken!"
-
-
-/obj/item/weapon/gun/syringe/afterattack(obj/target, mob/user , flag)
- if(!isturf(target.loc) || target == user) return
- ..()
-
-/obj/item/weapon/gun/syringe/can_fire()
- return syringes.len
-
-/obj/item/weapon/gun/syringe/can_hit(var/mob/living/target as mob, var/mob/living/user as mob)
- return 1 //SHOOT AND LET THE GOD GUIDE IT (probably will hit a wall anyway)
-
-/obj/item/weapon/gun/syringe/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0)
- if(syringes.len)
- spawn(0) fire_syringe(target,user)
- else
- usr << "\red [src] is empty."
-
-/obj/item/weapon/gun/syringe/proc/fire_syringe(atom/target, mob/user)
- if (locate (/obj/structure/table, src.loc))
- return
- else
- var/turf/trg = get_turf(target)
- var/obj/effect/syringe_gun_dummy/D = new/obj/effect/syringe_gun_dummy(get_turf(src))
- var/obj/item/weapon/reagent_containers/syringe/S = syringes[1]
- if((!S) || (!S.reagents)) //ho boy! wot runtimes!
- return
- S.reagents.trans_to(D, S.reagents.total_volume)
- syringes -= S
- del(S)
- D.icon_state = "syringeproj"
- D.name = "syringe"
- playsound(user.loc, 'sound/items/syringeproj.ogg', 50, 1)
-
- for(var/i=0, i<6, i++)
- if(!D) break
- if(D.loc == trg) break
- step_towards(D,trg)
-
- if(D)
- for(var/mob/living/carbon/M in D.loc)
- if(!istype(M,/mob/living/carbon)) continue
- if(M == user) continue
- //Syringe gun attack logging by Yvarov
- var/R
- if(D.reagents)
- for(var/datum/reagent/A in D.reagents.reagent_list)
- R += A.id + " ("
- R += num2text(A.volume) + "),"
- if (istype(M, /mob))
- M.attack_log += "\[[time_stamp()]\] [user]/[user.ckey] shot [M]/[M.ckey] with a syringegun ([R])"
- user.attack_log += "\[[time_stamp()]\] [user]/[user.ckey] shot [M]/[M.ckey] with a syringegun ([R])"
- msg_admin_attack("[user] ([user.ckey]) shot [M] ([M.ckey]) with a syringegun ([R]) (JMP)")
-
- else
- M.attack_log += "\[[time_stamp()]\] UNKNOWN SUBJECT (No longer exists) shot [M]/[M.ckey] with a syringegun ([R])"
- msg_admin_attack("UNKNOWN shot [M] ([M.ckey]) with a syringegun ([R]) (JMP)")
-
- var/mob/living/T
- if(istype(M,/mob/living))
- T = M
-
- M.visible_message("[M] is hit by the syringe!")
-
- if(T && istype(T) && T.can_inject())
- if(D.reagents)
- D.reagents.trans_to(M, 15)
- else
- M.visible_message("The syringe bounces off [M]!")
-
- del(D)
- break
- if(D)
- for(var/atom/A in D.loc)
- if(A == user) continue
- if(A.density) del(D)
-
- sleep(1)
-
- if (D) spawn(10) del(D)
-
- return
-
-/obj/item/weapon/gun/syringe/rapidsyringe
- name = "rapid syringe gun"
- desc = "A modification of the syringe gun design, using a rotating cylinder to store up to four syringes."
- icon_state = "rapidsyringegun"
- max_syringes = 4
-
-
-/obj/effect/syringe_gun_dummy
- name = ""
- desc = ""
- icon = 'icons/obj/chemical.dmi'
- icon_state = "null"
- anchored = 1
- density = 0
-
- New()
- var/datum/reagents/R = new/datum/reagents(15)
- reagents = R
- R.my_atom = src
\ No newline at end of file
diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm
index e04618cf20..9083a47e1c 100644
--- a/code/modules/research/designs.dm
+++ b/code/modules/research/designs.dm
@@ -451,7 +451,7 @@ datum/design/circuit/tcom/server
name = "server mainframe"
id = "tcom-server"
build_path = /obj/item/weapon/circuitboard/telecomms/server
-
+
datum/design/circuit/tcom/processor
name = "processor unit"
id = "tcom-processor"
@@ -1312,7 +1312,7 @@ datum/design/item/weapon/rapidsyringe
id = "rapidsyringe"
req_tech = list("combat" = 3, "materials" = 3, "engineering" = 3, "biotech" = 2)
materials = list("$metal" = 5000, "$glass" = 1000)
- build_path = /obj/item/weapon/gun/syringe/rapidsyringe
+ build_path = /obj/item/weapon/gun/launcher/syringe/rapid
/*
datum/design/item/weapon/largecrossbow
name = "Energy Crossbow"
@@ -1567,7 +1567,7 @@ datum/design/item/mesons
req_tech = list("magnets" = 2, "engineering" = 2)
materials = list("$metal" = 50, "$glass" = 50)
build_path = /obj/item/clothing/glasses/meson
-
+
datum/design/item/binaryencrypt
name = "Binary encryption key"
desc = "Allows for deciphering the binary channel on-the-fly."
diff --git a/code/modules/research/xenoarchaeology/finds/finds.dm b/code/modules/research/xenoarchaeology/finds/finds.dm
index 3c2a3dd8e2..b758192bee 100644
--- a/code/modules/research/xenoarchaeology/finds/finds.dm
+++ b/code/modules/research/xenoarchaeology/finds/finds.dm
@@ -367,7 +367,7 @@
item_type = "gun"
if(27)
//revolver
- var/obj/item/weapon/gun/projectile/new_gun = new /obj/item/weapon/gun/projectile(src.loc)
+ var/obj/item/weapon/gun/projectile/new_gun = new /obj/item/weapon/gun/projectile/revolver(src.loc)
new_item = new_gun
new_item.icon_state = "gun[rand(1,4)]"
new_item.icon = 'icons/obj/xenoarchaeology.dmi'
@@ -383,7 +383,7 @@
if(num_bullets < new_gun.loaded.len)
new_gun.loaded.Cut()
for(var/i = 1, i <= num_bullets, i++)
- var/A = text2path(new_gun.ammo_type)
+ var/A = new_gun.ammo_type
new_gun.loaded += new A(new_gun)
else
for(var/obj/item/I in new_gun)
diff --git a/code/setup.dm b/code/setup.dm
index bece6572ca..06235da7fc 100644
--- a/code/setup.dm
+++ b/code/setup.dm
@@ -83,7 +83,7 @@
#define FIRE_MAX_FIRESUIT_STACKS 20 // If the number of stacks goes above this firesuits won't protect you anymore. If not, you can walk around while on fire like a badass.
#define THROWFORCE_SPEED_DIVISOR 5 // The throwing speed value at which the throwforce multiplier is exactly 1.
-#define THROWNOBJ_KNOCKBACK_SPEED 15 // The minumum speed of a thrown object that will cause living mobs it hits to be knocked back.
+#define THROWNOBJ_KNOCKBACK_SPEED 15 // The minumum speed of a w_class 2 thrown object that will cause living mobs it hits to be knocked back. Heavier objects can cause knockback at lower speeds.
#define THROWNOBJ_KNOCKBACK_DIVISOR 2 // Affects how much speed the mob is knocked back with.
#define PRESSURE_DAMAGE_COEFFICIENT 4 // The amount of pressure damage someone takes is equal to (pressure / HAZARD_HIGH_PRESSURE)*PRESSURE_DAMAGE_COEFFICIENT, with the maximum of MAX_PRESSURE_DAMAGE.
@@ -166,6 +166,7 @@
#define SLOT_DENYPOCKET 4096 // This is to deny items with a w_class of 2 or 1 from fitting in pockets.
#define SLOT_TWOEARS 8192
#define SLOT_TIE 16384
+#define SLOT_HOLSTER 32768 //16th bit
// Flags bitmasks.
#define STOPPRESSUREDAMAGE 1 // This flag is used on the flags variable for SUIT and HEAD items which stop pressure damage. Note that the flag 1 was previous used as ONBACK, so it is possible for some code to use (flags & 1) when checking if something can be put on your back. Replace this code with (inv_flags & SLOT_BACK) if you see it anywhere
diff --git a/icons/mob/back.dmi b/icons/mob/back.dmi
index f160af9933..893b58c663 100644
Binary files a/icons/mob/back.dmi and b/icons/mob/back.dmi differ
diff --git a/icons/obj/ammo.dmi b/icons/obj/ammo.dmi
index b6780ecec3..05f0fbaecf 100644
Binary files a/icons/obj/ammo.dmi and b/icons/obj/ammo.dmi differ
diff --git a/icons/obj/gun.dmi b/icons/obj/gun.dmi
index 1e03bbe0b7..dd77da454b 100644
Binary files a/icons/obj/gun.dmi and b/icons/obj/gun.dmi differ
diff --git a/icons/obj/projectiles.dmi b/icons/obj/projectiles.dmi
index 03915794e4..7f3468a363 100644
Binary files a/icons/obj/projectiles.dmi and b/icons/obj/projectiles.dmi differ
diff --git a/icons/obj/syringe.dmi b/icons/obj/syringe.dmi
index 2adc34b05b..a9a46f6046 100644
Binary files a/icons/obj/syringe.dmi and b/icons/obj/syringe.dmi differ
diff --git a/interface/skin.dmf b/interface/skin.dmf
index 8eee4e1817..a8ae16d887 100644
--- a/interface/skin.dmf
+++ b/interface/skin.dmf
@@ -341,6 +341,14 @@ macro "hotkeymode"
name = "CTRL+H"
command = "holster"
is-disabled = false
+ elem
+ name = "J"
+ command = "toggle-gun-mode"
+ is-disabled = false
+ elem
+ name = "CTRL+J"
+ command = "toggle-gun-mode"
+ is-disabled = false
elem
name = "Q"
command = ".northwest"
diff --git a/maps/exodus-1.dmm b/maps/exodus-1.dmm
index 976678d8e4..6139254ec4 100644
--- a/maps/exodus-1.dmm
+++ b/maps/exodus-1.dmm
@@ -5586,7 +5586,7 @@
"cdv" = (/turf/simulated/floor{icon_state = "bcarpet02"},/area/medical/psych)
"cdw" = (/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/turf/simulated/floor{icon_state = "bcarpet03"},/area/medical/psych)
"cdx" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -22},/obj/machinery/light/small{dir = 8},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor{icon_state = "dark"},/area/medical/biostorage)
-"cdy" = (/obj/structure/table,/obj/item/weapon/storage/box/cdeathalarm_kit,/turf/simulated/floor{icon_state = "dark"},/area/medical/biostorage)
+"cdy" = (/obj/structure/table,/obj/item/weapon/storage/box/cdeathalarm_kit,/obj/item/bodybag/cryobag{pixel_x = -3},/obj/item/bodybag/cryobag{pixel_x = -3},/turf/simulated/floor{icon_state = "dark"},/area/medical/biostorage)
"cdz" = (/obj/machinery/firealarm{dir = 1; pixel_y = -24},/obj/structure/closet/secure_closet/personal/patient,/turf/simulated/floor{dir = 10; icon_state = "whitered"},/area/medical/patient_c)
"cdA" = (/obj/machinery/light,/obj/machinery/newscaster{pixel_y = -28},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/machinery/hologram/holopad,/turf/simulated/floor{dir = 3; icon_state = "whitered"},/area/medical/patient_c)
"cdB" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/green{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/turf/simulated/floor/carpet,/area/engineering/break_room)
@@ -5795,7 +5795,7 @@
"chw" = (/obj/structure/sign/biohazard,/turf/simulated/wall,/area/medical/virologyaccess)
"chx" = (/obj/structure/disposaloutlet,/obj/structure/disposalpipe/trunk{dir = 1},/turf/simulated/floor/plating/airless,/area/medical/virology)
"chy" = (/obj/structure/bedsheetbin,/obj/structure/table,/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/obj/structure/cable/green,/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor{icon_state = "dark"},/area/medical/biostorage)
-"chz" = (/obj/structure/table,/obj/item/bodybag/cryobag{pixel_x = -3},/obj/item/bodybag/cryobag{pixel_x = -3},/obj/item/weapon/gun/syringe,/turf/simulated/floor{icon_state = "dark"},/area/medical/biostorage)
+"chz" = (/obj/structure/table,/obj/item/weapon/gun/launcher/syringe,/obj/item/weapon/storage/box/syringegun,/turf/simulated/floor{icon_state = "dark"},/area/medical/biostorage)
"chA" = (/obj/effect/decal/cleanable/dirt,/turf/simulated/floor/plating,/area/maintenance/research_port)
"chB" = (/turf/simulated/floor/plating,/area/maintenance/research_port)
"chC" = (/obj/machinery/door/airlock/medical{autoclose = 0; icon_state = "door_open"; id_tag = "cubicle1"; name = "Cubicle 1"},/turf/simulated/floor{icon_state = "freezerfloor"},/area/medical/patient_wing)
diff --git a/maps/exodus-2.dmm b/maps/exodus-2.dmm
index 944bc52a02..7a50f27ee6 100644
--- a/maps/exodus-2.dmm
+++ b/maps/exodus-2.dmm
@@ -705,7 +705,7 @@
"nC" = (/obj/structure/closet/secure_closet/freezer/kitchen{req_access = null; req_access_txt = "150"},/turf/unsimulated/floor{icon_state = "white"},/area/syndicate_mothership)
"nD" = (/obj/structure/table/reinforced,/obj/item/weapon/tray{pixel_y = 5},/turf/unsimulated/floor{icon_state = "white"},/area/syndicate_mothership)
"nE" = (/obj/structure/table/reinforced,/obj/item/weapon/reagent_containers/food/drinks/bottle/vodka{pixel_x = 3; pixel_y = 12},/obj/item/weapon/reagent_containers/food/drinks/bottle/wine{pixel_x = -1; pixel_y = 8},/turf/unsimulated/floor{icon_state = "white"},/area/syndicate_mothership)
-"nF" = (/obj/structure/table/rack,/obj/item/weapon/storage/belt/security,/obj/item/weapon/storage/belt/security,/turf/simulated/shuttle/floor{icon_state = "floor6"},/area/syndicate_station/start)
+"nF" = (/obj/structure/table/rack,/obj/item/weapon/storage/belt/security,/obj/item/weapon/storage/belt/security,/obj/item/ammo_magazine/mc9mm/flash,/obj/item/weapon/gun/projectile/pistol/flash,/turf/simulated/shuttle/floor{icon_state = "floor6"},/area/syndicate_station/start)
"nG" = (/obj/structure/table/rack,/obj/item/clothing/shoes/magboots,/obj/item/clothing/suit/space/syndicate/black/red,/obj/item/clothing/mask/breath,/obj/item/clothing/head/helmet/space/syndicate/black/red,/turf/unsimulated/floor{icon_state = "dark"},/area/syndicate_mothership)
"nH" = (/turf/simulated/shuttle/wall{icon_state = "wall3"},/area/syndicate_station/start)
"nI" = (/obj/structure/table,/obj/machinery/recharger,/turf/simulated/shuttle/floor{icon_state = "floor6"},/area/syndicate_station/start)
@@ -1046,7 +1046,7 @@
"uf" = (/turf/unsimulated/floor{icon_state = "floor"},/area/centcom/control)
"ug" = (/turf/unsimulated/wall,/area/centcom/test)
"uh" = (/turf/unsimulated/floor{icon_state = "vault"; dir = 8},/area/centcom/specops)
-"ui" = (/obj/structure/table/rack,/obj/item/weapon/gun/grenadelauncher,/turf/unsimulated/floor{icon_state = "vault"; dir = 1},/area/centcom)
+"ui" = (/obj/structure/table/rack,/obj/item/weapon/gun/launcher/grenade,/turf/unsimulated/floor{icon_state = "vault"; dir = 1},/area/centcom)
"uj" = (/obj/structure/table/rack,/obj/item/clothing/shoes/magboots,/obj/item/clothing/shoes/magboots,/obj/item/clothing/shoes/magboots,/obj/item/clothing/shoes/magboots,/obj/item/clothing/accessory/storage/black_vest,/obj/item/clothing/accessory/storage/black_vest,/obj/item/clothing/accessory/storage/black_vest,/obj/item/clothing/accessory/storage/black_vest,/turf/unsimulated/floor{icon_state = "vault"; dir = 1},/area/centcom)
"uk" = (/obj/structure/table/rack,/obj/item/clothing/suit/armor/vest/ert/security,/obj/item/clothing/suit/armor/vest/ert/security,/obj/item/clothing/suit/armor/vest/ert/security,/obj/item/clothing/suit/armor/vest/ert/security,/obj/item/clothing/head/helmet/ert/security,/obj/item/clothing/head/helmet/ert/security,/obj/item/clothing/head/helmet/ert/security,/obj/item/clothing/head/helmet/ert/security,/obj/item/weapon/storage/backpack/ert/security,/obj/item/weapon/storage/backpack/ert/security,/obj/item/weapon/storage/backpack/ert/security,/obj/item/weapon/storage/backpack/ert/security,/turf/unsimulated/floor{icon_state = "vault"; dir = 1},/area/centcom/specops)
"ul" = (/obj/structure/table/rack,/obj/item/weapon/rig/ert/security,/obj/item/clothing/accessory/storage/black_vest,/obj/item/weapon/rig/ert/security,/obj/item/clothing/accessory/storage/black_vest,/turf/unsimulated/floor{icon_state = "vault"; dir = 1},/area/centcom)
@@ -1912,7 +1912,7 @@
"KN" = (/obj/machinery/atmospherics/pipe/tank/nitrogen{dir = 1; initialize_directions = 1; start_pressure = 493.6},/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox/station)
"KO" = (/obj/machinery/portable_atmospherics/canister/phoron,/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox/station)
"KP" = (/obj/machinery/portable_atmospherics/canister/nitrogen,/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox/station)
-"KQ" = (/obj/structure/table/rack,/obj/item/weapon/gun/dartgun/vox/raider,/obj/item/weapon/gun/dartgun/vox/medical,/obj/item/weapon/dart_cartridge,/obj/item/weapon/dart_cartridge,/obj/item/weapon/dart_cartridge,/obj/item/weapon/dart_cartridge,/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox/station)
+"KQ" = (/obj/structure/table/rack,/obj/item/weapon/gun/projectile/dartgun/vox/raider,/obj/item/weapon/gun/projectile/dartgun/vox/medical,/obj/item/ammo_magazine/chemdart,/obj/item/ammo_magazine/chemdart,/obj/item/ammo_magazine/chemdart,/obj/item/ammo_magazine/chemdart,/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox/station)
"KR" = (/obj/structure/table/rack,/obj/item/clothing/accessory/storage/black_vest,/obj/item/clothing/suit/space/vox/medic,/obj/item/clothing/head/helmet/space/vox/medic,/obj/item/clothing/mask/breath,/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox/station)
"KS" = (/obj/structure/table/rack,/obj/item/weapon/gun/launcher/pneumatic,/obj/item/weapon/harpoon,/obj/item/weapon/harpoon,/obj/item/weapon/harpoon,/obj/item/weapon/harpoon,/obj/item/weapon/tank/nitrogen,/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox/station)
"KT" = (/obj/structure/table/rack,/obj/item/clothing/accessory/storage/black_vest,/obj/item/clothing/suit/space/vox/pressure,/obj/item/clothing/head/helmet/space/vox/pressure,/obj/item/clothing/mask/breath,/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox/station)
diff --git a/sound/weapons/gunshot_smg2.ogg b/sound/weapons/gunshot_smg2.ogg
new file mode 100644
index 0000000000..faba955f52
Binary files /dev/null and b/sound/weapons/gunshot_smg2.ogg differ