Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into Ghommie-cit800
This commit is contained in:
@@ -1,17 +1,21 @@
|
||||
/obj/item/ammo_casing/proc/fire_casing(atom/target, mob/living/user, params, distro, quiet, zone_override, spread, atom/fired_from)
|
||||
distro += variance
|
||||
for (var/i = max(1, pellets), i > 0, i--)
|
||||
var/targloc = get_turf(target)
|
||||
ready_proj(target, user, quiet, zone_override, fired_from)
|
||||
var/targloc = get_turf(target)
|
||||
ready_proj(target, user, quiet, zone_override, fired_from)
|
||||
if(pellets == 1)
|
||||
if(distro) //We have to spread a pixel-precision bullet. throw_proj was called before so angles should exist by now...
|
||||
if(randomspread)
|
||||
spread = round((rand() - 0.5) * distro)
|
||||
else //Smart spread
|
||||
spread = round((i / pellets - 0.5) * distro)
|
||||
spread = round(1 - 0.5) * distro
|
||||
if(!throw_proj(target, targloc, user, params, spread))
|
||||
return 0
|
||||
if(i > 1)
|
||||
newshot()
|
||||
return FALSE
|
||||
else
|
||||
if(isnull(BB))
|
||||
return FALSE
|
||||
AddComponent(/datum/component/pellet_cloud, projectile_type, pellets)
|
||||
SEND_SIGNAL(src, COMSIG_PELLET_CLOUD_INIT, target, user, fired_from, randomspread, spread, zone_override, params, distro)
|
||||
|
||||
if(click_cooldown_override)
|
||||
user.changeNext_move(click_cooldown_override)
|
||||
else
|
||||
@@ -31,7 +35,7 @@
|
||||
else
|
||||
BB.def_zone = user.zone_selected
|
||||
BB.suppressed = quiet
|
||||
|
||||
|
||||
if(isgun(fired_from))
|
||||
var/obj/item/gun/G = fired_from
|
||||
BB.damage *= G.projectile_damage_multiplier
|
||||
|
||||
@@ -21,3 +21,16 @@
|
||||
name = "1.95x129mm incendiary bullet casing"
|
||||
desc = "A 1.95x129mm bullet casing designed with a chemical-filled capsule on the tip that when bursted, reacts with the atmosphere to produce a fireball, engulfing the target in flames."
|
||||
projectile_type = /obj/item/projectile/bullet/incendiary/mm195x129
|
||||
|
||||
/obj/item/ammo_casing/mm712x82/match
|
||||
name = "7.12x82mm match bullet casing"
|
||||
desc = "A 7.12x82mm bullet casing manufactured to unfailingly high standards, you could pull off some cool trickshots with this."
|
||||
projectile_type = /obj/item/projectile/bullet/mm712x82_match
|
||||
|
||||
/obj/item/projectile/bullet/mm712x82_match
|
||||
name = "7.12x82mm match bullet"
|
||||
damage = 40
|
||||
ricochets_max = 2
|
||||
ricochet_chance = 60
|
||||
ricochet_auto_aim_range = 4
|
||||
ricochet_incidence_leeway = 35
|
||||
@@ -44,7 +44,6 @@
|
||||
desc = "A 9mm incendiary bullet casing."
|
||||
projectile_type = /obj/item/projectile/bullet/incendiary/c9mm
|
||||
|
||||
|
||||
// .50AE (Desert Eagle)
|
||||
|
||||
/obj/item/ammo_casing/a50AE
|
||||
@@ -53,3 +52,16 @@
|
||||
caliber = ".50"
|
||||
projectile_type = /obj/item/projectile/bullet/a50AE
|
||||
|
||||
// .32 ACP (Improvised Pistol)
|
||||
|
||||
/obj/item/ammo_casing/c32acp
|
||||
name = ".32 bullet casing"
|
||||
desc = "A .32 bullet casing."
|
||||
caliber = "c32acp"
|
||||
projectile_type = /obj/item/projectile/bullet/c32acp
|
||||
|
||||
/obj/item/ammo_casing/r32acp
|
||||
name = ".32 rubber bullet casing"
|
||||
desc = "A .32 rubber bullet casing."
|
||||
caliber = "c32acp"
|
||||
projectile_type = /obj/item/projectile/bullet/r32acp
|
||||
|
||||
@@ -11,6 +11,12 @@
|
||||
desc = "A .357 armor-piercing bullet casing."
|
||||
projectile_type = /obj/item/projectile/bullet/a357/ap
|
||||
|
||||
/obj/item/ammo_casing/a357/match
|
||||
name = ".357 match bullet casing"
|
||||
desc = "A .357 bullet casing, manufactured to exceedingly high standards."
|
||||
caliber = "357"
|
||||
projectile_type = /obj/item/projectile/bullet/a357/match
|
||||
|
||||
// 7.62x38mmR (Nagant Revolver)
|
||||
|
||||
/obj/item/ammo_casing/n762
|
||||
@@ -47,4 +53,19 @@
|
||||
name = ".38 Iceblox bullet casing"
|
||||
desc = "A .38 Iceblox bullet casing."
|
||||
caliber = "38"
|
||||
projectile_type = /obj/item/projectile/bullet/c38/iceblox
|
||||
projectile_type = /obj/item/projectile/bullet/c38/iceblox
|
||||
|
||||
/obj/item/ammo_casing/c38/match
|
||||
name = ".38 Match bullet casing"
|
||||
desc = "A .38 bullet casing, manufactured to exceedingly high standards."
|
||||
projectile_type = /obj/item/projectile/bullet/c38/match
|
||||
|
||||
/obj/item/ammo_casing/c38/match/bouncy
|
||||
name = ".38 Rubber bullet casing"
|
||||
desc = "A .38 rubber bullet casing, manufactured to exceedingly high standards."
|
||||
projectile_type = /obj/item/projectile/bullet/c38/match/bouncy
|
||||
|
||||
/obj/item/ammo_casing/c38/dumdum
|
||||
name = ".38 DumDum bullet casing"
|
||||
desc = "A .38 DumDum bullet casing."
|
||||
projectile_type = /obj/item/projectile/bullet/c38/dumdum
|
||||
@@ -143,3 +143,12 @@
|
||||
reagents.add_reagent(/datum/reagent/toxin/acid/fluacid, 5) //this and the acid equal about 25ish burn, not counting the minute toxin damage dealt by their metabolism, this makes each dart about as lethal as a stechkin shot in upfront damage
|
||||
reagents.add_reagent(/datum/reagent/toxin/acid, 5)
|
||||
reagents.add_reagent(/datum/reagent/consumable/frostoil, 10) //tempgun slowdown goes both ways and adds to the burn
|
||||
|
||||
/obj/item/ammo_casing/shotgun/incapacitate
|
||||
name = "custom incapacitating shot"
|
||||
desc = "A shotgun casing filled with... something. used to incapacitate targets."
|
||||
icon_state = "bountyshell"
|
||||
projectile_type = /obj/item/projectile/bullet/pellet/shotgun_incapacitate
|
||||
pellets = 12//double the pellets, but half the stun power of each, which makes this best for just dumping right in someone's face.
|
||||
variance = 25
|
||||
custom_materials = list(/datum/material/iron=4000)
|
||||
@@ -12,6 +12,15 @@
|
||||
e_cost = 200
|
||||
select_name = "kill"
|
||||
|
||||
/obj/item/ammo_casing/energy/lasergun/improvised
|
||||
projectile_type = /obj/item/projectile/beam/weak/improvised
|
||||
e_cost = 200
|
||||
select_name = "kill"
|
||||
|
||||
/obj/item/ammo_casing/energy/lasergun/improvised/upgraded
|
||||
projectile_type = /obj/item/projectile/beam/weak
|
||||
e_cost = 100
|
||||
|
||||
/obj/item/ammo_casing/energy/laser/hos
|
||||
e_cost = 100
|
||||
|
||||
|
||||
@@ -7,6 +7,11 @@
|
||||
max_ammo = 7
|
||||
multiple_sprites = 1
|
||||
|
||||
/obj/item/ammo_box/a357/match
|
||||
name = "speed loader (.357 Match)"
|
||||
desc = "Designed to quickly reload revolvers. These rounds are manufactured within extremely tight tolerances, making them easy to show off trickshots with."
|
||||
ammo_type = /obj/item/ammo_casing/a357/match
|
||||
|
||||
/obj/item/ammo_box/a357/ap
|
||||
name = "speed loader (.357 AP)"
|
||||
ammo_type = /obj/item/ammo_casing/a357/ap
|
||||
@@ -40,6 +45,28 @@
|
||||
desc = "Designed to quickly reload revolvers. Iceblox bullets contain a cryogenic payload."
|
||||
ammo_type = /obj/item/ammo_casing/c38/iceblox
|
||||
|
||||
/obj/item/ammo_box/c38/dumdum
|
||||
name = "speed loader (.38 DumDum)"
|
||||
desc = "Designed to quickly reload revolvers. DumDum bullets shatter on impact and shred the target's innards, likely getting caught inside."
|
||||
ammo_type = /obj/item/ammo_casing/c38/dumdum
|
||||
|
||||
/obj/item/ammo_box/c38/match
|
||||
name = "speed loader (.38 Match)"
|
||||
desc = "Designed to quickly reload revolvers. These rounds are manufactured within extremely tight tolerances, making them easy to show off trickshots with."
|
||||
ammo_type = /obj/item/ammo_casing/c38/match
|
||||
|
||||
/obj/item/ammo_box/c32mm
|
||||
name = "ammo box (.32 acp)"
|
||||
desc = "Lethal .32 acp bullets, there's forty in the box."
|
||||
ammo_type = /obj/item/ammo_casing/c32acp
|
||||
max_ammo = 40
|
||||
|
||||
/obj/item/ammo_box/r32mm
|
||||
name = "ammo box (rubber .32 acp)"
|
||||
desc = "Non-lethal .32 acp bullets, there's forty in the box."
|
||||
ammo_type = /obj/item/ammo_casing/r32acp
|
||||
max_ammo = 40
|
||||
|
||||
/obj/item/ammo_box/c9mm
|
||||
name = "ammo box (9mm)"
|
||||
icon_state = "9mmbox"
|
||||
|
||||
@@ -20,3 +20,7 @@
|
||||
/obj/item/ammo_box/magazine/mm195x129/update_icon()
|
||||
..()
|
||||
icon_state = "a762-[round(ammo_count(),10)]"
|
||||
|
||||
/obj/item/ammo_box/magazine/mm712x82/match
|
||||
name = "box magazine (Match 7.12x82mm)"
|
||||
ammo_type = /obj/item/ammo_casing/mm712x82/match
|
||||
@@ -66,3 +66,15 @@
|
||||
caliber = ".50"
|
||||
max_ammo = 7
|
||||
multiple_sprites = 1
|
||||
|
||||
/obj/item/ammo_box/magazine/m32acp
|
||||
name = "pistol magazine (.32)"
|
||||
desc = "A crudely construction pistol magazine that holds .32 ACP rounds. It looks like it can only fit eight bullets."
|
||||
icon_state = "32acp"
|
||||
ammo_type = /obj/item/ammo_casing/c32acp
|
||||
caliber = "c32acp"
|
||||
max_ammo = 8
|
||||
multiple_sprites = 2
|
||||
|
||||
/obj/item/ammo_box/magazine/m32acp/empty
|
||||
start_empty = 1
|
||||
|
||||
@@ -12,3 +12,105 @@
|
||||
|
||||
/obj/item/ammo_box/magazine/recharge/attack_self() //No popping out the "bullets"
|
||||
return
|
||||
|
||||
// MWS Magazine //
|
||||
/obj/item/ammo_box/magazine/mws_mag
|
||||
name = "microbattery magazine"
|
||||
desc = "A microbattery holder for the 'Big Iron'"
|
||||
|
||||
icon = 'icons/obj/ammo.dmi'
|
||||
icon_state = "mws_mag"
|
||||
caliber = "mws"
|
||||
ammo_type = /obj/item/ammo_casing/mws_batt
|
||||
start_empty = TRUE
|
||||
max_ammo = 3
|
||||
|
||||
var/list/modes = list()
|
||||
|
||||
/obj/item/ammo_box/magazine/mws_mag/update_overlays()
|
||||
.=..()
|
||||
if(!stored_ammo.len)
|
||||
return //Why bother
|
||||
|
||||
var/x_offset = 5
|
||||
var/current = 0
|
||||
for(var/B in stored_ammo)
|
||||
var/obj/item/ammo_casing/mws_batt/batt = B
|
||||
var/mutable_appearance/cap = mutable_appearance(icon, "[initial(icon_state)]_cap", color = batt.type_color)
|
||||
cap.pixel_x = current * x_offset //Caps don't need a pixel_y offset
|
||||
. += cap
|
||||
if(batt.cell.charge > 0)
|
||||
var/ratio = CEILING(clamp(batt.cell.charge / batt.cell.maxcharge, 0, 1) * 4, 1) //4 is how many lights we have a sprite for
|
||||
var/mutable_appearance/charge = mutable_appearance(icon, "[initial(icon_state)]_charge-[ratio]", color = "#29EAF4") //Could use battery color but eh.
|
||||
charge.pixel_x = current * x_offset
|
||||
. += charge
|
||||
|
||||
current++ //Increment for offsets
|
||||
|
||||
|
||||
// MWS Batteries //
|
||||
/obj/item/ammo_casing/mws_batt
|
||||
name = "\'MWS\' microbattery - UNKNOWN"
|
||||
desc = "A miniature battery for an energy weapon."
|
||||
icon = 'icons/obj/ammo.dmi'
|
||||
icon_state = "mws_batt"
|
||||
slot_flags = SLOT_BELT | SLOT_EARS
|
||||
throwforce = 1
|
||||
|
||||
caliber = "mws"
|
||||
var/type_color = null
|
||||
var/type_name = null
|
||||
|
||||
var/obj/item/stock_parts/cell/cell
|
||||
var/cell_type = /obj/item/stock_parts/cell{charge = 600; maxcharge = 600}
|
||||
|
||||
var/e_cost = 100
|
||||
projectile_type = /obj/item/projectile/beam
|
||||
|
||||
/obj/item/ammo_casing/mws_batt/Initialize()
|
||||
. = ..()
|
||||
pixel_x = rand(-10, 10)
|
||||
pixel_y = rand(-10, 10)
|
||||
cell = new cell_type(src)
|
||||
cell.give(cell.maxcharge)
|
||||
update_icon()
|
||||
|
||||
/obj/item/ammo_casing/mws_batt/update_overlays()
|
||||
.=..()
|
||||
|
||||
var/mutable_appearance/ends = mutable_appearance(icon, "[initial(icon_state)]_ends", color = type_color)
|
||||
. += ends
|
||||
|
||||
/obj/item/ammo_casing/mws_batt/get_cell()
|
||||
return cell
|
||||
|
||||
/obj/item/ammo_casing/mws_batt/proc/chargeshot()
|
||||
if(cell.charge >= e_cost)
|
||||
cell.use(e_cost)
|
||||
newshot()
|
||||
return
|
||||
|
||||
// Specific batteries //
|
||||
/obj/item/ammo_casing/mws_batt/lethal
|
||||
name = "'MWS' microbattery - LETHAL"
|
||||
type_color = "#bf3d3d"
|
||||
type_name = "<span class='lethal'>LETHAL</span>"
|
||||
projectile_type = /obj/item/projectile/beam
|
||||
|
||||
/obj/item/ammo_casing/mws_batt/stun
|
||||
name = "'MWS' microbattery - STUN"
|
||||
type_color = "#0f81bc"
|
||||
type_name = "<span class='stun'>STUN</span>"
|
||||
projectile_type = /obj/item/projectile/beam/disabler
|
||||
|
||||
/obj/item/ammo_casing/mws_batt/xray
|
||||
name = "'MWS' microbattery - XRAY"
|
||||
type_color = "#32c025"
|
||||
type_name = "<span class='xray'>XRAY</span>"
|
||||
projectile_type = /obj/item/projectile/beam/xray
|
||||
|
||||
/obj/item/ammo_casing/mws_batt/ion
|
||||
name = "'MWS' microbattery - ION"
|
||||
type_color = "#d084d6"
|
||||
type_name = "<span class='ion'>ION</span>"
|
||||
projectile_type = /obj/item/projectile/ion
|
||||
@@ -50,3 +50,8 @@
|
||||
name = "riot shotgun internal magazine"
|
||||
ammo_type = /obj/item/ammo_casing/shotgun/rubbershot
|
||||
max_ammo = 6
|
||||
|
||||
/obj/item/ammo_box/magazine/internal/shot/bounty
|
||||
name = "triple-barrel shotgun internal magazine"
|
||||
ammo_type = /obj/item/ammo_casing/shotgun/incapacitate
|
||||
max_ammo = 3
|
||||
@@ -15,7 +15,7 @@
|
||||
throw_speed = 3
|
||||
throw_range = 5
|
||||
force = 5
|
||||
item_flags = NEEDS_PERMIT | NO_ATTACK_CHAIN_SOFT_STAMCRIT
|
||||
item_flags = NEEDS_PERMIT
|
||||
attack_verb = list("struck", "hit", "bashed")
|
||||
|
||||
var/fire_sound = "gunshot"
|
||||
@@ -128,7 +128,7 @@
|
||||
zoom(user, FALSE) //we can only stay zoomed in if it's in our hands //yeah and we only unzoom if we're actually zoomed using the gun!!
|
||||
|
||||
//called after the gun has successfully fired its chambered ammo.
|
||||
/obj/item/gun/proc/process_chamber()
|
||||
/obj/item/gun/proc/process_chamber(mob/living/user)
|
||||
return FALSE
|
||||
|
||||
//check if there's enough ammo/energy/whatever to shoot one time
|
||||
@@ -140,12 +140,13 @@
|
||||
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)
|
||||
/obj/item/gun/proc/shoot_live_shot(mob/living/user, pointblank = FALSE, mob/pbtarget, message = 1, stam_cost = 0)
|
||||
if(recoil)
|
||||
shake_camera(user, recoil + 1, recoil)
|
||||
|
||||
if(isliving(user)) //CIT CHANGE - makes gun recoil cause staminaloss
|
||||
user.adjustStaminaLossBuffered(getstamcost(user)*(firing && burst_size >= 2 ? 1/burst_size : 1)) //CIT CHANGE - ditto
|
||||
if(stam_cost) //CIT CHANGE - makes gun recoil cause staminaloss
|
||||
var/safe_cost = clamp(stam_cost, 0, STAMINA_NEAR_CRIT - user.getStaminaLoss())*(firing && burst_size >= 2 ? 1/burst_size : 1)
|
||||
user.adjustStaminaLossBuffered(safe_cost) //CIT CHANGE - ditto
|
||||
|
||||
if(suppressed)
|
||||
playsound(user, fire_sound, 10, 1)
|
||||
@@ -172,9 +173,10 @@
|
||||
return
|
||||
if(firing)
|
||||
return
|
||||
if(IS_STAMCRIT(user)) //respect stamina softcrit
|
||||
to_chat(user, "<span class='warning'>You are too exhausted to fire [src]!</span>")
|
||||
return
|
||||
var/stamloss = user.getStaminaLoss()
|
||||
if(stamloss >= STAMINA_NEAR_SOFTCRIT) //The more tired you are, the less damage you do.
|
||||
var/penalty = (stamloss - STAMINA_NEAR_SOFTCRIT)/(STAMINA_NEAR_CRIT - STAMINA_NEAR_SOFTCRIT)*STAM_CRIT_GUN_DELAY
|
||||
user.changeNext_move(CLICK_CD_RANGE+(CLICK_CD_RANGE*penalty))
|
||||
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
|
||||
@@ -216,7 +218,7 @@
|
||||
var/loop_counter = 0
|
||||
|
||||
if(user)
|
||||
bonus_spread += getinaccuracy(user) //CIT CHANGE - adds bonus spread while not aiming
|
||||
bonus_spread = getinaccuracy(user, bonus_spread, stamloss) //CIT CHANGE - adds bonus spread while not aiming
|
||||
if(ishuman(user) && user.a_intent == INTENT_HARM && weapon_weight <= WEAPON_LIGHT)
|
||||
var/mob/living/carbon/human/H = user
|
||||
for(var/obj/item/gun/G in H.held_items)
|
||||
@@ -225,9 +227,11 @@
|
||||
else if(G.can_trigger_gun(user))
|
||||
bonus_spread += 24 * G.weapon_weight * G.dualwield_spread_mult
|
||||
loop_counter++
|
||||
addtimer(CALLBACK(G, /obj/item/gun.proc/process_fire, target, user, TRUE, params, null, bonus_spread), loop_counter)
|
||||
var/stam_cost = G.getstamcost(user)
|
||||
addtimer(CALLBACK(G, /obj/item/gun.proc/process_fire, target, user, TRUE, params, null, bonus_spread, stam_cost), loop_counter)
|
||||
|
||||
process_fire(target, user, TRUE, params, null, bonus_spread)
|
||||
var/stam_cost = getstamcost(user)
|
||||
process_fire(target, user, TRUE, params, null, bonus_spread, stam_cost)
|
||||
|
||||
/obj/item/gun/can_trigger_gun(mob/living/user)
|
||||
. = ..()
|
||||
@@ -258,21 +262,21 @@
|
||||
/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)
|
||||
/obj/item/gun/proc/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
add_fingerprint(user)
|
||||
|
||||
if(on_cooldown())
|
||||
return
|
||||
firing = TRUE
|
||||
. = do_fire(target, user, message, params, zone_override, bonus_spread)
|
||||
. = do_fire(target, user, message, params, zone_override, bonus_spread, stam_cost)
|
||||
firing = FALSE
|
||||
last_fire = world.time
|
||||
|
||||
if(user)
|
||||
user.update_inv_hands()
|
||||
SEND_SIGNAL(user, COMSIG_LIVING_GUN_PROCESS_FIRE, target, params, zone_override)
|
||||
SEND_SIGNAL(user, COMSIG_LIVING_GUN_PROCESS_FIRE, target, params, zone_override, bonus_spread, stam_cost)
|
||||
|
||||
/obj/item/gun/proc/do_fire(atom/target, mob/living/user, message = TRUE, params, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/proc/do_fire(atom/target, mob/living/user, message = TRUE, params, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
var/sprd = 0
|
||||
var/randomized_gun_spread = 0
|
||||
var/rand_spr = rand()
|
||||
@@ -290,7 +294,7 @@
|
||||
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)
|
||||
do_burst_shot(user, target, message, params, zone_override, sprd, randomized_gun_spread, randomized_bonus_spread, rand_spr, i, stam_cost)
|
||||
else
|
||||
if(chambered)
|
||||
sprd = round((rand() - 0.5) * DUALWIELD_PENALTY_EXTRA_MULTIPLIER * (randomized_gun_spread + randomized_bonus_spread))
|
||||
@@ -300,19 +304,19 @@
|
||||
return
|
||||
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)
|
||||
shoot_live_shot(user, 1, target, message, stam_cost)
|
||||
else
|
||||
shoot_live_shot(user, 0, target, message)
|
||||
shoot_live_shot(user, 0, target, message, stam_cost)
|
||||
else
|
||||
shoot_with_empty_chamber(user)
|
||||
return
|
||||
process_chamber()
|
||||
process_chamber(user)
|
||||
update_icon()
|
||||
|
||||
SSblackbox.record_feedback("tally", "gun_fired", 1, type)
|
||||
return TRUE
|
||||
|
||||
/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)
|
||||
/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, stam_cost = 0)
|
||||
if(!user || !firing)
|
||||
firing = FALSE
|
||||
return FALSE
|
||||
@@ -336,33 +340,34 @@
|
||||
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)
|
||||
shoot_live_shot(user, 1, target, message, stam_cost)
|
||||
else
|
||||
shoot_live_shot(user, 0, target, message)
|
||||
shoot_live_shot(user, 0, target, message, stam_cost)
|
||||
if (iteration >= burst_size)
|
||||
firing = FALSE
|
||||
else
|
||||
shoot_with_empty_chamber(user)
|
||||
firing = FALSE
|
||||
return FALSE
|
||||
process_chamber()
|
||||
process_chamber(user)
|
||||
update_icon()
|
||||
return TRUE
|
||||
|
||||
/obj/item/gun/attack(mob/M as mob, mob/user)
|
||||
/obj/item/gun/attack(mob/living/M, mob/user)
|
||||
if(user.a_intent == INTENT_HARM) //Flogging
|
||||
if(bayonet)
|
||||
M.attackby(bayonet, user)
|
||||
attack_delay_done = TRUE
|
||||
return
|
||||
else
|
||||
return ..()
|
||||
return
|
||||
attack_delay_done = TRUE //we are firing the gun, not bashing people with its butt.
|
||||
|
||||
/obj/item/gun/attack_obj(obj/O, mob/user)
|
||||
if(user.a_intent == INTENT_HARM)
|
||||
if(bayonet)
|
||||
O.attackby(bayonet, user)
|
||||
return
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/obj/item/gun/attackby(obj/item/I, mob/user, params)
|
||||
@@ -498,7 +503,7 @@
|
||||
if(chambered && chambered.BB)
|
||||
chambered.BB.damage *= 5
|
||||
|
||||
process_fire(target, user, TRUE, params)
|
||||
process_fire(target, user, TRUE, params, stam_cost = getstamcost(user))
|
||||
|
||||
/obj/item/gun/proc/unlock() //used in summon guns and as a convience for admins
|
||||
if(pin)
|
||||
@@ -566,7 +571,25 @@
|
||||
chambered = null
|
||||
update_icon()
|
||||
|
||||
/obj/item/gun/proc/getinaccuracy(mob/user)
|
||||
if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
|
||||
return ((weapon_weight * 25) * inaccuracy_modifier)
|
||||
return 0
|
||||
/obj/item/gun/proc/getinaccuracy(mob/living/user, bonus_spread, stamloss)
|
||||
if(inaccuracy_modifier == 0)
|
||||
return bonus_spread
|
||||
var/base_inaccuracy = weapon_weight * 25 * inaccuracy_modifier
|
||||
var/aiming_delay = 0 //Otherwise aiming would be meaningless for slower guns such as sniper rifles and launchers.
|
||||
if(fire_delay)
|
||||
var/penalty = (last_fire + GUN_AIMING_TIME + fire_delay) - world.time
|
||||
if(penalty > 0) //Yet we only penalize users firing it multiple times in a haste. fire_delay isn't necessarily cumbersomeness.
|
||||
aiming_delay = penalty
|
||||
if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE)) //To be removed in favor of something less tactless later.
|
||||
base_inaccuracy /= 1.5
|
||||
if(stamloss > STAMINA_NEAR_SOFTCRIT) //This can null out the above bonus.
|
||||
base_inaccuracy *= 1 + (stamloss - STAMINA_NEAR_SOFTCRIT)/(STAMINA_NEAR_CRIT - STAMINA_NEAR_SOFTCRIT)*0.5
|
||||
var/mult = max((GUN_AIMING_TIME + aiming_delay + user.last_click_move - world.time)/GUN_AIMING_TIME, -0.5) //Yes, there is a bonus for taking time aiming.
|
||||
if(mult < 0) //accurate weapons should provide a proper bonus with negative inaccuracy. the opposite is true too.
|
||||
mult *= 1/inaccuracy_modifier
|
||||
return max(bonus_spread + (base_inaccuracy * mult), 0) //no negative spread.
|
||||
|
||||
/obj/item/gun/proc/getstamcost(mob/living/carbon/user)
|
||||
. = recoil
|
||||
if(user && !user.has_gravity())
|
||||
. = recoil*5
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
else
|
||||
icon_state = "[initial(icon_state)][suppressed ? "-suppressed" : ""][sawn_off ? "-sawn" : ""]"
|
||||
|
||||
/obj/item/gun/ballistic/process_chamber(empty_chamber = 1)
|
||||
/obj/item/gun/ballistic/process_chamber(mob/living/user, empty_chamber = 1)
|
||||
var/obj/item/ammo_casing/AC = chambered //Find chambered round
|
||||
if(istype(AC)) //there's a chambered round
|
||||
if(casing_ejector)
|
||||
|
||||
@@ -365,7 +365,7 @@
|
||||
can_unsuppress = TRUE
|
||||
can_suppress = TRUE
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.5
|
||||
zoomable = TRUE
|
||||
zoom_amt = 10 //Long range, enough to see in front of you, but no tiles behind you.
|
||||
zoom_out_amt = 13
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
..()
|
||||
|
||||
/obj/item/minigunpack/dropped(mob/user)
|
||||
. = ..()
|
||||
if(armed)
|
||||
user.dropItemToGround(gun, TRUE)
|
||||
|
||||
@@ -125,12 +126,13 @@
|
||||
return
|
||||
|
||||
/obj/item/gun/ballistic/minigun/dropped(mob/user)
|
||||
. = ..()
|
||||
if(ammo_pack)
|
||||
ammo_pack.attach_gun(user)
|
||||
else
|
||||
qdel(src)
|
||||
|
||||
/obj/item/gun/ballistic/minigun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/ballistic/minigun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
if(ammo_pack)
|
||||
if(ammo_pack.overheat < ammo_pack.overheat_max)
|
||||
ammo_pack.overheat += burst_size
|
||||
@@ -144,4 +146,5 @@
|
||||
. = ..()
|
||||
|
||||
/obj/item/gun/ballistic/minigun/dropped(mob/living/user)
|
||||
. = ..()
|
||||
ammo_pack.attach_gun(user)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
name = "grenade launcher"
|
||||
icon_state = "dshotgun-sawn"
|
||||
item_state = "gun"
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.5
|
||||
mag_type = /obj/item/ammo_box/magazine/internal/grenadelauncher
|
||||
fire_sound = 'sound/weapons/grenadelaunch.ogg'
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
@@ -87,7 +87,7 @@
|
||||
pin = /obj/item/firing_pin/implant/pindicate
|
||||
burst_size = 1
|
||||
fire_delay = 0
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.25
|
||||
casing_ejector = FALSE
|
||||
weapon_weight = WEAPON_HEAVY
|
||||
magazine_wording = "rocket"
|
||||
@@ -144,13 +144,13 @@
|
||||
user.visible_message("<span class='warning'>[user] aims [src] at the ground! It looks like [user.p_theyre()] performing a sick rocket jump!</span>", \
|
||||
"<span class='userdanger'>You aim [src] at the ground to perform a bisnasty rocket jump...</span>")
|
||||
if(can_shoot())
|
||||
user.notransform = TRUE
|
||||
user.mob_transforming = TRUE
|
||||
playsound(src, 'sound/vehicles/rocketlaunch.ogg', 80, 1, 5)
|
||||
animate(user, pixel_z = 300, time = 30, easing = LINEAR_EASING)
|
||||
sleep(70)
|
||||
animate(user, pixel_z = 0, time = 5, easing = LINEAR_EASING)
|
||||
sleep(5)
|
||||
user.notransform = FALSE
|
||||
user.mob_transforming = FALSE
|
||||
process_fire(user, user, TRUE)
|
||||
if(!QDELETED(user)) //if they weren't gibbed by the explosion, take care of them for good.
|
||||
user.gib()
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
spread = 0
|
||||
recoil = 0.1
|
||||
casing_ejector = FALSE
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.15
|
||||
dualwield_spread_mult = 1.4
|
||||
weapon_weight = WEAPON_MEDIUM
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
@@ -46,7 +46,7 @@
|
||||
return 0
|
||||
. = ..()
|
||||
|
||||
/obj/item/gun/ballistic/automatic/magrifle/shoot_live_shot()
|
||||
/obj/item/gun/ballistic/automatic/magrifle/shoot_live_shot(mob/living/user, pointblank = FALSE, mob/pbtarget, message = 1, stam_cost = 0)
|
||||
var/obj/item/ammo_casing/caseless/magnetic/shot = chambered
|
||||
cell.use(shot.energy_cost)
|
||||
. = ..()
|
||||
|
||||
@@ -115,6 +115,7 @@
|
||||
icon_state = "flatgun"
|
||||
|
||||
/obj/item/gun/ballistic/automatic/pistol/stickman/pickup(mob/living/user)
|
||||
. = ..()
|
||||
to_chat(user, "<span class='notice'>As you try to pick up [src], it slips out of your grip..</span>")
|
||||
if(prob(50))
|
||||
to_chat(user, "<span class='notice'>..and vanishes from your vision! Where the hell did it go?</span>")
|
||||
@@ -155,3 +156,19 @@
|
||||
name = "Syndicate Anti Tank Pistol"
|
||||
desc = "A massively impractical and silly monstrosity of a pistol that fires .50 calliber rounds. The recoil is likely to dislocate a variety of joints without proper bracing."
|
||||
pin = /obj/item/firing_pin/implant/pindicate
|
||||
|
||||
////////////Improvised Pistol////////////
|
||||
|
||||
/obj/item/gun/ballistic/automatic/pistol/improvised
|
||||
name = "Improvised Pistol"
|
||||
desc = "An improvised pocket-sized pistol that fires .32 calibre rounds. It looks incredibly flimsy."
|
||||
icon_state = "ipistol"
|
||||
item_state = "pistol"
|
||||
mag_type = /obj/item/ammo_box/magazine/m32acp
|
||||
fire_delay = 7.5
|
||||
can_suppress = FALSE
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
spread = 15 // Keep the spread between 15 and 20. This hardlocks it into being a mid-range pistol, the magazine size means you're allowed to miss. Fills the mid-range niche that slugs/rifle and buckshot doesn't fill.
|
||||
|
||||
/obj/item/gun/ballistic/automatic/pistol/improvised/nomag
|
||||
spawnwithmagazine = FALSE // For crafting as you shouldn't get eight bullets for free otherwise people will reaper reload.
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
. = ..()
|
||||
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)
|
||||
/obj/item/gun/ballistic/revolver/detective/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
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)
|
||||
@@ -242,7 +242,7 @@
|
||||
user.visible_message("<span class='danger'>*click*</span>")
|
||||
playsound(src, "gun_dry_fire", 30, 1)
|
||||
|
||||
/obj/item/gun/ballistic/revolver/russian/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/ballistic/revolver/russian/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
add_fingerprint(user)
|
||||
playsound(src, "gun_dry_fire", 30, TRUE)
|
||||
user.visible_message("<span class='danger'>[user.name] tries to fire \the [src] at the same time, but only succeeds at looking like an idiot.</span>", "<span class='danger'>\The [src]'s anti-combat mechanism prevents you from firing it at the same time!</span>")
|
||||
@@ -319,7 +319,6 @@
|
||||
|
||||
/obj/item/gun/ballistic/revolver/doublebarrel/improvised
|
||||
name = "improvised shotgun"
|
||||
desc = "Essentially a tube that aims shotgun shells."
|
||||
desc = "A shoddy break-action breechloaded shotgun. Its lacklustre construction will probably result in it hurting people less than a normal shotgun."
|
||||
icon_state = "ishotgun"
|
||||
item_state = "shotgun"
|
||||
@@ -330,8 +329,9 @@
|
||||
mag_type = /obj/item/ammo_box/magazine/internal/shot/improvised
|
||||
sawn_desc = "I'm just here for the gasoline."
|
||||
unique_reskin = null
|
||||
projectile_damage_multiplier = 0.8
|
||||
projectile_damage_multiplier = 0.9
|
||||
var/slung = FALSE
|
||||
weapon_weight = WEAPON_HEAVY
|
||||
|
||||
/obj/item/gun/ballistic/revolver/doublebarrel/improvised/attackby(obj/item/A, mob/user, params)
|
||||
..()
|
||||
@@ -358,7 +358,7 @@
|
||||
|
||||
/obj/item/gun/ballistic/revolver/doublebarrel/improvised/sawn
|
||||
name = "sawn-off improvised shotgun"
|
||||
desc = "A single-shot shotgun. Better not miss."
|
||||
desc = "The barrel and stock have been sawn and filed down; it can fit in backpacks. You still need two hands to fire this, if you value unbroken wrists."
|
||||
icon_state = "ishotgun"
|
||||
item_state = "gun"
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
@@ -377,3 +377,114 @@
|
||||
user.emote("scream")
|
||||
user.drop_all_held_items()
|
||||
user.DefaultCombatKnockdown(80)
|
||||
|
||||
// -------------- HoS Modular Weapon System -------------
|
||||
// ---------- Code originally from VoreStation ----------
|
||||
/obj/item/gun/ballistic/revolver/mws
|
||||
name = "MWS-01 'Big Iron'"
|
||||
desc = "Modular Weapons System"
|
||||
|
||||
icon = 'icons/obj/guns/projectile.dmi'
|
||||
icon_state = "mws"
|
||||
|
||||
fire_sound = 'sound/weapons/Taser.ogg'
|
||||
|
||||
mag_type = /obj/item/ammo_box/magazine/mws_mag
|
||||
spawnwithmagazine = FALSE
|
||||
|
||||
recoil = 0
|
||||
|
||||
var/charge_sections = 6
|
||||
|
||||
/obj/item/gun/ballistic/revolver/mws/examine(mob/user)
|
||||
. = ..()
|
||||
. += "<span class='notice'>Alt-click to remove the magazine.</span>"
|
||||
|
||||
/obj/item/gun/ballistic/revolver/mws/shoot_with_empty_chamber(mob/living/user as mob|obj)
|
||||
process_chamber(user)
|
||||
if(!chambered || !chambered.BB)
|
||||
to_chat(user, "<span class='danger'>*click*</span>")
|
||||
playsound(src, "gun_dry_fire", 30, 1)
|
||||
|
||||
|
||||
/obj/item/gun/ballistic/revolver/mws/process_chamber(mob/living/user)
|
||||
if(chambered && !chambered.BB) //if BB is null, i.e the shot has been fired...
|
||||
var/obj/item/ammo_casing/mws_batt/shot = chambered
|
||||
if(shot.cell.charge >= shot.e_cost)
|
||||
shot.chargeshot()
|
||||
else
|
||||
for(var/B in magazine.stored_ammo)
|
||||
var/obj/item/ammo_casing/mws_batt/other_batt = B
|
||||
if(istype(other_batt,shot) && other_batt.cell.charge >= other_batt.e_cost)
|
||||
switch_to(other_batt, user)
|
||||
break
|
||||
update_icon()
|
||||
|
||||
/obj/item/gun/ballistic/revolver/mws/proc/switch_to(obj/item/ammo_casing/mws_batt/new_batt, mob/living/user)
|
||||
if(ishuman(user))
|
||||
if(chambered && new_batt.type == chambered.type)
|
||||
to_chat(user,"<span class='warning'>[src] is now using the next [new_batt.type_name] power cell.</span>")
|
||||
else
|
||||
to_chat(user,"<span class='warning'>[src] is now firing [new_batt.type_name].</span>")
|
||||
|
||||
chambered = new_batt
|
||||
update_icon()
|
||||
|
||||
/obj/item/gun/ballistic/revolver/mws/attack_self(mob/living/user)
|
||||
if(!chambered)
|
||||
return
|
||||
|
||||
var/list/stored_ammo = magazine.stored_ammo
|
||||
|
||||
if(stored_ammo.len == 1)
|
||||
return //silly you.
|
||||
|
||||
//Find an ammotype that ISN'T the same, or exhaust the list and don't change.
|
||||
var/our_slot = stored_ammo.Find(chambered)
|
||||
|
||||
for(var/index in 1 to stored_ammo.len)
|
||||
var/true_index = ((our_slot + index - 1) % stored_ammo.len) + 1 // Stupid ONE BASED lists!
|
||||
var/obj/item/ammo_casing/mws_batt/next_batt = stored_ammo[true_index]
|
||||
if(chambered != next_batt && !istype(next_batt, chambered.type) && next_batt.cell.charge >= next_batt.e_cost)
|
||||
switch_to(next_batt, user)
|
||||
break
|
||||
|
||||
/obj/item/gun/ballistic/revolver/mws/AltClick(mob/living/user)
|
||||
.=..()
|
||||
if(magazine)
|
||||
user.put_in_hands(magazine)
|
||||
magazine.update_icon()
|
||||
if(magazine.ammo_count())
|
||||
playsound(src, 'sound/weapons/gun_magazine_remove_full.ogg', 70, 1)
|
||||
else
|
||||
playsound(src, "gun_remove_empty_magazine", 70, 1)
|
||||
magazine = null
|
||||
to_chat(user, "<span class='notice'>You pull the magazine out of [src].</span>")
|
||||
if(chambered)
|
||||
chambered = null
|
||||
update_icon()
|
||||
|
||||
/obj/item/gun/ballistic/revolver/mws/update_overlays()
|
||||
.=..()
|
||||
if(!chambered)
|
||||
return
|
||||
|
||||
var/obj/item/ammo_casing/mws_batt/batt = chambered
|
||||
var/batt_color = batt.type_color //Used many times
|
||||
|
||||
//Mode bar
|
||||
var/image/mode_bar = image(icon, icon_state = "[initial(icon_state)]_type")
|
||||
mode_bar.color = batt_color
|
||||
. += mode_bar
|
||||
|
||||
//Barrel color
|
||||
var/mutable_appearance/barrel_color = mutable_appearance(icon, "[initial(icon_state)]_barrel", color = batt_color)
|
||||
barrel_color.alpha = 150
|
||||
. += barrel_color
|
||||
|
||||
//Charge bar
|
||||
var/ratio = can_shoot() ? CEILING(clamp(batt.cell.charge / batt.cell.maxcharge, 0, 1) * charge_sections, 1) : 0
|
||||
for(var/i = 0, i < ratio, i++)
|
||||
var/mutable_appearance/charge_bar = mutable_appearance(icon, "[initial(icon_state)]_charge", color = batt_color)
|
||||
charge_bar.pixel_x = i
|
||||
. += charge_bar
|
||||
@@ -23,7 +23,7 @@
|
||||
A.update_icon()
|
||||
update_icon()
|
||||
|
||||
/obj/item/gun/ballistic/shotgun/process_chamber(empty_chamber = 0)
|
||||
/obj/item/gun/ballistic/shotgun/process_chamber(mob/living/user, empty_chamber = 0)
|
||||
return ..() //changed argument value
|
||||
|
||||
/obj/item/gun/ballistic/shotgun/chamber_round()
|
||||
@@ -116,7 +116,7 @@
|
||||
icon_state = "moistnugget"
|
||||
item_state = "moistnugget"
|
||||
slot_flags = 0 //no ITEM_SLOT_BACK sprite, alas
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.5
|
||||
mag_type = /obj/item/ammo_box/magazine/internal/boltaction
|
||||
var/bolt_open = FALSE
|
||||
can_bayonet = TRUE
|
||||
@@ -131,6 +131,7 @@
|
||||
desc = "A bolt-action breechloaded rifle that takes 7.62mm bullets."
|
||||
mag_type = /obj/item/ammo_box/magazine/internal/boltaction/improvised
|
||||
can_bayonet = FALSE
|
||||
var/slung = FALSE
|
||||
|
||||
/obj/item/gun/ballistic/shotgun/boltaction/pump(mob/M)
|
||||
playsound(M, 'sound/weapons/shotgunpump.ogg', 60, 1)
|
||||
@@ -152,6 +153,22 @@
|
||||
. = ..()
|
||||
. += "The bolt is [bolt_open ? "open" : "closed"]."
|
||||
|
||||
/obj/item/gun/ballistic/shotgun/boltaction/improvised/attackby(obj/item/A, mob/user, params)
|
||||
..()
|
||||
if(istype(A, /obj/item/stack/cable_coil) && !sawn_off)
|
||||
if(A.use_tool(src, user, 0, 10, max_level = JOB_SKILL_BASIC))
|
||||
slot_flags = ITEM_SLOT_BACK
|
||||
to_chat(user, "<span class='notice'>You tie the lengths of cable to the rifle, making a sling.</span>")
|
||||
slung = TRUE
|
||||
update_icon()
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You need at least ten lengths of cable if you want to make a sling!</span>")
|
||||
|
||||
/obj/item/gun/ballistic/shotgun/boltaction/improvised/update_icon()
|
||||
..()
|
||||
if(slung)
|
||||
icon_state += "sling"
|
||||
|
||||
/obj/item/gun/ballistic/shotgun/boltaction/enchanted
|
||||
name = "enchanted bolt action rifle"
|
||||
desc = "Careful not to lose your head."
|
||||
@@ -191,7 +208,7 @@
|
||||
/obj/item/gun/ballistic/shotgun/boltaction/enchanted/attack_self()
|
||||
return
|
||||
|
||||
/obj/item/gun/ballistic/shotgun/boltaction/enchanted/shoot_live_shot(mob/living/user as mob|obj, pointblank = 0, mob/pbtarget = null, message = 1)
|
||||
/obj/item/gun/ballistic/shotgun/boltaction/enchanted/shoot_live_shot(mob/living/user, pointblank = FALSE, mob/pbtarget, message = 1, stam_cost = 0)
|
||||
..()
|
||||
if(guns_left)
|
||||
var/obj/item/gun/ballistic/shotgun/boltaction/enchanted/GUN = new gun_type
|
||||
@@ -205,7 +222,7 @@
|
||||
|
||||
// Automatic Shotguns//
|
||||
|
||||
/obj/item/gun/ballistic/shotgun/automatic/shoot_live_shot(mob/living/user as mob|obj)
|
||||
/obj/item/gun/ballistic/shotgun/automatic/shoot_live_shot(mob/living/user, pointblank = FALSE, mob/pbtarget, message = 1, stam_cost = 0)
|
||||
..()
|
||||
src.pump(user)
|
||||
|
||||
@@ -303,3 +320,18 @@
|
||||
return TRUE
|
||||
|
||||
// DOUBLE BARRELED SHOTGUN and IMPROVISED SHOTGUN are in revolver.dm
|
||||
|
||||
/obj/item/gun/ballistic/shotgun/doublebarrel/hook
|
||||
name = "hook modified sawn-off shotgun"
|
||||
desc = "Range isn't an issue when you can bring your victim to you."
|
||||
icon_state = "hookshotgun"
|
||||
item_state = "shotgun"
|
||||
mag_type = /obj/item/ammo_box/magazine/internal/shot/bounty
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
weapon_weight = WEAPON_MEDIUM
|
||||
force = 16 //it has a hook on it
|
||||
attack_verb = list("slashed", "hooked", "stabbed")
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
//our hook gun!
|
||||
var/obj/item/gun/magic/hook/bounty/hook
|
||||
var/toggled = FALSE
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
casing_ejector = FALSE
|
||||
can_suppress = FALSE
|
||||
|
||||
/obj/item/gun/ballistic/shotgun/toy/process_chamber(empty_chamber = 0)
|
||||
/obj/item/gun/ballistic/shotgun/toy/process_chamber(mob/living/user, empty_chamber = 0)
|
||||
..()
|
||||
if(chambered && !chambered.BB)
|
||||
qdel(chambered)
|
||||
|
||||
@@ -127,12 +127,12 @@
|
||||
chambered = null //either way, released the prepared shot
|
||||
recharge_newshot() //try to charge a new shot
|
||||
|
||||
/obj/item/gun/energy/do_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, stam_cost = 0)
|
||||
if(!chambered && can_shoot())
|
||||
process_chamber() // If the gun was drained and then recharged, load a new shot.
|
||||
return ..()
|
||||
|
||||
/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)
|
||||
/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, stam_cost = 0)
|
||||
if(!chambered && can_shoot())
|
||||
process_chamber() // Ditto.
|
||||
return ..()
|
||||
|
||||
@@ -237,7 +237,7 @@
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/gun/energy/dueling/process_fire(atom/target, mob/living/user, message, params, zone_override, bonus_spread)
|
||||
/obj/item/gun/energy/dueling/process_fire(atom/target, mob/living/user, message, params, zone_override, bonus_spread = 0, stam_cost = 0)
|
||||
if(duel.state == DUEL_READY)
|
||||
duel.confirmations[src] = TRUE
|
||||
to_chat(user,"<span class='notice'>You confirm your readiness.</span>")
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
fail_tick--
|
||||
..()
|
||||
|
||||
/obj/item/gun/energy/e_gun/nuclear/shoot_live_shot()
|
||||
/obj/item/gun/energy/e_gun/nuclear/shoot_live_shot(mob/living/user, pointblank = FALSE, mob/pbtarget, message = 1, stam_cost = 0)
|
||||
failcheck()
|
||||
update_icon()
|
||||
..()
|
||||
|
||||
@@ -60,6 +60,12 @@
|
||||
else
|
||||
cut_overlays()
|
||||
|
||||
/obj/item/gun/energy/kinetic_accelerator/getinaccuracy(mob/living/user, bonus_spread, stamloss)
|
||||
var/old_fire_delay = fire_delay //It's pretty irrelevant tbh but whatever.
|
||||
fire_delay = overheat_time
|
||||
. = ..()
|
||||
fire_delay = old_fire_delay
|
||||
|
||||
/obj/item/gun/energy/kinetic_accelerator/examine(mob/user)
|
||||
. = ..()
|
||||
if(max_mod_capacity)
|
||||
@@ -128,7 +134,7 @@
|
||||
if(!holds_charge)
|
||||
empty()
|
||||
|
||||
/obj/item/gun/energy/kinetic_accelerator/shoot_live_shot()
|
||||
/obj/item/gun/energy/kinetic_accelerator/shoot_live_shot(mob/living/user, pointblank = FALSE, mob/pbtarget, message = 1, stam_cost = 0)
|
||||
. = ..()
|
||||
attempt_reload()
|
||||
|
||||
@@ -207,6 +213,12 @@
|
||||
var/obj/item/gun/energy/kinetic_accelerator/KA = loc
|
||||
KA.modify_projectile(BB)
|
||||
|
||||
/obj/item/gun/energy/kinetic_accelerator/getstamcost(mob/living/carbon/user)
|
||||
if(user && !lavaland_equipment_pressure_check(get_turf(user)))
|
||||
return 0
|
||||
else
|
||||
return ..()
|
||||
|
||||
//Projectiles
|
||||
/obj/item/projectile/kinetic
|
||||
name = "kinetic force"
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
slot_flags = ITEM_SLOT_BACK
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
weapon_weight = WEAPON_MEDIUM
|
||||
inaccuracy_modifier = 0.5
|
||||
inaccuracy_modifier = 0.7
|
||||
force = 10
|
||||
throwforce = 10
|
||||
cell_type = /obj/item/stock_parts/cell/lascarbine
|
||||
@@ -240,3 +240,20 @@
|
||||
chambered.BB.damage *= 5
|
||||
|
||||
process_fire(target, user, TRUE, params)
|
||||
|
||||
////////////////
|
||||
// IMPROVISED //
|
||||
////////////////
|
||||
|
||||
/obj/item/gun/energy/e_gun/old/improvised
|
||||
name = "improvised energy rifle"
|
||||
desc = "A crude imitation of an energy gun. It works, however the beams are poorly focused and most of the energy is wasted before it reaches the target. Welp, it still burns things."
|
||||
icon_state = "improvised"
|
||||
ammo_x_offset = 1
|
||||
shaded_charge = 1
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/lasergun/improvised)
|
||||
|
||||
/obj/item/gun/energy/e_gun/old/improvised/upgraded
|
||||
name = "makeshift energy rifle"
|
||||
desc = "The new lens and upgraded parts gives this a higher capacity and more energy output, however, the shoddy construction still leaves it inferior to Nanotrasen's own energy weapons."
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/lasergun/improvised/upgraded)
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
suppressed = TRUE
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/bolt)
|
||||
weapon_weight = WEAPON_LIGHT
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.25
|
||||
obj_flags = 0
|
||||
overheat_time = 20
|
||||
holds_charge = TRUE
|
||||
@@ -126,7 +126,7 @@
|
||||
attack_verb = list("attacked", "slashed", "cut", "sliced")
|
||||
force = 12
|
||||
sharpness = IS_SHARP
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.25
|
||||
can_charge = 0
|
||||
|
||||
heat = 3800
|
||||
@@ -182,7 +182,7 @@
|
||||
item_state = null
|
||||
icon_state = "wormhole_projector"
|
||||
pin = null
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.25
|
||||
var/obj/effect/portal/p_blue
|
||||
var/obj/effect/portal/p_orange
|
||||
var/atmos_link = FALSE
|
||||
@@ -318,7 +318,7 @@
|
||||
icon_state = "emitter_carbine"
|
||||
force = 12
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.25
|
||||
cell_type = /obj/item/stock_parts/cell/super
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/emitter)
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
/obj/item/projectile/magic/death, /obj/item/projectile/magic/teleport, /obj/item/projectile/magic/door, /obj/item/projectile/magic/aoe/fireball,
|
||||
/obj/item/projectile/magic/spellblade, /obj/item/projectile/magic/arcane_barrage, /obj/item/projectile/magic/locker)
|
||||
|
||||
/obj/item/gun/magic/staff/chaos/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/magic/staff/chaos/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
chambered.projectile_type = pick(allowed_projectile_types)
|
||||
. = ..()
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
force = 4
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.25
|
||||
custom_materials = list(/datum/material/iron=2000)
|
||||
clumsy_check = FALSE
|
||||
fire_sound = 'sound/items/syringeproj.ogg'
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
/obj/item/gun/grenadelauncher/can_shoot()
|
||||
return grenades.len
|
||||
|
||||
/obj/item/gun/grenadelauncher/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/grenadelauncher/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
user.visible_message("<span class='danger'>[user] fired a grenade!</span>", \
|
||||
"<span class='danger'>You fire the grenade launcher!</span>")
|
||||
var/obj/item/grenade/F = grenades[1] //Now with less copypasta!
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
on_beam_release(current_target)
|
||||
current_target = null
|
||||
|
||||
/obj/item/gun/medbeam/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/medbeam/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
if(isliving(user))
|
||||
add_fingerprint(user)
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
force = 4
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.25
|
||||
custom_materials = list(/datum/material/iron=2000)
|
||||
clumsy_check = 0
|
||||
fire_sound = 'sound/items/syringeproj.ogg'
|
||||
@@ -160,7 +160,7 @@
|
||||
item_state = "blowgun"
|
||||
fire_sound = 'sound/items/syringeproj.ogg'
|
||||
|
||||
/obj/item/gun/syringe/blowgun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/syringe/blowgun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
visible_message("<span class='danger'>[user] starts aiming with a blowgun!</span>")
|
||||
if(do_after(user, 25, target = src))
|
||||
user.adjustStaminaLoss(20)
|
||||
|
||||
@@ -45,6 +45,8 @@
|
||||
var/pixels_range_leftover = 0
|
||||
/// "leftover" tick pixels and stuff yeah, so we don't round off things and introducing tracing inaccuracy.
|
||||
var/pixels_tick_leftover = 0
|
||||
/// Used to detect jumps in the middle of a pixel_move. Yes, this is ugly as sin code-wise but it works.
|
||||
var/pixel_move_interrupted = FALSE
|
||||
|
||||
/// Pixels moved per second.
|
||||
var/pixels_per_second = TILES_TO_PIXELS(12.5)
|
||||
@@ -56,9 +58,25 @@
|
||||
var/nondirectional_sprite = FALSE //Set TRUE to prevent projectiles from having their sprites rotated based on firing angle
|
||||
var/spread = 0 //amount (in degrees) of projectile spread
|
||||
animate_movement = 0 //Use SLIDE_STEPS in conjunction with legacy
|
||||
/// how many times we've ricochet'd so far (instance variable, not a stat)
|
||||
var/ricochets = 0
|
||||
var/ricochets_max = 2
|
||||
var/ricochet_chance = 30
|
||||
/// how many times we can ricochet max
|
||||
var/ricochets_max = 0
|
||||
/// 0-100, the base chance of ricocheting, before being modified by the atom we shoot and our chance decay
|
||||
var/ricochet_chance = 0
|
||||
/// 0-1 (or more, I guess) multiplier, the ricochet_chance is modified by multiplying this after each ricochet
|
||||
var/ricochet_decay_chance = 0.7
|
||||
/// 0-1 (or more, I guess) multiplier, the projectile's damage is modified by multiplying this after each ricochet
|
||||
var/ricochet_decay_damage = 0.7
|
||||
/// On ricochet, if nonzero, we consider all mobs within this range of our projectile at the time of ricochet to home in on like Revolver Ocelot, as governed by ricochet_auto_aim_angle
|
||||
var/ricochet_auto_aim_range = 0
|
||||
/// On ricochet, if ricochet_auto_aim_range is nonzero, we'll consider any mobs within this range of the normal angle of incidence to home in on, higher = more auto aim
|
||||
var/ricochet_auto_aim_angle = 30
|
||||
/// the angle of impact must be within this many degrees of the struck surface, set to 0 to allow any angle
|
||||
var/ricochet_incidence_leeway = 40
|
||||
|
||||
///If the object being hit can pass ths damage on to something else, it should not do it for this bullet
|
||||
var/force_hit = FALSE
|
||||
|
||||
//Hitscan
|
||||
var/hitscan = FALSE //Whether this is hitscan. If it is, speed is basically ignored.
|
||||
@@ -131,6 +149,11 @@
|
||||
|
||||
var/temporary_unstoppable_movement = FALSE
|
||||
|
||||
///If defined, on hit we create an item of this type then call hitby() on the hit target with this
|
||||
var/shrapnel_type
|
||||
///If TRUE, hit mobs even if they're on the floor and not our target
|
||||
var/hit_stunned_targets = FALSE
|
||||
|
||||
/obj/item/projectile/Initialize()
|
||||
. = ..()
|
||||
permutated = list()
|
||||
@@ -146,6 +169,7 @@
|
||||
on_range()
|
||||
|
||||
/obj/item/projectile/proc/on_range() //if we want there to be effects when they reach the end of their range
|
||||
SEND_SIGNAL(src, COMSIG_PROJECTILE_RANGE_OUT)
|
||||
qdel(src)
|
||||
|
||||
//to get the correct limb (if any) for the projectile hit message
|
||||
@@ -165,6 +189,14 @@
|
||||
/obj/item/projectile/proc/on_hit(atom/target, blocked = FALSE)
|
||||
if(fired_from)
|
||||
SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_ON_HIT, firer, target, Angle)
|
||||
|
||||
// i know that this is probably more with wands and gun mods in mind, but it's a bit silly that the projectile on_hit signal doesn't ping the projectile itself.
|
||||
// maybe we care what the projectile thinks! See about combining these via args some time when it's not 5AM
|
||||
var/obj/item/bodypart/hit_limb
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
hit_limb = L.check_limb_hit(def_zone)
|
||||
SEND_SIGNAL(src, COMSIG_PROJECTILE_SELF_ON_HIT, firer, target, Angle, hit_limb)
|
||||
var/turf/target_loca = get_turf(target)
|
||||
|
||||
var/hitx
|
||||
@@ -216,10 +248,13 @@
|
||||
new impact_effect_type(target_loca, hitx, hity)
|
||||
|
||||
var/organ_hit_text = ""
|
||||
var/limb_hit = L.check_limb_hit(def_zone)//to get the correct message info.
|
||||
var/limb_hit = hit_limb
|
||||
if(limb_hit)
|
||||
organ_hit_text = " in \the [parse_zone(limb_hit)]"
|
||||
if(suppressed)
|
||||
|
||||
if(suppressed==SUPPRESSED_VERY)
|
||||
playsound(loc, hitsound, 5, TRUE, -1)
|
||||
else if(suppressed)
|
||||
playsound(loc, hitsound, 5, 1, -1)
|
||||
to_chat(L, "<span class='userdanger'>You're shot by \a [src][organ_hit_text]!</span>")
|
||||
else
|
||||
@@ -250,7 +285,23 @@
|
||||
return 50 //if the projectile doesn't do damage, play its hitsound at 50% volume
|
||||
|
||||
/obj/item/projectile/proc/on_ricochet(atom/A)
|
||||
return
|
||||
if(!ricochet_auto_aim_angle || !ricochet_auto_aim_range)
|
||||
return
|
||||
|
||||
var/mob/living/unlucky_sob
|
||||
var/best_angle = ricochet_auto_aim_angle
|
||||
if(firer && HAS_TRAIT(firer, TRAIT_NICE_SHOT))
|
||||
best_angle += NICE_SHOT_RICOCHET_BONUS
|
||||
for(var/mob/living/L in range(ricochet_auto_aim_range, src.loc))
|
||||
if(L.stat == DEAD || !isInSight(src, L))
|
||||
continue
|
||||
var/our_angle = abs(closer_angle_difference(Angle, get_projectile_angle(src.loc, L.loc)))
|
||||
if(our_angle < best_angle)
|
||||
best_angle = our_angle
|
||||
unlucky_sob = L
|
||||
|
||||
if(unlucky_sob)
|
||||
setAngle(get_projectile_angle(src, unlucky_sob.loc))
|
||||
|
||||
/obj/item/projectile/proc/store_hitscan_collision(datum/point/pcache)
|
||||
beam_segments[beam_index] = pcache
|
||||
@@ -258,21 +309,22 @@
|
||||
beam_segments[beam_index] = null
|
||||
|
||||
/obj/item/projectile/Bump(atom/A)
|
||||
if(!trajectory)
|
||||
return
|
||||
var/turf/T = get_turf(A)
|
||||
if(trajectory && check_ricochet(A) && check_ricochet_flag(A) && ricochets < ricochets_max)
|
||||
if(check_ricochet(A) && A.handle_ricochet(src)) //if you can ricochet, attempt to ricochet off the object
|
||||
on_ricochet(A) //if allowed, use autoaim to ricochet into someone, otherwise default to ricocheting off the object from above
|
||||
var/datum/point/pcache = trajectory.copy_to()
|
||||
ricochets++
|
||||
if(A.handle_ricochet(src))
|
||||
on_ricochet(A)
|
||||
ignore_source_check = TRUE
|
||||
decayedRange = max(0, decayedRange - reflect_range_decrease)
|
||||
range = decayedRange
|
||||
if(hitscan)
|
||||
store_hitscan_collision(pcache)
|
||||
return TRUE
|
||||
if(hitscan)
|
||||
store_hitscan_collision(pcache)
|
||||
decayedRange = max(0, decayedRange - reflect_range_decrease)
|
||||
ricochet_chance *= ricochet_decay_chance
|
||||
damage *= ricochet_decay_damage
|
||||
range = decayedRange
|
||||
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.
|
||||
if(check_zone(def_zone) != BODY_ZONE_CHEST)
|
||||
if(def_zone && 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)
|
||||
@@ -344,13 +396,30 @@
|
||||
return T
|
||||
//Returns null if nothing at all was found.
|
||||
|
||||
/obj/item/projectile/proc/check_ricochet()
|
||||
if(prob(ricochet_chance))
|
||||
return TRUE
|
||||
return FALSE
|
||||
/obj/item/projectile/proc/check_ricochet(atom/A)
|
||||
if(ricochets > ricochets_max) //safety thing, we don't care about what the other thing says about this.
|
||||
return FALSE
|
||||
var/them = A.check_projectile_ricochet(src)
|
||||
switch(them)
|
||||
if(PROJECTILE_RICOCHET_PREVENT)
|
||||
return FALSE
|
||||
if(PROJECTILE_RICOCHET_FORCE)
|
||||
return TRUE
|
||||
if(PROJECTILE_RICOCHET_NO)
|
||||
return FALSE
|
||||
if(PROJECTILE_RICOCHET_YES)
|
||||
var/chance = ricochet_chance * A.ricochet_chance_mod
|
||||
if(firer && HAS_TRAIT(firer, TRAIT_NICE_SHOT))
|
||||
chance += NICE_SHOT_RICOCHET_BONUS
|
||||
if(prob(chance))
|
||||
return TRUE
|
||||
else
|
||||
CRASH("Invalid return value for projectile ricochet check from [A].")
|
||||
|
||||
/obj/item/projectile/proc/check_ricochet_flag(atom/A)
|
||||
if(A.flags_1 & CHECK_RICOCHET_1)
|
||||
if((flag in list("energy", "laser")) && (A.flags_ricochet & RICOCHET_SHINY))
|
||||
return TRUE
|
||||
if((flag in list("bomb", "bullet")) && (A.flags_ricochet & RICOCHET_HARD))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -391,6 +460,8 @@
|
||||
/obj/item/projectile/proc/fire(angle, atom/direct_target)
|
||||
if(fired_from)
|
||||
SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_BEFORE_FIRE, src, original) //If no angle needs to resolve it from xo/yo!
|
||||
if(shrapnel_type)
|
||||
AddElement(/datum/element/embed, projectile_payload = shrapnel_type)
|
||||
if(!log_override && firer && original)
|
||||
log_combat(firer, original, "fired at", src, "from [get_area_name(src, TRUE)]")
|
||||
if(direct_target)
|
||||
@@ -431,6 +502,7 @@
|
||||
|
||||
/obj/item/projectile/proc/setAngle(new_angle, hitscan_store_segment = TRUE) //wrapper for overrides.
|
||||
Angle = new_angle
|
||||
pixel_move_interrupted = TRUE
|
||||
if(!nondirectional_sprite)
|
||||
var/matrix/M = new
|
||||
M.Turn(Angle)
|
||||
@@ -457,6 +529,7 @@
|
||||
trajectory.initialize_location(target.x, target.y, target.z, 0, 0)
|
||||
if(hitscan)
|
||||
record_hitscan_start(RETURN_PRECISE_POINT(src))
|
||||
pixel_move_interrupted = TRUE
|
||||
if(zc)
|
||||
after_z_change(old, target)
|
||||
|
||||
@@ -505,7 +578,7 @@
|
||||
* The proc to make the projectile go, using a simulated pixel movement line trace.
|
||||
* Note: deciseconds_equivalent is currently only used for homing, times is the number of times to move pixel_increment_amount.
|
||||
* Trajectory multiplier directly modifies the factor of pixel_increment_amount to go per time.
|
||||
* It's complicated, so probably just don'ot mess with this unless you know what you're doing.
|
||||
* It's complicated, so probably just don't mess with this unless you know what you're doing.
|
||||
*/
|
||||
/obj/item/projectile/proc/pixel_move(times, hitscanning = FALSE, deciseconds_equivalent = world.tick_lag, trajectory_multiplier = 1, allow_animation = TRUE)
|
||||
if(!loc || !trajectory)
|
||||
@@ -515,6 +588,7 @@
|
||||
M.Turn(Angle)
|
||||
transform = M
|
||||
var/forcemoved = FALSE
|
||||
pixel_move_interrupted = FALSE // reset that
|
||||
var/turf/oldloc = loc
|
||||
var/old_px = pixel_x
|
||||
var/old_py = pixel_y
|
||||
@@ -548,9 +622,11 @@
|
||||
var/safety = CEILING(pixel_increment_amount / world.icon_size, 1) * 2 + 1
|
||||
while(T != loc)
|
||||
if(!--safety)
|
||||
CRASH("Projectile took more than pixel incrememnt speed times 2 to get to its location, this is probably something seriously scuffed going on.")
|
||||
CRASH("[type] took too long (allowed: [CEILING(pixel_increment_amount/world.icon_size,1)*2] moves) to get to its location.")
|
||||
step_towards(src, T)
|
||||
if(QDELETED(src))
|
||||
if(QDELETED(src) || pixel_move_interrupted) // this doesn't take into account with pixel_move_interrupted the portion of the move cut off by any forcemoves, but we're opting to ignore that for now
|
||||
// the reason is the entire point of moving to pixel speed rather than tile speed is smoothness, which will be crucial when pixel movement is done in the future
|
||||
// reverting back to tile is more or less the only way of fixing this issue.
|
||||
return
|
||||
pixels_range_leftover += pixel_increment_amount
|
||||
if(pixels_range_leftover > world.icon_size)
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
/obj/item/projectile/beam/weak
|
||||
damage = 15
|
||||
|
||||
/obj/item/projectile/beam/weak/improvised
|
||||
damage = 10
|
||||
|
||||
/obj/item/projectile/beam/weak/penetrator
|
||||
armour_penetration = 50
|
||||
|
||||
|
||||
@@ -47,4 +47,16 @@
|
||||
if(L.getStaminaLoss() >= 60)
|
||||
L.Sleeping(300)
|
||||
else
|
||||
L.adjustStaminaLoss(25)
|
||||
L.adjustStaminaLoss(25)
|
||||
|
||||
// .32 ACP (Improvised Pistol)
|
||||
|
||||
/obj/item/projectile/bullet/c32acp
|
||||
name = ".32 bullet"
|
||||
damage = 13
|
||||
|
||||
/obj/item/projectile/bullet/r32acp
|
||||
name = ".32 rubber bullet"
|
||||
damage = 3
|
||||
eyeblur = 1
|
||||
stamina = 20
|
||||
|
||||
@@ -15,6 +15,38 @@
|
||||
/obj/item/projectile/bullet/c38
|
||||
name = ".38 bullet"
|
||||
damage = 25
|
||||
ricochets_max = 2
|
||||
ricochet_chance = 50
|
||||
ricochet_auto_aim_angle = 10
|
||||
ricochet_auto_aim_range = 3
|
||||
|
||||
/obj/item/projectile/bullet/c38/match
|
||||
name = ".38 Match bullet"
|
||||
ricochets_max = 4
|
||||
ricochet_chance = 100
|
||||
ricochet_auto_aim_angle = 40
|
||||
ricochet_auto_aim_range = 5
|
||||
ricochet_incidence_leeway = 50
|
||||
ricochet_decay_chance = 1
|
||||
ricochet_decay_damage = 1
|
||||
|
||||
/obj/item/projectile/bullet/c38/match/bouncy
|
||||
name = ".38 Rubber bullet"
|
||||
damage = 10
|
||||
stamina = 30
|
||||
armour_penetration = -30
|
||||
ricochets_max = 6
|
||||
ricochet_incidence_leeway = 70
|
||||
ricochet_chance = 130
|
||||
ricochet_decay_damage = 0.8
|
||||
shrapnel_type = NONE
|
||||
|
||||
/obj/item/projectile/bullet/c38/dumdum
|
||||
name = ".38 DumDum bullet"
|
||||
damage = 15
|
||||
armour_penetration = -30
|
||||
ricochets_max = 0
|
||||
shrapnel_type = /obj/item/shrapnel/bullet/c38/dumdum
|
||||
|
||||
/obj/item/projectile/bullet/c38/rubber
|
||||
name = ".38 rubber bullet"
|
||||
@@ -24,6 +56,7 @@
|
||||
/obj/item/projectile/bullet/c38/trac
|
||||
name = ".38 TRAC bullet"
|
||||
damage = 10
|
||||
ricochets_max = 0
|
||||
|
||||
/obj/item/projectile/bullet/c38/trac/on_hit(atom/target, blocked = FALSE)
|
||||
. = ..()
|
||||
@@ -39,6 +72,7 @@
|
||||
/obj/item/projectile/bullet/c38/hotshot //similar to incendiary bullets, but do not leave a flaming trail
|
||||
name = ".38 Hot Shot bullet"
|
||||
damage = 20
|
||||
ricochets_max = 0
|
||||
|
||||
/obj/item/projectile/bullet/c38/hotshot/on_hit(atom/target, blocked = FALSE)
|
||||
. = ..()
|
||||
@@ -51,6 +85,7 @@
|
||||
name = ".38 Iceblox bullet"
|
||||
damage = 20
|
||||
var/temperature = 100
|
||||
ricochets_max = 0
|
||||
|
||||
/obj/item/projectile/bullet/c38/iceblox/on_hit(atom/target, blocked = FALSE)
|
||||
. = ..()
|
||||
@@ -68,4 +103,14 @@
|
||||
/obj/item/projectile/bullet/a357/ap
|
||||
name = ".357 armor-piercing bullet"
|
||||
damage = 45
|
||||
armour_penetration = 45
|
||||
armour_penetration = 45
|
||||
|
||||
// admin only really, for ocelot memes
|
||||
/obj/item/projectile/bullet/a357/match
|
||||
name = ".357 match bullet"
|
||||
ricochets_max = 5
|
||||
ricochet_chance = 140
|
||||
ricochet_auto_aim_angle = 50
|
||||
ricochet_auto_aim_range = 6
|
||||
ricochet_incidence_leeway = 80
|
||||
ricochet_decay_chance = 1
|
||||
@@ -112,3 +112,8 @@
|
||||
/obj/item/projectile/bullet/seed
|
||||
damage = 4
|
||||
stamina = 1
|
||||
|
||||
/obj/item/projectile/bullet/pellet/shotgun_incapacitate
|
||||
name = "incapacitating pellet"
|
||||
damage = 1
|
||||
stamina = 6
|
||||
@@ -121,10 +121,10 @@
|
||||
qdel(src)
|
||||
|
||||
/proc/wabbajack(mob/living/M)
|
||||
if(!istype(M) || M.stat == DEAD || M.notransform || (GODMODE & M.status_flags))
|
||||
if(!istype(M) || M.stat == DEAD || M.mob_transforming || (GODMODE & M.status_flags))
|
||||
return
|
||||
|
||||
M.notransform = TRUE
|
||||
M.mob_transforming = TRUE
|
||||
M.Paralyze(INFINITY)
|
||||
M.icon = null
|
||||
M.cut_overlays()
|
||||
|
||||
Reference in New Issue
Block a user