Gadgets & Gizmos

This commit is contained in:
Mechoid
2021-01-14 22:53:39 -08:00
committed by VirgoBot
parent 758db47b6b
commit 02ffbbe79b
25 changed files with 893 additions and 110 deletions
+109 -4
View File
@@ -7,16 +7,32 @@
icon_state = "uglymine"
var/triggered = 0
var/smoke_strength = 3
var/mineitemtype = /obj/item/weapon/mine
var/obj/item/weapon/mine/mineitemtype = /obj/item/weapon/mine
var/panel_open = 0
var/datum/wires/mines/wires = null
register_as_dangerous_object = TRUE
var/camo_net = FALSE // Will the mine 'cloak' on deployment?
// The trap item will be triggered in some manner when detonating. Default only checks for grenades.
var/obj/item/trap = null
/obj/effect/mine/New()
icon_state = "uglyminearmed"
wires = new(src)
if(ispath(trap))
trap = new trap(src)
/obj/effect/mine/Initialize()
..()
if(camo_net)
alpha = 50
/obj/effect/mine/Destroy()
if(trap)
QDEL_NULL(trap)
qdel_null(wires)
return ..()
@@ -25,11 +41,33 @@
triggered = 1
s.set_up(3, 1, src)
s.start()
explosion(loc, 0, 2, 3, 4) //land mines are dangerous, folks.
visible_message("\The [src.name] detonates!")
if(trap)
trigger_trap(M)
visible_message("\The [src.name] flashes as it is triggered!")
else
explosion(loc, 0, 2, 3, 4) //land mines are dangerous, folks.
visible_message("\The [src.name] detonates!")
qdel(s)
qdel(src)
/obj/effect/mine/proc/trigger_trap(var/mob/living/victim)
if(istype(trap, /obj/item/weapon/grenade))
var/obj/item/weapon/grenade/G = trap
trap = null
G.forceMove(get_turf(src))
if(victim.ckey)
msg_admin_attack("[key_name_admin(victim)] stepped on \a [src.name], triggering [trap]")
G.activate()
if(istype(trap, /obj/item/device/transfer_valve))
var/obj/item/device/transfer_valve/TV = trap
trap = null
TV.forceMove(get_turf(src))
TV.toggle_valve()
/obj/effect/mine/bullet_act()
if(prob(50))
explode()
@@ -63,6 +101,9 @@
"<span class='notice'>You very carefully screw the mine's panel [panel_open ? "open" : "closed"].</span>")
playsound(src, W.usesound, 50, 1)
// Panel open, stay uncloaked, or uncloak if already cloaked. If you don't cloak on place, ignore it and just be normal alpha.
alpha = camo_net ? (panel_open ? 255 : 50) : 255
else if((W.is_wirecutter() || istype(W, /obj/item/device/multitool)) && panel_open)
interact(user)
else
@@ -74,6 +115,9 @@
user.set_machine(src)
wires.Interact(user)
/obj/effect/mine/camo
camo_net = TRUE
/obj/effect/mine/dnascramble
mineitemtype = /obj/item/weapon/mine/dnascramble
@@ -193,6 +237,9 @@
spawn(0)
qdel(src)
/obj/effect/mine/emp/camo
camo_net = TRUE
/obj/effect/mine/incendiary
mineitemtype = /obj/item/weapon/mine/incendiary
@@ -208,6 +255,26 @@
spawn(0)
qdel(src)
/obj/effect/mine/gadget
mineitemtype = /obj/item/weapon/mine/gadget
/obj/effect/mine/gadget/explode(var/mob/living/M)
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread()
triggered = 1
s.set_up(3, 1, src)
s.start()
if(trap)
trigger_trap(M)
visible_message("\The [src.name] flashes as it is triggered!")
else
explosion(loc, 0, 0, 2, 2)
visible_message("\The [src.name] detonates!")
qdel(s)
qdel(src)
/////////////////////////////////////////////
// The held item version of the above mines
/////////////////////////////////////////////
@@ -219,6 +286,10 @@
var/countdown = 10
var/minetype = /obj/effect/mine //This MUST be an /obj/effect/mine type, or it'll runtime.
var/obj/item/trap = null
var/list/allowed_gadgets = null
/obj/item/weapon/mine/attack_self(mob/user as mob) // You do not want to move or throw a land mine while priming it... Explosives + Sudden Movement = Bad Times
add_fingerprint(user)
msg_admin_attack("[key_name_admin(user)] primed \a [src]")
@@ -231,11 +302,39 @@
prime(user, TRUE)
return
/obj/item/weapon/mine/attackby(obj/item/W as obj, mob/living/user as mob)
if(W.is_screwdriver() && trap)
to_chat(user, "<span class='notice'>You begin removing \the [trap].</span>")
if(do_after(user, 10 SECONDS))
to_chat(user, "<span class='notice'>You finish disconnecting the mine's trigger.</span>")
trap.forceMove(get_turf(src))
trap = null
return
if(LAZYLEN(allowed_gadgets) && !trap)
var/allowed = FALSE
for(var/path in allowed_gadgets)
if(istype(W, path))
allowed = TRUE
break
if(allowed)
user.drop_from_inventory(W)
W.forceMove(src)
trap = W
..()
/obj/item/weapon/mine/proc/prime(mob/user as mob, var/explode_now = FALSE)
visible_message("\The [src.name] beeps as the priming sequence completes.")
var/obj/effect/mine/R = new minetype(get_turf(src))
src.transfer_fingerprints_to(R)
R.add_fingerprint(user)
if(trap)
R.trap = trap
trap = null
R.trap.forceMove(R)
if(explode_now)
R.explode(user)
spawn(0)
@@ -286,8 +385,14 @@
desc = "A small explosive mine with a fire symbol on the side."
minetype = /obj/effect/mine/incendiary
/obj/item/weapon/mine/gadget
name = "gadget mine"
desc = "A small pressure-triggered device. If no component is added, the internal release bolts will detonate in unison when triggered."
allowed_gadgets = list(/obj/item/weapon/grenade, /obj/item/device/transfer_valve)
// This tells AI mobs to not be dumb and step on mines willingly.
/obj/item/weapon/mine/is_safe_to_step(mob/living/L)
if(!L.hovering)
return FALSE
return ..()
return ..()
@@ -88,6 +88,14 @@
if(get_dist(user, src) == 0)
. += "It has a tiny camera inside. Needs to be both configured and brought in contact with monitor device to be fully functional."
/obj/item/device/camerabug/update_icon()
..()
if(anchored) // Standard versions are relatively obvious if not hidden in a container. Anchoring them is advised, to disguise them.
alpha = 50
else
alpha = 255
/obj/item/device/camerabug/attackby(obj/item/W as obj, mob/living/user as mob)
if(istype(W, /obj/item/device/bug_monitor))
var/obj/item/device/bug_monitor/SM = W
@@ -101,6 +109,15 @@
linkedmonitor = null
else
to_chat(user, "Error: The device is linked to another monitor.")
else if(W.is_wrench() && user.a_intent != I_HURT)
if(isturf(loc))
anchored = !anchored
to_chat(user, "<span class='notice'>You [anchored ? "" : "un"]secure \the [src].</span>")
update_icon()
return
else
if(W.force >= 5)
visible_message("\The [src] lens shatters!")
@@ -56,3 +56,6 @@
name = "Bandage Synthesizer"
max_energy = 10
recharge_rate = 1
/datum/matter_synth/cloth
name = "Cloth Synthesizer"
+158
View File
@@ -0,0 +1,158 @@
/obj/item/stack/sandbags
name = "sandbag"
desc = "Filled sandbags. Fortunately pre-filled."
singular_name = "sandbag"
icon = 'icons/obj/sandbags.dmi'
icon_state = "sandbag"
w_class = ITEMSIZE_LARGE
force = 10.0
throwforce = 20.0
throw_speed = 5
throw_range = 3
drop_sound = 'sound/items/drop/clothing.ogg'
pickup_sound = 'sound/items/pickup/clothing.ogg'
matter = list(MAT_CLOTH = SHEET_MATERIAL_AMOUNT * 2)
max_amount = 30
attack_verb = list("hit", "bludgeoned", "pillowed")
no_variants = TRUE
stacktype = /obj/item/stack/sandbags
pass_color = TRUE
var/bag_material = "cloth"
/obj/item/stack/sandbags/cyborg
name = "sandbag synthesizer"
desc = "A device that makes filled sandbags. Don't ask how."
gender = NEUTER
matter = null
uses_charge = 1
charge_costs = list(500)
stacktype = /obj/item/stack/sandbags
bag_material = MAT_SYNCLOTH
/obj/item/stack/sandbags/New(var/newloc, var/amt, var/bag_mat)
..()
recipes = sandbag_recipes
update_icon()
if(bag_mat)
bag_material = bag_mat
var/datum/material/M = get_material_by_name("[bag_material]")
if(!M)
qdel(src)
return
color = M.icon_colour
/obj/item/stack/sandbags/update_icon()
var/amount = get_amount()
slowdown = round(amount / 10, 0.1)
var/global/list/datum/stack_recipe/sandbag_recipes = list( \
new/datum/stack_recipe("barricade", /obj/structure/barricade/sandbag, 3, time = 5 SECONDS, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE))
/obj/item/stack/sandbags/produce_recipe(datum/stack_recipe/recipe, var/quantity, mob/user)
var/required = quantity*recipe.req_amount
var/produced = min(quantity*recipe.res_amount, recipe.max_res_amount)
if (!can_use(required))
if (produced>1)
to_chat(user, "<span class='warning'>You haven't got enough [src] to build \the [produced] [recipe.title]\s!</span>")
else
to_chat(user, "<span class='warning'>You haven't got enough [src] to build \the [recipe.title]!</span>")
return
if (recipe.one_per_turf && (locate(recipe.result_type) in user.loc))
to_chat(user, "<span class='warning'>There is another [recipe.title] here!</span>")
return
if (recipe.on_floor && !isfloor(user.loc))
to_chat(user, "<span class='warning'>\The [recipe.title] must be constructed on the floor!</span>")
return
if (recipe.time)
to_chat(user, "<span class='notice'>Building [recipe.title] ...</span>")
if (!do_after(user, recipe.time))
return
if (use(required))
var/atom/O = new recipe.result_type(user.loc, bag_material)
if(istype(O, /obj))
var/obj/Ob = O
if(LAZYLEN(Ob.matter)) // Law of equivalent exchange.
Ob.matter.Cut()
else
Ob.matter = list()
var/mattermult = istype(Ob, /obj/item) ? min(2000, 400 * Ob.w_class) : 2000
Ob.matter[recipe.use_material] = mattermult / produced * required
O.set_dir(user.dir)
O.add_fingerprint(user)
if (istype(O, /obj/item/stack))
var/obj/item/stack/S = O
S.amount = produced
S.add_to_stacks(user)
if (istype(O, /obj/item/weapon/storage)) //BubbleWrap - so newly formed boxes are empty
for (var/obj/item/I in O)
qdel(I)
if ((pass_color || recipe.pass_color))
if(!color)
if(recipe.use_material)
var/datum/material/MAT = get_material_by_name(recipe.use_material)
if(MAT.icon_colour)
O.color = MAT.icon_colour
else
return
else
O.color = color
// Empty bags. Yes, you need to fill them.
/obj/item/stack/emptysandbag
name = "sandbag"
desc = "Empty sandbags. You know what must be done."
singular_name = "sandbag"
icon = 'icons/obj/sandbags.dmi'
icon_state = "sandbag_e"
w_class = ITEMSIZE_LARGE
strict_color_stacking = TRUE
max_amount = 30
stacktype = /obj/item/stack/emptysandbag
pass_color = TRUE
var/bag_material = "cloth"
/obj/item/stack/emptysandbag/New(var/newloc, var/amt, var/bag_mat)
..(newloc, amt)
if(bag_mat)
bag_material = bag_mat
var/datum/material/M = get_material_by_name("[bag_material]")
if(!M)
qdel(src)
return
color = M.icon_colour
/obj/item/stack/emptysandbag/attack_self(var/mob/user)
while(do_after(user, 1 SECOND) && can_use(1) && istype(get_turf(src), /turf/simulated/floor/outdoors))
use(1)
var/obj/item/stack/sandbags/SB = new (get_turf(src), 1, bag_material)
SB.color = color
if(user)
to_chat(user, "<span class='notice'>You fill a sandbag.</span>")
@@ -97,6 +97,8 @@
/obj/item/weapon/material/proc/check_health(var/consumed)
if(health<=0)
health = 0
if(fragile)
shatter(consumed)
else if(!dulled && can_dull)
+241
View File
@@ -1,3 +1,9 @@
/*
* Beartraps.
* Buckles crossing individuals, doing moderate brute damage.
*/
/obj/item/weapon/beartrap
name = "mechanical trap"
throw_speed = 2
@@ -158,3 +164,238 @@
color = "#C9DCE1"
origin_tech = list(TECH_MATERIAL = 4, TECH_BLUESPACE = 3, TECH_MAGNET = 4, TECH_PHORON = 2, TECH_ARCANE = 1)
/*
* Barbed-Wire.
* Slows individuals crossing it. Barefoot individuals will be cut. Can be electrified by placing over a cable node.
*/
/obj/item/weapon/material/barbedwire
name = "barbed wire"
desc = "A coil of wire."
icon = 'icons/obj/trap.dmi'
icon_state = "barbedwire"
anchored = FALSE
layer = TABLE_LAYER
w_class = ITEMSIZE_LARGE
explosion_resistance = 1
can_dull = TRUE
fragile = TRUE
force_divisor = 0.20
thrown_force_divisor = 0.25
sharp = TRUE
/obj/item/weapon/material/barbedwire/set_material(var/new_material)
..()
if(!QDELETED(src))
health = round(material.integrity / 3)
name = (material.get_edge_damage() * force_divisor > 15) ? "[material.display_name] razor wire" : "[material.display_name] [initial(name)]"
/obj/item/weapon/material/barbedwire/proc/can_use(mob/user)
return (user.IsAdvancedToolUser() && !issilicon(user) && !user.stat && !user.restrained())
/obj/item/weapon/material/barbedwire/attack_hand(mob/user as mob)
if(anchored && can_use(user))
user.visible_message(
"<span class='danger'>[user] starts to collect \the [src].</span>",
"<span class='notice'>You begin collecting \the [src]!</span>",
"You hear the sound of rustling [material.name]."
)
playsound(src, 'sound/machines/click.ogg', 50, 1)
if(do_after(user, health))
user.visible_message(
"<span class='danger'>[user] has collected \the [src].</span>",
"<span class='notice'>You have collected \the [src]!</span>"
)
anchored = 0
update_icon()
else
..()
/obj/item/weapon/material/barbedwire/attack_self(mob/user as mob)
..()
if(!anchored && can_use(user))
user.visible_message(
"<span class='danger'>[user] starts to deploy \the [src].</span>",
"<span class='danger'>You begin deploying \the [src]!</span>",
"You hear the rustling of [material.name]."
)
if (do_after(user, 60))
user.visible_message(
"<span class='danger'>[user] has deployed \the [src].</span>",
"<span class='danger'>You have deployed \the [src]!</span>",
"You hear the rustling of [material.name]."
)
playsound(src, 'sound/items/Wirecutter.ogg',70, 1)
spawn(2)
playsound(src, 'sound/items/Wirecutter.ogg',40, 1)
user.drop_from_inventory(src)
forceMove(get_turf(src))
anchored = 1
update_icon()
/obj/item/weapon/material/barbedwire/attackby(obj/item/W as obj, mob/user as mob)
if(!istype(W))
return
if((W.flags & NOCONDUCT) || !shock(user, 70, pick(BP_L_HAND, BP_R_HAND)))
user.setClickCooldown(user.get_attack_speed(W))
user.do_attack_animation(src)
playsound(src, 'sound/effects/grillehit.ogg', 40, 1)
var/inc_damage = W.force
if(W.is_wirecutter())
if(!shock(user, 100, pick(BP_L_HAND, BP_R_HAND)))
playsound(src, W.usesound, 100, 1)
inc_damage *= 3
if(W.damtype != BRUTE)
inc_damage *= 0.3
health -= inc_damage
check_health()
..()
/obj/item/weapon/material/barbedwire/update_icon()
..()
if(anchored)
icon_state = "[initial(icon_state)]-out"
else
icon_state = "[initial(icon_state)]"
/obj/item/weapon/material/barbedwire/Crossed(atom/movable/AM as mob|obj)
if(AM.is_incorporeal())
return
if(anchored && isliving(AM))
var/mob/living/L = AM
if(L.m_intent == "run")
L.visible_message(
"<span class='danger'>[L] steps in \the [src].</span>",
"<span class='danger'>You step in \the [src]!</span>",
"<b>You hear a sharp rustling!</b>"
)
attack_mob(L)
update_icon()
..()
/obj/item/weapon/material/barbedwire/proc/shock(mob/user as mob, prb, var/target_zone = BP_TORSO)
if(!anchored || health == 0) // anchored/destroyed grilles are never connected
return 0
if(material.conductivity <= 0)
return 0
if(!prob(prb))
return 0
if(!in_range(src, user))//To prevent TK and mech users from getting shocked
return 0
var/turf/T = get_turf(src)
var/obj/structure/cable/C = T.get_cable_node()
if(C)
if(C.powernet)
var/datum/powernet/PN = C.powernet
if(PN)
PN.trigger_warning()
var/PN_damage = PN.get_electrocute_damage() * (material.conductivity / 50)
var/drained_energy = PN_damage * 10 / CELLRATE
PN.draw_power(drained_energy)
if(ishuman(user))
var/mob/living/carbon/human/H = user
var/obj/item/organ/external/affected = H.get_organ(check_zone(target_zone))
H.electrocute_act(PN_damage, src, H.get_siemens_coefficient_organ(affected))
else
if(isliving(user))
var/mob/living/L = user
L.electrocute_act(PN_damage, src, 0.8)
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(3, 1, src)
s.start()
if(user.stunned)
return 1
else
return 0
return 0
/obj/item/weapon/material/barbedwire/proc/attack_mob(mob/living/L)
var/target_zone
if(L.lying)
target_zone = ran_zone()
else
target_zone = pick("l_foot", "r_foot", "l_leg", "r_leg")
//armour
var/blocked = L.run_armor_check(target_zone, "melee")
var/soaked = L.get_armor_soak(target_zone, "melee")
if(blocked >= 100)
return
if(soaked >= 30)
return
if(L.buckled) //wheelchairs, office chairs, rollerbeds
return
shock(L, 100, target_zone)
L.add_modifier(/datum/modifier/entangled, 3 SECONDS)
if(!L.apply_damage(force * (issilicon(L) ? 0.25 : 1), BRUTE, target_zone, blocked, soaked, src, sharp, edge))
return
playsound(src, 'sound/effects/glass_step.ogg', 50, 1) // not sure how to handle metal shards with sounds
if(ishuman(L))
var/mob/living/carbon/human/H = L
if(H.species.siemens_coefficient<0.5) //Thick skin.
return
if( H.shoes || ( H.wear_suit && (H.wear_suit.body_parts_covered & FEET) ) )
return
if(H.species.flags & NO_MINOR_CUT)
return
to_chat(H, "<span class='danger'>You step directly on \the [src]!</span>")
var/list/check = list("l_foot", "r_foot")
while(check.len)
var/picked = pick(check)
var/obj/item/organ/external/affecting = H.get_organ(picked)
if(affecting)
if(affecting.robotic >= ORGAN_ROBOT)
return
if(affecting.take_damage(force, 0))
H.UpdateDamageIcon()
H.updatehealth()
if(affecting.organ_can_feel_pain())
H.Weaken(3)
return
check -= picked
if(material.is_brittle() && prob(material.hardness))
health = 0
else if(!prob(material.hardness))
health--
check_health()
return
/obj/item/weapon/material/barbedwire/plastic
name = "snare wire"
default_material = MAT_PLASTIC
+2
View File
@@ -92,6 +92,8 @@
return pick(prob(30);/obj/effect/mine,
prob(25);/obj/effect/mine/frag,
prob(25);/obj/effect/mine/emp,
prob(15);/obj/effect/mine/camo,
prob(15);/obj/effect/mine/emp/camo,
prob(10);/obj/effect/mine/stun,
prob(10);/obj/effect/mine/incendiary,)
+185
View File
@@ -0,0 +1,185 @@
//Barricades!
/obj/structure/barricade
name = "barricade"
desc = "This space is blocked off by a barricade."
icon = 'icons/obj/structures.dmi'
icon_state = "barricade"
anchored = 1.0
density = 1.0
var/health = 100
var/maxhealth = 100
var/datum/material/material
/obj/structure/barricade/New(var/newloc, var/material_name)
..(newloc)
if(!material_name)
material_name = "wood"
material = get_material_by_name("[material_name]")
if(!material)
qdel(src)
return
name = "[material.display_name] barricade"
desc = "This space is blocked off by a barricade made of [material.display_name]."
color = material.icon_colour
maxhealth = material.integrity
health = maxhealth
/obj/structure/barricade/get_material()
return material
/obj/structure/barricade/attackby(obj/item/W as obj, mob/user as mob)
user.setClickCooldown(user.get_attack_speed(W))
if(istype(W, /obj/item/stack))
var/obj/item/stack/D = W
if(D.get_material_name() != material.name)
return //hitting things with the wrong type of stack usually doesn't produce messages, and probably doesn't need to.
if(health < maxhealth)
if(D.get_amount() < 1)
to_chat(user, "<span class='warning'>You need one sheet of [material.display_name] to repair \the [src].</span>")
return
visible_message("<span class='notice'>[user] begins to repair \the [src].</span>")
if(do_after(user,20) && health < maxhealth)
if(D.use(1))
health = maxhealth
visible_message("<span class='notice'>[user] repairs \the [src].</span>")
return
return
else
switch(W.damtype)
if("fire")
health -= W.force * 1
if("brute")
health -= W.force * 0.75
if(material == (get_material_by_name(MAT_WOOD) || get_material_by_name(MAT_SIFWOOD)))
playsound(src, 'sound/effects/woodcutting.ogg', 100, 1)
else
playsound(src, 'sound/weapons/smash.ogg', 50, 1)
CheckHealth()
..()
/obj/structure/barricade/proc/CheckHealth()
if(health <= 0)
dismantle()
health = min(health, maxhealth)
return
/obj/structure/barricade/take_damage(var/damage)
health -= damage
CheckHealth()
return
/obj/structure/barricade/attack_generic(var/mob/user, var/damage, var/attack_verb)
visible_message("<span class='danger'>[user] [attack_verb] the [src]!</span>")
if(material == get_material_by_name("resin"))
playsound(src, 'sound/effects/attackblob.ogg', 100, 1)
else if(material == (get_material_by_name(MAT_CLOTH) || get_material_by_name(MAT_SYNCLOTH)))
playsound(src, 'sound/items/drop/clothing.ogg', 100, 1)
else if(material == (get_material_by_name(MAT_WOOD) || get_material_by_name(MAT_SIFWOOD)))
playsound(src, 'sound/effects/woodcutting.ogg', 100, 1)
else
playsound(src, 'sound/weapons/smash.ogg', 50, 1)
user.do_attack_animation(src)
health -= damage
CheckHealth()
return
/obj/structure/barricade/proc/dismantle()
material.place_dismantled_product(get_turf(src))
visible_message("<span class='danger'>\The [src] falls apart!</span>")
qdel(src)
return
/obj/structure/barricade/ex_act(severity)
switch(severity)
if(1.0)
dismantle()
if(2.0)
health -= 25
CheckHealth()
/obj/structure/barricade/CanPass(atom/movable/mover, turf/target)//So bullets will fly over and stuff.
if(istype(mover) && mover.checkpass(PASSTABLE))
return TRUE
return FALSE
/obj/structure/barricade/sandbag
name = "sandbags"
desc = "Bags. Bags of sand. It's rough and coarse and somehow stays in the bag."
icon = 'icons/obj/sandbags.dmi'
icon_state = "blank"
/obj/structure/barricade/sandbag/New(var/newloc, var/material_name)
if(!material_name)
material_name = "cloth"
..(newloc, material_name)
material = get_material_by_name("[material_name]")
if(!material)
qdel(src)
return
name = "[material.display_name] [initial(name)]"
desc = "This space is blocked off by a barricade made of [material.display_name]."
color = null
maxhealth = material.integrity * 2 // These things are, commonly, used to stop bullets where possible.
health = maxhealth
update_connections(1)
/obj/structure/barricade/sandbag/Destroy()
update_connections(1, src)
..()
/obj/structure/barricade/sandbag/dismantle()
update_connections(1, src)
material.place_dismantled_product(get_turf(src))
visible_message("<span class='danger'>\The [src] falls apart!</span>")
qdel(src)
return
/obj/structure/barricade/sandbag/update_icon()
if(!material)
return
cut_overlays()
var/image/I
for(var/i = 1 to 4)
I = image('icons/obj/sandbags.dmi', "sandbags[connections[i]]", dir = 1<<(i-1))
I.color = material.icon_colour
add_overlay(I)
return
/obj/structure/barricade/sandbag/update_connections(propagate = 0, var/obj/structure/barricade/sandbag/ignore = null)
if(!material)
return
var/list/dirs = list()
for(var/obj/structure/barricade/sandbag/S in orange(src, 1))
if(!S.material)
continue
if(S == ignore)
continue
if(propagate >= 1)
S.update_connections(propagate - 1, ignore)
if(can_join_with(S))
dirs += get_dir(src, S)
connections = dirs_to_corner_states(dirs)
update_icon()
/obj/structure/barricade/sandbag/proc/can_join_with(var/obj/structure/barricade/sandbag/S)
if(material == S.material)
return 1
return 0
/obj/structure/barricade/sandbag/CanPass(atom/movable/mover, turf/target)
. = ..()
if(.)
if(istype(mover, /obj/item/projectile))
var/obj/item/projectile/P = mover
if(P.firer && get_dist(P.firer, src) > 1) // If you're firing from adjacent turfs, you are unobstructed.
if(P.armor_penetration < (material.protectiveness + material.hardness) || prob(33))
return FALSE