mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-08-25 21:19:44 +01:00
Merge remote-tracking branch 'upstream/dev' into inventoryfix
Conflicts: code/game/gamemodes/revolution/rp-revolution.dm code/game/machinery/kitchen/juicer.dm code/game/objects/items/stacks/stack.dm code/game/objects/items/weapons/cigs_lighters.dm code/game/objects/structures/stool_bed_chair_nest/stools.dm code/modules/destilery/main.dm code/modules/hydroponics/biogenerator.dm code/modules/mob/living/carbon/human/inventory.dm code/modules/mob/living/carbon/monkey/inventory.dm code/modules/projectiles/guns/launcher/pneumatic.dm
This commit is contained in:
@@ -6,73 +6,159 @@
|
||||
flags = CONDUCT
|
||||
slot_flags = SLOT_BELT
|
||||
throwforce = 1
|
||||
w_class = 1.0
|
||||
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
|
||||
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 - 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(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 = sanitizeSafe(input(user, "Inscribe some text into \the [initial(BB.name)]","Inscription",tmp_label), 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 << "<span class='warning'>[C] does not fit into [src].</span>"
|
||||
return
|
||||
if(stored_ammo.len >= max_ammo)
|
||||
user << "<span class='warning'>[src] is full!</span>"
|
||||
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 << "<span class='notice'>[src] is already empty!</span>"
|
||||
return
|
||||
user << "<span class='notice'>You empty [src].</span>"
|
||||
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
|
||||
|
||||
|
||||
@@ -1,38 +1,200 @@
|
||||
/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
|
||||
matter = list("metal" = 1260)
|
||||
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"
|
||||
matter = list("metal" = 360)
|
||||
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
|
||||
matter = list("metal" = 525) //metal costs are very roughly based around 1 .45 casing = 75 metal
|
||||
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"
|
||||
ammo_type = /obj/item/ammo_casing/c45r
|
||||
|
||||
/obj/item/ammo_magazine/c45m/flash
|
||||
name = "magazine (.45 flash)"
|
||||
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
|
||||
matter = list("metal" = 600)
|
||||
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"
|
||||
matter = list("metal" = 1800)
|
||||
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/mc9mmt
|
||||
name = "top mounted magazine (9mm)"
|
||||
icon_state = "9mmt"
|
||||
mag_type = MAGAZINE
|
||||
ammo_type = /obj/item/ammo_casing/c9mm
|
||||
matter = list("metal" = 1200)
|
||||
caliber = "9mm"
|
||||
max_ammo = 20
|
||||
multiple_sprites = 1
|
||||
|
||||
/obj/item/ammo_magazine/mc9mmt/empty
|
||||
initial_ammo = 0
|
||||
|
||||
/obj/item/ammo_magazine/mc9mmt/rubber
|
||||
name = "top mounted magazine (9mm rubber)"
|
||||
ammo_type = /obj/item/ammo_casing/c9mmr
|
||||
|
||||
/obj/item/ammo_magazine/c45
|
||||
name = "ammunition Box (.45)"
|
||||
icon_state = "9mm"
|
||||
origin_tech = "combat=2"
|
||||
caliber = ".45"
|
||||
matter = list("metal" = 2250)
|
||||
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"
|
||||
matter = list("metal" = 1500)
|
||||
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/a556
|
||||
name = "magazine (5.56mm)"
|
||||
icon_state = "5.56"
|
||||
origin_tech = "combat=2"
|
||||
mag_type = MAGAZINE
|
||||
caliber = "a556"
|
||||
matter = list("metal" = 1800)
|
||||
ammo_type = /obj/item/ammo_casing/a556
|
||||
max_ammo = 10
|
||||
multiple_sprites = 1
|
||||
|
||||
/obj/item/ammo_magazine/a556/empty
|
||||
initial_ammo = 0
|
||||
|
||||
/obj/item/ammo_magazine/a50
|
||||
name = "magazine (.50)"
|
||||
icon_state = "50ae"
|
||||
origin_tech = "combat=2"
|
||||
mag_type = MAGAZINE
|
||||
caliber = ".50"
|
||||
matter = list("metal" = 1260)
|
||||
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"
|
||||
matter = list("metal" = 4500)
|
||||
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"
|
||||
matter = list("metal" = 1800)
|
||||
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)"
|
||||
@@ -41,114 +203,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 = 8
|
||||
multiple_sprites = 1
|
||||
|
||||
/obj/item/ammo_magazine/mc9mm/empty
|
||||
max_ammo = 0
|
||||
|
||||
/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()
|
||||
*/
|
||||
|
||||
@@ -1,113 +1,156 @@
|
||||
/obj/item/ammo_casing/a357
|
||||
desc = "A .357 bullet casing."
|
||||
caliber = "357"
|
||||
projectile_type = "/obj/item/projectile/bullet"
|
||||
projectile_type = /obj/item/projectile/bullet/pistol/strong
|
||||
|
||||
/obj/item/ammo_casing/a50
|
||||
desc = "A .50AE bullet casing."
|
||||
caliber = ".50"
|
||||
projectile_type = "/obj/item/projectile/bullet"
|
||||
|
||||
/obj/item/ammo_casing/a418
|
||||
desc = "A .418 bullet casing."
|
||||
caliber = "357"
|
||||
projectile_type = "/obj/item/projectile/bullet/suffocationbullet"
|
||||
|
||||
projectile_type = /obj/item/projectile/bullet/pistol/strong
|
||||
|
||||
/obj/item/ammo_casing/a75
|
||||
desc = "A .75 bullet casing."
|
||||
desc = "A 20mm bullet casing."
|
||||
caliber = "75"
|
||||
projectile_type = "/obj/item/projectile/bullet/gyro"
|
||||
|
||||
|
||||
/obj/item/ammo_casing/a666
|
||||
desc = "A .666 bullet casing."
|
||||
caliber = "357"
|
||||
projectile_type = "/obj/item/projectile/bullet/cyanideround"
|
||||
|
||||
projectile_type = /obj/item/projectile/bullet/gyro
|
||||
|
||||
/obj/item/ammo_casing/c38
|
||||
desc = "A .38 bullet casing."
|
||||
caliber = "38"
|
||||
projectile_type = "/obj/item/projectile/bullet/weakbullet"
|
||||
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
|
||||
desc = "A 9mm bullet casing."
|
||||
caliber = "9mm"
|
||||
projectile_type = "/obj/item/projectile/bullet/midbullet2"
|
||||
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/c9mmr
|
||||
desc = "A 9mm rubber bullet casing."
|
||||
caliber = "9mm"
|
||||
projectile_type = /obj/item/projectile/bullet/pistol/rubber
|
||||
|
||||
|
||||
/obj/item/ammo_casing/c45
|
||||
desc = "A .45 bullet casing."
|
||||
caliber = ".45"
|
||||
projectile_type = "/obj/item/projectile/bullet/midbullet"
|
||||
projectile_type = /obj/item/projectile/bullet/pistol/medium
|
||||
|
||||
/obj/item/ammo_casing/c45r
|
||||
desc = "A .45 rubber bullet casing."
|
||||
caliber = ".45"
|
||||
projectile_type = "/obj/item/projectile/bullet/weakbullet/rubber"
|
||||
projectile_type = /obj/item/projectile/bullet/pistol/rubber
|
||||
|
||||
/obj/item/ammo_casing/c45f
|
||||
desc = "A .45 flash shell casing."
|
||||
caliber = ".45"
|
||||
projectile_type = /obj/item/projectile/energy/flash
|
||||
|
||||
/obj/item/ammo_casing/a12mm
|
||||
desc = "A 12mm bullet casing."
|
||||
caliber = "12mm"
|
||||
projectile_type = "/obj/item/projectile/bullet/midbullet2"
|
||||
projectile_type = /obj/item/projectile/bullet/pistol/medium
|
||||
|
||||
|
||||
/obj/item/ammo_casing/shotgun
|
||||
name = "shotgun slug"
|
||||
desc = "A 12 gauge slug."
|
||||
icon_state = "slshell"
|
||||
caliber = "shotgun"
|
||||
projectile_type = /obj/item/projectile/bullet/shotgun
|
||||
matter = list("metal" = 360)
|
||||
|
||||
/obj/item/ammo_casing/shotgun/pellet
|
||||
name = "shotgun shell"
|
||||
desc = "A 12 gauge shell."
|
||||
icon_state = "gshell"
|
||||
caliber = "shotgun"
|
||||
projectile_type = "/obj/item/projectile/bullet"
|
||||
matter = list("metal" = 12500)
|
||||
|
||||
projectile_type = /obj/item/projectile/bullet/pellet/shotgun
|
||||
matter = list("metal" = 360)
|
||||
|
||||
/obj/item/ammo_casing/shotgun/blank
|
||||
name = "shotgun shell"
|
||||
desc = "A blank shell."
|
||||
icon_state = "blshell"
|
||||
projectile_type = "/obj/item/projectile/bullet/chameleon"
|
||||
matter = list("metal" = 250)
|
||||
|
||||
projectile_type = /obj/item/projectile/bullet/blank
|
||||
matter = list("metal" = 90)
|
||||
|
||||
/obj/item/ammo_casing/shotgun/beanbag
|
||||
name = "beanbag shell"
|
||||
desc = "A weak beanbag shell."
|
||||
desc = "A beanbag shell."
|
||||
icon_state = "bshell"
|
||||
projectile_type = "/obj/item/projectile/bullet/weakbullet/beanbag"
|
||||
matter = list("metal" = 500)
|
||||
|
||||
projectile_type = /obj/item/projectile/bullet/shotgun/beanbag
|
||||
matter = list("metal" = 180)
|
||||
|
||||
//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 stunning shell."
|
||||
desc = "A 12 gauge taser cartridge."
|
||||
icon_state = "stunshell"
|
||||
projectile_type = "/obj/item/projectile/bullet/stunshot"
|
||||
matter = list("metal" = 2500)
|
||||
spent_icon = "stunshell-spent"
|
||||
projectile_type = /obj/item/projectile/energy/electrode/stunshot
|
||||
matter = list("metal" = 360, "glass" = 720)
|
||||
|
||||
/obj/item/ammo_casing/shotgun/stunshell/emp_act(severity)
|
||||
if(prob(100/severity)) BB = null
|
||||
update_icon()
|
||||
|
||||
/obj/item/ammo_casing/shotgun/dart
|
||||
name = "shotgun darts"
|
||||
desc = "A dart for use in shotguns."
|
||||
icon_state = "dart"
|
||||
projectile_type = "/obj/item/projectile/energy/dart"
|
||||
matter = list("metal" = 12500)
|
||||
//Does not stun, only blinds, but has area of effect.
|
||||
/obj/item/ammo_casing/shotgun/flash
|
||||
name = "flash shell"
|
||||
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" = 90, "glass" = 90)
|
||||
|
||||
/obj/item/ammo_casing/a762
|
||||
desc = "A 7.62 bullet casing."
|
||||
desc = "A 7.62mm bullet casing."
|
||||
caliber = "a762"
|
||||
projectile_type = "/obj/item/projectile/bullet/a762"
|
||||
projectile_type = /obj/item/projectile/bullet/rifle/a762
|
||||
|
||||
/obj/item/ammo_casing/a145
|
||||
name = "shell casing"
|
||||
desc = "A 14.5mm shell."
|
||||
icon_state = "lcasing"
|
||||
spent_icon = "lcasing-spent"
|
||||
caliber = "14.5mm"
|
||||
projectile_type = /obj/item/projectile/bullet/rifle/a145
|
||||
matter = list("metal" = 1250)
|
||||
|
||||
/obj/item/ammo_casing/a556
|
||||
desc = "A 5.56mm bullet casing."
|
||||
caliber = "a556"
|
||||
projectile_type = /obj/item/projectile/bullet/rifle/a556
|
||||
|
||||
/obj/item/ammo_casing/rocket
|
||||
name = "rocket shell"
|
||||
desc = "A high explosive designed to be fired from a launcher."
|
||||
icon_state = "rocketshell"
|
||||
projectile_type = "/obj/item/missile"
|
||||
projectile_type = /obj/item/missile
|
||||
caliber = "rocket"
|
||||
|
||||
/obj/item/ammo_casing/chameleon
|
||||
name = "chameleon bullets"
|
||||
desc = "A set of bullets for the Chameleon Gun."
|
||||
projectile_type = "/obj/item/projectile/bullet/chameleon"
|
||||
projectile_type = /obj/item/projectile/bullet/chameleon
|
||||
caliber = ".45"
|
||||
|
||||
/*
|
||||
/obj/item/ammo_casing/a418
|
||||
desc = "A .418 bullet casing."
|
||||
caliber = "357"
|
||||
projectile_type = /obj/item/projectile/bullet/suffocationbullet
|
||||
|
||||
/obj/item/ammo_casing/a666
|
||||
desc = "A .666 bullet casing."
|
||||
caliber = "357"
|
||||
projectile_type = /obj/item/projectile/bullet/cyanideround
|
||||
*/
|
||||
@@ -0,0 +1,126 @@
|
||||
/obj/effect/projectile
|
||||
icon = 'icons/effects/projectiles.dmi'
|
||||
icon_state = "bolt"
|
||||
layer = 20
|
||||
|
||||
/obj/effect/projectile/New(var/turf/location)
|
||||
if(istype(location))
|
||||
loc = location
|
||||
|
||||
/obj/effect/projectile/proc/set_transform(var/matrix/M)
|
||||
if(istype(M))
|
||||
transform = M
|
||||
|
||||
/obj/effect/projectile/proc/activate()
|
||||
spawn(3)
|
||||
delete() //see effect_system.dm - sets loc to null and lets GC handle removing these effects
|
||||
|
||||
return
|
||||
|
||||
//----------------------------
|
||||
// Laser beam
|
||||
//----------------------------
|
||||
/obj/effect/projectile/laser/tracer
|
||||
icon_state = "beam"
|
||||
|
||||
/obj/effect/projectile/laser/muzzle
|
||||
icon_state = "muzzle_laser"
|
||||
|
||||
/obj/effect/projectile/laser/impact
|
||||
icon_state = "impact_laser"
|
||||
|
||||
//----------------------------
|
||||
// Blue laser beam
|
||||
//----------------------------
|
||||
/obj/effect/projectile/laser_blue/tracer
|
||||
icon_state = "beam_blue"
|
||||
|
||||
/obj/effect/projectile/laser_blue/muzzle
|
||||
icon_state = "muzzle_blue"
|
||||
|
||||
/obj/effect/projectile/laser_blue/impact
|
||||
icon_state = "impact_blue"
|
||||
|
||||
//----------------------------
|
||||
// Omni laser beam
|
||||
//----------------------------
|
||||
/obj/effect/projectile/laser_omni/tracer
|
||||
icon_state = "beam_omni"
|
||||
|
||||
/obj/effect/projectile/laser_omni/muzzle
|
||||
icon_state = "muzzle_omni"
|
||||
|
||||
/obj/effect/projectile/laser_omni/impact
|
||||
icon_state = "impact_omni"
|
||||
|
||||
//----------------------------
|
||||
// Xray laser beam
|
||||
//----------------------------
|
||||
/obj/effect/projectile/xray/tracer
|
||||
icon_state = "xray"
|
||||
|
||||
/obj/effect/projectile/xray/muzzle
|
||||
icon_state = "muzzle_xray"
|
||||
|
||||
/obj/effect/projectile/xray/impact
|
||||
icon_state = "impact_xray"
|
||||
|
||||
//----------------------------
|
||||
// Heavy laser beam
|
||||
//----------------------------
|
||||
/obj/effect/projectile/laser_heavy/tracer
|
||||
icon_state = "beam_heavy"
|
||||
|
||||
/obj/effect/projectile/laser_heavy/muzzle
|
||||
icon_state = "muzzle_beam_heavy"
|
||||
|
||||
/obj/effect/projectile/laser_heavy/impact
|
||||
icon_state = "impact_beam_heavy"
|
||||
|
||||
//----------------------------
|
||||
// Pulse laser beam
|
||||
//----------------------------
|
||||
/obj/effect/projectile/laser_pulse/tracer
|
||||
icon_state = "u_laser"
|
||||
|
||||
/obj/effect/projectile/laser_pulse/muzzle
|
||||
icon_state = "muzzle_u_laser"
|
||||
|
||||
/obj/effect/projectile/laser_pulse/impact
|
||||
icon_state = "impact_u_laser"
|
||||
|
||||
//----------------------------
|
||||
// Pulse muzzle effect only
|
||||
//----------------------------
|
||||
/obj/effect/projectile/pulse/muzzle
|
||||
icon_state = "muzzle_pulse"
|
||||
|
||||
//----------------------------
|
||||
// Emitter beam
|
||||
//----------------------------
|
||||
/obj/effect/projectile/emitter/tracer
|
||||
icon_state = "emitter"
|
||||
|
||||
/obj/effect/projectile/emitter/muzzle
|
||||
icon_state = "muzzle_emitter"
|
||||
|
||||
/obj/effect/projectile/emitter/impact
|
||||
icon_state = "impact_emitter"
|
||||
|
||||
//----------------------------
|
||||
// Stun beam
|
||||
//----------------------------
|
||||
/obj/effect/projectile/stun/tracer
|
||||
icon_state = "stun"
|
||||
|
||||
/obj/effect/projectile/stun/muzzle
|
||||
icon_state = "muzzle_stun"
|
||||
|
||||
/obj/effect/projectile/stun/impact
|
||||
icon_state = "impact_stun"
|
||||
|
||||
//----------------------------
|
||||
// Bullet
|
||||
//----------------------------
|
||||
/obj/effect/projectile/bullet/muzzle
|
||||
icon_state = "muzzle_bullet"
|
||||
+207
-163
@@ -1,107 +1,124 @@
|
||||
//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."
|
||||
icon = 'icons/obj/gun.dmi'
|
||||
item_icons = list(
|
||||
icon_l_hand = 'icons/mob/items/lefthand_guns.dmi',
|
||||
icon_r_hand = 'icons/mob/items/righthand_guns.dmi',
|
||||
)
|
||||
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 << "<span class='danger'>Your fingers are much too large for the trigger guard!</span>"
|
||||
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(
|
||||
"<span class='danger'>[user] shoots \himself in the foot with \the [src]!</span>",
|
||||
"<span class='danger'>You shoot yourself in the foot with \the [src]!</span>"
|
||||
)
|
||||
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)
|
||||
if(user.a_intent == I_HELP && isliving(A) && !C.gun_mode)
|
||||
C.ToggleGunMode()
|
||||
|
||||
if(C.gun_mode)
|
||||
aiming = PreFire(A,user,params) //They're using the new gun system, locate what they're aiming at.
|
||||
|
||||
if (!aiming)
|
||||
if(user && user.a_intent == "help") //regardless of what happens, refuse to shoot if help intent is on
|
||||
if(user && user.a_intent == I_HELP) //regardless of what happens, refuse to shoot if help intent is on
|
||||
user << "\red You refrain from firing your [src] as your intent is set to help."
|
||||
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 == I_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(clumsy_check)
|
||||
if(istype(user, /mob/living))
|
||||
var/mob/living/M = user
|
||||
if ((CLUMSY in M.mutations) && prob(50))
|
||||
M << "<span class='danger'>[src] blows up in your face.</span>"
|
||||
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 << "<span class='danger'>Your fingers are much too large for the trigger guard!</span>"
|
||||
return
|
||||
/obj/item/weapon/gun/proc/Fire(atom/target, mob/living/user, params, pointblank=0, reflex=0)
|
||||
if(!user || !target) return
|
||||
|
||||
add_fingerprint(user)
|
||||
|
||||
var/turf/curloc = get_turf(user)
|
||||
var/turf/targloc = get_turf(target)
|
||||
if (!istype(targloc) || !istype(curloc))
|
||||
return
|
||||
|
||||
if(!special_check(user))
|
||||
return
|
||||
|
||||
@@ -110,128 +127,155 @@
|
||||
user << "<span class='warning'>[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
|
||||
|
||||
in_chamber.firer = user
|
||||
in_chamber.def_zone = user.zone_sel.selecting
|
||||
if(targloc == curloc)
|
||||
user.bullet_act(in_chamber)
|
||||
del(in_chamber)
|
||||
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()
|
||||
return
|
||||
update_held_icon()
|
||||
|
||||
if(recoil)
|
||||
spawn()
|
||||
shake_camera(user, recoil + 1, recoil)
|
||||
|
||||
//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*", "<span class='danger'>*click*</span>")
|
||||
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("<span class='warning'>[user] fires [src][reflex ? " by reflex":""]!</span>", \
|
||||
"<span class='warning'>You fire [src][reflex ? "by reflex":""]!</span>", \
|
||||
"You hear a [istype(in_chamber, /obj/item/projectile/beam) ? "laser blast" : "gunshot"]!")
|
||||
user.visible_message(
|
||||
"<span class='danger'>[user] fires [src][pointblank ? " point blank at [target]":""][reflex ? " by reflex":""]!</span>",
|
||||
"<span class='warning'>You fire [src][reflex ? "by reflex":""]!</span>",
|
||||
"You hear a [fire_sound_text]!"
|
||||
)
|
||||
|
||||
if(recoil)
|
||||
spawn()
|
||||
shake_camera(user, recoil+1, recoil)
|
||||
update_icon()
|
||||
|
||||
in_chamber.original = target
|
||||
in_chamber.loc = get_turf(user)
|
||||
in_chamber.starting = get_turf(user)
|
||||
in_chamber.shot_from = src
|
||||
user.next_move = world.time + 4
|
||||
in_chamber.silenced = silenced
|
||||
in_chamber.current = curloc
|
||||
in_chamber.yo = targloc.y - curloc.y
|
||||
in_chamber.xo = targloc.x - curloc.x
|
||||
//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))
|
||||
var/mob/living/carbon/mob = user
|
||||
if(mob.shock_stage > 120)
|
||||
in_chamber.yo += rand(-2,2)
|
||||
in_chamber.xo += rand(-2,2)
|
||||
y_offset = rand(-2,2)
|
||||
x_offset = rand(-2,2)
|
||||
else if(mob.shock_stage > 70)
|
||||
in_chamber.yo += rand(-1,1)
|
||||
in_chamber.xo += rand(-1,1)
|
||||
y_offset = rand(-1,1)
|
||||
x_offset = rand(-1,1)
|
||||
|
||||
//Point blank bonus
|
||||
if(pointblank)
|
||||
var/damage_mult = 1.3 //default point blank multiplier
|
||||
|
||||
//determine multiplier due to the target being grabbed
|
||||
if(ismob(target))
|
||||
var/mob/M = target
|
||||
if(M.grabbed_by.len)
|
||||
var/grabstate = 0
|
||||
for(var/obj/item/weapon/grab/G in M.grabbed_by)
|
||||
grabstate = max(grabstate, G.state)
|
||||
if(grabstate >= GRAB_NECK)
|
||||
damage_mult = 3.0
|
||||
else if (grabstate >= GRAB_AGGRESSIVE)
|
||||
damage_mult = 1.5
|
||||
|
||||
P.damage *= damage_mult
|
||||
|
||||
if(params)
|
||||
var/list/mouse_control = params2list(params)
|
||||
if(mouse_control["icon-x"])
|
||||
in_chamber.p_x = text2num(mouse_control["icon-x"])
|
||||
if(mouse_control["icon-y"])
|
||||
in_chamber.p_y = text2num(mouse_control["icon-y"])
|
||||
P.set_clickpoint(params)
|
||||
|
||||
spawn()
|
||||
if(in_chamber)
|
||||
in_chamber.process()
|
||||
sleep(1)
|
||||
in_chamber = null
|
||||
return !P.launch(target, user, src, target_zone, x_offset, y_offset)
|
||||
|
||||
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 <b>*click*</b>")
|
||||
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("<span class = 'warning'>[user] pulls the trigger.</span>")
|
||||
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("<span class = 'warning'>You feel rather silly, trying to commit suicide with a toy.</span>")
|
||||
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 << "<span class = 'notice'>Ow...</span>"
|
||||
user.apply_effect(110,AGONY,0)
|
||||
del(in_chamber)
|
||||
mouthshoot = 0
|
||||
return
|
||||
//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
|
||||
|
||||
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("<span class = 'warning'>[user] pulls the trigger.</span>")
|
||||
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("<span class = 'warning'>You feel rather silly, trying to commit suicide with a toy.</span>")
|
||||
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 <b> \The [user] fires \the [src] point blank at [M]!</b>")
|
||||
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 << "<span class = 'notice'>Ow...</span>"
|
||||
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
|
||||
|
||||
//make sure accuracy and recoil are reset regardless of how the item is unzoomed.
|
||||
/obj/item/weapon/gun/zoom()
|
||||
..()
|
||||
if(!zoom)
|
||||
accuracy = initial(accuracy)
|
||||
recoil = initial(recoil)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//Vox pinning weapon.
|
||||
/obj/item/weapon/gun/launcher/spikethrower
|
||||
name = "Vox spike thrower"
|
||||
|
||||
name = "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 +25,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,89 +32,23 @@
|
||||
|
||||
/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!"
|
||||
if(H.species && H.species.name != "Vox")
|
||||
user << "<span class='warning'>\The [src] does not respond to you!</span>"
|
||||
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()
|
||||
|
||||
//This gun only functions for armalis. The on-sprite is too huge to render properly on other sprites.
|
||||
/obj/item/weapon/gun/energy/noisecannon
|
||||
name = "alien heavy cannon"
|
||||
desc = "It's some kind of enormous alien weapon, as long as a man is tall."
|
||||
|
||||
icon = 'icons/obj/gun.dmi' //Actual on-sprite is handled by icon_override.
|
||||
icon_state = "noisecannon"
|
||||
item_state = "noisecannon"
|
||||
recoil = 1
|
||||
|
||||
force = 10
|
||||
projectile_type = "/obj/item/projectile/energy/sonic"
|
||||
cell_type = "/obj/item/weapon/cell/super"
|
||||
fire_delay = 40
|
||||
fire_sound = 'sound/effects/basscannon.ogg'
|
||||
|
||||
var/mode = 1
|
||||
|
||||
sprite_sheets = list(
|
||||
"Vox Armalis" = 'icons/mob/species/armalis/held.dmi'
|
||||
)
|
||||
|
||||
/obj/item/weapon/gun/energy/noisecannon/attack_hand(mob/user as mob)
|
||||
if(loc != user)
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(istype(H))
|
||||
if(H.species.name == "Vox Armalis")
|
||||
..()
|
||||
return
|
||||
user << "\red \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
|
||||
|
||||
//Projectile.
|
||||
/obj/item/projectile/energy/sonic
|
||||
name = "distortion"
|
||||
icon = 'icons/obj/machines/particle_accelerator2.dmi'
|
||||
icon_state = "particle"
|
||||
damage = 60
|
||||
damage_type = BRUTE
|
||||
flag = "bullet"
|
||||
pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
|
||||
|
||||
embed = 0
|
||||
weaken = 5
|
||||
stun = 5
|
||||
|
||||
/obj/item/projectile/energy/sonic/proc/split()
|
||||
//TODO: create two more projectiles to either side of this one, fire at targets to the side of target turf.
|
||||
return
|
||||
return new /obj/item/weapon/spike(src)
|
||||
|
||||
@@ -3,42 +3,89 @@
|
||||
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/projectile_type = "/obj/item/projectile/beam/practice"
|
||||
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(!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)
|
||||
update_icon()
|
||||
|
||||
/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
|
||||
|
||||
//make sure that rounding down will not give us the empty state even if we have charge for a shot left.
|
||||
if(power_supply.charge < charge_cost)
|
||||
ratio = 0
|
||||
else
|
||||
ratio = max(round(ratio, 0.25) * 100, 25)
|
||||
|
||||
if(modifystate)
|
||||
icon_state = "[modifystate][ratio]"
|
||||
else
|
||||
icon_state = "[initial(icon_state)][ratio]"
|
||||
|
||||
|
||||
@@ -1,173 +1,131 @@
|
||||
/obj/item/weapon/gun/energy/laser
|
||||
name = "laser carbine"
|
||||
desc = "A basic weapon designed to kill with concentrated energy bolts."
|
||||
desc = "A common laser weapon, designed to kill with concentrated energy blasts."
|
||||
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
|
||||
matter = list("metal" = 2000)
|
||||
origin_tech = "combat=3;magnets=2"
|
||||
projectile_type = /obj/item/projectile/beam
|
||||
fire_delay = 1 //rapid fire
|
||||
|
||||
/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
|
||||
obj/item/weapon/gun/energy/retro
|
||||
name = "retro laser"
|
||||
icon_state = "retro"
|
||||
item_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."
|
||||
fire_sound = 'sound/weapons/Laser.ogg'
|
||||
slot_flags = SLOT_BELT
|
||||
w_class = 3
|
||||
projectile_type = /obj/item/projectile/beam
|
||||
fire_delay = 10 //old technology
|
||||
|
||||
|
||||
/obj/item/weapon/gun/energy/laser/captain
|
||||
/obj/item/weapon/gun/energy/captain
|
||||
name = "antique laser gun"
|
||||
icon_state = "caplaser"
|
||||
item_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
|
||||
fire_sound = 'sound/weapons/Laser.ogg'
|
||||
slot_flags = SLOT_BELT
|
||||
w_class = 3
|
||||
projectile_type = /obj/item/projectile/beam
|
||||
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
|
||||
|
||||
|
||||
charge_cost = 200 //to compensate a bit for self-recharging
|
||||
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 = null
|
||||
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
|
||||
name = "mounted laser cannon"
|
||||
self_recharge = 1
|
||||
use_external_power = 1
|
||||
recharge_time = 10
|
||||
|
||||
/obj/item/weapon/gun/energy/xray
|
||||
name = "xray laser gun"
|
||||
desc = "A high-power laser gun capable of expelling concentrated xray blasts."
|
||||
icon_state = "xray"
|
||||
item_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
|
||||
fire_delay = 1
|
||||
|
||||
/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 << "<span class='warning'>You need to be wearing your laser tag vest!</span>"
|
||||
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
|
||||
item_state = "bluetag"
|
||||
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
|
||||
item_state = "redtag"
|
||||
projectile_type = /obj/item/projectile/beam/lastertag/red
|
||||
required_vest = /obj/item/clothing/suit/redtag
|
||||
|
||||
@@ -1,129 +1,117 @@
|
||||
/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'
|
||||
|
||||
charge_cost = 100 //How much energy is needed to fire.
|
||||
projectile_type = "/obj/item/projectile/beam/stun"
|
||||
projectile_type = /obj/item/projectile/beam/stun
|
||||
origin_tech = "combat=3;magnets=2"
|
||||
modifystate = "energystun"
|
||||
|
||||
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 << "<span class='warning'>[src.name] is now set to kill.</span>"
|
||||
projectile_type = /obj/item/projectile/beam
|
||||
modifystate = "energykill"
|
||||
if(1)
|
||||
mode = 0
|
||||
charge_cost = 100
|
||||
fire_sound = 'sound/weapons/Taser.ogg'
|
||||
user << "<span class='warning'>[src.name] is now set to stun.</span>"
|
||||
projectile_type = /obj/item/projectile/beam/stun
|
||||
modifystate = "energystun"
|
||||
update_icon()
|
||||
update_held_icon()
|
||||
|
||||
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
|
||||
name = "mounted energy gun"
|
||||
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 << "<span class='warning'>Your gun feels pleasantly warm for a moment.</span>"
|
||||
else
|
||||
M << "<span class='warning'>You feel a warm sensation.</span>"
|
||||
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 << "<span class='danger'>Your gun's reactor overloads!</span>"
|
||||
M << "<span class='warning'>You feel a wave of heat wash over you.</span>"
|
||||
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()
|
||||
|
||||
@@ -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"
|
||||
projectile_type = /obj/item/projectile/beam/pulse
|
||||
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 [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 << "\red [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 << "\red [src.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 << "<span class='warning'>[src.name] is now set to stun.</span>"
|
||||
projectile_type = /obj/item/projectile/beam/stun
|
||||
if(0)
|
||||
mode = 1
|
||||
charge_cost = 100
|
||||
fire_sound = 'sound/weapons/Laser.ogg'
|
||||
user << "<span class='warning'>[src.name] is now set to kill.</span>"
|
||||
projectile_type = /obj/item/projectile/beam
|
||||
if(1)
|
||||
mode = 2
|
||||
charge_cost = 200
|
||||
fire_sound = 'sound/weapons/pulse.ogg'
|
||||
user << "<span class='warning'>[src.name] is now set to DESTROY.</span>"
|
||||
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 [src.name] has three settings, and they are all DESTROY."
|
||||
|
||||
/obj/item/weapon/gun/energy/pulse_rifle/destroyer/attack_self(mob/living/user as mob)
|
||||
user << "<span class='warning'>[src.name] has three settings, and they are all DESTROY.</span>"
|
||||
|
||||
|
||||
//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
|
||||
|
||||
@@ -2,138 +2,72 @@
|
||||
name = "ion rifle"
|
||||
desc = "A man portable anti-armor weapon designed to disable mechanical threats"
|
||||
icon_state = "ionrifle"
|
||||
item_state = "ionrifle"
|
||||
fire_sound = 'sound/weapons/Laser.ogg'
|
||||
origin_tech = "combat=2;magnets=4"
|
||||
w_class = 4.0
|
||||
w_class = 4
|
||||
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()
|
||||
..(max(severity, 2)) //so it doesn't EMP itself, I guess
|
||||
|
||||
/obj/item/weapon/gun/energy/ionrifle/update_icon()
|
||||
..()
|
||||
if(power_supply.charge < charge_cost)
|
||||
item_state = "ionrifle-empty"
|
||||
else
|
||||
return
|
||||
item_state = initial(item_state)
|
||||
|
||||
/obj/item/weapon/gun/energy/decloner
|
||||
name = "biological demolecularisor"
|
||||
desc = "A gun that discharges high amounts of controlled radiation to slowly break a target into component elements."
|
||||
icon_state = "decloner"
|
||||
item_state = "decloner"
|
||||
fire_sound = 'sound/weapons/pulse3.ogg'
|
||||
origin_tech = "combat=5;materials=4;powerstorage=3"
|
||||
charge_cost = 100
|
||||
projectile_type = "/obj/item/projectile/energy/declone"
|
||||
|
||||
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'
|
||||
icon_state = "staffofchange"
|
||||
item_state = "staffofchange"
|
||||
fire_sound = 'sound/weapons/emitter.ogg'
|
||||
flags = CONDUCT
|
||||
slot_flags = SLOT_BACK
|
||||
w_class = 4.0
|
||||
charge_cost = 200
|
||||
projectile_type = "/obj/item/projectile/change"
|
||||
origin_tech = null
|
||||
clumsy_check = 0
|
||||
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(200)
|
||||
return 1
|
||||
|
||||
update_icon()
|
||||
return
|
||||
|
||||
|
||||
click_empty(mob/user = null)
|
||||
if (user)
|
||||
user.visible_message("*fizzle*", "\red <b>*fizzle*</b>")
|
||||
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"
|
||||
charge_cost = 100
|
||||
projectile_type = /obj/item/projectile/energy/declone
|
||||
|
||||
/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"
|
||||
item_state = "floramut"
|
||||
fire_sound = 'sound/effects/stealthoff.ogg'
|
||||
charge_cost = 100
|
||||
projectile_type = "/obj/item/projectile/energy/floramut"
|
||||
projectile_type = /obj/item/projectile/energy/floramut
|
||||
origin_tech = "materials=2;biotech=3;powerstorage=3"
|
||||
modifystate = "floramut"
|
||||
var/charge_tick = 0
|
||||
self_recharge = 1
|
||||
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"
|
||||
user << "<span class='warning'>The [src.name] is now set to increase yield.</span>"
|
||||
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"
|
||||
user << "<span class='warning'>The [src.name] is now set to induce mutations.</span>"
|
||||
projectile_type = /obj/item/projectile/energy/floramut
|
||||
modifystate = "floramut"
|
||||
update_icon()
|
||||
return
|
||||
update_held_icon()
|
||||
|
||||
/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 <b> \The [user] fires \the [src] into \the [tray]!</b>")
|
||||
Fire(target,user)
|
||||
/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("<span class='danger'>\The [user] fires \the [src] into \the [target]!</span>")
|
||||
Fire(target,user)
|
||||
return
|
||||
|
||||
..()
|
||||
|
||||
/obj/item/weapon/gun/energy/meteorgun
|
||||
@@ -141,33 +75,14 @@ obj/item/weapon/gun/energy/staff
|
||||
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"
|
||||
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
|
||||
|
||||
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"
|
||||
@@ -176,34 +91,16 @@ obj/item/weapon/gun/energy/staff
|
||||
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."
|
||||
desc = "A custom-built weapon of some kind."
|
||||
icon_state = "xray"
|
||||
projectile_type = "/obj/item/projectile/beam/mindflayer"
|
||||
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"
|
||||
/*
|
||||
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."
|
||||
projectile_type = "/obj/item/projectile/forcebolt/strong"
|
||||
else
|
||||
charge_cost = 100
|
||||
user << "\red 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."
|
||||
@@ -211,25 +108,108 @@ obj/item/weapon/gun/energy/staff/focus
|
||||
fire_sound = 'sound/effects/stealthoff.ogg'
|
||||
w_class = 3.0
|
||||
origin_tech = "combat=5;phorontech=4"
|
||||
projectile_type = "/obj/item/projectile/energy/phoron"
|
||||
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."
|
||||
/* 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'
|
||||
icon_state = "sniper"
|
||||
fire_sound = 'sound/weapons/marauder.ogg'
|
||||
origin_tech = "combat=6;materials=5;powerstorage=4"
|
||||
projectile_type = "/obj/item/projectile/beam/sniper"
|
||||
item_icons = null
|
||||
icon_state = "staffofchange"
|
||||
item_state = "staffofchange"
|
||||
fire_sound = 'sound/weapons/emitter.ogg'
|
||||
flags = CONDUCT
|
||||
slot_flags = SLOT_BACK
|
||||
charge_cost = 250
|
||||
fire_delay = 35
|
||||
w_class = 4.0
|
||||
zoomdevicename = "scope"
|
||||
charge_cost = 200
|
||||
projectile_type = /obj/item/projectile/change
|
||||
origin_tech = null
|
||||
self_recharge = 1
|
||||
charge_meter = 0
|
||||
|
||||
/obj/item/weapon/gun/energy/sniperrifle/verb/scope()
|
||||
/obj/item/weapon/gun/energy/staff/handle_click_empty(mob/user = null)
|
||||
if (user)
|
||||
user.visible_message("*fizzle*", "<span class='danger'>*fizzle*</span>")
|
||||
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
|
||||
charge_cost = 100
|
||||
|
||||
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"
|
||||
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 << "<span class='warning'>The [src.name] will now strike a small area.</span>"
|
||||
projectile_type = "/obj/item/projectile/forcebolt/strong"
|
||||
else
|
||||
charge_cost = 100
|
||||
user << "<span class='warning'>The [src.name] will now strike only a single person.</span>"
|
||||
projectile_type = "/obj/item/projectile/forcebolt"
|
||||
*/
|
||||
|
||||
/* 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
|
||||
icon = 'icons/obj/watercloset.dmi'
|
||||
item_icons = null
|
||||
icon_state = "rubberducky"
|
||||
item_state = "rubberducky"
|
||||
charge_cost = 0
|
||||
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
|
||||
user << "You inform the Icarus to switch to the main guns."
|
||||
else
|
||||
projectile_type = /obj/item/projectile/icarus/pointdefense
|
||||
user << "You inform the Icarus to switch to the point-defense lasers."
|
||||
|
||||
. = ..()
|
||||
|
||||
/obj/item/weapon/gun/energy/icarus/update_icon()
|
||||
return
|
||||
|
||||
/obj/item/weapon/gun/energy/icarus/verb/SetIcarusAngle()
|
||||
set src in usr
|
||||
set name = "Set Firing Angle"
|
||||
set desc = "Sets the angle from which the icarus will fire."
|
||||
set category = "Object"
|
||||
set name = "Use Scope"
|
||||
set popup_menu = 1
|
||||
|
||||
zoom()
|
||||
Icarus_SetPosition(usr)
|
||||
|
||||
|
||||
/obj/item/weapon/gun/energy/variable
|
||||
name = "abstract weapon"
|
||||
desc = "It seems to shift and flow as you watch."
|
||||
charge_cost = 0
|
||||
silenced = 1
|
||||
|
||||
/obj/item/weapon/gun/energy/variable/update_icon()
|
||||
return
|
||||
|
||||
/obj/item/weapon/gun/energy/variable/attack_self(mob/living/user as mob)
|
||||
var/type = input(user,"What projectile type?","Projectile", null) as null|anything in typesof(/obj/item/projectile)
|
||||
if(!type)
|
||||
return ..()
|
||||
projectile_type = type
|
||||
. = ..()
|
||||
|
||||
@@ -5,51 +5,30 @@
|
||||
item_state = null //so the human update icon uses the icon_state instead.
|
||||
fire_sound = 'sound/weapons/Taser.ogg'
|
||||
charge_cost = 100
|
||||
projectile_type = "/obj/item/projectile/beam/stun"
|
||||
cell_type = "/obj/item/weapon/cell/crap"
|
||||
projectile_type = /obj/item/projectile/beam/stun
|
||||
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
|
||||
name = "mounted taser gun"
|
||||
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
|
||||
name = "taser gun"
|
||||
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
|
||||
name = "stun revolver"
|
||||
desc = "A high-tech revolver that fires stun cartridges. The stun cartridges can be recharged using a conventional energy weapon recharger."
|
||||
icon_state = "stunrevolver"
|
||||
fire_sound = 'sound/weapons/Taser.ogg'
|
||||
item_state = "stunrevolver"
|
||||
fire_sound = 'sound/weapons/Gunshot.ogg'
|
||||
origin_tech = "combat=3;materials=3;powerstorage=2"
|
||||
charge_cost = 125
|
||||
projectile_type = "/obj/item/projectile/beam/stun"
|
||||
cell_type = "/obj/item/weapon/cell"
|
||||
|
||||
projectile_type = /obj/item/projectile/energy/electrode/stunshot
|
||||
cell_type = /obj/item/weapon/cell
|
||||
|
||||
|
||||
/obj/item/weapon/gun/energy/crossbow
|
||||
@@ -60,43 +39,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
|
||||
projectile_type = /obj/item/projectile/energy/bolt
|
||||
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"
|
||||
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"
|
||||
projectile_type = /obj/item/projectile/energy/bolt/large
|
||||
|
||||
@@ -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 = "<FONT color=black>[temperature] ([round(temperature-T0C)]°C) ([round(temperature*1.8-459.67)]°F)</FONT>"
|
||||
/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 = "<FONT color=black>[temperature] ([round(temperature-T0C)]°C) ([round(temperature*1.8-459.67)]°F)</FONT>"
|
||||
else
|
||||
temp_text = "<FONT color=blue>[temperature] ([round(temperature-T0C)]°C) ([round(temperature*1.8-459.67)]°F)</FONT>"
|
||||
|
||||
var/dat = {"<B>Freeze Gun Configuration: </B><BR>
|
||||
Current output temperature: [temp_text]<BR>
|
||||
Target output temperature: <A href='?src=\ref[src];temp=-100'>-</A> <A href='?src=\ref[src];temp=-10'>-</A> <A href='?src=\ref[src];temp=-1'>-</A> [current_temperature] <A href='?src=\ref[src];temp=1'>+</A> <A href='?src=\ref[src];temp=10'>+</A> <A href='?src=\ref[src];temp=100'>+</A><BR>
|
||||
"}
|
||||
|
||||
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 1
|
||||
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 = "<FONT color=blue>[temperature] ([round(temperature-T0C)]°C) ([round(temperature*1.8-459.67)]°F)</FONT>"
|
||||
|
||||
var/dat = {"<B>Freeze Gun Configuration: </B><BR>
|
||||
Current output temperature: [temp_text]<BR>
|
||||
Target output temperature: <A href='?src=\ref[src];temp=-100'>-</A> <A href='?src=\ref[src];temp=-10'>-</A> <A href='?src=\ref[src];temp=-1'>-</A> [current_temperature] <A href='?src=\ref[src];temp=1'>+</A> <A href='?src=\ref[src];temp=10'>+</A> <A href='?src=\ref[src];temp=100'>+</A><BR>
|
||||
"}
|
||||
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
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/obj/item/weapon/gun/launcher
|
||||
name = "launcher"
|
||||
desc = "A device that launches things."
|
||||
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
|
||||
+51
-47
@@ -48,46 +48,43 @@
|
||||
/obj/item/weapon/gun/launcher/crossbow
|
||||
name = "powered crossbow"
|
||||
desc = "A 2557AD twist on an old classic. Pick up that can."
|
||||
icon = 'icons/obj/weapons.dmi'
|
||||
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 +95,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 +103,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].","<span class='notice'>You begin to draw back the string of [src].</span>")
|
||||
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].","<span class='warning'>You stop drawing back and relax the string of [src].</span>")
|
||||
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]!","<span class='notice'>You continue drawing back the string of [src]!</span>")
|
||||
|
||||
/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 << "<span class='notice'>You jam [cell] into [src] and wire it to the firing coil.</span>"
|
||||
superheat_rod(user)
|
||||
else
|
||||
@@ -168,14 +172,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 << "<span class='notice'>[in_chamber] plinks and crackles as it begins to glow red-hot.</span>"
|
||||
in_chamber.throwforce = 15
|
||||
in_chamber.icon_state = "metal-rod-superheated"
|
||||
user << "<span class='notice'>[bolt] plinks and crackles as it begins to glow red-hot.</span>"
|
||||
bolt.throwforce = 15
|
||||
bolt.icon_state = "metal-rod-superheated"
|
||||
cell.use(500)
|
||||
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/obj/item/weapon/gun/launcher/grenade
|
||||
name = "grenade launcher"
|
||||
desc = "A bulky pump-action grenade launcher. Holds up to 6 grenades in a revolving magazine."
|
||||
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 = 5 //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 << "<span class='warning'>You pump [src], loading \a [next] into the chamber.</span>"
|
||||
else
|
||||
M << "<span class='warning'>You pump [src], but the magazine is empty.</span>"
|
||||
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/proc/load(obj/item/weapon/grenade/G, mob/user)
|
||||
if(grenades.len >= max_grenades)
|
||||
user << "<span class='warning'>[src] is full.</span>"
|
||||
return
|
||||
user.remove_from_mob(G)
|
||||
G.loc = src
|
||||
grenades.Insert(1, G) //add to the head of the list, so that it is loaded on the next pump
|
||||
user.visible_message("[user] inserts \a [G] into [src].", "<span class='notice'>You insert \a [G] into [src].</span>")
|
||||
|
||||
/obj/item/weapon/gun/launcher/grenade/proc/unload(mob/user)
|
||||
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].", "<span class='notice'>You remove \a [G] from [src].</span>")
|
||||
else
|
||||
user << "<span class='warning'>[src] is empty.</span>"
|
||||
|
||||
/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)))
|
||||
load(I, user)
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/weapon/gun/launcher/grenade/attack_hand(mob/user)
|
||||
if(user.get_inactive_hand() == src)
|
||||
unload(user)
|
||||
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
|
||||
|
||||
//Underslung grenade launcher to be used with the Z8
|
||||
/obj/item/weapon/gun/launcher/grenade/underslung
|
||||
name = "underslung grenade launcher"
|
||||
desc = "Not much more than a tube and a firing mechanism, this grenade launcher is designed to be fitted to a rifle."
|
||||
w_class = 3
|
||||
force = 5
|
||||
max_grenades = 0
|
||||
|
||||
/obj/item/weapon/gun/launcher/grenade/underslung/attack_self()
|
||||
return
|
||||
|
||||
//load and unload directly into chambered
|
||||
/obj/item/weapon/gun/launcher/grenade/underslung/load(obj/item/weapon/grenade/G, mob/user)
|
||||
if(chambered)
|
||||
user << "<span class='warning'>[src] is already loaded.</span>"
|
||||
return
|
||||
user.remove_from_mob(G)
|
||||
G.loc = src
|
||||
chambered = G
|
||||
user.visible_message("[user] load \a [G] into [src].", "<span class='notice'>You load \a [G] into [src].</span>")
|
||||
|
||||
/obj/item/weapon/gun/launcher/grenade/underslung/unload(mob/user)
|
||||
if(chambered)
|
||||
user.put_in_hands(chambered)
|
||||
user.visible_message("[user] removes \a [chambered] from [src].", "<span class='notice'>You remove \a [chambered] from [src].</span>")
|
||||
chambered = null
|
||||
else
|
||||
user << "<span class='warning'>[src] is empty.</span>"
|
||||
+31
-38
@@ -1,9 +1,9 @@
|
||||
/obj/item/weapon/gun/launcher/pneumatic
|
||||
name = "pneumatic cannon"
|
||||
desc = "A large gas-powered cannon."
|
||||
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"
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
var/fire_pressure // Used in fire checks/pressure checks.
|
||||
var/max_w_class = 3 // Hopper intake size.
|
||||
var/max_combined_w_class = 20 // Total internal storage size.
|
||||
var/max_storage_space = 20 // Total internal storage size.
|
||||
var/obj/item/weapon/tank/tank = null // Tank of gas for use in firing the cannon.
|
||||
var/obj/item/weapon/storage/tank_container // Something to hold the tank item so we don't accidentally fire it.
|
||||
var/pressure_setting = 10 // Percentage of the gas in the tank used to fire the projectile.
|
||||
@@ -61,17 +61,16 @@
|
||||
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
|
||||
if(total_stored + W.w_class <= max_combined_w_class)
|
||||
total_stored += O.get_storage_cost()
|
||||
if(total_stored + W.get_storage_cost() <= max_storage_space)
|
||||
user.remove_from_mob(W)
|
||||
W.loc = src
|
||||
user << "You shove [W] into the hopper."
|
||||
else
|
||||
user << "That won't fit into the hopper - it's full."
|
||||
user << "That won't fit into the hopper - it's too full."
|
||||
return
|
||||
else
|
||||
user << "That won't fit into the hopper."
|
||||
@@ -79,9 +78,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 +85,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 +108,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.
|
||||
|
||||
@@ -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].")
|
||||
..()
|
||||
@@ -0,0 +1,137 @@
|
||||
/obj/item/weapon/syringe_cartridge
|
||||
name = "syringe gun cartridge"
|
||||
desc = "An impact-triggered compressed gas cartridge that can be 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 << "<span class='notice'>You carefully insert [syringe] into [src].</span>"
|
||||
user.remove_from_mob(syringe)
|
||||
syringe.loc = src
|
||||
sharp = 1
|
||||
name = "syringe dart"
|
||||
update_icon()
|
||||
|
||||
/obj/item/weapon/syringe_cartridge/attack_self(mob/user)
|
||||
if(syringe)
|
||||
user << "<span class='notice'>You remove [syringe] from [src].</span>"
|
||||
user.put_in_hands(syringe)
|
||||
syringe = null
|
||||
sharp = initial(sharp)
|
||||
name = initial(name)
|
||||
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_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].", "<span class='warning'>You unlatch and carefully relax the bolt on [src], unloading the spring.</span>")
|
||||
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.", "<span class='warning'>You draw back the bolt on the [src], loading the spring!</span>")
|
||||
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 << "<span class='warning'>[src] is empty.</span>"
|
||||
return
|
||||
if(next)
|
||||
user << "<span class='warning'>[src]'s cover is locked shut.</span>"
|
||||
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].", "<span class='notice'>You remove \a [C] from [src].</span>")
|
||||
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 << "<span class='warning'>[src] is full!</span>"
|
||||
return
|
||||
user.remove_from_mob(C)
|
||||
C.loc = src
|
||||
darts += C //add to the end
|
||||
user.visible_message("[user] inserts \a [C] into [src].", "<span class='notice'>You insert \a [C] into [src].</span>")
|
||||
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"
|
||||
item_state = "rapidsyringegun"
|
||||
max_darts = 5
|
||||
@@ -1,119 +1,205 @@
|
||||
#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/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
|
||||
//TODO generalize ammo icon states for guns
|
||||
//var/magazine_states = 0
|
||||
//var/list/icon_keys = list() //keys
|
||||
//var/list/ammo_states = list() //values
|
||||
|
||||
/obj/item/weapon/gun/projectile/New()
|
||||
..()
|
||||
for(var/i = 1, i <= max_shells, i++)
|
||||
loaded += new ammo_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()
|
||||
return
|
||||
|
||||
/obj/item/weapon/gun/projectile/consume_next_projectile()
|
||||
//get the next casing
|
||||
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
|
||||
|
||||
if (chambered)
|
||||
return chambered.BB
|
||||
return null
|
||||
|
||||
/obj/item/weapon/gun/projectile/handle_post_fire()
|
||||
..()
|
||||
if(chambered)
|
||||
chambered.expend()
|
||||
process_chambered()
|
||||
|
||||
/obj/item/weapon/gun/projectile/handle_click_empty()
|
||||
..()
|
||||
process_chambered()
|
||||
|
||||
/obj/item/weapon/gun/projectile/proc/process_chambered()
|
||||
if (!chambered) return
|
||||
|
||||
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
|
||||
|
||||
if(handle_casings != HOLD_CASINGS)
|
||||
chambered = null
|
||||
|
||||
|
||||
/obj/item/weapon/gun/projectile/load_into_chamber()
|
||||
if(in_chamber)
|
||||
return 1 //{R}
|
||||
//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
|
||||
|
||||
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
|
||||
switch(AM.mag_type)
|
||||
if(MAGAZINE)
|
||||
if(ammo_magazine)
|
||||
user << "<span class='warning'>[src] already has a magazine loaded.</span>" //already a magazine here
|
||||
return
|
||||
user.remove_from_mob(AM)
|
||||
AM.loc = src
|
||||
ammo_magazine = AM
|
||||
user.visible_message("[user] inserts [AM] into [src].", "<span class='notice'>You insert [AM] into [src].</span>")
|
||||
playsound(src.loc, 'sound/weapons/flipblade.ogg', 50, 1)
|
||||
if(SPEEDLOADER)
|
||||
if(loaded.len >= max_shells)
|
||||
user << "<span class='warning'>[src] is full!</span>"
|
||||
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].", "<span class='notice'>You load [count] round\s into [src].</span>")
|
||||
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 << "<span class='warning'>[src] is full.</span>"
|
||||
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].", "<span class='notice'>You insert \a [C] into [src].</span>")
|
||||
playsound(src.loc, 'sound/weapons/empty.ogg', 50, 1)
|
||||
|
||||
update_icon()
|
||||
|
||||
//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].", "<span class='notice'>You remove [ammo_magazine] from [src].</span>")
|
||||
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].", "<span class='notice'>You unload [count] round\s from [src].</span>")
|
||||
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].", "<span class='notice'>You remove \a [C] from [src].</span>")
|
||||
else
|
||||
user << "<span class='warning'>[src] is empty.</span>"
|
||||
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 << "<span class='warning'>The magazine is empty!</span>"
|
||||
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!",
|
||||
"<span class='notice'>[ammo_magazine] falls out and clatters on the floor!</span>"
|
||||
)
|
||||
if(auto_eject_sound)
|
||||
playsound(user, auto_eject_sound, 40, 1)
|
||||
ammo_magazine.update_icon()
|
||||
ammo_magazine = null
|
||||
update_icon() //make sure to do this after unsetting ammo_magazine
|
||||
|
||||
/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
|
||||
|
||||
@@ -2,71 +2,153 @@
|
||||
name = "submachine gun"
|
||||
desc = "A lightweight, fast firing gun. Uses 9mm rounds."
|
||||
icon_state = "saber" //ugly
|
||||
w_class = 3.0
|
||||
max_shells = 18
|
||||
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
|
||||
|
||||
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/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 = 2
|
||||
load_method = MAGAZINE
|
||||
magazine_type = /obj/item/ammo_magazine/a12mm
|
||||
auto_eject = 1
|
||||
auto_eject_sound = 'sound/weapons/smg_empty_alarm.ogg'
|
||||
|
||||
/obj/item/weapon/gun/projectile/automatic/c20r/update_icon()
|
||||
..()
|
||||
if(ammo_magazine)
|
||||
icon_state = "c20r-[round(ammo_magazine.stored_ammo.len,4)]"
|
||||
else
|
||||
icon_state = "c20r"
|
||||
return
|
||||
|
||||
New()
|
||||
/obj/item/weapon/gun/projectile/automatic/sts35
|
||||
name = "\improper STS-35 automatic rifle"
|
||||
desc = "A durable, rugged looking automatic weapon of a make popular on the frontier worlds. Uses 7.62mm rounds. It is unmarked."
|
||||
icon_state = "arifle"
|
||||
item_state = null
|
||||
w_class = 4
|
||||
force = 10
|
||||
caliber = "a762"
|
||||
origin_tech = "combat=6;materials=1;syndicate=4"
|
||||
slot_flags = SLOT_BACK
|
||||
load_method = MAGAZINE
|
||||
magazine_type = /obj/item/ammo_magazine/c762
|
||||
|
||||
/obj/item/weapon/gun/projectile/automatic/sts35/update_icon()
|
||||
..()
|
||||
icon_state = (ammo_magazine)? "arifle-0" : "arifle"
|
||||
update_held_icon()
|
||||
|
||||
/obj/item/weapon/gun/projectile/automatic/wt550
|
||||
name = "\improper W-T 550 Saber"
|
||||
desc = "A cheap, mass produced Ward-Takahashi PDW. Uses 9mm rounds."
|
||||
icon_state = "wt550"
|
||||
item_state = "wt550"
|
||||
w_class = 3
|
||||
caliber = "9mm"
|
||||
origin_tech = "combat=5;materials=2"
|
||||
slot_flags = SLOT_BELT
|
||||
ammo_type = "/obj/item/ammo_casing/c9mmr"
|
||||
fire_sound = 'sound/weapons/Gunshot_smg.ogg'
|
||||
load_method = MAGAZINE
|
||||
magazine_type = /obj/item/ammo_magazine/mc9mmt/rubber
|
||||
|
||||
/obj/item/weapon/gun/projectile/automatic/wt550/update_icon()
|
||||
..()
|
||||
if(ammo_magazine)
|
||||
icon_state = "wt550-[round(ammo_magazine.stored_ammo.len,4)]"
|
||||
else
|
||||
icon_state = "wt550"
|
||||
return
|
||||
|
||||
/obj/item/weapon/gun/projectile/automatic/z8
|
||||
name = "\improper Z8 Bulldog"
|
||||
desc = "An older model bullpup carbine, made by the now defunct Zendai Foundries. Uses armor piercing 5.56mm rounds. Makes you feel like a space marine when you hold it."
|
||||
icon_state = "carbine"
|
||||
item_state = "z8carbine"
|
||||
w_class = 4
|
||||
force = 10
|
||||
caliber = "a556"
|
||||
origin_tech = "combat=8;materials=3"
|
||||
ammo_type = "/obj/item/ammo_casing/a556"
|
||||
fire_sound = 'sound/weapons/Gunshot.ogg'
|
||||
slot_flags = SLOT_BACK
|
||||
load_method = MAGAZINE
|
||||
magazine_type = /obj/item/ammo_magazine/a556
|
||||
auto_eject = 1
|
||||
auto_eject_sound = 'sound/weapons/smg_empty_alarm.ogg'
|
||||
|
||||
var/use_launcher = 0
|
||||
var/obj/item/weapon/gun/launcher/grenade/underslung/launcher
|
||||
|
||||
/obj/item/weapon/gun/projectile/automatic/z8/New()
|
||||
..()
|
||||
launcher = new(src)
|
||||
|
||||
/obj/item/weapon/gun/projectile/automatic/z8/attack_self(mob/user)
|
||||
use_launcher = !use_launcher
|
||||
user << "<span class='notice'>You switch to [use_launcher? "\the [launcher]" : "firing normally"].</span>"
|
||||
|
||||
/obj/item/weapon/gun/projectile/automatic/z8/attackby(obj/item/I, mob/user)
|
||||
if((istype(I, /obj/item/weapon/grenade)))
|
||||
launcher.load(I, user)
|
||||
else
|
||||
..()
|
||||
empty_mag = new /obj/item/ammo_magazine/a12mm/empty(src)
|
||||
update_icon()
|
||||
return
|
||||
|
||||
|
||||
afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag)
|
||||
/obj/item/weapon/gun/projectile/automatic/z8/attack_hand(mob/user)
|
||||
if(user.get_inactive_hand() == src && use_launcher)
|
||||
launcher.unload(user)
|
||||
else
|
||||
..()
|
||||
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()
|
||||
/obj/item/weapon/gun/projectile/automatic/z8/Fire(atom/target, mob/living/user, params, pointblank=0, reflex=0)
|
||||
if(use_launcher)
|
||||
launcher.Fire(target, user, params, pointblank, reflex)
|
||||
if(!launcher.chambered)
|
||||
use_launcher = 0 //switch back automatically
|
||||
else
|
||||
..()
|
||||
if(empty_mag)
|
||||
icon_state = "c20r-[round(loaded.len,4)]"
|
||||
else
|
||||
icon_state = "c20r"
|
||||
return
|
||||
|
||||
/obj/item/weapon/gun/projectile/automatic/z8/update_icon()
|
||||
..()
|
||||
if(ammo_magazine)
|
||||
icon_state = "carbine-[round(ammo_magazine.stored_ammo.len,2)]"
|
||||
else
|
||||
icon_state = "carbine"
|
||||
return
|
||||
|
||||
/obj/item/weapon/gun/projectile/automatic/z8/examine(mob/user)
|
||||
..()
|
||||
if(launcher.chambered)
|
||||
user << "\The [launcher] has \a [launcher.chambered] loaded."
|
||||
else
|
||||
user << "\The [launcher] is empty."
|
||||
|
||||
/obj/item/weapon/gun/projectile/automatic/l6_saw
|
||||
name = "\improper L6 SAW"
|
||||
@@ -74,74 +156,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"
|
||||
origin_tech = "combat=6;materials=1;syndicate=2"
|
||||
slot_flags = SLOT_BACK
|
||||
ammo_type = "/obj/item/ammo_casing/a762"
|
||||
fire_sound = 'sound/weapons/Gunshot_smg.ogg'
|
||||
load_method = 2
|
||||
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 << "<span class='notice'>You [cover_open ? "open" : "close"] [src]'s cover.</span>"
|
||||
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(ammo_magazine.stored_ammo.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 << "<span class='notice'>[src]'s cover is open! Close it before firing!</span>"
|
||||
else
|
||||
..()
|
||||
update_icon()
|
||||
user << "<span class='warning'>[src]'s cover is open! Close it before firing!</span>"
|
||||
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 << "<span class='notice'>You remove the magazine from [src].</span>"
|
||||
|
||||
|
||||
/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 << "<span class='notice'>[src]'s cover is closed! You can't insert a new mag!</span>"
|
||||
user << "<span class='warning'>You need to open the cover to load [src].</span>"
|
||||
return
|
||||
else if(cover_open && mag_inserted)
|
||||
user << "<span class='notice'>[src] already has a magazine inserted!</span>"
|
||||
return
|
||||
else if(cover_open && !mag_inserted)
|
||||
mag_inserted = 1
|
||||
user << "<span class='notice'>You insert the magazine!</span>"
|
||||
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 */
|
||||
|
||||
/obj/item/weapon/gun/projectile/automatic/l6_saw/unload_ammo(mob/user, var/allow_dump=1)
|
||||
if(!cover_open)
|
||||
return
|
||||
..()
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
/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
|
||||
|
||||
muzzle_type = null
|
||||
|
||||
/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"
|
||||
item_state = null
|
||||
|
||||
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 = "<b>[src] mixing control:</b><br><br>"
|
||||
|
||||
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 += "<br> [R.volume] units of [R.name], "
|
||||
if (check_beaker_mixing(B))
|
||||
dat += text("<A href='?src=\ref[src];stop_mix=[i]'><font color='green'>Mixing</font></A> ")
|
||||
else
|
||||
dat += text("<A href='?src=\ref[src];mix=[i]'><font color='red'>Not mixing</font></A> ")
|
||||
else
|
||||
dat += "nothing."
|
||||
dat += " \[<A href='?src=\ref[src];eject=[i]'>Eject</A>\]<br>"
|
||||
i++
|
||||
else
|
||||
dat += "There are no beakers inserted!<br><br>"
|
||||
|
||||
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 += "<font color='red'>The dart cartridge is empty!</font>"
|
||||
dat += " \[<A href='?src=\ref[src];eject_cart=1'>Eject</A>\]"
|
||||
|
||||
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)
|
||||
if(..()) return 1
|
||||
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")
|
||||
@@ -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 << "<span class='warning'>[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("<span class='warning'>[user] fires [src][reflex ? " by reflex":""]!</span>", \
|
||||
"<span class='warning'>You fire [src][reflex ? "by reflex":""]!</span>", \
|
||||
"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
|
||||
@@ -1,52 +1,85 @@
|
||||
/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/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 << "<span class='notice'>You don't feel cool enough to name this gun, chump.</span>"
|
||||
return 0
|
||||
|
||||
var/input = sanitizeSafe(input("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/sec
|
||||
desc = "A NanoTrasen designed sidearm, found pretty much everywhere humans are. Uses less-than-lethal .45 rounds."
|
||||
name = "\improper NT Mk58"
|
||||
icon_state = "secguncomp"
|
||||
magazine_type = /obj/item/ammo_magazine/c45m/rubber
|
||||
caliber = ".45"
|
||||
origin_tech = "combat=2;materials=2"
|
||||
load_method = MAGAZINE
|
||||
|
||||
/obj/item/weapon/gun/projectile/sec/flash
|
||||
name = "\improper NT Mk58 signal pistol"
|
||||
desc = "A NanoTrasen designed sidearm, found pretty much everywhere humans are. Uses .45 signal flash rounds."
|
||||
magazine_type = /obj/item/ammo_magazine/c45m/flash
|
||||
|
||||
/obj/item/weapon/gun/projectile/sec/wood
|
||||
desc = "A Nanotrasen designed sidearm, this one has a sweet wooden grip. Uses less-than-lethal .45 rounds."
|
||||
name = "\improper Custom NT Mk58"
|
||||
icon_state = "secgundark"
|
||||
|
||||
/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"
|
||||
item_state = "deagle"
|
||||
force = 14.0
|
||||
max_shells = 7
|
||||
caliber = ".50"
|
||||
ammo_type ="/obj/item/ammo_casing/a50"
|
||||
load_method = 2
|
||||
New()
|
||||
..()
|
||||
empty_mag = new /obj/item/ammo_magazine/a50/empty(src)
|
||||
update_icon()
|
||||
return
|
||||
|
||||
|
||||
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
|
||||
load_method = MAGAZINE
|
||||
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'
|
||||
|
||||
|
||||
|
||||
@@ -59,57 +92,37 @@
|
||||
fire_sound = 'sound/effects/Explosion1.ogg'
|
||||
origin_tech = "combat=3"
|
||||
ammo_type = "/obj/item/ammo_casing/a75"
|
||||
load_method = 2
|
||||
New()
|
||||
..()
|
||||
empty_mag = new /obj/item/ammo_magazine/a75/empty(src)
|
||||
update_icon()
|
||||
return
|
||||
load_method = MAGAZINE
|
||||
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"
|
||||
item_state = null
|
||||
w_class = 2
|
||||
max_shells = 8
|
||||
caliber = "9mm"
|
||||
silenced = 0
|
||||
origin_tech = "combat=2;materials=2;syndicate=2"
|
||||
ammo_type = "/obj/item/ammo_casing/c9mm"
|
||||
load_method = 2
|
||||
load_method = MAGAZINE
|
||||
magazine_type = /obj/item/ammo_magazine/mc9mm
|
||||
|
||||
/obj/item/weapon/gun/projectile/pistol/New()
|
||||
..()
|
||||
empty_mag = new /obj/item/ammo_magazine/mc9mm/empty(src)
|
||||
return
|
||||
|
||||
/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)
|
||||
..()
|
||||
@@ -122,7 +135,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
|
||||
|
||||
@@ -1,184 +1,43 @@
|
||||
/obj/item/weapon/gun/projectile/detective
|
||||
/obj/item/weapon/gun/projectile/revolver
|
||||
name = "revolver"
|
||||
desc = "A classic revolver. Uses .357 ammo"
|
||||
icon_state = "revolver"
|
||||
item_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
|
||||
|
||||
/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."
|
||||
|
||||
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 << "<span class='danger'>[src] blows up in your face.</span>"
|
||||
M.take_organ_damage(0,20)
|
||||
M.drop_item()
|
||||
del(src)
|
||||
return 0
|
||||
var/mob/M = usr
|
||||
if(!M.mind) return 0
|
||||
if(!M.mind.assigned_role == "Detective")
|
||||
M << "<span class='notice'>You don't feel cool enough to name this gun, chump.</span>"
|
||||
return 0
|
||||
|
||||
var/input = sanitizeSafe(input("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 << "<span class='notice'>You don't feel cool enough to name this gun, chump.</span>"
|
||||
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 << "<span class='notice'>You begin to reinforce the barrel of [src].</span>"
|
||||
if(loaded.len)
|
||||
afterattack(user, user) //you know the drill
|
||||
playsound(user, fire_sound, 50, 1)
|
||||
user.visible_message("<span class='danger'>[src] goes off!</span>", "<span class='danger'>[src] goes off in your face!</span>")
|
||||
return
|
||||
if(do_after(user, 30))
|
||||
if(loaded.len)
|
||||
user << "<span class='notice'>You can't modify it!</span>"
|
||||
return
|
||||
caliber = "357"
|
||||
desc = "The barrel and chamber assembly seems to have been modified."
|
||||
user << "<span class='warning'>You reinforce the barrel of [src]! Now it will fire .357 rounds.</span>"
|
||||
else if (caliber == "357")
|
||||
user << "<span class='notice'>You begin to revert the modifications to [src].</span>"
|
||||
if(loaded.len)
|
||||
afterattack(user, user) //and again
|
||||
playsound(user, fire_sound, 50, 1)
|
||||
user.visible_message("<span class='danger'>[src] goes off!</span>", "<span class='danger'>[src] goes off in your face!</span>")
|
||||
return
|
||||
if(do_after(user, 30))
|
||||
if(loaded.len)
|
||||
user << "<span class='notice'>You can't modify it!</span>"
|
||||
return
|
||||
caliber = "38"
|
||||
desc = initial(desc)
|
||||
user << "<span class='warning'>You remove the modifications on [src]! Now it will fire .38 rounds.</span>"
|
||||
|
||||
|
||||
/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 = 2
|
||||
|
||||
/obj/item/weapon/gun/projectile/detective/semiauto/New()
|
||||
..()
|
||||
empty_mag = new /obj/item/ammo_magazine/c45r/empty(src)
|
||||
return
|
||||
|
||||
/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 << "<span class='notice'>The Magazine falls out and clatters on the floor!</span>"
|
||||
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 == 2) && 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("<span class='warning'>[user] loads a single bullet into the revolver and spins the chamber.</span>", "<span class='warning'>You load a single bullet into the chamber and spin it.</span>")
|
||||
else
|
||||
user.visible_message("<span class='warning'>[user] spins the chamber of the revolver.</span>", "<span class='warning'>You spin the revolver's chamber.</span>")
|
||||
if(getAmmo() > 0)
|
||||
Spin()
|
||||
update_icon()
|
||||
return
|
||||
|
||||
/obj/item/weapon/gun/projectile/russian/attack_self(mob/user as mob)
|
||||
user.visible_message("<span class='warning'>[user] spins the chamber of the revolver.</span>", "<span class='warning'>You spin the revolver's chamber.</span>")
|
||||
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("<span class='danger'>[user.name] fires [src] at \his head!</span>", "<span class='danger'>You fire [src] at your head!</span>", "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
|
||||
..()
|
||||
|
||||
@@ -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."
|
||||
@@ -10,127 +10,85 @@
|
||||
slot_flags = SLOT_BACK
|
||||
caliber = "shotgun"
|
||||
origin_tech = "combat=4;materials=2"
|
||||
ammo_type = "/obj/item/ammo_casing/shotgun/beanbag"
|
||||
load_method = SINGLE_CASING
|
||||
ammo_type = /obj/item/ammo_casing/shotgun/beanbag
|
||||
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
|
||||
|
||||
|
||||
attack_self(mob/living/user as mob)
|
||||
if(recentpump) return
|
||||
/obj/item/weapon/gun/projectile/shotgun/pump/attack_self(mob/living/user as mob)
|
||||
if(world.time >= recentpump + 10)
|
||||
pump(user)
|
||||
recentpump = 1
|
||||
spawn(10)
|
||||
recentpump = 0
|
||||
return
|
||||
recentpump = world.time
|
||||
|
||||
/obj/item/weapon/gun/projectile/shotgun/pump/proc/pump(mob/M as mob)
|
||||
playsound(M, 'sound/weapons/shotgunpump.ogg', 60, 1)
|
||||
|
||||
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
|
||||
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
|
||||
item_state = "cshotgun"
|
||||
origin_tech = "combat=5;materials=2"
|
||||
ammo_type = "/obj/item/ammo_casing/shotgun"
|
||||
max_shells = 7 //match the ammo box capacity, also it can hold a round in the chamber anyways, for a total of 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"
|
||||
item_state = "dshotgun"
|
||||
//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"
|
||||
ammo_type = /obj/item/ammo_casing/shotgun/beanbag
|
||||
|
||||
New()
|
||||
for(var/i = 1, i <= max_shells, i++)
|
||||
loaded += new ammo_type(src)
|
||||
/obj/item/weapon/gun/projectile/shotgun/doublebarrel/flare
|
||||
name = "signal shotgun"
|
||||
desc = "A double-barreled shotgun meant to fire signal flash shells."
|
||||
ammo_type = /obj/item/ammo_casing/shotgun/flash
|
||||
|
||||
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 << "<span class='notice'>\The [src] is empty.</span>"
|
||||
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 << "<span class='notice'>You break \the [src].</span>"
|
||||
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 << "<span class='notice'>You load a shell into \the [src]!</span>"
|
||||
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 << "<span class='notice'>You begin to shorten the barrel of \the [src].</span>"
|
||||
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 << "<span class='notice'>You begin to shorten the barrel of \the [src].</span>"
|
||||
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("<span class='danger'>The shotgun goes off!</span>", "<span class='danger'>The shotgun goes off in your face!</span>")
|
||||
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 << "<span class='warning'>You shorten the barrel of \the [src]!</span>"
|
||||
user.visible_message("<span class='danger'>The shotgun goes off!</span>", "<span class='danger'>The shotgun goes off in your face!</span>")
|
||||
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 << "<span class='warning'>You shorten the barrel of \the [src]!</span>"
|
||||
else
|
||||
..()
|
||||
@@ -0,0 +1,67 @@
|
||||
/obj/item/weapon/gun/projectile/heavysniper
|
||||
name = "\improper PTR-7 rifle"
|
||||
desc = "A portable anti-armour rifle fitted with a scope. Originally designed to used against armoured exosuits, it is capable of punching through windows and non-reinforced walls with ease. Fires armor piercing 14.5mm shells."
|
||||
icon_state = "heavysniper"
|
||||
item_state = "l6closednomag" //placeholder
|
||||
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 << "<span class='notice'>You work the bolt open, ejecting [chambered]!</span>"
|
||||
chambered.loc = get_turf(src)
|
||||
loaded -= chambered
|
||||
chambered = null
|
||||
else
|
||||
user << "<span class='notice'>You work the bolt open.</span>"
|
||||
else
|
||||
user << "<span class='notice'>You work the bolt closed.</span>"
|
||||
bolt_open = 0
|
||||
add_fingerprint(user)
|
||||
update_icon()
|
||||
|
||||
/obj/item/weapon/gun/projectile/heavysniper/special_check(mob/user)
|
||||
if(bolt_open)
|
||||
user << "<span class='warning'>You can't fire [src] while the bolt is open!</span>"
|
||||
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)
|
||||
|
||||
@@ -36,8 +36,10 @@
|
||||
var/damage = 10
|
||||
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/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/projectile_type = "/obj/item/projectile"
|
||||
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/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.
|
||||
//Effects
|
||||
var/stun = 0
|
||||
@@ -49,117 +51,302 @@
|
||||
var/drowsy = 0
|
||||
var/agony = 0
|
||||
var/embed = 0 // whether or not the projectile can embed itself in the mob
|
||||
|
||||
var/hitscan = 0 // whether the projectile should be hitscan
|
||||
|
||||
proc/on_hit(var/atom/target, var/blocked = 0)
|
||||
if(blocked >= 2) return 0//Full block
|
||||
if(!isliving(target)) return 0
|
||||
if(isanimal(target)) return 0
|
||||
var/mob/living/L = target
|
||||
L.apply_effects(stun, weaken, paralyze, irradiate, stutter, eyeblur, drowsy, agony, blocked) // add in AGONY!
|
||||
// effect types to be used
|
||||
var/muzzle_type
|
||||
var/tracer_type
|
||||
var/impact_type
|
||||
|
||||
var/datum/plot_vector/trajectory // used to plot the path of the projectile
|
||||
var/datum/vector_loc/location // current location of the projectile in pixel space
|
||||
var/matrix/effect_transform // matrix to rotate and scale projectile effects - putting it here so it doesn't
|
||||
// have to be recreated multiple times
|
||||
|
||||
//TODO: make it so this is called more reliably, instead of sometimes by bullet_act() and sometimes not
|
||||
/obj/item/projectile/proc/on_hit(var/atom/target, var/blocked = 0, var/def_zone = null)
|
||||
if(blocked >= 2) return 0//Full block
|
||||
if(!isliving(target)) return 0
|
||||
if(isanimal(target)) return 0
|
||||
var/mob/living/L = target
|
||||
L.apply_effects(stun, weaken, paralyze, irradiate, stutter, eyeblur, drowsy, agony, blocked) // add in AGONY!
|
||||
return 1
|
||||
|
||||
//called when the projectile stops flying because it collided with something
|
||||
/obj/item/projectile/proc/on_impact(var/atom/A)
|
||||
impact_effect(effect_transform) // generate impact effect
|
||||
return
|
||||
|
||||
//Checks if the projectile is eligible for embedding. Not that it necessarily will.
|
||||
/obj/item/projectile/proc/can_embed()
|
||||
//embed must be enabled and damage type must be brute
|
||||
if(!embed || damage_type != BRUTE)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
//return 1 if the projectile should be allowed to pass through after all, 0 if not.
|
||||
/obj/item/projectile/proc/check_penetrate(var/atom/A)
|
||||
return 1
|
||||
|
||||
/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/turf/curloc = get_turf(user)
|
||||
var/turf/targloc = get_turf(target)
|
||||
if (!istype(targloc) || !istype(curloc))
|
||||
return 1
|
||||
|
||||
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!
|
||||
firer = user
|
||||
def_zone = user.zone_sel.selecting
|
||||
|
||||
Bump(atom/A as mob|obj|turf|area)
|
||||
if(A == firer)
|
||||
loc = A.loc
|
||||
return 0 //cannot shoot yourself
|
||||
if(user == target) //Shooting yourself
|
||||
user.bullet_act(src, target_zone)
|
||||
on_impact(user)
|
||||
del(src)
|
||||
return 0
|
||||
if(targloc == curloc) //Shooting something in the same turf
|
||||
target.bullet_act(src, target_zone)
|
||||
on_impact(target)
|
||||
del(src)
|
||||
return 0
|
||||
|
||||
if(bumped) return 0
|
||||
var/forcedodge = 0 // force the projectile to pass
|
||||
original = target
|
||||
loc = curloc
|
||||
starting = curloc
|
||||
current = curloc
|
||||
yo = targloc.y - curloc.y + y_offset
|
||||
xo = targloc.x - curloc.x + x_offset
|
||||
|
||||
bumped = 1
|
||||
if(firer && istype(A, /mob))
|
||||
var/mob/M = A
|
||||
if(!istype(A, /mob/living))
|
||||
loc = A.loc
|
||||
return 0// nope.avi
|
||||
shot_from = launcher
|
||||
silenced = launcher.silenced
|
||||
|
||||
var/distance = get_dist(starting,loc)
|
||||
var/miss_modifier = -30
|
||||
spawn()
|
||||
process()
|
||||
|
||||
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 += -30
|
||||
def_zone = get_zone_with_miss_chance(def_zone, M, miss_modifier + 15*distance)
|
||||
return 0
|
||||
|
||||
if(!def_zone)
|
||||
visible_message("\blue \The [src] misses [M] narrowly!")
|
||||
forcedodge = -1
|
||||
else
|
||||
if(silenced)
|
||||
M << "\red You've been shot in the [parse_zone(def_zone)] by the [src.name]!"
|
||||
else
|
||||
visible_message("\red [A.name] is hit by the [src.name] in the [parse_zone(def_zone)]!")//X has fired Y is now given by the guns so you cant tell who shot you if you could not see the shooter
|
||||
if(istype(firer, /mob))
|
||||
M.attack_log += "\[[time_stamp()]\] <b>[firer]/[firer.ckey]</b> shot <b>[M]/[M.ckey]</b> with a <b>[src.type]</b>"
|
||||
firer.attack_log += "\[[time_stamp()]\] <b>[firer]/[firer.ckey]</b> shot <b>[M]/[M.ckey]</b> with a <b>[src.type]</b>"
|
||||
msg_admin_attack("[firer] ([firer.ckey]) shot [M] ([M.ckey]) with a [src] (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[firer.x];Y=[firer.y];Z=[firer.z]'>JMP</a>)") //BS12 EDIT ALG
|
||||
else
|
||||
M.attack_log += "\[[time_stamp()]\] <b>UNKNOWN SUBJECT (No longer exists)</b> shot <b>[M]/[M.ckey]</b> with a <b>[src]</b>"
|
||||
msg_admin_attack("UNKNOWN shot [M] ([M.ckey]) with a [src] (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[firer.x];Y=[firer.y];Z=[firer.z]'>JMP</a>)") //BS12 EDIT ALG
|
||||
//Used to change the direction of the projectile in flight.
|
||||
/obj/item/projectile/proc/redirect(var/new_x, var/new_y, var/atom/starting_loc, var/mob/new_firer=null)
|
||||
original = locate(new_x, new_y, src.z)
|
||||
starting = starting_loc
|
||||
current = starting_loc
|
||||
if(new_firer)
|
||||
firer = src
|
||||
|
||||
if(A)
|
||||
if (!forcedodge)
|
||||
forcedodge = A.bullet_act(src, def_zone) // searches for return value
|
||||
if(forcedodge == -1) // the bullet passes through a dense object!
|
||||
bumped = 0 // reset bumped variable!
|
||||
if(istype(A, /turf))
|
||||
loc = A
|
||||
else
|
||||
loc = A.loc
|
||||
permutated.Add(A)
|
||||
return 0
|
||||
if(istype(A,/turf))
|
||||
for(var/obj/O in A)
|
||||
O.bullet_act(src)
|
||||
for(var/mob/M in A)
|
||||
M.bullet_act(src, def_zone)
|
||||
density = 0
|
||||
invisibility = 101
|
||||
del(src)
|
||||
return 1
|
||||
yo = new_y - starting_loc.y
|
||||
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=0)
|
||||
//accuracy bonus from aiming
|
||||
if (istype(shot_from, /obj/item/weapon/gun))
|
||||
var/obj/item/weapon/gun/daddy = shot_from
|
||||
miss_modifier -= round(15*daddy.accuracy)
|
||||
|
||||
//If you aim at someone beforehead, it'll hit more often.
|
||||
//Kinda balanced by fact you need like 2 seconds to aim
|
||||
//As opposed to no-delay pew pew
|
||||
if (daddy.aim_targets && original in daddy.aim_targets)
|
||||
miss_modifier += -30
|
||||
|
||||
CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
||||
if(air_group || (height==0)) return 1
|
||||
//roll to-hit
|
||||
miss_modifier = max(miss_modifier + 15*(distance-2), 0)
|
||||
var/hit_zone = get_zone_with_miss_chance(def_zone, target_mob, miss_modifier, ranged_attack=(distance > 1))
|
||||
if(!hit_zone)
|
||||
visible_message("<span class='notice'>\The [src] misses [target_mob] narrowly!</span>")
|
||||
return 0
|
||||
|
||||
if(istype(mover, /obj/item/projectile))
|
||||
return prob(95)
|
||||
//set def_zone, so if the projectile ends up hitting someone else later (to be implemented), it is more likely to hit the same part
|
||||
def_zone = hit_zone
|
||||
|
||||
//hit messages
|
||||
if(silenced)
|
||||
target_mob << "<span class='danger'>You've been hit in the [parse_zone(def_zone)] by \the [src]!</span>"
|
||||
else
|
||||
visible_message("<span class='danger'>\The [target_mob] is hit by \the [src] in the [parse_zone(def_zone)]!</span>")//X has fired Y is now given by the guns so you cant tell who shot you if you could not see the shooter
|
||||
|
||||
//admin logs
|
||||
if(istype(firer, /mob))
|
||||
target_mob.attack_log += "\[[time_stamp()]\] <b>[firer]/[firer.ckey]</b> shot <b>[target_mob]/[target_mob.ckey]</b> with a <b>[src.type]</b>"
|
||||
firer.attack_log += "\[[time_stamp()]\] <b>[firer]/[firer.ckey]</b> shot <b>[target_mob]/[target_mob.ckey]</b> with a <b>[src.type]</b>"
|
||||
msg_admin_attack("[firer] ([firer.ckey]) shot [target_mob] ([target_mob.ckey]) with a [src] (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[firer.x];Y=[firer.y];Z=[firer.z]'>JMP</a>)") //BS12 EDIT ALG
|
||||
else if(firer)
|
||||
target_mob.attack_log += "\[[time_stamp()]\] <b>UNKNOWN SUBJECT (No longer exists)</b> shot <b>[target_mob]/[target_mob.ckey]</b> with a <b>[src]</b>"
|
||||
msg_admin_attack("UNKNOWN shot [target_mob] ([target_mob.ckey]) with a [src] (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[firer.x];Y=[firer.y];Z=[firer.z]'>JMP</a>)") //BS12 EDIT ALG
|
||||
else
|
||||
target_mob.attack_log += "\[[time_stamp()]\] <b>UNKNOWN SUBJECT (No longer exists)</b> shot <b>[target_mob]/[target_mob.ckey]</b> with a <b>[src]</b>"
|
||||
msg_admin_attack("UNKNOWN shot [target_mob] ([target_mob.ckey]) with a [src] (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[target_mob.x];Y=[target_mob.y];Z=[target_mob.z]'>JMP</a>)") //BS12 EDIT ALG
|
||||
|
||||
//sometimes bullet_act() will want the projectile to continue flying
|
||||
if (target_mob.bullet_act(src, def_zone) == -1)
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
/obj/item/projectile/Bump(atom/A as mob|obj|turf|area, forced=0)
|
||||
if(A == src)
|
||||
return 0 //no
|
||||
|
||||
if(A == firer)
|
||||
loc = A.loc
|
||||
return 0 //cannot shoot yourself
|
||||
|
||||
if((bumped && !forced) || (A in permutated))
|
||||
return 0
|
||||
|
||||
var/passthrough = 0 //if the projectile should continue flying
|
||||
var/distance = get_dist(starting,loc)
|
||||
|
||||
bumped = 1
|
||||
if(ismob(A))
|
||||
var/mob/M = A
|
||||
if(istype(A, /mob/living))
|
||||
//if they have a neck grab on someone, that person gets hit instead
|
||||
var/obj/item/weapon/grab/G = locate() in M
|
||||
if(G && G.state >= GRAB_NECK)
|
||||
visible_message("<span class='danger'>\The [M] uses [G.affecting] as a shield!</span>")
|
||||
if(Bump(G.affecting, forced=1))
|
||||
return //If Bump() returns 0 (keep going) then we continue on to attack M.
|
||||
|
||||
passthrough = !attack_mob(M, distance)
|
||||
else
|
||||
return 1
|
||||
passthrough = 1 //so ghosts don't stop bullets
|
||||
else
|
||||
passthrough = (A.bullet_act(src, def_zone) == -1) //backwards compatibility
|
||||
if(isturf(A))
|
||||
for(var/obj/O in A)
|
||||
O.bullet_act(src)
|
||||
for(var/mob/M in A)
|
||||
attack_mob(M, distance)
|
||||
|
||||
//penetrating projectiles can pass through things that otherwise would not let them
|
||||
if(!passthrough && penetrating > 0)
|
||||
if(check_penetrate(A))
|
||||
passthrough = 1
|
||||
penetrating--
|
||||
|
||||
process()
|
||||
if(kill_count < 1)
|
||||
//the bullet passes through a dense object!
|
||||
if(passthrough)
|
||||
//move ourselves onto A so we can continue on our way.
|
||||
if(A)
|
||||
if(istype(A, /turf))
|
||||
loc = A
|
||||
else
|
||||
loc = A.loc
|
||||
permutated.Add(A)
|
||||
bumped = 0 //reset bumped variable!
|
||||
return 0
|
||||
|
||||
//stop flying
|
||||
on_impact(A)
|
||||
|
||||
density = 0
|
||||
invisibility = 101
|
||||
|
||||
del(src)
|
||||
return 1
|
||||
|
||||
/obj/item/projectile/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
||||
if(air_group || (height==0)) return 1
|
||||
|
||||
if(istype(mover, /obj/item/projectile))
|
||||
return prob(95) //ha
|
||||
else
|
||||
return 1
|
||||
|
||||
/obj/item/projectile/process()
|
||||
var/first_step = 1
|
||||
|
||||
//plot the initial trajectory
|
||||
setup_trajectory()
|
||||
|
||||
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))
|
||||
del(src)
|
||||
kill_count--
|
||||
spawn while(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))
|
||||
del(src)
|
||||
return
|
||||
step_towards(src, current)
|
||||
sleep(1)
|
||||
if(!bumped && !isturf(original))
|
||||
if(loc == get_turf(original))
|
||||
if(!(original in permutated))
|
||||
Bump(original)
|
||||
sleep(1)
|
||||
return
|
||||
|
||||
trajectory.increment() // increment the current location
|
||||
location = trajectory.return_location(location) // update the locally stored location data
|
||||
|
||||
if(!location)
|
||||
del(src) // if it's left the world... kill it
|
||||
|
||||
Move(location.return_turf())
|
||||
|
||||
if(first_step)
|
||||
muzzle_effect(effect_transform)
|
||||
first_step = 0
|
||||
else
|
||||
tracer_effect(effect_transform)
|
||||
|
||||
if(!bumped && !isturf(original))
|
||||
if(loc == get_turf(original))
|
||||
if(!(original in permutated))
|
||||
Bump(original)
|
||||
|
||||
if(!hitscan)
|
||||
sleep(1) //add delay between movement iterations if it's not a hitscan weapon
|
||||
|
||||
/obj/item/projectile/proc/setup_trajectory()
|
||||
// plot the initial trajectory
|
||||
trajectory = new()
|
||||
trajectory.setup(starting, original, pixel_x, pixel_y)
|
||||
|
||||
// generate this now since all visual effects the projectile makes can use it
|
||||
effect_transform = new()
|
||||
effect_transform.Scale(trajectory.return_hypotenuse(), 1)
|
||||
effect_transform.Turn(-trajectory.return_angle()) //no idea why this has to be inverted, but it works
|
||||
|
||||
/obj/item/projectile/proc/muzzle_effect(var/matrix/T)
|
||||
if(silenced)
|
||||
return
|
||||
|
||||
if(ispath(muzzle_type))
|
||||
var/obj/effect/projectile/M = new muzzle_type(get_turf(src))
|
||||
|
||||
if(istype(M))
|
||||
M.set_transform(T)
|
||||
M.pixel_x = location.pixel_x
|
||||
M.pixel_y = location.pixel_y
|
||||
M.activate()
|
||||
|
||||
/obj/item/projectile/proc/tracer_effect(var/matrix/M)
|
||||
if(ispath(tracer_type))
|
||||
var/obj/effect/projectile/P = new tracer_type(location.loc)
|
||||
|
||||
if(istype(P))
|
||||
P.set_transform(M)
|
||||
P.pixel_x = location.pixel_x
|
||||
P.pixel_y = location.pixel_y
|
||||
P.activate()
|
||||
|
||||
/obj/item/projectile/proc/impact_effect(var/matrix/M)
|
||||
if(ispath(tracer_type))
|
||||
var/obj/effect/projectile/P = new impact_type(location.loc)
|
||||
|
||||
if(istype(P))
|
||||
P.set_transform(M)
|
||||
P.pixel_x = location.pixel_x
|
||||
P.pixel_y = location.pixel_y
|
||||
P.activate()
|
||||
|
||||
//"Tracing" projectile
|
||||
/obj/item/projectile/test //Used to see if you can hit them.
|
||||
invisibility = 101 //Nope! Can't see me!
|
||||
yo = null
|
||||
@@ -167,36 +354,58 @@
|
||||
var/target = null
|
||||
var/result = 0 //To pass the message back to the gun.
|
||||
|
||||
Bump(atom/A as mob|obj|turf|area)
|
||||
if(A == firer)
|
||||
loc = A.loc
|
||||
return //cannot shoot yourself
|
||||
if(istype(A, /obj/item/projectile))
|
||||
return
|
||||
if(istype(A, /mob/living))
|
||||
result = 2 //We hit someone, return 1!
|
||||
return
|
||||
result = 1
|
||||
/obj/item/projectile/test/Bump(atom/A as mob|obj|turf|area)
|
||||
if(A == firer)
|
||||
loc = A.loc
|
||||
return //cannot shoot yourself
|
||||
if(istype(A, /obj/item/projectile))
|
||||
return
|
||||
if(istype(A, /mob/living))
|
||||
result = 2 //We hit someone, return 1!
|
||||
return
|
||||
result = 1
|
||||
return
|
||||
|
||||
process()
|
||||
var/turf/curloc = get_turf(src)
|
||||
var/turf/targloc = get_turf(target)
|
||||
if(!curloc || !targloc)
|
||||
return 0
|
||||
yo = targloc.y - curloc.y
|
||||
xo = targloc.x - curloc.x
|
||||
target = targloc
|
||||
while(src) //Loop on through!
|
||||
if(result)
|
||||
return (result - 1)
|
||||
if((!( target ) || loc == target))
|
||||
target = locate(min(max(x + xo, 1), world.maxx), min(max(y + yo, 1), world.maxy), z) //Finding the target turf at map edge
|
||||
step_towards(src, target)
|
||||
var/mob/living/M = locate() in get_turf(src)
|
||||
if(istype(M)) //If there is someting living...
|
||||
return 1 //Return 1
|
||||
else
|
||||
M = locate() in get_step(src,target)
|
||||
if(istype(M))
|
||||
return 1
|
||||
/obj/item/projectile/test/process()
|
||||
var/turf/curloc = get_turf(src)
|
||||
var/turf/targloc = get_turf(target)
|
||||
if(!curloc || !targloc)
|
||||
return 0
|
||||
yo = targloc.y - curloc.y
|
||||
xo = targloc.x - curloc.x
|
||||
target = targloc
|
||||
|
||||
//plot the initial trajectory
|
||||
setup_trajectory()
|
||||
|
||||
while(src) //Loop on through!
|
||||
if(result)
|
||||
return (result - 1)
|
||||
if((!( target ) || loc == target))
|
||||
target = locate(min(max(x + xo, 1), world.maxx), min(max(y + yo, 1), world.maxy), z) //Finding the target turf at map edge
|
||||
|
||||
trajectory.increment() // increment the current location
|
||||
location = trajectory.return_location(location) // update the locally stored location data
|
||||
|
||||
Move(location.return_turf())
|
||||
|
||||
var/mob/living/M = locate() in get_turf(src)
|
||||
if(istype(M)) //If there is someting living...
|
||||
return 1 //Return 1
|
||||
else
|
||||
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!
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -1,84 +1,17 @@
|
||||
var/list/beam_master = list()
|
||||
//Use: Caches beam state images and holds turfs that had these images overlaid.
|
||||
//Structure:
|
||||
//beam_master
|
||||
// icon_states/dirs of beams
|
||||
// image for that beam
|
||||
// references for fired beams
|
||||
// icon_states/dirs for each placed beam image
|
||||
// turfs that have that icon_state/dir
|
||||
|
||||
/obj/item/projectile/beam
|
||||
name = "laser"
|
||||
icon_state = "laser"
|
||||
pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
|
||||
damage = 40
|
||||
damage_type = BURN
|
||||
flag = "laser"
|
||||
check_armour = "laser"
|
||||
eyeblur = 4
|
||||
var/frequency = 1
|
||||
process()
|
||||
var/reference = "\ref[src]" //So we do not have to recalculate it a ton
|
||||
var/first = 1 //So we don't make the overlay in the same tile as the firer
|
||||
spawn while(src) //Move until we hit something
|
||||
hitscan = 1
|
||||
|
||||
if((!( current ) || loc == current)) //If we pass our target
|
||||
current = locate(min(max(x + xo, 1), world.maxx), min(max(y + yo, 1), world.maxy), z)
|
||||
if((x == 1 || x == world.maxx || y == 1 || y == world.maxy))
|
||||
del(src) //Delete if it passes the world edge
|
||||
return
|
||||
step_towards(src, current) //Move~
|
||||
|
||||
if(kill_count < 1)
|
||||
del(src)
|
||||
kill_count--
|
||||
|
||||
if(!bumped && !isturf(original))
|
||||
if(loc == get_turf(original))
|
||||
if(!(original in permutated))
|
||||
Bump(original)
|
||||
|
||||
if(!first) //Add the overlay as we pass over tiles
|
||||
var/target_dir = get_dir(src, current) //So we don't call this too much
|
||||
|
||||
//If the icon has not been added yet
|
||||
if( !("[icon_state][target_dir]" in beam_master) )
|
||||
var/image/I = image(icon,icon_state,10,target_dir) //Generate it.
|
||||
beam_master["[icon_state][target_dir]"] = I //And cache it!
|
||||
|
||||
//Finally add the overlay
|
||||
src.loc.overlays += beam_master["[icon_state][target_dir]"]
|
||||
|
||||
//Add the turf to a list in the beam master so they can be cleaned up easily.
|
||||
if(reference in beam_master)
|
||||
var/list/turf_master = beam_master[reference]
|
||||
if("[icon_state][target_dir]" in turf_master)
|
||||
var/list/turfs = turf_master["[icon_state][target_dir]"]
|
||||
turfs += loc
|
||||
else
|
||||
turf_master["[icon_state][target_dir]"] = list(loc)
|
||||
else
|
||||
var/list/turfs = list()
|
||||
turfs["[icon_state][target_dir]"] = list(loc)
|
||||
beam_master[reference] = turfs
|
||||
else
|
||||
first = 0
|
||||
cleanup(reference)
|
||||
return
|
||||
|
||||
Del()
|
||||
cleanup("\ref[src]")
|
||||
..()
|
||||
|
||||
proc/cleanup(reference) //Waits .3 seconds then removes the overlay.
|
||||
src = null //we're getting deleted! this will keep the code running
|
||||
spawn(3)
|
||||
var/list/turf_master = beam_master[reference]
|
||||
for(var/laser_state in turf_master)
|
||||
var/list/turfs = turf_master[laser_state]
|
||||
for(var/turf/T in turfs)
|
||||
T.overlays -= beam_master[laser_state]
|
||||
return
|
||||
muzzle_type = /obj/effect/projectile/laser/muzzle
|
||||
tracer_type = /obj/effect/projectile/laser/tracer
|
||||
impact_type = /obj/effect/projectile/laser/impact
|
||||
|
||||
/obj/item/projectile/beam/practice
|
||||
name = "laser"
|
||||
@@ -86,31 +19,49 @@ 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
|
||||
name = "heavy laser"
|
||||
icon_state = "heavylaser"
|
||||
damage = 60
|
||||
|
||||
muzzle_type = /obj/effect/projectile/laser_heavy/muzzle
|
||||
tracer_type = /obj/effect/projectile/laser_heavy/tracer
|
||||
impact_type = /obj/effect/projectile/laser_heavy/impact
|
||||
|
||||
/obj/item/projectile/beam/xray
|
||||
name = "xray beam"
|
||||
icon_state = "xray"
|
||||
damage = 30
|
||||
|
||||
muzzle_type = /obj/effect/projectile/xray/muzzle
|
||||
tracer_type = /obj/effect/projectile/xray/tracer
|
||||
impact_type = /obj/effect/projectile/xray/impact
|
||||
|
||||
/obj/item/projectile/beam/pulse
|
||||
name = "pulse"
|
||||
icon_state = "u_laser"
|
||||
damage = 50
|
||||
|
||||
muzzle_type = /obj/effect/projectile/laser_pulse/muzzle
|
||||
tracer_type = /obj/effect/projectile/laser_pulse/tracer
|
||||
impact_type = /obj/effect/projectile/laser_pulse/impact
|
||||
|
||||
/obj/item/projectile/beam/pulse/on_hit(var/atom/target, var/blocked = 0)
|
||||
if(isturf(target))
|
||||
target.ex_act(2)
|
||||
..()
|
||||
|
||||
/obj/item/projectile/beam/emitter
|
||||
name = "emitter beam"
|
||||
icon_state = "emitter"
|
||||
damage = 30
|
||||
damage = 0 // The actual damage is computed in /code/modules/power/singularity/emitter.dm
|
||||
|
||||
muzzle_type = /obj/effect/projectile/emitter/muzzle
|
||||
tracer_type = /obj/effect/projectile/emitter/tracer
|
||||
impact_type = /obj/effect/projectile/emitter/impact
|
||||
|
||||
/obj/item/projectile/beam/lastertag/blue
|
||||
name = "lasertag beam"
|
||||
@@ -118,14 +69,18 @@ var/list/beam_master = list()
|
||||
pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
|
||||
damage = 0
|
||||
damage_type = BURN
|
||||
flag = "laser"
|
||||
check_armour = "laser"
|
||||
|
||||
on_hit(var/atom/target, var/blocked = 0)
|
||||
if(istype(target, /mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/M = target
|
||||
if(istype(M.wear_suit, /obj/item/clothing/suit/redtag))
|
||||
M.Weaken(5)
|
||||
return 1
|
||||
muzzle_type = /obj/effect/projectile/laser_blue/muzzle
|
||||
tracer_type = /obj/effect/projectile/laser_blue/tracer
|
||||
impact_type = /obj/effect/projectile/laser_blue/impact
|
||||
|
||||
/obj/item/projectile/beam/lastertag/blue/on_hit(var/atom/target, var/blocked = 0)
|
||||
if(istype(target, /mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/M = target
|
||||
if(istype(M.wear_suit, /obj/item/clothing/suit/redtag))
|
||||
M.Weaken(5)
|
||||
return 1
|
||||
|
||||
/obj/item/projectile/beam/lastertag/red
|
||||
name = "lasertag beam"
|
||||
@@ -133,14 +88,14 @@ var/list/beam_master = list()
|
||||
pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
|
||||
damage = 0
|
||||
damage_type = BURN
|
||||
flag = "laser"
|
||||
check_armour = "laser"
|
||||
|
||||
on_hit(var/atom/target, var/blocked = 0)
|
||||
if(istype(target, /mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/M = target
|
||||
if(istype(M.wear_suit, /obj/item/clothing/suit/bluetag))
|
||||
M.Weaken(5)
|
||||
return 1
|
||||
/obj/item/projectile/beam/lastertag/red/on_hit(var/atom/target, var/blocked = 0)
|
||||
if(istype(target, /mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/M = target
|
||||
if(istype(M.wear_suit, /obj/item/clothing/suit/bluetag))
|
||||
M.Weaken(5)
|
||||
return 1
|
||||
|
||||
/obj/item/projectile/beam/lastertag/omni//A laser tag bolt that stuns EVERYONE
|
||||
name = "lasertag beam"
|
||||
@@ -148,26 +103,39 @@ var/list/beam_master = list()
|
||||
pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
|
||||
damage = 0
|
||||
damage_type = BURN
|
||||
flag = "laser"
|
||||
check_armour = "laser"
|
||||
|
||||
on_hit(var/atom/target, var/blocked = 0)
|
||||
if(istype(target, /mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/M = target
|
||||
if((istype(M.wear_suit, /obj/item/clothing/suit/bluetag))||(istype(M.wear_suit, /obj/item/clothing/suit/redtag)))
|
||||
M.Weaken(5)
|
||||
return 1
|
||||
muzzle_type = /obj/effect/projectile/laser_omni/muzzle
|
||||
tracer_type = /obj/effect/projectile/laser_omni/tracer
|
||||
impact_type = /obj/effect/projectile/laser_omni/impact
|
||||
|
||||
/obj/item/projectile/beam/lastertag/omni/on_hit(var/atom/target, var/blocked = 0)
|
||||
if(istype(target, /mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/M = target
|
||||
if((istype(M.wear_suit, /obj/item/clothing/suit/bluetag))||(istype(M.wear_suit, /obj/item/clothing/suit/redtag)))
|
||||
M.Weaken(5)
|
||||
return 1
|
||||
|
||||
/obj/item/projectile/beam/sniper
|
||||
name = "sniper beam"
|
||||
icon_state = "xray"
|
||||
damage = 60
|
||||
stun = 5
|
||||
weaken = 5
|
||||
stutter = 5
|
||||
stun = 3
|
||||
weaken = 3
|
||||
stutter = 3
|
||||
|
||||
muzzle_type = /obj/effect/projectile/xray/muzzle
|
||||
tracer_type = /obj/effect/projectile/xray/tracer
|
||||
impact_type = /obj/effect/projectile/xray/impact
|
||||
|
||||
/obj/item/projectile/beam/stun
|
||||
name = "stun beam"
|
||||
icon_state = "stun"
|
||||
nodamage = 1
|
||||
taser_effect = 1
|
||||
agony = 40
|
||||
damage_type = HALLOSS
|
||||
|
||||
muzzle_type = /obj/effect/projectile/stun/muzzle
|
||||
tracer_type = /obj/effect/projectile/stun/tracer
|
||||
impact_type = /obj/effect/projectile/stun/impact
|
||||
|
||||
@@ -4,66 +4,182 @@
|
||||
damage = 60
|
||||
damage_type = BRUTE
|
||||
nodamage = 0
|
||||
flag = "bullet"
|
||||
check_armour = "bullet"
|
||||
embed = 1
|
||||
sharp = 1
|
||||
var/mob_passthrough_check = 0
|
||||
|
||||
muzzle_type = /obj/effect/projectile/bullet/muzzle
|
||||
|
||||
on_hit(var/atom/target, var/blocked = 0)
|
||||
if (..(target, blocked))
|
||||
var/mob/living/L = target
|
||||
shake_camera(L, 3, 2)
|
||||
/obj/item/projectile/bullet/on_hit(var/atom/target, var/blocked = 0)
|
||||
if (..(target, blocked))
|
||||
var/mob/living/L = target
|
||||
shake_camera(L, 3, 2)
|
||||
|
||||
/obj/item/projectile/bullet/weakbullet // "rubber" bullets
|
||||
/obj/item/projectile/bullet/attack_mob(var/mob/living/target_mob, var/distance, var/miss_modifier)
|
||||
if(penetrating > 0 && damage > 20 && prob(damage))
|
||||
mob_passthrough_check = 1
|
||||
else
|
||||
mob_passthrough_check = 0
|
||||
return ..()
|
||||
|
||||
/obj/item/projectile/bullet/can_embed()
|
||||
//prevent embedding if the projectile is passing through the mob
|
||||
if(mob_passthrough_check)
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/obj/item/projectile/bullet/check_penetrate(var/atom/A)
|
||||
if(!A || !A.density) return 1 //if whatever it was got destroyed when we hit it, then I guess we can just keep going
|
||||
|
||||
if(istype(A, /obj/mecha))
|
||||
return 1 //mecha have their own penetration handling
|
||||
|
||||
if(ismob(A))
|
||||
if(!mob_passthrough_check)
|
||||
return 0
|
||||
if(iscarbon(A))
|
||||
damage *= 0.7 //squishy mobs absorb KE
|
||||
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*180)
|
||||
if(D.glass) chance *= 2
|
||||
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 = 25
|
||||
|
||||
if(prob(chance))
|
||||
if(A.opacity)
|
||||
//display a message so that people on the other side aren't so confused
|
||||
A.visible_message("<span class='warning'>\The [src] pierces through \the [A]!")
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
//For projectiles that actually represent clouds of projectiles
|
||||
/obj/item/projectile/bullet/pellet
|
||||
name = "shrapnel" //'shrapnel' sounds more dangerous (i.e. cooler) than 'pellet'
|
||||
damage = 20
|
||||
//icon_state = "bullet" //TODO: would be nice to have it's own icon state
|
||||
var/pellets = 4 //number of pellets
|
||||
var/range_step = 2 //effective pellet count decreases every few tiles
|
||||
var/base_spread = 90 //lower means the pellets spread more across body parts
|
||||
var/spread_step = 10 //higher means the pellets spread more across body parts with distance
|
||||
|
||||
/obj/item/projectile/bullet/pellet/Bumped()
|
||||
. = ..()
|
||||
bumped = 0 //can hit all mobs in a tile. pellets is decremented inside attack_mob so this should be fine.
|
||||
|
||||
/obj/item/projectile/bullet/pellet/attack_mob(var/mob/living/target_mob, var/distance)
|
||||
if (pellets < 0) return 1
|
||||
|
||||
var/pellet_loss = round((distance - 1)/range_step) //pellets lost due to distance
|
||||
var/total_pellets = max(pellets - pellet_loss, 1)
|
||||
var/spread = max(base_spread - (spread_step*distance), 0)
|
||||
var/hits = 0
|
||||
for (var/i in 1 to total_pellets)
|
||||
//pellet hits spread out across different zones, but 'aim at' the targeted zone with higher probability
|
||||
//whether the pellet actually hits the def_zone or a different zone should still be determined by the parent using get_zone_with_miss_chance().
|
||||
var/old_zone = def_zone
|
||||
def_zone = ran_zone(def_zone, spread)
|
||||
if (..()) hits++
|
||||
def_zone = old_zone //restore the original zone the projectile was aimed at
|
||||
|
||||
pellets -= hits //each hit reduces the number of pellets left
|
||||
if (hits >= total_pellets || pellets <= 0)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/* short-casing projectiles, like the kind used in pistols or SMGs */
|
||||
|
||||
/obj/item/projectile/bullet/pistol
|
||||
damage = 20
|
||||
|
||||
/obj/item/projectile/bullet/pistol/medium
|
||||
damage = 25
|
||||
|
||||
/obj/item/projectile/bullet/pistol/strong //revolvers and matebas
|
||||
damage = 60
|
||||
|
||||
/obj/item/projectile/bullet/pistol/rubber //"rubber" bullets
|
||||
name = "rubber bullet"
|
||||
damage = 10
|
||||
agony = 40
|
||||
embed = 0
|
||||
sharp = 0
|
||||
|
||||
/obj/item/projectile/bullet/weakbullet/beanbag //because beanbags are not bullets
|
||||
/* shotgun projectiles */
|
||||
|
||||
/obj/item/projectile/bullet/shotgun
|
||||
name = "slug"
|
||||
damage = 60
|
||||
|
||||
/obj/item/projectile/bullet/shotgun/beanbag //because beanbags are not bullets
|
||||
name = "beanbag"
|
||||
damage = 20
|
||||
agony = 60
|
||||
embed = 0
|
||||
sharp = 0
|
||||
|
||||
/obj/item/projectile/bullet/weakbullet/rubber
|
||||
name = "rubber bullet"
|
||||
//Should do about 80 damage at 1 tile distance (adjacent), and 50 damage at 3 tiles distance.
|
||||
//Overall less damage than slugs in exchange for more damage at very close range and more embedding
|
||||
/obj/item/projectile/bullet/pellet/shotgun
|
||||
name = "shrapnel"
|
||||
damage = 13
|
||||
pellets = 6
|
||||
range_step = 1
|
||||
spread_step = 10
|
||||
|
||||
/obj/item/projectile/bullet/midbullet
|
||||
damage = 20
|
||||
/* "Rifle" rounds */
|
||||
|
||||
/obj/item/projectile/bullet/midbullet2
|
||||
damage = 25
|
||||
/obj/item/projectile/bullet/rifle/a762
|
||||
damage = 30
|
||||
penetrating = 1
|
||||
|
||||
/obj/item/projectile/bullet/rifle/a145
|
||||
damage = 80
|
||||
stun = 3
|
||||
weaken = 3
|
||||
penetrating = 5
|
||||
|
||||
/obj/item/projectile/bullet/rifle/a556
|
||||
damage = 40
|
||||
penetrating = 1
|
||||
|
||||
/* Miscellaneous */
|
||||
|
||||
/obj/item/projectile/bullet/suffocationbullet//How does this even work?
|
||||
name = "co bullet"
|
||||
damage = 20
|
||||
damage_type = OXY
|
||||
|
||||
|
||||
/obj/item/projectile/bullet/cyanideround
|
||||
name = "poison bullet"
|
||||
damage = 40
|
||||
damage_type = TOX
|
||||
|
||||
|
||||
/obj/item/projectile/bullet/burstbullet//I think this one needs something for the on hit
|
||||
/obj/item/projectile/bullet/burstbullet
|
||||
name = "exploding bullet"
|
||||
damage = 20
|
||||
embed = 0
|
||||
edge = 1
|
||||
|
||||
/obj/item/projectile/bullet/gyro/on_hit(var/atom/target, var/blocked = 0)
|
||||
if(isturf(target))
|
||||
explosion(target, -1, 0, 2)
|
||||
..()
|
||||
|
||||
/obj/item/projectile/bullet/stunshot
|
||||
name = "stunshot"
|
||||
damage = 5
|
||||
agony = 80
|
||||
stutter = 10
|
||||
/obj/item/projectile/bullet/blank
|
||||
invisibility = 101
|
||||
damage = 1
|
||||
embed = 0
|
||||
sharp = 0
|
||||
|
||||
/obj/item/projectile/bullet/a762
|
||||
damage = 25
|
||||
|
||||
/obj/item/projectile/bullet/chameleon
|
||||
damage = 1 // stop trying to murderbone with a fake gun dumbass!!!
|
||||
|
||||
@@ -4,43 +4,47 @@
|
||||
damage = 0
|
||||
damage_type = BURN
|
||||
nodamage = 1
|
||||
flag = "energy"
|
||||
check_armour = "energy"
|
||||
|
||||
on_hit(var/atom/change)
|
||||
wabbajack(change)
|
||||
/obj/item/projectile/change/on_hit(var/atom/change)
|
||||
wabbajack(change)
|
||||
|
||||
|
||||
/obj/item/projectile/change/proc/wabbajack (mob/M as mob in living_mob_list)
|
||||
/obj/item/projectile/change/proc/wabbajack(var/mob/M)
|
||||
if(istype(M, /mob/living) && M.stat != DEAD)
|
||||
if(M.monkeyizing) return
|
||||
if(M.has_brain_worms()) return //Borer stuff - RR
|
||||
|
||||
M.monkeyizing = 1
|
||||
M.canmove = 0
|
||||
M.icon = null
|
||||
M.overlays.Cut()
|
||||
M.invisibility = 101
|
||||
if(M.monkeyizing)
|
||||
return
|
||||
if(M.has_brain_worms())
|
||||
return //Borer stuff - RR
|
||||
|
||||
if(istype(M, /mob/living/silicon/robot))
|
||||
var/mob/living/silicon/robot/Robot = M
|
||||
if(Robot.mmi) del(Robot.mmi)
|
||||
Robot.notify_ai(1)
|
||||
if(Robot.mmi)
|
||||
del(Robot.mmi)
|
||||
else
|
||||
for(var/obj/item/W in M)
|
||||
if(istype(W, /obj/item/weapon/implant)) //TODO: Carn. give implants a dropped() or something
|
||||
del(W)
|
||||
continue
|
||||
W.layer = initial(W.layer)
|
||||
W.loc = M.loc
|
||||
W.dropped(M)
|
||||
M.drop_from_inventory(W)
|
||||
|
||||
var/mob/living/new_mob
|
||||
|
||||
var/randomize = pick("monkey","robot","slime","xeno","human")
|
||||
var/options = list("robot", "slime")
|
||||
for(var/t in all_species)
|
||||
options += t
|
||||
options -= "Xenomorph Queen"
|
||||
options -= "Xenomorph"
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(H.species)
|
||||
options -= H.species.name
|
||||
else if(isrobot(M))
|
||||
options -= "robot"
|
||||
else if(isslime(M))
|
||||
options -= "slime"
|
||||
|
||||
var/randomize = pick(options)
|
||||
switch(randomize)
|
||||
if("monkey")
|
||||
new_mob = new /mob/living/carbon/monkey(M.loc)
|
||||
new_mob.universal_speak = 1
|
||||
if("robot")
|
||||
new_mob = new /mob/living/silicon/robot(M.loc)
|
||||
new_mob.gender = M.gender
|
||||
@@ -52,36 +56,42 @@
|
||||
if("slime")
|
||||
new_mob = new /mob/living/carbon/slime(M.loc)
|
||||
new_mob.universal_speak = 1
|
||||
if("xeno")
|
||||
var/alien_caste = pick("Hunter","Sentinel","Drone","Larva")
|
||||
new_mob = create_new_xenomorph(alien_caste,M.loc)
|
||||
new_mob.universal_speak = 1
|
||||
if("human")
|
||||
new_mob = new /mob/living/carbon/human(M.loc, pick(all_species))
|
||||
if(M.gender == MALE)
|
||||
new_mob.gender = MALE
|
||||
new_mob.name = pick(first_names_male)
|
||||
else
|
||||
new_mob.gender = FEMALE
|
||||
new_mob.name = pick(first_names_female)
|
||||
new_mob.name += " [pick(last_names)]"
|
||||
new_mob.real_name = new_mob.name
|
||||
|
||||
var/datum/preferences/A = new() //Randomize appearance for the human
|
||||
A.randomize_appearance_for(new_mob)
|
||||
else
|
||||
return
|
||||
var/mob/living/carbon/human/H
|
||||
if(ishuman(M))
|
||||
H = M
|
||||
else
|
||||
new_mob = new /mob/living/carbon/human(M.loc)
|
||||
H = new_mob
|
||||
|
||||
for (var/obj/effect/proc_holder/spell/S in M.spell_list)
|
||||
new_mob.spell_list += new S.type
|
||||
if(M.gender == MALE)
|
||||
H.gender = MALE
|
||||
H.name = pick(first_names_male)
|
||||
else
|
||||
H.gender = FEMALE
|
||||
H.name = pick(first_names_female)
|
||||
H.name += " [pick(last_names)]"
|
||||
H.real_name = H.name
|
||||
|
||||
new_mob.a_intent = "hurt"
|
||||
if(M.mind)
|
||||
M.mind.transfer_to(new_mob)
|
||||
H.set_species(randomize)
|
||||
H.universal_speak = 1
|
||||
var/datum/preferences/A = new() //Randomize appearance for the human
|
||||
A.randomize_appearance_for(H)
|
||||
|
||||
if(new_mob)
|
||||
for (var/obj/effect/proc_holder/spell/S in M.spell_list)
|
||||
new_mob.spell_list += new S.type
|
||||
|
||||
new_mob.a_intent = "hurt"
|
||||
if(M.mind)
|
||||
M.mind.transfer_to(new_mob)
|
||||
else
|
||||
new_mob.key = M.key
|
||||
|
||||
new_mob << "<span class='warning'>Your form morphs into that of \a [lowertext(randomize)].</span>"
|
||||
|
||||
del(M)
|
||||
return
|
||||
else
|
||||
new_mob.key = M.key
|
||||
|
||||
new_mob << "<B>Your form morphs into that of a [randomize].</B>"
|
||||
|
||||
del(M)
|
||||
return new_mob
|
||||
M << "<span class='warning'>Your form morphs into that of \a [lowertext(randomize)].</span>"
|
||||
return
|
||||
@@ -3,9 +3,43 @@
|
||||
icon_state = "spark"
|
||||
damage = 0
|
||||
damage_type = BURN
|
||||
flag = "energy"
|
||||
check_armour = "energy"
|
||||
|
||||
|
||||
//releases a burst of light on impact or after travelling a distance
|
||||
/obj/item/projectile/energy/flash
|
||||
name = "chemical shell"
|
||||
icon_state = "bullet"
|
||||
damage = 5
|
||||
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
|
||||
|
||||
//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)
|
||||
src.visible_message("<span class='warning'>\The [src] explodes in a bright flash!</span>")
|
||||
|
||||
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 = 9 //similar to a flare
|
||||
light_duration = 200
|
||||
|
||||
/obj/item/projectile/energy/electrode
|
||||
name = "electrode"
|
||||
icon_state = "spark"
|
||||
@@ -15,11 +49,16 @@
|
||||
weaken = 10
|
||||
stutter = 10
|
||||
*/
|
||||
taser_effect = 1
|
||||
agony = 40
|
||||
damage_type = HALLOSS
|
||||
//Damage will be handled on the MOB side, to prevent window shattering.
|
||||
|
||||
|
||||
/obj/item/projectile/energy/electrode/stunshot
|
||||
name = "stunshot"
|
||||
damage = 5
|
||||
taser_effect = 1
|
||||
agony = 80
|
||||
|
||||
/obj/item/projectile/energy/declone
|
||||
name = "declone"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
@@ -137,3 +137,16 @@
|
||||
var/mob/living/carbon/human/M = target
|
||||
M.adjustBrainLoss(20)
|
||||
M.hallucination += 20
|
||||
|
||||
/obj/item/projectile/icarus/pointdefense/process()
|
||||
Icarus_FireLaser(get_turf(original))
|
||||
spawn
|
||||
del src
|
||||
|
||||
return
|
||||
|
||||
/obj/item/projectile/icarus/guns/process()
|
||||
Icarus_FireCannon(get_turf(original))
|
||||
spawn
|
||||
del src
|
||||
return
|
||||
|
||||
@@ -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 <b>[usr] turns \the [src] on [M]!</b>")
|
||||
else
|
||||
usr.visible_message("\red <b>[usr] aims \a [src] at [M]!</b>")
|
||||
@@ -85,34 +85,31 @@
|
||||
return
|
||||
|
||||
//reflex firing is disabled when help intent is set
|
||||
if (M.a_intent == "help")
|
||||
if (M.a_intent == I_HELP)
|
||||
M << "\red You refrain from firing your [src] as your intent is set to help."
|
||||
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 <b>walk</b> at the discretion of their targeter."
|
||||
if(!target_can_run)
|
||||
@@ -320,7 +318,7 @@ client/verb/AllowTargetMove()
|
||||
else
|
||||
M << "\red <b>Your character will now be shot if they move.</b>"
|
||||
|
||||
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 <b>run</b> at the discretion of their targeter."
|
||||
else
|
||||
M << "\red <b>Your character will now be shot if they run.</b>"
|
||||
|
||||
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 <b>use items</b> at the discretion of their targeter."
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user