Merge pull request #4494 from Citadel-Station-13/upstream-merge-32433
[MIRROR] [READY]Refactors projectile trajectories, fixes piercing projectile inaccuracy and beam rifle visual deflections
This commit is contained in:
12
code/datums/actions/beam_rifle.dm
Normal file
12
code/datums/actions/beam_rifle.dm
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
/datum/action/item_action/zoom_speed_action
|
||||
name = "Toggle Zooming Speed"
|
||||
icon_icon = 'icons/mob/actions/actions_spells.dmi'
|
||||
button_icon_state = "projectile"
|
||||
background_icon_state = "bg_tech"
|
||||
|
||||
/datum/action/item_action/zoom_lock_action
|
||||
name = "Switch Zoom Mode"
|
||||
icon_icon = 'icons/mob/actions/actions_items.dmi'
|
||||
button_icon_state = "zoom_mode"
|
||||
background_icon_state = "bg_tech"
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
/datum/action/item_action/flightsuit
|
||||
icon_icon = 'icons/mob/actions/actions_flightsuit.dmi'
|
||||
|
||||
|
||||
239
code/datums/position_point_vector.dm
Normal file
239
code/datums/position_point_vector.dm
Normal file
@@ -0,0 +1,239 @@
|
||||
//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)
|
||||
@@ -0,0 +1,70 @@
|
||||
/proc/generate_projectile_beam_between_points(datum/point/starting, datum/point/ending, beam_type, color, qdel_in = 5) //Do not pass z-crossing points as that will not be properly (and likely will never be properly until it's absolutely needed) supported!
|
||||
if(!istype(starting) || !istype(ending) || !ispath(beam_type))
|
||||
return
|
||||
var/datum/point/midpoint = point_midpoint_points(starting, ending)
|
||||
var/obj/effect/projectile_beam/PB = new beam_type
|
||||
PB.apply_vars(angle_between_points(starting, ending), midpoint.return_px(), midpoint.return_py(), color, pixel_length_between_points(starting, ending) / world.icon_size, midpoint.return_turf(), 0)
|
||||
. = PB
|
||||
if(qdel_in)
|
||||
QDEL_IN(PB, qdel_in)
|
||||
|
||||
/obj/effect/projectile_beam
|
||||
icon = 'icons/obj/projectiles.dmi'
|
||||
layer = ABOVE_MOB_LAYER
|
||||
anchored = TRUE
|
||||
light_power = 1
|
||||
light_range = 2
|
||||
light_color = "#00ffff"
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
flags_1 = ABSTRACT_1
|
||||
appearance_flags = 0
|
||||
|
||||
/obj/effect/projectile_beam/singularity_pull()
|
||||
return
|
||||
|
||||
/obj/effect/projectile_beam/singularity_act()
|
||||
return
|
||||
|
||||
/obj/effect/projectile_beam/proc/scale_to(nx,ny,override=TRUE)
|
||||
var/matrix/M
|
||||
if(!override)
|
||||
M = transform
|
||||
else
|
||||
M = new
|
||||
M.Scale(nx,ny)
|
||||
transform = M
|
||||
|
||||
/obj/effect/projectile_beam/proc/turn_to(angle,override=TRUE)
|
||||
var/matrix/M
|
||||
if(!override)
|
||||
M = transform
|
||||
else
|
||||
M = new
|
||||
M.Turn(angle)
|
||||
transform = M
|
||||
|
||||
/obj/effect/projectile_beam/New(angle_override, p_x, p_y, color_override, scaling = 1)
|
||||
if(angle_override && p_x && p_y && color_override && scaling)
|
||||
apply_vars(angle_override, p_x, p_y, color_override, scaling)
|
||||
return ..()
|
||||
|
||||
/obj/effect/projectile_beam/proc/apply_vars(angle_override, p_x = 0, p_y = 0, color_override, scaling = 1, new_loc, increment = 0)
|
||||
var/mutable_appearance/look = new(src)
|
||||
look.pixel_x = p_x
|
||||
look.pixel_y = p_y
|
||||
if(color_override)
|
||||
look.color = color_override
|
||||
appearance = look
|
||||
scale_to(1,scaling, FALSE)
|
||||
turn_to(angle_override, FALSE)
|
||||
if(!isnull(new_loc)) //If you want to null it just delete it...
|
||||
forceMove(new_loc)
|
||||
for(var/i in 1 to increment)
|
||||
pixel_x += round((sin(angle_override)+16*sin(angle_override)*2), 1)
|
||||
pixel_y += round((cos(angle_override)+16*cos(angle_override)*2), 1)
|
||||
|
||||
/obj/effect/projectile_beam/tracer
|
||||
icon_state = "tracer_beam"
|
||||
|
||||
/obj/effect/projectile_beam/tracer/aiming
|
||||
icon_state = "gbeam"
|
||||
@@ -202,7 +202,7 @@
|
||||
var/new_angle = WRAP(rotation_angle + norm_inc, 180, -180)
|
||||
if(ISINRANGE_EX(norm_inc, -90, 90))
|
||||
return FALSE
|
||||
P.Angle = new_angle
|
||||
P.setAngle(new_angle)
|
||||
return ..()
|
||||
|
||||
//DOUBLE
|
||||
@@ -229,7 +229,7 @@
|
||||
var/new_angle = WRAP(rotation_angle + norm_inc, 180, -180)
|
||||
if(ISINRANGE_EX(norm_inc, -90, 90))
|
||||
new_angle += 180
|
||||
P.Angle = new_angle
|
||||
P.setAngle(new_angle)
|
||||
return ..()
|
||||
|
||||
//BOX
|
||||
@@ -251,7 +251,7 @@
|
||||
anchored = TRUE
|
||||
|
||||
/obj/structure/reflector/box/auto_reflect(obj/item/projectile/P)
|
||||
P.Angle = rotation_angle
|
||||
P.setAngle(rotation_angle)
|
||||
return ..()
|
||||
|
||||
/obj/structure/reflector/ex_act()
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
new_angle_s -= 360
|
||||
while(new_angle_s < -180)
|
||||
new_angle_s += 360
|
||||
P.Angle = new_angle_s
|
||||
P.setAngle(new_angle_s)
|
||||
return TRUE
|
||||
|
||||
/turf/closed/wall/proc/dismantle_wall(devastated=0, explode=0)
|
||||
|
||||
@@ -400,7 +400,8 @@
|
||||
|
||||
/obj/item/gun/dropped(mob/user)
|
||||
..()
|
||||
zoom(user,FALSE)
|
||||
if(zoomed)
|
||||
zoom(user,FALSE)
|
||||
if(azoom)
|
||||
azoom.Remove(user)
|
||||
if(alight)
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
#define ZOOM_LOCK_CENTER_VIEW 2
|
||||
#define ZOOM_LOCK_OFF 3
|
||||
|
||||
#define ZOOM_SPEED_STEP 0
|
||||
#define ZOOM_SPEED_INSTANT 1
|
||||
|
||||
#define AUTOZOOM_PIXEL_STEP_FACTOR 48
|
||||
|
||||
#define AIMING_BEAM_ANGLE_CHANGE_THRESHOLD 0.1
|
||||
@@ -45,7 +42,7 @@
|
||||
var/lastangle = 0
|
||||
var/aiming_lastangle = 0
|
||||
var/mob/current_user = null
|
||||
var/obj/effect/projectile_beam/current_tracer
|
||||
var/list/obj/effect/projectile_beam/current_tracers
|
||||
|
||||
var/structure_piercing = 2 //Amount * 2. For some reason structures aren't respecting this unless you have it doubled. Probably with the objects in question's Bump() code instead of this but I'll deal with this later.
|
||||
var/structure_bleed_coeff = 0.7
|
||||
@@ -69,9 +66,8 @@
|
||||
//ZOOMING
|
||||
var/zoom_current_view_increase = 0
|
||||
var/zoom_target_view_increase = 10
|
||||
var/zoom_speed = ZOOM_SPEED_STEP
|
||||
var/zooming = FALSE
|
||||
var/zoom_lock = ZOOM_LOCK_AUTOZOOM_FREEMOVE
|
||||
var/zoom_lock = ZOOM_LOCK_OFF
|
||||
var/zooming_angle
|
||||
var/current_zoom_x = 0
|
||||
var/current_zoom_y = 0
|
||||
@@ -80,7 +76,6 @@
|
||||
var/static/image/charged_overlay = image(icon = 'icons/obj/guns/energy.dmi', icon_state = "esniper_charged")
|
||||
var/static/image/drained_overlay = image(icon = 'icons/obj/guns/energy.dmi', icon_state = "esniper_empty")
|
||||
|
||||
var/datum/action/item_action/zoom_speed_action/zoom_speed_action
|
||||
var/datum/action/item_action/zoom_lock_action/zoom_lock_action
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/debug
|
||||
@@ -103,15 +98,6 @@
|
||||
. = ..()
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/ui_action_click(owner, action)
|
||||
if(istype(action, /datum/action/item_action/zoom_speed_action))
|
||||
zoom_speed++
|
||||
if(zoom_speed > 1)
|
||||
zoom_speed = ZOOM_SPEED_STEP
|
||||
switch(zoom_speed)
|
||||
if(ZOOM_SPEED_STEP)
|
||||
to_chat(owner, "<span class='boldnotice'>You switch [src]'s digital zoom to stepper mode.</span>")
|
||||
if(ZOOM_SPEED_INSTANT)
|
||||
to_chat(owner, "<span class='boldnotice'>You switch [src]'s digital zoom to instant mode.</span>")
|
||||
if(istype(action, /datum/action/item_action/zoom_lock_action))
|
||||
zoom_lock++
|
||||
if(zoom_lock > 3)
|
||||
@@ -135,8 +121,6 @@
|
||||
var/total_time = SSfastprocess.wait
|
||||
if(delay_override)
|
||||
total_time = delay_override
|
||||
if(zoom_speed == ZOOM_SPEED_INSTANT)
|
||||
total_time = 0
|
||||
zoom_animating = total_time
|
||||
animate(current_user.client, pixel_x = current_zoom_x, pixel_y = current_zoom_y , total_time, SINE_EASING, ANIMATION_PARALLEL)
|
||||
zoom_animating = 0
|
||||
@@ -150,18 +134,10 @@
|
||||
/obj/item/gun/energy/beam_rifle/proc/handle_zooming()
|
||||
if(!zooming || !check_user())
|
||||
return
|
||||
if(zoom_speed == ZOOM_SPEED_INSTANT)
|
||||
current_user.client.change_view(world.view + zoom_target_view_increase)
|
||||
zoom_current_view_increase = zoom_target_view_increase
|
||||
set_autozoom_pixel_offsets_immediate(zooming_angle)
|
||||
smooth_zooming()
|
||||
return
|
||||
if(zoom_current_view_increase > zoom_target_view_increase)
|
||||
return
|
||||
zoom_current_view_increase++
|
||||
current_user.client.change_view(zoom_current_view_increase + world.view)
|
||||
current_user.client.change_view(world.view + zoom_target_view_increase)
|
||||
zoom_current_view_increase = zoom_target_view_increase
|
||||
set_autozoom_pixel_offsets_immediate(zooming_angle)
|
||||
smooth_zooming(SSfastprocess.wait * zoom_target_view_increase * zoom_speed)
|
||||
smooth_zooming()
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/proc/start_zooming()
|
||||
if(zoom_lock == ZOOM_LOCK_OFF)
|
||||
@@ -169,8 +145,9 @@
|
||||
zooming = TRUE
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/proc/stop_zooming()
|
||||
zooming = FALSE
|
||||
reset_zooming()
|
||||
if(zooming)
|
||||
zooming = FALSE
|
||||
reset_zooming()
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/proc/reset_zooming()
|
||||
if(!check_user(FALSE))
|
||||
@@ -204,14 +181,14 @@
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/Initialize()
|
||||
. = ..()
|
||||
current_tracers = list()
|
||||
START_PROCESSING(SSprojectiles, src)
|
||||
zoom_speed_action = new(src)
|
||||
zoom_lock_action = new(src)
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/Destroy()
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
set_user(null)
|
||||
QDEL_NULL(current_tracer)
|
||||
QDEL_LIST(current_tracers)
|
||||
return ..()
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/emp_act(severity)
|
||||
@@ -245,6 +222,7 @@
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/process()
|
||||
if(!aiming)
|
||||
last_process = world.time
|
||||
return
|
||||
check_user()
|
||||
handle_zooming()
|
||||
@@ -299,7 +277,7 @@
|
||||
set waitfor = FALSE
|
||||
aiming_time_left = aiming_time
|
||||
aiming = FALSE
|
||||
QDEL_NULL(current_tracer)
|
||||
QDEL_LIST(current_tracers)
|
||||
stop_zooming()
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/proc/set_user(mob/user)
|
||||
@@ -341,7 +319,7 @@
|
||||
sync_ammo()
|
||||
afterattack(M.client.mouseObject, M, FALSE, M.client.mouseParams, passthrough = TRUE)
|
||||
stop_aiming()
|
||||
QDEL_NULL(current_tracer)
|
||||
QDEL_LIST(current_tracers)
|
||||
return ..()
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/afterattack(atom/target, mob/living/user, flag, params, passthrough = FALSE)
|
||||
@@ -555,136 +533,103 @@
|
||||
handle_impact(target)
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/Collide(atom/target)
|
||||
paused = TRUE
|
||||
if(check_pierce(target))
|
||||
permutated += target
|
||||
return FALSE
|
||||
if(!QDELETED(target))
|
||||
cached = get_turf(target)
|
||||
paused = FALSE
|
||||
. = ..()
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/on_hit(atom/target, blocked = FALSE)
|
||||
paused = TRUE
|
||||
if(!QDELETED(target))
|
||||
cached = get_turf(target)
|
||||
handle_hit(target)
|
||||
paused = FALSE
|
||||
. = ..()
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/hitscan
|
||||
icon_state = ""
|
||||
var/tracer_type = /obj/effect/projectile_beam/tracer
|
||||
var/starting_z
|
||||
var/starting_p_x
|
||||
var/starting_p_y
|
||||
var/list/beam_segments //assoc list of datum/point or datum/point/vector, start = end.
|
||||
var/constant_tracer = FALSE
|
||||
var/travelled_p_x = 0
|
||||
var/travelled_p_y = 0
|
||||
var/tracer_spawned = FALSE
|
||||
var/beam_index
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/hitscan/Destroy()
|
||||
paused = TRUE //STOP HITTING WHEN YOU'RE ALREADY BEING DELETED!
|
||||
spawn_tracer(constant_tracer)
|
||||
if(loc)
|
||||
var/datum/point/pcache = trajectory.copy_to()
|
||||
beam_segments[beam_index] = pcache
|
||||
generate_tracers(constant_tracer)
|
||||
return ..()
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/hitscan/proc/spawn_tracer(put_in_rifle = FALSE)
|
||||
if(tracer_spawned)
|
||||
return
|
||||
tracer_spawned = TRUE
|
||||
//Remind me to port baystation trajectories so this shit isn't needed...
|
||||
var/pixels_travelled = round(sqrt(travelled_p_x**2 + travelled_p_y**2),1)
|
||||
var/scaling = pixels_travelled/world.icon_size
|
||||
var/midpoint_p_x = round(starting_p_x + (travelled_p_x / 2))
|
||||
var/midpoint_p_y = round(starting_p_y + (travelled_p_y / 2))
|
||||
var/tracer_px = midpoint_p_x % world.icon_size
|
||||
var/tracer_py = midpoint_p_y % world.icon_size
|
||||
var/tracer_lx = (midpoint_p_x - tracer_px) / world.icon_size
|
||||
var/tracer_ly = (midpoint_p_y - tracer_py) / world.icon_size
|
||||
var/obj/effect/projectile_beam/PB = new tracer_type(src)
|
||||
PB.apply_vars(Angle, tracer_px, tracer_py, color, scaling, locate(tracer_lx,tracer_ly,starting_z))
|
||||
if(put_in_rifle && istype(gun))
|
||||
if(gun.current_tracer)
|
||||
QDEL_NULL(gun.current_tracer)
|
||||
gun.current_tracer = PB
|
||||
else
|
||||
QDEL_IN(PB, 5)
|
||||
/obj/item/projectile/beam/beam_rifle/hitscan/Collide(atom/target)
|
||||
var/datum/point/pcache = trajectory.copy_to()
|
||||
. = ..()
|
||||
if(. && !QDELETED(src)) //successful touch and not destroyed.
|
||||
beam_segments[beam_index] = pcache
|
||||
beam_index = pcache
|
||||
beam_segments[beam_index] = null
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/hitscan/proc/check_for_turf_edge(turf/T)
|
||||
if(!istype(T))
|
||||
return TRUE
|
||||
var/tx = T.x
|
||||
var/ty = T.y
|
||||
if(tx < 10 || tx > (world.maxx - 10) || ty < 10 || ty > (world.maxy-10))
|
||||
return TRUE
|
||||
return FALSE
|
||||
/obj/item/projectile/beam/beam_rifle/hitscan/before_z_change(turf/oldloc, turf/newloc)
|
||||
var/datum/point/pcache = trajectory.copy_to()
|
||||
beam_segments[beam_index] = pcache
|
||||
beam_index = RETURN_PRECISE_POINT(newloc)
|
||||
beam_segments[beam_index] = null
|
||||
return ..()
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/hitscan/proc/generate_tracers(highlander = FALSE, cleanup = TRUE)
|
||||
set waitfor = FALSE
|
||||
if(highlander && istype(gun))
|
||||
QDEL_LIST(gun.current_tracers)
|
||||
for(var/datum/point/p in beam_segments)
|
||||
gun.current_tracers += generate_projectile_beam_between_points(p, beam_segments[p], tracer_type, color, 0)
|
||||
else
|
||||
for(var/datum/point/p in beam_segments)
|
||||
generate_projectile_beam_between_points(p, beam_segments[p], tracer_type, color, 5)
|
||||
if(cleanup)
|
||||
QDEL_LIST(beam_segments)
|
||||
beam_segments = null
|
||||
QDEL_NULL(beam_index)
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/hitscan/fire(setAngle, atom/direct_target) //oranges didn't let me make this a var the first time around so copypasta time
|
||||
set waitfor = 0
|
||||
set waitfor = FALSE
|
||||
var/turf/starting = get_turf(src)
|
||||
trajectory = new(starting.x, starting.y, starting.z, 0, 0, setAngle? setAngle : Angle, 33)
|
||||
if(!log_override && firer && original)
|
||||
add_logs(firer, original, "fired at", src, " [get_area(src)]")
|
||||
fired = TRUE
|
||||
if(setAngle)
|
||||
Angle = setAngle
|
||||
var/next_run = world.time
|
||||
var/old_pixel_x = pixel_x
|
||||
var/old_pixel_y = pixel_y
|
||||
var/safety = 0 //The code works fine, but... just in case...
|
||||
var/turf/c2
|
||||
var/starting_x = loc.x
|
||||
var/starting_y = loc.y
|
||||
starting_z = loc.z
|
||||
starting_p_x = starting_x * world.icon_size + pixel_x
|
||||
starting_p_y = starting_y * world.icon_size + pixel_y
|
||||
beam_segments = list() //initialize segment list with the list for the first segment
|
||||
beam_index = RETURN_PRECISE_POINT(src)
|
||||
beam_segments[beam_index] = null //record start.
|
||||
if(spread)
|
||||
Angle += (rand() - 0.5) * spread
|
||||
while(loc)
|
||||
if(paused || QDELETED(src))
|
||||
return
|
||||
if(++safety > (range * 3)) //If it's looping for way, way too long...
|
||||
qdel(src)
|
||||
stack_trace("WARNING: [type] projectile encountered infinite recursion in [__FILE__]/[__LINE__]!")
|
||||
return //Kill!
|
||||
if(spread)
|
||||
Angle += (rand() - 0.5) * spread
|
||||
var/matrix/M = new
|
||||
M.Turn(Angle)
|
||||
transform = M
|
||||
var/Pixel_x=sin(Angle)+16*sin(Angle)*2
|
||||
var/Pixel_y=cos(Angle)+16*cos(Angle)*2
|
||||
travelled_p_x += Pixel_x
|
||||
travelled_p_y += Pixel_y
|
||||
var/pixel_x_offset = old_pixel_x + Pixel_x
|
||||
var/pixel_y_offset = old_pixel_y + Pixel_y
|
||||
var/new_x = x
|
||||
var/new_y = y
|
||||
while(pixel_x_offset > 16)
|
||||
pixel_x_offset -= 32
|
||||
old_pixel_x -= 32
|
||||
new_x++// x++
|
||||
while(pixel_x_offset < -16)
|
||||
pixel_x_offset += 32
|
||||
old_pixel_x += 32
|
||||
new_x--
|
||||
while(pixel_y_offset > 16)
|
||||
pixel_y_offset -= 32
|
||||
old_pixel_y -= 32
|
||||
new_y++
|
||||
while(pixel_y_offset < -16)
|
||||
pixel_y_offset += 32
|
||||
old_pixel_y += 32
|
||||
new_y--
|
||||
pixel_x = old_pixel_x
|
||||
pixel_y = old_pixel_y
|
||||
step_towards(src, locate(new_x, new_y, z))
|
||||
next_run += max(world.tick_lag, speed)
|
||||
var/delay = next_run - world.time
|
||||
if(delay <= world.tick_lag*2)
|
||||
pixel_x = pixel_x_offset
|
||||
pixel_y = pixel_y_offset
|
||||
trajectory.increment()
|
||||
var/turf/T = trajectory.return_turf()
|
||||
if(T.z != loc.z)
|
||||
before_z_change(loc, T)
|
||||
trajectory_ignore_forcemove = TRUE
|
||||
forceMove(T)
|
||||
trajectory_ignore_forcemove = FALSE
|
||||
else
|
||||
animate(src, pixel_x = pixel_x_offset, pixel_y = pixel_y_offset, time = max(1, (delay <= 3 ? delay - 1 : delay)), flags = ANIMATION_END_NOW)
|
||||
old_pixel_x = pixel_x_offset
|
||||
old_pixel_y = pixel_y_offset
|
||||
step_towards(src, T)
|
||||
animate(src, pixel_x = trajectory.return_px(), pixel_y = trajectory.return_py(), time = 1, flags = ANIMATION_END_NOW)
|
||||
|
||||
if(can_hit_target(original, permutated))
|
||||
Collide(original)
|
||||
c2 = loc
|
||||
Range()
|
||||
if(check_for_turf_edge(loc))
|
||||
spawn_tracer(constant_tracer)
|
||||
c2 = get_turf(src)
|
||||
if(istype(c2))
|
||||
cached = c2
|
||||
|
||||
@@ -704,76 +649,3 @@
|
||||
/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/on_hit()
|
||||
qdel(src)
|
||||
return FALSE
|
||||
|
||||
/obj/effect/projectile_beam
|
||||
icon = 'icons/obj/projectiles.dmi'
|
||||
layer = ABOVE_MOB_LAYER
|
||||
anchored = TRUE
|
||||
light_power = 1
|
||||
light_range = 2
|
||||
light_color = "#00ffff"
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
flags_1 = ABSTRACT_1
|
||||
appearance_flags = 0
|
||||
|
||||
/obj/effect/projectile_beam/proc/scale_to(nx,ny,override=TRUE)
|
||||
var/matrix/M
|
||||
if(!override)
|
||||
M = transform
|
||||
else
|
||||
M = new
|
||||
M.Scale(nx,ny)
|
||||
transform = M
|
||||
|
||||
/obj/effect/projectile_beam/proc/turn_to(angle,override=TRUE)
|
||||
var/matrix/M
|
||||
if(!override)
|
||||
M = transform
|
||||
else
|
||||
M = new
|
||||
M.Turn(angle)
|
||||
transform = M
|
||||
|
||||
/obj/effect/projectile_beam/New(angle_override, p_x, p_y, color_override, scaling = 1)
|
||||
if(angle_override && p_x && p_y && color_override && scaling)
|
||||
apply_vars(angle_override, p_x, p_y, color_override, scaling)
|
||||
return ..()
|
||||
|
||||
/obj/effect/projectile_beam/proc/apply_vars(angle_override, p_x, p_y, color_override, scaling = 1, new_loc, increment = 0)
|
||||
var/mutable_appearance/look = new(src)
|
||||
look.pixel_x = p_x
|
||||
look.pixel_y = p_y
|
||||
if(color_override)
|
||||
look.color = color_override
|
||||
appearance = look
|
||||
scale_to(1,scaling, FALSE)
|
||||
turn_to(angle_override, FALSE)
|
||||
if(!isnull(new_loc)) //If you want to null it just delete it...
|
||||
forceMove(new_loc)
|
||||
for(var/i in 1 to increment)
|
||||
pixel_x += round((sin(angle_override)+16*sin(angle_override)*2), 1)
|
||||
pixel_y += round((cos(angle_override)+16*cos(angle_override)*2), 1)
|
||||
|
||||
/obj/effect/projectile_beam/tracer
|
||||
icon_state = "tracer_beam"
|
||||
|
||||
/obj/effect/projectile_beam/tracer/aiming
|
||||
icon_state = "gbeam"
|
||||
|
||||
/datum/action/item_action/zoom_speed_action
|
||||
name = "Toggle Zooming Speed"
|
||||
icon_icon = 'icons/mob/actions/actions_spells.dmi'
|
||||
button_icon_state = "projectile"
|
||||
background_icon_state = "bg_tech"
|
||||
|
||||
/datum/action/item_action/zoom_lock_action
|
||||
name = "Switch Zoom Mode"
|
||||
icon_icon = 'icons/mob/actions/actions_items.dmi'
|
||||
button_icon_state = "zoom_mode"
|
||||
background_icon_state = "bg_tech"
|
||||
|
||||
/obj/effect/projectile_beam/singularity_pull()
|
||||
return
|
||||
|
||||
/obj/effect/projectile_beam/singularity_act()
|
||||
return
|
||||
|
||||
@@ -31,16 +31,11 @@
|
||||
var/last_projectile_move = 0
|
||||
var/last_process = 0
|
||||
var/time_offset = 0
|
||||
var/old_pixel_x = 0
|
||||
var/old_pixel_y = 0
|
||||
var/pixel_x_increment = 0
|
||||
var/pixel_y_increment = 0
|
||||
var/pixel_x_offset = 0
|
||||
var/pixel_y_offset = 0
|
||||
var/new_x = 0
|
||||
var/new_y = 0
|
||||
var/datum/point/vector/trajectory
|
||||
var/trajectory_ignore_forcemove = FALSE //instructs forceMove to NOT reset our trajectory to the new location!
|
||||
|
||||
var/speed = 0.8 //Amount of deciseconds it takes for projectile to travel
|
||||
var/pixel_speed = 33 //pixels per move - DO NOT FUCK WITH THIS UNLESS YOU ABSOLUTELY KNOW WHAT YOU ARE DOING OR UNEXPECTED THINGS /WILL/ HAPPEN!
|
||||
var/Angle = 0
|
||||
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
|
||||
@@ -48,6 +43,9 @@
|
||||
var/ricochets = 0
|
||||
var/ricochets_max = 2
|
||||
var/ricochet_chance = 30
|
||||
|
||||
var/colliding = FALSE //pause processing..
|
||||
|
||||
var/ignore_source_check = FALSE
|
||||
|
||||
var/damage = 10
|
||||
@@ -168,20 +166,28 @@
|
||||
|
||||
/obj/item/projectile/proc/vol_by_damage()
|
||||
if(src.damage)
|
||||
return CLAMP((src.damage) * 0.67, 30, 100)// Multiply projectile damage by 0.67, then clamp the value between 30 and 100
|
||||
return CLAMP((src.damage) * 0.67, 30, 100)// Multiply projectile damage by 0.67, then CLAMP the value between 30 and 100
|
||||
else
|
||||
return 50 //if the projectile doesn't do damage, play its hitsound at 50% volume
|
||||
|
||||
/obj/item/projectile/proc/on_ricochet(atom/A)
|
||||
return
|
||||
|
||||
/obj/item/projectile/Collide(atom/A)
|
||||
colliding = TRUE
|
||||
if(check_ricochet(A) && check_ricochet_flag(A) && ricochets < ricochets_max)
|
||||
ricochets++
|
||||
if(A.handle_ricochet(src))
|
||||
on_ricochet(A)
|
||||
ignore_source_check = TRUE
|
||||
range = initial(range)
|
||||
return FALSE
|
||||
return TRUE
|
||||
if(firer && !ignore_source_check)
|
||||
if(A == firer || (A == firer.loc && ismecha(A))) //cannot shoot yourself or your mech
|
||||
loc = A.loc
|
||||
trajectory_ignore_forcemove = TRUE
|
||||
forceMove(get_turf(A))
|
||||
trajectory_ignore_forcemove = FALSE
|
||||
colliding = FALSE
|
||||
return FALSE
|
||||
|
||||
var/distance = get_dist(get_turf(A), starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations.
|
||||
@@ -197,25 +203,32 @@
|
||||
|
||||
if(!prehit(A))
|
||||
if(forcedodge)
|
||||
loc = target_turf
|
||||
trajectory_ignore_forcemove = TRUE
|
||||
forceMove(target_turf)
|
||||
trajectory_ignore_forcemove = FALSE
|
||||
colliding = FALSE
|
||||
return FALSE
|
||||
|
||||
var/permutation = A.bullet_act(src, def_zone) // searches for return value, could be deleted after run so check A isn't null
|
||||
if(permutation == -1 || forcedodge)// the bullet passes through a dense object!
|
||||
loc = target_turf
|
||||
trajectory_ignore_forcemove = TRUE
|
||||
forceMove(target_turf)
|
||||
trajectory_ignore_forcemove = FALSE
|
||||
if(A)
|
||||
permutated.Add(A)
|
||||
colliding = FALSE
|
||||
return FALSE
|
||||
else
|
||||
var/atom/alt = select_target(A)
|
||||
if(alt)
|
||||
if(!prehit(alt))
|
||||
colliding = FALSE
|
||||
return FALSE
|
||||
alt.bullet_act(src, def_zone)
|
||||
qdel(src)
|
||||
colliding = FALSE
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/item/projectile/proc/select_target(atom/A) //Selects another target from a wall if we hit a wall.
|
||||
if(!A || !A.density || (A.flags_1 & ON_BORDER_1) || ismob(A) || A == original) //if we hit a dense non-border obj or dense turf then we also hit one of the mobs or machines/structures on that tile.
|
||||
return
|
||||
@@ -246,12 +259,30 @@
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/projectile/proc/return_predicted_turf_after_moves(moves, forced_angle) //I say predicted because there's no telling that the projectile won't change direction/location in flight.
|
||||
if(!trajectory && isnull(forced_angle) && isnull(Angle))
|
||||
return FALSE
|
||||
var/datum/point/vector/current = trajectory
|
||||
if(!current)
|
||||
var/turf/T = get_turf(src)
|
||||
current = new(T.x, T.y, T.z, pixel_x, pixel_y, isnull(forced_angle)? Angle : forced_angle, pixel_speed)
|
||||
var/datum/point/vector/v = current.return_vector_after_increments(moves)
|
||||
return v.return_turf()
|
||||
|
||||
/obj/item/projectile/proc/return_pathing_turfs_in_moves(moves, forced_angle)
|
||||
var/turf/current = get_turf(src)
|
||||
var/turf/ending = return_predicted_turf_after_moves(moves, forced_angle)
|
||||
return getline(current, ending)
|
||||
|
||||
/obj/item/projectile/proc/before_z_change(turf/oldloc, turf/newloc)
|
||||
return
|
||||
|
||||
/obj/item/projectile/Process_Spacemove(var/movement_dir = 0)
|
||||
return TRUE //Bullets don't drift in space
|
||||
|
||||
/obj/item/projectile/process()
|
||||
last_process = world.time
|
||||
if(!loc || !fired)
|
||||
if(!loc || !fired || !trajectory)
|
||||
fired = FALSE
|
||||
return PROCESS_KILL
|
||||
if(paused || !isturf(loc))
|
||||
@@ -285,73 +316,70 @@
|
||||
setAngle(angle)
|
||||
if(spread)
|
||||
setAngle(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.
|
||||
var/turf/starting = get_turf(src)
|
||||
if(isnull(xo) || isnull(yo))
|
||||
stack_trace("WARNING: Projectile [type] deleted due to being unable to resolve a target after angle was null!")
|
||||
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))
|
||||
if(!nondirectional_sprite)
|
||||
var/matrix/M = new
|
||||
M.Turn(Angle)
|
||||
transform = M
|
||||
old_pixel_x = pixel_x
|
||||
old_pixel_y = pixel_y
|
||||
trajectory = new(starting.x, starting.y, starting.z, 0, 0, Angle, pixel_speed)
|
||||
last_projectile_move = world.time
|
||||
fired = TRUE
|
||||
if(!isprocessing)
|
||||
START_PROCESSING(SSprojectiles, src)
|
||||
pixel_move(1) //move it now!
|
||||
|
||||
/obj/item/projectile/proc/setAngle(new_angle) //wrapper for overrides.
|
||||
Angle = new_angle
|
||||
return TRUE
|
||||
|
||||
/obj/item/projectile/proc/pixel_move(moves)
|
||||
if(!nondirectional_sprite)
|
||||
var/matrix/M = new
|
||||
M.Turn(Angle)
|
||||
transform = M
|
||||
if(trajectory)
|
||||
trajectory.set_angle(new_angle)
|
||||
return TRUE
|
||||
|
||||
pixel_x_increment=round((sin(Angle)+16*sin(Angle)*2), 1) //round() is a floor operation when only one argument is supplied, we don't want that here
|
||||
pixel_y_increment=round((cos(Angle)+16*cos(Angle)*2), 1)
|
||||
pixel_x_offset = old_pixel_x + pixel_x_increment
|
||||
pixel_y_offset = old_pixel_y + pixel_y_increment
|
||||
new_x = x
|
||||
new_y = y
|
||||
/obj/item/projectile/forceMove(atom/target)
|
||||
. = ..()
|
||||
if(trajectory && !trajectory_ignore_forcemove && isturf(target))
|
||||
trajectory.initialize_location(target.x, target.y, target.z, 0, 0)
|
||||
|
||||
while(pixel_x_offset > 16)
|
||||
pixel_x_offset -= 32
|
||||
old_pixel_x -= 32
|
||||
new_x++// x++
|
||||
while(pixel_x_offset < -16)
|
||||
pixel_x_offset += 32
|
||||
old_pixel_x += 32
|
||||
new_x--
|
||||
while(pixel_y_offset > 16)
|
||||
pixel_y_offset -= 32
|
||||
old_pixel_y -= 32
|
||||
new_y++
|
||||
while(pixel_y_offset < -16)
|
||||
pixel_y_offset += 32
|
||||
old_pixel_y += 32
|
||||
new_y--
|
||||
/obj/item/projectile/proc/pixel_move(moves, trajectory_multiplier = 1)
|
||||
if(!loc || !trajectory)
|
||||
return
|
||||
last_projectile_move = world.time
|
||||
if(!nondirectional_sprite)
|
||||
var/matrix/M = new
|
||||
M.Turn(Angle)
|
||||
transform = M
|
||||
trajectory.increment(trajectory_multiplier)
|
||||
var/turf/T = trajectory.return_turf()
|
||||
if(T.z != loc.z)
|
||||
before_z_change(loc, T)
|
||||
trajectory_ignore_forcemove = TRUE
|
||||
forceMove(T)
|
||||
trajectory_ignore_forcemove = FALSE
|
||||
pixel_x = trajectory.return_px()
|
||||
pixel_y = trajectory.return_py()
|
||||
else
|
||||
step_towards(src, T)
|
||||
pixel_x = trajectory.return_px() - trajectory.mpx * trajectory_multiplier
|
||||
pixel_y = trajectory.return_py() - trajectory.mpy * trajectory_multiplier
|
||||
animate(src, pixel_x = trajectory.return_px(), pixel_y = trajectory.return_py(), time = 1, flags = ANIMATION_END_NOW)
|
||||
|
||||
step_towards(src, locate(new_x, new_y, z))
|
||||
pixel_x = old_pixel_x
|
||||
pixel_y = old_pixel_y
|
||||
animate(src, pixel_x = pixel_x_offset, pixel_y = pixel_y_offset, time = 1, flags = ANIMATION_END_NOW)
|
||||
old_pixel_x = pixel_x_offset
|
||||
old_pixel_y = pixel_y_offset
|
||||
if(can_hit_target(original, permutated))
|
||||
Collide(original)
|
||||
Range()
|
||||
last_projectile_move = world.time
|
||||
|
||||
//Returns true if the target atom is on our current turf and above the right layer
|
||||
/obj/item/projectile/proc/can_hit_target(atom/target, var/list/passthrough)
|
||||
if(target && (target.layer >= PROJECTILE_HIT_THRESHHOLD_LAYER) || ismob(target))
|
||||
if(loc == get_turf(target))
|
||||
if(!(target in passthrough))
|
||||
return TRUE
|
||||
return FALSE
|
||||
return (target && ((target.layer >= PROJECTILE_HIT_THRESHHOLD_LAYER) || ismob(target)) && (loc == get_turf(target)) && (!(target in passthrough)))
|
||||
|
||||
/obj/item/projectile/proc/preparePixelProjectile(atom/target, atom/source, params, spread = 0)
|
||||
var/turf/curloc = get_turf(source)
|
||||
@@ -362,7 +390,8 @@
|
||||
if(targloc || !params)
|
||||
yo = targloc.y - curloc.y
|
||||
xo = targloc.x - curloc.x
|
||||
|
||||
setAngle(Get_Angle(src, targloc))
|
||||
|
||||
if(isliving(source) && params)
|
||||
var/list/calculated = calculate_projectile_angle_and_pixel_offsets(source, params)
|
||||
p_x = calculated[2]
|
||||
@@ -372,8 +401,13 @@
|
||||
setAngle(calculated[1] + spread)
|
||||
else
|
||||
setAngle(calculated[1])
|
||||
else
|
||||
else if(targloc)
|
||||
yo = targloc.y - curloc.y
|
||||
xo = targloc.x - curloc.x
|
||||
setAngle(Get_Angle(src, targloc))
|
||||
else
|
||||
stack_trace("WARNING: Projectile [type] fired without either mouse parameters, or a target atom to aim at!")
|
||||
qdel(src)
|
||||
|
||||
/proc/calculate_projectile_angle_and_pixel_offsets(mob/user, params)
|
||||
var/list/mouse_control = params2list(params)
|
||||
|
||||
@@ -19,7 +19,7 @@ GLOBAL_LIST_EMPTY(z_levels_list)
|
||||
neigbours[A] = src
|
||||
|
||||
/datum/space_level/proc/set_neigbours(list/L)
|
||||
for(var/datum/point/P in L)
|
||||
for(var/datum/space_transition_point/P in L)
|
||||
if(P.x == xi)
|
||||
if(P.y == yi+1)
|
||||
neigbours[TEXT_NORTH] = P.spl
|
||||
@@ -35,13 +35,13 @@ GLOBAL_LIST_EMPTY(z_levels_list)
|
||||
neigbours[TEXT_WEST] = P.spl
|
||||
P.spl.neigbours[TEXT_EAST] = src
|
||||
|
||||
/datum/point //this is explicitly utilitarian datum type made specially for the space map generation and are absolutely unusable for anything else
|
||||
/datum/space_transition_point //this is explicitly utilitarian datum type made specially for the space map generation and are absolutely unusable for anything else
|
||||
var/list/neigbours = list()
|
||||
var/x
|
||||
var/y
|
||||
var/datum/space_level/spl
|
||||
|
||||
/datum/point/New(nx, ny, list/point_grid)
|
||||
/datum/space_transition_point/New(nx, ny, list/point_grid)
|
||||
if(!point_grid)
|
||||
qdel(src)
|
||||
return
|
||||
@@ -55,7 +55,7 @@ GLOBAL_LIST_EMPTY(z_levels_list)
|
||||
return
|
||||
point_grid[x][y] = src
|
||||
|
||||
/datum/point/proc/set_neigbours(list/grid)
|
||||
/datum/space_transition_point/proc/set_neigbours(list/grid)
|
||||
var/max_X = grid.len
|
||||
var/list/max_Y = grid[1]
|
||||
max_Y = max_Y.len
|
||||
@@ -86,13 +86,13 @@ GLOBAL_LIST_EMPTY(z_levels_list)
|
||||
k++
|
||||
var/list/point_grid[conf_set_len*2+1][conf_set_len*2+1]
|
||||
var/list/grid = list()
|
||||
var/datum/point/P
|
||||
var/datum/space_transition_point/P
|
||||
for(var/i = 1, i<=conf_set_len*2+1, i++)
|
||||
for(var/j = 1, j<=conf_set_len*2+1, j++)
|
||||
P = new/datum/point(i,j, point_grid)
|
||||
P = new/datum/space_transition_point(i,j, point_grid)
|
||||
point_grid[i][j] = P
|
||||
grid.Add(P)
|
||||
for(var/datum/point/pnt in grid)
|
||||
for(var/datum/space_transition_point/pnt in grid)
|
||||
pnt.set_neigbours(point_grid)
|
||||
P = point_grid[conf_set_len+1][conf_set_len+1]
|
||||
var/list/possible_points = list()
|
||||
|
||||
@@ -306,6 +306,7 @@
|
||||
#include "code\datums\mutable_appearance.dm"
|
||||
#include "code\datums\mutations.dm"
|
||||
#include "code\datums\outfit.dm"
|
||||
#include "code\datums\position_point_vector.dm"
|
||||
#include "code\datums\profiling.dm"
|
||||
#include "code\datums\progressbar.dm"
|
||||
#include "code\datums\radiation_wave.dm"
|
||||
@@ -318,6 +319,7 @@
|
||||
#include "code\datums\verbs.dm"
|
||||
#include "code\datums\weakrefs.dm"
|
||||
#include "code\datums\world_topic.dm"
|
||||
#include "code\datums\actions\beam_rifle.dm"
|
||||
#include "code\datums\actions\flightsuit.dm"
|
||||
#include "code\datums\actions\ninja.dm"
|
||||
#include "code\datums\antagonists\abductor.dm"
|
||||
@@ -852,6 +854,7 @@
|
||||
#include "code\game\objects\effects\temporary_visuals\clockcult.dm"
|
||||
#include "code\game\objects\effects\temporary_visuals\cult.dm"
|
||||
#include "code\game\objects\effects\temporary_visuals\miscellaneous.dm"
|
||||
#include "code\game\objects\effects\temporary_visuals\projectile_beam.dm"
|
||||
#include "code\game\objects\effects\temporary_visuals\temporary_visual.dm"
|
||||
#include "code\game\objects\items\AI_modules.dm"
|
||||
#include "code\game\objects\items\airlock_painter.dm"
|
||||
|
||||
Reference in New Issue
Block a user