mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-29 16:18:01 +01:00
Fixes reflection of hitscan beams against tiles (#56881)
Co-authored-by: Ranged <nickvanderkroon@gmail.com>
This commit is contained in:
@@ -113,7 +113,7 @@
|
||||
A.visible_message("<span class='danger'>[A] effortlessly swats the projectile aside! They can block bullets with their bare hands!</span>", "<span class='userdanger'>You deflect the projectile!</span>")
|
||||
playsound(get_turf(A), pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, TRUE)
|
||||
P.firer = A
|
||||
P.setAngle(rand(0, 360))//SHING
|
||||
P.set_angle(rand(0, 360))//SHING
|
||||
return BULLET_ACT_FORCE_PIERCE
|
||||
return BULLET_ACT_HIT
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
|
||||
/proc/point_midpoint_points(datum/point/a, datum/point/b) //Obviously will not support multiZ calculations! Same for the two below.
|
||||
var/datum/point/P = new
|
||||
P.x = a.x + (b.x - a.x) / 2
|
||||
P.y = a.y + (b.y - a.y) / 2
|
||||
P.x = a.x + (b.x - a.x) * 0.5
|
||||
P.y = a.y + (b.y - a.y) * 0.5
|
||||
P.z = a.z
|
||||
return P
|
||||
|
||||
@@ -22,7 +22,8 @@
|
||||
/proc/angle_between_points(datum/point/a, datum/point/b)
|
||||
return ATAN2((b.y - a.y), (b.x - a.x))
|
||||
|
||||
/datum/position //For positions with map x/y/z and pixel x/y so you don't have to return lists. Could use addition/subtraction in the future I guess.
|
||||
/// For positions with map x/y/z and pixel x/y so you don't have to return lists. Could use addition/subtraction in the future I guess.
|
||||
/datum/position
|
||||
var/x = 0
|
||||
var/y = 0
|
||||
var/z = 0
|
||||
@@ -66,7 +67,8 @@
|
||||
/datum/position/proc/return_point()
|
||||
return new /datum/point(src)
|
||||
|
||||
/datum/point //A precise point on the map in absolute pixel locations based on world.icon_size. Pixels are FROM THE EDGE OF THE MAP!
|
||||
/// A precise point on the map in absolute pixel locations based on world.icon_size. Pixels are FROM THE EDGE OF THE MAP!
|
||||
/datum/point
|
||||
var/x = 0
|
||||
var/y = 0
|
||||
var/z = 0
|
||||
@@ -80,7 +82,8 @@
|
||||
p.z = z
|
||||
return p
|
||||
|
||||
/datum/point/New(_x, _y, _z, _pixel_x = 0, _pixel_y = 0) //first argument can also be a /datum/position or /atom.
|
||||
/// First argument can also be a /datum/position or /atom.
|
||||
/datum/point/New(_x, _y, _z, _pixel_x = 0, _pixel_y = 0)
|
||||
if(istype(_x, /datum/position))
|
||||
var/datum/position/P = _x
|
||||
_x = P.x
|
||||
@@ -99,9 +102,9 @@
|
||||
|
||||
/datum/point/proc/initialize_location(tile_x, tile_y, tile_z, p_x = 0, p_y = 0)
|
||||
if(!isnull(tile_x))
|
||||
x = ((tile_x - 1) * world.icon_size) + world.icon_size / 2 + p_x + 1
|
||||
x = ((tile_x - 1) * world.icon_size) + world.icon_size * 0.5 + p_x + 1
|
||||
if(!isnull(tile_y))
|
||||
y = ((tile_y - 1) * world.icon_size) + world.icon_size / 2 + p_y + 1
|
||||
y = ((tile_y - 1) * world.icon_size) + world.icon_size * 0.5 + p_y + 1
|
||||
if(!isnull(tile_z))
|
||||
z = tile_z
|
||||
|
||||
@@ -130,10 +133,13 @@
|
||||
return MODULUS(y, world.icon_size) - 16 - 1
|
||||
|
||||
/datum/point/vector
|
||||
var/speed = 32 //pixels per iteration
|
||||
/// Pixels per iteration
|
||||
var/speed = 32
|
||||
var/iteration = 0
|
||||
var/angle = 0
|
||||
var/mpx = 0 //calculated x/y movement amounts to prevent having to do trig every step.
|
||||
/// Calculated x movement amounts to prevent having to do trig every step.
|
||||
var/mpx = 0
|
||||
/// Calculated y movement amounts to prevent having to do trig every step.
|
||||
var/mpy = 0
|
||||
var/starting_x = 0 //just like before, pixels from EDGE of map! This is set in initialize_location().
|
||||
var/starting_y = 0
|
||||
@@ -151,6 +157,15 @@
|
||||
starting_y = y
|
||||
starting_z = z
|
||||
|
||||
/// Same effect as initiliaze_location, but without setting the starting_x/y/z
|
||||
/datum/point/vector/proc/set_location(tile_x, tile_y, tile_z, p_x = 0, p_y = 0)
|
||||
if(!isnull(tile_x))
|
||||
x = ((tile_x - 1) * world.icon_size) + world.icon_size * 0.5 + p_x + 1
|
||||
if(!isnull(tile_y))
|
||||
y = ((tile_y - 1) * world.icon_size) + world.icon_size * 0.5 + p_y + 1
|
||||
if(!isnull(tile_z))
|
||||
z = tile_z
|
||||
|
||||
/datum/point/vector/copy_to(datum/point/vector/v = new)
|
||||
..(v)
|
||||
v.speed = speed
|
||||
@@ -168,7 +183,8 @@
|
||||
speed = pixel_speed
|
||||
set_angle(new_angle)
|
||||
|
||||
/datum/point/vector/proc/set_angle(new_angle) //calculations use "byond angle" where north is 0 instead of 90, and south is 180 instead of 270.
|
||||
/// Calculations use "byond angle" where north is 0 instead of 90, and south is 180 instead of 270.
|
||||
/datum/point/vector/proc/set_angle(new_angle)
|
||||
if(isnull(angle))
|
||||
return
|
||||
angle = new_angle
|
||||
|
||||
+1
-1
@@ -303,7 +303,7 @@
|
||||
if((a_incidence_s < 90 && a_incidence_s < 90 - P.ricochet_incidence_leeway) || (a_incidence_s > 270 && a_incidence_s -270 > P.ricochet_incidence_leeway))
|
||||
return FALSE
|
||||
var/new_angle_s = SIMPLIFY_DEGREES(face_angle + incidence_s)
|
||||
P.setAngle(new_angle_s)
|
||||
P.set_angle(new_angle_s)
|
||||
return TRUE
|
||||
|
||||
///Can the mover object pass this atom, while heading for the target turf
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
add_overlay(deflector_overlay)
|
||||
|
||||
if(rotation_angle == -1)
|
||||
setAngle(dir2angle(dir))
|
||||
set_angle(dir2angle(dir))
|
||||
else
|
||||
setAngle(rotation_angle)
|
||||
set_angle(rotation_angle)
|
||||
|
||||
if(admin)
|
||||
can_rotate = FALSE
|
||||
@@ -43,7 +43,7 @@
|
||||
else
|
||||
. += "<span class='notice'>Use screwdriver to unlock the rotation.</span>"
|
||||
|
||||
/obj/structure/reflector/proc/setAngle(new_angle)
|
||||
/obj/structure/reflector/proc/set_angle(new_angle)
|
||||
if(can_rotate)
|
||||
rotation_angle = new_angle
|
||||
if(deflector_overlay)
|
||||
@@ -160,7 +160,7 @@
|
||||
if(!user.canUseTopic(src, BE_CLOSE, NO_DEXTERITY, FALSE, !iscyborg(user)))
|
||||
return
|
||||
if(!isnull(new_angle))
|
||||
setAngle(SIMPLIFY_DEGREES(new_angle))
|
||||
set_angle(SIMPLIFY_DEGREES(new_angle))
|
||||
return TRUE
|
||||
|
||||
/obj/structure/reflector/AltClick(mob/user)
|
||||
@@ -195,7 +195,7 @@
|
||||
if(abs(incidence) > 90 && abs(incidence) < 270)
|
||||
return FALSE
|
||||
var/new_angle = SIMPLIFY_DEGREES(rotation_angle + incidence)
|
||||
P.setAngle(new_angle)
|
||||
P.set_angle_centered(new_angle)
|
||||
return ..()
|
||||
|
||||
//DOUBLE
|
||||
@@ -219,7 +219,7 @@
|
||||
/obj/structure/reflector/double/auto_reflect(obj/projectile/P, pdir, turf/ploc, pangle)
|
||||
var/incidence = GET_ANGLE_OF_INCIDENCE(rotation_angle, (P.Angle + 180))
|
||||
var/new_angle = SIMPLIFY_DEGREES(rotation_angle + incidence)
|
||||
P.setAngle(new_angle)
|
||||
P.set_angle_centered(new_angle)
|
||||
return ..()
|
||||
|
||||
//BOX
|
||||
@@ -241,7 +241,7 @@
|
||||
anchored = TRUE
|
||||
|
||||
/obj/structure/reflector/box/auto_reflect(obj/projectile/P)
|
||||
P.setAngle(rotation_angle)
|
||||
P.set_angle_centered(rotation_angle)
|
||||
return ..()
|
||||
|
||||
/obj/structure/reflector/ex_act()
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
var/new_angle_s = P.Angle + rand(120,240)
|
||||
while(new_angle_s > 180) // Translate to regular projectile degrees
|
||||
new_angle_s -= 360
|
||||
P.setAngle(new_angle_s)
|
||||
P.set_angle(new_angle_s)
|
||||
|
||||
return BULLET_ACT_FORCE_PIERCE // complete projectile permutation
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@
|
||||
var/new_angle_s = P.Angle + rand(120,240)
|
||||
while(new_angle_s > 180) // Translate to regular projectile degrees
|
||||
new_angle_s -= 360
|
||||
P.setAngle(new_angle_s)
|
||||
P.set_angle(new_angle_s)
|
||||
|
||||
return BULLET_ACT_FORCE_PIERCE // complete projectile permutation
|
||||
|
||||
|
||||
@@ -317,11 +317,11 @@
|
||||
unlucky_sob = L
|
||||
|
||||
if(unlucky_sob)
|
||||
setAngle(Get_Angle(src, unlucky_sob.loc))
|
||||
set_angle(Get_Angle(src, unlucky_sob.loc))
|
||||
|
||||
/obj/projectile/proc/store_hitscan_collision(datum/point/pcache)
|
||||
beam_segments[beam_index] = pcache
|
||||
beam_index = pcache
|
||||
/obj/projectile/proc/store_hitscan_collision(datum/point/point_cache)
|
||||
beam_segments[beam_index] = point_cache
|
||||
beam_index = point_cache
|
||||
beam_segments[beam_index] = null
|
||||
|
||||
/obj/projectile/Bump(atom/A)
|
||||
@@ -347,7 +347,7 @@
|
||||
return FALSE
|
||||
if(impacted[A]) // NEVER doublehit
|
||||
return FALSE
|
||||
var/datum/point/pcache = trajectory.copy_to()
|
||||
var/datum/point/point_cache = trajectory.copy_to()
|
||||
var/turf/T = get_turf(A)
|
||||
if(ricochets < ricochets_max && check_ricochet_flag(A) && check_ricochet(A))
|
||||
ricochets++
|
||||
@@ -360,7 +360,7 @@
|
||||
damage *= ricochet_decay_damage
|
||||
range = decayedRange
|
||||
if(hitscan)
|
||||
store_hitscan_collision(pcache)
|
||||
store_hitscan_collision(point_cache)
|
||||
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.
|
||||
@@ -663,9 +663,9 @@
|
||||
if(QDELETED(src))
|
||||
return
|
||||
if(isnum(angle))
|
||||
setAngle(angle)
|
||||
set_angle(angle)
|
||||
if(spread)
|
||||
setAngle(Angle + ((rand() - 0.5) * spread))
|
||||
set_angle(Angle + ((rand() - 0.5) * spread))
|
||||
var/turf/starting = get_turf(src)
|
||||
if(isnull(Angle)) //Try to resolve through offsets if there's no angle set.
|
||||
if(isnull(xo) || isnull(yo))
|
||||
@@ -673,12 +673,12 @@
|
||||
qdel(src)
|
||||
return
|
||||
var/turf/target = locate(clamp(starting + xo, 1, world.maxx), clamp(starting + yo, 1, world.maxy), starting.z)
|
||||
setAngle(Get_Angle(src, target))
|
||||
set_angle(Get_Angle(src, target))
|
||||
original_angle = Angle
|
||||
if(!nondirectional_sprite)
|
||||
var/matrix/M = new
|
||||
M.Turn(Angle)
|
||||
transform = M
|
||||
var/matrix/matrix = new
|
||||
matrix.Turn(Angle)
|
||||
transform = matrix
|
||||
trajectory_ignore_forcemove = TRUE
|
||||
forceMove(starting)
|
||||
trajectory_ignore_forcemove = FALSE
|
||||
@@ -692,23 +692,43 @@
|
||||
START_PROCESSING(SSprojectiles, src)
|
||||
pixel_move(1, FALSE) //move it now!
|
||||
|
||||
/obj/projectile/proc/setAngle(new_angle) //wrapper for overrides.
|
||||
/obj/projectile/proc/set_angle(new_angle) //wrapper for overrides.
|
||||
Angle = new_angle
|
||||
if(!nondirectional_sprite)
|
||||
var/matrix/M = new
|
||||
M.Turn(Angle)
|
||||
transform = M
|
||||
var/matrix/matrix = new
|
||||
matrix.Turn(Angle)
|
||||
transform = matrix
|
||||
if(trajectory)
|
||||
trajectory.set_angle(new_angle)
|
||||
if(fired && hitscan && isloc(loc) && (loc != last_angle_set_hitscan_store))
|
||||
last_angle_set_hitscan_store = loc
|
||||
var/datum/point/pcache = new (src)
|
||||
var/list/coordinates = trajectory.return_coordinates()
|
||||
pcache.initialize_location(coordinates[1], coordinates[2], coordinates[3]) // Take the center of the hitscan collision tile, so it looks good on reflector boxes and the like
|
||||
trajectory.initialize_location(coordinates[1], coordinates[2], coordinates[3]) // Sets the trajectory to it as well, to prevent a strange visual bug
|
||||
store_hitscan_collision(pcache)
|
||||
var/datum/point/point_cache = new (src)
|
||||
point_cache = trajectory.copy_to()
|
||||
store_hitscan_collision(point_cache)
|
||||
return TRUE
|
||||
|
||||
/// Same as set_angle, but the reflection continues from the center of the object that reflects it instead of the side
|
||||
/obj/projectile/proc/set_angle_centered(new_angle)
|
||||
Angle = new_angle
|
||||
if(!nondirectional_sprite)
|
||||
var/matrix/matrix = new
|
||||
matrix.Turn(Angle)
|
||||
transform = matrix
|
||||
if(trajectory)
|
||||
trajectory.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(fired && hitscan && isloc(loc) && (loc != last_angle_set_hitscan_store)) // Handles hitscan projectiles
|
||||
last_angle_set_hitscan_store = loc
|
||||
var/datum/point/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/projectile/forceMove(atom/target)
|
||||
if(!isloc(target) || !isloc(loc) || !z)
|
||||
return ..()
|
||||
@@ -735,7 +755,7 @@
|
||||
/obj/projectile/vv_edit_var(var_name, var_value)
|
||||
switch(var_name)
|
||||
if(NAMEOF(src, Angle))
|
||||
setAngle(var_value)
|
||||
set_angle(var_value)
|
||||
return TRUE
|
||||
else
|
||||
return ..()
|
||||
@@ -746,10 +766,10 @@
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/projectile/proc/record_hitscan_start(datum/point/pcache)
|
||||
if(pcache)
|
||||
/obj/projectile/proc/record_hitscan_start(datum/point/point_cache)
|
||||
if(point_cache)
|
||||
beam_segments = list()
|
||||
beam_index = pcache
|
||||
beam_index = point_cache
|
||||
beam_segments[beam_index] = null //record start.
|
||||
|
||||
/obj/projectile/proc/process_hitscan()
|
||||
@@ -772,9 +792,9 @@
|
||||
return
|
||||
last_projectile_move = world.time
|
||||
if(!nondirectional_sprite && !hitscanning)
|
||||
var/matrix/M = new
|
||||
M.Turn(Angle)
|
||||
transform = M
|
||||
var/matrix/matrix = new
|
||||
matrix.Turn(Angle)
|
||||
transform = matrix
|
||||
if(homing)
|
||||
process_homing()
|
||||
var/forcemoved = FALSE
|
||||
@@ -814,7 +834,7 @@
|
||||
PT.x += clamp(homing_offset_x, 1, world.maxx)
|
||||
PT.y += clamp(homing_offset_y, 1, world.maxy)
|
||||
var/angle = closer_angle_difference(Angle, angle_between_points(RETURN_PRECISE_POINT(src), PT))
|
||||
setAngle(Angle + clamp(angle, -homing_turn_speed, homing_turn_speed))
|
||||
set_angle(Angle + clamp(angle, -homing_turn_speed, homing_turn_speed))
|
||||
|
||||
/obj/projectile/proc/set_homing_target(atom/A)
|
||||
if(!A || (!isturf(A) && !isturf(A.loc)))
|
||||
@@ -840,18 +860,18 @@
|
||||
if(targloc || !params)
|
||||
yo = targloc.y - curloc.y
|
||||
xo = targloc.x - curloc.x
|
||||
setAngle(Get_Angle(src, targloc) + spread)
|
||||
set_angle(Get_Angle(src, targloc) + spread)
|
||||
|
||||
if(isliving(source) && params)
|
||||
var/list/calculated = calculate_projectile_angle_and_pixel_offsets(source, params)
|
||||
p_x = calculated[2]
|
||||
p_y = calculated[3]
|
||||
|
||||
setAngle(calculated[1] + spread)
|
||||
set_angle(calculated[1] + spread)
|
||||
else if(targloc)
|
||||
yo = targloc.y - curloc.y
|
||||
xo = targloc.x - curloc.x
|
||||
setAngle(Get_Angle(src, targloc) + spread)
|
||||
set_angle(Get_Angle(src, targloc) + spread)
|
||||
else
|
||||
stack_trace("WARNING: Projectile [type] fired without either mouse parameters, or a target atom to aim at!")
|
||||
qdel(src)
|
||||
@@ -902,8 +922,8 @@
|
||||
|
||||
/obj/projectile/proc/finalize_hitscan_and_generate_tracers(impacting = TRUE)
|
||||
if(trajectory && beam_index)
|
||||
var/datum/point/pcache = trajectory.copy_to()
|
||||
beam_segments[beam_index] = pcache
|
||||
var/datum/point/point_cache = trajectory.copy_to()
|
||||
beam_segments[beam_index] = point_cache
|
||||
generate_hitscan_tracers(null, null, impacting)
|
||||
|
||||
/obj/projectile/proc/generate_hitscan_tracers(cleanup = TRUE, duration = 3, impacting = TRUE)
|
||||
@@ -917,9 +937,9 @@
|
||||
var/datum/point/p = beam_segments[1]
|
||||
var/atom/movable/thing = new muzzle_type
|
||||
p.move_atom_to_src(thing)
|
||||
var/matrix/M = new
|
||||
M.Turn(original_angle)
|
||||
thing.transform = M
|
||||
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)
|
||||
@@ -927,9 +947,9 @@
|
||||
var/datum/point/p = beam_segments[beam_segments[beam_segments.len]]
|
||||
var/atom/movable/thing = new impact_type
|
||||
p.move_atom_to_src(thing)
|
||||
var/matrix/M = new
|
||||
M.Turn(Angle)
|
||||
thing.transform = M
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user