Merge pull request #12173 from kevinz000/projectiles_2

Refactors projectile speed to pixels per second
This commit is contained in:
Lin
2020-05-24 21:21:41 +00:00
committed by GitHub
25 changed files with 178 additions and 99 deletions

View File

@@ -209,3 +209,5 @@
/// Make sure something is a boolean TRUE/FALSE 1/0 value, since things like bitfield & bitflag doesn't always give 1s and 0s. /// Make sure something is a boolean TRUE/FALSE 1/0 value, since things like bitfield & bitflag doesn't always give 1s and 0s.
#define FORCE_BOOLEAN(x) ((x)? TRUE : FALSE) #define FORCE_BOOLEAN(x) ((x)? TRUE : FALSE)
#define TILES_TO_PIXELS(tiles) (tiles * PIXELS)

View File

@@ -9,6 +9,9 @@
#define TEXT_EAST "[EAST]" #define TEXT_EAST "[EAST]"
#define TEXT_WEST "[WEST]" #define TEXT_WEST "[WEST]"
/// world.icon_size
#define PIXELS 32
//These get to go at the top, because they're special //These get to go at the top, because they're special
//You can use these defines to get the typepath of the currently running proc/verb (yes procs + verbs are objects) //You can use these defines to get the typepath of the currently running proc/verb (yes procs + verbs are objects)
/* eg: /* eg:

View File

@@ -117,6 +117,7 @@
#define FIRE_PRIORITY_NPC 80 #define FIRE_PRIORITY_NPC 80
#define FIRE_PRIORITY_MOBS 100 #define FIRE_PRIORITY_MOBS 100
#define FIRE_PRIORITY_TGUI 110 #define FIRE_PRIORITY_TGUI 110
#define FIRE_PRIORITY_PROJECTILES 200
#define FIRE_PRIORITY_TICKER 200 #define FIRE_PRIORITY_TICKER 200
#define FIRE_PRIORITY_ATMOS_ADJACENCY 300 #define FIRE_PRIORITY_ATMOS_ADJACENCY 300
#define FIRE_PRIORITY_CHAT 400 #define FIRE_PRIORITY_CHAT 400

39
code/__HELPERS/angles.dm Normal file
View File

@@ -0,0 +1,39 @@
/proc/get_projectile_angle(atom/source, atom/target)
var/sx = source.x * world.icon_size
var/sy = source.y * world.icon_size
var/tx = target.x * world.icon_size
var/ty = target.y * world.icon_size
var/atom/movable/AM
if(ismovable(source))
AM = source
sx += AM.step_x
sy += AM.step_y
if(ismovable(target))
AM = target
tx += AM.step_x
ty += AM.step_y
return SIMPLIFY_DEGREES(arctan(ty - sy, tx - sx))
/proc/Get_Angle(atom/movable/start,atom/movable/end)//For beams.
if(!start || !end)
return 0
var/dy
var/dx
dy=(32*end.y+end.pixel_y)-(32*start.y+start.pixel_y)
dx=(32*end.x+end.pixel_x)-(32*start.x+start.pixel_x)
if(!dy)
return (dx>=0)?90:270
.=arctan(dx/dy)
if(dy<0)
.+=180
else if(dx<0)
.+=360
/proc/Get_Pixel_Angle(var/y, var/x)//for getting the angle when animating something's pixel_x and pixel_y
if(!y)
return (x>=0)?90:270
.=arctan(x/y)
if(y<0)
.+=180
else if(x<0)
.+=360

View File

@@ -15,30 +15,6 @@
var/textb = copytext(HTMLstring, 6, 8) var/textb = copytext(HTMLstring, 6, 8)
return rgb(255 - hex2num(textr), 255 - hex2num(textg), 255 - hex2num(textb)) return rgb(255 - hex2num(textr), 255 - hex2num(textg), 255 - hex2num(textb))
/proc/Get_Angle(atom/movable/start,atom/movable/end)//For beams.
if(!start || !end)
return 0
var/dy
var/dx
dy=(32*end.y+end.pixel_y)-(32*start.y+start.pixel_y)
dx=(32*end.x+end.pixel_x)-(32*start.x+start.pixel_x)
if(!dy)
return (dx>=0)?90:270
.=arctan(dx/dy)
if(dy<0)
.+=180
else if(dx<0)
.+=360
/proc/Get_Pixel_Angle(var/y, var/x)//for getting the angle when animating something's pixel_x and pixel_y
if(!y)
return (x>=0)?90:270
.=arctan(x/y)
if(y<0)
.+=180
else if(x<0)
.+=360
//Returns location. Returns null if no location was found. //Returns location. Returns null if no location was found.
/proc/get_teleport_loc(turf/location,mob/target,distance = 1, density = FALSE, errorx = 0, errory = 0, eoffsetx = 0, eoffsety = 0) /proc/get_teleport_loc(turf/location,mob/target,distance = 1, density = FALSE, errorx = 0, errory = 0, eoffsetx = 0, eoffsety = 0)
/* /*

View File

@@ -1,21 +1,22 @@
PROCESSING_SUBSYSTEM_DEF(projectiles) PROCESSING_SUBSYSTEM_DEF(projectiles)
name = "Projectiles" name = "Projectiles"
priority = FIRE_PRIORITY_PROJECTILES
wait = 1 wait = 1
stat_tag = "PP" stat_tag = "PP"
flags = SS_NO_INIT|SS_TICKER flags = SS_NO_INIT|SS_TICKER
var/global_pixel_speed = 2 var/global_pixel_increment_amount = 4
var/global_iterations_per_move = 16 var/global_projectile_speed_multiplier = 1
/datum/controller/subsystem/processing/projectiles/proc/set_pixel_speed(new_speed) /datum/controller/subsystem/processing/projectiles/proc/set_pixel_speed(new_speed)
global_pixel_speed = new_speed global_pixel_increment_amount = new_speed
for(var/i in processing) for(var/i in processing)
var/obj/item/projectile/P = i var/obj/item/projectile/P = i
if(istype(P)) //there's non projectiles on this too. if(istype(P)) //there's non projectiles on this too.
P.set_pixel_speed(new_speed) P.set_pixel_increment_amount(new_speed)
/datum/controller/subsystem/processing/projectiles/vv_edit_var(var_name, var_value) /datum/controller/subsystem/processing/projectiles/vv_edit_var(var_name, var_value)
switch(var_name) switch(var_name)
if(NAMEOF(src, global_pixel_speed)) if(NAMEOF(src, global_pixel_increment_amount))
set_pixel_speed(var_value) set_pixel_speed(var_value)
return TRUE return TRUE
else else

View File

@@ -189,6 +189,12 @@
x += mpx * (multiplier) x += mpx * (multiplier)
y += mpy * (multiplier) y += mpy * (multiplier)
/datum/point/vector/proc/pixel_increment(pixels = 32, update_iteration = TRUE, realistic_iteration = FALSE)
if(update_iteration)
iteration += realistic_iteration? round(pixels / speed) : 1
x += sin(angle) * pixels
y += cos(angle) * pixels
/datum/point/vector/proc/return_vector_after_increments(amount = 7, multiplier = 1, force_simulate = FALSE) /datum/point/vector/proc/return_vector_after_increments(amount = 7, multiplier = 1, force_simulate = FALSE)
var/datum/point/vector/v = copy_to() var/datum/point/vector/v = copy_to()
if(force_simulate) if(force_simulate)

View File

@@ -419,7 +419,7 @@
A.BB.damage = hitdamage A.BB.damage = hitdamage
if(hitdamage) if(hitdamage)
A.BB.nodamage = FALSE A.BB.nodamage = FALSE
A.BB.speed = 0.5 A.BB.pixels_per_second = TILES_TO_PIXELS(20)
playsound(src.loc, 'sound/machines/click.ogg', 50, 1) playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
A.fire_casing(target, user, params, 0, 0, null, 0, src) A.fire_casing(target, user, params, 0, 0, null, 0, src)
user.visible_message("<span class='warning'>[user] blasts a flying lollipop at [target]!</span>") user.visible_message("<span class='warning'>[user] blasts a flying lollipop at [target]!</span>")
@@ -434,7 +434,7 @@
A.BB.damage = hitdamage A.BB.damage = hitdamage
if(hitdamage) if(hitdamage)
A.BB.nodamage = FALSE A.BB.nodamage = FALSE
A.BB.speed = 0.5 A.BB.pixels_per_second = TILES_TO_PIXELS(20)
A.BB.color = rgb(rand(0, 255), rand(0, 255), rand(0, 255)) A.BB.color = rgb(rand(0, 255), rand(0, 255), rand(0, 255))
playsound(src.loc, 'sound/weapons/bulletflyby3.ogg', 50, 1) playsound(src.loc, 'sound/weapons/bulletflyby3.ogg', 50, 1)
A.fire_casing(target, user, params, 0, 0, null, 0, src) A.fire_casing(target, user, params, 0, 0, null, 0, src)
@@ -671,13 +671,13 @@
if(track_projectile) if(track_projectile)
tracked[P] = P.damage tracked[P] = P.damage
P.damage *= projectile_damage_coefficient P.damage *= projectile_damage_coefficient
P.speed *= projectile_speed_coefficient P.pixels_per_second *= projectile_speed_coefficient
P.add_overlay(projectile_effect) P.add_overlay(projectile_effect)
/obj/item/borg/projectile_dampen/proc/restore_projectile(obj/item/projectile/P) /obj/item/borg/projectile_dampen/proc/restore_projectile(obj/item/projectile/P)
tracked -= P tracked -= P
P.damage *= (1/projectile_damage_coefficient) P.damage *= (1/projectile_damage_coefficient)
P.speed *= (1/projectile_speed_coefficient) P.pixels_per_second *= (1/projectile_speed_coefficient)
P.cut_overlay(projectile_effect) P.cut_overlay(projectile_effect)
/********************************************************************** /**********************************************************************

View File

@@ -417,7 +417,7 @@
marker.icon_state = "chronobolt" marker.icon_state = "chronobolt"
marker.damage = bonus_value marker.damage = bonus_value
marker.nodamage = FALSE marker.nodamage = FALSE
marker.speed = 2 marker.pixels_per_second = TILES_TO_PIXELS(5)
deadly_shot = FALSE deadly_shot = FALSE
/obj/item/crusher_trophy/blaster_tubes/on_mark_detonation(mob/living/target, mob/living/user) /obj/item/crusher_trophy/blaster_tubes/on_mark_detonation(mob/living/target, mob/living/user)

View File

@@ -75,7 +75,7 @@ Difficulty: Medium
/obj/item/projectile/kinetic/miner /obj/item/projectile/kinetic/miner
damage = 40 damage = 40
speed = 0.9 pixels_per_second = TILES_TO_PIXELS(11.111)
icon_state = "ka_tracer" icon_state = "ka_tracer"
range = MINER_DASH_RANGE range = MINER_DASH_RANGE

View File

@@ -212,7 +212,7 @@ Difficulty: Very Hard
icon_state= "chronobolt" icon_state= "chronobolt"
damage = 25 damage = 25
armour_penetration = 100 armour_penetration = 100
speed = 2 pixels_per_second = TILES_TO_PIXELS(5)
eyeblur = 0 eyeblur = 0
damage_type = BRUTE damage_type = BRUTE
pass_flags = PASSTABLE pass_flags = PASSTABLE

View File

@@ -71,7 +71,10 @@ Difficulty: Extremely Hard
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/OpenFire() /mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/OpenFire()
check_enraged() check_enraged()
projectile_speed_multiplier = 1 - enraged * 0.25 if(enraged)
projectile_speed_multiplier = 1.33
else
projectile_speed_multiplier = 1
SetRecoveryTime(100, 100) SetRecoveryTime(100, 100)
if(client) if(client)
@@ -109,7 +112,7 @@ Difficulty: Extremely Hard
icon_state = "ice_1" icon_state = "ice_1"
damage = 20 damage = 20
armour_penetration = 100 armour_penetration = 100
speed = 10 pixels_per_second = TILES_TO_PIXELS(1)
homing_turn_speed = 30 homing_turn_speed = 30
damage_type = BURN damage_type = BURN
@@ -123,7 +126,7 @@ Difficulty: Extremely Hard
icon_state = "nuclear_particle" icon_state = "nuclear_particle"
damage = 5 damage = 5
armour_penetration = 100 armour_penetration = 100
speed = 4 pixels_per_second = TILES_TO_PIXELS(2.5)
damage_type = BRUTE damage_type = BRUTE
/obj/item/projectile/ice_blast /obj/item/projectile/ice_blast
@@ -131,7 +134,7 @@ Difficulty: Extremely Hard
icon_state = "ice_2" icon_state = "ice_2"
damage = 15 damage = 15
armour_penetration = 100 armour_penetration = 100
speed = 4 pixels_per_second = TILES_TO_PIXELS(2.5)
damage_type = BRUTE damage_type = BRUTE
/obj/item/projectile/ice_blast/on_hit(atom/target, blocked = FALSE) /obj/item/projectile/ice_blast/on_hit(atom/target, blocked = FALSE)
@@ -185,7 +188,7 @@ Difficulty: Extremely Hard
if(!startloc || !endloc) if(!startloc || !endloc)
break break
var/obj/item/projectile/ice_blast/P = new(startloc) var/obj/item/projectile/ice_blast/P = new(startloc)
P.speed *= projectile_speed_multiplier P.pixels_per_second *= projectile_speed_multiplier
P.preparePixelProjectile(endloc, startloc, null, angle + rand(-10, 10)) P.preparePixelProjectile(endloc, startloc, null, angle + rand(-10, 10))
P.firer = firer P.firer = firer
if(original) if(original)
@@ -201,7 +204,7 @@ Difficulty: Extremely Hard
if(!endloc) if(!endloc)
break break
var/obj/item/projectile/P = new /obj/item/projectile/snowball(startloc) var/obj/item/projectile/P = new /obj/item/projectile/snowball(startloc)
P.speed *= projectile_speed_multiplier P.pixels_per_second *= projectile_speed_multiplier
P.preparePixelProjectile(endloc, startloc, null, rand(-spread, spread)) P.preparePixelProjectile(endloc, startloc, null, rand(-spread, spread))
P.firer = src P.firer = src
if(target) if(target)
@@ -220,7 +223,7 @@ Difficulty: Extremely Hard
if(!endloc) if(!endloc)
break break
var/obj/item/projectile/P = new /obj/item/projectile/ice_blast(startloc) var/obj/item/projectile/P = new /obj/item/projectile/ice_blast(startloc)
P.speed *= projectile_speed_multiplier P.pixels_per_second *= projectile_speed_multiplier
P.preparePixelProjectile(endloc, startloc, null, spread) P.preparePixelProjectile(endloc, startloc, null, spread)
P.firer = src P.firer = src
if(target) if(target)

View File

@@ -145,6 +145,7 @@
/mob/living/simple_animal/hostile/megafauna/proc/SetRecoveryTime(buffer_time) /mob/living/simple_animal/hostile/megafauna/proc/SetRecoveryTime(buffer_time)
recovery_time = world.time + buffer_time recovery_time = world.time + buffer_time
ranged_cooldown = max(ranged_cooldown, world.time + buffer_time) // CITADEL BANDAID FIX FOR MEGAFAUNA NOT RESPECTING RECOVERY TIME.
/mob/living/simple_animal/hostile/megafauna/proc/grant_achievement(medaltype, scoretype, crusher_kill) /mob/living/simple_animal/hostile/megafauna/proc/grant_achievement(medaltype, scoretype, crusher_kill)
if(!medal_type || (flags_1 & ADMIN_SPAWNED_1)) //Don't award medals if the medal type isn't set if(!medal_type || (flags_1 & ADMIN_SPAWNED_1)) //Don't award medals if the medal type isn't set

View File

@@ -217,7 +217,7 @@
icon_state= "chronobolt" icon_state= "chronobolt"
damage = 15 damage = 15
armour_penetration = 60 armour_penetration = 60
speed = 2 pixels_per_second = TILES_TO_PIXELS(5)
eyeblur = 0 eyeblur = 0
damage_type = BRUTE damage_type = BRUTE
pass_flags = PASSTABLE pass_flags = PASSTABLE

View File

@@ -1,6 +1,10 @@
#define MOVES_HITSCAN -1 //Not actually hitscan but close as we get without actual hitscan. #define MOVES_HITSCAN -1 //Not actually hitscan but close as we get without actual hitscan.
#define MUZZLE_EFFECT_PIXEL_INCREMENT 17 //How many pixels to move the muzzle flash up so your character doesn't look like they're shitting out lasers. #define MUZZLE_EFFECT_PIXEL_INCREMENT 17 //How many pixels to move the muzzle flash up so your character doesn't look like they're shitting out lasers.
/// Minimum projectile pixels to move before it animate()S, below this it's a direct set.
#define MINIMUM_PIXELS_TO_ANIMATE 4
/// Pixels to instantly travel on firing.
#define PROJECTILE_FIRING_INSTANT_TRAVEL_AMOUNT 16
/obj/item/projectile /obj/item/projectile
name = "projectile" name = "projectile"
@@ -12,7 +16,9 @@
pass_flags = PASSTABLE pass_flags = PASSTABLE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT mouse_opacity = MOUSE_OPACITY_TRANSPARENT
movement_type = FLYING movement_type = FLYING
animate_movement = NO_STEPS
hitsound = 'sound/weapons/pierce.ogg' hitsound = 'sound/weapons/pierce.ogg'
appearance_flags = PIXEL_SCALE
var/hitsound_wall = "" var/hitsound_wall = ""
resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
@@ -32,14 +38,19 @@
//Fired processing vars //Fired processing vars
var/fired = FALSE //Have we been fired yet var/fired = FALSE //Have we been fired yet
var/paused = FALSE //for suspending the projectile midair var/paused = FALSE //for suspending the projectile midair
var/last_projectile_move = 0
var/time_offset = 0 var/time_offset = 0
var/datum/point/vector/trajectory var/datum/point/vector/trajectory
var/trajectory_ignore_forcemove = FALSE //instructs forceMove to NOT reset our trajectory to the new location! var/trajectory_ignore_forcemove = FALSE //instructs forceMove to NOT reset our trajectory to the new location!
/// "leftover" pixels for Range() calculation as pixel_move() was moved to simulated semi-pixel movement and Range() is in tiles.
var/pixels_range_leftover = 0
/// "leftover" tick pixels and stuff yeah, so we don't round off things and introducing tracing inaccuracy.
var/pixels_tick_leftover = 0
/// Pixels moved per second.
var/pixels_per_second = TILES_TO_PIXELS(12.5)
/// The number of pixels we increment by. THIS IS NOT SPEED, DO NOT TOUCH THIS UNLESS YOU KNOW WHAT YOU ARE DOING. In general, lower values means more linetrace accuracy up to a point at cost of performance.
var/pixel_increment_amount
var/speed = 0.8 //Amount of deciseconds it takes for projectile to travel
/// "leftover" ticks and stuff yeah. hey when are we rewriting projectiles for the eighth time to do something smarter like incrementing x pixels until it meets a goal instead of for(var/i in 1 to required_moves)?
var/tick_moves_leftover = 0
var/Angle = 0 var/Angle = 0
var/original_angle = 0 //Angle at firing var/original_angle = 0 //Angle at firing
var/nondirectional_sprite = FALSE //Set TRUE to prevent projectiles from having their sprites rotated based on firing angle var/nondirectional_sprite = FALSE //Set TRUE to prevent projectiles from having their sprites rotated based on firing angle
@@ -75,12 +86,16 @@
//Homing //Homing
var/homing = FALSE var/homing = FALSE
var/atom/homing_target var/atom/homing_target
var/homing_turn_speed = 10 //Angle per tick. /// How fast the projectile turns towards its homing targets, in angle per second.
var/homing_turn_speed = 100
var/homing_inaccuracy_min = 0 //in pixels for these. offsets are set once when setting target. var/homing_inaccuracy_min = 0 //in pixels for these. offsets are set once when setting target.
var/homing_inaccuracy_max = 0 var/homing_inaccuracy_max = 0
var/homing_offset_x = 0 var/homing_offset_x = 0
var/homing_offset_y = 0 var/homing_offset_y = 0
/// How many deciseconds are each hitscan movement considered. Used for homing and other things that use seconds for timing rather than ticks.
var/hitscan_movement_decisecond_equivalency = 0.1
var/ignore_source_check = FALSE var/ignore_source_check = FALSE
var/damage = 10 var/damage = 10
@@ -88,7 +103,8 @@
var/nodamage = 0 //Determines if the projectile will skip any damage inflictions var/nodamage = 0 //Determines if the projectile will skip any damage inflictions
var/flag = "bullet" //Defines what armor to use when it hits things. Must be set to bullet, laser, energy,or bomb var/flag = "bullet" //Defines what armor to use when it hits things. Must be set to bullet, laser, energy,or bomb
var/projectile_type = /obj/item/projectile var/projectile_type = /obj/item/projectile
var/range = 50 //This will de-increment every step. When 0, it will deletze the projectile. /// Range of the projectile, de-incrementing every step. The projectile deletes itself at 0. This is in tiles.
var/range = 50
var/decayedRange //stores original range var/decayedRange //stores original range
var/reflect_range_decrease = 5 //amount of original range that falls off when reflecting, so it doesn't go forever var/reflect_range_decrease = 5 //amount of original range that falls off when reflecting, so it doesn't go forever
var/is_reflectable = FALSE // Can it be reflected or not? var/is_reflectable = FALSE // Can it be reflected or not?
@@ -120,6 +136,10 @@
permutated = list() permutated = list()
decayedRange = range decayedRange = range
/**
* Artificially modified to be called at around every world.icon_size pixels of movement.
* WARNING: Range() can only be called once per pixel_increment_amount pixels.
*/
/obj/item/projectile/proc/Range() /obj/item/projectile/proc/Range()
range-- range--
if(range <= 0 && loc) if(range <= 0 && loc)
@@ -334,14 +354,15 @@
return TRUE return TRUE
return FALSE return FALSE
/// one move is a tile.
/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. /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)) if(!trajectory && isnull(forced_angle) && isnull(Angle))
return FALSE return FALSE
var/datum/point/vector/current = trajectory var/datum/point/vector/current = trajectory
if(!current) if(!current)
var/turf/T = get_turf(src) var/turf/T = get_turf(src)
current = new(T.x, T.y, T.z, pixel_x, pixel_y, isnull(forced_angle)? Angle : forced_angle, SSprojectiles.global_pixel_speed) current = new(T.x, T.y, T.z, pixel_x, pixel_y, isnull(forced_angle)? Angle : forced_angle, pixel_increment_amount || SSprojectiles.global_pixel_increment_amount)
var/datum/point/vector/v = current.return_vector_after_increments(moves * SSprojectiles.global_iterations_per_move) var/datum/point/vector/v = current.return_vector_after_increments(TILES_TO_PIXELS(moves) / (pixel_increment_amount || SSprojectiles.global_pixel_increment_amount))
return v.return_turf() return v.return_turf()
/obj/item/projectile/proc/return_pathing_turfs_in_moves(moves, forced_angle) /obj/item/projectile/proc/return_pathing_turfs_in_moves(moves, forced_angle)
@@ -358,16 +379,14 @@
return PROCESS_KILL return PROCESS_KILL
if(paused || !isturf(loc)) if(paused || !isturf(loc))
return return
var/ds = (SSprojectiles.flags & SS_TICKER)? (wait * world.tick_lag) : wait var/ds = (SSprojectiles.flags & SS_TICKER)? (wait * world.tick_lag) : wait
var/required_moves = ds / speed var/required_pixels = (pixels_per_second * ds * 0.1) + pixels_tick_leftover
var/leftover = MODULUS(required_moves, 1) if(required_pixels >= pixel_increment_amount)
tick_moves_leftover += leftover pixels_tick_leftover = MODULUS(required_pixels, pixel_increment_amount)
required_moves = round(required_moves) pixel_move(FLOOR(required_pixels / pixel_increment_amount, 1), FALSE, ds, SSprojectiles.global_projectile_speed_multiplier)
if(tick_moves_leftover > 1) else
required_moves += round(tick_moves_leftover) pixels_tick_leftover = required_pixels
tick_moves_leftover = MODULUS(tick_moves_leftover, 1)
for(var/i in 1 to required_moves)
pixel_move(1, FALSE)
/obj/item/projectile/proc/fire(angle, atom/direct_target) /obj/item/projectile/proc/fire(angle, atom/direct_target)
if(fired_from) if(fired_from)
@@ -390,7 +409,7 @@
qdel(src) qdel(src)
return return
var/turf/target = locate(clamp(starting + xo, 1, world.maxx), clamp(starting + yo, 1, world.maxy), starting.z) var/turf/target = locate(clamp(starting + xo, 1, world.maxx), clamp(starting + yo, 1, world.maxy), starting.z)
setAngle(Get_Angle(src, target)) setAngle(get_projectile_angle(src, target))
original_angle = Angle original_angle = Angle
if(!nondirectional_sprite) if(!nondirectional_sprite)
var/matrix/M = new var/matrix/M = new
@@ -399,14 +418,16 @@
trajectory_ignore_forcemove = TRUE trajectory_ignore_forcemove = TRUE
forceMove(starting) forceMove(starting)
trajectory_ignore_forcemove = FALSE trajectory_ignore_forcemove = FALSE
trajectory = new(starting.x, starting.y, starting.z, pixel_x, pixel_y, Angle, SSprojectiles.global_pixel_speed) if(isnull(pixel_increment_amount))
last_projectile_move = world.time pixel_increment_amount = SSprojectiles.global_pixel_increment_amount
trajectory = new(starting.x, starting.y, starting.z, pixel_x, pixel_y, Angle, pixel_increment_amount)
fired = TRUE fired = TRUE
if(hitscan) if(hitscan)
process_hitscan() process_hitscan()
return
if(!(datum_flags & DF_ISPROCESSING)) if(!(datum_flags & DF_ISPROCESSING))
START_PROCESSING(SSprojectiles, src) START_PROCESSING(SSprojectiles, src)
pixel_move(1, FALSE) //move it now! pixel_move(round(PROJECTILE_FIRING_INSTANT_TRAVEL_AMOUNT / pixel_increment_amount), FALSE, allow_animation = FALSE) //move it now!
/obj/item/projectile/proc/setAngle(new_angle, hitscan_store_segment = TRUE) //wrapper for overrides. /obj/item/projectile/proc/setAngle(new_angle, hitscan_store_segment = TRUE) //wrapper for overrides.
Angle = new_angle Angle = new_angle
@@ -451,7 +472,8 @@
else else
return ..() return ..()
/obj/item/projectile/proc/set_pixel_speed(new_speed) /obj/item/projectile/proc/set_pixel_increment_amount(new_speed)
pixel_increment_amount = new_speed
if(trajectory) if(trajectory)
trajectory.set_speed(new_speed) trajectory.set_speed(new_speed)
return TRUE return TRUE
@@ -464,6 +486,7 @@
beam_segments[beam_index] = null //record start. beam_segments[beam_index] = null //record start.
/obj/item/projectile/proc/process_hitscan() /obj/item/projectile/proc/process_hitscan()
var/ttm = round(world.icon_size / pixel_increment_amount, 1)
var/safety = range * 10 var/safety = range * 10
record_hitscan_start(RETURN_POINT_VECTOR_INCREMENT(src, Angle, MUZZLE_EFFECT_PIXEL_INCREMENT, 1)) record_hitscan_start(RETURN_POINT_VECTOR_INCREMENT(src, Angle, MUZZLE_EFFECT_PIXEL_INCREMENT, 1))
while(loc && !QDELETED(src)) while(loc && !QDELETED(src))
@@ -476,20 +499,33 @@
if(!QDELETED(src)) if(!QDELETED(src))
qdel(src) qdel(src)
return //Kill! return //Kill!
pixel_move(1, TRUE) pixel_move(ttm, TRUE, hitscan_movement_decisecond_equivalency)
/obj/item/projectile/proc/pixel_move(trajectory_multiplier, hitscanning = FALSE) /**
* The proc to make the projectile go, using a simulated pixel movement line trace.
* Note: deciseconds_equivalent is currently only used for homing, times is the number of times to move pixel_increment_amount.
* Trajectory multiplier directly modifies the factor of pixel_increment_amount to go per time.
* It's complicated, so probably just don'ot mess with this unless you know what you're doing.
*/
/obj/item/projectile/proc/pixel_move(times, hitscanning = FALSE, deciseconds_equivalent = world.tick_lag, trajectory_multiplier = 1, allow_animation = TRUE)
if(!loc || !trajectory) if(!loc || !trajectory)
return return
last_projectile_move = world.time
if(!nondirectional_sprite && !hitscanning) if(!nondirectional_sprite && !hitscanning)
var/matrix/M = new var/matrix/M = new
M.Turn(Angle) M.Turn(Angle)
transform = M transform = M
if(homing)
process_homing()
var/forcemoved = FALSE var/forcemoved = FALSE
for(var/i in 1 to SSprojectiles.global_iterations_per_move) var/turf/oldloc = loc
var/old_px = pixel_x
var/old_py = pixel_y
for(var/i in 1 to times)
// HOMING START - Too expensive to proccall at this point.
if(homing_target)
// No datum/points, too expensive.
var/angle = closer_angle_difference(Angle, get_projectile_angle(src, homing_target))
var/max_turn = homing_turn_speed * deciseconds_equivalent * 0.1
setAngle(Angle + clamp(angle, -max_turn, max_turn))
// HOMING END
trajectory.increment(trajectory_multiplier) trajectory.increment(trajectory_multiplier)
var/turf/T = trajectory.return_turf() var/turf/T = trajectory.return_turf()
if(!istype(T)) if(!istype(T))
@@ -509,23 +545,29 @@
pixel_x = trajectory.return_px() pixel_x = trajectory.return_px()
pixel_y = trajectory.return_py() pixel_y = trajectory.return_py()
else if(T != loc) else if(T != loc)
step_towards(src, T) var/safety = CEILING(pixel_increment_amount / world.icon_size, 1) * 2 + 1
while(T != loc)
if(!--safety)
CRASH("Projectile took more than pixel incrememnt speed times 2 to get to its location, this is probably something seriously scuffed going on.")
step_towards(src, T)
if(QDELETED(src))
return
pixels_range_leftover += pixel_increment_amount
if(pixels_range_leftover > world.icon_size)
Range()
if(QDELETED(src)) if(QDELETED(src))
return return
pixels_range_leftover -= world.icon_size
if(!hitscanning && !forcemoved) if(!hitscanning && !forcemoved)
pixel_x = trajectory.return_px() - trajectory.mpx * trajectory_multiplier * SSprojectiles.global_iterations_per_move var/traj_px = round(trajectory.return_px(), 1)
pixel_y = trajectory.return_py() - trajectory.mpy * trajectory_multiplier * SSprojectiles.global_iterations_per_move var/traj_py = round(trajectory.return_py(), 1)
animate(src, pixel_x = trajectory.return_px(), pixel_y = trajectory.return_py(), time = 1, flags = ANIMATION_END_NOW) if(allow_animation && (pixel_increment_amount * times > MINIMUM_PIXELS_TO_ANIMATE))
Range() pixel_x = ((oldloc.x - x) * world.icon_size) + old_px
pixel_y = ((oldloc.y - y) * world.icon_size) + old_py
/obj/item/projectile/proc/process_homing() //may need speeding up in the future performance wise. animate(src, pixel_x = traj_px, pixel_y = traj_py, time = 1, flags = ANIMATION_END_NOW)
if(!homing_target) else
return FALSE pixel_x = traj_px
var/datum/point/PT = RETURN_PRECISE_POINT(homing_target) pixel_y = traj_py
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))
/obj/item/projectile/proc/set_homing_target(atom/A) /obj/item/projectile/proc/set_homing_target(atom/A)
if(!A || (!isturf(A) && !isturf(A.loc))) if(!A || (!isturf(A) && !isturf(A.loc)))
@@ -575,7 +617,7 @@
if(targloc || !params) if(targloc || !params)
yo = targloc.y - curloc.y yo = targloc.y - curloc.y
xo = targloc.x - curloc.x xo = targloc.x - curloc.x
setAngle(Get_Angle(src, targloc) + spread) setAngle(get_projectile_angle(src, targloc) + spread)
if(isliving(source) && params) if(isliving(source) && params)
var/list/calculated = calculate_projectile_angle_and_pixel_offsets(source, params) var/list/calculated = calculate_projectile_angle_and_pixel_offsets(source, params)
@@ -586,7 +628,7 @@
else if(targloc) else if(targloc)
yo = targloc.y - curloc.y yo = targloc.y - curloc.y
xo = targloc.x - curloc.x xo = targloc.x - curloc.x
setAngle(Get_Angle(src, targloc) + spread) setAngle(get_projectile_angle(src, targloc) + spread)
else else
stack_trace("WARNING: Projectile [type] fired without either mouse parameters, or a target atom to aim at!") stack_trace("WARNING: Projectile [type] fired without either mouse parameters, or a target atom to aim at!")
qdel(src) qdel(src)
@@ -698,3 +740,7 @@
/proc/is_energy_reflectable_projectile(atom/A) /proc/is_energy_reflectable_projectile(atom/A)
var/obj/item/projectile/P = A var/obj/item/projectile/P = A
return istype(P) && P.is_reflectable return istype(P) && P.is_reflectable
#undef MOVES_HITSCAN
#undef MINIMUM_PIXELS_TO_ANIMATE
#undef MUZZLE_EFFECT_PIXEL_INCREMENT

