Merge branch 'master' into Ghommie-cit539
This commit is contained in:
@@ -34,6 +34,11 @@
|
||||
setDir(pick(GLOB.alldirs))
|
||||
update_icon()
|
||||
|
||||
/obj/item/ammo_casing/Destroy()
|
||||
if(BB)
|
||||
QDEL_NULL(BB)
|
||||
return ..()
|
||||
|
||||
/obj/item/ammo_casing/update_icon()
|
||||
..()
|
||||
icon_state = "[initial(icon_state)][BB ? "-live" : ""]"
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
/obj/item/ammo_casing/caseless/arrow
|
||||
name = "wooden arrow"
|
||||
desc = "An arrow made of wood, typically fired from a bow."
|
||||
projectile_type = /obj/item/projectile/bullet/reusable/arrow
|
||||
caliber = "arrow"
|
||||
icon_state = "arrow"
|
||||
throwforce = 3 //good luck hitting someone with the pointy end of the arrow
|
||||
throw_speed = 3
|
||||
@@ -0,0 +1,39 @@
|
||||
/obj/item/ammo_casing/caseless/magnetic
|
||||
desc = "A large ferromagnetic slug intended to be launched out of a compatible weapon."
|
||||
caliber = "mag"
|
||||
icon_state = "mag-casing-live"
|
||||
click_cooldown_override = 2.5
|
||||
delay = 3
|
||||
var/energy_cost = 200
|
||||
|
||||
/obj/item/ammo_casing/caseless/magnetic
|
||||
projectile_type = /obj/item/projectile/bullet/magnetic
|
||||
|
||||
/obj/item/ammo_casing/caseless/magnetic/disabler
|
||||
desc = "A large, specialized ferromagnetic slug designed with a less-than-lethal payload."
|
||||
projectile_type = /obj/item/projectile/bullet/magnetic/disabler
|
||||
|
||||
/obj/item/ammo_casing/caseless/magnetic/weak
|
||||
desc = "A ferromagnetic slug intended to be launched out of a compatible weapon."
|
||||
projectile_type = /obj/item/projectile/bullet/magnetic/weak
|
||||
energy_cost = 125
|
||||
|
||||
/obj/item/ammo_casing/caseless/magnetic/weak/disabler
|
||||
desc = "A specialized ferromagnetic slug designed with a less-than-lethal payload."
|
||||
projectile_type = /obj/item/projectile/bullet/magnetic/weak/disabler
|
||||
energy_cost = 125
|
||||
|
||||
/obj/item/ammo_casing/caseless/magnetic/hyper
|
||||
desc = "A large block of speciallized ferromagnetic material designed to be fired out of the experimental Hyper-Burst Rifle."
|
||||
caliber = "hypermag"
|
||||
icon_state = "hyper-casing-live"
|
||||
projectile_type = /obj/item/projectile/bullet/magnetic/hyper
|
||||
pellets = 8
|
||||
variance = 30
|
||||
energy_cost = 1500
|
||||
|
||||
/obj/item/ammo_casing/caseless/magnetic/hyper/inferno
|
||||
projectile_type = /obj/item/projectile/bullet/incendiary/mag_inferno
|
||||
pellets = 1
|
||||
variance = 0
|
||||
|
||||
@@ -63,3 +63,8 @@
|
||||
projectile_type = /obj/item/projectile/bullet/reusable/foam_dart/riot
|
||||
icon_state = "foamdart_riot"
|
||||
materials = list(MAT_METAL = 1125)
|
||||
|
||||
/obj/item/ammo_casing/caseless/foam_dart/mag
|
||||
name = "magfoam dart"
|
||||
desc = "A foam dart with fun light-up projectiles powered by magnets!"
|
||||
projectile_type = /obj/item/projectile/bullet/reusable/foam_dart/mag
|
||||
|
||||
@@ -15,15 +15,15 @@
|
||||
. = ..()
|
||||
|
||||
/obj/item/ammo_casing/energy/gravity/repulse
|
||||
projectile_type = /obj/item/projectile/gravityrepulse
|
||||
projectile_type = /obj/item/projectile/gravity/repulse
|
||||
select_name = "repulse"
|
||||
|
||||
/obj/item/ammo_casing/energy/gravity/attract
|
||||
projectile_type = /obj/item/projectile/gravityattract
|
||||
projectile_type = /obj/item/projectile/gravity/attract
|
||||
select_name = "attract"
|
||||
|
||||
/obj/item/ammo_casing/energy/gravity/chaos
|
||||
projectile_type = /obj/item/projectile/gravitychaos
|
||||
projectile_type = /obj/item/projectile/gravity/chaos
|
||||
select_name = "chaos"
|
||||
|
||||
|
||||
|
||||
@@ -62,6 +62,14 @@
|
||||
/obj/item/ammo_casing/energy/laser/redtag/hitscan/holy
|
||||
projectile_type = /obj/item/projectile/beam/lasertag/redtag/hitscan/holy
|
||||
|
||||
/obj/item/ammo_casing/energy/laser/magtag
|
||||
projectile_type = /obj/item/projectile/beam/lasertag/mag
|
||||
select_name = "magtag"
|
||||
pellets = 3
|
||||
variance = 30
|
||||
e_cost = 1000
|
||||
fire_sound = 'sound/weapons/magburst.ogg'
|
||||
|
||||
/obj/item/ammo_casing/energy/xray
|
||||
projectile_type = /obj/item/projectile/beam/xray
|
||||
e_cost = 50
|
||||
|
||||
@@ -12,4 +12,4 @@
|
||||
|
||||
/obj/item/ammo_casing/energy/plasma/weak
|
||||
projectile_type = /obj/item/projectile/plasma/weak
|
||||
e_cost = 100
|
||||
e_cost = 100
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
e_cost = 200
|
||||
harmful = FALSE
|
||||
|
||||
/obj/item/ammo_casing/energy/electrode/security
|
||||
projectile_type = /obj/item/projectile/energy/electrode/security
|
||||
e_cost = 100
|
||||
|
||||
/obj/item/ammo_casing/energy/electrode/spec
|
||||
e_cost = 100
|
||||
|
||||
@@ -13,6 +17,7 @@
|
||||
e_cost = 100
|
||||
|
||||
/obj/item/ammo_casing/energy/electrode/hos
|
||||
projectile_type = /obj/item/projectile/energy/electrode/security/hos
|
||||
e_cost = 200
|
||||
|
||||
/obj/item/ammo_casing/energy/electrode/old
|
||||
@@ -27,4 +32,4 @@
|
||||
click_cooldown_override = 3.5
|
||||
|
||||
/obj/item/ammo_casing/energy/disabler/secborg
|
||||
e_cost = 50
|
||||
e_cost = 50
|
||||
|
||||
@@ -87,7 +87,14 @@
|
||||
max_ammo = 40
|
||||
materials = list(MAT_METAL = 500)
|
||||
|
||||
/obj/item/ammo_box/foambox/mag
|
||||
name = "ammo box (Magnetic Foam Darts)"
|
||||
icon = 'icons/obj/guns/toy.dmi'
|
||||
icon_state = "foambox"
|
||||
ammo_type = /obj/item/ammo_casing/caseless/foam_dart/mag
|
||||
max_ammo = 42
|
||||
|
||||
/obj/item/ammo_box/foambox/riot
|
||||
icon_state = "foambox_riot"
|
||||
ammo_type = /obj/item/ammo_casing/caseless/foam_dart/riot
|
||||
materials = list(MAT_METAL = 50000)
|
||||
materials = list(MAT_METAL = 50000)
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/obj/item/ammo_box/magazine/mmag
|
||||
icon_state = "mediummagmag"
|
||||
ammo_type = /obj/item/ammo_casing/caseless/magnetic/disabler
|
||||
caliber = "mag"
|
||||
max_ammo = 24
|
||||
multiple_sprites = 2
|
||||
|
||||
/obj/item/ammo_box/magazine/mmag/lethal
|
||||
name = "magrifle magazine (lethal)"
|
||||
ammo_type = /obj/item/ammo_casing/caseless/magnetic
|
||||
|
||||
/obj/item/ammo_box/magazine/mmag/small
|
||||
name = "magpistol magazine (non-lethal disabler)"
|
||||
icon_state = "smallmagmag"
|
||||
ammo_type = /obj/item/ammo_casing/caseless/magnetic/weak/disabler
|
||||
max_ammo = 16
|
||||
|
||||
/obj/item/ammo_box/magazine/mmag/small/lethal
|
||||
name = "magpistol magazine (lethal)"
|
||||
ammo_type = /obj/item/ammo_casing/caseless/magnetic/weak
|
||||
|
||||
/obj/item/ammo_box/magazine/mhyper
|
||||
name = "hyper-burst rifle magazine"
|
||||
icon_state = "hypermag"
|
||||
ammo_type = /obj/item/ammo_casing/caseless/magnetic/hyper
|
||||
caliber = "hypermag"
|
||||
desc = "A magazine for the Hyper-Burst Rifle. Loaded with a special slug that fragments into 6 smaller shards which can absolutely puncture anything, but has rather short effective range."
|
||||
max_ammo = 4
|
||||
multiple_sprites = 4
|
||||
|
||||
/obj/item/ammo_box/magazine/mhyper/inferno
|
||||
name = "hyper-burst rifle magazine (inferno)"
|
||||
ammo_type = /obj/item/ammo_casing/caseless/magnetic/hyper/inferno
|
||||
desc = "A magazine for the Hyper-Burst Rifle. Loaded with a special slug that violently reacts with whatever surface it strikes, generating massive amount of heat and light."
|
||||
@@ -57,3 +57,11 @@
|
||||
/obj/item/ammo_box/magazine/toy/m762/riot
|
||||
icon_state = "a762-riot"
|
||||
ammo_type = /obj/item/ammo_casing/caseless/foam_dart/riot
|
||||
|
||||
/obj/item/ammo_box/magazine/toy/foamag
|
||||
name = "foam force magrifle magazine"
|
||||
icon_state = "foamagmag"
|
||||
max_ammo = 24
|
||||
multiple_sprites = 2
|
||||
ammo_type = /obj/item/ammo_casing/caseless/foam_dart/mag
|
||||
materials = list(MAT_METAL = 200)
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/obj/item/ammo_box/magazine/internal/bow
|
||||
name = "bow... magazine?" //shouldn't be seeing this
|
||||
ammo_type = /obj/item/ammo_casing/caseless/arrow
|
||||
caliber = "arrow"
|
||||
max_ammo = 1
|
||||
start_empty = 1
|
||||
@@ -5,3 +5,7 @@
|
||||
|
||||
/obj/item/ammo_box/magazine/internal/shot/toy/crossbow
|
||||
max_ammo = 5
|
||||
|
||||
/obj/item/ammo_box/magazine/internal/shot/toy/mag
|
||||
ammo_type = /obj/item/ammo_casing/caseless/foam_dart/mag
|
||||
max_ammo = 14
|
||||
|
||||
+102
-67
@@ -28,10 +28,19 @@
|
||||
trigger_guard = TRIGGER_GUARD_NORMAL //trigger guard on the weapon, hulks can't fire them with their big meaty fingers
|
||||
var/sawn_desc = null //description change if weapon is sawn-off
|
||||
var/sawn_off = FALSE
|
||||
var/burst_size = 1 //how large a burst is
|
||||
var/fire_delay = 0 //rate of fire for burst firing and semi auto
|
||||
var/firing_burst = 0 //Prevent the weapon from firing again while already firing
|
||||
var/semicd = 0 //cooldown handler
|
||||
|
||||
/// Weapon is burst fire if this is above 1
|
||||
var/burst_size = 1
|
||||
/// The time between shots in burst.
|
||||
var/burst_shot_delay = 3
|
||||
/// The time between firing actions, this means between bursts if this is burst weapon. The reason this is 0 is because you are still, by default, limited by clickdelay.
|
||||
var/fire_delay = 0
|
||||
/// Last world.time this was fired
|
||||
var/last_fire = 0
|
||||
/// Currently firing, whether or not it's a burst or not.
|
||||
var/firing = FALSE
|
||||
/// Used in gun-in-mouth execution/suicide and similar, while TRUE nothing should work on this like firing or modification and so on and so forth.
|
||||
var/busy_action = FALSE
|
||||
var/weapon_weight = WEAPON_LIGHT //currently only used for inaccuracy
|
||||
var/spread = 0 //Spread induced by the gun itself.
|
||||
var/burst_spread = 0 //Spread induced by the gun itself during burst fire per iteration. Only checked if spread is 0.
|
||||
@@ -42,6 +51,7 @@
|
||||
righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi'
|
||||
|
||||
var/obj/item/firing_pin/pin = /obj/item/firing_pin //standard firing pin for most guns
|
||||
var/no_pin_required = FALSE //whether the gun can be fired without a pin
|
||||
|
||||
var/obj/item/flashlight/gun_light
|
||||
var/can_flashlight = 0
|
||||
@@ -70,12 +80,26 @@
|
||||
/obj/item/gun/Initialize()
|
||||
. = ..()
|
||||
if(pin)
|
||||
pin = new pin(src)
|
||||
if(no_pin_required)
|
||||
pin = null
|
||||
else
|
||||
pin = new pin(src)
|
||||
if(gun_light)
|
||||
alight = new (src)
|
||||
if(zoomable)
|
||||
azoom = new (src)
|
||||
|
||||
/obj/item/gun/Destroy()
|
||||
if(pin)
|
||||
QDEL_NULL(pin)
|
||||
if(gun_light)
|
||||
QDEL_NULL(gun_light)
|
||||
if(bayonet)
|
||||
QDEL_NULL(bayonet)
|
||||
if(chambered)
|
||||
QDEL_NULL(chambered)
|
||||
return ..()
|
||||
|
||||
/obj/item/gun/CheckParts(list/parts_list)
|
||||
..()
|
||||
var/obj/item/gun/G = locate(/obj/item/gun) in contents
|
||||
@@ -87,6 +111,8 @@
|
||||
|
||||
/obj/item/gun/examine(mob/user)
|
||||
. = ..()
|
||||
if(no_pin_required)
|
||||
return
|
||||
if(pin)
|
||||
. += "It has \a [pin] installed."
|
||||
else
|
||||
@@ -110,13 +136,12 @@
|
||||
to_chat(user, "<span class='danger'>*click*</span>")
|
||||
playsound(src, "gun_dry_fire", 30, 1)
|
||||
|
||||
|
||||
/obj/item/gun/proc/shoot_live_shot(mob/living/user as mob|obj, pointblank = 0, mob/pbtarget = null, message = 1)
|
||||
if(recoil)
|
||||
shake_camera(user, recoil + 1, recoil)
|
||||
|
||||
if(isliving(user)) //CIT CHANGE - makes gun recoil cause staminaloss
|
||||
user.adjustStaminaLossBuffered(getstamcost(user)*(firing_burst && burst_size >= 2 ? 1/burst_size : 1)) //CIT CHANGE - ditto
|
||||
user.adjustStaminaLossBuffered(getstamcost(user)*(firing && burst_size >= 2 ? 1/burst_size : 1)) //CIT CHANGE - ditto
|
||||
|
||||
if(suppressed)
|
||||
playsound(user, fire_sound, 10, 1)
|
||||
@@ -136,9 +161,12 @@
|
||||
|
||||
/obj/item/gun/afterattack(atom/target, mob/living/user, flag, params)
|
||||
. = ..()
|
||||
process_afterattack(target, user, flag, params)
|
||||
|
||||
/obj/item/gun/proc/process_afterattack(atom/target, mob/living/user, flag, params)
|
||||
if(!target)
|
||||
return
|
||||
if(firing_burst)
|
||||
if(firing)
|
||||
return
|
||||
if(flag) //It's adjacent, is the user, or is on the user's person
|
||||
if(target in user.contents) //can't shoot stuff inside us.
|
||||
@@ -162,7 +190,6 @@
|
||||
handle_suicide(user, target, params)
|
||||
return
|
||||
|
||||
|
||||
//Exclude lasertag guns from the TRAIT_CLUMSY check.
|
||||
if(clumsy_check)
|
||||
if(istype(user))
|
||||
@@ -194,8 +221,6 @@
|
||||
|
||||
process_fire(target, user, TRUE, params, null, bonus_spread)
|
||||
|
||||
|
||||
|
||||
/obj/item/gun/can_trigger_gun(mob/living/user)
|
||||
. = ..()
|
||||
if(!.)
|
||||
@@ -207,6 +232,8 @@
|
||||
return FALSE
|
||||
|
||||
/obj/item/gun/proc/handle_pins(mob/living/user)
|
||||
if(no_pin_required)
|
||||
return TRUE
|
||||
if(pin)
|
||||
if(pin.pin_auth(user) || (pin.obj_flags & EMAGGED))
|
||||
return TRUE
|
||||
@@ -220,54 +247,29 @@
|
||||
/obj/item/gun/proc/recharge_newshot()
|
||||
return
|
||||
|
||||
/obj/item/gun/proc/process_burst(mob/living/user, atom/target, message = TRUE, params=null, zone_override = "", sprd = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, rand_spr = 0, iteration = 0)
|
||||
if(!user || !firing_burst)
|
||||
firing_burst = FALSE
|
||||
return FALSE
|
||||
if(!issilicon(user))
|
||||
if(iteration > 1 && !(user.is_holding(src))) //for burst firing
|
||||
firing_burst = FALSE
|
||||
return FALSE
|
||||
if(chambered && chambered.BB)
|
||||
if(HAS_TRAIT(user, TRAIT_PACIFISM)) // If the user has the pacifist trait, then they won't be able to fire [src] if the round chambered inside of [src] is lethal.
|
||||
if(chambered.harmful) // Is the bullet chambered harmful?
|
||||
to_chat(user, "<span class='notice'> [src] is lethally chambered! You don't want to risk harming anyone...</span>")
|
||||
return
|
||||
if(randomspread)
|
||||
sprd = round((rand() - 0.5) * DUALWIELD_PENALTY_EXTRA_MULTIPLIER * (randomized_gun_spread + randomized_bonus_spread), 1)
|
||||
else //Smart spread
|
||||
sprd = round((((rand_spr/burst_size) * iteration) - (0.5 + (rand_spr * 0.25))) * (randomized_gun_spread + randomized_bonus_spread), 1)
|
||||
|
||||
if(!chambered.fire_casing(target, user, params, ,suppressed, zone_override, sprd, src))
|
||||
shoot_with_empty_chamber(user)
|
||||
firing_burst = FALSE
|
||||
return FALSE
|
||||
else
|
||||
if(get_dist(user, target) <= 1) //Making sure whether the target is in vicinity for the pointblank shot
|
||||
shoot_live_shot(user, 1, target, message)
|
||||
else
|
||||
shoot_live_shot(user, 0, target, message)
|
||||
if (iteration >= burst_size)
|
||||
firing_burst = FALSE
|
||||
else
|
||||
shoot_with_empty_chamber(user)
|
||||
firing_burst = FALSE
|
||||
return FALSE
|
||||
process_chamber()
|
||||
update_icon()
|
||||
return TRUE
|
||||
/obj/item/gun/proc/on_cooldown()
|
||||
return busy_action || firing || ((last_fire + fire_delay) > world.time)
|
||||
|
||||
/obj/item/gun/proc/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
add_fingerprint(user)
|
||||
|
||||
if(semicd)
|
||||
if(on_cooldown())
|
||||
return
|
||||
firing = TRUE
|
||||
. = do_fire(target, user, message, params, zone_override, bonus_spread)
|
||||
firing = FALSE
|
||||
last_fire = world.time
|
||||
|
||||
if(user)
|
||||
user.update_inv_hands()
|
||||
SEND_SIGNAL(user, COMSIG_LIVING_GUN_PROCESS_FIRE, target, params, zone_override)
|
||||
|
||||
/obj/item/gun/proc/do_fire(atom/target, mob/living/user, message = TRUE, params, zone_override = "", bonus_spread = 0)
|
||||
var/sprd = 0
|
||||
var/randomized_gun_spread = 0
|
||||
var/rand_spr = rand()
|
||||
if(spread)
|
||||
randomized_gun_spread = rand(0, spread)
|
||||
randomized_gun_spread = rand(0, spread)
|
||||
else if(burst_size > 1 && burst_spread)
|
||||
randomized_gun_spread = rand(0, burst_spread)
|
||||
if(HAS_TRAIT(user, TRAIT_POOR_AIM)) //nice shootin' tex
|
||||
@@ -275,12 +277,16 @@
|
||||
var/randomized_bonus_spread = rand(0, bonus_spread)
|
||||
|
||||
if(burst_size > 1)
|
||||
firing_burst = TRUE
|
||||
for(var/i = 1 to burst_size)
|
||||
addtimer(CALLBACK(src, .proc/process_burst, user, target, message, params, zone_override, sprd, randomized_gun_spread, randomized_bonus_spread, rand_spr, i), fire_delay * (i - 1))
|
||||
do_burst_shot(user, target, message, params, zone_override, sprd, randomized_gun_spread, randomized_bonus_spread, rand_spr, 1)
|
||||
for(var/i in 2 to burst_size)
|
||||
sleep(burst_shot_delay)
|
||||
if(QDELETED(src))
|
||||
break
|
||||
do_burst_shot(user, target, message, params, zone_override, sprd, randomized_gun_spread, randomized_bonus_spread, rand_spr, i)
|
||||
else
|
||||
if(chambered)
|
||||
sprd = round((rand() - 0.5) * DUALWIELD_PENALTY_EXTRA_MULTIPLIER * (randomized_gun_spread + randomized_bonus_spread))
|
||||
before_firing(target,user)
|
||||
if(!chambered.fire_casing(target, user, params, , suppressed, zone_override, sprd, src))
|
||||
shoot_with_empty_chamber(user)
|
||||
return
|
||||
@@ -294,21 +300,46 @@
|
||||
return
|
||||
process_chamber()
|
||||
update_icon()
|
||||
semicd = TRUE
|
||||
addtimer(CALLBACK(src, .proc/reset_semicd), fire_delay)
|
||||
|
||||
if(user)
|
||||
user.update_inv_hands()
|
||||
SEND_SIGNAL(user, COMSIG_LIVING_GUN_PROCESS_FIRE, target, params, zone_override)
|
||||
SSblackbox.record_feedback("tally", "gun_fired", 1, type)
|
||||
return TRUE
|
||||
|
||||
/obj/item/gun/update_icon()
|
||||
..()
|
||||
|
||||
|
||||
/obj/item/gun/proc/reset_semicd()
|
||||
semicd = FALSE
|
||||
/obj/item/gun/proc/do_burst_shot(mob/living/user, atom/target, message = TRUE, params=null, zone_override = "", sprd = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, rand_spr = 0, iteration = 0)
|
||||
if(!user || !firing)
|
||||
firing = FALSE
|
||||
return FALSE
|
||||
if(!issilicon(user))
|
||||
if(iteration > 1 && !(user.is_holding(src))) //for burst firing
|
||||
firing = FALSE
|
||||
return FALSE
|
||||
if(chambered && chambered.BB)
|
||||
if(HAS_TRAIT(user, TRAIT_PACIFISM)) // If the user has the pacifist trait, then they won't be able to fire [src] if the round chambered inside of [src] is lethal.
|
||||
if(chambered.harmful) // Is the bullet chambered harmful?
|
||||
to_chat(user, "<span class='notice'> [src] is lethally chambered! You don't want to risk harming anyone...</span>")
|
||||
return
|
||||
if(randomspread)
|
||||
sprd = round((rand() - 0.5) * DUALWIELD_PENALTY_EXTRA_MULTIPLIER * (randomized_gun_spread + randomized_bonus_spread), 1)
|
||||
else //Smart spread
|
||||
sprd = round((((rand_spr/burst_size) * iteration) - (0.5 + (rand_spr * 0.25))) * (randomized_gun_spread + randomized_bonus_spread), 1)
|
||||
before_firing(target,user)
|
||||
if(!chambered.fire_casing(target, user, params, ,suppressed, zone_override, sprd, src))
|
||||
shoot_with_empty_chamber(user)
|
||||
firing = FALSE
|
||||
return FALSE
|
||||
else
|
||||
if(get_dist(user, target) <= 1) //Making sure whether the target is in vicinity for the pointblank shot
|
||||
shoot_live_shot(user, 1, target, message)
|
||||
else
|
||||
shoot_live_shot(user, 0, target, message)
|
||||
if (iteration >= burst_size)
|
||||
firing = FALSE
|
||||
else
|
||||
shoot_with_empty_chamber(user)
|
||||
firing = FALSE
|
||||
return FALSE
|
||||
process_chamber()
|
||||
update_icon()
|
||||
return TRUE
|
||||
|
||||
/obj/item/gun/attack(mob/M as mob, mob/user)
|
||||
if(user.a_intent == INTENT_HARM) //Flogging
|
||||
@@ -429,7 +460,7 @@
|
||||
if(!ishuman(user) || !ishuman(target))
|
||||
return
|
||||
|
||||
if(semicd)
|
||||
if(on_cooldown())
|
||||
return
|
||||
|
||||
if(user == target)
|
||||
@@ -439,7 +470,7 @@
|
||||
target.visible_message("<span class='warning'>[user] points [src] at [target]'s head, ready to pull the trigger...</span>", \
|
||||
"<span class='userdanger'>[user] points [src] at your head, ready to pull the trigger...</span>")
|
||||
|
||||
semicd = TRUE
|
||||
busy_action = TRUE
|
||||
|
||||
if(!bypass_timer && (!do_mob(user, target, 120) || user.zone_selected != BODY_ZONE_PRECISE_MOUTH))
|
||||
if(user)
|
||||
@@ -447,10 +478,10 @@
|
||||
user.visible_message("<span class='notice'>[user] decided not to shoot.</span>")
|
||||
else if(target && target.Adjacent(user))
|
||||
target.visible_message("<span class='notice'>[user] has decided to spare [target]</span>", "<span class='notice'>[user] has decided to spare your life!</span>")
|
||||
semicd = FALSE
|
||||
busy_action = FALSE
|
||||
return
|
||||
|
||||
semicd = FALSE
|
||||
busy_action = FALSE
|
||||
|
||||
target.visible_message("<span class='warning'>[user] pulls the trigger!</span>", "<span class='userdanger'>[user] pulls the trigger!</span>")
|
||||
|
||||
@@ -466,6 +497,10 @@
|
||||
qdel(pin)
|
||||
pin = new /obj/item/firing_pin
|
||||
|
||||
//Happens before the actual projectile creation
|
||||
/obj/item/gun/proc/before_firing(atom/target,mob/user)
|
||||
return
|
||||
|
||||
/////////////
|
||||
// ZOOMING //
|
||||
/////////////
|
||||
|
||||
@@ -163,7 +163,7 @@
|
||||
user.visible_message("<span class='suicide'>[user] blows [user.p_their()] brain[user.p_s()] out with [src]!</span>")
|
||||
playsound(src, 'sound/weapons/dink.ogg', 30, 1)
|
||||
var/turf/target = get_ranged_target_turf(user, turn(user.dir, 180), BRAINS_BLOWN_THROW_RANGE)
|
||||
B.Remove(user)
|
||||
B.Remove()
|
||||
B.forceMove(T)
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
var/automatic_burst_overlay = TRUE
|
||||
can_suppress = TRUE
|
||||
burst_size = 3
|
||||
fire_delay = 2
|
||||
burst_shot_delay = 2
|
||||
actions_types = list(/datum/action/item_action/toggle_firemode)
|
||||
|
||||
/obj/item/gun/ballistic/automatic/proto
|
||||
@@ -77,11 +77,9 @@
|
||||
|
||||
/obj/item/gun/ballistic/automatic/proc/enable_burst()
|
||||
burst_size = initial(burst_size)
|
||||
fire_delay = initial(fire_delay)
|
||||
|
||||
/obj/item/gun/ballistic/automatic/proc/disable_burst()
|
||||
burst_size = 1
|
||||
fire_delay = 0
|
||||
|
||||
/obj/item/gun/ballistic/automatic/can_shoot()
|
||||
return get_ammo()
|
||||
@@ -100,7 +98,7 @@
|
||||
item_state = "c20r"
|
||||
mag_type = /obj/item/ammo_box/magazine/smgm45
|
||||
fire_sound = 'sound/weapons/gunshot_smg.ogg'
|
||||
fire_delay = 2
|
||||
burst_shot_delay = 2
|
||||
burst_size = 2
|
||||
pin = /obj/item/firing_pin/implant/pindicate
|
||||
can_bayonet = TRUE
|
||||
@@ -130,7 +128,7 @@
|
||||
mag_type = /obj/item/ammo_box/magazine/wt550m9
|
||||
can_suppress = FALSE
|
||||
burst_size = 2
|
||||
fire_delay = 1
|
||||
burst_shot_delay = 1
|
||||
can_bayonet = TRUE
|
||||
knife_x_offset = 25
|
||||
knife_y_offset = 12
|
||||
@@ -165,7 +163,7 @@
|
||||
can_suppress = FALSE
|
||||
var/obj/item/gun/ballistic/revolver/grenadelauncher/underbarrel
|
||||
burst_size = 3
|
||||
fire_delay = 2
|
||||
burst_shot_delay = 2
|
||||
pin = /obj/item/firing_pin/implant/pindicate
|
||||
|
||||
/obj/item/gun/ballistic/automatic/m90/Initialize()
|
||||
@@ -212,7 +210,6 @@
|
||||
if(0)
|
||||
select = 1
|
||||
burst_size = initial(burst_size)
|
||||
fire_delay = initial(fire_delay)
|
||||
to_chat(user, "<span class='notice'>You switch to [burst_size]-rnd burst.</span>")
|
||||
if(1)
|
||||
select = 2
|
||||
@@ -220,7 +217,6 @@
|
||||
if(2)
|
||||
select = 0
|
||||
burst_size = 1
|
||||
fire_delay = 0
|
||||
to_chat(user, "<span class='notice'>You switch to semi-auto.</span>")
|
||||
playsound(user, 'sound/weapons/empty.ogg', 100, 1)
|
||||
update_icon()
|
||||
@@ -237,7 +233,7 @@
|
||||
fire_sound = 'sound/weapons/gunshot_smg.ogg'
|
||||
can_suppress = FALSE
|
||||
burst_size = 4
|
||||
fire_delay = 1
|
||||
burst_shot_delay = 1
|
||||
|
||||
/obj/item/gun/ballistic/automatic/ar
|
||||
name = "\improper NT-ARG 'Boarder'"
|
||||
@@ -249,7 +245,7 @@
|
||||
fire_sound = 'sound/weapons/gunshot_smg.ogg'
|
||||
can_suppress = FALSE
|
||||
burst_size = 3
|
||||
fire_delay = 1
|
||||
burst_shot_delay = 1
|
||||
|
||||
// Bulldog shotgun //
|
||||
|
||||
@@ -264,7 +260,6 @@
|
||||
fire_sound = 'sound/weapons/gunshot.ogg'
|
||||
can_suppress = FALSE
|
||||
burst_size = 1
|
||||
fire_delay = 0
|
||||
pin = /obj/item/firing_pin/implant/pindicate
|
||||
actions_types = list()
|
||||
|
||||
@@ -301,7 +296,7 @@
|
||||
var/cover_open = FALSE
|
||||
can_suppress = FALSE
|
||||
burst_size = 3
|
||||
fire_delay = 1
|
||||
burst_shot_delay = 1
|
||||
spread = 7
|
||||
pin = /obj/item/firing_pin/implant/pindicate
|
||||
|
||||
@@ -421,7 +416,7 @@
|
||||
mag_type = /obj/item/ammo_box/magazine/recharge
|
||||
fire_delay = 2
|
||||
can_suppress = FALSE
|
||||
burst_size = 0
|
||||
burst_size = 1
|
||||
actions_types = list()
|
||||
fire_sound = 'sound/weapons/laser.ogg'
|
||||
casing_ejector = FALSE
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/obj/item/gun/ballistic/bow
|
||||
name = "wooden bow"
|
||||
desc = "Some sort of primitive projectile weapon. Used to fire arrows."
|
||||
icon_state = "bow"
|
||||
item_state = "bow"
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
weapon_weight = WEAPON_HEAVY //need both hands to fire
|
||||
force = 5
|
||||
mag_type = /obj/item/ammo_box/magazine/internal/bow
|
||||
fire_sound = 'sound/weapons/bowfire.wav'
|
||||
slot_flags = ITEM_SLOT_BACK
|
||||
item_flags = NONE
|
||||
casing_ejector = FALSE
|
||||
inaccuracy_modifier = 0.33 //to counteract the innaccuracy from WEAPON_HEAVY, bows are supposed to be accurate but only able to be fired with both hands
|
||||
pin = null
|
||||
no_pin_required = TRUE
|
||||
trigger_guard = TRIGGER_GUARD_NONE //so ashwalkers can use it
|
||||
|
||||
/obj/item/gun/ballistic/bow/shoot_with_empty_chamber()
|
||||
return
|
||||
|
||||
/obj/item/gun/ballistic/bow/chamber_round()
|
||||
chambered = magazine.get_round(1)
|
||||
|
||||
/obj/item/gun/ballistic/bow/afterattack()
|
||||
. = ..()
|
||||
if (chambered)
|
||||
chambered = null
|
||||
magazine.get_round(0)
|
||||
update_icon()
|
||||
|
||||
/obj/item/gun/ballistic/bow/attack_self(mob/living/user)
|
||||
if (chambered)
|
||||
var/obj/item/ammo_casing/AC = magazine.get_round(0)
|
||||
user.put_in_hands(AC)
|
||||
chambered = null
|
||||
to_chat(user, "<span class='notice'>You gently release the bowstring, removing the arrow.</span>")
|
||||
else if (get_ammo())
|
||||
to_chat(user, "<span class='notice'>You draw back the bowstring.</span>")
|
||||
playsound(src, 'sound/weapons/bowdraw.wav', 75, 0) //gets way too high pitched if the freq varies
|
||||
chamber_round()
|
||||
update_icon()
|
||||
|
||||
/obj/item/gun/ballistic/bow/attackby(obj/item/I, mob/user, params)
|
||||
if (magazine.attackby(I, user, params, 1))
|
||||
to_chat(user, "<span class='notice'>You notch the arrow.</span>")
|
||||
update_icon()
|
||||
|
||||
/obj/item/gun/ballistic/bow/update_icon()
|
||||
icon_state = "bow_[get_ammo() ? (chambered ? "firing" : "loaded") : "unloaded"]"
|
||||
|
||||
/obj/item/gun/ballistic/bow/can_shoot()
|
||||
return chambered
|
||||
@@ -0,0 +1,103 @@
|
||||
/obj/item/gun/ballistic/automatic/magrifle
|
||||
name = "\improper Magnetic Rifle"
|
||||
desc = "A simple upscalling of the technologies used in the magpistol, the magrifle is capable of firing slightly larger slugs in bursts. Compatible with the magpistol's slugs."
|
||||
icon_state = "magrifle"
|
||||
item_state = "arg"
|
||||
force = 10
|
||||
slot_flags = NONE
|
||||
mag_type = /obj/item/ammo_box/magazine/mmag
|
||||
fire_sound = 'sound/weapons/magrifle.ogg'
|
||||
can_suppress = FALSE
|
||||
burst_size = 1
|
||||
actions_types = null
|
||||
fire_delay = 3
|
||||
spread = 0
|
||||
recoil = 0.1
|
||||
casing_ejector = FALSE
|
||||
inaccuracy_modifier = 0.5
|
||||
dualwield_spread_mult = 1.4
|
||||
weapon_weight = WEAPON_MEDIUM
|
||||
var/obj/item/stock_parts/cell/cell
|
||||
var/cell_type = /obj/item/stock_parts/cell/magnetic
|
||||
|
||||
/obj/item/gun/ballistic/automatic/magrifle/Initialize()
|
||||
. = ..()
|
||||
if(cell_type)
|
||||
cell = new cell_type(src)
|
||||
else
|
||||
cell = new(src)
|
||||
|
||||
/obj/item/gun/ballistic/automatic/magrifle/examine(mob/user)
|
||||
. = ..()
|
||||
if(cell)
|
||||
. += "<span class='notice'>[src]'s cell is [round(cell.charge / cell.maxcharge, 0.1) * 100]% full.</span>"
|
||||
else
|
||||
. += "<span class='notice'>[src] doesn't seem to have a cell!</span>"
|
||||
|
||||
/obj/item/gun/ballistic/automatic/magrifle/can_shoot()
|
||||
if(QDELETED(cell))
|
||||
return 0
|
||||
|
||||
var/obj/item/ammo_casing/caseless/magnetic/shot = chambered
|
||||
if(!shot)
|
||||
return 0
|
||||
if(cell.charge < shot.energy_cost * burst_size)
|
||||
return 0
|
||||
. = ..()
|
||||
|
||||
/obj/item/gun/ballistic/automatic/magrifle/shoot_live_shot()
|
||||
var/obj/item/ammo_casing/caseless/magnetic/shot = chambered
|
||||
cell.use(shot.energy_cost)
|
||||
. = ..()
|
||||
|
||||
/obj/item/gun/ballistic/automatic/magrifle/emp_act(severity)
|
||||
. = ..()
|
||||
if(!(. & EMP_PROTECT_CONTENTS))
|
||||
cell.use(round(cell.charge / severity))
|
||||
|
||||
/obj/item/gun/ballistic/automatic/magrifle/get_cell()
|
||||
return cell
|
||||
|
||||
/obj/item/gun/ballistic/automatic/magrifle/nopin
|
||||
pin = null
|
||||
spawnwithmagazine = FALSE
|
||||
cell_type = /obj/item/stock_parts/cell/magnetic/empty
|
||||
|
||||
/obj/item/gun/ballistic/automatic/magrifle/hyperburst
|
||||
name = "\improper Hyper-Burst Rifle"
|
||||
desc = "An extremely beefed up version of a stolen Nanotrasen weapon prototype, this 'rifle' is more like a cannon, with an extremely large bore barrel capable of generating several smaller magnetic 'barrels' to simultaneously launch multiple projectiles at once."
|
||||
icon_state = "hyperburst"
|
||||
item_state = "arg"
|
||||
mag_type = /obj/item/ammo_box/magazine/mhyper
|
||||
fire_sound = 'sound/weapons/magburst.ogg'
|
||||
fire_delay = 40
|
||||
recoil = 2
|
||||
weapon_weight = WEAPON_HEAVY
|
||||
|
||||
/obj/item/gun/ballistic/automatic/magrifle/hyperburst/update_icon()
|
||||
..()
|
||||
icon_state = "hyperburst[magazine ? "-[get_ammo()]" : ""][chambered ? "" : "-e"]"
|
||||
|
||||
///magpistol///
|
||||
|
||||
/obj/item/gun/ballistic/automatic/magrifle/pistol
|
||||
name = "magpistol"
|
||||
desc = "A handgun utilizing maglev technologies to propel a ferromagnetic slug to extreme velocities."
|
||||
icon_state = "magpistol"
|
||||
fire_sound = 'sound/weapons/magpistol.ogg'
|
||||
mag_type = /obj/item/ammo_box/magazine/mmag/small
|
||||
fire_delay = 2
|
||||
inaccuracy_modifier = 0.25
|
||||
cell_type = /obj/item/stock_parts/cell/magnetic/pistol
|
||||
|
||||
/obj/item/gun/ballistic/automatic/magrifle/pistol/update_icon()
|
||||
..()
|
||||
cut_overlays()
|
||||
if(magazine)
|
||||
add_overlay("magpistol-magazine")
|
||||
icon_state = "[initial(icon_state)][chambered ? "" : "-e"]"
|
||||
|
||||
/obj/item/gun/ballistic/automatic/magrifle/pistol/nopin
|
||||
pin = null
|
||||
spawnwithmagazine = FALSE
|
||||
cell_type = /obj/item/stock_parts/cell/magnetic/pistol/empty
|
||||
@@ -79,6 +79,7 @@
|
||||
/obj/item/gun/ballistic/automatic/pistol/stickman
|
||||
name = "flat gun"
|
||||
desc = "A 2 dimensional gun.. what?"
|
||||
can_suppress = FALSE
|
||||
icon_state = "flatgun"
|
||||
|
||||
/obj/item/gun/ballistic/automatic/pistol/stickman/pickup(mob/living/user)
|
||||
|
||||
@@ -96,15 +96,20 @@
|
||||
"Gold Trim" = "detective_gold",
|
||||
"The Peacemaker" = "detective_peacemaker"
|
||||
)
|
||||
var/list/safe_calibers
|
||||
|
||||
/obj/item/gun/ballistic/revolver/detective/Initialize()
|
||||
. = ..()
|
||||
safe_calibers = magazine.caliber
|
||||
|
||||
/obj/item/gun/ballistic/revolver/detective/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
if(magazine.caliber != initial(magazine.caliber))
|
||||
if(chambered && !(chambered.caliber in safe_calibers))
|
||||
if(prob(70 - (magazine.ammo_count() * 10))) //minimum probability of 10, maximum of 60
|
||||
playsound(user, fire_sound, 50, 1)
|
||||
to_chat(user, "<span class='userdanger'>[src] blows up in your face!</span>")
|
||||
user.take_bodypart_damage(0,20)
|
||||
user.dropItemToGround(src)
|
||||
return 0
|
||||
return FALSE
|
||||
..()
|
||||
|
||||
/obj/item/gun/ballistic/revolver/detective/screwdriver_act(mob/living/user, obj/item/I)
|
||||
|
||||
@@ -109,3 +109,36 @@
|
||||
|
||||
/obj/item/gun/ballistic/automatic/l6_saw/toy/unrestricted/riot
|
||||
mag_type = /obj/item/ammo_box/magazine/toy/m762/riot
|
||||
|
||||
/obj/item/gun/ballistic/automatic/toy/magrifle
|
||||
name = "foamag rifle"
|
||||
desc = "A foam launching magnetic rifle. Ages 8 and up."
|
||||
icon_state = "foamagrifle"
|
||||
obj_flags = NONE
|
||||
mag_type = /obj/item/ammo_box/magazine/toy/foamag
|
||||
fire_sound = 'sound/weapons/magrifle.ogg'
|
||||
burst_size = 1
|
||||
actions_types = null
|
||||
fire_delay = 3
|
||||
spread = 60
|
||||
recoil = 0.1
|
||||
can_suppress = FALSE
|
||||
inaccuracy_modifier = 0.5
|
||||
weapon_weight = WEAPON_MEDIUM
|
||||
dualwield_spread_mult = 1.4
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
|
||||
/obj/item/gun/ballistic/shotgun/toy/mag
|
||||
name = "foam force magpistol"
|
||||
desc = "A fancy toy sold alongside light-up foam force darts. Ages 8 and up."
|
||||
icon_state = "toymag"
|
||||
item_state = "gun"
|
||||
mag_type = /obj/item/ammo_box/magazine/internal/shot/toy/mag
|
||||
fire_sound = 'sound/weapons/magpistol.ogg'
|
||||
fire_delay = 2
|
||||
recoil = 0.1
|
||||
inaccuracy_modifier = 0.25
|
||||
dualwield_spread_mult = 1.4
|
||||
slot_flags = SLOT_BELT
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
weapon_weight = WEAPON_MEDIUM
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/*
|
||||
* Energy guns that draw from a cell to fire.
|
||||
*
|
||||
* This is a bit weird but this is how it currently works:
|
||||
* When switching shots, it clears the chamber, and loads the correct energy ammo casing if there is enough energy to fire it.
|
||||
* If there's no projectile in the casing, it creates it now.
|
||||
* Otherwise the chamber stays null.
|
||||
* After firing, it actually deducts the energy and then clears the chamber and does the above again.
|
||||
* It detects if a successful fire is done by checking if the chambered energy ammo casing still has its projectile intact.
|
||||
*
|
||||
* It might be good in the future to move away from ammo casinsgs and instead use a datum-firemode system, but that would make handling firing,
|
||||
* which the casing does as of now, a little interesting to implement.
|
||||
*/
|
||||
/obj/item/gun/energy
|
||||
icon_state = "energy"
|
||||
name = "energy gun"
|
||||
@@ -7,8 +20,10 @@
|
||||
var/obj/item/stock_parts/cell/cell //What type of power cell this uses
|
||||
var/cell_type = /obj/item/stock_parts/cell
|
||||
var/modifystate = 0
|
||||
var/list/ammo_type = list(/obj/item/ammo_casing/energy)
|
||||
var/select = 1 //The state of the select fire switch. Determines from the ammo_type list what kind of shot is fired next.
|
||||
/// = TRUE/FALSE decides if the user can switch to it of their own accord
|
||||
var/list/ammo_type = list(/obj/item/ammo_casing/energy = TRUE)
|
||||
/// The index of the ammo_types/firemodes which we're using right now
|
||||
var/current_firemode_index = 1
|
||||
var/can_charge = 1 //Can it be charged in a recharger?
|
||||
var/automatic_charge_overlays = TRUE //Do we handle overlays with base update_icon()?
|
||||
var/charge_sections = 4
|
||||
@@ -21,6 +36,9 @@
|
||||
var/use_cyborg_cell = FALSE //whether the gun drains the cyborg user's cell instead, not to be confused with EGUN_SELFCHARGE_BORG
|
||||
var/dead_cell = FALSE //set to true so the gun is given an empty cell
|
||||
|
||||
/// SET THIS TO TRUE IF YOU OVERRIDE altafterattack() or ANY right click action! If this is FALSE, the gun will show in examine its default right click behavior, which is to switch modes.
|
||||
var/right_click_overridden = FALSE
|
||||
|
||||
/obj/item/gun/energy/emp_act(severity)
|
||||
. = ..()
|
||||
if(!(. & EMP_PROTECT_CONTENTS))
|
||||
@@ -46,21 +64,18 @@
|
||||
START_PROCESSING(SSobj, src)
|
||||
update_icon()
|
||||
|
||||
/obj/item/gun/energy/proc/update_ammo_types()
|
||||
var/obj/item/ammo_casing/energy/shot
|
||||
for (var/i = 1, i <= ammo_type.len, i++)
|
||||
var/shottype = ammo_type[i]
|
||||
shot = new shottype(src)
|
||||
ammo_type[i] = shot
|
||||
shot = ammo_type[select]
|
||||
fire_sound = shot.fire_sound
|
||||
fire_delay = shot.delay
|
||||
|
||||
/obj/item/gun/energy/Destroy()
|
||||
QDEL_NULL(cell)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
if(flags_1 & INITIALIZED_1)
|
||||
QDEL_NULL(cell)
|
||||
QDEL_LIST(ammo_type)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/item/gun/energy/examine(mob/user)
|
||||
. = ..()
|
||||
if(!right_click_overridden)
|
||||
. += "<span class='notice'>Right click in combat mode to switch modes.</span>"
|
||||
|
||||
/obj/item/gun/energy/process()
|
||||
if(selfcharge && cell?.charge < cell.maxcharge)
|
||||
charge_tick++
|
||||
@@ -81,13 +96,14 @@
|
||||
recharge_newshot(TRUE)
|
||||
update_icon()
|
||||
|
||||
/obj/item/gun/energy/attack_self(mob/living/user as mob)
|
||||
if(ammo_type.len > 1)
|
||||
// ATTACK SELF IGNORING PARENT RETURN VALUE
|
||||
/obj/item/gun/energy/attack_self(mob/living/user)
|
||||
. = ..()
|
||||
if(can_select_fire(user))
|
||||
select_fire(user)
|
||||
update_icon()
|
||||
|
||||
/obj/item/gun/energy/can_shoot()
|
||||
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
|
||||
var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index]
|
||||
return !QDELETED(cell) ? (cell.charge >= shot.e_cost) : FALSE
|
||||
|
||||
/obj/item/gun/energy/recharge_newshot(no_cyborg_drain)
|
||||
@@ -97,11 +113,11 @@
|
||||
if(iscyborg(loc))
|
||||
var/mob/living/silicon/robot/R = loc
|
||||
if(R.cell)
|
||||
var/obj/item/ammo_casing/energy/shot = ammo_type[select] //Necessary to find cost of shot
|
||||
var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index] //Necessary to find cost of shot
|
||||
if(R.cell.use(shot.e_cost)) //Take power from the borg...
|
||||
cell.give(shot.e_cost) //... to recharge the shot
|
||||
if(!chambered)
|
||||
var/obj/item/ammo_casing/energy/AC = ammo_type[select]
|
||||
var/obj/item/ammo_casing/energy/AC = ammo_type[current_firemode_index]
|
||||
if(cell.charge >= AC.e_cost) //if there's enough power in the cell cell...
|
||||
chambered = AC //...prepare a new shot based on the current ammo type selected
|
||||
if(!chambered.BB)
|
||||
@@ -114,29 +130,104 @@
|
||||
chambered = null //either way, released the prepared shot
|
||||
recharge_newshot() //try to charge a new shot
|
||||
|
||||
/obj/item/gun/energy/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/energy/do_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
if(!chambered && can_shoot())
|
||||
process_chamber() // If the gun was drained and then recharged, load a new shot.
|
||||
return ..()
|
||||
|
||||
/obj/item/gun/energy/process_burst(mob/living/user, atom/target, message = TRUE, params = null, zone_override="", sprd = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, rand_spr = 0, iteration = 0)
|
||||
/obj/item/gun/energy/do_burst_shot(mob/living/user, atom/target, message = TRUE, params = null, zone_override="", sprd = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, rand_spr = 0, iteration = 0)
|
||||
if(!chambered && can_shoot())
|
||||
process_chamber() // Ditto.
|
||||
return ..()
|
||||
|
||||
/obj/item/gun/energy/proc/select_fire(mob/living/user)
|
||||
select++
|
||||
if (select > ammo_type.len)
|
||||
select = 1
|
||||
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
|
||||
fire_sound = shot.fire_sound
|
||||
fire_delay = shot.delay
|
||||
if (shot.select_name)
|
||||
to_chat(user, "<span class='notice'>[src] is now set to [shot.select_name].</span>")
|
||||
chambered = null
|
||||
recharge_newshot(TRUE)
|
||||
// Firemodes/Ammotypes
|
||||
|
||||
/obj/item/gun/energy/proc/update_ammo_types()
|
||||
var/obj/item/ammo_casing/energy/C
|
||||
for(var/i in 1 to length(ammo_type))
|
||||
var/v = ammo_type[i]
|
||||
var/user_can_select = ammo_type[v]
|
||||
if(istype(v, /obj/item/ammo_casing/energy)) //already set
|
||||
ammo_type[v] = isnull(user_can_select)? TRUE : user_can_select
|
||||
else
|
||||
C = new v(src) //if you put non energycasing/type stuff in here you deserve the runtime
|
||||
ammo_type[i] = C
|
||||
ammo_type[C] = isnull(user_can_select)? TRUE : user_can_select
|
||||
set_firemode_index(initial(current_firemode_index))
|
||||
|
||||
/obj/item/gun/energy/proc/set_firemode_index(index, mob/user_for_feedback)
|
||||
chambered = null //unchamber whatever we have chambered
|
||||
if(index > length(ammo_type))
|
||||
index = 1
|
||||
else if(index < 1)
|
||||
index = length(ammo_type)
|
||||
var/obj/item/ammo_casing/energy/C = ammo_type[index] //energy weapons should not have no casings, if it does you deserve the runtime.
|
||||
current_firemode_index = index
|
||||
fire_sound = C.fire_sound
|
||||
fire_delay = C.delay
|
||||
if(user_for_feedback)
|
||||
to_chat(user_for_feedback, "<span class='notice'>[src] is now set to [C.select_name || C].</span>")
|
||||
post_set_firemode()
|
||||
update_icon(TRUE)
|
||||
return
|
||||
|
||||
/obj/item/gun/energy/proc/post_set_firemode(recharge_newshot = TRUE)
|
||||
if(recharge_newshot)
|
||||
recharge_newshot(TRUE)
|
||||
|
||||
/obj/item/gun/energy/proc/set_firemode_to_next(mob/user_for_feedback)
|
||||
return set_firemode_index(++current_firemode_index, user_for_feedback)
|
||||
|
||||
/obj/item/gun/energy/proc/set_firemode_to_prev(mob/user_for_feedback)
|
||||
return set_firemode_index(--current_firemode_index, user_for_feedback)
|
||||
|
||||
/obj/item/gun/energy/proc/get_firemode_index(casing_type)
|
||||
var/obj/item/ammo_casing/energy/E = locate(casing_type) in ammo_type
|
||||
if(E)
|
||||
return ammo_type.Find(E)
|
||||
|
||||
/obj/item/gun/energy/proc/set_firemode_to_type(casing_type)
|
||||
var/index = get_firemode_index(casing_type)
|
||||
if(index)
|
||||
set_firemode_index(index)
|
||||
|
||||
/// This is the proc used in general for when a user switches firemodes. Just goes to next firemode by default.
|
||||
/obj/item/gun/energy/proc/select_fire(mob/living/user)
|
||||
return user_set_firemode_to_next(user)
|
||||
|
||||
/obj/item/gun/energy/proc/can_select_fire(mob/living/user)
|
||||
return TRUE
|
||||
|
||||
#define INCREMENT_OR_WRAP(i) i = (i >= length(ammo_type))? 1 : (i + 1)
|
||||
#define DECREMENT_OR_WRAP(i) i = (i <= 1)? length(ammo_type) : (i - 1)
|
||||
#define IS_VALID_INDEX(i) (ammo_type[ammo_type[i]])
|
||||
/obj/item/gun/energy/proc/user_set_firemode_to_next(mob/user_for_feedback)
|
||||
var/current_index = current_firemode_index
|
||||
var/new_index = current_index
|
||||
INCREMENT_OR_WRAP(new_index)
|
||||
if(!IS_VALID_INDEX(new_index))
|
||||
var/initial_index = new_index
|
||||
while(!IS_VALID_INDEX(new_index) && (new_index != initial_index))
|
||||
new_index = INCREMENT_OR_WRAP(new_index)
|
||||
if(initial_index == new_index) //cycled through without finding another
|
||||
new_index = current_index
|
||||
|
||||
set_firemode_index(new_index, user_for_feedback)
|
||||
|
||||
/obj/item/gun/energy/proc/user_set_firemode_to_prev(mob/user_for_feedback)
|
||||
var/current_index = current_firemode_index
|
||||
var/new_index = current_index
|
||||
DECREMENT_OR_WRAP(new_index)
|
||||
if(!IS_VALID_INDEX(new_index))
|
||||
var/initial_index = new_index
|
||||
while(!IS_VALID_INDEX(new_index) && (new_index != initial_index))
|
||||
new_index = DECREMENT_OR_WRAP(new_index)
|
||||
if(initial_index == new_index) //cycled through without finding another
|
||||
new_index = current_index
|
||||
|
||||
set_firemode_index(new_index, user_for_feedback)
|
||||
#undef INCREMENT_OR_WRAP
|
||||
#undef DECREMENT_OR_WRAP
|
||||
#undef IS_VALID_INDEX
|
||||
|
||||
/obj/item/gun/energy/update_icon(force_update)
|
||||
if(QDELETED(src))
|
||||
@@ -156,7 +247,7 @@
|
||||
if(!initial(item_state))
|
||||
itemState = icon_state
|
||||
if (modifystate)
|
||||
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
|
||||
var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index]
|
||||
add_overlay("[icon_state]_[shot.select_name]")
|
||||
iconState += "_[shot.select_name]"
|
||||
if(itemState)
|
||||
@@ -175,6 +266,9 @@
|
||||
if(itemState)
|
||||
itemState += "[ratio]"
|
||||
item_state = itemState
|
||||
if(ismob(loc)) //forces inhands to update
|
||||
var/mob/M = loc
|
||||
M.update_inv_hands()
|
||||
|
||||
/obj/item/gun/energy/suicide_act(mob/living/user)
|
||||
if (istype(user) && can_shoot() && can_trigger_gun(user) && user.get_bodypart(BODY_ZONE_HEAD))
|
||||
@@ -184,7 +278,7 @@
|
||||
user.visible_message("<span class='suicide'>[user] melts [user.p_their()] face off with [src]!</span>")
|
||||
playsound(loc, fire_sound, 50, 1, -1)
|
||||
playsound(src, 'sound/weapons/dink.ogg', 30, 1)
|
||||
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
|
||||
var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index]
|
||||
cell.use(shot.e_cost)
|
||||
update_icon()
|
||||
return(FIRELOSS)
|
||||
@@ -206,13 +300,12 @@
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
. = ..()
|
||||
|
||||
|
||||
/obj/item/gun/energy/ignition_effect(atom/A, mob/living/user)
|
||||
if(!can_shoot() || !ammo_type[select])
|
||||
if(!can_shoot() || !ammo_type[current_firemode_index])
|
||||
shoot_with_empty_chamber()
|
||||
. = ""
|
||||
else
|
||||
var/obj/item/ammo_casing/energy/E = ammo_type[select]
|
||||
var/obj/item/ammo_casing/energy/E = ammo_type[current_firemode_index]
|
||||
var/obj/item/projectile/energy/BB = E.BB
|
||||
if(!BB)
|
||||
. = ""
|
||||
@@ -234,3 +327,9 @@
|
||||
playsound(user, BB.hitsound, 50, 1)
|
||||
cell.use(E.e_cost)
|
||||
. = "<span class='danger'>[user] casually lights their [A.name] with [src]. Damn.</span>"
|
||||
|
||||
/obj/item/gun/energy/altafterattack(atom/target, mob/user, proximity_flags, params)
|
||||
if(!right_click_overridden)
|
||||
select_fire(user)
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
@@ -0,0 +1,389 @@
|
||||
#define DUEL_IDLE 1
|
||||
#define DUEL_PREPARATION 2
|
||||
#define DUEL_READY 3
|
||||
#define DUEL_COUNTDOWN 4
|
||||
#define DUEL_FIRING 5
|
||||
|
||||
//paper rock scissors
|
||||
#define DUEL_SETTING_A "wide"
|
||||
#define DUEL_SETTING_B "cone"
|
||||
#define DUEL_SETTING_C "pinpoint"
|
||||
|
||||
#define DUEL_HUGBOX_NONE 0 //dismember head
|
||||
#define DUEL_HUGBOX_LETHAL 1 //200 damage to chest
|
||||
#define DUEL_HUGBOX_NONLETHAL 2 //stamcrit
|
||||
|
||||
/datum/duel
|
||||
var/obj/item/gun/energy/dueling/gun_A
|
||||
var/obj/item/gun/energy/dueling/gun_B
|
||||
var/state = DUEL_IDLE
|
||||
var/required_distance = 5
|
||||
var/list/confirmations = list()
|
||||
var/list/fired = list()
|
||||
var/countdown_length = 10
|
||||
var/countdown_step = 0
|
||||
var/static/next_id = 1
|
||||
var/id
|
||||
|
||||
/datum/duel/New()
|
||||
id = next_id++
|
||||
|
||||
/datum/duel/proc/try_begin()
|
||||
//Check if both guns are held and if so begin.
|
||||
var/mob/living/A = get_duelist(gun_A)
|
||||
var/mob/living/B = get_duelist(gun_B)
|
||||
if(!A || !B)
|
||||
message_duelists("<span class='warning'>To begin the duel, both participants need to be holding paired dueling pistols.</span>")
|
||||
return
|
||||
begin()
|
||||
|
||||
/datum/duel/proc/begin()
|
||||
state = DUEL_PREPARATION
|
||||
confirmations.Cut()
|
||||
fired.Cut()
|
||||
countdown_step = countdown_length
|
||||
|
||||
message_duelists("<span class='notice'>Set your gun setting and move [required_distance] steps away from your opponent.</span>")
|
||||
|
||||
START_PROCESSING(SSobj,src)
|
||||
|
||||
/datum/duel/proc/get_duelist(obj/gun)
|
||||
var/mob/living/G = gun.loc
|
||||
if(!istype(G) || !G.is_holding(gun))
|
||||
return null
|
||||
return G
|
||||
|
||||
/datum/duel/proc/message_duelists(message)
|
||||
var/mob/living/LA = get_duelist(gun_A)
|
||||
if(LA)
|
||||
to_chat(LA,message)
|
||||
var/mob/living/LB = get_duelist(gun_B)
|
||||
if(LB)
|
||||
to_chat(LB,message)
|
||||
|
||||
/datum/duel/proc/other_gun(obj/item/gun/energy/dueling/G)
|
||||
return G == gun_A ? gun_B : gun_A
|
||||
|
||||
/datum/duel/proc/end()
|
||||
message_duelists("<span class='notice'>Duel finished. Re-engaging safety.</span>")
|
||||
STOP_PROCESSING(SSobj,src)
|
||||
state = DUEL_IDLE
|
||||
|
||||
/datum/duel/process()
|
||||
switch(state)
|
||||
if(DUEL_PREPARATION)
|
||||
if(check_positioning())
|
||||
confirm_positioning()
|
||||
else if (!get_duelist(gun_A) && !get_duelist(gun_B))
|
||||
end()
|
||||
if(DUEL_READY)
|
||||
if(!check_positioning())
|
||||
back_to_prep()
|
||||
else if(confirmations.len == 2)
|
||||
confirm_ready()
|
||||
if(DUEL_COUNTDOWN)
|
||||
if(!check_positioning())
|
||||
back_to_prep()
|
||||
else
|
||||
countdown_step()
|
||||
if(DUEL_FIRING)
|
||||
if(check_fired())
|
||||
end()
|
||||
|
||||
/datum/duel/proc/back_to_prep()
|
||||
message_duelists("<span class='notice'>Positions invalid. Please move to valid positions [required_distance] steps aways from each other to continue.</span>")
|
||||
state = DUEL_PREPARATION
|
||||
confirmations.Cut()
|
||||
countdown_step = countdown_length
|
||||
|
||||
/datum/duel/proc/confirm_positioning()
|
||||
message_duelists("<span class='notice'>Position confirmed. Confirm readiness by pulling the trigger once.</span>")
|
||||
state = DUEL_READY
|
||||
|
||||
/datum/duel/proc/confirm_ready()
|
||||
message_duelists("<span class='notice'>Readiness confirmed. Starting countdown. Commence firing at zero mark.</span>")
|
||||
state = DUEL_COUNTDOWN
|
||||
|
||||
/datum/duel/proc/countdown_step()
|
||||
countdown_step--
|
||||
if(countdown_step == 0)
|
||||
state = DUEL_FIRING
|
||||
message_duelists("<span class='userdanger'>Fire!</span>")
|
||||
else
|
||||
message_duelists("<span class='userdanger'>[countdown_step]!</span>")
|
||||
|
||||
/datum/duel/proc/check_fired()
|
||||
if(fired.len == 2)
|
||||
return TRUE
|
||||
//Let's say if gun was dropped/stowed the user is finished
|
||||
if(!get_duelist(gun_A))
|
||||
return TRUE
|
||||
if(!get_duelist(gun_B))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/duel/proc/check_positioning()
|
||||
var/mob/living/A = get_duelist(gun_A)
|
||||
var/mob/living/B = get_duelist(gun_B)
|
||||
if(!A || !B)
|
||||
return FALSE
|
||||
if(!isturf(A.loc) || !isturf(B.loc))
|
||||
return FALSE
|
||||
if(get_dist(A,B) != required_distance)
|
||||
return FALSE
|
||||
for(var/turf/T in getline(get_turf(A),get_turf(B)))
|
||||
if(is_blocked_turf(T,TRUE))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/gun/energy/dueling
|
||||
name = "dueling pistol"
|
||||
desc = "High-tech dueling pistol. Launches chaff and projectile according to preset settings."
|
||||
icon_state = "dueling_pistol"
|
||||
item_state = "gun"
|
||||
ammo_x_offset = 2
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/duel)
|
||||
automatic_charge_overlays = FALSE
|
||||
var/unlocked = FALSE
|
||||
var/setting = DUEL_SETTING_A
|
||||
var/datum/duel/duel
|
||||
var/mutable_appearance/setting_overlay
|
||||
var/hugbox = DUEL_HUGBOX_NONE
|
||||
|
||||
/obj/item/gun/energy/dueling/hugbox
|
||||
hugbox = DUEL_HUGBOX_LETHAL
|
||||
|
||||
/obj/item/gun/energy/dueling/hugbox/stamina
|
||||
hugbox = DUEL_HUGBOX_NONLETHAL
|
||||
|
||||
/obj/item/gun/energy/dueling/Initialize()
|
||||
. = ..()
|
||||
setting_overlay = mutable_appearance(icon,setting_iconstate())
|
||||
add_overlay(setting_overlay)
|
||||
|
||||
/obj/item/gun/energy/dueling/examine(mob/user)
|
||||
. = ..()
|
||||
if(duel)
|
||||
. += "Its linking number is [duel.id]."
|
||||
else
|
||||
. += "ERROR: No linking number on gun."
|
||||
|
||||
/obj/item/gun/energy/dueling/proc/setting_iconstate()
|
||||
switch(setting)
|
||||
if(DUEL_SETTING_A)
|
||||
return "duel_red"
|
||||
if(DUEL_SETTING_B)
|
||||
return "duel_green"
|
||||
if(DUEL_SETTING_C)
|
||||
return "duel_blue"
|
||||
return "duel_red"
|
||||
|
||||
/obj/item/gun/energy/dueling/attack_self(mob/living/user)
|
||||
. = ..()
|
||||
if(duel.state == DUEL_IDLE)
|
||||
duel.try_begin()
|
||||
else
|
||||
toggle_setting(user)
|
||||
|
||||
/obj/item/gun/energy/dueling/proc/toggle_setting(mob/living/user)
|
||||
switch(setting)
|
||||
if(DUEL_SETTING_A)
|
||||
setting = DUEL_SETTING_B
|
||||
if(DUEL_SETTING_B)
|
||||
setting = DUEL_SETTING_C
|
||||
if(DUEL_SETTING_C)
|
||||
setting = DUEL_SETTING_A
|
||||
to_chat(user,"<span class='notice'>You switch [src] setting to [setting] mode.</span>")
|
||||
update_icon()
|
||||
|
||||
/obj/item/gun/energy/dueling/update_icon(force_update)
|
||||
. = ..()
|
||||
if(setting_overlay)
|
||||
cut_overlay(setting_overlay)
|
||||
setting_overlay.icon_state = setting_iconstate()
|
||||
add_overlay(setting_overlay)
|
||||
|
||||
/obj/item/gun/energy/dueling/Destroy()
|
||||
. = ..()
|
||||
if(duel.gun_A == src)
|
||||
duel.gun_A = null
|
||||
if(duel.gun_B == src)
|
||||
duel.gun_B = null
|
||||
duel = null
|
||||
|
||||
/obj/item/gun/energy/dueling/can_trigger_gun(mob/living/user)
|
||||
. = ..()
|
||||
switch(duel.state)
|
||||
if(DUEL_FIRING)
|
||||
return . && !duel.fired[src]
|
||||
if(DUEL_READY)
|
||||
return .
|
||||
else
|
||||
to_chat(user,"<span class='warning'>[src] is locked. Wait for FIRE signal before shooting.</span>")
|
||||
return FALSE
|
||||
|
||||
/obj/item/gun/energy/dueling/proc/is_duelist(mob/living/L)
|
||||
if(!istype(L))
|
||||
return FALSE
|
||||
if(!L.is_holding(duel.other_gun(src)))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/gun/energy/dueling/process_fire(atom/target, mob/living/user, message, params, zone_override, bonus_spread)
|
||||
if(duel.state == DUEL_READY)
|
||||
duel.confirmations[src] = TRUE
|
||||
to_chat(user,"<span class='notice'>You confirm your readiness.</span>")
|
||||
return
|
||||
else if(!is_duelist(target)) //I kinda want to leave this out just to see someone shoot a bystander or missing.
|
||||
to_chat(user,"<span class='warning'>[src] safety system prevents shooting anyone but your designated opponent.</span>")
|
||||
return
|
||||
else
|
||||
duel.fired[src] = TRUE
|
||||
. = ..()
|
||||
|
||||
/obj/item/gun/energy/dueling/before_firing(target,user)
|
||||
var/obj/item/ammo_casing/energy/duel/D = chambered
|
||||
D.setting = setting
|
||||
D.hugbox = hugbox
|
||||
|
||||
/obj/effect/temp_visual/dueling_chaff
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "shield-old"
|
||||
duration = 30
|
||||
var/setting
|
||||
|
||||
/obj/effect/temp_visual/dueling_chaff/update_icon()
|
||||
. = ..()
|
||||
switch(setting)
|
||||
if(DUEL_SETTING_A)
|
||||
color = "red"
|
||||
if(DUEL_SETTING_B)
|
||||
color = "green"
|
||||
if(DUEL_SETTING_C)
|
||||
color = "blue"
|
||||
|
||||
//Casing
|
||||
|
||||
/obj/item/ammo_casing/energy/duel
|
||||
e_cost = 0
|
||||
projectile_type = /obj/item/projectile/energy/duel
|
||||
var/setting
|
||||
var/hugbox = DUEL_HUGBOX_NONE
|
||||
|
||||
/obj/item/ammo_casing/energy/duel/ready_proj(atom/target, mob/living/user, quiet, zone_override)
|
||||
. = ..()
|
||||
var/obj/item/projectile/energy/duel/D = BB
|
||||
D.setting = setting
|
||||
D.hugbox = hugbox
|
||||
D.update_icon()
|
||||
|
||||
/obj/item/ammo_casing/energy/duel/fire_casing(atom/target, mob/living/user, params, distro, quiet, zone_override, spread, atom/fired_from)
|
||||
. = ..()
|
||||
var/obj/effect/temp_visual/dueling_chaff/C = new(get_turf(user))
|
||||
C.setting = setting
|
||||
C.update_icon()
|
||||
|
||||
//Projectile
|
||||
|
||||
/obj/item/projectile/energy/duel
|
||||
name = "dueling beam"
|
||||
icon_state = "declone"
|
||||
is_reflectable = FALSE
|
||||
homing = TRUE
|
||||
var/setting
|
||||
var/hugbox = DUEL_HUGBOX_NONE
|
||||
|
||||
/obj/item/projectile/energy/duel/update_icon()
|
||||
. = ..()
|
||||
switch(setting)
|
||||
if(DUEL_SETTING_A)
|
||||
color = "red"
|
||||
if(DUEL_SETTING_B)
|
||||
color = "green"
|
||||
if(DUEL_SETTING_C)
|
||||
color = "blue"
|
||||
|
||||
/obj/item/projectile/energy/duel/on_hit(atom/target, blocked)
|
||||
. = ..()
|
||||
var/turf/T = get_turf(target)
|
||||
var/obj/effect/temp_visual/dueling_chaff/C = locate() in T
|
||||
if(C)
|
||||
var/counter_setting
|
||||
switch(setting)
|
||||
if(DUEL_SETTING_A)
|
||||
counter_setting = DUEL_SETTING_B
|
||||
if(DUEL_SETTING_B)
|
||||
counter_setting = DUEL_SETTING_C
|
||||
if(DUEL_SETTING_C)
|
||||
counter_setting = DUEL_SETTING_A
|
||||
if(C.setting == counter_setting)
|
||||
return BULLET_ACT_BLOCK
|
||||
|
||||
var/mob/living/L = target
|
||||
if(!istype(target))
|
||||
return BULLET_ACT_BLOCK
|
||||
|
||||
switch(hugbox)
|
||||
if(DUEL_HUGBOX_NONE)
|
||||
var/obj/item/bodypart/B = L.get_bodypart(BODY_ZONE_HEAD)
|
||||
B.dismember()
|
||||
QDEL_IN(B, 1)
|
||||
if(DUEL_HUGBOX_LETHAL)
|
||||
L.adjustBruteLoss(180)
|
||||
L.death() //Die, powergamers.
|
||||
if(DUEL_HUGBOX_NONLETHAL)
|
||||
L.adjustStaminaLoss(200, forced = TRUE) //Die, powergamers x 2
|
||||
L.Knockdown(100, override_hardstun = 100) //For good measure.
|
||||
|
||||
//Storage case.
|
||||
/obj/item/storage/lockbox/dueling
|
||||
name = "dueling pistol case"
|
||||
desc = "Let's solve this like gentlespacemen."
|
||||
icon_state = "medalbox+l"
|
||||
item_state = "syringe_kit"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
req_access = list(ACCESS_CAPTAIN)
|
||||
icon_locked = "medalbox+l"
|
||||
icon_closed = "medalbox"
|
||||
icon_broken = "medalbox+b"
|
||||
var/gun_type = /obj/item/gun/energy/dueling
|
||||
|
||||
/obj/item/storage/lockbox/dueling/ComponentInitialize()
|
||||
. = ..()
|
||||
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
|
||||
STR.max_w_class = WEIGHT_CLASS_SMALL
|
||||
STR.max_items = 2
|
||||
STR.can_hold = typecacheof(/obj/item/gun/energy/dueling)
|
||||
|
||||
/obj/item/storage/lockbox/dueling/update_icon()
|
||||
cut_overlays()
|
||||
var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
|
||||
if(locked)
|
||||
icon_state = "medalbox+l"
|
||||
else
|
||||
icon_state = "medalbox"
|
||||
if(open)
|
||||
icon_state += "open"
|
||||
if(broken)
|
||||
icon_state += "+b"
|
||||
|
||||
/obj/item/storage/lockbox/dueling/PopulateContents()
|
||||
. = ..()
|
||||
var/obj/item/gun/energy/dueling/gun_A = new gun_type(src)
|
||||
var/obj/item/gun/energy/dueling/gun_B = new gun_type(src)
|
||||
var/datum/duel/D = new
|
||||
gun_A.duel = D
|
||||
gun_B.duel = D
|
||||
D.gun_A = gun_A
|
||||
D.gun_B = gun_B
|
||||
|
||||
/obj/item/storage/lockbox/dueling/hugbox
|
||||
gun_type = /obj/item/gun/energy/dueling/hugbox
|
||||
req_access = list(ACCESS_ARMORY)
|
||||
|
||||
/obj/item/storage/lockbox/dueling/hugbox/stamina
|
||||
gun_type = /obj/item/gun/energy/dueling/hugbox/stamina
|
||||
req_access = null
|
||||
@@ -97,7 +97,7 @@
|
||||
pin = null
|
||||
can_charge = 0
|
||||
ammo_x_offset = 1
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/electrode, /obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/laser)
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/laser)
|
||||
selfcharge = EGUN_SELFCHARGE
|
||||
var/fail_tick = 0
|
||||
var/fail_chance = 0
|
||||
@@ -113,18 +113,21 @@
|
||||
..()
|
||||
|
||||
/obj/item/gun/energy/e_gun/nuclear/proc/failcheck()
|
||||
if(prob(fail_chance) && isliving(loc))
|
||||
var/mob/living/M = loc
|
||||
if(prob(fail_chance))
|
||||
switch(fail_tick)
|
||||
if(0 to 200)
|
||||
fail_tick += (2*(fail_chance))
|
||||
M.rad_act(400)
|
||||
to_chat(M, "<span class='userdanger'>Your [name] feels warmer.</span>")
|
||||
radiation_pulse(src, 50)
|
||||
var/mob/M = (ismob(loc) && loc) || (ismob(loc.loc) && loc.loc) //thank you short circuiting. if you powergame and nest these guns deeply you get to suffer no-warning radiation death.
|
||||
if(M)
|
||||
to_chat(M, "<span class='userdanger'>Your [name] feels warmer.</span>")
|
||||
if(201 to INFINITY)
|
||||
SSobj.processing.Remove(src)
|
||||
M.rad_act(800)
|
||||
crit_fail = 1
|
||||
to_chat(M, "<span class='userdanger'>Your [name]'s reactor overloads!</span>")
|
||||
radiation_pulse(src, 200)
|
||||
crit_fail = TRUE
|
||||
var/mob/M = (ismob(loc) && loc) || (ismob(loc.loc) && loc.loc)
|
||||
if(M)
|
||||
to_chat(M, "<span class='userdanger'>Your [name]'s reactor overloads!</span>")
|
||||
|
||||
/obj/item/gun/energy/e_gun/nuclear/emp_act(severity)
|
||||
. = ..()
|
||||
|
||||
@@ -297,7 +297,7 @@
|
||||
/obj/item/borg/upgrade/modkit/proc/install(obj/item/gun/energy/kinetic_accelerator/KA, mob/user)
|
||||
. = TRUE
|
||||
if(src in KA.modkits) // Sanity check to prevent installing the same modkit twice thanks to occasional click/lag delays.
|
||||
return
|
||||
return FALSE
|
||||
if(minebot_upgrade)
|
||||
if(minebot_exclusive && !istype(KA.loc, /mob/living/simple_animal/hostile/mining_drone))
|
||||
to_chat(user, "<span class='notice'>The modkit you're trying to install is only rated for minebot use.</span>")
|
||||
@@ -317,7 +317,7 @@
|
||||
if(KA.get_remaining_mod_capacity() >= cost)
|
||||
if(.)
|
||||
if(!user.transferItemToLoc(src, KA))
|
||||
return
|
||||
return FALSE
|
||||
to_chat(user, "<span class='notice'>You install the modkit.</span>")
|
||||
playsound(loc, 'sound/items/screwdriver.ogg', 100, 1)
|
||||
KA.modkits += src
|
||||
@@ -382,7 +382,7 @@
|
||||
var/old = KA.overheat_time
|
||||
KA.overheat_time = max(0, KA.overheat_time - modifier)
|
||||
decreased = old - KA.overheat_time
|
||||
|
||||
|
||||
|
||||
/obj/item/borg/upgrade/modkit/cooldown/uninstall(obj/item/gun/energy/kinetic_accelerator/KA)
|
||||
KA.overheat_time += decreased
|
||||
|
||||
@@ -16,6 +16,19 @@
|
||||
clumsy_check = 0
|
||||
item_flags = NONE
|
||||
|
||||
/obj/item/gun/energy/laser/practice/hyperburst
|
||||
name = "toy hyper-burst launcher"
|
||||
desc = "A toy laser with a unique beam shaping lens that projects harmless bolts capable of going through objects. Compatible with existing laser tag systems."
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/laser/magtag)
|
||||
icon_state = "toyburst"
|
||||
obj_flags = NONE
|
||||
fire_delay = 40
|
||||
weapon_weight = WEAPON_HEAVY
|
||||
selfcharge = EGUN_SELFCHARGE
|
||||
charge_delay = 2
|
||||
recoil = 2
|
||||
cell_type = /obj/item/stock_parts/cell/toymagburst
|
||||
|
||||
/obj/item/gun/energy/laser/retro
|
||||
name ="retro laser gun"
|
||||
icon_state = "retro"
|
||||
@@ -189,7 +202,7 @@
|
||||
if(!ishuman(user) || !ishuman(target))
|
||||
return
|
||||
|
||||
if(semicd)
|
||||
if(on_cooldown())
|
||||
return
|
||||
|
||||
if(user == target)
|
||||
@@ -199,7 +212,7 @@
|
||||
target.visible_message("<span class='warning'>[user] points [src] at [target]'s head, ready to pull the trigger...</span>", \
|
||||
"<span class='userdanger'>[user] points [src] at your head, ready to pull the trigger...</span>")
|
||||
|
||||
semicd = TRUE
|
||||
busy_action = TRUE
|
||||
|
||||
if(!bypass_timer && (!do_mob(user, target, 120) || user.zone_selected != BODY_ZONE_PRECISE_MOUTH))
|
||||
if(user)
|
||||
@@ -207,10 +220,10 @@
|
||||
user.visible_message("<span class='notice'>[user] decided not to shoot.</span>")
|
||||
else if(target && target.Adjacent(user))
|
||||
target.visible_message("<span class='notice'>[user] has decided to spare [target]</span>", "<span class='notice'>[user] has decided to spare your life!</span>")
|
||||
semicd = FALSE
|
||||
busy_action = FALSE
|
||||
return
|
||||
|
||||
semicd = FALSE
|
||||
busy_action = FALSE
|
||||
|
||||
target.visible_message("<span class='warning'>[user] pulls the trigger!</span>", "<span class='userdanger'>[user] pulls the trigger!</span>")
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
/obj/item/gun/energy/decloner/update_icon()
|
||||
..()
|
||||
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
|
||||
var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index]
|
||||
if(!QDELETED(cell) && (cell.charge > shot.e_cost))
|
||||
add_overlay("decloner_spin")
|
||||
|
||||
@@ -105,13 +105,15 @@
|
||||
|
||||
/obj/item/gun/energy/kinetic_accelerator/crossbow/large
|
||||
name = "energy crossbow"
|
||||
desc = "A reverse engineered weapon using syndicate technology."
|
||||
desc = "A reverse engineered weapon using syndicate technology. This thing seems incredibly unwieldly, and seems to be using similar internals to the Proto-Kinetic Accelerator. It might not play nice when brought near weapons similar to it."
|
||||
icon_state = "crossbowlarge"
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
materials = list(MAT_METAL=4000)
|
||||
suppressed = null
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/bolt/large)
|
||||
weapon_weight = WEAPON_HEAVY
|
||||
pin = null
|
||||
unique_frequency = FALSE
|
||||
|
||||
/obj/item/gun/energy/plasmacutter
|
||||
name = "plasma cutter"
|
||||
@@ -183,7 +185,7 @@
|
||||
var/atmos_link = FALSE
|
||||
|
||||
/obj/item/gun/energy/wormhole_projector/update_icon()
|
||||
icon_state = "[initial(icon_state)][select]"
|
||||
icon_state = "[initial(icon_state)][current_firemode_index]"
|
||||
item_state = icon_state
|
||||
|
||||
/obj/item/gun/energy/wormhole_projector/update_ammo_types()
|
||||
@@ -318,7 +320,7 @@
|
||||
|
||||
/obj/item/gun/energy/emitter/update_icon()
|
||||
..()
|
||||
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
|
||||
var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index]
|
||||
if(!QDELETED(cell) && (cell.charge > shot.e_cost))
|
||||
add_overlay("emitter_carbine_empty")
|
||||
else
|
||||
|
||||
@@ -18,10 +18,23 @@
|
||||
|
||||
/obj/item/gun/energy/e_gun/advtaser
|
||||
name = "hybrid taser"
|
||||
desc = "A dual-mode taser designed to fire both short-range high-power electrodes and long-range disabler beams."
|
||||
desc = "A dual-mode taser designed to fire both short-range high-power electrodes and long-range disabler beams. <span class='boldnotice'>Right click in combat mode to fire a taser shot with a cooldown.</span>"
|
||||
icon_state = "advtaser"
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/electrode)
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/electrode/security = FALSE)
|
||||
ammo_x_offset = 2
|
||||
// Not enough guns have altfire systems like this yet for this to be a universal framework.
|
||||
var/last_altfire = 0
|
||||
var/altfire_delay = 15
|
||||
|
||||
/obj/item/gun/energy/e_gun/advtaser/altafterattack(atom/target, mob/user, proximity_flag, params)
|
||||
. = TRUE
|
||||
if(last_altfire + altfire_delay > world.time)
|
||||
return
|
||||
var/current_index = current_firemode_index
|
||||
set_firemode_to_type(/obj/item/ammo_casing/energy/electrode)
|
||||
process_afterattack(target, user, proximity_flag, params)
|
||||
set_firemode_index(current_index)
|
||||
last_altfire = world.time
|
||||
|
||||
/obj/item/gun/energy/e_gun/advtaser/cyborg
|
||||
name = "cyborg taser"
|
||||
|
||||
@@ -73,6 +73,12 @@
|
||||
user.adjustOxyLoss(500)
|
||||
charges--
|
||||
|
||||
/obj/item/gun/magic/wand/death/debug
|
||||
desc = "In some obscure circles, this is known as the 'cloning tester's friend'."
|
||||
max_charges = 500
|
||||
variable_charges = FALSE
|
||||
can_charge = TRUE
|
||||
recharge_rate = 1
|
||||
|
||||
/////////////////////////////////////
|
||||
//WAND OF HEALING
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
|
||||
var/lastangle = 0
|
||||
var/aiming_lastangle = 0
|
||||
var/last_aimbeam = 0
|
||||
var/mob/current_user = null
|
||||
var/list/obj/effect/projectile/tracer/current_tracers
|
||||
|
||||
@@ -186,8 +187,9 @@
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/proc/aiming_beam(force_update = FALSE)
|
||||
var/diff = abs(aiming_lastangle - lastangle)
|
||||
check_user()
|
||||
if(diff < AIMING_BEAM_ANGLE_CHANGE_THRESHOLD && !force_update)
|
||||
if(!check_user())
|
||||
return
|
||||
if(((diff < AIMING_BEAM_ANGLE_CHANGE_THRESHOLD) || ((last_aimbeam + 1) > world.time)) && !force_update)
|
||||
return
|
||||
aiming_lastangle = lastangle
|
||||
var/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/P = new
|
||||
@@ -208,6 +210,7 @@
|
||||
targloc = get_turf_in_angle(lastangle, curloc, 10)
|
||||
P.preparePixelProjectile(targloc, current_user, current_user.client.mouseParams, 0)
|
||||
P.fire(lastangle)
|
||||
last_aimbeam = world.time
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/process()
|
||||
if(!aiming)
|
||||
@@ -296,27 +299,17 @@
|
||||
if(istype(object, /obj/screen) && !istype(object, /obj/screen/click_catcher))
|
||||
return
|
||||
process_aim()
|
||||
if(aiming_time_left <= aiming_time_fire_threshold && check_user())
|
||||
if(aiming_time_left <= aiming_time_fire_threshold && check_user() && ((lastfire + delay) <= world.time))
|
||||
sync_ammo()
|
||||
afterattack(M.client.mouseObject, M, FALSE, M.client.mouseParams, passthrough = TRUE)
|
||||
do_fire(M.client.mouseObject, M, FALSE, M.client.mouseParams, M.zone_selected)
|
||||
stop_aiming()
|
||||
QDEL_LIST(current_tracers)
|
||||
return ..()
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/afterattack(atom/target, mob/living/user, flag, params, passthrough = FALSE)
|
||||
if(flag) //It's adjacent, is the user, or is on the user's person
|
||||
if(target in user.contents) //can't shoot stuff inside us.
|
||||
return
|
||||
if(!ismob(target) || user.a_intent == INTENT_HARM) //melee attack
|
||||
return
|
||||
if(target == user && user.zone_selected != BODY_ZONE_PRECISE_MOUTH) //so we can't shoot ourselves (unless mouth selected)
|
||||
return
|
||||
if(!passthrough && (aiming_time > aiming_time_fire_threshold))
|
||||
return
|
||||
if(lastfire > world.time + delay)
|
||||
return
|
||||
lastfire = world.time
|
||||
/obj/item/gun/energy/beam_rifle/do_fire(atom/target, mob/living/user, message = TRUE, params, zone_override = "", bonus_spread = 0)
|
||||
. = ..()
|
||||
if(.)
|
||||
lastfire = world.time
|
||||
stop_aiming()
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/proc/sync_ammo()
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
if(proximity_flag)
|
||||
if(istype(target, /obj/item/gun))
|
||||
var/obj/item/gun/G = target
|
||||
if(G.no_pin_required)
|
||||
return
|
||||
if(G.pin && (force_replace || G.pin.pin_removeable))
|
||||
G.pin.forceMove(get_turf(G))
|
||||
G.pin.gun_remove(user)
|
||||
@@ -69,13 +71,10 @@
|
||||
if(gun)
|
||||
qdel(gun)
|
||||
|
||||
|
||||
|
||||
/obj/item/firing_pin/magic
|
||||
name = "magic crystal shard"
|
||||
desc = "A small enchanted shard which allows magical weapons to fire."
|
||||
|
||||
|
||||
// Test pin, works only near firing range.
|
||||
/obj/item/firing_pin/test_range
|
||||
name = "test-range firing pin"
|
||||
@@ -229,3 +228,16 @@
|
||||
if(gun)
|
||||
gun.pin = null
|
||||
return ..()
|
||||
|
||||
//Station Locked
|
||||
|
||||
/obj/item/firing_pin/away
|
||||
name = "station locked pin"
|
||||
desc = "A firing pin that only will fire when off the station."
|
||||
|
||||
/obj/item/firing_pin/away/pin_auth(mob/living/user)
|
||||
var/area/station_area = get_area(src)
|
||||
if(!station_area || is_station_level(station_area.z))
|
||||
to_chat(user, "<span class='warning'>The pin beeps, refusing to fire.</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -90,6 +90,10 @@
|
||||
var/decayedRange //stores original range
|
||||
var/reflect_range_decrease = 5 //amount of original range that falls off when reflecting, so it doesn't go forever
|
||||
var/is_reflectable = FALSE // Can it be reflected or not?
|
||||
|
||||
/// factor to multiply by for zone accuracy percent.
|
||||
var/zone_accuracy_factor = 1
|
||||
|
||||
//Effects
|
||||
var/stun = 0
|
||||
var/knockdown = 0
|
||||
@@ -185,10 +189,6 @@
|
||||
else
|
||||
new /obj/effect/temp_visual/dir_setting/bloodsplatter(target_loca, splatter_dir, bloodtype_to_color())
|
||||
|
||||
if(iscarbon(L) && !HAS_TRAIT(L, TRAIT_NOMARROW))
|
||||
var/mob/living/carbon/C = L
|
||||
C.bleed(damage)
|
||||
else
|
||||
L.add_splatter_floor(target_loca)
|
||||
else if(impact_effect_type && !hitscan)
|
||||
new impact_effect_type(target_loca, hitx, hity)
|
||||
@@ -250,7 +250,8 @@
|
||||
return TRUE
|
||||
|
||||
var/distance = get_dist(T, starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations.
|
||||
def_zone = ran_zone(def_zone, max(100-(7*distance), 5)) //Lower accurancy/longer range tradeoff. 7 is a balanced number to use.
|
||||
if(check_zone(def_zone) != BODY_ZONE_CHEST)
|
||||
def_zone = ran_zone(def_zone, max(100-(7*distance), 5) * zone_accuracy_factor) //Lower accurancy/longer range tradeoff. 7 is a balanced number to use.
|
||||
|
||||
if(isturf(A) && hitsound_wall)
|
||||
var/volume = CLAMP(vol_by_damage() + 20, 0, 100)
|
||||
@@ -640,11 +641,11 @@
|
||||
Bump(original)
|
||||
|
||||
/obj/item/projectile/Destroy()
|
||||
STOP_PROCESSING(SSprojectiles, src)
|
||||
if(hitscan)
|
||||
finalize_hitscan_and_generate_tracers()
|
||||
STOP_PROCESSING(SSprojectiles, src)
|
||||
cleanup_beam_segments()
|
||||
qdel(trajectory)
|
||||
QDEL_NULL(trajectory)
|
||||
return ..()
|
||||
|
||||
/obj/item/projectile/proc/cleanup_beam_segments()
|
||||
|
||||
@@ -146,6 +146,15 @@
|
||||
if(M.wear_suit.type in suit_types)
|
||||
M.adjustStaminaLoss(34)
|
||||
|
||||
/obj/item/projectile/beam/lasertag/mag //the projectile, compatible with regular laser tag armor
|
||||
icon_state = "magjectile-toy"
|
||||
name = "lasertag magbolt"
|
||||
movement_type = FLYING | UNSTOPPABLE //for penetration memes
|
||||
range = 5 //so it isn't super annoying
|
||||
light_range = 2
|
||||
light_color = LIGHT_COLOR_YELLOW
|
||||
eyeblur = 0
|
||||
|
||||
/obj/item/projectile/beam/lasertag/redtag
|
||||
icon_state = "laser"
|
||||
suit_types = list(/obj/item/clothing/suit/bluetag)
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/obj/item/projectile/bullet/magnetic
|
||||
icon_state = "magjectile"
|
||||
damage = 20
|
||||
armour_penetration = 20
|
||||
light_range = 3
|
||||
speed = 0.6
|
||||
range = 35
|
||||
light_color = LIGHT_COLOR_RED
|
||||
|
||||
/obj/item/projectile/bullet/magnetic/disabler
|
||||
icon_state = "magjectile-nl" //nl stands for non-lethal
|
||||
damage = 2
|
||||
armour_penetration = 10
|
||||
stamina = 20
|
||||
light_color = LIGHT_COLOR_BLUE
|
||||
|
||||
/obj/item/projectile/bullet/magnetic/weak
|
||||
damage = 15
|
||||
armour_penetration = 10
|
||||
light_range = 2
|
||||
range = 25
|
||||
|
||||
/obj/item/projectile/bullet/magnetic/weak/disabler
|
||||
damage = 2
|
||||
stamina = 20
|
||||
|
||||
/obj/item/projectile/bullet/magnetic/hyper
|
||||
damage = 10
|
||||
armour_penetration = 20
|
||||
stamina = 10
|
||||
movement_type = FLYING | UNSTOPPABLE
|
||||
range = 6
|
||||
light_range = 1
|
||||
light_color = LIGHT_COLOR_RED
|
||||
|
||||
/obj/item/projectile/bullet/incendiary/mag_inferno
|
||||
icon_state = "magjectile-large"
|
||||
damage = 10
|
||||
armour_penetration = 20
|
||||
movement_type = FLYING | UNSTOPPABLE
|
||||
range = 20
|
||||
speed = 0.8
|
||||
light_range = 4
|
||||
light_color = LIGHT_COLOR_RED
|
||||
|
||||
/obj/item/projectile/bullet/incendiary/mag_inferno/on_hit(atom/target, blocked = FALSE)
|
||||
..()
|
||||
explosion(target, -1, 0, 0, 1, 2, flame_range = 2)
|
||||
return BULLET_ACT_HIT
|
||||
@@ -61,7 +61,7 @@
|
||||
|
||||
/obj/item/projectile/bullet/pellet/shotgun_buckshot
|
||||
name = "buckshot pellet"
|
||||
damage = 10
|
||||
damage = 12.5
|
||||
|
||||
/obj/item/projectile/bullet/pellet/shotgun_rubbershot
|
||||
name = "rubbershot pellet"
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
knockdown = 100
|
||||
dismemberment = 50
|
||||
armour_penetration = 50
|
||||
zone_accuracy_factor = 100 //guarunteed 100%
|
||||
var/breakthings = TRUE
|
||||
|
||||
/obj/item/projectile/bullet/p50/on_hit(atom/target, blocked = 0)
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
/obj/item/projectile/energy/bolt //ebow bolts
|
||||
name = "bolt"
|
||||
icon_state = "cbbolt"
|
||||
damage = 8
|
||||
damage = 15
|
||||
damage_type = TOX
|
||||
nodamage = 0
|
||||
knockdown = 100
|
||||
stutter = 5
|
||||
drowsy = 50
|
||||
eyeblur = 10
|
||||
slur = 5
|
||||
knockdown = 160
|
||||
stamina = 60
|
||||
knockdown_stamoverride = 0
|
||||
|
||||
/obj/item/projectile/energy/bolt/halloween
|
||||
name = "candy corn"
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
name = "electrode"
|
||||
icon_state = "spark"
|
||||
color = "#FFFF00"
|
||||
nodamage = 1
|
||||
nodamage = TRUE
|
||||
knockdown = 60
|
||||
knockdown_stamoverride = 36
|
||||
knockdown_stam_max = 50
|
||||
stutter = 5
|
||||
stutter = 10
|
||||
jitter = 20
|
||||
hitsound = 'sound/weapons/taserhit.ogg'
|
||||
range = 7
|
||||
@@ -14,6 +14,7 @@
|
||||
muzzle_type = /obj/effect/projectile/muzzle/stun
|
||||
impact_type = /obj/effect/projectile/impact/stun
|
||||
var/tase_duration = 50
|
||||
var/strong_tase = TRUE
|
||||
|
||||
/obj/item/projectile/energy/electrode/on_hit(atom/target, blocked = FALSE)
|
||||
. = ..()
|
||||
@@ -26,10 +27,24 @@
|
||||
C.IgniteMob()
|
||||
if(C.dna && C.dna.check_mutation(HULK))
|
||||
C.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ), forced = "hulk")
|
||||
else if((C.status_flags & CANKNOCKDOWN) && !HAS_TRAIT(C, TRAIT_STUNIMMUNE))
|
||||
C.apply_status_effect(STATUS_EFFECT_TASED, tase_duration)
|
||||
else if(tase_duration && (C.status_flags & CANKNOCKDOWN) && !HAS_TRAIT(C, TRAIT_STUNIMMUNE))
|
||||
C.apply_status_effect(strong_tase? STATUS_EFFECT_TASED : STATUS_EFFECT_TASED_WEAK, tase_duration)
|
||||
addtimer(CALLBACK(C, /mob/living/carbon.proc/do_jitter_animation, jitter), 5)
|
||||
|
||||
/obj/item/projectile/energy/electrode/on_range() //to ensure the bolt sparks when it reaches the end of its range if it didn't hit a target yet
|
||||
do_sparks(1, TRUE, src)
|
||||
..()
|
||||
|
||||
/obj/item/projectile/energy/electrode/security
|
||||
tase_duration = 30
|
||||
knockdown = 0
|
||||
stamina = 10
|
||||
knockdown_stamoverride = 0
|
||||
knockdown_stam_max = 0
|
||||
strong_tase = FALSE
|
||||
range = 12
|
||||
|
||||
/obj/item/projectile/energy/electrode/security/hos
|
||||
knockdown = 100
|
||||
knockdown_stamoverride = 30
|
||||
knockdown_stam_max = null
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/obj/item/projectile/bullet/reusable/arrow
|
||||
name = "wooden arrow"
|
||||
desc = "Woosh!"
|
||||
damage = 15
|
||||
icon_state = "arrow"
|
||||
ammo_type = /obj/item/ammo_casing/caseless/arrow
|
||||
@@ -39,3 +39,10 @@
|
||||
icon_state = "foamdart_riot_proj"
|
||||
ammo_type = /obj/item/ammo_casing/caseless/foam_dart/riot
|
||||
stamina = 25
|
||||
|
||||
/obj/item/projectile/bullet/reusable/foam_dart/mag
|
||||
name = "magfoam dart"
|
||||
icon_state = "magjectile-toy"
|
||||
ammo_type = /obj/item/ammo_casing/caseless/foam_dart/mag
|
||||
light_range = 2
|
||||
light_color = LIGHT_COLOR_YELLOW
|
||||
|
||||
@@ -1,90 +1,65 @@
|
||||
/obj/item/projectile/gravityrepulse
|
||||
/obj/item/projectile/gravity
|
||||
name = "gravity bolt"
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "chronofield"
|
||||
hitsound = 'sound/weapons/wave.ogg'
|
||||
damage = 0
|
||||
damage_type = BRUTE
|
||||
nodamage = TRUE
|
||||
var/power = 4
|
||||
var/list/thrown = list() //normally we wouldn't need this but incase on_hit is called multiple times, yeah.. this is a good idea.
|
||||
|
||||
/obj/item/projectile/gravity/Initialize(mapload)
|
||||
. = ..()
|
||||
var/obj/item/ammo_casing/energy/gravity/G = loc
|
||||
if(istype(G))
|
||||
power = min(G.gun.power, 15)
|
||||
|
||||
/obj/item/projectile/gravity/on_hit()
|
||||
. = ..()
|
||||
var/turf/T = get_turf(src)
|
||||
var/list/tothrow = list()
|
||||
var/list/cachedrange = range(T, power)
|
||||
for(var/mob/M in cachedrange)
|
||||
tothrow += M
|
||||
for(var/obj/O in cachedrange)
|
||||
tothrow += O
|
||||
var/safety = 50
|
||||
for(var/i in tothrow)
|
||||
if(!safety)
|
||||
break
|
||||
var/atom/movable/AM = i
|
||||
if((AM == src) || (AM == firer) || (AM.move_resist > MOVE_FORCE_EXTREMELY_STRONG) || AM.anchored || thrown[AM])
|
||||
continue
|
||||
thrown[AM] = TRUE
|
||||
safety--
|
||||
var/target = get_target(T, AM)
|
||||
if(!target)
|
||||
return FALSE
|
||||
AM.throw_at(target, power + 1, 1)
|
||||
for(var/turf/F in range(T,power))
|
||||
new /obj/effect/temp_visual/gravpush(F)
|
||||
|
||||
/obj/item/projectile/gravity/proc/get_target(turf/origin, atom/movable/AM)
|
||||
return origin
|
||||
|
||||
/obj/item/projectile/gravity/repulse
|
||||
name = "repulsion bolt"
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "chronofield"
|
||||
hitsound = 'sound/weapons/wave.ogg'
|
||||
damage = 0
|
||||
damage_type = BRUTE
|
||||
nodamage = 1
|
||||
color = "#33CCFF"
|
||||
var/turf/T
|
||||
var/power = 4
|
||||
var/list/thrown_items = list()
|
||||
|
||||
/obj/item/projectile/gravityrepulse/Initialize()
|
||||
. = ..()
|
||||
var/obj/item/ammo_casing/energy/gravity/repulse/C = loc
|
||||
if(istype(C)) //Hard-coded maximum power so servers can't be crashed by trying to throw the entire Z level's items
|
||||
power = min(C.gun.power, 15)
|
||||
/obj/item/projectile/gravity/repulse/get_target(turf/origin, atom/movable/AM)
|
||||
return get_turf_in_angle(Get_Angle(origin, AM), origin, power)
|
||||
|
||||
/obj/item/projectile/gravityrepulse/on_hit()
|
||||
. = ..()
|
||||
T = get_turf(src)
|
||||
for(var/atom/movable/A in range(T, power))
|
||||
if(A == src || (firer && A == src.firer) || A.anchored || thrown_items[A])
|
||||
continue
|
||||
var/throwtarget = get_edge_target_turf(src, get_dir(src, get_step_away(A, src)))
|
||||
A.throw_at(throwtarget,power+1,1)
|
||||
thrown_items[A] = A
|
||||
for(var/turf/F in range(T,power))
|
||||
new /obj/effect/temp_visual/gravpush(F)
|
||||
|
||||
/obj/item/projectile/gravityattract
|
||||
/obj/item/projectile/gravity/attract
|
||||
name = "attraction bolt"
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "chronofield"
|
||||
hitsound = 'sound/weapons/wave.ogg'
|
||||
damage = 0
|
||||
damage_type = BRUTE
|
||||
nodamage = 1
|
||||
color = "#FF6600"
|
||||
var/turf/T
|
||||
var/power = 4
|
||||
var/list/thrown_items = list()
|
||||
|
||||
/obj/item/projectile/gravityattract/Initialize()
|
||||
. = ..()
|
||||
var/obj/item/ammo_casing/energy/gravity/attract/C = loc
|
||||
if(istype(C)) //Hard-coded maximum power so servers can't be crashed by trying to throw the entire Z level's items
|
||||
power = min(C.gun.power, 15)
|
||||
/obj/item/projectile/gravity/attract/get_target(turf/origin, atom/movable/AM)
|
||||
return origin
|
||||
|
||||
/obj/item/projectile/gravityattract/on_hit()
|
||||
. = ..()
|
||||
T = get_turf(src)
|
||||
for(var/atom/movable/A in range(T, power))
|
||||
if(A == src || (firer && A == src.firer) || A.anchored || thrown_items[A])
|
||||
continue
|
||||
A.throw_at(T, power+1, 1)
|
||||
thrown_items[A] = A
|
||||
for(var/turf/F in range(T,power))
|
||||
new /obj/effect/temp_visual/gravpush(F)
|
||||
|
||||
/obj/item/projectile/gravitychaos
|
||||
/obj/item/projectile/gravity/chaos
|
||||
name = "gravitational blast"
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "chronofield"
|
||||
hitsound = 'sound/weapons/wave.ogg'
|
||||
damage = 0
|
||||
damage_type = BRUTE
|
||||
nodamage = 1
|
||||
color = "#101010"
|
||||
var/turf/T
|
||||
var/power = 4
|
||||
var/list/thrown_items = list()
|
||||
|
||||
/obj/item/projectile/gravitychaos/Initialize()
|
||||
. = ..()
|
||||
var/obj/item/ammo_casing/energy/gravity/chaos/C = loc
|
||||
if(istype(C)) //Hard-coded maximum power so servers can't be crashed by trying to throw the entire Z level's items
|
||||
power = min(C.gun.power, 15)
|
||||
|
||||
/obj/item/projectile/gravitychaos/on_hit()
|
||||
. = ..()
|
||||
T = get_turf(src)
|
||||
for(var/atom/movable/A in range(T, power))
|
||||
if(A == src|| (firer && A == src.firer) || A.anchored || thrown_items[A])
|
||||
continue
|
||||
A.throw_at(get_edge_target_turf(A, pick(GLOB.cardinals)), power+1, 1)
|
||||
thrown_items[A] = A
|
||||
for(var/turf/Z in range(T,power))
|
||||
new /obj/effect/temp_visual/gravpush(Z)
|
||||
/obj/item/projectile/gravity/chaos/get_target(turf/origin, atom/movable/AM)
|
||||
return get_turf_in_angle(rand(0, 359), origin, power)
|
||||
|
||||
Reference in New Issue
Block a user