mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-25 21:19:00 +01:00
Ports hitscan from TG, adds it to *SELECT* things (#22754)
* this was just going to be a plasma cutter change but no had to make it look good, whats next, ai sat turrets (yes) * ai turret * Coca cola, don't forget the ice. Or the pulse * almost done, pull master than map edit * we ball * ah, chasms. * it's for the best. Fuck should not sleep checker though * hitscan reflection limiting system * Apply suggestions from code review Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com> * c-c-c-changes --------- Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com> Co-authored-by: S34N <12197162+S34NW@users.noreply.github.com>
This commit is contained in:
co-authored by
Henri215
S34N
parent
49c9d6f65a
commit
357c62b6d7
@@ -209,7 +209,7 @@
|
||||
projectile_type = /obj/item/projectile/bullet/meteorshot
|
||||
|
||||
/obj/item/ammo_casing/shotgun/pulseslug
|
||||
name = "pulse slug"
|
||||
name = "proto pulse slug"
|
||||
desc = "A delicate device which can be loaded into a shotgun. The primer acts as a button which triggers the gain medium and fires a powerful \
|
||||
energy blast. While the heat and power drain limit it to one use, it can still allow an operator to engage targets that ballistic ammunition \
|
||||
would have difficulty with."
|
||||
|
||||
@@ -42,14 +42,14 @@
|
||||
fire_sound = 'sound/weapons/lasercannonfire.ogg'
|
||||
|
||||
/obj/item/ammo_casing/energy/laser/pulse
|
||||
projectile_type = /obj/item/projectile/beam/pulse
|
||||
projectile_type = /obj/item/projectile/beam/pulse/hitscan
|
||||
muzzle_flash_color = LIGHT_COLOR_DARKBLUE
|
||||
e_cost = 200
|
||||
select_name = "DESTROY"
|
||||
fire_sound = 'sound/weapons/pulse.ogg'
|
||||
|
||||
/obj/item/ammo_casing/energy/laser/scatter/pulse
|
||||
projectile_type = /obj/item/projectile/beam/pulse
|
||||
projectile_type = /obj/item/projectile/beam/pulse/hitscan
|
||||
e_cost = 200
|
||||
select_name = "ANNIHILATE"
|
||||
fire_sound = 'sound/weapons/pulse.ogg'
|
||||
@@ -286,7 +286,7 @@
|
||||
select_name = "clown"
|
||||
|
||||
/obj/item/ammo_casing/energy/emitter
|
||||
projectile_type = /obj/item/projectile/beam/emitter
|
||||
projectile_type = /obj/item/projectile/beam/emitter/hitscan
|
||||
muzzle_flash_color = LIGHT_COLOR_GREEN
|
||||
fire_sound = 'sound/weapons/emitter.ogg'
|
||||
e_cost = 100
|
||||
|
||||
@@ -417,42 +417,11 @@
|
||||
reset_overloaded()
|
||||
do_sparks(2, 1, src)
|
||||
update_icon()
|
||||
if(prob(25))
|
||||
visible_message("<span class='danger'>[src] vents heated plasma!</span>")
|
||||
var/turf/simulated/T = get_turf(src)
|
||||
if(istype(T))
|
||||
T.atmos_spawn_air(LINDA_SPAWN_TOXINS|LINDA_SPAWN_20C,15)
|
||||
return
|
||||
if(prob(50))
|
||||
var/list/mob_targets = list()
|
||||
for(var/mob/living/M in oview(get_turf(src), 7))
|
||||
mob_targets += M
|
||||
if(length(mob_targets))
|
||||
var/mob/living/target = pick(mob_targets)
|
||||
shootAt(target)
|
||||
visible_message("<span class='danger'>[src] discharges a plasma bolt!</span>")
|
||||
return
|
||||
visible_message("<span class='danger'>[src] vents heated plasma!</span>")
|
||||
var/turf/simulated/T = get_turf(src)
|
||||
if(istype(T))
|
||||
T.atmos_spawn_air(LINDA_SPAWN_HEAT | LINDA_SPAWN_TOXINS|LINDA_SPAWN_20C, 20)
|
||||
|
||||
visible_message("<span class='danger'>[src] discharges a plasma bolt!</span>")
|
||||
var/list/turf_targets = list()
|
||||
for(var/turf/T in orange(get_turf(src), 7))
|
||||
turf_targets += T
|
||||
if(length(turf_targets))
|
||||
var/turf/target = pick(turf_targets)
|
||||
shootAt(target)
|
||||
|
||||
|
||||
/obj/item/gun/energy/plasma_pistol/proc/shootAt(atom/movable/target)
|
||||
var/turf/T = get_turf(src)
|
||||
var/turf/U = get_turf(target)
|
||||
if(!T || !U)
|
||||
return
|
||||
var/obj/item/projectile/energy/charged_plasma/O = new /obj/item/projectile/energy/charged_plasma(T)
|
||||
playsound(get_turf(src), 'sound/weapons/marauder.ogg', 75, 1)
|
||||
O.current = T
|
||||
O.yo = U.y - T.y
|
||||
O.xo = U.x - T.x
|
||||
O.fire()
|
||||
|
||||
/obj/item/gun/energy/bsg
|
||||
name = "\improper B.S.G"
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
return FALSE
|
||||
var/obj/dummy = new(user_turf)
|
||||
dummy.pass_flags |= PASSTABLE | PASSGLASS | PASSGRILLE | PASSFENCE //Grille/Glass so it can be used through common windows
|
||||
for(var/turf/turf in getline(user_turf,target))
|
||||
for(var/turf/turf in get_line(user_turf,target))
|
||||
if(turf.density)
|
||||
qdel(dummy)
|
||||
return FALSE
|
||||
|
||||
@@ -33,6 +33,39 @@
|
||||
icon_state = "heavylaser"
|
||||
damage = 40
|
||||
|
||||
/obj/item/projectile/beam/laser/ai_turret
|
||||
damage = 17.5 //Slight loss in damage because hitscan
|
||||
forcedodge = 1
|
||||
hitscan = TRUE
|
||||
muzzle_type = /obj/effect/projectile/muzzle/laser
|
||||
tracer_type = /obj/effect/projectile/tracer/laser
|
||||
impact_type = /obj/effect/projectile/impact/laser
|
||||
impact_effect_type = null
|
||||
hitscan_light_intensity = 3
|
||||
hitscan_light_range = 0.75
|
||||
hitscan_light_color_override = LIGHT_COLOR_DARKRED
|
||||
muzzle_flash_intensity = 6
|
||||
muzzle_flash_range = 2
|
||||
muzzle_flash_color_override = LIGHT_COLOR_DARKRED
|
||||
impact_light_intensity = 7
|
||||
impact_light_range = 2.5
|
||||
impact_light_color_override = LIGHT_COLOR_DARKRED
|
||||
|
||||
/obj/item/projectile/beam/laser/ai_turret/prehit(atom/target)
|
||||
if(isAI(target))
|
||||
damage = 0 //cheater cheater I don't want AI to die to stupid placement eater
|
||||
nodamage = 1
|
||||
if(isliving(target))
|
||||
forcedodge = 0 //no peircing after hitting a mob to avoid rooms destroying itself. If someone does monkey chair on AI sat though, I swear to god
|
||||
..()
|
||||
|
||||
/obj/item/projectile/beam/laser/ai_turret/heavylaser
|
||||
damage = 35
|
||||
muzzle_type = /obj/effect/projectile/muzzle/heavy_laser
|
||||
tracer_type = /obj/effect/projectile/tracer/heavy_laser
|
||||
impact_type = /obj/effect/projectile/impact/heavy_laser
|
||||
|
||||
|
||||
/obj/item/projectile/beam/practice
|
||||
name = "practice laser"
|
||||
damage = 0
|
||||
@@ -73,12 +106,31 @@
|
||||
impact_effect_type = /obj/effect/temp_visual/impact_effect/blue_laser
|
||||
light_color = LIGHT_COLOR_DARKBLUE
|
||||
|
||||
/obj/item/projectile/beam/pulse/hitscan
|
||||
impact_effect_type = null
|
||||
light_color = null
|
||||
hitscan = TRUE
|
||||
muzzle_type = /obj/effect/projectile/muzzle/pulse
|
||||
tracer_type = /obj/effect/projectile/tracer/pulse
|
||||
impact_type = /obj/effect/projectile/impact/pulse
|
||||
impact_effect_type = null
|
||||
hitscan_light_intensity = 3
|
||||
hitscan_light_range = 0.75
|
||||
hitscan_light_color_override = LIGHT_COLOR_DARKBLUE
|
||||
muzzle_flash_intensity = 6
|
||||
muzzle_flash_range = 2
|
||||
muzzle_flash_color_override = LIGHT_COLOR_DARKBLUE
|
||||
impact_light_intensity = 7
|
||||
impact_light_range = 2.5
|
||||
impact_light_color_override = LIGHT_COLOR_DARKBLUE
|
||||
|
||||
/obj/item/projectile/beam/pulse/on_hit(atom/target, blocked = 0)
|
||||
if(isturf(target) || isstructure(target) || ismachinery(target))
|
||||
target.ex_act(2)
|
||||
..()
|
||||
|
||||
/obj/item/projectile/beam/pulse/shot
|
||||
name = "proto pulse"
|
||||
damage = 40
|
||||
|
||||
/obj/item/projectile/beam/emitter
|
||||
@@ -88,6 +140,22 @@
|
||||
impact_effect_type = /obj/effect/temp_visual/impact_effect/green_laser
|
||||
light_color = LIGHT_COLOR_GREEN
|
||||
|
||||
/obj/item/projectile/beam/emitter/hitscan
|
||||
hitscan = TRUE
|
||||
muzzle_type = /obj/effect/projectile/muzzle/laser/emitter
|
||||
tracer_type = /obj/effect/projectile/tracer/laser/emitter
|
||||
impact_type = /obj/effect/projectile/impact/laser/emitter
|
||||
impact_effect_type = null
|
||||
hitscan_light_intensity = 3
|
||||
hitscan_light_range = 0.75
|
||||
hitscan_light_color_override = LIGHT_COLOR_GREEN
|
||||
muzzle_flash_intensity = 6
|
||||
muzzle_flash_range = 2
|
||||
muzzle_flash_color_override = LIGHT_COLOR_GREEN
|
||||
impact_light_intensity = 7
|
||||
impact_light_range = 2.5
|
||||
impact_light_color_override = LIGHT_COLOR_GREEN
|
||||
|
||||
/obj/item/projectile/beam/emitter/singularity_pull()
|
||||
return //don't want the emitters to miss
|
||||
|
||||
@@ -141,6 +209,23 @@
|
||||
damage = 8
|
||||
icon_state = "scatterlaser"
|
||||
|
||||
/obj/item/projectile/beam/immolator/weak/hitscan
|
||||
color = LIGHT_COLOR_FIRE
|
||||
hitscan = TRUE
|
||||
muzzle_type = /obj/effect/projectile/muzzle/laser
|
||||
tracer_type = /obj/effect/projectile/tracer/laser
|
||||
impact_type = /obj/effect/projectile/impact/laser
|
||||
impact_effect_type = null
|
||||
hitscan_light_intensity = 3
|
||||
hitscan_light_range = 0.75
|
||||
hitscan_light_color_override = LIGHT_COLOR_FIRE
|
||||
muzzle_flash_intensity = 6
|
||||
muzzle_flash_range = 2
|
||||
muzzle_flash_color_override = LIGHT_COLOR_FIRE
|
||||
impact_light_intensity = 7
|
||||
impact_light_range = 2.5
|
||||
impact_light_color_override = LIGHT_COLOR_FIRE
|
||||
|
||||
/obj/item/projectile/beam/immolator/on_hit(atom/target, blocked = 0)
|
||||
. = ..()
|
||||
if(isliving(target))
|
||||
|
||||
@@ -9,7 +9,20 @@
|
||||
|
||||
/obj/item/projectile/magic/death
|
||||
name = "bolt of death"
|
||||
icon_state = "pulse1_bl"
|
||||
icon_state = null
|
||||
hitscan = TRUE
|
||||
muzzle_type = /obj/effect/projectile/muzzle/death
|
||||
tracer_type = /obj/effect/projectile/tracer/death
|
||||
impact_type = /obj/effect/projectile/impact/death
|
||||
hitscan_light_intensity = 3
|
||||
hitscan_light_range = 0.75
|
||||
hitscan_light_color_override = LIGHT_COLOR_PURPLE
|
||||
muzzle_flash_intensity = 6
|
||||
muzzle_flash_range = 2
|
||||
muzzle_flash_color_override = LIGHT_COLOR_PURPLE
|
||||
impact_light_intensity = 7
|
||||
impact_light_range = 2.5
|
||||
impact_light_color_override = LIGHT_COLOR_PURPLE
|
||||
|
||||
/obj/item/projectile/magic/fireball
|
||||
name = "bolt of fireball"
|
||||
|
||||
@@ -240,7 +240,20 @@
|
||||
range = 3
|
||||
dismemberment = 20
|
||||
sharp = TRUE
|
||||
impact_effect_type = /obj/effect/temp_visual/impact_effect/purple_laser
|
||||
hitscan = TRUE
|
||||
muzzle_type = /obj/effect/projectile/muzzle/plasma_cutter
|
||||
tracer_type = /obj/effect/projectile/tracer/plasma_cutter
|
||||
impact_type = /obj/effect/projectile/impact/plasma_cutter
|
||||
impact_effect_type = null
|
||||
hitscan_light_intensity = 3
|
||||
hitscan_light_range = 0.75
|
||||
hitscan_light_color_override = LIGHT_COLOR_CYAN
|
||||
muzzle_flash_intensity = 6
|
||||
muzzle_flash_range = 2
|
||||
muzzle_flash_color_override = LIGHT_COLOR_CYAN
|
||||
impact_light_intensity = 7
|
||||
impact_light_range = 2.5
|
||||
impact_light_color_override = LIGHT_COLOR_CYAN
|
||||
|
||||
/obj/item/projectile/plasma/prehit(atom/target)
|
||||
. = ..()
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/// Is this a hitscan projectile or not, if so move like one
|
||||
#define MOVES_HITSCAN -1
|
||||
/// How many pixels to move the muzzle flash up so your character doesn't look like they're shitting out lasers.
|
||||
#define MUZZLE_EFFECT_PIXEL_INCREMENT 17
|
||||
|
||||
/obj/item/projectile
|
||||
name = "projectile"
|
||||
icon = 'icons/obj/projectiles.dmi'
|
||||
@@ -26,6 +31,7 @@
|
||||
var/p_y = 16 // the pixel location of the tile that the player clicked. Default is the center
|
||||
var/speed = 1 //Amount of deciseconds it takes for projectile to travel
|
||||
var/Angle = null
|
||||
var/original_angle = null //Angle at firing
|
||||
var/spread = 0 //amount (in degrees) of projectile spread
|
||||
animate_movement = 0
|
||||
|
||||
@@ -80,6 +86,32 @@
|
||||
var/shield_buster = FALSE
|
||||
var/forced_accuracy = FALSE
|
||||
|
||||
///Has the projectile been fired?
|
||||
var/has_been_fired = FALSE
|
||||
|
||||
//Hitscan
|
||||
var/hitscan = FALSE //Whether this is hitscan. If it is, speed is basically ignored.
|
||||
var/list/beam_segments //assoc list of datum/point_precise or datum/point_precise/vector, start = end. Used for hitscan effect generation.
|
||||
/// Last turf an angle was changed in for hitscan projectiles.
|
||||
var/turf/last_angle_set_hitscan_store
|
||||
var/datum/point_precise/beam_index
|
||||
var/turf/hitscan_last //last turf touched during hitscanning.
|
||||
var/tracer_type
|
||||
var/muzzle_type
|
||||
var/impact_type
|
||||
|
||||
//Fancy hitscan lighting effects!
|
||||
var/hitscan_light_intensity = 1.5
|
||||
var/hitscan_light_range = 0.75
|
||||
var/hitscan_light_color_override
|
||||
var/muzzle_flash_intensity = 3
|
||||
var/muzzle_flash_range = 1.5
|
||||
var/muzzle_flash_color_override
|
||||
var/impact_light_intensity = 3
|
||||
var/impact_light_range = 2
|
||||
var/impact_light_color_override
|
||||
var/hitscan_duration = 0.3 SECONDS
|
||||
|
||||
/obj/item/projectile/New()
|
||||
return ..()
|
||||
|
||||
@@ -112,7 +144,7 @@
|
||||
hity = target.pixel_y + rand(-8, 8)
|
||||
if(!nodamage && (damage_type == BRUTE || damage_type == BURN) && iswallturf(target_loca) && prob(75))
|
||||
var/turf/simulated/wall/W = target_loca
|
||||
if(impact_effect_type)
|
||||
if(impact_effect_type && !hitscan)
|
||||
new impact_effect_type(target_loca, hitx, hity)
|
||||
|
||||
W.add_dent(WALL_DENT_SHOT, hitx, hity)
|
||||
@@ -120,7 +152,7 @@
|
||||
if(alwayslog)
|
||||
add_attack_logs(firer, target, "Shot with a [type]")
|
||||
if(!isliving(target))
|
||||
if(impact_effect_type)
|
||||
if(impact_effect_type && !hitscan)
|
||||
new impact_effect_type(target_loca, hitx, hity)
|
||||
return 0
|
||||
var/mob/living/L = target
|
||||
@@ -152,7 +184,7 @@
|
||||
M.bloody_hands(H)
|
||||
/* Uncomment when bloody_body stops randomly not transferring blood colour.
|
||||
M.bloody_body(H) */
|
||||
else if(impact_effect_type)
|
||||
else if(impact_effect_type && !hitscan)
|
||||
new impact_effect_type(target_loca, hitx, hity)
|
||||
var/organ_hit_text = ""
|
||||
if(L.has_limbs)
|
||||
@@ -199,11 +231,18 @@
|
||||
else
|
||||
return 50 //if the projectile doesn't do damage, play its hitsound at 50% volume
|
||||
|
||||
/obj/item/projectile/proc/store_hitscan_collision(datum/point_precise/point_cache)
|
||||
beam_segments[beam_index] = point_cache
|
||||
beam_index = point_cache
|
||||
beam_segments[beam_index] = null
|
||||
|
||||
/obj/item/projectile/Bump(atom/A, yes)
|
||||
if(!yes) //prevents double bumps.
|
||||
return
|
||||
|
||||
if(check_ricochet(A) && check_ricochet_flag(A) && ricochets < ricochets_max && is_reflectable(REFLECTABILITY_PHYSICAL))
|
||||
if(hitscan && ricochets_max > 10)
|
||||
ricochets_max = 10 //I do not want a chucklefuck editing this higher, sorry.
|
||||
ricochets++
|
||||
if(A.handle_ricochet(src))
|
||||
on_ricochet(A)
|
||||
@@ -265,7 +304,9 @@
|
||||
return
|
||||
var/elapsed_time_deciseconds = (world.time - last_projectile_move) + time_offset
|
||||
time_offset = 0
|
||||
var/required_moves = FLOOR(elapsed_time_deciseconds / speed, 1)
|
||||
var/required_moves = hitscan ? MOVES_HITSCAN : FLOOR(elapsed_time_deciseconds / speed, 1)
|
||||
if(required_moves == MOVES_HITSCAN)
|
||||
required_moves = SSprojectiles.global_max_tick_moves
|
||||
if(required_moves > SSprojectiles.global_max_tick_moves)
|
||||
var/overrun = required_moves - SSprojectiles.global_max_tick_moves
|
||||
required_moves = SSprojectiles.global_max_tick_moves
|
||||
@@ -275,14 +316,15 @@
|
||||
for(var/i in 1 to required_moves)
|
||||
pixel_move(1)
|
||||
|
||||
/obj/item/projectile/proc/pixel_move(trajectory_multiplier)
|
||||
/obj/item/projectile/proc/pixel_move(trajectory_multiplier, hitscanning = FALSE)
|
||||
if(!loc || !trajectory)
|
||||
return
|
||||
last_projectile_move = world.time
|
||||
// Keep on course
|
||||
var/matrix/M = new
|
||||
M.Turn(Angle)
|
||||
transform = M
|
||||
if(!hitscanning)
|
||||
var/matrix/M = new
|
||||
M.Turn(Angle)
|
||||
transform = M
|
||||
// Iterate
|
||||
var/forcemoved = FALSE
|
||||
for(var/i in 1 to SSprojectiles.global_iterations_per_move)
|
||||
@@ -297,17 +339,20 @@
|
||||
trajectory_ignore_forcemove = TRUE
|
||||
forceMove(T)
|
||||
trajectory_ignore_forcemove = FALSE
|
||||
pixel_x = trajectory.return_px()
|
||||
pixel_y = trajectory.return_py()
|
||||
if(!hitscanning)
|
||||
pixel_x = trajectory.return_px()
|
||||
pixel_y = trajectory.return_py()
|
||||
forcemoved = TRUE
|
||||
hitscan_last = loc
|
||||
else if(T != loc)
|
||||
step_towards(src, T)
|
||||
hitscan_last = loc
|
||||
if(original && (original.layer >= PROJECTILE_HIT_THRESHHOLD_LAYER || ismob(original)))
|
||||
if(loc == get_turf(original) && !(original in permutated))
|
||||
Bump(original, TRUE)
|
||||
if(QDELETED(src)) //deleted on last move
|
||||
return
|
||||
if(!forcemoved)
|
||||
if(!hitscanning && !forcemoved)
|
||||
pixel_x = trajectory.return_px() - trajectory.mpx * trajectory_multiplier * SSprojectiles.global_iterations_per_move
|
||||
pixel_y = trajectory.return_py() - trajectory.mpy * trajectory_multiplier * SSprojectiles.global_iterations_per_move
|
||||
animate(src, pixel_x = trajectory.return_px(), pixel_y = trajectory.return_py(), time = 1, flags = ANIMATION_END_NOW)
|
||||
@@ -320,6 +365,7 @@
|
||||
current = locate(clamp(x + xo, 1, world.maxx), clamp(y + yo, 1, world.maxy), z)
|
||||
if(isnull(Angle))
|
||||
Angle = round(get_angle(src, current))
|
||||
original_angle = Angle
|
||||
if(spread)
|
||||
Angle += (rand() - 0.5) * spread
|
||||
// Turn right away
|
||||
@@ -329,6 +375,9 @@
|
||||
// Start flying
|
||||
trajectory = new(x, y, z, pixel_x, pixel_y, Angle, SSprojectiles.global_pixel_speed)
|
||||
last_projectile_move = world.time
|
||||
has_been_fired = TRUE
|
||||
if(hitscan)
|
||||
process_hitscan()
|
||||
START_PROCESSING(SSprojectiles, src)
|
||||
pixel_move(1, FALSE)
|
||||
|
||||
@@ -358,6 +407,8 @@
|
||||
Bump(AM, 1)
|
||||
|
||||
/obj/item/projectile/Destroy()
|
||||
if(hitscan)
|
||||
finalize_hitscan_and_generate_tracers()
|
||||
STOP_PROCESSING(SSprojectiles, src)
|
||||
ammo_casing = null
|
||||
firer_source_atom = null
|
||||
@@ -386,11 +437,22 @@
|
||||
..()
|
||||
Angle = new_angle
|
||||
trajectory.set_angle(new_angle)
|
||||
if(has_been_fired && hitscan && isloc(loc) && (loc != last_angle_set_hitscan_store))
|
||||
last_angle_set_hitscan_store = loc
|
||||
var/datum/point/point_cache = new (src)
|
||||
point_cache = trajectory.copy_to()
|
||||
store_hitscan_collision(point_cache)
|
||||
|
||||
/obj/item/projectile/proc/set_angle_centered(new_angle)
|
||||
set_angle(new_angle)
|
||||
var/list/coordinates = trajectory.return_coordinates()
|
||||
trajectory.set_location(coordinates[1], coordinates[2], coordinates[3]) // Sets the trajectory to the center of the tile it bounced at
|
||||
if(has_been_fired && hitscan && isloc(loc))// Handles hitscan projectiles
|
||||
last_angle_set_hitscan_store = loc
|
||||
var/datum/point_precise/point_cache = new (src)
|
||||
point_cache.initialize_location(coordinates[1], coordinates[2], coordinates[3]) // Take the center of the hitscan collision tile
|
||||
store_hitscan_collision(point_cache)
|
||||
return TRUE
|
||||
|
||||
/obj/item/projectile/experience_pressure_difference()
|
||||
return
|
||||
@@ -400,7 +462,11 @@
|
||||
if(QDELETED(src)) // we coulda bumped something
|
||||
return
|
||||
if(trajectory && !trajectory_ignore_forcemove && isturf(target))
|
||||
if(hitscan)
|
||||
finalize_hitscan_and_generate_tracers(FALSE)
|
||||
trajectory.initialize_location(target.x, target.y, target.z, 0, 0)
|
||||
if(hitscan)
|
||||
record_hitscan_start(RETURN_PRECISE_POINT(src))
|
||||
|
||||
/obj/item/projectile/proc/is_reflectable(desired_reflectability_level)
|
||||
if(reflectability == REFLECTABILITY_NEVER) //You'd trust coders not to try and override never reflectable things, but heaven help us I do not
|
||||
@@ -408,3 +474,67 @@
|
||||
if(reflectability < desired_reflectability_level)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/projectile/proc/record_hitscan_start(datum/point_precise/point_cache)
|
||||
if(point_cache)
|
||||
beam_segments = list()
|
||||
beam_index = point_cache
|
||||
beam_segments[beam_index] = null //record start.
|
||||
|
||||
/obj/item/projectile/proc/process_hitscan()
|
||||
//Safety here is to make hitscan stop if something goes wrong. Why is it equal to range * 10, when range is the maximum amount of tiles it can go? No clue.
|
||||
var/safety = range * 10
|
||||
record_hitscan_start(RETURN_POINT_VECTOR_INCREMENT(src, Angle, MUZZLE_EFFECT_PIXEL_INCREMENT, 1))
|
||||
while(loc && !QDELETED(src))
|
||||
if(paused)
|
||||
stoplag(1)
|
||||
continue
|
||||
if(safety-- <= 0)
|
||||
if(loc)
|
||||
Bump(loc)
|
||||
if(!QDELETED(src))
|
||||
qdel(src)
|
||||
return //Kill!
|
||||
pixel_move(1, TRUE)
|
||||
|
||||
/obj/item/projectile/proc/finalize_hitscan_and_generate_tracers(impacting = TRUE)
|
||||
if(trajectory && beam_index)
|
||||
var/datum/point_precise/point_cache = trajectory.copy_to()
|
||||
beam_segments[beam_index] = point_cache
|
||||
generate_hitscan_tracers(null, hitscan_duration, impacting)
|
||||
|
||||
/obj/item/projectile/proc/generate_hitscan_tracers(cleanup = TRUE, duration = 3, impacting = TRUE)
|
||||
if(!length(beam_segments))
|
||||
return
|
||||
if(tracer_type)
|
||||
var/tempuid = UID()
|
||||
for(var/datum/point_precise/p in beam_segments)
|
||||
generate_tracer_between_points(p, beam_segments[p], tracer_type, color, duration, hitscan_light_range, hitscan_light_color_override, hitscan_light_intensity, tempuid)
|
||||
if(muzzle_type && duration > 0)
|
||||
var/datum/point_precise/p = beam_segments[1]
|
||||
var/atom/movable/thing = new muzzle_type
|
||||
p.move_atom_to_src(thing)
|
||||
var/matrix/matrix = new
|
||||
matrix.Turn(original_angle)
|
||||
thing.transform = matrix
|
||||
thing.color = color
|
||||
thing.set_light(muzzle_flash_range, muzzle_flash_intensity, muzzle_flash_color_override? muzzle_flash_color_override : color)
|
||||
QDEL_IN(thing, duration)
|
||||
if(impacting && impact_type && duration > 0)
|
||||
var/datum/point_precise/p = beam_segments[beam_segments[beam_segments.len]]
|
||||
var/atom/movable/thing = new impact_type
|
||||
p.move_atom_to_src(thing)
|
||||
var/matrix/matrix = new
|
||||
matrix.Turn(Angle)
|
||||
thing.transform = matrix
|
||||
thing.color = color
|
||||
thing.set_light(impact_light_range, impact_light_intensity, impact_light_color_override? impact_light_color_override : color)
|
||||
QDEL_IN(thing, duration)
|
||||
if(cleanup)
|
||||
cleanup_beam_segments()
|
||||
|
||||
/obj/item/projectile/proc/cleanup_beam_segments()
|
||||
QDEL_LIST_ASSOC(beam_segments)
|
||||
|
||||
#undef MOVES_HITSCAN
|
||||
#undef MUZZLE_EFFECT_PIXEL_INCREMENT
|
||||
|
||||
Reference in New Issue
Block a user