View File

@@ -74,7 +74,7 @@
flag = "energy" flag = "energy"
hitsound = 'sound/weapons/tap.ogg' hitsound = 'sound/weapons/tap.ogg'
eyeblur = 0 eyeblur = 0
speed = 0.6 pixels_per_second = TILES_TO_PIXELS(16.667)
impact_effect_type = /obj/effect/temp_visual/impact_effect/blue_laser impact_effect_type = /obj/effect/temp_visual/impact_effect/blue_laser
light_color = LIGHT_COLOR_BLUE light_color = LIGHT_COLOR_BLUE
tracer_type = /obj/effect/projectile/tracer/disabler tracer_type = /obj/effect/projectile/tracer/disabler

View File

@@ -3,7 +3,7 @@
damage = 20 damage = 20
armour_penetration = 20 armour_penetration = 20
light_range = 3 light_range = 3
speed = 0.6 pixels_per_second = TILES_TO_PIXELS(16.667)
range = 35 range = 35
light_color = LIGHT_COLOR_RED light_color = LIGHT_COLOR_RED
@@ -39,7 +39,7 @@
armour_penetration = 20 armour_penetration = 20
movement_type = FLYING | UNSTOPPABLE movement_type = FLYING | UNSTOPPABLE
range = 20 range = 20
speed = 0.8 pixels_per_second = TILES_TO_PIXELS(12.5)
light_range = 4 light_range = 4
light_color = LIGHT_COLOR_RED light_color = LIGHT_COLOR_RED

