[DNM][DNM][WIP] Projectile backend code port and update
Ports#54924, #65061, #59804 from /tg. adds auxiliary code from /tg to make code work.
This commit is contained in:
@@ -46,10 +46,10 @@
|
||||
else
|
||||
adjustFireLoss(5)
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/CanPass(atom/movable/mover, turf/target)
|
||||
/mob/living/simple_animal/hostile/blob/CanAllowThrough(atom/movable/mover, turf/target)
|
||||
. = ..()
|
||||
if(istype(mover, /obj/structure/blob))
|
||||
return 1
|
||||
return ..()
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/Process_Spacemove(movement_dir = 0)
|
||||
for(var/obj/structure/blob/B in range(1, src))
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
opacity = 0
|
||||
anchored = TRUE
|
||||
layer = BELOW_MOB_LAYER
|
||||
pass_flags_self = PASSBLOB
|
||||
CanAtmosPass = ATMOS_PASS_PROC
|
||||
var/point_return = 0 //How many points the blob gets back when it removes a blob of that type. If less than 0, blob cannot be removed.
|
||||
max_integrity = 30
|
||||
@@ -67,20 +68,9 @@
|
||||
/obj/structure/blob/BlockThermalConductivity()
|
||||
return atmosblock
|
||||
|
||||
/obj/structure/blob/CanPass(atom/movable/mover, turf/target)
|
||||
if(istype(mover) && (mover.pass_flags & PASSBLOB))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/structure/blob/CanAtmosPass(turf/T)
|
||||
return !atmosblock
|
||||
|
||||
/obj/structure/blob/CanAStarPass(ID, dir, caller)
|
||||
. = 0
|
||||
if(ismovable(caller))
|
||||
var/atom/movable/mover = caller
|
||||
. = . || (mover.pass_flags & PASSBLOB)
|
||||
|
||||
/obj/structure/blob/update_icon() //Updates color based on overmind color if we have an overmind.
|
||||
if(overmind)
|
||||
add_atom_colour(overmind.blobstrain.color, FIXED_COLOUR_PRIORITY)
|
||||
|
||||
@@ -139,12 +139,12 @@
|
||||
else
|
||||
death()
|
||||
|
||||
/mob/living/simple_animal/hostile/swarmer/CanPass(atom/movable/O)
|
||||
/mob/living/simple_animal/hostile/swarmer/CanAllowThrough(atom/movable/O)
|
||||
. = ..()
|
||||
if(istype(O, /obj/item/projectile/beam/disabler))//Allows for swarmers to fight as a group without wasting their shots hitting each other
|
||||
return 1
|
||||
if(isswarmer(O))
|
||||
return 1
|
||||
..()
|
||||
|
||||
////CTRL CLICK FOR SWARMERS AND SWARMER_ACT()'S////
|
||||
/mob/living/simple_animal/hostile/swarmer/AttackingTarget()
|
||||
@@ -698,11 +698,12 @@
|
||||
light_range = MINIMUM_USEFUL_LIGHT_RANGE
|
||||
max_integrity = 50
|
||||
|
||||
/obj/structure/swarmer/blockade/CanPass(atom/movable/O)
|
||||
/obj/structure/swarmer/blockade/CanAllowThrough(atom/movable/O)
|
||||
. = ..()
|
||||
if(isswarmer(O))
|
||||
return 1
|
||||
return TRUE
|
||||
if(istype(O, /obj/item/projectile/beam/disabler))
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/swarmer/proc/CreateSwarmer()
|
||||
set name = "Replicate"
|
||||
|
||||
@@ -220,7 +220,8 @@
|
||||
icon_state = "ibeam"
|
||||
anchored = TRUE
|
||||
density = FALSE
|
||||
pass_flags = PASSTABLE|PASSGLASS|PASSGRILLE|LETPASSTHROW
|
||||
pass_flags = PASSTABLE|PASSGLASS|PASSGRILLE
|
||||
pass_flags_self = LETPASSTHROW
|
||||
var/obj/item/assembly/infra/master
|
||||
|
||||
/obj/effect/beam/i_beam/Crossed(atom/movable/AM as mob|obj)
|
||||
|
||||
@@ -6,10 +6,11 @@
|
||||
invisibility = INVISIBILITY_MAXIMUM
|
||||
anchored = TRUE
|
||||
|
||||
/obj/effect/oneway/CanPass(atom/movable/mover, turf/target)
|
||||
/obj/effect/oneway/CanAllowThrough(atom/movable/mover, turf/target)
|
||||
. = ..()
|
||||
var/turf/T = get_turf(src)
|
||||
var/turf/MT = get_turf(mover)
|
||||
return ..() && (T == MT || get_dir(MT,T) == dir)
|
||||
return . && (T == MT || get_dir(MT,T) == dir)
|
||||
|
||||
|
||||
/obj/effect/wind
|
||||
|
||||
@@ -405,10 +405,10 @@
|
||||
/obj/item/projectile/bullet/ctf
|
||||
damage = 0
|
||||
|
||||
/obj/item/projectile/bullet/ctf/prehit(atom/target)
|
||||
/obj/item/projectile/bullet/ctf/prehit_pierce(atom/target)
|
||||
if(is_ctf_target(target))
|
||||
damage = 60
|
||||
return //PROJECTILE_PIERCE_NONE /// hey uhh don't hit anyone behind them
|
||||
return PROJECTILE_PIERCE_NONE /// hey uhh don't hit anyone behind them
|
||||
. = ..()
|
||||
|
||||
/obj/item/gun/ballistic/automatic/laser/ctf
|
||||
@@ -442,10 +442,10 @@
|
||||
damage = 0
|
||||
icon_state = "omnilaser"
|
||||
|
||||
/obj/item/projectile/beam/ctf/prehit(atom/target)
|
||||
/obj/item/projectile/beam/ctf/prehit_pierce(atom/target)
|
||||
if(is_ctf_target(target))
|
||||
damage = 150
|
||||
return //PROJECTILE_PIERCE_NONE /// hey uhhh don't hit anyone behind them
|
||||
return PROJECTILE_PIERCE_NONE /// hey uhhh don't hit anyone behind them
|
||||
. = ..()
|
||||
|
||||
/proc/is_ctf_target(atom/target)
|
||||
|
||||
@@ -523,7 +523,7 @@
|
||||
if(!override)
|
||||
qdel(src)
|
||||
|
||||
/obj/structure/spacevine/CanPass(atom/movable/mover, turf/target)
|
||||
/obj/structure/spacevine/CanAllowThrough(atom/movable/mover, turf/target)
|
||||
. = ..()
|
||||
if(isvineimmune(mover))
|
||||
return TRUE
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
name = "energy field"
|
||||
desc = "Get off my turf!"
|
||||
|
||||
/obj/effect/abstract/proximity_checker/advanced/field_turf/CanPass(atom/movable/AM, turf/target)
|
||||
/obj/effect/abstract/proximity_checker/advanced/field_turf/CanAllowThrough(atom/movable/AM, turf/target)
|
||||
. = ..()
|
||||
if(parent)
|
||||
return parent.field_turf_canpass(AM, src, target)
|
||||
@@ -48,7 +48,7 @@
|
||||
name = "energy field edge"
|
||||
desc = "Edgy description here."
|
||||
|
||||
/obj/effect/abstract/proximity_checker/advanced/field_edge/CanPass(atom/movable/AM, turf/target)
|
||||
/obj/effect/abstract/proximity_checker/advanced/field_edge/CanAllowThrough(atom/movable/AM, turf/target)
|
||||
. = ..()
|
||||
if(parent)
|
||||
return parent.field_edge_canpass(AM, src, target)
|
||||
|
||||
@@ -647,10 +647,10 @@ GLOBAL_LIST_INIT(hallucination_list, list(
|
||||
target.playsound_local(get_turf(airlock), 'sound/machines/boltsup.ogg',30,0,3)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/hallucination/fake_door_lock/CanPass(atom/movable/mover, turf/_target)
|
||||
/obj/effect/hallucination/fake_door_lock/CanAllowThrough(atom/movable/mover, turf/_target)
|
||||
. = ..()
|
||||
if(mover == target && airlock.density)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/hallucination/chat
|
||||
|
||||
|
||||
@@ -175,9 +175,6 @@
|
||||
step(I,direction)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/shade/howling_ghost/CanPass(atom/movable/mover, turf/target)
|
||||
return 1
|
||||
|
||||
///////////////////////////
|
||||
//Spookoween Insane Clown//
|
||||
///////////////////////////
|
||||
@@ -233,7 +230,7 @@
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/clown/insane/adjustHealth()
|
||||
. = ..()
|
||||
. = ..()
|
||||
if(prob(5))
|
||||
playsound(loc, 'sound/spookoween/insane_low_laugh.ogg', 300, 1)
|
||||
|
||||
|
||||
@@ -151,6 +151,7 @@
|
||||
density = FALSE
|
||||
anchored = TRUE
|
||||
buckle_lying = 0
|
||||
pass_flags_self = PASSTABLE | LETPASSTHROW
|
||||
var/burning = 0
|
||||
var/burn_icon = "bonfire_on_fire" //for a softer more burning embers icon, use "bonfire_warm"
|
||||
var/grill = FALSE
|
||||
@@ -163,13 +164,6 @@
|
||||
. = ..()
|
||||
StartBurning()
|
||||
|
||||
/obj/structure/bonfire/CanPass(atom/movable/mover, turf/target)
|
||||
if(istype(mover) && (mover.pass_flags & PASSTABLE))
|
||||
return TRUE
|
||||
if(mover.throwing)
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/obj/structure/bonfire/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/stack/rods) && !can_buckle && !grill)
|
||||
var/obj/item/stack/rods/R = W
|
||||
|
||||
@@ -131,7 +131,8 @@
|
||||
to_chat(M, "<span class='info'>[src] has been set to attack hostile wildlife.</span>")
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/mining_drone/CanPass(atom/movable/O)
|
||||
/mob/living/simple_animal/hostile/mining_drone/CanAllowThrough(atom/movable/O)
|
||||
. = ..()
|
||||
if(istype(O, /obj/item/projectile/kinetic))
|
||||
var/obj/item/projectile/kinetic/K = O
|
||||
if(K.kinetic_gun)
|
||||
@@ -141,7 +142,6 @@
|
||||
return TRUE
|
||||
if(istype(O, /obj/item/projectile/destabilizer))
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/mining_drone/proc/SetCollectBehavior()
|
||||
mode = MINEDRONE_COLLECT
|
||||
|
||||
@@ -166,9 +166,6 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
|
||||
QDEL_NULL(spawners_menu)
|
||||
return ..()
|
||||
|
||||
/mob/dead/CanPass(atom/movable/mover, turf/target)
|
||||
return 1
|
||||
|
||||
/*
|
||||
* This proc will update the icon of the ghost itself, with hair overlays, as well as the ghost image.
|
||||
* Please call update_icon(icon_state) from now on when you want to update the icon_state of the ghost,
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
dna.species.on_hit(P, src)
|
||||
|
||||
|
||||
/mob/living/carbon/human/bullet_act(obj/item/projectile/P, def_zone)
|
||||
/mob/living/carbon/human/bullet_act(obj/item/projectile/P, def_zone, piercing_hit = FALSE)
|
||||
if(dna && dna.species)
|
||||
var/spec_return = dna.species.bullet_act(P, src)
|
||||
if(spec_return)
|
||||
@@ -61,7 +61,7 @@
|
||||
|
||||
if(mind) //martial art stuff
|
||||
if(mind.martial_art && mind.martial_art.can_use(src)) //Some martial arts users can deflect projectiles!
|
||||
var/martial_art_result = mind.martial_art.on_projectile_hit(src, P, def_zone)
|
||||
var/martial_art_result = mind.martial_art.on_projectile_hit(src, P, def_zone, piercing_hit)
|
||||
if(!(martial_art_result == BULLET_ACT_HIT))
|
||||
return martial_art_result
|
||||
return ..()
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
else
|
||||
CRASH("Invalid rediretion mode [redirection_mode]")
|
||||
|
||||
/mob/living/bullet_act(obj/item/projectile/P, def_zone)
|
||||
/mob/living/bullet_act(obj/item/projectile/P, def_zone, piercing_hit = FALSE)
|
||||
var/totaldamage = P.damage
|
||||
var/final_percent = 0
|
||||
if(P.original != src || P.firer != src) //try to block or reflect the bullet, can't do so when shooting oneself
|
||||
@@ -81,7 +81,7 @@
|
||||
if(returned & BLOCK_REDIRECTED)
|
||||
return BULLET_ACT_FORCE_PIERCE
|
||||
if(returned & BLOCK_SUCCESS)
|
||||
P.on_hit(src, final_percent, def_zone)
|
||||
P.on_hit(src, final_percent, def_zone, piercing_hit)
|
||||
return BULLET_ACT_BLOCK
|
||||
totaldamage = block_calculate_resultant_damage(totaldamage, returnlist)
|
||||
var/armor = run_armor_check(def_zone, P.flag, null, null, P.armour_penetration, null)
|
||||
|
||||
@@ -20,12 +20,10 @@
|
||||
/mob/living/proc/update_density()
|
||||
density = !lying && !HAS_TRAIT(src, TRAIT_LIVING_NO_DENSITY)
|
||||
|
||||
/mob/living/CanPass(atom/movable/mover, turf/target)
|
||||
if((mover.pass_flags & PASSMOB))
|
||||
return TRUE
|
||||
if(istype(mover, /obj/item/projectile))
|
||||
var/obj/item/projectile/P = mover
|
||||
return !P.can_hit_target(src, P.permutated, src == P.original, TRUE)
|
||||
/mob/living/CanAllowThrough(atom/movable/mover, turf/target)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(mover.throwing)
|
||||
return (!density || lying)
|
||||
if(buckled == mover)
|
||||
@@ -41,7 +39,7 @@
|
||||
var/mob/living/L = mover //typecast first, check isliving and only check this if living using short circuit
|
||||
if(isliving(L) && lying && L.lying) //if we're both lying down and aren't already being thrown/shipped around, don't pass
|
||||
return FALSE
|
||||
return (!density || (isliving(mover)? L.can_move_under_living(src) : !mover.density))
|
||||
return (isliving(mover)? L.can_move_under_living(src) : !mover.density)
|
||||
|
||||
/mob/living/toggle_move_intent()
|
||||
. = ..()
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
"<span class='boldwarning'>You are thrown off of [src]!</span>")
|
||||
flash_act(affect_silicon = 1)
|
||||
|
||||
/mob/living/silicon/bullet_act(obj/item/projectile/P, def_zone)
|
||||
/mob/living/silicon/bullet_act(obj/item/projectile/P, def_zone, piercing_hit = FALSE)
|
||||
var/totaldamage = P.damage
|
||||
if(P.original != src || P.firer != src) //try to block or reflect the bullet, can't do so when shooting oneself
|
||||
var/list/returnlist = list()
|
||||
@@ -141,7 +141,7 @@
|
||||
"<span class='boldwarning'>You are knocked off of [src] by the [P]!</span>")
|
||||
unbuckle_mob(M)
|
||||
M.DefaultCombatKnockdown(40)
|
||||
P.on_hit(src, 0, def_zone)
|
||||
P.on_hit(src, 0, def_zone, 0, piercing_hit)
|
||||
return BULLET_ACT_HIT
|
||||
|
||||
/mob/living/silicon/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /atom/movable/screen/fullscreen/tiled/flash/static)
|
||||
|
||||
@@ -124,10 +124,10 @@
|
||||
apply_damage(damage, damagetype, null, getarmor(null, armorcheck))
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/bullet_act(obj/item/projectile/Proj)
|
||||
/mob/living/simple_animal/bullet_act(obj/item/projectile/Proj, def_zone, piercing_hit = FALSE)
|
||||
if(!Proj)
|
||||
return
|
||||
apply_damage(Proj.damage, Proj.damage_type)
|
||||
apply_damage(Proj.damage, Proj.damage_type, 0, piercing_hit)
|
||||
Proj.on_hit(src)
|
||||
return BULLET_ACT_HIT
|
||||
|
||||
|
||||
@@ -33,12 +33,12 @@
|
||||
|
||||
footstep_type = FOOTSTEP_MOB_BAREFOOT
|
||||
|
||||
/mob/living/simple_animal/hostile/jungle/mook/CanPass(atom/movable/O)
|
||||
/mob/living/simple_animal/hostile/jungle/mook/CanAllowThrough(atom/movable/O)
|
||||
. = ..()
|
||||
if(istype(O, /mob/living/simple_animal/hostile/jungle/mook))
|
||||
var/mob/living/simple_animal/hostile/jungle/mook/M = O
|
||||
if(M.attack_state == MOOK_ATTACK_ACTIVE && M.throwing)
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/jungle/mook/death()
|
||||
desc = "A deceased primitive. Upon closer inspection, it was suffering from severe cellular degeneration and its garments are machine made..."//Can you guess the twist
|
||||
|
||||
@@ -160,10 +160,10 @@ Difficulty: Hard
|
||||
severity = EXPLODE_LIGHT // puny mortals
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/CanPass(atom/movable/mover, turf/target)
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/CanAllowThrough(atom/movable/mover, turf/target)
|
||||
. = ..()
|
||||
if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination))
|
||||
return 1
|
||||
return ..()
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Goto(target, delay, minimum_distance)
|
||||
if(!charging)
|
||||
@@ -466,10 +466,10 @@ Difficulty: Hard
|
||||
new /obj/effect/decal/cleanable/blood(get_turf(src))
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/CanPass(atom/movable/mover, turf/target)
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/CanAllowThrough(atom/movable/mover, turf/target)
|
||||
. = ..()
|
||||
if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum)) // hallucinations should not be stopping bubblegum or eachother
|
||||
return 1
|
||||
return ..()
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/Life()
|
||||
return
|
||||
|
||||
@@ -490,7 +490,8 @@ Difficulty: Normal
|
||||
queue_smooth_neighbors(src)
|
||||
return ..()
|
||||
|
||||
/obj/effect/temp_visual/hierophant/wall/CanPass(atom/movable/mover, turf/target)
|
||||
/obj/effect/temp_visual/hierophant/wall/CanAllowThrough(atom/movable/mover, turf/target)
|
||||
. = ..()
|
||||
if(QDELETED(caster))
|
||||
return FALSE
|
||||
if(mover == caster.pulledby)
|
||||
@@ -501,7 +502,6 @@ Difficulty: Normal
|
||||
return TRUE
|
||||
if(mover == caster)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/effect/temp_visual/hierophant/chaser //a hierophant's chaser. follows target around, moving and producing a blast every speed deciseconds.
|
||||
duration = 98
|
||||
|
||||
@@ -394,7 +394,7 @@ SHITCODE AHEAD. BE ADVISED. Also comment extravaganza
|
||||
muzzle_type = /obj/effect/projectile/tracer/legion
|
||||
impact_type = /obj/effect/projectile/tracer/legion
|
||||
hitscan = TRUE
|
||||
movement_type = UNSTOPPABLE
|
||||
projectile_piercing = ALL
|
||||
|
||||
///Used for the legion turret tracer.
|
||||
/obj/effect/projectile/tracer/legion/tracer
|
||||
|
||||
@@ -72,14 +72,14 @@
|
||||
return
|
||||
|
||||
//if it's not our target, we ignore it
|
||||
/mob/living/simple_animal/hostile/asteroid/curseblob/CanPass(atom/movable/mover, turf/target)
|
||||
/mob/living/simple_animal/hostile/asteroid/curseblob/CanAllowThrough(atom/movable/mover, turf/target)
|
||||
. = ..()
|
||||
if(mover == set_target)
|
||||
return FALSE
|
||||
if(istype(mover, /obj/item/projectile))
|
||||
var/obj/item/projectile/P = mover
|
||||
if(P.firer == set_target)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
#define IGNORE_PROC_IF_NOT_TARGET(X) /mob/living/simple_animal/hostile/asteroid/curseblob/##X(AM) { if (AM == set_target) return ..(); }
|
||||
|
||||
|
||||
@@ -383,8 +383,7 @@ While using this makes the system rely on OnFire, it still gives options for tim
|
||||
ourelite = null
|
||||
return ..()
|
||||
|
||||
/obj/effect/temp_visual/elite_tumor_wall/CanPass(atom/movable/mover, turf/target)
|
||||
/obj/effect/temp_visual/elite_tumor_wall/CanAllowThrough(atom/movable/mover, turf/target)
|
||||
. = ..()
|
||||
if(mover == ourelite || mover == activator)
|
||||
return FALSE
|
||||
else
|
||||
return TRUE
|
||||
|
||||
@@ -231,11 +231,11 @@
|
||||
amount = -abs(amount)
|
||||
return ..() //Heals them
|
||||
|
||||
/mob/living/simple_animal/slime/bullet_act(obj/item/projectile/Proj)
|
||||
/mob/living/simple_animal/slime/bullet_act(obj/item/projectile/Proj, def_zone, piercing_hit = FALSE)
|
||||
attacked += 10
|
||||
if((Proj.damage_type == BURN))
|
||||
adjustBruteLoss(-abs(Proj.damage)) //fire projectiles heals slimes.
|
||||
Proj.on_hit(src)
|
||||
Proj.on_hit(src, 0, piercing_hit)
|
||||
return BULLET_ACT_BLOCK
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
mouse_drag_pointer = MOUSE_ACTIVE_POINTER
|
||||
throwforce = 10
|
||||
blocks_emissive = EMISSIVE_BLOCK_GENERIC
|
||||
|
||||
pass_flags_self = PASSMOB
|
||||
vis_flags = VIS_INHERIT_PLANE //when this be added to vis_contents of something it inherit something.plane, important for visualisation of mob in openspace.
|
||||
|
||||
attack_hand_is_action = TRUE
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
eat_dir = WEST
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/plumbing/grinder_chemical/CanPass(atom/movable/AM)
|
||||
/obj/machinery/plumbing/grinder_chemical/CanAllowThrough(atom/movable/AM)
|
||||
. = ..()
|
||||
if(!anchored)
|
||||
return
|
||||
|
||||
@@ -100,10 +100,10 @@
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/field/CanPass(atom/movable/mover, turf/target)
|
||||
/obj/machinery/field/CanAllowThrough(atom/movable/mover, turf/target)
|
||||
. = ..()
|
||||
if(hasShocked || isliving(mover) || ismachinery(mover) || isstructure(mover) || ismecha(mover))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/machinery/field/proc/shock(mob/living/user)
|
||||
var/shock_damage = min(rand(30,40),rand(30,40))
|
||||
|
||||
@@ -232,14 +232,14 @@
|
||||
kinetic_gun = null
|
||||
return ..()
|
||||
|
||||
/obj/item/projectile/kinetic/prehit(atom/target)
|
||||
/obj/item/projectile/kinetic/prehit_pierce(atom/target)
|
||||
. = ..()
|
||||
if(.)
|
||||
if(kinetic_gun)
|
||||
var/list/mods = kinetic_gun.get_modkits()
|
||||
for(var/obj/item/borg/upgrade/modkit/M in mods)
|
||||
M.projectile_prehit(src, target, kinetic_gun)
|
||||
if(!lavaland_equipment_pressure_check(get_turf(target)))
|
||||
if(!pressure_decrease_active && !lavaland_equipment_pressure_check(get_turf(target)))
|
||||
name = "weakened [name]"
|
||||
damage = damage * pressure_decrease
|
||||
pressure_decrease_active = TRUE
|
||||
|
||||
@@ -427,11 +427,9 @@
|
||||
var/aoe_mob_damage = 30
|
||||
var/impact_structure_damage = 0
|
||||
var/impact_direct_damage = 0
|
||||
var/turf/cached
|
||||
var/list/pierced = list()
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/proc/AOE(turf/epicenter)
|
||||
set waitfor = FALSE
|
||||
if(!epicenter)
|
||||
return
|
||||
new /obj/effect/temp_visual/explosion/fast(epicenter)
|
||||
@@ -447,31 +445,22 @@
|
||||
continue
|
||||
O.take_damage(aoe_structure_damage * get_damage_coeff(O), BURN, "laser", FALSE)
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/proc/check_pierce(atom/target)
|
||||
if(!do_pierce)
|
||||
return FALSE
|
||||
if(pierced[target]) //we already pierced them go away
|
||||
return TRUE
|
||||
if(isclosedturf(target))
|
||||
if(wall_pierce++ < wall_pierce_amount)
|
||||
if(prob(wall_devastate))
|
||||
if(iswallturf(target))
|
||||
var/turf/closed/wall/W = target
|
||||
W.dismantle_wall(TRUE, TRUE)
|
||||
else
|
||||
target.ex_act(EXPLODE_HEAVY)
|
||||
return TRUE
|
||||
if(ismovable(target))
|
||||
var/atom/movable/AM = target
|
||||
if(AM.density && !AM.CanPass(src, get_turf(target)) && !ismob(AM))
|
||||
if(structure_pierce < structure_pierce_amount)
|
||||
if(isobj(AM))
|
||||
var/obj/O = AM
|
||||
O.take_damage((impact_structure_damage + aoe_structure_damage) * structure_bleed_coeff * get_damage_coeff(AM), BURN, "energy", FALSE)
|
||||
pierced[AM] = TRUE
|
||||
structure_pierce++
|
||||
return TRUE
|
||||
return FALSE
|
||||
/obj/item/projectile/beam/beam_rifle/proc/check_pierce(atom/A)
|
||||
if(isclosedturf(A) && (wall_pierce < wall_pierce_amount))
|
||||
if(prob(wall_devastate))
|
||||
if(iswallturf(A))
|
||||
var/turf/closed/wall/W = A
|
||||
W.dismantle_wall(TRUE, TRUE)
|
||||
else
|
||||
target.ex_act(EXPLODE_HEAVY)
|
||||
++wall_pierce
|
||||
return PROJECTILE_PIERCE_PHASE // yeah this gun is a snowflakey piece of garbage - Silly-Cons
|
||||
if(isobj(A) && (structure_pierce < structure_pierce_amount))
|
||||
++structure_pierce
|
||||
var/obj/O = A
|
||||
O.take_damage((impact_structure_damage + aoe_structure_damage) * structure_bleed_coeff * get_damage_coeff(A), BURN, ENERGY, FALSE)
|
||||
return PROJECTILE_PIERCE_PHASE // ditto and this could be refactored to on_hit honestly - Silly-Cons
|
||||
return ..()
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/proc/get_damage_coeff(atom/target)
|
||||
if(istype(target, /obj/machinery/door))
|
||||
@@ -491,32 +480,18 @@
|
||||
L.adjustFireLoss(impact_direct_damage)
|
||||
L.emote("scream")
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/proc/handle_hit(atom/target)
|
||||
/obj/item/projectile/beam/beam_rifle/proc/handle_hit(atom/target, piercing_hit = FALSE)
|
||||
set waitfor = FALSE
|
||||
if(!cached && !QDELETED(target))
|
||||
cached = get_turf(target)
|
||||
if(nodamage)
|
||||
return FALSE
|
||||
playsound(cached, 'sound/effects/explosion3.ogg', 100, 1)
|
||||
AOE(cached)
|
||||
playsound(src, 'sound/effects/explosion3.ogg', 100, TRUE)
|
||||
if(!piercing_hit)
|
||||
AOE(get_turf(target) || get_turf(src))
|
||||
if(!QDELETED(target))
|
||||
handle_impact(target)
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/Bump(atom/target)
|
||||
if(check_pierce(target))
|
||||
permutated += target
|
||||
trajectory_ignore_forcemove = TRUE
|
||||
forceMove(target.loc)
|
||||
trajectory_ignore_forcemove = FALSE
|
||||
return FALSE
|
||||
if(!QDELETED(target))
|
||||
cached = get_turf(target)
|
||||
. = ..()
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/on_hit(atom/target, blocked = FALSE)
|
||||
if(!QDELETED(target))
|
||||
cached = get_turf(target)
|
||||
handle_hit(target)
|
||||
/obj/projectile/beam/beam_rifle/on_hit(atom/target, blocked = FALSE, piercing_hit = FALSE)
|
||||
handle_hit(target, piercing_hit)
|
||||
. = ..()
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/hitscan
|
||||
@@ -547,6 +522,9 @@
|
||||
hitscan_light_intensity = 0
|
||||
hitscan_light_color_override = "#99ff99"
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/prehit(atom/target)
|
||||
/obj/projectile/beam/beam_rifle/hitscan/aiming_beam/prehit_pierce(atom/target)
|
||||
return PROJECTILE_DELETE_WITHOUT_HITTING
|
||||
|
||||
/obj/projectile/beam/beam_rifle/hitscan/aiming_beam/on_hit()
|
||||
qdel(src)
|
||||
return FALSE
|
||||
return BULLET_ACT_BLOCK
|
||||
|
||||
@@ -114,7 +114,8 @@
|
||||
icon_state = "blastwave"
|
||||
damage = 0
|
||||
nodamage = FALSE
|
||||
movement_type = FLYING | UNSTOPPABLE
|
||||
movement_type = FLYING
|
||||
projectile_phasing = ALL // just blows up the turfs lmao - Silly-Cons
|
||||
var/heavyr = 0
|
||||
var/mediumr = 0
|
||||
var/lightr = 0
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
density = FALSE
|
||||
anchored = TRUE
|
||||
item_flags = ABSTRACT
|
||||
pass_flags = PASSTABLE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
movement_type = FLYING
|
||||
generic_canpass = FALSE
|
||||
animate_movement = NO_STEPS
|
||||
hitsound = 'sound/weapons/pierce.ogg'
|
||||
appearance_flags = PIXEL_SCALE
|
||||
@@ -40,6 +40,35 @@
|
||||
var/time_offset = 0
|
||||
var/datum/point/vector/trajectory
|
||||
var/trajectory_ignore_forcemove = FALSE //instructs forceMove to NOT reset our trajectory to the new location!
|
||||
/// We already impacted these things, do not impact them again. Used to make sure we can pierce things we want to pierce. Lazylist, typecache style (object = TRUE) for performance.
|
||||
var/list/impacted
|
||||
/// If TRUE, we can hit our firer.
|
||||
var/ignore_source_check = FALSE
|
||||
/// We are flagged PHASING temporarily to not stop moving when we Bump something but want to keep going anyways.
|
||||
var/temporary_unstoppable_movement = FALSE
|
||||
|
||||
/** PROJECTILE PIERCING
|
||||
* WARNING:
|
||||
* Projectile piercing MUST be done using these variables.
|
||||
* Ordinary passflags will be **IGNORED**.
|
||||
* The two flag variables below both use pass flags.
|
||||
* In the context of LETPASStHROW, it means the projectile will ignore things that are currently "in the air" from a throw.
|
||||
*
|
||||
* Also, projectiles sense hits using Bump(), and then pierce them if necessary.
|
||||
* They simply do not follow conventional movement rules.
|
||||
* NEVER flag a projectile as PHASING movement type.
|
||||
* If you so badly need to make one go through *everything*, override check_pierce() for your projectile to always return PROJECTILE_PIERCE_PHASE/HIT.
|
||||
*/
|
||||
/// The "usual" flags of pass_flags is used in that can_hit_target ignores these unless they're specifically targeted/clicked on. This behavior entirely bypasses process_hit if triggered, rather than phasing which uses prehit_pierce() to check.
|
||||
pass_flags = PASSTABLE
|
||||
/// If FALSE, allow us to hit something directly targeted/clicked/whatnot even if we're able to phase through it
|
||||
var/phasing_ignore_direct_target = FALSE
|
||||
/// Bitflag for things the projectile should just phase through entirely - No hitting unless direct target and [phasing_ignore_direct_target] is FALSE. Uses pass_flags flags.
|
||||
var/projectile_phasing = NONE
|
||||
/// Bitflag for things the projectile should hit, but pierce through without deleting itself. Defers to projectile_phasing. Uses pass_flags flags.
|
||||
var/projectile_piercing = NONE
|
||||
/// number of times we've pierced something. Incremented BEFORE bullet_act and on_hit proc!
|
||||
var/pierces = 0
|
||||
/// "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.
|
||||
@@ -117,8 +146,6 @@
|
||||
/// 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/damage = 10
|
||||
var/damage_type = BRUTE //BRUTE, BURN, TOX, OXY, CLONE are the only things that should be in here
|
||||
var/nodamage = 0 //Determines if the projectile will skip any damage inflictions
|
||||
@@ -150,8 +177,6 @@
|
||||
var/impact_effect_type //what type of impact effect to show when hitting something
|
||||
var/log_override = FALSE //is this type spammed enough to not log? (KAs)
|
||||
|
||||
var/temporary_unstoppable_movement = FALSE
|
||||
|
||||
///If defined, on hit we create an item of this type then call hitby() on the hit target with this, mainly used for embedding items (bullets) in targets
|
||||
var/shrapnel_type
|
||||
///If TRUE, hit mobs even if they're on the floor and not our target
|
||||
@@ -167,7 +192,6 @@
|
||||
|
||||
/obj/item/projectile/Initialize()
|
||||
. = ..()
|
||||
permutated = list()
|
||||
decayedRange = range
|
||||
if(embedding)
|
||||
updateEmbedding()
|
||||
@@ -201,10 +225,7 @@
|
||||
else //when a limb is missing the damage is actually passed to the chest
|
||||
return BODY_ZONE_CHEST
|
||||
|
||||
/obj/item/projectile/proc/prehit(atom/target)
|
||||
return TRUE
|
||||
|
||||
/obj/item/projectile/proc/on_hit(atom/target, blocked = FALSE)
|
||||
/obj/item/projectile/proc/on_hit(atom/target, blocked = FALSE, pierce_hit)
|
||||
if(fired_from)
|
||||
SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_ON_HIT, firer, target, Angle)
|
||||
|
||||
@@ -238,6 +259,11 @@
|
||||
if(!isliving(target))
|
||||
if(impact_effect_type && !hitscan)
|
||||
new impact_effect_type(target_loca, hitx, hity)
|
||||
if(isturf(target) && hitsound_wall)
|
||||
var/volume = clamp(vol_by_damage() + 20, 0, 100)
|
||||
if(suppressed)
|
||||
volume = 5
|
||||
playsound(loc, hitsound_wall, volume, TRUE, -1)
|
||||
return BULLET_ACT_HIT
|
||||
|
||||
var/mob/living/L = target
|
||||
@@ -278,7 +304,7 @@
|
||||
else
|
||||
if(hitsound)
|
||||
var/volume = vol_by_damage()
|
||||
playsound(loc, hitsound, volume, 1, -1)
|
||||
playsound(src, hitsound, volume, 1, -1)
|
||||
L.visible_message("<span class='danger'>[L] is hit by \a [src][organ_hit_text]!</span>", \
|
||||
"<span class='userdanger'>[L] is hit by \a [src][organ_hit_text]!</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
if(candink && def_zone == BODY_ZONE_HEAD)
|
||||
@@ -298,7 +324,7 @@
|
||||
|
||||
/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
|
||||
|
||||
@@ -327,95 +353,267 @@
|
||||
beam_segments[beam_index] = null
|
||||
|
||||
/obj/item/projectile/Bump(atom/A)
|
||||
if(!trajectory)
|
||||
SEND_SIGNAL(src, COMSIG_MOVABLE_BUMP, A)
|
||||
if(!can_hit_target(A, A == original, TRUE))
|
||||
return
|
||||
Impact(A)
|
||||
|
||||
/**
|
||||
* Called when the projectile hits something
|
||||
* This can either be from it bumping something,
|
||||
* or it passing over a turf/being crossed and scanning that there is infact
|
||||
* a valid target it needs to hit.
|
||||
* This target isn't however necessarily WHAT it hits
|
||||
* that is determined by process_hit and select_target.
|
||||
*
|
||||
* Furthermore, this proc shouldn't check can_hit_target - this should only be called if can hit target is already checked.
|
||||
* Also, we select_target to find what to process_hit first.
|
||||
*/
|
||||
/obj/projectile/proc/Impact(atom/A)
|
||||
if(!trajectory)
|
||||
qdel(src)
|
||||
return FALSE
|
||||
if(impacted[A]) // NEVER doublehit - Silly-Cons
|
||||
return FALSE
|
||||
var/datum/point/pcache = trajectory.copy_to()
|
||||
var/turf/T = get_turf(A)
|
||||
if(check_ricochet_flag(A) && check_ricochet(A)) //if you can ricochet, attempt to ricochet off the object
|
||||
ricochets++
|
||||
if(A.handle_ricochet(src))
|
||||
on_ricochet(A) //if allowed, use autoaim to ricochet into someone, otherwise default to ricocheting off the object from above
|
||||
var/datum/point/pcache = trajectory.copy_to()
|
||||
if(hitscan)
|
||||
store_hitscan_collision(pcache)
|
||||
impacted = list() // Shoot a x-ray laser at a pair of mirrors I dare you
|
||||
ignore_source_check = TRUE // Firer is no longer immune
|
||||
decayedRange = max(0, decayedRange - reflect_range_decrease)
|
||||
ricochet_chance *= ricochet_decay_chance
|
||||
damage *= ricochet_decay_damage
|
||||
range = decayedRange
|
||||
if(hitscan)
|
||||
store_hitscan_collision(pcache)
|
||||
return TRUE
|
||||
|
||||
var/distance = get_dist(T, starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations.
|
||||
if(def_zone && check_zone(def_zone) != BODY_ZONE_CHEST)
|
||||
def_zone = ran_zone(def_zone, max(100-(7*distance), 5) * zone_accuracy_factor) //Lower accurancy/longer range tradeoff. 7 is a balanced number to use.
|
||||
|
||||
if(isturf(A) && hitsound_wall)
|
||||
var/volume = clamp(vol_by_damage() + 20, 0, 100)
|
||||
if(suppressed)
|
||||
volume = 5
|
||||
playsound(loc, hitsound_wall, volume, 1, -1)
|
||||
return process_hit(T, select_target(T, A)) // SELECT TARGET FIRST!
|
||||
|
||||
return process_hit(T, select_target(T, A))
|
||||
|
||||
#define QDEL_SELF 1 //Delete if we're not UNSTOPPABLE flagged non-temporarily
|
||||
#define DO_NOT_QDEL 2 //Pass through.
|
||||
#define FORCE_QDEL 3 //Force deletion.
|
||||
|
||||
/obj/item/projectile/proc/process_hit(turf/T, atom/target, qdel_self, hit_something = FALSE) //probably needs to be reworked entirely when pixel movement is done.
|
||||
if(QDELETED(src) || !T || !target) //We're done, nothing's left.
|
||||
if((qdel_self == FORCE_QDEL) || ((qdel_self == QDEL_SELF) && !temporary_unstoppable_movement && !(movement_type & UNSTOPPABLE)))
|
||||
qdel(src)
|
||||
/**
|
||||
* The primary workhorse proc of projectile impacts.
|
||||
* This is a RECURSIVE call - process_hit is called on the first selected target, and then repeatedly called if the projectile still hasn't been deleted.
|
||||
*
|
||||
* Order of operations:
|
||||
* 1. Checks if we are deleted, or if we're somehow trying to hit a null, in which case, bail out
|
||||
* 2. Adds the thing we're hitting to impacted so we can make sure we don't doublehit
|
||||
* 3. Checks piercing - stores this.
|
||||
* Afterwards:
|
||||
* Hit and delete, hit without deleting and pass through, pass through without hitting, or delete without hitting depending on result
|
||||
* If we're going through without hitting, find something else to hit if possible and recurse, set unstoppable movement to true
|
||||
* If we're deleting without hitting, delete and return
|
||||
* Otherwise, send signal of COMSIG_PROJECTILE_PREHIT to target
|
||||
* Then, hit, deleting ourselves if necessary.
|
||||
* @params
|
||||
* T - Turf we're on/supposedly hitting
|
||||
* target - target we're hitting
|
||||
* hit_something - only should be set by recursive calling by this proc - tracks if we hit something already
|
||||
*
|
||||
* Returns if we hit something.
|
||||
* - Silly-Cons
|
||||
*/
|
||||
/obj/item/projectile/proc/process_hit(turf/T, atom/target, hit_something = FALSE)
|
||||
// 1.
|
||||
if(QDELETED(src) || !T || !target)
|
||||
return
|
||||
// 2.
|
||||
impacted[target] = TRUE //hash lookup > in for performance in hit-checking
|
||||
// 3.
|
||||
var/mode = prehit_pierce(target)
|
||||
if(mode == PROJECTILE_DELETE_WITHOUT_HITTING)
|
||||
qdel(src)
|
||||
return hit_something
|
||||
permutated |= target //Make sure we're never hitting it again. If we ever run into weirdness with piercing projectiles needing to hit something multiple times.. well.. that's a to-do.
|
||||
if(!prehit(target))
|
||||
return process_hit(T, select_target(T), qdel_self, hit_something) //Hit whatever else we can since that didn't work.
|
||||
var/result = target.bullet_act(src, def_zone)
|
||||
if(result == BULLET_ACT_FORCE_PIERCE)
|
||||
if(!(movement_type & UNSTOPPABLE))
|
||||
else if(mode == PROJECTILE_PIERCE_PHASE)
|
||||
if(!(movement_type & PHASING))
|
||||
temporary_unstoppable_movement = TRUE
|
||||
movement_type |= UNSTOPPABLE
|
||||
return process_hit(T, select_target(T), qdel_self, TRUE) //Hit whatever else we can since we're piercing through but we're still on the same tile.
|
||||
else if(result == BULLET_ACT_TURF) //We hit the turf but instead we're going to also hit something else on it.
|
||||
return process_hit(T, select_target(T), QDEL_SELF, TRUE)
|
||||
else //Whether it hit or blocked, we're done!
|
||||
qdel_self = QDEL_SELF
|
||||
hit_something = TRUE
|
||||
if((qdel_self == FORCE_QDEL) || ((qdel_self == QDEL_SELF) && !temporary_unstoppable_movement && !(movement_type & UNSTOPPABLE)))
|
||||
movement_type |= PHASING
|
||||
return process_hit(T, select_target(T, target), hit_something) // try to hit something else
|
||||
// at this point we are going to hit the thing
|
||||
// in which case send signal to it
|
||||
SEND_SIGNAL(target, COMSIG_PROJECTILE_PREHIT, args)
|
||||
if(mode == PROJECTILE_PIERCE_HIT)
|
||||
++pierces
|
||||
hit_something = TRUE
|
||||
var/result = target.bullet_act(src, def_zone, mode == PROJECTILE_PIERCE_HIT)
|
||||
if((result == BULLET_ACT_FORCE_PIERCE) || (mode == PROJECTILE_PIERCE_HIT))
|
||||
if(!(movement_type & PHASING))
|
||||
temporary_unstoppable_movement = TRUE
|
||||
movement_type |= PHASING
|
||||
return process_hit(T, select_target(T, target), TRUE)
|
||||
qdel(src)
|
||||
return hit_something
|
||||
|
||||
#undef QDEL_SELF
|
||||
#undef DO_NOT_QDEL
|
||||
#undef FORCE_QDEL
|
||||
|
||||
/obj/item/projectile/proc/select_target(turf/T, atom/target) //Select a target from a turf.
|
||||
if((original in T) && can_hit_target(original, permutated, TRUE, TRUE))
|
||||
/**
|
||||
* Selects a target to hit from a turf
|
||||
*
|
||||
* @params
|
||||
* T - The turf
|
||||
* target - The "preferred" atom to hit, usually what we Bumped() first.
|
||||
*
|
||||
* Priority:
|
||||
* 0. Anything that is already in impacted is ignored no matter what. Furthermore, in any bracket, if the target atom parameter is in it, that's hit first.
|
||||
* Furthermore, can_hit_target is always checked. This (entire proc) is PERFORMANCE OVERHEAD!! But, it shouldn't be ""too"" bad and I frankly don't have a better *generic non snowflakey* way that I can think of right now at 3 AM.
|
||||
* FURTHERMORE, mobs/objs have a density check from can_hit_target - to hit non dense objects over a turf, you must click on them, same for mobs that usually wouldn't get hit.
|
||||
* 1. The thing originally aimed at/clicked on
|
||||
* 2. Mobs - picks lowest buckled mob to prevent scarp piggybacking memes
|
||||
* 3. Objs
|
||||
* 4. Turf
|
||||
* 5. Nothing
|
||||
*/
|
||||
/obj/projectile/proc/select_target(turf/T, atom/target)
|
||||
// 1. original
|
||||
if(can_hit_target(original, TRUE, FALSE))
|
||||
return original
|
||||
if(target && can_hit_target(target, permutated, target == original, TRUE))
|
||||
return target
|
||||
var/list/mob/living/possible_mobs = typecache_filter_list(T, GLOB.typecache_mob)
|
||||
var/list/mob/mobs = list()
|
||||
for(var/mob/living/M in possible_mobs)
|
||||
if(!can_hit_target(M, permutated, M == original, TRUE))
|
||||
var/list/atom/possible = list() // let's define these ONCE
|
||||
var/list/atom/considering = list()
|
||||
// 2. mobs
|
||||
possible = typecache_filter_list(T, GLOB.typecache_living) // living only
|
||||
for(var/i in possible)
|
||||
if(!can_hit_target(i, i == original, TRUE))
|
||||
continue
|
||||
mobs += M
|
||||
var/mob/M = safepick(mobs)
|
||||
if(M)
|
||||
considering += i
|
||||
if(considering.len)
|
||||
var/mob/living/M = pick(considering)
|
||||
return M.lowest_buckled_mob()
|
||||
var/list/obj/possible_objs = typecache_filter_list(T, GLOB.typecache_machine_or_structure)
|
||||
var/list/obj/objs = list()
|
||||
for(var/obj/O in possible_objs)
|
||||
if(!can_hit_target(O, permutated, O == original, TRUE))
|
||||
considering.len = 0
|
||||
// 3. objs
|
||||
possible = typecache_filter_list(T, GLOB.typecache_machine_or_structure) // because why are items ever dense?
|
||||
for(var/i in possible)
|
||||
if(!can_hit_target(i, i == original, TRUE))
|
||||
continue
|
||||
objs += O
|
||||
var/obj/O = safepick(objs)
|
||||
if(O)
|
||||
if(length(O.buckled_mobs))
|
||||
return pick(O.buckled_mobs)
|
||||
return O
|
||||
//Nothing else is here that we can hit, hit the turf if we haven't.
|
||||
if(!(T in permutated) && can_hit_target(T, permutated, T == original, TRUE))
|
||||
considering += i
|
||||
if(considering.len)
|
||||
return pick(considering)
|
||||
// 4. turf
|
||||
if(can_hit_target(T, T == original, TRUE))
|
||||
return T
|
||||
//Returns null if nothing at all was found.
|
||||
// 5. nothing
|
||||
// (returns null)
|
||||
|
||||
//Returns true if the target atom is on our current turf and above the right layer
|
||||
//If direct target is true it's the originally clicked target.
|
||||
/obj/projectile/proc/can_hit_target(atom/target, direct_target = FALSE, ignore_loc = FALSE)
|
||||
if(QDELETED(target) || impacted[target])
|
||||
return FALSE
|
||||
if(!ignore_loc && (loc != target.loc))
|
||||
return FALSE
|
||||
// if pass_flags match, pass through entirely
|
||||
if(target.pass_flags_self & pass_flags) // phasing
|
||||
return FALSE
|
||||
if(!ignore_source_check && firer)
|
||||
var/mob/M = firer
|
||||
if((target == firer) || ((target == firer.loc) && ismecha(firer.loc)) || (target in firer.buckled_mobs) || (istype(M) && (M.buckled == target)))
|
||||
return FALSE
|
||||
if(target.density) //This thing blocks projectiles, hit it regardless of layer/mob stuns/etc.
|
||||
return TRUE
|
||||
if(!isliving(target))
|
||||
if(isturf(target)) // non dense turfs
|
||||
return FALSE
|
||||
if(target.layer < PROJECTILE_HIT_THRESHHOLD_LAYER)
|
||||
return FALSE
|
||||
else if(!direct_target) // non dense objects do not get hit unless specifically clicked
|
||||
return FALSE
|
||||
else
|
||||
var/mob/living/L = target
|
||||
if(direct_target)
|
||||
return TRUE
|
||||
// If target not able to use items, move and stand - or if they're just dead, pass over.
|
||||
if(L.stat == DEAD || (!hit_stunned_targets && HAS_TRAIT(L, TRAIT_IMMOBILIZED) && HAS_TRAIT(L, TRAIT_FLOORED) && HAS_TRAIT(L, TRAIT_HANDS_BLOCKED)))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Scan if we should hit something and hit it if we need to
|
||||
* The difference between this and handling in Impact is
|
||||
* In this we strictly check if we need to Impact() something in specific
|
||||
* If we do, we do
|
||||
* We don't even check if it got hit already - Impact() does that
|
||||
* In impact there's more code for selecting WHAT to hit
|
||||
* So this proc is more of checking if we should hit something at all BY having an atom cross us.
|
||||
*/
|
||||
/obj/projectile/proc/scan_crossed_hit(atom/movable/A)
|
||||
if(can_hit_target(A, direct_target = (A == original)))
|
||||
Impact(A)
|
||||
|
||||
/**
|
||||
* Scans if we should hit something on the turf we just moved to if we haven't already
|
||||
*
|
||||
* This proc is a little high in overhead but allows us to not snowflake CanPass in living and other things.
|
||||
*/
|
||||
/obj/projectile/proc/scan_moved_turf()
|
||||
// Optimally, we scan: mobs --> objs --> turf for impact
|
||||
// but, overhead is a thing and 2 for loops every time it moves is a no-go.
|
||||
// realistically, since we already do select_target in impact, we can not do that
|
||||
// and hope projectiles get refactored again in the future to have a less stupid impact detection system
|
||||
// that hopefully won't also involve a ton of overhead
|
||||
if(can_hit_target(original, TRUE, FALSE))
|
||||
Impact(original) // try to hit thing clicked on
|
||||
// else, try to hit mobs
|
||||
else // because if we impacted original and pierced we'll already have select target'd and hit everything else we should be hitting
|
||||
for(var/mob/M in loc) // so I guess we're STILL doing a for loop of mobs because living movement would otherwise have snowflake code for projectile CanPass
|
||||
// so the snowflake vs performance is pretty arguable here
|
||||
if(can_hit_target(M, M == original, TRUE))
|
||||
Impact(M)
|
||||
break
|
||||
|
||||
/**
|
||||
* Projectile crossed: When something enters a projectile's tile, make sure the projectile hits it if it should be hitting it.
|
||||
*/
|
||||
/obj/projectile/Crossed(atom/movable/AM)
|
||||
. = ..()
|
||||
scan_crossed_hit(AM)
|
||||
|
||||
/**
|
||||
* Projectile can pass through
|
||||
* Used to not even attempt to Bump() or fail to Cross() anything we already hit.
|
||||
*/
|
||||
/obj/projectile/CanPassThrough(atom/blocker, turf/target, blocker_opinion)
|
||||
return impacted[blocker]? TRUE : ..()
|
||||
|
||||
/**
|
||||
* Projectile moved:
|
||||
*
|
||||
* If not fired yet, do not do anything. Else,
|
||||
*
|
||||
* If temporary unstoppable movement used for piercing through things we already hit (impacted list) is set, unset it.
|
||||
* Scan turf we're now in for anything we can/should hit. This is useful for hitting non dense objects the user
|
||||
* directly clicks on, as well as for PHASING projectiles to be able to hit things at all as they don't ever Bump().
|
||||
*/
|
||||
/obj/projectile/Moved(atom/OldLoc, Dir)
|
||||
. = ..()
|
||||
if(!fired)
|
||||
return
|
||||
if(temporary_unstoppable_movement)
|
||||
temporary_unstoppable_movement = FALSE
|
||||
movement_type &= ~PHASING
|
||||
scan_moved_turf() //mostly used for making sure we can hit a non-dense object the user directly clicked on, and for penetrating projectiles that don't bump
|
||||
|
||||
/**
|
||||
* Checks if we should pierce something.
|
||||
*
|
||||
* NOT meant to be a pure proc, since this replaces prehit() which was used to do things.
|
||||
* Return PROJECTILE_DELETE_WITHOUT_HITTING to delete projectile without hitting at all!
|
||||
*/
|
||||
/obj/projectile/proc/prehit_pierce(atom/A)
|
||||
if(projectile_phasing & A.pass_flags_self)
|
||||
return PROJECTILE_PIERCE_PHASE
|
||||
if(projectile_piercing & A.pass_flags_self)
|
||||
return PROJECTILE_PIERCE_HIT
|
||||
if(ismovable(A))
|
||||
var/atom/movable/AM = A
|
||||
if(AM.throwing)
|
||||
return (projectile_phasing & LETPASSTHROW)? PROJECTILE_PIERCE_PHASE : ((projectile_piercing & LETPASSTHROW)? PROJECTILE_PIERCE_HIT : PROJECTILE_PIERCE_NONE)
|
||||
return PROJECTILE_PIERCE_NONE
|
||||
|
||||
/**INeedAnAdult I am unsure what the fuck is going on in here and I'll have to get clairification on this shit.
|
||||
*/
|
||||
/obj/item/projectile/proc/check_ricochet(atom/A)
|
||||
if(ricochets > ricochets_max) //safety thing, we don't care about what the other thing says about this.
|
||||
return FALSE
|
||||
@@ -484,11 +682,10 @@
|
||||
AddElement(/datum/element/embed, projectile_payload = shrapnel_type)
|
||||
if(!log_override && firer && original)
|
||||
log_combat(firer, original, "fired at", src, "from [get_area_name(src, TRUE)]")
|
||||
if(direct_target)
|
||||
if(prehit(direct_target))
|
||||
direct_target.bullet_act(src, def_zone)
|
||||
qdel(src)
|
||||
return
|
||||
if(direct_target && (get_dist(direct_target, get_turf(src)) <= 1)) // point blank shots
|
||||
process_hit(get_turf(direct_target), direct_target)
|
||||
if(QDELETED(src))
|
||||
return
|
||||
if(isnum(angle))
|
||||
setAngle(angle)
|
||||
if(spread)
|
||||
@@ -506,6 +703,7 @@
|
||||
var/matrix/M = new
|
||||
M.Turn(Angle)
|
||||
transform = M
|
||||
LAZYINITLIST(impacted)
|
||||
trajectory_ignore_forcemove = TRUE
|
||||
forceMove(starting)
|
||||
set_light(fired_light_range, fired_light_intensity, fired_light_color)
|
||||
@@ -544,6 +742,8 @@
|
||||
if(zc)
|
||||
before_z_change(old, target)
|
||||
. = ..()
|
||||
if(QDELETED(src)) // we coulda bumped something
|
||||
return
|
||||
if(trajectory && !trajectory_ignore_forcemove && isturf(target))
|
||||
if(hitscan)
|
||||
finalize_hitscan_and_generate_tracers(FALSE)
|
||||
@@ -678,30 +878,6 @@
|
||||
if(prob(50))
|
||||
homing_offset_y = -homing_offset_y
|
||||
|
||||
//Returns true if the target atom is on our current turf and above the right layer
|
||||
//If direct target is true it's the originally clicked target.
|
||||
/obj/item/projectile/proc/can_hit_target(atom/target, list/passthrough, direct_target = FALSE, ignore_loc = FALSE)
|
||||
if(QDELETED(target))
|
||||
return FALSE
|
||||
if(!ignore_source_check && firer)
|
||||
var/mob/M = firer
|
||||
if((target == firer) || ((target == firer.loc) && ismecha(firer.loc)) || (target in firer.buckled_mobs) || (istype(M) && (M.buckled == target)))
|
||||
if(!ricochets) //if it has ricocheted, it can hit the firer.
|
||||
return FALSE
|
||||
if(!ignore_loc && (loc != target.loc))
|
||||
return FALSE
|
||||
if(target in passthrough)
|
||||
return FALSE
|
||||
if(target.density) //This thing blocks projectiles, hit it regardless of layer/mob stuns/etc.
|
||||
return TRUE
|
||||
if(!isliving(target))
|
||||
if(target.layer < PROJECTILE_HIT_THRESHHOLD_LAYER)
|
||||
return FALSE
|
||||
else
|
||||
var/mob/living/L = target
|
||||
if(!direct_target && !L.density)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
//Spread is FORCED!
|
||||
/obj/item/projectile/proc/preparePixelProjectile(atom/target, atom/source, params, spread = 0)
|
||||
@@ -762,22 +938,6 @@
|
||||
angle = arctan(y - oy, x - ox)
|
||||
return list(angle, p_x, p_y)
|
||||
|
||||
/obj/item/projectile/Crossed(atom/movable/AM) //A mob moving on a tile with a projectile is hit by it.
|
||||
. = ..()
|
||||
if(isliving(AM) && !(pass_flags & PASSMOB))
|
||||
var/mob/living/L = AM
|
||||
if(can_hit_target(L, permutated, (AM == original)))
|
||||
Bump(AM)
|
||||
|
||||
/obj/item/projectile/Move(atom/newloc, dir = NONE)
|
||||
. = ..()
|
||||
if(.)
|
||||
if(temporary_unstoppable_movement)
|
||||
temporary_unstoppable_movement = FALSE
|
||||
movement_type &= ~(UNSTOPPABLE)
|
||||
if(fired && can_hit_target(original, permutated, TRUE))
|
||||
Bump(original)
|
||||
|
||||
/obj/item/projectile/Destroy()
|
||||
STOP_PROCESSING(SSprojectiles, src)
|
||||
if(hitscan)
|
||||
|
||||
@@ -166,7 +166,7 @@
|
||||
/obj/item/projectile/beam/lasertag/mag //the projectile, compatible with regular laser tag armor
|
||||
icon_state = "magjectile-toy"
|
||||
name = "lasertag magbolt"
|
||||
movement_type = FLYING | UNSTOPPABLE //for penetration memes
|
||||
movement_type = FLYING | PHASING //for penetration memes
|
||||
range = 5 //so it isn't super annoying
|
||||
light_range = 2
|
||||
light_color = LIGHT_COLOR_YELLOW
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
damage = 10
|
||||
armour_penetration = 20
|
||||
stamina = 10
|
||||
movement_type = FLYING | UNSTOPPABLE
|
||||
movement_type = FLYING | PHASING
|
||||
range = 6
|
||||
fired_light_range = 1
|
||||
fired_light_color = LIGHT_COLOR_RED
|
||||
@@ -37,7 +37,7 @@
|
||||
icon_state = "magjectile-large"
|
||||
damage = 10
|
||||
armour_penetration = 20
|
||||
movement_type = FLYING | UNSTOPPABLE
|
||||
movement_type = FLYING | PHASING
|
||||
range = 20
|
||||
pixels_per_second = TILES_TO_PIXELS(12.5)
|
||||
fired_light_range = 4
|
||||
|
||||
@@ -35,7 +35,8 @@
|
||||
icon_state = "gauss"
|
||||
name = "penetrator round"
|
||||
damage = 60
|
||||
movement_type = FLYING | UNSTOPPABLE
|
||||
projectile_piercing = PASSMOB
|
||||
projectile_phasing = (ALL & (~PASSMOB))
|
||||
dismemberment = 0 //It goes through you cleanly.
|
||||
knockdown = 0
|
||||
breakthings = FALSE
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
/obj/item/projectile/bullet/honker
|
||||
damage = 0
|
||||
knockdown = 60
|
||||
movement_type = FLYING | UNSTOPPABLE
|
||||
movement_type = FLYING
|
||||
projectile_piercing = ALL
|
||||
nodamage = TRUE
|
||||
candink = FALSE
|
||||
hitsound = 'sound/items/bikehorn.ogg'
|
||||
|
||||
@@ -344,18 +344,17 @@
|
||||
var/created = FALSE //prevents creation of more then one locker if it has multiple hits
|
||||
var/locker_suck = TRUE
|
||||
|
||||
/obj/item/projectile/magic/locker/prehit(atom/A)
|
||||
/obj/item/projectile/magic/locker/prehit_pierce(atom/A)
|
||||
. = ..()
|
||||
if(ismob(A) && locker_suck)
|
||||
var/mob/M = A
|
||||
if(M.anti_magic_check())
|
||||
if(M.anti_magic_check()) // no this doesn't check if ..() returned to phase through do I care no it's magic ain't gotta explain shit - Silly-Cons
|
||||
M.visible_message("<span class='warning'>[src] vanishes on contact with [A]!</span>")
|
||||
qdel(src)
|
||||
return
|
||||
return PROJECTILE_DELETE_WITHOUT_HITTING
|
||||
if(M.anchored)
|
||||
return ..()
|
||||
return
|
||||
M.forceMove(src)
|
||||
return FALSE
|
||||
return ..()
|
||||
return PROJECTILE_PIERCE_PHASE
|
||||
|
||||
/obj/item/projectile/magic/locker/on_hit(target)
|
||||
if(created)
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
knockdown = 20
|
||||
pixels_per_second = TILES_TO_PIXELS(5)
|
||||
range = 16
|
||||
movement_type = FLYING | UNSTOPPABLE
|
||||
var/datum/beam/arm
|
||||
var/handedness = 0
|
||||
|
||||
@@ -29,18 +28,14 @@
|
||||
arm = starting.Beam(src, icon_state = "curse[handedness]", time = INFINITY, maxdistance = INFINITY, beam_type=/obj/effect/ebeam/curse_arm)
|
||||
..()
|
||||
|
||||
/obj/item/projectile/curse_hand/prehit(atom/target)
|
||||
if(target == original)
|
||||
movement_type &= ~(UNSTOPPABLE)
|
||||
else if(!isturf(target))
|
||||
return FALSE
|
||||
return ..()
|
||||
/obj/projectile/curse_hand/prehit_pierce(atom/target)
|
||||
return (target == original)? PROJECTILE_PIERCE_NONE : PROJECTILE_PIERCE_PHASE
|
||||
|
||||
/obj/item/projectile/curse_hand/Destroy()
|
||||
if(arm)
|
||||
arm.End()
|
||||
arm = null
|
||||
if((movement_type & UNSTOPPABLE))
|
||||
if((movement_type & PHASING))
|
||||
playsound(src, 'sound/effects/curse3.ogg', 25, 1, -1)
|
||||
var/turf/T = get_step(src, dir)
|
||||
var/obj/effect/temp_visual/dir_setting/curse/hand/leftover = new(T, dir)
|
||||
|
||||
@@ -59,10 +59,10 @@
|
||||
/obj/structure/necropolis_gate/singularity_pull()
|
||||
return 0
|
||||
|
||||
/obj/structure/necropolis_gate/CanPass(atom/movable/mover, turf/target)
|
||||
if(get_dir(loc, target) == dir)
|
||||
return !density
|
||||
return 1
|
||||
/obj/structure/necropolis_gate/CanAllowThrough(atom/movable/mover, turf/target)
|
||||
. = ..()
|
||||
if(!(get_dir(loc, target) == dir))
|
||||
return TRUE
|
||||
|
||||
/obj/structure/necropolis_gate/CheckExit(atom/movable/O, target)
|
||||
if(get_dir(O.loc, target) == dir)
|
||||
|
||||
@@ -80,7 +80,8 @@
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
color = rgb(145, 150, 0)
|
||||
|
||||
/obj/effect/gluttony/CanPass(atom/movable/mover, turf/target)//So bullets will fly over and stuff.
|
||||
/obj/effect/gluttony/CanAllowThrough(atom/movable/mover, turf/target)//So bullets will fly over and stuff.
|
||||
. = ..()
|
||||
if(ishuman(mover))
|
||||
var/mob/living/carbon/human/H = mover
|
||||
if(H.nutrition >= NUTRITION_LEVEL_FAT)
|
||||
@@ -90,8 +91,6 @@
|
||||
to_chat(H, "<span class='warning'>You're repulsed by even looking at [src]. Only a pig could force themselves to go through it.</span>")
|
||||
if(istype(mover, /mob/living/simple_animal/hostile/morph))
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/obj/structure/mirror/magic/pride //Pride's mirror: Used in the Pride ruin.
|
||||
name = "pride's mirror"
|
||||
|
||||
@@ -212,15 +212,14 @@
|
||||
var/static/list/check_times = list()
|
||||
|
||||
|
||||
/obj/effect/forcefield/luxury_shuttle/CanPass(atom/movable/mover, turf/target)
|
||||
/obj/effect/forcefield/luxury_shuttle/CanAllowThrough(atom/movable/mover, turf/target)
|
||||
. = ..()
|
||||
if(mover in approved_passengers)
|
||||
return TRUE
|
||||
|
||||
if(!isliving(mover)) //No stowaways
|
||||
return FALSE
|
||||
|
||||
return FALSE
|
||||
|
||||
|
||||
#define LUXURY_MESSAGE_COOLDOWN 100
|
||||
/obj/effect/forcefield/luxury_shuttle/Bumped(atom/movable/AM)
|
||||
|
||||
@@ -30,11 +30,11 @@
|
||||
. = ..()
|
||||
wizard = summoner
|
||||
|
||||
/obj/effect/forcefield/wizard/CanPass(atom/movable/mover, turf/target)
|
||||
/obj/effect/forcefield/wizard/CanAllowThrough(atom/movable/mover, turf/target)
|
||||
. = ..()
|
||||
if(mover == wizard)
|
||||
return TRUE
|
||||
if(ismob(mover))
|
||||
var/mob/M = mover
|
||||
if(M.anti_magic_check(chargecost = 0))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
max_buckled_mobs = 1
|
||||
buckle_lying = FALSE
|
||||
default_driver_move = FALSE
|
||||
pass_flags_self = PASSTABLE
|
||||
var/legs_required = 1
|
||||
var/arms_required = 0 //why not?
|
||||
|
||||
|
||||
Reference in New Issue
Block a user