/////////////////////////////////////////////// // The cable coil object, used for laying cable /////////////////////////////////////////////// #define HEALPERCABLE 3 #define MAXCABLEPERHEAL 8 GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe/cable_restraints("cable restraints", /obj/item/restraints/handcuffs/cable, 15))) /obj/item/stack/cable_coil name = "cable coil" desc = "A low-cost superconducting cable." singular_name = "cable" icon = 'icons/obj/power.dmi' icon_state = "coil" inhand_icon_state = "coil" belt_icon = "cable_coil" hitsound = 'sound/weapons/whip.ogg' amount = MAXCOIL max_amount = MAXCOIL merge_type = /obj/item/stack/cable_coil // This is here to let its children merge between themselves color = COLOR_RED w_class = WEIGHT_CLASS_SMALL throw_range = 5 materials = list(MAT_METAL = 15, MAT_GLASS = 10) flags = CONDUCT slot_flags = ITEM_SLOT_BELT attack_verb = list("whipped", "lashed", "disciplined", "flogged") usesound = 'sound/items/deconstruct.ogg' /// Deletes the cable coil upon getting empty. /// Used for RCL cable spools to stop the stack from being eaten. /// Type of cable this coil makes var/cable_type = /obj/structure/cable /// Bitflag of the types of cable we can add cable to with this coil. /// This is different to the cable connection flag since it only governs connecting on the same tile var/cable_merge_id = CABLE_MERGE_LOW_POWER /obj/item/stack/cable_coil/Initialize(mapload, length, paramcolor) . = ..() if(paramcolor) color = paramcolor update_icon() recipes = GLOB.cable_coil_recipes update_wclass() /obj/item/stack/cable_coil/should_play_hitsound(damage) return TRUE /obj/item/stack/cable_coil/random/change_stack(mob/user, amount) var/obj/item/stack/cable_coil/new_stack = ..() new_stack.color = color return new_stack /// Used to decouple the physical color of the cable from the logical color. Used by RCL to stop its spool holder from being colored in. /obj/item/stack/cable_coil/proc/get_cable_color() return color /obj/item/stack/cable_coil/update_name() . = ..() if(amount > 2) name = "cable coil" else name = "cable piece" /obj/item/stack/cable_coil/update_icon_state() if(amount == 1) icon_state = "coil1" else if(amount == 2) icon_state = "coil2" else icon_state = "coil" /obj/item/stack/cable_coil/proc/update_wclass() if(amount == 1) w_class = WEIGHT_CLASS_TINY else w_class = WEIGHT_CLASS_SMALL /obj/item/stack/cable_coil/can_merge(obj/item/stack/check, inhand = FALSE) . = FALSE if(istype(check, merge_type)) var/obj/item/stack/cable_coil/coil_check = check . = coil_check.cable_merge_id == cable_merge_id return . && ..() //you can use wires to heal robotics /obj/item/stack/cable_coil/interact_with_atom(atom/target, mob/living/user, list/modifiers) if(!ishuman(target)) return ..() var/mob/living/carbon/human/H = target var/obj/item/organ/external/S = H.bodyparts_by_name[user.zone_selected] if(!S && ismachineperson(target) && user.a_intent == INTENT_HELP) to_chat(user, SPAN_NOTICE("[H.p_they(TRUE)] [H.p_are()] missing that limb!")) return ITEM_INTERACT_COMPLETE if(!S?.is_robotic() || user.a_intent != INTENT_HELP || S.open == ORGAN_SYNTHETIC_OPEN) return ..() if(S.burn_dam > ROBOLIMB_SELF_REPAIR_CAP) to_chat(user, SPAN_DANGER("The damage is far too severe to patch over externally.")) return ITEM_INTERACT_COMPLETE if(!S.burn_dam) to_chat(user, SPAN_NOTICE("Nothing to fix!")) return ITEM_INTERACT_COMPLETE if(H == user) if(!do_mob(user, H, 10)) return ITEM_INTERACT_COMPLETE var/cable_used = 0 var/childlist if(!isnull(S.children)) childlist = S.children.Copy() var/parenthealed = FALSE while(cable_used <= MAXCABLEPERHEAL && amount >= 1) var/obj/item/organ/external/E if(S.burn_dam) E = S else if(LAZYLEN(childlist)) E = pick_n_take(childlist) if(!E.burn_dam || E.burn_dam >= ROBOLIMB_SELF_REPAIR_CAP || !E.is_robotic()) continue else if(S.parent && !parenthealed) E = S.parent parenthealed = TRUE if(!E.burn_dam || E.burn_dam >= ROBOLIMB_SELF_REPAIR_CAP || !E.is_robotic()) break else break while(cable_used <= MAXCABLEPERHEAL && E.burn_dam && amount >= 1) use(1, destroy_upon_empty) cable_used += 1 E.heal_damage(0, HEALPERCABLE, 0, TRUE) H.UpdateDamageIcon() user.visible_message(SPAN_ALERT("[user] repairs some burn damage on [H]'s [E.name] with [src].")) return ITEM_INTERACT_COMPLETE /obj/item/stack/cable_coil/split() var/obj/item/stack/cable_coil/C = ..() C.color = color return C /obj/item/stack/cable_coil/item_interaction(mob/living/user, obj/item/used, list/modifiers) if(istype(used, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/C = used if(C.cable_merge_id != cable_merge_id) to_chat(user, "These coils are of different types.") return ITEM_INTERACT_COMPLETE if(C.get_amount() >= C.max_amount) to_chat(user, "The coil is as long as it will get.") return ITEM_INTERACT_COMPLETE // Cable merging is handled by parent proc. if((C.get_amount() + get_amount() <= C.max_amount)) to_chat(user, "You join the cable coils together.") return ..() to_chat(user, "You transfer [get_amount_transferred()] length\s of cable from one coil to the other.") return ..() if(istype(used, /obj/item/toy/crayon)) var/obj/item/toy/crayon/C = used cable_color(C.dye_color) return ITEM_INTERACT_COMPLETE return ..() /////////////////////////////////////////////// // Cable laying procedures ////////////////////////////////////////////// /obj/item/stack/cable_coil/proc/get_new_cable(location) var/obj/structure/cable/C = new cable_type(location) C.cable_color(get_cable_color()) return C /// called when cable_coil is clicked on a turf/simulated/floor /obj/item/stack/cable_coil/proc/place_turf(turf/T, mob/user, cable_direction) if(!isturf(user.loc)) return if(!isturf(T) || T.intact || !T.can_have_cabling()) to_chat(user, SPAN_WARNING("You can only lay cables on catwalks and plating!")) return if(get_amount() < 1) // Out of cable to_chat(user, SPAN_WARNING("There is no cable left!")) return if(get_dist(T, user) > 1) // Too far to_chat(user, SPAN_WARNING("You can't lay cable at a place that far away!")) return if(!cable_direction) //If we weren't given a direction, come up with one! (Called as null from catwalk.dm and floor.dm) if(user.loc == T) cable_direction = user.dir //If laying on the tile we're on, lay in the direction we're facing else cable_direction = get_dir(T, user) //otherwise get direction from us to the turf we've clicked for(var/obj/structure/cable/LC in T) if(LC.d2 == cable_direction && LC.d1 == NO_DIRECTION) //there's already a cable here that would be exactly what we just placed! to_chat(user, SPAN_WARNING("There's already a cable at that position!")) return var/obj/structure/cable/C = get_new_cable(T) //set up the new cable C.d1 = NO_DIRECTION //it's a O-X node cable C.d2 = cable_direction C.add_fingerprint(user) C.update_icon() //create a new powernet with the cable, if needed it will be merged later var/datum/regional_powernet/new_powernet = new() new_powernet.add_cable(C) C.merge_connected_networks(C.d2) //merge the powernet with adjacents powernets C.merge_connected_networks_on_turf() //merge the powernet with on turf powernets if(IS_DIR_DIAGONAL(C.d2))// if the cable is layed diagonally, check the others 2 possible directions C.merge_diagonal_networks(C.d2) use(1, destroy_upon_empty) if(C.shock(user, 50)) if(prob(50)) //fail C.deconstruct() SEND_GLOBAL_SIGNAL(COMSIG_GLOB_CABLE_UPDATED, T) return C /// called when cable_coil is click on an installed obj/cable or click on a turf that already contains a "node" cable /obj/item/stack/cable_coil/proc/cable_join(obj/structure/cable/C, mob/user) if(C.merge_id != cable_merge_id) return var/turf/U = user.loc if(!isturf(U)) return var/turf/T = get_turf(C) // sanity checks, also stop use interacting with T-scanner revealed cable if(!isturf(T) || T.intact || T.transparent_floor) return // make sure it's close enough if(get_dist(C, user) > 1) to_chat(user, SPAN_WARNING("You can't lay cable at a place that far away!")) return //if clicked on the turf we're standing on, try to put a cable in the direction we're facing if(U == T) place_turf(T,user) return var/new_direction = get_dir(C, user) // one end of the clicked cable is pointing towards us if(C.d1 == new_direction || C.d2 == new_direction) if(U.intact || U.transparent_floor) // can't place a cable if the floor is complete to_chat(user, SPAN_WARNING("You can't lay cable there unless the floor tiles are removed!")) return // cable is pointing at us, we're standing on an open tile // so create a stub pointing at the clicked cable on our tile var/direction_flipped = turn(new_direction, 180) // the opposite direction for(var/obj/structure/cable/LC in U) // check to make sure there's not a cable there already if(LC.d1 == direction_flipped || LC.d2 == direction_flipped) to_chat(user, SPAN_WARNING("There's already a cable at that position!")) return var/obj/structure/cable/NC = get_new_cable (U) NC.d1 = 0 NC.d2 = direction_flipped NC.add_fingerprint(user) NC.update_icon() //create a new powernet with the cable, if needed it will be merged later var/datum/regional_powernet/newPN = new() newPN.add_cable(NC) NC.merge_connected_networks(NC.d2) //merge the powernet with adjacents powernets NC.merge_connected_networks_on_turf() //merge the powernet with on turf powernets if(IS_DIR_DIAGONAL(NC.d2)) // if the cable is layed diagonally, check the others 2 possible directions NC.merge_diagonal_networks(NC.d2) use(1, destroy_upon_empty) if(NC.shock(user, 50)) if(prob(50)) //fail NC.deconstruct() return // exisiting cable doesn't point at our position, so see if it's a stub else if(C.d1 == 0) // if so, make it a full cable pointing from it's old direction to our new_direction var/nd1 = C.d2 // these will be the new directions var/nd2 = new_direction if(nd1 > nd2) // swap directions to match icons/states nd1 = new_direction nd2 = C.d2 for(var/obj/structure/cable/LC in T) // check to make sure there's no matching cable if(LC == C) // skip the cable we're interacting with continue if((LC.d1 == nd1 && LC.d2 == nd2) || (LC.d1 == nd2 && LC.d2 == nd1)) // make sure no cable matches either direction to_chat(user, SPAN_WARNING("There's already a cable at that position!")) return C.cable_color(get_cable_color()) C.d1 = nd1 C.d2 = nd2 C.add_fingerprint() C.update_icon() C.merge_connected_networks(C.d1) //merge the powernets... C.merge_connected_networks(C.d2) //...in the two new cable directions C.merge_connected_networks_on_turf() if(C.d1 & (C.d1 - 1))// if the cable is layed diagonally, check the others 2 possible directions C.merge_connected_networks(C.d1) if(C.d2 & (C.d2 - 1))// if the cable is layed diagonally, check the others 2 possible directions C.merge_connected_networks(C.d2) use(1, destroy_upon_empty) if(C.shock(user, 50)) if(prob(50)) //fail C.deconstruct() return C.denode()// this call may have disconnected some cables that terminated on the centre of the turf, if so split the powernets. SEND_GLOBAL_SIGNAL(COMSIG_GLOB_CABLE_UPDATED, T) ////////////////////////////// // Misc. ///////////////////////////// /obj/item/stack/cable_coil/proc/cable_color(colorC) if(!colorC) color = COLOR_RED else if(colorC == "rainbow") color = color_rainbow() else if(colorC == "orange") // byond only knows 16 colors by name, and orange isn't one of them color = COLOR_ORANGE else if(colorC == "pink") color = COLOR_PINK // nor is pink.. thanks byond else color = colorC /obj/item/stack/cable_coil/suicide_act(mob/user) if(locate(/obj/structure/chair/stool) in user.loc) user.visible_message(SPAN_SUICIDE("[user] is making a noose with [src]! It looks like [user.p_theyre()] trying to commit suicide!")) else user.visible_message(SPAN_SUICIDE("[user] is strangling [user.p_themselves()] with [src]! It looks like [user.p_theyre()] trying to commit suicide!")) return OXYLOSS /obj/item/stack/cable_coil/proc/color_rainbow() color = pick(COLOR_RED, COLOR_PINK, COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN, COLOR_CYAN, COLOR_BLUE, COLOR_WHITE) return color /obj/item/stack/cable_coil/five amount = 5 /obj/item/stack/cable_coil/ten amount = 10 /obj/item/stack/cable_coil/pink color = COLOR_PINK /obj/item/stack/cable_coil/yellow color = COLOR_YELLOW /obj/item/stack/cable_coil/orange color = COLOR_ORANGE /obj/item/stack/cable_coil/green color = COLOR_GREEN /obj/item/stack/cable_coil/cyan color = COLOR_CYAN /obj/item/stack/cable_coil/blue color = COLOR_BLUE /obj/item/stack/cable_coil/white color = COLOR_WHITE /obj/item/stack/cable_coil/random/Initialize(mapload) . = ..() color = pick(COLOR_RED, COLOR_PINK, COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN, COLOR_CYAN, COLOR_BLUE, COLOR_WHITE) /obj/item/stack/cable_coil/extra_insulated name = "heavy duty cable coil" singular_name = "heavy duty cable" icon = 'icons/obj/cable_coils/heavy_duty.dmi' materials = list(MAT_METAL = 30, MAT_GLASS = 30) color = null cable_type = /obj/structure/cable/extra_insulated cable_merge_id = CABLE_MERGE_HIGH_POWER req_one_access = list(ACCESS_ENGINE, ACCESS_CE) /obj/item/stack/cable_coil/extra_insulated/proc/toggle_connection(user) if(allowed(user)) if(cable_type == /obj/structure/cable/extra_insulated/pre_connect) cable_type = /obj/structure/cable/extra_insulated icon = 'icons/obj/cable_coils/heavy_duty.dmi' else cable_type = /obj/structure/cable/extra_insulated/pre_connect icon = 'icons/obj/cable_coils/heavy_duty_connected.dmi' /obj/item/stack/cable_coil/extra_insulated/item_interaction(mob/living/user, obj/item/used, list/modifiers) if(used.GetID()) toggle_connection(user) return ITEM_INTERACT_COMPLETE return ..() /obj/item/stack/cable_coil/cut icon_state = "coil2" /obj/item/stack/cable_coil/cut/Initialize(mapload) . = ..() src.amount = rand(1,2) update_appearance(UPDATE_NAME|UPDATE_ICON_STATE) update_wclass() #undef HEALPERCABLE #undef MAXCABLEPERHEAL