View File

@@ -2,7 +2,7 @@
/obj/item/projectile/bullet/p50 /obj/item/projectile/bullet/p50
name =".50 bullet" name =".50 bullet"
speed = 0.4 pixels_per_second = TILES_TO_PIXELS(25)
damage = 70 damage = 70
knockdown = 100 knockdown = 100
dismemberment = 50 dismemberment = 50
@@ -43,5 +43,5 @@
/obj/item/projectile/bullet/p50/penetrator/shuttle //Nukeop Shuttle Variety /obj/item/projectile/bullet/p50/penetrator/shuttle //Nukeop Shuttle Variety
icon_state = "gaussstrong" icon_state = "gaussstrong"
damage = 25 damage = 25
speed = 0.3 pixels_per_second = TILES_TO_PIXELS(33.33)
range = 16 range = 16

View File

@@ -5,7 +5,7 @@
pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
flag = "rad" flag = "rad"
irradiate = 5000 irradiate = 5000
speed = 0.4 pixels_per_second = TILES_TO_PIXELS(25)
hitsound = 'sound/weapons/emitter2.ogg' hitsound = 'sound/weapons/emitter2.ogg'
impact_type = /obj/effect/projectile/impact/xray impact_type = /obj/effect/projectile/impact/xray
var/static/list/particle_colors = list( var/static/list/particle_colors = list(

View File

@@ -10,7 +10,7 @@
jitter = 20 jitter = 20
hitsound = 'sound/weapons/taserhit.ogg' hitsound = 'sound/weapons/taserhit.ogg'
range = 14 range = 14
speed = 0.6 pixels_per_second = TILES_TO_PIXELS(16.667)
tracer_type = /obj/effect/projectile/tracer/stun tracer_type = /obj/effect/projectile/tracer/stun
muzzle_type = /obj/effect/projectile/muzzle/stun muzzle_type = /obj/effect/projectile/muzzle/stun
impact_type = /obj/effect/projectile/impact/stun impact_type = /obj/effect/projectile/impact/stun

View File

@@ -434,7 +434,7 @@
damage = 15 damage = 15
damage_type = BURN damage_type = BURN
nodamage = 0 nodamage = 0
speed = 0.3 pixels_per_second = TILES_TO_PIXELS(33.33)
flag = "magic" flag = "magic"
var/zap_power = 20000 var/zap_power = 20000

View File

@@ -10,7 +10,7 @@
damage_type = BURN damage_type = BURN
damage = 10 damage = 10
knockdown = 20 knockdown = 20
speed = 2 pixels_per_second = TILES_TO_PIXELS(5)
range = 16 range = 16
movement_type = FLYING | UNSTOPPABLE movement_type = FLYING | UNSTOPPABLE
var/datum/beam/arm var/datum/beam/arm

View File

@@ -178,7 +178,7 @@
name = "positron blast" name = "positron blast"
damage = 80 damage = 80
range = 14 range = 14
speed = 0.6 pixels_per_second = TILES_TO_PIXELS(16.667)
icon_state = "disablerslug" icon_state = "disablerslug"
/obj/item/projectile/beam/pump /obj/item/projectile/beam/pump

View File

@@ -137,6 +137,7 @@
#include "code\__HELPERS\_lists.dm" #include "code\__HELPERS\_lists.dm"
#include "code\__HELPERS\_logging.dm" #include "code\__HELPERS\_logging.dm"
#include "code\__HELPERS\_string_lists.dm" #include "code\__HELPERS\_string_lists.dm"
#include "code\__HELPERS\angles.dm"
#include "code\__HELPERS\areas.dm" #include "code\__HELPERS\areas.dm"
#include "code\__HELPERS\AStar.dm" #include "code\__HELPERS\AStar.dm"
#include "code\__HELPERS\cmp.dm" #include "code\__HELPERS\cmp.dm"