/obj/structure/closet/crate name = "crate" desc = "A rectangular steel crate." icon = 'icons/obj/crates.dmi' icon_state = "crate" icon_opened = "crate_open" icon_closed = "crate" climbable = TRUE var/rigged = FALSE open_sound = 'sound/machines/crate_open.ogg' close_sound = 'sound/machines/crate_close.ogg' open_sound_volume = 35 close_sound_volume = 50 var/obj/item/paper/manifest/manifest /// A list of beacon names that the crate will announce the arrival of, when delivered. var/list/announce_beacons = list() /// How much this crate is worth if you sell it via the cargo shuttle, needed for balance :) var/crate_value = DEFAULT_CRATE_VALUE /obj/structure/closet/crate/update_overlays() . = ..() if(manifest) . += "manifest" /obj/structure/closet/crate/can_open() return TRUE /obj/structure/closet/crate/can_close() return TRUE /obj/structure/closet/crate/open(by_hand = FALSE) if(opened) return FALSE if(!can_open()) return FALSE if(by_hand) for(var/obj/O in src) if(O.density) var/response = tgui_alert(usr, "This crate has been packed with bluespace compression, an item inside won't fit back inside. Are you sure you want to open it?", "Bluespace Compression Warning", list("Yes", "No")) if(response != "Yes" || !Adjacent(usr)) return FALSE break if(rigged && locate(/obj/item/electropack) in src) if(isliving(usr)) var/mob/living/L = usr if(L.electrocute_act(17, src)) do_sparks(5, 1, src) return 2 playsound(loc, open_sound, open_sound_volume, TRUE, -3) for(var/obj/O in src) //Objects O.forceMove(loc) for(var/mob/M in src) //Mobs M.forceMove(loc) icon_state = icon_opened opened = TRUE if(climbable) structure_shaken() return TRUE /obj/structure/closet/crate/close() if(!opened) return FALSE if(!can_close()) return FALSE playsound(loc, close_sound, close_sound_volume, TRUE, -3) var/itemcount = 0 for(var/atom/movable/O in get_turf(src)) if(itemcount >= storage_capacity) break if(O.density || O.anchored || istype(O,/obj/structure/closet)) continue if(ismob(O) && !HAS_TRAIT(O, TRAIT_CONTORTED_BODY)) continue if(O.has_buckled_mobs()) // You can't put mobs into crates, so naturally if a mob is attached to something, it shouldn't be able to go in the crate continue O.forceMove(src) itemcount++ icon_state = icon_closed opened = FALSE return TRUE /obj/structure/closet/crate/attackby(obj/item/W, mob/user, params) if(!opened && try_rig(W, user)) return return ..() /obj/structure/closet/crate/toggle(mob/user, by_hand = FALSE) if(!(opened ? close() : open(by_hand))) to_chat(user, "It won't budge!") /obj/structure/closet/crate/proc/try_rig(obj/item/W, mob/user) if(istype(W, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/C = W if(rigged) to_chat(user, "[src] is already rigged!") return TRUE if(C.use(15)) to_chat(user, "You rig [src].") rigged = TRUE else to_chat(user, "You need at least 15 wires to rig [src]!") return TRUE if(istype(W, /obj/item/electropack)) if(rigged) if(!user.drop_item()) to_chat(user, "[W] seems to be stuck to your hand!") return TRUE to_chat(user, "You attach [W] to [src].") W.forceMove(src) return TRUE /obj/structure/closet/crate/wirecutter_act(mob/living/user, obj/item/I) if(opened) return if(!rigged) return if(I.use_tool(src, user)) to_chat(user, "You cut away the wiring.") playsound(loc, I.usesound, 100, 1) rigged = FALSE return TRUE /obj/structure/closet/crate/welder_act() return /obj/structure/closet/crate/attack_hand(mob/user) if(manifest) to_chat(user, "You tear the manifest off of the crate.") playsound(loc, 'sound/items/poster_ripped.ogg', 75, TRUE) manifest.forceMove(loc) if(ishuman(user)) user.put_in_hands(manifest) manifest = null update_icon() return else if(rigged && locate(/obj/item/electropack) in src) if(isliving(user)) var/mob/living/L = user if(L.electrocute_act(17, src)) do_sparks(5, 1, src) return add_fingerprint(user) toggle(user, by_hand = TRUE) /obj/structure/closet/crate/shove_impact(mob/living/target, mob/living/attacker) return FALSE // Called when a crate is delivered by MULE at a location, for notifying purposes /obj/structure/closet/crate/proc/notifyRecipient(destination) var/list/msg = list("[capitalize(name)] has arrived at [destination].") if(destination in announce_beacons) for(var/obj/machinery/requests_console/D in GLOB.allRequestConsoles) if(D.department in announce_beacons[destination]) D.createMessage(name, "Your Crate has Arrived!", msg, RQ_NORMALPRIORITY) /obj/structure/closet/crate/secure desc = "A secure crate." name = "Secure crate" icon_state = "securecrate" icon_opened = "securecrate_open" icon_closed = "securecrate" max_integrity = 500 armor = list(MELEE = 30, BULLET = 50, LASER = 50, ENERGY = 100, BOMB = 0, RAD = 0, FIRE = 80, ACID = 80) damage_deflection = 25 broken = FALSE locked = TRUE can_be_emaged = TRUE crate_value = 25 // rarer and cannot be crafted, bonus credits for exporting them var/redlight = "securecrater" var/greenlight = "securecrateg" var/emag = "securecrateemag" var/tamperproof = FALSE /obj/structure/closet/crate/secure/update_overlays() . = ..() if(broken) . += emag return if(locked) . += redlight else . += greenlight /obj/structure/closet/crate/secure/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1) if(prob(tamperproof) && damage_amount >= DAMAGE_PRECISION) boom() else return ..() /obj/structure/closet/crate/secure/proc/boom(mob/user) if(user) to_chat(user, "The crate's anti-tamper system activates!") investigate_log("[key_name(user)] has detonated a [src]", INVESTIGATE_BOMB) add_attack_logs(user, src, "has detonated", ATKLOG_MOST) for(var/atom/movable/AM in src) qdel(AM) explosion(get_turf(src), 0, 1, 5, 5) qdel(src) /obj/structure/closet/crate/secure/can_open() return !locked /obj/structure/closet/crate/secure/proc/togglelock(mob/user) if(opened) to_chat(user, "Close the crate first.") return FALSE if(broken) to_chat(user, "The crate appears to be broken.") return FALSE if(allowed(user)) locked = !locked visible_message("The crate has been [locked ? null : "un"]locked by [user].") update_icon() return TRUE else to_chat(user, "Access Denied.") return FALSE /obj/structure/closet/crate/secure/AltClick(mob/user) if(Adjacent(user) && !opened) if(HAS_TRAIT(user, TRAIT_HANDS_BLOCKED) || user.stat) // Don't use it if you're not able to! Checks for stuns, ghost and restrain return togglelock(user) return . = ..() /obj/structure/closet/crate/secure/attack_hand(mob/user) if(manifest) to_chat(user, "You tear the manifest off of the crate.") playsound(loc, 'sound/items/poster_ripped.ogg', 75, 1) manifest.forceMove(loc) if(ishuman(user)) user.put_in_hands(manifest) manifest = null update_icon() return if(locked) togglelock(user) else toggle(user, by_hand = TRUE) /obj/structure/closet/crate/secure/closed_item_click(mob/user) togglelock(user) /obj/structure/closet/crate/secure/emag_act(mob/user) if(locked) locked = FALSE broken = TRUE update_icon() do_sparks(2, TRUE, src) to_chat(user, "You unlock \the [src].") return TRUE /obj/structure/closet/crate/secure/emp_act(severity) for(var/obj/O in src) O.emp_act(severity) if(!broken && !opened && prob(50/severity)) if(!locked) locked = TRUE else do_sparks(2, 1, src) locked = FALSE update_icon() if(!opened && prob(20/severity)) if(!locked) open() else req_access = list() req_access += pick(get_all_accesses()) ..() /obj/structure/closet/crate/secure/personal name = "personal crate" desc = "The crate version of Nanotrasen's famous personal locker, ideal for shipping booze, food, or drugs to CC without letting Cargo consume it. This one has not been configured by CC, and the first card swiped gains control." req_access = list(ACCESS_ALL_PERSONAL_LOCKERS) /// The name of the person this crate is registered to. var/registered_name = null // Unlike most secure crates, personal crates are easily obtained. crate_value = DEFAULT_CRATE_VALUE /obj/structure/closet/crate/secure/personal/allowed(mob/user) if(..()) return TRUE var/obj/item/card/id/id = user.get_id_card() if(is_usable_id(id)) return id.registered_name == registered_name return FALSE /// Returns whether the object is a usable ID card (not guest pass, has name). /obj/structure/closet/crate/secure/personal/proc/is_usable_id(obj/item/card/id/id) if(!istype(id)) return FALSE if(istype(id, /obj/item/card/id/guest) || !id.registered_name) return FALSE return TRUE /obj/structure/closet/crate/secure/personal/attackby(obj/item/I, mob/user, params) if(opened || !istype(I, /obj/item/card/id)) return ..() if(broken) to_chat(user, "It appears to be broken.") return FALSE var/obj/item/card/id/id = I if(!is_usable_id(id)) to_chat(user, "Invalid identification card.") return FALSE if(registered_name && allowed(user)) return ..() if(!registered_name) registered_name = id.registered_name desc = "Owned by [id.registered_name]." to_chat(user, "Crate reserved") return TRUE if(registered_name == id.registered_name) return ..() return FALSE /obj/structure/closet/crate/plastic name = "plastic crate" desc = "A rectangular plastic crate." icon_state = "plasticcrate" icon_opened = "plasticcrate_open" icon_closed = "plasticcrate" material_drop = /obj/item/stack/sheet/plastic material_drop_amount = 4 crate_value = 3 // You can mass produce plastic crates, this is needed to prevent cargo from making tons of money too easily /obj/structure/closet/crate/internals desc = "A internals crate." name = "internals crate" icon_state = "o2crate" icon_opened = "o2crate_open" icon_closed = "o2crate" /obj/structure/closet/crate/trashcart desc = "A heavy, metal trashcart with wheels." name = "trash Cart" icon_state = "trashcart" icon_opened = "trashcart_open" icon_closed = "trashcart" /obj/structure/closet/crate/medical desc = "A medical crate." name = "medical crate" icon_state = "medicalcrate" icon_opened = "medicalcrate_open" icon_closed = "medicalcrate" /obj/structure/closet/crate/rcd desc = "A crate for the storage of the RCD." name = "\improper RCD crate" /obj/structure/closet/crate/rcd/populate_contents() new /obj/item/rcd_ammo(src) new /obj/item/rcd_ammo(src) new /obj/item/rcd_ammo(src) new /obj/item/rcd(src) /obj/structure/closet/crate/freezer name = "Freezer" desc = "A freezer for keeping food and organs fresh." icon_state = "freezer" icon_opened = "freezer_open" icon_closed = "freezer" var/target_temp = T0C - 40 var/cooling_power = 40 /obj/structure/closet/crate/freezer/return_obj_air() RETURN_TYPE(/datum/gas_mixture) var/datum/gas_mixture/gas = ..() if(!gas) var/turf/T = get_turf(src) gas = T.get_readonly_air() var/datum/gas_mixture/newgas = new/datum/gas_mixture() newgas.set_oxygen(gas.oxygen()) newgas.set_carbon_dioxide(gas.carbon_dioxide()) newgas.set_nitrogen(gas.nitrogen()) newgas.set_toxins(gas.toxins()) newgas.volume = gas.volume newgas.set_temperature(gas.temperature()) if(newgas.temperature() <= target_temp) return if((newgas.temperature() - cooling_power) > target_temp) newgas.set_temperature(newgas.temperature() - cooling_power) else newgas.set_temperature(target_temp) return newgas /obj/structure/closet/crate/freezer/iv_storage name = "IV storage freezer" desc = "A freezer used to store IV bags containing various blood types." /obj/structure/closet/crate/freezer/iv_storage/populate_contents() new /obj/item/reagent_containers/iv_bag/blood/OMinus(src) new /obj/item/reagent_containers/iv_bag/blood/OPlus(src) new /obj/item/reagent_containers/iv_bag/blood/AMinus(src) new /obj/item/reagent_containers/iv_bag/blood/APlus(src) new /obj/item/reagent_containers/iv_bag/blood/BMinus(src) new /obj/item/reagent_containers/iv_bag/blood/BPlus(src) new /obj/item/reagent_containers/iv_bag/blood/random(src) new /obj/item/reagent_containers/iv_bag/blood/random(src) new /obj/item/reagent_containers/iv_bag/blood/random(src) new /obj/item/reagent_containers/iv_bag/salglu(src) new /obj/item/reagent_containers/iv_bag/slime(src) new /obj/item/reagent_containers/iv_bag/blood/vox(src) /obj/structure/closet/crate/can desc = "A large can, looks like a bin to me." name = "garbage can" icon_state = "largebin" icon_opened = "largebin_open" icon_closed = "largebin" anchored = TRUE open_sound = 'sound/effects/bin_open.ogg' close_sound = 'sound/effects/bin_close.ogg' /obj/structure/closet/crate/can/wrench_act(mob/user, obj/item/I) . = TRUE if(!I.tool_use_check(user, 0)) return default_unfasten_wrench(user, I, 40) /obj/structure/closet/crate/radiation desc = "A crate with a radiation sign on it." name = "radioactive gear crate" icon_state = "radiation" icon_opened = "radiation_open" icon_closed = "radiation" /obj/structure/closet/crate/secure/weapon desc = "A secure weapons crate." name = "weapons crate" icon_state = "weaponcrate" icon_opened = "weaponcrate_open" icon_closed = "weaponcrate" /obj/structure/closet/crate/secure/plasma desc = "A secure plasma crate." name = "plasma crate" icon_state = "plasmacrate" icon_opened = "plasmacrate_open" icon_closed = "plasmacrate" /obj/structure/closet/crate/secure/gear desc = "A secure gear crate." name = "gear crate" icon_state = "secgearcrate" icon_opened = "secgearcrate_open" icon_closed = "secgearcrate" /obj/structure/closet/crate/secure/hydrosec desc = "A crate with a lock on it, painted in the scheme of the station's botanists." name = "secure hydroponics crate" icon_state = "hydrosecurecrate" icon_opened = "hydrosecurecrate_open" icon_closed = "hydrosecurecrate" /obj/structure/closet/crate/secure/bin desc = "A secure bin." name = "secure bin" icon_state = "largebins" icon_opened = "largebins_open" icon_closed = "largebins" redlight = "largebinr" greenlight = "largebing" emag = "largebinemag" open_sound = 'sound/effects/bin_open.ogg' close_sound = 'sound/effects/bin_close.ogg' /obj/structure/closet/crate/hydroponics name = "hydroponics crate" desc = "All you need to destroy those pesky weeds and pests." icon_state = "hydrocrate" icon_opened = "hydrocrate_open" icon_closed = "hydrocrate" /obj/structure/closet/crate/hydroponics/prespawned //This exists so the prespawned hydro crates spawn with their contents. // Do I need the definition above? Who knows! /obj/structure/closet/crate/hydroponics/prespawned/populate_contents() new /obj/item/reagent_containers/glass/bucket(src) new /obj/item/reagent_containers/glass/bucket(src) new /obj/item/screwdriver(src) new /obj/item/screwdriver(src) new /obj/item/wrench(src) new /obj/item/wrench(src) new /obj/item/wirecutters(src) new /obj/item/wirecutters(src) new /obj/item/shovel/spade(src) new /obj/item/shovel/spade(src) new /obj/item/storage/box/beakers(src) new /obj/item/storage/box/beakers(src) new /obj/item/hand_labeler(src) new /obj/item/hand_labeler(src) /obj/structure/closet/crate/sci name = "science crate" desc = "A science crate." icon_state = "scicrate" icon_opened = "scicrate_open" icon_closed = "scicrate" /obj/structure/closet/crate/sci/robo desc = "A science crate. Contain various mech parts." icon_state = "scicrate_mech" icon_opened = "scicrate_mech_open" icon_closed = "scicrate_mech" /obj/structure/closet/crate/secure/scisec name = "secure science crate" desc = "A crate with a lock on it, painted in the scheme of the station's scientists." icon_state = "scisecurecrate" icon_opened = "scisecurecrate_open" icon_closed = "scisecurecrate" /obj/structure/closet/crate/engineering name = "engineering crate" desc = "An engineering crate." icon_state = "engicrate" icon_opened = "engicrate_open" icon_closed = "engicrate" /obj/structure/closet/crate/secure/engineering name = "secure engineering crate" desc = "A crate with a lock on it, painted in the scheme of the station's engineers." icon_state = "engisecurecrate" icon_opened = "engisecurecrate_open" icon_closed = "engisecurecrate" /obj/structure/closet/crate/engineering/electrical name = "electrical engineering crate" desc = "An electrical engineering crate." icon_state = "electricalcrate" icon_opened = "electricalcrate_open" icon_closed = "electricalcrate" /obj/structure/closet/crate/mail name = "mail crate" desc = "A plastic crate for mail delivery." icon = 'icons/obj/bureaucracy.dmi' icon_state = "mailsealed" icon_opened = "mailopen" icon_closed = "mailsealed" material_drop = /obj/item/stack/sheet/plastic material_drop_amount = 4 var/list/possible_contents = list(/obj/item/envelope/security, /obj/item/envelope/science, /obj/item/envelope/supply, /obj/item/envelope/medical, /obj/item/envelope/engineering, /obj/item/envelope/bread, /obj/item/envelope/circuses, /obj/item/envelope/command, /obj/item/envelope/misc) /obj/structure/closet/crate/mail/populate_contents() . = ..() for(var/i in 1 to rand(5, 10)) var/item = pick(possible_contents) new item(src) /obj/structure/closet/crate/tape/populate_contents() if(prob(10)) new /obj/item/bikehorn/rubberducky(src) //crates of gear in the free golem ship /obj/structure/closet/crate/golemgear/populate_contents() new /obj/item/storage/backpack/industrial(src) new /obj/item/shovel(src) new /obj/item/pickaxe(src) new /obj/item/t_scanner/adv_mining_scanner/lesser(src) new /obj/item/storage/bag/ore(src) new /obj/item/clothing/glasses/meson(src) new /obj/item/card/id/golem(src) new /obj/item/flashlight/lantern(src) #define RECURSION_PANIC_AMOUNT 10 /obj/structure/closet/crate/surplus /obj/structure/closet/crate/surplus/Initialize(mapload, obj/item/uplink/U, crate_value, cost, mob/user) . = ..() var/list/temp_uplink_list = get_uplink_items(U, user) var/list/buyable_items = list() for(var/category in temp_uplink_list) buyable_items += temp_uplink_list[category] for(var/datum/uplink_item/uplink_item in buyable_items) if(!uplink_item.surplus) // Otherwise we'll just have an element with a weight of 0 in our weighted list continue buyable_items[uplink_item] = uplink_item.surplus if(!length(buyable_items)) // UH OH - Will almost always happen when an admin will try to spawn a crate fucked_shit_up_alert(loc, "[src] spawning failed: had no buyable items on purchase which would have caused an infinite loop, refunding [cost] telecrystals instead. (Original cost of the crate). Report this to coders please.") generate_refund(cost, loc) return var/remaining_TC = crate_value var/list/bought_items = list() var/list/itemlog = list() var/datum/uplink_item/uplink_item var/danger_counter = 0 // lets make sure we dont get into an infinite loop... while(remaining_TC) if(danger_counter > RECURSION_PANIC_AMOUNT) fucked_shit_up_alert(loc, "[src] spawning failed: approached an infinite loop by cost checking, giving the remaining [remaining_TC] telecrystals instead.") generate_refund(remaining_TC, loc) break if(!length(buyable_items)) // UH OH V.2 fucked_shit_up_alert(loc, "[src] spawning failed: ran out of buyable items while looping, refunding [remaining_TC] telecrystals and cancelling crate. (Original cost of the crate). Report this to coders please.") generate_refund(remaining_TC, loc) bought_items.Cut() break uplink_item = pickweight(buyable_items) if(uplink_item.cost > remaining_TC) danger_counter++ buyable_items -= uplink_item continue bought_items += uplink_item.item remaining_TC -= uplink_item.cost buyable_items[uplink_item] *= 0.66 // To prevent people from getting the same thing over and over again itemlog += uplink_item.name // To make the name more readable for the log compared to just uplink_item.item danger_counter = 0 U.purchase_log += "[bicon(src)]" for(var/item in bought_items) var/obj/purchased = new item(src) U.purchase_log += "[bicon(purchased)]" log_game("[key_name(usr)] purchased a surplus crate with [jointext(itemlog, ", ")]") /obj/structure/closet/crate/surplus/proc/generate_refund(amount) var/changing_amount = amount var/prohibitor = 0 var/given_out_TC = 0 while(changing_amount >= 1) var/obj/item/stack/telecrystal/TC = new /obj/item/stack/telecrystal(src) var/give_amount = min(changing_amount, TC.max_amount) TC.amount = give_amount changing_amount -= give_amount given_out_TC += give_amount if(prohibitor > RECURSION_PANIC_AMOUNT) // idk how they got 1000+ tc, dont ask me new /obj/item/stack/telecrystal(src, changing_amount) // Return of Bogdanoff: doomp it var/turf/T = get_turf(loc) given_out_TC += changing_amount message_admins("While refunding telecrystals, [src] went over the expected limit, for a total of [amount] TC. Expected refund is likely [given_out_TC]. [ADMIN_COORDJMP(T)]") break prohibitor++ /obj/structure/closet/crate/surplus/proc/fucked_shit_up_alert(turf/loc, msg) // yeah just fuckin tell everyone, this shit is bad stack_trace(msg) message_admins("[msg] [ADMIN_COORDJMP(loc)]") log_admin(msg) #undef RECURSION_PANIC_AMOUNT /obj/structure/closet/crate/secure/sec_shuttle_ruin name = "locked crate" desc = "The side of the crate has a slot for a keycard to be swiped." can_be_emaged = FALSE /obj/structure/closet/crate/secure/sec_shuttle_ruin/allowed(mob/user) if(!user) return var/obj/item/card/sec_shuttle_ruin/keycard = user.get_active_hand() if(!istype(keycard)) return to_chat(user, "You swipe [keycard] in [src]'s keycard slot.") return TRUE /obj/item/card/sec_shuttle_ruin name = "warden's card" desc = "A card used by the warden to unlock their crate." icon_state = "data"