/obj/structure icon = 'icons/obj/structures.dmi' w_class = WEIGHT_CLASS_GIGANTIC layer = STRUCTURE_LAYER blocks_emissive = EMISSIVE_BLOCK_GENERIC pass_flags_self = PASSSTRUCTURE should_use_health = TRUE /// Overrides for material shit. Set them manually if you don't want colors etc. See wood chairs/office chairs. var/material_alteration = MATERIAL_ALTERATION_ALL var/climbable var/parts var/list/climbers /// Footstep sounds when stepped on var/list/footstep_sound var/singleton/material/material /// Used by some structures to determine into how many pieces they should disassemble into or be made with var/build_amt = 2 /// Amount that pulling mobs have their movement delayed by var/slowdown = 0 /obj/structure/Initialize(mapload) . = ..() if(!isnull(material) && !istype(material)) material = SSmaterials.get_material_by_id(material) if (!mapload) updateVisibility(src) // No point checking this before visualnet initializes. if(climbable) verbs += /obj/structure/proc/climb_on if (smoothing_flags) QUEUE_SMOOTH(src) QUEUE_SMOOTH_NEIGHBORS(src) /obj/structure/Destroy() if(parts) new parts(loc) if (smoothing_flags) SSicon_smooth.remove_from_queues(src) QUEUE_SMOOTH_NEIGHBORS(src) climbers = null material = null return ..() /obj/structure/examine_descriptor(mob/user) return "structure" /obj/structure/examine_tags(atom/source, mob/user, list/examine_list) . = ..() if(climbable) .["climbable"] = "It can be climbed on, either by dragging your mob onto it or middle-clicking it." /obj/structure/attackby(obj/item/attacking_item, mob/user, params) . = ..() if(user?.a_intent == I_HURT && maxhealth) user.do_attack_animation(src) user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) add_damage(attacking_item.force, attacking_item.damage_flags(), attacking_item.damtype, attacking_item.armor_penetration, attacking_item) if(hitsound) playsound(user, hitsound, attacking_item.get_clamped_volume()) /obj/structure/attack_hand(mob/living/user) if((user.mutations & HULK) && !(user.isSynthetic()) && !(isvaurca(user))) user.say(pick("RAAAAAAAARGH!!!", "HNNNNNNNNNGGGGGGH!!!", "GWAAAAAAAARRRHHH!!!", "NNNNNNNNGGGGGGGGHH!!!", "AAAAAAARRRGH!!!" )) attack_generic(user, 25, "smashes") else if(istype(user,/mob/living/carbon/human)) var/mob/living/carbon/human/H = user if(H.species.can_shred(user)) attack_generic(user, 25, "slices") if(LAZYLEN(climbers) && !(user in climbers)) user.visible_message(SPAN_WARNING("[user] shakes \the [src]."), \ SPAN_NOTICE("You shake \the [src].")) structure_shaken() return ..() /obj/structure/ex_act(severity) // If this object doesn't use health for whatever reason, default to ancient ex_act() code. if(!should_use_health) switch(severity) if(1.0) qdel(src) return if(2.0) if(prob(50)) qdel(src) return if(3.0) return // If we do use health, normal atom health behavior. else switch(severity) if(1) add_damage(maxhealth) if(2) add_damage(maxhealth * 0.5) if(3) add_damage(maxhealth * 0.25) /obj/structure/proc/dismantle() var/singleton/material/dismantle_material if(!get_material()) dismantle_material = GET_SINGLETON(MATERIAL_STEEL) else dismantle_material = get_material() if(should_use_health && health <= 0) build_amt /= rand(2, 4) //if the structure is destroyed by damage, it will yield less materials. build_amt = max(1, min(build_amt, 5)) //Bound between 5 and 1, as shards don't stack into sheets. for(var/i = 1 to build_amt) dismantle_material.place_shard(loc) else for(var/i = 1 to build_amt) dismantle_material.place_sheet(loc) qdel(src) /obj/structure/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit) . = ..() if(. != BULLET_ACT_HIT) return . if(hitting_projectile.get_structure_damage() > 5) bullet_ping(hitting_projectile) add_damage(hitting_projectile.damage, hitting_projectile.damage_flags(), hitting_projectile.damage_type, hitting_projectile.armor_penetration, hitting_projectile) /obj/structure/proc/climb_on() set name = "Climb Structure" set desc = "Climbs onto a structure. Shortcut middle-mouse click." set category = "Object" set src in oview(1) if(can_climb(usr)) do_climb(usr) /obj/structure/handle_middle_mouse_click(mob/user) if(can_climb(user)) do_climb(usr) return TRUE return FALSE /obj/structure/mouse_drop_receive(atom/dropped, mob/user, params) var/mob/living/H = user if(istype(H) && can_climb(H) && dropped == user) do_climb(dropped) return ..() /obj/structure/proc/can_climb(var/mob/living/user, post_climb_check=0) if (!climbable) return FALSE if (!can_touch(user) || (!post_climb_check && (user in climbers))) return FALSE if (!user.Adjacent(src)) return FALSE var/obj/occupied = turf_is_crowded() if(occupied) to_chat(user, SPAN_WARNING("There's \a [occupied] in the way of climbing this.")) return FALSE return TRUE /obj/structure/proc/turf_is_crowded(var/exclude_self = FALSE) var/turf/T = get_turf(src) if(!T || !istype(T)) return 0 for(var/obj/O in T.contents) if(istype(O,/obj/structure)) var/obj/structure/S = O if(S.climbable) continue if(O && O.density && !(O.atom_flags & ATOM_FLAG_CHECKS_BORDER)) //ATOM_FLAG_CHECKS_BORDER structures are handled by the Adjacent() check. if(exclude_self && O == src) continue return O return 0 /obj/structure/proc/do_climb(var/mob/living/user) if (!can_climb(user)) return FALSE user.visible_message(SPAN_WARNING("[user] starts [atom_flags & ATOM_FLAG_CHECKS_BORDER ? "leaping over" : "climbing onto"] \the [src]!")) LAZYADD(climbers, user) if(!do_after(user, 5 SECONDS, src, DO_DEFAULT | DO_USER_UNIQUE_ACT)) LAZYREMOVE(climbers, user) return if (!can_climb(user, post_climb_check=1)) LAZYREMOVE(climbers, user) return var/turf/TT = get_turf(src) if(atom_flags & ATOM_FLAG_CHECKS_BORDER) TT = get_step(get_turf(src), dir) if(user.loc == TT) TT = get_turf(src) user.visible_message(SPAN_WARNING("[user] [atom_flags & ATOM_FLAG_CHECKS_BORDER ? "leaps over" : "climbs onto"] \the [src]!")) user.forceMove(TT) LAZYREMOVE(climbers, user) /obj/structure/proc/structure_shaken() for(var/mob/living/M in climbers) M.Weaken(1) to_chat(M, SPAN_DANGER("You topple as you are shaken off \the [src]!")) LAZYREMOVE(climbers, M) for(var/mob/living/M in get_turf(src)) if(M.lying) return //No spamming this on people. M.Weaken(3) to_chat(M, SPAN_DANGER("You topple as \the [src] moves under you!")) if(prob(25)) var/damage = rand(15,30) var/mob/living/carbon/human/H = M if(!istype(H)) to_chat(H, SPAN_DANGER("You land heavily!")) M.adjustBruteLoss(damage) return var/obj/item/organ/external/affecting switch(pick(list("ankle","wrist",BP_HEAD,"knee","elbow"))) if("ankle") affecting = H.get_organ(pick(BP_L_FOOT, BP_R_FOOT)) if("knee") affecting = H.get_organ(pick(BP_L_LEG, BP_R_LEG)) if("wrist") affecting = H.get_organ(pick(BP_L_HAND, BP_R_HAND)) if("elbow") affecting = H.get_organ(pick(BP_L_ARM, BP_R_ARM)) if(BP_HEAD) affecting = H.get_organ(BP_HEAD) if(affecting) to_chat(M, SPAN_DANGER("You land heavily on your [affecting.name]!")) affecting.take_damage(damage, 0) if(affecting.parent) affecting.parent.add_autopsy_data("Misadventure", damage) else to_chat(H, SPAN_DANGER("You land heavily!")) H.adjustBruteLoss(damage) H.UpdateDamageIcon() H.updatehealth() return /obj/structure/proc/can_touch(var/mob/user) if (!user) return 0 if(!Adjacent(user)) return 0 if (user.restrained() || user.buckled_to) to_chat(user, SPAN_NOTICE("You need your hands and legs free for this.")) return 0 if (user.stat || user.paralysis || user.sleeping || user.lying || user.weakened) return 0 if (issilicon(user)) to_chat(user, SPAN_NOTICE("You need hands for this.")) return 0 return 1 /obj/structure/on_death(damage, damage_flags, damage_type, armor_penetration, obj/weapon) dismantle() /obj/structure/get_material() return material