mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-12 23:53:47 +01:00
Refactors projectile ricochets (#25764)
* same taste, twice the speed * pulls proc/handle_ricochet() to the atom level. adds var/flags_ricochet and related defines. * space indentation sneaks its way in yet again --------- Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com>
This commit is contained in:
@@ -63,12 +63,10 @@
|
||||
|
||||
#define OVERLAY_QUEUED_2 (1<<12)
|
||||
|
||||
#define CHECK_RICOCHET_2 (1<<13)
|
||||
|
||||
/// should the contents of this atom be acted upon
|
||||
#define RAD_PROTECT_CONTENTS_2 (1<<14)
|
||||
#define RAD_PROTECT_CONTENTS_2 (1<<14)
|
||||
/// should this object be allowed to be contaminated
|
||||
#define RAD_NO_CONTAMINATE_2 (1<<15)
|
||||
#define RAD_NO_CONTAMINATE_2 (1<<15)
|
||||
/// Prevents shuttles from deleting the item
|
||||
#define IMMUNE_TO_SHUTTLECRUSH_2 (1<<16)
|
||||
/// Prevents malf AI animate + overload ability
|
||||
@@ -80,6 +78,12 @@
|
||||
/// This flag allows for wearing of a belt item, even if you're not wearing a jumpsuit
|
||||
#define ALLOW_BELT_NO_JUMPSUIT_2 (1<<20)
|
||||
|
||||
// /atom ricochet flags
|
||||
/// If the thing can reflect light (lasers/energy)
|
||||
#define RICOCHET_SHINY (1<<0)
|
||||
/// If the thing can reflect matter (bullets/bomb shrapnel)
|
||||
#define RICOCHET_HARD (1<<1)
|
||||
|
||||
//Reagent flags
|
||||
#define REAGENT_NOREACT 1
|
||||
|
||||
|
||||
+21
-2
@@ -4,6 +4,8 @@
|
||||
var/level = 2
|
||||
var/flags = NONE
|
||||
var/flags_2 = NONE
|
||||
/// how the atom should handle ricochet behavior
|
||||
var/flags_ricochet = NONE
|
||||
var/list/fingerprints
|
||||
var/list/fingerprintshidden
|
||||
var/fingerprintslast = null
|
||||
@@ -107,6 +109,11 @@
|
||||
/// Contains the world.time of when we start dragging something with our mouse. Used to prevent weird situations where you fail to click on something
|
||||
var/drag_start = 0
|
||||
|
||||
///When a projectile tries to ricochet off this atom, the projectile ricochet chance is multiplied by this
|
||||
var/receive_ricochet_chance_mod = 1
|
||||
///When a projectile ricochets off this atom, it deals the normal damage * this modifier to this atom
|
||||
var/receive_ricochet_damage_coeff = 0.33
|
||||
|
||||
/atom/New(loc, ...)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
if(GLOB.use_preloader && (src.type == GLOB._preloader.target_path))//in case the instanciated atom is creating other atoms in New()
|
||||
@@ -1107,8 +1114,20 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
|
||||
/atom/proc/zap_act(power, zap_flags)
|
||||
return
|
||||
|
||||
/atom/proc/handle_ricochet(obj/item/projectile/P)
|
||||
return
|
||||
/atom/proc/handle_ricochet(obj/item/projectile/ricocheting_projectile)
|
||||
var/turf/p_turf = get_turf(ricocheting_projectile)
|
||||
var/face_direction = get_dir(src, p_turf) || get_dir(src, ricocheting_projectile)
|
||||
var/face_angle = dir2angle(face_direction)
|
||||
var/incidence_s = GET_ANGLE_OF_INCIDENCE(face_angle, (ricocheting_projectile.Angle + 180))
|
||||
var/a_incidence_s = abs(incidence_s)
|
||||
if(a_incidence_s > 90 && a_incidence_s < 270)
|
||||
return FALSE
|
||||
if((ricocheting_projectile.flag in list(BULLET, BOMB)) && ricocheting_projectile.ricochet_incidence_leeway)
|
||||
if((a_incidence_s < 90 && a_incidence_s < 90 - ricocheting_projectile.ricochet_incidence_leeway) || (a_incidence_s > 270 && a_incidence_s -270 > ricocheting_projectile.ricochet_incidence_leeway))
|
||||
return FALSE
|
||||
var/new_angle_s = SIMPLIFY_DEGREES(face_angle + incidence_s)
|
||||
ricocheting_projectile.set_angle(new_angle_s)
|
||||
return TRUE
|
||||
|
||||
//This proc is called on the location of an atom when the atom is Destroy()'d
|
||||
/atom/proc/handle_atom_del(atom/A)
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
layer = BELOW_OBJ_LAYER
|
||||
armor = list(melee = 25, bullet = 10, laser = 10, energy = 0, bomb = 0, rad = 0, fire = 50, acid = 70)
|
||||
atom_say_verb = "beeps"
|
||||
flags_ricochet = RICOCHET_HARD
|
||||
receive_ricochet_chance_mod = 0.3
|
||||
var/stat = 0
|
||||
|
||||
/// How is this machine currently passively consuming power?
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
air = environment
|
||||
if(isnull(air))
|
||||
return
|
||||
|
||||
|
||||
var/breath_percentage = BREATH_VOLUME / air.return_volume()
|
||||
return air.remove(air.total_moles() * breath_percentage)
|
||||
else
|
||||
@@ -303,6 +303,12 @@
|
||||
else
|
||||
C.KnockDown(3 SECONDS)
|
||||
|
||||
/obj/handle_ricochet(obj/item/projectile/P)
|
||||
. = ..()
|
||||
if(. && receive_ricochet_damage_coeff)
|
||||
// pass along receive_ricochet_damage_coeff damage to the structure for the ricochet
|
||||
take_damage(P.damage * receive_ricochet_damage_coeff, P.damage_type, P.flag, 0, REVERSE_DIR(P.dir), P.armour_penetration_flat, P.armour_penetration_percentage)
|
||||
|
||||
/obj/proc/return_obj_air()
|
||||
RETURN_TYPE(/datum/gas_mixture)
|
||||
if(isobj(loc))
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
pressure_resistance = 8
|
||||
max_integrity = 300
|
||||
face_while_pulling = TRUE
|
||||
flags_ricochet = RICOCHET_HARD
|
||||
receive_ricochet_chance_mod = 0.6
|
||||
var/climbable
|
||||
/// Determines if a structure adds the TRAIT_TURF_COVERED to its turf.
|
||||
var/creates_cover = FALSE
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
anchored = TRUE
|
||||
flags = ON_BORDER
|
||||
flags_2 = RAD_PROTECT_CONTENTS_2
|
||||
flags_ricochet = RICOCHET_HARD
|
||||
receive_ricochet_chance_mod = 0.5
|
||||
can_be_unanchored = TRUE
|
||||
max_integrity = 25
|
||||
resistance_flags = ACID_PROOF
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
explosion_block = 1
|
||||
|
||||
flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2
|
||||
flags_ricochet = RICOCHET_HARD
|
||||
rad_insulation = RAD_MEDIUM_INSULATION
|
||||
|
||||
thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT
|
||||
@@ -154,17 +155,6 @@
|
||||
else
|
||||
update_icon()
|
||||
|
||||
/turf/simulated/wall/handle_ricochet(obj/item/projectile/P) //A huge pile of shitcode!
|
||||
var/turf/p_turf = get_turf(P)
|
||||
var/face_direction = get_dir(src, p_turf)
|
||||
var/face_angle = dir2angle(face_direction)
|
||||
var/incidence_s = GET_ANGLE_OF_INCIDENCE(face_angle, (P.Angle + 180))
|
||||
if(abs(incidence_s) > 90 && abs(incidence_s) < 270)
|
||||
return FALSE
|
||||
var/new_angle_s = SIMPLIFY_DEGREES(face_angle + incidence_s)
|
||||
P.set_angle(new_angle_s)
|
||||
return TRUE
|
||||
|
||||
/turf/simulated/wall/dismantle_wall(devastated = FALSE, explode = FALSE)
|
||||
if(devastated)
|
||||
devastate_wall()
|
||||
|
||||
@@ -220,7 +220,7 @@
|
||||
icon_state = "plastinum_wall-0"
|
||||
base_icon_state = "plastinum_wall"
|
||||
explosion_block = 3
|
||||
flags_2 = CHECK_RICOCHET_2
|
||||
flags_ricochet = RICOCHET_SHINY | RICOCHET_HARD
|
||||
sheet_type = /obj/item/stack/sheet/mineral/titanium
|
||||
smoothing_flags = SMOOTH_BITMASK | SMOOTH_DIAGONAL_CORNERS
|
||||
smoothing_groups = list(SMOOTH_GROUP_TITANIUM_WALLS, SMOOTH_GROUP_WINDOW_FULLTILE_SHUTTLE)
|
||||
|
||||
@@ -61,16 +61,4 @@
|
||||
brute_resist = 0.5
|
||||
explosion_block = 2
|
||||
point_return = 9
|
||||
flags_2 = CHECK_RICOCHET_2
|
||||
|
||||
/obj/structure/blob/shield/reflective/handle_ricochet(obj/item/projectile/P)
|
||||
var/turf/p_turf = get_turf(P)
|
||||
var/face_direction = get_dir(src, p_turf)
|
||||
var/face_angle = dir2angle(face_direction)
|
||||
var/incidence_s = GET_ANGLE_OF_INCIDENCE(face_angle, (P.Angle + 180))
|
||||
if(abs(incidence_s) > 90 && abs(incidence_s) < 270)
|
||||
return FALSE
|
||||
var/new_angle_s = SIMPLIFY_DEGREES(face_angle + incidence_s)
|
||||
P.set_angle(new_angle_s)
|
||||
visible_message("<span class='warning'>[P] reflects off [src]!</span>")
|
||||
return TRUE
|
||||
flags_ricochet = RICOCHET_SHINY
|
||||
|
||||
@@ -66,9 +66,6 @@
|
||||
var/immolate = 0
|
||||
var/dismemberment = 0 //The higher the number, the greater the bonus to dismembering. 0 will not dismember at all.
|
||||
var/impact_effect_type //what type of impact effect to show when hitting something
|
||||
var/ricochets = 0
|
||||
var/ricochets_max = 2
|
||||
var/ricochet_chance = 30
|
||||
|
||||
var/log_override = FALSE //whether print to admin attack logs or just keep it in the diary
|
||||
|
||||
@@ -114,6 +111,27 @@
|
||||
var/impact_light_color_override
|
||||
var/hitscan_duration = 0.3 SECONDS
|
||||
|
||||
/// how many times we've ricochet'd so far (instance variable, not a stat)
|
||||
var/ricochets = 0
|
||||
/// how many times we can ricochet max
|
||||
var/ricochets_max = 0
|
||||
/// how many times we have to ricochet min (unless we hit an atom we can ricochet off)
|
||||
var/min_ricochets = 0
|
||||
/// 0-100 (or more, I guess), the base chance of ricocheting, before being modified by the atom we shoot and our chance decay
|
||||
var/ricochet_chance = 0
|
||||
/// 0-1 (or more, I guess) multiplier, the ricochet_chance is modified by multiplying this after each ricochet
|
||||
var/ricochet_decay_chance = 0.7
|
||||
/// 0-1 (or more, I guess) multiplier, the projectile's damage is modified by multiplying this after each ricochet
|
||||
var/ricochet_decay_damage = 0.7
|
||||
/// On ricochet, if nonzero, we consider all mobs within this range of our projectile at the time of ricochet to home in on like Revolver Ocelot, as governed by ricochet_auto_aim_angle
|
||||
var/ricochet_auto_aim_range = 0
|
||||
/// On ricochet, if ricochet_auto_aim_range is nonzero, we'll consider any mobs within this range of the normal angle of incidence to home in on, higher = more auto aim
|
||||
var/ricochet_auto_aim_angle = 30
|
||||
/// the angle of impact must be within this many degrees of the struck surface, set to 0 to allow any angle
|
||||
var/ricochet_incidence_leeway = 40
|
||||
/// Can our ricochet autoaim hit our firer?
|
||||
var/ricochet_shoots_firer = TRUE
|
||||
|
||||
/obj/item/projectile/New()
|
||||
return ..()
|
||||
|
||||
@@ -429,7 +447,21 @@
|
||||
|
||||
|
||||
/obj/item/projectile/proc/on_ricochet(atom/A)
|
||||
return
|
||||
if(!ricochet_auto_aim_angle || !ricochet_auto_aim_range)
|
||||
return
|
||||
|
||||
var/mob/living/unlucky_sob
|
||||
var/best_angle = ricochet_auto_aim_angle
|
||||
for(var/mob/living/L in range(ricochet_auto_aim_range, src.loc))
|
||||
if(L.stat == DEAD || !isInSight(src, L) || (!ricochet_shoots_firer && L == firer))
|
||||
continue
|
||||
var/our_angle = abs(closer_angle_difference(Angle, get_angle(src.loc, L.loc)))
|
||||
if(our_angle < best_angle)
|
||||
best_angle = our_angle
|
||||
unlucky_sob = L
|
||||
|
||||
if(unlucky_sob)
|
||||
set_angle(get_angle(src, unlucky_sob.loc))
|
||||
|
||||
/obj/item/projectile/proc/check_ricochet()
|
||||
if(prob(ricochet_chance))
|
||||
@@ -437,8 +469,12 @@
|
||||
return FALSE
|
||||
|
||||
/obj/item/projectile/proc/check_ricochet_flag(atom/A)
|
||||
if(A.flags_2 & CHECK_RICOCHET_2)
|
||||
if((flag in list(ENERGY, LASER)) && (A.flags_ricochet & RICOCHET_SHINY))
|
||||
return TRUE
|
||||
|
||||
if((flag in list(BOMB, BULLET)) && (A.flags_ricochet & RICOCHET_HARD))
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/obj/item/projectile/set_angle(new_angle)
|
||||
|
||||
Reference in New Issue
Block a user