mirror of
https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13.git
synced 2025-12-10 01:49:19 +00:00
482 lines
13 KiB
Plaintext
482 lines
13 KiB
Plaintext
<<<<<<< HEAD
|
|
//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.
|
|
|
|
#define RETURN_PRECISE_POSITION(A) new /datum/position(A)
|
|
#define RETURN_PRECISE_POINT(A) new /datum/point(A)
|
|
|
|
/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.
|
|
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.
|
|
if(istype(_x, /datum/point))
|
|
var/datum/point/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(src)
|
|
|
|
/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 = round(a.x + (b.x - a.x) / 2, 1)
|
|
P.y = round(a.y + (b.y - a.y) / 2, 1)
|
|
P.z = a.z
|
|
return P
|
|
|
|
/proc/pixel_length_between_points(datum/point/a, datum/point/b)
|
|
return sqrt(((b.x - a.x) ** 2) + ((b.y - a.y) ** 2))
|
|
|
|
/proc/angle_between_points(datum/point/a, datum/point/b)
|
|
return ATAN2((b.y - a.y), (b.x - a.x))
|
|
|
|
/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!
|
|
var/x = 0
|
|
var/y = 0
|
|
var/z = 0
|
|
|
|
/datum/point/proc/valid()
|
|
return x && y && z
|
|
|
|
/datum/point/proc/copy_to(datum/point/p = new)
|
|
p.x = x
|
|
p.y = y
|
|
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.
|
|
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/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
|
|
if(!isnull(tile_y))
|
|
y = ((tile_y - 1) * world.icon_size) + world.icon_size / 2+ p_y
|
|
if(!isnull(tile_z))
|
|
z = tile_z
|
|
|
|
/datum/point/proc/return_turf()
|
|
return locate(CEILING(x / world.icon_size, 1), CEILING(y / world.icon_size, 1), z)
|
|
|
|
/datum/point/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/proc/return_position()
|
|
return new /datum/position(src)
|
|
|
|
/datum/point/proc/return_px()
|
|
return MODULUS(x, world.icon_size) - 16
|
|
|
|
/datum/point/proc/return_py()
|
|
return MODULUS(y, world.icon_size) - 16
|
|
|
|
/datum/point/proc/mapcheck()
|
|
. = FALSE
|
|
var/maxx = world.icon_size * world.maxx
|
|
var/maxy = world.icon_size * world.maxy
|
|
var/move_zx = 0
|
|
var/move_zy = 0
|
|
if(x < 0)
|
|
x += maxx
|
|
move_zx -= 1
|
|
if(y < 0)
|
|
y += maxy
|
|
move_zy -= 1
|
|
if(x > maxx)
|
|
x -= maxx
|
|
move_zx += 1
|
|
if(y > maxy)
|
|
y -= maxy
|
|
move_zy += 1
|
|
var/datum/space_level/S = GLOB.z_levels_list["[z]"]
|
|
if(move_zx != 0)
|
|
var/datum/space_level/L = S.neigbours["[move_zx < 0? WEST : EAST]"]
|
|
z = L.z_value
|
|
. = TRUE
|
|
if(move_zy != 0)
|
|
var/datum/space_level/L = S.neigbours["[move_zy < 0? SOUTH : NORTH]"]
|
|
z = L.z_value
|
|
. = TRUE
|
|
|
|
/datum/point/vector
|
|
var/speed = 32 //pixels per iteration
|
|
var/iteration = 0
|
|
var/angle = 0
|
|
var/mpx = 0 //calculated x/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/vector/New(_x, _y, _z, _pixel_x = 0, _pixel_y = 0, _angle, _speed)
|
|
..()
|
|
initialize_trajectory(_speed, _angle)
|
|
|
|
/datum/point/vector/initialize_location(tile_x, tile_y, tile_z, p_x = 0, p_y = 0)
|
|
. = ..()
|
|
starting_x = x
|
|
starting_y = y
|
|
starting_z = z
|
|
|
|
/datum/point/vector/copy_to(datum/point/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/vector/proc/initialize_trajectory(pixel_speed, new_angle)
|
|
if(!isnull(pixel_speed))
|
|
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.
|
|
if(isnull(angle))
|
|
return
|
|
angle = new_angle
|
|
update_offsets()
|
|
|
|
/datum/point/vector/proc/update_offsets()
|
|
mpx = sin(angle) * speed
|
|
mpy = cos(angle) * speed
|
|
|
|
/datum/point/vector/proc/set_speed(new_speed)
|
|
if(isnull(new_speed) || speed == new_speed)
|
|
return
|
|
speed = new_speed
|
|
update_offsets()
|
|
|
|
/datum/point/vector/proc/increment(multiplier = 1)
|
|
iteration++
|
|
x += mpx * 1
|
|
y += mpy * 1
|
|
if(mapcheck())
|
|
on_z_change()
|
|
|
|
/datum/point/vector/proc/return_vector_after_increments(amount = 7, multiplier = 1, force_simulate = FALSE)
|
|
var/datum/point/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/vector/proc/on_z_change()
|
|
return
|
|
|
|
/datum/point/vector/processed //pixel_speed is per decisecond.
|
|
var/last_process = 0
|
|
var/last_move = 0
|
|
var/paused = FALSE
|
|
|
|
/datum/point/vector/processed/Destroy()
|
|
STOP_PROCESSING(SSprojectiles, src)
|
|
|
|
/datum/point/vector/processed/proc/start()
|
|
last_process = world.time
|
|
last_move = world.time
|
|
START_PROCESSING(SSprojectiles, src)
|
|
|
|
/datum/point/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)
|
|
=======
|
|
//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.
|
|
|
|
#define RETURN_PRECISE_POSITION(A) new /datum/position(A)
|
|
#define RETURN_PRECISE_POINT(A) new /datum/point(A)
|
|
|
|
/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.
|
|
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.
|
|
if(istype(_x, /datum/point))
|
|
var/datum/point/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(src)
|
|
|
|
/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 = round(a.x + (b.x - a.x) / 2, 1)
|
|
P.y = round(a.y + (b.y - a.y) / 2, 1)
|
|
P.z = a.z
|
|
return P
|
|
|
|
/proc/pixel_length_between_points(datum/point/a, datum/point/b)
|
|
return sqrt(((b.x - a.x) ** 2) + ((b.y - a.y) ** 2))
|
|
|
|
/proc/angle_between_points(datum/point/a, datum/point/b)
|
|
return ATAN2((b.y - a.y), (b.x - a.x))
|
|
|
|
/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!
|
|
var/x = 0
|
|
var/y = 0
|
|
var/z = 0
|
|
|
|
/datum/point/proc/valid()
|
|
return x && y && z
|
|
|
|
/datum/point/proc/copy_to(datum/point/p = new)
|
|
p.x = x
|
|
p.y = y
|
|
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.
|
|
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/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
|
|
if(!isnull(tile_y))
|
|
y = ((tile_y - 1) * world.icon_size) + world.icon_size / 2+ p_y
|
|
if(!isnull(tile_z))
|
|
z = tile_z
|
|
|
|
/datum/point/proc/return_turf()
|
|
return locate(CEILING(x / world.icon_size, 1), CEILING(y / world.icon_size, 1), z)
|
|
|
|
/datum/point/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/proc/return_position()
|
|
return new /datum/position(src)
|
|
|
|
/datum/point/proc/return_px()
|
|
return MODULUS(x, world.icon_size) - 16
|
|
|
|
/datum/point/proc/return_py()
|
|
return MODULUS(y, world.icon_size) - 16
|
|
|
|
/datum/point/proc/mapcheck()
|
|
. = FALSE
|
|
var/maxx = world.icon_size * world.maxx
|
|
var/maxy = world.icon_size * world.maxy
|
|
var/move_zx = 0
|
|
var/move_zy = 0
|
|
if(x < 0)
|
|
x += maxx
|
|
move_zx -= 1
|
|
if(y < 0)
|
|
y += maxy
|
|
move_zy -= 1
|
|
if(x > maxx)
|
|
x -= maxx
|
|
move_zx += 1
|
|
if(y > maxy)
|
|
y -= maxy
|
|
move_zy += 1
|
|
var/datum/space_level/S = SSmapping.get_level(z)
|
|
if(move_zx != 0)
|
|
var/datum/space_level/L = S.neigbours["[move_zx < 0? WEST : EAST]"]
|
|
z = L.z_value
|
|
. = TRUE
|
|
if(move_zy != 0)
|
|
var/datum/space_level/L = S.neigbours["[move_zy < 0? SOUTH : NORTH]"]
|
|
z = L.z_value
|
|
. = TRUE
|
|
|
|
/datum/point/vector
|
|
var/speed = 32 //pixels per iteration
|
|
var/iteration = 0
|
|
var/angle = 0
|
|
var/mpx = 0 //calculated x/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/vector/New(_x, _y, _z, _pixel_x = 0, _pixel_y = 0, _angle, _speed)
|
|
..()
|
|
initialize_trajectory(_speed, _angle)
|
|
|
|
/datum/point/vector/initialize_location(tile_x, tile_y, tile_z, p_x = 0, p_y = 0)
|
|
. = ..()
|
|
starting_x = x
|
|
starting_y = y
|
|
starting_z = z
|
|
|
|
/datum/point/vector/copy_to(datum/point/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/vector/proc/initialize_trajectory(pixel_speed, new_angle)
|
|
if(!isnull(pixel_speed))
|
|
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.
|
|
if(isnull(angle))
|
|
return
|
|
angle = new_angle
|
|
update_offsets()
|
|
|
|
/datum/point/vector/proc/update_offsets()
|
|
mpx = sin(angle) * speed
|
|
mpy = cos(angle) * speed
|
|
|
|
/datum/point/vector/proc/set_speed(new_speed)
|
|
if(isnull(new_speed) || speed == new_speed)
|
|
return
|
|
speed = new_speed
|
|
update_offsets()
|
|
|
|
/datum/point/vector/proc/increment(multiplier = 1)
|
|
iteration++
|
|
x += mpx * 1
|
|
y += mpy * 1
|
|
if(mapcheck())
|
|
on_z_change()
|
|
|
|
/datum/point/vector/proc/return_vector_after_increments(amount = 7, multiplier = 1, force_simulate = FALSE)
|
|
var/datum/point/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/vector/proc/on_z_change()
|
|
return
|
|
|
|
/datum/point/vector/processed //pixel_speed is per decisecond.
|
|
var/last_process = 0
|
|
var/last_move = 0
|
|
var/paused = FALSE
|
|
|
|
/datum/point/vector/processed/Destroy()
|
|
STOP_PROCESSING(SSprojectiles, src)
|
|
|
|
/datum/point/vector/processed/proc/start()
|
|
last_process = world.time
|
|
last_move = world.time
|
|
START_PROCESSING(SSprojectiles, src)
|
|
|
|
/datum/point/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)
|
|
>>>>>>> 827c4b3... Replace hardcoded z-level numbers with a trait system (#34090)
|