/obj/structure/barricade icon = 'icons/obj/barricades.dmi' climbable = TRUE anchored = TRUE density = TRUE atom_flags = ATOM_FLAG_CHECKS_BORDER /// The type of stack the barricade dropped when disassembled if any. var/stack_type /// The amount of stack dropped when disassembled at full health var/stack_amount = 5 /// to specify a non-zero amount of stack to drop when destroyed var/destroyed_stack_amount /// Pretty tough. Changes sprites at 300 and 150 var/health = 100 /// Basic code functions var/maxhealth = 100 /// Used for calculating some stuff related to maxhealth as it constantly changes due to e.g. barbed wire. set to 100 to avoid possible divisions by zero var/starting_maxhealth = 100 /// How much force an item needs to even damage it at all. var/force_level_absorption = 5 var/barricade_hitsound /// "metal", "plasteel", etc. var/barricade_type = "barricade" var/can_change_dmg_state = TRUE var/damage_state = BARRICADE_DMG_NONE var/closed = FALSE var/can_wire = FALSE var/is_wired = FALSE var/metallic = TRUE /obj/structure/barricade/Initialize(mapload, mob/user) . = ..() update_icon() starting_maxhealth = maxhealth /obj/structure/barricade/condition_hints(mob/user, distance, is_adjacent) . += ..() switch(damage_state) if(BARRICADE_DMG_NONE) . += SPAN_INFO("It appears to be in good shape.") if(BARRICADE_DMG_SLIGHT) . += SPAN_WARNING("It's slightly damaged, but still very functional.") if(BARRICADE_DMG_MODERATE) . += SPAN_WARNING("It's quite beat up, but it's holding together.") if(BARRICADE_DMG_HEAVY) . += SPAN_WARNING("It's crumbling apart, just a few more blows will tear it apart!") /obj/structure/barricade/mechanics_hints(mob/user, distance, is_adjacent) . += ..() . += "RIGHT-click on this to rotate it (if not anchored to the floor)." if(!is_wired) . += "Use a length of barbed wire on this barricade to prevent enemies from climbing it and damage them on attacking it at close range." else . += "Wirecutters could remove the barbed wire on this, but it will take several moments." /obj/structure/barricade/feedback_hints(mob/user, distance, is_adjacent) . += ..() . += SPAN_INFO("It is recommended to stand flush to a barricade or one tile away for maximum effectiveness.") if(is_wired) . += SPAN_INFO("There is a length of barbed wire strewn across the top of this barricade, preventing it from being climbed and making it hazardous to attack at close range.") /obj/structure/barricade/update_icon() CutOverlays() if(!closed) if(can_change_dmg_state) icon_state = "[barricade_type]_[damage_state]" else icon_state = "[barricade_type]" switch(dir) if(SOUTH) layer = ABOVE_HUMAN_LAYER if(NORTH) layer = initial(layer) - 0.01 else reset_plane_and_layer() if(!anchored) reset_plane_and_layer() else if(can_change_dmg_state) icon_state = "[barricade_type]_closed_[damage_state]" else icon_state = "[barricade_type]_closed" layer = OBJ_LAYER if(is_wired) if(!closed) AddOverlays(image('icons/obj/barricades.dmi', icon_state = "[src.barricade_type]_wire")) else AddOverlays(image('icons/obj/barricades.dmi', icon_state = "[src.barricade_type]_closed_wire")) ..() /obj/structure/barricade/proc/handle_barrier_chance() if(!anchored) return FALSE return prob(max(30,(100.0*health)/maxhealth)) /obj/structure/barricade/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) if(mover?.movement_type & PHASING) return TRUE if(air_group || (height==0)) return TRUE if(istype(mover, /obj/projectile)) return (check_cover(mover,target)) if (get_dir(loc, target) == dir) return !density else return TRUE /obj/structure/barricade/proc/check_cover(obj/projectile/P, turf/from) var/turf/cover = get_turf(src) if(!cover) return TRUE if (get_dist(P.starting, loc) <= 1) return TRUE var/chance = handle_barrier_chance() if(chance) bullet_act(P) return FALSE return TRUE /obj/structure/barricade/CheckExit(atom/movable/O as mob|obj, target as turf) if(istype(O) && O.pass_flags & PASSTABLE) return TRUE if (get_dir(loc, target) == dir) return !density else return TRUE /obj/structure/barricade/can_climb(var/mob/living/user, post_climb_check=0) if(is_wired) to_chat(user, SPAN_WARNING("\The [src] has barbed wire over it, restricting you from climbing over!")) return FALSE return ..() /obj/structure/barricade/attack_robot(mob/user) return attack_hand(user) /obj/structure/barricade/attack_hand(var/mob/user) user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) if(ishuman(user)) var/mob/living/carbon/human/H = user var/shredding = H.species.can_shred(H) if(shredding) var/datum/unarmed_attack/UA = H.default_attack if((UA.damage + UA.armor_penetration) > force_level_absorption) var/attack_verb = pick("mangles", "slices", "slashes", "shreds") attack_generic(user, UA.damage, attack_verb) /obj/structure/barricade/attack_generic(mob/user, damage, attack_message, environment_smash, armor_penetration, attack_flags, damage_type) if(!damage) return FALSE if(!isliving(user)) return var/mob/living/L = user L.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) visible_message(SPAN_DANGER("[L] [attack_verb] the [src]!")) if(barricade_hitsound) playsound(src, barricade_hitsound, 50, 1) if(is_wired) visible_message(SPAN_DANGER("\The [src]'s barbed wire slices into [L]!")) L.apply_damage((5), DAMAGE_BRUTE, pick(BP_R_HAND, BP_L_HAND), "barbed wire", DAMAGE_FLAG_SHARP|DAMAGE_FLAG_EDGE, 25) L.do_attack_animation(src) take_damage(damage) /obj/structure/barricade/attackby(obj/item/attacking_item, mob/user) if(istype(attacking_item, /obj/item/stack/barbed_wire)) var/obj/item/stack/barbed_wire/B = attacking_item if(can_wire) user.visible_message(SPAN_NOTICE("[user] starts setting up [attacking_item.name] on [src]."), SPAN_NOTICE("You start setting up [attacking_item.name] on [src].")) if(do_after(user, 20, src, DO_REPAIR_CONSTRUCT) && can_wire) // Make sure there's still enough wire in the stack if(!B.use(1)) return playsound(src.loc, 'sound/effects/barbed_wire_movement.ogg', 25, 1) user.visible_message(SPAN_NOTICE("[user] sets up [attacking_item.name] on [src]."), SPAN_NOTICE("You set up [attacking_item.name] on [src].")) maxhealth += 50 update_health(-50) can_wire = FALSE is_wired = TRUE climbable = FALSE update_icon() return if(attacking_item.tool_behaviour == TOOL_WIRECUTTER) if(is_wired) user.visible_message(SPAN_NOTICE("[user] begin removing the barbed wire on [src]."), SPAN_NOTICE("You begin removing the barbed wire on [src].")) if(do_after(user, 20, src, DO_REPAIR_CONSTRUCT)) if(!is_wired) return playsound(src.loc, 'sound/items/Wirecutter.ogg', 25, 1) user.visible_message(SPAN_NOTICE("[user] removes the barbed wire on [src]."), SPAN_NOTICE("You remove the barbed wire on [src].")) maxhealth -= 50 update_health(50) can_wire = TRUE is_wired = FALSE climbable = TRUE update_icon() new /obj/item/stack/barbed_wire(loc) return if((attacking_item.force + attacking_item.armor_penetration) > force_level_absorption) ..() if(barricade_hitsound) playsound(src, barricade_hitsound, 25, 1) hit_barricade(attacking_item, user) /obj/structure/barricade/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit) . = ..() if(. != BULLET_ACT_HIT) return . bullet_ping(hitting_projectile) var/damage_to_take = hitting_projectile.damage * hitting_projectile.anti_materiel_potential take_damage(damage_to_take) /obj/structure/barricade/proc/barricade_deconstruct(deconstruct) if(deconstruct && is_wired) new /obj/item/stack/barbed_wire(loc) if(stack_type) var/stack_amt if(!deconstruct && destroyed_stack_amount) stack_amt = destroyed_stack_amount else stack_amt = round(stack_amount * (health/starting_maxhealth)) //Get an amount of sheets back equivalent to remaining health. Obviously, fully destroyed means 0 if(stack_amt) new stack_type (loc, stack_amt) qdel(src) /obj/structure/barricade/ex_act(severity, direction, cause_data) for(var/obj/structure/barricade/B in get_step(src,dir)) //discourage double-stacking barricades by removing health from opposing barricade if(B.dir == REVERSE_DIR(dir)) INVOKE_ASYNC(B, TYPE_PROC_REF(/atom, ex_act), severity, direction) update_health(round(severity)) // This proc is called whenever the cade is moved, so I thought it was appropriate, // especially since the barricade's direction needs to be handled when moving // diagonally. /obj/structure/barricade/Move() . = ..() if (dir & EAST) set_dir(EAST) else if(dir & WEST) set_dir(WEST) update_icon() /obj/structure/barricade/set_dir(ndir) . = ..() update_icon() /obj/structure/barricade/proc/hit_barricade(var/obj/item/I, var/mob/user) if(!isliving(user)) return var/mob/living/L = user L.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) var/message = pick(I.attack_verb) visible_message(SPAN_DANGER("[L] has [message] the [src]!")) L.do_attack_animation(src) take_damage(I.force) /obj/structure/barricade/proc/take_damage(var/damage) for(var/obj/structure/barricade/B in get_step(src,dir)) //discourage double-stacking barricades by removing health from opposing barricade if(B.dir == REVERSE_DIR(dir)) B.update_health(damage) update_health(damage) /obj/structure/barricade/proc/update_health(damage, nomessage) health -= damage health = clamp(health, 0, maxhealth) if(!health) if(!nomessage) visible_message(SPAN_DANGER("[src] falls apart!")) barricade_deconstruct() return update_damage_state() update_icon() /obj/structure/barricade/proc/update_damage_state() var/health_percent = round(health/maxhealth * 100) switch(health_percent) if(0 to 25) damage_state = BARRICADE_DMG_HEAVY if(25 to 50) damage_state = BARRICADE_DMG_MODERATE if(50 to 75) damage_state = BARRICADE_DMG_SLIGHT if(75 to INFINITY) damage_state = BARRICADE_DMG_NONE /obj/structure/barricade/proc/weld_cade(obj/item/weldingtool/WT, mob/user) if(!metallic) return FALSE if(!(WT.use(2, user))) return FALSE user.visible_message(SPAN_NOTICE("[user] begins repairing damage to [src]."), SPAN_NOTICE("You begin repairing the damage to [src].")) if(WT.use_tool(src, user, 7 SECONDS, volume = 40)) user.visible_message(SPAN_NOTICE("[user] repairs some damage on [src]."), SPAN_NOTICE("You repair \the [src].")) update_health(-200) return TRUE /obj/structure/barricade/verb/count_rotate() set name = "Rotate Barricade Counter-Clockwise" set category = "Object" set src in oview(1) rotate(usr, 1) /obj/structure/barricade/verb/clock_rotate() set name = "Rotate Barricade Clockwise" set category = "Object" set src in oview(1) rotate(usr, -1) /obj/structure/barricade/rotate(var/mob/user, var/rotation_dir = -1)//-1 for clockwise, 1 for counter clockwise if(world.time <= user.next_move || !ishuman(user) || use_check_and_message(user)) return if(anchored) to_chat(usr, SPAN_WARNING("\The [src] is fastened to the floor, you can't rotate it!")) return user.next_move = world.time + 3 //slight spam prevention? you don't want every metal cade to turn into a doorway set_dir(turn(dir, 90 * rotation_dir)) update_icon() /obj/structure/barricade/AltClick(mob/user) rotate(user)