This commit is contained in:
Timothy Teakettle
2020-06-10 23:14:25 +01:00
parent 8ec5672b85
commit 4c55e86da7
74 changed files with 1495 additions and 386 deletions

View File

@@ -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

View File

@@ -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/projectile/bullet/mm712x82_match
/obj/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

View File

@@ -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/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/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/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/projectile/bullet/c38/dumdum

View File

@@ -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

View File

@@ -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

View File

@@ -56,9 +56,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 +147,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 +167,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 +187,10 @@
/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
SEND_SIGNAL(src, COMSIG_PROJECTILE_SELF_ON_HIT, firer, target, Angle)
var/turf/target_loca = get_turf(target)
var/hitx
@@ -219,7 +245,10 @@
var/limb_hit = L.check_limb_hit(def_zone)//to get the correct message info.
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 +279,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_Angle(src.loc, L.loc)))
if(our_angle < best_angle)
best_angle = our_angle
unlucky_sob = L
if(unlucky_sob)
setAngle(Get_Angle(src, unlucky_sob.loc))
/obj/item/projectile/proc/store_hitscan_collision(datum/point/pcache)
beam_segments[beam_index] = pcache
@@ -259,13 +304,15 @@
/obj/item/projectile/Bump(atom/A)
var/turf/T = get_turf(A)
if(trajectory && check_ricochet(A) && check_ricochet_flag(A) && ricochets < ricochets_max)
if(trajectory && ricochets < ricochets_max && check_ricochet_flag(A) && check_ricochet(A))
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)
ricochet_chance *= ricochet_decay_chance
damage *= ricochet_decay_damage
range = decayedRange
if(hitscan)
store_hitscan_collision(pcache)
@@ -344,13 +391,18 @@
return T
//Returns null if nothing at all was found.
/obj/item/projectile/proc/check_ricochet()
if(prob(ricochet_chance))
/obj/projectile/proc/check_ricochet(atom/A)
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
return FALSE
/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 +443,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)

View File

@@ -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/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/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/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/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