mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-29 23:17:02 +01:00
SSprojectiles - smoother and saner projectiles (#17127)
* SSprojectiles - smoother and saner projectiles * trailing newline * toki wo tomare * Lower projectile speed back to 2x, reflector fix * Tables stop projectiles properly
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
PROCESSING_SUBSYSTEM_DEF(projectiles)
|
||||
name = "Projectiles"
|
||||
wait = 1
|
||||
flags = SS_NO_INIT|SS_TICKER
|
||||
offline_implications = "Projectiles will no longer move. Shuttle call recommended."
|
||||
|
||||
/// Maximum moves a projectile can make per tick.
|
||||
var/global_max_tick_moves = 10
|
||||
/// How many pixels one iteration can move a projectile.
|
||||
var/global_pixel_speed = 2
|
||||
/// Maximum iterations a move can perform.
|
||||
var/global_iterations_per_move = 16
|
||||
@@ -0,0 +1,242 @@
|
||||
//Designed for things that need precision trajectories like projectiles.
|
||||
//Don't use this for anything that you don't absolutely have to use this with (like projectiles!) because it isn't worth using a datum unless you need accuracy down to decimal places in pixels.
|
||||
|
||||
//You might see places where it does - 16 - 1. This is intentionally 17 instead of 16, because of how byond's tiles work and how not doing it will result in rounding errors like things getting put on the wrong turf.
|
||||
|
||||
#define RETURN_PRECISE_POSITION(A) new /datum/position(A)
|
||||
#define RETURN_PRECISE_POINT(A) new /datum/point_precise(A)
|
||||
|
||||
#define RETURN_POINT_VECTOR(ATOM, ANGLE, SPEED) (new /datum/point_precise/vector(ATOM, null, null, null, null, ANGLE, SPEED))
|
||||
#define RETURN_POINT_VECTOR_INCREMENT(ATOM, ANGLE, SPEED, AMT) (new /datum/point_precise/vector(ATOM, null, null, null, null, ANGLE, SPEED, AMT))
|
||||
|
||||
/proc/point_midpoint_points(datum/point_precise/a, datum/point_precise/b) //Obviously will not support multiZ calculations! Same for the two below.
|
||||
var/datum/point_precise/P = new
|
||||
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
|
||||
|
||||
/proc/pixel_length_between_points(datum/point_precise/a, datum/point_precise/b)
|
||||
return sqrt(((b.x - a.x) ** 2) + ((b.y - a.y) ** 2))
|
||||
|
||||
/proc/angle_between_points(datum/point_precise/a, datum/point_precise/b)
|
||||
return ATAN2((b.y - a.y), (b.x - a.x))
|
||||
|
||||
/// 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
|
||||
var/pixel_x = 0
|
||||
var/pixel_y = 0
|
||||
|
||||
/datum/position/proc/valid()
|
||||
return x && y && z && !isnull(pixel_x) && !isnull(pixel_y)
|
||||
|
||||
/datum/position/New(_x = 0, _y = 0, _z = 0, _pixel_x = 0, _pixel_y = 0) //first argument can also be a /datum/point_precise.
|
||||
if(istype(_x, /datum/point_precise))
|
||||
var/datum/point_precise/P = _x
|
||||
var/turf/T = P.return_turf()
|
||||
_x = T.x
|
||||
_y = T.y
|
||||
_z = T.z
|
||||
_pixel_x = P.return_px()
|
||||
_pixel_y = P.return_py()
|
||||
else if(isatom(_x))
|
||||
var/atom/A = _x
|
||||
_x = A.x
|
||||
_y = A.y
|
||||
_z = A.z
|
||||
_pixel_x = A.pixel_x
|
||||
_pixel_y = A.pixel_y
|
||||
x = _x
|
||||
y = _y
|
||||
z = _z
|
||||
pixel_x = _pixel_x
|
||||
pixel_y = _pixel_y
|
||||
|
||||
/datum/position/proc/return_turf()
|
||||
return locate(x, y, z)
|
||||
|
||||
/datum/position/proc/return_px()
|
||||
return pixel_x
|
||||
|
||||
/datum/position/proc/return_py()
|
||||
return pixel_y
|
||||
|
||||
/datum/position/proc/return_point()
|
||||
return new /datum/point_precise(src)
|
||||
|
||||
/// 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_precise
|
||||
var/x = 0
|
||||
var/y = 0
|
||||
var/z = 0
|
||||
|
||||
/datum/point_precise/proc/valid()
|
||||
return x && y && z
|
||||
|
||||
/datum/point_precise/proc/copy_to(datum/point_precise/p = new)
|
||||
p.x = x
|
||||
p.y = y
|
||||
p.z = z
|
||||
return p
|
||||
|
||||
/// First argument can also be a /datum/position or /atom.
|
||||
/datum/point_precise/New(_x, _y, _z, _pixel_x = 0, _pixel_y = 0)
|
||||
if(istype(_x, /datum/position))
|
||||
var/datum/position/P = _x
|
||||
_x = P.x
|
||||
_y = P.y
|
||||
_z = P.z
|
||||
_pixel_x = P.pixel_x
|
||||
_pixel_y = P.pixel_y
|
||||
else if(istype(_x, /atom))
|
||||
var/atom/A = _x
|
||||
_x = A.x
|
||||
_y = A.y
|
||||
_z = A.z
|
||||
_pixel_x = A.pixel_x
|
||||
_pixel_y = A.pixel_y
|
||||
initialize_location(_x, _y, _z, _pixel_x, _pixel_y)
|
||||
|
||||
/datum/point_precise/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 * 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_precise/proc/debug_out()
|
||||
var/turf/T = return_turf()
|
||||
return "\ref[src] aX [x] aY [y] aZ [z] pX [return_px()] pY [return_py()] mX [T.x] mY [T.y] mZ [T.z]"
|
||||
|
||||
/datum/point_precise/proc/move_atom_to_src(atom/movable/AM)
|
||||
AM.forceMove(return_turf())
|
||||
AM.pixel_x = return_px()
|
||||
AM.pixel_y = return_py()
|
||||
|
||||
/datum/point_precise/proc/return_turf()
|
||||
return locate(CEILING(x / world.icon_size, 1), CEILING(y / world.icon_size, 1), z)
|
||||
|
||||
/datum/point_precise/proc/return_coordinates() //[turf_x, turf_y, z]
|
||||
return list(CEILING(x / world.icon_size, 1), CEILING(y / world.icon_size, 1), z)
|
||||
|
||||
/datum/point_precise/proc/return_position()
|
||||
return new /datum/position(src)
|
||||
|
||||
/datum/point_precise/proc/return_px()
|
||||
return MODULUS(x, world.icon_size) - 16 - 1
|
||||
|
||||
/datum/point_precise/proc/return_py()
|
||||
return MODULUS(y, world.icon_size) - 16 - 1
|
||||
|
||||
/datum/point_precise/vector
|
||||
/// Pixels per iteration
|
||||
var/speed = 32
|
||||
var/iteration = 0
|
||||
var/angle = 0
|
||||
/// 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
|
||||
var/starting_z = 0
|
||||
|
||||
/datum/point_precise/vector/New(_x, _y, _z, _pixel_x = 0, _pixel_y = 0, _angle, _speed, initial_increment = 0)
|
||||
..()
|
||||
initialize_trajectory(_speed, _angle)
|
||||
if(initial_increment)
|
||||
increment(initial_increment)
|
||||
|
||||
/datum/point_precise/vector/initialize_location(tile_x, tile_y, tile_z, p_x = 0, p_y = 0)
|
||||
. = ..()
|
||||
starting_x = x
|
||||
starting_y = y
|
||||
starting_z = z
|
||||
|
||||
/// Same effect as initiliaze_location, but without setting the starting_x/y/z
|
||||
/datum/point_precise/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_precise/vector/copy_to(datum/point_precise/vector/v = new)
|
||||
..(v)
|
||||
v.speed = speed
|
||||
v.iteration = iteration
|
||||
v.angle = angle
|
||||
v.mpx = mpx
|
||||
v.mpy = mpy
|
||||
v.starting_x = starting_x
|
||||
v.starting_y = starting_y
|
||||
v.starting_z = starting_z
|
||||
return v
|
||||
|
||||
/datum/point_precise/vector/proc/initialize_trajectory(pixel_speed, new_angle)
|
||||
if(!isnull(pixel_speed))
|
||||
speed = pixel_speed
|
||||
set_angle(new_angle)
|
||||
|
||||
/// Calculations use "byond angle" where north is 0 instead of 90, and south is 180 instead of 270.
|
||||
/datum/point_precise/vector/proc/set_angle(new_angle)
|
||||
if(isnull(angle))
|
||||
return
|
||||
angle = new_angle
|
||||
update_offsets()
|
||||
|
||||
/datum/point_precise/vector/proc/update_offsets()
|
||||
mpx = sin(angle) * speed
|
||||
mpy = cos(angle) * speed
|
||||
|
||||
/datum/point_precise/vector/proc/set_speed(new_speed)
|
||||
if(isnull(new_speed) || speed == new_speed)
|
||||
return
|
||||
speed = new_speed
|
||||
update_offsets()
|
||||
|
||||
/datum/point_precise/vector/proc/increment(multiplier = 1)
|
||||
iteration++
|
||||
x += mpx * (multiplier)
|
||||
y += mpy * (multiplier)
|
||||
|
||||
/datum/point_precise/vector/proc/return_vector_after_increments(amount = 7, multiplier = 1, force_simulate = FALSE)
|
||||
var/datum/point_precise/vector/v = copy_to()
|
||||
if(force_simulate)
|
||||
for(var/i in 1 to amount)
|
||||
v.increment(multiplier)
|
||||
else
|
||||
v.increment(multiplier * amount)
|
||||
return v
|
||||
|
||||
/datum/point_precise/vector/proc/on_z_change()
|
||||
return
|
||||
|
||||
/datum/point_precise/vector/processed //pixel_speed is per decisecond.
|
||||
var/last_process = 0
|
||||
var/last_move = 0
|
||||
var/paused = FALSE
|
||||
|
||||
/datum/point_precise/vector/processed/Destroy()
|
||||
STOP_PROCESSING(SSprojectiles, src)
|
||||
return ..()
|
||||
|
||||
/datum/point_precise/vector/processed/proc/start()
|
||||
last_process = world.time
|
||||
last_move = world.time
|
||||
START_PROCESSING(SSprojectiles, src)
|
||||
|
||||
/datum/point_precise/vector/processed/process()
|
||||
if(paused)
|
||||
last_move += world.time - last_process
|
||||
last_process = world.time
|
||||
return
|
||||
var/needed_time = world.time - last_move
|
||||
last_process = world.time
|
||||
last_move = world.time
|
||||
increment(needed_time / SSprojectiles.wait)
|
||||
@@ -48,6 +48,6 @@
|
||||
if(abs(incidence_s) > 90 && abs(incidence_s) < 270)
|
||||
return FALSE
|
||||
var/new_angle_s = SIMPLIFY_DEGREES(face_angle + incidence_s)
|
||||
P.setAngle(new_angle_s)
|
||||
P.set_angle(new_angle_s)
|
||||
visible_message("<span class='warning'>[P] reflects off [src]!</span>")
|
||||
return TRUE
|
||||
|
||||
@@ -22,16 +22,14 @@
|
||||
new_dir = 0
|
||||
return ..() //Hits as normal, explodes or emps or whatever
|
||||
|
||||
reflect_turf = get_step(loc,new_dir)
|
||||
reflect_turf = get_step(loc, new_dir)
|
||||
|
||||
P.original = reflect_turf
|
||||
P.starting = reflector_turf
|
||||
P.current = reflector_turf
|
||||
P.yo = reflect_turf.y - reflector_turf.y
|
||||
P.xo = reflect_turf.x - reflector_turf.x
|
||||
P.ignore_source_check = TRUE //If shot by a laser, will now hit the mob that fired it
|
||||
var/reflect_angle = dir2angle(new_dir)
|
||||
P.setAngle(reflect_angle)
|
||||
P.set_angle_centered(reflect_angle)
|
||||
P.trajectory.set_location(reflect_turf.x, reflect_turf.y, reflect_turf.z)
|
||||
|
||||
new_dir = 0
|
||||
return -1
|
||||
|
||||
@@ -138,32 +138,26 @@
|
||||
var/atom/movable/mover = caller
|
||||
. = . || mover.checkpass(PASSTABLE)
|
||||
|
||||
//checks if projectile 'P' from turf 'from' can hit whatever is behind the table. Returns 1 if it can, 0 if bullet stops.
|
||||
/**
|
||||
* Determines whether a projectile crossing our turf should be stopped.
|
||||
* Return FALSE to stop the projectile.
|
||||
*
|
||||
* Arguments:
|
||||
* * P - The projectile trying to cross.
|
||||
* * from - Where the projectile is located.
|
||||
*/
|
||||
/obj/structure/table/proc/check_cover(obj/item/projectile/P, turf/from)
|
||||
var/turf/cover = flipped ? get_turf(src) : get_step(loc, get_dir(from, loc))
|
||||
if(get_dist(P.starting, loc) <= 1) //Tables won't help you if people are THIS close
|
||||
return 1
|
||||
if(get_turf(P.original) == cover)
|
||||
var/chance = 20
|
||||
if(ismob(P.original))
|
||||
var/mob/M = P.original
|
||||
if(M.lying)
|
||||
chance += 20 //Lying down lets you catch less bullets
|
||||
if(flipped)
|
||||
if(get_dir(loc, from) == dir) //Flipped tables catch mroe bullets
|
||||
chance += 20
|
||||
else
|
||||
return 1 //But only from one side
|
||||
if(prob(chance))
|
||||
obj_integrity -= P.damage/2
|
||||
if(obj_integrity > 0)
|
||||
visible_message("<span class='warning'>[P] hits \the [src]!</span>")
|
||||
return 0
|
||||
else
|
||||
visible_message("<span class='warning'>[src] breaks down!</span>")
|
||||
deconstruct(FALSE)
|
||||
return 1
|
||||
return 1
|
||||
. = TRUE
|
||||
if(!flipped)
|
||||
return
|
||||
if(get_dist(P.starting, loc) <= 1) // Tables won't help you if people are THIS close
|
||||
return
|
||||
var/proj_dir = get_dir(from, loc)
|
||||
var/block_dir = get_dir(get_step(loc, dir), loc)
|
||||
if(proj_dir != block_dir) // Back/side shots may pass
|
||||
return
|
||||
if(prob(40))
|
||||
return FALSE // Blocked
|
||||
|
||||
/obj/structure/table/CheckExit(atom/movable/O, turf/target)
|
||||
if(istype(O) && O.checkpass(PASSTABLE))
|
||||
|
||||
@@ -139,7 +139,7 @@
|
||||
if(abs(incidence_s) > 90 && abs(incidence_s) < 270)
|
||||
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
|
||||
|
||||
/turf/simulated/wall/dismantle_wall(devastated = FALSE, explode = FALSE)
|
||||
|
||||
@@ -52,7 +52,7 @@ emp_act
|
||||
visible_message("<span class='danger'>[src] deflects the projectile!</span>", "<span class='userdanger'>You deflect the projectile!</span>")
|
||||
if(mind.martial_art.reroute_deflection)
|
||||
P.firer = src
|
||||
P.setAngle(rand(0, 360))
|
||||
P.set_angle(rand(0, 360))
|
||||
return -1
|
||||
else
|
||||
return FALSE
|
||||
|
||||
@@ -63,8 +63,16 @@
|
||||
/// For when you want your projectile to have a chain coming out of the gun
|
||||
var/chain = null
|
||||
|
||||
/// Last world.time the projectile proper moved
|
||||
var/last_projectile_move = 0
|
||||
/// Left over ticks in movement calculation
|
||||
var/time_offset = 0
|
||||
/// The projectile's trajectory
|
||||
var/datum/point_precise/vector/trajectory
|
||||
/// Instructs forceMove to NOT reset our trajectory to the new location!
|
||||
var/trajectory_ignore_forcemove = FALSE
|
||||
|
||||
/obj/item/projectile/New()
|
||||
permutated = list()
|
||||
return ..()
|
||||
|
||||
/obj/item/projectile/proc/Range()
|
||||
@@ -232,83 +240,102 @@
|
||||
/obj/item/projectile/Process_Spacemove(movement_dir = 0)
|
||||
return 1 //Bullets don't drift in space
|
||||
|
||||
/obj/item/projectile/process()
|
||||
if(!loc || !trajectory)
|
||||
return PROCESS_KILL
|
||||
if(paused || !isturf(loc))
|
||||
last_projectile_move = world.time
|
||||
return
|
||||
var/elapsed_time_deciseconds = (world.time - last_projectile_move) + time_offset
|
||||
time_offset = 0
|
||||
var/required_moves = FLOOR(elapsed_time_deciseconds / speed, 1)
|
||||
if(required_moves > SSprojectiles.global_max_tick_moves)
|
||||
var/overrun = required_moves - SSprojectiles.global_max_tick_moves
|
||||
required_moves = SSprojectiles.global_max_tick_moves
|
||||
time_offset += overrun * speed
|
||||
time_offset += MODULUS(elapsed_time_deciseconds, speed)
|
||||
|
||||
for(var/i in 1 to required_moves)
|
||||
pixel_move(1)
|
||||
|
||||
/obj/item/projectile/proc/pixel_move(trajectory_multiplier)
|
||||
if(!loc || !trajectory)
|
||||
return
|
||||
last_projectile_move = world.time
|
||||
// Keep on course
|
||||
var/matrix/M = new
|
||||
M.Turn(Angle)
|
||||
transform = M
|
||||
// Iterate
|
||||
var/forcemoved = FALSE
|
||||
for(var/i in 1 to SSprojectiles.global_iterations_per_move)
|
||||
if(QDELETED(src))
|
||||
return
|
||||
trajectory.increment(trajectory_multiplier)
|
||||
var/turf/T = trajectory.return_turf()
|
||||
if(!istype(T))
|
||||
qdel(src)
|
||||
return
|
||||
if(T.z != loc.z)
|
||||
trajectory_ignore_forcemove = TRUE
|
||||
forceMove(T)
|
||||
trajectory_ignore_forcemove = FALSE
|
||||
pixel_x = trajectory.return_px()
|
||||
pixel_y = trajectory.return_py()
|
||||
forcemoved = TRUE
|
||||
else if(T != loc)
|
||||
step_towards(src, T)
|
||||
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)
|
||||
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)
|
||||
Range()
|
||||
|
||||
/obj/item/projectile/proc/fire(setAngle)
|
||||
set waitfor = FALSE
|
||||
if(setAngle)
|
||||
Angle = setAngle
|
||||
|
||||
while(!QDELETED(src))
|
||||
if(!paused)
|
||||
if((!current || loc == current))
|
||||
current = locate(clamp(x + xo, 1, world.maxx), clamp(y + yo, 1, world.maxy), z)
|
||||
if(isnull(Angle))
|
||||
Angle = round(get_angle(src, current))
|
||||
if(spread)
|
||||
Angle += (rand() - 0.5) * spread
|
||||
var/matrix/M = new
|
||||
M.Turn(Angle)
|
||||
transform = M
|
||||
|
||||
var/Pixel_x = round(sin(Angle) + 16 * sin(Angle) * 2, 1)
|
||||
var/Pixel_y = round(cos(Angle) + 16 * cos(Angle) * 2, 1)
|
||||
var/pixel_x_offset = pixel_x + Pixel_x
|
||||
var/pixel_y_offset = pixel_y + Pixel_y
|
||||
var/new_x = x
|
||||
var/new_y = y
|
||||
|
||||
while(pixel_x_offset > 16)
|
||||
pixel_x_offset -= 32
|
||||
pixel_x -= 32
|
||||
new_x++ // x++
|
||||
while(pixel_x_offset < -16)
|
||||
pixel_x_offset += 32
|
||||
pixel_x += 32
|
||||
new_x--
|
||||
|
||||
while(pixel_y_offset > 16)
|
||||
pixel_y_offset -= 32
|
||||
pixel_y -= 32
|
||||
new_y++
|
||||
while(pixel_y_offset < -16)
|
||||
pixel_y_offset += 32
|
||||
pixel_y += 32
|
||||
new_y--
|
||||
|
||||
speed = round(speed)
|
||||
step_towards(src, locate(new_x, new_y, z))
|
||||
if(QDELETED(src)) // It hit something during the move
|
||||
return
|
||||
if(speed <= 1)
|
||||
pixel_x = pixel_x_offset
|
||||
pixel_y = pixel_y_offset
|
||||
else
|
||||
animate(src, pixel_x = pixel_x_offset, pixel_y = pixel_y_offset, time = max(1, (speed <= 3 ? speed - 1 : speed)))
|
||||
|
||||
if(original && (original.layer >= 2.75 || ismob(original)))
|
||||
if(loc == get_turf(original))
|
||||
if(!(original in permutated))
|
||||
Bump(original, TRUE)
|
||||
Range()
|
||||
sleep(max(1, speed))
|
||||
if(!current || loc == current)
|
||||
current = locate(clamp(x + xo, 1, world.maxx), clamp(y + yo, 1, world.maxy), z)
|
||||
if(isnull(Angle))
|
||||
Angle = round(get_angle(src, current))
|
||||
if(spread)
|
||||
Angle += (rand() - 0.5) * spread
|
||||
// Turn right away
|
||||
var/matrix/M = new
|
||||
M.Turn(Angle)
|
||||
transform = M
|
||||
// Start flying
|
||||
trajectory = new(x, y, z, pixel_x, pixel_y, Angle, SSprojectiles.global_pixel_speed)
|
||||
last_projectile_move = world.time
|
||||
START_PROCESSING(SSprojectiles, src)
|
||||
pixel_move(1, FALSE)
|
||||
|
||||
/obj/item/projectile/proc/reflect_back(atom/source, list/position_modifiers = list(0, 0, 0, 0, 0, -1, 1, -2, 2))
|
||||
if(starting)
|
||||
var/new_x = starting.x + pick(position_modifiers)
|
||||
var/new_y = starting.y + pick(position_modifiers)
|
||||
var/turf/curloc = get_turf(source)
|
||||
if(!starting)
|
||||
return
|
||||
var/new_x = starting.x + pick(position_modifiers)
|
||||
var/new_y = starting.y + pick(position_modifiers)
|
||||
var/turf/curloc = get_turf(source)
|
||||
if(!curloc)
|
||||
return
|
||||
|
||||
if(ismob(source))
|
||||
firer = source // The reflecting mob will be the new firer
|
||||
else
|
||||
firer = null // Reflected by something other than a mob so firer will be null
|
||||
if(ismob(source))
|
||||
firer = source // The reflecting mob will be the new firer
|
||||
else
|
||||
firer = null // Reflected by something other than a mob so firer will be null
|
||||
|
||||
// redirect the projectile
|
||||
original = locate(new_x, new_y, z)
|
||||
starting = curloc
|
||||
current = curloc
|
||||
yo = new_y - curloc.y
|
||||
xo = new_x - curloc.x
|
||||
Angle = null // Will be calculated in fire()
|
||||
// redirect the projectile
|
||||
original = locate(new_x, new_y, z)
|
||||
starting = curloc
|
||||
current = curloc
|
||||
yo = new_y - curloc.y
|
||||
xo = new_x - curloc.x
|
||||
set_angle(get_angle(curloc, original))
|
||||
|
||||
/obj/item/projectile/Crossed(atom/movable/AM, oldloc) //A mob moving on a tile with a projectile is hit by it.
|
||||
..()
|
||||
@@ -316,6 +343,7 @@
|
||||
Bump(AM, 1)
|
||||
|
||||
/obj/item/projectile/Destroy()
|
||||
STOP_PROCESSING(SSprojectiles, src)
|
||||
ammo_casing = null
|
||||
return ..()
|
||||
|
||||
@@ -337,9 +365,22 @@
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/projectile/proc/setAngle(new_angle) //wrapper for overrides.
|
||||
/obj/item/projectile/set_angle(new_angle)
|
||||
..()
|
||||
Angle = new_angle
|
||||
return TRUE
|
||||
trajectory.set_angle(new_angle)
|
||||
|
||||
/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
|
||||
|
||||
/obj/item/projectile/experience_pressure_difference()
|
||||
return
|
||||
|
||||
/obj/item/projectile/forceMove(atom/target)
|
||||
. = ..()
|
||||
if(QDELETED(src)) // we coulda bumped something
|
||||
return
|
||||
if(trajectory && !trajectory_ignore_forcemove && isturf(target))
|
||||
trajectory.initialize_location(target.x, target.y, target.z, 0, 0)
|
||||
|
||||
@@ -279,6 +279,7 @@
|
||||
#include "code\controllers\subsystem\processing\instruments.dm"
|
||||
#include "code\controllers\subsystem\processing\obj.dm"
|
||||
#include "code\controllers\subsystem\processing\processing.dm"
|
||||
#include "code\controllers\subsystem\processing\projectiles.dm"
|
||||
#include "code\controllers\subsystem\tickets\mentor_tickets.dm"
|
||||
#include "code\controllers\subsystem\tickets\tickets.dm"
|
||||
#include "code\datums\action.dm"
|
||||
@@ -307,6 +308,7 @@
|
||||
#include "code\datums\mutable_appearance.dm"
|
||||
#include "code\datums\periodic_news.dm"
|
||||
#include "code\datums\pipe_datums.dm"
|
||||
#include "code\datums\position_point_vector.dm"
|
||||
#include "code\datums\progressbar.dm"
|
||||
#include "code\datums\radiation_wave.dm"
|
||||
#include "code\datums\radio.dm"
|
||||
|
||||
Reference in New Issue
Block a user